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