diff options
Diffstat (limited to 'net')
43 files changed, 661 insertions, 806 deletions
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index c742d37bfb97..ba6428f204f9 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
@@ -24,16 +24,6 @@ Author: Marcell GAL, 2000, XDSL Ltd, Hungary | |||
24 | 24 | ||
25 | #include "common.h" | 25 | #include "common.h" |
26 | 26 | ||
27 | /* | ||
28 | * Define this to use a version of the code which interacts with the higher | ||
29 | * layers in a more intellegent way, by always reserving enough space for | ||
30 | * our header at the begining of the packet. However, there may still be | ||
31 | * some problems with programs like tcpdump. In 2.5 we'll sort out what | ||
32 | * we need to do to get this perfect. For now we just will copy the packet | ||
33 | * if we need space for the header | ||
34 | */ | ||
35 | /* #define FASTER_VERSION */ | ||
36 | |||
37 | #ifdef SKB_DEBUG | 27 | #ifdef SKB_DEBUG |
38 | static void skb_debug(const struct sk_buff *skb) | 28 | static void skb_debug(const struct sk_buff *skb) |
39 | { | 29 | { |
@@ -69,9 +59,7 @@ struct br2684_vcc { | |||
69 | #ifdef CONFIG_ATM_BR2684_IPFILTER | 59 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
70 | struct br2684_filter filter; | 60 | struct br2684_filter filter; |
71 | #endif /* CONFIG_ATM_BR2684_IPFILTER */ | 61 | #endif /* CONFIG_ATM_BR2684_IPFILTER */ |
72 | #ifndef FASTER_VERSION | ||
73 | unsigned copies_needed, copies_failed; | 62 | unsigned copies_needed, copies_failed; |
74 | #endif /* FASTER_VERSION */ | ||
75 | }; | 63 | }; |
76 | 64 | ||
77 | struct br2684_dev { | 65 | struct br2684_dev { |
@@ -147,13 +135,6 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, | |||
147 | struct br2684_vcc *brvcc) | 135 | struct br2684_vcc *brvcc) |
148 | { | 136 | { |
149 | struct atm_vcc *atmvcc; | 137 | struct atm_vcc *atmvcc; |
150 | #ifdef FASTER_VERSION | ||
151 | if (brvcc->encaps == e_llc) | ||
152 | memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8); | ||
153 | /* last 2 bytes of llc_oui_pid_pad are managed by header routines; | ||
154 | yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad) | ||
155 | */ | ||
156 | #else | ||
157 | int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; | 138 | int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; |
158 | if (skb_headroom(skb) < minheadroom) { | 139 | if (skb_headroom(skb) < minheadroom) { |
159 | struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); | 140 | struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); |
@@ -170,7 +151,6 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev, | |||
170 | skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10); | 151 | skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10); |
171 | else | 152 | else |
172 | memset(skb->data, 0, 2); | 153 | memset(skb->data, 0, 2); |
173 | #endif /* FASTER_VERSION */ | ||
174 | skb_debug(skb); | 154 | skb_debug(skb); |
175 | 155 | ||
176 | ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; | 156 | ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; |
@@ -237,87 +217,6 @@ static struct net_device_stats *br2684_get_stats(struct net_device *dev) | |||
237 | return &BRPRIV(dev)->stats; | 217 | return &BRPRIV(dev)->stats; |
238 | } | 218 | } |
239 | 219 | ||
240 | #ifdef FASTER_VERSION | ||
241 | /* | ||
242 | * These mirror eth_header and eth_header_cache. They are not usually | ||
243 | * exported for use in modules, so we grab them from net_device | ||
244 | * after ether_setup() is done with it. Bit of a hack. | ||
245 | */ | ||
246 | static int (*my_eth_header)(struct sk_buff *, struct net_device *, | ||
247 | unsigned short, void *, void *, unsigned); | ||
248 | static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *); | ||
249 | |||
250 | static int | ||
251 | br2684_header(struct sk_buff *skb, struct net_device *dev, | ||
252 | unsigned short type, void *daddr, void *saddr, unsigned len) | ||
253 | { | ||
254 | u16 *pad_before_eth; | ||
255 | int t = my_eth_header(skb, dev, type, daddr, saddr, len); | ||
256 | if (t > 0) { | ||
257 | pad_before_eth = (u16 *) skb_push(skb, 2); | ||
258 | *pad_before_eth = 0; | ||
259 | return dev->hard_header_len; /* or return 16; ? */ | ||
260 | } else | ||
261 | return t; | ||
262 | } | ||
263 | |||
264 | static int | ||
265 | br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh) | ||
266 | { | ||
267 | /* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so | ||
268 | xmit will add the additional header part in that case */ | ||
269 | u16 *pad_before_eth = (u16 *)(hh->hh_data); | ||
270 | int t = my_eth_header_cache(neigh, hh); | ||
271 | DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh); | ||
272 | if (t < 0) | ||
273 | return t; | ||
274 | else { | ||
275 | *pad_before_eth = 0; | ||
276 | hh->hh_len = PADLEN + ETH_HLEN; | ||
277 | } | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * This is similar to eth_type_trans, which cannot be used because of | ||
283 | * our dev->hard_header_len | ||
284 | */ | ||
285 | static inline __be16 br_type_trans(struct sk_buff *skb, struct net_device *dev) | ||
286 | { | ||
287 | struct ethhdr *eth; | ||
288 | unsigned char *rawp; | ||
289 | eth = eth_hdr(skb); | ||
290 | |||
291 | if (is_multicast_ether_addr(eth->h_dest)) { | ||
292 | if (!compare_ether_addr(eth->h_dest, dev->broadcast)) | ||
293 | skb->pkt_type = PACKET_BROADCAST; | ||
294 | else | ||
295 | skb->pkt_type = PACKET_MULTICAST; | ||
296 | } | ||
297 | |||
298 | else if (compare_ether_addr(eth->h_dest, dev->dev_addr)) | ||
299 | skb->pkt_type = PACKET_OTHERHOST; | ||
300 | |||
301 | if (ntohs(eth->h_proto) >= 1536) | ||
302 | return eth->h_proto; | ||
303 | |||
304 | rawp = skb->data; | ||
305 | |||
306 | /* | ||
307 | * This is a magic hack to spot IPX packets. Older Novell breaks | ||
308 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC | ||
309 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | ||
310 | * won't work for fault tolerant netware but does for the rest. | ||
311 | */ | ||
312 | if (*(unsigned short *) rawp == 0xFFFF) | ||
313 | return htons(ETH_P_802_3); | ||
314 | |||
315 | /* | ||
316 | * Real 802.2 LLC | ||
317 | */ | ||
318 | return htons(ETH_P_802_2); | ||
319 | } | ||
320 | #endif /* FASTER_VERSION */ | ||
321 | 220 | ||
322 | /* | 221 | /* |
323 | * We remember when the MAC gets set, so we don't override it later with | 222 | * We remember when the MAC gets set, so we don't override it later with |
@@ -448,17 +347,8 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |||
448 | return; | 347 | return; |
449 | } | 348 | } |
450 | 349 | ||
451 | #ifdef FASTER_VERSION | ||
452 | /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier, | ||
453 | than should be. What else should I set? */ | ||
454 | skb_pull(skb, plen); | ||
455 | skb_set_mac_header(skb, -ETH_HLEN); | ||
456 | skb->pkt_type = PACKET_HOST; | ||
457 | skb->protocol = br_type_trans(skb, net_dev); | ||
458 | #else | ||
459 | skb_pull(skb, plen - ETH_HLEN); | 350 | skb_pull(skb, plen - ETH_HLEN); |
460 | skb->protocol = eth_type_trans(skb, net_dev); | 351 | skb->protocol = eth_type_trans(skb, net_dev); |
461 | #endif /* FASTER_VERSION */ | ||
462 | #ifdef CONFIG_ATM_BR2684_IPFILTER | 352 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
463 | if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) { | 353 | if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) { |
464 | brdev->stats.rx_dropped++; | 354 | brdev->stats.rx_dropped++; |
@@ -584,13 +474,6 @@ static void br2684_setup(struct net_device *netdev) | |||
584 | ether_setup(netdev); | 474 | ether_setup(netdev); |
585 | brdev->net_dev = netdev; | 475 | brdev->net_dev = netdev; |
586 | 476 | ||
587 | #ifdef FASTER_VERSION | ||
588 | my_eth_header = netdev->hard_header; | ||
589 | netdev->hard_header = br2684_header; | ||
590 | my_eth_header_cache = netdev->hard_header_cache; | ||
591 | netdev->hard_header_cache = br2684_header_cache; | ||
592 | netdev->hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */ | ||
593 | #endif | ||
594 | my_eth_mac_addr = netdev->set_mac_address; | 477 | my_eth_mac_addr = netdev->set_mac_address; |
595 | netdev->set_mac_address = br2684_mac_addr; | 478 | netdev->set_mac_address = br2684_mac_addr; |
596 | netdev->hard_start_xmit = br2684_start_xmit; | 479 | netdev->hard_start_xmit = br2684_start_xmit; |
@@ -719,16 +602,12 @@ static int br2684_seq_show(struct seq_file *seq, void *v) | |||
719 | 602 | ||
720 | list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { | 603 | list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { |
721 | seq_printf(seq, " vcc %d.%d.%d: encaps=%s" | 604 | seq_printf(seq, " vcc %d.%d.%d: encaps=%s" |
722 | #ifndef FASTER_VERSION | ||
723 | ", failed copies %u/%u" | 605 | ", failed copies %u/%u" |
724 | #endif /* FASTER_VERSION */ | ||
725 | "\n", brvcc->atmvcc->dev->number, | 606 | "\n", brvcc->atmvcc->dev->number, |
726 | brvcc->atmvcc->vpi, brvcc->atmvcc->vci, | 607 | brvcc->atmvcc->vpi, brvcc->atmvcc->vci, |
727 | (brvcc->encaps == e_llc) ? "LLC" : "VC" | 608 | (brvcc->encaps == e_llc) ? "LLC" : "VC" |
728 | #ifndef FASTER_VERSION | ||
729 | , brvcc->copies_failed | 609 | , brvcc->copies_failed |
730 | , brvcc->copies_needed | 610 | , brvcc->copies_needed |
731 | #endif /* FASTER_VERSION */ | ||
732 | ); | 611 | ); |
733 | #ifdef CONFIG_ATM_BR2684_IPFILTER | 612 | #ifdef CONFIG_ATM_BR2684_IPFILTER |
734 | #define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] | 613 | #define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte] |
diff --git a/net/core/filter.c b/net/core/filter.c index bd903aaf7aa7..1f0068eae501 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -387,6 +387,25 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
387 | } | 387 | } |
388 | 388 | ||
389 | /** | 389 | /** |
390 | * sk_filter_rcu_release: Release a socket filter by rcu_head | ||
391 | * @rcu: rcu_head that contains the sk_filter to free | ||
392 | */ | ||
393 | static void sk_filter_rcu_release(struct rcu_head *rcu) | ||
394 | { | ||
395 | struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); | ||
396 | |||
397 | sk_filter_release(fp); | ||
398 | } | ||
399 | |||
400 | static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp) | ||
401 | { | ||
402 | unsigned int size = sk_filter_len(fp); | ||
403 | |||
404 | atomic_sub(size, &sk->sk_omem_alloc); | ||
405 | call_rcu_bh(&fp->rcu, sk_filter_rcu_release); | ||
406 | } | ||
407 | |||
408 | /** | ||
390 | * sk_attach_filter - attach a socket filter | 409 | * sk_attach_filter - attach a socket filter |
391 | * @fprog: the filter program | 410 | * @fprog: the filter program |
392 | * @sk: the socket to use | 411 | * @sk: the socket to use |
@@ -398,7 +417,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
398 | */ | 417 | */ |
399 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | 418 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) |
400 | { | 419 | { |
401 | struct sk_filter *fp; | 420 | struct sk_filter *fp, *old_fp; |
402 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; | 421 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; |
403 | int err; | 422 | int err; |
404 | 423 | ||
@@ -418,19 +437,34 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
418 | fp->len = fprog->len; | 437 | fp->len = fprog->len; |
419 | 438 | ||
420 | err = sk_chk_filter(fp->insns, fp->len); | 439 | err = sk_chk_filter(fp->insns, fp->len); |
421 | if (!err) { | 440 | if (err) { |
422 | struct sk_filter *old_fp; | 441 | sk_filter_uncharge(sk, fp); |
423 | 442 | return err; | |
424 | rcu_read_lock_bh(); | ||
425 | old_fp = rcu_dereference(sk->sk_filter); | ||
426 | rcu_assign_pointer(sk->sk_filter, fp); | ||
427 | rcu_read_unlock_bh(); | ||
428 | fp = old_fp; | ||
429 | } | 443 | } |
430 | 444 | ||
431 | if (fp) | 445 | rcu_read_lock_bh(); |
432 | sk_filter_release(sk, fp); | 446 | old_fp = rcu_dereference(sk->sk_filter); |
433 | return err; | 447 | rcu_assign_pointer(sk->sk_filter, fp); |
448 | rcu_read_unlock_bh(); | ||
449 | |||
450 | sk_filter_delayed_uncharge(sk, old_fp); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | int sk_detach_filter(struct sock *sk) | ||
455 | { | ||
456 | int ret = -ENOENT; | ||
457 | struct sk_filter *filter; | ||
458 | |||
459 | rcu_read_lock_bh(); | ||
460 | filter = rcu_dereference(sk->sk_filter); | ||
461 | if (filter) { | ||
462 | rcu_assign_pointer(sk->sk_filter, NULL); | ||
463 | sk_filter_delayed_uncharge(sk, filter); | ||
464 | ret = 0; | ||
465 | } | ||
466 | rcu_read_unlock_bh(); | ||
467 | return ret; | ||
434 | } | 468 | } |
435 | 469 | ||
436 | EXPORT_SYMBOL(sk_chk_filter); | 470 | EXPORT_SYMBOL(sk_chk_filter); |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2100c734b102..8cae60c53383 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -2454,7 +2454,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev) | |||
2454 | spin_lock(&x->lock); | 2454 | spin_lock(&x->lock); |
2455 | iph = ip_hdr(skb); | 2455 | iph = ip_hdr(skb); |
2456 | 2456 | ||
2457 | err = x->mode->output(x, skb); | 2457 | err = x->outer_mode->output(x, skb); |
2458 | if (err) | 2458 | if (err) |
2459 | goto error; | 2459 | goto error; |
2460 | err = x->type->output(x, skb); | 2460 | err = x->type->output(x, skb); |
diff --git a/net/core/sock.c b/net/core/sock.c index d45ecdccc6a1..d292b4113d6e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -428,7 +428,6 @@ int sock_setsockopt(struct socket *sock, int level, int optname, | |||
428 | char __user *optval, int optlen) | 428 | char __user *optval, int optlen) |
429 | { | 429 | { |
430 | struct sock *sk=sock->sk; | 430 | struct sock *sk=sock->sk; |
431 | struct sk_filter *filter; | ||
432 | int val; | 431 | int val; |
433 | int valbool; | 432 | int valbool; |
434 | struct linger ling; | 433 | struct linger ling; |
@@ -652,16 +651,7 @@ set_rcvbuf: | |||
652 | break; | 651 | break; |
653 | 652 | ||
654 | case SO_DETACH_FILTER: | 653 | case SO_DETACH_FILTER: |
655 | rcu_read_lock_bh(); | 654 | ret = sk_detach_filter(sk); |
656 | filter = rcu_dereference(sk->sk_filter); | ||
657 | if (filter) { | ||
658 | rcu_assign_pointer(sk->sk_filter, NULL); | ||
659 | sk_filter_release(sk, filter); | ||
660 | rcu_read_unlock_bh(); | ||
661 | break; | ||
662 | } | ||
663 | rcu_read_unlock_bh(); | ||
664 | ret = -ENONET; | ||
665 | break; | 655 | break; |
666 | 656 | ||
667 | case SO_PASSSEC: | 657 | case SO_PASSSEC: |
@@ -925,7 +915,7 @@ void sk_free(struct sock *sk) | |||
925 | 915 | ||
926 | filter = rcu_dereference(sk->sk_filter); | 916 | filter = rcu_dereference(sk->sk_filter); |
927 | if (filter) { | 917 | if (filter) { |
928 | sk_filter_release(sk, filter); | 918 | sk_filter_uncharge(sk, filter); |
929 | rcu_assign_pointer(sk->sk_filter, NULL); | 919 | rcu_assign_pointer(sk->sk_filter, NULL); |
930 | } | 920 | } |
931 | 921 | ||
diff --git a/net/dccp/input.c b/net/dccp/input.c index 19d7e1dbd87e..3560a2a875a0 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include "ccid.h" | 19 | #include "ccid.h" |
20 | #include "dccp.h" | 20 | #include "dccp.h" |
21 | 21 | ||
22 | /* rate-limit for syncs in reply to sequence-invalid packets; RFC 4340, 7.5.4 */ | ||
23 | int sysctl_dccp_sync_ratelimit __read_mostly = HZ / 8; | ||
24 | |||
22 | static void dccp_fin(struct sock *sk, struct sk_buff *skb) | 25 | static void dccp_fin(struct sock *sk, struct sk_buff *skb) |
23 | { | 26 | { |
24 | sk->sk_shutdown |= RCV_SHUTDOWN; | 27 | sk->sk_shutdown |= RCV_SHUTDOWN; |
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 9364b2fb4dbd..c62c05039f69 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c | |||
@@ -18,9 +18,6 @@ | |||
18 | #error This file should not be compiled without CONFIG_SYSCTL defined | 18 | #error This file should not be compiled without CONFIG_SYSCTL defined |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | /* rate-limit for syncs in reply to sequence-invalid packets; RFC 4340, 7.5.4 */ | ||
22 | int sysctl_dccp_sync_ratelimit __read_mostly = HZ / 8; | ||
23 | |||
24 | static struct ctl_table dccp_default_table[] = { | 21 | static struct ctl_table dccp_default_table[] = { |
25 | { | 22 | { |
26 | .procname = "seq_window", | 23 | .procname = "seq_window", |
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 6cc54eeca3ed..72e6ab66834f 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c | |||
@@ -586,7 +586,7 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) | |||
586 | if (stype & IEEE80211_STYPE_QOS_DATA) { | 586 | if (stype & IEEE80211_STYPE_QOS_DATA) { |
587 | const struct ieee80211_hdr_3addrqos *qoshdr = | 587 | const struct ieee80211_hdr_3addrqos *qoshdr = |
588 | (struct ieee80211_hdr_3addrqos *)skb->data; | 588 | (struct ieee80211_hdr_3addrqos *)skb->data; |
589 | hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID); | 589 | hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID; |
590 | } else | 590 | } else |
591 | hdr[12] = 0; /* priority */ | 591 | hdr[12] = 0; /* priority */ |
592 | 592 | ||
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 484cf512858f..e15e04fc6661 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c | |||
@@ -136,7 +136,9 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, | |||
136 | *work -= f->qsize; | 136 | *work -= f->qsize; |
137 | atomic_sub(f->qsize, &f->mem); | 137 | atomic_sub(f->qsize, &f->mem); |
138 | 138 | ||
139 | f->destructor(q); | 139 | if (f->destructor) |
140 | f->destructor(q); | ||
141 | kfree(q); | ||
140 | 142 | ||
141 | } | 143 | } |
142 | EXPORT_SYMBOL(inet_frag_destroy); | 144 | EXPORT_SYMBOL(inet_frag_destroy); |
@@ -172,3 +174,88 @@ int inet_frag_evictor(struct inet_frags *f) | |||
172 | return evicted; | 174 | return evicted; |
173 | } | 175 | } |
174 | EXPORT_SYMBOL(inet_frag_evictor); | 176 | EXPORT_SYMBOL(inet_frag_evictor); |
177 | |||
178 | static struct inet_frag_queue *inet_frag_intern(struct inet_frag_queue *qp_in, | ||
179 | struct inet_frags *f, unsigned int hash, void *arg) | ||
180 | { | ||
181 | struct inet_frag_queue *qp; | ||
182 | #ifdef CONFIG_SMP | ||
183 | struct hlist_node *n; | ||
184 | #endif | ||
185 | |||
186 | write_lock(&f->lock); | ||
187 | #ifdef CONFIG_SMP | ||
188 | /* With SMP race we have to recheck hash table, because | ||
189 | * such entry could be created on other cpu, while we | ||
190 | * promoted read lock to write lock. | ||
191 | */ | ||
192 | hlist_for_each_entry(qp, n, &f->hash[hash], list) { | ||
193 | if (f->match(qp, arg)) { | ||
194 | atomic_inc(&qp->refcnt); | ||
195 | write_unlock(&f->lock); | ||
196 | qp_in->last_in |= COMPLETE; | ||
197 | inet_frag_put(qp_in, f); | ||
198 | return qp; | ||
199 | } | ||
200 | } | ||
201 | #endif | ||
202 | qp = qp_in; | ||
203 | if (!mod_timer(&qp->timer, jiffies + f->ctl->timeout)) | ||
204 | atomic_inc(&qp->refcnt); | ||
205 | |||
206 | atomic_inc(&qp->refcnt); | ||
207 | hlist_add_head(&qp->list, &f->hash[hash]); | ||
208 | list_add_tail(&qp->lru_list, &f->lru_list); | ||
209 | f->nqueues++; | ||
210 | write_unlock(&f->lock); | ||
211 | return qp; | ||
212 | } | ||
213 | |||
214 | static struct inet_frag_queue *inet_frag_alloc(struct inet_frags *f, void *arg) | ||
215 | { | ||
216 | struct inet_frag_queue *q; | ||
217 | |||
218 | q = kzalloc(f->qsize, GFP_ATOMIC); | ||
219 | if (q == NULL) | ||
220 | return NULL; | ||
221 | |||
222 | f->constructor(q, arg); | ||
223 | atomic_add(f->qsize, &f->mem); | ||
224 | setup_timer(&q->timer, f->frag_expire, (unsigned long)q); | ||
225 | spin_lock_init(&q->lock); | ||
226 | atomic_set(&q->refcnt, 1); | ||
227 | |||
228 | return q; | ||
229 | } | ||
230 | |||
231 | static struct inet_frag_queue *inet_frag_create(struct inet_frags *f, | ||
232 | void *arg, unsigned int hash) | ||
233 | { | ||
234 | struct inet_frag_queue *q; | ||
235 | |||
236 | q = inet_frag_alloc(f, arg); | ||
237 | if (q == NULL) | ||
238 | return NULL; | ||
239 | |||
240 | return inet_frag_intern(q, f, hash, arg); | ||
241 | } | ||
242 | |||
243 | struct inet_frag_queue *inet_frag_find(struct inet_frags *f, void *key, | ||
244 | unsigned int hash) | ||
245 | { | ||
246 | struct inet_frag_queue *q; | ||
247 | struct hlist_node *n; | ||
248 | |||
249 | read_lock(&f->lock); | ||
250 | hlist_for_each_entry(q, n, &f->hash[hash], list) { | ||
251 | if (f->match(q, key)) { | ||
252 | atomic_inc(&q->refcnt); | ||
253 | read_unlock(&f->lock); | ||
254 | return q; | ||
255 | } | ||
256 | } | ||
257 | read_unlock(&f->lock); | ||
258 | |||
259 | return inet_frag_create(f, key, hash); | ||
260 | } | ||
261 | EXPORT_SYMBOL(inet_frag_find); | ||
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 443b3f89192f..2143bf30597a 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -108,6 +108,11 @@ int ip_frag_mem(void) | |||
108 | static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | 108 | static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, |
109 | struct net_device *dev); | 109 | struct net_device *dev); |
110 | 110 | ||
111 | struct ip4_create_arg { | ||
112 | struct iphdr *iph; | ||
113 | u32 user; | ||
114 | }; | ||
115 | |||
111 | static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) | 116 | static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) |
112 | { | 117 | { |
113 | return jhash_3words((__force u32)id << 16 | prot, | 118 | return jhash_3words((__force u32)id << 16 | prot, |
@@ -123,6 +128,19 @@ static unsigned int ip4_hashfn(struct inet_frag_queue *q) | |||
123 | return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); | 128 | return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); |
124 | } | 129 | } |
125 | 130 | ||
131 | static int ip4_frag_match(struct inet_frag_queue *q, void *a) | ||
132 | { | ||
133 | struct ipq *qp; | ||
134 | struct ip4_create_arg *arg = a; | ||
135 | |||
136 | qp = container_of(q, struct ipq, q); | ||
137 | return (qp->id == arg->iph->id && | ||
138 | qp->saddr == arg->iph->saddr && | ||
139 | qp->daddr == arg->iph->daddr && | ||
140 | qp->protocol == arg->iph->protocol && | ||
141 | qp->user == arg->user); | ||
142 | } | ||
143 | |||
126 | /* Memory Tracking Functions. */ | 144 | /* Memory Tracking Functions. */ |
127 | static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) | 145 | static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) |
128 | { | 146 | { |
@@ -132,6 +150,20 @@ static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work) | |||
132 | kfree_skb(skb); | 150 | kfree_skb(skb); |
133 | } | 151 | } |
134 | 152 | ||
153 | static void ip4_frag_init(struct inet_frag_queue *q, void *a) | ||
154 | { | ||
155 | struct ipq *qp = container_of(q, struct ipq, q); | ||
156 | struct ip4_create_arg *arg = a; | ||
157 | |||
158 | qp->protocol = arg->iph->protocol; | ||
159 | qp->id = arg->iph->id; | ||
160 | qp->saddr = arg->iph->saddr; | ||
161 | qp->daddr = arg->iph->daddr; | ||
162 | qp->user = arg->user; | ||
163 | qp->peer = sysctl_ipfrag_max_dist ? | ||
164 | inet_getpeer(arg->iph->saddr, 1) : NULL; | ||
165 | } | ||
166 | |||
135 | static __inline__ void ip4_frag_free(struct inet_frag_queue *q) | 167 | static __inline__ void ip4_frag_free(struct inet_frag_queue *q) |
136 | { | 168 | { |
137 | struct ipq *qp; | 169 | struct ipq *qp; |
@@ -139,17 +171,6 @@ static __inline__ void ip4_frag_free(struct inet_frag_queue *q) | |||
139 | qp = container_of(q, struct ipq, q); | 171 | qp = container_of(q, struct ipq, q); |
140 | if (qp->peer) | 172 | if (qp->peer) |
141 | inet_putpeer(qp->peer); | 173 | inet_putpeer(qp->peer); |
142 | kfree(qp); | ||
143 | } | ||
144 | |||
145 | static __inline__ struct ipq *frag_alloc_queue(void) | ||
146 | { | ||
147 | struct ipq *qp = kzalloc(sizeof(struct ipq), GFP_ATOMIC); | ||
148 | |||
149 | if (!qp) | ||
150 | return NULL; | ||
151 | atomic_add(sizeof(struct ipq), &ip4_frags.mem); | ||
152 | return qp; | ||
153 | } | 174 | } |
154 | 175 | ||
155 | 176 | ||
@@ -185,7 +206,9 @@ static void ip_evictor(void) | |||
185 | */ | 206 | */ |
186 | static void ip_expire(unsigned long arg) | 207 | static void ip_expire(unsigned long arg) |
187 | { | 208 | { |
188 | struct ipq *qp = (struct ipq *) arg; | 209 | struct ipq *qp; |
210 | |||
211 | qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); | ||
189 | 212 | ||
190 | spin_lock(&qp->q.lock); | 213 | spin_lock(&qp->q.lock); |
191 | 214 | ||
@@ -210,112 +233,30 @@ out: | |||
210 | ipq_put(qp); | 233 | ipq_put(qp); |
211 | } | 234 | } |
212 | 235 | ||
213 | /* Creation primitives. */ | 236 | /* Find the correct entry in the "incomplete datagrams" queue for |
214 | 237 | * this IP datagram, and create new one, if nothing is found. | |
215 | static struct ipq *ip_frag_intern(struct ipq *qp_in) | 238 | */ |
239 | static inline struct ipq *ip_find(struct iphdr *iph, u32 user) | ||
216 | { | 240 | { |
217 | struct ipq *qp; | 241 | struct inet_frag_queue *q; |
218 | #ifdef CONFIG_SMP | 242 | struct ip4_create_arg arg; |
219 | struct hlist_node *n; | ||
220 | #endif | ||
221 | unsigned int hash; | 243 | unsigned int hash; |
222 | 244 | ||
223 | write_lock(&ip4_frags.lock); | 245 | arg.iph = iph; |
224 | hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr, | 246 | arg.user = user; |
225 | qp_in->protocol); | 247 | hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); |
226 | #ifdef CONFIG_SMP | ||
227 | /* With SMP race we have to recheck hash table, because | ||
228 | * such entry could be created on other cpu, while we | ||
229 | * promoted read lock to write lock. | ||
230 | */ | ||
231 | hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) { | ||
232 | if (qp->id == qp_in->id && | ||
233 | qp->saddr == qp_in->saddr && | ||
234 | qp->daddr == qp_in->daddr && | ||
235 | qp->protocol == qp_in->protocol && | ||
236 | qp->user == qp_in->user) { | ||
237 | atomic_inc(&qp->q.refcnt); | ||
238 | write_unlock(&ip4_frags.lock); | ||
239 | qp_in->q.last_in |= COMPLETE; | ||
240 | ipq_put(qp_in); | ||
241 | return qp; | ||
242 | } | ||
243 | } | ||
244 | #endif | ||
245 | qp = qp_in; | ||
246 | |||
247 | if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout)) | ||
248 | atomic_inc(&qp->q.refcnt); | ||
249 | 248 | ||
250 | atomic_inc(&qp->q.refcnt); | 249 | q = inet_frag_find(&ip4_frags, &arg, hash); |
251 | hlist_add_head(&qp->q.list, &ip4_frags.hash[hash]); | 250 | if (q == NULL) |
252 | INIT_LIST_HEAD(&qp->q.lru_list); | ||
253 | list_add_tail(&qp->q.lru_list, &ip4_frags.lru_list); | ||
254 | ip4_frags.nqueues++; | ||
255 | write_unlock(&ip4_frags.lock); | ||
256 | return qp; | ||
257 | } | ||
258 | |||
259 | /* Add an entry to the 'ipq' queue for a newly received IP datagram. */ | ||
260 | static struct ipq *ip_frag_create(struct iphdr *iph, u32 user) | ||
261 | { | ||
262 | struct ipq *qp; | ||
263 | |||
264 | if ((qp = frag_alloc_queue()) == NULL) | ||
265 | goto out_nomem; | 251 | goto out_nomem; |
266 | 252 | ||
267 | qp->protocol = iph->protocol; | 253 | return container_of(q, struct ipq, q); |
268 | qp->id = iph->id; | ||
269 | qp->saddr = iph->saddr; | ||
270 | qp->daddr = iph->daddr; | ||
271 | qp->user = user; | ||
272 | qp->peer = sysctl_ipfrag_max_dist ? inet_getpeer(iph->saddr, 1) : NULL; | ||
273 | |||
274 | /* Initialize a timer for this entry. */ | ||
275 | init_timer(&qp->q.timer); | ||
276 | qp->q.timer.data = (unsigned long) qp; /* pointer to queue */ | ||
277 | qp->q.timer.function = ip_expire; /* expire function */ | ||
278 | spin_lock_init(&qp->q.lock); | ||
279 | atomic_set(&qp->q.refcnt, 1); | ||
280 | |||
281 | return ip_frag_intern(qp); | ||
282 | 254 | ||
283 | out_nomem: | 255 | out_nomem: |
284 | LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); | 256 | LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); |
285 | return NULL; | 257 | return NULL; |
286 | } | 258 | } |
287 | 259 | ||
288 | /* Find the correct entry in the "incomplete datagrams" queue for | ||
289 | * this IP datagram, and create new one, if nothing is found. | ||
290 | */ | ||
291 | static inline struct ipq *ip_find(struct iphdr *iph, u32 user) | ||
292 | { | ||
293 | __be16 id = iph->id; | ||
294 | __be32 saddr = iph->saddr; | ||
295 | __be32 daddr = iph->daddr; | ||
296 | __u8 protocol = iph->protocol; | ||
297 | unsigned int hash; | ||
298 | struct ipq *qp; | ||
299 | struct hlist_node *n; | ||
300 | |||
301 | read_lock(&ip4_frags.lock); | ||
302 | hash = ipqhashfn(id, saddr, daddr, protocol); | ||
303 | hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) { | ||
304 | if (qp->id == id && | ||
305 | qp->saddr == saddr && | ||
306 | qp->daddr == daddr && | ||
307 | qp->protocol == protocol && | ||
308 | qp->user == user) { | ||
309 | atomic_inc(&qp->q.refcnt); | ||
310 | read_unlock(&ip4_frags.lock); | ||
311 | return qp; | ||
312 | } | ||
313 | } | ||
314 | read_unlock(&ip4_frags.lock); | ||
315 | |||
316 | return ip_frag_create(iph, user); | ||
317 | } | ||
318 | |||
319 | /* Is the fragment too far ahead to be part of ipq? */ | 260 | /* Is the fragment too far ahead to be part of ipq? */ |
320 | static inline int ip_frag_too_far(struct ipq *qp) | 261 | static inline int ip_frag_too_far(struct ipq *qp) |
321 | { | 262 | { |
@@ -545,7 +486,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
545 | if (prev) { | 486 | if (prev) { |
546 | head = prev->next; | 487 | head = prev->next; |
547 | fp = skb_clone(head, GFP_ATOMIC); | 488 | fp = skb_clone(head, GFP_ATOMIC); |
548 | |||
549 | if (!fp) | 489 | if (!fp) |
550 | goto out_nomem; | 490 | goto out_nomem; |
551 | 491 | ||
@@ -571,7 +511,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
571 | goto out_oversize; | 511 | goto out_oversize; |
572 | 512 | ||
573 | /* Head of list must not be cloned. */ | 513 | /* Head of list must not be cloned. */ |
574 | err = -ENOMEM; | ||
575 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) | 514 | if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) |
576 | goto out_nomem; | 515 | goto out_nomem; |
577 | 516 | ||
@@ -627,6 +566,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
627 | out_nomem: | 566 | out_nomem: |
628 | LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing " | 567 | LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing " |
629 | "queue %p\n", qp); | 568 | "queue %p\n", qp); |
569 | err = -ENOMEM; | ||
630 | goto out_fail; | 570 | goto out_fail; |
631 | out_oversize: | 571 | out_oversize: |
632 | if (net_ratelimit()) | 572 | if (net_ratelimit()) |
@@ -671,9 +611,12 @@ void __init ipfrag_init(void) | |||
671 | { | 611 | { |
672 | ip4_frags.ctl = &ip4_frags_ctl; | 612 | ip4_frags.ctl = &ip4_frags_ctl; |
673 | ip4_frags.hashfn = ip4_hashfn; | 613 | ip4_frags.hashfn = ip4_hashfn; |
614 | ip4_frags.constructor = ip4_frag_init; | ||
674 | ip4_frags.destructor = ip4_frag_free; | 615 | ip4_frags.destructor = ip4_frag_free; |
675 | ip4_frags.skb_free = NULL; | 616 | ip4_frags.skb_free = NULL; |
676 | ip4_frags.qsize = sizeof(struct ipq); | 617 | ip4_frags.qsize = sizeof(struct ipq); |
618 | ip4_frags.match = ip4_frag_match; | ||
619 | ip4_frags.frag_expire = ip_expire; | ||
677 | inet_frags_init(&ip4_frags); | 620 | inet_frags_init(&ip4_frags); |
678 | } | 621 | } |
679 | 622 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0f00966b1784..9288220b73a8 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1121,7 +1121,7 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) | |||
1121 | struct sk_buff *skb; | 1121 | struct sk_buff *skb; |
1122 | int flag = 0; | 1122 | int flag = 0; |
1123 | int cnt = 0; | 1123 | int cnt = 0; |
1124 | u32 new_low_seq = 0; | 1124 | u32 new_low_seq = tp->snd_nxt; |
1125 | 1125 | ||
1126 | tcp_for_write_queue(skb, sk) { | 1126 | tcp_for_write_queue(skb, sk) { |
1127 | u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; | 1127 | u32 ack_seq = TCP_SKB_CB(skb)->ack_seq; |
@@ -1153,7 +1153,7 @@ static int tcp_mark_lost_retrans(struct sock *sk, u32 received_upto) | |||
1153 | NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); | 1153 | NET_INC_STATS_BH(LINUX_MIB_TCPLOSTRETRANSMIT); |
1154 | } | 1154 | } |
1155 | } else { | 1155 | } else { |
1156 | if (!new_low_seq || before(ack_seq, new_low_seq)) | 1156 | if (before(ack_seq, new_low_seq)) |
1157 | new_low_seq = ack_seq; | 1157 | new_low_seq = ack_seq; |
1158 | cnt += tcp_skb_pcount(skb); | 1158 | cnt += tcp_skb_pcount(skb); |
1159 | } | 1159 | } |
@@ -1242,7 +1242,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1242 | int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; | 1242 | int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3; |
1243 | int reord = tp->packets_out; | 1243 | int reord = tp->packets_out; |
1244 | int prior_fackets; | 1244 | int prior_fackets; |
1245 | u32 highest_sack_end_seq = 0; | 1245 | u32 highest_sack_end_seq = tp->lost_retrans_low; |
1246 | int flag = 0; | 1246 | int flag = 0; |
1247 | int found_dup_sack = 0; | 1247 | int found_dup_sack = 0; |
1248 | int cached_fack_count; | 1248 | int cached_fack_count; |
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index e9bbfde19ac3..5e95c8a07efb 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c | |||
@@ -16,19 +16,6 @@ | |||
16 | #include <net/ip.h> | 16 | #include <net/ip.h> |
17 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
18 | 18 | ||
19 | static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | ||
20 | { | ||
21 | switch (nexthdr) { | ||
22 | case IPPROTO_IPIP: | ||
23 | case IPPROTO_IPV6: | ||
24 | *spi = ip_hdr(skb)->saddr; | ||
25 | *seq = 0; | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | return xfrm_parse_spi(skb, nexthdr, spi, seq); | ||
30 | } | ||
31 | |||
32 | #ifdef CONFIG_NETFILTER | 19 | #ifdef CONFIG_NETFILTER |
33 | static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) | 20 | static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb) |
34 | { | 21 | { |
@@ -46,28 +33,29 @@ drop: | |||
46 | } | 33 | } |
47 | #endif | 34 | #endif |
48 | 35 | ||
49 | static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) | 36 | int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
37 | int encap_type) | ||
50 | { | 38 | { |
51 | __be32 spi, seq; | 39 | int err; |
40 | __be32 seq; | ||
52 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; | 41 | struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH]; |
53 | struct xfrm_state *x; | 42 | struct xfrm_state *x; |
54 | int xfrm_nr = 0; | 43 | int xfrm_nr = 0; |
55 | int decaps = 0; | 44 | int decaps = 0; |
56 | int err = xfrm4_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq); | ||
57 | unsigned int nhoff = offsetof(struct iphdr, protocol); | 45 | unsigned int nhoff = offsetof(struct iphdr, protocol); |
58 | 46 | ||
59 | if (err != 0) | 47 | seq = 0; |
48 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | ||
60 | goto drop; | 49 | goto drop; |
61 | 50 | ||
62 | do { | 51 | do { |
63 | const struct iphdr *iph = ip_hdr(skb); | 52 | const struct iphdr *iph = ip_hdr(skb); |
64 | int nexthdr; | ||
65 | 53 | ||
66 | if (xfrm_nr == XFRM_MAX_DEPTH) | 54 | if (xfrm_nr == XFRM_MAX_DEPTH) |
67 | goto drop; | 55 | goto drop; |
68 | 56 | ||
69 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, | 57 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, |
70 | iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET); | 58 | nexthdr, AF_INET); |
71 | if (x == NULL) | 59 | if (x == NULL) |
72 | goto drop; | 60 | goto drop; |
73 | 61 | ||
@@ -103,15 +91,15 @@ static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) | |||
103 | 91 | ||
104 | xfrm_vec[xfrm_nr++] = x; | 92 | xfrm_vec[xfrm_nr++] = x; |
105 | 93 | ||
106 | if (x->mode->input(x, skb)) | 94 | if (x->outer_mode->input(x, skb)) |
107 | goto drop; | 95 | goto drop; |
108 | 96 | ||
109 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 97 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
110 | decaps = 1; | 98 | decaps = 1; |
111 | break; | 99 | break; |
112 | } | 100 | } |
113 | 101 | ||
114 | err = xfrm_parse_spi(skb, ip_hdr(skb)->protocol, &spi, &seq); | 102 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
115 | if (err < 0) | 103 | if (err < 0) |
116 | goto drop; | 104 | goto drop; |
117 | } while (!err); | 105 | } while (!err); |
@@ -165,6 +153,7 @@ drop: | |||
165 | kfree_skb(skb); | 153 | kfree_skb(skb); |
166 | return 0; | 154 | return 0; |
167 | } | 155 | } |
156 | EXPORT_SYMBOL(xfrm4_rcv_encap); | ||
168 | 157 | ||
169 | /* If it's a keepalive packet, then just eat it. | 158 | /* If it's a keepalive packet, then just eat it. |
170 | * If it's an encapsulated packet, then pass it to the | 159 | * If it's an encapsulated packet, then pass it to the |
@@ -252,11 +241,8 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) | |||
252 | __skb_pull(skb, len); | 241 | __skb_pull(skb, len); |
253 | skb_reset_transport_header(skb); | 242 | skb_reset_transport_header(skb); |
254 | 243 | ||
255 | /* modify the protocol (it's ESP!) */ | ||
256 | iph->protocol = IPPROTO_ESP; | ||
257 | |||
258 | /* process ESP */ | 244 | /* process ESP */ |
259 | ret = xfrm4_rcv_encap(skb, encap_type); | 245 | ret = xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type); |
260 | return ret; | 246 | return ret; |
261 | 247 | ||
262 | drop: | 248 | drop: |
@@ -266,7 +252,7 @@ drop: | |||
266 | 252 | ||
267 | int xfrm4_rcv(struct sk_buff *skb) | 253 | int xfrm4_rcv(struct sk_buff *skb) |
268 | { | 254 | { |
269 | return xfrm4_rcv_encap(skb, 0); | 255 | return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0); |
270 | } | 256 | } |
271 | 257 | ||
272 | EXPORT_SYMBOL(xfrm4_rcv); | 258 | EXPORT_SYMBOL(xfrm4_rcv); |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index 73d2338bec55..e42e122414be 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c | |||
@@ -114,6 +114,7 @@ static struct xfrm_mode xfrm4_beet_mode = { | |||
114 | .output = xfrm4_beet_output, | 114 | .output = xfrm4_beet_output, |
115 | .owner = THIS_MODULE, | 115 | .owner = THIS_MODULE, |
116 | .encap = XFRM_MODE_BEET, | 116 | .encap = XFRM_MODE_BEET, |
117 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
117 | }; | 118 | }; |
118 | 119 | ||
119 | static int __init xfrm4_beet_init(void) | 120 | static int __init xfrm4_beet_init(void) |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 1ae9d32276f0..e4deecba6dd2 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -139,6 +139,7 @@ static struct xfrm_mode xfrm4_tunnel_mode = { | |||
139 | .output = xfrm4_tunnel_output, | 139 | .output = xfrm4_tunnel_output, |
140 | .owner = THIS_MODULE, | 140 | .owner = THIS_MODULE, |
141 | .encap = XFRM_MODE_TUNNEL, | 141 | .encap = XFRM_MODE_TUNNEL, |
142 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
142 | }; | 143 | }; |
143 | 144 | ||
144 | static int __init xfrm4_tunnel_init(void) | 145 | static int __init xfrm4_tunnel_init(void) |
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index a4edd666318b..c4a7156962bd 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -47,7 +47,7 @@ static inline int xfrm4_output_one(struct sk_buff *skb) | |||
47 | struct iphdr *iph; | 47 | struct iphdr *iph; |
48 | int err; | 48 | int err; |
49 | 49 | ||
50 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 50 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
51 | err = xfrm4_tunnel_check_size(skb); | 51 | err = xfrm4_tunnel_check_size(skb); |
52 | if (err) | 52 | if (err) |
53 | goto error_nolock; | 53 | goto error_nolock; |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 329825ca68fe..cc86fb110dd8 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -117,7 +117,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
117 | header_len += xfrm[i]->props.header_len; | 117 | header_len += xfrm[i]->props.header_len; |
118 | trailer_len += xfrm[i]->props.trailer_len; | 118 | trailer_len += xfrm[i]->props.trailer_len; |
119 | 119 | ||
120 | if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL) { | 120 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
121 | unsigned short encap_family = xfrm[i]->props.family; | 121 | unsigned short encap_family = xfrm[i]->props.family; |
122 | switch (encap_family) { | 122 | switch (encap_family) { |
123 | case AF_INET: | 123 | case AF_INET: |
@@ -151,7 +151,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
151 | i = 0; | 151 | i = 0; |
152 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 152 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
153 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 153 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
154 | struct xfrm_state_afinfo *afinfo; | ||
155 | x->u.rt.fl = *fl; | 154 | x->u.rt.fl = *fl; |
156 | 155 | ||
157 | dst_prev->xfrm = xfrm[i++]; | 156 | dst_prev->xfrm = xfrm[i++]; |
@@ -169,27 +168,17 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
169 | /* Copy neighbout for reachability confirmation */ | 168 | /* Copy neighbout for reachability confirmation */ |
170 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 169 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
171 | dst_prev->input = rt->u.dst.input; | 170 | dst_prev->input = rt->u.dst.input; |
172 | /* XXX: When IPv6 module can be unloaded, we should manage reference | 171 | dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output; |
173 | * to xfrm6_output in afinfo->output. Miyazawa | 172 | if (rt0->peer) |
174 | * */ | 173 | atomic_inc(&rt0->peer->refcnt); |
175 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | 174 | x->u.rt.peer = rt0->peer; |
176 | if (!afinfo) { | ||
177 | dst = *dst_p; | ||
178 | err = -EAFNOSUPPORT; | ||
179 | goto error; | ||
180 | } | ||
181 | dst_prev->output = afinfo->output; | ||
182 | xfrm_state_put_afinfo(afinfo); | ||
183 | if (dst_prev->xfrm->props.family == AF_INET && rt->peer) | ||
184 | atomic_inc(&rt->peer->refcnt); | ||
185 | x->u.rt.peer = rt->peer; | ||
186 | /* Sheit... I remember I did this right. Apparently, | 175 | /* Sheit... I remember I did this right. Apparently, |
187 | * it was magically lost, so this code needs audit */ | 176 | * it was magically lost, so this code needs audit */ |
188 | x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); | 177 | x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); |
189 | x->u.rt.rt_type = rt->rt_type; | 178 | x->u.rt.rt_type = rt0->rt_type; |
190 | x->u.rt.rt_src = rt0->rt_src; | 179 | x->u.rt.rt_src = rt0->rt_src; |
191 | x->u.rt.rt_dst = rt0->rt_dst; | 180 | x->u.rt.rt_dst = rt0->rt_dst; |
192 | x->u.rt.rt_gateway = rt->rt_gateway; | 181 | x->u.rt.rt_gateway = rt0->rt_gateway; |
193 | x->u.rt.rt_spec_dst = rt0->rt_spec_dst; | 182 | x->u.rt.rt_spec_dst = rt0->rt_spec_dst; |
194 | x->u.rt.idev = rt0->idev; | 183 | x->u.rt.idev = rt0->idev; |
195 | in_dev_hold(rt0->idev); | 184 | in_dev_hold(rt0->idev); |
@@ -291,7 +280,7 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) | |||
291 | 280 | ||
292 | if (likely(xdst->u.rt.idev)) | 281 | if (likely(xdst->u.rt.idev)) |
293 | in_dev_put(xdst->u.rt.idev); | 282 | in_dev_put(xdst->u.rt.idev); |
294 | if (dst->xfrm && dst->xfrm->props.family == AF_INET && likely(xdst->u.rt.peer)) | 283 | if (likely(xdst->u.rt.peer)) |
295 | inet_putpeer(xdst->u.rt.peer); | 284 | inet_putpeer(xdst->u.rt.peer); |
296 | xfrm_dst_destroy(xdst); | 285 | xfrm_dst_destroy(xdst); |
297 | } | 286 | } |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 93e2c061cdda..13d54a1c3337 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -49,6 +49,7 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
49 | 49 | ||
50 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { | 50 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { |
51 | .family = AF_INET, | 51 | .family = AF_INET, |
52 | .owner = THIS_MODULE, | ||
52 | .init_flags = xfrm4_init_flags, | 53 | .init_flags = xfrm4_init_flags, |
53 | .init_tempsel = __xfrm4_init_tempsel, | 54 | .init_tempsel = __xfrm4_init_tempsel, |
54 | .output = xfrm4_output, | 55 | .output = xfrm4_output, |
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 1312417608e2..326845195620 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c | |||
@@ -18,7 +18,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) | |||
18 | 18 | ||
19 | static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) | 19 | static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) |
20 | { | 20 | { |
21 | return IPPROTO_IP; | 21 | return ip_hdr(skb)->protocol; |
22 | } | 22 | } |
23 | 23 | ||
24 | static int ipip_init_state(struct xfrm_state *x) | 24 | static int ipip_init_state(struct xfrm_state *x) |
@@ -48,20 +48,25 @@ static struct xfrm_type ipip_type = { | |||
48 | .output = ipip_output | 48 | .output = ipip_output |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static int xfrm_tunnel_rcv(struct sk_buff *skb) | ||
52 | { | ||
53 | return xfrm4_rcv_spi(skb, IPPROTO_IP, ip_hdr(skb)->saddr); | ||
54 | } | ||
55 | |||
51 | static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) | 56 | static int xfrm_tunnel_err(struct sk_buff *skb, u32 info) |
52 | { | 57 | { |
53 | return -ENOENT; | 58 | return -ENOENT; |
54 | } | 59 | } |
55 | 60 | ||
56 | static struct xfrm_tunnel xfrm_tunnel_handler = { | 61 | static struct xfrm_tunnel xfrm_tunnel_handler = { |
57 | .handler = xfrm4_rcv, | 62 | .handler = xfrm_tunnel_rcv, |
58 | .err_handler = xfrm_tunnel_err, | 63 | .err_handler = xfrm_tunnel_err, |
59 | .priority = 2, | 64 | .priority = 2, |
60 | }; | 65 | }; |
61 | 66 | ||
62 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 67 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
63 | static struct xfrm_tunnel xfrm64_tunnel_handler = { | 68 | static struct xfrm_tunnel xfrm64_tunnel_handler = { |
64 | .handler = xfrm4_rcv, | 69 | .handler = xfrm_tunnel_rcv, |
65 | .err_handler = xfrm_tunnel_err, | 70 | .err_handler = xfrm_tunnel_err, |
66 | .priority = 2, | 71 | .priority = 2, |
67 | }; | 72 | }; |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 52d10d213217..348bd8d06112 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -255,11 +255,6 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
255 | 255 | ||
256 | static int snmp6_alloc_dev(struct inet6_dev *idev) | 256 | static int snmp6_alloc_dev(struct inet6_dev *idev) |
257 | { | 257 | { |
258 | int err = -ENOMEM; | ||
259 | |||
260 | if (!idev || !idev->dev) | ||
261 | return -EINVAL; | ||
262 | |||
263 | if (snmp_mib_init((void **)idev->stats.ipv6, | 258 | if (snmp_mib_init((void **)idev->stats.ipv6, |
264 | sizeof(struct ipstats_mib), | 259 | sizeof(struct ipstats_mib), |
265 | __alignof__(struct ipstats_mib)) < 0) | 260 | __alignof__(struct ipstats_mib)) < 0) |
@@ -280,15 +275,14 @@ err_icmpmsg: | |||
280 | err_icmp: | 275 | err_icmp: |
281 | snmp_mib_free((void **)idev->stats.ipv6); | 276 | snmp_mib_free((void **)idev->stats.ipv6); |
282 | err_ip: | 277 | err_ip: |
283 | return err; | 278 | return -ENOMEM; |
284 | } | 279 | } |
285 | 280 | ||
286 | static int snmp6_free_dev(struct inet6_dev *idev) | 281 | static void snmp6_free_dev(struct inet6_dev *idev) |
287 | { | 282 | { |
288 | snmp_mib_free((void **)idev->stats.icmpv6msg); | 283 | snmp_mib_free((void **)idev->stats.icmpv6msg); |
289 | snmp_mib_free((void **)idev->stats.icmpv6); | 284 | snmp_mib_free((void **)idev->stats.icmpv6); |
290 | snmp_mib_free((void **)idev->stats.ipv6); | 285 | snmp_mib_free((void **)idev->stats.ipv6); |
291 | return 0; | ||
292 | } | 286 | } |
293 | 287 | ||
294 | /* Nobody refers to this device, we may destroy it. */ | 288 | /* Nobody refers to this device, we may destroy it. */ |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index bc929381fa46..1b1caf3aa1c1 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -747,6 +747,7 @@ static void cleanup_ipv6_mibs(void) | |||
747 | { | 747 | { |
748 | snmp_mib_free((void **)ipv6_statistics); | 748 | snmp_mib_free((void **)ipv6_statistics); |
749 | snmp_mib_free((void **)icmpv6_statistics); | 749 | snmp_mib_free((void **)icmpv6_statistics); |
750 | snmp_mib_free((void **)icmpv6msg_statistics); | ||
750 | snmp_mib_free((void **)udp_stats_in6); | 751 | snmp_mib_free((void **)udp_stats_in6); |
751 | snmp_mib_free((void **)udplite_stats_in6); | 752 | snmp_mib_free((void **)udplite_stats_in6); |
752 | } | 753 | } |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index f9f689162692..67cd06613a25 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -344,6 +344,8 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
344 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | 344 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) |
345 | goto out; | 345 | goto out; |
346 | 346 | ||
347 | skb->ip_summed = CHECKSUM_NONE; | ||
348 | |||
347 | hdr_len = skb->data - skb_network_header(skb); | 349 | hdr_len = skb->data - skb_network_header(skb); |
348 | ah = (struct ip_auth_hdr *)skb->data; | 350 | ah = (struct ip_auth_hdr *)skb->data; |
349 | ahp = x->data; | 351 | ahp = x->data; |
@@ -475,8 +477,15 @@ static int ah6_init_state(struct xfrm_state *x) | |||
475 | 477 | ||
476 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + | 478 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + |
477 | ahp->icv_trunc_len); | 479 | ahp->icv_trunc_len); |
478 | if (x->props.mode == XFRM_MODE_TUNNEL) | 480 | switch (x->props.mode) { |
481 | case XFRM_MODE_BEET: | ||
482 | case XFRM_MODE_TRANSPORT: | ||
483 | break; | ||
484 | case XFRM_MODE_TUNNEL: | ||
479 | x->props.header_len += sizeof(struct ipv6hdr); | 485 | x->props.header_len += sizeof(struct ipv6hdr); |
486 | default: | ||
487 | goto error; | ||
488 | } | ||
480 | x->data = ahp; | 489 | x->data = ahp; |
481 | 490 | ||
482 | return 0; | 491 | return 0; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 9eb928598351..b0715432e454 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -354,8 +354,15 @@ static int esp6_init_state(struct xfrm_state *x) | |||
354 | (x->ealg->alg_key_len + 7) / 8)) | 354 | (x->ealg->alg_key_len + 7) / 8)) |
355 | goto error; | 355 | goto error; |
356 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; | 356 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; |
357 | if (x->props.mode == XFRM_MODE_TUNNEL) | 357 | switch (x->props.mode) { |
358 | case XFRM_MODE_BEET: | ||
359 | case XFRM_MODE_TRANSPORT: | ||
360 | break; | ||
361 | case XFRM_MODE_TUNNEL: | ||
358 | x->props.header_len += sizeof(struct ipv6hdr); | 362 | x->props.header_len += sizeof(struct ipv6hdr); |
363 | default: | ||
364 | goto error; | ||
365 | } | ||
359 | x->data = esp; | 366 | x->data = esp; |
360 | return 0; | 367 | return 0; |
361 | 368 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 217d60f9fc80..b12cc22e7745 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -154,8 +154,10 @@ static void ip6_fl_gc(unsigned long dummy) | |||
154 | write_unlock(&ip6_fl_lock); | 154 | write_unlock(&ip6_fl_lock); |
155 | } | 155 | } |
156 | 156 | ||
157 | static int fl_intern(struct ip6_flowlabel *fl, __be32 label) | 157 | static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) |
158 | { | 158 | { |
159 | struct ip6_flowlabel *lfl; | ||
160 | |||
159 | fl->label = label & IPV6_FLOWLABEL_MASK; | 161 | fl->label = label & IPV6_FLOWLABEL_MASK; |
160 | 162 | ||
161 | write_lock_bh(&ip6_fl_lock); | 163 | write_lock_bh(&ip6_fl_lock); |
@@ -163,12 +165,26 @@ static int fl_intern(struct ip6_flowlabel *fl, __be32 label) | |||
163 | for (;;) { | 165 | for (;;) { |
164 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; | 166 | fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; |
165 | if (fl->label) { | 167 | if (fl->label) { |
166 | struct ip6_flowlabel *lfl; | ||
167 | lfl = __fl_lookup(fl->label); | 168 | lfl = __fl_lookup(fl->label); |
168 | if (lfl == NULL) | 169 | if (lfl == NULL) |
169 | break; | 170 | break; |
170 | } | 171 | } |
171 | } | 172 | } |
173 | } else { | ||
174 | /* | ||
175 | * we dropper the ip6_fl_lock, so this entry could reappear | ||
176 | * and we need to recheck with it. | ||
177 | * | ||
178 | * OTOH no need to search the active socket first, like it is | ||
179 | * done in ipv6_flowlabel_opt - sock is locked, so new entry | ||
180 | * with the same label can only appear on another sock | ||
181 | */ | ||
182 | lfl = __fl_lookup(fl->label); | ||
183 | if (lfl != NULL) { | ||
184 | atomic_inc(&lfl->users); | ||
185 | write_unlock_bh(&ip6_fl_lock); | ||
186 | return lfl; | ||
187 | } | ||
172 | } | 188 | } |
173 | 189 | ||
174 | fl->lastuse = jiffies; | 190 | fl->lastuse = jiffies; |
@@ -176,7 +192,7 @@ static int fl_intern(struct ip6_flowlabel *fl, __be32 label) | |||
176 | fl_ht[FL_HASH(fl->label)] = fl; | 192 | fl_ht[FL_HASH(fl->label)] = fl; |
177 | atomic_inc(&fl_size); | 193 | atomic_inc(&fl_size); |
178 | write_unlock_bh(&ip6_fl_lock); | 194 | write_unlock_bh(&ip6_fl_lock); |
179 | return 0; | 195 | return NULL; |
180 | } | 196 | } |
181 | 197 | ||
182 | 198 | ||
@@ -190,14 +206,17 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) | |||
190 | 206 | ||
191 | label &= IPV6_FLOWLABEL_MASK; | 207 | label &= IPV6_FLOWLABEL_MASK; |
192 | 208 | ||
209 | read_lock_bh(&ip6_sk_fl_lock); | ||
193 | for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) { | 210 | for (sfl=np->ipv6_fl_list; sfl; sfl = sfl->next) { |
194 | struct ip6_flowlabel *fl = sfl->fl; | 211 | struct ip6_flowlabel *fl = sfl->fl; |
195 | if (fl->label == label) { | 212 | if (fl->label == label) { |
196 | fl->lastuse = jiffies; | 213 | fl->lastuse = jiffies; |
197 | atomic_inc(&fl->users); | 214 | atomic_inc(&fl->users); |
215 | read_unlock_bh(&ip6_sk_fl_lock); | ||
198 | return fl; | 216 | return fl; |
199 | } | 217 | } |
200 | } | 218 | } |
219 | read_unlock_bh(&ip6_sk_fl_lock); | ||
201 | return NULL; | 220 | return NULL; |
202 | } | 221 | } |
203 | 222 | ||
@@ -409,6 +428,16 @@ static int ipv6_opt_cmp(struct ipv6_txoptions *o1, struct ipv6_txoptions *o2) | |||
409 | return 0; | 428 | return 0; |
410 | } | 429 | } |
411 | 430 | ||
431 | static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, | ||
432 | struct ip6_flowlabel *fl) | ||
433 | { | ||
434 | write_lock_bh(&ip6_sk_fl_lock); | ||
435 | sfl->fl = fl; | ||
436 | sfl->next = np->ipv6_fl_list; | ||
437 | np->ipv6_fl_list = sfl; | ||
438 | write_unlock_bh(&ip6_sk_fl_lock); | ||
439 | } | ||
440 | |||
412 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 441 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) |
413 | { | 442 | { |
414 | int err; | 443 | int err; |
@@ -416,7 +445,8 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
416 | struct in6_flowlabel_req freq; | 445 | struct in6_flowlabel_req freq; |
417 | struct ipv6_fl_socklist *sfl1=NULL; | 446 | struct ipv6_fl_socklist *sfl1=NULL; |
418 | struct ipv6_fl_socklist *sfl, **sflp; | 447 | struct ipv6_fl_socklist *sfl, **sflp; |
419 | struct ip6_flowlabel *fl; | 448 | struct ip6_flowlabel *fl, *fl1 = NULL; |
449 | |||
420 | 450 | ||
421 | if (optlen < sizeof(freq)) | 451 | if (optlen < sizeof(freq)) |
422 | return -EINVAL; | 452 | return -EINVAL; |
@@ -472,8 +502,6 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
472 | sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL); | 502 | sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL); |
473 | 503 | ||
474 | if (freq.flr_label) { | 504 | if (freq.flr_label) { |
475 | struct ip6_flowlabel *fl1 = NULL; | ||
476 | |||
477 | err = -EEXIST; | 505 | err = -EEXIST; |
478 | read_lock_bh(&ip6_sk_fl_lock); | 506 | read_lock_bh(&ip6_sk_fl_lock); |
479 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { | 507 | for (sfl = np->ipv6_fl_list; sfl; sfl = sfl->next) { |
@@ -492,6 +520,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
492 | if (fl1 == NULL) | 520 | if (fl1 == NULL) |
493 | fl1 = fl_lookup(freq.flr_label); | 521 | fl1 = fl_lookup(freq.flr_label); |
494 | if (fl1) { | 522 | if (fl1) { |
523 | recheck: | ||
495 | err = -EEXIST; | 524 | err = -EEXIST; |
496 | if (freq.flr_flags&IPV6_FL_F_EXCL) | 525 | if (freq.flr_flags&IPV6_FL_F_EXCL) |
497 | goto release; | 526 | goto release; |
@@ -513,11 +542,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
513 | fl1->linger = fl->linger; | 542 | fl1->linger = fl->linger; |
514 | if ((long)(fl->expires - fl1->expires) > 0) | 543 | if ((long)(fl->expires - fl1->expires) > 0) |
515 | fl1->expires = fl->expires; | 544 | fl1->expires = fl->expires; |
516 | write_lock_bh(&ip6_sk_fl_lock); | 545 | fl_link(np, sfl1, fl1); |
517 | sfl1->fl = fl1; | ||
518 | sfl1->next = np->ipv6_fl_list; | ||
519 | np->ipv6_fl_list = sfl1; | ||
520 | write_unlock_bh(&ip6_sk_fl_lock); | ||
521 | fl_free(fl); | 546 | fl_free(fl); |
522 | return 0; | 547 | return 0; |
523 | 548 | ||
@@ -534,9 +559,9 @@ release: | |||
534 | if (sfl1 == NULL || (err = mem_check(sk)) != 0) | 559 | if (sfl1 == NULL || (err = mem_check(sk)) != 0) |
535 | goto done; | 560 | goto done; |
536 | 561 | ||
537 | err = fl_intern(fl, freq.flr_label); | 562 | fl1 = fl_intern(fl, freq.flr_label); |
538 | if (err) | 563 | if (fl1 != NULL) |
539 | goto done; | 564 | goto recheck; |
540 | 565 | ||
541 | if (!freq.flr_label) { | 566 | if (!freq.flr_label) { |
542 | if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label, | 567 | if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label, |
@@ -545,9 +570,7 @@ release: | |||
545 | } | 570 | } |
546 | } | 571 | } |
547 | 572 | ||
548 | sfl1->fl = fl; | 573 | fl_link(np, sfl1, fl); |
549 | sfl1->next = np->ipv6_fl_list; | ||
550 | np->ipv6_fl_list = sfl1; | ||
551 | return 0; | 574 | return 0; |
552 | 575 | ||
553 | default: | 576 | default: |
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 28fc8edfdc3a..80ef2a1d39fd 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -411,8 +411,15 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
411 | goto out; | 411 | goto out; |
412 | 412 | ||
413 | x->props.header_len = 0; | 413 | x->props.header_len = 0; |
414 | if (x->props.mode == XFRM_MODE_TUNNEL) | 414 | switch (x->props.mode) { |
415 | case XFRM_MODE_BEET: | ||
416 | case XFRM_MODE_TRANSPORT: | ||
417 | break; | ||
418 | case XFRM_MODE_TUNNEL: | ||
415 | x->props.header_len += sizeof(struct ipv6hdr); | 419 | x->props.header_len += sizeof(struct ipv6hdr); |
420 | default: | ||
421 | goto error; | ||
422 | } | ||
416 | 423 | ||
417 | mutex_lock(&ipcomp6_resource_mutex); | 424 | mutex_lock(&ipcomp6_resource_mutex); |
418 | if (!ipcomp6_alloc_scratches()) | 425 | if (!ipcomp6_alloc_scratches()) |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 726fafd41961..e170c67c47a5 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -130,22 +130,6 @@ static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work) | |||
130 | kfree_skb(skb); | 130 | kfree_skb(skb); |
131 | } | 131 | } |
132 | 132 | ||
133 | static void nf_frag_free(struct inet_frag_queue *q) | ||
134 | { | ||
135 | kfree(container_of(q, struct nf_ct_frag6_queue, q)); | ||
136 | } | ||
137 | |||
138 | static inline struct nf_ct_frag6_queue *frag_alloc_queue(void) | ||
139 | { | ||
140 | struct nf_ct_frag6_queue *fq; | ||
141 | |||
142 | fq = kzalloc(sizeof(struct nf_ct_frag6_queue), GFP_ATOMIC); | ||
143 | if (fq == NULL) | ||
144 | return NULL; | ||
145 | atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_frags.mem); | ||
146 | return fq; | ||
147 | } | ||
148 | |||
149 | /* Destruction primitives. */ | 133 | /* Destruction primitives. */ |
150 | 134 | ||
151 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) | 135 | static __inline__ void fq_put(struct nf_ct_frag6_queue *fq) |
@@ -168,7 +152,10 @@ static void nf_ct_frag6_evictor(void) | |||
168 | 152 | ||
169 | static void nf_ct_frag6_expire(unsigned long data) | 153 | static void nf_ct_frag6_expire(unsigned long data) |
170 | { | 154 | { |
171 | struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data; | 155 | struct nf_ct_frag6_queue *fq; |
156 | |||
157 | fq = container_of((struct inet_frag_queue *)data, | ||
158 | struct nf_ct_frag6_queue, q); | ||
172 | 159 | ||
173 | spin_lock(&fq->q.lock); | 160 | spin_lock(&fq->q.lock); |
174 | 161 | ||
@@ -184,89 +171,29 @@ out: | |||
184 | 171 | ||
185 | /* Creation primitives. */ | 172 | /* Creation primitives. */ |
186 | 173 | ||
187 | static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash, | 174 | static __inline__ struct nf_ct_frag6_queue * |
188 | struct nf_ct_frag6_queue *fq_in) | 175 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) |
189 | { | 176 | { |
190 | struct nf_ct_frag6_queue *fq; | 177 | struct inet_frag_queue *q; |
191 | #ifdef CONFIG_SMP | 178 | struct ip6_create_arg arg; |
192 | struct hlist_node *n; | 179 | unsigned int hash; |
193 | #endif | ||
194 | |||
195 | write_lock(&nf_frags.lock); | ||
196 | #ifdef CONFIG_SMP | ||
197 | hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) { | ||
198 | if (fq->id == fq_in->id && | ||
199 | ipv6_addr_equal(&fq_in->saddr, &fq->saddr) && | ||
200 | ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) { | ||
201 | atomic_inc(&fq->q.refcnt); | ||
202 | write_unlock(&nf_frags.lock); | ||
203 | fq_in->q.last_in |= COMPLETE; | ||
204 | fq_put(fq_in); | ||
205 | return fq; | ||
206 | } | ||
207 | } | ||
208 | #endif | ||
209 | fq = fq_in; | ||
210 | |||
211 | if (!mod_timer(&fq->q.timer, jiffies + nf_frags_ctl.timeout)) | ||
212 | atomic_inc(&fq->q.refcnt); | ||
213 | |||
214 | atomic_inc(&fq->q.refcnt); | ||
215 | hlist_add_head(&fq->q.list, &nf_frags.hash[hash]); | ||
216 | INIT_LIST_HEAD(&fq->q.lru_list); | ||
217 | list_add_tail(&fq->q.lru_list, &nf_frags.lru_list); | ||
218 | nf_frags.nqueues++; | ||
219 | write_unlock(&nf_frags.lock); | ||
220 | return fq; | ||
221 | } | ||
222 | 180 | ||
181 | arg.id = id; | ||
182 | arg.src = src; | ||
183 | arg.dst = dst; | ||
184 | hash = ip6qhashfn(id, src, dst); | ||
223 | 185 | ||
224 | static struct nf_ct_frag6_queue * | 186 | q = inet_frag_find(&nf_frags, &arg, hash); |
225 | nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src, struct in6_addr *dst) | 187 | if (q == NULL) |
226 | { | ||
227 | struct nf_ct_frag6_queue *fq; | ||
228 | |||
229 | if ((fq = frag_alloc_queue()) == NULL) { | ||
230 | pr_debug("Can't alloc new queue\n"); | ||
231 | goto oom; | 188 | goto oom; |
232 | } | ||
233 | |||
234 | fq->id = id; | ||
235 | ipv6_addr_copy(&fq->saddr, src); | ||
236 | ipv6_addr_copy(&fq->daddr, dst); | ||
237 | |||
238 | setup_timer(&fq->q.timer, nf_ct_frag6_expire, (unsigned long)fq); | ||
239 | spin_lock_init(&fq->q.lock); | ||
240 | atomic_set(&fq->q.refcnt, 1); | ||
241 | 189 | ||
242 | return nf_ct_frag6_intern(hash, fq); | 190 | return container_of(q, struct nf_ct_frag6_queue, q); |
243 | 191 | ||
244 | oom: | 192 | oom: |
193 | pr_debug("Can't alloc new queue\n"); | ||
245 | return NULL; | 194 | return NULL; |
246 | } | 195 | } |
247 | 196 | ||
248 | static __inline__ struct nf_ct_frag6_queue * | ||
249 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) | ||
250 | { | ||
251 | struct nf_ct_frag6_queue *fq; | ||
252 | struct hlist_node *n; | ||
253 | unsigned int hash = ip6qhashfn(id, src, dst); | ||
254 | |||
255 | read_lock(&nf_frags.lock); | ||
256 | hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) { | ||
257 | if (fq->id == id && | ||
258 | ipv6_addr_equal(src, &fq->saddr) && | ||
259 | ipv6_addr_equal(dst, &fq->daddr)) { | ||
260 | atomic_inc(&fq->q.refcnt); | ||
261 | read_unlock(&nf_frags.lock); | ||
262 | return fq; | ||
263 | } | ||
264 | } | ||
265 | read_unlock(&nf_frags.lock); | ||
266 | |||
267 | return nf_ct_frag6_create(hash, id, src, dst); | ||
268 | } | ||
269 | |||
270 | 197 | ||
271 | static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | 198 | static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, |
272 | struct frag_hdr *fhdr, int nhoff) | 199 | struct frag_hdr *fhdr, int nhoff) |
@@ -749,9 +676,12 @@ int nf_ct_frag6_init(void) | |||
749 | { | 676 | { |
750 | nf_frags.ctl = &nf_frags_ctl; | 677 | nf_frags.ctl = &nf_frags_ctl; |
751 | nf_frags.hashfn = nf_hashfn; | 678 | nf_frags.hashfn = nf_hashfn; |
752 | nf_frags.destructor = nf_frag_free; | 679 | nf_frags.constructor = ip6_frag_init; |
680 | nf_frags.destructor = NULL; | ||
753 | nf_frags.skb_free = nf_skb_free; | 681 | nf_frags.skb_free = nf_skb_free; |
754 | nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); | 682 | nf_frags.qsize = sizeof(struct nf_ct_frag6_queue); |
683 | nf_frags.match = ip6_frag_match; | ||
684 | nf_frags.frag_expire = nf_ct_frag6_expire; | ||
755 | inet_frags_init(&nf_frags); | 685 | inet_frags_init(&nf_frags); |
756 | 686 | ||
757 | return 0; | 687 | return 0; |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 6ad19cfc2025..76c88a93b9b5 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -143,6 +143,18 @@ static unsigned int ip6_hashfn(struct inet_frag_queue *q) | |||
143 | return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr); | 143 | return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr); |
144 | } | 144 | } |
145 | 145 | ||
146 | int ip6_frag_match(struct inet_frag_queue *q, void *a) | ||
147 | { | ||
148 | struct frag_queue *fq; | ||
149 | struct ip6_create_arg *arg = a; | ||
150 | |||
151 | fq = container_of(q, struct frag_queue, q); | ||
152 | return (fq->id == arg->id && | ||
153 | ipv6_addr_equal(&fq->saddr, arg->src) && | ||
154 | ipv6_addr_equal(&fq->daddr, arg->dst)); | ||
155 | } | ||
156 | EXPORT_SYMBOL(ip6_frag_match); | ||
157 | |||
146 | /* Memory Tracking Functions. */ | 158 | /* Memory Tracking Functions. */ |
147 | static inline void frag_kfree_skb(struct sk_buff *skb, int *work) | 159 | static inline void frag_kfree_skb(struct sk_buff *skb, int *work) |
148 | { | 160 | { |
@@ -152,20 +164,16 @@ static inline void frag_kfree_skb(struct sk_buff *skb, int *work) | |||
152 | kfree_skb(skb); | 164 | kfree_skb(skb); |
153 | } | 165 | } |
154 | 166 | ||
155 | static void ip6_frag_free(struct inet_frag_queue *fq) | 167 | void ip6_frag_init(struct inet_frag_queue *q, void *a) |
156 | { | 168 | { |
157 | kfree(container_of(fq, struct frag_queue, q)); | 169 | struct frag_queue *fq = container_of(q, struct frag_queue, q); |
158 | } | 170 | struct ip6_create_arg *arg = a; |
159 | |||
160 | static inline struct frag_queue *frag_alloc_queue(void) | ||
161 | { | ||
162 | struct frag_queue *fq = kzalloc(sizeof(struct frag_queue), GFP_ATOMIC); | ||
163 | 171 | ||
164 | if(!fq) | 172 | fq->id = arg->id; |
165 | return NULL; | 173 | ipv6_addr_copy(&fq->saddr, arg->src); |
166 | atomic_add(sizeof(struct frag_queue), &ip6_frags.mem); | 174 | ipv6_addr_copy(&fq->daddr, arg->dst); |
167 | return fq; | ||
168 | } | 175 | } |
176 | EXPORT_SYMBOL(ip6_frag_init); | ||
169 | 177 | ||
170 | /* Destruction primitives. */ | 178 | /* Destruction primitives. */ |
171 | 179 | ||
@@ -193,9 +201,11 @@ static void ip6_evictor(struct inet6_dev *idev) | |||
193 | 201 | ||
194 | static void ip6_frag_expire(unsigned long data) | 202 | static void ip6_frag_expire(unsigned long data) |
195 | { | 203 | { |
196 | struct frag_queue *fq = (struct frag_queue *) data; | 204 | struct frag_queue *fq; |
197 | struct net_device *dev = NULL; | 205 | struct net_device *dev = NULL; |
198 | 206 | ||
207 | fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); | ||
208 | |||
199 | spin_lock(&fq->q.lock); | 209 | spin_lock(&fq->q.lock); |
200 | 210 | ||
201 | if (fq->q.last_in & COMPLETE) | 211 | if (fq->q.last_in & COMPLETE) |
@@ -230,98 +240,30 @@ out: | |||
230 | fq_put(fq); | 240 | fq_put(fq); |
231 | } | 241 | } |
232 | 242 | ||
233 | /* Creation primitives. */ | 243 | static __inline__ struct frag_queue * |
234 | 244 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst, | |
235 | 245 | struct inet6_dev *idev) | |
236 | static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in) | ||
237 | { | 246 | { |
238 | struct frag_queue *fq; | 247 | struct inet_frag_queue *q; |
248 | struct ip6_create_arg arg; | ||
239 | unsigned int hash; | 249 | unsigned int hash; |
240 | #ifdef CONFIG_SMP | ||
241 | struct hlist_node *n; | ||
242 | #endif | ||
243 | 250 | ||
244 | write_lock(&ip6_frags.lock); | 251 | arg.id = id; |
245 | hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr); | 252 | arg.src = src; |
246 | #ifdef CONFIG_SMP | 253 | arg.dst = dst; |
247 | hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) { | 254 | hash = ip6qhashfn(id, src, dst); |
248 | if (fq->id == fq_in->id && | ||
249 | ipv6_addr_equal(&fq_in->saddr, &fq->saddr) && | ||
250 | ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) { | ||
251 | atomic_inc(&fq->q.refcnt); | ||
252 | write_unlock(&ip6_frags.lock); | ||
253 | fq_in->q.last_in |= COMPLETE; | ||
254 | fq_put(fq_in); | ||
255 | return fq; | ||
256 | } | ||
257 | } | ||
258 | #endif | ||
259 | fq = fq_in; | ||
260 | |||
261 | if (!mod_timer(&fq->q.timer, jiffies + ip6_frags_ctl.timeout)) | ||
262 | atomic_inc(&fq->q.refcnt); | ||
263 | |||
264 | atomic_inc(&fq->q.refcnt); | ||
265 | hlist_add_head(&fq->q.list, &ip6_frags.hash[hash]); | ||
266 | INIT_LIST_HEAD(&fq->q.lru_list); | ||
267 | list_add_tail(&fq->q.lru_list, &ip6_frags.lru_list); | ||
268 | ip6_frags.nqueues++; | ||
269 | write_unlock(&ip6_frags.lock); | ||
270 | return fq; | ||
271 | } | ||
272 | |||
273 | |||
274 | static struct frag_queue * | ||
275 | ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst, | ||
276 | struct inet6_dev *idev) | ||
277 | { | ||
278 | struct frag_queue *fq; | ||
279 | 255 | ||
280 | if ((fq = frag_alloc_queue()) == NULL) | 256 | q = inet_frag_find(&ip6_frags, &arg, hash); |
257 | if (q == NULL) | ||
281 | goto oom; | 258 | goto oom; |
282 | 259 | ||
283 | fq->id = id; | 260 | return container_of(q, struct frag_queue, q); |
284 | ipv6_addr_copy(&fq->saddr, src); | ||
285 | ipv6_addr_copy(&fq->daddr, dst); | ||
286 | |||
287 | init_timer(&fq->q.timer); | ||
288 | fq->q.timer.function = ip6_frag_expire; | ||
289 | fq->q.timer.data = (long) fq; | ||
290 | spin_lock_init(&fq->q.lock); | ||
291 | atomic_set(&fq->q.refcnt, 1); | ||
292 | |||
293 | return ip6_frag_intern(fq); | ||
294 | 261 | ||
295 | oom: | 262 | oom: |
296 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); | 263 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); |
297 | return NULL; | 264 | return NULL; |
298 | } | 265 | } |
299 | 266 | ||
300 | static __inline__ struct frag_queue * | ||
301 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst, | ||
302 | struct inet6_dev *idev) | ||
303 | { | ||
304 | struct frag_queue *fq; | ||
305 | struct hlist_node *n; | ||
306 | unsigned int hash; | ||
307 | |||
308 | read_lock(&ip6_frags.lock); | ||
309 | hash = ip6qhashfn(id, src, dst); | ||
310 | hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) { | ||
311 | if (fq->id == id && | ||
312 | ipv6_addr_equal(src, &fq->saddr) && | ||
313 | ipv6_addr_equal(dst, &fq->daddr)) { | ||
314 | atomic_inc(&fq->q.refcnt); | ||
315 | read_unlock(&ip6_frags.lock); | ||
316 | return fq; | ||
317 | } | ||
318 | } | ||
319 | read_unlock(&ip6_frags.lock); | ||
320 | |||
321 | return ip6_frag_create(id, src, dst, idev); | ||
322 | } | ||
323 | |||
324 | |||
325 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 267 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
326 | struct frag_hdr *fhdr, int nhoff) | 268 | struct frag_hdr *fhdr, int nhoff) |
327 | { | 269 | { |
@@ -697,8 +639,11 @@ void __init ipv6_frag_init(void) | |||
697 | 639 | ||
698 | ip6_frags.ctl = &ip6_frags_ctl; | 640 | ip6_frags.ctl = &ip6_frags_ctl; |
699 | ip6_frags.hashfn = ip6_hashfn; | 641 | ip6_frags.hashfn = ip6_hashfn; |
700 | ip6_frags.destructor = ip6_frag_free; | 642 | ip6_frags.constructor = ip6_frag_init; |
643 | ip6_frags.destructor = NULL; | ||
701 | ip6_frags.skb_free = NULL; | 644 | ip6_frags.skb_free = NULL; |
702 | ip6_frags.qsize = sizeof(struct frag_queue); | 645 | ip6_frags.qsize = sizeof(struct frag_queue); |
646 | ip6_frags.match = ip6_frag_match; | ||
647 | ip6_frags.frag_expire = ip6_frag_expire; | ||
703 | inet_frags_init(&ip6_frags); | 648 | inet_frags_init(&ip6_frags); |
704 | } | 649 | } |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 02f69e544f6f..515783707e86 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <net/ipv6.h> | 16 | #include <net/ipv6.h> |
17 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
18 | 18 | ||
19 | int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) | 19 | int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) |
20 | { | 20 | { |
21 | int err; | 21 | int err; |
22 | __be32 seq; | 22 | __be32 seq; |
@@ -24,11 +24,9 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) | |||
24 | struct xfrm_state *x; | 24 | struct xfrm_state *x; |
25 | int xfrm_nr = 0; | 25 | int xfrm_nr = 0; |
26 | int decaps = 0; | 26 | int decaps = 0; |
27 | int nexthdr; | ||
28 | unsigned int nhoff; | 27 | unsigned int nhoff; |
29 | 28 | ||
30 | nhoff = IP6CB(skb)->nhoff; | 29 | nhoff = IP6CB(skb)->nhoff; |
31 | nexthdr = skb_network_header(skb)[nhoff]; | ||
32 | 30 | ||
33 | seq = 0; | 31 | seq = 0; |
34 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | 32 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) |
@@ -41,7 +39,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) | |||
41 | goto drop; | 39 | goto drop; |
42 | 40 | ||
43 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, | 41 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, |
44 | nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6); | 42 | nexthdr, AF_INET6); |
45 | if (x == NULL) | 43 | if (x == NULL) |
46 | goto drop; | 44 | goto drop; |
47 | spin_lock(&x->lock); | 45 | spin_lock(&x->lock); |
@@ -70,10 +68,10 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) | |||
70 | 68 | ||
71 | xfrm_vec[xfrm_nr++] = x; | 69 | xfrm_vec[xfrm_nr++] = x; |
72 | 70 | ||
73 | if (x->mode->input(x, skb)) | 71 | if (x->outer_mode->input(x, skb)) |
74 | goto drop; | 72 | goto drop; |
75 | 73 | ||
76 | if (x->props.mode == XFRM_MODE_TUNNEL) { /* XXX */ | 74 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
77 | decaps = 1; | 75 | decaps = 1; |
78 | break; | 76 | break; |
79 | } | 77 | } |
@@ -99,7 +97,6 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) | |||
99 | memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, | 97 | memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec, |
100 | xfrm_nr * sizeof(xfrm_vec[0])); | 98 | xfrm_nr * sizeof(xfrm_vec[0])); |
101 | skb->sp->len += xfrm_nr; | 99 | skb->sp->len += xfrm_nr; |
102 | skb->ip_summed = CHECKSUM_NONE; | ||
103 | 100 | ||
104 | nf_reset(skb); | 101 | nf_reset(skb); |
105 | 102 | ||
@@ -135,7 +132,8 @@ EXPORT_SYMBOL(xfrm6_rcv_spi); | |||
135 | 132 | ||
136 | int xfrm6_rcv(struct sk_buff *skb) | 133 | int xfrm6_rcv(struct sk_buff *skb) |
137 | { | 134 | { |
138 | return xfrm6_rcv_spi(skb, 0); | 135 | return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], |
136 | 0); | ||
139 | } | 137 | } |
140 | 138 | ||
141 | EXPORT_SYMBOL(xfrm6_rcv); | 139 | EXPORT_SYMBOL(xfrm6_rcv); |
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c index 13bb1e856764..2bfb4f05c14c 100644 --- a/net/ipv6/xfrm6_mode_beet.c +++ b/net/ipv6/xfrm6_mode_beet.c | |||
@@ -79,6 +79,7 @@ static struct xfrm_mode xfrm6_beet_mode = { | |||
79 | .output = xfrm6_beet_output, | 79 | .output = xfrm6_beet_output, |
80 | .owner = THIS_MODULE, | 80 | .owner = THIS_MODULE, |
81 | .encap = XFRM_MODE_BEET, | 81 | .encap = XFRM_MODE_BEET, |
82 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
82 | }; | 83 | }; |
83 | 84 | ||
84 | static int __init xfrm6_beet_init(void) | 85 | static int __init xfrm6_beet_init(void) |
diff --git a/net/ipv6/xfrm6_mode_ro.c b/net/ipv6/xfrm6_mode_ro.c index 957ae36b6695..a7bc8c62317a 100644 --- a/net/ipv6/xfrm6_mode_ro.c +++ b/net/ipv6/xfrm6_mode_ro.c | |||
@@ -58,16 +58,7 @@ static int xfrm6_ro_output(struct xfrm_state *x, struct sk_buff *skb) | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* | ||
62 | * Do nothing about routing optimization header unlike IPsec. | ||
63 | */ | ||
64 | static int xfrm6_ro_input(struct xfrm_state *x, struct sk_buff *skb) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static struct xfrm_mode xfrm6_ro_mode = { | 61 | static struct xfrm_mode xfrm6_ro_mode = { |
70 | .input = xfrm6_ro_input, | ||
71 | .output = xfrm6_ro_output, | 62 | .output = xfrm6_ro_output, |
72 | .owner = THIS_MODULE, | 63 | .owner = THIS_MODULE, |
73 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, | 64 | .encap = XFRM_MODE_ROUTEOPTIMIZATION, |
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index ea2283879112..fd84e2217274 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -118,6 +118,7 @@ static struct xfrm_mode xfrm6_tunnel_mode = { | |||
118 | .output = xfrm6_tunnel_output, | 118 | .output = xfrm6_tunnel_output, |
119 | .owner = THIS_MODULE, | 119 | .owner = THIS_MODULE, |
120 | .encap = XFRM_MODE_TUNNEL, | 120 | .encap = XFRM_MODE_TUNNEL, |
121 | .flags = XFRM_MODE_FLAG_TUNNEL, | ||
121 | }; | 122 | }; |
122 | 123 | ||
123 | static int __init xfrm6_tunnel_init(void) | 124 | static int __init xfrm6_tunnel_init(void) |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index a5a32c17249d..656976760ad4 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -50,7 +50,7 @@ static inline int xfrm6_output_one(struct sk_buff *skb) | |||
50 | struct ipv6hdr *iph; | 50 | struct ipv6hdr *iph; |
51 | int err; | 51 | int err; |
52 | 52 | ||
53 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 53 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
54 | err = xfrm6_tunnel_check_size(skb); | 54 | err = xfrm6_tunnel_check_size(skb); |
55 | if (err) | 55 | if (err) |
56 | goto error_nolock; | 56 | goto error_nolock; |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 15aa4c58c315..82e27b80d07d 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -178,8 +178,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
178 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); | 178 | __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]); |
179 | trailer_len += xfrm[i]->props.trailer_len; | 179 | trailer_len += xfrm[i]->props.trailer_len; |
180 | 180 | ||
181 | if (xfrm[i]->props.mode == XFRM_MODE_TUNNEL || | 181 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
182 | xfrm[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) { | ||
183 | unsigned short encap_family = xfrm[i]->props.family; | 182 | unsigned short encap_family = xfrm[i]->props.family; |
184 | switch(encap_family) { | 183 | switch(encap_family) { |
185 | case AF_INET: | 184 | case AF_INET: |
@@ -215,7 +214,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
215 | i = 0; | 214 | i = 0; |
216 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { | 215 | for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) { |
217 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; | 216 | struct xfrm_dst *x = (struct xfrm_dst*)dst_prev; |
218 | struct xfrm_state_afinfo *afinfo; | ||
219 | 217 | ||
220 | dst_prev->xfrm = xfrm[i++]; | 218 | dst_prev->xfrm = xfrm[i++]; |
221 | dst_prev->dev = rt->u.dst.dev; | 219 | dst_prev->dev = rt->u.dst.dev; |
@@ -232,18 +230,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
232 | /* Copy neighbour for reachability confirmation */ | 230 | /* Copy neighbour for reachability confirmation */ |
233 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); | 231 | dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); |
234 | dst_prev->input = rt->u.dst.input; | 232 | dst_prev->input = rt->u.dst.input; |
235 | /* XXX: When IPv4 is implemented as module and can be unloaded, | 233 | dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output; |
236 | * we should manage reference to xfrm4_output in afinfo->output. | ||
237 | * Miyazawa | ||
238 | */ | ||
239 | afinfo = xfrm_state_get_afinfo(dst_prev->xfrm->props.family); | ||
240 | if (!afinfo) { | ||
241 | dst = *dst_p; | ||
242 | goto error; | ||
243 | } | ||
244 | |||
245 | dst_prev->output = afinfo->output; | ||
246 | xfrm_state_put_afinfo(afinfo); | ||
247 | /* Sheit... I remember I did this right. Apparently, | 234 | /* Sheit... I remember I did this right. Apparently, |
248 | * it was magically lost, so this code needs audit */ | 235 | * it was magically lost, so this code needs audit */ |
249 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); | 236 | x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL); |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index cdadb4847469..b392bee396f1 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -93,7 +93,8 @@ __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) | |||
93 | /* Rule 4: select IPsec tunnel */ | 93 | /* Rule 4: select IPsec tunnel */ |
94 | for (i = 0; i < n; i++) { | 94 | for (i = 0; i < n; i++) { |
95 | if (src[i] && | 95 | if (src[i] && |
96 | src[i]->props.mode == XFRM_MODE_TUNNEL) { | 96 | (src[i]->props.mode == XFRM_MODE_TUNNEL || |
97 | src[i]->props.mode == XFRM_MODE_BEET)) { | ||
97 | dst[j++] = src[i]; | 98 | dst[j++] = src[i]; |
98 | src[i] = NULL; | 99 | src[i] = NULL; |
99 | } | 100 | } |
@@ -146,7 +147,8 @@ __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) | |||
146 | /* Rule 3: select IPsec tunnel */ | 147 | /* Rule 3: select IPsec tunnel */ |
147 | for (i = 0; i < n; i++) { | 148 | for (i = 0; i < n; i++) { |
148 | if (src[i] && | 149 | if (src[i] && |
149 | src[i]->mode == XFRM_MODE_TUNNEL) { | 150 | (src[i]->mode == XFRM_MODE_TUNNEL || |
151 | src[i]->mode == XFRM_MODE_BEET)) { | ||
150 | dst[j++] = src[i]; | 152 | dst[j++] = src[i]; |
151 | src[i] = NULL; | 153 | src[i] = NULL; |
152 | } | 154 | } |
@@ -168,6 +170,7 @@ __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) | |||
168 | 170 | ||
169 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { | 171 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { |
170 | .family = AF_INET6, | 172 | .family = AF_INET6, |
173 | .owner = THIS_MODULE, | ||
171 | .init_tempsel = __xfrm6_init_tempsel, | 174 | .init_tempsel = __xfrm6_init_tempsel, |
172 | .tmpl_sort = __xfrm6_tmpl_sort, | 175 | .tmpl_sort = __xfrm6_tmpl_sort, |
173 | .state_sort = __xfrm6_state_sort, | 176 | .state_sort = __xfrm6_state_sort, |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 3f8a3abde67e..fae90ff31087 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -248,7 +248,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
248 | 248 | ||
249 | static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | 249 | static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) |
250 | { | 250 | { |
251 | return 0; | 251 | return skb_network_header(skb)[IP6CB(skb)->nhoff]; |
252 | } | 252 | } |
253 | 253 | ||
254 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 254 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
@@ -257,7 +257,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb) | |||
257 | __be32 spi; | 257 | __be32 spi; |
258 | 258 | ||
259 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 259 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); |
260 | return xfrm6_rcv_spi(skb, spi) > 0 ? : 0; | 260 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; |
261 | } | 261 | } |
262 | 262 | ||
263 | static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 263 | static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index 824309dabfe9..b5a13882c927 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c | |||
@@ -381,18 +381,9 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery, | |||
381 | info.daddr = discovery->daddr; | 381 | info.daddr = discovery->daddr; |
382 | info.saddr = discovery->saddr; | 382 | info.saddr = discovery->saddr; |
383 | 383 | ||
384 | /* FIXME. We have a locking problem on the hashbin here. | 384 | self = (struct ircomm_tty_cb *) priv; |
385 | * We probably need to use hashbin_find_next(), but we first | 385 | ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, |
386 | * need to ensure that "line" is unique. - Jean II */ | 386 | NULL, &info); |
387 | self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); | ||
388 | while (self != NULL) { | ||
389 | IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); | ||
390 | |||
391 | ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, | ||
392 | NULL, &info); | ||
393 | |||
394 | self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); | ||
395 | } | ||
396 | } | 387 | } |
397 | 388 | ||
398 | /* | 389 | /* |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index f0224c2311d2..6caa3ec2cff7 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -306,9 +306,12 @@ int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) | |||
306 | ((chan->chan == channel) || (chan->freq == freq))) { | 306 | ((chan->chan == channel) || (chan->freq == freq))) { |
307 | local->oper_channel = chan; | 307 | local->oper_channel = chan; |
308 | local->oper_hw_mode = mode; | 308 | local->oper_hw_mode = mode; |
309 | set++; | 309 | set = 1; |
310 | break; | ||
310 | } | 311 | } |
311 | } | 312 | } |
313 | if (set) | ||
314 | break; | ||
312 | } | 315 | } |
313 | 316 | ||
314 | if (set) { | 317 | if (set) { |
@@ -508,10 +511,11 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
508 | 511 | ||
509 | static int ieee80211_ioctl_siwscan(struct net_device *dev, | 512 | static int ieee80211_ioctl_siwscan(struct net_device *dev, |
510 | struct iw_request_info *info, | 513 | struct iw_request_info *info, |
511 | struct iw_point *data, char *extra) | 514 | union iwreq_data *wrqu, char *extra) |
512 | { | 515 | { |
513 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 516 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
514 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 517 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
518 | struct iw_scan_req *req = NULL; | ||
515 | u8 *ssid = NULL; | 519 | u8 *ssid = NULL; |
516 | size_t ssid_len = 0; | 520 | size_t ssid_len = 0; |
517 | 521 | ||
@@ -536,6 +540,14 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, | |||
536 | return -EOPNOTSUPP; | 540 | return -EOPNOTSUPP; |
537 | } | 541 | } |
538 | 542 | ||
543 | /* if SSID was specified explicitly then use that */ | ||
544 | if (wrqu->data.length == sizeof(struct iw_scan_req) && | ||
545 | wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||
546 | req = (struct iw_scan_req *)extra; | ||
547 | ssid = req->essid; | ||
548 | ssid_len = req->essid_len; | ||
549 | } | ||
550 | |||
539 | return ieee80211_sta_req_scan(dev, ssid, ssid_len); | 551 | return ieee80211_sta_req_scan(dev, ssid, ssid_len); |
540 | } | 552 | } |
541 | 553 | ||
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 1641e8fe44b7..db81aef6177a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -12,7 +12,6 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* TODO: | 14 | /* TODO: |
15 | * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs | ||
16 | * order BSS list by RSSI(?) ("quality of AP") | 15 | * order BSS list by RSSI(?) ("quality of AP") |
17 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, | 16 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, |
18 | * SSID) | 17 | * SSID) |
@@ -61,7 +60,8 @@ | |||
61 | static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, | 60 | static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, |
62 | u8 *ssid, size_t ssid_len); | 61 | u8 *ssid, size_t ssid_len); |
63 | static struct ieee80211_sta_bss * | 62 | static struct ieee80211_sta_bss * |
64 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid); | 63 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, |
64 | u8 *ssid, u8 ssid_len); | ||
65 | static void ieee80211_rx_bss_put(struct net_device *dev, | 65 | static void ieee80211_rx_bss_put(struct net_device *dev, |
66 | struct ieee80211_sta_bss *bss); | 66 | struct ieee80211_sta_bss *bss); |
67 | static int ieee80211_sta_find_ibss(struct net_device *dev, | 67 | static int ieee80211_sta_find_ibss(struct net_device *dev, |
@@ -427,7 +427,9 @@ static void ieee80211_set_associated(struct net_device *dev, | |||
427 | if (sdata->type != IEEE80211_IF_TYPE_STA) | 427 | if (sdata->type != IEEE80211_IF_TYPE_STA) |
428 | return; | 428 | return; |
429 | 429 | ||
430 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid); | 430 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, |
431 | local->hw.conf.channel, | ||
432 | ifsta->ssid, ifsta->ssid_len); | ||
431 | if (bss) { | 433 | if (bss) { |
432 | if (bss->has_erp_value) | 434 | if (bss->has_erp_value) |
433 | ieee80211_handle_erp_ie(dev, bss->erp_value); | 435 | ieee80211_handle_erp_ie(dev, bss->erp_value); |
@@ -574,7 +576,8 @@ static void ieee80211_send_assoc(struct net_device *dev, | |||
574 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | | 576 | capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | |
575 | WLAN_CAPABILITY_SHORT_PREAMBLE; | 577 | WLAN_CAPABILITY_SHORT_PREAMBLE; |
576 | } | 578 | } |
577 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid); | 579 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, |
580 | ifsta->ssid, ifsta->ssid_len); | ||
578 | if (bss) { | 581 | if (bss) { |
579 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) | 582 | if (bss->capability & WLAN_CAPABILITY_PRIVACY) |
580 | capab |= WLAN_CAPABILITY_PRIVACY; | 583 | capab |= WLAN_CAPABILITY_PRIVACY; |
@@ -722,6 +725,7 @@ static void ieee80211_send_disassoc(struct net_device *dev, | |||
722 | static int ieee80211_privacy_mismatch(struct net_device *dev, | 725 | static int ieee80211_privacy_mismatch(struct net_device *dev, |
723 | struct ieee80211_if_sta *ifsta) | 726 | struct ieee80211_if_sta *ifsta) |
724 | { | 727 | { |
728 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
725 | struct ieee80211_sta_bss *bss; | 729 | struct ieee80211_sta_bss *bss; |
726 | int res = 0; | 730 | int res = 0; |
727 | 731 | ||
@@ -729,7 +733,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, | |||
729 | ifsta->key_management_enabled) | 733 | ifsta->key_management_enabled) |
730 | return 0; | 734 | return 0; |
731 | 735 | ||
732 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid); | 736 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, |
737 | ifsta->ssid, ifsta->ssid_len); | ||
733 | if (!bss) | 738 | if (!bss) |
734 | return 0; | 739 | return 0; |
735 | 740 | ||
@@ -1203,15 +1208,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, | |||
1203 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1208 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
1204 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | 1209 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); |
1205 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); | 1210 | aid = le16_to_cpu(mgmt->u.assoc_resp.aid); |
1206 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | ||
1207 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | ||
1208 | "set\n", dev->name, aid); | ||
1209 | aid &= ~(BIT(15) | BIT(14)); | ||
1210 | 1211 | ||
1211 | printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " | 1212 | printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " |
1212 | "status=%d aid=%d)\n", | 1213 | "status=%d aid=%d)\n", |
1213 | dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), | 1214 | dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), |
1214 | capab_info, status_code, aid); | 1215 | capab_info, status_code, aid & ~(BIT(15) | BIT(14))); |
1215 | 1216 | ||
1216 | if (status_code != WLAN_STATUS_SUCCESS) { | 1217 | if (status_code != WLAN_STATUS_SUCCESS) { |
1217 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", | 1218 | printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", |
@@ -1223,6 +1224,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, | |||
1223 | return; | 1224 | return; |
1224 | } | 1225 | } |
1225 | 1226 | ||
1227 | if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) | ||
1228 | printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " | ||
1229 | "set\n", dev->name, aid); | ||
1230 | aid &= ~(BIT(15) | BIT(14)); | ||
1231 | |||
1226 | pos = mgmt->u.assoc_resp.variable; | 1232 | pos = mgmt->u.assoc_resp.variable; |
1227 | if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) | 1233 | if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems) |
1228 | == ParseFailed) { | 1234 | == ParseFailed) { |
@@ -1241,7 +1247,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, | |||
1241 | * update our stored copy */ | 1247 | * update our stored copy */ |
1242 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1248 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1243 | struct ieee80211_sta_bss *bss | 1249 | struct ieee80211_sta_bss *bss |
1244 | = ieee80211_rx_bss_get(dev, ifsta->bssid); | 1250 | = ieee80211_rx_bss_get(dev, ifsta->bssid, |
1251 | local->hw.conf.channel, | ||
1252 | ifsta->ssid, ifsta->ssid_len); | ||
1245 | if (bss) { | 1253 | if (bss) { |
1246 | bss->erp_value = elems.erp_info[0]; | 1254 | bss->erp_value = elems.erp_info[0]; |
1247 | bss->has_erp_value = 1; | 1255 | bss->has_erp_value = 1; |
@@ -1271,7 +1279,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev, | |||
1271 | " AP\n", dev->name); | 1279 | " AP\n", dev->name); |
1272 | return; | 1280 | return; |
1273 | } | 1281 | } |
1274 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid); | 1282 | bss = ieee80211_rx_bss_get(dev, ifsta->bssid, |
1283 | local->hw.conf.channel, | ||
1284 | ifsta->ssid, ifsta->ssid_len); | ||
1275 | if (bss) { | 1285 | if (bss) { |
1276 | sta->last_rssi = bss->rssi; | 1286 | sta->last_rssi = bss->rssi; |
1277 | sta->last_signal = bss->signal; | 1287 | sta->last_signal = bss->signal; |
@@ -1347,7 +1357,8 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev, | |||
1347 | 1357 | ||
1348 | 1358 | ||
1349 | static struct ieee80211_sta_bss * | 1359 | static struct ieee80211_sta_bss * |
1350 | ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) | 1360 | ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, |
1361 | u8 *ssid, u8 ssid_len) | ||
1351 | { | 1362 | { |
1352 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1363 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1353 | struct ieee80211_sta_bss *bss; | 1364 | struct ieee80211_sta_bss *bss; |
@@ -1358,6 +1369,11 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) | |||
1358 | atomic_inc(&bss->users); | 1369 | atomic_inc(&bss->users); |
1359 | atomic_inc(&bss->users); | 1370 | atomic_inc(&bss->users); |
1360 | memcpy(bss->bssid, bssid, ETH_ALEN); | 1371 | memcpy(bss->bssid, bssid, ETH_ALEN); |
1372 | bss->channel = channel; | ||
1373 | if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
1374 | memcpy(bss->ssid, ssid, ssid_len); | ||
1375 | bss->ssid_len = ssid_len; | ||
1376 | } | ||
1361 | 1377 | ||
1362 | spin_lock_bh(&local->sta_bss_lock); | 1378 | spin_lock_bh(&local->sta_bss_lock); |
1363 | /* TODO: order by RSSI? */ | 1379 | /* TODO: order by RSSI? */ |
@@ -1369,7 +1385,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid) | |||
1369 | 1385 | ||
1370 | 1386 | ||
1371 | static struct ieee80211_sta_bss * | 1387 | static struct ieee80211_sta_bss * |
1372 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid) | 1388 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, |
1389 | u8 *ssid, u8 ssid_len) | ||
1373 | { | 1390 | { |
1374 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1391 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1375 | struct ieee80211_sta_bss *bss; | 1392 | struct ieee80211_sta_bss *bss; |
@@ -1377,7 +1394,10 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid) | |||
1377 | spin_lock_bh(&local->sta_bss_lock); | 1394 | spin_lock_bh(&local->sta_bss_lock); |
1378 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | 1395 | bss = local->sta_bss_hash[STA_HASH(bssid)]; |
1379 | while (bss) { | 1396 | while (bss) { |
1380 | if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { | 1397 | if (!memcmp(bss->bssid, bssid, ETH_ALEN) && |
1398 | bss->channel == channel && | ||
1399 | bss->ssid_len == ssid_len && | ||
1400 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | ||
1381 | atomic_inc(&bss->users); | 1401 | atomic_inc(&bss->users); |
1382 | break; | 1402 | break; |
1383 | } | 1403 | } |
@@ -1545,9 +1565,11 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
1545 | else | 1565 | else |
1546 | channel = rx_status->channel; | 1566 | channel = rx_status->channel; |
1547 | 1567 | ||
1548 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid); | 1568 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel, |
1569 | elems.ssid, elems.ssid_len); | ||
1549 | if (!bss) { | 1570 | if (!bss) { |
1550 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid); | 1571 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, |
1572 | elems.ssid, elems.ssid_len); | ||
1551 | if (!bss) | 1573 | if (!bss) |
1552 | return; | 1574 | return; |
1553 | } else { | 1575 | } else { |
@@ -1573,10 +1595,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
1573 | 1595 | ||
1574 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); | 1596 | bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); |
1575 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); | 1597 | bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); |
1576 | if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) { | ||
1577 | memcpy(bss->ssid, elems.ssid, elems.ssid_len); | ||
1578 | bss->ssid_len = elems.ssid_len; | ||
1579 | } | ||
1580 | 1598 | ||
1581 | bss->supp_rates_len = 0; | 1599 | bss->supp_rates_len = 0; |
1582 | if (elems.supp_rates) { | 1600 | if (elems.supp_rates) { |
@@ -1647,7 +1665,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
1647 | 1665 | ||
1648 | 1666 | ||
1649 | bss->hw_mode = rx_status->phymode; | 1667 | bss->hw_mode = rx_status->phymode; |
1650 | bss->channel = channel; | ||
1651 | bss->freq = rx_status->freq; | 1668 | bss->freq = rx_status->freq; |
1652 | if (channel != rx_status->channel && | 1669 | if (channel != rx_status->channel && |
1653 | (bss->hw_mode == MODE_IEEE80211G || | 1670 | (bss->hw_mode == MODE_IEEE80211G || |
@@ -2375,7 +2392,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, | |||
2375 | { | 2392 | { |
2376 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2393 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2377 | struct ieee80211_sta_bss *bss; | 2394 | struct ieee80211_sta_bss *bss; |
2378 | struct ieee80211_sub_if_data *sdata; | 2395 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
2379 | struct ieee80211_hw_mode *mode; | 2396 | struct ieee80211_hw_mode *mode; |
2380 | u8 bssid[ETH_ALEN], *pos; | 2397 | u8 bssid[ETH_ALEN], *pos; |
2381 | int i; | 2398 | int i; |
@@ -2398,18 +2415,17 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, | |||
2398 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", | 2415 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", |
2399 | dev->name, print_mac(mac, bssid)); | 2416 | dev->name, print_mac(mac, bssid)); |
2400 | 2417 | ||
2401 | bss = ieee80211_rx_bss_add(dev, bssid); | 2418 | bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel, |
2419 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | ||
2402 | if (!bss) | 2420 | if (!bss) |
2403 | return -ENOMEM; | 2421 | return -ENOMEM; |
2404 | 2422 | ||
2405 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2406 | mode = local->oper_hw_mode; | 2423 | mode = local->oper_hw_mode; |
2407 | 2424 | ||
2408 | if (local->hw.conf.beacon_int == 0) | 2425 | if (local->hw.conf.beacon_int == 0) |
2409 | local->hw.conf.beacon_int = 100; | 2426 | local->hw.conf.beacon_int = 100; |
2410 | bss->beacon_int = local->hw.conf.beacon_int; | 2427 | bss->beacon_int = local->hw.conf.beacon_int; |
2411 | bss->hw_mode = local->hw.conf.phymode; | 2428 | bss->hw_mode = local->hw.conf.phymode; |
2412 | bss->channel = local->hw.conf.channel; | ||
2413 | bss->freq = local->hw.conf.freq; | 2429 | bss->freq = local->hw.conf.freq; |
2414 | bss->last_update = jiffies; | 2430 | bss->last_update = jiffies; |
2415 | bss->capability = WLAN_CAPABILITY_IBSS; | 2431 | bss->capability = WLAN_CAPABILITY_IBSS; |
@@ -2469,7 +2485,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, | |||
2469 | "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); | 2485 | "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); |
2470 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 2486 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
2471 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && | 2487 | if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && |
2472 | (bss = ieee80211_rx_bss_get(dev, bssid))) { | 2488 | (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel, |
2489 | ifsta->ssid, ifsta->ssid_len))) { | ||
2473 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" | 2490 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" |
2474 | " based on configured SSID\n", | 2491 | " based on configured SSID\n", |
2475 | dev->name, print_mac(mac, bssid)); | 2492 | dev->name, print_mac(mac, bssid)); |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index a127ab32881e..7a3f64c1aca6 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -834,10 +834,12 @@ static int tcp_packet(struct nf_conn *conntrack, | |||
834 | case TCP_CONNTRACK_SYN_SENT: | 834 | case TCP_CONNTRACK_SYN_SENT: |
835 | if (old_state < TCP_CONNTRACK_TIME_WAIT) | 835 | if (old_state < TCP_CONNTRACK_TIME_WAIT) |
836 | break; | 836 | break; |
837 | if (conntrack->proto.tcp.seen[!dir].flags & | 837 | if ((conntrack->proto.tcp.seen[!dir].flags & |
838 | IP_CT_TCP_FLAG_CLOSE_INIT) { | 838 | IP_CT_TCP_FLAG_CLOSE_INIT) |
839 | /* Attempt to reopen a closed connection. | 839 | || (conntrack->proto.tcp.last_dir == dir |
840 | * Delete this connection and look up again. */ | 840 | && conntrack->proto.tcp.last_index == TCP_RST_SET)) { |
841 | /* Attempt to reopen a closed/aborted connection. | ||
842 | * Delete this connection and look up again. */ | ||
841 | write_unlock_bh(&tcp_lock); | 843 | write_unlock_bh(&tcp_lock); |
842 | if (del_timer(&conntrack->timeout)) | 844 | if (del_timer(&conntrack->timeout)) |
843 | conntrack->timeout.function((unsigned long) | 845 | conntrack->timeout.function((unsigned long) |
@@ -925,6 +927,7 @@ static int tcp_packet(struct nf_conn *conntrack, | |||
925 | in_window: | 927 | in_window: |
926 | /* From now on we have got in-window packets */ | 928 | /* From now on we have got in-window packets */ |
927 | conntrack->proto.tcp.last_index = index; | 929 | conntrack->proto.tcp.last_index = index; |
930 | conntrack->proto.tcp.last_dir = dir; | ||
928 | 931 | ||
929 | pr_debug("tcp_conntracks: "); | 932 | pr_debug("tcp_conntracks: "); |
930 | NF_CT_DUMP_TUPLE(tuple); | 933 | NF_CT_DUMP_TUPLE(tuple); |
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index f907770fd4e9..3358273a47b7 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c | |||
@@ -42,21 +42,21 @@ match_flags(const struct xt_sctp_flag_info *flag_info, | |||
42 | static inline bool | 42 | static inline bool |
43 | match_packet(const struct sk_buff *skb, | 43 | match_packet(const struct sk_buff *skb, |
44 | unsigned int offset, | 44 | unsigned int offset, |
45 | const u_int32_t *chunkmap, | 45 | const struct xt_sctp_info *info, |
46 | int chunk_match_type, | ||
47 | const struct xt_sctp_flag_info *flag_info, | ||
48 | const int flag_count, | ||
49 | bool *hotdrop) | 46 | bool *hotdrop) |
50 | { | 47 | { |
51 | u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; | 48 | u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; |
52 | sctp_chunkhdr_t _sch, *sch; | 49 | sctp_chunkhdr_t _sch, *sch; |
50 | int chunk_match_type = info->chunk_match_type; | ||
51 | const struct xt_sctp_flag_info *flag_info = info->flag_info; | ||
52 | int flag_count = info->flag_count; | ||
53 | 53 | ||
54 | #ifdef DEBUG_SCTP | 54 | #ifdef DEBUG_SCTP |
55 | int i = 0; | 55 | int i = 0; |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) | 58 | if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) |
59 | SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap); | 59 | SCTP_CHUNKMAP_COPY(chunkmapcopy, info->chunkmap); |
60 | 60 | ||
61 | do { | 61 | do { |
62 | sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); | 62 | sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); |
@@ -73,7 +73,7 @@ match_packet(const struct sk_buff *skb, | |||
73 | 73 | ||
74 | duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); | 74 | duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); |
75 | 75 | ||
76 | if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) { | 76 | if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) { |
77 | switch (chunk_match_type) { | 77 | switch (chunk_match_type) { |
78 | case SCTP_CHUNK_MATCH_ANY: | 78 | case SCTP_CHUNK_MATCH_ANY: |
79 | if (match_flags(flag_info, flag_count, | 79 | if (match_flags(flag_info, flag_count, |
@@ -104,7 +104,7 @@ match_packet(const struct sk_buff *skb, | |||
104 | 104 | ||
105 | switch (chunk_match_type) { | 105 | switch (chunk_match_type) { |
106 | case SCTP_CHUNK_MATCH_ALL: | 106 | case SCTP_CHUNK_MATCH_ALL: |
107 | return SCTP_CHUNKMAP_IS_CLEAR(chunkmap); | 107 | return SCTP_CHUNKMAP_IS_CLEAR(info->chunkmap); |
108 | case SCTP_CHUNK_MATCH_ANY: | 108 | case SCTP_CHUNK_MATCH_ANY: |
109 | return false; | 109 | return false; |
110 | case SCTP_CHUNK_MATCH_ONLY: | 110 | case SCTP_CHUNK_MATCH_ONLY: |
@@ -148,9 +148,7 @@ match(const struct sk_buff *skb, | |||
148 | && ntohs(sh->dest) <= info->dpts[1], | 148 | && ntohs(sh->dest) <= info->dpts[1], |
149 | XT_SCTP_DEST_PORTS, info->flags, info->invflags) | 149 | XT_SCTP_DEST_PORTS, info->flags, info->invflags) |
150 | && SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t), | 150 | && SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t), |
151 | info->chunkmap, info->chunk_match_type, | 151 | info, hotdrop), |
152 | info->flag_info, info->flag_count, | ||
153 | hotdrop), | ||
154 | XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); | 152 | XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); |
155 | } | 153 | } |
156 | 154 | ||
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 95ae11956f35..e01d57692c9a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -249,10 +249,11 @@ static void dev_watchdog_down(struct net_device *dev) | |||
249 | */ | 249 | */ |
250 | void netif_carrier_on(struct net_device *dev) | 250 | void netif_carrier_on(struct net_device *dev) |
251 | { | 251 | { |
252 | if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) | 252 | if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) { |
253 | linkwatch_fire_event(dev); | 253 | linkwatch_fire_event(dev); |
254 | if (netif_running(dev)) | 254 | if (netif_running(dev)) |
255 | __netdev_watchdog_up(dev); | 255 | __netdev_watchdog_up(dev); |
256 | } | ||
256 | } | 257 | } |
257 | 258 | ||
258 | /** | 259 | /** |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 113f44429982..cb97fda1b6df 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -49,13 +49,16 @@ EXPORT_SYMBOL(secpath_dup); | |||
49 | int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | 49 | int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) |
50 | { | 50 | { |
51 | int offset, offset_seq; | 51 | int offset, offset_seq; |
52 | int hlen; | ||
52 | 53 | ||
53 | switch (nexthdr) { | 54 | switch (nexthdr) { |
54 | case IPPROTO_AH: | 55 | case IPPROTO_AH: |
56 | hlen = sizeof(struct ip_auth_hdr); | ||
55 | offset = offsetof(struct ip_auth_hdr, spi); | 57 | offset = offsetof(struct ip_auth_hdr, spi); |
56 | offset_seq = offsetof(struct ip_auth_hdr, seq_no); | 58 | offset_seq = offsetof(struct ip_auth_hdr, seq_no); |
57 | break; | 59 | break; |
58 | case IPPROTO_ESP: | 60 | case IPPROTO_ESP: |
61 | hlen = sizeof(struct ip_esp_hdr); | ||
59 | offset = offsetof(struct ip_esp_hdr, spi); | 62 | offset = offsetof(struct ip_esp_hdr, spi); |
60 | offset_seq = offsetof(struct ip_esp_hdr, seq_no); | 63 | offset_seq = offsetof(struct ip_esp_hdr, seq_no); |
61 | break; | 64 | break; |
@@ -69,7 +72,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) | |||
69 | return 1; | 72 | return 1; |
70 | } | 73 | } |
71 | 74 | ||
72 | if (!pskb_may_pull(skb, 16)) | 75 | if (!pskb_may_pull(skb, hlen)) |
73 | return -EINVAL; | 76 | return -EINVAL; |
74 | 77 | ||
75 | *spi = *(__be32*)(skb_transport_header(skb) + offset); | 78 | *spi = *(__be32*)(skb_transport_header(skb) + offset); |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 0eb3377602e9..f4bfd6c45651 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
@@ -63,7 +63,7 @@ int xfrm_output(struct sk_buff *skb) | |||
63 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); | 63 | xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); |
64 | } | 64 | } |
65 | 65 | ||
66 | err = x->mode->output(x, skb); | 66 | err = x->outer_mode->output(x, skb); |
67 | if (err) | 67 | if (err) |
68 | goto error; | 68 | goto error; |
69 | 69 | ||
@@ -82,7 +82,7 @@ int xfrm_output(struct sk_buff *skb) | |||
82 | } | 82 | } |
83 | dst = skb->dst; | 83 | dst = skb->dst; |
84 | x = dst->xfrm; | 84 | x = dst->xfrm; |
85 | } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); | 85 | } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); |
86 | 86 | ||
87 | err = 0; | 87 | err = 0; |
88 | 88 | ||
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index af27c193697c..b702bd8a3893 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -49,8 +49,6 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock); | |||
49 | 49 | ||
50 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); | 50 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); |
51 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); | 51 | static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); |
52 | static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family); | ||
53 | static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo); | ||
54 | 52 | ||
55 | static inline int | 53 | static inline int |
56 | __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl) | 54 | __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl) |
@@ -86,72 +84,6 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, | |||
86 | return 0; | 84 | return 0; |
87 | } | 85 | } |
88 | 86 | ||
89 | int xfrm_register_type(struct xfrm_type *type, unsigned short family) | ||
90 | { | ||
91 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family); | ||
92 | struct xfrm_type **typemap; | ||
93 | int err = 0; | ||
94 | |||
95 | if (unlikely(afinfo == NULL)) | ||
96 | return -EAFNOSUPPORT; | ||
97 | typemap = afinfo->type_map; | ||
98 | |||
99 | if (likely(typemap[type->proto] == NULL)) | ||
100 | typemap[type->proto] = type; | ||
101 | else | ||
102 | err = -EEXIST; | ||
103 | xfrm_policy_unlock_afinfo(afinfo); | ||
104 | return err; | ||
105 | } | ||
106 | EXPORT_SYMBOL(xfrm_register_type); | ||
107 | |||
108 | int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) | ||
109 | { | ||
110 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family); | ||
111 | struct xfrm_type **typemap; | ||
112 | int err = 0; | ||
113 | |||
114 | if (unlikely(afinfo == NULL)) | ||
115 | return -EAFNOSUPPORT; | ||
116 | typemap = afinfo->type_map; | ||
117 | |||
118 | if (unlikely(typemap[type->proto] != type)) | ||
119 | err = -ENOENT; | ||
120 | else | ||
121 | typemap[type->proto] = NULL; | ||
122 | xfrm_policy_unlock_afinfo(afinfo); | ||
123 | return err; | ||
124 | } | ||
125 | EXPORT_SYMBOL(xfrm_unregister_type); | ||
126 | |||
127 | struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) | ||
128 | { | ||
129 | struct xfrm_policy_afinfo *afinfo; | ||
130 | struct xfrm_type **typemap; | ||
131 | struct xfrm_type *type; | ||
132 | int modload_attempted = 0; | ||
133 | |||
134 | retry: | ||
135 | afinfo = xfrm_policy_get_afinfo(family); | ||
136 | if (unlikely(afinfo == NULL)) | ||
137 | return NULL; | ||
138 | typemap = afinfo->type_map; | ||
139 | |||
140 | type = typemap[proto]; | ||
141 | if (unlikely(type && !try_module_get(type->owner))) | ||
142 | type = NULL; | ||
143 | if (!type && !modload_attempted) { | ||
144 | xfrm_policy_put_afinfo(afinfo); | ||
145 | request_module("xfrm-type-%d-%d", | ||
146 | (int) family, (int) proto); | ||
147 | modload_attempted = 1; | ||
148 | goto retry; | ||
149 | } | ||
150 | |||
151 | xfrm_policy_put_afinfo(afinfo); | ||
152 | return type; | ||
153 | } | ||
154 | |||
155 | int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, | 87 | int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, |
156 | unsigned short family) | 88 | unsigned short family) |
157 | { | 89 | { |
@@ -170,94 +102,6 @@ int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, | |||
170 | } | 102 | } |
171 | EXPORT_SYMBOL(xfrm_dst_lookup); | 103 | EXPORT_SYMBOL(xfrm_dst_lookup); |
172 | 104 | ||
173 | void xfrm_put_type(struct xfrm_type *type) | ||
174 | { | ||
175 | module_put(type->owner); | ||
176 | } | ||
177 | |||
178 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | ||
179 | { | ||
180 | struct xfrm_policy_afinfo *afinfo; | ||
181 | struct xfrm_mode **modemap; | ||
182 | int err; | ||
183 | |||
184 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
185 | return -EINVAL; | ||
186 | |||
187 | afinfo = xfrm_policy_lock_afinfo(family); | ||
188 | if (unlikely(afinfo == NULL)) | ||
189 | return -EAFNOSUPPORT; | ||
190 | |||
191 | err = -EEXIST; | ||
192 | modemap = afinfo->mode_map; | ||
193 | if (likely(modemap[mode->encap] == NULL)) { | ||
194 | modemap[mode->encap] = mode; | ||
195 | err = 0; | ||
196 | } | ||
197 | |||
198 | xfrm_policy_unlock_afinfo(afinfo); | ||
199 | return err; | ||
200 | } | ||
201 | EXPORT_SYMBOL(xfrm_register_mode); | ||
202 | |||
203 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | ||
204 | { | ||
205 | struct xfrm_policy_afinfo *afinfo; | ||
206 | struct xfrm_mode **modemap; | ||
207 | int err; | ||
208 | |||
209 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
210 | return -EINVAL; | ||
211 | |||
212 | afinfo = xfrm_policy_lock_afinfo(family); | ||
213 | if (unlikely(afinfo == NULL)) | ||
214 | return -EAFNOSUPPORT; | ||
215 | |||
216 | err = -ENOENT; | ||
217 | modemap = afinfo->mode_map; | ||
218 | if (likely(modemap[mode->encap] == mode)) { | ||
219 | modemap[mode->encap] = NULL; | ||
220 | err = 0; | ||
221 | } | ||
222 | |||
223 | xfrm_policy_unlock_afinfo(afinfo); | ||
224 | return err; | ||
225 | } | ||
226 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
227 | |||
228 | struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
229 | { | ||
230 | struct xfrm_policy_afinfo *afinfo; | ||
231 | struct xfrm_mode *mode; | ||
232 | int modload_attempted = 0; | ||
233 | |||
234 | if (unlikely(encap >= XFRM_MODE_MAX)) | ||
235 | return NULL; | ||
236 | |||
237 | retry: | ||
238 | afinfo = xfrm_policy_get_afinfo(family); | ||
239 | if (unlikely(afinfo == NULL)) | ||
240 | return NULL; | ||
241 | |||
242 | mode = afinfo->mode_map[encap]; | ||
243 | if (unlikely(mode && !try_module_get(mode->owner))) | ||
244 | mode = NULL; | ||
245 | if (!mode && !modload_attempted) { | ||
246 | xfrm_policy_put_afinfo(afinfo); | ||
247 | request_module("xfrm-mode-%d-%d", family, encap); | ||
248 | modload_attempted = 1; | ||
249 | goto retry; | ||
250 | } | ||
251 | |||
252 | xfrm_policy_put_afinfo(afinfo); | ||
253 | return mode; | ||
254 | } | ||
255 | |||
256 | void xfrm_put_mode(struct xfrm_mode *mode) | ||
257 | { | ||
258 | module_put(mode->owner); | ||
259 | } | ||
260 | |||
261 | static inline unsigned long make_jiffies(long secs) | 105 | static inline unsigned long make_jiffies(long secs) |
262 | { | 106 | { |
263 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) | 107 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) |
@@ -2096,7 +1940,8 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, | |||
2096 | if (xdst->genid != dst->xfrm->genid) | 1940 | if (xdst->genid != dst->xfrm->genid) |
2097 | return 0; | 1941 | return 0; |
2098 | 1942 | ||
2099 | if (strict && fl && dst->xfrm->props.mode != XFRM_MODE_TUNNEL && | 1943 | if (strict && fl && |
1944 | !(dst->xfrm->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | ||
2100 | !xfrm_state_addr_flow_check(dst->xfrm, fl, family)) | 1945 | !xfrm_state_addr_flow_check(dst->xfrm, fl, family)) |
2101 | return 0; | 1946 | return 0; |
2102 | 1947 | ||
@@ -2213,23 +2058,6 @@ static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2213 | read_unlock(&xfrm_policy_afinfo_lock); | 2058 | read_unlock(&xfrm_policy_afinfo_lock); |
2214 | } | 2059 | } |
2215 | 2060 | ||
2216 | static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family) | ||
2217 | { | ||
2218 | struct xfrm_policy_afinfo *afinfo; | ||
2219 | if (unlikely(family >= NPROTO)) | ||
2220 | return NULL; | ||
2221 | write_lock_bh(&xfrm_policy_afinfo_lock); | ||
2222 | afinfo = xfrm_policy_afinfo[family]; | ||
2223 | if (unlikely(!afinfo)) | ||
2224 | write_unlock_bh(&xfrm_policy_afinfo_lock); | ||
2225 | return afinfo; | ||
2226 | } | ||
2227 | |||
2228 | static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo) | ||
2229 | { | ||
2230 | write_unlock_bh(&xfrm_policy_afinfo_lock); | ||
2231 | } | ||
2232 | |||
2233 | static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) | 2061 | static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) |
2234 | { | 2062 | { |
2235 | struct net_device *dev = ptr; | 2063 | struct net_device *dev = ptr; |
@@ -2464,7 +2292,8 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, | |||
2464 | if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) | 2292 | if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) |
2465 | continue; | 2293 | continue; |
2466 | n++; | 2294 | n++; |
2467 | if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL) | 2295 | if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL && |
2296 | pol->xfrm_vec[i].mode != XFRM_MODE_BEET) | ||
2468 | continue; | 2297 | continue; |
2469 | /* update endpoints */ | 2298 | /* update endpoints */ |
2470 | memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, | 2299 | memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 344f0a6abec5..224b44e31a07 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -57,6 +57,9 @@ static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; | |||
57 | static unsigned int xfrm_state_num; | 57 | static unsigned int xfrm_state_num; |
58 | static unsigned int xfrm_state_genid; | 58 | static unsigned int xfrm_state_genid; |
59 | 59 | ||
60 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | ||
61 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | ||
62 | |||
60 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, | 63 | static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, |
61 | xfrm_address_t *saddr, | 64 | xfrm_address_t *saddr, |
62 | u32 reqid, | 65 | u32 reqid, |
@@ -187,6 +190,184 @@ int __xfrm_state_delete(struct xfrm_state *x); | |||
187 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 190 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
188 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); | 191 | void km_state_expired(struct xfrm_state *x, int hard, u32 pid); |
189 | 192 | ||
193 | static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) | ||
194 | { | ||
195 | struct xfrm_state_afinfo *afinfo; | ||
196 | if (unlikely(family >= NPROTO)) | ||
197 | return NULL; | ||
198 | write_lock_bh(&xfrm_state_afinfo_lock); | ||
199 | afinfo = xfrm_state_afinfo[family]; | ||
200 | if (unlikely(!afinfo)) | ||
201 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
202 | return afinfo; | ||
203 | } | ||
204 | |||
205 | static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) | ||
206 | { | ||
207 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
208 | } | ||
209 | |||
210 | int xfrm_register_type(struct xfrm_type *type, unsigned short family) | ||
211 | { | ||
212 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | ||
213 | struct xfrm_type **typemap; | ||
214 | int err = 0; | ||
215 | |||
216 | if (unlikely(afinfo == NULL)) | ||
217 | return -EAFNOSUPPORT; | ||
218 | typemap = afinfo->type_map; | ||
219 | |||
220 | if (likely(typemap[type->proto] == NULL)) | ||
221 | typemap[type->proto] = type; | ||
222 | else | ||
223 | err = -EEXIST; | ||
224 | xfrm_state_unlock_afinfo(afinfo); | ||
225 | return err; | ||
226 | } | ||
227 | EXPORT_SYMBOL(xfrm_register_type); | ||
228 | |||
229 | int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) | ||
230 | { | ||
231 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | ||
232 | struct xfrm_type **typemap; | ||
233 | int err = 0; | ||
234 | |||
235 | if (unlikely(afinfo == NULL)) | ||
236 | return -EAFNOSUPPORT; | ||
237 | typemap = afinfo->type_map; | ||
238 | |||
239 | if (unlikely(typemap[type->proto] != type)) | ||
240 | err = -ENOENT; | ||
241 | else | ||
242 | typemap[type->proto] = NULL; | ||
243 | xfrm_state_unlock_afinfo(afinfo); | ||
244 | return err; | ||
245 | } | ||
246 | EXPORT_SYMBOL(xfrm_unregister_type); | ||
247 | |||
248 | static struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) | ||
249 | { | ||
250 | struct xfrm_state_afinfo *afinfo; | ||
251 | struct xfrm_type **typemap; | ||
252 | struct xfrm_type *type; | ||
253 | int modload_attempted = 0; | ||
254 | |||
255 | retry: | ||
256 | afinfo = xfrm_state_get_afinfo(family); | ||
257 | if (unlikely(afinfo == NULL)) | ||
258 | return NULL; | ||
259 | typemap = afinfo->type_map; | ||
260 | |||
261 | type = typemap[proto]; | ||
262 | if (unlikely(type && !try_module_get(type->owner))) | ||
263 | type = NULL; | ||
264 | if (!type && !modload_attempted) { | ||
265 | xfrm_state_put_afinfo(afinfo); | ||
266 | request_module("xfrm-type-%d-%d", family, proto); | ||
267 | modload_attempted = 1; | ||
268 | goto retry; | ||
269 | } | ||
270 | |||
271 | xfrm_state_put_afinfo(afinfo); | ||
272 | return type; | ||
273 | } | ||
274 | |||
275 | static void xfrm_put_type(struct xfrm_type *type) | ||
276 | { | ||
277 | module_put(type->owner); | ||
278 | } | ||
279 | |||
280 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | ||
281 | { | ||
282 | struct xfrm_state_afinfo *afinfo; | ||
283 | struct xfrm_mode **modemap; | ||
284 | int err; | ||
285 | |||
286 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
287 | return -EINVAL; | ||
288 | |||
289 | afinfo = xfrm_state_lock_afinfo(family); | ||
290 | if (unlikely(afinfo == NULL)) | ||
291 | return -EAFNOSUPPORT; | ||
292 | |||
293 | err = -EEXIST; | ||
294 | modemap = afinfo->mode_map; | ||
295 | if (modemap[mode->encap]) | ||
296 | goto out; | ||
297 | |||
298 | err = -ENOENT; | ||
299 | if (!try_module_get(afinfo->owner)) | ||
300 | goto out; | ||
301 | |||
302 | mode->afinfo = afinfo; | ||
303 | modemap[mode->encap] = mode; | ||
304 | err = 0; | ||
305 | |||
306 | out: | ||
307 | xfrm_state_unlock_afinfo(afinfo); | ||
308 | return err; | ||
309 | } | ||
310 | EXPORT_SYMBOL(xfrm_register_mode); | ||
311 | |||
312 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | ||
313 | { | ||
314 | struct xfrm_state_afinfo *afinfo; | ||
315 | struct xfrm_mode **modemap; | ||
316 | int err; | ||
317 | |||
318 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
319 | return -EINVAL; | ||
320 | |||
321 | afinfo = xfrm_state_lock_afinfo(family); | ||
322 | if (unlikely(afinfo == NULL)) | ||
323 | return -EAFNOSUPPORT; | ||
324 | |||
325 | err = -ENOENT; | ||
326 | modemap = afinfo->mode_map; | ||
327 | if (likely(modemap[mode->encap] == mode)) { | ||
328 | modemap[mode->encap] = NULL; | ||
329 | module_put(mode->afinfo->owner); | ||
330 | err = 0; | ||
331 | } | ||
332 | |||
333 | xfrm_state_unlock_afinfo(afinfo); | ||
334 | return err; | ||
335 | } | ||
336 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
337 | |||
338 | static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
339 | { | ||
340 | struct xfrm_state_afinfo *afinfo; | ||
341 | struct xfrm_mode *mode; | ||
342 | int modload_attempted = 0; | ||
343 | |||
344 | if (unlikely(encap >= XFRM_MODE_MAX)) | ||
345 | return NULL; | ||
346 | |||
347 | retry: | ||
348 | afinfo = xfrm_state_get_afinfo(family); | ||
349 | if (unlikely(afinfo == NULL)) | ||
350 | return NULL; | ||
351 | |||
352 | mode = afinfo->mode_map[encap]; | ||
353 | if (unlikely(mode && !try_module_get(mode->owner))) | ||
354 | mode = NULL; | ||
355 | if (!mode && !modload_attempted) { | ||
356 | xfrm_state_put_afinfo(afinfo); | ||
357 | request_module("xfrm-mode-%d-%d", family, encap); | ||
358 | modload_attempted = 1; | ||
359 | goto retry; | ||
360 | } | ||
361 | |||
362 | xfrm_state_put_afinfo(afinfo); | ||
363 | return mode; | ||
364 | } | ||
365 | |||
366 | static void xfrm_put_mode(struct xfrm_mode *mode) | ||
367 | { | ||
368 | module_put(mode->owner); | ||
369 | } | ||
370 | |||
190 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 371 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
191 | { | 372 | { |
192 | del_timer_sync(&x->timer); | 373 | del_timer_sync(&x->timer); |
@@ -196,8 +377,10 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
196 | kfree(x->calg); | 377 | kfree(x->calg); |
197 | kfree(x->encap); | 378 | kfree(x->encap); |
198 | kfree(x->coaddr); | 379 | kfree(x->coaddr); |
199 | if (x->mode) | 380 | if (x->inner_mode) |
200 | xfrm_put_mode(x->mode); | 381 | xfrm_put_mode(x->inner_mode); |
382 | if (x->outer_mode) | ||
383 | xfrm_put_mode(x->outer_mode); | ||
201 | if (x->type) { | 384 | if (x->type) { |
202 | x->type->destructor(x); | 385 | x->type->destructor(x); |
203 | xfrm_put_type(x->type); | 386 | xfrm_put_type(x->type); |
@@ -1699,7 +1882,7 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1699 | } | 1882 | } |
1700 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1883 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1701 | 1884 | ||
1702 | struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | 1885 | static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) |
1703 | { | 1886 | { |
1704 | struct xfrm_state_afinfo *afinfo; | 1887 | struct xfrm_state_afinfo *afinfo; |
1705 | if (unlikely(family >= NPROTO)) | 1888 | if (unlikely(family >= NPROTO)) |
@@ -1711,14 +1894,11 @@ struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family) | |||
1711 | return afinfo; | 1894 | return afinfo; |
1712 | } | 1895 | } |
1713 | 1896 | ||
1714 | void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1897 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1715 | { | 1898 | { |
1716 | read_unlock(&xfrm_state_afinfo_lock); | 1899 | read_unlock(&xfrm_state_afinfo_lock); |
1717 | } | 1900 | } |
1718 | 1901 | ||
1719 | EXPORT_SYMBOL(xfrm_state_get_afinfo); | ||
1720 | EXPORT_SYMBOL(xfrm_state_put_afinfo); | ||
1721 | |||
1722 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ | 1902 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ |
1723 | void xfrm_state_delete_tunnel(struct xfrm_state *x) | 1903 | void xfrm_state_delete_tunnel(struct xfrm_state *x) |
1724 | { | 1904 | { |
@@ -1769,6 +1949,14 @@ int xfrm_init_state(struct xfrm_state *x) | |||
1769 | goto error; | 1949 | goto error; |
1770 | 1950 | ||
1771 | err = -EPROTONOSUPPORT; | 1951 | err = -EPROTONOSUPPORT; |
1952 | x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); | ||
1953 | if (x->inner_mode == NULL) | ||
1954 | goto error; | ||
1955 | |||
1956 | if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && | ||
1957 | family != x->sel.family) | ||
1958 | goto error; | ||
1959 | |||
1772 | x->type = xfrm_get_type(x->id.proto, family); | 1960 | x->type = xfrm_get_type(x->id.proto, family); |
1773 | if (x->type == NULL) | 1961 | if (x->type == NULL) |
1774 | goto error; | 1962 | goto error; |
@@ -1777,8 +1965,8 @@ int xfrm_init_state(struct xfrm_state *x) | |||
1777 | if (err) | 1965 | if (err) |
1778 | goto error; | 1966 | goto error; |
1779 | 1967 | ||
1780 | x->mode = xfrm_get_mode(x->props.mode, family); | 1968 | x->outer_mode = xfrm_get_mode(x->props.mode, family); |
1781 | if (x->mode == NULL) | 1969 | if (x->outer_mode == NULL) |
1782 | goto error; | 1970 | goto error; |
1783 | 1971 | ||
1784 | x->km.state = XFRM_STATE_VALID; | 1972 | x->km.state = XFRM_STATE_VALID; |