diff options
author | Marek Lindner <lindner_marek@yahoo.de> | 2011-04-20 15:40:58 +0200 |
---|---|---|
committer | Sven Eckelmann <sven@narfation.org> | 2011-05-01 22:49:03 +0200 |
commit | 32ae9b221e788413ce68feaae2ca39e406211a0a (patch) | |
tree | d827f989976a28fea5cdcb349c308baa98182c35 /net/batman-adv/unicast.c | |
parent | batman-adv: fix gw_node_update() and gw_election() (diff) | |
download | linux-32ae9b221e788413ce68feaae2ca39e406211a0a.tar.xz linux-32ae9b221e788413ce68feaae2ca39e406211a0a.zip |
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, struct hard_iface *hard_iface, uint8_t dstaddr[]) { struct unicast_packet tmp_uc, *unicast_packet; + struct hard_iface *primary_if; struct sk_buff *frag_skb; struct unicast_frag_packet *frag1, *frag2; int uc_hdr_len = sizeof(struct unicast_packet); int ucf_hdr_len = sizeof(struct unicast_frag_packet); int data_len = skb->len - uc_hdr_len; - int large_tail = 0; + int large_tail = 0, ret = NET_RX_DROP; uint16_t seqno; - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto dropped; 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, frag1->version = COMPAT_VERSION; frag1->packet_type = BAT_UNICAST_FRAG; - memcpy(frag1->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(frag1->orig, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(frag2, frag1, sizeof(struct unicast_frag_packet)); if (data_len & 1) @@ -269,13 +271,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, send_skb_packet(skb, hard_iface, dstaddr); send_skb_packet(frag_skb, hard_iface, dstaddr); - return NET_RX_SUCCESS; + ret = NET_RX_SUCCESS; + goto out; drop_frag: kfree_skb(frag_skb); dropped: kfree_skb(skb); - return NET_RX_DROP; +out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; } int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) |