diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-02-27 09:14:03 -0500 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-03-04 01:18:23 -0500 |
commit | 662397fd7aaa10afdbdc55a0bfdb7e9701454c27 (patch) | |
tree | 7bfc7866229b2d4042164d5dd0019c46575ecbc5 /net/ipv6/af_inet6.c | |
parent | db1ed684f6c430c4cdad67d058688b8a1b5e607c (diff) |
[IPV6]: Move packet_type{} related bits to af_inet6.c.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/af_inet6.c')
-rw-r--r-- | net/ipv6/af_inet6.c | 123 |
1 files changed, 123 insertions, 0 deletions
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, |