Commit dcfd9cdc authored by David S. Miller's avatar David S. Miller

Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge

parents 56157872 32ae9b22
...@@ -95,7 +95,6 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet, ...@@ -95,7 +95,6 @@ static bool can_aggregate_with(struct batman_packet *new_batman_packet,
return false; 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 */ /* create a new aggregated packet and add this packet to it */
static void new_aggregated_packet(unsigned char *packet_buff, int packet_len, static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
unsigned long send_time, bool direct_link, unsigned long send_time, bool direct_link,
......
...@@ -127,7 +127,7 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -127,7 +127,7 @@ void gw_election(struct bat_priv *bat_priv)
return; return;
curr_gw = gw_get_selected_gw_node(bat_priv); curr_gw = gw_get_selected_gw_node(bat_priv);
if (!curr_gw) if (curr_gw)
goto out; goto out;
rcu_read_lock(); rcu_read_lock();
...@@ -310,9 +310,13 @@ void gw_node_update(struct bat_priv *bat_priv, ...@@ -310,9 +310,13 @@ void gw_node_update(struct bat_priv *bat_priv,
struct hlist_node *node; struct hlist_node *node;
struct gw_node *gw_node, *curr_gw; 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); curr_gw = gw_get_selected_gw_node(bat_priv);
if (!curr_gw)
goto out;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
...@@ -350,7 +354,7 @@ void gw_node_update(struct bat_priv *bat_priv, ...@@ -350,7 +354,7 @@ void gw_node_update(struct bat_priv *bat_priv,
gw_deselect(bat_priv); gw_deselect(bat_priv);
unlock: unlock:
rcu_read_unlock(); rcu_read_unlock();
out:
if (curr_gw) if (curr_gw)
gw_node_free_ref(curr_gw); gw_node_free_ref(curr_gw);
} }
...@@ -435,30 +439,32 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -435,30 +439,32 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
{ {
struct net_device *net_dev = (struct net_device *)seq->private; struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hard_iface *primary_if;
struct gw_node *gw_node; struct gw_node *gw_node;
struct hlist_node *node; struct hlist_node *node;
int gw_count = 0; int gw_count = 0, ret = 0;
if (!bat_priv->primary_if) { primary_if = primary_if_get_selected(bat_priv);
if (!primary_if) {
return seq_printf(seq, "BATMAN mesh %s disabled - please " ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
"specify interfaces to enable it\n", "specify interfaces to enable it\n",
net_dev->name); net_dev->name);
goto out;
} }
if (bat_priv->primary_if->if_status != IF_ACTIVE) { if (primary_if->if_status != IF_ACTIVE) {
ret = seq_printf(seq, "BATMAN mesh %s disabled - "
return seq_printf(seq, "BATMAN mesh %s disabled - "
"primary interface not active\n", "primary interface not active\n",
net_dev->name); net_dev->name);
goto out;
} }
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " 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", "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
"Gateway", "#", TQ_MAX_VALUE, "Nexthop", "Gateway", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR,
bat_priv->primary_if->net_dev->name, primary_if->net_dev->name,
bat_priv->primary_if->net_dev->dev_addr, net_dev->name); primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
...@@ -476,7 +482,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -476,7 +482,10 @@ int gw_client_seq_print_text(struct seq_file *seq, void *offset)
if (gw_count == 0) if (gw_count == 0)
seq_printf(seq, "No gateways in range ...\n"); 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) int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
......
...@@ -110,47 +110,60 @@ static struct hard_iface *hardif_get_active(struct net_device *soft_iface) ...@@ -110,47 +110,60 @@ static struct hard_iface *hardif_get_active(struct net_device *soft_iface)
return hard_iface; 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 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 *) vis_packet = (struct vis_packet *)
bat_priv->my_vis_info->skb_packet->data; bat_priv->my_vis_info->skb_packet->data;
memcpy(vis_packet->vis_orig, memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
memcpy(vis_packet->sender_orig, 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, static void primary_if_select(struct bat_priv *bat_priv,
struct hard_iface *hard_iface) struct hard_iface *new_hard_iface)
{ {
struct hard_iface *curr_hard_iface;
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
struct hard_iface *old_if;
if (hard_iface && !atomic_inc_not_zero(&hard_iface->refcount)) spin_lock_bh(&hardif_list_lock);
hard_iface = NULL;
old_if = bat_priv->primary_if; if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
bat_priv->primary_if = hard_iface; new_hard_iface = NULL;
if (old_if) curr_hard_iface = bat_priv->primary_if;
hardif_free_ref(old_if); rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
if (!bat_priv->primary_if) if (curr_hard_iface)
return; 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->flags = PRIMARIES_FIRST_HOP;
batman_packet->ttl = TTL; 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 * hacky trick to make sure that we send the HNA information via
* our new primary interface * our new primary interface
*/ */
atomic_set(&bat_priv->hna_local_changed, 1); 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) static bool hardif_is_iface_up(struct hard_iface *hard_iface)
...@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface) ...@@ -236,9 +249,10 @@ void update_min_mtu(struct net_device *soft_iface)
static void hardif_activate_interface(struct hard_iface *hard_iface) static void hardif_activate_interface(struct hard_iface *hard_iface)
{ {
struct bat_priv *bat_priv; struct bat_priv *bat_priv;
struct hard_iface *primary_if = NULL;
if (hard_iface->if_status != IF_INACTIVE) if (hard_iface->if_status != IF_INACTIVE)
return; goto out;
bat_priv = netdev_priv(hard_iface->soft_iface); bat_priv = netdev_priv(hard_iface->soft_iface);
...@@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface) ...@@ -249,14 +263,18 @@ static void hardif_activate_interface(struct hard_iface *hard_iface)
* the first active interface becomes our primary interface or * the first active interface becomes our primary interface or
* the next active interface after the old primay interface was removed * the next active interface after the old primay interface was removed
*/ */
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
set_primary_if(bat_priv, hard_iface); if (!primary_if)
primary_if_select(bat_priv, hard_iface);
bat_info(hard_iface->soft_iface, "Interface activated: %s\n", bat_info(hard_iface->soft_iface, "Interface activated: %s\n",
hard_iface->net_dev->name); hard_iface->net_dev->name);
update_min_mtu(hard_iface->soft_iface); 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) static void hardif_deactivate_interface(struct hard_iface *hard_iface)
...@@ -386,12 +404,13 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name) ...@@ -386,12 +404,13 @@ int hardif_enable_interface(struct hard_iface *hard_iface, char *iface_name)
void hardif_disable_interface(struct hard_iface *hard_iface) void hardif_disable_interface(struct hard_iface *hard_iface)
{ {
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_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) if (hard_iface->if_status == IF_ACTIVE)
hardif_deactivate_interface(hard_iface); hardif_deactivate_interface(hard_iface);
if (hard_iface->if_status != IF_INACTIVE) if (hard_iface->if_status != IF_INACTIVE)
return; goto out;
bat_info(hard_iface->soft_iface, "Removing interface: %s\n", bat_info(hard_iface->soft_iface, "Removing interface: %s\n",
hard_iface->net_dev->name); hard_iface->net_dev->name);
...@@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface) ...@@ -400,11 +419,12 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
bat_priv->num_ifaces--; bat_priv->num_ifaces--;
orig_hash_del_if(hard_iface, 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; struct hard_iface *new_if;
new_if = hardif_get_active(hard_iface->soft_iface); 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) if (new_if)
hardif_free_ref(new_if); hardif_free_ref(new_if);
...@@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface) ...@@ -425,6 +445,10 @@ void hardif_disable_interface(struct hard_iface *hard_iface)
hard_iface->soft_iface = NULL; hard_iface->soft_iface = NULL;
hardif_free_ref(hard_iface); 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) static struct hard_iface *hardif_add_interface(struct net_device *net_dev)
...@@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this, ...@@ -514,6 +538,7 @@ static int hard_if_event(struct notifier_block *this,
{ {
struct net_device *net_dev = (struct net_device *)ptr; struct net_device *net_dev = (struct net_device *)ptr;
struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev);
struct hard_iface *primary_if = NULL;
struct bat_priv *bat_priv; struct bat_priv *bat_priv;
if (!hard_iface && event == NETDEV_REGISTER) if (!hard_iface && event == NETDEV_REGISTER)
...@@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this, ...@@ -549,8 +574,12 @@ static int hard_if_event(struct notifier_block *this,
update_mac_addresses(hard_iface); update_mac_addresses(hard_iface);
bat_priv = netdev_priv(hard_iface->soft_iface); bat_priv = netdev_priv(hard_iface->soft_iface);
if (hard_iface == bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
update_primary_addr(bat_priv); if (!primary_if)
goto hardif_put;
if (hard_iface == primary_if)
primary_if_update_addr(bat_priv);
break; break;
default: default:
break; break;
...@@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this, ...@@ -559,6 +588,8 @@ static int hard_if_event(struct notifier_block *this,
hardif_put: hardif_put:
hardif_free_ref(hard_iface); hardif_free_ref(hard_iface);
out: out:
if (primary_if)
hardif_free_ref(primary_if);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
...@@ -45,4 +45,22 @@ static inline void hardif_free_ref(struct hard_iface *hard_iface) ...@@ -45,4 +45,22 @@ static inline void hardif_free_ref(struct hard_iface *hard_iface)
call_rcu(&hard_iface->rcu, hardif_free_rcu); 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_ */ #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */
...@@ -153,6 +153,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -153,6 +153,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
{ {
struct socket_client *socket_client = file->private_data; struct socket_client *socket_client = file->private_data;
struct bat_priv *bat_priv = socket_client->bat_priv; struct bat_priv *bat_priv = socket_client->bat_priv;
struct hard_iface *primary_if = NULL;
struct sk_buff *skb; struct sk_buff *skb;
struct icmp_packet_rr *icmp_packet; struct icmp_packet_rr *icmp_packet;
...@@ -167,15 +168,21 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -167,15 +168,21 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
return -EINVAL; return -EINVAL;
} }
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
return -EFAULT;
if (!primary_if) {
len = -EFAULT;
goto out;
}
if (len >= sizeof(struct icmp_packet_rr)) if (len >= sizeof(struct icmp_packet_rr))
packet_len = sizeof(struct icmp_packet_rr); packet_len = sizeof(struct icmp_packet_rr);
skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr)); skb = dev_alloc_skb(packet_len + sizeof(struct ethhdr));
if (!skb) if (!skb) {
return -ENOMEM; len = -ENOMEM;
goto out;
}
skb_reserve(skb, sizeof(struct ethhdr)); skb_reserve(skb, sizeof(struct ethhdr));
icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len); icmp_packet = (struct icmp_packet_rr *)skb_put(skb, packet_len);
...@@ -233,7 +240,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -233,7 +240,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
goto dst_unreach; goto dst_unreach;
memcpy(icmp_packet->orig, 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)) if (packet_len == sizeof(struct icmp_packet_rr))
memcpy(icmp_packet->rr, memcpy(icmp_packet->rr,
...@@ -248,6 +255,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff, ...@@ -248,6 +255,8 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
free_skb: free_skb:
kfree_skb(skb); kfree_skb(skb);
out: out:
if (primary_if)
hardif_free_ref(primary_if);
if (neigh_node) if (neigh_node)
neigh_node_free_ref(neigh_node); neigh_node_free_ref(neigh_node);
if (orig_node) if (orig_node)
......
...@@ -175,4 +175,6 @@ static inline int compare_eth(void *data1, void *data2) ...@@ -175,4 +175,6 @@ static inline int compare_eth(void *data1, void *data2)
return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0); 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_ */ #endif /* _NET_BATMAN_ADV_MAIN_H_ */
...@@ -405,29 +405,34 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) ...@@ -405,29 +405,34 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
struct hashtable_t *hash = bat_priv->orig_hash; struct hashtable_t *hash = bat_priv->orig_hash;
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct hlist_head *head; struct hlist_head *head;
struct hard_iface *primary_if;
struct orig_node *orig_node; struct orig_node *orig_node;
struct neigh_node *neigh_node, *neigh_node_tmp; struct neigh_node *neigh_node, *neigh_node_tmp;
int batman_count = 0; int batman_count = 0;
int last_seen_secs; int last_seen_secs;
int last_seen_msecs; int last_seen_msecs;
int i; int i, ret = 0;
primary_if = primary_if_get_selected(bat_priv);
if ((!bat_priv->primary_if) || if (!primary_if) {
(bat_priv->primary_if->if_status != IF_ACTIVE)) { ret = seq_printf(seq, "BATMAN mesh %s disabled - "
if (!bat_priv->primary_if)
return seq_printf(seq, "BATMAN mesh %s disabled - "
"please specify interfaces to enable it\n", "please specify interfaces to enable it\n",
net_dev->name); net_dev->name);
goto out;
}
return seq_printf(seq, "BATMAN mesh %s " if (primary_if->if_status != IF_ACTIVE) {
ret = seq_printf(seq, "BATMAN mesh %s "
"disabled - primary interface not active\n", "disabled - primary interface not active\n",
net_dev->name); net_dev->name);
goto out;
} }
seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
SOURCE_VERSION, REVISION_VERSION_STR, SOURCE_VERSION, REVISION_VERSION_STR,
bat_priv->primary_if->net_dev->name, primary_if->net_dev->name,
bat_priv->primary_if->net_dev->dev_addr, net_dev->name); primary_if->net_dev->dev_addr, net_dev->name);
seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
"Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", "Potential nexthops"); "outgoingIF", "Potential nexthops");
...@@ -474,7 +479,10 @@ int orig_seq_print_text(struct seq_file *seq, void *offset) ...@@ -474,7 +479,10 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
if (batman_count == 0) if (batman_count == 0)
seq_printf(seq, "No batman nodes in range ...\n"); 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) static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
......
...@@ -904,6 +904,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface) ...@@ -904,6 +904,7 @@ int recv_bat_packet(struct sk_buff *skb, struct hard_iface *hard_iface)
static int recv_my_icmp_packet(struct bat_priv *bat_priv, static int recv_my_icmp_packet(struct bat_priv *bat_priv,
struct sk_buff *skb, size_t icmp_len) struct sk_buff *skb, size_t icmp_len)
{ {
struct hard_iface *primary_if = NULL;
struct orig_node *orig_node = NULL; struct orig_node *orig_node = NULL;
struct neigh_node *router = NULL; struct neigh_node *router = NULL;
struct icmp_packet_rr *icmp_packet; struct icmp_packet_rr *icmp_packet;
...@@ -917,7 +918,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ...@@ -917,7 +918,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
goto out; goto out;
} }
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out; goto out;
/* answer echo request (ping) */ /* answer echo request (ping) */
...@@ -937,8 +939,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ...@@ -937,8 +939,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
icmp_packet = (struct icmp_packet_rr *)skb->data; icmp_packet = (struct icmp_packet_rr *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
memcpy(icmp_packet->orig, memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
icmp_packet->msg_type = ECHO_REPLY; icmp_packet->msg_type = ECHO_REPLY;
icmp_packet->ttl = TTL; icmp_packet->ttl = TTL;
...@@ -946,6 +947,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ...@@ -946,6 +947,8 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
out: out:
if (primary_if)
hardif_free_ref(primary_if);
if (router) if (router)
neigh_node_free_ref(router); neigh_node_free_ref(router);
if (orig_node) if (orig_node)
...@@ -956,6 +959,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv, ...@@ -956,6 +959,7 @@ static int recv_my_icmp_packet(struct bat_priv *bat_priv,
static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct hard_iface *primary_if = NULL;
struct orig_node *orig_node = NULL; struct orig_node *orig_node = NULL;
struct neigh_node *router = NULL; struct neigh_node *router = NULL;
struct icmp_packet *icmp_packet; struct icmp_packet *icmp_packet;
...@@ -971,7 +975,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ...@@ -971,7 +975,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
goto out; goto out;
} }
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out; goto out;
/* get routing information */ /* get routing information */
...@@ -990,8 +995,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ...@@ -990,8 +995,7 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
icmp_packet = (struct icmp_packet *)skb->data; icmp_packet = (struct icmp_packet *)skb->data;
memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN); memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
memcpy(icmp_packet->orig, memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
icmp_packet->msg_type = TTL_EXCEEDED; icmp_packet->msg_type = TTL_EXCEEDED;
icmp_packet->ttl = TTL; icmp_packet->ttl = TTL;
...@@ -999,6 +1003,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv, ...@@ -999,6 +1003,8 @@ static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
out: out:
if (primary_if)
hardif_free_ref(primary_if);
if (router) if (router)
neigh_node_free_ref(router); neigh_node_free_ref(router);
if (orig_node) if (orig_node)
...@@ -1310,13 +1316,10 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -1310,13 +1316,10 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
} }
/* get routing information */ /* get routing information */
rcu_read_lock();
orig_node = orig_hash_find(bat_priv, unicast_packet->dest); orig_node = orig_hash_find(bat_priv, unicast_packet->dest);
if (!orig_node) if (!orig_node)
goto unlock; goto out;
rcu_read_unlock();
/* find_router() increases neigh_nodes refcount if found. */ /* find_router() increases neigh_nodes refcount if found. */
neigh_node = find_router(bat_priv, orig_node, recv_if); neigh_node = find_router(bat_priv, orig_node, recv_if);
...@@ -1362,10 +1365,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -1362,10 +1365,7 @@ int route_unicast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
/* route it */ /* route it */
send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
goto out;
unlock:
rcu_read_unlock();
out: out:
if (neigh_node) if (neigh_node)
neigh_node_free_ref(neigh_node); neigh_node_free_ref(neigh_node);
...@@ -1464,13 +1464,10 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -1464,13 +1464,10 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
if (bcast_packet->ttl < 2) if (bcast_packet->ttl < 2)
goto out; goto out;
rcu_read_lock();
orig_node = orig_hash_find(bat_priv, bcast_packet->orig); orig_node = orig_hash_find(bat_priv, bcast_packet->orig);
if (!orig_node) if (!orig_node)
goto rcu_unlock; goto out;
rcu_read_unlock();
spin_lock_bh(&orig_node->bcast_seqno_lock); spin_lock_bh(&orig_node->bcast_seqno_lock);
...@@ -1501,9 +1498,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if) ...@@ -1501,9 +1498,6 @@ int recv_bcast_packet(struct sk_buff *skb, struct hard_iface *recv_if)
ret = NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
goto out; goto out;
rcu_unlock:
rcu_read_unlock();
goto out;
spin_unlock: spin_unlock:
spin_unlock_bh(&orig_node->bcast_seqno_lock); spin_unlock_bh(&orig_node->bcast_seqno_lock);
out: out:
......
...@@ -244,6 +244,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv, ...@@ -244,6 +244,7 @@ static void rebuild_batman_packet(struct bat_priv *bat_priv,
void schedule_own_packet(struct hard_iface *hard_iface) void schedule_own_packet(struct hard_iface *hard_iface)
{ {
struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct bat_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
struct hard_iface *primary_if;
unsigned long send_time; unsigned long send_time;
struct batman_packet *batman_packet; struct batman_packet *batman_packet;
int vis_server; int vis_server;
...@@ -253,6 +254,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) ...@@ -253,6 +254,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
return; return;
vis_server = atomic_read(&bat_priv->vis_mode); 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 * the interface gets activated here to avoid race conditions between
...@@ -266,7 +268,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) ...@@ -266,7 +268,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
/* if local hna has changed and interface is a primary interface */ /* if local hna has changed and interface is a primary interface */
if ((atomic_read(&bat_priv->hna_local_changed)) && 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); rebuild_batman_packet(bat_priv, hard_iface);
/** /**
...@@ -284,7 +286,7 @@ void schedule_own_packet(struct hard_iface *hard_iface) ...@@ -284,7 +286,7 @@ void schedule_own_packet(struct hard_iface *hard_iface)
else else
batman_packet->flags &= ~VIS_SERVER; 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)) (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER))
batman_packet->gw_flags = batman_packet->gw_flags =
(uint8_t)atomic_read(&bat_priv->gw_bandwidth); (uint8_t)atomic_read(&bat_priv->gw_bandwidth);
...@@ -299,6 +301,9 @@ void schedule_own_packet(struct hard_iface *hard_iface) ...@@ -299,6 +301,9 @@ void schedule_own_packet(struct hard_iface *hard_iface)
hard_iface->packet_buff, hard_iface->packet_buff,
hard_iface->packet_len, hard_iface->packet_len,
hard_iface, 1, send_time); hard_iface, 1, send_time);
if (primary_if)
hardif_free_ref(primary_if);
} }
void schedule_forward_packet(struct orig_node *orig_node, void schedule_forward_packet(struct orig_node *orig_node,
...@@ -393,7 +398,6 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, ...@@ -393,7 +398,6 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
send_time); 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 /* add a broadcast packet to the queue and setup timers. broadcast packets
* are sent multiple times to increase probability for beeing received. * are sent multiple times to increase probability for beeing received.
* *
...@@ -404,6 +408,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv, ...@@ -404,6 +408,7 @@ static void _add_bcast_packet_to_list(struct bat_priv *bat_priv,
* skb is freed. */ * skb is freed. */
int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) 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 forw_packet *forw_packet;
struct bcast_packet *bcast_packet; struct bcast_packet *bcast_packet;
...@@ -412,7 +417,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) ...@@ -412,7 +417,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
goto out; goto out;
} }
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto out; goto out;
forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC); forw_packet = kmalloc(sizeof(struct forw_packet), GFP_ATOMIC);
...@@ -431,7 +437,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) ...@@ -431,7 +437,7 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
forw_packet->skb = 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 ? */ /* how often did we send the bcast packet ? */
forw_packet->num_packets = 0; forw_packet->num_packets = 0;
...@@ -444,6 +450,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb) ...@@ -444,6 +450,8 @@ int add_bcast_packet_to_list(struct bat_priv *bat_priv, struct sk_buff *skb)
out_and_inc: out_and_inc:
atomic_inc(&bat_priv->bcast_queue_left); atomic_inc(&bat_priv->bcast_queue_left);
out: out:
if (primary_if)
hardif_free_ref(primary_if);
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
......
...@@ -211,13 +211,24 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) ...@@ -211,13 +211,24 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
struct net_device *net_dev = (struct net_device *)seq->private; struct net_device *net_dev = (struct net_device *)seq->private;
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct softif_neigh *softif_neigh; struct softif_neigh *softif_neigh;
struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
struct softif_neigh *curr_softif_neigh; struct softif_neigh *curr_softif_neigh;
int ret = 0;
if (!bat_priv->primary_if) { primary_if = primary_if_get_selected(bat_priv);
return seq_printf(seq, "BATMAN mesh %s disabled - " if (!primary_if) {
ret = seq_printf(seq, "BATMAN mesh %s disabled - "
"please specify interfaces to enable it\n", "please specify interfaces to enable it\n",
net_dev->name); 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); seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
...@@ -234,7 +245,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) ...@@ -234,7 +245,10 @@ int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)
if (curr_softif_neigh) if (curr_softif_neigh)
softif_neigh_free_ref(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, static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
...@@ -243,7 +257,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -243,7 +257,8 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
struct bat_priv *bat_priv = netdev_priv(dev); struct bat_priv *bat_priv = netdev_priv(dev);
struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batman_packet *batman_packet; 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; struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
...@@ -253,28 +268,34 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -253,28 +268,34 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN); batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
if (batman_packet->version != COMPAT_VERSION) if (batman_packet->version != COMPAT_VERSION)
goto err; goto out;
if (batman_packet->packet_type != BAT_PACKET) if (batman_packet->packet_type != BAT_PACKET)
goto err; goto out;
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) if (!(batman_packet->flags & PRIMARIES_FIRST_HOP))
goto err; goto out;
if (is_my_mac(batman_packet->orig)) if (is_my_mac(batman_packet->orig))
goto err; goto out;
softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid);
if (!softif_neigh) if (!softif_neigh)
goto err; goto out;
curr_softif_neigh = softif_neigh_get_selected(bat_priv); curr_softif_neigh = softif_neigh_get_selected(bat_priv);
if (!curr_softif_neigh)
goto out;
if (curr_softif_neigh == softif_neigh) if (curr_softif_neigh == softif_neigh)
goto out; 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 */ /* 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) softif_neigh->addr, ETH_ALEN) < 0)
goto out; goto out;
...@@ -296,7 +317,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -296,7 +317,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
/* close own batX device and use softif_neigh as exit node */ /* close own batX device and use softif_neigh as exit node */
if ((!curr_softif_neigh) && if ((!curr_softif_neigh) &&
(memcmp(softif_neigh->addr, (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, bat_dbg(DBG_ROUTES, bat_priv,
"Setting mesh exit point to %pM (vid: %d).\n", "Setting mesh exit point to %pM (vid: %d).\n",
softif_neigh->addr, softif_neigh->vid); softif_neigh->addr, softif_neigh->vid);
...@@ -306,12 +327,13 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, ...@@ -306,12 +327,13 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,
} }
out: out:
softif_neigh_free_ref(softif_neigh);
err:
kfree_skb(skb); kfree_skb(skb);
if (softif_neigh)
softif_neigh_free_ref(softif_neigh);
if (curr_softif_neigh) if (curr_softif_neigh)
softif_neigh_free_ref(curr_softif_neigh); softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
return; return;
} }
...@@ -367,6 +389,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) ...@@ -367,6 +389,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
{ {
struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bat_priv *bat_priv = netdev_priv(soft_iface);
struct hard_iface *primary_if = NULL;
struct bcast_packet *bcast_packet; struct bcast_packet *bcast_packet;
struct vlan_ethhdr *vhdr; struct vlan_ethhdr *vhdr;
struct softif_neigh *curr_softif_neigh = NULL; struct softif_neigh *curr_softif_neigh = NULL;
...@@ -416,7 +439,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) ...@@ -416,7 +439,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
/* ethernet packet should be broadcasted */ /* ethernet packet should be broadcasted */
if (do_bcast) { if (do_bcast) {
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto dropped; goto dropped;
if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
...@@ -432,7 +456,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) ...@@ -432,7 +456,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
/* hw address of first interface is the orig mac because only /* hw address of first interface is the orig mac because only
* this mac is known throughout the mesh */ * this mac is known throughout the mesh */
memcpy(bcast_packet->orig, 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 */ /* set broadcast sequence number */
bcast_packet->seqno = bcast_packet->seqno =
...@@ -462,6 +486,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface) ...@@ -462,6 +486,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
end: end:
if (curr_softif_neigh) if (curr_softif_neigh)
softif_neigh_free_ref(curr_softif_neigh); softif_neigh_free_ref(curr_softif_neigh);
if (primary_if)
hardif_free_ref(primary_if);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "main.h" #include "main.h"
#include "translation-table.h" #include "translation-table.h"
#include "soft-interface.h" #include "soft-interface.h"
#include "hard-interface.h"
#include "hash.h" #include "hash.h"
#include "originator.h" #include "originator.h"
...@@ -237,16 +238,26 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) ...@@ -237,16 +238,26 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->hna_local_hash; struct hashtable_t *hash = bat_priv->hna_local_hash;
struct hna_local_entry *hna_local_entry; struct hna_local_entry *hna_local_entry;
struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
size_t buf_size, pos; size_t buf_size, pos;
char *buff; char *buff;
int i; int i, ret = 0;
if (!bat_priv->primary_if) { primary_if = primary_if_get_selected(bat_priv);
return seq_printf(seq, "BATMAN mesh %s disabled - " if (!primary_if) {
ret = seq_printf(seq, "BATMAN mesh %s disabled - "
"please specify interfaces to enable it\n", "please specify interfaces to enable it\n",
net_dev->name); 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, "Locally retrieved addresses (from %s) " seq_printf(seq, "Locally retrieved addresses (from %s) "
...@@ -269,7 +280,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) ...@@ -269,7 +280,8 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC); buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) { if (!buff) {
spin_unlock_bh(&bat_priv->hna_lhash_lock); spin_unlock_bh(&bat_priv->hna_lhash_lock);
return -ENOMEM; ret = -ENOMEM;
goto out;
} }
buff[0] = '\0'; buff[0] = '\0';
...@@ -291,7 +303,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset) ...@@ -291,7 +303,10 @@ int hna_local_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff); seq_printf(seq, "%s", buff);
kfree(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) static void _hna_local_del(struct hlist_node *node, void *arg)
...@@ -468,16 +483,26 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) ...@@ -468,16 +483,26 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
struct bat_priv *bat_priv = netdev_priv(net_dev); struct bat_priv *bat_priv = netdev_priv(net_dev);
struct hashtable_t *hash = bat_priv->hna_global_hash; struct hashtable_t *hash = bat_priv->hna_global_hash;
struct hna_global_entry *hna_global_entry; struct hna_global_entry *hna_global_entry;
struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
size_t buf_size, pos; size_t buf_size, pos;
char *buff; char *buff;
int i; int i, ret = 0;
if (!bat_priv->primary_if) { primary_if = primary_if_get_selected(bat_priv);
return seq_printf(seq, "BATMAN mesh %s disabled - " if (!primary_if) {
"please specify interfaces to enable it\n", ret = seq_printf(seq, "BATMAN mesh %s disabled - please "
"specify interfaces to enable it\n",
net_dev->name); 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, "Globally announced HNAs received via the mesh %s\n", seq_printf(seq, "Globally announced HNAs received via the mesh %s\n",
...@@ -499,7 +524,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) ...@@ -499,7 +524,8 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC); buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) { if (!buff) {
spin_unlock_bh(&bat_priv->hna_ghash_lock); spin_unlock_bh(&bat_priv->hna_ghash_lock);
return -ENOMEM; ret = -ENOMEM;
goto out;
} }
buff[0] = '\0'; buff[0] = '\0';
pos = 0; pos = 0;
...@@ -522,7 +548,10 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset) ...@@ -522,7 +548,10 @@ int hna_global_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff); seq_printf(seq, "%s", buff);
kfree(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, static void _hna_global_del_orig(struct bat_priv *bat_priv,
......
...@@ -149,7 +149,6 @@ struct bat_priv { ...@@ -149,7 +149,6 @@ struct bat_priv {
struct hlist_head softif_neigh_list; struct hlist_head softif_neigh_list;
struct softif_neigh __rcu *softif_neigh; struct softif_neigh __rcu *softif_neigh;
struct debug_log *debug_log; struct debug_log *debug_log;
struct hard_iface *primary_if;
struct kobject *mesh_obj; struct kobject *mesh_obj;
struct dentry *debug_dir; struct dentry *debug_dir;
struct hlist_head forw_bat_list; struct hlist_head forw_bat_list;
...@@ -174,6 +173,7 @@ struct bat_priv { ...@@ -174,6 +173,7 @@ struct bat_priv {
struct delayed_work orig_work; struct delayed_work orig_work;
struct delayed_work vis_work; struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */ struct gw_node __rcu *curr_gw; /* rcu protected pointer */
struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info; struct vis_info *my_vis_info;
}; };
......
...@@ -221,15 +221,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -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 hard_iface *hard_iface, uint8_t dstaddr[])
{ {
struct unicast_packet tmp_uc, *unicast_packet; struct unicast_packet tmp_uc, *unicast_packet;
struct hard_iface *primary_if;
struct sk_buff *frag_skb; struct sk_buff *frag_skb;
struct unicast_frag_packet *frag1, *frag2; struct unicast_frag_packet *frag1, *frag2;
int uc_hdr_len = sizeof(struct unicast_packet); int uc_hdr_len = sizeof(struct unicast_packet);
int ucf_hdr_len = sizeof(struct unicast_frag_packet); int ucf_hdr_len = sizeof(struct unicast_frag_packet);
int data_len = skb->len - uc_hdr_len; int data_len = skb->len - uc_hdr_len;
int large_tail = 0; int large_tail = 0, ret = NET_RX_DROP;
uint16_t seqno; uint16_t seqno;
if (!bat_priv->primary_if) primary_if = primary_if_get_selected(bat_priv);
if (!primary_if)
goto dropped; goto dropped;
frag_skb = dev_alloc_skb(data_len - (data_len / 2) + ucf_hdr_len); 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,7 +256,7 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv,
frag1->version = COMPAT_VERSION; frag1->version = COMPAT_VERSION;
frag1->packet_type = BAT_UNICAST_FRAG; 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)); memcpy(frag2, frag1, sizeof(struct unicast_frag_packet));
if (data_len & 1) if (data_len & 1)
...@@ -269,13 +271,17 @@ int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, ...@@ -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(skb, hard_iface, dstaddr);
send_skb_packet(frag_skb, hard_iface, dstaddr); send_skb_packet(frag_skb, hard_iface, dstaddr);
return NET_RX_SUCCESS; ret = NET_RX_SUCCESS;
goto out;
drop_frag: drop_frag:
kfree_skb(frag_skb); kfree_skb(frag_skb);
dropped: dropped:
kfree_skb(skb); 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) int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
......
...@@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, ...@@ -204,6 +204,7 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry,
int vis_seq_print_text(struct seq_file *seq, void *offset) int vis_seq_print_text(struct seq_file *seq, void *offset)
{ {
struct hard_iface *primary_if;
struct hlist_node *node; struct hlist_node *node;
struct hlist_head *head; struct hlist_head *head;
struct vis_info *info; struct vis_info *info;
...@@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) ...@@ -215,15 +216,18 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
HLIST_HEAD(vis_if_list); HLIST_HEAD(vis_if_list);
struct if_list_entry *entry; struct if_list_entry *entry;
struct hlist_node *pos, *n; struct hlist_node *pos, *n;
int i, j; int i, j, ret = 0;
int vis_server = atomic_read(&bat_priv->vis_mode); int vis_server = atomic_read(&bat_priv->vis_mode);
size_t buff_pos, buf_size; size_t buff_pos, buf_size;
char *buff; char *buff;
int compare; int compare;
if ((!bat_priv->primary_if) || primary_if = primary_if_get_selected(bat_priv);
(vis_server == VIS_TYPE_CLIENT_UPDATE)) if (!primary_if)
return 0; goto out;
if (vis_server == VIS_TYPE_CLIENT_UPDATE)
goto out;
buf_size = 1; buf_size = 1;
/* Estimate length */ /* Estimate length */
...@@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) ...@@ -270,7 +274,8 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
buff = kmalloc(buf_size, GFP_ATOMIC); buff = kmalloc(buf_size, GFP_ATOMIC);
if (!buff) { if (!buff) {
spin_unlock_bh(&bat_priv->vis_hash_lock); spin_unlock_bh(&bat_priv->vis_hash_lock);
return -ENOMEM; ret = -ENOMEM;
goto out;
} }
buff[0] = '\0'; buff[0] = '\0';
buff_pos = 0; buff_pos = 0;
...@@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset) ...@@ -328,7 +333,10 @@ int vis_seq_print_text(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buff); seq_printf(seq, "%s", buff);
kfree(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 /* add the info packet to the send list, if it was not
...@@ -815,16 +823,20 @@ static void unicast_vis_packet(struct bat_priv *bat_priv, ...@@ -815,16 +823,20 @@ static void unicast_vis_packet(struct bat_priv *bat_priv,
/* only send one vis packet. called from send_vis_packets() */ /* only send one vis packet. called from send_vis_packets() */
static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
{ {
struct hard_iface *primary_if;
struct vis_packet *packet; 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; packet = (struct vis_packet *)info->skb_packet->data;
if (packet->ttl < 2) { if (packet->ttl < 2) {
pr_debug("Error - can't send vis packet: ttl exceeded\n"); 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, memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
ETH_ALEN);
packet->ttl--; packet->ttl--;
if (is_broadcast_ether_addr(packet->target_orig)) if (is_broadcast_ether_addr(packet->target_orig))
...@@ -832,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) ...@@ -832,6 +844,10 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
else else
unicast_vis_packet(bat_priv, info); unicast_vis_packet(bat_priv, info);
packet->ttl++; /* restore TTL */ packet->ttl++; /* restore TTL */
out:
if (primary_if)
hardif_free_ref(primary_if);
} }
/* called from timer; send (and maybe generate) vis packet. */ /* called from timer; send (and maybe generate) vis packet. */
...@@ -858,7 +874,6 @@ static void send_vis_packets(struct work_struct *work) ...@@ -858,7 +874,6 @@ static void send_vis_packets(struct work_struct *work)
kref_get(&info->refcount); kref_get(&info->refcount);
spin_unlock_bh(&bat_priv->vis_hash_lock); 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); spin_lock_bh(&bat_priv->vis_hash_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment