Merge tag 'x86-fpu-2020-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[linux-block.git] / net / batman-adv / gateway_client.c
CommitLineData
7db7d9f3 1// SPDX-License-Identifier: GPL-2.0
68e039f9 2/* Copyright (C) 2009-2020 B.A.T.M.A.N. contributors:
c6c8fea2
SE
3 *
4 * Marek Lindner
c6c8fea2
SE
5 */
6
c6c8fea2 7#include "gateway_client.h"
1e2c2a4f
SE
8#include "main.h"
9
10#include <linux/atomic.h>
11#include <linux/byteorder/generic.h>
d7129daf 12#include <linux/errno.h>
1e2c2a4f 13#include <linux/etherdevice.h>
b92b94ac 14#include <linux/gfp.h>
1e2c2a4f
SE
15#include <linux/if_ether.h>
16#include <linux/if_vlan.h>
17#include <linux/in.h>
18#include <linux/ip.h>
19#include <linux/ipv6.h>
1e2c2a4f 20#include <linux/kernel.h>
e7aed321 21#include <linux/kref.h>
1e2c2a4f 22#include <linux/list.h>
dff9bc42 23#include <linux/lockdep.h>
1e2c2a4f 24#include <linux/netdevice.h>
d7129daf 25#include <linux/netlink.h>
1e2c2a4f
SE
26#include <linux/rculist.h>
27#include <linux/rcupdate.h>
28#include <linux/seq_file.h>
29#include <linux/skbuff.h>
30#include <linux/slab.h>
31#include <linux/spinlock.h>
32#include <linux/stddef.h>
33#include <linux/udp.h>
d7129daf 34#include <net/sock.h>
fec149f5 35#include <uapi/linux/batadv_packet.h>
d7129daf 36#include <uapi/linux/batman_adv.h>
1e2c2a4f 37
c6c8fea2 38#include "hard-interface.h"
ba412080 39#include "log.h"
d7129daf 40#include "netlink.h"
57f0c07c 41#include "originator.h"
43676ab5 42#include "routing.h"
d7129daf 43#include "soft-interface.h"
1e2c2a4f 44#include "translation-table.h"
c6c8fea2 45
6c413b1c
AQ
46/* These are the offsets of the "hw type" and "hw address length" in the dhcp
47 * packet starting at the beginning of the dhcp header
9cfc7bd6 48 */
6c413b1c
AQ
49#define BATADV_DHCP_HTYPE_OFFSET 1
50#define BATADV_DHCP_HLEN_OFFSET 2
51/* Value of htype representing Ethernet */
52#define BATADV_DHCP_HTYPE_ETHERNET 0x01
53/* This is the offset of the "chaddr" field in the dhcp packet starting at the
54 * beginning of the dhcp header
55 */
56#define BATADV_DHCP_CHADDR_OFFSET 28
43676ab5 57
e7aed321 58/**
7e9a8c2c
SE
59 * batadv_gw_node_release() - release gw_node from lists and queue for free
60 * after rcu grace period
e7aed321
SE
61 * @ref: kref pointer of the gw_node
62 */
63static void batadv_gw_node_release(struct kref *ref)
64{
65 struct batadv_gw_node *gw_node;
66
67 gw_node = container_of(ref, struct batadv_gw_node, refcount);
68
5d967310 69 batadv_orig_node_put(gw_node->orig_node);
e7aed321
SE
70 kfree_rcu(gw_node, rcu);
71}
72
73/**
7e9a8c2c
SE
74 * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release
75 * it
e7aed321
SE
76 * @gw_node: gateway node to free
77 */
34d99cfe 78void batadv_gw_node_put(struct batadv_gw_node *gw_node)
c6c8fea2 79{
e7aed321 80 kref_put(&gw_node->refcount, batadv_gw_node_release);
c6c8fea2
SE
81}
82
ff15c27c
SE
83/**
84 * batadv_gw_get_selected_gw_node() - Get currently selected gateway
85 * @bat_priv: the bat priv with all the soft interface information
86 *
87 * Return: selected gateway (with increased refcnt), NULL on errors
88 */
34d99cfe 89struct batadv_gw_node *
56303d34 90batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv)
c6c8fea2 91{
56303d34 92 struct batadv_gw_node *gw_node;
c6c8fea2 93
5d02b3cd 94 rcu_read_lock();
807736f6 95 gw_node = rcu_dereference(bat_priv->gw.curr_gw);
c4aac1ab 96 if (!gw_node)
7b36e8ee 97 goto out;
c6c8fea2 98
e7aed321 99 if (!kref_get_unless_zero(&gw_node->refcount))
c4aac1ab 100 gw_node = NULL;
43c70ad5 101
5d02b3cd
LL
102out:
103 rcu_read_unlock();
c4aac1ab 104 return gw_node;
c6c8fea2
SE
105}
106
ff15c27c
SE
107/**
108 * batadv_gw_get_selected_orig() - Get originator of currently selected gateway
109 * @bat_priv: the bat priv with all the soft interface information
110 *
111 * Return: orig_node of selected gateway (with increased refcnt), NULL on errors
112 */
56303d34
SE
113struct batadv_orig_node *
114batadv_gw_get_selected_orig(struct batadv_priv *bat_priv)
c6c8fea2 115{
56303d34
SE
116 struct batadv_gw_node *gw_node;
117 struct batadv_orig_node *orig_node = NULL;
c6c8fea2 118
1409a834 119 gw_node = batadv_gw_get_selected_gw_node(bat_priv);
c4aac1ab
ML
120 if (!gw_node)
121 goto out;
122
123 rcu_read_lock();
124 orig_node = gw_node->orig_node;
125 if (!orig_node)
126 goto unlock;
127
7c124391 128 if (!kref_get_unless_zero(&orig_node->refcount))
c4aac1ab 129 orig_node = NULL;
c6c8fea2 130
c4aac1ab
ML
131unlock:
132 rcu_read_unlock();
133out:
c6c8fea2 134 if (gw_node)
3a01743d 135 batadv_gw_node_put(gw_node);
c4aac1ab 136 return orig_node;
c6c8fea2
SE
137}
138
56303d34
SE
139static void batadv_gw_select(struct batadv_priv *bat_priv,
140 struct batadv_gw_node *new_gw_node)
c6c8fea2 141{
56303d34 142 struct batadv_gw_node *curr_gw_node;
c6c8fea2 143
807736f6 144 spin_lock_bh(&bat_priv->gw.list_lock);
c4aac1ab 145
a08d497d
SE
146 if (new_gw_node)
147 kref_get(&new_gw_node->refcount);
c6c8fea2 148
cf78bb0b
AQ
149 curr_gw_node = rcu_replace_pointer(bat_priv->gw.curr_gw, new_gw_node,
150 true);
25b6d3c1
ML
151
152 if (curr_gw_node)
3a01743d 153 batadv_gw_node_put(curr_gw_node);
c4aac1ab 154
807736f6 155 spin_unlock_bh(&bat_priv->gw.list_lock);
c4aac1ab
ML
156}
157
4e820e72 158/**
7e9a8c2c 159 * batadv_gw_reselect() - force a gateway reselection
4e820e72
AQ
160 * @bat_priv: the bat priv with all the soft interface information
161 *
162 * Set a flag to remind the GW component to perform a new gateway reselection.
163 * However this function does not ensure that the current gateway is going to be
164 * deselected. The reselection mechanism may elect the same gateway once again.
165 *
166 * This means that invoking batadv_gw_reselect() does not guarantee a gateway
167 * change and therefore a uevent is not necessarily expected.
168 */
169void batadv_gw_reselect(struct batadv_priv *bat_priv)
c4aac1ab 170{
807736f6 171 atomic_set(&bat_priv->gw.reselect, 1);
c6c8fea2
SE
172}
173
c6eaa3f0 174/**
7e9a8c2c 175 * batadv_gw_check_client_stop() - check if client mode has been switched off
c6eaa3f0
AQ
176 * @bat_priv: the bat priv with all the soft interface information
177 *
178 * This function assumes the caller has checked that the gw state *is actually
179 * changing*. This function is not supposed to be called when there is no state
180 * change.
181 */
182void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
183{
184 struct batadv_gw_node *curr_gw;
185
3a24a63e 186 if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
c6eaa3f0
AQ
187 return;
188
189 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
190 if (!curr_gw)
191 return;
192
f3163181
AQ
193 /* deselect the current gateway so that next time that client mode is
194 * enabled a proper GW_ADD event can be sent
195 */
196 batadv_gw_select(bat_priv, NULL);
197
c6eaa3f0
AQ
198 /* if batman-adv is switching the gw client mode off and a gateway was
199 * already selected, send a DEL uevent
200 */
201 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL, NULL);
202
3a01743d 203 batadv_gw_node_put(curr_gw);
c6eaa3f0
AQ
204}
205
ff15c27c
SE
206/**
207 * batadv_gw_election() - Elect the best gateway
208 * @bat_priv: the bat priv with all the soft interface information
209 */
56303d34 210void batadv_gw_election(struct batadv_priv *bat_priv)
2265c141 211{
4f248cff
SE
212 struct batadv_gw_node *curr_gw = NULL;
213 struct batadv_gw_node *next_gw = NULL;
56303d34 214 struct batadv_neigh_node *router = NULL;
89652331 215 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
19595e05 216 char gw_addr[18] = { '\0' };
2265c141 217
3a24a63e 218 if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
2265c141
AQ
219 goto out;
220
34d99cfe
AQ
221 if (!bat_priv->algo_ops->gw.get_best_gw_node)
222 goto out;
223
1409a834 224 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
2265c141 225
807736f6 226 if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw)
caa0bf64
ML
227 goto out;
228
34d99cfe
AQ
229 /* if gw.reselect is set to 1 it means that a previous call to
230 * gw.is_eligible() said that we have a new best GW, therefore it can
231 * now be picked from the list and selected
232 */
233 next_gw = bat_priv->algo_ops->gw.get_best_gw_node(bat_priv);
2265c141
AQ
234
235 if (curr_gw == next_gw)
236 goto out;
237
238 if (next_gw) {
19595e05
AQ
239 sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
240
7351a482
SW
241 router = batadv_orig_router_get(next_gw->orig_node,
242 BATADV_IF_DEFAULT);
2265c141 243 if (!router) {
4e820e72 244 batadv_gw_reselect(bat_priv);
2265c141
AQ
245 goto out;
246 }
89652331
SW
247
248 router_ifinfo = batadv_neigh_ifinfo_get(router,
249 BATADV_IF_DEFAULT);
250 if (!router_ifinfo) {
251 batadv_gw_reselect(bat_priv);
252 goto out;
253 }
c6c8fea2
SE
254 }
255
825ffe1f 256 if (curr_gw && !next_gw) {
39c75a51 257 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bf 258 "Removing selected gateway - no gateway in range\n");
39c75a51
SE
259 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL,
260 NULL);
825ffe1f 261 } else if (!curr_gw && next_gw) {
39c75a51 262 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
414254e3 263 "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
1eda58bf 264 next_gw->orig_node->orig,
414254e3
ML
265 next_gw->bandwidth_down / 10,
266 next_gw->bandwidth_down % 10,
267 next_gw->bandwidth_up / 10,
89652331
SW
268 next_gw->bandwidth_up % 10,
269 router_ifinfo->bat_iv.tq_avg);
39c75a51
SE
270 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
271 gw_addr);
2265c141 272 } else {
39c75a51 273 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
414254e3 274 "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
1eda58bf 275 next_gw->orig_node->orig,
414254e3
ML
276 next_gw->bandwidth_down / 10,
277 next_gw->bandwidth_down % 10,
278 next_gw->bandwidth_up / 10,
89652331
SW
279 next_gw->bandwidth_up % 10,
280 router_ifinfo->bat_iv.tq_avg);
39c75a51
SE
281 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
282 gw_addr);
2265c141
AQ
283 }
284
1409a834 285 batadv_gw_select(bat_priv, next_gw);
2265c141 286
c4aac1ab
ML
287out:
288 if (curr_gw)
3a01743d 289 batadv_gw_node_put(curr_gw);
2265c141 290 if (next_gw)
3a01743d 291 batadv_gw_node_put(next_gw);
2265c141 292 if (router)
25bb2509 293 batadv_neigh_node_put(router);
89652331 294 if (router_ifinfo)
044fa3ae 295 batadv_neigh_ifinfo_put(router_ifinfo);
c6c8fea2
SE
296}
297
ff15c27c
SE
298/**
299 * batadv_gw_check_election() - Elect orig node as best gateway when eligible
300 * @bat_priv: the bat priv with all the soft interface information
301 * @orig_node: orig node which is to be checked
302 */
56303d34
SE
303void batadv_gw_check_election(struct batadv_priv *bat_priv,
304 struct batadv_orig_node *orig_node)
c6c8fea2 305{
56303d34 306 struct batadv_orig_node *curr_gw_orig;
34d99cfe
AQ
307
308 /* abort immediately if the routing algorithm does not support gateway
309 * election
310 */
311 if (!bat_priv->algo_ops->gw.is_eligible)
312 return;
c6c8fea2 313
7cf06bc6 314 curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
57f0c07c 315 if (!curr_gw_orig)
4e820e72 316 goto reselect;
c6c8fea2 317
c6c8fea2 318 /* this node already is the gateway */
57f0c07c 319 if (curr_gw_orig == orig_node)
e1a5382f 320 goto out;
c6c8fea2 321
34d99cfe
AQ
322 if (!bat_priv->algo_ops->gw.is_eligible(bat_priv, curr_gw_orig,
323 orig_node))
e1a5382f 324 goto out;
5d02b3cd 325
4e820e72
AQ
326reselect:
327 batadv_gw_reselect(bat_priv);
5d02b3cd 328out:
57f0c07c 329 if (curr_gw_orig)
5d967310 330 batadv_orig_node_put(curr_gw_orig);
c6c8fea2
SE
331}
332
414254e3 333/**
7e9a8c2c 334 * batadv_gw_node_add() - add gateway node to list of available gateways
414254e3
ML
335 * @bat_priv: the bat priv with all the soft interface information
336 * @orig_node: originator announcing gateway capabilities
337 * @gateway: announced bandwidth information
dff9bc42
SE
338 *
339 * Has to be called with the appropriate locks being acquired
340 * (gw.list_lock).
414254e3 341 */
56303d34
SE
342static void batadv_gw_node_add(struct batadv_priv *bat_priv,
343 struct batadv_orig_node *orig_node,
414254e3 344 struct batadv_tvlv_gateway_data *gateway)
c6c8fea2 345{
56303d34 346 struct batadv_gw_node *gw_node;
414254e3 347
dff9bc42
SE
348 lockdep_assert_held(&bat_priv->gw.list_lock);
349
414254e3
ML
350 if (gateway->bandwidth_down == 0)
351 return;
c6c8fea2 352
704509b8 353 gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
c3ba37a7 354 if (!gw_node)
c6c8fea2
SE
355 return;
356
f665fa7e 357 kref_init(&gw_node->refcount);
c6c8fea2 358 INIT_HLIST_NODE(&gw_node->list);
55db2d59 359 kref_get(&orig_node->refcount);
c6c8fea2 360 gw_node->orig_node = orig_node;
27a4d5ef
SW
361 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
362 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
c6c8fea2 363
f665fa7e 364 kref_get(&gw_node->refcount);
70ea5cee 365 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.gateway_list);
9264c85c 366 bat_priv->gw.generation++;
c6c8fea2 367
39c75a51 368 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
414254e3
ML
369 "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
370 orig_node->orig,
371 ntohl(gateway->bandwidth_down) / 10,
372 ntohl(gateway->bandwidth_down) % 10,
373 ntohl(gateway->bandwidth_up) / 10,
374 ntohl(gateway->bandwidth_up) % 10);
f665fa7e
SE
375
376 /* don't return reference to new gw_node */
377 batadv_gw_node_put(gw_node);
c6c8fea2
SE
378}
379
414254e3 380/**
7e9a8c2c 381 * batadv_gw_node_get() - retrieve gateway node from list of available gateways
414254e3
ML
382 * @bat_priv: the bat priv with all the soft interface information
383 * @orig_node: originator announcing gateway capabilities
384 *
62fe710f 385 * Return: gateway node if found or NULL otherwise.
414254e3 386 */
50164d8f
AQ
387struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv,
388 struct batadv_orig_node *orig_node)
c6c8fea2 389{
414254e3 390 struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
c6c8fea2
SE
391
392 rcu_read_lock();
70ea5cee
SE
393 hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.gateway_list,
394 list) {
414254e3 395 if (gw_node_tmp->orig_node != orig_node)
c6c8fea2
SE
396 continue;
397
e7aed321 398 if (!kref_get_unless_zero(&gw_node_tmp->refcount))
414254e3 399 continue;
c6c8fea2 400
414254e3
ML
401 gw_node = gw_node_tmp;
402 break;
403 }
404 rcu_read_unlock();
c6c8fea2 405
414254e3
ML
406 return gw_node;
407}
c6c8fea2 408
414254e3 409/**
7e9a8c2c 410 * batadv_gw_node_update() - update list of available gateways with changed
414254e3
ML
411 * bandwidth information
412 * @bat_priv: the bat priv with all the soft interface information
413 * @orig_node: originator announcing gateway capabilities
414 * @gateway: announced bandwidth information
415 */
416void batadv_gw_node_update(struct batadv_priv *bat_priv,
417 struct batadv_orig_node *orig_node,
418 struct batadv_tvlv_gateway_data *gateway)
419{
420 struct batadv_gw_node *gw_node, *curr_gw = NULL;
421
dff9bc42 422 spin_lock_bh(&bat_priv->gw.list_lock);
414254e3
ML
423 gw_node = batadv_gw_node_get(bat_priv, orig_node);
424 if (!gw_node) {
425 batadv_gw_node_add(bat_priv, orig_node, gateway);
dff9bc42 426 spin_unlock_bh(&bat_priv->gw.list_lock);
414254e3 427 goto out;
c6c8fea2 428 }
dff9bc42 429 spin_unlock_bh(&bat_priv->gw.list_lock);
c6c8fea2 430
825ffe1f
SE
431 if (gw_node->bandwidth_down == ntohl(gateway->bandwidth_down) &&
432 gw_node->bandwidth_up == ntohl(gateway->bandwidth_up))
414254e3 433 goto out;
c6c8fea2 434
414254e3
ML
435 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
436 "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n",
437 orig_node->orig,
438 gw_node->bandwidth_down / 10,
439 gw_node->bandwidth_down % 10,
440 gw_node->bandwidth_up / 10,
441 gw_node->bandwidth_up % 10,
442 ntohl(gateway->bandwidth_down) / 10,
443 ntohl(gateway->bandwidth_down) % 10,
444 ntohl(gateway->bandwidth_up) / 10,
445 ntohl(gateway->bandwidth_up) % 10);
446
447 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
448 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
449
414254e3 450 if (ntohl(gateway->bandwidth_down) == 0) {
414254e3
ML
451 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
452 "Gateway %pM removed from gateway list\n",
453 orig_node->orig);
c4aac1ab 454
414254e3
ML
455 /* Note: We don't need a NULL check here, since curr_gw never
456 * gets dereferenced.
457 */
bd3524c1 458 spin_lock_bh(&bat_priv->gw.list_lock);
c18bdd01
SE
459 if (!hlist_unhashed(&gw_node->list)) {
460 hlist_del_init_rcu(&gw_node->list);
3a01743d 461 batadv_gw_node_put(gw_node);
9264c85c 462 bat_priv->gw.generation++;
c18bdd01 463 }
bd3524c1
SW
464 spin_unlock_bh(&bat_priv->gw.list_lock);
465
414254e3
ML
466 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
467 if (gw_node == curr_gw)
4e820e72 468 batadv_gw_reselect(bat_priv);
bd3524c1
SW
469
470 if (curr_gw)
3a01743d 471 batadv_gw_node_put(curr_gw);
414254e3 472 }
71e4aa9c 473
414254e3 474out:
414254e3 475 if (gw_node)
3a01743d 476 batadv_gw_node_put(gw_node);
c6c8fea2
SE
477}
478
ff15c27c
SE
479/**
480 * batadv_gw_node_delete() - Remove orig_node from gateway list
481 * @bat_priv: the bat priv with all the soft interface information
482 * @orig_node: orig node which is currently in process of being removed
483 */
56303d34
SE
484void batadv_gw_node_delete(struct batadv_priv *bat_priv,
485 struct batadv_orig_node *orig_node)
c6c8fea2 486{
414254e3
ML
487 struct batadv_tvlv_gateway_data gateway;
488
489 gateway.bandwidth_down = 0;
490 gateway.bandwidth_up = 0;
491
492 batadv_gw_node_update(bat_priv, orig_node, &gateway);
c6c8fea2
SE
493}
494
ff15c27c
SE
495/**
496 * batadv_gw_node_free() - Free gateway information from soft interface
497 * @bat_priv: the bat priv with all the soft interface information
498 */
bd3524c1 499void batadv_gw_node_free(struct batadv_priv *bat_priv)
c6c8fea2 500{
bd3524c1 501 struct batadv_gw_node *gw_node;
b67bfe0d 502 struct hlist_node *node_tmp;
c6c8fea2 503
807736f6 504 spin_lock_bh(&bat_priv->gw.list_lock);
b67bfe0d 505 hlist_for_each_entry_safe(gw_node, node_tmp,
70ea5cee 506 &bat_priv->gw.gateway_list, list) {
bd3524c1 507 hlist_del_init_rcu(&gw_node->list);
3a01743d 508 batadv_gw_node_put(gw_node);
9264c85c 509 bat_priv->gw.generation++;
c6c8fea2 510 }
807736f6 511 spin_unlock_bh(&bat_priv->gw.list_lock);
c6c8fea2
SE
512}
513
dc1cbd14 514#ifdef CONFIG_BATMAN_ADV_DEBUGFS
ff15c27c
SE
515
516/**
517 * batadv_gw_client_seq_print_text() - Print the gateway table in a seq file
518 * @seq: seq file to print on
519 * @offset: not used
520 *
521 * Return: always 0
522 */
7cf06bc6 523int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
c6c8fea2
SE
524{
525 struct net_device *net_dev = (struct net_device *)seq->private;
56303d34
SE
526 struct batadv_priv *bat_priv = netdev_priv(net_dev);
527 struct batadv_hard_iface *primary_if;
c6c8fea2 528
30da63a6
ML
529 primary_if = batadv_seq_print_text_primary_if_get(seq);
530 if (!primary_if)
34d99cfe 531 return 0;
c6c8fea2 532
34d99cfe 533 seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
42d0b044 534 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
34d99cfe
AQ
535 primary_if->net_dev->dev_addr, net_dev->name,
536 bat_priv->algo_ops->name);
c6c8fea2 537
34d99cfe 538 batadv_hardif_put(primary_if);
c6c8fea2 539
34d99cfe
AQ
540 if (!bat_priv->algo_ops->gw.print) {
541 seq_puts(seq,
542 "No printing function for this routing protocol\n");
543 return 0;
c6c8fea2 544 }
c6c8fea2 545
34d99cfe 546 bat_priv->algo_ops->gw.print(bat_priv, seq);
c6c8fea2 547
30da63a6 548 return 0;
c6c8fea2 549}
dc1cbd14 550#endif
c6c8fea2 551
d7129daf 552/**
7e9a8c2c 553 * batadv_gw_dump() - Dump gateways into a message
d7129daf
SE
554 * @msg: Netlink message to dump into
555 * @cb: Control block containing additional options
556 *
557 * Return: Error code, or length of message
558 */
559int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb)
560{
561 struct batadv_hard_iface *primary_if = NULL;
562 struct net *net = sock_net(cb->skb->sk);
563 struct net_device *soft_iface;
564 struct batadv_priv *bat_priv;
565 int ifindex;
566 int ret;
567
568 ifindex = batadv_netlink_get_ifindex(cb->nlh,
569 BATADV_ATTR_MESH_IFINDEX);
570 if (!ifindex)
571 return -EINVAL;
572
573 soft_iface = dev_get_by_index(net, ifindex);
574 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
575 ret = -ENODEV;
576 goto out;
577 }
578
579 bat_priv = netdev_priv(soft_iface);
580
581 primary_if = batadv_primary_if_get_selected(bat_priv);
582 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
583 ret = -ENOENT;
584 goto out;
585 }
586
587 if (!bat_priv->algo_ops->gw.dump) {
588 ret = -EOPNOTSUPP;
589 goto out;
590 }
591
592 bat_priv->algo_ops->gw.dump(msg, cb, bat_priv);
593
594 ret = msg->len;
595
596out:
597 if (primary_if)
598 batadv_hardif_put(primary_if);
599 if (soft_iface)
600 dev_put(soft_iface);
601
602 return ret;
603}
604
6c413b1c 605/**
7e9a8c2c 606 * batadv_gw_dhcp_recipient_get() - check if a packet is a DHCP message
6c413b1c
AQ
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 *
62fe710f
SE
612 * This function may re-allocate the data buffer of the skb passed as argument.
613 *
614 * Return:
6c413b1c
AQ
615 * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
616 * while parsing it
617 * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
618 * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
6c413b1c
AQ
619 */
620enum batadv_dhcp_recipient
621batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
6b5e971a 622 u8 *chaddr)
c6c8fea2 623{
6c413b1c 624 enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
c6c8fea2
SE
625 struct ethhdr *ethhdr;
626 struct iphdr *iphdr;
627 struct ipv6hdr *ipv6hdr;
628 struct udphdr *udphdr;
f7f8ed56 629 struct vlan_ethhdr *vhdr;
6c413b1c 630 int chaddr_offset;
f7f8ed56 631 __be16 proto;
6b5e971a 632 u8 *p;
c6c8fea2
SE
633
634 /* check for ethernet header */
be7af5cf 635 if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
6c413b1c
AQ
636 return BATADV_DHCP_NO;
637
927c2ed7 638 ethhdr = eth_hdr(skb);
f7f8ed56 639 proto = ethhdr->h_proto;
be7af5cf 640 *header_len += ETH_HLEN;
c6c8fea2
SE
641
642 /* check for initial vlan header */
f7f8ed56 643 if (proto == htons(ETH_P_8021Q)) {
be7af5cf 644 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
6c413b1c 645 return BATADV_DHCP_NO;
f7f8ed56 646
927c2ed7 647 vhdr = vlan_eth_hdr(skb);
f7f8ed56 648 proto = vhdr->h_vlan_encapsulated_proto;
be7af5cf 649 *header_len += VLAN_HLEN;
c6c8fea2
SE
650 }
651
652 /* check for ip header */
f7f8ed56
AQ
653 switch (proto) {
654 case htons(ETH_P_IP):
be7af5cf 655 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
6c413b1c
AQ
656 return BATADV_DHCP_NO;
657
be7af5cf
ML
658 iphdr = (struct iphdr *)(skb->data + *header_len);
659 *header_len += iphdr->ihl * 4;
c6c8fea2
SE
660
661 /* check for udp header */
662 if (iphdr->protocol != IPPROTO_UDP)
6c413b1c 663 return BATADV_DHCP_NO;
c6c8fea2
SE
664
665 break;
f7f8ed56 666 case htons(ETH_P_IPV6):
be7af5cf 667 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
6c413b1c
AQ
668 return BATADV_DHCP_NO;
669
be7af5cf
ML
670 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
671 *header_len += sizeof(*ipv6hdr);
c6c8fea2
SE
672
673 /* check for udp header */
674 if (ipv6hdr->nexthdr != IPPROTO_UDP)
6c413b1c 675 return BATADV_DHCP_NO;
c6c8fea2
SE
676
677 break;
678 default:
6c413b1c 679 return BATADV_DHCP_NO;
c6c8fea2
SE
680 }
681
be7af5cf 682 if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
6c413b1c 683 return BATADV_DHCP_NO;
9d2c9488 684
be7af5cf
ML
685 udphdr = (struct udphdr *)(skb->data + *header_len);
686 *header_len += sizeof(*udphdr);
c6c8fea2
SE
687
688 /* check for bootp port */
6c413b1c
AQ
689 switch (proto) {
690 case htons(ETH_P_IP):
691 if (udphdr->dest == htons(67))
692 ret = BATADV_DHCP_TO_SERVER;
693 else if (udphdr->source == htons(67))
694 ret = BATADV_DHCP_TO_CLIENT;
695 break;
696 case htons(ETH_P_IPV6):
697 if (udphdr->dest == htons(547))
698 ret = BATADV_DHCP_TO_SERVER;
699 else if (udphdr->source == htons(547))
700 ret = BATADV_DHCP_TO_CLIENT;
701 break;
702 }
c6c8fea2 703
6c413b1c
AQ
704 chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
705 /* store the client address if the message is going to a client */
303216e7
SE
706 if (ret == BATADV_DHCP_TO_CLIENT) {
707 if (!pskb_may_pull(skb, chaddr_offset + ETH_ALEN))
708 return BATADV_DHCP_NO;
709
6c413b1c
AQ
710 /* check if the DHCP packet carries an Ethernet DHCP */
711 p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
712 if (*p != BATADV_DHCP_HTYPE_ETHERNET)
713 return BATADV_DHCP_NO;
714
715 /* check if the DHCP packet carries a valid Ethernet address */
716 p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
717 if (*p != ETH_ALEN)
718 return BATADV_DHCP_NO;
719
8fdd0153 720 ether_addr_copy(chaddr, skb->data + chaddr_offset);
6c413b1c 721 }
c6c8fea2 722
6c413b1c 723 return ret;
be7af5cf 724}
aa143d28 725
bbb877ed 726/**
7e9a8c2c
SE
727 * batadv_gw_out_of_range() - check if the dhcp request destination is the best
728 * gateway
bbb877ed
AQ
729 * @bat_priv: the bat priv with all the soft interface information
730 * @skb: the outgoing packet
731 *
732 * Check if the skb is a DHCP request and if it is sent to the current best GW
733 * server. Due to topology changes it may be the case that the GW server
734 * previously selected is not the best one anymore.
735 *
bbb877ed 736 * This call might reallocate skb data.
6c413b1c 737 * Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
62fe710f
SE
738 *
739 * Return: true if the packet destination is unicast and it is not the best gw,
740 * false otherwise.
bbb877ed 741 */
56303d34 742bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
9d2c9488 743 struct sk_buff *skb)
be7af5cf 744{
4f248cff
SE
745 struct batadv_neigh_node *neigh_curr = NULL;
746 struct batadv_neigh_node *neigh_old = NULL;
a752c0a4 747 struct batadv_orig_node *orig_dst_node = NULL;
4f248cff
SE
748 struct batadv_gw_node *gw_node = NULL;
749 struct batadv_gw_node *curr_gw = NULL;
89652331 750 struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
6c413b1c
AQ
751 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
752 bool out_of_range = false;
6b5e971a 753 u8 curr_tq_avg;
bbb877ed
AQ
754 unsigned short vid;
755
756 vid = batadv_get_vid(skb, 0);
be7af5cf 757
a752c0a4
LL
758 if (is_multicast_ether_addr(ethhdr->h_dest))
759 goto out;
760
08c36d3e 761 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
bbb877ed 762 ethhdr->h_dest, vid);
be7af5cf
ML
763 if (!orig_dst_node)
764 goto out;
765
414254e3 766 gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
0d164491 767 if (!gw_node)
be7af5cf
ML
768 goto out;
769
3a24a63e 770 switch (atomic_read(&bat_priv->gw.mode)) {
cd646ab1 771 case BATADV_GW_MODE_SERVER:
be7af5cf 772 /* If we are a GW then we are our best GW. We can artificially
9cfc7bd6
SE
773 * set the tq towards ourself as the maximum value
774 */
42d0b044 775 curr_tq_avg = BATADV_TQ_MAX_VALUE;
be7af5cf 776 break;
cd646ab1 777 case BATADV_GW_MODE_CLIENT:
1409a834 778 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
be7af5cf
ML
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
9cfc7bd6
SE
788 * reliable enough
789 */
30d3c511
SE
790 neigh_curr = batadv_find_router(bat_priv, curr_gw->orig_node,
791 NULL);
be7af5cf
ML
792 if (!neigh_curr)
793 goto out;
794
89652331
SW
795 curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
796 BATADV_IF_DEFAULT);
797 if (!curr_ifinfo)
798 goto out;
799
800 curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
044fa3ae 801 batadv_neigh_ifinfo_put(curr_ifinfo);
89652331 802
be7af5cf 803 break;
cd646ab1 804 case BATADV_GW_MODE_OFF:
be7af5cf
ML
805 default:
806 goto out;
43676ab5 807 }
be7af5cf 808
30d3c511 809 neigh_old = batadv_find_router(bat_priv, orig_dst_node, NULL);
2ef04f47 810 if (!neigh_old)
be7af5cf
ML
811 goto out;
812
89652331
SW
813 old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
814 if (!old_ifinfo)
815 goto out;
816
817 if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
be7af5cf 818 out_of_range = true;
044fa3ae 819 batadv_neigh_ifinfo_put(old_ifinfo);
be7af5cf
ML
820
821out:
822 if (orig_dst_node)
5d967310 823 batadv_orig_node_put(orig_dst_node);
be7af5cf 824 if (curr_gw)
3a01743d 825 batadv_gw_node_put(curr_gw);
414254e3 826 if (gw_node)
3a01743d 827 batadv_gw_node_put(gw_node);
43676ab5 828 if (neigh_old)
25bb2509 829 batadv_neigh_node_put(neigh_old);
43676ab5 830 if (neigh_curr)
25bb2509 831 batadv_neigh_node_put(neigh_curr);
be7af5cf 832 return out_of_range;
c6c8fea2 833}