diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 79 |
1 files changed, 34 insertions, 45 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e89ede192ed0..824e1f6e50f2 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors: | 2 | * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: |
3 | * | 3 | * |
4 | * Marek Lindner, Simon Wunderlich | 4 | * Marek Lindner, Simon Wunderlich |
5 | * | 5 | * |
@@ -26,18 +26,15 @@ | |||
26 | #include "send.h" | 26 | #include "send.h" |
27 | #include "bat_debugfs.h" | 27 | #include "bat_debugfs.h" |
28 | #include "translation-table.h" | 28 | #include "translation-table.h" |
29 | #include "types.h" | ||
30 | #include "hash.h" | 29 | #include "hash.h" |
31 | #include "gateway_common.h" | 30 | #include "gateway_common.h" |
32 | #include "gateway_client.h" | 31 | #include "gateway_client.h" |
33 | #include "send.h" | ||
34 | #include "bat_sysfs.h" | 32 | #include "bat_sysfs.h" |
35 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
36 | #include <linux/ethtool.h> | 34 | #include <linux/ethtool.h> |
37 | #include <linux/etherdevice.h> | 35 | #include <linux/etherdevice.h> |
38 | #include <linux/if_vlan.h> | 36 | #include <linux/if_vlan.h> |
39 | #include "unicast.h" | 37 | #include "unicast.h" |
40 | #include "routing.h" | ||
41 | 38 | ||
42 | 39 | ||
43 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); | 40 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); |
@@ -79,20 +76,18 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) | |||
79 | return 0; | 76 | return 0; |
80 | } | 77 | } |
81 | 78 | ||
82 | static void softif_neigh_free_ref(struct kref *refcount) | 79 | static void softif_neigh_free_rcu(struct rcu_head *rcu) |
83 | { | 80 | { |
84 | struct softif_neigh *softif_neigh; | 81 | struct softif_neigh *softif_neigh; |
85 | 82 | ||
86 | softif_neigh = container_of(refcount, struct softif_neigh, refcount); | 83 | softif_neigh = container_of(rcu, struct softif_neigh, rcu); |
87 | kfree(softif_neigh); | 84 | kfree(softif_neigh); |
88 | } | 85 | } |
89 | 86 | ||
90 | static void softif_neigh_free_rcu(struct rcu_head *rcu) | 87 | static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) |
91 | { | 88 | { |
92 | struct softif_neigh *softif_neigh; | 89 | if (atomic_dec_and_test(&softif_neigh->refcount)) |
93 | 90 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | |
94 | softif_neigh = container_of(rcu, struct softif_neigh, rcu); | ||
95 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
96 | } | 91 | } |
97 | 92 | ||
98 | void softif_neigh_purge(struct bat_priv *bat_priv) | 93 | void softif_neigh_purge(struct bat_priv *bat_priv) |
@@ -119,11 +114,10 @@ void softif_neigh_purge(struct bat_priv *bat_priv) | |||
119 | softif_neigh->addr, softif_neigh->vid); | 114 | softif_neigh->addr, softif_neigh->vid); |
120 | softif_neigh_tmp = bat_priv->softif_neigh; | 115 | softif_neigh_tmp = bat_priv->softif_neigh; |
121 | bat_priv->softif_neigh = NULL; | 116 | bat_priv->softif_neigh = NULL; |
122 | kref_put(&softif_neigh_tmp->refcount, | 117 | softif_neigh_free_ref(softif_neigh_tmp); |
123 | softif_neigh_free_ref); | ||
124 | } | 118 | } |
125 | 119 | ||
126 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | 120 | softif_neigh_free_ref(softif_neigh); |
127 | } | 121 | } |
128 | 122 | ||
129 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 123 | spin_unlock_bh(&bat_priv->softif_neigh_lock); |
@@ -138,14 +132,17 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | |||
138 | rcu_read_lock(); | 132 | rcu_read_lock(); |
139 | hlist_for_each_entry_rcu(softif_neigh, node, | 133 | hlist_for_each_entry_rcu(softif_neigh, node, |
140 | &bat_priv->softif_neigh_list, list) { | 134 | &bat_priv->softif_neigh_list, list) { |
141 | if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) | 135 | if (!compare_eth(softif_neigh->addr, addr)) |
142 | continue; | 136 | continue; |
143 | 137 | ||
144 | if (softif_neigh->vid != vid) | 138 | if (softif_neigh->vid != vid) |
145 | continue; | 139 | continue; |
146 | 140 | ||
141 | if (!atomic_inc_not_zero(&softif_neigh->refcount)) | ||
142 | continue; | ||
143 | |||
147 | softif_neigh->last_seen = jiffies; | 144 | softif_neigh->last_seen = jiffies; |
148 | goto found; | 145 | goto out; |
149 | } | 146 | } |
150 | 147 | ||
151 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); | 148 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); |
@@ -155,15 +152,14 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | |||
155 | memcpy(softif_neigh->addr, addr, ETH_ALEN); | 152 | memcpy(softif_neigh->addr, addr, ETH_ALEN); |
156 | softif_neigh->vid = vid; | 153 | softif_neigh->vid = vid; |
157 | softif_neigh->last_seen = jiffies; | 154 | softif_neigh->last_seen = jiffies; |
158 | kref_init(&softif_neigh->refcount); | 155 | /* initialize with 2 - caller decrements counter by one */ |
156 | atomic_set(&softif_neigh->refcount, 2); | ||
159 | 157 | ||
160 | INIT_HLIST_NODE(&softif_neigh->list); | 158 | INIT_HLIST_NODE(&softif_neigh->list); |
161 | spin_lock_bh(&bat_priv->softif_neigh_lock); | 159 | spin_lock_bh(&bat_priv->softif_neigh_lock); |
162 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); | 160 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); |
163 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 161 | spin_unlock_bh(&bat_priv->softif_neigh_lock); |
164 | 162 | ||
165 | found: | ||
166 | kref_get(&softif_neigh->refcount); | ||
167 | out: | 163 | out: |
168 | rcu_read_unlock(); | 164 | rcu_read_unlock(); |
169 | return softif_neigh; | 165 | return softif_neigh; |
@@ -175,8 +171,6 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
175 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 171 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
176 | struct softif_neigh *softif_neigh; | 172 | struct softif_neigh *softif_neigh; |
177 | struct hlist_node *node; | 173 | struct hlist_node *node; |
178 | size_t buf_size, pos; | ||
179 | char *buff; | ||
180 | 174 | ||
181 | if (!bat_priv->primary_if) { | 175 | if (!bat_priv->primary_if) { |
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 176 | return seq_printf(seq, "BATMAN mesh %s disabled - " |
@@ -186,33 +180,15 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | |||
186 | 180 | ||
187 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | 181 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); |
188 | 182 | ||
189 | buf_size = 1; | ||
190 | /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ | ||
191 | rcu_read_lock(); | 183 | rcu_read_lock(); |
192 | hlist_for_each_entry_rcu(softif_neigh, node, | 184 | hlist_for_each_entry_rcu(softif_neigh, node, |
193 | &bat_priv->softif_neigh_list, list) | 185 | &bat_priv->softif_neigh_list, list) |
194 | buf_size += 30; | 186 | seq_printf(seq, "%s %pM (vid: %d)\n", |
195 | rcu_read_unlock(); | ||
196 | |||
197 | buff = kmalloc(buf_size, GFP_ATOMIC); | ||
198 | if (!buff) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | buff[0] = '\0'; | ||
202 | pos = 0; | ||
203 | |||
204 | rcu_read_lock(); | ||
205 | hlist_for_each_entry_rcu(softif_neigh, node, | ||
206 | &bat_priv->softif_neigh_list, list) { | ||
207 | pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", | ||
208 | bat_priv->softif_neigh == softif_neigh | 187 | bat_priv->softif_neigh == softif_neigh |
209 | ? "=>" : " ", softif_neigh->addr, | 188 | ? "=>" : " ", softif_neigh->addr, |
210 | softif_neigh->vid); | 189 | softif_neigh->vid); |
211 | } | ||
212 | rcu_read_unlock(); | 190 | rcu_read_unlock(); |
213 | 191 | ||
214 | seq_printf(seq, "%s", buff); | ||
215 | kfree(buff); | ||
216 | return 0; | 192 | return 0; |
217 | } | 193 | } |
218 | 194 | ||
@@ -267,7 +243,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
267 | softif_neigh->addr, softif_neigh->vid); | 243 | softif_neigh->addr, softif_neigh->vid); |
268 | softif_neigh_tmp = bat_priv->softif_neigh; | 244 | softif_neigh_tmp = bat_priv->softif_neigh; |
269 | bat_priv->softif_neigh = softif_neigh; | 245 | bat_priv->softif_neigh = softif_neigh; |
270 | kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); | 246 | softif_neigh_free_ref(softif_neigh_tmp); |
271 | /* we need to hold the additional reference */ | 247 | /* we need to hold the additional reference */ |
272 | goto err; | 248 | goto err; |
273 | } | 249 | } |
@@ -285,7 +261,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
285 | } | 261 | } |
286 | 262 | ||
287 | out: | 263 | out: |
288 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | 264 | softif_neigh_free_ref(softif_neigh); |
289 | err: | 265 | err: |
290 | kfree_skb(skb); | 266 | kfree_skb(skb); |
291 | return; | 267 | return; |
@@ -438,7 +414,7 @@ end: | |||
438 | } | 414 | } |
439 | 415 | ||
440 | void interface_rx(struct net_device *soft_iface, | 416 | void interface_rx(struct net_device *soft_iface, |
441 | struct sk_buff *skb, struct batman_if *recv_if, | 417 | struct sk_buff *skb, struct hard_iface *recv_if, |
442 | int hdr_size) | 418 | int hdr_size) |
443 | { | 419 | { |
444 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 420 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
@@ -486,7 +462,7 @@ void interface_rx(struct net_device *soft_iface, | |||
486 | 462 | ||
487 | memcpy(unicast_packet->dest, | 463 | memcpy(unicast_packet->dest, |
488 | bat_priv->softif_neigh->addr, ETH_ALEN); | 464 | bat_priv->softif_neigh->addr, ETH_ALEN); |
489 | ret = route_unicast_packet(skb, recv_if, hdr_size); | 465 | ret = route_unicast_packet(skb, recv_if); |
490 | if (ret == NET_RX_DROP) | 466 | if (ret == NET_RX_DROP) |
491 | goto dropped; | 467 | goto dropped; |
492 | 468 | ||
@@ -498,7 +474,7 @@ void interface_rx(struct net_device *soft_iface, | |||
498 | goto dropped; | 474 | goto dropped; |
499 | skb->protocol = eth_type_trans(skb, soft_iface); | 475 | skb->protocol = eth_type_trans(skb, soft_iface); |
500 | 476 | ||
501 | /* should not be neccesary anymore as we use skb_pull_rcsum() | 477 | /* should not be necessary anymore as we use skb_pull_rcsum() |
502 | * TODO: please verify this and remove this TODO | 478 | * TODO: please verify this and remove this TODO |
503 | * -- Dec 21st 2009, Simon Wunderlich */ | 479 | * -- Dec 21st 2009, Simon Wunderlich */ |
504 | 480 | ||
@@ -646,6 +622,19 @@ void softif_destroy(struct net_device *soft_iface) | |||
646 | unregister_netdevice(soft_iface); | 622 | unregister_netdevice(soft_iface); |
647 | } | 623 | } |
648 | 624 | ||
625 | int softif_is_valid(struct net_device *net_dev) | ||
626 | { | ||
627 | #ifdef HAVE_NET_DEVICE_OPS | ||
628 | if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) | ||
629 | return 1; | ||
630 | #else | ||
631 | if (net_dev->hard_start_xmit == interface_tx) | ||
632 | return 1; | ||
633 | #endif | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
649 | /* ethtool */ | 638 | /* ethtool */ |
650 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 639 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
651 | { | 640 | { |