|
@@ -917,8 +917,22 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
|
|
|
}
|
|
|
|
|
|
helper = __nf_conntrack_helper_find_byname(helpname);
|
|
|
- if (helper == NULL)
|
|
|
+ if (helper == NULL) {
|
|
|
+#ifdef CONFIG_MODULES
|
|
|
+ spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+
|
|
|
+ if (request_module("nfct-helper-%s", helpname) < 0) {
|
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
|
+ helper = __nf_conntrack_helper_find_byname(helpname);
|
|
|
+ if (helper)
|
|
|
+ return -EAGAIN;
|
|
|
+#endif
|
|
|
return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
|
|
|
if (help) {
|
|
|
if (help->helper == helper)
|
|
@@ -1082,7 +1096,6 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
|
|
{
|
|
|
struct nf_conn *ct;
|
|
|
int err = -EINVAL;
|
|
|
- struct nf_conn_help *help;
|
|
|
struct nf_conntrack_helper *helper;
|
|
|
|
|
|
ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_KERNEL);
|
|
@@ -1097,16 +1110,55 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
|
|
ct->status |= IPS_CONFIRMED;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- helper = __nf_ct_helper_find(rtuple);
|
|
|
- if (helper) {
|
|
|
- help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
|
|
|
- if (help == NULL) {
|
|
|
+ if (cda[CTA_HELP]) {
|
|
|
+ char *helpname;
|
|
|
+
|
|
|
+ err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
|
|
|
+ if (err < 0) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ helper = __nf_conntrack_helper_find_byname(helpname);
|
|
|
+ if (helper == NULL) {
|
|
|
+ rcu_read_unlock();
|
|
|
+#ifdef CONFIG_MODULES
|
|
|
+ if (request_module("nfct-helper-%s", helpname) < 0) {
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ helper = __nf_conntrack_helper_find_byname(helpname);
|
|
|
+ if (helper) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ err = -EAGAIN;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+ rcu_read_unlock();
|
|
|
+#endif
|
|
|
+ err = -EOPNOTSUPP;
|
|
|
+ goto err;
|
|
|
+ } else {
|
|
|
+ struct nf_conn_help *help;
|
|
|
+
|
|
|
+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
|
|
|
+ if (help == NULL) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ err = -ENOMEM;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* not in hash table yet so not strictly necessary */
|
|
|
+ rcu_assign_pointer(help->helper, helper);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* try an implicit helper assignation */
|
|
|
+ err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
|
|
|
+ if (err < 0) {
|
|
|
rcu_read_unlock();
|
|
|
- err = -ENOMEM;
|
|
|
goto err;
|
|
|
}
|
|
|
- /* not in hash table yet so not strictly necessary */
|
|
|
- rcu_assign_pointer(help->helper, helper);
|
|
|
}
|
|
|
|
|
|
if (cda[CTA_STATUS]) {
|