diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 17:25:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 17:25:41 -0500 |
commit | 5fbbf5f648a9c4ef99276854f05b2255d1b004d3 (patch) | |
tree | 59c9ae762c3df2800e894001b3de58c5f1972486 /net/ipv6 | |
parent | ce279e6ec91c49f2c5f59f7492e19d39edbf8bbd (diff) | |
parent | 56cf391a9462a4897ea660a6af3662dda5ae8c84 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (84 commits)
wimax: fix kernel-doc for debufs_dentry member of struct wimax_dev
net: convert pegasus driver to net_device_ops
bnx2x: Prevent eeprom set when driver is down
net: switch kaweth driver to netdevops
pcnet32: round off carrier watch timer
i2400m/usb: wrap USB power saving in #ifdef CONFIG_PM
wimax: testing for rfkill support should also test for CONFIG_RFKILL_MODULE
wimax: fix kconfig interactions with rfkill and input layers
wimax: fix '#ifndef CONFIG_BUG' layout to avoid warning
r6040: bump release number to 0.20
r6040: warn about MAC address being unset
r6040: check PHY status when bringing interface up
r6040: make printks consistent with DRV_NAME
gianfar: Fixup use of BUS_ID_SIZE
mlx4_en: Returning real Max in get_ringparam
mlx4_en: Consider inline packets on completion
netdev: bfin_mac: enable bfin_mac net dev driver for BF51x
qeth: convert to net_device_ops
vlan: add neigh_setup
dm9601: warn on invalid mac address
...
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/af_inet6.c | 107 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 45 |
2 files changed, 143 insertions, 9 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 437b750b98fd..94f74f5b0cbf 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -672,8 +672,7 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) | |||
672 | 672 | ||
673 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); | 673 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); |
674 | 674 | ||
675 | static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | 675 | static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) |
676 | int proto) | ||
677 | { | 676 | { |
678 | struct inet6_protocol *ops = NULL; | 677 | struct inet6_protocol *ops = NULL; |
679 | 678 | ||
@@ -704,7 +703,7 @@ static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | |||
704 | __skb_pull(skb, len); | 703 | __skb_pull(skb, len); |
705 | } | 704 | } |
706 | 705 | ||
707 | return ops; | 706 | return proto; |
708 | } | 707 | } |
709 | 708 | ||
710 | static int ipv6_gso_send_check(struct sk_buff *skb) | 709 | static int ipv6_gso_send_check(struct sk_buff *skb) |
@@ -721,7 +720,9 @@ static int ipv6_gso_send_check(struct sk_buff *skb) | |||
721 | err = -EPROTONOSUPPORT; | 720 | err = -EPROTONOSUPPORT; |
722 | 721 | ||
723 | rcu_read_lock(); | 722 | rcu_read_lock(); |
724 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | 723 | ops = rcu_dereference(inet6_protos[ |
724 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
725 | |||
725 | if (likely(ops && ops->gso_send_check)) { | 726 | if (likely(ops && ops->gso_send_check)) { |
726 | skb_reset_transport_header(skb); | 727 | skb_reset_transport_header(skb); |
727 | err = ops->gso_send_check(skb); | 728 | err = ops->gso_send_check(skb); |
@@ -757,7 +758,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | |||
757 | segs = ERR_PTR(-EPROTONOSUPPORT); | 758 | segs = ERR_PTR(-EPROTONOSUPPORT); |
758 | 759 | ||
759 | rcu_read_lock(); | 760 | rcu_read_lock(); |
760 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | 761 | ops = rcu_dereference(inet6_protos[ |
762 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
763 | |||
761 | if (likely(ops && ops->gso_segment)) { | 764 | if (likely(ops && ops->gso_segment)) { |
762 | skb_reset_transport_header(skb); | 765 | skb_reset_transport_header(skb); |
763 | segs = ops->gso_segment(skb, features); | 766 | segs = ops->gso_segment(skb, features); |
@@ -777,11 +780,105 @@ out: | |||
777 | return segs; | 780 | return segs; |
778 | } | 781 | } |
779 | 782 | ||
783 | struct ipv6_gro_cb { | ||
784 | struct napi_gro_cb napi; | ||
785 | int proto; | ||
786 | }; | ||
787 | |||
788 | #define IPV6_GRO_CB(skb) ((struct ipv6_gro_cb *)(skb)->cb) | ||
789 | |||
790 | static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | ||
791 | struct sk_buff *skb) | ||
792 | { | ||
793 | struct inet6_protocol *ops; | ||
794 | struct sk_buff **pp = NULL; | ||
795 | struct sk_buff *p; | ||
796 | struct ipv6hdr *iph; | ||
797 | unsigned int nlen; | ||
798 | int flush = 1; | ||
799 | int proto; | ||
800 | |||
801 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) | ||
802 | goto out; | ||
803 | |||
804 | iph = ipv6_hdr(skb); | ||
805 | __skb_pull(skb, sizeof(*iph)); | ||
806 | |||
807 | flush += ntohs(iph->payload_len) != skb->len; | ||
808 | |||
809 | rcu_read_lock(); | ||
810 | proto = ipv6_gso_pull_exthdrs(skb, iph->nexthdr); | ||
811 | IPV6_GRO_CB(skb)->proto = proto; | ||
812 | ops = rcu_dereference(inet6_protos[proto]); | ||
813 | if (!ops || !ops->gro_receive) | ||
814 | goto out_unlock; | ||
815 | |||
816 | flush--; | ||
817 | skb_reset_transport_header(skb); | ||
818 | nlen = skb_network_header_len(skb); | ||
819 | |||
820 | for (p = *head; p; p = p->next) { | ||
821 | struct ipv6hdr *iph2; | ||
822 | |||
823 | if (!NAPI_GRO_CB(p)->same_flow) | ||
824 | continue; | ||
825 | |||
826 | iph2 = ipv6_hdr(p); | ||
827 | |||
828 | /* All fields must match except length. */ | ||
829 | if (nlen != skb_network_header_len(p) || | ||
830 | memcmp(iph, iph2, offsetof(struct ipv6hdr, payload_len)) || | ||
831 | memcmp(&iph->nexthdr, &iph2->nexthdr, | ||
832 | nlen - offsetof(struct ipv6hdr, nexthdr))) { | ||
833 | NAPI_GRO_CB(p)->same_flow = 0; | ||
834 | continue; | ||
835 | } | ||
836 | |||
837 | NAPI_GRO_CB(p)->flush |= flush; | ||
838 | } | ||
839 | |||
840 | NAPI_GRO_CB(skb)->flush |= flush; | ||
841 | |||
842 | pp = ops->gro_receive(head, skb); | ||
843 | |||
844 | out_unlock: | ||
845 | rcu_read_unlock(); | ||
846 | |||
847 | out: | ||
848 | NAPI_GRO_CB(skb)->flush |= flush; | ||
849 | |||
850 | return pp; | ||
851 | } | ||
852 | |||
853 | static int ipv6_gro_complete(struct sk_buff *skb) | ||
854 | { | ||
855 | struct inet6_protocol *ops; | ||
856 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
857 | int err = -ENOSYS; | ||
858 | |||
859 | iph->payload_len = htons(skb->len - skb_network_offset(skb) - | ||
860 | sizeof(*iph)); | ||
861 | |||
862 | rcu_read_lock(); | ||
863 | ops = rcu_dereference(inet6_protos[IPV6_GRO_CB(skb)->proto]); | ||
864 | if (WARN_ON(!ops || !ops->gro_complete)) | ||
865 | goto out_unlock; | ||
866 | |||
867 | err = ops->gro_complete(skb); | ||
868 | |||
869 | out_unlock: | ||
870 | rcu_read_unlock(); | ||
871 | |||
872 | return err; | ||
873 | } | ||
874 | |||
780 | static struct packet_type ipv6_packet_type = { | 875 | static struct packet_type ipv6_packet_type = { |
781 | .type = __constant_htons(ETH_P_IPV6), | 876 | .type = __constant_htons(ETH_P_IPV6), |
782 | .func = ipv6_rcv, | 877 | .func = ipv6_rcv, |
783 | .gso_send_check = ipv6_gso_send_check, | 878 | .gso_send_check = ipv6_gso_send_check, |
784 | .gso_segment = ipv6_gso_segment, | 879 | .gso_segment = ipv6_gso_segment, |
880 | .gro_receive = ipv6_gro_receive, | ||
881 | .gro_complete = ipv6_gro_complete, | ||
785 | }; | 882 | }; |
786 | 883 | ||
787 | static int __init ipv6_packet_init(void) | 884 | static int __init ipv6_packet_init(void) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e8b8337a8310..1297306d729c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -101,7 +101,7 @@ static void tcp_v6_hash(struct sock *sk) | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | static __inline__ __sum16 tcp_v6_check(struct tcphdr *th, int len, | 104 | static __inline__ __sum16 tcp_v6_check(int len, |
105 | struct in6_addr *saddr, | 105 | struct in6_addr *saddr, |
106 | struct in6_addr *daddr, | 106 | struct in6_addr *daddr, |
107 | __wsum base) | 107 | __wsum base) |
@@ -501,7 +501,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) | |||
501 | if (skb) { | 501 | if (skb) { |
502 | struct tcphdr *th = tcp_hdr(skb); | 502 | struct tcphdr *th = tcp_hdr(skb); |
503 | 503 | ||
504 | th->check = tcp_v6_check(th, skb->len, | 504 | th->check = tcp_v6_check(skb->len, |
505 | &treq->loc_addr, &treq->rmt_addr, | 505 | &treq->loc_addr, &treq->rmt_addr, |
506 | csum_partial(th, skb->len, skb->csum)); | 506 | csum_partial(th, skb->len, skb->csum)); |
507 | 507 | ||
@@ -942,6 +942,41 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb) | |||
942 | return 0; | 942 | return 0; |
943 | } | 943 | } |
944 | 944 | ||
945 | struct sk_buff **tcp6_gro_receive(struct sk_buff **head, struct sk_buff *skb) | ||
946 | { | ||
947 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
948 | |||
949 | switch (skb->ip_summed) { | ||
950 | case CHECKSUM_COMPLETE: | ||
951 | if (!tcp_v6_check(skb->len, &iph->saddr, &iph->daddr, | ||
952 | skb->csum)) { | ||
953 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | /* fall through */ | ||
958 | case CHECKSUM_NONE: | ||
959 | NAPI_GRO_CB(skb)->flush = 1; | ||
960 | return NULL; | ||
961 | } | ||
962 | |||
963 | return tcp_gro_receive(head, skb); | ||
964 | } | ||
965 | EXPORT_SYMBOL(tcp6_gro_receive); | ||
966 | |||
967 | int tcp6_gro_complete(struct sk_buff *skb) | ||
968 | { | ||
969 | struct ipv6hdr *iph = ipv6_hdr(skb); | ||
970 | struct tcphdr *th = tcp_hdr(skb); | ||
971 | |||
972 | th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), | ||
973 | &iph->saddr, &iph->daddr, 0); | ||
974 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | ||
975 | |||
976 | return tcp_gro_complete(skb); | ||
977 | } | ||
978 | EXPORT_SYMBOL(tcp6_gro_complete); | ||
979 | |||
945 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | 980 | static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, |
946 | u32 ts, struct tcp_md5sig_key *key, int rst) | 981 | u32 ts, struct tcp_md5sig_key *key, int rst) |
947 | { | 982 | { |
@@ -1429,14 +1464,14 @@ out: | |||
1429 | static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) | 1464 | static __sum16 tcp_v6_checksum_init(struct sk_buff *skb) |
1430 | { | 1465 | { |
1431 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | 1466 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
1432 | if (!tcp_v6_check(tcp_hdr(skb), skb->len, &ipv6_hdr(skb)->saddr, | 1467 | if (!tcp_v6_check(skb->len, &ipv6_hdr(skb)->saddr, |
1433 | &ipv6_hdr(skb)->daddr, skb->csum)) { | 1468 | &ipv6_hdr(skb)->daddr, skb->csum)) { |
1434 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1469 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1435 | return 0; | 1470 | return 0; |
1436 | } | 1471 | } |
1437 | } | 1472 | } |
1438 | 1473 | ||
1439 | skb->csum = ~csum_unfold(tcp_v6_check(tcp_hdr(skb), skb->len, | 1474 | skb->csum = ~csum_unfold(tcp_v6_check(skb->len, |
1440 | &ipv6_hdr(skb)->saddr, | 1475 | &ipv6_hdr(skb)->saddr, |
1441 | &ipv6_hdr(skb)->daddr, 0)); | 1476 | &ipv6_hdr(skb)->daddr, 0)); |
1442 | 1477 | ||
@@ -2062,6 +2097,8 @@ static struct inet6_protocol tcpv6_protocol = { | |||
2062 | .err_handler = tcp_v6_err, | 2097 | .err_handler = tcp_v6_err, |
2063 | .gso_send_check = tcp_v6_gso_send_check, | 2098 | .gso_send_check = tcp_v6_gso_send_check, |
2064 | .gso_segment = tcp_tso_segment, | 2099 | .gso_segment = tcp_tso_segment, |
2100 | .gro_receive = tcp6_gro_receive, | ||
2101 | .gro_complete = tcp6_gro_complete, | ||
2065 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, | 2102 | .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, |
2066 | }; | 2103 | }; |
2067 | 2104 | ||