Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) B.A.T.M.A.N. contributors:
0003  *
0004  * Marek Lindner
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  * batadv_parse_throughput() - parse supplied string buffer to extract
0028  *  throughput information
0029  * @net_dev: the soft interface net device
0030  * @buff: string buffer to parse
0031  * @description: text shown when throughput string cannot be parsed
0032  * @throughput: pointer holding the returned throughput information
0033  *
0034  * Return: false on parse error and true otherwise.
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, &lthroughput);
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         /* prevent overflow */
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  * batadv_parse_gw_bandwidth() - parse supplied string buffer to extract
0095  *  download and upload bandwidth information
0096  * @net_dev: the soft interface net device
0097  * @buff: string buffer to parse
0098  * @down: pointer holding the returned download bandwidth information
0099  * @up: pointer holding the returned upload bandwidth information
0100  *
0101  * Return: false on parse error and true otherwise.
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     /* we also got some upload info */
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  * batadv_gw_tvlv_container_update() - update the gw tvlv container after
0131  *  gateway setting change
0132  * @bat_priv: the bat priv with all the soft interface information
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  * batadv_gw_bandwidth_set() - Parse and set download/upload gateway bandwidth
0160  *  from supplied string buffer
0161  * @net_dev: netdev struct of the soft interface
0162  * @buff: the buffer containing the user data
0163  * @count: number of bytes in the buffer
0164  *
0165  * Return: 'count' on success or a negative error code in case of failure
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  * batadv_gw_tvlv_ogm_handler_v1() - process incoming gateway tvlv container
0211  * @bat_priv: the bat priv with all the soft interface information
0212  * @orig: the orig_node of the ogm
0213  * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
0214  * @tvlv_value: tvlv buffer containing the gateway data
0215  * @tvlv_value_len: tvlv buffer length
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     /* only fetch the tvlv value if the handler wasn't called via the
0225      * CIFNOTFND flag and if there is data to fetch
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     /* restart gateway selection */
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  * batadv_gw_init() - initialise the gateway handling internals
0252  * @bat_priv: the bat priv with all the soft interface information
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  * batadv_gw_free() - free the gateway handling internals
0268  * @bat_priv: the bat priv with all the soft interface information
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 }