aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/gateway_client.c153
-rw-r--r--net/batman-adv/gateway_client.h5
-rw-r--r--net/batman-adv/soft-interface.c43
3 files changed, 126 insertions, 75 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 619fb73b3b76..9373a143c6d4 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -25,6 +25,7 @@
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 "translation-table.h"
28#include "routing.h" 29#include "routing.h"
29#include <linux/ip.h> 30#include <linux/ip.h>
30#include <linux/ipv6.h> 31#include <linux/ipv6.h>
@@ -572,108 +573,142 @@ out:
572 return ret; 573 return ret;
573} 574}
574 575
575int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb, 576bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
576 struct orig_node *old_gw)
577{ 577{
578 struct ethhdr *ethhdr; 578 struct ethhdr *ethhdr;
579 struct iphdr *iphdr; 579 struct iphdr *iphdr;
580 struct ipv6hdr *ipv6hdr; 580 struct ipv6hdr *ipv6hdr;
581 struct udphdr *udphdr; 581 struct udphdr *udphdr;
582 struct gw_node *curr_gw;
583 struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
584 unsigned int header_len = 0;
585 int ret = 1;
586
587 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
588 return 0;
589 582
590 /* check for ethernet header */ 583 /* check for ethernet header */
591 if (!pskb_may_pull(skb, header_len + ETH_HLEN)) 584 if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
592 return 0; 585 return false;
593 ethhdr = (struct ethhdr *)skb->data; 586 ethhdr = (struct ethhdr *)skb->data;
594 header_len += ETH_HLEN; 587 *header_len += ETH_HLEN;
595 588
596 /* check for initial vlan header */ 589 /* check for initial vlan header */
597 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) { 590 if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) {
598 if (!pskb_may_pull(skb, header_len + VLAN_HLEN)) 591 if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
599 return 0; 592 return false;
600 ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN); 593 ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
601 header_len += VLAN_HLEN; 594 *header_len += VLAN_HLEN;
602 } 595 }
603 596
604 /* check for ip header */ 597 /* check for ip header */
605 switch (ntohs(ethhdr->h_proto)) { 598 switch (ntohs(ethhdr->h_proto)) {
606 case ETH_P_IP: 599 case ETH_P_IP:
607 if (!pskb_may_pull(skb, header_len + sizeof(*iphdr))) 600 if (!pskb_may_pull(skb, *header_len + sizeof(*iphdr)))
608 return 0; 601 return false;
609 iphdr = (struct iphdr *)(skb->data + header_len); 602 iphdr = (struct iphdr *)(skb->data + *header_len);
610 header_len += iphdr->ihl * 4; 603 *header_len += iphdr->ihl * 4;
611 604
612 /* check for udp header */ 605 /* check for udp header */
613 if (iphdr->protocol != IPPROTO_UDP) 606 if (iphdr->protocol != IPPROTO_UDP)
614 return 0; 607 return false;
615 608
616 break; 609 break;
617 case ETH_P_IPV6: 610 case ETH_P_IPV6:
618 if (!pskb_may_pull(skb, header_len + sizeof(*ipv6hdr))) 611 if (!pskb_may_pull(skb, *header_len + sizeof(*ipv6hdr)))
619 return 0; 612 return false;
620 ipv6hdr = (struct ipv6hdr *)(skb->data + header_len); 613 ipv6hdr = (struct ipv6hdr *)(skb->data + *header_len);
621 header_len += sizeof(*ipv6hdr); 614 *header_len += sizeof(*ipv6hdr);
622 615
623 /* check for udp header */ 616 /* check for udp header */
624 if (ipv6hdr->nexthdr != IPPROTO_UDP) 617 if (ipv6hdr->nexthdr != IPPROTO_UDP)
625 return 0; 618 return false;
626 619
627 break; 620 break;
628 default: 621 default:
629 return 0; 622 return false;
630 } 623 }
631 624
632 if (!pskb_may_pull(skb, header_len + sizeof(*udphdr))) 625 if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
633 return 0; 626 return false;
634 udphdr = (struct udphdr *)(skb->data + header_len); 627 udphdr = (struct udphdr *)(skb->data + *header_len);
635 header_len += sizeof(*udphdr); 628 *header_len += sizeof(*udphdr);
636 629
637 /* check for bootp port */ 630 /* check for bootp port */
638 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) && 631 if ((ntohs(ethhdr->h_proto) == ETH_P_IP) &&
639 (ntohs(udphdr->dest) != 67)) 632 (ntohs(udphdr->dest) != 67))
640 return 0; 633 return false;
641 634
642 if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) && 635 if ((ntohs(ethhdr->h_proto) == ETH_P_IPV6) &&
643 (ntohs(udphdr->dest) != 547)) 636 (ntohs(udphdr->dest) != 547))
644 return 0; 637 return false;
645 638
646 if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) 639 return true;
647 return -1; 640}
648 641
649 curr_gw = gw_get_selected_gw_node(bat_priv); 642bool gw_out_of_range(struct bat_priv *bat_priv,
650 if (!curr_gw) 643 struct sk_buff *skb, struct ethhdr *ethhdr)
651 return 0; 644{
652 645 struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
653 /* If old_gw != NULL then this packet is unicast. 646 struct orig_node *orig_dst_node = NULL;
654 * So, at this point we have to check the message type: if it is a 647 struct gw_node *curr_gw = NULL;
655 * DHCPREQUEST we have to decide whether to drop it or not */ 648 bool ret, out_of_range = false;
656 if (old_gw && curr_gw->orig_node != old_gw) { 649 unsigned int header_len = 0;
657 if (is_type_dhcprequest(skb, header_len)) { 650 uint8_t curr_tq_avg;
658 /* If the dhcp packet has been sent to a different gw, 651
659 * we have to evaluate whether the old gw is still 652 ret = gw_is_dhcp_target(skb, &header_len);
660 * reliable enough */ 653 if (!ret)
661 neigh_curr = find_router(bat_priv, curr_gw->orig_node, 654 goto out;
662 NULL); 655
663 neigh_old = find_router(bat_priv, old_gw, NULL); 656 orig_dst_node = transtable_search(bat_priv, ethhdr->h_source,
664 if (!neigh_curr || !neigh_old) 657 ethhdr->h_dest);
665 goto free_neigh; 658 if (!orig_dst_node)
666 if (neigh_curr->tq_avg - neigh_old->tq_avg < 659 goto out;
667 GW_THRESHOLD) 660
668 ret = -1; 661 if (!orig_dst_node->gw_flags)
669 } 662 goto out;
663
664 ret = is_type_dhcprequest(skb, header_len);
665 if (!ret)
666 goto out;
667
668 switch (atomic_read(&bat_priv->gw_mode)) {
669 case GW_MODE_SERVER:
670 /* If we are a GW then we are our best GW. We can artificially
671 * set the tq towards ourself as the maximum value */
672 curr_tq_avg = TQ_MAX_VALUE;
673 break;
674 case GW_MODE_CLIENT:
675 curr_gw = gw_get_selected_gw_node(bat_priv);
676 if (!curr_gw)
677 goto out;
678
679 /* packet is going to our gateway */
680 if (curr_gw->orig_node == orig_dst_node)
681 goto out;
682
683 /* If the dhcp packet has been sent to a different gw,
684 * we have to evaluate whether the old gw is still
685 * reliable enough */
686 neigh_curr = find_router(bat_priv, curr_gw->orig_node, NULL);
687 if (!neigh_curr)
688 goto out;
689
690 curr_tq_avg = neigh_curr->tq_avg;
691 break;
692 case GW_MODE_OFF:
693 default:
694 goto out;
670 } 695 }
671free_neigh: 696
697 neigh_old = find_router(bat_priv, orig_dst_node, NULL);
698 if (!!neigh_old)
699 goto out;
700
701 if (curr_tq_avg - neigh_old->tq_avg > GW_THRESHOLD)
702 out_of_range = true;
703
704out:
705 if (orig_dst_node)
706 orig_node_free_ref(orig_dst_node);
707 if (curr_gw)
708 gw_node_free_ref(curr_gw);
672 if (neigh_old) 709 if (neigh_old)
673 neigh_node_free_ref(neigh_old); 710 neigh_node_free_ref(neigh_old);
674 if (neigh_curr) 711 if (neigh_curr)
675 neigh_node_free_ref(neigh_curr); 712 neigh_node_free_ref(neigh_curr);
676 if (curr_gw) 713 return out_of_range;
677 gw_node_free_ref(curr_gw);
678 return ret;
679} 714}
diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h
index b9b983c07feb..e1edba08eb1d 100644
--- a/net/batman-adv/gateway_client.h
+++ b/net/batman-adv/gateway_client.h
@@ -31,7 +31,8 @@ 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, 34bool gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
35 struct orig_node *old_gw); 35bool gw_out_of_range(struct bat_priv *bat_priv,
36 struct sk_buff *skb, struct ethhdr *ethhdr);
36 37
37#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ 38#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index f9cc95728989..45297c843092 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -563,10 +563,10 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
563 struct bcast_packet *bcast_packet; 563 struct bcast_packet *bcast_packet;
564 struct vlan_ethhdr *vhdr; 564 struct vlan_ethhdr *vhdr;
565 struct softif_neigh *curr_softif_neigh = NULL; 565 struct softif_neigh *curr_softif_neigh = NULL;
566 struct orig_node *orig_node = NULL; 566 unsigned int header_len = 0;
567 int data_len = skb->len, ret; 567 int data_len = skb->len, ret;
568 short vid = -1; 568 short vid = -1;
569 bool do_bcast; 569 bool do_bcast = false;
570 570
571 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) 571 if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
572 goto dropped; 572 goto dropped;
@@ -598,17 +598,28 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
598 /* Register the client MAC in the transtable */ 598 /* Register the client MAC in the transtable */
599 tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); 599 tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
600 600
601 orig_node = transtable_search(bat_priv, ethhdr->h_source, 601 if (is_multicast_ether_addr(ethhdr->h_dest)) {
602 ethhdr->h_dest); 602 do_bcast = true;
603 do_bcast = is_multicast_ether_addr(ethhdr->h_dest);
604 if (do_bcast || (orig_node && orig_node->gw_flags)) {
605 ret = gw_is_target(bat_priv, skb, orig_node);
606 603
607 if (ret < 0) 604 switch (atomic_read(&bat_priv->gw_mode)) {
608 goto dropped; 605 case GW_MODE_SERVER:
609 606 /* gateway servers should not send dhcp
610 if (ret) 607 * requests into the mesh */
611 do_bcast = false; 608 ret = gw_is_dhcp_target(skb, &header_len);
609 if (ret)
610 goto dropped;
611 break;
612 case GW_MODE_CLIENT:
613 /* gateway clients should send dhcp requests
614 * via unicast to their gateway */
615 ret = gw_is_dhcp_target(skb, &header_len);
616 if (ret)
617 do_bcast = false;
618 break;
619 case GW_MODE_OFF:
620 default:
621 break;
622 }
612 } 623 }
613 624
614 /* ethernet packet should be broadcasted */ 625 /* ethernet packet should be broadcasted */
@@ -644,6 +655,12 @@ static int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
644 655
645 /* unicast packet */ 656 /* unicast packet */
646 } else { 657 } else {
658 if (atomic_read(&bat_priv->gw_mode) != GW_MODE_OFF) {
659 ret = gw_out_of_range(bat_priv, skb, ethhdr);
660 if (ret)
661 goto dropped;
662 }
663
647 ret = unicast_send_skb(skb, bat_priv); 664 ret = unicast_send_skb(skb, bat_priv);
648 if (ret != 0) 665 if (ret != 0)
649 goto dropped_freed; 666 goto dropped_freed;
@@ -662,8 +679,6 @@ end:
662 softif_neigh_free_ref(curr_softif_neigh); 679 softif_neigh_free_ref(curr_softif_neigh);
663 if (primary_if) 680 if (primary_if)
664 hardif_free_ref(primary_if); 681 hardif_free_ref(primary_if);
665 if (orig_node)
666 orig_node_free_ref(orig_node);
667 return NETDEV_TX_OK; 682 return NETDEV_TX_OK;
668} 683}
669 684