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