xref: /src/lib/libpfctl/libpfctl.c (revision 281282e9357b95b679d36ca6d8561e96c1263937)
10d6c8174SKristof Provost /*-
20d6c8174SKristof Provost  * SPDX-License-Identifier: BSD-2-Clause
30d6c8174SKristof Provost  *
40d6c8174SKristof Provost  * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
50d6c8174SKristof Provost  * All rights reserved.
60d6c8174SKristof Provost  *
70d6c8174SKristof Provost  * Redistribution and use in source and binary forms, with or without
80d6c8174SKristof Provost  * modification, are permitted provided that the following conditions
90d6c8174SKristof Provost  * are met:
100d6c8174SKristof Provost  *
110d6c8174SKristof Provost  *    - Redistributions of source code must retain the above copyright
120d6c8174SKristof Provost  *      notice, this list of conditions and the following disclaimer.
130d6c8174SKristof Provost  *    - Redistributions in binary form must reproduce the above
140d6c8174SKristof Provost  *      copyright notice, this list of conditions and the following
150d6c8174SKristof Provost  *      disclaimer in the documentation and/or other materials provided
160d6c8174SKristof Provost  *      with the distribution.
170d6c8174SKristof Provost  *
180d6c8174SKristof Provost  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
190d6c8174SKristof Provost  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
200d6c8174SKristof Provost  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
210d6c8174SKristof Provost  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
220d6c8174SKristof Provost  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
230d6c8174SKristof Provost  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
240d6c8174SKristof Provost  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
250d6c8174SKristof Provost  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
260d6c8174SKristof Provost  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
270d6c8174SKristof Provost  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
280d6c8174SKristof Provost  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290d6c8174SKristof Provost  * POSSIBILITY OF SUCH DAMAGE.
300d6c8174SKristof Provost  */
310d6c8174SKristof Provost 
320d6c8174SKristof Provost #include <sys/cdefs.h>
330d6c8174SKristof Provost 
340d6c8174SKristof Provost #include <sys/ioctl.h>
350d6c8174SKristof Provost #include <sys/nv.h>
360d6c8174SKristof Provost #include <sys/queue.h>
370d6c8174SKristof Provost #include <sys/types.h>
380d6c8174SKristof Provost 
390d6c8174SKristof Provost #include <net/if.h>
400d6c8174SKristof Provost #include <net/pfvar.h>
410d6c8174SKristof Provost #include <netinet/in.h>
420d6c8174SKristof Provost 
432cef6288SAlexander V. Chernikov #include <netpfil/pf/pf_nl.h>
442cef6288SAlexander V. Chernikov #include <netlink/netlink.h>
452cef6288SAlexander V. Chernikov #include <netlink/netlink_generic.h>
462cef6288SAlexander V. Chernikov #include <netlink/netlink_snl.h>
472cef6288SAlexander V. Chernikov #include <netlink/netlink_snl_generic.h>
482cef6288SAlexander V. Chernikov #include <netlink/netlink_snl_route.h>
492cef6288SAlexander V. Chernikov 
500d6c8174SKristof Provost #include <assert.h>
510d6c8174SKristof Provost #include <err.h>
520d6c8174SKristof Provost #include <errno.h>
5366cacc14SKristof Provost #include <fcntl.h>
540d6c8174SKristof Provost #include <stdlib.h>
550d6c8174SKristof Provost #include <string.h>
560d6c8174SKristof Provost 
570d71f9f3SKristof Provost #include "libpfctl.h"
580d6c8174SKristof Provost 
5966cacc14SKristof Provost struct pfctl_handle {
6066cacc14SKristof Provost 	int fd;
6166cacc14SKristof Provost 	struct snl_state ss;
6266cacc14SKristof Provost };
6366cacc14SKristof Provost 
645062afffSKristof Provost const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = {
655062afffSKristof Provost 	"never",
665062afffSKristof Provost 	"always",
675062afffSKristof Provost 	"adaptive"
685062afffSKristof Provost };
695062afffSKristof Provost 
702a00c4dbSKristof Provost static int	_pfctl_clear_states(int , const struct pfctl_kill *,
712a00c4dbSKristof Provost 		    unsigned int *, uint64_t);
721e7665e3SKristof Provost static void	_pfctl_verify_parsers(void);
732a00c4dbSKristof Provost 
7466cacc14SKristof Provost struct pfctl_handle *
pfctl_open(const char * pf_device)7566cacc14SKristof Provost pfctl_open(const char *pf_device)
7666cacc14SKristof Provost {
7766cacc14SKristof Provost 	struct pfctl_handle *h;
7866cacc14SKristof Provost 
791e7665e3SKristof Provost 	_pfctl_verify_parsers();
801e7665e3SKristof Provost 
8166cacc14SKristof Provost 	h = calloc(1, sizeof(struct pfctl_handle));
8266cacc14SKristof Provost 
8366cacc14SKristof Provost 	h->fd = open(pf_device, O_RDWR);
8466cacc14SKristof Provost 	if (h->fd < 0)
8566cacc14SKristof Provost 		goto error;
8666cacc14SKristof Provost 
8766cacc14SKristof Provost 	if (!snl_init(&h->ss, NETLINK_GENERIC))
8866cacc14SKristof Provost 		goto error;
8966cacc14SKristof Provost 
9066cacc14SKristof Provost 	return (h);
9166cacc14SKristof Provost error:
92238ad591SKristof Provost 	if (h->fd != -1)
9366cacc14SKristof Provost 		close(h->fd);
9466cacc14SKristof Provost 	snl_free(&h->ss);
9566cacc14SKristof Provost 	free(h);
9666cacc14SKristof Provost 
9766cacc14SKristof Provost 	return (NULL);
9866cacc14SKristof Provost }
9966cacc14SKristof Provost 
10066cacc14SKristof Provost void
pfctl_close(struct pfctl_handle * h)10166cacc14SKristof Provost pfctl_close(struct pfctl_handle *h)
10266cacc14SKristof Provost {
10366cacc14SKristof Provost 	close(h->fd);
10466cacc14SKristof Provost 	snl_free(&h->ss);
10566cacc14SKristof Provost 	free(h);
10666cacc14SKristof Provost }
10766cacc14SKristof Provost 
108044243fcSKristof Provost int
pfctl_fd(struct pfctl_handle * h)109044243fcSKristof Provost pfctl_fd(struct pfctl_handle *h)
110044243fcSKristof Provost {
111044243fcSKristof Provost 	return (h->fd);
112044243fcSKristof Provost }
113044243fcSKristof Provost 
1147ed19f5cSKristof Provost static int
pfctl_do_netlink_cmd(struct pfctl_handle * h,uint cmd)1159dbbe68bSKristof Provost pfctl_do_netlink_cmd(struct pfctl_handle *h, uint cmd)
1169dbbe68bSKristof Provost {
1179dbbe68bSKristof Provost 	struct snl_errmsg_data e = {};
1189dbbe68bSKristof Provost 	struct snl_writer nw;
1199dbbe68bSKristof Provost 	struct nlmsghdr *hdr;
1209dbbe68bSKristof Provost 	uint32_t seq_id;
1219dbbe68bSKristof Provost 	int family_id;
1229dbbe68bSKristof Provost 
1239dbbe68bSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
1249dbbe68bSKristof Provost 	if (family_id == 0)
1259dbbe68bSKristof Provost 		return (ENOTSUP);
1269dbbe68bSKristof Provost 
1279dbbe68bSKristof Provost 	snl_init_writer(&h->ss, &nw);
1289dbbe68bSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, cmd);
1299dbbe68bSKristof Provost 
1309dbbe68bSKristof Provost 	hdr = snl_finalize_msg(&nw);
1319dbbe68bSKristof Provost 	if (hdr == NULL)
1329dbbe68bSKristof Provost 		return (ENOMEM);
1339dbbe68bSKristof Provost 	seq_id = hdr->nlmsg_seq;
1349dbbe68bSKristof Provost 
1359dbbe68bSKristof Provost 	snl_send_message(&h->ss, hdr);
1369dbbe68bSKristof Provost 
1379dbbe68bSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1389dbbe68bSKristof Provost 	}
1399dbbe68bSKristof Provost 
1409dbbe68bSKristof Provost 	return (e.error);
1419dbbe68bSKristof Provost }
1429dbbe68bSKristof Provost 
1439dbbe68bSKristof Provost static int
pfctl_do_ioctl(int dev,uint cmd,size_t size,nvlist_t ** nvl)1447ed19f5cSKristof Provost pfctl_do_ioctl(int dev, uint cmd, size_t size, nvlist_t **nvl)
1457ed19f5cSKristof Provost {
1467ed19f5cSKristof Provost 	struct pfioc_nv nv;
1477ed19f5cSKristof Provost 	void *data;
1487ed19f5cSKristof Provost 	size_t nvlen;
1497ed19f5cSKristof Provost 	int ret;
1507ed19f5cSKristof Provost 
1517ed19f5cSKristof Provost 	data = nvlist_pack(*nvl, &nvlen);
1526422599eSKristof Provost 	if (nvlen > size)
1536422599eSKristof Provost 		size = nvlen;
1547ed19f5cSKristof Provost 
1557ed19f5cSKristof Provost retry:
1567ed19f5cSKristof Provost 	nv.data = malloc(size);
15733d55d0dSKristof Provost 	if (nv.data == NULL) {
15833d55d0dSKristof Provost 		ret = ENOMEM;
15933d55d0dSKristof Provost 		goto out;
16033d55d0dSKristof Provost 	}
16133d55d0dSKristof Provost 
1627ed19f5cSKristof Provost 	memcpy(nv.data, data, nvlen);
1637ed19f5cSKristof Provost 
1647ed19f5cSKristof Provost 	nv.len = nvlen;
1657ed19f5cSKristof Provost 	nv.size = size;
1667ed19f5cSKristof Provost 
1677ed19f5cSKristof Provost 	ret = ioctl(dev, cmd, &nv);
1687ed19f5cSKristof Provost 	if (ret == -1 && errno == ENOSPC) {
1697ed19f5cSKristof Provost 		size *= 2;
1707ed19f5cSKristof Provost 		free(nv.data);
1717ed19f5cSKristof Provost 		goto retry;
1727ed19f5cSKristof Provost 	}
1737ed19f5cSKristof Provost 
1747ed19f5cSKristof Provost 	nvlist_destroy(*nvl);
1757ed19f5cSKristof Provost 	*nvl = NULL;
1767ed19f5cSKristof Provost 
1777ed19f5cSKristof Provost 	if (ret == 0) {
1787ed19f5cSKristof Provost 		*nvl = nvlist_unpack(nv.data, nv.len, 0);
1797ed19f5cSKristof Provost 		if (*nvl == NULL) {
1802cffb525SKristof Provost 			ret = EIO;
1812cffb525SKristof Provost 			goto out;
1827ed19f5cSKristof Provost 		}
1837ed19f5cSKristof Provost 	} else {
1847ed19f5cSKristof Provost 		ret = errno;
1857ed19f5cSKristof Provost 	}
1867ed19f5cSKristof Provost 
1872cffb525SKristof Provost out:
1882cffb525SKristof Provost 	free(data);
1897ed19f5cSKristof Provost 	free(nv.data);
1907ed19f5cSKristof Provost 
1917ed19f5cSKristof Provost 	return (ret);
1927ed19f5cSKristof Provost }
1937ed19f5cSKristof Provost 
1940d6c8174SKristof Provost static void
pf_nvuint_8_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint8_t * numbers,size_t * nelems)1950d6c8174SKristof Provost pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems,
1967bb3c927SKristof Provost     uint8_t *numbers, size_t *nelems)
1970d6c8174SKristof Provost {
1980d6c8174SKristof Provost 	const uint64_t *tmp;
1990d6c8174SKristof Provost 	size_t elems;
2000d6c8174SKristof Provost 
2010d6c8174SKristof Provost 	tmp = nvlist_get_number_array(nvl, name, &elems);
2020d6c8174SKristof Provost 	assert(elems <= maxelems);
2030d6c8174SKristof Provost 
2040d6c8174SKristof Provost 	for (size_t i = 0; i < elems; i++)
2050d6c8174SKristof Provost 		numbers[i] = tmp[i];
2060d6c8174SKristof Provost 
2070d6c8174SKristof Provost 	if (nelems)
2080d6c8174SKristof Provost 		*nelems = elems;
2090d6c8174SKristof Provost }
2100d6c8174SKristof Provost 
2110d6c8174SKristof Provost static void
pf_nvuint_16_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint16_t * numbers,size_t * nelems)2120d6c8174SKristof Provost pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems,
2137bb3c927SKristof Provost     uint16_t *numbers, size_t *nelems)
2140d6c8174SKristof Provost {
2150d6c8174SKristof Provost 	const uint64_t *tmp;
2160d6c8174SKristof Provost 	size_t elems;
2170d6c8174SKristof Provost 
2180d6c8174SKristof Provost 	tmp = nvlist_get_number_array(nvl, name, &elems);
2190d6c8174SKristof Provost 	assert(elems <= maxelems);
2200d6c8174SKristof Provost 
2210d6c8174SKristof Provost 	for (size_t i = 0; i < elems; i++)
2220d6c8174SKristof Provost 		numbers[i] = tmp[i];
2230d6c8174SKristof Provost 
2240d6c8174SKristof Provost 	if (nelems)
2250d6c8174SKristof Provost 		*nelems = elems;
2260d6c8174SKristof Provost }
2270d6c8174SKristof Provost 
2280d6c8174SKristof Provost static void
pf_nvuint_32_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint32_t * numbers,size_t * nelems)2290d6c8174SKristof Provost pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems,
2307bb3c927SKristof Provost     uint32_t *numbers, size_t *nelems)
2310d6c8174SKristof Provost {
2320d6c8174SKristof Provost 	const uint64_t *tmp;
2330d6c8174SKristof Provost 	size_t elems;
2340d6c8174SKristof Provost 
2350d6c8174SKristof Provost 	tmp = nvlist_get_number_array(nvl, name, &elems);
2360d6c8174SKristof Provost 
2372b1eb63fSKristof Provost 	for (size_t i = 0; i < elems && i < maxelems; i++)
2380d6c8174SKristof Provost 		numbers[i] = tmp[i];
2390d6c8174SKristof Provost 
2400d6c8174SKristof Provost 	if (nelems)
2410d6c8174SKristof Provost 		*nelems = elems;
2420d6c8174SKristof Provost }
2430d6c8174SKristof Provost 
2440d6c8174SKristof Provost static void
pf_nvuint_64_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint64_t * numbers,size_t * nelems)2450d6c8174SKristof Provost pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems,
2467bb3c927SKristof Provost     uint64_t *numbers, size_t *nelems)
2470d6c8174SKristof Provost {
2480d6c8174SKristof Provost 	const uint64_t *tmp;
2490d6c8174SKristof Provost 	size_t elems;
2500d6c8174SKristof Provost 
2510d6c8174SKristof Provost 	tmp = nvlist_get_number_array(nvl, name, &elems);
2520d6c8174SKristof Provost 	assert(elems <= maxelems);
2530d6c8174SKristof Provost 
2540d6c8174SKristof Provost 	for (size_t i = 0; i < elems; i++)
2550d6c8174SKristof Provost 		numbers[i] = tmp[i];
2560d6c8174SKristof Provost 
2570d6c8174SKristof Provost 	if (nelems)
2580d6c8174SKristof Provost 		*nelems = elems;
2590d6c8174SKristof Provost }
2600d6c8174SKristof Provost 
26181647eb6SKristof Provost int
pfctl_startstop(struct pfctl_handle * h,int start)26266cacc14SKristof Provost pfctl_startstop(struct pfctl_handle *h, int start)
26381647eb6SKristof Provost {
2649dbbe68bSKristof Provost 	return (pfctl_do_netlink_cmd(h, start ? PFNL_CMD_START : PFNL_CMD_STOP));
26581647eb6SKristof Provost }
26681647eb6SKristof Provost 
2670d6c8174SKristof Provost static void
_pfctl_get_status_counters(const nvlist_t * nvl,struct pfctl_status_counters * counters)26846fb68b1SKristof Provost _pfctl_get_status_counters(const nvlist_t *nvl,
26946fb68b1SKristof Provost     struct pfctl_status_counters *counters)
27046fb68b1SKristof Provost {
27146fb68b1SKristof Provost 	const uint64_t		*ids, *counts;
27246fb68b1SKristof Provost 	const char *const	*names;
27346fb68b1SKristof Provost 	size_t id_len, counter_len, names_len;
27446fb68b1SKristof Provost 
27546fb68b1SKristof Provost 	ids = nvlist_get_number_array(nvl, "ids", &id_len);
27646fb68b1SKristof Provost 	counts = nvlist_get_number_array(nvl, "counters", &counter_len);
27746fb68b1SKristof Provost 	names = nvlist_get_string_array(nvl, "names", &names_len);
27846fb68b1SKristof Provost 	assert(id_len == counter_len);
27946fb68b1SKristof Provost 	assert(counter_len == names_len);
28046fb68b1SKristof Provost 
28146fb68b1SKristof Provost 	TAILQ_INIT(counters);
28246fb68b1SKristof Provost 
28346fb68b1SKristof Provost 	for (size_t i = 0; i < id_len; i++) {
28446fb68b1SKristof Provost 		struct pfctl_status_counter *c;
28546fb68b1SKristof Provost 
28646fb68b1SKristof Provost 		c = malloc(sizeof(*c));
28733d55d0dSKristof Provost 		if (c == NULL)
28833d55d0dSKristof Provost 			continue;
28946fb68b1SKristof Provost 
29046fb68b1SKristof Provost 		c->id = ids[i];
29146fb68b1SKristof Provost 		c->counter = counts[i];
29246fb68b1SKristof Provost 		c->name = strdup(names[i]);
29346fb68b1SKristof Provost 
29446fb68b1SKristof Provost 		TAILQ_INSERT_TAIL(counters, c, entry);
29546fb68b1SKristof Provost 	}
29646fb68b1SKristof Provost }
29746fb68b1SKristof Provost 
2985824df8dSKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_status_counter, _field)
2995824df8dSKristof Provost static const struct snl_attr_parser ap_counter[] = {
3005824df8dSKristof Provost 	{ .type = PF_C_COUNTER, .off = _OUT(counter), .cb = snl_attr_get_uint64 },
3015824df8dSKristof Provost 	{ .type = PF_C_NAME, .off = _OUT(name), .cb = snl_attr_get_string },
3025824df8dSKristof Provost 	{ .type = PF_C_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
3035824df8dSKristof Provost };
3045824df8dSKristof Provost SNL_DECLARE_ATTR_PARSER(counter_parser, ap_counter);
3055824df8dSKristof Provost #undef _OUT
3065824df8dSKristof Provost 
3075824df8dSKristof Provost static bool
snl_attr_get_counters(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)3085824df8dSKristof Provost snl_attr_get_counters(struct snl_state *ss, struct nlattr *nla,
3095824df8dSKristof Provost     const void *arg __unused, void *target)
3105824df8dSKristof Provost {
3115824df8dSKristof Provost 	struct pfctl_status_counter counter = {};
3125824df8dSKristof Provost 	struct pfctl_status_counter *c;
3135824df8dSKristof Provost 	bool error;
3145824df8dSKristof Provost 
3155824df8dSKristof Provost 	error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &counter_parser, &counter);
3165824df8dSKristof Provost 	if (! error)
3175824df8dSKristof Provost 		return (error);
3185824df8dSKristof Provost 
3195824df8dSKristof Provost 	c = malloc(sizeof(*c));
3205824df8dSKristof Provost 	if (c == NULL)
3215824df8dSKristof Provost 		return (false);
3225824df8dSKristof Provost 
3235824df8dSKristof Provost 	c->id = counter.id;
3245824df8dSKristof Provost 	c->counter = counter.counter;
3255824df8dSKristof Provost 	c->name = strdup(counter.name);
3265824df8dSKristof Provost 
3275824df8dSKristof Provost 	TAILQ_INSERT_TAIL((struct pfctl_status_counters *)target, c, entry);
3285824df8dSKristof Provost 
3295824df8dSKristof Provost 	return (error);
3305824df8dSKristof Provost }
3315824df8dSKristof Provost 
3325824df8dSKristof Provost struct snl_uint64_array {
3335824df8dSKristof Provost 	uint64_t *array;
3345824df8dSKristof Provost 	size_t count;
3355824df8dSKristof Provost 	size_t max;
3365824df8dSKristof Provost };
3375824df8dSKristof Provost static bool
snl_attr_get_uint64_element(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)3385824df8dSKristof Provost snl_attr_get_uint64_element(struct snl_state *ss, struct nlattr *nla,
3395824df8dSKristof Provost     const void *arg, void *target)
3405824df8dSKristof Provost {
3415824df8dSKristof Provost 	bool error;
3425824df8dSKristof Provost 	uint64_t value;
3435824df8dSKristof Provost 	struct snl_uint64_array *t = (struct snl_uint64_array *)target;
3445824df8dSKristof Provost 
3455824df8dSKristof Provost 	if (t->count >= t->max)
3465824df8dSKristof Provost 		return (false);
3475824df8dSKristof Provost 
3485824df8dSKristof Provost 	error = snl_attr_get_uint64(ss, nla, arg, &value);
3495824df8dSKristof Provost 	if (! error)
3505824df8dSKristof Provost 		return (error);
3515824df8dSKristof Provost 
3525824df8dSKristof Provost 	t->array[t->count++] = value;
3535824df8dSKristof Provost 
3545824df8dSKristof Provost 	return (true);
3555824df8dSKristof Provost }
3565824df8dSKristof Provost 
3575824df8dSKristof Provost static const struct snl_attr_parser ap_array[] = {
3585824df8dSKristof Provost 	{ .cb = snl_attr_get_uint64_element },
3595824df8dSKristof Provost };
3605824df8dSKristof Provost SNL_DECLARE_ATTR_PARSER(array_parser, ap_array);
3615824df8dSKristof Provost static bool
snl_attr_get_uint64_array(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)3625824df8dSKristof Provost snl_attr_get_uint64_array(struct snl_state *ss, struct nlattr *nla,
3635824df8dSKristof Provost     const void *arg, void *target)
3645824df8dSKristof Provost {
3655824df8dSKristof Provost 	struct snl_uint64_array a = {
3665824df8dSKristof Provost 		.array = target,
3675824df8dSKristof Provost 		.count = 0,
3685824df8dSKristof Provost 		.max = (size_t)arg,
3695824df8dSKristof Provost 	};
3705824df8dSKristof Provost 	bool error;
3715824df8dSKristof Provost 
3725824df8dSKristof Provost 	error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &array_parser, &a);
3735824df8dSKristof Provost 	if (! error)
3745824df8dSKristof Provost 		return (error);
3755824df8dSKristof Provost 
3765824df8dSKristof Provost 	return (true);
3775824df8dSKristof Provost }
3785824df8dSKristof Provost 
3795824df8dSKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_status, _field)
3805824df8dSKristof Provost static const struct snl_attr_parser ap_getstatus[] = {
3815824df8dSKristof Provost 	{ .type = PF_GS_IFNAME, .off = _OUT(ifname), .arg_u32 = IFNAMSIZ, .cb = snl_attr_copy_string },
3825824df8dSKristof Provost 	{ .type = PF_GS_RUNNING, .off = _OUT(running), .cb = snl_attr_get_bool },
3835824df8dSKristof Provost 	{ .type = PF_GS_SINCE, .off = _OUT(since), .cb = snl_attr_get_uint32 },
3845824df8dSKristof Provost 	{ .type = PF_GS_DEBUG, .off = _OUT(debug), .cb = snl_attr_get_uint32 },
3855824df8dSKristof Provost 	{ .type = PF_GS_HOSTID, .off = _OUT(hostid), .cb = snl_attr_get_uint32 },
3865824df8dSKristof Provost 	{ .type = PF_GS_STATES, .off = _OUT(states), .cb = snl_attr_get_uint32 },
3875824df8dSKristof Provost 	{ .type = PF_GS_SRC_NODES, .off = _OUT(src_nodes), .cb = snl_attr_get_uint32 },
3885824df8dSKristof Provost 	{ .type = PF_GS_REASSEMBLE, .off = _OUT(reass), .cb = snl_attr_get_uint32 },
3895824df8dSKristof Provost 	{ .type = PF_GS_SYNCOOKIES_ACTIVE, .off = _OUT(syncookies_active), .cb = snl_attr_get_uint32 },
3905824df8dSKristof Provost 	{ .type = PF_GS_COUNTERS, .off = _OUT(counters), .cb = snl_attr_get_counters },
3915824df8dSKristof Provost 	{ .type = PF_GS_LCOUNTERS, .off = _OUT(lcounters), .cb = snl_attr_get_counters },
3925824df8dSKristof Provost 	{ .type = PF_GS_FCOUNTERS, .off = _OUT(fcounters), .cb = snl_attr_get_counters },
3935824df8dSKristof Provost 	{ .type = PF_GS_SCOUNTERS, .off = _OUT(scounters), .cb = snl_attr_get_counters },
3945824df8dSKristof Provost 	{ .type = PF_GS_CHKSUM, .off = _OUT(pf_chksum), .arg_u32 = PF_MD5_DIGEST_LENGTH, .cb = snl_attr_get_bytes },
3955824df8dSKristof Provost 	{ .type = PF_GS_PCOUNTERS, .off = _OUT(pcounters), .arg_u32 = 2 * 2 * 2, .cb = snl_attr_get_uint64_array },
396363b57d5SEric A. Borisch 	{ .type = PF_GS_BCOUNTERS, .off = _OUT(bcounters), .arg_u32 = 2 * 2, .cb = snl_attr_get_uint64_array },
397c00aca9aSKristof Provost 	{ .type = PF_GS_NCOUNTERS, .off = _OUT(ncounters), .cb = snl_attr_get_counters },
398c00aca9aSKristof Provost 	{ .type = PF_GS_FRAGMENTS, .off = _OUT(fragments), .cb = snl_attr_get_uint64 },
3995824df8dSKristof Provost };
4007c882c69SKristof Provost SNL_DECLARE_PARSER(getstatus_parser, struct genlmsghdr, snl_f_p_empty, ap_getstatus);
4015824df8dSKristof Provost #undef _OUT
4025824df8dSKristof Provost 
4035824df8dSKristof Provost struct pfctl_status *
pfctl_get_status_h(struct pfctl_handle * h)404a34efd08SKristof Provost pfctl_get_status_h(struct pfctl_handle *h)
4055824df8dSKristof Provost {
4065824df8dSKristof Provost 	struct pfctl_status	*status;
4075824df8dSKristof Provost 	struct snl_errmsg_data e = {};
4085824df8dSKristof Provost 	struct nlmsghdr *hdr;
4095824df8dSKristof Provost 	struct snl_writer nw;
4105824df8dSKristof Provost 	uint32_t seq_id;
4115824df8dSKristof Provost 	int family_id;
4125824df8dSKristof Provost 
4135824df8dSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4145824df8dSKristof Provost 	if (family_id == 0)
4155824df8dSKristof Provost 		return (NULL);
4165824df8dSKristof Provost 
4175824df8dSKristof Provost 	snl_init_writer(&h->ss, &nw);
4185824df8dSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_STATUS);
4195824df8dSKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
4205824df8dSKristof Provost 
4215824df8dSKristof Provost 	hdr = snl_finalize_msg(&nw);
4225824df8dSKristof Provost 	if (hdr == NULL) {
4235824df8dSKristof Provost 		return (NULL);
4245824df8dSKristof Provost 	}
4255824df8dSKristof Provost 
4265824df8dSKristof Provost 	seq_id = hdr->nlmsg_seq;
4275824df8dSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4285824df8dSKristof Provost 		return (NULL);
4295824df8dSKristof Provost 
4305824df8dSKristof Provost 	status = calloc(1, sizeof(*status));
4315824df8dSKristof Provost 	if (status == NULL)
4325824df8dSKristof Provost 		return (NULL);
4335824df8dSKristof Provost 	TAILQ_INIT(&status->counters);
4345824df8dSKristof Provost 	TAILQ_INIT(&status->lcounters);
4355824df8dSKristof Provost 	TAILQ_INIT(&status->fcounters);
4365824df8dSKristof Provost 	TAILQ_INIT(&status->scounters);
437c00aca9aSKristof Provost 	TAILQ_INIT(&status->ncounters);
4385824df8dSKristof Provost 
4395824df8dSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4405824df8dSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &getstatus_parser, status))
4415824df8dSKristof Provost 			continue;
4425824df8dSKristof Provost 	}
4435824df8dSKristof Provost 
4445824df8dSKristof Provost 	return (status);
4455824df8dSKristof Provost }
4465824df8dSKristof Provost 
44746fb68b1SKristof Provost struct pfctl_status *
pfctl_get_status(int dev)44846fb68b1SKristof Provost pfctl_get_status(int dev)
44946fb68b1SKristof Provost {
45046fb68b1SKristof Provost 	struct pfctl_status	*status;
45146fb68b1SKristof Provost 	nvlist_t	*nvl;
45246fb68b1SKristof Provost 	size_t		 len;
45346fb68b1SKristof Provost 	const void	*chksum;
45446fb68b1SKristof Provost 
45546fb68b1SKristof Provost 	status = calloc(1, sizeof(*status));
45646fb68b1SKristof Provost 	if (status == NULL)
45746fb68b1SKristof Provost 		return (NULL);
45846fb68b1SKristof Provost 
4597ed19f5cSKristof Provost 	nvl = nvlist_create(0);
46046fb68b1SKristof Provost 
4617ed19f5cSKristof Provost 	if (pfctl_do_ioctl(dev, DIOCGETSTATUSNV, 4096, &nvl)) {
462498934c5SKristof Provost 		nvlist_destroy(nvl);
46346fb68b1SKristof Provost 		free(status);
46446fb68b1SKristof Provost 		return (NULL);
46546fb68b1SKristof Provost 	}
46646fb68b1SKristof Provost 
46746fb68b1SKristof Provost 	status->running = nvlist_get_bool(nvl, "running");
46846fb68b1SKristof Provost 	status->since = nvlist_get_number(nvl, "since");
46946fb68b1SKristof Provost 	status->debug = nvlist_get_number(nvl, "debug");
470735748f3SKristof Provost 	status->hostid = ntohl(nvlist_get_number(nvl, "hostid"));
47146fb68b1SKristof Provost 	status->states = nvlist_get_number(nvl, "states");
47246fb68b1SKristof Provost 	status->src_nodes = nvlist_get_number(nvl, "src_nodes");
473444a77caSKristof Provost 	status->syncookies_active = nvlist_get_bool(nvl, "syncookies_active");
47439282ef3SKajetan Staszkiewicz 	status->reass = nvlist_get_number(nvl, "reass");
47546fb68b1SKristof Provost 
47646fb68b1SKristof Provost 	strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"),
47746fb68b1SKristof Provost 	    IFNAMSIZ);
47846fb68b1SKristof Provost 	chksum = nvlist_get_binary(nvl, "chksum", &len);
47946fb68b1SKristof Provost 	assert(len == PF_MD5_DIGEST_LENGTH);
48046fb68b1SKristof Provost 	memcpy(status->pf_chksum, chksum, len);
48146fb68b1SKristof Provost 
48246fb68b1SKristof Provost 	_pfctl_get_status_counters(nvlist_get_nvlist(nvl, "counters"),
48346fb68b1SKristof Provost 	    &status->counters);
48446fb68b1SKristof Provost 	_pfctl_get_status_counters(nvlist_get_nvlist(nvl, "lcounters"),
48546fb68b1SKristof Provost 	    &status->lcounters);
48646fb68b1SKristof Provost 	_pfctl_get_status_counters(nvlist_get_nvlist(nvl, "fcounters"),
48746fb68b1SKristof Provost 	    &status->fcounters);
48846fb68b1SKristof Provost 	_pfctl_get_status_counters(nvlist_get_nvlist(nvl, "scounters"),
48946fb68b1SKristof Provost 	    &status->scounters);
49046fb68b1SKristof Provost 
491a3f71765SKristof Provost 	pf_nvuint_64_array(nvl, "pcounters", 2 * 2 * 2,
49246fb68b1SKristof Provost 	    (uint64_t *)status->pcounters, NULL);
49346fb68b1SKristof Provost 	pf_nvuint_64_array(nvl, "bcounters", 2 * 2,
49446fb68b1SKristof Provost 	    (uint64_t *)status->bcounters, NULL);
49546fb68b1SKristof Provost 
49646fb68b1SKristof Provost 	nvlist_destroy(nvl);
49746fb68b1SKristof Provost 
49846fb68b1SKristof Provost 	return (status);
49946fb68b1SKristof Provost }
5009dbbe68bSKristof Provost int
pfctl_clear_status(struct pfctl_handle * h)5019dbbe68bSKristof Provost pfctl_clear_status(struct pfctl_handle *h)
5029dbbe68bSKristof Provost {
5039dbbe68bSKristof Provost 	return (pfctl_do_netlink_cmd(h, PFNL_CMD_CLEAR_STATUS));
5049dbbe68bSKristof Provost }
50546fb68b1SKristof Provost 
506e3d3d61aSKristof Provost static uint64_t
_pfctl_status_counter(struct pfctl_status_counters * counters,uint64_t id)507e3d3d61aSKristof Provost _pfctl_status_counter(struct pfctl_status_counters *counters, uint64_t id)
508e3d3d61aSKristof Provost {
509e3d3d61aSKristof Provost 	struct pfctl_status_counter *c;
510e3d3d61aSKristof Provost 
511e3d3d61aSKristof Provost 	TAILQ_FOREACH(c, counters, entry) {
512e3d3d61aSKristof Provost 		if (c->id == id)
513e3d3d61aSKristof Provost 			return (c->counter);
514e3d3d61aSKristof Provost 	}
515e3d3d61aSKristof Provost 
516e3d3d61aSKristof Provost 	return (0);
517e3d3d61aSKristof Provost }
518e3d3d61aSKristof Provost 
519e3d3d61aSKristof Provost uint64_t
pfctl_status_counter(struct pfctl_status * status,int id)520e3d3d61aSKristof Provost pfctl_status_counter(struct pfctl_status *status, int id)
521e3d3d61aSKristof Provost {
522e3d3d61aSKristof Provost 	return (_pfctl_status_counter(&status->counters, id));
523e3d3d61aSKristof Provost }
524e3d3d61aSKristof Provost 
525e3d3d61aSKristof Provost uint64_t
pfctl_status_lcounter(struct pfctl_status * status,int id)5261c824f43SKristof Provost pfctl_status_lcounter(struct pfctl_status *status, int id)
5271c824f43SKristof Provost {
5281c824f43SKristof Provost 	return (_pfctl_status_counter(&status->lcounters, id));
5291c824f43SKristof Provost }
5301c824f43SKristof Provost 
5311c824f43SKristof Provost uint64_t
pfctl_status_fcounter(struct pfctl_status * status,int id)532e3d3d61aSKristof Provost pfctl_status_fcounter(struct pfctl_status *status, int id)
533e3d3d61aSKristof Provost {
534e3d3d61aSKristof Provost 	return (_pfctl_status_counter(&status->fcounters, id));
535e3d3d61aSKristof Provost }
536e3d3d61aSKristof Provost 
537e3d3d61aSKristof Provost uint64_t
pfctl_status_scounter(struct pfctl_status * status,int id)538e3d3d61aSKristof Provost pfctl_status_scounter(struct pfctl_status *status, int id)
539e3d3d61aSKristof Provost {
540e3d3d61aSKristof Provost 	return (_pfctl_status_counter(&status->scounters, id));
541e3d3d61aSKristof Provost }
542e3d3d61aSKristof Provost 
54346fb68b1SKristof Provost void
pfctl_free_status(struct pfctl_status * status)54446fb68b1SKristof Provost pfctl_free_status(struct pfctl_status *status)
54546fb68b1SKristof Provost {
54646fb68b1SKristof Provost 	struct pfctl_status_counter *c, *tmp;
54746fb68b1SKristof Provost 
5480b01878fSKristof Provost 	if (status == NULL)
5490b01878fSKristof Provost 		return;
5500b01878fSKristof Provost 
55146fb68b1SKristof Provost 	TAILQ_FOREACH_SAFE(c, &status->counters, entry, tmp) {
55246fb68b1SKristof Provost 		free(c->name);
55346fb68b1SKristof Provost 		free(c);
55446fb68b1SKristof Provost 	}
55546fb68b1SKristof Provost 	TAILQ_FOREACH_SAFE(c, &status->lcounters, entry, tmp) {
55646fb68b1SKristof Provost 		free(c->name);
55746fb68b1SKristof Provost 		free(c);
55846fb68b1SKristof Provost 	}
55946fb68b1SKristof Provost 	TAILQ_FOREACH_SAFE(c, &status->fcounters, entry, tmp) {
56046fb68b1SKristof Provost 		free(c->name);
56146fb68b1SKristof Provost 		free(c);
56246fb68b1SKristof Provost 	}
56346fb68b1SKristof Provost 	TAILQ_FOREACH_SAFE(c, &status->scounters, entry, tmp) {
56446fb68b1SKristof Provost 		free(c->name);
56546fb68b1SKristof Provost 		free(c);
56646fb68b1SKristof Provost 	}
567bdb205c5SKristof Provost 	TAILQ_FOREACH_SAFE(c, &status->ncounters, entry, tmp) {
568bdb205c5SKristof Provost 		free(c->name);
569bdb205c5SKristof Provost 		free(c);
570bdb205c5SKristof Provost 	}
57146fb68b1SKristof Provost 
57246fb68b1SKristof Provost 	free(status);
57346fb68b1SKristof Provost }
57446fb68b1SKristof Provost 
57546fb68b1SKristof Provost static void
pfctl_nv_add_addr(nvlist_t * nvparent,const char * name,const struct pf_addr * addr)5760d71f9f3SKristof Provost pfctl_nv_add_addr(nvlist_t *nvparent, const char *name,
5770d71f9f3SKristof Provost     const struct pf_addr *addr)
5780d71f9f3SKristof Provost {
5790d71f9f3SKristof Provost 	nvlist_t *nvl = nvlist_create(0);
5800d71f9f3SKristof Provost 
5810d71f9f3SKristof Provost 	nvlist_add_binary(nvl, "addr", addr, sizeof(*addr));
5820d71f9f3SKristof Provost 
5830d71f9f3SKristof Provost 	nvlist_add_nvlist(nvparent, name, nvl);
5846dbb729dSKristof Provost 	nvlist_destroy(nvl);
5850d71f9f3SKristof Provost }
5860d71f9f3SKristof Provost 
5870d71f9f3SKristof Provost static void
pf_nvaddr_to_addr(const nvlist_t * nvl,struct pf_addr * addr)5880d6c8174SKristof Provost pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *addr)
5890d6c8174SKristof Provost {
5900d6c8174SKristof Provost 	size_t len;
5910d6c8174SKristof Provost 	const void *data;
5920d6c8174SKristof Provost 
5930d6c8174SKristof Provost 	data = nvlist_get_binary(nvl, "addr", &len);
5940d6c8174SKristof Provost 	assert(len == sizeof(struct pf_addr));
5950d6c8174SKristof Provost 	memcpy(addr, data, len);
5960d6c8174SKristof Provost }
5970d6c8174SKristof Provost 
5980d6c8174SKristof Provost static void
pfctl_nv_add_addr_wrap(nvlist_t * nvparent,const char * name,const struct pf_addr_wrap * addr)5990d71f9f3SKristof Provost pfctl_nv_add_addr_wrap(nvlist_t *nvparent, const char *name,
6000d71f9f3SKristof Provost     const struct pf_addr_wrap *addr)
6010d71f9f3SKristof Provost {
6020d71f9f3SKristof Provost 	nvlist_t *nvl = nvlist_create(0);
6030d71f9f3SKristof Provost 
6040d71f9f3SKristof Provost 	nvlist_add_number(nvl, "type", addr->type);
6050d71f9f3SKristof Provost 	nvlist_add_number(nvl, "iflags", addr->iflags);
606402dfb0aSKristof Provost 	if (addr->type == PF_ADDR_DYNIFTL)
6070d71f9f3SKristof Provost 		nvlist_add_string(nvl, "ifname", addr->v.ifname);
608402dfb0aSKristof Provost 	if (addr->type == PF_ADDR_TABLE)
6090d71f9f3SKristof Provost 		nvlist_add_string(nvl, "tblname", addr->v.tblname);
6100d71f9f3SKristof Provost 	pfctl_nv_add_addr(nvl, "addr", &addr->v.a.addr);
6110d71f9f3SKristof Provost 	pfctl_nv_add_addr(nvl, "mask", &addr->v.a.mask);
6120d71f9f3SKristof Provost 
6130d71f9f3SKristof Provost 	nvlist_add_nvlist(nvparent, name, nvl);
6146dbb729dSKristof Provost 	nvlist_destroy(nvl);
6150d71f9f3SKristof Provost }
6160d71f9f3SKristof Provost 
6170d71f9f3SKristof Provost static void
pf_nvaddr_wrap_to_addr_wrap(const nvlist_t * nvl,struct pf_addr_wrap * addr)6180d6c8174SKristof Provost pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
6190d6c8174SKristof Provost {
620218a8a49SKristof Provost 	bzero(addr, sizeof(*addr));
621218a8a49SKristof Provost 
6220d6c8174SKristof Provost 	addr->type = nvlist_get_number(nvl, "type");
6230d6c8174SKristof Provost 	addr->iflags = nvlist_get_number(nvl, "iflags");
624218a8a49SKristof Provost 	if (addr->type == PF_ADDR_DYNIFTL) {
625402dfb0aSKristof Provost 		strlcpy(addr->v.ifname, nvlist_get_string(nvl, "ifname"),
626402dfb0aSKristof Provost 		    IFNAMSIZ);
6272de49deeSKristof Provost 		addr->p.dyncnt = nvlist_get_number(nvl, "dyncnt");
628218a8a49SKristof Provost 	}
629218a8a49SKristof Provost 	if (addr->type == PF_ADDR_TABLE) {
6300d6c8174SKristof Provost 		strlcpy(addr->v.tblname, nvlist_get_string(nvl, "tblname"),
6310d6c8174SKristof Provost 		    PF_TABLE_NAME_SIZE);
632218a8a49SKristof Provost 		addr->p.tblcnt = nvlist_get_number(nvl, "tblcnt");
633218a8a49SKristof Provost 	}
6340d6c8174SKristof Provost 
6350d6c8174SKristof Provost 	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &addr->v.a.addr);
6360d6c8174SKristof Provost 	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"), &addr->v.a.mask);
6370d6c8174SKristof Provost }
6380d6c8174SKristof Provost 
6390d6c8174SKristof Provost static void
pfctl_nv_add_rule_addr(nvlist_t * nvparent,const char * name,const struct pf_rule_addr * addr)6400d71f9f3SKristof Provost pfctl_nv_add_rule_addr(nvlist_t *nvparent, const char *name,
6410d71f9f3SKristof Provost     const struct pf_rule_addr *addr)
6420d71f9f3SKristof Provost {
6437bb3c927SKristof Provost 	uint64_t ports[2];
6440d71f9f3SKristof Provost 	nvlist_t *nvl = nvlist_create(0);
6450d71f9f3SKristof Provost 
6460d71f9f3SKristof Provost 	pfctl_nv_add_addr_wrap(nvl, "addr", &addr->addr);
6470d71f9f3SKristof Provost 	ports[0] = addr->port[0];
6480d71f9f3SKristof Provost 	ports[1] = addr->port[1];
6490d71f9f3SKristof Provost 	nvlist_add_number_array(nvl, "port", ports, 2);
6500d71f9f3SKristof Provost 	nvlist_add_number(nvl, "neg", addr->neg);
6510d71f9f3SKristof Provost 	nvlist_add_number(nvl, "port_op", addr->port_op);
6520d71f9f3SKristof Provost 
6530d71f9f3SKristof Provost 	nvlist_add_nvlist(nvparent, name, nvl);
6546dbb729dSKristof Provost 	nvlist_destroy(nvl);
6550d71f9f3SKristof Provost }
6560d71f9f3SKristof Provost 
6570d71f9f3SKristof Provost static void
pf_nvrule_addr_to_rule_addr(const nvlist_t * nvl,struct pf_rule_addr * addr)6580d6c8174SKristof Provost pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
6590d6c8174SKristof Provost {
6600d6c8174SKristof Provost 	pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"), &addr->addr);
6610d6c8174SKristof Provost 
6620d6c8174SKristof Provost 	pf_nvuint_16_array(nvl, "port", 2, addr->port, NULL);
6630d6c8174SKristof Provost 	addr->neg = nvlist_get_number(nvl, "neg");
6640d6c8174SKristof Provost 	addr->port_op = nvlist_get_number(nvl, "port_op");
6650d6c8174SKristof Provost }
6660d6c8174SKristof Provost 
6670d6c8174SKristof Provost static void
pf_nvmape_to_mape(const nvlist_t * nvl,struct pf_mape_portset * mape)6682aa21096SKurosawa Takahiro pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
6692aa21096SKurosawa Takahiro {
6702aa21096SKurosawa Takahiro 	mape->offset = nvlist_get_number(nvl, "offset");
6712aa21096SKurosawa Takahiro 	mape->psidlen = nvlist_get_number(nvl, "psidlen");
6722aa21096SKurosawa Takahiro 	mape->psid = nvlist_get_number(nvl, "psid");
6732aa21096SKurosawa Takahiro }
6742aa21096SKurosawa Takahiro 
6752aa21096SKurosawa Takahiro static void
pf_nvpool_to_pool(const nvlist_t * nvl,struct pfctl_pool * pool)676600bd6ceSKurosawa Takahiro pf_nvpool_to_pool(const nvlist_t *nvl, struct pfctl_pool *pool)
6770d6c8174SKristof Provost {
6780d6c8174SKristof Provost 	size_t len;
6790d6c8174SKristof Provost 	const void *data;
6800d6c8174SKristof Provost 
6810d6c8174SKristof Provost 	data = nvlist_get_binary(nvl, "key", &len);
6820d6c8174SKristof Provost 	assert(len == sizeof(pool->key));
6830d6c8174SKristof Provost 	memcpy(&pool->key, data, len);
6840d6c8174SKristof Provost 
6850d6c8174SKristof Provost 	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"), &pool->counter);
6860d6c8174SKristof Provost 
6870d6c8174SKristof Provost 	pool->tblidx = nvlist_get_number(nvl, "tblidx");
6880d6c8174SKristof Provost 	pf_nvuint_16_array(nvl, "proxy_port", 2, pool->proxy_port, NULL);
6890d6c8174SKristof Provost 	pool->opts = nvlist_get_number(nvl, "opts");
6902aa21096SKurosawa Takahiro 
6912aa21096SKurosawa Takahiro 	if (nvlist_exists_nvlist(nvl, "mape"))
6922aa21096SKurosawa Takahiro 		pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"), &pool->mape);
6930d6c8174SKristof Provost }
6940d6c8174SKristof Provost 
6950d6c8174SKristof Provost static void
pf_nvrule_uid_to_rule_uid(const nvlist_t * nvl,struct pf_rule_uid * uid)6960d6c8174SKristof Provost pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
6970d6c8174SKristof Provost {
6980d6c8174SKristof Provost 	pf_nvuint_32_array(nvl, "uid", 2, uid->uid, NULL);
6990d6c8174SKristof Provost 	uid->op = nvlist_get_number(nvl, "op");
7000d6c8174SKristof Provost }
7010d6c8174SKristof Provost 
7020d6c8174SKristof Provost static void
pf_nvdivert_to_divert(const nvlist_t * nvl,struct pfctl_rule * rule)703e9eb0941SKristof Provost pf_nvdivert_to_divert(const nvlist_t *nvl, struct pfctl_rule *rule)
7040d6c8174SKristof Provost {
7050d6c8174SKristof Provost 	pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &rule->divert.addr);
7060d6c8174SKristof Provost 	rule->divert.port = nvlist_get_number(nvl, "port");
7070d6c8174SKristof Provost }
7080d6c8174SKristof Provost 
7090d6c8174SKristof Provost static void
pf_nvrule_to_rule(const nvlist_t * nvl,struct pfctl_rule * rule)710e9eb0941SKristof Provost pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule)
7110d6c8174SKristof Provost {
7120d6c8174SKristof Provost 	const uint64_t *skip;
7136fcc8e04SKristof Provost 	const char *const *labels;
7146fcc8e04SKristof Provost 	size_t skipcount, labelcount;
7150d6c8174SKristof Provost 
7160d6c8174SKristof Provost 	rule->nr = nvlist_get_number(nvl, "nr");
7170d6c8174SKristof Provost 
7180d6c8174SKristof Provost 	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"), &rule->src);
7190d6c8174SKristof Provost 	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &rule->dst);
7200d6c8174SKristof Provost 
7210d6c8174SKristof Provost 	skip = nvlist_get_number_array(nvl, "skip", &skipcount);
7220d6c8174SKristof Provost 	assert(skip);
7230d6c8174SKristof Provost 	assert(skipcount == PF_SKIP_COUNT);
7240d6c8174SKristof Provost 	for (int i = 0; i < PF_SKIP_COUNT; i++)
7250d6c8174SKristof Provost 		rule->skip[i].nr = skip[i];
7260d6c8174SKristof Provost 
7276fcc8e04SKristof Provost 	labels = nvlist_get_string_array(nvl, "labels", &labelcount);
7286fcc8e04SKristof Provost 	assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
7296fcc8e04SKristof Provost 	for (size_t i = 0; i < labelcount; i++)
7306fcc8e04SKristof Provost 		strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
73176c5eeccSKristof Provost 	rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
7320d6c8174SKristof Provost 	strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
7330d6c8174SKristof Provost 	strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
7340d6c8174SKristof Provost 	strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE);
7350d6c8174SKristof Provost 	strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
7360d6c8174SKristof Provost 	    PF_TAG_NAME_SIZE);
7370d6c8174SKristof Provost 	strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
7380d6c8174SKristof Provost 	    PF_TAG_NAME_SIZE);
7390d6c8174SKristof Provost 
7400d6c8174SKristof Provost 	strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"),
7410d6c8174SKristof Provost 	    PF_TABLE_NAME_SIZE);
7420d6c8174SKristof Provost 
743e11dacbfSKristof Provost 	pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rdr);
7440d6c8174SKristof Provost 
7450d6c8174SKristof Provost 	rule->evaluations = nvlist_get_number(nvl, "evaluations");
7460d6c8174SKristof Provost 	pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL);
7470d6c8174SKristof Provost 	pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL);
7480d6c8174SKristof Provost 
7490abcc1d2SReid Linnemann 	if (nvlist_exists_number(nvl, "timestamp")) {
7500abcc1d2SReid Linnemann 		rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp");
7510abcc1d2SReid Linnemann 	}
7520abcc1d2SReid Linnemann 
7530d6c8174SKristof Provost 	rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint");
7540d6c8174SKristof Provost 
7550d6c8174SKristof Provost 	rule->rtableid = nvlist_get_number(nvl, "rtableid");
7560d6c8174SKristof Provost 	pf_nvuint_32_array(nvl, "timeout", PFTM_MAX, rule->timeout, NULL);
7570d6c8174SKristof Provost 	rule->max_states = nvlist_get_number(nvl, "max_states");
7580d6c8174SKristof Provost 	rule->max_src_nodes = nvlist_get_number(nvl, "max_src_nodes");
7590d6c8174SKristof Provost 	rule->max_src_states = nvlist_get_number(nvl, "max_src_states");
7600d6c8174SKristof Provost 	rule->max_src_conn = nvlist_get_number(nvl, "max_src_conn");
7610d6c8174SKristof Provost 	rule->max_src_conn_rate.limit =
7620d6c8174SKristof Provost 	    nvlist_get_number(nvl, "max_src_conn_rate.limit");
7630d6c8174SKristof Provost 	rule->max_src_conn_rate.seconds =
7640d6c8174SKristof Provost 	    nvlist_get_number(nvl, "max_src_conn_rate.seconds");
7650d6c8174SKristof Provost 	rule->qid = nvlist_get_number(nvl, "qid");
7660d6c8174SKristof Provost 	rule->pqid = nvlist_get_number(nvl, "pqid");
76763b3c1c7SKristof Provost 	rule->dnpipe = nvlist_get_number(nvl, "dnpipe");
76863b3c1c7SKristof Provost 	rule->dnrpipe = nvlist_get_number(nvl, "dnrpipe");
76963b3c1c7SKristof Provost 	rule->free_flags = nvlist_get_number(nvl, "dnflags");
7700d6c8174SKristof Provost 	rule->prob = nvlist_get_number(nvl, "prob");
7710d6c8174SKristof Provost 	rule->cuid = nvlist_get_number(nvl, "cuid");
7720d6c8174SKristof Provost 	rule->cpid = nvlist_get_number(nvl, "cpid");
7730d6c8174SKristof Provost 
7740d6c8174SKristof Provost 	rule->return_icmp = nvlist_get_number(nvl, "return_icmp");
7750d6c8174SKristof Provost 	rule->return_icmp6 = nvlist_get_number(nvl, "return_icmp6");
7760d6c8174SKristof Provost 	rule->max_mss = nvlist_get_number(nvl, "max_mss");
7770d6c8174SKristof Provost 	rule->scrub_flags = nvlist_get_number(nvl, "scrub_flags");
7780d6c8174SKristof Provost 
7790d6c8174SKristof Provost 	pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"), &rule->uid);
7800d6c8174SKristof Provost 	pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "gid"),
7810d6c8174SKristof Provost 	    (struct pf_rule_uid *)&rule->gid);
7820d6c8174SKristof Provost 
7830d6c8174SKristof Provost 	rule->rule_flag = nvlist_get_number(nvl, "rule_flag");
7840d6c8174SKristof Provost 	rule->action = nvlist_get_number(nvl, "action");
7850d6c8174SKristof Provost 	rule->direction = nvlist_get_number(nvl, "direction");
7860d6c8174SKristof Provost 	rule->log = nvlist_get_number(nvl, "log");
7870d6c8174SKristof Provost 	rule->logif = nvlist_get_number(nvl, "logif");
7880d6c8174SKristof Provost 	rule->quick = nvlist_get_number(nvl, "quick");
7890d6c8174SKristof Provost 	rule->ifnot = nvlist_get_number(nvl, "ifnot");
7900d6c8174SKristof Provost 	rule->match_tag_not = nvlist_get_number(nvl, "match_tag_not");
7910d6c8174SKristof Provost 	rule->natpass = nvlist_get_number(nvl, "natpass");
7920d6c8174SKristof Provost 
7930d6c8174SKristof Provost 	rule->keep_state = nvlist_get_number(nvl, "keep_state");
7940d6c8174SKristof Provost 	rule->af = nvlist_get_number(nvl, "af");
7950d6c8174SKristof Provost 	rule->proto = nvlist_get_number(nvl, "proto");
7960d6c8174SKristof Provost 	rule->type = nvlist_get_number(nvl, "type");
7970d6c8174SKristof Provost 	rule->code = nvlist_get_number(nvl, "code");
7980d6c8174SKristof Provost 	rule->flags = nvlist_get_number(nvl, "flags");
7990d6c8174SKristof Provost 	rule->flagset = nvlist_get_number(nvl, "flagset");
8000d6c8174SKristof Provost 	rule->min_ttl = nvlist_get_number(nvl, "min_ttl");
8010d6c8174SKristof Provost 	rule->allow_opts = nvlist_get_number(nvl, "allow_opts");
8020d6c8174SKristof Provost 	rule->rt = nvlist_get_number(nvl, "rt");
8030d6c8174SKristof Provost 	rule->return_ttl  = nvlist_get_number(nvl, "return_ttl");
8040d6c8174SKristof Provost 	rule->tos = nvlist_get_number(nvl, "tos");
8050d6c8174SKristof Provost 	rule->set_tos = nvlist_get_number(nvl, "set_tos");
8060d6c8174SKristof Provost 	rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
8070d6c8174SKristof Provost 	rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
8080d6c8174SKristof Provost 
8090d6c8174SKristof Provost 	rule->flush = nvlist_get_number(nvl, "flush");
8100d6c8174SKristof Provost 	rule->prio = nvlist_get_number(nvl, "prio");
8110d6c8174SKristof Provost 	pf_nvuint_8_array(nvl, "set_prio", 2, rule->set_prio, NULL);
8120d6c8174SKristof Provost 
8130d6c8174SKristof Provost 	pf_nvdivert_to_divert(nvlist_get_nvlist(nvl, "divert"), rule);
8140d6c8174SKristof Provost 
815ab5707a5SKristof Provost 	rule->states_cur = nvlist_get_number(nvl, "states_cur");
816ab5707a5SKristof Provost 	rule->states_tot = nvlist_get_number(nvl, "states_tot");
817ab5707a5SKristof Provost 	rule->src_nodes = nvlist_get_number(nvl, "src_nodes");
8180d6c8174SKristof Provost }
8190d6c8174SKristof Provost 
8202b29ceb8SKristof Provost static void
pfctl_nveth_addr_to_eth_addr(const nvlist_t * nvl,struct pfctl_eth_addr * addr)8212b29ceb8SKristof Provost pfctl_nveth_addr_to_eth_addr(const nvlist_t *nvl, struct pfctl_eth_addr *addr)
8222b29ceb8SKristof Provost {
823c696d5c7SKristof Provost 	static const u_int8_t EMPTY_MAC[ETHER_ADDR_LEN] = { 0 };
8242b29ceb8SKristof Provost 	size_t len;
8252b29ceb8SKristof Provost 	const void *data;
8262b29ceb8SKristof Provost 
8272b29ceb8SKristof Provost 	data = nvlist_get_binary(nvl, "addr", &len);
8282b29ceb8SKristof Provost 	assert(len == sizeof(addr->addr));
8292b29ceb8SKristof Provost 	memcpy(addr->addr, data, sizeof(addr->addr));
8302b29ceb8SKristof Provost 
831b590f17aSKristof Provost 	data = nvlist_get_binary(nvl, "mask", &len);
832b590f17aSKristof Provost 	assert(len == sizeof(addr->mask));
833b590f17aSKristof Provost 	memcpy(addr->mask, data, sizeof(addr->mask));
834b590f17aSKristof Provost 
8352b29ceb8SKristof Provost 	addr->neg = nvlist_get_bool(nvl, "neg");
836c696d5c7SKristof Provost 
837c696d5c7SKristof Provost 	/* To make checks for 'is this address set?' easier. */
838c696d5c7SKristof Provost 	addr->isset = memcmp(addr->addr, EMPTY_MAC, ETHER_ADDR_LEN) != 0;
8392b29ceb8SKristof Provost }
8402b29ceb8SKristof Provost 
8412b29ceb8SKristof Provost static nvlist_t *
pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr * addr)8422b29ceb8SKristof Provost pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr *addr)
8432b29ceb8SKristof Provost {
8442b29ceb8SKristof Provost 	nvlist_t *nvl;
8452b29ceb8SKristof Provost 
8462b29ceb8SKristof Provost 	nvl = nvlist_create(0);
8472b29ceb8SKristof Provost 	if (nvl == NULL)
8482b29ceb8SKristof Provost 		return (NULL);
8492b29ceb8SKristof Provost 
8502b29ceb8SKristof Provost 	nvlist_add_bool(nvl, "neg", addr->neg);
8512b29ceb8SKristof Provost 	nvlist_add_binary(nvl, "addr", &addr->addr, ETHER_ADDR_LEN);
852b590f17aSKristof Provost 	nvlist_add_binary(nvl, "mask", &addr->mask, ETHER_ADDR_LEN);
8532b29ceb8SKristof Provost 
8542b29ceb8SKristof Provost 	return (nvl);
8552b29ceb8SKristof Provost }
8562b29ceb8SKristof Provost 
8572b29ceb8SKristof Provost static void
pfctl_nveth_rule_to_eth_rule(const nvlist_t * nvl,struct pfctl_eth_rule * rule)8582b29ceb8SKristof Provost pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
8592b29ceb8SKristof Provost {
860ef661d4aSChristian McDonald 	const char *const *labels;
861ef661d4aSChristian McDonald 	size_t labelcount, i;
862ef661d4aSChristian McDonald 
8632b29ceb8SKristof Provost 	rule->nr = nvlist_get_number(nvl, "nr");
8642b29ceb8SKristof Provost 	rule->quick = nvlist_get_bool(nvl, "quick");
8652b29ceb8SKristof Provost 	strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
8662b29ceb8SKristof Provost 	rule->ifnot = nvlist_get_bool(nvl, "ifnot");
8672b29ceb8SKristof Provost 	rule->direction = nvlist_get_number(nvl, "direction");
8682b29ceb8SKristof Provost 	rule->proto = nvlist_get_number(nvl, "proto");
8691f61367fSKristof Provost 	strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
8701f61367fSKristof Provost 	    PF_TAG_NAME_SIZE);
8711f61367fSKristof Provost 	rule->match_tag = nvlist_get_number(nvl, "match_tag");
8721f61367fSKristof Provost 	rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not");
8732b29ceb8SKristof Provost 
874ef661d4aSChristian McDonald 	labels = nvlist_get_string_array(nvl, "labels", &labelcount);
875ef661d4aSChristian McDonald 	assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
876ef661d4aSChristian McDonald 	for (i = 0; i < labelcount; i++)
877ef661d4aSChristian McDonald 		strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
878ef661d4aSChristian McDonald 	rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
879ef661d4aSChristian McDonald 
8802b29ceb8SKristof Provost 	pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"),
8812b29ceb8SKristof Provost 	    &rule->src);
8822b29ceb8SKristof Provost 	pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"),
8832b29ceb8SKristof Provost 	    &rule->dst);
8842b29ceb8SKristof Provost 
8858a42005dSKristof Provost 	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipsrc"),
8868a42005dSKristof Provost 	    &rule->ipsrc);
8878a42005dSKristof Provost 	pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipdst"),
8888a42005dSKristof Provost 	    &rule->ipdst);
8898a42005dSKristof Provost 
8902b29ceb8SKristof Provost 	rule->evaluations = nvlist_get_number(nvl, "evaluations");
8912b29ceb8SKristof Provost 	rule->packets[0] = nvlist_get_number(nvl, "packets-in");
8922b29ceb8SKristof Provost 	rule->packets[1] = nvlist_get_number(nvl, "packets-out");
8932b29ceb8SKristof Provost 	rule->bytes[0] = nvlist_get_number(nvl, "bytes-in");
8942b29ceb8SKristof Provost 	rule->bytes[1] = nvlist_get_number(nvl, "bytes-out");
8952b29ceb8SKristof Provost 
8960abcc1d2SReid Linnemann 	if (nvlist_exists_number(nvl, "timestamp")) {
8970abcc1d2SReid Linnemann 		rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp");
8980abcc1d2SReid Linnemann 	}
8990abcc1d2SReid Linnemann 
9002b29ceb8SKristof Provost 	strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
9012b29ceb8SKristof Provost 	strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
9022b29ceb8SKristof Provost 	    PF_TAG_NAME_SIZE);
9032b29ceb8SKristof Provost 
904fb330f39SKristof Provost 	rule->dnpipe = nvlist_get_number(nvl, "dnpipe");
905fb330f39SKristof Provost 	rule->dnflags = nvlist_get_number(nvl, "dnflags");
906fb330f39SKristof Provost 
907c5131afeSKristof Provost 	rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
908c5131afeSKristof Provost 	rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
909c5131afeSKristof Provost 
9108a8af942SKristof Provost 	strlcpy(rule->bridge_to, nvlist_get_string(nvl, "bridge_to"),
9118a8af942SKristof Provost 	    IFNAMSIZ);
9128a8af942SKristof Provost 
9132b29ceb8SKristof Provost 	rule->action = nvlist_get_number(nvl, "action");
9142b29ceb8SKristof Provost }
9152b29ceb8SKristof Provost 
9162b29ceb8SKristof Provost int
pfctl_get_eth_rulesets_info(int dev,struct pfctl_eth_rulesets_info * ri,const char * path)9179bb06778SKristof Provost pfctl_get_eth_rulesets_info(int dev, struct pfctl_eth_rulesets_info *ri,
9189bb06778SKristof Provost     const char *path)
9199bb06778SKristof Provost {
9209bb06778SKristof Provost 	nvlist_t *nvl;
9217ed19f5cSKristof Provost 	int ret;
9229bb06778SKristof Provost 
9239bb06778SKristof Provost 	bzero(ri, sizeof(*ri));
9249bb06778SKristof Provost 
9259bb06778SKristof Provost 	nvl = nvlist_create(0);
9269bb06778SKristof Provost 	nvlist_add_string(nvl, "path", path);
9279bb06778SKristof Provost 
9287ed19f5cSKristof Provost 	if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESETS, 256, &nvl)) != 0)
929498934c5SKristof Provost 		goto out;
9309bb06778SKristof Provost 
9319bb06778SKristof Provost 	ri->nr = nvlist_get_number(nvl, "nr");
9329bb06778SKristof Provost 
933498934c5SKristof Provost out:
9349bb06778SKristof Provost 	nvlist_destroy(nvl);
935498934c5SKristof Provost 	return (ret);
9369bb06778SKristof Provost }
9379bb06778SKristof Provost 
9389bb06778SKristof Provost int
pfctl_get_eth_ruleset(int dev,const char * path,int nr,struct pfctl_eth_ruleset_info * ri)9399bb06778SKristof Provost pfctl_get_eth_ruleset(int dev, const char *path, int nr,
9409bb06778SKristof Provost     struct pfctl_eth_ruleset_info *ri)
9419bb06778SKristof Provost {
9429bb06778SKristof Provost 	nvlist_t *nvl;
9437ed19f5cSKristof Provost 	int ret;
9449bb06778SKristof Provost 
9459bb06778SKristof Provost 	bzero(ri, sizeof(*ri));
9469bb06778SKristof Provost 
9479bb06778SKristof Provost 	nvl = nvlist_create(0);
9489bb06778SKristof Provost 	nvlist_add_string(nvl, "path", path);
9499bb06778SKristof Provost 	nvlist_add_number(nvl, "nr", nr);
9509bb06778SKristof Provost 
9517ed19f5cSKristof Provost 	if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESET, 1024, &nvl)) != 0)
952498934c5SKristof Provost 		goto out;
9539bb06778SKristof Provost 
9549bb06778SKristof Provost 	ri->nr = nvlist_get_number(nvl, "nr");
9559bb06778SKristof Provost 	strlcpy(ri->path, nvlist_get_string(nvl, "path"), MAXPATHLEN);
9569bb06778SKristof Provost 	strlcpy(ri->name, nvlist_get_string(nvl, "name"),
9579bb06778SKristof Provost 	    PF_ANCHOR_NAME_SIZE);
9589bb06778SKristof Provost 
959498934c5SKristof Provost out:
9604abc3b48SKristof Provost 	nvlist_destroy(nvl);
961498934c5SKristof Provost 	return (ret);
9629bb06778SKristof Provost }
9639bb06778SKristof Provost 
9649bb06778SKristof Provost int
pfctl_get_eth_rules_info(int dev,struct pfctl_eth_rules_info * rules,const char * path)965c5131afeSKristof Provost pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
966c5131afeSKristof Provost     const char *path)
9672b29ceb8SKristof Provost {
9682b29ceb8SKristof Provost 	nvlist_t *nvl;
9697ed19f5cSKristof Provost 	int ret;
9702b29ceb8SKristof Provost 
9712b29ceb8SKristof Provost 	bzero(rules, sizeof(*rules));
9722b29ceb8SKristof Provost 
973c5131afeSKristof Provost 	nvl = nvlist_create(0);
974c5131afeSKristof Provost 	nvlist_add_string(nvl, "anchor", path);
975c5131afeSKristof Provost 
9767ed19f5cSKristof Provost 	if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULES, 1024, &nvl)) != 0)
977498934c5SKristof Provost 		goto out;
9782b29ceb8SKristof Provost 
9792b29ceb8SKristof Provost 	rules->nr = nvlist_get_number(nvl, "nr");
9802b29ceb8SKristof Provost 	rules->ticket = nvlist_get_number(nvl, "ticket");
9812b29ceb8SKristof Provost 
982498934c5SKristof Provost out:
9832b29ceb8SKristof Provost 	nvlist_destroy(nvl);
984498934c5SKristof Provost 	return (ret);
9852b29ceb8SKristof Provost }
9862b29ceb8SKristof Provost 
9872b29ceb8SKristof Provost int
pfctl_get_eth_rule(int dev,uint32_t nr,uint32_t ticket,const char * path,struct pfctl_eth_rule * rule,bool clear,char * anchor_call)9882b29ceb8SKristof Provost pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
989c5131afeSKristof Provost     const char *path, struct pfctl_eth_rule *rule, bool clear,
990c5131afeSKristof Provost     char *anchor_call)
9912b29ceb8SKristof Provost {
9922b29ceb8SKristof Provost 	nvlist_t *nvl;
9937ed19f5cSKristof Provost 	int ret;
9942b29ceb8SKristof Provost 
9952b29ceb8SKristof Provost 	nvl = nvlist_create(0);
9962b29ceb8SKristof Provost 
997c5131afeSKristof Provost 	nvlist_add_string(nvl, "anchor", path);
9982b29ceb8SKristof Provost 	nvlist_add_number(nvl, "ticket", ticket);
9992b29ceb8SKristof Provost 	nvlist_add_number(nvl, "nr", nr);
10002b29ceb8SKristof Provost 	nvlist_add_bool(nvl, "clear", clear);
10012b29ceb8SKristof Provost 
10020abcc1d2SReid Linnemann 	if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 4096, &nvl)) != 0)
1003498934c5SKristof Provost 		goto out;
10042b29ceb8SKristof Provost 
10052b29ceb8SKristof Provost 	pfctl_nveth_rule_to_eth_rule(nvl, rule);
10062b29ceb8SKristof Provost 
1007c5131afeSKristof Provost 	if (anchor_call)
1008c5131afeSKristof Provost 		strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
1009c5131afeSKristof Provost 		    MAXPATHLEN);
1010c5131afeSKristof Provost 
1011498934c5SKristof Provost out:
10122b29ceb8SKristof Provost 	nvlist_destroy(nvl);
1013498934c5SKristof Provost 	return (ret);
10142b29ceb8SKristof Provost }
10152b29ceb8SKristof Provost 
10162b29ceb8SKristof Provost int
pfctl_add_eth_rule(int dev,const struct pfctl_eth_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket)1017c5131afeSKristof Provost pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
1018c5131afeSKristof Provost     const char *anchor_call, uint32_t ticket)
10192b29ceb8SKristof Provost {
10202b29ceb8SKristof Provost 	struct pfioc_nv nv;
10212b29ceb8SKristof Provost 	nvlist_t *nvl, *addr;
10222b29ceb8SKristof Provost 	void *packed;
1023514039bbSKristof Provost 	int error = 0;
1024ef661d4aSChristian McDonald 	size_t labelcount, size;
10252b29ceb8SKristof Provost 
10262b29ceb8SKristof Provost 	nvl = nvlist_create(0);
10272b29ceb8SKristof Provost 
10282b29ceb8SKristof Provost 	nvlist_add_number(nvl, "ticket", ticket);
1029c5131afeSKristof Provost 	nvlist_add_string(nvl, "anchor", anchor);
1030c5131afeSKristof Provost 	nvlist_add_string(nvl, "anchor_call", anchor_call);
10312b29ceb8SKristof Provost 
10322b29ceb8SKristof Provost 	nvlist_add_number(nvl, "nr", r->nr);
10332b29ceb8SKristof Provost 	nvlist_add_bool(nvl, "quick", r->quick);
10342b29ceb8SKristof Provost 	nvlist_add_string(nvl, "ifname", r->ifname);
10352b29ceb8SKristof Provost 	nvlist_add_bool(nvl, "ifnot", r->ifnot);
10362b29ceb8SKristof Provost 	nvlist_add_number(nvl, "direction", r->direction);
10372b29ceb8SKristof Provost 	nvlist_add_number(nvl, "proto", r->proto);
10381f61367fSKristof Provost 	nvlist_add_string(nvl, "match_tagname", r->match_tagname);
10391f61367fSKristof Provost 	nvlist_add_bool(nvl, "match_tag_not", r->match_tag_not);
10402b29ceb8SKristof Provost 
10412b29ceb8SKristof Provost 	addr = pfctl_eth_addr_to_nveth_addr(&r->src);
10422b29ceb8SKristof Provost 	if (addr == NULL) {
10432b29ceb8SKristof Provost 		nvlist_destroy(nvl);
10442b29ceb8SKristof Provost 		return (ENOMEM);
10452b29ceb8SKristof Provost 	}
10462b29ceb8SKristof Provost 	nvlist_add_nvlist(nvl, "src", addr);
10472b29ceb8SKristof Provost 	nvlist_destroy(addr);
10482b29ceb8SKristof Provost 
10492b29ceb8SKristof Provost 	addr = pfctl_eth_addr_to_nveth_addr(&r->dst);
10502b29ceb8SKristof Provost 	if (addr == NULL) {
10512b29ceb8SKristof Provost 		nvlist_destroy(nvl);
10522b29ceb8SKristof Provost 		return (ENOMEM);
10532b29ceb8SKristof Provost 	}
10542b29ceb8SKristof Provost 	nvlist_add_nvlist(nvl, "dst", addr);
10552b29ceb8SKristof Provost 	nvlist_destroy(addr);
10562b29ceb8SKristof Provost 
10578a42005dSKristof Provost 	pfctl_nv_add_rule_addr(nvl, "ipsrc", &r->ipsrc);
10588a42005dSKristof Provost 	pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst);
10598a42005dSKristof Provost 
1060ef661d4aSChristian McDonald 	labelcount = 0;
10614abc3b48SKristof Provost 	while (labelcount < PF_RULE_MAX_LABEL_COUNT &&
10624abc3b48SKristof Provost 	    r->label[labelcount][0] != 0) {
1063ef661d4aSChristian McDonald 		nvlist_append_string_array(nvl, "labels",
1064ef661d4aSChristian McDonald 		    r->label[labelcount]);
1065ef661d4aSChristian McDonald 		labelcount++;
1066ef661d4aSChristian McDonald 	}
1067ef661d4aSChristian McDonald 	nvlist_add_number(nvl, "ridentifier", r->ridentifier);
1068ef661d4aSChristian McDonald 
10692b29ceb8SKristof Provost 	nvlist_add_string(nvl, "qname", r->qname);
10702b29ceb8SKristof Provost 	nvlist_add_string(nvl, "tagname", r->tagname);
1071fb330f39SKristof Provost 	nvlist_add_number(nvl, "dnpipe", r->dnpipe);
1072fb330f39SKristof Provost 	nvlist_add_number(nvl, "dnflags", r->dnflags);
1073fb330f39SKristof Provost 
10748a8af942SKristof Provost 	nvlist_add_string(nvl, "bridge_to", r->bridge_to);
10758a8af942SKristof Provost 
10762b29ceb8SKristof Provost 	nvlist_add_number(nvl, "action", r->action);
10772b29ceb8SKristof Provost 
10782b29ceb8SKristof Provost 	packed = nvlist_pack(nvl, &size);
10792b29ceb8SKristof Provost 	if (packed == NULL) {
10802b29ceb8SKristof Provost 		nvlist_destroy(nvl);
10812b29ceb8SKristof Provost 		return (ENOMEM);
10822b29ceb8SKristof Provost 	}
10832b29ceb8SKristof Provost 
10842b29ceb8SKristof Provost 	nv.len = size;
10852b29ceb8SKristof Provost 	nv.size = size;
10862b29ceb8SKristof Provost 	nv.data = packed;
10872b29ceb8SKristof Provost 
1088514039bbSKristof Provost 	if (ioctl(dev, DIOCADDETHRULE, &nv) != 0)
1089514039bbSKristof Provost 		error = errno;
10902b29ceb8SKristof Provost 
10912b29ceb8SKristof Provost 	free(packed);
10922b29ceb8SKristof Provost 	nvlist_destroy(nvl);
10932b29ceb8SKristof Provost 
10942b29ceb8SKristof Provost 	return (error);
10952b29ceb8SKristof Provost }
10962b29ceb8SKristof Provost 
1097ffbf2595SKristof Provost static void
snl_add_msg_attr_addr_wrap(struct snl_writer * nw,uint32_t type,const struct pf_addr_wrap * addr)1098ffbf2595SKristof Provost snl_add_msg_attr_addr_wrap(struct snl_writer *nw, uint32_t type, const struct pf_addr_wrap *addr)
1099ffbf2595SKristof Provost {
1100ffbf2595SKristof Provost 	int off;
1101ffbf2595SKristof Provost 
1102ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1103ffbf2595SKristof Provost 
1104ffbf2595SKristof Provost 	snl_add_msg_attr_ip6(nw, PF_AT_ADDR, &addr->v.a.addr.v6);
1105ffbf2595SKristof Provost 	snl_add_msg_attr_ip6(nw, PF_AT_MASK, &addr->v.a.mask.v6);
1106ffbf2595SKristof Provost 
1107ffbf2595SKristof Provost 	if (addr->type == PF_ADDR_DYNIFTL)
1108ffbf2595SKristof Provost 		snl_add_msg_attr_string(nw, PF_AT_IFNAME, addr->v.ifname);
1109ffbf2595SKristof Provost 	if (addr->type == PF_ADDR_TABLE)
1110ffbf2595SKristof Provost 		snl_add_msg_attr_string(nw, PF_AT_TABLENAME, addr->v.tblname);
1111ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_AT_TYPE, addr->type);
1112ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_AT_IFLAGS, addr->iflags);
1113ffbf2595SKristof Provost 
1114ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1115ffbf2595SKristof Provost }
1116ffbf2595SKristof Provost 
1117ffbf2595SKristof Provost static void
snl_add_msg_attr_pool_addr(struct snl_writer * nw,uint32_t type,const struct pf_pooladdr * pa)1118d909f06bSKristof Provost snl_add_msg_attr_pool_addr(struct snl_writer *nw, uint32_t type, const struct pf_pooladdr *pa)
1119d909f06bSKristof Provost {
1120d909f06bSKristof Provost 	int off;
1121d909f06bSKristof Provost 
1122d909f06bSKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1123d909f06bSKristof Provost 
1124d909f06bSKristof Provost 	snl_add_msg_attr_string(nw, PF_PA_IFNAME, pa->ifname);
1125d909f06bSKristof Provost 	snl_add_msg_attr_addr_wrap(nw, PF_PA_ADDR, &pa->addr);
1126d909f06bSKristof Provost 
1127d909f06bSKristof Provost 	snl_end_attr_nested(nw, off);
1128d909f06bSKristof Provost }
1129d909f06bSKristof Provost 
1130d909f06bSKristof Provost static void
snl_add_msg_attr_rule_addr(struct snl_writer * nw,uint32_t type,const struct pf_rule_addr * addr)1131ffbf2595SKristof Provost snl_add_msg_attr_rule_addr(struct snl_writer *nw, uint32_t type, const struct pf_rule_addr *addr)
1132ffbf2595SKristof Provost {
1133ffbf2595SKristof Provost 	int off;
1134ffbf2595SKristof Provost 
1135ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1136ffbf2595SKristof Provost 
1137ffbf2595SKristof Provost 	snl_add_msg_attr_addr_wrap(nw, PF_RAT_ADDR, &addr->addr);
1138ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RAT_SRC_PORT, addr->port[0]);
1139ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RAT_DST_PORT, addr->port[1]);
1140ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RAT_NEG, addr->neg);
1141ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RAT_OP, addr->port_op);
1142ffbf2595SKristof Provost 
1143ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1144ffbf2595SKristof Provost }
1145ffbf2595SKristof Provost 
1146ffbf2595SKristof Provost static void
snl_add_msg_attr_rule_labels(struct snl_writer * nw,uint32_t type,const char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE])1147ffbf2595SKristof Provost snl_add_msg_attr_rule_labels(struct snl_writer *nw, uint32_t type, const char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE])
1148ffbf2595SKristof Provost {
1149ffbf2595SKristof Provost 	int off, i = 0;
1150ffbf2595SKristof Provost 
1151ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1152ffbf2595SKristof Provost 
1153306d3fb2SKristof Provost 	while (i < PF_RULE_MAX_LABEL_COUNT &&
1154306d3fb2SKristof Provost 	    labels[i][0] != 0) {
1155ffbf2595SKristof Provost 		snl_add_msg_attr_string(nw, PF_LT_LABEL, labels[i]);
1156ffbf2595SKristof Provost 		i++;
1157ffbf2595SKristof Provost 	}
1158ffbf2595SKristof Provost 
1159ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1160ffbf2595SKristof Provost }
1161ffbf2595SKristof Provost 
1162ffbf2595SKristof Provost static void
snl_add_msg_attr_mape(struct snl_writer * nw,uint32_t type,const struct pf_mape_portset * me)1163ffbf2595SKristof Provost snl_add_msg_attr_mape(struct snl_writer *nw, uint32_t type, const struct pf_mape_portset *me)
1164ffbf2595SKristof Provost {
1165ffbf2595SKristof Provost 	int off;
1166ffbf2595SKristof Provost 
1167ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1168ffbf2595SKristof Provost 
1169ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_MET_OFFSET, me->offset);
1170ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_MET_PSID_LEN, me->psidlen);
1171ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_MET_PSID, me->psid);
1172ffbf2595SKristof Provost 
1173ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1174ffbf2595SKristof Provost }
1175ffbf2595SKristof Provost 
1176ffbf2595SKristof Provost static void
snl_add_msg_attr_rpool(struct snl_writer * nw,uint32_t type,const struct pfctl_pool * pool)1177ffbf2595SKristof Provost snl_add_msg_attr_rpool(struct snl_writer *nw, uint32_t type, const struct pfctl_pool *pool)
1178ffbf2595SKristof Provost {
1179ffbf2595SKristof Provost 	int off;
1180ffbf2595SKristof Provost 
1181ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1182ffbf2595SKristof Provost 
1183ffbf2595SKristof Provost 	snl_add_msg_attr(nw, PF_PT_KEY, sizeof(pool->key), &pool->key);
1184ffbf2595SKristof Provost 	snl_add_msg_attr_ip6(nw, PF_PT_COUNTER, &pool->counter.v6);
1185ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_PT_TBLIDX, pool->tblidx);
1186ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
1187ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
1188ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_PT_OPTS, pool->opts);
1189ffbf2595SKristof Provost 	snl_add_msg_attr_mape(nw, PF_PT_MAPE, &pool->mape);
1190ffbf2595SKristof Provost 
1191ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1192ffbf2595SKristof Provost }
1193ffbf2595SKristof Provost 
1194ffbf2595SKristof Provost static void
snl_add_msg_attr_timeouts(struct snl_writer * nw,uint32_t type,const uint32_t * timeouts)1195ffbf2595SKristof Provost snl_add_msg_attr_timeouts(struct snl_writer *nw, uint32_t type, const uint32_t *timeouts)
1196ffbf2595SKristof Provost {
1197ffbf2595SKristof Provost 	int off;
1198ffbf2595SKristof Provost 
1199ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1200ffbf2595SKristof Provost 
1201ffbf2595SKristof Provost 	for (int i = 0; i < PFTM_MAX; i++)
1202ffbf2595SKristof Provost 		snl_add_msg_attr_u32(nw, PF_TT_TIMEOUT, timeouts[i]);
1203ffbf2595SKristof Provost 
1204ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1205ffbf2595SKristof Provost }
1206ffbf2595SKristof Provost 
1207ffbf2595SKristof Provost static void
snl_add_msg_attr_uid(struct snl_writer * nw,uint32_t type,const struct pf_rule_uid * uid)1208ffbf2595SKristof Provost snl_add_msg_attr_uid(struct snl_writer *nw, uint32_t type, const struct pf_rule_uid *uid)
1209ffbf2595SKristof Provost {
1210ffbf2595SKristof Provost 	int off;
1211ffbf2595SKristof Provost 
1212ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1213ffbf2595SKristof Provost 
1214ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RUT_UID_LOW, uid->uid[0]);
1215ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RUT_UID_HIGH, uid->uid[1]);
1216ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RUT_OP, uid->op);
1217ffbf2595SKristof Provost 
1218ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1219ffbf2595SKristof Provost }
1220ffbf2595SKristof Provost 
1221ffbf2595SKristof Provost static void
snl_add_msg_attr_threshold(struct snl_writer * nw,uint32_t type,const struct pfctl_threshold * th)1222ff11f1c8SKristof Provost snl_add_msg_attr_threshold(struct snl_writer *nw, uint32_t type, const struct pfctl_threshold *th)
1223ff11f1c8SKristof Provost {
1224ff11f1c8SKristof Provost 	int off;
1225ff11f1c8SKristof Provost 
1226ff11f1c8SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1227ff11f1c8SKristof Provost 
1228ff11f1c8SKristof Provost 	snl_add_msg_attr_u32(nw, PF_TH_LIMIT, th->limit);
1229ff11f1c8SKristof Provost 	snl_add_msg_attr_u32(nw, PF_TH_SECONDS, th->seconds);
1230ff11f1c8SKristof Provost 
1231ff11f1c8SKristof Provost 	snl_end_attr_nested(nw, off);
1232ff11f1c8SKristof Provost }
1233ff11f1c8SKristof Provost 
1234ff11f1c8SKristof Provost static void
snl_add_msg_attr_pf_rule(struct snl_writer * nw,uint32_t type,const struct pfctl_rule * r)1235ffbf2595SKristof Provost snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfctl_rule *r)
1236ffbf2595SKristof Provost {
1237ffbf2595SKristof Provost 	int off;
1238ffbf2595SKristof Provost 
1239ffbf2595SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
1240ffbf2595SKristof Provost 
1241ffbf2595SKristof Provost 	snl_add_msg_attr_rule_addr(nw, PF_RT_SRC, &r->src);
1242ffbf2595SKristof Provost 	snl_add_msg_attr_rule_addr(nw, PF_RT_DST, &r->dst);
1243ffbf2595SKristof Provost 	snl_add_msg_attr_rule_labels(nw, PF_RT_LABELS, r->label);
1244ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_RIDENTIFIER, r->ridentifier);
1245ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_IFNAME, r->ifname);
1246ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_QNAME, r->qname);
1247ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_PQNAME, r->pqname);
1248ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_TAGNAME, r->tagname);
1249ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_MATCH_TAGNAME, r->match_tagname);
1250ffbf2595SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname);
1251e11dacbfSKristof Provost 	snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RDR, &r->rdr);
1252e11dacbfSKristof Provost 	snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_NAT, &r->nat);
12530972294eSKristof Provost 	snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RT, &r->route);
1254ff11f1c8SKristof Provost 	snl_add_msg_attr_threshold(nw, PF_RT_PKTRATE, &r->pktrate);
1255ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint);
1256ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid);
1257ffbf2595SKristof Provost 	snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout);
1258ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_MAX_STATES, r->max_states);
1259ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_NODES, r->max_src_nodes);
1260ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_STATES, r->max_src_states);
12617fe42038SKajetan Staszkiewicz 	snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN, r->max_src_conn);
1262ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, r->max_src_conn_rate.limit);
1263ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, r->max_src_conn_rate.seconds);
126441fd03c0SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_MAX_PKT_SIZE, r->max_pkt_size);
1265ffbf2595SKristof Provost 
1266ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_DNPIPE, r->dnpipe);
1267ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_DNRPIPE, r->dnrpipe);
1268ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_DNFLAGS, r->free_flags);
1269ffbf2595SKristof Provost 
1270ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_NR, r->nr);
1271ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_PROB, r->prob);
1272ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_CUID, r->cuid);
1273ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_CPID, r->cpid);
1274ffbf2595SKristof Provost 
1275ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP, r->return_icmp);
1276ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP6, r->return_icmp6);
1277ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_MAX_MSS, r->max_mss);
1278ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_SCRUB_FLAGS, r->scrub_flags);
1279ffbf2595SKristof Provost 
1280ffbf2595SKristof Provost 	snl_add_msg_attr_uid(nw, PF_RT_UID, &r->uid);
1281ffbf2595SKristof Provost 	snl_add_msg_attr_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&r->gid);
12822339ead6SKristof Provost 	snl_add_msg_attr_string(nw, PF_RT_RCV_IFNAME, r->rcv_ifname);
128371594e32SKristof Provost 	snl_add_msg_attr_bool(nw, PF_RT_RCV_IFNOT, r->rcvifnot);
1284ffbf2595SKristof Provost 
1285ffbf2595SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_RULE_FLAG, r->rule_flag);
1286ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_ACTION, r->action);
1287ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_DIRECTION, r->direction);
1288ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_LOG, r->log);
1289ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_LOGIF, r->logif);
1290ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_QUICK, r->quick);
1291ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_IF_NOT, r->ifnot);
1292ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_MATCH_TAG_NOT, r->match_tag_not);
1293ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_NATPASS, r->natpass);
1294ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_KEEP_STATE, r->keep_state);
1295ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_AF, r->af);
1296ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_PROTO, r->proto);
1297932ec59dSKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_TYPE_2, r->type);
1298932ec59dSKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_CODE_2, r->code);
1299ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_FLAGS, r->flags);
1300ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_FLAGSET, r->flagset);
1301ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_MIN_TTL, r->min_ttl);
1302ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_ALLOW_OPTS, r->allow_opts);
1303ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_RT, r->rt);
1304ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_RETURN_TTL, r->return_ttl);
1305ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_TOS, r->tos);
1306ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_SET_TOS, r->set_tos);
1307ffbf2595SKristof Provost 
1308ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_RELATIVE, r->anchor_relative);
1309ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_WILDCARD, r->anchor_wildcard);
1310ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_FLUSH, r->flush);
1311ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_PRIO, r->prio);
1312ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO, r->set_prio[0]);
1313ffbf2595SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO_REPLY, r->set_prio[1]);
1314aa69fdf1SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_NAF, r->naf);
1315ffbf2595SKristof Provost 
1316ffbf2595SKristof Provost 	snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6);
1317ffbf2595SKristof Provost 	snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port);
1318ffbf2595SKristof Provost 
13198716d8c7SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_STATE_LIMIT, r->statelim.id);
13208716d8c7SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_STATE_LIMIT_ACTION, r->statelim.limiter_action);
13218716d8c7SKristof Provost 	snl_add_msg_attr_u8(nw, PF_RT_SOURCE_LIMIT, r->sourcelim.id);
13228716d8c7SKristof Provost 	snl_add_msg_attr_u32(nw, PF_RT_SOURCE_LIMIT_ACTION, r->sourcelim.limiter_action);
132346164812SKristof Provost 
1324ffbf2595SKristof Provost 	snl_end_attr_nested(nw, off);
1325ffbf2595SKristof Provost }
1326ffbf2595SKristof Provost 
13270d71f9f3SKristof Provost int
pfctl_add_rule(int dev __unused,const struct pfctl_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket,uint32_t pool_ticket)1328ffbf2595SKristof Provost pfctl_add_rule(int dev __unused, const struct pfctl_rule *r, const char *anchor,
13297bb3c927SKristof Provost     const char *anchor_call, uint32_t ticket, uint32_t pool_ticket)
13300d71f9f3SKristof Provost {
1331324fd7ecSKristof Provost 	struct pfctl_handle *h;
1332324fd7ecSKristof Provost 	int ret;
1333324fd7ecSKristof Provost 
1334324fd7ecSKristof Provost 	h = pfctl_open(PF_DEVICE);
1335324fd7ecSKristof Provost 	if (h == NULL)
1336324fd7ecSKristof Provost 		return (ENODEV);
1337324fd7ecSKristof Provost 
1338324fd7ecSKristof Provost 	ret = pfctl_add_rule_h(h, r, anchor, anchor_call, ticket, pool_ticket);
1339324fd7ecSKristof Provost 
1340324fd7ecSKristof Provost 	pfctl_close(h);
1341324fd7ecSKristof Provost 
1342324fd7ecSKristof Provost 	return (ret);
1343324fd7ecSKristof Provost }
1344324fd7ecSKristof Provost 
1345324fd7ecSKristof Provost int
pfctl_add_rule_h(struct pfctl_handle * h,const struct pfctl_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket,uint32_t pool_ticket)1346324fd7ecSKristof Provost pfctl_add_rule_h(struct pfctl_handle *h, const struct pfctl_rule *r,
1347324fd7ecSKristof Provost 	    const char *anchor, const char *anchor_call, uint32_t ticket,
1348324fd7ecSKristof Provost 	    uint32_t pool_ticket)
1349324fd7ecSKristof Provost {
1350ffbf2595SKristof Provost 	struct snl_writer nw;
1351ffbf2595SKristof Provost 	struct snl_errmsg_data e = {};
1352ffbf2595SKristof Provost 	struct nlmsghdr *hdr;
1353ffbf2595SKristof Provost 	uint32_t seq_id;
1354ffbf2595SKristof Provost 	int family_id;
13550d71f9f3SKristof Provost 
1356324fd7ecSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
1357497ccc21SKristof Provost 	if (family_id == 0)
1358497ccc21SKristof Provost 		return (ENOTSUP);
13590d71f9f3SKristof Provost 
1360324fd7ecSKristof Provost 	snl_init_writer(&h->ss, &nw);
1361ffbf2595SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_ADDRULE);
1362ffbf2595SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
1363ffbf2595SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_ART_TICKET, ticket);
1364ffbf2595SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_ART_POOL_TICKET, pool_ticket);
1365ffbf2595SKristof Provost 	snl_add_msg_attr_string(&nw, PF_ART_ANCHOR, anchor);
1366ffbf2595SKristof Provost 	snl_add_msg_attr_string(&nw, PF_ART_ANCHOR_CALL, anchor_call);
13670d71f9f3SKristof Provost 
1368ffbf2595SKristof Provost 	snl_add_msg_attr_pf_rule(&nw, PF_ART_RULE, r);
13690d71f9f3SKristof Provost 
1370ffbf2595SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
1371ffbf2595SKristof Provost 		return (ENXIO);
1372ffbf2595SKristof Provost 
1373ffbf2595SKristof Provost 	seq_id = hdr->nlmsg_seq;
1374ffbf2595SKristof Provost 
1375324fd7ecSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
1376ffbf2595SKristof Provost 		return (ENXIO);
13776fcc8e04SKristof Provost 
1378324fd7ecSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1379ffbf2595SKristof Provost 	}
13800d71f9f3SKristof Provost 
1381ffbf2595SKristof Provost 	return (e.error);
13820d71f9f3SKristof Provost }
13830d6c8174SKristof Provost 
138444f323ecSKristof Provost #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
138544f323ecSKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_rules_info, _field)
138644f323ecSKristof Provost static struct snl_attr_parser ap_getrules[] = {
138744f323ecSKristof Provost 	{ .type = PF_GR_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
138844f323ecSKristof Provost 	{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
138944f323ecSKristof Provost };
139044f323ecSKristof Provost #undef _IN
139144f323ecSKristof Provost #undef _OUT
13927c882c69SKristof Provost SNL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, snl_f_p_empty, ap_getrules);
139344f323ecSKristof Provost 
13940d6c8174SKristof Provost int
pfctl_get_rules_info_h(struct pfctl_handle * h,struct pfctl_rules_info * rules,uint32_t ruleset,const char * path)1395f1612e70SKristof Provost pfctl_get_rules_info_h(struct pfctl_handle *h, struct pfctl_rules_info *rules, uint32_t ruleset,
13968c1400b0SKristof Provost     const char *path)
13978c1400b0SKristof Provost {
139844f323ecSKristof Provost 	struct snl_errmsg_data e = {};
139944f323ecSKristof Provost 	struct nlmsghdr *hdr;
140044f323ecSKristof Provost 	struct snl_writer nw;
140144f323ecSKristof Provost 	uint32_t seq_id;
140244f323ecSKristof Provost 	int family_id;
14038c1400b0SKristof Provost 
1404f1612e70SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
140544f323ecSKristof Provost 	if (family_id == 0)
140644f323ecSKristof Provost 		return (ENOTSUP);
14078c1400b0SKristof Provost 
1408f1612e70SKristof Provost 	snl_init_writer(&h->ss, &nw);
140944f323ecSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULES);
141044f323ecSKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
14118c1400b0SKristof Provost 
141244f323ecSKristof Provost 	snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, path);
141344f323ecSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset);
14148c1400b0SKristof Provost 
141544f323ecSKristof Provost 	hdr = snl_finalize_msg(&nw);
141644f323ecSKristof Provost 	if (hdr == NULL)
141744f323ecSKristof Provost 		return (ENOMEM);
141844f323ecSKristof Provost 
141944f323ecSKristof Provost 	seq_id = hdr->nlmsg_seq;
1420f1612e70SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
142144f323ecSKristof Provost 		return (ENXIO);
142244f323ecSKristof Provost 
1423f1612e70SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1424f1612e70SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &getrules_parser, rules))
142544f323ecSKristof Provost 			continue;
142644f323ecSKristof Provost 	}
142744f323ecSKristof Provost 
142844f323ecSKristof Provost 	return (e.error);
14298c1400b0SKristof Provost }
14308c1400b0SKristof Provost 
14318c1400b0SKristof Provost int
pfctl_get_rules_info(int dev __unused,struct pfctl_rules_info * rules,uint32_t ruleset,const char * path)1432f1612e70SKristof Provost pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset,
1433f1612e70SKristof Provost     const char *path)
1434f1612e70SKristof Provost {
1435f1612e70SKristof Provost 	struct pfctl_handle *h;
1436f1612e70SKristof Provost 	int error;
1437f1612e70SKristof Provost 
1438f1612e70SKristof Provost 	h = pfctl_open(PF_DEVICE);
1439f1612e70SKristof Provost 	if (h == NULL)
1440f1612e70SKristof Provost 		return (ENOTSUP);
1441f1612e70SKristof Provost 	error = pfctl_get_rules_info_h(h, rules, ruleset, path);
1442f1612e70SKristof Provost 	pfctl_close(h);
1443f1612e70SKristof Provost 
1444f1612e70SKristof Provost 	return (error);
1445f1612e70SKristof Provost }
1446f1612e70SKristof Provost 
1447f1612e70SKristof Provost int
pfctl_get_rule_h(struct pfctl_handle * h,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call)1448cd2054d4SKristof Provost pfctl_get_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket, const char *anchor,
1449cd2054d4SKristof Provost     uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
1450cd2054d4SKristof Provost {
1451cd2054d4SKristof Provost 	return (pfctl_get_clear_rule_h(h, nr, ticket, anchor, ruleset, rule,
1452cd2054d4SKristof Provost 	    anchor_call, false));
1453cd2054d4SKristof Provost }
1454cd2054d4SKristof Provost 
1455cd2054d4SKristof Provost int
pfctl_get_rule(int dev,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call)14567bb3c927SKristof Provost pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor,
14577bb3c927SKristof Provost     uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
14580d6c8174SKristof Provost {
14594eabfe46SKristof Provost 	return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule,
14604eabfe46SKristof Provost 	    anchor_call, false));
14614eabfe46SKristof Provost }
14624eabfe46SKristof Provost 
1463777a4702SKristof Provost #define _OUT(_field)	offsetof(struct pf_addr_wrap, _field)
1464777a4702SKristof Provost static const struct snl_attr_parser ap_addr_wrap[] = {
1465777a4702SKristof Provost 	{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = snl_attr_get_in6_addr },
1466777a4702SKristof Provost 	{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = snl_attr_get_in6_addr },
1467777a4702SKristof Provost 	{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = snl_attr_copy_string },
1468777a4702SKristof Provost 	{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
1469777a4702SKristof Provost 	{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
1470777a4702SKristof Provost 	{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = snl_attr_get_uint8 },
1471777a4702SKristof Provost 	{ .type = PF_AT_TBLCNT, .off = _OUT(p.tblcnt), .cb = snl_attr_get_uint32 },
1472777a4702SKristof Provost 	{ .type = PF_AT_DYNCNT, .off = _OUT(p.dyncnt), .cb = snl_attr_get_uint32 },
1473777a4702SKristof Provost };
1474777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(addr_wrap_parser, ap_addr_wrap);
1475777a4702SKristof Provost #undef _OUT
1476777a4702SKristof Provost 
1477777a4702SKristof Provost #define _OUT(_field)	offsetof(struct pf_rule_addr, _field)
1478777a4702SKristof Provost static struct snl_attr_parser ap_rule_addr[] = {
1479777a4702SKristof Provost 	{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
1480777a4702SKristof Provost 	{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 },
1481777a4702SKristof Provost 	{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 },
1482777a4702SKristof Provost 	{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = snl_attr_get_uint8 },
1483777a4702SKristof Provost 	{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = snl_attr_get_uint8 },
1484777a4702SKristof Provost };
1485777a4702SKristof Provost #undef _OUT
1486777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(rule_addr_parser, ap_rule_addr);
1487777a4702SKristof Provost 
1488777a4702SKristof Provost struct snl_parsed_labels
1489777a4702SKristof Provost {
1490777a4702SKristof Provost 	char		labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
1491777a4702SKristof Provost 	uint32_t	i;
1492777a4702SKristof Provost };
1493777a4702SKristof Provost 
1494777a4702SKristof Provost static bool
snl_attr_get_pf_rule_labels(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1495777a4702SKristof Provost snl_attr_get_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
1496777a4702SKristof Provost     const void *arg __unused, void *target)
1497777a4702SKristof Provost {
1498777a4702SKristof Provost 	struct snl_parsed_labels *l = (struct snl_parsed_labels *)target;
1499777a4702SKristof Provost 	bool ret;
1500777a4702SKristof Provost 
1501777a4702SKristof Provost 	if (l->i >= PF_RULE_MAX_LABEL_COUNT)
15029bb1c46bSKristof Provost 		return (false);
1503777a4702SKristof Provost 
1504777a4702SKristof Provost 	ret = snl_attr_copy_string(ss, nla, (void *)PF_RULE_LABEL_SIZE,
1505777a4702SKristof Provost 	    l->labels[l->i]);
1506777a4702SKristof Provost 	if (ret)
1507777a4702SKristof Provost 		l->i++;
1508777a4702SKristof Provost 
1509777a4702SKristof Provost 	return (ret);
1510777a4702SKristof Provost }
1511777a4702SKristof Provost 
1512777a4702SKristof Provost #define _OUT(_field)	offsetof(struct nl_parsed_labels, _field)
1513777a4702SKristof Provost static const struct snl_attr_parser ap_labels[] = {
1514777a4702SKristof Provost 	{ .type = PF_LT_LABEL, .off = 0, .cb = snl_attr_get_pf_rule_labels },
1515777a4702SKristof Provost };
1516777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(rule_labels_parser, ap_labels);
1517777a4702SKristof Provost #undef _OUT
1518777a4702SKristof Provost 
1519777a4702SKristof Provost static bool
snl_attr_get_nested_pf_rule_labels(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1520777a4702SKristof Provost snl_attr_get_nested_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
1521777a4702SKristof Provost     const void *arg __unused, void *target)
1522777a4702SKristof Provost {
1523777a4702SKristof Provost 	struct snl_parsed_labels parsed_labels = { };
1524777a4702SKristof Provost 	bool error;
1525777a4702SKristof Provost 
1526777a4702SKristof Provost 	/* Assumes target points to the beginning of the structure */
1527777a4702SKristof Provost 	error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, &parsed_labels);
1528777a4702SKristof Provost 	if (! error)
1529777a4702SKristof Provost 		return (error);
1530777a4702SKristof Provost 
153188f557a2SKristof Provost 	memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
1532777a4702SKristof Provost 
1533777a4702SKristof Provost 	return (true);
1534777a4702SKristof Provost }
1535777a4702SKristof Provost 
1536777a4702SKristof Provost #define _OUT(_field)	offsetof(struct pf_mape_portset, _field)
1537777a4702SKristof Provost static const struct snl_attr_parser ap_mape_portset[] = {
1538777a4702SKristof Provost 	{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = snl_attr_get_uint8 },
1539777a4702SKristof Provost 	{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = snl_attr_get_uint8 },
1540777a4702SKristof Provost 	{. type = PF_MET_PSID, .off = _OUT(psid), .cb = snl_attr_get_uint16 },
1541777a4702SKristof Provost };
1542777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(mape_portset_parser, ap_mape_portset);
1543777a4702SKristof Provost #undef _OUT
1544777a4702SKristof Provost 
1545777a4702SKristof Provost #define _OUT(_field)	offsetof(struct pfctl_pool, _field)
1546777a4702SKristof Provost static const struct snl_attr_parser ap_pool[] = {
1547777a4702SKristof Provost 	{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = snl_attr_get_bytes },
1548777a4702SKristof Provost 	{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = snl_attr_get_in6_addr },
1549777a4702SKristof Provost 	{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = snl_attr_get_uint32 },
1550777a4702SKristof Provost 	{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = snl_attr_get_uint16 },
1551777a4702SKristof Provost 	{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = snl_attr_get_uint16 },
1552777a4702SKristof Provost 	{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = snl_attr_get_uint8 },
1553777a4702SKristof Provost 	{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = snl_attr_get_nested },
1554777a4702SKristof Provost };
1555777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(pool_parser, ap_pool);
1556777a4702SKristof Provost #undef _OUT
1557777a4702SKristof Provost 
1558777a4702SKristof Provost struct nl_parsed_timeouts
1559777a4702SKristof Provost {
1560777a4702SKristof Provost 	uint32_t	timeouts[PFTM_MAX];
1561777a4702SKristof Provost 	uint32_t	i;
1562777a4702SKristof Provost };
1563777a4702SKristof Provost 
1564777a4702SKristof Provost static bool
snl_attr_get_pf_timeout(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1565777a4702SKristof Provost snl_attr_get_pf_timeout(struct snl_state *ss, struct nlattr *nla,
1566777a4702SKristof Provost     const void *arg __unused, void *target)
1567777a4702SKristof Provost {
1568777a4702SKristof Provost 	struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
1569777a4702SKristof Provost 	bool ret;
1570777a4702SKristof Provost 
1571777a4702SKristof Provost 	if (t->i >= PFTM_MAX)
15729bb1c46bSKristof Provost 		return (false);
1573777a4702SKristof Provost 
1574777a4702SKristof Provost 	ret = snl_attr_get_uint32(ss, nla, NULL, &t->timeouts[t->i]);
1575777a4702SKristof Provost 	if (ret)
1576777a4702SKristof Provost 		t->i++;
1577777a4702SKristof Provost 
1578777a4702SKristof Provost 	return (ret);
1579777a4702SKristof Provost }
1580777a4702SKristof Provost 
1581777a4702SKristof Provost #define _OUT(_field)	offsetof(struct nl_parsed_timeout, _field)
1582777a4702SKristof Provost static const struct snl_attr_parser ap_timeouts[] = {
1583777a4702SKristof Provost 	{ .type = PF_TT_TIMEOUT, .off = 0, .cb = snl_attr_get_pf_timeout },
1584777a4702SKristof Provost };
1585777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(timeout_parser, ap_timeouts);
1586777a4702SKristof Provost #undef _OUT
1587777a4702SKristof Provost 
1588777a4702SKristof Provost static bool
snl_attr_get_nested_timeouts(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1589777a4702SKristof Provost snl_attr_get_nested_timeouts(struct snl_state *ss, struct nlattr *nla,
1590777a4702SKristof Provost     const void *arg __unused, void *target)
1591777a4702SKristof Provost {
1592777a4702SKristof Provost 	struct nl_parsed_timeouts parsed_timeouts = { };
1593777a4702SKristof Provost 	bool error;
1594777a4702SKristof Provost 
1595777a4702SKristof Provost 	/* Assumes target points to the beginning of the structure */
1596777a4702SKristof Provost 	error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, &parsed_timeouts);
1597777a4702SKristof Provost 	if (! error)
1598777a4702SKristof Provost 		return (error);
1599777a4702SKristof Provost 
1600777a4702SKristof Provost 	memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
1601777a4702SKristof Provost 
1602777a4702SKristof Provost 	return (true);
1603777a4702SKristof Provost }
1604777a4702SKristof Provost 
1605777a4702SKristof Provost #define _OUT(_field)	offsetof(struct pf_rule_uid, _field)
1606777a4702SKristof Provost static const struct snl_attr_parser ap_rule_uid[] = {
1607777a4702SKristof Provost 	{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = snl_attr_get_uint32 },
1608777a4702SKristof Provost 	{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = snl_attr_get_uint32 },
1609777a4702SKristof Provost 	{ .type = PF_RUT_OP, .off = _OUT(op), .cb = snl_attr_get_uint8 },
1610777a4702SKristof Provost };
1611777a4702SKristof Provost SNL_DECLARE_ATTR_PARSER(rule_uid_parser, ap_rule_uid);
1612777a4702SKristof Provost #undef _OUT
1613777a4702SKristof Provost 
1614ff11f1c8SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_threshold, _field)
1615ff11f1c8SKristof Provost static const struct snl_attr_parser ap_pfctl_threshold[] = {
1616ff11f1c8SKristof Provost 	{ .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
1617ff11f1c8SKristof Provost 	{ .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
1618ff11f1c8SKristof Provost 	{ .type = PF_TH_COUNT, .off = _OUT(count), .cb = snl_attr_get_uint32 },
1619ff11f1c8SKristof Provost };
1620ff11f1c8SKristof Provost SNL_DECLARE_ATTR_PARSER(pfctl_threshold_parser, ap_pfctl_threshold);
1621ff11f1c8SKristof Provost #undef _OUT
1622ff11f1c8SKristof Provost 
1623777a4702SKristof Provost struct pfctl_nl_get_rule {
1624777a4702SKristof Provost 	struct pfctl_rule r;
1625777a4702SKristof Provost 	char anchor_call[MAXPATHLEN];
1626777a4702SKristof Provost };
1627777a4702SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_nl_get_rule, _field)
1628777a4702SKristof Provost static struct snl_attr_parser ap_getrule[] = {
1629777a4702SKristof Provost 	{ .type = PF_RT_SRC, .off = _OUT(r.src), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
1630777a4702SKristof Provost 	{ .type = PF_RT_DST, .off = _OUT(r.dst), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
1631777a4702SKristof Provost 	{ .type = PF_RT_RIDENTIFIER, .off = _OUT(r.ridentifier), .cb = snl_attr_get_uint32 },
1632777a4702SKristof Provost 	{ .type = PF_RT_LABELS, .off = _OUT(r.label), .arg = &rule_labels_parser,.cb = snl_attr_get_nested_pf_rule_labels },
1633777a4702SKristof Provost 	{ .type = PF_RT_IFNAME, .off = _OUT(r.ifname), .arg = (void *)IFNAMSIZ, .cb = snl_attr_copy_string },
1634777a4702SKristof Provost 	{ .type = PF_RT_QNAME, .off = _OUT(r.qname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
1635777a4702SKristof Provost 	{ .type = PF_RT_PQNAME, .off = _OUT(r.pqname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
1636777a4702SKristof Provost 	{ .type = PF_RT_TAGNAME, .off = _OUT(r.tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
1637777a4702SKristof Provost 	{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(r.match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
1638777a4702SKristof Provost 	{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(r.overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
1639e11dacbfSKristof Provost 	{ .type = PF_RT_RPOOL_RDR, .off = _OUT(r.rdr), .arg = &pool_parser, .cb = snl_attr_get_nested },
1640777a4702SKristof Provost 	{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(r.os_fingerprint), .cb = snl_attr_get_uint32 },
1641777a4702SKristof Provost 	{ .type = PF_RT_RTABLEID, .off = _OUT(r.rtableid), .cb = snl_attr_get_uint32 },
1642777a4702SKristof Provost 	{ .type = PF_RT_TIMEOUT, .off = _OUT(r.timeout), .arg = &timeout_parser, .cb = snl_attr_get_nested_timeouts },
1643777a4702SKristof Provost 	{ .type = PF_RT_MAX_STATES, .off = _OUT(r.max_states), .cb = snl_attr_get_uint32 },
1644777a4702SKristof Provost 	{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(r.max_src_nodes), .cb = snl_attr_get_uint32 },
1645777a4702SKristof Provost 	{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(r.max_src_states), .cb = snl_attr_get_uint32 },
1646777a4702SKristof Provost 	{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(r.max_src_conn_rate.limit), .cb = snl_attr_get_uint32 },
1647777a4702SKristof Provost 	{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(r.max_src_conn_rate.seconds), .cb = snl_attr_get_uint32 },
1648777a4702SKristof Provost 	{ .type = PF_RT_DNPIPE, .off = _OUT(r.dnpipe), .cb = snl_attr_get_uint16 },
1649777a4702SKristof Provost 	{ .type = PF_RT_DNRPIPE, .off = _OUT(r.dnrpipe), .cb = snl_attr_get_uint16 },
1650777a4702SKristof Provost 	{ .type = PF_RT_DNFLAGS, .off = _OUT(r.free_flags), .cb = snl_attr_get_uint32 },
1651777a4702SKristof Provost 	{ .type = PF_RT_NR, .off = _OUT(r.nr), .cb = snl_attr_get_uint32 },
1652777a4702SKristof Provost 	{ .type = PF_RT_PROB, .off = _OUT(r.prob), .cb = snl_attr_get_uint32 },
1653777a4702SKristof Provost 	{ .type = PF_RT_CUID, .off = _OUT(r.cuid), .cb = snl_attr_get_uint32 },
1654777a4702SKristof Provost 	{. type = PF_RT_CPID, .off = _OUT(r.cpid), .cb = snl_attr_get_uint32 },
1655777a4702SKristof Provost 	{ .type = PF_RT_RETURN_ICMP, .off = _OUT(r.return_icmp), .cb = snl_attr_get_uint16 },
1656777a4702SKristof Provost 	{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(r.return_icmp6), .cb = snl_attr_get_uint16 },
1657777a4702SKristof Provost 	{ .type = PF_RT_MAX_MSS, .off = _OUT(r.max_mss), .cb = snl_attr_get_uint16 },
1658777a4702SKristof Provost 	{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(r.scrub_flags), .cb = snl_attr_get_uint16 },
1659777a4702SKristof Provost 	{ .type = PF_RT_UID, .off = _OUT(r.uid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
1660777a4702SKristof Provost 	{ .type = PF_RT_GID, .off = _OUT(r.gid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
1661777a4702SKristof Provost 	{ .type = PF_RT_RULE_FLAG, .off = _OUT(r.rule_flag), .cb = snl_attr_get_uint32 },
1662777a4702SKristof Provost 	{ .type = PF_RT_ACTION, .off = _OUT(r.action), .cb = snl_attr_get_uint8 },
1663777a4702SKristof Provost 	{ .type = PF_RT_DIRECTION, .off = _OUT(r.direction), .cb = snl_attr_get_uint8 },
1664777a4702SKristof Provost 	{ .type = PF_RT_LOG, .off = _OUT(r.log), .cb = snl_attr_get_uint8 },
1665777a4702SKristof Provost 	{ .type = PF_RT_LOGIF, .off = _OUT(r.logif), .cb = snl_attr_get_uint8 },
1666777a4702SKristof Provost 	{ .type = PF_RT_QUICK, .off = _OUT(r.quick), .cb = snl_attr_get_uint8 },
1667777a4702SKristof Provost 	{ .type = PF_RT_IF_NOT, .off = _OUT(r.ifnot), .cb = snl_attr_get_uint8 },
1668777a4702SKristof Provost 	{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(r.match_tag_not), .cb = snl_attr_get_uint8 },
1669777a4702SKristof Provost 	{ .type = PF_RT_NATPASS, .off = _OUT(r.natpass), .cb = snl_attr_get_uint8 },
1670777a4702SKristof Provost 	{ .type = PF_RT_KEEP_STATE, .off = _OUT(r.keep_state), .cb = snl_attr_get_uint8 },
1671777a4702SKristof Provost 	{ .type = PF_RT_AF, .off = _OUT(r.af), .cb = snl_attr_get_uint8 },
1672777a4702SKristof Provost 	{ .type = PF_RT_PROTO, .off = _OUT(r.proto), .cb = snl_attr_get_uint8 },
1673777a4702SKristof Provost 	{ .type = PF_RT_TYPE, .off = _OUT(r.type), .cb = snl_attr_get_uint8 },
1674777a4702SKristof Provost 	{ .type = PF_RT_CODE, .off = _OUT(r.code), .cb = snl_attr_get_uint8 },
1675777a4702SKristof Provost 	{ .type = PF_RT_FLAGS, .off = _OUT(r.flags), .cb = snl_attr_get_uint8 },
1676777a4702SKristof Provost 	{ .type = PF_RT_FLAGSET, .off = _OUT(r.flagset), .cb = snl_attr_get_uint8 },
1677777a4702SKristof Provost 	{ .type = PF_RT_MIN_TTL, .off = _OUT(r.min_ttl), .cb = snl_attr_get_uint8 },
1678777a4702SKristof Provost 	{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(r.allow_opts), .cb = snl_attr_get_uint8 },
1679777a4702SKristof Provost 	{ .type = PF_RT_RT, .off = _OUT(r.rt), .cb = snl_attr_get_uint8 },
1680777a4702SKristof Provost 	{ .type = PF_RT_RETURN_TTL, .off = _OUT(r.return_ttl), .cb = snl_attr_get_uint8 },
1681777a4702SKristof Provost 	{ .type = PF_RT_TOS, .off = _OUT(r.tos), .cb = snl_attr_get_uint8 },
1682777a4702SKristof Provost 	{ .type = PF_RT_SET_TOS, .off = _OUT(r.set_tos), .cb = snl_attr_get_uint8 },
1683777a4702SKristof Provost 	{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(r.anchor_relative), .cb = snl_attr_get_uint8 },
1684777a4702SKristof Provost 	{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(r.anchor_wildcard), .cb = snl_attr_get_uint8 },
1685777a4702SKristof Provost 	{ .type = PF_RT_FLUSH, .off = _OUT(r.flush), .cb = snl_attr_get_uint8 },
1686777a4702SKristof Provost 	{ .type = PF_RT_PRIO, .off = _OUT(r.prio), .cb = snl_attr_get_uint8 },
1687777a4702SKristof Provost 	{ .type = PF_RT_SET_PRIO, .off = _OUT(r.set_prio[0]), .cb = snl_attr_get_uint8 },
1688777a4702SKristof Provost 	{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(r.set_prio[1]), .cb = snl_attr_get_uint8 },
1689777a4702SKristof Provost 	{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(r.divert.addr), .cb = snl_attr_get_in6_addr },
1690777a4702SKristof Provost 	{ .type = PF_RT_DIVERT_PORT, .off = _OUT(r.divert.port), .cb = snl_attr_get_uint16 },
1691777a4702SKristof Provost 	{ .type = PF_RT_PACKETS_IN, .off = _OUT(r.packets[0]), .cb = snl_attr_get_uint64 },
1692777a4702SKristof Provost 	{ .type = PF_RT_PACKETS_OUT, .off = _OUT(r.packets[1]), .cb = snl_attr_get_uint64 },
1693777a4702SKristof Provost 	{ .type = PF_RT_BYTES_IN, .off = _OUT(r.bytes[0]), .cb = snl_attr_get_uint64 },
1694777a4702SKristof Provost 	{ .type = PF_RT_BYTES_OUT, .off = _OUT(r.bytes[1]), .cb = snl_attr_get_uint64 },
1695777a4702SKristof Provost 	{ .type = PF_RT_EVALUATIONS, .off = _OUT(r.evaluations), .cb = snl_attr_get_uint64 },
1696777a4702SKristof Provost 	{ .type = PF_RT_TIMESTAMP, .off = _OUT(r.last_active_timestamp), .cb = snl_attr_get_uint64 },
1697777a4702SKristof Provost 	{ .type = PF_RT_STATES_CUR, .off = _OUT(r.states_cur), .cb = snl_attr_get_uint64 },
1698777a4702SKristof Provost 	{ .type = PF_RT_STATES_TOTAL, .off = _OUT(r.states_tot), .cb = snl_attr_get_uint64 },
1699777a4702SKristof Provost 	{ .type = PF_RT_SRC_NODES, .off = _OUT(r.src_nodes), .cb = snl_attr_get_uint64 },
1700777a4702SKristof Provost 	{ .type = PF_RT_ANCHOR_CALL, .off = _OUT(anchor_call), .arg = (void*)MAXPATHLEN, .cb = snl_attr_copy_string },
17012339ead6SKristof Provost 	{ .type = PF_RT_RCV_IFNAME, .off = _OUT(r.rcv_ifname), .arg = (void*)IFNAMSIZ, .cb = snl_attr_copy_string },
17027fe42038SKajetan Staszkiewicz 	{ .type = PF_RT_MAX_SRC_CONN, .off = _OUT(r.max_src_conn), .cb = snl_attr_get_uint32 },
1703e11dacbfSKristof Provost 	{ .type = PF_RT_RPOOL_NAT, .off = _OUT(r.nat), .arg = &pool_parser, .cb = snl_attr_get_nested },
1704aa69fdf1SKristof Provost 	{ .type = PF_RT_NAF, .off = _OUT(r.naf), .cb = snl_attr_get_uint8 },
17050972294eSKristof Provost 	{ .type = PF_RT_RPOOL_RT, .off = _OUT(r.route), .arg = &pool_parser, .cb = snl_attr_get_nested },
170671594e32SKristof Provost 	{ .type = PF_RT_RCV_IFNOT, .off = _OUT(r.rcvifnot),.cb = snl_attr_get_bool },
170707e070efSKajetan Staszkiewicz 	{ .type = PF_RT_SRC_NODES_LIMIT, .off = _OUT(r.src_nodes_type[PF_SN_LIMIT]), .cb = snl_attr_get_uint64 },
170807e070efSKajetan Staszkiewicz 	{ .type = PF_RT_SRC_NODES_NAT, .off = _OUT(r.src_nodes_type[PF_SN_NAT]), .cb = snl_attr_get_uint64 },
170907e070efSKajetan Staszkiewicz 	{ .type = PF_RT_SRC_NODES_ROUTE, .off = _OUT(r.src_nodes_type[PF_SN_ROUTE]), .cb = snl_attr_get_uint64 },
1710ff11f1c8SKristof Provost 	{ .type = PF_RT_PKTRATE, .off = _OUT(r.pktrate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
171141fd03c0SKristof Provost 	{ .type = PF_RT_MAX_PKT_SIZE, .off =_OUT(r.max_pkt_size), .cb = snl_attr_get_uint16 },
1712932ec59dSKristof Provost 	{ .type = PF_RT_TYPE_2, .off = _OUT(r.type), .cb = snl_attr_get_uint16 },
1713932ec59dSKristof Provost 	{ .type = PF_RT_CODE_2, .off = _OUT(r.code), .cb = snl_attr_get_uint16 },
1714b84666f7SKristof Provost 	{ .type = PF_RT_EXPTIME, .off = _OUT(r.exptime), .cb = snl_attr_get_time_t },
17158716d8c7SKristof Provost 	{ .type = PF_RT_STATE_LIMIT, .off = _OUT(r.statelim.id), .cb = snl_attr_get_uint8 },
17168716d8c7SKristof Provost 	{ .type = PF_RT_SOURCE_LIMIT, .off = _OUT(r.sourcelim.id), .cb = snl_attr_get_uint8 },
17178716d8c7SKristof Provost 	{ .type = PF_RT_STATE_LIMIT_ACTION, .off = _OUT(r.statelim.limiter_action), .cb = snl_attr_get_uint32 },
17188716d8c7SKristof Provost 	{ .type = PF_RT_SOURCE_LIMIT_ACTION, .off = _OUT(r.sourcelim.limiter_action), .cb = snl_attr_get_uint32 },
1719777a4702SKristof Provost };
1720777a4702SKristof Provost #undef _OUT
17217c882c69SKristof Provost SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule);
1722777a4702SKristof Provost 
1723777a4702SKristof Provost int
pfctl_get_clear_rule_h(struct pfctl_handle * h,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call,bool clear)1724777a4702SKristof Provost pfctl_get_clear_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket,
1725777a4702SKristof Provost     const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
1726777a4702SKristof Provost     char *anchor_call, bool clear)
1727777a4702SKristof Provost {
1728777a4702SKristof Provost 	struct pfctl_nl_get_rule attrs = {};
1729777a4702SKristof Provost 	struct snl_errmsg_data e = {};
1730777a4702SKristof Provost 	struct nlmsghdr *hdr;
1731777a4702SKristof Provost 	struct snl_writer nw;
1732777a4702SKristof Provost 	uint32_t seq_id;
1733777a4702SKristof Provost 	int family_id;
1734777a4702SKristof Provost 
1735777a4702SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
1736777a4702SKristof Provost 	if (family_id == 0)
1737777a4702SKristof Provost 		return (ENOTSUP);
1738777a4702SKristof Provost 
1739777a4702SKristof Provost 	snl_init_writer(&h->ss, &nw);
1740777a4702SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULE);
1741777a4702SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
1742777a4702SKristof Provost 
1743777a4702SKristof Provost 	snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, anchor);
1744777a4702SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset);
1745777a4702SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_GR_NR, nr);
1746777a4702SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_GR_TICKET, ticket);
1747777a4702SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_GR_CLEAR, clear);
1748777a4702SKristof Provost 
1749777a4702SKristof Provost 	hdr = snl_finalize_msg(&nw);
1750777a4702SKristof Provost 	if (hdr == NULL)
1751777a4702SKristof Provost 		return (ENOMEM);
1752777a4702SKristof Provost 
1753777a4702SKristof Provost 	seq_id = hdr->nlmsg_seq;
1754777a4702SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
1755777a4702SKristof Provost 		return (ENXIO);
1756777a4702SKristof Provost 
1757777a4702SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1758777a4702SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &getrule_parser, &attrs))
1759777a4702SKristof Provost 			continue;
1760777a4702SKristof Provost 	}
1761777a4702SKristof Provost 
1762777a4702SKristof Provost 	memcpy(rule, &attrs.r, sizeof(attrs.r));
1763777a4702SKristof Provost 	strlcpy(anchor_call, attrs.anchor_call, MAXPATHLEN);
1764777a4702SKristof Provost 
1765777a4702SKristof Provost 	return (e.error);
1766777a4702SKristof Provost }
1767777a4702SKristof Provost 
1768777a4702SKristof Provost int
pfctl_get_clear_rule(int dev,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call,bool clear)1769777a4702SKristof Provost pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
17707bb3c927SKristof Provost 	    const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
17714eabfe46SKristof Provost 	    char *anchor_call, bool clear)
17724eabfe46SKristof Provost {
17730d6c8174SKristof Provost 	nvlist_t *nvl;
17740d6c8174SKristof Provost 	int ret;
17750d6c8174SKristof Provost 
17760d6c8174SKristof Provost 	nvl = nvlist_create(0);
17770d6c8174SKristof Provost 	if (nvl == 0)
17780d6c8174SKristof Provost 		return (ENOMEM);
17790d6c8174SKristof Provost 
17800d6c8174SKristof Provost 	nvlist_add_number(nvl, "nr", nr);
17810d6c8174SKristof Provost 	nvlist_add_number(nvl, "ticket", ticket);
17820d6c8174SKristof Provost 	nvlist_add_string(nvl, "anchor", anchor);
17830d6c8174SKristof Provost 	nvlist_add_number(nvl, "ruleset", ruleset);
17840d6c8174SKristof Provost 
17854eabfe46SKristof Provost 	if (clear)
17864eabfe46SKristof Provost 		nvlist_add_bool(nvl, "clear_counter", true);
17874eabfe46SKristof Provost 
17887ed19f5cSKristof Provost 	if ((ret = pfctl_do_ioctl(dev, DIOCGETRULENV, 8192, &nvl)) != 0)
1789498934c5SKristof Provost 		goto out;
17900d6c8174SKristof Provost 
17910d6c8174SKristof Provost 	pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule);
17920d6c8174SKristof Provost 
17930d6c8174SKristof Provost 	if (anchor_call)
17940d6c8174SKristof Provost 		strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
17950d6c8174SKristof Provost 		    MAXPATHLEN);
17960d6c8174SKristof Provost 
1797498934c5SKristof Provost out:
17980d6c8174SKristof Provost 	nvlist_destroy(nvl);
1799498934c5SKristof Provost 	return (ret);
18000d6c8174SKristof Provost }
180142ec75f8SKristof Provost 
180242ec75f8SKristof Provost int
pfctl_set_keepcounters(int dev,bool keep)180342ec75f8SKristof Provost pfctl_set_keepcounters(int dev, bool keep)
180442ec75f8SKristof Provost {
180542ec75f8SKristof Provost 	struct pfioc_nv	 nv;
180642ec75f8SKristof Provost 	nvlist_t	*nvl;
180742ec75f8SKristof Provost 	int		 ret;
180842ec75f8SKristof Provost 
180942ec75f8SKristof Provost 	nvl = nvlist_create(0);
181042ec75f8SKristof Provost 
181142ec75f8SKristof Provost 	nvlist_add_bool(nvl, "keep_counters", keep);
181242ec75f8SKristof Provost 
181342ec75f8SKristof Provost 	nv.data = nvlist_pack(nvl, &nv.len);
181442ec75f8SKristof Provost 	nv.size = nv.len;
181542ec75f8SKristof Provost 
181642ec75f8SKristof Provost 	nvlist_destroy(nvl);
181742ec75f8SKristof Provost 
181842ec75f8SKristof Provost 	ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv);
181942ec75f8SKristof Provost 
182042ec75f8SKristof Provost 	free(nv.data);
182142ec75f8SKristof Provost 	return (ret);
182242ec75f8SKristof Provost }
182353714a58SKristof Provost 
1824a7191e5dSKristof Provost struct pfctl_creator {
1825a7191e5dSKristof Provost 	uint32_t id;
1826a7191e5dSKristof Provost };
1827a7191e5dSKristof Provost #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
1828a7191e5dSKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_creator, _field)
1829a7191e5dSKristof Provost static struct snl_attr_parser ap_creators[] = {
1830a7191e5dSKristof Provost 	{ .type = PF_ST_CREATORID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
1831a7191e5dSKristof Provost };
1832a7191e5dSKristof Provost #undef _IN
1833a7191e5dSKristof Provost #undef _OUT
18347c882c69SKristof Provost SNL_DECLARE_PARSER(creator_parser, struct genlmsghdr, snl_f_p_empty, ap_creators);
1835a7191e5dSKristof Provost 
1836a7191e5dSKristof Provost static int
pfctl_get_creators_nl(struct snl_state * ss,uint32_t * creators,size_t * len)1837a7191e5dSKristof Provost pfctl_get_creators_nl(struct snl_state *ss, uint32_t *creators, size_t *len)
1838a7191e5dSKristof Provost {
1839a7191e5dSKristof Provost 
1840a7191e5dSKristof Provost 	int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME);
1841a7191e5dSKristof Provost 	size_t i = 0;
1842a7191e5dSKristof Provost 
1843a7191e5dSKristof Provost 	struct nlmsghdr *hdr;
1844a7191e5dSKristof Provost 	struct snl_writer nw;
1845a7191e5dSKristof Provost 
1846497ccc21SKristof Provost 	if (family_id == 0)
1847497ccc21SKristof Provost 		return (ENOTSUP);
1848497ccc21SKristof Provost 
1849a7191e5dSKristof Provost 	snl_init_writer(ss, &nw);
1850a7191e5dSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETCREATORS);
1851a7191e5dSKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
18524f8f43b0SKristof Provost 	hdr = snl_finalize_msg(&nw);
18534abc3b48SKristof Provost 	if (hdr == NULL)
18544abc3b48SKristof Provost 		return (ENOMEM);
1855a7191e5dSKristof Provost 	uint32_t seq_id = hdr->nlmsg_seq;
1856a7191e5dSKristof Provost 
1857a7191e5dSKristof Provost 	snl_send_message(ss, hdr);
1858a7191e5dSKristof Provost 
1859a7191e5dSKristof Provost 	struct snl_errmsg_data e = {};
1860a7191e5dSKristof Provost 	while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) {
1861a7191e5dSKristof Provost 		struct pfctl_creator c;
1862a7191e5dSKristof Provost 		bzero(&c, sizeof(c));
1863a7191e5dSKristof Provost 
1864a7191e5dSKristof Provost 		if (!snl_parse_nlmsg(ss, hdr, &creator_parser, &c))
1865a7191e5dSKristof Provost 			continue;
1866a7191e5dSKristof Provost 
1867a7191e5dSKristof Provost 		creators[i] = c.id;
1868a7191e5dSKristof Provost 		i++;
1869a7191e5dSKristof Provost 		if (i > *len)
1870a7191e5dSKristof Provost 			return (E2BIG);
1871a7191e5dSKristof Provost 	}
1872a7191e5dSKristof Provost 
1873a7191e5dSKristof Provost 	*len = i;
1874a7191e5dSKristof Provost 
1875a7191e5dSKristof Provost 	return (0);
1876a7191e5dSKristof Provost }
1877a7191e5dSKristof Provost 
1878a7191e5dSKristof Provost int
pfctl_get_creatorids(struct pfctl_handle * h,uint32_t * creators,size_t * len)187966cacc14SKristof Provost pfctl_get_creatorids(struct pfctl_handle *h, uint32_t *creators, size_t *len)
1880a7191e5dSKristof Provost {
1881a7191e5dSKristof Provost 	int error;
1882a7191e5dSKristof Provost 
188366cacc14SKristof Provost 	error = pfctl_get_creators_nl(&h->ss, creators, len);
1884a7191e5dSKristof Provost 
1885a7191e5dSKristof Provost 	return (error);
1886a7191e5dSKristof Provost }
1887a7191e5dSKristof Provost 
18882cef6288SAlexander V. Chernikov static inline bool
snl_attr_get_pfaddr(struct snl_state * ss __unused,struct nlattr * nla,const void * arg __unused,void * target)18892cef6288SAlexander V. Chernikov snl_attr_get_pfaddr(struct snl_state *ss __unused, struct nlattr *nla,
18902cef6288SAlexander V. Chernikov     const void *arg __unused, void *target)
1891bc941291SKristof Provost {
18922cef6288SAlexander V. Chernikov 	memcpy(target, NLA_DATA(nla), NLA_DATA_LEN(nla));
18932cef6288SAlexander V. Chernikov 	return (true);
1894bc941291SKristof Provost }
1895bc941291SKristof Provost 
18962cef6288SAlexander V. Chernikov static inline bool
snl_attr_store_ifname(struct snl_state * ss __unused,struct nlattr * nla,const void * arg __unused,void * target)18972cef6288SAlexander V. Chernikov snl_attr_store_ifname(struct snl_state *ss __unused, struct nlattr *nla,
18982cef6288SAlexander V. Chernikov     const void *arg __unused, void *target)
1899bc941291SKristof Provost {
19002cef6288SAlexander V. Chernikov 	size_t maxlen = NLA_DATA_LEN(nla);
19012cef6288SAlexander V. Chernikov 
19022cef6288SAlexander V. Chernikov 	if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) {
19032cef6288SAlexander V. Chernikov 		strlcpy(target, (char *)NLA_DATA(nla), maxlen);
19042cef6288SAlexander V. Chernikov 		return (true);
19052cef6288SAlexander V. Chernikov 	}
19062cef6288SAlexander V. Chernikov 	return (false);
1907bc941291SKristof Provost }
1908bc941291SKristof Provost 
19092cef6288SAlexander V. Chernikov #define	_OUT(_field)	offsetof(struct pfctl_state_peer, _field)
19102cef6288SAlexander V. Chernikov static const struct snl_attr_parser nla_p_speer[] = {
19112cef6288SAlexander V. Chernikov 	{ .type = PF_STP_SEQLO, .off = _OUT(seqlo), .cb = snl_attr_get_uint32 },
19122cef6288SAlexander V. Chernikov 	{ .type = PF_STP_SEQHI, .off = _OUT(seqhi), .cb = snl_attr_get_uint32 },
19132cef6288SAlexander V. Chernikov 	{ .type = PF_STP_SEQDIFF, .off = _OUT(seqdiff), .cb = snl_attr_get_uint32 },
19142cef6288SAlexander V. Chernikov 	{ .type = PF_STP_STATE, .off = _OUT(state), .cb = snl_attr_get_uint8 },
19152cef6288SAlexander V. Chernikov 	{ .type = PF_STP_WSCALE, .off = _OUT(wscale), .cb = snl_attr_get_uint8 },
19162cef6288SAlexander V. Chernikov };
19172cef6288SAlexander V. Chernikov SNL_DECLARE_ATTR_PARSER(speer_parser, nla_p_speer);
19182cef6288SAlexander V. Chernikov #undef _OUT
19192cef6288SAlexander V. Chernikov 
1920ebe11b46SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_state_key, _field)
19212cef6288SAlexander V. Chernikov static const struct snl_attr_parser nla_p_skey[] = {
19222cef6288SAlexander V. Chernikov 	{ .type = PF_STK_ADDR0, .off = _OUT(addr[0]), .cb = snl_attr_get_pfaddr },
19232cef6288SAlexander V. Chernikov 	{ .type = PF_STK_ADDR1, .off = _OUT(addr[1]), .cb = snl_attr_get_pfaddr },
19242cef6288SAlexander V. Chernikov 	{ .type = PF_STK_PORT0, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 },
19252cef6288SAlexander V. Chernikov 	{ .type = PF_STK_PORT1, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 },
1926ebe11b46SKristof Provost 	{ .type = PF_STK_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
1927ebe11b46SKristof Provost 	{ .type = PF_STK_PROTO, .off = _OUT(proto), .cb = snl_attr_get_uint16 },
19282cef6288SAlexander V. Chernikov };
19292cef6288SAlexander V. Chernikov SNL_DECLARE_ATTR_PARSER(skey_parser, nla_p_skey);
19302cef6288SAlexander V. Chernikov #undef _OUT
19312cef6288SAlexander V. Chernikov 
19322cef6288SAlexander V. Chernikov #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
19332cef6288SAlexander V. Chernikov #define	_OUT(_field)	offsetof(struct pfctl_state, _field)
19342cef6288SAlexander V. Chernikov static struct snl_attr_parser ap_state[] = {
19352cef6288SAlexander V. Chernikov 	{ .type = PF_ST_ID, .off = _OUT(id), .cb = snl_attr_get_uint64 },
19362cef6288SAlexander V. Chernikov 	{ .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = snl_attr_get_uint32 },
19372cef6288SAlexander V. Chernikov 	{ .type = PF_ST_IFNAME, .off = _OUT(ifname), .cb = snl_attr_store_ifname },
19382cef6288SAlexander V. Chernikov 	{ .type = PF_ST_ORIG_IFNAME, .off = _OUT(orig_ifname), .cb = snl_attr_store_ifname },
19392cef6288SAlexander V. Chernikov 	{ .type = PF_ST_KEY_WIRE, .off = _OUT(key[0]), .arg = &skey_parser, .cb = snl_attr_get_nested },
19402cef6288SAlexander V. Chernikov 	{ .type = PF_ST_KEY_STACK, .off = _OUT(key[1]), .arg = &skey_parser, .cb = snl_attr_get_nested },
19412cef6288SAlexander V. Chernikov 	{ .type = PF_ST_PEER_SRC, .off = _OUT(src), .arg = &speer_parser, .cb = snl_attr_get_nested },
19422cef6288SAlexander V. Chernikov 	{ .type = PF_ST_PEER_DST, .off = _OUT(dst), .arg = &speer_parser, .cb = snl_attr_get_nested },
19432cef6288SAlexander V. Chernikov 	{ .type = PF_ST_RT_ADDR, .off = _OUT(rt_addr), .cb = snl_attr_get_pfaddr },
19442cef6288SAlexander V. Chernikov 	{ .type = PF_ST_RULE, .off = _OUT(rule), .cb = snl_attr_get_uint32 },
19452cef6288SAlexander V. Chernikov 	{ .type = PF_ST_ANCHOR, .off = _OUT(anchor), .cb = snl_attr_get_uint32 },
19462cef6288SAlexander V. Chernikov 	{ .type = PF_ST_NAT_RULE, .off = _OUT(nat_rule), .cb = snl_attr_get_uint32 },
19472cef6288SAlexander V. Chernikov 	{ .type = PF_ST_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint32 },
19482cef6288SAlexander V. Chernikov 	{ .type = PF_ST_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint32 },
19492cef6288SAlexander V. Chernikov 	{ .type = PF_ST_PACKETS0, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 },
19502cef6288SAlexander V. Chernikov 	{ .type = PF_ST_PACKETS1, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 },
19512cef6288SAlexander V. Chernikov 	{ .type = PF_ST_BYTES0, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 },
19522cef6288SAlexander V. Chernikov 	{ .type = PF_ST_BYTES1, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 },
19532cef6288SAlexander V. Chernikov 	{ .type = PF_ST_DIRECTION, .off = _OUT(direction), .cb = snl_attr_get_uint8 },
19542cef6288SAlexander V. Chernikov 	{ .type = PF_ST_LOG, .off = _OUT(log), .cb = snl_attr_get_uint8 },
19552cef6288SAlexander V. Chernikov 	{ .type = PF_ST_STATE_FLAGS, .off = _OUT(state_flags), .cb = snl_attr_get_uint16 },
19562cef6288SAlexander V. Chernikov 	{ .type = PF_ST_SYNC_FLAGS, .off = _OUT(sync_flags), .cb = snl_attr_get_uint8 },
1957881bf881SKristof Provost 	{ .type = PF_ST_RTABLEID, .off = _OUT(rtableid), .cb = snl_attr_get_int32 },
1958881bf881SKristof Provost 	{ .type = PF_ST_MIN_TTL, .off = _OUT(min_ttl), .cb = snl_attr_get_uint8 },
1959881bf881SKristof Provost 	{ .type = PF_ST_MAX_MSS, .off = _OUT(max_mss), .cb = snl_attr_get_uint16 },
1960881bf881SKristof Provost 	{ .type = PF_ST_DNPIPE, .off = _OUT(dnpipe), .cb = snl_attr_get_uint16 },
1961881bf881SKristof Provost 	{ .type = PF_ST_DNRPIPE, .off = _OUT(dnrpipe), .cb = snl_attr_get_uint16 },
1962881bf881SKristof Provost 	{ .type = PF_ST_RT, .off = _OUT(rt), .cb = snl_attr_get_uint8 },
1963881bf881SKristof Provost 	{ .type = PF_ST_RT_IFNAME, .off = _OUT(rt_ifname), .cb = snl_attr_store_ifname },
196407e070efSKajetan Staszkiewicz 	{ .type = PF_ST_SRC_NODE_FLAGS, .off = _OUT(src_node_flags), .cb = snl_attr_get_uint8 },
1965d2761422SKajetan Staszkiewicz 	{ .type = PF_ST_RT_AF, .off = _OUT(rt_af), .cb = snl_attr_get_uint8 },
19662cef6288SAlexander V. Chernikov };
19672cef6288SAlexander V. Chernikov #undef _IN
19682cef6288SAlexander V. Chernikov #undef _OUT
19697c882c69SKristof Provost SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, snl_f_p_empty, ap_state);
19702cef6288SAlexander V. Chernikov 
1971823ebd7cSKristof Provost int
pfctl_get_states_h(struct pfctl_handle * h,struct pfctl_state_filter * filter,pfctl_get_state_fn f,void * arg)1972823ebd7cSKristof Provost pfctl_get_states_h(struct pfctl_handle *h, struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg)
1973bc941291SKristof Provost {
1974823ebd7cSKristof Provost 	int family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
1975f218b851SKristof Provost 	int ret;
1976bc941291SKristof Provost 
19772cef6288SAlexander V. Chernikov 	struct nlmsghdr *hdr;
19782cef6288SAlexander V. Chernikov 	struct snl_writer nw;
1979bc941291SKristof Provost 
1980497ccc21SKristof Provost 	if (family_id == 0)
1981497ccc21SKristof Provost 		return (ENOTSUP);
1982497ccc21SKristof Provost 
1983823ebd7cSKristof Provost 	snl_init_writer(&h->ss, &nw);
19842cef6288SAlexander V. Chernikov 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETSTATES);
19852cef6288SAlexander V. Chernikov 	hdr->nlmsg_flags |= NLM_F_DUMP;
1986044eef6aSKristof Provost 	snl_add_msg_attr_string(&nw, PF_ST_IFNAME, filter->ifname);
1987044eef6aSKristof Provost 	snl_add_msg_attr_u16(&nw, PF_ST_PROTO, filter->proto);
1988044eef6aSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_ST_AF, filter->af);
1989044eef6aSKristof Provost 	snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_ADDR, &filter->addr.v6);
1990044eef6aSKristof Provost 	snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_MASK, &filter->mask.v6);
1991044eef6aSKristof Provost 
19924f8f43b0SKristof Provost 	hdr = snl_finalize_msg(&nw);
19934abc3b48SKristof Provost 	if (hdr == NULL)
19944abc3b48SKristof Provost 		return (ENOMEM);
1995044eef6aSKristof Provost 
19962cef6288SAlexander V. Chernikov 	uint32_t seq_id = hdr->nlmsg_seq;
1997be70c7a5SKristof Provost 
1998823ebd7cSKristof Provost 	snl_send_message(&h->ss, hdr);
1999bc941291SKristof Provost 
20002cef6288SAlexander V. Chernikov 	struct snl_errmsg_data e = {};
2001823ebd7cSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2002f218b851SKristof Provost 		struct pfctl_state s;
2003f218b851SKristof Provost 		bzero(&s, sizeof(s));
2004823ebd7cSKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &state_parser, &s))
20052cef6288SAlexander V. Chernikov 			continue;
2006bc941291SKristof Provost 
2007f218b851SKristof Provost 		ret = f(&s, arg);
2008f218b851SKristof Provost 		if (ret != 0)
2009f218b851SKristof Provost 			return (ret);
2010f218b851SKristof Provost 	}
2011f218b851SKristof Provost 
2012f218b851SKristof Provost 	return (0);
2013f218b851SKristof Provost }
2014f218b851SKristof Provost 
2015f218b851SKristof Provost int
pfctl_get_states_iter(pfctl_get_state_fn f,void * arg)2016f218b851SKristof Provost pfctl_get_states_iter(pfctl_get_state_fn f, void *arg)
2017f218b851SKristof Provost {
2018044eef6aSKristof Provost 	struct pfctl_state_filter filter = {};
2019044eef6aSKristof Provost 	return (pfctl_get_filtered_states_iter(&filter, f, arg));
2020044eef6aSKristof Provost }
2021044eef6aSKristof Provost 
2022044eef6aSKristof Provost int
pfctl_get_filtered_states_iter(struct pfctl_state_filter * filter,pfctl_get_state_fn f,void * arg)2023044eef6aSKristof Provost pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg)
2024044eef6aSKristof Provost {
2025823ebd7cSKristof Provost 	struct pfctl_handle h = {};
2026f218b851SKristof Provost 	int error;
2027f218b851SKristof Provost 
2028823ebd7cSKristof Provost 	snl_init(&h.ss, NETLINK_GENERIC);
2029823ebd7cSKristof Provost 	error = pfctl_get_states_h(&h, filter, f, arg);
2030823ebd7cSKristof Provost 	snl_free(&h.ss);
2031f218b851SKristof Provost 
2032f218b851SKristof Provost 	return (error);
2033f218b851SKristof Provost }
2034f218b851SKristof Provost 
2035f218b851SKristof Provost static int
pfctl_append_states(struct pfctl_state * s,void * arg)2036f218b851SKristof Provost pfctl_append_states(struct pfctl_state *s, void *arg)
2037f218b851SKristof Provost {
2038f218b851SKristof Provost 	struct pfctl_state *new;
2039f218b851SKristof Provost 	struct pfctl_states *states = (struct pfctl_states *)arg;
2040f218b851SKristof Provost 
2041f218b851SKristof Provost 	new = malloc(sizeof(*s));
2042f218b851SKristof Provost 	if (new == NULL)
2043f218b851SKristof Provost 		return (ENOMEM);
2044f218b851SKristof Provost 
2045f218b851SKristof Provost 	memcpy(new, s, sizeof(*s));
20462cef6288SAlexander V. Chernikov 
20474abc3b48SKristof Provost 	TAILQ_INSERT_TAIL(&states->states, new, entry);
2048bc941291SKristof Provost 
20492cef6288SAlexander V. Chernikov 	return (0);
20502cef6288SAlexander V. Chernikov }
20512cef6288SAlexander V. Chernikov 
20522cef6288SAlexander V. Chernikov int
pfctl_get_states(int dev __unused,struct pfctl_states * states)20532cef6288SAlexander V. Chernikov pfctl_get_states(int dev __unused, struct pfctl_states *states)
20542cef6288SAlexander V. Chernikov {
2055f218b851SKristof Provost 	int ret;
20562cef6288SAlexander V. Chernikov 
2057f218b851SKristof Provost 	bzero(states, sizeof(*states));
2058f218b851SKristof Provost 	TAILQ_INIT(&states->states);
20592cef6288SAlexander V. Chernikov 
2060f218b851SKristof Provost 	ret = pfctl_get_states_iter(pfctl_append_states, states);
2061f218b851SKristof Provost 	if (ret != 0) {
2062f218b851SKristof Provost 		pfctl_free_states(states);
2063f218b851SKristof Provost 		return (ret);
2064f218b851SKristof Provost 	}
2065f218b851SKristof Provost 
2066f218b851SKristof Provost 	return (0);
2067bc941291SKristof Provost }
2068bc941291SKristof Provost 
2069bc941291SKristof Provost void
pfctl_free_states(struct pfctl_states * states)2070bc941291SKristof Provost pfctl_free_states(struct pfctl_states *states)
2071bc941291SKristof Provost {
2072bc941291SKristof Provost 	struct pfctl_state *s, *tmp;
2073bc941291SKristof Provost 
2074bc941291SKristof Provost 	TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) {
2075bc941291SKristof Provost 		free(s);
2076bc941291SKristof Provost 	}
2077bc941291SKristof Provost 
2078bc941291SKristof Provost 	bzero(states, sizeof(*states));
2079bc941291SKristof Provost }
2080bc941291SKristof Provost 
2081706d465dSKristof Provost struct pfctl_nl_clear_states {
2082706d465dSKristof Provost 	uint32_t killed;
2083706d465dSKristof Provost };
2084706d465dSKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_nl_clear_states, _field)
2085706d465dSKristof Provost static struct snl_attr_parser ap_clear_states[] = {
2086706d465dSKristof Provost 	{ .type = PF_CS_KILLED, .off = _OUT(killed), .cb = snl_attr_get_uint32 },
2087706d465dSKristof Provost };
2088706d465dSKristof Provost #undef _OUT
20897c882c69SKristof Provost SNL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, snl_f_p_empty, ap_clear_states);
2090706d465dSKristof Provost 
20912a00c4dbSKristof Provost static int
_pfctl_clear_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed,int cmd)2092706d465dSKristof Provost _pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2093706d465dSKristof Provost     unsigned int *killed, int cmd)
209453714a58SKristof Provost {
2095706d465dSKristof Provost 	struct snl_writer nw;
2096706d465dSKristof Provost 	struct snl_errmsg_data e = {};
2097706d465dSKristof Provost 	struct pfctl_nl_clear_states attrs = {};
2098706d465dSKristof Provost 	struct nlmsghdr *hdr;
2099706d465dSKristof Provost 	uint32_t seq_id;
2100706d465dSKristof Provost 	int family_id;
210153714a58SKristof Provost 
2102706d465dSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
2103706d465dSKristof Provost 	if (family_id == 0)
2104706d465dSKristof Provost 		return (ENOTSUP);
210553714a58SKristof Provost 
2106706d465dSKristof Provost 	snl_init_writer(&h->ss, &nw);
2107706d465dSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, cmd);
2108706d465dSKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
210953714a58SKristof Provost 
2110706d465dSKristof Provost 	snl_add_msg_attr_u64(&nw, PF_CS_CMP_ID, kill->cmp.id);
2111706d465dSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_CS_CMP_CREATORID, htonl(kill->cmp.creatorid));
2112706d465dSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_CS_CMP_DIR, kill->cmp.direction);
2113706d465dSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_CS_AF, kill->af);
2114706d465dSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_CS_PROTO, kill->proto);
2115706d465dSKristof Provost 	snl_add_msg_attr_rule_addr(&nw, PF_CS_SRC, &kill->src);
2116706d465dSKristof Provost 	snl_add_msg_attr_rule_addr(&nw, PF_CS_DST, &kill->dst);
2117706d465dSKristof Provost 	snl_add_msg_attr_rule_addr(&nw, PF_CS_RT_ADDR, &kill->rt_addr);
2118706d465dSKristof Provost 	snl_add_msg_attr_string(&nw, PF_CS_IFNAME, kill->ifname);
2119706d465dSKristof Provost 	snl_add_msg_attr_string(&nw, PF_CS_LABEL, kill->label);
2120706d465dSKristof Provost 	snl_add_msg_attr_bool(&nw, PF_CS_KILL_MATCH, kill->kill_match);
2121706d465dSKristof Provost 	snl_add_msg_attr_bool(&nw, PF_CS_NAT, kill->nat);
2122706d465dSKristof Provost 
2123706d465dSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
2124706d465dSKristof Provost 		return (ENXIO);
2125706d465dSKristof Provost 
2126706d465dSKristof Provost 	seq_id = hdr->nlmsg_seq;
2127706d465dSKristof Provost 
2128706d465dSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
2129706d465dSKristof Provost 		return (ENXIO);
2130706d465dSKristof Provost 
2131706d465dSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2132706d465dSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &clear_states_parser, &attrs))
2133706d465dSKristof Provost 			continue;
2134706d465dSKristof Provost 	}
213553714a58SKristof Provost 
213653714a58SKristof Provost 	if (killed)
2137706d465dSKristof Provost 		*killed = attrs.killed;
213853714a58SKristof Provost 
2139706d465dSKristof Provost 	return (e.error);
2140706d465dSKristof Provost }
2141706d465dSKristof Provost 
2142706d465dSKristof Provost int
pfctl_clear_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed)2143706d465dSKristof Provost pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2144706d465dSKristof Provost     unsigned int *killed)
2145706d465dSKristof Provost {
2146706d465dSKristof Provost 	return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_CLRSTATES));
2147706d465dSKristof Provost }
2148706d465dSKristof Provost 
2149706d465dSKristof Provost int
pfctl_kill_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed)2150706d465dSKristof Provost pfctl_kill_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2151706d465dSKristof Provost     unsigned int *killed)
2152706d465dSKristof Provost {
2153706d465dSKristof Provost 	return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_KILLSTATES));
2154706d465dSKristof Provost }
2155706d465dSKristof Provost 
2156706d465dSKristof Provost static int
_pfctl_clear_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed,uint64_t cmd)2157706d465dSKristof Provost _pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
2158706d465dSKristof Provost     unsigned int *killed, uint64_t cmd)
2159706d465dSKristof Provost {
2160706d465dSKristof Provost 	struct pfctl_handle *h;
2161706d465dSKristof Provost 	int ret;
2162706d465dSKristof Provost 
2163706d465dSKristof Provost 	h = pfctl_open(PF_DEVICE);
2164706d465dSKristof Provost 	if (h == NULL)
2165706d465dSKristof Provost 		return (ENODEV);
2166706d465dSKristof Provost 
2167706d465dSKristof Provost 	ret = _pfctl_clear_states_h(h, kill, killed, cmd);
2168706d465dSKristof Provost 	pfctl_close(h);
2169706d465dSKristof Provost 
217053714a58SKristof Provost 	return (ret);
217153714a58SKristof Provost }
21722a00c4dbSKristof Provost 
21732a00c4dbSKristof Provost int
pfctl_clear_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed)2174706d465dSKristof Provost pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
21752a00c4dbSKristof Provost     unsigned int *killed)
21762a00c4dbSKristof Provost {
2177706d465dSKristof Provost 	return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_CLRSTATES));
21782a00c4dbSKristof Provost }
21792a00c4dbSKristof Provost 
21802a00c4dbSKristof Provost int
pfctl_kill_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed)2181706d465dSKristof Provost pfctl_kill_states(int dev __unused, const struct pfctl_kill *kill, unsigned int *killed)
21822a00c4dbSKristof Provost {
2183706d465dSKristof Provost 	return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_KILLSTATES));
21842a00c4dbSKristof Provost }
2185c69121c4SKristof Provost 
2186f0c334e4SKristof Provost int
pfctl_clear_rules(int dev,const char * anchorname)2187f0c334e4SKristof Provost pfctl_clear_rules(int dev, const char *anchorname)
2188f0c334e4SKristof Provost {
2189f0c334e4SKristof Provost 	struct pfioc_trans trans;
2190f0c334e4SKristof Provost 	struct pfioc_trans_e transe[2];
2191f0c334e4SKristof Provost 	int ret;
2192f0c334e4SKristof Provost 
2193f0c334e4SKristof Provost 	bzero(&trans, sizeof(trans));
2194f0c334e4SKristof Provost 	bzero(&transe, sizeof(transe));
2195f0c334e4SKristof Provost 
2196f0c334e4SKristof Provost 	transe[0].rs_num = PF_RULESET_SCRUB;
2197f0c334e4SKristof Provost 	if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor))
2198f0c334e4SKristof Provost 	    >= sizeof(transe[0].anchor))
2199f0c334e4SKristof Provost 		return (E2BIG);
2200f0c334e4SKristof Provost 
2201f0c334e4SKristof Provost 	transe[1].rs_num = PF_RULESET_FILTER;
2202f0c334e4SKristof Provost 	if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor))
2203f0c334e4SKristof Provost 	    >= sizeof(transe[1].anchor))
2204f0c334e4SKristof Provost 		return (E2BIG);
2205f0c334e4SKristof Provost 
2206f0c334e4SKristof Provost 	trans.size = 2;
2207f0c334e4SKristof Provost 	trans.esize = sizeof(transe[0]);
2208f0c334e4SKristof Provost 	trans.array = transe;
2209f0c334e4SKristof Provost 
2210f0c334e4SKristof Provost 	ret = ioctl(dev, DIOCXBEGIN, &trans);
2211f0c334e4SKristof Provost 	if (ret != 0)
221293e96359SKristof Provost 		return (errno);
221393e96359SKristof Provost 	ret = ioctl(dev, DIOCXCOMMIT, &trans);
221493e96359SKristof Provost 	if (ret != 0)
221593e96359SKristof Provost 		return (errno);
221693e96359SKristof Provost 
221793e96359SKristof Provost 	return (0);
2218f0c334e4SKristof Provost }
2219f0c334e4SKristof Provost 
2220f0c334e4SKristof Provost int
pfctl_clear_nat(int dev,const char * anchorname)2221f0c334e4SKristof Provost pfctl_clear_nat(int dev, const char *anchorname)
2222f0c334e4SKristof Provost {
2223f0c334e4SKristof Provost 	struct pfioc_trans trans;
2224f0c334e4SKristof Provost 	struct pfioc_trans_e transe[3];
2225f0c334e4SKristof Provost 	int ret;
2226f0c334e4SKristof Provost 
2227f0c334e4SKristof Provost 	bzero(&trans, sizeof(trans));
2228f0c334e4SKristof Provost 	bzero(&transe, sizeof(transe));
2229f0c334e4SKristof Provost 
2230f0c334e4SKristof Provost 	transe[0].rs_num = PF_RULESET_NAT;
2231f0c334e4SKristof Provost 	if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor))
2232f0c334e4SKristof Provost 	    >= sizeof(transe[0].anchor))
2233f0c334e4SKristof Provost 		return (E2BIG);
2234f0c334e4SKristof Provost 
2235f0c334e4SKristof Provost 	transe[1].rs_num = PF_RULESET_BINAT;
2236f0c334e4SKristof Provost 	if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor))
2237f0c334e4SKristof Provost 	    >= sizeof(transe[0].anchor))
2238f0c334e4SKristof Provost 		return (E2BIG);
2239f0c334e4SKristof Provost 
2240f0c334e4SKristof Provost 	transe[2].rs_num = PF_RULESET_RDR;
2241f0c334e4SKristof Provost 	if (strlcpy(transe[2].anchor, anchorname, sizeof(transe[2].anchor))
2242f0c334e4SKristof Provost 	    >= sizeof(transe[2].anchor))
2243f0c334e4SKristof Provost 		return (E2BIG);
2244f0c334e4SKristof Provost 
2245f0c334e4SKristof Provost 	trans.size = 3;
2246f0c334e4SKristof Provost 	trans.esize = sizeof(transe[0]);
2247f0c334e4SKristof Provost 	trans.array = transe;
2248f0c334e4SKristof Provost 
2249f0c334e4SKristof Provost 	ret = ioctl(dev, DIOCXBEGIN, &trans);
2250f0c334e4SKristof Provost 	if (ret != 0)
225193e96359SKristof Provost 		return (errno);
225293e96359SKristof Provost 	ret = ioctl(dev, DIOCXCOMMIT, &trans);
225393e96359SKristof Provost 	if (ret != 0)
225493e96359SKristof Provost 		return (errno);
225593e96359SKristof Provost 
225693e96359SKristof Provost 	return (0);
2257f0c334e4SKristof Provost }
225893e96359SKristof Provost 
2259f0c334e4SKristof Provost int
pfctl_clear_eth_rules(int dev,const char * anchorname)2260f0c334e4SKristof Provost pfctl_clear_eth_rules(int dev, const char *anchorname)
2261f0c334e4SKristof Provost {
2262f0c334e4SKristof Provost 	struct pfioc_trans trans;
2263f0c334e4SKristof Provost 	struct pfioc_trans_e transe;
2264f0c334e4SKristof Provost 	int ret;
2265f0c334e4SKristof Provost 
2266f0c334e4SKristof Provost 	bzero(&trans, sizeof(trans));
2267f0c334e4SKristof Provost 	bzero(&transe, sizeof(transe));
2268f0c334e4SKristof Provost 
2269f0c334e4SKristof Provost 	transe.rs_num = PF_RULESET_ETH;
2270f0c334e4SKristof Provost 	if (strlcpy(transe.anchor, anchorname, sizeof(transe.anchor))
2271f0c334e4SKristof Provost 	    >= sizeof(transe.anchor))
2272f0c334e4SKristof Provost 		return (E2BIG);
2273f0c334e4SKristof Provost 
2274f0c334e4SKristof Provost 	trans.size = 1;
2275f0c334e4SKristof Provost 	trans.esize = sizeof(transe);
2276f0c334e4SKristof Provost 	trans.array = &transe;
2277f0c334e4SKristof Provost 
2278f0c334e4SKristof Provost 	ret = ioctl(dev, DIOCXBEGIN, &trans);
2279f0c334e4SKristof Provost 	if (ret != 0)
228093e96359SKristof Provost 		return (errno);
228193e96359SKristof Provost 	ret = ioctl(dev, DIOCXCOMMIT, &trans);
228293e96359SKristof Provost 	if (ret != 0)
228393e96359SKristof Provost 		return (errno);
228493e96359SKristof Provost 
228593e96359SKristof Provost 	return (0);
2286f0c334e4SKristof Provost }
2287f0c334e4SKristof Provost 
22885062afffSKristof Provost static int
_pfctl_get_limit(int dev,const int index,uint * limit)2289d9ab8999SKristof Provost _pfctl_get_limit(int dev, const int index, uint *limit)
22905062afffSKristof Provost {
22915062afffSKristof Provost 	struct pfioc_limit pl;
22925062afffSKristof Provost 
22935062afffSKristof Provost 	bzero(&pl, sizeof(pl));
22945062afffSKristof Provost 	pl.index = index;
22955062afffSKristof Provost 
22965062afffSKristof Provost 	if (ioctl(dev, DIOCGETLIMIT, &pl) == -1)
22975062afffSKristof Provost 		return (errno);
22985062afffSKristof Provost 
22995062afffSKristof Provost 	*limit = pl.limit;
23005062afffSKristof Provost 
23015062afffSKristof Provost 	return (0);
23025062afffSKristof Provost }
23035062afffSKristof Provost 
2304c69121c4SKristof Provost int
pfctl_set_syncookies(int dev,const struct pfctl_syncookies * s)2305c69121c4SKristof Provost pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
2306c69121c4SKristof Provost {
2307c69121c4SKristof Provost 	struct pfioc_nv	 nv;
2308c69121c4SKristof Provost 	nvlist_t	*nvl;
2309c69121c4SKristof Provost 	int		 ret;
23107bb3c927SKristof Provost 	uint		 state_limit;
23116049ee60SKristof Provost 	uint64_t	 lim, hi, lo;
23125062afffSKristof Provost 
2313d9ab8999SKristof Provost 	ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
23145062afffSKristof Provost 	if (ret != 0)
23155062afffSKristof Provost 		return (ret);
2316c69121c4SKristof Provost 
2317b70fadcaSKristof Provost 	if (state_limit == 0)
2318b70fadcaSKristof Provost 		state_limit = INT_MAX;
2319b70fadcaSKristof Provost 
23206049ee60SKristof Provost 	lim = state_limit;
23216049ee60SKristof Provost 	hi = lim * s->highwater / 100;
23226049ee60SKristof Provost 	lo = lim * s->lowwater / 100;
23236049ee60SKristof Provost 
23246049ee60SKristof Provost 	if (lo == hi)
23256049ee60SKristof Provost 		hi++;
23266049ee60SKristof Provost 
2327c69121c4SKristof Provost 	nvl = nvlist_create(0);
2328c69121c4SKristof Provost 
2329c69121c4SKristof Provost 	nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER);
23305062afffSKristof Provost 	nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE);
23316049ee60SKristof Provost 	nvlist_add_number(nvl, "highwater", hi);
23326049ee60SKristof Provost 	nvlist_add_number(nvl, "lowwater", lo);
2333c69121c4SKristof Provost 
2334c69121c4SKristof Provost 	nv.data = nvlist_pack(nvl, &nv.len);
2335c69121c4SKristof Provost 	nv.size = nv.len;
2336c69121c4SKristof Provost 	nvlist_destroy(nvl);
2337c69121c4SKristof Provost 	nvl = NULL;
2338c69121c4SKristof Provost 
2339c69121c4SKristof Provost 	ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv);
2340c69121c4SKristof Provost 
2341c69121c4SKristof Provost 	free(nv.data);
234293e96359SKristof Provost 	if (ret != 0)
234393e96359SKristof Provost 		return (errno);
234493e96359SKristof Provost 
234593e96359SKristof Provost 	return (0);
2346c69121c4SKristof Provost }
2347c69121c4SKristof Provost 
2348c69121c4SKristof Provost int
pfctl_get_syncookies(int dev,struct pfctl_syncookies * s)2349c69121c4SKristof Provost pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
2350c69121c4SKristof Provost {
2351c69121c4SKristof Provost 	nvlist_t	*nvl;
23525062afffSKristof Provost 	int		 ret;
23537bb3c927SKristof Provost 	uint		 state_limit;
2354c69121c4SKristof Provost 	bool		 enabled, adaptive;
2355c69121c4SKristof Provost 
2356d9ab8999SKristof Provost 	ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
23575062afffSKristof Provost 	if (ret != 0)
23585062afffSKristof Provost 		return (ret);
23595062afffSKristof Provost 
2360b70fadcaSKristof Provost 	if (state_limit == 0)
2361b70fadcaSKristof Provost 		state_limit = INT_MAX;
2362b70fadcaSKristof Provost 
2363c69121c4SKristof Provost 	bzero(s, sizeof(*s));
2364c69121c4SKristof Provost 
23657ed19f5cSKristof Provost 	nvl = nvlist_create(0);
2366c69121c4SKristof Provost 
2367498934c5SKristof Provost 	if ((ret = pfctl_do_ioctl(dev, DIOCGETSYNCOOKIES, 256, &nvl)) != 0) {
2368498934c5SKristof Provost 		ret = errno;
2369498934c5SKristof Provost 		goto out;
2370498934c5SKristof Provost 	}
2371c69121c4SKristof Provost 
2372c69121c4SKristof Provost 	enabled = nvlist_get_bool(nvl, "enabled");
2373c69121c4SKristof Provost 	adaptive = nvlist_get_bool(nvl, "adaptive");
2374c69121c4SKristof Provost 
23755062afffSKristof Provost 	if (enabled) {
23765062afffSKristof Provost 		if (adaptive)
23775062afffSKristof Provost 			s->mode = PFCTL_SYNCOOKIES_ADAPTIVE;
23785062afffSKristof Provost 		else
23795062afffSKristof Provost 			s->mode = PFCTL_SYNCOOKIES_ALWAYS;
23805062afffSKristof Provost 	} else {
23815062afffSKristof Provost 		s->mode = PFCTL_SYNCOOKIES_NEVER;
23825062afffSKristof Provost 	}
23835062afffSKristof Provost 
23845062afffSKristof Provost 	s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit;
23855062afffSKristof Provost 	s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit;
2386a6173e94SKristof Provost 	s->halfopen_states = nvlist_get_number(nvl, "halfopen_states");
2387c69121c4SKristof Provost 
2388498934c5SKristof Provost out:
2389c69121c4SKristof Provost 	nvlist_destroy(nvl);
2390498934c5SKristof Provost 	return (ret);
2391c69121c4SKristof Provost }
23924823489aSReid Linnemann 
23934823489aSReid Linnemann int
pfctl_table_add_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)23944823489aSReid Linnemann pfctl_table_add_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
23954823489aSReid Linnemann     *addr, int size, int *nadd, int flags)
23964823489aSReid Linnemann {
23974823489aSReid Linnemann 	struct pfioc_table io;
23984823489aSReid Linnemann 
23994823489aSReid Linnemann 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
24004823489aSReid Linnemann 		return (EINVAL);
24014823489aSReid Linnemann 	}
24024823489aSReid Linnemann 	bzero(&io, sizeof io);
24034823489aSReid Linnemann 	io.pfrio_flags = flags;
24044823489aSReid Linnemann 	io.pfrio_table = *tbl;
24054823489aSReid Linnemann 	io.pfrio_buffer = addr;
24064823489aSReid Linnemann 	io.pfrio_esize = sizeof(*addr);
24074823489aSReid Linnemann 	io.pfrio_size = size;
24084823489aSReid Linnemann 
24094823489aSReid Linnemann 	if (ioctl(dev, DIOCRADDADDRS, &io))
24104823489aSReid Linnemann 		return (errno);
24114823489aSReid Linnemann 	if (nadd != NULL)
24124823489aSReid Linnemann 		*nadd = io.pfrio_nadd;
24134823489aSReid Linnemann 	return (0);
24144823489aSReid Linnemann }
24154823489aSReid Linnemann 
24168b388995SKristof Provost static void
snl_add_msg_attr_table(struct snl_writer * nw,uint32_t type,const struct pfr_table * tbl)24178b388995SKristof Provost snl_add_msg_attr_table(struct snl_writer *nw, uint32_t type,
24188b388995SKristof Provost     const struct pfr_table *tbl)
24198b388995SKristof Provost {
24208b388995SKristof Provost 	int off;
24218b388995SKristof Provost 
24228b388995SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
24238b388995SKristof Provost 
24248b388995SKristof Provost 	snl_add_msg_attr_string(nw, PF_T_ANCHOR, tbl->pfrt_anchor);
24258b388995SKristof Provost 	snl_add_msg_attr_string(nw, PF_T_NAME, tbl->pfrt_name);
24268b388995SKristof Provost 	snl_add_msg_attr_u32(nw, PF_T_TABLE_FLAGS, tbl->pfrt_flags);
24278b388995SKristof Provost 
24288b388995SKristof Provost 	snl_end_attr_nested(nw, off);
24298b388995SKristof Provost }
24308b388995SKristof Provost 
24318b388995SKristof Provost static void
snl_add_msg_attr_pfr_addr(struct snl_writer * nw,uint32_t type,const struct pfr_addr * addr)24328b388995SKristof Provost snl_add_msg_attr_pfr_addr(struct snl_writer *nw, uint32_t type,
24338b388995SKristof Provost     const struct pfr_addr *addr)
24348b388995SKristof Provost {
24358b388995SKristof Provost 	int off;
24368b388995SKristof Provost 
24378b388995SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
24388b388995SKristof Provost 
24398b388995SKristof Provost 	snl_add_msg_attr_u8(nw, PFR_A_AF, addr->pfra_af);
24408b388995SKristof Provost 	snl_add_msg_attr_u8(nw, PFR_A_NET, addr->pfra_net);
24418b388995SKristof Provost 	snl_add_msg_attr_bool(nw, PFR_A_NOT, addr->pfra_not);
24428b388995SKristof Provost 	snl_add_msg_attr_ip6(nw, PFR_A_ADDR, &addr->pfra_ip6addr);
24438b388995SKristof Provost 
24448b388995SKristof Provost 	snl_end_attr_nested(nw, off);
24458b388995SKristof Provost }
24468b388995SKristof Provost 
24478b388995SKristof Provost static struct snl_attr_parser ap_table_add_addr[] = {
24488b388995SKristof Provost 	{ .type = PF_TA_NBR_ADDED, .off = 0, .cb = snl_attr_get_uint32 },
24498b388995SKristof Provost };
24508b388995SKristof Provost SNL_DECLARE_PARSER(table_add_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_add_addr);
24518b388995SKristof Provost 
24528b388995SKristof Provost static int
_pfctl_table_add_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nadd,int flags)24538b388995SKristof Provost _pfctl_table_add_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
24548b388995SKristof Provost     *addrs, int size, int *nadd, int flags)
24558b388995SKristof Provost {
24568b388995SKristof Provost 	struct snl_writer nw;
24578b388995SKristof Provost 	struct snl_errmsg_data e = {};
24588b388995SKristof Provost 	struct nlmsghdr *hdr;
24598b388995SKristof Provost 	uint32_t seq_id;
24608b388995SKristof Provost 	uint32_t added;
24618b388995SKristof Provost 	int family_id;
24628b388995SKristof Provost 
24638b388995SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
24648b388995SKristof Provost 	if (family_id == 0)
24658b388995SKristof Provost 		return (ENOTSUP);
24668b388995SKristof Provost 
24678b388995SKristof Provost 	snl_init_writer(&h->ss, &nw);
24688b388995SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_ADD_ADDR);
24698b388995SKristof Provost 
24708b388995SKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
24718b388995SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2472094a6028SKristof Provost 	for (int i = 0; i < size; i++)
24738b388995SKristof Provost 		snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
24748b388995SKristof Provost 
24758b388995SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
24768b388995SKristof Provost 		return (ENXIO);
24778b388995SKristof Provost 	seq_id = hdr->nlmsg_seq;
24788b388995SKristof Provost 
24798b388995SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
24808b388995SKristof Provost 		return (ENXIO);
24818b388995SKristof Provost 
24828b388995SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
24838b388995SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_add_addr_parser, &added))
24848b388995SKristof Provost 			continue;
24858b388995SKristof Provost 	}
24868b388995SKristof Provost 
24878b388995SKristof Provost 	if (nadd)
24888b388995SKristof Provost 		*nadd = added;
24898b388995SKristof Provost 
24908b388995SKristof Provost 	return (e.error);
24918b388995SKristof Provost }
24928b388995SKristof Provost 
24938b388995SKristof Provost int
pfctl_table_add_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)24948b388995SKristof Provost pfctl_table_add_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
24958b388995SKristof Provost     *addr, int size, int *nadd, int flags)
24968b388995SKristof Provost {
24978b388995SKristof Provost 	int ret;
24988b388995SKristof Provost 	int off = 0;
24998b388995SKristof Provost 	int partial_added;
2500094a6028SKristof Provost 	int chunk_size;
25018b388995SKristof Provost 
25028b388995SKristof Provost 	do {
2503094a6028SKristof Provost 		chunk_size = MIN(size - off, 256);
2504094a6028SKristof Provost 		ret = _pfctl_table_add_addrs_h(h, tbl, &addr[off], chunk_size, &partial_added, flags);
25058b388995SKristof Provost 		if (ret != 0)
25068b388995SKristof Provost 			break;
25078b388995SKristof Provost 		if (nadd)
25088b388995SKristof Provost 			*nadd += partial_added;
2509094a6028SKristof Provost 		off += chunk_size;
25108b388995SKristof Provost 	} while (off < size);
25118b388995SKristof Provost 
25128b388995SKristof Provost 	return (ret);
25138b388995SKristof Provost }
25148b388995SKristof Provost 
2515bad279e1SKristof Provost static struct snl_attr_parser ap_table_del_addr[] = {
2516bad279e1SKristof Provost 	{ .type = PF_TA_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint32 },
2517bad279e1SKristof Provost };
2518bad279e1SKristof Provost SNL_DECLARE_PARSER(table_del_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_del_addr);
2519bad279e1SKristof Provost static int
_pfctl_table_del_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * ndel,int flags)2520bad279e1SKristof Provost _pfctl_table_del_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2521bad279e1SKristof Provost     *addrs, int size, int *ndel, int flags)
2522bad279e1SKristof Provost {
2523bad279e1SKristof Provost 	struct snl_writer nw;
2524bad279e1SKristof Provost 	struct snl_errmsg_data e = {};
2525bad279e1SKristof Provost 	struct nlmsghdr *hdr;
2526bad279e1SKristof Provost 	uint32_t seq_id;
2527bad279e1SKristof Provost 	uint32_t deleted;
2528bad279e1SKristof Provost 	int family_id;
2529bad279e1SKristof Provost 
2530bad279e1SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
2531bad279e1SKristof Provost 	if (family_id == 0)
2532bad279e1SKristof Provost 		return (ENOTSUP);
2533bad279e1SKristof Provost 
2534bad279e1SKristof Provost 	snl_init_writer(&h->ss, &nw);
2535bad279e1SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_DEL_ADDR);
2536bad279e1SKristof Provost 
2537bad279e1SKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2538bad279e1SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2539094a6028SKristof Provost 	for (int i = 0; i < size; i++)
2540bad279e1SKristof Provost 		snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
2541bad279e1SKristof Provost 
2542bad279e1SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
2543bad279e1SKristof Provost 		return (ENXIO);
2544bad279e1SKristof Provost 	seq_id = hdr->nlmsg_seq;
2545bad279e1SKristof Provost 
2546bad279e1SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
2547bad279e1SKristof Provost 		return (ENXIO);
2548bad279e1SKristof Provost 
2549bad279e1SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2550bad279e1SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_del_addr_parser, &deleted))
2551bad279e1SKristof Provost 			continue;
2552bad279e1SKristof Provost 	}
2553bad279e1SKristof Provost 
2554bad279e1SKristof Provost 	if (ndel)
2555bad279e1SKristof Provost 		*ndel = deleted;
2556bad279e1SKristof Provost 
2557bad279e1SKristof Provost 	return (e.error);
2558bad279e1SKristof Provost }
2559bad279e1SKristof Provost 
25604823489aSReid Linnemann int
pfctl_table_del_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)25614823489aSReid Linnemann pfctl_table_del_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
25624823489aSReid Linnemann     *addr, int size, int *ndel, int flags)
25634823489aSReid Linnemann {
25644823489aSReid Linnemann 	struct pfioc_table io;
25654823489aSReid Linnemann 
25664823489aSReid Linnemann 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
25674823489aSReid Linnemann 		return (EINVAL);
25684823489aSReid Linnemann 	}
25694823489aSReid Linnemann 	bzero(&io, sizeof io);
25704823489aSReid Linnemann 	io.pfrio_flags = flags;
25714823489aSReid Linnemann 	io.pfrio_table = *tbl;
25724823489aSReid Linnemann 	io.pfrio_buffer = addr;
25734823489aSReid Linnemann 	io.pfrio_esize = sizeof(*addr);
25744823489aSReid Linnemann 	io.pfrio_size = size;
25754823489aSReid Linnemann 
25764823489aSReid Linnemann 	if (ioctl(dev, DIOCRDELADDRS, &io))
25774823489aSReid Linnemann 		return (errno);
25784823489aSReid Linnemann 	if (ndel != NULL)
25794823489aSReid Linnemann 		*ndel = io.pfrio_ndel;
25804823489aSReid Linnemann 	return (0);
25814823489aSReid Linnemann }
25824823489aSReid Linnemann 
25834823489aSReid Linnemann int
pfctl_table_del_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)2584bad279e1SKristof Provost pfctl_table_del_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2585bad279e1SKristof Provost     *addr, int size, int *ndel, int flags)
2586bad279e1SKristof Provost {
2587bad279e1SKristof Provost 	int ret;
2588bad279e1SKristof Provost 	int off = 0;
2589bad279e1SKristof Provost 	int partial_deleted;
2590094a6028SKristof Provost 	int chunk_size;
2591bad279e1SKristof Provost 
2592bad279e1SKristof Provost 	do {
2593094a6028SKristof Provost 		chunk_size = MIN(size - off, 256);
2594094a6028SKristof Provost 		ret = _pfctl_table_del_addrs_h(h, tbl, &addr[off], chunk_size,
2595bad279e1SKristof Provost 		    &partial_deleted, flags);
2596bad279e1SKristof Provost 		if (ret != 0)
2597bad279e1SKristof Provost 			break;
2598bad279e1SKristof Provost 		if (ndel)
2599bad279e1SKristof Provost 			*ndel += partial_deleted;
2600094a6028SKristof Provost 		off += chunk_size;
2601bad279e1SKristof Provost 	} while (off < size);
2602bad279e1SKristof Provost 
2603bad279e1SKristof Provost 	return (ret);
2604bad279e1SKristof Provost }
2605bad279e1SKristof Provost 
260608ed87a4SKristof Provost struct pfctl_change {
260708ed87a4SKristof Provost 	int add;
260808ed87a4SKristof Provost 	int del;
260908ed87a4SKristof Provost 	int change;
261008ed87a4SKristof Provost };
261108ed87a4SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_change, _field)
261208ed87a4SKristof Provost static struct snl_attr_parser ap_table_set_addr[] = {
261308ed87a4SKristof Provost 	{ .type = PF_TA_NBR_ADDED, .off = _OUT(add), .cb = snl_attr_get_uint32 },
261408ed87a4SKristof Provost 	{ .type = PF_TA_NBR_DELETED, .off = _OUT(del), .cb = snl_attr_get_uint32 },
261508ed87a4SKristof Provost 	{ .type = PF_TA_NBR_CHANGED, .off = _OUT(change), .cb = snl_attr_get_uint32 },
261608ed87a4SKristof Provost };
261708ed87a4SKristof Provost #undef _OUT
261808ed87a4SKristof Provost SNL_DECLARE_PARSER(table_set_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_set_addr);
261908ed87a4SKristof Provost 
262008ed87a4SKristof Provost static int
_pfctl_table_set_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nadd,int * ndel,int * nchange,int flags)262108ed87a4SKristof Provost _pfctl_table_set_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
262208ed87a4SKristof Provost     *addrs, int size, int *nadd, int *ndel, int *nchange, int flags)
262308ed87a4SKristof Provost {
262408ed87a4SKristof Provost 	struct snl_writer nw;
262508ed87a4SKristof Provost 	struct snl_errmsg_data e = {};
262608ed87a4SKristof Provost 	struct nlmsghdr *hdr;
262708ed87a4SKristof Provost 	struct pfctl_change change = { 0 };
262808ed87a4SKristof Provost 	uint32_t seq_id;
262908ed87a4SKristof Provost 	int family_id;
263008ed87a4SKristof Provost 
263108ed87a4SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
263208ed87a4SKristof Provost 	if (family_id == 0)
263308ed87a4SKristof Provost 		return (ENOTSUP);
263408ed87a4SKristof Provost 
263508ed87a4SKristof Provost 	snl_init_writer(&h->ss, &nw);
263608ed87a4SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_SET_ADDR);
263708ed87a4SKristof Provost 
263808ed87a4SKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
263908ed87a4SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
264008ed87a4SKristof Provost 	for (int i = 0; i < size; i++)
264108ed87a4SKristof Provost 		snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
264208ed87a4SKristof Provost 
264308ed87a4SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
264408ed87a4SKristof Provost 		return (ENXIO);
264508ed87a4SKristof Provost 	seq_id = hdr->nlmsg_seq;
264608ed87a4SKristof Provost 
264708ed87a4SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
264808ed87a4SKristof Provost 		return (ENXIO);
264908ed87a4SKristof Provost 
265008ed87a4SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
265108ed87a4SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_set_addr_parser, &change))
265208ed87a4SKristof Provost 			continue;
265308ed87a4SKristof Provost 	}
265408ed87a4SKristof Provost 
265508ed87a4SKristof Provost 	if (nadd)
265608ed87a4SKristof Provost 		*nadd = change.add;
265708ed87a4SKristof Provost 	if (ndel)
265808ed87a4SKristof Provost 		*ndel = change.del;
265908ed87a4SKristof Provost 	if (nchange)
266008ed87a4SKristof Provost 		*nchange = change.change;
266108ed87a4SKristof Provost 
266208ed87a4SKristof Provost 	return (e.error);
266308ed87a4SKristof Provost }
266408ed87a4SKristof Provost 
266508ed87a4SKristof Provost int
pfctl_table_set_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * ndel,int * nchange,int flags)266608ed87a4SKristof Provost pfctl_table_set_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
266708ed87a4SKristof Provost     struct pfr_addr *addr, int size, int *nadd, int *ndel,
266808ed87a4SKristof Provost     int *nchange, int flags)
266908ed87a4SKristof Provost {
267008ed87a4SKristof Provost 	int ret;
267108ed87a4SKristof Provost 	int off = 0;
267208ed87a4SKristof Provost 	int partial_add, partial_del, partial_change;
267308ed87a4SKristof Provost 	int chunk_size;
267408ed87a4SKristof Provost 
267508ed87a4SKristof Provost 	do {
267608ed87a4SKristof Provost 		flags &= ~(PFR_FLAG_START | PFR_FLAG_DONE);
267708ed87a4SKristof Provost 		if (off == 0)
267808ed87a4SKristof Provost 			flags |= PFR_FLAG_START;
267908ed87a4SKristof Provost 		chunk_size = MIN(size - off, 256);
268008ed87a4SKristof Provost 		if ((chunk_size + off) == size)
268108ed87a4SKristof Provost 			flags |= PFR_FLAG_DONE;
268208ed87a4SKristof Provost 		ret = _pfctl_table_set_addrs_h(h, tbl, &addr[off], chunk_size,
268308ed87a4SKristof Provost 		    &partial_add, &partial_del, &partial_change, flags);
268408ed87a4SKristof Provost 		if (ret != 0)
268508ed87a4SKristof Provost 			break;
268608ed87a4SKristof Provost 		if (! (flags & PFR_FLAG_DONE)) {
268708ed87a4SKristof Provost 			assert(partial_del == 0);
268808ed87a4SKristof Provost 		}
268908ed87a4SKristof Provost 		if (nadd)
269008ed87a4SKristof Provost 			*nadd += partial_add;
269108ed87a4SKristof Provost 		if (ndel)
269208ed87a4SKristof Provost 			*ndel += partial_del;
269308ed87a4SKristof Provost 		if (nchange)
269408ed87a4SKristof Provost 			*nchange += partial_change;
269508ed87a4SKristof Provost 		off += chunk_size;
269608ed87a4SKristof Provost 	} while (off < size);
269708ed87a4SKristof Provost 
269808ed87a4SKristof Provost 	return (ret);
269908ed87a4SKristof Provost }
270008ed87a4SKristof Provost 
2701bad279e1SKristof Provost int
pfctl_table_set_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags)27024823489aSReid Linnemann pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
27034823489aSReid Linnemann     *addr, int size, int *size2, int *nadd, int *ndel, int *nchange, int flags)
27044823489aSReid Linnemann {
27054823489aSReid Linnemann 	struct pfioc_table io;
27064823489aSReid Linnemann 
27074823489aSReid Linnemann 	if (tbl == NULL || size < 0 || (size && addr == NULL)) {
27084823489aSReid Linnemann 		return (EINVAL);
27094823489aSReid Linnemann 	}
27104823489aSReid Linnemann 	bzero(&io, sizeof io);
27114823489aSReid Linnemann 	io.pfrio_flags = flags;
27124823489aSReid Linnemann 	io.pfrio_table = *tbl;
27134823489aSReid Linnemann 	io.pfrio_buffer = addr;
27144823489aSReid Linnemann 	io.pfrio_esize = sizeof(*addr);
27154823489aSReid Linnemann 	io.pfrio_size = size;
27164823489aSReid Linnemann 	io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
27174823489aSReid Linnemann 	if (ioctl(dev, DIOCRSETADDRS, &io))
271893e96359SKristof Provost 		return (errno);
27194823489aSReid Linnemann 	if (nadd != NULL)
27204823489aSReid Linnemann 		*nadd = io.pfrio_nadd;
27214823489aSReid Linnemann 	if (ndel != NULL)
27224823489aSReid Linnemann 		*ndel = io.pfrio_ndel;
27234823489aSReid Linnemann 	if (nchange != NULL)
27244823489aSReid Linnemann 		*nchange = io.pfrio_nchange;
27254823489aSReid Linnemann 	if (size2 != NULL)
27264823489aSReid Linnemann 		*size2 = io.pfrio_size2;
27274823489aSReid Linnemann 	return (0);
27284823489aSReid Linnemann }
27294823489aSReid Linnemann 
pfctl_table_get_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)27304823489aSReid Linnemann int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr,
27314823489aSReid Linnemann     int *size, int flags)
27324823489aSReid Linnemann {
27334823489aSReid Linnemann 	struct pfioc_table io;
27344823489aSReid Linnemann 
27354823489aSReid Linnemann 	if (tbl == NULL || size == NULL || *size < 0 ||
27364823489aSReid Linnemann 	    (*size && addr == NULL)) {
27374823489aSReid Linnemann 		return (EINVAL);
27384823489aSReid Linnemann 	}
27394823489aSReid Linnemann 	bzero(&io, sizeof io);
27404823489aSReid Linnemann 	io.pfrio_flags = flags;
27414823489aSReid Linnemann 	io.pfrio_table = *tbl;
27424823489aSReid Linnemann 	io.pfrio_buffer = addr;
27434823489aSReid Linnemann 	io.pfrio_esize = sizeof(*addr);
27444823489aSReid Linnemann 	io.pfrio_size = *size;
27454823489aSReid Linnemann 	if (ioctl(dev, DIOCRGETADDRS, &io))
274693e96359SKristof Provost 		return (errno);
27474823489aSReid Linnemann 	*size = io.pfrio_size;
27484823489aSReid Linnemann 	return (0);
27494823489aSReid Linnemann }
2750470a2b33SKristof Provost 
2751f27e44e2SKristof Provost struct nl_addrs {
2752f27e44e2SKristof Provost 	size_t max;
2753f27e44e2SKristof Provost 	struct pfr_addr	*addrs;
2754f27e44e2SKristof Provost 	size_t count;
2755f27e44e2SKristof Provost 	size_t total_count;
2756f27e44e2SKristof Provost };
2757f27e44e2SKristof Provost 
2758f27e44e2SKristof Provost #define _OUT(_field)	offsetof(struct pfr_addr, _field)
2759f27e44e2SKristof Provost static const struct snl_attr_parser ap_pfr_addr[] = {
2760f27e44e2SKristof Provost 	{ .type = PFR_A_AF, .off = _OUT(pfra_af), .cb = snl_attr_get_uint32 },
2761f27e44e2SKristof Provost 	{ .type = PFR_A_NET, .off = _OUT(pfra_net), .cb = snl_attr_get_uint8 },
2762f27e44e2SKristof Provost 	{ .type = PFR_A_NOT, .off = _OUT(pfra_not), .cb = snl_attr_get_bool },
2763f27e44e2SKristof Provost 	{ .type = PFR_A_ADDR, .off = _OUT(pfra_ip6addr), .cb = snl_attr_get_in6_addr },
2764f27e44e2SKristof Provost };
2765f27e44e2SKristof Provost #undef _OUT
2766f27e44e2SKristof Provost SNL_DECLARE_ATTR_PARSER(pfr_addr_parser, ap_pfr_addr);
2767f27e44e2SKristof Provost 
2768f27e44e2SKristof Provost static bool
snl_attr_get_pfr_addrs(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)2769f27e44e2SKristof Provost snl_attr_get_pfr_addrs(struct snl_state *ss, struct nlattr *nla,
2770f27e44e2SKristof Provost     const void *arg __unused, void *target)
2771f27e44e2SKristof Provost {
2772f27e44e2SKristof Provost 	struct nl_addrs *a = (struct nl_addrs *)target;
2773f27e44e2SKristof Provost 	bool ret;
2774f27e44e2SKristof Provost 
2775f27e44e2SKristof Provost 	if (a->count >= a->max)
2776f27e44e2SKristof Provost 		return (false);
2777f27e44e2SKristof Provost 
2778f27e44e2SKristof Provost 	ret = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla),
2779f27e44e2SKristof Provost 	    &pfr_addr_parser, &a->addrs[a->count]);
2780f27e44e2SKristof Provost 	if (ret)
2781f27e44e2SKristof Provost 		a->count++;
2782f27e44e2SKristof Provost 
2783f27e44e2SKristof Provost 	return (ret);
2784f27e44e2SKristof Provost }
2785f27e44e2SKristof Provost 
2786f27e44e2SKristof Provost #define _OUT(_field)	offsetof(struct nl_addrs, _field)
2787f27e44e2SKristof Provost static struct snl_attr_parser ap_table_get_addr[] = {
2788f27e44e2SKristof Provost 	{ .type = PF_TA_ADDR, .off = 0, .cb = snl_attr_get_pfr_addrs },
2789f27e44e2SKristof Provost 	{ .type = PF_TA_ADDR_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
2790f27e44e2SKristof Provost };
2791f27e44e2SKristof Provost #undef _OUT
2792f27e44e2SKristof Provost SNL_DECLARE_PARSER(table_get_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_addr);
2793f27e44e2SKristof Provost int
pfctl_table_get_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)2794f27e44e2SKristof Provost pfctl_table_get_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
2795f27e44e2SKristof Provost     struct pfr_addr *addr, int *size, int flags)
2796f27e44e2SKristof Provost {
2797f27e44e2SKristof Provost 	struct nl_addrs addrs = { 0 };
2798f27e44e2SKristof Provost 	struct snl_writer nw;
2799f27e44e2SKristof Provost 	struct snl_errmsg_data e = {};
2800f27e44e2SKristof Provost 	struct nlmsghdr *hdr;
2801f27e44e2SKristof Provost 	uint32_t seq_id;
2802f27e44e2SKristof Provost 	int family_id;
2803f27e44e2SKristof Provost 
2804f27e44e2SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
2805f27e44e2SKristof Provost 	if (family_id == 0)
2806f27e44e2SKristof Provost 		return (ENOTSUP);
2807f27e44e2SKristof Provost 
2808f27e44e2SKristof Provost 	snl_init_writer(&h->ss, &nw);
2809f27e44e2SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_GET_ADDR);
2810f27e44e2SKristof Provost 
2811f27e44e2SKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2812f27e44e2SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2813f27e44e2SKristof Provost 
2814f27e44e2SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
2815f27e44e2SKristof Provost 		return (ENXIO);
2816f27e44e2SKristof Provost 
2817f27e44e2SKristof Provost 	seq_id = hdr->nlmsg_seq;
2818f27e44e2SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
2819f27e44e2SKristof Provost 		return (ENXIO);
2820f27e44e2SKristof Provost 
2821f27e44e2SKristof Provost 	addrs.addrs = addr;
2822f27e44e2SKristof Provost 	addrs.max = *size;
2823f27e44e2SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2824f27e44e2SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_get_addr_parser, &addrs))
2825f27e44e2SKristof Provost 			continue;
2826f27e44e2SKristof Provost 	}
2827f27e44e2SKristof Provost 
2828f27e44e2SKristof Provost 	*size = addrs.total_count;
2829f27e44e2SKristof Provost 
2830f27e44e2SKristof Provost 	return (e.error);
2831f27e44e2SKristof Provost }
2832f27e44e2SKristof Provost 
2833470a2b33SKristof Provost int
pfctl_set_statusif(struct pfctl_handle * h,const char * ifname)2834470a2b33SKristof Provost pfctl_set_statusif(struct pfctl_handle *h, const char *ifname)
2835470a2b33SKristof Provost {
2836470a2b33SKristof Provost 	struct snl_writer nw;
2837470a2b33SKristof Provost 	struct snl_errmsg_data e = {};
2838470a2b33SKristof Provost 	struct nlmsghdr *hdr;
2839470a2b33SKristof Provost 	uint32_t seq_id;
2840470a2b33SKristof Provost 	int family_id;
2841470a2b33SKristof Provost 
2842470a2b33SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
2843470a2b33SKristof Provost 	if (family_id == 0)
2844470a2b33SKristof Provost 		return (ENOTSUP);
2845470a2b33SKristof Provost 
2846470a2b33SKristof Provost 	snl_init_writer(&h->ss, &nw);
2847470a2b33SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_STATUSIF);
2848470a2b33SKristof Provost 
2849470a2b33SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SS_IFNAME, ifname);
2850470a2b33SKristof Provost 
2851470a2b33SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
2852470a2b33SKristof Provost 		return (ENXIO);
2853470a2b33SKristof Provost 
2854470a2b33SKristof Provost 	seq_id = hdr->nlmsg_seq;
2855470a2b33SKristof Provost 
2856470a2b33SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
2857470a2b33SKristof Provost 		return (ENXIO);
2858470a2b33SKristof Provost 
2859470a2b33SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2860470a2b33SKristof Provost 	}
2861470a2b33SKristof Provost 
2862470a2b33SKristof Provost 	return (e.error);
2863470a2b33SKristof Provost }
286471d3c704SKristof Provost 
286571d3c704SKristof Provost #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
286671d3c704SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_natlook, _field)
286771d3c704SKristof Provost static struct snl_attr_parser ap_natlook[] = {
286871d3c704SKristof Provost 	{ .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = snl_attr_get_in6_addr },
286971d3c704SKristof Provost 	{ .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = snl_attr_get_in6_addr },
287071d3c704SKristof Provost 	{ .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = snl_attr_get_uint16 },
287171d3c704SKristof Provost 	{ .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = snl_attr_get_uint16 },
287271d3c704SKristof Provost };
287371d3c704SKristof Provost #undef _IN
287471d3c704SKristof Provost #undef _OUT
28757c882c69SKristof Provost SNL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, snl_f_p_empty, ap_natlook);
287671d3c704SKristof Provost 
287771d3c704SKristof Provost int
pfctl_natlook(struct pfctl_handle * h,const struct pfctl_natlook_key * k,struct pfctl_natlook * r)287871d3c704SKristof Provost pfctl_natlook(struct pfctl_handle *h, const struct pfctl_natlook_key *k,
287971d3c704SKristof Provost     struct pfctl_natlook *r)
288071d3c704SKristof Provost {
288171d3c704SKristof Provost 	struct snl_writer nw;
288271d3c704SKristof Provost 	struct snl_errmsg_data e = {};
288371d3c704SKristof Provost 	struct nlmsghdr *hdr;
288471d3c704SKristof Provost 	uint32_t seq_id;
288571d3c704SKristof Provost 	int family_id;
288671d3c704SKristof Provost 
288771d3c704SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
288871d3c704SKristof Provost 	if (family_id == 0)
288971d3c704SKristof Provost 		return (ENOTSUP);
289071d3c704SKristof Provost 
289171d3c704SKristof Provost 	snl_init_writer(&h->ss, &nw);
289271d3c704SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_NATLOOK);
289371d3c704SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
289471d3c704SKristof Provost 
289571d3c704SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_NL_AF, k->af);
289671d3c704SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_NL_DIRECTION, k->direction);
289771d3c704SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_NL_PROTO, k->proto);
289871d3c704SKristof Provost 	snl_add_msg_attr_ip6(&nw, PF_NL_SRC_ADDR, &k->saddr.v6);
289971d3c704SKristof Provost 	snl_add_msg_attr_ip6(&nw, PF_NL_DST_ADDR, &k->daddr.v6);
290071d3c704SKristof Provost 	snl_add_msg_attr_u16(&nw, PF_NL_SRC_PORT, k->sport);
290171d3c704SKristof Provost 	snl_add_msg_attr_u16(&nw, PF_NL_DST_PORT, k->dport);
290271d3c704SKristof Provost 
290371d3c704SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
290471d3c704SKristof Provost 		return (ENXIO);
290571d3c704SKristof Provost 
290671d3c704SKristof Provost 	seq_id = hdr->nlmsg_seq;
290771d3c704SKristof Provost 
290871d3c704SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
290971d3c704SKristof Provost 		return (ENXIO);
291071d3c704SKristof Provost 
291171d3c704SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
291271d3c704SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &natlook_parser, r))
291371d3c704SKristof Provost 			continue;
291471d3c704SKristof Provost 	}
291571d3c704SKristof Provost 
291671d3c704SKristof Provost 	return (e.error);
291771d3c704SKristof Provost }
2918c36c90a2SKristof Provost 
2919c36c90a2SKristof Provost int
pfctl_set_debug(struct pfctl_handle * h,uint32_t level)2920c36c90a2SKristof Provost pfctl_set_debug(struct pfctl_handle *h, uint32_t level)
2921c36c90a2SKristof Provost {
2922c36c90a2SKristof Provost 	struct snl_writer nw;
2923c36c90a2SKristof Provost 	struct snl_errmsg_data e = {};
2924c36c90a2SKristof Provost 	struct nlmsghdr *hdr;
2925c36c90a2SKristof Provost 	uint32_t seq_id;
2926c36c90a2SKristof Provost 	int family_id;
2927c36c90a2SKristof Provost 
2928c36c90a2SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
2929c36c90a2SKristof Provost 	if (family_id == 0)
2930c36c90a2SKristof Provost 		return (ENOTSUP);
2931c36c90a2SKristof Provost 
2932c36c90a2SKristof Provost 	snl_init_writer(&h->ss, &nw);
2933c36c90a2SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_DEBUG);
2934c36c90a2SKristof Provost 
2935c36c90a2SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SD_LEVEL, level);
2936c36c90a2SKristof Provost 
2937c36c90a2SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
2938c36c90a2SKristof Provost 		return (ENXIO);
2939c36c90a2SKristof Provost 
2940c36c90a2SKristof Provost 	seq_id = hdr->nlmsg_seq;
2941c36c90a2SKristof Provost 
2942c36c90a2SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
2943c36c90a2SKristof Provost 		return (ENXIO);
2944c36c90a2SKristof Provost 
2945c36c90a2SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2946c36c90a2SKristof Provost 	}
2947c36c90a2SKristof Provost 
2948c36c90a2SKristof Provost 	return (e.error);
2949c36c90a2SKristof Provost }
295030bad751SKristof Provost 
295130bad751SKristof Provost int
pfctl_set_timeout(struct pfctl_handle * h,uint32_t timeout,uint32_t seconds)295230bad751SKristof Provost pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds)
295330bad751SKristof Provost {
295430bad751SKristof Provost 	struct snl_writer nw;
295530bad751SKristof Provost 	struct snl_errmsg_data e = {};
295630bad751SKristof Provost 	struct nlmsghdr *hdr;
295730bad751SKristof Provost 	uint32_t seq_id;
295830bad751SKristof Provost 	int family_id;
295930bad751SKristof Provost 
296030bad751SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
296130bad751SKristof Provost 	if (family_id == 0)
296230bad751SKristof Provost 		return (ENOTSUP);
296330bad751SKristof Provost 
296430bad751SKristof Provost 	snl_init_writer(&h->ss, &nw);
296530bad751SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_TIMEOUT);
296630bad751SKristof Provost 
296730bad751SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
296830bad751SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TO_SECONDS, seconds);
296930bad751SKristof Provost 
297030bad751SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
297130bad751SKristof Provost 		return (ENXIO);
297230bad751SKristof Provost 
297330bad751SKristof Provost 	seq_id = hdr->nlmsg_seq;
297430bad751SKristof Provost 
297530bad751SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
297630bad751SKristof Provost 		return (ENXIO);
297730bad751SKristof Provost 
297830bad751SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
297930bad751SKristof Provost 	}
298030bad751SKristof Provost 
298130bad751SKristof Provost 	return (e.error);
298230bad751SKristof Provost }
298330bad751SKristof Provost 
298430bad751SKristof Provost struct pfctl_nl_timeout {
298530bad751SKristof Provost 	uint32_t seconds;
298630bad751SKristof Provost };
298730bad751SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_nl_timeout, _field)
298830bad751SKristof Provost static struct snl_attr_parser ap_get_timeout[] = {
298930bad751SKristof Provost 	{ .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
299030bad751SKristof Provost };
299130bad751SKristof Provost #undef _OUT
29927c882c69SKristof Provost SNL_DECLARE_PARSER(get_timeout_parser, struct genlmsghdr, snl_f_p_empty, ap_get_timeout);
299330bad751SKristof Provost 
299430bad751SKristof Provost int
pfctl_get_timeout(struct pfctl_handle * h,uint32_t timeout,uint32_t * seconds)299530bad751SKristof Provost pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds)
299630bad751SKristof Provost {
299730bad751SKristof Provost 	struct snl_writer nw;
299830bad751SKristof Provost 	struct pfctl_nl_timeout to = {};
299930bad751SKristof Provost 	struct snl_errmsg_data e = {};
300030bad751SKristof Provost 	struct nlmsghdr *hdr;
300130bad751SKristof Provost 	uint32_t seq_id;
300230bad751SKristof Provost 	int family_id;
300330bad751SKristof Provost 
300430bad751SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
300530bad751SKristof Provost 	if (family_id == 0)
300630bad751SKristof Provost 		return (ENOTSUP);
300730bad751SKristof Provost 
300830bad751SKristof Provost 	snl_init_writer(&h->ss, &nw);
300930bad751SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_TIMEOUT);
301030bad751SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
301130bad751SKristof Provost 
301230bad751SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
301330bad751SKristof Provost 
301430bad751SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
301530bad751SKristof Provost 		return (ENXIO);
301630bad751SKristof Provost 
301730bad751SKristof Provost 	seq_id = hdr->nlmsg_seq;
301830bad751SKristof Provost 
301930bad751SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
302030bad751SKristof Provost 		return (ENXIO);
302130bad751SKristof Provost 
302230bad751SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
302330bad751SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &get_timeout_parser, &to))
302430bad751SKristof Provost 			continue;
302530bad751SKristof Provost 	}
302630bad751SKristof Provost 
302730bad751SKristof Provost 	if (seconds != NULL)
302830bad751SKristof Provost 		*seconds = to.seconds;
302930bad751SKristof Provost 
303030bad751SKristof Provost 	return (e.error);
303130bad751SKristof Provost }
303230bad751SKristof Provost 
3033d9ab8999SKristof Provost int
pfctl_set_limit(struct pfctl_handle * h,const int index,const uint limit)3034d9ab8999SKristof Provost pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit)
3035d9ab8999SKristof Provost {
3036d9ab8999SKristof Provost 	struct snl_writer nw;
3037d9ab8999SKristof Provost 	struct snl_errmsg_data e = {};
3038d9ab8999SKristof Provost 	struct nlmsghdr *hdr;
3039d9ab8999SKristof Provost 	uint32_t seq_id;
3040d9ab8999SKristof Provost 	int family_id;
3041d9ab8999SKristof Provost 
3042d9ab8999SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3043d9ab8999SKristof Provost 	if (family_id == 0)
3044d9ab8999SKristof Provost 		return (ENOTSUP);
3045d9ab8999SKristof Provost 
3046d9ab8999SKristof Provost 	snl_init_writer(&h->ss, &nw);
3047d9ab8999SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SET_LIMIT);
3048d9ab8999SKristof Provost 
3049d9ab8999SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
3050d9ab8999SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_LI_LIMIT, limit);
3051d9ab8999SKristof Provost 
3052d9ab8999SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3053d9ab8999SKristof Provost 		return (ENXIO);
3054d9ab8999SKristof Provost 
3055d9ab8999SKristof Provost 	seq_id = hdr->nlmsg_seq;
3056d9ab8999SKristof Provost 
3057d9ab8999SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3058d9ab8999SKristof Provost 		return (ENXIO);
3059d9ab8999SKristof Provost 
3060d9ab8999SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3061d9ab8999SKristof Provost 	}
3062d9ab8999SKristof Provost 
3063d9ab8999SKristof Provost 	return (e.error);
3064d9ab8999SKristof Provost }
3065d9ab8999SKristof Provost 
3066d9ab8999SKristof Provost struct pfctl_nl_limit {
3067d9ab8999SKristof Provost 	unsigned int limit;
3068d9ab8999SKristof Provost };
3069d9ab8999SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_nl_limit, _field)
3070d9ab8999SKristof Provost static struct snl_attr_parser ap_get_limit[] = {
3071d9ab8999SKristof Provost 	{ .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
3072d9ab8999SKristof Provost };
3073d9ab8999SKristof Provost #undef _OUT
30747c882c69SKristof Provost SNL_DECLARE_PARSER(get_limit_parser, struct genlmsghdr, snl_f_p_empty, ap_get_limit);
3075d9ab8999SKristof Provost 
3076d9ab8999SKristof Provost int
pfctl_get_limit(struct pfctl_handle * h,const int index,uint * limit)3077d9ab8999SKristof Provost pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit)
3078d9ab8999SKristof Provost {
3079d9ab8999SKristof Provost 	struct snl_writer nw;
3080d9ab8999SKristof Provost 	struct pfctl_nl_limit li = {};
3081d9ab8999SKristof Provost 	struct snl_errmsg_data e = {};
3082d9ab8999SKristof Provost 	struct nlmsghdr *hdr;
3083d9ab8999SKristof Provost 	uint32_t seq_id;
3084d9ab8999SKristof Provost 	int family_id;
3085d9ab8999SKristof Provost 
3086d9ab8999SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3087d9ab8999SKristof Provost 	if (family_id == 0)
3088d9ab8999SKristof Provost 		return (ENOTSUP);
3089d9ab8999SKristof Provost 
3090d9ab8999SKristof Provost 	snl_init_writer(&h->ss, &nw);
3091d9ab8999SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_LIMIT);
3092d9ab8999SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
3093d9ab8999SKristof Provost 
3094d9ab8999SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
3095d9ab8999SKristof Provost 
3096d9ab8999SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3097d9ab8999SKristof Provost 		return (ENXIO);
3098d9ab8999SKristof Provost 
3099d9ab8999SKristof Provost 	seq_id = hdr->nlmsg_seq;
3100d9ab8999SKristof Provost 
3101d9ab8999SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3102d9ab8999SKristof Provost 		return (ENXIO);
3103d9ab8999SKristof Provost 
3104d9ab8999SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3105d9ab8999SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &get_limit_parser, &li))
3106d9ab8999SKristof Provost 			continue;
3107d9ab8999SKristof Provost 	}
3108d9ab8999SKristof Provost 
3109d9ab8999SKristof Provost 	if (limit != NULL)
3110d9ab8999SKristof Provost 		*limit = li.limit;
3111d9ab8999SKristof Provost 
3112d9ab8999SKristof Provost 	return (e.error);
3113d9ab8999SKristof Provost }
3114ba2a9207SKristof Provost 
3115ba2a9207SKristof Provost struct pfctl_nl_begin_addrs {
3116ba2a9207SKristof Provost 	uint32_t ticket;
3117ba2a9207SKristof Provost };
3118ba2a9207SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_nl_begin_addrs, _field)
3119ba2a9207SKristof Provost static struct snl_attr_parser ap_begin_addrs[] = {
3120ba2a9207SKristof Provost 	{ .type = PF_BA_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
3121ba2a9207SKristof Provost };
3122ba2a9207SKristof Provost #undef _OUT
31237c882c69SKristof Provost SNL_DECLARE_PARSER(begin_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_begin_addrs);
3124ba2a9207SKristof Provost 
3125ba2a9207SKristof Provost int
pfctl_begin_addrs(struct pfctl_handle * h,uint32_t * ticket)3126ba2a9207SKristof Provost pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket)
3127ba2a9207SKristof Provost {
3128ba2a9207SKristof Provost 	struct snl_writer nw;
3129ba2a9207SKristof Provost 	struct pfctl_nl_begin_addrs attrs = {};
3130ba2a9207SKristof Provost 	struct snl_errmsg_data e = {};
3131ba2a9207SKristof Provost 	struct nlmsghdr *hdr;
3132ba2a9207SKristof Provost 	uint32_t seq_id;
3133ba2a9207SKristof Provost 	int family_id;
3134ba2a9207SKristof Provost 
3135ba2a9207SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3136ba2a9207SKristof Provost 	if (family_id == 0)
3137ba2a9207SKristof Provost 		return (ENOTSUP);
3138ba2a9207SKristof Provost 
3139ba2a9207SKristof Provost 	snl_init_writer(&h->ss, &nw);
3140ba2a9207SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_BEGIN_ADDRS);
3141ba2a9207SKristof Provost 	hdr->nlmsg_flags |= NLM_F_DUMP;
3142ba2a9207SKristof Provost 
3143ba2a9207SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3144ba2a9207SKristof Provost 		return (ENXIO);
3145ba2a9207SKristof Provost 
3146ba2a9207SKristof Provost 	seq_id = hdr->nlmsg_seq;
3147ba2a9207SKristof Provost 
3148ba2a9207SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3149ba2a9207SKristof Provost 		return (ENXIO);
3150ba2a9207SKristof Provost 
3151ba2a9207SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3152ba2a9207SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &begin_addrs_parser, &attrs))
3153ba2a9207SKristof Provost 			continue;
3154ba2a9207SKristof Provost 	}
3155ba2a9207SKristof Provost 
3156ba2a9207SKristof Provost 	if (ticket != NULL)
3157ba2a9207SKristof Provost 		*ticket = attrs.ticket;
3158ba2a9207SKristof Provost 
3159ba2a9207SKristof Provost 	return (e.error);
3160ba2a9207SKristof Provost }
3161ba2a9207SKristof Provost 
3162d909f06bSKristof Provost int
pfctl_add_addr(struct pfctl_handle * h,const struct pfioc_pooladdr * pa,int which)3163aa69fdf1SKristof Provost pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which)
3164d909f06bSKristof Provost {
3165d909f06bSKristof Provost 	struct snl_writer nw;
3166d909f06bSKristof Provost 	struct snl_errmsg_data e = {};
3167d909f06bSKristof Provost 	struct nlmsghdr *hdr;
3168d909f06bSKristof Provost 	uint32_t seq_id;
3169d909f06bSKristof Provost 	int family_id;
3170d909f06bSKristof Provost 
3171d909f06bSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3172d909f06bSKristof Provost 	if (family_id == 0)
3173d909f06bSKristof Provost 		return (ENOTSUP);
3174d909f06bSKristof Provost 
3175d909f06bSKristof Provost 	snl_init_writer(&h->ss, &nw);
3176d909f06bSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_ADD_ADDR);
3177d909f06bSKristof Provost 
3178d909f06bSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_ACTION, pa->action);
3179d909f06bSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_TICKET, pa->ticket);
3180d909f06bSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_NR, pa->nr);
3181d909f06bSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, pa->r_num);
3182d909f06bSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, pa->r_action);
3183d909f06bSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_AA_R_LAST, pa->r_last);
3184d909f06bSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_AA_AF, pa->af);
3185d909f06bSKristof Provost 	snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, pa->anchor);
3186d909f06bSKristof Provost 	snl_add_msg_attr_pool_addr(&nw, PF_AA_ADDR, &pa->addr);
3187aa69fdf1SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
3188d909f06bSKristof Provost 
3189d909f06bSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3190d909f06bSKristof Provost 		return (ENXIO);
3191d909f06bSKristof Provost 
3192d909f06bSKristof Provost 	seq_id = hdr->nlmsg_seq;
3193d909f06bSKristof Provost 
3194d909f06bSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3195d909f06bSKristof Provost 		return (ENXIO);
3196d909f06bSKristof Provost 
3197d909f06bSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3198d909f06bSKristof Provost 	}
3199d909f06bSKristof Provost 
3200d909f06bSKristof Provost 	return (e.error);
3201d909f06bSKristof Provost }
3202644b7b5aSKristof Provost 
3203644b7b5aSKristof Provost static const struct snl_attr_parser ap_get_addrs[] = {
3204644b7b5aSKristof Provost 	{ .type = PF_AA_NR, .off = 0, .cb = snl_attr_get_uint32 },
3205644b7b5aSKristof Provost };
32067c882c69SKristof Provost SNL_DECLARE_PARSER(get_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_get_addrs);
3207644b7b5aSKristof Provost 
3208644b7b5aSKristof Provost int
pfctl_get_addrs(struct pfctl_handle * h,uint32_t ticket,uint32_t r_num,uint8_t r_action,const char * anchor,uint32_t * nr,int which)3209644b7b5aSKristof Provost pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
3210aa69fdf1SKristof Provost     uint8_t r_action, const char *anchor, uint32_t *nr, int which)
3211644b7b5aSKristof Provost {
3212644b7b5aSKristof Provost 	struct snl_writer nw;
3213644b7b5aSKristof Provost 	struct snl_errmsg_data e = {};
3214644b7b5aSKristof Provost 	struct nlmsghdr *hdr;
3215644b7b5aSKristof Provost 	uint32_t seq_id;
3216644b7b5aSKristof Provost 	int family_id;
3217644b7b5aSKristof Provost 
3218644b7b5aSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3219644b7b5aSKristof Provost 	if (family_id == 0)
3220644b7b5aSKristof Provost 		return (ENOTSUP);
3221644b7b5aSKristof Provost 
3222644b7b5aSKristof Provost 	snl_init_writer(&h->ss, &nw);
3223644b7b5aSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_ADDRS);
3224644b7b5aSKristof Provost 
3225644b7b5aSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_TICKET, ticket);
3226644b7b5aSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num);
3227644b7b5aSKristof Provost 	snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action);
3228644b7b5aSKristof Provost 	snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor);
3229aa69fdf1SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
3230644b7b5aSKristof Provost 
3231644b7b5aSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3232644b7b5aSKristof Provost 		return (ENXIO);
3233644b7b5aSKristof Provost 
3234644b7b5aSKristof Provost 	seq_id = hdr->nlmsg_seq;
3235644b7b5aSKristof Provost 
3236644b7b5aSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3237644b7b5aSKristof Provost 		return (ENXIO);
3238644b7b5aSKristof Provost 
3239644b7b5aSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3240644b7b5aSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &get_addrs_parser, nr))
3241644b7b5aSKristof Provost 			continue;
3242644b7b5aSKristof Provost 	}
3243644b7b5aSKristof Provost 
3244644b7b5aSKristof Provost 	return (e.error);
3245644b7b5aSKristof Provost }
32469ae91f59SKristof Provost 
32479ae91f59SKristof Provost #define _OUT(_field)	offsetof(struct pf_pooladdr, _field)
32489ae91f59SKristof Provost static const struct snl_attr_parser ap_pool_addr[] = {
32499ae91f59SKristof Provost 	{ .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
32509ae91f59SKristof Provost 	{ .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg_u32 = IFNAMSIZ, .cb = snl_attr_copy_string },
32519ae91f59SKristof Provost };
32529ae91f59SKristof Provost SNL_DECLARE_ATTR_PARSER(pool_addr_parser, ap_pool_addr);
32539ae91f59SKristof Provost #undef _OUT
32549ae91f59SKristof Provost 
32559ae91f59SKristof Provost #define _OUT(_field)	offsetof(struct pfioc_pooladdr, _field)
32569ae91f59SKristof Provost static const struct snl_attr_parser ap_get_addr[] = {
32579ae91f59SKristof Provost 	{ .type = PF_AA_ACTION, .off = _OUT(action), .cb = snl_attr_get_uint32 },
32589ae91f59SKristof Provost 	{ .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
32599ae91f59SKristof Provost 	{ .type = PF_AA_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
32609ae91f59SKristof Provost 	{ .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = snl_attr_get_uint32 },
32619ae91f59SKristof Provost 	{ .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = snl_attr_get_uint8 },
32629ae91f59SKristof Provost 	{ .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = snl_attr_get_uint8 },
32639ae91f59SKristof Provost 	{ .type = PF_AA_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
32649ae91f59SKristof Provost 	{ .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg_u32 = MAXPATHLEN, .cb = snl_attr_copy_string },
32659ae91f59SKristof Provost 	{ .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = snl_attr_get_nested },
32669ae91f59SKristof Provost };
32677c882c69SKristof Provost SNL_DECLARE_PARSER(get_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_get_addr);
32689ae91f59SKristof Provost #undef _OUT
32699ae91f59SKristof Provost 
32709ae91f59SKristof Provost int
pfctl_get_addr(struct pfctl_handle * h,uint32_t ticket,uint32_t r_num,uint8_t r_action,const char * anchor,uint32_t nr,struct pfioc_pooladdr * pa,int which)32719ae91f59SKristof Provost pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
3272aa69fdf1SKristof Provost     uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa,
3273aa69fdf1SKristof Provost     int which)
32749ae91f59SKristof Provost {
32759ae91f59SKristof Provost 	struct snl_writer nw;
32769ae91f59SKristof Provost 	struct snl_errmsg_data e = {};
32779ae91f59SKristof Provost 	struct nlmsghdr *hdr;
32789ae91f59SKristof Provost 	uint32_t seq_id;
32799ae91f59SKristof Provost 	int family_id;
32809ae91f59SKristof Provost 
32819ae91f59SKristof Provost 	family_id =snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
32829ae91f59SKristof Provost 	if (family_id == 0)
32839ae91f59SKristof Provost 		return (ENOTSUP);
32849ae91f59SKristof Provost 
32859ae91f59SKristof Provost 	snl_init_writer(&h->ss, &nw);
32869ae91f59SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_ADDR);
32879ae91f59SKristof Provost 
32889ae91f59SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_TICKET, ticket);
32899ae91f59SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num);
32909ae91f59SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action);
32919ae91f59SKristof Provost 	snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor);
32929ae91f59SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_NR, nr);
3293aa69fdf1SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
32949ae91f59SKristof Provost 
32959ae91f59SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
32969ae91f59SKristof Provost 		return (ENXIO);
32979ae91f59SKristof Provost 
32989ae91f59SKristof Provost 	seq_id = hdr->nlmsg_seq;
32999ae91f59SKristof Provost 
33009ae91f59SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
33019ae91f59SKristof Provost 		return (ENXIO);
33029ae91f59SKristof Provost 
33039ae91f59SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
33049ae91f59SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &get_addr_parser, pa))
33059ae91f59SKristof Provost 			continue;
33069ae91f59SKristof Provost 	}
33079ae91f59SKristof Provost 
330825e0f8f9SKristof Provost 	return (e.error);
33099ae91f59SKristof Provost }
331025e0f8f9SKristof Provost 
331125e0f8f9SKristof Provost #define _OUT(_field)	offsetof(struct pfioc_ruleset, _field)
331225e0f8f9SKristof Provost static const struct snl_attr_parser ap_ruleset[] = {
331325e0f8f9SKristof Provost 	{ .type = PF_RS_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
331448f5bf8bSKristof Provost 	{ .type = PF_RS_NAME, .off = _OUT(name), .arg = (void *)PF_ANCHOR_NAME_SIZE, .cb = snl_attr_copy_string },
331525e0f8f9SKristof Provost };
33167c882c69SKristof Provost SNL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, snl_f_p_empty, ap_ruleset);
331725e0f8f9SKristof Provost #undef _OUT
331825e0f8f9SKristof Provost 
331925e0f8f9SKristof Provost int
pfctl_get_rulesets(struct pfctl_handle * h,const char * path,uint32_t * nr)332025e0f8f9SKristof Provost pfctl_get_rulesets(struct pfctl_handle *h, const char *path, uint32_t *nr)
332125e0f8f9SKristof Provost {
332225e0f8f9SKristof Provost 	struct snl_writer nw;
332325e0f8f9SKristof Provost 	struct snl_errmsg_data e = {};
332425e0f8f9SKristof Provost 	struct nlmsghdr *hdr;
332525e0f8f9SKristof Provost 	struct pfioc_ruleset rs = {};
332625e0f8f9SKristof Provost 	uint32_t seq_id;
332725e0f8f9SKristof Provost 	int family_id;
332825e0f8f9SKristof Provost 
332925e0f8f9SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
333025e0f8f9SKristof Provost 	if (family_id == 0)
333125e0f8f9SKristof Provost 		return (ENOTSUP);
333225e0f8f9SKristof Provost 
333325e0f8f9SKristof Provost 	snl_init_writer(&h->ss, &nw);
333425e0f8f9SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_RULESETS);
333525e0f8f9SKristof Provost 
333625e0f8f9SKristof Provost 	snl_add_msg_attr_string(&nw, PF_RS_PATH, path);
333725e0f8f9SKristof Provost 
333825e0f8f9SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
333925e0f8f9SKristof Provost 		return (ENXIO);
334025e0f8f9SKristof Provost 
334125e0f8f9SKristof Provost 	seq_id = hdr->nlmsg_seq;
334225e0f8f9SKristof Provost 
334325e0f8f9SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
334425e0f8f9SKristof Provost 		return (ENXIO);
334525e0f8f9SKristof Provost 
334625e0f8f9SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
334725e0f8f9SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &ruleset_parser, &rs))
334825e0f8f9SKristof Provost 			continue;
334925e0f8f9SKristof Provost 	}
335025e0f8f9SKristof Provost 
335125e0f8f9SKristof Provost 	*nr = rs.nr;
335225e0f8f9SKristof Provost 
335325e0f8f9SKristof Provost 	return (e.error);
335425e0f8f9SKristof Provost }
335525e0f8f9SKristof Provost 
335648f5bf8bSKristof Provost int
pfctl_get_ruleset(struct pfctl_handle * h,const char * path,uint32_t nr,struct pfioc_ruleset * rs)335748f5bf8bSKristof Provost pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct pfioc_ruleset *rs)
335848f5bf8bSKristof Provost {
335948f5bf8bSKristof Provost 	struct snl_writer nw;
336048f5bf8bSKristof Provost 	struct snl_errmsg_data e = {};
336148f5bf8bSKristof Provost 	struct nlmsghdr *hdr;
336248f5bf8bSKristof Provost 	uint32_t seq_id;
336348f5bf8bSKristof Provost 	int family_id;
336448f5bf8bSKristof Provost 
336548f5bf8bSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
336648f5bf8bSKristof Provost 	if (family_id == 0)
336748f5bf8bSKristof Provost 		return (ENOTSUP);
336848f5bf8bSKristof Provost 
336948f5bf8bSKristof Provost 	snl_init_writer(&h->ss, &nw);
337048f5bf8bSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_RULESET);
337148f5bf8bSKristof Provost 
337248f5bf8bSKristof Provost 	snl_add_msg_attr_string(&nw, PF_RS_PATH, path);
337348f5bf8bSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_RS_NR, nr);
337448f5bf8bSKristof Provost 
337548f5bf8bSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
337648f5bf8bSKristof Provost 		return (ENXIO);
337748f5bf8bSKristof Provost 
337848f5bf8bSKristof Provost 	seq_id = hdr->nlmsg_seq;
337948f5bf8bSKristof Provost 
338048f5bf8bSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
338148f5bf8bSKristof Provost 		return (ENXIO);
338248f5bf8bSKristof Provost 
338348f5bf8bSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
338448f5bf8bSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &ruleset_parser, rs))
338548f5bf8bSKristof Provost 			continue;
338648f5bf8bSKristof Provost 	}
338748f5bf8bSKristof Provost 
3388a943a96aSJose Luis Duran 	rs->nr = nr;
3389a943a96aSJose Luis Duran 	strlcpy(rs->path, path, sizeof(rs->path));
3390a943a96aSJose Luis Duran 
339148f5bf8bSKristof Provost 	return (e.error);
339248f5bf8bSKristof Provost }
339348f5bf8bSKristof Provost 
33949c125336SKristof Provost #define	_OUT(_field)	offsetof(struct pfctl_src_node, _field)
33959c125336SKristof Provost static struct snl_attr_parser ap_srcnode[] = {
33969c125336SKristof Provost 	{ .type = PF_SN_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
33979c125336SKristof Provost 	{ .type = PF_SN_RADDR, .off = _OUT(raddr), .cb = snl_attr_get_in6_addr },
33989c125336SKristof Provost 	{ .type = PF_SN_RULE_NR, .off = _OUT(rule), .cb = snl_attr_get_uint32 },
33999c125336SKristof Provost 	{ .type = PF_SN_BYTES_IN, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 },
34009c125336SKristof Provost 	{ .type = PF_SN_BYTES_OUT, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 },
34019c125336SKristof Provost 	{ .type = PF_SN_PACKETS_IN, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 },
34029c125336SKristof Provost 	{ .type = PF_SN_PACKETS_OUT, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 },
34039c125336SKristof Provost 	{ .type = PF_SN_STATES, .off = _OUT(states), .cb = snl_attr_get_uint32 },
34049c125336SKristof Provost 	{ .type = PF_SN_CONNECTIONS, .off = _OUT(conn), .cb = snl_attr_get_uint32 },
34059c125336SKristof Provost 	{ .type = PF_SN_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
34069c125336SKristof Provost 	{ .type = PF_SN_RULE_TYPE, .off = _OUT(ruletype), .cb = snl_attr_get_uint8 },
34079c125336SKristof Provost 	{ .type = PF_SN_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint64 },
34089c125336SKristof Provost 	{ .type = PF_SN_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint64 },
34099c125336SKristof Provost 	{ .type = PF_SN_CONNECTION_RATE, .off = _OUT(conn_rate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
3410d2761422SKajetan Staszkiewicz 	{ .type = PF_SN_RAF, .off = _OUT(raf), .cb = snl_attr_get_uint8 },
341107e070efSKajetan Staszkiewicz 	{ .type = PF_SN_NODE_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
34129c125336SKristof Provost };
34139c125336SKristof Provost #undef _OUT
34147c882c69SKristof Provost SNL_DECLARE_PARSER(srcnode_parser, struct genlmsghdr, snl_f_p_empty, ap_srcnode);
34159c125336SKristof Provost 
34169c125336SKristof Provost int
pfctl_get_srcnodes(struct pfctl_handle * h,pfctl_get_srcnode_fn fn,void * arg)34179c125336SKristof Provost pfctl_get_srcnodes(struct pfctl_handle *h, pfctl_get_srcnode_fn fn, void *arg)
34189c125336SKristof Provost {
34199c125336SKristof Provost 	struct snl_writer nw;
34209c125336SKristof Provost 	struct pfctl_src_node sn;
34219c125336SKristof Provost 	struct snl_errmsg_data e = {};
34229c125336SKristof Provost 	struct nlmsghdr *hdr;
34239c125336SKristof Provost 	uint32_t seq_id;
34249c125336SKristof Provost 	int family_id;
34259c125336SKristof Provost 	int ret;
34269c125336SKristof Provost 
34279c125336SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
34289c125336SKristof Provost 	if (family_id == 0)
34299c125336SKristof Provost 		return (ENOTSUP);
34309c125336SKristof Provost 
34319c125336SKristof Provost 	snl_init_writer(&h->ss, &nw);
34329c125336SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_SRCNODES);
34339c125336SKristof Provost 
34349c125336SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
34359c125336SKristof Provost 		return (ENXIO);
34369c125336SKristof Provost 
34379c125336SKristof Provost 	seq_id = hdr->nlmsg_seq;
34389c125336SKristof Provost 
34399c125336SKristof Provost 	if (!snl_send_message(&h->ss, hdr))
34409c125336SKristof Provost 		return (ENXIO);
34419c125336SKristof Provost 
34429c125336SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3443581e064dSKristof Provost 		bzero(&sn, sizeof(sn));
34449c125336SKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &srcnode_parser, &sn))
34459c125336SKristof Provost 			continue;
34469c125336SKristof Provost 
34479c125336SKristof Provost 		ret = fn(&sn, arg);
34489c125336SKristof Provost 		if (ret != 0)
34499c125336SKristof Provost 			return (ret);
34509c125336SKristof Provost 	}
34519c125336SKristof Provost 
34529c125336SKristof Provost 	return (e.error);
34539c125336SKristof Provost }
3454441d4894SKristof Provost 
3455441d4894SKristof Provost static struct snl_attr_parser ap_ndel[] = {
3456441d4894SKristof Provost 	{ .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint32 },
3457441d4894SKristof Provost };
34587c882c69SKristof Provost SNL_DECLARE_PARSER(ndel_parser, struct genlmsghdr, snl_f_p_empty, ap_ndel);
3459441d4894SKristof Provost 
3460441d4894SKristof Provost int
pfctl_clear_tables(struct pfctl_handle * h,struct pfr_table * filter,int * ndel,int flags)3461441d4894SKristof Provost pfctl_clear_tables(struct pfctl_handle *h, struct pfr_table *filter,
3462441d4894SKristof Provost     int *ndel, int flags)
3463441d4894SKristof Provost {
3464441d4894SKristof Provost 	struct snl_writer nw;
3465441d4894SKristof Provost 	struct snl_errmsg_data e = {};
3466441d4894SKristof Provost 	struct nlmsghdr *hdr;
3467441d4894SKristof Provost 	uint32_t seq_id;
3468441d4894SKristof Provost 	int family_id;
3469441d4894SKristof Provost 
3470441d4894SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3471441d4894SKristof Provost 	if (family_id == 0)
3472441d4894SKristof Provost 		return (ENOTSUP);
3473441d4894SKristof Provost 
3474441d4894SKristof Provost 	snl_init_writer(&h->ss, &nw);
3475441d4894SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLEAR_TABLES);
3476441d4894SKristof Provost 
3477441d4894SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3478441d4894SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3479441d4894SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3480441d4894SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3481441d4894SKristof Provost 
3482441d4894SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3483441d4894SKristof Provost 		return (ENXIO);
3484441d4894SKristof Provost 
3485441d4894SKristof Provost 	seq_id = hdr->nlmsg_seq;
3486441d4894SKristof Provost 
3487441d4894SKristof Provost 	if (!snl_send_message(&h->ss, hdr))
3488441d4894SKristof Provost 		return (ENXIO);
3489441d4894SKristof Provost 
3490441d4894SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3491441d4894SKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &ndel_parser, ndel))
3492441d4894SKristof Provost 			continue;
3493441d4894SKristof Provost 	}
3494441d4894SKristof Provost 
3495441d4894SKristof Provost 	return (e.error);
3496441d4894SKristof Provost }
349784a80eaeSKristof Provost 
349884a80eaeSKristof Provost static struct snl_attr_parser ap_nadd[] = {
349984a80eaeSKristof Provost 	{ .type = PF_T_NBR_ADDED, .off = 0, .cb = snl_attr_get_uint32 },
350084a80eaeSKristof Provost };
350184a80eaeSKristof Provost SNL_DECLARE_PARSER(nadd_parser, struct genlmsghdr, snl_f_p_empty, ap_nadd);
350284a80eaeSKristof Provost int
pfctl_add_table(struct pfctl_handle * h,struct pfr_table * table,int * nadd,int flags)350384a80eaeSKristof Provost pfctl_add_table(struct pfctl_handle *h, struct pfr_table *table,
350484a80eaeSKristof Provost     int *nadd, int flags)
350584a80eaeSKristof Provost {
350684a80eaeSKristof Provost 	struct snl_writer nw;
350784a80eaeSKristof Provost 	struct snl_errmsg_data e = {};
350884a80eaeSKristof Provost 	struct nlmsghdr *hdr;
350984a80eaeSKristof Provost 	uint32_t seq_id;
351084a80eaeSKristof Provost 	int family_id;
351184a80eaeSKristof Provost 
351284a80eaeSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
351384a80eaeSKristof Provost 	if (family_id == 0)
351484a80eaeSKristof Provost 		return (ENOTSUP);
351584a80eaeSKristof Provost 
351684a80eaeSKristof Provost 	snl_init_writer(&h->ss, &nw);
351784a80eaeSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_ADD_TABLE);
351884a80eaeSKristof Provost 
351984a80eaeSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, table->pfrt_anchor);
352084a80eaeSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, table->pfrt_name);
352184a80eaeSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, table->pfrt_flags);
352284a80eaeSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
352384a80eaeSKristof Provost 
352484a80eaeSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
352584a80eaeSKristof Provost 		return (ENXIO);
352684a80eaeSKristof Provost 
352784a80eaeSKristof Provost 	seq_id = hdr->nlmsg_seq;
352884a80eaeSKristof Provost 
352984a80eaeSKristof Provost 	if (!snl_send_message(&h->ss, hdr))
353084a80eaeSKristof Provost 		return (ENXIO);
353184a80eaeSKristof Provost 
353284a80eaeSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
353384a80eaeSKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &nadd_parser, nadd))
353484a80eaeSKristof Provost 			continue;
353584a80eaeSKristof Provost 	}
353684a80eaeSKristof Provost 
353784a80eaeSKristof Provost 	return (e.error);
353884a80eaeSKristof Provost }
353984a80eaeSKristof Provost 
35400d2058abSKristof Provost int
pfctl_del_table(struct pfctl_handle * h,struct pfr_table * table,int * ndel,int flags)35410d2058abSKristof Provost pfctl_del_table(struct pfctl_handle *h, struct pfr_table *table,
35420d2058abSKristof Provost     int *ndel, int flags)
35430d2058abSKristof Provost {
35440d2058abSKristof Provost 	struct snl_writer nw;
35450d2058abSKristof Provost 	struct snl_errmsg_data e = {};
35460d2058abSKristof Provost 	struct nlmsghdr *hdr;
35470d2058abSKristof Provost 	uint32_t seq_id;
35480d2058abSKristof Provost 	int family_id;
35490d2058abSKristof Provost 
35500d2058abSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
35510d2058abSKristof Provost 	if (family_id == 0)
35520d2058abSKristof Provost 		return (ENOTSUP);
35530d2058abSKristof Provost 
35540d2058abSKristof Provost 	snl_init_writer(&h->ss, &nw);
35550d2058abSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_DEL_TABLE);
35560d2058abSKristof Provost 
35570d2058abSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, table->pfrt_anchor);
35580d2058abSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, table->pfrt_name);
35590d2058abSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, table->pfrt_flags);
35600d2058abSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
35610d2058abSKristof Provost 
35620d2058abSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
35630d2058abSKristof Provost 		return (ENXIO);
35640d2058abSKristof Provost 
35650d2058abSKristof Provost 	seq_id = hdr->nlmsg_seq;
35660d2058abSKristof Provost 
35670d2058abSKristof Provost 	if (!snl_send_message(&h->ss, hdr))
35680d2058abSKristof Provost 		return (ENXIO);
35690d2058abSKristof Provost 
35700d2058abSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
35710d2058abSKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &ndel_parser, ndel))
35720d2058abSKristof Provost 			continue;
35730d2058abSKristof Provost 	}
35740d2058abSKristof Provost 
35750d2058abSKristof Provost 	return (e.error);
35760d2058abSKristof Provost }
35770d2058abSKristof Provost 
35789e8d2962SKristof Provost static bool
snl_attr_get_uint64_into_int_array(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)35799e8d2962SKristof Provost snl_attr_get_uint64_into_int_array(struct snl_state *ss, struct nlattr *nla,
35809e8d2962SKristof Provost     const void *arg, void *target)
35819e8d2962SKristof Provost {
35829e8d2962SKristof Provost 	uint64_t *u64target;
35839e8d2962SKristof Provost 	struct snl_uint64_array a = {
35849e8d2962SKristof Provost 		.count = 0,
35859e8d2962SKristof Provost 		.max = (size_t)arg,
35869e8d2962SKristof Provost 	};
35879e8d2962SKristof Provost 	bool error;
35889e8d2962SKristof Provost 
35899e8d2962SKristof Provost 	u64target = malloc(a.max * sizeof(uint64_t));
35909e8d2962SKristof Provost 	a.array = u64target;
35919e8d2962SKristof Provost 
35929e8d2962SKristof Provost 	error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &array_parser, &a);
35939e8d2962SKristof Provost 	if (! error)
35949e8d2962SKristof Provost 		return (error);
35959e8d2962SKristof Provost 
35969e8d2962SKristof Provost 	for (size_t i = 0; i < a.count; i++)
35979e8d2962SKristof Provost 		((int *)target)[i] = (int)u64target[i];
35989e8d2962SKristof Provost 
35999e8d2962SKristof Provost 	free(u64target);
36009e8d2962SKristof Provost 
36019e8d2962SKristof Provost 	return (true);
36029e8d2962SKristof Provost }
36039e8d2962SKristof Provost 
36049e8d2962SKristof Provost #define	_OUT(_field)	offsetof(struct pfr_table, _field)
36059e8d2962SKristof Provost static const struct snl_attr_parser ap_table[] = {
36069e8d2962SKristof Provost 	{ .type = PF_T_ANCHOR, .off = _OUT(pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = snl_attr_copy_string },
36079e8d2962SKristof Provost 	{ .type = PF_T_NAME, .off = _OUT(pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb =snl_attr_copy_string },
36089e8d2962SKristof Provost 	{ .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrt_flags), .cb = snl_attr_get_uint32 },
36099e8d2962SKristof Provost };
36109e8d2962SKristof Provost #undef	_OUT
36119e8d2962SKristof Provost SNL_DECLARE_ATTR_PARSER(table_parser, ap_table);
36129e8d2962SKristof Provost #define	_OUT(_field)	offsetof(struct pfr_tstats, _field)
36139e8d2962SKristof Provost static struct  snl_attr_parser ap_tstats[] = {
36149e8d2962SKristof Provost 	{ .type = PF_TS_TABLE, .off = _OUT(pfrts_t), .arg = &table_parser, .cb = snl_attr_get_nested },
36159e8d2962SKristof Provost 	{ .type = PF_TS_PACKETS, .off = _OUT(pfrts_packets), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array},
36169e8d2962SKristof Provost 	{ .type = PF_TS_BYTES, .off = _OUT(pfrts_bytes), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array },
36179e8d2962SKristof Provost 	{ .type = PF_TS_MATCH, .off = _OUT(pfrts_match), .cb = snl_attr_get_uint64 },
36189e8d2962SKristof Provost 	{. type = PF_TS_NOMATCH, .off = _OUT(pfrts_nomatch), .cb = snl_attr_get_uint64 },
36199e8d2962SKristof Provost 	{ .type = PF_TS_TZERO, .off = _OUT(pfrts_tzero), .cb = snl_attr_get_uint64 },
3620ad7f49f9SKristof Provost 	{ .type = PF_TS_CNT, .off = _OUT(pfrts_cnt), .cb = snl_attr_get_uint64 },
3621ad7f49f9SKristof Provost 	{ .type = PF_TS_REFCNT, .off = _OUT(pfrts_refcnt), . arg = (void *)PFR_REFCNT_MAX, .cb = snl_attr_get_uint64_into_int_array },
36229e8d2962SKristof Provost };
36239e8d2962SKristof Provost #undef _OUT
36249e8d2962SKristof Provost SNL_DECLARE_PARSER(tstats_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats);
36259e8d2962SKristof Provost 
36269e8d2962SKristof Provost int
pfctl_get_tstats(struct pfctl_handle * h,const struct pfr_table * filter,pfctl_get_tstats_fn fn,void * arg)36279e8d2962SKristof Provost pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
36289e8d2962SKristof Provost     pfctl_get_tstats_fn fn, void *arg)
36299e8d2962SKristof Provost {
36309e8d2962SKristof Provost 	struct snl_writer nw;
36319e8d2962SKristof Provost 	struct snl_errmsg_data e = {};
36329e8d2962SKristof Provost 	struct nlmsghdr *hdr;
36339e8d2962SKristof Provost 	uint32_t seq_id;
36349e8d2962SKristof Provost 	int family_id;
36359e8d2962SKristof Provost 	int ret;
36369e8d2962SKristof Provost 
36379e8d2962SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
36389e8d2962SKristof Provost 	if (family_id == 0)
36399e8d2962SKristof Provost 		return (ENOTSUP);
36409e8d2962SKristof Provost 
36419e8d2962SKristof Provost 	snl_init_writer(&h->ss, &nw);
36429e8d2962SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_TSTATS);
36439e8d2962SKristof Provost 
36449e8d2962SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
36459e8d2962SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
36469e8d2962SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
36479e8d2962SKristof Provost 
36489e8d2962SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
36499e8d2962SKristof Provost 		return (ENXIO);
36509e8d2962SKristof Provost 
36519e8d2962SKristof Provost 	seq_id = hdr->nlmsg_seq;
36529e8d2962SKristof Provost 
36539e8d2962SKristof Provost 	if (!snl_send_message(&h->ss, hdr))
36549e8d2962SKristof Provost 		return (ENXIO);
36559e8d2962SKristof Provost 
36569e8d2962SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
36579e8d2962SKristof Provost 		struct pfr_tstats tstats = {};
36589e8d2962SKristof Provost 
36599e8d2962SKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_parser, &tstats))
36609e8d2962SKristof Provost 			continue;
36619e8d2962SKristof Provost 
36629e8d2962SKristof Provost 		ret = fn(&tstats, arg);
36639e8d2962SKristof Provost 		if (ret != 0)
36649e8d2962SKristof Provost 			break;
36659e8d2962SKristof Provost 	}
36669e8d2962SKristof Provost 
36679e8d2962SKristof Provost 	return (e.error);
36689e8d2962SKristof Provost }
36699e8d2962SKristof Provost 
3670b3a68a2eSKristof Provost static struct snl_attr_parser ap_tstats_clr[] = {
3671b3a68a2eSKristof Provost 	{ .type = PF_TS_NZERO, .off = 0, .cb = snl_attr_get_uint64 },
3672b3a68a2eSKristof Provost };
3673b3a68a2eSKristof Provost SNL_DECLARE_PARSER(tstats_clr_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats_clr);
3674b3a68a2eSKristof Provost 
3675b3a68a2eSKristof Provost int
pfctl_clear_tstats(struct pfctl_handle * h,const struct pfr_table * filter,int * nzero,int flags)3676b3a68a2eSKristof Provost pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
3677b3a68a2eSKristof Provost     int *nzero, int flags)
3678b3a68a2eSKristof Provost {
3679b3a68a2eSKristof Provost 	struct snl_writer nw;
3680b3a68a2eSKristof Provost 	struct snl_errmsg_data e = {};
3681b3a68a2eSKristof Provost 	struct nlmsghdr *hdr;
3682b3a68a2eSKristof Provost 	uint64_t zero;
3683b3a68a2eSKristof Provost 	uint32_t seq_id;
3684b3a68a2eSKristof Provost 	int family_id;
3685b3a68a2eSKristof Provost 
3686b3a68a2eSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3687b3a68a2eSKristof Provost 	if (family_id == 0)
3688b3a68a2eSKristof Provost 		return (ENOTSUP);
3689b3a68a2eSKristof Provost 
3690b3a68a2eSKristof Provost 	snl_init_writer(&h->ss, &nw);
3691b3a68a2eSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_TSTATS);
3692b3a68a2eSKristof Provost 
3693b3a68a2eSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3694b3a68a2eSKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3695b3a68a2eSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3696b3a68a2eSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3697b3a68a2eSKristof Provost 
3698b3a68a2eSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3699b3a68a2eSKristof Provost 		return (ENXIO);
3700b3a68a2eSKristof Provost 
3701b3a68a2eSKristof Provost 	seq_id = hdr->nlmsg_seq;
3702b3a68a2eSKristof Provost 
3703b3a68a2eSKristof Provost 	if (!snl_send_message(&h->ss, hdr))
3704b3a68a2eSKristof Provost 		return (ENXIO);
3705b3a68a2eSKristof Provost 
3706b3a68a2eSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3707b3a68a2eSKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &zero))
3708b3a68a2eSKristof Provost 			continue;
3709b3a68a2eSKristof Provost 		if (nzero)
3710b3a68a2eSKristof Provost 			*nzero = (uint32_t)zero;
3711b3a68a2eSKristof Provost 	}
3712b3a68a2eSKristof Provost 
3713b3a68a2eSKristof Provost 	return (e.error);
3714b3a68a2eSKristof Provost }
3715b543f426SKristof Provost 
3716799e21d5SKristof Provost static struct snl_attr_parser ap_clr_addrs[] = {
3717799e21d5SKristof Provost 	{ .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint64 },
3718799e21d5SKristof Provost };
3719799e21d5SKristof Provost SNL_DECLARE_PARSER(clr_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_clr_addrs);
3720799e21d5SKristof Provost 
3721b543f426SKristof Provost int
pfctl_clear_addrs(struct pfctl_handle * h,const struct pfr_table * filter,int * ndel,int flags)3722b543f426SKristof Provost pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
3723b543f426SKristof Provost     int *ndel, int flags)
3724b543f426SKristof Provost {
3725b543f426SKristof Provost 	struct snl_writer nw;
3726b543f426SKristof Provost 	struct snl_errmsg_data e = {};
3727b543f426SKristof Provost 	struct nlmsghdr *hdr;
3728b543f426SKristof Provost 	uint64_t del;
3729b543f426SKristof Provost 	uint32_t seq_id;
3730b543f426SKristof Provost 	int family_id;
3731b543f426SKristof Provost 
3732b543f426SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3733b543f426SKristof Provost 	if (family_id == 0)
3734b543f426SKristof Provost 		return (ENOTSUP);
3735b543f426SKristof Provost 
3736b543f426SKristof Provost 	snl_init_writer(&h->ss, &nw);
3737b543f426SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_ADDRS);
3738b543f426SKristof Provost 
3739b543f426SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3740b543f426SKristof Provost 	snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3741b543f426SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3742b543f426SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3743b543f426SKristof Provost 
3744b543f426SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3745b543f426SKristof Provost 		return (ENXIO);
3746b543f426SKristof Provost 
3747b543f426SKristof Provost 	seq_id = hdr->nlmsg_seq;
3748b543f426SKristof Provost 
3749b543f426SKristof Provost 	if (!snl_send_message(&h->ss, hdr))
3750b543f426SKristof Provost 		return (ENXIO);
3751b543f426SKristof Provost 
3752b543f426SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3753799e21d5SKristof Provost 		if (!snl_parse_nlmsg(&h->ss, hdr, &clr_addrs_parser, &del))
3754b543f426SKristof Provost 			continue;
3755b543f426SKristof Provost 		if (ndel)
3756b543f426SKristof Provost 			*ndel = (uint32_t)del;
3757b543f426SKristof Provost 	}
3758b543f426SKristof Provost 
3759b543f426SKristof Provost 	return (e.error);
3760b543f426SKristof Provost }
376108f54dfcSKristof Provost 
376208f54dfcSKristof Provost struct nl_astats {
376308f54dfcSKristof Provost 	struct pfr_astats *a;
376408f54dfcSKristof Provost 	size_t max;
376508f54dfcSKristof Provost 	size_t count;
376696c7e70cSKristof Provost 	uint32_t total_count;
376796c7e70cSKristof Provost 	uint32_t zeroed;
376808f54dfcSKristof Provost };
376908f54dfcSKristof Provost 
377008f54dfcSKristof Provost #define _OUT(_field)	offsetof(struct pfr_astats, _field)
377108f54dfcSKristof Provost static const struct snl_attr_parser ap_pfr_astats[] = {
377208f54dfcSKristof Provost 	{ .type = PF_AS_ADDR , .off = _OUT(pfras_a), .arg = &pfr_addr_parser, .cb = snl_attr_get_nested },
377308f54dfcSKristof Provost 	{ .type = PF_AS_PACKETS, .off = _OUT(pfras_packets), .arg = (void *)(PFR_DIR_MAX * PFR_OP_ADDR_MAX), .cb = snl_attr_get_uint64_array },
377408f54dfcSKristof Provost 	{ .type = PF_AS_BYTES, .off = _OUT(pfras_bytes), .arg = (void *)(PFR_DIR_MAX * PFR_OP_ADDR_MAX), .cb = snl_attr_get_uint64_array },
377508f54dfcSKristof Provost 	{ .type = PF_AS_TZERO, .off = _OUT(pfras_tzero), .cb = snl_attr_get_time_t },
377608f54dfcSKristof Provost };
377708f54dfcSKristof Provost #undef _OUT
377808f54dfcSKristof Provost SNL_DECLARE_ATTR_PARSER(pfr_astats_parser, ap_pfr_astats);
377908f54dfcSKristof Provost 
378008f54dfcSKristof Provost static bool
snl_attr_get_pfr_astats(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)378108f54dfcSKristof Provost snl_attr_get_pfr_astats(struct snl_state *ss, struct nlattr *nla,
378208f54dfcSKristof Provost     const void *arg __unused, void *target)
378308f54dfcSKristof Provost {
378408f54dfcSKristof Provost 	struct nl_astats *a = (struct nl_astats *)target;
378508f54dfcSKristof Provost 	bool ret;
378608f54dfcSKristof Provost 
378708f54dfcSKristof Provost 	if (a->count >= a->max)
378808f54dfcSKristof Provost 		return (false);
378908f54dfcSKristof Provost 
379008f54dfcSKristof Provost 	ret = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla),
379108f54dfcSKristof Provost 	    &pfr_astats_parser, &a->a[a->count]);
379208f54dfcSKristof Provost 	if (ret)
379308f54dfcSKristof Provost 		a->count++;
379408f54dfcSKristof Provost 
379508f54dfcSKristof Provost 	return (ret);
379608f54dfcSKristof Provost }
379708f54dfcSKristof Provost 
379808f54dfcSKristof Provost #define _OUT(_field)	offsetof(struct nl_astats, _field)
379908f54dfcSKristof Provost static struct snl_attr_parser ap_table_get_astats[] = {
380008f54dfcSKristof Provost 	{ .type = PF_TAS_ASTATS, .off = 0, .cb = snl_attr_get_pfr_astats },
380108f54dfcSKristof Provost 	{ .type = PF_TAS_ASTATS_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
380296c7e70cSKristof Provost 	{ .type = PF_TAS_ASTATS_ZEROED, .off = _OUT(zeroed), .cb = snl_attr_get_uint32 },
380308f54dfcSKristof Provost };
380408f54dfcSKristof Provost #undef _OUT
380508f54dfcSKristof Provost SNL_DECLARE_PARSER(table_astats_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_astats);
380608f54dfcSKristof Provost 
38074aa79010SKristof Provost int
pfctl_get_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_astats * as,int * size,int flags)38084aa79010SKristof Provost pfctl_get_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
380908f54dfcSKristof Provost     struct pfr_astats *as, int *size, int flags)
38104aa79010SKristof Provost {
381108f54dfcSKristof Provost 	struct snl_writer nw;
381208f54dfcSKristof Provost 	struct snl_errmsg_data e = {};
381308f54dfcSKristof Provost 	struct nlmsghdr *hdr;
381408f54dfcSKristof Provost 	struct nl_astats out = { 0 };
381508f54dfcSKristof Provost 	uint32_t seq_id;
381608f54dfcSKristof Provost 	int family_id;
3817b543f426SKristof Provost 
38184aa79010SKristof Provost 	if (tbl == NULL || size == NULL || *size < 0 ||
381908f54dfcSKristof Provost 	    (*size && as == NULL)) {
38204aa79010SKristof Provost 		errno = EINVAL;
38214aa79010SKristof Provost 		return (-1);
38224aa79010SKristof Provost 	}
382308f54dfcSKristof Provost 
382408f54dfcSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
382508f54dfcSKristof Provost 	if (family_id == 0)
382608f54dfcSKristof Provost 		return (ENOTSUP);
382708f54dfcSKristof Provost 
382808f54dfcSKristof Provost 	snl_init_writer(&h->ss, &nw);
382908f54dfcSKristof Provost 
383008f54dfcSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_GET_ASTATS);
383108f54dfcSKristof Provost 
383208f54dfcSKristof Provost 	snl_add_msg_attr_table(&nw, PF_TAS_TABLE, tbl);
383308f54dfcSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TAS_FLAGS, flags);
383408f54dfcSKristof Provost 
383508f54dfcSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
383608f54dfcSKristof Provost 		return (ENXIO);
383708f54dfcSKristof Provost 	seq_id = hdr->nlmsg_seq;
383808f54dfcSKristof Provost 
383908f54dfcSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
384008f54dfcSKristof Provost 		return (ENXIO);
384108f54dfcSKristof Provost 
384208f54dfcSKristof Provost 	out.a = as;
384308f54dfcSKristof Provost 	out.max = *size;
384408f54dfcSKristof Provost 
384508f54dfcSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
384608f54dfcSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &out))
384708f54dfcSKristof Provost 			continue;
38484aa79010SKristof Provost 	}
384908f54dfcSKristof Provost 
385008f54dfcSKristof Provost 	*size = out.total_count;
385108f54dfcSKristof Provost 
38524aa79010SKristof Provost 	return (0);
38534aa79010SKristof Provost }
3854c2e7a523SKristof Provost 
385596c7e70cSKristof Provost static int
_pfctl_clr_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nzero,int flags)385696c7e70cSKristof Provost _pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
385796c7e70cSKristof Provost     struct pfr_addr *addrs, int size, int *nzero, int flags)
3858c2e7a523SKristof Provost {
385996c7e70cSKristof Provost 	struct snl_writer nw;
386096c7e70cSKristof Provost 	struct snl_errmsg_data e = {};
386196c7e70cSKristof Provost 	struct nlmsghdr *hdr;
386296c7e70cSKristof Provost 	uint32_t seq_id;
386396c7e70cSKristof Provost 	struct nl_astats attrs;
386496c7e70cSKristof Provost 	int family_id;
3865c2e7a523SKristof Provost 
386696c7e70cSKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
386796c7e70cSKristof Provost 	if (family_id == 0)
386896c7e70cSKristof Provost 		return (ENOTSUP);
386996c7e70cSKristof Provost 
387096c7e70cSKristof Provost 	snl_init_writer(&h->ss, &nw);
387196c7e70cSKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_CLEAR_ASTATS);
387296c7e70cSKristof Provost 
387396c7e70cSKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
387496c7e70cSKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
387596c7e70cSKristof Provost 	for (int i = 0; i < size; i++)
387696c7e70cSKristof Provost 		snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
387796c7e70cSKristof Provost 
387896c7e70cSKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
387996c7e70cSKristof Provost 		return (ENXIO);
388096c7e70cSKristof Provost 	seq_id = hdr->nlmsg_seq;
388196c7e70cSKristof Provost 
388296c7e70cSKristof Provost 	if (! snl_send_message(&h->ss, hdr))
388396c7e70cSKristof Provost 		return (ENXIO);
388496c7e70cSKristof Provost 
388596c7e70cSKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
388696c7e70cSKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &attrs))
388796c7e70cSKristof Provost 			continue;
3888c2e7a523SKristof Provost 	}
3889c2e7a523SKristof Provost 
3890c2e7a523SKristof Provost 	if (nzero)
389196c7e70cSKristof Provost 		*nzero = attrs.zeroed;
389296c7e70cSKristof Provost 
389396c7e70cSKristof Provost 	return (e.error);
389496c7e70cSKristof Provost }
389596c7e70cSKristof Provost 
389696c7e70cSKristof Provost int
pfctl_clr_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nzero,int flags)389796c7e70cSKristof Provost pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
389896c7e70cSKristof Provost     struct pfr_addr *addrs, int size, int *nzero, int flags)
389996c7e70cSKristof Provost {
390096c7e70cSKristof Provost 	int ret;
390196c7e70cSKristof Provost 	int off = 0;
390296c7e70cSKristof Provost 	int partial_zeroed;
390396c7e70cSKristof Provost 	int chunk_size;
390496c7e70cSKristof Provost 
390596c7e70cSKristof Provost 	do {
390696c7e70cSKristof Provost 		chunk_size = MIN(size - off, 256);
390796c7e70cSKristof Provost 		ret = _pfctl_clr_astats(h, tbl, &addrs[off], chunk_size,
390896c7e70cSKristof Provost 		    &partial_zeroed, flags);
390996c7e70cSKristof Provost 		if (ret != 0)
391096c7e70cSKristof Provost 			break;
391196c7e70cSKristof Provost 		if (nzero)
391296c7e70cSKristof Provost 			*nzero += partial_zeroed;
391396c7e70cSKristof Provost 		off += chunk_size;
391496c7e70cSKristof Provost 	} while (off < size);
391596c7e70cSKristof Provost 
391696c7e70cSKristof Provost 	return (ret);
3917c2e7a523SKristof Provost }
3918c2e7a523SKristof Provost 
3919*281282e9SKristof Provost static int
_pfctl_test_addrs(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nmatch,int flags)3920*281282e9SKristof Provost _pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
3921*281282e9SKristof Provost     struct pfr_addr *addrs, int size, int *nmatch, int flags)
3922*281282e9SKristof Provost {
3923*281282e9SKristof Provost 	struct snl_writer nw;
3924*281282e9SKristof Provost 	struct snl_errmsg_data e = {};
3925*281282e9SKristof Provost 	struct nlmsghdr *hdr;
3926*281282e9SKristof Provost 	uint32_t seq_id;
3927*281282e9SKristof Provost 	struct nl_astats attrs;
3928*281282e9SKristof Provost 	int family_id;
3929*281282e9SKristof Provost 
3930*281282e9SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
3931*281282e9SKristof Provost 	if (family_id == 0)
3932*281282e9SKristof Provost 		return (ENOTSUP);
3933*281282e9SKristof Provost 
3934*281282e9SKristof Provost 	snl_init_writer(&h->ss, &nw);
3935*281282e9SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_TABLE_TEST_ADDRS);
3936*281282e9SKristof Provost 
3937*281282e9SKristof Provost 	snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
3938*281282e9SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
3939*281282e9SKristof Provost 	for (int i = 0; i < size; i++)
3940*281282e9SKristof Provost 		snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
3941*281282e9SKristof Provost 
3942*281282e9SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
3943*281282e9SKristof Provost 		return (ENXIO);
3944*281282e9SKristof Provost 	seq_id = hdr->nlmsg_seq;
3945*281282e9SKristof Provost 
3946*281282e9SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
3947*281282e9SKristof Provost 		return (ENXIO);
3948*281282e9SKristof Provost 
3949*281282e9SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3950*281282e9SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &attrs))
3951*281282e9SKristof Provost 			continue;
3952*281282e9SKristof Provost 	}
3953*281282e9SKristof Provost 
3954*281282e9SKristof Provost 	if (nmatch)
3955*281282e9SKristof Provost 		*nmatch = attrs.total_count;
3956*281282e9SKristof Provost 
3957*281282e9SKristof Provost 	return (e.error);
3958*281282e9SKristof Provost }
3959*281282e9SKristof Provost 
3960*281282e9SKristof Provost int
pfctl_test_addrs(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nmatch,int flags)3961*281282e9SKristof Provost pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
3962*281282e9SKristof Provost     struct pfr_addr *addrs, int size, int *nmatch, int flags)
3963*281282e9SKristof Provost {
3964*281282e9SKristof Provost 	int ret;
3965*281282e9SKristof Provost 	int off = 0;
3966*281282e9SKristof Provost 	int partial_match;
3967*281282e9SKristof Provost 	int chunk_size;
3968*281282e9SKristof Provost 
3969*281282e9SKristof Provost 	if (nmatch)
3970*281282e9SKristof Provost 		*nmatch = 0;
3971*281282e9SKristof Provost 
3972*281282e9SKristof Provost 	do {
3973*281282e9SKristof Provost 		chunk_size = MIN(size - off, 256);
3974*281282e9SKristof Provost 		ret = _pfctl_test_addrs(h, tbl, &addrs[off], chunk_size,
3975*281282e9SKristof Provost 		    &partial_match, flags);
3976*281282e9SKristof Provost 		if (ret != 0)
3977*281282e9SKristof Provost 			break;
3978*281282e9SKristof Provost 		if (nmatch)
3979*281282e9SKristof Provost 			*nmatch += partial_match;
3980*281282e9SKristof Provost 		off += chunk_size;
3981*281282e9SKristof Provost 	} while (off < size);
3982*281282e9SKristof Provost 
3983*281282e9SKristof Provost 	return (ret);
3984*281282e9SKristof Provost }
3985*281282e9SKristof Provost 
3986c72fb110SKristof Provost static void
snl_add_msg_attr_limit_rate(struct snl_writer * nw,uint32_t type,const struct pfctl_limit_rate * rate)3987c72fb110SKristof Provost snl_add_msg_attr_limit_rate(struct snl_writer *nw, uint32_t type,
3988c72fb110SKristof Provost     const struct pfctl_limit_rate *rate)
3989c72fb110SKristof Provost {
3990c72fb110SKristof Provost 	int off;
3991c72fb110SKristof Provost 
3992c72fb110SKristof Provost 	off = snl_add_msg_attr_nested(nw, type);
3993c72fb110SKristof Provost 
3994c72fb110SKristof Provost 	snl_add_msg_attr_u32(nw, PF_LR_LIMIT, rate->limit);
3995c72fb110SKristof Provost 	snl_add_msg_attr_u32(nw, PF_LR_SECONDS, rate->seconds);
3996c72fb110SKristof Provost 
3997c72fb110SKristof Provost 	snl_end_attr_nested(nw, off);
3998c72fb110SKristof Provost }
3999c72fb110SKristof Provost 
4000c72fb110SKristof Provost #define _OUT(_field)	offsetof(struct pfctl_limit_rate, _field)
4001c72fb110SKristof Provost static const struct snl_attr_parser ap_limit_rate[] = {
4002c72fb110SKristof Provost 	{ .type = PF_LR_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4003c72fb110SKristof Provost 	{ .type = PF_LR_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
4004c72fb110SKristof Provost };
4005c72fb110SKristof Provost SNL_DECLARE_ATTR_PARSER(limit_rate_parser, ap_limit_rate);
4006c72fb110SKristof Provost #undef _OUT
4007c72fb110SKristof Provost 
4008c72fb110SKristof Provost #define _OUT(_field)	offsetof(struct pfctl_state_lim, _field)
4009c72fb110SKristof Provost static struct snl_attr_parser ap_statelim[] = {
4010c72fb110SKristof Provost 	{ .type = PF_SL_NAME, .off = _OUT(name), .arg_u32 = PF_STATELIM_NAME_LEN, .cb = snl_attr_copy_string },
4011c72fb110SKristof Provost 	{ .type = PF_SL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
4012c72fb110SKristof Provost 	{ .type = PF_SL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4013c72fb110SKristof Provost 	{ .type = PF_SL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
4014c72fb110SKristof Provost 	{ .type = PF_SL_DESCR, .off = _OUT(description), .arg_u32 = PF_STATELIM_DESCR_LEN, .cb = snl_attr_copy_string },
4015c72fb110SKristof Provost 	{ .type = PF_SL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4016c72fb110SKristof Provost 	{ .type = PF_SL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4017c72fb110SKristof Provost 	{ .type = PF_SL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4018c72fb110SKristof Provost 	{ .type = PF_SL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4019c72fb110SKristof Provost };
4020c72fb110SKristof Provost #undef _OUT
4021c72fb110SKristof Provost SNL_DECLARE_PARSER(statelim_parser, struct genlmsghdr, snl_f_p_empty, ap_statelim);
4022c72fb110SKristof Provost 
4023c72fb110SKristof Provost int
pfctl_state_limiter_nget(struct pfctl_handle * h,struct pfctl_state_lim * lim)4024c72fb110SKristof Provost pfctl_state_limiter_nget(struct pfctl_handle *h, struct pfctl_state_lim *lim)
4025c72fb110SKristof Provost {
4026c72fb110SKristof Provost 	struct snl_writer nw;
4027c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4028c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4029c72fb110SKristof Provost 	uint32_t seq_id;
4030c72fb110SKristof Provost 	int family_id;
4031c72fb110SKristof Provost 
4032c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4033c72fb110SKristof Provost 	if (family_id == 0)
4034c72fb110SKristof Provost 		return (ENOTSUP);
4035c72fb110SKristof Provost 
4036c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4037c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_STATE_LIMITER_NGET);
4038c72fb110SKristof Provost 
4039c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
4040c72fb110SKristof Provost 
4041c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4042c72fb110SKristof Provost 		return (ENXIO);
4043c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4044c72fb110SKristof Provost 
4045c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4046c72fb110SKristof Provost 		return (ENXIO);
4047c72fb110SKristof Provost 
4048c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4049c72fb110SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, lim))
4050c72fb110SKristof Provost 			continue;
4051c72fb110SKristof Provost 	}
4052c72fb110SKristof Provost 
4053c72fb110SKristof Provost 	return (e.error);
4054c72fb110SKristof Provost }
4055c72fb110SKristof Provost 
4056c72fb110SKristof Provost int
pfctl_state_limiter_add(struct pfctl_handle * h,struct pfctl_state_lim * lim)4057c72fb110SKristof Provost pfctl_state_limiter_add(struct pfctl_handle *h, struct pfctl_state_lim *lim)
4058c72fb110SKristof Provost {
4059c72fb110SKristof Provost 	struct snl_writer nw;
4060c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4061c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4062c72fb110SKristof Provost 	uint32_t seq_id;
4063c72fb110SKristof Provost 	int family_id;
4064c72fb110SKristof Provost 
4065c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4066c72fb110SKristof Provost 	if (family_id == 0)
4067c72fb110SKristof Provost 		return (ENOTSUP);
4068c72fb110SKristof Provost 
4069c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4070c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_STATE_LIMITER_ADD);
4071c72fb110SKristof Provost 
4072c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
4073c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SL_TICKET, lim->ticket);
4074c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SL_NAME, lim->name);
4075c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SL_LIMIT, lim->limit);
4076c72fb110SKristof Provost 	snl_add_msg_attr_limit_rate(&nw, PF_SL_RATE, &lim->rate);
4077c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SL_DESCR, lim->description);
4078c72fb110SKristof Provost 
4079c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4080c72fb110SKristof Provost 		return (ENXIO);
4081c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4082c72fb110SKristof Provost 
4083c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4084c72fb110SKristof Provost 		return (ENXIO);
4085c72fb110SKristof Provost 
4086c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4087c72fb110SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, &lim))
4088c72fb110SKristof Provost 			continue;
4089c72fb110SKristof Provost 	}
4090c72fb110SKristof Provost 
4091c72fb110SKristof Provost 	return (e.error);
4092c72fb110SKristof Provost }
4093c72fb110SKristof Provost 
4094c72fb110SKristof Provost #define _OUT(_field)	offsetof(struct pfctl_source_lim, _field)
4095c72fb110SKristof Provost static struct snl_attr_parser ap_sourcelim[] = {
4096c72fb110SKristof Provost 	{ .type = PF_SCL_NAME, .off = _OUT(name), .arg_u32 = PF_SOURCELIM_NAME_LEN, .cb = snl_attr_copy_string },
4097c72fb110SKristof Provost 	{ .type = PF_SCL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
4098c72fb110SKristof Provost 	{ .type = PF_SCL_ENTRIES, .off = _OUT(entries), .cb = snl_attr_get_uint32 },
4099c72fb110SKristof Provost 	{ .type = PF_SCL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4100c72fb110SKristof Provost 	{ .type = PF_SCL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
4101c72fb110SKristof Provost 	{ .type = PF_SCL_OVERLOAD_TBL_NAME, .off = _OUT(overload_tblname), .arg_u32 = PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
4102c72fb110SKristof Provost 	{ .type = PF_SCL_OVERLOAD_HIGH_WM, .off = _OUT(overload_hwm), .cb = snl_attr_get_uint32 },
4103c72fb110SKristof Provost 	{ .type = PF_SCL_OVERLOAD_LOW_WM, .off = _OUT(overload_lwm), .cb = snl_attr_get_uint32 },
4104c72fb110SKristof Provost 	{ .type = PF_SCL_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
4105c72fb110SKristof Provost 	{ .type = PF_SCL_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
4106c72fb110SKristof Provost 	{ .type = PF_SCL_DESCR, .off = _OUT(description), .arg_u32 = PF_SOURCELIM_DESCR_LEN, .cb = snl_attr_copy_string },
4107c72fb110SKristof Provost 	{ .type = PF_SCL_NENTRIES, .off = _OUT(nentries), .cb = snl_attr_get_uint32 },
4108c72fb110SKristof Provost 	{ .type = PF_SCL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4109c72fb110SKristof Provost 	{ .type = PF_SCL_ADDR_ALLOCS, .off = _OUT(addrallocs), .cb = snl_attr_get_uint64 },
4110c72fb110SKristof Provost 	{ .type = PF_SCL_ADDR_NOMEM, .off = _OUT(addrnomem), .cb = snl_attr_get_uint64 },
4111c72fb110SKristof Provost 	{ .type = PF_SCL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4112c72fb110SKristof Provost 	{ .type = PF_SCL_ADDRLIMITED, .off = _OUT(addrlimited), .cb = snl_attr_get_uint64 },
4113c72fb110SKristof Provost 	{ .type = PF_SCL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4114c72fb110SKristof Provost 	{ .type = PF_SCL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4115c72fb110SKristof Provost };
4116c72fb110SKristof Provost #undef _OUT
4117c72fb110SKristof Provost SNL_DECLARE_PARSER(sourcelim_parser, struct genlmsghdr, snl_f_p_empty, ap_sourcelim);
4118c72fb110SKristof Provost 
4119c72fb110SKristof Provost int
pfctl_source_limiter_add(struct pfctl_handle * h,struct pfctl_source_lim * lim)4120c72fb110SKristof Provost pfctl_source_limiter_add(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4121c72fb110SKristof Provost {
4122c72fb110SKristof Provost 	struct snl_writer nw;
4123c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4124c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4125c72fb110SKristof Provost 	uint32_t seq_id;
4126c72fb110SKristof Provost 	int family_id;
4127c72fb110SKristof Provost 
4128c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4129c72fb110SKristof Provost 	if (family_id == 0)
4130c72fb110SKristof Provost 		return (ENOTSUP);
4131c72fb110SKristof Provost 
4132c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4133c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_LIMITER_ADD);
4134c72fb110SKristof Provost 
4135c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_TICKET, lim->ticket);
4136c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SCL_NAME, lim->name);
4137c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
4138c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_ENTRIES, lim->entries);
4139c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_LIMIT, lim->limit);
4140c72fb110SKristof Provost 	snl_add_msg_attr_limit_rate(&nw, PF_SCL_RATE, &lim->rate);
4141c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SCL_OVERLOAD_TBL_NAME, lim->overload_tblname);
4142c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_HIGH_WM, lim->overload_hwm);
4143c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_LOW_WM, lim->overload_lwm);
4144c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_INET_PREFIX, lim->inet_prefix);
4145c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_INET6_PREFIX, lim->inet6_prefix);
4146c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SCL_DESCR, lim->description);
4147c72fb110SKristof Provost 
4148c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4149c72fb110SKristof Provost 		return (ENXIO);
4150c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4151c72fb110SKristof Provost 
4152c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4153c72fb110SKristof Provost 		return (ENXIO);
4154c72fb110SKristof Provost 
4155c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4156c72fb110SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, &lim))
4157c72fb110SKristof Provost 			continue;
4158c72fb110SKristof Provost 	}
4159c72fb110SKristof Provost 
4160c72fb110SKristof Provost 	return (e.error);
4161c72fb110SKristof Provost }
4162c72fb110SKristof Provost 
4163c72fb110SKristof Provost static int
_pfctl_source_limiter_get(struct pfctl_handle * h,int cmd,struct pfctl_source_lim * lim)4164c72fb110SKristof Provost _pfctl_source_limiter_get(struct pfctl_handle *h, int cmd, struct pfctl_source_lim *lim)
4165c72fb110SKristof Provost {
4166c72fb110SKristof Provost 	struct snl_writer nw;
4167c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4168c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4169c72fb110SKristof Provost 	uint32_t seq_id;
4170c72fb110SKristof Provost 	int family_id;
4171c72fb110SKristof Provost 
4172c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4173c72fb110SKristof Provost 	if (family_id == 0)
4174c72fb110SKristof Provost 		return (ENOTSUP);
4175c72fb110SKristof Provost 
4176c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4177c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, cmd);
4178c72fb110SKristof Provost 
4179c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
4180c72fb110SKristof Provost 
4181c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4182c72fb110SKristof Provost 		return (ENXIO);
4183c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4184c72fb110SKristof Provost 
4185c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4186c72fb110SKristof Provost 		return (ENXIO);
4187c72fb110SKristof Provost 
4188c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4189c72fb110SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, lim))
4190c72fb110SKristof Provost 			continue;
4191c72fb110SKristof Provost 	}
4192c72fb110SKristof Provost 
4193c72fb110SKristof Provost 	return (e.error);
4194c72fb110SKristof Provost }
4195c72fb110SKristof Provost 
4196c72fb110SKristof Provost int
pfctl_source_limiter_get(struct pfctl_handle * h,struct pfctl_source_lim * lim)4197c72fb110SKristof Provost pfctl_source_limiter_get(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4198c72fb110SKristof Provost {
4199c72fb110SKristof Provost 	return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_GET, lim));
4200c72fb110SKristof Provost }
4201c72fb110SKristof Provost 
4202c72fb110SKristof Provost int
pfctl_source_limiter_nget(struct pfctl_handle * h,struct pfctl_source_lim * lim)4203c72fb110SKristof Provost pfctl_source_limiter_nget(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4204c72fb110SKristof Provost {
4205c72fb110SKristof Provost 	return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_NGET, lim));
4206c72fb110SKristof Provost }
4207c72fb110SKristof Provost 
4208c72fb110SKristof Provost #define _OUT(_field)	offsetof(struct pfctl_source, _field)
4209c72fb110SKristof Provost static struct snl_attr_parser ap_source[] = {
4210c72fb110SKristof Provost 	{ .type = PF_SRC_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
4211c72fb110SKristof Provost 	{ .type = PF_SRC_RDOMAIN, .off = _OUT(rdomain), .cb = snl_attr_get_uint32 },
4212c72fb110SKristof Provost 	{ .type = PF_SRC_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
4213c72fb110SKristof Provost 	{ .type = PF_SRC_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4214c72fb110SKristof Provost 	{ .type = PF_SRC_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4215c72fb110SKristof Provost 	{ .type = PF_SRC_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4216c72fb110SKristof Provost 	{ .type = PF_SRC_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4217c72fb110SKristof Provost 	{ .type = PF_SRC_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4218c72fb110SKristof Provost 	{ .type = PF_SRC_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
4219c72fb110SKristof Provost 	{. type = PF_SRC_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
4220c72fb110SKristof Provost };
4221c72fb110SKristof Provost #undef _OUT
4222c72fb110SKristof Provost SNL_DECLARE_PARSER(source_parser, struct genlmsghdr, snl_f_p_empty, ap_source);
4223c72fb110SKristof Provost 
4224c72fb110SKristof Provost int
pfctl_source_get(struct pfctl_handle * h,int id,pfctl_get_source_fn fn,void * arg)4225c72fb110SKristof Provost pfctl_source_get(struct pfctl_handle *h, int id, pfctl_get_source_fn fn, void *arg)
4226c72fb110SKristof Provost {
4227c72fb110SKristof Provost 	struct snl_writer nw;
4228c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4229c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4230c72fb110SKristof Provost 	uint32_t seq_id;
4231c72fb110SKristof Provost 	int family_id, error;
4232c72fb110SKristof Provost 
4233c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4234c72fb110SKristof Provost 	if (family_id == 0)
4235c72fb110SKristof Provost 		return (ENOTSUP);
4236c72fb110SKristof Provost 
4237c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4238c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_NGET);
4239c72fb110SKristof Provost 
4240c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SRC_ID, id);
4241c72fb110SKristof Provost 
4242c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4243c72fb110SKristof Provost 		return (ENXIO);
4244c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4245c72fb110SKristof Provost 
4246c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4247c72fb110SKristof Provost 		return (ENXIO);
4248c72fb110SKristof Provost 
4249c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4250c72fb110SKristof Provost 		struct pfctl_source src;
4251c72fb110SKristof Provost 
4252c72fb110SKristof Provost 		if (! snl_parse_nlmsg(&h->ss, hdr, &source_parser, &src))
4253c72fb110SKristof Provost 			continue;
4254c72fb110SKristof Provost 
4255c72fb110SKristof Provost 		error = fn(&src, arg);
4256c72fb110SKristof Provost 		if (error != 0) {
4257c72fb110SKristof Provost 			e.error = error;
4258c72fb110SKristof Provost 			break;
4259c72fb110SKristof Provost 		}
4260c72fb110SKristof Provost 	}
4261c72fb110SKristof Provost 
4262c72fb110SKristof Provost 	return (e.error);
4263c72fb110SKristof Provost }
4264c72fb110SKristof Provost 
4265c72fb110SKristof Provost int
pfctl_source_clear(struct pfctl_handle * h,struct pfctl_source_clear * kill)4266c72fb110SKristof Provost pfctl_source_clear(struct pfctl_handle *h, struct pfctl_source_clear *kill)
4267c72fb110SKristof Provost {
4268c72fb110SKristof Provost 	struct snl_writer nw;
4269c72fb110SKristof Provost 	struct snl_errmsg_data e = {};
4270c72fb110SKristof Provost 	struct nlmsghdr *hdr;
4271c72fb110SKristof Provost 	uint32_t seq_id;
4272c72fb110SKristof Provost 	int family_id;
4273c72fb110SKristof Provost 
4274c72fb110SKristof Provost 	family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
4275c72fb110SKristof Provost 	if (family_id == 0)
4276c72fb110SKristof Provost 		return (ENOTSUP);
4277c72fb110SKristof Provost 
4278c72fb110SKristof Provost 	snl_init_writer(&h->ss, &nw);
4279c72fb110SKristof Provost 	hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_SOURCE_CLEAR);
4280c72fb110SKristof Provost 
4281c72fb110SKristof Provost 	snl_add_msg_attr_string(&nw, PF_SC_NAME, kill->name);
4282c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SC_ID, kill->id);
4283c72fb110SKristof Provost 	snl_add_msg_attr_u32(&nw, PF_SC_RDOMAIN, kill->rdomain);
4284c72fb110SKristof Provost 	snl_add_msg_attr_u8(&nw, PF_SC_AF, kill->af);
4285c72fb110SKristof Provost 	snl_add_msg_attr_ip6(&nw, PF_SC_ADDR, &kill->addr.v6);
4286c72fb110SKristof Provost 
4287c72fb110SKristof Provost 	if ((hdr = snl_finalize_msg(&nw)) == NULL)
4288c72fb110SKristof Provost 		return (ENXIO);
4289c72fb110SKristof Provost 	seq_id = hdr->nlmsg_seq;
4290c72fb110SKristof Provost 
4291c72fb110SKristof Provost 	if (! snl_send_message(&h->ss, hdr))
4292c72fb110SKristof Provost 		return (ENXIO);
4293c72fb110SKristof Provost 
4294c72fb110SKristof Provost 	while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4295c72fb110SKristof Provost 	}
4296c72fb110SKristof Provost 
4297c72fb110SKristof Provost 	return (e.error);
4298c72fb110SKristof Provost }
4299c72fb110SKristof Provost 
43001e7665e3SKristof Provost static const struct snl_hdr_parser *all_parsers[] = {
43011e7665e3SKristof Provost 	&begin_addrs_parser,
43021e7665e3SKristof Provost 	&clear_states_parser,
43031e7665e3SKristof Provost 	&clr_addrs_parser,
43041e7665e3SKristof Provost 	&creator_parser,
43051e7665e3SKristof Provost 	&get_addr_parser,
43061e7665e3SKristof Provost 	&get_addrs_parser,
43071e7665e3SKristof Provost 	&get_limit_parser,
43081e7665e3SKristof Provost 	&get_timeout_parser,
43091e7665e3SKristof Provost 	&getrule_parser,
43101e7665e3SKristof Provost 	&getrules_parser,
43111e7665e3SKristof Provost 	&getstatus_parser,
43121e7665e3SKristof Provost 	&nadd_parser,
43131e7665e3SKristof Provost 	&natlook_parser,
43141e7665e3SKristof Provost 	&ndel_parser,
43151e7665e3SKristof Provost 	&ruleset_parser,
43161e7665e3SKristof Provost 	&skey_parser,
43171e7665e3SKristof Provost 	&source_parser,
43181e7665e3SKristof Provost 	&sourcelim_parser,
43191e7665e3SKristof Provost 	&speer_parser,
43201e7665e3SKristof Provost 	&srcnode_parser,
43211e7665e3SKristof Provost 	&state_parser,
43221e7665e3SKristof Provost 	&statelim_parser,
43231e7665e3SKristof Provost 	&table_add_addr_parser,
43241e7665e3SKristof Provost 	&table_astats_parser,
43251e7665e3SKristof Provost 	&table_del_addr_parser,
43261e7665e3SKristof Provost 	&table_get_addr_parser,
43271e7665e3SKristof Provost 	&table_set_addr_parser,
43281e7665e3SKristof Provost 	&tstats_clr_parser,
43291e7665e3SKristof Provost 	&tstats_parser,
43301e7665e3SKristof Provost };
43311e7665e3SKristof Provost 
43321e7665e3SKristof Provost static void
_pfctl_verify_parsers(void)43331e7665e3SKristof Provost _pfctl_verify_parsers(void)
43341e7665e3SKristof Provost {
43351e7665e3SKristof Provost 	SNL_VERIFY_PARSERS(all_parsers);
43361e7665e3SKristof Provost }
4337