sctp: fix error path in sctp_proc_init
[pandora-kernel.git] / net / sctp / protocol.c
index ad0a406..98c6a88 100644 (file)
@@ -74,7 +74,7 @@ DEFINE_SPINLOCK(sctp_assocs_id_lock);
  * the Out-of-the-blue (OOTB) packets.  A control sock will be created
  * for this socket at the initialization time.
  */
-static struct socket *sctp_ctl_socket;
+static struct sock *sctp_ctl_sock;
 
 static struct sctp_pf *sctp_pf_inet6_specific;
 static struct sctp_pf *sctp_pf_inet_specific;
@@ -91,7 +91,7 @@ int sysctl_sctp_wmem[3];
 /* Return the address of the control sock. */
 struct sock *sctp_get_ctl_sock(void)
 {
-       return sctp_ctl_socket->sk;
+       return sctp_ctl_sock;
 }
 
 /* Set up the proc fs entry for the SCTP protocol. */
@@ -108,14 +108,27 @@ static __init int sctp_proc_init(void)
        }
 
        if (sctp_snmp_proc_init())
-               goto out_nomem;
+               goto out_snmp_proc_init;
        if (sctp_eps_proc_init())
-               goto out_nomem;
+               goto out_eps_proc_init;
        if (sctp_assocs_proc_init())
-               goto out_nomem;
+               goto out_assocs_proc_init;
+       if (sctp_remaddr_proc_init())
+               goto out_remaddr_proc_init;
 
        return 0;
 
+out_remaddr_proc_init:
+       sctp_assocs_proc_exit();
+out_assocs_proc_init:
+       sctp_eps_proc_exit();
+out_eps_proc_init:
+       sctp_snmp_proc_exit();
+out_snmp_proc_init:
+       if (proc_net_sctp) {
+               proc_net_sctp = NULL;
+               remove_proc_entry("sctp", init_net.proc_net);
+       }
 out_nomem:
        return -ENOMEM;
 }
@@ -129,6 +142,7 @@ static void sctp_proc_exit(void)
        sctp_snmp_proc_exit();
        sctp_eps_proc_exit();
        sctp_assocs_proc_exit();
+       sctp_remaddr_proc_exit();
 
        if (proc_net_sctp) {
                proc_net_sctp = NULL;
@@ -337,14 +351,14 @@ static int sctp_v4_cmp_addr(const union sctp_addr *addr1,
 static void sctp_v4_inaddr_any(union sctp_addr *addr, __be16 port)
 {
        addr->v4.sin_family = AF_INET;
-       addr->v4.sin_addr.s_addr = INADDR_ANY;
+       addr->v4.sin_addr.s_addr = htonl(INADDR_ANY);
        addr->v4.sin_port = port;
 }
 
 /* Is this a wildcard address? */
 static int sctp_v4_is_any(const union sctp_addr *addr)
 {
-       return INADDR_ANY == addr->v4.sin_addr.s_addr;
+       return htonl(INADDR_ANY) == addr->v4.sin_addr.s_addr;
 }
 
 /* This function checks if the address is a valid address to be used for
@@ -363,7 +377,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
                return 0;
 
        /* Is this a broadcast address? */
-       if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST)
+       if (skb && skb->rtable->rt_flags & RTCF_BROADCAST)
                return 0;
 
        return 1;
@@ -375,7 +389,7 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
        int ret = inet_addr_type(&init_net, addr->v4.sin_addr.s_addr);
 
 
-       if (addr->v4.sin_addr.s_addr != INADDR_ANY &&
+       if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
           ret != RTN_LOCAL &&
           !sp->inet.freebind &&
           !sysctl_ip_nonlocal_bind)
@@ -451,7 +465,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
                fl.fl4_src = saddr->v4.sin_addr.s_addr;
 
        SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
-                         __FUNCTION__, NIPQUAD(fl.fl4_dst),
+                         __func__, NIPQUAD(fl.fl4_dst),
                          NIPQUAD(fl.fl4_src));
 
        if (!ip_route_output_key(&init_net, &rt, &fl)) {
@@ -470,11 +484,11 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
                /* Walk through the bind address list and look for a bind
                 * address that matches the source address of the returned dst.
                 */
+               sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
                rcu_read_lock();
                list_for_each_entry_rcu(laddr, &bp->address_list, list) {
                        if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
                                continue;
-                       sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
                        if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
                                goto out_unlock;
                }
@@ -519,7 +533,8 @@ out:
 /* For v4, the source address is cached in the route entry(dst). So no need
  * to cache it separately and hence this is an empty routine.
  */
-static void sctp_v4_get_saddr(struct sctp_association *asoc,
+static void sctp_v4_get_saddr(struct sctp_sock *sk,
+                             struct sctp_association *asoc,
                              struct dst_entry *dst,
                              union sctp_addr *daddr,
                              union sctp_addr *saddr)
@@ -539,7 +554,7 @@ static void sctp_v4_get_saddr(struct sctp_association *asoc,
 /* What interface did this skb arrive on? */
 static int sctp_v4_skb_iif(const struct sk_buff *skb)
 {
-       return ((struct rtable *)skb->dst)->rt_iif;
+       return skb->rtable->rt_iif;
 }
 
 /* Was this packet marked by Explicit Congestion Notification? */
@@ -554,7 +569,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
 {
        struct inet_sock *inet = inet_sk(sk);
        struct inet_sock *newinet;
-       struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL,
+       struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL,
                        sk->sk_prot);
 
        if (!newsk)
@@ -616,6 +631,11 @@ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
        seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
 }
 
+static void sctp_v4_ecn_capable(struct sock *sk)
+{
+       INET_ECN_xmit(sk);
+}
+
 /* Event handler for inet address addition/deletion events.
  * The sctp_local_addr_list needs to be protocted by a spin lock since
  * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -630,6 +650,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
        struct sctp_sockaddr_entry *temp;
        int found = 0;
 
+       if (dev_net(ifa->ifa_dev->dev) != &init_net)
+               return NOTIFY_DONE;
+
        switch (ev) {
        case NETDEV_UP:
                addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
@@ -647,7 +670,9 @@ static int sctp_inetaddr_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 (addr->a.v4.sin_addr.s_addr == ifa->ifa_local) {
+                       if (addr->a.sa.sa_family == AF_INET &&
+                                       addr->a.v4.sin_addr.s_addr ==
+                                       ifa->ifa_local) {
                                found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
@@ -677,16 +702,13 @@ static int sctp_ctl_sock_init(void)
        else
                family = PF_INET;
 
-       err = sock_create_kern(family, SOCK_SEQPACKET, IPPROTO_SCTP,
-                              &sctp_ctl_socket);
+       err = inet_ctl_sock_create(&sctp_ctl_sock, family,
+                                  SOCK_SEQPACKET, IPPROTO_SCTP, &init_net);
        if (err < 0) {
                printk(KERN_ERR
                       "SCTP: Failed to create the SCTP control socket.\n");
                return err;
        }
-       sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
-       inet_sk(sctp_ctl_socket->sk)->uc_ttl = -1;
-
        return 0;
 }
 
@@ -785,8 +807,8 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1,
        /* PF_INET only supports AF_INET addresses. */
        if (addr1->sa.sa_family != addr2->sa.sa_family)
                return 0;
-       if (INADDR_ANY == addr1->v4.sin_addr.s_addr ||
-           INADDR_ANY == addr2->v4.sin_addr.s_addr)
+       if (htonl(INADDR_ANY) == addr1->v4.sin_addr.s_addr ||
+           htonl(INADDR_ANY) == addr2->v4.sin_addr.s_addr)
                return 1;
        if (addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr)
                return 1;
@@ -826,9 +848,9 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
 {
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
                          "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
-                         __FUNCTION__, skb, skb->len,
-                         NIPQUAD(((struct rtable *)skb->dst)->rt_src),
-                         NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
+                         __func__, skb, skb->len,
+                         NIPQUAD(skb->rtable->rt_src),
+                         NIPQUAD(skb->rtable->rt_dst));
 
        SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
        return ip_queue_xmit(skb, ipfragok);
@@ -932,6 +954,7 @@ static struct sctp_af sctp_af_inet = {
        .skb_iif           = sctp_v4_skb_iif,
        .is_ce             = sctp_v4_is_ce,
        .seq_dump_addr     = sctp_v4_seq_dump_addr,
+       .ecn_capable       = sctp_v4_ecn_capable,
        .net_header_len    = sizeof(struct iphdr),
        .sockaddr_len      = sizeof(struct sockaddr_in),
 #ifdef CONFIG_COMPAT
@@ -972,24 +995,66 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
        return 1;
 }
 
-static int __init init_sctp_mibs(void)
+static inline int init_sctp_mibs(void)
 {
-       sctp_statistics[0] = alloc_percpu(struct sctp_mib);
-       if (!sctp_statistics[0])
-               return -ENOMEM;
-       sctp_statistics[1] = alloc_percpu(struct sctp_mib);
-       if (!sctp_statistics[1]) {
-               free_percpu(sctp_statistics[0]);
-               return -ENOMEM;
-       }
+       return snmp_mib_init((void**)sctp_statistics, sizeof(struct sctp_mib));
+}
+
+static inline void cleanup_sctp_mibs(void)
+{
+       snmp_mib_free((void**)sctp_statistics);
+}
+
+static void sctp_v4_pf_init(void)
+{
+       /* Initialize the SCTP specific PF functions. */
+       sctp_register_pf(&sctp_pf_inet, PF_INET);
+       sctp_register_af(&sctp_af_inet);
+}
+
+static void sctp_v4_pf_exit(void)
+{
+       list_del(&sctp_af_inet.list);
+}
+
+static int sctp_v4_protosw_init(void)
+{
+       int rc;
+
+       rc = proto_register(&sctp_prot, 1);
+       if (rc)
+               return rc;
+
+       /* Register SCTP(UDP and TCP style) with socket layer.  */
+       inet_register_protosw(&sctp_seqpacket_protosw);
+       inet_register_protosw(&sctp_stream_protosw);
+
        return 0;
+}
+
+static void sctp_v4_protosw_exit(void)
+{
+       inet_unregister_protosw(&sctp_stream_protosw);
+       inet_unregister_protosw(&sctp_seqpacket_protosw);
+       proto_unregister(&sctp_prot);
+}
+
+static int sctp_v4_add_protocol(void)
+{
+       /* Register notifier for inet address additions/deletions. */
+       register_inetaddr_notifier(&sctp_inetaddr_notifier);
+
+       /* Register SCTP with inet layer.  */
+       if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
+               return -EAGAIN;
 
+       return 0;
 }
 
-static void cleanup_sctp_mibs(void)
+static void sctp_v4_del_protocol(void)
 {
-       free_percpu(sctp_statistics[0]);
-       free_percpu(sctp_statistics[1]);
+       inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
 }
 
 /* Initialize the universe into something sensible.  */
@@ -1035,8 +1100,6 @@ SCTP_STATIC __init int sctp_init(void)
        /* Initialize object count debugging.  */
        sctp_dbg_objcnt_init();
 
-       /* Initialize the SCTP specific PF functions. */
-       sctp_register_pf(&sctp_pf_inet, PF_INET);
        /*
         * 14. Suggested SCTP Protocol Parameter Values
         */
@@ -1194,19 +1257,22 @@ SCTP_STATIC __init int sctp_init(void)
        sctp_sysctl_register();
 
        INIT_LIST_HEAD(&sctp_address_families);
-       sctp_register_af(&sctp_af_inet);
+       sctp_v4_pf_init();
+       sctp_v6_pf_init();
 
-       status = proto_register(&sctp_prot, 1);
-       if (status)
-               goto err_proto_register;
+       /* Initialize the local address list. */
+       INIT_LIST_HEAD(&sctp_local_addr_list);
+       spin_lock_init(&sctp_local_addr_lock);
+       sctp_get_local_addr_list();
 
-       /* Register SCTP(UDP and TCP style) with socket layer.  */
-       inet_register_protosw(&sctp_seqpacket_protosw);
-       inet_register_protosw(&sctp_stream_protosw);
+       status = sctp_v4_protosw_init();
 
-       status = sctp_v6_init();
        if (status)
-               goto err_v6_init;
+               goto err_protosw_init;
+
+       status = sctp_v6_protosw_init();
+       if (status)
+               goto err_v6_protosw_init;
 
        /* Initialize the control inode/socket for handling OOTB packets.  */
        if ((status = sctp_ctl_sock_init())) {
@@ -1215,19 +1281,9 @@ SCTP_STATIC __init int sctp_init(void)
                goto err_ctl_sock_init;
        }
 
-       /* Initialize the local address list. */
-       INIT_LIST_HEAD(&sctp_local_addr_list);
-       spin_lock_init(&sctp_local_addr_lock);
-       sctp_get_local_addr_list();
-
-       /* Register notifier for inet address additions/deletions. */
-       register_inetaddr_notifier(&sctp_inetaddr_notifier);
-
-       /* Register SCTP with inet layer.  */
-       if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) {
-               status = -EAGAIN;
+       status = sctp_v4_add_protocol();
+       if (status)
                goto err_add_protocol;
-       }
 
        /* Register SCTP with inet6 layer.  */
        status = sctp_v6_add_protocol();
@@ -1238,18 +1294,18 @@ SCTP_STATIC __init int sctp_init(void)
 out:
        return status;
 err_v6_add_protocol:
-       inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+       sctp_v6_del_protocol();
 err_add_protocol:
-       sctp_free_local_addr_list();
-       sock_release(sctp_ctl_socket);
+       sctp_v4_del_protocol();
+       inet_ctl_sock_destroy(sctp_ctl_sock);
 err_ctl_sock_init:
-       sctp_v6_exit();
-err_v6_init:
-       inet_unregister_protosw(&sctp_stream_protosw);
-       inet_unregister_protosw(&sctp_seqpacket_protosw);
-       proto_unregister(&sctp_prot);
-err_proto_register:
+       sctp_v6_protosw_exit();
+err_v6_protosw_init:
+       sctp_v4_protosw_exit();
+err_protosw_init:
+       sctp_free_local_addr_list();
+       sctp_v4_pf_exit();
+       sctp_v6_pf_exit();
        sctp_sysctl_unregister();
        list_del(&sctp_af_inet.list);
        free_pages((unsigned long)sctp_port_hashtable,
@@ -1282,23 +1338,21 @@ SCTP_STATIC __exit void sctp_exit(void)
 
        /* Unregister with inet6/inet layers. */
        sctp_v6_del_protocol();
-       inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+       sctp_v4_del_protocol();
 
-       /* Unregister notifier for inet address additions/deletions. */
-       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+       /* Free the control endpoint.  */
+       inet_ctl_sock_destroy(sctp_ctl_sock);
+
+       /* Free protosw registrations */
+       sctp_v6_protosw_exit();
+       sctp_v4_protosw_exit();
 
        /* Free the local address list.  */
        sctp_free_local_addr_list();
 
-       /* Free the control endpoint.  */
-       sock_release(sctp_ctl_socket);
-
-       /* Cleanup v6 initializations. */
-       sctp_v6_exit();
-
        /* Unregister with socket layer. */
-       inet_unregister_protosw(&sctp_stream_protosw);
-       inet_unregister_protosw(&sctp_seqpacket_protosw);
+       sctp_v6_pf_exit();
+       sctp_v4_pf_exit();
 
        sctp_sysctl_unregister();
        list_del(&sctp_af_inet.list);
@@ -1317,8 +1371,6 @@ SCTP_STATIC __exit void sctp_exit(void)
 
        kmem_cache_destroy(sctp_chunk_cachep);
        kmem_cache_destroy(sctp_bucket_cachep);
-
-       proto_unregister(&sctp_prot);
 }
 
 module_init(sctp_init);