aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorAntonio Quartulli <ordex@autistici.org>2011-04-26 15:31:45 -0400
committerSven Eckelmann <sven@narfation.org>2011-06-20 05:37:41 -0400
commit43676ab590c3f8686fd047d34c3e33803eef71f0 (patch)
tree056303a6b33a23a74610cceee11c946847b22c61 /net/batman-adv
parent19595e054d35820e026caac314414e435287e3ae (diff)
batman-adv: improved gateway tq-based selection
If a client issues a DHCPREQUEST for renewal, the packet is dropped if the old destination (the old gateway for the client) TQ is smaller than the current best gateway TQ less GW_THRESHOLD Signed-off-by: Antonio Quartulli <ordex@autistici.org> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Sven Eckelmann <sven@narfation.org>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/gateway_client.c94
-rw-r--r--net/batman-adv/gateway_client.h3
-rw-r--r--net/batman-adv/main.h3
-rw-r--r--net/batman-adv/soft-interface.c10
4 files changed, 104 insertions, 6 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 6381864c1ca4..8b25b52a4764 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -25,11 +25,17 @@
25#include "gateway_common.h" 25#include "gateway_common.h"
26#include "hard-interface.h" 26#include "hard-interface.h"
27#include "originator.h" 27#include "originator.h"
28#include "routing.h"
28#include <linux/ip.h> 29#include <linux/ip.h>
29#include <linux/ipv6.h> 30#include <linux/ipv6.h>
30#include <linux/udp.h> 31#include <linux/udp.h>
31#include <linux/if_vlan.h> 32#include <linux/if_vlan.h>
32 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
33static void gw_node_free_ref(struct gw_node *gw_node) 39static void gw_node_free_ref(struct gw_node *gw_node)
34{ 40{
35 if (atomic_dec_and_test(&gw_node->refcount)) 41 if (atomic_dec_and_test(&gw_node->refcount))
@@ -509,14 +515,75 @@ out:
509 return ret; 515 return ret;
510} 516}
511 517
512int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) 518static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
519{
520 int ret = false;
521 unsigned char *p;
522 int pkt_len;
523
524 if (skb_linearize(skb) < 0)
525 goto out;
526
527 pkt_len = skb_headlen(skb);
528
529 if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
530 goto out;
531
532 p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
533 pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
534
535 /* Access the dhcp option lists. Each entry is made up by:
536 * - octect 1: option type
537 * - octect 2: option data len (only if type != 255 and 0)
538 * - octect 3: option data */
539 while (*p != 255 && !ret) {
540 /* p now points to the first octect: option type */
541 if (*p == 53) {
542 /* type 53 is the message type option.
543 * Jump the len octect and go to the data octect */
544 if (pkt_len < 2)
545 goto out;
546 p += 2;
547
548 /* check if the message type is what we need */
549 if (*p == DHCP_REQUEST)
550 ret = true;
551 break;
552 } else if (*p == 0) {
553 /* option type 0 (padding), just go forward */
554 if (pkt_len < 1)
555 goto out;
556 pkt_len--;
557 p++;
558 } else {
559 /* This is any other option. So we get the length... */
560 if (pkt_len < 1)
561 goto out;
562 pkt_len--;
563 p++;
564
565 /* ...and then we jump over the data */
566 if (pkt_len < *p)
567 goto out;
568 pkt_len -= *p;
569 p += (*p);
570 }
571 }
572out:
573 return ret;
574}
575
576int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
577 struct orig_node *old_gw)
513{ 578{
514 struct ethhdr *ethhdr; 579 struct ethhdr *ethhdr;
515 struct iphdr *iphdr; 580 struct iphdr *iphdr;
516 struct ipv6hdr *ipv6hdr; 581 struct ipv6hdr *ipv6hdr;
517 struct udphdr *udphdr; 582 struct udphdr *udphdr;
518 struct gw_node *curr_gw; 583 struct gw_node *curr_gw;
584 struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
519 unsigned int header_len = 0; 585 unsigned int header_len = 0;
586 int ret = 1;
520 587
521 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) 588 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
522 return 0; 589 return 0;
@@ -584,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
584 if (!curr_gw) 651 if (!curr_gw)
585 return 0; 652 return 0;
586 653
654 /* If old_gw != NULL then this packet is unicast.
655 * So, at this point we have to check the message type: if it is a
656 * DHCPREQUEST we have to decide whether to drop it or not */
657 if (old_gw && curr_gw->orig_node != old_gw) {
658 if (is_type_dhcprequest(skb, header_len)) {
659 /* If the dhcp packet has been sent to a different gw,
660 * we have to evaluate whether the old gw is still
661 * reliable enough */
662 neigh_curr = find_router(bat_priv, curr_gw->orig_node,
663 NULL);
664 neigh_old = find_router(bat_priv, old_gw, NULL);
665 if (!neigh_curr || !neigh_old)
666 goto free_neigh;
667 if (neigh_curr->tq_avg - neigh_old->tq_avg <
668 GW_THRESHOLD)
669 ret = -1;
670 }
671 }
672free_neigh:
673 if (neigh_old)
674 neigh_node_free_ref(neigh_old);
675 if (neigh_curr)
676 neigh_node_free_ref(neigh_curr);
587 if (curr_gw) 677 if (curr_gw)
588 gw_node_free_ref(curr_gw); 678 gw_node_free_ref(curr_gw);
589 return 1; 679 return ret;
590} 680}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index 1ce8c6066da1..b9b983c07feb 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
31void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); 31void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
32void gw_node_purge(struct bat_priv *bat_priv); 32void gw_node_purge(struct bat_priv *bat_priv);
33int gw_client_seq_print_text(struct seq_file *seq, void *offset); 33int gw_client_seq_print_text(struct seq_file *seq, void *offset);
34int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); 34int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
35 struct orig_node *old_gw);
35 36
36#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ 37#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index f9e0e174b3f6..4f293b594475 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -91,7 +91,6 @@ enum mesh_state {
91#define BCAST_QUEUE_LEN 256 91#define BCAST_QUEUE_LEN 256
92#define BATMAN_QUEUE_LEN 256 92#define BATMAN_QUEUE_LEN 256
93 93
94
95enum uev_action { 94enum uev_action {
96 UEV_ADD = 0, 95 UEV_ADD = 0,
97 UEV_DEL, 96 UEV_DEL,
@@ -102,6 +101,8 @@ enum uev_type {
102 UEV_GW = 0 101 UEV_GW = 0
103}; 102};
104 103
104#define GW_THRESHOLD 50
105
105/* 106/*
106 * Debug Messages 107 * Debug Messages
107 */ 108 */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 3371ece680a2..2dcdbb7a236c 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -30,6 +30,7 @@
30#include "gateway_common.h" 30#include "gateway_common.h"
31#include "gateway_client.h" 31#include "gateway_client.h"
32#include "bat_sysfs.h" 32#include "bat_sysfs.h"
33#include "originator.h"
33#include <linux/slab.h> 34#include <linux/slab.h>
34#include <linux/ethtool.h> 35#include <linux/ethtool.h>
35#include <linux/etherdevice.h> 36#include <linux/etherdevice.h>
@@ -561,6 +562,7 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
561 struct bcast_packet *bcast_packet; 562 struct bcast_packet *bcast_packet;
562 struct vlan_ethhdr *vhdr; 563 struct vlan_ethhdr *vhdr;
563 struct softif_neigh *curr_softif_neigh = NULL; 564 struct softif_neigh *curr_softif_neigh = NULL;
565 struct orig_node *orig_node = NULL;
564 int data_len = skb->len, ret; 566 int data_len = skb->len, ret;
565 short vid = -1; 567 short vid = -1;
566 bool do_bcast = false; 568 bool do_bcast = false;
@@ -595,8 +597,10 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
595 /* Register the client MAC in the transtable */ 597 /* Register the client MAC in the transtable */
596 tt_local_add(soft_iface, ethhdr->h_source); 598 tt_local_add(soft_iface, ethhdr->h_source);
597 599
598 if (is_multicast_ether_addr(ethhdr->h_dest)) { 600 orig_node = transtable_search(bat_priv, ethhdr->h_dest);
599 ret = gw_is_target(bat_priv, skb); 601 if (is_multicast_ether_addr(ethhdr->h_dest) ||
602 (orig_node && orig_node->gw_flags)) {
603 ret = gw_is_target(bat_priv, skb, orig_node);
600 604
601 if (ret < 0) 605 if (ret < 0)
602 goto dropped; 606 goto dropped;
@@ -656,6 +660,8 @@ end:
656 softif_neigh_free_ref(curr_softif_neigh); 660 softif_neigh_free_ref(curr_softif_neigh);
657 if (primary_if) 661 if (primary_if)
658 hardif_free_ref(primary_if); 662 hardif_free_ref(primary_if);
663 if (orig_node)
664 orig_node_free_ref(orig_node);
659 return NETDEV_TX_OK; 665 return NETDEV_TX_OK;
660} 666}
661 667