diff options
author | Antonio Quartulli <ordex@autistici.org> | 2011-06-25 21:37:18 -0400 |
---|---|---|
committer | Antonio Quartulli <ordex@autistici.org> | 2012-11-07 14:00:21 -0500 |
commit | c384ea3ec930ef11060a7308fbbd02b4871384f9 (patch) | |
tree | 14764f1a722c0a5633aa9dc5cebc19081703d446 /net/batman-adv/distributed-arp-table.c | |
parent | 5c3a0e5535933349a5d6e6bc8b704e0611f21d3f (diff) |
batman-adv: Distributed ARP Table - add snooping functions for ARP messages
In case of an ARP message going in or out the soft_iface, it is intercepted and
a special action is performed. In particular the DHT helper functions previously
implemented are used to store all the ARP entries belonging to the network in
order to provide a fast and unicast lookup instead of the classic broadcast
flooding mechanism.
Each node stores the entries it is responsible for (following the DHT rules) in
its soft_iface ARP table. This makes it possible to reuse the kernel data
structures and functions for ARP management.
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv/distributed-arp-table.c')
-rw-r--r-- | net/batman-adv/distributed-arp-table.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 49a213ce2aac..f43bf8e4a2b7 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/if_ether.h> | 20 | #include <linux/if_ether.h> |
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <net/arp.h> | ||
22 | 23 | ||
23 | #include "main.h" | 24 | #include "main.h" |
24 | #include "hash.h" | 25 | #include "hash.h" |
@@ -27,6 +28,7 @@ | |||
27 | #include "originator.h" | 28 | #include "originator.h" |
28 | #include "send.h" | 29 | #include "send.h" |
29 | #include "types.h" | 30 | #include "types.h" |
31 | #include "translation-table.h" | ||
30 | #include "unicast.h" | 32 | #include "unicast.h" |
31 | 33 | ||
32 | static void batadv_dat_purge(struct work_struct *work); | 34 | static void batadv_dat_purge(struct work_struct *work); |
@@ -766,3 +768,266 @@ static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv, | |||
766 | out: | 768 | out: |
767 | return type; | 769 | return type; |
768 | } | 770 | } |
771 | |||
772 | /** | ||
773 | * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to | ||
774 | * answer using DAT | ||
775 | * @bat_priv: the bat priv with all the soft interface information | ||
776 | * @skb: packet to check | ||
777 | * | ||
778 | * Returns true if the message has been sent to the dht candidates, false | ||
779 | * otherwise. In case of true the message has to be enqueued to permit the | ||
780 | * fallback | ||
781 | */ | ||
782 | bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, | ||
783 | struct sk_buff *skb) | ||
784 | { | ||
785 | uint16_t type = 0; | ||
786 | __be32 ip_dst, ip_src; | ||
787 | uint8_t *hw_src; | ||
788 | bool ret = false; | ||
789 | struct batadv_dat_entry *dat_entry = NULL; | ||
790 | struct sk_buff *skb_new; | ||
791 | struct batadv_hard_iface *primary_if = NULL; | ||
792 | |||
793 | type = batadv_arp_get_type(bat_priv, skb, 0); | ||
794 | /* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast | ||
795 | * message to the selected DHT candidates | ||
796 | */ | ||
797 | if (type != ARPOP_REQUEST) | ||
798 | goto out; | ||
799 | |||
800 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST"); | ||
801 | |||
802 | ip_src = batadv_arp_ip_src(skb, 0); | ||
803 | hw_src = batadv_arp_hw_src(skb, 0); | ||
804 | ip_dst = batadv_arp_ip_dst(skb, 0); | ||
805 | |||
806 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | ||
807 | |||
808 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | ||
809 | if (dat_entry) { | ||
810 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
811 | if (!primary_if) | ||
812 | goto out; | ||
813 | |||
814 | skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src, | ||
815 | primary_if->soft_iface, ip_dst, hw_src, | ||
816 | dat_entry->mac_addr, hw_src); | ||
817 | if (!skb_new) | ||
818 | goto out; | ||
819 | |||
820 | skb_reset_mac_header(skb_new); | ||
821 | skb_new->protocol = eth_type_trans(skb_new, | ||
822 | primary_if->soft_iface); | ||
823 | bat_priv->stats.rx_packets++; | ||
824 | bat_priv->stats.rx_bytes += skb->len + ETH_HLEN; | ||
825 | primary_if->soft_iface->last_rx = jiffies; | ||
826 | |||
827 | netif_rx(skb_new); | ||
828 | batadv_dbg(BATADV_DBG_DAT, bat_priv, "ARP request replied locally\n"); | ||
829 | ret = true; | ||
830 | } else { | ||
831 | /* Send the request on the DHT */ | ||
832 | ret = batadv_dat_send_data(bat_priv, skb, ip_dst, | ||
833 | BATADV_P_DAT_DHT_GET); | ||
834 | } | ||
835 | out: | ||
836 | if (dat_entry) | ||
837 | batadv_dat_entry_free_ref(dat_entry); | ||
838 | if (primary_if) | ||
839 | batadv_hardif_free_ref(primary_if); | ||
840 | return ret; | ||
841 | } | ||
842 | |||
843 | /** | ||
844 | * batadv_dat_snoop_incoming_arp_request - snoop the ARP request and try to | ||
845 | * answer using the local DAT storage | ||
846 | * @bat_priv: the bat priv with all the soft interface information | ||
847 | * @skb: packet to check | ||
848 | * @hdr_size: size of the encapsulation header | ||
849 | * | ||
850 | * Returns true if the request has been answered, false otherwise | ||
851 | */ | ||
852 | bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, | ||
853 | struct sk_buff *skb, int hdr_size) | ||
854 | { | ||
855 | uint16_t type; | ||
856 | __be32 ip_src, ip_dst; | ||
857 | uint8_t *hw_src; | ||
858 | struct sk_buff *skb_new; | ||
859 | struct batadv_hard_iface *primary_if = NULL; | ||
860 | struct batadv_dat_entry *dat_entry = NULL; | ||
861 | bool ret = false; | ||
862 | int err; | ||
863 | |||
864 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
865 | if (type != ARPOP_REQUEST) | ||
866 | goto out; | ||
867 | |||
868 | hw_src = batadv_arp_hw_src(skb, hdr_size); | ||
869 | ip_src = batadv_arp_ip_src(skb, hdr_size); | ||
870 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); | ||
871 | |||
872 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, | ||
873 | "Parsing incoming ARP REQUEST"); | ||
874 | |||
875 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | ||
876 | |||
877 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | ||
878 | if (!dat_entry) | ||
879 | goto out; | ||
880 | |||
881 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
882 | if (!primary_if) | ||
883 | goto out; | ||
884 | |||
885 | skb_new = arp_create(ARPOP_REPLY, ETH_P_ARP, ip_src, | ||
886 | primary_if->soft_iface, ip_dst, hw_src, | ||
887 | dat_entry->mac_addr, hw_src); | ||
888 | |||
889 | if (!skb_new) | ||
890 | goto out; | ||
891 | |||
892 | /* to preserve backwards compatibility, here the node has to answer | ||
893 | * using the same packet type it received for the request. This is due | ||
894 | * to that if a node is not using the 4addr packet format it may not | ||
895 | * support it. | ||
896 | */ | ||
897 | if (hdr_size == sizeof(struct batadv_unicast_4addr_packet)) | ||
898 | err = batadv_unicast_4addr_send_skb(bat_priv, skb_new, | ||
899 | BATADV_P_DAT_CACHE_REPLY); | ||
900 | else | ||
901 | err = batadv_unicast_send_skb(bat_priv, skb_new); | ||
902 | |||
903 | if (!err) | ||
904 | ret = true; | ||
905 | out: | ||
906 | if (dat_entry) | ||
907 | batadv_dat_entry_free_ref(dat_entry); | ||
908 | if (primary_if) | ||
909 | batadv_hardif_free_ref(primary_if); | ||
910 | if (ret) | ||
911 | kfree_skb(skb); | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | /** | ||
916 | * batadv_dat_snoop_outgoing_arp_reply - snoop the ARP reply and fill the DHT | ||
917 | * @bat_priv: the bat priv with all the soft interface information | ||
918 | * @skb: packet to check | ||
919 | */ | ||
920 | void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, | ||
921 | struct sk_buff *skb) | ||
922 | { | ||
923 | uint16_t type; | ||
924 | __be32 ip_src, ip_dst; | ||
925 | uint8_t *hw_src, *hw_dst; | ||
926 | |||
927 | type = batadv_arp_get_type(bat_priv, skb, 0); | ||
928 | if (type != ARPOP_REPLY) | ||
929 | return; | ||
930 | |||
931 | batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY"); | ||
932 | |||
933 | hw_src = batadv_arp_hw_src(skb, 0); | ||
934 | ip_src = batadv_arp_ip_src(skb, 0); | ||
935 | hw_dst = batadv_arp_hw_dst(skb, 0); | ||
936 | ip_dst = batadv_arp_ip_dst(skb, 0); | ||
937 | |||
938 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | ||
939 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | ||
940 | |||
941 | /* Send the ARP reply to the candidates for both the IP addresses that | ||
942 | * the node got within the ARP reply | ||
943 | */ | ||
944 | batadv_dat_send_data(bat_priv, skb, ip_src, BATADV_P_DAT_DHT_PUT); | ||
945 | batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_PUT); | ||
946 | } | ||
947 | /** | ||
948 | * batadv_dat_snoop_incoming_arp_reply - snoop the ARP reply and fill the local | ||
949 | * DAT storage only | ||
950 | * @bat_priv: the bat priv with all the soft interface information | ||
951 | * @skb: packet to check | ||
952 | * @hdr_size: siaze of the encapsulation header | ||
953 | */ | ||
954 | bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, | ||
955 | struct sk_buff *skb, int hdr_size) | ||
956 | { | ||
957 | uint16_t type; | ||
958 | __be32 ip_src, ip_dst; | ||
959 | uint8_t *hw_src, *hw_dst; | ||
960 | bool ret = false; | ||
961 | |||
962 | type = batadv_arp_get_type(bat_priv, skb, hdr_size); | ||
963 | if (type != ARPOP_REPLY) | ||
964 | goto out; | ||
965 | |||
966 | batadv_dbg_arp(bat_priv, skb, type, hdr_size, | ||
967 | "Parsing incoming ARP REPLY"); | ||
968 | |||
969 | hw_src = batadv_arp_hw_src(skb, hdr_size); | ||
970 | ip_src = batadv_arp_ip_src(skb, hdr_size); | ||
971 | hw_dst = batadv_arp_hw_dst(skb, hdr_size); | ||
972 | ip_dst = batadv_arp_ip_dst(skb, hdr_size); | ||
973 | |||
974 | /* Update our internal cache with both the IP addresses the node got | ||
975 | * within the ARP reply | ||
976 | */ | ||
977 | batadv_dat_entry_add(bat_priv, ip_src, hw_src); | ||
978 | batadv_dat_entry_add(bat_priv, ip_dst, hw_dst); | ||
979 | |||
980 | /* if this REPLY is directed to a client of mine, let's deliver the | ||
981 | * packet to the interface | ||
982 | */ | ||
983 | ret = !batadv_is_my_client(bat_priv, hw_dst); | ||
984 | out: | ||
985 | /* if ret == false -> packet has to be delivered to the interface */ | ||
986 | return ret; | ||
987 | } | ||
988 | |||
989 | /** | ||
990 | * batadv_dat_drop_broadcast_packet - check if an ARP request has to be dropped | ||
991 | * (because the node has already got the reply via DAT) or not | ||
992 | * @bat_priv: the bat priv with all the soft interface information | ||
993 | * @forw_packet: the broadcast packet | ||
994 | * | ||
995 | * Returns true if the node can drop the packet, false otherwise | ||
996 | */ | ||
997 | bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, | ||
998 | struct batadv_forw_packet *forw_packet) | ||
999 | { | ||
1000 | uint16_t type; | ||
1001 | __be32 ip_dst; | ||
1002 | struct batadv_dat_entry *dat_entry = NULL; | ||
1003 | bool ret = false; | ||
1004 | const size_t bcast_len = sizeof(struct batadv_bcast_packet); | ||
1005 | |||
1006 | /* If this packet is an ARP_REQUEST and the node already has the | ||
1007 | * information that it is going to ask, then the packet can be dropped | ||
1008 | */ | ||
1009 | if (forw_packet->num_packets) | ||
1010 | goto out; | ||
1011 | |||
1012 | type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len); | ||
1013 | if (type != ARPOP_REQUEST) | ||
1014 | goto out; | ||
1015 | |||
1016 | ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len); | ||
1017 | dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst); | ||
1018 | /* check if the node already got this entry */ | ||
1019 | if (!dat_entry) { | ||
1020 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | ||
1021 | "ARP Request for %pI4: fallback\n", &ip_dst); | ||
1022 | goto out; | ||
1023 | } | ||
1024 | |||
1025 | batadv_dbg(BATADV_DBG_DAT, bat_priv, | ||
1026 | "ARP Request for %pI4: fallback prevented\n", &ip_dst); | ||
1027 | ret = true; | ||
1028 | |||
1029 | out: | ||
1030 | if (dat_entry) | ||
1031 | batadv_dat_entry_free_ref(dat_entry); | ||
1032 | return ret; | ||
1033 | } | ||