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 /net/batman-adv/unicast.c | |
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>
Diffstat (limited to 'net/batman-adv/unicast.c')
-rw-r--r-- | net/batman-adv/unicast.c | 16 |
1 files changed, 11 insertions, 5 deletions
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) |