diff options
-rw-r--r-- | net/dccp/ccid.c | 39 | ||||
-rw-r--r-- | net/dccp/ccid.h | 1 | ||||
-rw-r--r-- | net/dccp/feat.c | 5 |
3 files changed, 35 insertions, 10 deletions
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index 330372a1a0b6..e3fb52b4f5c6 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c | |||
@@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops) | |||
196 | 196 | ||
197 | EXPORT_SYMBOL_GPL(ccid_unregister); | 197 | EXPORT_SYMBOL_GPL(ccid_unregister); |
198 | 198 | ||
199 | /** | ||
200 | * ccid_request_module - Pre-load CCID module for later use | ||
201 | * This should be called only from process context (e.g. during connection | ||
202 | * setup) and is necessary for later calls to ccid_new (typically in software | ||
203 | * interrupt), so that it has the modules available when they are needed. | ||
204 | */ | ||
205 | static int ccid_request_module(u8 id) | ||
206 | { | ||
207 | if (!in_atomic()) { | ||
208 | ccids_read_lock(); | ||
209 | if (ccids[id] == NULL) { | ||
210 | ccids_read_unlock(); | ||
211 | return request_module("net-dccp-ccid-%d", id); | ||
212 | } | ||
213 | ccids_read_unlock(); | ||
214 | } | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | int ccid_request_modules(u8 const *ccid_array, u8 array_len) | ||
219 | { | ||
220 | #ifdef CONFIG_KMOD | ||
221 | while (array_len--) | ||
222 | if (ccid_request_module(ccid_array[array_len])) | ||
223 | return -1; | ||
224 | #endif | ||
225 | return 0; | ||
226 | } | ||
227 | |||
199 | struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) | 228 | struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) |
200 | { | 229 | { |
201 | struct ccid_operations *ccid_ops; | 230 | struct ccid_operations *ccid_ops; |
202 | struct ccid *ccid = NULL; | 231 | struct ccid *ccid = NULL; |
203 | 232 | ||
204 | ccids_read_lock(); | 233 | ccids_read_lock(); |
205 | #ifdef CONFIG_KMOD | ||
206 | if (ccids[id] == NULL) { | ||
207 | /* We only try to load if in process context */ | ||
208 | ccids_read_unlock(); | ||
209 | if (gfp & GFP_ATOMIC) | ||
210 | goto out; | ||
211 | request_module("net-dccp-ccid-%d", id); | ||
212 | ccids_read_lock(); | ||
213 | } | ||
214 | #endif | ||
215 | ccid_ops = ccids[id]; | 234 | ccid_ops = ccids[id]; |
216 | if (ccid_ops == NULL) | 235 | if (ccid_ops == NULL) |
217 | goto out_unlock; | 236 | goto out_unlock; |
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 18f69423a708..20ba066b2775 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h | |||
@@ -108,6 +108,7 @@ extern int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len); | |||
108 | extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, | 108 | extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, |
109 | char __user *, int __user *); | 109 | char __user *, int __user *); |
110 | 110 | ||
111 | extern int ccid_request_modules(u8 const *ccid_array, u8 array_len); | ||
111 | extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, | 112 | extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, |
112 | gfp_t gfp); | 113 | gfp_t gfp); |
113 | 114 | ||
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index a687740e4420..9a4938092783 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -1158,6 +1158,11 @@ int dccp_feat_init(struct sock *sk) | |||
1158 | ccid_get_builtin_ccids(&rx.val, &rx.len)) | 1158 | ccid_get_builtin_ccids(&rx.val, &rx.len)) |
1159 | return -ENOBUFS; | 1159 | return -ENOBUFS; |
1160 | 1160 | ||
1161 | /* Pre-load all CCID modules that are going to be advertised */ | ||
1162 | rc = -EUNATCH; | ||
1163 | if (ccid_request_modules(tx.val, tx.len)) | ||
1164 | goto free_ccid_lists; | ||
1165 | |||
1161 | if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) || | 1166 | if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) || |
1162 | !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len)) | 1167 | !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len)) |
1163 | goto free_ccid_lists; | 1168 | goto free_ccid_lists; |