pf_snmp.c revision 179476
1143611Sphilip/*-
2143611Sphilip * Copyright (c) 2005 Philip Paeps <philip@FreeBSD.org>
3143611Sphilip * All rights reserved.
4143611Sphilip *
5143611Sphilip * Redistribution and use in source and binary forms, with or without
6143611Sphilip * modification, are permitted provided that the following conditions
7143611Sphilip * are met:
8143611Sphilip * 1. Redistributions of source code must retain the above copyright
9143611Sphilip *    notice, this list of conditions and the following disclaimer.
10143611Sphilip * 2. Redistributions in binary form must reproduce the above copyright
11143611Sphilip *    notice, this list of conditions and the following disclaimer in the
12143611Sphilip *    documentation and/or other materials provided with the distribution.
13143611Sphilip *
14143611Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15143611Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16143611Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17143611Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18143611Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19143611Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20143611Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21143611Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22143611Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23143611Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24143611Sphilip * SUCH DAMAGE.
25143611Sphilip *
26143611Sphilip * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c 179476 2008-06-01 14:09:54Z philip $
27143611Sphilip */
28143611Sphilip
29143611Sphilip#include <bsnmp/snmpmod.h>
30143611Sphilip
31143611Sphilip#include <net/pfvar.h>
32143611Sphilip#include <sys/ioctl.h>
33143611Sphilip
34143611Sphilip#include <errno.h>
35143611Sphilip#include <fcntl.h>
36143626Sphilip#include <stdint.h>
37143611Sphilip#include <stdio.h>
38143611Sphilip#include <stdlib.h>
39143611Sphilip#include <string.h>
40143611Sphilip#include <syslog.h>
41143611Sphilip#include <unistd.h>
42143611Sphilip
43143611Sphilip#include "pf_oid.h"
44143611Sphilip#include "pf_tree.h"
45143611Sphilip
46143611Sphilipstruct lmodule *module;
47143611Sphilip
48143611Sphilipstatic int dev = -1;
49143611Sphilipstatic int started;
50146531Sphilipstatic uint64_t pf_tick;
51143611Sphilip
52143611Sphilipstatic struct pf_status pfs;
53143611Sphilip
54143611Sphilipenum { IN, OUT };
55143611Sphilipenum { IPV4, IPV6 };
56143611Sphilipenum { PASS, BLOCK };
57143611Sphilip
58143611Sphilip#define PFI_IFTYPE_GROUP	0
59143611Sphilip#define PFI_IFTYPE_INSTANCE	1
60143611Sphilip#define PFI_IFTYPE_DETACHED	2
61143611Sphilip
62143611Sphilipstruct pfi_entry {
63171173Smlaier	struct pfi_kif	pfi;
64143611Sphilip	u_int		index;
65143611Sphilip	TAILQ_ENTRY(pfi_entry) link;
66143611Sphilip};
67143611SphilipTAILQ_HEAD(pfi_table, pfi_entry);
68143611Sphilip
69143611Sphilipstatic struct pfi_table pfi_table;
70143611Sphilipstatic time_t pfi_table_age;
71143611Sphilipstatic int pfi_table_count;
72143611Sphilip
73143611Sphilip#define PFI_TABLE_MAXAGE	5
74143611Sphilip
75143611Sphilipstruct pft_entry {
76143611Sphilip	struct pfr_tstats pft;
77143611Sphilip	u_int		index;
78143611Sphilip	TAILQ_ENTRY(pft_entry) link;
79143611Sphilip};
80143611SphilipTAILQ_HEAD(pft_table, pft_entry);
81143611Sphilip
82143611Sphilipstatic struct pft_table pft_table;
83143611Sphilipstatic time_t pft_table_age;
84143611Sphilipstatic int pft_table_count;
85143611Sphilip
86143611Sphilip#define PFT_TABLE_MAXAGE	5
87143611Sphilip
88143611Sphilipstruct pfq_entry {
89143611Sphilip	struct pf_altq	altq;
90143611Sphilip	u_int		index;
91143611Sphilip	TAILQ_ENTRY(pfq_entry) link;
92143611Sphilip};
93143611SphilipTAILQ_HEAD(pfq_table, pfq_entry);
94143611Sphilip
95143611Sphilipstatic struct pfq_table pfq_table;
96143611Sphilipstatic time_t pfq_table_age;
97143611Sphilipstatic int pfq_table_count;
98143611Sphilip
99152970Sphilipstatic int altq_enabled = 0;
100152970Sphilip
101143611Sphilip#define PFQ_TABLE_MAXAGE	5
102143611Sphilip
103143611Sphilip/* Forward declarations */
104143611Sphilipstatic int pfi_refresh(void);
105143611Sphilipstatic int pfq_refresh(void);
106143611Sphilipstatic int pfs_refresh(void);
107143611Sphilipstatic int pft_refresh(void);
108143611Sphilipstatic struct pfi_entry * pfi_table_find(u_int idx);
109143611Sphilipstatic struct pfq_entry * pfq_table_find(u_int idx);
110143611Sphilipstatic struct pft_entry * pft_table_find(u_int idx);
111143611Sphilip
112152970Sphilipstatic int altq_is_enabled(int pfdevice);
113152970Sphilip
114143611Sphilipint
115143611Sphilippf_status(struct snmp_context __unused *ctx, struct snmp_value *val,
116143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
117143611Sphilip{
118143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
119143611Sphilip	time_t		runtime;
120143611Sphilip	unsigned char	str[128];
121143611Sphilip
122143611Sphilip	if (op == SNMP_OP_SET)
123143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
124143611Sphilip
125143611Sphilip	if (op == SNMP_OP_GET) {
126143611Sphilip		if (pfs_refresh() == -1)
127143611Sphilip			return (SNMP_ERR_GENERR);
128143611Sphilip
129143611Sphilip		switch (which) {
130143611Sphilip			case LEAF_pfStatusRunning:
131143611Sphilip			    val->v.uint32 = pfs.running;
132143611Sphilip			    break;
133143611Sphilip			case LEAF_pfStatusRuntime:
134143611Sphilip			    runtime = (pfs.since > 0) ?
135143611Sphilip				time(NULL) - pfs.since : 0;
136143611Sphilip			    val->v.uint32 = runtime * 100;
137143611Sphilip			    break;
138143611Sphilip			case LEAF_pfStatusDebug:
139143611Sphilip			    val->v.uint32 = pfs.debug;
140143611Sphilip			    break;
141143611Sphilip			case LEAF_pfStatusHostId:
142143611Sphilip			    sprintf(str, "0x%08x", ntohl(pfs.hostid));
143143611Sphilip			    return (string_get(val, str, strlen(str)));
144143611Sphilip
145143611Sphilip			default:
146143611Sphilip			    return (SNMP_ERR_NOSUCHNAME);
147143611Sphilip		}
148143611Sphilip
149143611Sphilip		return (SNMP_ERR_NOERROR);
150143611Sphilip	}
151143611Sphilip
152143611Sphilip	abort();
153143611Sphilip}
154143611Sphilip
155143611Sphilipint
156143611Sphilippf_counter(struct snmp_context __unused *ctx, struct snmp_value *val,
157143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
158143611Sphilip{
159143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
160143611Sphilip
161143611Sphilip	if (op == SNMP_OP_SET)
162143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
163143611Sphilip
164143611Sphilip	if (op == SNMP_OP_GET) {
165143611Sphilip		if (pfs_refresh() == -1)
166143611Sphilip			return (SNMP_ERR_GENERR);
167143611Sphilip
168143611Sphilip		switch (which) {
169143611Sphilip			case LEAF_pfCounterMatch:
170143611Sphilip				val->v.counter64 = pfs.counters[PFRES_MATCH];
171143611Sphilip				break;
172143611Sphilip			case LEAF_pfCounterBadOffset:
173143611Sphilip				val->v.counter64 = pfs.counters[PFRES_BADOFF];
174143611Sphilip				break;
175143611Sphilip			case LEAF_pfCounterFragment:
176143611Sphilip				val->v.counter64 = pfs.counters[PFRES_FRAG];
177143611Sphilip				break;
178143611Sphilip			case LEAF_pfCounterShort:
179143611Sphilip				val->v.counter64 = pfs.counters[PFRES_SHORT];
180143611Sphilip				break;
181143611Sphilip			case LEAF_pfCounterNormalize:
182143611Sphilip				val->v.counter64 = pfs.counters[PFRES_NORM];
183143611Sphilip				break;
184143611Sphilip			case LEAF_pfCounterMemDrop:
185143611Sphilip				val->v.counter64 = pfs.counters[PFRES_MEMORY];
186143611Sphilip				break;
187143611Sphilip
188143611Sphilip			default:
189143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
190143611Sphilip		}
191143611Sphilip
192143611Sphilip		return (SNMP_ERR_NOERROR);
193143611Sphilip	}
194143611Sphilip
195143611Sphilip	abort();
196143611Sphilip}
197143611Sphilip
198143611Sphilipint
199143611Sphilippf_statetable(struct snmp_context __unused *ctx, struct snmp_value *val,
200143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
201143611Sphilip{
202143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
203143611Sphilip
204143611Sphilip	if (op == SNMP_OP_SET)
205143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
206143611Sphilip
207143611Sphilip	if (op == SNMP_OP_GET) {
208143611Sphilip		if (pfs_refresh() == -1)
209143611Sphilip			return (SNMP_ERR_GENERR);
210143611Sphilip
211143611Sphilip		switch (which) {
212143611Sphilip			case LEAF_pfStateTableCount:
213143611Sphilip				val->v.uint32 = pfs.states;
214143611Sphilip				break;
215143611Sphilip			case LEAF_pfStateTableSearches:
216143611Sphilip				val->v.counter64 =
217143611Sphilip				    pfs.fcounters[FCNT_STATE_SEARCH];
218143611Sphilip				break;
219143611Sphilip			case LEAF_pfStateTableInserts:
220143611Sphilip				val->v.counter64 =
221143611Sphilip				    pfs.fcounters[FCNT_STATE_INSERT];
222143611Sphilip				break;
223143611Sphilip			case LEAF_pfStateTableRemovals:
224143611Sphilip				val->v.counter64 =
225143611Sphilip				    pfs.fcounters[FCNT_STATE_REMOVALS];
226143611Sphilip				break;
227143611Sphilip
228143611Sphilip			default:
229143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
230143611Sphilip		}
231143611Sphilip
232143611Sphilip		return (SNMP_ERR_NOERROR);
233143611Sphilip	}
234143611Sphilip
235143611Sphilip	abort();
236143611Sphilip}
237143611Sphilip
238143611Sphilipint
239143611Sphilippf_srcnodes(struct snmp_context __unused *ctx, struct snmp_value *val,
240143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
241143611Sphilip{
242143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
243143611Sphilip
244143611Sphilip	if (op == SNMP_OP_SET)
245143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
246143611Sphilip
247143611Sphilip	if (op == SNMP_OP_GET) {
248143611Sphilip		if (pfs_refresh() == -1)
249143611Sphilip			return (SNMP_ERR_GENERR);
250143611Sphilip
251143611Sphilip		switch (which) {
252143611Sphilip			case LEAF_pfSrcNodesCount:
253143611Sphilip				val->v.uint32 = pfs.src_nodes;
254143611Sphilip				break;
255143611Sphilip			case LEAF_pfSrcNodesSearches:
256143611Sphilip				val->v.counter64 =
257143611Sphilip				    pfs.scounters[SCNT_SRC_NODE_SEARCH];
258143611Sphilip				break;
259143611Sphilip			case LEAF_pfSrcNodesInserts:
260143611Sphilip				val->v.counter64 =
261143611Sphilip				    pfs.scounters[SCNT_SRC_NODE_INSERT];
262143611Sphilip				break;
263143611Sphilip			case LEAF_pfSrcNodesRemovals:
264143611Sphilip				val->v.counter64 =
265143611Sphilip				    pfs.scounters[SCNT_SRC_NODE_REMOVALS];
266143611Sphilip				break;
267143611Sphilip
268143611Sphilip			default:
269143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
270143611Sphilip		}
271143611Sphilip
272143611Sphilip		return (SNMP_ERR_NOERROR);
273143611Sphilip	}
274143611Sphilip
275143611Sphilip	abort();
276143611Sphilip}
277143611Sphilip
278143611Sphilipint
279143611Sphilippf_limits(struct snmp_context __unused *ctx, struct snmp_value *val,
280143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
281143611Sphilip{
282143611Sphilip	asn_subid_t		which = val->var.subs[sub - 1];
283143611Sphilip	struct pfioc_limit	pl;
284143611Sphilip
285143611Sphilip	if (op == SNMP_OP_SET)
286143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
287143611Sphilip
288143611Sphilip	if (op == SNMP_OP_GET) {
289143611Sphilip		bzero(&pl, sizeof(struct pfioc_limit));
290143611Sphilip
291143611Sphilip		switch (which) {
292143611Sphilip			case LEAF_pfLimitsStates:
293143611Sphilip				pl.index = PF_LIMIT_STATES;
294143611Sphilip				break;
295143611Sphilip			case LEAF_pfLimitsSrcNodes:
296143611Sphilip				pl.index = PF_LIMIT_SRC_NODES;
297143611Sphilip				break;
298143611Sphilip			case LEAF_pfLimitsFrags:
299143611Sphilip				pl.index = PF_LIMIT_FRAGS;
300143611Sphilip				break;
301143611Sphilip
302143611Sphilip			default:
303143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
304143611Sphilip		}
305143611Sphilip
306143611Sphilip		if (ioctl(dev, DIOCGETLIMIT, &pl)) {
307143611Sphilip			syslog(LOG_ERR, "pf_limits(): ioctl(): %s",
308143611Sphilip			    strerror(errno));
309143611Sphilip			return (SNMP_ERR_GENERR);
310143611Sphilip		}
311143611Sphilip
312143611Sphilip		val->v.uint32 = pl.limit;
313143611Sphilip
314143611Sphilip		return (SNMP_ERR_NOERROR);
315143611Sphilip	}
316143611Sphilip
317143611Sphilip	abort();
318143611Sphilip}
319143611Sphilip
320143611Sphilipint
321143611Sphilippf_timeouts(struct snmp_context __unused *ctx, struct snmp_value *val,
322143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
323143611Sphilip{
324143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
325143611Sphilip	struct pfioc_tm	pt;
326143611Sphilip
327143611Sphilip	if (op == SNMP_OP_SET)
328143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
329143611Sphilip
330143611Sphilip	if (op == SNMP_OP_GET) {
331143611Sphilip		bzero(&pt, sizeof(struct pfioc_tm));
332143611Sphilip
333143611Sphilip		switch (which) {
334143611Sphilip			case LEAF_pfTimeoutsTcpFirst:
335143611Sphilip				pt.timeout = PFTM_TCP_FIRST_PACKET;
336143611Sphilip				break;
337143611Sphilip			case LEAF_pfTimeoutsTcpOpening:
338143611Sphilip				pt.timeout = PFTM_TCP_OPENING;
339143611Sphilip				break;
340143611Sphilip			case LEAF_pfTimeoutsTcpEstablished:
341143611Sphilip				pt.timeout = PFTM_TCP_ESTABLISHED;
342143611Sphilip				break;
343143611Sphilip			case LEAF_pfTimeoutsTcpClosing:
344143611Sphilip				pt.timeout = PFTM_TCP_CLOSING;
345143611Sphilip				break;
346143611Sphilip			case LEAF_pfTimeoutsTcpFinWait:
347143611Sphilip				pt.timeout = PFTM_TCP_FIN_WAIT;
348143611Sphilip				break;
349143611Sphilip			case LEAF_pfTimeoutsTcpClosed:
350143611Sphilip				pt.timeout = PFTM_TCP_CLOSED;
351143611Sphilip				break;
352143611Sphilip			case LEAF_pfTimeoutsUdpFirst:
353143611Sphilip				pt.timeout = PFTM_UDP_FIRST_PACKET;
354143611Sphilip				break;
355143611Sphilip			case LEAF_pfTimeoutsUdpSingle:
356143611Sphilip				pt.timeout = PFTM_UDP_SINGLE;
357143611Sphilip				break;
358143611Sphilip			case LEAF_pfTimeoutsUdpMultiple:
359143611Sphilip				pt.timeout = PFTM_UDP_MULTIPLE;
360143611Sphilip				break;
361143611Sphilip			case LEAF_pfTimeoutsIcmpFirst:
362143611Sphilip				pt.timeout = PFTM_ICMP_FIRST_PACKET;
363143611Sphilip				break;
364143611Sphilip			case LEAF_pfTimeoutsIcmpError:
365143611Sphilip				pt.timeout = PFTM_ICMP_ERROR_REPLY;
366143611Sphilip				break;
367143611Sphilip			case LEAF_pfTimeoutsOtherFirst:
368143611Sphilip				pt.timeout = PFTM_OTHER_FIRST_PACKET;
369143611Sphilip				break;
370143611Sphilip			case LEAF_pfTimeoutsOtherSingle:
371143611Sphilip				pt.timeout = PFTM_OTHER_SINGLE;
372143611Sphilip				break;
373143611Sphilip			case LEAF_pfTimeoutsOtherMultiple:
374143611Sphilip				pt.timeout = PFTM_OTHER_MULTIPLE;
375143611Sphilip				break;
376143611Sphilip			case LEAF_pfTimeoutsFragment:
377143611Sphilip				pt.timeout = PFTM_FRAG;
378143611Sphilip				break;
379143611Sphilip			case LEAF_pfTimeoutsInterval:
380143611Sphilip				pt.timeout = PFTM_INTERVAL;
381143611Sphilip				break;
382143611Sphilip			case LEAF_pfTimeoutsAdaptiveStart:
383143611Sphilip				pt.timeout = PFTM_ADAPTIVE_START;
384143611Sphilip				break;
385143611Sphilip			case LEAF_pfTimeoutsAdaptiveEnd:
386143611Sphilip				pt.timeout = PFTM_ADAPTIVE_END;
387143611Sphilip				break;
388143611Sphilip			case LEAF_pfTimeoutsSrcNode:
389143611Sphilip				pt.timeout = PFTM_SRC_NODE;
390143611Sphilip				break;
391143611Sphilip
392143611Sphilip			default:
393143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
394143611Sphilip		}
395143611Sphilip
396143611Sphilip		if (ioctl(dev, DIOCGETTIMEOUT, &pt)) {
397143611Sphilip			syslog(LOG_ERR, "pf_timeouts(): ioctl(): %s",
398143611Sphilip			    strerror(errno));
399143611Sphilip			return (SNMP_ERR_GENERR);
400143611Sphilip		}
401143611Sphilip
402143611Sphilip		val->v.integer = pt.seconds;
403143611Sphilip
404143611Sphilip		return (SNMP_ERR_NOERROR);
405143611Sphilip	}
406143611Sphilip
407143611Sphilip	abort();
408143611Sphilip}
409143611Sphilip
410143611Sphilipint
411143611Sphilippf_logif(struct snmp_context __unused *ctx, struct snmp_value *val,
412143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
413143611Sphilip{
414143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
415143611Sphilip	unsigned char	str[IFNAMSIZ];
416143611Sphilip
417143611Sphilip	if (op == SNMP_OP_SET)
418143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
419143611Sphilip
420143611Sphilip	if (op == SNMP_OP_GET) {
421143611Sphilip		if (pfs_refresh() == -1)
422143611Sphilip			return (SNMP_ERR_GENERR);
423143611Sphilip
424143611Sphilip		switch (which) {
425143611Sphilip	 		case LEAF_pfLogInterfaceName:
426143611Sphilip				strlcpy(str, pfs.ifname, sizeof str);
427143611Sphilip				return (string_get(val, str, strlen(str)));
428143611Sphilip			case LEAF_pfLogInterfaceIp4BytesIn:
429143611Sphilip				val->v.counter64 = pfs.bcounters[IPV4][IN];
430143611Sphilip				break;
431143611Sphilip			case LEAF_pfLogInterfaceIp4BytesOut:
432143611Sphilip				val->v.counter64 = pfs.bcounters[IPV4][OUT];
433143611Sphilip				break;
434143611Sphilip			case LEAF_pfLogInterfaceIp4PktsInPass:
435143611Sphilip				val->v.counter64 =
436143611Sphilip				    pfs.pcounters[IPV4][IN][PF_PASS];
437143611Sphilip				break;
438143611Sphilip			case LEAF_pfLogInterfaceIp4PktsInDrop:
439143611Sphilip				val->v.counter64 =
440143611Sphilip				    pfs.pcounters[IPV4][IN][PF_DROP];
441143611Sphilip				break;
442143611Sphilip			case LEAF_pfLogInterfaceIp4PktsOutPass:
443143611Sphilip				val->v.counter64 =
444143611Sphilip				    pfs.pcounters[IPV4][OUT][PF_PASS];
445143611Sphilip				break;
446143611Sphilip			case LEAF_pfLogInterfaceIp4PktsOutDrop:
447143611Sphilip				val->v.counter64 =
448143611Sphilip				    pfs.pcounters[IPV4][OUT][PF_DROP];
449143611Sphilip				break;
450143611Sphilip			case LEAF_pfLogInterfaceIp6BytesIn:
451143611Sphilip				val->v.counter64 = pfs.bcounters[IPV6][IN];
452143611Sphilip				break;
453143611Sphilip			case LEAF_pfLogInterfaceIp6BytesOut:
454143611Sphilip				val->v.counter64 = pfs.bcounters[IPV6][OUT];
455143611Sphilip				break;
456143611Sphilip			case LEAF_pfLogInterfaceIp6PktsInPass:
457143611Sphilip				val->v.counter64 =
458143611Sphilip				    pfs.pcounters[IPV6][IN][PF_PASS];
459143611Sphilip				break;
460143611Sphilip			case LEAF_pfLogInterfaceIp6PktsInDrop:
461143611Sphilip				val->v.counter64 =
462143611Sphilip				    pfs.pcounters[IPV6][IN][PF_DROP];
463143611Sphilip				break;
464143611Sphilip			case LEAF_pfLogInterfaceIp6PktsOutPass:
465143611Sphilip				val->v.counter64 =
466143611Sphilip				    pfs.pcounters[IPV6][OUT][PF_PASS];
467143611Sphilip				break;
468143611Sphilip			case LEAF_pfLogInterfaceIp6PktsOutDrop:
469143611Sphilip				val->v.counter64 =
470143611Sphilip				    pfs.pcounters[IPV6][OUT][PF_DROP];
471143611Sphilip				break;
472143611Sphilip
473143611Sphilip			default:
474143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
475143611Sphilip		}
476143611Sphilip
477143611Sphilip		return (SNMP_ERR_NOERROR);
478143611Sphilip	}
479143611Sphilip
480143611Sphilip	abort();
481143611Sphilip}
482143611Sphilip
483143611Sphilipint
484143611Sphilippf_interfaces(struct snmp_context __unused *ctx, struct snmp_value *val,
485143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
486143611Sphilip{
487143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
488143611Sphilip
489143611Sphilip	if (op == SNMP_OP_SET)
490143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
491143611Sphilip
492143611Sphilip	if (op == SNMP_OP_GET) {
493143611Sphilip		if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
494143611Sphilip			if (pfi_refresh() == -1)
495143611Sphilip			    return (SNMP_ERR_GENERR);
496143611Sphilip
497143611Sphilip		switch (which) {
498143611Sphilip			case LEAF_pfInterfacesIfNumber:
499143611Sphilip				val->v.uint32 = pfi_table_count;
500143611Sphilip				break;
501143611Sphilip
502143611Sphilip			default:
503143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
504143611Sphilip		}
505143611Sphilip
506143611Sphilip		return (SNMP_ERR_NOERROR);
507143611Sphilip	}
508143611Sphilip
509143611Sphilip	abort();
510143611Sphilip}
511143611Sphilip
512143611Sphilipint
513143611Sphilippf_iftable(struct snmp_context __unused *ctx, struct snmp_value *val,
514143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
515143611Sphilip{
516143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
517143611Sphilip	struct pfi_entry *e = NULL;
518143611Sphilip
519143611Sphilip	switch (op) {
520143611Sphilip		case SNMP_OP_SET:
521143611Sphilip			return (SNMP_ERR_NOT_WRITEABLE);
522143611Sphilip		case SNMP_OP_GETNEXT:
523143611Sphilip			if ((e = NEXT_OBJECT_INT(&pfi_table,
524143611Sphilip			    &val->var, sub)) == NULL)
525143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
526143611Sphilip			val->var.len = sub + 1;
527143611Sphilip			val->var.subs[sub] = e->index;
528143611Sphilip			break;
529143611Sphilip		case SNMP_OP_GET:
530143611Sphilip			if (val->var.len - sub != 1)
531143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
532143611Sphilip			if ((e = pfi_table_find(val->var.subs[sub])) == NULL)
533143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
534143611Sphilip			break;
535143611Sphilip
536143611Sphilip		case SNMP_OP_COMMIT:
537143611Sphilip		case SNMP_OP_ROLLBACK:
538143611Sphilip		default:
539143611Sphilip			abort();
540143611Sphilip	}
541143611Sphilip
542143611Sphilip	if ((time(NULL) - pfi_table_age) > PFI_TABLE_MAXAGE)
543143611Sphilip		pfi_refresh();
544143611Sphilip
545143611Sphilip	switch (which) {
546143611Sphilip		case LEAF_pfInterfacesIfDescr:
547171173Smlaier			return (string_get(val, e->pfi.pfik_name, -1));
548143611Sphilip		case LEAF_pfInterfacesIfType:
549143611Sphilip			val->v.integer = PFI_IFTYPE_INSTANCE;
550143611Sphilip			break;
551143611Sphilip		case LEAF_pfInterfacesIfTZero:
552143611Sphilip			val->v.uint32 =
553171173Smlaier			    (time(NULL) - e->pfi.pfik_tzero) * 100;
554143611Sphilip			break;
555143611Sphilip		case LEAF_pfInterfacesIfRefsState:
556171173Smlaier			val->v.uint32 = e->pfi.pfik_states;
557143611Sphilip			break;
558143611Sphilip		case LEAF_pfInterfacesIfRefsRule:
559171173Smlaier			val->v.uint32 = e->pfi.pfik_rules;
560143611Sphilip			break;
561143611Sphilip		case LEAF_pfInterfacesIf4BytesInPass:
562143611Sphilip			val->v.counter64 =
563171173Smlaier			    e->pfi.pfik_bytes[IPV4][IN][PASS];
564143611Sphilip			break;
565143611Sphilip		case LEAF_pfInterfacesIf4BytesInBlock:
566143611Sphilip			val->v.counter64 =
567171173Smlaier			    e->pfi.pfik_bytes[IPV4][IN][BLOCK];
568143611Sphilip			break;
569143611Sphilip		case LEAF_pfInterfacesIf4BytesOutPass:
570143611Sphilip			val->v.counter64 =
571171173Smlaier			    e->pfi.pfik_bytes[IPV4][OUT][PASS];
572143611Sphilip			break;
573143611Sphilip		case LEAF_pfInterfacesIf4BytesOutBlock:
574143611Sphilip			val->v.counter64 =
575171173Smlaier			    e->pfi.pfik_bytes[IPV4][OUT][BLOCK];
576143611Sphilip			break;
577143611Sphilip		case LEAF_pfInterfacesIf4PktsInPass:
578143611Sphilip			val->v.counter64 =
579171173Smlaier			    e->pfi.pfik_packets[IPV4][IN][PASS];
580143611Sphilip			break;
581143611Sphilip		case LEAF_pfInterfacesIf4PktsInBlock:
582143611Sphilip			val->v.counter64 =
583171173Smlaier			    e->pfi.pfik_packets[IPV4][IN][BLOCK];
584143611Sphilip			break;
585143611Sphilip		case LEAF_pfInterfacesIf4PktsOutPass:
586143611Sphilip			val->v.counter64 =
587171173Smlaier			    e->pfi.pfik_packets[IPV4][OUT][PASS];
588143611Sphilip			break;
589143611Sphilip		case LEAF_pfInterfacesIf4PktsOutBlock:
590143611Sphilip			val->v.counter64 =
591171173Smlaier			    e->pfi.pfik_packets[IPV4][OUT][BLOCK];
592143611Sphilip			break;
593143611Sphilip		case LEAF_pfInterfacesIf6BytesInPass:
594143611Sphilip			val->v.counter64 =
595171173Smlaier			    e->pfi.pfik_bytes[IPV6][IN][PASS];
596143611Sphilip			break;
597143611Sphilip		case LEAF_pfInterfacesIf6BytesInBlock:
598143611Sphilip			val->v.counter64 =
599171173Smlaier			    e->pfi.pfik_bytes[IPV6][IN][BLOCK];
600143611Sphilip			break;
601143611Sphilip		case LEAF_pfInterfacesIf6BytesOutPass:
602143611Sphilip			val->v.counter64 =
603171173Smlaier			    e->pfi.pfik_bytes[IPV6][OUT][PASS];
604143611Sphilip			break;
605143611Sphilip		case LEAF_pfInterfacesIf6BytesOutBlock:
606143611Sphilip			val->v.counter64 =
607171173Smlaier			    e->pfi.pfik_bytes[IPV6][OUT][BLOCK];
608143611Sphilip			break;
609143611Sphilip		case LEAF_pfInterfacesIf6PktsInPass:
610143611Sphilip			val->v.counter64 =
611171173Smlaier			    e->pfi.pfik_packets[IPV6][IN][PASS];
612143611Sphilip			break;
613143611Sphilip		case LEAF_pfInterfacesIf6PktsInBlock:
614143611Sphilip			val->v.counter64 =
615171173Smlaier			    e->pfi.pfik_packets[IPV6][IN][BLOCK];
616143611Sphilip			break;
617143611Sphilip		case LEAF_pfInterfacesIf6PktsOutPass:
618143611Sphilip			val->v.counter64 =
619171173Smlaier			    e->pfi.pfik_packets[IPV6][OUT][PASS];
620143611Sphilip			break;
621143611Sphilip		case LEAF_pfInterfacesIf6PktsOutBlock:
622143611Sphilip			val->v.counter64 =
623171173Smlaier			    e->pfi.pfik_packets[IPV6][OUT][BLOCK];
624143611Sphilip			break;
625143611Sphilip
626143611Sphilip		default:
627143611Sphilip			return (SNMP_ERR_NOSUCHNAME);
628143611Sphilip	}
629143611Sphilip
630143611Sphilip	return (SNMP_ERR_NOERROR);
631143611Sphilip}
632143611Sphilip
633143611Sphilipint
634143611Sphilippf_tables(struct snmp_context __unused *ctx, struct snmp_value *val,
635143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
636143611Sphilip{
637143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
638143611Sphilip
639143611Sphilip	if (op == SNMP_OP_SET)
640143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
641143611Sphilip
642143611Sphilip	if (op == SNMP_OP_GET) {
643143611Sphilip		if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
644143611Sphilip			if (pft_refresh() == -1)
645143611Sphilip			    return (SNMP_ERR_GENERR);
646143611Sphilip
647143611Sphilip		switch (which) {
648143611Sphilip			case LEAF_pfTablesTblNumber:
649143611Sphilip				val->v.uint32 = pft_table_count;
650143611Sphilip				break;
651143611Sphilip
652143611Sphilip			default:
653143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
654143611Sphilip		}
655143611Sphilip
656143611Sphilip		return (SNMP_ERR_NOERROR);
657143611Sphilip	}
658143611Sphilip
659143611Sphilip	abort();
660143611Sphilip}
661143611Sphilip
662143611Sphilipint
663143611Sphilippf_tbltable(struct snmp_context __unused *ctx, struct snmp_value *val,
664143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
665143611Sphilip{
666143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
667143611Sphilip	struct pft_entry *e = NULL;
668143611Sphilip
669143611Sphilip	switch (op) {
670143611Sphilip		case SNMP_OP_SET:
671143611Sphilip			return (SNMP_ERR_NOT_WRITEABLE);
672143611Sphilip		case SNMP_OP_GETNEXT:
673143611Sphilip			if ((e = NEXT_OBJECT_INT(&pft_table,
674143611Sphilip			    &val->var, sub)) == NULL)
675143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
676143611Sphilip			val->var.len = sub + 1;
677143611Sphilip			val->var.subs[sub] = e->index;
678143611Sphilip			break;
679143611Sphilip		case SNMP_OP_GET:
680143611Sphilip			if (val->var.len - sub != 1)
681143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
682143611Sphilip			if ((e = pft_table_find(val->var.subs[sub])) == NULL)
683143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
684143611Sphilip			break;
685143611Sphilip
686143611Sphilip		case SNMP_OP_COMMIT:
687143611Sphilip		case SNMP_OP_ROLLBACK:
688143611Sphilip		default:
689143611Sphilip			abort();
690143611Sphilip	}
691143611Sphilip
692143611Sphilip	if ((time(NULL) - pft_table_age) > PFT_TABLE_MAXAGE)
693143611Sphilip		pft_refresh();
694143611Sphilip
695143611Sphilip	switch (which) {
696143611Sphilip		case LEAF_pfTablesTblDescr:
697143611Sphilip			return (string_get(val, e->pft.pfrts_name, -1));
698143611Sphilip		case LEAF_pfTablesTblCount:
699143611Sphilip			val->v.integer = e->pft.pfrts_cnt;
700143611Sphilip			break;
701143611Sphilip		case LEAF_pfTablesTblTZero:
702143611Sphilip			val->v.uint32 =
703143611Sphilip			    (time(NULL) - e->pft.pfrts_tzero) * 100;
704143611Sphilip			break;
705143611Sphilip		case LEAF_pfTablesTblRefsAnchor:
706143611Sphilip			val->v.integer =
707143611Sphilip			    e->pft.pfrts_refcnt[PFR_REFCNT_ANCHOR];
708143611Sphilip			break;
709143611Sphilip		case LEAF_pfTablesTblRefsRule:
710143611Sphilip			val->v.integer =
711143611Sphilip			    e->pft.pfrts_refcnt[PFR_REFCNT_RULE];
712143611Sphilip			break;
713143611Sphilip		case LEAF_pfTablesTblEvalMatch:
714143611Sphilip			val->v.counter64 = e->pft.pfrts_match;
715143611Sphilip			break;
716143611Sphilip		case LEAF_pfTablesTblEvalNoMatch:
717143611Sphilip			val->v.counter64 = e->pft.pfrts_nomatch;
718143611Sphilip			break;
719143611Sphilip		case LEAF_pfTablesTblBytesInPass:
720143611Sphilip			val->v.counter64 =
721143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_PASS];
722143611Sphilip			break;
723143611Sphilip		case LEAF_pfTablesTblBytesInBlock:
724143611Sphilip			val->v.counter64 =
725143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_BLOCK];
726143611Sphilip			break;
727143611Sphilip		case LEAF_pfTablesTblBytesInXPass:
728143611Sphilip			val->v.counter64 =
729143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_IN][PFR_OP_XPASS];
730143611Sphilip			break;
731143611Sphilip		case LEAF_pfTablesTblBytesOutPass:
732143611Sphilip			val->v.counter64 =
733143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_PASS];
734143611Sphilip			break;
735143611Sphilip		case LEAF_pfTablesTblBytesOutBlock:
736143611Sphilip			val->v.counter64 =
737143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_BLOCK];
738143611Sphilip			break;
739143611Sphilip		case LEAF_pfTablesTblBytesOutXPass:
740143611Sphilip			val->v.counter64 =
741143611Sphilip			    e->pft.pfrts_bytes[PFR_DIR_OUT][PFR_OP_XPASS];
742143611Sphilip			break;
743143611Sphilip		case LEAF_pfTablesTblPktsInPass:
744143611Sphilip			val->v.counter64 =
745143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_PASS];
746143611Sphilip			break;
747143611Sphilip		case LEAF_pfTablesTblPktsInBlock:
748143611Sphilip			val->v.counter64 =
749143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_BLOCK];
750143611Sphilip			break;
751143611Sphilip		case LEAF_pfTablesTblPktsInXPass:
752143611Sphilip			val->v.counter64 =
753143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_IN][PFR_OP_XPASS];
754143611Sphilip			break;
755143611Sphilip		case LEAF_pfTablesTblPktsOutPass:
756143611Sphilip			val->v.counter64 =
757143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_PASS];
758143611Sphilip			break;
759143611Sphilip		case LEAF_pfTablesTblPktsOutBlock:
760143611Sphilip			val->v.counter64 =
761143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_BLOCK];
762143611Sphilip			break;
763143611Sphilip		case LEAF_pfTablesTblPktsOutXPass:
764143611Sphilip			val->v.counter64 =
765143611Sphilip			    e->pft.pfrts_packets[PFR_DIR_OUT][PFR_OP_XPASS];
766143611Sphilip			break;
767143611Sphilip
768143611Sphilip		default:
769143611Sphilip			return (SNMP_ERR_NOSUCHNAME);
770143611Sphilip	}
771143611Sphilip
772143611Sphilip	return (SNMP_ERR_NOERROR);
773143611Sphilip}
774143611Sphilip
775143611Sphilipint
776143611Sphilippf_tbladdr(struct snmp_context __unused *ctx, struct snmp_value __unused *val,
777143611Sphilip	u_int __unused sub, u_int __unused vindex, enum snmp_op __unused op)
778143611Sphilip{
779143611Sphilip	return (SNMP_ERR_GENERR);
780143611Sphilip}
781143611Sphilip
782143611Sphilipint
783143611Sphilippf_altq(struct snmp_context __unused *ctx, struct snmp_value *val,
784143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
785143611Sphilip{
786143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
787143611Sphilip
788152970Sphilip	if (!altq_enabled) {
789152970Sphilip	   return (SNMP_ERR_NOERROR);
790152970Sphilip	}
791152970Sphilip
792143611Sphilip	if (op == SNMP_OP_SET)
793143611Sphilip		return (SNMP_ERR_NOT_WRITEABLE);
794143611Sphilip
795143611Sphilip	if (op == SNMP_OP_GET) {
796143611Sphilip		if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
797143611Sphilip			if (pfq_refresh() == -1)
798143611Sphilip			    return (SNMP_ERR_GENERR);
799143611Sphilip
800143611Sphilip		switch (which) {
801143611Sphilip			case LEAF_pfAltqQueueNumber:
802143611Sphilip				val->v.uint32 = pfq_table_count;
803143611Sphilip				break;
804143611Sphilip
805143611Sphilip			default:
806143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
807143611Sphilip		}
808143611Sphilip
809143611Sphilip		return (SNMP_ERR_NOERROR);
810143611Sphilip	}
811143611Sphilip
812143611Sphilip	abort();
813143611Sphilip	return (SNMP_ERR_GENERR);
814143611Sphilip}
815143611Sphilip
816143611Sphilipint
817143611Sphilippf_altqq(struct snmp_context __unused *ctx, struct snmp_value *val,
818143611Sphilip	u_int sub, u_int __unused vindex, enum snmp_op op)
819143611Sphilip{
820143611Sphilip	asn_subid_t	which = val->var.subs[sub - 1];
821143611Sphilip	struct pfq_entry *e = NULL;
822143611Sphilip
823152970Sphilip	if (!altq_enabled) {
824152970Sphilip	   return (SNMP_ERR_NOERROR);
825152970Sphilip	}
826152970Sphilip
827143611Sphilip	switch (op) {
828143611Sphilip		case SNMP_OP_SET:
829143611Sphilip			return (SNMP_ERR_NOT_WRITEABLE);
830143611Sphilip		case SNMP_OP_GETNEXT:
831143611Sphilip			if ((e = NEXT_OBJECT_INT(&pfq_table,
832143611Sphilip			    &val->var, sub)) == NULL)
833143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
834143611Sphilip			val->var.len = sub + 1;
835143611Sphilip			val->var.subs[sub] = e->index;
836143611Sphilip			break;
837143611Sphilip		case SNMP_OP_GET:
838143611Sphilip			if (val->var.len - sub != 1)
839143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
840143611Sphilip			if ((e = pfq_table_find(val->var.subs[sub])) == NULL)
841143611Sphilip				return (SNMP_ERR_NOSUCHNAME);
842143611Sphilip			break;
843143611Sphilip
844143611Sphilip		case SNMP_OP_COMMIT:
845143611Sphilip		case SNMP_OP_ROLLBACK:
846143611Sphilip		default:
847143611Sphilip			abort();
848143611Sphilip	}
849143611Sphilip
850143611Sphilip	if ((time(NULL) - pfq_table_age) > PFQ_TABLE_MAXAGE)
851143611Sphilip		pfq_refresh();
852143611Sphilip
853143611Sphilip	switch (which) {
854143611Sphilip		case LEAF_pfAltqQueueDescr:
855143611Sphilip			return (string_get(val, e->altq.qname, -1));
856143611Sphilip		case LEAF_pfAltqQueueParent:
857143611Sphilip			return (string_get(val, e->altq.parent, -1));
858143611Sphilip		case LEAF_pfAltqQueueScheduler:
859143611Sphilip			val->v.integer = e->altq.scheduler;
860143611Sphilip			break;
861143611Sphilip		case LEAF_pfAltqQueueBandwidth:
862143611Sphilip			val->v.uint32 = e->altq.bandwidth;
863143611Sphilip			break;
864143611Sphilip		case LEAF_pfAltqQueuePriority:
865143611Sphilip			val->v.integer = e->altq.priority;
866143611Sphilip			break;
867143611Sphilip		case LEAF_pfAltqQueueLimit:
868143611Sphilip			val->v.integer = e->altq.qlimit;
869143611Sphilip			break;
870143611Sphilip
871143611Sphilip		default:
872143611Sphilip			return (SNMP_ERR_NOSUCHNAME);
873143611Sphilip	}
874143611Sphilip
875143611Sphilip	return (SNMP_ERR_NOERROR);
876143611Sphilip}
877143611Sphilip
878143611Sphilipstatic struct pfi_entry *
879143611Sphilippfi_table_find(u_int idx)
880143611Sphilip{
881143611Sphilip	struct pfi_entry *e;
882143611Sphilip
883143611Sphilip	TAILQ_FOREACH(e, &pfi_table, link)
884143611Sphilip		if (e->index == idx)
885143611Sphilip			return (e);
886143611Sphilip	return (NULL);
887143611Sphilip}
888143611Sphilip
889143611Sphilipstatic struct pfq_entry *
890143611Sphilippfq_table_find(u_int idx)
891143611Sphilip{
892143611Sphilip	struct pfq_entry *e;
893143611Sphilip	TAILQ_FOREACH(e, &pfq_table, link)
894143611Sphilip		if (e->index == idx)
895143611Sphilip			return (e);
896143611Sphilip	return (NULL);
897143611Sphilip}
898143611Sphilip
899143611Sphilipstatic struct pft_entry *
900143611Sphilippft_table_find(u_int idx)
901143611Sphilip{
902143611Sphilip	struct pft_entry *e;
903143611Sphilip
904143611Sphilip	TAILQ_FOREACH(e, &pft_table, link)
905143611Sphilip		if (e->index == idx)
906143611Sphilip			return (e);
907143611Sphilip	return (NULL);
908143611Sphilip}
909143611Sphilip
910143611Sphilipstatic int
911143611Sphilippfi_refresh(void)
912143611Sphilip{
913143611Sphilip	struct pfioc_iface io;
914171173Smlaier	struct pfi_kif *p = NULL;
915143611Sphilip	struct pfi_entry *e;
916143611Sphilip	int i, numifs = 1;
917143611Sphilip
918143611Sphilip	if (started && this_tick <= pf_tick)
919143611Sphilip		return (0);
920143611Sphilip
921143611Sphilip	while (!TAILQ_EMPTY(&pfi_table)) {
922143611Sphilip		e = TAILQ_FIRST(&pfi_table);
923143611Sphilip		TAILQ_REMOVE(&pfi_table, e, link);
924143611Sphilip		free(e);
925143611Sphilip	}
926143611Sphilip
927143611Sphilip	bzero(&io, sizeof(io));
928171173Smlaier	io.pfiio_esize = sizeof(struct pfi_kif);
929143611Sphilip
930143611Sphilip	for (;;) {
931171173Smlaier		p = reallocf(p, numifs * sizeof(struct pfi_kif));
932149571Sphilip		if (p == NULL) {
933149571Sphilip			syslog(LOG_ERR, "pfi_refresh(): reallocf() numifs=%d: %s",
934149571Sphilip			    numifs, strerror(errno));
935149571Sphilip			goto err2;
936149571Sphilip		}
937143611Sphilip		io.pfiio_size = numifs;
938143611Sphilip		io.pfiio_buffer = p;
939143611Sphilip
940143611Sphilip		if (ioctl(dev, DIOCIGETIFACES, &io)) {
941143611Sphilip			syslog(LOG_ERR, "pfi_refresh(): ioctl(): %s",
942143611Sphilip			    strerror(errno));
943149571Sphilip			goto err2;
944143611Sphilip		}
945143611Sphilip
946143611Sphilip		if (numifs >= io.pfiio_size)
947143611Sphilip			break;
948143611Sphilip
949143611Sphilip		numifs = io.pfiio_size;
950143611Sphilip	}
951143611Sphilip
952143611Sphilip	for (i = 0; i < numifs; i++) {
953143611Sphilip		e = malloc(sizeof(struct pfi_entry));
954149571Sphilip		if (e == NULL)
955149571Sphilip			goto err1;
956143611Sphilip		e->index = i + 1;
957171173Smlaier		memcpy(&e->pfi, p+i, sizeof(struct pfi_kif));
958143611Sphilip		TAILQ_INSERT_TAIL(&pfi_table, e, link);
959143611Sphilip	}
960143611Sphilip
961143611Sphilip	pfi_table_age = time(NULL);
962143611Sphilip	pfi_table_count = numifs;
963143611Sphilip	pf_tick = this_tick;
964143611Sphilip
965143611Sphilip	free(p);
966143611Sphilip	return (0);
967149571Sphilip
968149571Sphiliperr1:
969149571Sphilip	while (!TAILQ_EMPTY(&pfi_table)) {
970149571Sphilip		e = TAILQ_FIRST(&pfi_table);
971149571Sphilip		TAILQ_REMOVE(&pfi_table, e, link);
972149571Sphilip		free(e);
973149571Sphilip	}
974149571Sphiliperr2:
975149571Sphilip	free(p);
976149571Sphilip	return(-1);
977143611Sphilip}
978143611Sphilip
979143611Sphilipstatic int
980143611Sphilippfq_refresh(void)
981143611Sphilip{
982143611Sphilip	struct pfioc_altq pa;
983143611Sphilip	struct pfq_entry *e;
984143611Sphilip	int i, numqs, ticket;
985143611Sphilip
986143611Sphilip	if (started && this_tick <= pf_tick)
987143611Sphilip		return (0);
988143611Sphilip
989143611Sphilip	while (!TAILQ_EMPTY(&pfq_table)) {
990143611Sphilip		e = TAILQ_FIRST(&pfq_table);
991143611Sphilip		TAILQ_REMOVE(&pfq_table, e, link);
992143611Sphilip		free(e);
993143611Sphilip	}
994143611Sphilip
995143611Sphilip	bzero(&pa, sizeof(pa));
996143611Sphilip
997143611Sphilip	if (ioctl(dev, DIOCGETALTQS, &pa)) {
998143611Sphilip		syslog(LOG_ERR, "pfq_refresh: ioctl(DIOCGETALTQS): %s",
999143611Sphilip		    strerror(errno));
1000143611Sphilip		return (-1);
1001143611Sphilip	}
1002143611Sphilip
1003143611Sphilip	numqs = pa.nr;
1004143611Sphilip	ticket = pa.ticket;
1005143611Sphilip
1006143611Sphilip	for (i = 0; i < numqs; i++) {
1007143611Sphilip		e = malloc(sizeof(struct pfq_entry));
1008149571Sphilip		if (e == NULL) {
1009149571Sphilip			syslog(LOG_ERR, "pfq_refresh(): "
1010149571Sphilip			    "malloc(): %s",
1011149571Sphilip			    strerror(errno));
1012149571Sphilip			goto err;
1013149571Sphilip		}
1014143611Sphilip		pa.ticket = ticket;
1015143611Sphilip		pa.nr = i;
1016143611Sphilip
1017143611Sphilip		if (ioctl(dev, DIOCGETALTQ, &pa)) {
1018143611Sphilip			syslog(LOG_ERR, "pfq_refresh(): "
1019143611Sphilip			    "ioctl(DIOCGETALTQ): %s",
1020143611Sphilip			    strerror(errno));
1021149571Sphilip			goto err;
1022143611Sphilip		}
1023143611Sphilip
1024143611Sphilip		if (pa.altq.qid > 0) {
1025143611Sphilip			memcpy(&e->altq, &pa.altq, sizeof(struct pf_altq));
1026143611Sphilip			e->index = pa.altq.qid;
1027143611Sphilip			pfq_table_count = i;
1028179476Sphilip			INSERT_OBJECT_INT_LINK_INDEX(e, &pfq_table, link, index);
1029143611Sphilip		}
1030143611Sphilip	}
1031143611Sphilip
1032143611Sphilip	pfq_table_age = time(NULL);
1033143611Sphilip	pf_tick = this_tick;
1034143611Sphilip
1035143611Sphilip	return (0);
1036149571Sphiliperr:
1037149571Sphilip	free(e);
1038149571Sphilip	while (!TAILQ_EMPTY(&pfq_table)) {
1039149571Sphilip		e = TAILQ_FIRST(&pfq_table);
1040149571Sphilip		TAILQ_REMOVE(&pfq_table, e, link);
1041149571Sphilip		free(e);
1042149571Sphilip	}
1043149571Sphilip	return(-1);
1044143611Sphilip}
1045143611Sphilip
1046143611Sphilipstatic int
1047143611Sphilippfs_refresh(void)
1048143611Sphilip{
1049143611Sphilip	if (started && this_tick <= pf_tick)
1050143611Sphilip		return (0);
1051143611Sphilip
1052143611Sphilip	bzero(&pfs, sizeof(struct pf_status));
1053143611Sphilip
1054143611Sphilip	if (ioctl(dev, DIOCGETSTATUS, &pfs)) {
1055143611Sphilip		syslog(LOG_ERR, "pfs_refresh(): ioctl(): %s",
1056143611Sphilip		    strerror(errno));
1057143611Sphilip		return (-1);
1058143611Sphilip	}
1059143611Sphilip
1060143611Sphilip	pf_tick = this_tick;
1061143611Sphilip	return (0);
1062143611Sphilip}
1063143611Sphilip
1064143611Sphilipstatic int
1065143611Sphilippft_refresh(void)
1066143611Sphilip{
1067143611Sphilip	struct pfioc_table io;
1068149571Sphilip	struct pfr_tstats *t = NULL;
1069143611Sphilip	struct pft_entry *e;
1070143611Sphilip	int i, numtbls = 1;
1071143611Sphilip
1072143611Sphilip	if (started && this_tick <= pf_tick)
1073143611Sphilip		return (0);
1074143611Sphilip
1075143611Sphilip	while (!TAILQ_EMPTY(&pft_table)) {
1076143611Sphilip		e = TAILQ_FIRST(&pft_table);
1077143611Sphilip		TAILQ_REMOVE(&pft_table, e, link);
1078143611Sphilip		free(e);
1079143611Sphilip	}
1080143611Sphilip
1081143611Sphilip	bzero(&io, sizeof(io));
1082143611Sphilip	io.pfrio_esize = sizeof(struct pfr_tstats);
1083143611Sphilip
1084143611Sphilip	for (;;) {
1085149571Sphilip		t = reallocf(t, numtbls * sizeof(struct pfr_tstats));
1086149571Sphilip		if (t == NULL) {
1087149571Sphilip			syslog(LOG_ERR, "pft_refresh(): reallocf() numtbls=%d: %s",
1088149571Sphilip			    numtbls, strerror(errno));
1089149571Sphilip			goto err2;
1090149571Sphilip		}
1091143611Sphilip		io.pfrio_size = numtbls;
1092143611Sphilip		io.pfrio_buffer = t;
1093143611Sphilip
1094143611Sphilip		if (ioctl(dev, DIOCRGETTSTATS, &io)) {
1095143611Sphilip			syslog(LOG_ERR, "pft_refresh(): ioctl(): %s",
1096143611Sphilip			    strerror(errno));
1097149571Sphilip			goto err2;
1098143611Sphilip		}
1099143611Sphilip
1100143611Sphilip		if (numtbls >= io.pfrio_size)
1101143611Sphilip			break;
1102143611Sphilip
1103143611Sphilip		numtbls = io.pfrio_size;
1104143611Sphilip	}
1105143611Sphilip
1106143611Sphilip	for (i = 0; i < numtbls; i++) {
1107143611Sphilip		e = malloc(sizeof(struct pfr_tstats));
1108149571Sphilip		if (e == NULL)
1109149571Sphilip			goto err1;
1110143611Sphilip		e->index = i + 1;
1111143611Sphilip		memcpy(&e->pft, t+i, sizeof(struct pfr_tstats));
1112143611Sphilip		TAILQ_INSERT_TAIL(&pft_table, e, link);
1113143611Sphilip	}
1114143611Sphilip
1115143611Sphilip	pft_table_age = time(NULL);
1116143611Sphilip	pft_table_count = numtbls;
1117143611Sphilip	pf_tick = this_tick;
1118143611Sphilip
1119143611Sphilip	free(t);
1120143611Sphilip	return (0);
1121149571Sphiliperr1:
1122149571Sphilip	while (!TAILQ_EMPTY(&pft_table)) {
1123149571Sphilip		e = TAILQ_FIRST(&pft_table);
1124149571Sphilip		TAILQ_REMOVE(&pft_table, e, link);
1125149571Sphilip		free(e);
1126149571Sphilip	}
1127149571Sphiliperr2:
1128149571Sphilip	free(t);
1129149571Sphilip	return(-1);
1130143611Sphilip}
1131143611Sphilip
1132143611Sphilip/*
1133152970Sphilip * check whether altq support is enabled in kernel
1134152970Sphilip */
1135152970Sphilip
1136152970Sphilipstatic int
1137152970Sphilipaltq_is_enabled(int pfdev)
1138152970Sphilip{
1139152970Sphilip        struct pfioc_altq pa;
1140152970Sphilip
1141152970Sphilip	errno = 0;
1142152970Sphilip        if (ioctl(pfdev, DIOCGETALTQS, &pa)) {
1143152970Sphilip                if (errno == ENODEV) {
1144152970Sphilip			syslog(LOG_INFO, "No ALTQ support in kernel\n"
1145152970Sphilip			    "ALTQ related functions disabled\n");
1146152970Sphilip                        return (0);
1147152970Sphilip                } else
1148152970Sphilip                        syslog(LOG_ERR, "DIOCGETALTQS returned an error: %s",
1149152970Sphilip			    strerror(errno));
1150152970Sphilip			return (-1);
1151152970Sphilip        }
1152152970Sphilip        return (1);
1153152970Sphilip}
1154152970Sphilip
1155152970Sphilip/*
1156143611Sphilip * Implement the bsnmpd module interface
1157143611Sphilip */
1158143611Sphilipstatic int
1159143611Sphilippf_init(struct lmodule *mod, int __unused argc, char __unused *argv[])
1160143611Sphilip{
1161143611Sphilip	module = mod;
1162143611Sphilip
1163143611Sphilip	if ((dev = open("/dev/pf", O_RDONLY)) == -1) {
1164143611Sphilip		syslog(LOG_ERR, "pf_init(): open(): %s\n",
1165143611Sphilip		    strerror(errno));
1166143611Sphilip		return (-1);
1167143611Sphilip	}
1168143611Sphilip
1169152970Sphilip	if ((altq_enabled = altq_is_enabled(dev)) == -1) {
1170152970Sphilip		syslog(LOG_ERR, "pf_init(): altq test failed");
1171152970Sphilip		return (-1);
1172152970Sphilip	}
1173152970Sphilip
1174143611Sphilip	/* Prepare internal state */
1175143611Sphilip	TAILQ_INIT(&pfi_table);
1176143611Sphilip	TAILQ_INIT(&pfq_table);
1177143611Sphilip	TAILQ_INIT(&pft_table);
1178143611Sphilip
1179143611Sphilip	pfi_refresh();
1180152970Sphilip	if (altq_enabled) {
1181152970Sphilip		pfq_refresh();
1182152970Sphilip	}
1183152970Sphilip
1184143611Sphilip	pfs_refresh();
1185143611Sphilip	pft_refresh();
1186143611Sphilip
1187143611Sphilip	started = 1;
1188143611Sphilip
1189143611Sphilip	return (0);
1190143611Sphilip}
1191143611Sphilip
1192143611Sphilipstatic int
1193143611Sphilippf_fini(void)
1194143611Sphilip{
1195143611Sphilip	struct pfi_entry *i1, *i2;
1196143611Sphilip	struct pfq_entry *q1, *q2;
1197143611Sphilip	struct pft_entry *t1, *t2;
1198143611Sphilip
1199143611Sphilip	/* Empty the list of interfaces */
1200143611Sphilip	i1 = TAILQ_FIRST(&pfi_table);
1201143611Sphilip	while (i1 != NULL) {
1202143611Sphilip		i2 = TAILQ_NEXT(i1, link);
1203143611Sphilip		free(i1);
1204143611Sphilip		i1 = i2;
1205143611Sphilip	}
1206143611Sphilip
1207143611Sphilip	/* List of queues */
1208143611Sphilip	q1 = TAILQ_FIRST(&pfq_table);
1209143611Sphilip	while (q1 != NULL) {
1210143611Sphilip		q2 = TAILQ_NEXT(q1, link);
1211143611Sphilip		free(q1);
1212143611Sphilip		q1 = q2;
1213143611Sphilip	}
1214143611Sphilip
1215143611Sphilip	/* And the list of tables */
1216143611Sphilip	t1 = TAILQ_FIRST(&pft_table);
1217143611Sphilip	while (t1 != NULL) {
1218143611Sphilip		t2 = TAILQ_NEXT(t1, link);
1219143611Sphilip		free(t1);
1220143611Sphilip		t1 = t2;
1221143611Sphilip	}
1222143611Sphilip
1223143611Sphilip	close(dev);
1224143611Sphilip	return (0);
1225143611Sphilip}
1226143611Sphilip
1227143611Sphilipstatic void
1228143611Sphilippf_dump(void)
1229143611Sphilip{
1230143611Sphilip	pfi_refresh();
1231152970Sphilip	if (altq_enabled) {
1232152970Sphilip		pfq_refresh();
1233152970Sphilip	}
1234143611Sphilip	pft_refresh();
1235143611Sphilip
1236143654Sphilip	syslog(LOG_ERR, "Dump: pfi_table_age = %jd",
1237143654Sphilip	    (intmax_t)pfi_table_age);
1238143611Sphilip	syslog(LOG_ERR, "Dump: pfi_table_count = %d",
1239143611Sphilip	    pfi_table_count);
1240143611Sphilip
1241143654Sphilip	syslog(LOG_ERR, "Dump: pfq_table_age = %jd",
1242143654Sphilip	    (intmax_t)pfq_table_age);
1243143611Sphilip	syslog(LOG_ERR, "Dump: pfq_table_count = %d",
1244143611Sphilip	    pfq_table_count);
1245143611Sphilip
1246143654Sphilip	syslog(LOG_ERR, "Dump: pft_table_age = %jd",
1247143654Sphilip	    (intmax_t)pft_table_age);
1248143611Sphilip
1249143611Sphilip	syslog(LOG_ERR, "Dump: pft_table_count = %d",
1250143611Sphilip	    pft_table_count);
1251143611Sphilip}
1252143611Sphilip
1253143611Sphilipconst struct snmp_module config = {
1254143611Sphilip	.comment = "This module implements a MIB for the pf packet filter.",
1255143611Sphilip	.init =		pf_init,
1256143611Sphilip	.fini =		pf_fini,
1257143611Sphilip	.tree =		pf_ctree,
1258143611Sphilip	.dump =		pf_dump,
1259143611Sphilip	.tree_size =	pf_CTREE_SIZE,
1260143611Sphilip};
1261