fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / sctp / ipv6.c
index c7e42d1..ef36be0 100644 (file)
@@ -66,8 +66,8 @@
 #include <linux/seq_file.h>
 
 #include <net/protocol.h>
-#include <net/tcp.h>
 #include <net/ndisc.h>
+#include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/transp_v6.h>
 #include <net/addrconf.h>
 
 #include <asm/uaccess.h>
 
-extern int sctp_inetaddr_event(struct notifier_block *, unsigned long, void *);
+/* Event handler for inet6 address addition/deletion events.  */
+static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
+                               void *ptr)
+{
+       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+       struct sctp_sockaddr_entry *addr;
+       struct list_head *pos, *temp;
+
+       switch (ev) {
+       case NETDEV_UP:
+               addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+               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));
+                       addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
+                       list_add_tail(&addr->list, &sctp_local_addr_list);
+               }
+               break;
+       case NETDEV_DOWN:
+               list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+                       addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+                       if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) {
+                               list_del(pos);
+                               kfree(addr);
+                               break;
+                       }
+               }
+
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
 static struct notifier_block sctp_inet6addr_notifier = {
-       .notifier_call = sctp_inetaddr_event,
+       .notifier_call = sctp_inet6addr_event,
 };
 
 /* ICMP error handler. */
 SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                            int type, int code, int offset, __u32 info)
+                            int type, int code, int offset, __be32 info)
 {
        struct inet6_dev *idev;
        struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
        struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
        struct sock *sk;
-       struct sctp_endpoint *ep;
        struct sctp_association *asoc;
        struct sctp_transport *transport;
        struct ipv6_pinfo *np;
@@ -105,7 +139,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        savesctp  = skb->h.raw;
        skb->nh.ipv6h = iph;
        skb->h.raw = (char *)sh;
-       sk = sctp_err_lookup(AF_INET6, skb, sh, &ep, &asoc, &transport);
+       sk = sctp_err_lookup(AF_INET6, skb, sh, &asoc, &transport);
        /* Put back, the original pointers. */
        skb->nh.raw = saveip;
        skb->h.raw = savesctp;
@@ -124,7 +158,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                goto out_unlock;
        case ICMPV6_PARAMPROB:
                if (ICMPV6_UNK_NEXTHDR == code) {
-                       sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
+                       sctp_icmp_proto_unreachable(sk, asoc, transport);
                        goto out_unlock;
                }
                break;
@@ -142,7 +176,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        }
 
 out_unlock:
-       sctp_err_finish(sk, ep, asoc);
+       sctp_err_finish(sk, asoc);
 out:
        if (likely(idev != NULL))
                in6_dev_put(idev);
@@ -172,8 +206,6 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
                fl.oif = transport->saddr.v6.sin6_scope_id;
        else
                fl.oif = sk->sk_bound_dev_if;
-       fl.fl_ip_sport = inet_sk(sk)->sport;
-       fl.fl_ip_dport = transport->ipaddr.v6.sin6_port;
 
        if (np->opt && np->opt->srcrt) {
                struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
@@ -181,8 +213,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
        }
 
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-                         "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-                         "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                         "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
                          __FUNCTION__, skb, skb->len,
                          NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
 
@@ -207,29 +238,28 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
                fl.oif = daddr->v6.sin6_scope_id;
        
 
-       SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+       SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
                          __FUNCTION__, NIP6(fl.fl6_dst));
 
        if (saddr) {
                ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
                SCTP_DEBUG_PRINTK(
-                       "SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
+                       "SRC=" NIP6_FMT " - ",
                        NIP6(fl.fl6_src));
        }
 
        dst = ip6_route_output(NULL, &fl);
-       if (dst) {
+       if (!dst->error) {
                struct rt6_info *rt;
                rt = (struct rt6_info *)dst;
                SCTP_DEBUG_PRINTK(
-                       "rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-                       "rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                       "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
                        NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
-       } else {
-               SCTP_DEBUG_PRINTK("NO ROUTE\n");
+               return dst;
        }
-
-       return dst;
+       SCTP_DEBUG_PRINTK("NO ROUTE\n");
+       dst_release(dst);
+       return NULL;
 }
 
 /* Returns the number of consecutive initial bits that match in the 2 ipv6
@@ -243,7 +273,7 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
        int i, j;
 
        for (i = 0; i < 4 ; i++) {
-               __u32 a1xora2;
+               __be32 a1xora2;
 
                a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
 
@@ -272,13 +302,12 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
        __u8 bmatchlen;
 
        SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
-                         "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+                         "daddr:" NIP6_FMT " ",
                          __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
        if (!asoc) {
                ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
-                                 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
                                  NIP6(saddr->v6.sin6_addr));
                return;
        }
@@ -294,7 +323,8 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
        sctp_read_lock(addr_lock);
        list_for_each(pos, &bp->address_list) {
                laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
-               if ((laddr->a.sa.sa_family == AF_INET6) &&
+               if ((laddr->use_as_src) &&
+                   (laddr->a.sa.sa_family == AF_INET6) &&
                    (scope <= sctp_scope(&laddr->a))) {
                        bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
                        if (!baddr || (matchlen < bmatchlen)) {
@@ -306,13 +336,11 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
 
        if (baddr) {
                memcpy(saddr, baddr, sizeof(union sctp_addr));
-               SCTP_DEBUG_PRINTK("saddr: "
-                                 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+               SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
                                  NIP6(saddr->v6.sin6_addr));
        } else {
                printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
-                      "address for the "
-                      "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                      "address for the dest:" NIP6_FMT "\n",
                       __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
        }
 
@@ -327,9 +355,9 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
        struct inet6_ifaddr *ifp;
        struct sctp_sockaddr_entry *addr;
 
-       read_lock(&addrconf_lock);
+       rcu_read_lock();
        if ((in6_dev = __in6_dev_get(dev)) == NULL) {
-               read_unlock(&addrconf_lock);
+               rcu_read_unlock();
                return;
        }
 
@@ -348,7 +376,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
        }
 
        read_unlock(&in6_dev->lock);
-       read_unlock(&addrconf_lock);
+       rcu_read_unlock();
 }
 
 /* Initialize a sockaddr_storage from in incoming skb. */
@@ -356,7 +384,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
                             int is_saddr)
 {
        void *from;
-       __u16 *port;
+       __be16 *port;
        struct sctphdr *sh;
 
        port = &addr->v6.sin6_port;
@@ -366,10 +394,10 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
 
        sh = (struct sctphdr *) skb->h.raw;
        if (is_saddr) {
-               *port  = ntohs(sh->source);
+               *port  = sh->source;
                from = &skb->nh.ipv6h->saddr;
        } else {
-               *port = ntohs(sh->dest);
+               *port = sh->dest;
                from = &skb->nh.ipv6h->daddr;
        }
        ipv6_addr_copy(&addr->v6.sin6_addr, from);
@@ -379,7 +407,7 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
 static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
        addr->v6.sin6_family = AF_INET6;
-       addr->v6.sin6_port = inet_sk(sk)->num;
+       addr->v6.sin6_port = 0;
        addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
 }
 
@@ -413,7 +441,7 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
 /* Initialize a sctp_addr from an address parameter. */
 static void sctp_v6_from_addr_param(union sctp_addr *addr,
                                    union sctp_addr_param *param,
-                                   __u16 port, int iif)
+                                   __be16 port, int iif)
 {
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = port;
@@ -431,7 +459,7 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
        int length = sizeof(sctp_ipv6addr_param_t);
 
        param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
-       param->v6.param_hdr.length = ntohs(length);
+       param->v6.param_hdr.length = htons(length);
        ipv6_addr_copy(&param->v6.addr, &addr->v6.sin6_addr);
 
        return length;
@@ -439,7 +467,7 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
 
 /* Initialize a sctp_addr from a dst_entry. */
 static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
-                             unsigned short port)
+                             __be16 port)
 {
        struct rt6_info *rt = (struct rt6_info *)dst;
        addr->sa.sa_family = AF_INET6;
@@ -486,7 +514,7 @@ static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
 }
 
 /* Initialize addr struct to INADDR_ANY. */
-static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port)
+static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port)
 {
        memset(addr, 0x00, sizeof(union sctp_addr));
        addr->v6.sin6_family = AF_INET6;
@@ -529,7 +557,9 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
  * Return 0 - If the address is a non-unicast or an illegal address.
  * Return 1 - If the address is a unicast.
  */
-static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp)
+static int sctp_v6_addr_valid(union sctp_addr *addr,
+                             struct sctp_sock *sp,
+                             const struct sk_buff *skb)
 {
        int ret = ipv6_addr_type(&addr->v6.sin6_addr);
 
@@ -543,7 +573,7 @@ static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_sock *sp)
                if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
                        return 0;
                sctp_v6_map_v4(addr);
-               return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp);
+               return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb);
        }
 
        /* Is this a non-unicast address */
@@ -642,10 +672,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        else
                newinet->pmtudisc = IP_PMTUDISC_WANT;
 
-#ifdef INET_REFCNT_DEBUG
-       atomic_inc(&inet6_sock_nr);
-       atomic_inc(&inet_sock_nr);
-#endif
+       sk_refcnt_debug_inc(newsk);
 
        if (newsk->sk_prot->init(newsk)) {
                sk_common_release(newsk);
@@ -679,8 +706,7 @@ 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, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
-                  NIP6(addr->v6.sin6_addr));
+       seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
 }
 
 /* Initialize a PF_INET6 socket msg_name. */
@@ -863,31 +889,35 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
  * Returns number of addresses supported.
  */
 static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
-                                     __u16 *types)
+                                     __be16 *types)
 {
        types[0] = SCTP_PARAM_IPV4_ADDRESS;
        types[1] = SCTP_PARAM_IPV6_ADDRESS;
        return 2;
 }
 
-static struct proto_ops inet6_seqpacket_ops = {
-       .family     = PF_INET6,
-       .owner      = THIS_MODULE,
-       .release    = inet6_release,
-       .bind       = inet6_bind,
-       .connect    = inet_dgram_connect,
-       .socketpair = sock_no_socketpair,
-       .accept     = inet_accept,
-       .getname    = inet6_getname,
-       .poll       = sctp_poll,
-       .ioctl      = inet6_ioctl,
-       .listen     = sctp_inet_listen,
-       .shutdown   = inet_shutdown,
-       .setsockopt = sock_common_setsockopt,
-       .getsockopt = sock_common_getsockopt,
-       .sendmsg    = inet_sendmsg,
-       .recvmsg    = sock_common_recvmsg,
-       .mmap       = sock_no_mmap,
+static const struct proto_ops inet6_seqpacket_ops = {
+       .family            = PF_INET6,
+       .owner             = THIS_MODULE,
+       .release           = inet6_release,
+       .bind              = inet6_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = inet_accept,
+       .getname           = inet6_getname,
+       .poll              = sctp_poll,
+       .ioctl             = inet6_ioctl,
+       .listen            = sctp_inet_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
 };
 
 static struct inet_protosw sctpv6_seqpacket_protosw = {
@@ -909,7 +939,7 @@ static struct inet_protosw sctpv6_stream_protosw = {
        .flags         = SCTP_PROTOSW_FLAG,
 };
 
-static int sctp6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+static int sctp6_rcv(struct sk_buff **pskb)
 {
        return sctp_rcv(*pskb) ? -1 : 0;
 }
@@ -921,31 +951,35 @@ static struct inet6_protocol sctpv6_protocol = {
 };
 
 static struct sctp_af sctp_ipv6_specific = {
-       .sctp_xmit       = sctp_v6_xmit,
-       .setsockopt      = ipv6_setsockopt,
-       .getsockopt      = ipv6_getsockopt,
-       .get_dst         = sctp_v6_get_dst,
-       .get_saddr       = sctp_v6_get_saddr,
-       .copy_addrlist   = sctp_v6_copy_addrlist,
-       .from_skb        = sctp_v6_from_skb,
-       .from_sk         = sctp_v6_from_sk,
-       .to_sk_saddr     = sctp_v6_to_sk_saddr,
-       .to_sk_daddr     = sctp_v6_to_sk_daddr,
-       .from_addr_param = sctp_v6_from_addr_param,
-       .to_addr_param   = sctp_v6_to_addr_param,
-       .dst_saddr       = sctp_v6_dst_saddr,
-       .cmp_addr        = sctp_v6_cmp_addr,
-       .scope           = sctp_v6_scope,
-       .addr_valid      = sctp_v6_addr_valid,
-       .inaddr_any      = sctp_v6_inaddr_any,
-       .is_any          = sctp_v6_is_any,
-       .available       = sctp_v6_available,
-       .skb_iif         = sctp_v6_skb_iif,
-       .is_ce           = sctp_v6_is_ce,
-       .seq_dump_addr   = sctp_v6_seq_dump_addr,
-       .net_header_len  = sizeof(struct ipv6hdr),
-       .sockaddr_len    = sizeof(struct sockaddr_in6),
-       .sa_family       = AF_INET6,
+       .sa_family         = AF_INET6,
+       .sctp_xmit         = sctp_v6_xmit,
+       .setsockopt        = ipv6_setsockopt,
+       .getsockopt        = ipv6_getsockopt,
+       .get_dst           = sctp_v6_get_dst,
+       .get_saddr         = sctp_v6_get_saddr,
+       .copy_addrlist     = sctp_v6_copy_addrlist,
+       .from_skb          = sctp_v6_from_skb,
+       .from_sk           = sctp_v6_from_sk,
+       .to_sk_saddr       = sctp_v6_to_sk_saddr,
+       .to_sk_daddr       = sctp_v6_to_sk_daddr,
+       .from_addr_param   = sctp_v6_from_addr_param,
+       .to_addr_param     = sctp_v6_to_addr_param,
+       .dst_saddr         = sctp_v6_dst_saddr,
+       .cmp_addr          = sctp_v6_cmp_addr,
+       .scope             = sctp_v6_scope,
+       .addr_valid        = sctp_v6_addr_valid,
+       .inaddr_any        = sctp_v6_inaddr_any,
+       .is_any            = sctp_v6_is_any,
+       .available         = sctp_v6_available,
+       .skb_iif           = sctp_v6_skb_iif,
+       .is_ce             = sctp_v6_is_ce,
+       .seq_dump_addr     = sctp_v6_seq_dump_addr,
+       .net_header_len    = sizeof(struct ipv6hdr),
+       .sockaddr_len      = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ipv6_setsockopt,
+       .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
 };
 
 static struct sctp_pf sctp_pf_inet6_specific = {