]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/sctp/protocol.c
[SCTP]: IPv4 vs IPv6 addresses mess in sctp_inet[6]addr_event.
[linux-2.6-omap-h63xx.git] / net / sctp / protocol.c
index 688546dccd828f0821736a301535049cc3d8ca04..c2dd65d9f38da7de0a8bd0170e766a3bb9936733 100644 (file)
@@ -337,14 +337,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
@@ -375,7 +375,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)
@@ -628,6 +628,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
        struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
        struct sctp_sockaddr_entry *addr = NULL;
        struct sctp_sockaddr_entry *temp;
+       int found = 0;
 
        switch (ev) {
        case NETDEV_UP:
@@ -646,14 +647,17 @@ 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);
                                break;
                        }
                }
                spin_unlock_bh(&sctp_local_addr_lock);
-               if (addr && !addr->valid)
+               if (found)
                        call_rcu(&addr->rcu, sctp_local_addr_free);
                break;
        }
@@ -783,8 +787,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;
@@ -990,6 +994,58 @@ static void cleanup_sctp_mibs(void)
        free_percpu(sctp_statistics[1]);
 }
 
+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 sctp_v4_del_protocol(void)
+{
+       inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+}
+
 /* Initialize the universe into something sensible.  */
 SCTP_STATIC __init int sctp_init(void)
 {
@@ -1033,8 +1089,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
         */
@@ -1192,19 +1246,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())) {
@@ -1213,19 +1270,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();
@@ -1236,18 +1283,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();
+       sctp_v4_del_protocol();
        sock_release(sctp_ctl_socket);
 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,
@@ -1280,23 +1327,21 @@ SCTP_STATIC __exit void sctp_exit(void)
 
        /* Unregister with inet6/inet layers. */
        sctp_v6_del_protocol();
-       inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
-
-       /* Unregister notifier for inet address additions/deletions. */
-       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
-
-       /* Free the local address list.  */
-       sctp_free_local_addr_list();
+       sctp_v4_del_protocol();
 
        /* Free the control endpoint.  */
        sock_release(sctp_ctl_socket);
 
-       /* Cleanup v6 initializations. */
-       sctp_v6_exit();
+       /* Free protosw registrations */
+       sctp_v6_protosw_exit();
+       sctp_v4_protosw_exit();
+
+       /* Free the local address list.  */
+       sctp_free_local_addr_list();
 
        /* 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);
@@ -1315,8 +1360,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);