diff options
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r-- | net/batman-adv/routing.c | 185 |
1 files changed, 82 insertions, 103 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 457dfef9c5fc..3281a504c20a 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -25,10 +25,10 @@ | |||
25 | #include "icmp_socket.h" | 25 | #include "icmp_socket.h" |
26 | #include "translation-table.h" | 26 | #include "translation-table.h" |
27 | #include "originator.h" | 27 | #include "originator.h" |
28 | #include "unicast.h" | ||
29 | #include "bridge_loop_avoidance.h" | 28 | #include "bridge_loop_avoidance.h" |
30 | #include "distributed-arp-table.h" | 29 | #include "distributed-arp-table.h" |
31 | #include "network-coding.h" | 30 | #include "network-coding.h" |
31 | #include "fragmentation.h" | ||
32 | 32 | ||
33 | static int batadv_route_unicast_packet(struct sk_buff *skb, | 33 | static int batadv_route_unicast_packet(struct sk_buff *skb, |
34 | struct batadv_hard_iface *recv_if); | 34 | struct batadv_hard_iface *recv_if); |
@@ -258,7 +258,7 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
258 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 258 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
259 | 259 | ||
260 | /* add data to device queue */ | 260 | /* add data to device queue */ |
261 | if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { | 261 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { |
262 | batadv_socket_receive_packet(icmp_packet, icmp_len); | 262 | batadv_socket_receive_packet(icmp_packet, icmp_len); |
263 | goto out; | 263 | goto out; |
264 | } | 264 | } |
@@ -269,7 +269,7 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
269 | 269 | ||
270 | /* answer echo request (ping) */ | 270 | /* answer echo request (ping) */ |
271 | /* get routing information */ | 271 | /* get routing information */ |
272 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig); | 272 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); |
273 | if (!orig_node) | 273 | if (!orig_node) |
274 | goto out; | 274 | goto out; |
275 | 275 | ||
@@ -279,10 +279,11 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv, | |||
279 | 279 | ||
280 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 280 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
281 | 281 | ||
282 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 282 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); |
283 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); | 283 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, |
284 | icmp_packet->msg_type = BATADV_ECHO_REPLY; | 284 | ETH_ALEN); |
285 | icmp_packet->header.ttl = BATADV_TTL; | 285 | icmp_packet->icmph.msg_type = BATADV_ECHO_REPLY; |
286 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
286 | 287 | ||
287 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 288 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) |
288 | ret = NET_RX_SUCCESS; | 289 | ret = NET_RX_SUCCESS; |
@@ -306,9 +307,9 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
306 | icmp_packet = (struct batadv_icmp_packet *)skb->data; | 307 | icmp_packet = (struct batadv_icmp_packet *)skb->data; |
307 | 308 | ||
308 | /* send TTL exceeded if packet is an echo request (traceroute) */ | 309 | /* send TTL exceeded if packet is an echo request (traceroute) */ |
309 | if (icmp_packet->msg_type != BATADV_ECHO_REQUEST) { | 310 | if (icmp_packet->icmph.msg_type != BATADV_ECHO_REQUEST) { |
310 | pr_debug("Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", | 311 | pr_debug("Warning - can't forward icmp packet from %pM to %pM: ttl exceeded\n", |
311 | icmp_packet->orig, icmp_packet->dst); | 312 | icmp_packet->icmph.orig, icmp_packet->icmph.dst); |
312 | goto out; | 313 | goto out; |
313 | } | 314 | } |
314 | 315 | ||
@@ -317,7 +318,7 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
317 | goto out; | 318 | goto out; |
318 | 319 | ||
319 | /* get routing information */ | 320 | /* get routing information */ |
320 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->orig); | 321 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.orig); |
321 | if (!orig_node) | 322 | if (!orig_node) |
322 | goto out; | 323 | goto out; |
323 | 324 | ||
@@ -327,10 +328,11 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv, | |||
327 | 328 | ||
328 | icmp_packet = (struct batadv_icmp_packet *)skb->data; | 329 | icmp_packet = (struct batadv_icmp_packet *)skb->data; |
329 | 330 | ||
330 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 331 | memcpy(icmp_packet->icmph.dst, icmp_packet->icmph.orig, ETH_ALEN); |
331 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); | 332 | memcpy(icmp_packet->icmph.orig, primary_if->net_dev->dev_addr, |
332 | icmp_packet->msg_type = BATADV_TTL_EXCEEDED; | 333 | ETH_ALEN); |
333 | icmp_packet->header.ttl = BATADV_TTL; | 334 | icmp_packet->icmph.msg_type = BATADV_TTL_EXCEEDED; |
335 | icmp_packet->icmph.header.ttl = BATADV_TTL; | ||
334 | 336 | ||
335 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) | 337 | if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP) |
336 | ret = NET_RX_SUCCESS; | 338 | ret = NET_RX_SUCCESS; |
@@ -379,7 +381,9 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
379 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 381 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
380 | 382 | ||
381 | /* add record route information if not full */ | 383 | /* add record route information if not full */ |
382 | if ((hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | 384 | if ((icmp_packet->icmph.msg_type == BATADV_ECHO_REPLY || |
385 | icmp_packet->icmph.msg_type == BATADV_ECHO_REQUEST) && | ||
386 | (hdr_size == sizeof(struct batadv_icmp_packet_rr)) && | ||
383 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { | 387 | (icmp_packet->rr_cur < BATADV_RR_LEN)) { |
384 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), | 388 | memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]), |
385 | ethhdr->h_dest, ETH_ALEN); | 389 | ethhdr->h_dest, ETH_ALEN); |
@@ -387,15 +391,15 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
387 | } | 391 | } |
388 | 392 | ||
389 | /* packet for me */ | 393 | /* packet for me */ |
390 | if (batadv_is_my_mac(bat_priv, icmp_packet->dst)) | 394 | if (batadv_is_my_mac(bat_priv, icmp_packet->icmph.dst)) |
391 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); | 395 | return batadv_recv_my_icmp_packet(bat_priv, skb, hdr_size); |
392 | 396 | ||
393 | /* TTL exceeded */ | 397 | /* TTL exceeded */ |
394 | if (icmp_packet->header.ttl < 2) | 398 | if (icmp_packet->icmph.header.ttl < 2) |
395 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); | 399 | return batadv_recv_icmp_ttl_exceeded(bat_priv, skb); |
396 | 400 | ||
397 | /* get routing information */ | 401 | /* get routing information */ |
398 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->dst); | 402 | orig_node = batadv_orig_hash_find(bat_priv, icmp_packet->icmph.dst); |
399 | if (!orig_node) | 403 | if (!orig_node) |
400 | goto out; | 404 | goto out; |
401 | 405 | ||
@@ -406,7 +410,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, | |||
406 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; | 410 | icmp_packet = (struct batadv_icmp_packet_rr *)skb->data; |
407 | 411 | ||
408 | /* decrement ttl */ | 412 | /* decrement ttl */ |
409 | icmp_packet->header.ttl--; | 413 | icmp_packet->icmph.header.ttl--; |
410 | 414 | ||
411 | /* route it */ | 415 | /* route it */ |
412 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) | 416 | if (batadv_send_skb_to_orig(skb, orig_node, recv_if) != NET_XMIT_DROP) |
@@ -651,11 +655,9 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
651 | { | 655 | { |
652 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 656 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
653 | struct batadv_orig_node *orig_node = NULL; | 657 | struct batadv_orig_node *orig_node = NULL; |
654 | struct batadv_neigh_node *neigh_node = NULL; | ||
655 | struct batadv_unicast_packet *unicast_packet; | 658 | struct batadv_unicast_packet *unicast_packet; |
656 | struct ethhdr *ethhdr = eth_hdr(skb); | 659 | struct ethhdr *ethhdr = eth_hdr(skb); |
657 | int res, hdr_len, ret = NET_RX_DROP; | 660 | int res, hdr_len, ret = NET_RX_DROP; |
658 | struct sk_buff *new_skb; | ||
659 | 661 | ||
660 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | 662 | unicast_packet = (struct batadv_unicast_packet *)skb->data; |
661 | 663 | ||
@@ -672,46 +674,12 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
672 | if (!orig_node) | 674 | if (!orig_node) |
673 | goto out; | 675 | goto out; |
674 | 676 | ||
675 | /* find_router() increases neigh_nodes refcount if found. */ | ||
676 | neigh_node = batadv_find_router(bat_priv, orig_node, recv_if); | ||
677 | |||
678 | if (!neigh_node) | ||
679 | goto out; | ||
680 | |||
681 | /* create a copy of the skb, if needed, to modify it. */ | 677 | /* create a copy of the skb, if needed, to modify it. */ |
682 | if (skb_cow(skb, ETH_HLEN) < 0) | 678 | if (skb_cow(skb, ETH_HLEN) < 0) |
683 | goto out; | 679 | goto out; |
684 | 680 | ||
685 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
686 | |||
687 | if (unicast_packet->header.packet_type == BATADV_UNICAST && | ||
688 | atomic_read(&bat_priv->fragmentation) && | ||
689 | skb->len > neigh_node->if_incoming->net_dev->mtu) { | ||
690 | ret = batadv_frag_send_skb(skb, bat_priv, | ||
691 | neigh_node->if_incoming, | ||
692 | neigh_node->addr); | ||
693 | goto out; | ||
694 | } | ||
695 | |||
696 | if (unicast_packet->header.packet_type == BATADV_UNICAST_FRAG && | ||
697 | batadv_frag_can_reassemble(skb, | ||
698 | neigh_node->if_incoming->net_dev->mtu)) { | ||
699 | ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
700 | |||
701 | if (ret == NET_RX_DROP) | ||
702 | goto out; | ||
703 | |||
704 | /* packet was buffered for late merge */ | ||
705 | if (!new_skb) { | ||
706 | ret = NET_RX_SUCCESS; | ||
707 | goto out; | ||
708 | } | ||
709 | |||
710 | skb = new_skb; | ||
711 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
712 | } | ||
713 | |||
714 | /* decrement ttl */ | 681 | /* decrement ttl */ |
682 | unicast_packet = (struct batadv_unicast_packet *)skb->data; | ||
715 | unicast_packet->header.ttl--; | 683 | unicast_packet->header.ttl--; |
716 | 684 | ||
717 | switch (unicast_packet->header.packet_type) { | 685 | switch (unicast_packet->header.packet_type) { |
@@ -746,8 +714,6 @@ static int batadv_route_unicast_packet(struct sk_buff *skb, | |||
746 | } | 714 | } |
747 | 715 | ||
748 | out: | 716 | out: |
749 | if (neigh_node) | ||
750 | batadv_neigh_node_free_ref(neigh_node); | ||
751 | if (orig_node) | 717 | if (orig_node) |
752 | batadv_orig_node_free_ref(orig_node); | 718 | batadv_orig_node_free_ref(orig_node); |
753 | return ret; | 719 | return ret; |
@@ -1001,51 +967,6 @@ rx_success: | |||
1001 | return batadv_route_unicast_packet(skb, recv_if); | 967 | return batadv_route_unicast_packet(skb, recv_if); |
1002 | } | 968 | } |
1003 | 969 | ||
1004 | int batadv_recv_ucast_frag_packet(struct sk_buff *skb, | ||
1005 | struct batadv_hard_iface *recv_if) | ||
1006 | { | ||
1007 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1008 | struct batadv_unicast_frag_packet *unicast_packet; | ||
1009 | int hdr_size = sizeof(*unicast_packet); | ||
1010 | struct sk_buff *new_skb = NULL; | ||
1011 | int ret; | ||
1012 | |||
1013 | if (batadv_check_unicast_packet(bat_priv, skb, hdr_size) < 0) | ||
1014 | return NET_RX_DROP; | ||
1015 | |||
1016 | if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size)) | ||
1017 | return NET_RX_DROP; | ||
1018 | |||
1019 | unicast_packet = (struct batadv_unicast_frag_packet *)skb->data; | ||
1020 | |||
1021 | /* packet for me */ | ||
1022 | if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) { | ||
1023 | ret = batadv_frag_reassemble_skb(skb, bat_priv, &new_skb); | ||
1024 | |||
1025 | if (ret == NET_RX_DROP) | ||
1026 | return NET_RX_DROP; | ||
1027 | |||
1028 | /* packet was buffered for late merge */ | ||
1029 | if (!new_skb) | ||
1030 | return NET_RX_SUCCESS; | ||
1031 | |||
1032 | if (batadv_dat_snoop_incoming_arp_request(bat_priv, new_skb, | ||
1033 | hdr_size)) | ||
1034 | goto rx_success; | ||
1035 | if (batadv_dat_snoop_incoming_arp_reply(bat_priv, new_skb, | ||
1036 | hdr_size)) | ||
1037 | goto rx_success; | ||
1038 | |||
1039 | batadv_interface_rx(recv_if->soft_iface, new_skb, recv_if, | ||
1040 | sizeof(struct batadv_unicast_packet), NULL); | ||
1041 | |||
1042 | rx_success: | ||
1043 | return NET_RX_SUCCESS; | ||
1044 | } | ||
1045 | |||
1046 | return batadv_route_unicast_packet(skb, recv_if); | ||
1047 | } | ||
1048 | |||
1049 | /** | 970 | /** |
1050 | * batadv_recv_unicast_tvlv - receive and process unicast tvlv packets | 971 | * batadv_recv_unicast_tvlv - receive and process unicast tvlv packets |
1051 | * @skb: unicast tvlv packet to process | 972 | * @skb: unicast tvlv packet to process |
@@ -1095,6 +1016,64 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, | |||
1095 | return ret; | 1016 | return ret; |
1096 | } | 1017 | } |
1097 | 1018 | ||
1019 | /** | ||
1020 | * batadv_recv_frag_packet - process received fragment | ||
1021 | * @skb: the received fragment | ||
1022 | * @recv_if: interface that the skb is received on | ||
1023 | * | ||
1024 | * This function does one of the three following things: 1) Forward fragment, if | ||
1025 | * the assembled packet will exceed our MTU; 2) Buffer fragment, if we till | ||
1026 | * lack further fragments; 3) Merge fragments, if we have all needed parts. | ||
1027 | * | ||
1028 | * Return NET_RX_DROP if the skb is not consumed, NET_RX_SUCCESS otherwise. | ||
1029 | */ | ||
1030 | int batadv_recv_frag_packet(struct sk_buff *skb, | ||
1031 | struct batadv_hard_iface *recv_if) | ||
1032 | { | ||
1033 | struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); | ||
1034 | struct batadv_orig_node *orig_node_src = NULL; | ||
1035 | struct batadv_frag_packet *frag_packet; | ||
1036 | int ret = NET_RX_DROP; | ||
1037 | |||
1038 | if (batadv_check_unicast_packet(bat_priv, skb, | ||
1039 | sizeof(*frag_packet)) < 0) | ||
1040 | goto out; | ||
1041 | |||
1042 | frag_packet = (struct batadv_frag_packet *)skb->data; | ||
1043 | orig_node_src = batadv_orig_hash_find(bat_priv, frag_packet->orig); | ||
1044 | if (!orig_node_src) | ||
1045 | goto out; | ||
1046 | |||
1047 | /* Route the fragment if it is not for us and too big to be merged. */ | ||
1048 | if (!batadv_is_my_mac(bat_priv, frag_packet->dest) && | ||
1049 | batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) { | ||
1050 | ret = NET_RX_SUCCESS; | ||
1051 | goto out; | ||
1052 | } | ||
1053 | |||
1054 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_RX); | ||
1055 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_RX_BYTES, skb->len); | ||
1056 | |||
1057 | /* Add fragment to buffer and merge if possible. */ | ||
1058 | if (!batadv_frag_skb_buffer(&skb, orig_node_src)) | ||
1059 | goto out; | ||
1060 | |||
1061 | /* Deliver merged packet to the appropriate handler, if it was | ||
1062 | * merged | ||
1063 | */ | ||
1064 | if (skb) | ||
1065 | batadv_batman_skb_recv(skb, recv_if->net_dev, | ||
1066 | &recv_if->batman_adv_ptype, NULL); | ||
1067 | |||
1068 | ret = NET_RX_SUCCESS; | ||
1069 | |||
1070 | out: | ||
1071 | if (orig_node_src) | ||
1072 | batadv_orig_node_free_ref(orig_node_src); | ||
1073 | |||
1074 | return ret; | ||
1075 | } | ||
1076 | |||
1098 | int batadv_recv_bcast_packet(struct sk_buff *skb, | 1077 | int batadv_recv_bcast_packet(struct sk_buff *skb, |
1099 | struct batadv_hard_iface *recv_if) | 1078 | struct batadv_hard_iface *recv_if) |
1100 | { | 1079 | { |