The following commit has been merged in the merge/master branch: commit 9449da10f3b84e3c61b67aa5e7a7092e56be6cc9 Merge: 894e104b3e39cf335655f6f3a5a6ac9a7b9f8bec 2e8bad33846faecd76e5abfa010f964dbccdd77e Author: Sven Eckelmann sven@narfation.org Date: Sun May 1 22:41:07 2011 +0200
Merge remote-tracking branch 'origin/standalone/next' into merge/master
diff --combined net/batman-adv/aggregation.c index af45d6b,c11788c..c11788c --- a/net/batman-adv/aggregation.c +++ b/net/batman-adv/aggregation.c @@@ -95,7 -95,6 +95,6 @@@ static bool can_aggregate_with(struct b return false; }
- #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) /* create a new aggregated packet and add this packet to it */ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, unsigned long send_time, bool direct_link, diff --combined net/batman-adv/gateway_client.c index 2acd7a6,65f3953..65f3953 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@@ -127,7 -127,7 +127,7 @@@ void gw_election(struct bat_priv *bat_p return;
curr_gw = gw_get_selected_gw_node(bat_priv); - if (!curr_gw) + if (curr_gw) goto out;
rcu_read_lock(); @@@ -310,9 -310,13 +310,13 @@@ void gw_node_update(struct bat_priv *ba struct hlist_node *node; struct gw_node *gw_node, *curr_gw;
+ /** + * Note: We don't need a NULL check here, since curr_gw never gets + * dereferenced. If curr_gw is NULL we also should not exit as we may + * have this gateway in our list (duplication check!) even though we + * have no currently selected gateway. + */ curr_gw = gw_get_selected_gw_node(bat_priv); - if (!curr_gw) - goto out;
rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@@ -350,7 -354,7 +354,7 @@@ deselect gw_deselect(bat_priv); unlock: rcu_read_unlock(); - out: + if (curr_gw) gw_node_free_ref(curr_gw); } @@@ -435,30 -439,32 +439,32 @@@ int gw_client_seq_print_text(struct seq { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); + struct hard_iface *primary_if; struct gw_node *gw_node; struct hlist_node *node; - int gw_count = 0; - - if (!bat_priv->primary_if) { + int gw_count = 0, ret = 0;
- return seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + goto out; }
- if (bat_priv->primary_if->if_status != IF_ACTIVE) { - - return seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@@ -476,7 -482,10 +482,10 @@@ if (gw_count == 0) seq_printf(seq, "No gateways in range ...\n");
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) diff --combined net/batman-adv/hard-interface.c index b3058e4,3e888f1..3e888f1 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@@ -110,47 -110,60 +110,60 @@@ out return hard_iface; }
- static void update_primary_addr(struct bat_priv *bat_priv) + static void primary_if_update_addr(struct bat_priv *bat_priv) { struct vis_packet *vis_packet; + struct hard_iface *primary_if; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out;
vis_packet = (struct vis_packet *) bat_priv->my_vis_info->skb_packet->data; - memcpy(vis_packet->vis_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN); memcpy(vis_packet->sender_orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN); + + out: + if (primary_if) + hardif_free_ref(primary_if); }
- static void set_primary_if(struct bat_priv *bat_priv, - struct hard_iface *hard_iface) + static void primary_if_select(struct bat_priv *bat_priv, + struct hard_iface *new_hard_iface) { + struct hard_iface *curr_hard_iface; struct batman_packet *batman_packet; - struct hard_iface *old_if;
- if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) - hard_iface = NULL; + spin_lock_bh(&hardif_list_lock);
- old_if = bat_priv->primary_if; - bat_priv->primary_if = hard_iface; + if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount)) + new_hard_iface = NULL;
- if (old_if) - hardif_free_ref(old_if); + curr_hard_iface = bat_priv->primary_if; + rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
- if (!bat_priv->primary_if) - return; + if (curr_hard_iface) + hardif_free_ref(curr_hard_iface);
- batman_packet = (struct batman_packet *)(hard_iface->packet_buff); + if (!new_hard_iface) + goto out; + + batman_packet = (struct batman_packet *)(new_hard_iface->packet_buff); batman_packet->flags = PRIMARIES_FIRST_HOP; batman_packet->ttl = TTL;
- update_primary_addr(bat_priv); + primary_if_update_addr(bat_priv);
/*** * hacky trick to make sure that we send the HNA information via * our new primary interface */ atomic_set(&bat_priv->hna_local_changed, 1); + + out: + spin_unlock_bh(&hardif_list_lock); }
static bool hardif_is_iface_up(struct hard_iface *hard_iface) @@@ -236,9 -249,10 +249,10 @@@ void update_min_mtu(struct net_device * static void hardif_activate_interface(struct hard_iface *hard_iface) { struct bat_priv *bat_priv; + struct hard_iface *primary_if = NULL;
if (hard_iface->if_status != IF_INACTIVE) - return; + goto out;
bat_priv = netdev_priv(hard_iface->soft_iface);
@@@ -249,14 -263,18 +263,18 @@@ * the first active interface becomes our primary interface or * the next active interface after the old primay interface was removed */ - if (!bat_priv->primary_if) - set_primary_if(bat_priv, hard_iface); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + primary_if_select(bat_priv, hard_iface);
bat_info(hard_iface->soft_iface, "Interface activated: %s\n", hard_iface->net_dev->name);
update_min_mtu(hard_iface->soft_iface); - return; + + out: + if (primary_if) + hardif_free_ref(primary_if); }
static void hardif_deactivate_interface(struct hard_iface *hard_iface) @@@ -386,12 -404,13 +404,13 @@@ err void hardif_disable_interface(struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct hard_iface *primary_if = NULL;
if (hard_iface->if_status == IF_ACTIVE) hardif_deactivate_interface(hard_iface);
if (hard_iface->if_status != IF_INACTIVE) - return; + goto out;
bat_info(hard_iface->soft_iface, "Removing interface: %s\n", hard_iface->net_dev->name); @@@ -400,11 -419,12 +419,12 @@@ bat_priv->num_ifaces--; orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
- if (hard_iface == bat_priv->primary_if) { + primary_if = primary_if_get_selected(bat_priv); + if (hard_iface == primary_if) { struct hard_iface *new_if;
new_if = hardif_get_active(hard_iface->soft_iface); - set_primary_if(bat_priv, new_if); + primary_if_select(bat_priv, new_if);
if (new_if) hardif_free_ref(new_if); @@@ -425,6 -445,10 +445,10 @@@
hard_iface->soft_iface = NULL; hardif_free_ref(hard_iface); + + out: + if (primary_if) + hardif_free_ref(primary_if); }
static struct hard_iface *hardif_add_interface(struct net_device *net_dev) @@@ -514,6 -538,7 +538,7 @@@ static int hard_if_event(struct notifie { struct net_device *net_dev = (struct net_device *)ptr; struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); + struct hard_iface *primary_if = NULL; struct bat_priv *bat_priv;
if (!hard_iface && event == NETDEV_REGISTER) @@@ -549,8 -574,12 +574,12 @@@ update_mac_addresses(hard_iface);
bat_priv = netdev_priv(hard_iface->soft_iface); - if (hard_iface == bat_priv->primary_if) - update_primary_addr(bat_priv); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto hardif_put; + + if (hard_iface == primary_if) + primary_if_update_addr(bat_priv); break; default: break; @@@ -559,6 -588,8 +588,8 @@@ hardif_put: hardif_free_ref(hard_iface); out: + if (primary_if) + hardif_free_ref(primary_if); return NOTIFY_DONE; }
diff --combined net/batman-adv/hard-interface.h index a9ddf36,6426599..6426599 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@@ -45,4 -45,22 +45,22 @@@ static inline void hardif_free_ref(stru call_rcu(&hard_iface->rcu, hardif_free_rcu); }
+ static inline struct hard_iface *primary_if_get_selected( + struct bat_priv *bat_priv) + { + struct hard_iface *hard_iface; + + rcu_read_lock(); + hard_iface = rcu_dereference(bat_priv->primary_if); + if (!hard_iface) + goto out; + + if (!atomic_inc_not_zero(&hard_iface->refcount)) + hard_iface = NULL; + + out: + rcu_read_unlock(); + return hard_iface; + } + #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --combined net/batman-adv/icmp_socket.c index 49079c2,fa22ba2..fa22ba2 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@@ -153,6 -153,7 +153,7 @@@ static ssize_t bat_socket_write(struct { struct socket_client *socket_client = file->private_data; struct bat_priv *bat_priv = socket_client->bat_priv; + struct hard_iface *primary_if = NULL; struct sk_buff *skb; struct icmp_packet_rr *icmp_packet;
@@@ -167,15 -168,21 +168,21 @@@ return -EINVAL; }
- if (!bat_priv->primary_if) - return -EFAULT; + primary_if = primary_if_get_selected(bat_priv); + + if (!primary_if) { + len = -EFAULT; + goto out; + }
if (len >= sizeof(struct icmp_packet_rr)) packet_len = sizeof(struct icmp_packet_rr);
skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); - if (!skb) - return -ENOMEM; + if (!skb) { + len = -ENOMEM; + goto out; + }
skb_reserve(skb, sizeof(struct ethhdr)); icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); @@@ -233,7 -240,7 +240,7 @@@ goto dst_unreach;
memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN);
if (packet_len == sizeof(struct icmp_packet_rr)) memcpy(icmp_packet->rr, @@@ -248,6 -255,8 +255,8 @@@ dst_unreach free_skb: kfree_skb(skb); out: + if (primary_if) + hardif_free_ref(primary_if); if (neigh_node) neigh_node_free_ref(neigh_node); if (orig_node) diff --combined net/batman-adv/main.h index dc24869,0000000..ace7285 mode 100644,000000..100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@@ -1,178 -1,0 +1,180 @@@ +/* + * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: + * + * Marek Lindner, Simon Wunderlich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#ifndef _NET_BATMAN_ADV_MAIN_H_ +#define _NET_BATMAN_ADV_MAIN_H_ + +#define DRIVER_AUTHOR "Marek Lindner lindner_marek@yahoo.de, " \ + "Simon Wunderlich siwu@hrz.tu-chemnitz.de" +#define DRIVER_DESC "B.A.T.M.A.N. advanced" +#define DRIVER_DEVICE "batman-adv" + +#define SOURCE_VERSION "next" + + +/* B.A.T.M.A.N. parameters */ + +#define TQ_MAX_VALUE 255 +#define JITTER 20 +#define TTL 50 /* Time To Live of broadcast messages */ + +#define PURGE_TIMEOUT 200 /* purge originators after time in seconds if no + * valid packet comes in -> TODO: check + * influence on TQ_LOCAL_WINDOW_SIZE */ +#define LOCAL_HNA_TIMEOUT 3600 /* in seconds */ + +#define TQ_LOCAL_WINDOW_SIZE 64 /* sliding packet range of received originator + * messages in squence numbers (should be a + * multiple of our word size) */ +#define TQ_GLOBAL_WINDOW_SIZE 5 +#define TQ_LOCAL_BIDRECT_SEND_MINIMUM 1 +#define TQ_LOCAL_BIDRECT_RECV_MINIMUM 1 +#define TQ_TOTAL_BIDRECT_LIMIT 1 + +#define NUM_WORDS (TQ_LOCAL_WINDOW_SIZE / WORD_BIT_SIZE) + +#define LOG_BUF_LEN 8192 /* has to be a power of 2 */ + +#define VIS_INTERVAL 5000 /* 5 seconds */ + +/* how much worse secondary interfaces may be to + * to be considered as bonding candidates */ + +#define BONDING_TQ_THRESHOLD 50 + +#define MAX_AGGREGATION_BYTES 512 /* should not be bigger than 512 bytes or + * change the size of + * forw_packet->direct_link_flags */ +#define MAX_AGGREGATION_MS 100 + +#define SOFTIF_NEIGH_TIMEOUT 180000 /* 3 minutes */ + +#define RESET_PROTECTION_MS 30000 +#define EXPECTED_SEQNO_RANGE 65536 +/* don't reset again within 30 seconds */ + +#define MESH_INACTIVE 0 +#define MESH_ACTIVE 1 +#define MESH_DEACTIVATING 2 + +#define BCAST_QUEUE_LEN 256 +#define BATMAN_QUEUE_LEN 256 + +/* + * Debug Messages + */ +#ifdef pr_fmt +#undef pr_fmt +#endif +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt /* Append 'batman-adv: ' before + * kernel messages */ + +#define DBG_BATMAN 1 /* all messages related to routing / flooding / + * broadcasting / etc */ +#define DBG_ROUTES 2 /* route or hna added / changed / deleted */ +#define DBG_ALL 3 + + +/* + * Vis + */ + +/* + * Kernel headers + */ + +#include <linux/mutex.h> /* mutex */ +#include <linux/module.h> /* needed by all modules */ +#include <linux/netdevice.h> /* netdevice */ +#include <linux/etherdevice.h> /* ethernet address classifaction */ +#include <linux/if_ether.h> /* ethernet header */ +#include <linux/poll.h> /* poll_table */ +#include <linux/kthread.h> /* kernel threads */ +#include <linux/pkt_sched.h> /* schedule types */ +#include <linux/workqueue.h> /* workqueue */ +#include <linux/slab.h> +#include <net/sock.h> /* struct sock */ +#include <linux/jiffies.h> +#include <linux/seq_file.h> +#include "types.h" + +#ifndef REVISION_VERSION +#define REVISION_VERSION_STR "" +#else +#define REVISION_VERSION_STR " "REVISION_VERSION +#endif + +extern struct list_head hardif_list; + +extern unsigned char broadcast_addr[]; +extern struct workqueue_struct *bat_event_workqueue; + +int mesh_init(struct net_device *soft_iface); +void mesh_free(struct net_device *soft_iface); +void inc_module_count(void); +void dec_module_count(void); +int is_my_mac(uint8_t *addr); + +#ifdef CONFIG_BATMAN_ADV_DEBUG +int debug_log(struct bat_priv *bat_priv, char *fmt, ...); + +#define bat_dbg(type, bat_priv, fmt, arg...) \ + do { \ + if (atomic_read(&bat_priv->log_level) & type) \ + debug_log(bat_priv, fmt, ## arg); \ + } \ + while (0) +#else /* !CONFIG_BATMAN_ADV_DEBUG */ +static inline void bat_dbg(char type __always_unused, + struct bat_priv *bat_priv __always_unused, + char *fmt __always_unused, ...) +{ +} +#endif + +#define bat_info(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct bat_priv *_batpriv = netdev_priv(_netdev); \ + bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ + pr_info("%s: " fmt, _netdev->name, ## arg); \ + } while (0) +#define bat_err(net_dev, fmt, arg...) \ + do { \ + struct net_device *_netdev = (net_dev); \ + struct bat_priv *_batpriv = netdev_priv(_netdev); \ + bat_dbg(DBG_ALL, _batpriv, fmt, ## arg); \ + pr_err("%s: " fmt, _netdev->name, ## arg); \ + } while (0) + +/** + * returns 1 if they are the same ethernet addr + * + * note: can't use compare_ether_addr() as it requires aligned memory + */ +static inline int compare_eth(void *data1, void *data2) +{ + return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); +} + ++#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) ++ +#endif /* _NET_BATMAN_ADV_MAIN_H_ */ diff --combined net/batman-adv/originator.c index 5b8fe32,ef4a9be..ef4a9be --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@@ -405,29 -405,34 +405,34 @@@ int orig_seq_print_text(struct seq_fil struct hashtable_t *hash = bat_priv->orig_hash; struct hlist_node *node, *node_tmp; struct hlist_head *head; + struct hard_iface *primary_if; struct orig_node *orig_node; struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; - int i; + int i, ret = 0; + + primary_if = primary_if_get_selected(bat_priv);
- if ((!bat_priv->primary_if) || - (bat_priv->primary_if->if_status != IF_ACTIVE)) { - if (!bat_priv->primary_if) - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + }
- return seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name); seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops"); @@@ -474,7 -479,10 +479,10 @@@ next if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n");
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) diff --combined net/batman-adv/routing.c index f6c6422,49f5715..49f5715 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@@ -904,6 -904,7 +904,7 @@@ int recv_bat_packet(struct sk_buff *skb static int recv_my_icmp_packet(struct bat_priv *bat_priv, struct sk_buff *skb, size_t icmp_len) { + struct hard_iface *primary_if = NULL; struct orig_node *orig_node = NULL; struct neigh_node *router = NULL; struct icmp_packet_rr *icmp_packet; @@@ -917,7 -918,8 +918,8 @@@ goto out; }
- if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out;
/* answer echo request (ping) */ @@@ -937,8 -939,7 +939,7 @@@ icmp_packet = (struct icmp_packet_rr *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = ECHO_REPLY; icmp_packet->ttl = TTL;
@@@ -946,6 -947,8 +947,8 @@@ ret = NET_RX_SUCCESS;
out: + if (primary_if) + hardif_free_ref(primary_if); if (router) neigh_node_free_ref(router); if (orig_node) @@@ -956,6 -959,7 +959,7 @@@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, struct sk_buff *skb) { + struct hard_iface *primary_if = NULL; struct orig_node *orig_node = NULL; struct neigh_node *router = NULL; struct icmp_packet *icmp_packet; @@@ -971,7 -975,8 +975,8 @@@ goto out; }
- if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out;
/* get routing information */ @@@ -990,8 -995,7 +995,7 @@@ icmp_packet = (struct icmp_packet *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); - memcpy(icmp_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN); icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->ttl = TTL;
@@@ -999,6 -1003,8 +1003,8 @@@ ret = NET_RX_SUCCESS;
out: + if (primary_if) + hardif_free_ref(primary_if); if (router) neigh_node_free_ref(router); if (orig_node) @@@ -1310,13 -1316,10 +1316,10 @@@ int route_unicast_packet(struct sk_buf }
/* get routing information */ orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node) - goto unlock; - - rcu_read_unlock(); + goto out;
/* find_router() increases neigh_nodes refcount if found. */ neigh_node = find_router(bat_priv, orig_node, recv_if); @@@ -1362,10 -1365,7 +1365,7 @@@ /* 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) neigh_node_free_ref(neigh_node); @@@ -1464,13 -1464,10 +1464,10 @@@ int recv_bcast_packet(struct sk_buff *s if (bcast_packet->ttl < 2) goto out;
orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
if (!orig_node) - goto rcu_unlock; - - rcu_read_unlock(); + goto out;
spin_lock_bh(&orig_node->bcast_seqno_lock);
@@@ -1501,9 -1498,6 +1498,6 @@@ ret = NET_RX_SUCCESS; goto out;
- rcu_unlock: - rcu_read_unlock(); - goto out; spin_unlock: spin_unlock_bh(&orig_node->bcast_seqno_lock); out: diff --combined net/batman-adv/send.c index e78670c,02b541a..02b541a --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@@ -244,6 -244,7 +244,7 @@@ static void rebuild_batman_packet(struc void schedule_own_packet(struct hard_iface *hard_iface) { struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); + struct hard_iface *primary_if; unsigned long send_time; struct batman_packet *batman_packet; int vis_server; @@@ -253,6 -254,7 +254,7 @@@ return;
vis_server = atomic_read(&bat_priv->vis_mode); + primary_if = primary_if_get_selected(bat_priv);
/** * the interface gets activated here to avoid race conditions between @@@ -266,7 -268,7 +268,7 @@@
/* if local hna has changed and interface is a primary interface */ if ((atomic_read(&bat_priv->hna_local_changed)) && - (hard_iface == bat_priv->primary_if)) + (hard_iface == primary_if)) rebuild_batman_packet(bat_priv, hard_iface);
/** @@@ -284,7 -286,7 +286,7 @@@ else batman_packet->flags &= ~VIS_SERVER;
- if ((hard_iface == bat_priv->primary_if) && + if ((hard_iface == primary_if) && (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER)) batman_packet->gw_flags = (uint8_t)atomic_read(&bat_priv->gw_bandwidth); @@@ -299,6 -301,9 +301,9 @@@ hard_iface->packet_buff, hard_iface->packet_len, hard_iface, 1, send_time); + + if (primary_if) + hardif_free_ref(primary_if); }
void schedule_forward_packet(struct orig_node *orig_node, @@@ -393,7 -398,6 +398,6 @@@ static void _add_bcast_packet_to_list(s send_time); }
- #define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0) /* add a broadcast packet to the queue and setup timers. broadcast packets * are sent multiple times to increase probability for beeing received. * @@@ -404,6 -408,7 +408,7 @@@ * skb is freed. */ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) { + struct hard_iface *primary_if = NULL; struct forw_packet *forw_packet; struct bcast_packet *bcast_packet;
@@@ -412,7 -417,8 +417,8 @@@ goto out; }
- if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out;
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); @@@ -431,7 -437,7 +437,7 @@@ skb_reset_mac_header(skb);
forw_packet->skb = skb; - forw_packet->if_incoming = bat_priv->primary_if; + forw_packet->if_incoming = primary_if;
/* how often did we send the bcast packet ? */ forw_packet->num_packets = 0; @@@ -444,6 -450,8 +450,8 @@@ packet_free out_and_inc: atomic_inc(&bat_priv->bcast_queue_left); out: + if (primary_if) + hardif_free_ref(primary_if); return NETDEV_TX_BUSY; }
diff --combined net/batman-adv/soft-interface.c index 1f6f756,1772e2b..1772e2b --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -43,8 -43,6 +43,6 @@@ static void bat_get_drvinfo(struct net_ static u32 bat_get_msglevel(struct net_device *dev); static void bat_set_msglevel(struct net_device *dev, u32 value); static u32 bat_get_link(struct net_device *dev); - static u32 bat_get_rx_csum(struct net_device *dev); - static int bat_set_rx_csum(struct net_device *dev, u32 data);
static const struct ethtool_ops bat_ethtool_ops = { .get_settings = bat_get_settings, @@@ -52,8 -50,6 +50,6 @@@ .get_msglevel = bat_get_msglevel, .set_msglevel = bat_set_msglevel, .get_link = bat_get_link, - .get_rx_csum = bat_get_rx_csum, - .set_rx_csum = bat_set_rx_csum };
int my_skb_head_push(struct sk_buff *skb, unsigned int len) @@@ -215,13 -211,24 +211,24 @@@ int softif_neigh_seq_print_text(struct struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; + struct hard_iface *primary_if; struct hlist_node *node; struct softif_neigh *curr_softif_neigh; + int ret = 0;
- if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + } + + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name); @@@ -238,7 -245,10 +245,10 @@@ if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh);
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, @@@ -247,7 -257,8 +257,8 @@@ struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh; + struct softif_neigh *softif_neigh = NULL; + struct hard_iface *primary_if = NULL; struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) @@@ -257,28 -268,34 +268,34 @@@ batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
if (batman_packet->version != COMPAT_VERSION) - goto err; + goto out;
if (batman_packet->packet_type != BAT_PACKET) - goto err; + goto out;
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) - goto err; + goto out;
if (is_my_mac(batman_packet->orig)) - goto err; + goto out;
softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); - if (!softif_neigh) - goto err; + goto out;
curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (!curr_softif_neigh) + goto out; + if (curr_softif_neigh == softif_neigh) goto out;
+ primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + /* we got a neighbor but its mac is 'bigger' than ours */ - if (memcmp(bat_priv->primary_if->net_dev->dev_addr, + if (memcmp(primary_if->net_dev->dev_addr, softif_neigh->addr, ETH_ALEN) < 0) goto out;
@@@ -300,7 -317,7 +317,7 @@@ /* close own batX device and use softif_neigh as exit node */ if ((!curr_softif_neigh) && (memcmp(softif_neigh->addr, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { + primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point to %pM (vid: %d).\n", softif_neigh->addr, softif_neigh->vid); @@@ -310,12 -327,13 +327,13 @@@ }
out: - softif_neigh_free_ref(softif_neigh); - err: kfree_skb(skb); + if (softif_neigh) + softif_neigh_free_ref(softif_neigh); if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh); - + if (primary_if) + hardif_free_ref(primary_if); return; }
@@@ -371,6 -389,7 +389,7 @@@ int interface_tx(struct sk_buff *skb, s { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct hard_iface *primary_if = NULL; struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; struct softif_neigh *curr_softif_neigh = NULL; @@@ -420,7 -439,8 +439,8 @@@
/* ethernet packet should be broadcasted */ if (do_bcast) { - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto dropped;
if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) @@@ -436,7 -456,7 +456,7 @@@ /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ memcpy(bcast_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN);
/* set broadcast sequence number */ bcast_packet->seqno = @@@ -466,6 -486,8 +486,8 @@@ dropped_freed end: if (curr_softif_neigh) softif_neigh_free_ref(curr_softif_neigh); + if (primary_if) + hardif_free_ref(primary_if); return NETDEV_TX_OK; }
@@@ -736,12 -758,3 +758,3 @@@ static u32 bat_get_link(struct net_devi return 1; }
- static u32 bat_get_rx_csum(struct net_device *dev) - { - return 0; - } - - static int bat_set_rx_csum(struct net_device *dev, u32 data) - { - return -EOPNOTSUPP; - } diff --combined net/batman-adv/translation-table.c index 8d15b48,f931830..f931830 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@@ -22,6 -22,7 +22,7 @@@ #include "main.h" #include "translation-table.h" #include "soft-interface.h" + #include "hard-interface.h" #include "hash.h" #include "originator.h"
@@@ -237,16 -238,26 +238,26 @@@ int hna_local_seq_print_text(struct seq struct bat_priv *bat_priv = netdev_priv(net_dev); struct hashtable_t *hash = bat_priv->hna_local_hash; struct hna_local_entry *hna_local_entry; + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; size_t buf_size, pos; char *buff; - int i; + int i, ret = 0; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + }
- if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "Locally retrieved addresses (from %s) " @@@ -269,7 -280,8 +280,8 @@@ buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->hna_lhash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; }
buff[0] = '\0'; @@@ -291,7 -303,10 +303,10 @@@
seq_printf(seq, "%s", buff); kfree(buff); - return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
static void _hna_local_del(struct hlist_node *node, void *arg) @@@ -468,16 -483,26 +483,26 @@@ int hna_global_seq_print_text(struct se struct bat_priv *bat_priv = netdev_priv(net_dev); struct hashtable_t *hash = bat_priv->hna_global_hash; struct hna_global_entry *hna_global_entry; + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; size_t buf_size, pos; char *buff; - int i; + int i, ret = 0; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + goto out; + }
- if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", @@@ -499,7 -524,8 +524,8 @@@ buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->hna_ghash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } buff[0] = '\0'; pos = 0; @@@ -522,7 -548,10 +548,10 @@@
seq_printf(seq, "%s", buff); kfree(buff); - return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
static void _hna_global_del_orig(struct bat_priv *bat_priv, diff --combined net/batman-adv/types.h index 75123b1,947bafc..947bafc --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@@ -149,7 -149,6 +149,6 @@@ struct bat_priv struct hlist_head softif_neigh_list; struct softif_neigh __rcu *softif_neigh; struct debug_log *debug_log; - struct hard_iface *primary_if; struct kobject *mesh_obj; struct dentry *debug_dir; struct hlist_head forw_bat_list; @@@ -174,6 -173,7 +173,7 @@@ struct delayed_work orig_work; struct delayed_work vis_work; struct gw_node __rcu *curr_gw; /* rcu protected pointer */ + struct hard_iface __rcu *primary_if; /* rcu protected pointer */ struct vis_info *my_vis_info; };
diff --combined net/batman-adv/unicast.c index d46acc8,b46cbf1..b46cbf1 --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@@ -221,15 -221,17 +221,17 @@@ int frag_send_skb(struct sk_buff *skb, 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 +256,7 @@@ 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 +271,17 @@@
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) diff --combined net/batman-adv/vis.c index d4cc4f5,c8f571d..c8f571d --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@@ -204,6 -204,7 +204,7 @@@ static ssize_t vis_data_read_entry(cha
int vis_seq_print_text(struct seq_file *seq, void *offset) { + struct hard_iface *primary_if; struct hlist_node *node; struct hlist_head *head; struct vis_info *info; @@@ -215,15 -216,18 +216,18 @@@ HLIST_HEAD(vis_if_list); struct if_list_entry *entry; struct hlist_node *pos, *n; - int i, j; + int i, j, ret = 0; int vis_server = atomic_read(&bat_priv->vis_mode); size_t buff_pos, buf_size; char *buff; int compare;
- if ((!bat_priv->primary_if) || - (vis_server == VIS_TYPE_CLIENT_UPDATE)) - return 0; + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + if (vis_server == VIS_TYPE_CLIENT_UPDATE) + goto out;
buf_size = 1; /* Estimate length */ @@@ -270,7 -274,8 +274,8 @@@ buff = kmalloc(buf_size, GFP_ATOMIC); if (!buff) { spin_unlock_bh(&bat_priv->vis_hash_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } buff[0] = '\0'; buff_pos = 0; @@@ -328,7 -333,10 +333,10 @@@ seq_printf(seq, "%s", buff); kfree(buff);
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
/* add the info packet to the send list, if it was not @@@ -815,16 -823,20 +823,20 @@@ out /* only send one vis packet. called from send_vis_packets() */ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { + struct hard_iface *primary_if; struct vis_packet *packet;
+ primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + packet = (struct vis_packet *)info->skb_packet->data; if (packet->ttl < 2) { pr_debug("Error - can't send vis packet: ttl exceeded\n"); - return; + goto out; }
- memcpy(packet->sender_orig, bat_priv->primary_if->net_dev->dev_addr, - ETH_ALEN); + memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN); packet->ttl--;
if (is_broadcast_ether_addr(packet->target_orig)) @@@ -832,6 -844,10 +844,10 @@@ else unicast_vis_packet(bat_priv, info); packet->ttl++; /* restore TTL */ + + out: + if (primary_if) + hardif_free_ref(primary_if); }
/* called from timer; send (and maybe generate) vis packet. */ @@@ -858,8 -874,7 +874,7 @@@ static void send_vis_packets(struct wor kref_get(&info->refcount); spin_unlock_bh(&bat_priv->vis_hash_lock);
- if (bat_priv->primary_if) - send_vis_packet(bat_priv, info); + send_vis_packet(bat_priv, info);
spin_lock_bh(&bat_priv->vis_hash_lock); send_list_del(info);