aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/distributed-arp-table.c265
-rw-r--r--net/batman-adv/distributed-arp-table.h11
-rw-r--r--net/batman-adv/main.h2
-rw-r--r--net/batman-adv/routing.c29
-rw-r--r--net/batman-adv/send.c4
-rw-r--r--net/batman-adv/soft-interface.c16
6 files changed, 325 insertions, 2 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
32static void batadv_dat_purge(struct work_struct *work); 34static void batadv_dat_purge(struct work_struct *work);
@@ -766,3 +768,266 @@ static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv,
766out: 768out:
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 */
782bool 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 }
835out:
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 */
852bool 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;
905out:
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 */
920void 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 */
954bool 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);
984out:
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 */
997bool 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
1029out:
1030 if (dat_entry)
1031 batadv_dat_entry_free_ref(dat_entry);
1032 return ret;
1033}
diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h
index f4e282a6e634..01308cea5b4e 100644
--- a/net/batman-adv/distributed-arp-table.h
+++ b/net/batman-adv/distributed-arp-table.h
@@ -27,6 +27,17 @@
27 27
28#define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0) 28#define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0)
29 29
30bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
31 struct sk_buff *skb);
32bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
33 struct sk_buff *skb, int hdr_size);
34void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
35 struct sk_buff *skb);
36bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
37 struct sk_buff *skb, int hdr_size);
38bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
39 struct batadv_forw_packet *forw_packet);
40
30/** 41/**
31 * batadv_dat_init_orig_node_addr - assign a DAT address to the orig_node 42 * batadv_dat_init_orig_node_addr - assign a DAT address to the orig_node
32 * @orig_node: the node to assign the DAT address to 43 * @orig_node: the node to assign the DAT address to
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 25adfd29cc92..240c74ffeb93 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -74,6 +74,8 @@
74 74
75#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */ 75#define BATADV_LOG_BUF_LEN 8192 /* has to be a power of 2 */
76 76
77/* msecs after which an ARP_REQUEST is sent in broadcast as fallback */
78#define ARP_REQ_DELAY 250
77/* numbers of originator to contact for any PUT/GET DHT operation */ 79/* numbers of originator to contact for any PUT/GET DHT operation */
78#define BATADV_DAT_CANDIDATES_NUM 3 80#define BATADV_DAT_CANDIDATES_NUM 3
79 81
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 859679b08286..1826699314b7 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -28,6 +28,7 @@
28#include "vis.h" 28#include "vis.h"
29#include "unicast.h" 29#include "unicast.h"
30#include "bridge_loop_avoidance.h" 30#include "bridge_loop_avoidance.h"
31#include "distributed-arp-table.h"
31 32
32static int batadv_route_unicast_packet(struct sk_buff *skb, 33static int batadv_route_unicast_packet(struct sk_buff *skb,
33 struct batadv_hard_iface *recv_if); 34 struct batadv_hard_iface *recv_if);
@@ -985,11 +986,13 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
985 struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); 986 struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
986 struct batadv_unicast_packet *unicast_packet; 987 struct batadv_unicast_packet *unicast_packet;
987 int hdr_size = sizeof(*unicast_packet); 988 int hdr_size = sizeof(*unicast_packet);
989 bool is4addr;
988 990
989 unicast_packet = (struct batadv_unicast_packet *)skb->data; 991 unicast_packet = (struct batadv_unicast_packet *)skb->data;
990 992
993 is4addr = unicast_packet->header.packet_type == BATADV_UNICAST_4ADDR;
991 /* the caller function should have already pulled 2 bytes */ 994 /* the caller function should have already pulled 2 bytes */
992 if (unicast_packet->header.packet_type == BATADV_UNICAST_4ADDR) 995 if (is4addr)
993 hdr_size = sizeof(struct batadv_unicast_4addr_packet); 996 hdr_size = sizeof(struct batadv_unicast_4addr_packet);
994 997
995 if (batadv_check_unicast_packet(skb, hdr_size) < 0) 998 if (batadv_check_unicast_packet(skb, hdr_size) < 0)
@@ -1000,9 +1003,17 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
1000 1003
1001 /* packet for me */ 1004 /* packet for me */
1002 if (batadv_is_my_mac(unicast_packet->dest)) { 1005 if (batadv_is_my_mac(unicast_packet->dest)) {
1006 if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb,
1007 hdr_size))
1008 goto rx_success;
1009 if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb,
1010 hdr_size))
1011 goto rx_success;
1012
1003 batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size, 1013 batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size,
1004 NULL); 1014 NULL);
1005 1015
1016rx_success:
1006 return NET_RX_SUCCESS; 1017 return NET_RX_SUCCESS;
1007 } 1018 }
1008 1019
@@ -1038,8 +1049,17 @@ int batadv_recv_ucast_frag_packet(struct sk_buff *skb,
1038 if (!new_skb) 1049 if (!new_skb)
1039 return NET_RX_SUCCESS; 1050 return NET_RX_SUCCESS;
1040 1051
1052 if (batadv_dat_snoop_incoming_arp_request(bat_priv, new_skb,
1053 hdr_size))
1054 goto rx_success;
1055 if (batadv_dat_snoop_incoming_arp_reply(bat_priv, new_skb,
1056 hdr_size))
1057 goto rx_success;
1058
1041 batadv_interface_rx(recv_if->soft_iface, new_skb, recv_if, 1059 batadv_interface_rx(recv_if->soft_iface, new_skb, recv_if,
1042 sizeof(struct batadv_unicast_packet), NULL); 1060 sizeof(struct batadv_unicast_packet), NULL);
1061
1062rx_success:
1043 return NET_RX_SUCCESS; 1063 return NET_RX_SUCCESS;
1044 } 1064 }
1045 1065
@@ -1131,9 +1151,16 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
1131 if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size)) 1151 if (batadv_bla_is_backbone_gw(skb, orig_node, hdr_size))
1132 goto out; 1152 goto out;
1133 1153
1154 if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb, hdr_size))
1155 goto rx_success;
1156 if (batadv_dat_snoop_incoming_arp_reply(bat_priv, skb, hdr_size))
1157 goto rx_success;
1158
1134 /* broadcast for me */ 1159 /* broadcast for me */
1135 batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size, 1160 batadv_interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size,
1136 orig_node); 1161 orig_node);
1162
1163rx_success:
1137 ret = NET_RX_SUCCESS; 1164 ret = NET_RX_SUCCESS;
1138 goto out; 1165 goto out;
1139 1166
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c
index 570a8bce0364..660d9bf7d219 100644
--- a/net/batman-adv/send.c
+++ b/net/batman-adv/send.c
@@ -18,6 +18,7 @@
18 */ 18 */
19 19
20#include "main.h" 20#include "main.h"
21#include "distributed-arp-table.h"
21#include "send.h" 22#include "send.h"
22#include "routing.h" 23#include "routing.h"
23#include "translation-table.h" 24#include "translation-table.h"
@@ -209,6 +210,9 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
209 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) 210 if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
210 goto out; 211 goto out;
211 212
213 if (batadv_dat_drop_broadcast_packet(bat_priv, forw_packet))
214 goto out;
215
212 /* rebroadcast packet */ 216 /* rebroadcast packet */
213 rcu_read_lock(); 217 rcu_read_lock();
214 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { 218 list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 2f123a1b174b..9dc0ae1d4da3 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -20,6 +20,7 @@
20#include "main.h" 20#include "main.h"
21#include "soft-interface.h" 21#include "soft-interface.h"
22#include "hard-interface.h" 22#include "hard-interface.h"
23#include "distributed-arp-table.h"
23#include "routing.h" 24#include "routing.h"
24#include "send.h" 25#include "send.h"
25#include "debugfs.h" 26#include "debugfs.h"
@@ -155,6 +156,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
155 short vid __maybe_unused = -1; 156 short vid __maybe_unused = -1;
156 bool do_bcast = false; 157 bool do_bcast = false;
157 uint32_t seqno; 158 uint32_t seqno;
159 unsigned long brd_delay = 1;
158 160
159 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) 161 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
160 goto dropped; 162 goto dropped;
@@ -224,6 +226,13 @@ static int batadv_interface_tx(struct sk_buff *skb,
224 if (!primary_if) 226 if (!primary_if)
225 goto dropped; 227 goto dropped;
226 228
229 /* in case of ARP request, we do not immediately broadcasti the
230 * packet, instead we first wait for DAT to try to retrieve the
231 * correct ARP entry
232 */
233 if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
234 brd_delay = msecs_to_jiffies(ARP_REQ_DELAY);
235
227 if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0) 236 if (batadv_skb_head_push(skb, sizeof(*bcast_packet)) < 0)
228 goto dropped; 237 goto dropped;
229 238
@@ -245,7 +254,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
245 seqno = atomic_inc_return(&bat_priv->bcast_seqno); 254 seqno = atomic_inc_return(&bat_priv->bcast_seqno);
246 bcast_packet->seqno = htonl(seqno); 255 bcast_packet->seqno = htonl(seqno);
247 256
248 batadv_add_bcast_packet_to_list(bat_priv, skb, 1); 257 batadv_add_bcast_packet_to_list(bat_priv, skb, brd_delay);
249 258
250 /* a copy is stored in the bcast list, therefore removing 259 /* a copy is stored in the bcast list, therefore removing
251 * the original skb. 260 * the original skb.
@@ -260,6 +269,11 @@ static int batadv_interface_tx(struct sk_buff *skb,
260 goto dropped; 269 goto dropped;
261 } 270 }
262 271
272 if (batadv_dat_snoop_outgoing_arp_request(bat_priv, skb))
273 goto dropped;
274
275 batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
276
263 ret = batadv_unicast_send_skb(bat_priv, skb); 277 ret = batadv_unicast_send_skb(bat_priv, skb);
264 if (ret != 0) 278 if (ret != 0)
265 goto dropped_freed; 279 goto dropped_freed;