]> Pileus Git - ~andy/linux/blobdiff - net/ipv6/af_inet6.c
ipv6: Pull IPv6 GSO registration out of the module
[~andy/linux] / net / ipv6 / af_inet6.c
index f757e3b7cfbfbb969fea039a578de2791925a2ad..7bafc51cda117c1d58270773a0b42818e3addfa9 100644 (file)
@@ -699,256 +699,9 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
-static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
-{
-       const struct inet6_protocol *ops = NULL;
-
-       for (;;) {
-               struct ipv6_opt_hdr *opth;
-               int len;
-
-               if (proto != NEXTHDR_HOP) {
-                       ops = rcu_dereference(inet6_protos[proto]);
-
-                       if (unlikely(!ops))
-                               break;
-
-                       if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
-                               break;
-               }
-
-               if (unlikely(!pskb_may_pull(skb, 8)))
-                       break;
-
-               opth = (void *)skb->data;
-               len = ipv6_optlen(opth);
-
-               if (unlikely(!pskb_may_pull(skb, len)))
-                       break;
-
-               proto = opth->nexthdr;
-               __skb_pull(skb, len);
-       }
-
-       return proto;
-}
-
-static int ipv6_gso_send_check(struct sk_buff *skb)
-{
-       const struct ipv6hdr *ipv6h;
-       const struct inet6_protocol *ops;
-       int err = -EINVAL;
-
-       if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-               goto out;
-
-       ipv6h = ipv6_hdr(skb);
-       __skb_pull(skb, sizeof(*ipv6h));
-       err = -EPROTONOSUPPORT;
-
-       rcu_read_lock();
-       ops = rcu_dereference(inet6_protos[
-               ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
-
-       if (likely(ops && ops->gso_send_check)) {
-               skb_reset_transport_header(skb);
-               err = ops->gso_send_check(skb);
-       }
-       rcu_read_unlock();
-
-out:
-       return err;
-}
-
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
-       netdev_features_t features)
-{
-       struct sk_buff *segs = ERR_PTR(-EINVAL);
-       struct ipv6hdr *ipv6h;
-       const struct inet6_protocol *ops;
-       int proto;
-       struct frag_hdr *fptr;
-       unsigned int unfrag_ip6hlen;
-       u8 *prevhdr;
-       int offset = 0;
-
-       if (!(features & NETIF_F_V6_CSUM))
-               features &= ~NETIF_F_SG;
-
-       if (unlikely(skb_shinfo(skb)->gso_type &
-                    ~(SKB_GSO_UDP |
-                      SKB_GSO_DODGY |
-                      SKB_GSO_TCP_ECN |
-                      SKB_GSO_TCPV6 |
-                      0)))
-               goto out;
-
-       if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-               goto out;
-
-       ipv6h = ipv6_hdr(skb);
-       __skb_pull(skb, sizeof(*ipv6h));
-       segs = ERR_PTR(-EPROTONOSUPPORT);
-
-       proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
-       rcu_read_lock();
-       ops = rcu_dereference(inet6_protos[proto]);
-       if (likely(ops && ops->gso_segment)) {
-               skb_reset_transport_header(skb);
-               segs = ops->gso_segment(skb, features);
-       }
-       rcu_read_unlock();
-
-       if (IS_ERR(segs))
-               goto out;
-
-       for (skb = segs; skb; skb = skb->next) {
-               ipv6h = ipv6_hdr(skb);
-               ipv6h->payload_len = htons(skb->len - skb->mac_len -
-                                          sizeof(*ipv6h));
-               if (proto == IPPROTO_UDP) {
-                       unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
-                       fptr = (struct frag_hdr *)(skb_network_header(skb) +
-                               unfrag_ip6hlen);
-                       fptr->frag_off = htons(offset);
-                       if (skb->next != NULL)
-                               fptr->frag_off |= htons(IP6_MF);
-                       offset += (ntohs(ipv6h->payload_len) -
-                                  sizeof(struct frag_hdr));
-               }
-       }
-
-out:
-       return segs;
-}
-
-struct ipv6_gro_cb {
-       struct napi_gro_cb napi;
-       int proto;
-};
-
-#define IPV6_GRO_CB(skb) ((struct ipv6_gro_cb *)(skb)->cb)
-
-static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
-                                        struct sk_buff *skb)
-{
-       const struct inet6_protocol *ops;
-       struct sk_buff **pp = NULL;
-       struct sk_buff *p;
-       struct ipv6hdr *iph;
-       unsigned int nlen;
-       unsigned int hlen;
-       unsigned int off;
-       int flush = 1;
-       int proto;
-       __wsum csum;
-
-       off = skb_gro_offset(skb);
-       hlen = off + sizeof(*iph);
-       iph = skb_gro_header_fast(skb, off);
-       if (skb_gro_header_hard(skb, hlen)) {
-               iph = skb_gro_header_slow(skb, hlen, off);
-               if (unlikely(!iph))
-                       goto out;
-       }
-
-       skb_gro_pull(skb, sizeof(*iph));
-       skb_set_transport_header(skb, skb_gro_offset(skb));
-
-       flush += ntohs(iph->payload_len) != skb_gro_len(skb);
-
-       rcu_read_lock();
-       proto = iph->nexthdr;
-       ops = rcu_dereference(inet6_protos[proto]);
-       if (!ops || !ops->gro_receive) {
-               __pskb_pull(skb, skb_gro_offset(skb));
-               proto = ipv6_gso_pull_exthdrs(skb, proto);
-               skb_gro_pull(skb, -skb_transport_offset(skb));
-               skb_reset_transport_header(skb);
-               __skb_push(skb, skb_gro_offset(skb));
-
-               ops = rcu_dereference(inet6_protos[proto]);
-               if (!ops || !ops->gro_receive)
-                       goto out_unlock;
-
-               iph = ipv6_hdr(skb);
-       }
-
-       IPV6_GRO_CB(skb)->proto = proto;
-
-       flush--;
-       nlen = skb_network_header_len(skb);
-
-       for (p = *head; p; p = p->next) {
-               const struct ipv6hdr *iph2;
-               __be32 first_word; /* <Version:4><Traffic_Class:8><Flow_Label:20> */
-
-               if (!NAPI_GRO_CB(p)->same_flow)
-                       continue;
-
-               iph2 = ipv6_hdr(p);
-               first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ;
-
-               /* All fields must match except length and Traffic Class. */
-               if (nlen != skb_network_header_len(p) ||
-                   (first_word & htonl(0xF00FFFFF)) ||
-                   memcmp(&iph->nexthdr, &iph2->nexthdr,
-                          nlen - offsetof(struct ipv6hdr, nexthdr))) {
-                       NAPI_GRO_CB(p)->same_flow = 0;
-                       continue;
-               }
-               /* flush if Traffic Class fields are different */
-               NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
-               NAPI_GRO_CB(p)->flush |= flush;
-       }
-
-       NAPI_GRO_CB(skb)->flush |= flush;
-
-       csum = skb->csum;
-       skb_postpull_rcsum(skb, iph, skb_network_header_len(skb));
-
-       pp = ops->gro_receive(head, skb);
-
-       skb->csum = csum;
-
-out_unlock:
-       rcu_read_unlock();
-
-out:
-       NAPI_GRO_CB(skb)->flush |= flush;
-
-       return pp;
-}
-
-static int ipv6_gro_complete(struct sk_buff *skb)
-{
-       const struct inet6_protocol *ops;
-       struct ipv6hdr *iph = ipv6_hdr(skb);
-       int err = -ENOSYS;
-
-       iph->payload_len = htons(skb->len - skb_network_offset(skb) -
-                                sizeof(*iph));
-
-       rcu_read_lock();
-       ops = rcu_dereference(inet6_protos[IPV6_GRO_CB(skb)->proto]);
-       if (WARN_ON(!ops || !ops->gro_complete))
-               goto out_unlock;
-
-       err = ops->gro_complete(skb);
-
-out_unlock:
-       rcu_read_unlock();
-
-       return err;
-}
-
 static struct packet_type ipv6_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_IPV6),
        .func = ipv6_rcv,
-       .gso_send_check = ipv6_gso_send_check,
-       .gso_segment = ipv6_gso_segment,
-       .gro_receive = ipv6_gro_receive,
-       .gro_complete = ipv6_gro_complete,
 };
 
 static int __init ipv6_packet_init(void)