From patchwork Wed Nov 17 01:26:34 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Lindner X-Patchwork-Id: 565 Return-Path: Received: from nm11.bullet.mail.ukl.yahoo.com (nm11.bullet.mail.ukl.yahoo.com [217.146.183.185]) by open-mesh.org (Postfix) with SMTP id 05FDB1542E5 for ; Wed, 17 Nov 2010 02:29:49 +0100 (CET) Received: from [217.146.183.208] by nm11.bullet.mail.ukl.yahoo.com with NNFMP; 17 Nov 2010 01:29:49 -0000 Received: from [217.146.183.61] by tm1.bullet.mail.ukl.yahoo.com with NNFMP; 17 Nov 2010 01:29:49 -0000 Received: from [127.0.0.1] by omp1030.mail.ukl.yahoo.com with NNFMP; 17 Nov 2010 01:29:49 -0000 X-Yahoo-Newman-Id: 126632.6855.bm@omp1030.mail.ukl.yahoo.com Received: (qmail 69049 invoked from network); 17 Nov 2010 01:29:49 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.de; h=DKIM-Signature:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=Bym77XWOU0oFB8iUMIXflknM6TpLODsAwG7g6nGEl5PUzbg/Tfc4kmARZ3KSEpT8xROazLJvfAJMCGIt2vXWEb7RpzDbviQ5H9+27CTvmbuaHNFaqoI6cFr4mN9zbEAto7X0Sfcgj7FSJckydGmSVPxMTC2OpmMNhvRs7Xl54t4= ; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.de; s=s1024; t=1289957389; bh=mlz5sAe5oFt0/PJBt2c5iJrfox8VL3UJw2mOcleQkkk=; h=Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=ArmQPsCTBojMcYCASJNn9Oq/IL/Xw7trd6LIcE+WY0alMP/ZmcH7FhlPTX8MygBxEtfCoJSt24c+cIix1LNalYIc/m3NAZ7NGGecmmULOHQvNLuhoNzvalMzjdc7dvOUKmFl8Rfztaqkofrs0FnrZDLql1e7mQkr+n7AEUfVnMc= Received: from localhost (lindner_marek@81.57.254.118 with plain) by smtp138.mail.ukl.yahoo.com with SMTP; 17 Nov 2010 01:29:43 +0000 GMT X-Yahoo-SMTP: tW.h3tiswBBMXO2coYcbPigGD5Lt6zY_.Zc- X-YMail-OSG: .dsumHQVM1kfV8432GPpQ0suDXj7p7xCmgBASloETbv_oQE _QrmL3iNRIYka.L7Mo48yCGTcRiczG_ngT3ySQa9BwwkwYyd.Mjp_IKByedg 4lZoH4y4_12gazttKsjrkIK_QnKgzYZRR5iMf_YXGGJBfv9pp.W7nnD44_el NxEVd_2OQyp6SENwSLzy6UkWLVu1Utew6ro58UNXPEaeN77514vtm5cVGCXT lgUfT4eXv9h2_jrRFBctTyF.atqCj_NaTdMWTtlIAzv9e07TBJMYha2l1TB5 VDJBgVlhjvW10shaXcFnSmng3Kw-- X-Yahoo-Newman-Property: ymail-3 From: Marek Lindner To: b.a.t.m.a.n@lists.open-mesh.org Date: Wed, 17 Nov 2010 02:26:34 +0100 Message-Id: <1289957194-5455-8-git-send-email-lindner_marek@yahoo.de> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <201011170226.09739.lindner_marek@yahoo.de> References: <201011170226.09739.lindner_marek@yahoo.de> Cc: Marek Lindner Subject: [B.A.T.M.A.N.] [PATCH 8/8] batman-adv: remove orig_hash spinlock X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.11 Precedence: list Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Nov 2010 01:29:50 -0000 Signed-off-by: Marek Lindner --- batman-adv/icmp_socket.c | 35 +++--- batman-adv/main.c | 1 - batman-adv/originator.c | 21 --- batman-adv/routing.c | 312 ++++++++++++++++++++++++---------------------- batman-adv/types.h | 1 - batman-adv/unicast.c | 96 +++++++++------ batman-adv/vis.c | 58 +++++----- 7 files changed, 264 insertions(+), 260 deletions(-) diff --git a/batman-adv/icmp_socket.c b/batman-adv/icmp_socket.c index a9a10ed..3598f2b 100644 --- a/batman-adv/icmp_socket.c +++ b/batman-adv/icmp_socket.c @@ -157,10 +157,9 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, struct sk_buff *skb; struct icmp_packet_rr *icmp_packet; - struct orig_node *orig_node; - struct batman_if *batman_if; + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; size_t packet_len = sizeof(struct icmp_packet); - uint8_t dstaddr[ETH_ALEN]; if (len < sizeof(struct icmp_packet)) { bat_dbg(DBG_BATMAN, bat_priv, @@ -220,49 +219,51 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE) goto dst_unreach; - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->dst)); - rcu_read_unlock(); if (!orig_node) goto unlock; - if (!orig_node->router) - goto unlock; + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); + if (!neigh_node) + goto unlock; - spin_unlock_bh(&bat_priv->orig_hash_lock); + kref_get(&neigh_node->refcount); + rcu_read_unlock(); - if (!batman_if) + if (!neigh_node->if_incoming) goto dst_unreach; - if (batman_if->if_status != IF_ACTIVE) + if (neigh_node->if_incoming->if_status != IF_ACTIVE) goto dst_unreach; memcpy(icmp_packet->orig, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); if (packet_len == sizeof(struct icmp_packet_rr)) - memcpy(icmp_packet->rr, batman_if->net_dev->dev_addr, ETH_ALEN); - - - send_skb_packet(skb, batman_if, dstaddr); + memcpy(icmp_packet->rr, + neigh_node->if_incoming->net_dev->dev_addr, ETH_ALEN); + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); goto out; unlock: - spin_unlock_bh(&bat_priv->orig_hash_lock); + rcu_read_unlock(); dst_unreach: icmp_packet->msg_type = DESTINATION_UNREACHABLE; bat_socket_add_packet(socket_client, icmp_packet, packet_len); free_skb: kfree_skb(skb); out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); return len; } diff --git a/batman-adv/main.c b/batman-adv/main.c index c91e635..8acbb57 100644 --- a/batman-adv/main.c +++ b/batman-adv/main.c @@ -80,7 +80,6 @@ int mesh_init(struct net_device *soft_iface) { struct bat_priv *bat_priv = netdev_priv(soft_iface); - spin_lock_init(&bat_priv->orig_hash_lock); spin_lock_init(&bat_priv->forw_bat_list_lock); spin_lock_init(&bat_priv->forw_bcast_list_lock); spin_lock_init(&bat_priv->hna_lhash_lock); diff --git a/batman-adv/originator.c b/batman-adv/originator.c index d573a5b..923cc39 100644 --- a/batman-adv/originator.c +++ b/batman-adv/originator.c @@ -44,18 +44,15 @@ int originator_init(struct bat_priv *bat_priv) if (bat_priv->orig_hash) return 1; - spin_lock_bh(&bat_priv->orig_hash_lock); bat_priv->orig_hash = hash_new(1024); if (!bat_priv->orig_hash) goto err; - spin_unlock_bh(&bat_priv->orig_hash_lock); start_purge_timer(bat_priv); return 1; err: - spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; } @@ -146,7 +143,6 @@ void originator_free(struct bat_priv *bat_priv) cancel_delayed_work_sync(&bat_priv->orig_work); - spin_lock_bh(&bat_priv->orig_hash_lock); bat_priv->orig_hash = NULL; for (i = 0; i < hash->size; i++) { @@ -171,7 +167,6 @@ void originator_free(struct bat_priv *bat_priv) } hash_destroy(hash); - spin_unlock_bh(&bat_priv->orig_hash_lock); } /* this function finds or creates an originator entry for the given @@ -336,8 +331,6 @@ static void _purge_orig(struct bat_priv *bat_priv) if (!hash) return; - spin_lock_bh(&bat_priv->orig_hash_lock); - /* for all origins... */ for (i = 0; i < hash->size; i++) { rcu_read_lock(); @@ -373,8 +366,6 @@ static void _purge_orig(struct bat_priv *bat_priv) spin_unlock_bh(list_lock); } - spin_unlock_bh(&bat_priv->orig_hash_lock); - gw_node_purge(bat_priv); gw_election(bat_priv); @@ -432,8 +423,6 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops"); - spin_lock_bh(&bat_priv->orig_hash_lock); - for (i = 0; i < hash->size; i++) { rcu_read_lock(); ret = hlist_empty(&hash->table[i]); @@ -478,8 +467,6 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) rcu_read_unlock(); } - spin_unlock_bh(&bat_priv->orig_hash_lock); - if ((batman_count == 0)) seq_printf(seq, "No batman nodes in range ...\n"); @@ -528,8 +515,6 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_bh(&bat_priv->orig_hash_lock); - for (i = 0; i < hash->size; i++) { rcu_read_lock(); ret = hlist_empty(&hash->table[i]); @@ -550,12 +535,10 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); } - spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; err: rcu_read_unlock(); - spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; } @@ -624,8 +607,6 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) /* resize all orig nodes because orig_node->bcast_own(_sum) depend on * if_num */ - spin_lock_bh(&bat_priv->orig_hash_lock); - for (i = 0; i < hash->size; i++) { rcu_read_lock(); ret = hlist_empty(&hash->table[i]); @@ -667,11 +648,9 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num) rcu_read_unlock(); batman_if->if_num = -1; - spin_unlock_bh(&bat_priv->orig_hash_lock); return 0; err: rcu_read_unlock(); - spin_unlock_bh(&bat_priv->orig_hash_lock); return -ENOMEM; } diff --git a/batman-adv/routing.c b/batman-adv/routing.c index 8dadd2a..c50da08 100644 --- a/batman-adv/routing.c +++ b/batman-adv/routing.c @@ -47,8 +47,6 @@ void slide_own_bcast_window(struct batman_if *batman_if) TYPE_OF_WORD *word; int ret, i; - spin_lock_bh(&bat_priv->orig_hash_lock); - for (i = 0; i < hash->size; i++) { rcu_read_lock(); ret = hlist_empty(&hash->table[i]); @@ -71,8 +69,6 @@ void slide_own_bcast_window(struct batman_if *batman_if) } rcu_read_unlock(); } - - spin_unlock_bh(&bat_priv->orig_hash_lock); } static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node, @@ -816,7 +812,6 @@ out: int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) { - struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface); struct ethhdr *ethhdr; /* drop packet if it has not necessary minimum size */ @@ -843,12 +838,10 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) ethhdr = (struct ethhdr *)skb_mac_header(skb); - spin_lock_bh(&bat_priv->orig_hash_lock); receive_aggr_bat_packet(ethhdr, skb->data, skb_headlen(skb), batman_if); - spin_unlock_bh(&bat_priv->orig_hash_lock); kfree_skb(skb); return NET_RX_SUCCESS; @@ -857,12 +850,11 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if) static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { - struct orig_node *orig_node; + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; - struct batman_if *batman_if; - int ret; - uint8_t dstaddr[ETH_ALEN]; + int ret = NET_RX_DROP; icmp_packet = (struct icmp_packet_rr *)skb->data; ethhdr = (struct ethhdr *)skb_mac_header(skb); @@ -870,62 +862,65 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, /* add data to device queue */ if (icmp_packet->msg_type != ECHO_REQUEST) { bat_socket_receive_packet(icmp_packet, icmp_len); - return NET_RX_DROP; + goto out; } if (!bat_priv->primary_if) - return NET_RX_DROP; + goto out; /* answer echo request (ping) */ /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->orig)); - rcu_read_unlock(); - ret = NET_RX_DROP; + if (!orig_node) + goto unlock; - if ((orig_node != NULL) && - (orig_node->router != NULL)) { + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (!neigh_node) + goto unlock; - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; + kref_get(&neigh_node->refcount); + rcu_read_unlock(); - icmp_packet = (struct icmp_packet_rr *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); + /* create a copy of the skb, if needed, to modify it. */ + if (skb_cow(skb, sizeof(struct ethhdr)) < 0) + goto out; - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - icmp_packet->msg_type = ECHO_REPLY; - icmp_packet->ttl = TTL; + icmp_packet = (struct icmp_packet_rr *)skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb); - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; + memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + icmp_packet->msg_type = ECHO_REPLY; + icmp_packet->ttl = TTL; - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = NET_RX_SUCCESS; + goto out; +unlock: + rcu_read_unlock(); +out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); return ret; } static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { - struct orig_node *orig_node; + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; struct icmp_packet *icmp_packet; struct ethhdr *ethhdr; - struct batman_if *batman_if; - int ret; - uint8_t dstaddr[ETH_ALEN]; + int ret = NET_RX_DROP; icmp_packet = (struct icmp_packet *)skb->data; ethhdr = (struct ethhdr *)skb_mac_header(skb); @@ -935,49 +930,53 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, pr_debug("Warning - can't forward icmp packet from %pM to " "%pM: ttl exceeded\n", icmp_packet->orig, icmp_packet->dst); - return NET_RX_DROP; + goto out; } if (!bat_priv->primary_if) - return NET_RX_DROP; + goto out; /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->orig)); - rcu_read_unlock(); - ret = NET_RX_DROP; + if (!orig_node) + goto unlock; - if ((orig_node != NULL) && - (orig_node->router != NULL)) { + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (!neigh_node) + goto unlock; - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; + kref_get(&neigh_node->refcount); + rcu_read_unlock(); - icmp_packet = (struct icmp_packet *) skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); + /* create a copy of the skb, if needed, to modify it. */ + if (skb_cow(skb, sizeof(struct ethhdr)) < 0) + goto out; - memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); - icmp_packet->msg_type = TTL_EXCEEDED; - icmp_packet->ttl = TTL; + icmp_packet = (struct icmp_packet *)skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb); - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; + memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); + memcpy(icmp_packet->orig, + bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + icmp_packet->msg_type = TTL_EXCEEDED; + icmp_packet->ttl = TTL; - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = NET_RX_SUCCESS; + goto out; +unlock: + rcu_read_unlock(); +out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); return ret; } @@ -987,11 +986,10 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct icmp_packet_rr *icmp_packet; struct ethhdr *ethhdr; - struct orig_node *orig_node; - struct batman_if *batman_if; + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; int hdr_size = sizeof(struct icmp_packet); - int ret; - uint8_t dstaddr[ETH_ALEN]; + int ret = NET_RX_DROP; /** * we truncate all incoming icmp packets if they don't match our size @@ -1001,21 +999,21 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) - return NET_RX_DROP; + goto out; ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with unicast indication but broadcast recipient */ if (is_bcast(ethhdr->h_dest)) - return NET_RX_DROP; + goto out; /* packet with broadcast sender address */ if (is_bcast(ethhdr->h_source)) - return NET_RX_DROP; + goto out; /* not for me */ if (!is_my_mac(ethhdr->h_dest)) - return NET_RX_DROP; + goto out; icmp_packet = (struct icmp_packet_rr *)skb->data; @@ -1035,42 +1033,45 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if) if (icmp_packet->ttl < 2) return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size); - ret = NET_RX_DROP; - /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, icmp_packet->dst)); - rcu_read_unlock(); + if (!orig_node) + goto unlock; - if ((orig_node != NULL) && - (orig_node->router != NULL)) { + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (!neigh_node) + goto unlock; - /* create a copy of the skb, if needed, to modify it. */ - if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; + kref_get(&neigh_node->refcount); + rcu_read_unlock(); - icmp_packet = (struct icmp_packet_rr *)skb->data; - ethhdr = (struct ethhdr *)skb_mac_header(skb); + /* create a copy of the skb, if needed, to modify it. */ + if (skb_cow(skb, sizeof(struct ethhdr)) < 0) + goto out; - /* decrement ttl */ - icmp_packet->ttl--; + icmp_packet = (struct icmp_packet_rr *)skb->data; + ethhdr = (struct ethhdr *)skb_mac_header(skb); - /* route it */ - send_skb_packet(skb, batman_if, dstaddr); - ret = NET_RX_SUCCESS; + /* decrement ttl */ + icmp_packet->ttl--; - } else - spin_unlock_bh(&bat_priv->orig_hash_lock); + /* route it */ + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = NET_RX_SUCCESS; + goto out; +unlock: + rcu_read_unlock(); +out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); return ret; } @@ -1200,13 +1201,11 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, int hdr_size) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct orig_node *orig_node; - struct neigh_node *router; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN]; + struct orig_node *orig_node = NULL; + struct neigh_node *neigh_node = NULL; struct unicast_packet *unicast_packet; struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb); - int ret; + int ret = NET_RX_DROP; struct sk_buff *new_skb; unicast_packet = (struct unicast_packet *)skb->data; @@ -1216,55 +1215,54 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, pr_debug("Warning - can't forward unicast packet from %pM to " "%pM: ttl exceeded\n", ethhdr->h_source, unicast_packet->dest); - return NET_RX_DROP; + goto out; } /* get routing information */ - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->dest)); - rcu_read_unlock(); - router = find_router(bat_priv, orig_node, recv_if); - - if (!router) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } + if (!orig_node) + goto unlock; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ + kref_get(&orig_node->refcount); + neigh_node = find_router(bat_priv, orig_node, recv_if); - batman_if = router->if_incoming; - memcpy(dstaddr, router->addr, ETH_ALEN); + if (!neigh_node) + goto unlock; - spin_unlock_bh(&bat_priv->orig_hash_lock); + kref_get(&neigh_node->refcount); + rcu_read_unlock(); /* create a copy of the skb, if needed, to modify it. */ if (skb_cow(skb, sizeof(struct ethhdr)) < 0) - return NET_RX_DROP; + goto out; unicast_packet = (struct unicast_packet *)skb->data; if (unicast_packet->packet_type == BAT_UNICAST && atomic_read(&bat_priv->fragmentation) && - skb->len > batman_if->net_dev->mtu) - return frag_send_skb(skb, bat_priv, batman_if, - dstaddr); + skb->len > neigh_node->if_incoming->net_dev->mtu) { + ret = frag_send_skb(skb, bat_priv, + neigh_node->if_incoming, neigh_node->addr); + goto out; + } if (unicast_packet->packet_type == BAT_UNICAST_FRAG && - 2 * skb->len - hdr_size <= batman_if->net_dev->mtu) { + 2 * skb->len - hdr_size <= neigh_node->if_incoming->net_dev->mtu) { ret = frag_reassemble_skb(skb, bat_priv, &new_skb); if (ret == NET_RX_DROP) - return NET_RX_DROP; + goto out; /* packet was buffered for late merge */ - if (!new_skb) - return NET_RX_SUCCESS; + if (!new_skb) { + ret = NET_RX_SUCCESS; + goto out; + } skb = new_skb; unicast_packet = (struct unicast_packet *)skb->data; @@ -1274,9 +1272,18 @@ int route_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if, unicast_packet->ttl--; /* route it */ - send_skb_packet(skb, batman_if, dstaddr); + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = NET_RX_SUCCESS; + goto out; - return NET_RX_SUCCESS; +unlock: + rcu_read_unlock(); +out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); + return ret; } int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if) @@ -1335,81 +1342,82 @@ int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if) int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if) { struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface); - struct orig_node *orig_node; + struct orig_node *orig_node = NULL; struct bcast_packet *bcast_packet; struct ethhdr *ethhdr; int hdr_size = sizeof(struct bcast_packet); + int ret = NET_RX_DROP; int32_t seq_diff; /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) - return NET_RX_DROP; + goto out; ethhdr = (struct ethhdr *)skb_mac_header(skb); /* packet with broadcast indication but unicast recipient */ if (!is_bcast(ethhdr->h_dest)) - return NET_RX_DROP; + goto out; /* packet with broadcast sender address */ if (is_bcast(ethhdr->h_source)) - return NET_RX_DROP; + goto out; /* ignore broadcasts sent by myself */ if (is_my_mac(ethhdr->h_source)) - return NET_RX_DROP; + goto out; bcast_packet = (struct bcast_packet *)skb->data; /* ignore broadcasts originated by myself */ if (is_my_mac(bcast_packet->orig)) - return NET_RX_DROP; + goto out; if (bcast_packet->ttl < 2) - return NET_RX_DROP; + goto out; - spin_lock_bh(&bat_priv->orig_hash_lock); rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, bcast_packet->orig)); - rcu_read_unlock(); - if (orig_node == NULL) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } + if (!orig_node) + goto unlock; + + kref_get(&orig_node->refcount); + rcu_read_unlock(); /* check whether the packet is a duplicate */ - if (get_bit_status(orig_node->bcast_bits, - orig_node->last_bcast_seqno, - ntohl(bcast_packet->seqno))) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } + if (get_bit_status(orig_node->bcast_bits, orig_node->last_bcast_seqno, + ntohl(bcast_packet->seqno))) + goto out; seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno; /* check whether the packet is old and the host just restarted. */ if (window_protected(bat_priv, seq_diff, - &orig_node->bcast_seqno_reset)) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return NET_RX_DROP; - } + &orig_node->bcast_seqno_reset)) + goto out; /* mark broadcast in flood history, update window position * if required. */ if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1)) orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno); - spin_unlock_bh(&bat_priv->orig_hash_lock); /* rebroadcast packet */ add_bcast_packet_to_list(bat_priv, skb); /* broadcast for me */ interface_rx(recv_if->soft_iface, skb, recv_if, hdr_size); + ret = NET_RX_SUCCESS; + goto out; - return NET_RX_SUCCESS; +unlock: + rcu_read_unlock(); +out: + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); + return ret; } int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if) diff --git a/batman-adv/types.h b/batman-adv/types.h index f4ce526..167781f 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -156,7 +156,6 @@ struct bat_priv { struct hashtable_t *hna_local_hash; struct hashtable_t *hna_global_hash; struct hashtable_t *vis_hash; - spinlock_t orig_hash_lock; /* protects orig_hash */ spinlock_t forw_bat_list_lock; /* protects forw_bat_list */ spinlock_t forw_bcast_list_lock; /* protects */ spinlock_t hna_lhash_lock; /* protects hna_local_hash */ diff --git a/batman-adv/unicast.c b/batman-adv/unicast.c index 9df1c40..fdfb9a2 100644 --- a/batman-adv/unicast.c +++ b/batman-adv/unicast.c @@ -178,17 +178,16 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, (struct unicast_frag_packet *)skb->data; *new_skb = NULL; - spin_lock_bh(&bat_priv->orig_hash_lock); + rcu_read_lock(); orig_node = ((struct orig_node *) hash_find(bat_priv->orig_hash, compare_orig, choose_orig, unicast_packet->orig)); - rcu_read_unlock(); + if (!orig_node) + goto unlock; - if (!orig_node) { - pr_debug("couldn't find originator in orig_hash\n"); - goto out; - } + kref_get(&orig_node->refcount); + rcu_read_unlock(); orig_node->last_frag_packet = jiffies; @@ -212,9 +211,14 @@ int frag_reassemble_skb(struct sk_buff *skb, struct bat_priv *bat_priv, /* if not, merge failed */ if (*new_skb) ret = NET_RX_SUCCESS; -out: - spin_unlock_bh(&bat_priv->orig_hash_lock); + goto out; + +unlock: + rcu_read_unlock(); +out: + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); return ret; } @@ -277,47 +281,53 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct unicast_packet *unicast_packet; struct orig_node *orig_node; - struct batman_if *batman_if; - struct neigh_node *router; + struct neigh_node *neigh_node; int data_len = skb->len; - uint8_t dstaddr[6]; - - spin_lock_bh(&bat_priv->orig_hash_lock); + int ret = 1; /* get routing information */ - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) + if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { orig_node = (struct orig_node *)gw_get_selected(bat_priv); - else { + if (!orig_node) + goto trans_search; + + kref_get(&orig_node->refcount); + goto find_router; + } else { rcu_read_lock(); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, ethhdr->h_dest)); - rcu_read_lock(); + if (!orig_node) { + rcu_read_unlock(); + goto trans_search; + } + + kref_get(&orig_node->refcount); + rcu_read_unlock(); + goto find_router; } +trans_search: /* check for hna host */ - if (!orig_node) - orig_node = transtable_search(bat_priv, ethhdr->h_dest); + orig_node = transtable_search(bat_priv, ethhdr->h_dest); - router = find_router(bat_priv, orig_node, NULL); +find_router: + rcu_read_lock(); + neigh_node = find_router(bat_priv, orig_node, NULL); - if (!router) + if (!neigh_node) goto unlock; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - - batman_if = router->if_incoming; - memcpy(dstaddr, router->addr, ETH_ALEN); - - spin_unlock_bh(&bat_priv->orig_hash_lock); + kref_get(&neigh_node->refcount); + rcu_read_unlock(); - if (batman_if->if_status != IF_ACTIVE) - goto dropped; + if (neigh_node->if_incoming->if_status != IF_ACTIVE) + goto out; if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) - goto dropped; + goto out; unicast_packet = (struct unicast_packet *)skb->data; @@ -331,18 +341,26 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) if (atomic_read(&bat_priv->fragmentation) && data_len + sizeof(struct unicast_packet) > - batman_if->net_dev->mtu) { + neigh_node->if_incoming->net_dev->mtu) { /* send frag skb decreases ttl */ unicast_packet->ttl++; - return frag_send_skb(skb, bat_priv, batman_if, - dstaddr); + ret = frag_send_skb(skb, bat_priv, + neigh_node->if_incoming, neigh_node->addr); + goto out; } - send_skb_packet(skb, batman_if, dstaddr); - return 0; + + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = 0; + goto out; unlock: - spin_unlock_bh(&bat_priv->orig_hash_lock); -dropped: - kfree_skb(skb); - return 1; + rcu_read_unlock(); +out: + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); + if (ret == 1) + kfree_skb(skb); + return ret; } diff --git a/batman-adv/vis.c b/batman-adv/vis.c index 69efdf4..0d35497 100644 --- a/batman-adv/vis.c +++ b/batman-adv/vis.c @@ -582,7 +582,6 @@ static int generate_vis_packet(struct bat_priv *bat_priv) info->first_seen = jiffies; packet->vis_type = atomic_read(&bat_priv->vis_mode); - spin_lock_bh(&bat_priv->orig_hash_lock); memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); packet->ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); @@ -592,10 +591,8 @@ static int generate_vis_packet(struct bat_priv *bat_priv) if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { best_tq = find_best_vis_server(bat_priv, info); - if (best_tq < 0) { - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (best_tq < 0) return -1; - } } for (i = 0; i < hash->size; i++) { @@ -635,16 +632,12 @@ static int generate_vis_packet(struct bat_priv *bat_priv) entry->quality = neigh_node->tq_avg; packet->entries++; - if (vis_packet_full(info)) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; - } + if (vis_packet_full(info)) + goto unlock; } rcu_read_unlock(); } - spin_unlock_bh(&bat_priv->orig_hash_lock); - spin_lock_bh(&bat_priv->hna_lhash_lock); while (hash_iterate(bat_priv->hna_local_hash, &hashit_local)) { bucket = hlist_entry(hashit_local.walk, struct element_t, @@ -665,6 +658,10 @@ static int generate_vis_packet(struct bat_priv *bat_priv) spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; + +unlock: + rcu_read_unlock(); + return 0; } /* free old vis packets. Must be called with this vis_hash_lock @@ -707,7 +704,6 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, int i, ret; - spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; /* send to all routers in range. */ @@ -739,54 +735,58 @@ static void broadcast_vis_packet(struct bat_priv *bat_priv, memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); batman_if = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) send_skb_packet(skb, batman_if, dstaddr); - spin_lock_bh(&bat_priv->orig_hash_lock); } rcu_read_unlock(); } - - spin_unlock_bh(&bat_priv->orig_hash_lock); } static void unicast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { struct orig_node *orig_node; + struct neigh_node *neigh_node = NULL; struct sk_buff *skb; struct vis_packet *packet; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN]; - spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; + rcu_read_lock(); orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, compare_orig, choose_orig, packet->target_orig)); - rcu_read_unlock(); - if ((!orig_node) || (!orig_node->router)) - goto out; + if (!orig_node) + goto unlock; + + kref_get(&orig_node->refcount); + neigh_node = orig_node->router; + + if (!neigh_node) + goto unlock; - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); + kref_get(&neigh_node->refcount); + rcu_read_unlock(); skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) - send_skb_packet(skb, batman_if, dstaddr); + send_skb_packet(skb, neigh_node->if_incoming, + neigh_node->addr); - return; + goto out; +unlock: + rcu_read_unlock(); out: - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (neigh_node) + kref_put(&neigh_node->refcount, neigh_node_free_ref); + if (orig_node) + kref_put(&orig_node->refcount, orig_node_free_ref); + return; } /* only send one vis packet. called from send_vis_packets() */