• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/netfilter/exp.c	Conntrack Expectation
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11  * Copyright (c) 2007 Secure Computing Corporation
12  * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
13  * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
14  */
15 
16 /**
17  * @ingroup nfnl
18  * @defgroup exp Expectation
19  * @brief
20  * @{
21  */
22 
23 #include <byteswap.h>
24 #include <sys/types.h>
25 #include <linux/netfilter/nfnetlink_conntrack.h>
26 
27 #include <netlink-private/netlink.h>
28 #include <netlink/attr.h>
29 #include <netlink/netfilter/nfnl.h>
30 #include <netlink/netfilter/exp.h>
31 
32 static struct nl_cache_ops nfnl_exp_ops;
33 
34 static struct nla_policy exp_policy[CTA_EXPECT_MAX+1] = {
35 	[CTA_EXPECT_MASTER]	= { .type = NLA_NESTED },
36 	[CTA_EXPECT_TUPLE]	= { .type = NLA_NESTED },
37 	[CTA_EXPECT_MASK]	= { .type = NLA_NESTED },
38 	[CTA_EXPECT_TIMEOUT]	= { .type = NLA_U32 },
39 	[CTA_EXPECT_ID]		= { .type = NLA_U32 },
40 	[CTA_EXPECT_HELP_NAME]	= { .type = NLA_STRING },
41 	[CTA_EXPECT_ZONE]	= { .type = NLA_U16 },
42 	[CTA_EXPECT_FLAGS]	= { .type = NLA_U32 },    // Added in kernel 2.6.37
43 	[CTA_EXPECT_CLASS]	= { .type = NLA_U32 },    // Added in kernel 3.5
44 	[CTA_EXPECT_NAT]	= { .type = NLA_NESTED }, // Added in kernel 3.5
45 	[CTA_EXPECT_FN]		= { .type = NLA_STRING }, // Added in kernel 3.5
46 };
47 
48 static struct nla_policy exp_tuple_policy[CTA_TUPLE_MAX+1] = {
49 	[CTA_TUPLE_IP]		= { .type = NLA_NESTED },
50 	[CTA_TUPLE_PROTO]	= { .type = NLA_NESTED },
51 };
52 
53 static struct nla_policy exp_ip_policy[CTA_IP_MAX+1] = {
54 	[CTA_IP_V4_SRC]		= { .type = NLA_U32 },
55 	[CTA_IP_V4_DST]		= { .type = NLA_U32 },
56 	[CTA_IP_V6_SRC]		= { .minlen = 16 },
57 	[CTA_IP_V6_DST]		= { .minlen = 16 },
58 };
59 
60 static struct nla_policy exp_proto_policy[CTA_PROTO_MAX+1] = {
61 	[CTA_PROTO_NUM]		= { .type = NLA_U8 },
62 	[CTA_PROTO_SRC_PORT]	= { .type = NLA_U16 },
63 	[CTA_PROTO_DST_PORT]	= { .type = NLA_U16 },
64 	[CTA_PROTO_ICMP_ID]	= { .type = NLA_U16 },
65 	[CTA_PROTO_ICMP_TYPE]	= { .type = NLA_U8 },
66 	[CTA_PROTO_ICMP_CODE]	= { .type = NLA_U8 },
67 	[CTA_PROTO_ICMPV6_ID]	= { .type = NLA_U16 },
68 	[CTA_PROTO_ICMPV6_TYPE]	= { .type = NLA_U8 },
69 	[CTA_PROTO_ICMPV6_CODE]	= { .type = NLA_U8 },
70 };
71 
72 static struct nla_policy exp_nat_policy[CTA_EXPECT_NAT_MAX+1] = {
73 	[CTA_EXPECT_NAT_DIR]	= { .type = NLA_U32 },
74 	[CTA_EXPECT_NAT_TUPLE]	= { .type = NLA_NESTED },
75 };
76 
exp_parse_ip(struct nfnl_exp * exp,int tuple,struct nlattr * attr)77 static int exp_parse_ip(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
78 {
79 	struct nlattr *tb[CTA_IP_MAX+1];
80 	struct nl_addr *addr;
81 	int err;
82 
83 	err = nla_parse_nested(tb, CTA_IP_MAX, attr, exp_ip_policy);
84 	if (err < 0)
85 		goto errout;
86 
87 	if (tb[CTA_IP_V4_SRC]) {
88 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
89 		if (addr == NULL)
90 			goto errout_enomem;
91 		err = nfnl_exp_set_src(exp, tuple, addr);
92 		nl_addr_put(addr);
93 		if (err < 0)
94 			goto errout;
95 	}
96 	if (tb[CTA_IP_V4_DST]) {
97 		addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
98 		if (addr == NULL)
99 			goto errout_enomem;
100 		err = nfnl_exp_set_dst(exp, tuple, addr);
101 		nl_addr_put(addr);
102 		if (err < 0)
103 			goto errout;
104 	}
105 	if (tb[CTA_IP_V6_SRC]) {
106 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
107 		if (addr == NULL)
108 			goto errout_enomem;
109 		err = nfnl_exp_set_src(exp, tuple, addr);
110 		nl_addr_put(addr);
111 		if (err < 0)
112 			goto errout;
113 	}
114 	if (tb[CTA_IP_V6_DST]) {
115 		addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
116 		if (addr == NULL)
117 			goto errout_enomem;
118 		err = nfnl_exp_set_dst(exp, tuple, addr);
119 		nl_addr_put(addr);
120 		if (err < 0)
121 			goto errout;
122 	}
123 
124 	return 0;
125 
126 errout_enomem:
127 	err = -NLE_NOMEM;
128 errout:
129 	return err;
130 }
131 
exp_parse_proto(struct nfnl_exp * exp,int tuple,struct nlattr * attr)132 static int exp_parse_proto(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
133 {
134 	struct nlattr *tb[CTA_PROTO_MAX+1];
135 	int err;
136 	uint16_t srcport = 0, dstport = 0, icmpid = 0;
137 	uint8_t icmptype = 0, icmpcode = 0;
138 
139 	err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, exp_proto_policy);
140 	if (err < 0)
141 		return err;
142 
143 	if (tb[CTA_PROTO_NUM])
144 		nfnl_exp_set_l4protonum(exp, tuple, nla_get_u8(tb[CTA_PROTO_NUM]));
145 
146 	if (tb[CTA_PROTO_SRC_PORT])
147 		srcport = ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
148 	if (tb[CTA_PROTO_DST_PORT])
149 		dstport = ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]));
150 	if (tb[CTA_PROTO_SRC_PORT] || tb[CTA_PROTO_DST_PORT])
151 		nfnl_exp_set_ports(exp, tuple, srcport, dstport);
152 
153 	if (tb[CTA_PROTO_ICMP_ID])
154 		icmpid = ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
155 	if (tb[CTA_PROTO_ICMP_TYPE])
156 		icmptype = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
157 	if (tb[CTA_PROTO_ICMP_CODE])
158 		icmpcode = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
159 	if (tb[CTA_PROTO_ICMP_ID] || tb[CTA_PROTO_ICMP_TYPE] || tb[CTA_PROTO_ICMP_CODE])
160 		nfnl_exp_set_icmp(exp, tuple, icmpid, icmptype, icmpcode);
161 	return 0;
162 }
163 
exp_parse_tuple(struct nfnl_exp * exp,int tuple,struct nlattr * attr)164 static int exp_parse_tuple(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
165 {
166 	struct nlattr *tb[CTA_TUPLE_MAX+1];
167 	int err;
168 
169 	err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, exp_tuple_policy);
170 	if (err < 0)
171 		return err;
172 
173 	if (tb[CTA_TUPLE_IP]) {
174 		err = exp_parse_ip(exp, tuple, tb[CTA_TUPLE_IP]);
175 		if (err < 0)
176 			return err;
177 	}
178 
179 	if (tb[CTA_TUPLE_PROTO]) {
180 		err = exp_parse_proto(exp, tuple, tb[CTA_TUPLE_PROTO]);
181 		if (err < 0)
182 			return err;
183 	}
184 
185 	return 0;
186 }
187 
exp_parse_nat(struct nfnl_exp * exp,struct nlattr * attr)188 static int exp_parse_nat(struct nfnl_exp *exp, struct nlattr *attr)
189 {
190 	struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
191 	int err;
192 
193 	err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_policy);
194 	if (err < 0)
195 		return err;
196 
197 	if (tb[CTA_EXPECT_NAT_DIR])
198 		nfnl_exp_set_nat_dir(exp, nla_get_u32(tb[CTA_EXPECT_NAT_DIR]));
199 
200 	if (tb[CTA_EXPECT_NAT_TUPLE]) {
201 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_NAT, tb[CTA_EXPECT_NAT_TUPLE]);
202 		if (err < 0)
203 			return err;
204 	}
205 
206 	return 0;
207 }
208 
nfnlmsg_exp_group(struct nlmsghdr * nlh)209 int nfnlmsg_exp_group(struct nlmsghdr *nlh)
210 {
211 	switch (nfnlmsg_subtype(nlh)) {
212 	case IPCTNL_MSG_EXP_NEW:
213 		if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
214 			return NFNLGRP_CONNTRACK_EXP_NEW;
215 		else
216 			return NFNLGRP_CONNTRACK_EXP_UPDATE;
217 	case IPCTNL_MSG_EXP_DELETE:
218 		return NFNLGRP_CONNTRACK_EXP_DESTROY;
219 	default:
220 		return NFNLGRP_NONE;
221 	}
222 }
223 
nfnlmsg_exp_parse(struct nlmsghdr * nlh,struct nfnl_exp ** result)224 int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result)
225 {
226 	struct nfnl_exp *exp;
227 	struct nlattr *tb[CTA_MAX+1];
228 	int err;
229 
230 	exp = nfnl_exp_alloc();
231 	if (!exp)
232 		return -NLE_NOMEM;
233 
234 	exp->ce_msgtype = nlh->nlmsg_type;
235 
236 	err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX,
237 			  exp_policy);
238 	if (err < 0)
239 		goto errout;
240 
241 	nfnl_exp_set_family(exp, nfnlmsg_family(nlh));
242 
243 	if (tb[CTA_EXPECT_TUPLE]) {
244 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]);
245 		if (err < 0)
246 			goto errout;
247 	}
248 	if (tb[CTA_EXPECT_MASTER]) {
249 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]);
250 		if (err < 0)
251 			goto errout;
252 	}
253 	if (tb[CTA_EXPECT_MASK]) {
254 		err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]);
255 		if (err < 0)
256 			goto errout;
257 	}
258 
259 	if (tb[CTA_EXPECT_NAT]) {
260 		err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]);
261 		if (err < 0)
262 			goto errout;
263 	}
264 
265 	if (tb[CTA_EXPECT_CLASS])
266 		nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS])));
267 
268 	if (tb[CTA_EXPECT_FN])
269 		nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN]));
270 
271 	if (tb[CTA_EXPECT_TIMEOUT])
272 		nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT])));
273 
274 	if (tb[CTA_EXPECT_ID])
275 		nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID])));
276 
277 	if (tb[CTA_EXPECT_HELP_NAME])
278 		nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME]));
279 
280 	if (tb[CTA_EXPECT_ZONE])
281 		nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE])));
282 
283 	if (tb[CTA_EXPECT_FLAGS])
284 		nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS])));
285 
286 	*result = exp;
287 	return 0;
288 
289 errout:
290 	nfnl_exp_put(exp);
291 	return err;
292 }
293 
exp_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * nlh,struct nl_parser_param * pp)294 static int exp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
295 			 struct nlmsghdr *nlh, struct nl_parser_param *pp)
296 {
297 	struct nfnl_exp *exp;
298 	int err;
299 
300 	if ((err = nfnlmsg_exp_parse(nlh, &exp)) < 0)
301 		return err;
302 
303 	err = pp->pp_cb((struct nl_object *) exp, pp);
304 	nfnl_exp_put(exp);
305 	return err;
306 }
307 
nfnl_exp_dump_request(struct nl_sock * sk)308 int nfnl_exp_dump_request(struct nl_sock *sk)
309 {
310 	return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET,
311 				NLM_F_DUMP, AF_UNSPEC, 0);
312 }
313 
exp_request_update(struct nl_cache * cache,struct nl_sock * sk)314 static int exp_request_update(struct nl_cache *cache, struct nl_sock *sk)
315 {
316 	return nfnl_exp_dump_request(sk);
317 }
318 
exp_get_tuple_attr(int tuple)319 static int exp_get_tuple_attr(int tuple)
320 {
321 	int attr = 0;
322 
323 	switch (tuple) {
324 		case CTA_EXPECT_MASTER:
325 			attr = NFNL_EXP_TUPLE_MASTER;
326 			break;
327 		case CTA_EXPECT_MASK:
328 			attr = NFNL_EXP_TUPLE_MASK;
329 			break;
330 		case CTA_EXPECT_NAT:
331 			attr = NFNL_EXP_TUPLE_NAT;
332 			break;
333 		case CTA_EXPECT_TUPLE:
334 		default :
335 			attr = NFNL_EXP_TUPLE_EXPECT;
336 			break;
337 	}
338 
339 	return attr;
340 }
341 
nfnl_exp_build_tuple(struct nl_msg * msg,const struct nfnl_exp * exp,int cta)342 static int nfnl_exp_build_tuple(struct nl_msg *msg, const struct nfnl_exp *exp,
343 			       int cta)
344 {
345 	struct nlattr *tuple, *ip, *proto;
346 	struct nl_addr *addr;
347 	int family;
348 
349 	family = nfnl_exp_get_family(exp);
350 
351 	int type = exp_get_tuple_attr(cta);
352 
353     if (cta == CTA_EXPECT_NAT)
354         tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
355     else
356         tuple = nla_nest_start(msg, cta);
357 
358 	if (!tuple)
359 		goto nla_put_failure;
360 
361 	ip = nla_nest_start(msg, CTA_TUPLE_IP);
362 	if (!ip)
363 		goto nla_put_failure;
364 
365 	addr = nfnl_exp_get_src(exp, type);
366 	if (addr)
367 		NLA_PUT_ADDR(msg,
368 			     family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
369 			     addr);
370 
371 	addr = nfnl_exp_get_dst(exp, type);
372 	if (addr)
373 		NLA_PUT_ADDR(msg,
374 			     family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
375 			     addr);
376 
377 	nla_nest_end(msg, ip);
378 
379 	proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
380 	if (!proto)
381 		goto nla_put_failure;
382 
383 	if (nfnl_exp_test_l4protonum(exp, type))
384 		NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_exp_get_l4protonum(exp, type));
385 
386 	if (nfnl_exp_test_ports(exp, type)) {
387 		NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
388 			htons(nfnl_exp_get_src_port(exp, type)));
389 
390 		NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
391 			htons(nfnl_exp_get_dst_port(exp, type)));
392 	}
393 
394 	if (nfnl_exp_test_icmp(exp, type)) {
395 		NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
396 			htons(nfnl_exp_get_icmp_id(exp, type)));
397 
398 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
399 			    nfnl_exp_get_icmp_type(exp, type));
400 
401 		NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
402 			    nfnl_exp_get_icmp_code(exp, type));
403 	}
404 
405 	nla_nest_end(msg, proto);
406 
407 	nla_nest_end(msg, tuple);
408 	return 0;
409 
410 nla_put_failure:
411 	return -NLE_MSGSIZE;
412 }
413 
nfnl_exp_build_nat(struct nl_msg * msg,const struct nfnl_exp * exp)414 static int nfnl_exp_build_nat(struct nl_msg *msg, const struct nfnl_exp *exp)
415 {
416 	struct nlattr *nat;
417 	int err;
418 
419 	nat = nla_nest_start(msg, CTA_EXPECT_NAT);
420 
421 	if (nfnl_exp_test_nat_dir(exp)) {
422 		NLA_PUT_U32(msg, CTA_EXPECT_NAT_DIR,
423 				nfnl_exp_get_nat_dir(exp));
424 	}
425 
426 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_NAT)) < 0)
427 		goto nla_put_failure;
428 
429 	nla_nest_end(msg, nat);
430 	return 0;
431 
432 nla_put_failure:
433 	return -NLE_MSGSIZE;
434 }
435 
nfnl_exp_build_message(const struct nfnl_exp * exp,int cmd,int flags,struct nl_msg ** result)436 static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags,
437 				 struct nl_msg **result)
438 {
439 	struct nl_msg *msg;
440 	int err;
441 
442 	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK_EXP, cmd, flags,
443 				   nfnl_exp_get_family(exp), 0);
444 	if (msg == NULL)
445 		return -NLE_NOMEM;
446 
447 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_TUPLE)) < 0)
448 		goto err_out;
449 
450 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASTER)) < 0)
451 		goto err_out;
452 
453 	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASK)) < 0)
454 		goto err_out;
455 
456 	if (nfnl_exp_test_src(exp, NFNL_EXP_TUPLE_NAT)) {
457 		if ((err = nfnl_exp_build_nat(msg, exp)) < 0)
458 			goto err_out;
459 	}
460 
461 	if (nfnl_exp_test_class(exp))
462 		NLA_PUT_U32(msg, CTA_EXPECT_CLASS, htonl(nfnl_exp_get_class(exp)));
463 
464 	if (nfnl_exp_test_fn(exp))
465 		NLA_PUT_STRING(msg, CTA_EXPECT_FN, nfnl_exp_get_fn(exp));
466 
467 	if (nfnl_exp_test_id(exp))
468 		NLA_PUT_U32(msg, CTA_EXPECT_ID, htonl(nfnl_exp_get_id(exp)));
469 
470 	if (nfnl_exp_test_timeout(exp))
471 		NLA_PUT_U32(msg, CTA_EXPECT_TIMEOUT, htonl(nfnl_exp_get_timeout(exp)));
472 
473 	if (nfnl_exp_test_helper_name(exp))
474 		NLA_PUT_STRING(msg, CTA_EXPECT_HELP_NAME, nfnl_exp_get_helper_name(exp));
475 
476 	if (nfnl_exp_test_zone(exp))
477 		NLA_PUT_U16(msg, CTA_EXPECT_ZONE, htons(nfnl_exp_get_zone(exp)));
478 
479 	if (nfnl_exp_test_flags(exp))
480 		NLA_PUT_U32(msg, CTA_EXPECT_FLAGS, htonl(nfnl_exp_get_flags(exp)));
481 
482 	*result = msg;
483 	return 0;
484 
485 nla_put_failure:
486 err_out:
487 	nlmsg_free(msg);
488 	return err;
489 }
490 
nfnl_exp_build_add_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)491 int nfnl_exp_build_add_request(const struct nfnl_exp *exp, int flags,
492 			      struct nl_msg **result)
493 {
494 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_NEW, flags, result);
495 }
496 
nfnl_exp_add(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)497 int nfnl_exp_add(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
498 {
499 	struct nl_msg *msg;
500 	int err;
501 
502 	if ((err = nfnl_exp_build_add_request(exp, flags, &msg)) < 0)
503 		return err;
504 
505 	err = nl_send_auto_complete(sk, msg);
506 	nlmsg_free(msg);
507 	if (err < 0)
508 		return err;
509 
510 	return wait_for_ack(sk);
511 }
512 
nfnl_exp_build_delete_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)513 int nfnl_exp_build_delete_request(const struct nfnl_exp *exp, int flags,
514 				 struct nl_msg **result)
515 {
516 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_DELETE, flags, result);
517 }
518 
nfnl_exp_del(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)519 int nfnl_exp_del(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
520 {
521 	struct nl_msg *msg;
522 	int err;
523 
524 	if ((err = nfnl_exp_build_delete_request(exp, flags, &msg)) < 0)
525 		return err;
526 
527 	err = nl_send_auto_complete(sk, msg);
528 	nlmsg_free(msg);
529 	if (err < 0)
530 		return err;
531 
532 	return wait_for_ack(sk);
533 }
534 
nfnl_exp_build_query_request(const struct nfnl_exp * exp,int flags,struct nl_msg ** result)535 int nfnl_exp_build_query_request(const struct nfnl_exp *exp, int flags,
536 				struct nl_msg **result)
537 {
538 	return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_GET, flags, result);
539 }
540 
nfnl_exp_query(struct nl_sock * sk,const struct nfnl_exp * exp,int flags)541 int nfnl_exp_query(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
542 {
543 	struct nl_msg *msg;
544 	int err;
545 
546 	if ((err = nfnl_exp_build_query_request(exp, flags, &msg)) < 0)
547 		return err;
548 
549 	err = nl_send_auto_complete(sk, msg);
550 	nlmsg_free(msg);
551 	if (err < 0)
552 		return err;
553 
554 	return wait_for_ack(sk);
555 }
556 
557 /**
558  * @name Cache Management
559  * @{
560  */
561 
562 /**
563  * Build a expectation cache holding all expectations currently in the kernel
564  * @arg sk		Netlink socket.
565  * @arg result		Pointer to store resulting cache.
566  *
567  * Allocates a new cache, initializes it properly and updates it to
568  * contain all expectations currently in the kernel.
569  *
570  * @return 0 on success or a negative error code.
571  */
nfnl_exp_alloc_cache(struct nl_sock * sk,struct nl_cache ** result)572 int nfnl_exp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
573 {
574 	return nl_cache_alloc_and_fill(&nfnl_exp_ops, sk, result);
575 }
576 
577 /** @} */
578 
579 /**
580  * @name Expectation Addition
581  * @{
582  */
583 
584 /** @} */
585 
586 static struct nl_af_group exp_groups[] = {
587 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_NEW },
588 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_UPDATE },
589 	{ AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_DESTROY },
590 	{ END_OF_GROUP_LIST },
591 };
592 
593 #define NFNLMSG_EXP_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK_EXP, (type))
594 static struct nl_cache_ops nfnl_exp_ops = {
595 	.co_name		    = "netfilter/exp",
596 	.co_hdrsize		    = NFNL_HDRLEN,
597 	.co_msgtypes		= {
598 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_NEW), NL_ACT_NEW, "new" },
599 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_GET), NL_ACT_GET, "get" },
600 		{ NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_DELETE), NL_ACT_DEL, "del" },
601 		END_OF_MSGTYPES_LIST,
602 	},
603 	.co_protocol		= NETLINK_NETFILTER,
604 	.co_groups		= exp_groups,
605 	.co_request_update	= exp_request_update,
606 	.co_msg_parser		= exp_msg_parser,
607 	.co_obj_ops		= &exp_obj_ops,
608 };
609 
exp_init(void)610 static void __init exp_init(void)
611 {
612 	nl_cache_mngt_register(&nfnl_exp_ops);
613 }
614 
exp_exit(void)615 static void __exit exp_exit(void)
616 {
617 	nl_cache_mngt_unregister(&nfnl_exp_ops);
618 }
619 
620 /** @} */
621