xref: /openbsd/usr.bin/systat/pftop.c (revision 603ea060)
1*603ea060Sjsg /* $OpenBSD: pftop.c,v 1.47 2024/04/22 14:19:48 jsg Exp $	 */
273baed14Scanacar /*
373baed14Scanacar  * Copyright (c) 2001, 2007 Can Erkin Acar
473baed14Scanacar  * Copyright (c) 2001 Daniel Hartmeier
573baed14Scanacar  * All rights reserved.
673baed14Scanacar  *
773baed14Scanacar  * Redistribution and use in source and binary forms, with or without
873baed14Scanacar  * modification, are permitted provided that the following conditions
973baed14Scanacar  * are met:
1073baed14Scanacar  *
1173baed14Scanacar  *    - Redistributions of source code must retain the above copyright
1273baed14Scanacar  *      notice, this list of conditions and the following disclaimer.
1373baed14Scanacar  *    - Redistributions in binary form must reproduce the above
1473baed14Scanacar  *      copyright notice, this list of conditions and the following
1573baed14Scanacar  *      disclaimer in the documentation and/or other materials provided
1673baed14Scanacar  *      with the distribution.
1773baed14Scanacar  *
1873baed14Scanacar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1973baed14Scanacar  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2073baed14Scanacar  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2173baed14Scanacar  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2273baed14Scanacar  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2373baed14Scanacar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2473baed14Scanacar  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2573baed14Scanacar  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2673baed14Scanacar  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2773baed14Scanacar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
2873baed14Scanacar  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2973baed14Scanacar  * POSSIBILITY OF SUCH DAMAGE.
3073baed14Scanacar  *
3173baed14Scanacar  */
3273baed14Scanacar 
3373baed14Scanacar #include <sys/types.h>
3473baed14Scanacar #include <sys/ioctl.h>
3573baed14Scanacar #include <sys/socket.h>
3673baed14Scanacar 
3773baed14Scanacar #include <net/if.h>
3873baed14Scanacar #include <netinet/in.h>
3926f2f421Smcbride #include <netinet/tcp.h>
4073baed14Scanacar #include <netinet/tcp_fsm.h>
4173baed14Scanacar #include <net/pfvar.h>
4273baed14Scanacar #include <arpa/inet.h>
4373baed14Scanacar 
44aa14b181Shenning #include <net/hfsc.h>
45aa14b181Shenning 
4673baed14Scanacar #include <ctype.h>
4773baed14Scanacar #include <curses.h>
4873baed14Scanacar #include <err.h>
4973baed14Scanacar #include <errno.h>
5073baed14Scanacar #include <fcntl.h>
5173baed14Scanacar #include <netdb.h>
5273baed14Scanacar #include <signal.h>
5373baed14Scanacar #include <stdio.h>
5473baed14Scanacar #include <stdlib.h>
5573baed14Scanacar #include <string.h>
5673baed14Scanacar #include <unistd.h>
578f6b3bafSderaadt #include <limits.h>
5873baed14Scanacar #include <stdarg.h>
5973baed14Scanacar 
60b1d2a504Scanacar #include "systat.h"
6173baed14Scanacar #include "engine.h"
6273baed14Scanacar #include "cache.h"
6373baed14Scanacar 
6473baed14Scanacar extern const char *tcpstates[];
6573baed14Scanacar 
6673baed14Scanacar #define MIN_NUM_STATES 1024
6773baed14Scanacar #define NUM_STATE_INC  1024
6873baed14Scanacar 
6973baed14Scanacar #define DEFAULT_CACHE_SIZE 10000
7073baed14Scanacar 
7173baed14Scanacar /* XXX must also check type before use */
7273baed14Scanacar #define PT_ADDR(x) (&(x)->addr.v.a.addr)
7373baed14Scanacar 
7473baed14Scanacar /* XXX must also check type before use */
7573baed14Scanacar #define PT_MASK(x) (&(x)->addr.v.a.mask)
7673baed14Scanacar 
7773baed14Scanacar #define PT_NOROUTE(x) ((x)->addr.type == PF_ADDR_NOROUTE)
7873baed14Scanacar 
7973baed14Scanacar /* view management */
8073baed14Scanacar int select_states(void);
8173baed14Scanacar int read_states(void);
8273baed14Scanacar void sort_states(void);
8373baed14Scanacar void print_states(void);
8473baed14Scanacar 
8573baed14Scanacar int select_rules(void);
8673baed14Scanacar int read_rules(void);
8773baed14Scanacar void print_rules(void);
8873baed14Scanacar 
8973baed14Scanacar int select_queues(void);
9073baed14Scanacar int read_queues(void);
9173baed14Scanacar void print_queues(void);
9273baed14Scanacar 
93035d703dScanacar void update_cache(void);
94035d703dScanacar 
9573baed14Scanacar /* qsort callbacks */
9673baed14Scanacar int sort_size_callback(const void *s1, const void *s2);
9773baed14Scanacar int sort_exp_callback(const void *s1, const void *s2);
9873baed14Scanacar int sort_pkt_callback(const void *s1, const void *s2);
9973baed14Scanacar int sort_age_callback(const void *s1, const void *s2);
10073baed14Scanacar int sort_sa_callback(const void *s1, const void *s2);
10173baed14Scanacar int sort_sp_callback(const void *s1, const void *s2);
10273baed14Scanacar int sort_da_callback(const void *s1, const void *s2);
10373baed14Scanacar int sort_dp_callback(const void *s1, const void *s2);
10473baed14Scanacar int sort_rate_callback(const void *s1, const void *s2);
10573baed14Scanacar int sort_peak_callback(const void *s1, const void *s2);
10673baed14Scanacar int pf_dev = -1;
10773baed14Scanacar 
10873baed14Scanacar struct sc_ent **state_cache = NULL;
109d93808b7Scanacar struct pfsync_state *state_buf = NULL;
1104c82f412Sbluhm size_t state_buf_len = 0;
1114c82f412Sbluhm size_t *state_ord = NULL;
1124c82f412Sbluhm size_t num_states = 0;
1134c82f412Sbluhm size_t num_states_all = 0;
11473baed14Scanacar u_int32_t num_rules = 0;
11573baed14Scanacar u_int32_t num_queues = 0;
11673baed14Scanacar int cachestates = 0;
11773baed14Scanacar 
11873baed14Scanacar char *filter_string = NULL;
11973baed14Scanacar 
12073baed14Scanacar #define MIN_LABEL_SIZE 5
12173baed14Scanacar #define ANCHOR_FLD_SIZE 12
12273baed14Scanacar 
12373baed14Scanacar /* Define fields */
12473baed14Scanacar field_def fields[] = {
12573baed14Scanacar 	{"SRC", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
12673baed14Scanacar 	{"DEST", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
12773baed14Scanacar 	{"GW", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
12873baed14Scanacar 	{"STATE", 5, 23, 18, FLD_ALIGN_COLUMN, -1, 0, 0, 0},
12973baed14Scanacar 	{"AGE", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13073baed14Scanacar 	{"EXP", 5, 9, 4, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13173baed14Scanacar 	{"PR ", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
13273baed14Scanacar 	{"DIR", 1, 3, 2, FLD_ALIGN_CENTER, -1, 0, 0, 0},
13373baed14Scanacar 	{"PKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13473baed14Scanacar 	{"BYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13573baed14Scanacar 	{"RULE", 2, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13673baed14Scanacar 	{"LABEL", MIN_LABEL_SIZE, MIN_LABEL_SIZE, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
13773baed14Scanacar 	{"STATES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13873baed14Scanacar 	{"EVAL", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
13973baed14Scanacar 	{"ACTION", 1, 8, 4, FLD_ALIGN_LEFT, -1, 0, 0, 0},
14073baed14Scanacar 	{"LOG", 1, 3, 2, FLD_ALIGN_LEFT, -1, 0, 0, 0},
14173baed14Scanacar 	{"QUICK", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
14273baed14Scanacar 	{"KS", 1, 1, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
143076a12fbSjasper 	{"IF", 4, 7, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
14473baed14Scanacar 	{"INFO", 40, 80, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
145d93808b7Scanacar 	{"MAX", 3, 5, 2, FLD_ALIGN_RIGHT, -1, 0, 0},
14673baed14Scanacar 	{"RATE", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
14773baed14Scanacar 	{"AVG", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
14873baed14Scanacar 	{"PEAK", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
149d93808b7Scanacar 	{"ANCHOR", 6, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0},
15073baed14Scanacar 	{"QUEUE", 15, 30, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
1516cb74e26Smikeb 	{"BW/FL", 4, 5, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15273baed14Scanacar 	{"SCH", 3, 4, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
15373baed14Scanacar 	{"DROP_P", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15473baed14Scanacar 	{"DROP_B", 6, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15573baed14Scanacar 	{"QLEN", 4, 4, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15673baed14Scanacar 	{"BORROW", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15773baed14Scanacar 	{"SUSPENDS", 4, 6, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15873baed14Scanacar 	{"P/S", 3, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
15973baed14Scanacar 	{"B/S", 4, 7, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}
16073baed14Scanacar };
16173baed14Scanacar 
16273baed14Scanacar 
16373baed14Scanacar /* for states */
164596a8091Sjasper #define FLD_SRC     FIELD_ADDR(fields,0)
165596a8091Sjasper #define FLD_DEST    FIELD_ADDR(fields,1)
166596a8091Sjasper #define FLD_GW      FIELD_ADDR(fields,2)
167596a8091Sjasper #define FLD_STATE   FIELD_ADDR(fields,3)
168596a8091Sjasper #define FLD_AGE     FIELD_ADDR(fields,4)
169596a8091Sjasper #define FLD_EXP     FIELD_ADDR(fields,5)
17073baed14Scanacar /* common */
171596a8091Sjasper #define FLD_PROTO   FIELD_ADDR(fields,6)
172596a8091Sjasper #define FLD_DIR     FIELD_ADDR(fields,7)
173596a8091Sjasper #define FLD_PKTS    FIELD_ADDR(fields,8)
174596a8091Sjasper #define FLD_BYTES   FIELD_ADDR(fields,9)
175596a8091Sjasper #define FLD_RULE    FIELD_ADDR(fields,10)
17673baed14Scanacar /* for rules */
177596a8091Sjasper #define FLD_LABEL   FIELD_ADDR(fields,11)
178596a8091Sjasper #define FLD_STATS   FIELD_ADDR(fields,12)
179596a8091Sjasper #define FLD_EVAL    FIELD_ADDR(fields,13)
180596a8091Sjasper #define FLD_ACTION  FIELD_ADDR(fields,14)
181596a8091Sjasper #define FLD_LOG     FIELD_ADDR(fields,15)
182596a8091Sjasper #define FLD_QUICK   FIELD_ADDR(fields,16)
183596a8091Sjasper #define FLD_KST     FIELD_ADDR(fields,17)
184596a8091Sjasper #define FLD_IF      FIELD_ADDR(fields,18)
185596a8091Sjasper #define FLD_RINFO   FIELD_ADDR(fields,19)
186596a8091Sjasper #define FLD_STMAX   FIELD_ADDR(fields,20)
18773baed14Scanacar /* other */
188596a8091Sjasper #define FLD_SI      FIELD_ADDR(fields,21)    /* instantaneous speed */
189596a8091Sjasper #define FLD_SA      FIELD_ADDR(fields,22)    /* average speed */
190596a8091Sjasper #define FLD_SP      FIELD_ADDR(fields,23)    /* peak speed */
191596a8091Sjasper #define FLD_ANCHOR  FIELD_ADDR(fields,24)
19273baed14Scanacar /* for queues */
193596a8091Sjasper #define FLD_QUEUE   FIELD_ADDR(fields,25)
194596a8091Sjasper #define FLD_BANDW   FIELD_ADDR(fields,26)
195596a8091Sjasper #define FLD_SCHED   FIELD_ADDR(fields,27)
19675cf0799Smikeb #define FLD_DROPP   FIELD_ADDR(fields,28)
19775cf0799Smikeb #define FLD_DROPB   FIELD_ADDR(fields,29)
19875cf0799Smikeb #define FLD_QLEN    FIELD_ADDR(fields,30)
19975cf0799Smikeb #define FLD_BORR    FIELD_ADDR(fields,31)
20075cf0799Smikeb #define FLD_SUSP    FIELD_ADDR(fields,32)
20175cf0799Smikeb #define FLD_PKTSPS  FIELD_ADDR(fields,33)
20275cf0799Smikeb #define FLD_BYTESPS FIELD_ADDR(fields,34)
20373baed14Scanacar 
20473baed14Scanacar /* Define views */
20573baed14Scanacar field_def *view0[] = {
20673baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE,
20773baed14Scanacar 	FLD_AGE, FLD_EXP, FLD_PKTS, FLD_BYTES, NULL
20873baed14Scanacar };
20973baed14Scanacar 
21073baed14Scanacar field_def *view1[] = {
21173baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_GW, FLD_STATE, FLD_AGE,
21273baed14Scanacar 	FLD_EXP, FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, NULL
21373baed14Scanacar };
21473baed14Scanacar 
21573baed14Scanacar field_def *view2[] = {
21673baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_STATE, FLD_AGE, FLD_EXP,
21773baed14Scanacar 	FLD_PKTS, FLD_BYTES, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL
21873baed14Scanacar };
21973baed14Scanacar 
22073baed14Scanacar field_def *view3[] = {
22173baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_AGE, FLD_EXP, FLD_PKTS,
22273baed14Scanacar 	FLD_BYTES, FLD_STATE, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL
22373baed14Scanacar };
22473baed14Scanacar 
22573baed14Scanacar field_def *view4[] = {
22673baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST, FLD_PKTS, FLD_BYTES, FLD_STATE,
22773baed14Scanacar 	FLD_AGE, FLD_EXP, FLD_SI, FLD_SP, FLD_SA, FLD_RULE, FLD_GW, NULL
22873baed14Scanacar };
22973baed14Scanacar 
23073baed14Scanacar field_def *view5[] = {
23173baed14Scanacar 	FLD_RULE, FLD_ANCHOR, FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF,
23273baed14Scanacar 	FLD_PROTO, FLD_KST, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX,
23373baed14Scanacar 	FLD_RINFO, NULL
23473baed14Scanacar };
23573baed14Scanacar 
23673baed14Scanacar field_def *view6[] = {
23773baed14Scanacar 	FLD_RULE, FLD_LABEL, FLD_PKTS, FLD_BYTES, FLD_STATS, FLD_STMAX,
23873baed14Scanacar 	FLD_ACTION, FLD_DIR, FLD_LOG, FLD_QUICK, FLD_IF, FLD_PROTO,
23973baed14Scanacar 	FLD_ANCHOR, FLD_KST, NULL
24073baed14Scanacar };
24173baed14Scanacar 
24273baed14Scanacar field_def *view7[] = {
24373baed14Scanacar 	FLD_PROTO, FLD_DIR, FLD_SRC, FLD_DEST,  FLD_SI, FLD_SP, FLD_SA,
24473baed14Scanacar 	FLD_BYTES, FLD_STATE, FLD_PKTS, FLD_AGE, FLD_EXP, FLD_RULE, FLD_GW, NULL
24573baed14Scanacar };
24673baed14Scanacar 
24773baed14Scanacar field_def *view8[] = {
24875cf0799Smikeb 	FLD_QUEUE, FLD_BANDW, FLD_SCHED, FLD_PKTS, FLD_BYTES,
24973baed14Scanacar 	FLD_DROPP, FLD_DROPB, FLD_QLEN, FLD_BORR, FLD_SUSP, FLD_PKTSPS,
25073baed14Scanacar 	FLD_BYTESPS, NULL
25173baed14Scanacar };
25273baed14Scanacar 
25373baed14Scanacar /* Define orderings */
25473baed14Scanacar order_type order_list[] = {
25573baed14Scanacar 	{"none", "none", 'N', NULL},
25673baed14Scanacar 	{"bytes", "bytes", 'B', sort_size_callback},
25773baed14Scanacar 	{"expiry", "exp", 'E', sort_exp_callback},
25873baed14Scanacar 	{"packets", "pkt", 'P', sort_pkt_callback},
25973baed14Scanacar 	{"age", "age", 'A', sort_age_callback},
26073baed14Scanacar 	{"source addr", "src", 'F', sort_sa_callback},
26173baed14Scanacar 	{"dest. addr", "dest", 'T', sort_da_callback},
26273baed14Scanacar 	{"source port", "sport", 'S', sort_sp_callback},
26373baed14Scanacar 	{"dest. port", "dport", 'D', sort_dp_callback},
26473baed14Scanacar 	{"rate", "rate", 'R', sort_rate_callback},
26573baed14Scanacar 	{"peak", "peak", 'K', sort_peak_callback},
26673baed14Scanacar 	{NULL, NULL, 0, NULL}
26773baed14Scanacar };
26873baed14Scanacar 
26973baed14Scanacar /* Define view managers */
27073baed14Scanacar struct view_manager state_mgr = {
27173baed14Scanacar 	"States", select_states, read_states, sort_states, print_header,
2728d6a960aSmartijn 	print_states, keyboard_callback, order_list, order_list
27373baed14Scanacar };
27473baed14Scanacar 
27573baed14Scanacar struct view_manager rule_mgr = {
27673baed14Scanacar 	"Rules", select_rules, read_rules, NULL, print_header,
27773baed14Scanacar 	print_rules, keyboard_callback, NULL, NULL
27873baed14Scanacar };
27973baed14Scanacar 
28073baed14Scanacar struct view_manager queue_mgr = {
28173baed14Scanacar 	"Queues", select_queues, read_queues, NULL, print_header,
28273baed14Scanacar 	print_queues, keyboard_callback, NULL, NULL
28373baed14Scanacar };
28473baed14Scanacar 
28573baed14Scanacar field_view views[] = {
28673baed14Scanacar 	{view2, "states", '8', &state_mgr},
28773baed14Scanacar 	{view5, "rules", '9', &rule_mgr},
28873baed14Scanacar 	{view8, "queues", 'Q', &queue_mgr},
28973baed14Scanacar 	{NULL, NULL, 0, NULL}
29073baed14Scanacar };
29173baed14Scanacar 
292aa14b181Shenning /* queue structures from pfctl */
293aa14b181Shenning 
294aa14b181Shenning struct queue_stats {
295aa14b181Shenning 	struct hfsc_class_stats	 data;
296aa14b181Shenning 	int			 valid;
297aa14b181Shenning 	struct timeval		 timestamp;
298aa14b181Shenning };
299aa14b181Shenning 
300aa14b181Shenning struct pfctl_queue_node {
301aa14b181Shenning 	TAILQ_ENTRY(pfctl_queue_node)	entries;
302aa14b181Shenning 	struct pf_queuespec		qs;
303aa14b181Shenning 	struct queue_stats		qstats;
304aa14b181Shenning 	struct queue_stats		qstats_last;
305aa14b181Shenning 	int				depth;
306aa14b181Shenning };
307aa14b181Shenning TAILQ_HEAD(qnodes, pfctl_queue_node) qnodes = TAILQ_HEAD_INITIALIZER(qnodes);
30873baed14Scanacar 
30973baed14Scanacar /* ordering functions */
31073baed14Scanacar 
31173baed14Scanacar int
sort_size_callback(const void * s1,const void * s2)31273baed14Scanacar sort_size_callback(const void *s1, const void *s2)
31373baed14Scanacar {
3144c82f412Sbluhm 	u_int64_t b1 = COUNTER(state_buf[* (size_t *) s1].bytes[0]) +
3154c82f412Sbluhm 		COUNTER(state_buf[* (size_t *) s1].bytes[1]);
3164c82f412Sbluhm 	u_int64_t b2 = COUNTER(state_buf[* (size_t *) s2].bytes[0]) +
3174c82f412Sbluhm 		COUNTER(state_buf[* (size_t *) s2].bytes[1]);
31873baed14Scanacar 	if (b2 > b1)
31973baed14Scanacar 		return sortdir;
32073baed14Scanacar 	if (b2 < b1)
32173baed14Scanacar 		return -sortdir;
32273baed14Scanacar 	return 0;
32373baed14Scanacar }
32473baed14Scanacar 
32573baed14Scanacar int
sort_pkt_callback(const void * s1,const void * s2)32673baed14Scanacar sort_pkt_callback(const void *s1, const void *s2)
32773baed14Scanacar {
3284c82f412Sbluhm 	u_int64_t p1 = COUNTER(state_buf[* (size_t *) s1].packets[0]) +
3294c82f412Sbluhm 		COUNTER(state_buf[* (size_t *) s1].packets[1]);
3304c82f412Sbluhm 	u_int64_t p2 = COUNTER(state_buf[* (size_t *) s2].packets[0]) +
3314c82f412Sbluhm 		COUNTER(state_buf[* (size_t *) s2].packets[1]);
33273baed14Scanacar 	if (p2 > p1)
33373baed14Scanacar 		return sortdir;
33473baed14Scanacar 	if (p2 < p1)
33573baed14Scanacar 		return -sortdir;
33673baed14Scanacar 	return 0;
33773baed14Scanacar }
33873baed14Scanacar 
33973baed14Scanacar int
sort_age_callback(const void * s1,const void * s2)34073baed14Scanacar sort_age_callback(const void *s1, const void *s2)
34173baed14Scanacar {
3424c82f412Sbluhm 	if (ntohl(state_buf[* (size_t *) s2].creation) >
3434c82f412Sbluhm 	    ntohl(state_buf[* (size_t *) s1].creation))
34473baed14Scanacar 		return sortdir;
3454c82f412Sbluhm 	if (ntohl(state_buf[* (size_t *) s2].creation) <
3464c82f412Sbluhm 	    ntohl(state_buf[* (size_t *) s1].creation))
34773baed14Scanacar 		return -sortdir;
34873baed14Scanacar 	return 0;
34973baed14Scanacar }
35073baed14Scanacar 
35173baed14Scanacar int
sort_exp_callback(const void * s1,const void * s2)35273baed14Scanacar sort_exp_callback(const void *s1, const void *s2)
35373baed14Scanacar {
3544c82f412Sbluhm 	if (ntohl(state_buf[* (size_t *) s2].expire) >
3554c82f412Sbluhm 	    ntohl(state_buf[* (size_t *) s1].expire))
35673baed14Scanacar 		return sortdir;
3574c82f412Sbluhm 	if (ntohl(state_buf[* (size_t *) s2].expire) <
3584c82f412Sbluhm 	    ntohl(state_buf[* (size_t *) s1].expire))
35973baed14Scanacar 		return -sortdir;
36073baed14Scanacar 	return 0;
36173baed14Scanacar }
36273baed14Scanacar 
36373baed14Scanacar int
sort_rate_callback(const void * s1,const void * s2)36473baed14Scanacar sort_rate_callback(const void *s1, const void *s2)
36573baed14Scanacar {
36673baed14Scanacar 	struct sc_ent *e1 = state_cache[* (u_int32_t *) s1];
36773baed14Scanacar 	struct sc_ent *e2 = state_cache[* (u_int32_t *) s2];
36873baed14Scanacar 
36973baed14Scanacar 	if (e1 == NULL)
37073baed14Scanacar 		return sortdir;
37173baed14Scanacar 	if (e2 == NULL)
37273baed14Scanacar 		return -sortdir;
37373baed14Scanacar 
37473baed14Scanacar 	if (e2->rate > e1 -> rate)
37573baed14Scanacar 		return sortdir;
37673baed14Scanacar 	if (e2->rate < e1 -> rate)
37773baed14Scanacar 		return -sortdir;
37873baed14Scanacar 	return 0;
37973baed14Scanacar }
38073baed14Scanacar 
38173baed14Scanacar int
sort_peak_callback(const void * s1,const void * s2)38273baed14Scanacar sort_peak_callback(const void *s1, const void *s2)
38373baed14Scanacar {
38473baed14Scanacar 	struct sc_ent *e1 = state_cache[* (u_int32_t *) s1];
38573baed14Scanacar 	struct sc_ent *e2 = state_cache[* (u_int32_t *) s2];
38673baed14Scanacar 
38773baed14Scanacar 	if (e2 == NULL)
38873baed14Scanacar 		return -sortdir;
38973baed14Scanacar 	if (e1 == NULL || e2 == NULL)
39073baed14Scanacar 		return 0;
39173baed14Scanacar 
39273baed14Scanacar 	if (e2->peak > e1 -> peak)
39373baed14Scanacar 		return sortdir;
39473baed14Scanacar 	if (e2->peak < e1 -> peak)
39573baed14Scanacar 		return -sortdir;
39673baed14Scanacar 	return 0;
39773baed14Scanacar }
39873baed14Scanacar 
39973baed14Scanacar int
compare_addr(int af,const struct pf_addr * a,const struct pf_addr * b)40073baed14Scanacar compare_addr(int af, const struct pf_addr *a, const struct pf_addr *b)
40173baed14Scanacar {
40273baed14Scanacar 	switch (af) {
40373baed14Scanacar 	case AF_INET:
40473baed14Scanacar 		if (ntohl(a->addr32[0]) > ntohl(b->addr32[0]))
40573baed14Scanacar 			return 1;
40673baed14Scanacar 		if (a->addr32[0] != b->addr32[0])
40773baed14Scanacar 			return -1;
40873baed14Scanacar 		break;
40973baed14Scanacar 	case AF_INET6:
41073baed14Scanacar 		if (ntohl(a->addr32[0]) > ntohl(b->addr32[0]))
41173baed14Scanacar 			return 1;
41273baed14Scanacar 		if (a->addr32[0] != b->addr32[0])
41373baed14Scanacar 			return -1;
41473baed14Scanacar 		if (ntohl(a->addr32[1]) > ntohl(b->addr32[1]))
41573baed14Scanacar 			return 1;
41673baed14Scanacar 		if (a->addr32[1] != b->addr32[1])
41773baed14Scanacar 			return -1;
41873baed14Scanacar 		if (ntohl(a->addr32[2]) > ntohl(b->addr32[2]))
41973baed14Scanacar 			return 1;
42073baed14Scanacar 		if (a->addr32[2] != b->addr32[2])
42173baed14Scanacar 			return -1;
42273baed14Scanacar 		if (ntohl(a->addr32[3]) > ntohl(b->addr32[3]))
42373baed14Scanacar 			return 1;
42473baed14Scanacar 		if (a->addr32[3] != b->addr32[3])
42573baed14Scanacar 			return -1;
42673baed14Scanacar 		break;
42773baed14Scanacar 	}
42873baed14Scanacar 
42973baed14Scanacar 	return 0;
43073baed14Scanacar }
43173baed14Scanacar 
43238bde8c5Sjsg static __inline int
sort_addr_callback(const struct pfsync_state * s1,const struct pfsync_state * s2,int dir)433d93808b7Scanacar sort_addr_callback(const struct pfsync_state *s1,
434d93808b7Scanacar 		   const struct pfsync_state *s2, int dir)
43573baed14Scanacar {
43673baed14Scanacar 	const struct pf_addr *aa, *ab;
43773baed14Scanacar 	u_int16_t pa, pb;
438d25344e8Sclaudio 	int af, side, ret, ii, io;
43973baed14Scanacar 
440d25344e8Sclaudio 	side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE;
44173baed14Scanacar 
442d25344e8Sclaudio 	if (s1->key[side].af > s2->key[side].af)
44373baed14Scanacar 		return sortdir;
444d25344e8Sclaudio 	if (s1->key[side].af < s2->key[side].af)
44573baed14Scanacar 		return -sortdir;
44673baed14Scanacar 
44773baed14Scanacar 	ii = io = 0;
44873baed14Scanacar 
44973baed14Scanacar 	if (dir == PF_OUT)	/* looking for source addr */
45073baed14Scanacar 		io = 1;
45173baed14Scanacar 	else			/* looking for dest addr */
45273baed14Scanacar 		ii = 1;
45373baed14Scanacar 
454d25344e8Sclaudio 	if (s1->key[PF_SK_STACK].af != s1->key[PF_SK_WIRE].af) {
455d25344e8Sclaudio 		dir = PF_OUT;
456d25344e8Sclaudio 		side = PF_SK_STACK;
45773baed14Scanacar 	} else {
458d25344e8Sclaudio 		dir = s1->direction;
459d25344e8Sclaudio 		side = PF_SK_WIRE;
46073baed14Scanacar 	}
46173baed14Scanacar 
462d25344e8Sclaudio 	if (dir == PF_IN) {
463d25344e8Sclaudio 		aa = &s1->key[PF_SK_STACK].addr[ii];
464d25344e8Sclaudio 		pa =  s1->key[PF_SK_STACK].port[ii];
465d25344e8Sclaudio 		af = s1->key[PF_SK_STACK].af;
466d25344e8Sclaudio 	} else {
467d25344e8Sclaudio 		aa = &s1->key[side].addr[io];
468d25344e8Sclaudio 		pa =  s1->key[side].port[io];
469d25344e8Sclaudio 		af = s1->key[side].af;
470d25344e8Sclaudio 	}
471d25344e8Sclaudio 
472d25344e8Sclaudio 	if (s2->key[PF_SK_STACK].af != s2->key[PF_SK_WIRE].af) {
473d25344e8Sclaudio 		dir = PF_OUT;
474d25344e8Sclaudio 		side = PF_SK_STACK;
475d25344e8Sclaudio 	} else {
476d25344e8Sclaudio 		dir = s2->direction;
477d25344e8Sclaudio 		side = PF_SK_WIRE;
478d25344e8Sclaudio 	}
479d25344e8Sclaudio 
480d25344e8Sclaudio 	if (dir == PF_IN) {
481969c2abfSderaadt 		ab = &s2->key[PF_SK_STACK].addr[ii];
48273baed14Scanacar 		pb =  s2->key[PF_SK_STACK].port[ii];
483d25344e8Sclaudio 		af = s1->key[PF_SK_STACK].af;
48473baed14Scanacar 	} else {
485d25344e8Sclaudio 		ab = &s2->key[side].addr[io];
486d25344e8Sclaudio 		pb =  s2->key[side].port[io];
487d25344e8Sclaudio 		af = s1->key[side].af;
48873baed14Scanacar 	}
48973baed14Scanacar 
49073baed14Scanacar 	ret = compare_addr(af, aa, ab);
49173baed14Scanacar 	if (ret)
49273baed14Scanacar 		return ret * sortdir;
49373baed14Scanacar 
49473baed14Scanacar 	if (ntohs(pa) > ntohs(pb))
49573baed14Scanacar 		return sortdir;
49673baed14Scanacar 	return -sortdir;
49773baed14Scanacar }
49873baed14Scanacar 
49938bde8c5Sjsg static __inline int
sort_port_callback(const struct pfsync_state * s1,const struct pfsync_state * s2,int dir)500d93808b7Scanacar sort_port_callback(const struct pfsync_state *s1,
501d93808b7Scanacar 		   const struct pfsync_state *s2, int dir)
50273baed14Scanacar {
50373baed14Scanacar 	const struct pf_addr *aa, *ab;
50473baed14Scanacar 	u_int16_t pa, pb;
505d25344e8Sclaudio 	int af, side, ret, ii, io;
50673baed14Scanacar 
507d25344e8Sclaudio 	side = s1->direction == PF_IN ? PF_SK_STACK : PF_SK_WIRE;
50873baed14Scanacar 
509d25344e8Sclaudio 	if (s1->key[side].af > s2->key[side].af)
51073baed14Scanacar 		return sortdir;
511d25344e8Sclaudio 	if (s1->key[side].af < s2->key[side].af)
51273baed14Scanacar 		return -sortdir;
51373baed14Scanacar 
51473baed14Scanacar 	ii = io = 0;
51573baed14Scanacar 
51673baed14Scanacar 	if (dir == PF_OUT)	/* looking for source addr */
51773baed14Scanacar 		io = 1;
51873baed14Scanacar 	else			/* looking for dest addr */
51973baed14Scanacar 		ii = 1;
52073baed14Scanacar 
521d25344e8Sclaudio 	if (s1->key[PF_SK_STACK].af != s1->key[PF_SK_WIRE].af) {
522d25344e8Sclaudio 		dir = PF_OUT;
523d25344e8Sclaudio 		side = PF_SK_STACK;
52473baed14Scanacar 	} else {
525d25344e8Sclaudio 		dir = s1->direction;
526d25344e8Sclaudio 		side = PF_SK_WIRE;
52773baed14Scanacar 	}
52873baed14Scanacar 
529d25344e8Sclaudio 	if (dir == PF_IN) {
530d25344e8Sclaudio 		aa = &s1->key[PF_SK_STACK].addr[ii];
531d25344e8Sclaudio 		pa =  s1->key[PF_SK_STACK].port[ii];
532d25344e8Sclaudio 		af = s1->key[PF_SK_STACK].af;
533d25344e8Sclaudio 	} else {
534d25344e8Sclaudio 		aa = &s1->key[side].addr[io];
535d25344e8Sclaudio 		pa =  s1->key[side].port[io];
536d25344e8Sclaudio 		af = s1->key[side].af;
537d25344e8Sclaudio 	}
538d25344e8Sclaudio 
539d25344e8Sclaudio 	if (s2->key[PF_SK_STACK].af != s2->key[PF_SK_WIRE].af) {
540d25344e8Sclaudio 		dir = PF_OUT;
541d25344e8Sclaudio 		side = PF_SK_STACK;
542d25344e8Sclaudio 	} else {
543d25344e8Sclaudio 		dir = s2->direction;
544d25344e8Sclaudio 		side = PF_SK_WIRE;
545d25344e8Sclaudio 	}
546d25344e8Sclaudio 
547d25344e8Sclaudio 	if (dir == PF_IN) {
548969c2abfSderaadt 		ab = &s2->key[PF_SK_STACK].addr[ii];
54973baed14Scanacar 		pb =  s2->key[PF_SK_STACK].port[ii];
550d25344e8Sclaudio 		af = s1->key[PF_SK_STACK].af;
55173baed14Scanacar 	} else {
552d25344e8Sclaudio 		ab = &s2->key[side].addr[io];
553d25344e8Sclaudio 		pb =  s2->key[side].port[io];
554d25344e8Sclaudio 		af = s1->key[side].af;
55573baed14Scanacar 	}
55673baed14Scanacar 
55773baed14Scanacar 
55873baed14Scanacar 	if (ntohs(pa) > ntohs(pb))
55973baed14Scanacar 		return sortdir;
56073baed14Scanacar 	if (ntohs(pa) < ntohs(pb))
56173baed14Scanacar 		return - sortdir;
56273baed14Scanacar 
56373baed14Scanacar 	ret = compare_addr(af, aa, ab);
56473baed14Scanacar 	if (ret)
56573baed14Scanacar 		return ret * sortdir;
56673baed14Scanacar 	return -sortdir;
56773baed14Scanacar }
56873baed14Scanacar 
56973baed14Scanacar int
sort_sa_callback(const void * p1,const void * p2)570d93808b7Scanacar sort_sa_callback(const void *p1, const void *p2)
57173baed14Scanacar {
5724c82f412Sbluhm 	struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
5734c82f412Sbluhm 	struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
57473baed14Scanacar 	return sort_addr_callback(s1, s2, PF_OUT);
57573baed14Scanacar }
57673baed14Scanacar 
577d93808b7Scanacar int
sort_da_callback(const void * p1,const void * p2)578d93808b7Scanacar sort_da_callback(const void *p1, const void *p2)
57973baed14Scanacar {
5804c82f412Sbluhm 	struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
5814c82f412Sbluhm 	struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
58273baed14Scanacar 	return sort_addr_callback(s1, s2, PF_IN);
58373baed14Scanacar }
58473baed14Scanacar 
58573baed14Scanacar int
sort_sp_callback(const void * p1,const void * p2)58673baed14Scanacar sort_sp_callback(const void *p1, const void *p2)
58773baed14Scanacar {
5884c82f412Sbluhm 	struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
5894c82f412Sbluhm 	struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
59073baed14Scanacar 	return sort_port_callback(s1, s2, PF_OUT);
59173baed14Scanacar }
59273baed14Scanacar 
59373baed14Scanacar int
sort_dp_callback(const void * p1,const void * p2)59473baed14Scanacar sort_dp_callback(const void *p1, const void *p2)
59573baed14Scanacar {
5964c82f412Sbluhm 	struct pfsync_state *s1 = state_buf + (* (size_t *) p1);
5974c82f412Sbluhm 	struct pfsync_state *s2 = state_buf + (* (size_t *) p2);
59873baed14Scanacar 	return sort_port_callback(s1, s2, PF_IN);
59973baed14Scanacar }
60073baed14Scanacar 
60173baed14Scanacar void
sort_states(void)60273baed14Scanacar sort_states(void)
60373baed14Scanacar {
60473baed14Scanacar 	order_type *ordering;
60573baed14Scanacar 
60673baed14Scanacar 	if (curr_mgr == NULL)
60773baed14Scanacar 		return;
60873baed14Scanacar 
60973baed14Scanacar 	ordering = curr_mgr->order_curr;
61073baed14Scanacar 
61173baed14Scanacar 	if (ordering == NULL)
61273baed14Scanacar 		return;
61373baed14Scanacar 	if (ordering->func == NULL)
61473baed14Scanacar 		return;
61573baed14Scanacar 	if (state_buf == NULL)
61673baed14Scanacar 		return;
61773baed14Scanacar 	if (num_states <= 0)
61873baed14Scanacar 		return;
61973baed14Scanacar 
6204c82f412Sbluhm 	mergesort(state_ord, num_states, sizeof(size_t), ordering->func);
62173baed14Scanacar }
62273baed14Scanacar 
62373baed14Scanacar /* state management functions */
62473baed14Scanacar 
62573baed14Scanacar void
alloc_buf(size_t ns)6264c82f412Sbluhm alloc_buf(size_t ns)
62773baed14Scanacar {
6284c82f412Sbluhm 	size_t len;
62973baed14Scanacar 
63073baed14Scanacar 	if (ns < MIN_NUM_STATES)
63173baed14Scanacar 		ns = MIN_NUM_STATES;
63273baed14Scanacar 
63373baed14Scanacar 	len = ns;
63473baed14Scanacar 
63573baed14Scanacar 	if (len >= state_buf_len) {
63673baed14Scanacar 		len += NUM_STATE_INC;
6372daca27aSdoug 		state_buf = reallocarray(state_buf, len,
6382daca27aSdoug 		    sizeof(struct pfsync_state));
6394c82f412Sbluhm 		state_ord = reallocarray(state_ord, len, sizeof(size_t));
6402daca27aSdoug 		state_cache = reallocarray(state_cache, len,
6412daca27aSdoug 		    sizeof(struct sc_ent *));
64273baed14Scanacar 		if (state_buf == NULL || state_ord == NULL ||
64373baed14Scanacar 		    state_cache == NULL)
64473baed14Scanacar 			err(1, "realloc");
64573baed14Scanacar 		state_buf_len = len;
64673baed14Scanacar 	}
64773baed14Scanacar }
64873baed14Scanacar 
64973baed14Scanacar int
select_states(void)65073baed14Scanacar select_states(void)
65173baed14Scanacar {
65273baed14Scanacar 	num_disp = num_states;
65373baed14Scanacar 	return (0);
65473baed14Scanacar }
65573baed14Scanacar 
65673baed14Scanacar int
read_states(void)65773baed14Scanacar read_states(void)
65873baed14Scanacar {
65973baed14Scanacar 	struct pfioc_states ps;
6604c82f412Sbluhm 	size_t n;
66173baed14Scanacar 
66273baed14Scanacar 	if (pf_dev == -1)
66373baed14Scanacar 		return -1;
66473baed14Scanacar 
66573baed14Scanacar 	for (;;) {
6664c82f412Sbluhm 		size_t sbytes = state_buf_len * sizeof(struct pfsync_state);
66773baed14Scanacar 
66873baed14Scanacar 		ps.ps_len = sbytes;
6694c82f412Sbluhm 		ps.ps_states = state_buf;
67073baed14Scanacar 
6713aaa63ebSderaadt 		if (ioctl(pf_dev, DIOCGETSTATES, &ps) == -1) {
67273baed14Scanacar 			error("DIOCGETSTATES");
67373baed14Scanacar 		}
674d93808b7Scanacar 		num_states_all = ps.ps_len / sizeof(struct pfsync_state);
67573baed14Scanacar 
67673baed14Scanacar 		if (ps.ps_len < sbytes)
67773baed14Scanacar 			break;
67873baed14Scanacar 
67973baed14Scanacar 		alloc_buf(num_states_all);
68073baed14Scanacar 	}
68173baed14Scanacar 
68273baed14Scanacar 	num_states = num_states_all;
68373baed14Scanacar 	for (n = 0; n < num_states_all; n++)
68473baed14Scanacar 		state_ord[n] = n;
68573baed14Scanacar 
68673baed14Scanacar 	if (cachestates) {
68773baed14Scanacar 		for (n = 0; n < num_states; n++)
68873baed14Scanacar 			state_cache[n] = cache_state(state_buf + n);
68973baed14Scanacar 		cache_endupdate();
69073baed14Scanacar 	}
69173baed14Scanacar 
69273baed14Scanacar 	num_disp = num_states;
69373baed14Scanacar 	return 0;
69473baed14Scanacar }
69573baed14Scanacar 
69673baed14Scanacar int
unmask(struct pf_addr * m)697eaa84e12Skn unmask(struct pf_addr * m)
69873baed14Scanacar {
699eaa84e12Skn 	int i = 31, j = 0, b = 0;
70073baed14Scanacar 	u_int32_t tmp;
70173baed14Scanacar 
702eaa84e12Skn 	while (j < 4 && m->addr32[j] == 0xffffffff) {
70373baed14Scanacar 		b += 32;
70473baed14Scanacar 		j++;
70573baed14Scanacar 	}
706eaa84e12Skn 	if (j < 4) {
70773baed14Scanacar 		tmp = ntohl(m->addr32[j]);
70873baed14Scanacar 		for (i = 31; tmp & (1 << i); --i)
70973baed14Scanacar 			b++;
71073baed14Scanacar 	}
71173baed14Scanacar 	return (b);
71273baed14Scanacar }
71373baed14Scanacar 
71473baed14Scanacar /* display functions */
71573baed14Scanacar 
71673baed14Scanacar void
tb_print_addr(struct pf_addr * addr,struct pf_addr * mask,int af)71773baed14Scanacar tb_print_addr(struct pf_addr * addr, struct pf_addr * mask, int af)
71873baed14Scanacar {
7190b1a326cSgiovanni 	switch (af) {
720*603ea060Sjsg 	case AF_INET:
7210b1a326cSgiovanni 		tbprintf("%s", inetname(addr->v4));
7220b1a326cSgiovanni 		break;
723*603ea060Sjsg 	case AF_INET6:
7240b1a326cSgiovanni 		tbprintf("%s", inet6name(&addr->v6));
7250b1a326cSgiovanni 		break;
7260b1a326cSgiovanni 	}
72773baed14Scanacar 
72873baed14Scanacar 	if (mask != NULL) {
72973baed14Scanacar 		if (!PF_AZERO(mask, af))
730eaa84e12Skn 			tbprintf("/%u", unmask(mask));
73173baed14Scanacar 	}
73273baed14Scanacar }
733d93808b7Scanacar 
73473baed14Scanacar void
print_fld_host2(field_def * fld,struct pfsync_state_key * ks,struct pfsync_state_key * kn,int idx)73573baed14Scanacar print_fld_host2(field_def *fld, struct pfsync_state_key *ks,
736d25344e8Sclaudio 		struct pfsync_state_key *kn, int idx)
73773baed14Scanacar {
73873baed14Scanacar 	struct pf_addr *as = &ks->addr[idx];
73973baed14Scanacar 	struct pf_addr *an = &kn->addr[idx];
74073baed14Scanacar 
74173baed14Scanacar 	u_int16_t ps = ntohs(ks->port[idx]);
74273baed14Scanacar 	u_int16_t pn = ntohs(kn->port[idx]);
74373baed14Scanacar 
744d25344e8Sclaudio 	int asf = ks->af;
745d25344e8Sclaudio 	int anf = kn->af;
746d25344e8Sclaudio 
74773baed14Scanacar 	if (fld == NULL)
74873baed14Scanacar 		return;
74973baed14Scanacar 
75073baed14Scanacar 	if (fld->width < 3) {
75173baed14Scanacar 		print_fld_str(fld, "*");
75273baed14Scanacar 		return;
75373baed14Scanacar 	}
75473baed14Scanacar 
75573baed14Scanacar 	tb_start();
756d25344e8Sclaudio 	tb_print_addr(as, NULL, asf);
75773baed14Scanacar 
758d25344e8Sclaudio 	if (asf == AF_INET)
75973baed14Scanacar 		tbprintf(":%u", ps);
76073baed14Scanacar 	else
76173baed14Scanacar 		tbprintf("[%u]", ps);
76273baed14Scanacar 
76373baed14Scanacar 	print_fld_tb(fld);
76473baed14Scanacar 
765d25344e8Sclaudio 	if (asf != anf || PF_ANEQ(as, an, asf) || ps != pn) {
76673baed14Scanacar 		tb_start();
767d25344e8Sclaudio 		tb_print_addr(an, NULL, anf);
76873baed14Scanacar 
769d25344e8Sclaudio 		if (anf == AF_INET)
77073baed14Scanacar 			tbprintf(":%u", pn);
77173baed14Scanacar 		else
77273baed14Scanacar 			tbprintf("[%u]", pn);
77373baed14Scanacar 		print_fld_tb(FLD_GW);
77473baed14Scanacar 	}
77573baed14Scanacar 
77673baed14Scanacar }
77773baed14Scanacar 
77873baed14Scanacar void
print_fld_state(field_def * fld,unsigned int proto,unsigned int s1,unsigned int s2)77973baed14Scanacar print_fld_state(field_def *fld, unsigned int proto,
78073baed14Scanacar 		unsigned int s1, unsigned int s2)
78173baed14Scanacar {
78273baed14Scanacar 	int len;
78373baed14Scanacar 
78473baed14Scanacar 	if (fld == NULL)
78573baed14Scanacar 		return;
78673baed14Scanacar 
78773baed14Scanacar 	len = fld->width;
78873baed14Scanacar 	if (len < 1)
78973baed14Scanacar 		return;
79073baed14Scanacar 
79173baed14Scanacar 	tb_start();
79273baed14Scanacar 
79373baed14Scanacar 	if (proto == IPPROTO_TCP) {
79473baed14Scanacar 		if (s1 <= TCPS_TIME_WAIT && s2 <= TCPS_TIME_WAIT)
79573baed14Scanacar 			tbprintf("%s:%s", tcpstates[s1], tcpstates[s2]);
79673baed14Scanacar #ifdef PF_TCPS_PROXY_SRC
79773baed14Scanacar 		else if (s1 == PF_TCPS_PROXY_SRC ||
79873baed14Scanacar 			   s2 == PF_TCPS_PROXY_SRC)
79973baed14Scanacar 			tbprintf("PROXY:SRC\n");
80073baed14Scanacar 		else if (s1 == PF_TCPS_PROXY_DST ||
80173baed14Scanacar 			 s2 == PF_TCPS_PROXY_DST)
80273baed14Scanacar 			tbprintf("PROXY:DST\n");
80373baed14Scanacar #endif
80473baed14Scanacar 		else
80573baed14Scanacar 			tbprintf("<BAD STATE LEVELS>");
80673baed14Scanacar 	} else if (proto == IPPROTO_UDP && s1 < PFUDPS_NSTATES &&
80773baed14Scanacar 		   s2 < PFUDPS_NSTATES) {
80873baed14Scanacar 		const char *states[] = PFUDPS_NAMES;
80973baed14Scanacar 		tbprintf("%s:%s", states[s1], states[s2]);
81073baed14Scanacar 	} else if (proto != IPPROTO_ICMP && s1 < PFOTHERS_NSTATES &&
81173baed14Scanacar 		   s2 < PFOTHERS_NSTATES) {
81273baed14Scanacar 		/* XXX ICMP doesn't really have state levels */
81373baed14Scanacar 		const char *states[] = PFOTHERS_NAMES;
81473baed14Scanacar 		tbprintf("%s:%s", states[s1], states[s2]);
81573baed14Scanacar 	} else {
81673baed14Scanacar 		tbprintf("%u:%u", s1, s2);
81773baed14Scanacar 	}
81873baed14Scanacar 
81973baed14Scanacar 	if (strlen(tmp_buf) > len) {
82073baed14Scanacar 		tb_start();
82173baed14Scanacar 		tbprintf("%u:%u", s1, s2);
82273baed14Scanacar 	}
82373baed14Scanacar 
82473baed14Scanacar 	print_fld_tb(fld);
82573baed14Scanacar }
82673baed14Scanacar 
82773baed14Scanacar int
print_state(struct pfsync_state * s,struct sc_ent * ent)828d93808b7Scanacar print_state(struct pfsync_state * s, struct sc_ent * ent)
82973baed14Scanacar {
830d93808b7Scanacar 	struct pfsync_state_peer *src, *dst;
83173baed14Scanacar 	struct protoent *p;
832d93808b7Scanacar 	u_int64_t sz;
833d25344e8Sclaudio 	int afto, dir;
83473baed14Scanacar 
835d25344e8Sclaudio 	afto = s->key[PF_SK_STACK].af == s->key[PF_SK_WIRE].af ? 0 : 1;
836d25344e8Sclaudio 	dir = afto ? PF_OUT : s->direction;
837d25344e8Sclaudio 
838d25344e8Sclaudio 	if (dir == PF_OUT) {
83973baed14Scanacar 		src = &s->src;
84073baed14Scanacar 		dst = &s->dst;
84173baed14Scanacar 	} else {
84273baed14Scanacar 		src = &s->dst;
84373baed14Scanacar 		dst = &s->src;
84473baed14Scanacar 	}
84573baed14Scanacar 
84673baed14Scanacar 	p = getprotobynumber(s->proto);
84773baed14Scanacar 
84873baed14Scanacar 	if (p != NULL)
84973baed14Scanacar 		print_fld_str(FLD_PROTO, p->p_name);
85073baed14Scanacar 	else
85173baed14Scanacar 		print_fld_uint(FLD_PROTO, s->proto);
85273baed14Scanacar 
853d25344e8Sclaudio 	if (dir == PF_OUT) {
854d25344e8Sclaudio 		print_fld_host2(FLD_SRC,
855d25344e8Sclaudio 		    &s->key[afto ? PF_SK_STACK : PF_SK_WIRE],
856d25344e8Sclaudio 		    &s->key[PF_SK_STACK], 1);
857d25344e8Sclaudio 		print_fld_host2(FLD_DEST,
858d25344e8Sclaudio 		    &s->key[afto ? PF_SK_STACK : PF_SK_WIRE],
859d25344e8Sclaudio 		    &s->key[afto ? PF_SK_WIRE : PF_SK_STACK], 0);
86073baed14Scanacar 	} else {
86173baed14Scanacar 		print_fld_host2(FLD_SRC, &s->key[PF_SK_STACK],
862d25344e8Sclaudio 		    &s->key[PF_SK_WIRE], 0);
86373baed14Scanacar 		print_fld_host2(FLD_DEST, &s->key[PF_SK_STACK],
864d25344e8Sclaudio 		    &s->key[PF_SK_WIRE], 1);
86573baed14Scanacar 	}
86673baed14Scanacar 
867d25344e8Sclaudio 	if (dir == PF_OUT)
86873baed14Scanacar 		print_fld_str(FLD_DIR, "Out");
86973baed14Scanacar 	else
87073baed14Scanacar 		print_fld_str(FLD_DIR, "In");
87173baed14Scanacar 
87273baed14Scanacar 	print_fld_state(FLD_STATE, s->proto, src->state, dst->state);
873d20a4fd2Smcbride 	print_fld_age(FLD_AGE, ntohl(s->creation));
874d20a4fd2Smcbride 	print_fld_age(FLD_EXP, ntohl(s->expire));
875d93808b7Scanacar 
876d93808b7Scanacar 	sz = COUNTER(s->bytes[0]) + COUNTER(s->bytes[1]);
87773baed14Scanacar 
87873baed14Scanacar 	print_fld_size(FLD_PKTS, COUNTER(s->packets[0]) +
87973baed14Scanacar 		       COUNTER(s->packets[1]));
88073baed14Scanacar 	print_fld_size(FLD_BYTES, sz);
881d20a4fd2Smcbride 	print_fld_rate(FLD_SA, (s->creation) ?
8825ddc7cc1Scanacar 		       ((double)sz/(double)ntohl(s->creation)) : -1);
88373baed14Scanacar 
8844d6ee8b4Scanacar 	print_fld_uint(FLD_RULE, ntohl(s->rule));
88573baed14Scanacar 	if (cachestates && ent != NULL) {
88673baed14Scanacar 		print_fld_rate(FLD_SI, ent->rate);
88773baed14Scanacar 		print_fld_rate(FLD_SP, ent->peak);
88873baed14Scanacar 	}
88973baed14Scanacar 
89073baed14Scanacar 	end_line();
89173baed14Scanacar 	return 1;
89273baed14Scanacar }
89373baed14Scanacar 
89473baed14Scanacar void
print_states(void)89573baed14Scanacar print_states(void)
89673baed14Scanacar {
89773baed14Scanacar 	int n, count = 0;
89873baed14Scanacar 
89973baed14Scanacar 	for (n = dispstart; n < num_disp; n++) {
90073baed14Scanacar 		count += print_state(state_buf + state_ord[n],
90173baed14Scanacar 				     state_cache[state_ord[n]]);
90273baed14Scanacar 		if (maxprint > 0 && count >= maxprint)
90373baed14Scanacar 			break;
90473baed14Scanacar 	}
90573baed14Scanacar }
90673baed14Scanacar 
90773baed14Scanacar /* rule display */
90873baed14Scanacar 
90973baed14Scanacar struct pf_rule *rules = NULL;
91073baed14Scanacar u_int32_t alloc_rules = 0;
91173baed14Scanacar 
91273baed14Scanacar int
select_rules(void)91373baed14Scanacar select_rules(void)
91473baed14Scanacar {
91573baed14Scanacar 	num_disp = num_rules;
91673baed14Scanacar 	return (0);
91773baed14Scanacar }
91873baed14Scanacar 
91973baed14Scanacar 
92073baed14Scanacar void
add_rule_alloc(u_int32_t nr)92173baed14Scanacar add_rule_alloc(u_int32_t nr)
92273baed14Scanacar {
92373baed14Scanacar 	if (nr == 0)
92473baed14Scanacar 		return;
92573baed14Scanacar 
92673baed14Scanacar 	num_rules += nr;
92773baed14Scanacar 
92873baed14Scanacar 	if (rules == NULL) {
9292daca27aSdoug 		rules = reallocarray(NULL, num_rules, sizeof(struct pf_rule));
93073baed14Scanacar 		if (rules == NULL)
93173baed14Scanacar 			err(1, "malloc");
93273baed14Scanacar 		alloc_rules = num_rules;
93373baed14Scanacar 	} else if (num_rules > alloc_rules) {
9342daca27aSdoug 		rules = reallocarray(rules, num_rules, sizeof(struct pf_rule));
93573baed14Scanacar 		if (rules == NULL)
93673baed14Scanacar 			err(1, "realloc");
93773baed14Scanacar 		alloc_rules = num_rules;
93873baed14Scanacar 	}
93973baed14Scanacar }
94073baed14Scanacar 
94173baed14Scanacar int label_length;
94273baed14Scanacar 
943d2364f60Ssashan void
close_pf_trans(u_int32_t ticket)944d2364f60Ssashan close_pf_trans(u_int32_t ticket)
945d2364f60Ssashan {
946d2364f60Ssashan 	if (ioctl(pf_dev, DIOCXEND, &ticket) == -1)
947d2364f60Ssashan 		error("DIOCXEND: %s", strerror(errno));
948d2364f60Ssashan }
949d2364f60Ssashan 
95073baed14Scanacar int
read_anchor_rules(char * anchor)95173baed14Scanacar read_anchor_rules(char *anchor)
95273baed14Scanacar {
95373baed14Scanacar 	struct pfioc_rule pr;
95473baed14Scanacar 	u_int32_t nr, num, off;
955d93808b7Scanacar 	int len;
95673baed14Scanacar 
95773baed14Scanacar 	if (pf_dev < 0)
95873baed14Scanacar 		return (-1);
95973baed14Scanacar 
96073baed14Scanacar 	memset(&pr, 0, sizeof(pr));
96173baed14Scanacar 	strlcpy(pr.anchor, anchor, sizeof(pr.anchor));
962d93808b7Scanacar 
9633aaa63ebSderaadt 	if (ioctl(pf_dev, DIOCGETRULES, &pr) == -1) {
96473baed14Scanacar 		error("anchor %s: %s", anchor, strerror(errno));
96573baed14Scanacar 		return (-1);
96673baed14Scanacar 	}
96773baed14Scanacar 
96873baed14Scanacar 	off = num_rules;
96973baed14Scanacar 	num = pr.nr;
97073baed14Scanacar 	add_rule_alloc(num);
97173baed14Scanacar 
97273baed14Scanacar 	for (nr = 0; nr < num; ++nr) {
97373baed14Scanacar 		pr.nr = nr;
9743aaa63ebSderaadt 		if (ioctl(pf_dev, DIOCGETRULE, &pr) == -1) {
97573baed14Scanacar 			error("DIOCGETRULE: %s", strerror(errno));
976d2364f60Ssashan 			close_pf_trans(pr.ticket);
97773baed14Scanacar 			return (-1);
97873baed14Scanacar 		}
97973baed14Scanacar 		/* XXX overload pr.anchor, to store a pointer to
98073baed14Scanacar 		 * anchor name */
98173baed14Scanacar 		pr.rule.anchor = (struct pf_anchor *) anchor;
982d93808b7Scanacar 		len = strlen(pr.rule.label);
98373baed14Scanacar 		if (len > label_length)
98473baed14Scanacar 			label_length = len;
98573baed14Scanacar 		rules[off + nr] = pr.rule;
98673baed14Scanacar 	}
98773baed14Scanacar 
988d2364f60Ssashan 	close_pf_trans(pr.ticket);
989d2364f60Ssashan 
99073baed14Scanacar 	return (num);
99173baed14Scanacar }
99273baed14Scanacar 
99373baed14Scanacar struct anchor_name {
9948f6b3bafSderaadt 	char name[PATH_MAX];
99573baed14Scanacar 	struct anchor_name *next;
99673baed14Scanacar 	u_int32_t ref;
99773baed14Scanacar };
99873baed14Scanacar 
99973baed14Scanacar struct anchor_name *anchor_root = NULL;
100073baed14Scanacar struct anchor_name *anchor_end = NULL;
100173baed14Scanacar struct anchor_name *anchor_free = NULL;
100273baed14Scanacar 
100373baed14Scanacar struct anchor_name*
alloc_anchor_name(const char * path)100473baed14Scanacar alloc_anchor_name(const char *path)
100573baed14Scanacar {
100673baed14Scanacar 	struct anchor_name *a;
100773baed14Scanacar 
100873baed14Scanacar 	a = anchor_free;
100973baed14Scanacar 	if (a == NULL) {
1010cfff592fSderaadt 		a = malloc(sizeof(struct anchor_name));
101173baed14Scanacar 		if (a == NULL)
101273baed14Scanacar 			return (NULL);
101373baed14Scanacar 	} else
101473baed14Scanacar 		anchor_free = a->next;
101573baed14Scanacar 
101673baed14Scanacar 	if (anchor_root == NULL)
101773baed14Scanacar 		anchor_end = a;
101873baed14Scanacar 
101973baed14Scanacar 	a->next = anchor_root;
102073baed14Scanacar 	anchor_root = a;
102173baed14Scanacar 
102273baed14Scanacar 	a->ref = 0;
102373baed14Scanacar 	strlcpy(a->name, path, sizeof(a->name));
102473baed14Scanacar 	return (a);
102573baed14Scanacar }
102673baed14Scanacar 
102773baed14Scanacar void
reset_anchor_names(void)102873baed14Scanacar reset_anchor_names(void)
102973baed14Scanacar {
103073baed14Scanacar 	if (anchor_end == NULL)
103173baed14Scanacar 		return;
103273baed14Scanacar 
103373baed14Scanacar 	anchor_end->next = anchor_free;
103473baed14Scanacar 	anchor_free = anchor_root;
103573baed14Scanacar 	anchor_root = anchor_end = NULL;
103673baed14Scanacar }
103773baed14Scanacar 
103873baed14Scanacar struct pfioc_ruleset ruleset;
103973baed14Scanacar char *rs_end = NULL;
104073baed14Scanacar 
104173baed14Scanacar int
read_rulesets(const char * path)104273baed14Scanacar read_rulesets(const char *path)
104373baed14Scanacar {
104473baed14Scanacar 	char *pre;
104573baed14Scanacar 	struct anchor_name *a;
104673baed14Scanacar 	u_int32_t nr, ns;
104773baed14Scanacar 	int len;
104873baed14Scanacar 
104973baed14Scanacar 	if (path == NULL)
105073baed14Scanacar 		ruleset.path[0] = '\0';
105173baed14Scanacar 	else if (strlcpy(ruleset.path, path, sizeof(ruleset.path)) >=
105273baed14Scanacar 	    sizeof(ruleset.path))
105373baed14Scanacar 		 return (-1);
105473baed14Scanacar 
105573baed14Scanacar 	/* a persistent storage for anchor names */
105673baed14Scanacar 	a = alloc_anchor_name(ruleset.path);
105773baed14Scanacar 	if (a == NULL)
105873baed14Scanacar 		return (-1);
105973baed14Scanacar 
106073baed14Scanacar 	len = read_anchor_rules(a->name);
106173baed14Scanacar 	if (len < 0)
106273baed14Scanacar 		return (-1);
106373baed14Scanacar 
106473baed14Scanacar 	a->ref += len;
106573baed14Scanacar 
10663aaa63ebSderaadt 	if (ioctl(pf_dev, DIOCGETRULESETS, &ruleset) == -1) {
106773baed14Scanacar 		error("DIOCGETRULESETS: %s", strerror(errno));
106873baed14Scanacar 		return (-1);
106973baed14Scanacar 	}
107073baed14Scanacar 
107173baed14Scanacar 	ns = ruleset.nr;
107273baed14Scanacar 
107373baed14Scanacar 	if (rs_end == NULL)
107473baed14Scanacar 		rs_end = ruleset.path + sizeof(ruleset.path);
107573baed14Scanacar 
107673baed14Scanacar 	/* 'pre' tracks the previous level on the anchor */
107773baed14Scanacar 	pre = strchr(ruleset.path, 0);
107873baed14Scanacar 	len = rs_end - pre;
107973baed14Scanacar 	if (len < 1)
108073baed14Scanacar 		return (-1);
108173baed14Scanacar 	--len;
108273baed14Scanacar 
108373baed14Scanacar 	for (nr = 0; nr < ns; ++nr) {
108473baed14Scanacar 		ruleset.nr = nr;
10853aaa63ebSderaadt 		if (ioctl(pf_dev, DIOCGETRULESET, &ruleset) == -1) {
108673baed14Scanacar 			error("DIOCGETRULESET: %s", strerror(errno));
108773baed14Scanacar 			return (-1);
108873baed14Scanacar 		}
108973baed14Scanacar 		*pre = '/';
109073baed14Scanacar 		if (strlcpy(pre + 1, ruleset.name, len) < len)
109173baed14Scanacar 			read_rulesets(ruleset.path);
109273baed14Scanacar 		*pre = '\0';
109373baed14Scanacar 	}
109473baed14Scanacar 
109573baed14Scanacar 	return (0);
109673baed14Scanacar }
109773baed14Scanacar 
109873baed14Scanacar void
compute_anchor_field(void)109973baed14Scanacar compute_anchor_field(void)
110073baed14Scanacar {
110173baed14Scanacar 	struct anchor_name *a;
110273baed14Scanacar 	int sum, cnt, mx, nx;
110373baed14Scanacar 	sum = cnt = mx = 0;
110473baed14Scanacar 
110573baed14Scanacar 	for (a = anchor_root; a != NULL; a = a->next, cnt++) {
110673baed14Scanacar 		int len;
110773baed14Scanacar 		if (a->ref == 0)
110873baed14Scanacar 			continue;
110973baed14Scanacar 		len = strlen(a->name);
111073baed14Scanacar 		sum += len;
111173baed14Scanacar 		if (len > mx)
111273baed14Scanacar 			mx = len;
111373baed14Scanacar 	}
111473baed14Scanacar 
111573baed14Scanacar 	nx = sum/cnt;
111673baed14Scanacar 	if (nx < ANCHOR_FLD_SIZE)
111773baed14Scanacar 		nx = (mx < ANCHOR_FLD_SIZE) ? mx : ANCHOR_FLD_SIZE;
111873baed14Scanacar 
111973baed14Scanacar 	if (FLD_ANCHOR->max_width != mx ||
112073baed14Scanacar 	    FLD_ANCHOR->norm_width != nx) {
112173baed14Scanacar 		FLD_ANCHOR->max_width = mx;
112273baed14Scanacar 		FLD_ANCHOR->norm_width = nx;
112373baed14Scanacar 		field_setup();
112473baed14Scanacar 		need_update = 1;
112573baed14Scanacar 	}
112673baed14Scanacar }
112773baed14Scanacar 
112873baed14Scanacar int
read_rules(void)112973baed14Scanacar read_rules(void)
113073baed14Scanacar {
1131d93808b7Scanacar 	int ret, nw, mw;
113273baed14Scanacar 	num_rules = 0;
113373baed14Scanacar 
113473baed14Scanacar 	if (pf_dev == -1)
113573baed14Scanacar 		return (-1);
113673baed14Scanacar 
113773baed14Scanacar 	label_length = MIN_LABEL_SIZE;
113873baed14Scanacar 
113973baed14Scanacar 	reset_anchor_names();
114073baed14Scanacar 	ret = read_rulesets(NULL);
114173baed14Scanacar 	compute_anchor_field();
114273baed14Scanacar 
114373baed14Scanacar 	nw = mw = label_length;
114473baed14Scanacar 	if (nw > 16)
114573baed14Scanacar 		nw = 16;
114673baed14Scanacar 
114773baed14Scanacar 	if (FLD_LABEL->norm_width != nw ||
114873baed14Scanacar 	    FLD_LABEL->max_width != mw) {
114973baed14Scanacar 		FLD_LABEL->norm_width = nw;
115073baed14Scanacar 		FLD_LABEL->max_width = mw;
115173baed14Scanacar 		field_setup();
115273baed14Scanacar 		need_update = 1;
115373baed14Scanacar 	}
115473baed14Scanacar 
115573baed14Scanacar 	num_disp = num_rules;
115673baed14Scanacar 	return (ret);
115773baed14Scanacar }
115873baed14Scanacar 
115973baed14Scanacar void
tb_print_addrw(struct pf_addr_wrap * addr,struct pf_addr * mask,u_int8_t af)116073baed14Scanacar tb_print_addrw(struct pf_addr_wrap *addr, struct pf_addr *mask, u_int8_t af)
116173baed14Scanacar {
116273baed14Scanacar 	switch (addr->type) {
116373baed14Scanacar 	case PF_ADDR_ADDRMASK:
116473baed14Scanacar 		tb_print_addr(&addr->v.a.addr, mask, af);
116573baed14Scanacar 		break;
116673baed14Scanacar 	case  PF_ADDR_NOROUTE:
116773baed14Scanacar 		tbprintf("noroute");
116873baed14Scanacar 		break;
116973baed14Scanacar 	case PF_ADDR_DYNIFTL:
117073baed14Scanacar 		tbprintf("(%s)", addr->v.ifname);
117173baed14Scanacar 		break;
117273baed14Scanacar 	case PF_ADDR_TABLE:
117373baed14Scanacar 		tbprintf("<%s>", addr->v.tblname);
117473baed14Scanacar 		break;
117573baed14Scanacar 	default:
117673baed14Scanacar 		tbprintf("UNKNOWN");
117773baed14Scanacar 		break;
117873baed14Scanacar 	}
117973baed14Scanacar }
118073baed14Scanacar 
118173baed14Scanacar void
tb_print_op(u_int8_t op,const char * a1,const char * a2)118273baed14Scanacar tb_print_op(u_int8_t op, const char *a1, const char *a2)
118373baed14Scanacar {
118473baed14Scanacar 	if (op == PF_OP_IRG)
118573baed14Scanacar 		tbprintf("%s >< %s ", a1, a2);
118673baed14Scanacar 	else if (op == PF_OP_XRG)
118773baed14Scanacar 		tbprintf("%s <> %s ", a1, a2);
118873baed14Scanacar 	else if (op == PF_OP_RRG)
118973baed14Scanacar 		tbprintf("%s:%s ", a1, a2);
119073baed14Scanacar 	else if (op == PF_OP_EQ)
119173baed14Scanacar 		tbprintf("= %s ", a1);
119273baed14Scanacar 	else if (op == PF_OP_NE)
119373baed14Scanacar 		tbprintf("!= %s ", a1);
119473baed14Scanacar 	else if (op == PF_OP_LT)
119573baed14Scanacar 		tbprintf("< %s ", a1);
119673baed14Scanacar 	else if (op == PF_OP_LE)
119773baed14Scanacar 		tbprintf("<= %s ", a1);
119873baed14Scanacar 	else if (op == PF_OP_GT)
119973baed14Scanacar 		tbprintf("> %s ", a1);
120073baed14Scanacar 	else if (op == PF_OP_GE)
120173baed14Scanacar 		tbprintf(">= %s ", a1);
120273baed14Scanacar }
120373baed14Scanacar 
120473baed14Scanacar void
tb_print_port(u_int8_t op,u_int16_t p1,u_int16_t p2,char * proto)120573baed14Scanacar tb_print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, char *proto)
120673baed14Scanacar {
120773baed14Scanacar 	char a1[6], a2[6];
120873baed14Scanacar 	struct servent *s = getservbyport(p1, proto);
120973baed14Scanacar 
121073baed14Scanacar 	p1 = ntohs(p1);
121173baed14Scanacar 	p2 = ntohs(p2);
121273baed14Scanacar 	snprintf(a1, sizeof(a1), "%u", p1);
121373baed14Scanacar 	snprintf(a2, sizeof(a2), "%u", p2);
121473baed14Scanacar 	tbprintf("port ");
121573baed14Scanacar 	if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
121673baed14Scanacar 		tb_print_op(op, s->s_name, a2);
121773baed14Scanacar 	else
121873baed14Scanacar 		tb_print_op(op, a1, a2);
121973baed14Scanacar }
122073baed14Scanacar 
122173baed14Scanacar void
tb_print_fromto(struct pf_rule_addr * src,struct pf_rule_addr * dst,u_int8_t af,u_int8_t proto)122273baed14Scanacar tb_print_fromto(struct pf_rule_addr *src, struct pf_rule_addr *dst,
122373baed14Scanacar 		u_int8_t af, u_int8_t proto)
122473baed14Scanacar {
122573baed14Scanacar 	if (
122673baed14Scanacar 	    PF_AZERO(PT_ADDR(src), AF_INET6) &&
122773baed14Scanacar 	    PF_AZERO(PT_ADDR(dst), AF_INET6) &&
122873baed14Scanacar 	    ! PT_NOROUTE(src) && ! PT_NOROUTE(dst) &&
122973baed14Scanacar 	    PF_AZERO(PT_MASK(src), AF_INET6) &&
123073baed14Scanacar 	    PF_AZERO(PT_MASK(dst), AF_INET6) &&
123173baed14Scanacar 	    !src->port_op && !dst->port_op)
123273baed14Scanacar 		tbprintf("all ");
123373baed14Scanacar 	else {
123473baed14Scanacar 		tbprintf("from ");
123573baed14Scanacar 		if (PT_NOROUTE(src))
123673baed14Scanacar 			tbprintf("no-route ");
123773baed14Scanacar 		else if (PF_AZERO(PT_ADDR(src), AF_INET6) &&
123873baed14Scanacar 			 PF_AZERO(PT_MASK(src), AF_INET6))
123973baed14Scanacar 			tbprintf("any ");
124073baed14Scanacar 		else {
124173baed14Scanacar 			if (src->neg)
124273baed14Scanacar 				tbprintf("! ");
124373baed14Scanacar 			tb_print_addrw(&src->addr, PT_MASK(src), af);
124473baed14Scanacar 			tbprintf(" ");
124573baed14Scanacar 		}
124673baed14Scanacar 		if (src->port_op)
124773baed14Scanacar 			tb_print_port(src->port_op, src->port[0],
124873baed14Scanacar 				      src->port[1],
124973baed14Scanacar 				      proto == IPPROTO_TCP ? "tcp" : "udp");
125073baed14Scanacar 
125173baed14Scanacar 		tbprintf("to ");
125273baed14Scanacar 		if (PT_NOROUTE(dst))
125373baed14Scanacar 			tbprintf("no-route ");
125473baed14Scanacar 		else if (PF_AZERO(PT_ADDR(dst), AF_INET6) &&
125573baed14Scanacar 			 PF_AZERO(PT_MASK(dst), AF_INET6))
125673baed14Scanacar 			tbprintf("any ");
125773baed14Scanacar 		else {
125873baed14Scanacar 			if (dst->neg)
125973baed14Scanacar 				tbprintf("! ");
126073baed14Scanacar 			tb_print_addrw(&dst->addr, PT_MASK(dst), af);
126173baed14Scanacar 			tbprintf(" ");
126273baed14Scanacar 		}
126373baed14Scanacar 		if (dst->port_op)
126473baed14Scanacar 			tb_print_port(dst->port_op, dst->port[0],
126573baed14Scanacar 				      dst->port[1],
126673baed14Scanacar 				      proto == IPPROTO_TCP ? "tcp" : "udp");
126773baed14Scanacar 	}
126873baed14Scanacar }
126973baed14Scanacar 
127073baed14Scanacar void
tb_print_ugid(u_int8_t op,id_t i1,id_t i2,const char * t)1271b4de0548Smillert tb_print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t)
127273baed14Scanacar {
127373baed14Scanacar 	char	a1[11], a2[11];
127473baed14Scanacar 
1275b4de0548Smillert 	snprintf(a1, sizeof(a1), "%u", i1);
1276b4de0548Smillert 	snprintf(a2, sizeof(a2), "%u", i2);
127773baed14Scanacar 
127873baed14Scanacar 	tbprintf("%s ", t);
1279b4de0548Smillert 	if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE))
128073baed14Scanacar 		tb_print_op(op, "unknown", a2);
128173baed14Scanacar 	else
128273baed14Scanacar 		tb_print_op(op, a1, a2);
128373baed14Scanacar }
128473baed14Scanacar 
128573baed14Scanacar void
tb_print_flags(u_int8_t f)128673baed14Scanacar tb_print_flags(u_int8_t f)
128773baed14Scanacar {
128873baed14Scanacar 	const char *tcpflags = "FSRPAUEW";
128973baed14Scanacar 	int i;
129073baed14Scanacar 
129173baed14Scanacar 	for (i = 0; tcpflags[i]; ++i)
129273baed14Scanacar 		if (f & (1 << i))
129373baed14Scanacar 			tbprintf("%c", tcpflags[i]);
129473baed14Scanacar }
129573baed14Scanacar 
129673baed14Scanacar void
print_rule(struct pf_rule * pr)129773baed14Scanacar print_rule(struct pf_rule *pr)
129873baed14Scanacar {
1299af821ee0Shenning 	static const char *actiontypes[] = { "Pass", "Block", "Scrub",
1300af821ee0Shenning 	    "no Scrub", "Nat", "no Nat", "Binat", "no Binat", "Rdr",
1301af821ee0Shenning 	    "no Rdr", "SynProxy Block", "Defer", "Match" };
130273baed14Scanacar 	int numact = sizeof(actiontypes) / sizeof(char *);
130373baed14Scanacar 
130473baed14Scanacar 	static const char *routetypes[] = { "", "fastroute", "route-to",
130573baed14Scanacar 	    "dup-to", "reply-to" };
130673baed14Scanacar 
130773baed14Scanacar 	int numroute = sizeof(routetypes) / sizeof(char *);
130873baed14Scanacar 
130973baed14Scanacar 	if (pr == NULL) return;
131073baed14Scanacar 
131173baed14Scanacar 	print_fld_str(FLD_LABEL, pr->label);
131273baed14Scanacar 	print_fld_size(FLD_STATS, pr->states_tot);
131373baed14Scanacar 
131473baed14Scanacar 	print_fld_size(FLD_PKTS, pr->packets[0] + pr->packets[1]);
131573baed14Scanacar 	print_fld_size(FLD_BYTES, pr->bytes[0] + pr->bytes[1]);
1316d93808b7Scanacar 
131773baed14Scanacar 	print_fld_uint(FLD_RULE, pr->nr);
13187c6304b1Ssthen 	if (pr->direction == PF_OUT)
13197c6304b1Ssthen 		print_fld_str(FLD_DIR, "Out");
13207c6304b1Ssthen 	else if (pr->direction == PF_IN)
13217c6304b1Ssthen 		print_fld_str(FLD_DIR, "In");
13227c6304b1Ssthen 	else
13237c6304b1Ssthen 		print_fld_str(FLD_DIR, "Any");
13247c6304b1Ssthen 
132573baed14Scanacar 	if (pr->quick)
132673baed14Scanacar 		print_fld_str(FLD_QUICK, "Quick");
132773baed14Scanacar 
132873baed14Scanacar 	if (pr->keep_state == PF_STATE_NORMAL)
132973baed14Scanacar 		print_fld_str(FLD_KST, "Keep");
133073baed14Scanacar 	else if (pr->keep_state == PF_STATE_MODULATE)
133173baed14Scanacar 		print_fld_str(FLD_KST, "Mod");
13322b0241cfSjsg 	else if (pr->keep_state == PF_STATE_SYNPROXY)
133373baed14Scanacar 		print_fld_str(FLD_KST, "Syn");
133473baed14Scanacar 	if (pr->log == 1)
133573baed14Scanacar 		print_fld_str(FLD_LOG, "Log");
133673baed14Scanacar 	else if (pr->log == 2)
133773baed14Scanacar 		print_fld_str(FLD_LOG, "All");
133873baed14Scanacar 
1339d693a71aScanacar 	if (pr->action >= numact)
134073baed14Scanacar 		print_fld_uint(FLD_ACTION, pr->action);
134173baed14Scanacar 	else print_fld_str(FLD_ACTION, actiontypes[pr->action]);
1342d693a71aScanacar 
134373baed14Scanacar 	if (pr->proto) {
134473baed14Scanacar 		struct protoent *p = getprotobynumber(pr->proto);
134573baed14Scanacar 
134673baed14Scanacar 		if (p != NULL)
134773baed14Scanacar 			print_fld_str(FLD_PROTO, p->p_name);
134873baed14Scanacar 		else
134973baed14Scanacar 			print_fld_uint(FLD_PROTO, pr->proto);
135073baed14Scanacar 	}
135173baed14Scanacar 
135273baed14Scanacar 	if (pr->ifname[0]) {
135373baed14Scanacar 		tb_start();
135473baed14Scanacar 		if (pr->ifnot)
135573baed14Scanacar 			tbprintf("!");
135673baed14Scanacar 		tbprintf("%s", pr->ifname);
135773baed14Scanacar 		print_fld_tb(FLD_IF);
135873baed14Scanacar 	}
135973baed14Scanacar 	if (pr->max_states)
136073baed14Scanacar 		print_fld_uint(FLD_STMAX, pr->max_states);
1361d93808b7Scanacar 
136273baed14Scanacar 	/* print info field */
136373baed14Scanacar 
136473baed14Scanacar 	tb_start();
136573baed14Scanacar 
136673baed14Scanacar 	if (pr->action == PF_DROP) {
136773baed14Scanacar 		if (pr->rule_flag & PFRULE_RETURNRST)
136873baed14Scanacar 			tbprintf("return-rst ");
136973baed14Scanacar #ifdef PFRULE_RETURN
137073baed14Scanacar 		else if (pr->rule_flag & PFRULE_RETURN)
137173baed14Scanacar 			tbprintf("return ");
137273baed14Scanacar #endif
137373baed14Scanacar #ifdef PFRULE_RETURNICMP
137473baed14Scanacar 		else if (pr->rule_flag & PFRULE_RETURNICMP)
137573baed14Scanacar 			tbprintf("return-icmp ");
137673baed14Scanacar #endif
137773baed14Scanacar 		else
137873baed14Scanacar 			tbprintf("drop ");
137973baed14Scanacar 	}
138073baed14Scanacar 
138173baed14Scanacar 	if (pr->rt > 0 && pr->rt < numroute) {
138273baed14Scanacar 		tbprintf("%s ", routetypes[pr->rt]);
138373baed14Scanacar 	}
1384d93808b7Scanacar 
138573baed14Scanacar 	if (pr->af) {
138673baed14Scanacar 		if (pr->af == AF_INET)
138773baed14Scanacar 			tbprintf("inet ");
138873baed14Scanacar 		else
138973baed14Scanacar 			tbprintf("inet6 ");
139073baed14Scanacar 	}
139173baed14Scanacar 
139273baed14Scanacar 	tb_print_fromto(&pr->src, &pr->dst, pr->af, pr->proto);
1393d93808b7Scanacar 
139473baed14Scanacar 	if (pr->uid.op)
139573baed14Scanacar 		tb_print_ugid(pr->uid.op, pr->uid.uid[0], pr->uid.uid[1],
1396b4de0548Smillert 		        "user");
139773baed14Scanacar 	if (pr->gid.op)
139873baed14Scanacar 		tb_print_ugid(pr->gid.op, pr->gid.gid[0], pr->gid.gid[1],
1399b4de0548Smillert 		        "group");
140073baed14Scanacar 
140126f2f421Smcbride 	if (pr->action == PF_PASS &&
140226f2f421Smcbride 	    (pr->proto == 0 || pr->proto == IPPROTO_TCP) &&
140326f2f421Smcbride 	    (pr->flags != TH_SYN || pr->flagset != (TH_SYN | TH_ACK) )) {
140473baed14Scanacar 		tbprintf("flags ");
140526f2f421Smcbride 		if (pr->flags || pr->flagset) {
140673baed14Scanacar 			tb_print_flags(pr->flags);
140773baed14Scanacar 			tbprintf("/");
140873baed14Scanacar 			tb_print_flags(pr->flagset);
140926f2f421Smcbride 		} else
141026f2f421Smcbride 			tbprintf("any ");
141173baed14Scanacar 	}
141273baed14Scanacar 
141373baed14Scanacar 	tbprintf(" ");
141473baed14Scanacar 
141573baed14Scanacar 	if (pr->tos)
141673baed14Scanacar 		tbprintf("tos 0x%2.2x ", pr->tos);
141773baed14Scanacar #ifdef PFRULE_FRAGMENT
141873baed14Scanacar 	if (pr->rule_flag & PFRULE_FRAGMENT)
141973baed14Scanacar 		tbprintf("fragment ");
142073baed14Scanacar #endif
142173baed14Scanacar #ifdef PFRULE_NODF
142273baed14Scanacar 	if (pr->rule_flag & PFRULE_NODF)
142373baed14Scanacar 		tbprintf("no-df ");
142473baed14Scanacar #endif
142573baed14Scanacar #ifdef PFRULE_RANDOMID
142673baed14Scanacar 	if (pr->rule_flag & PFRULE_RANDOMID)
142773baed14Scanacar 		tbprintf("random-id ");
142873baed14Scanacar #endif
142973baed14Scanacar 	if (pr->min_ttl)
143073baed14Scanacar 		tbprintf("min-ttl %d ", pr->min_ttl);
143173baed14Scanacar 	if (pr->max_mss)
143273baed14Scanacar 		tbprintf("max-mss %d ", pr->max_mss);
143373baed14Scanacar 	if (pr->allow_opts)
143473baed14Scanacar 		tbprintf("allow-opts ");
143573baed14Scanacar 
143660e2494dShenning 	/* XXX more missing */
143773baed14Scanacar 
143873baed14Scanacar 	if (pr->qname[0] && pr->pqname[0])
143973baed14Scanacar 		tbprintf("queue(%s, %s) ", pr->qname, pr->pqname);
144073baed14Scanacar 	else if (pr->qname[0])
144173baed14Scanacar 		tbprintf("queue %s ", pr->qname);
1442d93808b7Scanacar 
144373baed14Scanacar 	if (pr->tagname[0])
144473baed14Scanacar 		tbprintf("tag %s ", pr->tagname);
144573baed14Scanacar 	if (pr->match_tagname[0]) {
144673baed14Scanacar 		if (pr->match_tag_not)
144773baed14Scanacar 			tbprintf("! ");
144873baed14Scanacar 		tbprintf("tagged %s ", pr->match_tagname);
144973baed14Scanacar 	}
1450d93808b7Scanacar 
145173baed14Scanacar 	print_fld_tb(FLD_RINFO);
145273baed14Scanacar 
145373baed14Scanacar 	/* XXX anchor field overloaded with anchor name */
145473baed14Scanacar 	print_fld_str(FLD_ANCHOR, (char *)pr->anchor);
145573baed14Scanacar 	tb_end();
145673baed14Scanacar 
145773baed14Scanacar 	end_line();
145873baed14Scanacar }
145973baed14Scanacar 
146073baed14Scanacar void
print_rules(void)146173baed14Scanacar print_rules(void)
146273baed14Scanacar {
146373baed14Scanacar 	u_int32_t n, count = 0;
146473baed14Scanacar 
146573baed14Scanacar 	for (n = dispstart; n < num_rules; n++) {
146673baed14Scanacar 		print_rule(rules + n);
146773baed14Scanacar 		count ++;
146873baed14Scanacar 		if (maxprint > 0 && count >= maxprint)
146973baed14Scanacar 			break;
147073baed14Scanacar 	}
147173baed14Scanacar }
147273baed14Scanacar 
147373baed14Scanacar /* queue display */
1474aa14b181Shenning struct pfctl_queue_node *
pfctl_find_queue_node(const char * qname,const char * ifname)1475aa14b181Shenning pfctl_find_queue_node(const char *qname, const char *ifname)
1476aa14b181Shenning {
1477aa14b181Shenning 	struct pfctl_queue_node	*node;
1478aa14b181Shenning 
1479aa14b181Shenning 	TAILQ_FOREACH(node, &qnodes, entries)
1480aa14b181Shenning 		if (!strcmp(node->qs.qname, qname)
1481aa14b181Shenning 		    && !(strcmp(node->qs.ifname, ifname)))
1482aa14b181Shenning 			return (node);
1483aa14b181Shenning 	return (NULL);
1484aa14b181Shenning }
1485aa14b181Shenning 
1486aa14b181Shenning void
pfctl_insert_queue_node(const struct pf_queuespec qs,const struct queue_stats qstats)1487aa14b181Shenning pfctl_insert_queue_node(const struct pf_queuespec qs,
1488aa14b181Shenning     const struct queue_stats qstats)
1489aa14b181Shenning {
1490aa14b181Shenning 	struct pfctl_queue_node	*node, *parent;
1491aa14b181Shenning 
1492aa14b181Shenning 	node = calloc(1, sizeof(struct pfctl_queue_node));
1493aa14b181Shenning 	if (node == NULL)
1494aa14b181Shenning 		err(1, "pfctl_insert_queue_node: calloc");
1495aa14b181Shenning 	memcpy(&node->qs, &qs, sizeof(qs));
1496aa14b181Shenning 	memcpy(&node->qstats, &qstats, sizeof(qstats));
1497aa14b181Shenning 
1498aa14b181Shenning 	if (node->qs.parent[0]) {
1499aa14b181Shenning 		parent = pfctl_find_queue_node(node->qs.parent,
1500aa14b181Shenning 		    node->qs.ifname);
1501aa14b181Shenning 		if (parent)
1502aa14b181Shenning 			node->depth = parent->depth + 1;
1503aa14b181Shenning 	}
1504aa14b181Shenning 
1505aa14b181Shenning 	TAILQ_INSERT_TAIL(&qnodes, node, entries);
1506aa14b181Shenning }
1507aa14b181Shenning 
150873baed14Scanacar int
pfctl_update_qstats(void)1509aa14b181Shenning pfctl_update_qstats(void)
1510aa14b181Shenning {
1511aa14b181Shenning 	struct pfctl_queue_node	*node;
1512aa14b181Shenning 	struct pfioc_queue	 pq;
1513aa14b181Shenning 	struct pfioc_qstats	 pqs;
1514aa14b181Shenning 	u_int32_t		 mnr, nr;
1515aa14b181Shenning 	struct queue_stats	 qstats;
1516aa14b181Shenning 	static u_int32_t	 last_ticket;
1517aa14b181Shenning 
1518aa14b181Shenning 	memset(&pq, 0, sizeof(pq));
1519aa14b181Shenning 	memset(&pqs, 0, sizeof(pqs));
1520aa14b181Shenning 	memset(&qstats, 0, sizeof(qstats));
1521aa14b181Shenning 
1522aa14b181Shenning 	if (pf_dev < 0)
1523aa14b181Shenning 		return (-1);
1524aa14b181Shenning 
15253aaa63ebSderaadt 	if (ioctl(pf_dev, DIOCGETQUEUES, &pq) == -1) {
1526aa14b181Shenning 		error("DIOCGETQUEUES: %s", strerror(errno));
1527aa14b181Shenning 		return (-1);
1528aa14b181Shenning 	}
1529aa14b181Shenning 
1530aa14b181Shenning 	/* if a new set is found, start over */
1531aa14b181Shenning 	if (pq.ticket != last_ticket)
1532635c567dSpelikan 		while ((node = TAILQ_FIRST(&qnodes)) != NULL) {
1533aa14b181Shenning 			TAILQ_REMOVE(&qnodes, node, entries);
1534635c567dSpelikan 			free(node);
1535635c567dSpelikan 		}
1536aa14b181Shenning 	last_ticket = pq.ticket;
1537aa14b181Shenning 
1538aa14b181Shenning 	num_queues = mnr = pq.nr;
1539aa14b181Shenning 	for (nr = 0; nr < mnr; ++nr) {
1540aa14b181Shenning 		pqs.nr = nr;
1541aa14b181Shenning 		pqs.ticket = pq.ticket;
1542aa14b181Shenning 		pqs.buf = &qstats.data;
1543aa14b181Shenning 		pqs.nbytes = sizeof(qstats.data);
15443aaa63ebSderaadt 		if (ioctl(pf_dev, DIOCGETQSTATS, &pqs) == -1) {
1545aa14b181Shenning 			error("DIOCGETQSTATS: %s", strerror(errno));
1546aa14b181Shenning 			return (-1);
1547aa14b181Shenning 		}
1548aa14b181Shenning 		qstats.valid = 1;
1549aa14b181Shenning 		gettimeofday(&qstats.timestamp, NULL);
1550aa14b181Shenning 		if ((node = pfctl_find_queue_node(pqs.queue.qname,
1551aa14b181Shenning 		    pqs.queue.ifname)) != NULL) {
1552aa14b181Shenning 			memcpy(&node->qstats_last, &node->qstats,
1553aa14b181Shenning 			    sizeof(struct queue_stats));
1554aa14b181Shenning 			memcpy(&node->qstats, &qstats,
1555aa14b181Shenning 			    sizeof(struct queue_stats));
1556aa14b181Shenning 		} else {
1557aa14b181Shenning 			pfctl_insert_queue_node(pqs.queue, qstats);
1558aa14b181Shenning 		}
1559aa14b181Shenning 	}
1560aa14b181Shenning 	return (0);
1561aa14b181Shenning }
1562aa14b181Shenning 
1563aa14b181Shenning int
select_queues(void)156473baed14Scanacar select_queues(void)
156573baed14Scanacar {
15664e976734Shenning 	num_disp = num_queues;
156773baed14Scanacar 	return (0);
156873baed14Scanacar }
156973baed14Scanacar 
157073baed14Scanacar int
read_queues(void)157173baed14Scanacar read_queues(void)
157273baed14Scanacar {
15734e976734Shenning 	num_disp = num_queues = 0;
1574aa14b181Shenning 
1575aa14b181Shenning 	if (pfctl_update_qstats() < 0)
157673baed14Scanacar 		return (-1);
15774e976734Shenning 	num_disp = num_queues;
157873baed14Scanacar 
157973baed14Scanacar 	return(0);
158073baed14Scanacar }
158173baed14Scanacar 
158273baed14Scanacar double
calc_interval(struct timeval * cur_time,struct timeval * last_time)158373baed14Scanacar calc_interval(struct timeval *cur_time, struct timeval *last_time)
158473baed14Scanacar {
158573baed14Scanacar 	double	sec;
158673baed14Scanacar 
158773baed14Scanacar 	sec = (double)(cur_time->tv_sec - last_time->tv_sec) +
158873baed14Scanacar 	    (double)(cur_time->tv_usec - last_time->tv_usec) / 1000000;
158973baed14Scanacar 
159073baed14Scanacar 	return (sec);
159173baed14Scanacar }
159273baed14Scanacar 
159373baed14Scanacar double
calc_rate(u_int64_t new_bytes,u_int64_t last_bytes,double interval)159473baed14Scanacar calc_rate(u_int64_t new_bytes, u_int64_t last_bytes, double interval)
159573baed14Scanacar {
159673baed14Scanacar 	double	rate;
159773baed14Scanacar 
159873baed14Scanacar 	rate = (double)(new_bytes - last_bytes) / interval;
159973baed14Scanacar 	return (rate);
160073baed14Scanacar }
160173baed14Scanacar 
160273baed14Scanacar double
calc_pps(u_int64_t new_pkts,u_int64_t last_pkts,double interval)160373baed14Scanacar calc_pps(u_int64_t new_pkts, u_int64_t last_pkts, double interval)
160473baed14Scanacar {
160573baed14Scanacar 	double	pps;
160673baed14Scanacar 
160773baed14Scanacar 	pps = (double)(new_pkts - last_pkts) / interval;
160873baed14Scanacar 	return (pps);
160973baed14Scanacar }
161073baed14Scanacar 
161173baed14Scanacar void
print_queue_node(struct pfctl_queue_node * node)1612aa14b181Shenning print_queue_node(struct pfctl_queue_node *node)
1613aa14b181Shenning {
1614ab6b4157Smikeb 	u_int	rate, rtmp;
1615aa14b181Shenning 	int 	i;
1616aa14b181Shenning 	double	interval, pps, bps;
1617aa14b181Shenning 	static const char unit[] = " KMG";
1618aa14b181Shenning 
1619aa14b181Shenning 	tb_start();
1620aa14b181Shenning 	for (i = 0; i < node->depth; i++)
1621aa14b181Shenning 		tbprintf(" ");
1622aa14b181Shenning 	tbprintf("%s", node->qs.qname);
16230b4f1cf4Ssthen 	if (i == 0 && node->qs.ifname[0])
16240b4f1cf4Ssthen 		tbprintf(" on %s ", node->qs.ifname);
1625aa14b181Shenning 	print_fld_tb(FLD_QUEUE);
1626aa14b181Shenning 
1627aa14b181Shenning 	// XXX: missing min, max, burst
1628aa14b181Shenning 	tb_start();
1629aa14b181Shenning 	rate = node->qs.linkshare.m2.absolute;
1630ab6b4157Smikeb 	for (i = 0; rate > 9999 && i <= 3; i++) {
1631ab6b4157Smikeb 		rtmp = rate / 1000;
1632ab6b4157Smikeb 		if (rtmp <= 9999)
1633ab6b4157Smikeb 			rtmp += (rate % 1000) / 500;
1634ab6b4157Smikeb 		rate = rtmp;
1635ab6b4157Smikeb 	}
163690944f0fSmikeb 	if (rate == 0 && (node->qs.flags & PFQS_FLOWQUEUE)) {
163790944f0fSmikeb 		/*
163890944f0fSmikeb 		 * XXX We're abusing the fact that 'flows' in
163990944f0fSmikeb 		 * the fqcodel_stats structure is at the same
164090944f0fSmikeb 		 * spot as the 'period' in hfsc_class_stats.
164190944f0fSmikeb 		 */
164290944f0fSmikeb 		tbprintf("%u", node->qstats.data.period);
164390944f0fSmikeb 	} else
1644aa14b181Shenning 		tbprintf("%u%c", rate, unit[i]);
1645aa14b181Shenning 	print_fld_tb(FLD_BANDW);
1646aa14b181Shenning 
16476cb74e26Smikeb 	print_fld_str(FLD_SCHED, node->qs.flags & PFQS_FLOWQUEUE ?
16486cb74e26Smikeb 	    "flow" : "fifo");
16496cb74e26Smikeb 
1650aa14b181Shenning 	if (node->qstats.valid && node->qstats_last.valid)
1651aa14b181Shenning 		interval = calc_interval(&node->qstats.timestamp,
1652aa14b181Shenning 		    &node->qstats_last.timestamp);
1653aa14b181Shenning 	else
1654aa14b181Shenning 		interval = 0;
1655aa14b181Shenning 
1656aa14b181Shenning 	print_fld_size(FLD_PKTS, node->qstats.data.xmit_cnt.packets);
1657aa14b181Shenning 	print_fld_size(FLD_BYTES, node->qstats.data.xmit_cnt.bytes);
1658aa14b181Shenning 	print_fld_size(FLD_DROPP, node->qstats.data.drop_cnt.packets);
1659aa14b181Shenning 	print_fld_size(FLD_DROPB, node->qstats.data.drop_cnt.bytes);
1660aa14b181Shenning 	print_fld_size(FLD_QLEN, node->qstats.data.qlength);
1661aa14b181Shenning 
1662aa14b181Shenning 	if (interval > 0) {
1663aa14b181Shenning 		pps = calc_pps(node->qstats.data.xmit_cnt.packets,
1664aa14b181Shenning 		    node->qstats_last.data.xmit_cnt.packets, interval);
1665aa14b181Shenning 		bps = calc_rate(node->qstats.data.xmit_cnt.bytes,
1666aa14b181Shenning 		    node->qstats_last.data.xmit_cnt.bytes, interval);
1667aa14b181Shenning 
1668aa14b181Shenning 		tb_start();
1669aa14b181Shenning 		if (pps > 0 && pps < 1)
1670aa14b181Shenning 			tbprintf("%-3.1lf", pps);
1671aa14b181Shenning 		else
1672aa14b181Shenning 			tbprintf("%u", (unsigned int)pps);
1673aa14b181Shenning 
1674aa14b181Shenning 		print_fld_tb(FLD_PKTSPS);
1675aa14b181Shenning 		print_fld_bw(FLD_BYTESPS, bps);
1676aa14b181Shenning 	}
1677aa14b181Shenning }
1678aa14b181Shenning 
1679aa14b181Shenning void
print_queues(void)168073baed14Scanacar print_queues(void)
168173baed14Scanacar {
1682aa14b181Shenning 	uint32_t n, count, start;
1683aa14b181Shenning 	struct pfctl_queue_node *node;
168473baed14Scanacar 
1685aa14b181Shenning 	n = count = 0;
1686aa14b181Shenning 	start = dispstart;
168773baed14Scanacar 
1688aa14b181Shenning 	TAILQ_FOREACH(node, &qnodes, entries) {
1689aa14b181Shenning 		if (n < start) {
1690aa14b181Shenning 			n++;
1691aa14b181Shenning 			continue;
1692aa14b181Shenning 		}
1693aa14b181Shenning 		print_queue_node(node);
1694aa14b181Shenning 		end_line();
1695aa14b181Shenning 		count++;
1696aa14b181Shenning 		if (maxprint > 0 && count >= maxprint)
1697aa14b181Shenning 			return;
1698aa14b181Shenning 	}
169973baed14Scanacar }
170073baed14Scanacar 
170173baed14Scanacar /* main program functions */
170273baed14Scanacar 
170373baed14Scanacar void
update_cache(void)1704035d703dScanacar update_cache(void)
170573baed14Scanacar {
170673baed14Scanacar 	static int pstate = -1;
170773baed14Scanacar 	if (pstate == cachestates)
170873baed14Scanacar 		return;
170973baed14Scanacar 
171073baed14Scanacar 	pstate = cachestates;
171173baed14Scanacar 	if (cachestates) {
171273baed14Scanacar 		show_field(FLD_SI);
171373baed14Scanacar 		show_field(FLD_SP);
171473baed14Scanacar 		gotsig_alarm = 1;
171573baed14Scanacar 	} else {
171673baed14Scanacar 		hide_field(FLD_SI);
171773baed14Scanacar 		hide_field(FLD_SP);
171873baed14Scanacar 		need_update = 1;
171973baed14Scanacar 	}
172073baed14Scanacar 	field_setup();
172173baed14Scanacar }
172273baed14Scanacar 
1723035d703dScanacar int
initpftop(void)172473baed14Scanacar initpftop(void)
172573baed14Scanacar {
172673baed14Scanacar 	struct pf_status status;
172773baed14Scanacar 	field_view *v;
172873baed14Scanacar 	int cachesize = DEFAULT_CACHE_SIZE;
172973baed14Scanacar 
173073baed14Scanacar 	v = views;
173173baed14Scanacar 	while(v->name != NULL)
173273baed14Scanacar 		add_view(v++);
173373baed14Scanacar 
173473baed14Scanacar 	pf_dev = open("/dev/pf", O_RDONLY);
173573baed14Scanacar 	if (pf_dev == -1) {
173673baed14Scanacar 		alloc_buf(0);
17373aaa63ebSderaadt 	} else if (ioctl(pf_dev, DIOCGETSTATUS, &status) == -1) {
173873baed14Scanacar 		warn("DIOCGETSTATUS");
173973baed14Scanacar 		alloc_buf(0);
174073baed14Scanacar 	} else
174173baed14Scanacar 		alloc_buf(status.states);
174273baed14Scanacar 
174373baed14Scanacar 	/* initialize cache with given size */
174473baed14Scanacar 	if (cache_init(cachesize))
174573baed14Scanacar 		warnx("Failed to initialize cache.");
174673baed14Scanacar 	else if (interactive && cachesize > 0)
174773baed14Scanacar 		cachestates = 1;
174873baed14Scanacar 
174973baed14Scanacar 	update_cache();
175073baed14Scanacar 
175173baed14Scanacar 	show_field(FLD_STMAX);
175273baed14Scanacar 	show_field(FLD_ANCHOR);
1753035d703dScanacar 
1754035d703dScanacar 	return (1);
175573baed14Scanacar }
1756