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