[commits] linux integration; branch, linux, updated. v2.6.36-rc3-498-g556fac7

postmaster at open-mesh.net postmaster at open-mesh.net
Sun Sep 12 22:35:55 CEST 2010


The following commit has been merged in the linux branch:
commit 556fac794a2a8f95030a6e0892d2329bf83b258b
Merge: 6a10cd96982e33b7587c635eaabf1a8944b65f4f 69d187ffb8e22024a87d8457e5dcb10e297108e9
Author: Sven Eckelmann <sven.eckelmann at gmx.de>
Date:   Sun Sep 12 22:26:10 2010 +0200

    Merge remote branch 'origin/next' into linux

diff --combined drivers/staging/batman-adv/bitarray.h
index d961d56,77b1e61..77b1e61
--- a/drivers/staging/batman-adv/bitarray.h
+++ b/drivers/staging/batman-adv/bitarray.h
@@@ -23,7 -23,7 +23,7 @@@
  #define _NET_BATMAN_ADV_BITARRAY_H_
  
  /* you should choose something big, if you don't want to waste cpu
-    and keep the type in sync with bit_packet_count */
+  * and keep the type in sync with bit_packet_count */
  #define TYPE_OF_WORD unsigned long
  #define WORD_BIT_SIZE (sizeof(TYPE_OF_WORD) * 8)
  
diff --combined drivers/staging/batman-adv/main.c
index 498861f,0000000..78ceebf
mode 100644,000000..100644
--- a/drivers/staging/batman-adv/main.c
+++ b/drivers/staging/batman-adv/main.c
@@@ -1,225 -1,0 +1,222 @@@
 +/*
 + * Copyright (C) 2007-2010 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
 + *
 + */
 +
 +#include "main.h"
 +#include "bat_sysfs.h"
 +#include "bat_debugfs.h"
 +#include "routing.h"
 +#include "send.h"
 +#include "originator.h"
 +#include "soft-interface.h"
 +#include "icmp_socket.h"
 +#include "translation-table.h"
 +#include "hard-interface.h"
 +#include "types.h"
 +#include "vis.h"
 +#include "hash.h"
 +
 +struct list_head if_list;
 +
 +unsigned char broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 +
 +struct workqueue_struct *bat_event_workqueue;
 +
 +static int __init batman_init(void)
 +{
 +	INIT_LIST_HEAD(&if_list);
 +
 +	/* the name should not be longer than 10 chars - see
 +	 * http://lwn.net/Articles/23634/ */
 +	bat_event_workqueue = create_singlethread_workqueue("bat_events");
 +
 +	if (!bat_event_workqueue)
 +		return -ENOMEM;
 +
 +	bat_socket_init();
 +	debugfs_init();
 +
 +	register_netdevice_notifier(&hard_if_notifier);
 +
 +	pr_info("B.A.T.M.A.N. advanced %s%s (compatibility version %i) "
 +		"loaded\n", SOURCE_VERSION, REVISION_VERSION_STR,
 +		COMPAT_VERSION);
 +
 +	return 0;
 +}
 +
 +static void __exit batman_exit(void)
 +{
 +	debugfs_destroy();
 +	unregister_netdevice_notifier(&hard_if_notifier);
 +	hardif_remove_interfaces();
 +
 +	flush_workqueue(bat_event_workqueue);
 +	destroy_workqueue(bat_event_workqueue);
 +	bat_event_workqueue = NULL;
++
++	synchronize_net();
 +}
 +
 +int mesh_init(struct net_device *soft_iface)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(soft_iface);
 +
 +	spin_lock_init(&bat_priv->orig_hash_lock);
 +	spin_lock_init(&bat_priv->forw_bat_list_lock);
 +	spin_lock_init(&bat_priv->forw_bcast_list_lock);
 +	spin_lock_init(&bat_priv->hna_lhash_lock);
 +	spin_lock_init(&bat_priv->hna_ghash_lock);
- 	spin_lock_init(&bat_priv->gw_list_lock);
 +	spin_lock_init(&bat_priv->vis_hash_lock);
 +	spin_lock_init(&bat_priv->vis_list_lock);
 +
 +	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
 +	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
- 	INIT_HLIST_HEAD(&bat_priv->gw_list);
 +
 +	if (originator_init(bat_priv) < 1)
 +		goto err;
 +
 +	if (hna_local_init(bat_priv) < 1)
 +		goto err;
 +
 +	if (hna_global_init(bat_priv) < 1)
 +		goto err;
 +
 +	hna_local_add(soft_iface, soft_iface->dev_addr);
 +
 +	if (vis_init(bat_priv) < 1)
 +		goto err;
 +
 +	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 +	goto end;
 +
 +err:
 +	pr_err("Unable to allocate memory for mesh information structures: "
 +	       "out of mem ?\n");
 +	mesh_free(soft_iface);
 +	return -1;
 +
 +end:
 +	return 0;
 +}
 +
 +void mesh_free(struct net_device *soft_iface)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(soft_iface);
 +
 +	atomic_set(&bat_priv->mesh_state, MESH_DEACTIVATING);
 +
 +	purge_outstanding_packets(bat_priv, NULL);
 +
 +	vis_quit(bat_priv);
 +
 +	originator_free(bat_priv);
 +
 +	hna_local_free(bat_priv);
 +	hna_global_free(bat_priv);
 +
- 	synchronize_net();
- 
- 	synchronize_rcu();
 +	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 +}
 +
 +void inc_module_count(void)
 +{
 +	try_module_get(THIS_MODULE);
 +}
 +
 +void dec_module_count(void)
 +{
 +	module_put(THIS_MODULE);
 +}
 +
 +int addr_to_string(char *buff, uint8_t *addr)
 +{
 +	return sprintf(buff, "%pM", addr);
 +}
 +
 +/* returns 1 if they are the same originator */
 +
 +int compare_orig(void *data1, void *data2)
 +{
 +	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 +}
 +
 +/* hashfunction to choose an entry in a hash table of given size */
 +/* hash algorithm from http://en.wikipedia.org/wiki/Hash_table */
 +int choose_orig(void *data, int32_t size)
 +{
 +	unsigned char *key = data;
 +	uint32_t hash = 0;
 +	size_t i;
 +
 +	for (i = 0; i < 6; i++) {
 +		hash += key[i];
 +		hash += (hash << 10);
 +		hash ^= (hash >> 6);
 +	}
 +
 +	hash += (hash << 3);
 +	hash ^= (hash >> 11);
 +	hash += (hash << 15);
 +
 +	return hash % size;
 +}
 +
 +int is_my_mac(uint8_t *addr)
 +{
 +	struct batman_if *batman_if;
 +
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(batman_if, &if_list, list) {
 +		if (batman_if->if_status != IF_ACTIVE)
 +			continue;
 +
 +		if (compare_orig(batman_if->net_dev->dev_addr, addr)) {
 +			rcu_read_unlock();
 +			return 1;
 +		}
 +	}
 +	rcu_read_unlock();
 +	return 0;
 +
 +}
 +
 +int is_bcast(uint8_t *addr)
 +{
 +	return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
 +}
 +
 +int is_mcast(uint8_t *addr)
 +{
 +	return *addr & 0x01;
 +}
 +
 +module_init(batman_init);
 +module_exit(batman_exit);
 +
 +MODULE_LICENSE("GPL");
 +
 +MODULE_AUTHOR(DRIVER_AUTHOR);
 +MODULE_DESCRIPTION(DRIVER_DESC);
 +MODULE_SUPPORTED_DEVICE(DRIVER_DEVICE);
 +#ifdef REVISION_VERSION
 +MODULE_VERSION(SOURCE_VERSION "-" REVISION_VERSION);
 +#else
 +MODULE_VERSION(SOURCE_VERSION);
 +#endif
diff --combined drivers/staging/batman-adv/routing.c
index e12fd99,0000000..e545260
mode 100644,000000..100644
--- a/drivers/staging/batman-adv/routing.c
+++ b/drivers/staging/batman-adv/routing.c
@@@ -1,1387 -1,0 +1,1389 @@@
 +/*
 + * Copyright (C) 2007-2010 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
 + *
 + */
 +
 +#include "main.h"
 +#include "routing.h"
 +#include "send.h"
 +#include "hash.h"
 +#include "soft-interface.h"
 +#include "hard-interface.h"
 +#include "icmp_socket.h"
 +#include "translation-table.h"
 +#include "originator.h"
 +#include "types.h"
 +#include "ring_buffer.h"
 +#include "vis.h"
 +#include "aggregation.h"
 +#include "unicast.h"
 +
 +void slide_own_bcast_window(struct batman_if *batman_if)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
 +	HASHIT(hashit);
 +	struct orig_node *orig_node;
 +	TYPE_OF_WORD *word;
 +	unsigned long flags;
 +
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +
 +	while (hash_iterate(bat_priv->orig_hash, &hashit)) {
 +		orig_node = hashit.bucket->data;
 +		word = &(orig_node->bcast_own[batman_if->if_num * NUM_WORDS]);
 +
 +		bit_get_packet(bat_priv, word, 1, 0);
 +		orig_node->bcast_own_sum[batman_if->if_num] =
 +			bit_packet_count(word);
 +	}
 +
 +	spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +}
 +
 +static void update_HNA(struct bat_priv *bat_priv, struct orig_node *orig_node,
 +		       unsigned char *hna_buff, int hna_buff_len)
 +{
 +	if ((hna_buff_len != orig_node->hna_buff_len) ||
 +	    ((hna_buff_len > 0) &&
 +	     (orig_node->hna_buff_len > 0) &&
 +	     (memcmp(orig_node->hna_buff, hna_buff, hna_buff_len) != 0))) {
 +
 +		if (orig_node->hna_buff_len > 0)
 +			hna_global_del_orig(bat_priv, orig_node,
 +					    "originator changed hna");
 +
 +		if ((hna_buff_len > 0) && (hna_buff != NULL))
 +			hna_global_add_orig(bat_priv, orig_node,
 +					    hna_buff, hna_buff_len);
 +	}
 +}
 +
 +static void update_route(struct bat_priv *bat_priv,
 +			 struct orig_node *orig_node,
 +			 struct neigh_node *neigh_node,
 +			 unsigned char *hna_buff, int hna_buff_len)
 +{
 +	/* route deleted */
 +	if ((orig_node->router != NULL) && (neigh_node == NULL)) {
 +
 +		bat_dbg(DBG_ROUTES, bat_priv, "Deleting route towards: %pM\n",
 +			orig_node->orig);
 +		hna_global_del_orig(bat_priv, orig_node,
 +				    "originator timed out");
 +
 +		/* route added */
 +	} else if ((orig_node->router == NULL) && (neigh_node != NULL)) {
 +
 +		bat_dbg(DBG_ROUTES, bat_priv,
 +			"Adding route towards: %pM (via %pM)\n",
 +			orig_node->orig, neigh_node->addr);
 +		hna_global_add_orig(bat_priv, orig_node,
 +				    hna_buff, hna_buff_len);
 +
 +		/* route changed */
 +	} else {
 +		bat_dbg(DBG_ROUTES, bat_priv,
 +			"Changing route towards: %pM "
 +			"(now via %pM - was via %pM)\n",
 +			orig_node->orig, neigh_node->addr,
 +			orig_node->router->addr);
 +	}
 +
 +	orig_node->router = neigh_node;
 +}
 +
 +
 +void update_routes(struct bat_priv *bat_priv, struct orig_node *orig_node,
 +		   struct neigh_node *neigh_node, unsigned char *hna_buff,
 +		   int hna_buff_len)
 +{
 +
 +	if (orig_node == NULL)
 +		return;
 +
 +	if (orig_node->router != neigh_node)
 +		update_route(bat_priv, orig_node, neigh_node,
 +			     hna_buff, hna_buff_len);
 +	/* may be just HNA changed */
 +	else
 +		update_HNA(bat_priv, orig_node, hna_buff, hna_buff_len);
 +}
 +
 +static int is_bidirectional_neigh(struct orig_node *orig_node,
 +				struct orig_node *orig_neigh_node,
 +				struct batman_packet *batman_packet,
 +				struct batman_if *if_incoming)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 +	struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
 +	unsigned char total_count;
 +
 +	if (orig_node == orig_neigh_node) {
 +		list_for_each_entry(tmp_neigh_node,
 +				    &orig_node->neigh_list,
 +				    list) {
 +
 +			if (compare_orig(tmp_neigh_node->addr,
 +					 orig_neigh_node->orig) &&
 +			    (tmp_neigh_node->if_incoming == if_incoming))
 +				neigh_node = tmp_neigh_node;
 +		}
 +
 +		if (!neigh_node)
 +			neigh_node = create_neighbor(orig_node,
 +						     orig_neigh_node,
 +						     orig_neigh_node->orig,
 +						     if_incoming);
 +		/* create_neighbor failed, return 0 */
 +		if (!neigh_node)
 +			return 0;
 +
 +		neigh_node->last_valid = jiffies;
 +	} else {
 +		/* find packet count of corresponding one hop neighbor */
 +		list_for_each_entry(tmp_neigh_node,
 +				    &orig_neigh_node->neigh_list, list) {
 +
 +			if (compare_orig(tmp_neigh_node->addr,
 +					 orig_neigh_node->orig) &&
 +			    (tmp_neigh_node->if_incoming == if_incoming))
 +				neigh_node = tmp_neigh_node;
 +		}
 +
 +		if (!neigh_node)
 +			neigh_node = create_neighbor(orig_neigh_node,
 +						     orig_neigh_node,
 +						     orig_neigh_node->orig,
 +						     if_incoming);
 +		/* create_neighbor failed, return 0 */
 +		if (!neigh_node)
 +			return 0;
 +	}
 +
 +	orig_node->last_valid = jiffies;
 +
 +	/* pay attention to not get a value bigger than 100 % */
 +	total_count = (orig_neigh_node->bcast_own_sum[if_incoming->if_num] >
 +		       neigh_node->real_packet_count ?
 +		       neigh_node->real_packet_count :
 +		       orig_neigh_node->bcast_own_sum[if_incoming->if_num]);
 +
 +	/* if we have too few packets (too less data) we set tq_own to zero */
 +	/* if we receive too few packets it is not considered bidirectional */
 +	if ((total_count < TQ_LOCAL_BIDRECT_SEND_MINIMUM) ||
 +	    (neigh_node->real_packet_count < TQ_LOCAL_BIDRECT_RECV_MINIMUM))
 +		orig_neigh_node->tq_own = 0;
 +	else
 +		/* neigh_node->real_packet_count is never zero as we
 +		 * only purge old information when getting new
 +		 * information */
 +		orig_neigh_node->tq_own = (TQ_MAX_VALUE * total_count) /
 +			neigh_node->real_packet_count;
 +
 +	/*
 +	 * 1 - ((1-x) ** 3), normalized to TQ_MAX_VALUE this does
 +	 * affect the nearly-symmetric links only a little, but
 +	 * punishes asymmetric links more.  This will give a value
 +	 * between 0 and TQ_MAX_VALUE
 +	 */
 +	orig_neigh_node->tq_asym_penalty =
 +		TQ_MAX_VALUE -
 +		(TQ_MAX_VALUE *
 +		 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
 +		 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count) *
 +		 (TQ_LOCAL_WINDOW_SIZE - neigh_node->real_packet_count)) /
 +		(TQ_LOCAL_WINDOW_SIZE *
 +		 TQ_LOCAL_WINDOW_SIZE *
 +		 TQ_LOCAL_WINDOW_SIZE);
 +
 +	batman_packet->tq = ((batman_packet->tq *
 +			      orig_neigh_node->tq_own *
 +			      orig_neigh_node->tq_asym_penalty) /
 +			     (TQ_MAX_VALUE * TQ_MAX_VALUE));
 +
 +	bat_dbg(DBG_BATMAN, bat_priv,
 +		"bidirectional: "
 +		"orig = %-15pM neigh = %-15pM => own_bcast = %2i, "
 +		"real recv = %2i, local tq: %3i, asym_penalty: %3i, "
 +		"total tq: %3i\n",
 +		orig_node->orig, orig_neigh_node->orig, total_count,
 +		neigh_node->real_packet_count, orig_neigh_node->tq_own,
 +		orig_neigh_node->tq_asym_penalty, batman_packet->tq);
 +
 +	/* if link has the minimum required transmission quality
 +	 * consider it bidirectional */
 +	if (batman_packet->tq >= TQ_TOTAL_BIDRECT_LIMIT)
 +		return 1;
 +
 +	return 0;
 +}
 +
 +static void update_orig(struct bat_priv *bat_priv,
 +			struct orig_node *orig_node,
 +			struct ethhdr *ethhdr,
 +			struct batman_packet *batman_packet,
 +			struct batman_if *if_incoming,
 +			unsigned char *hna_buff, int hna_buff_len,
 +			char is_duplicate)
 +{
 +	struct neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL;
 +	int tmp_hna_buff_len;
 +
 +	bat_dbg(DBG_BATMAN, bat_priv, "update_originator(): "
 +		"Searching and updating originator entry of received packet\n");
 +
 +	list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 +		if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
 +		    (tmp_neigh_node->if_incoming == if_incoming)) {
 +			neigh_node = tmp_neigh_node;
 +			continue;
 +		}
 +
 +		if (is_duplicate)
 +			continue;
 +
 +		ring_buffer_set(tmp_neigh_node->tq_recv,
 +				&tmp_neigh_node->tq_index, 0);
 +		tmp_neigh_node->tq_avg =
 +			ring_buffer_avg(tmp_neigh_node->tq_recv);
 +	}
 +
 +	if (!neigh_node) {
 +		struct orig_node *orig_tmp;
 +
 +		orig_tmp = get_orig_node(bat_priv, ethhdr->h_source);
 +		if (!orig_tmp)
 +			return;
 +
 +		neigh_node = create_neighbor(orig_node, orig_tmp,
 +					     ethhdr->h_source, if_incoming);
 +		if (!neigh_node)
 +			return;
 +	} else
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Updating existing last-hop neighbor of originator\n");
 +
 +	orig_node->flags = batman_packet->flags;
 +	neigh_node->last_valid = jiffies;
 +
 +	ring_buffer_set(neigh_node->tq_recv,
 +			&neigh_node->tq_index,
 +			batman_packet->tq);
 +	neigh_node->tq_avg = ring_buffer_avg(neigh_node->tq_recv);
 +
 +	if (!is_duplicate) {
 +		orig_node->last_ttl = batman_packet->ttl;
 +		neigh_node->last_ttl = batman_packet->ttl;
 +	}
 +
 +	tmp_hna_buff_len = (hna_buff_len > batman_packet->num_hna * ETH_ALEN ?
 +			    batman_packet->num_hna * ETH_ALEN : hna_buff_len);
 +
 +	/* if this neighbor already is our next hop there is nothing
 +	 * to change */
 +	if (orig_node->router == neigh_node)
 +		goto update_hna;
 +
 +	/* if this neighbor does not offer a better TQ we won't consider it */
 +	if ((orig_node->router) &&
 +	    (orig_node->router->tq_avg > neigh_node->tq_avg))
 +		goto update_hna;
 +
 +	/* if the TQ is the same and the link not more symetric we
 +	 * won't consider it either */
 +	if ((orig_node->router) &&
 +	     ((neigh_node->tq_avg == orig_node->router->tq_avg) &&
 +	     (orig_node->router->orig_node->bcast_own_sum[if_incoming->if_num]
 +	      >= neigh_node->orig_node->bcast_own_sum[if_incoming->if_num])))
 +		goto update_hna;
 +
 +	update_routes(bat_priv, orig_node, neigh_node,
 +		      hna_buff, tmp_hna_buff_len);
 +	return;
 +
 +update_hna:
 +	update_routes(bat_priv, orig_node, orig_node->router,
 +		      hna_buff, tmp_hna_buff_len);
 +}
 +
 +/* checks whether the host restarted and is in the protection time.
 + * returns:
 + *  0 if the packet is to be accepted
 + *  1 if the packet is to be ignored.
 + */
 +static int window_protected(struct bat_priv *bat_priv,
 +			    int32_t seq_num_diff,
 +			    unsigned long *last_reset)
 +{
 +	if ((seq_num_diff <= -TQ_LOCAL_WINDOW_SIZE)
 +		|| (seq_num_diff >= EXPECTED_SEQNO_RANGE)) {
 +		if (time_after(jiffies, *last_reset +
 +			msecs_to_jiffies(RESET_PROTECTION_MS))) {
 +
 +			*last_reset = jiffies;
 +			bat_dbg(DBG_BATMAN, bat_priv,
 +				"old packet received, start protection\n");
 +
 +			return 0;
 +		} else
 +			return 1;
 +	}
 +	return 0;
 +}
 +
 +/* processes a batman packet for all interfaces, adjusts the sequence number and
 + * finds out whether it is a duplicate.
 + * returns:
 + *   1 the packet is a duplicate
 + *   0 the packet has not yet been received
 + *  -1 the packet is old and has been received while the seqno window
 + *     was protected. Caller should drop it.
 + */
 +static char count_real_packets(struct ethhdr *ethhdr,
 +			       struct batman_packet *batman_packet,
 +			       struct batman_if *if_incoming)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 +	struct orig_node *orig_node;
 +	struct neigh_node *tmp_neigh_node;
 +	char is_duplicate = 0;
 +	int32_t seq_diff;
 +	int need_update = 0;
 +	int set_mark;
 +
 +	orig_node = get_orig_node(bat_priv, batman_packet->orig);
 +	if (orig_node == NULL)
 +		return 0;
 +
 +	seq_diff = batman_packet->seqno - orig_node->last_real_seqno;
 +
 +	/* signalize caller that the packet is to be dropped. */
 +	if (window_protected(bat_priv, seq_diff,
 +			     &orig_node->batman_seqno_reset))
 +		return -1;
 +
 +	list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 +
 +		is_duplicate |= get_bit_status(tmp_neigh_node->real_bits,
 +					       orig_node->last_real_seqno,
 +					       batman_packet->seqno);
 +
 +		if (compare_orig(tmp_neigh_node->addr, ethhdr->h_source) &&
 +		    (tmp_neigh_node->if_incoming == if_incoming))
 +			set_mark = 1;
 +		else
 +			set_mark = 0;
 +
 +		/* if the window moved, set the update flag. */
 +		need_update |= bit_get_packet(bat_priv,
 +					      tmp_neigh_node->real_bits,
 +					      seq_diff, set_mark);
 +
 +		tmp_neigh_node->real_packet_count =
 +			bit_packet_count(tmp_neigh_node->real_bits);
 +	}
 +
 +	if (need_update) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"updating last_seqno: old %d, new %d\n",
 +			orig_node->last_real_seqno, batman_packet->seqno);
 +		orig_node->last_real_seqno = batman_packet->seqno;
 +	}
 +
 +	return is_duplicate;
 +}
 +
 +/* copy primary address for bonding */
 +static void mark_bonding_address(struct bat_priv *bat_priv,
 +				 struct orig_node *orig_node,
 +				 struct orig_node *orig_neigh_node,
 +				 struct batman_packet *batman_packet)
 +
 +{
 +	if (batman_packet->flags & PRIMARIES_FIRST_HOP)
 +		memcpy(orig_neigh_node->primary_addr,
 +		       orig_node->orig, ETH_ALEN);
 +
 +	return;
 +}
 +
 +/* mark possible bond.candidates in the neighbor list */
 +void update_bonding_candidates(struct bat_priv *bat_priv,
 +			       struct orig_node *orig_node)
 +{
 +	int candidates;
 +	int interference_candidate;
 +	int best_tq;
 +	struct neigh_node *tmp_neigh_node, *tmp_neigh_node2;
 +	struct neigh_node *first_candidate, *last_candidate;
 +
 +	/* update the candidates for this originator */
 +	if (!orig_node->router) {
 +		orig_node->bond.candidates = 0;
 +		return;
 +	}
 +
 +	best_tq = orig_node->router->tq_avg;
 +
 +	/* update bond.candidates */
 +
 +	candidates = 0;
 +
 +	/* mark other nodes which also received "PRIMARIES FIRST HOP" packets
 +	 * as "bonding partner" */
 +
 +	/* first, zero the list */
 +	list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 +		tmp_neigh_node->next_bond_candidate = NULL;
 +	}
 +
 +	first_candidate = NULL;
 +	last_candidate = NULL;
 +	list_for_each_entry(tmp_neigh_node, &orig_node->neigh_list, list) {
 +
 +		/* only consider if it has the same primary address ...  */
 +		if (memcmp(orig_node->orig,
 +				tmp_neigh_node->orig_node->primary_addr,
 +				ETH_ALEN) != 0)
 +			continue;
 +
 +		/* ... and is good enough to be considered */
 +		if (tmp_neigh_node->tq_avg < best_tq - BONDING_TQ_THRESHOLD)
 +			continue;
 +
 +		/* check if we have another candidate with the same
 +		 * mac address or interface. If we do, we won't
 +		 * select this candidate because of possible interference. */
 +
 +		interference_candidate = 0;
 +		list_for_each_entry(tmp_neigh_node2,
 +				&orig_node->neigh_list, list) {
 +
 +			if (tmp_neigh_node2 == tmp_neigh_node)
 +				continue;
 +
 +			/* we only care if the other candidate is even
 +			 * considered as candidate. */
 +			if (tmp_neigh_node2->next_bond_candidate == NULL)
 +				continue;
 +
 +
 +			if ((tmp_neigh_node->if_incoming ==
 +				tmp_neigh_node2->if_incoming)
 +				|| (memcmp(tmp_neigh_node->addr,
 +				tmp_neigh_node2->addr, ETH_ALEN) == 0)) {
 +
 +				interference_candidate = 1;
 +				break;
 +			}
 +		}
 +		/* don't care further if it is an interference candidate */
 +		if (interference_candidate)
 +			continue;
 +
 +		if (first_candidate == NULL) {
 +			first_candidate = tmp_neigh_node;
 +			tmp_neigh_node->next_bond_candidate = first_candidate;
 +		} else
 +			tmp_neigh_node->next_bond_candidate = last_candidate;
 +
 +		last_candidate = tmp_neigh_node;
 +
 +		candidates++;
 +	}
 +
 +	if (candidates > 0) {
 +		first_candidate->next_bond_candidate = last_candidate;
 +		orig_node->bond.selected = first_candidate;
 +	}
 +
 +	orig_node->bond.candidates = candidates;
 +}
 +
 +void receive_bat_packet(struct ethhdr *ethhdr,
 +				struct batman_packet *batman_packet,
 +				unsigned char *hna_buff, int hna_buff_len,
 +				struct batman_if *if_incoming)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
 +	struct batman_if *batman_if;
 +	struct orig_node *orig_neigh_node, *orig_node;
 +	char has_directlink_flag;
 +	char is_my_addr = 0, is_my_orig = 0, is_my_oldorig = 0;
 +	char is_broadcast = 0, is_bidirectional, is_single_hop_neigh;
 +	char is_duplicate;
 +	uint32_t if_incoming_seqno;
 +
 +	/* Silently drop when the batman packet is actually not a
 +	 * correct packet.
 +	 *
 +	 * This might happen if a packet is padded (e.g. Ethernet has a
 +	 * minimum frame length of 64 byte) and the aggregation interprets
 +	 * it as an additional length.
 +	 *
 +	 * TODO: A more sane solution would be to have a bit in the
 +	 * batman_packet to detect whether the packet is the last
 +	 * packet in an aggregation.  Here we expect that the padding
 +	 * is always zero (or not 0x01)
 +	 */
 +	if (batman_packet->packet_type != BAT_PACKET)
 +		return;
 +
 +	/* could be changed by schedule_own_packet() */
 +	if_incoming_seqno = atomic_read(&if_incoming->seqno);
 +
 +	has_directlink_flag = (batman_packet->flags & DIRECTLINK ? 1 : 0);
 +
 +	is_single_hop_neigh = (compare_orig(ethhdr->h_source,
 +					    batman_packet->orig) ? 1 : 0);
 +
 +	bat_dbg(DBG_BATMAN, bat_priv,
 +		"Received BATMAN packet via NB: %pM, IF: %s [%s] "
 +		"(from OG: %pM, via prev OG: %pM, seqno %d, tq %d, "
 +		"TTL %d, V %d, IDF %d)\n",
 +		ethhdr->h_source, if_incoming->net_dev->name,
 +		if_incoming->addr_str, batman_packet->orig,
 +		batman_packet->prev_sender, batman_packet->seqno,
 +		batman_packet->tq, batman_packet->ttl, batman_packet->version,
 +		has_directlink_flag);
 +
 +	list_for_each_entry_rcu(batman_if, &if_list, list) {
 +		if (batman_if->if_status != IF_ACTIVE)
 +			continue;
 +
 +		if (batman_if->soft_iface != if_incoming->soft_iface)
 +			continue;
 +
 +		if (compare_orig(ethhdr->h_source,
 +				 batman_if->net_dev->dev_addr))
 +			is_my_addr = 1;
 +
 +		if (compare_orig(batman_packet->orig,
 +				 batman_if->net_dev->dev_addr))
 +			is_my_orig = 1;
 +
 +		if (compare_orig(batman_packet->prev_sender,
 +				 batman_if->net_dev->dev_addr))
 +			is_my_oldorig = 1;
 +
 +		if (compare_orig(ethhdr->h_source, broadcast_addr))
 +			is_broadcast = 1;
 +	}
 +
 +	if (batman_packet->version != COMPAT_VERSION) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: incompatible batman version (%i)\n",
 +			batman_packet->version);
 +		return;
 +	}
 +
 +	if (is_my_addr) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: received my own broadcast (sender: %pM"
 +			")\n",
 +			ethhdr->h_source);
 +		return;
 +	}
 +
 +	if (is_broadcast) {
 +		bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
 +		"ignoring all packets with broadcast source addr (sender: %pM"
 +		")\n", ethhdr->h_source);
 +		return;
 +	}
 +
 +	if (is_my_orig) {
 +		TYPE_OF_WORD *word;
 +		int offset;
 +
 +		orig_neigh_node = get_orig_node(bat_priv, ethhdr->h_source);
 +
 +		if (!orig_neigh_node)
 +			return;
 +
 +		/* neighbor has to indicate direct link and it has to
 +		 * come via the corresponding interface */
 +		/* if received seqno equals last send seqno save new
 +		 * seqno for bidirectional check */
 +		if (has_directlink_flag &&
 +		    compare_orig(if_incoming->net_dev->dev_addr,
 +				 batman_packet->orig) &&
 +		    (batman_packet->seqno - if_incoming_seqno + 2 == 0)) {
 +			offset = if_incoming->if_num * NUM_WORDS;
 +			word = &(orig_neigh_node->bcast_own[offset]);
 +			bit_mark(word, 0);
 +			orig_neigh_node->bcast_own_sum[if_incoming->if_num] =
 +				bit_packet_count(word);
 +		}
 +
 +		bat_dbg(DBG_BATMAN, bat_priv, "Drop packet: "
 +			"originator packet from myself (via neighbor)\n");
 +		return;
 +	}
 +
 +	if (is_my_oldorig) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: ignoring all rebroadcast echos (sender: "
 +			"%pM)\n", ethhdr->h_source);
 +		return;
 +	}
 +
 +	orig_node = get_orig_node(bat_priv, batman_packet->orig);
 +	if (orig_node == NULL)
 +		return;
 +
 +	is_duplicate = count_real_packets(ethhdr, batman_packet, if_incoming);
 +
 +	if (is_duplicate == -1) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: packet within seqno protection time "
 +			"(sender: %pM)\n", ethhdr->h_source);
 +		return;
 +	}
 +
 +	if (batman_packet->tq == 0) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: originator packet with tq equal 0\n");
 +		return;
 +	}
 +
 +	/* avoid temporary routing loops */
 +	if ((orig_node->router) &&
 +	    (orig_node->router->orig_node->router) &&
 +	    (compare_orig(orig_node->router->addr,
 +			  batman_packet->prev_sender)) &&
 +	    !(compare_orig(batman_packet->orig, batman_packet->prev_sender)) &&
 +	    (compare_orig(orig_node->router->addr,
 +			  orig_node->router->orig_node->router->addr))) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: ignoring all rebroadcast packets that "
 +			"may make me loop (sender: %pM)\n", ethhdr->h_source);
 +		return;
 +	}
 +
 +	/* if sender is a direct neighbor the sender mac equals
 +	 * originator mac */
 +	orig_neigh_node = (is_single_hop_neigh ?
 +			   orig_node :
 +			   get_orig_node(bat_priv, ethhdr->h_source));
 +	if (orig_neigh_node == NULL)
 +		return;
 +
 +	/* drop packet if sender is not a direct neighbor and if we
 +	 * don't route towards it */
 +	if (!is_single_hop_neigh &&
 +	    (orig_neigh_node->router == NULL)) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: OGM via unknown neighbor!\n");
 +		return;
 +	}
 +
 +	is_bidirectional = is_bidirectional_neigh(orig_node, orig_neigh_node,
 +						batman_packet, if_incoming);
 +
 +	/* update ranking if it is not a duplicate or has the same
 +	 * seqno and similar ttl as the non-duplicate */
 +	if (is_bidirectional &&
 +	    (!is_duplicate ||
 +	     ((orig_node->last_real_seqno == batman_packet->seqno) &&
 +	      (orig_node->last_ttl - 3 <= batman_packet->ttl))))
 +		update_orig(bat_priv, orig_node, ethhdr, batman_packet,
 +			    if_incoming, hna_buff, hna_buff_len, is_duplicate);
 +
 +	mark_bonding_address(bat_priv, orig_node,
 +			     orig_neigh_node, batman_packet);
 +	update_bonding_candidates(bat_priv, orig_node);
 +
 +	/* is single hop (direct) neighbor */
 +	if (is_single_hop_neigh) {
 +
 +		/* mark direct link on incoming interface */
 +		schedule_forward_packet(orig_node, ethhdr, batman_packet,
 +					1, hna_buff_len, if_incoming);
 +
 +		bat_dbg(DBG_BATMAN, bat_priv, "Forwarding packet: "
 +			"rebroadcast neighbor packet with direct link flag\n");
 +		return;
 +	}
 +
 +	/* multihop originator */
 +	if (!is_bidirectional) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: not received via bidirectional link\n");
 +		return;
 +	}
 +
 +	if (is_duplicate) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: duplicate packet received\n");
 +		return;
 +	}
 +
 +	bat_dbg(DBG_BATMAN, bat_priv,
 +		"Forwarding packet: rebroadcast originator packet\n");
 +	schedule_forward_packet(orig_node, ethhdr, batman_packet,
 +				0, hna_buff_len, if_incoming);
 +}
 +
 +int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
 +	struct ethhdr *ethhdr;
 +	unsigned long flags;
 +
 +	/* drop packet if it has not necessary minimum size */
 +	if (unlikely(!pskb_may_pull(skb, sizeof(struct batman_packet))))
 +		return NET_RX_DROP;
 +
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* packet with broadcast indication but unicast recipient */
 +	if (!is_bcast(ethhdr->h_dest))
 +		return NET_RX_DROP;
 +
 +	/* packet with broadcast sender address */
 +	if (is_bcast(ethhdr->h_source))
 +		return NET_RX_DROP;
 +
 +	/* create a copy of the skb, if needed, to modify it. */
 +	if (skb_cow(skb, 0) < 0)
 +		return NET_RX_DROP;
 +
 +	/* keep skb linear */
 +	if (skb_linearize(skb) < 0)
 +		return NET_RX_DROP;
 +
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	receive_aggr_bat_packet(ethhdr,
 +				skb->data,
 +				skb_headlen(skb),
 +				batman_if);
 +	spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +	kfree_skb(skb);
 +	return NET_RX_SUCCESS;
 +}
 +
 +static int recv_my_icmp_packet(struct bat_priv *bat_priv,
 +			       struct sk_buff *skb, size_t icmp_len)
 +{
 +	struct orig_node *orig_node;
 +	struct icmp_packet_rr *icmp_packet;
 +	struct ethhdr *ethhdr;
 +	struct batman_if *batman_if;
 +	int ret;
 +	unsigned long flags;
 +	uint8_t dstaddr[ETH_ALEN];
 +
 +	icmp_packet = (struct icmp_packet_rr *)skb->data;
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* add data to device queue */
 +	if (icmp_packet->msg_type != ECHO_REQUEST) {
 +		bat_socket_receive_packet(icmp_packet, icmp_len);
 +		return NET_RX_DROP;
 +	}
 +
 +	if (!bat_priv->primary_if)
 +		return NET_RX_DROP;
 +
 +	/* answer echo request (ping) */
 +	/* get routing information */
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
 +						   icmp_packet->orig));
 +	ret = NET_RX_DROP;
 +
 +	if ((orig_node != NULL) &&
 +	    (orig_node->router != NULL)) {
 +
 +		/* don't lock while sending the packets ... we therefore
 +		 * copy the required data before sending */
 +		batman_if = orig_node->router->if_incoming;
 +		memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +		/* create a copy of the skb, if needed, to modify it. */
 +		if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
 +			return NET_RX_DROP;
 +
 +		icmp_packet = (struct icmp_packet_rr *)skb->data;
 +		ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +		memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
 +		memcpy(icmp_packet->orig,
 +		       bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
 +		icmp_packet->msg_type = ECHO_REPLY;
 +		icmp_packet->ttl = TTL;
 +
 +		send_skb_packet(skb, batman_if, dstaddr);
 +		ret = NET_RX_SUCCESS;
 +
 +	} else
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +	return ret;
 +}
 +
 +static int recv_icmp_ttl_exceeded(struct bat_priv *bat_priv,
 +				  struct sk_buff *skb, size_t icmp_len)
 +{
 +	struct orig_node *orig_node;
 +	struct icmp_packet *icmp_packet;
 +	struct ethhdr *ethhdr;
 +	struct batman_if *batman_if;
 +	int ret;
 +	unsigned long flags;
 +	uint8_t dstaddr[ETH_ALEN];
 +
 +	icmp_packet = (struct icmp_packet *)skb->data;
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* send TTL exceeded if packet is an echo request (traceroute) */
 +	if (icmp_packet->msg_type != ECHO_REQUEST) {
 +		pr_debug("Warning - can't forward icmp packet from %pM to "
 +			 "%pM: ttl exceeded\n", icmp_packet->orig,
 +			 icmp_packet->dst);
 +		return NET_RX_DROP;
 +	}
 +
 +	if (!bat_priv->primary_if)
 +		return NET_RX_DROP;
 +
 +	/* get routing information */
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	orig_node = ((struct orig_node *)
 +		     hash_find(bat_priv->orig_hash, icmp_packet->orig));
 +	ret = NET_RX_DROP;
 +
 +	if ((orig_node != NULL) &&
 +	    (orig_node->router != NULL)) {
 +
 +		/* don't lock while sending the packets ... we therefore
 +		 * copy the required data before sending */
 +		batman_if = orig_node->router->if_incoming;
 +		memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +		/* create a copy of the skb, if needed, to modify it. */
 +		if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
 +			return NET_RX_DROP;
 +
 +		icmp_packet = (struct icmp_packet *) skb->data;
 +		ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +		memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
 +		memcpy(icmp_packet->orig,
 +		       bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN);
 +		icmp_packet->msg_type = TTL_EXCEEDED;
 +		icmp_packet->ttl = TTL;
 +
 +		send_skb_packet(skb, batman_if, dstaddr);
 +		ret = NET_RX_SUCCESS;
 +
 +	} else
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +	return ret;
 +}
 +
 +
 +int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 +	struct icmp_packet_rr *icmp_packet;
 +	struct ethhdr *ethhdr;
 +	struct orig_node *orig_node;
 +	struct batman_if *batman_if;
 +	int hdr_size = sizeof(struct icmp_packet);
 +	int ret;
 +	unsigned long flags;
 +	uint8_t dstaddr[ETH_ALEN];
 +
 +	/**
 +	 * we truncate all incoming icmp packets if they don't match our size
 +	 */
 +	if (skb->len >= sizeof(struct icmp_packet_rr))
 +		hdr_size = sizeof(struct icmp_packet_rr);
 +
 +	/* drop packet if it has not necessary minimum size */
 +	if (unlikely(!pskb_may_pull(skb, hdr_size)))
 +		return NET_RX_DROP;
 +
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* packet with unicast indication but broadcast recipient */
 +	if (is_bcast(ethhdr->h_dest))
 +		return NET_RX_DROP;
 +
 +	/* packet with broadcast sender address */
 +	if (is_bcast(ethhdr->h_source))
 +		return NET_RX_DROP;
 +
 +	/* not for me */
 +	if (!is_my_mac(ethhdr->h_dest))
 +		return NET_RX_DROP;
 +
 +	icmp_packet = (struct icmp_packet_rr *)skb->data;
 +
 +	/* add record route information if not full */
 +	if ((hdr_size == sizeof(struct icmp_packet_rr)) &&
 +	    (icmp_packet->rr_cur < BAT_RR_LEN)) {
 +		memcpy(&(icmp_packet->rr[icmp_packet->rr_cur]),
 +			ethhdr->h_dest, ETH_ALEN);
 +		icmp_packet->rr_cur++;
 +	}
 +
 +	/* packet for me */
 +	if (is_my_mac(icmp_packet->dst))
 +		return recv_my_icmp_packet(bat_priv, skb, hdr_size);
 +
 +	/* TTL exceeded */
 +	if (icmp_packet->ttl < 2)
 +		return recv_icmp_ttl_exceeded(bat_priv, skb, hdr_size);
 +
 +	ret = NET_RX_DROP;
 +
 +	/* get routing information */
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	orig_node = ((struct orig_node *)
 +		     hash_find(bat_priv->orig_hash, icmp_packet->dst));
 +
 +	if ((orig_node != NULL) &&
 +	    (orig_node->router != NULL)) {
 +
 +		/* don't lock while sending the packets ... we therefore
 +		 * copy the required data before sending */
 +		batman_if = orig_node->router->if_incoming;
 +		memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +		/* create a copy of the skb, if needed, to modify it. */
 +		if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
 +			return NET_RX_DROP;
 +
 +		icmp_packet = (struct icmp_packet_rr *)skb->data;
 +		ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +		/* decrement ttl */
 +		icmp_packet->ttl--;
 +
 +		/* route it */
 +		send_skb_packet(skb, batman_if, dstaddr);
 +		ret = NET_RX_SUCCESS;
 +
 +	} else
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +	return ret;
 +}
 +
 +/* find a suitable router for this originator, and use
 + * bonding if possible. */
 +struct neigh_node *find_router(struct orig_node *orig_node,
 +			       struct batman_if *recv_if)
 +{
 +	struct bat_priv *bat_priv;
 +	struct orig_node *primary_orig_node;
 +	struct orig_node *router_orig;
 +	struct neigh_node *router, *first_candidate, *best_router;
 +	static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 +	int bonding_enabled;
 +
 +	if (!orig_node)
 +		return NULL;
 +
 +	if (!orig_node->router)
 +		return NULL;
 +
 +	/* without bonding, the first node should
 +	 * always choose the default router. */
 +
 +	if (!recv_if)
 +		return orig_node->router;
 +
 +	bat_priv = netdev_priv(recv_if->soft_iface);
 +	bonding_enabled = atomic_read(&bat_priv->bonding_enabled);
 +
 +	if (!bonding_enabled)
 +		return orig_node->router;
 +
 +	router_orig = orig_node->router->orig_node;
 +
 +	/* if we have something in the primary_addr, we can search
 +	 * for a potential bonding candidate. */
 +	if (memcmp(router_orig->primary_addr, zero_mac, ETH_ALEN) == 0)
 +		return orig_node->router;
 +
 +	/* find the orig_node which has the primary interface. might
 +	 * even be the same as our router_orig in many cases */
 +
 +	if (memcmp(router_orig->primary_addr,
 +				router_orig->orig, ETH_ALEN) == 0) {
 +		primary_orig_node = router_orig;
 +	} else {
 +		primary_orig_node = hash_find(bat_priv->orig_hash,
 +						router_orig->primary_addr);
 +
 +		if (!primary_orig_node)
 +			return orig_node->router;
 +	}
 +
 +	/* with less than 2 candidates, we can't do any
 +	 * bonding and prefer the original router. */
 +
 +	if (primary_orig_node->bond.candidates < 2)
 +		return orig_node->router;
 +
 +
 +	/* all nodes between should choose a candidate which
 +	 * is is not on the interface where the packet came
 +	 * in. */
 +	first_candidate = primary_orig_node->bond.selected;
 +	router = first_candidate;
 +
 +	if (bonding_enabled) {
 +		/* in the bonding case, send the packets in a round
 +		 * robin fashion over the remaining interfaces. */
 +		do {
 +			/* recv_if == NULL on the first node. */
 +			if (router->if_incoming != recv_if)
 +				break;
 +
 +			router = router->next_bond_candidate;
 +		} while (router != first_candidate);
 +
 +		primary_orig_node->bond.selected = router->next_bond_candidate;
 +
 +	} else {
 +		/* if bonding is disabled, use the best of the
 +		 * remaining candidates which are not using
 +		 * this interface. */
 +		best_router = first_candidate;
 +
 +		do {
 +			/* recv_if == NULL on the first node. */
 +			if ((router->if_incoming != recv_if) &&
 +				(router->tq_avg > best_router->tq_avg))
 +					best_router = router;
 +
 +			router = router->next_bond_candidate;
 +		} while (router != first_candidate);
 +
 +		router = best_router;
 +	}
 +
 +	return router;
 +}
 +
 +static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
 +{
 +	struct ethhdr *ethhdr;
 +
 +	/* drop packet if it has not necessary minimum size */
 +	if (unlikely(!pskb_may_pull(skb, hdr_size)))
 +		return -1;
 +
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* packet with unicast indication but broadcast recipient */
 +	if (is_bcast(ethhdr->h_dest))
 +		return -1;
 +
 +	/* packet with broadcast sender address */
 +	if (is_bcast(ethhdr->h_source))
 +		return -1;
 +
 +	/* not for me */
 +	if (!is_my_mac(ethhdr->h_dest))
 +		return -1;
 +
 +	return 0;
 +}
 +
 +static int route_unicast_packet(struct sk_buff *skb,
 +				struct batman_if *recv_if, int hdr_size)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 +	struct orig_node *orig_node;
 +	struct neigh_node *router;
 +	struct batman_if *batman_if;
 +	uint8_t dstaddr[ETH_ALEN];
 +	unsigned long flags;
 +	struct unicast_packet *unicast_packet;
 +	struct ethhdr *ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	unicast_packet = (struct unicast_packet *)skb->data;
 +
 +	/* packet for me */
 +	if (is_my_mac(unicast_packet->dest)) {
 +		interface_rx(recv_if->soft_iface, skb, hdr_size);
 +		return NET_RX_SUCCESS;
 +	}
 +
 +	/* TTL exceeded */
 +	if (unicast_packet->ttl < 2) {
 +		pr_debug("Warning - can't forward unicast packet from %pM to "
 +			 "%pM: ttl exceeded\n", ethhdr->h_source,
 +			 unicast_packet->dest);
 +		return NET_RX_DROP;
 +	}
 +
 +	/* get routing information */
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	orig_node = ((struct orig_node *)
 +		     hash_find(bat_priv->orig_hash, unicast_packet->dest));
 +
 +	router = find_router(orig_node, recv_if);
 +
 +	if (!router) {
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +		return NET_RX_DROP;
 +	}
 +
 +	/* don't lock while sending the packets ... we therefore
 +	 * copy the required data before sending */
 +
 +	batman_if = router->if_incoming;
 +	memcpy(dstaddr, router->addr, ETH_ALEN);
 +
 +	spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +
 +	/* create a copy of the skb, if needed, to modify it. */
 +	if (skb_cow(skb, sizeof(struct ethhdr)) < 0)
 +		return NET_RX_DROP;
 +
 +	unicast_packet = (struct unicast_packet *)skb->data;
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* decrement ttl */
 +	unicast_packet->ttl--;
 +
 +	/* route it */
 +	send_skb_packet(skb, batman_if, dstaddr);
 +
 +	return NET_RX_SUCCESS;
 +}
 +
 +int recv_unicast_packet(struct sk_buff *skb, struct batman_if *recv_if)
 +{
 +	struct unicast_packet *unicast_packet;
 +	int hdr_size = sizeof(struct unicast_packet);
 +
 +	if (check_unicast_packet(skb, hdr_size) < 0)
 +		return NET_RX_DROP;
 +
 +	unicast_packet = (struct unicast_packet *)skb->data;
 +
 +	/* packet for me */
 +	if (is_my_mac(unicast_packet->dest)) {
 +		interface_rx(recv_if->soft_iface, skb, hdr_size);
 +		return NET_RX_SUCCESS;
 +	}
 +
 +	return route_unicast_packet(skb, recv_if, hdr_size);
 +}
 +
 +int recv_ucast_frag_packet(struct sk_buff *skb, struct batman_if *recv_if)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 +	struct unicast_frag_packet *unicast_packet;
 +	struct orig_node *orig_node;
 +	struct frag_packet_list_entry *tmp_frag_entry;
 +	int hdr_size = sizeof(struct unicast_frag_packet);
 +	unsigned long flags;
 +
 +	if (check_unicast_packet(skb, hdr_size) < 0)
 +		return NET_RX_DROP;
 +
 +	unicast_packet = (struct unicast_frag_packet *)skb->data;
 +
 +	/* packet for me */
 +	if (is_my_mac(unicast_packet->dest)) {
 +
 +		spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +		orig_node = ((struct orig_node *)
 +			hash_find(bat_priv->orig_hash, unicast_packet->orig));
 +
 +		if (!orig_node) {
 +			pr_debug("couldn't find orig node for fragmentation\n");
 +			spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
 +					       flags);
 +			return NET_RX_DROP;
 +		}
 +
 +		orig_node->last_frag_packet = jiffies;
 +
- 		if (list_empty(&orig_node->frag_list))
- 			create_frag_buffer(&orig_node->frag_list);
++		if (list_empty(&orig_node->frag_list)) {
++			if (create_frag_buffer(&orig_node->frag_list))
++				return NET_RX_DROP;
++		}
 +
 +		tmp_frag_entry =
 +			search_frag_packet(&orig_node->frag_list,
 +					   unicast_packet);
 +
 +		if (!tmp_frag_entry) {
 +			create_frag_entry(&orig_node->frag_list, skb);
 +			spin_unlock_irqrestore(&bat_priv->orig_hash_lock,
 +					       flags);
 +			return NET_RX_SUCCESS;
 +		}
 +
 +		skb = merge_frag_packet(&orig_node->frag_list,
 +					tmp_frag_entry, skb);
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +		if (!skb)
 +			return NET_RX_DROP;
 +
 +		interface_rx(recv_if->soft_iface, skb, hdr_size);
 +		return NET_RX_SUCCESS;
 +	}
 +
 +	return route_unicast_packet(skb, recv_if, hdr_size);
 +}
 +
 +
 +int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 +	struct orig_node *orig_node;
 +	struct bcast_packet *bcast_packet;
 +	struct ethhdr *ethhdr;
 +	int hdr_size = sizeof(struct bcast_packet);
 +	int32_t seq_diff;
 +	unsigned long flags;
 +
 +	/* drop packet if it has not necessary minimum size */
 +	if (unlikely(!pskb_may_pull(skb, hdr_size)))
 +		return NET_RX_DROP;
 +
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* packet with broadcast indication but unicast recipient */
 +	if (!is_bcast(ethhdr->h_dest))
 +		return NET_RX_DROP;
 +
 +	/* packet with broadcast sender address */
 +	if (is_bcast(ethhdr->h_source))
 +		return NET_RX_DROP;
 +
 +	/* ignore broadcasts sent by myself */
 +	if (is_my_mac(ethhdr->h_source))
 +		return NET_RX_DROP;
 +
 +	bcast_packet = (struct bcast_packet *)skb->data;
 +
 +	/* ignore broadcasts originated by myself */
 +	if (is_my_mac(bcast_packet->orig))
 +		return NET_RX_DROP;
 +
 +	if (bcast_packet->ttl < 2)
 +		return NET_RX_DROP;
 +
 +	spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
 +	orig_node = ((struct orig_node *)
 +		     hash_find(bat_priv->orig_hash, bcast_packet->orig));
 +
 +	if (orig_node == NULL) {
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +		return NET_RX_DROP;
 +	}
 +
 +	/* check whether the packet is a duplicate */
 +	if (get_bit_status(orig_node->bcast_bits,
 +			   orig_node->last_bcast_seqno,
 +			   ntohl(bcast_packet->seqno))) {
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +		return NET_RX_DROP;
 +	}
 +
 +	seq_diff = ntohl(bcast_packet->seqno) - orig_node->last_bcast_seqno;
 +
 +	/* check whether the packet is old and the host just restarted. */
 +	if (window_protected(bat_priv, seq_diff,
 +			     &orig_node->bcast_seqno_reset)) {
 +		spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +		return NET_RX_DROP;
 +	}
 +
 +	/* mark broadcast in flood history, update window position
 +	 * if required. */
 +	if (bit_get_packet(bat_priv, orig_node->bcast_bits, seq_diff, 1))
 +		orig_node->last_bcast_seqno = ntohl(bcast_packet->seqno);
 +
 +	spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
 +	/* rebroadcast packet */
 +	add_bcast_packet_to_list(bat_priv, skb);
 +
 +	/* broadcast for me */
 +	interface_rx(recv_if->soft_iface, skb, hdr_size);
 +
 +	return NET_RX_SUCCESS;
 +}
 +
 +int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if)
 +{
 +	struct vis_packet *vis_packet;
 +	struct ethhdr *ethhdr;
 +	struct bat_priv *bat_priv = netdev_priv(recv_if->soft_iface);
 +	int hdr_size = sizeof(struct vis_packet);
 +
 +	/* keep skb linear */
 +	if (skb_linearize(skb) < 0)
 +		return NET_RX_DROP;
 +
 +	if (unlikely(!pskb_may_pull(skb, hdr_size)))
 +		return NET_RX_DROP;
 +
 +	vis_packet = (struct vis_packet *)skb->data;
 +	ethhdr = (struct ethhdr *)skb_mac_header(skb);
 +
 +	/* not for me */
 +	if (!is_my_mac(ethhdr->h_dest))
 +		return NET_RX_DROP;
 +
 +	/* ignore own packets */
 +	if (is_my_mac(vis_packet->vis_orig))
 +		return NET_RX_DROP;
 +
 +	if (is_my_mac(vis_packet->sender_orig))
 +		return NET_RX_DROP;
 +
 +	switch (vis_packet->vis_type) {
 +	case VIS_TYPE_SERVER_SYNC:
 +		receive_server_sync_packet(bat_priv, vis_packet,
 +					   skb_headlen(skb));
 +		break;
 +
 +	case VIS_TYPE_CLIENT_UPDATE:
 +		receive_client_update_packet(bat_priv, vis_packet,
 +					     skb_headlen(skb));
 +		break;
 +
 +	default:	/* ignore unknown packet */
 +		break;
 +	}
 +
 +	/* We take a copy of the data in the packet, so we should
 +	   always free the skbuf. */
 +	return NET_RX_DROP;
 +}
diff --combined drivers/staging/batman-adv/soft-interface.c
index 8d14343,0000000..3904db9
mode 100644,000000..100644
--- a/drivers/staging/batman-adv/soft-interface.c
+++ b/drivers/staging/batman-adv/soft-interface.c
@@@ -1,395 -1,0 +1,392 @@@
 +/*
 + * Copyright (C) 2007-2010 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
 + *
 + */
 +
 +#include "main.h"
 +#include "soft-interface.h"
 +#include "hard-interface.h"
 +#include "routing.h"
 +#include "send.h"
 +#include "bat_debugfs.h"
 +#include "translation-table.h"
 +#include "types.h"
 +#include "hash.h"
 +#include "send.h"
 +#include "bat_sysfs.h"
 +#include <linux/slab.h>
 +#include <linux/ethtool.h>
 +#include <linux/etherdevice.h>
 +#include "unicast.h"
 +
 +
 +static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd);
 +static void bat_get_drvinfo(struct net_device *dev,
 +			    struct ethtool_drvinfo *info);
 +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,
 +	.get_drvinfo = bat_get_drvinfo,
 +	.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)
 +{
 +	int result;
 +
 +	/**
 +	 * TODO: We must check if we can release all references to non-payload
 +	 * data using skb_header_release in our skbs to allow skb_cow_header to
 +	 * work optimally. This means that those skbs are not allowed to read
 +	 * or write any data which is before the current position of skb->data
 +	 * after that call and thus allow other skbs with the same data buffer
 +	 * to write freely in that area.
 +	 */
 +	result = skb_cow_head(skb, len);
 +	if (result < 0)
 +		return result;
 +
 +	skb_push(skb, len);
 +	return 0;
 +}
 +
 +static int interface_open(struct net_device *dev)
 +{
 +	netif_start_queue(dev);
 +	return 0;
 +}
 +
 +static int interface_release(struct net_device *dev)
 +{
 +	netif_stop_queue(dev);
 +	return 0;
 +}
 +
 +static struct net_device_stats *interface_stats(struct net_device *dev)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(dev);
 +	return &bat_priv->stats;
 +}
 +
 +static int interface_set_mac_addr(struct net_device *dev, void *p)
 +{
 +	struct bat_priv *bat_priv = netdev_priv(dev);
 +	struct sockaddr *addr = p;
 +
 +	if (!is_valid_ether_addr(addr->sa_data))
 +		return -EADDRNOTAVAIL;
 +
 +	/* only modify hna-table if it has been initialised before */
 +	if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) {
 +		hna_local_remove(bat_priv, dev->dev_addr,
 +				 "mac address changed");
 +		hna_local_add(dev, addr->sa_data);
 +	}
 +
 +	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 +
 +	return 0;
 +}
 +
 +static int interface_change_mtu(struct net_device *dev, int new_mtu)
 +{
 +	/* check ranges */
 +	if ((new_mtu < 68) || (new_mtu > hardif_min_mtu(dev)))
 +		return -EINVAL;
 +
 +	dev->mtu = new_mtu;
 +
 +	return 0;
 +}
 +
 +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 bcast_packet *bcast_packet;
 +	int data_len = skb->len, ret;
 +
 +	if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
 +		goto dropped;
 +
 +	soft_iface->trans_start = jiffies;
 +
 +	/* TODO: check this for locks */
 +	hna_local_add(soft_iface, ethhdr->h_source);
 +
 +	/* ethernet packet should be broadcasted */
 +	if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
 +		if (!bat_priv->primary_if)
 +			goto dropped;
 +
 +		if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0)
 +			goto dropped;
 +
 +		bcast_packet = (struct bcast_packet *)skb->data;
 +		bcast_packet->version = COMPAT_VERSION;
 +		bcast_packet->ttl = TTL;
 +
 +		/* batman packet type: broadcast */
 +		bcast_packet->packet_type = BAT_BCAST;
 +
 +		/* 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);
 +
 +		/* set broadcast sequence number */
 +		bcast_packet->seqno =
 +			htonl(atomic_inc_return(&bat_priv->bcast_seqno));
 +
 +		add_bcast_packet_to_list(bat_priv, skb);
 +
 +		/* a copy is stored in the bcast list, therefore removing
 +		 * the original skb. */
 +		kfree_skb(skb);
 +
 +	/* unicast packet */
 +	} else {
 +		ret = unicast_send_skb(skb, bat_priv);
 +		if (ret != 0)
 +			goto dropped_freed;
 +	}
 +
 +	bat_priv->stats.tx_packets++;
 +	bat_priv->stats.tx_bytes += data_len;
 +	goto end;
 +
 +dropped:
 +	kfree_skb(skb);
 +dropped_freed:
 +	bat_priv->stats.tx_dropped++;
 +end:
 +	return NETDEV_TX_OK;
 +}
 +
 +void interface_rx(struct net_device *soft_iface,
 +		  struct sk_buff *skb, int hdr_size)
 +{
 +	struct bat_priv *priv = netdev_priv(soft_iface);
 +
 +	/* check if enough space is available for pulling, and pull */
 +	if (!pskb_may_pull(skb, hdr_size)) {
 +		kfree_skb(skb);
 +		return;
 +	}
 +	skb_pull_rcsum(skb, hdr_size);
 +/*	skb_set_mac_header(skb, -sizeof(struct ethhdr));*/
 +
- 	skb->dev = soft_iface;
++	/* skb->dev & skb->pkt_type are set here */
 +	skb->protocol = eth_type_trans(skb, soft_iface);
 +
 +	/* should not be neccesary anymore as we use skb_pull_rcsum()
 +	 * TODO: please verify this and remove this TODO
 +	 * -- Dec 21st 2009, Simon Wunderlich */
 +
 +/*	skb->ip_summed = CHECKSUM_UNNECESSARY;*/
- 
- 	/* TODO: set skb->pkt_type to PACKET_BROADCAST, PACKET_MULTICAST,
- 	 * PACKET_OTHERHOST or PACKET_HOST */
 +
 +	priv->stats.rx_packets++;
 +	priv->stats.rx_bytes += skb->len + sizeof(struct ethhdr);
 +
 +	soft_iface->last_rx = jiffies;
 +
 +	netif_rx(skb);
 +}
 +
 +#ifdef HAVE_NET_DEVICE_OPS
 +static const struct net_device_ops bat_netdev_ops = {
 +	.ndo_open = interface_open,
 +	.ndo_stop = interface_release,
 +	.ndo_get_stats = interface_stats,
 +	.ndo_set_mac_address = interface_set_mac_addr,
 +	.ndo_change_mtu = interface_change_mtu,
 +	.ndo_start_xmit = interface_tx,
 +	.ndo_validate_addr = eth_validate_addr
 +};
 +#endif
 +
 +static void interface_setup(struct net_device *dev)
 +{
 +	struct bat_priv *priv = netdev_priv(dev);
 +	char dev_addr[ETH_ALEN];
 +
 +	ether_setup(dev);
 +
 +#ifdef HAVE_NET_DEVICE_OPS
 +	dev->netdev_ops = &bat_netdev_ops;
 +#else
 +	dev->open = interface_open;
 +	dev->stop = interface_release;
 +	dev->get_stats = interface_stats;
 +	dev->set_mac_address = interface_set_mac_addr;
 +	dev->change_mtu = interface_change_mtu;
 +	dev->hard_start_xmit = interface_tx;
 +#endif
 +	dev->destructor = free_netdev;
 +
 +	/**
 +	 * 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 */
 +
 +	/* generate random address */
 +	random_ether_addr(dev_addr);
 +	memcpy(dev->dev_addr, dev_addr, ETH_ALEN);
 +
 +	SET_ETHTOOL_OPS(dev, &bat_ethtool_ops);
 +
 +	memset(priv, 0, sizeof(struct bat_priv));
 +}
 +
 +struct net_device *softif_create(char *name)
 +{
 +	struct net_device *soft_iface;
 +	struct bat_priv *bat_priv;
 +	int ret;
 +
 +	soft_iface = alloc_netdev(sizeof(struct bat_priv) , name,
 +				   interface_setup);
 +
 +	if (!soft_iface) {
 +		pr_err("Unable to allocate the batman interface: %s\n", name);
 +		goto out;
 +	}
 +
 +	ret = register_netdev(soft_iface);
 +	if (ret < 0) {
 +		pr_err("Unable to register the batman interface '%s': %i\n",
 +		       name, ret);
 +		goto free_soft_iface;
 +	}
 +
 +	bat_priv = netdev_priv(soft_iface);
 +
 +	atomic_set(&bat_priv->aggregation_enabled, 1);
 +	atomic_set(&bat_priv->bonding_enabled, 0);
 +	atomic_set(&bat_priv->vis_mode, VIS_TYPE_CLIENT_UPDATE);
 +	atomic_set(&bat_priv->orig_interval, 1000);
 +	atomic_set(&bat_priv->log_level, 0);
 +	atomic_set(&bat_priv->frag_enabled, 1);
 +	atomic_set(&bat_priv->bcast_queue_left, BCAST_QUEUE_LEN);
 +	atomic_set(&bat_priv->batman_queue_left, BATMAN_QUEUE_LEN);
 +
 +	atomic_set(&bat_priv->mesh_state, MESH_INACTIVE);
 +	atomic_set(&bat_priv->bcast_seqno, 1);
 +	atomic_set(&bat_priv->hna_local_changed, 0);
 +
 +	bat_priv->primary_if = NULL;
 +	bat_priv->num_ifaces = 0;
 +
 +	ret = sysfs_add_meshif(soft_iface);
 +	if (ret < 0)
 +		goto unreg_soft_iface;
 +
 +	ret = debugfs_add_meshif(soft_iface);
 +	if (ret < 0)
 +		goto unreg_sysfs;
 +
 +	ret = mesh_init(soft_iface);
 +	if (ret < 0)
 +		goto unreg_debugfs;
 +
 +	return soft_iface;
 +
 +unreg_debugfs:
 +	debugfs_del_meshif(soft_iface);
 +unreg_sysfs:
 +	sysfs_del_meshif(soft_iface);
 +unreg_soft_iface:
 +	unregister_netdev(soft_iface);
 +	return NULL;
 +
 +free_soft_iface:
 +	free_netdev(soft_iface);
 +out:
 +	return NULL;
 +}
 +
 +void softif_destroy(struct net_device *soft_iface)
 +{
 +	debugfs_del_meshif(soft_iface);
 +	sysfs_del_meshif(soft_iface);
 +	mesh_free(soft_iface);
 +	unregister_netdevice(soft_iface);
 +}
 +
 +/* ethtool */
 +static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 +{
 +	cmd->supported = 0;
 +	cmd->advertising = 0;
 +	cmd->speed = SPEED_10;
 +	cmd->duplex = DUPLEX_FULL;
 +	cmd->port = PORT_TP;
 +	cmd->phy_address = 0;
 +	cmd->transceiver = XCVR_INTERNAL;
 +	cmd->autoneg = AUTONEG_DISABLE;
 +	cmd->maxtxpkt = 0;
 +	cmd->maxrxpkt = 0;
 +
 +	return 0;
 +}
 +
 +static void bat_get_drvinfo(struct net_device *dev,
 +			    struct ethtool_drvinfo *info)
 +{
 +	strcpy(info->driver, "B.A.T.M.A.N. advanced");
 +	strcpy(info->version, SOURCE_VERSION);
 +	strcpy(info->fw_version, "N/A");
 +	strcpy(info->bus_info, "batman");
 +}
 +
 +static u32 bat_get_msglevel(struct net_device *dev)
 +{
 +	return -EOPNOTSUPP;
 +}
 +
 +static void bat_set_msglevel(struct net_device *dev, u32 value)
 +{
 +}
 +
 +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;
 +}
diff --combined drivers/staging/batman-adv/types.h
index e779c4a,9d744d8..9d744d8
--- a/drivers/staging/batman-adv/types.h
+++ b/drivers/staging/batman-adv/types.h
@@@ -128,7 -128,6 +128,6 @@@ struct bat_priv 
  	struct dentry *debug_dir;
  	struct hlist_head forw_bat_list;
  	struct hlist_head forw_bcast_list;
- 	struct hlist_head gw_list;
  	struct list_head vis_send_list;
  	struct hashtable_t *orig_hash;
  	struct hashtable_t *hna_local_hash;
@@@ -139,7 -138,6 +138,6 @@@
  	spinlock_t forw_bcast_list_lock;
  	spinlock_t hna_lhash_lock;
  	spinlock_t hna_ghash_lock;
- 	spinlock_t gw_list_lock;
  	spinlock_t vis_hash_lock;
  	spinlock_t vis_list_lock;
  	int16_t num_local_hna;
@@@ -147,7 -145,6 +145,6 @@@
  	struct delayed_work hna_work;
  	struct delayed_work orig_work;
  	struct delayed_work vis_work;
- 	struct gw_node *curr_gw;
  	struct vis_info *my_vis_info;
  };
  
diff --combined drivers/staging/batman-adv/unicast.c
index f951abc,0dac50d..0dac50d
--- a/drivers/staging/batman-adv/unicast.c
+++ b/drivers/staging/batman-adv/unicast.c
@@@ -78,7 -78,7 +78,7 @@@ void create_frag_entry(struct list_hea
  	return;
  }
  
- void create_frag_buffer(struct list_head *head)
+ int create_frag_buffer(struct list_head *head)
  {
  	int i;
  	struct frag_packet_list_entry *tfp;
@@@ -86,13 -86,17 +86,17 @@@
  	for (i = 0; i < FRAG_BUFFER_SIZE; i++) {
  		tfp = kmalloc(sizeof(struct frag_packet_list_entry),
  			GFP_ATOMIC);
+ 		if (!tfp) {
+ 			frag_list_free(head);
+ 			return -ENOMEM;
+ 		}
  		tfp->skb = NULL;
  		tfp->seqno = 0;
  		INIT_LIST_HEAD(&tfp->list);
  		list_add(&tfp->list, head);
  	}
  
- 	return;
+ 	return 0;
  }
  
  struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
diff --combined drivers/staging/batman-adv/unicast.h
index 1d5cbeb,7973697..7973697
--- a/drivers/staging/batman-adv/unicast.h
+++ b/drivers/staging/batman-adv/unicast.h
@@@ -30,7 -30,7 +30,7 @@@ struct sk_buff *merge_frag_packet(struc
  	struct sk_buff *skb);
  
  void create_frag_entry(struct list_head *head, struct sk_buff *skb);
- void create_frag_buffer(struct list_head *head);
+ int create_frag_buffer(struct list_head *head);
  struct frag_packet_list_entry *search_frag_packet(struct list_head *head,
  	struct unicast_frag_packet *up);
  void frag_list_free(struct list_head *head);

-- 
linux integration


More information about the commits mailing list