1 /* Copyright (C) 2009-2015 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 "gateway_common.h" 19 #include "main.h" 20 21 #include <linux/atomic.h> 22 #include <linux/errno.h> 23 #include <linux/byteorder/generic.h> 24 #include <linux/kernel.h> 25 #include <linux/math64.h> 26 #include <linux/netdevice.h> 27 #include <linux/stddef.h> 28 #include <linux/string.h> 29 30 #include "gateway_client.h" 31 #include "packet.h" 32 33 /** 34 * batadv_parse_gw_bandwidth - parse supplied string buffer to extract download 35 * and upload bandwidth information 36 * @net_dev: the soft interface net device 37 * @buff: string buffer to parse 38 * @down: pointer holding the returned download bandwidth information 39 * @up: pointer holding the returned upload bandwidth information 40 * 41 * Returns false on parse error and true otherwise. 42 */ 43 static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, 44 u32 *down, u32 *up) 45 { 46 enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; 47 char *slash_ptr, *tmp_ptr; 48 u64 ldown, lup; 49 int ret; 50 51 slash_ptr = strchr(buff, '/'); 52 if (slash_ptr) 53 *slash_ptr = 0; 54 55 if (strlen(buff) > 4) { 56 tmp_ptr = buff + strlen(buff) - 4; 57 58 if (strncasecmp(tmp_ptr, "mbit", 4) == 0) 59 bw_unit_type = BATADV_BW_UNIT_MBIT; 60 61 if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) || 62 (bw_unit_type == BATADV_BW_UNIT_MBIT)) 63 *tmp_ptr = '\0'; 64 } 65 66 ret = kstrtou64(buff, 10, &ldown); 67 if (ret) { 68 batadv_err(net_dev, 69 "Download speed of gateway mode invalid: %s\n", 70 buff); 71 return false; 72 } 73 74 switch (bw_unit_type) { 75 case BATADV_BW_UNIT_MBIT: 76 /* prevent overflow */ 77 if (U64_MAX / 10 < ldown) { 78 batadv_err(net_dev, 79 "Download speed of gateway mode too large: %s\n", 80 buff); 81 return false; 82 } 83 84 ldown *= 10; 85 break; 86 case BATADV_BW_UNIT_KBIT: 87 default: 88 ldown = div_u64(ldown, 100); 89 break; 90 } 91 92 if (U32_MAX < ldown) { 93 batadv_err(net_dev, 94 "Download speed of gateway mode too large: %s\n", 95 buff); 96 return false; 97 } 98 99 *down = ldown; 100 101 /* we also got some upload info */ 102 if (slash_ptr) { 103 bw_unit_type = BATADV_BW_UNIT_KBIT; 104 105 if (strlen(slash_ptr + 1) > 4) { 106 tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1); 107 108 if (strncasecmp(tmp_ptr, "mbit", 4) == 0) 109 bw_unit_type = BATADV_BW_UNIT_MBIT; 110 111 if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) || 112 (bw_unit_type == BATADV_BW_UNIT_MBIT)) 113 *tmp_ptr = '\0'; 114 } 115 116 ret = kstrtou64(slash_ptr + 1, 10, &lup); 117 if (ret) { 118 batadv_err(net_dev, 119 "Upload speed of gateway mode invalid: %s\n", 120 slash_ptr + 1); 121 return false; 122 } 123 124 switch (bw_unit_type) { 125 case BATADV_BW_UNIT_MBIT: 126 /* prevent overflow */ 127 if (U64_MAX / 10 < lup) { 128 batadv_err(net_dev, 129 "Upload speed of gateway mode too large: %s\n", 130 slash_ptr + 1); 131 return false; 132 } 133 134 lup *= 10; 135 break; 136 case BATADV_BW_UNIT_KBIT: 137 default: 138 lup = div_u64(lup, 100); 139 break; 140 } 141 142 if (U32_MAX < lup) { 143 batadv_err(net_dev, 144 "Upload speed of gateway mode too large: %s\n", 145 slash_ptr + 1); 146 return false; 147 } 148 149 *up = lup; 150 } 151 152 return true; 153 } 154 155 /** 156 * batadv_gw_tvlv_container_update - update the gw tvlv container after gateway 157 * setting change 158 * @bat_priv: the bat priv with all the soft interface information 159 */ 160 void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) 161 { 162 struct batadv_tvlv_gateway_data gw; 163 u32 down, up; 164 char gw_mode; 165 166 gw_mode = atomic_read(&bat_priv->gw_mode); 167 168 switch (gw_mode) { 169 case BATADV_GW_MODE_OFF: 170 case BATADV_GW_MODE_CLIENT: 171 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); 172 break; 173 case BATADV_GW_MODE_SERVER: 174 down = atomic_read(&bat_priv->gw.bandwidth_down); 175 up = atomic_read(&bat_priv->gw.bandwidth_up); 176 gw.bandwidth_down = htonl(down); 177 gw.bandwidth_up = htonl(up); 178 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, 179 &gw, sizeof(gw)); 180 break; 181 } 182 } 183 184 ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, 185 size_t count) 186 { 187 struct batadv_priv *bat_priv = netdev_priv(net_dev); 188 u32 down_curr; 189 u32 up_curr; 190 u32 down_new = 0; 191 u32 up_new = 0; 192 bool ret; 193 194 down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); 195 up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up); 196 197 ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new); 198 if (!ret) 199 return -EINVAL; 200 201 if (!down_new) 202 down_new = 1; 203 204 if (!up_new) 205 up_new = down_new / 5; 206 207 if (!up_new) 208 up_new = 1; 209 210 if ((down_curr == down_new) && (up_curr == up_new)) 211 return count; 212 213 batadv_gw_reselect(bat_priv); 214 batadv_info(net_dev, 215 "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n", 216 down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10, 217 down_new / 10, down_new % 10, up_new / 10, up_new % 10); 218 219 atomic_set(&bat_priv->gw.bandwidth_down, down_new); 220 atomic_set(&bat_priv->gw.bandwidth_up, up_new); 221 batadv_gw_tvlv_container_update(bat_priv); 222 223 return count; 224 } 225 226 /** 227 * batadv_gw_tvlv_ogm_handler_v1 - process incoming gateway tvlv container 228 * @bat_priv: the bat priv with all the soft interface information 229 * @orig: the orig_node of the ogm 230 * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) 231 * @tvlv_value: tvlv buffer containing the gateway data 232 * @tvlv_value_len: tvlv buffer length 233 */ 234 static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, 235 struct batadv_orig_node *orig, 236 u8 flags, 237 void *tvlv_value, u16 tvlv_value_len) 238 { 239 struct batadv_tvlv_gateway_data gateway, *gateway_ptr; 240 241 /* only fetch the tvlv value if the handler wasn't called via the 242 * CIFNOTFND flag and if there is data to fetch 243 */ 244 if ((flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) || 245 (tvlv_value_len < sizeof(gateway))) { 246 gateway.bandwidth_down = 0; 247 gateway.bandwidth_up = 0; 248 } else { 249 gateway_ptr = tvlv_value; 250 gateway.bandwidth_down = gateway_ptr->bandwidth_down; 251 gateway.bandwidth_up = gateway_ptr->bandwidth_up; 252 if ((gateway.bandwidth_down == 0) || 253 (gateway.bandwidth_up == 0)) { 254 gateway.bandwidth_down = 0; 255 gateway.bandwidth_up = 0; 256 } 257 } 258 259 batadv_gw_node_update(bat_priv, orig, &gateway); 260 261 /* restart gateway selection if fast or late switching was enabled */ 262 if ((gateway.bandwidth_down != 0) && 263 (atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) && 264 (atomic_read(&bat_priv->gw_sel_class) > 2)) 265 batadv_gw_check_election(bat_priv, orig); 266 } 267 268 /** 269 * batadv_gw_init - initialise the gateway handling internals 270 * @bat_priv: the bat priv with all the soft interface information 271 */ 272 void batadv_gw_init(struct batadv_priv *bat_priv) 273 { 274 batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, 275 NULL, BATADV_TVLV_GW, 1, 276 BATADV_TVLV_HANDLER_OGM_CIFNOTFND); 277 } 278 279 /** 280 * batadv_gw_free - free the gateway handling internals 281 * @bat_priv: the bat priv with all the soft interface information 282 */ 283 void batadv_gw_free(struct batadv_priv *bat_priv) 284 { 285 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); 286 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1); 287 } 288