Home | History | Annotate | Download | only in netfilter
      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 (at) suug.ch>
     10  * Copyright (c) 2007 Philip Craig <philipc (at) snapgear.com>
     11  * Copyright (c) 2007 Secure Computing Corporation
     12  * Copyright (c= 2008 Patrick McHardy <kaber (at) trash.net>
     13  * Copyright (c) 2012 Rich Fought <rich.fought (at) 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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    314 static int exp_request_update(struct nl_cache *cache, struct nl_sock *sk)
    315 {
    316 	return nfnl_exp_dump_request(sk);
    317 }
    318 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    610 static void __init exp_init(void)
    611 {
    612 	nl_cache_mngt_register(&nfnl_exp_ops);
    613 }
    614 
    615 static void __exit exp_exit(void)
    616 {
    617 	nl_cache_mngt_unregister(&nfnl_exp_ops);
    618 }
    619 
    620 /** @} */
    621