aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/soft-interface.c
diff options
context:
space:
mode:
authorMarek Lindner <lindner_marek@yahoo.de>2011-04-20 09:40:58 -0400
committerSven Eckelmann <sven@narfation.org>2011-05-01 16:49:03 -0400
commit32ae9b221e788413ce68feaae2ca39e406211a0a (patch)
treed827f989976a28fea5cdcb349c308baa98182c35 /net/batman-adv/soft-interface.c
parent71e4aa9c465fd66c110667ab5d620fb6a4ef2157 (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>
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r--net/batman-adv/soft-interface.c64
1 files changed, 45 insertions, 19 deletions
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; 252out:
253 if (primary_if)
254 hardif_free_ref(primary_if);
255 return ret;
242} 256}
243 257
244static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, 258static 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
312out: 333out:
313 softif_neigh_free_ref(softif_neigh);
314err:
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:
466end: 490end:
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