diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br.c | 12 | ||||
-rw-r--r-- | net/bridge/br_device.c | 22 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 42 | ||||
-rw-r--r-- | net/bridge/br_forward.c | 2 | ||||
-rw-r--r-- | net/bridge/br_if.c | 6 | ||||
-rw-r--r-- | net/bridge/br_input.c | 51 | ||||
-rw-r--r-- | net/bridge/br_ioctl.c | 5 | ||||
-rw-r--r-- | net/bridge/br_netfilter.c | 142 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 24 | ||||
-rw-r--r-- | net/bridge/br_notify.c | 13 | ||||
-rw-r--r-- | net/bridge/br_private.h | 23 | ||||
-rw-r--r-- | net/bridge/br_stp.c | 10 | ||||
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 19 | ||||
-rw-r--r-- | net/bridge/br_stp_if.c | 59 | ||||
-rw-r--r-- | net/bridge/br_sysfs_br.c | 20 | ||||
-rw-r--r-- | net/bridge/br_sysfs_if.c | 8 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_arp.c | 48 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_log.c | 12 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 12 |
19 files changed, 374 insertions, 156 deletions
diff --git a/net/bridge/br.c b/net/bridge/br.c index 2994387999a8..848b8fa8bedd 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -37,7 +37,9 @@ static int __init br_init(void) | |||
37 | return -EADDRINUSE; | 37 | return -EADDRINUSE; |
38 | } | 38 | } |
39 | 39 | ||
40 | br_fdb_init(); | 40 | err = br_fdb_init(); |
41 | if (err) | ||
42 | goto err_out1; | ||
41 | 43 | ||
42 | err = br_netfilter_init(); | 44 | err = br_netfilter_init(); |
43 | if (err) | 45 | if (err) |
@@ -47,7 +49,10 @@ static int __init br_init(void) | |||
47 | if (err) | 49 | if (err) |
48 | goto err_out2; | 50 | goto err_out2; |
49 | 51 | ||
50 | br_netlink_init(); | 52 | err = br_netlink_init(); |
53 | if (err) | ||
54 | goto err_out3; | ||
55 | |||
51 | brioctl_set(br_ioctl_deviceless_stub); | 56 | brioctl_set(br_ioctl_deviceless_stub); |
52 | br_handle_frame_hook = br_handle_frame; | 57 | br_handle_frame_hook = br_handle_frame; |
53 | 58 | ||
@@ -55,7 +60,8 @@ static int __init br_init(void) | |||
55 | br_fdb_put_hook = br_fdb_put; | 60 | br_fdb_put_hook = br_fdb_put; |
56 | 61 | ||
57 | return 0; | 62 | return 0; |
58 | 63 | err_out3: | |
64 | unregister_netdevice_notifier(&br_device_notifier); | ||
59 | err_out2: | 65 | err_out2: |
60 | br_netfilter_fini(); | 66 | br_netfilter_fini(); |
61 | err_out1: | 67 | err_out1: |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 905a39c33a16..5e1892d8d874 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -37,7 +37,7 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
37 | br->statistics.tx_packets++; | 37 | br->statistics.tx_packets++; |
38 | br->statistics.tx_bytes += skb->len; | 38 | br->statistics.tx_bytes += skb->len; |
39 | 39 | ||
40 | skb->mac.raw = skb->data; | 40 | skb_reset_mac_header(skb); |
41 | skb_pull(skb, ETH_HLEN); | 41 | skb_pull(skb, ETH_HLEN); |
42 | 42 | ||
43 | if (dest[0] & 1) | 43 | if (dest[0] & 1) |
@@ -83,27 +83,21 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | /* Allow setting mac address of pseudo-bridge to be same as | 86 | /* Allow setting mac address to any valid ethernet address. */ |
87 | * any of the bound interfaces | ||
88 | */ | ||
89 | static int br_set_mac_address(struct net_device *dev, void *p) | 87 | static int br_set_mac_address(struct net_device *dev, void *p) |
90 | { | 88 | { |
91 | struct net_bridge *br = netdev_priv(dev); | 89 | struct net_bridge *br = netdev_priv(dev); |
92 | struct sockaddr *addr = p; | 90 | struct sockaddr *addr = p; |
93 | struct net_bridge_port *port; | 91 | |
94 | int err = -EADDRNOTAVAIL; | 92 | if (!is_valid_ether_addr(addr->sa_data)) |
93 | return -EINVAL; | ||
95 | 94 | ||
96 | spin_lock_bh(&br->lock); | 95 | spin_lock_bh(&br->lock); |
97 | list_for_each_entry(port, &br->port_list, list) { | 96 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
98 | if (!compare_ether_addr(port->dev->dev_addr, addr->sa_data)) { | 97 | br_stp_change_bridge_id(br, addr->sa_data); |
99 | br_stp_change_bridge_id(br, addr->sa_data); | ||
100 | err = 0; | ||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | spin_unlock_bh(&br->lock); | 98 | spin_unlock_bh(&br->lock); |
105 | 99 | ||
106 | return err; | 100 | return 0; |
107 | } | 101 | } |
108 | 102 | ||
109 | static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) | 103 | static void br_getinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 8d566c13cc73..91b017016d5b 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -20,19 +20,28 @@ | |||
20 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
21 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
22 | #include <linux/jhash.h> | 22 | #include <linux/jhash.h> |
23 | #include <linux/random.h> | ||
23 | #include <asm/atomic.h> | 24 | #include <asm/atomic.h> |
25 | #include <asm/unaligned.h> | ||
24 | #include "br_private.h" | 26 | #include "br_private.h" |
25 | 27 | ||
26 | static struct kmem_cache *br_fdb_cache __read_mostly; | 28 | static struct kmem_cache *br_fdb_cache __read_mostly; |
27 | static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, | 29 | static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, |
28 | const unsigned char *addr); | 30 | const unsigned char *addr); |
29 | 31 | ||
30 | void __init br_fdb_init(void) | 32 | static u32 fdb_salt __read_mostly; |
33 | |||
34 | int __init br_fdb_init(void) | ||
31 | { | 35 | { |
32 | br_fdb_cache = kmem_cache_create("bridge_fdb_cache", | 36 | br_fdb_cache = kmem_cache_create("bridge_fdb_cache", |
33 | sizeof(struct net_bridge_fdb_entry), | 37 | sizeof(struct net_bridge_fdb_entry), |
34 | 0, | 38 | 0, |
35 | SLAB_HWCACHE_ALIGN, NULL, NULL); | 39 | SLAB_HWCACHE_ALIGN, NULL, NULL); |
40 | if (!br_fdb_cache) | ||
41 | return -ENOMEM; | ||
42 | |||
43 | get_random_bytes(&fdb_salt, sizeof(fdb_salt)); | ||
44 | return 0; | ||
36 | } | 45 | } |
37 | 46 | ||
38 | void __exit br_fdb_fini(void) | 47 | void __exit br_fdb_fini(void) |
@@ -44,24 +53,26 @@ void __exit br_fdb_fini(void) | |||
44 | /* if topology_changing then use forward_delay (default 15 sec) | 53 | /* if topology_changing then use forward_delay (default 15 sec) |
45 | * otherwise keep longer (default 5 minutes) | 54 | * otherwise keep longer (default 5 minutes) |
46 | */ | 55 | */ |
47 | static __inline__ unsigned long hold_time(const struct net_bridge *br) | 56 | static inline unsigned long hold_time(const struct net_bridge *br) |
48 | { | 57 | { |
49 | return br->topology_change ? br->forward_delay : br->ageing_time; | 58 | return br->topology_change ? br->forward_delay : br->ageing_time; |
50 | } | 59 | } |
51 | 60 | ||
52 | static __inline__ int has_expired(const struct net_bridge *br, | 61 | static inline int has_expired(const struct net_bridge *br, |
53 | const struct net_bridge_fdb_entry *fdb) | 62 | const struct net_bridge_fdb_entry *fdb) |
54 | { | 63 | { |
55 | return !fdb->is_static | 64 | return !fdb->is_static |
56 | && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); | 65 | && time_before_eq(fdb->ageing_timer + hold_time(br), jiffies); |
57 | } | 66 | } |
58 | 67 | ||
59 | static __inline__ int br_mac_hash(const unsigned char *mac) | 68 | static inline int br_mac_hash(const unsigned char *mac) |
60 | { | 69 | { |
61 | return jhash(mac, ETH_ALEN, 0) & (BR_HASH_SIZE - 1); | 70 | /* use 1 byte of OUI cnd 3 bytes of NIC */ |
71 | u32 key = get_unaligned((u32 *)(mac + 2)); | ||
72 | return jhash_1word(key, fdb_salt) & (BR_HASH_SIZE - 1); | ||
62 | } | 73 | } |
63 | 74 | ||
64 | static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f) | 75 | static inline void fdb_delete(struct net_bridge_fdb_entry *f) |
65 | { | 76 | { |
66 | hlist_del_rcu(&f->hlist); | 77 | hlist_del_rcu(&f->hlist); |
67 | br_fdb_put(f); | 78 | br_fdb_put(f); |
@@ -128,7 +139,26 @@ void br_fdb_cleanup(unsigned long _data) | |||
128 | mod_timer(&br->gc_timer, jiffies + HZ/10); | 139 | mod_timer(&br->gc_timer, jiffies + HZ/10); |
129 | } | 140 | } |
130 | 141 | ||
142 | /* Completely flush all dynamic entries in forwarding database.*/ | ||
143 | void br_fdb_flush(struct net_bridge *br) | ||
144 | { | ||
145 | int i; | ||
131 | 146 | ||
147 | spin_lock_bh(&br->hash_lock); | ||
148 | for (i = 0; i < BR_HASH_SIZE; i++) { | ||
149 | struct net_bridge_fdb_entry *f; | ||
150 | struct hlist_node *h, *n; | ||
151 | hlist_for_each_entry_safe(f, h, n, &br->hash[i], hlist) { | ||
152 | if (!f->is_static) | ||
153 | fdb_delete(f); | ||
154 | } | ||
155 | } | ||
156 | spin_unlock_bh(&br->hash_lock); | ||
157 | } | ||
158 | |||
159 | /* Flush all entries refering to a specific port. | ||
160 | * if do_all is set also flush static entries | ||
161 | */ | ||
132 | void br_fdb_delete_by_port(struct net_bridge *br, | 162 | void br_fdb_delete_by_port(struct net_bridge *br, |
133 | const struct net_bridge_port *p, | 163 | const struct net_bridge_port *p, |
134 | int do_all) | 164 | int do_all) |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 3e45c1a1aa96..ada7f495445c 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -71,7 +71,7 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) | |||
71 | 71 | ||
72 | indev = skb->dev; | 72 | indev = skb->dev; |
73 | skb->dev = to->dev; | 73 | skb->dev = to->dev; |
74 | skb->ip_summed = CHECKSUM_NONE; | 74 | skb_forward_csum(skb); |
75 | 75 | ||
76 | NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, | 76 | NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev, |
77 | br_forward_finish); | 77 | br_forward_finish); |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f3a2e29be40c..690573bbf012 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -152,6 +152,8 @@ static void del_nbp(struct net_bridge_port *p) | |||
152 | br_stp_disable_port(p); | 152 | br_stp_disable_port(p); |
153 | spin_unlock_bh(&br->lock); | 153 | spin_unlock_bh(&br->lock); |
154 | 154 | ||
155 | br_ifinfo_notify(RTM_DELLINK, p); | ||
156 | |||
155 | br_fdb_delete_by_port(br, p, 1); | 157 | br_fdb_delete_by_port(br, p, 1); |
156 | 158 | ||
157 | list_del_rcu(&p->list); | 159 | list_del_rcu(&p->list); |
@@ -203,7 +205,7 @@ static struct net_device *new_bridge_dev(const char *name) | |||
203 | memcpy(br->group_addr, br_group_address, ETH_ALEN); | 205 | memcpy(br->group_addr, br_group_address, ETH_ALEN); |
204 | 206 | ||
205 | br->feature_mask = dev->features; | 207 | br->feature_mask = dev->features; |
206 | br->stp_enabled = 0; | 208 | br->stp_enabled = BR_NO_STP; |
207 | br->designated_root = br->bridge_id; | 209 | br->designated_root = br->bridge_id; |
208 | br->root_path_cost = 0; | 210 | br->root_path_cost = 0; |
209 | br->root_port = 0; | 211 | br->root_port = 0; |
@@ -434,6 +436,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) | |||
434 | br_stp_enable_port(p); | 436 | br_stp_enable_port(p); |
435 | spin_unlock_bh(&br->lock); | 437 | spin_unlock_bh(&br->lock); |
436 | 438 | ||
439 | br_ifinfo_notify(RTM_NEWLINK, p); | ||
440 | |||
437 | dev_set_mtu(br->dev, br_min_mtu(br)); | 441 | dev_set_mtu(br->dev, br_min_mtu(br)); |
438 | 442 | ||
439 | kobject_uevent(&p->kobj, KOBJ_ADD); | 443 | kobject_uevent(&p->kobj, KOBJ_ADD); |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 35b94f9a1ac5..420bbb9955e9 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -112,46 +112,59 @@ static int br_handle_local_finish(struct sk_buff *skb) | |||
112 | */ | 112 | */ |
113 | static inline int is_link_local(const unsigned char *dest) | 113 | static inline int is_link_local(const unsigned char *dest) |
114 | { | 114 | { |
115 | return memcmp(dest, br_group_address, 5) == 0 && (dest[5] & 0xf0) == 0; | 115 | const u16 *a = (const u16 *) dest; |
116 | static const u16 *const b = (const u16 *const ) br_group_address; | ||
117 | static const u16 m = __constant_cpu_to_be16(0xfff0); | ||
118 | |||
119 | return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; | ||
116 | } | 120 | } |
117 | 121 | ||
118 | /* | 122 | /* |
119 | * Called via br_handle_frame_hook. | 123 | * Called via br_handle_frame_hook. |
120 | * Return 0 if *pskb should be processed furthur | 124 | * Return NULL if skb is handled |
121 | * 1 if *pskb is handled | ||
122 | * note: already called with rcu_read_lock (preempt_disabled) | 125 | * note: already called with rcu_read_lock (preempt_disabled) |
123 | */ | 126 | */ |
124 | int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) | 127 | struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) |
125 | { | 128 | { |
126 | struct sk_buff *skb = *pskb; | ||
127 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 129 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
128 | 130 | ||
129 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 131 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
130 | goto err; | 132 | goto drop; |
131 | 133 | ||
132 | if (unlikely(is_link_local(dest))) { | 134 | if (unlikely(is_link_local(dest))) { |
133 | skb->pkt_type = PACKET_HOST; | 135 | /* Pause frames shouldn't be passed up by driver anyway */ |
134 | return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | 136 | if (skb->protocol == htons(ETH_P_PAUSE)) |
135 | NULL, br_handle_local_finish) != 0; | 137 | goto drop; |
138 | |||
139 | /* Process STP BPDU's through normal netif_receive_skb() path */ | ||
140 | if (p->br->stp_enabled != BR_NO_STP) { | ||
141 | if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev, | ||
142 | NULL, br_handle_local_finish)) | ||
143 | return NULL; | ||
144 | else | ||
145 | return skb; | ||
146 | } | ||
136 | } | 147 | } |
137 | 148 | ||
138 | if (p->state == BR_STATE_FORWARDING || p->state == BR_STATE_LEARNING) { | 149 | switch (p->state) { |
150 | case BR_STATE_FORWARDING: | ||
151 | |||
139 | if (br_should_route_hook) { | 152 | if (br_should_route_hook) { |
140 | if (br_should_route_hook(pskb)) | 153 | if (br_should_route_hook(&skb)) |
141 | return 0; | 154 | return skb; |
142 | skb = *pskb; | ||
143 | dest = eth_hdr(skb)->h_dest; | 155 | dest = eth_hdr(skb)->h_dest; |
144 | } | 156 | } |
145 | 157 | /* fall through */ | |
158 | case BR_STATE_LEARNING: | ||
146 | if (!compare_ether_addr(p->br->dev->dev_addr, dest)) | 159 | if (!compare_ether_addr(p->br->dev->dev_addr, dest)) |
147 | skb->pkt_type = PACKET_HOST; | 160 | skb->pkt_type = PACKET_HOST; |
148 | 161 | ||
149 | NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 162 | NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
150 | br_handle_frame_finish); | 163 | br_handle_frame_finish); |
151 | return 1; | 164 | break; |
165 | default: | ||
166 | drop: | ||
167 | kfree_skb(skb); | ||
152 | } | 168 | } |
153 | 169 | return NULL; | |
154 | err: | ||
155 | kfree_skb(skb); | ||
156 | return 1; | ||
157 | } | 170 | } |
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 147015fe5c75..eda0fbfc923a 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c | |||
@@ -137,7 +137,8 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
137 | b.topology_change = br->topology_change; | 137 | b.topology_change = br->topology_change; |
138 | b.topology_change_detected = br->topology_change_detected; | 138 | b.topology_change_detected = br->topology_change_detected; |
139 | b.root_port = br->root_port; | 139 | b.root_port = br->root_port; |
140 | b.stp_enabled = br->stp_enabled; | 140 | |
141 | b.stp_enabled = (br->stp_enabled != BR_NO_STP); | ||
141 | b.ageing_time = jiffies_to_clock_t(br->ageing_time); | 142 | b.ageing_time = jiffies_to_clock_t(br->ageing_time); |
142 | b.hello_timer_value = br_timer_value(&br->hello_timer); | 143 | b.hello_timer_value = br_timer_value(&br->hello_timer); |
143 | b.tcn_timer_value = br_timer_value(&br->tcn_timer); | 144 | b.tcn_timer_value = br_timer_value(&br->tcn_timer); |
@@ -251,7 +252,7 @@ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
251 | if (!capable(CAP_NET_ADMIN)) | 252 | if (!capable(CAP_NET_ADMIN)) |
252 | return -EPERM; | 253 | return -EPERM; |
253 | 254 | ||
254 | br->stp_enabled = args[1]?1:0; | 255 | br_stp_set_enabled(br, args[1]); |
255 | return 0; | 256 | return 0; |
256 | 257 | ||
257 | case BRCTL_SET_BRIDGE_PRIORITY: | 258 | case BRCTL_SET_BRIDGE_PRIORITY: |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 5439a3c46c3e..9b2986b182ba 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/if_arp.h> | 29 | #include <linux/if_arp.h> |
30 | #include <linux/if_ether.h> | 30 | #include <linux/if_ether.h> |
31 | #include <linux/if_vlan.h> | 31 | #include <linux/if_vlan.h> |
32 | #include <linux/if_pppox.h> | ||
33 | #include <linux/ppp_defs.h> | ||
32 | #include <linux/netfilter_bridge.h> | 34 | #include <linux/netfilter_bridge.h> |
33 | #include <linux/netfilter_ipv4.h> | 35 | #include <linux/netfilter_ipv4.h> |
34 | #include <linux/netfilter_ipv6.h> | 36 | #include <linux/netfilter_ipv6.h> |
@@ -48,8 +50,8 @@ | |||
48 | 50 | ||
49 | #define skb_origaddr(skb) (((struct bridge_skb_cb *) \ | 51 | #define skb_origaddr(skb) (((struct bridge_skb_cb *) \ |
50 | (skb->nf_bridge->data))->daddr.ipv4) | 52 | (skb->nf_bridge->data))->daddr.ipv4) |
51 | #define store_orig_dstaddr(skb) (skb_origaddr(skb) = (skb)->nh.iph->daddr) | 53 | #define store_orig_dstaddr(skb) (skb_origaddr(skb) = ip_hdr(skb)->daddr) |
52 | #define dnat_took_place(skb) (skb_origaddr(skb) != (skb)->nh.iph->daddr) | 54 | #define dnat_took_place(skb) (skb_origaddr(skb) != ip_hdr(skb)->daddr) |
53 | 55 | ||
54 | #ifdef CONFIG_SYSCTL | 56 | #ifdef CONFIG_SYSCTL |
55 | static struct ctl_table_header *brnf_sysctl_header; | 57 | static struct ctl_table_header *brnf_sysctl_header; |
@@ -57,8 +59,10 @@ static int brnf_call_iptables __read_mostly = 1; | |||
57 | static int brnf_call_ip6tables __read_mostly = 1; | 59 | static int brnf_call_ip6tables __read_mostly = 1; |
58 | static int brnf_call_arptables __read_mostly = 1; | 60 | static int brnf_call_arptables __read_mostly = 1; |
59 | static int brnf_filter_vlan_tagged __read_mostly = 1; | 61 | static int brnf_filter_vlan_tagged __read_mostly = 1; |
62 | static int brnf_filter_pppoe_tagged __read_mostly = 1; | ||
60 | #else | 63 | #else |
61 | #define brnf_filter_vlan_tagged 1 | 64 | #define brnf_filter_vlan_tagged 1 |
65 | #define brnf_filter_pppoe_tagged 1 | ||
62 | #endif | 66 | #endif |
63 | 67 | ||
64 | static inline __be16 vlan_proto(const struct sk_buff *skb) | 68 | static inline __be16 vlan_proto(const struct sk_buff *skb) |
@@ -81,6 +85,22 @@ static inline __be16 vlan_proto(const struct sk_buff *skb) | |||
81 | vlan_proto(skb) == htons(ETH_P_ARP) && \ | 85 | vlan_proto(skb) == htons(ETH_P_ARP) && \ |
82 | brnf_filter_vlan_tagged) | 86 | brnf_filter_vlan_tagged) |
83 | 87 | ||
88 | static inline __be16 pppoe_proto(const struct sk_buff *skb) | ||
89 | { | ||
90 | return *((__be16 *)(skb_mac_header(skb) + ETH_HLEN + | ||
91 | sizeof(struct pppoe_hdr))); | ||
92 | } | ||
93 | |||
94 | #define IS_PPPOE_IP(skb) \ | ||
95 | (skb->protocol == htons(ETH_P_PPP_SES) && \ | ||
96 | pppoe_proto(skb) == htons(PPP_IP) && \ | ||
97 | brnf_filter_pppoe_tagged) | ||
98 | |||
99 | #define IS_PPPOE_IPV6(skb) \ | ||
100 | (skb->protocol == htons(ETH_P_PPP_SES) && \ | ||
101 | pppoe_proto(skb) == htons(PPP_IPV6) && \ | ||
102 | brnf_filter_pppoe_tagged) | ||
103 | |||
84 | /* We need these fake structures to make netfilter happy -- | 104 | /* We need these fake structures to make netfilter happy -- |
85 | * lots of places assume that skb->dst != NULL, which isn't | 105 | * lots of places assume that skb->dst != NULL, which isn't |
86 | * all that unreasonable. | 106 | * all that unreasonable. |
@@ -128,8 +148,11 @@ static inline void nf_bridge_save_header(struct sk_buff *skb) | |||
128 | 148 | ||
129 | if (skb->protocol == htons(ETH_P_8021Q)) | 149 | if (skb->protocol == htons(ETH_P_8021Q)) |
130 | header_size += VLAN_HLEN; | 150 | header_size += VLAN_HLEN; |
151 | else if (skb->protocol == htons(ETH_P_PPP_SES)) | ||
152 | header_size += PPPOE_SES_HLEN; | ||
131 | 153 | ||
132 | memcpy(skb->nf_bridge->data, skb->data - header_size, header_size); | 154 | skb_copy_from_linear_data_offset(skb, -header_size, |
155 | skb->nf_bridge->data, header_size); | ||
133 | } | 156 | } |
134 | 157 | ||
135 | /* | 158 | /* |
@@ -143,15 +166,20 @@ int nf_bridge_copy_header(struct sk_buff *skb) | |||
143 | 166 | ||
144 | if (skb->protocol == htons(ETH_P_8021Q)) | 167 | if (skb->protocol == htons(ETH_P_8021Q)) |
145 | header_size += VLAN_HLEN; | 168 | header_size += VLAN_HLEN; |
169 | else if (skb->protocol == htons(ETH_P_PPP_SES)) | ||
170 | header_size += PPPOE_SES_HLEN; | ||
146 | 171 | ||
147 | err = skb_cow(skb, header_size); | 172 | err = skb_cow(skb, header_size); |
148 | if (err) | 173 | if (err) |
149 | return err; | 174 | return err; |
150 | 175 | ||
151 | memcpy(skb->data - header_size, skb->nf_bridge->data, header_size); | 176 | skb_copy_to_linear_data_offset(skb, -header_size, |
177 | skb->nf_bridge->data, header_size); | ||
152 | 178 | ||
153 | if (skb->protocol == htons(ETH_P_8021Q)) | 179 | if (skb->protocol == htons(ETH_P_8021Q)) |
154 | __skb_push(skb, VLAN_HLEN); | 180 | __skb_push(skb, VLAN_HLEN); |
181 | else if (skb->protocol == htons(ETH_P_PPP_SES)) | ||
182 | __skb_push(skb, PPPOE_SES_HLEN); | ||
155 | return 0; | 183 | return 0; |
156 | } | 184 | } |
157 | 185 | ||
@@ -174,7 +202,10 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) | |||
174 | skb->dev = nf_bridge->physindev; | 202 | skb->dev = nf_bridge->physindev; |
175 | if (skb->protocol == htons(ETH_P_8021Q)) { | 203 | if (skb->protocol == htons(ETH_P_8021Q)) { |
176 | skb_push(skb, VLAN_HLEN); | 204 | skb_push(skb, VLAN_HLEN); |
177 | skb->nh.raw -= VLAN_HLEN; | 205 | skb->network_header -= VLAN_HLEN; |
206 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
207 | skb_push(skb, PPPOE_SES_HLEN); | ||
208 | skb->network_header -= PPPOE_SES_HLEN; | ||
178 | } | 209 | } |
179 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 210 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
180 | br_handle_frame_finish, 1); | 211 | br_handle_frame_finish, 1); |
@@ -255,7 +286,10 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | |||
255 | else { | 286 | else { |
256 | if (skb->protocol == htons(ETH_P_8021Q)) { | 287 | if (skb->protocol == htons(ETH_P_8021Q)) { |
257 | skb_pull(skb, VLAN_HLEN); | 288 | skb_pull(skb, VLAN_HLEN); |
258 | skb->nh.raw += VLAN_HLEN; | 289 | skb->network_header += VLAN_HLEN; |
290 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
291 | skb_pull(skb, PPPOE_SES_HLEN); | ||
292 | skb->network_header += PPPOE_SES_HLEN; | ||
259 | } | 293 | } |
260 | skb->dst->output(skb); | 294 | skb->dst->output(skb); |
261 | } | 295 | } |
@@ -265,7 +299,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) | |||
265 | static int br_nf_pre_routing_finish(struct sk_buff *skb) | 299 | static int br_nf_pre_routing_finish(struct sk_buff *skb) |
266 | { | 300 | { |
267 | struct net_device *dev = skb->dev; | 301 | struct net_device *dev = skb->dev; |
268 | struct iphdr *iph = skb->nh.iph; | 302 | struct iphdr *iph = ip_hdr(skb); |
269 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 303 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
270 | int err; | 304 | int err; |
271 | 305 | ||
@@ -325,7 +359,11 @@ bridged_dnat: | |||
325 | if (skb->protocol == | 359 | if (skb->protocol == |
326 | htons(ETH_P_8021Q)) { | 360 | htons(ETH_P_8021Q)) { |
327 | skb_push(skb, VLAN_HLEN); | 361 | skb_push(skb, VLAN_HLEN); |
328 | skb->nh.raw -= VLAN_HLEN; | 362 | skb->network_header -= VLAN_HLEN; |
363 | } else if(skb->protocol == | ||
364 | htons(ETH_P_PPP_SES)) { | ||
365 | skb_push(skb, PPPOE_SES_HLEN); | ||
366 | skb->network_header -= PPPOE_SES_HLEN; | ||
329 | } | 367 | } |
330 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, | 368 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, |
331 | skb, skb->dev, NULL, | 369 | skb, skb->dev, NULL, |
@@ -344,7 +382,10 @@ bridged_dnat: | |||
344 | skb->dev = nf_bridge->physindev; | 382 | skb->dev = nf_bridge->physindev; |
345 | if (skb->protocol == htons(ETH_P_8021Q)) { | 383 | if (skb->protocol == htons(ETH_P_8021Q)) { |
346 | skb_push(skb, VLAN_HLEN); | 384 | skb_push(skb, VLAN_HLEN); |
347 | skb->nh.raw -= VLAN_HLEN; | 385 | skb->network_header -= VLAN_HLEN; |
386 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
387 | skb_push(skb, PPPOE_SES_HLEN); | ||
388 | skb->network_header -= PPPOE_SES_HLEN; | ||
348 | } | 389 | } |
349 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 390 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
350 | br_handle_frame_finish, 1); | 391 | br_handle_frame_finish, 1); |
@@ -372,9 +413,10 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb) | |||
372 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ | 413 | /* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */ |
373 | static int check_hbh_len(struct sk_buff *skb) | 414 | static int check_hbh_len(struct sk_buff *skb) |
374 | { | 415 | { |
375 | unsigned char *raw = (u8 *) (skb->nh.ipv6h + 1); | 416 | unsigned char *raw = (u8 *)(ipv6_hdr(skb) + 1); |
376 | u32 pkt_len; | 417 | u32 pkt_len; |
377 | int off = raw - skb->nh.raw; | 418 | const unsigned char *nh = skb_network_header(skb); |
419 | int off = raw - nh; | ||
378 | int len = (raw[1] + 1) << 3; | 420 | int len = (raw[1] + 1) << 3; |
379 | 421 | ||
380 | if ((raw + len) - skb->data > skb_headlen(skb)) | 422 | if ((raw + len) - skb->data > skb_headlen(skb)) |
@@ -384,9 +426,9 @@ static int check_hbh_len(struct sk_buff *skb) | |||
384 | len -= 2; | 426 | len -= 2; |
385 | 427 | ||
386 | while (len > 0) { | 428 | while (len > 0) { |
387 | int optlen = skb->nh.raw[off + 1] + 2; | 429 | int optlen = nh[off + 1] + 2; |
388 | 430 | ||
389 | switch (skb->nh.raw[off]) { | 431 | switch (nh[off]) { |
390 | case IPV6_TLV_PAD0: | 432 | case IPV6_TLV_PAD0: |
391 | optlen = 1; | 433 | optlen = 1; |
392 | break; | 434 | break; |
@@ -395,17 +437,18 @@ static int check_hbh_len(struct sk_buff *skb) | |||
395 | break; | 437 | break; |
396 | 438 | ||
397 | case IPV6_TLV_JUMBO: | 439 | case IPV6_TLV_JUMBO: |
398 | if (skb->nh.raw[off + 1] != 4 || (off & 3) != 2) | 440 | if (nh[off + 1] != 4 || (off & 3) != 2) |
399 | goto bad; | 441 | goto bad; |
400 | pkt_len = ntohl(*(__be32 *) (skb->nh.raw + off + 2)); | 442 | pkt_len = ntohl(*(__be32 *) (nh + off + 2)); |
401 | if (pkt_len <= IPV6_MAXPLEN || | 443 | if (pkt_len <= IPV6_MAXPLEN || |
402 | skb->nh.ipv6h->payload_len) | 444 | ipv6_hdr(skb)->payload_len) |
403 | goto bad; | 445 | goto bad; |
404 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) | 446 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) |
405 | goto bad; | 447 | goto bad; |
406 | if (pskb_trim_rcsum(skb, | 448 | if (pskb_trim_rcsum(skb, |
407 | pkt_len + sizeof(struct ipv6hdr))) | 449 | pkt_len + sizeof(struct ipv6hdr))) |
408 | goto bad; | 450 | goto bad; |
451 | nh = skb_network_header(skb); | ||
409 | break; | 452 | break; |
410 | default: | 453 | default: |
411 | if (optlen > len) | 454 | if (optlen > len) |
@@ -439,7 +482,7 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook, | |||
439 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | 482 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
440 | goto inhdr_error; | 483 | goto inhdr_error; |
441 | 484 | ||
442 | hdr = skb->nh.ipv6h; | 485 | hdr = ipv6_hdr(skb); |
443 | 486 | ||
444 | if (hdr->version != 6) | 487 | if (hdr->version != 6) |
445 | goto inhdr_error; | 488 | goto inhdr_error; |
@@ -485,7 +528,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
485 | __u32 len; | 528 | __u32 len; |
486 | struct sk_buff *skb = *pskb; | 529 | struct sk_buff *skb = *pskb; |
487 | 530 | ||
488 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb)) { | 531 | if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb) || |
532 | IS_PPPOE_IPV6(skb)) { | ||
489 | #ifdef CONFIG_SYSCTL | 533 | #ifdef CONFIG_SYSCTL |
490 | if (!brnf_call_ip6tables) | 534 | if (!brnf_call_ip6tables) |
491 | return NF_ACCEPT; | 535 | return NF_ACCEPT; |
@@ -495,7 +539,10 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
495 | 539 | ||
496 | if (skb->protocol == htons(ETH_P_8021Q)) { | 540 | if (skb->protocol == htons(ETH_P_8021Q)) { |
497 | skb_pull_rcsum(skb, VLAN_HLEN); | 541 | skb_pull_rcsum(skb, VLAN_HLEN); |
498 | skb->nh.raw += VLAN_HLEN; | 542 | skb->network_header += VLAN_HLEN; |
543 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
544 | skb_pull_rcsum(skb, PPPOE_SES_HLEN); | ||
545 | skb->network_header += PPPOE_SES_HLEN; | ||
499 | } | 546 | } |
500 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); | 547 | return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn); |
501 | } | 548 | } |
@@ -504,7 +551,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
504 | return NF_ACCEPT; | 551 | return NF_ACCEPT; |
505 | #endif | 552 | #endif |
506 | 553 | ||
507 | if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb)) | 554 | if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb) && |
555 | !IS_PPPOE_IP(skb)) | ||
508 | return NF_ACCEPT; | 556 | return NF_ACCEPT; |
509 | 557 | ||
510 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) | 558 | if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL) |
@@ -512,20 +560,23 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb, | |||
512 | 560 | ||
513 | if (skb->protocol == htons(ETH_P_8021Q)) { | 561 | if (skb->protocol == htons(ETH_P_8021Q)) { |
514 | skb_pull_rcsum(skb, VLAN_HLEN); | 562 | skb_pull_rcsum(skb, VLAN_HLEN); |
515 | skb->nh.raw += VLAN_HLEN; | 563 | skb->network_header += VLAN_HLEN; |
564 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
565 | skb_pull_rcsum(skb, PPPOE_SES_HLEN); | ||
566 | skb->network_header += PPPOE_SES_HLEN; | ||
516 | } | 567 | } |
517 | 568 | ||
518 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 569 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
519 | goto inhdr_error; | 570 | goto inhdr_error; |
520 | 571 | ||
521 | iph = skb->nh.iph; | 572 | iph = ip_hdr(skb); |
522 | if (iph->ihl < 5 || iph->version != 4) | 573 | if (iph->ihl < 5 || iph->version != 4) |
523 | goto inhdr_error; | 574 | goto inhdr_error; |
524 | 575 | ||
525 | if (!pskb_may_pull(skb, 4 * iph->ihl)) | 576 | if (!pskb_may_pull(skb, 4 * iph->ihl)) |
526 | goto inhdr_error; | 577 | goto inhdr_error; |
527 | 578 | ||
528 | iph = skb->nh.iph; | 579 | iph = ip_hdr(skb); |
529 | if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0) | 580 | if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0) |
530 | goto inhdr_error; | 581 | goto inhdr_error; |
531 | 582 | ||
@@ -593,7 +644,10 @@ static int br_nf_forward_finish(struct sk_buff *skb) | |||
593 | } | 644 | } |
594 | if (skb->protocol == htons(ETH_P_8021Q)) { | 645 | if (skb->protocol == htons(ETH_P_8021Q)) { |
595 | skb_push(skb, VLAN_HLEN); | 646 | skb_push(skb, VLAN_HLEN); |
596 | skb->nh.raw -= VLAN_HLEN; | 647 | skb->network_header -= VLAN_HLEN; |
648 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
649 | skb_push(skb, PPPOE_SES_HLEN); | ||
650 | skb->network_header -= PPPOE_SES_HLEN; | ||
597 | } | 651 | } |
598 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, | 652 | NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in, |
599 | skb->dev, br_forward_finish, 1); | 653 | skb->dev, br_forward_finish, 1); |
@@ -622,14 +676,18 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb, | |||
622 | if (!parent) | 676 | if (!parent) |
623 | return NF_DROP; | 677 | return NF_DROP; |
624 | 678 | ||
625 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) | 679 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) || |
680 | IS_PPPOE_IP(skb)) | ||
626 | pf = PF_INET; | 681 | pf = PF_INET; |
627 | else | 682 | else |
628 | pf = PF_INET6; | 683 | pf = PF_INET6; |
629 | 684 | ||
630 | if (skb->protocol == htons(ETH_P_8021Q)) { | 685 | if (skb->protocol == htons(ETH_P_8021Q)) { |
631 | skb_pull(*pskb, VLAN_HLEN); | 686 | skb_pull(*pskb, VLAN_HLEN); |
632 | (*pskb)->nh.raw += VLAN_HLEN; | 687 | (*pskb)->network_header += VLAN_HLEN; |
688 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
689 | skb_pull(*pskb, PPPOE_SES_HLEN); | ||
690 | (*pskb)->network_header += PPPOE_SES_HLEN; | ||
633 | } | 691 | } |
634 | 692 | ||
635 | nf_bridge = skb->nf_bridge; | 693 | nf_bridge = skb->nf_bridge; |
@@ -665,13 +723,13 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, | |||
665 | if (!IS_VLAN_ARP(skb)) | 723 | if (!IS_VLAN_ARP(skb)) |
666 | return NF_ACCEPT; | 724 | return NF_ACCEPT; |
667 | skb_pull(*pskb, VLAN_HLEN); | 725 | skb_pull(*pskb, VLAN_HLEN); |
668 | (*pskb)->nh.raw += VLAN_HLEN; | 726 | (*pskb)->network_header += VLAN_HLEN; |
669 | } | 727 | } |
670 | 728 | ||
671 | if (skb->nh.arph->ar_pln != 4) { | 729 | if (arp_hdr(skb)->ar_pln != 4) { |
672 | if (IS_VLAN_ARP(skb)) { | 730 | if (IS_VLAN_ARP(skb)) { |
673 | skb_push(*pskb, VLAN_HLEN); | 731 | skb_push(*pskb, VLAN_HLEN); |
674 | (*pskb)->nh.raw -= VLAN_HLEN; | 732 | (*pskb)->network_header -= VLAN_HLEN; |
675 | } | 733 | } |
676 | return NF_ACCEPT; | 734 | return NF_ACCEPT; |
677 | } | 735 | } |
@@ -721,7 +779,10 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, | |||
721 | } | 779 | } |
722 | if (skb->protocol == htons(ETH_P_8021Q)) { | 780 | if (skb->protocol == htons(ETH_P_8021Q)) { |
723 | skb_push(skb, VLAN_HLEN); | 781 | skb_push(skb, VLAN_HLEN); |
724 | skb->nh.raw -= VLAN_HLEN; | 782 | skb->network_header -= VLAN_HLEN; |
783 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
784 | skb_push(skb, PPPOE_SES_HLEN); | ||
785 | skb->network_header -= PPPOE_SES_HLEN; | ||
725 | } | 786 | } |
726 | 787 | ||
727 | NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev, | 788 | NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev, |
@@ -753,7 +814,8 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
753 | #ifdef CONFIG_NETFILTER_DEBUG | 814 | #ifdef CONFIG_NETFILTER_DEBUG |
754 | /* Be very paranoid. This probably won't happen anymore, but let's | 815 | /* Be very paranoid. This probably won't happen anymore, but let's |
755 | * keep the check just to be sure... */ | 816 | * keep the check just to be sure... */ |
756 | if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { | 817 | if (skb_mac_header(skb) < skb->head || |
818 | skb_mac_header(skb) + ETH_HLEN > skb->data) { | ||
757 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " | 819 | printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " |
758 | "bad mac.raw pointer.\n"); | 820 | "bad mac.raw pointer.\n"); |
759 | goto print_error; | 821 | goto print_error; |
@@ -766,7 +828,8 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
766 | if (!realoutdev) | 828 | if (!realoutdev) |
767 | return NF_DROP; | 829 | return NF_DROP; |
768 | 830 | ||
769 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) | 831 | if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb) || |
832 | IS_PPPOE_IP(skb)) | ||
770 | pf = PF_INET; | 833 | pf = PF_INET; |
771 | else | 834 | else |
772 | pf = PF_INET6; | 835 | pf = PF_INET6; |
@@ -787,7 +850,10 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, | |||
787 | 850 | ||
788 | if (skb->protocol == htons(ETH_P_8021Q)) { | 851 | if (skb->protocol == htons(ETH_P_8021Q)) { |
789 | skb_pull(skb, VLAN_HLEN); | 852 | skb_pull(skb, VLAN_HLEN); |
790 | skb->nh.raw += VLAN_HLEN; | 853 | skb->network_header += VLAN_HLEN; |
854 | } else if (skb->protocol == htons(ETH_P_PPP_SES)) { | ||
855 | skb_pull(skb, PPPOE_SES_HLEN); | ||
856 | skb->network_header += PPPOE_SES_HLEN; | ||
791 | } | 857 | } |
792 | 858 | ||
793 | nf_bridge_save_header(skb); | 859 | nf_bridge_save_header(skb); |
@@ -808,7 +874,7 @@ print_error: | |||
808 | if (realoutdev) | 874 | if (realoutdev) |
809 | printk("[%s]", realoutdev->name); | 875 | printk("[%s]", realoutdev->name); |
810 | } | 876 | } |
811 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw, | 877 | printk(" head:%p, raw:%p, data:%p\n", skb->head, skb_mac_header(skb), |
812 | skb->data); | 878 | skb->data); |
813 | dump_stack(); | 879 | dump_stack(); |
814 | return NF_ACCEPT; | 880 | return NF_ACCEPT; |
@@ -925,6 +991,14 @@ static ctl_table brnf_table[] = { | |||
925 | .mode = 0644, | 991 | .mode = 0644, |
926 | .proc_handler = &brnf_sysctl_call_tables, | 992 | .proc_handler = &brnf_sysctl_call_tables, |
927 | }, | 993 | }, |
994 | { | ||
995 | .ctl_name = NET_BRIDGE_NF_FILTER_PPPOE_TAGGED, | ||
996 | .procname = "bridge-nf-filter-pppoe-tagged", | ||
997 | .data = &brnf_filter_pppoe_tagged, | ||
998 | .maxlen = sizeof(int), | ||
999 | .mode = 0644, | ||
1000 | .proc_handler = &brnf_sysctl_call_tables, | ||
1001 | }, | ||
928 | { .ctl_name = 0 } | 1002 | { .ctl_name = 0 } |
929 | }; | 1003 | }; |
930 | 1004 | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 7d68b24b5654..35facc0c11c2 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -11,8 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/rtnetlink.h> | 14 | #include <net/rtnetlink.h> |
15 | #include <net/netlink.h> | ||
16 | #include "br_private.h" | 15 | #include "br_private.h" |
17 | 16 | ||
18 | static inline size_t br_nlmsg_size(void) | 17 | static inline size_t br_nlmsg_size(void) |
@@ -110,7 +109,6 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
110 | struct net_device *dev; | 109 | struct net_device *dev; |
111 | int idx; | 110 | int idx; |
112 | 111 | ||
113 | read_lock(&dev_base_lock); | ||
114 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { | 112 | for (dev = dev_base, idx = 0; dev; dev = dev->next) { |
115 | /* not a bridge port */ | 113 | /* not a bridge port */ |
116 | if (dev->br_port == NULL || idx < cb->args[0]) | 114 | if (dev->br_port == NULL || idx < cb->args[0]) |
@@ -123,7 +121,6 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | |||
123 | skip: | 121 | skip: |
124 | ++idx; | 122 | ++idx; |
125 | } | 123 | } |
126 | read_unlock(&dev_base_lock); | ||
127 | 124 | ||
128 | cb->args[0] = idx; | 125 | cb->args[0] = idx; |
129 | 126 | ||
@@ -166,7 +163,7 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
166 | return -EINVAL; | 163 | return -EINVAL; |
167 | 164 | ||
168 | /* if kernel STP is running, don't allow changes */ | 165 | /* if kernel STP is running, don't allow changes */ |
169 | if (p->br->stp_enabled) | 166 | if (p->br->stp_enabled == BR_KERNEL_STP) |
170 | return -EBUSY; | 167 | return -EBUSY; |
171 | 168 | ||
172 | if (!netif_running(dev) || | 169 | if (!netif_running(dev) || |
@@ -179,18 +176,19 @@ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
179 | } | 176 | } |
180 | 177 | ||
181 | 178 | ||
182 | static struct rtnetlink_link bridge_rtnetlink_table[RTM_NR_MSGTYPES] = { | 179 | int __init br_netlink_init(void) |
183 | [RTM_GETLINK - RTM_BASE] = { .dumpit = br_dump_ifinfo, }, | ||
184 | [RTM_SETLINK - RTM_BASE] = { .doit = br_rtm_setlink, }, | ||
185 | }; | ||
186 | |||
187 | void __init br_netlink_init(void) | ||
188 | { | 180 | { |
189 | rtnetlink_links[PF_BRIDGE] = bridge_rtnetlink_table; | 181 | if (__rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, br_dump_ifinfo)) |
182 | return -ENOBUFS; | ||
183 | |||
184 | /* Only the first call to __rtnl_register can fail */ | ||
185 | __rtnl_register(PF_BRIDGE, RTM_SETLINK, br_rtm_setlink, NULL); | ||
186 | |||
187 | return 0; | ||
190 | } | 188 | } |
191 | 189 | ||
192 | void __exit br_netlink_fini(void) | 190 | void __exit br_netlink_fini(void) |
193 | { | 191 | { |
194 | rtnetlink_links[PF_BRIDGE] = NULL; | 192 | rtnl_unregister_all(PF_BRIDGE); |
195 | } | 193 | } |
196 | 194 | ||
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 37357ed2149b..c8451d3a070c 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c | |||
@@ -50,7 +50,6 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
50 | case NETDEV_CHANGEADDR: | 50 | case NETDEV_CHANGEADDR: |
51 | spin_lock_bh(&br->lock); | 51 | spin_lock_bh(&br->lock); |
52 | br_fdb_changeaddr(p, dev->dev_addr); | 52 | br_fdb_changeaddr(p, dev->dev_addr); |
53 | br_ifinfo_notify(RTM_NEWLINK, p); | ||
54 | br_stp_recalculate_bridge_id(br); | 53 | br_stp_recalculate_bridge_id(br); |
55 | spin_unlock_bh(&br->lock); | 54 | spin_unlock_bh(&br->lock); |
56 | break; | 55 | break; |
@@ -74,10 +73,11 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
74 | break; | 73 | break; |
75 | 74 | ||
76 | case NETDEV_UP: | 75 | case NETDEV_UP: |
77 | spin_lock_bh(&br->lock); | 76 | if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) { |
78 | if (netif_carrier_ok(dev) && (br->dev->flags & IFF_UP)) | 77 | spin_lock_bh(&br->lock); |
79 | br_stp_enable_port(p); | 78 | br_stp_enable_port(p); |
80 | spin_unlock_bh(&br->lock); | 79 | spin_unlock_bh(&br->lock); |
80 | } | ||
81 | break; | 81 | break; |
82 | 82 | ||
83 | case NETDEV_UNREGISTER: | 83 | case NETDEV_UNREGISTER: |
@@ -85,5 +85,10 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v | |||
85 | break; | 85 | break; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* Events that may cause spanning tree to refresh */ | ||
89 | if (event == NETDEV_CHANGEADDR || event == NETDEV_UP || | ||
90 | event == NETDEV_CHANGE || event == NETDEV_DOWN) | ||
91 | br_ifinfo_notify(RTM_NEWLINK, p); | ||
92 | |||
88 | return NOTIFY_DONE; | 93 | return NOTIFY_DONE; |
89 | } | 94 | } |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index cc3f1c99261a..21bf3a9a03fd 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -26,7 +26,10 @@ | |||
26 | #define BR_PORT_BITS 10 | 26 | #define BR_PORT_BITS 10 |
27 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) | 27 | #define BR_MAX_PORTS (1<<BR_PORT_BITS) |
28 | 28 | ||
29 | #define BR_VERSION "2.2" | 29 | #define BR_VERSION "2.3" |
30 | |||
31 | /* Path to usermode spanning tree program */ | ||
32 | #define BR_STP_PROG "/sbin/bridge-stp" | ||
30 | 33 | ||
31 | typedef struct bridge_id bridge_id; | 34 | typedef struct bridge_id bridge_id; |
32 | typedef struct mac_addr mac_addr; | 35 | typedef struct mac_addr mac_addr; |
@@ -107,7 +110,13 @@ struct net_bridge | |||
107 | 110 | ||
108 | u8 group_addr[ETH_ALEN]; | 111 | u8 group_addr[ETH_ALEN]; |
109 | u16 root_port; | 112 | u16 root_port; |
110 | unsigned char stp_enabled; | 113 | |
114 | enum { | ||
115 | BR_NO_STP, /* no spanning tree */ | ||
116 | BR_KERNEL_STP, /* old STP in kernel */ | ||
117 | BR_USER_STP, /* new RSTP in userspace */ | ||
118 | } stp_enabled; | ||
119 | |||
111 | unsigned char topology_change; | 120 | unsigned char topology_change; |
112 | unsigned char topology_change_detected; | 121 | unsigned char topology_change_detected; |
113 | 122 | ||
@@ -127,14 +136,14 @@ static inline int br_is_root_bridge(const struct net_bridge *br) | |||
127 | return !memcmp(&br->bridge_id, &br->designated_root, 8); | 136 | return !memcmp(&br->bridge_id, &br->designated_root, 8); |
128 | } | 137 | } |
129 | 138 | ||
130 | |||
131 | /* br_device.c */ | 139 | /* br_device.c */ |
132 | extern void br_dev_setup(struct net_device *dev); | 140 | extern void br_dev_setup(struct net_device *dev); |
133 | extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); | 141 | extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev); |
134 | 142 | ||
135 | /* br_fdb.c */ | 143 | /* br_fdb.c */ |
136 | extern void br_fdb_init(void); | 144 | extern int br_fdb_init(void); |
137 | extern void br_fdb_fini(void); | 145 | extern void br_fdb_fini(void); |
146 | extern void br_fdb_flush(struct net_bridge *br); | ||
138 | extern void br_fdb_changeaddr(struct net_bridge_port *p, | 147 | extern void br_fdb_changeaddr(struct net_bridge_port *p, |
139 | const unsigned char *newaddr); | 148 | const unsigned char *newaddr); |
140 | extern void br_fdb_cleanup(unsigned long arg); | 149 | extern void br_fdb_cleanup(unsigned long arg); |
@@ -182,7 +191,8 @@ extern void br_features_recompute(struct net_bridge *br); | |||
182 | 191 | ||
183 | /* br_input.c */ | 192 | /* br_input.c */ |
184 | extern int br_handle_frame_finish(struct sk_buff *skb); | 193 | extern int br_handle_frame_finish(struct sk_buff *skb); |
185 | extern int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb); | 194 | extern struct sk_buff *br_handle_frame(struct net_bridge_port *p, |
195 | struct sk_buff *skb); | ||
186 | 196 | ||
187 | /* br_ioctl.c */ | 197 | /* br_ioctl.c */ |
188 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 198 | extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
@@ -207,6 +217,7 @@ extern void br_become_designated_port(struct net_bridge_port *p); | |||
207 | /* br_stp_if.c */ | 217 | /* br_stp_if.c */ |
208 | extern void br_stp_enable_bridge(struct net_bridge *br); | 218 | extern void br_stp_enable_bridge(struct net_bridge *br); |
209 | extern void br_stp_disable_bridge(struct net_bridge *br); | 219 | extern void br_stp_disable_bridge(struct net_bridge *br); |
220 | extern void br_stp_set_enabled(struct net_bridge *br, unsigned long val); | ||
210 | extern void br_stp_enable_port(struct net_bridge_port *p); | 221 | extern void br_stp_enable_port(struct net_bridge_port *p); |
211 | extern void br_stp_disable_port(struct net_bridge_port *p); | 222 | extern void br_stp_disable_port(struct net_bridge_port *p); |
212 | extern void br_stp_recalculate_bridge_id(struct net_bridge *br); | 223 | extern void br_stp_recalculate_bridge_id(struct net_bridge *br); |
@@ -235,7 +246,7 @@ extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent); | |||
235 | 246 | ||
236 | 247 | ||
237 | /* br_netlink.c */ | 248 | /* br_netlink.c */ |
238 | extern void br_netlink_init(void); | 249 | extern int br_netlink_init(void); |
239 | extern void br_netlink_fini(void); | 250 | extern void br_netlink_fini(void); |
240 | extern void br_ifinfo_notify(int event, struct net_bridge_port *port); | 251 | extern void br_ifinfo_notify(int event, struct net_bridge_port *port); |
241 | 252 | ||
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index f9ff4d57b0d7..ebb0861e9bd5 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c | |||
@@ -370,11 +370,11 @@ static void br_make_blocking(struct net_bridge_port *p) | |||
370 | static void br_make_forwarding(struct net_bridge_port *p) | 370 | static void br_make_forwarding(struct net_bridge_port *p) |
371 | { | 371 | { |
372 | if (p->state == BR_STATE_BLOCKING) { | 372 | if (p->state == BR_STATE_BLOCKING) { |
373 | if (p->br->stp_enabled) { | 373 | if (p->br->stp_enabled == BR_KERNEL_STP) |
374 | p->state = BR_STATE_LISTENING; | 374 | p->state = BR_STATE_LISTENING; |
375 | } else { | 375 | else |
376 | p->state = BR_STATE_LEARNING; | 376 | p->state = BR_STATE_LEARNING; |
377 | } | 377 | |
378 | br_log_state(p); | 378 | br_log_state(p); |
379 | mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); } | 379 | mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay); } |
380 | } | 380 | } |
@@ -384,6 +384,10 @@ void br_port_state_selection(struct net_bridge *br) | |||
384 | { | 384 | { |
385 | struct net_bridge_port *p; | 385 | struct net_bridge_port *p; |
386 | 386 | ||
387 | /* Don't change port states if userspace is handling STP */ | ||
388 | if (br->stp_enabled == BR_USER_STP) | ||
389 | return; | ||
390 | |||
387 | list_for_each_entry(p, &br->port_list, list) { | 391 | list_for_each_entry(p, &br->port_list, list) { |
388 | if (p->state != BR_STATE_DISABLED) { | 392 | if (p->state != BR_STATE_DISABLED) { |
389 | if (p->port_no == br->root_port) { | 393 | if (p->port_no == br->root_port) { |
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index b9fb0dc4ab12..60112bce6698 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -33,9 +33,6 @@ static void br_send_bpdu(struct net_bridge_port *p, | |||
33 | { | 33 | { |
34 | struct sk_buff *skb; | 34 | struct sk_buff *skb; |
35 | 35 | ||
36 | if (!p->br->stp_enabled) | ||
37 | return; | ||
38 | |||
39 | skb = dev_alloc_skb(length+LLC_RESERVE); | 36 | skb = dev_alloc_skb(length+LLC_RESERVE); |
40 | if (!skb) | 37 | if (!skb) |
41 | return; | 38 | return; |
@@ -75,6 +72,9 @@ void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) | |||
75 | { | 72 | { |
76 | unsigned char buf[35]; | 73 | unsigned char buf[35]; |
77 | 74 | ||
75 | if (p->br->stp_enabled != BR_KERNEL_STP) | ||
76 | return; | ||
77 | |||
78 | buf[0] = 0; | 78 | buf[0] = 0; |
79 | buf[1] = 0; | 79 | buf[1] = 0; |
80 | buf[2] = 0; | 80 | buf[2] = 0; |
@@ -117,6 +117,9 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) | |||
117 | { | 117 | { |
118 | unsigned char buf[4]; | 118 | unsigned char buf[4]; |
119 | 119 | ||
120 | if (p->br->stp_enabled != BR_KERNEL_STP) | ||
121 | return; | ||
122 | |||
120 | buf[0] = 0; | 123 | buf[0] = 0; |
121 | buf[1] = 0; | 124 | buf[1] = 0; |
122 | buf[2] = 0; | 125 | buf[2] = 0; |
@@ -157,9 +160,13 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, | |||
157 | br = p->br; | 160 | br = p->br; |
158 | spin_lock(&br->lock); | 161 | spin_lock(&br->lock); |
159 | 162 | ||
160 | if (p->state == BR_STATE_DISABLED | 163 | if (br->stp_enabled != BR_KERNEL_STP) |
161 | || !br->stp_enabled | 164 | goto out; |
162 | || !(br->dev->flags & IFF_UP)) | 165 | |
166 | if (!(br->dev->flags & IFF_UP)) | ||
167 | goto out; | ||
168 | |||
169 | if (p->state == BR_STATE_DISABLED) | ||
163 | goto out; | 170 | goto out; |
164 | 171 | ||
165 | if (compare_ether_addr(dest, br->group_addr) != 0) | 172 | if (compare_ether_addr(dest, br->group_addr) != 0) |
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index a285897a2fb4..3e246b37020e 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -87,7 +87,6 @@ void br_stp_disable_bridge(struct net_bridge *br) | |||
87 | void br_stp_enable_port(struct net_bridge_port *p) | 87 | void br_stp_enable_port(struct net_bridge_port *p) |
88 | { | 88 | { |
89 | br_init_port(p); | 89 | br_init_port(p); |
90 | br_ifinfo_notify(RTM_NEWLINK, p); | ||
91 | br_port_state_selection(p->br); | 90 | br_port_state_selection(p->br); |
92 | } | 91 | } |
93 | 92 | ||
@@ -101,8 +100,6 @@ void br_stp_disable_port(struct net_bridge_port *p) | |||
101 | printk(KERN_INFO "%s: port %i(%s) entering %s state\n", | 100 | printk(KERN_INFO "%s: port %i(%s) entering %s state\n", |
102 | br->dev->name, p->port_no, p->dev->name, "disabled"); | 101 | br->dev->name, p->port_no, p->dev->name, "disabled"); |
103 | 102 | ||
104 | br_ifinfo_notify(RTM_DELLINK, p); | ||
105 | |||
106 | wasroot = br_is_root_bridge(br); | 103 | wasroot = br_is_root_bridge(br); |
107 | br_become_designated_port(p); | 104 | br_become_designated_port(p); |
108 | p->state = BR_STATE_DISABLED; | 105 | p->state = BR_STATE_DISABLED; |
@@ -123,6 +120,62 @@ void br_stp_disable_port(struct net_bridge_port *p) | |||
123 | br_become_root_bridge(br); | 120 | br_become_root_bridge(br); |
124 | } | 121 | } |
125 | 122 | ||
123 | static void br_stp_start(struct net_bridge *br) | ||
124 | { | ||
125 | int r; | ||
126 | char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL }; | ||
127 | char *envp[] = { NULL }; | ||
128 | |||
129 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | ||
130 | if (r == 0) { | ||
131 | br->stp_enabled = BR_USER_STP; | ||
132 | printk(KERN_INFO "%s: userspace STP started\n", br->dev->name); | ||
133 | } else { | ||
134 | br->stp_enabled = BR_KERNEL_STP; | ||
135 | printk(KERN_INFO "%s: starting userspace STP failed, " | ||
136 | "staring kernel STP\n", br->dev->name); | ||
137 | |||
138 | /* To start timers on any ports left in blocking */ | ||
139 | spin_lock_bh(&br->lock); | ||
140 | br_port_state_selection(br); | ||
141 | spin_unlock_bh(&br->lock); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static void br_stp_stop(struct net_bridge *br) | ||
146 | { | ||
147 | int r; | ||
148 | char *argv[] = { BR_STP_PROG, br->dev->name, "stop", NULL }; | ||
149 | char *envp[] = { NULL }; | ||
150 | |||
151 | if (br->stp_enabled == BR_USER_STP) { | ||
152 | r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); | ||
153 | printk(KERN_INFO "%s: userspace STP stopped, return code %d\n", | ||
154 | br->dev->name, r); | ||
155 | |||
156 | |||
157 | /* To start timers on any ports left in blocking */ | ||
158 | spin_lock_bh(&br->lock); | ||
159 | br_port_state_selection(br); | ||
160 | spin_unlock_bh(&br->lock); | ||
161 | } | ||
162 | |||
163 | br->stp_enabled = BR_NO_STP; | ||
164 | } | ||
165 | |||
166 | void br_stp_set_enabled(struct net_bridge *br, unsigned long val) | ||
167 | { | ||
168 | ASSERT_RTNL(); | ||
169 | |||
170 | if (val) { | ||
171 | if (br->stp_enabled == BR_NO_STP) | ||
172 | br_stp_start(br); | ||
173 | } else { | ||
174 | if (br->stp_enabled != BR_NO_STP) | ||
175 | br_stp_stop(br); | ||
176 | } | ||
177 | } | ||
178 | |||
126 | /* called under bridge lock */ | 179 | /* called under bridge lock */ |
127 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) | 180 | void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr) |
128 | { | 181 | { |
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 01a22ad0cc75..33c6c4a7c689 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -149,7 +149,11 @@ static ssize_t show_stp_state(struct device *d, | |||
149 | 149 | ||
150 | static void set_stp_state(struct net_bridge *br, unsigned long val) | 150 | static void set_stp_state(struct net_bridge *br, unsigned long val) |
151 | { | 151 | { |
152 | br->stp_enabled = val; | 152 | rtnl_lock(); |
153 | spin_unlock_bh(&br->lock); | ||
154 | br_stp_set_enabled(br, val); | ||
155 | spin_lock_bh(&br->lock); | ||
156 | rtnl_unlock(); | ||
153 | } | 157 | } |
154 | 158 | ||
155 | static ssize_t store_stp_state(struct device *d, | 159 | static ssize_t store_stp_state(struct device *d, |
@@ -309,6 +313,19 @@ static ssize_t store_group_addr(struct device *d, | |||
309 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, | 313 | static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, |
310 | show_group_addr, store_group_addr); | 314 | show_group_addr, store_group_addr); |
311 | 315 | ||
316 | static ssize_t store_flush(struct device *d, | ||
317 | struct device_attribute *attr, | ||
318 | const char *buf, size_t len) | ||
319 | { | ||
320 | struct net_bridge *br = to_bridge(d); | ||
321 | |||
322 | if (!capable(CAP_NET_ADMIN)) | ||
323 | return -EPERM; | ||
324 | |||
325 | br_fdb_flush(br); | ||
326 | return len; | ||
327 | } | ||
328 | static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush); | ||
312 | 329 | ||
313 | static struct attribute *bridge_attrs[] = { | 330 | static struct attribute *bridge_attrs[] = { |
314 | &dev_attr_forward_delay.attr, | 331 | &dev_attr_forward_delay.attr, |
@@ -328,6 +345,7 @@ static struct attribute *bridge_attrs[] = { | |||
328 | &dev_attr_topology_change_timer.attr, | 345 | &dev_attr_topology_change_timer.attr, |
329 | &dev_attr_gc_timer.attr, | 346 | &dev_attr_gc_timer.attr, |
330 | &dev_attr_group_addr.attr, | 347 | &dev_attr_group_addr.attr, |
348 | &dev_attr_flush.attr, | ||
331 | NULL | 349 | NULL |
332 | }; | 350 | }; |
333 | 351 | ||
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 0bc2aef8f9f3..2da22927d8dd 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c | |||
@@ -137,6 +137,13 @@ static ssize_t show_hold_timer(struct net_bridge_port *p, | |||
137 | } | 137 | } |
138 | static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); | 138 | static BRPORT_ATTR(hold_timer, S_IRUGO, show_hold_timer, NULL); |
139 | 139 | ||
140 | static ssize_t store_flush(struct net_bridge_port *p, unsigned long v) | ||
141 | { | ||
142 | br_fdb_delete_by_port(p->br, p, 0); // Don't delete local entry | ||
143 | return 0; | ||
144 | } | ||
145 | static BRPORT_ATTR(flush, S_IWUSR, NULL, store_flush); | ||
146 | |||
140 | static struct brport_attribute *brport_attrs[] = { | 147 | static struct brport_attribute *brport_attrs[] = { |
141 | &brport_attr_path_cost, | 148 | &brport_attr_path_cost, |
142 | &brport_attr_priority, | 149 | &brport_attr_priority, |
@@ -152,6 +159,7 @@ static struct brport_attribute *brport_attrs[] = { | |||
152 | &brport_attr_message_age_timer, | 159 | &brport_attr_message_age_timer, |
153 | &brport_attr_forward_delay_timer, | 160 | &brport_attr_forward_delay_timer, |
154 | &brport_attr_hold_timer, | 161 | &brport_attr_hold_timer, |
162 | &brport_attr_flush, | ||
155 | NULL | 163 | NULL |
156 | }; | 164 | }; |
157 | 165 | ||
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index 9c599800a900..1a46952a56d9 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c | |||
@@ -35,40 +35,36 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in | |||
35 | return EBT_NOMATCH; | 35 | return EBT_NOMATCH; |
36 | 36 | ||
37 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { | 37 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { |
38 | __be32 _addr, *ap; | 38 | __be32 saddr, daddr, *sap, *dap; |
39 | 39 | ||
40 | /* IPv4 addresses are always 4 bytes */ | 40 | if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP)) |
41 | if (ah->ar_pln != sizeof(__be32)) | 41 | return EBT_NOMATCH; |
42 | sap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
43 | ah->ar_hln, sizeof(saddr), | ||
44 | &saddr); | ||
45 | if (sap == NULL) | ||
46 | return EBT_NOMATCH; | ||
47 | dap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
48 | 2*ah->ar_hln+sizeof(saddr), | ||
49 | sizeof(daddr), &daddr); | ||
50 | if (dap == NULL) | ||
51 | return EBT_NOMATCH; | ||
52 | if (info->bitmask & EBT_ARP_SRC_IP && | ||
53 | FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) | ||
54 | return EBT_NOMATCH; | ||
55 | if (info->bitmask & EBT_ARP_DST_IP && | ||
56 | FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) | ||
57 | return EBT_NOMATCH; | ||
58 | if (info->bitmask & EBT_ARP_GRAT && | ||
59 | FWINV(*dap != *sap, EBT_ARP_GRAT)) | ||
42 | return EBT_NOMATCH; | 60 | return EBT_NOMATCH; |
43 | if (info->bitmask & EBT_ARP_SRC_IP) { | ||
44 | ap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
45 | ah->ar_hln, sizeof(_addr), | ||
46 | &_addr); | ||
47 | if (ap == NULL) | ||
48 | return EBT_NOMATCH; | ||
49 | if (FWINV(info->saddr != (*ap & info->smsk), | ||
50 | EBT_ARP_SRC_IP)) | ||
51 | return EBT_NOMATCH; | ||
52 | } | ||
53 | |||
54 | if (info->bitmask & EBT_ARP_DST_IP) { | ||
55 | ap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
56 | 2*ah->ar_hln+sizeof(__be32), | ||
57 | sizeof(_addr), &_addr); | ||
58 | if (ap == NULL) | ||
59 | return EBT_NOMATCH; | ||
60 | if (FWINV(info->daddr != (*ap & info->dmsk), | ||
61 | EBT_ARP_DST_IP)) | ||
62 | return EBT_NOMATCH; | ||
63 | } | ||
64 | } | 61 | } |
65 | 62 | ||
66 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { | 63 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { |
67 | unsigned char _mac[ETH_ALEN], *mp; | 64 | unsigned char _mac[ETH_ALEN], *mp; |
68 | uint8_t verdict, i; | 65 | uint8_t verdict, i; |
69 | 66 | ||
70 | /* MAC addresses are 6 bytes */ | 67 | if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) |
71 | if (ah->ar_hln != ETH_ALEN) | ||
72 | return EBT_NOMATCH; | 68 | return EBT_NOMATCH; |
73 | if (info->bitmask & EBT_ARP_SRC_MAC) { | 69 | if (info->bitmask & EBT_ARP_SRC_MAC) { |
74 | mp = skb_header_pointer(skb, sizeof(struct arphdr), | 70 | mp = skb_header_pointer(skb, sizeof(struct arphdr), |
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 45712aec6a0e..031bfa4a51fc 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c | |||
@@ -196,14 +196,10 @@ static int __init ebt_log_init(void) | |||
196 | ret = ebt_register_watcher(&log); | 196 | ret = ebt_register_watcher(&log); |
197 | if (ret < 0) | 197 | if (ret < 0) |
198 | return ret; | 198 | return ret; |
199 | if (nf_log_register(PF_BRIDGE, &ebt_log_logger) < 0) { | 199 | ret = nf_log_register(PF_BRIDGE, &ebt_log_logger); |
200 | printk(KERN_WARNING "ebt_log: not logging via system console " | 200 | if (ret < 0 && ret != -EEXIST) |
201 | "since somebody else already registered for PF_INET\n"); | 201 | ebt_unregister_watcher(&log); |
202 | /* we cannot make module load fail here, since otherwise | 202 | return ret; |
203 | * ebtables userspace would abort */ | ||
204 | } | ||
205 | |||
206 | return 0; | ||
207 | } | 203 | } |
208 | 204 | ||
209 | static void __exit ebt_log_fini(void) | 205 | static void __exit ebt_log_fini(void) |
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 8e15cc47f6c0..9411db625917 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -130,6 +130,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
130 | unsigned int group = uloginfo->nlgroup; | 130 | unsigned int group = uloginfo->nlgroup; |
131 | ebt_ulog_buff_t *ub = &ulog_buffers[group]; | 131 | ebt_ulog_buff_t *ub = &ulog_buffers[group]; |
132 | spinlock_t *lock = &ub->lock; | 132 | spinlock_t *lock = &ub->lock; |
133 | ktime_t kt; | ||
133 | 134 | ||
134 | if ((uloginfo->cprange == 0) || | 135 | if ((uloginfo->cprange == 0) || |
135 | (uloginfo->cprange > skb->len + ETH_HLEN)) | 136 | (uloginfo->cprange > skb->len + ETH_HLEN)) |
@@ -164,9 +165,10 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
164 | 165 | ||
165 | /* Fill in the ulog data */ | 166 | /* Fill in the ulog data */ |
166 | pm->version = EBT_ULOG_VERSION; | 167 | pm->version = EBT_ULOG_VERSION; |
167 | do_gettimeofday(&pm->stamp); | 168 | kt = ktime_get_real(); |
169 | pm->stamp = ktime_to_timeval(kt); | ||
168 | if (ub->qlen == 1) | 170 | if (ub->qlen == 1) |
169 | skb_set_timestamp(ub->skb, &pm->stamp); | 171 | ub->skb->tstamp = kt; |
170 | pm->data_len = copy_len; | 172 | pm->data_len = copy_len; |
171 | pm->mark = skb->mark; | 173 | pm->mark = skb->mark; |
172 | pm->hook = hooknr; | 174 | pm->hook = hooknr; |
@@ -295,14 +297,12 @@ static int __init ebt_ulog_init(void) | |||
295 | 297 | ||
296 | /* initialize ulog_buffers */ | 298 | /* initialize ulog_buffers */ |
297 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | 299 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { |
298 | init_timer(&ulog_buffers[i].timer); | 300 | setup_timer(&ulog_buffers[i].timer, ulog_timer, i); |
299 | ulog_buffers[i].timer.function = ulog_timer; | ||
300 | ulog_buffers[i].timer.data = i; | ||
301 | spin_lock_init(&ulog_buffers[i].lock); | 301 | spin_lock_init(&ulog_buffers[i].lock); |
302 | } | 302 | } |
303 | 303 | ||
304 | ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS, | 304 | ebtulognl = netlink_kernel_create(NETLINK_NFLOG, EBT_ULOG_MAXNLGROUPS, |
305 | NULL, THIS_MODULE); | 305 | NULL, NULL, THIS_MODULE); |
306 | if (!ebtulognl) | 306 | if (!ebtulognl) |
307 | ret = -ENOMEM; | 307 | ret = -ENOMEM; |
308 | else if ((ret = ebt_register_watcher(&ulog))) | 308 | else if ((ret = ebt_register_watcher(&ulog))) |