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