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