1/* Copyright (C) 2009-2014 B.A.T.M.A.N. contributors: 2 * 3 * Marek Lindner 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of version 2 of the GNU General Public 7 * License as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18#include "main.h" 19#include "gateway_common.h" 20#include "gateway_client.h" 21 22/** 23 * batadv_parse_gw_bandwidth - parse supplied string buffer to extract download 24 * and upload bandwidth information 25 * @net_dev: the soft interface net device 26 * @buff: string buffer to parse 27 * @down: pointer holding the returned download bandwidth information 28 * @up: pointer holding the returned upload bandwidth information 29 * 30 * Returns false on parse error and true otherwise. 31 */ 32static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, 33 uint32_t *down, uint32_t *up) 34{ 35 enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; 36 char *slash_ptr, *tmp_ptr; 37 long ldown, lup; 38 int ret; 39 40 slash_ptr = strchr(buff, '/'); 41 if (slash_ptr) 42 *slash_ptr = 0; 43 44 if (strlen(buff) > 4) { 45 tmp_ptr = buff + strlen(buff) - 4; 46 47 if (strncasecmp(tmp_ptr, "mbit", 4) == 0) 48 bw_unit_type = BATADV_BW_UNIT_MBIT; 49 50 if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) || 51 (bw_unit_type == BATADV_BW_UNIT_MBIT)) 52 *tmp_ptr = '\0'; 53 } 54 55 ret = kstrtol(buff, 10, &ldown); 56 if (ret) { 57 batadv_err(net_dev, 58 "Download speed of gateway mode invalid: %s\n", 59 buff); 60 return false; 61 } 62 63 switch (bw_unit_type) { 64 case BATADV_BW_UNIT_MBIT: 65 *down = ldown * 10; 66 break; 67 case BATADV_BW_UNIT_KBIT: 68 default: 69 *down = ldown / 100; 70 break; 71 } 72 73 /* we also got some upload info */ 74 if (slash_ptr) { 75 bw_unit_type = BATADV_BW_UNIT_KBIT; 76 77 if (strlen(slash_ptr + 1) > 4) { 78 tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); 79 80 if (strncasecmp(tmp_ptr, "mbit", 4) == 0) 81 bw_unit_type = BATADV_BW_UNIT_MBIT; 82 83 if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) || 84 (bw_unit_type == BATADV_BW_UNIT_MBIT)) 85 *tmp_ptr = '\0'; 86 } 87 88 ret = kstrtol(slash_ptr + 1, 10, &lup); 89 if (ret) { 90 batadv_err(net_dev, 91 "Upload speed of gateway mode invalid: %s\n", 92 slash_ptr + 1); 93 return false; 94 } 95 96 switch (bw_unit_type) { 97 case BATADV_BW_UNIT_MBIT: 98 *up = lup * 10; 99 break; 100 case BATADV_BW_UNIT_KBIT: 101 default: 102 *up = lup / 100; 103 break; 104 } 105 } 106 107 return true; 108} 109 110/** 111 * batadv_gw_tvlv_container_update - update the gw tvlv container after gateway 112 * setting change 113 * @bat_priv: the bat priv with all the soft interface information 114 */ 115void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) 116{ 117 struct batadv_tvlv_gateway_data gw; 118 uint32_t down, up; 119 char gw_mode; 120 121 gw_mode = atomic_read(&bat_priv->gw_mode); 122 123 switch (gw_mode) { 124 case BATADV_GW_MODE_OFF: 125 case BATADV_GW_MODE_CLIENT: 126 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); 127 break; 128 case BATADV_GW_MODE_SERVER: 129 down = atomic_read(&bat_priv->gw.bandwidth_down); 130 up = atomic_read(&bat_priv->gw.bandwidth_up); 131 gw.bandwidth_down = htonl(down); 132 gw.bandwidth_up = htonl(up); 133 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, 134 &gw, sizeof(gw)); 135 break; 136 } 137} 138 139ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, 140 size_t count) 141{ 142 struct batadv_priv *bat_priv = netdev_priv(net_dev); 143 uint32_t down_curr, up_curr, down_new = 0, up_new = 0; 144 bool ret; 145 146 down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); 147 up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up); 148 149 ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new); 150 if (!ret) 151 goto end; 152 153 if (!down_new) 154 down_new = 1; 155 156 if (!up_new) 157 up_new = down_new / 5; 158 159 if (!up_new) 160 up_new = 1; 161 162 if ((down_curr == down_new) && (up_curr == up_new)) 163 return count; 164 165 batadv_gw_reselect(bat_priv); 166 batadv_info(net_dev, 167 "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", 168 down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, 169 down_new / 10, down_new % 10, up_new / 10, up_new % 10); 170 171 atomic_set(&bat_priv->gw.bandwidth_down, down_new); 172 atomic_set(&bat_priv->gw.bandwidth_up, up_new); 173 batadv_gw_tvlv_container_update(bat_priv); 174 175end: 176 return count; 177} 178 179/** 180 * batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container 181 * @bat_priv: the bat priv with all the soft interface information 182 * @orig: the orig_node of the ogm 183 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 184 * @tvlv_value: tvlv buffer containing the gateway data 185 * @tvlv_value_len: tvlv buffer length 186 */ 187static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 188 struct batadv_orig_node *orig, 189 uint8_t flags, 190 void *tvlv_value, 191 uint16_t tvlv_value_len) 192{ 193 struct batadv_tvlv_gateway_data gateway, *gateway_ptr; 194 195 /* only fetch the tvlv value if the handler wasn't called via the 196 * CIFNOTFND flag and if there is data to fetch 197 */ 198 if ((flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) || 199 (tvlv_value_len < sizeof(gateway))) { 200 gateway.bandwidth_down = 0; 201 gateway.bandwidth_up = 0; 202 } else { 203 gateway_ptr = tvlv_value; 204 gateway.bandwidth_down = gateway_ptr->bandwidth_down; 205 gateway.bandwidth_up = gateway_ptr->bandwidth_up; 206 if ((gateway.bandwidth_down == 0) || 207 (gateway.bandwidth_up == 0)) { 208 gateway.bandwidth_down = 0; 209 gateway.bandwidth_up = 0; 210 } 211 } 212 213 batadv_gw_node_update(bat_priv, orig, &gateway); 214 215 /* restart gateway selection if fast or late switching was enabled */ 216 if ((gateway.bandwidth_down != 0) && 217 (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && 218 (atomic_read(&bat_priv->gw_sel_class) > 2)) 219 batadv_gw_check_election(bat_priv, orig); 220} 221 222/** 223 * batadv_gw_init - initialise the gateway handling internals 224 * @bat_priv: the bat priv with all the soft interface information 225 */ 226void batadv_gw_init(struct batadv_priv *bat_priv) 227{ 228 batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, 229 NULL, BATADV_TVLV_GW, 1, 230 BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 231} 232 233/** 234 * batadv_gw_free - free the gateway handling internals 235 * @bat_priv: the bat priv with all the soft interface information 236 */ 237void batadv_gw_free(struct batadv_priv *bat_priv) 238{ 239 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); 240 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); 241} 242