diff options
Diffstat (limited to 'net/bridge/br_device.c')
-rw-r--r-- | net/bridge/br_device.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index f564ee99782d..0b33a7b3a00c 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -15,7 +15,9 @@ | |||
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
18 | #include <linux/module.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/ethtool.h> | ||
20 | |||
19 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
20 | #include "br_private.h" | 22 | #include "br_private.h" |
21 | 23 | ||
@@ -82,6 +84,87 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
82 | return 0; | 84 | return 0; |
83 | } | 85 | } |
84 | 86 | ||
87 | /* Allow setting mac address of pseudo-bridge to be same as | ||
88 | * any of the bound interfaces | ||
89 | */ | ||
90 | static int br_set_mac_address(struct net_device *dev, void *p) | ||
91 | { | ||
92 | struct net_bridge *br = netdev_priv(dev); | ||
93 | struct sockaddr *addr = p; | ||
94 | struct net_bridge_port *port; | ||
95 | int err = -EADDRNOTAVAIL; | ||
96 | |||
97 | spin_lock_bh(&br->lock); | ||
98 | list_for_each_entry(port, &br->port_list, list) { | ||
99 | if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) { | ||
100 | br_stp_change_bridge_id(br, addr->sa_data); | ||
101 | err = 0; | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | spin_unlock_bh(&br->lock); | ||
106 | |||
107 | return err; | ||
108 | } | ||
109 | |||
110 | static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) | ||
111 | { | ||
112 | strcpy(info->driver, "bridge"); | ||
113 | strcpy(info->version, BR_VERSION); | ||
114 | strcpy(info->fw_version, "N/A"); | ||
115 | strcpy(info->bus_info, "N/A"); | ||
116 | } | ||
117 | |||
118 | static int br_set_sg(struct net_device *dev, u32 data) | ||
119 | { | ||
120 | struct net_bridge *br = netdev_priv(dev); | ||
121 | |||
122 | if (data) | ||
123 | br->feature_mask |= NETIF_F_SG; | ||
124 | else | ||
125 | br->feature_mask &= ~NETIF_F_SG; | ||
126 | |||
127 | br_features_recompute(br); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int br_set_tso(struct net_device *dev, u32 data) | ||
132 | { | ||
133 | struct net_bridge *br = netdev_priv(dev); | ||
134 | |||
135 | if (data) | ||
136 | br->feature_mask |= NETIF_F_TSO; | ||
137 | else | ||
138 | br->feature_mask &= ~NETIF_F_TSO; | ||
139 | |||
140 | br_features_recompute(br); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int br_set_tx_csum(struct net_device *dev, u32 data) | ||
145 | { | ||
146 | struct net_bridge *br = netdev_priv(dev); | ||
147 | |||
148 | if (data) | ||
149 | br->feature_mask |= NETIF_F_IP_CSUM; | ||
150 | else | ||
151 | br->feature_mask &= ~NETIF_F_IP_CSUM; | ||
152 | |||
153 | br_features_recompute(br); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct ethtool_ops br_ethtool_ops = { | ||
158 | .get_drvinfo = br_getinfo, | ||
159 | .get_link = ethtool_op_get_link, | ||
160 | .get_sg = ethtool_op_get_sg, | ||
161 | .set_sg = br_set_sg, | ||
162 | .get_tx_csum = ethtool_op_get_tx_csum, | ||
163 | .set_tx_csum = br_set_tx_csum, | ||
164 | .get_tso = ethtool_op_get_tso, | ||
165 | .set_tso = br_set_tso, | ||
166 | }; | ||
167 | |||
85 | void br_dev_setup(struct net_device *dev) | 168 | void br_dev_setup(struct net_device *dev) |
86 | { | 169 | { |
87 | memset(dev->dev_addr, 0, ETH_ALEN); | 170 | memset(dev->dev_addr, 0, ETH_ALEN); |
@@ -96,8 +179,12 @@ void br_dev_setup(struct net_device *dev) | |||
96 | dev->change_mtu = br_change_mtu; | 179 | dev->change_mtu = br_change_mtu; |
97 | dev->destructor = free_netdev; | 180 | dev->destructor = free_netdev; |
98 | SET_MODULE_OWNER(dev); | 181 | SET_MODULE_OWNER(dev); |
182 | SET_ETHTOOL_OPS(dev, &br_ethtool_ops); | ||
99 | dev->stop = br_dev_stop; | 183 | dev->stop = br_dev_stop; |
100 | dev->tx_queue_len = 0; | 184 | dev->tx_queue_len = 0; |
101 | dev->set_mac_address = NULL; | 185 | dev->set_mac_address = br_set_mac_address; |
102 | dev->priv_flags = IFF_EBRIDGE; | 186 | dev->priv_flags = IFF_EBRIDGE; |
187 | |||
188 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | ||
189 | | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM; | ||
103 | } | 190 | } |