diff options
-rw-r--r-- | include/net/ipv6.h | 4 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 123 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 122 |
3 files changed, 123 insertions, 126 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 96b1763bfcaa..5dc8164e5d3b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -555,10 +555,6 @@ extern int compat_ipv6_getsockopt(struct sock *sk, | |||
555 | char __user *optval, | 555 | char __user *optval, |
556 | int __user *optlen); | 556 | int __user *optlen); |
557 | 557 | ||
558 | extern int ipv6_packet_init(void); | ||
559 | |||
560 | extern void ipv6_packet_cleanup(void); | ||
561 | |||
562 | extern int ip6_datagram_connect(struct sock *sk, | 558 | extern int ip6_datagram_connect(struct sock *sk, |
563 | struct sockaddr *addr, int addr_len); | 559 | struct sockaddr *addr, int addr_len); |
564 | 560 | ||
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 243c42a6b80d..73021d5baece 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -678,6 +678,129 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) | |||
678 | 678 | ||
679 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); | 679 | EXPORT_SYMBOL_GPL(ipv6_opt_accepted); |
680 | 680 | ||
681 | static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | ||
682 | int proto) | ||
683 | { | ||
684 | struct inet6_protocol *ops = NULL; | ||
685 | |||
686 | for (;;) { | ||
687 | struct ipv6_opt_hdr *opth; | ||
688 | int len; | ||
689 | |||
690 | if (proto != NEXTHDR_HOP) { | ||
691 | ops = rcu_dereference(inet6_protos[proto]); | ||
692 | |||
693 | if (unlikely(!ops)) | ||
694 | break; | ||
695 | |||
696 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
701 | break; | ||
702 | |||
703 | opth = (void *)skb->data; | ||
704 | len = ipv6_optlen(opth); | ||
705 | |||
706 | if (unlikely(!pskb_may_pull(skb, len))) | ||
707 | break; | ||
708 | |||
709 | proto = opth->nexthdr; | ||
710 | __skb_pull(skb, len); | ||
711 | } | ||
712 | |||
713 | return ops; | ||
714 | } | ||
715 | |||
716 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
717 | { | ||
718 | struct ipv6hdr *ipv6h; | ||
719 | struct inet6_protocol *ops; | ||
720 | int err = -EINVAL; | ||
721 | |||
722 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
723 | goto out; | ||
724 | |||
725 | ipv6h = ipv6_hdr(skb); | ||
726 | __skb_pull(skb, sizeof(*ipv6h)); | ||
727 | err = -EPROTONOSUPPORT; | ||
728 | |||
729 | rcu_read_lock(); | ||
730 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
731 | if (likely(ops && ops->gso_send_check)) { | ||
732 | skb_reset_transport_header(skb); | ||
733 | err = ops->gso_send_check(skb); | ||
734 | } | ||
735 | rcu_read_unlock(); | ||
736 | |||
737 | out: | ||
738 | return err; | ||
739 | } | ||
740 | |||
741 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | ||
742 | { | ||
743 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
744 | struct ipv6hdr *ipv6h; | ||
745 | struct inet6_protocol *ops; | ||
746 | |||
747 | if (!(features & NETIF_F_V6_CSUM)) | ||
748 | features &= ~NETIF_F_SG; | ||
749 | |||
750 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
751 | ~(SKB_GSO_UDP | | ||
752 | SKB_GSO_DODGY | | ||
753 | SKB_GSO_TCP_ECN | | ||
754 | SKB_GSO_TCPV6 | | ||
755 | 0))) | ||
756 | goto out; | ||
757 | |||
758 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
759 | goto out; | ||
760 | |||
761 | ipv6h = ipv6_hdr(skb); | ||
762 | __skb_pull(skb, sizeof(*ipv6h)); | ||
763 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
764 | |||
765 | rcu_read_lock(); | ||
766 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
767 | if (likely(ops && ops->gso_segment)) { | ||
768 | skb_reset_transport_header(skb); | ||
769 | segs = ops->gso_segment(skb, features); | ||
770 | } | ||
771 | rcu_read_unlock(); | ||
772 | |||
773 | if (unlikely(IS_ERR(segs))) | ||
774 | goto out; | ||
775 | |||
776 | for (skb = segs; skb; skb = skb->next) { | ||
777 | ipv6h = ipv6_hdr(skb); | ||
778 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
779 | sizeof(*ipv6h)); | ||
780 | } | ||
781 | |||
782 | out: | ||
783 | return segs; | ||
784 | } | ||
785 | |||
786 | static struct packet_type ipv6_packet_type = { | ||
787 | .type = __constant_htons(ETH_P_IPV6), | ||
788 | .func = ipv6_rcv, | ||
789 | .gso_send_check = ipv6_gso_send_check, | ||
790 | .gso_segment = ipv6_gso_segment, | ||
791 | }; | ||
792 | |||
793 | static int __init ipv6_packet_init(void) | ||
794 | { | ||
795 | dev_add_pack(&ipv6_packet_type); | ||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | static void ipv6_packet_cleanup(void) | ||
800 | { | ||
801 | dev_remove_pack(&ipv6_packet_type); | ||
802 | } | ||
803 | |||
681 | static int __init init_ipv6_mibs(void) | 804 | static int __init init_ipv6_mibs(void) |
682 | { | 805 | { |
683 | if (snmp_mib_init((void **)ipv6_statistics, | 806 | if (snmp_mib_init((void **)ipv6_statistics, |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0a18fecb93d1..3bbfdff698d2 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -57,118 +57,6 @@ | |||
57 | 57 | ||
58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; | 58 | DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; |
59 | 59 | ||
60 | static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, | ||
61 | int proto) | ||
62 | { | ||
63 | struct inet6_protocol *ops = NULL; | ||
64 | |||
65 | for (;;) { | ||
66 | struct ipv6_opt_hdr *opth; | ||
67 | int len; | ||
68 | |||
69 | if (proto != NEXTHDR_HOP) { | ||
70 | ops = rcu_dereference(inet6_protos[proto]); | ||
71 | |||
72 | if (unlikely(!ops)) | ||
73 | break; | ||
74 | |||
75 | if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | if (unlikely(!pskb_may_pull(skb, 8))) | ||
80 | break; | ||
81 | |||
82 | opth = (void *)skb->data; | ||
83 | len = opth->hdrlen * 8 + 8; | ||
84 | |||
85 | if (unlikely(!pskb_may_pull(skb, len))) | ||
86 | break; | ||
87 | |||
88 | proto = opth->nexthdr; | ||
89 | __skb_pull(skb, len); | ||
90 | } | ||
91 | |||
92 | return ops; | ||
93 | } | ||
94 | |||
95 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
96 | { | ||
97 | struct ipv6hdr *ipv6h; | ||
98 | struct inet6_protocol *ops; | ||
99 | int err = -EINVAL; | ||
100 | |||
101 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
102 | goto out; | ||
103 | |||
104 | ipv6h = ipv6_hdr(skb); | ||
105 | __skb_pull(skb, sizeof(*ipv6h)); | ||
106 | err = -EPROTONOSUPPORT; | ||
107 | |||
108 | rcu_read_lock(); | ||
109 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
110 | if (likely(ops && ops->gso_send_check)) { | ||
111 | skb_reset_transport_header(skb); | ||
112 | err = ops->gso_send_check(skb); | ||
113 | } | ||
114 | rcu_read_unlock(); | ||
115 | |||
116 | out: | ||
117 | return err; | ||
118 | } | ||
119 | |||
120 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) | ||
121 | { | ||
122 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
123 | struct ipv6hdr *ipv6h; | ||
124 | struct inet6_protocol *ops; | ||
125 | |||
126 | if (!(features & NETIF_F_V6_CSUM)) | ||
127 | features &= ~NETIF_F_SG; | ||
128 | |||
129 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
130 | ~(SKB_GSO_UDP | | ||
131 | SKB_GSO_DODGY | | ||
132 | SKB_GSO_TCP_ECN | | ||
133 | SKB_GSO_TCPV6 | | ||
134 | 0))) | ||
135 | goto out; | ||
136 | |||
137 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
138 | goto out; | ||
139 | |||
140 | ipv6h = ipv6_hdr(skb); | ||
141 | __skb_pull(skb, sizeof(*ipv6h)); | ||
142 | segs = ERR_PTR(-EPROTONOSUPPORT); | ||
143 | |||
144 | rcu_read_lock(); | ||
145 | ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); | ||
146 | if (likely(ops && ops->gso_segment)) { | ||
147 | skb_reset_transport_header(skb); | ||
148 | segs = ops->gso_segment(skb, features); | ||
149 | } | ||
150 | rcu_read_unlock(); | ||
151 | |||
152 | if (unlikely(IS_ERR(segs))) | ||
153 | goto out; | ||
154 | |||
155 | for (skb = segs; skb; skb = skb->next) { | ||
156 | ipv6h = ipv6_hdr(skb); | ||
157 | ipv6h->payload_len = htons(skb->len - skb->mac_len - | ||
158 | sizeof(*ipv6h)); | ||
159 | } | ||
160 | |||
161 | out: | ||
162 | return segs; | ||
163 | } | ||
164 | |||
165 | static struct packet_type ipv6_packet_type = { | ||
166 | .type = __constant_htons(ETH_P_IPV6), | ||
167 | .func = ipv6_rcv, | ||
168 | .gso_send_check = ipv6_gso_send_check, | ||
169 | .gso_segment = ipv6_gso_segment, | ||
170 | }; | ||
171 | |||
172 | struct ip6_ra_chain *ip6_ra_chain; | 60 | struct ip6_ra_chain *ip6_ra_chain; |
173 | DEFINE_RWLOCK(ip6_ra_lock); | 61 | DEFINE_RWLOCK(ip6_ra_lock); |
174 | 62 | ||
@@ -1132,13 +1020,3 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1132 | EXPORT_SYMBOL(compat_ipv6_getsockopt); | 1020 | EXPORT_SYMBOL(compat_ipv6_getsockopt); |
1133 | #endif | 1021 | #endif |
1134 | 1022 | ||
1135 | int __init ipv6_packet_init(void) | ||
1136 | { | ||
1137 | dev_add_pack(&ipv6_packet_type); | ||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | void ipv6_packet_cleanup(void) | ||
1142 | { | ||
1143 | dev_remove_pack(&ipv6_packet_type); | ||
1144 | } | ||