diff options
Diffstat (limited to 'net/tipc/eth_media.c')
| -rw-r--r-- | net/tipc/eth_media.c | 317 | 
1 files changed, 46 insertions, 271 deletions
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index ee683cc8f4b..5e1426f1751 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -1,8 +1,8 @@  /*   * net/tipc/eth_media.c: Ethernet bearer support for TIPC   * - * Copyright (c) 2001-2007, Ericsson AB - * Copyright (c) 2005-2007, Wind River Systems + * Copyright (c) 2001-2007, 2013-2014, Ericsson AB + * Copyright (c) 2005-2008, 2011-2013, Wind River Systems   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -34,293 +34,68 @@   * POSSIBILITY OF SUCH DAMAGE.   */ -#include <linux/netdevice.h> -#include <linux/slab.h> -#include <net/net_namespace.h> -  #include "core.h"  #include "bearer.h" -#define MAX_ETH_BEARERS		2 -#define ETH_LINK_PRIORITY	TIPC_DEF_LINK_PRI -#define ETH_LINK_TOLERANCE	TIPC_DEF_LINK_TOL -#define ETH_LINK_WINDOW		TIPC_DEF_LINK_WIN - -/** - * struct eth_bearer - Ethernet bearer data structure - * @bearer: ptr to associated "generic" bearer structure - * @dev: ptr to associated Ethernet network device - * @tipc_packet_type: used in binding TIPC to Ethernet driver - */ - -struct eth_bearer { -	struct tipc_bearer *bearer; -	struct net_device *dev; -	struct packet_type tipc_packet_type; -}; - -static struct eth_bearer eth_bearers[MAX_ETH_BEARERS]; -static int eth_started = 0; -static struct notifier_block notifier; - -/** - * send_msg - send a TIPC message out over an Ethernet interface - */ +#define ETH_ADDR_OFFSET  4  /* MAC addr position inside address field */ -static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, -		    struct tipc_media_addr *dest) +/* Convert Ethernet address (media address format) to string */ +static int tipc_eth_addr2str(struct tipc_media_addr *addr, +			     char *strbuf, int bufsz)  { -	struct sk_buff *clone; -	struct net_device *dev; -	int delta; +	if (bufsz < 18)	/* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */ +		return 1; -	clone = skb_clone(buf, GFP_ATOMIC); -	if (!clone) -		return 0; - -	dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev; -	delta = dev->hard_header_len - skb_headroom(buf); - -	if ((delta > 0) && -	    pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { -		kfree_skb(clone); -		return 0; -	} - -	skb_reset_network_header(clone); -	clone->dev = dev; -	dev_hard_header(clone, dev, ETH_P_TIPC, &dest->dev_addr.eth_addr, -			dev->dev_addr, clone->len); -	dev_queue_xmit(clone); +	sprintf(strbuf, "%pM", addr->value);  	return 0;  } -/** - * recv_msg - handle incoming TIPC message from an Ethernet interface - * - * Accept only packets explicitly sent to this node, or broadcast packets; - * ignores packets sent using Ethernet multicast, and traffic sent to other - * nodes (which can happen if interface is running in promiscuous mode). - */ - -static int recv_msg(struct sk_buff *buf, struct net_device *dev, -		    struct packet_type *pt, struct net_device *orig_dev) +/* Convert from media address format to discovery message addr format */ +static int tipc_eth_addr2msg(char *msg, struct tipc_media_addr *addr)  { -	struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; - -	if (!net_eq(dev_net(dev), &init_net)) { -		kfree_skb(buf); -		return 0; -	} - -	if (likely(eb_ptr->bearer)) { -		if (likely(buf->pkt_type <= PACKET_BROADCAST)) { -			buf->next = NULL; -			tipc_recv_msg(buf, eb_ptr->bearer); -			return 0; -		} -	} -	kfree_skb(buf); +	memset(msg, 0, TIPC_MEDIA_ADDR_SIZE); +	msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH; +	memcpy(msg + ETH_ADDR_OFFSET, addr->value, ETH_ALEN);  	return 0;  } -/** - * enable_bearer - attach TIPC bearer to an Ethernet interface - */ - -static int enable_bearer(struct tipc_bearer *tb_ptr) +/* Convert raw mac address format to media addr format */ +static int tipc_eth_raw2addr(struct tipc_bearer *b, +			     struct tipc_media_addr *addr, +			     char *msg)  { -	struct net_device *dev = NULL; -	struct net_device *pdev = NULL; -	struct eth_bearer *eb_ptr = ð_bearers[0]; -	struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; -	char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1; -	int pending_dev = 0; - -	/* Find unused Ethernet bearer structure */ - -	while (eb_ptr->dev) { -		if (!eb_ptr->bearer) -			pending_dev++; -		if (++eb_ptr == stop) -			return pending_dev ? -EAGAIN : -EDQUOT; -	} - -	/* Find device with specified name */ - -	for_each_netdev(&init_net, pdev){ -		if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { -			dev = pdev; -			break; -		} -	} -	if (!dev) -		return -ENODEV; - -	/* Find Ethernet bearer for device (or create one) */ - -	for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++); -	if (eb_ptr == stop) -		return -EDQUOT; -	if (!eb_ptr->dev) { -		eb_ptr->dev = dev; -		eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); -		eb_ptr->tipc_packet_type.dev = dev; -		eb_ptr->tipc_packet_type.func = recv_msg; -		eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; -		INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); -		dev_hold(dev); -		dev_add_pack(&eb_ptr->tipc_packet_type); -	} +	char bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -	/* Associate TIPC bearer with Ethernet bearer */ - -	eb_ptr->bearer = tb_ptr; -	tb_ptr->usr_handle = (void *)eb_ptr; -	tb_ptr->mtu = dev->mtu; -	tb_ptr->blocked = 0; -	tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH); -	memcpy(&tb_ptr->addr.dev_addr, dev->dev_addr, ETH_ALEN); +	memset(addr, 0, sizeof(*addr)); +	ether_addr_copy(addr->value, msg); +	addr->media_id = TIPC_MEDIA_TYPE_ETH; +	addr->broadcast = !memcmp(addr->value, bcast_mac, ETH_ALEN);  	return 0;  } -/** - * disable_bearer - detach TIPC bearer from an Ethernet interface - * - * We really should do dev_remove_pack() here, but this function can not be - * called at tasklet level. => Use eth_bearer->bearer as a flag to throw away - * incoming buffers, & postpone dev_remove_pack() to eth_media_stop() on exit. - */ - -static void disable_bearer(struct tipc_bearer *tb_ptr) -{ -	((struct eth_bearer *)tb_ptr->usr_handle)->bearer = NULL; -} - -/** - * recv_notification - handle device updates from OS - * - * Change the state of the Ethernet bearer (if any) associated with the - * specified device. - */ - -static int recv_notification(struct notifier_block *nb, unsigned long evt, -			     void *dv) -{ -	struct net_device *dev = (struct net_device *)dv; -	struct eth_bearer *eb_ptr = ð_bearers[0]; -	struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; - -	if (!net_eq(dev_net(dev), &init_net)) -		return NOTIFY_DONE; - -	while ((eb_ptr->dev != dev)) { -		if (++eb_ptr == stop) -			return NOTIFY_DONE;	/* couldn't find device */ -	} -	if (!eb_ptr->bearer) -		return NOTIFY_DONE;		/* bearer had been disabled */ - -	eb_ptr->bearer->mtu = dev->mtu; - -	switch (evt) { -	case NETDEV_CHANGE: -		if (netif_carrier_ok(dev)) -			tipc_continue(eb_ptr->bearer); -		else -			tipc_block_bearer(eb_ptr->bearer->name); -		break; -	case NETDEV_UP: -		tipc_continue(eb_ptr->bearer); -		break; -	case NETDEV_DOWN: -		tipc_block_bearer(eb_ptr->bearer->name); -		break; -	case NETDEV_CHANGEMTU: -	case NETDEV_CHANGEADDR: -		tipc_block_bearer(eb_ptr->bearer->name); -		tipc_continue(eb_ptr->bearer); -		break; -	case NETDEV_UNREGISTER: -	case NETDEV_CHANGENAME: -		tipc_disable_bearer(eb_ptr->bearer->name); -		break; -	} -	return NOTIFY_OK; -} - -/** - * eth_addr2str - convert Ethernet address to string - */ - -static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) +/* Convert discovery msg addr format to Ethernet media addr format */ +static int tipc_eth_msg2addr(struct tipc_bearer *b, +			     struct tipc_media_addr *addr, +			     char *msg)  { -	unchar *addr = (unchar *)&a->dev_addr; - -	if (str_size < 18) -		*str_buf = '\0'; -	else -		sprintf(str_buf, "%pM", addr); -	return str_buf; +	/* Skip past preamble: */ +	msg += ETH_ADDR_OFFSET; +	return tipc_eth_raw2addr(b, addr, msg);  } -/** - * tipc_eth_media_start - activate Ethernet bearer support - * - * Register Ethernet media type with TIPC bearer code.  Also register - * with OS for notifications about device state changes. - */ - -int tipc_eth_media_start(void) -{ -	struct tipc_media_addr bcast_addr; -	int res; - -	if (eth_started) -		return -EINVAL; - -	bcast_addr.type = htonl(TIPC_MEDIA_TYPE_ETH); -	memset(&bcast_addr.dev_addr, 0xff, ETH_ALEN); - -	memset(eth_bearers, 0, sizeof(eth_bearers)); - -	res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth", -				  enable_bearer, disable_bearer, send_msg, -				  eth_addr2str, &bcast_addr, ETH_LINK_PRIORITY, -				  ETH_LINK_TOLERANCE, ETH_LINK_WINDOW); -	if (res) -		return res; - -	notifier.notifier_call = &recv_notification; -	notifier.priority = 0; -	res = register_netdevice_notifier(¬ifier); -	if (!res) -		eth_started = 1; -	return res; -} - -/** - * tipc_eth_media_stop - deactivate Ethernet bearer support - */ - -void tipc_eth_media_stop(void) -{ -	int i; - -	if (!eth_started) -		return; - -	unregister_netdevice_notifier(¬ifier); -	for (i = 0; i < MAX_ETH_BEARERS ; i++) { -		if (eth_bearers[i].bearer) { -			eth_bearers[i].bearer->blocked = 1; -			eth_bearers[i].bearer = NULL; -		} -		if (eth_bearers[i].dev) { -			dev_remove_pack(ð_bearers[i].tipc_packet_type); -			dev_put(eth_bearers[i].dev); -		} -	} -	memset(ð_bearers, 0, sizeof(eth_bearers)); -	eth_started = 0; -} +/* Ethernet media registration info */ +struct tipc_media eth_media_info = { +	.send_msg	= tipc_l2_send_msg, +	.enable_media	= tipc_enable_l2_media, +	.disable_media	= tipc_disable_l2_media, +	.addr2str	= tipc_eth_addr2str, +	.addr2msg	= tipc_eth_addr2msg, +	.msg2addr	= tipc_eth_msg2addr, +	.raw2addr	= tipc_eth_raw2addr, +	.priority	= TIPC_DEF_LINK_PRI, +	.tolerance	= TIPC_DEF_LINK_TOL, +	.window		= TIPC_DEF_LINK_WIN, +	.type_id	= TIPC_MEDIA_TYPE_ETH, +	.hwaddr_len	= ETH_ALEN, +	.name		= "eth" +};  | 
