diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-04-20 09:40:58 -0400 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-05-01 16:49:03 -0400 |
commit | 32ae9b221e788413ce68feaae2ca39e406211a0a (patch) | |
tree | d827f989976a28fea5cdcb349c308baa98182c35 | |
parent | 71e4aa9c465fd66c110667ab5d620fb6a4ef2157 (diff) |
batman-adv: Make bat_priv->primary_if an rcu protected pointer
The rcu protected macros rcu_dereference() and rcu_assign_pointer()
for the bat_priv->primary_if need to be used, as well as spin/rcu locking.
Otherwise we might end up using a primary_if pointer pointing to already
freed memory.
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
-rw-r--r-- | net/batman-adv/gateway_client.c | 33 | ||||
-rw-r--r-- | net/batman-adv/hard-interface.c | 83 | ||||
-rw-r--r-- | net/batman-adv/hard-interface.h | 18 | ||||
-rw-r--r-- | net/batman-adv/icmp_socket.c | 19 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 34 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 18 | ||||
-rw-r--r-- | net/batman-adv/send.c | 17 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.c | 64 | ||||
-rw-r--r-- | net/batman-adv/translation-table.c | 57 | ||||
-rw-r--r-- | net/batman-adv/types.h | 2 | ||||
-rw-r--r-- | net/batman-adv/unicast.c | 16 | ||||
-rw-r--r-- | net/batman-adv/vis.c | 37 |
12 files changed, 280 insertions, 118 deletions
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index af128eff2edf..65f39530799d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c | |||
@@ -439,30 +439,32 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) | |||
439 | { | 439 | { |
440 | struct net_device *net_dev = (struct net_device *)seq->private; | 440 | struct net_device *net_dev = (struct net_device *)seq->private; |
441 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 441 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
442 | struct hard_iface *primary_if; | ||
442 | struct gw_node *gw_node; | 443 | struct gw_node *gw_node; |
443 | struct hlist_node *node; | 444 | struct hlist_node *node; |
444 | int gw_count = 0; | 445 | int gw_count = 0, ret = 0; |
445 | 446 | ||
446 | if (!bat_priv->primary_if) { | 447 | primary_if = primary_if_get_selected(bat_priv); |
447 | 448 | if (!primary_if) { | |
448 | return seq_printf(seq, "BATMAN mesh %s disabled - please " | 449 | ret = seq_printf(seq, "BATMAN mesh %s disabled - please " |
449 | "specify interfaces to enable it\n", | 450 | "specify interfaces to enable it\n", |
450 | net_dev->name); | 451 | net_dev->name); |
452 | goto out; | ||
451 | } | 453 | } |
452 | 454 | ||
453 | if (bat_priv->primary_if->if_status != IF_ACTIVE) { | 455 | if (primary_if->if_status != IF_ACTIVE) { |
454 | 456 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " | |
455 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 457 | "primary interface not active\n", |
456 | "primary interface not active\n", | 458 | net_dev->name); |
457 | net_dev->name); | 459 | goto out; |
458 | } | 460 | } |
459 | 461 | ||
460 | seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " | 462 | seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " |
461 | "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | 463 | "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", |
462 | "Gateway", "#", TQ_MAX_VALUE, "Nexthop", | 464 | "Gateway", "#", TQ_MAX_VALUE, "Nexthop", |
463 | "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, | 465 | "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, |
464 | bat_priv->primary_if->net_dev->name, | 466 | primary_if->net_dev->name, |
465 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | 467 | primary_if->net_dev->dev_addr, net_dev->name); |
466 | 468 | ||
467 | rcu_read_lock(); | 469 | rcu_read_lock(); |
468 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { | 470 | hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { |
@@ -480,7 +482,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) | |||
480 | if (gw_count == 0) | 482 | if (gw_count == 0) |
481 | seq_printf(seq, "No gateways in range ...\n"); | 483 | seq_printf(seq, "No gateways in range ...\n"); |
482 | 484 | ||
483 | return 0; | 485 | out: |
486 | if (primary_if) | ||
487 | hardif_free_ref(primary_if); | ||
488 | return ret; | ||
484 | } | 489 | } |
485 | 490 | ||
486 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) | 491 | int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) |
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index b3058e46ee6b..3e888f133d75 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c | |||
@@ -110,47 +110,60 @@ out: | |||
110 | return hard_iface; | 110 | return hard_iface; |
111 | } | 111 | } |
112 | 112 | ||
113 | static void update_primary_addr(struct bat_priv *bat_priv) | 113 | static void primary_if_update_addr(struct bat_priv *bat_priv) |
114 | { | 114 | { |
115 | struct vis_packet *vis_packet; | 115 | struct vis_packet *vis_packet; |
116 | struct hard_iface *primary_if; | ||
117 | |||
118 | primary_if = primary_if_get_selected(bat_priv); | ||
119 | if (!primary_if) | ||
120 | goto out; | ||
116 | 121 | ||
117 | vis_packet = (struct vis_packet *) | 122 | vis_packet = (struct vis_packet *) |
118 | bat_priv->my_vis_info->skb_packet->data; | 123 | bat_priv->my_vis_info->skb_packet->data; |
119 | memcpy(vis_packet->vis_orig, | 124 | memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
120 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
121 | memcpy(vis_packet->sender_orig, | 125 | memcpy(vis_packet->sender_orig, |
122 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 126 | primary_if->net_dev->dev_addr, ETH_ALEN); |
127 | |||
128 | out: | ||
129 | if (primary_if) | ||
130 | hardif_free_ref(primary_if); | ||
123 | } | 131 | } |
124 | 132 | ||
125 | static void set_primary_if(struct bat_priv *bat_priv, | 133 | static void primary_if_select(struct bat_priv *bat_priv, |
126 | struct hard_iface *hard_iface) | 134 | struct hard_iface *new_hard_iface) |
127 | { | 135 | { |
136 | struct hard_iface *curr_hard_iface; | ||
128 | struct batman_packet *batman_packet; | 137 | struct batman_packet *batman_packet; |
129 | struct hard_iface *old_if; | ||
130 | 138 | ||
131 | if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) | 139 | spin_lock_bh(&hardif_list_lock); |
132 | hard_iface = NULL; | ||
133 | 140 | ||
134 | old_if = bat_priv->primary_if; | 141 | if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) |
135 | bat_priv->primary_if = hard_iface; | 142 | new_hard_iface = NULL; |
136 | 143 | ||
137 | if (old_if) | 144 | curr_hard_iface = bat_priv->primary_if; |
138 | hardif_free_ref(old_if); | 145 | rcu_assign_pointer(bat_priv->primary_if, new_hard_iface); |
139 | 146 | ||
140 | if (!bat_priv->primary_if) | 147 | if (curr_hard_iface) |
141 | return; | 148 | hardif_free_ref(curr_hard_iface); |
142 | 149 | ||
143 | batman_packet = (struct batman_packet *)(hard_iface->packet_buff); | 150 | if (!new_hard_iface) |
151 | goto out; | ||
152 | |||
153 | batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); | ||
144 | batman_packet->flags = PRIMARIES_FIRST_HOP; | 154 | batman_packet->flags = PRIMARIES_FIRST_HOP; |
145 | batman_packet->ttl = TTL; | 155 | batman_packet->ttl = TTL; |
146 | 156 | ||
147 | update_primary_addr(bat_priv); | 157 | primary_if_update_addr(bat_priv); |
148 | 158 | ||
149 | /*** | 159 | /*** |
150 | * hacky trick to make sure that we send the HNA information via | 160 | * hacky trick to make sure that we send the HNA information via |
151 | * our new primary interface | 161 | * our new primary interface |
152 | */ | 162 | */ |
153 | atomic_set(&bat_priv->hna_local_changed, 1); | 163 | atomic_set(&bat_priv->hna_local_changed, 1); |
164 | |||
165 | out: | ||
166 | spin_unlock_bh(&hardif_list_lock); | ||
154 | } | 167 | } |
155 | 168 | ||
156 | static bool hardif_is_iface_up(struct hard_iface *hard_iface) | 169 | static bool hardif_is_iface_up(struct hard_iface *hard_iface) |
@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface) | |||
236 | static void hardif_activate_interface(struct hard_iface *hard_iface) | 249 | static void hardif_activate_interface(struct hard_iface *hard_iface) |
237 | { | 250 | { |
238 | struct bat_priv *bat_priv; | 251 | struct bat_priv *bat_priv; |
252 | struct hard_iface *primary_if = NULL; | ||
239 | 253 | ||
240 | if (hard_iface->if_status != IF_INACTIVE) | 254 | if (hard_iface->if_status != IF_INACTIVE) |
241 | return; | 255 | goto out; |
242 | 256 | ||
243 | bat_priv = netdev_priv(hard_iface->soft_iface); | 257 | bat_priv = netdev_priv(hard_iface->soft_iface); |
244 | 258 | ||
@@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface) | |||
249 | * the first active interface becomes our primary interface or | 263 | * the first active interface becomes our primary interface or |
250 | * the next active interface after the old primay interface was removed | 264 | * the next active interface after the old primay interface was removed |
251 | */ | 265 | */ |
252 | if (!bat_priv->primary_if) | 266 | primary_if = primary_if_get_selected(bat_priv); |
253 | set_primary_if(bat_priv, hard_iface); | 267 | if (!primary_if) |
268 | primary_if_select(bat_priv, hard_iface); | ||
254 | 269 | ||
255 | bat_info(hard_iface->soft_iface, "Interface activated: %s\n", | 270 | bat_info(hard_iface->soft_iface, "Interface activated: %s\n", |
256 | hard_iface->net_dev->name); | 271 | hard_iface->net_dev->name); |
257 | 272 | ||
258 | update_min_mtu(hard_iface->soft_iface); | 273 | update_min_mtu(hard_iface->soft_iface); |
259 | return; | 274 | |
275 | out: | ||
276 | if (primary_if) | ||
277 | hardif_free_ref(primary_if); | ||
260 | } | 278 | } |
261 | 279 | ||
262 | static void hardif_deactivate_interface(struct hard_iface *hard_iface) | 280 | static void hardif_deactivate_interface(struct hard_iface *hard_iface) |
@@ -386,12 +404,13 @@ err: | |||
386 | void hardif_disable_interface(struct hard_iface *hard_iface) | 404 | void hardif_disable_interface(struct hard_iface *hard_iface) |
387 | { | 405 | { |
388 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 406 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
407 | struct hard_iface *primary_if = NULL; | ||
389 | 408 | ||
390 | if (hard_iface->if_status == IF_ACTIVE) | 409 | if (hard_iface->if_status == IF_ACTIVE) |
391 | hardif_deactivate_interface(hard_iface); | 410 | hardif_deactivate_interface(hard_iface); |
392 | 411 | ||
393 | if (hard_iface->if_status != IF_INACTIVE) | 412 | if (hard_iface->if_status != IF_INACTIVE) |
394 | return; | 413 | goto out; |
395 | 414 | ||
396 | bat_info(hard_iface->soft_iface, "Removing interface: %s\n", | 415 | bat_info(hard_iface->soft_iface, "Removing interface: %s\n", |
397 | hard_iface->net_dev->name); | 416 | hard_iface->net_dev->name); |
@@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface) | |||
400 | bat_priv->num_ifaces--; | 419 | bat_priv->num_ifaces--; |
401 | orig_hash_del_if(hard_iface, bat_priv->num_ifaces); | 420 | orig_hash_del_if(hard_iface, bat_priv->num_ifaces); |
402 | 421 | ||
403 | if (hard_iface == bat_priv->primary_if) { | 422 | primary_if = primary_if_get_selected(bat_priv); |
423 | if (hard_iface == primary_if) { | ||
404 | struct hard_iface *new_if; | 424 | struct hard_iface *new_if; |
405 | 425 | ||
406 | new_if = hardif_get_active(hard_iface->soft_iface); | 426 | new_if = hardif_get_active(hard_iface->soft_iface); |
407 | set_primary_if(bat_priv, new_if); | 427 | primary_if_select(bat_priv, new_if); |
408 | 428 | ||
409 | if (new_if) | 429 | if (new_if) |
410 | hardif_free_ref(new_if); | 430 | hardif_free_ref(new_if); |
@@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface) | |||
425 | 445 | ||
426 | hard_iface->soft_iface = NULL; | 446 | hard_iface->soft_iface = NULL; |
427 | hardif_free_ref(hard_iface); | 447 | hardif_free_ref(hard_iface); |
448 | |||
449 | out: | ||
450 | if (primary_if) | ||
451 | hardif_free_ref(primary_if); | ||
428 | } | 452 | } |
429 | 453 | ||
430 | static struct hard_iface *hardif_add_interface(struct net_device *net_dev) | 454 | static struct hard_iface *hardif_add_interface(struct net_device *net_dev) |
@@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this, | |||
514 | { | 538 | { |
515 | struct net_device *net_dev = (struct net_device *)ptr; | 539 | struct net_device *net_dev = (struct net_device *)ptr; |
516 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | 540 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); |
541 | struct hard_iface *primary_if = NULL; | ||
517 | struct bat_priv *bat_priv; | 542 | struct bat_priv *bat_priv; |
518 | 543 | ||
519 | if (!hard_iface && event == NETDEV_REGISTER) | 544 | if (!hard_iface && event == NETDEV_REGISTER) |
@@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this, | |||
549 | update_mac_addresses(hard_iface); | 574 | update_mac_addresses(hard_iface); |
550 | 575 | ||
551 | bat_priv = netdev_priv(hard_iface->soft_iface); | 576 | bat_priv = netdev_priv(hard_iface->soft_iface); |
552 | if (hard_iface == bat_priv->primary_if) | 577 | primary_if = primary_if_get_selected(bat_priv); |
553 | update_primary_addr(bat_priv); | 578 | if (!primary_if) |
579 | goto hardif_put; | ||
580 | |||
581 | if (hard_iface == primary_if) | ||
582 | primary_if_update_addr(bat_priv); | ||
554 | break; | 583 | break; |
555 | default: | 584 | default: |
556 | break; | 585 | break; |
@@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this, | |||
559 | hardif_put: | 588 | hardif_put: |
560 | hardif_free_ref(hard_iface); | 589 | hardif_free_ref(hard_iface); |
561 | out: | 590 | out: |
591 | if (primary_if) | ||
592 | hardif_free_ref(primary_if); | ||
562 | return NOTIFY_DONE; | 593 | return NOTIFY_DONE; |
563 | } | 594 | } |
564 | 595 | ||
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index a9ddf36e51c8..64265991460b 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h | |||
@@ -45,4 +45,22 @@ static inline void hardif_free_ref(struct hard_iface *hard_iface) | |||
45 | call_rcu(&hard_iface->rcu, hardif_free_rcu); | 45 | call_rcu(&hard_iface->rcu, hardif_free_rcu); |
46 | } | 46 | } |
47 | 47 | ||
48 | static inline struct hard_iface *primary_if_get_selected( | ||
49 | struct bat_priv *bat_priv) | ||
50 | { | ||
51 | struct hard_iface *hard_iface; | ||
52 | |||
53 | rcu_read_lock(); | ||
54 | hard_iface = rcu_dereference(bat_priv->primary_if); | ||
55 | if (!hard_iface) | ||
56 | goto out; | ||
57 | |||
58 | if (!atomic_inc_not_zero(&hard_iface->refcount)) | ||
59 | hard_iface = NULL; | ||
60 | |||
61 | out: | ||
62 | rcu_read_unlock(); | ||
63 | return hard_iface; | ||
64 | } | ||
65 | |||
48 | #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ | 66 | #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ |
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 49079c254476..fa22ba2bb832 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c | |||
@@ -153,6 +153,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
153 | { | 153 | { |
154 | struct socket_client *socket_client = file->private_data; | 154 | struct socket_client *socket_client = file->private_data; |
155 | struct bat_priv *bat_priv = socket_client->bat_priv; | 155 | struct bat_priv *bat_priv = socket_client->bat_priv; |
156 | struct hard_iface *primary_if = NULL; | ||
156 | struct sk_buff *skb; | 157 | struct sk_buff *skb; |
157 | struct icmp_packet_rr *icmp_packet; | 158 | struct icmp_packet_rr *icmp_packet; |
158 | 159 | ||
@@ -167,15 +168,21 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
167 | return -EINVAL; | 168 | return -EINVAL; |
168 | } | 169 | } |
169 | 170 | ||
170 | if (!bat_priv->primary_if) | 171 | primary_if = primary_if_get_selected(bat_priv); |
171 | return -EFAULT; | 172 | |
173 | if (!primary_if) { | ||
174 | len = -EFAULT; | ||
175 | goto out; | ||
176 | } | ||
172 | 177 | ||
173 | if (len >= sizeof(struct icmp_packet_rr)) | 178 | if (len >= sizeof(struct icmp_packet_rr)) |
174 | packet_len = sizeof(struct icmp_packet_rr); | 179 | packet_len = sizeof(struct icmp_packet_rr); |
175 | 180 | ||
176 | skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); | 181 | skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); |
177 | if (!skb) | 182 | if (!skb) { |
178 | return -ENOMEM; | 183 | len = -ENOMEM; |
184 | goto out; | ||
185 | } | ||
179 | 186 | ||
180 | skb_reserve(skb, sizeof(struct ethhdr)); | 187 | skb_reserve(skb, sizeof(struct ethhdr)); |
181 | icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); | 188 | icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); |
@@ -233,7 +240,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, | |||
233 | goto dst_unreach; | 240 | goto dst_unreach; |
234 | 241 | ||
235 | memcpy(icmp_packet->orig, | 242 | memcpy(icmp_packet->orig, |
236 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 243 | primary_if->net_dev->dev_addr, ETH_ALEN); |
237 | 244 | ||
238 | if (packet_len == sizeof(struct icmp_packet_rr)) | 245 | if (packet_len == sizeof(struct icmp_packet_rr)) |
239 | memcpy(icmp_packet->rr, | 246 | memcpy(icmp_packet->rr, |
@@ -248,6 +255,8 @@ dst_unreach: | |||
248 | free_skb: | 255 | free_skb: |
249 | kfree_skb(skb); | 256 | kfree_skb(skb); |
250 | out: | 257 | out: |
258 | if (primary_if) | ||
259 | hardif_free_ref(primary_if); | ||
251 | if (neigh_node) | 260 | if (neigh_node) |
252 | neigh_node_free_ref(neigh_node); | 261 | neigh_node_free_ref(neigh_node); |
253 | if (orig_node) | 262 | if (orig_node) |
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 5b8fe32043da..ef4a9be7613a 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c | |||
@@ -405,29 +405,34 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) | |||
405 | struct hashtable_t *hash = bat_priv->orig_hash; | 405 | struct hashtable_t *hash = bat_priv->orig_hash; |
406 | struct hlist_node *node, *node_tmp; | 406 | struct hlist_node *node, *node_tmp; |
407 | struct hlist_head *head; | 407 | struct hlist_head *head; |
408 | struct hard_iface *primary_if; | ||
408 | struct orig_node *orig_node; | 409 | struct orig_node *orig_node; |
409 | struct neigh_node *neigh_node, *neigh_node_tmp; | 410 | struct neigh_node *neigh_node, *neigh_node_tmp; |
410 | int batman_count = 0; | 411 | int batman_count = 0; |
411 | int last_seen_secs; | 412 | int last_seen_secs; |
412 | int last_seen_msecs; | 413 | int last_seen_msecs; |
413 | int i; | 414 | int i, ret = 0; |
415 | |||
416 | primary_if = primary_if_get_selected(bat_priv); | ||
414 | 417 | ||
415 | if ((!bat_priv->primary_if) || | 418 | if (!primary_if) { |
416 | (bat_priv->primary_if->if_status != IF_ACTIVE)) { | 419 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " |
417 | if (!bat_priv->primary_if) | 420 | "please specify interfaces to enable it\n", |
418 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 421 | net_dev->name); |
419 | "please specify interfaces to enable it\n", | 422 | goto out; |
420 | net_dev->name); | 423 | } |
421 | 424 | ||
422 | return seq_printf(seq, "BATMAN mesh %s " | 425 | if (primary_if->if_status != IF_ACTIVE) { |
423 | "disabled - primary interface not active\n", | 426 | ret = seq_printf(seq, "BATMAN mesh %s " |
424 | net_dev->name); | 427 | "disabled - primary interface not active\n", |
428 | net_dev->name); | ||
429 | goto out; | ||
425 | } | 430 | } |
426 | 431 | ||
427 | seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", | 432 | seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", |
428 | SOURCE_VERSION, REVISION_VERSION_STR, | 433 | SOURCE_VERSION, REVISION_VERSION_STR, |
429 | bat_priv->primary_if->net_dev->name, | 434 | primary_if->net_dev->name, |
430 | bat_priv->primary_if->net_dev->dev_addr, net_dev->name); | 435 | primary_if->net_dev->dev_addr, net_dev->name); |
431 | seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", | 436 | seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", |
432 | "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", | 437 | "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", |
433 | "outgoingIF", "Potential nexthops"); | 438 | "outgoingIF", "Potential nexthops"); |
@@ -474,7 +479,10 @@ next: | |||
474 | if (batman_count == 0) | 479 | if (batman_count == 0) |
475 | seq_printf(seq, "No batman nodes in range ...\n"); | 480 | seq_printf(seq, "No batman nodes in range ...\n"); |
476 | 481 | ||
477 | return 0; | 482 | out: |
483 | if (primary_if) | ||
484 | hardif_free_ref(primary_if); | ||
485 | return ret; | ||
478 | } | 486 | } |
479 | 487 | ||
480 | static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) | 488 | static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) |
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 2d77bd3a3e9a..49f571553050 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c | |||
@@ -904,6 +904,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface) | |||
904 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, | 904 | static int recv_my_icmp_packet(struct bat_priv *bat_priv, |
905 | struct sk_buff *skb, size_t icmp_len) | 905 | struct sk_buff *skb, size_t icmp_len) |
906 | { | 906 | { |
907 | struct hard_iface *primary_if = NULL; | ||
907 | struct orig_node *orig_node = NULL; | 908 | struct orig_node *orig_node = NULL; |
908 | struct neigh_node *router = NULL; | 909 | struct neigh_node *router = NULL; |
909 | struct icmp_packet_rr *icmp_packet; | 910 | struct icmp_packet_rr *icmp_packet; |
@@ -917,7 +918,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, | |||
917 | goto out; | 918 | goto out; |
918 | } | 919 | } |
919 | 920 | ||
920 | if (!bat_priv->primary_if) | 921 | primary_if = primary_if_get_selected(bat_priv); |
922 | if (!primary_if) | ||
921 | goto out; | 923 | goto out; |
922 | 924 | ||
923 | /* answer echo request (ping) */ | 925 | /* answer echo request (ping) */ |
@@ -937,8 +939,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, | |||
937 | icmp_packet = (struct icmp_packet_rr *)skb->data; | 939 | icmp_packet = (struct icmp_packet_rr *)skb->data; |
938 | 940 | ||
939 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 941 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); |
940 | memcpy(icmp_packet->orig, | 942 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
941 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
942 | icmp_packet->msg_type = ECHO_REPLY; | 943 | icmp_packet->msg_type = ECHO_REPLY; |
943 | icmp_packet->ttl = TTL; | 944 | icmp_packet->ttl = TTL; |
944 | 945 | ||
@@ -946,6 +947,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, | |||
946 | ret = NET_RX_SUCCESS; | 947 | ret = NET_RX_SUCCESS; |
947 | 948 | ||
948 | out: | 949 | out: |
950 | if (primary_if) | ||
951 | hardif_free_ref(primary_if); | ||
949 | if (router) | 952 | if (router) |
950 | neigh_node_free_ref(router); | 953 | neigh_node_free_ref(router); |
951 | if (orig_node) | 954 | if (orig_node) |
@@ -956,6 +959,7 @@ out: | |||
956 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | 959 | static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, |
957 | struct sk_buff *skb) | 960 | struct sk_buff *skb) |
958 | { | 961 | { |
962 | struct hard_iface *primary_if = NULL; | ||
959 | struct orig_node *orig_node = NULL; | 963 | struct orig_node *orig_node = NULL; |
960 | struct neigh_node *router = NULL; | 964 | struct neigh_node *router = NULL; |
961 | struct icmp_packet *icmp_packet; | 965 | struct icmp_packet *icmp_packet; |
@@ -971,7 +975,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | |||
971 | goto out; | 975 | goto out; |
972 | } | 976 | } |
973 | 977 | ||
974 | if (!bat_priv->primary_if) | 978 | primary_if = primary_if_get_selected(bat_priv); |
979 | if (!primary_if) | ||
975 | goto out; | 980 | goto out; |
976 | 981 | ||
977 | /* get routing information */ | 982 | /* get routing information */ |
@@ -990,8 +995,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | |||
990 | icmp_packet = (struct icmp_packet *)skb->data; | 995 | icmp_packet = (struct icmp_packet *)skb->data; |
991 | 996 | ||
992 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); | 997 | memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); |
993 | memcpy(icmp_packet->orig, | 998 | memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
994 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | ||
995 | icmp_packet->msg_type = TTL_EXCEEDED; | 999 | icmp_packet->msg_type = TTL_EXCEEDED; |
996 | icmp_packet->ttl = TTL; | 1000 | icmp_packet->ttl = TTL; |
997 | 1001 | ||
@@ -999,6 +1003,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, | |||
999 | ret = NET_RX_SUCCESS; | 1003 | ret = NET_RX_SUCCESS; |
1000 | 1004 | ||
1001 | out: | 1005 | out: |
1006 | if (primary_if) | ||
1007 | hardif_free_ref(primary_if); | ||
1002 | if (router) | 1008 | if (router) |
1003 | neigh_node_free_ref(router); | 1009 | neigh_node_free_ref(router); |
1004 | if (orig_node) | 1010 | if (orig_node) |
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 7650e2bf187d..02b541a6dfef 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c | |||
@@ -244,6 +244,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, | |||
244 | void schedule_own_packet(struct hard_iface *hard_iface) | 244 | void schedule_own_packet(struct hard_iface *hard_iface) |
245 | { | 245 | { |
246 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); | 246 | struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); |
247 | struct hard_iface *primary_if; | ||
247 | unsigned long send_time; | 248 | unsigned long send_time; |
248 | struct batman_packet *batman_packet; | 249 | struct batman_packet *batman_packet; |
249 | int vis_server; | 250 | int vis_server; |
@@ -253,6 +254,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) | |||
253 | return; | 254 | return; |
254 | 255 | ||
255 | vis_server = atomic_read(&bat_priv->vis_mode); | 256 | vis_server = atomic_read(&bat_priv->vis_mode); |
257 | primary_if = primary_if_get_selected(bat_priv); | ||
256 | 258 | ||
257 | /** | 259 | /** |
258 | * the interface gets activated here to avoid race conditions between | 260 | * the interface gets activated here to avoid race conditions between |
@@ -266,7 +268,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) | |||
266 | 268 | ||
267 | /* if local hna has changed and interface is a primary interface */ | 269 | /* if local hna has changed and interface is a primary interface */ |
268 | if ((atomic_read(&bat_priv->hna_local_changed)) && | 270 | if ((atomic_read(&bat_priv->hna_local_changed)) && |
269 | (hard_iface == bat_priv->primary_if)) | 271 | (hard_iface == primary_if)) |
270 | rebuild_batman_packet(bat_priv, hard_iface); | 272 | rebuild_batman_packet(bat_priv, hard_iface); |
271 | 273 | ||
272 | /** | 274 | /** |
@@ -284,7 +286,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) | |||
284 | else | 286 | else |
285 | batman_packet->flags &= ~VIS_SERVER; | 287 | batman_packet->flags &= ~VIS_SERVER; |
286 | 288 | ||
287 | if ((hard_iface == bat_priv->primary_if) && | 289 | if ((hard_iface == primary_if) && |
288 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) | 290 | (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) |
289 | batman_packet->gw_flags = | 291 | batman_packet->gw_flags = |
290 | (uint8_t)atomic_read(&bat_priv->gw_bandwidth); | 292 | (uint8_t)atomic_read(&bat_priv->gw_bandwidth); |
@@ -299,6 +301,9 @@ void schedule_own_packet(struct hard_iface *hard_iface) | |||
299 | hard_iface->packet_buff, | 301 | hard_iface->packet_buff, |
300 | hard_iface->packet_len, | 302 | hard_iface->packet_len, |
301 | hard_iface, 1, send_time); | 303 | hard_iface, 1, send_time); |
304 | |||
305 | if (primary_if) | ||
306 | hardif_free_ref(primary_if); | ||
302 | } | 307 | } |
303 | 308 | ||
304 | void schedule_forward_packet(struct orig_node *orig_node, | 309 | void schedule_forward_packet(struct orig_node *orig_node, |
@@ -403,6 +408,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, | |||
403 | * skb is freed. */ | 408 | * skb is freed. */ |
404 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) | 409 | int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) |
405 | { | 410 | { |
411 | struct hard_iface *primary_if = NULL; | ||
406 | struct forw_packet *forw_packet; | 412 | struct forw_packet *forw_packet; |
407 | struct bcast_packet *bcast_packet; | 413 | struct bcast_packet *bcast_packet; |
408 | 414 | ||
@@ -411,7 +417,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) | |||
411 | goto out; | 417 | goto out; |
412 | } | 418 | } |
413 | 419 | ||
414 | if (!bat_priv->primary_if) | 420 | primary_if = primary_if_get_selected(bat_priv); |
421 | if (!primary_if) | ||
415 | goto out; | 422 | goto out; |
416 | 423 | ||
417 | forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); | 424 | forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); |
@@ -430,7 +437,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) | |||
430 | skb_reset_mac_header(skb); | 437 | skb_reset_mac_header(skb); |
431 | 438 | ||
432 | forw_packet->skb = skb; | 439 | forw_packet->skb = skb; |
433 | forw_packet->if_incoming = bat_priv->primary_if; | 440 | forw_packet->if_incoming = primary_if; |
434 | 441 | ||
435 | /* how often did we send the bcast packet ? */ | 442 | /* how often did we send the bcast packet ? */ |
436 | forw_packet->num_packets = 0; | 443 | forw_packet->num_packets = 0; |
@@ -443,6 +450,8 @@ packet_free: | |||
443 | out_and_inc: | 450 | out_and_inc: |
444 | atomic_inc(&bat_priv->bcast_queue_left); | 451 | atomic_inc(&bat_priv->bcast_queue_left); |
445 | out: | 452 | out: |
453 | if (primary_if) | ||
454 | hardif_free_ref(primary_if); | ||
446 | return NETDEV_TX_BUSY; | 455 | return NETDEV_TX_BUSY; |
447 | } | 456 | } |
448 | 457 | ||
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 58ce4400d581..ea5e58c252f0 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -215,13 +215,24 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
215 | struct net_device *net_dev = (struct net_device *)seq->private; | 215 | struct net_device *net_dev = (struct net_device *)seq->private; |
216 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 216 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
217 | struct softif_neigh *softif_neigh; | 217 | struct softif_neigh *softif_neigh; |
218 | struct hard_iface *primary_if; | ||
218 | struct hlist_node *node; | 219 | struct hlist_node *node; |
219 | struct softif_neigh *curr_softif_neigh; | 220 | struct softif_neigh *curr_softif_neigh; |
221 | int ret = 0; | ||
220 | 222 | ||
221 | if (!bat_priv->primary_if) { | 223 | primary_if = primary_if_get_selected(bat_priv); |
222 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 224 | if (!primary_if) { |
223 | "please specify interfaces to enable it\n", | 225 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " |
224 | net_dev->name); | 226 | "please specify interfaces to enable it\n", |
227 | net_dev->name); | ||
228 | goto out; | ||
229 | } | ||
230 | |||
231 | if (primary_if->if_status != IF_ACTIVE) { | ||
232 | ret = seq_printf(seq, "BATMAN mesh %s " | ||
233 | "disabled - primary interface not active\n", | ||
234 | net_dev->name); | ||
235 | goto out; | ||
225 | } | 236 | } |
226 | 237 | ||
227 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | 238 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); |
@@ -238,7 +249,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
238 | if (curr_softif_neigh) | 249 | if (curr_softif_neigh) |
239 | softif_neigh_free_ref(curr_softif_neigh); | 250 | softif_neigh_free_ref(curr_softif_neigh); |
240 | 251 | ||
241 | return 0; | 252 | out: |
253 | if (primary_if) | ||
254 | hardif_free_ref(primary_if); | ||
255 | return ret; | ||
242 | } | 256 | } |
243 | 257 | ||
244 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | 258 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, |
@@ -247,7 +261,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
247 | struct bat_priv *bat_priv = netdev_priv(dev); | 261 | struct bat_priv *bat_priv = netdev_priv(dev); |
248 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 262 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
249 | struct batman_packet *batman_packet; | 263 | struct batman_packet *batman_packet; |
250 | struct softif_neigh *softif_neigh; | 264 | struct softif_neigh *softif_neigh = NULL; |
265 | struct hard_iface *primary_if = NULL; | ||
251 | struct softif_neigh *curr_softif_neigh = NULL; | 266 | struct softif_neigh *curr_softif_neigh = NULL; |
252 | 267 | ||
253 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) | 268 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) |
@@ -257,28 +272,34 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
257 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); | 272 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); |
258 | 273 | ||
259 | if (batman_packet->version != COMPAT_VERSION) | 274 | if (batman_packet->version != COMPAT_VERSION) |
260 | goto err; | 275 | goto out; |
261 | 276 | ||
262 | if (batman_packet->packet_type != BAT_PACKET) | 277 | if (batman_packet->packet_type != BAT_PACKET) |
263 | goto err; | 278 | goto out; |
264 | 279 | ||
265 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) | 280 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) |
266 | goto err; | 281 | goto out; |
267 | 282 | ||
268 | if (is_my_mac(batman_packet->orig)) | 283 | if (is_my_mac(batman_packet->orig)) |
269 | goto err; | 284 | goto out; |
270 | 285 | ||
271 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); | 286 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); |
272 | |||
273 | if (!softif_neigh) | 287 | if (!softif_neigh) |
274 | goto err; | 288 | goto out; |
275 | 289 | ||
276 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); | 290 | curr_softif_neigh = softif_neigh_get_selected(bat_priv); |
291 | if (!curr_softif_neigh) | ||
292 | goto out; | ||
293 | |||
277 | if (curr_softif_neigh == softif_neigh) | 294 | if (curr_softif_neigh == softif_neigh) |
278 | goto out; | 295 | goto out; |
279 | 296 | ||
297 | primary_if = primary_if_get_selected(bat_priv); | ||
298 | if (!primary_if) | ||
299 | goto out; | ||
300 | |||
280 | /* we got a neighbor but its mac is 'bigger' than ours */ | 301 | /* we got a neighbor but its mac is 'bigger' than ours */ |
281 | if (memcmp(bat_priv->primary_if->net_dev->dev_addr, | 302 | if (memcmp(primary_if->net_dev->dev_addr, |
282 | softif_neigh->addr, ETH_ALEN) < 0) | 303 | softif_neigh->addr, ETH_ALEN) < 0) |
283 | goto out; | 304 | goto out; |
284 | 305 | ||
@@ -300,7 +321,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
300 | /* close own batX device and use softif_neigh as exit node */ | 321 | /* close own batX device and use softif_neigh as exit node */ |
301 | if ((!curr_softif_neigh) && | 322 | if ((!curr_softif_neigh) && |
302 | (memcmp(softif_neigh->addr, | 323 | (memcmp(softif_neigh->addr, |
303 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | 324 | primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { |
304 | bat_dbg(DBG_ROUTES, bat_priv, | 325 | bat_dbg(DBG_ROUTES, bat_priv, |
305 | "Setting mesh exit point to %pM (vid: %d).\n", | 326 | "Setting mesh exit point to %pM (vid: %d).\n", |
306 | softif_neigh->addr, softif_neigh->vid); | 327 | softif_neigh->addr, softif_neigh->vid); |
@@ -310,12 +331,13 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
310 | } | 331 | } |
311 | 332 | ||
312 | out: | 333 | out: |
313 | softif_neigh_free_ref(softif_neigh); | ||
314 | err: | ||
315 | kfree_skb(skb); | 334 | kfree_skb(skb); |
335 | if (softif_neigh) | ||
336 | softif_neigh_free_ref(softif_neigh); | ||
316 | if (curr_softif_neigh) | 337 | if (curr_softif_neigh) |
317 | softif_neigh_free_ref(curr_softif_neigh); | 338 | softif_neigh_free_ref(curr_softif_neigh); |
318 | 339 | if (primary_if) | |
340 | hardif_free_ref(primary_if); | ||
319 | return; | 341 | return; |
320 | } | 342 | } |
321 | 343 | ||
@@ -371,6 +393,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
371 | { | 393 | { |
372 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 394 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
373 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 395 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
396 | struct hard_iface *primary_if = NULL; | ||
374 | struct bcast_packet *bcast_packet; | 397 | struct bcast_packet *bcast_packet; |
375 | struct vlan_ethhdr *vhdr; | 398 | struct vlan_ethhdr *vhdr; |
376 | struct softif_neigh *curr_softif_neigh = NULL; | 399 | struct softif_neigh *curr_softif_neigh = NULL; |
@@ -420,7 +443,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
420 | 443 | ||
421 | /* ethernet packet should be broadcasted */ | 444 | /* ethernet packet should be broadcasted */ |
422 | if (do_bcast) { | 445 | if (do_bcast) { |
423 | if (!bat_priv->primary_if) | 446 | primary_if = primary_if_get_selected(bat_priv); |
447 | if (!primary_if) | ||
424 | goto dropped; | 448 | goto dropped; |
425 | 449 | ||
426 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) | 450 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) |
@@ -436,7 +460,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
436 | /* hw address of first interface is the orig mac because only | 460 | /* hw address of first interface is the orig mac because only |
437 | * this mac is known throughout the mesh */ | 461 | * this mac is known throughout the mesh */ |
438 | memcpy(bcast_packet->orig, | 462 | memcpy(bcast_packet->orig, |
439 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 463 | primary_if->net_dev->dev_addr, ETH_ALEN); |
440 | 464 | ||
441 | /* set broadcast sequence number */ | 465 | /* set broadcast sequence number */ |
442 | bcast_packet->seqno = | 466 | bcast_packet->seqno = |
@@ -466,6 +490,8 @@ dropped_freed: | |||
466 | end: | 490 | end: |
467 | if (curr_softif_neigh) | 491 | if (curr_softif_neigh) |
468 | softif_neigh_free_ref(curr_softif_neigh); | 492 | softif_neigh_free_ref(curr_softif_neigh); |
493 | if (primary_if) | ||
494 | hardif_free_ref(primary_if); | ||
469 | return NETDEV_TX_OK; | 495 | return NETDEV_TX_OK; |
470 | } | 496 | } |
471 | 497 | ||
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 8d15b48d1692..f931830d630e 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "main.h" | 22 | #include "main.h" |
23 | #include "translation-table.h" | 23 | #include "translation-table.h" |
24 | #include "soft-interface.h" | 24 | #include "soft-interface.h" |
25 | #include "hard-interface.h" | ||
25 | #include "hash.h" | 26 | #include "hash.h" |
26 | #include "originator.h" | 27 | #include "originator.h" |
27 | 28 | ||
@@ -237,16 +238,26 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) | |||
237 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 238 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
238 | struct hashtable_t *hash = bat_priv->hna_local_hash; | 239 | struct hashtable_t *hash = bat_priv->hna_local_hash; |
239 | struct hna_local_entry *hna_local_entry; | 240 | struct hna_local_entry *hna_local_entry; |
241 | struct hard_iface *primary_if; | ||
240 | struct hlist_node *node; | 242 | struct hlist_node *node; |
241 | struct hlist_head *head; | 243 | struct hlist_head *head; |
242 | size_t buf_size, pos; | 244 | size_t buf_size, pos; |
243 | char *buff; | 245 | char *buff; |
244 | int i; | 246 | int i, ret = 0; |
245 | 247 | ||
246 | if (!bat_priv->primary_if) { | 248 | primary_if = primary_if_get_selected(bat_priv); |
247 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 249 | if (!primary_if) { |
248 | "please specify interfaces to enable it\n", | 250 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " |
249 | net_dev->name); | 251 | "please specify interfaces to enable it\n", |
252 | net_dev->name); | ||
253 | goto out; | ||
254 | } | ||
255 | |||
256 | if (primary_if->if_status != IF_ACTIVE) { | ||
257 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " | ||
258 | "primary interface not active\n", | ||
259 | net_dev->name); | ||
260 | goto out; | ||
250 | } | 261 | } |
251 | 262 | ||
252 | seq_printf(seq, "Locally retrieved addresses (from %s) " | 263 | seq_printf(seq, "Locally retrieved addresses (from %s) " |
@@ -269,7 +280,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) | |||
269 | buff = kmalloc(buf_size, GFP_ATOMIC); | 280 | buff = kmalloc(buf_size, GFP_ATOMIC); |
270 | if (!buff) { | 281 | if (!buff) { |
271 | spin_unlock_bh(&bat_priv->hna_lhash_lock); | 282 | spin_unlock_bh(&bat_priv->hna_lhash_lock); |
272 | return -ENOMEM; | 283 | ret = -ENOMEM; |
284 | goto out; | ||
273 | } | 285 | } |
274 | 286 | ||
275 | buff[0] = '\0'; | 287 | buff[0] = '\0'; |
@@ -291,7 +303,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) | |||
291 | 303 | ||
292 | seq_printf(seq, "%s", buff); | 304 | seq_printf(seq, "%s", buff); |
293 | kfree(buff); | 305 | kfree(buff); |
294 | return 0; | 306 | out: |
307 | if (primary_if) | ||
308 | hardif_free_ref(primary_if); | ||
309 | return ret; | ||
295 | } | 310 | } |
296 | 311 | ||
297 | static void _hna_local_del(struct hlist_node *node, void *arg) | 312 | static void _hna_local_del(struct hlist_node *node, void *arg) |
@@ -468,16 +483,26 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) | |||
468 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 483 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
469 | struct hashtable_t *hash = bat_priv->hna_global_hash; | 484 | struct hashtable_t *hash = bat_priv->hna_global_hash; |
470 | struct hna_global_entry *hna_global_entry; | 485 | struct hna_global_entry *hna_global_entry; |
486 | struct hard_iface *primary_if; | ||
471 | struct hlist_node *node; | 487 | struct hlist_node *node; |
472 | struct hlist_head *head; | 488 | struct hlist_head *head; |
473 | size_t buf_size, pos; | 489 | size_t buf_size, pos; |
474 | char *buff; | 490 | char *buff; |
475 | int i; | 491 | int i, ret = 0; |
476 | 492 | ||
477 | if (!bat_priv->primary_if) { | 493 | primary_if = primary_if_get_selected(bat_priv); |
478 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 494 | if (!primary_if) { |
479 | "please specify interfaces to enable it\n", | 495 | ret = seq_printf(seq, "BATMAN mesh %s disabled - please " |
480 | net_dev->name); | 496 | "specify interfaces to enable it\n", |
497 | net_dev->name); | ||
498 | goto out; | ||
499 | } | ||
500 | |||
501 | if (primary_if->if_status != IF_ACTIVE) { | ||
502 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " | ||
503 | "primary interface not active\n", | ||
504 | net_dev->name); | ||
505 | goto out; | ||
481 | } | 506 | } |
482 | 507 | ||
483 | seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", | 508 | seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", |
@@ -499,7 +524,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) | |||
499 | buff = kmalloc(buf_size, GFP_ATOMIC); | 524 | buff = kmalloc(buf_size, GFP_ATOMIC); |
500 | if (!buff) { | 525 | if (!buff) { |
501 | spin_unlock_bh(&bat_priv->hna_ghash_lock); | 526 | spin_unlock_bh(&bat_priv->hna_ghash_lock); |
502 | return -ENOMEM; | 527 | ret = -ENOMEM; |
528 | goto out; | ||
503 | } | 529 | } |
504 | buff[0] = '\0'; | 530 | buff[0] = '\0'; |
505 | pos = 0; | 531 | pos = 0; |
@@ -522,7 +548,10 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) | |||
522 | 548 | ||
523 | seq_printf(seq, "%s", buff); | 549 | seq_printf(seq, "%s", buff); |
524 | kfree(buff); | 550 | kfree(buff); |
525 | return 0; | 551 | out: |
552 | if (primary_if) | ||
553 | hardif_free_ref(primary_if); | ||
554 | return ret; | ||
526 | } | 555 | } |
527 | 556 | ||
528 | static void _hna_global_del_orig(struct bat_priv *bat_priv, | 557 | static void _hna_global_del_orig(struct bat_priv *bat_priv, |
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 75123b1ae0de..947bafc6431a 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h | |||
@@ -149,7 +149,6 @@ struct bat_priv { | |||
149 | struct hlist_head softif_neigh_list; | 149 | struct hlist_head softif_neigh_list; |
150 | struct softif_neigh __rcu *softif_neigh; | 150 | struct softif_neigh __rcu *softif_neigh; |
151 | struct debug_log *debug_log; | 151 | struct debug_log *debug_log; |
152 | struct hard_iface *primary_if; | ||
153 | struct kobject *mesh_obj; | 152 | struct kobject *mesh_obj; |
154 | struct dentry *debug_dir; | 153 | struct dentry *debug_dir; |
155 | struct hlist_head forw_bat_list; | 154 | struct hlist_head forw_bat_list; |
@@ -174,6 +173,7 @@ struct bat_priv { | |||
174 | struct delayed_work orig_work; | 173 | struct delayed_work orig_work; |
175 | struct delayed_work vis_work; | 174 | struct delayed_work vis_work; |
176 | struct gw_node __rcu *curr_gw; /* rcu protected pointer */ | 175 | struct gw_node __rcu *curr_gw; /* rcu protected pointer */ |
176 | struct hard_iface __rcu *primary_if; /* rcu protected pointer */ | ||
177 | struct vis_info *my_vis_info; | 177 | struct vis_info *my_vis_info; |
178 | }; | 178 | }; |
179 | 179 | ||
diff --git a/net/batman-adv/unicast.c b/net/batman-adv/unicast.c index d46acc815138..b46cbf1507e4 100644 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c | |||
@@ -221,15 +221,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | |||
221 | struct hard_iface *hard_iface, uint8_t dstaddr[]) | 221 | struct hard_iface *hard_iface, uint8_t dstaddr[]) |
222 | { | 222 | { |
223 | struct unicast_packet tmp_uc, *unicast_packet; | 223 | struct unicast_packet tmp_uc, *unicast_packet; |
224 | struct hard_iface *primary_if; | ||
224 | struct sk_buff *frag_skb; | 225 | struct sk_buff *frag_skb; |
225 | struct unicast_frag_packet *frag1, *frag2; | 226 | struct unicast_frag_packet *frag1, *frag2; |
226 | int uc_hdr_len = sizeof(struct unicast_packet); | 227 | int uc_hdr_len = sizeof(struct unicast_packet); |
227 | int ucf_hdr_len = sizeof(struct unicast_frag_packet); | 228 | int ucf_hdr_len = sizeof(struct unicast_frag_packet); |
228 | int data_len = skb->len - uc_hdr_len; | 229 | int data_len = skb->len - uc_hdr_len; |
229 | int large_tail = 0; | 230 | int large_tail = 0, ret = NET_RX_DROP; |
230 | uint16_t seqno; | 231 | uint16_t seqno; |
231 | 232 | ||
232 | if (!bat_priv->primary_if) | 233 | primary_if = primary_if_get_selected(bat_priv); |
234 | if (!primary_if) | ||
233 | goto dropped; | 235 | goto dropped; |
234 | 236 | ||
235 | frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); | 237 | frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); |
@@ -254,7 +256,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | |||
254 | frag1->version = COMPAT_VERSION; | 256 | frag1->version = COMPAT_VERSION; |
255 | frag1->packet_type = BAT_UNICAST_FRAG; | 257 | frag1->packet_type = BAT_UNICAST_FRAG; |
256 | 258 | ||
257 | memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 259 | memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
258 | memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); | 260 | memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); |
259 | 261 | ||
260 | if (data_len & 1) | 262 | if (data_len & 1) |
@@ -269,13 +271,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, | |||
269 | 271 | ||
270 | send_skb_packet(skb, hard_iface, dstaddr); | 272 | send_skb_packet(skb, hard_iface, dstaddr); |
271 | send_skb_packet(frag_skb, hard_iface, dstaddr); | 273 | send_skb_packet(frag_skb, hard_iface, dstaddr); |
272 | return NET_RX_SUCCESS; | 274 | ret = NET_RX_SUCCESS; |
275 | goto out; | ||
273 | 276 | ||
274 | drop_frag: | 277 | drop_frag: |
275 | kfree_skb(frag_skb); | 278 | kfree_skb(frag_skb); |
276 | dropped: | 279 | dropped: |
277 | kfree_skb(skb); | 280 | kfree_skb(skb); |
278 | return NET_RX_DROP; | 281 | out: |
282 | if (primary_if) | ||
283 | hardif_free_ref(primary_if); | ||
284 | return ret; | ||
279 | } | 285 | } |
280 | 286 | ||
281 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) | 287 | int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) |
diff --git a/net/batman-adv/vis.c b/net/batman-adv/vis.c index d4cc4f5399f4..c8f571d3b5d4 100644 --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c | |||
@@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, | |||
204 | 204 | ||
205 | int vis_seq_print_text(struct seq_file *seq, void *offset) | 205 | int vis_seq_print_text(struct seq_file *seq, void *offset) |
206 | { | 206 | { |
207 | struct hard_iface *primary_if; | ||
207 | struct hlist_node *node; | 208 | struct hlist_node *node; |
208 | struct hlist_head *head; | 209 | struct hlist_head *head; |
209 | struct vis_info *info; | 210 | struct vis_info *info; |
@@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
215 | HLIST_HEAD(vis_if_list); | 216 | HLIST_HEAD(vis_if_list); |
216 | struct if_list_entry *entry; | 217 | struct if_list_entry *entry; |
217 | struct hlist_node *pos, *n; | 218 | struct hlist_node *pos, *n; |
218 | int i, j; | 219 | int i, j, ret = 0; |
219 | int vis_server = atomic_read(&bat_priv->vis_mode); | 220 | int vis_server = atomic_read(&bat_priv->vis_mode); |
220 | size_t buff_pos, buf_size; | 221 | size_t buff_pos, buf_size; |
221 | char *buff; | 222 | char *buff; |
222 | int compare; | 223 | int compare; |
223 | 224 | ||
224 | if ((!bat_priv->primary_if) || | 225 | primary_if = primary_if_get_selected(bat_priv); |
225 | (vis_server == VIS_TYPE_CLIENT_UPDATE)) | 226 | if (!primary_if) |
226 | return 0; | 227 | goto out; |
228 | |||
229 | if (vis_server == VIS_TYPE_CLIENT_UPDATE) | ||
230 | goto out; | ||
227 | 231 | ||
228 | buf_size = 1; | 232 | buf_size = 1; |
229 | /* Estimate length */ | 233 | /* Estimate length */ |
@@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
270 | buff = kmalloc(buf_size, GFP_ATOMIC); | 274 | buff = kmalloc(buf_size, GFP_ATOMIC); |
271 | if (!buff) { | 275 | if (!buff) { |
272 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 276 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
273 | return -ENOMEM; | 277 | ret = -ENOMEM; |
278 | goto out; | ||
274 | } | 279 | } |
275 | buff[0] = '\0'; | 280 | buff[0] = '\0'; |
276 | buff_pos = 0; | 281 | buff_pos = 0; |
@@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) | |||
328 | seq_printf(seq, "%s", buff); | 333 | seq_printf(seq, "%s", buff); |
329 | kfree(buff); | 334 | kfree(buff); |
330 | 335 | ||
331 | return 0; | 336 | out: |
337 | if (primary_if) | ||
338 | hardif_free_ref(primary_if); | ||
339 | return ret; | ||
332 | } | 340 | } |
333 | 341 | ||
334 | /* add the info packet to the send list, if it was not | 342 | /* add the info packet to the send list, if it was not |
@@ -815,16 +823,20 @@ out: | |||
815 | /* only send one vis packet. called from send_vis_packets() */ | 823 | /* only send one vis packet. called from send_vis_packets() */ |
816 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | 824 | static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) |
817 | { | 825 | { |
826 | struct hard_iface *primary_if; | ||
818 | struct vis_packet *packet; | 827 | struct vis_packet *packet; |
819 | 828 | ||
829 | primary_if = primary_if_get_selected(bat_priv); | ||
830 | if (!primary_if) | ||
831 | goto out; | ||
832 | |||
820 | packet = (struct vis_packet *)info->skb_packet->data; | 833 | packet = (struct vis_packet *)info->skb_packet->data; |
821 | if (packet->ttl < 2) { | 834 | if (packet->ttl < 2) { |
822 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); | 835 | pr_debug("Error - can't send vis packet: ttl exceeded\n"); |
823 | return; | 836 | goto out; |
824 | } | 837 | } |
825 | 838 | ||
826 | memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, | 839 | memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); |
827 | ETH_ALEN); | ||
828 | packet->ttl--; | 840 | packet->ttl--; |
829 | 841 | ||
830 | if (is_broadcast_ether_addr(packet->target_orig)) | 842 | if (is_broadcast_ether_addr(packet->target_orig)) |
@@ -832,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) | |||
832 | else | 844 | else |
833 | unicast_vis_packet(bat_priv, info); | 845 | unicast_vis_packet(bat_priv, info); |
834 | packet->ttl++; /* restore TTL */ | 846 | packet->ttl++; /* restore TTL */ |
847 | |||
848 | out: | ||
849 | if (primary_if) | ||
850 | hardif_free_ref(primary_if); | ||
835 | } | 851 | } |
836 | 852 | ||
837 | /* called from timer; send (and maybe generate) vis packet. */ | 853 | /* called from timer; send (and maybe generate) vis packet. */ |
@@ -858,8 +874,7 @@ static void send_vis_packets(struct work_struct *work) | |||
858 | kref_get(&info->refcount); | 874 | kref_get(&info->refcount); |
859 | spin_unlock_bh(&bat_priv->vis_hash_lock); | 875 | spin_unlock_bh(&bat_priv->vis_hash_lock); |
860 | 876 | ||
861 | if (bat_priv->primary_if) | 877 | send_vis_packet(bat_priv, info); |
862 | send_vis_packet(bat_priv, info); | ||
863 | 878 | ||
864 | spin_lock_bh(&bat_priv->vis_hash_lock); | 879 | spin_lock_bh(&bat_priv->vis_hash_lock); |
865 | send_list_del(info); | 880 | send_list_del(info); |