diff options
-rw-r--r-- | net/batman-adv/icmp_socket.c | 27 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 26 | ||||
-rw-r--r-- | net/batman-adv/originator.h | 3 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 338 | ||||
-rw-r--r-- | net/batman-adv/types.h | 3 | ||||
-rw-r--r-- | net/batman-adv/unicast.c | 57 | ||||
-rw-r--r-- | net/batman-adv/vis.c | 33 |
7 files changed, 313 insertions, 174 deletions
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 8e0cd8a1bc02..7fa5bb8a9409 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
@@ -156,7 +156,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
156 | struct sk_buff *skb; | 156 | struct sk_buff *skb; |
157 | struct icmp_packet_rr *icmp_packet; | 157 | struct icmp_packet_rr *icmp_packet; |
158 | 158 | ||
159 | struct orig_node *orig_node; | 159 | struct orig_node *orig_node = NULL; |
160 | struct neigh_node *neigh_node = NULL; | ||
160 | struct batman_if *batman_if; | 161 | struct batman_if *batman_if; |
161 | size_t packet_len = sizeof(struct icmp_packet); | 162 | size_t packet_len = sizeof(struct icmp_packet); |
162 | uint8_t dstaddr[ETH_ALEN]; | 163 | uint8_t dstaddr[ETH_ALEN]; |
@@ -224,17 +225,25 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
224 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | 225 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, |
225 | compare_orig, choose_orig, | 226 | compare_orig, choose_orig, |
226 | icmp_packet->dst)); | 227 | icmp_packet->dst)); |
227 | rcu_read_unlock(); | ||
228 | 228 | ||
229 | if (!orig_node) | 229 | if (!orig_node) |
230 | goto unlock; | 230 | goto unlock; |
231 | 231 | ||
232 | if (!orig_node->router) | 232 | kref_get(&orig_node->refcount); |
233 | neigh_node = orig_node->router; | ||
234 | |||
235 | if (!neigh_node) | ||
236 | goto unlock; | ||
237 | |||
238 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { | ||
239 | neigh_node = NULL; | ||
233 | goto unlock; | 240 | goto unlock; |
241 | } | ||
242 | |||
243 | rcu_read_unlock(); | ||
234 | 244 | ||
235 | batman_if = orig_node->router->if_incoming; | 245 | batman_if = orig_node->router->if_incoming; |
236 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | 246 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
237 | |||
238 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 247 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
239 | 248 | ||
240 | if (!batman_if) | 249 | if (!batman_if) |
@@ -247,14 +256,14 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
247 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 256 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); |
248 | 257 | ||
249 | if (packet_len == sizeof(struct icmp_packet_rr)) | 258 | if (packet_len == sizeof(struct icmp_packet_rr)) |
250 | memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); | 259 | memcpy(icmp_packet->rr, |
251 | 260 | batman_if->net_dev->dev_addr, ETH_ALEN); | |
252 | 261 | ||
253 | send_skb_packet(skb, batman_if, dstaddr); | 262 | send_skb_packet(skb, batman_if, dstaddr); |
254 | |||
255 | goto out; | 263 | goto out; |
256 | 264 | ||
257 | unlock: | 265 | unlock: |
266 | rcu_read_unlock(); | ||
258 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 267 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
259 | dst_unreach: | 268 | dst_unreach: |
260 | icmp_packet->msg_type = DESTINATION_UNREACHABLE; | 269 | icmp_packet->msg_type = DESTINATION_UNREACHABLE; |
@@ -262,6 +271,10 @@ dst_unreach: | |||
262 | free_skb: | 271 | free_skb: |
263 | kfree_skb(skb); | 272 | kfree_skb(skb); |
264 | out: | 273 | out: |
274 | if (neigh_node) | ||
275 | neigh_node_free_ref(neigh_node); | ||
276 | if (orig_node) | ||
277 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
265 | return len; | 278 | return len; |
266 | } | 279 | } |
267 | 280 | ||
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index a85eadca6b2d..61299da82c6b 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -59,28 +59,18 @@ err: | |||
59 | return 0; | 59 | return 0; |
60 | } | 60 | } |
61 | 61 | ||
62 | void neigh_node_free_ref(struct kref *refcount) | ||
63 | { | ||
64 | struct neigh_node *neigh_node; | ||
65 | |||
66 | neigh_node = container_of(refcount, struct neigh_node, refcount); | ||
67 | kfree(neigh_node); | ||
68 | } | ||
69 | |||
70 | static void neigh_node_free_rcu(struct rcu_head *rcu) | 62 | static void neigh_node_free_rcu(struct rcu_head *rcu) |
71 | { | 63 | { |
72 | struct neigh_node *neigh_node; | 64 | struct neigh_node *neigh_node; |
73 | 65 | ||
74 | neigh_node = container_of(rcu, struct neigh_node, rcu); | 66 | neigh_node = container_of(rcu, struct neigh_node, rcu); |
75 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | 67 | kfree(neigh_node); |
76 | } | 68 | } |
77 | 69 | ||
78 | void neigh_node_free_rcu_bond(struct rcu_head *rcu) | 70 | void neigh_node_free_ref(struct neigh_node *neigh_node) |
79 | { | 71 | { |
80 | struct neigh_node *neigh_node; | 72 | if (atomic_dec_and_test(&neigh_node->refcount)) |
81 | 73 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); | |
82 | neigh_node = container_of(rcu, struct neigh_node, rcu_bond); | ||
83 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | ||
84 | } | 74 | } |
85 | 75 | ||
86 | struct neigh_node *create_neighbor(struct orig_node *orig_node, | 76 | struct neigh_node *create_neighbor(struct orig_node *orig_node, |
@@ -104,7 +94,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, | |||
104 | memcpy(neigh_node->addr, neigh, ETH_ALEN); | 94 | memcpy(neigh_node->addr, neigh, ETH_ALEN); |
105 | neigh_node->orig_node = orig_neigh_node; | 95 | neigh_node->orig_node = orig_neigh_node; |
106 | neigh_node->if_incoming = if_incoming; | 96 | neigh_node->if_incoming = if_incoming; |
107 | kref_init(&neigh_node->refcount); | 97 | atomic_set(&neigh_node->refcount, 1); |
108 | 98 | ||
109 | spin_lock_bh(&orig_node->neigh_list_lock); | 99 | spin_lock_bh(&orig_node->neigh_list_lock); |
110 | hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); | 100 | hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); |
@@ -126,14 +116,14 @@ void orig_node_free_ref(struct kref *refcount) | |||
126 | list_for_each_entry_safe(neigh_node, tmp_neigh_node, | 116 | list_for_each_entry_safe(neigh_node, tmp_neigh_node, |
127 | &orig_node->bond_list, bonding_list) { | 117 | &orig_node->bond_list, bonding_list) { |
128 | list_del_rcu(&neigh_node->bonding_list); | 118 | list_del_rcu(&neigh_node->bonding_list); |
129 | call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond); | 119 | neigh_node_free_ref(neigh_node); |
130 | } | 120 | } |
131 | 121 | ||
132 | /* for all neighbors towards this originator ... */ | 122 | /* for all neighbors towards this originator ... */ |
133 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, | 123 | hlist_for_each_entry_safe(neigh_node, node, node_tmp, |
134 | &orig_node->neigh_list, list) { | 124 | &orig_node->neigh_list, list) { |
135 | hlist_del_rcu(&neigh_node->list); | 125 | hlist_del_rcu(&neigh_node->list); |
136 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); | 126 | neigh_node_free_ref(neigh_node); |
137 | } | 127 | } |
138 | 128 | ||
139 | spin_unlock_bh(&orig_node->neigh_list_lock); | 129 | spin_unlock_bh(&orig_node->neigh_list_lock); |
@@ -315,7 +305,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, | |||
315 | 305 | ||
316 | hlist_del_rcu(&neigh_node->list); | 306 | hlist_del_rcu(&neigh_node->list); |
317 | bonding_candidate_del(orig_node, neigh_node); | 307 | bonding_candidate_del(orig_node, neigh_node); |
318 | call_rcu(&neigh_node->rcu, neigh_node_free_rcu); | 308 | neigh_node_free_ref(neigh_node); |
319 | } else { | 309 | } else { |
320 | if ((!*best_neigh_node) || | 310 | if ((!*best_neigh_node) || |
321 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) | 311 | (neigh_node->tq_avg > (*best_neigh_node)->tq_avg)) |
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 360dfd19a32f..84d96e2eea47 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h | |||
@@ -26,13 +26,12 @@ int originator_init(struct bat_priv *bat_priv); | |||
26 | void originator_free(struct bat_priv *bat_priv); | 26 | void originator_free(struct bat_priv *bat_priv); |
27 | void purge_orig_ref(struct bat_priv *bat_priv); | 27 | void purge_orig_ref(struct bat_priv *bat_priv); |
28 | void orig_node_free_ref(struct kref *refcount); | 28 | void orig_node_free_ref(struct kref *refcount); |
29 | void neigh_node_free_rcu_bond(struct rcu_head *rcu); | ||
30 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); | 29 | struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr); |
31 | struct neigh_node *create_neighbor(struct orig_node *orig_node, | 30 | struct neigh_node *create_neighbor(struct orig_node *orig_node, |
32 | struct orig_node *orig_neigh_node, | 31 | struct orig_node *orig_neigh_node, |
33 | uint8_t *neigh, | 32 | uint8_t *neigh, |
34 | struct batman_if *if_incoming); | 33 | struct batman_if *if_incoming); |
35 | void neigh_node_free_ref(struct kref *refcount); | 34 | void neigh_node_free_ref(struct neigh_node *neigh_node); |
36 | int orig_seq_print_text(struct seq_file *seq, void *offset); | 35 | int orig_seq_print_text(struct seq_file *seq, void *offset); |
37 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); | 36 | int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); |
38 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); | 37 | int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 1ad14da20839..9185666ab3e0 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -121,12 +121,12 @@ static void update_route(struct bat_priv *bat_priv, | |||
121 | orig_node->router->addr); | 121 | orig_node->router->addr); |
122 | } | 122 | } |
123 | 123 | ||
124 | if (neigh_node) | 124 | if (neigh_node && !atomic_inc_not_zero(&neigh_node->refcount)) |
125 | kref_get(&neigh_node->refcount); | 125 | neigh_node = NULL; |
126 | neigh_node_tmp = orig_node->router; | 126 | neigh_node_tmp = orig_node->router; |
127 | orig_node->router = neigh_node; | 127 | orig_node->router = neigh_node; |
128 | if (neigh_node_tmp) | 128 | if (neigh_node_tmp) |
129 | kref_put(&neigh_node_tmp->refcount, neigh_node_free_ref); | 129 | neigh_node_free_ref(neigh_node_tmp); |
130 | } | 130 | } |
131 | 131 | ||
132 | 132 | ||
@@ -177,7 +177,11 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
177 | if (!neigh_node) | 177 | if (!neigh_node) |
178 | goto unlock; | 178 | goto unlock; |
179 | 179 | ||
180 | kref_get(&neigh_node->refcount); | 180 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { |
181 | neigh_node = NULL; | ||
182 | goto unlock; | ||
183 | } | ||
184 | |||
181 | rcu_read_unlock(); | 185 | rcu_read_unlock(); |
182 | 186 | ||
183 | neigh_node->last_valid = jiffies; | 187 | neigh_node->last_valid = jiffies; |
@@ -202,7 +206,11 @@ static int is_bidirectional_neigh(struct orig_node *orig_node, | |||
202 | if (!neigh_node) | 206 | if (!neigh_node) |
203 | goto unlock; | 207 | goto unlock; |
204 | 208 | ||
205 | kref_get(&neigh_node->refcount); | 209 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { |
210 | neigh_node = NULL; | ||
211 | goto unlock; | ||
212 | } | ||
213 | |||
206 | rcu_read_unlock(); | 214 | rcu_read_unlock(); |
207 | } | 215 | } |
208 | 216 | ||
@@ -267,7 +275,7 @@ unlock: | |||
267 | rcu_read_unlock(); | 275 | rcu_read_unlock(); |
268 | out: | 276 | out: |
269 | if (neigh_node) | 277 | if (neigh_node) |
270 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | 278 | neigh_node_free_ref(neigh_node); |
271 | return ret; | 279 | return ret; |
272 | } | 280 | } |
273 | 281 | ||
@@ -280,8 +288,8 @@ void bonding_candidate_del(struct orig_node *orig_node, | |||
280 | goto out; | 288 | goto out; |
281 | 289 | ||
282 | list_del_rcu(&neigh_node->bonding_list); | 290 | list_del_rcu(&neigh_node->bonding_list); |
283 | call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond); | ||
284 | INIT_LIST_HEAD(&neigh_node->bonding_list); | 291 | INIT_LIST_HEAD(&neigh_node->bonding_list); |
292 | neigh_node_free_ref(neigh_node); | ||
285 | atomic_dec(&orig_node->bond_candidates); | 293 | atomic_dec(&orig_node->bond_candidates); |
286 | 294 | ||
287 | out: | 295 | out: |
@@ -342,8 +350,10 @@ static void bonding_candidate_add(struct orig_node *orig_node, | |||
342 | if (!list_empty(&neigh_node->bonding_list)) | 350 | if (!list_empty(&neigh_node->bonding_list)) |
343 | goto out; | 351 | goto out; |
344 | 352 | ||
353 | if (!atomic_inc_not_zero(&neigh_node->refcount)) | ||
354 | goto out; | ||
355 | |||
345 | list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list); | 356 | list_add_rcu(&neigh_node->bonding_list, &orig_node->bond_list); |
346 | kref_get(&neigh_node->refcount); | ||
347 | atomic_inc(&orig_node->bond_candidates); | 357 | atomic_inc(&orig_node->bond_candidates); |
348 | goto out; | 358 | goto out; |
349 | 359 | ||
@@ -387,7 +397,10 @@ static void update_orig(struct bat_priv *bat_priv, | |||
387 | hlist_for_each_entry_rcu(tmp_neigh_node, node, | 397 | hlist_for_each_entry_rcu(tmp_neigh_node, node, |
388 | &orig_node->neigh_list, list) { | 398 | &orig_node->neigh_list, list) { |
389 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && | 399 | if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) && |
390 | (tmp_neigh_node->if_incoming == if_incoming)) { | 400 | (tmp_neigh_node->if_incoming == if_incoming) && |
401 | atomic_inc_not_zero(&tmp_neigh_node->refcount)) { | ||
402 | if (neigh_node) | ||
403 | neigh_node_free_ref(neigh_node); | ||
391 | neigh_node = tmp_neigh_node; | 404 | neigh_node = tmp_neigh_node; |
392 | continue; | 405 | continue; |
393 | } | 406 | } |
@@ -414,11 +427,15 @@ static void update_orig(struct bat_priv *bat_priv, | |||
414 | kref_put(&orig_tmp->refcount, orig_node_free_ref); | 427 | kref_put(&orig_tmp->refcount, orig_node_free_ref); |
415 | if (!neigh_node) | 428 | if (!neigh_node) |
416 | goto unlock; | 429 | goto unlock; |
430 | |||
431 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { | ||
432 | neigh_node = NULL; | ||
433 | goto unlock; | ||
434 | } | ||
417 | } else | 435 | } else |
418 | bat_dbg(DBG_BATMAN, bat_priv, | 436 | bat_dbg(DBG_BATMAN, bat_priv, |
419 | "Updating existing last-hop neighbor of originator\n"); | 437 | "Updating existing last-hop neighbor of originator\n"); |
420 | 438 | ||
421 | kref_get(&neigh_node->refcount); | ||
422 | rcu_read_unlock(); | 439 | rcu_read_unlock(); |
423 | 440 | ||
424 | orig_node->flags = batman_packet->flags; | 441 | orig_node->flags = batman_packet->flags; |
@@ -495,7 +512,7 @@ unlock: | |||
495 | rcu_read_unlock(); | 512 | rcu_read_unlock(); |
496 | out: | 513 | out: |
497 | if (neigh_node) | 514 | if (neigh_node) |
498 | kref_put(&neigh_node->refcount, neigh_node_free_ref); | 515 | neigh_node_free_ref(neigh_node); |
499 | } | 516 | } |
500 | 517 | ||
501 | /* checks whether the host restarted and is in the protection time. | 518 | /* checks whether the host restarted and is in the protection time. |
@@ -870,22 +887,23 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) | |||
870 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, | 887 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, |
871 | struct sk_buff *skb, size_t icmp_len) | 888 | struct sk_buff *skb, size_t icmp_len) |
872 | { | 889 | { |
873 | struct orig_node *orig_node; | 890 | struct orig_node *orig_node = NULL; |
891 | struct neigh_node *neigh_node = NULL; | ||
874 | struct icmp_packet_rr *icmp_packet; | 892 | struct icmp_packet_rr *icmp_packet; |
875 | struct batman_if *batman_if; | 893 | struct batman_if *batman_if; |
876 | int ret; | ||
877 | uint8_t dstaddr[ETH_ALEN]; | 894 | uint8_t dstaddr[ETH_ALEN]; |
895 | int ret = NET_RX_DROP; | ||
878 | 896 | ||
879 | icmp_packet = (struct icmp_packet_rr *)skb->data; | 897 | icmp_packet = (struct icmp_packet_rr *)skb->data; |
880 | 898 | ||
881 | /* add data to device queue */ | 899 | /* add data to device queue */ |
882 | if (icmp_packet->msg_type != ECHO_REQUEST) { | 900 | if (icmp_packet->msg_type != ECHO_REQUEST) { |
883 | bat_socket_receive_packet(icmp_packet, icmp_len); | 901 | bat_socket_receive_packet(icmp_packet, icmp_len); |
884 | return NET_RX_DROP; | 902 | goto out; |
885 | } | 903 | } |
886 | 904 | ||
887 | if (!bat_priv->primary_if) | 905 | if (!bat_priv->primary_if) |
888 | return NET_RX_DROP; | 906 | goto out; |
889 | 907 | ||
890 | /* answer echo request (ping) */ | 908 | /* answer echo request (ping) */ |
891 | /* get routing information */ | 909 | /* get routing information */ |
@@ -894,46 +912,65 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, | |||
894 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | 912 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, |
895 | compare_orig, choose_orig, | 913 | compare_orig, choose_orig, |
896 | icmp_packet->orig)); | 914 | icmp_packet->orig)); |
897 | rcu_read_unlock(); | ||
898 | ret = NET_RX_DROP; | ||
899 | 915 | ||
900 | if ((orig_node) && (orig_node->router)) { | 916 | if (!orig_node) |
917 | goto unlock; | ||
901 | 918 | ||
902 | /* don't lock while sending the packets ... we therefore | 919 | kref_get(&orig_node->refcount); |
903 | * copy the required data before sending */ | 920 | neigh_node = orig_node->router; |
904 | batman_if = orig_node->router->if_incoming; | ||
905 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
906 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
907 | 921 | ||
908 | /* create a copy of the skb, if needed, to modify it. */ | 922 | if (!neigh_node) |
909 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | 923 | goto unlock; |
910 | return NET_RX_DROP; | ||
911 | 924 | ||
912 | icmp_packet = (struct icmp_packet_rr *)skb->data; | 925 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { |
926 | neigh_node = NULL; | ||
927 | goto unlock; | ||
928 | } | ||
913 | 929 | ||
914 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 930 | rcu_read_unlock(); |
915 | memcpy(icmp_packet->orig, | ||
916 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
917 | icmp_packet->msg_type = ECHO_REPLY; | ||
918 | icmp_packet->ttl = TTL; | ||
919 | 931 | ||
920 | send_skb_packet(skb, batman_if, dstaddr); | 932 | /* don't lock while sending the packets ... we therefore |
921 | ret = NET_RX_SUCCESS; | 933 | * copy the required data before sending */ |
934 | batman_if = orig_node->router->if_incoming; | ||
935 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
936 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
922 | 937 | ||
923 | } else | 938 | /* create a copy of the skb, if needed, to modify it. */ |
924 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 939 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) |
940 | goto out; | ||
925 | 941 | ||
942 | icmp_packet = (struct icmp_packet_rr *)skb->data; | ||
943 | |||
944 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
945 | memcpy(icmp_packet->orig, | ||
946 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
947 | icmp_packet->msg_type = ECHO_REPLY; | ||
948 | icmp_packet->ttl = TTL; | ||
949 | |||
950 | send_skb_packet(skb, batman_if, dstaddr); | ||
951 | ret = NET_RX_SUCCESS; | ||
952 | goto out; | ||
953 | |||
954 | unlock: | ||
955 | rcu_read_unlock(); | ||
956 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
957 | out: | ||
958 | if (neigh_node) | ||
959 | neigh_node_free_ref(neigh_node); | ||
960 | if (orig_node) | ||
961 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
926 | return ret; | 962 | return ret; |
927 | } | 963 | } |
928 | 964 | ||
929 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | 965 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, |
930 | struct sk_buff *skb) | 966 | struct sk_buff *skb) |
931 | { | 967 | { |
932 | struct orig_node *orig_node; | 968 | struct orig_node *orig_node = NULL; |
969 | struct neigh_node *neigh_node = NULL; | ||
933 | struct icmp_packet *icmp_packet; | 970 | struct icmp_packet *icmp_packet; |
934 | struct batman_if *batman_if; | 971 | struct batman_if *batman_if; |
935 | int ret; | ||
936 | uint8_t dstaddr[ETH_ALEN]; | 972 | uint8_t dstaddr[ETH_ALEN]; |
973 | int ret = NET_RX_DROP; | ||
937 | 974 | ||
938 | icmp_packet = (struct icmp_packet *)skb->data; | 975 | icmp_packet = (struct icmp_packet *)skb->data; |
939 | 976 | ||
@@ -942,11 +979,11 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | |||
942 | pr_debug("Warning - can't forward icmp packet from %pM to " | 979 | pr_debug("Warning - can't forward icmp packet from %pM to " |
943 | "%pM: ttl exceeded\n", icmp_packet->orig, | 980 | "%pM: ttl exceeded\n", icmp_packet->orig, |
944 | icmp_packet->dst); | 981 | icmp_packet->dst); |
945 | return NET_RX_DROP; | 982 | goto out; |
946 | } | 983 | } |
947 | 984 | ||
948 | if (!bat_priv->primary_if) | 985 | if (!bat_priv->primary_if) |
949 | return NET_RX_DROP; | 986 | goto out; |
950 | 987 | ||
951 | /* get routing information */ | 988 | /* get routing information */ |
952 | spin_lock_bh(&bat_priv->orig_hash_lock); | 989 | spin_lock_bh(&bat_priv->orig_hash_lock); |
@@ -954,35 +991,53 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | |||
954 | orig_node = ((struct orig_node *) | 991 | orig_node = ((struct orig_node *) |
955 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | 992 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, |
956 | icmp_packet->orig)); | 993 | icmp_packet->orig)); |
957 | rcu_read_unlock(); | ||
958 | ret = NET_RX_DROP; | ||
959 | 994 | ||
960 | if ((orig_node) && (orig_node->router)) { | 995 | if (!orig_node) |
996 | goto unlock; | ||
961 | 997 | ||
962 | /* don't lock while sending the packets ... we therefore | 998 | kref_get(&orig_node->refcount); |
963 | * copy the required data before sending */ | 999 | neigh_node = orig_node->router; |
964 | batman_if = orig_node->router->if_incoming; | ||
965 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
966 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
967 | 1000 | ||
968 | /* create a copy of the skb, if needed, to modify it. */ | 1001 | if (!neigh_node) |
969 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | 1002 | goto unlock; |
970 | return NET_RX_DROP; | 1003 | |
1004 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { | ||
1005 | neigh_node = NULL; | ||
1006 | goto unlock; | ||
1007 | } | ||
971 | 1008 | ||
972 | icmp_packet = (struct icmp_packet *) skb->data; | 1009 | rcu_read_unlock(); |
973 | 1010 | ||
974 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 1011 | /* don't lock while sending the packets ... we therefore |
975 | memcpy(icmp_packet->orig, | 1012 | * copy the required data before sending */ |
976 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 1013 | batman_if = orig_node->router->if_incoming; |
977 | icmp_packet->msg_type = TTL_EXCEEDED; | 1014 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); |
978 | icmp_packet->ttl = TTL; | 1015 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
979 | 1016 | ||
980 | send_skb_packet(skb, batman_if, dstaddr); | 1017 | /* create a copy of the skb, if needed, to modify it. */ |
981 | ret = NET_RX_SUCCESS; | 1018 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) |
1019 | goto out; | ||
982 | 1020 | ||
983 | } else | 1021 | icmp_packet = (struct icmp_packet *)skb->data; |
984 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 1022 | |
1023 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | ||
1024 | memcpy(icmp_packet->orig, | ||
1025 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
1026 | icmp_packet->msg_type = TTL_EXCEEDED; | ||
1027 | icmp_packet->ttl = TTL; | ||
1028 | |||
1029 | send_skb_packet(skb, batman_if, dstaddr); | ||
1030 | ret = NET_RX_SUCCESS; | ||
1031 | goto out; | ||
985 | 1032 | ||
1033 | unlock: | ||
1034 | rcu_read_unlock(); | ||
1035 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1036 | out: | ||
1037 | if (neigh_node) | ||
1038 | neigh_node_free_ref(neigh_node); | ||
1039 | if (orig_node) | ||
1040 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
986 | return ret; | 1041 | return ret; |
987 | } | 1042 | } |
988 | 1043 | ||
@@ -992,11 +1047,12 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) | |||
992 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 1047 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
993 | struct icmp_packet_rr *icmp_packet; | 1048 | struct icmp_packet_rr *icmp_packet; |
994 | struct ethhdr *ethhdr; | 1049 | struct ethhdr *ethhdr; |
995 | struct orig_node *orig_node; | 1050 | struct orig_node *orig_node = NULL; |
1051 | struct neigh_node *neigh_node = NULL; | ||
996 | struct batman_if *batman_if; | 1052 | struct batman_if *batman_if; |
997 | int hdr_size = sizeof(struct icmp_packet); | 1053 | int hdr_size = sizeof(struct icmp_packet); |
998 | int ret; | ||
999 | uint8_t dstaddr[ETH_ALEN]; | 1054 | uint8_t dstaddr[ETH_ALEN]; |
1055 | int ret = NET_RX_DROP; | ||
1000 | 1056 | ||
1001 | /** | 1057 | /** |
1002 | * we truncate all incoming icmp packets if they don't match our size | 1058 | * we truncate all incoming icmp packets if they don't match our size |
@@ -1006,21 +1062,21 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) | |||
1006 | 1062 | ||
1007 | /* drop packet if it has not necessary minimum size */ | 1063 | /* drop packet if it has not necessary minimum size */ |
1008 | if (unlikely(!pskb_may_pull(skb, hdr_size))) | 1064 | if (unlikely(!pskb_may_pull(skb, hdr_size))) |
1009 | return NET_RX_DROP; | 1065 | goto out; |
1010 | 1066 | ||
1011 | ethhdr = (struct ethhdr *)skb_mac_header(skb); | 1067 | ethhdr = (struct ethhdr *)skb_mac_header(skb); |
1012 | 1068 | ||
1013 | /* packet with unicast indication but broadcast recipient */ | 1069 | /* packet with unicast indication but broadcast recipient */ |
1014 | if (is_broadcast_ether_addr(ethhdr->h_dest)) | 1070 | if (is_broadcast_ether_addr(ethhdr->h_dest)) |
1015 | return NET_RX_DROP; | 1071 | goto out; |
1016 | 1072 | ||
1017 | /* packet with broadcast sender address */ | 1073 | /* packet with broadcast sender address */ |
1018 | if (is_broadcast_ether_addr(ethhdr->h_source)) | 1074 | if (is_broadcast_ether_addr(ethhdr->h_source)) |
1019 | return NET_RX_DROP; | 1075 | goto out; |
1020 | 1076 | ||
1021 | /* not for me */ | 1077 | /* not for me */ |
1022 | if (!is_my_mac(ethhdr->h_dest)) | 1078 | if (!is_my_mac(ethhdr->h_dest)) |
1023 | return NET_RX_DROP; | 1079 | goto out; |
1024 | 1080 | ||
1025 | icmp_packet = (struct icmp_packet_rr *)skb->data; | 1081 | icmp_packet = (struct icmp_packet_rr *)skb->data; |
1026 | 1082 | ||
@@ -1040,40 +1096,56 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) | |||
1040 | if (icmp_packet->ttl < 2) | 1096 | if (icmp_packet->ttl < 2) |
1041 | return recv_icmp_ttl_exceeded(bat_priv, skb); | 1097 | return recv_icmp_ttl_exceeded(bat_priv, skb); |
1042 | 1098 | ||
1043 | ret = NET_RX_DROP; | ||
1044 | |||
1045 | /* get routing information */ | 1099 | /* get routing information */ |
1046 | spin_lock_bh(&bat_priv->orig_hash_lock); | 1100 | spin_lock_bh(&bat_priv->orig_hash_lock); |
1047 | rcu_read_lock(); | 1101 | rcu_read_lock(); |
1048 | orig_node = ((struct orig_node *) | 1102 | orig_node = ((struct orig_node *) |
1049 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | 1103 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, |
1050 | icmp_packet->dst)); | 1104 | icmp_packet->dst)); |
1051 | rcu_read_unlock(); | 1105 | if (!orig_node) |
1106 | goto unlock; | ||
1052 | 1107 | ||
1053 | if ((orig_node) && (orig_node->router)) { | 1108 | kref_get(&orig_node->refcount); |
1109 | neigh_node = orig_node->router; | ||
1054 | 1110 | ||
1055 | /* don't lock while sending the packets ... we therefore | 1111 | if (!neigh_node) |
1056 | * copy the required data before sending */ | 1112 | goto unlock; |
1057 | batman_if = orig_node->router->if_incoming; | ||
1058 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
1059 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1060 | 1113 | ||
1061 | /* create a copy of the skb, if needed, to modify it. */ | 1114 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { |
1062 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | 1115 | neigh_node = NULL; |
1063 | return NET_RX_DROP; | 1116 | goto unlock; |
1117 | } | ||
1118 | |||
1119 | rcu_read_unlock(); | ||
1064 | 1120 | ||
1065 | icmp_packet = (struct icmp_packet_rr *)skb->data; | 1121 | /* don't lock while sending the packets ... we therefore |
1122 | * copy the required data before sending */ | ||
1123 | batman_if = orig_node->router->if_incoming; | ||
1124 | memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); | ||
1125 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1066 | 1126 | ||
1067 | /* decrement ttl */ | 1127 | /* create a copy of the skb, if needed, to modify it. */ |
1068 | icmp_packet->ttl--; | 1128 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) |
1129 | goto out; | ||
1069 | 1130 | ||
1070 | /* route it */ | 1131 | icmp_packet = (struct icmp_packet_rr *)skb->data; |
1071 | send_skb_packet(skb, batman_if, dstaddr); | ||
1072 | ret = NET_RX_SUCCESS; | ||
1073 | 1132 | ||
1074 | } else | 1133 | /* decrement ttl */ |
1075 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 1134 | icmp_packet->ttl--; |
1076 | 1135 | ||
1136 | /* route it */ | ||
1137 | send_skb_packet(skb, batman_if, dstaddr); | ||
1138 | ret = NET_RX_SUCCESS; | ||
1139 | goto out; | ||
1140 | |||
1141 | unlock: | ||
1142 | rcu_read_unlock(); | ||
1143 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1144 | out: | ||
1145 | if (neigh_node) | ||
1146 | neigh_node_free_ref(neigh_node); | ||
1147 | if (orig_node) | ||
1148 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
1077 | return ret; | 1149 | return ret; |
1078 | } | 1150 | } |
1079 | 1151 | ||
@@ -1104,12 +1176,11 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, | |||
1104 | /* select default router to output */ | 1176 | /* select default router to output */ |
1105 | router = orig_node->router; | 1177 | router = orig_node->router; |
1106 | router_orig = orig_node->router->orig_node; | 1178 | router_orig = orig_node->router->orig_node; |
1107 | if (!router_orig) { | 1179 | if (!router_orig || !atomic_inc_not_zero(&router->refcount)) { |
1108 | rcu_read_unlock(); | 1180 | rcu_read_unlock(); |
1109 | return NULL; | 1181 | return NULL; |
1110 | } | 1182 | } |
1111 | 1183 | ||
1112 | |||
1113 | if ((!recv_if) && (!bonding_enabled)) | 1184 | if ((!recv_if) && (!bonding_enabled)) |
1114 | goto return_router; | 1185 | goto return_router; |
1115 | 1186 | ||
@@ -1142,6 +1213,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, | |||
1142 | * is is not on the interface where the packet came | 1213 | * is is not on the interface where the packet came |
1143 | * in. */ | 1214 | * in. */ |
1144 | 1215 | ||
1216 | neigh_node_free_ref(router); | ||
1145 | first_candidate = NULL; | 1217 | first_candidate = NULL; |
1146 | router = NULL; | 1218 | router = NULL; |
1147 | 1219 | ||
@@ -1154,16 +1226,23 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, | |||
1154 | if (!first_candidate) | 1226 | if (!first_candidate) |
1155 | first_candidate = tmp_neigh_node; | 1227 | first_candidate = tmp_neigh_node; |
1156 | /* recv_if == NULL on the first node. */ | 1228 | /* recv_if == NULL on the first node. */ |
1157 | if (tmp_neigh_node->if_incoming != recv_if) { | 1229 | if (tmp_neigh_node->if_incoming != recv_if && |
1230 | atomic_inc_not_zero(&tmp_neigh_node->refcount)) { | ||
1158 | router = tmp_neigh_node; | 1231 | router = tmp_neigh_node; |
1159 | break; | 1232 | break; |
1160 | } | 1233 | } |
1161 | } | 1234 | } |
1162 | 1235 | ||
1163 | /* use the first candidate if nothing was found. */ | 1236 | /* use the first candidate if nothing was found. */ |
1164 | if (!router) | 1237 | if (!router && first_candidate && |
1238 | atomic_inc_not_zero(&first_candidate->refcount)) | ||
1165 | router = first_candidate; | 1239 | router = first_candidate; |
1166 | 1240 | ||
1241 | if (!router) { | ||
1242 | rcu_read_unlock(); | ||
1243 | return NULL; | ||
1244 | } | ||
1245 | |||
1167 | /* selected should point to the next element | 1246 | /* selected should point to the next element |
1168 | * after the current router */ | 1247 | * after the current router */ |
1169 | spin_lock_bh(&primary_orig_node->neigh_list_lock); | 1248 | spin_lock_bh(&primary_orig_node->neigh_list_lock); |
@@ -1184,21 +1263,34 @@ struct neigh_node *find_router(struct bat_priv *bat_priv, | |||
1184 | first_candidate = tmp_neigh_node; | 1263 | first_candidate = tmp_neigh_node; |
1185 | 1264 | ||
1186 | /* recv_if == NULL on the first node. */ | 1265 | /* recv_if == NULL on the first node. */ |
1187 | if (tmp_neigh_node->if_incoming != recv_if) | 1266 | if (tmp_neigh_node->if_incoming == recv_if) |
1188 | /* if we don't have a router yet | 1267 | continue; |
1189 | * or this one is better, choose it. */ | 1268 | |
1190 | if ((!router) || | 1269 | if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) |
1191 | (tmp_neigh_node->tq_avg > router->tq_avg)) { | 1270 | continue; |
1192 | router = tmp_neigh_node; | 1271 | |
1193 | } | 1272 | /* if we don't have a router yet |
1273 | * or this one is better, choose it. */ | ||
1274 | if ((!router) || | ||
1275 | (tmp_neigh_node->tq_avg > router->tq_avg)) { | ||
1276 | /* decrement refcount of | ||
1277 | * previously selected router */ | ||
1278 | if (router) | ||
1279 | neigh_node_free_ref(router); | ||
1280 | |||
1281 | router = tmp_neigh_node; | ||
1282 | atomic_inc_not_zero(&router->refcount); | ||
1283 | } | ||
1284 | |||
1285 | neigh_node_free_ref(tmp_neigh_node); | ||
1194 | } | 1286 | } |
1195 | 1287 | ||
1196 | /* use the first candidate if nothing was found. */ | 1288 | /* use the first candidate if nothing was found. */ |
1197 | if (!router) | 1289 | if (!router && first_candidate && |
1290 | atomic_inc_not_zero(&first_candidate->refcount)) | ||
1198 | router = first_candidate; | 1291 | router = first_candidate; |
1199 | } | 1292 | } |
1200 | return_router: | 1293 | return_router: |
1201 | kref_get(&router->refcount); | ||
1202 | rcu_read_unlock(); | 1294 | rcu_read_unlock(); |
1203 | return router; | 1295 | return router; |
1204 | } | 1296 | } |
@@ -1232,13 +1324,13 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | |||
1232 | int hdr_size) | 1324 | int hdr_size) |
1233 | { | 1325 | { |
1234 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); | 1326 | struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); |
1235 | struct orig_node *orig_node; | 1327 | struct orig_node *orig_node = NULL; |
1236 | struct neigh_node *router; | 1328 | struct neigh_node *neigh_node = NULL; |
1237 | struct batman_if *batman_if; | 1329 | struct batman_if *batman_if; |
1238 | uint8_t dstaddr[ETH_ALEN]; | 1330 | uint8_t dstaddr[ETH_ALEN]; |
1239 | struct unicast_packet *unicast_packet; | 1331 | struct unicast_packet *unicast_packet; |
1240 | struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); | 1332 | struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); |
1241 | int ret; | 1333 | int ret = NET_RX_DROP; |
1242 | struct sk_buff *new_skb; | 1334 | struct sk_buff *new_skb; |
1243 | 1335 | ||
1244 | unicast_packet = (struct unicast_packet *)skb->data; | 1336 | unicast_packet = (struct unicast_packet *)skb->data; |
@@ -1248,7 +1340,7 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | |||
1248 | pr_debug("Warning - can't forward unicast packet from %pM to " | 1340 | pr_debug("Warning - can't forward unicast packet from %pM to " |
1249 | "%pM: ttl exceeded\n", ethhdr->h_source, | 1341 | "%pM: ttl exceeded\n", ethhdr->h_source, |
1250 | unicast_packet->dest); | 1342 | unicast_packet->dest); |
1251 | return NET_RX_DROP; | 1343 | goto out; |
1252 | } | 1344 | } |
1253 | 1345 | ||
1254 | /* get routing information */ | 1346 | /* get routing information */ |
@@ -1257,27 +1349,29 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | |||
1257 | orig_node = ((struct orig_node *) | 1349 | orig_node = ((struct orig_node *) |
1258 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, | 1350 | hash_find(bat_priv->orig_hash, compare_orig, choose_orig, |
1259 | unicast_packet->dest)); | 1351 | unicast_packet->dest)); |
1352 | if (!orig_node) | ||
1353 | goto unlock; | ||
1354 | |||
1355 | kref_get(&orig_node->refcount); | ||
1260 | rcu_read_unlock(); | 1356 | rcu_read_unlock(); |
1261 | 1357 | ||
1262 | /* find_router() increases neigh_nodes refcount if found. */ | 1358 | /* find_router() increases neigh_nodes refcount if found. */ |
1263 | router = find_router(bat_priv, orig_node, recv_if); | 1359 | neigh_node = find_router(bat_priv, orig_node, recv_if); |
1264 | 1360 | ||
1265 | if (!router) { | 1361 | if (!neigh_node) { |
1266 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 1362 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
1267 | return NET_RX_DROP; | 1363 | goto out; |
1268 | } | 1364 | } |
1269 | 1365 | ||
1270 | /* don't lock while sending the packets ... we therefore | 1366 | /* don't lock while sending the packets ... we therefore |
1271 | * copy the required data before sending */ | 1367 | * copy the required data before sending */ |
1272 | 1368 | batman_if = neigh_node->if_incoming; | |
1273 | batman_if = router->if_incoming; | 1369 | memcpy(dstaddr, neigh_node->addr, ETH_ALEN); |
1274 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
1275 | |||
1276 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 1370 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
1277 | 1371 | ||
1278 | /* create a copy of the skb, if needed, to modify it. */ | 1372 | /* create a copy of the skb, if needed, to modify it. */ |
1279 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) | 1373 | if (skb_cow(skb, sizeof(struct ethhdr)) < 0) |
1280 | return NET_RX_DROP; | 1374 | goto out; |
1281 | 1375 | ||
1282 | unicast_packet = (struct unicast_packet *)skb->data; | 1376 | unicast_packet = (struct unicast_packet *)skb->data; |
1283 | 1377 | ||
@@ -1293,11 +1387,13 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | |||
1293 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); | 1387 | ret = frag_reassemble_skb(skb, bat_priv, &new_skb); |
1294 | 1388 | ||
1295 | if (ret == NET_RX_DROP) | 1389 | if (ret == NET_RX_DROP) |
1296 | return NET_RX_DROP; | 1390 | goto out; |
1297 | 1391 | ||
1298 | /* packet was buffered for late merge */ | 1392 | /* packet was buffered for late merge */ |
1299 | if (!new_skb) | 1393 | if (!new_skb) { |
1300 | return NET_RX_SUCCESS; | 1394 | ret = NET_RX_SUCCESS; |
1395 | goto out; | ||
1396 | } | ||
1301 | 1397 | ||
1302 | skb = new_skb; | 1398 | skb = new_skb; |
1303 | unicast_packet = (struct unicast_packet *)skb->data; | 1399 | unicast_packet = (struct unicast_packet *)skb->data; |
@@ -1308,8 +1404,18 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, | |||
1308 | 1404 | ||
1309 | /* route it */ | 1405 | /* route it */ |
1310 | send_skb_packet(skb, batman_if, dstaddr); | 1406 | send_skb_packet(skb, batman_if, dstaddr); |
1407 | ret = NET_RX_SUCCESS; | ||
1408 | goto out; | ||
1311 | 1409 | ||
1312 | return NET_RX_SUCCESS; | 1410 | unlock: |
1411 | rcu_read_unlock(); | ||
1412 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
1413 | out: | ||
1414 | if (neigh_node) | ||
1415 | neigh_node_free_ref(neigh_node); | ||
1416 | if (orig_node) | ||
1417 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
1418 | return ret; | ||
1313 | } | 1419 | } |
1314 | 1420 | ||
1315 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) | 1421 | int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 1f833f04222e..084604a6dcf1 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -117,9 +117,8 @@ struct neigh_node { | |||
117 | struct list_head bonding_list; | 117 | struct list_head bonding_list; |
118 | unsigned long last_valid; | 118 | unsigned long last_valid; |
119 | unsigned long real_bits[NUM_WORDS]; | 119 | unsigned long real_bits[NUM_WORDS]; |
120 | struct kref refcount; | 120 | atomic_t refcount; |
121 | struct rcu_head rcu; | 121 | struct rcu_head rcu; |
122 | struct rcu_head rcu_bond; | ||
123 | struct orig_node *orig_node; | 122 | struct orig_node *orig_node; |
124 | struct batman_if *if_incoming; | 123 | struct batman_if *if_incoming; |
125 | }; | 124 | }; |
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index 00bfeaf9ece3..7ca994ccac1d 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c | |||
@@ -285,38 +285,42 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) | |||
285 | struct unicast_packet *unicast_packet; | 285 | struct unicast_packet *unicast_packet; |
286 | struct orig_node *orig_node = NULL; | 286 | struct orig_node *orig_node = NULL; |
287 | struct batman_if *batman_if; | 287 | struct batman_if *batman_if; |
288 | struct neigh_node *router; | 288 | struct neigh_node *neigh_node; |
289 | int data_len = skb->len; | 289 | int data_len = skb->len; |
290 | uint8_t dstaddr[6]; | 290 | uint8_t dstaddr[6]; |
291 | int ret = 1; | ||
291 | 292 | ||
292 | spin_lock_bh(&bat_priv->orig_hash_lock); | 293 | spin_lock_bh(&bat_priv->orig_hash_lock); |
293 | 294 | ||
294 | /* get routing information */ | 295 | /* get routing information */ |
295 | if (is_multicast_ether_addr(ethhdr->h_dest)) | 296 | if (is_multicast_ether_addr(ethhdr->h_dest)) |
296 | orig_node = (struct orig_node *)gw_get_selected(bat_priv); | 297 | orig_node = (struct orig_node *)gw_get_selected(bat_priv); |
298 | if (orig_node) { | ||
299 | kref_get(&orig_node->refcount); | ||
300 | goto find_router; | ||
301 | } | ||
297 | 302 | ||
298 | /* check for hna host */ | 303 | /* check for hna host - increases orig_node refcount */ |
299 | if (!orig_node) | 304 | orig_node = transtable_search(bat_priv, ethhdr->h_dest); |
300 | orig_node = transtable_search(bat_priv, ethhdr->h_dest); | ||
301 | 305 | ||
306 | find_router: | ||
302 | /* find_router() increases neigh_nodes refcount if found. */ | 307 | /* find_router() increases neigh_nodes refcount if found. */ |
303 | router = find_router(bat_priv, orig_node, NULL); | 308 | neigh_node = find_router(bat_priv, orig_node, NULL); |
304 | 309 | ||
305 | if (!router) | 310 | if (!neigh_node) |
306 | goto unlock; | 311 | goto unlock; |
307 | 312 | ||
308 | /* don't lock while sending the packets ... we therefore | 313 | if (neigh_node->if_incoming->if_status != IF_ACTIVE) |
309 | * copy the required data before sending */ | 314 | goto unlock; |
310 | batman_if = router->if_incoming; | ||
311 | memcpy(dstaddr, router->addr, ETH_ALEN); | ||
312 | |||
313 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
314 | |||
315 | if (batman_if->if_status != IF_ACTIVE) | ||
316 | goto dropped; | ||
317 | 315 | ||
318 | if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) | 316 | if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) |
319 | goto dropped; | 317 | goto unlock; |
318 | |||
319 | /* don't lock while sending the packets ... we therefore | ||
320 | * copy the required data before sending */ | ||
321 | batman_if = neigh_node->if_incoming; | ||
322 | memcpy(dstaddr, neigh_node->addr, ETH_ALEN); | ||
323 | spin_unlock_bh(&bat_priv->orig_hash_lock); | ||
320 | 324 | ||
321 | unicast_packet = (struct unicast_packet *)skb->data; | 325 | unicast_packet = (struct unicast_packet *)skb->data; |
322 | 326 | ||
@@ -330,18 +334,25 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) | |||
330 | 334 | ||
331 | if (atomic_read(&bat_priv->fragmentation) && | 335 | if (atomic_read(&bat_priv->fragmentation) && |
332 | data_len + sizeof(struct unicast_packet) > | 336 | data_len + sizeof(struct unicast_packet) > |
333 | batman_if->net_dev->mtu) { | 337 | batman_if->net_dev->mtu) { |
334 | /* send frag skb decreases ttl */ | 338 | /* send frag skb decreases ttl */ |
335 | unicast_packet->ttl++; | 339 | unicast_packet->ttl++; |
336 | return frag_send_skb(skb, bat_priv, batman_if, | 340 | ret = frag_send_skb(skb, bat_priv, batman_if, dstaddr); |
337 | dstaddr); | 341 | goto out; |
338 | } | 342 | } |
343 | |||
339 | send_skb_packet(skb, batman_if, dstaddr); | 344 | send_skb_packet(skb, batman_if, dstaddr); |
340 | return 0; | 345 | ret = 0; |
346 | goto out; | ||
341 | 347 | ||
342 | unlock: | 348 | unlock: |
343 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 349 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
344 | dropped: | 350 | out: |
345 | kfree_skb(skb); | 351 | if (neigh_node) |
346 | return 1; | 352 | neigh_node_free_ref(neigh_node); |
353 | if (orig_node) | ||
354 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
355 | if (ret == 1) | ||
356 | kfree_skb(skb); | ||
357 | return ret; | ||
347 | } | 358 | } |
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index 8092eadcbdee..9832d8f9ed44 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c | |||
@@ -764,21 +764,35 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, | |||
764 | struct vis_info *info) | 764 | struct vis_info *info) |
765 | { | 765 | { |
766 | struct orig_node *orig_node; | 766 | struct orig_node *orig_node; |
767 | struct neigh_node *neigh_node = NULL; | ||
767 | struct sk_buff *skb; | 768 | struct sk_buff *skb; |
768 | struct vis_packet *packet; | 769 | struct vis_packet *packet; |
769 | struct batman_if *batman_if; | 770 | struct batman_if *batman_if; |
770 | uint8_t dstaddr[ETH_ALEN]; | 771 | uint8_t dstaddr[ETH_ALEN]; |
771 | 772 | ||
772 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
773 | packet = (struct vis_packet *)info->skb_packet->data; | 773 | packet = (struct vis_packet *)info->skb_packet->data; |
774 | |||
775 | spin_lock_bh(&bat_priv->orig_hash_lock); | ||
774 | rcu_read_lock(); | 776 | rcu_read_lock(); |
775 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, | 777 | orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, |
776 | compare_orig, choose_orig, | 778 | compare_orig, choose_orig, |
777 | packet->target_orig)); | 779 | packet->target_orig)); |
778 | rcu_read_unlock(); | ||
779 | 780 | ||
780 | if ((!orig_node) || (!orig_node->router)) | 781 | if (!orig_node) |
781 | goto out; | 782 | goto unlock; |
783 | |||
784 | kref_get(&orig_node->refcount); | ||
785 | neigh_node = orig_node->router; | ||
786 | |||
787 | if (!neigh_node) | ||
788 | goto unlock; | ||
789 | |||
790 | if (!atomic_inc_not_zero(&neigh_node->refcount)) { | ||
791 | neigh_node = NULL; | ||
792 | goto unlock; | ||
793 | } | ||
794 | |||
795 | rcu_read_unlock(); | ||
782 | 796 | ||
783 | /* don't lock while sending the packets ... we therefore | 797 | /* don't lock while sending the packets ... we therefore |
784 | * copy the required data before sending */ | 798 | * copy the required data before sending */ |
@@ -790,10 +804,17 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, | |||
790 | if (skb) | 804 | if (skb) |
791 | send_skb_packet(skb, batman_if, dstaddr); | 805 | send_skb_packet(skb, batman_if, dstaddr); |
792 | 806 | ||
793 | return; | 807 | goto out; |
794 | 808 | ||
795 | out: | 809 | unlock: |
810 | rcu_read_unlock(); | ||
796 | spin_unlock_bh(&bat_priv->orig_hash_lock); | 811 | spin_unlock_bh(&bat_priv->orig_hash_lock); |
812 | out: | ||
813 | if (neigh_node) | ||
814 | neigh_node_free_ref(neigh_node); | ||
815 | if (orig_node) | ||
816 | kref_put(&orig_node->refcount, orig_node_free_ref); | ||
817 | return; | ||
797 | } | 818 | } |
798 | 819 | ||
799 | /* only send one vis packet. called from send_vis_packets() */ | 820 | /* only send one vis packet. called from send_vis_packets() */ |