Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Device handling code | |
3 | * Linux ethernet bridge | |
4 | * | |
5 | * Authors: | |
6 | * Lennert Buytenhek <buytenh@gnu.org> | |
7 | * | |
1da177e4 LT |
8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License | |
10 | * as published by the Free Software Foundation; either version | |
11 | * 2 of the License, or (at your option) any later version. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/netdevice.h> | |
4505a3ef | 16 | #include <linux/etherdevice.h> |
edb5e46f | 17 | #include <linux/ethtool.h> |
4505a3ef | 18 | |
1da177e4 LT |
19 | #include <asm/uaccess.h> |
20 | #include "br_private.h" | |
21 | ||
f8ae737d | 22 | /* net device transmit always called with no BH (preempt_disabled) */ |
6fef4c0c | 23 | netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) |
1da177e4 LT |
24 | { |
25 | struct net_bridge *br = netdev_priv(dev); | |
26 | const unsigned char *dest = skb->data; | |
27 | struct net_bridge_fdb_entry *dst; | |
c4fcb78c | 28 | struct net_bridge_mdb_entry *mdst; |
1da177e4 | 29 | |
6088a539 HX |
30 | BR_INPUT_SKB_CB(skb)->brdev = dev; |
31 | ||
a339f1c8 PE |
32 | dev->stats.tx_packets++; |
33 | dev->stats.tx_bytes += skb->len; | |
1da177e4 | 34 | |
459a98ed | 35 | skb_reset_mac_header(skb); |
1da177e4 LT |
36 | skb_pull(skb, ETH_HLEN); |
37 | ||
c4fcb78c HX |
38 | if (dest[0] & 1) { |
39 | if (br_multicast_rcv(br, NULL, skb)) | |
40 | goto out; | |
41 | ||
42 | mdst = br_mdb_get(br, skb); | |
32dec5dd | 43 | if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) |
c4fcb78c HX |
44 | br_multicast_deliver(mdst, skb); |
45 | else | |
46 | br_flood_deliver(br, skb); | |
47 | } else if ((dst = __br_fdb_get(br, dest)) != NULL) | |
1da177e4 LT |
48 | br_deliver(dst->dst, skb); |
49 | else | |
e081e1e3 | 50 | br_flood_deliver(br, skb); |
1da177e4 | 51 | |
c4fcb78c | 52 | out: |
6ed10654 | 53 | return NETDEV_TX_OK; |
1da177e4 LT |
54 | } |
55 | ||
56 | static int br_dev_open(struct net_device *dev) | |
57 | { | |
81d35307 | 58 | struct net_bridge *br = netdev_priv(dev); |
1da177e4 | 59 | |
81d35307 SH |
60 | br_features_recompute(br); |
61 | netif_start_queue(dev); | |
62 | br_stp_enable_bridge(br); | |
3fe2d7c7 | 63 | br_multicast_open(br); |
1da177e4 LT |
64 | |
65 | return 0; | |
66 | } | |
67 | ||
68 | static void br_dev_set_multicast_list(struct net_device *dev) | |
69 | { | |
70 | } | |
71 | ||
72 | static int br_dev_stop(struct net_device *dev) | |
73 | { | |
3fe2d7c7 HX |
74 | struct net_bridge *br = netdev_priv(dev); |
75 | ||
76 | br_stp_disable_bridge(br); | |
77 | br_multicast_stop(br); | |
1da177e4 LT |
78 | |
79 | netif_stop_queue(dev); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int br_change_mtu(struct net_device *dev, int new_mtu) | |
85 | { | |
4adf0af6 SW |
86 | struct net_bridge *br = netdev_priv(dev); |
87 | if (new_mtu < 68 || new_mtu > br_min_mtu(br)) | |
1da177e4 LT |
88 | return -EINVAL; |
89 | ||
90 | dev->mtu = new_mtu; | |
4adf0af6 SW |
91 | |
92 | #ifdef CONFIG_BRIDGE_NETFILTER | |
93 | /* remember the MTU in the rtable for PMTU */ | |
94 | br->fake_rtable.u.dst.metrics[RTAX_MTU - 1] = new_mtu; | |
95 | #endif | |
96 | ||
1da177e4 LT |
97 | return 0; |
98 | } | |
99 | ||
ffe1d49c | 100 | /* Allow setting mac address to any valid ethernet address. */ |
4505a3ef SH |
101 | static int br_set_mac_address(struct net_device *dev, void *p) |
102 | { | |
103 | struct net_bridge *br = netdev_priv(dev); | |
104 | struct sockaddr *addr = p; | |
ffe1d49c SH |
105 | |
106 | if (!is_valid_ether_addr(addr->sa_data)) | |
107 | return -EINVAL; | |
4505a3ef SH |
108 | |
109 | spin_lock_bh(&br->lock); | |
ffe1d49c SH |
110 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
111 | br_stp_change_bridge_id(br, addr->sa_data); | |
92c0574f | 112 | br->flags |= BR_SET_MAC_ADDR; |
4505a3ef SH |
113 | spin_unlock_bh(&br->lock); |
114 | ||
ffe1d49c | 115 | return 0; |
4505a3ef SH |
116 | } |
117 | ||
edb5e46f SH |
118 | static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
119 | { | |
120 | strcpy(info->driver, "bridge"); | |
121 | strcpy(info->version, BR_VERSION); | |
122 | strcpy(info->fw_version, "N/A"); | |
123 | strcpy(info->bus_info, "N/A"); | |
124 | } | |
125 | ||
126 | static int br_set_sg(struct net_device *dev, u32 data) | |
127 | { | |
128 | struct net_bridge *br = netdev_priv(dev); | |
129 | ||
130 | if (data) | |
131 | br->feature_mask |= NETIF_F_SG; | |
132 | else | |
133 | br->feature_mask &= ~NETIF_F_SG; | |
134 | ||
135 | br_features_recompute(br); | |
136 | return 0; | |
137 | } | |
138 | ||
139 | static int br_set_tso(struct net_device *dev, u32 data) | |
140 | { | |
141 | struct net_bridge *br = netdev_priv(dev); | |
142 | ||
143 | if (data) | |
144 | br->feature_mask |= NETIF_F_TSO; | |
145 | else | |
146 | br->feature_mask &= ~NETIF_F_TSO; | |
147 | ||
148 | br_features_recompute(br); | |
149 | return 0; | |
150 | } | |
151 | ||
152 | static int br_set_tx_csum(struct net_device *dev, u32 data) | |
153 | { | |
154 | struct net_bridge *br = netdev_priv(dev); | |
155 | ||
156 | if (data) | |
2c6cc0d8 | 157 | br->feature_mask |= NETIF_F_NO_CSUM; |
edb5e46f | 158 | else |
2c6cc0d8 | 159 | br->feature_mask &= ~NETIF_F_ALL_CSUM; |
edb5e46f SH |
160 | |
161 | br_features_recompute(br); | |
162 | return 0; | |
163 | } | |
164 | ||
a2dbb882 | 165 | static const struct ethtool_ops br_ethtool_ops = { |
e4119a43 SH |
166 | .get_drvinfo = br_getinfo, |
167 | .get_link = ethtool_op_get_link, | |
168 | .get_tx_csum = ethtool_op_get_tx_csum, | |
169 | .set_tx_csum = br_set_tx_csum, | |
170 | .get_sg = ethtool_op_get_sg, | |
171 | .set_sg = br_set_sg, | |
172 | .get_tso = ethtool_op_get_tso, | |
173 | .set_tso = br_set_tso, | |
174 | .get_ufo = ethtool_op_get_ufo, | |
72dad218 | 175 | .set_ufo = ethtool_op_set_ufo, |
e4119a43 | 176 | .get_flags = ethtool_op_get_flags, |
edb5e46f SH |
177 | }; |
178 | ||
a2dbb882 SH |
179 | static const struct net_device_ops br_netdev_ops = { |
180 | .ndo_open = br_dev_open, | |
181 | .ndo_stop = br_dev_stop, | |
00829823 SH |
182 | .ndo_start_xmit = br_dev_xmit, |
183 | .ndo_set_mac_address = br_set_mac_address, | |
184 | .ndo_set_multicast_list = br_dev_set_multicast_list, | |
185 | .ndo_change_mtu = br_change_mtu, | |
186 | .ndo_do_ioctl = br_dev_ioctl, | |
a2dbb882 SH |
187 | }; |
188 | ||
1da177e4 LT |
189 | void br_dev_setup(struct net_device *dev) |
190 | { | |
3ae41254 | 191 | random_ether_addr(dev->dev_addr); |
1da177e4 LT |
192 | ether_setup(dev); |
193 | ||
a2dbb882 | 194 | dev->netdev_ops = &br_netdev_ops; |
1da177e4 | 195 | dev->destructor = free_netdev; |
9d6f229f | 196 | SET_ETHTOOL_OPS(dev, &br_ethtool_ops); |
1da177e4 | 197 | dev->tx_queue_len = 0; |
1da177e4 | 198 | dev->priv_flags = IFF_EBRIDGE; |
edb5e46f | 199 | |
9d6f229f | 200 | dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | |
4aa678ba | 201 | NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX | |
b63365a2 | 202 | NETIF_F_NETNS_LOCAL | NETIF_F_GSO; |
1da177e4 | 203 | } |