Skip to content

Commit

Permalink
[SCTP]: Re-order SCTP initializations to avoid race with sctp_rcv()
Browse files Browse the repository at this point in the history
Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Sridhar Samudrala authored and David S. Miller committed May 4, 2007
1 parent ce5325c commit 827bf12
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 53 deletions.
4 changes: 4 additions & 0 deletions include/net/sctp/sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -378,11 +378,15 @@ static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int

int sctp_v6_init(void);
void sctp_v6_exit(void);
int sctp_v6_add_protocol(void);
void sctp_v6_del_protocol(void);

#else /* #ifdef defined(CONFIG_IPV6) */

static inline int sctp_v6_init(void) { return 0; }
static inline void sctp_v6_exit(void) { return; }
static inline int sctp_v6_add_protocol(void) { return 0; }
static inline void sctp_v6_del_protocol(void) { return; }

#endif /* #if defined(CONFIG_IPV6) */

Expand Down
49 changes: 28 additions & 21 deletions net/sctp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -992,45 +992,52 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.af = &sctp_ipv6_specific,
};

/* Initialize IPv6 support and register with inet6 stack. */
/* Initialize IPv6 support and register with socket layer. */
int sctp_v6_init(void)
{
int rc = proto_register(&sctpv6_prot, 1);
int rc;

/* Register the SCTP specific PF_INET6 functions. */
sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);

/* Register the SCTP specific AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific);

rc = proto_register(&sctpv6_prot, 1);
if (rc)
goto out;
/* Register inet6 protocol. */
rc = -EAGAIN;
if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
goto out_unregister_sctp_proto;
return rc;

/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_seqpacket_protosw);
inet6_register_protosw(&sctpv6_stream_protosw);

/* Register the SCTP specific PF_INET6 functions. */
sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);

/* Register the SCTP specific AF_INET6 functions. */
sctp_register_af(&sctp_ipv6_specific);
return 0;
}

/* Register with inet6 layer. */
int sctp_v6_add_protocol(void)
{
/* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inet6addr_notifier);
rc = 0;
out:
return rc;
out_unregister_sctp_proto:
proto_unregister(&sctpv6_prot);
goto out;

if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
return -EAGAIN;

return 0;
}

/* IPv6 specific exit support. */
void sctp_v6_exit(void)
{
list_del(&sctp_ipv6_specific.list);
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
inet6_unregister_protosw(&sctpv6_stream_protosw);
unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
proto_unregister(&sctpv6_prot);
list_del(&sctp_ipv6_specific.list);
}

/* Unregister with inet6 layer. */
void sctp_v6_del_protocol(void)
{
inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
}
79 changes: 47 additions & 32 deletions net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,28 +975,14 @@ SCTP_STATIC __init int sctp_init(void)
if (!sctp_sanity_check())
goto out;

status = proto_register(&sctp_prot, 1);
if (status)
goto out;

/* Add SCTP to inet_protos hash table. */
status = -EAGAIN;
if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
goto err_add_protocol;

/* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw);

/* Allocate a cache pools. */
/* Allocate bind_bucket and chunk caches. */
status = -ENOBUFS;
sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
sizeof(struct sctp_bind_bucket),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);

if (!sctp_bucket_cachep)
goto err_bucket_cachep;
goto out;

sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
sizeof(struct sctp_chunk),
Expand Down Expand Up @@ -1153,6 +1139,14 @@ SCTP_STATIC __init int sctp_init(void)
INIT_LIST_HEAD(&sctp_address_families);
sctp_register_af(&sctp_ipv4_specific);

status = proto_register(&sctp_prot, 1);
if (status)
goto err_proto_register;

/* Register SCTP(UDP and TCP style) with socket layer. */
inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw);

status = sctp_v6_init();
if (status)
goto err_v6_init;
Expand All @@ -1166,19 +1160,39 @@ SCTP_STATIC __init int sctp_init(void)

/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);

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;
goto err_add_protocol;
}

/* Register SCTP with inet6 layer. */
status = sctp_v6_add_protocol();
if (status)
goto err_v6_add_protocol;

__unsafe(THIS_MODULE);
status = 0;
out:
return status;
err_v6_add_protocol:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
err_add_protocol:
sctp_free_local_addr_list();
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_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
free_pages((unsigned long)sctp_port_hashtable,
Expand All @@ -1192,19 +1206,13 @@ SCTP_STATIC __init int sctp_init(void)
sizeof(struct sctp_hashbucket)));
err_ahash_alloc:
sctp_dbg_objcnt_exit();
err_init_proc:
sctp_proc_exit();
err_init_proc:
cleanup_sctp_mibs();
err_init_mibs:
kmem_cache_destroy(sctp_chunk_cachep);
err_chunk_cachep:
kmem_cache_destroy(sctp_bucket_cachep);
err_bucket_cachep:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw);
err_add_protocol:
proto_unregister(&sctp_prot);
goto out;
}

Expand All @@ -1215,16 +1223,26 @@ SCTP_STATIC __exit void sctp_exit(void)
* up all the remaining associations and all that memory.
*/

/* Unregister notifier for inet address additions/deletions. */
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
/* Unregister with inet6/inet layers. */
sctp_v6_del_protocol();
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);

/* 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);

/* Unregister notifier for inet address additions/deletions. */
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);

sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);

Expand All @@ -1236,16 +1254,13 @@ SCTP_STATIC __exit void sctp_exit(void)
get_order(sctp_port_hashsize *
sizeof(struct sctp_bind_hashbucket)));

kmem_cache_destroy(sctp_chunk_cachep);
kmem_cache_destroy(sctp_bucket_cachep);

sctp_dbg_objcnt_exit();
sctp_proc_exit();
cleanup_sctp_mibs();

inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw);
kmem_cache_destroy(sctp_chunk_cachep);
kmem_cache_destroy(sctp_bucket_cachep);

proto_unregister(&sctp_prot);
}

Expand Down

0 comments on commit 827bf12

Please sign in to comment.