blob: 9d8e5eda2314119f1ba4118587ffc29d792fc8e0 [file] [log] [blame]
Sven Eckelmann7db7d9f2017-11-19 15:05:11 +01001// SPDX-License-Identifier: GPL-2.0
Sven Eckelmann6b1aea82018-01-01 00:00:00 +01002/* Copyright (C) 2009-2018 B.A.T.M.A.N. contributors:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +00003 *
4 * Marek Lindner
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of version 2 of the GNU General Public
8 * License as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
Antonio Quartulliebf38fb2013-11-03 20:40:48 +010016 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000017 */
18
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000019#include "gateway_client.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020020#include "main.h"
21
22#include <linux/atomic.h>
23#include <linux/byteorder/generic.h>
Sven Eckelmannd7129da2016-07-03 13:31:42 +020024#include <linux/errno.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020025#include <linux/etherdevice.h>
Sven Eckelmannb92b94a2017-11-19 17:12:02 +010026#include <linux/gfp.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020027#include <linux/if_ether.h>
28#include <linux/if_vlan.h>
29#include <linux/in.h>
30#include <linux/ip.h>
31#include <linux/ipv6.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020032#include <linux/kernel.h>
Sven Eckelmanne7aed322016-01-16 10:29:41 +010033#include <linux/kref.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020034#include <linux/list.h>
Sven Eckelmanndff9bc42018-08-12 21:04:41 +020035#include <linux/lockdep.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020036#include <linux/netdevice.h>
Sven Eckelmannd7129da2016-07-03 13:31:42 +020037#include <linux/netlink.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020038#include <linux/rculist.h>
39#include <linux/rcupdate.h>
40#include <linux/seq_file.h>
41#include <linux/skbuff.h>
42#include <linux/slab.h>
43#include <linux/spinlock.h>
44#include <linux/stddef.h>
45#include <linux/udp.h>
Sven Eckelmannd7129da2016-07-03 13:31:42 +020046#include <net/sock.h>
Sven Eckelmannfec149f2017-12-21 10:17:41 +010047#include <uapi/linux/batadv_packet.h>
Sven Eckelmannd7129da2016-07-03 13:31:42 +020048#include <uapi/linux/batman_adv.h>
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020049
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000050#include "gateway_common.h"
51#include "hard-interface.h"
Sven Eckelmannba412082016-05-15 23:48:31 +020052#include "log.h"
Sven Eckelmannd7129da2016-07-03 13:31:42 +020053#include "netlink.h"
Linus Lüssing57f0c072011-03-14 22:43:33 +000054#include "originator.h"
Antonio Quartulli43676ab2011-04-26 21:31:45 +020055#include "routing.h"
Sven Eckelmannd7129da2016-07-03 13:31:42 +020056#include "soft-interface.h"
Sven Eckelmann1e2c2a42015-04-17 19:40:28 +020057#include "sysfs.h"
58#include "translation-table.h"
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000059
Antonio Quartulli6c413b12013-11-05 19:31:08 +010060/* These are the offsets of the "hw type" and "hw address length" in the dhcp
61 * packet starting at the beginning of the dhcp header
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +020062 */
Antonio Quartulli6c413b12013-11-05 19:31:08 +010063#define BATADV_DHCP_HTYPE_OFFSET 1
64#define BATADV_DHCP_HLEN_OFFSET 2
65/* Value of htype representing Ethernet */
66#define BATADV_DHCP_HTYPE_ETHERNET 0x01
67/* This is the offset of the "chaddr" field in the dhcp packet starting at the
68 * beginning of the dhcp header
69 */
70#define BATADV_DHCP_CHADDR_OFFSET 28
Antonio Quartulli43676ab2011-04-26 21:31:45 +020071
Sven Eckelmanne7aed322016-01-16 10:29:41 +010072/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +010073 * batadv_gw_node_release() - release gw_node from lists and queue for free
74 * after rcu grace period
Sven Eckelmanne7aed322016-01-16 10:29:41 +010075 * @ref: kref pointer of the gw_node
76 */
77static void batadv_gw_node_release(struct kref *ref)
78{
79 struct batadv_gw_node *gw_node;
80
81 gw_node = container_of(ref, struct batadv_gw_node, refcount);
82
Sven Eckelmann5d967312016-01-17 11:01:09 +010083 batadv_orig_node_put(gw_node->orig_node);
Sven Eckelmanne7aed322016-01-16 10:29:41 +010084 kfree_rcu(gw_node, rcu);
85}
86
87/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +010088 * batadv_gw_node_put() - decrement the gw_node refcounter and possibly release
89 * it
Sven Eckelmanne7aed322016-01-16 10:29:41 +010090 * @gw_node: gateway node to free
91 */
Antonio Quartulli34d99cf2016-07-03 12:46:33 +020092void batadv_gw_node_put(struct batadv_gw_node *gw_node)
Marek Lindner25b6d3c2011-02-10 14:33:49 +000093{
Sven Eckelmanne7aed322016-01-16 10:29:41 +010094 kref_put(&gw_node->refcount, batadv_gw_node_release);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +000095}
96
Sven Eckelmannff15c272017-12-02 19:51:53 +010097/**
98 * batadv_gw_get_selected_gw_node() - Get currently selected gateway
99 * @bat_priv: the bat priv with all the soft interface information
100 *
101 * Return: selected gateway (with increased refcnt), NULL on errors
102 */
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200103struct batadv_gw_node *
Sven Eckelmann56303d32012-06-05 22:31:31 +0200104batadv_gw_get_selected_gw_node(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000105{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200106 struct batadv_gw_node *gw_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000107
Linus Lüssing5d02b3c2011-02-13 21:13:02 +0000108 rcu_read_lock();
Sven Eckelmann807736f2012-07-15 22:26:51 +0200109 gw_node = rcu_dereference(bat_priv->gw.curr_gw);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100110 if (!gw_node)
Linus Lüssing5d02b3c2011-02-13 21:13:02 +0000111 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000112
Sven Eckelmanne7aed322016-01-16 10:29:41 +0100113 if (!kref_get_unless_zero(&gw_node->refcount))
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100114 gw_node = NULL;
115
116out:
117 rcu_read_unlock();
118 return gw_node;
119}
120
Sven Eckelmannff15c272017-12-02 19:51:53 +0100121/**
122 * batadv_gw_get_selected_orig() - Get originator of currently selected gateway
123 * @bat_priv: the bat priv with all the soft interface information
124 *
125 * Return: orig_node of selected gateway (with increased refcnt), NULL on errors
126 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200127struct batadv_orig_node *
128batadv_gw_get_selected_orig(struct batadv_priv *bat_priv)
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100129{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200130 struct batadv_gw_node *gw_node;
131 struct batadv_orig_node *orig_node = NULL;
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100132
Sven Eckelmann1409a832012-05-12 18:33:55 +0200133 gw_node = batadv_gw_get_selected_gw_node(bat_priv);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100134 if (!gw_node)
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000135 goto out;
Linus Lüssing5d02b3c2011-02-13 21:13:02 +0000136
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100137 rcu_read_lock();
138 orig_node = gw_node->orig_node;
139 if (!orig_node)
140 goto unlock;
141
Sven Eckelmann7c124392016-01-16 10:29:56 +0100142 if (!kref_get_unless_zero(&orig_node->refcount))
Marek Lindner7b36e8e2011-02-18 12:28:10 +0000143 orig_node = NULL;
Linus Lüssing43c70ad2011-02-13 21:13:04 +0000144
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100145unlock:
Linus Lüssing5d02b3c2011-02-13 21:13:02 +0000146 rcu_read_unlock();
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100147out:
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000148 if (gw_node)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100149 batadv_gw_node_put(gw_node);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100150 return orig_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000151}
152
Sven Eckelmann56303d32012-06-05 22:31:31 +0200153static void batadv_gw_select(struct batadv_priv *bat_priv,
154 struct batadv_gw_node *new_gw_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000155{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200156 struct batadv_gw_node *curr_gw_node;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000157
Sven Eckelmann807736f2012-07-15 22:26:51 +0200158 spin_lock_bh(&bat_priv->gw.list_lock);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100159
Sven Eckelmanna08d4972016-03-05 16:09:22 +0100160 if (new_gw_node)
161 kref_get(&new_gw_node->refcount);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000162
Sven Eckelmann807736f2012-07-15 22:26:51 +0200163 curr_gw_node = rcu_dereference_protected(bat_priv->gw.curr_gw, 1);
164 rcu_assign_pointer(bat_priv->gw.curr_gw, new_gw_node);
Marek Lindner25b6d3c2011-02-10 14:33:49 +0000165
166 if (curr_gw_node)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100167 batadv_gw_node_put(curr_gw_node);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100168
Sven Eckelmann807736f2012-07-15 22:26:51 +0200169 spin_unlock_bh(&bat_priv->gw.list_lock);
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100170}
171
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100172/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100173 * batadv_gw_reselect() - force a gateway reselection
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100174 * @bat_priv: the bat priv with all the soft interface information
175 *
176 * Set a flag to remind the GW component to perform a new gateway reselection.
177 * However this function does not ensure that the current gateway is going to be
178 * deselected. The reselection mechanism may elect the same gateway once again.
179 *
180 * This means that invoking batadv_gw_reselect() does not guarantee a gateway
181 * change and therefore a uevent is not necessarily expected.
182 */
183void batadv_gw_reselect(struct batadv_priv *bat_priv)
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100184{
Sven Eckelmann807736f2012-07-15 22:26:51 +0200185 atomic_set(&bat_priv->gw.reselect, 1);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000186}
187
Antonio Quartullic6eaa3f2013-07-13 00:06:00 +0200188/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100189 * batadv_gw_check_client_stop() - check if client mode has been switched off
Antonio Quartullic6eaa3f2013-07-13 00:06:00 +0200190 * @bat_priv: the bat priv with all the soft interface information
191 *
192 * This function assumes the caller has checked that the gw state *is actually
193 * changing*. This function is not supposed to be called when there is no state
194 * change.
195 */
196void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
197{
198 struct batadv_gw_node *curr_gw;
199
Antonio Quartulli3a24a632016-05-06 02:46:38 +0800200 if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
Antonio Quartullic6eaa3f2013-07-13 00:06:00 +0200201 return;
202
203 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
204 if (!curr_gw)
205 return;
206
Antonio Quartullif3163182013-11-04 20:59:40 +0100207 /* deselect the current gateway so that next time that client mode is
208 * enabled a proper GW_ADD event can be sent
209 */
210 batadv_gw_select(bat_priv, NULL);
211
Antonio Quartullic6eaa3f2013-07-13 00:06:00 +0200212 /* if batman-adv is switching the gw client mode off and a gateway was
213 * already selected, send a DEL uevent
214 */
215 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL, NULL);
216
Sven Eckelmann3a017432016-01-17 11:01:18 +0100217 batadv_gw_node_put(curr_gw);
Antonio Quartullic6eaa3f2013-07-13 00:06:00 +0200218}
219
Sven Eckelmannff15c272017-12-02 19:51:53 +0100220/**
221 * batadv_gw_election() - Elect the best gateway
222 * @bat_priv: the bat priv with all the soft interface information
223 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200224void batadv_gw_election(struct batadv_priv *bat_priv)
Antonio Quartulli2265c142011-04-27 00:22:00 +0200225{
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200226 struct batadv_gw_node *curr_gw = NULL;
227 struct batadv_gw_node *next_gw = NULL;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200228 struct batadv_neigh_node *router = NULL;
Simon Wunderlich89652332013-11-13 19:14:46 +0100229 struct batadv_neigh_ifinfo *router_ifinfo = NULL;
Antonio Quartulli19595e02011-06-12 11:58:58 +0200230 char gw_addr[18] = { '\0' };
Antonio Quartulli2265c142011-04-27 00:22:00 +0200231
Antonio Quartulli3a24a632016-05-06 02:46:38 +0800232 if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
Antonio Quartulli2265c142011-04-27 00:22:00 +0200233 goto out;
234
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200235 if (!bat_priv->algo_ops->gw.get_best_gw_node)
236 goto out;
237
Sven Eckelmann1409a832012-05-12 18:33:55 +0200238 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200239
Sven Eckelmann807736f2012-07-15 22:26:51 +0200240 if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw)
Marek Lindnercaa0bf62012-08-04 04:13:26 +0000241 goto out;
242
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200243 /* if gw.reselect is set to 1 it means that a previous call to
244 * gw.is_eligible() said that we have a new best GW, therefore it can
245 * now be picked from the list and selected
246 */
247 next_gw = bat_priv->algo_ops->gw.get_best_gw_node(bat_priv);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200248
249 if (curr_gw == next_gw)
250 goto out;
251
252 if (next_gw) {
Antonio Quartulli19595e02011-06-12 11:58:58 +0200253 sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
254
Simon Wunderlich7351a4822013-11-13 19:14:47 +0100255 router = batadv_orig_router_get(next_gw->orig_node,
256 BATADV_IF_DEFAULT);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200257 if (!router) {
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100258 batadv_gw_reselect(bat_priv);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200259 goto out;
260 }
Simon Wunderlich89652332013-11-13 19:14:46 +0100261
262 router_ifinfo = batadv_neigh_ifinfo_get(router,
263 BATADV_IF_DEFAULT);
264 if (!router_ifinfo) {
265 batadv_gw_reselect(bat_priv);
266 goto out;
267 }
Antonio Quartulli2265c142011-04-27 00:22:00 +0200268 }
269
Sven Eckelmann825ffe12017-08-23 21:52:13 +0200270 if (curr_gw && !next_gw) {
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200271 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200272 "Removing selected gateway - no gateway in range\n");
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200273 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_DEL,
274 NULL);
Sven Eckelmann825ffe12017-08-23 21:52:13 +0200275 } else if (!curr_gw && next_gw) {
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200276 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Marek Lindner414254e2013-04-23 21:39:58 +0800277 "Adding route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200278 next_gw->orig_node->orig,
Marek Lindner414254e2013-04-23 21:39:58 +0800279 next_gw->bandwidth_down / 10,
280 next_gw->bandwidth_down % 10,
281 next_gw->bandwidth_up / 10,
Simon Wunderlich89652332013-11-13 19:14:46 +0100282 next_gw->bandwidth_up % 10,
283 router_ifinfo->bat_iv.tq_avg);
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200284 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_ADD,
285 gw_addr);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200286 } else {
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200287 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Marek Lindner414254e2013-04-23 21:39:58 +0800288 "Changing route to gateway %pM (bandwidth: %u.%u/%u.%u MBit, tq: %i)\n",
Sven Eckelmann1eda58b2012-05-12 13:48:58 +0200289 next_gw->orig_node->orig,
Marek Lindner414254e2013-04-23 21:39:58 +0800290 next_gw->bandwidth_down / 10,
291 next_gw->bandwidth_down % 10,
292 next_gw->bandwidth_up / 10,
Simon Wunderlich89652332013-11-13 19:14:46 +0100293 next_gw->bandwidth_up % 10,
294 router_ifinfo->bat_iv.tq_avg);
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200295 batadv_throw_uevent(bat_priv, BATADV_UEV_GW, BATADV_UEV_CHANGE,
296 gw_addr);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200297 }
298
Sven Eckelmann1409a832012-05-12 18:33:55 +0200299 batadv_gw_select(bat_priv, next_gw);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200300
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100301out:
302 if (curr_gw)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100303 batadv_gw_node_put(curr_gw);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200304 if (next_gw)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100305 batadv_gw_node_put(next_gw);
Antonio Quartulli2265c142011-04-27 00:22:00 +0200306 if (router)
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100307 batadv_neigh_node_put(router);
Simon Wunderlich89652332013-11-13 19:14:46 +0100308 if (router_ifinfo)
Sven Eckelmann044fa3a2016-01-17 11:01:12 +0100309 batadv_neigh_ifinfo_put(router_ifinfo);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000310}
311
Sven Eckelmannff15c272017-12-02 19:51:53 +0100312/**
313 * batadv_gw_check_election() - Elect orig node as best gateway when eligible
314 * @bat_priv: the bat priv with all the soft interface information
315 * @orig_node: orig node which is to be checked
316 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200317void batadv_gw_check_election(struct batadv_priv *bat_priv,
318 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000319{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200320 struct batadv_orig_node *curr_gw_orig;
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200321
322 /* abort immediately if the routing algorithm does not support gateway
323 * election
324 */
325 if (!bat_priv->algo_ops->gw.is_eligible)
326 return;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000327
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200328 curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
Linus Lüssing57f0c072011-03-14 22:43:33 +0000329 if (!curr_gw_orig)
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100330 goto reselect;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000331
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000332 /* this node already is the gateway */
Linus Lüssing57f0c072011-03-14 22:43:33 +0000333 if (curr_gw_orig == orig_node)
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000334 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000335
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200336 if (!bat_priv->algo_ops->gw.is_eligible(bat_priv, curr_gw_orig,
337 orig_node))
Linus Lüssinge1a5382f2011-03-14 22:43:37 +0000338 goto out;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000339
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100340reselect:
341 batadv_gw_reselect(bat_priv);
Linus Lüssing5d02b3c2011-02-13 21:13:02 +0000342out:
Linus Lüssing57f0c072011-03-14 22:43:33 +0000343 if (curr_gw_orig)
Sven Eckelmann5d967312016-01-17 11:01:09 +0100344 batadv_orig_node_put(curr_gw_orig);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000345}
346
Marek Lindner414254e2013-04-23 21:39:58 +0800347/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100348 * batadv_gw_node_add() - add gateway node to list of available gateways
Marek Lindner414254e2013-04-23 21:39:58 +0800349 * @bat_priv: the bat priv with all the soft interface information
350 * @orig_node: originator announcing gateway capabilities
351 * @gateway: announced bandwidth information
Sven Eckelmanndff9bc42018-08-12 21:04:41 +0200352 *
353 * Has to be called with the appropriate locks being acquired
354 * (gw.list_lock).
Marek Lindner414254e2013-04-23 21:39:58 +0800355 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200356static void batadv_gw_node_add(struct batadv_priv *bat_priv,
357 struct batadv_orig_node *orig_node,
Marek Lindner414254e2013-04-23 21:39:58 +0800358 struct batadv_tvlv_gateway_data *gateway)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000359{
Sven Eckelmann56303d32012-06-05 22:31:31 +0200360 struct batadv_gw_node *gw_node;
Marek Lindner414254e2013-04-23 21:39:58 +0800361
Sven Eckelmanndff9bc42018-08-12 21:04:41 +0200362 lockdep_assert_held(&bat_priv->gw.list_lock);
363
Marek Lindner414254e2013-04-23 21:39:58 +0800364 if (gateway->bandwidth_down == 0)
365 return;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000366
Antonio Quartulli377fe0f2014-05-02 01:35:13 +0200367 gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
Sven Eckelmannc3ba37a72016-03-05 16:09:23 +0100368 if (!gw_node)
Antonio Quartulli377fe0f2014-05-02 01:35:13 +0200369 return;
Antonio Quartulli377fe0f2014-05-02 01:35:13 +0200370
Sven Eckelmannf665fa72016-07-15 17:39:27 +0200371 kref_init(&gw_node->refcount);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000372 INIT_HLIST_NODE(&gw_node->list);
Sven Eckelmann55db2d52016-07-15 17:39:21 +0200373 kref_get(&orig_node->refcount);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000374 gw_node->orig_node = orig_node;
Simon Wunderlich27a4d5e2015-06-24 14:50:19 +0200375 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
376 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000377
Sven Eckelmannf665fa72016-07-15 17:39:27 +0200378 kref_get(&gw_node->refcount);
Sven Eckelmann70ea5ce2016-07-27 12:31:08 +0200379 hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.gateway_list);
Sven Eckelmann9264c852018-10-30 22:01:23 +0100380 bat_priv->gw.generation++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000381
Sven Eckelmann39c75a52012-06-03 22:19:22 +0200382 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
Marek Lindner414254e2013-04-23 21:39:58 +0800383 "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
384 orig_node->orig,
385 ntohl(gateway->bandwidth_down) / 10,
386 ntohl(gateway->bandwidth_down) % 10,
387 ntohl(gateway->bandwidth_up) / 10,
388 ntohl(gateway->bandwidth_up) % 10);
Sven Eckelmannf665fa72016-07-15 17:39:27 +0200389
390 /* don't return reference to new gw_node */
391 batadv_gw_node_put(gw_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000392}
393
Marek Lindner414254e2013-04-23 21:39:58 +0800394/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100395 * batadv_gw_node_get() - retrieve gateway node from list of available gateways
Marek Lindner414254e2013-04-23 21:39:58 +0800396 * @bat_priv: the bat priv with all the soft interface information
397 * @orig_node: originator announcing gateway capabilities
398 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200399 * Return: gateway node if found or NULL otherwise.
Marek Lindner414254e2013-04-23 21:39:58 +0800400 */
Antonio Quartulli50164d82016-07-03 12:46:34 +0200401struct batadv_gw_node *batadv_gw_node_get(struct batadv_priv *bat_priv,
402 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000403{
Marek Lindner414254e2013-04-23 21:39:58 +0800404 struct batadv_gw_node *gw_node_tmp, *gw_node = NULL;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000405
406 rcu_read_lock();
Sven Eckelmann70ea5ce2016-07-27 12:31:08 +0200407 hlist_for_each_entry_rcu(gw_node_tmp, &bat_priv->gw.gateway_list,
408 list) {
Marek Lindner414254e2013-04-23 21:39:58 +0800409 if (gw_node_tmp->orig_node != orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000410 continue;
411
Sven Eckelmanne7aed322016-01-16 10:29:41 +0100412 if (!kref_get_unless_zero(&gw_node_tmp->refcount))
Marek Lindner414254e2013-04-23 21:39:58 +0800413 continue;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000414
Marek Lindner414254e2013-04-23 21:39:58 +0800415 gw_node = gw_node_tmp;
416 break;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000417 }
Marek Lindnerc4aac1a2011-03-23 11:24:34 +0100418 rcu_read_unlock();
Antonio Quartulli71e4aa92011-04-25 22:44:32 +0200419
Marek Lindner414254e2013-04-23 21:39:58 +0800420 return gw_node;
421}
422
423/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100424 * batadv_gw_node_update() - update list of available gateways with changed
Marek Lindner414254e2013-04-23 21:39:58 +0800425 * bandwidth information
426 * @bat_priv: the bat priv with all the soft interface information
427 * @orig_node: originator announcing gateway capabilities
428 * @gateway: announced bandwidth information
429 */
430void batadv_gw_node_update(struct batadv_priv *bat_priv,
431 struct batadv_orig_node *orig_node,
432 struct batadv_tvlv_gateway_data *gateway)
433{
434 struct batadv_gw_node *gw_node, *curr_gw = NULL;
435
Sven Eckelmanndff9bc42018-08-12 21:04:41 +0200436 spin_lock_bh(&bat_priv->gw.list_lock);
Marek Lindner414254e2013-04-23 21:39:58 +0800437 gw_node = batadv_gw_node_get(bat_priv, orig_node);
438 if (!gw_node) {
439 batadv_gw_node_add(bat_priv, orig_node, gateway);
Sven Eckelmanndff9bc42018-08-12 21:04:41 +0200440 spin_unlock_bh(&bat_priv->gw.list_lock);
Marek Lindner414254e2013-04-23 21:39:58 +0800441 goto out;
442 }
Sven Eckelmanndff9bc42018-08-12 21:04:41 +0200443 spin_unlock_bh(&bat_priv->gw.list_lock);
Marek Lindner414254e2013-04-23 21:39:58 +0800444
Sven Eckelmann825ffe12017-08-23 21:52:13 +0200445 if (gw_node->bandwidth_down == ntohl(gateway->bandwidth_down) &&
446 gw_node->bandwidth_up == ntohl(gateway->bandwidth_up))
Marek Lindner414254e2013-04-23 21:39:58 +0800447 goto out;
448
449 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
450 "Gateway bandwidth of originator %pM changed from %u.%u/%u.%u MBit to %u.%u/%u.%u MBit\n",
451 orig_node->orig,
452 gw_node->bandwidth_down / 10,
453 gw_node->bandwidth_down % 10,
454 gw_node->bandwidth_up / 10,
455 gw_node->bandwidth_up % 10,
456 ntohl(gateway->bandwidth_down) / 10,
457 ntohl(gateway->bandwidth_down) % 10,
458 ntohl(gateway->bandwidth_up) / 10,
459 ntohl(gateway->bandwidth_up) % 10);
460
461 gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
462 gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
463
Marek Lindner414254e2013-04-23 21:39:58 +0800464 if (ntohl(gateway->bandwidth_down) == 0) {
Marek Lindner414254e2013-04-23 21:39:58 +0800465 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
466 "Gateway %pM removed from gateway list\n",
467 orig_node->orig);
468
469 /* Note: We don't need a NULL check here, since curr_gw never
470 * gets dereferenced.
471 */
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200472 spin_lock_bh(&bat_priv->gw.list_lock);
Sven Eckelmannc18bdd02016-01-31 13:27:59 +0100473 if (!hlist_unhashed(&gw_node->list)) {
474 hlist_del_init_rcu(&gw_node->list);
Sven Eckelmann3a017432016-01-17 11:01:18 +0100475 batadv_gw_node_put(gw_node);
Sven Eckelmann9264c852018-10-30 22:01:23 +0100476 bat_priv->gw.generation++;
Sven Eckelmannc18bdd02016-01-31 13:27:59 +0100477 }
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200478 spin_unlock_bh(&bat_priv->gw.list_lock);
479
Marek Lindner414254e2013-04-23 21:39:58 +0800480 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
481 if (gw_node == curr_gw)
Antonio Quartulli4e820e72013-11-04 20:59:41 +0100482 batadv_gw_reselect(bat_priv);
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200483
484 if (curr_gw)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100485 batadv_gw_node_put(curr_gw);
Marek Lindner414254e2013-04-23 21:39:58 +0800486 }
487
488out:
Marek Lindner414254e2013-04-23 21:39:58 +0800489 if (gw_node)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100490 batadv_gw_node_put(gw_node);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000491}
492
Sven Eckelmannff15c272017-12-02 19:51:53 +0100493/**
494 * batadv_gw_node_delete() - Remove orig_node from gateway list
495 * @bat_priv: the bat priv with all the soft interface information
496 * @orig_node: orig node which is currently in process of being removed
497 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200498void batadv_gw_node_delete(struct batadv_priv *bat_priv,
499 struct batadv_orig_node *orig_node)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000500{
Marek Lindner414254e2013-04-23 21:39:58 +0800501 struct batadv_tvlv_gateway_data gateway;
502
503 gateway.bandwidth_down = 0;
504 gateway.bandwidth_up = 0;
505
506 batadv_gw_node_update(bat_priv, orig_node, &gateway);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000507}
508
Sven Eckelmannff15c272017-12-02 19:51:53 +0100509/**
510 * batadv_gw_node_free() - Free gateway information from soft interface
511 * @bat_priv: the bat priv with all the soft interface information
512 */
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200513void batadv_gw_node_free(struct batadv_priv *bat_priv)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000514{
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200515 struct batadv_gw_node *gw_node;
Sasha Levinb67bfe02013-02-27 17:06:00 -0800516 struct hlist_node *node_tmp;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000517
Sven Eckelmann807736f2012-07-15 22:26:51 +0200518 spin_lock_bh(&bat_priv->gw.list_lock);
Sasha Levinb67bfe02013-02-27 17:06:00 -0800519 hlist_for_each_entry_safe(gw_node, node_tmp,
Sven Eckelmann70ea5ce2016-07-27 12:31:08 +0200520 &bat_priv->gw.gateway_list, list) {
Simon Wunderlichbd3524c2015-08-03 19:13:58 +0200521 hlist_del_init_rcu(&gw_node->list);
Sven Eckelmann3a017432016-01-17 11:01:18 +0100522 batadv_gw_node_put(gw_node);
Sven Eckelmann9264c852018-10-30 22:01:23 +0100523 bat_priv->gw.generation++;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000524 }
Sven Eckelmann807736f2012-07-15 22:26:51 +0200525 spin_unlock_bh(&bat_priv->gw.list_lock);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000526}
527
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +0200528#ifdef CONFIG_BATMAN_ADV_DEBUGFS
Sven Eckelmannff15c272017-12-02 19:51:53 +0100529
530/**
531 * batadv_gw_client_seq_print_text() - Print the gateway table in a seq file
532 * @seq: seq file to print on
533 * @offset: not used
534 *
535 * Return: always 0
536 */
Sven Eckelmann7cf06bc2012-05-12 02:09:29 +0200537int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000538{
539 struct net_device *net_dev = (struct net_device *)seq->private;
Sven Eckelmann56303d32012-06-05 22:31:31 +0200540 struct batadv_priv *bat_priv = netdev_priv(net_dev);
541 struct batadv_hard_iface *primary_if;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000542
Marek Lindner30da63a2012-08-03 17:15:46 +0200543 primary_if = batadv_seq_print_text_primary_if_get(seq);
544 if (!primary_if)
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200545 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000546
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200547 seq_printf(seq, "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s %s)]\n",
Sven Eckelmann42d0b042012-06-03 22:19:17 +0200548 BATADV_SOURCE_VERSION, primary_if->net_dev->name,
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200549 primary_if->net_dev->dev_addr, net_dev->name,
550 bat_priv->algo_ops->name);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000551
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200552 batadv_hardif_put(primary_if);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000553
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200554 if (!bat_priv->algo_ops->gw.print) {
555 seq_puts(seq,
556 "No printing function for this routing protocol\n");
557 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000558 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000559
Antonio Quartulli34d99cf2016-07-03 12:46:33 +0200560 bat_priv->algo_ops->gw.print(bat_priv, seq);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000561
Marek Lindner30da63a2012-08-03 17:15:46 +0200562 return 0;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000563}
Sven Eckelmanndc1cbd12016-07-16 09:31:20 +0200564#endif
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000565
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100566/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100567 * batadv_gw_dump() - Dump gateways into a message
Sven Eckelmannd7129da2016-07-03 13:31:42 +0200568 * @msg: Netlink message to dump into
569 * @cb: Control block containing additional options
570 *
571 * Return: Error code, or length of message
572 */
573int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb)
574{
575 struct batadv_hard_iface *primary_if = NULL;
576 struct net *net = sock_net(cb->skb->sk);
577 struct net_device *soft_iface;
578 struct batadv_priv *bat_priv;
579 int ifindex;
580 int ret;
581
582 ifindex = batadv_netlink_get_ifindex(cb->nlh,
583 BATADV_ATTR_MESH_IFINDEX);
584 if (!ifindex)
585 return -EINVAL;
586
587 soft_iface = dev_get_by_index(net, ifindex);
588 if (!soft_iface || !batadv_softif_is_valid(soft_iface)) {
589 ret = -ENODEV;
590 goto out;
591 }
592
593 bat_priv = netdev_priv(soft_iface);
594
595 primary_if = batadv_primary_if_get_selected(bat_priv);
596 if (!primary_if || primary_if->if_status != BATADV_IF_ACTIVE) {
597 ret = -ENOENT;
598 goto out;
599 }
600
601 if (!bat_priv->algo_ops->gw.dump) {
602 ret = -EOPNOTSUPP;
603 goto out;
604 }
605
606 bat_priv->algo_ops->gw.dump(msg, cb, bat_priv);
607
608 ret = msg->len;
609
610out:
611 if (primary_if)
612 batadv_hardif_put(primary_if);
613 if (soft_iface)
614 dev_put(soft_iface);
615
616 return ret;
617}
618
619/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100620 * batadv_gw_dhcp_recipient_get() - check if a packet is a DHCP message
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100621 * @skb: the packet to check
622 * @header_len: a pointer to the batman-adv header size
623 * @chaddr: buffer where the client address will be stored. Valid
624 * only if the function returns BATADV_DHCP_TO_CLIENT
625 *
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200626 * This function may re-allocate the data buffer of the skb passed as argument.
627 *
628 * Return:
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100629 * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
630 * while parsing it
631 * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
632 * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100633 */
634enum batadv_dhcp_recipient
635batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200636 u8 *chaddr)
Antonio Quartulli43676ab2011-04-26 21:31:45 +0200637{
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100638 enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000639 struct ethhdr *ethhdr;
640 struct iphdr *iphdr;
641 struct ipv6hdr *ipv6hdr;
642 struct udphdr *udphdr;
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200643 struct vlan_ethhdr *vhdr;
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100644 int chaddr_offset;
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200645 __be16 proto;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200646 u8 *p;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000647
648 /* check for ethernet header */
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200649 if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100650 return BATADV_DHCP_NO;
651
Linus Lüssing927c2ed2014-01-19 22:22:45 +0100652 ethhdr = eth_hdr(skb);
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200653 proto = ethhdr->h_proto;
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200654 *header_len += ETH_HLEN;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000655
656 /* check for initial vlan header */
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200657 if (proto == htons(ETH_P_8021Q)) {
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200658 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100659 return BATADV_DHCP_NO;
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200660
Linus Lüssing927c2ed2014-01-19 22:22:45 +0100661 vhdr = vlan_eth_hdr(skb);
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200662 proto = vhdr->h_vlan_encapsulated_proto;
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200663 *header_len += VLAN_HLEN;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000664 }
665
666 /* check for ip header */
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200667 switch (proto) {
668 case htons(ETH_P_IP):
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200669 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100670 return BATADV_DHCP_NO;
671
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200672 iphdr = (struct iphdr *)(skb->data + *header_len);
673 *header_len += iphdr->ihl * 4;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000674
675 /* check for udp header */
676 if (iphdr->protocol != IPPROTO_UDP)
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100677 return BATADV_DHCP_NO;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000678
679 break;
Antonio Quartullif7f8ed52013-05-12 21:51:15 +0200680 case htons(ETH_P_IPV6):
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200681 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100682 return BATADV_DHCP_NO;
683
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200684 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
685 *header_len += sizeof(*ipv6hdr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000686
687 /* check for udp header */
688 if (ipv6hdr->nexthdr != IPPROTO_UDP)
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100689 return BATADV_DHCP_NO;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000690
691 break;
692 default:
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100693 return BATADV_DHCP_NO;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000694 }
695
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200696 if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100697 return BATADV_DHCP_NO;
Linus Lüssing9d2c9482013-08-06 20:21:15 +0200698
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200699 udphdr = (struct udphdr *)(skb->data + *header_len);
700 *header_len += sizeof(*udphdr);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000701
702 /* check for bootp port */
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100703 switch (proto) {
704 case htons(ETH_P_IP):
705 if (udphdr->dest == htons(67))
706 ret = BATADV_DHCP_TO_SERVER;
707 else if (udphdr->source == htons(67))
708 ret = BATADV_DHCP_TO_CLIENT;
709 break;
710 case htons(ETH_P_IPV6):
711 if (udphdr->dest == htons(547))
712 ret = BATADV_DHCP_TO_SERVER;
713 else if (udphdr->source == htons(547))
714 ret = BATADV_DHCP_TO_CLIENT;
715 break;
716 }
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000717
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100718 chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
719 /* store the client address if the message is going to a client */
720 if (ret == BATADV_DHCP_TO_CLIENT &&
721 pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
722 /* check if the DHCP packet carries an Ethernet DHCP */
723 p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
724 if (*p != BATADV_DHCP_HTYPE_ETHERNET)
725 return BATADV_DHCP_NO;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000726
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100727 /* check if the DHCP packet carries a valid Ethernet address */
728 p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
729 if (*p != ETH_ALEN)
730 return BATADV_DHCP_NO;
731
Antonio Quartulli8fdd0152014-01-22 00:42:11 +0100732 ether_addr_copy(chaddr, skb->data + chaddr_offset);
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100733 }
734
735 return ret;
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200736}
Antonio Quartulliaa143d22014-09-01 14:37:27 +0200737
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200738/**
Sven Eckelmann7e9a8c22017-12-02 19:51:47 +0100739 * batadv_gw_out_of_range() - check if the dhcp request destination is the best
740 * gateway
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200741 * @bat_priv: the bat priv with all the soft interface information
742 * @skb: the outgoing packet
743 *
744 * Check if the skb is a DHCP request and if it is sent to the current best GW
745 * server. Due to topology changes it may be the case that the GW server
746 * previously selected is not the best one anymore.
747 *
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200748 * This call might reallocate skb data.
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100749 * Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
Sven Eckelmann62fe7102015-09-15 19:00:48 +0200750 *
751 * Return: true if the packet destination is unicast and it is not the best gw,
752 * false otherwise.
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200753 */
Sven Eckelmann56303d32012-06-05 22:31:31 +0200754bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
Linus Lüssing9d2c9482013-08-06 20:21:15 +0200755 struct sk_buff *skb)
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200756{
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200757 struct batadv_neigh_node *neigh_curr = NULL;
758 struct batadv_neigh_node *neigh_old = NULL;
Linus Lüssinga752c0a2018-03-22 00:21:32 +0100759 struct batadv_orig_node *orig_dst_node = NULL;
Sven Eckelmann4f248cf2015-06-09 20:50:49 +0200760 struct batadv_gw_node *gw_node = NULL;
761 struct batadv_gw_node *curr_gw = NULL;
Simon Wunderlich89652332013-11-13 19:14:46 +0100762 struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
Antonio Quartulli6c413b12013-11-05 19:31:08 +0100763 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
764 bool out_of_range = false;
Sven Eckelmann6b5e9712015-05-26 18:34:26 +0200765 u8 curr_tq_avg;
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200766 unsigned short vid;
767
768 vid = batadv_get_vid(skb, 0);
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000769
Linus Lüssinga752c0a2018-03-22 00:21:32 +0100770 if (is_multicast_ether_addr(ethhdr->h_dest))
771 goto out;
772
Sven Eckelmann08c36d32012-05-12 02:09:39 +0200773 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
Antonio Quartullibbb877e2013-06-04 12:11:42 +0200774 ethhdr->h_dest, vid);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200775 if (!orig_dst_node)
776 goto out;
777
Marek Lindner414254e2013-04-23 21:39:58 +0800778 gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
Antonio Quartulli0d164492014-12-20 13:48:57 +0100779 if (!gw_node)
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200780 goto out;
781
Antonio Quartulli3a24a632016-05-06 02:46:38 +0800782 switch (atomic_read(&bat_priv->gw.mode)) {
Sven Eckelmanncd646ab2012-06-03 22:19:18 +0200783 case BATADV_GW_MODE_SERVER:
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200784 /* If we are a GW then we are our best GW. We can artificially
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200785 * set the tq towards ourself as the maximum value
786 */
Sven Eckelmann42d0b042012-06-03 22:19:17 +0200787 curr_tq_avg = BATADV_TQ_MAX_VALUE;
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200788 break;
Sven Eckelmanncd646ab2012-06-03 22:19:18 +0200789 case BATADV_GW_MODE_CLIENT:
Sven Eckelmann1409a832012-05-12 18:33:55 +0200790 curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200791 if (!curr_gw)
792 goto out;
793
794 /* packet is going to our gateway */
795 if (curr_gw->orig_node == orig_dst_node)
796 goto out;
797
798 /* If the dhcp packet has been sent to a different gw,
799 * we have to evaluate whether the old gw is still
Sven Eckelmann9cfc7bd2012-05-12 02:09:43 +0200800 * reliable enough
801 */
Sven Eckelmann30d3c512012-05-12 02:09:36 +0200802 neigh_curr = batadv_find_router(bat_priv, curr_gw->orig_node,
803 NULL);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200804 if (!neigh_curr)
805 goto out;
806
Simon Wunderlich89652332013-11-13 19:14:46 +0100807 curr_ifinfo = batadv_neigh_ifinfo_get(neigh_curr,
808 BATADV_IF_DEFAULT);
809 if (!curr_ifinfo)
810 goto out;
811
812 curr_tq_avg = curr_ifinfo->bat_iv.tq_avg;
Sven Eckelmann044fa3a2016-01-17 11:01:12 +0100813 batadv_neigh_ifinfo_put(curr_ifinfo);
Simon Wunderlich89652332013-11-13 19:14:46 +0100814
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200815 break;
Sven Eckelmanncd646ab2012-06-03 22:19:18 +0200816 case BATADV_GW_MODE_OFF:
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200817 default:
818 goto out;
Antonio Quartulli43676ab2011-04-26 21:31:45 +0200819 }
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200820
Sven Eckelmann30d3c512012-05-12 02:09:36 +0200821 neigh_old = batadv_find_router(bat_priv, orig_dst_node, NULL);
Dan Carpenter2ef04f42011-11-29 09:09:09 +0300822 if (!neigh_old)
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200823 goto out;
824
Simon Wunderlich89652332013-11-13 19:14:46 +0100825 old_ifinfo = batadv_neigh_ifinfo_get(neigh_old, BATADV_IF_DEFAULT);
826 if (!old_ifinfo)
827 goto out;
828
829 if ((curr_tq_avg - old_ifinfo->bat_iv.tq_avg) > BATADV_GW_THRESHOLD)
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200830 out_of_range = true;
Sven Eckelmann044fa3a2016-01-17 11:01:12 +0100831 batadv_neigh_ifinfo_put(old_ifinfo);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200832
833out:
834 if (orig_dst_node)
Sven Eckelmann5d967312016-01-17 11:01:09 +0100835 batadv_orig_node_put(orig_dst_node);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200836 if (curr_gw)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100837 batadv_gw_node_put(curr_gw);
Marek Lindner414254e2013-04-23 21:39:58 +0800838 if (gw_node)
Sven Eckelmann3a017432016-01-17 11:01:18 +0100839 batadv_gw_node_put(gw_node);
Antonio Quartulli43676ab2011-04-26 21:31:45 +0200840 if (neigh_old)
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100841 batadv_neigh_node_put(neigh_old);
Antonio Quartulli43676ab2011-04-26 21:31:45 +0200842 if (neigh_curr)
Sven Eckelmann25bb2502016-01-17 11:01:11 +0100843 batadv_neigh_node_put(neigh_curr);
Marek Lindnerbe7af5c2011-09-08 13:12:53 +0200844 return out_of_range;
Sven Eckelmannc6c8fea2010-12-13 11:19:28 +0000845}