aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/ccid.c39
-rw-r--r--net/dccp/ccid.h1
-rw-r--r--net/dccp/feat.c5
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
197EXPORT_SYMBOL_GPL(ccid_unregister); 197EXPORT_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 */
205static 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
218int 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
199struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp) 228struct 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);
108extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, 108extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
109 char __user *, int __user *); 109 char __user *, int __user *);
110 110
111extern int ccid_request_modules(u8 const *ccid_array, u8 array_len);
111extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, 112extern 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;