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 | } |
