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