X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fbridge%2Fbr_device.c;h=f8dbcee80ebad7cdffb110fd87a8796db93643ab;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=b7e6adc0bd9be52dcc0183f2a325e27fd4098475;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index b7e6adc0b..f8dbcee80 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -15,85 +15,155 @@ #include #include -#include +#include +#include + #include #include "br_private.h" static struct net_device_stats *br_dev_get_stats(struct net_device *dev) { - struct net_bridge *br; - - br = dev->priv; - + struct net_bridge *br = netdev_priv(dev); return &br->statistics; } -static int __br_dev_xmit(struct sk_buff *skb, struct net_device *dev) +/* net device transmit always called with no BH (preempt_disabled) */ +int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_bridge *br; - unsigned char *dest; + struct net_bridge *br = netdev_priv(dev); + const unsigned char *dest = skb->data; struct net_bridge_fdb_entry *dst; - br = dev->priv; br->statistics.tx_packets++; br->statistics.tx_bytes += skb->len; - dest = skb->mac.raw = skb->data; + skb->mac.raw = skb->data; skb_pull(skb, ETH_HLEN); - if (dest[0] & 1) { + if (dest[0] & 1) br_flood_deliver(br, skb, 0); - return 0; - } - - if ((dst = br_fdb_get(br, dest)) != NULL) { + else if ((dst = __br_fdb_get(br, dest)) != NULL) br_deliver(dst->dst, skb); - br_fdb_put(dst); - return 0; - } + else + br_flood_deliver(br, skb, 0); - br_flood_deliver(br, skb, 0); return 0; } -int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) +static int br_dev_open(struct net_device *dev) { - int ret; + struct net_bridge *br = netdev_priv(dev); - rcu_read_lock(); - ret = __br_dev_xmit(skb, dev); - rcu_read_unlock(); + br_features_recompute(br); + netif_start_queue(dev); + br_stp_enable_bridge(br); - return ret; + return 0; } -static int br_dev_open(struct net_device *dev) +static void br_dev_set_multicast_list(struct net_device *dev) { - netif_start_queue(dev); +} - br_stp_enable_bridge(dev->priv); +static int br_dev_stop(struct net_device *dev) +{ + br_stp_disable_bridge(netdev_priv(dev)); + + netif_stop_queue(dev); return 0; } -static void br_dev_set_multicast_list(struct net_device *dev) +static int br_change_mtu(struct net_device *dev, int new_mtu) { + if (new_mtu < 68 || new_mtu > br_min_mtu(netdev_priv(dev))) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; } -static int br_dev_stop(struct net_device *dev) +/* Allow setting mac address of pseudo-bridge to be same as + * any of the bound interfaces + */ +static int br_set_mac_address(struct net_device *dev, void *p) { - br_stp_disable_bridge(dev->priv); + struct net_bridge *br = netdev_priv(dev); + struct sockaddr *addr = p; + struct net_bridge_port *port; + int err = -EADDRNOTAVAIL; + + spin_lock_bh(&br->lock); + list_for_each_entry(port, &br->port_list, list) { + if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) { + br_stp_change_bridge_id(br, addr->sa_data); + err = 0; + break; + } + } + spin_unlock_bh(&br->lock); - netif_stop_queue(dev); + return err; +} + +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_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) +static int br_set_tso(struct net_device *dev, u32 data) { - return -1; + 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) + br->feature_mask |= NETIF_F_NO_CSUM; + else + br->feature_mask &= ~NETIF_F_ALL_CSUM; + + br_features_recompute(br); + return 0; +} + +static struct ethtool_ops br_ethtool_ops = { + .get_drvinfo = br_getinfo, + .get_link = ethtool_op_get_link, + .get_sg = ethtool_op_get_sg, + .set_sg = br_set_sg, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = br_set_tx_csum, + .get_tso = ethtool_op_get_tso, + .set_tso = br_set_tso, +}; + void br_dev_setup(struct net_device *dev) { memset(dev->dev_addr, 0, ETH_ALEN); @@ -105,11 +175,15 @@ void br_dev_setup(struct net_device *dev) 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; SET_MODULE_OWNER(dev); + SET_ETHTOOL_OPS(dev, &br_ethtool_ops); dev->stop = br_dev_stop; - dev->accept_fastpath = br_dev_accept_fastpath; dev->tx_queue_len = 0; - dev->set_mac_address = NULL; + dev->set_mac_address = br_set_mac_address; dev->priv_flags = IFF_EBRIDGE; + + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | + NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST; }