linux/net/batman-adv/gateway_client.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 "sysfs.h"
  22#include "gateway_client.h"
  23#include "gateway_common.h"
  24#include "hard-interface.h"
  25#include "originator.h"
  26#include "translation-table.h"
  27#include "routing.h"
  28#include <linux/ip.h>
  29#include <linux/ipv6.h>
  30#include <linux/udp.h>
  31#include <linux/if_vlan.h>
  32
  33/* This is the offset of the options field in a dhcp packet starting at
  34 * the beginning of the dhcp header
  35 */
  36#define BATADV_DHCP_OPTIONS_OFFSET 240
  37#define BATADV_DHCP_REQUEST 3
  38
  39static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
  40{
  41        if (atomic_dec_and_test(&gw_node->refcount))
  42                kfree_rcu(gw_node, rcu);
  43}
  44
  45static struct batadv_gw_node *
  46batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv)
  47{
  48        struct batadv_gw_node *gw_node;
  49
  50        rcu_read_lock();
  51        gw_node = rcu_dereference(bat_priv->gw.curr_gw);
  52        if (!gw_node)
  53                goto out;
  54
  55        if (!atomic_inc_not_zero(&gw_node->refcount))
  56                gw_node = NULL;
  57
  58out:
  59        rcu_read_unlock();
  60        return gw_node;
  61}
  62
  63struct batadv_orig_node *
  64batadv_gw_get_selected_orig(struct batadv_priv *bat_priv)
  65{
  66        struct batadv_gw_node *gw_node;
  67        struct batadv_orig_node *orig_node = NULL;
  68
  69        gw_node = batadv_gw_get_selected_gw_node(bat_priv);
  70        if (!gw_node)
  71                goto out;
  72
  73        rcu_read_lock();
  74        orig_node = gw_node->orig_node;
  75        if (!orig_node)
  76                goto unlock;
  77
  78        if (!atomic_inc_not_zero(&orig_node->refcount))
  79                orig_node = NULL;
  80
  81unlock:
  82        rcu_read_unlock();
  83out:
  84        if (gw_node)
  85                batadv_gw_node_free_ref(gw_node);
  86        return orig_node;
  87}
  88
  89static void batadv_gw_select(struct batadv_priv *bat_priv,
  90                             struct batadv_gw_node *new_gw_node)
  91{
  92        struct batadv_gw_node *curr_gw_node;
  93
  94        spin_lock_bh(&bat_priv->gw.list_lock);
  95
  96        if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
  97                new_gw_node = NULL;
  98
  99        curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1);
 100        rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node);
 101
 102        if (curr_gw_node)
 103                batadv_gw_node_free_ref(curr_gw_node);
 104
 105        spin_unlock_bh(&bat_priv->gw.list_lock);
 106}
 107
 108void batadv_gw_deselect(struct batadv_priv *bat_priv)
 109{
 110        atomic_set(&bat_priv->gw.reselect, 1);
 111}
 112
 113static struct batadv_gw_node *
 114batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
 115{
 116        struct batadv_neigh_node *router;
 117        struct batadv_gw_node *gw_node, *curr_gw = NULL;
 118        uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
 119        uint32_t gw_divisor;
 120        uint8_t max_tq = 0;
 121        uint8_t tq_avg;
 122        struct batadv_orig_node *orig_node;
 123
 124        gw_divisor = BATADV_TQ_LOCAL_WINDOW_SIZE * BATADV_TQ_LOCAL_WINDOW_SIZE;
 125        gw_divisor *= 64;
 126
 127        rcu_read_lock();
 128        hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
 129                if (gw_node->deleted)
 130                        continue;
 131
 132                orig_node = gw_node->orig_node;
 133                router = batadv_orig_node_get_router(orig_node);
 134                if (!router)
 135                        continue;
 136
 137                if (!atomic_inc_not_zero(&gw_node->refcount))
 138                        goto next;
 139
 140                tq_avg = router->bat_iv.tq_avg;
 141
 142                switch (atomic_read(&bat_priv->gw_sel_class)) {
 143                case 1: /* fast connection */
 144                        tmp_gw_factor = tq_avg * tq_avg;
 145                        tmp_gw_factor *= gw_node->bandwidth_down;
 146                        tmp_gw_factor *= 100 * 100;
 147                        tmp_gw_factor /= gw_divisor;
 148
 149                        if ((tmp_gw_factor > max_gw_factor) ||
 150                            ((tmp_gw_factor == max_gw_factor) &&
 151                             (tq_avg > max_tq))) {
 152                                if (curr_gw)
 153                                        batadv_gw_node_free_ref(curr_gw);
 154                                curr_gw = gw_node;
 155                                atomic_inc(&curr_gw->refcount);
 156                        }
 157                        break;
 158
 159                default: /* 2:  stable connection (use best statistic)
 160                          * 3:  fast-switch (use best statistic but change as
 161                          *     soon as a better gateway appears)
 162                          * XX: late-switch (use best statistic but change as
 163                          *     soon as a better gateway appears which has
 164                          *     $routing_class more tq points)
 165                          */
 166                        if (tq_avg > max_tq) {
 167                                if (curr_gw)
 168                                        batadv_gw_node_free_ref(curr_gw);
 169                                curr_gw = gw_node;
 170                                atomic_inc(&curr_gw->refcount);
 171                        }
 172                        break;
 173                }
 174
 175                if (tq_avg > max_tq)
 176                        max_tq = tq_avg;
 177
 178                if (tmp_gw_factor > max_gw_factor)
 179                        max_gw_factor = tmp_gw_factor;
 180
 181                batadv_gw_node_free_ref(gw_node);
 182
 183next:
 184                batadv_neigh_node_free_ref(router);
 185        }
 186        rcu_read_unlock();
 187
 188        return curr_gw;
 189}
 190
 191/**
 192 * batadv_gw_check_client_stop - check if client mode has been switched off
 193 * @bat_priv: the bat priv with all the soft interface information
 194 *
 195 * This function assumes the caller has checked that the gw state *is actually
 196 * changing*. This function is not supposed to be called when there is no state
 197 * change.
 198 */
 199void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
 200{
 201        struct batadv_gw_node *curr_gw;
 202
 203        if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
 204                return;
 205
 206        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 207        if (!curr_gw)
 208                return;
 209
 210        /* if batman-adv is switching the gw client mode off and a gateway was
 211         * already selected, send a DEL uevent
 212         */
 213        batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL, NULL);
 214
 215        batadv_gw_node_free_ref(curr_gw);
 216}
 217
 218void batadv_gw_election(struct batadv_priv *bat_priv)
 219{
 220        struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL;
 221        struct batadv_neigh_node *router = NULL;
 222        char gw_addr[18] = { '\0' };
 223
 224        if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
 225                goto out;
 226
 227        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 228
 229        if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw)
 230                goto out;
 231
 232        next_gw = batadv_gw_get_best_gw_node(bat_priv);
 233
 234        if (curr_gw == next_gw)
 235                goto out;
 236
 237        if (next_gw) {
 238                sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
 239
 240                router = batadv_orig_node_get_router(next_gw->orig_node);
 241                if (!router) {
 242                        batadv_gw_deselect(bat_priv);
 243                        goto out;
 244                }
 245        }
 246
 247        if ((curr_gw) && (!next_gw)) {
 248                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 249                           "Removing selected gateway - no gateway in range\n");
 250                batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL,
 251                                    NULL);
 252        } else if ((!curr_gw) && (next_gw)) {
 253                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 254                           "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
 255                           next_gw->orig_node->orig,
 256                           next_gw->bandwidth_down / 10,
 257                           next_gw->bandwidth_down % 10,
 258                           next_gw->bandwidth_up / 10,
 259                           next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
 260                batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
 261                                    gw_addr);
 262        } else {
 263                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 264                           "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
 265                           next_gw->orig_node->orig,
 266                           next_gw->bandwidth_down / 10,
 267                           next_gw->bandwidth_down % 10,
 268                           next_gw->bandwidth_up / 10,
 269                           next_gw->bandwidth_up % 10, router->bat_iv.tq_avg);
 270                batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
 271                                    gw_addr);
 272        }
 273
 274        batadv_gw_select(bat_priv, next_gw);
 275
 276out:
 277        if (curr_gw)
 278                batadv_gw_node_free_ref(curr_gw);
 279        if (next_gw)
 280                batadv_gw_node_free_ref(next_gw);
 281        if (router)
 282                batadv_neigh_node_free_ref(router);
 283}
 284
 285void batadv_gw_check_election(struct batadv_priv *bat_priv,
 286                              struct batadv_orig_node *orig_node)
 287{
 288        struct batadv_orig_node *curr_gw_orig;
 289        struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL;
 290        uint8_t gw_tq_avg, orig_tq_avg;
 291
 292        curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
 293        if (!curr_gw_orig)
 294                goto deselect;
 295
 296        router_gw = batadv_orig_node_get_router(curr_gw_orig);
 297        if (!router_gw)
 298                goto deselect;
 299
 300        /* this node already is the gateway */
 301        if (curr_gw_orig == orig_node)
 302                goto out;
 303
 304        router_orig = batadv_orig_node_get_router(orig_node);
 305        if (!router_orig)
 306                goto out;
 307
 308        gw_tq_avg = router_gw->bat_iv.tq_avg;
 309        orig_tq_avg = router_orig->bat_iv.tq_avg;
 310
 311        /* the TQ value has to be better */
 312        if (orig_tq_avg < gw_tq_avg)
 313                goto out;
 314
 315        /* if the routing class is greater than 3 the value tells us how much
 316         * greater the TQ value of the new gateway must be
 317         */
 318        if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
 319            (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
 320                goto out;
 321
 322        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 323                   "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
 324                   gw_tq_avg, orig_tq_avg);
 325
 326deselect:
 327        batadv_gw_deselect(bat_priv);
 328out:
 329        if (curr_gw_orig)
 330                batadv_orig_node_free_ref(curr_gw_orig);
 331        if (router_gw)
 332                batadv_neigh_node_free_ref(router_gw);
 333        if (router_orig)
 334                batadv_neigh_node_free_ref(router_orig);
 335
 336        return;
 337}
 338
 339/**
 340 * batadv_gw_node_add - add gateway node to list of available gateways
 341 * @bat_priv: the bat priv with all the soft interface information
 342 * @orig_node: originator announcing gateway capabilities
 343 * @gateway: announced bandwidth information
 344 */
 345static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 346                               struct batadv_orig_node *orig_node,
 347                               struct batadv_tvlv_gateway_data *gateway)
 348{
 349        struct batadv_gw_node *gw_node;
 350
 351        if (gateway->bandwidth_down == 0)
 352                return;
 353
 354        gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
 355        if (!gw_node)
 356                return;
 357
 358        INIT_HLIST_NODE(&gw_node->list);
 359        gw_node->orig_node = orig_node;
 360        atomic_set(&gw_node->refcount, 1);
 361
 362        spin_lock_bh(&bat_priv->gw.list_lock);
 363        hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.list);
 364        spin_unlock_bh(&bat_priv->gw.list_lock);
 365
 366        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 367                   "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
 368                   orig_node->orig,
 369                   ntohl(gateway->bandwidth_down) / 10,
 370                   ntohl(gateway->bandwidth_down) % 10,
 371                   ntohl(gateway->bandwidth_up) / 10,
 372                   ntohl(gateway->bandwidth_up) % 10);
 373}
 374
 375/**
 376 * batadv_gw_node_get - retrieve gateway node from list of available gateways
 377 * @bat_priv: the bat priv with all the soft interface information
 378 * @orig_node: originator announcing gateway capabilities
 379 *
 380 * Returns gateway node if found or NULL otherwise.
 381 */
 382static struct batadv_gw_node *
 383batadv_gw_node_get(struct batadv_priv *bat_priv,
 384                   struct batadv_orig_node *orig_node)
 385{
 386        struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
 387
 388        rcu_read_lock();
 389        hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.list, list) {
 390                if (gw_node_tmp->orig_node != orig_node)
 391                        continue;
 392
 393                if (gw_node_tmp->deleted)
 394                        continue;
 395
 396                if (!atomic_inc_not_zero(&gw_node_tmp->refcount))
 397                        continue;
 398
 399                gw_node = gw_node_tmp;
 400                break;
 401        }
 402        rcu_read_unlock();
 403
 404        return gw_node;
 405}
 406
 407/**
 408 * batadv_gw_node_update - update list of available gateways with changed
 409 *  bandwidth information
 410 * @bat_priv: the bat priv with all the soft interface information
 411 * @orig_node: originator announcing gateway capabilities
 412 * @gateway: announced bandwidth information
 413 */
 414void batadv_gw_node_update(struct batadv_priv *bat_priv,
 415                           struct batadv_orig_node *orig_node,
 416                           struct batadv_tvlv_gateway_data *gateway)
 417{
 418        struct batadv_gw_node *gw_node, *curr_gw = NULL;
 419
 420        gw_node = batadv_gw_node_get(bat_priv, orig_node);
 421        if (!gw_node) {
 422                batadv_gw_node_add(bat_priv, orig_node, gateway);
 423                goto out;
 424        }
 425
 426        if ((gw_node->bandwidth_down == ntohl(gateway->bandwidth_down)) &&
 427            (gw_node->bandwidth_up == ntohl(gateway->bandwidth_up)))
 428                goto out;
 429
 430        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 431                   "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n",
 432                   orig_node->orig,
 433                   gw_node->bandwidth_down / 10,
 434                   gw_node->bandwidth_down % 10,
 435                   gw_node->bandwidth_up / 10,
 436                   gw_node->bandwidth_up % 10,
 437                   ntohl(gateway->bandwidth_down) / 10,
 438                   ntohl(gateway->bandwidth_down) % 10,
 439                   ntohl(gateway->bandwidth_up) / 10,
 440                   ntohl(gateway->bandwidth_up) % 10);
 441
 442        gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
 443        gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
 444
 445        gw_node->deleted = 0;
 446        if (ntohl(gateway->bandwidth_down) == 0) {
 447                gw_node->deleted = jiffies;
 448                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 449                           "Gateway %pM removed from gateway list\n",
 450                           orig_node->orig);
 451
 452                /* Note: We don't need a NULL check here, since curr_gw never
 453                 * gets dereferenced.
 454                 */
 455                curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 456                if (gw_node == curr_gw)
 457                        batadv_gw_deselect(bat_priv);
 458        }
 459
 460out:
 461        if (curr_gw)
 462                batadv_gw_node_free_ref(curr_gw);
 463        if (gw_node)
 464                batadv_gw_node_free_ref(gw_node);
 465}
 466
 467void batadv_gw_node_delete(struct batadv_priv *bat_priv,
 468                           struct batadv_orig_node *orig_node)
 469{
 470        struct batadv_tvlv_gateway_data gateway;
 471
 472        gateway.bandwidth_down = 0;
 473        gateway.bandwidth_up = 0;
 474
 475        batadv_gw_node_update(bat_priv, orig_node, &gateway);
 476}
 477
 478void batadv_gw_node_purge(struct batadv_priv *bat_priv)
 479{
 480        struct batadv_gw_node *gw_node, *curr_gw;
 481        struct hlist_node *node_tmp;
 482        unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT);
 483        int do_deselect = 0;
 484
 485        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 486
 487        spin_lock_bh(&bat_priv->gw.list_lock);
 488
 489        hlist_for_each_entry_safe(gw_node, node_tmp,
 490                                  &bat_priv->gw.list, list) {
 491                if (((!gw_node->deleted) ||
 492                     (time_before(jiffies, gw_node->deleted + timeout))) &&
 493                    atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE)
 494                        continue;
 495
 496                if (curr_gw == gw_node)
 497                        do_deselect = 1;
 498
 499                hlist_del_rcu(&gw_node->list);
 500                batadv_gw_node_free_ref(gw_node);
 501        }
 502
 503        spin_unlock_bh(&bat_priv->gw.list_lock);
 504
 505        /* gw_deselect() needs to acquire the gw_list_lock */
 506        if (do_deselect)
 507                batadv_gw_deselect(bat_priv);
 508
 509        if (curr_gw)
 510                batadv_gw_node_free_ref(curr_gw);
 511}
 512
 513/* fails if orig_node has no router */
 514static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
 515                                    struct seq_file *seq,
 516                                    const struct batadv_gw_node *gw_node)
 517{
 518        struct batadv_gw_node *curr_gw;
 519        struct batadv_neigh_node *router;
 520        int ret = -1;
 521
 522        router = batadv_orig_node_get_router(gw_node->orig_node);
 523        if (!router)
 524                goto out;
 525
 526        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 527
 528        ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %u.%u/%u.%u MBit\n",
 529                         (curr_gw == gw_node ? "=>" : "  "),
 530                         gw_node->orig_node->orig,
 531                         router->bat_iv.tq_avg, router->addr,
 532                         router->if_incoming->net_dev->name,
 533                         gw_node->bandwidth_down / 10,
 534                         gw_node->bandwidth_down % 10,
 535                         gw_node->bandwidth_up / 10,
 536                         gw_node->bandwidth_up % 10);
 537
 538        batadv_neigh_node_free_ref(router);
 539        if (curr_gw)
 540                batadv_gw_node_free_ref(curr_gw);
 541out:
 542        return ret;
 543}
 544
 545int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
 546{
 547        struct net_device *net_dev = (struct net_device *)seq->private;
 548        struct batadv_priv *bat_priv = netdev_priv(net_dev);
 549        struct batadv_hard_iface *primary_if;
 550        struct batadv_gw_node *gw_node;
 551        int gw_count = 0;
 552
 553        primary_if = batadv_seq_print_text_primary_if_get(seq);
 554        if (!primary_if)
 555                goto out;
 556
 557        seq_printf(seq,
 558                   "      %-12s (%s/%i) %17s [%10s]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
 559                   "Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF",
 560                   BATADV_SOURCE_VERSION, primary_if->net_dev->name,
 561                   primary_if->net_dev->dev_addr, net_dev->name);
 562
 563        rcu_read_lock();
 564        hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
 565                if (gw_node->deleted)
 566                        continue;
 567
 568                /* fails if orig_node has no router */
 569                if (batadv_write_buffer_text(bat_priv, seq, gw_node) < 0)
 570                        continue;
 571
 572                gw_count++;
 573        }
 574        rcu_read_unlock();
 575
 576        if (gw_count == 0)
 577                seq_puts(seq, "No gateways in range ...\n");
 578
 579out:
 580        if (primary_if)
 581                batadv_hardif_free_ref(primary_if);
 582        return 0;
 583}
 584
 585/* this call might reallocate skb data */
 586static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
 587{
 588        int ret = false;
 589        unsigned char *p;
 590        int pkt_len;
 591
 592        if (skb_linearize(skb) < 0)
 593                goto out;
 594
 595        pkt_len = skb_headlen(skb);
 596
 597        if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1)
 598                goto out;
 599
 600        p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET;
 601        pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1;
 602
 603        /* Access the dhcp option lists. Each entry is made up by:
 604         * - octet 1: option type
 605         * - octet 2: option data len (only if type != 255 and 0)
 606         * - octet 3: option data
 607         */
 608        while (*p != 255 && !ret) {
 609                /* p now points to the first octet: option type */
 610                if (*p == 53) {
 611                        /* type 53 is the message type option.
 612                         * Jump the len octet and go to the data octet
 613                         */
 614                        if (pkt_len < 2)
 615                                goto out;
 616                        p += 2;
 617
 618                        /* check if the message type is what we need */
 619                        if (*p == BATADV_DHCP_REQUEST)
 620                                ret = true;
 621                        break;
 622                } else if (*p == 0) {
 623                        /* option type 0 (padding), just go forward */
 624                        if (pkt_len < 1)
 625                                goto out;
 626                        pkt_len--;
 627                        p++;
 628                } else {
 629                        /* This is any other option. So we get the length... */
 630                        if (pkt_len < 1)
 631                                goto out;
 632                        pkt_len--;
 633                        p++;
 634
 635                        /* ...and then we jump over the data */
 636                        if (pkt_len < 1 + (*p))
 637                                goto out;
 638                        pkt_len -= 1 + (*p);
 639                        p += 1 + (*p);
 640                }
 641        }
 642out:
 643        return ret;
 644}
 645
 646/* this call might reallocate skb data */
 647bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 648{
 649        struct ethhdr *ethhdr;
 650        struct iphdr *iphdr;
 651        struct ipv6hdr *ipv6hdr;
 652        struct udphdr *udphdr;
 653        struct vlan_ethhdr *vhdr;
 654        __be16 proto;
 655
 656        /* check for ethernet header */
 657        if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
 658                return false;
 659        ethhdr = (struct ethhdr *)skb->data;
 660        proto = ethhdr->h_proto;
 661        *header_len += ETH_HLEN;
 662
 663        /* check for initial vlan header */
 664        if (proto == htons(ETH_P_8021Q)) {
 665                if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
 666                        return false;
 667
 668                vhdr = (struct vlan_ethhdr *)skb->data;
 669                proto = vhdr->h_vlan_encapsulated_proto;
 670                *header_len += VLAN_HLEN;
 671        }
 672
 673        /* check for ip header */
 674        switch (proto) {
 675        case htons(ETH_P_IP):
 676                if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
 677                        return false;
 678                iphdr = (struct iphdr *)(skb->data + *header_len);
 679                *header_len += iphdr->ihl * 4;
 680
 681                /* check for udp header */
 682                if (iphdr->protocol != IPPROTO_UDP)
 683                        return false;
 684
 685                break;
 686        case htons(ETH_P_IPV6):
 687                if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
 688                        return false;
 689                ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
 690                *header_len += sizeof(*ipv6hdr);
 691
 692                /* check for udp header */
 693                if (ipv6hdr->nexthdr != IPPROTO_UDP)
 694                        return false;
 695
 696                break;
 697        default:
 698                return false;
 699        }
 700
 701        if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
 702                return false;
 703
 704        /* skb->data might have been reallocated by pskb_may_pull() */
 705        ethhdr = (struct ethhdr *)skb->data;
 706        if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
 707                ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
 708
 709        udphdr = (struct udphdr *)(skb->data + *header_len);
 710        *header_len += sizeof(*udphdr);
 711
 712        /* check for bootp port */
 713        if ((proto == htons(ETH_P_IP)) &&
 714            (udphdr->dest != htons(67)))
 715                return false;
 716
 717        if ((proto == htons(ETH_P_IPV6)) &&
 718            (udphdr->dest != htons(547)))
 719                return false;
 720
 721        return true;
 722}
 723
 724/**
 725 * batadv_gw_out_of_range - check if the dhcp request destination is the best gw
 726 * @bat_priv: the bat priv with all the soft interface information
 727 * @skb: the outgoing packet
 728 *
 729 * Check if the skb is a DHCP request and if it is sent to the current best GW
 730 * server. Due to topology changes it may be the case that the GW server
 731 * previously selected is not the best one anymore.
 732 *
 733 * Returns true if the packet destination is unicast and it is not the best gw,
 734 * false otherwise.
 735 *
 736 * This call might reallocate skb data.
 737 */
 738bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 739                            struct sk_buff *skb)
 740{
 741        struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 742        struct batadv_orig_node *orig_dst_node = NULL;
 743        struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
 744        struct ethhdr *ethhdr;
 745        bool ret, out_of_range = false;
 746        unsigned int header_len = 0;
 747        uint8_t curr_tq_avg;
 748        unsigned short vid;
 749
 750        vid = batadv_get_vid(skb, 0);
 751
 752        ret = batadv_gw_is_dhcp_target(skb, &header_len);
 753        if (!ret)
 754                goto out;
 755
 756        ethhdr = (struct ethhdr *)skb->data;
 757        orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
 758                                                 ethhdr->h_dest, vid);
 759        if (!orig_dst_node)
 760                goto out;
 761
 762        gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
 763        if (!gw_node->bandwidth_down == 0)
 764                goto out;
 765
 766        ret = batadv_is_type_dhcprequest(skb, header_len);
 767        if (!ret)
 768                goto out;
 769
 770        switch (atomic_read(&bat_priv->gw_mode)) {
 771        case BATADV_GW_MODE_SERVER:
 772                /* If we are a GW then we are our best GW. We can artificially
 773                 * set the tq towards ourself as the maximum value
 774                 */
 775                curr_tq_avg = BATADV_TQ_MAX_VALUE;
 776                break;
 777        case BATADV_GW_MODE_CLIENT:
 778                curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 779                if (!curr_gw)
 780                        goto out;
 781
 782                /* packet is going to our gateway */
 783                if (curr_gw->orig_node == orig_dst_node)
 784                        goto out;
 785
 786                /* If the dhcp packet has been sent to a different gw,
 787                 * we have to evaluate whether the old gw is still
 788                 * reliable enough
 789                 */
 790                neigh_curr = batadv_find_router(bat_priv, curr_gw->orig_node,
 791                                                NULL);
 792                if (!neigh_curr)
 793                        goto out;
 794
 795                curr_tq_avg = neigh_curr->bat_iv.tq_avg;
 796                break;
 797        case BATADV_GW_MODE_OFF:
 798        default:
 799                goto out;
 800        }
 801
 802        neigh_old = batadv_find_router(bat_priv, orig_dst_node, NULL);
 803        if (!neigh_old)
 804                goto out;
 805
 806        if (curr_tq_avg - neigh_old->bat_iv.tq_avg > BATADV_GW_THRESHOLD)
 807                out_of_range = true;
 808
 809out:
 810        if (orig_dst_node)
 811                batadv_orig_node_free_ref(orig_dst_node);
 812        if (curr_gw)
 813                batadv_gw_node_free_ref(curr_gw);
 814        if (gw_node)
 815                batadv_gw_node_free_ref(gw_node);
 816        if (neigh_old)
 817                batadv_neigh_node_free_ref(neigh_old);
 818        if (neigh_curr)
 819                batadv_neigh_node_free_ref(neigh_curr);
 820        return out_of_range;
 821}
 822