diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
| -rw-r--r-- | net/batman-adv/soft-interface.c | 473 | 
1 files changed, 357 insertions, 116 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 824e1f6e50f..d5aa60999e8 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -43,8 +43,6 @@ static void bat_get_drvinfo(struct net_device *dev,  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 @@ static const struct ethtool_ops bat_ethtool_ops = {  	.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) @@ -76,120 +72,371 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len)  	return 0;  } -static void softif_neigh_free_rcu(struct rcu_head *rcu) -{ -	struct softif_neigh *softif_neigh; - -	softif_neigh = container_of(rcu, struct softif_neigh, rcu); -	kfree(softif_neigh); -} -  static void softif_neigh_free_ref(struct softif_neigh *softif_neigh)  {  	if (atomic_dec_and_test(&softif_neigh->refcount)) -		call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); +		kfree_rcu(softif_neigh, rcu);  } -void softif_neigh_purge(struct bat_priv *bat_priv) +static void softif_neigh_vid_free_rcu(struct rcu_head *rcu)  { -	struct softif_neigh *softif_neigh, *softif_neigh_tmp; +	struct softif_neigh_vid *softif_neigh_vid; +	struct softif_neigh *softif_neigh;  	struct hlist_node *node, *node_tmp; +	struct bat_priv *bat_priv; -	spin_lock_bh(&bat_priv->softif_neigh_lock); +	softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu); +	bat_priv = softif_neigh_vid->bat_priv; +	spin_lock_bh(&bat_priv->softif_neigh_lock);  	hlist_for_each_entry_safe(softif_neigh, node, node_tmp, -				  &bat_priv->softif_neigh_list, list) { +				  &softif_neigh_vid->softif_neigh_list, list) { +		hlist_del_rcu(&softif_neigh->list); +		softif_neigh_free_ref(softif_neigh); +	} +	spin_unlock_bh(&bat_priv->softif_neigh_lock); -		if ((!time_after(jiffies, softif_neigh->last_seen + -				msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && -		    (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) -			continue; +	kfree(softif_neigh_vid); +} -		hlist_del_rcu(&softif_neigh->list); +static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid) +{ +	if (atomic_dec_and_test(&softif_neigh_vid->refcount)) +		call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu); +} -		if (bat_priv->softif_neigh == softif_neigh) { -			bat_dbg(DBG_ROUTES, bat_priv, -				 "Current mesh exit point '%pM' vanished " -				 "(vid: %d).\n", -				 softif_neigh->addr, softif_neigh->vid); -			softif_neigh_tmp = bat_priv->softif_neigh; -			bat_priv->softif_neigh = NULL; -			softif_neigh_free_ref(softif_neigh_tmp); -		} +static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv, +						     short vid) +{ +	struct softif_neigh_vid *softif_neigh_vid; +	struct hlist_node *node; -		softif_neigh_free_ref(softif_neigh); +	rcu_read_lock(); +	hlist_for_each_entry_rcu(softif_neigh_vid, node, +				 &bat_priv->softif_neigh_vids, list) { +		if (softif_neigh_vid->vid != vid) +			continue; + +		if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) +			continue; + +		goto out;  	} -	spin_unlock_bh(&bat_priv->softif_neigh_lock); +	softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid), +				   GFP_ATOMIC); +	if (!softif_neigh_vid) +		goto out; + +	softif_neigh_vid->vid = vid; +	softif_neigh_vid->bat_priv = bat_priv; + +	/* initialize with 2 - caller decrements counter by one */ +	atomic_set(&softif_neigh_vid->refcount, 2); +	INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list); +	INIT_HLIST_NODE(&softif_neigh_vid->list); +	spin_lock_bh(&bat_priv->softif_neigh_vid_lock); +	hlist_add_head_rcu(&softif_neigh_vid->list, +			   &bat_priv->softif_neigh_vids); +	spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); + +out: +	rcu_read_unlock(); +	return softif_neigh_vid;  }  static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv,  					     uint8_t *addr, short vid)  { -	struct softif_neigh *softif_neigh; +	struct softif_neigh_vid *softif_neigh_vid; +	struct softif_neigh *softif_neigh = NULL;  	struct hlist_node *node; +	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); +	if (!softif_neigh_vid) +		goto out; +  	rcu_read_lock();  	hlist_for_each_entry_rcu(softif_neigh, node, -				 &bat_priv->softif_neigh_list, list) { +				 &softif_neigh_vid->softif_neigh_list, +				 list) {  		if (!compare_eth(softif_neigh->addr, addr))  			continue; -		if (softif_neigh->vid != vid) -			continue; -  		if (!atomic_inc_not_zero(&softif_neigh->refcount))  			continue;  		softif_neigh->last_seen = jiffies; -		goto out; +		goto unlock;  	}  	softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC);  	if (!softif_neigh) -		goto out; +		goto unlock;  	memcpy(softif_neigh->addr, addr, ETH_ALEN); -	softif_neigh->vid = vid;  	softif_neigh->last_seen = jiffies;  	/* initialize with 2 - caller decrements counter by one */  	atomic_set(&softif_neigh->refcount, 2);  	INIT_HLIST_NODE(&softif_neigh->list);  	spin_lock_bh(&bat_priv->softif_neigh_lock); -	hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); +	hlist_add_head_rcu(&softif_neigh->list, +			   &softif_neigh_vid->softif_neigh_list);  	spin_unlock_bh(&bat_priv->softif_neigh_lock); +unlock: +	rcu_read_unlock();  out: +	if (softif_neigh_vid) +		softif_neigh_vid_free_ref(softif_neigh_vid); +	return softif_neigh; +} + +static struct softif_neigh *softif_neigh_get_selected( +				struct softif_neigh_vid *softif_neigh_vid) +{ +	struct softif_neigh *softif_neigh; + +	rcu_read_lock(); +	softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + +	if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount)) +		softif_neigh = NULL; +  	rcu_read_unlock();  	return softif_neigh;  } +static struct softif_neigh *softif_neigh_vid_get_selected( +						struct bat_priv *bat_priv, +						short vid) +{ +	struct softif_neigh_vid *softif_neigh_vid; +	struct softif_neigh *softif_neigh = NULL; + +	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); +	if (!softif_neigh_vid) +		goto out; + +	softif_neigh = softif_neigh_get_selected(softif_neigh_vid); +out: +	if (softif_neigh_vid) +		softif_neigh_vid_free_ref(softif_neigh_vid); +	return softif_neigh; +} + +static void softif_neigh_vid_select(struct bat_priv *bat_priv, +				    struct softif_neigh *new_neigh, +				    short vid) +{ +	struct softif_neigh_vid *softif_neigh_vid; +	struct softif_neigh *curr_neigh; + +	softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); +	if (!softif_neigh_vid) +		goto out; + +	spin_lock_bh(&bat_priv->softif_neigh_lock); + +	if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) +		new_neigh = NULL; + +	curr_neigh = softif_neigh_vid->softif_neigh; +	rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh); + +	if ((curr_neigh) && (!new_neigh)) +		bat_dbg(DBG_ROUTES, bat_priv, +			"Removing mesh exit point on vid: %d (prev: %pM).\n", +			vid, curr_neigh->addr); +	else if ((curr_neigh) && (new_neigh)) +		bat_dbg(DBG_ROUTES, bat_priv, +			"Changing mesh exit point on vid: %d from %pM " +			"to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); +	else if ((!curr_neigh) && (new_neigh)) +		bat_dbg(DBG_ROUTES, bat_priv, +			"Setting mesh exit point on vid: %d to %pM.\n", +			vid, new_neigh->addr); + +	if (curr_neigh) +		softif_neigh_free_ref(curr_neigh); + +	spin_unlock_bh(&bat_priv->softif_neigh_lock); + +out: +	if (softif_neigh_vid) +		softif_neigh_vid_free_ref(softif_neigh_vid); +} + +static void softif_neigh_vid_deselect(struct bat_priv *bat_priv, +				      struct softif_neigh_vid *softif_neigh_vid) +{ +	struct softif_neigh *curr_neigh; +	struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp; +	struct hard_iface *primary_if = NULL; +	struct hlist_node *node; + +	primary_if = primary_if_get_selected(bat_priv); +	if (!primary_if) +		goto out; + +	/* find new softif_neigh immediately to avoid temporary loops */ +	rcu_read_lock(); +	curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + +	hlist_for_each_entry_rcu(softif_neigh_tmp, node, +				 &softif_neigh_vid->softif_neigh_list, +				 list) { +		if (softif_neigh_tmp == curr_neigh) +			continue; + +		/* we got a neighbor but its mac is 'bigger' than ours  */ +		if (memcmp(primary_if->net_dev->dev_addr, +			   softif_neigh_tmp->addr, ETH_ALEN) < 0) +			continue; + +		if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount)) +			continue; + +		softif_neigh = softif_neigh_tmp; +		goto unlock; +	} + +unlock: +	rcu_read_unlock(); +out: +	softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid); + +	if (primary_if) +		hardif_free_ref(primary_if); +	if (softif_neigh) +		softif_neigh_free_ref(softif_neigh); +} +  int softif_neigh_seq_print_text(struct seq_file *seq, void *offset)  {  	struct net_device *net_dev = (struct net_device *)seq->private;  	struct bat_priv *bat_priv = netdev_priv(net_dev); +	struct softif_neigh_vid *softif_neigh_vid;  	struct softif_neigh *softif_neigh; -	struct hlist_node *node; +	struct hard_iface *primary_if; +	struct hlist_node *node, *node_tmp; +	struct softif_neigh *curr_softif_neigh; +	int ret = 0, last_seen_secs, last_seen_msecs; -	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);  	rcu_read_lock(); -	hlist_for_each_entry_rcu(softif_neigh, node, -				 &bat_priv->softif_neigh_list, list) -		seq_printf(seq, "%s %pM (vid: %d)\n", -				bat_priv->softif_neigh == softif_neigh -				? "=>" : "  ", softif_neigh->addr, -				softif_neigh->vid); +	hlist_for_each_entry_rcu(softif_neigh_vid, node, +				 &bat_priv->softif_neigh_vids, list) { +		seq_printf(seq, "     %-15s %s on vid: %d\n", +			   "Originator", "last-seen", softif_neigh_vid->vid); + +		curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + +		hlist_for_each_entry_rcu(softif_neigh, node_tmp, +					 &softif_neigh_vid->softif_neigh_list, +					 list) { +			last_seen_secs = jiffies_to_msecs(jiffies - +						softif_neigh->last_seen) / 1000; +			last_seen_msecs = jiffies_to_msecs(jiffies - +						softif_neigh->last_seen) % 1000; +			seq_printf(seq, "%s %pM  %3i.%03is\n", +				   curr_softif_neigh == softif_neigh +				   ? "=>" : "  ", softif_neigh->addr, +				   last_seen_secs, last_seen_msecs); +		} + +		if (curr_softif_neigh) +			softif_neigh_free_ref(curr_softif_neigh); + +		seq_printf(seq, "\n"); +	}  	rcu_read_unlock(); -	return 0; +out: +	if (primary_if) +		hardif_free_ref(primary_if); +	return ret; +} + +void softif_neigh_purge(struct bat_priv *bat_priv) +{ +	struct softif_neigh *softif_neigh, *curr_softif_neigh; +	struct softif_neigh_vid *softif_neigh_vid; +	struct hlist_node *node, *node_tmp, *node_tmp2; +	char do_deselect; + +	rcu_read_lock(); +	hlist_for_each_entry_rcu(softif_neigh_vid, node, +				 &bat_priv->softif_neigh_vids, list) { +		if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) +			continue; + +		curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); +		do_deselect = 0; + +		spin_lock_bh(&bat_priv->softif_neigh_lock); +		hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, +					  &softif_neigh_vid->softif_neigh_list, +					  list) { +			if ((!time_after(jiffies, softif_neigh->last_seen + +				msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && +			    (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) +				continue; + +			if (curr_softif_neigh == softif_neigh) { +				bat_dbg(DBG_ROUTES, bat_priv, +					"Current mesh exit point on vid: %d " +					"'%pM' vanished.\n", +					softif_neigh_vid->vid, +					softif_neigh->addr); +				do_deselect = 1; +			} + +			hlist_del_rcu(&softif_neigh->list); +			softif_neigh_free_ref(softif_neigh); +		} +		spin_unlock_bh(&bat_priv->softif_neigh_lock); + +		/* soft_neigh_vid_deselect() needs to acquire the +		 * softif_neigh_lock */ +		if (do_deselect) +			softif_neigh_vid_deselect(bat_priv, softif_neigh_vid); + +		if (curr_softif_neigh) +			softif_neigh_free_ref(curr_softif_neigh); + +		softif_neigh_vid_free_ref(softif_neigh_vid); +	} +	rcu_read_unlock(); + +	spin_lock_bh(&bat_priv->softif_neigh_vid_lock); +	hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp, +				  &bat_priv->softif_neigh_vids, list) { +		if (!hlist_empty(&softif_neigh_vid->softif_neigh_list)) +			continue; + +		hlist_del_rcu(&softif_neigh_vid->list); +		softif_neigh_vid_free_ref(softif_neigh_vid); +	} +	spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); +  }  static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, @@ -198,7 +445,9 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,  	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, *softif_neigh_tmp; +	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)  		batman_packet = (struct batman_packet *) @@ -207,63 +456,52 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev,  		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_vid_get_selected(bat_priv, vid); +	if (curr_softif_neigh == softif_neigh) +		goto out; -	if (bat_priv->softif_neigh == softif_neigh) +	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; -	/* switch to new 'smallest neighbor' */ -	if ((bat_priv->softif_neigh) && -	    (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, -							ETH_ALEN) < 0)) { -		bat_dbg(DBG_ROUTES, bat_priv, -			"Changing mesh exit point from %pM (vid: %d) " -			"to %pM (vid: %d).\n", -			 bat_priv->softif_neigh->addr, -			 bat_priv->softif_neigh->vid, -			 softif_neigh->addr, softif_neigh->vid); -		softif_neigh_tmp = bat_priv->softif_neigh; -		bat_priv->softif_neigh = softif_neigh; -		softif_neigh_free_ref(softif_neigh_tmp); -		/* we need to hold the additional reference */ -		goto err; -	} -  	/* close own batX device and use softif_neigh as exit node */ -	if ((!bat_priv->softif_neigh) && -	    (memcmp(softif_neigh->addr, -		    bat_priv->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); -		bat_priv->softif_neigh = softif_neigh; -		/* we need to hold the additional reference */ -		goto err; +	if (!curr_softif_neigh) { +		softif_neigh_vid_select(bat_priv, softif_neigh, vid); +		goto out;  	} +	/* switch to new 'smallest neighbor' */ +	if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0) +		softif_neigh_vid_select(bat_priv, softif_neigh, vid); +  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;  } @@ -293,11 +531,11 @@ static int interface_set_mac_addr(struct net_device *dev, void *p)  	if (!is_valid_ether_addr(addr->sa_data))  		return -EADDRNOTAVAIL; -	/* only modify hna-table if it has been initialised before */ +	/* only modify transtable if it has been initialised before */  	if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { -		hna_local_remove(bat_priv, dev->dev_addr, +		tt_local_remove(bat_priv, dev->dev_addr,  				 "mac address changed"); -		hna_local_add(dev, addr->sa_data); +		tt_local_add(dev, addr->sa_data);  	}  	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); @@ -319,8 +557,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)  {  	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;  	int data_len = skb->len, ret;  	short vid = -1;  	bool do_bcast = false; @@ -348,11 +588,12 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)  	 * if we have a another chosen mesh exit node in range  	 * it will transport the packets to the mesh  	 */ -	if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) +	curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); +	if (curr_softif_neigh)  		goto dropped;  	/* TODO: check this for locks */ -	hna_local_add(soft_iface, ethhdr->h_source); +	tt_local_add(soft_iface, ethhdr->h_source);  	if (is_multicast_ether_addr(ethhdr->h_dest)) {  		ret = gw_is_target(bat_priv, skb); @@ -366,7 +607,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)  	/* 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) @@ -382,7 +624,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)  		/* 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 = @@ -410,6 +652,10 @@ dropped:  dropped_freed:  	bat_priv->stats.tx_dropped++;  end: +	if (curr_softif_neigh) +		softif_neigh_free_ref(curr_softif_neigh); +	if (primary_if) +		hardif_free_ref(primary_if);  	return NETDEV_TX_OK;  } @@ -421,6 +667,7 @@ void interface_rx(struct net_device *soft_iface,  	struct unicast_packet *unicast_packet;  	struct ethhdr *ethhdr;  	struct vlan_ethhdr *vhdr; +	struct softif_neigh *curr_softif_neigh = NULL;  	short vid = -1;  	int ret; @@ -450,7 +697,8 @@ void interface_rx(struct net_device *soft_iface,  	 * if we have a another chosen mesh exit node in range  	 * it will transport the packets to the non-mesh network  	 */ -	if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { +	curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); +	if (curr_softif_neigh) {  		skb_push(skb, hdr_size);  		unicast_packet = (struct unicast_packet *)skb->data; @@ -461,7 +709,7 @@ void interface_rx(struct net_device *soft_iface,  		skb_reset_mac_header(skb);  		memcpy(unicast_packet->dest, -		       bat_priv->softif_neigh->addr, ETH_ALEN); +		       curr_softif_neigh->addr, ETH_ALEN);  		ret = route_unicast_packet(skb, recv_if);  		if (ret == NET_RX_DROP)  			goto dropped; @@ -486,11 +734,13 @@ void interface_rx(struct net_device *soft_iface,  	soft_iface->last_rx = jiffies;  	netif_rx(skb); -	return; +	goto out;  dropped:  	kfree_skb(skb);  out: +	if (curr_softif_neigh) +		softif_neigh_free_ref(curr_softif_neigh);  	return;  } @@ -524,14 +774,15 @@ static void interface_setup(struct net_device *dev)  	dev->hard_start_xmit = interface_tx;  #endif  	dev->destructor = free_netdev; +	dev->tx_queue_len = 0;  	/**  	 * can't call min_mtu, because the needed variables  	 * have not been initialized yet  	 */  	dev->mtu = ETH_DATA_LEN; -	dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the -						* skbuff for our header */ +	/* reserve more space in the skbuff for our header */ +	dev->hard_header_len = BAT_HEADER_LEN;  	/* generate random address */  	random_ether_addr(dev_addr); @@ -556,7 +807,7 @@ struct net_device *softif_create(char *name)  		goto out;  	} -	ret = register_netdev(soft_iface); +	ret = register_netdevice(soft_iface);  	if (ret < 0) {  		pr_err("Unable to register the batman interface '%s': %i\n",  		       name, ret); @@ -580,11 +831,10 @@ struct net_device *softif_create(char *name)  	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);  	atomic_set(&bat_priv->bcast_seqno, 1); -	atomic_set(&bat_priv->hna_local_changed, 0); +	atomic_set(&bat_priv->tt_local_changed, 0);  	bat_priv->primary_if = NULL;  	bat_priv->num_ifaces = 0; -	bat_priv->softif_neigh = NULL;  	ret = sysfs_add_meshif(soft_iface);  	if (ret < 0) @@ -640,7 +890,7 @@ static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)  {  	cmd->supported = 0;  	cmd->advertising = 0; -	cmd->speed = SPEED_10; +	ethtool_cmd_speed_set(cmd, SPEED_10);  	cmd->duplex = DUPLEX_FULL;  	cmd->port = PORT_TP;  	cmd->phy_address = 0; @@ -675,12 +925,3 @@ static u32 bat_get_link(struct net_device *dev)  	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; -}  |