xref: /freebsd/sys/netpfil/pf/pf_nl.c (revision f1ddb6fb8c4d051a205dae3a848776c9d56f86ff)
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->src_node)
190 		sync_flags |= PFSYNC_FLAG_SRCNODE;
191 	if (s->nat_src_node)
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 
214 	if (!dump_state_peer(nw, PF_ST_PEER_SRC, &s->src))
215 		goto enomem;
216 	if (!dump_state_peer(nw, PF_ST_PEER_DST, &s->dst))
217 		goto enomem;
218 
219 	if (nlmsg_end(nw))
220 		return (0);
221 
222 enomem:
223 	error = ENOMEM;
224 	nlmsg_abort(nw);
225 	return (error);
226 }
227 
228 static int
229 handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
230     struct nlmsghdr *hdr, struct nl_pstate *npt)
231 {
232 	int error = 0;
233 
234 	hdr->nlmsg_flags |= NLM_F_MULTI;
235 
236 	for (int i = 0; i <= V_pf_hashmask; i++) {
237 		struct pf_idhash *ih = &V_pf_idhash[i];
238 		struct pf_kstate *s;
239 
240 		if (LIST_EMPTY(&ih->states))
241 			continue;
242 
243 		PF_HASHROW_LOCK(ih);
244 		LIST_FOREACH(s, &ih->states, entry) {
245 			sa_family_t af = s->key[PF_SK_WIRE]->af;
246 
247 			if (s->timeout == PFTM_UNLINKED)
248 				continue;
249 
250 			/* Filter */
251 			if (attrs->creatorid != 0 && s->creatorid != attrs->creatorid)
252 				continue;
253 			if (attrs->ifname[0] != 0 &&
254 			    strncmp(attrs->ifname, s->kif->pfik_name, IFNAMSIZ) != 0)
255 				continue;
256 			if (attrs->proto != 0 && s->key[PF_SK_WIRE]->proto != attrs->proto)
257 				continue;
258 			if (attrs->af != 0 && af != attrs->af)
259 				continue;
260 			if (pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[0],
261 			    &attrs->mask, &attrs->addr, af) &&
262 			    pf_match_addr(1, &s->key[PF_SK_WIRE]->addr[1],
263 			    &attrs->mask, &attrs->addr, af) &&
264 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[0],
265 			    &attrs->mask, &attrs->addr, af) &&
266 			    pf_match_addr(1, &s->key[PF_SK_STACK]->addr[1],
267 			    &attrs->mask, &attrs->addr, af))
268 				continue;
269 
270 			error = dump_state(nlp, hdr, s, npt);
271 			if (error != 0)
272 				break;
273 		}
274 		PF_HASHROW_UNLOCK(ih);
275 	}
276 
277 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
278 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
279 		return (ENOMEM);
280 	}
281 
282 	return (error);
283 }
284 
285 static int
286 handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
287     struct nlmsghdr *hdr, struct nl_pstate *npt)
288 {
289 	struct pf_kstate *s;
290 	int ret;
291 
292 	s = pf_find_state_byid(attrs->id, attrs->creatorid);
293 	if (s == NULL)
294 		return (ENOENT);
295 	ret = dump_state(nlp, hdr, s, npt);
296 	PF_STATE_UNLOCK(s);
297 
298 	return (ret);
299 }
300 
301 static int
302 dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
303     struct nl_pstate *npt)
304 {
305 	struct nl_writer *nw = npt->nw;
306 
307 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
308 		goto enomem;
309 
310 	struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
311 	ghdr_new->cmd = PFNL_CMD_GETCREATORS;
312 	ghdr_new->version = 0;
313 	ghdr_new->reserved = 0;
314 
315 	nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
316 
317 	if (nlmsg_end(nw))
318 		return (0);
319 
320 enomem:
321 	nlmsg_abort(nw);
322 	return (ENOMEM);
323 }
324 
325 static int
326 pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
327 {
328 	int error;
329 
330 	struct nl_parsed_state attrs = {};
331 	error = nl_parse_nlmsg(hdr, &state_parser, npt, &attrs);
332 	if (error != 0)
333 		return (error);
334 
335 	if (attrs.id != 0)
336 		error = handle_getstate(npt->nlp, &attrs, hdr, npt);
337 	else
338 		error = handle_dumpstates(npt->nlp, &attrs, hdr, npt);
339 
340 	return (error);
341 }
342 
343 static int
344 pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
345 {
346 	uint32_t creators[16];
347 	int error = 0;
348 
349 	bzero(creators, sizeof(creators));
350 
351 	for (int i = 0; i < V_pf_hashmask; i++) {
352 		struct pf_idhash *ih = &V_pf_idhash[i];
353 		struct pf_kstate *s;
354 
355 		if (LIST_EMPTY(&ih->states))
356 			continue;
357 
358 		PF_HASHROW_LOCK(ih);
359 		LIST_FOREACH(s, &ih->states, entry) {
360 			int j;
361 			if (s->timeout == PFTM_UNLINKED)
362 				continue;
363 
364 			for (j = 0; j < nitems(creators); j++) {
365 				if (creators[j] == s->creatorid)
366 					break;
367 				if (creators[j] == 0) {
368 					creators[j] = s->creatorid;
369 					break;
370 				}
371 			}
372 			if (j == nitems(creators))
373 				printf("Warning: too many creators!\n");
374 		}
375 		PF_HASHROW_UNLOCK(ih);
376 	}
377 
378 	hdr->nlmsg_flags |= NLM_F_MULTI;
379 	for (int i = 0; i < nitems(creators); i++) {
380 		if (creators[i] == 0)
381 			break;
382 		error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
383 	}
384 
385 	if (!nlmsg_end_dump(npt->nw, error, hdr)) {
386 		NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
387 		return (ENOMEM);
388 	}
389 
390 	return (error);
391 }
392 
393 static int
394 pf_handle_start(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
395 {
396 	return (pf_start());
397 }
398 
399 static int
400 pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
401 {
402 	return (pf_stop());
403 }
404 
405 #define _OUT(_field)	offsetof(struct pf_addr_wrap, _field)
406 static const struct nlattr_parser nla_p_addr_wrap[] = {
407 	{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
408 	{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
409 	{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
410 	{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
411 	{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
412 	{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
413 };
414 NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
415 #undef _OUT
416 
417 static bool
418 nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
419 {
420 	int off = nlattr_add_nested(nw, attrtype);
421 
422 	nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
423 	nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
424 	nlattr_add_u8(nw, PF_AT_TYPE, a->type);
425 	nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
426 
427 	if (a->type == PF_ADDR_DYNIFTL) {
428 		nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
429 		nlattr_add_u32(nw, PF_AT_DYNCNT, a->p.dyncnt);
430 	} else if (a->type == PF_ADDR_TABLE) {
431 		nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
432 		nlattr_add_u32(nw, PF_AT_TBLCNT, a->p.tblcnt);
433 	}
434 
435 	nlattr_set_len(nw, off);
436 
437 	return (true);
438 }
439 
440 #define _OUT(_field)	offsetof(struct pf_rule_addr, _field)
441 static const struct nlattr_parser nla_p_ruleaddr[] = {
442 	{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
443 	{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
444 	{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
445 	{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
446 	{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
447 };
448 NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
449 #undef _OUT
450 
451 static bool
452 nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
453 {
454 	struct pf_addr_wrap aw = {0};
455 	int off = nlattr_add_nested(nw, attrtype);
456 
457 	bcopy(&(r->addr), &aw, sizeof(struct pf_addr_wrap));
458 	pf_addr_copyout(&aw);
459 
460 	nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &aw);
461 	nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
462 	nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
463 	nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
464 	nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
465 
466 	nlattr_set_len(nw, off);
467 
468 	return (true);
469 }
470 
471 #define _OUT(_field)	offsetof(struct pf_mape_portset, _field)
472 static const struct nlattr_parser nla_p_mape_portset[] = {
473 	{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
474 	{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
475 	{. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
476 };
477 NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
478 #undef _OUT
479 
480 static bool
481 nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
482 {
483 	int off = nlattr_add_nested(nw, attrtype);
484 
485 	nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
486 	nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
487 	nlattr_add_u16(nw, PF_MET_PSID, m->psid);
488 
489 	nlattr_set_len(nw, off);
490 
491 	return (true);
492 }
493 
494 struct nl_parsed_labels
495 {
496 	char		labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
497 	uint32_t	i;
498 };
499 
500 static int
501 nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
502     const void *arg, void *target)
503 {
504 	struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
505 	int ret;
506 
507 	if (l->i >= PF_RULE_MAX_LABEL_COUNT)
508 		return (E2BIG);
509 
510 	ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
511 	    l->labels[l->i]);
512 	if (ret == 0)
513 		l->i++;
514 
515 	return (ret);
516 }
517 
518 #define _OUT(_field)	offsetof(struct nl_parsed_labels, _field)
519 static const struct nlattr_parser nla_p_labels[] = {
520 	{ .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
521 };
522 NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
523 #undef _OUT
524 
525 static int
526 nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
527 {
528 	struct nl_parsed_labels parsed_labels = { };
529 	int error;
530 
531 	/* Assumes target points to the beginning of the structure */
532 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
533 	if (error != 0)
534 		return (error);
535 
536 	memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
537 
538 	return (0);
539 }
540 
541 static bool
542 nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
543 {
544 	int off = nlattr_add_nested(nw, attrtype);
545 	int i = 0;
546 
547 	while (r->label[i][0] != 0
548 	    && i < PF_RULE_MAX_LABEL_COUNT) {
549 		nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
550 		i++;
551 	}
552 
553 	nlattr_set_len(nw, off);
554 
555 	return (true);
556 }
557 
558 #define _OUT(_field)	offsetof(struct pf_kpool, _field)
559 static const struct nlattr_parser nla_p_pool[] = {
560 	{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
561 	{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
562 	{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
563 	{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
564 	{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
565 	{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
566 	{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
567 };
568 NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
569 #undef _OUT
570 
571 static bool
572 nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
573 {
574 	int off = nlattr_add_nested(nw, attrtype);
575 
576 	nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
577 	nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
578 	nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
579 	nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
580 	nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
581 	nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
582 	nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
583 
584 	nlattr_set_len(nw, off);
585 
586 	return (true);
587 }
588 
589 #define _OUT(_field)	offsetof(struct pf_rule_uid, _field)
590 static const struct nlattr_parser nla_p_rule_uid[] = {
591 	{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
592 	{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
593 	{ .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
594 };
595 NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
596 #undef _OUT
597 
598 static bool
599 nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
600 {
601 	int off = nlattr_add_nested(nw, attrtype);
602 
603 	nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
604 	nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
605 	nlattr_add_u8(nw, PF_RUT_OP, u->op);
606 
607 	nlattr_set_len(nw, off);
608 
609 	return (true);
610 }
611 
612 struct nl_parsed_timeouts
613 {
614 	uint32_t	timeouts[PFTM_MAX];
615 	uint32_t	i;
616 };
617 
618 static int
619 nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
620     const void *arg, void *target)
621 {
622 	struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
623 	int ret;
624 
625 	if (t->i >= PFTM_MAX)
626 		return (E2BIG);
627 
628 	ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
629 	if (ret == 0)
630 		t->i++;
631 
632 	return (ret);
633 }
634 
635 #define _OUT(_field)	offsetof(struct nl_parsed_timeout, _field)
636 static const struct nlattr_parser nla_p_timeouts[] = {
637 	{ .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
638 };
639 NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
640 #undef _OUT
641 
642 static int
643 nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
644 {
645 	struct nl_parsed_timeouts parsed_timeouts = { };
646 	int error;
647 
648 	/* Assumes target points to the beginning of the structure */
649 	error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
650 	if (error != 0)
651 		return (error);
652 
653 	memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
654 
655 	return (0);
656 }
657 
658 static bool
659 nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
660 {
661 	int off = nlattr_add_nested(nw, attrtype);
662 
663 	for (int i = 0; i < PFTM_MAX; i++)
664 		nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
665 
666 	nlattr_set_len(nw, off);
667 
668 	return (true);
669 }
670 
671 #define _OUT(_field)	offsetof(struct pf_krule, _field)
672 static const struct nlattr_parser nla_p_rule[] = {
673 	{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
674 	{ .type = PF_RT_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
675 	{ .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
676 	{ .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
677 	{ .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
678 	{ .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
679 	{ .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
680 	{ .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
681 	{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
682 	{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
683 	{ .type = PF_RT_RPOOL_RDR, .off = _OUT(rdr), .arg = &pool_parser, .cb = nlattr_get_nested },
684 	{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
685 	{ .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
686 	{ .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
687 	{ .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
688 	{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
689 	{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
690 	{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
691 	{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
692 	{ .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
693 	{ .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
694 	{ .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
695 	{ .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
696 	{ .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
697 	{ .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
698 	{. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
699 	{ .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
700 	{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
701 	{ .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
702 	{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
703 	{ .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
704 	{ .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
705 	{ .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
706 	{ .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
707 	{ .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
708 	{ .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
709 	{ .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
710 	{ .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
711 	{ .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
712 	{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
713 	{ .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
714 	{ .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
715 	{ .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
716 	{ .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
717 	{ .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
718 	{ .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
719 	{ .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
720 	{ .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
721 	{ .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
722 	{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
723 	{ .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
724 	{ .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
725 	{ .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
726 	{ .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
727 	{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
728 	{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
729 	{ .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
730 	{ .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
731 	{ .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
732 	{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
733 	{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
734 	{ .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
735 	{ .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
736 	{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(max_src_conn), .cb = nlattr_get_uint32 },
737 	{ .type = PF_RT_RPOOL_NAT, .off = _OUT(nat), .arg = &pool_parser, .cb = nlattr_get_nested },
738 	{ .type = PF_RT_NAF, .off = _OUT(naf), .cb = nlattr_get_uint8 },
739 };
740 NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
741 #undef _OUT
742 struct nl_parsed_addrule {
743 	struct pf_krule	*rule;
744 	uint32_t	 ticket;
745 	uint32_t	 pool_ticket;
746 	char		*anchor;
747 	char		*anchor_call;
748 };
749 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
750 #define	_OUT(_field)	offsetof(struct nl_parsed_addrule, _field)
751 static const struct nlattr_parser nla_p_addrule[] = {
752 	{ .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
753 	{ .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
754 	{ .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
755 	{ .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
756 	{ .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
757 };
758 static const struct nlfield_parser nlf_p_addrule[] = {
759 };
760 #undef _IN
761 #undef _OUT
762 NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_addrule, nla_p_addrule);
763 
764 static int
765 pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
766 {
767 	int error;
768 	struct nl_parsed_addrule attrs = {};
769 
770 	attrs.rule = pf_krule_alloc();
771 
772 	error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
773 	if (error != 0) {
774 		pf_free_rule(attrs.rule);
775 		return (error);
776 	}
777 
778 	error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
779 	    attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
780 	    hdr->nlmsg_pid);
781 
782 	return (error);
783 }
784 
785 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
786 #define	_OUT(_field)	offsetof(struct pfioc_rule, _field)
787 static const struct nlattr_parser nla_p_getrules[] = {
788 	{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
789 	{ .type = PF_GR_ACTION, .off = _OUT(rule.action), .cb = nlattr_get_uint8 },
790 };
791 static const struct nlfield_parser nlf_p_getrules[] = {
792 };
793 #undef _IN
794 #undef _OUT
795 NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
796 
797 static int
798 pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
799 {
800 	struct pfioc_rule attrs = {};
801 	int error;
802 	struct nl_writer *nw = npt->nw;
803 	struct genlmsghdr *ghdr_new;
804 
805 	error = nl_parse_nlmsg(hdr, &getrules_parser, npt, &attrs);
806 	if (error != 0)
807 		return (error);
808 
809 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
810 		return (ENOMEM);
811 
812 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
813 	ghdr_new->cmd = PFNL_CMD_GETRULES;
814 	ghdr_new->version = 0;
815 	ghdr_new->reserved = 0;
816 
817 	error = pf_ioctl_getrules(&attrs);
818 	if (error != 0)
819 		goto out;
820 
821 	nlattr_add_u32(nw, PF_GR_NR, attrs.nr);
822 	nlattr_add_u32(nw, PF_GR_TICKET, attrs.ticket);
823 
824 	if (!nlmsg_end(nw)) {
825 		error = ENOMEM;
826 		goto out;
827 	}
828 
829 	return (0);
830 
831 out:
832 	nlmsg_abort(nw);
833 	return (error);
834 }
835 
836 struct nl_parsed_get_rule {
837 	char anchor[MAXPATHLEN];
838 	uint8_t action;
839 	uint32_t nr;
840 	uint32_t ticket;
841 	uint8_t clear;
842 };
843 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
844 #define	_OUT(_field)	offsetof(struct nl_parsed_get_rule, _field)
845 static const struct nlattr_parser nla_p_getrule[] = {
846 	{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
847 	{ .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
848 	{ .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
849 	{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
850 	{ .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
851 };
852 static const struct nlfield_parser nlf_p_getrule[] = {
853 };
854 #undef _IN
855 #undef _OUT
856 NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_getrule, nla_p_getrule);
857 
858 static int
859 pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
860 {
861 	char				 anchor_call[MAXPATHLEN];
862 	struct nl_parsed_get_rule	 attrs = {};
863 	struct nl_writer		*nw = npt->nw;
864 	struct genlmsghdr		*ghdr_new;
865 	struct pf_kruleset		*ruleset;
866 	struct pf_krule			*rule;
867 	int				 rs_num;
868 	int				 error;
869 
870 	error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
871 	if (error != 0)
872 		return (error);
873 
874 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
875 		return (ENOMEM);
876 
877 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
878 	ghdr_new->cmd = PFNL_CMD_GETRULE;
879 	ghdr_new->version = 0;
880 	ghdr_new->reserved = 0;
881 
882 	PF_RULES_WLOCK();
883 	ruleset = pf_find_kruleset(attrs.anchor);
884 	if (ruleset == NULL) {
885 		PF_RULES_WUNLOCK();
886 		error = ENOENT;
887 		goto out;
888 	}
889 
890 	rs_num = pf_get_ruleset_number(attrs.action);
891 	if (rs_num >= PF_RULESET_MAX) {
892 		PF_RULES_WUNLOCK();
893 		error = EINVAL;
894 		goto out;
895 	}
896 
897 	if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
898 		PF_RULES_WUNLOCK();
899 		error = EBUSY;
900 		goto out;
901 	}
902 
903 	rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
904 	while ((rule != NULL) && (rule->nr != attrs.nr))
905 		rule = TAILQ_NEXT(rule, entries);
906 	if (rule == NULL) {
907 		PF_RULES_WUNLOCK();
908 		error = EBUSY;
909 		goto out;
910 	}
911 
912 	nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
913 	nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
914 	nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
915 	nlattr_add_labels(nw, PF_RT_LABELS, rule);
916 	nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
917 	nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
918 	nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
919 	nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
920 	nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
921 	nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
922 	nlattr_add_pool(nw, PF_RT_RPOOL_RDR, &rule->rdr);
923 	nlattr_add_pool(nw, PF_RT_RPOOL_NAT, &rule->nat);
924 	nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
925 	nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
926 	nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
927 	nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
928 	nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
929 	nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
930 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN, rule->max_src_conn);
931 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
932 	nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
933 
934 	nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
935 	nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
936 	nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
937 
938 	nlattr_add_u32(nw, PF_RT_NR, rule->nr);
939 	nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
940 	nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
941 	nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
942 
943 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
944 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
945 	nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
946 	nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
947 	nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
948 
949 	nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
950 	nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
951 
952 	nlattr_add_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
953 
954 	nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
955 	nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
956 	nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
957 	nlattr_add_u8(nw, PF_RT_LOG, rule->log);
958 	nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
959 	nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
960 	nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
961 	nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
962 	nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
963 	nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
964 
965 	nlattr_add_u8(nw, PF_RT_AF, rule->af);
966 	nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
967 	nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
968 	nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
969 	nlattr_add_u8(nw, PF_RT_CODE, rule->code);
970 	nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
971 	nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
972 	nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
973 	nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
974 	nlattr_add_u8(nw, PF_RT_RT, rule->rt);
975 	nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
976 	nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
977 	nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
978 	nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
979 	nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
980 	nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
981 	nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
982 	nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
983 	nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
984 
985 	nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
986 	nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
987 
988 	nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
989 	nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
990 	nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
991 	nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
992 	nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
993 	nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
994 	nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
995 	nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
996 	nlattr_add_u64(nw, PF_RT_SRC_NODES, counter_u64_fetch(rule->src_nodes));
997 
998 	error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
999 	MPASS(error == 0);
1000 
1001 	nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
1002 
1003 	if (attrs.clear)
1004 		pf_krule_clear_counters(rule);
1005 
1006 	PF_RULES_WUNLOCK();
1007 
1008 	if (!nlmsg_end(nw)) {
1009 		error = ENOMEM;
1010 		goto out;
1011 	}
1012 
1013 	return (0);
1014 out:
1015 	nlmsg_abort(nw);
1016 	return (error);
1017 }
1018 
1019 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
1020 #define	_OUT(_field)	offsetof(struct pf_kstate_kill, _field)
1021 static const struct nlattr_parser nla_p_clear_states[] = {
1022 	{ .type = PF_CS_CMP_ID, .off = _OUT(psk_pfcmp.id), .cb = nlattr_get_uint64 },
1023 	{ .type = PF_CS_CMP_CREATORID, .off = _OUT(psk_pfcmp.creatorid), .cb = nlattr_get_uint32 },
1024 	{ .type = PF_CS_CMP_DIR, .off = _OUT(psk_pfcmp.direction), .cb = nlattr_get_uint8 },
1025 	{ .type = PF_CS_AF, .off = _OUT(psk_af), .cb = nlattr_get_uint8 },
1026 	{ .type = PF_CS_PROTO, .off = _OUT(psk_proto), .cb = nlattr_get_uint8 },
1027 	{ .type = PF_CS_SRC, .off = _OUT(psk_src), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1028 	{ .type = PF_CS_DST, .off = _OUT(psk_dst), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1029 	{ .type = PF_CS_RT_ADDR, .off = _OUT(psk_rt_addr), .arg = &rule_addr_parser, .cb = nlattr_get_nested },
1030 	{ .type = PF_CS_IFNAME, .off = _OUT(psk_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
1031 	{ .type = PF_CS_LABEL, .off = _OUT(psk_label), .arg = (void *)PF_RULE_LABEL_SIZE, .cb = nlattr_get_chara },
1032 	{ .type = PF_CS_KILL_MATCH, .off = _OUT(psk_kill_match), .cb = nlattr_get_bool },
1033 	{ .type = PF_CS_NAT, .off = _OUT(psk_nat), .cb = nlattr_get_bool },
1034 };
1035 static const struct nlfield_parser nlf_p_clear_states[] = {};
1036 #undef _IN
1037 #undef _OUT
1038 NL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, nlf_p_clear_states, nla_p_clear_states);
1039 
1040 static int
1041 pf_handle_killclear_states(struct nlmsghdr *hdr, struct nl_pstate *npt, int cmd)
1042 {
1043 	struct pf_kstate_kill		 kill = {};
1044 	struct epoch_tracker		 et;
1045 	struct nl_writer		*nw = npt->nw;
1046 	struct genlmsghdr		*ghdr_new;
1047 	int				 error;
1048 	unsigned int			 killed = 0;
1049 
1050 	error = nl_parse_nlmsg(hdr, &clear_states_parser, npt, &kill);
1051 	if (error != 0)
1052 		return (error);
1053 
1054 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1055 		return (ENOMEM);
1056 
1057 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1058 	ghdr_new->cmd = cmd;
1059 	ghdr_new->version = 0;
1060 	ghdr_new->reserved = 0;
1061 
1062 	NET_EPOCH_ENTER(et);
1063 	if (cmd == PFNL_CMD_KILLSTATES)
1064 		pf_killstates(&kill, &killed);
1065 	else
1066 		killed = pf_clear_states(&kill);
1067 	NET_EPOCH_EXIT(et);
1068 
1069 	nlattr_add_u32(nw, PF_CS_KILLED, killed);
1070 
1071 	if (! nlmsg_end(nw)) {
1072 		error = ENOMEM;
1073 		goto out;
1074 	}
1075 
1076 	return (0);
1077 
1078 out:
1079 	nlmsg_abort(nw);
1080 	return (error);
1081 }
1082 
1083 static int
1084 pf_handle_clear_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1085 {
1086 	return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_CLRSTATES));
1087 }
1088 
1089 static int
1090 pf_handle_kill_states(struct nlmsghdr *hdr, struct nl_pstate *npt)
1091 {
1092 	return (pf_handle_killclear_states(hdr, npt, PFNL_CMD_KILLSTATES));
1093 }
1094 
1095 struct nl_parsed_set_statusif {
1096 	char ifname[IFNAMSIZ];
1097 };
1098 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
1099 #define	_OUT(_field)	offsetof(struct nl_parsed_set_statusif, _field)
1100 static const struct nlattr_parser nla_p_set_statusif[] = {
1101 	{ .type = PF_SS_IFNAME, .off = _OUT(ifname), .arg = (const void *)IFNAMSIZ, .cb = nlattr_get_chara },
1102 };
1103 static const struct nlfield_parser nlf_p_set_statusif[] = {};
1104 #undef _IN
1105 #undef _OUT
1106 NL_DECLARE_PARSER(set_statusif_parser, struct genlmsghdr, nlf_p_set_statusif, nla_p_set_statusif);
1107 
1108 static int
1109 pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
1110 {
1111 	int error;
1112 	struct nl_parsed_set_statusif attrs = {};
1113 
1114 	error = nl_parse_nlmsg(hdr, &set_statusif_parser, npt, &attrs);
1115 	if (error != 0)
1116 		return (error);
1117 
1118 	PF_RULES_WLOCK();
1119 	strlcpy(V_pf_status.ifname, attrs.ifname, IFNAMSIZ);
1120 	PF_RULES_WUNLOCK();
1121 
1122 	return (0);
1123 }
1124 
1125 static bool
1126 nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
1127     counter_u64_t *counters)
1128 {
1129 	for (int i = 0; i < number; i++) {
1130 		int off = nlattr_add_nested(nw, attr);
1131 		nlattr_add_u32(nw, PF_C_ID, i);
1132 		nlattr_add_string(nw, PF_C_NAME, names[i]);
1133 		nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
1134 		nlattr_set_len(nw, off);
1135 	}
1136 
1137 	return (true);
1138 }
1139 
1140 static bool
1141 nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
1142     struct pf_counter_u64 *counters)
1143 {
1144 	for (int i = 0; i < number; i++) {
1145 		int off = nlattr_add_nested(nw, attr);
1146 		nlattr_add_u32(nw, PF_C_ID, i);
1147 		nlattr_add_string(nw, PF_C_NAME, names[i]);
1148 		nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
1149 		nlattr_set_len(nw, off);
1150 	}
1151 
1152 	return (true);
1153 }
1154 
1155 static bool
1156 nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
1157 {
1158 	int off = nlattr_add_nested(nw, attr);
1159 
1160 	for (size_t i = 0; i < number; i++)
1161 		nlattr_add_u64(nw, 0, array[i]);
1162 
1163 	nlattr_set_len(nw, off);
1164 
1165 	return (true);
1166 }
1167 
1168 static int
1169 pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1170 {
1171 	struct pf_status s;
1172 	struct nl_writer *nw = npt->nw;
1173 	struct genlmsghdr *ghdr_new;
1174 	char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
1175 	char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
1176 	char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
1177 	int error;
1178 
1179 	PF_RULES_RLOCK_TRACKER;
1180 
1181 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1182 		return (ENOMEM);
1183 
1184 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1185 	ghdr_new->cmd = PFNL_CMD_GET_STATUS;
1186 	ghdr_new->version = 0;
1187 	ghdr_new->reserved = 0;
1188 
1189 	PF_RULES_RLOCK();
1190 
1191 	nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
1192 	nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
1193 	nlattr_add_u32(nw, PF_GS_SINCE, V_pf_status.since);
1194 	nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
1195 	nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
1196 	nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
1197 	nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
1198 	nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
1199 	nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
1200 
1201 	nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
1202 	    V_pf_status.counters);
1203 	nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
1204 	    V_pf_status.lcounters);
1205 	nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
1206 	    V_pf_status.fcounters);
1207 	nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
1208 	    V_pf_status.scounters);
1209 
1210 	pfi_update_status(V_pf_status.ifname, &s);
1211 	nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
1212 	nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
1213 
1214 	nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
1215 
1216 	PF_RULES_RUNLOCK();
1217 
1218 	if (!nlmsg_end(nw)) {
1219 		error = ENOMEM;
1220 		goto out;
1221 	}
1222 
1223 	return (0);
1224 
1225 out:
1226 	nlmsg_abort(nw);
1227 	return (error);
1228 }
1229 
1230 static int
1231 pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
1232 {
1233 	pf_ioctl_clear_status();
1234 
1235 	return (0);
1236 }
1237 
1238 struct pf_nl_natlook {
1239 	sa_family_t af;
1240 	uint8_t direction;
1241 	uint8_t proto;
1242 	struct pf_addr src;
1243 	struct pf_addr dst;
1244 	uint16_t sport;
1245 	uint16_t dport;
1246 };
1247 
1248 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
1249 #define	_OUT(_field)	offsetof(struct pf_nl_natlook, _field)
1250 static const struct nlattr_parser nla_p_natlook[] = {
1251 	{ .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
1252 	{ .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
1253 	{ .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
1254 	{ .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
1255 	{ .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
1256 	{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
1257 	{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
1258 };
1259 static const struct nlfield_parser nlf_p_natlook[] = {};
1260 #undef _IN
1261 #undef _OUT
1262 NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_natlook, nla_p_natlook);
1263 
1264 static int
1265 pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
1266 {
1267 	struct pf_nl_natlook	 attrs = {};
1268 	struct pf_state_key_cmp	 key = {};
1269 	struct nl_writer	*nw = npt->nw;
1270 	struct pf_state_key	*sk;
1271 	struct pf_kstate	*state;
1272 	struct genlmsghdr	*ghdr_new;
1273 	int			 error, m = 0;
1274 	int			 sidx, didx;
1275 
1276 	error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
1277 	if (error != 0)
1278 		return (error);
1279 
1280 	if (attrs.proto == 0 ||
1281 	    PF_AZERO(&attrs.src, attrs.af) ||
1282 	    PF_AZERO(&attrs.dst, attrs.af) ||
1283 	    ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
1284 	     (attrs.sport == 0 || attrs.dport == 0)))
1285 		return (EINVAL);
1286 
1287 	/* NATLOOK src and dst are reversed, so reverse sidx/didx */
1288 	sidx = (attrs.direction == PF_IN) ? 1 : 0;
1289 	didx = (attrs.direction == PF_IN) ? 0 : 1;
1290 
1291 	key.af = attrs.af;
1292 	key.proto = attrs.proto;
1293 	PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af);
1294 	key.port[sidx] = attrs.sport;
1295 	PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af);
1296 	key.port[didx] = attrs.dport;
1297 
1298 	state = pf_find_state_all(&key, attrs.direction, &m);
1299 	if (state == NULL)
1300 		return (ENOENT);
1301 	if (m > 1) {
1302 		PF_STATE_UNLOCK(state);
1303 		return (E2BIG);
1304 	}
1305 
1306 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1307 		PF_STATE_UNLOCK(state);
1308 		return (ENOMEM);
1309 	}
1310 
1311 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1312 	ghdr_new->cmd = PFNL_CMD_NATLOOK;
1313 	ghdr_new->version = 0;
1314 	ghdr_new->reserved = 0;
1315 
1316 	sk = state->key[sidx];
1317 
1318 	nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
1319 	nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
1320 	nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
1321 	nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
1322 
1323 	PF_STATE_UNLOCK(state);
1324 
1325 	if (!nlmsg_end(nw)) {
1326 		nlmsg_abort(nw);
1327 		return (ENOMEM);
1328 	}
1329 
1330 	return (0);
1331 }
1332 
1333 struct pf_nl_set_debug
1334 {
1335 	uint32_t level;
1336 };
1337 #define	_OUT(_field)	offsetof(struct pf_nl_set_debug, _field)
1338 static const struct nlattr_parser nla_p_set_debug[] = {
1339 	{ .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
1340 };
1341 static const struct nlfield_parser nlf_p_set_debug[] = {};
1342 #undef _OUT
1343 NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_set_debug, nla_p_set_debug);
1344 
1345 static int
1346 pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
1347 {
1348 	struct pf_nl_set_debug attrs = {};
1349 	int error;
1350 
1351 	error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
1352 	if (error != 0)
1353 		return (error);
1354 
1355 	PF_RULES_WLOCK();
1356 	V_pf_status.debug = attrs.level;
1357 	PF_RULES_WUNLOCK();
1358 
1359 	return (0);
1360 }
1361 
1362 struct pf_nl_set_timeout
1363 {
1364 	uint32_t timeout;
1365 	uint32_t seconds;
1366 };
1367 #define	_OUT(_field)	offsetof(struct pf_nl_set_timeout, _field)
1368 static const struct nlattr_parser nla_p_set_timeout[] = {
1369 	{ .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
1370 	{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
1371 };
1372 static const struct nlfield_parser nlf_p_set_timeout[] = {};
1373 #undef _OUT
1374 NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_set_timeout, nla_p_set_timeout);
1375 
1376 static int
1377 pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1378 {
1379 	struct pf_nl_set_timeout attrs = {};
1380 	int error;
1381 
1382 	error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1383 	if (error != 0)
1384 		return (error);
1385 
1386 	return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
1387 }
1388 
1389 static int
1390 pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
1391 {
1392 	struct pf_nl_set_timeout attrs = {};
1393 	struct nl_writer *nw = npt->nw;
1394 	struct genlmsghdr *ghdr_new;
1395 	int error;
1396 
1397 	error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
1398 	if (error != 0)
1399 		return (error);
1400 
1401 	error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
1402 	if (error != 0)
1403 		return (error);
1404 
1405 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1406 		return (ENOMEM);
1407 
1408 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1409 	ghdr_new->cmd = PFNL_CMD_GET_TIMEOUT;
1410 	ghdr_new->version = 0;
1411 	ghdr_new->reserved = 0;
1412 
1413 	nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
1414 
1415 	if (!nlmsg_end(nw)) {
1416 		nlmsg_abort(nw);
1417 		return (ENOMEM);
1418 	}
1419 
1420 	return (0);
1421 }
1422 
1423 struct pf_nl_set_limit
1424 {
1425 	uint32_t index;
1426 	uint32_t limit;
1427 };
1428 #define	_OUT(_field)	offsetof(struct pf_nl_set_limit, _field)
1429 static const struct nlattr_parser nla_p_set_limit[] = {
1430 	{ .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
1431 	{ .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
1432 };
1433 static const struct nlfield_parser nlf_p_set_limit[] = {};
1434 #undef _OUT
1435 NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_set_limit, 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 static const struct nlfield_parser nlf_p_add_addr[] = {};
1551 #undef _OUT
1552 NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_add_addr, nla_p_add_addr);
1553 
1554 static int
1555 pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1556 {
1557 	struct pf_nl_pooladdr attrs = { 0 };
1558 	int error;
1559 
1560 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1561 	if (error != 0)
1562 		return (error);
1563 
1564 	if (attrs.which == 0)
1565 		attrs.which = PF_RDR;
1566 
1567 	error = pf_ioctl_add_addr(&attrs);
1568 
1569 	return (error);
1570 }
1571 
1572 static int
1573 pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
1574 {
1575 	struct pf_nl_pooladdr attrs = { 0 };
1576 	struct nl_writer *nw = npt->nw;
1577 	struct genlmsghdr *ghdr_new;
1578 	int error;
1579 
1580 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1581 	if (error != 0)
1582 		return (error);
1583 
1584 	if (attrs.which == 0)
1585 		attrs.which = PF_RDR;
1586 
1587 	error = pf_ioctl_get_addrs(&attrs);
1588 	if (error != 0)
1589 		return (error);
1590 
1591 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1592 		return (ENOMEM);
1593 
1594 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1595 	ghdr_new->cmd = PFNL_CMD_GET_ADDRS;
1596 	ghdr_new->version = 0;
1597 	ghdr_new->reserved = 0;
1598 
1599 	nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1600 
1601 	if (!nlmsg_end(nw)) {
1602 		nlmsg_abort(nw);
1603 		return (ENOMEM);
1604 	}
1605 
1606 	return (error);
1607 }
1608 
1609 static int
1610 pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
1611 {
1612 	struct pf_nl_pooladdr attrs = { 0 };
1613 	struct nl_writer *nw = npt->nw;
1614 	struct genlmsghdr *ghdr_new;
1615 	int error;
1616 
1617 	error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
1618 	if (error != 0)
1619 		return (error);
1620 
1621 	if (attrs.which == 0)
1622 		attrs.which = PF_RDR;
1623 
1624 	error = pf_ioctl_get_addr(&attrs);
1625 	if (error != 0)
1626 		return (error);
1627 
1628 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1629 		return (ENOMEM);
1630 
1631 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1632 	ghdr_new->cmd = PFNL_CMD_GET_ADDR;
1633 	ghdr_new->version = 0;
1634 	ghdr_new->reserved = 0;
1635 
1636 	nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
1637 	nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
1638 	nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
1639 	nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
1640 	nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
1641 	nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
1642 	nlattr_add_u8(nw, PF_AA_AF, attrs.af);
1643 	nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
1644 	nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);
1645 
1646 	if (!nlmsg_end(nw)) {
1647 		nlmsg_abort(nw);
1648 		return (ENOMEM);
1649 	}
1650 
1651 	return (0);
1652 }
1653 
1654 #define _OUT(_field)	offsetof(struct pfioc_ruleset, _field)
1655 static const struct nlattr_parser nla_p_ruleset[] = {
1656 	{ .type = PF_RS_PATH, .off = _OUT(path), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
1657 	{ .type = PF_RS_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
1658 };
1659 static const struct nlfield_parser nlf_p_ruleset[] = {
1660 };
1661 NL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, nlf_p_ruleset, nla_p_ruleset);
1662 #undef _OUT
1663 
1664 static int
1665 pf_handle_get_rulesets(struct nlmsghdr *hdr, struct nl_pstate *npt)
1666 {
1667 	struct pfioc_ruleset attrs = { 0 };
1668 	struct nl_writer *nw = npt->nw;
1669 	struct genlmsghdr *ghdr_new;
1670 	int error;
1671 
1672 	error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1673 	if (error != 0)
1674 		return (error);
1675 
1676 	error = pf_ioctl_get_rulesets(&attrs);
1677 	if (error != 0)
1678 		return (error);
1679 
1680 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1681 		return (ENOMEM);
1682 
1683 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1684 	ghdr_new->cmd = PFNL_CMD_GET_RULESETS;
1685 	ghdr_new->version = 0;
1686 	ghdr_new->reserved = 0;
1687 
1688 	nlattr_add_u32(nw, PF_RS_NR, attrs.nr);
1689 
1690 	if (!nlmsg_end(nw)) {
1691 		nlmsg_abort(nw);
1692 		return (ENOMEM);
1693 	}
1694 
1695 	return (0);
1696 }
1697 
1698 static int
1699 pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt)
1700 {
1701 	struct pfioc_ruleset attrs = { 0 };
1702 	struct nl_writer *nw = npt->nw;
1703 	struct genlmsghdr *ghdr_new;
1704 	int error;
1705 
1706 	error = nl_parse_nlmsg(hdr, &ruleset_parser, npt, &attrs);
1707 	if (error)
1708 		return (error);
1709 
1710 	error = pf_ioctl_get_ruleset(&attrs);
1711 	if (error != 0)
1712 		return (error);
1713 
1714 	if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
1715 		return (ENOMEM);
1716 
1717 	ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1718 	ghdr_new->cmd = PFNL_CMD_GET_RULESET;
1719 	ghdr_new->version = 0;
1720 	ghdr_new->reserved = 0;
1721 
1722 	nlattr_add_string(nw, PF_RS_NAME, attrs.name);
1723 
1724 	if (!nlmsg_end(nw)) {
1725 		nlmsg_abort(nw);
1726 		return (ENOMEM);
1727 	}
1728 
1729 	return (0);
1730 }
1731 
1732 static bool
1733 nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype,
1734     struct pf_threshold *t, int secs)
1735 {
1736 	int	 off = nlattr_add_nested(nw, attrtype);
1737 	int	 diff, conn_rate_count;
1738 
1739 	/* Adjust the connection rate estimate. */
1740 	conn_rate_count = t->count;
1741 	diff = secs - t->last;
1742 	if (diff >= t->seconds)
1743 		conn_rate_count = 0;
1744 	else
1745 		conn_rate_count -= t->count * diff / t->seconds;
1746 
1747 	nlattr_add_u32(nw, PF_TH_LIMIT, t->limit);
1748 	nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds);
1749 	nlattr_add_u32(nw, PF_TH_COUNT, conn_rate_count);
1750 	nlattr_add_u32(nw, PF_TH_LAST, t->last);
1751 
1752 	nlattr_set_len(nw, off);
1753 
1754 	return (true);
1755 }
1756 
1757 static int
1758 pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt)
1759 {
1760 	struct nl_writer	*nw = npt->nw;
1761 	struct genlmsghdr	*ghdr_new;
1762 	struct pf_ksrc_node	*n;
1763 	struct pf_srchash	*sh;
1764 	int			 i;
1765 	int			 secs;
1766 
1767 	hdr->nlmsg_flags |= NLM_F_MULTI;
1768 
1769 	for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
1770 	    i++, sh++) {
1771 		/* Avoid locking empty rows. */
1772 		if (LIST_EMPTY(&sh->nodes))
1773 			continue;
1774 
1775 		PF_HASHROW_LOCK(sh);
1776 		secs = time_uptime;
1777 
1778 		LIST_FOREACH(n, &sh->nodes, entry) {
1779 			if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
1780 				nlmsg_abort(nw);
1781 				return (ENOMEM);
1782 			}
1783 
1784 			ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
1785 			ghdr_new->cmd = PFNL_CMD_GET_SRCNODES;
1786 			ghdr_new->version = 0;
1787 			ghdr_new->reserved = 0;
1788 
1789 			nlattr_add_in6_addr(nw, PF_SN_ADDR, &n->addr.v6);
1790 			nlattr_add_in6_addr(nw, PF_SN_RADDR, &n->raddr.v6);
1791 			nlattr_add_u32(nw, PF_SN_RULE_NR, n->rule->nr);
1792 			nlattr_add_u64(nw, PF_SN_BYTES_IN, counter_u64_fetch(n->bytes[0]));
1793 			nlattr_add_u64(nw, PF_SN_BYTES_OUT, counter_u64_fetch(n->bytes[1]));
1794 			nlattr_add_u64(nw, PF_SN_PACKETS_IN, counter_u64_fetch(n->packets[0]));
1795 			nlattr_add_u64(nw, PF_SN_PACKETS_OUT, counter_u64_fetch(n->packets[1]));
1796 			nlattr_add_u32(nw, PF_SN_STATES, n->states);
1797 			nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
1798 			nlattr_add_u8(nw, PF_SN_AF, n->af);
1799 			nlattr_add_u8(nw, PF_SN_NAF, n->naf);
1800 			nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
1801 
1802 			nlattr_add_u64(nw, PF_SN_CREATION, secs - n->creation);
1803 			if (n->expire > secs)
1804 				nlattr_add_u64(nw, PF_SN_EXPIRE, n->expire - secs);
1805 			else
1806 				nlattr_add_u64(nw, PF_SN_EXPIRE, 0);
1807 
1808 			nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE,
1809 			    &n->conn_rate, secs);
1810 
1811 			if (!nlmsg_end(nw)) {
1812 				PF_HASHROW_UNLOCK(sh);
1813 				nlmsg_abort(nw);
1814 				return (ENOMEM);
1815 			}
1816 		}
1817 		PF_HASHROW_UNLOCK(sh);
1818 	}
1819 
1820 	return (0);
1821 }
1822 
1823 static const struct nlhdr_parser *all_parsers[] = {
1824 	&state_parser,
1825 	&addrule_parser,
1826 	&getrules_parser,
1827 	&clear_states_parser,
1828 	&set_statusif_parser,
1829 	&natlook_parser,
1830 	&set_debug_parser,
1831 	&set_timeout_parser,
1832 	&set_limit_parser,
1833 	&pool_addr_parser,
1834 	&add_addr_parser,
1835 	&ruleset_parser,
1836 };
1837 
1838 static int family_id;
1839 
1840 static const struct genl_cmd pf_cmds[] = {
1841 	{
1842 		.cmd_num = PFNL_CMD_GETSTATES,
1843 		.cmd_name = "GETSTATES",
1844 		.cmd_cb = pf_handle_getstates,
1845 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1846 		.cmd_priv = PRIV_NETINET_PF,
1847 	},
1848 	{
1849 		.cmd_num = PFNL_CMD_GETCREATORS,
1850 		.cmd_name = "GETCREATORS",
1851 		.cmd_cb = pf_handle_getcreators,
1852 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1853 		.cmd_priv = PRIV_NETINET_PF,
1854 	},
1855 	{
1856 		.cmd_num = PFNL_CMD_START,
1857 		.cmd_name = "START",
1858 		.cmd_cb = pf_handle_start,
1859 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1860 		.cmd_priv = PRIV_NETINET_PF,
1861 	},
1862 	{
1863 		.cmd_num = PFNL_CMD_STOP,
1864 		.cmd_name = "STOP",
1865 		.cmd_cb = pf_handle_stop,
1866 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1867 		.cmd_priv = PRIV_NETINET_PF,
1868 	},
1869 	{
1870 		.cmd_num = PFNL_CMD_ADDRULE,
1871 		.cmd_name = "ADDRULE",
1872 		.cmd_cb = pf_handle_addrule,
1873 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1874 		.cmd_priv = PRIV_NETINET_PF,
1875 	},
1876 	{
1877 		.cmd_num = PFNL_CMD_GETRULES,
1878 		.cmd_name = "GETRULES",
1879 		.cmd_cb = pf_handle_getrules,
1880 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1881 		.cmd_priv = PRIV_NETINET_PF,
1882 	},
1883 	{
1884 		.cmd_num = PFNL_CMD_GETRULE,
1885 		.cmd_name = "GETRULE",
1886 		.cmd_cb = pf_handle_getrule,
1887 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1888 		.cmd_priv = PRIV_NETINET_PF,
1889 	},
1890 	{
1891 		.cmd_num = PFNL_CMD_CLRSTATES,
1892 		.cmd_name = "CLRSTATES",
1893 		.cmd_cb = pf_handle_clear_states,
1894 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1895 		.cmd_priv = PRIV_NETINET_PF,
1896 	},
1897 	{
1898 		.cmd_num = PFNL_CMD_KILLSTATES,
1899 		.cmd_name = "KILLSTATES",
1900 		.cmd_cb = pf_handle_kill_states,
1901 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1902 		.cmd_priv = PRIV_NETINET_PF,
1903 	},
1904 	{
1905 		.cmd_num = PFNL_CMD_SET_STATUSIF,
1906 		.cmd_name = "SETSTATUSIF",
1907 		.cmd_cb = pf_handle_set_statusif,
1908 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1909 		.cmd_priv = PRIV_NETINET_PF,
1910 	},
1911 	{
1912 		.cmd_num = PFNL_CMD_GET_STATUS,
1913 		.cmd_name = "GETSTATUS",
1914 		.cmd_cb = pf_handle_get_status,
1915 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1916 		.cmd_priv = PRIV_NETINET_PF,
1917 	},
1918 	{
1919 		.cmd_num = PFNL_CMD_CLEAR_STATUS,
1920 		.cmd_name = "CLEARSTATUS",
1921 		.cmd_cb = pf_handle_clear_status,
1922 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1923 		.cmd_priv = PRIV_NETINET_PF,
1924 	},
1925 	{
1926 		.cmd_num = PFNL_CMD_NATLOOK,
1927 		.cmd_name = "NATLOOK",
1928 		.cmd_cb = pf_handle_natlook,
1929 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1930 		.cmd_priv = PRIV_NETINET_PF,
1931 	},
1932 	{
1933 		.cmd_num = PFNL_CMD_SET_DEBUG,
1934 		.cmd_name = "SET_DEBUG",
1935 		.cmd_cb = pf_handle_set_debug,
1936 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1937 		.cmd_priv = PRIV_NETINET_PF,
1938 	},
1939 	{
1940 		.cmd_num = PFNL_CMD_SET_TIMEOUT,
1941 		.cmd_name = "SET_TIMEOUT",
1942 		.cmd_cb = pf_handle_set_timeout,
1943 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1944 		.cmd_priv = PRIV_NETINET_PF,
1945 	},
1946 	{
1947 		.cmd_num = PFNL_CMD_GET_TIMEOUT,
1948 		.cmd_name = "GET_TIMEOUT",
1949 		.cmd_cb = pf_handle_get_timeout,
1950 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1951 		.cmd_priv = PRIV_NETINET_PF,
1952 	},
1953 	{
1954 		.cmd_num = PFNL_CMD_SET_LIMIT,
1955 		.cmd_name = "SET_LIMIT",
1956 		.cmd_cb = pf_handle_set_limit,
1957 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1958 		.cmd_priv = PRIV_NETINET_PF,
1959 	},
1960 	{
1961 		.cmd_num = PFNL_CMD_GET_LIMIT,
1962 		.cmd_name = "GET_LIMIT",
1963 		.cmd_cb = pf_handle_get_limit,
1964 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1965 		.cmd_priv = PRIV_NETINET_PF,
1966 	},
1967 	{
1968 		.cmd_num = PFNL_CMD_BEGIN_ADDRS,
1969 		.cmd_name = "BEGIN_ADDRS",
1970 		.cmd_cb = pf_handle_begin_addrs,
1971 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1972 		.cmd_priv = PRIV_NETINET_PF,
1973 	},
1974 	{
1975 		.cmd_num = PFNL_CMD_ADD_ADDR,
1976 		.cmd_name = "ADD_ADDR",
1977 		.cmd_cb = pf_handle_add_addr,
1978 		.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
1979 		.cmd_priv = PRIV_NETINET_PF,
1980 	},
1981 	{
1982 		.cmd_num = PFNL_CMD_GET_ADDRS,
1983 		.cmd_name = "GET_ADDRS",
1984 		.cmd_cb = pf_handle_get_addrs,
1985 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1986 		.cmd_priv = PRIV_NETINET_PF,
1987 	},
1988 	{
1989 		.cmd_num = PFNL_CMD_GET_ADDR,
1990 		.cmd_name = "GET_ADDRS",
1991 		.cmd_cb = pf_handle_get_addr,
1992 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
1993 		.cmd_priv = PRIV_NETINET_PF,
1994 	},
1995 	{
1996 		.cmd_num = PFNL_CMD_GET_RULESETS,
1997 		.cmd_name = "GET_RULESETS",
1998 		.cmd_cb = pf_handle_get_rulesets,
1999 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2000 		.cmd_priv = PRIV_NETINET_PF,
2001 	},
2002 	{
2003 		.cmd_num = PFNL_CMD_GET_RULESET,
2004 		.cmd_name = "GET_RULESET",
2005 		.cmd_cb = pf_handle_get_ruleset,
2006 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2007 		.cmd_priv = PRIV_NETINET_PF,
2008 	},
2009 	{
2010 		.cmd_num = PFNL_CMD_GET_SRCNODES,
2011 		.cmd_name = "GET_SRCNODES",
2012 		.cmd_cb = pf_handle_get_srcnodes,
2013 		.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
2014 		.cmd_priv = PRIV_NETINET_PF,
2015 	},
2016 };
2017 
2018 void
2019 pf_nl_register(void)
2020 {
2021 	NL_VERIFY_PARSERS(all_parsers);
2022 
2023 	family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
2024 	genl_register_cmds(PFNL_FAMILY_NAME, pf_cmds, nitems(pf_cmds));
2025 }
2026 
2027 void
2028 pf_nl_unregister(void)
2029 {
2030 	genl_unregister_family(PFNL_FAMILY_NAME);
2031 }
2032