Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 827bf122 authored by Sridhar Samudrala's avatar Sridhar Samudrala Committed by David S. Miller
Browse files

[SCTP]: Re-order SCTP initializations to avoid race with sctp_rcv()

parent ce5325c1
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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) */

+28 −21
Original line number Diff line number Diff line
@@ -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);
}
+47 −32
Original line number Diff line number Diff line
@@ -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),
@@ -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;
@@ -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,
@@ -1192,19 +1206,13 @@ err_ehash_alloc:
			     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;
}

@@ -1215,8 +1223,9 @@ 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();
@@ -1224,7 +1233,16 @@ SCTP_STATIC __exit void sctp_exit(void)
	/* 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);

@@ -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);
}