[commits] [git] linux integration branch, linux, updated. v2.6.36-rc1-459-g7fb26b6

postmaster at open-mesh.net postmaster at open-mesh.net
Sat Aug 21 13:50:44 CEST 2010


The following commit has been merged in the linux branch:
commit 7fb26b6de8848c84a8064941e2cd3287a616b2fb
Merge: e2ce75583a9ad51ec915e99206a8b39d9d36c5db e3a0cc90940915dd14e4ca6bdab6d74bbc60f4a4
Author: Sven Eckelmann <sven.eckelmann at gmx.de>
Date:   Sat Aug 21 13:34:27 2010 +0200

    Merge remote branch 'origin/next' into linux

diff --combined drivers/staging/batman-adv/hard-interface.c
index f6345c4,0000000..baa8b05
mode 100644,000000..100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@@ -1,538 -1,0 +1,541 @@@
 +/*
 + * 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 "hard-interface.h"
 +#include "soft-interface.h"
 +#include "send.h"
 +#include "translation-table.h"
 +#include "routing.h"
 +#include "bat_sysfs.h"
 +#include "originator.h"
 +#include "hash.h"
 +
 +#include <linux/if_arp.h>
 +#include <linux/netfilter_bridge.h>
 +
 +#define MIN(x, y) ((x) < (y) ? (x) : (y))
 +
 +struct batman_if *get_batman_if_by_netdev(struct net_device *net_dev)
 +{
 +	struct batman_if *batman_if;
 +
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(batman_if, &if_list, list) {
 +		if (batman_if->net_dev == net_dev)
 +			goto out;
 +	}
 +
 +	batman_if = NULL;
 +
 +out:
 +	rcu_read_unlock();
 +	return batman_if;
 +}
 +
 +static int is_valid_iface(struct net_device *net_dev)
 +{
 +	if (net_dev->flags & IFF_LOOPBACK)
 +		return 0;
 +
 +	if (net_dev->type != ARPHRD_ETHER)
 +		return 0;
 +
 +	if (net_dev->addr_len != ETH_ALEN)
 +		return 0;
 +
 +	/* no batman over batman */
 +#ifdef HAVE_NET_DEVICE_OPS
 +	if (net_dev->netdev_ops->ndo_start_xmit == interface_tx)
 +		return 0;
 +#else
 +	if (net_dev->hard_start_xmit == interface_tx)
 +		return 0;
 +#endif
 +
 +	/* Device is being bridged */
 +	/* if (net_dev->priv_flags & IFF_BRIDGE_PORT)
 +		return 0; */
 +
 +	return 1;
 +}
 +
 +static struct batman_if *get_active_batman_if(void)
 +{
 +	struct batman_if *batman_if;
 +
 +	/* TODO: should check interfaces belonging to bat_priv */
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(batman_if, &if_list, list) {
 +		if (batman_if->if_status == IF_ACTIVE)
 +			goto out;
 +	}
 +
 +	batman_if = NULL;
 +
 +out:
 +	rcu_read_unlock();
 +	return batman_if;
 +}
 +
 +static void set_primary_if(struct bat_priv *bat_priv,
 +			   struct batman_if *batman_if)
 +{
 +	struct batman_packet *batman_packet;
 +
 +	bat_priv->primary_if = batman_if;
 +
 +	if (!bat_priv->primary_if)
 +		return;
 +
 +	set_main_if_addr(batman_if->net_dev->dev_addr);
 +
 +	batman_packet = (struct batman_packet *)(batman_if->packet_buff);
 +	batman_packet->flags = PRIMARIES_FIRST_HOP;
 +	batman_packet->ttl = TTL;
 +
 +	/***
 +	 * hacky trick to make sure that we send the HNA information via
 +	 * our new primary interface
 +	 */
 +	atomic_set(&hna_local_changed, 1);
 +}
 +
 +static bool hardif_is_iface_up(struct batman_if *batman_if)
 +{
 +	if (batman_if->net_dev->flags & IFF_UP)
 +		return true;
 +
 +	return false;
 +}
 +
 +static void update_mac_addresses(struct batman_if *batman_if)
 +{
++	if (!batman_if || !batman_if->packet_buff)
++		return;
++
 +	addr_to_string(batman_if->addr_str, batman_if->net_dev->dev_addr);
 +
 +	memcpy(((struct batman_packet *)(batman_if->packet_buff))->orig,
 +	       batman_if->net_dev->dev_addr, ETH_ALEN);
 +	memcpy(((struct batman_packet *)(batman_if->packet_buff))->prev_sender,
 +	       batman_if->net_dev->dev_addr, ETH_ALEN);
 +}
 +
 +static void check_known_mac_addr(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) &&
 +		    (batman_if->if_status != IF_TO_BE_ACTIVATED))
 +			continue;
 +
 +		if (!compare_orig(batman_if->net_dev->dev_addr, addr))
 +			continue;
 +
 +		pr_warning("The newly added mac address (%pM) already exists "
 +			   "on: %s\n", addr, batman_if->dev);
 +		pr_warning("It is strongly recommended to keep mac addresses "
 +			   "unique to avoid problems!\n");
 +	}
 +	rcu_read_unlock();
 +}
 +
 +int hardif_min_mtu(void)
 +{
 +	struct batman_if *batman_if;
 +	/* allow big frames if all devices are capable to do so
 +	 * (have MTU > 1500 + BAT_HEADER_LEN) */
 +	int min_mtu = ETH_DATA_LEN;
 +
 +	rcu_read_lock();
 +	list_for_each_entry_rcu(batman_if, &if_list, list) {
 +		if ((batman_if->if_status == IF_ACTIVE) ||
 +		    (batman_if->if_status == IF_TO_BE_ACTIVATED))
 +			min_mtu = MIN(batman_if->net_dev->mtu - BAT_HEADER_LEN,
 +				      min_mtu);
 +	}
 +	rcu_read_unlock();
 +
 +	return min_mtu;
 +}
 +
 +/* adjusts the MTU if a new interface with a smaller MTU appeared. */
 +void update_min_mtu(void)
 +{
 +	int min_mtu;
 +
 +	min_mtu = hardif_min_mtu();
 +	if (soft_device->mtu != min_mtu)
 +		soft_device->mtu = min_mtu;
 +}
 +
 +static void hardif_activate_interface(struct net_device *net_dev,
 +				      struct bat_priv *bat_priv,
 +				      struct batman_if *batman_if)
 +{
 +	if (batman_if->if_status != IF_INACTIVE)
 +		return;
 +
- 	dev_hold(batman_if->net_dev);
- 
 +	update_mac_addresses(batman_if);
 +	batman_if->if_status = IF_TO_BE_ACTIVATED;
 +
 +	/**
 +	 * the first active interface becomes our primary interface or
 +	 * the next active interface after the old primay interface was removed
 +	 */
 +	if (!bat_priv->primary_if)
 +		set_primary_if(bat_priv, batman_if);
 +
 +	bat_info(net_dev, "Interface activated: %s\n", batman_if->dev);
 +
 +	if (atomic_read(&module_state) == MODULE_INACTIVE)
 +		activate_module();
 +
 +	update_min_mtu();
 +	return;
 +}
 +
 +static void hardif_deactivate_interface(struct net_device *net_dev,
 +					struct batman_if *batman_if)
 +{
 +	if ((batman_if->if_status != IF_ACTIVE) &&
 +	   (batman_if->if_status != IF_TO_BE_ACTIVATED))
 +		return;
 +
- 	dev_put(batman_if->net_dev);
- 
 +	batman_if->if_status = IF_INACTIVE;
 +
 +	bat_info(net_dev, "Interface deactivated: %s\n", batman_if->dev);
 +
 +	update_min_mtu();
 +}
 +
 +int hardif_enable_interface(struct batman_if *batman_if)
 +{
 +	/* FIXME: each batman_if will be attached to a softif */
 +	struct bat_priv *bat_priv = netdev_priv(soft_device);
 +	struct batman_packet *batman_packet;
 +
 +	if (batman_if->if_status != IF_NOT_IN_USE)
 +		goto out;
 +
 +	batman_if->packet_len = BAT_PACKET_LEN;
 +	batman_if->packet_buff = kmalloc(batman_if->packet_len, GFP_ATOMIC);
 +
 +	if (!batman_if->packet_buff) {
 +		bat_err(soft_device, "Can't add interface packet (%s): "
 +			"out of memory\n", batman_if->dev);
 +		goto err;
 +	}
 +
 +	batman_packet = (struct batman_packet *)(batman_if->packet_buff);
 +	batman_packet->packet_type = BAT_PACKET;
 +	batman_packet->version = COMPAT_VERSION;
 +	batman_packet->flags = 0;
 +	batman_packet->ttl = 2;
 +	batman_packet->tq = TQ_MAX_VALUE;
 +	batman_packet->num_hna = 0;
 +
 +	batman_if->if_num = bat_priv->num_ifaces;
 +	bat_priv->num_ifaces++;
 +	batman_if->if_status = IF_INACTIVE;
 +	orig_hash_add_if(batman_if, bat_priv->num_ifaces);
 +
 +	atomic_set(&batman_if->seqno, 1);
 +	bat_info(soft_device, "Adding interface: %s\n", batman_if->dev);
 +
 +	if (hardif_is_iface_up(batman_if))
 +		hardif_activate_interface(soft_device, bat_priv, batman_if);
 +	else
 +		bat_err(soft_device, "Not using interface %s "
 +			"(retrying later): interface not active\n",
 +			batman_if->dev);
 +
 +	/* begin scheduling originator messages on that interface */
 +	schedule_own_packet(batman_if);
 +
 +out:
 +	return 0;
 +
 +err:
 +	return -ENOMEM;
 +}
 +
 +void hardif_disable_interface(struct batman_if *batman_if)
 +{
 +	/* FIXME: each batman_if will be attached to a softif */
 +	struct bat_priv *bat_priv = netdev_priv(soft_device);
 +
 +	if (batman_if->if_status == IF_ACTIVE)
 +		hardif_deactivate_interface(soft_device, batman_if);
 +
 +	if (batman_if->if_status != IF_INACTIVE)
 +		return;
 +
 +	bat_info(soft_device, "Removing interface: %s\n", batman_if->dev);
 +	bat_priv->num_ifaces--;
 +	orig_hash_del_if(batman_if, bat_priv->num_ifaces);
 +
 +	if (batman_if == bat_priv->primary_if)
 +		set_primary_if(bat_priv, get_active_batman_if());
 +
 +	kfree(batman_if->packet_buff);
 +	batman_if->packet_buff = NULL;
 +	batman_if->if_status = IF_NOT_IN_USE;
 +
 +	if ((atomic_read(&module_state) == MODULE_ACTIVE) &&
 +	    (bat_priv->num_ifaces == 0))
 +		deactivate_module();
 +}
 +
 +static struct batman_if *hardif_add_interface(struct net_device *net_dev)
 +{
 +	struct batman_if *batman_if;
 +	int ret;
 +
 +	ret = is_valid_iface(net_dev);
 +	if (ret != 1)
 +		goto out;
 +
++	dev_hold(net_dev);
++
 +	batman_if = kmalloc(sizeof(struct batman_if), GFP_ATOMIC);
 +	if (!batman_if) {
 +		pr_err("Can't add interface (%s): out of memory\n",
 +		       net_dev->name);
- 		goto out;
++		goto release_dev;
 +	}
 +
 +	batman_if->dev = kstrdup(net_dev->name, GFP_ATOMIC);
 +	if (!batman_if->dev)
 +		goto free_if;
 +
 +	ret = sysfs_add_hardif(&batman_if->hardif_obj, net_dev);
 +	if (ret)
 +		goto free_dev;
 +
 +	batman_if->if_num = -1;
 +	batman_if->net_dev = net_dev;
 +	batman_if->if_status = IF_NOT_IN_USE;
++	batman_if->packet_buff = NULL;
 +	INIT_LIST_HEAD(&batman_if->list);
 +
 +	check_known_mac_addr(batman_if->net_dev->dev_addr);
 +	list_add_tail_rcu(&batman_if->list, &if_list);
 +	return batman_if;
 +
 +free_dev:
 +	kfree(batman_if->dev);
 +free_if:
 +	kfree(batman_if);
++release_dev:
++	dev_put(net_dev);
 +out:
 +	return NULL;
 +}
 +
 +static void hardif_free_interface(struct rcu_head *rcu)
 +{
 +	struct batman_if *batman_if = container_of(rcu, struct batman_if, rcu);
 +
 +	/* delete all references to this batman_if */
 +	purge_orig(NULL);
 +	purge_outstanding_packets(batman_if);
 +
 +	kfree(batman_if->dev);
 +	kfree(batman_if);
 +}
 +
 +static void hardif_remove_interface(struct batman_if *batman_if)
 +{
 +	/* first deactivate interface */
 +	if (batman_if->if_status != IF_NOT_IN_USE)
 +		hardif_disable_interface(batman_if);
 +
 +	if (batman_if->if_status != IF_NOT_IN_USE)
 +		return;
 +
 +	batman_if->if_status = IF_TO_BE_REMOVED;
 +	list_del_rcu(&batman_if->list);
 +	sysfs_del_hardif(&batman_if->hardif_obj);
++	dev_put(batman_if->net_dev);
 +	call_rcu(&batman_if->rcu, hardif_free_interface);
 +}
 +
 +void hardif_remove_interfaces(void)
 +{
 +	struct batman_if *batman_if, *batman_if_tmp;
 +
 +	list_for_each_entry_safe(batman_if, batman_if_tmp, &if_list, list)
 +		hardif_remove_interface(batman_if);
 +}
 +
 +static int hard_if_event(struct notifier_block *this,
 +			 unsigned long event, void *ptr)
 +{
 +	struct net_device *net_dev = (struct net_device *)ptr;
 +	struct batman_if *batman_if = get_batman_if_by_netdev(net_dev);
 +	/* FIXME: each batman_if will be attached to a softif */
 +	struct bat_priv *bat_priv = netdev_priv(soft_device);
 +
- 	if (!batman_if)
- 		batman_if = hardif_add_interface(net_dev);
++	if (!batman_if && event == NETDEV_REGISTER)
++			batman_if = hardif_add_interface(net_dev);
 +
 +	if (!batman_if)
 +		goto out;
 +
 +	switch (event) {
- 	case NETDEV_REGISTER:
- 		break;
 +	case NETDEV_UP:
 +		hardif_activate_interface(soft_device, bat_priv, batman_if);
 +		break;
 +	case NETDEV_GOING_DOWN:
 +	case NETDEV_DOWN:
 +		hardif_deactivate_interface(soft_device, batman_if);
 +		break;
 +	case NETDEV_UNREGISTER:
 +		hardif_remove_interface(batman_if);
 +		break;
 +	case NETDEV_CHANGENAME:
 +		break;
 +	case NETDEV_CHANGEADDR:
 +		check_known_mac_addr(batman_if->net_dev->dev_addr);
 +		update_mac_addresses(batman_if);
 +		if (batman_if == bat_priv->primary_if)
 +			set_primary_if(bat_priv, batman_if);
 +		break;
 +	default:
 +		break;
 +	};
 +
 +out:
 +	return NOTIFY_DONE;
 +}
 +
 +static int batman_skb_recv_finish(struct sk_buff *skb)
 +{
 +	return NF_ACCEPT;
 +}
 +
 +/* receive a packet with the batman ethertype coming on a hard
 + * interface */
 +int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
 +	struct packet_type *ptype, struct net_device *orig_dev)
 +{
 +	/* FIXME: each orig_node->batman_if will be attached to a softif */
 +	struct bat_priv *bat_priv = netdev_priv(soft_device);
 +	struct batman_packet *batman_packet;
 +	struct batman_if *batman_if;
 +	int ret;
 +
 +	skb = skb_share_check(skb, GFP_ATOMIC);
 +
 +	/* skb was released by skb_share_check() */
 +	if (!skb)
 +		goto err_out;
 +
 +	if (atomic_read(&module_state) != MODULE_ACTIVE)
 +		goto err_free;
 +
 +	/* if netfilter/ebtables wants to block incoming batman
 +	 * packets then give them a chance to do so here */
 +	ret = NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, dev, NULL,
 +		      batman_skb_recv_finish);
 +	if (ret != 1)
 +		goto err_out;
 +
 +	/* packet should hold at least type and version */
 +	if (unlikely(skb_headlen(skb) < 2))
 +		goto err_free;
 +
 +	/* expect a valid ethernet header here. */
 +	if (unlikely(skb->mac_len != sizeof(struct ethhdr)
 +				|| !skb_mac_header(skb)))
 +		goto err_free;
 +
 +	batman_if = get_batman_if_by_netdev(skb->dev);
 +	if (!batman_if)
 +		goto err_free;
 +
 +	/* discard frames on not active interfaces */
 +	if (batman_if->if_status != IF_ACTIVE)
 +		goto err_free;
 +
 +	batman_packet = (struct batman_packet *)skb->data;
 +
 +	if (batman_packet->version != COMPAT_VERSION) {
 +		bat_dbg(DBG_BATMAN, bat_priv,
 +			"Drop packet: incompatible batman version (%i)\n",
 +			batman_packet->version);
 +		goto err_free;
 +	}
 +
 +	/* all receive handlers return whether they received or reused
 +	 * the supplied skb. if not, we have to free the skb. */
 +
 +	switch (batman_packet->packet_type) {
 +		/* batman originator packet */
 +	case BAT_PACKET:
 +		ret = recv_bat_packet(skb, batman_if);
 +		break;
 +
 +		/* batman icmp packet */
 +	case BAT_ICMP:
 +		ret = recv_icmp_packet(skb);
 +		break;
 +
 +		/* unicast packet */
 +	case BAT_UNICAST:
 +		ret = recv_unicast_packet(skb, batman_if);
 +		break;
 +
 +		/* broadcast packet */
 +	case BAT_BCAST:
 +		ret = recv_bcast_packet(skb);
 +		break;
 +
 +		/* vis packet */
 +	case BAT_VIS:
 +		ret = recv_vis_packet(skb);
 +		break;
 +	default:
 +		ret = NET_RX_DROP;
 +	}
 +
 +	if (ret == NET_RX_DROP)
 +		kfree_skb(skb);
 +
 +	/* return NET_RX_SUCCESS in any case as we
 +	 * most probably dropped the packet for
 +	 * routing-logical reasons. */
 +
 +	return NET_RX_SUCCESS;
 +
 +err_free:
 +	kfree_skb(skb);
 +err_out:
 +	return NET_RX_DROP;
 +}
 +
 +struct notifier_block hard_if_notifier = {
 +	.notifier_call = hard_if_event,
 +};

-- 
linux integration


More information about the commits mailing list