|
@@ -949,6 +949,31 @@ ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static inline int
|
|
|
+ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
|
|
|
+{
|
|
|
+ struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
|
|
|
+ struct ip_conntrack_protocol *proto;
|
|
|
+ u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr) < 0)
|
|
|
+ goto nfattr_failure;
|
|
|
+
|
|
|
+ proto = ip_conntrack_proto_find_get(npt);
|
|
|
+ if (!proto)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (proto->from_nfattr)
|
|
|
+ err = proto->from_nfattr(tb, ct);
|
|
|
+ ip_conntrack_proto_put(proto);
|
|
|
+
|
|
|
+ return err;
|
|
|
+
|
|
|
+nfattr_failure:
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
static int
|
|
|
ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
|
|
|
{
|
|
@@ -974,6 +999,12 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ if (cda[CTA_PROTOINFO-1]) {
|
|
|
+ err = ctnetlink_change_protoinfo(ct, cda);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
DEBUGP("all done\n");
|
|
|
return 0;
|
|
|
}
|
|
@@ -1003,6 +1034,12 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
|
|
|
if (err < 0)
|
|
|
goto err;
|
|
|
|
|
|
+ if (cda[CTA_PROTOINFO-1]) {
|
|
|
+ err = ctnetlink_change_protoinfo(ct, cda);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
ct->helper = ip_conntrack_helper_find_get(rtuple);
|
|
|
|
|
|
add_timer(&ct->timeout);
|