linux/net/batman-adv/gateway_common.c
<<
>>
Prefs
   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 */
  34static 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 */
 117void 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
 141ssize_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
 177end:
 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 */
 189static 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 */
 228void 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 */
 239void 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