diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-02 00:33:06 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-02 00:33:06 -0500 |
commit | f98e85691bbbca1e72f8bfe9dfee2639e8545790 (patch) | |
tree | 0b7071e72c6b553dd7ccbed4906954c313ca7b61 | |
parent | ec33b309101bb2904e9fe20252f7760e254d05ec (diff) | |
parent | 97300b5fdfe28c6edae926926f9467a27cf5889c (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6
-rw-r--r-- | include/linux/netfilter_arp/arp_tables.h | 20 | ||||
-rw-r--r-- | include/linux/netfilter_ipv6/ip6_tables.h | 27 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 12 | ||||
-rw-r--r-- | net/bridge/br_input.c | 2 | ||||
-rw-r--r-- | net/bridge/br_stp_if.c | 9 | ||||
-rw-r--r-- | net/dccp/dccp.h | 1 | ||||
-rw-r--r-- | net/dccp/output.c | 34 | ||||
-rw-r--r-- | net/ipv4/netfilter/arp_tables.c | 201 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 19 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 298 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_MARK.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 2 | ||||
-rw-r--r-- | net/rose/rose_timer.c | 1 |
13 files changed, 415 insertions, 219 deletions
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index d759a637bded..e98a870a20be 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h | |||
@@ -68,7 +68,8 @@ struct arpt_entry_target | |||
68 | u_int16_t target_size; | 68 | u_int16_t target_size; |
69 | 69 | ||
70 | /* Used by userspace */ | 70 | /* Used by userspace */ |
71 | char name[ARPT_FUNCTION_MAXNAMELEN]; | 71 | char name[ARPT_FUNCTION_MAXNAMELEN-1]; |
72 | u_int8_t revision; | ||
72 | } user; | 73 | } user; |
73 | struct { | 74 | struct { |
74 | u_int16_t target_size; | 75 | u_int16_t target_size; |
@@ -148,7 +149,9 @@ struct arpt_entry | |||
148 | 149 | ||
149 | #define ARPT_SO_GET_INFO (ARPT_BASE_CTL) | 150 | #define ARPT_SO_GET_INFO (ARPT_BASE_CTL) |
150 | #define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) | 151 | #define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) |
151 | #define ARPT_SO_GET_MAX ARPT_SO_GET_ENTRIES | 152 | /* #define ARPT_SO_GET_REVISION_MATCH (ARPT_BASE_CTL + 2)*/ |
153 | #define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3) | ||
154 | #define ARPT_SO_GET_MAX ARPT_SO_GET_REVISION_TARGET | ||
152 | 155 | ||
153 | /* CONTINUE verdict for targets */ | 156 | /* CONTINUE verdict for targets */ |
154 | #define ARPT_CONTINUE 0xFFFFFFFF | 157 | #define ARPT_CONTINUE 0xFFFFFFFF |
@@ -236,6 +239,15 @@ struct arpt_get_entries | |||
236 | struct arpt_entry entrytable[0]; | 239 | struct arpt_entry entrytable[0]; |
237 | }; | 240 | }; |
238 | 241 | ||
242 | /* The argument to ARPT_SO_GET_REVISION_*. Returns highest revision | ||
243 | * kernel supports, if >= revision. */ | ||
244 | struct arpt_get_revision | ||
245 | { | ||
246 | char name[ARPT_FUNCTION_MAXNAMELEN-1]; | ||
247 | |||
248 | u_int8_t revision; | ||
249 | }; | ||
250 | |||
239 | /* Standard return verdict, or do jump. */ | 251 | /* Standard return verdict, or do jump. */ |
240 | #define ARPT_STANDARD_TARGET "" | 252 | #define ARPT_STANDARD_TARGET "" |
241 | /* Error verdict. */ | 253 | /* Error verdict. */ |
@@ -274,7 +286,9 @@ struct arpt_target | |||
274 | { | 286 | { |
275 | struct list_head list; | 287 | struct list_head list; |
276 | 288 | ||
277 | const char name[ARPT_FUNCTION_MAXNAMELEN]; | 289 | const char name[ARPT_FUNCTION_MAXNAMELEN-1]; |
290 | |||
291 | u_int8_t revision; | ||
278 | 292 | ||
279 | /* Returns verdict. */ | 293 | /* Returns verdict. */ |
280 | unsigned int (*target)(struct sk_buff **pskb, | 294 | unsigned int (*target)(struct sk_buff **pskb, |
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 59f70b34e029..2efc046d9e94 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -57,7 +57,8 @@ struct ip6t_entry_match | |||
57 | u_int16_t match_size; | 57 | u_int16_t match_size; |
58 | 58 | ||
59 | /* Used by userspace */ | 59 | /* Used by userspace */ |
60 | char name[IP6T_FUNCTION_MAXNAMELEN]; | 60 | char name[IP6T_FUNCTION_MAXNAMELEN-1]; |
61 | u_int8_t revision; | ||
61 | } user; | 62 | } user; |
62 | struct { | 63 | struct { |
63 | u_int16_t match_size; | 64 | u_int16_t match_size; |
@@ -80,7 +81,8 @@ struct ip6t_entry_target | |||
80 | u_int16_t target_size; | 81 | u_int16_t target_size; |
81 | 82 | ||
82 | /* Used by userspace */ | 83 | /* Used by userspace */ |
83 | char name[IP6T_FUNCTION_MAXNAMELEN]; | 84 | char name[IP6T_FUNCTION_MAXNAMELEN-1]; |
85 | u_int8_t revision; | ||
84 | } user; | 86 | } user; |
85 | struct { | 87 | struct { |
86 | u_int16_t target_size; | 88 | u_int16_t target_size; |
@@ -161,7 +163,9 @@ struct ip6t_entry | |||
161 | 163 | ||
162 | #define IP6T_SO_GET_INFO (IP6T_BASE_CTL) | 164 | #define IP6T_SO_GET_INFO (IP6T_BASE_CTL) |
163 | #define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) | 165 | #define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) |
164 | #define IP6T_SO_GET_MAX IP6T_SO_GET_ENTRIES | 166 | #define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 2) |
167 | #define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 3) | ||
168 | #define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET | ||
165 | 169 | ||
166 | /* CONTINUE verdict for targets */ | 170 | /* CONTINUE verdict for targets */ |
167 | #define IP6T_CONTINUE 0xFFFFFFFF | 171 | #define IP6T_CONTINUE 0xFFFFFFFF |
@@ -291,6 +295,15 @@ struct ip6t_get_entries | |||
291 | struct ip6t_entry entrytable[0]; | 295 | struct ip6t_entry entrytable[0]; |
292 | }; | 296 | }; |
293 | 297 | ||
298 | /* The argument to IP6T_SO_GET_REVISION_*. Returns highest revision | ||
299 | * kernel supports, if >= revision. */ | ||
300 | struct ip6t_get_revision | ||
301 | { | ||
302 | char name[IP6T_FUNCTION_MAXNAMELEN-1]; | ||
303 | |||
304 | u_int8_t revision; | ||
305 | }; | ||
306 | |||
294 | /* Standard return verdict, or do jump. */ | 307 | /* Standard return verdict, or do jump. */ |
295 | #define IP6T_STANDARD_TARGET "" | 308 | #define IP6T_STANDARD_TARGET "" |
296 | /* Error verdict. */ | 309 | /* Error verdict. */ |
@@ -352,7 +365,9 @@ struct ip6t_match | |||
352 | { | 365 | { |
353 | struct list_head list; | 366 | struct list_head list; |
354 | 367 | ||
355 | const char name[IP6T_FUNCTION_MAXNAMELEN]; | 368 | const char name[IP6T_FUNCTION_MAXNAMELEN-1]; |
369 | |||
370 | u_int8_t revision; | ||
356 | 371 | ||
357 | /* Return true or false: return FALSE and set *hotdrop = 1 to | 372 | /* Return true or false: return FALSE and set *hotdrop = 1 to |
358 | force immediate packet drop. */ | 373 | force immediate packet drop. */ |
@@ -387,7 +402,9 @@ struct ip6t_target | |||
387 | { | 402 | { |
388 | struct list_head list; | 403 | struct list_head list; |
389 | 404 | ||
390 | const char name[IP6T_FUNCTION_MAXNAMELEN]; | 405 | const char name[IP6T_FUNCTION_MAXNAMELEN-1]; |
406 | |||
407 | u_int8_t revision; | ||
391 | 408 | ||
392 | /* Returns verdict. Argument order changed since 2.6.9, as this | 409 | /* Returns verdict. Argument order changed since 2.6.9, as this |
393 | must now handle non-linear skbs, using skb_copy_bits and | 410 | must now handle non-linear skbs, using skb_copy_bits and |
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 24396b914d11..1f08a59b51ea 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -86,8 +86,8 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) | |||
86 | struct net_bridge_port *op; | 86 | struct net_bridge_port *op; |
87 | list_for_each_entry(op, &br->port_list, list) { | 87 | list_for_each_entry(op, &br->port_list, list) { |
88 | if (op != p && | 88 | if (op != p && |
89 | !memcmp(op->dev->dev_addr, | 89 | !compare_ether_addr(op->dev->dev_addr, |
90 | f->addr.addr, ETH_ALEN)) { | 90 | f->addr.addr)) { |
91 | f->dst = op; | 91 | f->dst = op; |
92 | goto insert; | 92 | goto insert; |
93 | } | 93 | } |
@@ -151,8 +151,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) | |||
151 | struct net_bridge_port *op; | 151 | struct net_bridge_port *op; |
152 | list_for_each_entry(op, &br->port_list, list) { | 152 | list_for_each_entry(op, &br->port_list, list) { |
153 | if (op != p && | 153 | if (op != p && |
154 | !memcmp(op->dev->dev_addr, | 154 | !compare_ether_addr(op->dev->dev_addr, |
155 | f->addr.addr, ETH_ALEN)) { | 155 | f->addr.addr)) { |
156 | f->dst = op; | 156 | f->dst = op; |
157 | goto skip_delete; | 157 | goto skip_delete; |
158 | } | 158 | } |
@@ -174,7 +174,7 @@ struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | |||
174 | struct net_bridge_fdb_entry *fdb; | 174 | struct net_bridge_fdb_entry *fdb; |
175 | 175 | ||
176 | hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { | 176 | hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { |
177 | if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { | 177 | if (!compare_ether_addr(fdb->addr.addr, addr)) { |
178 | if (unlikely(has_expired(br, fdb))) | 178 | if (unlikely(has_expired(br, fdb))) |
179 | break; | 179 | break; |
180 | return fdb; | 180 | return fdb; |
@@ -264,7 +264,7 @@ static inline struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head, | |||
264 | struct net_bridge_fdb_entry *fdb; | 264 | struct net_bridge_fdb_entry *fdb; |
265 | 265 | ||
266 | hlist_for_each_entry_rcu(fdb, h, head, hlist) { | 266 | hlist_for_each_entry_rcu(fdb, h, head, hlist) { |
267 | if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) | 267 | if (!compare_ether_addr(fdb->addr.addr, addr)) |
268 | return fdb; | 268 | return fdb; |
269 | } | 269 | } |
270 | return NULL; | 270 | return NULL; |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 9a45e6279c57..b88220a64cd8 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -128,7 +128,7 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) | |||
128 | dest = eth_hdr(skb)->h_dest; | 128 | dest = eth_hdr(skb)->h_dest; |
129 | } | 129 | } |
130 | 130 | ||
131 | if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN)) | 131 | if (!compare_ether_addr(p->br->dev->dev_addr, dest)) |
132 | skb->pkt_type = PACKET_HOST; | 132 | skb->pkt_type = PACKET_HOST; |
133 | 133 | ||
134 | NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, | 134 | NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, |
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 0da11ff05fa3..ac09b6a23523 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/smp_lock.h> | 17 | #include <linux/smp_lock.h> |
18 | #include <linux/etherdevice.h> | ||
18 | 19 | ||
19 | #include "br_private.h" | 20 | #include "br_private.h" |
20 | #include "br_private_stp.h" | 21 | #include "br_private_stp.h" |
@@ -133,10 +134,10 @@ static void br_stp_change_bridge_id(struct net_bridge *br, | |||
133 | memcpy(br->dev->dev_addr, addr, ETH_ALEN); | 134 | memcpy(br->dev->dev_addr, addr, ETH_ALEN); |
134 | 135 | ||
135 | list_for_each_entry(p, &br->port_list, list) { | 136 | list_for_each_entry(p, &br->port_list, list) { |
136 | if (!memcmp(p->designated_bridge.addr, oldaddr, ETH_ALEN)) | 137 | if (!compare_ether_addr(p->designated_bridge.addr, oldaddr)) |
137 | memcpy(p->designated_bridge.addr, addr, ETH_ALEN); | 138 | memcpy(p->designated_bridge.addr, addr, ETH_ALEN); |
138 | 139 | ||
139 | if (!memcmp(p->designated_root.addr, oldaddr, ETH_ALEN)) | 140 | if (!compare_ether_addr(p->designated_root.addr, oldaddr)) |
140 | memcpy(p->designated_root.addr, addr, ETH_ALEN); | 141 | memcpy(p->designated_root.addr, addr, ETH_ALEN); |
141 | 142 | ||
142 | } | 143 | } |
@@ -157,12 +158,12 @@ void br_stp_recalculate_bridge_id(struct net_bridge *br) | |||
157 | 158 | ||
158 | list_for_each_entry(p, &br->port_list, list) { | 159 | list_for_each_entry(p, &br->port_list, list) { |
159 | if (addr == br_mac_zero || | 160 | if (addr == br_mac_zero || |
160 | memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) | 161 | compare_ether_addr(p->dev->dev_addr, addr) < 0) |
161 | addr = p->dev->dev_addr; | 162 | addr = p->dev->dev_addr; |
162 | 163 | ||
163 | } | 164 | } |
164 | 165 | ||
165 | if (memcmp(br->bridge_id.addr, addr, ETH_ALEN)) | 166 | if (compare_ether_addr(br->bridge_id.addr, addr)) |
166 | br_stp_change_bridge_id(br, addr); | 167 | br_stp_change_bridge_id(br, addr); |
167 | } | 168 | } |
168 | 169 | ||
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 5871c027f9dc..f97b85d55ad8 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -118,7 +118,6 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics); | |||
118 | #define DCCP_ADD_STATS_USER(field, val) \ | 118 | #define DCCP_ADD_STATS_USER(field, val) \ |
119 | SNMP_ADD_STATS_USER(dccp_statistics, field, val) | 119 | SNMP_ADD_STATS_USER(dccp_statistics, field, val) |
120 | 120 | ||
121 | extern int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb); | ||
122 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); | 121 | extern int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb); |
123 | 122 | ||
124 | extern int dccp_send_response(struct sock *sk); | 123 | extern int dccp_send_response(struct sock *sk); |
diff --git a/net/dccp/output.c b/net/dccp/output.c index d59f86f7ceab..74ff87025878 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <linux/dccp.h> | 14 | #include <linux/dccp.h> |
15 | #include <linux/kernel.h> | ||
15 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
16 | 17 | ||
17 | #include <net/sock.h> | 18 | #include <net/sock.h> |
@@ -25,13 +26,20 @@ static inline void dccp_event_ack_sent(struct sock *sk) | |||
25 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); | 26 | inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); |
26 | } | 27 | } |
27 | 28 | ||
29 | static inline void dccp_skb_entail(struct sock *sk, struct sk_buff *skb) | ||
30 | { | ||
31 | skb_set_owner_w(skb, sk); | ||
32 | WARN_ON(sk->sk_send_head); | ||
33 | sk->sk_send_head = skb; | ||
34 | } | ||
35 | |||
28 | /* | 36 | /* |
29 | * All SKB's seen here are completely headerless. It is our | 37 | * All SKB's seen here are completely headerless. It is our |
30 | * job to build the DCCP header, and pass the packet down to | 38 | * job to build the DCCP header, and pass the packet down to |
31 | * IP so it can do the same plus pass the packet off to the | 39 | * IP so it can do the same plus pass the packet off to the |
32 | * device. | 40 | * device. |
33 | */ | 41 | */ |
34 | int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | 42 | static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) |
35 | { | 43 | { |
36 | if (likely(skb != NULL)) { | 44 | if (likely(skb != NULL)) { |
37 | const struct inet_sock *inet = inet_sk(sk); | 45 | const struct inet_sock *inet = inet_sk(sk); |
@@ -50,10 +58,21 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
50 | switch (dcb->dccpd_type) { | 58 | switch (dcb->dccpd_type) { |
51 | case DCCP_PKT_DATA: | 59 | case DCCP_PKT_DATA: |
52 | set_ack = 0; | 60 | set_ack = 0; |
61 | /* fall through */ | ||
62 | case DCCP_PKT_DATAACK: | ||
53 | break; | 63 | break; |
64 | |||
54 | case DCCP_PKT_SYNC: | 65 | case DCCP_PKT_SYNC: |
55 | case DCCP_PKT_SYNCACK: | 66 | case DCCP_PKT_SYNCACK: |
56 | ackno = dcb->dccpd_seq; | 67 | ackno = dcb->dccpd_seq; |
68 | /* fall through */ | ||
69 | default: | ||
70 | /* | ||
71 | * Only data packets should come through with skb->sk | ||
72 | * set. | ||
73 | */ | ||
74 | WARN_ON(skb->sk); | ||
75 | skb_set_owner_w(skb, sk); | ||
57 | break; | 76 | break; |
58 | } | 77 | } |
59 | 78 | ||
@@ -63,9 +82,6 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) | |||
63 | skb->h.raw = skb_push(skb, dccp_header_size); | 82 | skb->h.raw = skb_push(skb, dccp_header_size); |
64 | dh = dccp_hdr(skb); | 83 | dh = dccp_hdr(skb); |
65 | 84 | ||
66 | if (!skb->sk) | ||
67 | skb_set_owner_w(skb, sk); | ||
68 | |||
69 | /* Build DCCP header and checksum it. */ | 85 | /* Build DCCP header and checksum it. */ |
70 | memset(dh, 0, dccp_header_size); | 86 | memset(dh, 0, dccp_header_size); |
71 | dh->dccph_type = dcb->dccpd_type; | 87 | dh->dccph_type = dcb->dccpd_type; |
@@ -393,10 +409,8 @@ int dccp_connect(struct sock *sk) | |||
393 | 409 | ||
394 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; | 410 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; |
395 | skb->csum = 0; | 411 | skb->csum = 0; |
396 | skb_set_owner_w(skb, sk); | ||
397 | 412 | ||
398 | BUG_TRAP(sk->sk_send_head == NULL); | 413 | dccp_skb_entail(sk, skb); |
399 | sk->sk_send_head = skb; | ||
400 | dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)); | 414 | dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL)); |
401 | DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS); | 415 | DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS); |
402 | 416 | ||
@@ -425,7 +439,6 @@ void dccp_send_ack(struct sock *sk) | |||
425 | skb_reserve(skb, MAX_DCCP_HEADER); | 439 | skb_reserve(skb, MAX_DCCP_HEADER); |
426 | skb->csum = 0; | 440 | skb->csum = 0; |
427 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; | 441 | DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK; |
428 | skb_set_owner_w(skb, sk); | ||
429 | dccp_transmit_skb(sk, skb); | 442 | dccp_transmit_skb(sk, skb); |
430 | } | 443 | } |
431 | } | 444 | } |
@@ -482,7 +495,6 @@ void dccp_send_sync(struct sock *sk, const u64 seq, | |||
482 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; | 495 | DCCP_SKB_CB(skb)->dccpd_type = pkt_type; |
483 | DCCP_SKB_CB(skb)->dccpd_seq = seq; | 496 | DCCP_SKB_CB(skb)->dccpd_seq = seq; |
484 | 497 | ||
485 | skb_set_owner_w(skb, sk); | ||
486 | dccp_transmit_skb(sk, skb); | 498 | dccp_transmit_skb(sk, skb); |
487 | } | 499 | } |
488 | 500 | ||
@@ -507,10 +519,8 @@ void dccp_send_close(struct sock *sk, const int active) | |||
507 | DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? | 519 | DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ? |
508 | DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; | 520 | DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ; |
509 | 521 | ||
510 | skb_set_owner_w(skb, sk); | ||
511 | if (active) { | 522 | if (active) { |
512 | BUG_TRAP(sk->sk_send_head == NULL); | 523 | dccp_skb_entail(sk, skb); |
513 | sk->sk_send_head = skb; | ||
514 | dccp_transmit_skb(sk, skb_clone(skb, prio)); | 524 | dccp_transmit_skb(sk, skb_clone(skb, prio)); |
515 | } else | 525 | } else |
516 | dccp_transmit_skb(sk, skb); | 526 | dccp_transmit_skb(sk, skb); |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index a7969286e6e7..3c2e9639bba6 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -347,58 +347,106 @@ unsigned int arpt_do_table(struct sk_buff **pskb, | |||
347 | return verdict; | 347 | return verdict; |
348 | } | 348 | } |
349 | 349 | ||
350 | static inline void *find_inlist_lock_noload(struct list_head *head, | 350 | /* |
351 | const char *name, | 351 | * These are weird, but module loading must not be done with mutex |
352 | int *error, | 352 | * held (since they will register), and we have to have a single |
353 | struct semaphore *mutex) | 353 | * function to use try_then_request_module(). |
354 | */ | ||
355 | |||
356 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ | ||
357 | static inline struct arpt_table *find_table_lock(const char *name) | ||
354 | { | 358 | { |
355 | void *ret; | 359 | struct arpt_table *t; |
356 | 360 | ||
357 | *error = down_interruptible(mutex); | 361 | if (down_interruptible(&arpt_mutex) != 0) |
358 | if (*error != 0) | 362 | return ERR_PTR(-EINTR); |
359 | return NULL; | ||
360 | 363 | ||
361 | ret = list_named_find(head, name); | 364 | list_for_each_entry(t, &arpt_tables, list) |
362 | if (!ret) { | 365 | if (strcmp(t->name, name) == 0 && try_module_get(t->me)) |
363 | *error = -ENOENT; | 366 | return t; |
364 | up(mutex); | 367 | up(&arpt_mutex); |
365 | } | 368 | return NULL; |
366 | return ret; | ||
367 | } | 369 | } |
368 | 370 | ||
369 | #ifndef CONFIG_KMOD | 371 | |
370 | #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) | 372 | /* Find target, grabs ref. Returns ERR_PTR() on error. */ |
371 | #else | 373 | static inline struct arpt_target *find_target(const char *name, u8 revision) |
372 | static void * | ||
373 | find_inlist_lock(struct list_head *head, | ||
374 | const char *name, | ||
375 | const char *prefix, | ||
376 | int *error, | ||
377 | struct semaphore *mutex) | ||
378 | { | 374 | { |
379 | void *ret; | 375 | struct arpt_target *t; |
376 | int err = 0; | ||
380 | 377 | ||
381 | ret = find_inlist_lock_noload(head, name, error, mutex); | 378 | if (down_interruptible(&arpt_mutex) != 0) |
382 | if (!ret) { | 379 | return ERR_PTR(-EINTR); |
383 | duprintf("find_inlist: loading `%s%s'.\n", prefix, name); | 380 | |
384 | request_module("%s%s", prefix, name); | 381 | list_for_each_entry(t, &arpt_target, list) { |
385 | ret = find_inlist_lock_noload(head, name, error, mutex); | 382 | if (strcmp(t->name, name) == 0) { |
383 | if (t->revision == revision) { | ||
384 | if (try_module_get(t->me)) { | ||
385 | up(&arpt_mutex); | ||
386 | return t; | ||
387 | } | ||
388 | } else | ||
389 | err = -EPROTOTYPE; /* Found something. */ | ||
390 | } | ||
386 | } | 391 | } |
392 | up(&arpt_mutex); | ||
393 | return ERR_PTR(err); | ||
394 | } | ||
387 | 395 | ||
388 | return ret; | 396 | struct arpt_target *arpt_find_target(const char *name, u8 revision) |
397 | { | ||
398 | struct arpt_target *target; | ||
399 | |||
400 | target = try_then_request_module(find_target(name, revision), | ||
401 | "arpt_%s", name); | ||
402 | if (IS_ERR(target) || !target) | ||
403 | return NULL; | ||
404 | return target; | ||
389 | } | 405 | } |
390 | #endif | ||
391 | 406 | ||
392 | static inline struct arpt_table *arpt_find_table_lock(const char *name, int *error, struct semaphore *mutex) | 407 | static int target_revfn(const char *name, u8 revision, int *bestp) |
393 | { | 408 | { |
394 | return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); | 409 | struct arpt_target *t; |
410 | int have_rev = 0; | ||
411 | |||
412 | list_for_each_entry(t, &arpt_target, list) { | ||
413 | if (strcmp(t->name, name) == 0) { | ||
414 | if (t->revision > *bestp) | ||
415 | *bestp = t->revision; | ||
416 | if (t->revision == revision) | ||
417 | have_rev =1; | ||
418 | } | ||
419 | } | ||
420 | return have_rev; | ||
395 | } | 421 | } |
396 | 422 | ||
397 | static struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) | 423 | /* Returns true or false (if no such extension at all) */ |
424 | static inline int find_revision(const char *name, u8 revision, | ||
425 | int (*revfn)(const char *, u8, int *), | ||
426 | int *err) | ||
398 | { | 427 | { |
399 | return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); | 428 | int have_rev, best = -1; |
429 | |||
430 | if (down_interruptible(&arpt_mutex) != 0) { | ||
431 | *err = -EINTR; | ||
432 | return 1; | ||
433 | } | ||
434 | have_rev = revfn(name, revision, &best); | ||
435 | up(&arpt_mutex); | ||
436 | |||
437 | /* Nothing at all? Return 0 to try loading module. */ | ||
438 | if (best == -1) { | ||
439 | *err = -ENOENT; | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | *err = best; | ||
444 | if (!have_rev) | ||
445 | *err = -EPROTONOSUPPORT; | ||
446 | return 1; | ||
400 | } | 447 | } |
401 | 448 | ||
449 | |||
402 | /* All zeroes == unconditional rule. */ | 450 | /* All zeroes == unconditional rule. */ |
403 | static inline int unconditional(const struct arpt_arp *arp) | 451 | static inline int unconditional(const struct arpt_arp *arp) |
404 | { | 452 | { |
@@ -544,17 +592,15 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
544 | } | 592 | } |
545 | 593 | ||
546 | t = arpt_get_target(e); | 594 | t = arpt_get_target(e); |
547 | target = arpt_find_target_lock(t->u.user.name, &ret, &arpt_mutex); | 595 | target = try_then_request_module(find_target(t->u.user.name, |
548 | if (!target) { | 596 | t->u.user.revision), |
597 | "arpt_%s", t->u.user.name); | ||
598 | if (IS_ERR(target) || !target) { | ||
549 | duprintf("check_entry: `%s' not found\n", t->u.user.name); | 599 | duprintf("check_entry: `%s' not found\n", t->u.user.name); |
600 | ret = target ? PTR_ERR(target) : -ENOENT; | ||
550 | goto out; | 601 | goto out; |
551 | } | 602 | } |
552 | if (!try_module_get((target->me))) { | ||
553 | ret = -ENOENT; | ||
554 | goto out_unlock; | ||
555 | } | ||
556 | t->u.kernel.target = target; | 603 | t->u.kernel.target = target; |
557 | up(&arpt_mutex); | ||
558 | 604 | ||
559 | if (t->u.kernel.target == &arpt_standard_target) { | 605 | if (t->u.kernel.target == &arpt_standard_target) { |
560 | if (!standard_check(t, size)) { | 606 | if (!standard_check(t, size)) { |
@@ -576,8 +622,6 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i | |||
576 | (*i)++; | 622 | (*i)++; |
577 | return 0; | 623 | return 0; |
578 | 624 | ||
579 | out_unlock: | ||
580 | up(&arpt_mutex); | ||
581 | out: | 625 | out: |
582 | return ret; | 626 | return ret; |
583 | } | 627 | } |
@@ -846,8 +890,8 @@ static int get_entries(const struct arpt_get_entries *entries, | |||
846 | int ret; | 890 | int ret; |
847 | struct arpt_table *t; | 891 | struct arpt_table *t; |
848 | 892 | ||
849 | t = arpt_find_table_lock(entries->name, &ret, &arpt_mutex); | 893 | t = find_table_lock(entries->name); |
850 | if (t) { | 894 | if (t || !IS_ERR(t)) { |
851 | duprintf("t->private->number = %u\n", | 895 | duprintf("t->private->number = %u\n", |
852 | t->private->number); | 896 | t->private->number); |
853 | if (entries->size == t->private->size) | 897 | if (entries->size == t->private->size) |
@@ -859,10 +903,10 @@ static int get_entries(const struct arpt_get_entries *entries, | |||
859 | entries->size); | 903 | entries->size); |
860 | ret = -EINVAL; | 904 | ret = -EINVAL; |
861 | } | 905 | } |
906 | module_put(t->me); | ||
862 | up(&arpt_mutex); | 907 | up(&arpt_mutex); |
863 | } else | 908 | } else |
864 | duprintf("get_entries: Can't find %s!\n", | 909 | ret = t ? PTR_ERR(t) : -ENOENT; |
865 | entries->name); | ||
866 | 910 | ||
867 | return ret; | 911 | return ret; |
868 | } | 912 | } |
@@ -913,22 +957,19 @@ static int do_replace(void __user *user, unsigned int len) | |||
913 | 957 | ||
914 | duprintf("arp_tables: Translated table\n"); | 958 | duprintf("arp_tables: Translated table\n"); |
915 | 959 | ||
916 | t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); | 960 | t = try_then_request_module(find_table_lock(tmp.name), |
917 | if (!t) | 961 | "arptable_%s", tmp.name); |
962 | if (!t || IS_ERR(t)) { | ||
963 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
918 | goto free_newinfo_counters_untrans; | 964 | goto free_newinfo_counters_untrans; |
965 | } | ||
919 | 966 | ||
920 | /* You lied! */ | 967 | /* You lied! */ |
921 | if (tmp.valid_hooks != t->valid_hooks) { | 968 | if (tmp.valid_hooks != t->valid_hooks) { |
922 | duprintf("Valid hook crap: %08X vs %08X\n", | 969 | duprintf("Valid hook crap: %08X vs %08X\n", |
923 | tmp.valid_hooks, t->valid_hooks); | 970 | tmp.valid_hooks, t->valid_hooks); |
924 | ret = -EINVAL; | 971 | ret = -EINVAL; |
925 | goto free_newinfo_counters_untrans_unlock; | 972 | goto put_module; |
926 | } | ||
927 | |||
928 | /* Get a reference in advance, we're not allowed fail later */ | ||
929 | if (!try_module_get(t->me)) { | ||
930 | ret = -EBUSY; | ||
931 | goto free_newinfo_counters_untrans_unlock; | ||
932 | } | 973 | } |
933 | 974 | ||
934 | oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); | 975 | oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); |
@@ -959,7 +1000,6 @@ static int do_replace(void __user *user, unsigned int len) | |||
959 | 1000 | ||
960 | put_module: | 1001 | put_module: |
961 | module_put(t->me); | 1002 | module_put(t->me); |
962 | free_newinfo_counters_untrans_unlock: | ||
963 | up(&arpt_mutex); | 1003 | up(&arpt_mutex); |
964 | free_newinfo_counters_untrans: | 1004 | free_newinfo_counters_untrans: |
965 | ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry, NULL); | 1005 | ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry, NULL); |
@@ -989,7 +1029,7 @@ static int do_add_counters(void __user *user, unsigned int len) | |||
989 | unsigned int i; | 1029 | unsigned int i; |
990 | struct arpt_counters_info tmp, *paddc; | 1030 | struct arpt_counters_info tmp, *paddc; |
991 | struct arpt_table *t; | 1031 | struct arpt_table *t; |
992 | int ret; | 1032 | int ret = 0; |
993 | 1033 | ||
994 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1034 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
995 | return -EFAULT; | 1035 | return -EFAULT; |
@@ -1006,9 +1046,11 @@ static int do_add_counters(void __user *user, unsigned int len) | |||
1006 | goto free; | 1046 | goto free; |
1007 | } | 1047 | } |
1008 | 1048 | ||
1009 | t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); | 1049 | t = find_table_lock(tmp.name); |
1010 | if (!t) | 1050 | if (!t || IS_ERR(t)) { |
1051 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
1011 | goto free; | 1052 | goto free; |
1053 | } | ||
1012 | 1054 | ||
1013 | write_lock_bh(&t->lock); | 1055 | write_lock_bh(&t->lock); |
1014 | if (t->private->number != paddc->num_counters) { | 1056 | if (t->private->number != paddc->num_counters) { |
@@ -1025,6 +1067,7 @@ static int do_add_counters(void __user *user, unsigned int len) | |||
1025 | unlock_up_free: | 1067 | unlock_up_free: |
1026 | write_unlock_bh(&t->lock); | 1068 | write_unlock_bh(&t->lock); |
1027 | up(&arpt_mutex); | 1069 | up(&arpt_mutex); |
1070 | module_put(t->me); | ||
1028 | free: | 1071 | free: |
1029 | vfree(paddc); | 1072 | vfree(paddc); |
1030 | 1073 | ||
@@ -1079,8 +1122,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len | |||
1079 | break; | 1122 | break; |
1080 | } | 1123 | } |
1081 | name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; | 1124 | name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; |
1082 | t = arpt_find_table_lock(name, &ret, &arpt_mutex); | 1125 | |
1083 | if (t) { | 1126 | t = try_then_request_module(find_table_lock(name), |
1127 | "arptable_%s", name); | ||
1128 | if (t && !IS_ERR(t)) { | ||
1084 | struct arpt_getinfo info; | 1129 | struct arpt_getinfo info; |
1085 | 1130 | ||
1086 | info.valid_hooks = t->valid_hooks; | 1131 | info.valid_hooks = t->valid_hooks; |
@@ -1096,9 +1141,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len | |||
1096 | ret = -EFAULT; | 1141 | ret = -EFAULT; |
1097 | else | 1142 | else |
1098 | ret = 0; | 1143 | ret = 0; |
1099 | |||
1100 | up(&arpt_mutex); | 1144 | up(&arpt_mutex); |
1101 | } | 1145 | module_put(t->me); |
1146 | } else | ||
1147 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
1102 | } | 1148 | } |
1103 | break; | 1149 | break; |
1104 | 1150 | ||
@@ -1119,6 +1165,24 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len | |||
1119 | break; | 1165 | break; |
1120 | } | 1166 | } |
1121 | 1167 | ||
1168 | case ARPT_SO_GET_REVISION_TARGET: { | ||
1169 | struct arpt_get_revision rev; | ||
1170 | |||
1171 | if (*len != sizeof(rev)) { | ||
1172 | ret = -EINVAL; | ||
1173 | break; | ||
1174 | } | ||
1175 | if (copy_from_user(&rev, user, sizeof(rev)) != 0) { | ||
1176 | ret = -EFAULT; | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | try_then_request_module(find_revision(rev.name, rev.revision, | ||
1181 | target_revfn, &ret), | ||
1182 | "arpt_%s", rev.name); | ||
1183 | break; | ||
1184 | } | ||
1185 | |||
1122 | default: | 1186 | default: |
1123 | duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); | 1187 | duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); |
1124 | ret = -EINVAL; | 1188 | ret = -EINVAL; |
@@ -1136,12 +1200,9 @@ int arpt_register_target(struct arpt_target *target) | |||
1136 | if (ret != 0) | 1200 | if (ret != 0) |
1137 | return ret; | 1201 | return ret; |
1138 | 1202 | ||
1139 | if (!list_named_insert(&arpt_target, target)) { | 1203 | list_add(&target->list, &arpt_target); |
1140 | duprintf("arpt_register_target: `%s' already in list!\n", | ||
1141 | target->name); | ||
1142 | ret = -EINVAL; | ||
1143 | } | ||
1144 | up(&arpt_mutex); | 1204 | up(&arpt_mutex); |
1205 | |||
1145 | return ret; | 1206 | return ret; |
1146 | } | 1207 | } |
1147 | 1208 | ||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index c4f2a0ef7489..966b2372aaab 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -1087,7 +1087,7 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
1087 | 1087 | ||
1088 | int igmp6_event_query(struct sk_buff *skb) | 1088 | int igmp6_event_query(struct sk_buff *skb) |
1089 | { | 1089 | { |
1090 | struct mld2_query *mlh2 = (struct mld2_query *) skb->h.raw; | 1090 | struct mld2_query *mlh2 = NULL; |
1091 | struct ifmcaddr6 *ma; | 1091 | struct ifmcaddr6 *ma; |
1092 | struct in6_addr *group; | 1092 | struct in6_addr *group; |
1093 | unsigned long max_delay; | 1093 | unsigned long max_delay; |
@@ -1140,6 +1140,13 @@ int igmp6_event_query(struct sk_buff *skb) | |||
1140 | /* clear deleted report items */ | 1140 | /* clear deleted report items */ |
1141 | mld_clear_delrec(idev); | 1141 | mld_clear_delrec(idev); |
1142 | } else if (len >= 28) { | 1142 | } else if (len >= 28) { |
1143 | int srcs_offset = sizeof(struct mld2_query) - | ||
1144 | sizeof(struct icmp6hdr); | ||
1145 | if (!pskb_may_pull(skb, srcs_offset)) { | ||
1146 | in6_dev_put(idev); | ||
1147 | return -EINVAL; | ||
1148 | } | ||
1149 | mlh2 = (struct mld2_query *) skb->h.raw; | ||
1143 | max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; | 1150 | max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; |
1144 | if (!max_delay) | 1151 | if (!max_delay) |
1145 | max_delay = 1; | 1152 | max_delay = 1; |
@@ -1156,7 +1163,15 @@ int igmp6_event_query(struct sk_buff *skb) | |||
1156 | return 0; | 1163 | return 0; |
1157 | } | 1164 | } |
1158 | /* mark sources to include, if group & source-specific */ | 1165 | /* mark sources to include, if group & source-specific */ |
1159 | mark = mlh2->nsrcs != 0; | 1166 | if (mlh2->nsrcs != 0) { |
1167 | if (!pskb_may_pull(skb, srcs_offset + | ||
1168 | mlh2->nsrcs * sizeof(struct in6_addr))) { | ||
1169 | in6_dev_put(idev); | ||
1170 | return -EINVAL; | ||
1171 | } | ||
1172 | mlh2 = (struct mld2_query *) skb->h.raw; | ||
1173 | mark = 1; | ||
1174 | } | ||
1160 | } else { | 1175 | } else { |
1161 | in6_dev_put(idev); | 1176 | in6_dev_put(idev); |
1162 | return -EINVAL; | 1177 | return -EINVAL; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 21deec25a12b..7d492226c16e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Packet matching code. | 2 | * Packet matching code. |
3 | * | 3 | * |
4 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling | 4 | * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling |
5 | * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org> | 5 | * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/tcp.h> | 23 | #include <linux/tcp.h> |
24 | #include <linux/udp.h> | 24 | #include <linux/udp.h> |
25 | #include <linux/icmpv6.h> | 25 | #include <linux/icmpv6.h> |
26 | #include <net/ip.h> | ||
27 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
28 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
29 | #include <asm/semaphore.h> | 28 | #include <asm/semaphore.h> |
@@ -80,13 +79,12 @@ static DECLARE_MUTEX(ip6t_mutex); | |||
80 | #define inline | 79 | #define inline |
81 | #endif | 80 | #endif |
82 | 81 | ||
83 | /* Locking is simple: we assume at worst case there will be one packet | 82 | /* |
84 | in user context and one from bottom halves (or soft irq if Alexey's | ||
85 | softnet patch was applied). | ||
86 | |||
87 | We keep a set of rules for each CPU, so we can avoid write-locking | 83 | We keep a set of rules for each CPU, so we can avoid write-locking |
88 | them; doing a readlock_bh() stops packets coming through if we're | 84 | them in the softirq when updating the counters and therefore |
89 | in user context. | 85 | only need to read-lock in the softirq; doing a write_lock_bh() in user |
86 | context stops packets coming through and allows user context to read | ||
87 | the counters or update the rules. | ||
90 | 88 | ||
91 | To be cache friendly on SMP, we arrange them like so: | 89 | To be cache friendly on SMP, we arrange them like so: |
92 | [ n-entries ] | 90 | [ n-entries ] |
@@ -356,7 +354,7 @@ ip6t_do_table(struct sk_buff **pskb, | |||
356 | struct ip6t_table *table, | 354 | struct ip6t_table *table, |
357 | void *userdata) | 355 | void *userdata) |
358 | { | 356 | { |
359 | static const char nulldevname[IFNAMSIZ]; | 357 | static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); |
360 | int offset = 0; | 358 | int offset = 0; |
361 | unsigned int protoff = 0; | 359 | unsigned int protoff = 0; |
362 | int hotdrop = 0; | 360 | int hotdrop = 0; |
@@ -369,7 +367,6 @@ ip6t_do_table(struct sk_buff **pskb, | |||
369 | /* Initialization */ | 367 | /* Initialization */ |
370 | indev = in ? in->name : nulldevname; | 368 | indev = in ? in->name : nulldevname; |
371 | outdev = out ? out->name : nulldevname; | 369 | outdev = out ? out->name : nulldevname; |
372 | |||
373 | /* We handle fragments by dealing with the first fragment as | 370 | /* We handle fragments by dealing with the first fragment as |
374 | * if it was a normal packet. All other fragments are treated | 371 | * if it was a normal packet. All other fragments are treated |
375 | * normally, except that they will NEVER match rules that ask | 372 | * normally, except that they will NEVER match rules that ask |
@@ -497,75 +494,145 @@ ip6t_do_table(struct sk_buff **pskb, | |||
497 | #endif | 494 | #endif |
498 | } | 495 | } |
499 | 496 | ||
500 | /* If it succeeds, returns element and locks mutex */ | 497 | /* |
501 | static inline void * | 498 | * These are weird, but module loading must not be done with mutex |
502 | find_inlist_lock_noload(struct list_head *head, | 499 | * held (since they will register), and we have to have a single |
503 | const char *name, | 500 | * function to use try_then_request_module(). |
504 | int *error, | 501 | */ |
505 | struct semaphore *mutex) | 502 | |
503 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ | ||
504 | static inline struct ip6t_table *find_table_lock(const char *name) | ||
506 | { | 505 | { |
507 | void *ret; | 506 | struct ip6t_table *t; |
508 | 507 | ||
509 | #if 1 | 508 | if (down_interruptible(&ip6t_mutex) != 0) |
510 | duprintf("find_inlist: searching for `%s' in %s.\n", | 509 | return ERR_PTR(-EINTR); |
511 | name, head == &ip6t_target ? "ip6t_target" | ||
512 | : head == &ip6t_match ? "ip6t_match" | ||
513 | : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN"); | ||
514 | #endif | ||
515 | 510 | ||
516 | *error = down_interruptible(mutex); | 511 | list_for_each_entry(t, &ip6t_tables, list) |
517 | if (*error != 0) | 512 | if (strcmp(t->name, name) == 0 && try_module_get(t->me)) |
518 | return NULL; | 513 | return t; |
514 | up(&ip6t_mutex); | ||
515 | return NULL; | ||
516 | } | ||
517 | |||
518 | /* Find match, grabs ref. Returns ERR_PTR() on error. */ | ||
519 | static inline struct ip6t_match *find_match(const char *name, u8 revision) | ||
520 | { | ||
521 | struct ip6t_match *m; | ||
522 | int err = 0; | ||
519 | 523 | ||
520 | ret = list_named_find(head, name); | 524 | if (down_interruptible(&ip6t_mutex) != 0) |
521 | if (!ret) { | 525 | return ERR_PTR(-EINTR); |
522 | *error = -ENOENT; | 526 | |
523 | up(mutex); | 527 | list_for_each_entry(m, &ip6t_match, list) { |
528 | if (strcmp(m->name, name) == 0) { | ||
529 | if (m->revision == revision) { | ||
530 | if (try_module_get(m->me)) { | ||
531 | up(&ip6t_mutex); | ||
532 | return m; | ||
533 | } | ||
534 | } else | ||
535 | err = -EPROTOTYPE; /* Found something. */ | ||
536 | } | ||
524 | } | 537 | } |
525 | return ret; | 538 | up(&ip6t_mutex); |
539 | return ERR_PTR(err); | ||
526 | } | 540 | } |
527 | 541 | ||
528 | #ifndef CONFIG_KMOD | 542 | /* Find target, grabs ref. Returns ERR_PTR() on error. */ |
529 | #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) | 543 | static inline struct ip6t_target *find_target(const char *name, u8 revision) |
530 | #else | ||
531 | static void * | ||
532 | find_inlist_lock(struct list_head *head, | ||
533 | const char *name, | ||
534 | const char *prefix, | ||
535 | int *error, | ||
536 | struct semaphore *mutex) | ||
537 | { | 544 | { |
538 | void *ret; | 545 | struct ip6t_target *t; |
546 | int err = 0; | ||
539 | 547 | ||
540 | ret = find_inlist_lock_noload(head, name, error, mutex); | 548 | if (down_interruptible(&ip6t_mutex) != 0) |
541 | if (!ret) { | 549 | return ERR_PTR(-EINTR); |
542 | duprintf("find_inlist: loading `%s%s'.\n", prefix, name); | 550 | |
543 | request_module("%s%s", prefix, name); | 551 | list_for_each_entry(t, &ip6t_target, list) { |
544 | ret = find_inlist_lock_noload(head, name, error, mutex); | 552 | if (strcmp(t->name, name) == 0) { |
553 | if (t->revision == revision) { | ||
554 | if (try_module_get(t->me)) { | ||
555 | up(&ip6t_mutex); | ||
556 | return t; | ||
557 | } | ||
558 | } else | ||
559 | err = -EPROTOTYPE; /* Found something. */ | ||
560 | } | ||
545 | } | 561 | } |
562 | up(&ip6t_mutex); | ||
563 | return ERR_PTR(err); | ||
564 | } | ||
546 | 565 | ||
547 | return ret; | 566 | struct ip6t_target *ip6t_find_target(const char *name, u8 revision) |
567 | { | ||
568 | struct ip6t_target *target; | ||
569 | |||
570 | target = try_then_request_module(find_target(name, revision), | ||
571 | "ip6t_%s", name); | ||
572 | if (IS_ERR(target) || !target) | ||
573 | return NULL; | ||
574 | return target; | ||
548 | } | 575 | } |
549 | #endif | ||
550 | 576 | ||
551 | static inline struct ip6t_table * | 577 | static int match_revfn(const char *name, u8 revision, int *bestp) |
552 | ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex) | ||
553 | { | 578 | { |
554 | return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex); | 579 | struct ip6t_match *m; |
580 | int have_rev = 0; | ||
581 | |||
582 | list_for_each_entry(m, &ip6t_match, list) { | ||
583 | if (strcmp(m->name, name) == 0) { | ||
584 | if (m->revision > *bestp) | ||
585 | *bestp = m->revision; | ||
586 | if (m->revision == revision) | ||
587 | have_rev = 1; | ||
588 | } | ||
589 | } | ||
590 | return have_rev; | ||
555 | } | 591 | } |
556 | 592 | ||
557 | static inline struct ip6t_match * | 593 | static int target_revfn(const char *name, u8 revision, int *bestp) |
558 | find_match_lock(const char *name, int *error, struct semaphore *mutex) | ||
559 | { | 594 | { |
560 | return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); | 595 | struct ip6t_target *t; |
596 | int have_rev = 0; | ||
597 | |||
598 | list_for_each_entry(t, &ip6t_target, list) { | ||
599 | if (strcmp(t->name, name) == 0) { | ||
600 | if (t->revision > *bestp) | ||
601 | *bestp = t->revision; | ||
602 | if (t->revision == revision) | ||
603 | have_rev = 1; | ||
604 | } | ||
605 | } | ||
606 | return have_rev; | ||
561 | } | 607 | } |
562 | 608 | ||
563 | static struct ip6t_target * | 609 | /* Returns true or fals (if no such extension at all) */ |
564 | ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) | 610 | static inline int find_revision(const char *name, u8 revision, |
611 | int (*revfn)(const char *, u8, int *), | ||
612 | int *err) | ||
565 | { | 613 | { |
566 | return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); | 614 | int have_rev, best = -1; |
615 | |||
616 | if (down_interruptible(&ip6t_mutex) != 0) { | ||
617 | *err = -EINTR; | ||
618 | return 1; | ||
619 | } | ||
620 | have_rev = revfn(name, revision, &best); | ||
621 | up(&ip6t_mutex); | ||
622 | |||
623 | /* Nothing at all? Return 0 to try loading module. */ | ||
624 | if (best == -1) { | ||
625 | *err = -ENOENT; | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | *err = best; | ||
630 | if (!have_rev) | ||
631 | *err = -EPROTONOSUPPORT; | ||
632 | return 1; | ||
567 | } | 633 | } |
568 | 634 | ||
635 | |||
569 | /* All zeroes == unconditional rule. */ | 636 | /* All zeroes == unconditional rule. */ |
570 | static inline int | 637 | static inline int |
571 | unconditional(const struct ip6t_ip6 *ipv6) | 638 | unconditional(const struct ip6t_ip6 *ipv6) |
@@ -725,20 +792,16 @@ check_match(struct ip6t_entry_match *m, | |||
725 | unsigned int hookmask, | 792 | unsigned int hookmask, |
726 | unsigned int *i) | 793 | unsigned int *i) |
727 | { | 794 | { |
728 | int ret; | ||
729 | struct ip6t_match *match; | 795 | struct ip6t_match *match; |
730 | 796 | ||
731 | match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex); | 797 | match = try_then_request_module(find_match(m->u.user.name, |
732 | if (!match) { | 798 | m->u.user.revision), |
733 | // duprintf("check_match: `%s' not found\n", m->u.name); | 799 | "ip6t_%s", m->u.user.name); |
734 | return ret; | 800 | if (IS_ERR(match) || !match) { |
735 | } | 801 | duprintf("check_match: `%s' not found\n", m->u.user.name); |
736 | if (!try_module_get(match->me)) { | 802 | return match ? PTR_ERR(match) : -ENOENT; |
737 | up(&ip6t_mutex); | ||
738 | return -ENOENT; | ||
739 | } | 803 | } |
740 | m->u.kernel.match = match; | 804 | m->u.kernel.match = match; |
741 | up(&ip6t_mutex); | ||
742 | 805 | ||
743 | if (m->u.kernel.match->checkentry | 806 | if (m->u.kernel.match->checkentry |
744 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, | 807 | && !m->u.kernel.match->checkentry(name, ipv6, m->data, |
@@ -776,22 +839,16 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
776 | goto cleanup_matches; | 839 | goto cleanup_matches; |
777 | 840 | ||
778 | t = ip6t_get_target(e); | 841 | t = ip6t_get_target(e); |
779 | target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex); | 842 | target = try_then_request_module(find_target(t->u.user.name, |
780 | if (!target) { | 843 | t->u.user.revision), |
844 | "ip6t_%s", t->u.user.name); | ||
845 | if (IS_ERR(target) || !target) { | ||
781 | duprintf("check_entry: `%s' not found\n", t->u.user.name); | 846 | duprintf("check_entry: `%s' not found\n", t->u.user.name); |
782 | goto cleanup_matches; | 847 | ret = target ? PTR_ERR(target) : -ENOENT; |
783 | } | ||
784 | if (!try_module_get(target->me)) { | ||
785 | up(&ip6t_mutex); | ||
786 | ret = -ENOENT; | ||
787 | goto cleanup_matches; | 848 | goto cleanup_matches; |
788 | } | 849 | } |
789 | t->u.kernel.target = target; | 850 | t->u.kernel.target = target; |
790 | up(&ip6t_mutex); | 851 | |
791 | if (!t->u.kernel.target) { | ||
792 | ret = -EBUSY; | ||
793 | goto cleanup_matches; | ||
794 | } | ||
795 | if (t->u.kernel.target == &ip6t_standard_target) { | 852 | if (t->u.kernel.target == &ip6t_standard_target) { |
796 | if (!standard_check(t, size)) { | 853 | if (!standard_check(t, size)) { |
797 | ret = -EINVAL; | 854 | ret = -EINVAL; |
@@ -1118,8 +1175,8 @@ get_entries(const struct ip6t_get_entries *entries, | |||
1118 | int ret; | 1175 | int ret; |
1119 | struct ip6t_table *t; | 1176 | struct ip6t_table *t; |
1120 | 1177 | ||
1121 | t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex); | 1178 | t = find_table_lock(entries->name); |
1122 | if (t) { | 1179 | if (t && !IS_ERR(t)) { |
1123 | duprintf("t->private->number = %u\n", | 1180 | duprintf("t->private->number = %u\n", |
1124 | t->private->number); | 1181 | t->private->number); |
1125 | if (entries->size == t->private->size) | 1182 | if (entries->size == t->private->size) |
@@ -1131,10 +1188,10 @@ get_entries(const struct ip6t_get_entries *entries, | |||
1131 | entries->size); | 1188 | entries->size); |
1132 | ret = -EINVAL; | 1189 | ret = -EINVAL; |
1133 | } | 1190 | } |
1191 | module_put(t->me); | ||
1134 | up(&ip6t_mutex); | 1192 | up(&ip6t_mutex); |
1135 | } else | 1193 | } else |
1136 | duprintf("get_entries: Can't find %s!\n", | 1194 | ret = t ? PTR_ERR(t) : -ENOENT; |
1137 | entries->name); | ||
1138 | 1195 | ||
1139 | return ret; | 1196 | return ret; |
1140 | } | 1197 | } |
@@ -1182,22 +1239,19 @@ do_replace(void __user *user, unsigned int len) | |||
1182 | 1239 | ||
1183 | duprintf("ip_tables: Translated table\n"); | 1240 | duprintf("ip_tables: Translated table\n"); |
1184 | 1241 | ||
1185 | t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); | 1242 | t = try_then_request_module(find_table_lock(tmp.name), |
1186 | if (!t) | 1243 | "ip6table_%s", tmp.name); |
1244 | if (!t || IS_ERR(t)) { | ||
1245 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
1187 | goto free_newinfo_counters_untrans; | 1246 | goto free_newinfo_counters_untrans; |
1247 | } | ||
1188 | 1248 | ||
1189 | /* You lied! */ | 1249 | /* You lied! */ |
1190 | if (tmp.valid_hooks != t->valid_hooks) { | 1250 | if (tmp.valid_hooks != t->valid_hooks) { |
1191 | duprintf("Valid hook crap: %08X vs %08X\n", | 1251 | duprintf("Valid hook crap: %08X vs %08X\n", |
1192 | tmp.valid_hooks, t->valid_hooks); | 1252 | tmp.valid_hooks, t->valid_hooks); |
1193 | ret = -EINVAL; | 1253 | ret = -EINVAL; |
1194 | goto free_newinfo_counters_untrans_unlock; | 1254 | goto put_module; |
1195 | } | ||
1196 | |||
1197 | /* Get a reference in advance, we're not allowed fail later */ | ||
1198 | if (!try_module_get(t->me)) { | ||
1199 | ret = -EBUSY; | ||
1200 | goto free_newinfo_counters_untrans_unlock; | ||
1201 | } | 1255 | } |
1202 | 1256 | ||
1203 | oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); | 1257 | oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); |
@@ -1219,7 +1273,6 @@ do_replace(void __user *user, unsigned int len) | |||
1219 | /* Decrease module usage counts and free resource */ | 1273 | /* Decrease module usage counts and free resource */ |
1220 | IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL); | 1274 | IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL); |
1221 | vfree(oldinfo); | 1275 | vfree(oldinfo); |
1222 | /* Silent error: too late now. */ | ||
1223 | if (copy_to_user(tmp.counters, counters, | 1276 | if (copy_to_user(tmp.counters, counters, |
1224 | sizeof(struct ip6t_counters) * tmp.num_counters) != 0) | 1277 | sizeof(struct ip6t_counters) * tmp.num_counters) != 0) |
1225 | ret = -EFAULT; | 1278 | ret = -EFAULT; |
@@ -1229,7 +1282,6 @@ do_replace(void __user *user, unsigned int len) | |||
1229 | 1282 | ||
1230 | put_module: | 1283 | put_module: |
1231 | module_put(t->me); | 1284 | module_put(t->me); |
1232 | free_newinfo_counters_untrans_unlock: | ||
1233 | up(&ip6t_mutex); | 1285 | up(&ip6t_mutex); |
1234 | free_newinfo_counters_untrans: | 1286 | free_newinfo_counters_untrans: |
1235 | IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL); | 1287 | IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL); |
@@ -1268,7 +1320,7 @@ do_add_counters(void __user *user, unsigned int len) | |||
1268 | unsigned int i; | 1320 | unsigned int i; |
1269 | struct ip6t_counters_info tmp, *paddc; | 1321 | struct ip6t_counters_info tmp, *paddc; |
1270 | struct ip6t_table *t; | 1322 | struct ip6t_table *t; |
1271 | int ret; | 1323 | int ret = 0; |
1272 | 1324 | ||
1273 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1325 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1274 | return -EFAULT; | 1326 | return -EFAULT; |
@@ -1285,9 +1337,11 @@ do_add_counters(void __user *user, unsigned int len) | |||
1285 | goto free; | 1337 | goto free; |
1286 | } | 1338 | } |
1287 | 1339 | ||
1288 | t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); | 1340 | t = find_table_lock(tmp.name); |
1289 | if (!t) | 1341 | if (!t || IS_ERR(t)) { |
1342 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
1290 | goto free; | 1343 | goto free; |
1344 | } | ||
1291 | 1345 | ||
1292 | write_lock_bh(&t->lock); | 1346 | write_lock_bh(&t->lock); |
1293 | if (t->private->number != paddc->num_counters) { | 1347 | if (t->private->number != paddc->num_counters) { |
@@ -1304,6 +1358,7 @@ do_add_counters(void __user *user, unsigned int len) | |||
1304 | unlock_up_free: | 1358 | unlock_up_free: |
1305 | write_unlock_bh(&t->lock); | 1359 | write_unlock_bh(&t->lock); |
1306 | up(&ip6t_mutex); | 1360 | up(&ip6t_mutex); |
1361 | module_put(t->me); | ||
1307 | free: | 1362 | free: |
1308 | vfree(paddc); | 1363 | vfree(paddc); |
1309 | 1364 | ||
@@ -1360,8 +1415,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1360 | break; | 1415 | break; |
1361 | } | 1416 | } |
1362 | name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; | 1417 | name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; |
1363 | t = ip6t_find_table_lock(name, &ret, &ip6t_mutex); | 1418 | |
1364 | if (t) { | 1419 | t = try_then_request_module(find_table_lock(name), |
1420 | "ip6table_%s", name); | ||
1421 | if (t && !IS_ERR(t)) { | ||
1365 | struct ip6t_getinfo info; | 1422 | struct ip6t_getinfo info; |
1366 | 1423 | ||
1367 | info.valid_hooks = t->valid_hooks; | 1424 | info.valid_hooks = t->valid_hooks; |
@@ -1377,9 +1434,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1377 | ret = -EFAULT; | 1434 | ret = -EFAULT; |
1378 | else | 1435 | else |
1379 | ret = 0; | 1436 | ret = 0; |
1380 | |||
1381 | up(&ip6t_mutex); | 1437 | up(&ip6t_mutex); |
1382 | } | 1438 | module_put(t->me); |
1439 | } else | ||
1440 | ret = t ? PTR_ERR(t) : -ENOENT; | ||
1383 | } | 1441 | } |
1384 | break; | 1442 | break; |
1385 | 1443 | ||
@@ -1400,6 +1458,31 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) | |||
1400 | break; | 1458 | break; |
1401 | } | 1459 | } |
1402 | 1460 | ||
1461 | case IP6T_SO_GET_REVISION_MATCH: | ||
1462 | case IP6T_SO_GET_REVISION_TARGET: { | ||
1463 | struct ip6t_get_revision rev; | ||
1464 | int (*revfn)(const char *, u8, int *); | ||
1465 | |||
1466 | if (*len != sizeof(rev)) { | ||
1467 | ret = -EINVAL; | ||
1468 | break; | ||
1469 | } | ||
1470 | if (copy_from_user(&rev, user, sizeof(rev)) != 0) { | ||
1471 | ret = -EFAULT; | ||
1472 | break; | ||
1473 | } | ||
1474 | |||
1475 | if (cmd == IP6T_SO_GET_REVISION_TARGET) | ||
1476 | revfn = target_revfn; | ||
1477 | else | ||
1478 | revfn = match_revfn; | ||
1479 | |||
1480 | try_then_request_module(find_revision(rev.name, rev.revision, | ||
1481 | revfn, &ret), | ||
1482 | "ip6t_%s", rev.name); | ||
1483 | break; | ||
1484 | } | ||
1485 | |||
1403 | default: | 1486 | default: |
1404 | duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd); | 1487 | duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd); |
1405 | ret = -EINVAL; | 1488 | ret = -EINVAL; |
@@ -1417,12 +1500,7 @@ ip6t_register_target(struct ip6t_target *target) | |||
1417 | ret = down_interruptible(&ip6t_mutex); | 1500 | ret = down_interruptible(&ip6t_mutex); |
1418 | if (ret != 0) | 1501 | if (ret != 0) |
1419 | return ret; | 1502 | return ret; |
1420 | 1503 | list_add(&target->list, &ip6t_target); | |
1421 | if (!list_named_insert(&ip6t_target, target)) { | ||
1422 | duprintf("ip6t_register_target: `%s' already in list!\n", | ||
1423 | target->name); | ||
1424 | ret = -EINVAL; | ||
1425 | } | ||
1426 | up(&ip6t_mutex); | 1504 | up(&ip6t_mutex); |
1427 | return ret; | 1505 | return ret; |
1428 | } | 1506 | } |
@@ -1444,11 +1522,7 @@ ip6t_register_match(struct ip6t_match *match) | |||
1444 | if (ret != 0) | 1522 | if (ret != 0) |
1445 | return ret; | 1523 | return ret; |
1446 | 1524 | ||
1447 | if (!list_named_insert(&ip6t_match, match)) { | 1525 | list_add(&match->list, &ip6t_match); |
1448 | duprintf("ip6t_register_match: `%s' already in list!\n", | ||
1449 | match->name); | ||
1450 | ret = -EINVAL; | ||
1451 | } | ||
1452 | up(&ip6t_mutex); | 1526 | up(&ip6t_mutex); |
1453 | 1527 | ||
1454 | return ret; | 1528 | return ret; |
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c index 81924fcc5857..0c7584f92172 100644 --- a/net/ipv6/netfilter/ip6t_MARK.c +++ b/net/ipv6/netfilter/ip6t_MARK.c | |||
@@ -56,8 +56,12 @@ checkentry(const char *tablename, | |||
56 | return 1; | 56 | return 1; |
57 | } | 57 | } |
58 | 58 | ||
59 | static struct ip6t_target ip6t_mark_reg | 59 | static struct ip6t_target ip6t_mark_reg = { |
60 | = { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE }; | 60 | .name = "MARK", |
61 | .target = target, | ||
62 | .checkentry = checkentry, | ||
63 | .me = THIS_MODULE | ||
64 | }; | ||
61 | 65 | ||
62 | static int __init init(void) | 66 | static int __init init(void) |
63 | { | 67 | { |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5d5bbb49ec78..227e99ed510c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -483,7 +483,7 @@ restart: | |||
483 | goto out; | 483 | goto out; |
484 | } | 484 | } |
485 | 485 | ||
486 | rt = rt6_device_match(rt, skb->dev->ifindex, 0); | 486 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); |
487 | BACKTRACK(); | 487 | BACKTRACK(); |
488 | 488 | ||
489 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 489 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { |
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c index 50ae0371dab8..b6c8f38cc26c 100644 --- a/net/rose/rose_timer.c +++ b/net/rose/rose_timer.c | |||
@@ -138,6 +138,7 @@ static void rose_heartbeat_expiry(unsigned long param) | |||
138 | is accepted() it isn't 'dead' so doesn't get removed. */ | 138 | is accepted() it isn't 'dead' so doesn't get removed. */ |
139 | if (sock_flag(sk, SOCK_DESTROY) || | 139 | if (sock_flag(sk, SOCK_DESTROY) || |
140 | (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { | 140 | (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { |
141 | bh_unlock_sock(sk); | ||
141 | rose_destroy_socket(sk); | 142 | rose_destroy_socket(sk); |
142 | return; | 143 | return; |
143 | } | 144 | } |