gateway_client.c 17.3 KB
Newer Older
1
/*
2
 * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * Marek Lindner
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 *
 */

#include "main.h"
23
#include "bat_sysfs.h"
24 25 26
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
27
#include "originator.h"
28
#include "translation-table.h"
29
#include "routing.h"
30 31 32 33 34
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>

35 36 37 38 39
/* This is the offset of the options field in a dhcp packet starting at
 * the beginning of the dhcp header */
#define DHCP_OPTIONS_OFFSET 240
#define DHCP_REQUEST 3

40
static void gw_node_free_ref(struct gw_node *gw_node)
41
{
42
	if (atomic_dec_and_test(&gw_node->refcount))
43
		kfree_rcu(gw_node, rcu);
44 45
}

46
static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv)
47
{
48
	struct gw_node *gw_node;
49

50
	rcu_read_lock();
51 52
	gw_node = rcu_dereference(bat_priv->curr_gw);
	if (!gw_node)
53
		goto out;
54

55 56
	if (!atomic_inc_not_zero(&gw_node->refcount))
		gw_node = NULL;
57

58 59
out:
	rcu_read_unlock();
60
	return gw_node;
61 62
}

63
struct orig_node *batadv_gw_get_selected_orig(struct bat_priv *bat_priv)
64
{
65
	struct gw_node *gw_node;
66
	struct orig_node *orig_node = NULL;
67

68 69 70 71 72 73 74 75 76 77 78
	gw_node = gw_get_selected_gw_node(bat_priv);
	if (!gw_node)
		goto out;

	rcu_read_lock();
	orig_node = gw_node->orig_node;
	if (!orig_node)
		goto unlock;

	if (!atomic_inc_not_zero(&orig_node->refcount))
		orig_node = NULL;
79

80 81 82
unlock:
	rcu_read_unlock();
out:
83
	if (gw_node)
84
		gw_node_free_ref(gw_node);
85
	return orig_node;
86 87
}

88
static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
89
{
90
	struct gw_node *curr_gw_node;
91

92 93
	spin_lock_bh(&bat_priv->gw_list_lock);

94 95
	if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
		new_gw_node = NULL;
96

97
	curr_gw_node = rcu_dereference_protected(bat_priv->curr_gw, 1);
98
	rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
99 100 101

	if (curr_gw_node)
		gw_node_free_ref(curr_gw_node);
102 103 104 105

	spin_unlock_bh(&bat_priv->gw_list_lock);
}

106
void batadv_gw_deselect(struct bat_priv *bat_priv)
107
{
108
	atomic_set(&bat_priv->gw_reselect, 1);
109 110
}

111
static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
112
{
113
	struct neigh_node *router;
114 115
	struct hlist_node *node;
	struct gw_node *gw_node, *curr_gw = NULL;
116
	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
117
	uint8_t max_tq = 0;
118
	int down, up;
119
	struct orig_node *orig_node;
120

121
	rcu_read_lock();
122
	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
123
		if (gw_node->deleted)
124 125
			continue;

126
		orig_node = gw_node->orig_node;
127
		router = batadv_orig_node_get_router(orig_node);
128
		if (!router)
129 130
			continue;

131 132 133
		if (!atomic_inc_not_zero(&gw_node->refcount))
			goto next;

134 135
		switch (atomic_read(&bat_priv->gw_sel_class)) {
		case 1: /* fast connection */
136 137
			batadv_gw_bandwidth_to_kbit(orig_node->gw_flags,
						    &down, &up);
138

139
			tmp_gw_factor = (router->tq_avg * router->tq_avg *
140 141 142 143 144 145
					 down * 100 * 100) /
					 (TQ_LOCAL_WINDOW_SIZE *
					 TQ_LOCAL_WINDOW_SIZE * 64);

			if ((tmp_gw_factor > max_gw_factor) ||
			    ((tmp_gw_factor == max_gw_factor) &&
146 147 148 149 150 151
			     (router->tq_avg > max_tq))) {
				if (curr_gw)
					gw_node_free_ref(curr_gw);
				curr_gw = gw_node;
				atomic_inc(&curr_gw->refcount);
			}
152 153 154 155 156 157 158 159 160 161
			break;

		default: /**
			  * 2:  stable connection (use best statistic)
			  * 3:  fast-switch (use best statistic but change as
			  *     soon as a better gateway appears)
			  * XX: late-switch (use best statistic but change as
			  *     soon as a better gateway appears which has
			  *     $routing_class more tq points)
			  **/
162 163 164 165 166 167
			if (router->tq_avg > max_tq) {
				if (curr_gw)
					gw_node_free_ref(curr_gw);
				curr_gw = gw_node;
				atomic_inc(&curr_gw->refcount);
			}
168 169 170
			break;
		}

171 172
		if (router->tq_avg > max_tq)
			max_tq = router->tq_avg;
173 174 175

		if (tmp_gw_factor > max_gw_factor)
			max_gw_factor = tmp_gw_factor;
176

177 178 179
		gw_node_free_ref(gw_node);

next:
180
		batadv_neigh_node_free_ref(router);
181
	}
182
	rcu_read_unlock();
183

184 185
	return curr_gw;
}
186

187
void batadv_gw_election(struct bat_priv *bat_priv)
188 189 190
{
	struct gw_node *curr_gw = NULL, *next_gw = NULL;
	struct neigh_node *router = NULL;
191
	char gw_addr[18] = { '\0' };
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

	/**
	 * The batman daemon checks here if we already passed a full originator
	 * cycle in order to make sure we don't choose the first gateway we
	 * hear about. This check is based on the daemon's uptime which we
	 * don't have.
	 **/
	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
		goto out;

	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
		goto out;

	curr_gw = gw_get_selected_gw_node(bat_priv);

	next_gw = gw_get_best_gw_node(bat_priv);

	if (curr_gw == next_gw)
		goto out;

	if (next_gw) {
213 214
		sprintf(gw_addr, "%pM", next_gw->orig_node->orig);

215
		router = batadv_orig_node_get_router(next_gw->orig_node);
216
		if (!router) {
217
			batadv_gw_deselect(bat_priv);
218 219
			goto out;
		}
220 221
	}

222 223 224
	if ((curr_gw) && (!next_gw)) {
		bat_dbg(DBG_BATMAN, bat_priv,
			"Removing selected gateway - no gateway in range\n");
225
		batadv_throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
226 227 228
	} else if ((!curr_gw) && (next_gw)) {
		bat_dbg(DBG_BATMAN, bat_priv,
			"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
229
			next_gw->orig_node->orig, next_gw->orig_node->gw_flags,
230
			router->tq_avg);
231
		batadv_throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
232 233
	} else {
		bat_dbg(DBG_BATMAN, bat_priv,
234 235
			"Changing route to gateway %pM (gw_flags: %i, tq: %i)\n",
			next_gw->orig_node->orig, next_gw->orig_node->gw_flags,
236
			router->tq_avg);
237
		batadv_throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
238 239 240 241
	}

	gw_select(bat_priv, next_gw);

242 243 244
out:
	if (curr_gw)
		gw_node_free_ref(curr_gw);
245 246 247
	if (next_gw)
		gw_node_free_ref(next_gw);
	if (router)
248
		batadv_neigh_node_free_ref(router);
249 250
}

251 252
void batadv_gw_check_election(struct bat_priv *bat_priv,
			      struct orig_node *orig_node)
253
{
254
	struct orig_node *curr_gw_orig;
255
	struct neigh_node *router_gw = NULL, *router_orig = NULL;
256 257
	uint8_t gw_tq_avg, orig_tq_avg;

258
	curr_gw_orig = batadv_gw_get_selected_orig(bat_priv);
259 260
	if (!curr_gw_orig)
		goto deselect;
261

262
	router_gw = batadv_orig_node_get_router(curr_gw_orig);
263 264
	if (!router_gw)
		goto deselect;
265 266

	/* this node already is the gateway */
267
	if (curr_gw_orig == orig_node)
268
		goto out;
269

270
	router_orig = batadv_orig_node_get_router(orig_node);
271 272
	if (!router_orig)
		goto out;
273

274 275
	gw_tq_avg = router_gw->tq_avg;
	orig_tq_avg = router_orig->tq_avg;
276 277 278

	/* the TQ value has to be better */
	if (orig_tq_avg < gw_tq_avg)
279
		goto out;
280 281 282 283 284 285 286

	/**
	 * if the routing class is greater than 3 the value tells us how much
	 * greater the TQ value of the new gateway must be
	 **/
	if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
	    (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
287
		goto out;
288 289

	bat_dbg(DBG_BATMAN, bat_priv,
290
		"Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i)\n",
291 292 293
		gw_tq_avg, orig_tq_avg);

deselect:
294
	batadv_gw_deselect(bat_priv);
295
out:
296
	if (curr_gw_orig)
297
		batadv_orig_node_free_ref(curr_gw_orig);
298
	if (router_gw)
299
		batadv_neigh_node_free_ref(router_gw);
300
	if (router_orig)
301
		batadv_neigh_node_free_ref(router_orig);
302

303
	return;
304 305 306 307 308 309 310 311
}

static void gw_node_add(struct bat_priv *bat_priv,
			struct orig_node *orig_node, uint8_t new_gwflags)
{
	struct gw_node *gw_node;
	int down, up;

312
	gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
313 314 315 316 317
	if (!gw_node)
		return;

	INIT_HLIST_NODE(&gw_node->list);
	gw_node->orig_node = orig_node;
318
	atomic_set(&gw_node->refcount, 1);
319 320 321 322 323

	spin_lock_bh(&bat_priv->gw_list_lock);
	hlist_add_head_rcu(&gw_node->list, &bat_priv->gw_list);
	spin_unlock_bh(&bat_priv->gw_list_lock);

324
	batadv_gw_bandwidth_to_kbit(new_gwflags, &down, &up);
325 326 327 328 329 330 331 332 333
	bat_dbg(DBG_BATMAN, bat_priv,
		"Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n",
		orig_node->orig, new_gwflags,
		(down > 2048 ? down / 1024 : down),
		(down > 2048 ? "MBit" : "KBit"),
		(up > 2048 ? up / 1024 : up),
		(up > 2048 ? "MBit" : "KBit"));
}

334 335
void batadv_gw_node_update(struct bat_priv *bat_priv,
			   struct orig_node *orig_node, uint8_t new_gwflags)
336 337
{
	struct hlist_node *node;
338 339
	struct gw_node *gw_node, *curr_gw;

340 341 342 343 344 345
	/**
	 * Note: We don't need a NULL check here, since curr_gw never gets
	 * dereferenced. If curr_gw is NULL we also should not exit as we may
	 * have this gateway in our list (duplication check!) even though we
	 * have no currently selected gateway.
	 */
346
	curr_gw = gw_get_selected_gw_node(bat_priv);
347 348 349 350 351 352 353

	rcu_read_lock();
	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
		if (gw_node->orig_node != orig_node)
			continue;

		bat_dbg(DBG_BATMAN, bat_priv,
354
			"Gateway class of originator %pM changed from %i to %i\n",
355 356 357 358 359
			orig_node->orig, gw_node->orig_node->gw_flags,
			new_gwflags);

		gw_node->deleted = 0;

360
		if (new_gwflags == NO_FLAGS) {
361 362 363 364 365
			gw_node->deleted = jiffies;
			bat_dbg(DBG_BATMAN, bat_priv,
				"Gateway %pM removed from gateway list\n",
				orig_node->orig);

366 367
			if (gw_node == curr_gw)
				goto deselect;
368 369
		}

370
		goto unlock;
371 372
	}

373
	if (new_gwflags == NO_FLAGS)
374
		goto unlock;
375 376

	gw_node_add(bat_priv, orig_node, new_gwflags);
377 378 379
	goto unlock;

deselect:
380
	batadv_gw_deselect(bat_priv);
381 382
unlock:
	rcu_read_unlock();
383

384 385
	if (curr_gw)
		gw_node_free_ref(curr_gw);
386 387
}

388 389
void batadv_gw_node_delete(struct bat_priv *bat_priv,
			   struct orig_node *orig_node)
390
{
391
	batadv_gw_node_update(bat_priv, orig_node, 0);
392 393
}

394
void batadv_gw_node_purge(struct bat_priv *bat_priv)
395
{
396
	struct gw_node *gw_node, *curr_gw;
397
	struct hlist_node *node, *node_tmp;
398
	unsigned long timeout = msecs_to_jiffies(2 * PURGE_TIMEOUT);
399
	int do_deselect = 0;
400 401

	curr_gw = gw_get_selected_gw_node(bat_priv);
402 403 404 405 406 407 408 409 410 411

	spin_lock_bh(&bat_priv->gw_list_lock);

	hlist_for_each_entry_safe(gw_node, node, node_tmp,
				  &bat_priv->gw_list, list) {
		if (((!gw_node->deleted) ||
		     (time_before(jiffies, gw_node->deleted + timeout))) &&
		    atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)
			continue;

412 413
		if (curr_gw == gw_node)
			do_deselect = 1;
414 415

		hlist_del_rcu(&gw_node->list);
416
		gw_node_free_ref(gw_node);
417 418 419
	}

	spin_unlock_bh(&bat_priv->gw_list_lock);
420 421 422

	/* gw_deselect() needs to acquire the gw_list_lock */
	if (do_deselect)
423
		batadv_gw_deselect(bat_priv);
424 425 426

	if (curr_gw)
		gw_node_free_ref(curr_gw);
427 428
}

429 430 431
/**
 * fails if orig_node has no router
 */
432 433
static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
			      const struct gw_node *gw_node)
434
{
435
	struct gw_node *curr_gw;
436 437
	struct neigh_node *router;
	int down, up, ret = -1;
438

439
	batadv_gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
440

441
	router = batadv_orig_node_get_router(gw_node->orig_node);
442 443
	if (!router)
		goto out;
444

445
	curr_gw = gw_get_selected_gw_node(bat_priv);
446 447

	ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
448 449 450 451 452 453 454 455 456
			 (curr_gw == gw_node ? "=>" : "  "),
			 gw_node->orig_node->orig,
			 router->tq_avg, router->addr,
			 router->if_incoming->net_dev->name,
			 gw_node->orig_node->gw_flags,
			 (down > 2048 ? down / 1024 : down),
			 (down > 2048 ? "MBit" : "KBit"),
			 (up > 2048 ? up / 1024 : up),
			 (up > 2048 ? "MBit" : "KBit"));
457

458
	batadv_neigh_node_free_ref(router);
459 460
	if (curr_gw)
		gw_node_free_ref(curr_gw);
461
out:
462
	return ret;
463 464
}

465
int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
466 467 468
{
	struct net_device *net_dev = (struct net_device *)seq->private;
	struct bat_priv *bat_priv = netdev_priv(net_dev);
469
	struct hard_iface *primary_if;
470 471
	struct gw_node *gw_node;
	struct hlist_node *node;
472
	int gw_count = 0, ret = 0;
473

474 475
	primary_if = primary_if_get_selected(bat_priv);
	if (!primary_if) {
476 477
		ret = seq_printf(seq,
				 "BATMAN mesh %s disabled - please specify interfaces to enable it\n",
478 479
				 net_dev->name);
		goto out;
480 481
	}

482
	if (primary_if->if_status != IF_ACTIVE) {
483 484
		ret = seq_printf(seq,
				 "BATMAN mesh %s disabled - primary interface not active\n",
485 486
				 net_dev->name);
		goto out;
487 488
	}

489 490 491 492
	seq_printf(seq,
		   "      %-12s (%s/%i) %17s [%10s]: gw_class ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
		   "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
		   SOURCE_VERSION, primary_if->net_dev->name,
493
		   primary_if->net_dev->dev_addr, net_dev->name);
494 495 496 497 498 499

	rcu_read_lock();
	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
		if (gw_node->deleted)
			continue;

500 501
		/* fails if orig_node has no router */
		if (_write_buffer_text(bat_priv, seq, gw_node) < 0)
502 503 504 505 506 507 508 509 510
			continue;

		gw_count++;
	}
	rcu_read_unlock();

	if (gw_count == 0)
		seq_printf(seq, "No gateways in range ...\n");

511 512 513 514
out:
	if (primary_if)
		hardif_free_ref(primary_if);
	return ret;
515 516
}

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
{
	int ret = false;
	unsigned char *p;
	int pkt_len;

	if (skb_linearize(skb) < 0)
		goto out;

	pkt_len = skb_headlen(skb);

	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
		goto out;

	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;

	/* Access the dhcp option lists. Each entry is made up by:
535 536 537
	 * - octet 1: option type
	 * - octet 2: option data len (only if type != 255 and 0)
	 * - octet 3: option data */
538
	while (*p != 255 && !ret) {
539
		/* p now points to the first octet: option type */
540 541
		if (*p == 53) {
			/* type 53 is the message type option.
542
			 * Jump the len octet and go to the data octet */
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
			if (pkt_len < 2)
				goto out;
			p += 2;

			/* check if the message type is what we need */
			if (*p == DHCP_REQUEST)
				ret = true;
			break;
		} else if (*p == 0) {
			/* option type 0 (padding), just go forward */
			if (pkt_len < 1)
				goto out;
			pkt_len--;
			p++;
		} else {
			/* This is any other option. So we get the length... */
			if (pkt_len < 1)
				goto out;
			pkt_len--;
			p++;

			/* ...and then we jump over the data */
565
			if (pkt_len < 1 + (*p))
566
				goto out;
567 568
			pkt_len -= 1 + (*p);
			p += 1 + (*p);
569 570 571 572 573 574
		}
	}
out:
	return ret;
}

575
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
576 577 578 579 580 581 582
{
	struct ethhdr *ethhdr;
	struct iphdr *iphdr;
	struct ipv6hdr *ipv6hdr;
	struct udphdr *udphdr;

	/* check for ethernet header */
583 584
	if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
		return false;
585
	ethhdr = (struct ethhdr *)skb->data;
586
	*header_len += ETH_HLEN;
587 588 589

	/* check for initial vlan header */
	if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
590 591
		if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
			return false;
592
		ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
593
		*header_len += VLAN_HLEN;
594 595 596 597 598
	}

	/* check for ip header */
	switch (ntohs(ethhdr->h_proto)) {
	case ETH_P_IP:
599 600 601 602
		if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
			return false;
		iphdr = (struct iphdr *)(skb->data + *header_len);
		*header_len += iphdr->ihl * 4;
603 604 605

		/* check for udp header */
		if (iphdr->protocol != IPPROTO_UDP)
606
			return false;
607 608 609

		break;
	case ETH_P_IPV6:
610 611 612 613
		if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
			return false;
		ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
		*header_len += sizeof(*ipv6hdr);
614 615 616

		/* check for udp header */
		if (ipv6hdr->nexthdr != IPPROTO_UDP)
617
			return false;
618 619 620

		break;
	default:
621
		return false;
622 623
	}

624 625 626 627
	if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
		return false;
	udphdr = (struct udphdr *)(skb->data + *header_len);
	*header_len += sizeof(*udphdr);
628 629 630

	/* check for bootp port */
	if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
631
	    (ntohs(udphdr->dest) != 67))
632
		return false;
633 634 635

	if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
	    (ntohs(udphdr->dest) != 547))
636
		return false;
637

638 639
	return true;
}
640

641 642
bool batadv_gw_out_of_range(struct bat_priv *bat_priv,
			    struct sk_buff *skb, struct ethhdr *ethhdr)
643 644 645 646 647 648 649 650
{
	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
	struct orig_node *orig_dst_node = NULL;
	struct gw_node *curr_gw = NULL;
	bool ret, out_of_range = false;
	unsigned int header_len = 0;
	uint8_t curr_tq_avg;

651
	ret = batadv_gw_is_dhcp_target(skb, &header_len);
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
	if (!ret)
		goto out;

	orig_dst_node = transtable_search(bat_priv, ethhdr->h_source,
					  ethhdr->h_dest);
	if (!orig_dst_node)
		goto out;

	if (!orig_dst_node->gw_flags)
		goto out;

	ret = is_type_dhcprequest(skb, header_len);
	if (!ret)
		goto out;

	switch (atomic_read(&bat_priv->gw_mode)) {
	case GW_MODE_SERVER:
		/* If we are a GW then we are our best GW. We can artificially
		 * set the tq towards ourself as the maximum value */
		curr_tq_avg = TQ_MAX_VALUE;
		break;
	case GW_MODE_CLIENT:
		curr_gw = gw_get_selected_gw_node(bat_priv);
		if (!curr_gw)
			goto out;

		/* packet is going to our gateway */
		if (curr_gw->orig_node == orig_dst_node)
			goto out;

		/* If the dhcp packet has been sent to a different gw,
		 * we have to evaluate whether the old gw is still
		 * reliable enough */
		neigh_curr = find_router(bat_priv, curr_gw->orig_node, NULL);
		if (!neigh_curr)
			goto out;

		curr_tq_avg = neigh_curr->tq_avg;
		break;
	case GW_MODE_OFF:
	default:
		goto out;
694
	}
695 696

	neigh_old = find_router(bat_priv, orig_dst_node, NULL);
697
	if (!neigh_old)
698 699 700 701 702 703 704
		goto out;

	if (curr_tq_avg - neigh_old->tq_avg > GW_THRESHOLD)
		out_of_range = true;

out:
	if (orig_dst_node)
705
		batadv_orig_node_free_ref(orig_dst_node);
706 707
	if (curr_gw)
		gw_node_free_ref(curr_gw);
708
	if (neigh_old)
709
		batadv_neigh_node_free_ref(neigh_old);
710
	if (neigh_curr)
711
		batadv_neigh_node_free_ref(neigh_curr);
712
	return out_of_range;
713
}