2005-04-17 02:20:36 +04:00
/*
* Device handling code
* Linux ethernet bridge
*
* Authors :
* Lennert Buytenhek < buytenh @ gnu . org >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/kernel.h>
# include <linux/netdevice.h>
2005-12-22 05:51:49 +03:00
# include <linux/etherdevice.h>
2005-12-22 06:00:58 +03:00
# include <linux/ethtool.h>
2005-12-22 05:51:49 +03:00
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include "br_private.h"
2006-03-21 09:58:36 +03:00
/* net device transmit always called with no BH (preempt_disabled) */
2009-08-31 23:50:41 +04:00
netdev_tx_t br_dev_xmit ( struct sk_buff * skb , struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct net_bridge * br = netdev_priv ( dev ) ;
const unsigned char * dest = skb - > data ;
struct net_bridge_fdb_entry * dst ;
2008-05-22 01:13:47 +04:00
dev - > stats . tx_packets + + ;
dev - > stats . tx_bytes + = skb - > len ;
2005-04-17 02:20:36 +04:00
2007-03-20 01:30:44 +03:00
skb_reset_mac_header ( skb ) ;
2005-04-17 02:20:36 +04:00
skb_pull ( skb , ETH_HLEN ) ;
2007-02-09 17:24:35 +03:00
if ( dest [ 0 ] & 1 )
2007-09-17 03:20:48 +04:00
br_flood_deliver ( br , skb ) ;
2005-04-17 02:20:36 +04:00
else if ( ( dst = __br_fdb_get ( br , dest ) ) ! = NULL )
br_deliver ( dst - > dst , skb ) ;
else
2007-09-17 03:20:48 +04:00
br_flood_deliver ( br , skb ) ;
2005-04-17 02:20:36 +04:00
2009-06-23 10:03:08 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
static int br_dev_open ( struct net_device * dev )
{
2005-05-30 01:15:17 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2005-05-30 01:15:17 +04:00
br_features_recompute ( br ) ;
netif_start_queue ( dev ) ;
br_stp_enable_bridge ( br ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void br_dev_set_multicast_list ( struct net_device * dev )
{
}
static int br_dev_stop ( struct net_device * dev )
{
2005-05-30 01:15:17 +04:00
br_stp_disable_bridge ( netdev_priv ( dev ) ) ;
2005-04-17 02:20:36 +04:00
netif_stop_queue ( dev ) ;
return 0 ;
}
static int br_change_mtu ( struct net_device * dev , int new_mtu )
{
2008-07-31 03:27:55 +04:00
struct net_bridge * br = netdev_priv ( dev ) ;
if ( new_mtu < 68 | | new_mtu > br_min_mtu ( br ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
dev - > mtu = new_mtu ;
2008-07-31 03:27:55 +04:00
# ifdef CONFIG_BRIDGE_NETFILTER
/* remember the MTU in the rtable for PMTU */
br - > fake_rtable . u . dst . metrics [ RTAX_MTU - 1 ] = new_mtu ;
# endif
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-04-09 22:49:58 +04:00
/* Allow setting mac address to any valid ethernet address. */
2005-12-22 05:51:49 +03:00
static int br_set_mac_address ( struct net_device * dev , void * p )
{
struct net_bridge * br = netdev_priv ( dev ) ;
struct sockaddr * addr = p ;
2007-04-09 22:49:58 +04:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EINVAL ;
2005-12-22 05:51:49 +03:00
spin_lock_bh ( & br - > lock ) ;
2007-04-09 22:49:58 +04:00
memcpy ( dev - > dev_addr , addr - > sa_data , ETH_ALEN ) ;
br_stp_change_bridge_id ( br , addr - > sa_data ) ;
2008-06-18 03:10:06 +04:00
br - > flags | = BR_SET_MAC_ADDR ;
2005-12-22 05:51:49 +03:00
spin_unlock_bh ( & br - > lock ) ;
2007-04-09 22:49:58 +04:00
return 0 ;
2005-12-22 05:51:49 +03:00
}
2005-12-22 06:00:58 +03:00
static void br_getinfo ( struct net_device * dev , struct ethtool_drvinfo * info )
{
strcpy ( info - > driver , " bridge " ) ;
strcpy ( info - > version , BR_VERSION ) ;
strcpy ( info - > fw_version , " N/A " ) ;
strcpy ( info - > bus_info , " N/A " ) ;
}
static int br_set_sg ( struct net_device * dev , u32 data )
{
struct net_bridge * br = netdev_priv ( dev ) ;
if ( data )
br - > feature_mask | = NETIF_F_SG ;
else
br - > feature_mask & = ~ NETIF_F_SG ;
br_features_recompute ( br ) ;
return 0 ;
}
static int br_set_tso ( struct net_device * dev , u32 data )
{
struct net_bridge * br = netdev_priv ( dev ) ;
if ( data )
br - > feature_mask | = NETIF_F_TSO ;
else
br - > feature_mask & = ~ NETIF_F_TSO ;
br_features_recompute ( br ) ;
return 0 ;
}
static int br_set_tx_csum ( struct net_device * dev , u32 data )
{
struct net_bridge * br = netdev_priv ( dev ) ;
if ( data )
2006-06-18 09:06:45 +04:00
br - > feature_mask | = NETIF_F_NO_CSUM ;
2005-12-22 06:00:58 +03:00
else
2006-06-18 09:06:45 +04:00
br - > feature_mask & = ~ NETIF_F_ALL_CSUM ;
2005-12-22 06:00:58 +03:00
br_features_recompute ( br ) ;
return 0 ;
}
2008-11-20 08:49:00 +03:00
static const struct ethtool_ops br_ethtool_ops = {
2008-08-16 06:51:07 +04:00
. get_drvinfo = br_getinfo ,
. get_link = ethtool_op_get_link ,
. get_tx_csum = ethtool_op_get_tx_csum ,
. set_tx_csum = br_set_tx_csum ,
. get_sg = ethtool_op_get_sg ,
. set_sg = br_set_sg ,
. get_tso = ethtool_op_get_tso ,
. set_tso = br_set_tso ,
. get_ufo = ethtool_op_get_ufo ,
2009-10-07 16:41:17 +04:00
. set_ufo = ethtool_op_set_ufo ,
2008-08-16 06:51:07 +04:00
. get_flags = ethtool_op_get_flags ,
2005-12-22 06:00:58 +03:00
} ;
2008-11-20 08:49:00 +03:00
static const struct net_device_ops br_netdev_ops = {
. ndo_open = br_dev_open ,
. ndo_stop = br_dev_stop ,
2008-11-21 07:14:53 +03:00
. ndo_start_xmit = br_dev_xmit ,
. ndo_set_mac_address = br_set_mac_address ,
. ndo_set_multicast_list = br_dev_set_multicast_list ,
. ndo_change_mtu = br_change_mtu ,
. ndo_do_ioctl = br_dev_ioctl ,
2008-11-20 08:49:00 +03:00
} ;
2005-04-17 02:20:36 +04:00
void br_dev_setup ( struct net_device * dev )
{
2007-12-17 00:35:51 +03:00
random_ether_addr ( dev - > dev_addr ) ;
2005-04-17 02:20:36 +04:00
ether_setup ( dev ) ;
2008-11-20 08:49:00 +03:00
dev - > netdev_ops = & br_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > destructor = free_netdev ;
2007-02-09 17:24:35 +03:00
SET_ETHTOOL_OPS ( dev , & br_ethtool_ops ) ;
2005-04-17 02:20:36 +04:00
dev - > tx_queue_len = 0 ;
dev - > priv_flags = IFF_EBRIDGE ;
2005-12-22 06:00:58 +03:00
2007-02-09 17:24:35 +03:00
dev - > features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
2008-09-09 03:19:58 +04:00
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX |
2008-10-23 12:11:29 +04:00
NETIF_F_NETNS_LOCAL | NETIF_F_GSO ;
2005-04-17 02:20:36 +04:00
}