aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorAntonio Quartulli <antonio@open-mesh.com>2013-11-05 13:31:08 -0500
committerAntonio Quartulli <antonio@meshcoding.com>2014-01-08 14:49:42 -0500
commit6c413b1c22a2c4ef324f1c6f2c282f1ca10a93b9 (patch)
tree5e7d10d691a64b8ae180d4f718a41120118c6432 /net/batman-adv
parent36484f84d567f79fc7cc62c4391c7752a0ede7f2 (diff)
batman-adv: send every DHCP packet as bat-unicast
In different situations it is possible that the DHCP server or client uses broadcast Ethernet frames to send messages to each other. The GW component in batman-adv takes care of using bat-unicast packets to bring broadcast DHCP Discover/Requests to the "best" server. On the way back the DHCP server usually sends unicasts, but upon client request it may decide to use broadcasts as well. This patch improves the GW component so that it now snoops and sends as unicast all the DHCP packets, no matter if they were generated by a DHCP server or client. Signed-off-by: Antonio Quartulli <antonio@open-mesh.com> Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/distributed-arp-table.c4
-rw-r--r--net/batman-adv/gateway_client.c171
-rw-r--r--net/batman-adv/gateway_client.h4
-rw-r--r--net/batman-adv/send.c16
-rw-r--r--net/batman-adv/send.h10
-rw-r--r--net/batman-adv/soft-interface.c76
-rw-r--r--net/batman-adv/types.h12
7 files changed, 153 insertions, 140 deletions
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 93e1fb049055..997ae6ac51ff 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1037,9 +1037,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
1037 if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) 1037 if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
1038 err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new, 1038 err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
1039 BATADV_P_DAT_CACHE_REPLY, 1039 BATADV_P_DAT_CACHE_REPLY,
1040 vid); 1040 NULL, vid);
1041 else 1041 else
1042 err = batadv_send_skb_via_tt(bat_priv, skb_new, vid); 1042 err = batadv_send_skb_via_tt(bat_priv, skb_new, NULL, vid);
1043 1043
1044 if (err != NET_XMIT_DROP) { 1044 if (err != NET_XMIT_DROP) {
1045 batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX); 1045 batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index a5602ef0f262..4150a641c52e 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -28,11 +28,17 @@
28#include <linux/udp.h> 28#include <linux/udp.h>
29#include <linux/if_vlan.h> 29#include <linux/if_vlan.h>
30 30
31/* This is the offset of the options field in a dhcp packet starting at 31/* These are the offsets of the "hw type" and "hw address length" in the dhcp
32 * the beginning of the dhcp header 32 * packet starting at the beginning of the dhcp header
33 */ 33 */
34#define BATADV_DHCP_OPTIONS_OFFSET 240 34#define BATADV_DHCP_HTYPE_OFFSET 1
35#define BATADV_DHCP_REQUEST 3 35#define BATADV_DHCP_HLEN_OFFSET 2
36/* Value of htype representing Ethernet */
37#define BATADV_DHCP_HTYPE_ETHERNET 0x01
38/* This is the offset of the "chaddr" field in the dhcp packet starting at the
39 * beginning of the dhcp header
40 */
41#define BATADV_DHCP_CHADDR_OFFSET 28
36 42
37static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node) 43static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node)
38{ 44{
@@ -596,80 +602,39 @@ out:
596 return 0; 602 return 0;
597} 603}
598 604
599/* this call might reallocate skb data */ 605/**
600static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) 606 * batadv_gw_dhcp_recipient_get - check if a packet is a DHCP message
601{ 607 * @skb: the packet to check
602 int ret = false; 608 * @header_len: a pointer to the batman-adv header size
603 unsigned char *p; 609 * @chaddr: buffer where the client address will be stored. Valid
604 int pkt_len; 610 * only if the function returns BATADV_DHCP_TO_CLIENT
605 611 *
606 if (skb_linearize(skb) < 0) 612 * Returns:
607 goto out; 613 * - BATADV_DHCP_NO if the packet is not a dhcp message or if there was an error
608 614 * while parsing it
609 pkt_len = skb_headlen(skb); 615 * - BATADV_DHCP_TO_SERVER if this is a message going to the DHCP server
610 616 * - BATADV_DHCP_TO_CLIENT if this is a message going to a DHCP client
611 if (pkt_len < header_len + BATADV_DHCP_OPTIONS_OFFSET + 1) 617 *
612 goto out; 618 * This function may re-allocate the data buffer of the skb passed as argument.
613 619 */
614 p = skb->data + header_len + BATADV_DHCP_OPTIONS_OFFSET; 620enum batadv_dhcp_recipient
615 pkt_len -= header_len + BATADV_DHCP_OPTIONS_OFFSET + 1; 621batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
616 622 uint8_t *chaddr)
617 /* Access the dhcp option lists. Each entry is made up by:
618 * - octet 1: option type
619 * - octet 2: option data len (only if type != 255 and 0)
620 * - octet 3: option data
621 */
622 while (*p != 255 && !ret) {
623 /* p now points to the first octet: option type */
624 if (*p == 53) {
625 /* type 53 is the message type option.
626 * Jump the len octet and go to the data octet
627 */
628 if (pkt_len < 2)
629 goto out;
630 p += 2;
631
632 /* check if the message type is what we need */
633 if (*p == BATADV_DHCP_REQUEST)
634 ret = true;
635 break;
636 } else if (*p == 0) {
637 /* option type 0 (padding), just go forward */
638 if (pkt_len < 1)
639 goto out;
640 pkt_len--;
641 p++;
642 } else {
643 /* This is any other option. So we get the length... */
644 if (pkt_len < 1)
645 goto out;
646 pkt_len--;
647 p++;
648
649 /* ...and then we jump over the data */
650 if (pkt_len < 1 + (*p))
651 goto out;
652 pkt_len -= 1 + (*p);
653 p += 1 + (*p);
654 }
655 }
656out:
657 return ret;
658}
659
660/* this call might reallocate skb data */
661bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
662{ 623{
624 enum batadv_dhcp_recipient ret = BATADV_DHCP_NO;
663 struct ethhdr *ethhdr; 625 struct ethhdr *ethhdr;
664 struct iphdr *iphdr; 626 struct iphdr *iphdr;
665 struct ipv6hdr *ipv6hdr; 627 struct ipv6hdr *ipv6hdr;
666 struct udphdr *udphdr; 628 struct udphdr *udphdr;
667 struct vlan_ethhdr *vhdr; 629 struct vlan_ethhdr *vhdr;
630 int chaddr_offset;
668 __be16 proto; 631 __be16 proto;
632 uint8_t *p;
669 633
670 /* check for ethernet header */ 634 /* check for ethernet header */
671 if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) 635 if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
672 return false; 636 return BATADV_DHCP_NO;
637
673 ethhdr = (struct ethhdr *)skb->data; 638 ethhdr = (struct ethhdr *)skb->data;
674 proto = ethhdr->h_proto; 639 proto = ethhdr->h_proto;
675 *header_len += ETH_HLEN; 640 *header_len += ETH_HLEN;
@@ -677,7 +642,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
677 /* check for initial vlan header */ 642 /* check for initial vlan header */
678 if (proto == htons(ETH_P_8021Q)) { 643 if (proto == htons(ETH_P_8021Q)) {
679 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN)) 644 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
680 return false; 645 return BATADV_DHCP_NO;
681 646
682 vhdr = (struct vlan_ethhdr *)skb->data; 647 vhdr = (struct vlan_ethhdr *)skb->data;
683 proto = vhdr->h_vlan_encapsulated_proto; 648 proto = vhdr->h_vlan_encapsulated_proto;
@@ -688,32 +653,34 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
688 switch (proto) { 653 switch (proto) {
689 case htons(ETH_P_IP): 654 case htons(ETH_P_IP):
690 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr))) 655 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
691 return false; 656 return BATADV_DHCP_NO;
657
692 iphdr = (struct iphdr *)(skb->data + *header_len); 658 iphdr = (struct iphdr *)(skb->data + *header_len);
693 *header_len += iphdr->ihl * 4; 659 *header_len += iphdr->ihl * 4;
694 660
695 /* check for udp header */ 661 /* check for udp header */
696 if (iphdr->protocol != IPPROTO_UDP) 662 if (iphdr->protocol != IPPROTO_UDP)
697 return false; 663 return BATADV_DHCP_NO;
698 664
699 break; 665 break;
700 case htons(ETH_P_IPV6): 666 case htons(ETH_P_IPV6):
701 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr))) 667 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
702 return false; 668 return BATADV_DHCP_NO;
669
703 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len); 670 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
704 *header_len += sizeof(*ipv6hdr); 671 *header_len += sizeof(*ipv6hdr);
705 672
706 /* check for udp header */ 673 /* check for udp header */
707 if (ipv6hdr->nexthdr != IPPROTO_UDP) 674 if (ipv6hdr->nexthdr != IPPROTO_UDP)
708 return false; 675 return BATADV_DHCP_NO;
709 676
710 break; 677 break;
711 default: 678 default:
712 return false; 679 return BATADV_DHCP_NO;
713 } 680 }
714 681
715 if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr))) 682 if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
716 return false; 683 return BATADV_DHCP_NO;
717 684
718 /* skb->data might have been reallocated by pskb_may_pull() */ 685 /* skb->data might have been reallocated by pskb_may_pull() */
719 ethhdr = (struct ethhdr *)skb->data; 686 ethhdr = (struct ethhdr *)skb->data;
@@ -724,17 +691,40 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
724 *header_len += sizeof(*udphdr); 691 *header_len += sizeof(*udphdr);
725 692
726 /* check for bootp port */ 693 /* check for bootp port */
727 if ((proto == htons(ETH_P_IP)) && 694 switch (proto) {
728 (udphdr->dest != htons(67))) 695 case htons(ETH_P_IP):
729 return false; 696 if (udphdr->dest == htons(67))
697 ret = BATADV_DHCP_TO_SERVER;
698 else if (udphdr->source == htons(67))
699 ret = BATADV_DHCP_TO_CLIENT;
700 break;
701 case htons(ETH_P_IPV6):
702 if (udphdr->dest == htons(547))
703 ret = BATADV_DHCP_TO_SERVER;
704 else if (udphdr->source == htons(547))
705 ret = BATADV_DHCP_TO_CLIENT;
706 break;
707 }
730 708
731 if ((proto == htons(ETH_P_IPV6)) && 709 chaddr_offset = *header_len + BATADV_DHCP_CHADDR_OFFSET;
732 (udphdr->dest != htons(547))) 710 /* store the client address if the message is going to a client */
733 return false; 711 if (ret == BATADV_DHCP_TO_CLIENT &&
712 pskb_may_pull(skb, chaddr_offset + ETH_ALEN)) {
713 /* check if the DHCP packet carries an Ethernet DHCP */
714 p = skb->data + *header_len + BATADV_DHCP_HTYPE_OFFSET;
715 if (*p != BATADV_DHCP_HTYPE_ETHERNET)
716 return BATADV_DHCP_NO;
717
718 /* check if the DHCP packet carries a valid Ethernet address */
719 p = skb->data + *header_len + BATADV_DHCP_HLEN_OFFSET;
720 if (*p != ETH_ALEN)
721 return BATADV_DHCP_NO;
722
723 memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN);
724 }
734 725
735 return true; 726 return ret;
736} 727}
737
738/** 728/**
739 * batadv_gw_out_of_range - check if the dhcp request destination is the best gw 729 * batadv_gw_out_of_range - check if the dhcp request destination is the best gw
740 * @bat_priv: the bat priv with all the soft interface information 730 * @bat_priv: the bat priv with all the soft interface information
@@ -748,6 +738,7 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
748 * false otherwise. 738 * false otherwise.
749 * 739 *
750 * This call might reallocate skb data. 740 * This call might reallocate skb data.
741 * Must be invoked only when the DHCP packet is going TO a DHCP SERVER.
751 */ 742 */
752bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, 743bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
753 struct sk_buff *skb) 744 struct sk_buff *skb)
@@ -755,19 +746,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
755 struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; 746 struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
756 struct batadv_orig_node *orig_dst_node = NULL; 747 struct batadv_orig_node *orig_dst_node = NULL;
757 struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; 748 struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL;
758 struct ethhdr *ethhdr; 749 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
759 bool ret, out_of_range = false; 750 bool out_of_range = false;
760 unsigned int header_len = 0;
761 uint8_t curr_tq_avg; 751 uint8_t curr_tq_avg;
762 unsigned short vid; 752 unsigned short vid;
763 753
764 vid = batadv_get_vid(skb, 0); 754 vid = batadv_get_vid(skb, 0);
765 755
766 ret = batadv_gw_is_dhcp_target(skb, &header_len);
767 if (!ret)
768 goto out;
769
770 ethhdr = (struct ethhdr *)skb->data;
771 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, 756 orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
772 ethhdr->h_dest, vid); 757 ethhdr->h_dest, vid);
773 if (!orig_dst_node) 758 if (!orig_dst_node)
@@ -777,10 +762,6 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
777 if (!gw_node->bandwidth_down == 0) 762 if (!gw_node->bandwidth_down == 0)
778 goto out; 763 goto out;
779 764
780 ret = batadv_is_type_dhcprequest(skb, header_len);
781 if (!ret)
782 goto out;
783
784 switch (atomic_read(&bat_priv->gw_mode)) { 765 switch (atomic_read(&bat_priv->gw_mode)) {
785 case BATADV_GW_MODE_SERVER: 766 case BATADV_GW_MODE_SERVER:
786 /* If we are a GW then we are our best GW. We can artificially 767 /* If we are a GW then we are our best GW. We can artificially
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index 514cff68890c..006befb8c7b8 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -32,7 +32,9 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
32 struct batadv_orig_node *orig_node); 32 struct batadv_orig_node *orig_node);
33void batadv_gw_node_purge(struct batadv_priv *bat_priv); 33void batadv_gw_node_purge(struct batadv_priv *bat_priv);
34int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); 34int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
35bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
36bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); 35bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
36enum batadv_dhcp_recipient
37batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
38 uint8_t *chaddr);
37 39
38#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ 40#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index cea6578ee7be..30d12c445ea3 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -319,13 +319,23 @@ out:
319 */ 319 */
320int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, 320int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
321 struct sk_buff *skb, int packet_type, 321 struct sk_buff *skb, int packet_type,
322 int packet_subtype, unsigned short vid) 322 int packet_subtype, uint8_t *dst_hint,
323 unsigned short vid)
323{ 324{
324 struct ethhdr *ethhdr = (struct ethhdr *)skb->data; 325 struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
325 struct batadv_orig_node *orig_node; 326 struct batadv_orig_node *orig_node;
327 uint8_t *src, *dst;
328
329 src = ethhdr->h_source;
330 dst = ethhdr->h_dest;
331
332 /* if we got an hint! let's send the packet to this client (if any) */
333 if (dst_hint) {
334 src = NULL;
335 dst = dst_hint;
336 }
337 orig_node = batadv_transtable_search(bat_priv, src, dst, vid);
326 338
327 orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
328 ethhdr->h_dest, vid);
329 return batadv_send_skb_unicast(bat_priv, skb, packet_type, 339 return batadv_send_skb_unicast(bat_priv, skb, packet_type,
330 packet_subtype, orig_node, vid); 340 packet_subtype, orig_node, vid);
331} 341}
diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h
index f6d125e2a15b..0b17f8d56f2e 100644
--- a/net/batman-adv/send.h
+++ b/net/batman-adv/send.h
@@ -38,7 +38,8 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
38 int packet_subtype); 38 int packet_subtype);
39int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, 39int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
40 struct sk_buff *skb, int packet_type, 40 struct sk_buff *skb, int packet_type,
41 int packet_subtype, unsigned short vid); 41 int packet_subtype, uint8_t *dst_hint,
42 unsigned short vid);
42int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, 43int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
43 unsigned short vid); 44 unsigned short vid);
44 45
@@ -55,11 +56,11 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
55 * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. 56 * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
56 */ 57 */
57static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, 58static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
58 struct sk_buff *skb, 59 struct sk_buff *skb, uint8_t *dst_hint,
59 unsigned short vid) 60 unsigned short vid)
60{ 61{
61 return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, 62 return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
62 vid); 63 dst_hint, vid);
63} 64}
64 65
65/** 66/**
@@ -79,11 +80,12 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
79static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, 80static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
80 struct sk_buff *skb, 81 struct sk_buff *skb,
81 int packet_subtype, 82 int packet_subtype,
83 uint8_t *dst_hint,
82 unsigned short vid) 84 unsigned short vid)
83{ 85{
84 return batadv_send_skb_via_tt_generic(bat_priv, skb, 86 return batadv_send_skb_via_tt_generic(bat_priv, skb,
85 BATADV_UNICAST_4ADDR, 87 BATADV_UNICAST_4ADDR,
86 packet_subtype, vid); 88 packet_subtype, dst_hint, vid);
87} 89}
88 90
89#endif /* _NET_BATMAN_ADV_SEND_H_ */ 91#endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 3686be7805f3..b569932ddcc4 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -160,6 +160,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
160 0x00, 0x00}; 160 0x00, 0x00};
161 static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 161 static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
162 0x00, 0x00}; 162 0x00, 0x00};
163 enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
164 uint8_t *dst_hint = NULL, chaddr[ETH_ALEN];
163 struct vlan_ethhdr *vhdr; 165 struct vlan_ethhdr *vhdr;
164 unsigned int header_len = 0; 166 unsigned int header_len = 0;
165 int data_len = skb->len, ret; 167 int data_len = skb->len, ret;
@@ -167,6 +169,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
167 bool do_bcast = false, client_added; 169 bool do_bcast = false, client_added;
168 unsigned short vid; 170 unsigned short vid;
169 uint32_t seqno; 171 uint32_t seqno;
172 int gw_mode;
170 173
171 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 174 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
172 goto dropped; 175 goto dropped;
@@ -213,36 +216,39 @@ static int batadv_interface_tx(struct sk_buff *skb,
213 if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) 216 if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
214 goto dropped; 217 goto dropped;
215 218
219 gw_mode = atomic_read(&bat_priv->gw_mode);
216 if (is_multicast_ether_addr(ethhdr->h_dest)) { 220 if (is_multicast_ether_addr(ethhdr->h_dest)) {
217 do_bcast = true; 221 /* if gw mode is off, broadcast every packet */
218 222 if (gw_mode == BATADV_GW_MODE_OFF) {
219 switch (atomic_read(&bat_priv->gw_mode)) { 223 do_bcast = true;
220 case BATADV_GW_MODE_SERVER: 224 goto send;
221 /* gateway servers should not send dhcp
222 * requests into the mesh
223 */
224 ret = batadv_gw_is_dhcp_target(skb, &header_len);
225 if (ret)
226 goto dropped;
227 break;
228 case BATADV_GW_MODE_CLIENT:
229 /* gateway clients should send dhcp requests
230 * via unicast to their gateway
231 */
232 ret = batadv_gw_is_dhcp_target(skb, &header_len);
233 if (ret)
234 do_bcast = false;
235 break;
236 case BATADV_GW_MODE_OFF:
237 default:
238 break;
239 } 225 }
240 226
241 /* reminder: ethhdr might have become unusable from here on 227 dhcp_rcp = batadv_gw_dhcp_recipient_get(skb, &header_len,
242 * (batadv_gw_is_dhcp_target() might have reallocated skb data) 228 chaddr);
229 /* skb->data may have been modified by
230 * batadv_gw_dhcp_recipient_get()
243 */ 231 */
232 ethhdr = (struct ethhdr *)skb->data;
233 /* if gw_mode is on, broadcast any non-DHCP message.
234 * All the DHCP packets are going to be sent as unicast
235 */
236 if (dhcp_rcp == BATADV_DHCP_NO) {
237 do_bcast = true;
238 goto send;
239 }
240
241 if (dhcp_rcp == BATADV_DHCP_TO_CLIENT)
242 dst_hint = chaddr;
243 else if ((gw_mode == BATADV_GW_MODE_SERVER) &&
244 (dhcp_rcp == BATADV_DHCP_TO_SERVER))
245 /* gateways should not forward any DHCP message if
246 * directed to a DHCP server
247 */
248 goto dropped;
244 } 249 }
245 250
251send:
246 batadv_skb_set_priority(skb, 0); 252 batadv_skb_set_priority(skb, 0);
247 253
248 /* ethernet packet should be broadcasted */ 254 /* ethernet packet should be broadcasted */
@@ -288,22 +294,22 @@ static int batadv_interface_tx(struct sk_buff *skb,
288 294
289 /* unicast packet */ 295 /* unicast packet */
290 } else { 296 } else {
291 if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { 297 /* DHCP packets going to a server will use the GW feature */
298 if (dhcp_rcp == BATADV_DHCP_TO_SERVER) {
292 ret = batadv_gw_out_of_range(bat_priv, skb); 299 ret = batadv_gw_out_of_range(bat_priv, skb);
293 if (ret) 300 if (ret)
294 goto dropped; 301 goto dropped;
295 }
296
297 if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
298 goto dropped;
299
300 batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
301
302 if (is_multicast_ether_addr(ethhdr->h_dest))
303 ret = batadv_send_skb_via_gw(bat_priv, skb, vid); 302 ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
304 else 303 } else {
305 ret = batadv_send_skb_via_tt(bat_priv, skb, vid); 304 if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
305 skb))
306 goto dropped;
306 307
308 batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
309
310 ret = batadv_send_skb_via_tt(bat_priv, skb, dst_hint,
311 vid);
312 }
307 if (ret == NET_XMIT_DROP) 313 if (ret == NET_XMIT_DROP)
308 goto dropped_freed; 314 goto dropped_freed;
309 } 315 }
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index e545ac972433..70abb1c7087f 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -34,6 +34,18 @@
34#endif /* CONFIG_BATMAN_ADV_DAT */ 34#endif /* CONFIG_BATMAN_ADV_DAT */
35 35
36/** 36/**
37 * enum batadv_dhcp_recipient - dhcp destination
38 * @BATADV_DHCP_NO: packet is not a dhcp message
39 * @BATADV_DHCP_TO_SERVER: dhcp message is directed to a server
40 * @BATADV_DHCP_TO_CLIENT: dhcp message is directed to a client
41 */
42enum batadv_dhcp_recipient {
43 BATADV_DHCP_NO = 0,
44 BATADV_DHCP_TO_SERVER,
45 BATADV_DHCP_TO_CLIENT,
46};
47
48/**
37 * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the 49 * BATADV_TT_REMOTE_MASK - bitmask selecting the flags that are sent over the
38 * wire only 50 * wire only
39 */ 51 */