xref: /freebsd/sys/netpfil/pf/pf_nl.c (revision ee3960cba1068e12fb032a68c46d74841d9edab3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2023 Alexander V. Chernikov <melifaro@FreeBSD.org>
5  * Copyright (c) 2023 Rubicon Communications, LLC (Netgate)
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 #include <sys/cdefs.h>
30 #include "opt_inet.h"
31 #include "opt_inet6.h"
32 
33 #include <sys/param.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/priv.h>
37 #include <sys/socket.h>
38 #include <sys/ucred.h>
39 
40 #include <net/pfvar.h>
41 
42 #include <netlink/netlink.h>
43 #include <netlink/netlink_ctl.h>
44 #include <netlink/netlink_generic.h>
45 #include <netlink/netlink_message_writer.h>
46 
47 #include <netpfil/pf/pf_nl.h>
48 
49 #define	DEBUG_MOD_NAME	nl_pf
50 #define	DEBUG_MAX_LEVEL	LOG_DEBUG3
51 #include <netlink/netlink_debug.h>
52 _DECLARE_DEBUG(LOG_DEBUG);
53 
54 struct nl_parsed_state {
55 	uint8_t		version;
56 	uint32_t	id;
57 	uint32_t	creatorid;
58 	char		ifname[IFNAMSIZ];
59 	uint16_t	proto;
60 	sa_family_t	af;
61 	struct pf_addr	addr;
62 	struct pf_addr	mask;
63 };
64 
65 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
66 #define	_OUT(_field)	offsetof(struct nl_parsed_state, _field)
67 static const struct nlattr_parser nla_p_state[] = {
68 	{ .type = PF_ST_ID, .off = _OUT(id), .cb = nlattr_get_uint32 },
69 	{ .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = nlattr_get_uint32 },
70 	{ .type = PF_ST_IFNAME, .arg = (const void *)IFNAMSIZ, .off = _OUT(ifname), .cb = nlattr_get_chara },
71 	{ .type = PF_ST_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
72 	{ .type = PF_ST_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint16 },
73 	{ .type = PF_ST_FILTER_ADDR, .off = _OUT(addr), .cb = nlattr_get_in6_addr },
74 	{ .type = PF_ST_FILTER_MASK, .off = _OUT(mask), .cb = nlattr_get_in6_addr },
75 };
76 static const struct nlfield_parser nlf_p_generic[] = {
77 	{ .off_in = _IN(version), .off_out = _OUT(version), .cb = nlf_get_u8 },
78 };
79 #undef _IN
80 #undef _OUT
81 NL_DECLARE_PARSER(state_parser, struct genlmsghdr, nlf_p_generic, nla_p_state);
82 
83 static void
84 dump_addr(struct nl_writer *nw, int attr, const struct pf_addr *addr, int af)
85 {
86 	switch (af) {
87 	case AF_INET:
88 		nlattr_add(nw, attr, 4, &addr->v4);
89 		break;
90 	case AF_INET6:
91 		nlattr_add(nw, attr, 16, &addr->v6);
92 		break;
93 	};
94 }
95 
96 static bool
97 dump_state_peer(struct nl_writer *nw, int attr, const struct pf_state_peer *peer)
98 {
99 	int off = nlattr_add_nested(nw, attr);
100 	if (off == 0)
101 		return (false);
102 
103 	nlattr_add_u32(nw, PF_STP_SEQLO, peer->seqlo);
104 	nlattr_add_u32(nw, PF_STP_SEQHI, peer->seqhi);
105 	nlattr_add_u32(nw, PF_STP_SEQDIFF, peer->seqdiff);
106 	nlattr_add_u16(nw, PF_STP_MAX_WIN, peer->max_win);
107 	nlattr_add_u16(nw, PF_STP_MSS, peer->mss);
108 	nlattr_add_u8(nw, PF_STP_STATE, peer->state);
109 	nlattr_add_u8(nw, PF_STP_WSCALE, peer->wscale);
110 
111 	if (peer->scrub != NULL) {
112 		struct pf_state_scrub *sc = peer->scrub;
113 		uint16_t pfss_flags = sc->pfss_flags & PFSS_TIMESTAMP;
114 
115 		nlattr_add_u16(nw, PF_STP_PFSS_FLAGS, pfss_flags);
116 		nlattr_add_u32(nw, PF_STP_PFSS_TS_MOD, sc->pfss_ts_mod);
117 		nlattr_add_u8(nw, PF_STP_PFSS_TTL, sc->pfss_ttl);
118 		nlattr_add_u8(nw, PF_STP_SCRUB_FLAG, PFSYNC_SCRUB_FLAG_VALID);
119 	}
120 	nlattr_set_len(nw, off);
121 
122 	return (true);
123 }
124 
125 static bool
126 dump_state_key(struct nl_writer *nw, int attr, const struct pf_state_key *key)
127 {
128 	int off = nlattr_add_nested(nw, attr);
129 	if (off == 0)
130 		return (false);
131 
132 	dump_addr(nw, PF_STK_ADDR0, &key->addr[0], key->af);
133 	dump_addr(nw, PF_STK_ADDR1, &key->addr[1], key->af);
134 	nlattr_add_u16(nw, PF_STK_PORT0, key->port[0]);
135 	nlattr_add_u16(nw, PF_STK_PORT1, key->port[1]);
136 	nlattr_add_u8(nw, PF_STK_AF, key->af);
137 	nlattr_add_u16(nw, PF_STK_PROTO, key->proto);
138 
139 	nlattr_set_len(nw, off);
140 
141 	return (true);
142 }
143 
144 static int
145 dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
146     struct nl_pstate *npt)
147 {
148 	struct nl_writer *nw = npt->nw;
149 	int error = 0;
150 	int af;
151 	struct pf_state_key *key;
152 
153 	PF_STATE_LOCK_ASSERT(s);
154 
155 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
156 		goto enomem;
157 
158 	struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
159 	ghdr_new->cmd = PFNL_CMD_GETSTATES;
160 	ghdr_new->version = 0;
161 	ghdr_new->reserved = 0;
162 
163 	nlattr_add_u64(nw, PF_ST_VERSION, PF_STATE_VERSION);
164 
165 	key = s->key[PF_SK_WIRE];
166 	if (!dump_state_key(nw, PF_ST_KEY_WIRE, key))
167 		goto enomem;
168 	key = s->key[PF_SK_STACK];
169 	if (!dump_state_key(nw, PF_ST_KEY_STACK, key))
170 		goto enomem;
171 
172 	af = s->key[PF_SK_WIRE]->af;
173 	nlattr_add_u8(nw, PF_ST_PROTO, s->key[PF_SK_WIRE]->proto);
174 	nlattr_add_u8(nw, PF_ST_AF, af);
175 
176 	nlattr_add_string(nw, PF_ST_IFNAME, s->kif->pfik_name);
177 	nlattr_add_string(nw, PF_ST_ORIG_IFNAME, s->orig_kif->pfik_name);
178 	dump_addr(nw, PF_ST_RT_ADDR, &s->act.rt_addr, af);
179 	nlattr_add_u32(nw, PF_ST_CREATION, time_uptime - (s->creation / 1000));
180 	uint32_t expire = pf_state_expires(s);
181 	if (expire > time_uptime)
182 		expire = expire - time_uptime;
183 	nlattr_add_u32(nw, PF_ST_EXPIRE, expire);
184 	nlattr_add_u8(nw, PF_ST_DIRECTION, s->direction);
185 	nlattr_add_u8(nw, PF_ST_LOG, s->act.log);
186 	nlattr_add_u8(nw, PF_ST_TIMEOUT, s->timeout);
187 	nlattr_add_u16(nw, PF_ST_STATE_FLAGS, s->state_flags);
188 	uint8_t sync_flags = 0;
189 	if (s->sns[PF_SN_LIMIT] != NULL)
190 		sync_flags |= PFSYNC_FLAG_SRCNODE;
191 	if (s->sns[PF_SN_NAT] != NULL || s->sns[PF_SN_ROUTE])
192 		sync_flags |= PFSYNC_FLAG_NATSRCNODE;
193 	nlattr_add_u8(nw, PF_ST_SYNC_FLAGS, sync_flags);
194 	nlattr_add_u64(nw, PF_ST_ID, s->id);
195 	nlattr_add_u32(nw, PF_ST_CREATORID, htonl(s->creatorid));
196 
197 	nlattr_add_u32(nw, PF_ST_RULE, s->rule ? s->rule->nr : -1);
198 	nlattr_add_u32(nw, PF_ST_ANCHOR, s->anchor ? s->anchor->nr : -1);
199 	nlattr_add_u32(nw, PF_ST_NAT_RULE, s->nat_rule ? s->nat_rule->nr : -1);
200 
201 	nlattr_add_u64(nw, PF_ST_PACKETS0, s->packets[0]);
202 	nlattr_add_u64(nw, PF_ST_PACKETS1, s->packets[1]);
203 	nlattr_add_u64(nw, PF_ST_BYTES0, s->bytes[0]);
204 	nlattr_add_u64(nw, PF_ST_BYTES1, s->bytes[1]);
205 	nlattr_add_u32(nw, PF_ST_RTABLEID, s->act.rtableid);
206 	nlattr_add_u8(nw, PF_ST_MIN_TTL, s->act.min_ttl);
207 	nlattr_add_u16(nw, PF_ST_MAX_MSS, s->act.max_mss);
208 	nlattr_add_u16(nw, PF_ST_DNPIPE, s->act.dnpipe);
209 	nlattr_add_u16(nw, PF_ST_DNRPIPE, s->act.dnrpipe);
210 	nlattr_add_u8(nw, PF_ST_RT, s->act.rt);
211 	if (s->act.rt_kif != NULL)
212 		nlattr_add_string(nw, PF_ST_RT_IFNAME, s->act.rt_kif->pfik_name);
213 	uint8_t src_node_flags = 0;
214 	if (s->sns[PF_SN_LIMIT] != NULL) {
215 		src_node_flags |= PFSTATE_SRC_NODE_LIMIT;
216 		if (s->sns[PF_SN_LIMIT]->rule == &V_pf_default_rule)
217 			src_node_flags |= PFSTATE_SRC_NODE_LIMIT_GLOBAL;
218 	}
219 	if (s->sns[PF_SN_NAT] != NULL)
220 		src_node_flags |= PFSTATE_SRC_NODE_NAT;
221 	if (s->sns[PF_SN_ROUTE] != NULL)
222 		src_node_flags |= PFSTATE_SRC_NODE_ROUTE;
223 	nlattr_add_u8(nw, PF_ST_SRC_NODE_FLAGS, src_node_flags);
224 
225 	if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
226 		goto enomem;
227 	if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
228 		goto enomem;
229 
230 	if (nlmsg_end(nw))
231 		return (0);
232 
233 enomem:
234 	error = ENOMEM;
235 	nlmsg_abort(nw);
236 	return (error);
237 }
238 
239 static int
240 handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
241     struct nlmsghdr *hdr, struct nl_pstate *npt)
242 {
243 	int error = 0;
244 
245 	hdr->nlmsg_flags |= NLM_F_MULTI;
246 
247 	for (int i = 0; i <= V_pf_hashmask; i++) {
248 		struct pf_idhash *ih = &V_pf_idhash[i];
249 		struct pf_kstate *s;
250 
251 		if (LIST_EMPTY(&ih->states))
252 			continue;
253 
254 		PF_HASHROW_LOCK(ih);
255 		LIST_FOREACH(s, &ih->states, entry) {
256 			sa_family_t af = s->key[PF_SK_WIRE]->af;
257 
258 			if (s->timeout == PFTM_UNLINKED)
259 				continue;
260 
261 			/* Filter */
262 			if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
263 				continue;
264 			if (attrs->ifname[0] != 0 &&
265 			    strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
266 				continue;
267 			if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
268 				continue;
269 			if (attrs->af != 0 && af != attrs->af)
270 				continue;
271 			if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
272 			    &attrs->mask, &attrs->addr, af) &&
273 			    pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
274 			    &attrs->mask, &attrs->addr, af) &&
275 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
276 			    &attrs->mask, &attrs->addr, af) &&
277 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
278 			    &attrs->mask, &attrs->addr, af))
279 				continue;
280 
281 			error = dump_state(nlp, hdr, s, npt);
282 			if (error != 0)
283 				break;
284 		}
285 		PF_HASHROW_UNLOCK(ih);
286 	}
287 
288 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
289 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
290 		return (ENOMEM);
291 	}
292 
293 	return (error);
294 }
295 
296 static int
297 handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
298     struct nlmsghdr *hdr, struct nl_pstate *npt)
299 {
300 	struct pf_kstate *s;
301 	int ret;
302 
303 	s = pf_find_state_byid(attrs->id, attrs->creatorid);
304 	if (s == NULL)
305 		return (ENOENT);
306 	ret = dump_state(nlp, hdr, s, npt);
307 	PF_STATE_UNLOCK(s);
308 
309 	return (ret);
310 }
311 
312 static int
313 dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
314     struct nl_pstate *npt)
315 {
316 	struct nl_writer *nw = npt->nw;
317 
318 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
319 		goto enomem;
320 
321 	struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
322 	ghdr_new->cmd = PFNL_CMD_GETCREATORS;
323 	ghdr_new->version = 0;
324 	ghdr_new->reserved = 0;
325 
326 	nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
327 
328 	if (nlmsg_end(nw))
329 		return (0);
330 
331 enomem:
332 	nlmsg_abort(nw);
333 	return (ENOMEM);
334 }
335 
336 static int
337 pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
338 {
339 	int error;
340 
341 	struct nl_parsed_state attrs = {};
342 	error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
343 	if (error != 0)
344 		return (error);
345 
346 	if (attrs.id != 0)
347 		error = handle_getstate(npt->nlp, &attrs, hdr, npt);
348 	else
349 		error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
350 
351 	return (error);
352 }
353 
354 static int
355 pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
356 {
357 	uint32_t creators[16];
358 	int error = 0;
359 
360 	bzero(creators, sizeof(creators));
361 
362 	for (int i = 0; i < V_pf_hashmask; i++) {
363 		struct pf_idhash *ih = &V_pf_idhash[i];
364 		struct pf_kstate *s;
365 
366 		if (LIST_EMPTY(&ih->states))
367 			continue;
368 
369 		PF_HASHROW_LOCK(ih);
370 		LIST_FOREACH(s, &ih->states, entry) {
371 			int j;
372 			if (s->timeout == PFTM_UNLINKED)
373 				continue;
374 
375 			for (j = 0; j < nitems(creators); j++) {
376 				if (creators[j] == s->creatorid)
377 					break;
378 				if (creators[j] == 0) {
379 					creators[j] = s->creatorid;
380 					break;
381 				}
382 			}
383 			if (j == nitems(creators))
384 				printf("Warning: too many creators!\n");
385 		}
386 		PF_HASHROW_UNLOCK(ih);
387 	}
388 
389 	hdr->nlmsg_flags |= NLM_F_MULTI;
390 	for (int i = 0; i < nitems(creators); i++) {
391 		if (creators[i] == 0)
392 			break;
393 		error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
394 	}
395 
396 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
397 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
398 		return (ENOMEM);
399 	}
400 
401 	return (error);
402 }
403 
404 static int
405 pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
406 {
407 	return (pf_start());
408 }
409 
410 static int
411 pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
412 {
413 	return (pf_stop());
414 }
415 
416 #define _OUT(_field)	offsetof(struct pf_addr_wrap, _field)
417 static const struct nlattr_parser nla_p_addr_wrap[] = {
418 	{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
419 	{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
420 	{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
421 	{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
422 	{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
423 	{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
424 };
425 NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
426 #undef _OUT
427 
428 static bool
429 nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
430 {
431 	int off = nlattr_add_nested(nw, attrtype);
432 
433 	nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
434 	nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
435 	nlattr_add_u8(nw, PF_AT_TYPE, a->type);
436 	nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
437 
438 	if (a->type == PF_ADDR_DYNIFTL) {
439 		nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
440 		nlattr_add_u32(nw, PF_AT_DYNCNT, a->p.dyncnt);
441 	} else if (a->type == PF_ADDR_TABLE) {
442 		nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
443 		nlattr_add_u32(nw, PF_AT_TBLCNT, a->p.tblcnt);
444 	}
445 
446 	nlattr_set_len(nw, off);
447 
448 	return (true);
449 }
450 
451 #define _OUT(_field)	offsetof(struct pf_rule_addr, _field)
452 static const struct nlattr_parser nla_p_ruleaddr[] = {
453 	{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
454 	{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
455 	{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
456 	{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
457 	{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
458 };
459 NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
460 #undef _OUT
461 
462 static bool
463 nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
464 {
465 	struct pf_addr_wrap aw = {0};
466 	int off = nlattr_add_nested(nw, attrtype);
467 
468 	bcopy(&(r->addr), &aw, sizeof(struct pf_addr_wrap));
469 	pf_addr_copyout(&aw);
470 
471 	nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &aw);
472 	nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
473 	nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
474 	nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
475 	nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
476 
477 	nlattr_set_len(nw, off);
478 
479 	return (true);
480 }
481 
482 #define _OUT(_field)	offsetof(struct pf_mape_portset, _field)
483 static const struct nlattr_parser nla_p_mape_portset[] = {
484 	{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
485 	{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
486 	{. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
487 };
488 NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
489 #undef _OUT
490 
491 static bool
492 nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
493 {
494 	int off = nlattr_add_nested(nw, attrtype);
495 
496 	nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
497 	nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
498 	nlattr_add_u16(nw, PF_MET_PSID, m->psid);
499 
500 	nlattr_set_len(nw, off);
501 
502 	return (true);
503 }
504 
505 struct nl_parsed_labels
506 {
507 	char		labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
508 	uint32_t	i;
509 };
510 
511 static int
512 nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
513     const void *arg, void *target)
514 {
515 	struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
516 	int ret;
517 
518 	if (l->i >= PF_RULE_MAX_LABEL_COUNT)
519 		return (E2BIG);
520 
521 	ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
522 	    l->labels[l->i]);
523 	if (ret == 0)
524 		l->i++;
525 
526 	return (ret);
527 }
528 
529 #define _OUT(_field)	offsetof(struct nl_parsed_labels, _field)
530 static const struct nlattr_parser nla_p_labels[] = {
531 	{ .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
532 };
533 NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
534 #undef _OUT
535 
536 static int
537 nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
538 {
539 	struct nl_parsed_labels parsed_labels = { };
540 	int error;
541 
542 	/* Assumes target points to the beginning of the structure */
543 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
544 	if (error != 0)
545 		return (error);
546 
547 	memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
548 
549 	return (0);
550 }
551 
552 static bool
553 nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
554 {
555 	int off = nlattr_add_nested(nw, attrtype);
556 	int i = 0;
557 
558 	while (r->label[i][0] != 0
559 	    && i < PF_RULE_MAX_LABEL_COUNT) {
560 		nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
561 		i++;
562 	}
563 
564 	nlattr_set_len(nw, off);
565 
566 	return (true);
567 }
568 
569 #define _OUT(_field)	offsetof(struct pf_kpool, _field)
570 static const struct nlattr_parser nla_p_pool[] = {
571 	{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
572 	{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
573 	{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
574 	{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
575 	{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
576 	{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
577 	{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
578 };
579 NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
580 #undef _OUT
581 
582 static bool
583 nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
584 {
585 	int off = nlattr_add_nested(nw, attrtype);
586 
587 	nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
588 	nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
589 	nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
590 	nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
591 	nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
592 	nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
593 	nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
594 
595 	nlattr_set_len(nw, off);
596 
597 	return (true);
598 }
599 
600 #define _OUT(_field)	offsetof(struct pf_rule_uid, _field)
601 static const struct nlattr_parser nla_p_rule_uid[] = {
602 	{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
603 	{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
604 	{ .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
605 };
606 NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
607 #undef _OUT
608 
609 static bool
610 nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
611 {
612 	int off = nlattr_add_nested(nw, attrtype);
613 
614 	nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
615 	nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
616 	nlattr_add_u8(nw, PF_RUT_OP, u->op);
617 
618 	nlattr_set_len(nw, off);
619 
620 	return (true);
621 }
622 
623 struct nl_parsed_timeouts
624 {
625 	uint32_t	timeouts[PFTM_MAX];
626 	uint32_t	i;
627 };
628 
629 static int
630 nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
631     const void *arg, void *target)
632 {
633 	struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
634 	int ret;
635 
636 	if (t->i >= PFTM_MAX)
637 		return (E2BIG);
638 
639 	ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
640 	if (ret == 0)
641 		t->i++;
642 
643 	return (ret);
644 }
645 
646 #define _OUT(_field)	offsetof(struct nl_parsed_timeout, _field)
647 static const struct nlattr_parser nla_p_timeouts[] = {
648 	{ .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
649 };
650 NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
651 #undef _OUT
652 
653 static int
654 nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
655 {
656 	struct nl_parsed_timeouts parsed_timeouts = { };
657 	int error;
658 
659 	/* Assumes target points to the beginning of the structure */
660 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
661 	if (error != 0)
662 		return (error);
663 
664 	memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
665 
666 	return (0);
667 }
668 
669 static bool
670 nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
671 {
672 	int off = nlattr_add_nested(nw, attrtype);
673 
674 	for (int i = 0; i < PFTM_MAX; i++)
675 		nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
676 
677 	nlattr_set_len(nw, off);
678 
679 	return (true);
680 }
681 
682 #define _OUT(_field)	offsetof(struct pf_krule, _field)
683 static const struct nlattr_parser nla_p_rule[] = {
684 	{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
685 	{ .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
686 	{ .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
687 	{ .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
688 	{ .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
689 	{ .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
690 	{ .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
691 	{ .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
692 	{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
693 	{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
694 	{ .type = PF_RT_RPOOL_RDR, .off = _OUT(rdr), .arg = &pool_parser, .cb = nlattr_get_nested },
695 	{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
696 	{ .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
697 	{ .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
698 	{ .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
699 	{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
700 	{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
701 	{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
702 	{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
703 	{ .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
704 	{ .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
705 	{ .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
706 	{ .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
707 	{ .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
708 	{ .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
709 	{. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
710 	{ .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
711 	{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
712 	{ .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
713 	{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
714 	{ .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
715 	{ .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
716 	{ .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
717 	{ .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
718 	{ .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
719 	{ .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
720 	{ .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
721 	{ .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
722 	{ .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
723 	{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
724 	{ .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
725 	{ .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
726 	{ .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
727 	{ .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
728 	{ .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
729 	{ .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
730 	{ .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
731 	{ .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
732 	{ .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
733 	{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
734 	{ .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
735 	{ .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
736 	{ .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
737 	{ .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
738 	{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
739 	{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
740 	{ .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
741 	{ .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
742 	{ .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
743 	{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
744 	{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
745 	{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
746 	{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
747 	{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 },
748 	{ .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested },
749 	{ .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 },
750 	{ .type = PF_RT_RPOOL_RT, .off = _OUT(route), .arg = &pool_parser, .cb = nlattr_get_nested },
751 	{ .type = PF_RT_RCV_IFNOT, .off = _OUT(rcvifnot), .cb = nlattr_get_bool },
752 };
753 NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
754 #undef _OUT
755 struct nl_parsed_addrule {
756 	struct pf_krule	*rule;
757 	uint32_t	 ticket;
758 	uint32_t	 pool_ticket;
759 	char		*anchor;
760 	char		*anchor_call;
761 };
762 #define	_OUT(_field)	offsetof(struct nl_parsed_addrule, _field)
763 static const struct nlattr_parser nla_p_addrule[] = {
764 	{ .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
765 	{ .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
766 	{ .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
767 	{ .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
768 	{ .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
769 };
770 #undef _OUT
771 NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_addrule);
772 
773 static int
774 pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
775 {
776 	int error;
777 	struct nl_parsed_addrule attrs = {};
778 
779 	attrs.rule = pf_krule_alloc();
780 
781 	error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
782 	if (error != 0) {
783 		pf_free_rule(attrs.rule);
784 		return (error);
785 	}
786 
787 	error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
788 	    attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
789 	    hdr->nlmsg_pid);
790 
791 	return (error);
792 }
793 
794 #define	_OUT(_field)	offsetof(struct pfioc_rule, _field)
795 static const struct nlattr_parser nla_p_getrules[] = {
796 	{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
797 	{ .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
798 };
799 #undef _OUT
800 NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrules);
801 
802 static int
803 pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
804 {
805 	struct pfioc_rule attrs = {};
806 	int error;
807 	struct nl_writer *nw = npt->nw;
808 	struct genlmsghdr *ghdr_new;
809 
810 	error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
811 	if (error != 0)
812 		return (error);
813 
814 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
815 		return (ENOMEM);
816 
817 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
818 	ghdr_new->cmd = PFNL_CMD_GETRULES;
819 	ghdr_new->version = 0;
820 	ghdr_new->reserved = 0;
821 
822 	error = pf_ioctl_getrules(&attrs);
823 	if (error != 0)
824 		goto out;
825 
826 	nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
827 	nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
828 
829 	if (!nlmsg_end(nw)) {
830 		error = ENOMEM;
831 		goto out;
832 	}
833 
834 	return (0);
835 
836 out:
837 	nlmsg_abort(nw);
838 	return (error);
839 }
840 
841 struct nl_parsed_get_rule {
842 	char anchor[MAXPATHLEN];
843 	uint8_t action;
844 	uint32_t nr;
845 	uint32_t ticket;
846 	uint8_t clear;
847 };
848 #define	_OUT(_field)	offsetof(struct nl_parsed_get_rule, _field)
849 static const struct nlattr_parser nla_p_getrule[] = {
850 	{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
851 	{ .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
852 	{ .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
853 	{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
854 	{ .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
855 };
856 #undef _OUT
857 NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_empty, nla_p_getrule);
858 
859 static int
860 pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
861 {
862 	char				 anchor_call[MAXPATHLEN];
863 	struct nl_parsed_get_rule	 attrs = {};
864 	struct nl_writer		*nw = npt->nw;
865 	struct genlmsghdr		*ghdr_new;
866 	struct pf_kruleset		*ruleset;
867 	struct pf_krule			*rule;
868 	u_int64_t			 src_nodes_total = 0;
869 	int				 rs_num;
870 	int				 error;
871 
872 	error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
873 	if (error != 0)
874 		return (error);
875 
876 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
877 		return (ENOMEM);
878 
879 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
880 	ghdr_new->cmd = PFNL_CMD_GETRULE;
881 	ghdr_new->version = 0;
882 	ghdr_new->reserved = 0;
883 
884 	PF_RULES_WLOCK();
885 	ruleset = pf_find_kruleset(attrs.anchor);
886 	if (ruleset == NULL) {
887 		PF_RULES_WUNLOCK();
888 		error = ENOENT;
889 		goto out;
890 	}
891 
892 	rs_num = pf_get_ruleset_number(attrs.action);
893 	if (rs_num >= PF_RULESET_MAX) {
894 		PF_RULES_WUNLOCK();
895 		error = EINVAL;
896 		goto out;
897 	}
898 
899 	if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
900 		PF_RULES_WUNLOCK();
901 		error = EBUSY;
902 		goto out;
903 	}
904 
905 	rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
906 	while ((rule != NULL) && (rule->nr != attrs.nr))
907 		rule = TAILQ_NEXT(rule, entries);
908 	if (rule == NULL) {
909 		PF_RULES_WUNLOCK();
910 		error = EBUSY;
911 		goto out;
912 	}
913 
914 	nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
915 	nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
916 	nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
917 	nlattr_add_labels(nw, PF_RT_LABELS, rule);
918 	nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
919 	nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
920 	nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
921 	nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
922 	nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
923 	nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
924 	nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr);
925 	nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat);
926 	nlattr_add_pool(nw, PF_RT_RPOOL_RT, &rule->route);
927 	nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
928 	nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
929 	nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
930 	nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
931 	nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
932 	nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
933 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN, rule->max_src_conn);
934 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
935 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
936 
937 	nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
938 	nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
939 	nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
940 
941 	nlattr_add_u32(nw, PF_RT_NR, rule->nr);
942 	nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
943 	nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
944 	nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
945 
946 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
947 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
948 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
949 	nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
950 	nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
951 
952 	nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
953 	nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
954 
955 	nlattr_add_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
956 	nlattr_add_bool(nw, PF_RT_RCV_IFNOT, rule->rcvifnot);
957 
958 	nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
959 	nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
960 	nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
961 	nlattr_add_u8(nw, PF_RT_LOG, rule->log);
962 	nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
963 	nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
964 	nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
965 	nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
966 	nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
967 	nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
968 
969 	nlattr_add_u8(nw, PF_RT_AF, rule->af);
970 	nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
971 	nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
972 	nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
973 	nlattr_add_u8(nw, PF_RT_CODE, rule->code);
974 	nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
975 	nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
976 	nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
977 	nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
978 	nlattr_add_u8(nw, PF_RT_RT, rule->rt);
979 	nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
980 	nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
981 	nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
982 	nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
983 	nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
984 	nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
985 	nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
986 	nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
987 	nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
988 
989 	nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
990 	nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
991 
992 	nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
993 	nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
994 	nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
995 	nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
996 	nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
997 	nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
998 	nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
999 	nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
1000 	for (pf_sn_types_t sn_type=0; sn_type<PF_SN_MAX; sn_type++)
1001 		src_nodes_total += counter_u64_fetch(rule->src_nodes[sn_type]);
1002 	nlattr_add_u64(nw, PF_RT_SRC_NODES, src_nodes_total);
1003 	nlattr_add_u64(nw, PF_RT_SRC_NODES_LIMIT, counter_u64_fetch(rule->src_nodes[PF_SN_LIMIT]));
1004 	nlattr_add_u64(nw, PF_RT_SRC_NODES_NAT, counter_u64_fetch(rule->src_nodes[PF_SN_NAT]));
1005 	nlattr_add_u64(nw, PF_RT_SRC_NODES_ROUTE, counter_u64_fetch(rule->src_nodes[PF_SN_ROUTE]));
1006 
1007 	error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
1008 	MPASS(error == 0);
1009 
1010 	nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
1011 
1012 	if (attrs.clear)
1013 		pf_krule_clear_counters(rule);
1014 
1015 	PF_RULES_WUNLOCK();
1016 
1017 	if (!nlmsg_end(nw)) {
1018 		error = ENOMEM;
1019 		goto out;
1020 	}
1021 
1022 	return (0);
1023 out:
1024 	nlmsg_abort(nw);
1025 	return (error);
1026 }
1027 
1028 #define	_OUT(_field)	offsetof(struct pf_kstate_kill, _field)
1029 static const struct nlattr_parser nla_p_clear_states[] = {
1030 	{ .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1031 	{ .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1032 	{ .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1033 	{ .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1034 	{ .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1035 	{ .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1036 	{ .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1037 	{ .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1038 	{ .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1039 	{ .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1040 	{ .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1041 	{ .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1042 };
1043 #undef _OUT
1044 NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_empty, nla_p_clear_states);
1045 
1046 static int
1047 pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1048 {
1049 	struct pf_kstate_kill		 kill = {};
1050 	struct epoch_tracker		 et;
1051 	struct nl_writer		*nw = npt->nw;
1052 	struct genlmsghdr		*ghdr_new;
1053 	int				 error;
1054 	unsigned int			 killed = 0;
1055 
1056 	error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1057 	if (error != 0)
1058 		return (error);
1059 
1060 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1061 		return (ENOMEM);
1062 
1063 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1064 	ghdr_new->cmd = cmd;
1065 	ghdr_new->version = 0;
1066 	ghdr_new->reserved = 0;
1067 
1068 	NET_EPOCH_ENTER(et);
1069 	if (cmd == PFNL_CMD_KILLSTATES)
1070 		pf_killstates(&kill, &killed);
1071 	else
1072 		killed = pf_clear_states(&kill);
1073 	NET_EPOCH_EXIT(et);
1074 
1075 	nlattr_add_u32(nw, PF_CS_KILLED, killed);
1076 
1077 	if (! nlmsg_end(nw)) {
1078 		error = ENOMEM;
1079 		goto out;
1080 	}
1081 
1082 	return (0);
1083 
1084 out:
1085 	nlmsg_abort(nw);
1086 	return (error);
1087 }
1088 
1089 static int
1090 pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1091 {
1092 	return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1093 }
1094 
1095 static int
1096 pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1097 {
1098 	return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1099 }
1100 
1101 struct nl_parsed_set_statusif {
1102 	char ifname[IFNAMSIZ];
1103 };
1104 #define	_OUT(_field)	offsetof(struct nl_parsed_set_statusif, _field)
1105 static const struct nlattr_parser nla_p_set_statusif[] = {
1106 	{ .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1107 };
1108 #undef _OUT
1109 NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_statusif);
1110 
1111 static int
1112 pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1113 {
1114 	int error;
1115 	struct nl_parsed_set_statusif attrs = {};
1116 
1117 	error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1118 	if (error != 0)
1119 		return (error);
1120 
1121 	PF_RULES_WLOCK();
1122 	strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1123 	PF_RULES_WUNLOCK();
1124 
1125 	return (0);
1126 }
1127 
1128 static bool
1129 nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1130     counter_u64_t *counters)
1131 {
1132 	for (int i = 0; i < number; i++) {
1133 		int off = nlattr_add_nested(nw, attr);
1134 		nlattr_add_u32(nw, PF_C_ID, i);
1135 		nlattr_add_string(nw, PF_C_NAME, names[i]);
1136 		nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1137 		nlattr_set_len(nw, off);
1138 	}
1139 
1140 	return (true);
1141 }
1142 
1143 static bool
1144 nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1145     struct pf_counter_u64 *counters)
1146 {
1147 	for (int i = 0; i < number; i++) {
1148 		int off = nlattr_add_nested(nw, attr);
1149 		nlattr_add_u32(nw, PF_C_ID, i);
1150 		nlattr_add_string(nw, PF_C_NAME, names[i]);
1151 		nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1152 		nlattr_set_len(nw, off);
1153 	}
1154 
1155 	return (true);
1156 }
1157 
1158 static bool
1159 nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
1160 {
1161 	int off = nlattr_add_nested(nw, attr);
1162 
1163 	for (size_t i = 0; i < number; i++)
1164 		nlattr_add_u64(nw, 0, array[i]);
1165 
1166 	nlattr_set_len(nw, off);
1167 
1168 	return (true);
1169 }
1170 
1171 static int
1172 pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1173 {
1174 	struct pf_status s;
1175 	struct nl_writer *nw = npt->nw;
1176 	struct genlmsghdr *ghdr_new;
1177 	char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1178 	char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1179 	char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1180 	time_t since;
1181 	int error;
1182 
1183 	PF_RULES_RLOCK_TRACKER;
1184 
1185 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1186 		return (ENOMEM);
1187 
1188 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1189 	ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1190 	ghdr_new->version = 0;
1191 	ghdr_new->reserved = 0;
1192 
1193 	since = time_second - (time_uptime - V_pf_status.since);
1194 
1195 	PF_RULES_RLOCK();
1196 
1197 	nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1198 	nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1199 	nlattr_add_u32(nw, PF_GS_SINCE, since);
1200 	nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1201 	nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1202 	nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1203 	nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1204 	nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1205 	nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1206 
1207 	nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1208 	    V_pf_status.counters);
1209 	nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1210 	    V_pf_status.lcounters);
1211 	nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1212 	    V_pf_status.fcounters);
1213 	nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1214 	    V_pf_status.scounters);
1215 
1216 	pfi_update_status(V_pf_status.ifname, &s);
1217 	nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1218 	nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1219 
1220 	nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1221 
1222 	PF_RULES_RUNLOCK();
1223 
1224 	if (!nlmsg_end(nw)) {
1225 		error = ENOMEM;
1226 		goto out;
1227 	}
1228 
1229 	return (0);
1230 
1231 out:
1232 	nlmsg_abort(nw);
1233 	return (error);
1234 }
1235 
1236 static int
1237 pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1238 {
1239 	pf_ioctl_clear_status();
1240 
1241 	return (0);
1242 }
1243 
1244 struct pf_nl_natlook {
1245 	sa_family_t af;
1246 	uint8_t direction;
1247 	uint8_t proto;
1248 	struct pf_addr src;
1249 	struct pf_addr dst;
1250 	uint16_t sport;
1251 	uint16_t dport;
1252 };
1253 
1254 #define	_OUT(_field)	offsetof(struct pf_nl_natlook, _field)
1255 static const struct nlattr_parser nla_p_natlook[] = {
1256 	{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1257 	{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
1258 	{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
1259 	{ .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
1260 	{ .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
1261 	{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
1262 	{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
1263 };
1264 #undef _OUT
1265 NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_empty, nla_p_natlook);
1266 
1267 static int
1268 pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
1269 {
1270 	struct pf_nl_natlook	 attrs = {};
1271 	struct pf_state_key_cmp	 key = {};
1272 	struct nl_writer	*nw = npt->nw;
1273 	struct pf_state_key	*sk;
1274 	struct pf_kstate	*state;
1275 	struct genlmsghdr	*ghdr_new;
1276 	int			 error, m = 0;
1277 	int			 sidx, didx;
1278 
1279 	error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
1280 	if (error != 0)
1281 		return (error);
1282 
1283 	if (attrs.proto == 0 ||
1284 	    PF_AZERO(&attrs.src, attrs.af) ||
1285 	    PF_AZERO(&attrs.dst, attrs.af) ||
1286 	    ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
1287 	     (attrs.sport == 0 || attrs.dport == 0)))
1288 		return (EINVAL);
1289 
1290 	/* NATLOOK src and dst are reversed, so reverse sidx/didx */
1291 	sidx = (attrs.direction == PF_IN) ? 1 : 0;
1292 	didx = (attrs.direction == PF_IN) ? 0 : 1;
1293 
1294 	key.af = attrs.af;
1295 	key.proto = attrs.proto;
1296 	PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af);
1297 	key.port[sidx] = attrs.sport;
1298 	PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af);
1299 	key.port[didx] = attrs.dport;
1300 
1301 	state = pf_find_state_all(&key, attrs.direction, &m);
1302 	if (state == NULL)
1303 		return (ENOENT);
1304 	if (m > 1) {
1305 		PF_STATE_UNLOCK(state);
1306 		return (E2BIG);
1307 	}
1308 
1309 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1310 		PF_STATE_UNLOCK(state);
1311 		return (ENOMEM);
1312 	}
1313 
1314 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1315 	ghdr_new->cmd = PFNL_CMD_NATLOOK;
1316 	ghdr_new->version = 0;
1317 	ghdr_new->reserved = 0;
1318 
1319 	sk = state->key[sidx];
1320 
1321 	nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
1322 	nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
1323 	nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
1324 	nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
1325 
1326 	PF_STATE_UNLOCK(state);
1327 
1328 	if (!nlmsg_end(nw)) {
1329 		nlmsg_abort(nw);
1330 		return (ENOMEM);
1331 	}
1332 
1333 	return (0);
1334 }
1335 
1336 struct pf_nl_set_debug
1337 {
1338 	uint32_t level;
1339 };
1340 #define	_OUT(_field)	offsetof(struct pf_nl_set_debug, _field)
1341 static const struct nlattr_parser nla_p_set_debug[] = {
1342 	{ .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
1343 };
1344 #undef _OUT
1345 NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_debug);
1346 
1347 static int
1348 pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
1349 {
1350 	struct pf_nl_set_debug attrs = {};
1351 	int error;
1352 
1353 	error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
1354 	if (error != 0)
1355 		return (error);
1356 
1357 	PF_RULES_WLOCK();
1358 	V_pf_status.debug = attrs.level;
1359 	PF_RULES_WUNLOCK();
1360 
1361 	return (0);
1362 }
1363 
1364 struct pf_nl_set_timeout
1365 {
1366 	uint32_t timeout;
1367 	uint32_t seconds;
1368 };
1369 #define	_OUT(_field)	offsetof(struct pf_nl_set_timeout, _field)
1370 static const struct nlattr_parser nla_p_set_timeout[] = {
1371 	{ .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
1372 	{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
1373 };
1374 #undef _OUT
1375 NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_timeout);
1376 
1377 static int
1378 pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1379 {
1380 	struct pf_nl_set_timeout attrs = {};
1381 	int error;
1382 
1383 	error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1384 	if (error != 0)
1385 		return (error);
1386 
1387 	return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
1388 }
1389 
1390 static int
1391 pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1392 {
1393 	struct pf_nl_set_timeout attrs = {};
1394 	struct nl_writer *nw = npt->nw;
1395 	struct genlmsghdr *ghdr_new;
1396 	int error;
1397 
1398 	error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1399 	if (error != 0)
1400 		return (error);
1401 
1402 	error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
1403 	if (error != 0)
1404 		return (error);
1405 
1406 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1407 		return (ENOMEM);
1408 
1409 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1410 	ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
1411 	ghdr_new->version = 0;
1412 	ghdr_new->reserved = 0;
1413 
1414 	nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
1415 
1416 	if (!nlmsg_end(nw)) {
1417 		nlmsg_abort(nw);
1418 		return (ENOMEM);
1419 	}
1420 
1421 	return (0);
1422 }
1423 
1424 struct pf_nl_set_limit
1425 {
1426 	uint32_t index;
1427 	uint32_t limit;
1428 };
1429 #define	_OUT(_field)	offsetof(struct pf_nl_set_limit, _field)
1430 static const struct nlattr_parser nla_p_set_limit[] = {
1431 	{ .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
1432 	{ .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
1433 };
1434 #undef _OUT
1435 NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_empty, nla_p_set_limit);
1436 
1437 static int
1438 pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1439 {
1440 	struct pf_nl_set_limit attrs = {};
1441 	int error;
1442 
1443 	error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1444 	if (error != 0)
1445 		return (error);
1446 
1447 	return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
1448 }
1449 
1450 static int
1451 pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
1452 {
1453 	struct pf_nl_set_limit attrs = {};
1454 	struct nl_writer *nw = npt->nw;
1455 	struct genlmsghdr *ghdr_new;
1456 	int error;
1457 
1458 	error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
1459 	if (error != 0)
1460 		return (error);
1461 
1462 	error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
1463 	if (error != 0)
1464 		return (error);
1465 
1466 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1467 		return (ENOMEM);
1468 
1469 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1470 	ghdr_new->cmd = PFNL_CMD_GET_LIMIT;
1471 	ghdr_new->version = 0;
1472 	ghdr_new->reserved = 0;
1473 
1474 	nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
1475 
1476 	if (!nlmsg_end(nw)) {
1477 		nlmsg_abort(nw);
1478 		return (ENOMEM);
1479 	}
1480 
1481 	return (0);
1482 }
1483 
1484 static int
1485 pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1486 {
1487 	struct nl_writer *nw = npt->nw;
1488 	struct genlmsghdr *ghdr_new;
1489 	uint32_t ticket;
1490 	int error;
1491 
1492 	error = pf_ioctl_begin_addrs(&ticket);
1493 	if (error != 0)
1494 		return (error);
1495 
1496 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1497 		return (ENOMEM);
1498 
1499 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1500 	ghdr_new->cmd = PFNL_CMD_BEGIN_ADDRS;
1501 	ghdr_new->version = 0;
1502 	ghdr_new->reserved = 0;
1503 
1504 	nlattr_add_u32(nw, PF_BA_TICKET, ticket);
1505 
1506 	if (!nlmsg_end(nw)) {
1507 		nlmsg_abort(nw);
1508 		return (ENOMEM);
1509 	}
1510 
1511 	return (0);
1512 }
1513 
1514 static bool
1515 nlattr_add_pool_addr(struct nl_writer *nw, int attrtype, struct pf_pooladdr *a)
1516 {
1517 	int off;
1518 
1519 	off = nlattr_add_nested(nw, attrtype);
1520 
1521 	nlattr_add_addr_wrap(nw, PF_PA_ADDR, &a->addr);
1522 	nlattr_add_string(nw, PF_PA_IFNAME, a->ifname);
1523 
1524 	nlattr_set_len(nw, off);
1525 
1526 	return (true);
1527 }
1528 
1529 #define _OUT(_field)	offsetof(struct pf_pooladdr, _field)
1530 static const struct nlattr_parser nla_p_pool_addr[] = {
1531 	{ .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
1532 	{ .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1533 };
1534 NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr);
1535 #undef _OUT
1536 
1537 #define	_OUT(_field)	offsetof(struct pf_nl_pooladdr, _field)
1538 static const struct nlattr_parser nla_p_add_addr[] = {
1539 	{ .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 },
1540 	{ .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
1541 	{ .type = PF_AA_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1542 	{ .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = nlattr_get_uint32 },
1543 	{ .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = nlattr_get_uint8 },
1544 	{ .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = nlattr_get_uint8 },
1545 	{ .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1546 	{ .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1547 	{ .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested },
1548 	{ .type = PF_AA_WHICH, .off = _OUT(which), .cb = nlattr_get_uint32 },
1549 };
1550 #undef _OUT
1551 NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_empty, nla_p_add_addr);
1552 
1553 static int
1554 pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1555 {
1556 	struct pf_nl_pooladdr attrs = { 0 };
1557 	int error;
1558 
1559 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1560 	if (error != 0)
1561 		return (error);
1562 
1563 	if (attrs.which == 0)
1564 		attrs.which = PF_RDR;
1565 
1566 	error = pf_ioctl_add_addr(&attrs);
1567 
1568 	return (error);
1569 }
1570 
1571 static int
1572 pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1573 {
1574 	struct pf_nl_pooladdr attrs = { 0 };
1575 	struct nl_writer *nw = npt->nw;
1576 	struct genlmsghdr *ghdr_new;
1577 	int error;
1578 
1579 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1580 	if (error != 0)
1581 		return (error);
1582 
1583 	if (attrs.which == 0)
1584 		attrs.which = PF_RDR;
1585 
1586 	error = pf_ioctl_get_addrs(&attrs);
1587 	if (error != 0)
1588 		return (error);
1589 
1590 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1591 		return (ENOMEM);
1592 
1593 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1594 	ghdr_new->cmd = PFNL_CMD_GET_ADDRS;
1595 	ghdr_new->version = 0;
1596 	ghdr_new->reserved = 0;
1597 
1598 	nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1599 
1600 	if (!nlmsg_end(nw)) {
1601 		nlmsg_abort(nw);
1602 		return (ENOMEM);
1603 	}
1604 
1605 	return (error);
1606 }
1607 
1608 static int
1609 pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1610 {
1611 	struct pf_nl_pooladdr attrs = { 0 };
1612 	struct nl_writer *nw = npt->nw;
1613 	struct genlmsghdr *ghdr_new;
1614 	int error;
1615 
1616 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1617 	if (error != 0)
1618 		return (error);
1619 
1620 	if (attrs.which == 0)
1621 		attrs.which = PF_RDR;
1622 
1623 	error = pf_ioctl_get_addr(&attrs);
1624 	if (error != 0)
1625 		return (error);
1626 
1627 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1628 		return (ENOMEM);
1629 
1630 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1631 	ghdr_new->cmd = PFNL_CMD_GET_ADDR;
1632 	ghdr_new->version = 0;
1633 	ghdr_new->reserved = 0;
1634 
1635 	nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
1636 	nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
1637 	nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1638 	nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
1639 	nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
1640 	nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
1641 	nlattr_add_u8(nw, PF_AA_AF, attrs.af);
1642 	nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
1643 	nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);
1644 
1645 	if (!nlmsg_end(nw)) {
1646 		nlmsg_abort(nw);
1647 		return (ENOMEM);
1648 	}
1649 
1650 	return (0);
1651 }
1652 
1653 #define _OUT(_field)	offsetof(struct pfioc_ruleset, _field)
1654 static const struct nlattr_parser nla_p_ruleset[] = {
1655 	{ .type = PF_RS_PATH, .off = _OUT(path), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1656 	{ .type = PF_RS_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1657 };
1658 NL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, nlf_p_empty, nla_p_ruleset);
1659 #undef _OUT
1660 
1661 static int
1662 pf_handle_get_rulesets(struct nlmsghdr *hdr, struct nl_pstate *npt)
1663 {
1664 	struct pfioc_ruleset attrs = { 0 };
1665 	struct nl_writer *nw = npt->nw;
1666 	struct genlmsghdr *ghdr_new;
1667 	int error;
1668 
1669 	error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1670 	if (error != 0)
1671 		return (error);
1672 
1673 	error = pf_ioctl_get_rulesets(&attrs);
1674 	if (error != 0)
1675 		return (error);
1676 
1677 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1678 		return (ENOMEM);
1679 
1680 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1681 	ghdr_new->cmd = PFNL_CMD_GET_RULESETS;
1682 	ghdr_new->version = 0;
1683 	ghdr_new->reserved = 0;
1684 
1685 	nlattr_add_u32(nw, PF_RS_NR, attrs.nr);
1686 
1687 	if (!nlmsg_end(nw)) {
1688 		nlmsg_abort(nw);
1689 		return (ENOMEM);
1690 	}
1691 
1692 	return (0);
1693 }
1694 
1695 static int
1696 pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt)
1697 {
1698 	struct pfioc_ruleset attrs = { 0 };
1699 	struct nl_writer *nw = npt->nw;
1700 	struct genlmsghdr *ghdr_new;
1701 	int error;
1702 
1703 	error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1704 	if (error)
1705 		return (error);
1706 
1707 	error = pf_ioctl_get_ruleset(&attrs);
1708 	if (error != 0)
1709 		return (error);
1710 
1711 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1712 		return (ENOMEM);
1713 
1714 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1715 	ghdr_new->cmd = PFNL_CMD_GET_RULESET;
1716 	ghdr_new->version = 0;
1717 	ghdr_new->reserved = 0;
1718 
1719 	nlattr_add_string(nw, PF_RS_NAME, attrs.name);
1720 
1721 	if (!nlmsg_end(nw)) {
1722 		nlmsg_abort(nw);
1723 		return (ENOMEM);
1724 	}
1725 
1726 	return (0);
1727 }
1728 
1729 static bool
1730 nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype,
1731     struct pf_threshold *t, int secs)
1732 {
1733 	int	 off = nlattr_add_nested(nw, attrtype);
1734 	int	 diff, conn_rate_count;
1735 
1736 	/* Adjust the connection rate estimate. */
1737 	conn_rate_count = t->count;
1738 	diff = secs - t->last;
1739 	if (diff >= t->seconds)
1740 		conn_rate_count = 0;
1741 	else
1742 		conn_rate_count -= t->count * diff / t->seconds;
1743 
1744 	nlattr_add_u32(nw, PF_TH_LIMIT, t->limit);
1745 	nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds);
1746 	nlattr_add_u32(nw, PF_TH_COUNT, conn_rate_count);
1747 	nlattr_add_u32(nw, PF_TH_LAST, t->last);
1748 
1749 	nlattr_set_len(nw, off);
1750 
1751 	return (true);
1752 }
1753 
1754 static int
1755 pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt)
1756 {
1757 	struct nl_writer	*nw = npt->nw;
1758 	struct genlmsghdr	*ghdr_new;
1759 	struct pf_ksrc_node	*n;
1760 	struct pf_srchash	*sh;
1761 	int			 i;
1762 	int			 secs;
1763 
1764 	hdr->nlmsg_flags |= NLM_F_MULTI;
1765 
1766 	for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
1767 	    i++, sh++) {
1768 		/* Avoid locking empty rows. */
1769 		if (LIST_EMPTY(&sh->nodes))
1770 			continue;
1771 
1772 		PF_HASHROW_LOCK(sh);
1773 		secs = time_uptime;
1774 
1775 		LIST_FOREACH(n, &sh->nodes, entry) {
1776 			if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1777 				nlmsg_abort(nw);
1778 				return (ENOMEM);
1779 			}
1780 
1781 			ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1782 			ghdr_new->cmd = PFNL_CMD_GET_SRCNODES;
1783 			ghdr_new->version = 0;
1784 			ghdr_new->reserved = 0;
1785 
1786 			nlattr_add_in6_addr(nw, PF_SN_ADDR, &n->addr.v6);
1787 			nlattr_add_in6_addr(nw, PF_SN_RADDR, &n->raddr.v6);
1788 			nlattr_add_u32(nw, PF_SN_RULE_NR, n->rule->nr);
1789 			nlattr_add_u64(nw, PF_SN_BYTES_IN, counter_u64_fetch(n->bytes[0]));
1790 			nlattr_add_u64(nw, PF_SN_BYTES_OUT, counter_u64_fetch(n->bytes[1]));
1791 			nlattr_add_u64(nw, PF_SN_PACKETS_IN, counter_u64_fetch(n->packets[0]));
1792 			nlattr_add_u64(nw, PF_SN_PACKETS_OUT, counter_u64_fetch(n->packets[1]));
1793 			nlattr_add_u32(nw, PF_SN_STATES, n->states);
1794 			nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
1795 			nlattr_add_u8(nw, PF_SN_AF, n->af);
1796 			nlattr_add_u8(nw, PF_SN_NAF, n->naf);
1797 			nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
1798 
1799 			nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation);
1800 			if (n->expire > secs)
1801 				nlattr_add_u64(nw, PF_SN_EXPIRE, n->expire - secs);
1802 			else
1803 				nlattr_add_u64(nw, PF_SN_EXPIRE, 0);
1804 
1805 			nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE,
1806 			    &n->conn_rate, secs);
1807 
1808 			nlattr_add_u8(nw, PF_SN_NODE_TYPE, n->type);
1809 
1810 			if (!nlmsg_end(nw)) {
1811 				PF_HASHROW_UNLOCK(sh);
1812 				nlmsg_abort(nw);
1813 				return (ENOMEM);
1814 			}
1815 		}
1816 		PF_HASHROW_UNLOCK(sh);
1817 	}
1818 
1819 	return (0);
1820 }
1821 
1822 #define _OUT(_field)	offsetof(struct pfioc_table, _field)
1823 static const struct nlattr_parser nla_p_table[] = {
1824 	{ .type = PF_T_ANCHOR, .off = _OUT(pfrio_table.pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1825 	{ .type = PF_T_NAME, .off = _OUT(pfrio_table.pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
1826 	{ .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrio_table.pfrt_flags), .cb = nlattr_get_uint32 },
1827 	{ .type = PF_T_FLAGS, .off = _OUT(pfrio_flags), .cb = nlattr_get_uint32 },
1828 };
1829 static const struct nlfield_parser nlf_p_table[] = {};
1830 NL_DECLARE_PARSER(table_parser, struct genlmsghdr, nlf_p_table, nla_p_table);
1831 #undef _OUT
1832 static int
1833 pf_handle_clear_tables(struct nlmsghdr *hdr, struct nl_pstate *npt)
1834 {
1835 	struct pfioc_table attrs = { 0 };
1836 	struct nl_writer *nw = npt->nw;
1837 	struct genlmsghdr *ghdr_new;
1838 	int ndel = 0;
1839 	int error;
1840 
1841 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1842 	if (error != 0)
1843 		return (error);
1844 
1845 	PF_RULES_WLOCK();
1846 	error = pfr_clr_tables(&attrs.pfrio_table, &ndel, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1847 	PF_RULES_WUNLOCK();
1848 	if (error != 0)
1849 		return (error);
1850 
1851 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1852 		return (ENOMEM);
1853 
1854 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1855 	ghdr_new->cmd = PFNL_CMD_CLEAR_TABLES;
1856 	ghdr_new->version = 0;
1857 	ghdr_new->reserved = 0;
1858 
1859 	nlattr_add_u32(nw, PF_T_NBR_DELETED, ndel);
1860 
1861 	if (!nlmsg_end(nw)) {
1862 		nlmsg_abort(nw);
1863 		return (ENOMEM);
1864 	}
1865 
1866 	return (0);
1867 }
1868 
1869 static int
1870 pf_handle_add_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1871 {
1872 	struct pfioc_table attrs = { 0 };
1873 	struct nl_writer *nw = npt->nw;
1874 	struct genlmsghdr *ghdr_new;
1875 	int error;
1876 
1877 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1878 	if (error != 0)
1879 		return (error);
1880 
1881 	PF_RULES_WLOCK();
1882 	error = pfr_add_tables(&attrs.pfrio_table, 1, &attrs.pfrio_nadd,
1883 	    attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1884 	PF_RULES_WUNLOCK();
1885 	if (error != 0)
1886 		return (error);
1887 
1888 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1889 		return (ENOMEM);
1890 
1891 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1892 	ghdr_new->cmd = PFNL_CMD_ADD_TABLE;
1893 	ghdr_new->version = 0;
1894 	ghdr_new->reserved = 0;
1895 
1896 	nlattr_add_u32(nw, PF_T_NBR_ADDED, attrs.pfrio_nadd);
1897 
1898 	if (!nlmsg_end(nw)) {
1899 		nlmsg_abort(nw);
1900 		return (ENOMEM);
1901 	}
1902 
1903 	return (0);
1904 }
1905 
1906 static int
1907 pf_handle_del_table(struct nlmsghdr *hdr, struct nl_pstate *npt)
1908 {
1909 	struct pfioc_table attrs = { 0 };
1910 	struct nl_writer *nw = npt->nw;
1911 	struct genlmsghdr *ghdr_new;
1912 	int error;
1913 
1914 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1915 	if (error != 0)
1916 		return (error);
1917 
1918 	PF_RULES_WLOCK();
1919 	error = pfr_del_tables(&attrs.pfrio_table, 1, &attrs.pfrio_ndel,
1920 	    attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1921 	PF_RULES_WUNLOCK();
1922 	if (error != 0)
1923 		return (error);
1924 
1925 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1926 		return (ENOMEM);
1927 
1928 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1929 	ghdr_new->cmd = PFNL_CMD_ADD_TABLE;
1930 	ghdr_new->version = 0;
1931 	ghdr_new->reserved = 0;
1932 
1933 	nlattr_add_u32(nw, PF_T_NBR_DELETED, attrs.pfrio_ndel);
1934 
1935 	if (!nlmsg_end(nw)) {
1936 		nlmsg_abort(nw);
1937 		return (ENOMEM);
1938 	}
1939 
1940 	return (0);
1941 }
1942 
1943 static bool
1944 nlattr_add_pfr_table(struct nl_writer *nw, int attrtype,
1945     struct pfr_table *t)
1946 {
1947 	int	 off = nlattr_add_nested(nw, attrtype);
1948 
1949 	nlattr_add_string(nw, PF_T_ANCHOR, t->pfrt_anchor);
1950 	nlattr_add_string(nw, PF_T_NAME, t->pfrt_name);
1951 	nlattr_add_u32(nw, PF_T_TABLE_FLAGS, t->pfrt_flags);
1952 
1953 	nlattr_set_len(nw, off);
1954 
1955 	return (true);
1956 }
1957 
1958 static int
1959 pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
1960 {
1961 	struct pfioc_table attrs = { 0 };
1962 	struct nl_writer *nw = npt->nw;
1963 	struct genlmsghdr *ghdr_new;
1964 	struct pfr_tstats *pfrtstats;
1965 	int error;
1966 	int n;
1967 
1968 	PF_RULES_RLOCK_TRACKER;
1969 
1970 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
1971 	if (error != 0)
1972 		return (error);
1973 
1974 	PF_TABLE_STATS_LOCK();
1975 	PF_RULES_RLOCK();
1976 
1977 	n = pfr_table_count(&attrs.pfrio_table, attrs.pfrio_flags);
1978 	pfrtstats = mallocarray(n,
1979 	    sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT | M_ZERO);
1980 
1981 	error = pfr_get_tstats(&attrs.pfrio_table, pfrtstats,
1982 	    &n, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
1983 
1984 	PF_RULES_RUNLOCK();
1985 	PF_TABLE_STATS_UNLOCK();
1986 
1987 	if (error == 0) {
1988 		hdr->nlmsg_flags |= NLM_F_MULTI;
1989 
1990 		for (int i = 0; i < n; i++) {
1991 			uint64_t refcnt[PFR_REFCNT_MAX];
1992 
1993 			if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1994 				error = ENOMEM;
1995 				break;
1996 			}
1997 
1998 			ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1999 			ghdr_new->cmd = PFNL_CMD_GET_TSTATS;
2000 			ghdr_new->version = 0;
2001 			ghdr_new->reserved = 0;
2002 
2003 			nlattr_add_pfr_table(nw, PF_TS_TABLE,
2004 			    &pfrtstats[i].pfrts_t);
2005 			nlattr_add_u64_array(nw, PF_TS_PACKETS,
2006 			    PFR_DIR_MAX * PFR_OP_TABLE_MAX,
2007 			    (uint64_t *)pfrtstats[i].pfrts_packets);
2008 			nlattr_add_u64_array(nw, PF_TS_BYTES,
2009 			    PFR_DIR_MAX * PFR_OP_TABLE_MAX,
2010 			    (uint64_t *)pfrtstats[i].pfrts_bytes);
2011 			nlattr_add_u64(nw, PF_TS_MATCH,
2012 			    pfrtstats[i].pfrts_match);
2013 			nlattr_add_u64(nw, PF_TS_NOMATCH,
2014 			    pfrtstats[i].pfrts_nomatch);
2015 			nlattr_add_u64(nw, PF_TS_TZERO,
2016 			    pfrtstats[i].pfrts_tzero);
2017 			nlattr_add_u64(nw, PF_TS_CNT, pfrtstats[i].pfrts_cnt);
2018 
2019 			for (int j = 0; j < PFR_REFCNT_MAX; j++)
2020 				refcnt[j] = pfrtstats[i].pfrts_refcnt[j];
2021 
2022 			nlattr_add_u64_array(nw, PF_TS_REFCNT, PFR_REFCNT_MAX,
2023 			    refcnt);
2024 
2025 			if (! nlmsg_end(nw)) {
2026 				error = ENOMEM;
2027 				break;
2028 			}
2029 		}
2030 	}
2031 	free(pfrtstats, M_TEMP);
2032 
2033 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
2034 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
2035 		return (ENOMEM);
2036 	}
2037 
2038 	return (error);
2039 }
2040 
2041 static int
2042 pf_handle_clear_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
2043 {
2044 	struct pfioc_table attrs = { 0 };
2045 	struct nl_writer *nw = npt->nw;
2046 	struct genlmsghdr *ghdr_new;
2047 	int error;
2048 	int nzero;
2049 
2050 	PF_RULES_RLOCK_TRACKER;
2051 
2052 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2053 	if (error != 0)
2054 		return (error);
2055 
2056 	PF_TABLE_STATS_LOCK();
2057 	PF_RULES_RLOCK();
2058 	error = pfr_clr_tstats(&attrs.pfrio_table, 1,
2059 	    &nzero, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2060 	PF_RULES_RUNLOCK();
2061 	PF_TABLE_STATS_UNLOCK();
2062 
2063 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2064 		return (ENOMEM);
2065 
2066 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2067 	ghdr_new->cmd = PFNL_CMD_CLR_TSTATS;
2068 	ghdr_new->version = 0;
2069 	ghdr_new->reserved = 0;
2070 
2071 	nlattr_add_u64(nw, PF_TS_NZERO, nzero);
2072 
2073 	if (! nlmsg_end(nw))
2074 		error = ENOMEM;
2075 
2076 	return (error);
2077 }
2078 
2079 static int
2080 pf_handle_clear_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
2081 {
2082 	struct pfioc_table attrs = { 0 };
2083 	struct nl_writer *nw = npt->nw;
2084 	struct genlmsghdr *ghdr_new;
2085 	int error;
2086 	int ndel;
2087 
2088 	error = nl_parse_nlmsg(hdr, &table_parser, npt, &attrs);
2089 	if (error != 0)
2090 		return (error);
2091 
2092 	PF_RULES_WLOCK();
2093 	error = pfr_clr_addrs(&attrs.pfrio_table, &ndel,
2094 	    attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
2095 	PF_RULES_WUNLOCK();
2096 
2097 	if (error)
2098 		return (error);
2099 
2100 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
2101 		return (ENOMEM);
2102 
2103 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
2104 	ghdr_new->cmd = PFNL_CMD_CLR_ADDRS;
2105 	ghdr_new->version = 0;
2106 	ghdr_new->reserved = 0;
2107 
2108 	nlattr_add_u64(nw, PF_T_NBR_DELETED, ndel);
2109 
2110 	if (!nlmsg_end(nw))
2111 		return (ENOMEM);
2112 
2113 	return (error);
2114 }
2115 
2116 static const struct nlhdr_parser *all_parsers[] = {
2117 	&state_parser,
2118 	&addrule_parser,
2119 	&getrules_parser,
2120 	&clear_states_parser,
2121 	&set_statusif_parser,
2122 	&natlook_parser,
2123 	&set_debug_parser,
2124 	&set_timeout_parser,
2125 	&set_limit_parser,
2126 	&pool_addr_parser,
2127 	&add_addr_parser,
2128 	&ruleset_parser,
2129 	&table_parser,
2130 };
2131 
2132 static uint16_t family_id;
2133 
2134 static const struct genl_cmd pf_cmds[] = {
2135 	{
2136 		.cmd_num = PFNL_CMD_GETSTATES,
2137 		.cmd_name = "GETSTATES",
2138 		.cmd_cb = pf_handle_getstates,
2139 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2140 		.cmd_priv = PRIV_NETINET_PF,
2141 	},
2142 	{
2143 		.cmd_num = PFNL_CMD_GETCREATORS,
2144 		.cmd_name = "GETCREATORS",
2145 		.cmd_cb = pf_handle_getcreators,
2146 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2147 		.cmd_priv = PRIV_NETINET_PF,
2148 	},
2149 	{
2150 		.cmd_num = PFNL_CMD_START,
2151 		.cmd_name = "START",
2152 		.cmd_cb = pf_handle_start,
2153 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2154 		.cmd_priv = PRIV_NETINET_PF,
2155 	},
2156 	{
2157 		.cmd_num = PFNL_CMD_STOP,
2158 		.cmd_name = "STOP",
2159 		.cmd_cb = pf_handle_stop,
2160 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2161 		.cmd_priv = PRIV_NETINET_PF,
2162 	},
2163 	{
2164 		.cmd_num = PFNL_CMD_ADDRULE,
2165 		.cmd_name = "ADDRULE",
2166 		.cmd_cb = pf_handle_addrule,
2167 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2168 		.cmd_priv = PRIV_NETINET_PF,
2169 	},
2170 	{
2171 		.cmd_num = PFNL_CMD_GETRULES,
2172 		.cmd_name = "GETRULES",
2173 		.cmd_cb = pf_handle_getrules,
2174 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2175 		.cmd_priv = PRIV_NETINET_PF,
2176 	},
2177 	{
2178 		.cmd_num = PFNL_CMD_GETRULE,
2179 		.cmd_name = "GETRULE",
2180 		.cmd_cb = pf_handle_getrule,
2181 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2182 		.cmd_priv = PRIV_NETINET_PF,
2183 	},
2184 	{
2185 		.cmd_num = PFNL_CMD_CLRSTATES,
2186 		.cmd_name = "CLRSTATES",
2187 		.cmd_cb = pf_handle_clear_states,
2188 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2189 		.cmd_priv = PRIV_NETINET_PF,
2190 	},
2191 	{
2192 		.cmd_num = PFNL_CMD_KILLSTATES,
2193 		.cmd_name = "KILLSTATES",
2194 		.cmd_cb = pf_handle_kill_states,
2195 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2196 		.cmd_priv = PRIV_NETINET_PF,
2197 	},
2198 	{
2199 		.cmd_num = PFNL_CMD_SET_STATUSIF,
2200 		.cmd_name = "SETSTATUSIF",
2201 		.cmd_cb = pf_handle_set_statusif,
2202 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2203 		.cmd_priv = PRIV_NETINET_PF,
2204 	},
2205 	{
2206 		.cmd_num = PFNL_CMD_GET_STATUS,
2207 		.cmd_name = "GETSTATUS",
2208 		.cmd_cb = pf_handle_get_status,
2209 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2210 		.cmd_priv = PRIV_NETINET_PF,
2211 	},
2212 	{
2213 		.cmd_num = PFNL_CMD_CLEAR_STATUS,
2214 		.cmd_name = "CLEARSTATUS",
2215 		.cmd_cb = pf_handle_clear_status,
2216 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2217 		.cmd_priv = PRIV_NETINET_PF,
2218 	},
2219 	{
2220 		.cmd_num = PFNL_CMD_NATLOOK,
2221 		.cmd_name = "NATLOOK",
2222 		.cmd_cb = pf_handle_natlook,
2223 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2224 		.cmd_priv = PRIV_NETINET_PF,
2225 	},
2226 	{
2227 		.cmd_num = PFNL_CMD_SET_DEBUG,
2228 		.cmd_name = "SET_DEBUG",
2229 		.cmd_cb = pf_handle_set_debug,
2230 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2231 		.cmd_priv = PRIV_NETINET_PF,
2232 	},
2233 	{
2234 		.cmd_num = PFNL_CMD_SET_TIMEOUT,
2235 		.cmd_name = "SET_TIMEOUT",
2236 		.cmd_cb = pf_handle_set_timeout,
2237 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2238 		.cmd_priv = PRIV_NETINET_PF,
2239 	},
2240 	{
2241 		.cmd_num = PFNL_CMD_GET_TIMEOUT,
2242 		.cmd_name = "GET_TIMEOUT",
2243 		.cmd_cb = pf_handle_get_timeout,
2244 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2245 		.cmd_priv = PRIV_NETINET_PF,
2246 	},
2247 	{
2248 		.cmd_num = PFNL_CMD_SET_LIMIT,
2249 		.cmd_name = "SET_LIMIT",
2250 		.cmd_cb = pf_handle_set_limit,
2251 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2252 		.cmd_priv = PRIV_NETINET_PF,
2253 	},
2254 	{
2255 		.cmd_num = PFNL_CMD_GET_LIMIT,
2256 		.cmd_name = "GET_LIMIT",
2257 		.cmd_cb = pf_handle_get_limit,
2258 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2259 		.cmd_priv = PRIV_NETINET_PF,
2260 	},
2261 	{
2262 		.cmd_num = PFNL_CMD_BEGIN_ADDRS,
2263 		.cmd_name = "BEGIN_ADDRS",
2264 		.cmd_cb = pf_handle_begin_addrs,
2265 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2266 		.cmd_priv = PRIV_NETINET_PF,
2267 	},
2268 	{
2269 		.cmd_num = PFNL_CMD_ADD_ADDR,
2270 		.cmd_name = "ADD_ADDR",
2271 		.cmd_cb = pf_handle_add_addr,
2272 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2273 		.cmd_priv = PRIV_NETINET_PF,
2274 	},
2275 	{
2276 		.cmd_num = PFNL_CMD_GET_ADDRS,
2277 		.cmd_name = "GET_ADDRS",
2278 		.cmd_cb = pf_handle_get_addrs,
2279 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2280 		.cmd_priv = PRIV_NETINET_PF,
2281 	},
2282 	{
2283 		.cmd_num = PFNL_CMD_GET_ADDR,
2284 		.cmd_name = "GET_ADDRS",
2285 		.cmd_cb = pf_handle_get_addr,
2286 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2287 		.cmd_priv = PRIV_NETINET_PF,
2288 	},
2289 	{
2290 		.cmd_num = PFNL_CMD_GET_RULESETS,
2291 		.cmd_name = "GET_RULESETS",
2292 		.cmd_cb = pf_handle_get_rulesets,
2293 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2294 		.cmd_priv = PRIV_NETINET_PF,
2295 	},
2296 	{
2297 		.cmd_num = PFNL_CMD_GET_RULESET,
2298 		.cmd_name = "GET_RULESET",
2299 		.cmd_cb = pf_handle_get_ruleset,
2300 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2301 		.cmd_priv = PRIV_NETINET_PF,
2302 	},
2303 	{
2304 		.cmd_num = PFNL_CMD_GET_SRCNODES,
2305 		.cmd_name = "GET_SRCNODES",
2306 		.cmd_cb = pf_handle_get_srcnodes,
2307 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2308 		.cmd_priv = PRIV_NETINET_PF,
2309 	},
2310 	{
2311 		.cmd_num = PFNL_CMD_CLEAR_TABLES,
2312 		.cmd_name = "CLEAR_TABLES",
2313 		.cmd_cb = pf_handle_clear_tables,
2314 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2315 		.cmd_priv = PRIV_NETINET_PF,
2316 	},
2317 	{
2318 		.cmd_num = PFNL_CMD_ADD_TABLE,
2319 		.cmd_name = "ADD_TABLE",
2320 		.cmd_cb = pf_handle_add_table,
2321 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2322 		.cmd_priv = PRIV_NETINET_PF,
2323 	},
2324 	{
2325 		.cmd_num = PFNL_CMD_DEL_TABLE,
2326 		.cmd_name = "DEL_TABLE",
2327 		.cmd_cb = pf_handle_del_table,
2328 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2329 		.cmd_priv = PRIV_NETINET_PF,
2330 	},
2331 	{
2332 		.cmd_num = PFNL_CMD_GET_TSTATS,
2333 		.cmd_name = "GET_TSTATS",
2334 		.cmd_cb = pf_handle_get_tstats,
2335 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2336 		.cmd_priv = PRIV_NETINET_PF,
2337 	},
2338 	{
2339 		.cmd_num = PFNL_CMD_CLR_TSTATS,
2340 		.cmd_name = "CLR_TSTATS",
2341 		.cmd_cb = pf_handle_clear_tstats,
2342 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2343 		.cmd_priv = PRIV_NETINET_PF,
2344 	},
2345 	{
2346 		.cmd_num = PFNL_CMD_CLR_ADDRS,
2347 		.cmd_name = "CRL_ADDRS",
2348 		.cmd_cb = pf_handle_clear_addrs,
2349 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
2350 		.cmd_priv = PRIV_NETINET_PF,
2351 	},
2352 };
2353 
2354 void
2355 pf_nl_register(void)
2356 {
2357 	NL_VERIFY_PARSERS(all_parsers);
2358 
2359 	family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
2360 	genl_register_cmds(family_id, pf_cmds, nitems(pf_cmds));
2361 }
2362 
2363 void
2364 pf_nl_unregister(void)
2365 {
2366 	genl_unregister_family(family_id);
2367 }
2368