0001
0002
0003
0004
0005
0006
0007 #include "gateway_common.h"
0008 #include "main.h"
0009
0010 #include <linux/atomic.h>
0011 #include <linux/byteorder/generic.h>
0012 #include <linux/errno.h>
0013 #include <linux/kstrtox.h>
0014 #include <linux/limits.h>
0015 #include <linux/math64.h>
0016 #include <linux/netdevice.h>
0017 #include <linux/stddef.h>
0018 #include <linux/string.h>
0019 #include <uapi/linux/batadv_packet.h>
0020 #include <uapi/linux/batman_adv.h>
0021
0022 #include "gateway_client.h"
0023 #include "log.h"
0024 #include "tvlv.h"
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
0037 const char *description, u32 *throughput)
0038 {
0039 enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
0040 u64 lthroughput;
0041 char *tmp_ptr;
0042 int ret;
0043
0044 if (strlen(buff) > 4) {
0045 tmp_ptr = buff + strlen(buff) - 4;
0046
0047 if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
0048 bw_unit_type = BATADV_BW_UNIT_MBIT;
0049
0050 if (strncasecmp(tmp_ptr, "kbit", 4) == 0 ||
0051 bw_unit_type == BATADV_BW_UNIT_MBIT)
0052 *tmp_ptr = '\0';
0053 }
0054
0055 ret = kstrtou64(buff, 10, <hroughput);
0056 if (ret) {
0057 batadv_err(net_dev,
0058 "Invalid throughput speed for %s: %s\n",
0059 description, buff);
0060 return false;
0061 }
0062
0063 switch (bw_unit_type) {
0064 case BATADV_BW_UNIT_MBIT:
0065
0066 if (U64_MAX / 10 < lthroughput) {
0067 batadv_err(net_dev,
0068 "Throughput speed for %s too large: %s\n",
0069 description, buff);
0070 return false;
0071 }
0072
0073 lthroughput *= 10;
0074 break;
0075 case BATADV_BW_UNIT_KBIT:
0076 default:
0077 lthroughput = div_u64(lthroughput, 100);
0078 break;
0079 }
0080
0081 if (lthroughput > U32_MAX) {
0082 batadv_err(net_dev,
0083 "Throughput speed for %s too large: %s\n",
0084 description, buff);
0085 return false;
0086 }
0087
0088 *throughput = lthroughput;
0089
0090 return true;
0091 }
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
0104 u32 *down, u32 *up)
0105 {
0106 char *slash_ptr;
0107 bool ret;
0108
0109 slash_ptr = strchr(buff, '/');
0110 if (slash_ptr)
0111 *slash_ptr = 0;
0112
0113 ret = batadv_parse_throughput(net_dev, buff, "download gateway speed",
0114 down);
0115 if (!ret)
0116 return false;
0117
0118
0119 if (slash_ptr) {
0120 ret = batadv_parse_throughput(net_dev, slash_ptr + 1,
0121 "upload gateway speed", up);
0122 if (!ret)
0123 return false;
0124 }
0125
0126 return true;
0127 }
0128
0129
0130
0131
0132
0133
0134 void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv)
0135 {
0136 struct batadv_tvlv_gateway_data gw;
0137 u32 down, up;
0138 char gw_mode;
0139
0140 gw_mode = atomic_read(&bat_priv->gw.mode);
0141
0142 switch (gw_mode) {
0143 case BATADV_GW_MODE_OFF:
0144 case BATADV_GW_MODE_CLIENT:
0145 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1);
0146 break;
0147 case BATADV_GW_MODE_SERVER:
0148 down = atomic_read(&bat_priv->gw.bandwidth_down);
0149 up = atomic_read(&bat_priv->gw.bandwidth_up);
0150 gw.bandwidth_down = htonl(down);
0151 gw.bandwidth_up = htonl(up);
0152 batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1,
0153 &gw, sizeof(gw));
0154 break;
0155 }
0156 }
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167 ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
0168 size_t count)
0169 {
0170 struct batadv_priv *bat_priv = netdev_priv(net_dev);
0171 u32 down_curr;
0172 u32 up_curr;
0173 u32 down_new = 0;
0174 u32 up_new = 0;
0175 bool ret;
0176
0177 down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down);
0178 up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up);
0179
0180 ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new);
0181 if (!ret)
0182 return -EINVAL;
0183
0184 if (!down_new)
0185 down_new = 1;
0186
0187 if (!up_new)
0188 up_new = down_new / 5;
0189
0190 if (!up_new)
0191 up_new = 1;
0192
0193 if (down_curr == down_new && up_curr == up_new)
0194 return count;
0195
0196 batadv_gw_reselect(bat_priv);
0197 batadv_info(net_dev,
0198 "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n",
0199 down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10,
0200 down_new / 10, down_new % 10, up_new / 10, up_new % 10);
0201
0202 atomic_set(&bat_priv->gw.bandwidth_down, down_new);
0203 atomic_set(&bat_priv->gw.bandwidth_up, up_new);
0204 batadv_gw_tvlv_container_update(bat_priv);
0205
0206 return count;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
0218 struct batadv_orig_node *orig,
0219 u8 flags,
0220 void *tvlv_value, u16 tvlv_value_len)
0221 {
0222 struct batadv_tvlv_gateway_data gateway, *gateway_ptr;
0223
0224
0225
0226
0227 if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND ||
0228 tvlv_value_len < sizeof(gateway)) {
0229 gateway.bandwidth_down = 0;
0230 gateway.bandwidth_up = 0;
0231 } else {
0232 gateway_ptr = tvlv_value;
0233 gateway.bandwidth_down = gateway_ptr->bandwidth_down;
0234 gateway.bandwidth_up = gateway_ptr->bandwidth_up;
0235 if (gateway.bandwidth_down == 0 ||
0236 gateway.bandwidth_up == 0) {
0237 gateway.bandwidth_down = 0;
0238 gateway.bandwidth_up = 0;
0239 }
0240 }
0241
0242 batadv_gw_node_update(bat_priv, orig, &gateway);
0243
0244
0245 if (gateway.bandwidth_down != 0 &&
0246 atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT)
0247 batadv_gw_check_election(bat_priv, orig);
0248 }
0249
0250
0251
0252
0253
0254 void batadv_gw_init(struct batadv_priv *bat_priv)
0255 {
0256 if (bat_priv->algo_ops->gw.init_sel_class)
0257 bat_priv->algo_ops->gw.init_sel_class(bat_priv);
0258 else
0259 atomic_set(&bat_priv->gw.sel_class, 1);
0260
0261 batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1,
0262 NULL, BATADV_TVLV_GW, 1,
0263 BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
0264 }
0265
0266
0267
0268
0269
0270 void batadv_gw_free(struct batadv_priv *bat_priv)
0271 {
0272 batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1);
0273 batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_GW, 1);
0274 }