aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv/soft-interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r--net/batman-adv/soft-interface.c79
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
43static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); 40static 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
82static void softif_neigh_free_ref(struct kref *refcount) 79static 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
90static void softif_neigh_free_rcu(struct rcu_head *rcu) 87static 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
98void softif_neigh_purge(struct bat_priv *bat_priv) 93void 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
165found:
166 kref_get(&softif_neigh->refcount);
167out: 163out:
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
287out: 263out:
288 kref_put(&softif_neigh->refcount, softif_neigh_free_ref); 264 softif_neigh_free_ref(softif_neigh);
289err: 265err:
290 kfree_skb(skb); 266 kfree_skb(skb);
291 return; 267 return;
@@ -438,7 +414,7 @@ end:
438} 414}
439 415
440void interface_rx(struct net_device *soft_iface, 416void 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
625int 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 */
650static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 639static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
651{ 640{