diff options
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index ae0f8b595106..8b1a54c1e400 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -1098,7 +1098,7 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = { | |||
1098 | }; | 1098 | }; |
1099 | 1099 | ||
1100 | static int | 1100 | static int |
1101 | call_ad(struct sk_buff *skb, struct ip_set *set, | 1101 | call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, |
1102 | struct nlattr *tb[], enum ipset_adt adt, | 1102 | struct nlattr *tb[], enum ipset_adt adt, |
1103 | u32 flags, bool use_lineno) | 1103 | u32 flags, bool use_lineno) |
1104 | { | 1104 | { |
@@ -1118,12 +1118,25 @@ call_ad(struct sk_buff *skb, struct ip_set *set, | |||
1118 | return 0; | 1118 | return 0; |
1119 | if (lineno && use_lineno) { | 1119 | if (lineno && use_lineno) { |
1120 | /* Error in restore/batch mode: send back lineno */ | 1120 | /* Error in restore/batch mode: send back lineno */ |
1121 | struct nlmsghdr *nlh = nlmsg_hdr(skb); | 1121 | struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); |
1122 | struct sk_buff *skb2; | ||
1123 | struct nlmsgerr *errmsg; | ||
1124 | size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); | ||
1122 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); | 1125 | int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); |
1123 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; | 1126 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; |
1124 | struct nlattr *cmdattr = (void *)nlh + min_len; | 1127 | struct nlattr *cmdattr; |
1125 | u32 *errline; | 1128 | u32 *errline; |
1126 | 1129 | ||
1130 | skb2 = nlmsg_new(payload, GFP_KERNEL); | ||
1131 | if (skb2 == NULL) | ||
1132 | return -ENOMEM; | ||
1133 | rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid, | ||
1134 | nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); | ||
1135 | errmsg = nlmsg_data(rep); | ||
1136 | errmsg->error = ret; | ||
1137 | memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); | ||
1138 | cmdattr = (void *)&errmsg->msg + min_len; | ||
1139 | |||
1127 | nla_parse(cda, IPSET_ATTR_CMD_MAX, | 1140 | nla_parse(cda, IPSET_ATTR_CMD_MAX, |
1128 | cmdattr, nlh->nlmsg_len - min_len, | 1141 | cmdattr, nlh->nlmsg_len - min_len, |
1129 | ip_set_adt_policy); | 1142 | ip_set_adt_policy); |
@@ -1131,6 +1144,10 @@ call_ad(struct sk_buff *skb, struct ip_set *set, | |||
1131 | errline = nla_data(cda[IPSET_ATTR_LINENO]); | 1144 | errline = nla_data(cda[IPSET_ATTR_LINENO]); |
1132 | 1145 | ||
1133 | *errline = lineno; | 1146 | *errline = lineno; |
1147 | |||
1148 | netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1149 | /* Signal netlink not to send its ACK/errmsg. */ | ||
1150 | return -EINTR; | ||
1134 | } | 1151 | } |
1135 | 1152 | ||
1136 | return ret; | 1153 | return ret; |
@@ -1169,7 +1186,8 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, | |||
1169 | attr[IPSET_ATTR_DATA], | 1186 | attr[IPSET_ATTR_DATA], |
1170 | set->type->adt_policy)) | 1187 | set->type->adt_policy)) |
1171 | return -IPSET_ERR_PROTOCOL; | 1188 | return -IPSET_ERR_PROTOCOL; |
1172 | ret = call_ad(skb, set, tb, IPSET_ADD, flags, use_lineno); | 1189 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags, |
1190 | use_lineno); | ||
1173 | } else { | 1191 | } else { |
1174 | int nla_rem; | 1192 | int nla_rem; |
1175 | 1193 | ||
@@ -1180,7 +1198,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, | |||
1180 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, | 1198 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, |
1181 | set->type->adt_policy)) | 1199 | set->type->adt_policy)) |
1182 | return -IPSET_ERR_PROTOCOL; | 1200 | return -IPSET_ERR_PROTOCOL; |
1183 | ret = call_ad(skb, set, tb, IPSET_ADD, | 1201 | ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, |
1184 | flags, use_lineno); | 1202 | flags, use_lineno); |
1185 | if (ret < 0) | 1203 | if (ret < 0) |
1186 | return ret; | 1204 | return ret; |
@@ -1222,7 +1240,8 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, | |||
1222 | attr[IPSET_ATTR_DATA], | 1240 | attr[IPSET_ATTR_DATA], |
1223 | set->type->adt_policy)) | 1241 | set->type->adt_policy)) |
1224 | return -IPSET_ERR_PROTOCOL; | 1242 | return -IPSET_ERR_PROTOCOL; |
1225 | ret = call_ad(skb, set, tb, IPSET_DEL, flags, use_lineno); | 1243 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags, |
1244 | use_lineno); | ||
1226 | } else { | 1245 | } else { |
1227 | int nla_rem; | 1246 | int nla_rem; |
1228 | 1247 | ||
@@ -1233,7 +1252,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, | |||
1233 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, | 1252 | nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, |
1234 | set->type->adt_policy)) | 1253 | set->type->adt_policy)) |
1235 | return -IPSET_ERR_PROTOCOL; | 1254 | return -IPSET_ERR_PROTOCOL; |
1236 | ret = call_ad(skb, set, tb, IPSET_DEL, | 1255 | ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, |
1237 | flags, use_lineno); | 1256 | flags, use_lineno); |
1238 | if (ret < 0) | 1257 | if (ret < 0) |
1239 | return ret; | 1258 | return ret; |