KVM: PIT: provide an option to disable interrupt reinjection
[safe/jmp/linux-2.6] / net / sctp / ipv6.c
index 2622215..ceaa4aa 100644 (file)
@@ -89,6 +89,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:
@@ -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;
        }
@@ -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",
+       SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
                          __func__, skb, skb->len,
-                         NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
+                         &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, 0);
 }
 
 /* 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 " ",
-                         __func__, 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(&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");
@@ -296,7 +296,8 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
 /* 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 +309,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 " ",
-                         __func__, 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 +347,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",
-                      __func__, asoc, NIP6(daddr->v6.sin6_addr));
+                      "address for the dest:%pI6\n",
+                      __func__, asoc, &daddr->v6.sin6_addr);
        }
 
        rcu_read_unlock();
@@ -632,7 +634,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        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;
 
@@ -718,7 +720,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 +814,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 +830,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)
@@ -865,7 +878,11 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
                                return 0;
                        }
                        dev_put(dev);
+               } else if (type == IPV6_ADDR_MAPPED) {
+                       if (!opt->v4mapped)
+                               return 0;
                }
+
                af = opt->pf->af;
        }
        return af->available(addr, opt);
@@ -908,9 +925,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 = {
@@ -991,6 +1011,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 +1034,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 +1064,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 +1084,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)
 {