diff options
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r-- | net/ipv6/raw.c | 125 |
1 files changed, 67 insertions, 58 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 86c39526ba5e..4a1c3b46c56b 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/netfilter.h> | 31 | #include <linux/netfilter.h> |
32 | #include <linux/netfilter_ipv6.h> | 32 | #include <linux/netfilter_ipv6.h> |
33 | #include <linux/skbuff.h> | 33 | #include <linux/skbuff.h> |
34 | #include <linux/compat.h> | ||
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
35 | #include <asm/ioctls.h> | 36 | #include <asm/ioctls.h> |
36 | 37 | ||
@@ -123,18 +124,18 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) | |||
123 | } | 124 | } |
124 | 125 | ||
125 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 126 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
126 | static int (*mh_filter)(struct sock *sock, struct sk_buff *skb); | 127 | typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb); |
127 | 128 | ||
128 | int rawv6_mh_filter_register(int (*filter)(struct sock *sock, | 129 | static mh_filter_t __rcu *mh_filter __read_mostly; |
129 | struct sk_buff *skb)) | 130 | |
131 | int rawv6_mh_filter_register(mh_filter_t filter) | ||
130 | { | 132 | { |
131 | rcu_assign_pointer(mh_filter, filter); | 133 | rcu_assign_pointer(mh_filter, filter); |
132 | return 0; | 134 | return 0; |
133 | } | 135 | } |
134 | EXPORT_SYMBOL(rawv6_mh_filter_register); | 136 | EXPORT_SYMBOL(rawv6_mh_filter_register); |
135 | 137 | ||
136 | int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, | 138 | int rawv6_mh_filter_unregister(mh_filter_t filter) |
137 | struct sk_buff *skb)) | ||
138 | { | 139 | { |
139 | rcu_assign_pointer(mh_filter, NULL); | 140 | rcu_assign_pointer(mh_filter, NULL); |
140 | synchronize_rcu(); | 141 | synchronize_rcu(); |
@@ -192,10 +193,10 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) | |||
192 | * policy is placed in rawv6_rcv() because it is | 193 | * policy is placed in rawv6_rcv() because it is |
193 | * required for each socket. | 194 | * required for each socket. |
194 | */ | 195 | */ |
195 | int (*filter)(struct sock *sock, struct sk_buff *skb); | 196 | mh_filter_t *filter; |
196 | 197 | ||
197 | filter = rcu_dereference(mh_filter); | 198 | filter = rcu_dereference(mh_filter); |
198 | filtered = filter ? filter(sk, skb) : 0; | 199 | filtered = filter ? (*filter)(sk, skb) : 0; |
199 | break; | 200 | break; |
200 | } | 201 | } |
201 | #endif | 202 | #endif |
@@ -523,7 +524,7 @@ csum_copy_err: | |||
523 | goto out; | 524 | goto out; |
524 | } | 525 | } |
525 | 526 | ||
526 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | 527 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, |
527 | struct raw6_sock *rp) | 528 | struct raw6_sock *rp) |
528 | { | 529 | { |
529 | struct sk_buff *skb; | 530 | struct sk_buff *skb; |
@@ -585,11 +586,10 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, | |||
585 | if (unlikely(csum)) | 586 | if (unlikely(csum)) |
586 | tmp_csum = csum_sub(tmp_csum, csum_unfold(csum)); | 587 | tmp_csum = csum_sub(tmp_csum, csum_unfold(csum)); |
587 | 588 | ||
588 | csum = csum_ipv6_magic(&fl->fl6_src, | 589 | csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, |
589 | &fl->fl6_dst, | 590 | total_len, fl6->flowi6_proto, tmp_csum); |
590 | total_len, fl->proto, tmp_csum); | ||
591 | 591 | ||
592 | if (csum == 0 && fl->proto == IPPROTO_UDP) | 592 | if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) |
593 | csum = CSUM_MANGLED_0; | 593 | csum = CSUM_MANGLED_0; |
594 | 594 | ||
595 | if (skb_store_bits(skb, offset, &csum, 2)) | 595 | if (skb_store_bits(skb, offset, &csum, 2)) |
@@ -602,7 +602,7 @@ out: | |||
602 | } | 602 | } |
603 | 603 | ||
604 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | 604 | static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, |
605 | struct flowi *fl, struct dst_entry **dstp, | 605 | struct flowi6 *fl6, struct dst_entry **dstp, |
606 | unsigned int flags) | 606 | unsigned int flags) |
607 | { | 607 | { |
608 | struct ipv6_pinfo *np = inet6_sk(sk); | 608 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -612,7 +612,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, | |||
612 | struct rt6_info *rt = (struct rt6_info *)*dstp; | 612 | struct rt6_info *rt = (struct rt6_info *)*dstp; |
613 | 613 | ||
614 | if (length > rt->dst.dev->mtu) { | 614 | if (length > rt->dst.dev->mtu) { |
615 | ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu); | 615 | ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); |
616 | return -EMSGSIZE; | 616 | return -EMSGSIZE; |
617 | } | 617 | } |
618 | if (flags&MSG_PROBE) | 618 | if (flags&MSG_PROBE) |
@@ -661,7 +661,7 @@ error: | |||
661 | return err; | 661 | return err; |
662 | } | 662 | } |
663 | 663 | ||
664 | static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | 664 | static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg) |
665 | { | 665 | { |
666 | struct iovec *iov; | 666 | struct iovec *iov; |
667 | u8 __user *type = NULL; | 667 | u8 __user *type = NULL; |
@@ -678,7 +678,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
678 | if (!iov) | 678 | if (!iov) |
679 | continue; | 679 | continue; |
680 | 680 | ||
681 | switch (fl->proto) { | 681 | switch (fl6->flowi6_proto) { |
682 | case IPPROTO_ICMPV6: | 682 | case IPPROTO_ICMPV6: |
683 | /* check if one-byte field is readable or not. */ | 683 | /* check if one-byte field is readable or not. */ |
684 | if (iov->iov_base && iov->iov_len < 1) | 684 | if (iov->iov_base && iov->iov_len < 1) |
@@ -693,8 +693,8 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
693 | code = iov->iov_base; | 693 | code = iov->iov_base; |
694 | 694 | ||
695 | if (type && code) { | 695 | if (type && code) { |
696 | if (get_user(fl->fl_icmp_type, type) || | 696 | if (get_user(fl6->fl6_icmp_type, type) || |
697 | get_user(fl->fl_icmp_code, code)) | 697 | get_user(fl6->fl6_icmp_code, code)) |
698 | return -EFAULT; | 698 | return -EFAULT; |
699 | probed = 1; | 699 | probed = 1; |
700 | } | 700 | } |
@@ -705,7 +705,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) | |||
705 | /* check if type field is readable or not. */ | 705 | /* check if type field is readable or not. */ |
706 | if (iov->iov_len > 2 - len) { | 706 | if (iov->iov_len > 2 - len) { |
707 | u8 __user *p = iov->iov_base; | 707 | u8 __user *p = iov->iov_base; |
708 | if (get_user(fl->fl_mh_type, &p[2 - len])) | 708 | if (get_user(fl6->fl6_mh_type, &p[2 - len])) |
709 | return -EFAULT; | 709 | return -EFAULT; |
710 | probed = 1; | 710 | probed = 1; |
711 | } else | 711 | } else |
@@ -734,7 +734,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
734 | struct ipv6_txoptions *opt = NULL; | 734 | struct ipv6_txoptions *opt = NULL; |
735 | struct ip6_flowlabel *flowlabel = NULL; | 735 | struct ip6_flowlabel *flowlabel = NULL; |
736 | struct dst_entry *dst = NULL; | 736 | struct dst_entry *dst = NULL; |
737 | struct flowi fl; | 737 | struct flowi6 fl6; |
738 | int addr_len = msg->msg_namelen; | 738 | int addr_len = msg->msg_namelen; |
739 | int hlimit = -1; | 739 | int hlimit = -1; |
740 | int tclass = -1; | 740 | int tclass = -1; |
@@ -755,9 +755,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
755 | /* | 755 | /* |
756 | * Get and verify the address. | 756 | * Get and verify the address. |
757 | */ | 757 | */ |
758 | memset(&fl, 0, sizeof(fl)); | 758 | memset(&fl6, 0, sizeof(fl6)); |
759 | 759 | ||
760 | fl.mark = sk->sk_mark; | 760 | fl6.flowi6_mark = sk->sk_mark; |
761 | 761 | ||
762 | if (sin6) { | 762 | if (sin6) { |
763 | if (addr_len < SIN6_LEN_RFC2133) | 763 | if (addr_len < SIN6_LEN_RFC2133) |
@@ -779,9 +779,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
779 | 779 | ||
780 | daddr = &sin6->sin6_addr; | 780 | daddr = &sin6->sin6_addr; |
781 | if (np->sndflow) { | 781 | if (np->sndflow) { |
782 | fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; | 782 | fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
783 | if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { | 783 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
784 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 784 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
785 | if (flowlabel == NULL) | 785 | if (flowlabel == NULL) |
786 | return -EINVAL; | 786 | return -EINVAL; |
787 | daddr = &flowlabel->dst; | 787 | daddr = &flowlabel->dst; |
@@ -799,32 +799,32 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
799 | if (addr_len >= sizeof(struct sockaddr_in6) && | 799 | if (addr_len >= sizeof(struct sockaddr_in6) && |
800 | sin6->sin6_scope_id && | 800 | sin6->sin6_scope_id && |
801 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) | 801 | ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) |
802 | fl.oif = sin6->sin6_scope_id; | 802 | fl6.flowi6_oif = sin6->sin6_scope_id; |
803 | } else { | 803 | } else { |
804 | if (sk->sk_state != TCP_ESTABLISHED) | 804 | if (sk->sk_state != TCP_ESTABLISHED) |
805 | return -EDESTADDRREQ; | 805 | return -EDESTADDRREQ; |
806 | 806 | ||
807 | proto = inet->inet_num; | 807 | proto = inet->inet_num; |
808 | daddr = &np->daddr; | 808 | daddr = &np->daddr; |
809 | fl.fl6_flowlabel = np->flow_label; | 809 | fl6.flowlabel = np->flow_label; |
810 | } | 810 | } |
811 | 811 | ||
812 | if (fl.oif == 0) | 812 | if (fl6.flowi6_oif == 0) |
813 | fl.oif = sk->sk_bound_dev_if; | 813 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
814 | 814 | ||
815 | if (msg->msg_controllen) { | 815 | if (msg->msg_controllen) { |
816 | opt = &opt_space; | 816 | opt = &opt_space; |
817 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 817 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
818 | opt->tot_len = sizeof(struct ipv6_txoptions); | 818 | opt->tot_len = sizeof(struct ipv6_txoptions); |
819 | 819 | ||
820 | err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, | 820 | err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit, |
821 | &tclass, &dontfrag); | 821 | &tclass, &dontfrag); |
822 | if (err < 0) { | 822 | if (err < 0) { |
823 | fl6_sock_release(flowlabel); | 823 | fl6_sock_release(flowlabel); |
824 | return err; | 824 | return err; |
825 | } | 825 | } |
826 | if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { | 826 | if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { |
827 | flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); | 827 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
828 | if (flowlabel == NULL) | 828 | if (flowlabel == NULL) |
829 | return -EINVAL; | 829 | return -EINVAL; |
830 | } | 830 | } |
@@ -837,40 +837,31 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
837 | opt = fl6_merge_options(&opt_space, flowlabel, opt); | 837 | opt = fl6_merge_options(&opt_space, flowlabel, opt); |
838 | opt = ipv6_fixup_options(&opt_space, opt); | 838 | opt = ipv6_fixup_options(&opt_space, opt); |
839 | 839 | ||
840 | fl.proto = proto; | 840 | fl6.flowi6_proto = proto; |
841 | err = rawv6_probe_proto_opt(&fl, msg); | 841 | err = rawv6_probe_proto_opt(&fl6, msg); |
842 | if (err) | 842 | if (err) |
843 | goto out; | 843 | goto out; |
844 | 844 | ||
845 | if (!ipv6_addr_any(daddr)) | 845 | if (!ipv6_addr_any(daddr)) |
846 | ipv6_addr_copy(&fl.fl6_dst, daddr); | 846 | ipv6_addr_copy(&fl6.daddr, daddr); |
847 | else | 847 | else |
848 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | 848 | fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ |
849 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 849 | if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) |
850 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 850 | ipv6_addr_copy(&fl6.saddr, &np->saddr); |
851 | 851 | ||
852 | final_p = fl6_update_dst(&fl, opt, &final); | 852 | final_p = fl6_update_dst(&fl6, opt, &final); |
853 | 853 | ||
854 | if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) | 854 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
855 | fl.oif = np->mcast_oif; | 855 | fl6.flowi6_oif = np->mcast_oif; |
856 | security_sk_classify_flow(sk, &fl); | 856 | security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
857 | 857 | ||
858 | err = ip6_dst_lookup(sk, &dst, &fl); | 858 | dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true); |
859 | if (err) | 859 | if (IS_ERR(dst)) { |
860 | err = PTR_ERR(dst); | ||
860 | goto out; | 861 | goto out; |
861 | if (final_p) | ||
862 | ipv6_addr_copy(&fl.fl6_dst, final_p); | ||
863 | |||
864 | err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); | ||
865 | if (err < 0) { | ||
866 | if (err == -EREMOTE) | ||
867 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
868 | if (err < 0) | ||
869 | goto out; | ||
870 | } | 862 | } |
871 | |||
872 | if (hlimit < 0) { | 863 | if (hlimit < 0) { |
873 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 864 | if (ipv6_addr_is_multicast(&fl6.daddr)) |
874 | hlimit = np->mcast_hops; | 865 | hlimit = np->mcast_hops; |
875 | else | 866 | else |
876 | hlimit = np->hop_limit; | 867 | hlimit = np->hop_limit; |
@@ -889,17 +880,17 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
889 | 880 | ||
890 | back_from_confirm: | 881 | back_from_confirm: |
891 | if (inet->hdrincl) | 882 | if (inet->hdrincl) |
892 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags); | 883 | err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags); |
893 | else { | 884 | else { |
894 | lock_sock(sk); | 885 | lock_sock(sk); |
895 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, | 886 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, |
896 | len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst, | 887 | len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst, |
897 | msg->msg_flags, dontfrag); | 888 | msg->msg_flags, dontfrag); |
898 | 889 | ||
899 | if (err) | 890 | if (err) |
900 | ip6_flush_pending_frames(sk); | 891 | ip6_flush_pending_frames(sk); |
901 | else if (!(msg->msg_flags & MSG_MORE)) | 892 | else if (!(msg->msg_flags & MSG_MORE)) |
902 | err = rawv6_push_pending_frames(sk, &fl, rp); | 893 | err = rawv6_push_pending_frames(sk, &fl6, rp); |
903 | release_sock(sk); | 894 | release_sock(sk); |
904 | } | 895 | } |
905 | done: | 896 | done: |
@@ -1157,6 +1148,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
1157 | } | 1148 | } |
1158 | } | 1149 | } |
1159 | 1150 | ||
1151 | #ifdef CONFIG_COMPAT | ||
1152 | static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) | ||
1153 | { | ||
1154 | switch (cmd) { | ||
1155 | case SIOCOUTQ: | ||
1156 | case SIOCINQ: | ||
1157 | return -ENOIOCTLCMD; | ||
1158 | default: | ||
1159 | #ifdef CONFIG_IPV6_MROUTE | ||
1160 | return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg)); | ||
1161 | #else | ||
1162 | return -ENOIOCTLCMD; | ||
1163 | #endif | ||
1164 | } | ||
1165 | } | ||
1166 | #endif | ||
1167 | |||
1160 | static void rawv6_close(struct sock *sk, long timeout) | 1168 | static void rawv6_close(struct sock *sk, long timeout) |
1161 | { | 1169 | { |
1162 | if (inet_sk(sk)->inet_num == IPPROTO_RAW) | 1170 | if (inet_sk(sk)->inet_num == IPPROTO_RAW) |
@@ -1215,6 +1223,7 @@ struct proto rawv6_prot = { | |||
1215 | #ifdef CONFIG_COMPAT | 1223 | #ifdef CONFIG_COMPAT |
1216 | .compat_setsockopt = compat_rawv6_setsockopt, | 1224 | .compat_setsockopt = compat_rawv6_setsockopt, |
1217 | .compat_getsockopt = compat_rawv6_getsockopt, | 1225 | .compat_getsockopt = compat_rawv6_getsockopt, |
1226 | .compat_ioctl = compat_rawv6_ioctl, | ||
1218 | #endif | 1227 | #endif |
1219 | }; | 1228 | }; |
1220 | 1229 | ||