Commit 827bf12236fbafc02bc899aec1b37c342c8cf4e5
Committed by
David S. Miller
1 parent
ce5325c133
Exists in
master
and in
7 other branches
[SCTP]: Re-order SCTP initializations to avoid race with sctp_rcv()
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>
Showing 3 changed files with 79 additions and 53 deletions Side-by-side Diff
include/net/sctp/sctp.h
... | ... | @@ -378,11 +378,15 @@ |
378 | 378 | |
379 | 379 | int sctp_v6_init(void); |
380 | 380 | void sctp_v6_exit(void); |
381 | +int sctp_v6_add_protocol(void); | |
382 | +void sctp_v6_del_protocol(void); | |
381 | 383 | |
382 | 384 | #else /* #ifdef defined(CONFIG_IPV6) */ |
383 | 385 | |
384 | 386 | static inline int sctp_v6_init(void) { return 0; } |
385 | 387 | static inline void sctp_v6_exit(void) { return; } |
388 | +static inline int sctp_v6_add_protocol(void) { return 0; } | |
389 | +static inline void sctp_v6_del_protocol(void) { return; } | |
386 | 390 | |
387 | 391 | #endif /* #if defined(CONFIG_IPV6) */ |
388 | 392 |
net/sctp/ipv6.c
... | ... | @@ -992,46 +992,53 @@ |
992 | 992 | .af = &sctp_ipv6_specific, |
993 | 993 | }; |
994 | 994 | |
995 | -/* Initialize IPv6 support and register with inet6 stack. */ | |
995 | +/* Initialize IPv6 support and register with socket layer. */ | |
996 | 996 | int sctp_v6_init(void) |
997 | 997 | { |
998 | - int rc = proto_register(&sctpv6_prot, 1); | |
998 | + int rc; | |
999 | 999 | |
1000 | + /* Register the SCTP specific PF_INET6 functions. */ | |
1001 | + sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6); | |
1002 | + | |
1003 | + /* Register the SCTP specific AF_INET6 functions. */ | |
1004 | + sctp_register_af(&sctp_ipv6_specific); | |
1005 | + | |
1006 | + rc = proto_register(&sctpv6_prot, 1); | |
1000 | 1007 | if (rc) |
1001 | - goto out; | |
1002 | - /* Register inet6 protocol. */ | |
1003 | - rc = -EAGAIN; | |
1004 | - if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0) | |
1005 | - goto out_unregister_sctp_proto; | |
1008 | + return rc; | |
1006 | 1009 | |
1007 | 1010 | /* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */ |
1008 | 1011 | inet6_register_protosw(&sctpv6_seqpacket_protosw); |
1009 | 1012 | inet6_register_protosw(&sctpv6_stream_protosw); |
1010 | 1013 | |
1011 | - /* Register the SCTP specific PF_INET6 functions. */ | |
1012 | - sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6); | |
1014 | + return 0; | |
1015 | +} | |
1013 | 1016 | |
1014 | - /* Register the SCTP specific AF_INET6 functions. */ | |
1015 | - sctp_register_af(&sctp_ipv6_specific); | |
1016 | - | |
1017 | +/* Register with inet6 layer. */ | |
1018 | +int sctp_v6_add_protocol(void) | |
1019 | +{ | |
1017 | 1020 | /* Register notifier for inet6 address additions/deletions. */ |
1018 | 1021 | register_inet6addr_notifier(&sctp_inet6addr_notifier); |
1019 | - rc = 0; | |
1020 | -out: | |
1021 | - return rc; | |
1022 | -out_unregister_sctp_proto: | |
1023 | - proto_unregister(&sctpv6_prot); | |
1024 | - goto out; | |
1022 | + | |
1023 | + if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0) | |
1024 | + return -EAGAIN; | |
1025 | + | |
1026 | + return 0; | |
1025 | 1027 | } |
1026 | 1028 | |
1027 | 1029 | /* IPv6 specific exit support. */ |
1028 | 1030 | void sctp_v6_exit(void) |
1029 | 1031 | { |
1030 | - list_del(&sctp_ipv6_specific.list); | |
1031 | - inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP); | |
1032 | 1032 | inet6_unregister_protosw(&sctpv6_seqpacket_protosw); |
1033 | 1033 | inet6_unregister_protosw(&sctpv6_stream_protosw); |
1034 | - unregister_inet6addr_notifier(&sctp_inet6addr_notifier); | |
1035 | 1034 | proto_unregister(&sctpv6_prot); |
1035 | + list_del(&sctp_ipv6_specific.list); | |
1036 | +} | |
1037 | + | |
1038 | +/* Unregister with inet6 layer. */ | |
1039 | +void sctp_v6_del_protocol(void) | |
1040 | +{ | |
1041 | + inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP); | |
1042 | + unregister_inet6addr_notifier(&sctp_inet6addr_notifier); | |
1036 | 1043 | } |
net/sctp/protocol.c
... | ... | @@ -975,28 +975,14 @@ |
975 | 975 | if (!sctp_sanity_check()) |
976 | 976 | goto out; |
977 | 977 | |
978 | - status = proto_register(&sctp_prot, 1); | |
979 | - if (status) | |
980 | - goto out; | |
981 | - | |
982 | - /* Add SCTP to inet_protos hash table. */ | |
983 | - status = -EAGAIN; | |
984 | - if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) | |
985 | - goto err_add_protocol; | |
986 | - | |
987 | - /* Add SCTP(TCP and UDP style) to inetsw linked list. */ | |
988 | - inet_register_protosw(&sctp_seqpacket_protosw); | |
989 | - inet_register_protosw(&sctp_stream_protosw); | |
990 | - | |
991 | - /* Allocate a cache pools. */ | |
978 | + /* Allocate bind_bucket and chunk caches. */ | |
992 | 979 | status = -ENOBUFS; |
993 | 980 | sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket", |
994 | 981 | sizeof(struct sctp_bind_bucket), |
995 | 982 | 0, SLAB_HWCACHE_ALIGN, |
996 | 983 | NULL, NULL); |
997 | - | |
998 | 984 | if (!sctp_bucket_cachep) |
999 | - goto err_bucket_cachep; | |
985 | + goto out; | |
1000 | 986 | |
1001 | 987 | sctp_chunk_cachep = kmem_cache_create("sctp_chunk", |
1002 | 988 | sizeof(struct sctp_chunk), |
... | ... | @@ -1153,6 +1139,14 @@ |
1153 | 1139 | INIT_LIST_HEAD(&sctp_address_families); |
1154 | 1140 | sctp_register_af(&sctp_ipv4_specific); |
1155 | 1141 | |
1142 | + status = proto_register(&sctp_prot, 1); | |
1143 | + if (status) | |
1144 | + goto err_proto_register; | |
1145 | + | |
1146 | + /* Register SCTP(UDP and TCP style) with socket layer. */ | |
1147 | + inet_register_protosw(&sctp_seqpacket_protosw); | |
1148 | + inet_register_protosw(&sctp_stream_protosw); | |
1149 | + | |
1156 | 1150 | status = sctp_v6_init(); |
1157 | 1151 | if (status) |
1158 | 1152 | goto err_v6_init; |
1159 | 1153 | |
1160 | 1154 | |
1161 | 1155 | |
... | ... | @@ -1166,19 +1160,39 @@ |
1166 | 1160 | |
1167 | 1161 | /* Initialize the local address list. */ |
1168 | 1162 | INIT_LIST_HEAD(&sctp_local_addr_list); |
1169 | - | |
1170 | 1163 | sctp_get_local_addr_list(); |
1171 | 1164 | |
1172 | 1165 | /* Register notifier for inet address additions/deletions. */ |
1173 | 1166 | register_inetaddr_notifier(&sctp_inetaddr_notifier); |
1174 | 1167 | |
1168 | + /* Register SCTP with inet layer. */ | |
1169 | + if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) { | |
1170 | + status = -EAGAIN; | |
1171 | + goto err_add_protocol; | |
1172 | + } | |
1173 | + | |
1174 | + /* Register SCTP with inet6 layer. */ | |
1175 | + status = sctp_v6_add_protocol(); | |
1176 | + if (status) | |
1177 | + goto err_v6_add_protocol; | |
1178 | + | |
1175 | 1179 | __unsafe(THIS_MODULE); |
1176 | 1180 | status = 0; |
1177 | 1181 | out: |
1178 | 1182 | return status; |
1183 | +err_v6_add_protocol: | |
1184 | + inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); | |
1185 | + unregister_inetaddr_notifier(&sctp_inetaddr_notifier); | |
1186 | +err_add_protocol: | |
1187 | + sctp_free_local_addr_list(); | |
1188 | + sock_release(sctp_ctl_socket); | |
1179 | 1189 | err_ctl_sock_init: |
1180 | 1190 | sctp_v6_exit(); |
1181 | 1191 | err_v6_init: |
1192 | + inet_unregister_protosw(&sctp_stream_protosw); | |
1193 | + inet_unregister_protosw(&sctp_seqpacket_protosw); | |
1194 | + proto_unregister(&sctp_prot); | |
1195 | +err_proto_register: | |
1182 | 1196 | sctp_sysctl_unregister(); |
1183 | 1197 | list_del(&sctp_ipv4_specific.list); |
1184 | 1198 | free_pages((unsigned long)sctp_port_hashtable, |
1185 | 1199 | |
1186 | 1200 | |
... | ... | @@ -1192,19 +1206,13 @@ |
1192 | 1206 | sizeof(struct sctp_hashbucket))); |
1193 | 1207 | err_ahash_alloc: |
1194 | 1208 | sctp_dbg_objcnt_exit(); |
1195 | -err_init_proc: | |
1196 | 1209 | sctp_proc_exit(); |
1210 | +err_init_proc: | |
1197 | 1211 | cleanup_sctp_mibs(); |
1198 | 1212 | err_init_mibs: |
1199 | 1213 | kmem_cache_destroy(sctp_chunk_cachep); |
1200 | 1214 | err_chunk_cachep: |
1201 | 1215 | kmem_cache_destroy(sctp_bucket_cachep); |
1202 | -err_bucket_cachep: | |
1203 | - inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); | |
1204 | - inet_unregister_protosw(&sctp_seqpacket_protosw); | |
1205 | - inet_unregister_protosw(&sctp_stream_protosw); | |
1206 | -err_add_protocol: | |
1207 | - proto_unregister(&sctp_prot); | |
1208 | 1216 | goto out; |
1209 | 1217 | } |
1210 | 1218 | |
... | ... | @@ -1215,8 +1223,9 @@ |
1215 | 1223 | * up all the remaining associations and all that memory. |
1216 | 1224 | */ |
1217 | 1225 | |
1218 | - /* Unregister notifier for inet address additions/deletions. */ | |
1219 | - unregister_inetaddr_notifier(&sctp_inetaddr_notifier); | |
1226 | + /* Unregister with inet6/inet layers. */ | |
1227 | + sctp_v6_del_protocol(); | |
1228 | + inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); | |
1220 | 1229 | |
1221 | 1230 | /* Free the local address list. */ |
1222 | 1231 | sctp_free_local_addr_list(); |
1223 | 1232 | |
... | ... | @@ -1224,7 +1233,16 @@ |
1224 | 1233 | /* Free the control endpoint. */ |
1225 | 1234 | sock_release(sctp_ctl_socket); |
1226 | 1235 | |
1236 | + /* Cleanup v6 initializations. */ | |
1227 | 1237 | sctp_v6_exit(); |
1238 | + | |
1239 | + /* Unregister with socket layer. */ | |
1240 | + inet_unregister_protosw(&sctp_stream_protosw); | |
1241 | + inet_unregister_protosw(&sctp_seqpacket_protosw); | |
1242 | + | |
1243 | + /* Unregister notifier for inet address additions/deletions. */ | |
1244 | + unregister_inetaddr_notifier(&sctp_inetaddr_notifier); | |
1245 | + | |
1228 | 1246 | sctp_sysctl_unregister(); |
1229 | 1247 | list_del(&sctp_ipv4_specific.list); |
1230 | 1248 | |
1231 | 1249 | |
... | ... | @@ -1236,16 +1254,13 @@ |
1236 | 1254 | get_order(sctp_port_hashsize * |
1237 | 1255 | sizeof(struct sctp_bind_hashbucket))); |
1238 | 1256 | |
1239 | - kmem_cache_destroy(sctp_chunk_cachep); | |
1240 | - kmem_cache_destroy(sctp_bucket_cachep); | |
1241 | - | |
1242 | 1257 | sctp_dbg_objcnt_exit(); |
1243 | 1258 | sctp_proc_exit(); |
1244 | 1259 | cleanup_sctp_mibs(); |
1245 | 1260 | |
1246 | - inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); | |
1247 | - inet_unregister_protosw(&sctp_seqpacket_protosw); | |
1248 | - inet_unregister_protosw(&sctp_stream_protosw); | |
1261 | + kmem_cache_destroy(sctp_chunk_cachep); | |
1262 | + kmem_cache_destroy(sctp_bucket_cachep); | |
1263 | + | |
1249 | 1264 | proto_unregister(&sctp_prot); |
1250 | 1265 | } |
1251 | 1266 |