net: Put fl6_* macros to struct flowi6 and use them again.
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / ipv6 / raw.c
index 86c3952..4a1c3b4 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/skbuff.h>
+#include <linux/compat.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -123,18 +124,18 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
 }
 
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-static int (*mh_filter)(struct sock *sock, struct sk_buff *skb);
+typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb);
 
-int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
-                                          struct sk_buff *skb))
+static mh_filter_t __rcu *mh_filter __read_mostly;
+
+int rawv6_mh_filter_register(mh_filter_t filter)
 {
        rcu_assign_pointer(mh_filter, filter);
        return 0;
 }
 EXPORT_SYMBOL(rawv6_mh_filter_register);
 
-int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock,
-                                            struct sk_buff *skb))
+int rawv6_mh_filter_unregister(mh_filter_t filter)
 {
        rcu_assign_pointer(mh_filter, NULL);
        synchronize_rcu();
@@ -192,10 +193,10 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                         * policy is placed in rawv6_rcv() because it is
                         * required for each socket.
                         */
-                       int (*filter)(struct sock *sock, struct sk_buff *skb);
+                       mh_filter_t *filter;
 
                        filter = rcu_dereference(mh_filter);
-                       filtered = filter ? filter(sk, skb) : 0;
+                       filtered = filter ? (*filter)(sk, skb) : 0;
                        break;
                }
 #endif
@@ -523,7 +524,7 @@ csum_copy_err:
        goto out;
 }
 
-static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
+static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
                                     struct raw6_sock *rp)
 {
        struct sk_buff *skb;
@@ -585,11 +586,10 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,
        if (unlikely(csum))
                tmp_csum = csum_sub(tmp_csum, csum_unfold(csum));
 
-       csum = csum_ipv6_magic(&fl->fl6_src,
-                                  &fl->fl6_dst,
-                                  total_len, fl->proto, tmp_csum);
+       csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr,
+                              total_len, fl6->flowi6_proto, tmp_csum);
 
-       if (csum == 0 && fl->proto == IPPROTO_UDP)
+       if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP)
                csum = CSUM_MANGLED_0;
 
        if (skb_store_bits(skb, offset, &csum, 2))
@@ -602,7 +602,7 @@ out:
 }
 
 static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
-                       struct flowi *fl, struct dst_entry **dstp,
+                       struct flowi6 *fl6, struct dst_entry **dstp,
                        unsigned int flags)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -612,7 +612,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
        struct rt6_info *rt = (struct rt6_info *)*dstp;
 
        if (length > rt->dst.dev->mtu) {
-               ipv6_local_error(sk, EMSGSIZE, fl, rt->dst.dev->mtu);
+               ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu);
                return -EMSGSIZE;
        }
        if (flags&MSG_PROBE)
@@ -661,7 +661,7 @@ error:
        return err;
 }
 
-static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
+static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
 {
        struct iovec *iov;
        u8 __user *type = NULL;
@@ -678,7 +678,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                if (!iov)
                        continue;
 
-               switch (fl->proto) {
+               switch (fl6->flowi6_proto) {
                case IPPROTO_ICMPV6:
                        /* check if one-byte field is readable or not. */
                        if (iov->iov_base && iov->iov_len < 1)
@@ -693,8 +693,8 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                                code = iov->iov_base;
 
                        if (type && code) {
-                               if (get_user(fl->fl_icmp_type, type) ||
-                                   get_user(fl->fl_icmp_code, code))
+                               if (get_user(fl6->fl6_icmp_type, type) ||
+                                   get_user(fl6->fl6_icmp_code, code))
                                        return -EFAULT;
                                probed = 1;
                        }
@@ -705,7 +705,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
                        /* check if type field is readable or not. */
                        if (iov->iov_len > 2 - len) {
                                u8 __user *p = iov->iov_base;
-                               if (get_user(fl->fl_mh_type, &p[2 - len]))
+                               if (get_user(fl6->fl6_mh_type, &p[2 - len]))
                                        return -EFAULT;
                                probed = 1;
                        } else
@@ -734,7 +734,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        struct ipv6_txoptions *opt = NULL;
        struct ip6_flowlabel *flowlabel = NULL;
        struct dst_entry *dst = NULL;
-       struct flowi fl;
+       struct flowi6 fl6;
        int addr_len = msg->msg_namelen;
        int hlimit = -1;
        int tclass = -1;
@@ -755,9 +755,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        /*
         *      Get and verify the address.
         */
-       memset(&fl, 0, sizeof(fl));
+       memset(&fl6, 0, sizeof(fl6));
 
-       fl.mark = sk->sk_mark;
+       fl6.flowi6_mark = sk->sk_mark;
 
        if (sin6) {
                if (addr_len < SIN6_LEN_RFC2133)
@@ -779,9 +779,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 
                daddr = &sin6->sin6_addr;
                if (np->sndflow) {
-                       fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
-                       if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
-                               flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+                       fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+                       if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
+                               flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
                                if (flowlabel == NULL)
                                        return -EINVAL;
                                daddr = &flowlabel->dst;
@@ -799,32 +799,32 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                if (addr_len >= sizeof(struct sockaddr_in6) &&
                    sin6->sin6_scope_id &&
                    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
-                       fl.oif = sin6->sin6_scope_id;
+                       fl6.flowi6_oif = sin6->sin6_scope_id;
        } else {
                if (sk->sk_state != TCP_ESTABLISHED)
                        return -EDESTADDRREQ;
 
                proto = inet->inet_num;
                daddr = &np->daddr;
-               fl.fl6_flowlabel = np->flow_label;
+               fl6.flowlabel = np->flow_label;
        }
 
-       if (fl.oif == 0)
-               fl.oif = sk->sk_bound_dev_if;
+       if (fl6.flowi6_oif == 0)
+               fl6.flowi6_oif = sk->sk_bound_dev_if;
 
        if (msg->msg_controllen) {
                opt = &opt_space;
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
-               err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
+               err = datagram_send_ctl(sock_net(sk), msg, &fl6, opt, &hlimit,
                                        &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
                }
-               if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
-                       flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+               if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+                       flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
                        if (flowlabel == NULL)
                                return -EINVAL;
                }
@@ -837,40 +837,31 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                opt = fl6_merge_options(&opt_space, flowlabel, opt);
        opt = ipv6_fixup_options(&opt_space, opt);
 
-       fl.proto = proto;
-       err = rawv6_probe_proto_opt(&fl, msg);
+       fl6.flowi6_proto = proto;
+       err = rawv6_probe_proto_opt(&fl6, msg);
        if (err)
                goto out;
 
        if (!ipv6_addr_any(daddr))
-               ipv6_addr_copy(&fl.fl6_dst, daddr);
+               ipv6_addr_copy(&fl6.daddr, daddr);
        else
-               fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
-       if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
-               ipv6_addr_copy(&fl.fl6_src, &np->saddr);
+               fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
+       if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
+               ipv6_addr_copy(&fl6.saddr, &np->saddr);
 
-       final_p = fl6_update_dst(&fl, opt, &final);
+       final_p = fl6_update_dst(&fl6, opt, &final);
 
-       if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
-               fl.oif = np->mcast_oif;
-       security_sk_classify_flow(sk, &fl);
+       if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+               fl6.flowi6_oif = np->mcast_oif;
+       security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
 
-       err = ip6_dst_lookup(sk, &dst, &fl);
-       if (err)
+       dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
                goto out;
-       if (final_p)
-               ipv6_addr_copy(&fl.fl6_dst, final_p);
-
-       err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT);
-       if (err < 0) {
-               if (err == -EREMOTE)
-                       err = ip6_dst_blackhole(sk, &dst, &fl);
-               if (err < 0)
-                       goto out;
        }
-
        if (hlimit < 0) {
-               if (ipv6_addr_is_multicast(&fl.fl6_dst))
+               if (ipv6_addr_is_multicast(&fl6.daddr))
                        hlimit = np->mcast_hops;
                else
                        hlimit = np->hop_limit;
@@ -889,17 +880,17 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 
 back_from_confirm:
        if (inet->hdrincl)
-               err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, &dst, msg->msg_flags);
+               err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
        else {
                lock_sock(sk);
                err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
-                       len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
+                       len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst,
                        msg->msg_flags, dontfrag);
 
                if (err)
                        ip6_flush_pending_frames(sk);
                else if (!(msg->msg_flags & MSG_MORE))
-                       err = rawv6_push_pending_frames(sk, &fl, rp);
+                       err = rawv6_push_pending_frames(sk, &fl6, rp);
                release_sock(sk);
        }
 done:
@@ -1157,6 +1148,23 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
        }
 }
 
+#ifdef CONFIG_COMPAT
+static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case SIOCOUTQ:
+       case SIOCINQ:
+               return -ENOIOCTLCMD;
+       default:
+#ifdef CONFIG_IPV6_MROUTE
+               return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg));
+#else
+               return -ENOIOCTLCMD;
+#endif
+       }
+}
+#endif
+
 static void rawv6_close(struct sock *sk, long timeout)
 {
        if (inet_sk(sk)->inet_num == IPPROTO_RAW)
@@ -1215,6 +1223,7 @@ struct proto rawv6_prot = {
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_rawv6_setsockopt,
        .compat_getsockopt = compat_rawv6_getsockopt,
+       .compat_ioctl      = compat_rawv6_ioctl,
 #endif
 };