aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/routing.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/routing.c')
-rw-r--r--net/batman-adv/routing.c194
1 files changed, 93 insertions, 101 deletions
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index f212abe745bc..b7d43caaa9c8 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -87,18 +87,20 @@ static void update_route(struct bat_priv *bat_priv,
87 struct neigh_node *neigh_node, 87 struct neigh_node *neigh_node,
88 unsigned char *hna_buff, int hna_buff_len) 88 unsigned char *hna_buff, int hna_buff_len)
89{ 89{
90 struct neigh_node *neigh_node_tmp; 90 struct neigh_node *curr_router;
91
92 curr_router = orig_node_get_router(orig_node);
91 93
92 /* route deleted */ 94 /* route deleted */
93 if ((orig_node->router) && (!neigh_node)) { 95 if ((curr_router) && (!neigh_node)) {
94 96
95 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n", 97 bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
96 orig_node->orig); 98 orig_node->orig);
97 hna_global_del_orig(bat_priv, orig_node, 99 hna_global_del_orig(bat_priv, orig_node,
98 "originator timed out"); 100 "originator timed out");
99 101
100 /* route added */ 102 /* route added */
101 } else if ((!orig_node->router) && (neigh_node)) { 103 } else if ((!curr_router) && (neigh_node)) {
102 104
103 bat_dbg(DBG_ROUTES, bat_priv, 105 bat_dbg(DBG_ROUTES, bat_priv,
104 "Adding route towards: %pM (via %pM)\n", 106 "Adding route towards: %pM (via %pM)\n",
@@ -106,21 +108,29 @@ static void update_route(struct bat_priv *bat_priv,
106 hna_global_add_orig(bat_priv, orig_node, 108 hna_global_add_orig(bat_priv, orig_node,
107 hna_buff, hna_buff_len); 109 hna_buff, hna_buff_len);
108 110
109 /* route changed */ 111 /* route changed */
110 } else { 112 } else {
111 bat_dbg(DBG_ROUTES, bat_priv, 113 bat_dbg(DBG_ROUTES, bat_priv,
112 "Changing route towards: %pM " 114 "Changing route towards: %pM "
113 "(now via %pM - was via %pM)\n", 115 "(now via %pM - was via %pM)\n",
114 orig_node->orig, neigh_node->addr, 116 orig_node->orig, neigh_node->addr,
115 orig_node->router->addr); 117 curr_router->addr);
116 } 118 }
117 119
120 if (curr_router)
121 neigh_node_free_ref(curr_router);
122
123 /* increase refcount of new best neighbor */
118 if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) 124 if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount))
119 neigh_node = NULL; 125 neigh_node = NULL;
120 neigh_node_tmp = orig_node->router; 126
121 orig_node->router = neigh_node; 127 spin_lock_bh(&orig_node->neigh_list_lock);
122 if (neigh_node_tmp) 128 rcu_assign_pointer(orig_node->router, neigh_node);
123 neigh_node_free_ref(neigh_node_tmp); 129 spin_unlock_bh(&orig_node->neigh_list_lock);
130
131 /* decrease refcount of previous best neighbor */
132 if (curr_router)
133 neigh_node_free_ref(curr_router);
124} 134}
125 135
126 136
@@ -128,16 +138,23 @@ void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
128 struct neigh_node *neigh_node, unsigned char *hna_buff, 138 struct neigh_node *neigh_node, unsigned char *hna_buff,
129 int hna_buff_len) 139 int hna_buff_len)
130{ 140{
141 struct neigh_node *router = NULL;
131 142
132 if (!orig_node) 143 if (!orig_node)
133 return; 144 goto out;
145
146 router = orig_node_get_router(orig_node);
134 147
135 if (orig_node->router != neigh_node) 148 if (router != neigh_node)
136 update_route(bat_priv, orig_node, neigh_node, 149 update_route(bat_priv, orig_node, neigh_node,
137 hna_buff, hna_buff_len); 150 hna_buff, hna_buff_len);
138 /* may be just HNA changed */ 151 /* may be just HNA changed */
139 else 152 else
140 update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len); 153 update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
154
155out:
156 if (router)
157 neigh_node_free_ref(router);
141} 158}
142 159
143static int is_bidirectional_neigh(struct orig_node *orig_node, 160static int is_bidirectional_neigh(struct orig_node *orig_node,
@@ -288,8 +305,8 @@ static void bonding_candidate_add(struct orig_node *orig_node,
288 struct neigh_node *neigh_node) 305 struct neigh_node *neigh_node)
289{ 306{
290 struct hlist_node *node; 307 struct hlist_node *node;
291 struct neigh_node *tmp_neigh_node; 308 struct neigh_node *tmp_neigh_node, *router = NULL;
292 uint8_t best_tq, interference_candidate = 0; 309 uint8_t interference_candidate = 0;
293 310
294 spin_lock_bh(&orig_node->neigh_list_lock); 311 spin_lock_bh(&orig_node->neigh_list_lock);
295 312
@@ -298,13 +315,12 @@ static void bonding_candidate_add(struct orig_node *orig_node,
298 neigh_node->orig_node->primary_addr)) 315 neigh_node->orig_node->primary_addr))
299 goto candidate_del; 316 goto candidate_del;
300 317
301 if (!orig_node->router) 318 router = orig_node_get_router(orig_node);
319 if (!router)
302 goto candidate_del; 320 goto candidate_del;
303 321
304 best_tq = orig_node->router->tq_avg;
305
306 /* ... and is good enough to be considered */ 322 /* ... and is good enough to be considered */
307 if (neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD) 323 if (neigh_node->tq_avg < router->tq_avg - BONDING_TQ_THRESHOLD)
308 goto candidate_del; 324 goto candidate_del;
309 325
310 /** 326 /**
@@ -350,7 +366,9 @@ candidate_del:
350 366
351out: 367out:
352 spin_unlock_bh(&orig_node->neigh_list_lock); 368 spin_unlock_bh(&orig_node->neigh_list_lock);
353 return; 369
370 if (router)
371 neigh_node_free_ref(router);
354} 372}
355 373
356/* copy primary address for bonding */ 374/* copy primary address for bonding */
@@ -373,6 +391,7 @@ static void update_orig(struct bat_priv *bat_priv,
373 char is_duplicate) 391 char is_duplicate)
374{ 392{
375 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; 393 struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
394 struct neigh_node *router = NULL;
376 struct orig_node *orig_node_tmp; 395 struct orig_node *orig_node_tmp;
377 struct hlist_node *node; 396 struct hlist_node *node;
378 int tmp_hna_buff_len; 397 int tmp_hna_buff_len;
@@ -441,19 +460,18 @@ static void update_orig(struct bat_priv *bat_priv,
441 460
442 /* if this neighbor already is our next hop there is nothing 461 /* if this neighbor already is our next hop there is nothing
443 * to change */ 462 * to change */
444 if (orig_node->router == neigh_node) 463 router = orig_node_get_router(orig_node);
464 if (router == neigh_node)
445 goto update_hna; 465 goto update_hna;
446 466
447 /* if this neighbor does not offer a better TQ we won't consider it */ 467 /* if this neighbor does not offer a better TQ we won't consider it */
448 if ((orig_node->router) && 468 if (router && (router->tq_avg > neigh_node->tq_avg))
449 (orig_node->router->tq_avg > neigh_node->tq_avg))
450 goto update_hna; 469 goto update_hna;
451 470
452 /* if the TQ is the same and the link not more symetric we 471 /* if the TQ is the same and the link not more symetric we
453 * won't consider it either */ 472 * won't consider it either */
454 if ((orig_node->router) && 473 if (router && (neigh_node->tq_avg == router->tq_avg)) {
455 (neigh_node->tq_avg == orig_node->router->tq_avg)) { 474 orig_node_tmp = router->orig_node;
456 orig_node_tmp = orig_node->router->orig_node;
457 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock); 475 spin_lock_bh(&orig_node_tmp->ogm_cnt_lock);
458 bcast_own_sum_orig = 476 bcast_own_sum_orig =
459 orig_node_tmp->bcast_own_sum[if_incoming->if_num]; 477 orig_node_tmp->bcast_own_sum[if_incoming->if_num];
@@ -474,7 +492,7 @@ static void update_orig(struct bat_priv *bat_priv,
474 goto update_gw; 492 goto update_gw;
475 493
476update_hna: 494update_hna:
477 update_routes(bat_priv, orig_node, orig_node->router, 495 update_routes(bat_priv, orig_node, router,
478 hna_buff, tmp_hna_buff_len); 496 hna_buff, tmp_hna_buff_len);
479 497
480update_gw: 498update_gw:
@@ -496,6 +514,8 @@ unlock:
496out: 514out:
497 if (neigh_node) 515 if (neigh_node)
498 neigh_node_free_ref(neigh_node); 516 neigh_node_free_ref(neigh_node);
517 if (router)
518 neigh_node_free_ref(router);
499} 519}
500 520
501/* checks whether the host restarted and is in the protection time. 521/* checks whether the host restarted and is in the protection time.
@@ -603,6 +623,8 @@ void receive_bat_packet(struct ethhdr *ethhdr,
603 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface); 623 struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
604 struct hard_iface *hard_iface; 624 struct hard_iface *hard_iface;
605 struct orig_node *orig_neigh_node, *orig_node; 625 struct orig_node *orig_neigh_node, *orig_node;
626 struct neigh_node *router = NULL, *router_router = NULL;
627 struct neigh_node *orig_neigh_router = NULL;
606 char has_directlink_flag; 628 char has_directlink_flag;
607 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0; 629 char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
608 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh; 630 char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
@@ -747,14 +769,15 @@ void receive_bat_packet(struct ethhdr *ethhdr,
747 goto out; 769 goto out;
748 } 770 }
749 771
772 router = orig_node_get_router(orig_node);
773 if (router)
774 router_router = orig_node_get_router(router->orig_node);
775
750 /* avoid temporary routing loops */ 776 /* avoid temporary routing loops */
751 if ((orig_node->router) && 777 if (router && router_router &&
752 (orig_node->router->orig_node->router) && 778 (compare_eth(router->addr, batman_packet->prev_sender)) &&
753 (compare_eth(orig_node->router->addr,
754 batman_packet->prev_sender)) &&
755 !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) && 779 !(compare_eth(batman_packet->orig, batman_packet->prev_sender)) &&
756 (compare_eth(orig_node->router->addr, 780 (compare_eth(router->addr, router_router->addr))) {
757 orig_node->router->orig_node->router->addr))) {
758 bat_dbg(DBG_BATMAN, bat_priv, 781 bat_dbg(DBG_BATMAN, bat_priv,
759 "Drop packet: ignoring all rebroadcast packets that " 782 "Drop packet: ignoring all rebroadcast packets that "
760 "may make me loop (sender: %pM)\n", ethhdr->h_source); 783 "may make me loop (sender: %pM)\n", ethhdr->h_source);
@@ -769,9 +792,11 @@ void receive_bat_packet(struct ethhdr *ethhdr,
769 if (!orig_neigh_node) 792 if (!orig_neigh_node)
770 goto out; 793 goto out;
771 794
795 orig_neigh_router = orig_node_get_router(orig_neigh_node);
796
772 /* drop packet if sender is not a direct neighbor and if we 797 /* drop packet if sender is not a direct neighbor and if we
773 * don't route towards it */ 798 * don't route towards it */
774 if (!is_single_hop_neigh && (!orig_neigh_node->router)) { 799 if (!is_single_hop_neigh && (!orig_neigh_router)) {
775 bat_dbg(DBG_BATMAN, bat_priv, 800 bat_dbg(DBG_BATMAN, bat_priv,
776 "Drop packet: OGM via unknown neighbor!\n"); 801 "Drop packet: OGM via unknown neighbor!\n");
777 goto out_neigh; 802 goto out_neigh;
@@ -825,6 +850,13 @@ out_neigh:
825 if ((orig_neigh_node) && (!is_single_hop_neigh)) 850 if ((orig_neigh_node) && (!is_single_hop_neigh))
826 orig_node_free_ref(orig_neigh_node); 851 orig_node_free_ref(orig_neigh_node);
827out: 852out:
853 if (router)
854 neigh_node_free_ref(router);
855 if (router_router)
856 neigh_node_free_ref(router_router);
857 if (orig_neigh_router)
858 neigh_node_free_ref(orig_neigh_router);
859
828 orig_node_free_ref(orig_node); 860 orig_node_free_ref(orig_node);
829} 861}
830 862
@@ -869,7 +901,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
869 struct sk_buff *skb, size_t icmp_len) 901 struct sk_buff *skb, size_t icmp_len)
870{ 902{
871 struct orig_node *orig_node = NULL; 903 struct orig_node *orig_node = NULL;
872 struct neigh_node *neigh_node = NULL; 904 struct neigh_node *router = NULL;
873 struct icmp_packet_rr *icmp_packet; 905 struct icmp_packet_rr *icmp_packet;
874 int ret = NET_RX_DROP; 906 int ret = NET_RX_DROP;
875 907
@@ -886,23 +918,13 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
886 918
887 /* answer echo request (ping) */ 919 /* answer echo request (ping) */
888 /* get routing information */ 920 /* get routing information */
889 rcu_read_lock();
890 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 921 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
891
892 if (!orig_node) 922 if (!orig_node)
893 goto unlock; 923 goto out;
894
895 neigh_node = orig_node->router;
896
897 if (!neigh_node)
898 goto unlock;
899
900 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
901 neigh_node = NULL;
902 goto unlock;
903 }
904 924
905 rcu_read_unlock(); 925 router = orig_node_get_router(orig_node);
926 if (!router)
927 goto out;
906 928
907 /* create a copy of the skb, if needed, to modify it. */ 929 /* create a copy of the skb, if needed, to modify it. */
908 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 930 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -916,15 +938,12 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
916 icmp_packet->msg_type = ECHO_REPLY; 938 icmp_packet->msg_type = ECHO_REPLY;
917 icmp_packet->ttl = TTL; 939 icmp_packet->ttl = TTL;
918 940
919 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 941 send_skb_packet(skb, router->if_incoming, router->addr);
920 ret = NET_RX_SUCCESS; 942 ret = NET_RX_SUCCESS;
921 goto out;
922 943
923unlock:
924 rcu_read_unlock();
925out: 944out:
926 if (neigh_node) 945 if (router)
927 neigh_node_free_ref(neigh_node); 946 neigh_node_free_ref(router);
928 if (orig_node) 947 if (orig_node)
929 orig_node_free_ref(orig_node); 948 orig_node_free_ref(orig_node);
930 return ret; 949 return ret;
@@ -934,7 +953,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
934 struct sk_buff *skb) 953 struct sk_buff *skb)
935{ 954{
936 struct orig_node *orig_node = NULL; 955 struct orig_node *orig_node = NULL;
937 struct neigh_node *neigh_node = NULL; 956 struct neigh_node *router = NULL;
938 struct icmp_packet *icmp_packet; 957 struct icmp_packet *icmp_packet;
939 int ret = NET_RX_DROP; 958 int ret = NET_RX_DROP;
940 959
@@ -952,23 +971,13 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
952 goto out; 971 goto out;
953 972
954 /* get routing information */ 973 /* get routing information */
955 rcu_read_lock();
956 orig_node = orig_hash_find(bat_priv, icmp_packet->orig); 974 orig_node = orig_hash_find(bat_priv, icmp_packet->orig);
957
958 if (!orig_node) 975 if (!orig_node)
959 goto unlock; 976 goto out;
960
961 neigh_node = orig_node->router;
962
963 if (!neigh_node)
964 goto unlock;
965
966 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
967 neigh_node = NULL;
968 goto unlock;
969 }
970 977
971 rcu_read_unlock(); 978 router = orig_node_get_router(orig_node);
979 if (!router)
980 goto out;
972 981
973 /* create a copy of the skb, if needed, to modify it. */ 982 /* create a copy of the skb, if needed, to modify it. */
974 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 983 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -982,15 +991,12 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
982 icmp_packet->msg_type = TTL_EXCEEDED; 991 icmp_packet->msg_type = TTL_EXCEEDED;
983 icmp_packet->ttl = TTL; 992 icmp_packet->ttl = TTL;
984 993
985 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 994 send_skb_packet(skb, router->if_incoming, router->addr);
986 ret = NET_RX_SUCCESS; 995 ret = NET_RX_SUCCESS;
987 goto out;
988 996
989unlock:
990 rcu_read_unlock();
991out: 997out:
992 if (neigh_node) 998 if (router)
993 neigh_node_free_ref(neigh_node); 999 neigh_node_free_ref(router);
994 if (orig_node) 1000 if (orig_node)
995 orig_node_free_ref(orig_node); 1001 orig_node_free_ref(orig_node);
996 return ret; 1002 return ret;
@@ -1003,7 +1009,7 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1003 struct icmp_packet_rr *icmp_packet; 1009 struct icmp_packet_rr *icmp_packet;
1004 struct ethhdr *ethhdr; 1010 struct ethhdr *ethhdr;
1005 struct orig_node *orig_node = NULL; 1011 struct orig_node *orig_node = NULL;
1006 struct neigh_node *neigh_node = NULL; 1012 struct neigh_node *router = NULL;
1007 int hdr_size = sizeof(struct icmp_packet); 1013 int hdr_size = sizeof(struct icmp_packet);
1008 int ret = NET_RX_DROP; 1014 int ret = NET_RX_DROP;
1009 1015
@@ -1050,23 +1056,13 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1050 return recv_icmp_ttl_exceeded(bat_priv, skb); 1056 return recv_icmp_ttl_exceeded(bat_priv, skb);
1051 1057
1052 /* get routing information */ 1058 /* get routing information */
1053 rcu_read_lock();
1054 orig_node = orig_hash_find(bat_priv, icmp_packet->dst); 1059 orig_node = orig_hash_find(bat_priv, icmp_packet->dst);
1055
1056 if (!orig_node) 1060 if (!orig_node)
1057 goto unlock; 1061 goto out;
1058
1059 neigh_node = orig_node->router;
1060
1061 if (!neigh_node)
1062 goto unlock;
1063
1064 if (!atomic_inc_not_zero(&neigh_node->refcount)) {
1065 neigh_node = NULL;
1066 goto unlock;
1067 }
1068 1062
1069 rcu_read_unlock(); 1063 router = orig_node_get_router(orig_node);
1064 if (!router)
1065 goto out;
1070 1066
1071 /* create a copy of the skb, if needed, to modify it. */ 1067 /* create a copy of the skb, if needed, to modify it. */
1072 if (skb_cow(skb, sizeof(struct ethhdr)) < 0) 1068 if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
@@ -1078,15 +1074,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
1078 icmp_packet->ttl--; 1074 icmp_packet->ttl--;
1079 1075
1080 /* route it */ 1076 /* route it */
1081 send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); 1077 send_skb_packet(skb, router->if_incoming, router->addr);
1082 ret = NET_RX_SUCCESS; 1078 ret = NET_RX_SUCCESS;
1083 goto out;
1084 1079
1085unlock:
1086 rcu_read_unlock();
1087out: 1080out:
1088 if (neigh_node) 1081 if (router)
1089 neigh_node_free_ref(neigh_node); 1082 neigh_node_free_ref(router);
1090 if (orig_node) 1083 if (orig_node)
1091 orig_node_free_ref(orig_node); 1084 orig_node_free_ref(orig_node);
1092 return ret; 1085 return ret;
@@ -1208,7 +1201,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1208 if (!orig_node) 1201 if (!orig_node)
1209 return NULL; 1202 return NULL;
1210 1203
1211 if (!orig_node->router) 1204 router = orig_node_get_router(orig_node);
1205 if (!router)
1212 return NULL; 1206 return NULL;
1213 1207
1214 /* without bonding, the first node should 1208 /* without bonding, the first node should
@@ -1217,9 +1211,8 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1217 1211
1218 rcu_read_lock(); 1212 rcu_read_lock();
1219 /* select default router to output */ 1213 /* select default router to output */
1220 router = orig_node->router; 1214 router_orig = router->orig_node;
1221 router_orig = orig_node->router->orig_node; 1215 if (!router_orig) {
1222 if (!router_orig || !atomic_inc_not_zero(&router->refcount)) {
1223 rcu_read_unlock(); 1216 rcu_read_unlock();
1224 return NULL; 1217 return NULL;
1225 } 1218 }
@@ -1251,7 +1244,6 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
1251 if (atomic_read(&primary_orig_node->bond_candidates) < 2) 1244 if (atomic_read(&primary_orig_node->bond_candidates) < 2)
1252 goto return_router; 1245 goto return_router;
1253 1246
1254
1255 /* all nodes between should choose a candidate which 1247 /* all nodes between should choose a candidate which
1256 * is is not on the interface where the packet came 1248 * is is not on the interface where the packet came
1257 * in. */ 1249 * in. */