2006-01-02 21:04:38 +03:00
/*
* net / tipc / eth_media . c : Ethernet bearer support for TIPC
2007-02-09 17:25:21 +03:00
*
2007-06-11 04:24:20 +04:00
* Copyright ( c ) 2001 - 2007 , Ericsson AB
* Copyright ( c ) 2005 - 2007 , Wind River Systems
2006-01-02 21:04:38 +03:00
* All rights reserved .
*
2006-01-11 15:30:43 +03:00
* Redistribution and use in source and binary forms , with or without
2006-01-02 21:04:38 +03:00
* modification , are permitted provided that the following conditions are met :
*
2006-01-11 15:30:43 +03:00
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission .
2006-01-02 21:04:38 +03:00
*
2006-01-11 15:30:43 +03:00
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
2006-01-02 21:04:38 +03:00
* POSSIBILITY OF SUCH DAMAGE .
*/
# include <net/tipc/tipc.h>
# include <net/tipc/tipc_bearer.h>
# include <net/tipc/tipc_msg.h>
# include <linux/netdevice.h>
2007-09-17 22:53:39 +04:00
# include <net/net_namespace.h>
2006-01-02 21:04:38 +03:00
# define MAX_ETH_BEARERS 2
2006-01-14 00:22:22 +03:00
# define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI
2006-01-02 21:04:38 +03:00
# define ETH_LINK_TOLERANCE TIPC_DEF_LINK_TOL
2006-01-14 00:22:22 +03:00
# define ETH_LINK_WINDOW TIPC_DEF_LINK_WIN
2006-01-02 21:04:38 +03:00
/**
* 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
*/
2007-02-09 17:25:21 +03:00
2006-01-02 21:04:38 +03:00
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 ;
/**
2007-02-09 17:25:21 +03:00
* send_msg - send a TIPC message out over an Ethernet interface
2006-01-02 21:04:38 +03:00
*/
2007-02-09 17:25:21 +03:00
static int send_msg ( struct sk_buff * buf , struct tipc_bearer * tb_ptr ,
2006-01-02 21:04:38 +03:00
struct tipc_media_addr * dest )
{
struct sk_buff * clone ;
struct net_device * dev ;
clone = skb_clone ( buf , GFP_ATOMIC ) ;
if ( clone ) {
2007-04-11 07:45:18 +04:00
skb_reset_network_header ( clone ) ;
2006-01-02 21:04:38 +03:00
dev = ( ( struct eth_bearer * ) ( tb_ptr - > usr_handle ) ) - > dev ;
clone - > dev = dev ;
2007-10-09 12:36:32 +04:00
dev_hard_header ( clone , dev , ETH_P_TIPC ,
2006-01-02 21:04:38 +03:00
& dest - > dev_addr . eth_addr ,
dev - > dev_addr , clone - > len ) ;
dev_queue_xmit ( clone ) ;
}
2008-07-15 09:44:01 +04:00
return 0 ;
2006-01-02 21:04:38 +03:00
}
/**
* recv_msg - handle incoming TIPC message from an Ethernet interface
2007-02-09 17:25:21 +03:00
*
2007-06-11 04:24:20 +04:00
* 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 ) .
2006-01-02 21:04:38 +03:00
* Routine truncates any Ethernet padding / CRC appended to the message ,
* and ensures message size matches actual length
*/
2007-02-09 17:25:21 +03:00
static int recv_msg ( struct sk_buff * buf , struct net_device * dev ,
2006-01-02 21:04:38 +03:00
struct packet_type * pt , struct net_device * orig_dev )
{
struct eth_bearer * eb_ptr = ( struct eth_bearer * ) pt - > af_packet_priv ;
u32 size ;
2008-07-20 09:34:43 +04:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) ) {
2007-09-17 22:53:39 +04:00
kfree_skb ( buf ) ;
return 0 ;
}
2006-01-02 21:04:38 +03:00
if ( likely ( eb_ptr - > bearer ) ) {
2007-06-11 04:24:20 +04:00
if ( likely ( buf - > pkt_type < = PACKET_BROADCAST ) ) {
2007-02-09 17:25:21 +03:00
size = msg_size ( ( struct tipc_msg * ) buf - > data ) ;
skb_trim ( buf , size ) ;
if ( likely ( buf - > len = = size ) ) {
buf - > next = NULL ;
tipc_recv_msg ( buf , eb_ptr - > bearer ) ;
2008-07-15 09:44:01 +04:00
return 0 ;
2006-06-26 10:36:43 +04:00
}
2006-01-02 21:04:38 +03:00
}
}
2006-06-26 10:36:43 +04:00
kfree_skb ( buf ) ;
2008-07-15 09:44:01 +04:00
return 0 ;
2006-01-02 21:04:38 +03:00
}
/**
2007-02-09 17:25:21 +03:00
* enable_bearer - attach TIPC bearer to an Ethernet interface
2006-01-02 21:04:38 +03:00
*/
static int enable_bearer ( struct tipc_bearer * tb_ptr )
{
2007-05-24 02:11:15 +04:00
struct net_device * dev = NULL ;
struct net_device * pdev = NULL ;
2006-01-02 21:04:38 +03:00
struct eth_bearer * eb_ptr = & eth_bearers [ 0 ] ;
struct eth_bearer * stop = & eth_bearers [ MAX_ETH_BEARERS ] ;
char * driver_name = strchr ( ( const char * ) tb_ptr - > name , ' : ' ) + 1 ;
/* Find device with specified name */
2007-05-24 02:11:15 +04:00
2007-09-17 22:56:21 +04:00
for_each_netdev ( & init_net , pdev ) {
2007-05-24 02:11:15 +04:00
if ( ! strncmp ( pdev - > name , driver_name , IFNAMSIZ ) ) {
2007-05-04 02:13:45 +04:00
dev = pdev ;
break ;
}
2007-05-24 02:11:15 +04:00
}
2006-01-02 21:04:38 +03:00
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 ;
2007-03-07 08:21:31 +03:00
eb_ptr - > tipc_packet_type . type = htons ( ETH_P_TIPC ) ;
2006-01-02 21:04:38 +03:00
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 ) ;
}
/* Associate TIPC bearer with Ethernet bearer */
eb_ptr - > bearer = tb_ptr ;
tb_ptr - > usr_handle = ( void * ) eb_ptr ;
tb_ptr - > mtu = dev - > mtu ;
2007-02-09 17:25:21 +03:00
tb_ptr - > blocked = 0 ;
2006-01-02 21:04:38 +03:00
tb_ptr - > addr . type = htonl ( TIPC_MEDIA_TYPE_ETH ) ;
memcpy ( & tb_ptr - > addr . dev_addr , & dev - > dev_addr , ETH_ALEN ) ;
return 0 ;
}
/**
2007-02-09 17:25:21 +03:00
* disable_bearer - detach TIPC bearer from an Ethernet interface
2006-01-02 21:04:38 +03:00
*
* 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 )
{
2006-03-21 09:36:47 +03:00
( ( struct eth_bearer * ) tb_ptr - > usr_handle ) - > bearer = NULL ;
2006-01-02 21:04:38 +03:00
}
/**
* recv_notification - handle device updates from OS
*
2007-02-09 17:25:21 +03:00
* Change the state of the Ethernet bearer ( if any ) associated with the
2006-01-02 21:04:38 +03:00
* specified device .
*/
2007-02-09 17:25:21 +03:00
static int recv_notification ( struct notifier_block * nb , unsigned long evt ,
2006-01-02 21:04:38 +03:00
void * dv )
{
struct net_device * dev = ( struct net_device * ) dv ;
struct eth_bearer * eb_ptr = & eth_bearers [ 0 ] ;
struct eth_bearer * stop = & eth_bearers [ MAX_ETH_BEARERS ] ;
2008-07-20 09:34:43 +04:00
if ( ! net_eq ( dev_net ( dev ) , & init_net ) )
2007-09-12 15:02:17 +04:00
return NOTIFY_DONE ;
2006-01-02 21:04:38 +03:00
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 */
2007-02-09 17:25:21 +03:00
eb_ptr - > bearer - > mtu = dev - > mtu ;
2006-01-02 21:04:38 +03:00
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 :
2007-02-09 17:25:21 +03:00
case NETDEV_CHANGEADDR :
2006-01-02 21:04:38 +03:00
tipc_block_bearer ( eb_ptr - > bearer - > name ) ;
2007-02-09 17:25:21 +03:00
tipc_continue ( eb_ptr - > bearer ) ;
2006-01-02 21:04:38 +03:00
break ;
case NETDEV_UNREGISTER :
2007-02-09 17:25:21 +03:00
case NETDEV_CHANGENAME :
2006-01-02 21:04:38 +03:00
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 )
2007-02-09 17:25:21 +03:00
{
2006-01-02 21:04:38 +03:00
unchar * addr = ( unchar * ) & a - > dev_addr ;
2007-10-04 04:59:30 +04:00
DECLARE_MAC_BUF ( mac ) ;
2006-01-02 21:04:38 +03:00
if ( str_size < 18 )
* str_buf = ' \0 ' ;
else
2007-10-04 04:59:30 +04:00
sprintf ( str_buf , " %s " , print_mac ( mac , addr ) ) ;
2006-01-02 21:04:38 +03:00
return str_buf ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_eth_media_start - activate Ethernet bearer support
2006-01-02 21:04:38 +03:00
*
* Register Ethernet media type with TIPC bearer code . Also register
* with OS for notifications about device state changes .
*/
2006-01-18 02:38:21 +03:00
int tipc_eth_media_start ( void )
2007-02-09 17:25:21 +03:00
{
2006-01-02 21:04:38 +03:00
struct tipc_media_addr bcast_addr ;
int res ;
if ( eth_started )
return - EINVAL ;
2006-06-26 10:38:29 +04:00
bcast_addr . type = htonl ( TIPC_MEDIA_TYPE_ETH ) ;
memset ( & bcast_addr . dev_addr , 0xff , ETH_ALEN ) ;
2006-01-02 21:04:38 +03:00
memset ( eth_bearers , 0 , sizeof ( eth_bearers ) ) ;
res = tipc_register_media ( TIPC_MEDIA_TYPE_ETH , " eth " ,
2007-02-09 17:25:21 +03:00
enable_bearer , disable_bearer , send_msg ,
eth_addr2str , & bcast_addr , ETH_LINK_PRIORITY ,
2006-01-14 00:22:22 +03:00
ETH_LINK_TOLERANCE , ETH_LINK_WINDOW ) ;
2006-01-02 21:04:38 +03:00
if ( res )
return res ;
notifier . notifier_call = & recv_notification ;
notifier . priority = 0 ;
res = register_netdevice_notifier ( & notifier ) ;
if ( ! res )
eth_started = 1 ;
return res ;
}
/**
2006-01-18 02:38:21 +03:00
* tipc_eth_media_stop - deactivate Ethernet bearer support
2006-01-02 21:04:38 +03:00
*/
2006-01-18 02:38:21 +03:00
void tipc_eth_media_stop ( void )
2006-01-02 21:04:38 +03:00
{
int i ;
if ( ! eth_started )
return ;
unregister_netdevice_notifier ( & notifier ) ;
for ( i = 0 ; i < MAX_ETH_BEARERS ; i + + ) {
if ( eth_bearers [ i ] . bearer ) {
eth_bearers [ i ] . bearer - > blocked = 1 ;
2006-03-21 09:36:47 +03:00
eth_bearers [ i ] . bearer = NULL ;
2006-01-02 21:04:38 +03:00
}
if ( eth_bearers [ i ] . dev ) {
dev_remove_pack ( & eth_bearers [ i ] . tipc_packet_type ) ;
dev_put ( eth_bearers [ i ] . dev ) ;
}
}
memset ( & eth_bearers , 0 , sizeof ( eth_bearers ) ) ;
eth_started = 0 ;
}