diff options
Diffstat (limited to 'net/batman-adv/network-coding.c')
| -rw-r--r-- | net/batman-adv/network-coding.c | 195 | 
1 files changed, 150 insertions, 45 deletions
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index a487d46e0ae..8d04d174669 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012-2013 B.A.T.M.A.N. contributors: +/* Copyright (C) 2012-2014 B.A.T.M.A.N. contributors:   *   * Martin Hundebøll, Jeppe Ledet-Pedersen   * @@ -12,9 +12,7 @@   * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  #include <linux/debugfs.h> @@ -35,6 +33,20 @@ static int batadv_nc_recv_coded_packet(struct sk_buff *skb,  				       struct batadv_hard_iface *recv_if);  /** + * batadv_nc_init - one-time initialization for network coding + */ +int __init batadv_nc_init(void) +{ +	int ret; + +	/* Register our packet type */ +	ret = batadv_recv_handler_register(BATADV_CODED, +					   batadv_nc_recv_coded_packet); + +	return ret; +} + +/**   * batadv_nc_start_timer - initialise the nc periodic worker   * @bat_priv: the bat priv with all the soft interface information   */ @@ -45,10 +57,64 @@ static void batadv_nc_start_timer(struct batadv_priv *bat_priv)  }  /** - * batadv_nc_init - initialise coding hash table and start house keeping + * batadv_nc_tvlv_container_update - update the network coding tvlv container + *  after network coding setting change   * @bat_priv: the bat priv with all the soft interface information   */ -int batadv_nc_init(struct batadv_priv *bat_priv) +static void batadv_nc_tvlv_container_update(struct batadv_priv *bat_priv) +{ +	char nc_mode; + +	nc_mode = atomic_read(&bat_priv->network_coding); + +	switch (nc_mode) { +	case 0: +		batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); +		break; +	case 1: +		batadv_tvlv_container_register(bat_priv, BATADV_TVLV_NC, 1, +					       NULL, 0); +		break; +	} +} + +/** + * batadv_nc_status_update - update the network coding tvlv container after + *  network coding setting change + * @net_dev: the soft interface net device + */ +void batadv_nc_status_update(struct net_device *net_dev) +{ +	struct batadv_priv *bat_priv = netdev_priv(net_dev); + +	batadv_nc_tvlv_container_update(bat_priv); +} + +/** + * batadv_nc_tvlv_ogm_handler_v1 - process incoming nc tvlv container + * @bat_priv: the bat priv with all the soft interface information + * @orig: the orig_node of the ogm + * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags) + * @tvlv_value: tvlv buffer containing the gateway data + * @tvlv_value_len: tvlv buffer length + */ +static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, +					  struct batadv_orig_node *orig, +					  uint8_t flags, +					  void *tvlv_value, +					  uint16_t tvlv_value_len) +{ +	if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) +		orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_NC; +	else +		orig->capabilities |= BATADV_ORIG_CAPA_HAS_NC; +} + +/** + * batadv_nc_mesh_init - initialise coding hash table and start house keeping + * @bat_priv: the bat priv with all the soft interface information + */ +int batadv_nc_mesh_init(struct batadv_priv *bat_priv)  {  	bat_priv->nc.timestamp_fwd_flush = jiffies;  	bat_priv->nc.timestamp_sniffed_purge = jiffies; @@ -70,14 +136,13 @@ int batadv_nc_init(struct batadv_priv *bat_priv)  	batadv_hash_set_lock_class(bat_priv->nc.coding_hash,  				   &batadv_nc_decoding_hash_lock_class_key); -	/* Register our packet type */ -	if (batadv_recv_handler_register(BATADV_CODED, -					 batadv_nc_recv_coded_packet) < 0) -		goto err; -  	INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);  	batadv_nc_start_timer(bat_priv); +	batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1, +				     NULL, BATADV_TVLV_NC, 1, +				     BATADV_TVLV_HANDLER_OGM_CIFNOTFND); +	batadv_nc_tvlv_container_update(bat_priv);  	return 0;  err: @@ -654,9 +719,21 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,  				    struct batadv_orig_node *orig_node,  				    struct batadv_ogm_packet *ogm_packet)  { -	if (orig_node->last_real_seqno != ntohl(ogm_packet->seqno)) +	struct batadv_orig_ifinfo *orig_ifinfo; +	uint32_t last_real_seqno; +	uint8_t last_ttl; + +	orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT); +	if (!orig_ifinfo) +		return false; + +	last_ttl = orig_ifinfo->last_ttl; +	last_real_seqno = orig_ifinfo->last_real_seqno; +	batadv_orig_ifinfo_free_ref(orig_ifinfo); + +	if (last_real_seqno != ntohl(ogm_packet->seqno))  		return false; -	if (orig_node->last_ttl != ogm_packet->header.ttl + 1) +	if (last_ttl != ogm_packet->ttl + 1)  		return false;  	if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))  		return false; @@ -743,7 +820,7 @@ static struct batadv_nc_node  	/* Initialize nc_node */  	INIT_LIST_HEAD(&nc_node->list); -	memcpy(nc_node->addr, orig_node->orig, ETH_ALEN); +	ether_addr_copy(nc_node->addr, orig_node->orig);  	nc_node->orig_node = orig_neigh_node;  	atomic_set(&nc_node->refcount, 2); @@ -793,6 +870,10 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,  	if (!atomic_read(&bat_priv->network_coding))  		goto out; +	/* check if orig node is network coding enabled */ +	if (!(orig_node->capabilities & BATADV_ORIG_CAPA_HAS_NC)) +		goto out; +  	/* accept ogms from 'good' neighbors and single hop neighbors */  	if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) &&  	    !is_single_hop_neigh) @@ -861,8 +942,8 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,  	spin_lock_init(&nc_path->packet_list_lock);  	atomic_set(&nc_path->refcount, 2);  	nc_path->last_valid = jiffies; -	memcpy(nc_path->next_hop, dst, ETH_ALEN); -	memcpy(nc_path->prev_hop, src, ETH_ALEN); +	ether_addr_copy(nc_path->next_hop, dst); +	ether_addr_copy(nc_path->prev_hop, src);  	batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n",  		   nc_path->prev_hop, @@ -933,13 +1014,15 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,  				   struct batadv_nc_packet *nc_packet,  				   struct batadv_neigh_node *neigh_node)  { -	uint8_t tq_weighted_neigh, tq_weighted_coding; +	uint8_t tq_weighted_neigh, tq_weighted_coding, tq_tmp;  	struct sk_buff *skb_dest, *skb_src;  	struct batadv_unicast_packet *packet1;  	struct batadv_unicast_packet *packet2;  	struct batadv_coded_packet *coded_packet;  	struct batadv_neigh_node *neigh_tmp, *router_neigh;  	struct batadv_neigh_node *router_coding = NULL; +	struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL; +	struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;  	uint8_t *first_source, *first_dest, *second_source, *second_dest;  	__be32 packet_id1, packet_id2;  	size_t count; @@ -949,17 +1032,34 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,  	int coded_size = sizeof(*coded_packet);  	int header_add = coded_size - unicast_size; -	router_neigh = batadv_orig_node_get_router(neigh_node->orig_node); +	/* TODO: do we need to consider the outgoing interface for +	 * coded packets? +	 */ +	router_neigh = batadv_orig_router_get(neigh_node->orig_node, +					      BATADV_IF_DEFAULT);  	if (!router_neigh)  		goto out; +	router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh, +						      BATADV_IF_DEFAULT); +	if (!router_neigh_ifinfo) +		goto out; +  	neigh_tmp = nc_packet->neigh_node; -	router_coding = batadv_orig_node_get_router(neigh_tmp->orig_node); +	router_coding = batadv_orig_router_get(neigh_tmp->orig_node, +					       BATADV_IF_DEFAULT);  	if (!router_coding)  		goto out; -	tq_weighted_neigh = batadv_nc_random_weight_tq(router_neigh->tq_avg); -	tq_weighted_coding = batadv_nc_random_weight_tq(router_coding->tq_avg); +	router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding, +						       BATADV_IF_DEFAULT); +	if (!router_coding_ifinfo) +		goto out; + +	tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg; +	tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp); +	tq_tmp = router_coding_ifinfo->bat_iv.tq_avg; +	tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp);  	/* Select one destination for the MAC-header dst-field based on  	 * weighted TQ-values. @@ -1010,22 +1110,22 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,  	coded_packet = (struct batadv_coded_packet *)skb_dest->data;  	skb_reset_mac_header(skb_dest); -	coded_packet->header.packet_type = BATADV_CODED; -	coded_packet->header.version = BATADV_COMPAT_VERSION; -	coded_packet->header.ttl = packet1->header.ttl; +	coded_packet->packet_type = BATADV_CODED; +	coded_packet->version = BATADV_COMPAT_VERSION; +	coded_packet->ttl = packet1->ttl;  	/* Info about first unicast packet */ -	memcpy(coded_packet->first_source, first_source, ETH_ALEN); -	memcpy(coded_packet->first_orig_dest, packet1->dest, ETH_ALEN); +	ether_addr_copy(coded_packet->first_source, first_source); +	ether_addr_copy(coded_packet->first_orig_dest, packet1->dest);  	coded_packet->first_crc = packet_id1;  	coded_packet->first_ttvn = packet1->ttvn;  	/* Info about second unicast packet */ -	memcpy(coded_packet->second_dest, second_dest, ETH_ALEN); -	memcpy(coded_packet->second_source, second_source, ETH_ALEN); -	memcpy(coded_packet->second_orig_dest, packet2->dest, ETH_ALEN); +	ether_addr_copy(coded_packet->second_dest, second_dest); +	ether_addr_copy(coded_packet->second_source, second_source); +	ether_addr_copy(coded_packet->second_orig_dest, packet2->dest);  	coded_packet->second_crc = packet_id2; -	coded_packet->second_ttl = packet2->header.ttl; +	coded_packet->second_ttl = packet2->ttl;  	coded_packet->second_ttvn = packet2->ttvn;  	coded_packet->coded_len = htons(coding_len); @@ -1083,6 +1183,10 @@ out:  		batadv_neigh_node_free_ref(router_neigh);  	if (router_coding)  		batadv_neigh_node_free_ref(router_coding); +	if (router_neigh_ifinfo) +		batadv_neigh_ifinfo_free_ref(router_neigh_ifinfo); +	if (router_coding_ifinfo) +		batadv_neigh_ifinfo_free_ref(router_coding_ifinfo);  	return res;  } @@ -1240,14 +1344,14 @@ static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,  	struct ethhdr *ethhdr;  	/* Copy skb header to change the mac header */ -	skb = pskb_copy(skb, GFP_ATOMIC); +	skb = pskb_copy_for_clone(skb, GFP_ATOMIC);  	if (!skb)  		return;  	/* Set the mac header as if we actually sent the packet uncoded */  	ethhdr = eth_hdr(skb); -	memcpy(ethhdr->h_source, ethhdr->h_dest, ETH_ALEN); -	memcpy(ethhdr->h_dest, eth_dst_new, ETH_ALEN); +	ether_addr_copy(ethhdr->h_source, ethhdr->h_dest); +	ether_addr_copy(ethhdr->h_dest, eth_dst_new);  	/* Set data pointer to MAC header to mimic packets from our tx path */  	skb_push(skb, ETH_HLEN); @@ -1380,7 +1484,7 @@ bool batadv_nc_skb_forward(struct sk_buff *skb,  	/* We only handle unicast packets */  	payload = skb_network_header(skb);  	packet = (struct batadv_unicast_packet *)payload; -	if (packet->header.packet_type != BATADV_UNICAST) +	if (packet->packet_type != BATADV_UNICAST)  		goto out;  	/* Try to find a coding opportunity and send the skb if one is found */ @@ -1433,7 +1537,7 @@ void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,  	/* Check for supported packet type */  	payload = skb_network_header(skb);  	packet = (struct batadv_unicast_packet *)payload; -	if (packet->header.packet_type != BATADV_UNICAST) +	if (packet->packet_type != BATADV_UNICAST)  		goto out;  	/* Find existing nc_path or create a new */ @@ -1533,7 +1637,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,  	/* Reconstruct original mac header */  	ethhdr = eth_hdr(skb); -	memcpy(ethhdr, ðhdr_tmp, sizeof(*ethhdr)); +	*ethhdr = ethhdr_tmp;  	/* Select the correct unicast header information based on the location  	 * of our mac address in the coded_packet header @@ -1543,7 +1647,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,  		 * so the Ethernet address must be copied to h_dest and  		 * pkt_type changed from PACKET_OTHERHOST to PACKET_HOST  		 */ -		memcpy(ethhdr->h_dest, coded_packet_tmp.second_dest, ETH_ALEN); +		ether_addr_copy(ethhdr->h_dest, coded_packet_tmp.second_dest);  		skb->pkt_type = PACKET_HOST;  		orig_dest = coded_packet_tmp.second_orig_dest; @@ -1551,7 +1655,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,  		ttvn = coded_packet_tmp.second_ttvn;  	} else {  		orig_dest = coded_packet_tmp.first_orig_dest; -		ttl = coded_packet_tmp.header.ttl; +		ttl = coded_packet_tmp.ttl;  		ttvn = coded_packet_tmp.first_ttvn;  	} @@ -1576,10 +1680,10 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,  	/* Create decoded unicast packet */  	unicast_packet = (struct batadv_unicast_packet *)skb->data; -	unicast_packet->header.packet_type = BATADV_UNICAST; -	unicast_packet->header.version = BATADV_COMPAT_VERSION; -	unicast_packet->header.ttl = ttl; -	memcpy(unicast_packet->dest, orig_dest, ETH_ALEN); +	unicast_packet->packet_type = BATADV_UNICAST; +	unicast_packet->version = BATADV_COMPAT_VERSION; +	unicast_packet->ttl = ttl; +	ether_addr_copy(unicast_packet->dest, orig_dest);  	unicast_packet->ttvn = ttvn;  	batadv_nc_packet_free(nc_packet); @@ -1721,12 +1825,13 @@ free_nc_packet:  }  /** - * batadv_nc_free - clean up network coding memory + * batadv_nc_mesh_free - clean up network coding memory   * @bat_priv: the bat priv with all the soft interface information   */ -void batadv_nc_free(struct batadv_priv *bat_priv) +void batadv_nc_mesh_free(struct batadv_priv *bat_priv)  { -	batadv_recv_handler_unregister(BATADV_CODED); +	batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1); +	batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_NC, 1);  	cancel_delayed_work_sync(&bat_priv->nc.work);  	batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);  | 
