mmc: s3c6410: enable ADMA feature in 6410 sdhci controller
[safe/jmp/linux-2.6] / net / sctp / ipv6.c
index 3e48788..7326891 100644 (file)
@@ -58,6 +58,7 @@
 #include <linux/netdevice.h>
 #include <linux/init.h>
 #include <linux/ipsec.h>
+#include <linux/slab.h>
 
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
@@ -89,6 +90,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
        struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
        struct sctp_sockaddr_entry *addr = NULL;
        struct sctp_sockaddr_entry *temp;
+       int found = 0;
 
        switch (ev) {
        case NETDEV_UP:
@@ -96,8 +98,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
-                       memcpy(&addr->a.v6.sin6_addr, &ifa->addr,
-                                sizeof(struct in6_addr));
+                       ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifa->addr);
                        addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
                        addr->valid = 1;
                        spin_lock_bh(&sctp_local_addr_lock);
@@ -109,15 +110,17 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                spin_lock_bh(&sctp_local_addr_lock);
                list_for_each_entry_safe(addr, temp,
                                        &sctp_local_addr_list, list) {
-                       if (ipv6_addr_equal(&addr->a.v6.sin6_addr,
-                                            &ifa->addr)) {
+                       if (addr->a.sa.sa_family == AF_INET6 &&
+                                       ipv6_addr_equal(&addr->a.v6.sin6_addr,
+                                               &ifa->addr)) {
+                               found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
                                break;
                        }
                }
                spin_unlock_bh(&sctp_local_addr_lock);
-               if (addr && !addr->valid)
+               if (found)
                        call_rcu(&addr->rcu, sctp_local_addr_free);
                break;
        }
@@ -131,7 +134,7 @@ static struct notifier_block sctp_inet6addr_notifier = {
 
 /* ICMP error handler. */
 SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                            int type, int code, int offset, __be32 info)
+                            u8 type, u8 code, int offset, __be32 info)
 {
        struct inet6_dev *idev;
        struct sock *sk;
@@ -153,7 +156,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        skb->network_header   = saveip;
        skb->transport_header = savesctp;
        if (!sk) {
-               ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
+               ICMP6_INC_STATS_BH(dev_net(skb->dev), idev, ICMP6_MIB_INERRORS);
                goto out;
        }
 
@@ -192,8 +195,7 @@ out:
 }
 
 /* Based on tcp_v6_xmit() in tcp_ipv6.c. */
-static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
-                       int ipfragok)
+static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
 {
        struct sock *sk = skb->sk;
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -221,14 +223,16 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
                ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
        }
 
-       SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-                         "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
-                         __FUNCTION__, skb, skb->len,
-                         NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
+       SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
+                         __func__, skb, skb->len,
+                         &fl.fl6_src, &fl.fl6_dst);
 
        SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
 
-       return ip6_xmit(sk, skb, &fl, np->opt, ipfragok);
+       if (!(transport->param_flags & SPP_PMTUD_ENABLE))
+               skb->local_df = 1;
+
+       return ip6_xmit(sk, skb, &fl, np->opt);
 }
 
 /* Returns the dst cache entry for the given source and destination ip
@@ -247,23 +251,19 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
                fl.oif = daddr->v6.sin6_scope_id;
 
 
-       SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
-                         __FUNCTION__, NIP6(fl.fl6_dst));
+       SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst);
 
        if (saddr) {
                ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK(
-                       "SRC=" NIP6_FMT " - ",
-                       NIP6(fl.fl6_src));
+               SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src);
        }
 
-       dst = ip6_route_output(NULL, &fl);
+       dst = ip6_route_output(&init_net, NULL, &fl);
        if (!dst->error) {
                struct rt6_info *rt;
                rt = (struct rt6_info *)dst;
-               SCTP_DEBUG_PRINTK(
-                       "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
-                       NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
+               SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
+                       &rt->rt6i_dst.addr, &rt->rt6i_src.addr);
                return dst;
        }
        SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -277,26 +277,14 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
                                         union sctp_addr *s2)
 {
-       struct in6_addr *a1 = &s1->v6.sin6_addr;
-       struct in6_addr *a2 = &s2->v6.sin6_addr;
-       int i, j;
-
-       for (i = 0; i < 4 ; i++) {
-               __be32 a1xora2;
-
-               a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
-
-               if ((j = fls(ntohl(a1xora2))))
-                       return (i * 32 + 32 - j);
-       }
-
-       return (i*32);
+       return ipv6_addr_diff(&s1->v6.sin6_addr, &s2->v6.sin6_addr);
 }
 
 /* Fills in the source address(saddr) based on the destination address(daddr)
  * and asoc's bind address list.
  */
-static void sctp_v6_get_saddr(struct sctp_association *asoc,
+static void sctp_v6_get_saddr(struct sctp_sock *sk,
+                             struct sctp_association *asoc,
                              struct dst_entry *dst,
                              union sctp_addr *daddr,
                              union sctp_addr *saddr)
@@ -308,15 +296,17 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
        __u8 matchlen = 0;
        __u8 bmatchlen;
 
-       SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
-                         "daddr:" NIP6_FMT " ",
-                         __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+       SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
+                         __func__, asoc, dst, &daddr->v6.sin6_addr);
 
        if (!asoc) {
-               ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
-                                  &daddr->v6.sin6_addr, &saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
-                                 NIP6(saddr->v6.sin6_addr));
+               ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
+                                  dst ? ip6_dst_idev(dst)->dev : NULL,
+                                  &daddr->v6.sin6_addr,
+                                  inet6_sk(&sk->inet.sk)->srcprefs,
+                                  &saddr->v6.sin6_addr);
+               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
+                                 &saddr->v6.sin6_addr);
                return;
        }
 
@@ -344,12 +334,11 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
 
        if (baddr) {
                memcpy(saddr, baddr, sizeof(union sctp_addr));
-               SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
-                                 NIP6(saddr->v6.sin6_addr));
+               SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
        } else {
                printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
-                      "address for the dest:" NIP6_FMT "\n",
-                      __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
+                      "address for the dest:%pI6\n",
+                      __func__, asoc, &daddr->v6.sin6_addr);
        }
 
        rcu_read_unlock();
@@ -370,17 +359,16 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
        }
 
        read_lock_bh(&in6_dev->lock);
-       for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
+       list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
                /* Add the address to the local list.  */
                addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
-                       addr->a.v6.sin6_addr = ifp->addr;
+                       ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifp->addr);
                        addr->a.v6.sin6_scope_id = dev->ifindex;
                        addr->valid = 1;
                        INIT_LIST_HEAD(&addr->list);
-                       INIT_RCU_HEAD(&addr->rcu);
                        list_add_tail(&addr->list, addrlist);
                }
        }
@@ -418,7 +406,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = 0;
-       addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
+       ipv6_addr_copy(&addr->v6.sin6_addr, &inet6_sk(sk)->rcv_saddr);
 }
 
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
@@ -431,7 +419,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->rcv_saddr.s6_addr32[3] =
                        addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
+               ipv6_addr_copy(&inet6_sk(sk)->rcv_saddr, &addr->v6.sin6_addr);
        }
 }
 
@@ -444,7 +432,7 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
                inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+               ipv6_addr_copy(&inet6_sk(sk)->daddr, &addr->v6.sin6_addr);
        }
 }
 
@@ -626,29 +614,17 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
 static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
                                             struct sctp_association *asoc)
 {
-       struct inet_sock *inet = inet_sk(sk);
        struct sock *newsk;
-       struct inet_sock *newinet;
        struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
        struct sctp6_sock *newsctp6sk;
 
-       newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot);
+       newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot);
        if (!newsk)
                goto out;
 
        sock_init_data(NULL, newsk);
 
-       newsk->sk_type = SOCK_STREAM;
-
-       newsk->sk_prot = sk->sk_prot;
-       newsk->sk_no_check = sk->sk_no_check;
-       newsk->sk_reuse = sk->sk_reuse;
-
-       newsk->sk_destruct = inet_sock_destruct;
-       newsk->sk_family = PF_INET6;
-       newsk->sk_protocol = IPPROTO_SCTP;
-       newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
-       newsk->sk_shutdown = sk->sk_shutdown;
+       sctp_copy_sock(newsk, sk, asoc);
        sock_reset_flag(sk, SOCK_ZAPPED);
 
        newsctp6sk = (struct sctp6_sock *)newsk;
@@ -656,7 +632,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
 
        sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped;
 
-       newinet = inet_sk(newsk);
        newnp = inet6_sk(newsk);
 
        memcpy(newnp, np, sizeof(struct ipv6_pinfo));
@@ -664,26 +639,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
         * and getpeername().
         */
-       newinet->sport = inet->sport;
-       newnp->saddr = np->saddr;
-       newnp->rcv_saddr = np->rcv_saddr;
-       newinet->dport = htons(asoc->peer.port);
        sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
 
-       /* Init the ipv4 part of the socket since we can have sockets
-        * using v6 API for ipv4.
-        */
-       newinet->uc_ttl = -1;
-       newinet->mc_loop = 1;
-       newinet->mc_ttl = 1;
-       newinet->mc_index = 0;
-       newinet->mc_list = NULL;
-
-       if (ipv4_config.no_pmtu_disc)
-               newinet->pmtudisc = IP_PMTUDISC_DONT;
-       else
-               newinet->pmtudisc = IP_PMTUDISC_WANT;
-
        sk_refcnt_debug_inc(newsk);
 
        if (newsk->sk_prot->init(newsk)) {
@@ -718,7 +675,12 @@ static int sctp_v6_is_ce(const struct sk_buff *skb)
 /* Dump the v6 addr to the seq file. */
 static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
 {
-       seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
+       seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr);
+}
+
+static void sctp_v6_ecn_capable(struct sock *sk)
+{
+       inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
 }
 
 /* Initialize a PF_INET6 socket msg_name. */
@@ -807,7 +769,7 @@ static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp)
                return 1;
        /* v4-mapped-v6 addresses */
        case AF_INET:
-               if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped)
+               if (!__ipv6_only_sock(sctp_opt2sk(sp)))
                        return 1;
        default:
                return 0;
@@ -823,14 +785,20 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
                               struct sctp_sock *opt)
 {
        struct sctp_af *af1, *af2;
+       struct sock *sk = sctp_opt2sk(opt);
 
        af1 = sctp_get_af_specific(addr1->sa.sa_family);
        af2 = sctp_get_af_specific(addr2->sa.sa_family);
 
        if (!af1 || !af2)
                return 0;
+
+       /* If the socket is IPv6 only, v4 addrs will not match */
+       if (__ipv6_only_sock(sk) && af1 != af2)
+               return 0;
+
        /* Today, wildcard AF_INET/AF_INET6. */
-       if (sctp_is_any(addr1) || sctp_is_any(addr2))
+       if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
                return 1;
 
        if (addr1->sa.sa_family != addr2->sa.sa_family)
@@ -856,16 +824,21 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
                if (type & IPV6_ADDR_LINKLOCAL) {
                        if (!addr->v6.sin6_scope_id)
                                return 0;
-                       dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id);
-                       if (!dev)
-                               return 0;
-                       if (!ipv6_chk_addr(&init_net, &addr->v6.sin6_addr,
+                       rcu_read_lock();
+                       dev = dev_get_by_index_rcu(&init_net,
+                                                  addr->v6.sin6_scope_id);
+                       if (!dev ||
+                           !ipv6_chk_addr(&init_net, &addr->v6.sin6_addr,
                                           dev, 0)) {
-                               dev_put(dev);
+                               rcu_read_unlock();
                                return 0;
                        }
-                       dev_put(dev);
+                       rcu_read_unlock();
+               } else if (type == IPV6_ADDR_MAPPED) {
+                       if (!opt->v4mapped)
+                               return 0;
                }
+
                af = opt->pf->af;
        }
        return af->available(addr, opt);
@@ -888,10 +861,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
                if (type & IPV6_ADDR_LINKLOCAL) {
                        if (!addr->v6.sin6_scope_id)
                                return 0;
-                       dev = dev_get_by_index(&init_net, addr->v6.sin6_scope_id);
+                       rcu_read_lock();
+                       dev = dev_get_by_index_rcu(&init_net,
+                                                  addr->v6.sin6_scope_id);
+                       rcu_read_unlock();
                        if (!dev)
                                return 0;
-                       dev_put(dev);
                }
                af = opt->pf->af;
        }
@@ -908,9 +883,12 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
 static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
                                      __be16 *types)
 {
-       types[0] = SCTP_PARAM_IPV4_ADDRESS;
-       types[1] = SCTP_PARAM_IPV6_ADDRESS;
-       return 2;
+       types[0] = SCTP_PARAM_IPV6_ADDRESS;
+       if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
+               types[1] = SCTP_PARAM_IPV4_ADDRESS;
+               return 2;
+       }
+       return 1;
 }
 
 static const struct proto_ops inet6_seqpacket_ops = {
@@ -942,7 +920,6 @@ static struct inet_protosw sctpv6_seqpacket_protosw = {
        .protocol      = IPPROTO_SCTP,
        .prot          = &sctpv6_prot,
        .ops           = &inet6_seqpacket_ops,
-       .capability    = -1,
        .no_check      = 0,
        .flags         = SCTP_PROTOSW_FLAG
 };
@@ -951,7 +928,6 @@ static struct inet_protosw sctpv6_stream_protosw = {
        .protocol      = IPPROTO_SCTP,
        .prot          = &sctpv6_prot,
        .ops           = &inet6_seqpacket_ops,
-       .capability    = -1,
        .no_check      = 0,
        .flags         = SCTP_PROTOSW_FLAG,
 };
@@ -961,7 +937,7 @@ static int sctp6_rcv(struct sk_buff *skb)
        return sctp_rcv(skb) ? -1 : 0;
 }
 
-static struct inet6_protocol sctpv6_protocol = {
+static const struct inet6_protocol sctpv6_protocol = {
        .handler      = sctp6_rcv,
        .err_handler  = sctp_v6_err,
        .flags        = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
@@ -991,6 +967,7 @@ static struct sctp_af sctp_af_inet6 = {
        .skb_iif           = sctp_v6_skb_iif,
        .is_ce             = sctp_v6_is_ce,
        .seq_dump_addr     = sctp_v6_seq_dump_addr,
+       .ecn_capable       = sctp_v6_ecn_capable,
        .net_header_len    = sizeof(struct ipv6hdr),
        .sockaddr_len      = sizeof(struct sockaddr_in6),
 #ifdef CONFIG_COMPAT
@@ -1013,15 +990,24 @@ static struct sctp_pf sctp_pf_inet6 = {
 };
 
 /* Initialize IPv6 support and register with socket layer.  */
-int sctp_v6_init(void)
+void sctp_v6_pf_init(void)
 {
-       int rc;
-
        /* Register the SCTP specific PF_INET6 functions. */
        sctp_register_pf(&sctp_pf_inet6, PF_INET6);
 
        /* Register the SCTP specific AF_INET6 functions. */
        sctp_register_af(&sctp_af_inet6);
+}
+
+void sctp_v6_pf_exit(void)
+{
+       list_del(&sctp_af_inet6.list);
+}
+
+/* Initialize IPv6 support and register with socket layer.  */
+int sctp_v6_protosw_init(void)
+{
+       int rc;
 
        rc = proto_register(&sctpv6_prot, 1);
        if (rc)
@@ -1034,6 +1020,14 @@ int sctp_v6_init(void)
        return 0;
 }
 
+void sctp_v6_protosw_exit(void)
+{
+       inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
+       inet6_unregister_protosw(&sctpv6_stream_protosw);
+       proto_unregister(&sctpv6_prot);
+}
+
+
 /* Register with inet6 layer. */
 int sctp_v6_add_protocol(void)
 {
@@ -1046,15 +1040,6 @@ int sctp_v6_add_protocol(void)
        return 0;
 }
 
-/* IPv6 specific exit support. */
-void sctp_v6_exit(void)
-{
-       inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
-       inet6_unregister_protosw(&sctpv6_stream_protosw);
-       proto_unregister(&sctpv6_prot);
-       list_del(&sctp_af_inet6.list);
-}
-
 /* Unregister with inet6 layer. */
 void sctp_v6_del_protocol(void)
 {