diff options
Diffstat (limited to 'net/batman-adv')
-rw-r--r-- | net/batman-adv/gateway_client.c | 94 | ||||
-rw-r--r-- | net/batman-adv/gateway_client.h | 3 | ||||
-rw-r--r-- | net/batman-adv/main.h | 3 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.c | 10 |
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 | |||
33 | static void gw_node_free_ref(struct gw_node *gw_node) | 39 | static 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 | ||
512 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) | 518 | static 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 | } | ||
572 | out: | ||
573 | return ret; | ||
574 | } | ||
575 | |||
576 | int 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 | } | ||
672 | free_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, | |||
31 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); | 31 | void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node); |
32 | void gw_node_purge(struct bat_priv *bat_priv); | 32 | void gw_node_purge(struct bat_priv *bat_priv); |
33 | int gw_client_seq_print_text(struct seq_file *seq, void *offset); | 33 | int gw_client_seq_print_text(struct seq_file *seq, void *offset); |
34 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); | 34 | int 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 | |||
95 | enum uev_action { | 94 | enum 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 | ||