2005-04-17 02:20:36 +04:00
/*
* Device handling code
* Linux ethernet bridge
*
* Authors :
* Lennert Buytenhek < buytenh @ gnu . org >
*
* $ Id : br_device . c , v 1.6 2001 / 12 / 24 00 : 59 : 55 davem Exp $
*
* 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"
static struct net_device_stats * br_dev_get_stats ( 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
return & br - > statistics ;
}
2006-03-21 09:58:36 +03:00
/* net device transmit always called with no BH (preempt_disabled) */
2005-04-17 02:20:36 +04:00
int br_dev_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct net_bridge * br = netdev_priv ( dev ) ;
const unsigned char * dest = skb - > data ;
struct net_bridge_fdb_entry * dst ;
br - > statistics . tx_packets + + ;
br - > statistics . tx_bytes + = skb - > len ;
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
return 0 ;
}
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 )
{
2005-05-30 01:15:17 +04:00
if ( new_mtu < 68 | | new_mtu > br_min_mtu ( netdev_priv ( dev ) ) )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
dev - > mtu = new_mtu ;
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 ) ;
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 ;
}
static struct ethtool_ops br_ethtool_ops = {
. get_drvinfo = br_getinfo ,
. get_link = ethtool_op_get_link ,
. set_sg = br_set_sg ,
. set_tx_csum = br_set_tx_csum ,
. set_tso = br_set_tso ,
} ;
2005-04-17 02:20:36 +04:00
void br_dev_setup ( struct net_device * dev )
{
memset ( dev - > dev_addr , 0 , ETH_ALEN ) ;
ether_setup ( dev ) ;
dev - > do_ioctl = br_dev_ioctl ;
dev - > get_stats = br_dev_get_stats ;
dev - > hard_start_xmit = br_dev_xmit ;
dev - > open = br_dev_open ;
dev - > set_multicast_list = br_dev_set_multicast_list ;
dev - > change_mtu = br_change_mtu ;
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 - > stop = br_dev_stop ;
dev - > tx_queue_len = 0 ;
2005-12-22 05:51:49 +03:00
dev - > set_mac_address = br_set_mac_address ;
2005-04-17 02:20:36 +04:00
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 |
2007-08-11 02:47:58 +04:00
NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX ;
2005-04-17 02:20:36 +04:00
}