aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/gateway_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/gateway_client.c')
-rw-r--r--net/batman-adv/gateway_client.c268
1 files changed, 193 insertions, 75 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 61605a0f3f3..056180ef9e1 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -20,15 +20,22 @@
20 */ 20 */
21 21
22#include "main.h" 22#include "main.h"
23#include "bat_sysfs.h"
23#include "gateway_client.h" 24#include "gateway_client.h"
24#include "gateway_common.h" 25#include "gateway_common.h"
25#include "hard-interface.h" 26#include "hard-interface.h"
26#include "originator.h" 27#include "originator.h"
28#include "routing.h"
27#include <linux/ip.h> 29#include <linux/ip.h>
28#include <linux/ipv6.h> 30#include <linux/ipv6.h>
29#include <linux/udp.h> 31#include <linux/udp.h>
30#include <linux/if_vlan.h> 32#include <linux/if_vlan.h>
31 33
34/* This is the offset of the options field in a dhcp packet starting at
35 * the beginning of the dhcp header */
36#define DHCP_OPTIONS_OFFSET 240
37#define DHCP_REQUEST 3
38
32static void gw_node_free_ref(struct gw_node *gw_node) 39static void gw_node_free_ref(struct gw_node *gw_node)
33{ 40{
34 if (atomic_dec_and_test(&gw_node->refcount)) 41 if (atomic_dec_and_test(&gw_node->refcount))
@@ -86,7 +93,7 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
86 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) 93 if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount))
87 new_gw_node = NULL; 94 new_gw_node = NULL;
88 95
89 curr_gw_node = bat_priv->curr_gw; 96 curr_gw_node = rcu_dereference_protected(bat_priv->curr_gw, 1);
90 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node); 97 rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
91 98
92 if (curr_gw_node) 99 if (curr_gw_node)
@@ -97,40 +104,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
97 104
98void gw_deselect(struct bat_priv *bat_priv) 105void gw_deselect(struct bat_priv *bat_priv)
99{ 106{
100 gw_select(bat_priv, NULL); 107 atomic_set(&bat_priv->gw_reselect, 1);
101} 108}
102 109
103void gw_election(struct bat_priv *bat_priv) 110static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
104{ 111{
105 struct hlist_node *node;
106 struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
107 struct neigh_node *router; 112 struct neigh_node *router;
108 uint8_t max_tq = 0; 113 struct hlist_node *node;
114 struct gw_node *gw_node, *curr_gw = NULL;
109 uint32_t max_gw_factor = 0, tmp_gw_factor = 0; 115 uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
116 uint8_t max_tq = 0;
110 int down, up; 117 int down, up;
111 118
112 /**
113 * The batman daemon checks here if we already passed a full originator
114 * cycle in order to make sure we don't choose the first gateway we
115 * hear about. This check is based on the daemon's uptime which we
116 * don't have.
117 **/
118 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
119 return;
120
121 curr_gw = gw_get_selected_gw_node(bat_priv);
122 if (curr_gw)
123 goto out;
124
125 rcu_read_lock(); 119 rcu_read_lock();
126 if (hlist_empty(&bat_priv->gw_list)) {
127 bat_dbg(DBG_BATMAN, bat_priv,
128 "Removing selected gateway - "
129 "no gateway in range\n");
130 gw_deselect(bat_priv);
131 goto unlock;
132 }
133
134 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { 120 hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
135 if (gw_node->deleted) 121 if (gw_node->deleted)
136 continue; 122 continue;
@@ -139,6 +125,9 @@ void gw_election(struct bat_priv *bat_priv)
139 if (!router) 125 if (!router)
140 continue; 126 continue;
141 127
128 if (!atomic_inc_not_zero(&gw_node->refcount))
129 goto next;
130
142 switch (atomic_read(&bat_priv->gw_sel_class)) { 131 switch (atomic_read(&bat_priv->gw_sel_class)) {
143 case 1: /* fast connection */ 132 case 1: /* fast connection */
144 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, 133 gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +140,12 @@ void gw_election(struct bat_priv *bat_priv)
151 140
152 if ((tmp_gw_factor > max_gw_factor) || 141 if ((tmp_gw_factor > max_gw_factor) ||
153 ((tmp_gw_factor == max_gw_factor) && 142 ((tmp_gw_factor == max_gw_factor) &&
154 (router->tq_avg > max_tq))) 143 (router->tq_avg > max_tq))) {
155 curr_gw_tmp = gw_node; 144 if (curr_gw)
145 gw_node_free_ref(curr_gw);
146 curr_gw = gw_node;
147 atomic_inc(&curr_gw->refcount);
148 }
156 break; 149 break;
157 150
158 default: /** 151 default: /**
@@ -163,8 +156,12 @@ void gw_election(struct bat_priv *bat_priv)
163 * soon as a better gateway appears which has 156 * soon as a better gateway appears which has
164 * $routing_class more tq points) 157 * $routing_class more tq points)
165 **/ 158 **/
166 if (router->tq_avg > max_tq) 159 if (router->tq_avg > max_tq) {
167 curr_gw_tmp = gw_node; 160 if (curr_gw)
161 gw_node_free_ref(curr_gw);
162 curr_gw = gw_node;
163 atomic_inc(&curr_gw->refcount);
164 }
168 break; 165 break;
169 } 166 }
170 167
@@ -174,42 +171,81 @@ void gw_election(struct bat_priv *bat_priv)
174 if (tmp_gw_factor > max_gw_factor) 171 if (tmp_gw_factor > max_gw_factor)
175 max_gw_factor = tmp_gw_factor; 172 max_gw_factor = tmp_gw_factor;
176 173
174 gw_node_free_ref(gw_node);
175
176next:
177 neigh_node_free_ref(router); 177 neigh_node_free_ref(router);
178 } 178 }
179 rcu_read_unlock();
179 180
180 if (curr_gw != curr_gw_tmp) { 181 return curr_gw;
181 router = orig_node_get_router(curr_gw_tmp->orig_node); 182}
182 if (!router)
183 goto unlock;
184 183
185 if ((curr_gw) && (!curr_gw_tmp)) 184void gw_election(struct bat_priv *bat_priv)
186 bat_dbg(DBG_BATMAN, bat_priv, 185{
187 "Removing selected gateway - " 186 struct gw_node *curr_gw = NULL, *next_gw = NULL;
188 "no gateway in range\n"); 187 struct neigh_node *router = NULL;
189 else if ((!curr_gw) && (curr_gw_tmp)) 188 char gw_addr[18] = { '\0' };
190 bat_dbg(DBG_BATMAN, bat_priv,
191 "Adding route to gateway %pM "
192 "(gw_flags: %i, tq: %i)\n",
193 curr_gw_tmp->orig_node->orig,
194 curr_gw_tmp->orig_node->gw_flags,
195 router->tq_avg);
196 else
197 bat_dbg(DBG_BATMAN, bat_priv,
198 "Changing route to gateway %pM "
199 "(gw_flags: %i, tq: %i)\n",
200 curr_gw_tmp->orig_node->orig,
201 curr_gw_tmp->orig_node->gw_flags,
202 router->tq_avg);
203 189
204 neigh_node_free_ref(router); 190 /**
205 gw_select(bat_priv, curr_gw_tmp); 191 * The batman daemon checks here if we already passed a full originator
192 * cycle in order to make sure we don't choose the first gateway we
193 * hear about. This check is based on the daemon's uptime which we
194 * don't have.
195 **/
196 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
197 goto out;
198
199 if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
200 goto out;
201
202 curr_gw = gw_get_selected_gw_node(bat_priv);
203
204 next_gw = gw_get_best_gw_node(bat_priv);
205
206 if (curr_gw == next_gw)
207 goto out;
208
209 if (next_gw) {
210 sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
211
212 router = orig_node_get_router(next_gw->orig_node);
213 if (!router) {
214 gw_deselect(bat_priv);
215 goto out;
216 }
206 } 217 }
207 218
208unlock: 219 if ((curr_gw) && (!next_gw)) {
209 rcu_read_unlock(); 220 bat_dbg(DBG_BATMAN, bat_priv,
221 "Removing selected gateway - no gateway in range\n");
222 throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
223 } else if ((!curr_gw) && (next_gw)) {
224 bat_dbg(DBG_BATMAN, bat_priv,
225 "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
226 next_gw->orig_node->orig,
227 next_gw->orig_node->gw_flags,
228 router->tq_avg);
229 throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
230 } else {
231 bat_dbg(DBG_BATMAN, bat_priv,
232 "Changing route to gateway %pM "
233 "(gw_flags: %i, tq: %i)\n",
234 next_gw->orig_node->orig,
235 next_gw->orig_node->gw_flags,
236 router->tq_avg);
237 throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
238 }
239
240 gw_select(bat_priv, next_gw);
241
210out: 242out:
211 if (curr_gw) 243 if (curr_gw)
212 gw_node_free_ref(curr_gw); 244 gw_node_free_ref(curr_gw);
245 if (next_gw)
246 gw_node_free_ref(next_gw);
247 if (router)
248 neigh_node_free_ref(router);
213} 249}
214 250
215void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) 251void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
@@ -273,11 +309,10 @@ static void gw_node_add(struct bat_priv *bat_priv,
273 struct gw_node *gw_node; 309 struct gw_node *gw_node;
274 int down, up; 310 int down, up;
275 311
276 gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); 312 gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC);
277 if (!gw_node) 313 if (!gw_node)
278 return; 314 return;
279 315
280 memset(gw_node, 0, sizeof(struct gw_node));
281 INIT_HLIST_NODE(&gw_node->list); 316 INIT_HLIST_NODE(&gw_node->list);
282 gw_node->orig_node = orig_node; 317 gw_node->orig_node = orig_node;
283 atomic_set(&gw_node->refcount, 1); 318 atomic_set(&gw_node->refcount, 1);
@@ -323,7 +358,7 @@ void gw_node_update(struct bat_priv *bat_priv,
323 358
324 gw_node->deleted = 0; 359 gw_node->deleted = 0;
325 360
326 if (new_gwflags == 0) { 361 if (new_gwflags == NO_FLAGS) {
327 gw_node->deleted = jiffies; 362 gw_node->deleted = jiffies;
328 bat_dbg(DBG_BATMAN, bat_priv, 363 bat_dbg(DBG_BATMAN, bat_priv,
329 "Gateway %pM removed from gateway list\n", 364 "Gateway %pM removed from gateway list\n",
@@ -336,7 +371,7 @@ void gw_node_update(struct bat_priv *bat_priv,
336 goto unlock; 371 goto unlock;
337 } 372 }
338 373
339 if (new_gwflags == 0) 374 if (new_gwflags == NO_FLAGS)
340 goto unlock; 375 goto unlock;
341 376
342 gw_node_add(bat_priv, orig_node, new_gwflags); 377 gw_node_add(bat_priv, orig_node, new_gwflags);
@@ -353,7 +388,7 @@ unlock:
353 388
354void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) 389void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node)
355{ 390{
356 return gw_node_update(bat_priv, orig_node, 0); 391 gw_node_update(bat_priv, orig_node, 0);
357} 392}
358 393
359void gw_node_purge(struct bat_priv *bat_priv) 394void gw_node_purge(struct bat_priv *bat_priv)
@@ -361,7 +396,7 @@ void gw_node_purge(struct bat_priv *bat_priv)
361 struct gw_node *gw_node, *curr_gw; 396 struct gw_node *gw_node, *curr_gw;
362 struct hlist_node *node, *node_tmp; 397 struct hlist_node *node, *node_tmp;
363 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; 398 unsigned long timeout = 2 * PURGE_TIMEOUT * HZ;
364 char do_deselect = 0; 399 int do_deselect = 0;
365 400
366 curr_gw = gw_get_selected_gw_node(bat_priv); 401 curr_gw = gw_get_selected_gw_node(bat_priv);
367 402
@@ -394,8 +429,8 @@ void gw_node_purge(struct bat_priv *bat_priv)
394/** 429/**
395 * fails if orig_node has no router 430 * fails if orig_node has no router
396 */ 431 */
397static int _write_buffer_text(struct bat_priv *bat_priv, 432static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq,
398 struct seq_file *seq, struct gw_node *gw_node) 433 const struct gw_node *gw_node)
399{ 434{
400 struct gw_node *curr_gw; 435 struct gw_node *curr_gw;
401 struct neigh_node *router; 436 struct neigh_node *router;
@@ -452,10 +487,9 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
452 } 487 }
453 488
454 seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " 489 seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... "
455 "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", 490 "[B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
456 "Gateway", "#", TQ_MAX_VALUE, "Nexthop", 491 "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
457 "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, 492 "outgoingIF", SOURCE_VERSION, primary_if->net_dev->name,
458 primary_if->net_dev->name,
459 primary_if->net_dev->dev_addr, net_dev->name); 493 primary_if->net_dev->dev_addr, net_dev->name);
460 494
461 rcu_read_lock(); 495 rcu_read_lock();
@@ -480,14 +514,75 @@ out:
480 return ret; 514 return ret;
481} 515}
482 516
483int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) 517static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
518{
519 int ret = false;
520 unsigned char *p;
521 int pkt_len;
522
523 if (skb_linearize(skb) < 0)
524 goto out;
525
526 pkt_len = skb_headlen(skb);
527
528 if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
529 goto out;
530
531 p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
532 pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
533
534 /* Access the dhcp option lists. Each entry is made up by:
535 * - octect 1: option type
536 * - octect 2: option data len (only if type != 255 and 0)
537 * - octect 3: option data */
538 while (*p != 255 && !ret) {
539 /* p now points to the first octect: option type */
540 if (*p == 53) {
541 /* type 53 is the message type option.
542 * Jump the len octect and go to the data octect */
543 if (pkt_len < 2)
544 goto out;
545 p += 2;
546
547 /* check if the message type is what we need */
548 if (*p == DHCP_REQUEST)
549 ret = true;
550 break;
551 } else if (*p == 0) {
552 /* option type 0 (padding), just go forward */
553 if (pkt_len < 1)
554 goto out;
555 pkt_len--;
556 p++;
557 } else {
558 /* This is any other option. So we get the length... */
559 if (pkt_len < 1)
560 goto out;
561 pkt_len--;
562 p++;
563
564 /* ...and then we jump over the data */
565 if (pkt_len < *p)
566 goto out;
567 pkt_len -= *p;
568 p += (*p);
569 }
570 }
571out:
572 return ret;
573}
574
575int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
576 struct orig_node *old_gw)
484{ 577{
485 struct ethhdr *ethhdr; 578 struct ethhdr *ethhdr;
486 struct iphdr *iphdr; 579 struct iphdr *iphdr;
487 struct ipv6hdr *ipv6hdr; 580 struct ipv6hdr *ipv6hdr;
488 struct udphdr *udphdr; 581 struct udphdr *udphdr;
489 struct gw_node *curr_gw; 582 struct gw_node *curr_gw;
583 struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
490 unsigned int header_len = 0; 584 unsigned int header_len = 0;
585 int ret = 1;
491 586
492 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) 587 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
493 return 0; 588 return 0;
@@ -509,7 +604,7 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
509 /* check for ip header */ 604 /* check for ip header */
510 switch (ntohs(ethhdr->h_proto)) { 605 switch (ntohs(ethhdr->h_proto)) {
511 case ETH_P_IP: 606 case ETH_P_IP:
512 if (!pskb_may_pull(skb, header_len + sizeof(struct iphdr))) 607 if (!pskb_may_pull(skb, header_len + sizeof(*iphdr)))
513 return 0; 608 return 0;
514 iphdr = (struct iphdr *)(skb->data + header_len); 609 iphdr = (struct iphdr *)(skb->data + header_len);
515 header_len += iphdr->ihl * 4; 610 header_len += iphdr->ihl * 4;
@@ -520,10 +615,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
520 615
521 break; 616 break;
522 case ETH_P_IPV6: 617 case ETH_P_IPV6:
523 if (!pskb_may_pull(skb, header_len + sizeof(struct ipv6hdr))) 618 if (!pskb_may_pull(skb, header_len + sizeof(*ipv6hdr)))
524 return 0; 619 return 0;
525 ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); 620 ipv6hdr = (struct ipv6hdr *)(skb->data + header_len);
526 header_len += sizeof(struct ipv6hdr); 621 header_len += sizeof(*ipv6hdr);
527 622
528 /* check for udp header */ 623 /* check for udp header */
529 if (ipv6hdr->nexthdr != IPPROTO_UDP) 624 if (ipv6hdr->nexthdr != IPPROTO_UDP)
@@ -534,10 +629,10 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
534 return 0; 629 return 0;
535 } 630 }
536 631
537 if (!pskb_may_pull(skb, header_len + sizeof(struct udphdr))) 632 if (!pskb_may_pull(skb, header_len + sizeof(*udphdr)))
538 return 0; 633 return 0;
539 udphdr = (struct udphdr *)(skb->data + header_len); 634 udphdr = (struct udphdr *)(skb->data + header_len);
540 header_len += sizeof(struct udphdr); 635 header_len += sizeof(*udphdr);
541 636
542 /* check for bootp port */ 637 /* check for bootp port */
543 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && 638 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
@@ -555,7 +650,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
555 if (!curr_gw) 650 if (!curr_gw)
556 return 0; 651 return 0;
557 652
653 /* If old_gw != NULL then this packet is unicast.
654 * So, at this point we have to check the message type: if it is a
655 * DHCPREQUEST we have to decide whether to drop it or not */
656 if (old_gw && curr_gw->orig_node != old_gw) {
657 if (is_type_dhcprequest(skb, header_len)) {
658 /* If the dhcp packet has been sent to a different gw,
659 * we have to evaluate whether the old gw is still
660 * reliable enough */
661 neigh_curr = find_router(bat_priv, curr_gw->orig_node,
662 NULL);
663 neigh_old = find_router(bat_priv, old_gw, NULL);
664 if (!neigh_curr || !neigh_old)
665 goto free_neigh;
666 if (neigh_curr->tq_avg - neigh_old->tq_avg <
667 GW_THRESHOLD)
668 ret = -1;
669 }
670 }
671free_neigh:
672 if (neigh_old)
673 neigh_node_free_ref(neigh_old);
674 if (neigh_curr)
675 neigh_node_free_ref(neigh_curr);
558 if (curr_gw) 676 if (curr_gw)
559 gw_node_free_ref(curr_gw); 677 gw_node_free_ref(curr_gw);
560 return 1; 678 return ret;
561} 679}