diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 512 |
1 files changed, 371 insertions, 141 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index e89ede192ed0..d5aa60999e83 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); |
@@ -46,8 +43,6 @@ static void bat_get_drvinfo(struct net_device *dev, | |||
46 | static u32 bat_get_msglevel(struct net_device *dev); | 43 | static u32 bat_get_msglevel(struct net_device *dev); |
47 | static void bat_set_msglevel(struct net_device *dev, u32 value); | 44 | static void bat_set_msglevel(struct net_device *dev, u32 value); |
48 | static u32 bat_get_link(struct net_device *dev); | 45 | static u32 bat_get_link(struct net_device *dev); |
49 | static u32 bat_get_rx_csum(struct net_device *dev); | ||
50 | static int bat_set_rx_csum(struct net_device *dev, u32 data); | ||
51 | 46 | ||
52 | static const struct ethtool_ops bat_ethtool_ops = { | 47 | static const struct ethtool_ops bat_ethtool_ops = { |
53 | .get_settings = bat_get_settings, | 48 | .get_settings = bat_get_settings, |
@@ -55,8 +50,6 @@ static const struct ethtool_ops bat_ethtool_ops = { | |||
55 | .get_msglevel = bat_get_msglevel, | 50 | .get_msglevel = bat_get_msglevel, |
56 | .set_msglevel = bat_set_msglevel, | 51 | .set_msglevel = bat_set_msglevel, |
57 | .get_link = bat_get_link, | 52 | .get_link = bat_get_link, |
58 | .get_rx_csum = bat_get_rx_csum, | ||
59 | .set_rx_csum = bat_set_rx_csum | ||
60 | }; | 53 | }; |
61 | 54 | ||
62 | int my_skb_head_push(struct sk_buff *skb, unsigned int len) | 55 | int my_skb_head_push(struct sk_buff *skb, unsigned int len) |
@@ -79,141 +72,371 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) | |||
79 | return 0; | 72 | return 0; |
80 | } | 73 | } |
81 | 74 | ||
82 | static void softif_neigh_free_ref(struct kref *refcount) | 75 | static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) |
83 | { | 76 | { |
84 | struct softif_neigh *softif_neigh; | 77 | if (atomic_dec_and_test(&softif_neigh->refcount)) |
85 | 78 | kfree_rcu(softif_neigh, rcu); | |
86 | softif_neigh = container_of(refcount, struct softif_neigh, refcount); | ||
87 | kfree(softif_neigh); | ||
88 | } | 79 | } |
89 | 80 | ||
90 | static void softif_neigh_free_rcu(struct rcu_head *rcu) | 81 | static void softif_neigh_vid_free_rcu(struct rcu_head *rcu) |
91 | { | 82 | { |
83 | struct softif_neigh_vid *softif_neigh_vid; | ||
92 | struct softif_neigh *softif_neigh; | 84 | struct softif_neigh *softif_neigh; |
85 | struct hlist_node *node, *node_tmp; | ||
86 | struct bat_priv *bat_priv; | ||
87 | |||
88 | softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu); | ||
89 | bat_priv = softif_neigh_vid->bat_priv; | ||
90 | |||
91 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
92 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | ||
93 | &softif_neigh_vid->softif_neigh_list, list) { | ||
94 | hlist_del_rcu(&softif_neigh->list); | ||
95 | softif_neigh_free_ref(softif_neigh); | ||
96 | } | ||
97 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
93 | 98 | ||
94 | softif_neigh = container_of(rcu, struct softif_neigh, rcu); | 99 | kfree(softif_neigh_vid); |
95 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
96 | } | 100 | } |
97 | 101 | ||
98 | void softif_neigh_purge(struct bat_priv *bat_priv) | 102 | static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid) |
99 | { | 103 | { |
100 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | 104 | if (atomic_dec_and_test(&softif_neigh_vid->refcount)) |
101 | struct hlist_node *node, *node_tmp; | 105 | call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu); |
106 | } | ||
102 | 107 | ||
103 | spin_lock_bh(&bat_priv->softif_neigh_lock); | 108 | static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv, |
109 | short vid) | ||
110 | { | ||
111 | struct softif_neigh_vid *softif_neigh_vid; | ||
112 | struct hlist_node *node; | ||
104 | 113 | ||
105 | hlist_for_each_entry_safe(softif_neigh, node, node_tmp, | 114 | rcu_read_lock(); |
106 | &bat_priv->softif_neigh_list, list) { | 115 | hlist_for_each_entry_rcu(softif_neigh_vid, node, |
116 | &bat_priv->softif_neigh_vids, list) { | ||
117 | if (softif_neigh_vid->vid != vid) | ||
118 | continue; | ||
107 | 119 | ||
108 | if ((!time_after(jiffies, softif_neigh->last_seen + | 120 | if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) |
109 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | ||
110 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | ||
111 | continue; | 121 | continue; |
112 | 122 | ||
113 | hlist_del_rcu(&softif_neigh->list); | 123 | goto out; |
124 | } | ||
114 | 125 | ||
115 | if (bat_priv->softif_neigh == softif_neigh) { | 126 | softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid), |
116 | bat_dbg(DBG_ROUTES, bat_priv, | 127 | GFP_ATOMIC); |
117 | "Current mesh exit point '%pM' vanished " | 128 | if (!softif_neigh_vid) |
118 | "(vid: %d).\n", | 129 | goto out; |
119 | softif_neigh->addr, softif_neigh->vid); | ||
120 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
121 | bat_priv->softif_neigh = NULL; | ||
122 | kref_put(&softif_neigh_tmp->refcount, | ||
123 | softif_neigh_free_ref); | ||
124 | } | ||
125 | 130 | ||
126 | call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); | 131 | softif_neigh_vid->vid = vid; |
127 | } | 132 | softif_neigh_vid->bat_priv = bat_priv; |
128 | 133 | ||
129 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 134 | /* initialize with 2 - caller decrements counter by one */ |
135 | atomic_set(&softif_neigh_vid->refcount, 2); | ||
136 | INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list); | ||
137 | INIT_HLIST_NODE(&softif_neigh_vid->list); | ||
138 | spin_lock_bh(&bat_priv->softif_neigh_vid_lock); | ||
139 | hlist_add_head_rcu(&softif_neigh_vid->list, | ||
140 | &bat_priv->softif_neigh_vids); | ||
141 | spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); | ||
142 | |||
143 | out: | ||
144 | rcu_read_unlock(); | ||
145 | return softif_neigh_vid; | ||
130 | } | 146 | } |
131 | 147 | ||
132 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, | 148 | static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, |
133 | uint8_t *addr, short vid) | 149 | uint8_t *addr, short vid) |
134 | { | 150 | { |
135 | struct softif_neigh *softif_neigh; | 151 | struct softif_neigh_vid *softif_neigh_vid; |
152 | struct softif_neigh *softif_neigh = NULL; | ||
136 | struct hlist_node *node; | 153 | struct hlist_node *node; |
137 | 154 | ||
155 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
156 | if (!softif_neigh_vid) | ||
157 | goto out; | ||
158 | |||
138 | rcu_read_lock(); | 159 | rcu_read_lock(); |
139 | hlist_for_each_entry_rcu(softif_neigh, node, | 160 | hlist_for_each_entry_rcu(softif_neigh, node, |
140 | &bat_priv->softif_neigh_list, list) { | 161 | &softif_neigh_vid->softif_neigh_list, |
141 | if (memcmp(softif_neigh->addr, addr, ETH_ALEN) != 0) | 162 | list) { |
163 | if (!compare_eth(softif_neigh->addr, addr)) | ||
142 | continue; | 164 | continue; |
143 | 165 | ||
144 | if (softif_neigh->vid != vid) | 166 | if (!atomic_inc_not_zero(&softif_neigh->refcount)) |
145 | continue; | 167 | continue; |
146 | 168 | ||
147 | softif_neigh->last_seen = jiffies; | 169 | softif_neigh->last_seen = jiffies; |
148 | goto found; | 170 | goto unlock; |
149 | } | 171 | } |
150 | 172 | ||
151 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); | 173 | softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); |
152 | if (!softif_neigh) | 174 | if (!softif_neigh) |
153 | goto out; | 175 | goto unlock; |
154 | 176 | ||
155 | memcpy(softif_neigh->addr, addr, ETH_ALEN); | 177 | memcpy(softif_neigh->addr, addr, ETH_ALEN); |
156 | softif_neigh->vid = vid; | ||
157 | softif_neigh->last_seen = jiffies; | 178 | softif_neigh->last_seen = jiffies; |
158 | kref_init(&softif_neigh->refcount); | 179 | /* initialize with 2 - caller decrements counter by one */ |
180 | atomic_set(&softif_neigh->refcount, 2); | ||
159 | 181 | ||
160 | INIT_HLIST_NODE(&softif_neigh->list); | 182 | INIT_HLIST_NODE(&softif_neigh->list); |
161 | spin_lock_bh(&bat_priv->softif_neigh_lock); | 183 | spin_lock_bh(&bat_priv->softif_neigh_lock); |
162 | hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); | 184 | hlist_add_head_rcu(&softif_neigh->list, |
185 | &softif_neigh_vid->softif_neigh_list); | ||
163 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | 186 | spin_unlock_bh(&bat_priv->softif_neigh_lock); |
164 | 187 | ||
165 | found: | 188 | unlock: |
166 | kref_get(&softif_neigh->refcount); | 189 | rcu_read_unlock(); |
167 | out: | 190 | out: |
191 | if (softif_neigh_vid) | ||
192 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
193 | return softif_neigh; | ||
194 | } | ||
195 | |||
196 | static struct softif_neigh *softif_neigh_get_selected( | ||
197 | struct softif_neigh_vid *softif_neigh_vid) | ||
198 | { | ||
199 | struct softif_neigh *softif_neigh; | ||
200 | |||
201 | rcu_read_lock(); | ||
202 | softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); | ||
203 | |||
204 | if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount)) | ||
205 | softif_neigh = NULL; | ||
206 | |||
168 | rcu_read_unlock(); | 207 | rcu_read_unlock(); |
169 | return softif_neigh; | 208 | return softif_neigh; |
170 | } | 209 | } |
171 | 210 | ||
211 | static struct softif_neigh *softif_neigh_vid_get_selected( | ||
212 | struct bat_priv *bat_priv, | ||
213 | short vid) | ||
214 | { | ||
215 | struct softif_neigh_vid *softif_neigh_vid; | ||
216 | struct softif_neigh *softif_neigh = NULL; | ||
217 | |||
218 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
219 | if (!softif_neigh_vid) | ||
220 | goto out; | ||
221 | |||
222 | softif_neigh = softif_neigh_get_selected(softif_neigh_vid); | ||
223 | out: | ||
224 | if (softif_neigh_vid) | ||
225 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
226 | return softif_neigh; | ||
227 | } | ||
228 | |||
229 | static void softif_neigh_vid_select(struct bat_priv *bat_priv, | ||
230 | struct softif_neigh *new_neigh, | ||
231 | short vid) | ||
232 | { | ||
233 | struct softif_neigh_vid *softif_neigh_vid; | ||
234 | struct softif_neigh *curr_neigh; | ||
235 | |||
236 | softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); | ||
237 | if (!softif_neigh_vid) | ||
238 | goto out; | ||
239 | |||
240 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
241 | |||
242 | if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) | ||
243 | new_neigh = NULL; | ||
244 | |||
245 | curr_neigh = softif_neigh_vid->softif_neigh; | ||
246 | rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh); | ||
247 | |||
248 | if ((curr_neigh) && (!new_neigh)) | ||
249 | bat_dbg(DBG_ROUTES, bat_priv, | ||
250 | "Removing mesh exit point on vid: %d (prev: %pM).\n", | ||
251 | vid, curr_neigh->addr); | ||
252 | else if ((curr_neigh) && (new_neigh)) | ||
253 | bat_dbg(DBG_ROUTES, bat_priv, | ||
254 | "Changing mesh exit point on vid: %d from %pM " | ||
255 | "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); | ||
256 | else if ((!curr_neigh) && (new_neigh)) | ||
257 | bat_dbg(DBG_ROUTES, bat_priv, | ||
258 | "Setting mesh exit point on vid: %d to %pM.\n", | ||
259 | vid, new_neigh->addr); | ||
260 | |||
261 | if (curr_neigh) | ||
262 | softif_neigh_free_ref(curr_neigh); | ||
263 | |||
264 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
265 | |||
266 | out: | ||
267 | if (softif_neigh_vid) | ||
268 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
269 | } | ||
270 | |||
271 | static void softif_neigh_vid_deselect(struct bat_priv *bat_priv, | ||
272 | struct softif_neigh_vid *softif_neigh_vid) | ||
273 | { | ||
274 | struct softif_neigh *curr_neigh; | ||
275 | struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp; | ||
276 | struct hard_iface *primary_if = NULL; | ||
277 | struct hlist_node *node; | ||
278 | |||
279 | primary_if = primary_if_get_selected(bat_priv); | ||
280 | if (!primary_if) | ||
281 | goto out; | ||
282 | |||
283 | /* find new softif_neigh immediately to avoid temporary loops */ | ||
284 | rcu_read_lock(); | ||
285 | curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); | ||
286 | |||
287 | hlist_for_each_entry_rcu(softif_neigh_tmp, node, | ||
288 | &softif_neigh_vid->softif_neigh_list, | ||
289 | list) { | ||
290 | if (softif_neigh_tmp == curr_neigh) | ||
291 | continue; | ||
292 | |||
293 | /* we got a neighbor but its mac is 'bigger' than ours */ | ||
294 | if (memcmp(primary_if->net_dev->dev_addr, | ||
295 | softif_neigh_tmp->addr, ETH_ALEN) < 0) | ||
296 | continue; | ||
297 | |||
298 | if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount)) | ||
299 | continue; | ||
300 | |||
301 | softif_neigh = softif_neigh_tmp; | ||
302 | goto unlock; | ||
303 | } | ||
304 | |||
305 | unlock: | ||
306 | rcu_read_unlock(); | ||
307 | out: | ||
308 | softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid); | ||
309 | |||
310 | if (primary_if) | ||
311 | hardif_free_ref(primary_if); | ||
312 | if (softif_neigh) | ||
313 | softif_neigh_free_ref(softif_neigh); | ||
314 | } | ||
315 | |||
172 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) | 316 | int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) |
173 | { | 317 | { |
174 | struct net_device *net_dev = (struct net_device *)seq->private; | 318 | struct net_device *net_dev = (struct net_device *)seq->private; |
175 | struct bat_priv *bat_priv = netdev_priv(net_dev); | 319 | struct bat_priv *bat_priv = netdev_priv(net_dev); |
320 | struct softif_neigh_vid *softif_neigh_vid; | ||
176 | struct softif_neigh *softif_neigh; | 321 | struct softif_neigh *softif_neigh; |
177 | struct hlist_node *node; | 322 | struct hard_iface *primary_if; |
178 | size_t buf_size, pos; | 323 | struct hlist_node *node, *node_tmp; |
179 | char *buff; | 324 | struct softif_neigh *curr_softif_neigh; |
325 | int ret = 0, last_seen_secs, last_seen_msecs; | ||
326 | |||
327 | primary_if = primary_if_get_selected(bat_priv); | ||
328 | if (!primary_if) { | ||
329 | ret = seq_printf(seq, "BATMAN mesh %s disabled - " | ||
330 | "please specify interfaces to enable it\n", | ||
331 | net_dev->name); | ||
332 | goto out; | ||
333 | } | ||
180 | 334 | ||
181 | if (!bat_priv->primary_if) { | 335 | if (primary_if->if_status != IF_ACTIVE) { |
182 | return seq_printf(seq, "BATMAN mesh %s disabled - " | 336 | ret = seq_printf(seq, "BATMAN mesh %s " |
183 | "please specify interfaces to enable it\n", | 337 | "disabled - primary interface not active\n", |
184 | net_dev->name); | 338 | net_dev->name); |
339 | goto out; | ||
185 | } | 340 | } |
186 | 341 | ||
187 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); | 342 | seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); |
188 | 343 | ||
189 | buf_size = 1; | ||
190 | /* Estimate length for: " xx:xx:xx:xx:xx:xx\n" */ | ||
191 | rcu_read_lock(); | 344 | rcu_read_lock(); |
192 | hlist_for_each_entry_rcu(softif_neigh, node, | 345 | hlist_for_each_entry_rcu(softif_neigh_vid, node, |
193 | &bat_priv->softif_neigh_list, list) | 346 | &bat_priv->softif_neigh_vids, list) { |
194 | buf_size += 30; | 347 | seq_printf(seq, " %-15s %s on vid: %d\n", |
348 | "Originator", "last-seen", softif_neigh_vid->vid); | ||
349 | |||
350 | curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); | ||
351 | |||
352 | hlist_for_each_entry_rcu(softif_neigh, node_tmp, | ||
353 | &softif_neigh_vid->softif_neigh_list, | ||
354 | list) { | ||
355 | last_seen_secs = jiffies_to_msecs(jiffies - | ||
356 | softif_neigh->last_seen) / 1000; | ||
357 | last_seen_msecs = jiffies_to_msecs(jiffies - | ||
358 | softif_neigh->last_seen) % 1000; | ||
359 | seq_printf(seq, "%s %pM %3i.%03is\n", | ||
360 | curr_softif_neigh == softif_neigh | ||
361 | ? "=>" : " ", softif_neigh->addr, | ||
362 | last_seen_secs, last_seen_msecs); | ||
363 | } | ||
364 | |||
365 | if (curr_softif_neigh) | ||
366 | softif_neigh_free_ref(curr_softif_neigh); | ||
367 | |||
368 | seq_printf(seq, "\n"); | ||
369 | } | ||
195 | rcu_read_unlock(); | 370 | rcu_read_unlock(); |
196 | 371 | ||
197 | buff = kmalloc(buf_size, GFP_ATOMIC); | 372 | out: |
198 | if (!buff) | 373 | if (primary_if) |
199 | return -ENOMEM; | 374 | hardif_free_ref(primary_if); |
375 | return ret; | ||
376 | } | ||
200 | 377 | ||
201 | buff[0] = '\0'; | 378 | void softif_neigh_purge(struct bat_priv *bat_priv) |
202 | pos = 0; | 379 | { |
380 | struct softif_neigh *softif_neigh, *curr_softif_neigh; | ||
381 | struct softif_neigh_vid *softif_neigh_vid; | ||
382 | struct hlist_node *node, *node_tmp, *node_tmp2; | ||
383 | char do_deselect; | ||
203 | 384 | ||
204 | rcu_read_lock(); | 385 | rcu_read_lock(); |
205 | hlist_for_each_entry_rcu(softif_neigh, node, | 386 | hlist_for_each_entry_rcu(softif_neigh_vid, node, |
206 | &bat_priv->softif_neigh_list, list) { | 387 | &bat_priv->softif_neigh_vids, list) { |
207 | pos += snprintf(buff + pos, 31, "%s %pM (vid: %d)\n", | 388 | if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) |
208 | bat_priv->softif_neigh == softif_neigh | 389 | continue; |
209 | ? "=>" : " ", softif_neigh->addr, | 390 | |
210 | softif_neigh->vid); | 391 | curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); |
392 | do_deselect = 0; | ||
393 | |||
394 | spin_lock_bh(&bat_priv->softif_neigh_lock); | ||
395 | hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, | ||
396 | &softif_neigh_vid->softif_neigh_list, | ||
397 | list) { | ||
398 | if ((!time_after(jiffies, softif_neigh->last_seen + | ||
399 | msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && | ||
400 | (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) | ||
401 | continue; | ||
402 | |||
403 | if (curr_softif_neigh == softif_neigh) { | ||
404 | bat_dbg(DBG_ROUTES, bat_priv, | ||
405 | "Current mesh exit point on vid: %d " | ||
406 | "'%pM' vanished.\n", | ||
407 | softif_neigh_vid->vid, | ||
408 | softif_neigh->addr); | ||
409 | do_deselect = 1; | ||
410 | } | ||
411 | |||
412 | hlist_del_rcu(&softif_neigh->list); | ||
413 | softif_neigh_free_ref(softif_neigh); | ||
414 | } | ||
415 | spin_unlock_bh(&bat_priv->softif_neigh_lock); | ||
416 | |||
417 | /* soft_neigh_vid_deselect() needs to acquire the | ||
418 | * softif_neigh_lock */ | ||
419 | if (do_deselect) | ||
420 | softif_neigh_vid_deselect(bat_priv, softif_neigh_vid); | ||
421 | |||
422 | if (curr_softif_neigh) | ||
423 | softif_neigh_free_ref(curr_softif_neigh); | ||
424 | |||
425 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
211 | } | 426 | } |
212 | rcu_read_unlock(); | 427 | rcu_read_unlock(); |
213 | 428 | ||
214 | seq_printf(seq, "%s", buff); | 429 | spin_lock_bh(&bat_priv->softif_neigh_vid_lock); |
215 | kfree(buff); | 430 | hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp, |
216 | return 0; | 431 | &bat_priv->softif_neigh_vids, list) { |
432 | if (!hlist_empty(&softif_neigh_vid->softif_neigh_list)) | ||
433 | continue; | ||
434 | |||
435 | hlist_del_rcu(&softif_neigh_vid->list); | ||
436 | softif_neigh_vid_free_ref(softif_neigh_vid); | ||
437 | } | ||
438 | spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); | ||
439 | |||
217 | } | 440 | } |
218 | 441 | ||
219 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | 442 | static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, |
@@ -222,7 +445,9 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
222 | struct bat_priv *bat_priv = netdev_priv(dev); | 445 | struct bat_priv *bat_priv = netdev_priv(dev); |
223 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 446 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
224 | struct batman_packet *batman_packet; | 447 | struct batman_packet *batman_packet; |
225 | struct softif_neigh *softif_neigh, *softif_neigh_tmp; | 448 | struct softif_neigh *softif_neigh = NULL; |
449 | struct hard_iface *primary_if = NULL; | ||
450 | struct softif_neigh *curr_softif_neigh = NULL; | ||
226 | 451 | ||
227 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) | 452 | if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) |
228 | batman_packet = (struct batman_packet *) | 453 | batman_packet = (struct batman_packet *) |
@@ -231,63 +456,52 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, | |||
231 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); | 456 | batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); |
232 | 457 | ||
233 | if (batman_packet->version != COMPAT_VERSION) | 458 | if (batman_packet->version != COMPAT_VERSION) |
234 | goto err; | 459 | goto out; |
235 | 460 | ||
236 | if (batman_packet->packet_type != BAT_PACKET) | 461 | if (batman_packet->packet_type != BAT_PACKET) |
237 | goto err; | 462 | goto out; |
238 | 463 | ||
239 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) | 464 | if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) |
240 | goto err; | 465 | goto out; |
241 | 466 | ||
242 | if (is_my_mac(batman_packet->orig)) | 467 | if (is_my_mac(batman_packet->orig)) |
243 | goto err; | 468 | goto out; |
244 | 469 | ||
245 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); | 470 | softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); |
246 | |||
247 | if (!softif_neigh) | 471 | if (!softif_neigh) |
248 | goto err; | 472 | goto out; |
249 | 473 | ||
250 | if (bat_priv->softif_neigh == softif_neigh) | 474 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
475 | if (curr_softif_neigh == softif_neigh) | ||
476 | goto out; | ||
477 | |||
478 | primary_if = primary_if_get_selected(bat_priv); | ||
479 | if (!primary_if) | ||
251 | goto out; | 480 | goto out; |
252 | 481 | ||
253 | /* we got a neighbor but its mac is 'bigger' than ours */ | 482 | /* we got a neighbor but its mac is 'bigger' than ours */ |
254 | if (memcmp(bat_priv->primary_if->net_dev->dev_addr, | 483 | if (memcmp(primary_if->net_dev->dev_addr, |
255 | softif_neigh->addr, ETH_ALEN) < 0) | 484 | softif_neigh->addr, ETH_ALEN) < 0) |
256 | goto out; | 485 | goto out; |
257 | 486 | ||
258 | /* switch to new 'smallest neighbor' */ | ||
259 | if ((bat_priv->softif_neigh) && | ||
260 | (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, | ||
261 | ETH_ALEN) < 0)) { | ||
262 | bat_dbg(DBG_ROUTES, bat_priv, | ||
263 | "Changing mesh exit point from %pM (vid: %d) " | ||
264 | "to %pM (vid: %d).\n", | ||
265 | bat_priv->softif_neigh->addr, | ||
266 | bat_priv->softif_neigh->vid, | ||
267 | softif_neigh->addr, softif_neigh->vid); | ||
268 | softif_neigh_tmp = bat_priv->softif_neigh; | ||
269 | bat_priv->softif_neigh = softif_neigh; | ||
270 | kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); | ||
271 | /* we need to hold the additional reference */ | ||
272 | goto err; | ||
273 | } | ||
274 | |||
275 | /* close own batX device and use softif_neigh as exit node */ | 487 | /* close own batX device and use softif_neigh as exit node */ |
276 | if ((!bat_priv->softif_neigh) && | 488 | if (!curr_softif_neigh) { |
277 | (memcmp(softif_neigh->addr, | 489 | softif_neigh_vid_select(bat_priv, softif_neigh, vid); |
278 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { | 490 | goto out; |
279 | bat_dbg(DBG_ROUTES, bat_priv, | ||
280 | "Setting mesh exit point to %pM (vid: %d).\n", | ||
281 | softif_neigh->addr, softif_neigh->vid); | ||
282 | bat_priv->softif_neigh = softif_neigh; | ||
283 | /* we need to hold the additional reference */ | ||
284 | goto err; | ||
285 | } | 491 | } |
286 | 492 | ||
493 | /* switch to new 'smallest neighbor' */ | ||
494 | if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0) | ||
495 | softif_neigh_vid_select(bat_priv, softif_neigh, vid); | ||
496 | |||
287 | out: | 497 | out: |
288 | kref_put(&softif_neigh->refcount, softif_neigh_free_ref); | ||
289 | err: | ||
290 | kfree_skb(skb); | 498 | kfree_skb(skb); |
499 | if (softif_neigh) | ||
500 | softif_neigh_free_ref(softif_neigh); | ||
501 | if (curr_softif_neigh) | ||
502 | softif_neigh_free_ref(curr_softif_neigh); | ||
503 | if (primary_if) | ||
504 | hardif_free_ref(primary_if); | ||
291 | return; | 505 | return; |
292 | } | 506 | } |
293 | 507 | ||
@@ -317,11 +531,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p) | |||
317 | if (!is_valid_ether_addr(addr->sa_data)) | 531 | if (!is_valid_ether_addr(addr->sa_data)) |
318 | return -EADDRNOTAVAIL; | 532 | return -EADDRNOTAVAIL; |
319 | 533 | ||
320 | /* only modify hna-table if it has been initialised before */ | 534 | /* only modify transtable if it has been initialised before */ |
321 | if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { | 535 | if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { |
322 | hna_local_remove(bat_priv, dev->dev_addr, | 536 | tt_local_remove(bat_priv, dev->dev_addr, |
323 | "mac address changed"); | 537 | "mac address changed"); |
324 | hna_local_add(dev, addr->sa_data); | 538 | tt_local_add(dev, addr->sa_data); |
325 | } | 539 | } |
326 | 540 | ||
327 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 541 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
@@ -343,8 +557,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
343 | { | 557 | { |
344 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; | 558 | struct ethhdr *ethhdr = (struct ethhdr *)skb->data; |
345 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 559 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
560 | struct hard_iface *primary_if = NULL; | ||
346 | struct bcast_packet *bcast_packet; | 561 | struct bcast_packet *bcast_packet; |
347 | struct vlan_ethhdr *vhdr; | 562 | struct vlan_ethhdr *vhdr; |
563 | struct softif_neigh *curr_softif_neigh = NULL; | ||
348 | int data_len = skb->len, ret; | 564 | int data_len = skb->len, ret; |
349 | short vid = -1; | 565 | short vid = -1; |
350 | bool do_bcast = false; | 566 | bool do_bcast = false; |
@@ -372,11 +588,12 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
372 | * if we have a another chosen mesh exit node in range | 588 | * if we have a another chosen mesh exit node in range |
373 | * it will transport the packets to the mesh | 589 | * it will transport the packets to the mesh |
374 | */ | 590 | */ |
375 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) | 591 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
592 | if (curr_softif_neigh) | ||
376 | goto dropped; | 593 | goto dropped; |
377 | 594 | ||
378 | /* TODO: check this for locks */ | 595 | /* TODO: check this for locks */ |
379 | hna_local_add(soft_iface, ethhdr->h_source); | 596 | tt_local_add(soft_iface, ethhdr->h_source); |
380 | 597 | ||
381 | if (is_multicast_ether_addr(ethhdr->h_dest)) { | 598 | if (is_multicast_ether_addr(ethhdr->h_dest)) { |
382 | ret = gw_is_target(bat_priv, skb); | 599 | ret = gw_is_target(bat_priv, skb); |
@@ -390,7 +607,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
390 | 607 | ||
391 | /* ethernet packet should be broadcasted */ | 608 | /* ethernet packet should be broadcasted */ |
392 | if (do_bcast) { | 609 | if (do_bcast) { |
393 | if (!bat_priv->primary_if) | 610 | primary_if = primary_if_get_selected(bat_priv); |
611 | if (!primary_if) | ||
394 | goto dropped; | 612 | goto dropped; |
395 | 613 | ||
396 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) | 614 | if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) |
@@ -406,7 +624,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) | |||
406 | /* hw address of first interface is the orig mac because only | 624 | /* hw address of first interface is the orig mac because only |
407 | * this mac is known throughout the mesh */ | 625 | * this mac is known throughout the mesh */ |
408 | memcpy(bcast_packet->orig, | 626 | memcpy(bcast_packet->orig, |
409 | bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); | 627 | primary_if->net_dev->dev_addr, ETH_ALEN); |
410 | 628 | ||
411 | /* set broadcast sequence number */ | 629 | /* set broadcast sequence number */ |
412 | bcast_packet->seqno = | 630 | bcast_packet->seqno = |
@@ -434,17 +652,22 @@ dropped: | |||
434 | dropped_freed: | 652 | dropped_freed: |
435 | bat_priv->stats.tx_dropped++; | 653 | bat_priv->stats.tx_dropped++; |
436 | end: | 654 | end: |
655 | if (curr_softif_neigh) | ||
656 | softif_neigh_free_ref(curr_softif_neigh); | ||
657 | if (primary_if) | ||
658 | hardif_free_ref(primary_if); | ||
437 | return NETDEV_TX_OK; | 659 | return NETDEV_TX_OK; |
438 | } | 660 | } |
439 | 661 | ||
440 | void interface_rx(struct net_device *soft_iface, | 662 | void interface_rx(struct net_device *soft_iface, |
441 | struct sk_buff *skb, struct batman_if *recv_if, | 663 | struct sk_buff *skb, struct hard_iface *recv_if, |
442 | int hdr_size) | 664 | int hdr_size) |
443 | { | 665 | { |
444 | struct bat_priv *bat_priv = netdev_priv(soft_iface); | 666 | struct bat_priv *bat_priv = netdev_priv(soft_iface); |
445 | struct unicast_packet *unicast_packet; | 667 | struct unicast_packet *unicast_packet; |
446 | struct ethhdr *ethhdr; | 668 | struct ethhdr *ethhdr; |
447 | struct vlan_ethhdr *vhdr; | 669 | struct vlan_ethhdr *vhdr; |
670 | struct softif_neigh *curr_softif_neigh = NULL; | ||
448 | short vid = -1; | 671 | short vid = -1; |
449 | int ret; | 672 | int ret; |
450 | 673 | ||
@@ -474,7 +697,8 @@ void interface_rx(struct net_device *soft_iface, | |||
474 | * if we have a another chosen mesh exit node in range | 697 | * if we have a another chosen mesh exit node in range |
475 | * it will transport the packets to the non-mesh network | 698 | * it will transport the packets to the non-mesh network |
476 | */ | 699 | */ |
477 | if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { | 700 | curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); |
701 | if (curr_softif_neigh) { | ||
478 | skb_push(skb, hdr_size); | 702 | skb_push(skb, hdr_size); |
479 | unicast_packet = (struct unicast_packet *)skb->data; | 703 | unicast_packet = (struct unicast_packet *)skb->data; |
480 | 704 | ||
@@ -485,8 +709,8 @@ void interface_rx(struct net_device *soft_iface, | |||
485 | skb_reset_mac_header(skb); | 709 | skb_reset_mac_header(skb); |
486 | 710 | ||
487 | memcpy(unicast_packet->dest, | 711 | memcpy(unicast_packet->dest, |
488 | bat_priv->softif_neigh->addr, ETH_ALEN); | 712 | curr_softif_neigh->addr, ETH_ALEN); |
489 | ret = route_unicast_packet(skb, recv_if, hdr_size); | 713 | ret = route_unicast_packet(skb, recv_if); |
490 | if (ret == NET_RX_DROP) | 714 | if (ret == NET_RX_DROP) |
491 | goto dropped; | 715 | goto dropped; |
492 | 716 | ||
@@ -498,7 +722,7 @@ void interface_rx(struct net_device *soft_iface, | |||
498 | goto dropped; | 722 | goto dropped; |
499 | skb->protocol = eth_type_trans(skb, soft_iface); | 723 | skb->protocol = eth_type_trans(skb, soft_iface); |
500 | 724 | ||
501 | /* should not be neccesary anymore as we use skb_pull_rcsum() | 725 | /* should not be necessary anymore as we use skb_pull_rcsum() |
502 | * TODO: please verify this and remove this TODO | 726 | * TODO: please verify this and remove this TODO |
503 | * -- Dec 21st 2009, Simon Wunderlich */ | 727 | * -- Dec 21st 2009, Simon Wunderlich */ |
504 | 728 | ||
@@ -510,11 +734,13 @@ void interface_rx(struct net_device *soft_iface, | |||
510 | soft_iface->last_rx = jiffies; | 734 | soft_iface->last_rx = jiffies; |
511 | 735 | ||
512 | netif_rx(skb); | 736 | netif_rx(skb); |
513 | return; | 737 | goto out; |
514 | 738 | ||
515 | dropped: | 739 | dropped: |
516 | kfree_skb(skb); | 740 | kfree_skb(skb); |
517 | out: | 741 | out: |
742 | if (curr_softif_neigh) | ||
743 | softif_neigh_free_ref(curr_softif_neigh); | ||
518 | return; | 744 | return; |
519 | } | 745 | } |
520 | 746 | ||
@@ -548,14 +774,15 @@ static void interface_setup(struct net_device *dev) | |||
548 | dev->hard_start_xmit = interface_tx; | 774 | dev->hard_start_xmit = interface_tx; |
549 | #endif | 775 | #endif |
550 | dev->destructor = free_netdev; | 776 | dev->destructor = free_netdev; |
777 | dev->tx_queue_len = 0; | ||
551 | 778 | ||
552 | /** | 779 | /** |
553 | * can't call min_mtu, because the needed variables | 780 | * can't call min_mtu, because the needed variables |
554 | * have not been initialized yet | 781 | * have not been initialized yet |
555 | */ | 782 | */ |
556 | dev->mtu = ETH_DATA_LEN; | 783 | dev->mtu = ETH_DATA_LEN; |
557 | dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the | 784 | /* reserve more space in the skbuff for our header */ |
558 | * skbuff for our header */ | 785 | dev->hard_header_len = BAT_HEADER_LEN; |
559 | 786 | ||
560 | /* generate random address */ | 787 | /* generate random address */ |
561 | random_ether_addr(dev_addr); | 788 | random_ether_addr(dev_addr); |
@@ -580,7 +807,7 @@ struct net_device *softif_create(char *name) | |||
580 | goto out; | 807 | goto out; |
581 | } | 808 | } |
582 | 809 | ||
583 | ret = register_netdev(soft_iface); | 810 | ret = register_netdevice(soft_iface); |
584 | if (ret < 0) { | 811 | if (ret < 0) { |
585 | pr_err("Unable to register the batman interface '%s': %i\n", | 812 | pr_err("Unable to register the batman interface '%s': %i\n", |
586 | name, ret); | 813 | name, ret); |
@@ -604,11 +831,10 @@ struct net_device *softif_create(char *name) | |||
604 | 831 | ||
605 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); | 832 | atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); |
606 | atomic_set(&bat_priv->bcast_seqno, 1); | 833 | atomic_set(&bat_priv->bcast_seqno, 1); |
607 | atomic_set(&bat_priv->hna_local_changed, 0); | 834 | atomic_set(&bat_priv->tt_local_changed, 0); |
608 | 835 | ||
609 | bat_priv->primary_if = NULL; | 836 | bat_priv->primary_if = NULL; |
610 | bat_priv->num_ifaces = 0; | 837 | bat_priv->num_ifaces = 0; |
611 | bat_priv->softif_neigh = NULL; | ||
612 | 838 | ||
613 | ret = sysfs_add_meshif(soft_iface); | 839 | ret = sysfs_add_meshif(soft_iface); |
614 | if (ret < 0) | 840 | if (ret < 0) |
@@ -646,12 +872,25 @@ void softif_destroy(struct net_device *soft_iface) | |||
646 | unregister_netdevice(soft_iface); | 872 | unregister_netdevice(soft_iface); |
647 | } | 873 | } |
648 | 874 | ||
875 | int softif_is_valid(struct net_device *net_dev) | ||
876 | { | ||
877 | #ifdef HAVE_NET_DEVICE_OPS | ||
878 | if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) | ||
879 | return 1; | ||
880 | #else | ||
881 | if (net_dev->hard_start_xmit == interface_tx) | ||
882 | return 1; | ||
883 | #endif | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
649 | /* ethtool */ | 888 | /* ethtool */ |
650 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 889 | static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
651 | { | 890 | { |
652 | cmd->supported = 0; | 891 | cmd->supported = 0; |
653 | cmd->advertising = 0; | 892 | cmd->advertising = 0; |
654 | cmd->speed = SPEED_10; | 893 | ethtool_cmd_speed_set(cmd, SPEED_10); |
655 | cmd->duplex = DUPLEX_FULL; | 894 | cmd->duplex = DUPLEX_FULL; |
656 | cmd->port = PORT_TP; | 895 | cmd->port = PORT_TP; |
657 | cmd->phy_address = 0; | 896 | cmd->phy_address = 0; |
@@ -686,12 +925,3 @@ static u32 bat_get_link(struct net_device *dev) | |||
686 | return 1; | 925 | return 1; |
687 | } | 926 | } |
688 | 927 | ||
689 | static u32 bat_get_rx_csum(struct net_device *dev) | ||
690 | { | ||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int bat_set_rx_csum(struct net_device *dev, u32 data) | ||
695 | { | ||
696 | return -EOPNOTSUPP; | ||
697 | } | ||