summaryrefslogtreecommitdiffstats
path: root/freebsd/sbin
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sbin
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sbin')
-rw-r--r--freebsd/sbin/dhclient/bpf.c220
-rw-r--r--freebsd/sbin/dhclient/clparse.c4
-rw-r--r--freebsd/sbin/dhclient/conflex.c4
-rw-r--r--freebsd/sbin/dhclient/dhclient.c179
-rw-r--r--freebsd/sbin/dhclient/dhcpd.h20
-rw-r--r--freebsd/sbin/dhclient/options.c4
-rw-r--r--freebsd/sbin/dhclient/packet.c23
-rw-r--r--freebsd/sbin/dhclient/privsep.c5
-rw-r--r--freebsd/sbin/dhclient/privsep.h5
-rw-r--r--freebsd/sbin/ifconfig/af_inet.c75
-rw-r--r--freebsd/sbin/ifconfig/af_inet6.c170
-rw-r--r--freebsd/sbin/ifconfig/af_link.c30
-rw-r--r--freebsd/sbin/ifconfig/af_nd6.c22
-rw-r--r--freebsd/sbin/ifconfig/ifbridge.c33
-rw-r--r--freebsd/sbin/ifconfig/ifcarp.c10
-rw-r--r--freebsd/sbin/ifconfig/ifclone.c54
-rw-r--r--freebsd/sbin/ifconfig/ifconfig.c452
-rw-r--r--freebsd/sbin/ifconfig/ifconfig.h15
-rw-r--r--freebsd/sbin/ifconfig/ifgif.c25
-rw-r--r--freebsd/sbin/ifconfig/ifgre.c77
-rw-r--r--freebsd/sbin/ifconfig/ifgroup.c52
-rw-r--r--freebsd/sbin/ifconfig/ifieee80211.c26
-rw-r--r--freebsd/sbin/ifconfig/iflagg.c119
-rw-r--r--freebsd/sbin/ifconfig/ifmac.c18
-rw-r--r--freebsd/sbin/ifconfig/ifmedia.c190
-rw-r--r--freebsd/sbin/ifconfig/ifpfsync.c44
-rw-r--r--freebsd/sbin/ifconfig/ifvlan.c56
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h9
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h13
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h8
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h4
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h39
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h9
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h7
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h9
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h6
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h6
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h7
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h6
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h6
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h29
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h6
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h7
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h76
-rw-r--r--freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h15
-rw-r--r--freebsd/sbin/ifconfig/sfp.c935
-rw-r--r--freebsd/sbin/pfctl/parse.c9315
-rw-r--r--freebsd/sbin/pfctl/parse.h337
-rw-r--r--freebsd/sbin/pfctl/parse.y6290
-rw-r--r--freebsd/sbin/pfctl/pf_print_state.c387
-rw-r--r--freebsd/sbin/pfctl/pfctl.c2445
-rw-r--r--freebsd/sbin/pfctl/pfctl.h130
-rw-r--r--freebsd/sbin/pfctl/pfctl_altq.c1536
-rw-r--r--freebsd/sbin/pfctl/pfctl_optimize.c1705
-rw-r--r--freebsd/sbin/pfctl/pfctl_osfp.c1123
-rw-r--r--freebsd/sbin/pfctl/pfctl_parser.c1780
-rw-r--r--freebsd/sbin/pfctl/pfctl_parser.h322
-rw-r--r--freebsd/sbin/pfctl/pfctl_qstats.c528
-rw-r--r--freebsd/sbin/pfctl/pfctl_radix.c597
-rw-r--r--freebsd/sbin/pfctl/pfctl_table.c650
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h25
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h262
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h36
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h4
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h22
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h9
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h11
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h7
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h5
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h5
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h4
-rw-r--r--freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h6
-rw-r--r--freebsd/sbin/ping/ping.c396
-rw-r--r--freebsd/sbin/ping/rtems-bsd-ping-data.h3
-rw-r--r--freebsd/sbin/ping/rtems-bsd-ping-namespace.h2
-rw-r--r--freebsd/sbin/ping/rtems-bsd-ping-ping-data.h43
-rw-r--r--freebsd/sbin/ping6/ping6.c715
-rw-r--r--freebsd/sbin/ping6/rtems-bsd-ping6-data.h4
-rw-r--r--freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h3
-rw-r--r--freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h40
-rw-r--r--freebsd/sbin/route/keywords1
-rw-r--r--freebsd/sbin/route/route.c1452
-rw-r--r--freebsd/sbin/route/rtems-bsd-route-data.h3
-rw-r--r--freebsd/sbin/route/rtems-bsd-route-namespace.h2
-rw-r--r--freebsd/sbin/route/rtems-bsd-route-route-data.h30
-rw-r--r--freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h3
-rw-r--r--freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h2
-rw-r--r--freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h23
-rw-r--r--freebsd/sbin/sysctl/sysctl.c760
89 files changed, 32038 insertions, 2114 deletions
diff --git a/freebsd/sbin/dhclient/bpf.c b/freebsd/sbin/dhclient/bpf.c
index 8ff451b2..4d3d2276 100644
--- a/freebsd/sbin/dhclient/bpf.c
+++ b/freebsd/sbin/dhclient/bpf.c
@@ -46,6 +46,8 @@
__FBSDID("$FreeBSD$");
#include "dhcpd.h"
+#include "privsep.h"
+#include <sys/capsicum.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
@@ -63,15 +65,15 @@ __FBSDID("$FreeBSD$");
* mask.
*/
int
-if_register_bpf(struct interface_info *info)
+if_register_bpf(struct interface_info *info, int flags)
{
char filename[50];
int sock, b;
/* Open a BPF device */
- for (b = 0; 1; b++) {
+ for (b = 0;; b++) {
snprintf(filename, sizeof(filename), BPF_FORMAT, b);
- sock = open(filename, O_RDWR, 0);
+ sock = open(filename, flags);
if (sock < 0) {
if (errno == EBUSY)
continue;
@@ -89,16 +91,81 @@ if_register_bpf(struct interface_info *info)
return (sock);
}
+/*
+ * Packet write filter program:
+ * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
+ */
+struct bpf_insn dhcp_bpf_wfilter[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
+
+ /* Make sure this is an IP packet... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
+
+ /* Get the IP header length... */
+ BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's from the right port... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
+
+ /* Make sure it is to the right ports ... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+ /* Otherwise, drop it. */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
+
void
if_register_send(struct interface_info *info)
{
+ cap_rights_t rights;
+ struct bpf_version v;
+ struct bpf_program p;
int sock, on = 1;
- /*
- * If we're using the bpf API for sending and receiving, we
- * don't need to register this interface twice.
- */
- info->wfdesc = info->rfdesc;
+ /* Open a BPF device and hang it on this interface... */
+ info->wfdesc = if_register_bpf(info, O_WRONLY);
+
+ /* Make sure the BPF version is in range... */
+ if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0)
+ error("Can't get BPF version: %m");
+
+ if (v.bv_major != BPF_MAJOR_VERSION ||
+ v.bv_minor < BPF_MINOR_VERSION)
+ error("Kernel BPF version out of range - recompile dhcpd!");
+
+ /* Set up the bpf write filter program structure. */
+ p.bf_len = dhcp_bpf_wfilter_len;
+ p.bf_insns = dhcp_bpf_wfilter;
+
+ if (dhcp_bpf_wfilter[7].k == 0x1fff)
+ dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
+
+ if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0)
+ error("Can't install write filter program: %m");
+
+ if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0)
+ error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
/*
* Use raw socket for unicast send.
@@ -146,55 +213,17 @@ struct bpf_insn dhcp_bpf_filter[] = {
int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
-/*
- * Packet write filter program:
- * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
- */
-struct bpf_insn dhcp_bpf_wfilter[] = {
- BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
-
- /* Make sure this is an IP packet... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
-
- /* Make sure it's a UDP packet... */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
-
- /* Make sure this isn't a fragment... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
-
- /* Get the IP header length... */
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
-
- /* Make sure it's from the right port... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
-
- /* Make sure it is to the right ports ... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
-
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
-
- /* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
-};
-
-int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
-
void
if_register_receive(struct interface_info *info)
{
+ static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA };
+ cap_rights_t rights;
struct bpf_version v;
struct bpf_program p;
int flag = 1, sz;
/* Open a BPF device and hang it on this interface... */
- info->rfdesc = if_register_bpf(info);
+ info->rfdesc = if_register_bpf(info, O_RDONLY);
/* Make sure the BPF version is in range... */
if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0)
@@ -237,48 +266,94 @@ if_register_receive(struct interface_info *info)
if (ioctl(info->rfdesc, BIOCSETF, &p) < 0)
error("Can't install packet filter program: %m");
- /* Set up the bpf write filter program structure. */
- p.bf_len = dhcp_bpf_wfilter_len;
- p.bf_insns = dhcp_bpf_wfilter;
-
- if (dhcp_bpf_wfilter[7].k == 0x1fff)
- dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
-
- if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0)
- error("Can't install write filter program: %m");
-
if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0)
error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_IOCTL, CAP_EVENT, CAP_READ);
+ if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
+ if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS)
+ error("Can't limit ioctls for bpf descriptor: %m");
}
-ssize_t
-send_packet(struct interface_info *interface, struct dhcp_packet *raw,
- size_t len, struct in_addr from, struct sockaddr_in *to,
- struct hardware *hto)
+void
+send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len,
+ struct in_addr from, struct in_addr to)
+{
+ struct imsg_hdr hdr;
+ struct buf *buf;
+ int errs;
+
+ hdr.code = IMSG_SEND_PACKET;
+ hdr.len = sizeof(hdr) +
+ sizeof(size_t) + len +
+ sizeof(from) + sizeof(to);
+
+ if ((buf = buf_open(hdr.len)) == NULL)
+ error("buf_open: %m");
+
+ errs = 0;
+ errs += buf_add(buf, &hdr, sizeof(hdr));
+ errs += buf_add(buf, &len, sizeof(len));
+ errs += buf_add(buf, raw, len);
+ errs += buf_add(buf, &from, sizeof(from));
+ errs += buf_add(buf, &to, sizeof(to));
+ if (errs)
+ error("buf_add: %m");
+
+ if (buf_close(privfd, buf) == -1)
+ error("buf_close: %m");
+}
+
+void
+send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd)
{
unsigned char buf[256];
struct iovec iov[2];
struct msghdr msg;
+ struct dhcp_packet raw;
+ size_t len;
+ struct in_addr from, to;
int result, bufp = 0;
+ if (hdr->len < sizeof(*hdr) + sizeof(size_t))
+ error("corrupted message received");
+ buf_read(fd, &len, sizeof(len));
+ if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len +
+ sizeof(from) + sizeof(to)) {
+ error("corrupted message received");
+ }
+ if (len > sizeof(raw))
+ error("corrupted message received");
+ buf_read(fd, &raw, len);
+ buf_read(fd, &from, sizeof(from));
+ buf_read(fd, &to, sizeof(to));
+
/* Assemble the headers... */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
- assemble_hw_header(interface, buf, &bufp, hto);
- assemble_udp_ip_header(buf, &bufp, from.s_addr,
- to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
+ if (to.s_addr == INADDR_BROADCAST)
+ assemble_hw_header(interface, buf, &bufp);
+ assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr,
+ htons(REMOTE_PORT), (unsigned char *)&raw, len);
- iov[0].iov_base = (char *)buf;
+ iov[0].iov_base = buf;
iov[0].iov_len = bufp;
- iov[1].iov_base = (char *)raw;
+ iov[1].iov_base = &raw;
iov[1].iov_len = len;
/* Fire it off */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
+ if (to.s_addr == INADDR_BROADCAST)
result = writev(interface->wfdesc, iov, 2);
else {
+ struct sockaddr_in sato;
+
+ sato.sin_addr = to;
+ sato.sin_port = htons(REMOTE_PORT);
+ sato.sin_family = AF_INET;
+ sato.sin_len = sizeof(sato);
+
memset(&msg, 0, sizeof(msg));
- msg.msg_name = (struct sockaddr *)to;
- msg.msg_namelen = sizeof(*to);
+ msg.msg_name = (struct sockaddr *)&sato;
+ msg.msg_namelen = sizeof(sato);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
result = sendmsg(interface->ufdesc, &msg, 0);
@@ -286,7 +361,6 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw,
if (result < 0)
warning("send_packet: %m");
- return (result);
}
ssize_t
diff --git a/freebsd/sbin/dhclient/clparse.c b/freebsd/sbin/dhclient/clparse.c
index b52bc473..a65236fc 100644
--- a/freebsd/sbin/dhclient/clparse.c
+++ b/freebsd/sbin/dhclient/clparse.c
@@ -644,6 +644,10 @@ parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
case FILENAME:
lease->filename = parse_string(cfile);
return;
+ case NEXT_SERVER:
+ if (!parse_ip_addr(cfile, &lease->nextserver))
+ return;
+ break;
case SERVER_NAME:
lease->server_name = parse_string(cfile);
return;
diff --git a/freebsd/sbin/dhclient/conflex.c b/freebsd/sbin/dhclient/conflex.c
index 4990f45f..c4fd442c 100644
--- a/freebsd/sbin/dhclient/conflex.c
+++ b/freebsd/sbin/dhclient/conflex.c
@@ -99,8 +99,8 @@ get_char(FILE *cfile)
cur_line = line2;
prev_line = line1;
} else {
- cur_line = line2;
- prev_line = line1;
+ cur_line = line1;
+ prev_line = line2;
}
line++;
lpos = 1;
diff --git a/freebsd/sbin/dhclient/dhclient.c b/freebsd/sbin/dhclient/dhclient.c
index 97824985..c7b75c59 100644
--- a/freebsd/sbin/dhclient/dhclient.c
+++ b/freebsd/sbin/dhclient/dhclient.c
@@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$");
#include "dhcpd.h"
#include "privsep.h"
+#include <sys/capsicum.h>
+
#include <net80211/ieee80211_freebsd.h>
#ifndef _PATH_VAREMPTY
@@ -93,9 +95,10 @@ int log_perror = 1;
int privfd;
int nullfd = -1;
+char hostname[_POSIX_HOST_NAME_MAX + 1];
+
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
-struct in_addr inaddr_any;
-struct sockaddr_in sockaddr_broadcast;
+struct in_addr inaddr_any, inaddr_broadcast;
char *path_dhclient_pidfile;
struct pidfh *pidfile;
@@ -345,6 +348,7 @@ main(int argc, char *argv[])
int immediate_daemon = 0;
struct passwd *pw;
pid_t otherpid;
+ cap_rights_t rights;
/* Initially, log errors to stderr as well as to syslogd. */
openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
@@ -389,7 +393,7 @@ main(int argc, char *argv[])
if (path_dhclient_pidfile == NULL)
error("asprintf");
}
- pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
+ pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
if (pidfile == NULL) {
if (errno == EEXIST)
error("dhclient already running, pid: %d.", otherpid);
@@ -412,11 +416,7 @@ main(int argc, char *argv[])
tzset();
time(&cur_time);
- memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
- sockaddr_broadcast.sin_family = AF_INET;
- sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
- sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
- sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
+ inaddr_broadcast.s_addr = INADDR_BROADCAST;
inaddr_any.s_addr = INADDR_ANY;
read_client_conf();
@@ -453,13 +453,36 @@ main(int argc, char *argv[])
error("no such user: nobody");
}
+ /*
+ * Obtain hostname before entering capability mode - it won't be
+ * possible then, as reading kern.hostname is not permitted.
+ */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ hostname[0] = '\0';
+
+ priv_script_init("PREINIT", NULL);
+ if (ifi->client->alias)
+ priv_script_write_params("alias_", ifi->client->alias);
+ priv_script_go();
+
+ /* set up the interface */
+ discover_interfaces(ifi);
+
if (pipe(pipe_fd) == -1)
error("pipe");
fork_privchld(pipe_fd[0], pipe_fd[1]);
+ close(ifi->ufdesc);
+ ifi->ufdesc = -1;
+ close(ifi->wfdesc);
+ ifi->wfdesc = -1;
+
close(pipe_fd[0]);
privfd = pipe_fd[1];
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE);
+ if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit private descriptor: %m");
if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
error("can't open and lock %s: %m", path_dhclient_db);
@@ -467,16 +490,13 @@ main(int argc, char *argv[])
rewrite_client_leases();
close(fd);
- priv_script_init("PREINIT", NULL);
- if (ifi->client->alias)
- priv_script_write_params("alias_", ifi->client->alias);
- priv_script_go();
-
if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
add_protocol("AF_ROUTE", routefd, routehandler, ifi);
-
- /* set up the interface */
- discover_interfaces(ifi);
+ if (shutdown(routefd, SHUT_WR) < 0)
+ error("can't shutdown route socket: %m");
+ cap_rights_init(&rights, CAP_EVENT, CAP_READ);
+ if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit route socket: %m");
if (chroot(_PATH_VAREMPTY) == -1)
error("chroot");
@@ -492,6 +512,9 @@ main(int argc, char *argv[])
setproctitle("%s", ifi->name);
+ if (cap_enter() < 0 && errno != ENOSYS)
+ error("can't enter capability mode: %m");
+
if (immediate_daemon)
go_daemon();
@@ -1065,6 +1088,9 @@ packet_to_lease(struct packet *packet)
lease->address.len = sizeof(packet->raw->yiaddr);
memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
+ lease->nextserver.len = sizeof(packet->raw->siaddr);
+ memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
+
/* If the server name was filled out, copy it.
Do not attempt to validate the server name as a host name.
RFC 2131 merely states that sname is NUL-terminated (which do
@@ -1225,13 +1251,12 @@ again:
ip->client->secs = ip->client->packet.secs;
note("DHCPDISCOVER on %s to %s port %d interval %d",
- ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port),
+ ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
(int)ip->client->interval);
/* Send out a packet. */
- (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
add_timeout(cur_time + ip->client->interval, send_discover, ip);
}
@@ -1339,8 +1364,7 @@ void
send_request(void *ipp)
{
struct interface_info *ip = ipp;
- struct sockaddr_in destination;
- struct in_addr from;
+ struct in_addr from, to;
int interval;
/* Figure out how long it's been since we started transmitting. */
@@ -1428,18 +1452,13 @@ cancel:
/* If the lease T2 time has elapsed, or if we're not yet bound,
broadcast the DHCPREQUEST rather than unicasting. */
- memset(&destination, 0, sizeof(destination));
if (ip->client->state == S_REQUESTING ||
ip->client->state == S_REBOOTING ||
cur_time > ip->client->active->rebind)
- destination.sin_addr.s_addr = INADDR_BROADCAST;
+ to.s_addr = INADDR_BROADCAST;
else
- memcpy(&destination.sin_addr.s_addr,
- ip->client->destination.iabuf,
- sizeof(destination.sin_addr.s_addr));
- destination.sin_port = htons(REMOTE_PORT);
- destination.sin_family = AF_INET;
- destination.sin_len = sizeof(destination);
+ memcpy(&to.s_addr, ip->client->destination.iabuf,
+ sizeof(to.s_addr));
if (ip->client->state != S_REQUESTING)
memcpy(&from, ip->client->active->address.iabuf,
@@ -1457,12 +1476,12 @@ cancel:
ip->client->packet.secs = htons(65535);
}
- note("DHCPREQUEST on %s to %s port %d", ip->name,
- inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
+ note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
+ REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- from, &destination, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, from, to);
add_timeout(cur_time + ip->client->interval, send_request, ip);
}
@@ -1473,12 +1492,11 @@ send_decline(void *ipp)
struct interface_info *ip = ipp;
note("DHCPDECLINE on %s to %s port %d", ip->name,
- inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port));
+ inet_ntoa(inaddr_broadcast), REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
}
void
@@ -1535,11 +1553,10 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1555,12 +1572,12 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
}
/* set unique client identifier */
- char client_ident[sizeof(struct hardware)];
+ char client_ident[sizeof(ip->hw_address.haddr) + 1];
if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) {
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1659,11 +1676,10 @@ make_request(struct interface_info *ip, struct client_lease * lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1684,7 +1700,7 @@ make_request(struct interface_info *ip, struct client_lease * lease)
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1825,11 +1841,22 @@ void
rewrite_client_leases(void)
{
struct client_lease *lp;
+ cap_rights_t rights;
if (!leaseFile) {
leaseFile = fopen(path_dhclient_db, "w");
if (!leaseFile)
error("can't create %s: %m", path_dhclient_db);
+ cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC,
+ CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit lease descriptor: %m");
+ }
+ if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit lease descriptor fcntls: %m");
+ }
} else {
fflush(leaseFile);
rewind(leaseFile);
@@ -1876,6 +1903,11 @@ write_client_lease(struct interface_info *ip, struct client_lease *lease,
fprintf(leaseFile, " bootp;\n");
fprintf(leaseFile, " interface \"%s\";\n", ip->name);
fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
+ if (lease->nextserver.len == sizeof(inaddr_any) &&
+ 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
+ sizeof(inaddr_any)))
+ fprintf(leaseFile, " next-server %s;\n",
+ piaddr(lease->nextserver));
if (lease->filename)
fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
if (lease->server_name)
@@ -2245,6 +2277,17 @@ script_set_env(struct client_state *client, const char *prefix,
{
int i, j, namelen;
+ /* No `` or $() command substitution allowed in environment values! */
+ for (j=0; j < strlen(value); j++)
+ switch (value[j]) {
+ case '`':
+ case '$':
+ warning("illegal character (%c) in value '%s'",
+ value[j], value);
+ /* Ignore this option */
+ return;
+ }
+
namelen = strlen(name);
for (i = 0; client->scriptEnv[i]; i++)
@@ -2281,16 +2324,6 @@ script_set_env(struct client_state *client, const char *prefix,
strlen(value) + 1);
if (client->scriptEnv[i] == NULL)
error("script_set_env: no memory for variable assignment");
-
- /* No `` or $() command substitution allowed in environment values! */
- for (j=0; j < strlen(value); j++)
- switch (value[j]) {
- case '`':
- case '$':
- error("illegal character (%c) in value '%s'", value[j],
- value);
- /* not reached */
- }
snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) +
1 + strlen(value) + 1, "%s%s=%s", prefix, name, value);
}
@@ -2329,6 +2362,7 @@ void
go_daemon(void)
{
static int state = 0;
+ cap_rights_t rights;
if (no_daemon || state)
return;
@@ -2341,8 +2375,15 @@ go_daemon(void)
if (daemon(1, 0) == -1)
error("daemon");
- if (pidfile != NULL)
+ cap_rights_init(&rights);
+
+ if (pidfile != NULL) {
pidfile_write(pidfile);
+ if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit pidfile descriptor: %m");
+ }
+ }
/* we are chrooted, daemon(3) fails to open /dev/null */
if (nullfd != -1) {
@@ -2352,6 +2393,14 @@ go_daemon(void)
close(nullfd);
nullfd = -1;
}
+
+ if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdin: %m");
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdout: %m");
+ if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stderr: %m");
}
int
@@ -2496,19 +2545,19 @@ check_classless_option(unsigned char *data, int len)
i += 4;
continue;
} else if (width < 9) {
- addr = (in_addr_t)(data[i] << 24);
+ addr = (in_addr_t)(data[i] << 24);
i += 1;
} else if (width < 17) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16);
i += 2;
} else if (width < 25) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8);
i += 3;
} else if (width < 33) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8) +
data[i + 3];
@@ -2532,7 +2581,7 @@ check_classless_option(unsigned char *data, int len)
addr &= mask;
data[i - 1] = (unsigned char)(
(addr >> (((32 - width)/8)*8)) & 0xFF);
- }
+ }
i += 4;
}
if (i > len) {
@@ -2696,6 +2745,8 @@ fork_privchld(int fd, int fd2)
dup2(nullfd, STDERR_FILENO);
close(nullfd);
close(fd2);
+ close(ifi->rfdesc);
+ ifi->rfdesc = -1;
for (;;) {
pfd[0].fd = fd;
@@ -2707,6 +2758,6 @@ fork_privchld(int fd, int fd2)
if (nfds == 0 || !(pfd[0].revents & POLLIN))
continue;
- dispatch_imsg(fd);
+ dispatch_imsg(ifi, fd);
}
}
diff --git a/freebsd/sbin/dhclient/dhcpd.h b/freebsd/sbin/dhclient/dhcpd.h
index 030a96a0..852513a8 100644
--- a/freebsd/sbin/dhclient/dhcpd.h
+++ b/freebsd/sbin/dhclient/dhcpd.h
@@ -121,6 +121,7 @@ struct client_lease {
struct client_lease *next;
time_t expiry, renewal, rebind;
struct iaddr address;
+ struct iaddr nextserver;
char *server_name;
char *filename;
struct string_list *medium;
@@ -296,11 +297,13 @@ struct hash_table *new_hash_table(int);
struct hash_bucket *new_hash_bucket(void);
/* bpf.c */
-int if_register_bpf(struct interface_info *);
+int if_register_bpf(struct interface_info *, int);
void if_register_send(struct interface_info *);
void if_register_receive(struct interface_info *);
-ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t,
- struct in_addr, struct sockaddr_in *, struct hardware *);
+void send_packet_unpriv(int, struct dhcp_packet *, size_t, struct in_addr,
+ struct in_addr);
+struct imsg_hdr;
+void send_packet_priv(struct interface_info *, struct imsg_hdr *, int);
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t,
struct sockaddr_in *, struct hardware *);
@@ -404,20 +407,13 @@ void bootp(struct packet *);
void dhcp(struct packet *);
/* packet.c */
-void assemble_hw_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
+void assemble_hw_header(struct interface_info *, unsigned char *, int *);
void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t,
unsigned int, unsigned char *, int);
ssize_t decode_hw_header(unsigned char *, int, struct hardware *);
ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *,
unsigned char *, int);
-/* ethernet.c */
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int, struct hardware *);
-
/* clparse.c */
int read_client_conf(void);
void read_client_leases(void);
@@ -441,4 +437,4 @@ struct buf *buf_open(size_t);
int buf_add(struct buf *, void *, size_t);
int buf_close(int, struct buf *);
ssize_t buf_read(int, void *, size_t);
-void dispatch_imsg(int);
+void dispatch_imsg(struct interface_info *, int);
diff --git a/freebsd/sbin/dhclient/options.c b/freebsd/sbin/dhclient/options.c
index c86b7e3b..5ea8de7c 100644
--- a/freebsd/sbin/dhclient/options.c
+++ b/freebsd/sbin/dhclient/options.c
@@ -286,8 +286,8 @@ find_search_domain_name_len(struct option_data *option, int *offset)
option->data[i + 1];
if (pointer >= *offset) {
/*
- * The pointer must indicates a prior
- * occurance.
+ * The pointer must indicate a prior
+ * occurrence.
*/
warning("Invalid forward pointer in DHCP "
"Domain Search option compression.");
diff --git a/freebsd/sbin/dhclient/packet.c b/freebsd/sbin/dhclient/packet.c
index e4fa0e86..28a9ccec 100644
--- a/freebsd/sbin/dhclient/packet.c
+++ b/freebsd/sbin/dhclient/packet.c
@@ -57,11 +57,6 @@ __FBSDID("$FreeBSD$");
u_int32_t checksum(unsigned char *, unsigned, u_int32_t);
u_int32_t wrapsum(u_int32_t);
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int bufix, struct hardware *);
-
u_int32_t
checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
{
@@ -97,14 +92,11 @@ wrapsum(u_int32_t sum)
void
assemble_hw_header(struct interface_info *interface, unsigned char *buf,
- int *bufix, struct hardware *to)
+ int *bufix)
{
struct ether_header eh;
- if (to != NULL && to->hlen == 6) /* XXX */
- memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost));
- else
- memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
+ memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
if (interface->hw_address.hlen == sizeof(eh.ether_shost))
memcpy(eh.ether_shost, interface->hw_address.haddr,
sizeof(eh.ether_shost));
@@ -137,17 +129,6 @@ assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from,
ip.ip_dst.s_addr = to;
ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
-
- /*
- * While the BPF -- used for broadcasts -- expects a "true" IP header
- * with all the bytes in network byte order, the raw socket interface
- * which is used for unicasts expects the ip_len field to be in host
- * byte order. In both cases, the checksum has to be correct, so this
- * is as good a place as any to turn the bytes around again.
- */
- if (to != INADDR_BROADCAST)
- ip.ip_len = ntohs(ip.ip_len);
-
memcpy(&buf[*bufix], &ip, sizeof(ip));
*bufix += sizeof(ip);
diff --git a/freebsd/sbin/dhclient/privsep.c b/freebsd/sbin/dhclient/privsep.c
index 7b68059a..aa1042fd 100644
--- a/freebsd/sbin/dhclient/privsep.c
+++ b/freebsd/sbin/dhclient/privsep.c
@@ -103,7 +103,7 @@ buf_read(int sock, void *buf, size_t nbytes)
}
void
-dispatch_imsg(int fd)
+dispatch_imsg(struct interface_info *ifi, int fd)
{
struct imsg_hdr hdr;
char *medium, *reason, *filename,
@@ -234,6 +234,9 @@ dispatch_imsg(int fd)
if (buf_close(fd, buf) == -1)
error("buf_close: %m");
break;
+ case IMSG_SEND_PACKET:
+ send_packet_priv(ifi, &hdr, fd);
+ break;
default:
error("received unknown message, code %d", hdr.code);
}
diff --git a/freebsd/sbin/dhclient/privsep.h b/freebsd/sbin/dhclient/privsep.h
index f30284ee..d464da43 100644
--- a/freebsd/sbin/dhclient/privsep.h
+++ b/freebsd/sbin/dhclient/privsep.h
@@ -14,6 +14,8 @@
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
*/
#include <sys/types.h>
@@ -33,7 +35,8 @@ enum imsg_code {
IMSG_SCRIPT_INIT,
IMSG_SCRIPT_WRITE_PARAMS,
IMSG_SCRIPT_GO,
- IMSG_SCRIPT_GO_RET
+ IMSG_SCRIPT_GO_RET,
+ IMSG_SEND_PACKET
};
struct imsg_hdr {
diff --git a/freebsd/sbin/ifconfig/af_inet.c b/freebsd/sbin/ifconfig/af_inet.c
index 1d713eec..d464df52 100644
--- a/freebsd/sbin/ifconfig/af_inet.c
+++ b/freebsd/sbin/ifconfig/af_inet.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -34,7 +38,10 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
-#include <sys/types.h>
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
@@ -48,20 +55,25 @@ static const char rcsid[] =
#include <ifaddrs.h>
#include <netinet/in.h>
-#include <net/if_var.h> /* for struct ifaddr */
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-af_inet-data.h"
+#endif /* __rtems__ */
static struct in_aliasreq in_addreq;
static struct ifreq in_ridreq;
+static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
+extern char *f_inet, *f_addr;
static void
in_status(int s __unused, const struct ifaddrs *ifa)
{
struct sockaddr_in *sin, null_sin;
+ int error, n_flags;
memset(&null_sin, 0, sizeof(null_sin));
@@ -69,25 +81,56 @@ in_status(int s __unused, const struct ifaddrs *ifa)
if (sin == NULL)
return;
- printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+ if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
+ n_flags = 0;
+ else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
+ n_flags = NI_NOFQDN;
+ else
+ n_flags = NI_NUMERICHOST;
+
+ error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf,
+ sizeof(addr_buf), NULL, 0, n_flags);
+
+ if (error)
+ inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf));
+
+ printf("\tinet %s", addr_buf);
if (ifa->ifa_flags & IFF_POINTOPOINT) {
sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
if (sin == NULL)
sin = &null_sin;
- printf("--> %s ", inet_ntoa(sin->sin_addr));
+ printf(" --> %s ", inet_ntoa(sin->sin_addr));
}
sin = (struct sockaddr_in *)ifa->ifa_netmask;
if (sin == NULL)
sin = &null_sin;
- printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+ if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) {
+ int cidr = 32;
+ unsigned long smask;
+
+ smask = ntohl(sin->sin_addr.s_addr);
+ while ((smask & 1) == 0) {
+ smask = smask >> 1;
+ cidr--;
+ if (cidr == 0)
+ break;
+ }
+ printf("/%d ", cidr);
+ } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0)
+ printf(" netmask %s ", inet_ntoa(sin->sin_addr));
+ else
+ printf(" netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
if (ifa->ifa_flags & IFF_BROADCAST) {
sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
if (sin != NULL && sin->sin_addr.s_addr != 0)
- printf("broadcast %s", inet_ntoa(sin->sin_addr));
+ printf("broadcast %s ", inet_ntoa(sin->sin_addr));
}
+
+ print_vhid(ifa, " ");
+
putchar('\n');
}
@@ -100,7 +143,6 @@ static struct sockaddr_in *sintab[] = {
static void
in_getaddr(const char *s, int which)
{
-#define MIN(a,b) ((a)<(b)?(a):(b))
struct sockaddr_in *sin = sintab[which];
struct hostent *hp;
struct netent *np;
@@ -117,7 +159,11 @@ in_getaddr(const char *s, int which)
int masklen;
struct sockaddr_in *min = sintab[MASK];
*p = '\0';
+#ifndef __rtems__
+ if (!isdigit(*(p + 1)))
+#else /* __rtems__ */
if (!isdigit((unsigned char)*(p + 1)))
+#endif /* __rtems__ */
errstr = "invalid";
else
masklen = (int)strtonum(p + 1, 0, 32, &errstr);
@@ -134,14 +180,13 @@ in_getaddr(const char *s, int which)
if (inet_aton(s, &sin->sin_addr))
return;
- if ((hp = gethostbyname(s)) != 0)
+ if ((hp = gethostbyname(s)) != NULL)
bcopy(hp->h_addr, (char *)&sin->sin_addr,
MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
- else if ((np = getnetbyname(s)) != 0)
+ else if ((np = getnetbyname(s)) != NULL)
sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
else
errx(1, "%s: bad value", s);
-#undef MIN
}
static void
@@ -153,7 +198,7 @@ in_status_tunnel(int s)
const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, name, IFNAMSIZ);
+ strlcpy(ifr.ifr_name, name, IFNAMSIZ);
if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
return;
@@ -178,7 +223,7 @@ in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
struct in_aliasreq addreq;
memset(&addreq, 0, sizeof(addreq));
- strncpy(addreq.ifra_name, name, IFNAMSIZ);
+ strlcpy(addreq.ifra_name, name, IFNAMSIZ);
memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
@@ -211,11 +256,5 @@ inet_ctor(void)
if (!feature_present("inet"))
return;
#endif
-
-#ifdef __rtems__
- memset(&in_addreq, 0, sizeof(in_addreq));
- memset(&in_ridreq, 0, sizeof(in_ridreq));
-#endif /* __rtems__ */
-
af_register(&af_inet);
}
diff --git a/freebsd/sbin/ifconfig/af_inet6.c b/freebsd/sbin/ifconfig/af_inet6.c
index 0e099ada..f743ee8f 100644
--- a/freebsd/sbin/ifconfig/af_inet6.c
+++ b/freebsd/sbin/ifconfig/af_inet6.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -34,6 +38,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -45,12 +52,12 @@ static const char rcsid[] =
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <time.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <netinet/in.h>
-#include <net/if_var.h> /* for struct ifaddr */
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -58,23 +65,26 @@ static const char rcsid[] =
#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-af_inet6-data.h"
+#endif /* __rtems__ */
static struct in6_ifreq in6_ridreq;
-static struct in6_aliasreq in6_addreq =
- { .ifra_flags = 0,
+static struct in6_aliasreq in6_addreq =
+ { .ifra_flags = 0,
.ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
static int ip6lifetime;
-static void in6_fillscopeid(struct sockaddr_in6 *sin6);
static int prefix(void *, int);
static char *sec2str(time_t);
static int explicit_prefix = 0;
+extern char *f_inet6, *f_addr;
extern void setnd6flags(const char *, int, int, const struct afswtch *);
extern void setnd6defif(const char *, int, int, const struct afswtch *);
extern void nd6_status(int);
-static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
+static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
static void
setifprefixlen(const char *addr, int dummy __unused, int s,
@@ -102,20 +112,21 @@ static void
setip6lifetime(const char *cmd, const char *val, int s,
const struct afswtch *afp)
{
- time_t newval, t;
+ struct timespec now;
+ time_t newval;
char *ep;
- t = time(NULL);
+ clock_gettime(CLOCK_MONOTONIC_FAST, &now);
newval = (time_t)strtoul(val, &ep, 0);
if (val == ep)
errx(1, "invalid %s", cmd);
if (afp->af_af != AF_INET6)
errx(1, "%s not allowed for the AF", cmd);
if (strcmp(cmd, "vltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval;
in6_addreq.ifra_lifetime.ia6t_vltime = newval;
} else if (strcmp(cmd, "pltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval;
in6_addreq.ifra_lifetime.ia6t_pltime = newval;
}
}
@@ -169,18 +180,6 @@ setip6eui64(const char *cmd, int dummy __unused, int s,
}
static void
-in6_fillscopeid(struct sockaddr_in6 *sin6)
-{
-#if defined(__KAME__) && defined(KAME_SCOPEID)
- if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
- sin6->sin6_scope_id =
- ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
- sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
- }
-#endif
-}
-
-static void
in6_status(int s __unused, const struct ifaddrs *ifa)
{
struct sockaddr_in6 *sin, null_sin;
@@ -188,9 +187,10 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
int s6;
u_int32_t flags6;
struct in6_addrlifetime lifetime;
- time_t t = time(NULL);
- int error;
- u_int32_t scopeid;
+ struct timespec now;
+ int error, n_flags;
+
+ clock_gettime(CLOCK_MONOTONIC_FAST, &now);
memset(&null_sin, 0, sizeof(null_sin));
@@ -198,7 +198,7 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
if (sin == NULL)
return;
- strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
warn("socket(AF_INET6,SOCK_DGRAM)");
return;
@@ -220,24 +220,19 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
lifetime = ifr6.ifr_ifru.ifru_lifetime;
close(s6);
- /* XXX: embedded link local addr check */
- if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
- *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
- u_short index;
-
- index = *(u_short *)&sin->sin6_addr.s6_addr[2];
- *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
- if (sin->sin6_scope_id == 0)
- sin->sin6_scope_id = ntohs(index);
- }
- scopeid = sin->sin6_scope_id;
-
- error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
- sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
+ if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
+ n_flags = 0;
+ else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
+ n_flags = NI_NOFQDN;
+ else
+ n_flags = NI_NUMERICHOST;
+ error = getnameinfo((struct sockaddr *)sin, sin->sin6_len,
+ addr_buf, sizeof(addr_buf), NULL, 0,
+ n_flags);
if (error != 0)
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
sizeof(addr_buf));
- printf("\tinet6 %s ", addr_buf);
+ printf("\tinet6 %s", addr_buf);
if (ifa->ifa_flags & IFF_POINTOPOINT) {
sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
@@ -248,17 +243,6 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
if (sin != NULL && sin->sin6_family == AF_INET6) {
int error;
- /* XXX: embedded link local addr check */
- if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
- *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
- u_short index;
-
- index = *(u_short *)&sin->sin6_addr.s6_addr[2];
- *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
- if (sin->sin6_scope_id == 0)
- sin->sin6_scope_id = ntohs(index);
- }
-
error = getnameinfo((struct sockaddr *)sin,
sin->sin6_len, addr_buf,
sizeof(addr_buf), NULL, 0,
@@ -266,15 +250,19 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
if (error != 0)
inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
sizeof(addr_buf));
- printf("--> %s ", addr_buf);
+ printf(" --> %s ", addr_buf);
}
}
sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
if (sin == NULL)
sin = &null_sin;
- printf("prefixlen %d ", prefix(&sin->sin6_addr,
- sizeof(struct in6_addr)));
+ if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0)
+ printf("/%d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+ else
+ printf(" prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
if ((flags6 & IN6_IFF_ANYCAST) != 0)
printf("anycast ");
@@ -293,25 +281,30 @@ in6_status(int s __unused, const struct ifaddrs *ifa)
if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
printf("prefer_source ");
- if (scopeid)
- printf("scopeid 0x%x ", scopeid);
+ if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id)
+ printf("scopeid 0x%x ",
+ ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id);
if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
printf("pltime ");
if (lifetime.ia6t_preferred) {
- printf("%s ", lifetime.ia6t_preferred < t
- ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ printf("%s ", lifetime.ia6t_preferred < now.tv_sec
+ ? "0" :
+ sec2str(lifetime.ia6t_preferred - now.tv_sec));
} else
printf("infty ");
printf("vltime ");
if (lifetime.ia6t_expire) {
- printf("%s ", lifetime.ia6t_expire < t
- ? "0" : sec2str(lifetime.ia6t_expire - t));
+ printf("%s ", lifetime.ia6t_expire < now.tv_sec
+ ? "0" :
+ sec2str(lifetime.ia6t_expire - now.tv_sec));
} else
printf("infty ");
}
+ print_vhid(ifa, " ");
+
putchar('\n');
}
@@ -389,25 +382,25 @@ done:
static int
prefix(void *val, int size)
{
- u_char *name = (u_char *)val;
- int byte, bit, plen = 0;
+ u_char *name = (u_char *)val;
+ int byte, bit, plen = 0;
- for (byte = 0; byte < size; byte++, plen += 8)
- if (name[byte] != 0xff)
- break;
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
if (byte == size)
return (plen);
for (bit = 7; bit != 0; bit--, plen++)
- if (!(name[byte] & (1 << bit)))
- break;
- for (; bit != 0; bit--)
- if (name[byte] & (1 << bit))
- return(0);
- byte++;
- for (; byte < size; byte++)
- if (name[byte])
- return(0);
- return (plen);
+ if (!(name[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (name[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (name[byte])
+ return(0);
+ return (plen);
}
static char *
@@ -464,13 +457,12 @@ in6_status_tunnel(int s)
const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
memset(&in6_ifr, 0, sizeof(in6_ifr));
- strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
+ strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
return;
if (sa->sa_family != AF_INET6)
return;
- in6_fillscopeid(&in6_ifr.ifr_addr);
if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
NI_NUMERICHOST) != 0)
src[0] = '\0';
@@ -479,7 +471,6 @@ in6_status_tunnel(int s)
return;
if (sa->sa_family != AF_INET6)
return;
- in6_fillscopeid(&in6_ifr.ifr_addr);
if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
NI_NUMERICHOST) != 0)
dst[0] = '\0';
@@ -493,7 +484,7 @@ in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
struct in6_aliasreq in6_addreq;
memset(&in6_addreq, 0, sizeof(in6_addreq));
- strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
+ strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
dstres->ai_addr->sa_len);
@@ -527,6 +518,8 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags),
DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags),
+ DEF_CMD("no_dad", ND6_IFF_NO_DAD, setnd6flags),
+ DEF_CMD("-no_dad", -ND6_IFF_NO_DAD, setnd6flags),
DEF_CMD_ARG("pltime", setip6pltime),
DEF_CMD_ARG("vltime", setip6vltime),
DEF_CMD("eui64", 0, setip6eui64),
@@ -553,7 +546,11 @@ in6_Lopt_cb(const char *optarg __unused)
{
ip6lifetime++; /* print IPv6 address lifetime */
}
-static struct option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb };
+static struct option in6_Lopt = {
+ .opt = "L",
+ .opt_usage = "[-L]",
+ .cb = in6_Lopt_cb
+};
#ifndef __rtems__
static __constructor void
@@ -562,16 +559,6 @@ void
#endif /* __rtems__ */
inet6_ctor(void)
{
-#ifdef __rtems__
- memset(&in6_ridreq, 0, sizeof(in6_ridreq));
- memset(&in6_addreq, 0, sizeof(in6_addreq));
- in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
- in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
- ip6lifetime = 0;
- explicit_prefix = 0;
- memset(&addr_buf, 0, sizeof(addr_buf));
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
#ifndef RESCUE
@@ -579,9 +566,8 @@ inet6_ctor(void)
return;
#endif
- for (i = 0; i < N(inet6_cmds); i++)
+ for (i = 0; i < nitems(inet6_cmds); i++)
cmd_register(&inet6_cmds[i]);
af_register(&af_inet6);
opt_register(&in6_Lopt);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/af_link.c b/freebsd/sbin/ifconfig/af_link.c
index ffd92e30..1c37496e 100644
--- a/freebsd/sbin/ifconfig/af_link.c
+++ b/freebsd/sbin/ifconfig/af_link.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -34,6 +38,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -50,23 +57,35 @@ static const char rcsid[] =
#include <net/ethernet.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-af_link-data.h"
+#endif /* __rtems__ */
static struct ifreq link_ridreq;
+extern char *f_ether;
+
static void
link_status(int s __unused, const struct ifaddrs *ifa)
{
/* XXX no const 'cuz LLADDR is defined wrong */
struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ char *ether_format, *format_char;
if (sdl != NULL && sdl->sdl_alen > 0) {
if ((sdl->sdl_type == IFT_ETHER ||
sdl->sdl_type == IFT_L2VLAN ||
sdl->sdl_type == IFT_BRIDGE) &&
- sdl->sdl_alen == ETHER_ADDR_LEN)
- printf("\tether %s\n",
- ether_ntoa((struct ether_addr *)LLADDR(sdl)));
- else {
+ sdl->sdl_alen == ETHER_ADDR_LEN) {
+ ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl));
+ if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
+ for (format_char = strchr(ether_format, ':');
+ format_char != NULL;
+ format_char = strchr(ether_format, ':'))
+ *format_char = '-';
+ }
+ printf("\tether %s\n", ether_format);
+ } else {
int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
printf("\tlladdr %s\n", link_ntoa(sdl) + n);
@@ -129,9 +148,6 @@ void
#endif /* __rtems__ */
link_ctor(void)
{
-#ifdef __rtems__
- memset(&link_ridreq, 0, sizeof(link_ridreq));
-#endif /* __rtems__ */
af_register(&af_link);
af_register(&af_ether);
af_register(&af_lladdr);
diff --git a/freebsd/sbin/ifconfig/af_nd6.c b/freebsd/sbin/ifconfig/af_nd6.c
index a1e930b0..ac302c65 100644
--- a/freebsd/sbin/ifconfig/af_nd6.c
+++ b/freebsd/sbin/ifconfig/af_nd6.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 2009 Hiroki Sato. All rights reserved.
*
@@ -30,6 +34,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -48,7 +55,6 @@ static const char rcsid[] =
#include <arpa/inet.h>
#include <netinet/in.h>
-#include <net/if_var.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -56,11 +62,15 @@ static const char rcsid[] =
#include <netinet6/nd6.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-af_nd6-data.h"
+#endif /* __rtems__ */
#define MAX_SYSCTL_TRY 5
#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
"\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \
- "\007NO_RADR\010NO_PREFER_IFACE\020DEFAULTIF"
+ "\007NO_RADR\010NO_PREFER_IFACE\011IGNORELOOP\012NO_DAD" \
+ "\020DEFAULTIF"
static int isnd6defif(int);
void setnd6flags(const char *, int, int, const struct afswtch *);
@@ -76,7 +86,7 @@ setnd6flags(const char *dummyaddr __unused,
int error;
memset(&nd, 0, sizeof(nd));
- strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
error = ioctl(s, SIOCGIFINFO_IN6, &nd);
if (error) {
warn("ioctl(SIOCGIFINFO_IN6)");
@@ -101,7 +111,7 @@ setnd6defif(const char *dummyaddr __unused,
int error;
memset(&ndifreq, 0, sizeof(ndifreq));
- strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
+ strlcpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
if (d < 0) {
if (isnd6defif(s)) {
@@ -128,7 +138,7 @@ isnd6defif(int s)
int error;
memset(&ndifreq, 0, sizeof(ndifreq));
- strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
+ strlcpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
ifindex = if_nametoindex(ndifreq.ifname);
error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq);
@@ -148,7 +158,7 @@ nd6_status(int s)
int isdefif;
memset(&nd, 0, sizeof(nd));
- strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
warn("socket(AF_INET6, SOCK_DGRAM)");
diff --git a/freebsd/sbin/ifconfig/ifbridge.c b/freebsd/sbin/ifconfig/ifbridge.c
index 9a4d868d..26412a02 100644
--- a/freebsd/sbin/ifconfig/ifbridge.c
+++ b/freebsd/sbin/ifconfig/ifbridge.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
* Copyright 2001 Wasabi Systems, Inc.
* All rights reserved.
@@ -40,6 +44,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -62,6 +69,9 @@ static const char rcsid[] =
#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifbridge-data.h"
+#endif /* __rtems__ */
#define PV2ID(pv, epri, eaddr) do { \
epri = pv >> 48; \
@@ -73,7 +83,7 @@ static const char rcsid[] =
eaddr[5] = pv >> 0; \
} while (0)
-static const char *const stpstates[] = {
+static const char *stpstates[] = {
"disabled",
"listening",
"learning",
@@ -81,12 +91,12 @@ static const char *const stpstates[] = {
"blocking",
"discarding"
};
-static const char *const stpproto[] = {
+static const char *stpproto[] = {
"stp",
"-",
"rstp"
};
-static const char *const stproles[] = {
+static const char *stproles[] = {
"disabled",
"root",
"designated",
@@ -157,7 +167,11 @@ bridge_interfaces(int s, const char *prefix)
err(1, "strdup");
/* replace the prefix with whitespace */
for (p = pad; *p != '\0'; p++) {
+#ifndef __rtems__
+ if(isprint(*p))
+#else /* __rtems__ */
if(isprint((unsigned char)*p))
+#endif /* __rtems__ */
*p = ' ';
}
@@ -187,22 +201,19 @@ bridge_interfaces(int s, const char *prefix)
printf(" path cost %u", req->ifbr_path_cost);
if (req->ifbr_ifsflags & IFBIF_STP) {
- if (req->ifbr_proto <
- sizeof(stpproto) / sizeof(stpproto[0]))
+ if (req->ifbr_proto < nitems(stpproto))
printf(" proto %s", stpproto[req->ifbr_proto]);
else
printf(" <unknown proto %d>",
req->ifbr_proto);
printf("\n%s", pad);
- if (req->ifbr_role <
- sizeof(stproles) / sizeof(stproles[0]))
+ if (req->ifbr_role < nitems(stproles))
printf("role %s", stproles[req->ifbr_role]);
else
printf("<unknown role %d>",
req->ifbr_role);
- if (req->ifbr_state <
- sizeof(stpstates) / sizeof(stpstates[0]))
+ if (req->ifbr_state < nitems(stpstates))
printf(" state %s", stpstates[req->ifbr_state]);
else
printf(" <unknown state %d>",
@@ -755,11 +766,9 @@ void
#endif /* __rtems__ */
bridge_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
- for (i = 0; i < N(bridge_cmds); i++)
+ for (i = 0; i < nitems(bridge_cmds); i++)
cmd_register(&bridge_cmds[i]);
af_register(&af_bridge);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifcarp.c b/freebsd/sbin/ifconfig/ifcarp.c
index d0f3616d..61e3fa36 100644
--- a/freebsd/sbin/ifconfig/ifcarp.c
+++ b/freebsd/sbin/ifconfig/ifcarp.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/* $FreeBSD$ */
/* from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */
@@ -29,6 +33,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -51,6 +58,9 @@
#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifcarp-data.h"
+#endif /* __rtems__ */
static const char *const carp_states[] = { CARP_STATES };
diff --git a/freebsd/sbin/ifconfig/ifclone.c b/freebsd/sbin/ifconfig/ifclone.c
index 8fb9d6c3..6dcd344c 100644
--- a/freebsd/sbin/ifconfig/ifclone.c
+++ b/freebsd/sbin/ifconfig/ifclone.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -35,20 +39,11 @@ static const char rcsid[] =
#endif /* not lint */
#ifdef __rtems__
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#endif /* __rtems__ */
-#include <sys/queue.h>
-#include <sys/types.h>
+#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
+#include <sys/queue.h>
#include <sys/socket.h>
#include <net/if.h>
@@ -59,6 +54,9 @@ static const char rcsid[] =
#include <unistd.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifclone-data.h"
+#endif /* __rtems__ */
static void
list_cloners(void)
@@ -84,10 +82,8 @@ list_cloners(void)
ifcr.ifcr_count = ifcr.ifcr_total;
ifcr.ifcr_buffer = buf;
- if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) {
- free(buf);
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
err(1, "SIOCIFGCLONERS for names");
- }
/*
* In case some disappeared in the mean time, clamp it down.
@@ -111,7 +107,11 @@ struct clone_defcb {
SLIST_ENTRY(clone_defcb) next;
};
+#ifndef __rtems__
static SLIST_HEAD(, clone_defcb) clone_defcbh =
+#else /* __rtems__ */
+static SLIST_HEAD(clone_defcb_list, clone_defcb) clone_defcbh =
+#endif /* __rtems__ */
SLIST_HEAD_INITIALIZER(clone_defcbh);
void
@@ -165,11 +165,12 @@ ifclonecreate(int s, void *arg)
}
/*
- * If we get a different name back than we put in, print it.
+ * If we get a different name back than we put in, update record and
+ * indicate it should be printed later.
*/
if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
strlcpy(name, ifr.ifr_name, sizeof(name));
- printf("%s\n", name);
+ printifname = 1;
}
}
@@ -182,7 +183,7 @@ DECL_CMD_FUNC(clone_create, arg, d)
static
DECL_CMD_FUNC(clone_destroy, arg, d)
{
- (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
err(1, "SIOCIFDESTROY");
}
@@ -209,26 +210,9 @@ void
#endif /* __rtems__ */
clone_ctor(void)
{
-#ifdef __rtems__
- SLIST_INIT(&clone_defcbh);
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(clone_cmds); i++)
+ for (i = 0; i < nitems(clone_cmds); i++)
cmd_register(&clone_cmds[i]);
opt_register(&clone_Copt);
-#undef N
}
-#ifdef __rtems__
-void
-clone_dtor(void)
-{
- struct clone_defcb *dcp;
- struct clone_defcb *dcp_tmp;
-
- SLIST_FOREACH_SAFE(dcp, &clone_defcbh, next, dcp_tmp) {
- free(dcp);
- }
-}
-#endif /* __rtems__ */
diff --git a/freebsd/sbin/ifconfig/ifconfig.c b/freebsd/sbin/ifconfig/ifconfig.c
index 041e53d0..ad199be8 100644
--- a/freebsd/sbin/ifconfig/ifconfig.c
+++ b/freebsd/sbin/ifconfig/ifconfig.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
@@ -48,28 +52,19 @@ static const char rcsid[] =
#define option getopt_option
#include <getopt.h>
#undef option
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#include <machine/rtems-bsd-commands.h>
#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/time.h>
#include <sys/module.h>
#include <sys/linker.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/time.h>
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
@@ -85,13 +80,18 @@ static const char rcsid[] =
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#ifdef JAIL
#include <jail.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifconfig-data.h"
+#endif /* __rtems__ */
/*
* Since "struct ifreq" is composed of various union members, callers
@@ -110,10 +110,14 @@ int clearaddr;
int newaddr = 1;
int verbose;
int noload;
+int printifname = 0;
int supmedia = 0;
int printkeys = 0; /* Print keying material for interfaces. */
+/* Formatter Strings */
+char *f_inet, *f_inet6, *f_ether, *f_addr;
+
static int ifconfig(int argc, char *const *argv, int iscreate,
const struct afswtch *afp);
static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
@@ -125,8 +129,19 @@ static struct afswtch *af_getbyname(const char *name);
static struct afswtch *af_getbyfamily(int af);
static void af_other_status(int);
+void printifnamemaybe(void);
+
static struct option *opts = NULL;
+struct ifa_order_elt {
+ int if_order;
+ int af_orders[255];
+ struct ifaddrs *ifa;
+ TAILQ_ENTRY(ifa_order_elt) link;
+};
+
+TAILQ_HEAD(ifa_queue, ifa_order_elt);
+
void
opt_register(struct option *p)
{
@@ -148,8 +163,8 @@ usage(void)
}
fprintf(stderr,
- "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
- " [parameters]\n"
+ "usage: ifconfig [-f type:format] %sinterface address_family\n"
+ " [address [dest_address]] [parameters]\n"
" ifconfig interface create\n"
" ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
" ifconfig -l [-d] [-u] [address_family]\n"
@@ -158,39 +173,241 @@ usage(void)
exit(1);
}
+#define ORDERS_SIZE(x) sizeof(x) / sizeof(x[0])
+
+static int
+calcorders(struct ifaddrs *ifa, struct ifa_queue *q)
+{
+ struct ifaddrs *prev;
+ struct ifa_order_elt *cur;
+ unsigned int ord, af, ifa_ord;
+
+ prev = NULL;
+ cur = NULL;
+ ord = 0;
+ ifa_ord = 0;
+
+ while (ifa != NULL) {
+ if (prev == NULL ||
+ strcmp(ifa->ifa_name, prev->ifa_name) != 0) {
+ cur = calloc(1, sizeof(*cur));
+
+ if (cur == NULL)
+ return (-1);
+
+ TAILQ_INSERT_TAIL(q, cur, link);
+ cur->if_order = ifa_ord ++;
+ cur->ifa = ifa;
+ ord = 0;
+ }
+
+ if (ifa->ifa_addr) {
+ af = ifa->ifa_addr->sa_family;
+
+ if (af < ORDERS_SIZE(cur->af_orders) &&
+ cur->af_orders[af] == 0)
+ cur->af_orders[af] = ++ord;
+ }
+ prev = ifa;
+ ifa = ifa->ifa_next;
+ }
+
+ return (0);
+}
+
+static int
+cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q)
+{
+ struct ifa_order_elt *cur, *e1, *e2;
+ unsigned int af1, af2;
+ int ret;
+
+ e1 = e2 = NULL;
+
+ ret = strcmp(a->ifa_name, b->ifa_name);
+ if (ret != 0) {
+ TAILQ_FOREACH(cur, q, link) {
+ if (e1 && e2)
+ break;
+
+ if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0)
+ e1 = cur;
+ else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0)
+ e2 = cur;
+ }
+
+ if (!e1 || !e2)
+ return (0);
+ else
+ return (e1->if_order - e2->if_order);
+
+ } else if (a->ifa_addr != NULL && b->ifa_addr != NULL) {
+ TAILQ_FOREACH(cur, q, link) {
+ if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) {
+ e1 = cur;
+ break;
+ }
+ }
+
+ if (!e1)
+ return (0);
+
+ af1 = a->ifa_addr->sa_family;
+ af2 = b->ifa_addr->sa_family;
+
+ if (af1 < ORDERS_SIZE(e1->af_orders) &&
+ af2 < ORDERS_SIZE(e1->af_orders))
+ return (e1->af_orders[af1] - e1->af_orders[af2]);
+ }
+
+ return (0);
+}
+
+static void freeformat(void)
+{
+
+ if (f_inet != NULL)
+ free(f_inet);
+ if (f_inet6 != NULL)
+ free(f_inet6);
+ if (f_ether != NULL)
+ free(f_ether);
+ if (f_addr != NULL)
+ free(f_addr);
+}
+
+static void setformat(char *input)
+{
+ char *formatstr, *category, *modifier;
+
+ formatstr = strdup(input);
+ while ((category = strsep(&formatstr, ",")) != NULL) {
+ modifier = strchr(category, ':');
+ if (modifier == NULL || modifier[1] == '\0') {
+ warnx("Skipping invalid format specification: %s\n",
+ category);
+ continue;
+ }
+
+ /* Split the string on the separator, then seek past it */
+ modifier[0] = '\0';
+ modifier++;
+
+ if (strcmp(category, "addr") == 0)
+ f_addr = strdup(modifier);
+ else if (strcmp(category, "ether") == 0)
+ f_ether = strdup(modifier);
+ else if (strcmp(category, "inet") == 0)
+ f_inet = strdup(modifier);
+ else if (strcmp(category, "inet6") == 0)
+ f_inet6 = strdup(modifier);
+ }
+ free(formatstr);
+}
+
+#undef ORDERS_SIZE
+
+static struct ifaddrs *
+sortifaddrs(struct ifaddrs *list,
+ int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *),
+ struct ifa_queue *q)
+{
+ struct ifaddrs *right, *temp, *last, *result, *next, *tail;
+
+ right = list;
+ temp = list;
+ last = list;
+ result = NULL;
+ next = NULL;
+ tail = NULL;
+
+ if (!list || !list->ifa_next)
+ return (list);
+
+ while (temp && temp->ifa_next) {
+ last = right;
+ right = right->ifa_next;
+ temp = temp->ifa_next->ifa_next;
+ }
+
+ last->ifa_next = NULL;
+
+ list = sortifaddrs(list, compare, q);
+ right = sortifaddrs(right, compare, q);
+
+ while (list || right) {
+
+ if (!right) {
+ next = list;
+ list = list->ifa_next;
+ } else if (!list) {
+ next = right;
+ right = right->ifa_next;
+ } else if (compare(list, right, q) <= 0) {
+ next = list;
+ list = list->ifa_next;
+ } else {
+ next = right;
+ right = right->ifa_next;
+ }
+
+ if (!result)
+ result = next;
+ else
+ tail->ifa_next = next;
+
+ tail = next;
+ }
+
+ return (result);
+}
+
+void printifnamemaybe()
+{
+ if (printifname)
+ printf("%s\n", name);
+}
+
#ifdef __rtems__
static void ifconfig_ctor(void);
-static void ifconfig_dtor(void);
static int main(int argc, char *argv[]);
-int rtems_bsd_command_ifconfig(int argc, char *argv[])
+static int
+mainwrapper(int argc, char *argv[])
{
- int exit_code;
-
- rtems_bsd_program_lock();
-
ifconfig_ctor();
-
bridge_ctor();
- carp_ctor();
clone_ctor();
gif_ctor();
gre_ctor();
group_ctor();
ifmedia_ctor();
- inet_ctor();
inet6_ctor();
+ inet_ctor();
lagg_ctor();
link_ctor();
mac_ctor();
pfsync_ctor();
vlan_ctor();
- exit_code = rtems_bsd_program_call_main("ifconfig", main, argc, argv);
+ return main(argc, argv);
+}
+
+RTEMS_LINKER_RWSET(bsd_prog_ifconfig, char);
+
+int
+rtems_bsd_command_ifconfig(int argc, char *argv[])
+{
+ int exit_code;
+ const void *data_begin;
+ size_t data_size;
- clone_dtor();
- ifconfig_dtor();
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ifconfig);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ifconfig);
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("ifconfig",
+ mainwrapper, argc, argv, data_begin, data_size);
rtems_bsd_program_unlock();
return exit_code;
@@ -202,10 +419,12 @@ main(int argc, char *argv[])
int c, all, namesonly, downonly, uponly;
const struct afswtch *afp = NULL;
int ifindex;
- struct ifaddrs *ifap, *ifa;
+ struct ifaddrs *ifap, *sifap, *ifa;
struct ifreq paifr;
const struct sockaddr_dl *sdl;
- char options[1024], *cp, *namecp = NULL;
+ char options[1024], *cp, *envformat, *namecp = NULL;
+ struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q);
+ struct ifa_order_elt *cur, *tmp;
const char *ifname;
struct option *p;
size_t iflen;
@@ -220,12 +439,23 @@ main(int argc, char *argv[])
#endif /* __rtems__ */
all = downonly = uponly = namesonly = noload = verbose = 0;
+ f_inet = f_inet6 = f_ether = f_addr = NULL;
+
+ envformat = getenv("IFCONFIG_FORMAT");
+ if (envformat != NULL)
+ setformat(envformat);
+
+ /*
+ * Ensure we print interface name when expected to,
+ * even if we terminate early due to error.
+ */
+ atexit(printifnamemaybe);
/* Parse leading line options */
#ifndef __rtems__
- strlcpy(options, "adklmnuv", sizeof(options));
+ strlcpy(options, "f:adklmnuv", sizeof(options));
#else /* __rtems__ */
- strlcpy(options, "+adklmnuv", sizeof(options));
+ strlcpy(options, "+f:adklmnuv", sizeof(options));
#endif /* __rtems__ */
for (p = opts; p != NULL; p = p->next)
strlcat(options, p->opt, sizeof(options));
@@ -237,6 +467,11 @@ main(int argc, char *argv[])
case 'd': /* restrict scan to "down" interfaces */
downonly++;
break;
+ case 'f':
+ if (optarg == NULL)
+ usage();
+ setformat(optarg);
+ break;
case 'k':
printkeys++;
break;
@@ -325,6 +560,7 @@ main(int argc, char *argv[])
ifconfig(argc, argv, 1, NULL);
exit(0);
}
+#ifdef JAIL
/*
* NOTE: We have to special-case the `-vnet' command
* right here as we would otherwise fail when trying
@@ -338,6 +574,7 @@ main(int argc, char *argv[])
ifconfig(argc, argv, 0, NULL);
exit(0);
}
+#endif
errx(1, "interface %s does not exist", ifname);
}
}
@@ -351,11 +588,21 @@ main(int argc, char *argv[])
if (getifaddrs(&ifap) != 0)
err(EXIT_FAILURE, "getifaddrs");
+
cp = NULL;
+
+ if (calcorders(ifap, &q) != 0)
+ err(EXIT_FAILURE, "calcorders");
+
+ sifap = sortifaddrs(ifap, cmpifaddrs, &q);
+
+ TAILQ_FOREACH_SAFE(cur, &q, link, tmp)
+ free(cur);
+
ifindex = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ for (ifa = sifap; ifa; ifa = ifa->ifa_next) {
memset(&paifr, 0, sizeof(paifr));
- strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
+ strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
memcpy(&paifr.ifr_addr, ifa->ifa_addr,
ifa->ifa_addr->sa_len);
@@ -399,7 +646,8 @@ main(int argc, char *argv[])
sdl->sdl_alen != ETHER_ADDR_LEN)
continue;
} else {
- if (ifa->ifa_addr->sa_family != afp->af_af)
+ if (ifa->ifa_addr->sa_family
+ != afp->af_af)
continue;
}
}
@@ -421,6 +669,7 @@ main(int argc, char *argv[])
printf("\n");
freeifaddrs(ifap);
+ freeformat();
exit(0);
}
@@ -501,7 +750,6 @@ cmd_register(struct cmd *p)
static const struct cmd *
cmd_lookup(const char *name, int iscreate)
{
-#define N(a) (sizeof(a)/sizeof(a[0]))
const struct cmd *p;
for (p = cmds; p != NULL; p = p->c_next)
@@ -515,7 +763,6 @@ cmd_lookup(const char *name, int iscreate)
}
}
return NULL;
-#undef N
}
struct callback {
@@ -555,7 +802,7 @@ ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
struct callback *cb;
int s;
- strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
afp = NULL;
if (uafp != NULL)
afp = uafp;
@@ -586,7 +833,7 @@ top:
AF_LOCAL : afp->af_af;
if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 &&
- (uafp != NULL || errno != EPROTONOSUPPORT ||
+ (uafp != NULL || errno != EAFNOSUPPORT ||
(s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0))
err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
@@ -676,7 +923,8 @@ top:
}
if (clearaddr) {
int ret;
- strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+ strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, name,
+ sizeof ifr.ifr_name);
ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
if (ret < 0) {
if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
@@ -693,7 +941,8 @@ top:
}
}
if (newaddr && (setaddr || setmask)) {
- strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+ strlcpy(((struct ifreq *)afp->af_addreq)->ifr_name, name,
+ sizeof ifr.ifr_name);
if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
Perror("ioctl (SIOCAIFADDR)");
}
@@ -735,7 +984,7 @@ settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
errx(1, "error in parsing address string: %s",
gai_strerror(ecode));
- if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
+ if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
errx(1, "error in parsing address string: %s",
gai_strerror(ecode));
@@ -758,7 +1007,7 @@ deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
err(1, "SIOCDIFPHYADDR");
}
-#ifndef __rtems__
+#ifdef JAIL
static void
setifvnet(const char *jname, int dummy __unused, int s,
const struct afswtch *afp)
@@ -786,7 +1035,7 @@ setifrvnet(const char *jname, int dummy __unused, int s,
if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0)
err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name);
}
-#endif /* __rtems__ */
+#endif
static void
setifnetmask(const char *addr, int dummy __unused, int s,
@@ -807,20 +1056,6 @@ setifbroadaddr(const char *addr, int dummy __unused, int s,
}
static void
-setifipdst(const char *addr, int dummy __unused, int s,
- const struct afswtch *afp)
-{
- const struct afswtch *inet;
-
- inet = af_getbyname("inet");
- if (inet == NULL)
- return;
- inet->af_getaddr(addr, DSTADDR);
- clearaddr = 0;
- newaddr = 0;
-}
-
-static void
notealias(const char *addr, int param, int s, const struct afswtch *afp)
{
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
@@ -903,20 +1138,20 @@ static void
setifmetric(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
- strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_metric = atoi(val);
if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
- warn("ioctl (set metric)");
+ err(1, "ioctl SIOCSIFMETRIC (set metric)");
}
static void
setifmtu(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
- strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = atoi(val);
if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
- warn("ioctl (set mtu)");
+ err(1, "ioctl SIOCSIFMTU (set mtu)");
}
static void
@@ -924,18 +1159,18 @@ setifname(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
char *newname;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
newname = strdup(val);
- if (newname == NULL) {
- warn("no memory to set ifname");
- return;
- }
+ if (newname == NULL)
+ err(1, "no memory to set ifname");
ifr.ifr_data = newname;
if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
- warn("ioctl (set name)");
free(newname);
- return;
+ err(1, "ioctl SIOCSIFNAME (set name)");
}
+ printifname = 1;
strlcpy(name, newname, sizeof(name));
free(newname);
}
@@ -947,6 +1182,8 @@ setifdescr(const char *val, int dummy __unused, int s,
{
char *newdescr;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
ifr.ifr_buffer.length = strlen(val) + 1;
if (ifr.ifr_buffer.length == 1) {
ifr.ifr_buffer.buffer = newdescr = NULL;
@@ -961,7 +1198,7 @@ setifdescr(const char *val, int dummy __unused, int s,
}
if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0)
- warn("ioctl (set descr)");
+ err(1, "ioctl SIOCSIFDESCR (set descr)");
free(newdescr);
}
@@ -975,7 +1212,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
}
#define IFFBITS \
-"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \
"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
@@ -1009,7 +1246,7 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
ifr.ifr_addr.sa_family =
afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af;
}
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
if (s < 0)
@@ -1091,10 +1328,13 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
else if (afp->af_other_status != NULL)
afp->af_other_status(s);
- strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+ strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
printf("%s", ifs.ascii);
+ if (verbose > 0)
+ sfp_status(s, &ifr, verbose);
+
close(s);
return;
}
@@ -1155,6 +1395,21 @@ printb(const char *s, unsigned v, const char *bits)
}
void
+print_vhid(const struct ifaddrs *ifa, const char *s)
+{
+ struct if_data *ifd;
+
+ if (ifa->ifa_data == NULL)
+ return;
+
+ ifd = ifa->ifa_data;
+ if (ifd->ifi_vhid == 0)
+ return;
+
+ printf("vhid %d ", ifd->ifi_vhid);
+}
+
+void
ifmaybeload(const char *name)
{
#ifndef __rtems__
@@ -1177,9 +1432,8 @@ ifmaybeload(const char *name)
}
/* turn interface and unit into module name */
- strcpy(ifkind, "if_");
- strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
- sizeof(ifkind) - MOD_PREFIX_LEN);
+ strlcpy(ifkind, "if_", sizeof(ifkind));
+ strlcat(ifkind, ifname, sizeof(ifkind));
/* scan files in kernel */
mstat.version = sizeof(struct module_stat);
@@ -1196,8 +1450,8 @@ ifmaybeload(const char *name)
cp = mstat.name;
}
/* already loaded? */
- if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
- strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
+ if (strcmp(ifname, cp) == 0 ||
+ strcmp(ifkind, cp) == 0)
return;
}
}
@@ -1233,14 +1487,13 @@ static struct cmd basic_cmds[] = {
DEF_CMD_ARG("netmask", setifnetmask),
DEF_CMD_ARG("metric", setifmetric),
DEF_CMD_ARG("broadcast", setifbroadaddr),
- DEF_CMD_ARG("ipdst", setifipdst),
DEF_CMD_ARG2("tunnel", settunnel),
DEF_CMD("-tunnel", 0, deletetunnel),
DEF_CMD("deletetunnel", 0, deletetunnel),
-#ifndef __rtems__
+#ifdef JAIL
DEF_CMD_ARG("vnet", setifvnet),
DEF_CMD_ARG("-vnet", setifrvnet),
-#endif /* __rtems__ */
+#endif
DEF_CMD("link0", IFF_LINK0, setifflags),
DEF_CMD("-link0", -IFF_LINK0, setifflags),
DEF_CMD("link1", IFF_LINK1, setifflags),
@@ -1288,48 +1541,15 @@ static struct cmd basic_cmds[] = {
DEF_CMD_ARG("name", setifname),
};
+#ifndef __rtems__
static __constructor void
+#else /* __rtems__ */
+static void
+#endif /* __rtems__ */
ifconfig_ctor(void)
{
-#ifdef __rtems__
- memset(&ifr, 0, sizeof(ifr));
- memset(&name, 0, sizeof(name));
- descr = NULL;
- descrlen = 64;
- setaddr = 0;
- setmask = 0;
- doalias = 0;
- clearaddr = 0;
- newaddr = 1;
- verbose = 0;
- noload = 0;
- supmedia = 0;
- printkeys = 0;
- opts = NULL;
- afs = NULL;
- callbacks = NULL;
- cmds = NULL;
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(basic_cmds); i++)
+ for (i = 0; i < nitems(basic_cmds); i++)
cmd_register(&basic_cmds[i]);
-#undef N
-}
-#ifdef __rtems__
-static void
-ifconfig_dtor(void)
-{
- struct callback *cb = callbacks;
-
- while (cb != NULL) {
- struct callback *to_free = cb;
-
- cb = to_free->cb_next;
- free(to_free);
- }
-
- free(descr);
}
-#endif /* __rtems__ */
diff --git a/freebsd/sbin/ifconfig/ifconfig.h b/freebsd/sbin/ifconfig/ifconfig.h
index 074e810e..d9be9c7b 100644
--- a/freebsd/sbin/ifconfig/ifconfig.h
+++ b/freebsd/sbin/ifconfig/ifconfig.h
@@ -34,11 +34,7 @@
* $FreeBSD$
*/
-#ifndef __rtems__
#define __constructor __attribute__((constructor))
-#else /* __rtems__ */
-#define __constructor
-#endif /* __rtems__ */
struct afswtch;
struct cmd;
@@ -78,6 +74,7 @@ void callback_register(callback_func *, void *);
#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 0, NULL }
#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1, NULL }
#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1, NULL }
+#define DEF_CLONE_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 1, NULL }
struct ifaddrs;
struct addrinfo;
@@ -136,6 +133,7 @@ extern int supmedia;
extern int printkeys;
extern int newaddr;
extern int verbose;
+extern int printifname;
void setifcap(const char *, int value, int s, const struct afswtch *);
@@ -147,19 +145,23 @@ void ifmaybeload(const char *name);
typedef void clone_callback_func(int, struct ifreq *);
void clone_setdefcallback(const char *, clone_callback_func *);
+void sfp_status(int s, struct ifreq *ifr, int verbose);
+
/*
* XXX expose this so modules that neeed to know of any pending
* operations on ifmedia can avoid cmd line ordering confusion.
*/
struct ifmediareq *ifmedia_getstate(int s);
+
+void print_vhid(const struct ifaddrs *, const char *);
#ifdef __rtems__
-void atalk_ctor(void);
void bridge_ctor(void);
void carp_ctor(void);
void clone_ctor(void);
void gif_ctor(void);
void gre_ctor(void);
void group_ctor(void);
+void ieee80211_ctor(void);
void ifmedia_ctor(void);
void inet6_ctor(void);
void inet_ctor(void);
@@ -169,5 +171,6 @@ void mac_ctor(void);
void pfsync_ctor(void);
void vlan_ctor(void);
-void clone_dtor(void);
+/* Necessary for struct ifmedia_description */
+#include <if_media.h>
#endif /* __rtems__ */
diff --git a/freebsd/sbin/ifconfig/ifgif.c b/freebsd/sbin/ifconfig/ifgif.c
index e55933a5..c13a0506 100644
--- a/freebsd/sbin/ifconfig/ifgif.c
+++ b/freebsd/sbin/ifconfig/ifgif.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
* Copyright (c) 2009 Hiroki Sato. All rights reserved.
*
@@ -30,6 +34,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -52,8 +59,11 @@ static const char rcsid[] =
#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifgif-data.h"
+#endif /* __rtems__ */
-#define GIFBITS "\020\1ACCEPT_REV_ETHIP_VER\5SEND_REV_ETHIP_VER"
+#define GIFBITS "\020\2IGNORE_SOURCE"
static void gif_status(int);
@@ -72,8 +82,7 @@ gif_status(int s)
}
static void
-setgifopts(const char *val,
- int d, int s, const struct afswtch *afp)
+setgifopts(const char *val, int d, int s, const struct afswtch *afp)
{
int opts;
@@ -95,10 +104,8 @@ setgifopts(const char *val,
}
static struct cmd gif_cmds[] = {
- DEF_CMD("accept_rev_ethip_ver", GIF_ACCEPT_REVETHIP, setgifopts),
- DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP, setgifopts),
- DEF_CMD("send_rev_ethip_ver", GIF_SEND_REVETHIP, setgifopts),
- DEF_CMD("-send_rev_ethip_ver", -GIF_SEND_REVETHIP, setgifopts),
+ DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts),
+ DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts),
};
static struct afswtch af_gif = {
@@ -114,11 +121,9 @@ void
#endif /* __rtems__ */
gif_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(gif_cmds); i++)
+ for (i = 0; i < nitems(gif_cmds); i++)
cmd_register(&gif_cmds[i]);
af_register(&af_gif);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifgre.c b/freebsd/sbin/ifconfig/ifgre.c
index 221371f6..6f72a89e 100644
--- a/freebsd/sbin/ifconfig/ifgre.c
+++ b/freebsd/sbin/ifconfig/ifgre.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
* Copyright (c) 2008 Andrew Thompson. All rights reserved.
*
@@ -25,61 +29,92 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_gre.h>
-#include <net/route.h>
#include <ctype.h>
+#include <limits.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include <err.h>
-#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifgre-data.h"
+#endif /* __rtems__ */
+
+#define GREBITS "\020\01ENABLE_CSUM\02ENABLE_SEQ"
static void gre_status(int s);
static void
gre_status(int s)
{
- int grekey = 0;
+ uint32_t opts = 0;
- ifr.ifr_data = (caddr_t)&grekey;
+ ifr.ifr_data = (caddr_t)&opts;
if (ioctl(s, GREGKEY, &ifr) == 0)
- if (grekey != 0)
- printf("\tgrekey: %d\n", grekey);
+ if (opts != 0)
+ printf("\tgrekey: 0x%x (%u)\n", opts, opts);
+ opts = 0;
+ if (ioctl(s, GREGOPTS, &ifr) != 0 || opts == 0)
+ return;
+ printb("\toptions", opts, GREBITS);
+ putchar('\n');
}
static void
setifgrekey(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
- uint32_t grekey = atol(val);
+ uint32_t grekey = strtol(val, NULL, 0);
- strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_data = (caddr_t)&grekey;
if (ioctl(s, GRESKEY, (caddr_t)&ifr) < 0)
warn("ioctl (set grekey)");
}
+static void
+setifgreopts(const char *val, int d, int s, const struct afswtch *afp)
+{
+ uint32_t opts;
+
+ ifr.ifr_data = (caddr_t)&opts;
+ if (ioctl(s, GREGOPTS, &ifr) == -1) {
+ warn("ioctl(GREGOPTS)");
+ return;
+ }
+
+ if (d < 0)
+ opts &= ~(-d);
+ else
+ opts |= d;
+
+ if (ioctl(s, GRESOPTS, &ifr) == -1) {
+ warn("ioctl(GIFSOPTS)");
+ return;
+ }
+}
+
+
static struct cmd gre_cmds[] = {
DEF_CMD_ARG("grekey", setifgrekey),
+ DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts),
+ DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts),
+ DEF_CMD("enable_seq", GRE_ENABLE_SEQ, setifgreopts),
+ DEF_CMD("-enable_seq",-GRE_ENABLE_SEQ, setifgreopts),
};
static struct afswtch af_gre = {
.af_name = "af_gre",
@@ -94,11 +129,9 @@ void
#endif /* __rtems__ */
gre_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(gre_cmds); i++)
+ for (i = 0; i < nitems(gre_cmds); i++)
cmd_register(&gre_cmds[i]);
af_register(&af_gre);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifgroup.c b/freebsd/sbin/ifconfig/ifgroup.c
index 444a1c22..0e19d4ae 100644
--- a/freebsd/sbin/ifconfig/ifgroup.c
+++ b/freebsd/sbin/ifconfig/ifgroup.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
* Copyright (c) 2006 Max Laier. All rights reserved.
*
@@ -31,18 +35,9 @@ static const char rcsid[] =
#endif /* not lint */
#ifdef __rtems__
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#endif /* __rtems__ */
-#include <sys/types.h>
+#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
@@ -56,6 +51,9 @@ static const char rcsid[] =
#include <unistd.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifgroup-data.h"
+#endif /* __rtems__ */
/* ARGSUSED */
static void
@@ -66,7 +64,12 @@ setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
memset(&ifgr, 0, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
- if (group_name[0] && isdigit((unsigned char)group_name[strlen(group_name) - 1]))
+#ifndef __rtems__
+ if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+#else /* __rtems__ */
+ if (group_name[0] && isdigit(
+ (unsigned char)group_name[strlen(group_name) - 1]))
+#endif /* __rtems__ */
errx(1, "setifgroup: group names may not end in a digit");
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
@@ -84,7 +87,12 @@ unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
memset(&ifgr, 0, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
- if (group_name[0] && isdigit((unsigned char)group_name[strlen(group_name) - 1]))
+#ifndef __rtems__
+ if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
+#else /* __rtems__ */
+ if (group_name[0] && isdigit(
+ (unsigned char)group_name[strlen(group_name) - 1]))
+#endif /* __rtems__ */
errx(1, "unsetifgroup: group names may not end in a digit");
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
@@ -100,9 +108,6 @@ getifgroups(int s)
struct ifgroupreq ifgr;
struct ifg_req *ifg;
- if (!verbose)
- return;
-
memset(&ifgr, 0, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
@@ -135,6 +140,8 @@ getifgroups(int s)
}
if (cnt)
printf("\n");
+
+ free(ifgr.ifgr_groups);
}
static void
@@ -151,7 +158,6 @@ printgroup(const char *groupname)
bzero(&ifgr, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
- close(s);
if (errno == EINVAL || errno == ENOTTY ||
errno == ENOENT)
exit(0);
@@ -160,15 +166,10 @@ printgroup(const char *groupname)
}
len = ifgr.ifgr_len;
- if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) {
- close(s);
+ if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
err(1, "printgroup");
- }
- if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
- free(ifgr.ifgr_groups);
- close(s);
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
err(1, "SIOCGIFGMEMB");
- }
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
ifg++) {
@@ -177,7 +178,6 @@ printgroup(const char *groupname)
cnt++;
}
free(ifgr.ifgr_groups);
- close(s);
exit(0);
}
@@ -200,12 +200,10 @@ void
#endif /* __rtems__ */
group_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
- for (i = 0; i < N(group_cmds); i++)
+ for (i = 0; i < nitems(group_cmds); i++)
cmd_register(&group_cmds[i]);
af_register(&af_group);
opt_register(&group_gopt);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifieee80211.c b/freebsd/sbin/ifconfig/ifieee80211.c
index 29b49a5b..ead27e2b 100644
--- a/freebsd/sbin/ifconfig/ifieee80211.c
+++ b/freebsd/sbin/ifconfig/ifieee80211.c
@@ -1,3 +1,9 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright 2001 The Aerospace Corporation. All rights reserved.
*
@@ -64,6 +70,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -98,6 +107,9 @@
#include "ifconfig.h"
#include "regdomain.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifieee80211-data.h"
+#endif /* __rtems__ */
#ifndef IEEE80211_FIXED_RATE_NONE
#define IEEE80211_FIXED_RATE_NONE 0xff
@@ -207,12 +219,22 @@ getchaninfo(int s)
gethtconf(s);
}
+#ifdef __rtems__
+static struct regdata *getregdata_rdp = NULL;
+#endif /* __rtems__ */
static struct regdata *
getregdata(void)
{
+#ifndef __rtems__
static struct regdata *rdp = NULL;
+#else /* __rtems__ */
+ struct regdata *rdp = getregdata_rdp;
+#endif /* __rtems__ */
if (rdp == NULL) {
rdp = lib80211_alloc_regdata();
+#ifdef __rtems__
+ getregdata_rdp = rdp;
+#endif /* __rtems__ */
if (rdp == NULL)
errx(-1, "missing or corrupted regdomain database");
}
@@ -5269,7 +5291,11 @@ static struct afswtch af_ieee80211 = {
.af_other_status = ieee80211_status,
};
+#ifndef __rtems__
static __constructor void
+#else /* __rtems__ */
+void
+#endif /* __rtems__ */
ieee80211_ctor(void)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
diff --git a/freebsd/sbin/ifconfig/iflagg.c b/freebsd/sbin/ifconfig/iflagg.c
index 56970e57..78f81fdb 100644
--- a/freebsd/sbin/ifconfig/iflagg.c
+++ b/freebsd/sbin/ifconfig/iflagg.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
*/
@@ -8,6 +12,9 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -19,6 +26,7 @@ static const char rcsid[] =
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_lagg.h>
+#include <net/ieee8023ad_lacp.h>
#include <net/route.h>
#include <ctype.h>
@@ -30,6 +38,9 @@ static const char rcsid[] =
#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-iflagg-data.h"
+#endif /* __rtems__ */
char lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */
@@ -70,7 +81,7 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
bzero(&ra, sizeof(ra));
ra.ra_proto = LAGG_PROTO_MAX;
- for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+ for (i = 0; i < nitems(lpr); i++) {
if (strcmp(val, lpr[i].lpr_name) == 0) {
ra.ra_proto = lpr[i].lpr_proto;
break;
@@ -85,6 +96,63 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp)
}
static void
+setlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct lagg_reqopts ro;
+
+ bzero(&ro, sizeof(ro));
+ ro.ro_opts = LAGG_OPT_FLOWIDSHIFT;
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+ ro.ro_flowid_shift = (int)strtol(val, NULL, 10);
+ if (ro.ro_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK)
+ errx(1, "Invalid flowid_shift option: %s", val);
+
+ if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
+ err(1, "SIOCSLAGGOPTS");
+}
+
+static void
+setlaggrr_limit(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct lagg_reqopts ro;
+
+ bzero(&ro, sizeof(ro));
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+ ro.ro_bkt = (int)strtol(val, NULL, 10);
+
+ if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
+ err(1, "SIOCSLAGG");
+}
+
+static void
+setlaggsetopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct lagg_reqopts ro;
+
+ bzero(&ro, sizeof(ro));
+ ro.ro_opts = d;
+ switch (ro.ro_opts) {
+ case LAGG_OPT_USE_FLOWID:
+ case -LAGG_OPT_USE_FLOWID:
+ case LAGG_OPT_LACP_STRICT:
+ case -LAGG_OPT_LACP_STRICT:
+ case LAGG_OPT_LACP_TXTEST:
+ case -LAGG_OPT_LACP_TXTEST:
+ case LAGG_OPT_LACP_RXTEST:
+ case -LAGG_OPT_LACP_RXTEST:
+ case LAGG_OPT_LACP_TIMEOUT:
+ case -LAGG_OPT_LACP_TIMEOUT:
+ break;
+ default:
+ err(1, "Invalid lagg option");
+ }
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+
+ if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0)
+ err(1, "SIOCSLAGGOPTS");
+}
+
+static void
setlagghash(const char *val, int d, int s, const struct afswtch *afp)
{
struct lagg_reqflags rf;
@@ -146,6 +214,7 @@ lagg_status(int s)
struct lagg_protos lpr[] = LAGG_PROTOS;
struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS];
struct lagg_reqall ra;
+ struct lagg_reqopts ro;
struct lagg_reqflags rf;
struct lacp_opreq *lp;
const char *proto = "<unknown>";
@@ -153,6 +222,7 @@ lagg_status(int s)
bzero(&rp, sizeof(rp));
bzero(&ra, sizeof(ra));
+ bzero(&ro, sizeof(ro));
strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname));
@@ -164,6 +234,9 @@ lagg_status(int s)
ra.ra_size = sizeof(rpbuf);
ra.ra_port = rpbuf;
+ strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname));
+ ioctl(s, SIOCGLAGGOPTS, &ro);
+
strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname));
if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0)
rf.rf_flags = 0;
@@ -171,7 +244,7 @@ lagg_status(int s)
if (ioctl(s, SIOCGLAGG, &ra) == 0) {
lp = (struct lacp_opreq *)&ra.ra_lacpreq;
- for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+ for (i = 0; i < nitems(lpr); i++) {
if (ra.ra_proto == lpr[i].lpr_proto) {
proto = lpr[i].lpr_name;
break;
@@ -199,16 +272,29 @@ lagg_status(int s)
if (isport)
printf(" laggdev %s", rp.rp_ifname);
putchar('\n');
- if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
- printf("\tlag id: %s\n",
- lacp_format_peer(lp, "\n\t\t "));
+ if (verbose) {
+ printf("\tlagg options:\n");
+ printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS);
+ putchar('\n');
+ printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift);
+ if (ra.ra_proto == LAGG_PROTO_ROUNDROBIN)
+ printf("\t\trr_limit: %d\n", ro.ro_bkt);
+ printf("\tlagg statistics:\n");
+ printf("\t\tactive ports: %d\n", ro.ro_active);
+ printf("\t\tflapping: %u\n", ro.ro_flapping);
+ if (ra.ra_proto == LAGG_PROTO_LACP) {
+ printf("\tlag id: %s\n",
+ lacp_format_peer(lp, "\n\t\t "));
+ }
+ }
for (i = 0; i < ra.ra_ports; i++) {
lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
printf("\tlaggport: %s ", rpbuf[i].rp_portname);
printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS);
if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
- printf(" state=%X", lp->actor_state);
+ printb(" state", lp->actor_state,
+ LACP_STATE_BITS);
putchar('\n');
if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
printf("\t\t%s\n",
@@ -217,7 +303,7 @@ lagg_status(int s)
if (0 /* XXX */) {
printf("\tsupported aggregation protocols:\n");
- for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++)
+ for (i = 0; i < nitems(lpr); i++)
printf("\t\tlaggproto %s\n", lpr[i].lpr_name);
}
}
@@ -228,6 +314,18 @@ static struct cmd lagg_cmds[] = {
DEF_CMD_ARG("-laggport", unsetlaggport),
DEF_CMD_ARG("laggproto", setlaggproto),
DEF_CMD_ARG("lagghash", setlagghash),
+ DEF_CMD("use_flowid", LAGG_OPT_USE_FLOWID, setlaggsetopt),
+ DEF_CMD("-use_flowid", -LAGG_OPT_USE_FLOWID, setlaggsetopt),
+ DEF_CMD("lacp_strict", LAGG_OPT_LACP_STRICT, setlaggsetopt),
+ DEF_CMD("-lacp_strict", -LAGG_OPT_LACP_STRICT, setlaggsetopt),
+ DEF_CMD("lacp_txtest", LAGG_OPT_LACP_TXTEST, setlaggsetopt),
+ DEF_CMD("-lacp_txtest", -LAGG_OPT_LACP_TXTEST, setlaggsetopt),
+ DEF_CMD("lacp_rxtest", LAGG_OPT_LACP_RXTEST, setlaggsetopt),
+ DEF_CMD("-lacp_rxtest", -LAGG_OPT_LACP_RXTEST, setlaggsetopt),
+ DEF_CMD("lacp_fast_timeout", LAGG_OPT_LACP_TIMEOUT, setlaggsetopt),
+ DEF_CMD("-lacp_fast_timeout", -LAGG_OPT_LACP_TIMEOUT, setlaggsetopt),
+ DEF_CMD_ARG("flowid_shift", setlaggflowidshift),
+ DEF_CMD_ARG("rr_limit", setlaggrr_limit),
};
static struct afswtch af_lagg = {
.af_name = "af_lagg",
@@ -242,14 +340,9 @@ void
#endif /* __rtems__ */
lagg_ctor(void)
{
-#ifdef __rtems__
- memset(&lacpbuf, 0, sizeof(lacpbuf));
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
- for (i = 0; i < N(lagg_cmds); i++)
+ for (i = 0; i < nitems(lagg_cmds); i++)
cmd_register(&lagg_cmds[i]);
af_register(&af_lagg);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifmac.c b/freebsd/sbin/ifconfig/ifmac.c
index a64a0cbf..b9aa5eed 100644
--- a/freebsd/sbin/ifconfig/ifmac.c
+++ b/freebsd/sbin/ifconfig/ifmac.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*-
* Copyright (c) 2001 Networks Associates Technology, Inc.
* All rights reserved.
@@ -36,6 +40,9 @@
* $FreeBSD$
*/
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/mac.h>
@@ -50,6 +57,9 @@
#include <string.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifmac-data.h"
+#endif /* __rtems__ */
static void
maclabel_status(int s)
@@ -59,7 +69,7 @@ maclabel_status(int s)
char *label_text;
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
if (mac_prepare_ifnet_label(&label) == -1)
return;
@@ -92,7 +102,7 @@ setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp)
}
memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_ifru.ifru_data = (void *)label;
error = ioctl(s, SIOCSIFMAC, &ifr);
@@ -117,11 +127,9 @@ void
#endif /* __rtems__ */
mac_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(mac_cmds); i++)
+ for (i = 0; i < nitems(mac_cmds); i++)
cmd_register(&mac_cmds[i]);
af_register(&af_mac);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifmedia.c b/freebsd/sbin/ifconfig/ifmedia.c
index ba029cb4..890ca8e3 100644
--- a/freebsd/sbin/ifconfig/ifmedia.c
+++ b/freebsd/sbin/ifconfig/ifmedia.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */
/* $FreeBSD$ */
@@ -64,6 +68,9 @@
* SUCH DAMAGE.
*/
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -86,19 +93,37 @@
#include <unistd.h>
#include "ifconfig.h"
+#ifdef __rtems__
+struct ifmedia_type_to_subtype {
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } subtypes[5];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } options[4];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } modes[3];
+};
+
+#include "rtems-bsd-ifconfig-ifmedia-data.h"
+#endif /* __rtems__ */
static void domediaopt(const char *, int, int);
static int get_media_subtype(int, const char *);
static int get_media_mode(int, const char *);
static int get_media_options(int, const char *);
-static int lookup_media_word(const struct ifmedia_description *, const char *);
+static int lookup_media_word(struct ifmedia_description *, const char *);
static void print_media_word(int, int);
static void print_media_word_ifconfig(int);
-static const struct ifmedia_description *get_toptype_desc(int);
-static const struct ifmedia_type_to_subtype *get_toptype_ttos(int);
-static const struct ifmedia_description *get_subtype_desc(int,
- const struct ifmedia_type_to_subtype *ttos);
+static struct ifmedia_description *get_toptype_desc(int);
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
+static struct ifmedia_description *get_subtype_desc(int,
+ struct ifmedia_type_to_subtype *ttos);
#define IFM_OPMODE(x) \
((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
@@ -111,11 +136,17 @@ media_status(int s)
{
struct ifmediareq ifmr;
int *media_list, i;
+ int xmedia = 1;
(void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+ (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ /*
+ * Check if interface supports extended media types.
+ */
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ xmedia = 0;
+ if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
/*
* Interface doesn't support SIOC{G,S}IFMEDIA.
*/
@@ -132,9 +163,12 @@ media_status(int s)
err(1, "malloc");
ifmr.ifm_ulist = media_list;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
- free(media_list);
- err(1, "SIOCGIFMEDIA");
+ if (xmedia) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ } else {
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFMEDIA");
}
printf("\tmedia: ");
@@ -194,23 +228,29 @@ media_status(int s)
}
#ifdef __rtems__
-static struct ifmediareq *ifmr = NULL;
+static struct ifmediareq *ifmedia_getstate_ifmr = NULL;
#endif /* __rtems__ */
struct ifmediareq *
ifmedia_getstate(int s)
{
#ifndef __rtems__
static struct ifmediareq *ifmr = NULL;
+#else /* __rtems__ */
+ struct ifmediareq *ifmr = ifmedia_getstate_ifmr;
#endif /* __rtems__ */
int *mwords;
+ int xmedia = 1;
if (ifmr == NULL) {
ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+#ifdef __rtems__
+ ifmedia_getstate_ifmr = ifmr;
+#endif /* __rtems__ */
if (ifmr == NULL)
err(1, "malloc");
(void) memset(ifmr, 0, sizeof(struct ifmediareq));
- (void) strncpy(ifmr->ifm_name, name,
+ (void) strlcpy(ifmr->ifm_name, name,
sizeof(ifmr->ifm_name));
ifmr->ifm_count = 0;
@@ -222,7 +262,10 @@ ifmedia_getstate(int s)
* the current media type and the top-level type.
*/
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) {
+ xmedia = 0;
+ }
+ if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
err(1, "SIOCGIFMEDIA");
}
@@ -234,8 +277,13 @@ ifmedia_getstate(int s)
err(1, "malloc");
ifmr->ifm_ulist = mwords;
- if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
- err(1, "SIOCGIFMEDIA");
+ if (xmedia) {
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ } else {
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFMEDIA");
+ }
}
return ifmr;
@@ -281,7 +329,7 @@ setmedia(const char *val, int d, int s, const struct afswtch *afp)
*/
subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
@@ -313,7 +361,7 @@ domediaopt(const char *val, int clear, int s)
options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_media = ifmr->ifm_current;
if (clear)
ifr.ifr_media &= ~options;
@@ -340,7 +388,7 @@ setmediainst(const char *val, int d, int s, const struct afswtch *afp)
if (inst < 0 || inst > (int)IFM_INST_MAX)
errx(1, "invalid media instance: %s", val);
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
ifmr->ifm_current = ifr.ifr_media;
@@ -357,7 +405,7 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp)
mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
ifmr->ifm_current = ifr.ifr_media;
@@ -368,89 +416,91 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp)
* A good chunk of this is duplicated from sys/net/ifmedia.c
**********************************************************************/
-static const struct ifmedia_description ifm_type_descriptions[] =
+static struct ifmedia_description ifm_type_descriptions[] =
IFM_TYPE_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
IFM_SUBTYPE_ETHERNET_ALIASES;
-static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
+static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_tokenring_aliases[] =
+static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
IFM_SUBTYPE_TOKENRING_ALIASES;
-static const struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
+static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_fddi_descriptions[] =
+static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
IFM_SUBTYPE_FDDI_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_fddi_aliases[] =
+static struct ifmedia_description ifm_subtype_fddi_aliases[] =
IFM_SUBTYPE_FDDI_ALIASES;
-static const struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
+static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
IFM_SUBTYPE_IEEE80211_ALIASES;
-static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
-static const struct ifmedia_description ifm_subtype_atm_descriptions[] =
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
IFM_SUBTYPE_ATM_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_atm_aliases[] =
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
IFM_SUBTYPE_ATM_ALIASES;
-static const struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_shared_descriptions[] =
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
IFM_SUBTYPE_SHARED_DESCRIPTIONS;
-static const struct ifmedia_description ifm_subtype_shared_aliases[] =
+static struct ifmedia_description ifm_subtype_shared_aliases[] =
IFM_SUBTYPE_SHARED_ALIASES;
-static const struct ifmedia_description ifm_shared_option_descriptions[] =
+static struct ifmedia_description ifm_shared_option_descriptions[] =
IFM_SHARED_OPTION_DESCRIPTIONS;
static struct ifmedia_description ifm_shared_option_aliases[] =
IFM_SHARED_OPTION_ALIASES;
+#ifndef __rtems__
struct ifmedia_type_to_subtype {
struct {
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
int alias;
} subtypes[5];
struct {
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
int alias;
} options[4];
struct {
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
int alias;
} modes[3];
};
+#endif /* __rtems__ */
/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
-static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
+static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
{
{
{ &ifm_subtype_shared_descriptions[0], 0 },
@@ -548,8 +598,8 @@ static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
static int
get_media_subtype(int type, const char *val)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
int rval, i;
/* Find the top-level interface type. */
@@ -572,8 +622,8 @@ get_media_subtype(int type, const char *val)
static int
get_media_mode(int type, const char *val)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
int rval, i;
/* Find the top-level interface type. */
@@ -595,8 +645,8 @@ get_media_mode(int type, const char *val)
static int
get_media_options(int type, const char *val)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
char *optlist, *optptr;
int option = 0, i, rval = 0;
@@ -634,7 +684,7 @@ get_media_options(int type, const char *val)
}
static int
-lookup_media_word(const struct ifmedia_description *desc, const char *val)
+lookup_media_word(struct ifmedia_description *desc, const char *val)
{
for (; desc->ifmt_string != NULL; desc++)
@@ -644,9 +694,9 @@ lookup_media_word(const struct ifmedia_description *desc, const char *val)
return (-1);
}
-static const struct ifmedia_description *get_toptype_desc(int ifmw)
+static struct ifmedia_description *get_toptype_desc(int ifmw)
{
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
if (IFM_TYPE(ifmw) == desc->ifmt_word)
@@ -655,10 +705,10 @@ static const struct ifmedia_description *get_toptype_desc(int ifmw)
return desc;
}
-static const struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
desc->ifmt_string != NULL; desc++, ttos++)
@@ -668,11 +718,11 @@ static const struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
return ttos;
}
-static const struct ifmedia_description *get_subtype_desc(int ifmw,
- const struct ifmedia_type_to_subtype *ttos)
+static struct ifmedia_description *get_subtype_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
{
int i;
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
if (ttos->subtypes[i].alias)
@@ -687,11 +737,11 @@ static const struct ifmedia_description *get_subtype_desc(int ifmw,
return NULL;
}
-static const struct ifmedia_description *get_mode_desc(int ifmw,
- const struct ifmedia_type_to_subtype *ttos)
+static struct ifmedia_description *get_mode_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
{
int i;
- const struct ifmedia_description *desc;
+ struct ifmedia_description *desc;
for (i = 0; ttos->modes[i].desc != NULL; i++) {
if (ttos->modes[i].alias)
@@ -709,8 +759,8 @@ static const struct ifmedia_description *get_mode_desc(int ifmw,
static void
print_media_word(int ifmw, int print_toptype)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
int seen_option = 0, i;
/* Find the top-level interface type. */
@@ -769,8 +819,8 @@ print_media_word(int ifmw, int print_toptype)
static void
print_media_word_ifconfig(int ifmw)
{
- const struct ifmedia_description *desc;
- const struct ifmedia_type_to_subtype *ttos;
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
int seen_option = 0, i;
/* Find the top-level interface type. */
@@ -843,15 +893,9 @@ void
#endif /* __rtems__ */
ifmedia_ctor(void)
{
-#ifdef __rtems__
- did_it = 0;
- ifmr = NULL;
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(media_cmds); i++)
+ for (i = 0; i < nitems(media_cmds); i++)
cmd_register(&media_cmds[i]);
af_register(&af_media);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifpfsync.c b/freebsd/sbin/ifconfig/ifpfsync.c
index ad65e659..162219c8 100644
--- a/freebsd/sbin/ifconfig/ifpfsync.c
+++ b/freebsd/sbin/ifconfig/ifpfsync.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 2003 Ryan McBride. All rights reserved.
* Copyright (c) 2004 Max Laier. All rights reserved.
@@ -28,7 +32,10 @@
* $FreeBSD$
*/
-#include <sys/types.h>
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -47,6 +54,9 @@
#include <unistd.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifpfsync-data.h"
+#endif /* __rtems__ */
void setpfsync_syncdev(const char *, int, int, const struct afswtch *);
void unsetpfsync_syncdev(const char *, int, int, const struct afswtch *);
@@ -54,6 +64,7 @@ void setpfsync_syncpeer(const char *, int, int, const struct afswtch *);
void unsetpfsync_syncpeer(const char *, int, int, const struct afswtch *);
void setpfsync_syncpeer(const char *, int, int, const struct afswtch *);
void setpfsync_maxupd(const char *, int, int, const struct afswtch *);
+void setpfsync_defer(const char *, int, int, const struct afswtch *);
void pfsync_status(int);
void
@@ -164,6 +175,23 @@ setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp)
err(1, "SIOCSETPFSYNC");
}
+/* ARGSUSED */
+void
+setpfsync_defer(const char *val, int d, int s, const struct afswtch *rafp)
+{
+ struct pfsyncreq preq;
+
+ memset((char *)&preq, 0, sizeof(struct pfsyncreq));
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETPFSYNC");
+
+ preq.pfsyncr_defer = d;
+ if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFSYNC");
+}
+
void
pfsync_status(int s)
{
@@ -185,8 +213,10 @@ pfsync_status(int s)
printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer));
if (preq.pfsyncr_syncdev[0] != '\0' ||
- preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP)
- printf("maxupd: %d\n", preq.pfsyncr_maxupdates);
+ preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP) {
+ printf("maxupd: %d ", preq.pfsyncr_maxupdates);
+ printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off");
+ }
}
static struct cmd pfsync_cmds[] = {
@@ -196,7 +226,9 @@ static struct cmd pfsync_cmds[] = {
DEF_CMD("-syncif", 1, unsetpfsync_syncdev),
DEF_CMD_ARG("syncpeer", setpfsync_syncpeer),
DEF_CMD("-syncpeer", 1, unsetpfsync_syncpeer),
- DEF_CMD_ARG("maxupd", setpfsync_maxupd)
+ DEF_CMD_ARG("maxupd", setpfsync_maxupd),
+ DEF_CMD("defer", 1, setpfsync_defer),
+ DEF_CMD("-defer", 0, setpfsync_defer),
};
static struct afswtch af_pfsync = {
.af_name = "af_pfsync",
@@ -211,11 +243,9 @@ void
#endif /* __rtems__ */
pfsync_ctor(void)
{
-#define N(a) (sizeof(a) / sizeof(a[0]))
int i;
- for (i = 0; i < N(pfsync_cmds); i++)
+ for (i = 0; i < nitems(pfsync_cmds); i++)
cmd_register(&pfsync_cmds[i]);
af_register(&af_pfsync);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/ifvlan.c b/freebsd/sbin/ifconfig/ifvlan.c
index 9fc2971d..14350baf 100644
--- a/freebsd/sbin/ifconfig/ifvlan.c
+++ b/freebsd/sbin/ifconfig/ifvlan.c
@@ -1,8 +1,16 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
/*
- * Copyright (c) 1999
- * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
+ * Copyright (c) 1999 Bill Paul <wpaul@ctr.columbia.edu>
+ * Copyright (c) 2012 ADARA Networks, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Robert N. M. Watson under
+ * contract to ADARA Networks, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,6 +40,9 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -42,7 +53,6 @@
#include <net/ethernet.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_vlan_var.h>
#include <net/route.h>
@@ -55,6 +65,9 @@
#include <errno.h>
#include "ifconfig.h"
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-ifvlan-data.h"
+#endif /* __rtems__ */
#ifndef lint
static const char rcsid[] =
@@ -81,10 +94,14 @@ vlan_status(int s)
{
struct vlanreq vreq;
- if (getvlan(s, &ifr, &vreq) != -1)
- printf("\tvlan: %d parent interface: %s\n",
- vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
- "<none>" : vreq.vlr_parent);
+ if (getvlan(s, &ifr, &vreq) == -1)
+ return;
+ printf("\tvlan: %d", vreq.vlr_tag);
+ if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1)
+ printf(" vlanpcp: %u", ifr.ifr_vlan_pcp);
+ printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+ printf("\n");
}
static void
@@ -152,6 +169,22 @@ DECL_CMD_FUNC(setvlandev, val, d)
}
static
+DECL_CMD_FUNC(setvlanpcp, val, d)
+{
+ u_long ul;
+ char *endp;
+
+ ul = strtoul(val, &endp, 0);
+ if (*endp != '\0')
+ errx(1, "invalid value for vlanpcp");
+ if (ul > 7)
+ errx(1, "value for vlanpcp out of range");
+ ifr.ifr_vlan_pcp = ul;
+ if (ioctl(s, SIOCSVLANPCP, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSVLANPCP");
+}
+
+static
DECL_CMD_FUNC(unsetvlandev, val, d)
{
struct vlanreq vreq;
@@ -172,6 +205,7 @@ DECL_CMD_FUNC(unsetvlandev, val, d)
static struct cmd vlan_cmds[] = {
DEF_CLONE_CMD_ARG("vlan", setvlantag),
DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ DEF_CMD_ARG("vlanpcp", setvlanpcp),
/* NB: non-clone cmds */
DEF_CMD_ARG("vlan", setvlantag),
DEF_CMD_ARG("vlandev", setvlandev),
@@ -201,17 +235,11 @@ void
#endif /* __rtems__ */
vlan_ctor(void)
{
-#ifdef __rtems__
- memset(&params, 0, sizeof(params));
- params.vlr_tag = NOTAG;
-#endif /* __rtems__ */
-#define N(a) (sizeof(a) / sizeof(a[0]))
size_t i;
- for (i = 0; i < N(vlan_cmds); i++)
+ for (i = 0; i < nitems(vlan_cmds); i++)
cmd_register(&vlan_cmds[i]);
af_register(&af_vlan);
callback_register(vlan_cb, NULL);
clone_setdefcallback("vlan", vlan_create);
-#undef N
}
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h
new file mode 100644
index 00000000..962974a0
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h
@@ -0,0 +1,9 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* af_inet.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in_aliasreq in_addreq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifreq in_ridreq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_inet);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char addr_buf[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct sockaddr_in *sintab[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h
new file mode 100644
index 00000000..6038db41
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h
@@ -0,0 +1,13 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* af_inet6.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in6_ifreq in6_ridreq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in6_aliasreq in6_addreq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int ip6lifetime);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int explicit_prefix);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_inet6);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option in6_Lopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char addr_buf[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct sockaddr_in6 *sin6tab[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd inet6_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h
new file mode 100644
index 00000000..b5f77c05
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h
@@ -0,0 +1,8 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* af_link.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifreq link_ridreq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_link);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_ether);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_lladdr);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h
new file mode 100644
index 00000000..5ad9960a
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* af_nd6.c */
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h
new file mode 100644
index 00000000..d5d6f294
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h
@@ -0,0 +1,39 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+/* af_inet6.c */
+/* af_inet.c */
+/* af_link.c */
+/* af_nd6.c */
+/* ifbridge.c */
+/* ifclone.c */
+/* ifconfig.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int setaddr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifreq ifr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char name[16]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *descr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern size_t descrlen);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int setmask);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int doalias);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int clearaddr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int newaddr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int verbose);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int noload);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int printifname);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int supmedia);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int printkeys);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_inet);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_inet6);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_ether);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_addr);
+/* ifgif.c */
+/* ifgre.c */
+/* ifgroup.c */
+/* iflagg.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char lacpbuf[120]);
+/* ifmac.c */
+/* ifmedia.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[8]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[2]);
+/* ifpfsync.c */
+/* ifvlan.c */
+/* sfp.c */
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h
new file mode 100644
index 00000000..ba3ee5c6
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h
@@ -0,0 +1,9 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifbridge.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_bridge);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stpstates[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stpproto[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stproles[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd bridge_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h
new file mode 100644
index 00000000..746e12c5
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h
@@ -0,0 +1,7 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifclone.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct clone_defcb_list clone_defcbh);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option clone_Copt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd clone_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h
new file mode 100644
index 00000000..4ce74977
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h
@@ -0,0 +1,9 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifconfig.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option *opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch *afs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd *cmds);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct callback *callbacks);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd basic_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h
new file mode 100644
index 00000000..2364de3e
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifgif.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_gif);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd gif_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h
new file mode 100644
index 00000000..af37782d
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifgre.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_gre);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd gre_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h
new file mode 100644
index 00000000..3b306f50
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h
@@ -0,0 +1,7 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifgroup.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_group);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option group_gopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd group_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h
new file mode 100644
index 00000000..64f05f94
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* iflagg.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_lagg);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd lagg_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h
new file mode 100644
index 00000000..c7bc23f2
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifmac.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_mac);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd mac_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h
new file mode 100644
index 00000000..a14edd2b
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h
@@ -0,0 +1,29 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifmedia.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmediareq *ifmedia_getstate_ifmr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int did_it);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_media);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_type_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_shared_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_shared_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_shared_option_descriptions[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_shared_option_aliases[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd media_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h
new file mode 100644
index 00000000..ad28104a
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifpfsync.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_pfsync);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd pfsync_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h
new file mode 100644
index 00000000..0d8ffe8a
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h
@@ -0,0 +1,7 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* ifvlan.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct vlanreq params);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_vlan);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd vlan_cmds[]);
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h
new file mode 100644
index 00000000..5bf653b8
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h
@@ -0,0 +1,76 @@
+/* generated by userspace-header-gen.py */
+/* af_inet6.c */
+#define inet6_ctor _bsd_ifconfig_inet6_ctor
+/* af_inet.c */
+#define inet_ctor _bsd_ifconfig_inet_ctor
+/* af_link.c */
+#define link_ctor _bsd_ifconfig_link_ctor
+/* af_nd6.c */
+#define nd6_status _bsd_ifconfig_nd6_status
+#define setnd6defif _bsd_ifconfig_setnd6defif
+#define setnd6flags _bsd_ifconfig_setnd6flags
+/* ifbridge.c */
+#define bridge_ctor _bsd_ifconfig_bridge_ctor
+/* ifclone.c */
+#define clone_ctor _bsd_ifconfig_clone_ctor
+#define clone_setdefcallback _bsd_ifconfig_clone_setdefcallback
+/* ifconfig.c */
+#define setaddr _bsd_ifconfig_setaddr
+#define ifr _bsd_ifconfig_ifr
+#define name _bsd_ifconfig_name
+#define descr _bsd_ifconfig_descr
+#define descrlen _bsd_ifconfig_descrlen
+#define setmask _bsd_ifconfig_setmask
+#define doalias _bsd_ifconfig_doalias
+#define clearaddr _bsd_ifconfig_clearaddr
+#define newaddr _bsd_ifconfig_newaddr
+#define verbose _bsd_ifconfig_verbose
+#define noload _bsd_ifconfig_noload
+#define printifname _bsd_ifconfig_printifname
+#define supmedia _bsd_ifconfig_supmedia
+#define printkeys _bsd_ifconfig_printkeys
+#define f_inet _bsd_ifconfig_f_inet
+#define f_inet6 _bsd_ifconfig_f_inet6
+#define f_ether _bsd_ifconfig_f_ether
+#define f_addr _bsd_ifconfig_f_addr
+#define ifmaybeload _bsd_ifconfig_ifmaybeload
+#define print_vhid _bsd_ifconfig_print_vhid
+#define printb _bsd_ifconfig_printb
+#define Perror _bsd_ifconfig_Perror
+#define setifcap _bsd_ifconfig_setifcap
+#define callback_register _bsd_ifconfig_callback_register
+#define cmd_register _bsd_ifconfig_cmd_register
+#define af_register _bsd_ifconfig_af_register
+#define printifnamemaybe _bsd_ifconfig_printifnamemaybe
+#define opt_register _bsd_ifconfig_opt_register
+/* ifgif.c */
+#define gif_ctor _bsd_ifconfig_gif_ctor
+/* ifgre.c */
+#define gre_ctor _bsd_ifconfig_gre_ctor
+/* ifgroup.c */
+#define group_ctor _bsd_ifconfig_group_ctor
+/* iflagg.c */
+#define lacpbuf _bsd_ifconfig_lacpbuf
+#define lagg_ctor _bsd_ifconfig_lagg_ctor
+/* ifmac.c */
+#define mac_ctor _bsd_ifconfig_mac_ctor
+/* ifmedia.c */
+#define ifm_subtype_ieee80211_mode_descriptions _bsd_ifconfig_ifm_subtype_ieee80211_mode_descriptions
+#define ifm_subtype_ieee80211_mode_aliases _bsd_ifconfig_ifm_subtype_ieee80211_mode_aliases
+#define ifmedia_ctor _bsd_ifconfig_ifmedia_ctor
+#define ifmedia_getstate _bsd_ifconfig_ifmedia_getstate
+/* ifpfsync.c */
+#define pfsync_ctor _bsd_ifconfig_pfsync_ctor
+#define pfsync_status _bsd_ifconfig_pfsync_status
+#define setpfsync_defer _bsd_ifconfig_setpfsync_defer
+#define setpfsync_maxupd _bsd_ifconfig_setpfsync_maxupd
+#define unsetpfsync_syncpeer _bsd_ifconfig_unsetpfsync_syncpeer
+#define setpfsync_syncpeer _bsd_ifconfig_setpfsync_syncpeer
+#define unsetpfsync_syncdev _bsd_ifconfig_unsetpfsync_syncdev
+#define setpfsync_syncdev _bsd_ifconfig_setpfsync_syncdev
+/* ifvlan.c */
+#define vlan_ctor _bsd_ifconfig_vlan_ctor
+/* sfp.c */
+#define sfp_status _bsd_ifconfig_sfp_status
+#define find_zero_bit _bsd_ifconfig_find_zero_bit
+#define find_value _bsd_ifconfig_find_value
diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h
new file mode 100644
index 00000000..994d2279
--- /dev/null
+++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h
@@ -0,0 +1,15 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ifconfig-data.h"
+/* sfp.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *sff_8024_id[23]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv conn[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_10g[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_compat[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_len[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv cab_tech[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_media[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_speed[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_1040g[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_extended_comp[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv rev_compl[]);
diff --git a/freebsd/sbin/ifconfig/sfp.c b/freebsd/sbin/ifconfig/sfp.c
new file mode 100644
index 00000000..55fb7c7e
--- /dev/null
+++ b/freebsd/sbin/ifconfig/sfp.c
@@ -0,0 +1,935 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-ifconfig-namespace.h"
+#endif /* __rtems__ */
+
+/*-
+ * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/sff8436.h>
+#include <net/sff8472.h>
+
+#include <math.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+#ifdef __rtems__
+struct _nv {
+ int v;
+ const char *n;
+};
+
+#include "rtems-bsd-ifconfig-sfp-data.h"
+#endif /* __rtems__ */
+
+struct i2c_info {
+ int fd; /* fd to issue SIOCGI2C */
+ int error; /* Store first error */
+ int qsfp; /* True if transceiver is QSFP */
+ int do_diag; /* True if we need to request DDM */
+ struct ifreq *ifr; /* Pointer to pre-filled ifreq */
+};
+
+static int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off,
+ uint8_t len, uint8_t *buf);
+static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off,
+ uint8_t len);
+
+#ifndef __rtems__
+struct _nv {
+ int v;
+ const char *n;
+};
+#endif /* __rtems__ */
+
+const char *find_value(struct _nv *x, int value);
+const char *find_zero_bit(struct _nv *x, int value, int sz);
+
+/* SFF-8472 Rev. 11.4 table 3.4: Connector values */
+static struct _nv conn[] = {
+ { 0x00, "Unknown" },
+ { 0x01, "SC" },
+ { 0x02, "Fibre Channel Style 1 copper" },
+ { 0x03, "Fibre Channel Style 2 copper" },
+ { 0x04, "BNC/TNC" },
+ { 0x05, "Fibre Channel coaxial" },
+ { 0x06, "FiberJack" },
+ { 0x07, "LC" },
+ { 0x08, "MT-RJ" },
+ { 0x09, "MU" },
+ { 0x0A, "SG" },
+ { 0x0B, "Optical pigtail" },
+ { 0x0C, "MPO Parallel Optic" },
+ { 0x20, "HSSDC II" },
+ { 0x21, "Copper pigtail" },
+ { 0x22, "RJ45" },
+ { 0x23, "No separate connector" }, /* SFF-8436 */
+ { 0, NULL }
+};
+
+/* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */
+/* 10G Ethernet/IB compliance codes, byte 3 */
+static struct _nv eth_10g[] = {
+ { 0x80, "10G Base-ER" },
+ { 0x40, "10G Base-LRM" },
+ { 0x20, "10G Base-LR" },
+ { 0x10, "10G Base-SR" },
+ { 0x08, "1X SX" },
+ { 0x04, "1X LX" },
+ { 0x02, "1X Copper Active" },
+ { 0x01, "1X Copper Passive" },
+ { 0, NULL }
+};
+
+/* Ethernet compliance codes, byte 6 */
+static struct _nv eth_compat[] = {
+ { 0x80, "BASE-PX" },
+ { 0x40, "BASE-BX10" },
+ { 0x20, "100BASE-FX" },
+ { 0x10, "100BASE-LX/LX10" },
+ { 0x08, "1000BASE-T" },
+ { 0x04, "1000BASE-CX" },
+ { 0x02, "1000BASE-LX" },
+ { 0x01, "1000BASE-SX" },
+ { 0, NULL }
+};
+
+/* FC link length, byte 7 */
+static struct _nv fc_len[] = {
+ { 0x80, "very long distance" },
+ { 0x40, "short distance" },
+ { 0x20, "intermediate distance" },
+ { 0x10, "long distance" },
+ { 0x08, "medium distance" },
+ { 0, NULL }
+};
+
+/* Channel/Cable technology, byte 7-8 */
+static struct _nv cab_tech[] = {
+ { 0x0400, "Shortwave laser (SA)" },
+ { 0x0200, "Longwave laser (LC)" },
+ { 0x0100, "Electrical inter-enclosure (EL)" },
+ { 0x80, "Electrical intra-enclosure (EL)" },
+ { 0x40, "Shortwave laser (SN)" },
+ { 0x20, "Shortwave laser (SL)" },
+ { 0x10, "Longwave laser (LL)" },
+ { 0x08, "Active Cable" },
+ { 0x04, "Passive Cable" },
+ { 0, NULL }
+};
+
+/* FC Transmission media, byte 9 */
+static struct _nv fc_media[] = {
+ { 0x80, "Twin Axial Pair" },
+ { 0x40, "Twisted Pair" },
+ { 0x20, "Miniature Coax" },
+ { 0x10, "Viao Coax" },
+ { 0x08, "Miltimode, 62.5um" },
+ { 0x04, "Multimode, 50um" },
+ { 0x02, "" },
+ { 0x01, "Single Mode" },
+ { 0, NULL }
+};
+
+/* FC Speed, byte 10 */
+static struct _nv fc_speed[] = {
+ { 0x80, "1200 MBytes/sec" },
+ { 0x40, "800 MBytes/sec" },
+ { 0x20, "1600 MBytes/sec" },
+ { 0x10, "400 MBytes/sec" },
+ { 0x08, "3200 MBytes/sec" },
+ { 0x04, "200 MBytes/sec" },
+ { 0x01, "100 MBytes/sec" },
+ { 0, NULL }
+};
+
+/* SFF-8436 Rev. 4.8 table 33: Specification compliance */
+
+/* 10/40G Ethernet compliance codes, byte 128 + 3 */
+static struct _nv eth_1040g[] = {
+ { 0x80, "Extended" },
+ { 0x40, "10GBASE-LRM" },
+ { 0x20, "10GBASE-LR" },
+ { 0x10, "10GBASE-SR" },
+ { 0x08, "40GBASE-CR4" },
+ { 0x04, "40GBASE-SR4" },
+ { 0x02, "40GBASE-LR4" },
+ { 0x01, "40G Active Cable" },
+ { 0, NULL }
+};
+#define SFF_8636_EXT_COMPLIANCE 0x80
+
+/* SFF-8024 Rev. 3.4 table 4.4: Extended Specification Compliance */
+static struct _nv eth_extended_comp[] = {
+ { 0xFF, "Reserved" },
+ { 0x1A, "2 lambda DWDM 100G" },
+ { 0x19, "100G ACC or 25GAUI C2M ACC" },
+ { 0x18, "100G AOC or 25GAUI C2M AOC" },
+ { 0x17, "100G CLR4" },
+ { 0x16, "10GBASE-T with SFI electrical interface" },
+ { 0x15, "G959.1 profile P1L1-2D2" },
+ { 0x14, "G959.1 profile P1S1-2D2" },
+ { 0x13, "G959.1 profile P1I1-2D1" },
+ { 0x12, "40G PSM4 Parallel SMF" },
+ { 0x11, "4 x 10GBASE-SR" },
+ { 0x10, "40GBASE-ER4" },
+ { 0x0F, "Reserved" },
+ { 0x0D, "25GBASE-CR CA-N" },
+ { 0x0C, "25GBASE-CR CA-S" },
+ { 0x0B, "100GBASE-CR4 or 25GBASE-CR CA-L" },
+ { 0x0A, "Reserved" },
+ { 0x09, "100G CWDM4 MSA without FEC" },
+ { 0x08, "100G ACC (Active Copper Cable)" },
+ { 0x07, "100G PSM4 Parallel SMF" },
+ { 0x06, "100G CWDM4 MSA with FEC" },
+ { 0x05, "100GBASE-SR10" },
+ { 0x04, "100GBASE-ER4" },
+ { 0x03, "100GBASE-LR4" },
+ { 0x02, "100GBASE-SR4" },
+ { 0x01, "100G AOC (Active Optical Cable) or 25GAUI C2M ACC" },
+ { 0x00, "Unspecified" }
+};
+
+/* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */
+static struct _nv rev_compl[] = {
+ { 0x1, "SFF-8436 rev <=4.8" },
+ { 0x2, "SFF-8436 rev <=4.8" },
+ { 0x3, "SFF-8636 rev <=1.3" },
+ { 0x4, "SFF-8636 rev <=1.4" },
+ { 0x5, "SFF-8636 rev <=1.5" },
+ { 0x6, "SFF-8636 rev <=2.0" },
+ { 0x7, "SFF-8636 rev <=2.5" },
+ { 0x0, "Unspecified" }
+};
+
+const char *
+find_value(struct _nv *x, int value)
+{
+ for (; x->n != NULL; x++)
+ if (x->v == value)
+ return (x->n);
+ return (NULL);
+}
+
+const char *
+find_zero_bit(struct _nv *x, int value, int sz)
+{
+ int v, m;
+ const char *s;
+
+ v = 1;
+ for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) {
+ if ((value & v) == 0)
+ continue;
+ if ((s = find_value(x, value & v)) != NULL) {
+ value &= ~v;
+ return (s);
+ }
+ }
+
+ return (NULL);
+}
+
+static void
+convert_sff_identifier(char *buf, size_t size, uint8_t value)
+{
+ const char *x;
+
+ x = NULL;
+ if (value <= SFF_8024_ID_LAST)
+ x = sff_8024_id[value];
+ else {
+ if (value > 0x80)
+ x = "Vendor specific";
+ else
+ x = "Reserved";
+ }
+
+ snprintf(buf, size, "%s", x);
+}
+
+static void
+convert_sff_connector(char *buf, size_t size, uint8_t value)
+{
+ const char *x;
+
+ if ((x = find_value(conn, value)) == NULL) {
+ if (value >= 0x0D && value <= 0x1F)
+ x = "Unallocated";
+ else if (value >= 0x24 && value <= 0x7F)
+ x = "Unallocated";
+ else
+ x = "Vendor specific";
+ }
+
+ snprintf(buf, size, "%s", x);
+}
+
+static void
+convert_sff_rev_compliance(char *buf, size_t size, uint8_t value)
+{
+ const char *x;
+
+ if (value > 0x07)
+ x = "Unallocated";
+ else
+ x = find_value(rev_compl, value);
+
+ snprintf(buf, size, "%s", x);
+}
+
+static void
+get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data);
+ convert_sff_identifier(buf, size, data);
+}
+
+static void
+get_sfp_connector(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data);
+ convert_sff_connector(buf, size, data);
+}
+
+static void
+get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data);
+ convert_sff_identifier(buf, size, data);
+}
+
+static void
+get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t data;
+
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data);
+ convert_sff_connector(buf, size, data);
+}
+
+static void
+printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[12];
+ const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed;
+
+ tech_class = NULL;
+ tech_len = NULL;
+ tech_tech = NULL;
+ tech_media = NULL;
+ tech_speed = NULL;
+
+ /* Read bytes 3-10 at once */
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]);
+
+ /* Check 10G ethernet first */
+ tech_class = find_zero_bit(eth_10g, xbuf[3], 1);
+ if (tech_class == NULL) {
+ /* No match. Try 1G */
+ tech_class = find_zero_bit(eth_compat, xbuf[6], 1);
+ }
+
+ tech_len = find_zero_bit(fc_len, xbuf[7], 1);
+ tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2);
+ tech_media = find_zero_bit(fc_media, xbuf[9], 1);
+ tech_speed = find_zero_bit(fc_speed, xbuf[10], 1);
+
+ printf("Class: %s\n", tech_class);
+ printf("Length: %s\n", tech_len);
+ printf("Tech: %s\n", tech_tech);
+ printf("Media: %s\n", tech_media);
+ printf("Speed: %s\n", tech_speed);
+}
+
+static void
+get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
+{
+ const char *tech_class;
+ uint8_t code;
+
+ unsigned char qbuf[8];
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf);
+
+ /* Check 10G Ethernet/IB first */
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code);
+ tech_class = find_zero_bit(eth_10g, code, 1);
+ if (tech_class == NULL) {
+ /* No match. Try Ethernet 1G */
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3,
+ 1, (caddr_t)&code);
+ tech_class = find_zero_bit(eth_compat, code, 1);
+ }
+
+ if (tech_class == NULL)
+ tech_class = "Unknown";
+
+ snprintf(buf, size, "%s", tech_class);
+}
+
+static void
+get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size)
+{
+ const char *tech_class;
+ uint8_t code;
+
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code);
+
+ /* Check for extended specification compliance */
+ if (code & SFF_8636_EXT_COMPLIANCE) {
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1, &code);
+ tech_class = find_value(eth_extended_comp, code);
+ } else
+ /* Check 10/40G Ethernet class only */
+ tech_class = find_zero_bit(eth_1040g, code, 1);
+
+ if (tech_class == NULL)
+ tech_class = "Unknown";
+
+ snprintf(buf, size, "%s", tech_class);
+}
+
+/*
+ * Print SFF-8472/SFF-8436 string to supplied buffer.
+ * All (vendor-specific) strings are padded right with '0x20'.
+ */
+static void
+convert_sff_name(char *buf, size_t size, char *xbuf)
+{
+ char *p;
+
+ for (p = &xbuf[16]; *(p - 1) == 0x20; p--)
+ ;
+ *p = '\0';
+ snprintf(buf, size, "%s", xbuf);
+}
+
+static void
+convert_sff_date(char *buf, size_t size, char *xbuf)
+{
+
+ snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1],
+ xbuf[2], xbuf[3], xbuf[4], xbuf[5]);
+}
+
+static void
+get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[6];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ /* Date code, see Table 3.8 for description */
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf);
+ convert_sff_date(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[17];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf);
+ convert_sff_name(buf, size, xbuf);
+}
+
+static void
+get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[6];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf);
+ convert_sff_date(buf, size, xbuf);
+}
+
+static void
+print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size)
+{
+ char xbuf[80];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ if (ii->qsfp != 0) {
+ get_qsfp_vendor_name(ii, xbuf, 20);
+ get_qsfp_vendor_pn(ii, &xbuf[20], 20);
+ get_qsfp_vendor_sn(ii, &xbuf[40], 20);
+ get_qsfp_vendor_date(ii, &xbuf[60], 20);
+ } else {
+ get_sfp_vendor_name(ii, xbuf, 20);
+ get_sfp_vendor_pn(ii, &xbuf[20], 20);
+ get_sfp_vendor_sn(ii, &xbuf[40], 20);
+ get_sfp_vendor_date(ii, &xbuf[60], 20);
+ }
+
+ snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s",
+ xbuf, &xbuf[20], &xbuf[40], &xbuf[60]);
+}
+
+/*
+ * Converts internal templerature (SFF-8472, SFF-8436)
+ * 16-bit unsigned value to human-readable representation:
+ *
+ * Internally measured Module temperature are represented
+ * as a 16-bit signed twos complement value in increments of
+ * 1/256 degrees Celsius, yielding a total range of –128C to +128C
+ * that is considered valid between –40 and +125C.
+ *
+ */
+static void
+convert_sff_temp(char *buf, size_t size, uint8_t *xbuf)
+{
+ double d;
+
+ d = (double)xbuf[0];
+ d += (double)xbuf[1] / 256;
+
+ snprintf(buf, size, "%.2f C", d);
+}
+
+/*
+ * Retrieves supplied voltage (SFF-8472, SFF-8436).
+ * 16-bit usigned value, treated as range 0..+6.55 Volts
+ */
+static void
+convert_sff_voltage(char *buf, size_t size, uint8_t *xbuf)
+{
+ double d;
+
+ d = (double)((xbuf[0] << 8) | xbuf[1]);
+ snprintf(buf, size, "%.2f Volts", d / 10000);
+}
+
+/*
+ * Converts value in @xbuf to both milliwats and dBm
+ * human representation.
+ */
+static void
+convert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf)
+{
+ uint16_t mW;
+ double dbm;
+
+ mW = (xbuf[0] << 8) + xbuf[1];
+
+ /* Convert mw to dbm */
+ dbm = 10.0 * log10(1.0 * mW / 10000);
+
+ /*
+ * Assume internally-calibrated data.
+ * This is always true for SFF-8346, and explicitly
+ * checked for SFF-8472.
+ */
+
+ /* Table 3.9, bit 5 is set, internally calibrated */
+ snprintf(buf, size, "%d.%02d mW (%.2f dBm)",
+ mW / 10000, (mW % 10000) / 100, dbm);
+}
+
+static void
+get_sfp_temp(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf);
+ convert_sff_temp(buf, size, xbuf);
+}
+
+static void
+get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf);
+ convert_sff_voltage(buf, size, xbuf);
+}
+
+static int
+get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf);
+ if ((xbuf[0] == 0xFF && xbuf[1] == 0xFF) || (xbuf[0] == 0 && xbuf[1] == 0))
+ return (-1);
+ convert_sff_temp(buf, size, xbuf);
+ return (0);
+}
+
+static void
+get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf);
+ convert_sff_voltage(buf, size, xbuf);
+}
+
+static void
+get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan)
+{
+ uint8_t xbuf[2];
+
+ memset(xbuf, 0, sizeof(xbuf));
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf);
+ convert_sff_power(ii, buf, size, xbuf);
+}
+
+static void
+get_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size)
+{
+ uint8_t xbuf;
+
+ xbuf = 0;
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf);
+ convert_sff_rev_compliance(buf, size, xbuf);
+}
+
+static uint32_t
+get_qsfp_br(struct i2c_info *ii)
+{
+ uint8_t xbuf;
+ uint32_t rate;
+
+ xbuf = 0;
+ read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf);
+ rate = xbuf * 100;
+ if (xbuf == 0xFF) {
+ read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf);
+ rate = xbuf * 250;
+ }
+
+ return (rate);
+}
+
+/*
+ * Reads i2c data from opened kernel socket.
+ */
+static int
+read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len,
+ uint8_t *buf)
+{
+ struct ifi2creq req;
+ int i, l;
+
+ if (ii->error != 0)
+ return (ii->error);
+
+ ii->ifr->ifr_data = (caddr_t)&req;
+
+ i = 0;
+ l = 0;
+ memset(&req, 0, sizeof(req));
+ req.dev_addr = addr;
+ req.offset = off;
+ req.len = len;
+
+ while (len > 0) {
+ l = MIN(sizeof(req.data), len);
+ req.len = l;
+ if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) {
+ ii->error = errno;
+ return (errno);
+ }
+
+ memcpy(&buf[i], req.data, l);
+ len -= l;
+ i += l;
+ req.offset += l;
+ }
+
+ return (0);
+}
+
+static void
+dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len)
+{
+ unsigned char buf[16];
+ int i, read;
+
+ while (len > 0) {
+ memset(buf, 0, sizeof(buf));
+ read = MIN(sizeof(buf), len);
+ read_i2c(ii, addr, off, read, buf);
+ if (ii->error != 0) {
+ fprintf(stderr, "Error reading i2c info\n");
+ return;
+ }
+
+ printf("\t");
+ for (i = 0; i < read; i++)
+ printf("%02X ", buf[i]);
+ printf("\n");
+ len -= read;
+ off += read;
+ }
+}
+
+static void
+print_qsfp_status(struct i2c_info *ii, int verbose)
+{
+ char buf[80], buf2[40], buf3[40];
+ uint32_t bitrate;
+ int i;
+
+ ii->qsfp = 1;
+
+ /* Transceiver type */
+ get_qsfp_identifier(ii, buf, sizeof(buf));
+ get_qsfp_transceiver_class(ii, buf2, sizeof(buf2));
+ get_qsfp_connector(ii, buf3, sizeof(buf3));
+ if (ii->error == 0)
+ printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
+ print_sfp_vendor(ii, buf, sizeof(buf));
+ if (ii->error == 0)
+ printf("\t%s\n", buf);
+
+ if (verbose > 1) {
+ get_qsfp_rev_compliance(ii, buf, sizeof(buf));
+ if (ii->error == 0)
+ printf("\tcompliance level: %s\n", buf);
+
+ bitrate = get_qsfp_br(ii);
+ if (ii->error == 0 && bitrate > 0)
+ printf("\tnominal bitrate: %u Mbps\n", bitrate);
+ }
+
+ /*
+ * The standards in this area are not clear when the
+ * additional measurements are present or not. Use a valid
+ * temperature reading as an indicator for the presence of
+ * voltage and TX/RX power measurements.
+ */
+ if (get_qsfp_temp(ii, buf, sizeof(buf)) == 0) {
+ get_qsfp_voltage(ii, buf2, sizeof(buf2));
+ printf("\tmodule temperature: %s voltage: %s\n", buf, buf2);
+ for (i = 1; i <= 4; i++) {
+ get_qsfp_rx_power(ii, buf, sizeof(buf), i);
+ get_qsfp_tx_power(ii, buf2, sizeof(buf2), i);
+ printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2);
+ }
+ }
+
+ if (verbose > 2) {
+ printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n");
+ dump_i2c_data(ii, SFF_8436_BASE, 128, 128);
+ printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n");
+ dump_i2c_data(ii, SFF_8436_BASE, 0, 82);
+ }
+}
+
+static void
+print_sfp_status(struct i2c_info *ii, int verbose)
+{
+ char buf[80], buf2[40], buf3[40];
+ uint8_t diag_type, flags;
+
+ /* Read diagnostic monitoring type */
+ read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type);
+ if (ii->error != 0)
+ return;
+
+ /*
+ * Read monitoring data IFF it is supplied AND is
+ * internally calibrated
+ */
+ flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL;
+ if ((diag_type & flags) == flags)
+ ii->do_diag = 1;
+
+ /* Transceiver type */
+ get_sfp_identifier(ii, buf, sizeof(buf));
+ get_sfp_transceiver_class(ii, buf2, sizeof(buf2));
+ get_sfp_connector(ii, buf3, sizeof(buf3));
+ if (ii->error == 0)
+ printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3);
+ print_sfp_vendor(ii, buf, sizeof(buf));
+ if (ii->error == 0)
+ printf("\t%s\n", buf);
+
+ if (verbose > 5)
+ printf_sfp_transceiver_descr(ii, buf, sizeof(buf));
+ /*
+ * Request current measurements iff they are provided:
+ */
+ if (ii->do_diag != 0) {
+ get_sfp_temp(ii, buf, sizeof(buf));
+ get_sfp_voltage(ii, buf2, sizeof(buf2));
+ printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2);
+ get_sfp_rx_power(ii, buf, sizeof(buf));
+ get_sfp_tx_power(ii, buf2, sizeof(buf2));
+ printf("\tRX: %s TX: %s\n", buf, buf2);
+ }
+
+ if (verbose > 2) {
+ printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n");
+ dump_i2c_data(ii, SFF_8472_BASE, 0, 128);
+ }
+}
+
+void
+sfp_status(int s, struct ifreq *ifr, int verbose)
+{
+ struct i2c_info ii;
+ uint8_t id_byte;
+
+ /* Prepare necessary into pass to i2c reader */
+ memset(&ii, 0, sizeof(ii));
+ ii.fd = s;
+ ii.ifr = ifr;
+
+ /*
+ * Try to read byte 0 from i2c:
+ * Both SFF-8472 and SFF-8436 use it as
+ * 'identification byte'.
+ * Stop reading status on zero as value -
+ * this might happen in case of empty transceiver slot.
+ */
+ id_byte = 0;
+ read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte);
+ if (ii.error != 0 || id_byte == 0)
+ return;
+
+ switch (id_byte) {
+ case SFF_8024_ID_QSFP:
+ case SFF_8024_ID_QSFPPLUS:
+ case SFF_8024_ID_QSFP28:
+ print_qsfp_status(&ii, verbose);
+ break;
+ default:
+ print_sfp_status(&ii, verbose);
+ }
+}
+
diff --git a/freebsd/sbin/pfctl/parse.c b/freebsd/sbin/pfctl/parse.c
new file mode 100644
index 00000000..1ae5fc95
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.c
@@ -0,0 +1,9315 @@
+/* original parser id follows */
+/* yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93" */
+/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */
+
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYPATCH 20160324
+
+#define YYEMPTY (-1)
+#define yyclearin (yychar = YYEMPTY)
+#define yyerrok (yyerrflag = 0)
+#define YYRECOVERING() (yyerrflag != 0)
+#define YYENOMEM (-2)
+#define YYEOF 0
+
+#ifndef yyparse
+#define yyparse pfctlyparse
+#endif /* yyparse */
+
+#ifndef yylex
+#define yylex pfctlylex
+#endif /* yylex */
+
+#ifndef yyerror
+#define yyerror pfctlyerror
+#endif /* yyerror */
+
+#ifndef yychar
+#define yychar pfctlychar
+#endif /* yychar */
+
+#ifndef yyval
+#define yyval pfctlyval
+#endif /* yyval */
+
+#ifndef yylval
+#define yylval pfctlylval
+#endif /* yylval */
+
+#ifndef yydebug
+#define yydebug pfctlydebug
+#endif /* yydebug */
+
+#ifndef yynerrs
+#define yynerrs pfctlynerrs
+#endif /* yynerrs */
+
+#ifndef yyerrflag
+#define yyerrflag pfctlyerrflag
+#endif /* yyerrflag */
+
+#ifndef yylhs
+#define yylhs pfctlylhs
+#endif /* yylhs */
+
+#ifndef yylen
+#define yylen pfctlylen
+#endif /* yylen */
+
+#ifndef yydefred
+#define yydefred pfctlydefred
+#endif /* yydefred */
+
+#ifndef yydgoto
+#define yydgoto pfctlydgoto
+#endif /* yydgoto */
+
+#ifndef yysindex
+#define yysindex pfctlysindex
+#endif /* yysindex */
+
+#ifndef yyrindex
+#define yyrindex pfctlyrindex
+#endif /* yyrindex */
+
+#ifndef yygindex
+#define yygindex pfctlygindex
+#endif /* yygindex */
+
+#ifndef yytable
+#define yytable pfctlytable
+#endif /* yytable */
+
+#ifndef yycheck
+#define yycheck pfctlycheck
+#endif /* yycheck */
+
+#ifndef yyname
+#define yyname pfctlyname
+#endif /* yyname */
+
+#ifndef yyrule
+#define yyrule pfctlyrule
+#endif /* yyrule */
+#define YYPREFIX "pfctly"
+
+#define YYPURE 0
+
+#line 30 "../../freebsd/sbin/pfctl/parse.y"
+#ifdef __rtems__
+#include <machine/rtems-bsd-user-space.h>
+#endif /* __rtems__ */
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#define pf_anchor_setup _bsd_pf_anchor_setup
+#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <err.h>
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+#include <md5.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-parse-data.h"
+#endif /* __rtems__ */
+
+static struct pfctl *pf = NULL;
+static int debug = 0;
+static int rulestate = 0;
+static u_int16_t returnicmpdefault =
+ (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+static u_int16_t returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+static int blockpolicy = PFRULE_DROP;
+static int require_order = 1;
+static int default_statelock;
+
+static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
+static struct file {
+ TAILQ_ENTRY(file) entry;
+ FILE *stream;
+ char *name;
+ int lineno;
+ int errors;
+} *file;
+struct file *pushfile(const char *, int);
+int popfile(void);
+int check_file_secrecy(int, const char *);
+int yyparse(void);
+int yylex(void);
+int yyerror(const char *, ...);
+int kw_cmp(const void *, const void *);
+int lookup(char *);
+int lgetc(int);
+int lungetc(int);
+int findeol(void);
+
+static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
+struct sym {
+ TAILQ_ENTRY(sym) entry;
+ int used;
+ int persist;
+ char *nam;
+ char *val;
+};
+int symset(const char *, const char *, int);
+char *symget(const char *);
+
+int atoul(char *, u_long *);
+
+enum {
+ PFCTL_STATE_NONE,
+ PFCTL_STATE_OPTION,
+ PFCTL_STATE_SCRUB,
+ PFCTL_STATE_QUEUE,
+ PFCTL_STATE_NAT,
+ PFCTL_STATE_FILTER
+};
+
+struct node_proto {
+ u_int8_t proto;
+ struct node_proto *next;
+ struct node_proto *tail;
+};
+
+struct node_port {
+ u_int16_t port[2];
+ u_int8_t op;
+ struct node_port *next;
+ struct node_port *tail;
+};
+
+struct node_uid {
+ uid_t uid[2];
+ u_int8_t op;
+ struct node_uid *next;
+ struct node_uid *tail;
+};
+
+struct node_gid {
+ gid_t gid[2];
+ u_int8_t op;
+ struct node_gid *next;
+ struct node_gid *tail;
+};
+
+struct node_icmp {
+ u_int8_t code;
+ u_int8_t type;
+ u_int8_t proto;
+ struct node_icmp *next;
+ struct node_icmp *tail;
+};
+
+enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
+ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
+ PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
+ PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
+
+enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
+
+struct node_state_opt {
+ int type;
+ union {
+ u_int32_t max_states;
+ u_int32_t max_src_states;
+ u_int32_t max_src_conn;
+ struct {
+ u_int32_t limit;
+ u_int32_t seconds;
+ } max_src_conn_rate;
+ struct {
+ u_int8_t flush;
+ char tblname[PF_TABLE_NAME_SIZE];
+ } overload;
+ u_int32_t max_src_nodes;
+ u_int8_t src_track;
+ u_int32_t statelock;
+ struct {
+ int number;
+ u_int32_t seconds;
+ } timeout;
+ } data;
+ struct node_state_opt *next;
+ struct node_state_opt *tail;
+};
+
+struct peer {
+ struct node_host *host;
+ struct node_port *port;
+};
+
+static struct node_queue {
+ char queue[PF_QNAME_SIZE];
+ char parent[PF_QNAME_SIZE];
+ char ifname[IFNAMSIZ];
+ int scheduler;
+ struct node_queue *next;
+ struct node_queue *tail;
+} *queues = NULL;
+
+struct node_qassign {
+ char *qname;
+ char *pqname;
+};
+
+static struct filter_opts {
+ int marker;
+#define FOM_FLAGS 0x01
+#define FOM_ICMP 0x02
+#define FOM_TOS 0x04
+#define FOM_KEEP 0x08
+#define FOM_SRCTRACK 0x10
+#define FOM_SETPRIO 0x0400
+#define FOM_PRIO 0x2000
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } flags;
+ struct node_icmp *icmpspec;
+ u_int32_t tos;
+ u_int32_t prob;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep;
+ int fragment;
+ int allowopts;
+ char *label;
+ struct node_qassign queues;
+ char *tag;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+ u_int8_t prio;
+ u_int8_t set_prio[2];
+ struct {
+ struct node_host *addr;
+ u_int16_t port;
+ } divert;
+} filter_opts;
+
+static struct antispoof_opts {
+ char *label;
+ u_int rtableid;
+} antispoof_opts;
+
+static struct scrub_opts {
+ int marker;
+#define SOM_MINTTL 0x01
+#define SOM_MAXMSS 0x02
+#define SOM_FRAGCACHE 0x04
+#define SOM_SETTOS 0x08
+ int nodf;
+ int minttl;
+ int maxmss;
+ int settos;
+ int fragcache;
+ int randomid;
+ int reassemble_tcp;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+} scrub_opts;
+
+static struct queue_opts {
+ int marker;
+#define QOM_BWSPEC 0x01
+#define QOM_SCHEDULER 0x02
+#define QOM_PRIORITY 0x04
+#define QOM_TBRSIZE 0x08
+#define QOM_QLIMIT 0x10
+ struct node_queue_bw queue_bwspec;
+ struct node_queue_opt scheduler;
+ int priority;
+ int tbrsize;
+ int qlimit;
+} queue_opts;
+
+static struct table_opts {
+ int flags;
+ int init_addr;
+ struct node_tinithead init_nodes;
+} table_opts;
+
+static struct pool_opts {
+ int marker;
+#define POM_TYPE 0x01
+#define POM_STICKYADDRESS 0x02
+ u_int8_t opts;
+ int type;
+ int staticport;
+ struct pf_poolhashkey *key;
+
+} pool_opts;
+
+static struct codel_opts codel_opts;
+static struct node_hfsc_opts hfsc_opts;
+static struct node_fairq_opts fairq_opts;
+static struct node_state_opt *keep_state_defaults = NULL;
+
+int disallow_table(struct node_host *, const char *);
+int disallow_urpf_failed(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
+int rule_consistent(struct pf_rule *, int);
+int filter_consistent(struct pf_rule *, int);
+int nat_consistent(struct pf_rule *);
+int rdr_consistent(struct pf_rule *);
+int process_tabledef(char *, struct table_opts *);
+void expand_label_str(char *, size_t, const char *, const char *);
+void expand_label_if(const char *, char *, size_t, const char *);
+void expand_label_addr(const char *, char *, size_t, u_int8_t,
+ struct node_host *);
+void expand_label_port(const char *, char *, size_t,
+ struct node_port *);
+void expand_label_proto(const char *, char *, size_t, u_int8_t);
+void expand_label_nr(const char *, char *, size_t);
+void expand_label(char *, size_t, const char *, u_int8_t,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, u_int8_t);
+void expand_rule(struct pf_rule *, struct node_if *,
+ struct node_host *, struct node_proto *, struct node_os *,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, struct node_uid *, struct node_gid *,
+ struct node_icmp *, const char *);
+int expand_altq(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw bwspec,
+ struct node_queue_opt *);
+int expand_queue(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw,
+ struct node_queue_opt *);
+int expand_skip_interface(struct node_if *);
+
+int check_rulestate(int);
+int getservice(char *);
+int rule_label(struct pf_rule *, char *);
+int rt_tableid_max(void);
+
+void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
+void decide_address_family(struct node_host *, sa_family_t *);
+void remove_invalid_hosts(struct node_host **, sa_family_t *);
+int invalid_redirect(struct node_host *, sa_family_t);
+u_int16_t parseicmpspec(char *, sa_family_t);
+
+static TAILQ_HEAD(loadanchorshead, loadanchors)
+ loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
+
+struct loadanchors {
+ TAILQ_ENTRY(loadanchors) entries;
+ char *anchorname;
+ char *filename;
+};
+
+typedef struct {
+ union {
+ int64_t number;
+ double probability;
+ int i;
+ char *string;
+ u_int rtableid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } b;
+ struct range {
+ int a;
+ int b;
+ int t;
+ } range;
+ struct node_if *interface;
+ struct node_proto *proto;
+ struct node_icmp *icmp;
+ struct node_host *host;
+ struct node_os *os;
+ struct node_port *port;
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct node_state_opt *state_opt;
+ struct peer peer;
+ struct {
+ struct peer src, dst;
+ struct node_os *src_os;
+ } fromto;
+ struct {
+ struct node_host *host;
+ u_int8_t rt;
+ u_int8_t pool_opts;
+ sa_family_t af;
+ struct pf_poolhashkey *key;
+ } route;
+ struct redirection {
+ struct node_host *host;
+ struct range rport;
+ } *redirection;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep_state;
+ struct {
+ u_int8_t log;
+ u_int8_t logif;
+ u_int8_t quick;
+ } logquick;
+ struct {
+ int neg;
+ char *name;
+ } tagged;
+ struct pf_poolhashkey *hashkey;
+ struct node_queue *queue;
+ struct node_queue_opt queue_options;
+ struct node_queue_bw queue_bwspec;
+ struct node_qassign qassign;
+ struct filter_opts filter_opts;
+ struct antispoof_opts antispoof_opts;
+ struct queue_opts queue_opts;
+ struct scrub_opts scrub_opts;
+ struct table_opts table_opts;
+ struct pool_opts pool_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
+ } v;
+ int lineno;
+} YYSTYPE;
+
+#define PPORT_RANGE 1
+#define PPORT_STAR 2
+int parseport(char *, struct range *r, int);
+
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
+#line 534 "pfctly.tab.c"
+
+/* compatibility with bison */
+#ifdef YYPARSE_PARAM
+/* compatibility with FreeBSD */
+# ifdef YYPARSE_PARAM_TYPE
+# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)
+# else
+# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)
+# endif
+#else
+# define YYPARSE_DECL() yyparse(void)
+#endif
+
+/* Parameters sent to lex. */
+#ifdef YYLEX_PARAM
+# define YYLEX_DECL() yylex(void *YYLEX_PARAM)
+# define YYLEX yylex(YYLEX_PARAM)
+#else
+# define YYLEX_DECL() yylex(void)
+# define YYLEX yylex()
+#endif
+
+/* Parameters sent to yyerror. */
+#ifndef YYERROR_DECL
+#define YYERROR_DECL() yyerror(const char *s)
+#endif
+#ifndef YYERROR_CALL
+#define YYERROR_CALL(msg) yyerror(msg)
+#endif
+
+extern int YYPARSE_DECL();
+
+#define PASS 257
+#define BLOCK 258
+#define SCRUB 259
+#define RETURN 260
+#define IN 261
+#define OS 262
+#define OUT 263
+#define LOG 264
+#define QUICK 265
+#define ON 266
+#define FROM 267
+#define TO 268
+#define FLAGS 269
+#define RETURNRST 270
+#define RETURNICMP 271
+#define RETURNICMP6 272
+#define PROTO 273
+#define INET 274
+#define INET6 275
+#define ALL 276
+#define ANY 277
+#define ICMPTYPE 278
+#define ICMP6TYPE 279
+#define CODE 280
+#define KEEP 281
+#define MODULATE 282
+#define STATE 283
+#define PORT 284
+#define RDR 285
+#define NAT 286
+#define BINAT 287
+#define ARROW 288
+#define NODF 289
+#define MINTTL 290
+#define ERROR 291
+#define ALLOWOPTS 292
+#define FASTROUTE 293
+#define FILENAME 294
+#define ROUTETO 295
+#define DUPTO 296
+#define REPLYTO 297
+#define NO 298
+#define LABEL 299
+#define NOROUTE 300
+#define URPFFAILED 301
+#define FRAGMENT 302
+#define USER 303
+#define GROUP 304
+#define MAXMSS 305
+#define MAXIMUM 306
+#define TTL 307
+#define TOS 308
+#define DROP 309
+#define TABLE 310
+#define REASSEMBLE 311
+#define FRAGDROP 312
+#define FRAGCROP 313
+#define ANCHOR 314
+#define NATANCHOR 315
+#define RDRANCHOR 316
+#define BINATANCHOR 317
+#define SET 318
+#define OPTIMIZATION 319
+#define TIMEOUT 320
+#define LIMIT 321
+#define LOGINTERFACE 322
+#define BLOCKPOLICY 323
+#define RANDOMID 324
+#define REQUIREORDER 325
+#define SYNPROXY 326
+#define FINGERPRINTS 327
+#define NOSYNC 328
+#define DEBUG 329
+#define SKIP 330
+#define HOSTID 331
+#define ANTISPOOF 332
+#define FOR 333
+#define INCLUDE 334
+#define BITMASK 335
+#define RANDOM 336
+#define SOURCEHASH 337
+#define ROUNDROBIN 338
+#define STATICPORT 339
+#define PROBABILITY 340
+#define ALTQ 341
+#define CBQ 342
+#define CODEL 343
+#define PRIQ 344
+#define HFSC 345
+#define FAIRQ 346
+#define BANDWIDTH 347
+#define TBRSIZE 348
+#define LINKSHARE 349
+#define REALTIME 350
+#define UPPERLIMIT 351
+#define QUEUE 352
+#define PRIORITY 353
+#define QLIMIT 354
+#define HOGS 355
+#define BUCKETS 356
+#define RTABLE 357
+#define TARGET 358
+#define INTERVAL 359
+#define LOAD 360
+#define RULESET_OPTIMIZATION 361
+#define PRIO 362
+#define STICKYADDRESS 363
+#define MAXSRCSTATES 364
+#define MAXSRCNODES 365
+#define SOURCETRACK 366
+#define GLOBAL 367
+#define RULE 368
+#define MAXSRCCONN 369
+#define MAXSRCCONNRATE 370
+#define OVERLOAD 371
+#define FLUSH 372
+#define SLOPPY 373
+#define TAGGED 374
+#define TAG 375
+#define IFBOUND 376
+#define FLOATING 377
+#define STATEPOLICY 378
+#define STATEDEFAULTS 379
+#define ROUTE 380
+#define SETTOS 381
+#define DIVERTTO 382
+#define DIVERTREPLY 383
+#define STRING 384
+#define NUMBER 385
+#define PORTBINARY 386
+#define YYERRCODE 256
+typedef int YYINT;
+static const YYINT pfctlylhs[] = { -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 137, 150, 150,
+ 150, 150, 150, 150, 18, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 77, 77, 80, 80, 81, 81, 82, 82, 147,
+ 79, 79, 156, 156, 156, 156, 158, 157, 157, 143,
+ 143, 143, 143, 144, 26, 139, 159, 126, 126, 128,
+ 128, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 17, 17, 17, 148, 92, 92, 93, 93, 94, 94,
+ 161, 120, 120, 122, 122, 121, 121, 11, 11, 149,
+ 162, 129, 129, 131, 131, 130, 130, 130, 130, 145,
+ 146, 163, 123, 123, 125, 125, 124, 124, 124, 124,
+ 124, 113, 113, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 100, 100, 101, 102, 102, 103, 164,
+ 106, 104, 104, 105, 105, 105, 105, 105, 105, 105,
+ 165, 109, 107, 107, 108, 108, 108, 108, 108, 166,
+ 112, 110, 110, 111, 111, 111, 96, 96, 96, 97,
+ 97, 98, 142, 167, 114, 114, 116, 116, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 115, 115, 115,
+ 115, 115, 115, 115, 115, 115, 115, 117, 117, 119,
+ 119, 118, 30, 30, 13, 13, 23, 23, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 44, 44,
+ 45, 45, 15, 15, 15, 88, 88, 87, 87, 87,
+ 87, 87, 89, 89, 90, 90, 91, 91, 91, 91,
+ 1, 1, 1, 2, 2, 3, 4, 16, 16, 16,
+ 35, 35, 35, 36, 36, 37, 38, 38, 46, 46,
+ 61, 61, 61, 62, 63, 63, 48, 48, 49, 49,
+ 47, 47, 47, 152, 152, 50, 50, 50, 51, 51,
+ 55, 55, 52, 52, 52, 53, 53, 53, 53, 53,
+ 53, 53, 5, 5, 54, 64, 64, 65, 65, 66,
+ 66, 66, 31, 33, 67, 67, 68, 68, 69, 69,
+ 69, 8, 8, 70, 70, 71, 71, 72, 72, 72,
+ 9, 9, 28, 27, 27, 27, 39, 39, 39, 39,
+ 40, 40, 42, 42, 41, 41, 41, 43, 43, 43,
+ 6, 6, 7, 7, 10, 10, 19, 19, 19, 22,
+ 22, 83, 83, 83, 83, 20, 20, 20, 84, 84,
+ 85, 85, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 76, 95, 95, 95, 14, 14, 32,
+ 57, 57, 56, 56, 75, 75, 75, 34, 34, 168,
+ 132, 132, 134, 134, 133, 133, 133, 133, 133, 133,
+ 74, 74, 74, 25, 25, 25, 25, 24, 24, 140,
+ 141, 78, 78, 135, 135, 136, 136, 58, 58, 59,
+ 59, 60, 60, 73, 73, 73, 73, 73, 151, 151,
+ 153, 153, 154, 155, 155, 160, 160, 12, 12, 21,
+ 21, 21, 21, 21, 21,
+};
+static const YYINT pfctlylen[] = { 2,
+ 0, 3, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 3, 2, 2, 3,
+ 3, 3, 3, 3, 1, 3, 3, 3, 6, 3,
+ 6, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 2, 1, 2, 1, 1, 1, 3,
+ 1, 0, 0, 2, 3, 3, 0, 5, 0, 10,
+ 7, 7, 7, 5, 2, 8, 0, 2, 0, 2,
+ 1, 1, 2, 2, 2, 1, 2, 1, 2, 3,
+ 2, 2, 2, 5, 2, 5, 2, 4, 1, 3,
+ 0, 2, 0, 2, 1, 1, 2, 1, 0, 5,
+ 0, 2, 0, 2, 1, 1, 3, 4, 2, 5,
+ 5, 0, 2, 0, 2, 1, 2, 2, 2, 1,
+ 2, 1, 1, 1, 4, 1, 4, 1, 4, 1,
+ 4, 1, 4, 1, 3, 1, 1, 3, 1, 0,
+ 2, 1, 3, 2, 8, 2, 8, 2, 8, 1,
+ 0, 2, 1, 3, 2, 6, 2, 2, 1, 0,
+ 2, 1, 3, 2, 2, 1, 0, 1, 4, 2,
+ 4, 1, 9, 0, 2, 0, 2, 1, 2, 2,
+ 1, 1, 2, 2, 1, 1, 1, 1, 1, 2,
+ 3, 2, 2, 2, 4, 1, 1, 4, 2, 3,
+ 1, 1, 2, 6, 1, 1, 1, 2, 0, 1,
+ 1, 5, 1, 1, 4, 4, 6, 1, 1, 1,
+ 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
+ 2, 2, 1, 4, 1, 3, 1, 1, 1, 2,
+ 0, 2, 5, 2, 4, 2, 1, 0, 1, 1,
+ 0, 2, 5, 2, 4, 1, 1, 1, 1, 3,
+ 0, 2, 5, 1, 2, 4, 0, 2, 0, 2,
+ 1, 3, 2, 2, 0, 1, 1, 4, 2, 0,
+ 2, 4, 2, 2, 2, 1, 3, 3, 3, 1,
+ 3, 3, 1, 1, 3, 1, 4, 2, 4, 1,
+ 2, 3, 1, 1, 1, 4, 2, 4, 1, 2,
+ 3, 1, 1, 1, 4, 2, 4, 1, 2, 3,
+ 1, 1, 1, 4, 3, 2, 2, 5, 2, 5,
+ 2, 4, 2, 4, 1, 3, 3, 1, 3, 3,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
+ 1, 2, 3, 3, 3, 0, 1, 2, 3, 0,
+ 1, 3, 2, 1, 2, 2, 4, 5, 2, 1,
+ 1, 1, 2, 2, 2, 4, 6, 0, 1, 1,
+ 1, 4, 2, 4, 0, 2, 4, 0, 1, 0,
+ 2, 0, 2, 1, 1, 1, 2, 1, 1, 1,
+ 0, 2, 4, 0, 1, 2, 1, 3, 3, 10,
+ 13, 0, 2, 0, 3, 0, 2, 1, 4, 2,
+ 4, 1, 4, 0, 1, 3, 3, 3, 2, 2,
+ 4, 2, 2, 4, 2, 1, 0, 1, 1, 1,
+ 2, 2, 1, 2, 1,
+};
+static const YYINT pfctlydefred[] = { 0,
+ 0, 0, 0, 0, 207, 0, 379, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 19, 0,
+ 0, 0, 0, 0, 0, 17, 218, 0, 0, 0,
+ 210, 208, 0, 51, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 18, 0, 0, 0,
+ 0, 0, 65, 0, 0, 0, 224, 225, 0, 0,
+ 0, 2, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 24, 16, 22, 21, 23, 20,
+ 0, 0, 0, 0, 0, 44, 0, 0, 0, 26,
+ 0, 0, 0, 28, 0, 0, 30, 43, 42, 32,
+ 35, 34, 438, 439, 36, 37, 39, 40, 294, 293,
+ 33, 27, 25, 350, 351, 38, 0, 364, 0, 0,
+ 0, 0, 0, 0, 372, 0, 370, 371, 0, 361,
+ 0, 232, 0, 0, 231, 0, 98, 242, 0, 0,
+ 0, 0, 0, 49, 48, 50, 0, 0, 409, 407,
+ 408, 0, 0, 249, 250, 0, 0, 0, 219, 220,
+ 0, 221, 222, 0, 0, 227, 0, 0, 0, 0,
+ 430, 429, 0, 0, 433, 0, 363, 365, 369, 348,
+ 349, 366, 0, 0, 373, 436, 0, 0, 237, 238,
+ 239, 0, 235, 247, 0, 0, 89, 85, 0, 0,
+ 246, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 120, 116, 0, 0, 0, 46, 406, 0, 0,
+ 0, 0, 0, 0, 215, 0, 216, 100, 0, 0,
+ 0, 0, 0, 274, 0, 0, 0, 0, 0, 0,
+ 362, 240, 234, 0, 0, 0, 84, 0, 0, 0,
+ 172, 0, 110, 168, 0, 160, 0, 140, 151, 122,
+ 123, 117, 121, 118, 119, 115, 111, 64, 0, 425,
+ 0, 0, 0, 0, 257, 258, 0, 252, 256, 0,
+ 259, 0, 0, 0, 212, 0, 0, 106, 0, 105,
+ 0, 0, 0, 0, 0, 432, 29, 0, 435, 31,
+ 0, 367, 0, 236, 0, 0, 90, 0, 0, 96,
+ 95, 0, 243, 0, 244, 0, 136, 0, 134, 0,
+ 0, 139, 0, 137, 0, 0, 0, 0, 0, 418,
+ 0, 0, 422, 0, 0, 0, 0, 0, 276, 0,
+ 0, 0, 268, 0, 277, 0, 0, 0, 0, 0,
+ 217, 109, 0, 104, 0, 0, 61, 62, 63, 0,
+ 0, 0, 368, 86, 0, 87, 374, 97, 94, 0,
+ 0, 0, 125, 0, 133, 0, 0, 166, 0, 162,
+ 127, 0, 129, 0, 0, 0, 150, 0, 142, 131,
+ 0, 0, 0, 159, 0, 153, 0, 0, 0, 426,
+ 0, 428, 427, 0, 0, 0, 0, 440, 0, 0,
+ 0, 0, 0, 273, 296, 304, 0, 284, 285, 0,
+ 0, 0, 0, 283, 0, 0, 413, 0, 0, 264,
+ 0, 262, 0, 260, 0, 107, 0, 0, 0, 417,
+ 431, 434, 358, 0, 245, 169, 0, 170, 135, 165,
+ 164, 0, 138, 0, 144, 0, 146, 0, 148, 0,
+ 0, 155, 157, 158, 0, 0, 0, 0, 0, 395,
+ 396, 0, 398, 399, 400, 394, 0, 0, 253, 0,
+ 254, 0, 441, 442, 444, 301, 0, 0, 0, 0,
+ 0, 0, 0, 0, 272, 0, 0, 0, 270, 66,
+ 0, 281, 108, 0, 0, 0, 88, 0, 163, 0,
+ 0, 0, 143, 0, 154, 0, 0, 420, 423, 0,
+ 419, 397, 389, 393, 173, 0, 0, 0, 302, 278,
+ 287, 288, 289, 295, 292, 291, 415, 0, 0, 0,
+ 0, 72, 0, 0, 0, 0, 78, 0, 0, 0,
+ 76, 71, 0, 0, 57, 60, 0, 0, 0, 0,
+ 0, 187, 0, 186, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 196, 0, 181, 182, 188,
+ 185, 189, 178, 0, 197, 171, 0, 0, 0, 0,
+ 279, 0, 0, 255, 297, 0, 298, 0, 381, 0,
+ 410, 265, 263, 0, 73, 81, 83, 82, 74, 77,
+ 79, 345, 346, 75, 0, 70, 282, 0, 326, 323,
+ 0, 0, 341, 342, 0, 0, 327, 343, 344, 0,
+ 0, 329, 0, 0, 352, 312, 313, 0, 0, 0,
+ 179, 305, 321, 322, 0, 0, 0, 180, 314, 184,
+ 0, 0, 202, 199, 0, 205, 206, 192, 375, 0,
+ 193, 183, 190, 0, 194, 303, 0, 177, 0, 0,
+ 0, 0, 0, 421, 0, 0, 0, 0, 80, 53,
+ 325, 0, 0, 0, 0, 0, 0, 353, 354, 0,
+ 0, 310, 0, 0, 319, 203, 0, 201, 0, 355,
+ 0, 0, 191, 0, 0, 0, 156, 0, 299, 0,
+ 0, 387, 380, 266, 0, 324, 0, 0, 336, 337,
+ 0, 0, 339, 340, 0, 0, 0, 311, 0, 0,
+ 320, 0, 198, 0, 376, 0, 195, 0, 0, 0,
+ 0, 411, 383, 382, 0, 54, 58, 0, 0, 328,
+ 0, 331, 330, 0, 333, 359, 306, 0, 307, 315,
+ 0, 316, 0, 200, 0, 145, 147, 149, 0, 0,
+ 55, 56, 0, 0, 0, 0, 0, 377, 0, 384,
+ 332, 334, 308, 317, 204, 403,
+};
+static const YYINT pfctlydgoto[] = { 2,
+ 79, 279, 168, 227, 141, 656, 661, 669, 676, 644,
+ 372, 135, 688, 21, 89, 186, 581, 142, 157, 393,
+ 442, 158, 22, 23, 179, 24, 608, 652, 52, 683,
+ 695, 742, 443, 552, 252, 435, 308, 309, 609, 747,
+ 657, 751, 662, 191, 194, 312, 373, 313, 464, 374,
+ 547, 375, 454, 455, 468, 741, 630, 363, 498, 364,
+ 379, 462, 571, 444, 557, 445, 671, 756, 672, 678,
+ 759, 679, 304, 772, 569, 340, 130, 377, 55, 57,
+ 176, 446, 611, 718, 159, 160, 75, 197, 76, 222,
+ 223, 164, 335, 228, 612, 283, 401, 284, 242, 348,
+ 349, 353, 354, 418, 419, 355, 425, 426, 357, 409,
+ 410, 350, 292, 535, 613, 614, 615, 684, 729, 277,
+ 341, 342, 170, 243, 244, 530, 582, 583, 258, 320,
+ 321, 430, 506, 507, 459, 387, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 3,
+ 124, 204, 266, 127, 268, 745, 586, 648, 531, 217,
+ 278, 259, 171, 356, 358, 351, 536, 431,
+};
+static const YYINT pfctlysindex[] = { -28,
+ 0, 118, 1618, 94, 0, 604, 0, 57, -163, -158,
+ -158, -158, 1728, 392, -129, 213, -35, -49, 463, 0,
+ 680, -20, 213, -20, 519, 525, 538, 552, 569, 622,
+ 651, 664, 670, 678, 684, 691, 711, 714, 0, 716,
+ 424, 720, 726, 731, 749, 0, 0, 545, 650, 657,
+ 0, 0, 230, 0, -20, -158, 213, 213, 213, 386,
+ -93, -72, -226, -58, -230, 390, 403, 213, -107, -158,
+ 371, 1487, 754, 540, 486, 556, 0, 27, 0, 213,
+ -158, 428, 0, 326, 326, 326, 0, 0, 392, 579,
+ 392, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 516, 475, 532, 768, 601, 0, 579, 579, 579, 0,
+ 492, 496, 883, 0, 518, 883, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 529, 0, 555, 559,
+ 489, 567, 577, 841, 0, 587, 0, 0, 931, 0,
+ 347, 0, 19, 579, 0, 883, 0, 0, 611, 655,
+ 1926, 0, 744, 0, 0, 0, 428, 540, 0, 0,
+ 0, 213, 213, 0, 0, 747, 213, 632, 0, 0,
+ 599, 0, 0, 997, 0, 0, 213, 747, 747, 747,
+ 0, 0, 883, -156, 0, 669, 0, 0, 0, 0,
+ 0, 0, 994, 689, 0, 0, 1487, -158, 0, 0,
+ 0, 603, 0, 0, 883, 611, 0, 0, 0, 1006,
+ 0, -57, 1022, 1024, 1028, 1035, 1050, 535, 707, 713,
+ 739, 0, 0, 1926, -57, -158, 0, 0, 579, 382,
+ -47, -187, 579, 1067, 0, 532, 0, 0, -81, 579,
+ -187, -187, -187, 0, 883, 13, 883, 49, 770, 1034,
+ 0, 0, 0, 347, 34, 1082, 0, -101, 67, 883,
+ 0, 883, 0, 0, 745, 0, 750, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 747, 0,
+ 39, 39, 39, 579, 0, 0, 883, 0, 0, 192,
+ 0, 758, 894, 747, 0, 1119, 777, 0, 883, 0,
+ -81, 747, 810, 810, 810, 0, 0, -156, 0, 0,
+ 669, 0, 801, 0, 82, 883, 0, 790, 791, 0,
+ 0, -101, 0, 1006, 0, 797, 0, 679, 0, 1134,
+ 349, 0, 724, 0, 1141, 483, 1142, -274, 922, 0,
+ 883, 807, 0, 0, 0, 0, 747, 541, 0, 83,
+ 883, 246, 0, 908, 0, 813, 1006, -45, 926, -187,
+ 0, 0, 28, 0, -187, 815, 0, 0, 0, 883,
+ 883, 834, 0, 0, 34, 0, 0, 0, 0, 883,
+ 86, 883, 0, 745, 0, -107, -107, 0, 931, 0,
+ 0, 750, 0, 24, 187, 214, 0, 931, 0, 0,
+ 224, 535, -107, 0, 931, 0, 190, 56, 190, 0,
+ 765, 0, 0, -187, 97, 883, 883, 0, 1143, 1144,
+ 1146, 428, 822, 0, 0, 0, 32, 0, 0, 575,
+ 1167, 838, 839, 0, 1171, 83, 0, 852, 810, 0,
+ 883, 0, 192, 0, 0, 0, 883, 108, 0, 0,
+ 0, 0, 0, 883, 0, 0, 797, 0, 0, 0,
+ 0, 349, 0, 535, 0, 535, 0, 535, 0, 483,
+ 535, 0, 0, 0, -274, 959, 883, 136, 1188, 0,
+ 0, -158, 0, 0, 0, 0, 765, 0, 0, 541,
+ 0, 61, 0, 0, 0, 0, 428, 137, 846, 847,
+ 848, 1193, 1176, 855, 0, -158, 953, 858, 0, 0,
+ 1405, 0, 0, 32, 1122, 4400, 0, 883, 0, 931,
+ 931, 931, 0, -107, 0, 32, 758, 0, 0, 56,
+ 0, 0, 0, 0, 0, 883, 155, 883, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 417, 0, 883,
+ 200, 0, 863, 595, 866, 868, 0, 869, 550, 879,
+ 0, 0, 1405, 883, 0, 0, 235, 361, 376, 972,
+ 975, 0, 976, 0, 135, 283, 550, 37, 978, 562,
+ 69, 877, 880, -158, 570, 0, 890, 0, 0, 0,
+ 0, 0, 0, 4400, 0, 0, 888, 892, 893, 535,
+ 0, 1006, 883, 0, 0, 61, 0, 883, 0, 984,
+ 0, 0, 0, 858, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, -158, 0, 0, 1265, 0, 0,
+ 896, 1234, 0, 0, 883, 1007, 0, 0, 0, 883,
+ 1008, 0, 1249, 1249, 0, 0, 0, 883, 904, 630,
+ 0, 0, 0, 0, 883, 909, 642, 0, 0, 0,
+ -16, 934, 0, 0, 1249, 0, 0, 0, 0, 913,
+ 0, 0, 0, 1014, 0, 0, -158, 0, 931, 931,
+ 931, 1262, 810, 0, 883, 190, 428, 883, 0, 0,
+ 0, 896, 644, 659, 661, 665, 1487, 0, 0, 116,
+ 630, 0, 158, 642, 0, 0, 919, 0, 728, 0,
+ 734, 428, 0, 535, 535, 535, 0, 1017, 0, 883,
+ 363, 0, 0, 0, 654, 0, 385, 883, 0, 0,
+ 429, 883, 0, 0, 773, 452, 883, 0, 472, 883,
+ 0, 931, 0, 934, 0, 927, 0, 1269, 1271, 1272,
+ 190, 0, 0, 0, 190, 0, 0, 1296, 1304, 0,
+ 644, 0, 0, 661, 0, 0, 0, 116, 0, 0,
+ 158, 0, 930, 0, 1276, 0, 0, 0, 1037, 883,
+ 0, 0, 883, 883, 883, 883, 1277, 0, 428, 0,
+ 0, 0, 0, 0, 0, 0,
+};
+static const YYINT pfctlyrindex[] = { 36,
+ 0, 723, 738, 0, 0, 1644, 0, 0, 2743, 0,
+ 0, 0, 0, 986, 0, 1156, 0, 0, 0, 0,
+ 0, 2290, 2701, 4182, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1712, 1836, 1959,
+ 0, 0, 0, 0, 3033, 1283, 1115, 1115, 1115, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1312, 0, 0,
+ 0, 0, 1155, 1394, 0, 1521, 0, 939, 1813, 1027,
+ 0, 0, 0, 4235, 4235, 878, 0, 0, 2811, 4313,
+ 4202, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3144, 0, 629, 629, 629, 0,
+ 0, 0, -99, 0, 0, 942, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 289, 0, 0, 0, 0, 0, 0, 0, 793, 0,
+ 0, 0, 0, 15, 0, -23, 0, 0, 0, 0,
+ 0, 1055, 0, 0, 0, 0, 1318, 4267, 0, 0,
+ 0, 533, 2922, 0, 0, 4320, 3576, 0, 0, 0,
+ 687, 0, 0, 0, 2, 0, 3255, 219, 219, 219,
+ 0, 0, 1481, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 459, 0, 0, 78, 0, 0, 0, 30, 939,
+ 0, 1321, 258, 438, 795, 992, 1012, 0, 0, 0,
+ 0, 0, 0, 6, 1321, 0, 0, 0, -204, 3323,
+ 0, 505, 2139, 0, 0, 0, 0, 0, 0, 3459,
+ 73, 73, 73, 0, 574, -96, -27, 948, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, -13, -18,
+ 0, 942, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1066, 0,
+ 0, 0, 0, 3528, 0, 0, 697, 0, 0, 510,
+ 0, 154, 2167, 8, 0, 0, 0, 0, 1352, 0,
+ 684, 3645, 1331, 1331, 1331, 0, 0, 0, 0, 0,
+ 0, 0, 572, 0, 80, -17, 0, 0, 0, 0,
+ 0, 519, 0, 939, 0, 0, 0, 948, 0, 0,
+ 0, 0, 948, 0, 0, 0, 0, 0, 0, 0,
+ 78, 0, 0, 2499, 2499, 2499, 3697, 0, 0, 0,
+ 59, 0, 0, 2057, 0, 0, 748, 0, 2388, 2543,
+ 0, 0, 510, 0, 3795, 0, 0, 0, 0, 574,
+ -27, 690, 0, 0, 0, 0, 0, 0, 0, -18,
+ 948, -27, 0, 0, 0, 0, 0, 0, 287, 0,
+ 0, 0, 0, 0, 0, 0, 0, 285, 0, 0,
+ 0, 0, 0, 0, 514, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3846, 687, 142, 175, 0, 0, 710,
+ 733, 0, 695, 0, 0, 0, 510, 0, 0, 414,
+ 0, 0, 0, 0, 547, 0, 0, 0, 195, 0,
+ 942, 0, 510, 0, 882, 0, 1184, 704, 3935, 0,
+ 0, 0, 0, -17, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 23, -17, 80, 0, 0,
+ 0, 2610, 0, 0, 0, 0, 3391, 4079, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 704, 0, 0,
+ 0, 0, 0, 0, 0, 0, 75, 0, 0, 0,
+ 973, 0, 0, 510, 1338, 973, 0, -27, 0, 964,
+ 964, 964, 0, 0, 0, 510, -1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 142, 240, 10, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 229, -27,
+ 948, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 1184, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0,
+ 0, 43, -17, 0, 0, 0, 0, 209, 0, 653,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 697, 917, 0, 0, 0, 697,
+ 968, 0, 3981, 3981, 0, 0, 0, 175, 123, 0,
+ 0, 0, 0, 0, 175, 828, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3981, 0, 0, 0, 0, 0,
+ 0, 0, 0, 4033, 0, 0, 0, 0, 687, 687,
+ 687, 0, 1, 0, 10, 0, 0, -27, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 999, 0,
+ 948, 0, 0, 0, 0, 0, 0, 1353, 0, 87,
+ 264, 0, 0, 0, 0, 0, 687, 142, 0, 0,
+ 687, 142, 0, 0, 1707, 240, 10, 0, 240, 10,
+ 0, 964, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1357, 87,
+ 0, 0, 142, 142, 10, 10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+};
+static const YYINT pfctlygindex[] = { 0,
+ 1557, 0, -208, -102, -320, 0, 0, -476, -619, 771,
+ -70, 0, 0, 1359, 490, 1165, 0, 0, 0, 0,
+ 328, 1307, 0, 0, 874, 0, 0, -612, 0, 0,
+ 647, 578, -308, 0, 1650, 0, -331, 0, 0, 0,
+ -668, 0, -525, 0, 1128, 851, 923, 0, 0, -345,
+ 0, 0, -315, 0, 946, 0, 0, -379, 0, 677,
+ 0, -497, 0, 938, 0, -457, 0, 0, -554, 0,
+ 0, -444, 0, 0, 0, -421, 0, 860, 0, -8,
+ 1218, -80, 0, -182, 688, 1196, 537, 0, 130, 0,
+ 1136, 0, 0, -223, 0, 1170, 0, -312, 0, 0,
+ 1015, 0, 1004, 0, 936, 0, 0, 937, 0, 0,
+ 958, 0, 1472, 933, 821, 0, 0, -591, 0, 0,
+ 1100, 0, 1274, 1205, 0, 0, 872, 0, 0, 1135,
+ 0, -337, 955, 0, 842, -319, 0, 0, 0, 1462,
+ 1464, -3, -2, 0, 0, 0, 0, 0, 0, 0,
+ -169, -119, 0, -192, 0, 0, 0, 0, 0, -178,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define YYTABLESIZE 4783
+static const YYINT pfctlytable[] = { 44,
+ 45, 177, 58, 59, 388, 389, 206, 169, 412, 275,
+ 416, 103, 256, 267, 275, 113, 275, 251, 175, 437,
+ 68, 280, 275, 727, 248, 275, 275, 432, 433, 123,
+ 570, 412, 280, 402, 265, 1, 436, 467, 711, 93,
+ 251, 319, 275, 274, 748, 1, 230, 116, 497, 128,
+ 126, 336, 414, 275, 558, 280, 216, 725, 226, 167,
+ 167, 143, 248, 484, 167, 282, 231, 133, 248, 275,
+ 275, 275, 173, 226, 421, 307, 682, 461, 362, 310,
+ 422, 423, 267, 264, 385, 480, 481, 328, 311, 331,
+ 728, 275, 216, 439, 1, 362, 177, 275, 275, 746,
+ 344, 467, 494, 46, 761, 275, 275, 275, 690, 424,
+ 216, 496, 803, 499, 610, 439, 53, 275, 275, 437,
+ 440, 438, 441, 276, 101, 216, 275, 20, 113, 216,
+ 275, 175, 309, 516, 275, 400, 708, 327, 391, 527,
+ 216, 225, 440, 438, 441, 326, 275, 329, 439, 166,
+ 371, 216, 466, 134, 371, 309, 395, 129, 390, 169,
+ 345, 361, 346, 412, 538, 757, 309, 439, 705, 404,
+ 623, 474, 794, 330, 412, 440, 438, 441, 556, 216,
+ 216, 275, 309, 309, 309, 275, 412, 368, 584, 752,
+ 439, 343, 610, 722, 440, 438, 441, 338, 216, 383,
+ 621, 131, 121, 162, 416, 437, 394, 275, 559, 272,
+ 476, 275, 317, 180, 180, 180, 396, 440, 438, 441,
+ 54, 509, 477, 620, 167, 56, 486, 122, 251, 452,
+ 482, 631, 533, 805, 275, 275, 275, 298, 392, 490,
+ 87, 428, 88, 216, 758, 309, 495, 309, 275, 453,
+ 132, 447, 629, 488, 77, 339, 510, 668, 804, 275,
+ 549, 560, 437, 491, 81, 121, 275, 124, 275, 251,
+ 471, 472, 437, 169, 251, 251, 139, 140, 760, 625,
+ 475, 651, 478, 251, 275, 452, 412, 437, 416, 534,
+ 122, 1, 1, 1, 1, 101, 251, 251, 347, 437,
+ 437, 437, 318, 437, 369, 453, 458, 248, 369, 251,
+ 280, 125, 251, 248, 371, 439, 511, 512, 251, 550,
+ 1, 1, 1, 437, 633, 141, 281, 161, 91, 347,
+ 414, 251, 347, 1, 267, 275, 305, 306, 460, 534,
+ 267, 528, 440, 438, 441, 1, 806, 532, 80, 1,
+ 1, 1, 1, 1, 537, 412, 275, 113, 275, 275,
+ 275, 617, 618, 619, 251, 275, 275, 1, 726, 1,
+ 437, 248, 412, 4, 5, 6, 1, 548, 626, 280,
+ 124, 251, 99, 738, 99, 101, 91, 1, 251, 113,
+ 740, 309, 634, 275, 275, 1, 280, 280, 681, 414,
+ 309, 309, 224, 309, 309, 675, 216, 290, 291, 385,
+ 385, 385, 385, 385, 309, 7, 99, 224, 616, 1,
+ 309, 309, 360, 286, 309, 309, 309, 8, 216, 267,
+ 309, 9, 10, 11, 12, 13, 624, 385, 627, 360,
+ 309, 412, 275, 275, 174, 175, 286, 132, 309, 14,
+ 632, 15, 689, 286, 286, 799, 452, 286, 16, 800,
+ 580, 275, 309, 437, 647, 607, 174, 175, 369, 17,
+ 275, 275, 216, 286, 309, 370, 453, 18, 78, 309,
+ 251, 719, 416, 655, 309, 251, 251, 774, 412, 412,
+ 412, 412, 412, 553, 251, 216, 309, 309, 660, 666,
+ 667, 19, 730, 704, 309, 309, 309, 309, 706, 780,
+ 412, 649, 580, 91, 267, 216, 412, 567, 666, 667,
+ 734, 735, 736, 82, 696, 275, 275, 412, 92, 416,
+ 416, 416, 416, 416, 93, 713, 286, 267, 286, 628,
+ 715, 673, 674, 607, 115, 448, 449, 94, 720, 99,
+ 764, 458, 766, 783, 152, 723, 290, 416, 275, 275,
+ 132, 95, 775, 390, 390, 390, 390, 390, 781, 99,
+ 290, 291, 784, 450, 451, 251, 787, 788, 96, 290,
+ 791, 356, 178, 793, 111, 739, 290, 290, 744, 73,
+ 290, 390, 275, 275, 347, 693, 790, 290, 291, 124,
+ 124, 124, 124, 124, 124, 124, 290, 290, 291, 124,
+ 124, 124, 356, 114, 218, 356, 347, 275, 650, 519,
+ 773, 520, 219, 437, 437, 183, 743, 187, 782, 450,
+ 451, 97, 785, 437, 437, 437, 709, 789, 248, 255,
+ 792, 124, 216, 273, 437, 437, 216, 437, 437, 220,
+ 221, 696, 347, 347, 347, 73, 74, 347, 347, 347,
+ 98, 347, 386, 776, 347, 347, 673, 674, 437, 290,
+ 437, 290, 347, 99, 300, 286, 301, 302, 303, 100,
+ 810, 286, 286, 811, 812, 813, 814, 101, 733, 112,
+ 286, 286, 286, 102, 286, 286, 113, 286, 275, 357,
+ 103, 286, 286, 286, 300, 286, 406, 407, 84, 85,
+ 86, 286, 286, 286, 286, 286, 286, 286, 286, 403,
+ 104, 286, 216, 105, 286, 106, 437, 300, 743, 107,
+ 357, 286, 408, 357, 437, 108, 437, 286, 300, 286,
+ 109, 778, 779, 437, 653, 654, 144, 145, 286, 286,
+ 286, 286, 286, 286, 300, 300, 300, 414, 110, 658,
+ 659, 437, 437, 437, 411, 286, 267, 216, 763, 120,
+ 286, 216, 267, 136, 765, 286, 286, 216, 777, 132,
+ 132, 132, 132, 132, 132, 132, 137, 286, 286, 132,
+ 132, 132, 267, 161, 286, 286, 286, 286, 286, 241,
+ 450, 451, 41, 73, 126, 241, 241, 241, 290, 99,
+ 99, 174, 175, 786, 290, 290, 216, 300, 163, 300,
+ 165, 132, 188, 290, 290, 290, 437, 290, 290, 195,
+ 290, 414, 415, 416, 290, 290, 290, 318, 290, 267,
+ 267, 267, 267, 267, 290, 290, 290, 290, 290, 290,
+ 290, 290, 184, 185, 290, 210, 211, 290, 189, 190,
+ 318, 267, 437, 47, 290, 196, 417, 267, 437, 437,
+ 290, 318, 290, 48, 49, 50, 201, 356, 267, 267,
+ 202, 290, 290, 290, 290, 290, 290, 318, 318, 318,
+ 248, 69, 203, 99, 99, 248, 248, 437, 290, 356,
+ 214, 248, 205, 290, 248, 636, 637, 638, 290, 290,
+ 5, 6, 51, 207, 67, 192, 193, 126, 290, 291,
+ 290, 290, 670, 677, 305, 306, 335, 290, 290, 290,
+ 290, 290, 275, 642, 643, 356, 356, 356, 83, 208,
+ 356, 356, 356, 209, 356, 686, 687, 356, 356, 335,
+ 318, 212, 318, 694, 175, 356, 300, 275, 181, 182,
+ 335, 213, 300, 300, 84, 85, 86, 9, 10, 11,
+ 12, 215, 300, 300, 216, 300, 300, 338, 365, 366,
+ 437, 378, 300, 300, 300, 248, 300, 386, 386, 386,
+ 386, 386, 300, 300, 224, 357, 300, 300, 300, 300,
+ 338, 128, 300, 437, 437, 300, 232, 378, 378, 378,
+ 246, 338, 300, 666, 667, 386, 254, 357, 300, 251,
+ 300, 130, 378, 378, 378, 673, 674, 653, 654, 300,
+ 300, 300, 300, 300, 300, 414, 241, 257, 167, 335,
+ 269, 335, 749, 750, 658, 659, 300, 670, 753, 754,
+ 677, 300, 125, 357, 357, 357, 300, 300, 357, 357,
+ 357, 285, 357, 286, 114, 357, 357, 287, 300, 300,
+ 437, 437, 270, 357, 288, 300, 300, 300, 300, 300,
+ 275, 275, 414, 414, 414, 414, 414, 437, 437, 289,
+ 338, 293, 338, 443, 443, 333, 318, 294, 437, 500,
+ 501, 502, 503, 504, 414, 318, 318, 315, 318, 318,
+ 414, 323, 324, 325, 128, 670, 445, 445, 677, 318,
+ 437, 99, 337, 295, 241, 318, 318, 505, 347, 318,
+ 318, 318, 376, 352, 130, 318, 126, 126, 126, 126,
+ 126, 126, 126, 404, 404, 318, 126, 126, 126, 241,
+ 404, 404, 404, 318, 332, 378, 437, 437, 437, 381,
+ 382, 437, 437, 437, 233, 437, 386, 318, 437, 437,
+ 67, 67, 392, 397, 405, 398, 437, 114, 126, 318,
+ 281, 413, 420, 67, 318, 335, 67, 233, 427, 318,
+ 429, 456, 67, 463, 335, 335, 457, 335, 335, 470,
+ 473, 318, 318, 513, 514, 67, 515, 517, 335, 318,
+ 318, 318, 318, 521, 335, 335, 275, 524, 335, 335,
+ 335, 522, 523, 275, 335, 526, 546, 275, 551, 561,
+ 465, 562, 563, 564, 335, 469, 338, 565, 67, 566,
+ 568, 460, 335, 275, 585, 338, 338, 635, 338, 338,
+ 639, 640, 645, 641, 663, 67, 335, 664, 665, 338,
+ 685, 691, 67, 697, 692, 338, 338, 707, 335, 338,
+ 338, 338, 699, 335, 710, 338, 700, 701, 335, 650,
+ 712, 198, 199, 200, 508, 338, 714, 716, 717, 721,
+ 335, 335, 45, 338, 724, 681, 731, 732, 335, 335,
+ 335, 335, 737, 762, 771, 801, 275, 338, 275, 796,
+ 795, 797, 798, 802, 807, 45, 808, 815, 228, 338,
+ 809, 241, 99, 45, 338, 275, 45, 47, 229, 338,
+ 167, 437, 251, 128, 128, 128, 128, 128, 128, 128,
+ 416, 338, 338, 128, 128, 128, 99, 59, 437, 338,
+ 338, 338, 338, 130, 130, 130, 130, 130, 130, 130,
+ 437, 41, 401, 130, 130, 130, 402, 680, 241, 241,
+ 241, 241, 241, 241, 241, 128, 241, 146, 767, 241,
+ 241, 241, 241, 316, 275, 529, 816, 241, 241, 241,
+ 241, 275, 518, 525, 247, 130, 112, 112, 112, 112,
+ 112, 112, 112, 230, 755, 45, 622, 112, 112, 334,
+ 241, 275, 271, 299, 297, 483, 233, 314, 479, 233,
+ 233, 233, 233, 233, 322, 543, 230, 233, 233, 233,
+ 233, 545, 233, 233, 698, 233, 233, 167, 114, 539,
+ 555, 399, 233, 233, 233, 245, 233, 233, 296, 233,
+ 233, 233, 233, 233, 646, 384, 233, 233, 233, 233,
+ 275, 554, 233, 703, 42, 233, 43, 0, 367, 0,
+ 0, 241, 233, 0, 275, 0, 275, 0, 233, 0,
+ 233, 0, 0, 275, 275, 0, 0, 233, 0, 233,
+ 233, 233, 233, 233, 233, 0, 0, 241, 241, 241,
+ 241, 241, 241, 241, 0, 0, 233, 241, 241, 241,
+ 0, 233, 0, 275, 0, 0, 233, 233, 0, 0,
+ 275, 0, 0, 0, 275, 0, 0, 0, 233, 233,
+ 229, 0, 0, 0, 0, 233, 233, 233, 0, 0,
+ 275, 275, 275, 0, 45, 0, 0, 0, 45, 45,
+ 45, 45, 0, 229, 0, 45, 45, 45, 45, 0,
+ 45, 45, 0, 45, 45, 0, 0, 275, 275, 0,
+ 45, 45, 45, 0, 45, 0, 0, 0, 0, 90,
+ 45, 45, 0, 0, 45, 45, 45, 45, 0, 0,
+ 45, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 45, 0, 0, 275, 0, 275, 45, 0, 45, 0,
+ 0, 0, 0, 117, 118, 119, 0, 45, 45, 45,
+ 45, 45, 45, 0, 138, 0, 0, 39, 275, 0,
+ 0, 0, 0, 0, 45, 0, 172, 0, 0, 45,
+ 0, 0, 0, 0, 45, 45, 0, 0, 0, 0,
+ 0, 275, 275, 209, 0, 230, 45, 45, 0, 230,
+ 230, 230, 230, 45, 45, 45, 230, 230, 230, 230,
+ 0, 230, 230, 0, 230, 230, 209, 0, 0, 0,
+ 0, 0, 230, 230, 0, 230, 230, 0, 230, 230,
+ 230, 230, 230, 572, 573, 230, 230, 230, 230, 0,
+ 0, 230, 0, 0, 230, 0, 574, 0, 0, 575,
+ 0, 230, 0, 0, 0, 576, 0, 230, 0, 230,
+ 0, 211, 0, 0, 0, 0, 230, 0, 577, 0,
+ 0, 0, 0, 230, 0, 275, 275, 0, 249, 250,
+ 0, 0, 40, 253, 211, 230, 0, 0, 0, 0,
+ 230, 0, 0, 260, 0, 230, 0, 275, 0, 0,
+ 0, 578, 0, 0, 0, 0, 0, 230, 230, 0,
+ 0, 0, 0, 0, 230, 230, 230, 0, 0, 0,
+ 275, 275, 229, 0, 0, 579, 229, 229, 229, 229,
+ 0, 0, 147, 229, 229, 229, 229, 0, 229, 229,
+ 0, 229, 229, 0, 0, 0, 0, 0, 0, 229,
+ 229, 0, 229, 229, 148, 229, 229, 229, 229, 229,
+ 0, 0, 229, 229, 229, 229, 0, 0, 229, 0,
+ 0, 229, 0, 0, 0, 0, 0, 0, 229, 275,
+ 0, 0, 0, 0, 229, 213, 229, 261, 262, 263,
+ 149, 150, 151, 229, 0, 152, 153, 154, 0, 155,
+ 229, 0, 144, 145, 275, 275, 0, 0, 213, 0,
+ 156, 0, 229, 38, 5, 6, 0, 229, 0, 0,
+ 0, 0, 229, 0, 0, 485, 487, 489, 0, 0,
+ 0, 0, 492, 493, 229, 229, 0, 0, 0, 0,
+ 0, 229, 229, 229, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 0, 0, 7, 209, 209, 209, 209,
+ 0, 209, 209, 0, 209, 209, 0, 0, 0, 0,
+ 0, 9, 10, 11, 12, 209, 209, 0, 209, 209,
+ 209, 209, 209, 0, 0, 209, 209, 209, 359, 0,
+ 0, 209, 0, 0, 0, 540, 0, 541, 0, 542,
+ 0, 209, 544, 380, 0, 0, 0, 0, 214, 209,
+ 0, 385, 211, 211, 211, 211, 211, 211, 211, 211,
+ 211, 0, 0, 209, 211, 211, 211, 211, 0, 211,
+ 211, 214, 211, 211, 0, 209, 0, 0, 0, 0,
+ 209, 0, 0, 211, 211, 209, 211, 211, 211, 211,
+ 211, 0, 437, 211, 211, 211, 434, 209, 209, 211,
+ 0, 0, 0, 0, 0, 209, 209, 0, 0, 211,
+ 0, 0, 0, 0, 437, 0, 0, 211, 0, 0,
+ 0, 0, 0, 0, 0, 0, 60, 61, 62, 63,
+ 64, 211, 65, 0, 66, 0, 67, 68, 69, 0,
+ 0, 0, 0, 211, 0, 0, 271, 0, 211, 0,
+ 437, 437, 437, 211, 0, 437, 437, 437, 0, 437,
+ 0, 0, 437, 437, 0, 211, 211, 0, 70, 271,
+ 437, 702, 0, 211, 211, 0, 213, 213, 213, 213,
+ 213, 213, 213, 213, 213, 71, 72, 0, 213, 213,
+ 213, 213, 0, 213, 213, 0, 213, 213, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 213, 213, 0,
+ 213, 213, 213, 213, 213, 0, 0, 213, 213, 213,
+ 0, 0, 0, 213, 0, 0, 0, 0, 248, 0,
+ 0, 0, 0, 213, 112, 112, 112, 112, 112, 112,
+ 112, 213, 0, 0, 114, 112, 112, 0, 0, 0,
+ 0, 248, 0, 0, 0, 213, 261, 0, 0, 271,
+ 0, 0, 0, 0, 0, 0, 0, 213, 0, 0,
+ 0, 0, 213, 0, 0, 0, 0, 213, 0, 261,
+ 0, 0, 0, 0, 0, 768, 769, 770, 0, 213,
+ 213, 0, 0, 0, 0, 0, 0, 213, 213, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214, 0, 0,
+ 0, 214, 214, 214, 214, 0, 214, 214, 0, 214,
+ 214, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 214, 214, 0, 214, 214, 214, 214, 214, 0, 0,
+ 214, 214, 214, 0, 0, 0, 214, 233, 234, 235,
+ 236, 237, 238, 239, 0, 0, 214, 0, 240, 241,
+ 0, 0, 0, 0, 214, 0, 0, 0, 0, 261,
+ 0, 0, 0, 0, 0, 0, 0, 0, 214, 223,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 214, 0, 0, 0, 0, 214, 0, 0, 271, 0,
+ 214, 0, 223, 0, 271, 271, 0, 0, 0, 0,
+ 0, 0, 214, 214, 271, 271, 0, 271, 271, 0,
+ 214, 214, 0, 0, 271, 271, 271, 0, 271, 0,
+ 0, 0, 0, 0, 271, 271, 0, 0, 271, 271,
+ 271, 271, 0, 0, 271, 0, 0, 271, 0, 0,
+ 0, 0, 0, 0, 271, 0, 0, 0, 0, 0,
+ 271, 0, 271, 0, 0, 0, 0, 0, 0, 0,
+ 0, 271, 271, 271, 271, 271, 271, 269, 0, 0,
+ 248, 0, 0, 0, 0, 248, 248, 0, 271, 0,
+ 0, 248, 0, 271, 248, 0, 0, 0, 271, 271,
+ 269, 0, 0, 0, 0, 0, 0, 248, 248, 0,
+ 271, 271, 0, 0, 261, 261, 0, 271, 271, 271,
+ 248, 0, 0, 248, 261, 261, 0, 261, 261, 248,
+ 0, 0, 0, 0, 261, 261, 261, 0, 261, 0,
+ 0, 0, 248, 0, 261, 261, 0, 0, 261, 261,
+ 261, 261, 0, 0, 261, 0, 0, 261, 0, 0,
+ 0, 0, 0, 0, 261, 0, 0, 0, 0, 0,
+ 261, 0, 261, 0, 0, 248, 0, 0, 0, 0,
+ 0, 261, 261, 261, 261, 261, 261, 0, 392, 0,
+ 269, 0, 248, 0, 0, 0, 0, 0, 261, 248,
+ 0, 0, 0, 261, 0, 0, 0, 0, 261, 261,
+ 0, 392, 0, 0, 0, 0, 0, 0, 0, 0,
+ 261, 261, 0, 0, 0, 0, 0, 261, 261, 261,
+ 0, 223, 267, 223, 223, 223, 223, 223, 223, 0,
+ 0, 0, 223, 223, 223, 223, 0, 223, 223, 0,
+ 223, 223, 0, 0, 0, 267, 0, 0, 0, 0,
+ 0, 223, 223, 0, 223, 223, 223, 223, 223, 0,
+ 0, 223, 223, 223, 0, 0, 0, 223, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 223, 0, 0,
+ 0, 0, 0, 0, 0, 223, 0, 0, 0, 388,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 223,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 223, 388, 0, 0, 0, 223, 0, 0, 0,
+ 0, 223, 0, 0, 0, 0, 269, 0, 0, 0,
+ 0, 0, 0, 223, 223, 269, 269, 0, 269, 269,
+ 0, 223, 223, 0, 0, 269, 269, 269, 0, 269,
+ 0, 0, 0, 0, 0, 269, 269, 0, 0, 269,
+ 269, 269, 269, 0, 0, 269, 0, 0, 269, 0,
+ 0, 0, 0, 0, 0, 269, 0, 0, 0, 0,
+ 241, 269, 0, 269, 0, 0, 0, 0, 0, 0,
+ 0, 0, 269, 269, 269, 269, 269, 269, 0, 0,
+ 0, 0, 0, 241, 0, 0, 0, 0, 0, 269,
+ 0, 0, 0, 0, 269, 0, 0, 0, 0, 269,
+ 269, 0, 52, 0, 0, 0, 0, 0, 0, 0,
+ 392, 269, 269, 0, 0, 392, 392, 392, 269, 269,
+ 269, 392, 392, 392, 392, 52, 392, 392, 0, 392,
+ 392, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 392, 0, 0, 0, 0, 0, 392, 392, 0, 0,
+ 392, 392, 392, 0, 267, 0, 392, 0, 0, 0,
+ 267, 0, 0, 0, 0, 0, 392, 0, 0, 0,
+ 228, 0, 0, 0, 392, 0, 0, 0, 0, 0,
+ 0, 267, 267, 390, 390, 390, 390, 390, 392, 0,
+ 0, 0, 0, 228, 267, 0, 0, 267, 0, 0,
+ 392, 0, 0, 267, 0, 392, 0, 0, 0, 0,
+ 392, 390, 0, 0, 0, 52, 267, 0, 0, 0,
+ 0, 388, 392, 392, 0, 0, 388, 388, 388, 0,
+ 392, 392, 388, 388, 388, 388, 0, 388, 388, 0,
+ 388, 388, 0, 0, 0, 0, 0, 0, 0, 267,
+ 0, 388, 0, 0, 0, 0, 0, 388, 388, 0,
+ 0, 388, 388, 388, 0, 0, 267, 388, 0, 0,
+ 0, 0, 0, 267, 0, 0, 0, 388, 0, 0,
+ 0, 241, 0, 0, 0, 388, 0, 0, 0, 0,
+ 0, 0, 0, 0, 388, 388, 388, 388, 388, 388,
+ 0, 0, 0, 0, 241, 0, 0, 0, 0, 0,
+ 0, 388, 241, 0, 0, 0, 388, 241, 241, 0,
+ 0, 388, 388, 241, 241, 241, 241, 0, 0, 0,
+ 0, 0, 0, 388, 388, 0, 0, 0, 241, 0,
+ 0, 388, 388, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 52, 52, 52, 0, 52, 52, 52,
+ 52, 52, 0, 0, 0, 52, 52, 52, 52, 0,
+ 52, 52, 0, 52, 52, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 52, 241, 241, 241, 241, 241,
+ 52, 52, 223, 0, 52, 52, 52, 0, 0, 0,
+ 52, 0, 0, 0, 0, 0, 0, 241, 0, 0,
+ 52, 0, 0, 241, 0, 223, 0, 0, 52, 0,
+ 0, 0, 228, 0, 241, 241, 228, 228, 228, 228,
+ 0, 0, 52, 228, 228, 228, 228, 0, 228, 228,
+ 0, 228, 228, 0, 52, 0, 0, 0, 0, 52,
+ 0, 0, 228, 228, 52, 228, 228, 228, 228, 228,
+ 0, 0, 228, 228, 228, 0, 52, 52, 228, 0,
+ 0, 0, 0, 0, 52, 52, 0, 0, 228, 0,
+ 0, 0, 0, 0, 0, 0, 228, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 228, 0, 0, 226, 0, 223, 0, 0, 0, 0,
+ 0, 0, 228, 0, 0, 0, 0, 228, 0, 0,
+ 0, 0, 228, 0, 0, 0, 226, 0, 0, 0,
+ 0, 0, 0, 241, 228, 228, 0, 0, 241, 241,
+ 241, 0, 228, 228, 241, 241, 241, 241, 0, 241,
+ 241, 0, 241, 241, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 241, 241, 0, 241, 241, 241, 241,
+ 241, 0, 0, 241, 241, 241, 0, 0, 0, 241,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 241,
+ 0, 0, 0, 0, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 241, 0, 0, 241, 0, 226, 0, 0, 0,
+ 0, 0, 0, 241, 0, 0, 0, 0, 241, 0,
+ 0, 0, 0, 241, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 223, 241, 241, 223, 223, 223,
+ 223, 223, 0, 241, 241, 223, 223, 223, 223, 0,
+ 223, 223, 0, 223, 223, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 0,
+ 223, 223, 424, 0, 223, 223, 223, 0, 0, 0,
+ 223, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 223, 0, 0, 0, 0, 424, 0, 0, 223, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 223, 0, 0, 0, 0, 241, 0, 0,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 223,
+ 0, 0, 0, 0, 223, 0, 0, 0, 0, 0,
+ 391, 0, 0, 0, 0, 226, 223, 223, 0, 226,
+ 226, 226, 226, 0, 223, 223, 226, 226, 226, 226,
+ 0, 226, 226, 391, 226, 226, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 226, 226, 0, 0, 226, 226, 226, 0, 0,
+ 0, 226, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 226, 0, 0, 0, 0, 0, 0, 248, 226,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 226, 0, 0, 0, 0, 0, 0,
+ 0, 248, 0, 0, 0, 226, 0, 0, 0, 0,
+ 226, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 241, 226, 226, 0,
+ 0, 241, 241, 241, 0, 226, 226, 241, 241, 241,
+ 241, 0, 241, 241, 0, 241, 241, 248, 0, 0,
+ 0, 0, 0, 0, 0, 0, 241, 0, 0, 0,
+ 0, 0, 241, 241, 0, 0, 241, 241, 241, 0,
+ 248, 0, 241, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 241, 0, 0, 0, 0, 0, 0, 0,
+ 241, 248, 0, 0, 424, 241, 0, 0, 0, 424,
+ 424, 424, 0, 0, 241, 424, 424, 424, 424, 0,
+ 424, 424, 0, 424, 424, 0, 241, 0, 241, 0,
+ 0, 241, 0, 0, 424, 0, 241, 0, 0, 0,
+ 424, 424, 0, 0, 424, 424, 424, 0, 241, 241,
+ 424, 0, 0, 0, 0, 0, 241, 241, 0, 0,
+ 424, 0, 0, 0, 0, 0, 0, 0, 424, 0,
+ 0, 0, 391, 0, 251, 0, 0, 391, 391, 391,
+ 0, 0, 424, 391, 391, 391, 391, 0, 391, 391,
+ 0, 391, 391, 0, 424, 0, 0, 251, 0, 424,
+ 0, 0, 391, 0, 424, 0, 0, 0, 391, 391,
+ 0, 0, 391, 391, 391, 0, 424, 424, 391, 0,
+ 0, 0, 0, 0, 424, 424, 251, 0, 391, 0,
+ 0, 0, 0, 0, 0, 0, 391, 0, 0, 0,
+ 248, 0, 0, 0, 0, 248, 248, 248, 0, 251,
+ 391, 248, 0, 0, 248, 0, 248, 248, 0, 248,
+ 248, 0, 391, 0, 0, 0, 0, 391, 0, 0,
+ 248, 0, 391, 0, 0, 0, 248, 248, 0, 0,
+ 248, 248, 248, 0, 391, 391, 248, 251, 0, 0,
+ 0, 0, 391, 391, 0, 0, 248, 0, 0, 0,
+ 0, 0, 0, 0, 248, 0, 0, 0, 0, 248,
+ 0, 0, 0, 0, 248, 248, 248, 0, 248, 0,
+ 248, 0, 0, 248, 267, 248, 248, 0, 248, 248,
+ 248, 0, 0, 0, 0, 248, 0, 0, 0, 248,
+ 248, 0, 0, 0, 0, 248, 248, 267, 0, 248,
+ 248, 248, 248, 248, 0, 248, 0, 241, 0, 0,
+ 248, 248, 241, 241, 0, 248, 0, 0, 241, 241,
+ 241, 241, 0, 248, 0, 267, 0, 0, 0, 0,
+ 0, 0, 0, 0, 241, 241, 0, 248, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 241, 267, 248,
+ 241, 0, 0, 0, 248, 0, 241, 0, 0, 248,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 241,
+ 0, 248, 248, 0, 0, 0, 251, 0, 0, 248,
+ 248, 251, 251, 251, 0, 0, 0, 267, 0, 0,
+ 251, 0, 251, 251, 0, 251, 251, 0, 0, 0,
+ 0, 0, 241, 0, 0, 0, 251, 0, 0, 0,
+ 0, 0, 251, 251, 176, 0, 251, 251, 251, 241,
+ 0, 0, 251, 0, 0, 0, 241, 0, 251, 0,
+ 0, 0, 251, 251, 251, 251, 0, 174, 0, 0,
+ 251, 0, 251, 0, 251, 251, 0, 251, 251, 0,
+ 0, 0, 0, 0, 251, 0, 0, 0, 251, 0,
+ 360, 0, 0, 0, 251, 251, 251, 0, 251, 251,
+ 251, 251, 0, 0, 251, 0, 251, 0, 0, 0,
+ 0, 0, 0, 360, 251, 0, 0, 0, 251, 251,
+ 0, 0, 251, 0, 0, 0, 251, 251, 0, 0,
+ 0, 0, 0, 0, 0, 0, 251, 0, 0, 0,
+ 0, 0, 49, 0, 0, 0, 0, 0, 251, 0,
+ 0, 0, 0, 251, 0, 0, 267, 176, 251, 0,
+ 0, 0, 267, 267, 0, 49, 0, 0, 0, 0,
+ 251, 251, 267, 267, 0, 267, 267, 0, 251, 251,
+ 0, 0, 0, 0, 0, 0, 267, 0, 176, 0,
+ 0, 0, 267, 267, 0, 0, 267, 267, 267, 0,
+ 0, 0, 267, 360, 0, 0, 0, 267, 0, 0,
+ 0, 174, 267, 267, 267, 0, 0, 0, 0, 0,
+ 267, 0, 0, 267, 267, 0, 267, 267, 0, 0,
+ 0, 0, 0, 0, 267, 0, 0, 267, 0, 0,
+ 0, 0, 0, 267, 267, 0, 267, 267, 267, 267,
+ 0, 267, 0, 267, 0, 49, 267, 0, 0, 0,
+ 0, 0, 0, 267, 0, 0, 0, 0, 267, 267,
+ 0, 267, 0, 0, 0, 0, 267, 267, 0, 0,
+ 0, 0, 0, 0, 0, 267, 0, 0, 0, 0,
+ 0, 223, 0, 0, 0, 0, 0, 267, 0, 0,
+ 0, 0, 267, 174, 0, 0, 0, 267, 0, 0,
+ 0, 228, 174, 174, 223, 174, 174, 0, 0, 267,
+ 267, 0, 0, 0, 0, 0, 174, 267, 267, 0,
+ 0, 0, 174, 174, 228, 0, 174, 174, 174, 0,
+ 0, 0, 174, 0, 404, 0, 0, 0, 0, 360,
+ 0, 0, 174, 0, 0, 0, 0, 0, 360, 360,
+ 174, 360, 360, 0, 0, 0, 0, 404, 0, 0,
+ 0, 0, 360, 0, 174, 0, 405, 0, 360, 360,
+ 0, 0, 360, 360, 360, 0, 174, 0, 360, 0,
+ 0, 174, 0, 0, 0, 0, 174, 0, 360, 405,
+ 0, 49, 0, 0, 0, 0, 360, 0, 174, 174,
+ 49, 49, 0, 49, 49, 0, 174, 174, 0, 0,
+ 360, 0, 248, 0, 49, 0, 0, 0, 0, 251,
+ 49, 49, 360, 0, 49, 49, 49, 360, 0, 0,
+ 49, 0, 360, 0, 0, 248, 0, 174, 0, 0,
+ 49, 0, 251, 0, 360, 360, 174, 174, 49, 174,
+ 174, 0, 360, 360, 0, 0, 0, 0, 0, 0,
+ 174, 0, 49, 0, 0, 0, 174, 174, 0, 0,
+ 174, 174, 174, 0, 49, 0, 174, 0, 0, 49,
+ 0, 0, 0, 0, 49, 0, 174, 0, 0, 0,
+ 0, 0, 0, 0, 174, 0, 49, 49, 0, 0,
+ 0, 0, 0, 0, 49, 49, 0, 0, 174, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 174, 0, 167, 0, 0, 174, 0, 0, 0, 0,
+ 174, 0, 0, 223, 0, 223, 223, 223, 223, 223,
+ 0, 0, 174, 174, 223, 223, 223, 223, 0, 0,
+ 174, 174, 0, 228, 0, 0, 0, 228, 228, 228,
+ 223, 223, 0, 0, 228, 228, 228, 228, 0, 0,
+ 0, 0, 0, 223, 0, 0, 223, 0, 0, 0,
+ 228, 228, 223, 0, 0, 0, 404, 0, 0, 0,
+ 404, 404, 404, 228, 0, 223, 228, 404, 404, 404,
+ 404, 0, 228, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 404, 0, 0, 228, 0, 0, 405, 0,
+ 0, 0, 405, 405, 405, 0, 0, 0, 223, 405,
+ 405, 405, 405, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 405, 223, 0, 0, 228, 0,
+ 0, 0, 223, 0, 0, 0, 0, 0, 0, 404,
+ 404, 404, 404, 404, 248, 228, 0, 0, 0, 248,
+ 248, 251, 228, 0, 0, 248, 251, 251, 248, 0,
+ 0, 404, 0, 0, 0, 251, 0, 404, 0, 0,
+ 248, 405, 405, 405, 405, 405, 0, 251, 404, 404,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 405, 0, 0, 0, 0, 0, 405,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 405, 405, 0, 0, 0, 0, 0, 248, 248, 248,
+ 248, 248, 0, 0, 251, 251, 251, 251, 251, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 587, 248,
+ 0, 0, 0, 0, 0, 248, 251, 588, 589, 0,
+ 590, 591, 251, 0, 0, 0, 248, 248, 0, 0,
+ 0, 592, 0, 251, 251, 0, 0, 593, 338, 0,
+ 0, 594, 595, 596, 0, 0, 0, 597, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 598, 0, 0,
+ 0, 0, 0, 0, 0, 599, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 600,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 601, 0, 0, 0, 0, 602, 0, 0, 0,
+ 0, 603, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 604, 0, 0, 0, 0, 0,
+ 0, 605, 606,
+};
+static const YYINT pfctlycheck[] = { 3,
+ 3, 82, 11, 12, 324, 325, 126, 78, 10, 33,
+ 10, 10, 191, 206, 33, 10, 44, 10, 10, 33,
+ 10, 230, 40, 40, 10, 44, 44, 365, 366, 123,
+ 528, 33, 10, 346, 204, 0, 368, 383, 651, 10,
+ 33, 123, 33, 222, 713, 10, 166, 56, 428, 276,
+ 123, 275, 10, 44, 512, 33, 44, 677, 40, 33,
+ 33, 70, 267, 40, 33, 123, 169, 298, 273, 60,
+ 61, 62, 81, 40, 349, 123, 40, 123, 40, 267,
+ 355, 356, 10, 203, 10, 406, 407, 266, 276, 268,
+ 682, 33, 44, 33, 123, 40, 177, 125, 40, 712,
+ 279, 447, 423, 10, 724, 225, 125, 125, 40, 384,
+ 44, 427, 781, 429, 536, 33, 60, 40, 60, 40,
+ 60, 61, 62, 226, 123, 44, 40, 10, 123, 44,
+ 44, 123, 10, 442, 125, 344, 634, 125, 331, 459,
+ 44, 123, 60, 61, 62, 265, 60, 267, 33, 123,
+ 123, 44, 125, 384, 123, 33, 335, 384, 328, 230,
+ 280, 123, 282, 10, 477, 720, 44, 33, 626, 348,
+ 550, 395, 764, 125, 353, 60, 61, 62, 510, 44,
+ 44, 123, 60, 61, 62, 44, 33, 307, 534, 715,
+ 33, 125, 614, 670, 60, 61, 62, 299, 44, 319,
+ 546, 260, 359, 74, 10, 123, 125, 33, 517, 218,
+ 125, 125, 294, 84, 85, 86, 336, 60, 61, 62,
+ 384, 125, 401, 544, 33, 384, 40, 384, 10, 40,
+ 409, 569, 125, 788, 60, 61, 62, 246, 10, 418,
+ 261, 361, 263, 44, 721, 123, 425, 125, 40, 60,
+ 309, 371, 568, 40, 384, 357, 435, 123, 784, 359,
+ 125, 125, 359, 40, 314, 359, 125, 10, 60, 262,
+ 390, 391, 33, 344, 267, 268, 384, 385, 723, 125,
+ 400, 47, 402, 276, 384, 40, 288, 384, 288, 468,
+ 384, 256, 257, 258, 259, 294, 289, 290, 10, 60,
+ 61, 62, 384, 40, 277, 60, 377, 178, 277, 302,
+ 288, 384, 305, 299, 123, 33, 436, 437, 311, 498,
+ 285, 286, 287, 60, 125, 41, 384, 41, 299, 41,
+ 288, 324, 44, 298, 262, 277, 384, 385, 384, 518,
+ 268, 461, 60, 61, 62, 310, 791, 467, 384, 314,
+ 315, 316, 317, 318, 474, 357, 384, 352, 300, 301,
+ 384, 540, 541, 542, 357, 384, 384, 332, 385, 334,
+ 384, 357, 374, 256, 257, 258, 341, 497, 557, 357,
+ 123, 374, 374, 703, 374, 384, 357, 352, 381, 384,
+ 706, 269, 571, 384, 385, 360, 374, 375, 362, 357,
+ 278, 279, 384, 281, 282, 123, 44, 384, 385, 335,
+ 336, 337, 338, 339, 292, 298, 374, 384, 538, 384,
+ 298, 299, 384, 10, 302, 303, 304, 310, 44, 357,
+ 308, 314, 315, 316, 317, 318, 556, 363, 558, 384,
+ 318, 288, 384, 385, 384, 385, 33, 10, 326, 332,
+ 570, 334, 384, 40, 41, 771, 40, 44, 341, 775,
+ 531, 384, 340, 384, 584, 536, 384, 385, 277, 352,
+ 384, 385, 44, 60, 352, 284, 60, 360, 266, 357,
+ 262, 664, 288, 123, 362, 267, 268, 125, 335, 336,
+ 337, 338, 339, 502, 276, 44, 374, 375, 123, 384,
+ 385, 384, 685, 623, 382, 383, 384, 385, 628, 125,
+ 357, 277, 583, 24, 10, 44, 363, 526, 384, 385,
+ 699, 700, 701, 61, 605, 384, 385, 374, 10, 335,
+ 336, 337, 338, 339, 10, 655, 123, 33, 125, 123,
+ 660, 384, 385, 614, 55, 300, 301, 10, 668, 40,
+ 729, 622, 731, 125, 41, 675, 10, 363, 384, 385,
+ 123, 10, 741, 335, 336, 337, 338, 339, 747, 60,
+ 384, 385, 751, 384, 385, 357, 125, 756, 10, 33,
+ 759, 10, 257, 762, 40, 705, 40, 41, 708, 264,
+ 44, 363, 384, 385, 306, 604, 125, 384, 385, 342,
+ 343, 344, 345, 346, 347, 348, 60, 384, 385, 352,
+ 353, 354, 41, 384, 268, 44, 328, 44, 384, 45,
+ 740, 47, 276, 384, 385, 89, 707, 91, 748, 384,
+ 385, 10, 752, 349, 350, 351, 645, 757, 10, 41,
+ 760, 384, 44, 41, 358, 359, 44, 384, 385, 303,
+ 304, 732, 364, 365, 366, 264, 265, 369, 370, 371,
+ 10, 373, 10, 10, 376, 377, 384, 385, 384, 123,
+ 384, 125, 384, 10, 293, 262, 295, 296, 297, 10,
+ 800, 268, 269, 803, 804, 805, 806, 10, 697, 40,
+ 277, 278, 279, 10, 281, 282, 40, 284, 125, 10,
+ 10, 288, 289, 290, 10, 292, 358, 359, 285, 286,
+ 287, 298, 299, 300, 301, 302, 303, 304, 305, 41,
+ 10, 308, 44, 10, 311, 10, 268, 33, 809, 10,
+ 41, 318, 384, 44, 276, 10, 33, 324, 44, 326,
+ 10, 745, 745, 40, 384, 385, 376, 377, 335, 336,
+ 337, 338, 339, 340, 60, 61, 62, 10, 10, 384,
+ 385, 303, 304, 60, 41, 352, 262, 44, 41, 384,
+ 357, 44, 268, 384, 41, 362, 363, 44, 125, 342,
+ 343, 344, 345, 346, 347, 348, 384, 374, 375, 352,
+ 353, 354, 288, 40, 381, 382, 383, 384, 385, 267,
+ 384, 385, 10, 264, 10, 273, 274, 275, 262, 300,
+ 301, 384, 385, 41, 268, 269, 44, 123, 333, 125,
+ 265, 384, 307, 277, 278, 279, 123, 281, 282, 62,
+ 284, 349, 350, 351, 288, 289, 290, 10, 292, 335,
+ 336, 337, 338, 339, 298, 299, 300, 301, 302, 303,
+ 304, 305, 274, 275, 308, 367, 368, 311, 384, 385,
+ 33, 357, 349, 260, 318, 265, 384, 363, 355, 356,
+ 324, 44, 326, 270, 271, 272, 385, 306, 374, 375,
+ 385, 335, 336, 337, 338, 339, 340, 60, 61, 62,
+ 262, 10, 10, 384, 385, 267, 268, 384, 352, 328,
+ 60, 273, 385, 357, 276, 311, 312, 313, 362, 363,
+ 257, 258, 309, 385, 33, 384, 385, 123, 384, 385,
+ 374, 375, 595, 596, 384, 385, 10, 381, 382, 383,
+ 384, 385, 359, 384, 385, 364, 365, 366, 259, 385,
+ 369, 370, 371, 385, 373, 384, 385, 376, 377, 33,
+ 123, 385, 125, 384, 385, 384, 262, 384, 85, 86,
+ 44, 385, 268, 269, 285, 286, 287, 314, 315, 316,
+ 317, 385, 278, 279, 44, 281, 282, 10, 302, 303,
+ 277, 259, 288, 289, 290, 357, 292, 335, 336, 337,
+ 338, 339, 298, 299, 384, 306, 302, 303, 304, 305,
+ 33, 10, 308, 300, 301, 311, 352, 285, 286, 287,
+ 267, 44, 318, 384, 385, 363, 385, 328, 324, 273,
+ 326, 10, 285, 286, 287, 384, 385, 384, 385, 335,
+ 336, 337, 338, 339, 340, 288, 10, 41, 33, 123,
+ 47, 125, 384, 385, 384, 385, 352, 720, 384, 385,
+ 723, 357, 384, 364, 365, 366, 362, 363, 369, 370,
+ 371, 40, 373, 40, 10, 376, 377, 40, 374, 375,
+ 384, 385, 384, 384, 40, 381, 382, 383, 384, 385,
+ 384, 385, 335, 336, 337, 338, 339, 384, 385, 40,
+ 123, 385, 125, 384, 385, 62, 269, 385, 306, 335,
+ 336, 337, 338, 339, 357, 278, 279, 41, 281, 282,
+ 363, 261, 262, 263, 123, 788, 384, 385, 791, 292,
+ 328, 374, 41, 385, 10, 298, 299, 363, 384, 302,
+ 303, 304, 375, 384, 123, 308, 342, 343, 344, 345,
+ 346, 347, 348, 266, 267, 318, 352, 353, 354, 123,
+ 273, 274, 275, 326, 385, 262, 364, 365, 366, 41,
+ 384, 369, 370, 371, 10, 373, 357, 340, 376, 377,
+ 289, 290, 372, 384, 41, 385, 384, 123, 384, 352,
+ 384, 41, 41, 302, 357, 269, 305, 33, 267, 362,
+ 384, 284, 311, 268, 278, 279, 384, 281, 282, 385,
+ 367, 374, 375, 61, 61, 324, 61, 386, 292, 382,
+ 383, 384, 385, 47, 298, 299, 33, 47, 302, 303,
+ 304, 384, 384, 40, 308, 374, 268, 44, 41, 384,
+ 380, 385, 385, 41, 318, 385, 269, 62, 357, 385,
+ 288, 384, 326, 60, 123, 278, 279, 385, 281, 282,
+ 385, 384, 374, 385, 283, 374, 340, 283, 283, 292,
+ 283, 385, 381, 374, 385, 298, 299, 284, 352, 302,
+ 303, 304, 385, 357, 10, 308, 385, 385, 362, 384,
+ 47, 117, 118, 119, 434, 318, 280, 280, 40, 386,
+ 374, 375, 10, 326, 386, 362, 384, 284, 382, 383,
+ 384, 385, 41, 385, 288, 10, 123, 340, 125, 41,
+ 384, 41, 41, 10, 385, 33, 41, 41, 333, 352,
+ 284, 10, 384, 41, 357, 384, 44, 10, 164, 362,
+ 10, 384, 267, 342, 343, 344, 345, 346, 347, 348,
+ 10, 374, 375, 352, 353, 354, 374, 10, 385, 382,
+ 383, 384, 385, 342, 343, 344, 345, 346, 347, 348,
+ 362, 3, 10, 352, 353, 354, 10, 597, 342, 343,
+ 344, 345, 346, 347, 348, 384, 262, 71, 732, 353,
+ 354, 267, 268, 256, 33, 463, 809, 273, 274, 275,
+ 276, 40, 447, 456, 177, 384, 342, 343, 344, 345,
+ 346, 347, 348, 10, 717, 123, 547, 353, 354, 274,
+ 384, 60, 217, 249, 245, 412, 262, 253, 404, 265,
+ 266, 267, 268, 269, 260, 490, 33, 273, 274, 275,
+ 276, 495, 278, 279, 614, 281, 282, 33, 384, 482,
+ 508, 342, 288, 289, 290, 172, 292, 293, 244, 295,
+ 296, 297, 298, 299, 583, 321, 302, 303, 304, 305,
+ 277, 507, 308, 622, 3, 311, 3, -1, 304, -1,
+ -1, 357, 318, -1, 123, -1, 125, -1, 324, -1,
+ 326, -1, -1, 300, 301, -1, -1, 333, -1, 335,
+ 336, 337, 338, 339, 340, -1, -1, 342, 343, 344,
+ 345, 346, 347, 348, -1, -1, 352, 352, 353, 354,
+ -1, 357, -1, 33, -1, -1, 362, 363, -1, -1,
+ 40, -1, -1, -1, 44, -1, -1, -1, 374, 375,
+ 10, -1, -1, -1, -1, 381, 382, 383, -1, -1,
+ 60, 61, 62, -1, 262, -1, -1, -1, 266, 267,
+ 268, 269, -1, 33, -1, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, 384, 385, -1,
+ 288, 289, 290, -1, 292, -1, -1, -1, -1, 23,
+ 298, 299, -1, -1, 302, 303, 304, 305, -1, -1,
+ 308, -1, -1, 311, -1, -1, -1, -1, -1, -1,
+ 318, -1, -1, 123, -1, 125, 324, -1, 326, -1,
+ -1, -1, -1, 57, 58, 59, -1, 335, 336, 337,
+ 338, 339, 340, -1, 68, -1, -1, 10, 277, -1,
+ -1, -1, -1, -1, 352, -1, 80, -1, -1, 357,
+ -1, -1, -1, -1, 362, 363, -1, -1, -1, -1,
+ -1, 300, 301, 10, -1, 262, 374, 375, -1, 266,
+ 267, 268, 269, 381, 382, 383, 273, 274, 275, 276,
+ -1, 278, 279, -1, 281, 282, 33, -1, -1, -1,
+ -1, -1, 289, 290, -1, 292, 293, -1, 295, 296,
+ 297, 298, 299, 289, 290, 302, 303, 304, 305, -1,
+ -1, 308, -1, -1, 311, -1, 302, -1, -1, 305,
+ -1, 318, -1, -1, -1, 311, -1, 324, -1, 326,
+ -1, 10, -1, -1, -1, -1, 333, -1, 324, -1,
+ -1, -1, -1, 340, -1, 384, 385, -1, 182, 183,
+ -1, -1, 125, 187, 33, 352, -1, -1, -1, -1,
+ 357, -1, -1, 197, -1, 362, -1, 277, -1, -1,
+ -1, 357, -1, -1, -1, -1, -1, 374, 375, -1,
+ -1, -1, -1, -1, 381, 382, 383, -1, -1, -1,
+ 300, 301, 262, -1, -1, 381, 266, 267, 268, 269,
+ -1, -1, 306, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, -1, -1, -1, -1, -1, 289,
+ 290, -1, 292, 293, 328, 295, 296, 297, 298, 299,
+ -1, -1, 302, 303, 304, 305, -1, -1, 308, -1,
+ -1, 311, -1, -1, -1, -1, -1, -1, 318, 359,
+ -1, -1, -1, -1, 324, 10, 326, 198, 199, 200,
+ 364, 365, 366, 333, -1, 369, 370, 371, -1, 373,
+ 340, -1, 376, 377, 384, 385, -1, -1, 33, -1,
+ 384, -1, 352, 256, 257, 258, -1, 357, -1, -1,
+ -1, -1, 362, -1, -1, 414, 415, 416, -1, -1,
+ -1, -1, 421, 422, 374, 375, -1, -1, -1, -1,
+ -1, 381, 382, 383, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, -1, -1, 298, 273, 274, 275, 276,
+ -1, 278, 279, -1, 281, 282, -1, -1, -1, -1,
+ -1, 314, 315, 316, 317, 292, 293, -1, 295, 296,
+ 297, 298, 299, -1, -1, 302, 303, 304, 299, -1,
+ -1, 308, -1, -1, -1, 484, -1, 486, -1, 488,
+ -1, 318, 491, 314, -1, -1, -1, -1, 10, 326,
+ -1, 322, 261, 262, 263, 264, 265, 266, 267, 268,
+ 269, -1, -1, 340, 273, 274, 275, 276, -1, 278,
+ 279, 33, 281, 282, -1, 352, -1, -1, -1, -1,
+ 357, -1, -1, 292, 293, 362, 295, 296, 297, 298,
+ 299, -1, 306, 302, 303, 304, 367, 374, 375, 308,
+ -1, -1, -1, -1, -1, 382, 383, -1, -1, 318,
+ -1, -1, -1, -1, 328, -1, -1, 326, -1, -1,
+ -1, -1, -1, -1, -1, -1, 319, 320, 321, 322,
+ 323, 340, 325, -1, 327, -1, 329, 330, 331, -1,
+ -1, -1, -1, 352, -1, -1, 10, -1, 357, -1,
+ 364, 365, 366, 362, -1, 369, 370, 371, -1, 373,
+ -1, -1, 376, 377, -1, 374, 375, -1, 361, 33,
+ 384, 620, -1, 382, 383, -1, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 378, 379, -1, 273, 274,
+ 275, 276, -1, 278, 279, -1, 281, 282, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 292, 293, -1,
+ 295, 296, 297, 298, 299, -1, -1, 302, 303, 304,
+ -1, -1, -1, 308, -1, -1, -1, -1, 10, -1,
+ -1, -1, -1, 318, 342, 343, 344, 345, 346, 347,
+ 348, 326, -1, -1, 352, 353, 354, -1, -1, -1,
+ -1, 33, -1, -1, -1, 340, 10, -1, -1, 123,
+ -1, -1, -1, -1, -1, -1, -1, 352, -1, -1,
+ -1, -1, 357, -1, -1, -1, -1, 362, -1, 33,
+ -1, -1, -1, -1, -1, 734, 735, 736, -1, 374,
+ 375, -1, -1, -1, -1, -1, -1, 382, 383, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, -1, -1,
+ -1, 273, 274, 275, 276, -1, 278, 279, -1, 281,
+ 282, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 292, 293, -1, 295, 296, 297, 298, 299, -1, -1,
+ 302, 303, 304, -1, -1, -1, 308, 342, 343, 344,
+ 345, 346, 347, 348, -1, -1, 318, -1, 353, 354,
+ -1, -1, -1, -1, 326, -1, -1, -1, -1, 123,
+ -1, -1, -1, -1, -1, -1, -1, -1, 340, 10,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 352, -1, -1, -1, -1, 357, -1, -1, 262, -1,
+ 362, -1, 33, -1, 268, 269, -1, -1, -1, -1,
+ -1, -1, 374, 375, 278, 279, -1, 281, 282, -1,
+ 382, 383, -1, -1, 288, 289, 290, -1, 292, -1,
+ -1, -1, -1, -1, 298, 299, -1, -1, 302, 303,
+ 304, 305, -1, -1, 308, -1, -1, 311, -1, -1,
+ -1, -1, -1, -1, 318, -1, -1, -1, -1, -1,
+ 324, -1, 326, -1, -1, -1, -1, -1, -1, -1,
+ -1, 335, 336, 337, 338, 339, 340, 10, -1, -1,
+ 262, -1, -1, -1, -1, 267, 268, -1, 352, -1,
+ -1, 273, -1, 357, 276, -1, -1, -1, 362, 363,
+ 33, -1, -1, -1, -1, -1, -1, 289, 290, -1,
+ 374, 375, -1, -1, 268, 269, -1, 381, 382, 383,
+ 302, -1, -1, 305, 278, 279, -1, 281, 282, 311,
+ -1, -1, -1, -1, 288, 289, 290, -1, 292, -1,
+ -1, -1, 324, -1, 298, 299, -1, -1, 302, 303,
+ 304, 305, -1, -1, 308, -1, -1, 311, -1, -1,
+ -1, -1, -1, -1, 318, -1, -1, -1, -1, -1,
+ 324, -1, 326, -1, -1, 357, -1, -1, -1, -1,
+ -1, 335, 336, 337, 338, 339, 340, -1, 10, -1,
+ 123, -1, 374, -1, -1, -1, -1, -1, 352, 381,
+ -1, -1, -1, 357, -1, -1, -1, -1, 362, 363,
+ -1, 33, -1, -1, -1, -1, -1, -1, -1, -1,
+ 374, 375, -1, -1, -1, -1, -1, 381, 382, 383,
+ -1, 262, 10, 264, 265, 266, 267, 268, 269, -1,
+ -1, -1, 273, 274, 275, 276, -1, 278, 279, -1,
+ 281, 282, -1, -1, -1, 33, -1, -1, -1, -1,
+ -1, 292, 293, -1, 295, 296, 297, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, -1, 308, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 318, -1, -1,
+ -1, -1, -1, -1, -1, 326, -1, -1, -1, 10,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 340,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 352, 33, -1, -1, -1, 357, -1, -1, -1,
+ -1, 362, -1, -1, -1, -1, 269, -1, -1, -1,
+ -1, -1, -1, 374, 375, 278, 279, -1, 281, 282,
+ -1, 382, 383, -1, -1, 288, 289, 290, -1, 292,
+ -1, -1, -1, -1, -1, 298, 299, -1, -1, 302,
+ 303, 304, 305, -1, -1, 308, -1, -1, 311, -1,
+ -1, -1, -1, -1, -1, 318, -1, -1, -1, -1,
+ 10, 324, -1, 326, -1, -1, -1, -1, -1, -1,
+ -1, -1, 335, 336, 337, 338, 339, 340, -1, -1,
+ -1, -1, -1, 33, -1, -1, -1, -1, -1, 352,
+ -1, -1, -1, -1, 357, -1, -1, -1, -1, 362,
+ 363, -1, 10, -1, -1, -1, -1, -1, -1, -1,
+ 262, 374, 375, -1, -1, 267, 268, 269, 381, 382,
+ 383, 273, 274, 275, 276, 33, 278, 279, -1, 281,
+ 282, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 292, -1, -1, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 262, -1, 308, -1, -1, -1,
+ 268, -1, -1, -1, -1, -1, 318, -1, -1, -1,
+ 10, -1, -1, -1, 326, -1, -1, -1, -1, -1,
+ -1, 289, 290, 335, 336, 337, 338, 339, 340, -1,
+ -1, -1, -1, 33, 302, -1, -1, 305, -1, -1,
+ 352, -1, -1, 311, -1, 357, -1, -1, -1, -1,
+ 362, 363, -1, -1, -1, 123, 324, -1, -1, -1,
+ -1, 262, 374, 375, -1, -1, 267, 268, 269, -1,
+ 382, 383, 273, 274, 275, 276, -1, 278, 279, -1,
+ 281, 282, -1, -1, -1, -1, -1, -1, -1, 357,
+ -1, 292, -1, -1, -1, -1, -1, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, 374, 308, -1, -1,
+ -1, -1, -1, 381, -1, -1, -1, 318, -1, -1,
+ -1, 10, -1, -1, -1, 326, -1, -1, -1, -1,
+ -1, -1, -1, -1, 335, 336, 337, 338, 339, 340,
+ -1, -1, -1, -1, 33, -1, -1, -1, -1, -1,
+ -1, 352, 262, -1, -1, -1, 357, 267, 268, -1,
+ -1, 362, 363, 273, 274, 275, 276, -1, -1, -1,
+ -1, -1, -1, 374, 375, -1, -1, -1, 288, -1,
+ -1, 382, 383, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 261, 262, 263, -1, 265, 266, 267,
+ 268, 269, -1, -1, -1, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 292, 335, 336, 337, 338, 339,
+ 298, 299, 10, -1, 302, 303, 304, -1, -1, -1,
+ 308, -1, -1, -1, -1, -1, -1, 357, -1, -1,
+ 318, -1, -1, 363, -1, 33, -1, -1, 326, -1,
+ -1, -1, 262, -1, 374, 375, 266, 267, 268, 269,
+ -1, -1, 340, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, 352, -1, -1, -1, -1, 357,
+ -1, -1, 292, 293, 362, 295, 296, 297, 298, 299,
+ -1, -1, 302, 303, 304, -1, 374, 375, 308, -1,
+ -1, -1, -1, -1, 382, 383, -1, -1, 318, -1,
+ -1, -1, -1, -1, -1, -1, 326, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 340, -1, -1, 10, -1, 123, -1, -1, -1, -1,
+ -1, -1, 352, -1, -1, -1, -1, 357, -1, -1,
+ -1, -1, 362, -1, -1, -1, 33, -1, -1, -1,
+ -1, -1, -1, 262, 374, 375, -1, -1, 267, 268,
+ 269, -1, 382, 383, 273, 274, 275, 276, -1, 278,
+ 279, -1, 281, 282, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 292, 293, -1, 295, 296, 297, 298,
+ 299, -1, -1, 302, 303, 304, -1, -1, -1, 308,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 318,
+ -1, -1, -1, -1, -1, -1, -1, 326, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 340, -1, -1, 10, -1, 123, -1, -1, -1,
+ -1, -1, -1, 352, -1, -1, -1, -1, 357, -1,
+ -1, -1, -1, 362, -1, -1, -1, 33, -1, -1,
+ -1, -1, -1, -1, 262, 374, 375, 265, 266, 267,
+ 268, 269, -1, 382, 383, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 292, -1, -1, -1, -1, -1,
+ 298, 299, 10, -1, 302, 303, 304, -1, -1, -1,
+ 308, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 318, -1, -1, -1, -1, 33, -1, -1, 326, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 340, -1, -1, -1, -1, 123, -1, -1,
+ -1, -1, -1, -1, 352, -1, -1, -1, -1, 357,
+ -1, -1, -1, -1, 362, -1, -1, -1, -1, -1,
+ 10, -1, -1, -1, -1, 262, 374, 375, -1, 266,
+ 267, 268, 269, -1, 382, 383, 273, 274, 275, 276,
+ -1, 278, 279, 33, 281, 282, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 292, -1, -1, -1, -1,
+ -1, 298, 299, -1, -1, 302, 303, 304, -1, -1,
+ -1, 308, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 318, -1, -1, -1, -1, -1, -1, 10, 326,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 340, -1, -1, -1, -1, -1, -1,
+ -1, 33, -1, -1, -1, 352, -1, -1, -1, -1,
+ 357, -1, -1, -1, -1, 362, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 262, 374, 375, -1,
+ -1, 267, 268, 269, -1, 382, 383, 273, 274, 275,
+ 276, -1, 278, 279, -1, 281, 282, 10, -1, -1,
+ -1, -1, -1, -1, -1, -1, 292, -1, -1, -1,
+ -1, -1, 298, 299, -1, -1, 302, 303, 304, -1,
+ 33, -1, 308, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 318, -1, -1, -1, -1, -1, -1, -1,
+ 326, 123, -1, -1, 262, 10, -1, -1, -1, 267,
+ 268, 269, -1, -1, 340, 273, 274, 275, 276, -1,
+ 278, 279, -1, 281, 282, -1, 352, -1, 33, -1,
+ -1, 357, -1, -1, 292, -1, 362, -1, -1, -1,
+ 298, 299, -1, -1, 302, 303, 304, -1, 374, 375,
+ 308, -1, -1, -1, -1, -1, 382, 383, -1, -1,
+ 318, -1, -1, -1, -1, -1, -1, -1, 326, -1,
+ -1, -1, 262, -1, 10, -1, -1, 267, 268, 269,
+ -1, -1, 340, 273, 274, 275, 276, -1, 278, 279,
+ -1, 281, 282, -1, 352, -1, -1, 33, -1, 357,
+ -1, -1, 292, -1, 362, -1, -1, -1, 298, 299,
+ -1, -1, 302, 303, 304, -1, 374, 375, 308, -1,
+ -1, -1, -1, -1, 382, 383, 10, -1, 318, -1,
+ -1, -1, -1, -1, -1, -1, 326, -1, -1, -1,
+ 262, -1, -1, -1, -1, 267, 268, 269, -1, 33,
+ 340, 273, -1, -1, 276, -1, 278, 279, -1, 281,
+ 282, -1, 352, -1, -1, -1, -1, 357, -1, -1,
+ 292, -1, 362, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 374, 375, 308, 123, -1, -1,
+ -1, -1, 382, 383, -1, -1, 318, -1, -1, -1,
+ -1, -1, -1, -1, 326, -1, -1, -1, -1, 262,
+ -1, -1, -1, -1, 267, 268, 269, -1, 340, -1,
+ 273, -1, -1, 276, 10, 278, 279, -1, 281, 282,
+ 352, -1, -1, -1, -1, 357, -1, -1, -1, 292,
+ 362, -1, -1, -1, -1, 298, 299, 33, -1, 302,
+ 303, 304, 374, 375, -1, 308, -1, 262, -1, -1,
+ 382, 383, 267, 268, -1, 318, -1, -1, 273, 274,
+ 275, 276, -1, 326, -1, 10, -1, -1, -1, -1,
+ -1, -1, -1, -1, 289, 290, -1, 340, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 302, 33, 352,
+ 305, -1, -1, -1, 357, -1, 311, -1, -1, 362,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 324,
+ -1, 374, 375, -1, -1, -1, 262, -1, -1, 382,
+ 383, 267, 268, 269, -1, -1, -1, 123, -1, -1,
+ 276, -1, 278, 279, -1, 281, 282, -1, -1, -1,
+ -1, -1, 357, -1, -1, -1, 292, -1, -1, -1,
+ -1, -1, 298, 299, 10, -1, 302, 303, 304, 374,
+ -1, -1, 308, -1, -1, -1, 381, -1, 262, -1,
+ -1, -1, 318, 267, 268, 269, -1, 33, -1, -1,
+ 326, -1, 276, -1, 278, 279, -1, 281, 282, -1,
+ -1, -1, -1, -1, 340, -1, -1, -1, 292, -1,
+ 10, -1, -1, -1, 298, 299, 352, -1, 302, 303,
+ 304, 357, -1, -1, 308, -1, 362, -1, -1, -1,
+ -1, -1, -1, 33, 318, -1, -1, -1, 374, 375,
+ -1, -1, 326, -1, -1, -1, 382, 383, -1, -1,
+ -1, -1, -1, -1, -1, -1, 340, -1, -1, -1,
+ -1, -1, 10, -1, -1, -1, -1, -1, 352, -1,
+ -1, -1, -1, 357, -1, -1, 262, 123, 362, -1,
+ -1, -1, 268, 269, -1, 33, -1, -1, -1, -1,
+ 374, 375, 278, 279, -1, 281, 282, -1, 382, 383,
+ -1, -1, -1, -1, -1, -1, 292, -1, 10, -1,
+ -1, -1, 298, 299, -1, -1, 302, 303, 304, -1,
+ -1, -1, 308, 123, -1, -1, -1, 262, -1, -1,
+ -1, 33, 318, 268, 269, -1, -1, -1, -1, -1,
+ 326, -1, -1, 278, 279, -1, 281, 282, -1, -1,
+ -1, -1, -1, -1, 340, -1, -1, 292, -1, -1,
+ -1, -1, -1, 298, 299, -1, 352, 302, 303, 304,
+ -1, 357, -1, 308, -1, 123, 362, -1, -1, -1,
+ -1, -1, -1, 318, -1, -1, -1, -1, 374, 375,
+ -1, 326, -1, -1, -1, -1, 382, 383, -1, -1,
+ -1, -1, -1, -1, -1, 340, -1, -1, -1, -1,
+ -1, 10, -1, -1, -1, -1, -1, 352, -1, -1,
+ -1, -1, 357, 269, -1, -1, -1, 362, -1, -1,
+ -1, 10, 278, 279, 33, 281, 282, -1, -1, 374,
+ 375, -1, -1, -1, -1, -1, 292, 382, 383, -1,
+ -1, -1, 298, 299, 33, -1, 302, 303, 304, -1,
+ -1, -1, 308, -1, 10, -1, -1, -1, -1, 269,
+ -1, -1, 318, -1, -1, -1, -1, -1, 278, 279,
+ 326, 281, 282, -1, -1, -1, -1, 33, -1, -1,
+ -1, -1, 292, -1, 340, -1, 10, -1, 298, 299,
+ -1, -1, 302, 303, 304, -1, 352, -1, 308, -1,
+ -1, 357, -1, -1, -1, -1, 362, -1, 318, 33,
+ -1, 269, -1, -1, -1, -1, 326, -1, 374, 375,
+ 278, 279, -1, 281, 282, -1, 382, 383, -1, -1,
+ 340, -1, 10, -1, 292, -1, -1, -1, -1, 10,
+ 298, 299, 352, -1, 302, 303, 304, 357, -1, -1,
+ 308, -1, 362, -1, -1, 33, -1, 269, -1, -1,
+ 318, -1, 33, -1, 374, 375, 278, 279, 326, 281,
+ 282, -1, 382, 383, -1, -1, -1, -1, -1, -1,
+ 292, -1, 340, -1, -1, -1, 298, 299, -1, -1,
+ 302, 303, 304, -1, 352, -1, 308, -1, -1, 357,
+ -1, -1, -1, -1, 362, -1, 318, -1, -1, -1,
+ -1, -1, -1, -1, 326, -1, 374, 375, -1, -1,
+ -1, -1, -1, -1, 382, 383, -1, -1, 340, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 352, -1, 33, -1, -1, 357, -1, -1, -1, -1,
+ 362, -1, -1, 262, -1, 264, 265, 266, 267, 268,
+ -1, -1, 374, 375, 273, 274, 275, 276, -1, -1,
+ 382, 383, -1, 262, -1, -1, -1, 266, 267, 268,
+ 289, 290, -1, -1, 273, 274, 275, 276, -1, -1,
+ -1, -1, -1, 302, -1, -1, 305, -1, -1, -1,
+ 289, 290, 311, -1, -1, -1, 262, -1, -1, -1,
+ 266, 267, 268, 302, -1, 324, 305, 273, 274, 275,
+ 276, -1, 311, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 288, -1, -1, 324, -1, -1, 262, -1,
+ -1, -1, 266, 267, 268, -1, -1, -1, 357, 273,
+ 274, 275, 276, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 288, 374, -1, -1, 357, -1,
+ -1, -1, 381, -1, -1, -1, -1, -1, -1, 335,
+ 336, 337, 338, 339, 262, 374, -1, -1, -1, 267,
+ 268, 262, 381, -1, -1, 273, 267, 268, 276, -1,
+ -1, 357, -1, -1, -1, 276, -1, 363, -1, -1,
+ 288, 335, 336, 337, 338, 339, -1, 288, 374, 375,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 357, -1, -1, -1, -1, -1, 363,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 374, 375, -1, -1, -1, -1, -1, 335, 336, 337,
+ 338, 339, -1, -1, 335, 336, 337, 338, 339, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 269, 357,
+ -1, -1, -1, -1, -1, 363, 357, 278, 279, -1,
+ 281, 282, 363, -1, -1, -1, 374, 375, -1, -1,
+ -1, 292, -1, 374, 375, -1, -1, 298, 299, -1,
+ -1, 302, 303, 304, -1, -1, -1, 308, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 318, -1, -1,
+ -1, -1, -1, -1, -1, 326, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 340,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 352, -1, -1, -1, -1, 357, -1, -1, -1,
+ -1, 362, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 375, -1, -1, -1, -1, -1,
+ -1, 382, 383,
+};
+#define YYFINAL 2
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 386
+#define YYUNDFTOKEN 557
+#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a))
+#if YYDEBUG
+static const char *const pfctlyname[] = {
+
+"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,"'!'",0,0,0,0,0,0,"'('","')'",0,0,"','","'-'",0,"'/'",0,0,0,0,0,0,0,0,0,0,0,
+0,"'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,"PASS","BLOCK","SCRUB","RETURN","IN","OS","OUT","LOG","QUICK",
+"ON","FROM","TO","FLAGS","RETURNRST","RETURNICMP","RETURNICMP6","PROTO","INET",
+"INET6","ALL","ANY","ICMPTYPE","ICMP6TYPE","CODE","KEEP","MODULATE","STATE",
+"PORT","RDR","NAT","BINAT","ARROW","NODF","MINTTL","ERROR","ALLOWOPTS",
+"FASTROUTE","FILENAME","ROUTETO","DUPTO","REPLYTO","NO","LABEL","NOROUTE",
+"URPFFAILED","FRAGMENT","USER","GROUP","MAXMSS","MAXIMUM","TTL","TOS","DROP",
+"TABLE","REASSEMBLE","FRAGDROP","FRAGCROP","ANCHOR","NATANCHOR","RDRANCHOR",
+"BINATANCHOR","SET","OPTIMIZATION","TIMEOUT","LIMIT","LOGINTERFACE",
+"BLOCKPOLICY","RANDOMID","REQUIREORDER","SYNPROXY","FINGERPRINTS","NOSYNC",
+"DEBUG","SKIP","HOSTID","ANTISPOOF","FOR","INCLUDE","BITMASK","RANDOM",
+"SOURCEHASH","ROUNDROBIN","STATICPORT","PROBABILITY","ALTQ","CBQ","CODEL",
+"PRIQ","HFSC","FAIRQ","BANDWIDTH","TBRSIZE","LINKSHARE","REALTIME","UPPERLIMIT",
+"QUEUE","PRIORITY","QLIMIT","HOGS","BUCKETS","RTABLE","TARGET","INTERVAL",
+"LOAD","RULESET_OPTIMIZATION","PRIO","STICKYADDRESS","MAXSRCSTATES",
+"MAXSRCNODES","SOURCETRACK","GLOBAL","RULE","MAXSRCCONN","MAXSRCCONNRATE",
+"OVERLOAD","FLUSH","SLOPPY","TAGGED","TAG","IFBOUND","FLOATING","STATEPOLICY",
+"STATEDEFAULTS","ROUTE","SETTOS","DIVERTTO","DIVERTREPLY","STRING","NUMBER",
+"PORTBINARY",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"illegal-symbol",
+};
+static const char *const pfctlyrule[] = {
+"$accept : ruleset",
+"ruleset :",
+"ruleset : ruleset include '\\n'",
+"ruleset : ruleset '\\n'",
+"ruleset : ruleset option '\\n'",
+"ruleset : ruleset scrubrule '\\n'",
+"ruleset : ruleset natrule '\\n'",
+"ruleset : ruleset binatrule '\\n'",
+"ruleset : ruleset pfrule '\\n'",
+"ruleset : ruleset anchorrule '\\n'",
+"ruleset : ruleset loadrule '\\n'",
+"ruleset : ruleset altqif '\\n'",
+"ruleset : ruleset queuespec '\\n'",
+"ruleset : ruleset varset '\\n'",
+"ruleset : ruleset antispoof '\\n'",
+"ruleset : ruleset tabledef '\\n'",
+"ruleset : '{' fakeanchor '}' '\\n'",
+"ruleset : ruleset error '\\n'",
+"include : INCLUDE STRING",
+"fakeanchor : fakeanchor '\\n'",
+"fakeanchor : fakeanchor anchorrule '\\n'",
+"fakeanchor : fakeanchor binatrule '\\n'",
+"fakeanchor : fakeanchor natrule '\\n'",
+"fakeanchor : fakeanchor pfrule '\\n'",
+"fakeanchor : fakeanchor error '\\n'",
+"optimizer : string",
+"option : SET OPTIMIZATION STRING",
+"option : SET RULESET_OPTIMIZATION optimizer",
+"option : SET TIMEOUT timeout_spec",
+"option : SET TIMEOUT '{' optnl timeout_list '}'",
+"option : SET LIMIT limit_spec",
+"option : SET LIMIT '{' optnl limit_list '}'",
+"option : SET LOGINTERFACE stringall",
+"option : SET HOSTID number",
+"option : SET BLOCKPOLICY DROP",
+"option : SET BLOCKPOLICY RETURN",
+"option : SET REQUIREORDER yesno",
+"option : SET FINGERPRINTS STRING",
+"option : SET STATEPOLICY statelock",
+"option : SET DEBUG STRING",
+"option : SET SKIP interface",
+"option : SET STATEDEFAULTS state_opt_list",
+"stringall : STRING",
+"stringall : ALL",
+"string : STRING string",
+"string : STRING",
+"varstring : numberstring varstring",
+"varstring : numberstring",
+"numberstring : NUMBER",
+"numberstring : STRING",
+"varset : STRING '=' varstring",
+"anchorname : STRING",
+"anchorname :",
+"pfa_anchorlist :",
+"pfa_anchorlist : pfa_anchorlist '\\n'",
+"pfa_anchorlist : pfa_anchorlist pfrule '\\n'",
+"pfa_anchorlist : pfa_anchorlist anchorrule '\\n'",
+"$$1 :",
+"pfa_anchor : '{' $$1 '\\n' pfa_anchorlist '}'",
+"pfa_anchor :",
+"anchorrule : ANCHOR anchorname dir quick interface af proto fromto filter_opts pfa_anchor",
+"anchorrule : NATANCHOR string interface af proto fromto rtable",
+"anchorrule : RDRANCHOR string interface af proto fromto rtable",
+"anchorrule : BINATANCHOR string interface af proto fromto rtable",
+"loadrule : LOAD ANCHOR string FROM string",
+"scrubaction : no SCRUB",
+"scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts",
+"$$2 :",
+"scrub_opts : $$2 scrub_opts_l",
+"scrub_opts :",
+"scrub_opts_l : scrub_opts_l scrub_opt",
+"scrub_opts_l : scrub_opt",
+"scrub_opt : NODF",
+"scrub_opt : MINTTL NUMBER",
+"scrub_opt : MAXMSS NUMBER",
+"scrub_opt : SETTOS tos",
+"scrub_opt : fragcache",
+"scrub_opt : REASSEMBLE STRING",
+"scrub_opt : RANDOMID",
+"scrub_opt : RTABLE NUMBER",
+"scrub_opt : not TAGGED string",
+"fragcache : FRAGMENT REASSEMBLE",
+"fragcache : FRAGMENT FRAGCROP",
+"fragcache : FRAGMENT FRAGDROP",
+"antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts",
+"antispoof_ifspc : FOR antispoof_if",
+"antispoof_ifspc : FOR '{' optnl antispoof_iflst '}'",
+"antispoof_iflst : antispoof_if optnl",
+"antispoof_iflst : antispoof_iflst comma antispoof_if optnl",
+"antispoof_if : if_item",
+"antispoof_if : '(' if_item ')'",
+"$$3 :",
+"antispoof_opts : $$3 antispoof_opts_l",
+"antispoof_opts :",
+"antispoof_opts_l : antispoof_opts_l antispoof_opt",
+"antispoof_opts_l : antispoof_opt",
+"antispoof_opt : label",
+"antispoof_opt : RTABLE NUMBER",
+"not : '!'",
+"not :",
+"tabledef : TABLE '<' STRING '>' table_opts",
+"$$4 :",
+"table_opts : $$4 table_opts_l",
+"table_opts :",
+"table_opts_l : table_opts_l table_opt",
+"table_opts_l : table_opt",
+"table_opt : STRING",
+"table_opt : '{' optnl '}'",
+"table_opt : '{' optnl host_list '}'",
+"table_opt : FILENAME STRING",
+"altqif : ALTQ interface queue_opts QUEUE qassign",
+"queuespec : QUEUE STRING interface queue_opts qassign",
+"$$5 :",
+"queue_opts : $$5 queue_opts_l",
+"queue_opts :",
+"queue_opts_l : queue_opts_l queue_opt",
+"queue_opts_l : queue_opt",
+"queue_opt : BANDWIDTH bandwidth",
+"queue_opt : PRIORITY NUMBER",
+"queue_opt : QLIMIT NUMBER",
+"queue_opt : scheduler",
+"queue_opt : TBRSIZE NUMBER",
+"bandwidth : STRING",
+"bandwidth : NUMBER",
+"scheduler : CBQ",
+"scheduler : CBQ '(' cbqflags_list ')'",
+"scheduler : PRIQ",
+"scheduler : PRIQ '(' priqflags_list ')'",
+"scheduler : HFSC",
+"scheduler : HFSC '(' hfsc_opts ')'",
+"scheduler : FAIRQ",
+"scheduler : FAIRQ '(' fairq_opts ')'",
+"scheduler : CODEL",
+"scheduler : CODEL '(' codel_opts ')'",
+"cbqflags_list : cbqflags_item",
+"cbqflags_list : cbqflags_list comma cbqflags_item",
+"cbqflags_item : STRING",
+"priqflags_list : priqflags_item",
+"priqflags_list : priqflags_list comma priqflags_item",
+"priqflags_item : STRING",
+"$$6 :",
+"hfsc_opts : $$6 hfscopts_list",
+"hfscopts_list : hfscopts_item",
+"hfscopts_list : hfscopts_list comma hfscopts_item",
+"hfscopts_item : LINKSHARE bandwidth",
+"hfscopts_item : LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : REALTIME bandwidth",
+"hfscopts_item : REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : UPPERLIMIT bandwidth",
+"hfscopts_item : UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'",
+"hfscopts_item : STRING",
+"$$7 :",
+"fairq_opts : $$7 fairqopts_list",
+"fairqopts_list : fairqopts_item",
+"fairqopts_list : fairqopts_list comma fairqopts_item",
+"fairqopts_item : LINKSHARE bandwidth",
+"fairqopts_item : LINKSHARE '(' bandwidth number bandwidth ')'",
+"fairqopts_item : HOGS bandwidth",
+"fairqopts_item : BUCKETS number",
+"fairqopts_item : STRING",
+"$$8 :",
+"codel_opts : $$8 codelopts_list",
+"codelopts_list : codelopts_item",
+"codelopts_list : codelopts_list comma codelopts_item",
+"codelopts_item : INTERVAL number",
+"codelopts_item : TARGET number",
+"codelopts_item : STRING",
+"qassign :",
+"qassign : qassign_item",
+"qassign : '{' optnl qassign_list '}'",
+"qassign_list : qassign_item optnl",
+"qassign_list : qassign_list comma qassign_item optnl",
+"qassign_item : STRING",
+"pfrule : action dir logquick interface route af proto fromto filter_opts",
+"$$9 :",
+"filter_opts : $$9 filter_opts_l",
+"filter_opts :",
+"filter_opts_l : filter_opts_l filter_opt",
+"filter_opts_l : filter_opt",
+"filter_opt : USER uids",
+"filter_opt : GROUP gids",
+"filter_opt : flags",
+"filter_opt : icmpspec",
+"filter_opt : PRIO NUMBER",
+"filter_opt : TOS tos",
+"filter_opt : keep",
+"filter_opt : FRAGMENT",
+"filter_opt : ALLOWOPTS",
+"filter_opt : label",
+"filter_opt : qname",
+"filter_opt : TAG string",
+"filter_opt : not TAGGED string",
+"filter_opt : PROBABILITY probability",
+"filter_opt : RTABLE NUMBER",
+"filter_opt : DIVERTTO portplain",
+"filter_opt : DIVERTTO STRING PORT portplain",
+"filter_opt : DIVERTREPLY",
+"filter_opt : filter_sets",
+"filter_sets : SET '(' filter_sets_l ')'",
+"filter_sets : SET filter_set",
+"filter_sets_l : filter_sets_l comma filter_set",
+"filter_sets_l : filter_set",
+"filter_set : prio",
+"prio : PRIO NUMBER",
+"prio : PRIO '(' NUMBER comma NUMBER ')'",
+"probability : STRING",
+"probability : NUMBER",
+"action : PASS",
+"action : BLOCK blockspec",
+"blockspec :",
+"blockspec : DROP",
+"blockspec : RETURNRST",
+"blockspec : RETURNRST '(' TTL NUMBER ')'",
+"blockspec : RETURNICMP",
+"blockspec : RETURNICMP6",
+"blockspec : RETURNICMP '(' reticmpspec ')'",
+"blockspec : RETURNICMP6 '(' reticmp6spec ')'",
+"blockspec : RETURNICMP '(' reticmpspec comma reticmp6spec ')'",
+"blockspec : RETURN",
+"reticmpspec : STRING",
+"reticmpspec : NUMBER",
+"reticmp6spec : STRING",
+"reticmp6spec : NUMBER",
+"dir :",
+"dir : IN",
+"dir : OUT",
+"quick :",
+"quick : QUICK",
+"logquick :",
+"logquick : log",
+"logquick : QUICK",
+"logquick : log QUICK",
+"logquick : QUICK log",
+"log : LOG",
+"log : LOG '(' logopts ')'",
+"logopts : logopt",
+"logopts : logopts comma logopt",
+"logopt : ALL",
+"logopt : USER",
+"logopt : GROUP",
+"logopt : TO string",
+"interface :",
+"interface : ON if_item_not",
+"interface : ON '{' optnl if_list '}'",
+"if_list : if_item_not optnl",
+"if_list : if_list comma if_item_not optnl",
+"if_item_not : not if_item",
+"if_item : STRING",
+"af :",
+"af : INET",
+"af : INET6",
+"proto :",
+"proto : PROTO proto_item",
+"proto : PROTO '{' optnl proto_list '}'",
+"proto_list : proto_item optnl",
+"proto_list : proto_list comma proto_item optnl",
+"proto_item : protoval",
+"protoval : STRING",
+"protoval : NUMBER",
+"fromto : ALL",
+"fromto : from os to",
+"os :",
+"os : OS xos",
+"os : OS '{' optnl os_list '}'",
+"xos : STRING",
+"os_list : xos optnl",
+"os_list : os_list comma xos optnl",
+"from :",
+"from : FROM ipportspec",
+"to :",
+"to : TO ipportspec",
+"ipportspec : ipspec",
+"ipportspec : ipspec PORT portspec",
+"ipportspec : PORT portspec",
+"optnl : '\\n' optnl",
+"optnl :",
+"ipspec : ANY",
+"ipspec : xhost",
+"ipspec : '{' optnl host_list '}'",
+"toipspec : TO ipspec",
+"toipspec :",
+"host_list : ipspec optnl",
+"host_list : host_list comma ipspec optnl",
+"xhost : not host",
+"xhost : not NOROUTE",
+"xhost : not URPFFAILED",
+"host : STRING",
+"host : STRING '-' STRING",
+"host : STRING '/' NUMBER",
+"host : NUMBER '/' NUMBER",
+"host : dynaddr",
+"host : dynaddr '/' NUMBER",
+"host : '<' STRING '>'",
+"number : NUMBER",
+"number : STRING",
+"dynaddr : '(' STRING ')'",
+"portspec : port_item",
+"portspec : '{' optnl port_list '}'",
+"port_list : port_item optnl",
+"port_list : port_list comma port_item optnl",
+"port_item : portrange",
+"port_item : unaryop portrange",
+"port_item : portrange PORTBINARY portrange",
+"portplain : numberstring",
+"portrange : numberstring",
+"uids : uid_item",
+"uids : '{' optnl uid_list '}'",
+"uid_list : uid_item optnl",
+"uid_list : uid_list comma uid_item optnl",
+"uid_item : uid",
+"uid_item : unaryop uid",
+"uid_item : uid PORTBINARY uid",
+"uid : STRING",
+"uid : NUMBER",
+"gids : gid_item",
+"gids : '{' optnl gid_list '}'",
+"gid_list : gid_item optnl",
+"gid_list : gid_list comma gid_item optnl",
+"gid_item : gid",
+"gid_item : unaryop gid",
+"gid_item : gid PORTBINARY gid",
+"gid : STRING",
+"gid : NUMBER",
+"flag : STRING",
+"flags : FLAGS flag '/' flag",
+"flags : FLAGS '/' flag",
+"flags : FLAGS ANY",
+"icmpspec : ICMPTYPE icmp_item",
+"icmpspec : ICMPTYPE '{' optnl icmp_list '}'",
+"icmpspec : ICMP6TYPE icmp6_item",
+"icmpspec : ICMP6TYPE '{' optnl icmp6_list '}'",
+"icmp_list : icmp_item optnl",
+"icmp_list : icmp_list comma icmp_item optnl",
+"icmp6_list : icmp6_item optnl",
+"icmp6_list : icmp6_list comma icmp6_item optnl",
+"icmp_item : icmptype",
+"icmp_item : icmptype CODE STRING",
+"icmp_item : icmptype CODE NUMBER",
+"icmp6_item : icmp6type",
+"icmp6_item : icmp6type CODE STRING",
+"icmp6_item : icmp6type CODE NUMBER",
+"icmptype : STRING",
+"icmptype : NUMBER",
+"icmp6type : STRING",
+"icmp6type : NUMBER",
+"tos : STRING",
+"tos : NUMBER",
+"sourcetrack : SOURCETRACK",
+"sourcetrack : SOURCETRACK GLOBAL",
+"sourcetrack : SOURCETRACK RULE",
+"statelock : IFBOUND",
+"statelock : FLOATING",
+"keep : NO STATE",
+"keep : KEEP STATE state_opt_spec",
+"keep : MODULATE STATE state_opt_spec",
+"keep : SYNPROXY STATE state_opt_spec",
+"flush :",
+"flush : FLUSH",
+"flush : FLUSH GLOBAL",
+"state_opt_spec : '(' state_opt_list ')'",
+"state_opt_spec :",
+"state_opt_list : state_opt_item",
+"state_opt_list : state_opt_list comma state_opt_item",
+"state_opt_item : MAXIMUM NUMBER",
+"state_opt_item : NOSYNC",
+"state_opt_item : MAXSRCSTATES NUMBER",
+"state_opt_item : MAXSRCCONN NUMBER",
+"state_opt_item : MAXSRCCONNRATE NUMBER '/' NUMBER",
+"state_opt_item : OVERLOAD '<' STRING '>' flush",
+"state_opt_item : MAXSRCNODES NUMBER",
+"state_opt_item : sourcetrack",
+"state_opt_item : statelock",
+"state_opt_item : SLOPPY",
+"state_opt_item : STRING NUMBER",
+"label : LABEL STRING",
+"qname : QUEUE STRING",
+"qname : QUEUE '(' STRING ')'",
+"qname : QUEUE '(' STRING comma STRING ')'",
+"no :",
+"no : NO",
+"portstar : numberstring",
+"redirspec : host",
+"redirspec : '{' optnl redir_host_list '}'",
+"redir_host_list : host optnl",
+"redir_host_list : redir_host_list comma host optnl",
+"redirpool :",
+"redirpool : ARROW redirspec",
+"redirpool : ARROW redirspec PORT portstar",
+"hashkey :",
+"hashkey : string",
+"$$10 :",
+"pool_opts : $$10 pool_opts_l",
+"pool_opts :",
+"pool_opts_l : pool_opts_l pool_opt",
+"pool_opts_l : pool_opt",
+"pool_opt : BITMASK",
+"pool_opt : RANDOM",
+"pool_opt : SOURCEHASH hashkey",
+"pool_opt : ROUNDROBIN",
+"pool_opt : STATICPORT",
+"pool_opt : STICKYADDRESS",
+"redirection :",
+"redirection : ARROW host",
+"redirection : ARROW host PORT portstar",
+"natpasslog :",
+"natpasslog : PASS",
+"natpasslog : PASS log",
+"natpasslog : log",
+"nataction : no NAT natpasslog",
+"nataction : no RDR natpasslog",
+"natrule : nataction interface af proto fromto tag tagged rtable redirpool pool_opts",
+"binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection",
+"tag :",
+"tag : TAG STRING",
+"tagged :",
+"tagged : not TAGGED string",
+"rtable :",
+"rtable : RTABLE NUMBER",
+"route_host : STRING",
+"route_host : '(' STRING host ')'",
+"route_host_list : route_host optnl",
+"route_host_list : route_host_list comma route_host optnl",
+"routespec : route_host",
+"routespec : '{' optnl route_host_list '}'",
+"route :",
+"route : FASTROUTE",
+"route : ROUTETO routespec pool_opts",
+"route : REPLYTO routespec pool_opts",
+"route : DUPTO routespec pool_opts",
+"timeout_spec : STRING NUMBER",
+"timeout_spec : INTERVAL NUMBER",
+"timeout_list : timeout_list comma timeout_spec optnl",
+"timeout_list : timeout_spec optnl",
+"limit_spec : STRING NUMBER",
+"limit_list : limit_list comma limit_spec optnl",
+"limit_list : limit_spec optnl",
+"comma : ','",
+"comma :",
+"yesno : NO",
+"yesno : STRING",
+"unaryop : '='",
+"unaryop : '!' '='",
+"unaryop : '<' '='",
+"unaryop : '<'",
+"unaryop : '>' '='",
+"unaryop : '>'",
+
+};
+#endif
+
+int yydebug;
+int yynerrs;
+
+int yyerrflag;
+int yychar;
+YYSTYPE yyval;
+YYSTYPE yylval;
+
+/* define the initial stack-sizes */
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH 10000
+#endif
+#endif
+
+#define YYINITSTACKSIZE 200
+
+typedef struct {
+ unsigned stacksize;
+ YYINT *s_base;
+ YYINT *s_mark;
+ YYINT *s_last;
+ YYSTYPE *l_base;
+ YYSTYPE *l_mark;
+} YYSTACKDATA;
+/* variables for the parser stack */
+static YYSTACKDATA yystack;
+#line 4545 "../../freebsd/sbin/pfctl/parse.y"
+#ifdef __rtems__
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack);
+#endif /* __rtems__ */
+
+int
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ file->errors++;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ return (0);
+}
+
+int
+disallow_table(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_TABLE) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_urpf_failed(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_URPFFAILED) {
+ yyerror(fmt);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+rule_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ switch (r->action) {
+ case PF_PASS:
+ case PF_DROP:
+ case PF_SCRUB:
+ case PF_NOSCRUB:
+ problems = filter_consistent(r, anchor_call);
+ break;
+ case PF_NAT:
+ case PF_NONAT:
+ problems = nat_consistent(r);
+ break;
+ case PF_RDR:
+ case PF_NORDR:
+ problems = rdr_consistent(r);
+ break;
+ case PF_BINAT:
+ case PF_NOBINAT:
+ default:
+ break;
+ }
+ return (problems);
+}
+
+int
+filter_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
+ (r->src.port_op || r->dst.port_op)) {
+ yyerror("port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
+ (r->type || r->code)) {
+ yyerror("icmp-type/code only applies to icmp");
+ problems++;
+ }
+ if (!r->af && (r->type || r->code)) {
+ yyerror("must indicate address family with icmp-type/code");
+ problems++;
+ }
+ if (r->overload_tblname[0] &&
+ r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
+ yyerror("'overload' requires 'max-src-conn' "
+ "or 'max-src-conn-rate'");
+ problems++;
+ }
+ if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
+ (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
+ yyerror("proto %s doesn't match address family %s",
+ r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
+ r->af == AF_INET ? "inet" : "inet6");
+ problems++;
+ }
+ if (r->allow_opts && r->action != PF_PASS) {
+ yyerror("allow-opts can only be specified for pass rules");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
+ r->dst.port_op || r->flagset || r->type || r->code)) {
+ yyerror("fragments can be filtered only on IP header fields");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
+ yyerror("return-rst can only be applied to TCP rules");
+ problems++;
+ }
+ if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
+ yyerror("max-src-nodes requires 'source-track rule'");
+ problems++;
+ }
+ if (r->action == PF_DROP && r->keep_state) {
+ yyerror("keep state on block rules doesn't make sense");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY &&
+ (r->keep_state == PF_STATE_MODULATE ||
+ r->keep_state == PF_STATE_SYNPROXY)) {
+ yyerror("sloppy state matching cannot be used with "
+ "synproxy state or modulate state");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+nat_consistent(struct pf_rule *r)
+{
+ return (0); /* yeah! */
+}
+
+int
+rdr_consistent(struct pf_rule *r)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
+ if (r->src.port_op) {
+ yyerror("src port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->dst.port_op) {
+ yyerror("dst port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->rpool.proxy_port[0]) {
+ yyerror("rpool port only applies to tcp/udp");
+ problems++;
+ }
+ }
+ if (r->dst.port_op &&
+ r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
+ yyerror("invalid port operator for rdr destination port");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+process_tabledef(char *name, struct table_opts *opts)
+{
+ struct pfr_buffer ab;
+ struct node_tinit *ti;
+
+ bzero(&ab, sizeof(ab));
+ ab.pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
+ if (ti->file)
+ if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
+ if (errno)
+ yyerror("cannot load \"%s\": %s",
+ ti->file, strerror(errno));
+ else
+ yyerror("file \"%s\" contains bad data",
+ ti->file);
+ goto _error;
+ }
+ if (ti->host)
+ if (append_addr_host(&ab, ti->host, 0, 0)) {
+ yyerror("cannot create address buffer: %s",
+ strerror(errno));
+ goto _error;
+ }
+ }
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(name, opts->flags, opts->init_addr,
+ &opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) &&
+ pfctl_define_table(name, opts->flags, opts->init_addr,
+ pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
+ yyerror("cannot define table %s: %s", name,
+ pfr_strerror(errno));
+ goto _error;
+ }
+ pf->tdirty = 1;
+ pfr_buf_clear(&ab);
+ return (0);
+_error:
+ pfr_buf_clear(&ab);
+ return (-1);
+}
+
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+/* macro gore, but you should've seen the prior indentation nightmare... */
+
+#define FREE_LIST(T,r) \
+ do { \
+ T *p, *node = r; \
+ while (node != NULL) { \
+ p = node; \
+ node = node->next; \
+ free(p); \
+ } \
+ } while (0)
+
+#define LOOP_THROUGH(T,n,r,C) \
+ do { \
+ T *n; \
+ if (r == NULL) { \
+ r = calloc(1, sizeof(T)); \
+ if (r == NULL) \
+ err(1, "LOOP: calloc"); \
+ r->next = NULL; \
+ } \
+ n = r; \
+ while (n != NULL) { \
+ do { \
+ C; \
+ } while (0); \
+ n = n->next; \
+ } \
+ } while (0)
+
+void
+expand_label_str(char *label, size_t len, const char *srch, const char *repl)
+{
+ char *tmp;
+ char *p, *q;
+
+ if ((tmp = calloc(1, len)) == NULL)
+ err(1, "expand_label_str: calloc");
+ p = q = label;
+ while ((q = strstr(p, srch)) != NULL) {
+ *q = '\0';
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len))
+ errx(1, "expand_label: label too long");
+ q += strlen(srch);
+ p = q;
+ }
+ if (strlcat(tmp, p, len) >= len)
+ errx(1, "expand_label: label too long");
+ strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
+}
+
+void
+expand_label_if(const char *name, char *label, size_t len, const char *ifname)
+{
+ if (strstr(label, name) != NULL) {
+ if (!*ifname)
+ expand_label_str(label, len, name, "any");
+ else
+ expand_label_str(label, len, name, ifname);
+ }
+}
+
+void
+expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
+ struct node_host *h)
+{
+ char tmp[64], tmp_not[66];
+
+ if (strstr(label, name) != NULL) {
+ switch (h->addr.type) {
+ case PF_ADDR_DYNIFTL:
+ snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
+ break;
+ case PF_ADDR_TABLE:
+ snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
+ break;
+ case PF_ADDR_NOROUTE:
+ snprintf(tmp, sizeof(tmp), "no-route");
+ break;
+ case PF_ADDR_URPFFAILED:
+ snprintf(tmp, sizeof(tmp), "urpf-failed");
+ break;
+ case PF_ADDR_ADDRMASK:
+ if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
+ PF_AZERO(&h->addr.v.a.mask, af)))
+ snprintf(tmp, sizeof(tmp), "any");
+ else {
+ char a[48];
+ int bits;
+
+ if (inet_ntop(af, &h->addr.v.a.addr, a,
+ sizeof(a)) == NULL)
+ snprintf(tmp, sizeof(tmp), "?");
+ else {
+ bits = unmask(&h->addr.v.a.mask, af);
+ if ((af == AF_INET && bits < 32) ||
+ (af == AF_INET6 && bits < 128))
+ snprintf(tmp, sizeof(tmp),
+ "%s/%d", a, bits);
+ else
+ snprintf(tmp, sizeof(tmp),
+ "%s", a);
+ }
+ }
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "?");
+ break;
+ }
+
+ if (h->not) {
+ snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
+ expand_label_str(label, len, name, tmp_not);
+ } else
+ expand_label_str(label, len, name, tmp);
+ }
+}
+
+void
+expand_label_port(const char *name, char *label, size_t len,
+ struct node_port *port)
+{
+ char a1[6], a2[6], op[13] = "";
+
+ if (strstr(label, name) != NULL) {
+ snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
+ snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
+ if (!port->op)
+ ;
+ else if (port->op == PF_OP_IRG)
+ snprintf(op, sizeof(op), "%s><%s", a1, a2);
+ else if (port->op == PF_OP_XRG)
+ snprintf(op, sizeof(op), "%s<>%s", a1, a2);
+ else if (port->op == PF_OP_EQ)
+ snprintf(op, sizeof(op), "%s", a1);
+ else if (port->op == PF_OP_NE)
+ snprintf(op, sizeof(op), "!=%s", a1);
+ else if (port->op == PF_OP_LT)
+ snprintf(op, sizeof(op), "<%s", a1);
+ else if (port->op == PF_OP_LE)
+ snprintf(op, sizeof(op), "<=%s", a1);
+ else if (port->op == PF_OP_GT)
+ snprintf(op, sizeof(op), ">%s", a1);
+ else if (port->op == PF_OP_GE)
+ snprintf(op, sizeof(op), ">=%s", a1);
+ expand_label_str(label, len, name, op);
+ }
+}
+
+void
+expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
+{
+ struct protoent *pe;
+ char n[4];
+
+ if (strstr(label, name) != NULL) {
+ pe = getprotobynumber(proto);
+ if (pe != NULL)
+ expand_label_str(label, len, name, pe->p_name);
+ else {
+ snprintf(n, sizeof(n), "%u", proto);
+ expand_label_str(label, len, name, n);
+ }
+ }
+}
+
+void
+expand_label_nr(const char *name, char *label, size_t len)
+{
+ char n[11];
+
+ if (strstr(label, name) != NULL) {
+ snprintf(n, sizeof(n), "%u", pf->anchor->match);
+ expand_label_str(label, len, name, n);
+ }
+}
+
+void
+expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
+ struct node_host *src_host, struct node_port *src_port,
+ struct node_host *dst_host, struct node_port *dst_port,
+ u_int8_t proto)
+{
+ expand_label_if("$if", label, len, ifname);
+ expand_label_addr("$srcaddr", label, len, af, src_host);
+ expand_label_addr("$dstaddr", label, len, af, dst_host);
+ expand_label_port("$srcport", label, len, src_port);
+ expand_label_port("$dstport", label, len, dst_port);
+ expand_label_proto("$proto", label, len, proto);
+ expand_label_nr("$nr", label, len);
+}
+
+int
+expand_altq(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct pf_altq pa, pb;
+ char qname[PF_QNAME_SIZE];
+ struct node_queue *n;
+ struct node_queue_bw bw;
+ int errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ memcpy(&pa, a, sizeof(struct pf_altq));
+ if (strlcpy(pa.ifname, interface->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_altq: strlcpy");
+
+ if (interface->not) {
+ yyerror("altq on ! <interface> is not supported");
+ errs++;
+ } else {
+ if (eval_pfaltq(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ print_altq(&pf->paltq->altq, 0,
+ &bwspec, opts);
+ if (nqueues && nqueues->tail) {
+ printf("queue { ");
+ LOOP_THROUGH(struct node_queue, queue,
+ nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC) {
+ /* now create a root queue */
+ memset(&pb, 0, sizeof(struct pf_altq));
+ if (strlcpy(qname, "root_", sizeof(qname)) >=
+ sizeof(qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcat(qname, interface->ifname,
+ sizeof(qname)) >= sizeof(qname))
+ errx(1, "expand_altq: strlcat");
+ if (strlcpy(pb.qname, qname,
+ sizeof(pb.qname)) >= sizeof(pb.qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(pb.ifname, interface->ifname,
+ sizeof(pb.ifname)) >= sizeof(pb.ifname))
+ errx(1, "expand_altq: strlcpy");
+ pb.qlimit = pa.qlimit;
+ pb.scheduler = pa.scheduler;
+ bw.bw_absolute = pa.ifbandwidth;
+ bw.bw_percent = 0;
+ if (eval_pfqueue(pf, &pb, &bw, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pb))
+ errs++;
+ }
+
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = calloc(1, sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_altq: calloc");
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC)
+ if (strlcpy(n->parent, qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->queue, queue->queue,
+ sizeof(n->queue)) >= sizeof(n->queue))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->ifname, interface->ifname,
+ sizeof(n->ifname)) >= sizeof(n->ifname))
+ errx(1, "expand_altq: strlcpy");
+ n->scheduler = pa.scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ );
+ }
+ );
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+
+ return (errs);
+}
+
+int
+expand_queue(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct node_queue *n, *nq;
+ struct pf_altq pa;
+ u_int8_t found = 0;
+ u_int8_t errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ if (queues == NULL) {
+ yyerror("queue %s has no parent", a->qname);
+ FREE_LIST(struct node_queue, nqueues);
+ return (1);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_queue, tqueue, queues,
+ if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
+ (interface->ifname[0] == 0 ||
+ (!interface->not && !strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)) ||
+ (interface->not && strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)))) {
+ /* found ourself in queues */
+ found++;
+
+ memcpy(&pa, a, sizeof(struct pf_altq));
+
+ if (pa.scheduler != ALTQT_NONE &&
+ pa.scheduler != tqueue->scheduler) {
+ yyerror("exactly one scheduler type "
+ "per interface allowed");
+ return (1);
+ }
+ pa.scheduler = tqueue->scheduler;
+
+ /* scheduler dependent error checking */
+ switch (pa.scheduler) {
+ case ALTQT_PRIQ:
+ if (nqueues != NULL) {
+ yyerror("priq queues cannot "
+ "have child queues");
+ return (1);
+ }
+ if (bwspec.bw_absolute > 0 ||
+ bwspec.bw_percent < 100) {
+ yyerror("priq doesn't take "
+ "bandwidth");
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (strlcpy(pa.ifname, tqueue->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_queue: strlcpy");
+ if (strlcpy(pa.parent, tqueue->parent,
+ sizeof(pa.parent)) >= sizeof(pa.parent))
+ errx(1, "expand_queue: strlcpy");
+
+ if (eval_pfqueue(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ for (nq = nqueues; nq != NULL; nq = nq->next) {
+ if (!strcmp(a->qname, nq->queue)) {
+ yyerror("queue cannot have "
+ "itself as child");
+ errs++;
+ continue;
+ }
+ n = calloc(1,
+ sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_queue: calloc");
+ if (strlcpy(n->parent, a->qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->queue, nq->queue,
+ sizeof(n->queue)) >=
+ sizeof(n->queue))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->ifname, tqueue->ifname,
+ sizeof(n->ifname)) >=
+ sizeof(n->ifname))
+ errx(1, "expand_queue strlcpy");
+ n->scheduler = tqueue->scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ }
+ if ((pf->opts & PF_OPT_VERBOSE) && (
+ (found == 1 && interface->ifname[0] == 0) ||
+ (found > 0 && interface->ifname[0] != 0))) {
+ print_queue(&pf->paltq->altq, 0,
+ &bwspec, interface->ifname[0] != 0,
+ opts);
+ if (nqueues && nqueues->tail) {
+ printf("{ ");
+ LOOP_THROUGH(struct node_queue,
+ queue, nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+ }
+ );
+ );
+
+ FREE_LIST(struct node_queue, nqueues);
+ FREE_LIST(struct node_if, interfaces);
+
+ if (!found) {
+ yyerror("queue %s has no parent", a->qname);
+ errs++;
+ }
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+void
+expand_rule(struct pf_rule *r,
+ struct node_if *interfaces, struct node_host *rpool_hosts,
+ struct node_proto *protos, struct node_os *src_oses,
+ struct node_host *src_hosts, struct node_port *src_ports,
+ struct node_host *dst_hosts, struct node_port *dst_ports,
+ struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
+ const char *anchor_call)
+{
+ sa_family_t af = r->af;
+ int added = 0, error = 0;
+ char ifname[IF_NAMESIZE];
+ char label[PF_RULE_LABEL_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
+ struct pf_pooladdr *pa;
+ struct node_host *h;
+ u_int8_t flags, flagset, keep_state;
+
+ if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
+ sizeof(match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ flags = r->flags;
+ flagset = r->flagset;
+ keep_state = r->keep_state;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_proto, proto, protos,
+ LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
+ LOOP_THROUGH(struct node_host, src_host, src_hosts,
+ LOOP_THROUGH(struct node_port, src_port, src_ports,
+ LOOP_THROUGH(struct node_os, src_os, src_oses,
+ LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
+ LOOP_THROUGH(struct node_port, dst_port, dst_ports,
+ LOOP_THROUGH(struct node_uid, uid, uids,
+ LOOP_THROUGH(struct node_gid, gid, gids,
+
+ r->af = af;
+ /* for link-local IPv6 address, interface must match up */
+ if ((r->af && src_host->af && r->af != src_host->af) ||
+ (r->af && dst_host->af && r->af != dst_host->af) ||
+ (src_host->af && dst_host->af &&
+ src_host->af != dst_host->af) ||
+ (src_host->ifindex && dst_host->ifindex &&
+ src_host->ifindex != dst_host->ifindex) ||
+ (src_host->ifindex && *interface->ifname &&
+ src_host->ifindex != if_nametoindex(interface->ifname)) ||
+ (dst_host->ifindex && *interface->ifname &&
+ dst_host->ifindex != if_nametoindex(interface->ifname)))
+ continue;
+ if (!r->af && src_host->af)
+ r->af = src_host->af;
+ else if (!r->af && dst_host->af)
+ r->af = dst_host->af;
+
+ if (*interface->ifname)
+ strlcpy(r->ifname, interface->ifname,
+ sizeof(r->ifname));
+ else if (if_indextoname(src_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else if (if_indextoname(dst_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else
+ memset(r->ifname, '\0', sizeof(r->ifname));
+
+ if (strlcpy(r->label, label, sizeof(r->label)) >=
+ sizeof(r->label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
+ sizeof(r->tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->match_tagname, match_tagname,
+ sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
+ r->af, src_host, src_port, dst_host, dst_port,
+ proto->proto);
+
+ error += check_netmask(src_host, r->af);
+ error += check_netmask(dst_host, r->af);
+
+ r->ifnot = interface->not;
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.neg = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.neg = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ r->uid.op = uid->op;
+ r->uid.uid[0] = uid->uid[0];
+ r->uid.uid[1] = uid->uid[1];
+ r->gid.op = gid->op;
+ r->gid.gid[0] = gid->gid[0];
+ r->gid.gid[1] = gid->gid[1];
+ r->type = icmp_type->type;
+ r->code = icmp_type->code;
+
+ if ((keep_state == PF_STATE_MODULATE ||
+ keep_state == PF_STATE_SYNPROXY) &&
+ r->proto && r->proto != IPPROTO_TCP)
+ r->keep_state = PF_STATE_NORMAL;
+ else
+ r->keep_state = keep_state;
+
+ if (r->proto && r->proto != IPPROTO_TCP) {
+ r->flags = 0;
+ r->flagset = 0;
+ } else {
+ r->flags = flags;
+ r->flagset = flagset;
+ }
+ if (icmp_type->proto && r->proto != icmp_type->proto) {
+ yyerror("icmp-type mismatch");
+ error++;
+ }
+
+ if (src_os && src_os->os) {
+ r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
+ if ((pf->opts & PF_OPT_VERBOSE2) &&
+ r->os_fingerprint == PF_OSFP_NOMATCH)
+ fprintf(stderr,
+ "warning: unknown '%s' OS fingerprint\n",
+ src_os->os);
+ } else {
+ r->os_fingerprint = PF_OSFP_ANY;
+ }
+
+ TAILQ_INIT(&r->rpool.list);
+ for (h = rpool_hosts; h != NULL; h = h->next) {
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "expand_rule: calloc");
+ pa->addr = h->addr;
+ if (h->ifname != NULL) {
+ if (strlcpy(pa->ifname, h->ifname,
+ sizeof(pa->ifname)) >=
+ sizeof(pa->ifname))
+ errx(1, "expand_rule: strlcpy");
+ } else
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
+ }
+
+ if (rule_consistent(r, anchor_call[0]) < 0 || error)
+ yyerror("skipping rule due to errors");
+ else {
+ r->nr = pf->astack[pf->asd]->match++;
+ pfctl_add_rule(pf, r, anchor_call);
+ added++;
+ }
+
+ ))))))))));
+
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_os, src_oses);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, uids);
+ FREE_LIST(struct node_gid, gids);
+ FREE_LIST(struct node_icmp, icmp_types);
+ FREE_LIST(struct node_host, rpool_hosts);
+
+ if (!added)
+ yyerror("rule expands to no valid combination");
+}
+
+int
+expand_skip_interface(struct node_if *interfaces)
+{
+ int errs = 0;
+
+ if (!interfaces || (!interfaces->next && !interfaces->not &&
+ !strcmp(interfaces->ifname, "none"))) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on none\n");
+ errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
+ return (errs);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on {");
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" %s", interface->ifname);
+ if (interface->not) {
+ yyerror("skip on ! <interface> is not supported");
+ errs++;
+ } else
+ errs += pfctl_set_interface_flags(pf,
+ interface->ifname, PFI_IFLAG_SKIP, 1);
+ );
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" }\n");
+
+ FREE_LIST(struct node_if, interfaces);
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+#undef FREE_LIST
+#undef LOOP_THROUGH
+
+int
+check_rulestate(int desired_state)
+{
+ if (require_order && (rulestate > desired_state)) {
+ yyerror("Rules must be in order: options, normalization, "
+ "queueing, translation, filtering");
+ return (1);
+ }
+ rulestate = desired_state;
+ return (0);
+}
+
+int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcmp(k, ((const struct keywords *)e)->k_name));
+}
+
+int
+lookup(char *s)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "all", ALL},
+ { "allow-opts", ALLOWOPTS},
+ { "altq", ALTQ},
+ { "anchor", ANCHOR},
+ { "antispoof", ANTISPOOF},
+ { "any", ANY},
+ { "bandwidth", BANDWIDTH},
+ { "binat", BINAT},
+ { "binat-anchor", BINATANCHOR},
+ { "bitmask", BITMASK},
+ { "block", BLOCK},
+ { "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
+ { "cbq", CBQ},
+ { "code", CODE},
+ { "codelq", CODEL},
+ { "crop", FRAGCROP},
+ { "debug", DEBUG},
+ { "divert-reply", DIVERTREPLY},
+ { "divert-to", DIVERTTO},
+ { "drop", DROP},
+ { "drop-ovl", FRAGDROP},
+ { "dup-to", DUPTO},
+ { "fairq", FAIRQ},
+ { "fastroute", FASTROUTE},
+ { "file", FILENAME},
+ { "fingerprints", FINGERPRINTS},
+ { "flags", FLAGS},
+ { "floating", FLOATING},
+ { "flush", FLUSH},
+ { "for", FOR},
+ { "fragment", FRAGMENT},
+ { "from", FROM},
+ { "global", GLOBAL},
+ { "group", GROUP},
+ { "hfsc", HFSC},
+ { "hogs", HOGS},
+ { "hostid", HOSTID},
+ { "icmp-type", ICMPTYPE},
+ { "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
+ { "in", IN},
+ { "include", INCLUDE},
+ { "inet", INET},
+ { "inet6", INET6},
+ { "interval", INTERVAL},
+ { "keep", KEEP},
+ { "label", LABEL},
+ { "limit", LIMIT},
+ { "linkshare", LINKSHARE},
+ { "load", LOAD},
+ { "log", LOG},
+ { "loginterface", LOGINTERFACE},
+ { "max", MAXIMUM},
+ { "max-mss", MAXMSS},
+ { "max-src-conn", MAXSRCCONN},
+ { "max-src-conn-rate", MAXSRCCONNRATE},
+ { "max-src-nodes", MAXSRCNODES},
+ { "max-src-states", MAXSRCSTATES},
+ { "min-ttl", MINTTL},
+ { "modulate", MODULATE},
+ { "nat", NAT},
+ { "nat-anchor", NATANCHOR},
+ { "no", NO},
+ { "no-df", NODF},
+ { "no-route", NOROUTE},
+ { "no-sync", NOSYNC},
+ { "on", ON},
+ { "optimization", OPTIMIZATION},
+ { "os", OS},
+ { "out", OUT},
+ { "overload", OVERLOAD},
+ { "pass", PASS},
+ { "port", PORT},
+ { "prio", PRIO},
+ { "priority", PRIORITY},
+ { "priq", PRIQ},
+ { "probability", PROBABILITY},
+ { "proto", PROTO},
+ { "qlimit", QLIMIT},
+ { "queue", QUEUE},
+ { "quick", QUICK},
+ { "random", RANDOM},
+ { "random-id", RANDOMID},
+ { "rdr", RDR},
+ { "rdr-anchor", RDRANCHOR},
+ { "realtime", REALTIME},
+ { "reassemble", REASSEMBLE},
+ { "reply-to", REPLYTO},
+ { "require-order", REQUIREORDER},
+ { "return", RETURN},
+ { "return-icmp", RETURNICMP},
+ { "return-icmp6", RETURNICMP6},
+ { "return-rst", RETURNRST},
+ { "round-robin", ROUNDROBIN},
+ { "route", ROUTE},
+ { "route-to", ROUTETO},
+ { "rtable", RTABLE},
+ { "rule", RULE},
+ { "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "scrub", SCRUB},
+ { "set", SET},
+ { "set-tos", SETTOS},
+ { "skip", SKIP},
+ { "sloppy", SLOPPY},
+ { "source-hash", SOURCEHASH},
+ { "source-track", SOURCETRACK},
+ { "state", STATE},
+ { "state-defaults", STATEDEFAULTS},
+ { "state-policy", STATEPOLICY},
+ { "static-port", STATICPORT},
+ { "sticky-address", STICKYADDRESS},
+ { "synproxy", SYNPROXY},
+ { "table", TABLE},
+ { "tag", TAG},
+ { "tagged", TAGGED},
+ { "target", TARGET},
+ { "tbrsize", TBRSIZE},
+ { "timeout", TIMEOUT},
+ { "to", TO},
+ { "tos", TOS},
+ { "ttl", TTL},
+ { "upperlimit", UPPERLIMIT},
+ { "urpf-failed", URPFFAILED},
+ { "user", USER},
+ };
+ const struct keywords *p;
+
+ p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p) {
+ if (debug > 1)
+ fprintf(stderr, "%s: %d\n", s, p->k_val);
+ return (p->k_val);
+ } else {
+ if (debug > 1)
+ fprintf(stderr, "string: %s\n", s);
+ return (STRING);
+ }
+}
+
+#define MAXPUSHBACK 128
+
+static char *parsebuf;
+static int parseindex;
+static char pushback_buffer[MAXPUSHBACK];
+static int pushback_index = 0;
+
+int
+lgetc(int quotec)
+{
+ int c, next;
+
+ if (parsebuf) {
+ /* Read character from the parsebuffer instead of input. */
+ if (parseindex >= 0) {
+ c = parsebuf[parseindex++];
+ if (c != '\0')
+ return (c);
+ parsebuf = NULL;
+ } else
+ parseindex++;
+ }
+
+ if (pushback_index)
+ return (pushback_buffer[--pushback_index]);
+
+ if (quotec) {
+ if ((c = getc(file->stream)) == EOF) {
+ yyerror("reached end of file while parsing quoted string");
+ if (popfile() == EOF)
+ return (EOF);
+ return (quotec);
+ }
+ return (c);
+ }
+
+ while ((c = getc(file->stream)) == '\\') {
+ next = getc(file->stream);
+ if (next != '\n') {
+ c = next;
+ break;
+ }
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+
+ while (c == EOF) {
+ if (popfile() == EOF)
+ return (EOF);
+ c = getc(file->stream);
+ }
+ return (c);
+}
+
+int
+lungetc(int c)
+{
+ if (c == EOF)
+ return (EOF);
+ if (parsebuf) {
+ parseindex--;
+ if (parseindex >= 0)
+ return (c);
+ }
+ if (pushback_index < MAXPUSHBACK-1)
+ return (pushback_buffer[pushback_index++] = c);
+ else
+ return (EOF);
+}
+
+int
+findeol(void)
+{
+ int c;
+
+ parsebuf = NULL;
+
+ /* skip to either EOF or the first real EOL */
+ while (1) {
+ if (pushback_index)
+ c = pushback_buffer[--pushback_index];
+ else
+ c = lgetc(0);
+ if (c == '\n') {
+ file->lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ return (ERROR);
+}
+
+int
+yylex(void)
+{
+ char buf[8096];
+ char *p, *val;
+ int quotec, next, c;
+ int token;
+
+top:
+ p = buf;
+ while ((c = lgetc(0)) == ' ' || c == '\t')
+ ; /* nothing */
+
+ yylval.lineno = file->lineno;
+ if (c == '#')
+ while ((c = lgetc(0)) != '\n' && c != EOF)
+ ; /* nothing */
+ if (c == '$' && parsebuf == NULL) {
+ while (1) {
+ if ((c = lgetc(0)) == EOF)
+ return (0);
+
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ if (isalnum(c) || c == '_') {
+ *p++ = (char)c;
+ continue;
+ }
+ *p = '\0';
+ lungetc(c);
+ break;
+ }
+ val = symget(buf);
+ if (val == NULL) {
+ yyerror("macro '%s' not defined", buf);
+ return (findeol());
+ }
+ parsebuf = val;
+ parseindex = 0;
+ goto top;
+ }
+
+ switch (c) {
+ case '\'':
+ case '"':
+ quotec = c;
+ while (1) {
+ if ((c = lgetc(quotec)) == EOF)
+ return (0);
+ if (c == '\n') {
+ file->lineno++;
+ continue;
+ } else if (c == '\\') {
+ if ((next = lgetc(quotec)) == EOF)
+ return (0);
+ if (next == quotec || c == ' ' || c == '\t')
+ c = next;
+ else if (next == '\n')
+ continue;
+ else
+ lungetc(next);
+ } else if (c == quotec) {
+ *p = '\0';
+ break;
+ }
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ *p++ = (char)c;
+ }
+ yylval.v.string = strdup(buf);
+ if (yylval.v.string == NULL)
+ err(1, "yylex: strdup");
+ return (STRING);
+ case '<':
+ next = lgetc(0);
+ if (next == '>') {
+ yylval.v.i = PF_OP_XRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '>':
+ next = lgetc(0);
+ if (next == '<') {
+ yylval.v.i = PF_OP_IRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '-':
+ next = lgetc(0);
+ if (next == '>')
+ return (ARROW);
+ lungetc(next);
+ break;
+ }
+
+#define allowed_to_end_number(x) \
+ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
+
+ if (c == '-' || isdigit(c)) {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && isdigit(c));
+ lungetc(c);
+ if (p == buf + 1 && buf[0] == '-')
+ goto nodigits;
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+
+ *p = '\0';
+ yylval.v.number = strtonum(buf, LLONG_MIN,
+ LLONG_MAX, &errstr);
+ if (errstr) {
+ yyerror("\"%s\" invalid number: %s",
+ buf, errstr);
+ return (findeol());
+ }
+ return (NUMBER);
+ } else {
+nodigits:
+ while (p > buf + 1)
+ lungetc(*--p);
+ c = *--p;
+ if (c == '-')
+ return (c);
+ }
+ }
+
+#define allowed_in_string(x) \
+ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
+ x != '{' && x != '}' && x != '<' && x != '>' && \
+ x != '!' && x != '=' && x != '/' && x != '#' && \
+ x != ','))
+
+ if (isalnum(c) || c == ':' || c == '_') {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
+ lungetc(c);
+ *p = '\0';
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
+ return (token);
+ }
+ if (c == '\n') {
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+ if (c == EOF)
+ return (0);
+ return (c);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ warn("cannot stat %s", fname);
+ return (-1);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+ if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+ warnx("%s: group/world readable/writeable", fname);
+ return (-1);
+ }
+ return (0);
+}
+
+struct file *
+pushfile(const char *name, int secret)
+{
+ struct file *nfile;
+
+ if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
+ (nfile->name = strdup(name)) == NULL) {
+ warn("malloc");
+ return (NULL);
+ }
+ if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
+ nfile->stream = stdin;
+ free(nfile->name);
+ if ((nfile->name = strdup("stdin")) == NULL) {
+ warn("strdup");
+ free(nfile);
+ return (NULL);
+ }
+ } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
+ warn("%s", nfile->name);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ } else if (secret &&
+ check_file_secrecy(fileno(nfile->stream), nfile->name)) {
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
+ nfile->lineno = 1;
+ TAILQ_INSERT_TAIL(&files, nfile, entry);
+ return (nfile);
+}
+
+int
+popfile(void)
+{
+ struct file *prev;
+
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ prev->errors += file->errors;
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file);
+ file = prev;
+ return (0);
+ }
+ return (EOF);
+}
+
+int
+parse_config(char *filename, struct pfctl *xpf)
+{
+ int errors = 0;
+ struct sym *sym;
+
+ pf = xpf;
+ errors = 0;
+ rulestate = PFCTL_STATE_NONE;
+ returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+ returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+ blockpolicy = PFRULE_DROP;
+ require_order = 1;
+
+ if ((file = pushfile(filename, 0)) == NULL) {
+ warn("cannot open the main config file!");
+ return (-1);
+ }
+
+ yyparse();
+ errors = file->errors;
+ popfile();
+
+ /* Free macros and check which have not been used. */
+ while ((sym = TAILQ_FIRST(&symhead))) {
+ if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
+ fprintf(stderr, "warning: macro '%s' not "
+ "used\n", sym->nam);
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+
+ return (errors ? -1 : 0);
+}
+
+int
+symset(const char *nam, const char *val, int persist)
+{
+ struct sym *sym;
+
+ for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
+ sym = TAILQ_NEXT(sym, entry))
+ ; /* nothing */
+
+ if (sym != NULL) {
+ if (sym->persist == 1)
+ return (0);
+ else {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+ if ((sym = calloc(1, sizeof(*sym))) == NULL)
+ return (-1);
+
+ sym->nam = strdup(nam);
+ if (sym->nam == NULL) {
+ free(sym);
+ return (-1);
+ }
+ sym->val = strdup(val);
+ if (sym->val == NULL) {
+ free(sym->nam);
+ free(sym);
+ return (-1);
+ }
+ sym->used = 0;
+ sym->persist = persist;
+ TAILQ_INSERT_TAIL(&symhead, sym, entry);
+ return (0);
+}
+
+int
+pfctl_cmdline_symset(char *s)
+{
+ char *sym, *val;
+ int ret;
+
+ if ((val = strrchr(s, '=')) == NULL)
+ return (-1);
+
+ if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
+ err(1, "pfctl_cmdline_symset: malloc");
+
+ strlcpy(sym, s, strlen(s) - strlen(val) + 1);
+
+ ret = symset(sym, val + 1, 1);
+ free(sym);
+
+ return (ret);
+}
+
+char *
+symget(const char *nam)
+{
+ struct sym *sym;
+
+ TAILQ_FOREACH(sym, &symhead, entry)
+ if (strcmp(nam, sym->nam) == 0) {
+ sym->used = 1;
+ return (sym->val);
+ }
+ return (NULL);
+}
+
+void
+mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
+{
+ int i;
+ struct pf_rule *r;
+
+ for (i = 0; i < PF_RULESET_MAX; ++i) {
+ while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ dst->anchor->match++;
+ }
+ src->anchor->match = 0;
+ while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
+ r, entries);
+ }
+ }
+}
+
+void
+decide_address_family(struct node_host *n, sa_family_t *af)
+{
+ if (*af != 0 || n == NULL)
+ return;
+ *af = n->af;
+ while ((n = n->next) != NULL) {
+ if (n->af != *af) {
+ *af = 0;
+ return;
+ }
+ }
+}
+
+void
+remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
+{
+ struct node_host *n = *nh, *prev = NULL;
+
+ while (n != NULL) {
+ if (*af && n->af && n->af != *af) {
+ /* unlink and free n */
+ struct node_host *next = n->next;
+
+ /* adjust tail pointer */
+ if (n == (*nh)->tail)
+ (*nh)->tail = prev;
+ /* adjust previous node's next pointer */
+ if (prev == NULL)
+ *nh = next;
+ else
+ prev->next = next;
+ /* free node */
+ if (n->ifname != NULL)
+ free(n->ifname);
+ free(n);
+ n = next;
+ } else {
+ if (n->af && !*af)
+ *af = n->af;
+ prev = n;
+ n = n->next;
+ }
+ }
+}
+
+int
+invalid_redirect(struct node_host *nh, sa_family_t af)
+{
+ if (!af) {
+ struct node_host *n;
+
+ /* tables and dyniftl are ok without an address family */
+ for (n = nh; n != NULL; n = n->next) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
+ yyerror("address family not given and "
+ "translation address expands to multiple "
+ "address families");
+ return (1);
+ }
+ }
+ }
+ if (nh == NULL) {
+ yyerror("no translation address with matching address family "
+ "found.");
+ return (1);
+ }
+ return (0);
+}
+
+int
+atoul(char *s, u_long *ulvalp)
+{
+ u_long ulval;
+ char *ep;
+
+ errno = 0;
+ ulval = strtoul(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0')
+ return (-1);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (-1);
+ *ulvalp = ulval;
+ return (0);
+}
+
+int
+getservice(char *n)
+{
+ struct servent *s;
+ u_long ulval;
+
+ if (atoul(n, &ulval) == 0) {
+ if (ulval > 65535) {
+ yyerror("illegal port value %lu", ulval);
+ return (-1);
+ }
+ return (htons(ulval));
+ } else {
+ s = getservbyname(n, "tcp");
+ if (s == NULL)
+ s = getservbyname(n, "udp");
+ if (s == NULL) {
+ yyerror("unknown port %s", n);
+ return (-1);
+ }
+ return (s->s_port);
+ }
+}
+
+int
+rule_label(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->label, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+u_int16_t
+parseicmpspec(char *w, sa_family_t af)
+{
+ const struct icmpcodeent *p;
+ u_long ulval;
+ u_int8_t icmptype;
+
+ if (af == AF_INET)
+ icmptype = returnicmpdefault >> 8;
+ else
+ icmptype = returnicmp6default >> 8;
+
+ if (atoul(w, &ulval) == -1) {
+ if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
+ yyerror("unknown icmp code %s", w);
+ return (0);
+ }
+ ulval = p->code;
+ }
+ if (ulval > 255) {
+ yyerror("invalid icmp code %lu", ulval);
+ return (0);
+ }
+ return (icmptype << 8 | ulval);
+}
+
+int
+parseport(char *port, struct range *r, int extensions)
+{
+ char *p = strchr(port, ':');
+
+ if (p == NULL) {
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ return (0);
+ }
+ if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
+ *p = 0;
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_IRG;
+ return (0);
+ }
+ if ((extensions & PPORT_RANGE)) {
+ *p++ = 0;
+ if ((r->a = getservice(port)) == -1 ||
+ (r->b = getservice(p)) == -1)
+ return (-1);
+ if (r->a == r->b) {
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ } else
+ r->t = PF_OP_RRG;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
+{
+ struct loadanchors *la;
+
+ TAILQ_FOREACH(la, &loadanchorshead, entries) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "\nLoading anchor %s from %s\n",
+ la->anchorname, la->filename);
+ if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
+ la->anchorname, trans) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+rt_tableid_max(void)
+{
+#ifdef __FreeBSD__
+ int fibs;
+ size_t l = sizeof(fibs);
+
+ if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
+ fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
+ /*
+ * As the OpenBSD code only compares > and not >= we need to adjust
+ * here given we only accept values of 0..n and want to avoid #ifdefs
+ * in the grammar.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
+#line 4317 "pfctly.tab.c"
+
+#if YYDEBUG
+#include <stdio.h> /* needed for printf */
+#endif
+
+#include <stdlib.h> /* needed for malloc, etc */
+#include <string.h> /* needed for memset */
+
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+static int yygrowstack(YYSTACKDATA *data)
+{
+ int i;
+ unsigned newsize;
+ YYINT *newss;
+ YYSTYPE *newvs;
+
+ if ((newsize = data->stacksize) == 0)
+ newsize = YYINITSTACKSIZE;
+ else if (newsize >= YYMAXDEPTH)
+ return YYENOMEM;
+ else if ((newsize *= 2) > YYMAXDEPTH)
+ newsize = YYMAXDEPTH;
+
+ i = (int) (data->s_mark - data->s_base);
+ newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss));
+ if (newss == 0)
+ return YYENOMEM;
+
+ data->s_base = newss;
+ data->s_mark = newss + i;
+
+ newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs));
+ if (newvs == 0)
+ return YYENOMEM;
+
+ data->l_base = newvs;
+ data->l_mark = newvs + i;
+
+ data->stacksize = newsize;
+ data->s_last = data->s_base + newsize - 1;
+ return 0;
+}
+
+#if YYPURE || defined(YY_NO_LEAKS)
+static void yyfreestack(YYSTACKDATA *data)
+{
+ free(data->s_base);
+ free(data->l_base);
+ memset(data, 0, sizeof(*data));
+}
+#else
+#define yyfreestack(data) /* nothing */
+#endif
+
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+
+int
+YYPARSE_DECL()
+{
+ int yym, yyn, yystate;
+#if YYDEBUG
+ const char *yys;
+
+ if ((yys = getenv("YYDEBUG")) != 0)
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = YYEMPTY;
+ yystate = 0;
+
+#if YYPURE
+ memset(&yystack, 0, sizeof(yystack));
+#endif
+
+ if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+ yystack.s_mark = yystack.s_base;
+ yystack.l_mark = yystack.l_base;
+ yystate = 0;
+ *yystack.s_mark = 0;
+
+yyloop:
+ if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+ if (yychar < 0)
+ {
+ if ((yychar = YYLEX) < 0) yychar = YYEOF;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, yystate, yytable[yyn]);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ yystate = yytable[yyn];
+ *++yystack.s_mark = yytable[yyn];
+ *++yystack.l_mark = yylval;
+ yychar = YYEMPTY;
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+
+ YYERROR_CALL("syntax error");
+
+ goto yyerrlab;
+
+yyerrlab:
+ ++yynerrs;
+
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ yystate = yytable[yyn];
+ *++yystack.s_mark = yytable[yyn];
+ *++yystack.l_mark = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *yystack.s_mark);
+#endif
+ if (yystack.s_mark <= yystack.s_base) goto yyabort;
+ --yystack.s_mark;
+ --yystack.l_mark;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == YYEOF) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ yychar = YYEMPTY;
+ goto yyloop;
+ }
+
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ if (yym)
+ yyval = yystack.l_mark[1-yym];
+ else
+ memset(&yyval, 0, sizeof yyval);
+ switch (yyn)
+ {
+case 17:
+#line 553 "../../freebsd/sbin/pfctl/parse.y"
+ { file->errors++; }
+break;
+case 18:
+#line 556 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct file *nfile;
+
+ if ((nfile = pushfile(yystack.l_mark[0].v.string, 0)) == NULL) {
+ yyerror("failed to include file %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ file = nfile;
+ lungetc('\n');
+ }
+break;
+case 25:
+#line 583 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "none"))
+ yyval.v.i = 0;
+ else if (!strcmp(yystack.l_mark[0].v.string, "basic"))
+ yyval.v.i = PF_OPTIMIZE_BASIC;
+ else if (!strcmp(yystack.l_mark[0].v.string, "profile"))
+ yyval.v.i = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
+ else {
+ yyerror("unknown ruleset-optimization %s", yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+break;
+case 26:
+#line 597 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_optimization(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("unknown optimization %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 27:
+#line 609 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(pf->opts & PF_OPT_OPTIMIZE)) {
+ pf->opts |= PF_OPT_OPTIMIZE;
+ pf->optimize = yystack.l_mark[0].v.i;
+ }
+ }
+break;
+case 32:
+#line 619 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_logif(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("error setting loginterface %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 33:
+#line 631 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, yystack.l_mark[0].v.number) != 0) {
+ yyerror("error setting hostid %08x", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ }
+break;
+case 34:
+#line 641 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy drop\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_DROP;
+ }
+break;
+case 35:
+#line 648 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy return\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_RETURN;
+ }
+break;
+case 36:
+#line 655 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set require-order %s\n",
+ yystack.l_mark[0].v.number == 1 ? "yes" : "no");
+ require_order = yystack.l_mark[0].v.number;
+ }
+break;
+case 37:
+#line 661 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set fingerprints \"%s\"\n", yystack.l_mark[0].v.string);
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (!pf->anchor->name[0]) {
+ if (pfctl_file_fingerprints(pf->dev,
+ pf->opts, yystack.l_mark[0].v.string)) {
+ yyerror("error loading "
+ "fingerprints %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 38:
+#line 679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch (yystack.l_mark[0].v.i) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ }
+ default_statelock = yystack.l_mark[0].v.i;
+ }
+break;
+case 39:
+#line 691 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ if (pfctl_set_debug(pf, yystack.l_mark[0].v.string) != 0) {
+ yyerror("error setting debuglevel %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 40:
+#line 703 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (expand_skip_interface(yystack.l_mark[0].v.interface) != 0) {
+ yyerror("error setting skip interface(s)");
+ YYERROR;
+ }
+ }
+break;
+case 41:
+#line 709 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (keep_state_defaults != NULL) {
+ yyerror("cannot redefine state-defaults");
+ YYERROR;
+ }
+ keep_state_defaults = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 42:
+#line 718 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 43:
+#line 719 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if ((yyval.v.string = strdup("all")) == NULL) {
+ err(1, "stringall: strdup");
+ }
+ }
+break;
+case 44:
+#line 726 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1)
+ err(1, "string: asprintf");
+ free(yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 46:
+#line 735 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1)
+ err(1, "string: asprintf");
+ free(yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 48:
+#line 744 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *s;
+ if (asprintf(&s, "%lld", (long long)yystack.l_mark[0].v.number) == -1) {
+ yyerror("string: asprintf");
+ YYERROR;
+ }
+ yyval.v.string = s;
+ }
+break;
+case 50:
+#line 755 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("%s = \"%s\"\n", yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string);
+ if (symset(yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string, 0) == -1)
+ err(1, "cannot store variable %s", yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 51:
+#line 765 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 52:
+#line 766 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = NULL; }
+break;
+case 57:
+#line 776 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char ta[PF_ANCHOR_NAME_SIZE];
+ struct pf_ruleset *rs;
+
+ /* steping into a brace anchor */
+ pf->asd++;
+ pf->bn++;
+ pf->brace = 1;
+
+ /* create a holding ruleset in the root */
+ snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
+ rs = pf_find_or_create_ruleset(ta);
+ if (rs == NULL)
+ err(1, "pfa_anchor: pf_find_or_create_ruleset");
+ pf->astack[pf->asd] = rs->anchor;
+ pf->anchor = rs->anchor;
+ }
+break;
+case 58:
+#line 793 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ pf->alast = pf->anchor;
+ pf->asd--;
+ pf->anchor = pf->astack[pf->asd];
+ }
+break;
+case 60:
+#line 803 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_proto *proto;
+
+ if (check_rulestate(PFCTL_STATE_FILTER)) {
+ if (yystack.l_mark[-8].v.string)
+ free(yystack.l_mark[-8].v.string);
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-8].v.string && (yystack.l_mark[-8].v.string[0] == '_' || strstr(yystack.l_mark[-8].v.string, "/_") != NULL)) {
+ free(yystack.l_mark[-8].v.string);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ if (pf->astack[pf->asd + 1]) {
+ /* move inline rules into relative location */
+ pf_anchor_setup(&r,
+ &pf->astack[pf->asd]->ruleset,
+ yystack.l_mark[-8].v.string ? yystack.l_mark[-8].v.string : pf->alast->name);
+
+ if (r.anchor == NULL)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+
+ if (pf->alast != r.anchor) {
+ if (r.anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r.anchor->name);
+ YYERROR;
+ }
+ mv_rules(&pf->alast->ruleset,
+ &r.anchor->ruleset);
+ }
+ pf_remove_if_empty_ruleset(&pf->alast->ruleset);
+ pf->alast = r.anchor;
+ } else {
+ if (!yystack.l_mark[-8].v.string) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ YYERROR;
+ }
+ }
+ r.direction = yystack.l_mark[-7].v.i;
+ r.quick = yystack.l_mark[-6].v.logquick.quick;
+ r.af = yystack.l_mark[-4].v.i;
+ r.prob = yystack.l_mark[-1].v.filter_opts.prob;
+ r.rtableid = yystack.l_mark[-1].v.filter_opts.rtableid;
+
+ if (yystack.l_mark[-1].v.filter_opts.tag)
+ if (strlcpy(r.tagname, yystack.l_mark[-1].v.filter_opts.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not;
+ if (rule_label(&r, yystack.l_mark[-1].v.filter_opts.label))
+ YYERROR;
+ free(yystack.l_mark[-1].v.filter_opts.label);
+ r.flags = yystack.l_mark[-1].v.filter_opts.flags.b1;
+ r.flagset = yystack.l_mark[-1].v.filter_opts.flags.b2;
+ if ((yystack.l_mark[-1].v.filter_opts.flags.b1 & yystack.l_mark[-1].v.filter_opts.flags.b2) != yystack.l_mark[-1].v.filter_opts.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2 || yystack.l_mark[-2].v.fromto.src_os) {
+ for (proto = yystack.l_mark[-3].v.proto; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && yystack.l_mark[-3].v.proto != NULL) {
+ if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if (yystack.l_mark[-2].v.fromto.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "applies to tcp");
+ YYERROR;
+ }
+ }
+
+ r.tos = yystack.l_mark[-1].v.filter_opts.tos;
+
+ if (yystack.l_mark[-1].v.filter_opts.keep.action) {
+ yyerror("cannot specify state handling "
+ "on anchors");
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-1].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not;
+ if (yystack.l_mark[-1].v.filter_opts.marker & FOM_PRIO) {
+ if (yystack.l_mark[-1].v.filter_opts.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = yystack.l_mark[-1].v.filter_opts.prio;
+ }
+ if (yystack.l_mark[-1].v.filter_opts.marker & FOM_SETPRIO) {
+ r.set_prio[0] = yystack.l_mark[-1].v.filter_opts.set_prio[0];
+ r.set_prio[1] = yystack.l_mark[-1].v.filter_opts.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ decide_address_family(yystack.l_mark[-2].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-2].v.fromto.dst.host, &r.af);
+
+ expand_rule(&r, yystack.l_mark[-5].v.interface, NULL, yystack.l_mark[-3].v.proto, yystack.l_mark[-2].v.fromto.src_os,
+ yystack.l_mark[-2].v.fromto.src.host, yystack.l_mark[-2].v.fromto.src.port, yystack.l_mark[-2].v.fromto.dst.host, yystack.l_mark[-2].v.fromto.dst.port,
+ yystack.l_mark[-1].v.filter_opts.uid, yystack.l_mark[-1].v.filter_opts.gid, yystack.l_mark[-1].v.filter_opts.icmpspec,
+ pf->astack[pf->asd + 1] ? pf->alast->name : yystack.l_mark[-8].v.string);
+ free(yystack.l_mark[-8].v.string);
+ pf->astack[pf->asd + 1] = NULL;
+ }
+break;
+case 61:
+#line 935 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_NAT;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ 0, 0, 0, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 62:
+#line 956 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_RDR;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ if (yystack.l_mark[-1].v.fromto.src.port != NULL) {
+ yyerror("source port parameter not supported"
+ " in rdr-anchor");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.fromto.dst.port != NULL) {
+ if (yystack.l_mark[-1].v.fromto.dst.port->next != NULL) {
+ yyerror("destination port list "
+ "expansion not supported in "
+ "rdr-anchor");
+ YYERROR;
+ } else if (yystack.l_mark[-1].v.fromto.dst.port->op != PF_OP_EQ) {
+ yyerror("destination port operators"
+ " not supported in rdr-anchor");
+ YYERROR;
+ }
+ r.dst.port[0] = yystack.l_mark[-1].v.fromto.dst.port->port[0];
+ r.dst.port[1] = yystack.l_mark[-1].v.fromto.dst.port->port[1];
+ r.dst.port_op = yystack.l_mark[-1].v.fromto.dst.port->op;
+ }
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ 0, 0, 0, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 63:
+#line 998 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free(yystack.l_mark[-5].v.string);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_BINAT;
+ r.af = yystack.l_mark[-3].v.i;
+ r.rtableid = yystack.l_mark[0].v.rtableid;
+ if (yystack.l_mark[-2].v.proto != NULL) {
+ if (yystack.l_mark[-2].v.proto->next != NULL) {
+ yyerror("proto list expansion"
+ " not supported in binat-anchor");
+ YYERROR;
+ }
+ r.proto = yystack.l_mark[-2].v.proto->proto;
+ free(yystack.l_mark[-2].v.proto);
+ }
+
+ if (yystack.l_mark[-1].v.fromto.src.host != NULL || yystack.l_mark[-1].v.fromto.src.port != NULL ||
+ yystack.l_mark[-1].v.fromto.dst.host != NULL || yystack.l_mark[-1].v.fromto.dst.port != NULL) {
+ yyerror("fromto parameter not supported"
+ " in binat-anchor");
+ YYERROR;
+ }
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ pfctl_add_rule(pf, &r, yystack.l_mark[-5].v.string);
+ free(yystack.l_mark[-5].v.string);
+ }
+break;
+case 64:
+#line 1035 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct loadanchors *loadanchor;
+
+ if (strlen(pf->anchor->name) + 1 +
+ strlen(yystack.l_mark[-2].v.string) >= MAXPATHLEN) {
+ yyerror("anchorname %s too long, max %u\n",
+ yystack.l_mark[-2].v.string, MAXPATHLEN - 1);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ loadanchor = calloc(1, sizeof(struct loadanchors));
+ if (loadanchor == NULL)
+ err(1, "loadrule: calloc");
+ if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
+ NULL)
+ err(1, "loadrule: malloc");
+ if (pf->anchor->name[0])
+ snprintf(loadanchor->anchorname, MAXPATHLEN,
+ "%s/%s", pf->anchor->name, yystack.l_mark[-2].v.string);
+ else
+ strlcpy(loadanchor->anchorname, yystack.l_mark[-2].v.string, MAXPATHLEN);
+ if ((loadanchor->filename = strdup(yystack.l_mark[0].v.string)) == NULL)
+ err(1, "loadrule: strdup");
+
+ TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
+ entries);
+
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 65:
+#line 1066 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = yyval.v.b.w = 0;
+ if (yystack.l_mark[-1].v.i)
+ yyval.v.b.b1 = PF_NOSCRUB;
+ else
+ yyval.v.b.b1 = PF_SCRUB;
+ }
+break;
+case 66:
+#line 1076 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_SCRUB))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-7].v.b.b1;
+ r.direction = yystack.l_mark[-6].v.i;
+
+ r.log = yystack.l_mark[-5].v.logquick.log;
+ r.logif = yystack.l_mark[-5].v.logquick.logif;
+ if (yystack.l_mark[-5].v.logquick.quick) {
+ yyerror("scrub rules do not support 'quick'");
+ YYERROR;
+ }
+
+ r.af = yystack.l_mark[-3].v.i;
+ if (yystack.l_mark[0].v.scrub_opts.nodf)
+ r.rule_flag |= PFRULE_NODF;
+ if (yystack.l_mark[0].v.scrub_opts.randomid)
+ r.rule_flag |= PFRULE_RANDOMID;
+ if (yystack.l_mark[0].v.scrub_opts.reassemble_tcp) {
+ if (r.direction != PF_INOUT) {
+ yyerror("reassemble tcp rules can not "
+ "specify direction");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_REASSEMBLE_TCP;
+ }
+ if (yystack.l_mark[0].v.scrub_opts.minttl)
+ r.min_ttl = yystack.l_mark[0].v.scrub_opts.minttl;
+ if (yystack.l_mark[0].v.scrub_opts.maxmss)
+ r.max_mss = yystack.l_mark[0].v.scrub_opts.maxmss;
+ if (yystack.l_mark[0].v.scrub_opts.marker & SOM_SETTOS) {
+ r.rule_flag |= PFRULE_SET_TOS;
+ r.set_tos = yystack.l_mark[0].v.scrub_opts.settos;
+ }
+ if (yystack.l_mark[0].v.scrub_opts.fragcache)
+ r.rule_flag |= yystack.l_mark[0].v.scrub_opts.fragcache;
+ if (yystack.l_mark[0].v.scrub_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[0].v.scrub_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[0].v.scrub_opts.match_tag_not;
+ r.rtableid = yystack.l_mark[0].v.scrub_opts.rtableid;
+
+ expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ NULL, NULL, NULL, "");
+ }
+break;
+case 67:
+#line 1133 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ }
+break;
+case 68:
+#line 1138 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.scrub_opts = scrub_opts; }
+break;
+case 69:
+#line 1139 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ yyval.v.scrub_opts = scrub_opts;
+ }
+break;
+case 72:
+#line 1150 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.nodf) {
+ yyerror("no-df cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.nodf = 1;
+ }
+break;
+case 73:
+#line 1157 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_MINTTL) {
+ yyerror("min-ttl cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal min-ttl value %d", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MINTTL;
+ scrub_opts.minttl = yystack.l_mark[0].v.number;
+ }
+break;
+case 74:
+#line 1169 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_MAXMSS) {
+ yyerror("max-mss cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("illegal max-mss value %d", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MAXMSS;
+ scrub_opts.maxmss = yystack.l_mark[0].v.number;
+ }
+break;
+case 75:
+#line 1181 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_SETTOS) {
+ yyerror("set-tos cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_SETTOS;
+ scrub_opts.settos = yystack.l_mark[0].v.number;
+ }
+break;
+case 76:
+#line 1189 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.marker & SOM_FRAGCACHE) {
+ yyerror("fragcache cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_FRAGCACHE;
+ scrub_opts.fragcache = yystack.l_mark[0].v.i;
+ }
+break;
+case 77:
+#line 1197 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strcasecmp(yystack.l_mark[0].v.string, "tcp") != 0) {
+ yyerror("scrub reassemble supports only tcp, "
+ "not '%s'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ if (scrub_opts.reassemble_tcp) {
+ yyerror("reassemble tcp cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.reassemble_tcp = 1;
+ }
+break;
+case 78:
+#line 1211 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (scrub_opts.randomid) {
+ yyerror("random-id cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.randomid = 1;
+ }
+break;
+case 79:
+#line 1218 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ scrub_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 80:
+#line 1225 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ scrub_opts.match_tag = yystack.l_mark[0].v.string;
+ scrub_opts.match_tag_not = yystack.l_mark[-2].v.number;
+ }
+break;
+case 81:
+#line 1231 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; /* default */ }
+break;
+case 82:
+#line 1232 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 83:
+#line 1233 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 84:
+#line 1236 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_host *h = NULL, *hh;
+ struct node_if *i, *j;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ for (i = yystack.l_mark[-2].v.interface; i; i = i->next) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = yystack.l_mark[-3].v.logquick.log;
+ r.logif = yystack.l_mark[-3].v.logquick.logif;
+ r.quick = yystack.l_mark[-3].v.logquick.quick;
+ r.af = yystack.l_mark[-1].v.i;
+ if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label))
+ YYERROR;
+ r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid;
+ j = calloc(1, sizeof(struct node_if));
+ if (j == NULL)
+ err(1, "antispoof: calloc");
+ if (strlcpy(j->ifname, i->ifname,
+ sizeof(j->ifname)) >= sizeof(j->ifname)) {
+ free(j);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ j->not = 1;
+ if (i->dynamic) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->addr.type = PF_ADDR_DYNIFTL;
+ set_ipmask(h, 128);
+ if (strlcpy(h->addr.v.ifname, i->ifname,
+ sizeof(h->addr.v.ifname)) >=
+ sizeof(h->addr.v.ifname)) {
+ free(h);
+ yyerror(
+ "interface name too long");
+ YYERROR;
+ }
+ hh = malloc(sizeof(*hh));
+ if (hh == NULL)
+ err(1, "address: malloc");
+ bcopy(h, hh, sizeof(*hh));
+ h->addr.iflags = PFI_AFLAG_NETWORK;
+ } else {
+ h = ifa_lookup(j->ifname,
+ PFI_AFLAG_NETWORK);
+ hh = NULL;
+ }
+
+ if (h != NULL)
+ expand_rule(&r, j, NULL, NULL, NULL, h,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, "");
+
+ if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = yystack.l_mark[-3].v.logquick.log;
+ r.logif = yystack.l_mark[-3].v.logquick.logif;
+ r.quick = yystack.l_mark[-3].v.logquick.quick;
+ r.af = yystack.l_mark[-1].v.i;
+ if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label))
+ YYERROR;
+ r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid;
+ if (hh != NULL)
+ h = hh;
+ else
+ h = ifa_lookup(i->ifname, 0);
+ if (h != NULL)
+ expand_rule(&r, NULL, NULL,
+ NULL, NULL, h, NULL, NULL,
+ NULL, NULL, NULL, NULL, "");
+ } else
+ free(hh);
+ }
+ free(yystack.l_mark[0].v.antispoof_opts.label);
+ }
+break;
+case 85:
+#line 1323 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 86:
+#line 1324 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 87:
+#line 1327 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 88:
+#line 1328 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface;
+ yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface;
+ yyval.v.interface = yystack.l_mark[-3].v.interface;
+ }
+break;
+case 89:
+#line 1335 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 90:
+#line 1336 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-1].v.interface->dynamic = 1;
+ yyval.v.interface = yystack.l_mark[-1].v.interface;
+ }
+break;
+case 91:
+#line 1342 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ }
+break;
+case 92:
+#line 1347 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.antispoof_opts = antispoof_opts; }
+break;
+case 93:
+#line 1348 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ yyval.v.antispoof_opts = antispoof_opts;
+ }
+break;
+case 96:
+#line 1359 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (antispoof_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ antispoof_opts.label = yystack.l_mark[0].v.string;
+ }
+break;
+case 97:
+#line 1366 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ antispoof_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 98:
+#line 1375 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 1; }
+break;
+case 99:
+#line 1376 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 0; }
+break;
+case 100:
+#line 1379 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *h, *nh;
+ struct node_tinit *ti, *nti;
+
+ if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name too long, max %d chars",
+ PF_TABLE_NAME_SIZE - 1);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (process_tabledef(yystack.l_mark[-2].v.string, &yystack.l_mark[0].v.table_opts)) {
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-2].v.string);
+ for (ti = SIMPLEQ_FIRST(&yystack.l_mark[0].v.table_opts.init_nodes);
+ ti != SIMPLEQ_END(&yystack.l_mark[0].v.table_opts.init_nodes); ti = nti) {
+ if (ti->file)
+ free(ti->file);
+ for (h = ti->host; h != NULL; h = nh) {
+ nh = h->next;
+ free(h);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ free(ti);
+ }
+ }
+break;
+case 101:
+#line 1409 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ }
+break;
+case 102:
+#line 1414 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.table_opts = table_opts; }
+break;
+case 103:
+#line 1416 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ yyval.v.table_opts = table_opts;
+ }
+break;
+case 106:
+#line 1427 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "const"))
+ table_opts.flags |= PFR_TFLAG_CONST;
+ else if (!strcmp(yystack.l_mark[0].v.string, "persist"))
+ table_opts.flags |= PFR_TFLAG_PERSIST;
+ else if (!strcmp(yystack.l_mark[0].v.string, "counters"))
+ table_opts.flags |= PFR_TFLAG_COUNTERS;
+ else {
+ yyerror("invalid table option '%s'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 107:
+#line 1441 "../../freebsd/sbin/pfctl/parse.y"
+ { table_opts.init_addr = 1; }
+break;
+case 108:
+#line 1442 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+ struct node_tinit *ti;
+
+ for (n = yystack.l_mark[-1].v.host; n != NULL; n = n->next) {
+ switch (n->addr.type) {
+ case PF_ADDR_ADDRMASK:
+ continue; /* ok */
+ case PF_ADDR_RANGE:
+ yyerror("address ranges are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_DYNIFTL:
+ yyerror("dynamic addresses are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_TABLE:
+ yyerror("tables cannot contain tables");
+ break;
+ case PF_ADDR_NOROUTE:
+ yyerror("\"no-route\" is not permitted "
+ "inside tables");
+ break;
+ case PF_ADDR_URPFFAILED:
+ yyerror("\"urpf-failed\" is not "
+ "permitted inside tables");
+ break;
+ default:
+ yyerror("unknown address type %d",
+ n->addr.type);
+ }
+ YYERROR;
+ }
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->host = yystack.l_mark[-1].v.host;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+break;
+case 109:
+#line 1482 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_tinit *ti;
+
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->file = yystack.l_mark[0].v.string;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+break;
+case 110:
+#line 1494 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE))
+ YYERROR;
+
+ memset(&a, 0, sizeof(a));
+ if (yystack.l_mark[-2].v.queue_opts.scheduler.qtype == ALTQT_NONE) {
+ yyerror("no scheduler specified!");
+ YYERROR;
+ }
+ a.scheduler = yystack.l_mark[-2].v.queue_opts.scheduler.qtype;
+ a.qlimit = yystack.l_mark[-2].v.queue_opts.qlimit;
+ a.tbrsize = yystack.l_mark[-2].v.queue_opts.tbrsize;
+ if (yystack.l_mark[0].v.queue == NULL && yystack.l_mark[-2].v.queue_opts.scheduler.qtype != ALTQT_CODEL) {
+ yyerror("no child queues specified");
+ YYERROR;
+ }
+ if (expand_altq(&a, yystack.l_mark[-3].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-2].v.queue_opts.queue_bwspec,
+ &yystack.l_mark[-2].v.queue_opts.scheduler))
+ YYERROR;
+ }
+break;
+case 111:
+#line 1518 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE)) {
+ free(yystack.l_mark[-3].v.string);
+ YYERROR;
+ }
+
+ memset(&a, 0, sizeof(a));
+
+ if (strlcpy(a.qname, yystack.l_mark[-3].v.string, sizeof(a.qname)) >=
+ sizeof(a.qname)) {
+ yyerror("queue name too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ free(yystack.l_mark[-3].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-3].v.string);
+ if (yystack.l_mark[-1].v.queue_opts.tbrsize) {
+ yyerror("cannot specify tbrsize for queue");
+ YYERROR;
+ }
+ if (yystack.l_mark[-1].v.queue_opts.priority > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ a.priority = yystack.l_mark[-1].v.queue_opts.priority;
+ a.qlimit = yystack.l_mark[-1].v.queue_opts.qlimit;
+ a.scheduler = yystack.l_mark[-1].v.queue_opts.scheduler.qtype;
+ if (expand_queue(&a, yystack.l_mark[-2].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-1].v.queue_opts.queue_bwspec,
+ &yystack.l_mark[-1].v.queue_opts.scheduler)) {
+ yyerror("errors in queue definition");
+ YYERROR;
+ }
+ }
+break;
+case 112:
+#line 1555 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ }
+break;
+case 113:
+#line 1563 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue_opts = queue_opts; }
+break;
+case 114:
+#line 1564 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ yyval.v.queue_opts = queue_opts;
+ }
+break;
+case 117:
+#line 1578 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_BWSPEC) {
+ yyerror("bandwidth cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_BWSPEC;
+ queue_opts.queue_bwspec = yystack.l_mark[0].v.queue_bwspec;
+ }
+break;
+case 118:
+#line 1586 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_PRIORITY) {
+ yyerror("priority cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_PRIORITY;
+ queue_opts.priority = yystack.l_mark[0].v.number;
+ }
+break;
+case 119:
+#line 1598 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_QLIMIT) {
+ yyerror("qlimit cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("qlimit out of range: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_QLIMIT;
+ queue_opts.qlimit = yystack.l_mark[0].v.number;
+ }
+break;
+case 120:
+#line 1610 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_SCHEDULER) {
+ yyerror("scheduler cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_SCHEDULER;
+ queue_opts.scheduler = yystack.l_mark[0].v.queue_options;
+ }
+break;
+case 121:
+#line 1618 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (queue_opts.marker & QOM_TBRSIZE) {
+ yyerror("tbrsize cannot be respecified");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) {
+ yyerror("tbrsize too big: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_TBRSIZE;
+ queue_opts.tbrsize = yystack.l_mark[0].v.number;
+ }
+break;
+case 122:
+#line 1632 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ double bps;
+ char *cp;
+
+ yyval.v.queue_bwspec.bw_percent = 0;
+
+ bps = strtod(yystack.l_mark[0].v.string, &cp);
+ if (cp != NULL) {
+ if (strlen(cp) > 1) {
+ char *cu = cp + 1;
+ if (!strcmp(cu, "Bit") ||
+ !strcmp(cu, "B") ||
+ !strcmp(cu, "bit") ||
+ !strcmp(cu, "b")) {
+ *cu = 0;
+ }
+ }
+ if (!strcmp(cp, "b"))
+ ; /* nothing */
+ else if (!strcmp(cp, "K"))
+ bps *= 1000;
+ else if (!strcmp(cp, "M"))
+ bps *= 1000 * 1000;
+ else if (!strcmp(cp, "G"))
+ bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "%")) {
+ if (bps < 0 || bps > 100) {
+ yyerror("bandwidth spec "
+ "out of range");
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.queue_bwspec.bw_percent = bps;
+ bps = 0;
+ } else {
+ yyerror("unknown unit %s", cp);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.queue_bwspec.bw_absolute = (u_int32_t)bps;
+ }
+break;
+case 123:
+#line 1675 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("bandwidth number too big");
+ YYERROR;
+ }
+ yyval.v.queue_bwspec.bw_percent = 0;
+ yyval.v.queue_bwspec.bw_absolute = yystack.l_mark[0].v.number;
+ }
+break;
+case 124:
+#line 1685 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CBQ;
+ yyval.v.queue_options.data.cbq_opts.flags = 0;
+ }
+break;
+case 125:
+#line 1689 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CBQ;
+ yyval.v.queue_options.data.cbq_opts.flags = yystack.l_mark[-1].v.number;
+ }
+break;
+case 126:
+#line 1693 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_PRIQ;
+ yyval.v.queue_options.data.priq_opts.flags = 0;
+ }
+break;
+case 127:
+#line 1697 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_PRIQ;
+ yyval.v.queue_options.data.priq_opts.flags = yystack.l_mark[-1].v.number;
+ }
+break;
+case 128:
+#line 1701 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_HFSC;
+ bzero(&yyval.v.queue_options.data.hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+break;
+case 129:
+#line 1706 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_HFSC;
+ yyval.v.queue_options.data.hfsc_opts = yystack.l_mark[-1].v.hfsc_opts;
+ }
+break;
+case 130:
+#line 1710 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_FAIRQ;
+ bzero(&yyval.v.queue_options.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+break;
+case 131:
+#line 1715 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_FAIRQ;
+ yyval.v.queue_options.data.fairq_opts = yystack.l_mark[-1].v.fairq_opts;
+ }
+break;
+case 132:
+#line 1719 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CODEL;
+ bzero(&yyval.v.queue_options.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+break;
+case 133:
+#line 1724 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue_options.qtype = ALTQT_CODEL;
+ yyval.v.queue_options.data.codel_opts = yystack.l_mark[-1].v.codel_opts;
+ }
+break;
+case 134:
+#line 1730 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 135:
+#line 1731 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 136:
+#line 1734 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ yyval.v.number = CBQCLF_DEFCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "borrow"))
+ yyval.v.number = CBQCLF_BORROW;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ yyval.v.number = CBQCLF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ yyval.v.number = CBQCLF_RED|CBQCLF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ yyval.v.number = CBQCLF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ yyval.v.number = CBQCLF_CODEL;
+ else {
+ yyerror("unknown cbq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 137:
+#line 1756 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 138:
+#line 1757 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number |= yystack.l_mark[0].v.number; }
+break;
+case 139:
+#line 1760 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ yyval.v.number = PRCF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ yyval.v.number = PRCF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ yyval.v.number = PRCF_RED|PRCF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ yyval.v.number = PRCF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ yyval.v.number = PRCF_CODEL;
+ else {
+ yyerror("unknown priq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 140:
+#line 1780 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+break;
+case 141:
+#line 1784 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.hfsc_opts = hfsc_opts;
+ }
+break;
+case 144:
+#line 1793 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.linkshare.used = 1;
+ }
+break;
+case 145:
+#line 1802 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.linkshare.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.linkshare.used = 1;
+ }
+break;
+case 146:
+#line 1816 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.realtime.used = 1;
+ }
+break;
+case 147:
+#line 1825 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.realtime.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.realtime.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.realtime.used = 1;
+ }
+break;
+case 148:
+#line 1839 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m2 = yystack.l_mark[0].v.queue_bwspec;
+ hfsc_opts.upperlimit.used = 1;
+ }
+break;
+case 149:
+#line 1848 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m1 = yystack.l_mark[-5].v.queue_bwspec;
+ hfsc_opts.upperlimit.d = yystack.l_mark[-3].v.number;
+ hfsc_opts.upperlimit.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ hfsc_opts.upperlimit.used = 1;
+ }
+break;
+case 150:
+#line 1862 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ hfsc_opts.flags |= HFCF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ hfsc_opts.flags |= HFCF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
+ else {
+ yyerror("unknown hfsc flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 151:
+#line 1882 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+break;
+case 152:
+#line 1886 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fairq_opts = fairq_opts;
+ }
+break;
+case 155:
+#line 1895 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec;
+ fairq_opts.linkshare.used = 1;
+ }
+break;
+case 156:
+#line 1903 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = yystack.l_mark[-3].v.queue_bwspec;
+ fairq_opts.linkshare.d = yystack.l_mark[-2].v.number;
+ fairq_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec;
+ fairq_opts.linkshare.used = 1;
+ }
+break;
+case 157:
+#line 1913 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ fairq_opts.hogs_bw = yystack.l_mark[0].v.queue_bwspec;
+ }
+break;
+case 158:
+#line 1916 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ fairq_opts.nbuckets = yystack.l_mark[0].v.number;
+ }
+break;
+case 159:
+#line 1919 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp(yystack.l_mark[0].v.string, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp(yystack.l_mark[0].v.string, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp(yystack.l_mark[0].v.string, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 160:
+#line 1939 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+break;
+case 161:
+#line 1943 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.codel_opts = codel_opts;
+ }
+break;
+case 164:
+#line 1952 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = yystack.l_mark[0].v.number;
+ }
+break;
+case 165:
+#line 1959 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = yystack.l_mark[0].v.number;
+ }
+break;
+case 166:
+#line 1966 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 167:
+#line 1978 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = NULL; }
+break;
+case 168:
+#line 1979 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[0].v.queue; }
+break;
+case 169:
+#line 1980 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[-1].v.queue; }
+break;
+case 170:
+#line 1983 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.queue = yystack.l_mark[-1].v.queue; }
+break;
+case 171:
+#line 1984 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.queue->tail->next = yystack.l_mark[-1].v.queue;
+ yystack.l_mark[-3].v.queue->tail = yystack.l_mark[-1].v.queue;
+ yyval.v.queue = yystack.l_mark[-3].v.queue;
+ }
+break;
+case 172:
+#line 1991 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.queue = calloc(1, sizeof(struct node_queue));
+ if (yyval.v.queue == NULL)
+ err(1, "qassign_item: calloc");
+ if (strlcpy(yyval.v.queue->queue, yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)) >=
+ sizeof(yyval.v.queue->queue)) {
+ yyerror("queue name '%s' too long (max "
+ "%d chars)", yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)-1);
+ free(yystack.l_mark[0].v.string);
+ free(yyval.v.queue);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.queue->next = NULL;
+ yyval.v.queue->tail = yyval.v.queue;
+ }
+break;
+case 173:
+#line 2011 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+ struct node_state_opt *o;
+ struct node_proto *proto;
+ int srctrack = 0;
+ int statelock = 0;
+ int adaptive = 0;
+ int defaults = 0;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-8].v.b.b1;
+ switch (yystack.l_mark[-8].v.b.b2) {
+ case PFRULE_RETURNRST:
+ r.rule_flag |= PFRULE_RETURNRST;
+ r.return_ttl = yystack.l_mark[-8].v.b.w;
+ break;
+ case PFRULE_RETURNICMP:
+ r.rule_flag |= PFRULE_RETURNICMP;
+ r.return_icmp = yystack.l_mark[-8].v.b.w;
+ r.return_icmp6 = yystack.l_mark[-8].v.b.w2;
+ break;
+ case PFRULE_RETURN:
+ r.rule_flag |= PFRULE_RETURN;
+ r.return_icmp = yystack.l_mark[-8].v.b.w;
+ r.return_icmp6 = yystack.l_mark[-8].v.b.w2;
+ break;
+ }
+ r.direction = yystack.l_mark[-7].v.i;
+ r.log = yystack.l_mark[-6].v.logquick.log;
+ r.logif = yystack.l_mark[-6].v.logquick.logif;
+ r.quick = yystack.l_mark[-6].v.logquick.quick;
+ r.prob = yystack.l_mark[0].v.filter_opts.prob;
+ r.rtableid = yystack.l_mark[0].v.filter_opts.rtableid;
+
+ if (yystack.l_mark[0].v.filter_opts.marker & FOM_PRIO) {
+ if (yystack.l_mark[0].v.filter_opts.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = yystack.l_mark[0].v.filter_opts.prio;
+ }
+ if (yystack.l_mark[0].v.filter_opts.marker & FOM_SETPRIO) {
+ r.set_prio[0] = yystack.l_mark[0].v.filter_opts.set_prio[0];
+ r.set_prio[1] = yystack.l_mark[0].v.filter_opts.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ r.af = yystack.l_mark[-3].v.i;
+ if (yystack.l_mark[0].v.filter_opts.tag)
+ if (strlcpy(r.tagname, yystack.l_mark[0].v.filter_opts.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.match_tag)
+ if (strlcpy(r.match_tagname, yystack.l_mark[0].v.filter_opts.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[0].v.filter_opts.match_tag_not;
+ if (rule_label(&r, yystack.l_mark[0].v.filter_opts.label))
+ YYERROR;
+ free(yystack.l_mark[0].v.filter_opts.label);
+ r.flags = yystack.l_mark[0].v.filter_opts.flags.b1;
+ r.flagset = yystack.l_mark[0].v.filter_opts.flags.b2;
+ if ((yystack.l_mark[0].v.filter_opts.flags.b1 & yystack.l_mark[0].v.filter_opts.flags.b2) != yystack.l_mark[0].v.filter_opts.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2 || yystack.l_mark[-1].v.fromto.src_os) {
+ for (proto = yystack.l_mark[-2].v.proto; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && yystack.l_mark[-2].v.proto != NULL) {
+ if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if (yystack.l_mark[-1].v.fromto.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "apply to tcp");
+ YYERROR;
+ }
+#if 0
+ if ((yystack.l_mark[0].v.filter_opts.flags.b1 & parse_flags("S")) == 0 &&
+ yystack.l_mark[-1].v.fromto.src_os) {
+ yyerror("OS fingerprinting requires "
+ "the SYN TCP flag (flags S/SA)");
+ YYERROR;
+ }
+#endif
+ }
+
+ r.tos = yystack.l_mark[0].v.filter_opts.tos;
+ r.keep_state = yystack.l_mark[0].v.filter_opts.keep.action;
+ o = yystack.l_mark[0].v.filter_opts.keep.options;
+
+ /* 'keep state' by default on pass rules. */
+ if (!r.keep_state && !r.action &&
+ !(yystack.l_mark[0].v.filter_opts.marker & FOM_KEEP)) {
+ r.keep_state = PF_STATE_NORMAL;
+ o = keep_state_defaults;
+ defaults = 1;
+ }
+
+ while (o) {
+ struct node_state_opt *p = o;
+
+ switch (o->type) {
+ case PF_STATE_OPT_MAX:
+ if (r.max_states) {
+ yyerror("state option 'max' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.max_states = o->data.max_states;
+ break;
+ case PF_STATE_OPT_NOSYNC:
+ if (r.rule_flag & PFRULE_NOSYNC) {
+ yyerror("state option 'sync' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_NOSYNC;
+ break;
+ case PF_STATE_OPT_SRCTRACK:
+ if (srctrack) {
+ yyerror("state option "
+ "'source-track' "
+ "multiple definitions");
+ YYERROR;
+ }
+ srctrack = o->data.src_track;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_STATES:
+ if (r.max_src_states) {
+ yyerror("state option "
+ "'max-src-states' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_states == 0) {
+ yyerror("'max-src-states' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_states =
+ o->data.max_src_states;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_OVERLOAD:
+ if (r.overload_tblname[0]) {
+ yyerror("multiple 'overload' "
+ "table definitions");
+ YYERROR;
+ }
+ if (strlcpy(r.overload_tblname,
+ o->data.overload.tblname,
+ PF_TABLE_NAME_SIZE) >=
+ PF_TABLE_NAME_SIZE) {
+ yyerror("state option: "
+ "strlcpy");
+ YYERROR;
+ }
+ r.flush = o->data.overload.flush;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN:
+ if (r.max_src_conn) {
+ yyerror("state option "
+ "'max-src-conn' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_conn == 0) {
+ yyerror("'max-src-conn' "
+ "must be > 0");
+ YYERROR;
+ }
+ r.max_src_conn =
+ o->data.max_src_conn;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN_RATE:
+ if (r.max_src_conn_rate.limit) {
+ yyerror("state option "
+ "'max-src-conn-rate' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (!o->data.max_src_conn_rate.limit ||
+ !o->data.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' "
+ "values must be > 0");
+ YYERROR;
+ }
+ if (o->data.max_src_conn_rate.limit >
+ PF_THRESHOLD_MAX) {
+ yyerror("'max-src-conn-rate' "
+ "maximum rate must be < %u",
+ PF_THRESHOLD_MAX);
+ YYERROR;
+ }
+ r.max_src_conn_rate.limit =
+ o->data.max_src_conn_rate.limit;
+ r.max_src_conn_rate.seconds =
+ o->data.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_NODES:
+ if (r.max_src_nodes) {
+ yyerror("state option "
+ "'max-src-nodes' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-nodes' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_nodes =
+ o->data.max_src_nodes;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
+ case PF_STATE_OPT_SLOPPY:
+ if (r.rule_flag & PFRULE_STATESLOPPY) {
+ yyerror("state sloppy option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_STATESLOPPY;
+ break;
+ case PF_STATE_OPT_TIMEOUT:
+ if (o->data.timeout.number ==
+ PFTM_ADAPTIVE_START ||
+ o->data.timeout.number ==
+ PFTM_ADAPTIVE_END)
+ adaptive = 1;
+ if (r.timeout[o->data.timeout.number]) {
+ yyerror("state timeout %s "
+ "multiple definitions",
+ pf_timeouts[o->data.
+ timeout.number].name);
+ YYERROR;
+ }
+ r.timeout[o->data.timeout.number] =
+ o->data.timeout.seconds;
+ }
+ o = o->next;
+ if (!defaults)
+ free(p);
+ }
+
+ /* 'flags S/SA' by default on stateful rules */
+ if (!r.action && !r.flags && !r.flagset &&
+ !yystack.l_mark[0].v.filter_opts.fragment && !(yystack.l_mark[0].v.filter_opts.marker & FOM_FLAGS) &&
+ r.keep_state) {
+ r.flags = parse_flags("S");
+ r.flagset = parse_flags("SA");
+ }
+ if (!adaptive && r.max_states) {
+ r.timeout[PFTM_ADAPTIVE_START] =
+ (r.max_states / 10) * 6;
+ r.timeout[PFTM_ADAPTIVE_END] =
+ (r.max_states / 10) * 12;
+ }
+ if (r.rule_flag & PFRULE_SRCTRACK) {
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_nodes) {
+ yyerror("'max-src-nodes' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn) {
+ yyerror("'max-src-conn' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (r.timeout[PFTM_SRC_NODE] <
+ r.max_src_conn_rate.seconds)
+ r.timeout[PFTM_SRC_NODE] =
+ r.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ if (srctrack == PF_SRCTRACK_RULE)
+ r.rule_flag |= PFRULE_RULESRCTRACK;
+ }
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
+
+ if (yystack.l_mark[0].v.filter_opts.fragment)
+ r.rule_flag |= PFRULE_FRAGMENT;
+ r.allow_opts = yystack.l_mark[0].v.filter_opts.allowopts;
+
+ decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af);
+ decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af);
+
+ if (yystack.l_mark[-4].v.route.rt) {
+ if (!r.direction) {
+ yyerror("direction must be explicit "
+ "with rules that specify routing");
+ YYERROR;
+ }
+ r.rt = yystack.l_mark[-4].v.route.rt;
+ r.rpool.opts = yystack.l_mark[-4].v.route.pool_opts;
+ if (yystack.l_mark[-4].v.route.key != NULL)
+ memcpy(&r.rpool.key, yystack.l_mark[-4].v.route.key,
+ sizeof(struct pf_poolhashkey));
+ }
+ if (r.rt && r.rt != PF_FASTROUTE) {
+ decide_address_family(yystack.l_mark[-4].v.route.host, &r.af);
+ remove_invalid_hosts(&yystack.l_mark[-4].v.route.host, &r.af);
+ if (yystack.l_mark[-4].v.route.host == NULL) {
+ yyerror("no routing address with "
+ "matching address family found.");
+ YYERROR;
+ }
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && (yystack.l_mark[-4].v.route.host->next != NULL ||
+ yystack.l_mark[-4].v.route.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR(yystack.l_mark[-4].v.route.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table(yystack.l_mark[-4].v.route.host, "tables are only "
+ "supported in round-robin routing pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias(yystack.l_mark[-4].v.route.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
+ if (yystack.l_mark[-4].v.route.host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("r.rpool.opts must "
+ "be PF_POOL_ROUNDROBIN");
+ YYERROR;
+ }
+ }
+ }
+ if (yystack.l_mark[0].v.filter_opts.queues.qname != NULL) {
+ if (strlcpy(r.qname, yystack.l_mark[0].v.filter_opts.queues.qname,
+ sizeof(r.qname)) >= sizeof(r.qname)) {
+ yyerror("rule qname too long (max "
+ "%d chars)", sizeof(r.qname)-1);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.filter_opts.queues.qname);
+ }
+ if (yystack.l_mark[0].v.filter_opts.queues.pqname != NULL) {
+ if (strlcpy(r.pqname, yystack.l_mark[0].v.filter_opts.queues.pqname,
+ sizeof(r.pqname)) >= sizeof(r.pqname)) {
+ yyerror("rule pqname too long (max "
+ "%d chars)", sizeof(r.pqname)-1);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.filter_opts.queues.pqname);
+ }
+#ifdef __FreeBSD__
+ r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port;
+#else
+ if ((r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port)) {
+ if (r.direction == PF_OUT) {
+ if (yystack.l_mark[0].v.filter_opts.divert.addr) {
+ yyerror("address specified "
+ "for outgoing divert");
+ YYERROR;
+ }
+ bzero(&r.divert.addr,
+ sizeof(r.divert.addr));
+ } else {
+ if (!yystack.l_mark[0].v.filter_opts.divert.addr) {
+ yyerror("no address specified "
+ "for incoming divert");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.filter_opts.divert.addr->af != r.af) {
+ yyerror("address family "
+ "mismatch for divert");
+ YYERROR;
+ }
+ r.divert.addr =
+ yystack.l_mark[0].v.filter_opts.divert.addr->addr.v.a.addr;
+ }
+ }
+#endif
+
+ expand_rule(&r, yystack.l_mark[-5].v.interface, yystack.l_mark[-4].v.route.host, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os,
+ yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port,
+ yystack.l_mark[0].v.filter_opts.uid, yystack.l_mark[0].v.filter_opts.gid, yystack.l_mark[0].v.filter_opts.icmpspec, "");
+ }
+break;
+case 174:
+#line 2435 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ }
+break;
+case 175:
+#line 2440 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 176:
+#line 2441 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ yyval.v.filter_opts = filter_opts;
+ }
+break;
+case 179:
+#line 2452 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.uid)
+ yystack.l_mark[0].v.uid->tail->next = filter_opts.uid;
+ filter_opts.uid = yystack.l_mark[0].v.uid;
+ }
+break;
+case 180:
+#line 2457 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.gid)
+ yystack.l_mark[0].v.gid->tail->next = filter_opts.gid;
+ filter_opts.gid = yystack.l_mark[0].v.gid;
+ }
+break;
+case 181:
+#line 2462 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_FLAGS) {
+ yyerror("flags cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_FLAGS;
+ filter_opts.flags.b1 |= yystack.l_mark[0].v.b.b1;
+ filter_opts.flags.b2 |= yystack.l_mark[0].v.b.b2;
+ filter_opts.flags.w |= yystack.l_mark[0].v.b.w;
+ filter_opts.flags.w2 |= yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 182:
+#line 2473 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_ICMP) {
+ yyerror("icmp-type cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_ICMP;
+ filter_opts.icmpspec = yystack.l_mark[0].v.icmp;
+ }
+break;
+case 183:
+#line 2481 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_PRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_PRIO;
+ filter_opts.prio = yystack.l_mark[0].v.number;
+ }
+break;
+case 184:
+#line 2493 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_TOS) {
+ yyerror("tos cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_TOS;
+ filter_opts.tos = yystack.l_mark[0].v.number;
+ }
+break;
+case 185:
+#line 2501 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_KEEP) {
+ yyerror("modulate or keep cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_KEEP;
+ filter_opts.keep.action = yystack.l_mark[0].v.keep_state.action;
+ filter_opts.keep.options = yystack.l_mark[0].v.keep_state.options;
+ }
+break;
+case 186:
+#line 2510 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.fragment = 1;
+ }
+break;
+case 187:
+#line 2513 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.allowopts = 1;
+ }
+break;
+case 188:
+#line 2516 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.label = yystack.l_mark[0].v.string;
+ }
+break;
+case 189:
+#line 2523 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.queues.qname) {
+ yyerror("queue cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.queues = yystack.l_mark[0].v.qassign;
+ }
+break;
+case 190:
+#line 2530 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.tag = yystack.l_mark[0].v.string;
+ }
+break;
+case 191:
+#line 2533 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ filter_opts.match_tag = yystack.l_mark[0].v.string;
+ filter_opts.match_tag_not = yystack.l_mark[-2].v.number;
+ }
+break;
+case 192:
+#line 2537 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ double p;
+
+ p = floor(yystack.l_mark[0].v.probability * UINT_MAX + 0.5);
+ if (p < 0.0 || p > UINT_MAX) {
+ yyerror("invalid probability: %lf", p);
+ YYERROR;
+ }
+ filter_opts.prob = (u_int32_t)p;
+ if (filter_opts.prob == 0)
+ filter_opts.prob = 1;
+ }
+break;
+case 193:
+#line 2549 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ filter_opts.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 194:
+#line 2556 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifdef __FreeBSD__
+ filter_opts.divert.port = yystack.l_mark[0].v.range.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a));
+ YYERROR;
+ }
+#endif
+ }
+break;
+case 195:
+#line 2565 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifndef __FreeBSD__
+ if ((filter_opts.divert.addr = host(yystack.l_mark[-2].v.string)) == NULL) {
+ yyerror("could not parse divert address: %s",
+ yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+#else
+ if (yystack.l_mark[-2].v.string)
+#endif
+ free(yystack.l_mark[-2].v.string);
+ filter_opts.divert.port = yystack.l_mark[0].v.range.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a));
+ YYERROR;
+ }
+ }
+break;
+case 196:
+#line 2583 "../../freebsd/sbin/pfctl/parse.y"
+ {
+#ifdef __FreeBSD__
+ yyerror("divert-reply has no meaning in FreeBSD pf(4)");
+ YYERROR;
+#else
+ filter_opts.divert.port = 1; /* some random value */
+#endif
+ }
+break;
+case 198:
+#line 2594 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 199:
+#line 2595 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.filter_opts = filter_opts; }
+break;
+case 202:
+#line 2602 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & FOM_SETPRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_SETPRIO;
+ filter_opts.set_prio[0] = yystack.l_mark[0].v.b.b1;
+ filter_opts.set_prio[1] = yystack.l_mark[0].v.b.b2;
+ }
+break;
+case 203:
+#line 2611 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ yyval.v.b.b1 = yyval.v.b.b2 = yystack.l_mark[0].v.number;
+ }
+break;
+case 204:
+#line 2618 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > PF_PRIO_MAX ||
+ yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ yyval.v.b.b1 = yystack.l_mark[-3].v.number;
+ yyval.v.b.b2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 205:
+#line 2629 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *e;
+ double p = strtod(yystack.l_mark[0].v.string, &e);
+
+ if (*e == '%') {
+ p *= 0.01;
+ e++;
+ }
+ if (*e) {
+ yyerror("invalid probability: %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.probability = p;
+ }
+break;
+case 206:
+#line 2645 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.probability = (double)yystack.l_mark[0].v.number;
+ }
+break;
+case 207:
+#line 2651 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = PF_PASS; yyval.v.b.b2 = yyval.v.b.w = 0; }
+break;
+case 208:
+#line 2652 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b = yystack.l_mark[0].v.b; yyval.v.b.b1 = PF_DROP; }
+break;
+case 209:
+#line 2655 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = blockpolicy;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 210:
+#line 2660 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_DROP;
+ yyval.v.b.w = 0;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 211:
+#line 2665 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNRST;
+ yyval.v.b.w = 0;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 212:
+#line 2670 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > 255) {
+ yyerror("illegal ttl value %d", yystack.l_mark[-1].v.number);
+ YYERROR;
+ }
+ yyval.v.b.b2 = PFRULE_RETURNRST;
+ yyval.v.b.w = yystack.l_mark[-1].v.number;
+ yyval.v.b.w2 = 0;
+ }
+break;
+case 213:
+#line 2679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 214:
+#line 2684 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 215:
+#line 2689 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = yystack.l_mark[-1].v.number;
+ yyval.v.b.w2 = returnicmpdefault;
+ }
+break;
+case 216:
+#line 2694 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 217:
+#line 2699 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURNICMP;
+ yyval.v.b.w = yystack.l_mark[-3].v.number;
+ yyval.v.b.w2 = yystack.l_mark[-1].v.number;
+ }
+break;
+case 218:
+#line 2704 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.b.b2 = PFRULE_RETURN;
+ yyval.v.b.w = returnicmpdefault;
+ yyval.v.b.w2 = returnicmp6default;
+ }
+break;
+case 219:
+#line 2711 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET))) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 220:
+#line 2718 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t icmptype;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ icmptype = returnicmpdefault >> 8;
+ yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number);
+ }
+break;
+case 221:
+#line 2730 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET6))) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 222:
+#line 2737 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t icmptype;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ icmptype = returnicmp6default >> 8;
+ yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number);
+ }
+break;
+case 223:
+#line 2749 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_INOUT; }
+break;
+case 224:
+#line 2750 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_IN; }
+break;
+case 225:
+#line 2751 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OUT; }
+break;
+case 226:
+#line 2754 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 0; }
+break;
+case 227:
+#line 2755 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 1; }
+break;
+case 228:
+#line 2758 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = 0; yyval.v.logquick.quick = 0; yyval.v.logquick.logif = 0; }
+break;
+case 229:
+#line 2759 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 0; }
+break;
+case 230:
+#line 2760 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.quick = 1; yyval.v.logquick.log = 0; yyval.v.logquick.logif = 0; }
+break;
+case 231:
+#line 2761 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[-1].v.logquick; yyval.v.logquick.quick = 1; }
+break;
+case 232:
+#line 2762 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 1; }
+break;
+case 233:
+#line 2765 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG; yyval.v.logquick.logif = 0; }
+break;
+case 234:
+#line 2766 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.logquick.log = PF_LOG | yystack.l_mark[-1].v.logquick.log;
+ yyval.v.logquick.logif = yystack.l_mark[-1].v.logquick.logif;
+ }
+break;
+case 235:
+#line 2772 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick = yystack.l_mark[0].v.logquick; }
+break;
+case 236:
+#line 2773 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.logquick.log = yystack.l_mark[-2].v.logquick.log | yystack.l_mark[0].v.logquick.log;
+ yyval.v.logquick.logif = yystack.l_mark[0].v.logquick.logif;
+ if (yyval.v.logquick.logif == 0)
+ yyval.v.logquick.logif = yystack.l_mark[-2].v.logquick.logif;
+ }
+break;
+case 237:
+#line 2781 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_ALL; yyval.v.logquick.logif = 0; }
+break;
+case 238:
+#line 2782 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; }
+break;
+case 239:
+#line 2783 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; }
+break;
+case 240:
+#line 2784 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const char *errstr;
+ u_int i;
+
+ yyval.v.logquick.log = 0;
+ if (strncmp(yystack.l_mark[0].v.string, "pflog", 5)) {
+ yyerror("%s: should be a pflog interface", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ i = strtonum(yystack.l_mark[0].v.string + 5, 0, 255, &errstr);
+ if (errstr) {
+ yyerror("%s: %s", yystack.l_mark[0].v.string, errstr);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.logquick.logif = i;
+ }
+break;
+case 241:
+#line 2805 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = NULL; }
+break;
+case 242:
+#line 2806 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; }
+break;
+case 243:
+#line 2807 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 244:
+#line 2810 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[-1].v.interface; }
+break;
+case 245:
+#line 2811 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface;
+ yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface;
+ yyval.v.interface = yystack.l_mark[-3].v.interface;
+ }
+break;
+case 246:
+#line 2818 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.interface = yystack.l_mark[0].v.interface; yyval.v.interface->not = yystack.l_mark[-1].v.number; }
+break;
+case 247:
+#line 2821 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ yyval.v.interface = calloc(1, sizeof(struct node_if));
+ if (yyval.v.interface == NULL)
+ err(1, "if_item: calloc");
+ if (strlcpy(yyval.v.interface->ifname, yystack.l_mark[0].v.string, sizeof(yyval.v.interface->ifname)) >=
+ sizeof(yyval.v.interface->ifname)) {
+ free(yystack.l_mark[0].v.string);
+ free(yyval.v.interface);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+
+ if ((n = ifa_exists(yystack.l_mark[0].v.string)) != NULL)
+ yyval.v.interface->ifa_flags = n->ifa_flags;
+
+ free(yystack.l_mark[0].v.string);
+ yyval.v.interface->not = 0;
+ yyval.v.interface->next = NULL;
+ yyval.v.interface->tail = yyval.v.interface;
+ }
+break;
+case 248:
+#line 2845 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 249:
+#line 2846 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = AF_INET; }
+break;
+case 250:
+#line 2847 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = AF_INET6; }
+break;
+case 251:
+#line 2850 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = NULL; }
+break;
+case 252:
+#line 2851 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[0].v.proto; }
+break;
+case 253:
+#line 2852 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[-1].v.proto; }
+break;
+case 254:
+#line 2855 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.proto = yystack.l_mark[-1].v.proto; }
+break;
+case 255:
+#line 2856 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.proto->tail->next = yystack.l_mark[-1].v.proto;
+ yystack.l_mark[-3].v.proto->tail = yystack.l_mark[-1].v.proto;
+ yyval.v.proto = yystack.l_mark[-3].v.proto;
+ }
+break;
+case 256:
+#line 2863 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_int8_t pr;
+
+ pr = (u_int8_t)yystack.l_mark[0].v.number;
+ if (pr == 0) {
+ yyerror("proto 0 cannot be used");
+ YYERROR;
+ }
+ yyval.v.proto = calloc(1, sizeof(struct node_proto));
+ if (yyval.v.proto == NULL)
+ err(1, "proto_item: calloc");
+ yyval.v.proto->proto = pr;
+ yyval.v.proto->next = NULL;
+ yyval.v.proto->tail = yyval.v.proto;
+ }
+break;
+case 257:
+#line 2880 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct protoent *p;
+
+ p = getprotobyname(yystack.l_mark[0].v.string);
+ if (p == NULL) {
+ yyerror("unknown protocol %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->p_proto;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 258:
+#line 2892 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("protocol outside range");
+ YYERROR;
+ }
+ }
+break;
+case 259:
+#line 2900 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fromto.src.host = NULL;
+ yyval.v.fromto.src.port = NULL;
+ yyval.v.fromto.dst.host = NULL;
+ yyval.v.fromto.dst.port = NULL;
+ yyval.v.fromto.src_os = NULL;
+ }
+break;
+case 260:
+#line 2907 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.fromto.src = yystack.l_mark[-2].v.peer;
+ yyval.v.fromto.src_os = yystack.l_mark[-1].v.os;
+ yyval.v.fromto.dst = yystack.l_mark[0].v.peer;
+ }
+break;
+case 261:
+#line 2914 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = NULL; }
+break;
+case 262:
+#line 2915 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[0].v.os; }
+break;
+case 263:
+#line 2916 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[-1].v.os; }
+break;
+case 264:
+#line 2919 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.os = calloc(1, sizeof(struct node_os));
+ if (yyval.v.os == NULL)
+ err(1, "os: calloc");
+ yyval.v.os->os = yystack.l_mark[0].v.string;
+ yyval.v.os->tail = yyval.v.os;
+ }
+break;
+case 265:
+#line 2928 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.os = yystack.l_mark[-1].v.os; }
+break;
+case 266:
+#line 2929 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.os->tail->next = yystack.l_mark[-1].v.os;
+ yystack.l_mark[-3].v.os->tail = yystack.l_mark[-1].v.os;
+ yyval.v.os = yystack.l_mark[-3].v.os;
+ }
+break;
+case 267:
+#line 2936 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 268:
+#line 2940 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer = yystack.l_mark[0].v.peer;
+ }
+break;
+case 269:
+#line 2945 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 270:
+#line 2949 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (disallow_urpf_failed(yystack.l_mark[0].v.peer.host, "\"urpf-failed\" is "
+ "not permitted in a destination address"))
+ YYERROR;
+ yyval.v.peer = yystack.l_mark[0].v.peer;
+ }
+break;
+case 271:
+#line 2957 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = yystack.l_mark[0].v.host;
+ yyval.v.peer.port = NULL;
+ }
+break;
+case 272:
+#line 2961 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = yystack.l_mark[-2].v.host;
+ yyval.v.peer.port = yystack.l_mark[0].v.port;
+ }
+break;
+case 273:
+#line 2965 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.peer.host = NULL;
+ yyval.v.peer.port = yystack.l_mark[0].v.port;
+ }
+break;
+case 276:
+#line 2975 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = NULL; }
+break;
+case 277:
+#line 2976 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 278:
+#line 2977 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 279:
+#line 2980 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 280:
+#line 2981 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = NULL; }
+break;
+case 281:
+#line 2984 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 282:
+#line 2985 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-1].v.host == NULL)
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ else if (yystack.l_mark[-3].v.host == NULL)
+ yyval.v.host = yystack.l_mark[-1].v.host;
+ else {
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+ }
+break;
+case 283:
+#line 2998 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ for (n = yystack.l_mark[0].v.host; n != NULL; n = n->next)
+ n->not = yystack.l_mark[-1].v.number;
+ yyval.v.host = yystack.l_mark[0].v.host;
+ }
+break;
+case 284:
+#line 3005 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "xhost: calloc");
+ yyval.v.host->addr.type = PF_ADDR_NOROUTE;
+ yyval.v.host->next = NULL;
+ yyval.v.host->not = yystack.l_mark[-1].v.number;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 285:
+#line 3014 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "xhost: calloc");
+ yyval.v.host->addr.type = PF_ADDR_URPFFAILED;
+ yyval.v.host->next = NULL;
+ yyval.v.host->not = yystack.l_mark[-1].v.number;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 286:
+#line 3025 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if ((yyval.v.host = host(yystack.l_mark[0].v.string)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(yystack.l_mark[0].v.string);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ }
+break;
+case 287:
+#line 3035 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *b, *e;
+
+ if ((b = host(yystack.l_mark[-2].v.string)) == NULL || (e = host(yystack.l_mark[0].v.string)) == NULL) {
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ if (b->af != e->af ||
+ b->addr.type != PF_ADDR_ADDRMASK ||
+ e->addr.type != PF_ADDR_ADDRMASK ||
+ unmask(&b->addr.v.a.mask, b->af) !=
+ (b->af == AF_INET ? 32 : 128) ||
+ unmask(&e->addr.v.a.mask, e->af) !=
+ (e->af == AF_INET ? 32 : 128) ||
+ b->next != NULL || b->not ||
+ e->next != NULL || e->not) {
+ free(b);
+ free(e);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ yyerror("invalid address range");
+ YYERROR;
+ }
+ memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
+ sizeof(b->addr.v.a.mask));
+ b->addr.type = PF_ADDR_RANGE;
+ yyval.v.host = b;
+ free(e);
+ free(yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 288:
+#line 3068 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *buf;
+
+ if (asprintf(&buf, "%s/%lld", yystack.l_mark[-2].v.string, (long long)yystack.l_mark[0].v.number) == -1)
+ err(1, "host: asprintf");
+ free(yystack.l_mark[-2].v.string);
+ if ((yyval.v.host = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+break;
+case 289:
+#line 3082 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ char *buf;
+
+ /* ie. for 10/8 parsing */
+#ifdef __FreeBSD__
+ if (asprintf(&buf, "%lld/%lld", (long long)yystack.l_mark[-2].v.number, (long long)yystack.l_mark[0].v.number) == -1)
+#else
+ if (asprintf(&buf, "%lld/%lld", yystack.l_mark[-2].v.number, yystack.l_mark[0].v.number) == -1)
+#endif
+ err(1, "host: asprintf");
+ if ((yyval.v.host = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+break;
+case 291:
+#line 3101 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct node_host *n;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 128) {
+ yyerror("bit number too big");
+ YYERROR;
+ }
+ yyval.v.host = yystack.l_mark[-2].v.host;
+ for (n = yystack.l_mark[-2].v.host; n != NULL; n = n->next)
+ set_ipmask(n, yystack.l_mark[0].v.number);
+ }
+break;
+case 292:
+#line 3112 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strlen(yystack.l_mark[-1].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "host: calloc");
+ yyval.v.host->addr.type = PF_ADDR_TABLE;
+ if (strlcpy(yyval.v.host->addr.v.tblname, yystack.l_mark[-1].v.string,
+ sizeof(yyval.v.host->addr.v.tblname)) >=
+ sizeof(yyval.v.host->addr.v.tblname))
+ errx(1, "host: strlcpy");
+ free(yystack.l_mark[-1].v.string);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 294:
+#line 3133 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ u_long ulval;
+
+ if (atoul(yystack.l_mark[0].v.string, &ulval) == -1) {
+ yyerror("%s is not a number", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ } else
+ yyval.v.number = ulval;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 295:
+#line 3146 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int flags = 0;
+ char *p, *op;
+
+ op = yystack.l_mark[-1].v.string;
+ if (!isalpha(op[0])) {
+ yyerror("invalid interface name '%s'", op);
+ free(op);
+ YYERROR;
+ }
+ while ((p = strrchr(yystack.l_mark[-1].v.string, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ yystack.l_mark[-1].v.string);
+ free(op);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ free(op);
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "address: calloc");
+ yyval.v.host->af = 0;
+ set_ipmask(yyval.v.host, 128);
+ yyval.v.host->addr.type = PF_ADDR_DYNIFTL;
+ yyval.v.host->addr.iflags = flags;
+ if (strlcpy(yyval.v.host->addr.v.ifname, yystack.l_mark[-1].v.string,
+ sizeof(yyval.v.host->addr.v.ifname)) >=
+ sizeof(yyval.v.host->addr.v.ifname)) {
+ free(op);
+ free(yyval.v.host);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ free(op);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 296:
+#line 3200 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[0].v.port; }
+break;
+case 297:
+#line 3201 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[-1].v.port; }
+break;
+case 298:
+#line 3204 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.port = yystack.l_mark[-1].v.port; }
+break;
+case 299:
+#line 3205 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.port->tail->next = yystack.l_mark[-1].v.port;
+ yystack.l_mark[-3].v.port->tail = yystack.l_mark[-1].v.port;
+ yyval.v.port = yystack.l_mark[-3].v.port;
+ }
+break;
+case 300:
+#line 3212 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.b;
+ if (yystack.l_mark[0].v.range.t)
+ yyval.v.port->op = PF_OP_RRG;
+ else
+ yyval.v.port->op = PF_OP_EQ;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 301:
+#line 3225 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.range.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.b;
+ yyval.v.port->op = yystack.l_mark[-1].v.i;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 302:
+#line 3240 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.range.t || yystack.l_mark[0].v.range.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ yyval.v.port = calloc(1, sizeof(struct node_port));
+ if (yyval.v.port == NULL)
+ err(1, "port_item: calloc");
+ yyval.v.port->port[0] = yystack.l_mark[-2].v.range.a;
+ yyval.v.port->port[1] = yystack.l_mark[0].v.range.a;
+ yyval.v.port->op = yystack.l_mark[-1].v.i;
+ yyval.v.port->next = NULL;
+ yyval.v.port->tail = yyval.v.port;
+ }
+break;
+case 303:
+#line 3257 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, 0) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 304:
+#line 3266 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 305:
+#line 3275 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[0].v.uid; }
+break;
+case 306:
+#line 3276 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[-1].v.uid; }
+break;
+case 307:
+#line 3279 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.uid = yystack.l_mark[-1].v.uid; }
+break;
+case 308:
+#line 3280 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.uid->tail->next = yystack.l_mark[-1].v.uid;
+ yystack.l_mark[-3].v.uid->tail = yystack.l_mark[-1].v.uid;
+ yyval.v.uid = yystack.l_mark[-3].v.uid;
+ }
+break;
+case 309:
+#line 3287 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[0].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = PF_OP_EQ;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 310:
+#line 3297 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == UID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[0].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = yystack.l_mark[-1].v.i;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 311:
+#line 3312 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number == UID_MAX || yystack.l_mark[0].v.number == UID_MAX) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.uid = calloc(1, sizeof(struct node_uid));
+ if (yyval.v.uid == NULL)
+ err(1, "uid_item: calloc");
+ yyval.v.uid->uid[0] = yystack.l_mark[-2].v.number;
+ yyval.v.uid->uid[1] = yystack.l_mark[0].v.number;
+ yyval.v.uid->op = yystack.l_mark[-1].v.i;
+ yyval.v.uid->next = NULL;
+ yyval.v.uid->tail = yyval.v.uid;
+ }
+break;
+case 312:
+#line 3329 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "unknown"))
+ yyval.v.number = UID_MAX;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam(yystack.l_mark[0].v.string)) == NULL) {
+ yyerror("unknown user %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = pw->pw_uid;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 313:
+#line 3344 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= UID_MAX) {
+ yyerror("illegal uid value %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number;
+ }
+break;
+case 314:
+#line 3353 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[0].v.gid; }
+break;
+case 315:
+#line 3354 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[-1].v.gid; }
+break;
+case 316:
+#line 3357 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.gid = yystack.l_mark[-1].v.gid; }
+break;
+case 317:
+#line 3358 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.gid->tail->next = yystack.l_mark[-1].v.gid;
+ yystack.l_mark[-3].v.gid->tail = yystack.l_mark[-1].v.gid;
+ yyval.v.gid = yystack.l_mark[-3].v.gid;
+ }
+break;
+case 318:
+#line 3365 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[0].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = PF_OP_EQ;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 319:
+#line 3375 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number == GID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[0].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = yystack.l_mark[-1].v.i;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 320:
+#line 3390 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number == GID_MAX || yystack.l_mark[0].v.number == GID_MAX) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ yyval.v.gid = calloc(1, sizeof(struct node_gid));
+ if (yyval.v.gid == NULL)
+ err(1, "gid_item: calloc");
+ yyval.v.gid->gid[0] = yystack.l_mark[-2].v.number;
+ yyval.v.gid->gid[1] = yystack.l_mark[0].v.number;
+ yyval.v.gid->op = yystack.l_mark[-1].v.i;
+ yyval.v.gid->next = NULL;
+ yyval.v.gid->tail = yyval.v.gid;
+ }
+break;
+case 321:
+#line 3407 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "unknown"))
+ yyval.v.number = GID_MAX;
+ else {
+ struct group *grp;
+
+ if ((grp = getgrnam(yystack.l_mark[0].v.string)) == NULL) {
+ yyerror("unknown group %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = grp->gr_gid;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 322:
+#line 3422 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= GID_MAX) {
+ yyerror("illegal gid value %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number;
+ }
+break;
+case 323:
+#line 3431 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int f;
+
+ if ((f = parse_flags(yystack.l_mark[0].v.string)) < 0) {
+ yyerror("bad flags %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ yyval.v.b.b1 = f;
+ }
+break;
+case 324:
+#line 3444 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = yystack.l_mark[-2].v.b.b1; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; }
+break;
+case 325:
+#line 3445 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; }
+break;
+case 326:
+#line 3446 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = 0; }
+break;
+case 327:
+#line 3449 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[0].v.icmp; }
+break;
+case 328:
+#line 3450 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 329:
+#line 3451 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[0].v.icmp; }
+break;
+case 330:
+#line 3452 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 331:
+#line 3455 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 332:
+#line 3456 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp;
+ yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp;
+ yyval.v.icmp = yystack.l_mark[-3].v.icmp;
+ }
+break;
+case 333:
+#line 3463 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.icmp = yystack.l_mark[-1].v.icmp; }
+break;
+case 334:
+#line 3464 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp;
+ yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp;
+ yyval.v.icmp = yystack.l_mark[-3].v.icmp;
+ }
+break;
+case 335:
+#line 3471 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[0].v.number;
+ yyval.v.icmp->code = 0;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 336:
+#line 3481 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET)) == NULL) {
+ yyerror("unknown icmp-code %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+
+ free(yystack.l_mark[0].v.string);
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = p->code + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 337:
+#line 3500 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = yystack.l_mark[0].v.number + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMP;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 338:
+#line 3516 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[0].v.number;
+ yyval.v.icmp->code = 0;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 339:
+#line 3526 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET6)) == NULL) {
+ yyerror("unknown icmp6-code %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = p->code + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 340:
+#line 3545 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.icmp = calloc(1, sizeof(struct node_icmp));
+ if (yyval.v.icmp == NULL)
+ err(1, "icmp_item: calloc");
+ yyval.v.icmp->type = yystack.l_mark[-2].v.number;
+ yyval.v.icmp->code = yystack.l_mark[0].v.number + 1;
+ yyval.v.icmp->proto = IPPROTO_ICMPV6;
+ yyval.v.icmp->next = NULL;
+ yyval.v.icmp->tail = yyval.v.icmp;
+ }
+break;
+case 341:
+#line 3561 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET)) == NULL) {
+ yyerror("unknown icmp-type %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->type + 1;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 342:
+#line 3572 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp-type %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number + 1;
+ }
+break;
+case 343:
+#line 3581 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET6)) ==
+ NULL) {
+ yyerror("unknown icmp6-type %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ yyval.v.number = p->type + 1;
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 344:
+#line 3593 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) {
+ yyerror("illegal icmp6-type %lu", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ yyval.v.number = yystack.l_mark[0].v.number + 1;
+ }
+break;
+case 345:
+#line 3602 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "lowdelay"))
+ yyval.v.number = IPTOS_LOWDELAY;
+ else if (!strcmp(yystack.l_mark[0].v.string, "throughput"))
+ yyval.v.number = IPTOS_THROUGHPUT;
+ else if (!strcmp(yystack.l_mark[0].v.string, "reliability"))
+ yyval.v.number = IPTOS_RELIABILITY;
+ else if (yystack.l_mark[0].v.string[0] == '0' && yystack.l_mark[0].v.string[1] == 'x')
+ yyval.v.number = strtoul(yystack.l_mark[0].v.string, NULL, 16);
+ else
+ yyval.v.number = 256; /* flag bad argument */
+ if (yyval.v.number < 0 || yyval.v.number > 255) {
+ yyerror("illegal tos value %s", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 346:
+#line 3620 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.number = yystack.l_mark[0].v.number;
+ if (yyval.v.number < 0 || yyval.v.number > 255) {
+ yyerror("illegal tos value %s", yystack.l_mark[0].v.number);
+ YYERROR;
+ }
+ }
+break;
+case 347:
+#line 3629 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK; }
+break;
+case 348:
+#line 3630 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK_GLOBAL; }
+break;
+case 349:
+#line 3631 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_SRCTRACK_RULE; }
+break;
+case 350:
+#line 3634 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = PFRULE_IFBOUND;
+ }
+break;
+case 351:
+#line 3637 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = 0;
+ }
+break;
+case 352:
+#line 3642 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = 0;
+ yyval.v.keep_state.options = NULL;
+ }
+break;
+case 353:
+#line 3646 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_NORMAL;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 354:
+#line 3650 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_MODULATE;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 355:
+#line 3654 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.keep_state.action = PF_STATE_SYNPROXY;
+ yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt;
+ }
+break;
+case 356:
+#line 3660 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 357:
+#line 3661 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_FLUSH; }
+break;
+case 358:
+#line 3662 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.i = PF_FLUSH | PF_FLUSH_GLOBAL;
+ }
+break;
+case 359:
+#line 3667 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = yystack.l_mark[-1].v.state_opt; }
+break;
+case 360:
+#line 3668 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = NULL; }
+break;
+case 361:
+#line 3671 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.state_opt = yystack.l_mark[0].v.state_opt; }
+break;
+case 362:
+#line 3672 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-2].v.state_opt->tail->next = yystack.l_mark[0].v.state_opt;
+ yystack.l_mark[-2].v.state_opt->tail = yystack.l_mark[0].v.state_opt;
+ yyval.v.state_opt = yystack.l_mark[-2].v.state_opt;
+ }
+break;
+case 363:
+#line 3679 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX;
+ yyval.v.state_opt->data.max_states = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 364:
+#line 3692 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_NOSYNC;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 365:
+#line 3700 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_STATES;
+ yyval.v.state_opt->data.max_src_states = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 366:
+#line 3713 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN;
+ yyval.v.state_opt->data.max_src_conn = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 367:
+#line 3726 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.number < 0 || yystack.l_mark[-2].v.number > UINT_MAX ||
+ yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
+ yyval.v.state_opt->data.max_src_conn_rate.limit = yystack.l_mark[-2].v.number;
+ yyval.v.state_opt->data.max_src_conn_rate.seconds = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 368:
+#line 3741 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", yystack.l_mark[-2].v.string);
+ free(yystack.l_mark[-2].v.string);
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ if (strlcpy(yyval.v.state_opt->data.overload.tblname, yystack.l_mark[-2].v.string,
+ PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
+ errx(1, "state_opt_item: strlcpy");
+ free(yystack.l_mark[-2].v.string);
+ yyval.v.state_opt->type = PF_STATE_OPT_OVERLOAD;
+ yyval.v.state_opt->data.overload.flush = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 369:
+#line 3759 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_NODES;
+ yyval.v.state_opt->data.max_src_nodes = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 370:
+#line 3772 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_SRCTRACK;
+ yyval.v.state_opt->data.src_track = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 371:
+#line 3781 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_STATELOCK;
+ yyval.v.state_opt->data.statelock = yystack.l_mark[0].v.i;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 372:
+#line 3790 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_SLOPPY;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 373:
+#line 3798 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ int i;
+
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ for (i = 0; pf_timeouts[i].name &&
+ strcmp(pf_timeouts[i].name, yystack.l_mark[-1].v.string); ++i)
+ ; /* nothing */
+ if (!pf_timeouts[i].name) {
+ yyerror("illegal timeout name %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (strchr(pf_timeouts[i].name, '.') == NULL) {
+ yyerror("illegal state timeout %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt));
+ if (yyval.v.state_opt == NULL)
+ err(1, "state_opt_item: calloc");
+ yyval.v.state_opt->type = PF_STATE_OPT_TIMEOUT;
+ yyval.v.state_opt->data.timeout.number = pf_timeouts[i].timeout;
+ yyval.v.state_opt->data.timeout.seconds = yystack.l_mark[0].v.number;
+ yyval.v.state_opt->next = NULL;
+ yyval.v.state_opt->tail = yyval.v.state_opt;
+ }
+break;
+case 374:
+#line 3830 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.string = yystack.l_mark[0].v.string;
+ }
+break;
+case 375:
+#line 3835 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[0].v.string;
+ yyval.v.qassign.pqname = NULL;
+ }
+break;
+case 376:
+#line 3839 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[-1].v.string;
+ yyval.v.qassign.pqname = NULL;
+ }
+break;
+case 377:
+#line 3843 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.qassign.qname = yystack.l_mark[-3].v.string;
+ yyval.v.qassign.pqname = yystack.l_mark[-1].v.string;
+ }
+break;
+case 378:
+#line 3849 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 0; }
+break;
+case 379:
+#line 3850 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = 1; }
+break;
+case 380:
+#line 3853 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE|PPORT_STAR) == -1) {
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 381:
+#line 3862 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 382:
+#line 3863 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 383:
+#line 3866 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 384:
+#line 3867 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+break;
+case 385:
+#line 3874 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.redirection = NULL; }
+break;
+case 386:
+#line 3875 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[0].v.host;
+ yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0;
+ }
+break;
+case 387:
+#line 3882 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[-2].v.host;
+ yyval.v.redirection->rport = yystack.l_mark[0].v.range;
+ }
+break;
+case 388:
+#line 3892 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+ yyval.v.hashkey->key32[0] = arc4random();
+ yyval.v.hashkey->key32[1] = arc4random();
+ yyval.v.hashkey->key32[2] = arc4random();
+ yyval.v.hashkey->key32[3] = arc4random();
+ }
+break;
+case 389:
+#line 3902 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strncmp(yystack.l_mark[0].v.string, "0x", 2)) {
+ if (strlen(yystack.l_mark[0].v.string) != 34) {
+ free(yystack.l_mark[0].v.string);
+ yyerror("hex key must be 128 bits "
+ "(32 hex digits) long");
+ YYERROR;
+ }
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+
+ if (sscanf(yystack.l_mark[0].v.string, "0x%8x%8x%8x%8x",
+ &yyval.v.hashkey->key32[0], &yyval.v.hashkey->key32[1],
+ &yyval.v.hashkey->key32[2], &yyval.v.hashkey->key32[3]) != 4) {
+ free(yyval.v.hashkey);
+ free(yystack.l_mark[0].v.string);
+ yyerror("invalid hex key");
+ YYERROR;
+ }
+ } else {
+ MD5_CTX context;
+
+ yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey));
+ if (yyval.v.hashkey == NULL)
+ err(1, "hashkey: calloc");
+ MD5Init(&context);
+ MD5Update(&context, (unsigned char *)yystack.l_mark[0].v.string,
+ strlen(yystack.l_mark[0].v.string));
+ MD5Final((unsigned char *)yyval.v.hashkey, &context);
+ HTONL(yyval.v.hashkey->key32[0]);
+ HTONL(yyval.v.hashkey->key32[1]);
+ HTONL(yyval.v.hashkey->key32[2]);
+ HTONL(yyval.v.hashkey->key32[3]);
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 390:
+#line 3941 "../../freebsd/sbin/pfctl/parse.y"
+ { bzero(&pool_opts, sizeof pool_opts); }
+break;
+case 391:
+#line 3943 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.pool_opts = pool_opts; }
+break;
+case 392:
+#line 3944 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ bzero(&pool_opts, sizeof pool_opts);
+ yyval.v.pool_opts = pool_opts;
+ }
+break;
+case 395:
+#line 3954 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_BITMASK;
+ }
+break;
+case 396:
+#line 3961 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_RANDOM;
+ }
+break;
+case 397:
+#line 3968 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_SRCHASH;
+ pool_opts.key = yystack.l_mark[0].v.hashkey;
+ }
+break;
+case 398:
+#line 3976 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_ROUNDROBIN;
+ }
+break;
+case 399:
+#line 3983 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (pool_opts.staticport) {
+ yyerror("static-port cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.staticport = 1;
+ }
+break;
+case 400:
+#line 3990 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (filter_opts.marker & POM_STICKYADDRESS) {
+ yyerror("sticky-address cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_STICKYADDRESS;
+ pool_opts.opts |= PF_POOL_STICKYADDR;
+ }
+break;
+case 401:
+#line 4000 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.redirection = NULL; }
+break;
+case 402:
+#line 4001 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[0].v.host;
+ yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0;
+ }
+break;
+case 403:
+#line 4008 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.redirection = calloc(1, sizeof(struct redirection));
+ if (yyval.v.redirection == NULL)
+ err(1, "redirection: calloc");
+ yyval.v.redirection->host = yystack.l_mark[-2].v.host;
+ yyval.v.redirection->rport = yystack.l_mark[0].v.range;
+ }
+break;
+case 404:
+#line 4017 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; }
+break;
+case 405:
+#line 4018 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 1; yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; }
+break;
+case 406:
+#line 4019 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 1; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; }
+break;
+case 407:
+#line 4020 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; }
+break;
+case 408:
+#line 4023 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.i)
+ yyval.v.b.b1 = PF_NONAT;
+ else
+ yyval.v.b.b1 = PF_NAT;
+ yyval.v.b.b2 = yystack.l_mark[0].v.b.b1;
+ yyval.v.b.w = yystack.l_mark[0].v.b.b2;
+ yyval.v.b.w2 = yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 409:
+#line 4036 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.i)
+ yyval.v.b.b1 = PF_NORDR;
+ else
+ yyval.v.b.b1 = PF_RDR;
+ yyval.v.b.b2 = yystack.l_mark[0].v.b.b1;
+ yyval.v.b.w = yystack.l_mark[0].v.b.b2;
+ yyval.v.b.w2 = yystack.l_mark[0].v.b.w2;
+ }
+break;
+case 410:
+#line 4053 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = yystack.l_mark[-9].v.b.b1;
+ r.natpass = yystack.l_mark[-9].v.b.b2;
+ r.log = yystack.l_mark[-9].v.b.w;
+ r.logif = yystack.l_mark[-9].v.b.w2;
+ r.af = yystack.l_mark[-7].v.i;
+
+ if (!r.af) {
+ if (yystack.l_mark[-5].v.fromto.src.host && yystack.l_mark[-5].v.fromto.src.host->af &&
+ !yystack.l_mark[-5].v.fromto.src.host->ifindex)
+ r.af = yystack.l_mark[-5].v.fromto.src.host->af;
+ else if (yystack.l_mark[-5].v.fromto.dst.host && yystack.l_mark[-5].v.fromto.dst.host->af &&
+ !yystack.l_mark[-5].v.fromto.dst.host->ifindex)
+ r.af = yystack.l_mark[-5].v.fromto.dst.host->af;
+ }
+
+ if (yystack.l_mark[-4].v.string != NULL)
+ if (strlcpy(r.tagname, yystack.l_mark[-4].v.string, PF_TAG_NAME_SIZE) >=
+ PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-3].v.tagged.name)
+ if (strlcpy(r.match_tagname, yystack.l_mark[-3].v.tagged.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = yystack.l_mark[-3].v.tagged.neg;
+ r.rtableid = yystack.l_mark[-2].v.rtableid;
+
+ if (r.action == PF_NONAT || r.action == PF_NORDR) {
+ if (yystack.l_mark[-1].v.redirection != NULL) {
+ yyerror("translation rule with 'no' "
+ "does not need '->'");
+ YYERROR;
+ }
+ } else {
+ if (yystack.l_mark[-1].v.redirection == NULL || yystack.l_mark[-1].v.redirection->host == NULL) {
+ yyerror("translation rule requires '-> "
+ "address'");
+ YYERROR;
+ }
+ if (!r.af && ! yystack.l_mark[-1].v.redirection->host->ifindex)
+ r.af = yystack.l_mark[-1].v.redirection->host->af;
+
+ remove_invalid_hosts(&yystack.l_mark[-1].v.redirection->host, &r.af);
+ if (invalid_redirect(yystack.l_mark[-1].v.redirection->host, r.af))
+ YYERROR;
+ if (check_netmask(yystack.l_mark[-1].v.redirection->host, r.af))
+ YYERROR;
+
+ r.rpool.proxy_port[0] = ntohs(yystack.l_mark[-1].v.redirection->rport.a);
+
+ switch (r.action) {
+ case PF_RDR:
+ if (!yystack.l_mark[-1].v.redirection->rport.b && yystack.l_mark[-1].v.redirection->rport.t &&
+ yystack.l_mark[-5].v.fromto.dst.port != NULL) {
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.a) +
+ (ntohs(
+ yystack.l_mark[-5].v.fromto.dst.port->port[1]) -
+ ntohs(
+ yystack.l_mark[-5].v.fromto.dst.port->port[0]));
+ } else
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.b);
+ break;
+ case PF_NAT:
+ r.rpool.proxy_port[1] =
+ ntohs(yystack.l_mark[-1].v.redirection->rport.b);
+ if (!r.rpool.proxy_port[0] &&
+ !r.rpool.proxy_port[1]) {
+ r.rpool.proxy_port[0] =
+ PF_NAT_PROXY_PORT_LOW;
+ r.rpool.proxy_port[1] =
+ PF_NAT_PROXY_PORT_HIGH;
+ } else if (!r.rpool.proxy_port[1])
+ r.rpool.proxy_port[1] =
+ r.rpool.proxy_port[0];
+ break;
+ default:
+ break;
+ }
+
+ r.rpool.opts = yystack.l_mark[0].v.pool_opts.type;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && (yystack.l_mark[-1].v.redirection->host->next != NULL ||
+ yystack.l_mark[-1].v.redirection->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR(yystack.l_mark[-1].v.redirection->host->addr)))
+ r.rpool.opts = PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table(yystack.l_mark[-1].v.redirection->host, "tables are only "
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias(yystack.l_mark[-1].v.redirection->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
+ if (yystack.l_mark[-1].v.redirection->host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("only round-robin "
+ "valid for multiple "
+ "redirection addresses");
+ YYERROR;
+ }
+ }
+ }
+
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ memcpy(&r.rpool.key, yystack.l_mark[0].v.pool_opts.key,
+ sizeof(struct pf_poolhashkey));
+
+ if (yystack.l_mark[0].v.pool_opts.opts)
+ r.rpool.opts |= yystack.l_mark[0].v.pool_opts.opts;
+
+ if (yystack.l_mark[0].v.pool_opts.staticport) {
+ if (r.action != PF_NAT) {
+ yyerror("the 'static-port' option is "
+ "only valid with nat rules");
+ YYERROR;
+ }
+ if (r.rpool.proxy_port[0] !=
+ PF_NAT_PROXY_PORT_LOW &&
+ r.rpool.proxy_port[1] !=
+ PF_NAT_PROXY_PORT_HIGH) {
+ yyerror("the 'static-port' option can't"
+ " be used when specifying a port"
+ " range");
+ YYERROR;
+ }
+ r.rpool.proxy_port[0] = 0;
+ r.rpool.proxy_port[1] = 0;
+ }
+
+ expand_rule(&r, yystack.l_mark[-8].v.interface, yystack.l_mark[-1].v.redirection == NULL ? NULL : yystack.l_mark[-1].v.redirection->host, yystack.l_mark[-6].v.proto,
+ yystack.l_mark[-5].v.fromto.src_os, yystack.l_mark[-5].v.fromto.src.host, yystack.l_mark[-5].v.fromto.src.port, yystack.l_mark[-5].v.fromto.dst.host,
+ yystack.l_mark[-5].v.fromto.dst.port, 0, 0, 0, "");
+ free(yystack.l_mark[-1].v.redirection);
+ }
+break;
+case 411:
+#line 4212 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ struct pf_rule binat;
+ struct pf_pooladdr *pa;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+ if (disallow_urpf_failed(yystack.l_mark[-4].v.host, "\"urpf-failed\" is not "
+ "permitted as a binat destination"))
+ YYERROR;
+
+ memset(&binat, 0, sizeof(binat));
+
+ if (yystack.l_mark[-12].v.i && yystack.l_mark[-10].v.b.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if (yystack.l_mark[-12].v.i)
+ binat.action = PF_NOBINAT;
+ else
+ binat.action = PF_BINAT;
+ binat.natpass = yystack.l_mark[-10].v.b.b1;
+ binat.log = yystack.l_mark[-10].v.b.b2;
+ binat.logif = yystack.l_mark[-10].v.b.w2;
+ binat.af = yystack.l_mark[-8].v.i;
+ if (!binat.af && yystack.l_mark[-5].v.host != NULL && yystack.l_mark[-5].v.host->af)
+ binat.af = yystack.l_mark[-5].v.host->af;
+ if (!binat.af && yystack.l_mark[-4].v.host != NULL && yystack.l_mark[-4].v.host->af)
+ binat.af = yystack.l_mark[-4].v.host->af;
+
+ if (!binat.af && yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host)
+ binat.af = yystack.l_mark[0].v.redirection->host->af;
+ if (!binat.af) {
+ yyerror("address family (inet/inet6) "
+ "undefined");
+ YYERROR;
+ }
+
+ if (yystack.l_mark[-9].v.interface != NULL) {
+ memcpy(binat.ifname, yystack.l_mark[-9].v.interface->ifname,
+ sizeof(binat.ifname));
+ binat.ifnot = yystack.l_mark[-9].v.interface->not;
+ free(yystack.l_mark[-9].v.interface);
+ }
+
+ if (yystack.l_mark[-3].v.string != NULL)
+ if (strlcpy(binat.tagname, yystack.l_mark[-3].v.string,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if (yystack.l_mark[-2].v.tagged.name)
+ if (strlcpy(binat.match_tagname, yystack.l_mark[-2].v.tagged.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ binat.match_tag_not = yystack.l_mark[-2].v.tagged.neg;
+ binat.rtableid = yystack.l_mark[-1].v.rtableid;
+
+ if (yystack.l_mark[-7].v.proto != NULL) {
+ binat.proto = yystack.l_mark[-7].v.proto->proto;
+ free(yystack.l_mark[-7].v.proto);
+ }
+
+ if (yystack.l_mark[-5].v.host != NULL && disallow_table(yystack.l_mark[-5].v.host, "invalid use of "
+ "table <%s> as the source address of a binat rule"))
+ YYERROR;
+ if (yystack.l_mark[-5].v.host != NULL && disallow_alias(yystack.l_mark[-5].v.host, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_table(
+ yystack.l_mark[0].v.redirection->host, "invalid use of table <%s> as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_alias(
+ yystack.l_mark[0].v.redirection->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+
+ if (yystack.l_mark[-5].v.host != NULL) {
+ if (yystack.l_mark[-5].v.host->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if (yystack.l_mark[-5].v.host->addr.type == PF_ADDR_DYNIFTL)
+ yystack.l_mark[-5].v.host->af = binat.af;
+ if (yystack.l_mark[-5].v.host->af != binat.af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[-5].v.host, binat.af))
+ YYERROR;
+ memcpy(&binat.src.addr, &yystack.l_mark[-5].v.host->addr,
+ sizeof(binat.src.addr));
+ free(yystack.l_mark[-5].v.host);
+ }
+ if (yystack.l_mark[-4].v.host != NULL) {
+ if (yystack.l_mark[-4].v.host->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if (yystack.l_mark[-4].v.host->af != binat.af && yystack.l_mark[-4].v.host->af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[-4].v.host, binat.af))
+ YYERROR;
+ memcpy(&binat.dst.addr, &yystack.l_mark[-4].v.host->addr,
+ sizeof(binat.dst.addr));
+ binat.dst.neg = yystack.l_mark[-4].v.host->not;
+ free(yystack.l_mark[-4].v.host);
+ }
+
+ if (binat.action == PF_NOBINAT) {
+ if (yystack.l_mark[0].v.redirection != NULL) {
+ yyerror("'no binat' rule does not need"
+ " '->'");
+ YYERROR;
+ }
+ } else {
+ if (yystack.l_mark[0].v.redirection == NULL || yystack.l_mark[0].v.redirection->host == NULL) {
+ yyerror("'binat' rule requires"
+ " '-> address'");
+ YYERROR;
+ }
+
+ remove_invalid_hosts(&yystack.l_mark[0].v.redirection->host, &binat.af);
+ if (invalid_redirect(yystack.l_mark[0].v.redirection->host, binat.af))
+ YYERROR;
+ if (yystack.l_mark[0].v.redirection->host->next != NULL) {
+ yyerror("binat rule must redirect to "
+ "a single address");
+ YYERROR;
+ }
+ if (check_netmask(yystack.l_mark[0].v.redirection->host, binat.af))
+ YYERROR;
+
+ if (!PF_AZERO(&binat.src.addr.v.a.mask,
+ binat.af) &&
+ !PF_AEQ(&binat.src.addr.v.a.mask,
+ &yystack.l_mark[0].v.redirection->host->addr.v.a.mask, binat.af)) {
+ yyerror("'binat' source mask and "
+ "redirect mask must be the same");
+ YYERROR;
+ }
+
+ TAILQ_INIT(&binat.rpool.list);
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "binat: calloc");
+ pa->addr = yystack.l_mark[0].v.redirection->host->addr;
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&binat.rpool.list,
+ pa, entries);
+
+ free(yystack.l_mark[0].v.redirection);
+ }
+
+ pfctl_add_rule(pf, &binat, "");
+ }
+break;
+case 412:
+#line 4377 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = NULL; }
+break;
+case 413:
+#line 4378 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.string = yystack.l_mark[0].v.string; }
+break;
+case 414:
+#line 4381 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.tagged.neg = 0; yyval.v.tagged.name = NULL; }
+break;
+case 415:
+#line 4382 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.tagged.neg = yystack.l_mark[-2].v.number; yyval.v.tagged.name = yystack.l_mark[0].v.string; }
+break;
+case 416:
+#line 4385 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.rtableid = -1; }
+break;
+case 417:
+#line 4386 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ yyval.v.rtableid = yystack.l_mark[0].v.number;
+ }
+break;
+case 418:
+#line 4395 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = calloc(1, sizeof(struct node_host));
+ if (yyval.v.host == NULL)
+ err(1, "route_host: calloc");
+ yyval.v.host->ifname = yystack.l_mark[0].v.string;
+ set_ipmask(yyval.v.host, 128);
+ yyval.v.host->next = NULL;
+ yyval.v.host->tail = yyval.v.host;
+ }
+break;
+case 419:
+#line 4404 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.host = yystack.l_mark[-1].v.host;
+ yyval.v.host->ifname = yystack.l_mark[-2].v.string;
+ }
+break;
+case 420:
+#line 4410 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 421:
+#line 4411 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (yystack.l_mark[-3].v.host->af == 0)
+ yystack.l_mark[-3].v.host->af = yystack.l_mark[-1].v.host->af;
+ if (yystack.l_mark[-3].v.host->af != yystack.l_mark[-1].v.host->af) {
+ yyerror("all pool addresses must be in the "
+ "same address family");
+ YYERROR;
+ }
+ yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host;
+ yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail;
+ yyval.v.host = yystack.l_mark[-3].v.host;
+ }
+break;
+case 422:
+#line 4425 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[0].v.host; }
+break;
+case 423:
+#line 4426 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.host = yystack.l_mark[-1].v.host; }
+break;
+case 424:
+#line 4429 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = NULL;
+ yyval.v.route.rt = 0;
+ yyval.v.route.pool_opts = 0;
+ }
+break;
+case 425:
+#line 4434 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = NULL;
+ yyval.v.route.rt = PF_FASTROUTE;
+ yyval.v.route.pool_opts = 0;
+ }
+break;
+case 426:
+#line 4439 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_ROUTETO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 427:
+#line 4446 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_REPLYTO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 428:
+#line 4453 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ yyval.v.route.host = yystack.l_mark[-1].v.host;
+ yyval.v.route.rt = PF_DUPTO;
+ yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts;
+ if (yystack.l_mark[0].v.pool_opts.key != NULL)
+ yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key;
+ }
+break;
+case 429:
+#line 4463 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number, 0) != 0) {
+ yyerror("unknown timeout %s", yystack.l_mark[-1].v.string);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ }
+break;
+case 430:
+#line 4479 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, "interval", yystack.l_mark[0].v.number, 0) != 0)
+ YYERROR;
+ }
+break;
+case 433:
+#line 4496 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_limit(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number) != 0) {
+ yyerror("unable to set limit %s %u", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number);
+ free(yystack.l_mark[-1].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[-1].v.string);
+ }
+break;
+case 438:
+#line 4522 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.number = 0; }
+break;
+case 439:
+#line 4523 "../../freebsd/sbin/pfctl/parse.y"
+ {
+ if (!strcmp(yystack.l_mark[0].v.string, "yes"))
+ yyval.v.number = 1;
+ else {
+ yyerror("invalid value '%s', expected 'yes' "
+ "or 'no'", yystack.l_mark[0].v.string);
+ free(yystack.l_mark[0].v.string);
+ YYERROR;
+ }
+ free(yystack.l_mark[0].v.string);
+ }
+break;
+case 440:
+#line 4536 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_EQ; }
+break;
+case 441:
+#line 4537 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_NE; }
+break;
+case 442:
+#line 4538 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_LE; }
+break;
+case 443:
+#line 4539 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_LT; }
+break;
+case 444:
+#line 4540 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_GE; }
+break;
+case 445:
+#line 4541 "../../freebsd/sbin/pfctl/parse.y"
+ { yyval.v.i = PF_OP_GT; }
+break;
+#line 9257 "pfctly.tab.c"
+ }
+ yystack.s_mark -= yym;
+ yystate = *yystack.s_mark;
+ yystack.l_mark -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yystack.s_mark = YYFINAL;
+ *++yystack.l_mark = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = YYLEX) < 0) yychar = YYEOF;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = yyname[YYTRANSLATE(yychar)];
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == YYEOF) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yystack.s_mark, yystate);
+#endif
+ if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM)
+ {
+ goto yyoverflow;
+ }
+ *++yystack.s_mark = (YYINT) yystate;
+ *++yystack.l_mark = yyval;
+ goto yyloop;
+
+yyoverflow:
+ YYERROR_CALL("yacc stack overflow");
+
+yyabort:
+ yyfreestack(&yystack);
+ return (1);
+
+yyaccept:
+ yyfreestack(&yystack);
+ return (0);
+}
diff --git a/freebsd/sbin/pfctl/parse.h b/freebsd/sbin/pfctl/parse.h
new file mode 100644
index 00000000..929f9956
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.h
@@ -0,0 +1,337 @@
+/* A Bison parser, made by GNU Bison 2.7. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_PFCTLY_PFCTLY_TAB_H_INCLUDED
+# define YY_PFCTLY_PFCTLY_TAB_H_INCLUDED
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int pfctlydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ PASS = 258,
+ BLOCK = 259,
+ SCRUB = 260,
+ RETURN = 261,
+ IN = 262,
+ OS = 263,
+ OUT = 264,
+ LOG = 265,
+ QUICK = 266,
+ ON = 267,
+ FROM = 268,
+ TO = 269,
+ FLAGS = 270,
+ RETURNRST = 271,
+ RETURNICMP = 272,
+ RETURNICMP6 = 273,
+ PROTO = 274,
+ INET = 275,
+ INET6 = 276,
+ ALL = 277,
+ ANY = 278,
+ ICMPTYPE = 279,
+ ICMP6TYPE = 280,
+ CODE = 281,
+ KEEP = 282,
+ MODULATE = 283,
+ STATE = 284,
+ PORT = 285,
+ RDR = 286,
+ NAT = 287,
+ BINAT = 288,
+ ARROW = 289,
+ NODF = 290,
+ MINTTL = 291,
+ ERROR = 292,
+ ALLOWOPTS = 293,
+ FASTROUTE = 294,
+ FILENAME = 295,
+ ROUTETO = 296,
+ DUPTO = 297,
+ REPLYTO = 298,
+ NO = 299,
+ LABEL = 300,
+ NOROUTE = 301,
+ URPFFAILED = 302,
+ FRAGMENT = 303,
+ USER = 304,
+ GROUP = 305,
+ MAXMSS = 306,
+ MAXIMUM = 307,
+ TTL = 308,
+ TOS = 309,
+ DROP = 310,
+ TABLE = 311,
+ REASSEMBLE = 312,
+ FRAGDROP = 313,
+ FRAGCROP = 314,
+ ANCHOR = 315,
+ NATANCHOR = 316,
+ RDRANCHOR = 317,
+ BINATANCHOR = 318,
+ SET = 319,
+ OPTIMIZATION = 320,
+ TIMEOUT = 321,
+ LIMIT = 322,
+ LOGINTERFACE = 323,
+ BLOCKPOLICY = 324,
+ RANDOMID = 325,
+ REQUIREORDER = 326,
+ SYNPROXY = 327,
+ FINGERPRINTS = 328,
+ NOSYNC = 329,
+ DEBUG = 330,
+ SKIP = 331,
+ HOSTID = 332,
+ ANTISPOOF = 333,
+ FOR = 334,
+ INCLUDE = 335,
+ BITMASK = 336,
+ RANDOM = 337,
+ SOURCEHASH = 338,
+ ROUNDROBIN = 339,
+ STATICPORT = 340,
+ PROBABILITY = 341,
+ ALTQ = 342,
+ CBQ = 343,
+ CODEL = 344,
+ PRIQ = 345,
+ HFSC = 346,
+ FAIRQ = 347,
+ BANDWIDTH = 348,
+ TBRSIZE = 349,
+ LINKSHARE = 350,
+ REALTIME = 351,
+ UPPERLIMIT = 352,
+ QUEUE = 353,
+ PRIORITY = 354,
+ QLIMIT = 355,
+ HOGS = 356,
+ BUCKETS = 357,
+ RTABLE = 358,
+ TARGET = 359,
+ INTERVAL = 360,
+ LOAD = 361,
+ RULESET_OPTIMIZATION = 362,
+ PRIO = 363,
+ STICKYADDRESS = 364,
+ MAXSRCSTATES = 365,
+ MAXSRCNODES = 366,
+ SOURCETRACK = 367,
+ GLOBAL = 368,
+ RULE = 369,
+ MAXSRCCONN = 370,
+ MAXSRCCONNRATE = 371,
+ OVERLOAD = 372,
+ FLUSH = 373,
+ SLOPPY = 374,
+ TAGGED = 375,
+ TAG = 376,
+ IFBOUND = 377,
+ FLOATING = 378,
+ STATEPOLICY = 379,
+ STATEDEFAULTS = 380,
+ ROUTE = 381,
+ SETTOS = 382,
+ DIVERTTO = 383,
+ DIVERTREPLY = 384,
+ STRING = 385,
+ NUMBER = 386,
+ PORTBINARY = 387
+ };
+#endif
+/* Tokens. */
+#define PASS 258
+#define BLOCK 259
+#define SCRUB 260
+#define RETURN 261
+#define IN 262
+#define OS 263
+#define OUT 264
+#define LOG 265
+#define QUICK 266
+#define ON 267
+#define FROM 268
+#define TO 269
+#define FLAGS 270
+#define RETURNRST 271
+#define RETURNICMP 272
+#define RETURNICMP6 273
+#define PROTO 274
+#define INET 275
+#define INET6 276
+#define ALL 277
+#define ANY 278
+#define ICMPTYPE 279
+#define ICMP6TYPE 280
+#define CODE 281
+#define KEEP 282
+#define MODULATE 283
+#define STATE 284
+#define PORT 285
+#define RDR 286
+#define NAT 287
+#define BINAT 288
+#define ARROW 289
+#define NODF 290
+#define MINTTL 291
+#define ERROR 292
+#define ALLOWOPTS 293
+#define FASTROUTE 294
+#define FILENAME 295
+#define ROUTETO 296
+#define DUPTO 297
+#define REPLYTO 298
+#define NO 299
+#define LABEL 300
+#define NOROUTE 301
+#define URPFFAILED 302
+#define FRAGMENT 303
+#define USER 304
+#define GROUP 305
+#define MAXMSS 306
+#define MAXIMUM 307
+#define TTL 308
+#define TOS 309
+#define DROP 310
+#define TABLE 311
+#define REASSEMBLE 312
+#define FRAGDROP 313
+#define FRAGCROP 314
+#define ANCHOR 315
+#define NATANCHOR 316
+#define RDRANCHOR 317
+#define BINATANCHOR 318
+#define SET 319
+#define OPTIMIZATION 320
+#define TIMEOUT 321
+#define LIMIT 322
+#define LOGINTERFACE 323
+#define BLOCKPOLICY 324
+#define RANDOMID 325
+#define REQUIREORDER 326
+#define SYNPROXY 327
+#define FINGERPRINTS 328
+#define NOSYNC 329
+#define DEBUG 330
+#define SKIP 331
+#define HOSTID 332
+#define ANTISPOOF 333
+#define FOR 334
+#define INCLUDE 335
+#define BITMASK 336
+#define RANDOM 337
+#define SOURCEHASH 338
+#define ROUNDROBIN 339
+#define STATICPORT 340
+#define PROBABILITY 341
+#define ALTQ 342
+#define CBQ 343
+#define CODEL 344
+#define PRIQ 345
+#define HFSC 346
+#define FAIRQ 347
+#define BANDWIDTH 348
+#define TBRSIZE 349
+#define LINKSHARE 350
+#define REALTIME 351
+#define UPPERLIMIT 352
+#define QUEUE 353
+#define PRIORITY 354
+#define QLIMIT 355
+#define HOGS 356
+#define BUCKETS 357
+#define RTABLE 358
+#define TARGET 359
+#define INTERVAL 360
+#define LOAD 361
+#define RULESET_OPTIMIZATION 362
+#define PRIO 363
+#define STICKYADDRESS 364
+#define MAXSRCSTATES 365
+#define MAXSRCNODES 366
+#define SOURCETRACK 367
+#define GLOBAL 368
+#define RULE 369
+#define MAXSRCCONN 370
+#define MAXSRCCONNRATE 371
+#define OVERLOAD 372
+#define FLUSH 373
+#define SLOPPY 374
+#define TAGGED 375
+#define TAG 376
+#define IFBOUND 377
+#define FLOATING 378
+#define STATEPOLICY 379
+#define STATEDEFAULTS 380
+#define ROUTE 381
+#define SETTOS 382
+#define DIVERTTO 383
+#define DIVERTREPLY 384
+#define STRING 385
+#define NUMBER 386
+#define PORTBINARY 387
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE pfctlylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int pfctlyparse (void *YYPARSE_PARAM);
+#else
+int pfctlyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int pfctlyparse (void);
+#else
+int pfctlyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_PFCTLY_PFCTLY_TAB_H_INCLUDED */
diff --git a/freebsd/sbin/pfctl/parse.y b/freebsd/sbin/pfctl/parse.y
new file mode 100644
index 00000000..33edd3e5
--- /dev/null
+++ b/freebsd/sbin/pfctl/parse.y
@@ -0,0 +1,6290 @@
+/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */
+
+/*
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
+ * Copyright (c) 2001 Theo de Raadt. All rights reserved.
+ * Copyright (c) 2002,2003 Henning Brauer. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+%{
+#ifdef __rtems__
+#include <machine/rtems-bsd-user-space.h>
+#endif /* __rtems__ */
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#define pf_anchor_setup _bsd_pf_anchor_setup
+#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <err.h>
+#include <limits.h>
+#include <pwd.h>
+#include <grp.h>
+#include <md5.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-parse-data.h"
+#endif /* __rtems__ */
+
+static struct pfctl *pf = NULL;
+static int debug = 0;
+static int rulestate = 0;
+static u_int16_t returnicmpdefault =
+ (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+static u_int16_t returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+static int blockpolicy = PFRULE_DROP;
+static int require_order = 1;
+static int default_statelock;
+
+static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
+static struct file {
+ TAILQ_ENTRY(file) entry;
+ FILE *stream;
+ char *name;
+ int lineno;
+ int errors;
+} *file;
+struct file *pushfile(const char *, int);
+int popfile(void);
+int check_file_secrecy(int, const char *);
+int yyparse(void);
+int yylex(void);
+int yyerror(const char *, ...);
+int kw_cmp(const void *, const void *);
+int lookup(char *);
+int lgetc(int);
+int lungetc(int);
+int findeol(void);
+
+static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
+struct sym {
+ TAILQ_ENTRY(sym) entry;
+ int used;
+ int persist;
+ char *nam;
+ char *val;
+};
+int symset(const char *, const char *, int);
+char *symget(const char *);
+
+int atoul(char *, u_long *);
+
+enum {
+ PFCTL_STATE_NONE,
+ PFCTL_STATE_OPTION,
+ PFCTL_STATE_SCRUB,
+ PFCTL_STATE_QUEUE,
+ PFCTL_STATE_NAT,
+ PFCTL_STATE_FILTER
+};
+
+struct node_proto {
+ u_int8_t proto;
+ struct node_proto *next;
+ struct node_proto *tail;
+};
+
+struct node_port {
+ u_int16_t port[2];
+ u_int8_t op;
+ struct node_port *next;
+ struct node_port *tail;
+};
+
+struct node_uid {
+ uid_t uid[2];
+ u_int8_t op;
+ struct node_uid *next;
+ struct node_uid *tail;
+};
+
+struct node_gid {
+ gid_t gid[2];
+ u_int8_t op;
+ struct node_gid *next;
+ struct node_gid *tail;
+};
+
+struct node_icmp {
+ u_int8_t code;
+ u_int8_t type;
+ u_int8_t proto;
+ struct node_icmp *next;
+ struct node_icmp *tail;
+};
+
+enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK,
+ PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN,
+ PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
+ PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
+ PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, };
+
+enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
+
+struct node_state_opt {
+ int type;
+ union {
+ u_int32_t max_states;
+ u_int32_t max_src_states;
+ u_int32_t max_src_conn;
+ struct {
+ u_int32_t limit;
+ u_int32_t seconds;
+ } max_src_conn_rate;
+ struct {
+ u_int8_t flush;
+ char tblname[PF_TABLE_NAME_SIZE];
+ } overload;
+ u_int32_t max_src_nodes;
+ u_int8_t src_track;
+ u_int32_t statelock;
+ struct {
+ int number;
+ u_int32_t seconds;
+ } timeout;
+ } data;
+ struct node_state_opt *next;
+ struct node_state_opt *tail;
+};
+
+struct peer {
+ struct node_host *host;
+ struct node_port *port;
+};
+
+static struct node_queue {
+ char queue[PF_QNAME_SIZE];
+ char parent[PF_QNAME_SIZE];
+ char ifname[IFNAMSIZ];
+ int scheduler;
+ struct node_queue *next;
+ struct node_queue *tail;
+} *queues = NULL;
+
+struct node_qassign {
+ char *qname;
+ char *pqname;
+};
+
+static struct filter_opts {
+ int marker;
+#define FOM_FLAGS 0x01
+#define FOM_ICMP 0x02
+#define FOM_TOS 0x04
+#define FOM_KEEP 0x08
+#define FOM_SRCTRACK 0x10
+#define FOM_SETPRIO 0x0400
+#define FOM_PRIO 0x2000
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } flags;
+ struct node_icmp *icmpspec;
+ u_int32_t tos;
+ u_int32_t prob;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep;
+ int fragment;
+ int allowopts;
+ char *label;
+ struct node_qassign queues;
+ char *tag;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+ u_int8_t prio;
+ u_int8_t set_prio[2];
+ struct {
+ struct node_host *addr;
+ u_int16_t port;
+ } divert;
+} filter_opts;
+
+static struct antispoof_opts {
+ char *label;
+ u_int rtableid;
+} antispoof_opts;
+
+static struct scrub_opts {
+ int marker;
+#define SOM_MINTTL 0x01
+#define SOM_MAXMSS 0x02
+#define SOM_FRAGCACHE 0x04
+#define SOM_SETTOS 0x08
+ int nodf;
+ int minttl;
+ int maxmss;
+ int settos;
+ int fragcache;
+ int randomid;
+ int reassemble_tcp;
+ char *match_tag;
+ u_int8_t match_tag_not;
+ u_int rtableid;
+} scrub_opts;
+
+static struct queue_opts {
+ int marker;
+#define QOM_BWSPEC 0x01
+#define QOM_SCHEDULER 0x02
+#define QOM_PRIORITY 0x04
+#define QOM_TBRSIZE 0x08
+#define QOM_QLIMIT 0x10
+ struct node_queue_bw queue_bwspec;
+ struct node_queue_opt scheduler;
+ int priority;
+ int tbrsize;
+ int qlimit;
+} queue_opts;
+
+static struct table_opts {
+ int flags;
+ int init_addr;
+ struct node_tinithead init_nodes;
+} table_opts;
+
+static struct pool_opts {
+ int marker;
+#define POM_TYPE 0x01
+#define POM_STICKYADDRESS 0x02
+ u_int8_t opts;
+ int type;
+ int staticport;
+ struct pf_poolhashkey *key;
+
+} pool_opts;
+
+static struct codel_opts codel_opts;
+static struct node_hfsc_opts hfsc_opts;
+static struct node_fairq_opts fairq_opts;
+static struct node_state_opt *keep_state_defaults = NULL;
+
+int disallow_table(struct node_host *, const char *);
+int disallow_urpf_failed(struct node_host *, const char *);
+int disallow_alias(struct node_host *, const char *);
+int rule_consistent(struct pf_rule *, int);
+int filter_consistent(struct pf_rule *, int);
+int nat_consistent(struct pf_rule *);
+int rdr_consistent(struct pf_rule *);
+int process_tabledef(char *, struct table_opts *);
+void expand_label_str(char *, size_t, const char *, const char *);
+void expand_label_if(const char *, char *, size_t, const char *);
+void expand_label_addr(const char *, char *, size_t, u_int8_t,
+ struct node_host *);
+void expand_label_port(const char *, char *, size_t,
+ struct node_port *);
+void expand_label_proto(const char *, char *, size_t, u_int8_t);
+void expand_label_nr(const char *, char *, size_t);
+void expand_label(char *, size_t, const char *, u_int8_t,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, u_int8_t);
+void expand_rule(struct pf_rule *, struct node_if *,
+ struct node_host *, struct node_proto *, struct node_os *,
+ struct node_host *, struct node_port *, struct node_host *,
+ struct node_port *, struct node_uid *, struct node_gid *,
+ struct node_icmp *, const char *);
+int expand_altq(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw bwspec,
+ struct node_queue_opt *);
+int expand_queue(struct pf_altq *, struct node_if *,
+ struct node_queue *, struct node_queue_bw,
+ struct node_queue_opt *);
+int expand_skip_interface(struct node_if *);
+
+int check_rulestate(int);
+int getservice(char *);
+int rule_label(struct pf_rule *, char *);
+int rt_tableid_max(void);
+
+void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
+void decide_address_family(struct node_host *, sa_family_t *);
+void remove_invalid_hosts(struct node_host **, sa_family_t *);
+int invalid_redirect(struct node_host *, sa_family_t);
+u_int16_t parseicmpspec(char *, sa_family_t);
+
+static TAILQ_HEAD(loadanchorshead, loadanchors)
+ loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead);
+
+struct loadanchors {
+ TAILQ_ENTRY(loadanchors) entries;
+ char *anchorname;
+ char *filename;
+};
+
+typedef struct {
+ union {
+ int64_t number;
+ double probability;
+ int i;
+ char *string;
+ u_int rtableid;
+ struct {
+ u_int8_t b1;
+ u_int8_t b2;
+ u_int16_t w;
+ u_int16_t w2;
+ } b;
+ struct range {
+ int a;
+ int b;
+ int t;
+ } range;
+ struct node_if *interface;
+ struct node_proto *proto;
+ struct node_icmp *icmp;
+ struct node_host *host;
+ struct node_os *os;
+ struct node_port *port;
+ struct node_uid *uid;
+ struct node_gid *gid;
+ struct node_state_opt *state_opt;
+ struct peer peer;
+ struct {
+ struct peer src, dst;
+ struct node_os *src_os;
+ } fromto;
+ struct {
+ struct node_host *host;
+ u_int8_t rt;
+ u_int8_t pool_opts;
+ sa_family_t af;
+ struct pf_poolhashkey *key;
+ } route;
+ struct redirection {
+ struct node_host *host;
+ struct range rport;
+ } *redirection;
+ struct {
+ int action;
+ struct node_state_opt *options;
+ } keep_state;
+ struct {
+ u_int8_t log;
+ u_int8_t logif;
+ u_int8_t quick;
+ } logquick;
+ struct {
+ int neg;
+ char *name;
+ } tagged;
+ struct pf_poolhashkey *hashkey;
+ struct node_queue *queue;
+ struct node_queue_opt queue_options;
+ struct node_queue_bw queue_bwspec;
+ struct node_qassign qassign;
+ struct filter_opts filter_opts;
+ struct antispoof_opts antispoof_opts;
+ struct queue_opts queue_opts;
+ struct scrub_opts scrub_opts;
+ struct table_opts table_opts;
+ struct pool_opts pool_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ struct codel_opts codel_opts;
+ } v;
+ int lineno;
+} YYSTYPE;
+
+#define PPORT_RANGE 1
+#define PPORT_STAR 2
+int parseport(char *, struct range *r, int);
+
+#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \
+ (!((addr).iflags & PFI_AFLAG_NOALIAS) || \
+ !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1])))
+
+%}
+
+%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS
+%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE
+%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF
+%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL
+%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
+%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR
+%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
+%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
+%token ANTISPOOF FOR INCLUDE
+%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY
+%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
+%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
+%token LOAD RULESET_OPTIMIZATION PRIO
+%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
+%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY
+%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
+%token DIVERTTO DIVERTREPLY
+%token <v.string> STRING
+%token <v.number> NUMBER
+%token <v.i> PORTBINARY
+%type <v.interface> interface if_list if_item_not if_item
+%type <v.number> number icmptype icmp6type uid gid
+%type <v.number> tos not yesno
+%type <v.probability> probability
+%type <v.i> no dir af fragcache optimizer
+%type <v.i> sourcetrack flush unaryop statelock
+%type <v.b> action nataction natpasslog scrubaction
+%type <v.b> flags flag blockspec prio
+%type <v.range> portplain portstar portrange
+%type <v.hashkey> hashkey
+%type <v.proto> proto proto_list proto_item
+%type <v.number> protoval
+%type <v.icmp> icmpspec
+%type <v.icmp> icmp_list icmp_item
+%type <v.icmp> icmp6_list icmp6_item
+%type <v.number> reticmpspec reticmp6spec
+%type <v.fromto> fromto
+%type <v.peer> ipportspec from to
+%type <v.host> ipspec toipspec xhost host dynaddr host_list
+%type <v.host> redir_host_list redirspec
+%type <v.host> route_host route_host_list routespec
+%type <v.os> os xos os_list
+%type <v.port> portspec port_list port_item
+%type <v.uid> uids uid_list uid_item
+%type <v.gid> gids gid_list gid_item
+%type <v.route> route
+%type <v.redirection> redirection redirpool
+%type <v.string> label stringall tag anchorname
+%type <v.string> string varstring numberstring
+%type <v.keep_state> keep
+%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
+%type <v.logquick> logquick quick log logopts logopt
+%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
+%type <v.qassign> qname
+%type <v.queue> qassign qassign_list qassign_item
+%type <v.queue_options> scheduler
+%type <v.number> cbqflags_list cbqflags_item
+%type <v.number> priqflags_list priqflags_item
+%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts
+%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
+%type <v.codel_opts> codelopts_list codelopts_item codel_opts
+%type <v.queue_bwspec> bandwidth
+%type <v.filter_opts> filter_opts filter_opt filter_opts_l
+%type <v.filter_opts> filter_sets filter_set filter_sets_l
+%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
+%type <v.queue_opts> queue_opts queue_opt queue_opts_l
+%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l
+%type <v.table_opts> table_opts table_opt table_opts_l
+%type <v.pool_opts> pool_opts pool_opt pool_opts_l
+%type <v.tagged> tagged
+%type <v.rtableid> rtable
+%%
+
+ruleset : /* empty */
+ | ruleset include '\n'
+ | ruleset '\n'
+ | ruleset option '\n'
+ | ruleset scrubrule '\n'
+ | ruleset natrule '\n'
+ | ruleset binatrule '\n'
+ | ruleset pfrule '\n'
+ | ruleset anchorrule '\n'
+ | ruleset loadrule '\n'
+ | ruleset altqif '\n'
+ | ruleset queuespec '\n'
+ | ruleset varset '\n'
+ | ruleset antispoof '\n'
+ | ruleset tabledef '\n'
+ | '{' fakeanchor '}' '\n';
+ | ruleset error '\n' { file->errors++; }
+ ;
+
+include : INCLUDE STRING {
+ struct file *nfile;
+
+ if ((nfile = pushfile($2, 0)) == NULL) {
+ yyerror("failed to include file %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+
+ file = nfile;
+ lungetc('\n');
+ }
+ ;
+
+/*
+ * apply to previouslys specified rule: must be careful to note
+ * what that is: pf or nat or binat or rdr
+ */
+fakeanchor : fakeanchor '\n'
+ | fakeanchor anchorrule '\n'
+ | fakeanchor binatrule '\n'
+ | fakeanchor natrule '\n'
+ | fakeanchor pfrule '\n'
+ | fakeanchor error '\n'
+ ;
+
+optimizer : string {
+ if (!strcmp($1, "none"))
+ $$ = 0;
+ else if (!strcmp($1, "basic"))
+ $$ = PF_OPTIMIZE_BASIC;
+ else if (!strcmp($1, "profile"))
+ $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE;
+ else {
+ yyerror("unknown ruleset-optimization %s", $1);
+ YYERROR;
+ }
+ }
+ ;
+
+option : SET OPTIMIZATION STRING {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_optimization(pf, $3) != 0) {
+ yyerror("unknown optimization %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET RULESET_OPTIMIZATION optimizer {
+ if (!(pf->opts & PF_OPT_OPTIMIZE)) {
+ pf->opts |= PF_OPT_OPTIMIZE;
+ pf->optimize = $3;
+ }
+ }
+ | SET TIMEOUT timeout_spec
+ | SET TIMEOUT '{' optnl timeout_list '}'
+ | SET LIMIT limit_spec
+ | SET LIMIT '{' optnl limit_list '}'
+ | SET LOGINTERFACE stringall {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_logif(pf, $3) != 0) {
+ yyerror("error setting loginterface %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET HOSTID number {
+ if ($3 == 0 || $3 > UINT_MAX) {
+ yyerror("hostid must be non-zero");
+ YYERROR;
+ }
+ if (pfctl_set_hostid(pf, $3) != 0) {
+ yyerror("error setting hostid %08x", $3);
+ YYERROR;
+ }
+ }
+ | SET BLOCKPOLICY DROP {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy drop\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_DROP;
+ }
+ | SET BLOCKPOLICY RETURN {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set block-policy return\n");
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ blockpolicy = PFRULE_RETURN;
+ }
+ | SET REQUIREORDER yesno {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set require-order %s\n",
+ $3 == 1 ? "yes" : "no");
+ require_order = $3;
+ }
+ | SET FINGERPRINTS STRING {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set fingerprints \"%s\"\n", $3);
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (!pf->anchor->name[0]) {
+ if (pfctl_file_fingerprints(pf->dev,
+ pf->opts, $3)) {
+ yyerror("error loading "
+ "fingerprints %s", $3);
+ free($3);
+ YYERROR;
+ }
+ }
+ free($3);
+ }
+ | SET STATEPOLICY statelock {
+ if (pf->opts & PF_OPT_VERBOSE)
+ switch ($3) {
+ case 0:
+ printf("set state-policy floating\n");
+ break;
+ case PFRULE_IFBOUND:
+ printf("set state-policy if-bound\n");
+ break;
+ }
+ default_statelock = $3;
+ }
+ | SET DEBUG STRING {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($3);
+ YYERROR;
+ }
+ if (pfctl_set_debug(pf, $3) != 0) {
+ yyerror("error setting debuglevel %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | SET SKIP interface {
+ if (expand_skip_interface($3) != 0) {
+ yyerror("error setting skip interface(s)");
+ YYERROR;
+ }
+ }
+ | SET STATEDEFAULTS state_opt_list {
+ if (keep_state_defaults != NULL) {
+ yyerror("cannot redefine state-defaults");
+ YYERROR;
+ }
+ keep_state_defaults = $3;
+ }
+ ;
+
+stringall : STRING { $$ = $1; }
+ | ALL {
+ if (($$ = strdup("all")) == NULL) {
+ err(1, "stringall: strdup");
+ }
+ }
+ ;
+
+string : STRING string {
+ if (asprintf(&$$, "%s %s", $1, $2) == -1)
+ err(1, "string: asprintf");
+ free($1);
+ free($2);
+ }
+ | STRING
+ ;
+
+varstring : numberstring varstring {
+ if (asprintf(&$$, "%s %s", $1, $2) == -1)
+ err(1, "string: asprintf");
+ free($1);
+ free($2);
+ }
+ | numberstring
+ ;
+
+numberstring : NUMBER {
+ char *s;
+ if (asprintf(&s, "%lld", (long long)$1) == -1) {
+ yyerror("string: asprintf");
+ YYERROR;
+ }
+ $$ = s;
+ }
+ | STRING
+ ;
+
+varset : STRING '=' varstring {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("%s = \"%s\"\n", $1, $3);
+ if (symset($1, $3, 0) == -1)
+ err(1, "cannot store variable %s", $1);
+ free($1);
+ free($3);
+ }
+ ;
+
+anchorname : STRING { $$ = $1; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+pfa_anchorlist : /* empty */
+ | pfa_anchorlist '\n'
+ | pfa_anchorlist pfrule '\n'
+ | pfa_anchorlist anchorrule '\n'
+ ;
+
+pfa_anchor : '{'
+ {
+ char ta[PF_ANCHOR_NAME_SIZE];
+ struct pf_ruleset *rs;
+
+ /* steping into a brace anchor */
+ pf->asd++;
+ pf->bn++;
+ pf->brace = 1;
+
+ /* create a holding ruleset in the root */
+ snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn);
+ rs = pf_find_or_create_ruleset(ta);
+ if (rs == NULL)
+ err(1, "pfa_anchor: pf_find_or_create_ruleset");
+ pf->astack[pf->asd] = rs->anchor;
+ pf->anchor = rs->anchor;
+ } '\n' pfa_anchorlist '}'
+ {
+ pf->alast = pf->anchor;
+ pf->asd--;
+ pf->anchor = pf->astack[pf->asd];
+ }
+ | /* empty */
+ ;
+
+anchorrule : ANCHOR anchorname dir quick interface af proto fromto
+ filter_opts pfa_anchor
+ {
+ struct pf_rule r;
+ struct node_proto *proto;
+
+ if (check_rulestate(PFCTL_STATE_FILTER)) {
+ if ($2)
+ free($2);
+ YYERROR;
+ }
+
+ if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) {
+ free($2);
+ yyerror("anchor names beginning with '_' "
+ "are reserved for internal use");
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ if (pf->astack[pf->asd + 1]) {
+ /* move inline rules into relative location */
+ pf_anchor_setup(&r,
+ &pf->astack[pf->asd]->ruleset,
+ $2 ? $2 : pf->alast->name);
+
+ if (r.anchor == NULL)
+ err(1, "anchorrule: unable to "
+ "create ruleset");
+
+ if (pf->alast != r.anchor) {
+ if (r.anchor->match) {
+ yyerror("inline anchor '%s' "
+ "already exists",
+ r.anchor->name);
+ YYERROR;
+ }
+ mv_rules(&pf->alast->ruleset,
+ &r.anchor->ruleset);
+ }
+ pf_remove_if_empty_ruleset(&pf->alast->ruleset);
+ pf->alast = r.anchor;
+ } else {
+ if (!$2) {
+ yyerror("anchors without explicit "
+ "rules must specify a name");
+ YYERROR;
+ }
+ }
+ r.direction = $3;
+ r.quick = $4.quick;
+ r.af = $6;
+ r.prob = $9.prob;
+ r.rtableid = $9.rtableid;
+
+ if ($9.tag)
+ if (strlcpy(r.tagname, $9.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if (rule_label(&r, $9.label))
+ YYERROR;
+ free($9.label);
+ r.flags = $9.flags.b1;
+ r.flagset = $9.flags.b2;
+ if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
+ for (proto = $7; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && $7 != NULL) {
+ if ($9.flags.b1 || $9.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if ($8.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "applies to tcp");
+ YYERROR;
+ }
+ }
+
+ r.tos = $9.tos;
+
+ if ($9.keep.action) {
+ yyerror("cannot specify state handling "
+ "on anchors");
+ YYERROR;
+ }
+
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if ($9.marker & FOM_PRIO) {
+ if ($9.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = $9.prio;
+ }
+ if ($9.marker & FOM_SETPRIO) {
+ r.set_prio[0] = $9.set_prio[0];
+ r.set_prio[1] = $9.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ decide_address_family($8.src.host, &r.af);
+ decide_address_family($8.dst.host, &r.af);
+
+ expand_rule(&r, $5, NULL, $7, $8.src_os,
+ $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
+ $9.uid, $9.gid, $9.icmpspec,
+ pf->astack[pf->asd + 1] ? pf->alast->name : $2);
+ free($2);
+ pf->astack[pf->asd + 1] = NULL;
+ }
+ | NATANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_NAT;
+ r.af = $4;
+ r.rtableid = $7;
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ expand_rule(&r, $3, NULL, $5, $6.src_os,
+ $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
+ 0, 0, 0, $2);
+ free($2);
+ }
+ | RDRANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_RDR;
+ r.af = $4;
+ r.rtableid = $7;
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ if ($6.src.port != NULL) {
+ yyerror("source port parameter not supported"
+ " in rdr-anchor");
+ YYERROR;
+ }
+ if ($6.dst.port != NULL) {
+ if ($6.dst.port->next != NULL) {
+ yyerror("destination port list "
+ "expansion not supported in "
+ "rdr-anchor");
+ YYERROR;
+ } else if ($6.dst.port->op != PF_OP_EQ) {
+ yyerror("destination port operators"
+ " not supported in rdr-anchor");
+ YYERROR;
+ }
+ r.dst.port[0] = $6.dst.port->port[0];
+ r.dst.port[1] = $6.dst.port->port[1];
+ r.dst.port_op = $6.dst.port->op;
+ }
+
+ expand_rule(&r, $3, NULL, $5, $6.src_os,
+ $6.src.host, $6.src.port, $6.dst.host, $6.dst.port,
+ 0, 0, 0, $2);
+ free($2);
+ }
+ | BINATANCHOR string interface af proto fromto rtable {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&r, 0, sizeof(r));
+ r.action = PF_BINAT;
+ r.af = $4;
+ r.rtableid = $7;
+ if ($5 != NULL) {
+ if ($5->next != NULL) {
+ yyerror("proto list expansion"
+ " not supported in binat-anchor");
+ YYERROR;
+ }
+ r.proto = $5->proto;
+ free($5);
+ }
+
+ if ($6.src.host != NULL || $6.src.port != NULL ||
+ $6.dst.host != NULL || $6.dst.port != NULL) {
+ yyerror("fromto parameter not supported"
+ " in binat-anchor");
+ YYERROR;
+ }
+
+ decide_address_family($6.src.host, &r.af);
+ decide_address_family($6.dst.host, &r.af);
+
+ pfctl_add_rule(pf, &r, $2);
+ free($2);
+ }
+ ;
+
+loadrule : LOAD ANCHOR string FROM string {
+ struct loadanchors *loadanchor;
+
+ if (strlen(pf->anchor->name) + 1 +
+ strlen($3) >= MAXPATHLEN) {
+ yyerror("anchorname %s too long, max %u\n",
+ $3, MAXPATHLEN - 1);
+ free($3);
+ YYERROR;
+ }
+ loadanchor = calloc(1, sizeof(struct loadanchors));
+ if (loadanchor == NULL)
+ err(1, "loadrule: calloc");
+ if ((loadanchor->anchorname = malloc(MAXPATHLEN)) ==
+ NULL)
+ err(1, "loadrule: malloc");
+ if (pf->anchor->name[0])
+ snprintf(loadanchor->anchorname, MAXPATHLEN,
+ "%s/%s", pf->anchor->name, $3);
+ else
+ strlcpy(loadanchor->anchorname, $3, MAXPATHLEN);
+ if ((loadanchor->filename = strdup($5)) == NULL)
+ err(1, "loadrule: strdup");
+
+ TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor,
+ entries);
+
+ free($3);
+ free($5);
+ };
+
+scrubaction : no SCRUB {
+ $$.b2 = $$.w = 0;
+ if ($1)
+ $$.b1 = PF_NOSCRUB;
+ else
+ $$.b1 = PF_SCRUB;
+ }
+ ;
+
+scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_SCRUB))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ r.direction = $2;
+
+ r.log = $3.log;
+ r.logif = $3.logif;
+ if ($3.quick) {
+ yyerror("scrub rules do not support 'quick'");
+ YYERROR;
+ }
+
+ r.af = $5;
+ if ($8.nodf)
+ r.rule_flag |= PFRULE_NODF;
+ if ($8.randomid)
+ r.rule_flag |= PFRULE_RANDOMID;
+ if ($8.reassemble_tcp) {
+ if (r.direction != PF_INOUT) {
+ yyerror("reassemble tcp rules can not "
+ "specify direction");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_REASSEMBLE_TCP;
+ }
+ if ($8.minttl)
+ r.min_ttl = $8.minttl;
+ if ($8.maxmss)
+ r.max_mss = $8.maxmss;
+ if ($8.marker & SOM_SETTOS) {
+ r.rule_flag |= PFRULE_SET_TOS;
+ r.set_tos = $8.settos;
+ }
+ if ($8.fragcache)
+ r.rule_flag |= $8.fragcache;
+ if ($8.match_tag)
+ if (strlcpy(r.match_tagname, $8.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $8.match_tag_not;
+ r.rtableid = $8.rtableid;
+
+ expand_rule(&r, $4, NULL, $6, $7.src_os,
+ $7.src.host, $7.src.port, $7.dst.host, $7.dst.port,
+ NULL, NULL, NULL, "");
+ }
+ ;
+
+scrub_opts : {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ }
+ scrub_opts_l
+ { $$ = scrub_opts; }
+ | /* empty */ {
+ bzero(&scrub_opts, sizeof scrub_opts);
+ scrub_opts.rtableid = -1;
+ $$ = scrub_opts;
+ }
+ ;
+
+scrub_opts_l : scrub_opts_l scrub_opt
+ | scrub_opt
+ ;
+
+scrub_opt : NODF {
+ if (scrub_opts.nodf) {
+ yyerror("no-df cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.nodf = 1;
+ }
+ | MINTTL NUMBER {
+ if (scrub_opts.marker & SOM_MINTTL) {
+ yyerror("min-ttl cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 255) {
+ yyerror("illegal min-ttl value %d", $2);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MINTTL;
+ scrub_opts.minttl = $2;
+ }
+ | MAXMSS NUMBER {
+ if (scrub_opts.marker & SOM_MAXMSS) {
+ yyerror("max-mss cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("illegal max-mss value %d", $2);
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_MAXMSS;
+ scrub_opts.maxmss = $2;
+ }
+ | SETTOS tos {
+ if (scrub_opts.marker & SOM_SETTOS) {
+ yyerror("set-tos cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_SETTOS;
+ scrub_opts.settos = $2;
+ }
+ | fragcache {
+ if (scrub_opts.marker & SOM_FRAGCACHE) {
+ yyerror("fragcache cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.marker |= SOM_FRAGCACHE;
+ scrub_opts.fragcache = $1;
+ }
+ | REASSEMBLE STRING {
+ if (strcasecmp($2, "tcp") != 0) {
+ yyerror("scrub reassemble supports only tcp, "
+ "not '%s'", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if (scrub_opts.reassemble_tcp) {
+ yyerror("reassemble tcp cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.reassemble_tcp = 1;
+ }
+ | RANDOMID {
+ if (scrub_opts.randomid) {
+ yyerror("random-id cannot be respecified");
+ YYERROR;
+ }
+ scrub_opts.randomid = 1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ scrub_opts.rtableid = $2;
+ }
+ | not TAGGED string {
+ scrub_opts.match_tag = $3;
+ scrub_opts.match_tag_not = $1;
+ }
+ ;
+
+fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ }
+ | FRAGMENT FRAGCROP { $$ = 0; }
+ | FRAGMENT FRAGDROP { $$ = 0; }
+ ;
+
+antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
+ struct pf_rule r;
+ struct node_host *h = NULL, *hh;
+ struct node_if *i, *j;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ for (i = $3; i; i = i->next) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = $2.log;
+ r.logif = $2.logif;
+ r.quick = $2.quick;
+ r.af = $4;
+ if (rule_label(&r, $5.label))
+ YYERROR;
+ r.rtableid = $5.rtableid;
+ j = calloc(1, sizeof(struct node_if));
+ if (j == NULL)
+ err(1, "antispoof: calloc");
+ if (strlcpy(j->ifname, i->ifname,
+ sizeof(j->ifname)) >= sizeof(j->ifname)) {
+ free(j);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ j->not = 1;
+ if (i->dynamic) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->addr.type = PF_ADDR_DYNIFTL;
+ set_ipmask(h, 128);
+ if (strlcpy(h->addr.v.ifname, i->ifname,
+ sizeof(h->addr.v.ifname)) >=
+ sizeof(h->addr.v.ifname)) {
+ free(h);
+ yyerror(
+ "interface name too long");
+ YYERROR;
+ }
+ hh = malloc(sizeof(*hh));
+ if (hh == NULL)
+ err(1, "address: malloc");
+ bcopy(h, hh, sizeof(*hh));
+ h->addr.iflags = PFI_AFLAG_NETWORK;
+ } else {
+ h = ifa_lookup(j->ifname,
+ PFI_AFLAG_NETWORK);
+ hh = NULL;
+ }
+
+ if (h != NULL)
+ expand_rule(&r, j, NULL, NULL, NULL, h,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, "");
+
+ if ((i->ifa_flags & IFF_LOOPBACK) == 0) {
+ bzero(&r, sizeof(r));
+
+ r.action = PF_DROP;
+ r.direction = PF_IN;
+ r.log = $2.log;
+ r.logif = $2.logif;
+ r.quick = $2.quick;
+ r.af = $4;
+ if (rule_label(&r, $5.label))
+ YYERROR;
+ r.rtableid = $5.rtableid;
+ if (hh != NULL)
+ h = hh;
+ else
+ h = ifa_lookup(i->ifname, 0);
+ if (h != NULL)
+ expand_rule(&r, NULL, NULL,
+ NULL, NULL, h, NULL, NULL,
+ NULL, NULL, NULL, NULL, "");
+ } else
+ free(hh);
+ }
+ free($5.label);
+ }
+ ;
+
+antispoof_ifspc : FOR antispoof_if { $$ = $2; }
+ | FOR '{' optnl antispoof_iflst '}' { $$ = $4; }
+ ;
+
+antispoof_iflst : antispoof_if optnl { $$ = $1; }
+ | antispoof_iflst comma antispoof_if optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+antispoof_if : if_item { $$ = $1; }
+ | '(' if_item ')' {
+ $2->dynamic = 1;
+ $$ = $2;
+ }
+ ;
+
+antispoof_opts : {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ }
+ antispoof_opts_l
+ { $$ = antispoof_opts; }
+ | /* empty */ {
+ bzero(&antispoof_opts, sizeof antispoof_opts);
+ antispoof_opts.rtableid = -1;
+ $$ = antispoof_opts;
+ }
+ ;
+
+antispoof_opts_l : antispoof_opts_l antispoof_opt
+ | antispoof_opt
+ ;
+
+antispoof_opt : label {
+ if (antispoof_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ antispoof_opts.label = $1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ antispoof_opts.rtableid = $2;
+ }
+ ;
+
+not : '!' { $$ = 1; }
+ | /* empty */ { $$ = 0; }
+ ;
+
+tabledef : TABLE '<' STRING '>' table_opts {
+ struct node_host *h, *nh;
+ struct node_tinit *ti, *nti;
+
+ if (strlen($3) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name too long, max %d chars",
+ PF_TABLE_NAME_SIZE - 1);
+ free($3);
+ YYERROR;
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (process_tabledef($3, &$5)) {
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ for (ti = SIMPLEQ_FIRST(&$5.init_nodes);
+ ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) {
+ if (ti->file)
+ free(ti->file);
+ for (h = ti->host; h != NULL; h = nh) {
+ nh = h->next;
+ free(h);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ free(ti);
+ }
+ }
+ ;
+
+table_opts : {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ }
+ table_opts_l
+ { $$ = table_opts; }
+ | /* empty */
+ {
+ bzero(&table_opts, sizeof table_opts);
+ SIMPLEQ_INIT(&table_opts.init_nodes);
+ $$ = table_opts;
+ }
+ ;
+
+table_opts_l : table_opts_l table_opt
+ | table_opt
+ ;
+
+table_opt : STRING {
+ if (!strcmp($1, "const"))
+ table_opts.flags |= PFR_TFLAG_CONST;
+ else if (!strcmp($1, "persist"))
+ table_opts.flags |= PFR_TFLAG_PERSIST;
+ else if (!strcmp($1, "counters"))
+ table_opts.flags |= PFR_TFLAG_COUNTERS;
+ else {
+ yyerror("invalid table option '%s'", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | '{' optnl '}' { table_opts.init_addr = 1; }
+ | '{' optnl host_list '}' {
+ struct node_host *n;
+ struct node_tinit *ti;
+
+ for (n = $3; n != NULL; n = n->next) {
+ switch (n->addr.type) {
+ case PF_ADDR_ADDRMASK:
+ continue; /* ok */
+ case PF_ADDR_RANGE:
+ yyerror("address ranges are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_DYNIFTL:
+ yyerror("dynamic addresses are not "
+ "permitted inside tables");
+ break;
+ case PF_ADDR_TABLE:
+ yyerror("tables cannot contain tables");
+ break;
+ case PF_ADDR_NOROUTE:
+ yyerror("\"no-route\" is not permitted "
+ "inside tables");
+ break;
+ case PF_ADDR_URPFFAILED:
+ yyerror("\"urpf-failed\" is not "
+ "permitted inside tables");
+ break;
+ default:
+ yyerror("unknown address type %d",
+ n->addr.type);
+ }
+ YYERROR;
+ }
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->host = $3;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+ | FILENAME STRING {
+ struct node_tinit *ti;
+
+ if (!(ti = calloc(1, sizeof(*ti))))
+ err(1, "table_opt: calloc");
+ ti->file = $2;
+ SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti,
+ entries);
+ table_opts.init_addr = 1;
+ }
+ ;
+
+altqif : ALTQ interface queue_opts QUEUE qassign {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE))
+ YYERROR;
+
+ memset(&a, 0, sizeof(a));
+ if ($3.scheduler.qtype == ALTQT_NONE) {
+ yyerror("no scheduler specified!");
+ YYERROR;
+ }
+ a.scheduler = $3.scheduler.qtype;
+ a.qlimit = $3.qlimit;
+ a.tbrsize = $3.tbrsize;
+ if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) {
+ yyerror("no child queues specified");
+ YYERROR;
+ }
+ if (expand_altq(&a, $2, $5, $3.queue_bwspec,
+ &$3.scheduler))
+ YYERROR;
+ }
+ ;
+
+queuespec : QUEUE STRING interface queue_opts qassign {
+ struct pf_altq a;
+
+ if (check_rulestate(PFCTL_STATE_QUEUE)) {
+ free($2);
+ YYERROR;
+ }
+
+ memset(&a, 0, sizeof(a));
+
+ if (strlcpy(a.qname, $2, sizeof(a.qname)) >=
+ sizeof(a.qname)) {
+ yyerror("queue name too long (max "
+ "%d chars)", PF_QNAME_SIZE-1);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ if ($4.tbrsize) {
+ yyerror("cannot specify tbrsize for queue");
+ YYERROR;
+ }
+ if ($4.priority > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ a.priority = $4.priority;
+ a.qlimit = $4.qlimit;
+ a.scheduler = $4.scheduler.qtype;
+ if (expand_queue(&a, $3, $5, $4.queue_bwspec,
+ &$4.scheduler)) {
+ yyerror("errors in queue definition");
+ YYERROR;
+ }
+ }
+ ;
+
+queue_opts : {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ }
+ queue_opts_l
+ { $$ = queue_opts; }
+ | /* empty */ {
+ bzero(&queue_opts, sizeof queue_opts);
+ queue_opts.priority = DEFAULT_PRIORITY;
+ queue_opts.qlimit = DEFAULT_QLIMIT;
+ queue_opts.scheduler.qtype = ALTQT_NONE;
+ queue_opts.queue_bwspec.bw_percent = 100;
+ $$ = queue_opts;
+ }
+ ;
+
+queue_opts_l : queue_opts_l queue_opt
+ | queue_opt
+ ;
+
+queue_opt : BANDWIDTH bandwidth {
+ if (queue_opts.marker & QOM_BWSPEC) {
+ yyerror("bandwidth cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_BWSPEC;
+ queue_opts.queue_bwspec = $2;
+ }
+ | PRIORITY NUMBER {
+ if (queue_opts.marker & QOM_PRIORITY) {
+ yyerror("priority cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 255) {
+ yyerror("priority out of range: max 255");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_PRIORITY;
+ queue_opts.priority = $2;
+ }
+ | QLIMIT NUMBER {
+ if (queue_opts.marker & QOM_QLIMIT) {
+ yyerror("qlimit cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("qlimit out of range: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_QLIMIT;
+ queue_opts.qlimit = $2;
+ }
+ | scheduler {
+ if (queue_opts.marker & QOM_SCHEDULER) {
+ yyerror("scheduler cannot be respecified");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_SCHEDULER;
+ queue_opts.scheduler = $1;
+ }
+ | TBRSIZE NUMBER {
+ if (queue_opts.marker & QOM_TBRSIZE) {
+ yyerror("tbrsize cannot be respecified");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > 65535) {
+ yyerror("tbrsize too big: max 65535");
+ YYERROR;
+ }
+ queue_opts.marker |= QOM_TBRSIZE;
+ queue_opts.tbrsize = $2;
+ }
+ ;
+
+bandwidth : STRING {
+ double bps;
+ char *cp;
+
+ $$.bw_percent = 0;
+
+ bps = strtod($1, &cp);
+ if (cp != NULL) {
+ if (strlen(cp) > 1) {
+ char *cu = cp + 1;
+ if (!strcmp(cu, "Bit") ||
+ !strcmp(cu, "B") ||
+ !strcmp(cu, "bit") ||
+ !strcmp(cu, "b")) {
+ *cu = 0;
+ }
+ }
+ if (!strcmp(cp, "b"))
+ ; /* nothing */
+ else if (!strcmp(cp, "K"))
+ bps *= 1000;
+ else if (!strcmp(cp, "M"))
+ bps *= 1000 * 1000;
+ else if (!strcmp(cp, "G"))
+ bps *= 1000 * 1000 * 1000;
+ else if (!strcmp(cp, "%")) {
+ if (bps < 0 || bps > 100) {
+ yyerror("bandwidth spec "
+ "out of range");
+ free($1);
+ YYERROR;
+ }
+ $$.bw_percent = bps;
+ bps = 0;
+ } else {
+ yyerror("unknown unit %s", cp);
+ free($1);
+ YYERROR;
+ }
+ }
+ free($1);
+ $$.bw_absolute = (u_int32_t)bps;
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > UINT_MAX) {
+ yyerror("bandwidth number too big");
+ YYERROR;
+ }
+ $$.bw_percent = 0;
+ $$.bw_absolute = $1;
+ }
+ ;
+
+scheduler : CBQ {
+ $$.qtype = ALTQT_CBQ;
+ $$.data.cbq_opts.flags = 0;
+ }
+ | CBQ '(' cbqflags_list ')' {
+ $$.qtype = ALTQT_CBQ;
+ $$.data.cbq_opts.flags = $3;
+ }
+ | PRIQ {
+ $$.qtype = ALTQT_PRIQ;
+ $$.data.priq_opts.flags = 0;
+ }
+ | PRIQ '(' priqflags_list ')' {
+ $$.qtype = ALTQT_PRIQ;
+ $$.data.priq_opts.flags = $3;
+ }
+ | HFSC {
+ $$.qtype = ALTQT_HFSC;
+ bzero(&$$.data.hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+ | HFSC '(' hfsc_opts ')' {
+ $$.qtype = ALTQT_HFSC;
+ $$.data.hfsc_opts = $3;
+ }
+ | FAIRQ {
+ $$.qtype = ALTQT_FAIRQ;
+ bzero(&$$.data.fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ | FAIRQ '(' fairq_opts ')' {
+ $$.qtype = ALTQT_FAIRQ;
+ $$.data.fairq_opts = $3;
+ }
+ | CODEL {
+ $$.qtype = ALTQT_CODEL;
+ bzero(&$$.data.codel_opts,
+ sizeof(struct codel_opts));
+ }
+ | CODEL '(' codel_opts ')' {
+ $$.qtype = ALTQT_CODEL;
+ $$.data.codel_opts = $3;
+ }
+ ;
+
+cbqflags_list : cbqflags_item { $$ |= $1; }
+ | cbqflags_list comma cbqflags_item { $$ |= $3; }
+ ;
+
+cbqflags_item : STRING {
+ if (!strcmp($1, "default"))
+ $$ = CBQCLF_DEFCLASS;
+ else if (!strcmp($1, "borrow"))
+ $$ = CBQCLF_BORROW;
+ else if (!strcmp($1, "red"))
+ $$ = CBQCLF_RED;
+ else if (!strcmp($1, "ecn"))
+ $$ = CBQCLF_RED|CBQCLF_ECN;
+ else if (!strcmp($1, "rio"))
+ $$ = CBQCLF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = CBQCLF_CODEL;
+ else {
+ yyerror("unknown cbq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+priqflags_list : priqflags_item { $$ |= $1; }
+ | priqflags_list comma priqflags_item { $$ |= $3; }
+ ;
+
+priqflags_item : STRING {
+ if (!strcmp($1, "default"))
+ $$ = PRCF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ $$ = PRCF_RED;
+ else if (!strcmp($1, "ecn"))
+ $$ = PRCF_RED|PRCF_ECN;
+ else if (!strcmp($1, "rio"))
+ $$ = PRCF_RIO;
+ else if (!strcmp($1, "codel"))
+ $$ = PRCF_CODEL;
+ else {
+ yyerror("unknown priq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+hfsc_opts : {
+ bzero(&hfsc_opts,
+ sizeof(struct node_hfsc_opts));
+ }
+ hfscopts_list {
+ $$ = hfsc_opts;
+ }
+ ;
+
+hfscopts_list : hfscopts_item
+ | hfscopts_list comma hfscopts_item
+ ;
+
+hfscopts_item : LINKSHARE bandwidth {
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m2 = $2;
+ hfsc_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ hfsc_opts.linkshare.m1 = $3;
+ hfsc_opts.linkshare.d = $5;
+ hfsc_opts.linkshare.m2 = $7;
+ hfsc_opts.linkshare.used = 1;
+ }
+ | REALTIME bandwidth {
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m2 = $2;
+ hfsc_opts.realtime.used = 1;
+ }
+ | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.realtime.used) {
+ yyerror("realtime already specified");
+ YYERROR;
+ }
+ hfsc_opts.realtime.m1 = $3;
+ hfsc_opts.realtime.d = $5;
+ hfsc_opts.realtime.m2 = $7;
+ hfsc_opts.realtime.used = 1;
+ }
+ | UPPERLIMIT bandwidth {
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m2 = $2;
+ hfsc_opts.upperlimit.used = 1;
+ }
+ | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'
+ {
+ if ($5 < 0 || $5 > INT_MAX) {
+ yyerror("timing in curve out of range");
+ YYERROR;
+ }
+ if (hfsc_opts.upperlimit.used) {
+ yyerror("upperlimit already specified");
+ YYERROR;
+ }
+ hfsc_opts.upperlimit.m1 = $3;
+ hfsc_opts.upperlimit.d = $5;
+ hfsc_opts.upperlimit.m2 = $7;
+ hfsc_opts.upperlimit.used = 1;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ hfsc_opts.flags |= HFCF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ hfsc_opts.flags |= HFCF_RED;
+ else if (!strcmp($1, "ecn"))
+ hfsc_opts.flags |= HFCF_RED|HFCF_ECN;
+ else if (!strcmp($1, "rio"))
+ hfsc_opts.flags |= HFCF_RIO;
+ else if (!strcmp($1, "codel"))
+ hfsc_opts.flags |= HFCF_CODEL;
+ else {
+ yyerror("unknown hfsc flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+fairq_opts : {
+ bzero(&fairq_opts,
+ sizeof(struct node_fairq_opts));
+ }
+ fairqopts_list {
+ $$ = fairq_opts;
+ }
+ ;
+
+fairqopts_list : fairqopts_item
+ | fairqopts_list comma fairqopts_item
+ ;
+
+fairqopts_item : LINKSHARE bandwidth {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m2 = $2;
+ fairq_opts.linkshare.used = 1;
+ }
+ | LINKSHARE '(' bandwidth number bandwidth ')' {
+ if (fairq_opts.linkshare.used) {
+ yyerror("linkshare already specified");
+ YYERROR;
+ }
+ fairq_opts.linkshare.m1 = $3;
+ fairq_opts.linkshare.d = $4;
+ fairq_opts.linkshare.m2 = $5;
+ fairq_opts.linkshare.used = 1;
+ }
+ | HOGS bandwidth {
+ fairq_opts.hogs_bw = $2;
+ }
+ | BUCKETS number {
+ fairq_opts.nbuckets = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "default"))
+ fairq_opts.flags |= FARF_DEFAULTCLASS;
+ else if (!strcmp($1, "red"))
+ fairq_opts.flags |= FARF_RED;
+ else if (!strcmp($1, "ecn"))
+ fairq_opts.flags |= FARF_RED|FARF_ECN;
+ else if (!strcmp($1, "rio"))
+ fairq_opts.flags |= FARF_RIO;
+ else if (!strcmp($1, "codel"))
+ fairq_opts.flags |= FARF_CODEL;
+ else {
+ yyerror("unknown fairq flag \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+codel_opts : {
+ bzero(&codel_opts,
+ sizeof(struct codel_opts));
+ }
+ codelopts_list {
+ $$ = codel_opts;
+ }
+ ;
+
+codelopts_list : codelopts_item
+ | codelopts_list comma codelopts_item
+ ;
+
+codelopts_item : INTERVAL number {
+ if (codel_opts.interval) {
+ yyerror("interval already specified");
+ YYERROR;
+ }
+ codel_opts.interval = $2;
+ }
+ | TARGET number {
+ if (codel_opts.target) {
+ yyerror("target already specified");
+ YYERROR;
+ }
+ codel_opts.target = $2;
+ }
+ | STRING {
+ if (!strcmp($1, "ecn"))
+ codel_opts.ecn = 1;
+ else {
+ yyerror("unknown codel option \"%s\"", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+qassign : /* empty */ { $$ = NULL; }
+ | qassign_item { $$ = $1; }
+ | '{' optnl qassign_list '}' { $$ = $3; }
+ ;
+
+qassign_list : qassign_item optnl { $$ = $1; }
+ | qassign_list comma qassign_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+qassign_item : STRING {
+ $$ = calloc(1, sizeof(struct node_queue));
+ if ($$ == NULL)
+ err(1, "qassign_item: calloc");
+ if (strlcpy($$->queue, $1, sizeof($$->queue)) >=
+ sizeof($$->queue)) {
+ yyerror("queue name '%s' too long (max "
+ "%d chars)", $1, sizeof($$->queue)-1);
+ free($1);
+ free($$);
+ YYERROR;
+ }
+ free($1);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+pfrule : action dir logquick interface route af proto fromto
+ filter_opts
+ {
+ struct pf_rule r;
+ struct node_state_opt *o;
+ struct node_proto *proto;
+ int srctrack = 0;
+ int statelock = 0;
+ int adaptive = 0;
+ int defaults = 0;
+
+ if (check_rulestate(PFCTL_STATE_FILTER))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ switch ($1.b2) {
+ case PFRULE_RETURNRST:
+ r.rule_flag |= PFRULE_RETURNRST;
+ r.return_ttl = $1.w;
+ break;
+ case PFRULE_RETURNICMP:
+ r.rule_flag |= PFRULE_RETURNICMP;
+ r.return_icmp = $1.w;
+ r.return_icmp6 = $1.w2;
+ break;
+ case PFRULE_RETURN:
+ r.rule_flag |= PFRULE_RETURN;
+ r.return_icmp = $1.w;
+ r.return_icmp6 = $1.w2;
+ break;
+ }
+ r.direction = $2;
+ r.log = $3.log;
+ r.logif = $3.logif;
+ r.quick = $3.quick;
+ r.prob = $9.prob;
+ r.rtableid = $9.rtableid;
+
+ if ($9.marker & FOM_PRIO) {
+ if ($9.prio == 0)
+ r.prio = PF_PRIO_ZERO;
+ else
+ r.prio = $9.prio;
+ }
+ if ($9.marker & FOM_SETPRIO) {
+ r.set_prio[0] = $9.set_prio[0];
+ r.set_prio[1] = $9.set_prio[1];
+ r.scrub_flags |= PFSTATE_SETPRIO;
+ }
+
+ r.af = $6;
+ if ($9.tag)
+ if (strlcpy(r.tagname, $9.tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($9.match_tag)
+ if (strlcpy(r.match_tagname, $9.match_tag,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $9.match_tag_not;
+ if (rule_label(&r, $9.label))
+ YYERROR;
+ free($9.label);
+ r.flags = $9.flags.b1;
+ r.flagset = $9.flags.b2;
+ if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) {
+ yyerror("flags always false");
+ YYERROR;
+ }
+ if ($9.flags.b1 || $9.flags.b2 || $8.src_os) {
+ for (proto = $7; proto != NULL &&
+ proto->proto != IPPROTO_TCP;
+ proto = proto->next)
+ ; /* nothing */
+ if (proto == NULL && $7 != NULL) {
+ if ($9.flags.b1 || $9.flags.b2)
+ yyerror(
+ "flags only apply to tcp");
+ if ($8.src_os)
+ yyerror(
+ "OS fingerprinting only "
+ "apply to tcp");
+ YYERROR;
+ }
+#if 0
+ if (($9.flags.b1 & parse_flags("S")) == 0 &&
+ $8.src_os) {
+ yyerror("OS fingerprinting requires "
+ "the SYN TCP flag (flags S/SA)");
+ YYERROR;
+ }
+#endif
+ }
+
+ r.tos = $9.tos;
+ r.keep_state = $9.keep.action;
+ o = $9.keep.options;
+
+ /* 'keep state' by default on pass rules. */
+ if (!r.keep_state && !r.action &&
+ !($9.marker & FOM_KEEP)) {
+ r.keep_state = PF_STATE_NORMAL;
+ o = keep_state_defaults;
+ defaults = 1;
+ }
+
+ while (o) {
+ struct node_state_opt *p = o;
+
+ switch (o->type) {
+ case PF_STATE_OPT_MAX:
+ if (r.max_states) {
+ yyerror("state option 'max' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.max_states = o->data.max_states;
+ break;
+ case PF_STATE_OPT_NOSYNC:
+ if (r.rule_flag & PFRULE_NOSYNC) {
+ yyerror("state option 'sync' "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_NOSYNC;
+ break;
+ case PF_STATE_OPT_SRCTRACK:
+ if (srctrack) {
+ yyerror("state option "
+ "'source-track' "
+ "multiple definitions");
+ YYERROR;
+ }
+ srctrack = o->data.src_track;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_STATES:
+ if (r.max_src_states) {
+ yyerror("state option "
+ "'max-src-states' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_states == 0) {
+ yyerror("'max-src-states' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_states =
+ o->data.max_src_states;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ break;
+ case PF_STATE_OPT_OVERLOAD:
+ if (r.overload_tblname[0]) {
+ yyerror("multiple 'overload' "
+ "table definitions");
+ YYERROR;
+ }
+ if (strlcpy(r.overload_tblname,
+ o->data.overload.tblname,
+ PF_TABLE_NAME_SIZE) >=
+ PF_TABLE_NAME_SIZE) {
+ yyerror("state option: "
+ "strlcpy");
+ YYERROR;
+ }
+ r.flush = o->data.overload.flush;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN:
+ if (r.max_src_conn) {
+ yyerror("state option "
+ "'max-src-conn' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_conn == 0) {
+ yyerror("'max-src-conn' "
+ "must be > 0");
+ YYERROR;
+ }
+ r.max_src_conn =
+ o->data.max_src_conn;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_CONN_RATE:
+ if (r.max_src_conn_rate.limit) {
+ yyerror("state option "
+ "'max-src-conn-rate' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (!o->data.max_src_conn_rate.limit ||
+ !o->data.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' "
+ "values must be > 0");
+ YYERROR;
+ }
+ if (o->data.max_src_conn_rate.limit >
+ PF_THRESHOLD_MAX) {
+ yyerror("'max-src-conn-rate' "
+ "maximum rate must be < %u",
+ PF_THRESHOLD_MAX);
+ YYERROR;
+ }
+ r.max_src_conn_rate.limit =
+ o->data.max_src_conn_rate.limit;
+ r.max_src_conn_rate.seconds =
+ o->data.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_MAX_SRC_NODES:
+ if (r.max_src_nodes) {
+ yyerror("state option "
+ "'max-src-nodes' "
+ "multiple definitions");
+ YYERROR;
+ }
+ if (o->data.max_src_nodes == 0) {
+ yyerror("'max-src-nodes' must "
+ "be > 0");
+ YYERROR;
+ }
+ r.max_src_nodes =
+ o->data.max_src_nodes;
+ r.rule_flag |= PFRULE_SRCTRACK |
+ PFRULE_RULESRCTRACK;
+ break;
+ case PF_STATE_OPT_STATELOCK:
+ if (statelock) {
+ yyerror("state locking option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ statelock = 1;
+ r.rule_flag |= o->data.statelock;
+ break;
+ case PF_STATE_OPT_SLOPPY:
+ if (r.rule_flag & PFRULE_STATESLOPPY) {
+ yyerror("state sloppy option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_STATESLOPPY;
+ break;
+ case PF_STATE_OPT_TIMEOUT:
+ if (o->data.timeout.number ==
+ PFTM_ADAPTIVE_START ||
+ o->data.timeout.number ==
+ PFTM_ADAPTIVE_END)
+ adaptive = 1;
+ if (r.timeout[o->data.timeout.number]) {
+ yyerror("state timeout %s "
+ "multiple definitions",
+ pf_timeouts[o->data.
+ timeout.number].name);
+ YYERROR;
+ }
+ r.timeout[o->data.timeout.number] =
+ o->data.timeout.seconds;
+ }
+ o = o->next;
+ if (!defaults)
+ free(p);
+ }
+
+ /* 'flags S/SA' by default on stateful rules */
+ if (!r.action && !r.flags && !r.flagset &&
+ !$9.fragment && !($9.marker & FOM_FLAGS) &&
+ r.keep_state) {
+ r.flags = parse_flags("S");
+ r.flagset = parse_flags("SA");
+ }
+ if (!adaptive && r.max_states) {
+ r.timeout[PFTM_ADAPTIVE_START] =
+ (r.max_states / 10) * 6;
+ r.timeout[PFTM_ADAPTIVE_END] =
+ (r.max_states / 10) * 12;
+ }
+ if (r.rule_flag & PFRULE_SRCTRACK) {
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_nodes) {
+ yyerror("'max-src-nodes' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn) {
+ yyerror("'max-src-conn' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (srctrack == PF_SRCTRACK_GLOBAL &&
+ r.max_src_conn_rate.seconds) {
+ yyerror("'max-src-conn-rate' is "
+ "incompatible with "
+ "'source-track global'");
+ YYERROR;
+ }
+ if (r.timeout[PFTM_SRC_NODE] <
+ r.max_src_conn_rate.seconds)
+ r.timeout[PFTM_SRC_NODE] =
+ r.max_src_conn_rate.seconds;
+ r.rule_flag |= PFRULE_SRCTRACK;
+ if (srctrack == PF_SRCTRACK_RULE)
+ r.rule_flag |= PFRULE_RULESRCTRACK;
+ }
+ if (r.keep_state && !statelock)
+ r.rule_flag |= default_statelock;
+
+ if ($9.fragment)
+ r.rule_flag |= PFRULE_FRAGMENT;
+ r.allow_opts = $9.allowopts;
+
+ decide_address_family($8.src.host, &r.af);
+ decide_address_family($8.dst.host, &r.af);
+
+ if ($5.rt) {
+ if (!r.direction) {
+ yyerror("direction must be explicit "
+ "with rules that specify routing");
+ YYERROR;
+ }
+ r.rt = $5.rt;
+ r.rpool.opts = $5.pool_opts;
+ if ($5.key != NULL)
+ memcpy(&r.rpool.key, $5.key,
+ sizeof(struct pf_poolhashkey));
+ }
+ if (r.rt && r.rt != PF_FASTROUTE) {
+ decide_address_family($5.host, &r.af);
+ remove_invalid_hosts(&$5.host, &r.af);
+ if ($5.host == NULL) {
+ yyerror("no routing address with "
+ "matching address family found.");
+ YYERROR;
+ }
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($5.host->next != NULL ||
+ $5.host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($5.host->addr)))
+ r.rpool.opts |= PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($5.host, "tables are only "
+ "supported in round-robin routing pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($5.host, "interface (%s) "
+ "is only supported in round-robin "
+ "routing pools"))
+ YYERROR;
+ if ($5.host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("r.rpool.opts must "
+ "be PF_POOL_ROUNDROBIN");
+ YYERROR;
+ }
+ }
+ }
+ if ($9.queues.qname != NULL) {
+ if (strlcpy(r.qname, $9.queues.qname,
+ sizeof(r.qname)) >= sizeof(r.qname)) {
+ yyerror("rule qname too long (max "
+ "%d chars)", sizeof(r.qname)-1);
+ YYERROR;
+ }
+ free($9.queues.qname);
+ }
+ if ($9.queues.pqname != NULL) {
+ if (strlcpy(r.pqname, $9.queues.pqname,
+ sizeof(r.pqname)) >= sizeof(r.pqname)) {
+ yyerror("rule pqname too long (max "
+ "%d chars)", sizeof(r.pqname)-1);
+ YYERROR;
+ }
+ free($9.queues.pqname);
+ }
+#ifdef __FreeBSD__
+ r.divert.port = $9.divert.port;
+#else
+ if ((r.divert.port = $9.divert.port)) {
+ if (r.direction == PF_OUT) {
+ if ($9.divert.addr) {
+ yyerror("address specified "
+ "for outgoing divert");
+ YYERROR;
+ }
+ bzero(&r.divert.addr,
+ sizeof(r.divert.addr));
+ } else {
+ if (!$9.divert.addr) {
+ yyerror("no address specified "
+ "for incoming divert");
+ YYERROR;
+ }
+ if ($9.divert.addr->af != r.af) {
+ yyerror("address family "
+ "mismatch for divert");
+ YYERROR;
+ }
+ r.divert.addr =
+ $9.divert.addr->addr.v.a.addr;
+ }
+ }
+#endif
+
+ expand_rule(&r, $4, $5.host, $7, $8.src_os,
+ $8.src.host, $8.src.port, $8.dst.host, $8.dst.port,
+ $9.uid, $9.gid, $9.icmpspec, "");
+ }
+ ;
+
+filter_opts : {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ }
+ filter_opts_l
+ { $$ = filter_opts; }
+ | /* empty */ {
+ bzero(&filter_opts, sizeof filter_opts);
+ filter_opts.rtableid = -1;
+ $$ = filter_opts;
+ }
+ ;
+
+filter_opts_l : filter_opts_l filter_opt
+ | filter_opt
+ ;
+
+filter_opt : USER uids {
+ if (filter_opts.uid)
+ $2->tail->next = filter_opts.uid;
+ filter_opts.uid = $2;
+ }
+ | GROUP gids {
+ if (filter_opts.gid)
+ $2->tail->next = filter_opts.gid;
+ filter_opts.gid = $2;
+ }
+ | flags {
+ if (filter_opts.marker & FOM_FLAGS) {
+ yyerror("flags cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_FLAGS;
+ filter_opts.flags.b1 |= $1.b1;
+ filter_opts.flags.b2 |= $1.b2;
+ filter_opts.flags.w |= $1.w;
+ filter_opts.flags.w2 |= $1.w2;
+ }
+ | icmpspec {
+ if (filter_opts.marker & FOM_ICMP) {
+ yyerror("icmp-type cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_ICMP;
+ filter_opts.icmpspec = $1;
+ }
+ | PRIO NUMBER {
+ if (filter_opts.marker & FOM_PRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_PRIO;
+ filter_opts.prio = $2;
+ }
+ | TOS tos {
+ if (filter_opts.marker & FOM_TOS) {
+ yyerror("tos cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_TOS;
+ filter_opts.tos = $2;
+ }
+ | keep {
+ if (filter_opts.marker & FOM_KEEP) {
+ yyerror("modulate or keep cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_KEEP;
+ filter_opts.keep.action = $1.action;
+ filter_opts.keep.options = $1.options;
+ }
+ | FRAGMENT {
+ filter_opts.fragment = 1;
+ }
+ | ALLOWOPTS {
+ filter_opts.allowopts = 1;
+ }
+ | label {
+ if (filter_opts.label) {
+ yyerror("label cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.label = $1;
+ }
+ | qname {
+ if (filter_opts.queues.qname) {
+ yyerror("queue cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.queues = $1;
+ }
+ | TAG string {
+ filter_opts.tag = $2;
+ }
+ | not TAGGED string {
+ filter_opts.match_tag = $3;
+ filter_opts.match_tag_not = $1;
+ }
+ | PROBABILITY probability {
+ double p;
+
+ p = floor($2 * UINT_MAX + 0.5);
+ if (p < 0.0 || p > UINT_MAX) {
+ yyerror("invalid probability: %lf", p);
+ YYERROR;
+ }
+ filter_opts.prob = (u_int32_t)p;
+ if (filter_opts.prob == 0)
+ filter_opts.prob = 1;
+ }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ filter_opts.rtableid = $2;
+ }
+ | DIVERTTO portplain {
+#ifdef __FreeBSD__
+ filter_opts.divert.port = $2.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs($2.a));
+ YYERROR;
+ }
+#endif
+ }
+ | DIVERTTO STRING PORT portplain {
+#ifndef __FreeBSD__
+ if ((filter_opts.divert.addr = host($2)) == NULL) {
+ yyerror("could not parse divert address: %s",
+ $2);
+ free($2);
+ YYERROR;
+ }
+#else
+ if ($2)
+#endif
+ free($2);
+ filter_opts.divert.port = $4.a;
+ if (!filter_opts.divert.port) {
+ yyerror("invalid divert port: %u", ntohs($4.a));
+ YYERROR;
+ }
+ }
+ | DIVERTREPLY {
+#ifdef __FreeBSD__
+ yyerror("divert-reply has no meaning in FreeBSD pf(4)");
+ YYERROR;
+#else
+ filter_opts.divert.port = 1; /* some random value */
+#endif
+ }
+ | filter_sets
+ ;
+
+filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; }
+ | SET filter_set { $$ = filter_opts; }
+ ;
+
+filter_sets_l : filter_sets_l comma filter_set
+ | filter_set
+ ;
+
+filter_set : prio {
+ if (filter_opts.marker & FOM_SETPRIO) {
+ yyerror("prio cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.marker |= FOM_SETPRIO;
+ filter_opts.set_prio[0] = $1.b1;
+ filter_opts.set_prio[1] = $1.b2;
+ }
+prio : PRIO NUMBER {
+ if ($2 < 0 || $2 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ $$.b1 = $$.b2 = $2;
+ }
+ | PRIO '(' NUMBER comma NUMBER ')' {
+ if ($3 < 0 || $3 > PF_PRIO_MAX ||
+ $5 < 0 || $5 > PF_PRIO_MAX) {
+ yyerror("prio must be 0 - %u", PF_PRIO_MAX);
+ YYERROR;
+ }
+ $$.b1 = $3;
+ $$.b2 = $5;
+ }
+ ;
+
+probability : STRING {
+ char *e;
+ double p = strtod($1, &e);
+
+ if (*e == '%') {
+ p *= 0.01;
+ e++;
+ }
+ if (*e) {
+ yyerror("invalid probability: %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = p;
+ }
+ | NUMBER {
+ $$ = (double)$1;
+ }
+ ;
+
+
+action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; }
+ | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; }
+ ;
+
+blockspec : /* empty */ {
+ $$.b2 = blockpolicy;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | DROP {
+ $$.b2 = PFRULE_DROP;
+ $$.w = 0;
+ $$.w2 = 0;
+ }
+ | RETURNRST {
+ $$.b2 = PFRULE_RETURNRST;
+ $$.w = 0;
+ $$.w2 = 0;
+ }
+ | RETURNRST '(' TTL NUMBER ')' {
+ if ($4 < 0 || $4 > 255) {
+ yyerror("illegal ttl value %d", $4);
+ YYERROR;
+ }
+ $$.b2 = PFRULE_RETURNRST;
+ $$.w = $4;
+ $$.w2 = 0;
+ }
+ | RETURNICMP {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | RETURNICMP6 {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ | RETURNICMP '(' reticmpspec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = $3;
+ $$.w2 = returnicmpdefault;
+ }
+ | RETURNICMP6 '(' reticmp6spec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = returnicmpdefault;
+ $$.w2 = $3;
+ }
+ | RETURNICMP '(' reticmpspec comma reticmp6spec ')' {
+ $$.b2 = PFRULE_RETURNICMP;
+ $$.w = $3;
+ $$.w2 = $5;
+ }
+ | RETURN {
+ $$.b2 = PFRULE_RETURN;
+ $$.w = returnicmpdefault;
+ $$.w2 = returnicmp6default;
+ }
+ ;
+
+reticmpspec : STRING {
+ if (!($$ = parseicmpspec($1, AF_INET))) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ u_int8_t icmptype;
+
+ if ($1 < 0 || $1 > 255) {
+ yyerror("invalid icmp code %lu", $1);
+ YYERROR;
+ }
+ icmptype = returnicmpdefault >> 8;
+ $$ = (icmptype << 8 | $1);
+ }
+ ;
+
+reticmp6spec : STRING {
+ if (!($$ = parseicmpspec($1, AF_INET6))) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ u_int8_t icmptype;
+
+ if ($1 < 0 || $1 > 255) {
+ yyerror("invalid icmp code %lu", $1);
+ YYERROR;
+ }
+ icmptype = returnicmp6default >> 8;
+ $$ = (icmptype << 8 | $1);
+ }
+ ;
+
+dir : /* empty */ { $$ = PF_INOUT; }
+ | IN { $$ = PF_IN; }
+ | OUT { $$ = PF_OUT; }
+ ;
+
+quick : /* empty */ { $$.quick = 0; }
+ | QUICK { $$.quick = 1; }
+ ;
+
+logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; }
+ | log { $$ = $1; $$.quick = 0; }
+ | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; }
+ | log QUICK { $$ = $1; $$.quick = 1; }
+ | QUICK log { $$ = $2; $$.quick = 1; }
+ ;
+
+log : LOG { $$.log = PF_LOG; $$.logif = 0; }
+ | LOG '(' logopts ')' {
+ $$.log = PF_LOG | $3.log;
+ $$.logif = $3.logif;
+ }
+ ;
+
+logopts : logopt { $$ = $1; }
+ | logopts comma logopt {
+ $$.log = $1.log | $3.log;
+ $$.logif = $3.logif;
+ if ($$.logif == 0)
+ $$.logif = $1.logif;
+ }
+ ;
+
+logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
+ | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | TO string {
+ const char *errstr;
+ u_int i;
+
+ $$.log = 0;
+ if (strncmp($2, "pflog", 5)) {
+ yyerror("%s: should be a pflog interface", $2);
+ free($2);
+ YYERROR;
+ }
+ i = strtonum($2 + 5, 0, 255, &errstr);
+ if (errstr) {
+ yyerror("%s: %s", $2, errstr);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ $$.logif = i;
+ }
+ ;
+
+interface : /* empty */ { $$ = NULL; }
+ | ON if_item_not { $$ = $2; }
+ | ON '{' optnl if_list '}' { $$ = $4; }
+ ;
+
+if_list : if_item_not optnl { $$ = $1; }
+ | if_list comma if_item_not optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+if_item_not : not if_item { $$ = $2; $$->not = $1; }
+ ;
+
+if_item : STRING {
+ struct node_host *n;
+
+ $$ = calloc(1, sizeof(struct node_if));
+ if ($$ == NULL)
+ err(1, "if_item: calloc");
+ if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >=
+ sizeof($$->ifname)) {
+ free($1);
+ free($$);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+
+ if ((n = ifa_exists($1)) != NULL)
+ $$->ifa_flags = n->ifa_flags;
+
+ free($1);
+ $$->not = 0;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+af : /* empty */ { $$ = 0; }
+ | INET { $$ = AF_INET; }
+ | INET6 { $$ = AF_INET6; }
+ ;
+
+proto : /* empty */ { $$ = NULL; }
+ | PROTO proto_item { $$ = $2; }
+ | PROTO '{' optnl proto_list '}' { $$ = $4; }
+ ;
+
+proto_list : proto_item optnl { $$ = $1; }
+ | proto_list comma proto_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+proto_item : protoval {
+ u_int8_t pr;
+
+ pr = (u_int8_t)$1;
+ if (pr == 0) {
+ yyerror("proto 0 cannot be used");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_proto));
+ if ($$ == NULL)
+ err(1, "proto_item: calloc");
+ $$->proto = pr;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+protoval : STRING {
+ struct protoent *p;
+
+ p = getprotobyname($1);
+ if (p == NULL) {
+ yyerror("unknown protocol %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->p_proto;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("protocol outside range");
+ YYERROR;
+ }
+ }
+ ;
+
+fromto : ALL {
+ $$.src.host = NULL;
+ $$.src.port = NULL;
+ $$.dst.host = NULL;
+ $$.dst.port = NULL;
+ $$.src_os = NULL;
+ }
+ | from os to {
+ $$.src = $1;
+ $$.src_os = $2;
+ $$.dst = $3;
+ }
+ ;
+
+os : /* empty */ { $$ = NULL; }
+ | OS xos { $$ = $2; }
+ | OS '{' optnl os_list '}' { $$ = $4; }
+ ;
+
+xos : STRING {
+ $$ = calloc(1, sizeof(struct node_os));
+ if ($$ == NULL)
+ err(1, "os: calloc");
+ $$->os = $1;
+ $$->tail = $$;
+ }
+ ;
+
+os_list : xos optnl { $$ = $1; }
+ | os_list comma xos optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+from : /* empty */ {
+ $$.host = NULL;
+ $$.port = NULL;
+ }
+ | FROM ipportspec {
+ $$ = $2;
+ }
+ ;
+
+to : /* empty */ {
+ $$.host = NULL;
+ $$.port = NULL;
+ }
+ | TO ipportspec {
+ if (disallow_urpf_failed($2.host, "\"urpf-failed\" is "
+ "not permitted in a destination address"))
+ YYERROR;
+ $$ = $2;
+ }
+ ;
+
+ipportspec : ipspec {
+ $$.host = $1;
+ $$.port = NULL;
+ }
+ | ipspec PORT portspec {
+ $$.host = $1;
+ $$.port = $3;
+ }
+ | PORT portspec {
+ $$.host = NULL;
+ $$.port = $2;
+ }
+ ;
+
+optnl : '\n' optnl
+ |
+ ;
+
+ipspec : ANY { $$ = NULL; }
+ | xhost { $$ = $1; }
+ | '{' optnl host_list '}' { $$ = $3; }
+ ;
+
+toipspec : TO ipspec { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+host_list : ipspec optnl { $$ = $1; }
+ | host_list comma ipspec optnl {
+ if ($3 == NULL)
+ $$ = $1;
+ else if ($1 == NULL)
+ $$ = $3;
+ else {
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ }
+ ;
+
+xhost : not host {
+ struct node_host *n;
+
+ for (n = $2; n != NULL; n = n->next)
+ n->not = $1;
+ $$ = $2;
+ }
+ | not NOROUTE {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "xhost: calloc");
+ $$->addr.type = PF_ADDR_NOROUTE;
+ $$->next = NULL;
+ $$->not = $1;
+ $$->tail = $$;
+ }
+ | not URPFFAILED {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "xhost: calloc");
+ $$->addr.type = PF_ADDR_URPFFAILED;
+ $$->next = NULL;
+ $$->not = $1;
+ $$->tail = $$;
+ }
+ ;
+
+host : STRING {
+ if (($$ = host($1)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free($1);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free($1);
+
+ }
+ | STRING '-' STRING {
+ struct node_host *b, *e;
+
+ if ((b = host($1)) == NULL || (e = host($3)) == NULL) {
+ free($1);
+ free($3);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ if (b->af != e->af ||
+ b->addr.type != PF_ADDR_ADDRMASK ||
+ e->addr.type != PF_ADDR_ADDRMASK ||
+ unmask(&b->addr.v.a.mask, b->af) !=
+ (b->af == AF_INET ? 32 : 128) ||
+ unmask(&e->addr.v.a.mask, e->af) !=
+ (e->af == AF_INET ? 32 : 128) ||
+ b->next != NULL || b->not ||
+ e->next != NULL || e->not) {
+ free(b);
+ free(e);
+ free($1);
+ free($3);
+ yyerror("invalid address range");
+ YYERROR;
+ }
+ memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr,
+ sizeof(b->addr.v.a.mask));
+ b->addr.type = PF_ADDR_RANGE;
+ $$ = b;
+ free(e);
+ free($1);
+ free($3);
+ }
+ | STRING '/' NUMBER {
+ char *buf;
+
+ if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1)
+ err(1, "host: asprintf");
+ free($1);
+ if (($$ = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+ | NUMBER '/' NUMBER {
+ char *buf;
+
+ /* ie. for 10/8 parsing */
+#ifdef __FreeBSD__
+ if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1)
+#else
+ if (asprintf(&buf, "%lld/%lld", $1, $3) == -1)
+#endif
+ err(1, "host: asprintf");
+ if (($$ = host(buf)) == NULL) {
+ /* error. "any" is handled elsewhere */
+ free(buf);
+ yyerror("could not parse host specification");
+ YYERROR;
+ }
+ free(buf);
+ }
+ | dynaddr
+ | dynaddr '/' NUMBER {
+ struct node_host *n;
+
+ if ($3 < 0 || $3 > 128) {
+ yyerror("bit number too big");
+ YYERROR;
+ }
+ $$ = $1;
+ for (n = $1; n != NULL; n = n->next)
+ set_ipmask(n, $3);
+ }
+ | '<' STRING '>' {
+ if (strlen($2) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", $2);
+ free($2);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "host: calloc");
+ $$->addr.type = PF_ADDR_TABLE;
+ if (strlcpy($$->addr.v.tblname, $2,
+ sizeof($$->addr.v.tblname)) >=
+ sizeof($$->addr.v.tblname))
+ errx(1, "host: strlcpy");
+ free($2);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+number : NUMBER
+ | STRING {
+ u_long ulval;
+
+ if (atoul($1, &ulval) == -1) {
+ yyerror("%s is not a number", $1);
+ free($1);
+ YYERROR;
+ } else
+ $$ = ulval;
+ free($1);
+ }
+ ;
+
+dynaddr : '(' STRING ')' {
+ int flags = 0;
+ char *p, *op;
+
+ op = $2;
+ if (!isalpha(op[0])) {
+ yyerror("invalid interface name '%s'", op);
+ free(op);
+ YYERROR;
+ }
+ while ((p = strrchr($2, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ yyerror("interface %s has bad modifier",
+ $2);
+ free(op);
+ YYERROR;
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) {
+ free(op);
+ yyerror("illegal combination of "
+ "interface modifiers");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "address: calloc");
+ $$->af = 0;
+ set_ipmask($$, 128);
+ $$->addr.type = PF_ADDR_DYNIFTL;
+ $$->addr.iflags = flags;
+ if (strlcpy($$->addr.v.ifname, $2,
+ sizeof($$->addr.v.ifname)) >=
+ sizeof($$->addr.v.ifname)) {
+ free(op);
+ free($$);
+ yyerror("interface name too long");
+ YYERROR;
+ }
+ free(op);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+portspec : port_item { $$ = $1; }
+ | '{' optnl port_list '}' { $$ = $3; }
+ ;
+
+port_list : port_item optnl { $$ = $1; }
+ | port_list comma port_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+port_item : portrange {
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $1.a;
+ $$->port[1] = $1.b;
+ if ($1.t)
+ $$->op = PF_OP_RRG;
+ else
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop portrange {
+ if ($2.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $2.a;
+ $$->port[1] = $2.b;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | portrange PORTBINARY portrange {
+ if ($1.t || $3.t) {
+ yyerror("':' cannot be used with an other "
+ "port operator");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_port));
+ if ($$ == NULL)
+ err(1, "port_item: calloc");
+ $$->port[0] = $1.a;
+ $$->port[1] = $3.a;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+portplain : numberstring {
+ if (parseport($1, &$$, 0) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+portrange : numberstring {
+ if (parseport($1, &$$, PPORT_RANGE) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+uids : uid_item { $$ = $1; }
+ | '{' optnl uid_list '}' { $$ = $3; }
+ ;
+
+uid_list : uid_item optnl { $$ = $1; }
+ | uid_list comma uid_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+uid_item : uid {
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $1;
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop uid {
+ if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $2;
+ $$->uid[1] = $2;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | uid PORTBINARY uid {
+ if ($1 == UID_MAX || $3 == UID_MAX) {
+ yyerror("user unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_uid));
+ if ($$ == NULL)
+ err(1, "uid_item: calloc");
+ $$->uid[0] = $1;
+ $$->uid[1] = $3;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+uid : STRING {
+ if (!strcmp($1, "unknown"))
+ $$ = UID_MAX;
+ else {
+ struct passwd *pw;
+
+ if ((pw = getpwnam($1)) == NULL) {
+ yyerror("unknown user %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = pw->pw_uid;
+ }
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 >= UID_MAX) {
+ yyerror("illegal uid value %lu", $1);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+gids : gid_item { $$ = $1; }
+ | '{' optnl gid_list '}' { $$ = $3; }
+ ;
+
+gid_list : gid_item optnl { $$ = $1; }
+ | gid_list comma gid_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+gid_item : gid {
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $1;
+ $$->gid[1] = $1;
+ $$->op = PF_OP_EQ;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | unaryop gid {
+ if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $2;
+ $$->gid[1] = $2;
+ $$->op = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | gid PORTBINARY gid {
+ if ($1 == GID_MAX || $3 == GID_MAX) {
+ yyerror("group unknown requires operator = or "
+ "!=");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_gid));
+ if ($$ == NULL)
+ err(1, "gid_item: calloc");
+ $$->gid[0] = $1;
+ $$->gid[1] = $3;
+ $$->op = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+gid : STRING {
+ if (!strcmp($1, "unknown"))
+ $$ = GID_MAX;
+ else {
+ struct group *grp;
+
+ if ((grp = getgrnam($1)) == NULL) {
+ yyerror("unknown group %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = grp->gr_gid;
+ }
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 >= GID_MAX) {
+ yyerror("illegal gid value %lu", $1);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+flag : STRING {
+ int f;
+
+ if ((f = parse_flags($1)) < 0) {
+ yyerror("bad flags %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$.b1 = f;
+ }
+ ;
+
+flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; }
+ | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; }
+ | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; }
+ ;
+
+icmpspec : ICMPTYPE icmp_item { $$ = $2; }
+ | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; }
+ | ICMP6TYPE icmp6_item { $$ = $2; }
+ | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; }
+ ;
+
+icmp_list : icmp_item optnl { $$ = $1; }
+ | icmp_list comma icmp_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+icmp6_list : icmp6_item optnl { $$ = $1; }
+ | icmp6_list comma icmp6_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+icmp_item : icmptype {
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = 0;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmptype CODE STRING {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) {
+ yyerror("unknown icmp-code %s", $3);
+ free($3);
+ YYERROR;
+ }
+
+ free($3);
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = p->code + 1;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmptype CODE NUMBER {
+ if ($3 < 0 || $3 > 255) {
+ yyerror("illegal icmp-code %lu", $3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = $3 + 1;
+ $$->proto = IPPROTO_ICMP;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+icmp6_item : icmp6type {
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = 0;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmp6type CODE STRING {
+ const struct icmpcodeent *p;
+
+ if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) {
+ yyerror("unknown icmp6-code %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = p->code + 1;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | icmp6type CODE NUMBER {
+ if ($3 < 0 || $3 > 255) {
+ yyerror("illegal icmp-code %lu", $3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_icmp));
+ if ($$ == NULL)
+ err(1, "icmp_item: calloc");
+ $$->type = $1;
+ $$->code = $3 + 1;
+ $$->proto = IPPROTO_ICMPV6;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+icmptype : STRING {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname($1, AF_INET)) == NULL) {
+ yyerror("unknown icmp-type %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->type + 1;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("illegal icmp-type %lu", $1);
+ YYERROR;
+ }
+ $$ = $1 + 1;
+ }
+ ;
+
+icmp6type : STRING {
+ const struct icmptypeent *p;
+
+ if ((p = geticmptypebyname($1, AF_INET6)) ==
+ NULL) {
+ yyerror("unknown icmp6-type %s", $1);
+ free($1);
+ YYERROR;
+ }
+ $$ = p->type + 1;
+ free($1);
+ }
+ | NUMBER {
+ if ($1 < 0 || $1 > 255) {
+ yyerror("illegal icmp6-type %lu", $1);
+ YYERROR;
+ }
+ $$ = $1 + 1;
+ }
+ ;
+
+tos : STRING {
+ if (!strcmp($1, "lowdelay"))
+ $$ = IPTOS_LOWDELAY;
+ else if (!strcmp($1, "throughput"))
+ $$ = IPTOS_THROUGHPUT;
+ else if (!strcmp($1, "reliability"))
+ $$ = IPTOS_RELIABILITY;
+ else if ($1[0] == '0' && $1[1] == 'x')
+ $$ = strtoul($1, NULL, 16);
+ else
+ $$ = 256; /* flag bad argument */
+ if ($$ < 0 || $$ > 255) {
+ yyerror("illegal tos value %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ $$ = $1;
+ if ($$ < 0 || $$ > 255) {
+ yyerror("illegal tos value %s", $1);
+ YYERROR;
+ }
+ }
+ ;
+
+sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; }
+ | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; }
+ | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; }
+ ;
+
+statelock : IFBOUND {
+ $$ = PFRULE_IFBOUND;
+ }
+ | FLOATING {
+ $$ = 0;
+ }
+ ;
+
+keep : NO STATE {
+ $$.action = 0;
+ $$.options = NULL;
+ }
+ | KEEP STATE state_opt_spec {
+ $$.action = PF_STATE_NORMAL;
+ $$.options = $3;
+ }
+ | MODULATE STATE state_opt_spec {
+ $$.action = PF_STATE_MODULATE;
+ $$.options = $3;
+ }
+ | SYNPROXY STATE state_opt_spec {
+ $$.action = PF_STATE_SYNPROXY;
+ $$.options = $3;
+ }
+ ;
+
+flush : /* empty */ { $$ = 0; }
+ | FLUSH { $$ = PF_FLUSH; }
+ | FLUSH GLOBAL {
+ $$ = PF_FLUSH | PF_FLUSH_GLOBAL;
+ }
+ ;
+
+state_opt_spec : '(' state_opt_list ')' { $$ = $2; }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+state_opt_list : state_opt_item { $$ = $1; }
+ | state_opt_list comma state_opt_item {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+state_opt_item : MAXIMUM NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX;
+ $$->data.max_states = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | NOSYNC {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_NOSYNC;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCSTATES NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_STATES;
+ $$->data.max_src_states = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCCONN NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_CONN;
+ $$->data.max_src_conn = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCCONNRATE NUMBER '/' NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX ||
+ $4 < 0 || $4 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE;
+ $$->data.max_src_conn_rate.limit = $2;
+ $$->data.max_src_conn_rate.seconds = $4;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | OVERLOAD '<' STRING '>' flush {
+ if (strlen($3) >= PF_TABLE_NAME_SIZE) {
+ yyerror("table name '%s' too long", $3);
+ free($3);
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ if (strlcpy($$->data.overload.tblname, $3,
+ PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE)
+ errx(1, "state_opt_item: strlcpy");
+ free($3);
+ $$->type = PF_STATE_OPT_OVERLOAD;
+ $$->data.overload.flush = $5;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | MAXSRCNODES NUMBER {
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_MAX_SRC_NODES;
+ $$->data.max_src_nodes = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | sourcetrack {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_SRCTRACK;
+ $$->data.src_track = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | statelock {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_STATELOCK;
+ $$->data.statelock = $1;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | SLOPPY {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_SLOPPY;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | STRING NUMBER {
+ int i;
+
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ for (i = 0; pf_timeouts[i].name &&
+ strcmp(pf_timeouts[i].name, $1); ++i)
+ ; /* nothing */
+ if (!pf_timeouts[i].name) {
+ yyerror("illegal timeout name %s", $1);
+ free($1);
+ YYERROR;
+ }
+ if (strchr(pf_timeouts[i].name, '.') == NULL) {
+ yyerror("illegal state timeout %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_TIMEOUT;
+ $$->data.timeout.number = pf_timeouts[i].timeout;
+ $$->data.timeout.seconds = $2;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+label : LABEL STRING {
+ $$ = $2;
+ }
+ ;
+
+qname : QUEUE STRING {
+ $$.qname = $2;
+ $$.pqname = NULL;
+ }
+ | QUEUE '(' STRING ')' {
+ $$.qname = $3;
+ $$.pqname = NULL;
+ }
+ | QUEUE '(' STRING comma STRING ')' {
+ $$.qname = $3;
+ $$.pqname = $5;
+ }
+ ;
+
+no : /* empty */ { $$ = 0; }
+ | NO { $$ = 1; }
+ ;
+
+portstar : numberstring {
+ if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) {
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+redirspec : host { $$ = $1; }
+ | '{' optnl redir_host_list '}' { $$ = $3; }
+ ;
+
+redir_host_list : host optnl { $$ = $1; }
+ | redir_host_list comma host optnl {
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ ;
+
+redirpool : /* empty */ { $$ = NULL; }
+ | ARROW redirspec {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport.a = $$->rport.b = $$->rport.t = 0;
+ }
+ | ARROW redirspec PORT portstar {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport = $4;
+ }
+ ;
+
+hashkey : /* empty */
+ {
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+ $$->key32[0] = arc4random();
+ $$->key32[1] = arc4random();
+ $$->key32[2] = arc4random();
+ $$->key32[3] = arc4random();
+ }
+ | string
+ {
+ if (!strncmp($1, "0x", 2)) {
+ if (strlen($1) != 34) {
+ free($1);
+ yyerror("hex key must be 128 bits "
+ "(32 hex digits) long");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+
+ if (sscanf($1, "0x%8x%8x%8x%8x",
+ &$$->key32[0], &$$->key32[1],
+ &$$->key32[2], &$$->key32[3]) != 4) {
+ free($$);
+ free($1);
+ yyerror("invalid hex key");
+ YYERROR;
+ }
+ } else {
+ MD5_CTX context;
+
+ $$ = calloc(1, sizeof(struct pf_poolhashkey));
+ if ($$ == NULL)
+ err(1, "hashkey: calloc");
+ MD5Init(&context);
+ MD5Update(&context, (unsigned char *)$1,
+ strlen($1));
+ MD5Final((unsigned char *)$$, &context);
+ HTONL($$->key32[0]);
+ HTONL($$->key32[1]);
+ HTONL($$->key32[2]);
+ HTONL($$->key32[3]);
+ }
+ free($1);
+ }
+ ;
+
+pool_opts : { bzero(&pool_opts, sizeof pool_opts); }
+ pool_opts_l
+ { $$ = pool_opts; }
+ | /* empty */ {
+ bzero(&pool_opts, sizeof pool_opts);
+ $$ = pool_opts;
+ }
+ ;
+
+pool_opts_l : pool_opts_l pool_opt
+ | pool_opt
+ ;
+
+pool_opt : BITMASK {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_BITMASK;
+ }
+ | RANDOM {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_RANDOM;
+ }
+ | SOURCEHASH hashkey {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_SRCHASH;
+ pool_opts.key = $2;
+ }
+ | ROUNDROBIN {
+ if (pool_opts.type) {
+ yyerror("pool type cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.type = PF_POOL_ROUNDROBIN;
+ }
+ | STATICPORT {
+ if (pool_opts.staticport) {
+ yyerror("static-port cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.staticport = 1;
+ }
+ | STICKYADDRESS {
+ if (filter_opts.marker & POM_STICKYADDRESS) {
+ yyerror("sticky-address cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_STICKYADDRESS;
+ pool_opts.opts |= PF_POOL_STICKYADDR;
+ }
+ ;
+
+redirection : /* empty */ { $$ = NULL; }
+ | ARROW host {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport.a = $$->rport.b = $$->rport.t = 0;
+ }
+ | ARROW host PORT portstar {
+ $$ = calloc(1, sizeof(struct redirection));
+ if ($$ == NULL)
+ err(1, "redirection: calloc");
+ $$->host = $2;
+ $$->rport = $4;
+ }
+ ;
+
+natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; }
+ | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; }
+ | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; }
+ | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; }
+ ;
+
+nataction : no NAT natpasslog {
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ $$.b1 = PF_NONAT;
+ else
+ $$.b1 = PF_NAT;
+ $$.b2 = $3.b1;
+ $$.w = $3.b2;
+ $$.w2 = $3.w2;
+ }
+ | no RDR natpasslog {
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ $$.b1 = PF_NORDR;
+ else
+ $$.b1 = PF_RDR;
+ $$.b2 = $3.b1;
+ $$.w = $3.b2;
+ $$.w2 = $3.w2;
+ }
+ ;
+
+natrule : nataction interface af proto fromto tag tagged rtable
+ redirpool pool_opts
+ {
+ struct pf_rule r;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+
+ memset(&r, 0, sizeof(r));
+
+ r.action = $1.b1;
+ r.natpass = $1.b2;
+ r.log = $1.w;
+ r.logif = $1.w2;
+ r.af = $3;
+
+ if (!r.af) {
+ if ($5.src.host && $5.src.host->af &&
+ !$5.src.host->ifindex)
+ r.af = $5.src.host->af;
+ else if ($5.dst.host && $5.dst.host->af &&
+ !$5.dst.host->ifindex)
+ r.af = $5.dst.host->af;
+ }
+
+ if ($6 != NULL)
+ if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >=
+ PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+
+ if ($7.name)
+ if (strlcpy(r.match_tagname, $7.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ r.match_tag_not = $7.neg;
+ r.rtableid = $8;
+
+ if (r.action == PF_NONAT || r.action == PF_NORDR) {
+ if ($9 != NULL) {
+ yyerror("translation rule with 'no' "
+ "does not need '->'");
+ YYERROR;
+ }
+ } else {
+ if ($9 == NULL || $9->host == NULL) {
+ yyerror("translation rule requires '-> "
+ "address'");
+ YYERROR;
+ }
+ if (!r.af && ! $9->host->ifindex)
+ r.af = $9->host->af;
+
+ remove_invalid_hosts(&$9->host, &r.af);
+ if (invalid_redirect($9->host, r.af))
+ YYERROR;
+ if (check_netmask($9->host, r.af))
+ YYERROR;
+
+ r.rpool.proxy_port[0] = ntohs($9->rport.a);
+
+ switch (r.action) {
+ case PF_RDR:
+ if (!$9->rport.b && $9->rport.t &&
+ $5.dst.port != NULL) {
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.a) +
+ (ntohs(
+ $5.dst.port->port[1]) -
+ ntohs(
+ $5.dst.port->port[0]));
+ } else
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.b);
+ break;
+ case PF_NAT:
+ r.rpool.proxy_port[1] =
+ ntohs($9->rport.b);
+ if (!r.rpool.proxy_port[0] &&
+ !r.rpool.proxy_port[1]) {
+ r.rpool.proxy_port[0] =
+ PF_NAT_PROXY_PORT_LOW;
+ r.rpool.proxy_port[1] =
+ PF_NAT_PROXY_PORT_HIGH;
+ } else if (!r.rpool.proxy_port[1])
+ r.rpool.proxy_port[1] =
+ r.rpool.proxy_port[0];
+ break;
+ default:
+ break;
+ }
+
+ r.rpool.opts = $10.type;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_NONE && ($9->host->next != NULL ||
+ $9->host->addr.type == PF_ADDR_TABLE ||
+ DYNIF_MULTIADDR($9->host->addr)))
+ r.rpool.opts = PF_POOL_ROUNDROBIN;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_table($9->host, "tables are only "
+ "supported in round-robin redirection "
+ "pools"))
+ YYERROR;
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN &&
+ disallow_alias($9->host, "interface (%s) "
+ "is only supported in round-robin "
+ "redirection pools"))
+ YYERROR;
+ if ($9->host->next != NULL) {
+ if ((r.rpool.opts & PF_POOL_TYPEMASK) !=
+ PF_POOL_ROUNDROBIN) {
+ yyerror("only round-robin "
+ "valid for multiple "
+ "redirection addresses");
+ YYERROR;
+ }
+ }
+ }
+
+ if ($10.key != NULL)
+ memcpy(&r.rpool.key, $10.key,
+ sizeof(struct pf_poolhashkey));
+
+ if ($10.opts)
+ r.rpool.opts |= $10.opts;
+
+ if ($10.staticport) {
+ if (r.action != PF_NAT) {
+ yyerror("the 'static-port' option is "
+ "only valid with nat rules");
+ YYERROR;
+ }
+ if (r.rpool.proxy_port[0] !=
+ PF_NAT_PROXY_PORT_LOW &&
+ r.rpool.proxy_port[1] !=
+ PF_NAT_PROXY_PORT_HIGH) {
+ yyerror("the 'static-port' option can't"
+ " be used when specifying a port"
+ " range");
+ YYERROR;
+ }
+ r.rpool.proxy_port[0] = 0;
+ r.rpool.proxy_port[1] = 0;
+ }
+
+ expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4,
+ $5.src_os, $5.src.host, $5.src.port, $5.dst.host,
+ $5.dst.port, 0, 0, 0, "");
+ free($9);
+ }
+ ;
+
+binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag
+ tagged rtable redirection
+ {
+ struct pf_rule binat;
+ struct pf_pooladdr *pa;
+
+ if (check_rulestate(PFCTL_STATE_NAT))
+ YYERROR;
+ if (disallow_urpf_failed($9, "\"urpf-failed\" is not "
+ "permitted as a binat destination"))
+ YYERROR;
+
+ memset(&binat, 0, sizeof(binat));
+
+ if ($1 && $3.b1) {
+ yyerror("\"pass\" not valid with \"no\"");
+ YYERROR;
+ }
+ if ($1)
+ binat.action = PF_NOBINAT;
+ else
+ binat.action = PF_BINAT;
+ binat.natpass = $3.b1;
+ binat.log = $3.b2;
+ binat.logif = $3.w2;
+ binat.af = $5;
+ if (!binat.af && $8 != NULL && $8->af)
+ binat.af = $8->af;
+ if (!binat.af && $9 != NULL && $9->af)
+ binat.af = $9->af;
+
+ if (!binat.af && $13 != NULL && $13->host)
+ binat.af = $13->host->af;
+ if (!binat.af) {
+ yyerror("address family (inet/inet6) "
+ "undefined");
+ YYERROR;
+ }
+
+ if ($4 != NULL) {
+ memcpy(binat.ifname, $4->ifname,
+ sizeof(binat.ifname));
+ binat.ifnot = $4->not;
+ free($4);
+ }
+
+ if ($10 != NULL)
+ if (strlcpy(binat.tagname, $10,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ if ($11.name)
+ if (strlcpy(binat.match_tagname, $11.name,
+ PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) {
+ yyerror("tag too long, max %u chars",
+ PF_TAG_NAME_SIZE - 1);
+ YYERROR;
+ }
+ binat.match_tag_not = $11.neg;
+ binat.rtableid = $12;
+
+ if ($6 != NULL) {
+ binat.proto = $6->proto;
+ free($6);
+ }
+
+ if ($8 != NULL && disallow_table($8, "invalid use of "
+ "table <%s> as the source address of a binat rule"))
+ YYERROR;
+ if ($8 != NULL && disallow_alias($8, "invalid use of "
+ "interface (%s) as the source address of a binat "
+ "rule"))
+ YYERROR;
+ if ($13 != NULL && $13->host != NULL && disallow_table(
+ $13->host, "invalid use of table <%s> as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+ if ($13 != NULL && $13->host != NULL && disallow_alias(
+ $13->host, "invalid use of interface (%s) as the "
+ "redirect address of a binat rule"))
+ YYERROR;
+
+ if ($8 != NULL) {
+ if ($8->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if ($8->addr.type == PF_ADDR_DYNIFTL)
+ $8->af = binat.af;
+ if ($8->af != binat.af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask($8, binat.af))
+ YYERROR;
+ memcpy(&binat.src.addr, &$8->addr,
+ sizeof(binat.src.addr));
+ free($8);
+ }
+ if ($9 != NULL) {
+ if ($9->next) {
+ yyerror("multiple binat ip addresses");
+ YYERROR;
+ }
+ if ($9->af != binat.af && $9->af) {
+ yyerror("binat ip versions must match");
+ YYERROR;
+ }
+ if (check_netmask($9, binat.af))
+ YYERROR;
+ memcpy(&binat.dst.addr, &$9->addr,
+ sizeof(binat.dst.addr));
+ binat.dst.neg = $9->not;
+ free($9);
+ }
+
+ if (binat.action == PF_NOBINAT) {
+ if ($13 != NULL) {
+ yyerror("'no binat' rule does not need"
+ " '->'");
+ YYERROR;
+ }
+ } else {
+ if ($13 == NULL || $13->host == NULL) {
+ yyerror("'binat' rule requires"
+ " '-> address'");
+ YYERROR;
+ }
+
+ remove_invalid_hosts(&$13->host, &binat.af);
+ if (invalid_redirect($13->host, binat.af))
+ YYERROR;
+ if ($13->host->next != NULL) {
+ yyerror("binat rule must redirect to "
+ "a single address");
+ YYERROR;
+ }
+ if (check_netmask($13->host, binat.af))
+ YYERROR;
+
+ if (!PF_AZERO(&binat.src.addr.v.a.mask,
+ binat.af) &&
+ !PF_AEQ(&binat.src.addr.v.a.mask,
+ &$13->host->addr.v.a.mask, binat.af)) {
+ yyerror("'binat' source mask and "
+ "redirect mask must be the same");
+ YYERROR;
+ }
+
+ TAILQ_INIT(&binat.rpool.list);
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "binat: calloc");
+ pa->addr = $13->host->addr;
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&binat.rpool.list,
+ pa, entries);
+
+ free($13);
+ }
+
+ pfctl_add_rule(pf, &binat, "");
+ }
+ ;
+
+tag : /* empty */ { $$ = NULL; }
+ | TAG STRING { $$ = $2; }
+ ;
+
+tagged : /* empty */ { $$.neg = 0; $$.name = NULL; }
+ | not TAGGED string { $$.neg = $1; $$.name = $3; }
+ ;
+
+rtable : /* empty */ { $$ = -1; }
+ | RTABLE NUMBER {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
+ yyerror("invalid rtable id");
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+route_host : STRING {
+ $$ = calloc(1, sizeof(struct node_host));
+ if ($$ == NULL)
+ err(1, "route_host: calloc");
+ $$->ifname = $1;
+ set_ipmask($$, 128);
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ | '(' STRING host ')' {
+ $$ = $3;
+ $$->ifname = $2;
+ }
+ ;
+
+route_host_list : route_host optnl { $$ = $1; }
+ | route_host_list comma route_host optnl {
+ if ($1->af == 0)
+ $1->af = $3->af;
+ if ($1->af != $3->af) {
+ yyerror("all pool addresses must be in the "
+ "same address family");
+ YYERROR;
+ }
+ $1->tail->next = $3;
+ $1->tail = $3->tail;
+ $$ = $1;
+ }
+ ;
+
+routespec : route_host { $$ = $1; }
+ | '{' optnl route_host_list '}' { $$ = $3; }
+ ;
+
+route : /* empty */ {
+ $$.host = NULL;
+ $$.rt = 0;
+ $$.pool_opts = 0;
+ }
+ | FASTROUTE {
+ $$.host = NULL;
+ $$.rt = PF_FASTROUTE;
+ $$.pool_opts = 0;
+ }
+ | ROUTETO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_ROUTETO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ | REPLYTO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_REPLYTO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ | DUPTO routespec pool_opts {
+ $$.host = $2;
+ $$.rt = PF_DUPTO;
+ $$.pool_opts = $3.type | $3.opts;
+ if ($3.key != NULL)
+ $$.key = $3.key;
+ }
+ ;
+
+timeout_spec : STRING NUMBER
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, $1, $2, 0) != 0) {
+ yyerror("unknown timeout %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | INTERVAL NUMBER {
+ if (check_rulestate(PFCTL_STATE_OPTION))
+ YYERROR;
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_timeout(pf, "interval", $2, 0) != 0)
+ YYERROR;
+ }
+ ;
+
+timeout_list : timeout_list comma timeout_spec optnl
+ | timeout_spec optnl
+ ;
+
+limit_spec : STRING NUMBER
+ {
+ if (check_rulestate(PFCTL_STATE_OPTION)) {
+ free($1);
+ YYERROR;
+ }
+ if ($2 < 0 || $2 > UINT_MAX) {
+ yyerror("only positive values permitted");
+ YYERROR;
+ }
+ if (pfctl_set_limit(pf, $1, $2) != 0) {
+ yyerror("unable to set limit %s %u", $1, $2);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+limit_list : limit_list comma limit_spec optnl
+ | limit_spec optnl
+ ;
+
+comma : ','
+ | /* empty */
+ ;
+
+yesno : NO { $$ = 0; }
+ | STRING {
+ if (!strcmp($1, "yes"))
+ $$ = 1;
+ else {
+ yyerror("invalid value '%s', expected 'yes' "
+ "or 'no'", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
+
+unaryop : '=' { $$ = PF_OP_EQ; }
+ | '!' '=' { $$ = PF_OP_NE; }
+ | '<' '=' { $$ = PF_OP_LE; }
+ | '<' { $$ = PF_OP_LT; }
+ | '>' '=' { $$ = PF_OP_GE; }
+ | '>' { $$ = PF_OP_GT; }
+ ;
+
+%%
+#ifdef __rtems__
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack);
+#endif /* __rtems__ */
+
+int
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ file->errors++;
+ va_start(ap, fmt);
+ fprintf(stderr, "%s:%d: ", file->name, yylval.lineno);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ return (0);
+}
+
+int
+disallow_table(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_TABLE) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_urpf_failed(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (h->addr.type == PF_ADDR_URPFFAILED) {
+ yyerror(fmt);
+ return (1);
+ }
+ return (0);
+}
+
+int
+disallow_alias(struct node_host *h, const char *fmt)
+{
+ for (; h != NULL; h = h->next)
+ if (DYNIF_MULTIADDR(h->addr)) {
+ yyerror(fmt, h->addr.v.tblname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+rule_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ switch (r->action) {
+ case PF_PASS:
+ case PF_DROP:
+ case PF_SCRUB:
+ case PF_NOSCRUB:
+ problems = filter_consistent(r, anchor_call);
+ break;
+ case PF_NAT:
+ case PF_NONAT:
+ problems = nat_consistent(r);
+ break;
+ case PF_RDR:
+ case PF_NORDR:
+ problems = rdr_consistent(r);
+ break;
+ case PF_BINAT:
+ case PF_NOBINAT:
+ default:
+ break;
+ }
+ return (problems);
+}
+
+int
+filter_consistent(struct pf_rule *r, int anchor_call)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP &&
+ (r->src.port_op || r->dst.port_op)) {
+ yyerror("port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 &&
+ (r->type || r->code)) {
+ yyerror("icmp-type/code only applies to icmp");
+ problems++;
+ }
+ if (!r->af && (r->type || r->code)) {
+ yyerror("must indicate address family with icmp-type/code");
+ problems++;
+ }
+ if (r->overload_tblname[0] &&
+ r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) {
+ yyerror("'overload' requires 'max-src-conn' "
+ "or 'max-src-conn-rate'");
+ problems++;
+ }
+ if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) ||
+ (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) {
+ yyerror("proto %s doesn't match address family %s",
+ r->proto == IPPROTO_ICMP ? "icmp" : "icmp6",
+ r->af == AF_INET ? "inet" : "inet6");
+ problems++;
+ }
+ if (r->allow_opts && r->action != PF_PASS) {
+ yyerror("allow-opts can only be specified for pass rules");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op ||
+ r->dst.port_op || r->flagset || r->type || r->code)) {
+ yyerror("fragments can be filtered only on IP header fields");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) {
+ yyerror("return-rst can only be applied to TCP rules");
+ problems++;
+ }
+ if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) {
+ yyerror("max-src-nodes requires 'source-track rule'");
+ problems++;
+ }
+ if (r->action == PF_DROP && r->keep_state) {
+ yyerror("keep state on block rules doesn't make sense");
+ problems++;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY &&
+ (r->keep_state == PF_STATE_MODULATE ||
+ r->keep_state == PF_STATE_SYNPROXY)) {
+ yyerror("sloppy state matching cannot be used with "
+ "synproxy state or modulate state");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+nat_consistent(struct pf_rule *r)
+{
+ return (0); /* yeah! */
+}
+
+int
+rdr_consistent(struct pf_rule *r)
+{
+ int problems = 0;
+
+ if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) {
+ if (r->src.port_op) {
+ yyerror("src port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->dst.port_op) {
+ yyerror("dst port only applies to tcp/udp");
+ problems++;
+ }
+ if (r->rpool.proxy_port[0]) {
+ yyerror("rpool port only applies to tcp/udp");
+ problems++;
+ }
+ }
+ if (r->dst.port_op &&
+ r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) {
+ yyerror("invalid port operator for rdr destination port");
+ problems++;
+ }
+ return (-problems);
+}
+
+int
+process_tabledef(char *name, struct table_opts *opts)
+{
+ struct pfr_buffer ab;
+ struct node_tinit *ti;
+
+ bzero(&ab, sizeof(ab));
+ ab.pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) {
+ if (ti->file)
+ if (pfr_buf_load(&ab, ti->file, 0, append_addr)) {
+ if (errno)
+ yyerror("cannot load \"%s\": %s",
+ ti->file, strerror(errno));
+ else
+ yyerror("file \"%s\" contains bad data",
+ ti->file);
+ goto _error;
+ }
+ if (ti->host)
+ if (append_addr_host(&ab, ti->host, 0, 0)) {
+ yyerror("cannot create address buffer: %s",
+ strerror(errno));
+ goto _error;
+ }
+ }
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(name, opts->flags, opts->init_addr,
+ &opts->init_nodes);
+ if (!(pf->opts & PF_OPT_NOACTION) &&
+ pfctl_define_table(name, opts->flags, opts->init_addr,
+ pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) {
+ yyerror("cannot define table %s: %s", name,
+ pfr_strerror(errno));
+ goto _error;
+ }
+ pf->tdirty = 1;
+ pfr_buf_clear(&ab);
+ return (0);
+_error:
+ pfr_buf_clear(&ab);
+ return (-1);
+}
+
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+/* macro gore, but you should've seen the prior indentation nightmare... */
+
+#define FREE_LIST(T,r) \
+ do { \
+ T *p, *node = r; \
+ while (node != NULL) { \
+ p = node; \
+ node = node->next; \
+ free(p); \
+ } \
+ } while (0)
+
+#define LOOP_THROUGH(T,n,r,C) \
+ do { \
+ T *n; \
+ if (r == NULL) { \
+ r = calloc(1, sizeof(T)); \
+ if (r == NULL) \
+ err(1, "LOOP: calloc"); \
+ r->next = NULL; \
+ } \
+ n = r; \
+ while (n != NULL) { \
+ do { \
+ C; \
+ } while (0); \
+ n = n->next; \
+ } \
+ } while (0)
+
+void
+expand_label_str(char *label, size_t len, const char *srch, const char *repl)
+{
+ char *tmp;
+ char *p, *q;
+
+ if ((tmp = calloc(1, len)) == NULL)
+ err(1, "expand_label_str: calloc");
+ p = q = label;
+ while ((q = strstr(p, srch)) != NULL) {
+ *q = '\0';
+ if ((strlcat(tmp, p, len) >= len) ||
+ (strlcat(tmp, repl, len) >= len))
+ errx(1, "expand_label: label too long");
+ q += strlen(srch);
+ p = q;
+ }
+ if (strlcat(tmp, p, len) >= len)
+ errx(1, "expand_label: label too long");
+ strlcpy(label, tmp, len); /* always fits */
+ free(tmp);
+}
+
+void
+expand_label_if(const char *name, char *label, size_t len, const char *ifname)
+{
+ if (strstr(label, name) != NULL) {
+ if (!*ifname)
+ expand_label_str(label, len, name, "any");
+ else
+ expand_label_str(label, len, name, ifname);
+ }
+}
+
+void
+expand_label_addr(const char *name, char *label, size_t len, sa_family_t af,
+ struct node_host *h)
+{
+ char tmp[64], tmp_not[66];
+
+ if (strstr(label, name) != NULL) {
+ switch (h->addr.type) {
+ case PF_ADDR_DYNIFTL:
+ snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname);
+ break;
+ case PF_ADDR_TABLE:
+ snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname);
+ break;
+ case PF_ADDR_NOROUTE:
+ snprintf(tmp, sizeof(tmp), "no-route");
+ break;
+ case PF_ADDR_URPFFAILED:
+ snprintf(tmp, sizeof(tmp), "urpf-failed");
+ break;
+ case PF_ADDR_ADDRMASK:
+ if (!af || (PF_AZERO(&h->addr.v.a.addr, af) &&
+ PF_AZERO(&h->addr.v.a.mask, af)))
+ snprintf(tmp, sizeof(tmp), "any");
+ else {
+ char a[48];
+ int bits;
+
+ if (inet_ntop(af, &h->addr.v.a.addr, a,
+ sizeof(a)) == NULL)
+ snprintf(tmp, sizeof(tmp), "?");
+ else {
+ bits = unmask(&h->addr.v.a.mask, af);
+ if ((af == AF_INET && bits < 32) ||
+ (af == AF_INET6 && bits < 128))
+ snprintf(tmp, sizeof(tmp),
+ "%s/%d", a, bits);
+ else
+ snprintf(tmp, sizeof(tmp),
+ "%s", a);
+ }
+ }
+ break;
+ default:
+ snprintf(tmp, sizeof(tmp), "?");
+ break;
+ }
+
+ if (h->not) {
+ snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp);
+ expand_label_str(label, len, name, tmp_not);
+ } else
+ expand_label_str(label, len, name, tmp);
+ }
+}
+
+void
+expand_label_port(const char *name, char *label, size_t len,
+ struct node_port *port)
+{
+ char a1[6], a2[6], op[13] = "";
+
+ if (strstr(label, name) != NULL) {
+ snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0]));
+ snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1]));
+ if (!port->op)
+ ;
+ else if (port->op == PF_OP_IRG)
+ snprintf(op, sizeof(op), "%s><%s", a1, a2);
+ else if (port->op == PF_OP_XRG)
+ snprintf(op, sizeof(op), "%s<>%s", a1, a2);
+ else if (port->op == PF_OP_EQ)
+ snprintf(op, sizeof(op), "%s", a1);
+ else if (port->op == PF_OP_NE)
+ snprintf(op, sizeof(op), "!=%s", a1);
+ else if (port->op == PF_OP_LT)
+ snprintf(op, sizeof(op), "<%s", a1);
+ else if (port->op == PF_OP_LE)
+ snprintf(op, sizeof(op), "<=%s", a1);
+ else if (port->op == PF_OP_GT)
+ snprintf(op, sizeof(op), ">%s", a1);
+ else if (port->op == PF_OP_GE)
+ snprintf(op, sizeof(op), ">=%s", a1);
+ expand_label_str(label, len, name, op);
+ }
+}
+
+void
+expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto)
+{
+ struct protoent *pe;
+ char n[4];
+
+ if (strstr(label, name) != NULL) {
+ pe = getprotobynumber(proto);
+ if (pe != NULL)
+ expand_label_str(label, len, name, pe->p_name);
+ else {
+ snprintf(n, sizeof(n), "%u", proto);
+ expand_label_str(label, len, name, n);
+ }
+ }
+}
+
+void
+expand_label_nr(const char *name, char *label, size_t len)
+{
+ char n[11];
+
+ if (strstr(label, name) != NULL) {
+ snprintf(n, sizeof(n), "%u", pf->anchor->match);
+ expand_label_str(label, len, name, n);
+ }
+}
+
+void
+expand_label(char *label, size_t len, const char *ifname, sa_family_t af,
+ struct node_host *src_host, struct node_port *src_port,
+ struct node_host *dst_host, struct node_port *dst_port,
+ u_int8_t proto)
+{
+ expand_label_if("$if", label, len, ifname);
+ expand_label_addr("$srcaddr", label, len, af, src_host);
+ expand_label_addr("$dstaddr", label, len, af, dst_host);
+ expand_label_port("$srcport", label, len, src_port);
+ expand_label_port("$dstport", label, len, dst_port);
+ expand_label_proto("$proto", label, len, proto);
+ expand_label_nr("$nr", label, len);
+}
+
+int
+expand_altq(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct pf_altq pa, pb;
+ char qname[PF_QNAME_SIZE];
+ struct node_queue *n;
+ struct node_queue_bw bw;
+ int errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ memcpy(&pa, a, sizeof(struct pf_altq));
+ if (strlcpy(pa.ifname, interface->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_altq: strlcpy");
+
+ if (interface->not) {
+ yyerror("altq on ! <interface> is not supported");
+ errs++;
+ } else {
+ if (eval_pfaltq(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ print_altq(&pf->paltq->altq, 0,
+ &bwspec, opts);
+ if (nqueues && nqueues->tail) {
+ printf("queue { ");
+ LOOP_THROUGH(struct node_queue, queue,
+ nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC) {
+ /* now create a root queue */
+ memset(&pb, 0, sizeof(struct pf_altq));
+ if (strlcpy(qname, "root_", sizeof(qname)) >=
+ sizeof(qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcat(qname, interface->ifname,
+ sizeof(qname)) >= sizeof(qname))
+ errx(1, "expand_altq: strlcat");
+ if (strlcpy(pb.qname, qname,
+ sizeof(pb.qname)) >= sizeof(pb.qname))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(pb.ifname, interface->ifname,
+ sizeof(pb.ifname)) >= sizeof(pb.ifname))
+ errx(1, "expand_altq: strlcpy");
+ pb.qlimit = pa.qlimit;
+ pb.scheduler = pa.scheduler;
+ bw.bw_absolute = pa.ifbandwidth;
+ bw.bw_percent = 0;
+ if (eval_pfqueue(pf, &pb, &bw, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pb))
+ errs++;
+ }
+
+ LOOP_THROUGH(struct node_queue, queue, nqueues,
+ n = calloc(1, sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_altq: calloc");
+ if (pa.scheduler == ALTQT_CBQ ||
+ pa.scheduler == ALTQT_HFSC)
+ if (strlcpy(n->parent, qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->queue, queue->queue,
+ sizeof(n->queue)) >= sizeof(n->queue))
+ errx(1, "expand_altq: strlcpy");
+ if (strlcpy(n->ifname, interface->ifname,
+ sizeof(n->ifname)) >= sizeof(n->ifname))
+ errx(1, "expand_altq: strlcpy");
+ n->scheduler = pa.scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ );
+ }
+ );
+ FREE_LIST(struct node_if, interfaces);
+ if (nqueues)
+ FREE_LIST(struct node_queue, nqueues);
+
+ return (errs);
+}
+
+int
+expand_queue(struct pf_altq *a, struct node_if *interfaces,
+ struct node_queue *nqueues, struct node_queue_bw bwspec,
+ struct node_queue_opt *opts)
+{
+ struct node_queue *n, *nq;
+ struct pf_altq pa;
+ u_int8_t found = 0;
+ u_int8_t errs = 0;
+
+ if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) {
+ FREE_LIST(struct node_queue, nqueues);
+ return (0);
+ }
+
+ if (queues == NULL) {
+ yyerror("queue %s has no parent", a->qname);
+ FREE_LIST(struct node_queue, nqueues);
+ return (1);
+ }
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_queue, tqueue, queues,
+ if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) &&
+ (interface->ifname[0] == 0 ||
+ (!interface->not && !strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)) ||
+ (interface->not && strncmp(interface->ifname,
+ tqueue->ifname, IFNAMSIZ)))) {
+ /* found ourself in queues */
+ found++;
+
+ memcpy(&pa, a, sizeof(struct pf_altq));
+
+ if (pa.scheduler != ALTQT_NONE &&
+ pa.scheduler != tqueue->scheduler) {
+ yyerror("exactly one scheduler type "
+ "per interface allowed");
+ return (1);
+ }
+ pa.scheduler = tqueue->scheduler;
+
+ /* scheduler dependent error checking */
+ switch (pa.scheduler) {
+ case ALTQT_PRIQ:
+ if (nqueues != NULL) {
+ yyerror("priq queues cannot "
+ "have child queues");
+ return (1);
+ }
+ if (bwspec.bw_absolute > 0 ||
+ bwspec.bw_percent < 100) {
+ yyerror("priq doesn't take "
+ "bandwidth");
+ return (1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (strlcpy(pa.ifname, tqueue->ifname,
+ sizeof(pa.ifname)) >= sizeof(pa.ifname))
+ errx(1, "expand_queue: strlcpy");
+ if (strlcpy(pa.parent, tqueue->parent,
+ sizeof(pa.parent)) >= sizeof(pa.parent))
+ errx(1, "expand_queue: strlcpy");
+
+ if (eval_pfqueue(pf, &pa, &bwspec, opts))
+ errs++;
+ else
+ if (pfctl_add_altq(pf, &pa))
+ errs++;
+
+ for (nq = nqueues; nq != NULL; nq = nq->next) {
+ if (!strcmp(a->qname, nq->queue)) {
+ yyerror("queue cannot have "
+ "itself as child");
+ errs++;
+ continue;
+ }
+ n = calloc(1,
+ sizeof(struct node_queue));
+ if (n == NULL)
+ err(1, "expand_queue: calloc");
+ if (strlcpy(n->parent, a->qname,
+ sizeof(n->parent)) >=
+ sizeof(n->parent))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->queue, nq->queue,
+ sizeof(n->queue)) >=
+ sizeof(n->queue))
+ errx(1, "expand_queue strlcpy");
+ if (strlcpy(n->ifname, tqueue->ifname,
+ sizeof(n->ifname)) >=
+ sizeof(n->ifname))
+ errx(1, "expand_queue strlcpy");
+ n->scheduler = tqueue->scheduler;
+ n->next = NULL;
+ n->tail = n;
+ if (queues == NULL)
+ queues = n;
+ else {
+ queues->tail->next = n;
+ queues->tail = n;
+ }
+ }
+ if ((pf->opts & PF_OPT_VERBOSE) && (
+ (found == 1 && interface->ifname[0] == 0) ||
+ (found > 0 && interface->ifname[0] != 0))) {
+ print_queue(&pf->paltq->altq, 0,
+ &bwspec, interface->ifname[0] != 0,
+ opts);
+ if (nqueues && nqueues->tail) {
+ printf("{ ");
+ LOOP_THROUGH(struct node_queue,
+ queue, nqueues,
+ printf("%s ",
+ queue->queue);
+ );
+ printf("}");
+ }
+ printf("\n");
+ }
+ }
+ );
+ );
+
+ FREE_LIST(struct node_queue, nqueues);
+ FREE_LIST(struct node_if, interfaces);
+
+ if (!found) {
+ yyerror("queue %s has no parent", a->qname);
+ errs++;
+ }
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+void
+expand_rule(struct pf_rule *r,
+ struct node_if *interfaces, struct node_host *rpool_hosts,
+ struct node_proto *protos, struct node_os *src_oses,
+ struct node_host *src_hosts, struct node_port *src_ports,
+ struct node_host *dst_hosts, struct node_port *dst_ports,
+ struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types,
+ const char *anchor_call)
+{
+ sa_family_t af = r->af;
+ int added = 0, error = 0;
+ char ifname[IF_NAMESIZE];
+ char label[PF_RULE_LABEL_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ char match_tagname[PF_TAG_NAME_SIZE];
+ struct pf_pooladdr *pa;
+ struct node_host *h;
+ u_int8_t flags, flagset, keep_state;
+
+ if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >=
+ sizeof(match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ flags = r->flags;
+ flagset = r->flagset;
+ keep_state = r->keep_state;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_proto, proto, protos,
+ LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types,
+ LOOP_THROUGH(struct node_host, src_host, src_hosts,
+ LOOP_THROUGH(struct node_port, src_port, src_ports,
+ LOOP_THROUGH(struct node_os, src_os, src_oses,
+ LOOP_THROUGH(struct node_host, dst_host, dst_hosts,
+ LOOP_THROUGH(struct node_port, dst_port, dst_ports,
+ LOOP_THROUGH(struct node_uid, uid, uids,
+ LOOP_THROUGH(struct node_gid, gid, gids,
+
+ r->af = af;
+ /* for link-local IPv6 address, interface must match up */
+ if ((r->af && src_host->af && r->af != src_host->af) ||
+ (r->af && dst_host->af && r->af != dst_host->af) ||
+ (src_host->af && dst_host->af &&
+ src_host->af != dst_host->af) ||
+ (src_host->ifindex && dst_host->ifindex &&
+ src_host->ifindex != dst_host->ifindex) ||
+ (src_host->ifindex && *interface->ifname &&
+ src_host->ifindex != if_nametoindex(interface->ifname)) ||
+ (dst_host->ifindex && *interface->ifname &&
+ dst_host->ifindex != if_nametoindex(interface->ifname)))
+ continue;
+ if (!r->af && src_host->af)
+ r->af = src_host->af;
+ else if (!r->af && dst_host->af)
+ r->af = dst_host->af;
+
+ if (*interface->ifname)
+ strlcpy(r->ifname, interface->ifname,
+ sizeof(r->ifname));
+ else if (if_indextoname(src_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else if (if_indextoname(dst_host->ifindex, ifname))
+ strlcpy(r->ifname, ifname, sizeof(r->ifname));
+ else
+ memset(r->ifname, '\0', sizeof(r->ifname));
+
+ if (strlcpy(r->label, label, sizeof(r->label)) >=
+ sizeof(r->label))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >=
+ sizeof(r->tagname))
+ errx(1, "expand_rule: strlcpy");
+ if (strlcpy(r->match_tagname, match_tagname,
+ sizeof(r->match_tagname)) >= sizeof(r->match_tagname))
+ errx(1, "expand_rule: strlcpy");
+ expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af,
+ src_host, src_port, dst_host, dst_port, proto->proto);
+ expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname,
+ r->af, src_host, src_port, dst_host, dst_port,
+ proto->proto);
+
+ error += check_netmask(src_host, r->af);
+ error += check_netmask(dst_host, r->af);
+
+ r->ifnot = interface->not;
+ r->proto = proto->proto;
+ r->src.addr = src_host->addr;
+ r->src.neg = src_host->not;
+ r->src.port[0] = src_port->port[0];
+ r->src.port[1] = src_port->port[1];
+ r->src.port_op = src_port->op;
+ r->dst.addr = dst_host->addr;
+ r->dst.neg = dst_host->not;
+ r->dst.port[0] = dst_port->port[0];
+ r->dst.port[1] = dst_port->port[1];
+ r->dst.port_op = dst_port->op;
+ r->uid.op = uid->op;
+ r->uid.uid[0] = uid->uid[0];
+ r->uid.uid[1] = uid->uid[1];
+ r->gid.op = gid->op;
+ r->gid.gid[0] = gid->gid[0];
+ r->gid.gid[1] = gid->gid[1];
+ r->type = icmp_type->type;
+ r->code = icmp_type->code;
+
+ if ((keep_state == PF_STATE_MODULATE ||
+ keep_state == PF_STATE_SYNPROXY) &&
+ r->proto && r->proto != IPPROTO_TCP)
+ r->keep_state = PF_STATE_NORMAL;
+ else
+ r->keep_state = keep_state;
+
+ if (r->proto && r->proto != IPPROTO_TCP) {
+ r->flags = 0;
+ r->flagset = 0;
+ } else {
+ r->flags = flags;
+ r->flagset = flagset;
+ }
+ if (icmp_type->proto && r->proto != icmp_type->proto) {
+ yyerror("icmp-type mismatch");
+ error++;
+ }
+
+ if (src_os && src_os->os) {
+ r->os_fingerprint = pfctl_get_fingerprint(src_os->os);
+ if ((pf->opts & PF_OPT_VERBOSE2) &&
+ r->os_fingerprint == PF_OSFP_NOMATCH)
+ fprintf(stderr,
+ "warning: unknown '%s' OS fingerprint\n",
+ src_os->os);
+ } else {
+ r->os_fingerprint = PF_OSFP_ANY;
+ }
+
+ TAILQ_INIT(&r->rpool.list);
+ for (h = rpool_hosts; h != NULL; h = h->next) {
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "expand_rule: calloc");
+ pa->addr = h->addr;
+ if (h->ifname != NULL) {
+ if (strlcpy(pa->ifname, h->ifname,
+ sizeof(pa->ifname)) >=
+ sizeof(pa->ifname))
+ errx(1, "expand_rule: strlcpy");
+ } else
+ pa->ifname[0] = 0;
+ TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries);
+ }
+
+ if (rule_consistent(r, anchor_call[0]) < 0 || error)
+ yyerror("skipping rule due to errors");
+ else {
+ r->nr = pf->astack[pf->asd]->match++;
+ pfctl_add_rule(pf, r, anchor_call);
+ added++;
+ }
+
+ ))))))))));
+
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_proto, protos);
+ FREE_LIST(struct node_host, src_hosts);
+ FREE_LIST(struct node_port, src_ports);
+ FREE_LIST(struct node_os, src_oses);
+ FREE_LIST(struct node_host, dst_hosts);
+ FREE_LIST(struct node_port, dst_ports);
+ FREE_LIST(struct node_uid, uids);
+ FREE_LIST(struct node_gid, gids);
+ FREE_LIST(struct node_icmp, icmp_types);
+ FREE_LIST(struct node_host, rpool_hosts);
+
+ if (!added)
+ yyerror("rule expands to no valid combination");
+}
+
+int
+expand_skip_interface(struct node_if *interfaces)
+{
+ int errs = 0;
+
+ if (!interfaces || (!interfaces->next && !interfaces->not &&
+ !strcmp(interfaces->ifname, "none"))) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on none\n");
+ errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0);
+ return (errs);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set skip on {");
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" %s", interface->ifname);
+ if (interface->not) {
+ yyerror("skip on ! <interface> is not supported");
+ errs++;
+ } else
+ errs += pfctl_set_interface_flags(pf,
+ interface->ifname, PFI_IFLAG_SKIP, 1);
+ );
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" }\n");
+
+ FREE_LIST(struct node_if, interfaces);
+
+ if (errs)
+ return (1);
+ else
+ return (0);
+}
+
+#undef FREE_LIST
+#undef LOOP_THROUGH
+
+int
+check_rulestate(int desired_state)
+{
+ if (require_order && (rulestate > desired_state)) {
+ yyerror("Rules must be in order: options, normalization, "
+ "queueing, translation, filtering");
+ return (1);
+ }
+ rulestate = desired_state;
+ return (0);
+}
+
+int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcmp(k, ((const struct keywords *)e)->k_name));
+}
+
+int
+lookup(char *s)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "all", ALL},
+ { "allow-opts", ALLOWOPTS},
+ { "altq", ALTQ},
+ { "anchor", ANCHOR},
+ { "antispoof", ANTISPOOF},
+ { "any", ANY},
+ { "bandwidth", BANDWIDTH},
+ { "binat", BINAT},
+ { "binat-anchor", BINATANCHOR},
+ { "bitmask", BITMASK},
+ { "block", BLOCK},
+ { "block-policy", BLOCKPOLICY},
+ { "buckets", BUCKETS},
+ { "cbq", CBQ},
+ { "code", CODE},
+ { "codelq", CODEL},
+ { "crop", FRAGCROP},
+ { "debug", DEBUG},
+ { "divert-reply", DIVERTREPLY},
+ { "divert-to", DIVERTTO},
+ { "drop", DROP},
+ { "drop-ovl", FRAGDROP},
+ { "dup-to", DUPTO},
+ { "fairq", FAIRQ},
+ { "fastroute", FASTROUTE},
+ { "file", FILENAME},
+ { "fingerprints", FINGERPRINTS},
+ { "flags", FLAGS},
+ { "floating", FLOATING},
+ { "flush", FLUSH},
+ { "for", FOR},
+ { "fragment", FRAGMENT},
+ { "from", FROM},
+ { "global", GLOBAL},
+ { "group", GROUP},
+ { "hfsc", HFSC},
+ { "hogs", HOGS},
+ { "hostid", HOSTID},
+ { "icmp-type", ICMPTYPE},
+ { "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
+ { "in", IN},
+ { "include", INCLUDE},
+ { "inet", INET},
+ { "inet6", INET6},
+ { "interval", INTERVAL},
+ { "keep", KEEP},
+ { "label", LABEL},
+ { "limit", LIMIT},
+ { "linkshare", LINKSHARE},
+ { "load", LOAD},
+ { "log", LOG},
+ { "loginterface", LOGINTERFACE},
+ { "max", MAXIMUM},
+ { "max-mss", MAXMSS},
+ { "max-src-conn", MAXSRCCONN},
+ { "max-src-conn-rate", MAXSRCCONNRATE},
+ { "max-src-nodes", MAXSRCNODES},
+ { "max-src-states", MAXSRCSTATES},
+ { "min-ttl", MINTTL},
+ { "modulate", MODULATE},
+ { "nat", NAT},
+ { "nat-anchor", NATANCHOR},
+ { "no", NO},
+ { "no-df", NODF},
+ { "no-route", NOROUTE},
+ { "no-sync", NOSYNC},
+ { "on", ON},
+ { "optimization", OPTIMIZATION},
+ { "os", OS},
+ { "out", OUT},
+ { "overload", OVERLOAD},
+ { "pass", PASS},
+ { "port", PORT},
+ { "prio", PRIO},
+ { "priority", PRIORITY},
+ { "priq", PRIQ},
+ { "probability", PROBABILITY},
+ { "proto", PROTO},
+ { "qlimit", QLIMIT},
+ { "queue", QUEUE},
+ { "quick", QUICK},
+ { "random", RANDOM},
+ { "random-id", RANDOMID},
+ { "rdr", RDR},
+ { "rdr-anchor", RDRANCHOR},
+ { "realtime", REALTIME},
+ { "reassemble", REASSEMBLE},
+ { "reply-to", REPLYTO},
+ { "require-order", REQUIREORDER},
+ { "return", RETURN},
+ { "return-icmp", RETURNICMP},
+ { "return-icmp6", RETURNICMP6},
+ { "return-rst", RETURNRST},
+ { "round-robin", ROUNDROBIN},
+ { "route", ROUTE},
+ { "route-to", ROUTETO},
+ { "rtable", RTABLE},
+ { "rule", RULE},
+ { "ruleset-optimization", RULESET_OPTIMIZATION},
+ { "scrub", SCRUB},
+ { "set", SET},
+ { "set-tos", SETTOS},
+ { "skip", SKIP},
+ { "sloppy", SLOPPY},
+ { "source-hash", SOURCEHASH},
+ { "source-track", SOURCETRACK},
+ { "state", STATE},
+ { "state-defaults", STATEDEFAULTS},
+ { "state-policy", STATEPOLICY},
+ { "static-port", STATICPORT},
+ { "sticky-address", STICKYADDRESS},
+ { "synproxy", SYNPROXY},
+ { "table", TABLE},
+ { "tag", TAG},
+ { "tagged", TAGGED},
+ { "target", TARGET},
+ { "tbrsize", TBRSIZE},
+ { "timeout", TIMEOUT},
+ { "to", TO},
+ { "tos", TOS},
+ { "ttl", TTL},
+ { "upperlimit", UPPERLIMIT},
+ { "urpf-failed", URPFFAILED},
+ { "user", USER},
+ };
+ const struct keywords *p;
+
+ p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p) {
+ if (debug > 1)
+ fprintf(stderr, "%s: %d\n", s, p->k_val);
+ return (p->k_val);
+ } else {
+ if (debug > 1)
+ fprintf(stderr, "string: %s\n", s);
+ return (STRING);
+ }
+}
+
+#define MAXPUSHBACK 128
+
+static char *parsebuf;
+static int parseindex;
+static char pushback_buffer[MAXPUSHBACK];
+static int pushback_index = 0;
+
+int
+lgetc(int quotec)
+{
+ int c, next;
+
+ if (parsebuf) {
+ /* Read character from the parsebuffer instead of input. */
+ if (parseindex >= 0) {
+ c = parsebuf[parseindex++];
+ if (c != '\0')
+ return (c);
+ parsebuf = NULL;
+ } else
+ parseindex++;
+ }
+
+ if (pushback_index)
+ return (pushback_buffer[--pushback_index]);
+
+ if (quotec) {
+ if ((c = getc(file->stream)) == EOF) {
+ yyerror("reached end of file while parsing quoted string");
+ if (popfile() == EOF)
+ return (EOF);
+ return (quotec);
+ }
+ return (c);
+ }
+
+ while ((c = getc(file->stream)) == '\\') {
+ next = getc(file->stream);
+ if (next != '\n') {
+ c = next;
+ break;
+ }
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+
+ while (c == EOF) {
+ if (popfile() == EOF)
+ return (EOF);
+ c = getc(file->stream);
+ }
+ return (c);
+}
+
+int
+lungetc(int c)
+{
+ if (c == EOF)
+ return (EOF);
+ if (parsebuf) {
+ parseindex--;
+ if (parseindex >= 0)
+ return (c);
+ }
+ if (pushback_index < MAXPUSHBACK-1)
+ return (pushback_buffer[pushback_index++] = c);
+ else
+ return (EOF);
+}
+
+int
+findeol(void)
+{
+ int c;
+
+ parsebuf = NULL;
+
+ /* skip to either EOF or the first real EOL */
+ while (1) {
+ if (pushback_index)
+ c = pushback_buffer[--pushback_index];
+ else
+ c = lgetc(0);
+ if (c == '\n') {
+ file->lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ return (ERROR);
+}
+
+int
+yylex(void)
+{
+ char buf[8096];
+ char *p, *val;
+ int quotec, next, c;
+ int token;
+
+top:
+ p = buf;
+ while ((c = lgetc(0)) == ' ' || c == '\t')
+ ; /* nothing */
+
+ yylval.lineno = file->lineno;
+ if (c == '#')
+ while ((c = lgetc(0)) != '\n' && c != EOF)
+ ; /* nothing */
+ if (c == '$' && parsebuf == NULL) {
+ while (1) {
+ if ((c = lgetc(0)) == EOF)
+ return (0);
+
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ if (isalnum(c) || c == '_') {
+ *p++ = (char)c;
+ continue;
+ }
+ *p = '\0';
+ lungetc(c);
+ break;
+ }
+ val = symget(buf);
+ if (val == NULL) {
+ yyerror("macro '%s' not defined", buf);
+ return (findeol());
+ }
+ parsebuf = val;
+ parseindex = 0;
+ goto top;
+ }
+
+ switch (c) {
+ case '\'':
+ case '"':
+ quotec = c;
+ while (1) {
+ if ((c = lgetc(quotec)) == EOF)
+ return (0);
+ if (c == '\n') {
+ file->lineno++;
+ continue;
+ } else if (c == '\\') {
+ if ((next = lgetc(quotec)) == EOF)
+ return (0);
+ if (next == quotec || c == ' ' || c == '\t')
+ c = next;
+ else if (next == '\n')
+ continue;
+ else
+ lungetc(next);
+ } else if (c == quotec) {
+ *p = '\0';
+ break;
+ }
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ *p++ = (char)c;
+ }
+ yylval.v.string = strdup(buf);
+ if (yylval.v.string == NULL)
+ err(1, "yylex: strdup");
+ return (STRING);
+ case '<':
+ next = lgetc(0);
+ if (next == '>') {
+ yylval.v.i = PF_OP_XRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '>':
+ next = lgetc(0);
+ if (next == '<') {
+ yylval.v.i = PF_OP_IRG;
+ return (PORTBINARY);
+ }
+ lungetc(next);
+ break;
+ case '-':
+ next = lgetc(0);
+ if (next == '>')
+ return (ARROW);
+ lungetc(next);
+ break;
+ }
+
+#define allowed_to_end_number(x) \
+ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
+
+ if (c == '-' || isdigit(c)) {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && isdigit(c));
+ lungetc(c);
+ if (p == buf + 1 && buf[0] == '-')
+ goto nodigits;
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+
+ *p = '\0';
+ yylval.v.number = strtonum(buf, LLONG_MIN,
+ LLONG_MAX, &errstr);
+ if (errstr) {
+ yyerror("\"%s\" invalid number: %s",
+ buf, errstr);
+ return (findeol());
+ }
+ return (NUMBER);
+ } else {
+nodigits:
+ while (p > buf + 1)
+ lungetc(*--p);
+ c = *--p;
+ if (c == '-')
+ return (c);
+ }
+ }
+
+#define allowed_in_string(x) \
+ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
+ x != '{' && x != '}' && x != '<' && x != '>' && \
+ x != '!' && x != '=' && x != '/' && x != '#' && \
+ x != ','))
+
+ if (isalnum(c) || c == ':' || c == '_') {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
+ lungetc(c);
+ *p = '\0';
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
+ return (token);
+ }
+ if (c == '\n') {
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+ if (c == EOF)
+ return (0);
+ return (c);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ warn("cannot stat %s", fname);
+ return (-1);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+ if (st.st_mode & (S_IRWXG | S_IRWXO)) {
+ warnx("%s: group/world readable/writeable", fname);
+ return (-1);
+ }
+ return (0);
+}
+
+struct file *
+pushfile(const char *name, int secret)
+{
+ struct file *nfile;
+
+ if ((nfile = calloc(1, sizeof(struct file))) == NULL ||
+ (nfile->name = strdup(name)) == NULL) {
+ warn("malloc");
+ return (NULL);
+ }
+ if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) {
+ nfile->stream = stdin;
+ free(nfile->name);
+ if ((nfile->name = strdup("stdin")) == NULL) {
+ warn("strdup");
+ free(nfile);
+ return (NULL);
+ }
+ } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
+ warn("%s", nfile->name);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ } else if (secret &&
+ check_file_secrecy(fileno(nfile->stream), nfile->name)) {
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
+ nfile->lineno = 1;
+ TAILQ_INSERT_TAIL(&files, nfile, entry);
+ return (nfile);
+}
+
+int
+popfile(void)
+{
+ struct file *prev;
+
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL) {
+ prev->errors += file->errors;
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file);
+ file = prev;
+ return (0);
+ }
+ return (EOF);
+}
+
+int
+parse_config(char *filename, struct pfctl *xpf)
+{
+ int errors = 0;
+ struct sym *sym;
+
+ pf = xpf;
+ errors = 0;
+ rulestate = PFCTL_STATE_NONE;
+ returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT;
+ returnicmp6default =
+ (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT;
+ blockpolicy = PFRULE_DROP;
+ require_order = 1;
+
+ if ((file = pushfile(filename, 0)) == NULL) {
+ warn("cannot open the main config file!");
+ return (-1);
+ }
+
+ yyparse();
+ errors = file->errors;
+ popfile();
+
+ /* Free macros and check which have not been used. */
+ while ((sym = TAILQ_FIRST(&symhead))) {
+ if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used)
+ fprintf(stderr, "warning: macro '%s' not "
+ "used\n", sym->nam);
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+
+ return (errors ? -1 : 0);
+}
+
+int
+symset(const char *nam, const char *val, int persist)
+{
+ struct sym *sym;
+
+ for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
+ sym = TAILQ_NEXT(sym, entry))
+ ; /* nothing */
+
+ if (sym != NULL) {
+ if (sym->persist == 1)
+ return (0);
+ else {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+ if ((sym = calloc(1, sizeof(*sym))) == NULL)
+ return (-1);
+
+ sym->nam = strdup(nam);
+ if (sym->nam == NULL) {
+ free(sym);
+ return (-1);
+ }
+ sym->val = strdup(val);
+ if (sym->val == NULL) {
+ free(sym->nam);
+ free(sym);
+ return (-1);
+ }
+ sym->used = 0;
+ sym->persist = persist;
+ TAILQ_INSERT_TAIL(&symhead, sym, entry);
+ return (0);
+}
+
+int
+pfctl_cmdline_symset(char *s)
+{
+ char *sym, *val;
+ int ret;
+
+ if ((val = strrchr(s, '=')) == NULL)
+ return (-1);
+
+ if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL)
+ err(1, "pfctl_cmdline_symset: malloc");
+
+ strlcpy(sym, s, strlen(s) - strlen(val) + 1);
+
+ ret = symset(sym, val + 1, 1);
+ free(sym);
+
+ return (ret);
+}
+
+char *
+symget(const char *nam)
+{
+ struct sym *sym;
+
+ TAILQ_FOREACH(sym, &symhead, entry)
+ if (strcmp(nam, sym->nam) == 0) {
+ sym->used = 1;
+ return (sym->val);
+ }
+ return (NULL);
+}
+
+void
+mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst)
+{
+ int i;
+ struct pf_rule *r;
+
+ for (i = 0; i < PF_RULESET_MAX; ++i) {
+ while ((r = TAILQ_FIRST(src->rules[i].active.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].active.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries);
+ dst->anchor->match++;
+ }
+ src->anchor->match = 0;
+ while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries);
+ TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr,
+ r, entries);
+ }
+ }
+}
+
+void
+decide_address_family(struct node_host *n, sa_family_t *af)
+{
+ if (*af != 0 || n == NULL)
+ return;
+ *af = n->af;
+ while ((n = n->next) != NULL) {
+ if (n->af != *af) {
+ *af = 0;
+ return;
+ }
+ }
+}
+
+void
+remove_invalid_hosts(struct node_host **nh, sa_family_t *af)
+{
+ struct node_host *n = *nh, *prev = NULL;
+
+ while (n != NULL) {
+ if (*af && n->af && n->af != *af) {
+ /* unlink and free n */
+ struct node_host *next = n->next;
+
+ /* adjust tail pointer */
+ if (n == (*nh)->tail)
+ (*nh)->tail = prev;
+ /* adjust previous node's next pointer */
+ if (prev == NULL)
+ *nh = next;
+ else
+ prev->next = next;
+ /* free node */
+ if (n->ifname != NULL)
+ free(n->ifname);
+ free(n);
+ n = next;
+ } else {
+ if (n->af && !*af)
+ *af = n->af;
+ prev = n;
+ n = n->next;
+ }
+ }
+}
+
+int
+invalid_redirect(struct node_host *nh, sa_family_t af)
+{
+ if (!af) {
+ struct node_host *n;
+
+ /* tables and dyniftl are ok without an address family */
+ for (n = nh; n != NULL; n = n->next) {
+ if (n->addr.type != PF_ADDR_TABLE &&
+ n->addr.type != PF_ADDR_DYNIFTL) {
+ yyerror("address family not given and "
+ "translation address expands to multiple "
+ "address families");
+ return (1);
+ }
+ }
+ }
+ if (nh == NULL) {
+ yyerror("no translation address with matching address family "
+ "found.");
+ return (1);
+ }
+ return (0);
+}
+
+int
+atoul(char *s, u_long *ulvalp)
+{
+ u_long ulval;
+ char *ep;
+
+ errno = 0;
+ ulval = strtoul(s, &ep, 0);
+ if (s[0] == '\0' || *ep != '\0')
+ return (-1);
+ if (errno == ERANGE && ulval == ULONG_MAX)
+ return (-1);
+ *ulvalp = ulval;
+ return (0);
+}
+
+int
+getservice(char *n)
+{
+ struct servent *s;
+ u_long ulval;
+
+ if (atoul(n, &ulval) == 0) {
+ if (ulval > 65535) {
+ yyerror("illegal port value %lu", ulval);
+ return (-1);
+ }
+ return (htons(ulval));
+ } else {
+ s = getservbyname(n, "tcp");
+ if (s == NULL)
+ s = getservbyname(n, "udp");
+ if (s == NULL) {
+ yyerror("unknown port %s", n);
+ return (-1);
+ }
+ return (s->s_port);
+ }
+}
+
+int
+rule_label(struct pf_rule *r, char *s)
+{
+ if (s) {
+ if (strlcpy(r->label, s, sizeof(r->label)) >=
+ sizeof(r->label)) {
+ yyerror("rule label too long (max %d chars)",
+ sizeof(r->label)-1);
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+u_int16_t
+parseicmpspec(char *w, sa_family_t af)
+{
+ const struct icmpcodeent *p;
+ u_long ulval;
+ u_int8_t icmptype;
+
+ if (af == AF_INET)
+ icmptype = returnicmpdefault >> 8;
+ else
+ icmptype = returnicmp6default >> 8;
+
+ if (atoul(w, &ulval) == -1) {
+ if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) {
+ yyerror("unknown icmp code %s", w);
+ return (0);
+ }
+ ulval = p->code;
+ }
+ if (ulval > 255) {
+ yyerror("invalid icmp code %lu", ulval);
+ return (0);
+ }
+ return (icmptype << 8 | ulval);
+}
+
+int
+parseport(char *port, struct range *r, int extensions)
+{
+ char *p = strchr(port, ':');
+
+ if (p == NULL) {
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ return (0);
+ }
+ if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) {
+ *p = 0;
+ if ((r->a = getservice(port)) == -1)
+ return (-1);
+ r->b = 0;
+ r->t = PF_OP_IRG;
+ return (0);
+ }
+ if ((extensions & PPORT_RANGE)) {
+ *p++ = 0;
+ if ((r->a = getservice(port)) == -1 ||
+ (r->b = getservice(p)) == -1)
+ return (-1);
+ if (r->a == r->b) {
+ r->b = 0;
+ r->t = PF_OP_NONE;
+ } else
+ r->t = PF_OP_RRG;
+ return (0);
+ }
+ return (-1);
+}
+
+int
+pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
+{
+ struct loadanchors *la;
+
+ TAILQ_FOREACH(la, &loadanchorshead, entries) {
+ if (pf->opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "\nLoading anchor %s from %s\n",
+ la->anchorname, la->filename);
+ if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize,
+ la->anchorname, trans) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+rt_tableid_max(void)
+{
+#ifdef __FreeBSD__
+ int fibs;
+ size_t l = sizeof(fibs);
+
+ if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
+ fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
+ /*
+ * As the OpenBSD code only compares > and not >= we need to adjust
+ * here given we only accept values of 0..n and want to avoid #ifdefs
+ * in the grammar.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
diff --git a/freebsd/sbin/pfctl/pf_print_state.c b/freebsd/sbin/pfctl/pf_print_state.c
new file mode 100644
index 00000000..1e09a01f
--- /dev/null
+++ b/freebsd/sbin/pfctl/pf_print_state.c
@@ -0,0 +1,387 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/endian.h>
+#include <net/if.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pf_print_state-data.h"
+#endif /* __rtems__ */
+
+void print_name(struct pf_addr *, sa_family_t);
+
+void
+print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
+{
+ switch (addr->type) {
+ case PF_ADDR_DYNIFTL:
+ printf("(%s", addr->v.ifname);
+ if (addr->iflags & PFI_AFLAG_NETWORK)
+ printf(":network");
+ if (addr->iflags & PFI_AFLAG_BROADCAST)
+ printf(":broadcast");
+ if (addr->iflags & PFI_AFLAG_PEER)
+ printf(":peer");
+ if (addr->iflags & PFI_AFLAG_NOALIAS)
+ printf(":0");
+ if (verbose) {
+ if (addr->p.dyncnt <= 0)
+ printf(":*");
+ else
+ printf(":%d", addr->p.dyncnt);
+ }
+ printf(")");
+ break;
+ case PF_ADDR_TABLE:
+ if (verbose)
+ if (addr->p.tblcnt == -1)
+ printf("<%s:*>", addr->v.tblname);
+ else
+ printf("<%s:%d>", addr->v.tblname,
+ addr->p.tblcnt);
+ else
+ printf("<%s>", addr->v.tblname);
+ return;
+ case PF_ADDR_RANGE: {
+ char buf[48];
+
+ if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL)
+ printf(" - ?");
+ else
+ printf(" - %s", buf);
+ break;
+ }
+ case PF_ADDR_ADDRMASK:
+ if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
+ PF_AZERO(&addr->v.a.mask, AF_INET6))
+ printf("any");
+ else {
+ char buf[48];
+
+ if (inet_ntop(af, &addr->v.a.addr, buf,
+ sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ }
+ break;
+ case PF_ADDR_NOROUTE:
+ printf("no-route");
+ return;
+ case PF_ADDR_URPFFAILED:
+ printf("urpf-failed");
+ return;
+ default:
+ printf("?");
+ return;
+ }
+
+ /* mask if not _both_ address and mask are zero */
+ if (addr->type != PF_ADDR_RANGE &&
+ !(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
+ PF_AZERO(&addr->v.a.mask, AF_INET6))) {
+ int bits = unmask(&addr->v.a.mask, af);
+
+ if (bits != (af == AF_INET ? 32 : 128))
+ printf("/%d", bits);
+ }
+}
+
+void
+print_name(struct pf_addr *addr, sa_family_t af)
+{
+ char host[NI_MAXHOST];
+
+ strlcpy(host, "?", sizeof(host));
+ switch (af) {
+ case AF_INET: {
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr = addr->v4;
+ getnameinfo((struct sockaddr *)&sin, sin.sin_len,
+ host, sizeof(host), NULL, 0, NI_NOFQDN);
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = addr->v6;
+ getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ host, sizeof(host), NULL, 0, NI_NOFQDN);
+ break;
+ }
+ }
+ printf("%s", host);
+}
+
+void
+print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts)
+{
+ if (opts & PF_OPT_USEDNS)
+ print_name(addr, af);
+ else {
+ struct pf_addr_wrap aw;
+
+ memset(&aw, 0, sizeof(aw));
+ aw.v.a.addr = *addr;
+ if (af == AF_INET)
+ aw.v.a.mask.addr32[0] = 0xffffffff;
+ else {
+ memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+ af = AF_INET6;
+ }
+ print_addr(&aw, af, opts & PF_OPT_VERBOSE2);
+ }
+
+ if (port) {
+ if (af == AF_INET)
+ printf(":%u", ntohs(port));
+ else
+ printf("[%u]", ntohs(port));
+ }
+}
+
+void
+print_seq(struct pfsync_state_peer *p)
+{
+ if (p->seqdiff)
+ printf("[%u + %u](+%u)", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff));
+ else
+ printf("[%u + %u]", ntohl(p->seqlo),
+ ntohl(p->seqhi) - ntohl(p->seqlo));
+}
+
+void
+print_state(struct pfsync_state *s, int opts)
+{
+ struct pfsync_state_peer *src, *dst;
+ struct pfsync_state_key *key, *sk, *nk;
+ struct protoent *p;
+ int min, sec;
+#ifndef __NO_STRICT_ALIGNMENT
+ struct pfsync_state_key aligned_key[2];
+
+ bcopy(&s->key, aligned_key, sizeof(aligned_key));
+ key = aligned_key;
+#else
+ key = s->key;
+#endif
+
+ if (s->direction == PF_OUT) {
+ src = &s->src;
+ dst = &s->dst;
+ sk = &key[PF_SK_STACK];
+ nk = &key[PF_SK_WIRE];
+ if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+ sk->port[0] = nk->port[0];
+ } else {
+ src = &s->dst;
+ dst = &s->src;
+ sk = &key[PF_SK_WIRE];
+ nk = &key[PF_SK_STACK];
+ if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6)
+ sk->port[1] = nk->port[1];
+ }
+ printf("%s ", s->ifname);
+ if ((p = getprotobynumber(s->proto)) != NULL)
+ printf("%s ", p->p_name);
+ else
+ printf("%u ", s->proto);
+
+ print_host(&nk->addr[1], nk->port[1], s->af, opts);
+ if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) ||
+ nk->port[1] != sk->port[1]) {
+ printf(" (");
+ print_host(&sk->addr[1], sk->port[1], s->af, opts);
+ printf(")");
+ }
+ if (s->direction == PF_OUT)
+ printf(" -> ");
+ else
+ printf(" <- ");
+ print_host(&nk->addr[0], nk->port[0], s->af, opts);
+ if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) ||
+ nk->port[0] != sk->port[0]) {
+ printf(" (");
+ print_host(&sk->addr[0], sk->port[0], s->af, opts);
+ printf(")");
+ }
+
+ printf(" ");
+ if (s->proto == IPPROTO_TCP) {
+ if (src->state <= TCPS_TIME_WAIT &&
+ dst->state <= TCPS_TIME_WAIT)
+ printf(" %s:%s\n", tcpstates[src->state],
+ tcpstates[dst->state]);
+ else if (src->state == PF_TCPS_PROXY_SRC ||
+ dst->state == PF_TCPS_PROXY_SRC)
+ printf(" PROXY:SRC\n");
+ else if (src->state == PF_TCPS_PROXY_DST ||
+ dst->state == PF_TCPS_PROXY_DST)
+ printf(" PROXY:DST\n");
+ else
+ printf(" <BAD STATE LEVELS %u:%u>\n",
+ src->state, dst->state);
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" ");
+ print_seq(src);
+ if (src->wscale && dst->wscale)
+ printf(" wscale %u",
+ src->wscale & PF_WSCALE_MASK);
+ printf(" ");
+ print_seq(dst);
+ if (src->wscale && dst->wscale)
+ printf(" wscale %u",
+ dst->wscale & PF_WSCALE_MASK);
+ printf("\n");
+ }
+ } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES &&
+ dst->state < PFUDPS_NSTATES) {
+ const char *states[] = PFUDPS_NAMES;
+
+ printf(" %s:%s\n", states[src->state], states[dst->state]);
+#ifndef INET6
+ } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
+ dst->state < PFOTHERS_NSTATES) {
+#else
+ } else if (s->proto != IPPROTO_ICMP && s->proto != IPPROTO_ICMPV6 &&
+ src->state < PFOTHERS_NSTATES && dst->state < PFOTHERS_NSTATES) {
+#endif
+ /* XXX ICMP doesn't really have state levels */
+ const char *states[] = PFOTHERS_NAMES;
+
+ printf(" %s:%s\n", states[src->state], states[dst->state]);
+ } else {
+ printf(" %u:%u\n", src->state, dst->state);
+ }
+
+ if (opts & PF_OPT_VERBOSE) {
+ u_int64_t packets[2];
+ u_int64_t bytes[2];
+ u_int32_t creation = ntohl(s->creation);
+ u_int32_t expire = ntohl(s->expire);
+
+ sec = creation % 60;
+ creation /= 60;
+ min = creation % 60;
+ creation /= 60;
+ printf(" age %.2u:%.2u:%.2u", creation, min, sec);
+ sec = expire % 60;
+ expire /= 60;
+ min = expire % 60;
+ expire /= 60;
+ printf(", expires in %.2u:%.2u:%.2u", expire, min, sec);
+
+ bcopy(s->packets[0], &packets[0], sizeof(u_int64_t));
+ bcopy(s->packets[1], &packets[1], sizeof(u_int64_t));
+ bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t));
+ bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t));
+ printf(", %ju:%ju pkts, %ju:%ju bytes",
+ (uintmax_t )be64toh(packets[0]),
+ (uintmax_t )be64toh(packets[1]),
+ (uintmax_t )be64toh(bytes[0]),
+ (uintmax_t )be64toh(bytes[1]));
+ if (ntohl(s->anchor) != -1)
+ printf(", anchor %u", ntohl(s->anchor));
+ if (ntohl(s->rule) != -1)
+ printf(", rule %u", ntohl(s->rule));
+ if (s->state_flags & PFSTATE_SLOPPY)
+ printf(", sloppy");
+ if (s->sync_flags & PFSYNC_FLAG_SRCNODE)
+ printf(", source-track");
+ if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE)
+ printf(", sticky-address");
+ printf("\n");
+ }
+ if (opts & PF_OPT_VERBOSE2) {
+ u_int64_t id;
+
+ bcopy(&s->id, &id, sizeof(u_int64_t));
+ printf(" id: %016jx creatorid: %08x",
+ (uintmax_t )be64toh(id), ntohl(s->creatorid));
+ printf("\n");
+ }
+}
+
+int
+unmask(struct pf_addr *m, sa_family_t af)
+{
+ int i = 31, j = 0, b = 0;
+ u_int32_t tmp;
+
+ while (j < 4 && m->addr32[j] == 0xffffffff) {
+ b += 32;
+ j++;
+ }
+ if (j < 4) {
+ tmp = ntohl(m->addr32[j]);
+ for (i = 31; tmp & (1 << i); --i)
+ b++;
+ }
+ return (b);
+}
diff --git a/freebsd/sbin/pfctl/pfctl.c b/freebsd/sbin/pfctl/pfctl.c
new file mode 100644
index 00000000..ab597068
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl.c
@@ -0,0 +1,2445 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#define __need_getopt_newlib
+#include <getopt.h>
+#include <machine/rtems-bsd-program.h>
+#include <machine/rtems-bsd-commands.h>
+#define pf_get_ruleset_number _bsd_pf_get_ruleset_number
+#define pf_init_ruleset _bsd_pf_init_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/endian.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <net/altq/altq.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl-data.h"
+#endif /* __rtems__ */
+
+void usage(void);
+int pfctl_enable(int, int);
+int pfctl_disable(int, int);
+int pfctl_clear_stats(int, int);
+int pfctl_clear_interface_flags(int, int);
+int pfctl_clear_rules(int, int, char *);
+int pfctl_clear_nat(int, int, char *);
+int pfctl_clear_altq(int, int);
+int pfctl_clear_src_nodes(int, int);
+int pfctl_clear_states(int, const char *, int);
+void pfctl_addrprefix(char *, struct pf_addr *);
+int pfctl_kill_src_nodes(int, const char *, int);
+int pfctl_net_kill_states(int, const char *, int);
+int pfctl_label_kill_states(int, const char *, int);
+int pfctl_id_kill_states(int, const char *, int);
+void pfctl_init_options(struct pfctl *);
+int pfctl_load_options(struct pfctl *);
+int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
+int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int);
+int pfctl_load_debug(struct pfctl *, unsigned int);
+int pfctl_load_logif(struct pfctl *, char *);
+int pfctl_load_hostid(struct pfctl *, u_int32_t);
+int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int,
+ char *);
+void pfctl_print_rule_counters(struct pf_rule *, int);
+int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
+int pfctl_show_nat(int, int, char *);
+int pfctl_show_src_nodes(int, int);
+int pfctl_show_states(int, const char *, int);
+int pfctl_show_status(int, int);
+int pfctl_show_timeouts(int, int);
+int pfctl_show_limits(int, int);
+void pfctl_debug(int, u_int32_t, int);
+int pfctl_test_altqsupport(int, int);
+int pfctl_show_anchors(int, int, char *);
+int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *);
+int pfctl_load_ruleset(struct pfctl *, char *,
+ struct pf_ruleset *, int, int);
+int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int);
+const char *pfctl_lookup_option(char *, const char * const *);
+
+static struct pf_anchor_global pf_anchors;
+static struct pf_anchor pf_main_anchor;
+
+static const char *clearopt;
+static char *rulesopt;
+static const char *showopt;
+static const char *debugopt;
+static char *anchoropt;
+static const char *optiopt = NULL;
+static const char *pf_device = "/dev/pf";
+static char *ifaceopt;
+static char *tableopt;
+static const char *tblcmdopt;
+static int src_node_killers;
+static char *src_node_kill[2];
+static int state_killers;
+static char *state_kill[2];
+int loadopt;
+int altqsupport;
+
+int dev = -1;
+static int first_title = 1;
+static int labels = 0;
+
+#define INDENT(d, o) do { \
+ if (o) { \
+ int i; \
+ for (i=0; i < d; i++) \
+ printf(" "); \
+ } \
+ } while (0); \
+
+
+static const struct {
+ const char *name;
+ int index;
+} pf_limits[] = {
+ { "states", PF_LIMIT_STATES },
+ { "src-nodes", PF_LIMIT_SRC_NODES },
+ { "frags", PF_LIMIT_FRAGS },
+ { "table-entries", PF_LIMIT_TABLE_ENTRIES },
+ { NULL, 0 }
+};
+
+struct pf_hint {
+ const char *name;
+ int timeout;
+};
+static const struct pf_hint pf_hint_normal[] = {
+ { "tcp.first", 2 * 60 },
+ { "tcp.opening", 30 },
+ { "tcp.established", 24 * 60 * 60 },
+ { "tcp.closing", 15 * 60 },
+ { "tcp.finwait", 45 },
+ { "tcp.closed", 90 },
+ { "tcp.tsdiff", 30 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_satellite[] = {
+ { "tcp.first", 3 * 60 },
+ { "tcp.opening", 30 + 5 },
+ { "tcp.established", 24 * 60 * 60 },
+ { "tcp.closing", 15 * 60 + 5 },
+ { "tcp.finwait", 45 + 5 },
+ { "tcp.closed", 90 + 5 },
+ { "tcp.tsdiff", 60 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_conservative[] = {
+ { "tcp.first", 60 * 60 },
+ { "tcp.opening", 15 * 60 },
+ { "tcp.established", 5 * 24 * 60 * 60 },
+ { "tcp.closing", 60 * 60 },
+ { "tcp.finwait", 10 * 60 },
+ { "tcp.closed", 3 * 60 },
+ { "tcp.tsdiff", 60 },
+ { NULL, 0 }
+};
+static const struct pf_hint pf_hint_aggressive[] = {
+ { "tcp.first", 30 },
+ { "tcp.opening", 5 },
+ { "tcp.established", 5 * 60 * 60 },
+ { "tcp.closing", 60 },
+ { "tcp.finwait", 30 },
+ { "tcp.closed", 30 },
+ { "tcp.tsdiff", 10 },
+ { NULL, 0 }
+};
+
+static const struct {
+ const char *name;
+ const struct pf_hint *hint;
+} pf_hints[] = {
+ { "normal", pf_hint_normal },
+ { "satellite", pf_hint_satellite },
+ { "high-latency", pf_hint_satellite },
+ { "conservative", pf_hint_conservative },
+ { "aggressive", pf_hint_aggressive },
+ { NULL, NULL }
+};
+
+static const char * const clearopt_list[] = {
+ "nat", "queue", "rules", "Sources",
+ "states", "info", "Tables", "osfp", "all", NULL
+};
+
+static const char * const showopt_list[] = {
+ "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
+ "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
+ "all", NULL
+};
+
+static const char * const tblcmdopt_list[] = {
+ "kill", "flush", "add", "delete", "load", "replace", "show",
+ "test", "zero", "expire", NULL
+};
+
+static const char * const debugopt_list[] = {
+ "none", "urgent", "misc", "loud", NULL
+};
+
+static const char * const optiopt_list[] = {
+ "none", "basic", "profile", NULL
+};
+
+void
+usage(void)
+{
+#ifndef __rtems__
+ extern char *__progname;
+#else /* __rtems__ */
+#define __progname "pfctl"
+#endif /* __rtems__ */
+
+ fprintf(stderr,
+"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
+ "\t[-f file] [-i interface] [-K host | network]\n"
+ "\t[-k host | network | label | id] [-o level] [-p device]\n"
+ "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
+ __progname);
+
+ exit(1);
+}
+
+int
+pfctl_enable(int dev, int opts)
+{
+ if (ioctl(dev, DIOCSTART)) {
+ if (errno == EEXIST)
+ errx(1, "pf already enabled");
+ else if (errno == ESRCH)
+ errx(1, "pfil registeration failed");
+ else
+ err(1, "DIOCSTART");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf enabled\n");
+
+ if (altqsupport && ioctl(dev, DIOCSTARTALTQ))
+ if (errno != EEXIST)
+ err(1, "DIOCSTARTALTQ");
+
+ return (0);
+}
+
+int
+pfctl_disable(int dev, int opts)
+{
+ if (ioctl(dev, DIOCSTOP)) {
+ if (errno == ENOENT)
+ errx(1, "pf not enabled");
+ else
+ err(1, "DIOCSTOP");
+ }
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf disabled\n");
+
+ if (altqsupport && ioctl(dev, DIOCSTOPALTQ))
+ if (errno != ENOENT)
+ err(1, "DIOCSTOPALTQ");
+
+ return (0);
+}
+
+int
+pfctl_clear_stats(int dev, int opts)
+{
+ if (ioctl(dev, DIOCCLRSTATUS))
+ err(1, "DIOCCLRSTATUS");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf: statistics cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_interface_flags(int dev, int opts)
+{
+ struct pfioc_iface pi;
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ bzero(&pi, sizeof(pi));
+ pi.pfiio_flags = PFI_IFLAG_SKIP;
+
+ if (ioctl(dev, DIOCCLRIFFLAG, &pi))
+ err(1, "DIOCCLRIFFLAG");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "pf: interface flags reset\n");
+ }
+ return (0);
+}
+
+int
+pfctl_clear_rules(int dev, int opts, char *anchorname)
+{
+ struct pfr_buffer t;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_rules");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "rules cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_nat(int dev, int opts, char *anchorname)
+{
+ struct pfr_buffer t;
+
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) ||
+ pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_nat");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "nat cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_altq(int dev, int opts)
+{
+ struct pfr_buffer t;
+
+ if (!altqsupport)
+ return (-1);
+ memset(&t, 0, sizeof(t));
+ t.pfrb_type = PFRB_TRANS;
+ if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") ||
+ pfctl_trans(dev, &t, DIOCXBEGIN, 0) ||
+ pfctl_trans(dev, &t, DIOCXCOMMIT, 0))
+ err(1, "pfctl_clear_altq");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "altq cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_src_nodes(int dev, int opts)
+{
+ if (ioctl(dev, DIOCCLRSRCNODES))
+ err(1, "DIOCCLRSRCNODES");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "source tracking entries cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ memset(&psk, 0, sizeof(psk));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ if (ioctl(dev, DIOCCLRSTATES, &psk))
+ err(1, "DIOCCLRSTATES");
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "%d states cleared\n", psk.psk_killed);
+ return (0);
+}
+
+void
+pfctl_addrprefix(char *addr, struct pf_addr *mask)
+{
+ char *p;
+ const char *errstr;
+ int prefix, ret_ga, q, r;
+ struct addrinfo hints, *res;
+
+ if ((p = strchr(addr, '/')) == NULL)
+ return;
+
+ *p++ = '\0';
+ prefix = strtonum(p, 0, 128, &errstr);
+ if (errstr)
+ errx(1, "prefix is %s: %s", errstr, p);
+
+ bzero(&hints, sizeof(hints));
+ /* prefix only with numeric addresses */
+ hints.ai_flags |= AI_NUMERICHOST;
+
+ if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+
+ if (res->ai_family == AF_INET && prefix > 32)
+ errx(1, "prefix too long for AF_INET");
+ else if (res->ai_family == AF_INET6 && prefix > 128)
+ errx(1, "prefix too long for AF_INET6");
+
+ q = prefix >> 3;
+ r = prefix & 7;
+ switch (res->ai_family) {
+ case AF_INET:
+ bzero(&mask->v4, sizeof(mask->v4));
+ mask->v4.s_addr = htonl((u_int32_t)
+ (0xffffffffffULL << (32 - prefix)));
+ break;
+ case AF_INET6:
+ bzero(&mask->v6, sizeof(mask->v6));
+ if (q > 0)
+ memset((void *)&mask->v6, 0xff, q);
+ if (r > 0)
+ *((u_char *)&mask->v6 + q) =
+ (0xff00 >> r) & 0xff;
+ break;
+ }
+ freeaddrinfo(res);
+}
+
+int
+pfctl_kill_src_nodes(int dev, const char *iface, int opts)
+{
+ struct pfioc_src_node_kill psnk;
+ struct addrinfo *res[2], *resp[2];
+ struct sockaddr last_src, last_dst;
+ int killed, sources, dests;
+ int ret_ga;
+
+ killed = sources = dests = 0;
+
+ memset(&psnk, 0, sizeof(psnk));
+ memset(&psnk.psnk_src.addr.v.a.mask, 0xff,
+ sizeof(psnk.psnk_src.addr.v.a.mask));
+ memset(&last_src, 0xff, sizeof(last_src));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+
+ pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask);
+
+ if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
+ if (resp[0]->ai_addr == NULL)
+ continue;
+ /* We get lots of duplicates. Catch the easy ones */
+ if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
+ continue;
+ last_src = *(struct sockaddr *)resp[0]->ai_addr;
+
+ psnk.psnk_af = resp[0]->ai_family;
+ sources++;
+
+ if (psnk.psnk_af == AF_INET)
+ psnk.psnk_src.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
+ else if (psnk.psnk_af == AF_INET6)
+ psnk.psnk_src.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[0]->ai_addr)->
+ sin6_addr;
+ else
+ errx(1, "Unknown address family %d", psnk.psnk_af);
+
+ if (src_node_killers > 1) {
+ dests = 0;
+ memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
+ sizeof(psnk.psnk_dst.addr.v.a.mask));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ pfctl_addrprefix(src_node_kill[1],
+ &psnk.psnk_dst.addr.v.a.mask);
+ if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL,
+ &res[1]))) {
+ errx(1, "getaddrinfo: %s",
+ gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[1] = res[1]; resp[1];
+ resp[1] = resp[1]->ai_next) {
+ if (resp[1]->ai_addr == NULL)
+ continue;
+ if (psnk.psnk_af != resp[1]->ai_family)
+ continue;
+
+ if (memcmp(&last_dst, resp[1]->ai_addr,
+ sizeof(last_dst)) == 0)
+ continue;
+ last_dst = *(struct sockaddr *)resp[1]->ai_addr;
+
+ dests++;
+
+ if (psnk.psnk_af == AF_INET)
+ psnk.psnk_dst.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[1]->
+ ai_addr)->sin_addr;
+ else if (psnk.psnk_af == AF_INET6)
+ psnk.psnk_dst.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[1]->
+ ai_addr)->sin6_addr;
+ else
+ errx(1, "Unknown address family %d",
+ psnk.psnk_af);
+
+ if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
+ err(1, "DIOCKILLSRCNODES");
+ killed += psnk.psnk_killed;
+ }
+ freeaddrinfo(res[1]);
+ } else {
+ if (ioctl(dev, DIOCKILLSRCNODES, &psnk))
+ err(1, "DIOCKILLSRCNODES");
+ killed += psnk.psnk_killed;
+ }
+ }
+
+ freeaddrinfo(res[0]);
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d src nodes from %d sources and %d "
+ "destinations\n", killed, sources, dests);
+ return (0);
+}
+
+int
+pfctl_net_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+ struct addrinfo *res[2], *resp[2];
+ struct sockaddr last_src, last_dst;
+ int killed, sources, dests;
+ int ret_ga;
+
+ killed = sources = dests = 0;
+
+ memset(&psk, 0, sizeof(psk));
+ memset(&psk.psk_src.addr.v.a.mask, 0xff,
+ sizeof(psk.psk_src.addr.v.a.mask));
+ memset(&last_src, 0xff, sizeof(last_src));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
+
+ if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
+ errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) {
+ if (resp[0]->ai_addr == NULL)
+ continue;
+ /* We get lots of duplicates. Catch the easy ones */
+ if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0)
+ continue;
+ last_src = *(struct sockaddr *)resp[0]->ai_addr;
+
+ psk.psk_af = resp[0]->ai_family;
+ sources++;
+
+ if (psk.psk_af == AF_INET)
+ psk.psk_src.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr;
+ else if (psk.psk_af == AF_INET6)
+ psk.psk_src.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[0]->ai_addr)->
+ sin6_addr;
+ else
+ errx(1, "Unknown address family %d", psk.psk_af);
+
+ if (state_killers > 1) {
+ dests = 0;
+ memset(&psk.psk_dst.addr.v.a.mask, 0xff,
+ sizeof(psk.psk_dst.addr.v.a.mask));
+ memset(&last_dst, 0xff, sizeof(last_dst));
+ pfctl_addrprefix(state_kill[1],
+ &psk.psk_dst.addr.v.a.mask);
+ if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL,
+ &res[1]))) {
+ errx(1, "getaddrinfo: %s",
+ gai_strerror(ret_ga));
+ /* NOTREACHED */
+ }
+ for (resp[1] = res[1]; resp[1];
+ resp[1] = resp[1]->ai_next) {
+ if (resp[1]->ai_addr == NULL)
+ continue;
+ if (psk.psk_af != resp[1]->ai_family)
+ continue;
+
+ if (memcmp(&last_dst, resp[1]->ai_addr,
+ sizeof(last_dst)) == 0)
+ continue;
+ last_dst = *(struct sockaddr *)resp[1]->ai_addr;
+
+ dests++;
+
+ if (psk.psk_af == AF_INET)
+ psk.psk_dst.addr.v.a.addr.v4 =
+ ((struct sockaddr_in *)resp[1]->
+ ai_addr)->sin_addr;
+ else if (psk.psk_af == AF_INET6)
+ psk.psk_dst.addr.v.a.addr.v6 =
+ ((struct sockaddr_in6 *)resp[1]->
+ ai_addr)->sin6_addr;
+ else
+ errx(1, "Unknown address family %d",
+ psk.psk_af);
+
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+ killed += psk.psk_killed;
+ }
+ freeaddrinfo(res[1]);
+ } else {
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+ killed += psk.psk_killed;
+ }
+ }
+
+ freeaddrinfo(res[0]);
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states from %d sources and %d "
+ "destinations\n", killed, sources, dests);
+ return (0);
+}
+
+int
+pfctl_label_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
+ warnx("no label specified");
+ usage();
+ }
+ memset(&psk, 0, sizeof(psk));
+ if (iface != NULL && strlcpy(psk.psk_ifname, iface,
+ sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
+ errx(1, "invalid interface: %s", iface);
+
+ if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >=
+ sizeof(psk.psk_label))
+ errx(1, "label too long: %s", state_kill[1]);
+
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states\n", psk.psk_killed);
+
+ return (0);
+}
+
+int
+pfctl_id_kill_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_state_kill psk;
+
+ if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
+ warnx("no id specified");
+ usage();
+ }
+
+ memset(&psk, 0, sizeof(psk));
+ if ((sscanf(state_kill[1], "%jx/%x",
+ &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
+ HTONL(psk.psk_pfcmp.creatorid);
+ else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) {
+ psk.psk_pfcmp.creatorid = 0;
+ } else {
+ warnx("wrong id format specified");
+ usage();
+ }
+ if (psk.psk_pfcmp.id == 0) {
+ warnx("cannot kill id 0");
+ usage();
+ }
+
+ psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id);
+ if (ioctl(dev, DIOCKILLSTATES, &psk))
+ err(1, "DIOCKILLSTATES");
+
+ if ((opts & PF_OPT_QUIET) == 0)
+ fprintf(stderr, "killed %d states\n", psk.psk_killed);
+
+ return (0);
+}
+
+int
+pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr,
+ u_int32_t ticket, int r_action, char *anchorname)
+{
+ struct pfioc_pooladdr pp;
+ struct pf_pooladdr *pa;
+ u_int32_t pnr, mpnr;
+
+ memset(&pp, 0, sizeof(pp));
+ memcpy(pp.anchor, anchorname, sizeof(pp.anchor));
+ pp.r_action = r_action;
+ pp.r_num = nr;
+ pp.ticket = ticket;
+ if (ioctl(dev, DIOCGETADDRS, &pp)) {
+ warn("DIOCGETADDRS");
+ return (-1);
+ }
+ mpnr = pp.nr;
+ TAILQ_INIT(&pool->list);
+ for (pnr = 0; pnr < mpnr; ++pnr) {
+ pp.nr = pnr;
+ if (ioctl(dev, DIOCGETADDR, &pp)) {
+ warn("DIOCGETADDR");
+ return (-1);
+ }
+ pa = calloc(1, sizeof(struct pf_pooladdr));
+ if (pa == NULL)
+ err(1, "calloc");
+ bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr));
+ TAILQ_INSERT_TAIL(&pool->list, pa, entries);
+ }
+
+ return (0);
+}
+
+void
+pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst)
+{
+ struct pf_pooladdr *pa;
+
+ while ((pa = TAILQ_FIRST(&src->list)) != NULL) {
+ TAILQ_REMOVE(&src->list, pa, entries);
+ TAILQ_INSERT_TAIL(&dst->list, pa, entries);
+ }
+}
+
+void
+pfctl_clear_pool(struct pf_pool *pool)
+{
+ struct pf_pooladdr *pa;
+
+ while ((pa = TAILQ_FIRST(&pool->list)) != NULL) {
+ TAILQ_REMOVE(&pool->list, pa, entries);
+ free(pa);
+ }
+}
+
+void
+pfctl_print_rule_counters(struct pf_rule *rule, int opts)
+{
+ if (opts & PF_OPT_DEBUG) {
+ const char *t[PF_SKIP_COUNT] = { "i", "d", "f",
+ "p", "sa", "sp", "da", "dp" };
+ int i;
+
+ printf(" [ Skip steps: ");
+ for (i = 0; i < PF_SKIP_COUNT; ++i) {
+ if (rule->skip[i].nr == rule->nr + 1)
+ continue;
+ printf("%s=", t[i]);
+ if (rule->skip[i].nr == -1)
+ printf("end ");
+ else
+ printf("%u ", rule->skip[i].nr);
+ }
+ printf("]\n");
+
+ printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n",
+ rule->qname, rule->qid, rule->pqname, rule->pqid);
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" [ Evaluations: %-8llu Packets: %-8llu "
+ "Bytes: %-10llu States: %-6ju]\n",
+ (unsigned long long)rule->evaluations,
+ (unsigned long long)(rule->packets[0] +
+ rule->packets[1]),
+ (unsigned long long)(rule->bytes[0] +
+ rule->bytes[1]), (uintmax_t)rule->u_states_cur);
+ if (!(opts & PF_OPT_DEBUG))
+ printf(" [ Inserted: uid %u pid %u "
+ "State Creations: %-6ju]\n",
+ (unsigned)rule->cuid, (unsigned)rule->cpid,
+ (uintmax_t)rule->u_states_tot);
+ }
+}
+
+void
+pfctl_print_title(char *title)
+{
+ if (!first_title)
+ printf("\n");
+ first_title = 0;
+ printf("%s\n", title);
+}
+
+int
+pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
+ char *anchorname, int depth)
+{
+ struct pfioc_rule pr;
+ u_int32_t nr, mnr, header = 0;
+ int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG);
+ int numeric = opts & PF_OPT_NUMERIC;
+ int len = strlen(path);
+ int brace;
+ char *p;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname);
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.anchor, path, sizeof(pr.anchor));
+ if (opts & PF_OPT_SHOWALL) {
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ header++;
+ }
+ pr.rule.action = PF_SCRUB;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ if (opts & PF_OPT_SHOWALL) {
+ if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header))
+ pfctl_print_title("FILTER RULES:");
+ else if (format == PFCTL_SHOW_LABELS && labels)
+ pfctl_print_title("LABEL COUNTERS:");
+ }
+ mnr = pr.nr;
+ if (opts & PF_OPT_CLRRULECTRS)
+ pr.action = PF_GET_CLR_CNTR;
+
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ goto error;
+ }
+
+ if (pfctl_get_pool(dev, &pr.rule.rpool,
+ nr, pr.ticket, PF_SCRUB, path) != 0)
+ goto error;
+
+ switch (format) {
+ case PFCTL_SHOW_LABELS:
+ break;
+ case PFCTL_SHOW_RULES:
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
+ print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric);
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ break;
+ case PFCTL_SHOW_NOTHING:
+ break;
+ }
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ pr.rule.action = PF_PASS;
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ goto error;
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ goto error;
+ }
+
+ if (pfctl_get_pool(dev, &pr.rule.rpool,
+ nr, pr.ticket, PF_PASS, path) != 0)
+ goto error;
+
+ switch (format) {
+ case PFCTL_SHOW_LABELS:
+ if (pr.rule.label[0]) {
+ printf("%s %llu %llu %llu %llu"
+ " %llu %llu %llu %ju\n",
+ pr.rule.label,
+ (unsigned long long)pr.rule.evaluations,
+ (unsigned long long)(pr.rule.packets[0] +
+ pr.rule.packets[1]),
+ (unsigned long long)(pr.rule.bytes[0] +
+ pr.rule.bytes[1]),
+ (unsigned long long)pr.rule.packets[0],
+ (unsigned long long)pr.rule.bytes[0],
+ (unsigned long long)pr.rule.packets[1],
+ (unsigned long long)pr.rule.bytes[1],
+ (uintmax_t)pr.rule.u_states_tot);
+ }
+ break;
+ case PFCTL_SHOW_RULES:
+ brace = 0;
+ if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL))
+ labels = 1;
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ if (pr.anchor_call[0] &&
+ ((((p = strrchr(pr.anchor_call, '_')) != NULL) &&
+ ((void *)p == (void *)pr.anchor_call ||
+ *(--p) == '/')) || (opts & PF_OPT_RECURSE))) {
+ brace++;
+ if ((p = strrchr(pr.anchor_call, '/')) !=
+ NULL)
+ p++;
+ else
+ p = &pr.anchor_call[0];
+ } else
+ p = &pr.anchor_call[0];
+
+ print_rule(&pr.rule, p, rule_numbers, numeric);
+ if (brace)
+ printf(" {\n");
+ else
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ if (brace) {
+ pfctl_show_rules(dev, path, opts, format,
+ p, depth + 1);
+ INDENT(depth, !(opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ break;
+ case PFCTL_SHOW_NOTHING:
+ break;
+ }
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ path[len] = '\0';
+ return (0);
+
+ error:
+ path[len] = '\0';
+ return (-1);
+}
+
+int
+pfctl_show_nat(int dev, int opts, char *anchorname)
+{
+ struct pfioc_rule pr;
+ u_int32_t mnr, nr;
+#ifndef __rtems__
+ static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
+#else /* __rtems__ */
+ static const int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
+#endif /* __rtems__ */
+ int i, dotitle = opts & PF_OPT_SHOWALL;
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.anchor, anchorname, sizeof(pr.anchor));
+ for (i = 0; i < 3; i++) {
+ pr.rule.action = nattype[i];
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ return (-1);
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULE");
+ return (-1);
+ }
+ if (pfctl_get_pool(dev, &pr.rule.rpool, nr,
+ pr.ticket, nattype[i], anchorname) != 0)
+ return (-1);
+ if (dotitle) {
+ pfctl_print_title("TRANSLATION RULES:");
+ dotitle = 0;
+ }
+ print_rule(&pr.rule, pr.anchor_call,
+ opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC);
+ printf("\n");
+ pfctl_print_rule_counters(&pr.rule, opts);
+ pfctl_clear_pool(&pr.rule.rpool);
+ }
+ }
+ return (0);
+}
+
+int
+pfctl_show_src_nodes(int dev, int opts)
+{
+ struct pfioc_src_nodes psn;
+ struct pf_src_node *p;
+ char *inbuf = NULL, *newinbuf = NULL;
+ unsigned int len = 0;
+ int i;
+
+ memset(&psn, 0, sizeof(psn));
+ for (;;) {
+ psn.psn_len = len;
+ if (len) {
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
+ err(1, "realloc");
+ psn.psn_buf = inbuf = newinbuf;
+ }
+ if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
+ warn("DIOCGETSRCNODES");
+ free(inbuf);
+ return (-1);
+ }
+ if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
+ break;
+ if (len == 0 && psn.psn_len == 0)
+ goto done;
+ if (len == 0 && psn.psn_len != 0)
+ len = psn.psn_len;
+ if (psn.psn_len == 0)
+ goto done; /* no src_nodes */
+ len *= 2;
+ }
+ p = psn.psn_src_nodes;
+ if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
+ pfctl_print_title("SOURCE TRACKING NODES:");
+ for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
+ print_src_node(p, opts);
+ p++;
+ }
+done:
+ free(inbuf);
+ return (0);
+}
+
+int
+pfctl_show_states(int dev, const char *iface, int opts)
+{
+ struct pfioc_states ps;
+ struct pfsync_state *p;
+ char *inbuf = NULL, *newinbuf = NULL;
+ unsigned int len = 0;
+ int i, dotitle = (opts & PF_OPT_SHOWALL);
+
+ memset(&ps, 0, sizeof(ps));
+ for (;;) {
+ ps.ps_len = len;
+ if (len) {
+ newinbuf = realloc(inbuf, len);
+ if (newinbuf == NULL)
+ err(1, "realloc");
+ ps.ps_buf = inbuf = newinbuf;
+ }
+ if (ioctl(dev, DIOCGETSTATES, &ps) < 0) {
+ warn("DIOCGETSTATES");
+ free(inbuf);
+ return (-1);
+ }
+ if (ps.ps_len + sizeof(struct pfioc_states) < len)
+ break;
+ if (len == 0 && ps.ps_len == 0)
+ goto done;
+ if (len == 0 && ps.ps_len != 0)
+ len = ps.ps_len;
+ if (ps.ps_len == 0)
+ goto done; /* no states */
+ len *= 2;
+ }
+ p = ps.ps_states;
+ for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
+ if (iface != NULL && strcmp(p->ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("STATES:");
+ dotitle = 0;
+ }
+ print_state(p, opts);
+ }
+done:
+ free(inbuf);
+ return (0);
+}
+
+int
+pfctl_show_status(int dev, int opts)
+{
+ struct pf_status status;
+
+ if (ioctl(dev, DIOCGETSTATUS, &status)) {
+ warn("DIOCGETSTATUS");
+ return (-1);
+ }
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INFO:");
+ print_status(&status, opts);
+ return (0);
+}
+
+int
+pfctl_show_timeouts(int dev, int opts)
+{
+ struct pfioc_tm pt;
+ int i;
+
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("TIMEOUTS:");
+ memset(&pt, 0, sizeof(pt));
+ for (i = 0; pf_timeouts[i].name; i++) {
+ pt.timeout = pf_timeouts[i].timeout;
+ if (ioctl(dev, DIOCGETTIMEOUT, &pt))
+ err(1, "DIOCGETTIMEOUT");
+ printf("%-20s %10d", pf_timeouts[i].name, pt.seconds);
+ if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START &&
+ pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END)
+ printf(" states");
+ else
+ printf("s");
+ printf("\n");
+ }
+ return (0);
+
+}
+
+int
+pfctl_show_limits(int dev, int opts)
+{
+ struct pfioc_limit pl;
+ int i;
+
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("LIMITS:");
+ memset(&pl, 0, sizeof(pl));
+ for (i = 0; pf_limits[i].name; i++) {
+ pl.index = pf_limits[i].index;
+ if (ioctl(dev, DIOCGETLIMIT, &pl))
+ err(1, "DIOCGETLIMIT");
+ printf("%-13s ", pf_limits[i].name);
+ if (pl.limit == UINT_MAX)
+ printf("unlimited\n");
+ else
+ printf("hard limit %8u\n", pl.limit);
+ }
+ return (0);
+}
+
+/* callbacks for rule/nat/rdr/addr */
+int
+pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af)
+{
+ struct pf_pooladdr *pa;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr))
+ err(1, "DIOCBEGINADDRS");
+ }
+
+ pf->paddr.af = af;
+ TAILQ_FOREACH(pa, &p->list, entries) {
+ memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr))
+ err(1, "DIOCADDADDR");
+ }
+ }
+ return (0);
+}
+
+int
+pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call)
+{
+ u_int8_t rs_num;
+ struct pf_rule *rule;
+ struct pf_ruleset *rs;
+ char *p;
+
+ rs_num = pf_get_ruleset_number(r->action);
+ if (rs_num == PF_RULESET_MAX)
+ errx(1, "Invalid rule type %d", r->action);
+
+ rs = &pf->anchor->ruleset;
+
+ if (anchor_call[0] && r->anchor == NULL) {
+ /*
+ * Don't make non-brace anchors part of the main anchor pool.
+ */
+ if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL)
+ err(1, "pfctl_add_rule: calloc");
+
+ pf_init_ruleset(&r->anchor->ruleset);
+ r->anchor->ruleset.anchor = r->anchor;
+ if (strlcpy(r->anchor->path, anchor_call,
+ sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path))
+ errx(1, "pfctl_add_rule: strlcpy");
+ if ((p = strrchr(anchor_call, '/')) != NULL) {
+ if (!strlen(p))
+ err(1, "pfctl_add_rule: bad anchor name %s",
+ anchor_call);
+ } else
+ p = (char *)anchor_call;
+ if (strlcpy(r->anchor->name, p,
+ sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name))
+ errx(1, "pfctl_add_rule: strlcpy");
+ }
+
+ if ((rule = calloc(1, sizeof(*rule))) == NULL)
+ err(1, "calloc");
+ bcopy(r, rule, sizeof(*rule));
+ TAILQ_INIT(&rule->rpool.list);
+ pfctl_move_pool(&r->rpool, &rule->rpool);
+
+ TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries);
+ return (0);
+}
+
+int
+pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a)
+{
+ int osize = pf->trans->pfrb_size;
+
+ if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_RDR, path))
+ return (1);
+ }
+ if (a == pf->astack[0] && ((altqsupport &&
+ (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path))
+ return (2);
+ }
+ if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) ||
+ pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path))
+ return (3);
+ }
+ if (pf->loadopt & PFCTL_FLAG_TABLE)
+ if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path))
+ return (4);
+ if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize))
+ return (5);
+
+ return (0);
+}
+
+int
+pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs,
+ int rs_num, int depth)
+{
+ struct pf_rule *r;
+ int error, len = strlen(path);
+ int brace = 0;
+
+ pf->anchor = rs->anchor;
+
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name);
+
+ if (depth) {
+ if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) {
+ brace++;
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf(" {\n");
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ (error = pfctl_ruleset_trans(pf,
+ path, rs->anchor))) {
+ printf("pfctl_load_rulesets: "
+ "pfctl_ruleset_trans %d\n", error);
+ goto error;
+ }
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+
+ }
+
+ if (pf->optimize && rs_num == PF_RULESET_FILTER)
+ pfctl_optimize_ruleset(pf, rs);
+
+ while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) {
+ TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries);
+ if ((error = pfctl_load_rule(pf, path, r, depth)))
+ goto error;
+ if (r->anchor) {
+ if ((error = pfctl_load_ruleset(pf, path,
+ &r->anchor->ruleset, rs_num, depth + 1)))
+ goto error;
+ } else if (pf->opts & PF_OPT_VERBOSE)
+ printf("\n");
+ free(r);
+ }
+ if (brace && pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE));
+ printf("}\n");
+ }
+ path[len] = '\0';
+ return (0);
+
+ error:
+ path[len] = '\0';
+ return (error);
+
+}
+
+int
+pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth)
+{
+ u_int8_t rs_num = pf_get_ruleset_number(r->action);
+ char *name;
+ struct pfioc_rule pr;
+ int len = strlen(path);
+
+ bzero(&pr, sizeof(pr));
+ /* set up anchor before adding to path for anchor_call */
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path);
+ if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor))
+ errx(1, "pfctl_load_rule: strlcpy");
+
+ if (r->anchor) {
+ if (r->anchor->match) {
+ if (path[0])
+ snprintf(&path[len], MAXPATHLEN - len,
+ "/%s", r->anchor->name);
+ else
+ snprintf(&path[len], MAXPATHLEN - len,
+ "%s", r->anchor->name);
+ name = path;
+ } else
+ name = r->anchor->path;
+ } else
+ name = "";
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (pfctl_add_pool(pf, &r->rpool, r->af))
+ return (1);
+ pr.pool_ticket = pf->paddr.ticket;
+ memcpy(&pr.rule, r, sizeof(pr.rule));
+ if (r->anchor && strlcpy(pr.anchor_call, name,
+ sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call))
+ errx(1, "pfctl_load_rule: strlcpy");
+ if (ioctl(pf->dev, DIOCADDRULE, &pr))
+ err(1, "DIOCADDRULE");
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE) {
+ INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2));
+ print_rule(r, r->anchor ? r->anchor->name : "",
+ pf->opts & PF_OPT_VERBOSE2,
+ pf->opts & PF_OPT_NUMERIC);
+ }
+ path[len] = '\0';
+ pfctl_clear_pool(&r->rpool);
+ return (0);
+}
+
+int
+pfctl_add_altq(struct pfctl *pf, struct pf_altq *a)
+{
+ if (altqsupport &&
+ (loadopt & PFCTL_FLAG_ALTQ) != 0) {
+ memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq));
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) {
+ if (errno == ENXIO)
+ errx(1, "qtype not configured");
+ else if (errno == ENODEV)
+ errx(1, "%s: driver does not support "
+ "altq", a->ifname);
+ else
+ err(1, "DIOCADDALTQ");
+ }
+ }
+ pfaltq_store(&pf->paltq->altq);
+ }
+ return (0);
+}
+
+int
+pfctl_rules(int dev, char *filename, int opts, int optimize,
+ char *anchorname, struct pfr_buffer *trans)
+{
+#define ERR(x) do { warn(x); goto _error; } while(0)
+#define ERRX(x) do { warnx(x); goto _error; } while(0)
+
+ struct pfr_buffer *t, buf;
+ struct pfioc_altq pa;
+ struct pfctl pf;
+ struct pf_ruleset *rs;
+ struct pfr_table trs;
+ char *path;
+ int osize;
+
+ RB_INIT(&pf_anchors);
+ memset(&pf_main_anchor, 0, sizeof(pf_main_anchor));
+ pf_init_ruleset(&pf_main_anchor.ruleset);
+ pf_main_anchor.ruleset.anchor = &pf_main_anchor;
+ if (trans == NULL) {
+ bzero(&buf, sizeof(buf));
+ buf.pfrb_type = PFRB_TRANS;
+ t = &buf;
+ osize = 0;
+ } else {
+ t = trans;
+ osize = t->pfrb_size;
+ }
+
+ memset(&pa, 0, sizeof(pa));
+ memset(&pf, 0, sizeof(pf));
+ memset(&trs, 0, sizeof(trs));
+ if ((path = calloc(1, MAXPATHLEN)) == NULL)
+ ERRX("pfctl_rules: calloc");
+ if (strlcpy(trs.pfrt_anchor, anchorname,
+ sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor))
+ ERRX("pfctl_rules: strlcpy");
+ pf.dev = dev;
+ pf.opts = opts;
+ pf.optimize = optimize;
+ pf.loadopt = loadopt;
+
+ /* non-brace anchor, create without resolving the path */
+ if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
+ ERRX("pfctl_rules: calloc");
+ rs = &pf.anchor->ruleset;
+ pf_init_ruleset(rs);
+ rs->anchor = pf.anchor;
+ if (strlcpy(pf.anchor->path, anchorname,
+ sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path))
+ errx(1, "pfctl_add_rule: strlcpy");
+ if (strlcpy(pf.anchor->name, anchorname,
+ sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name))
+ errx(1, "pfctl_add_rule: strlcpy");
+
+
+ pf.astack[0] = pf.anchor;
+ pf.asd = 0;
+ if (anchorname[0])
+ pf.loadopt &= ~PFCTL_FLAG_ALTQ;
+ pf.paltq = &pa;
+ pf.trans = t;
+ pfctl_init_options(&pf);
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ /*
+ * XXX For the time being we need to open transactions for
+ * the main ruleset before parsing, because tables are still
+ * loaded at parse time.
+ */
+ if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
+ ERRX("pfctl_rules");
+ if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
+ pa.ticket =
+ pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
+ if (pf.loadopt & PFCTL_FLAG_TABLE)
+ pf.astack[0]->ruleset.tticket =
+ pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname);
+ }
+
+ if (parse_config(filename, &pf) < 0) {
+ if ((opts & PF_OPT_NOACTION) == 0)
+ ERRX("Syntax error in config file: "
+ "pf rules not loaded");
+ else
+ goto _error;
+ }
+
+ if ((pf.loadopt & PFCTL_FLAG_FILTER &&
+ (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_NAT &&
+ (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_FILTER &&
+ pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) {
+ if ((opts & PF_OPT_NOACTION) == 0)
+ ERRX("Unable to load rules into kernel");
+ else
+ goto _error;
+ }
+
+ if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0))
+ if (check_commit_altq(dev, opts) != 0)
+ ERRX("errors in altq config");
+
+ /* process "load anchor" directives */
+ if (!anchorname[0])
+ if (pfctl_load_anchors(dev, &pf, t) == -1)
+ ERRX("load anchors");
+
+ if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) {
+ if (!anchorname[0])
+ if (pfctl_load_options(&pf))
+ goto _error;
+ if (pfctl_trans(dev, t, DIOCXCOMMIT, osize))
+ ERR("DIOCXCOMMIT");
+ }
+ return (0);
+
+_error:
+ if (trans == NULL) { /* main ruleset */
+ if ((opts & PF_OPT_NOACTION) == 0)
+ if (pfctl_trans(dev, t, DIOCXROLLBACK, osize))
+ err(1, "DIOCXROLLBACK");
+ exit(1);
+ } else { /* sub ruleset */
+ return (-1);
+ }
+
+#undef ERR
+#undef ERRX
+}
+
+FILE *
+pfctl_fopen(const char *name, const char *mode)
+{
+ struct stat st;
+ FILE *fp;
+
+ fp = fopen(name, mode);
+ if (fp == NULL)
+ return (NULL);
+ if (fstat(fileno(fp), &st)) {
+ fclose(fp);
+ return (NULL);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ fclose(fp);
+ errno = EISDIR;
+ return (NULL);
+ }
+ return (fp);
+}
+
+void
+pfctl_init_options(struct pfctl *pf)
+{
+
+ pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL;
+ pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL;
+ pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL;
+ pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL;
+ pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL;
+ pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL;
+ pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL;
+ pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL;
+ pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL;
+ pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL;
+ pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL;
+ pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL;
+ pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL;
+ pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL;
+ pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL;
+ pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START;
+ pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END;
+
+ pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT;
+ pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT;
+ pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT;
+ pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT;
+
+ pf->debug = PF_DEBUG_URGENT;
+}
+
+int
+pfctl_load_options(struct pfctl *pf)
+{
+ int i, error = 0;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ /* load limits */
+ for (i = 0; i < PF_LIMIT_MAX; i++) {
+ if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i])
+ continue;
+ if (pfctl_load_limit(pf, i, pf->limit[i]))
+ error = 1;
+ }
+
+ /*
+ * If we've set the limit, but haven't explicitly set adaptive
+ * timeouts, do it now with a start of 60% and end of 120%.
+ */
+ if (pf->limit_set[PF_LIMIT_STATES] &&
+ !pf->timeout_set[PFTM_ADAPTIVE_START] &&
+ !pf->timeout_set[PFTM_ADAPTIVE_END]) {
+ pf->timeout[PFTM_ADAPTIVE_START] =
+ (pf->limit[PF_LIMIT_STATES] / 10) * 6;
+ pf->timeout_set[PFTM_ADAPTIVE_START] = 1;
+ pf->timeout[PFTM_ADAPTIVE_END] =
+ (pf->limit[PF_LIMIT_STATES] / 10) * 12;
+ pf->timeout_set[PFTM_ADAPTIVE_END] = 1;
+ }
+
+ /* load timeouts */
+ for (i = 0; i < PFTM_MAX; i++) {
+ if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i])
+ continue;
+ if (pfctl_load_timeout(pf, i, pf->timeout[i]))
+ error = 1;
+ }
+
+ /* load debug */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set)
+ if (pfctl_load_debug(pf, pf->debug))
+ error = 1;
+
+ /* load logif */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set)
+ if (pfctl_load_logif(pf, pf->ifname))
+ error = 1;
+
+ /* load hostid */
+ if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set)
+ if (pfctl_load_hostid(pf, pf->hostid))
+ error = 1;
+
+ return (error);
+}
+
+int
+pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit)
+{
+ int i;
+
+
+ for (i = 0; pf_limits[i].name; i++) {
+ if (strcasecmp(opt, pf_limits[i].name) == 0) {
+ pf->limit[pf_limits[i].index] = limit;
+ pf->limit_set[pf_limits[i].index] = 1;
+ break;
+ }
+ }
+ if (pf_limits[i].name == NULL) {
+ warnx("Bad pool name.");
+ return (1);
+ }
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set limit %s %d\n", opt, limit);
+
+ return (0);
+}
+
+int
+pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit)
+{
+ struct pfioc_limit pl;
+
+ memset(&pl, 0, sizeof(pl));
+ pl.index = index;
+ pl.limit = limit;
+ if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) {
+ if (errno == EBUSY)
+ warnx("Current pool size exceeds requested hard limit");
+ else
+ warnx("DIOCSETLIMIT");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet)
+{
+ int i;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ for (i = 0; pf_timeouts[i].name; i++) {
+ if (strcasecmp(opt, pf_timeouts[i].name) == 0) {
+ pf->timeout[pf_timeouts[i].timeout] = seconds;
+ pf->timeout_set[pf_timeouts[i].timeout] = 1;
+ break;
+ }
+ }
+
+ if (pf_timeouts[i].name == NULL) {
+ warnx("Bad timeout name.");
+ return (1);
+ }
+
+
+ if (pf->opts & PF_OPT_VERBOSE && ! quiet)
+ printf("set timeout %s %d\n", opt, seconds);
+
+ return (0);
+}
+
+int
+pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds)
+{
+ struct pfioc_tm pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.timeout = timeout;
+ pt.seconds = seconds;
+ if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) {
+ warnx("DIOCSETTIMEOUT");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_optimization(struct pfctl *pf, const char *opt)
+{
+ const struct pf_hint *hint;
+ int i, r;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ for (i = 0; pf_hints[i].name; i++)
+ if (strcasecmp(opt, pf_hints[i].name) == 0)
+ break;
+
+ hint = pf_hints[i].hint;
+ if (hint == NULL) {
+ warnx("invalid state timeouts optimization");
+ return (1);
+ }
+
+ for (i = 0; hint[i].name; i++)
+ if ((r = pfctl_set_timeout(pf, hint[i].name,
+ hint[i].timeout, 1)))
+ return (r);
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set optimization %s\n", opt);
+
+ return (0);
+}
+
+int
+pfctl_set_logif(struct pfctl *pf, char *ifname)
+{
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ if (!strcmp(ifname, "none")) {
+ free(pf->ifname);
+ pf->ifname = NULL;
+ } else {
+ pf->ifname = strdup(ifname);
+ if (!pf->ifname)
+ errx(1, "pfctl_set_logif: strdup");
+ }
+ pf->ifname_set = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set loginterface %s\n", ifname);
+
+ return (0);
+}
+
+int
+pfctl_load_logif(struct pfctl *pf, char *ifname)
+{
+ struct pfioc_if pi;
+
+ memset(&pi, 0, sizeof(pi));
+ if (ifname && strlcpy(pi.ifname, ifname,
+ sizeof(pi.ifname)) >= sizeof(pi.ifname)) {
+ warnx("pfctl_load_logif: strlcpy");
+ return (1);
+ }
+ if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) {
+ warnx("DIOCSETSTATUSIF");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ HTONL(hostid);
+
+ pf->hostid = hostid;
+ pf->hostid_set = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set hostid 0x%08x\n", ntohl(hostid));
+
+ return (0);
+}
+
+int
+pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid)
+{
+ if (ioctl(dev, DIOCSETHOSTID, &hostid)) {
+ warnx("DIOCSETHOSTID");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_debug(struct pfctl *pf, char *d)
+{
+ u_int32_t level;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ if (!strcmp(d, "none"))
+ pf->debug = PF_DEBUG_NONE;
+ else if (!strcmp(d, "urgent"))
+ pf->debug = PF_DEBUG_URGENT;
+ else if (!strcmp(d, "misc"))
+ pf->debug = PF_DEBUG_MISC;
+ else if (!strcmp(d, "loud"))
+ pf->debug = PF_DEBUG_NOISY;
+ else {
+ warnx("unknown debug level \"%s\"", d);
+ return (-1);
+ }
+
+ pf->debug_set = 1;
+ level = pf->debug;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0)
+ if (ioctl(dev, DIOCSETDEBUG, &level))
+ err(1, "DIOCSETDEBUG");
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ printf("set debug %s\n", d);
+
+ return (0);
+}
+
+int
+pfctl_load_debug(struct pfctl *pf, unsigned int level)
+{
+ if (ioctl(pf->dev, DIOCSETDEBUG, &level)) {
+ warnx("DIOCSETDEBUG");
+ return (1);
+ }
+ return (0);
+}
+
+int
+pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how)
+{
+ struct pfioc_iface pi;
+
+ if ((loadopt & PFCTL_FLAG_OPTION) == 0)
+ return (0);
+
+ bzero(&pi, sizeof(pi));
+
+ pi.pfiio_flags = flags;
+
+ if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >=
+ sizeof(pi.pfiio_name))
+ errx(1, "pfctl_set_interface_flags: strlcpy");
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ if (how == 0) {
+ if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi))
+ err(1, "DIOCCLRIFFLAG");
+ } else {
+ if (ioctl(pf->dev, DIOCSETIFFLAG, &pi))
+ err(1, "DIOCSETIFFLAG");
+ }
+ }
+ return (0);
+}
+
+void
+pfctl_debug(int dev, u_int32_t level, int opts)
+{
+ if (ioctl(dev, DIOCSETDEBUG, &level))
+ err(1, "DIOCSETDEBUG");
+ if ((opts & PF_OPT_QUIET) == 0) {
+ fprintf(stderr, "debug level set to '");
+ switch (level) {
+ case PF_DEBUG_NONE:
+ fprintf(stderr, "none");
+ break;
+ case PF_DEBUG_URGENT:
+ fprintf(stderr, "urgent");
+ break;
+ case PF_DEBUG_MISC:
+ fprintf(stderr, "misc");
+ break;
+ case PF_DEBUG_NOISY:
+ fprintf(stderr, "loud");
+ break;
+ default:
+ fprintf(stderr, "<invalid>");
+ break;
+ }
+ fprintf(stderr, "'\n");
+ }
+}
+
+int
+pfctl_test_altqsupport(int dev, int opts)
+{
+ struct pfioc_altq pa;
+
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ if (errno == ENODEV) {
+ if (opts & PF_OPT_VERBOSE)
+ fprintf(stderr, "No ALTQ support in kernel\n"
+ "ALTQ related functions disabled\n");
+ return (0);
+ } else
+ err(1, "DIOCGETALTQS");
+ }
+ return (1);
+}
+
+int
+pfctl_show_anchors(int dev, int opts, char *anchorname)
+{
+ struct pfioc_ruleset pr;
+ u_int32_t mnr, nr;
+
+ memset(&pr, 0, sizeof(pr));
+ memcpy(pr.path, anchorname, sizeof(pr.path));
+ if (ioctl(dev, DIOCGETRULESETS, &pr)) {
+ if (errno == EINVAL)
+ fprintf(stderr, "Anchor '%s' not found.\n",
+ anchorname);
+ else
+ err(1, "DIOCGETRULESETS");
+ return (-1);
+ }
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ char sub[MAXPATHLEN];
+
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULESET, &pr))
+ err(1, "DIOCGETRULESET");
+ if (!strcmp(pr.name, PF_RESERVED_ANCHOR))
+ continue;
+ sub[0] = 0;
+ if (pr.path[0]) {
+ strlcat(sub, pr.path, sizeof(sub));
+ strlcat(sub, "/", sizeof(sub));
+ }
+ strlcat(sub, pr.name, sizeof(sub));
+ if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
+ printf(" %s\n", sub);
+ if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub))
+ return (-1);
+ }
+ return (0);
+}
+
+const char *
+pfctl_lookup_option(char *cmd, const char * const *list)
+{
+ if (cmd != NULL && *cmd)
+ for (; *list; list++)
+ if (!strncmp(cmd, *list, strlen(cmd)))
+ return (*list);
+ return (NULL);
+}
+
+#ifdef __rtems__
+static int main(int argc, char *argv[]);
+
+RTEMS_LINKER_RWSET(bsd_prog_pfctl, char);
+
+int
+rtems_bsd_command_pfctl(int argc, char *argv[])
+{
+ int exit_code;
+ void *data_begin;
+ size_t data_size;
+
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_pfctl);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_pfctl);
+
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("pfctl",
+ main, argc, argv, data_begin, data_size);
+ rtems_bsd_program_unlock();
+
+ return exit_code;
+}
+#endif /* __rtems__ */
+int
+main(int argc, char *argv[])
+{
+ int error = 0;
+ int ch;
+ int mode = O_RDONLY;
+ int opts = 0;
+ int optimize = PF_OPTIMIZE_BASIC;
+ char anchorname[MAXPATHLEN];
+ char *path;
+#ifdef __rtems__
+ struct getopt_data getopt_data;
+ memset(&getopt_data, 0, sizeof(getopt_data));
+#define optind getopt_data.optind
+#define optarg getopt_data.optarg
+#define opterr getopt_data.opterr
+#define optopt getopt_data.optopt
+#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
+#endif /* __rtems__ */
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv,
+ "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) {
+ switch (ch) {
+ case 'a':
+ anchoropt = optarg;
+ break;
+ case 'd':
+ opts |= PF_OPT_DISABLE;
+ mode = O_RDWR;
+ break;
+ case 'D':
+ if (pfctl_cmdline_symset(optarg) < 0)
+ warnx("could not parse macro definition %s",
+ optarg);
+ break;
+ case 'e':
+ opts |= PF_OPT_ENABLE;
+ mode = O_RDWR;
+ break;
+ case 'q':
+ opts |= PF_OPT_QUIET;
+ break;
+ case 'F':
+ clearopt = pfctl_lookup_option(optarg, clearopt_list);
+ if (clearopt == NULL) {
+ warnx("Unknown flush modifier '%s'", optarg);
+ usage();
+ }
+ mode = O_RDWR;
+ break;
+ case 'i':
+ ifaceopt = optarg;
+ break;
+ case 'k':
+ if (state_killers >= 2) {
+ warnx("can only specify -k twice");
+ usage();
+ /* NOTREACHED */
+ }
+ state_kill[state_killers++] = optarg;
+ mode = O_RDWR;
+ break;
+ case 'K':
+ if (src_node_killers >= 2) {
+ warnx("can only specify -K twice");
+ usage();
+ /* NOTREACHED */
+ }
+ src_node_kill[src_node_killers++] = optarg;
+ mode = O_RDWR;
+ break;
+ case 'm':
+ opts |= PF_OPT_MERGE;
+ break;
+ case 'n':
+ opts |= PF_OPT_NOACTION;
+ break;
+ case 'N':
+ loadopt |= PFCTL_FLAG_NAT;
+ break;
+ case 'r':
+ opts |= PF_OPT_USEDNS;
+ break;
+ case 'f':
+ rulesopt = optarg;
+ mode = O_RDWR;
+ break;
+ case 'g':
+ opts |= PF_OPT_DEBUG;
+ break;
+ case 'A':
+ loadopt |= PFCTL_FLAG_ALTQ;
+ break;
+ case 'R':
+ loadopt |= PFCTL_FLAG_FILTER;
+ break;
+ case 'o':
+ optiopt = pfctl_lookup_option(optarg, optiopt_list);
+ if (optiopt == NULL) {
+ warnx("Unknown optimization '%s'", optarg);
+ usage();
+ }
+ opts |= PF_OPT_OPTIMIZE;
+ break;
+ case 'O':
+ loadopt |= PFCTL_FLAG_OPTION;
+ break;
+ case 'p':
+ pf_device = optarg;
+ break;
+ case 'P':
+ opts |= PF_OPT_NUMERIC;
+ break;
+ case 's':
+ showopt = pfctl_lookup_option(optarg, showopt_list);
+ if (showopt == NULL) {
+ warnx("Unknown show modifier '%s'", optarg);
+ usage();
+ }
+ break;
+ case 't':
+ tableopt = optarg;
+ break;
+ case 'T':
+ tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list);
+ if (tblcmdopt == NULL) {
+ warnx("Unknown table command '%s'", optarg);
+ usage();
+ }
+ break;
+ case 'v':
+ if (opts & PF_OPT_VERBOSE)
+ opts |= PF_OPT_VERBOSE2;
+ opts |= PF_OPT_VERBOSE;
+ break;
+ case 'x':
+ debugopt = pfctl_lookup_option(optarg, debugopt_list);
+ if (debugopt == NULL) {
+ warnx("Unknown debug level '%s'", optarg);
+ usage();
+ }
+ mode = O_RDWR;
+ break;
+ case 'z':
+ opts |= PF_OPT_CLRRULECTRS;
+ mode = O_RDWR;
+ break;
+ case 'h':
+ /* FALLTHROUGH */
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (tblcmdopt != NULL) {
+ argc -= optind;
+ argv += optind;
+ ch = *tblcmdopt;
+ if (ch == 'l') {
+ loadopt |= PFCTL_FLAG_TABLE;
+ tblcmdopt = NULL;
+ } else
+ mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY;
+ } else if (argc != optind) {
+ warnx("unknown command line argument: %s ...", argv[optind]);
+ usage();
+ /* NOTREACHED */
+ }
+ if (loadopt == 0)
+ loadopt = ~0;
+
+ if ((path = calloc(1, MAXPATHLEN)) == NULL)
+ errx(1, "pfctl: calloc");
+ memset(anchorname, 0, sizeof(anchorname));
+ if (anchoropt != NULL) {
+ int len = strlen(anchoropt);
+
+ if (anchoropt[len - 1] == '*') {
+ if (len >= 2 && anchoropt[len - 2] == '/')
+ anchoropt[len - 2] = '\0';
+ else
+ anchoropt[len - 1] = '\0';
+ opts |= PF_OPT_RECURSE;
+ }
+ if (strlcpy(anchorname, anchoropt,
+ sizeof(anchorname)) >= sizeof(anchorname))
+ errx(1, "anchor name '%s' too long",
+ anchoropt);
+ loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE;
+ }
+
+ if ((opts & PF_OPT_NOACTION) == 0) {
+ dev = open(pf_device, mode);
+ if (dev == -1)
+ err(1, "%s", pf_device);
+ altqsupport = pfctl_test_altqsupport(dev, opts);
+ } else {
+ dev = open(pf_device, O_RDONLY);
+ if (dev >= 0)
+ opts |= PF_OPT_DUMMYACTION;
+ /* turn off options */
+ opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
+ clearopt = showopt = debugopt = NULL;
+#if !defined(ENABLE_ALTQ)
+ altqsupport = 0;
+#else
+ altqsupport = 1;
+#endif
+ }
+
+ if (opts & PF_OPT_DISABLE)
+ if (pfctl_disable(dev, opts))
+ error = 1;
+
+ if (showopt != NULL) {
+ switch (*showopt) {
+ case 'A':
+ pfctl_show_anchors(dev, opts, anchorname);
+ break;
+ case 'r':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
+ anchorname, 0);
+ break;
+ case 'l':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
+ anchorname, 0);
+ break;
+ case 'n':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_nat(dev, opts, anchorname);
+ break;
+ case 'q':
+ pfctl_show_altq(dev, ifaceopt, opts,
+ opts & PF_OPT_VERBOSE2);
+ break;
+ case 's':
+ pfctl_show_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_show_src_nodes(dev, opts);
+ break;
+ case 'i':
+ pfctl_show_status(dev, opts);
+ break;
+ case 't':
+ pfctl_show_timeouts(dev, opts);
+ break;
+ case 'm':
+ pfctl_show_limits(dev, opts);
+ break;
+ case 'a':
+ opts |= PF_OPT_SHOWALL;
+ pfctl_load_fingerprints(dev, opts);
+
+ pfctl_show_nat(dev, opts, anchorname);
+ pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
+ pfctl_show_altq(dev, ifaceopt, opts, 0);
+ pfctl_show_states(dev, ifaceopt, opts);
+ pfctl_show_src_nodes(dev, opts);
+ pfctl_show_status(dev, opts);
+ pfctl_show_rules(dev, path, opts, 1, anchorname, 0);
+ pfctl_show_timeouts(dev, opts);
+ pfctl_show_limits(dev, opts);
+ pfctl_show_tables(anchorname, opts);
+ pfctl_show_fingerprints(opts);
+ break;
+ case 'T':
+ pfctl_show_tables(anchorname, opts);
+ break;
+ case 'o':
+ pfctl_load_fingerprints(dev, opts);
+ pfctl_show_fingerprints(opts);
+ break;
+ case 'I':
+ pfctl_show_ifaces(ifaceopt, opts);
+ break;
+ }
+ }
+
+ if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL)
+ pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING,
+ anchorname, 0);
+
+ if (clearopt != NULL) {
+ if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
+ errx(1, "anchor names beginning with '_' cannot "
+ "be modified from the command line");
+
+ switch (*clearopt) {
+ case 'r':
+ pfctl_clear_rules(dev, opts, anchorname);
+ break;
+ case 'n':
+ pfctl_clear_nat(dev, opts, anchorname);
+ break;
+ case 'q':
+ pfctl_clear_altq(dev, opts);
+ break;
+ case 's':
+ pfctl_clear_states(dev, ifaceopt, opts);
+ break;
+ case 'S':
+ pfctl_clear_src_nodes(dev, opts);
+ break;
+ case 'i':
+ pfctl_clear_stats(dev, opts);
+ break;
+ case 'a':
+ pfctl_clear_rules(dev, opts, anchorname);
+ pfctl_clear_nat(dev, opts, anchorname);
+ pfctl_clear_tables(anchorname, opts);
+ if (!*anchorname) {
+ pfctl_clear_altq(dev, opts);
+ pfctl_clear_states(dev, ifaceopt, opts);
+ pfctl_clear_src_nodes(dev, opts);
+ pfctl_clear_stats(dev, opts);
+ pfctl_clear_fingerprints(dev, opts);
+ pfctl_clear_interface_flags(dev, opts);
+ }
+ break;
+ case 'o':
+ pfctl_clear_fingerprints(dev, opts);
+ break;
+ case 'T':
+ pfctl_clear_tables(anchorname, opts);
+ break;
+ }
+ }
+ if (state_killers) {
+ if (!strcmp(state_kill[0], "label"))
+ pfctl_label_kill_states(dev, ifaceopt, opts);
+ else if (!strcmp(state_kill[0], "id"))
+ pfctl_id_kill_states(dev, ifaceopt, opts);
+ else
+ pfctl_net_kill_states(dev, ifaceopt, opts);
+ }
+
+ if (src_node_killers)
+ pfctl_kill_src_nodes(dev, ifaceopt, opts);
+
+ if (tblcmdopt != NULL) {
+ error = pfctl_command_tables(argc, argv, tableopt,
+ tblcmdopt, rulesopt, anchorname, opts);
+ rulesopt = NULL;
+ }
+ if (optiopt != NULL) {
+ switch (*optiopt) {
+ case 'n':
+ optimize = 0;
+ break;
+ case 'b':
+ optimize |= PF_OPTIMIZE_BASIC;
+ break;
+ case 'o':
+ case 'p':
+ optimize |= PF_OPTIMIZE_PROFILE;
+ break;
+ }
+ }
+
+ if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) &&
+ !anchorname[0])
+ if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET))
+ error = 1;
+
+ if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) &&
+ !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION))
+ if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE))
+ error = 1;
+
+ if (rulesopt != NULL) {
+ if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL)
+ errx(1, "anchor names beginning with '_' cannot "
+ "be modified from the command line");
+ if (pfctl_rules(dev, rulesopt, opts, optimize,
+ anchorname, NULL))
+ error = 1;
+ else if (!(opts & PF_OPT_NOACTION) &&
+ (loadopt & PFCTL_FLAG_TABLE))
+ warn_namespace_collision(NULL);
+ }
+
+ if (opts & PF_OPT_ENABLE)
+ if (pfctl_enable(dev, opts))
+ error = 1;
+
+ if (debugopt != NULL) {
+ switch (*debugopt) {
+ case 'n':
+ pfctl_debug(dev, PF_DEBUG_NONE, opts);
+ break;
+ case 'u':
+ pfctl_debug(dev, PF_DEBUG_URGENT, opts);
+ break;
+ case 'm':
+ pfctl_debug(dev, PF_DEBUG_MISC, opts);
+ break;
+ case 'l':
+ pfctl_debug(dev, PF_DEBUG_NOISY, opts);
+ break;
+ }
+ }
+
+ exit(error);
+}
diff --git a/freebsd/sbin/pfctl/pfctl.h b/freebsd/sbin/pfctl/pfctl.h
new file mode 100644
index 00000000..2c69bc20
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PFCTL_H_
+#define _PFCTL_H_
+
+enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING };
+
+enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS,
+ PFRB_IFACES, PFRB_TRANS, PFRB_MAX };
+struct pfr_buffer {
+ int pfrb_type; /* type of content, see enum above */
+ int pfrb_size; /* number of objects in buffer */
+ int pfrb_msize; /* maximum number of objects in buffer */
+ void *pfrb_caddr; /* malloc'ated memory area */
+};
+#define PFRB_FOREACH(var, buf) \
+ for ((var) = pfr_buf_next((buf), NULL); \
+ (var) != NULL; \
+ (var) = pfr_buf_next((buf), (var)))
+
+int pfr_get_fd(void);
+int pfr_clr_tables(struct pfr_table *, int *, int);
+int pfr_add_tables(struct pfr_table *, int, int *, int);
+int pfr_del_tables(struct pfr_table *, int, int *, int);
+int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int);
+int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int);
+int pfr_clr_tstats(struct pfr_table *, int, int *, int);
+int pfr_clr_addrs(struct pfr_table *, int *, int);
+int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int *, int *, int);
+int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int);
+int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int);
+int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int);
+int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *,
+ int *, int, int);
+void pfr_buf_clear(struct pfr_buffer *);
+int pfr_buf_add(struct pfr_buffer *, const void *);
+void *pfr_buf_next(struct pfr_buffer *, const void *);
+int pfr_buf_grow(struct pfr_buffer *, int);
+int pfr_buf_load(struct pfr_buffer *, char *, int,
+ int (*)(struct pfr_buffer *, char *, int));
+char *pfr_strerror(int);
+int pfi_get_ifaces(const char *, struct pfi_kif *, int *);
+int pfi_clr_istats(const char *, int *, int);
+
+void pfctl_print_title(char *);
+int pfctl_clear_tables(const char *, int);
+int pfctl_show_tables(const char *, int);
+int pfctl_command_tables(int, char *[], char *, const char *, char *,
+ const char *, int);
+int pfctl_show_altq(int, const char *, int, int);
+void warn_namespace_collision(const char *);
+int pfctl_show_ifaces(const char *, int);
+FILE *pfctl_fopen(const char *, const char *);
+
+#ifdef __FreeBSD__
+extern int altqsupport;
+extern int dummynetsupport;
+#define HTONL(x) (x) = htonl((__uint32_t)(x))
+#endif
+
+#ifndef DEFAULT_PRIORITY
+#define DEFAULT_PRIORITY 1
+#endif
+
+#ifndef DEFAULT_QLIMIT
+#define DEFAULT_QLIMIT 50
+#endif
+
+/*
+ * generalized service curve used for admission control
+ */
+struct segment {
+ LIST_ENTRY(segment) _next;
+ double x, y, d, m;
+};
+
+extern int loadopt;
+
+int check_commit_altq(int, int);
+void pfaltq_store(struct pf_altq *);
+struct pf_altq *pfaltq_lookup(const char *);
+char *rate2str(double);
+
+void print_addr(struct pf_addr_wrap *, sa_family_t, int);
+void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int);
+void print_seq(struct pfsync_state_peer *);
+void print_state(struct pfsync_state *, int);
+int unmask(struct pf_addr *, sa_family_t);
+
+int pfctl_cmdline_symset(char *);
+int pfctl_add_trans(struct pfr_buffer *, int, const char *);
+u_int32_t
+ pfctl_get_ticket(struct pfr_buffer *, int, const char *);
+int pfctl_trans(int, struct pfr_buffer *, u_long, int);
+
+#endif /* _PFCTL_H_ */
diff --git a/freebsd/sbin/pfctl/pfctl_altq.c b/freebsd/sbin/pfctl/pfctl_altq.c
new file mode 100644
index 00000000..145d60ae
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_altq.c
@@ -0,0 +1,1536 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */
+
+/*
+ * Copyright (c) 2002
+ * Sony Computer Science Laboratories Inc.
+ * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_altq-data.h"
+#endif /* __rtems__ */
+
+#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0))
+
+static TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs);
+static LIST_HEAD(gen_sc, segment) rtsc, lssc;
+
+struct pf_altq *qname_to_pfaltq(const char *, const char *);
+u_int32_t qname_to_qid(const char *);
+
+static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *);
+static int cbq_compute_idletime(struct pfctl *, struct pf_altq *);
+static int check_commit_cbq(int, int, struct pf_altq *);
+static int print_cbq_opts(const struct pf_altq *);
+
+static int print_codel_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+
+static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *);
+static int check_commit_priq(int, int, struct pf_altq *);
+static int print_priq_opts(const struct pf_altq *);
+
+static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *);
+static int check_commit_hfsc(int, int, struct pf_altq *);
+static int print_hfsc_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+
+static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *);
+static int print_fairq_opts(const struct pf_altq *,
+ const struct node_queue_opt *);
+static int check_commit_fairq(int, int, struct pf_altq *);
+
+static void gsc_add_sc(struct gen_sc *, struct service_curve *);
+static int is_gsc_under_sc(struct gen_sc *,
+ struct service_curve *);
+static void gsc_destroy(struct gen_sc *);
+static struct segment *gsc_getentry(struct gen_sc *, double);
+static int gsc_add_seg(struct gen_sc *, double, double, double,
+ double);
+static double sc_x2y(struct service_curve *, double);
+
+#ifdef __FreeBSD__
+u_int32_t getifspeed(int, char *);
+#else
+u_int32_t getifspeed(char *);
+#endif
+u_long getifmtu(char *);
+int eval_queue_opts(struct pf_altq *, struct node_queue_opt *,
+ u_int32_t);
+u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t);
+void print_hfsc_sc(const char *, u_int, u_int, u_int,
+ const struct node_hfsc_sc *);
+void print_fairq_sc(const char *, u_int, u_int, u_int,
+ const struct node_fairq_sc *);
+
+void
+pfaltq_store(struct pf_altq *a)
+{
+ struct pf_altq *altq;
+
+ if ((altq = malloc(sizeof(*altq))) == NULL)
+ err(1, "malloc");
+ memcpy(altq, a, sizeof(struct pf_altq));
+ TAILQ_INSERT_TAIL(&altqs, altq, entries);
+}
+
+struct pf_altq *
+pfaltq_lookup(const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ altq->qname[0] == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+struct pf_altq *
+qname_to_pfaltq(const char *qname, const char *ifname)
+{
+ struct pf_altq *altq;
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 &&
+ strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq);
+ }
+ return (NULL);
+}
+
+u_int32_t
+qname_to_qid(const char *qname)
+{
+ struct pf_altq *altq;
+
+ /*
+ * We guarantee that same named queues on different interfaces
+ * have the same qid, so we do NOT need to limit matching on
+ * one interface!
+ */
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0)
+ return (altq->qid);
+ }
+ return (0);
+}
+
+void
+print_altq(const struct pf_altq *a, unsigned int level,
+ struct node_queue_bw *bw, struct node_queue_opt *qopts)
+{
+ if (a->qname[0] != 0) {
+ print_queue(a, level, bw, 1, qopts);
+ return;
+ }
+
+#ifdef __FreeBSD__
+ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
+ printf("INACTIVE ");
+#endif
+
+ printf("altq on %s ", a->ifname);
+
+ switch (a->scheduler) {
+ case ALTQT_CBQ:
+ if (!print_cbq_opts(a))
+ printf("cbq ");
+ break;
+ case ALTQT_PRIQ:
+ if (!print_priq_opts(a))
+ printf("priq ");
+ break;
+ case ALTQT_HFSC:
+ if (!print_hfsc_opts(a, qopts))
+ printf("hfsc ");
+ break;
+ case ALTQT_FAIRQ:
+ if (!print_fairq_opts(a, qopts))
+ printf("fairq ");
+ break;
+ case ALTQT_CODEL:
+ if (!print_codel_opts(a, qopts))
+ printf("codel ");
+ break;
+ }
+
+ if (bw != NULL && bw->bw_percent > 0) {
+ if (bw->bw_percent < 100)
+ printf("bandwidth %u%% ", bw->bw_percent);
+ } else
+ printf("bandwidth %s ", rate2str((double)a->ifbandwidth));
+
+ if (a->qlimit != DEFAULT_QLIMIT)
+ printf("qlimit %u ", a->qlimit);
+ printf("tbrsize %u ", a->tbrsize);
+}
+
+void
+print_queue(const struct pf_altq *a, unsigned int level,
+ struct node_queue_bw *bw, int print_interface,
+ struct node_queue_opt *qopts)
+{
+ unsigned int i;
+
+#ifdef __FreeBSD__
+ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED)
+ printf("INACTIVE ");
+#endif
+ printf("queue ");
+ for (i = 0; i < level; ++i)
+ printf(" ");
+ printf("%s ", a->qname);
+ if (print_interface)
+ printf("on %s ", a->ifname);
+ if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC ||
+ a->scheduler == ALTQT_FAIRQ) {
+ if (bw != NULL && bw->bw_percent > 0) {
+ if (bw->bw_percent < 100)
+ printf("bandwidth %u%% ", bw->bw_percent);
+ } else
+ printf("bandwidth %s ", rate2str((double)a->bandwidth));
+ }
+ if (a->priority != DEFAULT_PRIORITY)
+ printf("priority %u ", a->priority);
+ if (a->qlimit != DEFAULT_QLIMIT)
+ printf("qlimit %u ", a->qlimit);
+ switch (a->scheduler) {
+ case ALTQT_CBQ:
+ print_cbq_opts(a);
+ break;
+ case ALTQT_PRIQ:
+ print_priq_opts(a);
+ break;
+ case ALTQT_HFSC:
+ print_hfsc_opts(a, qopts);
+ break;
+ case ALTQT_FAIRQ:
+ print_fairq_opts(a, qopts);
+ break;
+ }
+}
+
+/*
+ * eval_pfaltq computes the discipline parameters.
+ */
+int
+eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
+ struct node_queue_opt *opts)
+{
+ u_int rate, size, errors = 0;
+
+ if (bw->bw_absolute > 0)
+ pa->ifbandwidth = bw->bw_absolute;
+ else
+#ifdef __FreeBSD__
+ if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) {
+#else
+ if ((rate = getifspeed(pa->ifname)) == 0) {
+#endif
+ fprintf(stderr, "interface %s does not know its bandwidth, "
+ "please specify an absolute bandwidth\n",
+ pa->ifname);
+ errors++;
+ } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0)
+ pa->ifbandwidth = rate;
+
+ errors += eval_queue_opts(pa, opts, pa->ifbandwidth);
+
+ /* if tbrsize is not specified, use heuristics */
+ if (pa->tbrsize == 0) {
+ rate = pa->ifbandwidth;
+ if (rate <= 1 * 1000 * 1000)
+ size = 1;
+ else if (rate <= 10 * 1000 * 1000)
+ size = 4;
+ else if (rate <= 200 * 1000 * 1000)
+ size = 8;
+ else
+ size = 24;
+ size = size * getifmtu(pa->ifname);
+ if (size > 0xffff)
+ size = 0xffff;
+ pa->tbrsize = size;
+ }
+ return (errors);
+}
+
+/*
+ * check_commit_altq does consistency check for each interface
+ */
+int
+check_commit_altq(int dev, int opts)
+{
+ struct pf_altq *altq;
+ int error = 0;
+
+ /* call the discipline check for each interface. */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (altq->qname[0] == 0) {
+ switch (altq->scheduler) {
+ case ALTQT_CBQ:
+ error = check_commit_cbq(dev, opts, altq);
+ break;
+ case ALTQT_PRIQ:
+ error = check_commit_priq(dev, opts, altq);
+ break;
+ case ALTQT_HFSC:
+ error = check_commit_hfsc(dev, opts, altq);
+ break;
+ case ALTQT_FAIRQ:
+ error = check_commit_fairq(dev, opts, altq);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return (error);
+}
+
+/*
+ * eval_pfqueue computes the queue parameters.
+ */
+int
+eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw,
+ struct node_queue_opt *opts)
+{
+ /* should be merged with expand_queue */
+ struct pf_altq *if_pa, *parent, *altq;
+ u_int32_t bwsum;
+ int error = 0;
+
+ /* find the corresponding interface and copy fields used by queues */
+ if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) {
+ fprintf(stderr, "altq not defined on %s\n", pa->ifname);
+ return (1);
+ }
+ pa->scheduler = if_pa->scheduler;
+ pa->ifbandwidth = if_pa->ifbandwidth;
+
+ if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) {
+ fprintf(stderr, "queue %s already exists on interface %s\n",
+ pa->qname, pa->ifname);
+ return (1);
+ }
+ pa->qid = qname_to_qid(pa->qname);
+
+ parent = NULL;
+ if (pa->parent[0] != 0) {
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL) {
+ fprintf(stderr, "parent %s not found for %s\n",
+ pa->parent, pa->qname);
+ return (1);
+ }
+ pa->parent_qid = parent->qid;
+ }
+ if (pa->qlimit == 0)
+ pa->qlimit = DEFAULT_QLIMIT;
+
+ if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC ||
+ pa->scheduler == ALTQT_FAIRQ) {
+ pa->bandwidth = eval_bwspec(bw,
+ parent == NULL ? 0 : parent->bandwidth);
+
+ if (pa->bandwidth > pa->ifbandwidth) {
+ fprintf(stderr, "bandwidth for %s higher than "
+ "interface\n", pa->qname);
+ return (1);
+ }
+ /* check the sum of the child bandwidth is under parent's */
+ if (parent != NULL) {
+ if (pa->bandwidth > parent->bandwidth) {
+ warnx("bandwidth for %s higher than parent",
+ pa->qname);
+ return (1);
+ }
+ bwsum = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname,
+ IFNAMSIZ) == 0 &&
+ altq->qname[0] != 0 &&
+ strncmp(altq->parent, pa->parent,
+ PF_QNAME_SIZE) == 0)
+ bwsum += altq->bandwidth;
+ }
+ bwsum += pa->bandwidth;
+ if (bwsum > parent->bandwidth) {
+ warnx("the sum of the child bandwidth higher"
+ " than parent \"%s\"", parent->qname);
+ }
+ }
+ }
+
+ if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth))
+ return (1);
+
+ switch (pa->scheduler) {
+ case ALTQT_CBQ:
+ error = eval_pfqueue_cbq(pf, pa);
+ break;
+ case ALTQT_PRIQ:
+ error = eval_pfqueue_priq(pf, pa);
+ break;
+ case ALTQT_HFSC:
+ error = eval_pfqueue_hfsc(pf, pa);
+ break;
+ case ALTQT_FAIRQ:
+ error = eval_pfqueue_fairq(pf, pa);
+ break;
+ default:
+ break;
+ }
+ return (error);
+}
+
+/*
+ * CBQ support functions
+ */
+#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */
+#define RM_NS_PER_SEC (1000000000)
+
+static int
+eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ u_int ifmtu;
+
+ if (pa->priority >= CBQ_MAXPRI) {
+ warnx("priority out of range: max %d", CBQ_MAXPRI - 1);
+ return (-1);
+ }
+
+ ifmtu = getifmtu(pa->ifname);
+ opts = &pa->pq_u.cbq_opts;
+
+ if (opts->pktsize == 0) { /* use default */
+ opts->pktsize = ifmtu;
+ if (opts->pktsize > MCLBYTES) /* do what TCP does */
+ opts->pktsize &= ~MCLBYTES;
+ } else if (opts->pktsize > ifmtu)
+ opts->pktsize = ifmtu;
+ if (opts->maxpktsize == 0) /* use default */
+ opts->maxpktsize = ifmtu;
+ else if (opts->maxpktsize > ifmtu)
+ opts->pktsize = ifmtu;
+
+ if (opts->pktsize > opts->maxpktsize)
+ opts->pktsize = opts->maxpktsize;
+
+ if (pa->parent[0] == 0)
+ opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR);
+
+ cbq_compute_idletime(pf, pa);
+ return (0);
+}
+
+/*
+ * compute ns_per_byte, maxidle, minidle, and offtime
+ */
+static int
+cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct cbq_opts *opts;
+ double maxidle_s, maxidle, minidle;
+ double offtime, nsPerByte, ifnsPerByte, ptime, cptime;
+ double z, g, f, gton, gtom;
+ u_int minburst, maxburst;
+
+ opts = &pa->pq_u.cbq_opts;
+ ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8;
+ minburst = opts->minburst;
+ maxburst = opts->maxburst;
+
+ if (pa->bandwidth == 0)
+ f = 0.0001; /* small enough? */
+ else
+ f = ((double) pa->bandwidth / (double) pa->ifbandwidth);
+
+ nsPerByte = ifnsPerByte / f;
+ ptime = (double)opts->pktsize * ifnsPerByte;
+ cptime = ptime * (1.0 - f) / f;
+
+ if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) {
+ /*
+ * this causes integer overflow in kernel!
+ * (bandwidth < 6Kbps when max_pkt_size=1500)
+ */
+ if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0)
+ warnx("queue bandwidth must be larger than %s",
+ rate2str(ifnsPerByte * (double)opts->maxpktsize /
+ (double)INT_MAX * (double)pa->ifbandwidth));
+ fprintf(stderr, "cbq: queue %s is too slow!\n",
+ pa->qname);
+ nsPerByte = (double)(INT_MAX / opts->maxpktsize);
+ }
+
+ if (maxburst == 0) { /* use default */
+ if (cptime > 10.0 * 1000000)
+ maxburst = 4;
+ else
+ maxburst = 16;
+ }
+ if (minburst == 0) /* use default */
+ minburst = 2;
+ if (minburst > maxburst)
+ minburst = maxburst;
+
+ z = (double)(1 << RM_FILTER_GAIN);
+ g = (1.0 - 1.0 / z);
+ gton = pow(g, (double)maxburst);
+ gtom = pow(g, (double)(minburst-1));
+ maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton));
+ maxidle_s = (1.0 - g);
+ if (maxidle > maxidle_s)
+ maxidle = ptime * maxidle;
+ else
+ maxidle = ptime * maxidle_s;
+ offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom);
+ minidle = -((double)opts->maxpktsize * (double)nsPerByte);
+
+ /* scale parameters */
+ maxidle = ((maxidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ offtime = (offtime * 8.0) / nsPerByte *
+ pow(2.0, (double)RM_FILTER_GAIN);
+ minidle = ((minidle * 8.0) / nsPerByte) *
+ pow(2.0, (double)RM_FILTER_GAIN);
+
+ maxidle = maxidle / 1000.0;
+ offtime = offtime / 1000.0;
+ minidle = minidle / 1000.0;
+
+ opts->minburst = minburst;
+ opts->maxburst = maxburst;
+ opts->ns_per_byte = (u_int)nsPerByte;
+ opts->maxidle = (u_int)fabs(maxidle);
+ opts->minidle = (int)minidle;
+ opts->offtime = (u_int)fabs(offtime);
+
+ return (0);
+}
+
+static int
+check_commit_cbq(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+ int root_class, default_class;
+ int error = 0;
+
+ /*
+ * check if cbq has one root queue and one default queue
+ * for this interface
+ */
+ root_class = default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS)
+ root_class++;
+ if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS)
+ default_class++;
+ }
+ if (root_class != 1) {
+ warnx("should have one root queue on %s", pa->ifname);
+ error++;
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ error++;
+ }
+ return (error);
+}
+
+static int
+print_cbq_opts(const struct pf_altq *a)
+{
+ const struct cbq_opts *opts;
+
+ opts = &a->pq_u.cbq_opts;
+ if (opts->flags) {
+ printf("cbq(");
+ if (opts->flags & CBQCLF_RED)
+ printf(" red");
+ if (opts->flags & CBQCLF_ECN)
+ printf(" ecn");
+ if (opts->flags & CBQCLF_RIO)
+ printf(" rio");
+ if (opts->flags & CBQCLF_CODEL)
+ printf(" codel");
+ if (opts->flags & CBQCLF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & CBQCLF_FLOWVALVE)
+ printf(" flowvalve");
+ if (opts->flags & CBQCLF_BORROW)
+ printf(" borrow");
+ if (opts->flags & CBQCLF_WRR)
+ printf(" wrr");
+ if (opts->flags & CBQCLF_EFFICIENT)
+ printf(" efficient");
+ if (opts->flags & CBQCLF_ROOTCLASS)
+ printf(" root");
+ if (opts->flags & CBQCLF_DEFCLASS)
+ printf(" default");
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * PRIQ support functions
+ */
+static int
+eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+
+ if (pa->priority >= PRIQ_MAXPRI) {
+ warnx("priority out of range: max %d", PRIQ_MAXPRI - 1);
+ return (-1);
+ }
+ /* the priority should be unique for the interface */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 &&
+ altq->qname[0] != 0 && altq->priority == pa->priority) {
+ warnx("%s and %s have the same priority",
+ altq->qname, pa->qname);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+check_commit_priq(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq;
+ int default_class;
+ int error = 0;
+
+ /*
+ * check if priq has one default class for this interface
+ */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS)
+ default_class++;
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ error++;
+ }
+ return (error);
+}
+
+static int
+print_priq_opts(const struct pf_altq *a)
+{
+ const struct priq_opts *opts;
+
+ opts = &a->pq_u.priq_opts;
+
+ if (opts->flags) {
+ printf("priq(");
+ if (opts->flags & PRCF_RED)
+ printf(" red");
+ if (opts->flags & PRCF_ECN)
+ printf(" ecn");
+ if (opts->flags & PRCF_RIO)
+ printf(" rio");
+ if (opts->flags & PRCF_CODEL)
+ printf(" codel");
+ if (opts->flags & PRCF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & PRCF_DEFAULTCLASS)
+ printf(" default");
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * HFSC support functions
+ */
+static int
+eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *parent;
+ struct hfsc_opts *opts;
+ struct service_curve sc;
+
+ opts = &pa->pq_u.hfsc_opts;
+
+ if (pa->parent[0] == 0) {
+ /* root queue */
+ opts->lssc_m1 = pa->ifbandwidth;
+ opts->lssc_m2 = pa->ifbandwidth;
+ opts->lssc_d = 0;
+ return (0);
+ }
+
+ LIST_INIT(&rtsc);
+ LIST_INIT(&lssc);
+
+ /* if link_share is not specified, use bandwidth */
+ if (opts->lssc_m2 == 0)
+ opts->lssc_m2 = pa->bandwidth;
+
+ if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) ||
+ (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) ||
+ (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) {
+ warnx("m2 is zero for %s", pa->qname);
+ return (-1);
+ }
+
+ if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) ||
+ (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) ||
+ (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) {
+ warnx("m1 must be zero for convex curve: %s", pa->qname);
+ return (-1);
+ }
+
+ /*
+ * admission control:
+ * for the real-time service curve, the sum of the service curves
+ * should not exceed 80% of the interface bandwidth. 20% is reserved
+ * not to over-commit the actual interface bandwidth.
+ * for the linkshare service curve, the sum of the child service
+ * curve should not exceed the parent service curve.
+ * for the upper-limit service curve, the assigned bandwidth should
+ * be smaller than the interface bandwidth, and the upper-limit should
+ * be larger than the real-time service curve when both are defined.
+ */
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s", pa->parent, pa->qname);
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+
+ /* if the class has a real-time service curve, add it. */
+ if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) {
+ sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1;
+ sc.d = altq->pq_u.hfsc_opts.rtsc_d;
+ sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2;
+ gsc_add_sc(&rtsc, &sc);
+ }
+
+ if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
+ continue;
+
+ /* if the class has a linkshare service curve, add it. */
+ if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) {
+ sc.m1 = altq->pq_u.hfsc_opts.lssc_m1;
+ sc.d = altq->pq_u.hfsc_opts.lssc_d;
+ sc.m2 = altq->pq_u.hfsc_opts.lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ }
+ }
+
+ /* check the real-time service curve. reserve 20% of interface bw */
+ if (opts->rtsc_m2 != 0) {
+ /* add this queue to the sum */
+ sc.m1 = opts->rtsc_m1;
+ sc.d = opts->rtsc_d;
+ sc.m2 = opts->rtsc_m2;
+ gsc_add_sc(&rtsc, &sc);
+ /* compare the sum with 80% of the interface */
+ sc.m1 = 0;
+ sc.d = 0;
+ sc.m2 = pa->ifbandwidth / 100 * 80;
+ if (!is_gsc_under_sc(&rtsc, &sc)) {
+ warnx("real-time sc exceeds 80%% of the interface "
+ "bandwidth (%s)", rate2str((double)sc.m2));
+ goto err_ret;
+ }
+ }
+
+ /* check the linkshare service curve. */
+ if (opts->lssc_m2 != 0) {
+ /* add this queue to the child sum */
+ sc.m1 = opts->lssc_m1;
+ sc.d = opts->lssc_d;
+ sc.m2 = opts->lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ /* compare the sum of the children with parent's sc */
+ sc.m1 = parent->pq_u.hfsc_opts.lssc_m1;
+ sc.d = parent->pq_u.hfsc_opts.lssc_d;
+ sc.m2 = parent->pq_u.hfsc_opts.lssc_m2;
+ if (!is_gsc_under_sc(&lssc, &sc)) {
+ warnx("linkshare sc exceeds parent's sc");
+ goto err_ret;
+ }
+ }
+
+ /* check the upper-limit service curve. */
+ if (opts->ulsc_m2 != 0) {
+ if (opts->ulsc_m1 > pa->ifbandwidth ||
+ opts->ulsc_m2 > pa->ifbandwidth) {
+ warnx("upper-limit larger than interface bandwidth");
+ goto err_ret;
+ }
+ if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) {
+ warnx("upper-limit sc smaller than real-time sc");
+ goto err_ret;
+ }
+ }
+
+ gsc_destroy(&rtsc);
+ gsc_destroy(&lssc);
+
+ return (0);
+
+err_ret:
+ gsc_destroy(&rtsc);
+ gsc_destroy(&lssc);
+ return (-1);
+}
+
+/*
+ * FAIRQ support functions
+ */
+static int
+eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *parent;
+ struct fairq_opts *opts;
+ struct service_curve sc;
+
+ opts = &pa->pq_u.fairq_opts;
+
+ if (pa->parent[0] == 0) {
+ /* root queue */
+ opts->lssc_m1 = pa->ifbandwidth;
+ opts->lssc_m2 = pa->ifbandwidth;
+ opts->lssc_d = 0;
+ return (0);
+ }
+
+ LIST_INIT(&lssc);
+
+ /* if link_share is not specified, use bandwidth */
+ if (opts->lssc_m2 == 0)
+ opts->lssc_m2 = pa->bandwidth;
+
+ /*
+ * admission control:
+ * for the real-time service curve, the sum of the service curves
+ * should not exceed 80% of the interface bandwidth. 20% is reserved
+ * not to over-commit the actual interface bandwidth.
+ * for the link-sharing service curve, the sum of the child service
+ * curve should not exceed the parent service curve.
+ * for the upper-limit service curve, the assigned bandwidth should
+ * be smaller than the interface bandwidth, and the upper-limit should
+ * be larger than the real-time service curve when both are defined.
+ */
+ parent = qname_to_pfaltq(pa->parent, pa->ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found for %s", pa->parent, pa->qname);
+
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+
+ if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0)
+ continue;
+
+ /* if the class has a link-sharing service curve, add it. */
+ if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) {
+ sc.m1 = altq->pq_u.fairq_opts.lssc_m1;
+ sc.d = altq->pq_u.fairq_opts.lssc_d;
+ sc.m2 = altq->pq_u.fairq_opts.lssc_m2;
+ gsc_add_sc(&lssc, &sc);
+ }
+ }
+
+ /* check the link-sharing service curve. */
+ if (opts->lssc_m2 != 0) {
+ sc.m1 = parent->pq_u.fairq_opts.lssc_m1;
+ sc.d = parent->pq_u.fairq_opts.lssc_d;
+ sc.m2 = parent->pq_u.fairq_opts.lssc_m2;
+ if (!is_gsc_under_sc(&lssc, &sc)) {
+ warnx("link-sharing sc exceeds parent's sc");
+ goto err_ret;
+ }
+ }
+
+ gsc_destroy(&lssc);
+
+ return (0);
+
+err_ret:
+ gsc_destroy(&lssc);
+ return (-1);
+}
+
+static int
+check_commit_hfsc(int dev, int opts, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *def = NULL;
+ int default_class;
+ int error = 0;
+
+ /* check if hfsc has one default queue for this interface */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->parent[0] == 0) /* dummy root */
+ continue;
+ if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) {
+ default_class++;
+ def = altq;
+ }
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ return (1);
+ }
+ /* make sure the default queue is a leaf */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
+ warnx("default queue is not a leaf");
+ error++;
+ }
+ }
+ return (error);
+}
+
+static int
+check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa)
+{
+ struct pf_altq *altq, *def = NULL;
+ int default_class;
+ int error = 0;
+
+ /* check if fairq has one default queue for this interface */
+ default_class = 0;
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) {
+ default_class++;
+ def = altq;
+ }
+ }
+ if (default_class != 1) {
+ warnx("should have one default queue on %s", pa->ifname);
+ return (1);
+ }
+ /* make sure the default queue is a leaf */
+ TAILQ_FOREACH(altq, &altqs, entries) {
+ if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0)
+ continue;
+ if (altq->qname[0] == 0) /* this is for interface */
+ continue;
+ if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) {
+ warnx("default queue is not a leaf");
+ error++;
+ }
+ }
+ return (error);
+}
+
+static int
+print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct hfsc_opts *opts;
+ const struct node_hfsc_sc *rtsc, *lssc, *ulsc;
+
+ opts = &a->pq_u.hfsc_opts;
+ if (qopts == NULL)
+ rtsc = lssc = ulsc = NULL;
+ else {
+ rtsc = &qopts->data.hfsc_opts.realtime;
+ lssc = &qopts->data.hfsc_opts.linkshare;
+ ulsc = &qopts->data.hfsc_opts.upperlimit;
+ }
+
+ if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 ||
+ (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))) {
+ printf("hfsc(");
+ if (opts->flags & HFCF_RED)
+ printf(" red");
+ if (opts->flags & HFCF_ECN)
+ printf(" ecn");
+ if (opts->flags & HFCF_RIO)
+ printf(" rio");
+ if (opts->flags & HFCF_CODEL)
+ printf(" codel");
+ if (opts->flags & HFCF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & HFCF_DEFAULTCLASS)
+ printf(" default");
+ if (opts->rtsc_m2 != 0)
+ print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d,
+ opts->rtsc_m2, rtsc);
+ if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))
+ print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d,
+ opts->lssc_m2, lssc);
+ if (opts->ulsc_m2 != 0)
+ print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d,
+ opts->ulsc_m2, ulsc);
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+static int
+print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct codel_opts *opts;
+
+ opts = &a->pq_u.codel_opts;
+ if (opts->target || opts->interval || opts->ecn) {
+ printf("codel(");
+ if (opts->target)
+ printf(" target %d", opts->target);
+ if (opts->interval)
+ printf(" interval %d", opts->interval);
+ if (opts->ecn)
+ printf("ecn");
+ printf(" ) ");
+
+ return (1);
+ }
+
+ return (0);
+}
+
+static int
+print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts)
+{
+ const struct fairq_opts *opts;
+ const struct node_fairq_sc *loc_lssc;
+
+ opts = &a->pq_u.fairq_opts;
+ if (qopts == NULL)
+ loc_lssc = NULL;
+ else
+ loc_lssc = &qopts->data.fairq_opts.linkshare;
+
+ if (opts->flags ||
+ (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))) {
+ printf("fairq(");
+ if (opts->flags & FARF_RED)
+ printf(" red");
+ if (opts->flags & FARF_ECN)
+ printf(" ecn");
+ if (opts->flags & FARF_RIO)
+ printf(" rio");
+ if (opts->flags & FARF_CODEL)
+ printf(" codel");
+ if (opts->flags & FARF_CLEARDSCP)
+ printf(" cleardscp");
+ if (opts->flags & FARF_DEFAULTCLASS)
+ printf(" default");
+ if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth ||
+ opts->lssc_d != 0))
+ print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d,
+ opts->lssc_m2, loc_lssc);
+ printf(" ) ");
+
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * admission control using generalized service curve
+ */
+
+/* add a new service curve to a generalized service curve */
+static void
+gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc)
+{
+ if (is_sc_null(sc))
+ return;
+ if (sc->d != 0)
+ gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1);
+ gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2);
+}
+
+/*
+ * check whether all points of a generalized service curve have
+ * their y-coordinates no larger than a given two-piece linear
+ * service curve.
+ */
+static int
+is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc)
+{
+ struct segment *s, *last, *end;
+ double y;
+
+ if (is_sc_null(sc)) {
+ if (LIST_EMPTY(gsc))
+ return (1);
+ LIST_FOREACH(s, gsc, _next) {
+ if (s->m != 0)
+ return (0);
+ }
+ return (1);
+ }
+ /*
+ * gsc has a dummy entry at the end with x = INFINITY.
+ * loop through up to this dummy entry.
+ */
+ end = gsc_getentry(gsc, INFINITY);
+ if (end == NULL)
+ return (1);
+ last = NULL;
+ for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) {
+ if (s->y > sc_x2y(sc, s->x))
+ return (0);
+ last = s;
+ }
+ /* last now holds the real last segment */
+ if (last == NULL)
+ return (1);
+ if (last->m > sc->m2)
+ return (0);
+ if (last->x < sc->d && last->m > sc->m1) {
+ y = last->y + (sc->d - last->x) * last->m;
+ if (y > sc_x2y(sc, sc->d))
+ return (0);
+ }
+ return (1);
+}
+
+static void
+gsc_destroy(struct gen_sc *gsc)
+{
+ struct segment *s;
+
+ while ((s = LIST_FIRST(gsc)) != NULL) {
+ LIST_REMOVE(s, _next);
+ free(s);
+ }
+}
+
+/*
+ * return a segment entry starting at x.
+ * if gsc has no entry starting at x, a new entry is created at x.
+ */
+static struct segment *
+gsc_getentry(struct gen_sc *gsc, double x)
+{
+ struct segment *new, *prev, *s;
+
+ prev = NULL;
+ LIST_FOREACH(s, gsc, _next) {
+ if (s->x == x)
+ return (s); /* matching entry found */
+ else if (s->x < x)
+ prev = s;
+ else
+ break;
+ }
+
+ /* we have to create a new entry */
+ if ((new = calloc(1, sizeof(struct segment))) == NULL)
+ return (NULL);
+
+ new->x = x;
+ if (x == INFINITY || s == NULL)
+ new->d = 0;
+ else if (s->x == INFINITY)
+ new->d = INFINITY;
+ else
+ new->d = s->x - x;
+ if (prev == NULL) {
+ /* insert the new entry at the head of the list */
+ new->y = 0;
+ new->m = 0;
+ LIST_INSERT_HEAD(gsc, new, _next);
+ } else {
+ /*
+ * the start point intersects with the segment pointed by
+ * prev. divide prev into 2 segments
+ */
+ if (x == INFINITY) {
+ prev->d = INFINITY;
+ if (prev->m == 0)
+ new->y = prev->y;
+ else
+ new->y = INFINITY;
+ } else {
+ prev->d = x - prev->x;
+ new->y = prev->d * prev->m + prev->y;
+ }
+ new->m = prev->m;
+ LIST_INSERT_AFTER(prev, new, _next);
+ }
+ return (new);
+}
+
+/* add a segment to a generalized service curve */
+static int
+gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m)
+{
+ struct segment *start, *end, *s;
+ double x2;
+
+ if (d == INFINITY)
+ x2 = INFINITY;
+ else
+ x2 = x + d;
+ start = gsc_getentry(gsc, x);
+ end = gsc_getentry(gsc, x2);
+ if (start == NULL || end == NULL)
+ return (-1);
+
+ for (s = start; s != end; s = LIST_NEXT(s, _next)) {
+ s->m += m;
+ s->y += y + (s->x - x) * m;
+ }
+
+ end = gsc_getentry(gsc, INFINITY);
+ for (; s != end; s = LIST_NEXT(s, _next)) {
+ s->y += m * d;
+ }
+
+ return (0);
+}
+
+/* get y-projection of a service curve */
+static double
+sc_x2y(struct service_curve *sc, double x)
+{
+ double y;
+
+ if (x <= (double)sc->d)
+ /* y belongs to the 1st segment */
+ y = x * (double)sc->m1;
+ else
+ /* y belongs to the 2nd segment */
+ y = (double)sc->d * (double)sc->m1
+ + (x - (double)sc->d) * (double)sc->m2;
+ return (y);
+}
+
+/*
+ * misc utilities
+ */
+#define R2S_BUFS 8
+#define RATESTR_MAX 16
+
+#ifdef __rtems__
+static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
+static int idx = 0;
+#endif /* __rtems__ */
+char *
+rate2str(double rate)
+{
+ char *buf;
+#ifndef __rtems__
+ static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */
+ static int idx = 0;
+#endif /* __rtems__ */
+ int i;
+ static const char unit[] = " KMG";
+
+ buf = r2sbuf[idx++];
+ if (idx == R2S_BUFS)
+ idx = 0;
+
+ for (i = 0; rate >= 1000 && i <= 3; i++)
+ rate /= 1000;
+
+ if ((int)(rate * 100) % 100)
+ snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]);
+ else
+ snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]);
+
+ return (buf);
+}
+
+#ifdef __FreeBSD__
+/*
+ * XXX
+ * FreeBSD does not have SIOCGIFDATA.
+ * To emulate this, DIOCGIFSPEED ioctl added to pf.
+ */
+u_int32_t
+getifspeed(int pfdev, char *ifname)
+{
+ struct pf_ifspeed io;
+
+ bzero(&io, sizeof io);
+ if (strlcpy(io.ifname, ifname, IFNAMSIZ) >=
+ sizeof(io.ifname))
+ errx(1, "getifspeed: strlcpy");
+ if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1)
+ err(1, "DIOCGIFSPEED");
+ return ((u_int32_t)io.baudrate);
+}
+#else
+u_int32_t
+getifspeed(char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+ struct if_data ifrdat;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ bzero(&ifr, sizeof(ifr));
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
+ sizeof(ifr.ifr_name))
+ errx(1, "getifspeed: strlcpy");
+ ifr.ifr_data = (caddr_t)&ifrdat;
+ if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGIFDATA");
+ if (close(s))
+ err(1, "close");
+ return ((u_int32_t)ifrdat.ifi_baudrate);
+}
+#endif
+
+u_long
+getifmtu(char *ifname)
+{
+ int s;
+ struct ifreq ifr;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ bzero(&ifr, sizeof(ifr));
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
+ sizeof(ifr.ifr_name))
+ errx(1, "getifmtu: strlcpy");
+ if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1)
+#ifdef __FreeBSD__
+ ifr.ifr_mtu = 1500;
+#else
+ err(1, "SIOCGIFMTU");
+#endif
+ if (close(s))
+ err(1, "close");
+ if (ifr.ifr_mtu > 0)
+ return (ifr.ifr_mtu);
+ else {
+ warnx("could not get mtu for %s, assuming 1500", ifname);
+ return (1500);
+ }
+}
+
+int
+eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts,
+ u_int32_t ref_bw)
+{
+ int errors = 0;
+
+ switch (pa->scheduler) {
+ case ALTQT_CBQ:
+ pa->pq_u.cbq_opts = opts->data.cbq_opts;
+ break;
+ case ALTQT_PRIQ:
+ pa->pq_u.priq_opts = opts->data.priq_opts;
+ break;
+ case ALTQT_HFSC:
+ pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags;
+ if (opts->data.hfsc_opts.linkshare.used) {
+ pa->pq_u.hfsc_opts.lssc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.linkshare.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.lssc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.linkshare.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.lssc_d =
+ opts->data.hfsc_opts.linkshare.d;
+ }
+ if (opts->data.hfsc_opts.realtime.used) {
+ pa->pq_u.hfsc_opts.rtsc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.realtime.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.rtsc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.realtime.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.rtsc_d =
+ opts->data.hfsc_opts.realtime.d;
+ }
+ if (opts->data.hfsc_opts.upperlimit.used) {
+ pa->pq_u.hfsc_opts.ulsc_m1 =
+ eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1,
+ ref_bw);
+ pa->pq_u.hfsc_opts.ulsc_m2 =
+ eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2,
+ ref_bw);
+ pa->pq_u.hfsc_opts.ulsc_d =
+ opts->data.hfsc_opts.upperlimit.d;
+ }
+ break;
+ case ALTQT_FAIRQ:
+ pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags;
+ pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets;
+ pa->pq_u.fairq_opts.hogs_m1 =
+ eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw);
+
+ if (opts->data.fairq_opts.linkshare.used) {
+ pa->pq_u.fairq_opts.lssc_m1 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m1,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_m2 =
+ eval_bwspec(&opts->data.fairq_opts.linkshare.m2,
+ ref_bw);
+ pa->pq_u.fairq_opts.lssc_d =
+ opts->data.fairq_opts.linkshare.d;
+ }
+ break;
+ case ALTQT_CODEL:
+ pa->pq_u.codel_opts.target = opts->data.codel_opts.target;
+ pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval;
+ pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn;
+ break;
+ default:
+ warnx("eval_queue_opts: unknown scheduler type %u",
+ opts->qtype);
+ errors++;
+ break;
+ }
+
+ return (errors);
+}
+
+u_int32_t
+eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw)
+{
+ if (bw->bw_absolute > 0)
+ return (bw->bw_absolute);
+
+ if (bw->bw_percent > 0)
+ return (ref_bw / 100 * bw->bw_percent);
+
+ return (0);
+}
+
+void
+print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2,
+ const struct node_hfsc_sc *sc)
+{
+ printf(" %s", scname);
+
+ if (d != 0) {
+ printf("(");
+ if (sc != NULL && sc->m1.bw_percent > 0)
+ printf("%u%%", sc->m1.bw_percent);
+ else
+ printf("%s", rate2str((double)m1));
+ printf(" %u", d);
+ }
+
+ if (sc != NULL && sc->m2.bw_percent > 0)
+ printf(" %u%%", sc->m2.bw_percent);
+ else
+ printf(" %s", rate2str((double)m2));
+
+ if (d != 0)
+ printf(")");
+}
+
+void
+print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2,
+ const struct node_fairq_sc *sc)
+{
+ printf(" %s", scname);
+
+ if (d != 0) {
+ printf("(");
+ if (sc != NULL && sc->m1.bw_percent > 0)
+ printf("%u%%", sc->m1.bw_percent);
+ else
+ printf("%s", rate2str((double)m1));
+ printf(" %u", d);
+ }
+
+ if (sc != NULL && sc->m2.bw_percent > 0)
+ printf(" %u%%", sc->m2.bw_percent);
+ else
+ printf(" %s", rate2str((double)m2));
+
+ if (d != 0)
+ printf(")");
+}
diff --git a/freebsd/sbin/pfctl/pfctl_optimize.c b/freebsd/sbin/pfctl/pfctl_optimize.c
new file mode 100644
index 00000000..b8f44e8b
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_optimize.c
@@ -0,0 +1,1705 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */
+
+/*
+ * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+struct pf_rule_field {
+ const char *prf_name;
+ int prf_type;
+ size_t prf_offset;
+ size_t prf_size;
+};
+#include "rtems-bsd-pfctl-pfctl_optimize-data.h"
+#endif /* __rtems__ */
+
+/* The size at which a table becomes faster than individual rules */
+#define TABLE_THRESHOLD 6
+
+
+/* #define OPT_DEBUG 1 */
+#ifdef OPT_DEBUG
+# define DEBUG(str, v...) \
+ printf("%s: " str "\n", __FUNCTION__ , ## v)
+#else
+# define DEBUG(str, v...) ((void)0)
+#endif
+
+
+/*
+ * A container that lets us sort a superblock to optimize the skip step jumps
+ */
+struct pf_skip_step {
+ int ps_count; /* number of items */
+ TAILQ_HEAD( , pf_opt_rule) ps_rules;
+ TAILQ_ENTRY(pf_skip_step) ps_entry;
+};
+
+
+/*
+ * A superblock is a block of adjacent rules of similar action. If there
+ * are five PASS rules in a row, they all become members of a superblock.
+ * Once we have a superblock, we are free to re-order any rules within it
+ * in order to improve performance; if a packet is passed, it doesn't matter
+ * who passed it.
+ */
+struct superblock {
+ TAILQ_HEAD( , pf_opt_rule) sb_rules;
+ TAILQ_ENTRY(superblock) sb_entry;
+ struct superblock *sb_profiled_block;
+ TAILQ_HEAD(skiplist, pf_skip_step) sb_skipsteps[PF_SKIP_COUNT];
+};
+TAILQ_HEAD(superblocks, superblock);
+
+
+/*
+ * Description of the PF rule structure.
+ */
+enum {
+ BARRIER, /* the presence of the field puts the rule in it's own block */
+ BREAK, /* the field may not differ between rules in a superblock */
+ NOMERGE, /* the field may not differ between rules when combined */
+ COMBINED, /* the field may itself be combined with other rules */
+ DC, /* we just don't care about the field */
+ NEVER}; /* we should never see this field set?!? */
+#ifndef __rtems__
+static struct pf_rule_field {
+ const char *prf_name;
+ int prf_type;
+ size_t prf_offset;
+ size_t prf_size;
+} pf_rule_desc[] = {
+#else /* __rtems__ */
+static struct pf_rule_field pf_rule_desc[] = {
+#endif /* __rtems__ */
+#define PF_RULE_FIELD(field, ty) \
+ {#field, \
+ ty, \
+ offsetof(struct pf_rule, field), \
+ sizeof(((struct pf_rule *)0)->field)}
+
+
+ /*
+ * The presence of these fields in a rule put the rule in it's own
+ * superblock. Thus it will not be optimized. It also prevents the
+ * rule from being re-ordered at all.
+ */
+ PF_RULE_FIELD(label, BARRIER),
+ PF_RULE_FIELD(prob, BARRIER),
+ PF_RULE_FIELD(max_states, BARRIER),
+ PF_RULE_FIELD(max_src_nodes, BARRIER),
+ PF_RULE_FIELD(max_src_states, BARRIER),
+ PF_RULE_FIELD(max_src_conn, BARRIER),
+ PF_RULE_FIELD(max_src_conn_rate, BARRIER),
+ PF_RULE_FIELD(anchor, BARRIER), /* for now */
+
+ /*
+ * These fields must be the same between all rules in the same superblock.
+ * These rules are allowed to be re-ordered but only among like rules.
+ * For instance we can re-order all 'tag "foo"' rules because they have the
+ * same tag. But we can not re-order between a 'tag "foo"' and a
+ * 'tag "bar"' since that would change the meaning of the ruleset.
+ */
+ PF_RULE_FIELD(tagname, BREAK),
+ PF_RULE_FIELD(keep_state, BREAK),
+ PF_RULE_FIELD(qname, BREAK),
+ PF_RULE_FIELD(pqname, BREAK),
+ PF_RULE_FIELD(rt, BREAK),
+ PF_RULE_FIELD(allow_opts, BREAK),
+ PF_RULE_FIELD(rule_flag, BREAK),
+ PF_RULE_FIELD(action, BREAK),
+ PF_RULE_FIELD(log, BREAK),
+ PF_RULE_FIELD(quick, BREAK),
+ PF_RULE_FIELD(return_ttl, BREAK),
+ PF_RULE_FIELD(overload_tblname, BREAK),
+ PF_RULE_FIELD(flush, BREAK),
+ PF_RULE_FIELD(rpool, BREAK),
+ PF_RULE_FIELD(logif, BREAK),
+
+ /*
+ * Any fields not listed in this structure act as BREAK fields
+ */
+
+
+ /*
+ * These fields must not differ when we merge two rules together but
+ * their difference isn't enough to put the rules in different superblocks.
+ * There are no problems re-ordering any rules with these fields.
+ */
+ PF_RULE_FIELD(af, NOMERGE),
+ PF_RULE_FIELD(ifnot, NOMERGE),
+ PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */
+ PF_RULE_FIELD(match_tag_not, NOMERGE),
+ PF_RULE_FIELD(match_tagname, NOMERGE),
+ PF_RULE_FIELD(os_fingerprint, NOMERGE),
+ PF_RULE_FIELD(timeout, NOMERGE),
+ PF_RULE_FIELD(return_icmp, NOMERGE),
+ PF_RULE_FIELD(return_icmp6, NOMERGE),
+ PF_RULE_FIELD(uid, NOMERGE),
+ PF_RULE_FIELD(gid, NOMERGE),
+ PF_RULE_FIELD(direction, NOMERGE),
+ PF_RULE_FIELD(proto, NOMERGE),
+ PF_RULE_FIELD(type, NOMERGE),
+ PF_RULE_FIELD(code, NOMERGE),
+ PF_RULE_FIELD(flags, NOMERGE),
+ PF_RULE_FIELD(flagset, NOMERGE),
+ PF_RULE_FIELD(tos, NOMERGE),
+ PF_RULE_FIELD(src.port, NOMERGE),
+ PF_RULE_FIELD(dst.port, NOMERGE),
+ PF_RULE_FIELD(src.port_op, NOMERGE),
+ PF_RULE_FIELD(dst.port_op, NOMERGE),
+ PF_RULE_FIELD(src.neg, NOMERGE),
+ PF_RULE_FIELD(dst.neg, NOMERGE),
+
+ /* These fields can be merged */
+ PF_RULE_FIELD(src.addr, COMBINED),
+ PF_RULE_FIELD(dst.addr, COMBINED),
+
+ /* We just don't care about these fields. They're set by the kernel */
+ PF_RULE_FIELD(skip, DC),
+ PF_RULE_FIELD(evaluations, DC),
+ PF_RULE_FIELD(packets, DC),
+ PF_RULE_FIELD(bytes, DC),
+ PF_RULE_FIELD(kif, DC),
+ PF_RULE_FIELD(states_cur, DC),
+ PF_RULE_FIELD(states_tot, DC),
+ PF_RULE_FIELD(src_nodes, DC),
+ PF_RULE_FIELD(nr, DC),
+ PF_RULE_FIELD(entries, DC),
+ PF_RULE_FIELD(qid, DC),
+ PF_RULE_FIELD(pqid, DC),
+ PF_RULE_FIELD(anchor_relative, DC),
+ PF_RULE_FIELD(anchor_wildcard, DC),
+ PF_RULE_FIELD(tag, DC),
+ PF_RULE_FIELD(match_tag, DC),
+ PF_RULE_FIELD(overload_tbl, DC),
+
+ /* These fields should never be set in a PASS/BLOCK rule */
+ PF_RULE_FIELD(natpass, NEVER),
+ PF_RULE_FIELD(max_mss, NEVER),
+ PF_RULE_FIELD(min_ttl, NEVER),
+ PF_RULE_FIELD(set_tos, NEVER),
+};
+
+
+
+int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t,
+ struct pf_rule_addr *);
+int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *);
+int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *);
+int block_feedback(struct pfctl *, struct superblock *);
+int combine_rules(struct pfctl *, struct superblock *);
+void comparable_rule(struct pf_rule *, const struct pf_rule *, int);
+int construct_superblocks(struct pfctl *, struct pf_opt_queue *,
+ struct superblocks *);
+void exclude_supersets(struct pf_rule *, struct pf_rule *);
+int interface_group(const char *);
+int load_feedback_profile(struct pfctl *, struct superblocks *);
+int optimize_superblock(struct pfctl *, struct superblock *);
+int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *);
+void remove_from_skipsteps(struct skiplist *, struct superblock *,
+ struct pf_opt_rule *, struct pf_skip_step *);
+int remove_identical_rules(struct pfctl *, struct superblock *);
+int reorder_rules(struct pfctl *, struct superblock *, int);
+int rules_combineable(struct pf_rule *, struct pf_rule *);
+void skip_append(struct superblock *, int, struct pf_skip_step *,
+ struct pf_opt_rule *);
+int skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *);
+void skip_init(void);
+int skip_cmp_af(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dir(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *);
+int skip_cmp_dst_port(struct pf_rule *, struct pf_rule *);
+int skip_cmp_ifp(struct pf_rule *, struct pf_rule *);
+int skip_cmp_proto(struct pf_rule *, struct pf_rule *);
+int skip_cmp_src_addr(struct pf_rule *, struct pf_rule *);
+int skip_cmp_src_port(struct pf_rule *, struct pf_rule *);
+int superblock_inclusive(struct superblock *, struct pf_opt_rule *);
+void superblock_free(struct pfctl *, struct superblock *);
+
+
+static int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *,
+ struct pf_rule *);
+static const char *skip_comparitors_names[PF_SKIP_COUNT];
+#define PF_SKIP_COMPARITORS { \
+ { "ifp", PF_SKIP_IFP, skip_cmp_ifp }, \
+ { "dir", PF_SKIP_DIR, skip_cmp_dir }, \
+ { "af", PF_SKIP_AF, skip_cmp_af }, \
+ { "proto", PF_SKIP_PROTO, skip_cmp_proto }, \
+ { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr }, \
+ { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port }, \
+ { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr }, \
+ { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \
+}
+
+static struct pfr_buffer table_buffer;
+static int table_identifier;
+
+
+int
+pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs)
+{
+ struct superblocks superblocks;
+ struct pf_opt_queue opt_queue;
+ struct superblock *block;
+ struct pf_opt_rule *por;
+ struct pf_rule *r;
+ struct pf_rulequeue *old_rules;
+
+ DEBUG("optimizing ruleset");
+ memset(&table_buffer, 0, sizeof(table_buffer));
+ skip_init();
+ TAILQ_INIT(&opt_queue);
+
+ old_rules = rs->rules[PF_RULESET_FILTER].active.ptr;
+ rs->rules[PF_RULESET_FILTER].active.ptr =
+ rs->rules[PF_RULESET_FILTER].inactive.ptr;
+ rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules;
+
+ /*
+ * XXX expanding the pf_opt_rule format throughout pfctl might allow
+ * us to avoid all this copying.
+ */
+ while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr))
+ != NULL) {
+ TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r,
+ entries);
+ if ((por = calloc(1, sizeof(*por))) == NULL)
+ err(1, "calloc");
+ memcpy(&por->por_rule, r, sizeof(*r));
+ if (TAILQ_FIRST(&r->rpool.list) != NULL) {
+ TAILQ_INIT(&por->por_rule.rpool.list);
+ pfctl_move_pool(&r->rpool, &por->por_rule.rpool);
+ } else
+ bzero(&por->por_rule.rpool,
+ sizeof(por->por_rule.rpool));
+
+
+ TAILQ_INSERT_TAIL(&opt_queue, por, por_entry);
+ }
+
+ TAILQ_INIT(&superblocks);
+ if (construct_superblocks(pf, &opt_queue, &superblocks))
+ goto error;
+
+ if (pf->optimize & PF_OPTIMIZE_PROFILE) {
+ if (load_feedback_profile(pf, &superblocks))
+ goto error;
+ }
+
+ TAILQ_FOREACH(block, &superblocks, sb_entry) {
+ if (optimize_superblock(pf, block))
+ goto error;
+ }
+
+ rs->anchor->refcnt = 0;
+ while ((block = TAILQ_FIRST(&superblocks))) {
+ TAILQ_REMOVE(&superblocks, block, sb_entry);
+
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ por->por_rule.nr = rs->anchor->refcnt++;
+ if ((r = calloc(1, sizeof(*r))) == NULL)
+ err(1, "calloc");
+ memcpy(r, &por->por_rule, sizeof(*r));
+ TAILQ_INIT(&r->rpool.list);
+ pfctl_move_pool(&por->por_rule.rpool, &r->rpool);
+ TAILQ_INSERT_TAIL(
+ rs->rules[PF_RULESET_FILTER].active.ptr,
+ r, entries);
+ free(por);
+ }
+ free(block);
+ }
+
+ return (0);
+
+error:
+ while ((por = TAILQ_FIRST(&opt_queue))) {
+ TAILQ_REMOVE(&opt_queue, por, por_entry);
+ if (por->por_src_tbl) {
+ pfr_buf_clear(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl);
+ }
+ if (por->por_dst_tbl) {
+ pfr_buf_clear(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl);
+ }
+ free(por);
+ }
+ while ((block = TAILQ_FIRST(&superblocks))) {
+ TAILQ_REMOVE(&superblocks, block, sb_entry);
+ superblock_free(pf, block);
+ }
+ return (1);
+}
+
+
+/*
+ * Go ahead and optimize a superblock
+ */
+int
+optimize_superblock(struct pfctl *pf, struct superblock *block)
+{
+#ifdef OPT_DEBUG
+ struct pf_opt_rule *por;
+#endif /* OPT_DEBUG */
+
+ /* We have a few optimization passes:
+ * 1) remove duplicate rules or rules that are a subset of other
+ * rules
+ * 2) combine otherwise identical rules with different IP addresses
+ * into a single rule and put the addresses in a table.
+ * 3) re-order the rules to improve kernel skip steps
+ * 4) re-order the 'quick' rules based on feedback from the
+ * active ruleset statistics
+ *
+ * XXX combine_rules() doesn't combine v4 and v6 rules. would just
+ * have to keep af in the table container, make af 'COMBINE' and
+ * twiddle the af on the merged rule
+ * XXX maybe add a weighting to the metric on skipsteps when doing
+ * reordering. sometimes two sequential tables will be better
+ * that four consecutive interfaces.
+ * XXX need to adjust the skipstep count of everything after PROTO,
+ * since they aren't actually checked on a proto mismatch in
+ * pf_test_{tcp, udp, icmp}()
+ * XXX should i treat proto=0, af=0 or dir=0 special in skepstep
+ * calculation since they are a DC?
+ * XXX keep last skiplist of last superblock to influence this
+ * superblock. '5 inet6 log' should make '3 inet6' come before '4
+ * inet' in the next superblock.
+ * XXX would be useful to add tables for ports
+ * XXX we can also re-order some mutually exclusive superblocks to
+ * try merging superblocks before any of these optimization passes.
+ * for instance a single 'log in' rule in the middle of non-logging
+ * out rules.
+ */
+
+ /* shortcut. there will be a lot of 1-rule superblocks */
+ if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry))
+ return (0);
+
+#ifdef OPT_DEBUG
+ printf("--- Superblock ---\n");
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
+ printf(" ");
+ print_rule(&por->por_rule, por->por_rule.anchor ?
+ por->por_rule.anchor->name : "", 1, 0);
+ }
+#endif /* OPT_DEBUG */
+
+
+ if (remove_identical_rules(pf, block))
+ return (1);
+ if (combine_rules(pf, block))
+ return (1);
+ if ((pf->optimize & PF_OPTIMIZE_PROFILE) &&
+ TAILQ_FIRST(&block->sb_rules)->por_rule.quick &&
+ block->sb_profiled_block) {
+ if (block_feedback(pf, block))
+ return (1);
+ } else if (reorder_rules(pf, block, 0)) {
+ return (1);
+ }
+
+ /*
+ * Don't add any optimization passes below reorder_rules(). It will
+ * have divided superblocks into smaller blocks for further refinement
+ * and doesn't put them back together again. What once was a true
+ * superblock might have been split into multiple superblocks.
+ */
+
+#ifdef OPT_DEBUG
+ printf("--- END Superblock ---\n");
+#endif /* OPT_DEBUG */
+ return (0);
+}
+
+
+/*
+ * Optimization pass #1: remove identical rules
+ */
+int
+remove_identical_rules(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *por1, *por2, *por_next, *por2_next;
+ struct pf_rule a, a2, b, b2;
+
+ for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) {
+ por_next = TAILQ_NEXT(por1, por_entry);
+ for (por2 = por_next; por2; por2 = por2_next) {
+ por2_next = TAILQ_NEXT(por2, por_entry);
+ comparable_rule(&a, &por1->por_rule, DC);
+ comparable_rule(&b, &por2->por_rule, DC);
+ memcpy(&a2, &a, sizeof(a2));
+ memcpy(&b2, &b, sizeof(b2));
+
+ exclude_supersets(&a, &b);
+ exclude_supersets(&b2, &a2);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ DEBUG("removing identical rule nr%d = *nr%d*",
+ por1->por_rule.nr, por2->por_rule.nr);
+ TAILQ_REMOVE(&block->sb_rules, por2, por_entry);
+ if (por_next == por2)
+ por_next = TAILQ_NEXT(por1, por_entry);
+ free(por2);
+ } else if (memcmp(&a2, &b2, sizeof(a2)) == 0) {
+ DEBUG("removing identical rule *nr%d* = nr%d",
+ por1->por_rule.nr, por2->por_rule.nr);
+ TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
+ free(por1);
+ break;
+ }
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #2: combine similar rules with different addresses
+ * into a single rule and a table
+ */
+int
+combine_rules(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *p1, *p2, *por_next;
+ int src_eq, dst_eq;
+
+ if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) {
+ warnx("Must enable table loading for optimizations");
+ return (1);
+ }
+
+ /* First we make a pass to combine the rules. O(n log n) */
+ TAILQ_FOREACH(p1, &block->sb_rules, por_entry) {
+ for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) {
+ por_next = TAILQ_NEXT(p2, por_entry);
+
+ src_eq = addrs_equal(&p1->por_rule.src,
+ &p2->por_rule.src);
+ dst_eq = addrs_equal(&p1->por_rule.dst,
+ &p2->por_rule.dst);
+
+ if (src_eq && !dst_eq && p1->por_src_tbl == NULL &&
+ p2->por_dst_tbl == NULL &&
+ p2->por_src_tbl == NULL &&
+ rules_combineable(&p1->por_rule, &p2->por_rule) &&
+ addrs_combineable(&p1->por_rule.dst,
+ &p2->por_rule.dst)) {
+ DEBUG("can combine rules nr%d = nr%d",
+ p1->por_rule.nr, p2->por_rule.nr);
+ if (p1->por_dst_tbl == NULL &&
+ add_opt_table(pf, &p1->por_dst_tbl,
+ p1->por_rule.af, &p1->por_rule.dst))
+ return (1);
+ if (add_opt_table(pf, &p1->por_dst_tbl,
+ p1->por_rule.af, &p2->por_rule.dst))
+ return (1);
+ p2->por_dst_tbl = p1->por_dst_tbl;
+ if (p1->por_dst_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ TAILQ_REMOVE(&block->sb_rules, p2,
+ por_entry);
+ free(p2);
+ }
+ } else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL
+ && p2->por_src_tbl == NULL &&
+ p2->por_dst_tbl == NULL &&
+ rules_combineable(&p1->por_rule, &p2->por_rule) &&
+ addrs_combineable(&p1->por_rule.src,
+ &p2->por_rule.src)) {
+ DEBUG("can combine rules nr%d = nr%d",
+ p1->por_rule.nr, p2->por_rule.nr);
+ if (p1->por_src_tbl == NULL &&
+ add_opt_table(pf, &p1->por_src_tbl,
+ p1->por_rule.af, &p1->por_rule.src))
+ return (1);
+ if (add_opt_table(pf, &p1->por_src_tbl,
+ p1->por_rule.af, &p2->por_rule.src))
+ return (1);
+ p2->por_src_tbl = p1->por_src_tbl;
+ if (p1->por_src_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ TAILQ_REMOVE(&block->sb_rules, p2,
+ por_entry);
+ free(p2);
+ }
+ }
+ }
+ }
+
+
+ /*
+ * Then we make a final pass to create a valid table name and
+ * insert the name into the rules.
+ */
+ for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) {
+ por_next = TAILQ_NEXT(p1, por_entry);
+ assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL);
+
+ if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ if (p1->por_src_tbl->pt_generated) {
+ /* This rule is included in a table */
+ TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
+ free(p1);
+ continue;
+ }
+ p1->por_src_tbl->pt_generated = 1;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ pf_opt_create_table(pf, p1->por_src_tbl))
+ return (1);
+
+ pf->tdirty = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(p1->por_src_tbl->pt_name,
+ PFR_TFLAG_CONST, 1,
+ &p1->por_src_tbl->pt_nodes);
+
+ memset(&p1->por_rule.src.addr, 0,
+ sizeof(p1->por_rule.src.addr));
+ p1->por_rule.src.addr.type = PF_ADDR_TABLE;
+ strlcpy(p1->por_rule.src.addr.v.tblname,
+ p1->por_src_tbl->pt_name,
+ sizeof(p1->por_rule.src.addr.v.tblname));
+
+ pfr_buf_clear(p1->por_src_tbl->pt_buf);
+ free(p1->por_src_tbl->pt_buf);
+ p1->por_src_tbl->pt_buf = NULL;
+ }
+ if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >=
+ TABLE_THRESHOLD) {
+ if (p1->por_dst_tbl->pt_generated) {
+ /* This rule is included in a table */
+ TAILQ_REMOVE(&block->sb_rules, p1, por_entry);
+ free(p1);
+ continue;
+ }
+ p1->por_dst_tbl->pt_generated = 1;
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0 &&
+ pf_opt_create_table(pf, p1->por_dst_tbl))
+ return (1);
+ pf->tdirty = 1;
+
+ if (pf->opts & PF_OPT_VERBOSE)
+ print_tabledef(p1->por_dst_tbl->pt_name,
+ PFR_TFLAG_CONST, 1,
+ &p1->por_dst_tbl->pt_nodes);
+
+ memset(&p1->por_rule.dst.addr, 0,
+ sizeof(p1->por_rule.dst.addr));
+ p1->por_rule.dst.addr.type = PF_ADDR_TABLE;
+ strlcpy(p1->por_rule.dst.addr.v.tblname,
+ p1->por_dst_tbl->pt_name,
+ sizeof(p1->por_rule.dst.addr.v.tblname));
+
+ pfr_buf_clear(p1->por_dst_tbl->pt_buf);
+ free(p1->por_dst_tbl->pt_buf);
+ p1->por_dst_tbl->pt_buf = NULL;
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #3: re-order rules to improve skip steps
+ */
+int
+reorder_rules(struct pfctl *pf, struct superblock *block, int depth)
+{
+ struct superblock *newblock;
+ struct pf_skip_step *skiplist;
+ struct pf_opt_rule *por;
+ int i, largest, largest_list, rule_count = 0;
+ TAILQ_HEAD( , pf_opt_rule) head;
+
+ /*
+ * Calculate the best-case skip steps. We put each rule in a list
+ * of other rules with common fields
+ */
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry) {
+ TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i],
+ ps_entry) {
+ if (skip_compare(i, skiplist, por) == 0)
+ break;
+ }
+ if (skiplist == NULL) {
+ if ((skiplist = calloc(1, sizeof(*skiplist))) ==
+ NULL)
+ err(1, "calloc");
+ TAILQ_INIT(&skiplist->ps_rules);
+ TAILQ_INSERT_TAIL(&block->sb_skipsteps[i],
+ skiplist, ps_entry);
+ }
+ skip_append(block, i, skiplist, por);
+ }
+ }
+
+ TAILQ_FOREACH(por, &block->sb_rules, por_entry)
+ rule_count++;
+
+ /*
+ * Now we're going to ignore any fields that are identical between
+ * all of the rules in the superblock and those fields which differ
+ * between every rule in the superblock.
+ */
+ largest = 0;
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (skiplist->ps_count == rule_count) {
+ DEBUG("(%d) original skipstep '%s' is all rules",
+ depth, skip_comparitors_names[i]);
+ skiplist->ps_count = 0;
+ } else if (skiplist->ps_count == 1) {
+ skiplist->ps_count = 0;
+ } else {
+ DEBUG("(%d) original skipstep '%s' largest jump is %d",
+ depth, skip_comparitors_names[i],
+ skiplist->ps_count);
+ if (skiplist->ps_count > largest)
+ largest = skiplist->ps_count;
+ }
+ }
+ if (largest == 0) {
+ /* Ugh. There is NO commonality in the superblock on which
+ * optimize the skipsteps optimization.
+ */
+ goto done;
+ }
+
+ /*
+ * Now we're going to empty the superblock rule list and re-create
+ * it based on a more optimal skipstep order.
+ */
+ TAILQ_INIT(&head);
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ TAILQ_INSERT_TAIL(&head, por, por_entry);
+ }
+
+
+ while (!TAILQ_EMPTY(&head)) {
+ largest = 1;
+
+ /*
+ * Find the most useful skip steps remaining
+ */
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (skiplist->ps_count > largest) {
+ largest = skiplist->ps_count;
+ largest_list = i;
+ }
+ }
+
+ if (largest <= 1) {
+ /*
+ * Nothing useful left. Leave remaining rules in order.
+ */
+ DEBUG("(%d) no more commonality for skip steps", depth);
+ while ((por = TAILQ_FIRST(&head))) {
+ TAILQ_REMOVE(&head, por, por_entry);
+ TAILQ_INSERT_TAIL(&block->sb_rules, por,
+ por_entry);
+ }
+ } else {
+ /*
+ * There is commonality. Extract those common rules
+ * and place them in the ruleset adjacent to each
+ * other.
+ */
+ skiplist = TAILQ_FIRST(&block->sb_skipsteps[
+ largest_list]);
+ DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d",
+ depth, skip_comparitors_names[largest_list],
+ largest, TAILQ_FIRST(&TAILQ_FIRST(&block->
+ sb_skipsteps [largest_list])->ps_rules)->
+ por_rule.nr);
+ TAILQ_REMOVE(&block->sb_skipsteps[largest_list],
+ skiplist, ps_entry);
+
+
+ /*
+ * There may be further commonality inside these
+ * rules. So we'll split them off into they're own
+ * superblock and pass it back into the optimizer.
+ */
+ if (skiplist->ps_count > 2) {
+ if ((newblock = calloc(1, sizeof(*newblock)))
+ == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ TAILQ_INIT(&newblock->sb_rules);
+ for (i = 0; i < PF_SKIP_COUNT; i++)
+ TAILQ_INIT(&newblock->sb_skipsteps[i]);
+ TAILQ_INSERT_BEFORE(block, newblock, sb_entry);
+ DEBUG("(%d) splitting off %d rules from superblock @ #%d",
+ depth, skiplist->ps_count,
+ TAILQ_FIRST(&skiplist->ps_rules)->
+ por_rule.nr);
+ } else {
+ newblock = block;
+ }
+
+ while ((por = TAILQ_FIRST(&skiplist->ps_rules))) {
+ TAILQ_REMOVE(&head, por, por_entry);
+ TAILQ_REMOVE(&skiplist->ps_rules, por,
+ por_skip_entry[largest_list]);
+ TAILQ_INSERT_TAIL(&newblock->sb_rules, por,
+ por_entry);
+
+ /* Remove this rule from all other skiplists */
+ remove_from_skipsteps(&block->sb_skipsteps[
+ largest_list], block, por, skiplist);
+ }
+ free(skiplist);
+ if (newblock != block)
+ if (reorder_rules(pf, newblock, depth + 1))
+ return (1);
+ }
+ }
+
+done:
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) {
+ TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist,
+ ps_entry);
+ free(skiplist);
+ }
+ }
+
+ return (0);
+}
+
+
+/*
+ * Optimization pass #4: re-order 'quick' rules based on feedback from the
+ * currently running ruleset
+ */
+int
+block_feedback(struct pfctl *pf, struct superblock *block)
+{
+ TAILQ_HEAD( , pf_opt_rule) queue;
+ struct pf_opt_rule *por1, *por2;
+ u_int64_t total_count = 0;
+ struct pf_rule a, b;
+
+
+ /*
+ * Walk through all of the profiled superblock's rules and copy
+ * the counters onto our rules.
+ */
+ TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) {
+ comparable_rule(&a, &por1->por_rule, DC);
+ total_count += por1->por_rule.packets[0] +
+ por1->por_rule.packets[1];
+ TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
+ if (por2->por_profile_count)
+ continue;
+ comparable_rule(&b, &por2->por_rule, DC);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ por2->por_profile_count =
+ por1->por_rule.packets[0] +
+ por1->por_rule.packets[1];
+ break;
+ }
+ }
+ }
+ superblock_free(pf, block->sb_profiled_block);
+ block->sb_profiled_block = NULL;
+
+ /*
+ * Now we pull all of the rules off the superblock and re-insert them
+ * in sorted order.
+ */
+
+ TAILQ_INIT(&queue);
+ while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) {
+ TAILQ_REMOVE(&block->sb_rules, por1, por_entry);
+ TAILQ_INSERT_TAIL(&queue, por1, por_entry);
+ }
+
+ while ((por1 = TAILQ_FIRST(&queue)) != NULL) {
+ TAILQ_REMOVE(&queue, por1, por_entry);
+/* XXX I should sort all of the unused rules based on skip steps */
+ TAILQ_FOREACH(por2, &block->sb_rules, por_entry) {
+ if (por1->por_profile_count > por2->por_profile_count) {
+ TAILQ_INSERT_BEFORE(por2, por1, por_entry);
+ break;
+ }
+ }
+#ifdef __FreeBSD__
+ if (por2 == NULL)
+#else
+ if (por2 == TAILQ_END(&block->sb_rules))
+#endif
+ TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Load the current ruleset from the kernel and try to associate them with
+ * the ruleset we're optimizing.
+ */
+int
+load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks)
+{
+ struct superblock *block, *blockcur;
+ struct superblocks prof_superblocks;
+ struct pf_opt_rule *por;
+ struct pf_opt_queue queue;
+ struct pfioc_rule pr;
+ struct pf_rule a, b;
+ int nr, mnr;
+
+ TAILQ_INIT(&queue);
+ TAILQ_INIT(&prof_superblocks);
+
+ memset(&pr, 0, sizeof(pr));
+ pr.rule.action = PF_PASS;
+ if (ioctl(pf->dev, DIOCGETRULES, &pr)) {
+ warn("DIOCGETRULES");
+ return (1);
+ }
+ mnr = pr.nr;
+
+ DEBUG("Loading %d active rules for a feedback profile", mnr);
+ for (nr = 0; nr < mnr; ++nr) {
+ struct pf_ruleset *rs;
+ if ((por = calloc(1, sizeof(*por))) == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ pr.nr = nr;
+ if (ioctl(pf->dev, DIOCGETRULE, &pr)) {
+ warn("DIOCGETRULES");
+ return (1);
+ }
+ memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule));
+ rs = pf_find_or_create_ruleset(pr.anchor_call);
+ por->por_rule.anchor = rs->anchor;
+ if (TAILQ_EMPTY(&por->por_rule.rpool.list))
+ memset(&por->por_rule.rpool, 0,
+ sizeof(por->por_rule.rpool));
+ TAILQ_INSERT_TAIL(&queue, por, por_entry);
+
+ /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket,
+ * PF_PASS, pf->anchor) ???
+ * ... pfctl_clear_pool(&pr.rule.rpool)
+ */
+ }
+
+ if (construct_superblocks(pf, &queue, &prof_superblocks))
+ return (1);
+
+
+ /*
+ * Now we try to associate the active ruleset's superblocks with
+ * the superblocks we're compiling.
+ */
+ block = TAILQ_FIRST(superblocks);
+ blockcur = TAILQ_FIRST(&prof_superblocks);
+ while (block && blockcur) {
+ comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule,
+ BREAK);
+ comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule,
+ BREAK);
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ /* The two superblocks lined up */
+ block->sb_profiled_block = blockcur;
+ } else {
+ DEBUG("superblocks don't line up between #%d and #%d",
+ TAILQ_FIRST(&block->sb_rules)->por_rule.nr,
+ TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr);
+ break;
+ }
+ block = TAILQ_NEXT(block, sb_entry);
+ blockcur = TAILQ_NEXT(blockcur, sb_entry);
+ }
+
+
+
+ /* Free any superblocks we couldn't link */
+ while (blockcur) {
+ block = TAILQ_NEXT(blockcur, sb_entry);
+ superblock_free(pf, blockcur);
+ blockcur = block;
+ }
+ return (0);
+}
+
+
+/*
+ * Compare a rule to a skiplist to see if the rule is a member
+ */
+int
+skip_compare(int skipnum, struct pf_skip_step *skiplist,
+ struct pf_opt_rule *por)
+{
+ struct pf_rule *a, *b;
+ if (skipnum >= PF_SKIP_COUNT || skipnum < 0)
+ errx(1, "skip_compare() out of bounds");
+ a = &por->por_rule;
+ b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule;
+
+ return ((skip_comparitors[skipnum])(a, b));
+}
+
+
+/*
+ * Add a rule to a skiplist
+ */
+void
+skip_append(struct superblock *superblock, int skipnum,
+ struct pf_skip_step *skiplist, struct pf_opt_rule *por)
+{
+ struct pf_skip_step *prev;
+
+ skiplist->ps_count++;
+ TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]);
+
+ /* Keep the list of skiplists sorted by whichever is larger */
+ while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) &&
+ prev->ps_count < skiplist->ps_count) {
+ TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum],
+ skiplist, ps_entry);
+ TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry);
+ }
+}
+
+
+/*
+ * Remove a rule from the other skiplist calculations.
+ */
+void
+remove_from_skipsteps(struct skiplist *head, struct superblock *block,
+ struct pf_opt_rule *por, struct pf_skip_step *active_list)
+{
+ struct pf_skip_step *sk, *next;
+ struct pf_opt_rule *p2;
+ int i, found;
+
+ for (i = 0; i < PF_SKIP_COUNT; i++) {
+ sk = TAILQ_FIRST(&block->sb_skipsteps[i]);
+ if (sk == NULL || sk == active_list || sk->ps_count <= 1)
+ continue;
+ found = 0;
+ do {
+ TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i])
+ if (p2 == por) {
+ TAILQ_REMOVE(&sk->ps_rules, p2,
+ por_skip_entry[i]);
+ found = 1;
+ sk->ps_count--;
+ break;
+ }
+ } while (!found && (sk = TAILQ_NEXT(sk, ps_entry)));
+ if (found && sk) {
+ /* Does this change the sorting order? */
+ while ((next = TAILQ_NEXT(sk, ps_entry)) &&
+ next->ps_count > sk->ps_count) {
+ TAILQ_REMOVE(head, sk, ps_entry);
+ TAILQ_INSERT_AFTER(head, next, sk, ps_entry);
+ }
+#ifdef OPT_DEBUG
+ next = TAILQ_NEXT(sk, ps_entry);
+ assert(next == NULL || next->ps_count <= sk->ps_count);
+#endif /* OPT_DEBUG */
+ }
+ }
+}
+
+
+/* Compare two rules AF field for skiplist construction */
+int
+skip_cmp_af(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->af != b->af || a->af == 0)
+ return (1);
+ return (0);
+}
+
+/* Compare two rules DIRECTION field for skiplist construction */
+int
+skip_cmp_dir(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->direction == 0 || a->direction != b->direction)
+ return (1);
+ return (0);
+}
+
+/* Compare two rules DST Address field for skiplist construction */
+int
+skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->dst.neg != b->dst.neg ||
+ a->dst.addr.type != b->dst.addr.type)
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ switch (a->dst.addr.type) {
+ case PF_ADDR_ADDRMASK:
+ if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr,
+ sizeof(a->dst.addr.v.a.addr)) ||
+ memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
+ sizeof(a->dst.addr.v.a.mask)) ||
+ (a->dst.addr.v.a.addr.addr32[0] == 0 &&
+ a->dst.addr.v.a.addr.addr32[1] == 0 &&
+ a->dst.addr.v.a.addr.addr32[2] == 0 &&
+ a->dst.addr.v.a.addr.addr32[3] == 0))
+ return (1);
+ return (0);
+ case PF_ADDR_DYNIFTL:
+ if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 ||
+ a->dst.addr.iflags != a->dst.addr.iflags ||
+ memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask,
+ sizeof(a->dst.addr.v.a.mask)))
+ return (1);
+ return (0);
+ case PF_ADDR_NOROUTE:
+ case PF_ADDR_URPFFAILED:
+ return (0);
+ case PF_ADDR_TABLE:
+ return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname));
+ }
+ return (1);
+}
+
+/* Compare two rules DST port field for skiplist construction */
+int
+skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b)
+{
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op ||
+ a->dst.port[0] != b->dst.port[0] ||
+ a->dst.port[1] != b->dst.port[1])
+ return (1);
+ return (0);
+}
+
+/* Compare two rules IFP field for skiplist construction */
+int
+skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b)
+{
+ if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0')
+ return (1);
+ return (a->ifnot != b->ifnot);
+}
+
+/* Compare two rules PROTO field for skiplist construction */
+int
+skip_cmp_proto(struct pf_rule *a, struct pf_rule *b)
+{
+ return (a->proto != b->proto || a->proto == 0);
+}
+
+/* Compare two rules SRC addr field for skiplist construction */
+int
+skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->src.neg != b->src.neg ||
+ a->src.addr.type != b->src.addr.type)
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ switch (a->src.addr.type) {
+ case PF_ADDR_ADDRMASK:
+ if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr,
+ sizeof(a->src.addr.v.a.addr)) ||
+ memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
+ sizeof(a->src.addr.v.a.mask)) ||
+ (a->src.addr.v.a.addr.addr32[0] == 0 &&
+ a->src.addr.v.a.addr.addr32[1] == 0 &&
+ a->src.addr.v.a.addr.addr32[2] == 0 &&
+ a->src.addr.v.a.addr.addr32[3] == 0))
+ return (1);
+ return (0);
+ case PF_ADDR_DYNIFTL:
+ if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 ||
+ a->src.addr.iflags != a->src.addr.iflags ||
+ memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask,
+ sizeof(a->src.addr.v.a.mask)))
+ return (1);
+ return (0);
+ case PF_ADDR_NOROUTE:
+ case PF_ADDR_URPFFAILED:
+ return (0);
+ case PF_ADDR_TABLE:
+ return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname));
+ }
+ return (1);
+}
+
+/* Compare two rules SRC port field for skiplist construction */
+int
+skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b)
+{
+ if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op ||
+ a->src.port[0] != b->src.port[0] ||
+ a->src.port[1] != b->src.port[1])
+ return (1);
+ /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0
+ * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP ||
+ * a->proto == IPPROTO_ICMP
+ * return (1);
+ */
+ return (0);
+}
+
+
+void
+skip_init(void)
+{
+ struct {
+ char *name;
+ int skipnum;
+ int (*func)(struct pf_rule *, struct pf_rule *);
+ } comps[] = PF_SKIP_COMPARITORS;
+ int skipnum, i;
+
+ for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) {
+ for (i = 0; i < sizeof(comps)/sizeof(*comps); i++)
+ if (comps[i].skipnum == skipnum) {
+ skip_comparitors[skipnum] = comps[i].func;
+ skip_comparitors_names[skipnum] = comps[i].name;
+ }
+ }
+ for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++)
+ if (skip_comparitors[skipnum] == NULL)
+ errx(1, "Need to add skip step comparitor to pfctl?!");
+}
+
+/*
+ * Add a host/netmask to a table
+ */
+#ifdef __rtems__
+static int add_opt_tablenum = 0;
+#endif /* __rtems__ */
+int
+add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af,
+ struct pf_rule_addr *addr)
+{
+#ifdef OPT_DEBUG
+ char buf[128];
+#endif /* OPT_DEBUG */
+#ifndef __rtems__
+ static int tablenum = 0;
+#endif /* __rtems__ */
+ struct node_host node_host;
+
+ if (*tbl == NULL) {
+ if ((*tbl = calloc(1, sizeof(**tbl))) == NULL ||
+ ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) ==
+ NULL)
+ err(1, "calloc");
+ (*tbl)->pt_buf->pfrb_type = PFRB_ADDRS;
+ SIMPLEQ_INIT(&(*tbl)->pt_nodes);
+
+ /* This is just a temporary table name */
+ snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d",
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, tablenum++);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, add_opt_tablenum++);
+#endif /* __rtems__ */
+ DEBUG("creating table <%s>", (*tbl)->pt_name);
+ }
+
+ memset(&node_host, 0, sizeof(node_host));
+ node_host.af = af;
+ node_host.addr = addr->addr;
+
+#ifdef OPT_DEBUG
+ DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af,
+ &node_host.addr.v.a.addr, buf, sizeof(buf)),
+ unmask(&node_host.addr.v.a.mask, af));
+#endif /* OPT_DEBUG */
+
+ if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) {
+ warn("failed to add host");
+ return (1);
+ }
+ if (pf->opts & PF_OPT_VERBOSE) {
+ struct node_tinit *ti;
+
+ if ((ti = calloc(1, sizeof(*ti))) == NULL)
+ err(1, "malloc");
+ if ((ti->host = malloc(sizeof(*ti->host))) == NULL)
+ err(1, "malloc");
+ memcpy(ti->host, &node_host, sizeof(*ti->host));
+ SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries);
+ }
+
+ (*tbl)->pt_rulecount++;
+ if ((*tbl)->pt_rulecount == TABLE_THRESHOLD)
+ DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name);
+
+ return (0);
+}
+
+
+/*
+ * Do the dirty work of choosing an unused table name and creating it.
+ * (be careful with the table name, it might already be used in another anchor)
+ */
+#ifdef __rtems__
+static int pf_opt_create_tablenum;
+#endif /* __rtems__ */
+int
+pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl)
+{
+#ifndef __rtems__
+ static int tablenum;
+#endif /* __rtems__ */
+ struct pfr_table *t;
+
+ if (table_buffer.pfrb_type == 0) {
+ /* Initialize the list of tables */
+ table_buffer.pfrb_type = PFRB_TABLES;
+ for (;;) {
+ pfr_buf_grow(&table_buffer, table_buffer.pfrb_size);
+ table_buffer.pfrb_size = table_buffer.pfrb_msize;
+ if (pfr_get_tables(NULL, table_buffer.pfrb_caddr,
+ &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS))
+ err(1, "pfr_get_tables");
+ if (table_buffer.pfrb_size <= table_buffer.pfrb_msize)
+ break;
+ }
+ table_identifier = arc4random();
+ }
+
+ /* XXX would be *really* nice to avoid duplicating identical tables */
+
+ /* Now we have to pick a table name that isn't used */
+again:
+ DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name,
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum);
+#endif /* __rtems__ */
+ snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d",
+#ifndef __rtems__
+ PF_OPT_TABLE_PREFIX, table_identifier, tablenum);
+#else /* __rtems__ */
+ PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum);
+#endif /* __rtems__ */
+ PFRB_FOREACH(t, &table_buffer) {
+ if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) {
+ /* Collision. Try again */
+ DEBUG("wow, table <%s> in use. trying again",
+ tbl->pt_name);
+ table_identifier = arc4random();
+ goto again;
+ }
+ }
+#ifndef __rtems__
+ tablenum++;
+#else /* __rtems__ */
+ pf_opt_create_tablenum++;
+#endif /* __rtems__ */
+
+
+ if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1,
+ pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) {
+ warn("failed to create table %s in %s",
+ tbl->pt_name, pf->astack[0]->name);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Partition the flat ruleset into a list of distinct superblocks
+ */
+int
+construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue,
+ struct superblocks *superblocks)
+{
+ struct superblock *block = NULL;
+ struct pf_opt_rule *por;
+ int i;
+
+ while (!TAILQ_EMPTY(opt_queue)) {
+ por = TAILQ_FIRST(opt_queue);
+ TAILQ_REMOVE(opt_queue, por, por_entry);
+ if (block == NULL || !superblock_inclusive(block, por)) {
+ if ((block = calloc(1, sizeof(*block))) == NULL) {
+ warn("calloc");
+ return (1);
+ }
+ TAILQ_INIT(&block->sb_rules);
+ for (i = 0; i < PF_SKIP_COUNT; i++)
+ TAILQ_INIT(&block->sb_skipsteps[i]);
+ TAILQ_INSERT_TAIL(superblocks, block, sb_entry);
+ }
+ TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Compare two rule addresses
+ */
+int
+addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b)
+{
+ if (a->neg != b->neg)
+ return (0);
+ return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0);
+}
+
+
+/*
+ * The addresses are not equal, but can we combine them into one table?
+ */
+int
+addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b)
+{
+ if (a->addr.type != PF_ADDR_ADDRMASK ||
+ b->addr.type != PF_ADDR_ADDRMASK)
+ return (0);
+ if (a->neg != b->neg || a->port_op != b->port_op ||
+ a->port[0] != b->port[0] || a->port[1] != b->port[1])
+ return (0);
+ return (1);
+}
+
+
+/*
+ * Are we allowed to combine these two rules
+ */
+int
+rules_combineable(struct pf_rule *p1, struct pf_rule *p2)
+{
+ struct pf_rule a, b;
+
+ comparable_rule(&a, p1, COMBINED);
+ comparable_rule(&b, p2, COMBINED);
+ return (memcmp(&a, &b, sizeof(a)) == 0);
+}
+
+
+/*
+ * Can a rule be included inside a superblock
+ */
+int
+superblock_inclusive(struct superblock *block, struct pf_opt_rule *por)
+{
+ struct pf_rule a, b;
+ int i, j;
+
+ /* First check for hard breaks */
+ for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) {
+ if (pf_rule_desc[i].prf_type == BARRIER) {
+ for (j = 0; j < pf_rule_desc[i].prf_size; j++)
+ if (((char *)&por->por_rule)[j +
+ pf_rule_desc[i].prf_offset] != 0)
+ return (0);
+ }
+ }
+
+ /* per-rule src-track is also a hard break */
+ if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK)
+ return (0);
+
+ /*
+ * Have to handle interface groups separately. Consider the following
+ * rules:
+ * block on EXTIFS to any port 22
+ * pass on em0 to any port 22
+ * (where EXTIFS is an arbitrary interface group)
+ * The optimizer may decide to re-order the pass rule in front of the
+ * block rule. But what if EXTIFS includes em0??? Such a reordering
+ * would change the meaning of the ruleset.
+ * We can't just lookup the EXTIFS group and check if em0 is a member
+ * because the user is allowed to add interfaces to a group during
+ * runtime.
+ * Ergo interface groups become a defacto superblock break :-(
+ */
+ if (interface_group(por->por_rule.ifname) ||
+ interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) {
+ if (strcasecmp(por->por_rule.ifname,
+ TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0)
+ return (0);
+ }
+
+ comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE);
+ comparable_rule(&b, &por->por_rule, NOMERGE);
+ if (memcmp(&a, &b, sizeof(a)) == 0)
+ return (1);
+
+#ifdef OPT_DEBUG
+ for (i = 0; i < sizeof(por->por_rule); i++) {
+ int closest = -1;
+ if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) {
+ for (j = 0; j < sizeof(pf_rule_desc) /
+ sizeof(*pf_rule_desc); j++) {
+ if (i >= pf_rule_desc[j].prf_offset &&
+ i < pf_rule_desc[j].prf_offset +
+ pf_rule_desc[j].prf_size) {
+ DEBUG("superblock break @ %d due to %s",
+ por->por_rule.nr,
+ pf_rule_desc[j].prf_name);
+ return (0);
+ }
+ if (i > pf_rule_desc[j].prf_offset) {
+ if (closest == -1 ||
+ i-pf_rule_desc[j].prf_offset <
+ i-pf_rule_desc[closest].prf_offset)
+ closest = j;
+ }
+ }
+
+ if (closest >= 0)
+ DEBUG("superblock break @ %d on %s+%xh",
+ por->por_rule.nr,
+ pf_rule_desc[closest].prf_name,
+ i - pf_rule_desc[closest].prf_offset -
+ pf_rule_desc[closest].prf_size);
+ else
+ DEBUG("superblock break @ %d on field @ %d",
+ por->por_rule.nr, i);
+ return (0);
+ }
+ }
+#endif /* OPT_DEBUG */
+
+ return (0);
+}
+
+
+/*
+ * Figure out if an interface name is an actual interface or actually a
+ * group of interfaces.
+ */
+int
+interface_group(const char *ifname)
+{
+ if (ifname == NULL || !ifname[0])
+ return (0);
+
+ /* Real interfaces must end in a number, interface groups do not */
+ if (isdigit(ifname[strlen(ifname) - 1]))
+ return (0);
+ else
+ return (1);
+}
+
+
+/*
+ * Make a rule that can directly compared by memcmp()
+ */
+void
+comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type)
+{
+ int i;
+ /*
+ * To simplify the comparison, we just zero out the fields that are
+ * allowed to be different and then do a simple memcmp()
+ */
+ memcpy(dst, src, sizeof(*dst));
+ for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++)
+ if (pf_rule_desc[i].prf_type >= type) {
+#ifdef OPT_DEBUG
+ assert(pf_rule_desc[i].prf_type != NEVER ||
+ *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0);
+#endif /* OPT_DEBUG */
+ memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0,
+ pf_rule_desc[i].prf_size);
+ }
+}
+
+
+/*
+ * Remove superset information from two rules so we can directly compare them
+ * with memcmp()
+ */
+void
+exclude_supersets(struct pf_rule *super, struct pf_rule *sub)
+{
+ if (super->ifname[0] == '\0')
+ memset(sub->ifname, 0, sizeof(sub->ifname));
+ if (super->direction == PF_INOUT)
+ sub->direction = PF_INOUT;
+ if ((super->proto == 0 || super->proto == sub->proto) &&
+ super->flags == 0 && super->flagset == 0 && (sub->flags ||
+ sub->flagset)) {
+ sub->flags = super->flags;
+ sub->flagset = super->flagset;
+ }
+ if (super->proto == 0)
+ sub->proto = 0;
+
+ if (super->src.port_op == 0) {
+ sub->src.port_op = 0;
+ sub->src.port[0] = 0;
+ sub->src.port[1] = 0;
+ }
+ if (super->dst.port_op == 0) {
+ sub->dst.port_op = 0;
+ sub->dst.port[0] = 0;
+ sub->dst.port[1] = 0;
+ }
+
+ if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg &&
+ !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 &&
+ super->src.addr.v.a.mask.addr32[1] == 0 &&
+ super->src.addr.v.a.mask.addr32[2] == 0 &&
+ super->src.addr.v.a.mask.addr32[3] == 0)
+ memset(&sub->src.addr, 0, sizeof(sub->src.addr));
+ else if (super->src.addr.type == PF_ADDR_ADDRMASK &&
+ sub->src.addr.type == PF_ADDR_ADDRMASK &&
+ super->src.neg == sub->src.neg &&
+ super->af == sub->af &&
+ unmask(&super->src.addr.v.a.mask, super->af) <
+ unmask(&sub->src.addr.v.a.mask, sub->af) &&
+ super->src.addr.v.a.addr.addr32[0] ==
+ (sub->src.addr.v.a.addr.addr32[0] &
+ super->src.addr.v.a.mask.addr32[0]) &&
+ super->src.addr.v.a.addr.addr32[1] ==
+ (sub->src.addr.v.a.addr.addr32[1] &
+ super->src.addr.v.a.mask.addr32[1]) &&
+ super->src.addr.v.a.addr.addr32[2] ==
+ (sub->src.addr.v.a.addr.addr32[2] &
+ super->src.addr.v.a.mask.addr32[2]) &&
+ super->src.addr.v.a.addr.addr32[3] ==
+ (sub->src.addr.v.a.addr.addr32[3] &
+ super->src.addr.v.a.mask.addr32[3])) {
+ /* sub->src.addr is a subset of super->src.addr/mask */
+ memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr));
+ }
+
+ if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg &&
+ !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 &&
+ super->dst.addr.v.a.mask.addr32[1] == 0 &&
+ super->dst.addr.v.a.mask.addr32[2] == 0 &&
+ super->dst.addr.v.a.mask.addr32[3] == 0)
+ memset(&sub->dst.addr, 0, sizeof(sub->dst.addr));
+ else if (super->dst.addr.type == PF_ADDR_ADDRMASK &&
+ sub->dst.addr.type == PF_ADDR_ADDRMASK &&
+ super->dst.neg == sub->dst.neg &&
+ super->af == sub->af &&
+ unmask(&super->dst.addr.v.a.mask, super->af) <
+ unmask(&sub->dst.addr.v.a.mask, sub->af) &&
+ super->dst.addr.v.a.addr.addr32[0] ==
+ (sub->dst.addr.v.a.addr.addr32[0] &
+ super->dst.addr.v.a.mask.addr32[0]) &&
+ super->dst.addr.v.a.addr.addr32[1] ==
+ (sub->dst.addr.v.a.addr.addr32[1] &
+ super->dst.addr.v.a.mask.addr32[1]) &&
+ super->dst.addr.v.a.addr.addr32[2] ==
+ (sub->dst.addr.v.a.addr.addr32[2] &
+ super->dst.addr.v.a.mask.addr32[2]) &&
+ super->dst.addr.v.a.addr.addr32[3] ==
+ (sub->dst.addr.v.a.addr.addr32[3] &
+ super->dst.addr.v.a.mask.addr32[3])) {
+ /* sub->dst.addr is a subset of super->dst.addr/mask */
+ memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr));
+ }
+
+ if (super->af == 0)
+ sub->af = 0;
+}
+
+
+void
+superblock_free(struct pfctl *pf, struct superblock *block)
+{
+ struct pf_opt_rule *por;
+ while ((por = TAILQ_FIRST(&block->sb_rules))) {
+ TAILQ_REMOVE(&block->sb_rules, por, por_entry);
+ if (por->por_src_tbl) {
+ if (por->por_src_tbl->pt_buf) {
+ pfr_buf_clear(por->por_src_tbl->pt_buf);
+ free(por->por_src_tbl->pt_buf);
+ }
+ free(por->por_src_tbl);
+ }
+ if (por->por_dst_tbl) {
+ if (por->por_dst_tbl->pt_buf) {
+ pfr_buf_clear(por->por_dst_tbl->pt_buf);
+ free(por->por_dst_tbl->pt_buf);
+ }
+ free(por->por_dst_tbl);
+ }
+ free(por);
+ }
+ if (block->sb_profiled_block)
+ superblock_free(pf, block->sb_profiled_block);
+ free(block);
+}
+
diff --git a/freebsd/sbin/pfctl/pfctl_osfp.c b/freebsd/sbin/pfctl/pfctl_osfp.c
new file mode 100644
index 00000000..dd672623
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_osfp.c
@@ -0,0 +1,1123 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */
+
+/*
+ * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_osfp-data.h"
+#endif /* __rtems__ */
+
+#ifndef MIN
+# define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+#ifndef MAX
+# define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+
+#if 0
+# define DEBUG(fp, str, v...) \
+ fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \
+ (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v);
+#else
+# define DEBUG(fp, str, v...) ((void)0)
+#endif
+
+
+struct name_entry;
+LIST_HEAD(name_list, name_entry);
+struct name_entry {
+ LIST_ENTRY(name_entry) nm_entry;
+ int nm_num;
+ char nm_name[PF_OSFP_LEN];
+
+ struct name_list nm_sublist;
+ int nm_sublist_num;
+};
+static struct name_list classes = LIST_HEAD_INITIALIZER(&classes);
+static int class_count;
+static int fingerprint_count;
+
+void add_fingerprint(int, int, struct pf_osfp_ioctl *);
+struct name_entry *fingerprint_name_entry(struct name_list *, char *);
+void pfctl_flush_my_fingerprints(struct name_list *);
+char *get_field(char **, size_t *, int *);
+int get_int(char **, size_t *, int *, int *, const char *,
+ int, int, const char *, int);
+int get_str(char **, size_t *, char **, const char *, int,
+ const char *, int);
+int get_tcpopts(const char *, int, const char *,
+ pf_tcpopts_t *, int *, int *, int *, int *, int *,
+ int *);
+void import_fingerprint(struct pf_osfp_ioctl *);
+const char *print_ioctl(struct pf_osfp_ioctl *);
+void print_name_list(int, struct name_list *, const char *);
+void sort_name_list(int, struct name_list *);
+struct name_entry *lookup_name_list(struct name_list *, const char *);
+
+/* Load fingerprints from a file */
+int
+pfctl_file_fingerprints(int dev, int opts, const char *fp_filename)
+{
+ FILE *in;
+ char *line;
+ size_t len;
+ int i, lineno = 0;
+ int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale,
+ wscale_mod, optcnt, ts0;
+ pf_tcpopts_t packed_tcpopts;
+ char *class, *version, *subtype, *desc, *tcpopts;
+ struct pf_osfp_ioctl fp;
+
+ pfctl_flush_my_fingerprints(&classes);
+
+ if ((in = pfctl_fopen(fp_filename, "r")) == NULL) {
+ warn("%s", fp_filename);
+ return (1);
+ }
+ class = version = subtype = desc = tcpopts = NULL;
+
+ if ((opts & PF_OPT_NOACTION) == 0)
+ pfctl_clear_fingerprints(dev, opts);
+
+ while ((line = fgetln(in, &len)) != NULL) {
+ lineno++;
+ if (class)
+ free(class);
+ if (version)
+ free(version);
+ if (subtype)
+ free(subtype);
+ if (desc)
+ free(desc);
+ if (tcpopts)
+ free(tcpopts);
+ class = version = subtype = desc = tcpopts = NULL;
+ memset(&fp, 0, sizeof(fp));
+
+ /* Chop off comment */
+ for (i = 0; i < len; i++)
+ if (line[i] == '#') {
+ len = i;
+ break;
+ }
+ /* Chop off whitespace */
+ while (len > 0 && isspace(line[len - 1]))
+ len--;
+ while (len > 0 && isspace(line[0])) {
+ len--;
+ line++;
+ }
+ if (len == 0)
+ continue;
+
+#define T_DC 0x01 /* Allow don't care */
+#define T_MSS 0x02 /* Allow MSS multiple */
+#define T_MTU 0x04 /* Allow MTU multiple */
+#define T_MOD 0x08 /* Allow modulus */
+
+#define GET_INT(v, mod, n, ty, mx) \
+ get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno)
+#define GET_STR(v, n, mn) \
+ get_str(&line, &len, &v, n, mn, fp_filename, lineno)
+
+ if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU|
+ T_MOD, 0xffff) ||
+ GET_INT(ttl, NULL, "ttl", 0, 0xff) ||
+ GET_INT(df, NULL, "don't fragment frag", 0, 1) ||
+ GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC,
+ 8192) ||
+ GET_STR(tcpopts, "TCP Options", 1) ||
+ GET_STR(class, "OS class", 1) ||
+ GET_STR(version, "OS version", 0) ||
+ GET_STR(subtype, "OS subtype", 0) ||
+ GET_STR(desc, "OS description", 2))
+ continue;
+ if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts,
+ &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0))
+ continue;
+ if (len != 0) {
+ fprintf(stderr, "%s:%d excess field\n", fp_filename,
+ lineno);
+ continue;
+ }
+
+ fp.fp_ttl = ttl;
+ if (df)
+ fp.fp_flags |= PF_OSFP_DF;
+ switch (w_mod) {
+ case 0:
+ break;
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_WSIZE_DC;
+ break;
+ case T_MSS:
+ fp.fp_flags |= PF_OSFP_WSIZE_MSS;
+ break;
+ case T_MTU:
+ fp.fp_flags |= PF_OSFP_WSIZE_MTU;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_WSIZE_MOD;
+ break;
+ }
+ fp.fp_wsize = window;
+
+ switch (p_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_PSIZE_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_PSIZE_MOD;
+ }
+ fp.fp_psize = psize;
+
+
+ switch (wscale_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_WSCALE_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_WSCALE_MOD;
+ }
+ fp.fp_wscale = wscale;
+
+ switch (mss_mod) {
+ case T_DC:
+ fp.fp_flags |= PF_OSFP_MSS_DC;
+ break;
+ case T_MOD:
+ fp.fp_flags |= PF_OSFP_MSS_MOD;
+ break;
+ }
+ fp.fp_mss = mss;
+
+ fp.fp_tcpopts = packed_tcpopts;
+ fp.fp_optcnt = optcnt;
+ if (ts0)
+ fp.fp_flags |= PF_OSFP_TS0;
+
+ if (class[0] == '@')
+ fp.fp_os.fp_enflags |= PF_OSFP_GENERIC;
+ if (class[0] == '*')
+ fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL;
+
+ if (class[0] == '@' || class[0] == '*')
+ strlcpy(fp.fp_os.fp_class_nm, class + 1,
+ sizeof(fp.fp_os.fp_class_nm));
+ else
+ strlcpy(fp.fp_os.fp_class_nm, class,
+ sizeof(fp.fp_os.fp_class_nm));
+ strlcpy(fp.fp_os.fp_version_nm, version,
+ sizeof(fp.fp_os.fp_version_nm));
+ strlcpy(fp.fp_os.fp_subtype_nm, subtype,
+ sizeof(fp.fp_os.fp_subtype_nm));
+
+ add_fingerprint(dev, opts, &fp);
+
+ fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6);
+ fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip);
+ add_fingerprint(dev, opts, &fp);
+ }
+
+ if (class)
+ free(class);
+ if (version)
+ free(version);
+ if (subtype)
+ free(subtype);
+ if (desc)
+ free(desc);
+ if (tcpopts)
+ free(tcpopts);
+
+ fclose(in);
+
+ if (opts & PF_OPT_VERBOSE2)
+ printf("Loaded %d passive OS fingerprints\n",
+ fingerprint_count);
+ return (0);
+}
+
+/* flush the kernel's fingerprints */
+void
+pfctl_clear_fingerprints(int dev, int opts)
+{
+ if (ioctl(dev, DIOCOSFPFLUSH))
+ err(1, "DIOCOSFPFLUSH");
+}
+
+/* flush pfctl's view of the fingerprints */
+void
+pfctl_flush_my_fingerprints(struct name_list *list)
+{
+ struct name_entry *nm;
+
+ while ((nm = LIST_FIRST(list)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ pfctl_flush_my_fingerprints(&nm->nm_sublist);
+ free(nm);
+ }
+ fingerprint_count = 0;
+ class_count = 0;
+}
+
+/* Fetch the active fingerprints from the kernel */
+int
+pfctl_load_fingerprints(int dev, int opts)
+{
+ struct pf_osfp_ioctl io;
+ int i;
+
+ pfctl_flush_my_fingerprints(&classes);
+
+ for (i = 0; i >= 0; i++) {
+ memset(&io, 0, sizeof(io));
+ io.fp_getnum = i;
+ if (ioctl(dev, DIOCOSFPGET, &io)) {
+ if (errno == EBUSY)
+ break;
+ warn("DIOCOSFPGET");
+ return (1);
+ }
+ import_fingerprint(&io);
+ }
+ return (0);
+}
+
+/* List the fingerprints */
+void
+pfctl_show_fingerprints(int opts)
+{
+ if (LIST_FIRST(&classes) != NULL) {
+ if (opts & PF_OPT_SHOWALL) {
+ pfctl_print_title("OS FINGERPRINTS:");
+ printf("%u fingerprints loaded\n", fingerprint_count);
+ } else {
+ printf("Class\tVersion\tSubtype(subversion)\n");
+ printf("-----\t-------\t-------------------\n");
+ sort_name_list(opts, &classes);
+ print_name_list(opts, &classes, "");
+ }
+ }
+}
+
+/* Lookup a fingerprint */
+pf_osfp_t
+pfctl_get_fingerprint(const char *name)
+{
+ struct name_entry *nm, *class_nm, *version_nm, *subtype_nm;
+ pf_osfp_t ret = PF_OSFP_NOMATCH;
+ int class, version, subtype;
+ int unp_class, unp_version, unp_subtype;
+ int wr_len, version_len, subtype_len;
+ char *ptr, *wr_name;
+
+ if (strcasecmp(name, "unknown") == 0)
+ return (PF_OSFP_UNKNOWN);
+
+ /* Try most likely no version and no subtype */
+ if ((nm = lookup_name_list(&classes, name))) {
+ class = nm->nm_num;
+ version = PF_OSFP_ANY;
+ subtype = PF_OSFP_ANY;
+ goto found;
+ } else {
+
+ /* Chop it up into class/version/subtype */
+
+ if ((wr_name = strdup(name)) == NULL)
+ err(1, "malloc");
+ if ((ptr = strchr(wr_name, ' ')) == NULL) {
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+ *ptr++ = '\0';
+
+ /* The class is easy to find since it is delimited by a space */
+ if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) {
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+ class = class_nm->nm_num;
+
+ /* Try no subtype */
+ if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr)))
+ {
+ version = version_nm->nm_num;
+ subtype = PF_OSFP_ANY;
+ free(wr_name);
+ goto found;
+ }
+
+
+ /*
+ * There must be a version and a subtype.
+ * We'll do some fuzzy matching to pick up things like:
+ * Linux 2.2.14 (version=2.2 subtype=14)
+ * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE)
+ * Windows 2000 SP2 (version=2000 subtype=SP2)
+ */
+#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-')
+ wr_len = strlen(ptr);
+ LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) {
+ version_len = strlen(version_nm->nm_name);
+ if (wr_len < version_len + 2 ||
+ !CONNECTOR(ptr[version_len]))
+ continue;
+ /* first part of the string must be version */
+ if (strncasecmp(ptr, version_nm->nm_name,
+ version_len))
+ continue;
+
+ LIST_FOREACH(subtype_nm, &version_nm->nm_sublist,
+ nm_entry) {
+ subtype_len = strlen(subtype_nm->nm_name);
+ if (wr_len != version_len + subtype_len + 1)
+ continue;
+
+ /* last part of the string must be subtype */
+ if (strcasecmp(&ptr[version_len+1],
+ subtype_nm->nm_name) != 0)
+ continue;
+
+ /* Found it!! */
+ version = version_nm->nm_num;
+ subtype = subtype_nm->nm_num;
+ free(wr_name);
+ goto found;
+ }
+ }
+
+ free(wr_name);
+ return (PF_OSFP_NOMATCH);
+ }
+
+found:
+ PF_OSFP_PACK(ret, class, version, subtype);
+ if (ret != PF_OSFP_NOMATCH) {
+ PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype);
+ if (class != unp_class) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "classes\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ if (version != unp_version) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "versions\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ if (subtype != unp_subtype) {
+ fprintf(stderr, "warning: fingerprint table overflowed "
+ "subtypes\n");
+ return (PF_OSFP_NOMATCH);
+ }
+ }
+ if (ret == PF_OSFP_ANY) {
+ /* should never happen */
+ fprintf(stderr, "warning: fingerprint packed to 'any'\n");
+ return (PF_OSFP_NOMATCH);
+ }
+
+ return (ret);
+}
+
+/* Lookup a fingerprint name by ID */
+char *
+pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len)
+{
+ int class, version, subtype;
+ struct name_list *list;
+ struct name_entry *nm;
+
+ char *class_name, *version_name, *subtype_name;
+ class_name = version_name = subtype_name = NULL;
+
+ if (fp == PF_OSFP_UNKNOWN) {
+ strlcpy(buf, "unknown", len);
+ return (buf);
+ }
+ if (fp == PF_OSFP_ANY) {
+ strlcpy(buf, "any", len);
+ return (buf);
+ }
+
+ PF_OSFP_UNPACK(fp, class, version, subtype);
+ if (class >= (1 << _FP_CLASS_BITS) ||
+ version >= (1 << _FP_VERSION_BITS) ||
+ subtype >= (1 << _FP_SUBTYPE_BITS)) {
+ warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp);
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+
+ LIST_FOREACH(nm, &classes, nm_entry) {
+ if (nm->nm_num == class) {
+ class_name = nm->nm_name;
+ if (version == PF_OSFP_ANY)
+ goto found;
+ list = &nm->nm_sublist;
+ LIST_FOREACH(nm, list, nm_entry) {
+ if (nm->nm_num == version) {
+ version_name = nm->nm_name;
+ if (subtype == PF_OSFP_ANY)
+ goto found;
+ list = &nm->nm_sublist;
+ LIST_FOREACH(nm, list, nm_entry) {
+ if (nm->nm_num == subtype) {
+ subtype_name =
+ nm->nm_name;
+ goto found;
+ }
+ } /* foreach subtype */
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+ } /* foreach version */
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+ }
+ } /* foreach class */
+
+ strlcpy(buf, "nomatch", len);
+ return (buf);
+
+found:
+ snprintf(buf, len, "%s", class_name);
+ if (version_name) {
+ strlcat(buf, " ", len);
+ strlcat(buf, version_name, len);
+ if (subtype_name) {
+ if (strchr(version_name, ' '))
+ strlcat(buf, " ", len);
+ else if (strchr(version_name, '.') &&
+ isdigit(*subtype_name))
+ strlcat(buf, ".", len);
+ else
+ strlcat(buf, " ", len);
+ strlcat(buf, subtype_name, len);
+ }
+ }
+ return (buf);
+}
+
+/* lookup a name in a list */
+struct name_entry *
+lookup_name_list(struct name_list *list, const char *name)
+{
+ struct name_entry *nm;
+ LIST_FOREACH(nm, list, nm_entry)
+ if (strcasecmp(name, nm->nm_name) == 0)
+ return (nm);
+
+ return (NULL);
+}
+
+
+void
+add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp)
+{
+ struct pf_osfp_ioctl fptmp;
+ struct name_entry *nm_class, *nm_version, *nm_subtype;
+ int class, version, subtype;
+
+/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */
+#define EXPAND(field) do { \
+ int _dot = -1, _start = -1, _end = -1, _i = 0; \
+ /* pick major version out of #.# */ \
+ if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \
+ _dot = fp->field[_i] - '0'; \
+ _i += 2; \
+ } \
+ if (isdigit(fp->field[_i])) \
+ _start = fp->field[_i++] - '0'; \
+ else \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _start = (_start * 10) + fp->field[_i++] - '0'; \
+ if (fp->field[_i++] != '-') \
+ break; \
+ if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \
+ fp->field[_i] - '0' == _dot) \
+ _i += 2; \
+ else if (_dot != -1) \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _end = fp->field[_i++] - '0'; \
+ else \
+ break; \
+ if (isdigit(fp->field[_i])) \
+ _end = (_end * 10) + fp->field[_i++] - '0'; \
+ if (isdigit(fp->field[_i])) \
+ _end = (_end * 10) + fp->field[_i++] - '0'; \
+ if (fp->field[_i] != '\0') \
+ break; \
+ memcpy(&fptmp, fp, sizeof(fptmp)); \
+ for (;_start <= _end; _start++) { \
+ memset(fptmp.field, 0, sizeof(fptmp.field)); \
+ fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \
+ if (_dot == -1) \
+ snprintf(fptmp.field, sizeof(fptmp.field), \
+ "%d", _start); \
+ else \
+ snprintf(fptmp.field, sizeof(fptmp.field), \
+ "%d.%d", _dot, _start); \
+ add_fingerprint(dev, opts, &fptmp); \
+ } \
+} while(0)
+
+ /* We allow "#-#" as a version or subtype and we'll expand it */
+ EXPAND(fp_os.fp_version_nm);
+ EXPAND(fp_os.fp_subtype_nm);
+
+ if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0)
+ errx(1, "fingerprint class \"nomatch\" is reserved");
+
+ version = PF_OSFP_ANY;
+ subtype = PF_OSFP_ANY;
+
+ nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);
+ if (nm_class->nm_num == 0)
+ nm_class->nm_num = ++class_count;
+ class = nm_class->nm_num;
+
+ nm_version = fingerprint_name_entry(&nm_class->nm_sublist,
+ fp->fp_os.fp_version_nm);
+ if (nm_version) {
+ if (nm_version->nm_num == 0)
+ nm_version->nm_num = ++nm_class->nm_sublist_num;
+ version = nm_version->nm_num;
+ nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,
+ fp->fp_os.fp_subtype_nm);
+ if (nm_subtype) {
+ if (nm_subtype->nm_num == 0)
+ nm_subtype->nm_num =
+ ++nm_version->nm_sublist_num;
+ subtype = nm_subtype->nm_num;
+ }
+ }
+
+
+ DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype,
+ print_ioctl(fp));
+
+ PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype);
+ fingerprint_count++;
+
+#ifdef FAKE_PF_KERNEL
+ /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */
+ if ((errno = pf_osfp_add(fp)))
+#else
+ if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp))
+#endif /* FAKE_PF_KERNEL */
+ {
+ if (errno == EEXIST) {
+ warn("Duplicate signature for %s %s %s",
+ fp->fp_os.fp_class_nm,
+ fp->fp_os.fp_version_nm,
+ fp->fp_os.fp_subtype_nm);
+
+ } else {
+ err(1, "DIOCOSFPADD");
+ }
+ }
+}
+
+/* import a fingerprint from the kernel */
+void
+import_fingerprint(struct pf_osfp_ioctl *fp)
+{
+ struct name_entry *nm_class, *nm_version, *nm_subtype;
+ int class, version, subtype;
+
+ PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype);
+
+ nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm);
+ if (nm_class->nm_num == 0) {
+ nm_class->nm_num = class;
+ class_count = MAX(class_count, class);
+ }
+
+ nm_version = fingerprint_name_entry(&nm_class->nm_sublist,
+ fp->fp_os.fp_version_nm);
+ if (nm_version) {
+ if (nm_version->nm_num == 0) {
+ nm_version->nm_num = version;
+ nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num,
+ version);
+ }
+ nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist,
+ fp->fp_os.fp_subtype_nm);
+ if (nm_subtype) {
+ if (nm_subtype->nm_num == 0) {
+ nm_subtype->nm_num = subtype;
+ nm_version->nm_sublist_num =
+ MAX(nm_version->nm_sublist_num, subtype);
+ }
+ }
+ }
+
+
+ fingerprint_count++;
+ DEBUG(fp, "import signature %d:%d:%d", class, version, subtype);
+}
+
+/* Find an entry for a fingerprints class/version/subtype */
+struct name_entry *
+fingerprint_name_entry(struct name_list *list, char *name)
+{
+ struct name_entry *nm_entry;
+
+ if (name == NULL || strlen(name) == 0)
+ return (NULL);
+
+ LIST_FOREACH(nm_entry, list, nm_entry) {
+ if (strcasecmp(nm_entry->nm_name, name) == 0) {
+ /* We'll move this to the front of the list later */
+ LIST_REMOVE(nm_entry, nm_entry);
+ break;
+ }
+ }
+ if (nm_entry == NULL) {
+ nm_entry = calloc(1, sizeof(*nm_entry));
+ if (nm_entry == NULL)
+ err(1, "calloc");
+ LIST_INIT(&nm_entry->nm_sublist);
+ strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name));
+ }
+ LIST_INSERT_HEAD(list, nm_entry, nm_entry);
+ return (nm_entry);
+}
+
+
+void
+print_name_list(int opts, struct name_list *nml, const char *prefix)
+{
+ char newprefix[32];
+ struct name_entry *nm;
+
+ LIST_FOREACH(nm, nml, nm_entry) {
+ snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix,
+ nm->nm_name);
+ printf("%s\n", newprefix);
+ print_name_list(opts, &nm->nm_sublist, newprefix);
+ }
+}
+
+void
+sort_name_list(int opts, struct name_list *nml)
+{
+ struct name_list new;
+ struct name_entry *nm, *nmsearch, *nmlast;
+
+ /* yes yes, it's a very slow sort. so sue me */
+
+ LIST_INIT(&new);
+
+ while ((nm = LIST_FIRST(nml)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ nmlast = NULL;
+ LIST_FOREACH(nmsearch, &new, nm_entry) {
+ if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) {
+ LIST_INSERT_BEFORE(nmsearch, nm, nm_entry);
+ break;
+ }
+ nmlast = nmsearch;
+ }
+ if (nmsearch == NULL) {
+ if (nmlast)
+ LIST_INSERT_AFTER(nmlast, nm, nm_entry);
+ else
+ LIST_INSERT_HEAD(&new, nm, nm_entry);
+ }
+
+ sort_name_list(opts, &nm->nm_sublist);
+ }
+ nmlast = NULL;
+ while ((nm = LIST_FIRST(&new)) != NULL) {
+ LIST_REMOVE(nm, nm_entry);
+ if (nmlast == NULL)
+ LIST_INSERT_HEAD(nml, nm, nm_entry);
+ else
+ LIST_INSERT_AFTER(nmlast, nm, nm_entry);
+ nmlast = nm;
+ }
+}
+
+/* parse the next integer in a formatted config file line */
+int
+get_int(char **line, size_t *len, int *var, int *mod,
+ const char *name, int flags, int max, const char *filename, int lineno)
+{
+ int fieldlen, i;
+ char *field;
+ long val = 0;
+
+ if (mod)
+ *mod = 0;
+ *var = 0;
+
+ field = get_field(line, len, &fieldlen);
+ if (field == NULL)
+ return (1);
+ if (fieldlen == 0) {
+ fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name);
+ return (1);
+ }
+
+ i = 0;
+ if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*')
+ && fieldlen >= 1) {
+ switch (*field) {
+ case 'S':
+ if (mod && (flags & T_MSS))
+ *mod = T_MSS;
+ if (fieldlen == 1)
+ return (0);
+ break;
+ case 'T':
+ if (mod && (flags & T_MTU))
+ *mod = T_MTU;
+ if (fieldlen == 1)
+ return (0);
+ break;
+ case '*':
+ if (fieldlen != 1) {
+ fprintf(stderr, "%s:%d long '%c' %s\n",
+ filename, lineno, *field, name);
+ return (1);
+ }
+ if (mod && (flags & T_DC)) {
+ *mod = T_DC;
+ return (0);
+ }
+ case '%':
+ if (mod && (flags & T_MOD))
+ *mod = T_MOD;
+ if (fieldlen == 1) {
+ fprintf(stderr, "%s:%d modulus %s must have a "
+ "value\n", filename, lineno, name);
+ return (1);
+ }
+ break;
+ }
+ if (mod == NULL || *mod == 0) {
+ fprintf(stderr, "%s:%d does not allow %c' %s\n",
+ filename, lineno, *field, name);
+ return (1);
+ }
+ i++;
+ }
+
+ for (; i < fieldlen; i++) {
+ if (field[i] < '0' || field[i] > '9') {
+ fprintf(stderr, "%s:%d non-digit character in %s\n",
+ filename, lineno, name);
+ return (1);
+ }
+ val = val * 10 + field[i] - '0';
+ if (val < 0) {
+ fprintf(stderr, "%s:%d %s overflowed\n", filename,
+ lineno, name);
+ return (1);
+ }
+ }
+
+ if (val > max) {
+ fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno,
+ name, val, max);
+ return (1);
+ }
+ *var = (int)val;
+
+ return (0);
+}
+
+/* parse the next string in a formatted config file line */
+int
+get_str(char **line, size_t *len, char **v, const char *name, int minlen,
+ const char *filename, int lineno)
+{
+ int fieldlen;
+ char *ptr;
+
+ ptr = get_field(line, len, &fieldlen);
+ if (ptr == NULL)
+ return (1);
+ if (fieldlen < minlen) {
+ fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name);
+ return (1);
+ }
+ if ((*v = malloc(fieldlen + 1)) == NULL) {
+ perror("malloc()");
+ return (1);
+ }
+ memcpy(*v, ptr, fieldlen);
+ (*v)[fieldlen] = '\0';
+
+ return (0);
+}
+
+/* Parse out the TCP opts */
+int
+get_tcpopts(const char *filename, int lineno, const char *tcpopts,
+ pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale,
+ int *wscale_mod, int *ts0)
+{
+ int i, opt;
+
+ *packed = 0;
+ *optcnt = 0;
+ *wscale = 0;
+ *wscale_mod = T_DC;
+ *mss = 0;
+ *mss_mod = T_DC;
+ *ts0 = 0;
+ if (strcmp(tcpopts, ".") == 0)
+ return (0);
+
+ for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) {
+ switch ((opt = toupper(tcpopts[i++]))) {
+ case 'N': /* FALLTHROUGH */
+ case 'S':
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ (opt == 'N' ? PF_OSFP_TCPOPT_NOP :
+ PF_OSFP_TCPOPT_SACK);
+ break;
+ case 'W': /* FALLTHROUGH */
+ case 'M': {
+ int *this_mod, *this;
+
+ if (opt == 'W') {
+ this = wscale;
+ this_mod = wscale_mod;
+ } else {
+ this = mss;
+ this_mod = mss_mod;
+ }
+ *this = 0;
+ *this_mod = 0;
+
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE :
+ PF_OSFP_TCPOPT_MSS);
+ if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' ||
+ tcpopts[i + 1] == ',')) {
+ *this_mod = T_DC;
+ i++;
+ break;
+ }
+
+ if (tcpopts[i] == '%') {
+ *this_mod = T_MOD;
+ i++;
+ }
+ do {
+ if (!isdigit(tcpopts[i])) {
+ fprintf(stderr, "%s:%d unknown "
+ "character '%c' in %c TCP opt\n",
+ filename, lineno, tcpopts[i], opt);
+ return (1);
+ }
+ *this = (*this * 10) + tcpopts[i++] - '0';
+ } while(tcpopts[i] != ',' && tcpopts[i] != '\0');
+ break;
+ }
+ case 'T':
+ if (tcpopts[i] == '0') {
+ *ts0 = 1;
+ i++;
+ }
+ *packed = (*packed << PF_OSFP_TCPOPT_BITS) |
+ PF_OSFP_TCPOPT_TS;
+ break;
+ }
+ (*optcnt) ++;
+ if (tcpopts[i] == '\0')
+ break;
+ if (tcpopts[i] != ',') {
+ fprintf(stderr, "%s:%d unknown option to %c TCP opt\n",
+ filename, lineno, opt);
+ return (1);
+ }
+ i++;
+ }
+
+ return (0);
+}
+
+/* rip the next field ouf of a formatted config file line */
+char *
+get_field(char **line, size_t *len, int *fieldlen)
+{
+ char *ret, *ptr = *line;
+ size_t plen = *len;
+
+
+ while (plen && isspace(*ptr)) {
+ plen--;
+ ptr++;
+ }
+ ret = ptr;
+ *fieldlen = 0;
+
+ for (; plen > 0 && *ptr != ':'; plen--, ptr++)
+ (*fieldlen)++;
+ if (plen) {
+ *line = ptr + 1;
+ *len = plen - 1;
+ } else {
+ *len = 0;
+ }
+ while (*fieldlen && isspace(ret[*fieldlen - 1]))
+ (*fieldlen)--;
+ return (ret);
+}
+
+
+const char *
+print_ioctl(struct pf_osfp_ioctl *fp)
+{
+ static char buf[1024];
+ char tmp[32];
+ int i, opt;
+
+ *buf = '\0';
+ if (fp->fp_flags & PF_OSFP_WSIZE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else if (fp->fp_flags & PF_OSFP_WSIZE_MSS)
+ strlcat(buf, "S", sizeof(buf));
+ else if (fp->fp_flags & PF_OSFP_WSIZE_MTU)
+ strlcat(buf, "T", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_WSIZE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl);
+ strlcat(buf, tmp, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_flags & PF_OSFP_DF)
+ strlcat(buf, "1", sizeof(buf));
+ else
+ strlcat(buf, "0", sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_flags & PF_OSFP_PSIZE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_PSIZE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ if (fp->fp_optcnt == 0)
+ strlcat(buf, ".", sizeof(buf));
+ for (i = fp->fp_optcnt - 1; i >= 0; i--) {
+ opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS);
+ opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1;
+ switch (opt) {
+ case PF_OSFP_TCPOPT_NOP:
+ strlcat(buf, "N", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_SACK:
+ strlcat(buf, "S", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_TS:
+ strlcat(buf, "T", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_TS0)
+ strlcat(buf, "0", sizeof(buf));
+ break;
+ case PF_OSFP_TCPOPT_MSS:
+ strlcat(buf, "M", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_MSS_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_MSS_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ break;
+ case PF_OSFP_TCPOPT_WSCALE:
+ strlcat(buf, "W", sizeof(buf));
+ if (fp->fp_flags & PF_OSFP_WSCALE_DC)
+ strlcat(buf, "*", sizeof(buf));
+ else {
+ if (fp->fp_flags & PF_OSFP_WSCALE_MOD)
+ strlcat(buf, "%", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale);
+ strlcat(buf, tmp, sizeof(buf));
+ }
+ break;
+ }
+
+ if (i != 0)
+ strlcat(buf, ",", sizeof(buf));
+ }
+ strlcat(buf, ":", sizeof(buf));
+
+ strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+ strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+ strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf));
+ strlcat(buf, ":", sizeof(buf));
+
+ snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt,
+ (long long int)fp->fp_tcpopts);
+ strlcat(buf, tmp, sizeof(buf));
+
+ return (buf);
+}
diff --git a/freebsd/sbin/pfctl/pfctl_parser.c b/freebsd/sbin/pfctl/pfctl_parser.c
new file mode 100644
index 00000000..0ff7deec
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_parser.c
@@ -0,0 +1,1780 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * Copyright (c) 2002,2003 Henning Brauer
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/proc.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_parser-data.h"
+#endif /* __rtems__ */
+
+void print_op (u_int8_t, const char *, const char *);
+void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int);
+void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
+void print_flags (u_int8_t);
+void print_fromto(struct pf_rule_addr *, pf_osfp_t,
+ struct pf_rule_addr *, u_int8_t, u_int8_t, int, int);
+int ifa_skip_if(const char *filter, struct node_host *p);
+
+struct node_host *ifa_grouplookup(const char *, int);
+struct node_host *host_if(const char *, int);
+struct node_host *host_v4(const char *, int);
+struct node_host *host_v6(const char *, int);
+struct node_host *host_dns(const char *, int, int);
+
+const char * const tcpflags = "FSRPAUEW";
+
+static const struct icmptypeent icmp_type[] = {
+ { "echoreq", ICMP_ECHO },
+ { "echorep", ICMP_ECHOREPLY },
+ { "unreach", ICMP_UNREACH },
+ { "squench", ICMP_SOURCEQUENCH },
+ { "redir", ICMP_REDIRECT },
+ { "althost", ICMP_ALTHOSTADDR },
+ { "routeradv", ICMP_ROUTERADVERT },
+ { "routersol", ICMP_ROUTERSOLICIT },
+ { "timex", ICMP_TIMXCEED },
+ { "paramprob", ICMP_PARAMPROB },
+ { "timereq", ICMP_TSTAMP },
+ { "timerep", ICMP_TSTAMPREPLY },
+ { "inforeq", ICMP_IREQ },
+ { "inforep", ICMP_IREQREPLY },
+ { "maskreq", ICMP_MASKREQ },
+ { "maskrep", ICMP_MASKREPLY },
+ { "trace", ICMP_TRACEROUTE },
+ { "dataconv", ICMP_DATACONVERR },
+ { "mobredir", ICMP_MOBILE_REDIRECT },
+ { "ipv6-where", ICMP_IPV6_WHEREAREYOU },
+ { "ipv6-here", ICMP_IPV6_IAMHERE },
+ { "mobregreq", ICMP_MOBILE_REGREQUEST },
+ { "mobregrep", ICMP_MOBILE_REGREPLY },
+ { "skip", ICMP_SKIP },
+ { "photuris", ICMP_PHOTURIS }
+};
+
+static const struct icmptypeent icmp6_type[] = {
+ { "unreach", ICMP6_DST_UNREACH },
+ { "toobig", ICMP6_PACKET_TOO_BIG },
+ { "timex", ICMP6_TIME_EXCEEDED },
+ { "paramprob", ICMP6_PARAM_PROB },
+ { "echoreq", ICMP6_ECHO_REQUEST },
+ { "echorep", ICMP6_ECHO_REPLY },
+ { "groupqry", ICMP6_MEMBERSHIP_QUERY },
+ { "listqry", MLD_LISTENER_QUERY },
+ { "grouprep", ICMP6_MEMBERSHIP_REPORT },
+ { "listenrep", MLD_LISTENER_REPORT },
+ { "groupterm", ICMP6_MEMBERSHIP_REDUCTION },
+ { "listendone", MLD_LISTENER_DONE },
+ { "routersol", ND_ROUTER_SOLICIT },
+ { "routeradv", ND_ROUTER_ADVERT },
+ { "neighbrsol", ND_NEIGHBOR_SOLICIT },
+ { "neighbradv", ND_NEIGHBOR_ADVERT },
+ { "redir", ND_REDIRECT },
+ { "routrrenum", ICMP6_ROUTER_RENUMBERING },
+ { "wrureq", ICMP6_WRUREQUEST },
+ { "wrurep", ICMP6_WRUREPLY },
+ { "fqdnreq", ICMP6_FQDN_QUERY },
+ { "fqdnrep", ICMP6_FQDN_REPLY },
+ { "niqry", ICMP6_NI_QUERY },
+ { "nirep", ICMP6_NI_REPLY },
+ { "mtraceresp", MLD_MTRACE_RESP },
+ { "mtrace", MLD_MTRACE }
+};
+
+static const struct icmpcodeent icmp_code[] = {
+ { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET },
+ { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST },
+ { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL },
+ { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT },
+ { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG },
+ { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL },
+ { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN },
+ { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN },
+ { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED },
+ { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB },
+ { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB },
+ { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET },
+ { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST },
+ { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB },
+ { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE },
+ { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF },
+ { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET },
+ { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST },
+ { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET },
+ { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST },
+ { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
+ { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
+ { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS },
+ { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS },
+ { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR },
+ { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT },
+ { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH },
+ { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX },
+ { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED },
+ { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED }
+};
+
+static const struct icmpcodeent icmp6_code[] = {
+ { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
+ { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
+ { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
+ { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
+ { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
+ { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
+ { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
+ { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
+ { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
+ { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
+ { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
+ { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
+};
+
+const struct pf_timeout pf_timeouts[] = {
+ { "tcp.first", PFTM_TCP_FIRST_PACKET },
+ { "tcp.opening", PFTM_TCP_OPENING },
+ { "tcp.established", PFTM_TCP_ESTABLISHED },
+ { "tcp.closing", PFTM_TCP_CLOSING },
+ { "tcp.finwait", PFTM_TCP_FIN_WAIT },
+ { "tcp.closed", PFTM_TCP_CLOSED },
+ { "tcp.tsdiff", PFTM_TS_DIFF },
+ { "udp.first", PFTM_UDP_FIRST_PACKET },
+ { "udp.single", PFTM_UDP_SINGLE },
+ { "udp.multiple", PFTM_UDP_MULTIPLE },
+ { "icmp.first", PFTM_ICMP_FIRST_PACKET },
+ { "icmp.error", PFTM_ICMP_ERROR_REPLY },
+ { "other.first", PFTM_OTHER_FIRST_PACKET },
+ { "other.single", PFTM_OTHER_SINGLE },
+ { "other.multiple", PFTM_OTHER_MULTIPLE },
+ { "frag", PFTM_FRAG },
+ { "interval", PFTM_INTERVAL },
+ { "adaptive.start", PFTM_ADAPTIVE_START },
+ { "adaptive.end", PFTM_ADAPTIVE_END },
+ { "src.track", PFTM_SRC_NODE },
+ { NULL, 0 }
+};
+
+const struct icmptypeent *
+geticmptypebynumber(u_int8_t type, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_type); i++) {
+ if (type == icmp_type[i].type)
+ return (&icmp_type[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_type); i++) {
+ if (type == icmp6_type[i].type)
+ return (&icmp6_type[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmptypeent *
+geticmptypebyname(char *w, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_type); i++) {
+ if (!strcmp(w, icmp_type[i].name))
+ return (&icmp_type[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_type); i++) {
+ if (!strcmp(w, icmp6_type[i].name))
+ return (&icmp6_type[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmpcodeent *
+geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_code); i++) {
+ if (type == icmp_code[i].type &&
+ code == icmp_code[i].code)
+ return (&icmp_code[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_code); i++) {
+ if (type == icmp6_code[i].type &&
+ code == icmp6_code[i].code)
+ return (&icmp6_code[i]);
+ }
+ }
+ return (NULL);
+}
+
+const struct icmpcodeent *
+geticmpcodebyname(u_long type, char *w, sa_family_t af)
+{
+ unsigned int i;
+
+ if (af != AF_INET6) {
+ for (i=0; i < nitems(icmp_code); i++) {
+ if (type == icmp_code[i].type &&
+ !strcmp(w, icmp_code[i].name))
+ return (&icmp_code[i]);
+ }
+ } else {
+ for (i=0; i < nitems(icmp6_code); i++) {
+ if (type == icmp6_code[i].type &&
+ !strcmp(w, icmp6_code[i].name))
+ return (&icmp6_code[i]);
+ }
+ }
+ return (NULL);
+}
+
+void
+print_op(u_int8_t op, const char *a1, const char *a2)
+{
+ if (op == PF_OP_IRG)
+ printf(" %s >< %s", a1, a2);
+ else if (op == PF_OP_XRG)
+ printf(" %s <> %s", a1, a2);
+ else if (op == PF_OP_EQ)
+ printf(" = %s", a1);
+ else if (op == PF_OP_NE)
+ printf(" != %s", a1);
+ else if (op == PF_OP_LT)
+ printf(" < %s", a1);
+ else if (op == PF_OP_LE)
+ printf(" <= %s", a1);
+ else if (op == PF_OP_GT)
+ printf(" > %s", a1);
+ else if (op == PF_OP_GE)
+ printf(" >= %s", a1);
+ else if (op == PF_OP_RRG)
+ printf(" %s:%s", a1, a2);
+}
+
+void
+print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric)
+{
+ char a1[6], a2[6];
+ struct servent *s;
+
+ if (!numeric)
+ s = getservbyport(p1, proto);
+ else
+ s = NULL;
+ p1 = ntohs(p1);
+ p2 = ntohs(p2);
+ snprintf(a1, sizeof(a1), "%u", p1);
+ snprintf(a2, sizeof(a2), "%u", p2);
+ printf(" port");
+ if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, s->s_name, a2);
+ else
+ print_op(op, a1, a2);
+}
+
+void
+print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
+{
+ char a1[11], a2[11];
+
+ snprintf(a1, sizeof(a1), "%u", u1);
+ snprintf(a2, sizeof(a2), "%u", u2);
+ printf(" %s", t);
+ if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
+ print_op(op, "unknown", a2);
+ else
+ print_op(op, a1, a2);
+}
+
+void
+print_flags(u_int8_t f)
+{
+ int i;
+
+ for (i = 0; tcpflags[i]; ++i)
+ if (f & (1 << i))
+ printf("%c", tcpflags[i]);
+}
+
+void
+print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
+ sa_family_t af, u_int8_t proto, int verbose, int numeric)
+{
+ char buf[PF_OSFP_LEN*3];
+ if (src->addr.type == PF_ADDR_ADDRMASK &&
+ dst->addr.type == PF_ADDR_ADDRMASK &&
+ PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
+ PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
+ PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
+ PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
+ !src->neg && !dst->neg &&
+ !src->port_op && !dst->port_op &&
+ osfp == PF_OSFP_ANY)
+ printf(" all");
+ else {
+ printf(" from ");
+ if (src->neg)
+ printf("! ");
+ print_addr(&src->addr, af, verbose);
+ if (src->port_op)
+ print_port(src->port_op, src->port[0],
+ src->port[1],
+ proto == IPPROTO_TCP ? "tcp" : "udp",
+ numeric);
+ if (osfp != PF_OSFP_ANY)
+ printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
+ sizeof(buf)));
+
+ printf(" to ");
+ if (dst->neg)
+ printf("! ");
+ print_addr(&dst->addr, af, verbose);
+ if (dst->port_op)
+ print_port(dst->port_op, dst->port[0],
+ dst->port[1],
+ proto == IPPROTO_TCP ? "tcp" : "udp",
+ numeric);
+ }
+}
+
+void
+print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
+ sa_family_t af, int id)
+{
+ struct pf_pooladdr *pooladdr;
+
+ if ((TAILQ_FIRST(&pool->list) != NULL) &&
+ TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
+ printf("{ ");
+ TAILQ_FOREACH(pooladdr, &pool->list, entries){
+ switch (id) {
+ case PF_NAT:
+ case PF_RDR:
+ case PF_BINAT:
+ print_addr(&pooladdr->addr, af, 0);
+ break;
+ case PF_PASS:
+ if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
+ printf("%s", pooladdr->ifname);
+ else {
+ printf("(%s ", pooladdr->ifname);
+ print_addr(&pooladdr->addr, af, 0);
+ printf(")");
+ }
+ break;
+ default:
+ break;
+ }
+ if (TAILQ_NEXT(pooladdr, entries) != NULL)
+ printf(", ");
+ else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
+ printf(" }");
+ }
+ switch (id) {
+ case PF_NAT:
+ if ((p1 != PF_NAT_PROXY_PORT_LOW ||
+ p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
+ if (p1 == p2)
+ printf(" port %u", p1);
+ else
+ printf(" port %u:%u", p1, p2);
+ }
+ break;
+ case PF_RDR:
+ if (p1) {
+ printf(" port %u", p1);
+ if (p2 && (p2 != p1))
+ printf(":%u", p2);
+ }
+ break;
+ default:
+ break;
+ }
+ switch (pool->opts & PF_POOL_TYPEMASK) {
+ case PF_POOL_NONE:
+ break;
+ case PF_POOL_BITMASK:
+ printf(" bitmask");
+ break;
+ case PF_POOL_RANDOM:
+ printf(" random");
+ break;
+ case PF_POOL_SRCHASH:
+ printf(" source-hash 0x%08x%08x%08x%08x",
+ pool->key.key32[0], pool->key.key32[1],
+ pool->key.key32[2], pool->key.key32[3]);
+ break;
+ case PF_POOL_ROUNDROBIN:
+ printf(" round-robin");
+ break;
+ }
+ if (pool->opts & PF_POOL_STICKYADDR)
+ printf(" sticky-address");
+ if (id == PF_NAT && p1 == 0 && p2 == 0)
+ printf(" static-port");
+}
+
+const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
+const char * const pf_lcounters[LCNT_MAX+1] = LCNT_NAMES;
+const char * const pf_fcounters[FCNT_MAX+1] = FCNT_NAMES;
+const char * const pf_scounters[FCNT_MAX+1] = FCNT_NAMES;
+
+void
+print_status(struct pf_status *s, int opts)
+{
+ char statline[80], *running;
+ time_t runtime;
+ int i;
+ char buf[PF_MD5_DIGEST_LENGTH * 2 + 1];
+ static const char hex[] = "0123456789abcdef";
+
+ runtime = time(NULL) - s->since;
+ running = s->running ? "Enabled" : "Disabled";
+
+ if (s->since) {
+ unsigned int sec, min, hrs, day = runtime;
+
+ sec = day % 60;
+ day /= 60;
+ min = day % 60;
+ day /= 60;
+ hrs = day % 24;
+ day /= 24;
+ snprintf(statline, sizeof(statline),
+ "Status: %s for %u days %.2u:%.2u:%.2u",
+ running, day, hrs, min, sec);
+ } else
+ snprintf(statline, sizeof(statline), "Status: %s", running);
+ printf("%-44s", statline);
+ switch (s->debug) {
+ case PF_DEBUG_NONE:
+ printf("%15s\n\n", "Debug: None");
+ break;
+ case PF_DEBUG_URGENT:
+ printf("%15s\n\n", "Debug: Urgent");
+ break;
+ case PF_DEBUG_MISC:
+ printf("%15s\n\n", "Debug: Misc");
+ break;
+ case PF_DEBUG_NOISY:
+ printf("%15s\n\n", "Debug: Loud");
+ break;
+ }
+
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Hostid: 0x%08x\n", ntohl(s->hostid));
+
+ for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) {
+ buf[i + i] = hex[s->pf_chksum[i] >> 4];
+ buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f];
+ }
+ buf[i + i] = '\0';
+ printf("Checksum: 0x%s\n\n", buf);
+ }
+
+ if (s->ifname[0] != 0) {
+ printf("Interface Stats for %-16s %5s %16s\n",
+ s->ifname, "IPv4", "IPv6");
+ printf(" %-25s %14llu %16llu\n", "Bytes In",
+ (unsigned long long)s->bcounters[0][0],
+ (unsigned long long)s->bcounters[1][0]);
+ printf(" %-25s %14llu %16llu\n", "Bytes Out",
+ (unsigned long long)s->bcounters[0][1],
+ (unsigned long long)s->bcounters[1][1]);
+ printf(" Packets In\n");
+ printf(" %-23s %14llu %16llu\n", "Passed",
+ (unsigned long long)s->pcounters[0][0][PF_PASS],
+ (unsigned long long)s->pcounters[1][0][PF_PASS]);
+ printf(" %-23s %14llu %16llu\n", "Blocked",
+ (unsigned long long)s->pcounters[0][0][PF_DROP],
+ (unsigned long long)s->pcounters[1][0][PF_DROP]);
+ printf(" Packets Out\n");
+ printf(" %-23s %14llu %16llu\n", "Passed",
+ (unsigned long long)s->pcounters[0][1][PF_PASS],
+ (unsigned long long)s->pcounters[1][1][PF_PASS]);
+ printf(" %-23s %14llu %16llu\n\n", "Blocked",
+ (unsigned long long)s->pcounters[0][1][PF_DROP],
+ (unsigned long long)s->pcounters[1][1][PF_DROP]);
+ }
+ printf("%-27s %14s %16s\n", "State Table", "Total", "Rate");
+ printf(" %-25s %14u %14s\n", "current entries", s->states, "");
+ for (i = 0; i < FCNT_MAX; i++) {
+ printf(" %-25s %14llu ", pf_fcounters[i],
+ (unsigned long long)s->fcounters[i]);
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->fcounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Source Tracking Table\n");
+ printf(" %-25s %14u %14s\n", "current entries",
+ s->src_nodes, "");
+ for (i = 0; i < SCNT_MAX; i++) {
+ printf(" %-25s %14lld ", pf_scounters[i],
+#ifdef __FreeBSD__
+ (long long)s->scounters[i]);
+#else
+ s->scounters[i]);
+#endif
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->scounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ }
+ printf("Counters\n");
+ for (i = 0; i < PFRES_MAX; i++) {
+ printf(" %-25s %14llu ", pf_reasons[i],
+ (unsigned long long)s->counters[i]);
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->counters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ if (opts & PF_OPT_VERBOSE) {
+ printf("Limit Counters\n");
+ for (i = 0; i < LCNT_MAX; i++) {
+ printf(" %-25s %14lld ", pf_lcounters[i],
+#ifdef __FreeBSD__
+ (unsigned long long)s->lcounters[i]);
+#else
+ s->lcounters[i]);
+#endif
+ if (runtime > 0)
+ printf("%14.1f/s\n",
+ (double)s->lcounters[i] / (double)runtime);
+ else
+ printf("%14s\n", "");
+ }
+ }
+}
+
+void
+print_src_node(struct pf_src_node *sn, int opts)
+{
+ struct pf_addr_wrap aw;
+ int min, sec;
+
+ memset(&aw, 0, sizeof(aw));
+ if (sn->af == AF_INET)
+ aw.v.a.mask.addr32[0] = 0xffffffff;
+ else
+ memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask));
+
+ aw.v.a.addr = sn->addr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" -> ");
+ aw.v.a.addr = sn->raddr;
+ print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2);
+ printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states,
+ sn->conn, sn->conn_rate.count / 1000,
+ (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds);
+ if (opts & PF_OPT_VERBOSE) {
+ sec = sn->creation % 60;
+ sn->creation /= 60;
+ min = sn->creation % 60;
+ sn->creation /= 60;
+ printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec);
+ if (sn->states == 0) {
+ sec = sn->expire % 60;
+ sn->expire /= 60;
+ min = sn->expire % 60;
+ sn->expire /= 60;
+ printf(", expires in %.2u:%.2u:%.2u",
+ sn->expire, min, sec);
+ }
+ printf(", %llu pkts, %llu bytes",
+#ifdef __FreeBSD__
+ (unsigned long long)(sn->packets[0] + sn->packets[1]),
+ (unsigned long long)(sn->bytes[0] + sn->bytes[1]));
+#else
+ sn->packets[0] + sn->packets[1],
+ sn->bytes[0] + sn->bytes[1]);
+#endif
+ switch (sn->ruletype) {
+ case PF_NAT:
+ if (sn->rule.nr != -1)
+ printf(", nat rule %u", sn->rule.nr);
+ break;
+ case PF_RDR:
+ if (sn->rule.nr != -1)
+ printf(", rdr rule %u", sn->rule.nr);
+ break;
+ case PF_PASS:
+ if (sn->rule.nr != -1)
+ printf(", filter rule %u", sn->rule.nr);
+ break;
+ }
+ printf("\n");
+ }
+}
+
+void
+print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric)
+{
+ static const char *actiontypes[] = { "pass", "block", "scrub",
+ "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" };
+ static const char *anchortypes[] = { "anchor", "anchor", "anchor",
+ "anchor", "nat-anchor", "nat-anchor", "binat-anchor",
+ "binat-anchor", "rdr-anchor", "rdr-anchor" };
+ int i, opts;
+
+ if (verbose)
+ printf("@%d ", r->nr);
+ if (r->action > PF_NORDR)
+ printf("action(%d)", r->action);
+ else if (anchor_call[0]) {
+ if (anchor_call[0] == '_') {
+ printf("%s", anchortypes[r->action]);
+ } else
+ printf("%s \"%s\"", anchortypes[r->action],
+ anchor_call);
+ } else {
+ printf("%s", actiontypes[r->action]);
+ if (r->natpass)
+ printf(" pass");
+ }
+ if (r->action == PF_DROP) {
+ if (r->rule_flag & PFRULE_RETURN)
+ printf(" return");
+ else if (r->rule_flag & PFRULE_RETURNRST) {
+ if (!r->return_ttl)
+ printf(" return-rst");
+ else
+ printf(" return-rst(ttl %d)", r->return_ttl);
+ } else if (r->rule_flag & PFRULE_RETURNICMP) {
+ const struct icmpcodeent *ic, *ic6;
+
+ ic = geticmpcodebynumber(r->return_icmp >> 8,
+ r->return_icmp & 255, AF_INET);
+ ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
+ r->return_icmp6 & 255, AF_INET6);
+
+ switch (r->af) {
+ case AF_INET:
+ printf(" return-icmp");
+ if (ic == NULL)
+ printf("(%u)", r->return_icmp & 255);
+ else
+ printf("(%s)", ic->name);
+ break;
+ case AF_INET6:
+ printf(" return-icmp6");
+ if (ic6 == NULL)
+ printf("(%u)", r->return_icmp6 & 255);
+ else
+ printf("(%s)", ic6->name);
+ break;
+ default:
+ printf(" return-icmp");
+ if (ic == NULL)
+ printf("(%u, ", r->return_icmp & 255);
+ else
+ printf("(%s, ", ic->name);
+ if (ic6 == NULL)
+ printf("%u)", r->return_icmp6 & 255);
+ else
+ printf("%s)", ic6->name);
+ break;
+ }
+ } else
+ printf(" drop");
+ }
+ if (r->direction == PF_IN)
+ printf(" in");
+ else if (r->direction == PF_OUT)
+ printf(" out");
+ if (r->log) {
+ printf(" log");
+ if (r->log & ~PF_LOG || r->logif) {
+ int count = 0;
+
+ printf(" (");
+ if (r->log & PF_LOG_ALL)
+ printf("%sall", count++ ? ", " : "");
+ if (r->log & PF_LOG_SOCKET_LOOKUP)
+ printf("%suser", count++ ? ", " : "");
+ if (r->logif)
+ printf("%sto pflog%u", count++ ? ", " : "",
+ r->logif);
+ printf(")");
+ }
+ }
+ if (r->quick)
+ printf(" quick");
+ if (r->ifname[0]) {
+ if (r->ifnot)
+ printf(" on ! %s", r->ifname);
+ else
+ printf(" on %s", r->ifname);
+ }
+ if (r->rt) {
+ if (r->rt == PF_ROUTETO)
+ printf(" route-to");
+ else if (r->rt == PF_REPLYTO)
+ printf(" reply-to");
+ else if (r->rt == PF_DUPTO)
+ printf(" dup-to");
+ else if (r->rt == PF_FASTROUTE)
+ printf(" fastroute");
+ if (r->rt != PF_FASTROUTE) {
+ printf(" ");
+ print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
+ }
+ }
+ if (r->af) {
+ if (r->af == AF_INET)
+ printf(" inet");
+ else
+ printf(" inet6");
+ }
+ if (r->proto) {
+ struct protoent *p;
+
+ if ((p = getprotobynumber(r->proto)) != NULL)
+ printf(" proto %s", p->p_name);
+ else
+ printf(" proto %u", r->proto);
+ }
+ print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
+ verbose, numeric);
+ if (r->uid.op)
+ print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
+ UID_MAX);
+ if (r->gid.op)
+ print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
+ GID_MAX);
+ if (r->flags || r->flagset) {
+ printf(" flags ");
+ print_flags(r->flags);
+ printf("/");
+ print_flags(r->flagset);
+ } else if (r->action == PF_PASS &&
+ (!r->proto || r->proto == IPPROTO_TCP) &&
+ !(r->rule_flag & PFRULE_FRAGMENT) &&
+ !anchor_call[0] && r->keep_state)
+ printf(" flags any");
+ if (r->type) {
+ const struct icmptypeent *it;
+
+ it = geticmptypebynumber(r->type-1, r->af);
+ if (r->af != AF_INET6)
+ printf(" icmp-type");
+ else
+ printf(" icmp6-type");
+ if (it != NULL)
+ printf(" %s", it->name);
+ else
+ printf(" %u", r->type-1);
+ if (r->code) {
+ const struct icmpcodeent *ic;
+
+ ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
+ if (ic != NULL)
+ printf(" code %s", ic->name);
+ else
+ printf(" code %u", r->code-1);
+ }
+ }
+ if (r->tos)
+ printf(" tos 0x%2.2x", r->tos);
+ if (r->prio)
+ printf(" prio %u", r->prio == PF_PRIO_ZERO ? 0 : r->prio);
+ if (r->scrub_flags & PFSTATE_SETMASK) {
+ char *comma = "";
+ printf(" set (");
+ if (r->scrub_flags & PFSTATE_SETPRIO) {
+ if (r->set_prio[0] == r->set_prio[1])
+ printf("%s prio %u", comma, r->set_prio[0]);
+ else
+ printf("%s prio(%u, %u)", comma, r->set_prio[0],
+ r->set_prio[1]);
+ comma = ",";
+ }
+ printf(" )");
+ }
+ if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
+ printf(" no state");
+ else if (r->keep_state == PF_STATE_NORMAL)
+ printf(" keep state");
+ else if (r->keep_state == PF_STATE_MODULATE)
+ printf(" modulate state");
+ else if (r->keep_state == PF_STATE_SYNPROXY)
+ printf(" synproxy state");
+ if (r->prob) {
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0));
+ for (i = strlen(buf)-1; i > 0; i--) {
+ if (buf[i] == '0')
+ buf[i] = '\0';
+ else {
+ if (buf[i] == '.')
+ buf[i] = '\0';
+ break;
+ }
+ }
+ printf(" probability %s%%", buf);
+ }
+ opts = 0;
+ if (r->max_states || r->max_src_nodes || r->max_src_states)
+ opts = 1;
+ if (r->rule_flag & PFRULE_NOSYNC)
+ opts = 1;
+ if (r->rule_flag & PFRULE_SRCTRACK)
+ opts = 1;
+ if (r->rule_flag & PFRULE_IFBOUND)
+ opts = 1;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ opts = 1;
+ for (i = 0; !opts && i < PFTM_MAX; ++i)
+ if (r->timeout[i])
+ opts = 1;
+ if (opts) {
+ printf(" (");
+ if (r->max_states) {
+ printf("max %u", r->max_states);
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_NOSYNC) {
+ if (!opts)
+ printf(", ");
+ printf("no-sync");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_SRCTRACK) {
+ if (!opts)
+ printf(", ");
+ printf("source-track");
+ if (r->rule_flag & PFRULE_RULESRCTRACK)
+ printf(" rule");
+ else
+ printf(" global");
+ opts = 0;
+ }
+ if (r->max_src_states) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-states %u", r->max_src_states);
+ opts = 0;
+ }
+ if (r->max_src_conn) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-conn %u", r->max_src_conn);
+ opts = 0;
+ }
+ if (r->max_src_conn_rate.limit) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-conn-rate %u/%u",
+ r->max_src_conn_rate.limit,
+ r->max_src_conn_rate.seconds);
+ opts = 0;
+ }
+ if (r->max_src_nodes) {
+ if (!opts)
+ printf(", ");
+ printf("max-src-nodes %u", r->max_src_nodes);
+ opts = 0;
+ }
+ if (r->overload_tblname[0]) {
+ if (!opts)
+ printf(", ");
+ printf("overload <%s>", r->overload_tblname);
+ if (r->flush)
+ printf(" flush");
+ if (r->flush & PF_FLUSH_GLOBAL)
+ printf(" global");
+ }
+ if (r->rule_flag & PFRULE_IFBOUND) {
+ if (!opts)
+ printf(", ");
+ printf("if-bound");
+ opts = 0;
+ }
+ if (r->rule_flag & PFRULE_STATESLOPPY) {
+ if (!opts)
+ printf(", ");
+ printf("sloppy");
+ opts = 0;
+ }
+ for (i = 0; i < PFTM_MAX; ++i)
+ if (r->timeout[i]) {
+ int j;
+
+ if (!opts)
+ printf(", ");
+ opts = 0;
+ for (j = 0; pf_timeouts[j].name != NULL;
+ ++j)
+ if (pf_timeouts[j].timeout == i)
+ break;
+ printf("%s %u", pf_timeouts[j].name == NULL ?
+ "inv.timeout" : pf_timeouts[j].name,
+ r->timeout[i]);
+ }
+ printf(")");
+ }
+ if (r->rule_flag & PFRULE_FRAGMENT)
+ printf(" fragment");
+ if (r->rule_flag & PFRULE_NODF)
+ printf(" no-df");
+ if (r->rule_flag & PFRULE_RANDOMID)
+ printf(" random-id");
+ if (r->min_ttl)
+ printf(" min-ttl %d", r->min_ttl);
+ if (r->max_mss)
+ printf(" max-mss %d", r->max_mss);
+ if (r->rule_flag & PFRULE_SET_TOS)
+ printf(" set-tos 0x%2.2x", r->set_tos);
+ if (r->allow_opts)
+ printf(" allow-opts");
+ if (r->action == PF_SCRUB) {
+ if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
+ printf(" reassemble tcp");
+
+ printf(" fragment reassemble");
+ }
+ if (r->label[0])
+ printf(" label \"%s\"", r->label);
+ if (r->qname[0] && r->pqname[0])
+ printf(" queue(%s, %s)", r->qname, r->pqname);
+ else if (r->qname[0])
+ printf(" queue %s", r->qname);
+ if (r->tagname[0])
+ printf(" tag %s", r->tagname);
+ if (r->match_tagname[0]) {
+ if (r->match_tag_not)
+ printf(" !");
+ printf(" tagged %s", r->match_tagname);
+ }
+ if (r->rtableid != -1)
+ printf(" rtable %u", r->rtableid);
+ if (r->divert.port) {
+#ifdef __FreeBSD__
+ printf(" divert-to %u", ntohs(r->divert.port));
+#else
+ if (PF_AZERO(&r->divert.addr, r->af)) {
+ printf(" divert-reply");
+ } else {
+ /* XXX cut&paste from print_addr */
+ char buf[48];
+
+ printf(" divert-to ");
+ if (inet_ntop(r->af, &r->divert.addr, buf,
+ sizeof(buf)) == NULL)
+ printf("?");
+ else
+ printf("%s", buf);
+ printf(" port %u", ntohs(r->divert.port));
+ }
+#endif
+ }
+ if (!anchor_call[0] && (r->action == PF_NAT ||
+ r->action == PF_BINAT || r->action == PF_RDR)) {
+ printf(" -> ");
+ print_pool(&r->rpool, r->rpool.proxy_port[0],
+ r->rpool.proxy_port[1], r->af, r->action);
+ }
+}
+
+void
+print_tabledef(const char *name, int flags, int addrs,
+ struct node_tinithead *nodes)
+{
+ struct node_tinit *ti, *nti;
+ struct node_host *h;
+
+ printf("table <%s>", name);
+ if (flags & PFR_TFLAG_CONST)
+ printf(" const");
+ if (flags & PFR_TFLAG_PERSIST)
+ printf(" persist");
+ if (flags & PFR_TFLAG_COUNTERS)
+ printf(" counters");
+ SIMPLEQ_FOREACH(ti, nodes, entries) {
+ if (ti->file) {
+ printf(" file \"%s\"", ti->file);
+ continue;
+ }
+ printf(" {");
+ for (;;) {
+ for (h = ti->host; h != NULL; h = h->next) {
+ printf(h->not ? " !" : " ");
+ print_addr(&h->addr, h->af, 0);
+ }
+ nti = SIMPLEQ_NEXT(ti, entries);
+ if (nti != NULL && nti->file == NULL)
+ ti = nti; /* merge lists */
+ else
+ break;
+ }
+ printf(" }");
+ }
+ if (addrs && SIMPLEQ_EMPTY(nodes))
+ printf(" { }");
+ printf("\n");
+}
+
+int
+parse_flags(char *s)
+{
+ char *p, *q;
+ u_int8_t f = 0;
+
+ for (p = s; *p; p++) {
+ if ((q = strchr(tcpflags, *p)) == NULL)
+ return -1;
+ else
+ f |= 1 << (q - tcpflags);
+ }
+ return (f ? f : PF_TH_ALL);
+}
+
+void
+set_ipmask(struct node_host *h, u_int8_t b)
+{
+ struct pf_addr *m, *n;
+ int i, j = 0;
+
+ m = &h->addr.v.a.mask;
+ memset(m, 0, sizeof(*m));
+
+ while (b >= 32) {
+ m->addr32[j++] = 0xffffffff;
+ b -= 32;
+ }
+ for (i = 31; i > 31-b; --i)
+ m->addr32[j] |= (1 << i);
+ if (b)
+ m->addr32[j] = htonl(m->addr32[j]);
+
+ /* Mask off bits of the address that will never be used. */
+ n = &h->addr.v.a.addr;
+ if (h->addr.type == PF_ADDR_ADDRMASK)
+ for (i = 0; i < 4; i++)
+ n->addr32[i] = n->addr32[i] & m->addr32[i];
+}
+
+int
+check_netmask(struct node_host *h, sa_family_t af)
+{
+ struct node_host *n = NULL;
+ struct pf_addr *m;
+
+ for (n = h; n != NULL; n = n->next) {
+ if (h->addr.type == PF_ADDR_TABLE)
+ continue;
+ m = &h->addr.v.a.mask;
+ /* fix up netmask for dynaddr */
+ if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL &&
+ unmask(m, AF_INET6) > 32)
+ set_ipmask(n, 32);
+ /* netmasks > 32 bit are invalid on v4 */
+ if (af == AF_INET &&
+ (m->addr32[1] || m->addr32[2] || m->addr32[3])) {
+ fprintf(stderr, "netmask %u invalid for IPv4 address\n",
+ unmask(m, AF_INET6));
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/* interface lookup routines */
+
+static struct node_host *iftab;
+
+void
+ifa_load(void)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct node_host *n = NULL, *h = NULL;
+
+ if (getifaddrs(&ifap) < 0)
+ err(1, "getifaddrs");
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (!(ifa->ifa_addr->sa_family == AF_INET ||
+ ifa->ifa_addr->sa_family == AF_INET6 ||
+ ifa->ifa_addr->sa_family == AF_LINK))
+ continue;
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "address: calloc");
+ n->af = ifa->ifa_addr->sa_family;
+ n->ifa_flags = ifa->ifa_flags;
+#ifdef __KAME__
+ if (n->af == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_addr) &&
+ ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id ==
+ 0) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 |
+ sin6->sin6_addr.s6_addr[3];
+ sin6->sin6_addr.s6_addr[2] = 0;
+ sin6->sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ n->ifindex = 0;
+ if (n->af == AF_INET) {
+ memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *)
+ ifa->ifa_addr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *)
+ ifa->ifa_netmask)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ if (ifa->ifa_broadaddr != NULL)
+ memcpy(&n->bcast, &((struct sockaddr_in *)
+ ifa->ifa_broadaddr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in *)
+ ifa->ifa_dstaddr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ } else if (n->af == AF_INET6) {
+ memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *)
+ ifa->ifa_netmask)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ if (ifa->ifa_broadaddr != NULL)
+ memcpy(&n->bcast, &((struct sockaddr_in6 *)
+ ifa->ifa_broadaddr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ if (ifa->ifa_dstaddr != NULL)
+ memcpy(&n->peer, &((struct sockaddr_in6 *)
+ ifa->ifa_dstaddr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ n->ifindex = ((struct sockaddr_in6 *)
+ ifa->ifa_addr)->sin6_scope_id;
+ }
+ if ((n->ifname = strdup(ifa->ifa_name)) == NULL)
+ err(1, "ifa_load: strdup");
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+
+ iftab = h;
+ freeifaddrs(ifap);
+}
+
+int
+get_socket_domain(void)
+{
+ int sdom;
+
+ sdom = AF_UNSPEC;
+#ifdef WITH_INET6
+ if (sdom == AF_UNSPEC && feature_present("inet6"))
+ sdom = AF_INET6;
+#endif
+#ifdef WITH_INET
+ if (sdom == AF_UNSPEC && feature_present("inet"))
+ sdom = AF_INET;
+#endif
+ if (sdom == AF_UNSPEC)
+ sdom = AF_LINK;
+
+ return (sdom);
+}
+
+struct node_host *
+ifa_exists(const char *ifa_name)
+{
+ struct node_host *n;
+ struct ifgroupreq ifgr;
+ int s;
+
+ if (iftab == NULL)
+ ifa_load();
+
+ /* check wether this is a group */
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
+ err(1, "socket");
+ bzero(&ifgr, sizeof(ifgr));
+ strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) {
+ /* fake a node_host */
+ if ((n = calloc(1, sizeof(*n))) == NULL)
+ err(1, "calloc");
+ if ((n->ifname = strdup(ifa_name)) == NULL)
+ err(1, "strdup");
+ close(s);
+ return (n);
+ }
+ close(s);
+
+ for (n = iftab; n; n = n->next) {
+ if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ))
+ return (n);
+ }
+
+ return (NULL);
+}
+
+struct node_host *
+ifa_grouplookup(const char *ifa_name, int flags)
+{
+ struct ifg_req *ifg;
+ struct ifgroupreq ifgr;
+ int s, len;
+ struct node_host *n, *h = NULL;
+
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
+ err(1, "socket");
+ bzero(&ifgr, sizeof(ifgr));
+ strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
+ close(s);
+ return (NULL);
+ }
+
+ len = ifgr.ifgr_len;
+ if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
+ err(1, "calloc");
+ if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
+ err(1, "SIOCGIFGMEMB");
+
+ for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
+ ifg++) {
+ len -= sizeof(struct ifg_req);
+ if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL)
+ continue;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n->tail;
+ }
+ }
+ free(ifgr.ifgr_groups);
+ close(s);
+
+ return (h);
+}
+
+struct node_host *
+ifa_lookup(const char *ifa_name, int flags)
+{
+ struct node_host *p = NULL, *h = NULL, *n = NULL;
+ int got4 = 0, got6 = 0;
+ const char *last_if = NULL;
+
+ if ((h = ifa_grouplookup(ifa_name, flags)) != NULL)
+ return (h);
+
+ if (!strncmp(ifa_name, "self", IFNAMSIZ))
+ ifa_name = NULL;
+
+ if (iftab == NULL)
+ ifa_load();
+
+ for (p = iftab; p; p = p->next) {
+ if (ifa_skip_if(ifa_name, p))
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET)
+ continue;
+ if ((flags & PFI_AFLAG_BROADCAST) &&
+ !(p->ifa_flags & IFF_BROADCAST))
+ continue;
+ if ((flags & PFI_AFLAG_PEER) &&
+ !(p->ifa_flags & IFF_POINTOPOINT))
+ continue;
+ if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0)
+ continue;
+ if (last_if == NULL || strcmp(last_if, p->ifname))
+ got4 = got6 = 0;
+ last_if = p->ifname;
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4)
+ continue;
+ if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6)
+ continue;
+ if (p->af == AF_INET)
+ got4 = 1;
+ else
+ got6 = 1;
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "address: calloc");
+ n->af = p->af;
+ if (flags & PFI_AFLAG_BROADCAST)
+ memcpy(&n->addr.v.a.addr, &p->bcast,
+ sizeof(struct pf_addr));
+ else if (flags & PFI_AFLAG_PEER)
+ memcpy(&n->addr.v.a.addr, &p->peer,
+ sizeof(struct pf_addr));
+ else
+ memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr,
+ sizeof(struct pf_addr));
+ if (flags & PFI_AFLAG_NETWORK)
+ set_ipmask(n, unmask(&p->addr.v.a.mask, n->af));
+ else {
+ if (n->af == AF_INET) {
+ if (p->ifa_flags & IFF_LOOPBACK &&
+ p->ifa_flags & IFF_LINK1)
+ memcpy(&n->addr.v.a.mask,
+ &p->addr.v.a.mask,
+ sizeof(struct pf_addr));
+ else
+ set_ipmask(n, 32);
+ } else
+ set_ipmask(n, 128);
+ }
+ n->ifindex = p->ifindex;
+
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+ return (h);
+}
+
+int
+ifa_skip_if(const char *filter, struct node_host *p)
+{
+ int n;
+
+ if (p->af != AF_INET && p->af != AF_INET6)
+ return (1);
+ if (filter == NULL || !*filter)
+ return (0);
+ if (!strcmp(p->ifname, filter))
+ return (0); /* exact match */
+ n = strlen(filter);
+ if (n < 1 || n >= IFNAMSIZ)
+ return (1); /* sanity check */
+ if (filter[n-1] >= '0' && filter[n-1] <= '9')
+ return (1); /* only do exact match in that case */
+ if (strncmp(p->ifname, filter, n))
+ return (1); /* prefix doesn't match */
+ return (p->ifname[n] < '0' || p->ifname[n] > '9');
+}
+
+
+struct node_host *
+host(const char *s)
+{
+ struct node_host *h = NULL;
+ int mask, v4mask, v6mask, cont = 1;
+ char *p, *q, *ps;
+
+ if ((p = strrchr(s, '/')) != NULL) {
+ mask = strtol(p+1, &q, 0);
+ if (!q || *q || mask > 128 || q == (p+1)) {
+ fprintf(stderr, "invalid netmask '%s'\n", p);
+ return (NULL);
+ }
+ if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL)
+ err(1, "host: malloc");
+ strlcpy(ps, s, strlen(s) - strlen(p) + 1);
+ v4mask = v6mask = mask;
+ } else {
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host: strdup");
+ v4mask = 32;
+ v6mask = 128;
+ mask = -1;
+ }
+
+ /* interface with this name exists? */
+ if (cont && (h = host_if(ps, mask)) != NULL)
+ cont = 0;
+
+ /* IPv4 address? */
+ if (cont && (h = host_v4(s, mask)) != NULL)
+ cont = 0;
+
+ /* IPv6 address? */
+ if (cont && (h = host_v6(ps, v6mask)) != NULL)
+ cont = 0;
+
+ /* dns lookup */
+ if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL)
+ cont = 0;
+ free(ps);
+
+ if (h == NULL || cont == 1) {
+ fprintf(stderr, "no IP address found for %s\n", s);
+ return (NULL);
+ }
+ return (h);
+}
+
+struct node_host *
+host_if(const char *s, int mask)
+{
+ struct node_host *n, *h = NULL;
+ char *p, *ps;
+ int flags = 0;
+
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_if: strdup");
+ while ((p = strrchr(ps, ':')) != NULL) {
+ if (!strcmp(p+1, "network"))
+ flags |= PFI_AFLAG_NETWORK;
+ else if (!strcmp(p+1, "broadcast"))
+ flags |= PFI_AFLAG_BROADCAST;
+ else if (!strcmp(p+1, "peer"))
+ flags |= PFI_AFLAG_PEER;
+ else if (!strcmp(p+1, "0"))
+ flags |= PFI_AFLAG_NOALIAS;
+ else {
+ free(ps);
+ return (NULL);
+ }
+ *p = '\0';
+ }
+ if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */
+ fprintf(stderr, "illegal combination of interface modifiers\n");
+ free(ps);
+ return (NULL);
+ }
+ if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) {
+ fprintf(stderr, "network or broadcast lookup, but "
+ "extra netmask given\n");
+ free(ps);
+ return (NULL);
+ }
+ if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) {
+ /* interface with this name exists */
+ h = ifa_lookup(ps, flags);
+ for (n = h; n != NULL && mask > -1; n = n->next)
+ set_ipmask(n, mask);
+ }
+
+ free(ps);
+ return (h);
+}
+
+struct node_host *
+host_v4(const char *s, int mask)
+{
+ struct node_host *h = NULL;
+ struct in_addr ina;
+ int bits = 32;
+
+ memset(&ina, 0, sizeof(struct in_addr));
+ if (strrchr(s, '/') != NULL) {
+ if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1)
+ return (NULL);
+ } else {
+ if (inet_pton(AF_INET, s, &ina) != 1)
+ return (NULL);
+ }
+
+ h = calloc(1, sizeof(struct node_host));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->ifname = NULL;
+ h->af = AF_INET;
+ h->addr.v.a.addr.addr32[0] = ina.s_addr;
+ set_ipmask(h, bits);
+ h->next = NULL;
+ h->tail = h;
+
+ return (h);
+}
+
+struct node_host *
+host_v6(const char *s, int mask)
+{
+ struct addrinfo hints, *res;
+ struct node_host *h = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(s, "0", &hints, &res) == 0) {
+ h = calloc(1, sizeof(struct node_host));
+ if (h == NULL)
+ err(1, "address: calloc");
+ h->ifname = NULL;
+ h->af = AF_INET6;
+ memcpy(&h->addr.v.a.addr,
+ &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+ sizeof(h->addr.v.a.addr));
+ h->ifindex =
+ ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id;
+ set_ipmask(h, mask);
+ freeaddrinfo(res);
+ h->next = NULL;
+ h->tail = h;
+ }
+
+ return (h);
+}
+
+struct node_host *
+host_dns(const char *s, int v4mask, int v6mask)
+{
+ struct addrinfo hints, *res0, *res;
+ struct node_host *n, *h = NULL;
+ int error, noalias = 0;
+ int got4 = 0, got6 = 0;
+ char *p, *ps;
+
+ if ((ps = strdup(s)) == NULL)
+ err(1, "host_dns: strdup");
+ if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) {
+ noalias = 1;
+ *p = '\0';
+ }
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM; /* DUMMY */
+ error = getaddrinfo(ps, NULL, &hints, &res0);
+ if (error) {
+ free(ps);
+ return (h);
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_family != AF_INET &&
+ res->ai_family != AF_INET6)
+ continue;
+ if (noalias) {
+ if (res->ai_family == AF_INET) {
+ if (got4)
+ continue;
+ got4 = 1;
+ } else {
+ if (got6)
+ continue;
+ got6 = 1;
+ }
+ }
+ n = calloc(1, sizeof(struct node_host));
+ if (n == NULL)
+ err(1, "host_dns: calloc");
+ n->ifname = NULL;
+ n->af = res->ai_family;
+ if (res->ai_family == AF_INET) {
+ memcpy(&n->addr.v.a.addr,
+ &((struct sockaddr_in *)
+ res->ai_addr)->sin_addr.s_addr,
+ sizeof(struct in_addr));
+ set_ipmask(n, v4mask);
+ } else {
+ memcpy(&n->addr.v.a.addr,
+ &((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr.s6_addr,
+ sizeof(struct in6_addr));
+ n->ifindex =
+ ((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_scope_id;
+ set_ipmask(n, v6mask);
+ }
+ n->next = NULL;
+ n->tail = n;
+ if (h == NULL)
+ h = n;
+ else {
+ h->tail->next = n;
+ h->tail = n;
+ }
+ }
+ freeaddrinfo(res0);
+ free(ps);
+
+ return (h);
+}
+
+/*
+ * convert a hostname to a list of addresses and put them in the given buffer.
+ * test:
+ * if set to 1, only simple addresses are accepted (no netblock, no "!").
+ */
+int
+append_addr(struct pfr_buffer *b, char *s, int test)
+{
+ char *r;
+ struct node_host *h, *n;
+ int rv, not = 0;
+
+ for (r = s; *r == '!'; r++)
+ not = !not;
+ if ((n = host(r)) == NULL) {
+ errno = 0;
+ return (-1);
+ }
+ rv = append_addr_host(b, n, test, not);
+ do {
+ h = n;
+ n = n->next;
+ free(h);
+ } while (n != NULL);
+ return (rv);
+}
+
+/*
+ * same as previous function, but with a pre-parsed input and the ability
+ * to "negate" the result. Does not free the node_host list.
+ * not:
+ * setting it to 1 is equivalent to adding "!" in front of parameter s.
+ */
+int
+append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not)
+{
+ int bits;
+ struct pfr_addr addr;
+
+ do {
+ bzero(&addr, sizeof(addr));
+ addr.pfra_not = n->not ^ not;
+ addr.pfra_af = n->af;
+ addr.pfra_net = unmask(&n->addr.v.a.mask, n->af);
+ switch (n->af) {
+ case AF_INET:
+ addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0];
+ bits = 32;
+ break;
+ case AF_INET6:
+ memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6,
+ sizeof(struct in6_addr));
+ bits = 128;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((test && (not || addr.pfra_net != bits)) ||
+ addr.pfra_net > bits) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (pfr_buf_add(b, &addr))
+ return (-1);
+ } while ((n = n->next) != NULL);
+
+ return (0);
+}
+
+int
+pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor)
+{
+ struct pfioc_trans_e trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.rs_num = rs_num;
+ if (strlcpy(trans.anchor, anchor,
+ sizeof(trans.anchor)) >= sizeof(trans.anchor))
+ errx(1, "pfctl_add_trans: strlcpy");
+
+ return pfr_buf_add(buf, &trans);
+}
+
+u_int32_t
+pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor)
+{
+ struct pfioc_trans_e *p;
+
+ PFRB_FOREACH(p, buf)
+ if (rs_num == p->rs_num && !strcmp(anchor, p->anchor))
+ return (p->ticket);
+ errx(1, "pfctl_get_ticket: assertion failed");
+}
+
+int
+pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from)
+{
+ struct pfioc_trans trans;
+
+ bzero(&trans, sizeof(trans));
+ trans.size = buf->pfrb_size - from;
+ trans.esize = sizeof(struct pfioc_trans_e);
+ trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from;
+ return ioctl(dev, cmd, &trans);
+}
diff --git a/freebsd/sbin/pfctl/pfctl_parser.h b/freebsd/sbin/pfctl/pfctl_parser.h
new file mode 100644
index 00000000..2b7fea7b
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_parser.h
@@ -0,0 +1,322 @@
+/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2001 Daniel Hartmeier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _PFCTL_PARSER_H_
+#define _PFCTL_PARSER_H_
+
+#define PF_OSFP_FILE "/etc/pf.os"
+
+#define PF_OPT_DISABLE 0x0001
+#define PF_OPT_ENABLE 0x0002
+#define PF_OPT_VERBOSE 0x0004
+#define PF_OPT_NOACTION 0x0008
+#define PF_OPT_QUIET 0x0010
+#define PF_OPT_CLRRULECTRS 0x0020
+#define PF_OPT_USEDNS 0x0040
+#define PF_OPT_VERBOSE2 0x0080
+#define PF_OPT_DUMMYACTION 0x0100
+#define PF_OPT_DEBUG 0x0200
+#define PF_OPT_SHOWALL 0x0400
+#define PF_OPT_OPTIMIZE 0x0800
+#define PF_OPT_NUMERIC 0x1000
+#define PF_OPT_MERGE 0x2000
+#define PF_OPT_RECURSE 0x4000
+
+#define PF_TH_ALL 0xFF
+
+#define PF_NAT_PROXY_PORT_LOW 50001
+#define PF_NAT_PROXY_PORT_HIGH 65535
+
+#define PF_OPTIMIZE_BASIC 0x0001
+#define PF_OPTIMIZE_PROFILE 0x0002
+
+#define FCNT_NAMES { \
+ "searches", \
+ "inserts", \
+ "removals", \
+ NULL \
+}
+
+struct pfr_buffer; /* forward definition */
+
+
+struct pfctl {
+ int dev;
+ int opts;
+ int optimize;
+ int loadopt;
+ int asd; /* anchor stack depth */
+ int bn; /* brace number */
+ int brace;
+ int tdirty; /* kernel dirty */
+#define PFCTL_ANCHOR_STACK_DEPTH 64
+ struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH];
+ struct pfioc_pooladdr paddr;
+ struct pfioc_altq *paltq;
+ struct pfioc_queue *pqueue;
+ struct pfr_buffer *trans;
+ struct pf_anchor *anchor, *alast;
+ const char *ruleset;
+
+ /* 'set foo' options */
+ u_int32_t timeout[PFTM_MAX];
+ u_int32_t limit[PF_LIMIT_MAX];
+ u_int32_t debug;
+ u_int32_t hostid;
+ char *ifname;
+
+ u_int8_t timeout_set[PFTM_MAX];
+ u_int8_t limit_set[PF_LIMIT_MAX];
+ u_int8_t debug_set;
+ u_int8_t hostid_set;
+ u_int8_t ifname_set;
+};
+
+struct node_if {
+ char ifname[IFNAMSIZ];
+ u_int8_t not;
+ u_int8_t dynamic; /* antispoof */
+ u_int ifa_flags;
+ struct node_if *next;
+ struct node_if *tail;
+};
+
+struct node_host {
+ struct pf_addr_wrap addr;
+ struct pf_addr bcast;
+ struct pf_addr peer;
+ sa_family_t af;
+ u_int8_t not;
+ u_int32_t ifindex; /* link-local IPv6 addrs */
+ char *ifname;
+ u_int ifa_flags;
+ struct node_host *next;
+ struct node_host *tail;
+};
+
+struct node_os {
+ char *os;
+ pf_osfp_t fingerprint;
+ struct node_os *next;
+ struct node_os *tail;
+};
+
+struct node_queue_bw {
+ u_int32_t bw_absolute;
+ u_int16_t bw_percent;
+};
+
+struct node_hfsc_sc {
+ struct node_queue_bw m1; /* slope of 1st segment; bps */
+ u_int d; /* x-projection of m1; msec */
+ struct node_queue_bw m2; /* slope of 2nd segment; bps */
+ u_int8_t used;
+};
+
+struct node_hfsc_opts {
+ struct node_hfsc_sc realtime;
+ struct node_hfsc_sc linkshare;
+ struct node_hfsc_sc upperlimit;
+ int flags;
+};
+
+struct node_fairq_sc {
+ struct node_queue_bw m1; /* slope of 1st segment; bps */
+ u_int d; /* x-projection of m1; msec */
+ struct node_queue_bw m2; /* slope of 2nd segment; bps */
+ u_int8_t used;
+};
+
+struct node_fairq_opts {
+ struct node_fairq_sc linkshare;
+ struct node_queue_bw hogs_bw;
+ u_int nbuckets;
+ int flags;
+};
+
+struct node_queue_opt {
+ int qtype;
+ union {
+ struct cbq_opts cbq_opts;
+ struct codel_opts codel_opts;
+ struct priq_opts priq_opts;
+ struct node_hfsc_opts hfsc_opts;
+ struct node_fairq_opts fairq_opts;
+ } data;
+};
+
+#ifdef __FreeBSD__
+/*
+ * XXX
+ * Absolutely this is not correct location to define this.
+ * Should we use an another sperate header file?
+ */
+#define SIMPLEQ_HEAD STAILQ_HEAD
+#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER
+#define SIMPLEQ_ENTRY STAILQ_ENTRY
+#define SIMPLEQ_FIRST STAILQ_FIRST
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY STAILQ_EMPTY
+#define SIMPLEQ_NEXT STAILQ_NEXT
+/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+#define SIMPLEQ_INIT STAILQ_INIT
+#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD
+#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL
+#define SIMPLEQ_INSERT_AFTER STAILQ_INSERT_AFTER
+#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD
+#endif
+SIMPLEQ_HEAD(node_tinithead, node_tinit);
+struct node_tinit { /* table initializer */
+ SIMPLEQ_ENTRY(node_tinit) entries;
+ struct node_host *host;
+ char *file;
+};
+
+
+/* optimizer created tables */
+struct pf_opt_tbl {
+ char pt_name[PF_TABLE_NAME_SIZE];
+ int pt_rulecount;
+ int pt_generated;
+ struct node_tinithead pt_nodes;
+ struct pfr_buffer *pt_buf;
+};
+#define PF_OPT_TABLE_PREFIX "__automatic_"
+
+/* optimizer pf_rule container */
+struct pf_opt_rule {
+ struct pf_rule por_rule;
+ struct pf_opt_tbl *por_src_tbl;
+ struct pf_opt_tbl *por_dst_tbl;
+ u_int64_t por_profile_count;
+ TAILQ_ENTRY(pf_opt_rule) por_entry;
+ TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT];
+};
+
+TAILQ_HEAD(pf_opt_queue, pf_opt_rule);
+
+int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *);
+int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *);
+
+int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *);
+int pfctl_add_altq(struct pfctl *, struct pf_altq *);
+int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t);
+void pfctl_move_pool(struct pf_pool *, struct pf_pool *);
+void pfctl_clear_pool(struct pf_pool *);
+
+int pfctl_set_timeout(struct pfctl *, const char *, int, int);
+int pfctl_set_optimization(struct pfctl *, const char *);
+int pfctl_set_limit(struct pfctl *, const char *, unsigned int);
+int pfctl_set_logif(struct pfctl *, char *);
+int pfctl_set_hostid(struct pfctl *, u_int32_t);
+int pfctl_set_debug(struct pfctl *, char *);
+int pfctl_set_interface_flags(struct pfctl *, char *, int, int);
+
+int parse_config(char *, struct pfctl *);
+int parse_flags(char *);
+int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
+
+void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int);
+void print_src_node(struct pf_src_node *, int);
+void print_rule(struct pf_rule *, const char *, int, int);
+void print_tabledef(const char *, int, int, struct node_tinithead *);
+void print_status(struct pf_status *, int);
+
+int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
+ struct node_queue_opt *);
+int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *,
+ struct node_queue_opt *);
+
+void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *,
+ struct node_queue_opt *);
+void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *,
+ int, struct node_queue_opt *);
+
+int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *,
+ u_int32_t);
+
+void pfctl_clear_fingerprints(int, int);
+int pfctl_file_fingerprints(int, int, const char *);
+pf_osfp_t pfctl_get_fingerprint(const char *);
+int pfctl_load_fingerprints(int, int);
+char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t);
+void pfctl_show_fingerprints(int);
+
+
+struct icmptypeent {
+ const char *name;
+ u_int8_t type;
+};
+
+struct icmpcodeent {
+ const char *name;
+ u_int8_t type;
+ u_int8_t code;
+};
+
+const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t);
+const struct icmptypeent *geticmptypebyname(char *, u_int8_t);
+const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t);
+const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t);
+
+struct pf_timeout {
+ const char *name;
+ int timeout;
+};
+
+#define PFCTL_FLAG_FILTER 0x02
+#define PFCTL_FLAG_NAT 0x04
+#define PFCTL_FLAG_OPTION 0x08
+#define PFCTL_FLAG_ALTQ 0x10
+#define PFCTL_FLAG_TABLE 0x20
+
+extern const struct pf_timeout pf_timeouts[];
+
+void set_ipmask(struct node_host *, u_int8_t);
+int check_netmask(struct node_host *, sa_family_t);
+int unmask(struct pf_addr *, sa_family_t);
+void ifa_load(void);
+int get_socket_domain(void);
+struct node_host *ifa_exists(const char *);
+struct node_host *ifa_lookup(const char *, int);
+struct node_host *host(const char *);
+
+int append_addr(struct pfr_buffer *, char *, int);
+int append_addr_host(struct pfr_buffer *,
+ struct node_host *, int, int);
+
+#endif /* _PFCTL_PARSER_H_ */
diff --git a/freebsd/sbin/pfctl/pfctl_qstats.c b/freebsd/sbin/pfctl/pfctl_qstats.c
new file mode 100644
index 00000000..dda3a494
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_qstats.c
@@ -0,0 +1,528 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
+
+/*
+ * Copyright (c) Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/altq/altq.h>
+#include <net/altq/altq_cbq.h>
+#include <net/altq/altq_codel.h>
+#include <net/altq/altq_priq.h>
+#include <net/altq/altq_hfsc.h>
+#include <net/altq/altq_fairq.h>
+
+#include "pfctl.h"
+#include "pfctl_parser.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_qstats-data.h"
+#endif /* __rtems__ */
+
+union class_stats {
+ class_stats_t cbq_stats;
+ struct priq_classstats priq_stats;
+ struct hfsc_classstats hfsc_stats;
+ struct fairq_classstats fairq_stats;
+ struct codel_ifstats codel_stats;
+};
+
+#define AVGN_MAX 8
+#define STAT_INTERVAL 5
+
+struct queue_stats {
+ union class_stats data;
+ int avgn;
+ double avg_bytes;
+ double avg_packets;
+ u_int64_t prev_bytes;
+ u_int64_t prev_packets;
+};
+
+struct pf_altq_node {
+ struct pf_altq altq;
+ struct pf_altq_node *next;
+ struct pf_altq_node *children;
+ struct queue_stats qstats;
+};
+
+int pfctl_update_qstats(int, struct pf_altq_node **);
+void pfctl_insert_altq_node(struct pf_altq_node **,
+ const struct pf_altq, const struct queue_stats);
+struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *,
+ const char *, const char *);
+void pfctl_print_altq_node(int, const struct pf_altq_node *,
+ unsigned, int);
+void print_cbqstats(struct queue_stats);
+void print_codelstats(struct queue_stats);
+void print_priqstats(struct queue_stats);
+void print_hfscstats(struct queue_stats);
+void print_fairqstats(struct queue_stats);
+void pfctl_free_altq_node(struct pf_altq_node *);
+void pfctl_print_altq_nodestat(int,
+ const struct pf_altq_node *);
+
+void update_avg(struct pf_altq_node *);
+
+int
+pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
+{
+ struct pf_altq_node *root = NULL, *node;
+ int nodes, dotitle = (opts & PF_OPT_SHOWALL);
+
+#ifdef __FreeBSD__
+ if (!altqsupport)
+ return (-1);
+#endif
+
+ if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
+ return (-1);
+
+ if (nodes == 0)
+ printf("No queue in use\n");
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
+ if (dotitle) {
+ pfctl_print_title("ALTQ:");
+ dotitle = 0;
+ }
+ pfctl_print_altq_node(dev, node, 0, opts);
+ }
+
+ while (verbose2 && nodes > 0) {
+ printf("\n");
+ fflush(stdout);
+ sleep(STAT_INTERVAL);
+ if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
+ return (-1);
+ for (node = root; node != NULL; node = node->next) {
+ if (iface != NULL && strcmp(node->altq.ifname, iface))
+ continue;
+#ifdef __FreeBSD__
+ if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
+ continue;
+#endif
+ pfctl_print_altq_node(dev, node, 0, opts);
+ }
+ }
+ pfctl_free_altq_node(root);
+ return (0);
+}
+
+#ifdef __rtems__
+static u_int32_t last_ticket;
+#endif /* __rtems__ */
+int
+pfctl_update_qstats(int dev, struct pf_altq_node **root)
+{
+ struct pf_altq_node *node;
+ struct pfioc_altq pa;
+ struct pfioc_qstats pq;
+ u_int32_t mnr, nr;
+ struct queue_stats qstats;
+#ifndef __rtems__
+ static u_int32_t last_ticket;
+#endif /* __rtems__ */
+
+ memset(&pa, 0, sizeof(pa));
+ memset(&pq, 0, sizeof(pq));
+ memset(&qstats, 0, sizeof(qstats));
+ if (ioctl(dev, DIOCGETALTQS, &pa)) {
+ warn("DIOCGETALTQS");
+ return (-1);
+ }
+
+ /* if a new set is found, start over */
+ if (pa.ticket != last_ticket && *root != NULL) {
+ pfctl_free_altq_node(*root);
+ *root = NULL;
+ }
+ last_ticket = pa.ticket;
+
+ mnr = pa.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pa.nr = nr;
+ if (ioctl(dev, DIOCGETALTQ, &pa)) {
+ warn("DIOCGETALTQ");
+ return (-1);
+ }
+#ifdef __FreeBSD__
+ if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) &&
+ !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) {
+#else
+ if (pa.altq.qid > 0) {
+#endif
+ pq.nr = nr;
+ pq.ticket = pa.ticket;
+ pq.buf = &qstats.data;
+ pq.nbytes = sizeof(qstats.data);
+ if (ioctl(dev, DIOCGETQSTATS, &pq)) {
+ warn("DIOCGETQSTATS");
+ return (-1);
+ }
+ if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
+ pa.altq.ifname)) != NULL) {
+ memcpy(&node->qstats.data, &qstats.data,
+ sizeof(qstats.data));
+ update_avg(node);
+ } else {
+ pfctl_insert_altq_node(root, pa.altq, qstats);
+ }
+ }
+#ifdef __FreeBSD__
+ else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) {
+ memset(&qstats.data, 0, sizeof(qstats.data));
+ if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
+ pa.altq.ifname)) != NULL) {
+ memcpy(&node->qstats.data, &qstats.data,
+ sizeof(qstats.data));
+ update_avg(node);
+ } else {
+ pfctl_insert_altq_node(root, pa.altq, qstats);
+ }
+ }
+#endif
+ }
+ return (mnr);
+}
+
+void
+pfctl_insert_altq_node(struct pf_altq_node **root,
+ const struct pf_altq altq, const struct queue_stats qstats)
+{
+ struct pf_altq_node *node;
+
+ node = calloc(1, sizeof(struct pf_altq_node));
+ if (node == NULL)
+ err(1, "pfctl_insert_altq_node: calloc");
+ memcpy(&node->altq, &altq, sizeof(struct pf_altq));
+ memcpy(&node->qstats, &qstats, sizeof(qstats));
+ node->next = node->children = NULL;
+
+ if (*root == NULL)
+ *root = node;
+ else if (!altq.parent[0]) {
+ struct pf_altq_node *prev = *root;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ } else {
+ struct pf_altq_node *parent;
+
+ parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
+ if (parent == NULL)
+ errx(1, "parent %s not found", altq.parent);
+ if (parent->children == NULL)
+ parent->children = node;
+ else {
+ struct pf_altq_node *prev = parent->children;
+
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = node;
+ }
+ }
+ update_avg(node);
+}
+
+struct pf_altq_node *
+pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
+ const char *ifname)
+{
+ struct pf_altq_node *node, *child;
+
+ for (node = root; node != NULL; node = node->next) {
+ if (!strcmp(node->altq.qname, qname)
+ && !(strcmp(node->altq.ifname, ifname)))
+ return (node);
+ if (node->children != NULL) {
+ child = pfctl_find_altq_node(node->children, qname,
+ ifname);
+ if (child != NULL)
+ return (child);
+ }
+ }
+ return (NULL);
+}
+
+void
+pfctl_print_altq_node(int dev, const struct pf_altq_node *node,
+ unsigned int level, int opts)
+{
+ const struct pf_altq_node *child;
+
+ if (node == NULL)
+ return;
+
+ print_altq(&node->altq, level, NULL, NULL);
+
+ if (node->children != NULL) {
+ printf("{");
+ for (child = node->children; child != NULL;
+ child = child->next) {
+ printf("%s", child->altq.qname);
+ if (child->next != NULL)
+ printf(", ");
+ }
+ printf("}");
+ }
+ printf("\n");
+
+ if (opts & PF_OPT_VERBOSE)
+ pfctl_print_altq_nodestat(dev, node);
+
+ if (opts & PF_OPT_DEBUG)
+ printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n",
+ node->altq.qid, node->altq.ifname,
+ rate2str((double)(node->altq.ifbandwidth)));
+
+ for (child = node->children; child != NULL;
+ child = child->next)
+ pfctl_print_altq_node(dev, child, level + 1, opts);
+}
+
+void
+pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
+{
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
+ return;
+
+#ifdef __FreeBSD__
+ if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED)
+ return;
+#endif
+ switch (a->altq.scheduler) {
+ case ALTQT_CBQ:
+ print_cbqstats(a->qstats);
+ break;
+ case ALTQT_PRIQ:
+ print_priqstats(a->qstats);
+ break;
+ case ALTQT_HFSC:
+ print_hfscstats(a->qstats);
+ break;
+ case ALTQT_FAIRQ:
+ print_fairqstats(a->qstats);
+ break;
+ case ALTQT_CODEL:
+ print_codelstats(a->qstats);
+ break;
+ }
+}
+
+void
+print_cbqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n",
+ cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
+ cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_codelstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets +
+ cur.data.codel_stats.stats.drop_cnt.packets,
+ (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes +
+ cur.data.codel_stats.stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_priqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
+ (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
+ (unsigned long long)cur.data.priq_stats.dropcnt.packets,
+ (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_hfscstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+print_fairqstats(struct queue_stats cur)
+{
+ printf(" [ pkts: %10llu bytes: %10llu "
+ "dropped pkts: %6llu bytes: %6llu ]\n",
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.packets,
+ (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes);
+ printf(" [ qlength: %3d/%3d ]\n",
+ cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit);
+
+ if (cur.avgn < 2)
+ return;
+
+ printf(" [ measured: %7.1f packets/s, %s/s ]\n",
+ cur.avg_packets / STAT_INTERVAL,
+ rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
+}
+
+void
+pfctl_free_altq_node(struct pf_altq_node *node)
+{
+ while (node != NULL) {
+ struct pf_altq_node *prev;
+
+ if (node->children != NULL)
+ pfctl_free_altq_node(node->children);
+ prev = node;
+ node = node->next;
+ free(prev);
+ }
+}
+
+void
+update_avg(struct pf_altq_node *a)
+{
+ struct queue_stats *qs;
+ u_int64_t b, p;
+ int n;
+
+ if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL)
+ return;
+
+ qs = &a->qstats;
+ n = qs->avgn;
+
+ switch (a->altq.scheduler) {
+ case ALTQT_CBQ:
+ b = qs->data.cbq_stats.xmit_cnt.bytes;
+ p = qs->data.cbq_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_PRIQ:
+ b = qs->data.priq_stats.xmitcnt.bytes;
+ p = qs->data.priq_stats.xmitcnt.packets;
+ break;
+ case ALTQT_HFSC:
+ b = qs->data.hfsc_stats.xmit_cnt.bytes;
+ p = qs->data.hfsc_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_FAIRQ:
+ b = qs->data.fairq_stats.xmit_cnt.bytes;
+ p = qs->data.fairq_stats.xmit_cnt.packets;
+ break;
+ case ALTQT_CODEL:
+ b = qs->data.codel_stats.cl_xmitcnt.bytes;
+ p = qs->data.codel_stats.cl_xmitcnt.packets;
+ break;
+ default:
+ b = 0;
+ p = 0;
+ break;
+ }
+
+ if (n == 0) {
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ qs->avgn++;
+ return;
+ }
+
+ if (b >= qs->prev_bytes)
+ qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
+ (b - qs->prev_bytes)) / n;
+
+ if (p >= qs->prev_packets)
+ qs->avg_packets = ((qs->avg_packets * (n - 1)) +
+ (p - qs->prev_packets)) / n;
+
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ if (n < AVGN_MAX)
+ qs->avgn++;
+}
diff --git a/freebsd/sbin/pfctl/pfctl_radix.c b/freebsd/sbin/pfctl/pfctl_radix.c
new file mode 100644
index 00000000..c151f878
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_radix.c
@@ -0,0 +1,597 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <err.h>
+
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_radix-data.h"
+#endif /* __rtems__ */
+
+#define BUF_SIZE 256
+
+extern int dev;
+
+static int pfr_next_token(char buf[], FILE *);
+
+
+int
+pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ if (ioctl(dev, DIOCRCLRTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRADDTABLES, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRDELTABLES, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETTABLES, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (size == NULL || *size < 0 || (*size && tbl == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ if (filter != NULL)
+ io.pfrio_table = *filter;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETTSTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ if (ioctl(dev, DIOCRCLRADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRADDADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ return (0);
+}
+
+int
+pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *ndel, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRDELADDRS, &io))
+ return (-1);
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ return (0);
+}
+
+int
+pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *size2, int *nadd, int *ndel, int *nchange, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
+ if (ioctl(dev, DIOCRSETADDRS, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (ndel != NULL)
+ *ndel = io.pfrio_ndel;
+ if (nchange != NULL)
+ *nchange = io.pfrio_nchange;
+ if (size2 != NULL)
+ *size2 = io.pfrio_size2;
+ return (0);
+}
+
+int
+pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 ||
+ (*size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETADDRS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size,
+ int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size == NULL || *size < 0 ||
+ (*size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = *size;
+ if (ioctl(dev, DIOCRGETASTATS, &io))
+ return (-1);
+ *size = io.pfrio_size;
+ return (0);
+}
+
+int
+pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags)
+{
+ struct pfioc_table io;
+
+ if (size < 0 || (size && !tbl)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_buffer = tbl;
+ io.pfrio_esize = sizeof(*tbl);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRCLRTSTATS, &io))
+ return (-1);
+ if (nzero)
+ *nzero = io.pfrio_nzero;
+ return (0);
+}
+
+int
+pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nmatch, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ if (ioctl(dev, DIOCRTSTADDRS, &io))
+ return (-1);
+ if (nmatch)
+ *nmatch = io.pfrio_nmatch;
+ return (0);
+}
+
+int
+pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size,
+ int *nadd, int *naddr, int ticket, int flags)
+{
+ struct pfioc_table io;
+
+ if (tbl == NULL || size < 0 || (size && addr == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ io.pfrio_flags = flags;
+ io.pfrio_table = *tbl;
+ io.pfrio_buffer = addr;
+ io.pfrio_esize = sizeof(*addr);
+ io.pfrio_size = size;
+ io.pfrio_ticket = ticket;
+ if (ioctl(dev, DIOCRINADEFINE, &io))
+ return (-1);
+ if (nadd != NULL)
+ *nadd = io.pfrio_nadd;
+ if (naddr != NULL)
+ *naddr = io.pfrio_naddr;
+ return (0);
+}
+
+/* interface management code */
+
+int
+pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size)
+{
+ struct pfioc_iface io;
+
+ if (size == NULL || *size < 0 || (*size && buf == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bzero(&io, sizeof io);
+ if (filter != NULL)
+ if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >=
+ sizeof(io.pfiio_name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ io.pfiio_buffer = buf;
+ io.pfiio_esize = sizeof(*buf);
+ io.pfiio_size = *size;
+ if (ioctl(dev, DIOCIGETIFACES, &io))
+ return (-1);
+ *size = io.pfiio_size;
+ return (0);
+}
+
+/* buffer management code */
+
+const size_t buf_esize[PFRB_MAX] = { 0,
+ sizeof(struct pfr_table), sizeof(struct pfr_tstats),
+ sizeof(struct pfr_addr), sizeof(struct pfr_astats),
+ sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e)
+};
+
+/*
+ * add one element to the buffer
+ */
+int
+pfr_buf_add(struct pfr_buffer *b, const void *e)
+{
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX ||
+ e == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bs = buf_esize[b->pfrb_type];
+ if (b->pfrb_size == b->pfrb_msize)
+ if (pfr_buf_grow(b, 0))
+ return (-1);
+ memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs);
+ b->pfrb_size++;
+ return (0);
+}
+
+/*
+ * return next element of the buffer (or first one if prev is NULL)
+ * see PFRB_FOREACH macro
+ */
+void *
+pfr_buf_next(struct pfr_buffer *b, const void *prev)
+{
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX)
+ return (NULL);
+ if (b->pfrb_size == 0)
+ return (NULL);
+ if (prev == NULL)
+ return (b->pfrb_caddr);
+ bs = buf_esize[b->pfrb_type];
+ if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1)
+ return (NULL);
+ return (((caddr_t)prev) + bs);
+}
+
+/*
+ * minsize:
+ * 0: make the buffer somewhat bigger
+ * n: make room for "n" entries in the buffer
+ */
+int
+pfr_buf_grow(struct pfr_buffer *b, int minsize)
+{
+ caddr_t p;
+ size_t bs;
+
+ if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (minsize != 0 && minsize <= b->pfrb_msize)
+ return (0);
+ bs = buf_esize[b->pfrb_type];
+ if (!b->pfrb_msize) {
+ if (minsize < 64)
+ minsize = 64;
+ b->pfrb_caddr = calloc(bs, minsize);
+ if (b->pfrb_caddr == NULL)
+ return (-1);
+ b->pfrb_msize = minsize;
+ } else {
+ if (minsize == 0)
+ minsize = b->pfrb_msize * 2;
+ if (minsize < 0 || minsize >= SIZE_T_MAX / bs) {
+ /* msize overflow */
+ errno = ENOMEM;
+ return (-1);
+ }
+ p = realloc(b->pfrb_caddr, minsize * bs);
+ if (p == NULL)
+ return (-1);
+ bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs);
+ b->pfrb_caddr = p;
+ b->pfrb_msize = minsize;
+ }
+ return (0);
+}
+
+/*
+ * reset buffer and free memory.
+ */
+void
+pfr_buf_clear(struct pfr_buffer *b)
+{
+ if (b == NULL)
+ return;
+ if (b->pfrb_caddr != NULL)
+ free(b->pfrb_caddr);
+ b->pfrb_caddr = NULL;
+ b->pfrb_size = b->pfrb_msize = 0;
+}
+
+int
+pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork,
+ int (*append_addr)(struct pfr_buffer *, char *, int))
+{
+ FILE *fp;
+ char buf[BUF_SIZE];
+ int rv;
+
+ if (file == NULL)
+ return (0);
+ if (!strcmp(file, "-"))
+ fp = stdin;
+ else {
+ fp = pfctl_fopen(file, "r");
+ if (fp == NULL)
+ return (-1);
+ }
+ while ((rv = pfr_next_token(buf, fp)) == 1)
+ if (append_addr(b, buf, nonetwork)) {
+ rv = -1;
+ break;
+ }
+ if (fp != stdin)
+ fclose(fp);
+ return (rv);
+}
+
+int
+pfr_next_token(char buf[BUF_SIZE], FILE *fp)
+{
+ static char next_ch = ' ';
+ int i = 0;
+
+ for (;;) {
+ /* skip spaces */
+ while (isspace(next_ch) && !feof(fp))
+ next_ch = fgetc(fp);
+ /* remove from '#' until end of line */
+ if (next_ch == '#')
+ while (!feof(fp)) {
+ next_ch = fgetc(fp);
+ if (next_ch == '\n')
+ break;
+ }
+ else
+ break;
+ }
+ if (feof(fp)) {
+ next_ch = ' ';
+ return (0);
+ }
+ do {
+ if (i < BUF_SIZE)
+ buf[i++] = next_ch;
+ next_ch = fgetc(fp);
+ } while (!feof(fp) && !isspace(next_ch));
+ if (i >= BUF_SIZE) {
+ errno = EINVAL;
+ return (-1);
+ }
+ buf[i] = '\0';
+ return (1);
+}
+
+char *
+pfr_strerror(int errnum)
+{
+ switch (errnum) {
+ case ESRCH:
+ return "Table does not exist";
+ case ENOENT:
+ return "Anchor or Ruleset does not exist";
+ default:
+ return strerror(errnum);
+ }
+}
diff --git a/freebsd/sbin/pfctl/pfctl_table.c b/freebsd/sbin/pfctl/pfctl_table.c
new file mode 100644
index 00000000..4dfb0689
--- /dev/null
+++ b/freebsd/sbin/pfctl/pfctl_table.c
@@ -0,0 +1,650 @@
+#include <machine/rtems-bsd-user-space.h>
+
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-namespace.h"
+#endif /* __rtems__ */
+
+/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */
+
+/*
+ * Copyright (c) 2002 Cedric Berger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef __rtems__
+#include <machine/rtems-bsd-program.h>
+#endif /* __rtems__ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+#ifdef __rtems__
+#include "rtems-bsd-pfctl-pfctl_table-data.h"
+#endif /* __rtems__ */
+
+extern void usage(void);
+static int pfctl_table(int, char *[], char *, const char *, char *,
+ const char *, int);
+static void print_table(struct pfr_table *, int, int);
+static void print_tstats(struct pfr_tstats *, int);
+static int load_addr(struct pfr_buffer *, int, char *[], char *, int);
+static void print_addrx(struct pfr_addr *, struct pfr_addr *, int);
+static void print_astats(struct pfr_astats *, int);
+static void radix_perror(void);
+static void xprintf(int, const char *, ...);
+static void print_iface(struct pfi_kif *, int);
+
+static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = {
+ { "In/Block:", "In/Pass:", "In/XPass:" },
+ { "Out/Block:", "Out/Pass:", "Out/XPass:" }
+};
+
+static const char *istats_text[2][2][2] = {
+ { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } },
+ { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } }
+};
+
+#define RVTEST(fct) do { \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (fct)) { \
+ radix_perror(); \
+ goto _error; \
+ } \
+ } while (0)
+
+#define CREATE_TABLE do { \
+ table.pfrt_flags |= PFR_TFLAG_PERSIST; \
+ if ((!(opts & PF_OPT_NOACTION) || \
+ (opts & PF_OPT_DUMMYACTION)) && \
+ (pfr_add_tables(&table, 1, &nadd, flags)) && \
+ (errno != EPERM)) { \
+ radix_perror(); \
+ goto _error; \
+ } \
+ if (nadd) { \
+ warn_namespace_collision(table.pfrt_name); \
+ xprintf(opts, "%d table created", nadd); \
+ if (opts & PF_OPT_NOACTION) \
+ return (0); \
+ } \
+ table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \
+ } while(0)
+
+int
+pfctl_clear_tables(const char *anchor, int opts)
+{
+ return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts);
+}
+
+int
+pfctl_show_tables(const char *anchor, int opts)
+{
+ return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts);
+}
+
+int
+pfctl_command_tables(int argc, char *argv[], char *tname,
+ const char *command, char *file, const char *anchor, int opts)
+{
+ if (tname == NULL || command == NULL)
+ usage();
+ return pfctl_table(argc, argv, tname, command, file, anchor, opts);
+}
+
+int
+pfctl_table(int argc, char *argv[], char *tname, const char *command,
+ char *file, const char *anchor, int opts)
+{
+ struct pfr_table table;
+ struct pfr_buffer b, b2;
+ struct pfr_addr *a, *a2;
+ int nadd = 0, ndel = 0, nchange = 0, nzero = 0;
+ int rv = 0, flags = 0, nmatch = 0;
+ void *p;
+
+ if (command == NULL)
+ usage();
+ if (opts & PF_OPT_NOACTION)
+ flags |= PFR_FLAG_DUMMY;
+
+ bzero(&b, sizeof(b));
+ bzero(&b2, sizeof(b2));
+ bzero(&table, sizeof(table));
+ if (tname != NULL) {
+ if (strlen(tname) >= PF_TABLE_NAME_SIZE)
+ usage();
+ if (strlcpy(table.pfrt_name, tname,
+ sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
+ errx(1, "pfctl_table: strlcpy");
+ }
+ if (strlcpy(table.pfrt_anchor, anchor,
+ sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor))
+ errx(1, "pfctl_table: strlcpy");
+
+ if (!strcmp(command, "-F")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_tables(&table, &ndel, flags));
+ xprintf(opts, "%d tables deleted", ndel);
+ } else if (!strcmp(command, "-s")) {
+ b.pfrb_type = (opts & PF_OPT_VERBOSE2) ?
+ PFRB_TSTATS : PFRB_TABLES;
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (opts & PF_OPT_VERBOSE2)
+ RVTEST(pfr_get_tstats(&table,
+ b.pfrb_caddr, &b.pfrb_size, flags));
+ else
+ RVTEST(pfr_get_tables(&table,
+ b.pfrb_caddr, &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+
+ if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0)
+ pfctl_print_title("TABLES:");
+
+ PFRB_FOREACH(p, &b)
+ if (opts & PF_OPT_VERBOSE2)
+ print_tstats(p, opts & PF_OPT_DEBUG);
+ else
+ print_table(p, opts & PF_OPT_VERBOSE,
+ opts & PF_OPT_DEBUG);
+ } else if (!strcmp(command, "kill")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_del_tables(&table, 1, &ndel, flags));
+ xprintf(opts, "%d table deleted", ndel);
+ } else if (!strcmp(command, "flush")) {
+ if (argc || file != NULL)
+ usage();
+ RVTEST(pfr_clr_addrs(&table, &ndel, flags));
+ xprintf(opts, "%d addresses deleted", ndel);
+ } else if (!strcmp(command, "add")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ CREATE_TABLE;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &nadd, flags));
+ xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "delete")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &ndel, flags));
+ xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "replace")) {
+ b.pfrb_type = PFRB_ADDRS;
+ if (load_addr(&b, argc, argv, file, 0))
+ goto _error;
+ CREATE_TABLE;
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ for (;;) {
+ int sz2 = b.pfrb_msize;
+
+ RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &sz2, &nadd, &ndel, &nchange, flags));
+ if (sz2 <= b.pfrb_msize) {
+ b.pfrb_size = sz2;
+ break;
+ } else
+ pfr_buf_grow(&b, sz2);
+ }
+ if (nadd)
+ xprintf(opts, "%d addresses added", nadd);
+ if (ndel)
+ xprintf(opts, "%d addresses deleted", ndel);
+ if (nchange)
+ xprintf(opts, "%d addresses changed", nchange);
+ if (!nadd && !ndel && !nchange)
+ xprintf(opts, "no changes");
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "expire")) {
+ const char *errstr;
+ u_int lifetime;
+
+ b.pfrb_type = PFRB_ASTATS;
+ b2.pfrb_type = PFRB_ADDRS;
+ if (argc != 1 || file != NULL)
+ usage();
+ lifetime = strtonum(*argv, 0, UINT_MAX, &errstr);
+ if (errstr)
+ errx(1, "expiry time: %s", errstr);
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(p, &b) {
+ ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0;
+ if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero >
+ lifetime)
+ if (pfr_buf_add(&b2,
+ &((struct pfr_astats *)p)->pfras_a))
+ err(1, "duplicate buffer");
+ }
+
+ if (opts & PF_OPT_VERBOSE)
+ flags |= PFR_FLAG_FEEDBACK;
+ RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size,
+ &ndel, flags));
+ xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size);
+ if (opts & PF_OPT_VERBOSE)
+ PFRB_FOREACH(a, &b2)
+ if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "show")) {
+ b.pfrb_type = (opts & PF_OPT_VERBOSE) ?
+ PFRB_ASTATS : PFRB_ADDRS;
+ if (argc || file != NULL)
+ usage();
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (opts & PF_OPT_VERBOSE)
+ RVTEST(pfr_get_astats(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ else
+ RVTEST(pfr_get_addrs(&table, b.pfrb_caddr,
+ &b.pfrb_size, flags));
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(p, &b)
+ if (opts & PF_OPT_VERBOSE)
+ print_astats(p, opts & PF_OPT_USEDNS);
+ else
+ print_addrx(p, NULL, opts & PF_OPT_USEDNS);
+ } else if (!strcmp(command, "test")) {
+ b.pfrb_type = PFRB_ADDRS;
+ b2.pfrb_type = PFRB_ADDRS;
+
+ if (load_addr(&b, argc, argv, file, 1))
+ goto _error;
+ if (opts & PF_OPT_VERBOSE2) {
+ flags |= PFR_FLAG_REPLACE;
+ PFRB_FOREACH(a, &b)
+ if (pfr_buf_add(&b2, a))
+ err(1, "duplicate buffer");
+ }
+ RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size,
+ &nmatch, flags));
+ xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size);
+ if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2))
+ PFRB_FOREACH(a, &b)
+ if (a->pfra_fback == PFR_FB_MATCH)
+ print_addrx(a, NULL,
+ opts & PF_OPT_USEDNS);
+ if (opts & PF_OPT_VERBOSE2) {
+ a2 = NULL;
+ PFRB_FOREACH(a, &b) {
+ a2 = pfr_buf_next(&b2, a2);
+ print_addrx(a2, a, opts & PF_OPT_USEDNS);
+ }
+ }
+ if (nmatch < b.pfrb_size)
+ rv = 2;
+ } else if (!strcmp(command, "zero")) {
+ if (argc || file != NULL)
+ usage();
+ flags |= PFR_FLAG_ADDRSTOO;
+ RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags));
+ xprintf(opts, "%d table/stats cleared", nzero);
+ } else
+ warnx("pfctl_table: unknown command '%s'", command);
+ goto _cleanup;
+
+_error:
+ rv = -1;
+_cleanup:
+ pfr_buf_clear(&b);
+ pfr_buf_clear(&b2);
+ return (rv);
+}
+
+void
+print_table(struct pfr_table *ta, int verbose, int debug)
+{
+ if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE))
+ return;
+ if (verbose) {
+ printf("%c%c%c%c%c%c%c\t%s",
+ (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-',
+ (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-',
+ ta->pfrt_name);
+ if (ta->pfrt_anchor[0])
+ printf("\t%s", ta->pfrt_anchor);
+ puts("");
+ } else
+ puts(ta->pfrt_name);
+}
+
+void
+print_tstats(struct pfr_tstats *ts, int debug)
+{
+ time_t time = ts->pfrts_tzero;
+ int dir, op;
+
+ if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
+ return;
+ print_table(&ts->pfrts_t, 1, debug);
+ printf("\tAddresses: %d\n", ts->pfrts_cnt);
+ printf("\tCleared: %s", ctime(&time));
+ printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n",
+ ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
+ ts->pfrts_refcnt[PFR_REFCNT_RULE]);
+ printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n",
+ (unsigned long long)ts->pfrts_nomatch,
+ (unsigned long long)ts->pfrts_match);
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_TABLE_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ (unsigned long long)ts->pfrts_packets[dir][op],
+ (unsigned long long)ts->pfrts_bytes[dir][op]);
+}
+
+int
+load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file,
+ int nonetwork)
+{
+ while (argc--)
+ if (append_addr(b, *argv++, nonetwork)) {
+ if (errno)
+ warn("cannot decode %s", argv[-1]);
+ return (-1);
+ }
+ if (pfr_buf_load(b, file, nonetwork, append_addr)) {
+ warn("cannot load %s", file);
+ return (-1);
+ }
+ return (0);
+}
+
+void
+print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
+{
+ char ch, buf[256] = "{error}";
+ char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' };
+ unsigned int fback, hostnet;
+
+ fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback;
+ ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?';
+ hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32;
+ inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf));
+ printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf);
+ if (ad->pfra_net < hostnet)
+ printf("/%d", ad->pfra_net);
+ if (rad != NULL && fback != PFR_FB_NONE) {
+ if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf))
+ errx(1, "print_addrx: strlcpy");
+ inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf));
+ printf("\t%c%s", (rad->pfra_not?'!':' '), buf);
+ if (rad->pfra_net < hostnet)
+ printf("/%d", rad->pfra_net);
+ }
+ if (rad != NULL && fback == PFR_FB_NONE)
+ printf("\t nomatch");
+ if (dns && ad->pfra_net == hostnet) {
+ char host[NI_MAXHOST];
+ union sockaddr_union sa;
+
+ strlcpy(host, "?", sizeof(host));
+ bzero(&sa, sizeof(sa));
+ sa.sa.sa_family = ad->pfra_af;
+ if (sa.sa.sa_family == AF_INET) {
+ sa.sa.sa_len = sizeof(sa.sin);
+ sa.sin.sin_addr = ad->pfra_ip4addr;
+ } else {
+ sa.sa.sa_len = sizeof(sa.sin6);
+ sa.sin6.sin6_addr = ad->pfra_ip6addr;
+ }
+ if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host),
+ NULL, 0, NI_NAMEREQD) == 0)
+ printf("\t(%s)", host);
+ }
+ printf("\n");
+}
+
+void
+print_astats(struct pfr_astats *as, int dns)
+{
+ time_t time = as->pfras_tzero;
+ int dir, op;
+
+ print_addrx(&as->pfras_a, NULL, dns);
+ printf("\tCleared: %s", ctime(&time));
+ if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT)
+ return;
+ for (dir = 0; dir < PFR_DIR_MAX; dir++)
+ for (op = 0; op < PFR_OP_ADDR_MAX; op++)
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ stats_text[dir][op],
+ (unsigned long long)as->pfras_packets[dir][op],
+ (unsigned long long)as->pfras_bytes[dir][op]);
+}
+
+void
+radix_perror(void)
+{
+#ifndef __rtems__
+ extern char *__progname;
+#else /* __rtems__ */
+#define __progname "pfctl"
+#endif /* __rtems__ */
+ fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno));
+}
+
+int
+pfctl_define_table(char *name, int flags, int addrs, const char *anchor,
+ struct pfr_buffer *ab, u_int32_t ticket)
+{
+ struct pfr_table tbl;
+
+ bzero(&tbl, sizeof(tbl));
+ if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >=
+ sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor,
+ sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor))
+ errx(1, "pfctl_define_table: strlcpy");
+ tbl.pfrt_flags = flags;
+
+ return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL,
+ NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0);
+}
+
+void
+warn_namespace_collision(const char *filter)
+{
+ struct pfr_buffer b;
+ struct pfr_table *t;
+ const char *name = NULL, *lastcoll;
+ int coll = 0;
+
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_TABLES;
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfr_get_tables(NULL, b.pfrb_caddr,
+ &b.pfrb_size, PFR_FLAG_ALLRSETS))
+ err(1, "pfr_get_tables");
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ }
+ PFRB_FOREACH(t, &b) {
+ if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE))
+ continue;
+ if (filter != NULL && strcmp(filter, t->pfrt_name))
+ continue;
+ if (!t->pfrt_anchor[0])
+ name = t->pfrt_name;
+ else if (name != NULL && !strcmp(name, t->pfrt_name)) {
+ coll++;
+ lastcoll = name;
+ name = NULL;
+ }
+ }
+ if (coll == 1)
+ warnx("warning: namespace collision with <%s> global table.",
+ lastcoll);
+ else if (coll > 1)
+ warnx("warning: namespace collisions with %d global tables.",
+ coll);
+ pfr_buf_clear(&b);
+}
+
+void
+xprintf(int opts, const char *fmt, ...)
+{
+ va_list args;
+
+ if (opts & PF_OPT_QUIET)
+ return;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ if (opts & PF_OPT_DUMMYACTION)
+ fprintf(stderr, " (dummy).\n");
+ else if (opts & PF_OPT_NOACTION)
+ fprintf(stderr, " (syntax only).\n");
+ else
+ fprintf(stderr, ".\n");
+}
+
+
+/* interface stuff */
+
+int
+pfctl_show_ifaces(const char *filter, int opts)
+{
+ struct pfr_buffer b;
+ struct pfi_kif *p;
+ int i = 0;
+
+ bzero(&b, sizeof(b));
+ b.pfrb_type = PFRB_IFACES;
+ for (;;) {
+ pfr_buf_grow(&b, b.pfrb_size);
+ b.pfrb_size = b.pfrb_msize;
+ if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) {
+ radix_perror();
+ return (1);
+ }
+ if (b.pfrb_size <= b.pfrb_msize)
+ break;
+ i++;
+ }
+ if (opts & PF_OPT_SHOWALL)
+ pfctl_print_title("INTERFACES:");
+ PFRB_FOREACH(p, &b)
+ print_iface(p, opts);
+ return (0);
+}
+
+void
+print_iface(struct pfi_kif *p, int opts)
+{
+ time_t tzero = p->pfik_tzero;
+ int i, af, dir, act;
+
+ printf("%s", p->pfik_name);
+ if (opts & PF_OPT_VERBOSE) {
+ if (p->pfik_flags & PFI_IFLAG_SKIP)
+ printf(" (skip)");
+ }
+ printf("\n");
+
+ if (!(opts & PF_OPT_VERBOSE2))
+ return;
+ printf("\tCleared: %s", ctime(&tzero));
+ printf("\tReferences: %-18d\n", p->pfik_rulerefs);
+ for (i = 0; i < 8; i++) {
+ af = (i>>2) & 1;
+ dir = (i>>1) &1;
+ act = i & 1;
+ printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n",
+ istats_text[af][dir][act],
+ (unsigned long long)p->pfik_packets[af][dir][act],
+ (unsigned long long)p->pfik_bytes[af][dir][act]);
+ }
+}
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h
new file mode 100644
index 00000000..3984522e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h
@@ -0,0 +1,25 @@
+/* generated by userspace-header-gen.py */
+/*
+ * NOTE: MANUALLY CHANGED.
+ * YACC needs a special treatment for some variables. They are commented here.
+ */
+#include <rtems/linkersets.h>
+/* parse.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlydebug);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlynerrs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlyerrflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlychar);
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval); */
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval); */
+/* pfctl_altq.c */
+/* pfctl.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int loadopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int altqsupport);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int dev);
+/* pfctl_optimize.c */
+/* pfctl_osfp.c */
+/* pfctl_parser.c */
+/* pfctl_qstats.c */
+/* pfctl_radix.c */
+/* pfctl_table.c */
+/* pf_print_state.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h
new file mode 100644
index 00000000..4e815fee
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h
@@ -0,0 +1,262 @@
+/* generated by userspace-header-gen.py */
+/* parse.c */
+#define pfctlydebug _bsd_pfctl_pfctlydebug
+#define pfctlynerrs _bsd_pfctl_pfctlynerrs
+#define pfctlyerrflag _bsd_pfctl_pfctlyerrflag
+#define pfctlychar _bsd_pfctl_pfctlychar
+#define pfctlyval _bsd_pfctl_pfctlyval
+#define pfctlylval _bsd_pfctl_pfctlylval
+#define pfctlyparse _bsd_pfctl_pfctlyparse
+#define rt_tableid_max _bsd_pfctl_rt_tableid_max
+#define pfctl_load_anchors _bsd_pfctl_pfctl_load_anchors
+#define parseport _bsd_pfctl_parseport
+#define parseicmpspec _bsd_pfctl_parseicmpspec
+#define rule_label _bsd_pfctl_rule_label
+#define getservice _bsd_pfctl_getservice
+#define atoul _bsd_pfctl_atoul
+#define invalid_redirect _bsd_pfctl_invalid_redirect
+#define remove_invalid_hosts _bsd_pfctl_remove_invalid_hosts
+#define decide_address_family _bsd_pfctl_decide_address_family
+#define mv_rules _bsd_pfctl_mv_rules
+#define symget _bsd_pfctl_symget
+#define pfctl_cmdline_symset _bsd_pfctl_pfctl_cmdline_symset
+#define symset _bsd_pfctl_symset
+#define parse_config _bsd_pfctl_parse_config
+#define popfile _bsd_pfctl_popfile
+#define pushfile _bsd_pfctl_pushfile
+#define check_file_secrecy _bsd_pfctl_check_file_secrecy
+#define pfctlylex _bsd_pfctl_pfctlylex
+#define findeol _bsd_pfctl_findeol
+#define lungetc _bsd_pfctl_lungetc
+#define lgetc _bsd_pfctl_lgetc
+#define lookup _bsd_pfctl_lookup
+#define kw_cmp _bsd_pfctl_kw_cmp
+#define check_rulestate _bsd_pfctl_check_rulestate
+#define expand_skip_interface _bsd_pfctl_expand_skip_interface
+#define expand_rule _bsd_pfctl_expand_rule
+#define expand_queue _bsd_pfctl_expand_queue
+#define expand_altq _bsd_pfctl_expand_altq
+#define expand_label _bsd_pfctl_expand_label
+#define expand_label_nr _bsd_pfctl_expand_label_nr
+#define expand_label_proto _bsd_pfctl_expand_label_proto
+#define expand_label_port _bsd_pfctl_expand_label_port
+#define expand_label_addr _bsd_pfctl_expand_label_addr
+#define expand_label_if _bsd_pfctl_expand_label_if
+#define expand_label_str _bsd_pfctl_expand_label_str
+#define process_tabledef _bsd_pfctl_process_tabledef
+#define rdr_consistent _bsd_pfctl_rdr_consistent
+#define nat_consistent _bsd_pfctl_nat_consistent
+#define filter_consistent _bsd_pfctl_filter_consistent
+#define rule_consistent _bsd_pfctl_rule_consistent
+#define disallow_alias _bsd_pfctl_disallow_alias
+#define disallow_urpf_failed _bsd_pfctl_disallow_urpf_failed
+#define disallow_table _bsd_pfctl_disallow_table
+#define pfctlyerror _bsd_pfctl_pfctlyerror
+/* pfctl_altq.c */
+#define print_fairq_sc _bsd_pfctl_print_fairq_sc
+#define print_hfsc_sc _bsd_pfctl_print_hfsc_sc
+#define eval_bwspec _bsd_pfctl_eval_bwspec
+#define eval_queue_opts _bsd_pfctl_eval_queue_opts
+#define getifmtu _bsd_pfctl_getifmtu
+#define getifspeed _bsd_pfctl_getifspeed
+#define rate2str _bsd_pfctl_rate2str
+#define eval_pfqueue _bsd_pfctl_eval_pfqueue
+#define check_commit_altq _bsd_pfctl_check_commit_altq
+#define eval_pfaltq _bsd_pfctl_eval_pfaltq
+#define print_queue _bsd_pfctl_print_queue
+#define print_altq _bsd_pfctl_print_altq
+#define qname_to_qid _bsd_pfctl_qname_to_qid
+#define qname_to_pfaltq _bsd_pfctl_qname_to_pfaltq
+#define pfaltq_lookup _bsd_pfctl_pfaltq_lookup
+#define pfaltq_store _bsd_pfctl_pfaltq_store
+/* pfctl.c */
+#define loadopt _bsd_pfctl_loadopt
+#define altqsupport _bsd_pfctl_altqsupport
+#define dev _bsd_pfctl_dev
+#define pfctl_lookup_option _bsd_pfctl_pfctl_lookup_option
+#define pfctl_show_anchors _bsd_pfctl_pfctl_show_anchors
+#define pfctl_test_altqsupport _bsd_pfctl_pfctl_test_altqsupport
+#define pfctl_debug _bsd_pfctl_pfctl_debug
+#define pfctl_set_interface_flags _bsd_pfctl_pfctl_set_interface_flags
+#define pfctl_load_debug _bsd_pfctl_pfctl_load_debug
+#define pfctl_set_debug _bsd_pfctl_pfctl_set_debug
+#define pfctl_load_hostid _bsd_pfctl_pfctl_load_hostid
+#define pfctl_set_hostid _bsd_pfctl_pfctl_set_hostid
+#define pfctl_load_logif _bsd_pfctl_pfctl_load_logif
+#define pfctl_set_logif _bsd_pfctl_pfctl_set_logif
+#define pfctl_set_optimization _bsd_pfctl_pfctl_set_optimization
+#define pfctl_load_timeout _bsd_pfctl_pfctl_load_timeout
+#define pfctl_set_timeout _bsd_pfctl_pfctl_set_timeout
+#define pfctl_load_limit _bsd_pfctl_pfctl_load_limit
+#define pfctl_set_limit _bsd_pfctl_pfctl_set_limit
+#define pfctl_load_options _bsd_pfctl_pfctl_load_options
+#define pfctl_init_options _bsd_pfctl_pfctl_init_options
+#define pfctl_fopen _bsd_pfctl_pfctl_fopen
+#define pfctl_rules _bsd_pfctl_pfctl_rules
+#define pfctl_add_altq _bsd_pfctl_pfctl_add_altq
+#define pfctl_load_rule _bsd_pfctl_pfctl_load_rule
+#define pfctl_load_ruleset _bsd_pfctl_pfctl_load_ruleset
+#define pfctl_ruleset_trans _bsd_pfctl_pfctl_ruleset_trans
+#define pfctl_add_rule _bsd_pfctl_pfctl_add_rule
+#define pfctl_add_pool _bsd_pfctl_pfctl_add_pool
+#define pfctl_show_limits _bsd_pfctl_pfctl_show_limits
+#define pfctl_show_timeouts _bsd_pfctl_pfctl_show_timeouts
+#define pfctl_show_status _bsd_pfctl_pfctl_show_status
+#define pfctl_show_states _bsd_pfctl_pfctl_show_states
+#define pfctl_show_src_nodes _bsd_pfctl_pfctl_show_src_nodes
+#define pfctl_show_nat _bsd_pfctl_pfctl_show_nat
+#define pfctl_show_rules _bsd_pfctl_pfctl_show_rules
+#define pfctl_print_title _bsd_pfctl_pfctl_print_title
+#define pfctl_print_rule_counters _bsd_pfctl_pfctl_print_rule_counters
+#define pfctl_clear_pool _bsd_pfctl_pfctl_clear_pool
+#define pfctl_move_pool _bsd_pfctl_pfctl_move_pool
+#define pfctl_get_pool _bsd_pfctl_pfctl_get_pool
+#define pfctl_id_kill_states _bsd_pfctl_pfctl_id_kill_states
+#define pfctl_label_kill_states _bsd_pfctl_pfctl_label_kill_states
+#define pfctl_net_kill_states _bsd_pfctl_pfctl_net_kill_states
+#define pfctl_kill_src_nodes _bsd_pfctl_pfctl_kill_src_nodes
+#define pfctl_addrprefix _bsd_pfctl_pfctl_addrprefix
+#define pfctl_clear_states _bsd_pfctl_pfctl_clear_states
+#define pfctl_clear_src_nodes _bsd_pfctl_pfctl_clear_src_nodes
+#define pfctl_clear_altq _bsd_pfctl_pfctl_clear_altq
+#define pfctl_clear_nat _bsd_pfctl_pfctl_clear_nat
+#define pfctl_clear_rules _bsd_pfctl_pfctl_clear_rules
+#define pfctl_clear_interface_flags _bsd_pfctl_pfctl_clear_interface_flags
+#define pfctl_clear_stats _bsd_pfctl_pfctl_clear_stats
+#define pfctl_disable _bsd_pfctl_pfctl_disable
+#define pfctl_enable _bsd_pfctl_pfctl_enable
+#define usage _bsd_pfctl_usage
+/* pfctl_optimize.c */
+#define superblock_free _bsd_pfctl_superblock_free
+#define exclude_supersets _bsd_pfctl_exclude_supersets
+#define comparable_rule _bsd_pfctl_comparable_rule
+#define interface_group _bsd_pfctl_interface_group
+#define superblock_inclusive _bsd_pfctl_superblock_inclusive
+#define rules_combineable _bsd_pfctl_rules_combineable
+#define addrs_combineable _bsd_pfctl_addrs_combineable
+#define addrs_equal _bsd_pfctl_addrs_equal
+#define construct_superblocks _bsd_pfctl_construct_superblocks
+#define pf_opt_create_table _bsd_pfctl_pf_opt_create_table
+#define add_opt_table _bsd_pfctl_add_opt_table
+#define skip_init _bsd_pfctl_skip_init
+#define skip_cmp_src_port _bsd_pfctl_skip_cmp_src_port
+#define skip_cmp_src_addr _bsd_pfctl_skip_cmp_src_addr
+#define skip_cmp_proto _bsd_pfctl_skip_cmp_proto
+#define skip_cmp_ifp _bsd_pfctl_skip_cmp_ifp
+#define skip_cmp_dst_port _bsd_pfctl_skip_cmp_dst_port
+#define skip_cmp_dst_addr _bsd_pfctl_skip_cmp_dst_addr
+#define skip_cmp_dir _bsd_pfctl_skip_cmp_dir
+#define skip_cmp_af _bsd_pfctl_skip_cmp_af
+#define remove_from_skipsteps _bsd_pfctl_remove_from_skipsteps
+#define skip_append _bsd_pfctl_skip_append
+#define skip_compare _bsd_pfctl_skip_compare
+#define load_feedback_profile _bsd_pfctl_load_feedback_profile
+#define block_feedback _bsd_pfctl_block_feedback
+#define reorder_rules _bsd_pfctl_reorder_rules
+#define combine_rules _bsd_pfctl_combine_rules
+#define remove_identical_rules _bsd_pfctl_remove_identical_rules
+#define optimize_superblock _bsd_pfctl_optimize_superblock
+#define pfctl_optimize_ruleset _bsd_pfctl_pfctl_optimize_ruleset
+/* pfctl_osfp.c */
+#define print_ioctl _bsd_pfctl_print_ioctl
+#define get_field _bsd_pfctl_get_field
+#define get_tcpopts _bsd_pfctl_get_tcpopts
+#define get_str _bsd_pfctl_get_str
+#define get_int _bsd_pfctl_get_int
+#define sort_name_list _bsd_pfctl_sort_name_list
+#define print_name_list _bsd_pfctl_print_name_list
+#define fingerprint_name_entry _bsd_pfctl_fingerprint_name_entry
+#define import_fingerprint _bsd_pfctl_import_fingerprint
+#define add_fingerprint _bsd_pfctl_add_fingerprint
+#define lookup_name_list _bsd_pfctl_lookup_name_list
+#define pfctl_lookup_fingerprint _bsd_pfctl_pfctl_lookup_fingerprint
+#define pfctl_get_fingerprint _bsd_pfctl_pfctl_get_fingerprint
+#define pfctl_show_fingerprints _bsd_pfctl_pfctl_show_fingerprints
+#define pfctl_load_fingerprints _bsd_pfctl_pfctl_load_fingerprints
+#define pfctl_flush_my_fingerprints _bsd_pfctl_pfctl_flush_my_fingerprints
+#define pfctl_clear_fingerprints _bsd_pfctl_pfctl_clear_fingerprints
+#define pfctl_file_fingerprints _bsd_pfctl_pfctl_file_fingerprints
+/* pfctl_parser.c */
+#define pfctl_trans _bsd_pfctl_pfctl_trans
+#define pfctl_get_ticket _bsd_pfctl_pfctl_get_ticket
+#define pfctl_add_trans _bsd_pfctl_pfctl_add_trans
+#define append_addr_host _bsd_pfctl_append_addr_host
+#define append_addr _bsd_pfctl_append_addr
+#define host_dns _bsd_pfctl_host_dns
+#define host_v6 _bsd_pfctl_host_v6
+#define host_v4 _bsd_pfctl_host_v4
+#define host_if _bsd_pfctl_host_if
+#define host _bsd_pfctl_host
+#define ifa_skip_if _bsd_pfctl_ifa_skip_if
+#define ifa_lookup _bsd_pfctl_ifa_lookup
+#define ifa_grouplookup _bsd_pfctl_ifa_grouplookup
+#define ifa_exists _bsd_pfctl_ifa_exists
+#define get_socket_domain _bsd_pfctl_get_socket_domain
+#define ifa_load _bsd_pfctl_ifa_load
+#define check_netmask _bsd_pfctl_check_netmask
+#define set_ipmask _bsd_pfctl_set_ipmask
+#define parse_flags _bsd_pfctl_parse_flags
+#define print_tabledef _bsd_pfctl_print_tabledef
+#define print_rule _bsd_pfctl_print_rule
+#define print_src_node _bsd_pfctl_print_src_node
+#define print_status _bsd_pfctl_print_status
+#define print_pool _bsd_pfctl_print_pool
+#define print_fromto _bsd_pfctl_print_fromto
+#define print_flags _bsd_pfctl_print_flags
+#define print_ugid _bsd_pfctl_print_ugid
+#define print_port _bsd_pfctl_print_port
+#define print_op _bsd_pfctl_print_op
+#define geticmpcodebyname _bsd_pfctl_geticmpcodebyname
+#define geticmpcodebynumber _bsd_pfctl_geticmpcodebynumber
+#define geticmptypebyname _bsd_pfctl_geticmptypebyname
+#define geticmptypebynumber _bsd_pfctl_geticmptypebynumber
+/* pfctl_qstats.c */
+#define update_avg _bsd_pfctl_update_avg
+#define pfctl_free_altq_node _bsd_pfctl_pfctl_free_altq_node
+#define print_fairqstats _bsd_pfctl_print_fairqstats
+#define print_hfscstats _bsd_pfctl_print_hfscstats
+#define print_priqstats _bsd_pfctl_print_priqstats
+#define print_codelstats _bsd_pfctl_print_codelstats
+#define print_cbqstats _bsd_pfctl_print_cbqstats
+#define pfctl_print_altq_nodestat _bsd_pfctl_pfctl_print_altq_nodestat
+#define pfctl_print_altq_node _bsd_pfctl_pfctl_print_altq_node
+#define pfctl_find_altq_node _bsd_pfctl_pfctl_find_altq_node
+#define pfctl_insert_altq_node _bsd_pfctl_pfctl_insert_altq_node
+#define pfctl_update_qstats _bsd_pfctl_pfctl_update_qstats
+#define pfctl_show_altq _bsd_pfctl_pfctl_show_altq
+/* pfctl_radix.c */
+#define pfr_strerror _bsd_pfctl_pfr_strerror
+#define pfr_buf_load _bsd_pfctl_pfr_buf_load
+#define pfr_buf_clear _bsd_pfctl_pfr_buf_clear
+#define pfr_buf_grow _bsd_pfctl_pfr_buf_grow
+#define pfr_buf_next _bsd_pfctl_pfr_buf_next
+#define pfr_buf_add _bsd_pfctl_pfr_buf_add
+#define pfi_get_ifaces _bsd_pfctl_pfi_get_ifaces
+#define pfr_ina_define _bsd_pfctl_pfr_ina_define
+#define pfr_tst_addrs _bsd_pfctl_pfr_tst_addrs
+#define pfr_clr_tstats _bsd_pfctl_pfr_clr_tstats
+#define pfr_get_astats _bsd_pfctl_pfr_get_astats
+#define pfr_get_addrs _bsd_pfctl_pfr_get_addrs
+#define pfr_set_addrs _bsd_pfctl_pfr_set_addrs
+#define pfr_del_addrs _bsd_pfctl_pfr_del_addrs
+#define pfr_add_addrs _bsd_pfctl_pfr_add_addrs
+#define pfr_clr_addrs _bsd_pfctl_pfr_clr_addrs
+#define pfr_get_tstats _bsd_pfctl_pfr_get_tstats
+#define pfr_get_tables _bsd_pfctl_pfr_get_tables
+#define pfr_del_tables _bsd_pfctl_pfr_del_tables
+#define pfr_add_tables _bsd_pfctl_pfr_add_tables
+#define pfr_clr_tables _bsd_pfctl_pfr_clr_tables
+/* pfctl_table.c */
+#define pfctl_show_ifaces _bsd_pfctl_pfctl_show_ifaces
+#define warn_namespace_collision _bsd_pfctl_warn_namespace_collision
+#define pfctl_define_table _bsd_pfctl_pfctl_define_table
+#define pfctl_command_tables _bsd_pfctl_pfctl_command_tables
+#define pfctl_show_tables _bsd_pfctl_pfctl_show_tables
+#define pfctl_clear_tables _bsd_pfctl_pfctl_clear_tables
+/* pf_print_state.c */
+#define unmask _bsd_pfctl_unmask
+#define print_state _bsd_pfctl_print_state
+#define print_seq _bsd_pfctl_print_seq
+#define print_host _bsd_pfctl_print_host
+#define print_name _bsd_pfctl_print_name
+#define print_addr _bsd_pfctl_print_addr
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h
new file mode 100644
index 00000000..ed13a43a
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h
@@ -0,0 +1,36 @@
+/* generated by userspace-header-gen.py */
+/*
+ * NOTE: MANUALLY CHANGED.
+ * YACC needs a special treatment for some variables. They are commented here.
+ */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* parse.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfctl *pf);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int debug);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int rulestate);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmpdefault);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmp6default);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int blockpolicy);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int require_order);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int default_statelock);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct files files);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct file *file);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct symhead symhead);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_queue *queues);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct filter_opts filter_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct antispoof_opts antispoof_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct scrub_opts scrub_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct queue_opts queue_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct table_opts table_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pool_opts pool_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct codel_opts codel_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_hfsc_opts hfsc_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_fairq_opts fairq_opts);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_state_opt *keep_state_defaults);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct loadanchorshead loadanchorshead);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *parsebuf);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int parseindex);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pushback_index);
+/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char pushback_buffer[]);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h
new file mode 100644
index 00000000..33366e0d
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pf_print_state.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h
new file mode 100644
index 00000000..65956d58
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h
@@ -0,0 +1,22 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor_global pf_anchors);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor pf_main_anchor);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *clearopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *rulesopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *showopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *debugopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *anchoropt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *optiopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *pf_device);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *ifaceopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *tableopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *tblcmdopt);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int src_node_killers);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int state_killers);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int first_title);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int labels);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *src_node_kill[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *state_kill[]);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h
new file mode 100644
index 00000000..6a032132
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h
@@ -0,0 +1,9 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_altq.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct altqs altqs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc rtsc);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc lssc);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char r2sbuf[8][16]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int idx);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h
new file mode 100644
index 00000000..09598a79
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h
@@ -0,0 +1,11 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_optimize.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_rule_field pf_rule_desc[70]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int (*skip_comparitors[8])(struct pf_rule *, struct pf_rule *));
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *skip_comparitors_names[8]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfr_buffer table_buffer);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int table_identifier);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int add_opt_tablenum);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pf_opt_create_tablenum);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h
new file mode 100644
index 00000000..53bf09c4
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h
@@ -0,0 +1,7 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_osfp.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct name_list classes);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int class_count);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int fingerprint_count);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h
new file mode 100644
index 00000000..bb8832ac
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h
@@ -0,0 +1,5 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_parser.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h
new file mode 100644
index 00000000..0ee02a9e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h
@@ -0,0 +1,5 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_qstats.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int32_t last_ticket);
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h
new file mode 100644
index 00000000..b2a7340e
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_radix.c */
diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h
new file mode 100644
index 00000000..db4e915b
--- /dev/null
+++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h
@@ -0,0 +1,6 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-pfctl-data.h"
+/* pfctl_table.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *stats_text[2][3]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *istats_text[2][2][2]);
diff --git a/freebsd/sbin/ping/ping.c b/freebsd/sbin/ping/ping.c
index ad5515ab..f0d1f7ce 100644
--- a/freebsd/sbin/ping/ping.c
+++ b/freebsd/sbin/ping/ping.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ping-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -43,21 +47,6 @@ static const char copyright[] =
static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#endif /* not lint */
#endif
-#ifdef __rtems__
-#define __need_getopt_newlib
-#include <getopt.h>
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
-#include <machine/rtems-bsd-program.h>
-#include <machine/rtems-bsd-commands.h>
-#endif /* __rtems__ */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -79,7 +68,14 @@ __FBSDID("$FreeBSD$");
* This program has to run SUID to ROOT to access the ICMP socket.
*/
+#ifdef __rtems__
+#define __need_getopt_newlib
+#include <getopt.h>
+#include <machine/rtems-bsd-program.h>
+#include <machine/rtems-bsd-commands.h>
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h> /* NB: we rely on this for <sys/types.h> */
+#include <sys/capsicum.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
@@ -92,6 +88,11 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_var.h>
#include <arpa/inet.h>
+#ifdef HAVE_LIBCASPER
+#include <libcasper.h>
+#include <casper/cap_dns.h>
+#endif
+
#ifdef IPSEC
#include <netipsec/ipsec.h>
#endif /*IPSEC*/
@@ -107,6 +108,9 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#ifdef __rtems__
+#include "rtems-bsd-ping-ping-data.h"
+#endif /* __rtems__ */
#define INADDR_LEN ((int)sizeof(in_addr_t))
#define TIMEVAL_LEN ((int)sizeof(struct tv32))
@@ -168,20 +172,20 @@ static int options;
* to 8192 for complete accuracy...
*/
#define MAX_DUP_CHK (8 * 128)
-static const int mx_dup_ck = MAX_DUP_CHK;
static char rcvd_tbl[MAX_DUP_CHK / 8];
static struct sockaddr_in whereto; /* who to ping */
static int datalen = DEFDATALEN;
static int maxpayload;
-static int s; /* socket file descriptor */
+static int ssend; /* send socket file descriptor */
+static int srecv; /* receive socket file descriptor */
static u_char outpackhdr[IP_MAXPACKET], *outpack;
-static const char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
-static const char BSPACE = '\b'; /* characters written for flood */
+static const char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
+static const char BSPACE = '\b'; /* characters written for flood */
static const char DOT = '.';
static char *hostname;
static char *shostname;
-static int ident; /* process id to identify our packets */
+static int ident; /* process id to identify our packets */
static int uid; /* cached uid for micro-optimization */
static u_char icmp_type = ICMP_ECHO;
static u_char icmp_type_rsp = ICMP_ECHOREPLY;
@@ -190,31 +194,49 @@ static int send_len;
/* counters */
static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
-static long npackets; /* max packets to transmit */
-static long nreceived; /* # of packets we got back */
-static long nrepeats; /* number of duplicates */
-static long ntransmitted; /* sequence # for outbound packets = #sent */
+#ifndef __rtems__
+static long npackets; /* max packets to transmit */
+#else /* __rtems__ */
+static long npackets = 3; /* max packets to transmit */
+#endif /* __rtems__ */
+static long nreceived; /* # of packets we got back */
+static long nrepeats; /* number of duplicates */
+static long ntransmitted; /* sequence # for outbound packets = #sent */
static long snpackets; /* max packets to transmit in one sweep */
-static long sntransmitted; /* # of packets we sent in this sweep */
-static int sweepmax; /* max value of payload in sweep */
-static int sweepmin = 0; /* start value of payload in sweep */
-static int sweepincr = 1; /* payload increment in sweep */
-static int interval = 1000; /* interval between packets, ms */
-static int waittime = MAXWAIT; /* timeout for each packet */
-static long nrcvtimeout = 0; /* # of packets we got back after waittime */
+static long sntransmitted; /* # of packets we sent in this sweep */
+static int sweepmax; /* max value of payload in sweep */
+static int sweepmin = 0; /* start value of payload in sweep */
+static int sweepincr = 1; /* payload increment in sweep */
+static int interval = 1000; /* interval between packets, ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
/* timing */
-static int timing; /* flag to do timing */
+static int timing; /* flag to do timing */
static double tmin = 999999999.0; /* minimum round trip time */
-static double tmax = 0.0; /* maximum round trip time */
-static double tsum = 0.0; /* sum of all times, for doing average */
-static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+static double tmax = 0.0; /* maximum round trip time */
+static double tsum = 0.0; /* sum of all times, for doing average */
+static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
-static volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */
+/* nonzero if we've been told to finish up */
+static volatile sig_atomic_t finish_up;
+#ifndef __rtems__
static volatile sig_atomic_t siginfo_p;
+#endif /* __rtems__ */
+
+#ifdef HAVE_LIBCASPER
+static cap_channel_t *capdns;
+#endif
+#ifdef __rtems__
+static u_char packet[IP_MAXPACKET] __aligned(4);
+static char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
+#endif /* __rtems__ */
static void fill(char *, char *);
static u_short in_cksum(u_short *, int);
+#ifdef HAVE_LIBCASPER
+static cap_channel_t *capdns_setup(void);
+#endif
static void check_status(void);
static void finish(void) __dead2;
static void pinger(void);
@@ -232,55 +254,32 @@ static void tvsub(struct timeval *, const struct timeval *);
static void usage(void) __dead2;
#ifdef __rtems__
-static int main(int argc, char **argv);
+static int main(int argc, char *argv[]);
+
+RTEMS_LINKER_RWSET(bsd_prog_ping, char);
-int rtems_bsd_command_ping(int argc, char *argv[])
+int
+rtems_bsd_command_ping(int argc, char *argv[])
{
int exit_code;
+ void *data_begin;
+ size_t data_size;
- rtems_bsd_program_lock();
-
- memset(&rcvd_tbl[0], 0, sizeof(rcvd_tbl));
- s = -1;
- memset(&outpackhdr[0], 0, sizeof(outpackhdr));
- icmp_type = ICMP_ECHO;
- icmp_type_rsp = ICMP_ECHOREPLY;
- phdr_len = 0;
- nmissedmax = 0;
- npackets = 3;
- nreceived = 0;
- nrepeats = 0;
- ntransmitted = 0;
- snpackets = 0;
- sntransmitted = 0;
- sweepmax = 0;
- sweepmin = 0;
- sweepincr = 1;
- interval = 1000;
- waittime = MAXWAIT;
- nrcvtimeout = 0;
- timing = 0;
- tmin = 999999999.0;
- tmax = 0.0;
- tsum = 0.0;
- tsumsq = 0.0;
- finish_up = 0;
- siginfo_p = 0;
-
- exit_code = rtems_bsd_program_call_main("ping", main, argc, argv);
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ping);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ping);
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("ping",
+ main, argc, argv, data_begin, data_size);
rtems_bsd_program_unlock();
- close(s);
-
return exit_code;
}
-#endif /* __rtems__ */
int
-#ifndef __rtems__
-main(int argc, char *const *argv)
-#else /* __rtems__ */
main(int argc, char **argv)
+#else /* __rtems__ */
+int
+main(int argc, char *const *argv)
#endif /* __rtems__ */
{
struct sockaddr_in from, sock_in;
@@ -289,13 +288,14 @@ main(int argc, char **argv)
struct iovec iov;
struct ip *ip;
struct msghdr msg;
+#ifndef __rtems__
struct sigaction si_sa;
+#endif /* __rtems__ */
size_t sz;
#ifndef __rtems__
u_char *datap, packet[IP_MAXPACKET] __aligned(4);
#else /* __rtems__ */
u_char *datap;
- static u_char packet[IP_MAXPACKET] __aligned(4);
#endif /* __rtems__ */
char *ep, *source, *target, *payload;
struct hostent *hp;
@@ -305,19 +305,23 @@ main(int argc, char **argv)
struct sockaddr_in *to;
double t;
u_long alarmtimeout, ultmp;
- int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
- tos, ttl;
+ int almost_done, ch, df, hold, i, icmp_len, mib[4], preload;
+ int ssend_errno, srecv_errno, tos, ttl;
char ctrl[CMSG_SPACE(sizeof(struct timeval))];
#ifndef __rtems__
char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
-#else /* __rtems__ */
- static char hnamebuf[MAXHOSTNAMELEN];
- static char snamebuf[MAXHOSTNAMELEN];
#endif /* __rtems__ */
#ifdef IP_OPTIONS
char rspace[MAX_IPOPTLEN]; /* record route space */
#endif
unsigned char loop, mttl;
+
+ payload = source = NULL;
+#ifdef IPSEC_POLICY_IPSEC
+ policy_in = policy_out = NULL;
+#endif
+ cap_rights_t rights;
+ bool cansandbox;
#ifdef __rtems__
struct getopt_data getopt_data;
memset(&getopt_data, 0, sizeof(getopt_data));
@@ -328,22 +332,38 @@ main(int argc, char **argv)
#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
#endif /* __rtems__ */
- payload = source = NULL;
-#ifdef IPSEC_POLICY_IPSEC
- policy_in = policy_out = NULL;
-#endif
-
/*
* Do the stuff that we need root priv's for *first*, and
* then drop our setuid bit. Save error reporting for
* after arg parsing.
+ *
+ * Historicaly ping was using one socket 's' for sending and for
+ * receiving. After capsicum(4) related changes we use two
+ * sockets. It was done for special ping use case - when user
+ * issue ping on multicast or broadcast address replies come
+ * from different addresses, not from the address we
+ * connect(2)'ed to, and send socket do not receive those
+ * packets.
*/
- s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- sockerrno = errno;
+ ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ ssend_errno = errno;
+ srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ srecv_errno = errno;
- setuid(getuid());
+ if (setuid(getuid()) != 0)
+ err(EX_NOPERM, "setuid() failed");
uid = getuid();
+ if (ssend < 0) {
+ errno = ssend_errno;
+ err(EX_OSERR, "ssend socket");
+ }
+
+ if (srecv < 0) {
+ errno = srecv_errno;
+ err(EX_OSERR, "srecv socket");
+ }
+
alarmtimeout = df = preload = tos = 0;
outpack = outpackhdr + sizeof(struct ip);
@@ -612,13 +632,22 @@ main(int argc, char **argv)
if (options & F_PINGFILLED) {
fill((char *)datap, payload);
}
+#ifdef HAVE_LIBCASPER
+ capdns = capdns_setup();
+#endif
if (source) {
bzero((char *)&sock_in, sizeof(sock_in));
sock_in.sin_family = AF_INET;
if (inet_aton(source, &sock_in.sin_addr) != 0) {
shostname = source;
} else {
- hp = gethostbyname2(source, AF_INET);
+#ifdef HAVE_LIBCASPER
+ if (capdns != NULL)
+ hp = cap_gethostbyname2(capdns, source,
+ AF_INET);
+ else
+#endif
+ hp = gethostbyname2(source, AF_INET);
if (!hp)
errx(EX_NOHOST, "cannot resolve %s: %s",
source, hstrerror(h_errno));
@@ -634,7 +663,8 @@ main(int argc, char **argv)
snamebuf[sizeof(snamebuf) - 1] = '\0';
shostname = snamebuf;
}
- if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
+ if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) ==
+ -1)
err(1, "bind");
}
@@ -645,7 +675,12 @@ main(int argc, char **argv)
if (inet_aton(target, &to->sin_addr) != 0) {
hostname = target;
} else {
- hp = gethostbyname2(target, AF_INET);
+#ifdef HAVE_LIBCASPER
+ if (capdns != NULL)
+ hp = cap_gethostbyname2(capdns, target, AF_INET);
+ else
+#endif
+ hp = gethostbyname2(target, AF_INET);
if (!hp)
errx(EX_NOHOST, "cannot resolve %s: %s",
target, hstrerror(h_errno));
@@ -658,6 +693,20 @@ main(int argc, char **argv)
hostname = hnamebuf;
}
+#ifdef HAVE_LIBCASPER
+ /* From now on we will use only reverse DNS lookups. */
+ if (capdns != NULL) {
+ const char *types[1];
+
+ types[0] = "ADDR";
+ if (cap_dns_type_limit(capdns, types, 1) < 0)
+ err(1, "unable to limit access to system.dns service");
+ }
+#endif
+
+ if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0)
+ err(1, "connect");
+
if (options & F_FLOOD && options & F_INTERVAL)
errx(EX_USAGE, "-f and -i: incompatible options");
@@ -678,16 +727,15 @@ main(int argc, char **argv)
ident = getpid() & 0xFFFF;
- if (s < 0) {
- errno = sockerrno;
- err(EX_OSERR, "socket");
- }
hold = 1;
- if (options & F_SO_DEBUG)
- (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ if (options & F_SO_DEBUG) {
+ (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold,
sizeof(hold));
+ (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+ }
if (options & F_SO_DONTROUTE)
- (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
+ (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
sizeof(hold));
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
@@ -697,7 +745,7 @@ main(int argc, char **argv)
buf = ipsec_set_policy(policy_in, strlen(policy_in));
if (buf == NULL)
errx(EX_CONFIG, "%s", ipsec_strerror());
- if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0)
err(EX_CONFIG,
"ipsec policy cannot be configured");
@@ -708,7 +756,7 @@ main(int argc, char **argv)
buf = ipsec_set_policy(policy_out, strlen(policy_out));
if (buf == NULL)
errx(EX_CONFIG, "%s", ipsec_strerror());
- if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0)
err(EX_CONFIG,
"ipsec policy cannot be configured");
@@ -729,17 +777,43 @@ main(int argc, char **argv)
if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
err(1, "sysctl(net.inet.ip.ttl)");
}
- setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
+ setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = tos;
ip->ip_id = 0;
- ip->ip_off = df ? IP_DF : 0;
+ ip->ip_off = htons(df ? IP_DF : 0);
ip->ip_ttl = ttl;
ip->ip_p = IPPROTO_ICMP;
ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
ip->ip_dst = to->sin_addr;
}
+
+ if (options & F_NUMERIC)
+ cansandbox = true;
+#ifdef HAVE_LIBCASPER
+ else if (capdns != NULL)
+ cansandbox = true;
+#endif
+ else
+ cansandbox = false;
+
+ /*
+ * Here we enter capability mode. Further down access to global
+ * namespaces (e.g filesystem) is restricted (see capsicum(4)).
+ * We must connect(2) our socket before this point.
+ */
+ if (cansandbox && cap_enter() < 0 && errno != ENOSYS)
+ err(1, "cap_enter");
+
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT);
+ if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit srecv");
+
+ cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
+ if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit ssend");
+
/* record route option */
if (options & F_RROUTE) {
#ifdef IP_OPTIONS
@@ -748,7 +822,7 @@ main(int argc, char **argv)
rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
rspace[sizeof(rspace) - 1] = IPOPT_EOL;
- if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
+ if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace,
sizeof(rspace)) < 0)
err(EX_OSERR, "setsockopt IP_OPTIONS");
#else
@@ -758,38 +832,38 @@ main(int argc, char **argv)
}
if (options & F_TTL) {
- if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
+ if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl,
sizeof(ttl)) < 0) {
err(EX_OSERR, "setsockopt IP_TTL");
}
}
if (options & F_NOLOOP) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
sizeof(loop)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
}
}
if (options & F_MTTL) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
sizeof(mttl)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_TTL");
}
}
if (options & F_MIF) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
sizeof(ifaddr)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_IF");
}
}
#ifdef SO_TIMESTAMP
{ int on = 1;
- if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
+ if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
err(EX_OSERR, "setsockopt SO_TIMESTAMP");
}
#endif
if (sweepmax) {
- if (sweepmin >= sweepmax)
- errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+ if (sweepmin > sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be no less than the minimum packet size");
if (datalen != DEFDATALEN)
errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
@@ -802,7 +876,7 @@ main(int argc, char **argv)
datalen = sweepmin;
send_len = icmp_len + sweepmin;
}
- if (options & F_SWEEP && !sweepmax)
+ if (options & F_SWEEP && !sweepmax)
errx(EX_USAGE, "Maximum sweep size must be specified");
/*
@@ -818,11 +892,19 @@ main(int argc, char **argv)
* as well.
*/
hold = IP_MAXPACKET + 128;
- (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
sizeof(hold));
+ /* CAP_SETSOCKOPT removed */
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
+ if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit srecv setsockopt");
if (uid == 0)
- (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
+ (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
sizeof(hold));
+ /* CAP_SETSOCKOPT removed */
+ cap_rights_init(&rights, CAP_SEND);
+ if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit ssend setsockopt");
if (to->sin_family == AF_INET) {
(void)printf("PING %s (%s)", hostname,
@@ -832,9 +914,9 @@ main(int argc, char **argv)
if (sweepmax)
(void)printf(": (%d ... %d) data bytes\n",
sweepmin, sweepmax);
- else
+ else
(void)printf(": %d data bytes\n", datalen);
-
+
} else {
if (sweepmax)
(void)printf("PING %s: (%d ... %d) data bytes\n",
@@ -867,8 +949,6 @@ main(int argc, char **argv)
if (sigaction(SIGALRM, &si_sa, 0) == -1)
err(EX_OSERR, "sigaction SIGALRM");
}
-#else /* __rtems__ */
- (void) si_sa;
#endif /* __rtems__ */
bzero(&msg, sizeof(msg));
@@ -906,10 +986,10 @@ main(int argc, char **argv)
int cc, n;
check_status();
- if ((unsigned)s >= FD_SETSIZE)
+ if ((unsigned)srecv >= FD_SETSIZE)
errx(EX_OSERR, "descriptor too large");
FD_ZERO(&rfds);
- FD_SET(s, &rfds);
+ FD_SET(srecv, &rfds);
(void)gettimeofday(&now, NULL);
timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
@@ -922,8 +1002,8 @@ main(int argc, char **argv)
timeout.tv_sec++;
}
if (timeout.tv_sec < 0)
- timeout.tv_sec = timeout.tv_usec = 0;
- n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ timerclear(&timeout);
+ n = select(srecv + 1, &rfds, NULL, NULL, &timeout);
if (n < 0)
continue; /* Must be EINTR. */
if (n == 1) {
@@ -934,7 +1014,7 @@ main(int argc, char **argv)
msg.msg_controllen = sizeof(ctrl);
#endif
msg.msg_namelen = sizeof(from);
- if ((cc = recvmsg(s, &msg, 0)) < 0) {
+ if ((cc = recvmsg(srecv, &msg, 0)) < 0) {
if (errno == EINTR)
continue;
warn("recvmsg");
@@ -960,14 +1040,14 @@ main(int argc, char **argv)
}
if (n == 0 || options & F_FLOOD) {
if (sweepmax && sntransmitted == snpackets) {
- for (i = 0; i < sweepincr ; ++i)
+ for (i = 0; i < sweepincr ; ++i)
*datap++ = i;
datalen += sweepincr;
if (datalen > sweepmax)
break;
send_len = icmp_len + datalen;
sntransmitted = 0;
- }
+ }
if (!npackets || ntransmitted < npackets)
pinger();
else {
@@ -1044,7 +1124,7 @@ pinger(void)
icp->icmp_seq = htons(ntransmitted);
icp->icmp_id = ident; /* ID */
- CLR(ntransmitted % mx_dup_ck);
+ CLR(ntransmitted % MAX_DUP_CHK);
if ((options & F_TIME) || timing) {
(void)gettimeofday(&now, NULL);
@@ -1068,13 +1148,11 @@ pinger(void)
if (options & F_HDRINCL) {
cc += sizeof(struct ip);
ip = (struct ip *)outpackhdr;
- ip->ip_len = cc;
+ ip->ip_len = htons(cc);
ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
packet = outpackhdr;
}
- i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
- sizeof(whereto));
-
+ i = send(ssend, (char *)packet, cc, 0);
if (i < 0 || i != cc) {
if (i < 0) {
if (options & F_FLOOD && errno == ENOBUFS) {
@@ -1142,7 +1220,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
#endif
tp = (const char *)tp + phdr_len;
- if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
+ if ((size_t)(cc - ICMP_MINLEN - phdr_len) >=
+ sizeof(tv1)) {
/* Copy to avoid alignment problems: */
memcpy(&tv32, tp, sizeof(tv32));
tv1.tv_sec = ntohl(tv32.tv32_sec);
@@ -1162,18 +1241,18 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
seq = ntohs(icp->icmp_seq);
- if (TST(seq % mx_dup_ck)) {
+ if (TST(seq % MAX_DUP_CHK)) {
++nrepeats;
--nreceived;
dupflag = 1;
} else {
- SET(seq % mx_dup_ck);
+ SET(seq % MAX_DUP_CHK);
dupflag = 0;
}
if (options & F_QUIET)
return;
-
+
if (options & F_WAITTIME && triptime > waittime) {
++nrcvtimeout;
return;
@@ -1195,7 +1274,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv)
if (options & F_MASK) {
/* Just prentend this cast isn't ugly */
(void)printf(" mask=%s",
- pr_addr(*(struct in_addr *)&(icp->icmp_mask)));
+ inet_ntoa(*(struct in_addr *)&(icp->icmp_mask)));
}
if (options & F_TIME) {
(void)printf(" tso=%s", pr_ntime(icp->icmp_otime));
@@ -1437,6 +1516,7 @@ static void
check_status(void)
{
+#ifndef __rtems__
if (siginfo_p) {
siginfo_p = 0;
(void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
@@ -1447,6 +1527,7 @@ check_status(void)
tmin, tsum / (nreceived + nrepeats), tmax);
(void)fprintf(stderr, "\n");
}
+#endif /* __rtems__ */
}
/*
@@ -1697,12 +1778,21 @@ pr_addr(struct in_addr ina)
struct hostent *hp;
static char buf[16 + 3 + MAXHOSTNAMELEN];
- if ((options & F_NUMERIC) ||
- !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
+ if (options & F_NUMERIC)
return inet_ntoa(ina);
+
+#ifdef HAVE_LIBCASPER
+ if (capdns != NULL)
+ hp = cap_gethostbyaddr(capdns, (char *)&ina, 4, AF_INET);
else
- (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
- inet_ntoa(ina));
+#endif
+ hp = gethostbyaddr((char *)&ina, 4, AF_INET);
+
+ if (hp == NULL)
+ return inet_ntoa(ina);
+
+ (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
+ inet_ntoa(ina));
return(buf);
}
@@ -1752,7 +1842,7 @@ fill(char *bp, char *patp)
u_int ii, jj, kk;
for (cp = patp; *cp; cp++) {
- if (!isxdigit((unsigned char) *cp))
+ if (!isxdigit((unsigned char)*cp))
errx(EX_USAGE,
"patterns must be specified as hex digits");
@@ -1775,6 +1865,34 @@ fill(char *bp, char *patp)
}
}
+#ifdef HAVE_LIBCASPER
+static cap_channel_t *
+capdns_setup(void)
+{
+ cap_channel_t *capcas, *capdnsloc;
+ const char *types[2];
+ int families[1];
+
+ capcas = cap_init();
+ if (capcas == NULL)
+ err(1, "unable to create casper process");
+ capdnsloc = cap_service_open(capcas, "system.dns");
+ /* Casper capability no longer needed. */
+ cap_close(capcas);
+ if (capdnsloc == NULL)
+ err(1, "unable to open system.dns service");
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ if (cap_dns_type_limit(capdnsloc, types, 2) < 0)
+ err(1, "unable to limit access to system.dns service");
+ families[0] = AF_INET;
+ if (cap_dns_family_limit(capdnsloc, families, 1) < 0)
+ err(1, "unable to limit access to system.dns service");
+
+ return (capdnsloc);
+}
+#endif /* HAVE_LIBCASPER */
+
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define SECOPT " [-P policy]"
#else
diff --git a/freebsd/sbin/ping/rtems-bsd-ping-data.h b/freebsd/sbin/ping/rtems-bsd-ping-data.h
new file mode 100644
index 00000000..b89b2282
--- /dev/null
+++ b/freebsd/sbin/ping/rtems-bsd-ping-data.h
@@ -0,0 +1,3 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+/* ping.c */
diff --git a/freebsd/sbin/ping/rtems-bsd-ping-namespace.h b/freebsd/sbin/ping/rtems-bsd-ping-namespace.h
new file mode 100644
index 00000000..a46682da
--- /dev/null
+++ b/freebsd/sbin/ping/rtems-bsd-ping-namespace.h
@@ -0,0 +1,2 @@
+/* generated by userspace-header-gen.py */
+/* ping.c */
diff --git a/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h b/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h
new file mode 100644
index 00000000..46bada6b
--- /dev/null
+++ b/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h
@@ -0,0 +1,43 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ping-data.h"
+/* ping.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int options);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static struct sockaddr_in whereto);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int datalen);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int maxpayload);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int ssend);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int srecv);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char *outpack);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char *hostname);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char *shostname);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int ident);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int uid);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char icmp_type);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char icmp_type_rsp);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int phdr_len);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int send_len);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nmissedmax);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int npackets);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nreceived);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nrepeats);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int ntransmitted);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int snpackets);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int sntransmitted);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepmax);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepmin);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepincr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int interval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int waittime);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nrcvtimeout);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int timing);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tmin);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tmax);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tsum);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tsumsq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static sig_atomic_t volatile finish_up);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char rcvd_tbl[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char outpackhdr[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char packet[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char hnamebuf[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char snamebuf[]);
diff --git a/freebsd/sbin/ping6/ping6.c b/freebsd/sbin/ping6/ping6.c
index 054cebf2..b8f565c6 100644
--- a/freebsd/sbin/ping6/ping6.c
+++ b/freebsd/sbin/ping6/ping6.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-ping6-namespace.h"
+#endif /* __rtems__ */
+
/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */
/*
@@ -106,20 +110,8 @@ __FBSDID("$FreeBSD$");
#ifdef __rtems__
#define __need_getopt_newlib
#include <getopt.h>
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#include <machine/rtems-bsd-commands.h>
-
-#define USE_RFC2292BIS
-#define HAVE_POLL_H
#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/uio.h>
@@ -145,10 +137,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
#ifdef IPSEC
#include <netipsec/ah.h>
@@ -156,6 +146,9 @@ __FBSDID("$FreeBSD$");
#endif
#include <md5.h>
+#ifdef __rtems__
+#include "rtems-bsd-ping6-ping6-data.h"
+#endif /* __rtems__ */
struct tv32 {
u_int32_t tv32_sec;
@@ -174,6 +167,8 @@ struct tv32 {
#define DEFDATALEN ICMP6ECHOTMLEN
#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
#define NROUTES 9 /* number of record route slots */
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
@@ -210,7 +205,8 @@ struct tv32 {
#define F_MISSED 0x800000
#define F_DONTFRAG 0x1000000
#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
-static u_int options;
+#define F_WAITTIME 0x2000000
+u_int options;
#define IN6LEN sizeof(struct in6_addr)
#define SA6LEN sizeof(struct sockaddr_in6)
@@ -224,45 +220,40 @@ static u_int options;
* to 8192 for complete accuracy...
*/
#define MAX_DUP_CHK (8 * 8192)
-static const int mx_dup_ck = MAX_DUP_CHK;
+static int mx_dup_ck = MAX_DUP_CHK;
static char rcvd_tbl[MAX_DUP_CHK / 8];
-static struct addrinfo *res;
static struct sockaddr_in6 dst; /* who to ping6 */
static struct sockaddr_in6 src; /* src addr of this packet */
static socklen_t srclen;
-static int datalen;
-static int s; /* socket file descriptor */
+static size_t datalen = DEFDATALEN;
+static int s; /* socket file descriptor */
static u_char outpack[MAXPACKETLEN];
-static const char BSPACE = '\b'; /* characters written for flood */
-static const char BBELL = '\a'; /* characters written for AUDIBLE */
-static const char DOT = '.';
+static char BSPACE = '\b'; /* characters written for flood */
+static char BBELL = '\a'; /* characters written for AUDIBLE */
+static char DOT = '.';
static char *hostname;
-static int ident; /* process id to identify our packets */
-static u_int8_t nonce[8]; /* nonce field for node information */
-static int hoplimit; /* hoplimit */
-static u_char *packet;
-#ifdef HAVE_POLL_H
-static struct pollfd fdmaskp[1];
-#else
-static fd_set *fdmaskp = NULL;
-static int fdmasks;
-#endif
+static int ident; /* process id to identify our packets */
+static u_int8_t nonce[8]; /* nonce field for node information */
+static int hoplimit = -1; /* hoplimit */
+static u_char *packet = NULL;
/* counters */
static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
-static long npackets; /* max packets to transmit */
-static long nreceived; /* # of packets we got back */
-static long nrepeats; /* number of duplicates */
-static long ntransmitted; /* sequence # for outbound packets = #sent */
-static struct timeval interval; /* interval between packets */
+static long npackets; /* max packets to transmit */
+static long nreceived; /* # of packets we got back */
+static long nrepeats; /* number of duplicates */
+static long ntransmitted; /* sequence # for outbound packets = #sent */
+static int interval = 1000; /* interval between packets in ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
/* timing */
-static int timing; /* flag to do timing */
-static double tmin; /* minimum round trip time */
-static double tmax; /* maximum round trip time */
-static double tsum; /* sum of all times, for doing average */
-static double tsumsq; /* sum of all times squared, for std. dev. */
+static int timing; /* flag to do timing */
+static double tmin = 999999999.0; /* minimum round trip time */
+static double tmax = 0.0; /* maximum round trip time */
+static double tsum = 0.0; /* sum of all times, for doing average */
+static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
/* for node addresses */
static u_short naflags;
@@ -272,22 +263,19 @@ static struct msghdr smsghdr;
static struct iovec smsgiov;
static char *scmsg = 0;
-static volatile sig_atomic_t seenalrm;
static volatile sig_atomic_t seenint;
#ifdef SIGINFO
static volatile sig_atomic_t seeninfo;
#endif
-/* For control (ancillary) data received from recvmsg() */
-static struct cmsghdr cm[CONTROLLEN];
-
-static int main(int, char *[]);
+#ifndef __rtems__
+int main(int, char *[]);
+#endif /* __rtems__ */
static void fill(char *, char *);
static int get_hoplim(struct msghdr *);
static int get_pathmtu(struct msghdr *);
static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
static void onsignal(int);
-static void retransmit(void);
static void onint(int);
static size_t pingerlen(void);
static int pinger(void);
@@ -299,7 +287,7 @@ static void pr_nodeaddr(struct icmp6_nodeinfo *, int);
static int myechoreply(const struct icmp6_hdr *);
static int mynireply(const struct icmp6_nodeinfo *);
static char *dnsdecode(const u_char **, const u_char *, const u_char *,
- char *, size_t);
+ char *, size_t);
static void pr_pack(u_char *, int, struct msghdr *);
static void pr_exthdrs(struct msghdr *);
static void pr_ip6opt(void *, size_t);
@@ -308,85 +296,56 @@ static int pr_bitrange(u_int32_t, int, int);
static void pr_retip(struct ip6_hdr *, u_char *);
static void summary(void);
static void tvsub(struct timeval *, struct timeval *);
-#ifdef IPSEC
-#ifdef IPSEC_POLICY_IPSEC
static int setpolicy(int, char *);
-#endif
-#endif
static char *nigroup(char *, int);
static void usage(void);
#ifdef __rtems__
-int rtems_bsd_command_ping6(int argc, char **argv)
-{
- int exit_code;
+#define USE_RFC2292BIS
+#endif /* __rtems__ */
+#ifdef __rtems__
+static int main(int argc, char *argv[]);
- rtems_bsd_program_lock();
+RTEMS_LINKER_RWSET(bsd_prog_ping6, char);
- memset(&rcvd_tbl[0], 0, sizeof(rcvd_tbl));
- res = NULL;
- srclen = 0;
- datalen = DEFDATALEN;
- s = -1;
- memset(&outpack[0], 0, sizeof(outpack));
- hoplimit = -1;
- nmissedmax = 0;
- npackets = 0;
- nreceived = 0;
- nrepeats = 0;
- ntransmitted = 0;
- interval.tv_sec = 1;
- interval.tv_usec = 0;
- timing = 0;
- tmin = 999999999.0;
- tmax = 0.0;
- tsum = 0.0;
- tsumsq = 0.0;
- naflags = 0;
- scmsg = NULL;
- seenalrm = 0;
- seenint = 0;
-#ifdef SIGINFO
- seeninfo = 0;
-#endif
- packet = NULL;
+int
+rtems_bsd_command_ping6(int argc, char *argv[])
+{
+ int exit_code;
+ void *data_begin;
+ size_t data_size;
- exit_code = rtems_bsd_program_call_main("ping6", main, argc, argv);
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ping6);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ping6);
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("ping6",
+ main, argc, argv, data_begin, data_size);
rtems_bsd_program_unlock();
- close(s);
- free(scmsg);
- free(packet);
-
- if (res != NULL) {
- freeaddrinfo(res);
- }
-
return exit_code;
}
#endif /* __rtems__ */
int
main(int argc, char *argv[])
{
- struct itimerval itimer;
- struct sockaddr_in6 from;
-#ifndef HAVE_ARC4RANDOM
- struct timeval seed;
-#endif
-#ifdef HAVE_POLL_H
- int timeout;
-#else
- struct timeval timeout, *tv;
-#endif
- struct addrinfo hints;
+ struct timeval last, intvl;
+ struct sockaddr_in6 from, *sin6;
+ struct addrinfo hints, *res;
+ struct sigaction si_sa;
int cc, i;
- int ch, hold, packlen, preload, optval, ret_ga;
+ int almost_done, ch, hold, packlen, preload, optval, error;
int nig_oldmcprefix = -1;
u_char *datap;
char *e, *target, *ifname = NULL, *gateway = NULL;
int ip6optlen = 0;
struct cmsghdr *scmsgp = NULL;
+ /* For control (ancillary) data received from recvmsg() */
+#ifndef __rtems__
+ struct cmsghdr cm[CONTROLLEN];
+#else /* __rtems__ */
+ static struct cmsghdr cm[CONTROLLEN];
+#endif /* __rtems__ */
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
u_long lsockbufsize;
int sockbufsize = 0;
@@ -400,7 +359,8 @@ main(int argc, char *argv[])
char *policy_in = NULL;
char *policy_out = NULL;
#endif
- double intval;
+ double t;
+ u_long alarmtimeout;
size_t rthlen;
#ifdef IPV6_USE_MIN_MTU
int mflag = 0;
@@ -419,7 +379,7 @@ main(int argc, char *argv[])
memset(&smsghdr, 0, sizeof(smsghdr));
memset(&smsgiov, 0, sizeof(smsgiov));
- preload = 0;
+ alarmtimeout = preload = 0;
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
#ifndef IPSEC
#define ADDOPTS
@@ -431,7 +391,7 @@ main(int argc, char *argv[])
#endif /*IPSEC_POLICY_IPSEC*/
#endif
while ((ch = getopt(argc, argv,
- "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwW" ADDOPTS)) != -1) {
+ "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" ADDOPTS)) != -1) {
#undef ADDOPTS
switch (ch) {
case 'a':
@@ -482,9 +442,9 @@ main(int argc, char *argv[])
errno = 0;
e = NULL;
lsockbufsize = strtoul(optarg, &e, 10);
- sockbufsize = lsockbufsize;
+ sockbufsize = (int)lsockbufsize;
if (errno || !*optarg || *e ||
- sockbufsize != lsockbufsize)
+ lsockbufsize > INT_MAX)
errx(1, "invalid socket buffer size");
#else
errx(1,
@@ -533,22 +493,22 @@ main(int argc, char *argv[])
#endif
break;
case 'i': /* wait between sending packets */
- intval = strtod(optarg, &e);
+ t = strtod(optarg, &e);
if (*optarg == '\0' || *e != '\0')
errx(1, "illegal timing interval %s", optarg);
- if (intval < 1 && getuid()) {
+ if (t < 1 && getuid()) {
errx(1, "%s: only root may use interval < 1s",
strerror(EPERM));
}
- interval.tv_sec = (long)intval;
- interval.tv_usec =
- (long)((intval - interval.tv_sec) * 1000000);
- if (interval.tv_sec < 0)
+ intvl.tv_sec = (long)t;
+ intvl.tv_usec =
+ (long)((t - intvl.tv_sec) * 1000000);
+ if (intvl.tv_sec < 0)
errx(1, "illegal timing interval %s", optarg);
/* less than 1/hz does not make sense */
- if (interval.tv_sec == 0 && interval.tv_usec < 1) {
+ if (intvl.tv_sec == 0 && intvl.tv_usec < 1) {
warnx("too small interval, raised to .000001");
- interval.tv_usec = 1;
+ intvl.tv_usec = 1;
}
options |= F_INTERVAL;
break;
@@ -599,10 +559,10 @@ main(int argc, char *argv[])
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
- ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
- if (ret_ga) {
+ error = getaddrinfo(optarg, NULL, &hints, &res);
+ if (error) {
errx(1, "invalid source address: %s",
- gai_strerror(ret_ga));
+ gai_strerror(error));
}
/*
* res->ai_family must be AF_INET6 and res->ai_addrlen
@@ -611,7 +571,6 @@ main(int argc, char *argv[])
memcpy(&src, res->ai_addr, res->ai_addrlen);
srclen = res->ai_addrlen;
freeaddrinfo(res);
- res = NULL;
options |= F_SRCADDR;
break;
case 's': /* size of packet to send */
@@ -639,6 +598,24 @@ main(int argc, char *argv[])
options &= ~F_NOUSERDATA;
options |= F_FQDNOLD;
break;
+ case 'x':
+ t = strtod(optarg, &e);
+ if (*e || e == optarg || t > (double)INT_MAX)
+ err(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_WAITTIME;
+ waittime = (int)t;
+ break;
+ case 'X':
+ alarmtimeout = strtoul(optarg, &e, 0);
+ if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((int)alarmtimeout);
+ break;
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
case 'P':
@@ -705,11 +682,11 @@ main(int argc, char *argv[])
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMPV6;
- ret_ga = getaddrinfo(target, NULL, &hints, &res);
- if (ret_ga)
- errx(1, "%s", gai_strerror(ret_ga));
+ error = getaddrinfo(target, NULL, &hints, &res);
+ if (error)
+ errx(1, "%s", gai_strerror(error));
if (res->ai_canonname)
- hostname = res->ai_canonname;
+ hostname = strdup(res->ai_canonname);
else
hostname = target;
@@ -721,40 +698,44 @@ main(int argc, char *argv[])
if ((s = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) < 0)
err(1, "socket");
+ freeaddrinfo(res);
/* set the source address if specified. */
- if ((options & F_SRCADDR) &&
- bind(s, (struct sockaddr *)&src, srclen) != 0) {
- err(1, "bind");
+ if ((options & F_SRCADDR) != 0) {
+ /* properly fill sin6_scope_id */
+ if (IN6_IS_ADDR_LINKLOCAL(&src.sin6_addr) && (
+ IN6_IS_ADDR_LINKLOCAL(&dst.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&dst.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&dst.sin6_addr))) {
+ if (src.sin6_scope_id == 0)
+ src.sin6_scope_id = dst.sin6_scope_id;
+ if (dst.sin6_scope_id == 0)
+ dst.sin6_scope_id = src.sin6_scope_id;
+ }
+ if (bind(s, (struct sockaddr *)&src, srclen) != 0)
+ err(1, "bind");
}
-
/* set the gateway (next hop) if specified */
if (gateway) {
- struct addrinfo ghints, *gres;
- int error;
-
- memset(&ghints, 0, sizeof(ghints));
- ghints.ai_family = AF_INET6;
- ghints.ai_socktype = SOCK_RAW;
- ghints.ai_protocol = IPPROTO_ICMPV6;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
- error = getaddrinfo(gateway, NULL, &hints, &gres);
+ error = getaddrinfo(gateway, NULL, &hints, &res);
if (error) {
- freeaddrinfo(gres);
errx(1, "getaddrinfo for the gateway %s: %s",
gateway, gai_strerror(error));
}
- if (gres->ai_next && (options & F_VERBOSE))
- freeaddrinfo(gres);
+ if (res->ai_next && (options & F_VERBOSE))
warnx("gateway resolves to multiple addresses");
if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
- gres->ai_addr, gres->ai_addrlen)) {
- freeaddrinfo(gres);
+ res->ai_addr, res->ai_addrlen)) {
err(1, "setsockopt(IPV6_NEXTHOP)");
}
- freeaddrinfo(gres);
+ freeaddrinfo(res);
}
/*
@@ -790,8 +771,10 @@ main(int argc, char *argv[])
}
/* revoke root privilege */
- seteuid(getuid());
- setuid(getuid());
+ if (seteuid(getuid()) != 0)
+ err(1, "seteuid() failed");
+ if (setuid(getuid()) != 0)
+ err(1, "setuid() failed");
if ((options & F_FLOOD) && (options & F_INTERVAL))
errx(1, "-f and -i incompatible options");
@@ -821,17 +804,7 @@ main(int argc, char *argv[])
*datap++ = i;
ident = getpid() & 0xFFFF;
-#ifndef HAVE_ARC4RANDOM
- gettimeofday(&seed, NULL);
- srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident));
- memset(nonce, 0, sizeof(nonce));
- for (i = 0; i < sizeof(nonce); i += sizeof(int))
- *((int *)&nonce[i]) = rand();
-#else
- memset(nonce, 0, sizeof(nonce));
- for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
- *((u_int32_t *)&nonce[i]) = arc4random();
-#endif
+ arc4random_buf(nonce, sizeof(nonce));
optval = 1;
if (options & F_DONTFRAG)
if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG,
@@ -946,7 +919,7 @@ main(int argc, char *argv[])
/* set IP6 packet options */
if (ip6optlen) {
- if ((scmsg = (char *)malloc(ip6optlen)) == 0)
+ if ((scmsg = (char *)malloc(ip6optlen)) == NULL)
errx(1, "can't allocate enough memory");
smsghdr.msg_control = (caddr_t)scmsg;
smsghdr.msg_controllen = ip6optlen;
@@ -982,7 +955,7 @@ main(int argc, char *argv[])
}
if (argc > 1) { /* some intermediate addrs are specified */
- int hops, error;
+ int hops;
#ifdef USE_RFC2292BIS
int rthdrlen;
#endif
@@ -999,31 +972,30 @@ main(int argc, char *argv[])
errx(1, "can't initialize rthdr");
#else /* old advanced API */
if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
- IPV6_RTHDR_TYPE_0)) == 0)
+ IPV6_RTHDR_TYPE_0)) == NULL)
errx(1, "can't initialize rthdr");
#endif /* USE_RFC2292BIS */
for (hops = 0; hops < argc - 1; hops++) {
- struct addrinfo *iaip;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
if ((error = getaddrinfo(argv[hops], NULL, &hints,
- &iaip)))
+ &res)))
errx(1, "%s", gai_strerror(error));
- if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
+ if (res->ai_addr->sa_family != AF_INET6)
errx(1,
"bad addr family of an intermediate addr");
-
+ sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
#ifdef USE_RFC2292BIS
- if (inet6_rth_add(rthdr,
- &(SIN6(iaip->ai_addr))->sin6_addr))
+ if (inet6_rth_add(rthdr, &sin6->sin6_addr))
errx(1, "can't add an intermediate node");
#else /* old advanced API */
- if (inet6_rthdr_add(scmsgp,
- &(SIN6(iaip->ai_addr))->sin6_addr,
+ if (inet6_rthdr_add(scmsg, &sin6->sin6_addr,
IPV6_RTHDR_LOOSE))
errx(1, "can't add an intermediate node");
#endif /* USE_RFC2292BIS */
- freeaddrinfo(iaip);
+ freeaddrinfo(res);
}
#ifndef USE_RFC2292BIS
@@ -1088,7 +1060,7 @@ main(int argc, char *argv[])
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
if (sockbufsize) {
- if (datalen > sockbufsize)
+ if (datalen > (size_t)sockbufsize)
warnx("you need -b to increase socket buffer size");
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
sizeof(sockbufsize)) < 0)
@@ -1139,58 +1111,50 @@ main(int argc, char *argv[])
printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
- while (preload--) /* Fire off them quickies. */
- (void)pinger();
-
- (void)signal(SIGINT, onsignal);
-#ifdef SIGINFO
- (void)signal(SIGINFO, onsignal);
-#endif
-
- if ((options & F_FLOOD) == 0) {
- (void)signal(SIGALRM, onsignal);
- itimer.it_interval = interval;
- itimer.it_value = interval;
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
- if (ntransmitted == 0)
- retransmit();
+ if (preload == 0)
+ pinger();
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--)
+ pinger();
}
+ gettimeofday(&last, NULL);
-#ifndef HAVE_POLL_H
- fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
- if ((fdmaskp = malloc(fdmasks)) == NULL)
- err(1, "malloc");
-#endif
-
- seenalrm = seenint = 0;
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+ si_sa.sa_handler = onsignal;
+ if (sigaction(SIGINT, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGINT");
+ seenint = 0;
#ifdef SIGINFO
+ if (sigaction(SIGINFO, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGINFO");
seeninfo = 0;
#endif
+ if (alarmtimeout > 0) {
+ if (sigaction(SIGALRM, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGALRM");
+ }
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else if ((options & F_INTERVAL) == 0) {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
- for (;;) {
+ almost_done = 0;
+ while (seenint == 0) {
+ struct timeval now, timeout;
struct msghdr m;
struct iovec iov[2];
+ fd_set rfds;
+ int n;
/* signal handling */
- if (seenalrm) {
- /* last packet sent, timeout reached? */
- if (npackets && ntransmitted >= npackets) {
- struct timeval zerotime = {0, 0};
- itimer.it_value = zerotime;
- itimer.it_interval = zerotime;
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
- seenalrm = 0; /* clear flag */
- continue;
- }
- retransmit();
- seenalrm = 0;
- continue;
- }
- if (seenint) {
+ if (seenint)
onint(SIGINT);
- seenint = 0;
- continue;
- }
#ifdef SIGINFO
if (seeninfo) {
summary();
@@ -1198,122 +1162,121 @@ main(int argc, char *argv[])
continue;
}
#endif
-
- if (options & F_FLOOD) {
- (void)pinger();
-#ifdef HAVE_POLL_H
- timeout = 10;
-#else
- timeout.tv_sec = 0;
- timeout.tv_usec = 10000;
- tv = &timeout;
-#endif
- } else {
-#ifdef HAVE_POLL_H
- timeout = INFTIM;
-#else
- tv = NULL;
-#endif
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
}
-#ifdef HAVE_POLL_H
- fdmaskp[0].fd = s;
- fdmaskp[0].events = POLLIN;
- cc = poll(fdmaskp, 1, timeout);
-#else
- memset(fdmaskp, 0, fdmasks);
- FD_SET(s, fdmaskp);
- cc = select(s + 1, fdmaskp, NULL, NULL, tv);
-#endif
- if (cc < 0) {
- if (errno != EINTR) {
-#ifdef HAVE_POLL_H
- warn("poll");
-#else
- warn("select");
-#endif
- sleep(1);
- }
- continue;
- } else if (cc == 0)
- continue;
+ while (timeout.tv_usec > 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* EINTR */
+ if (n == 1) {
+ m.msg_name = (caddr_t)&from;
+ m.msg_namelen = sizeof(from);
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = (caddr_t)packet;
+ iov[0].iov_len = packlen;
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+ memset(cm, 0, CONTROLLEN);
+ m.msg_control = (void *)cm;
+ m.msg_controllen = CONTROLLEN;
+
+ cc = recvmsg(s, &m, 0);
+ if (cc < 0) {
+ if (errno != EINTR) {
+ warn("recvmsg");
+ sleep(1);
+ }
+ continue;
+ } else if (cc == 0) {
+ int mtu;
- m.msg_name = (caddr_t)&from;
- m.msg_namelen = sizeof(from);
- memset(&iov, 0, sizeof(iov));
- iov[0].iov_base = (caddr_t)packet;
- iov[0].iov_len = packlen;
- m.msg_iov = iov;
- m.msg_iovlen = 1;
- memset(cm, 0, CONTROLLEN);
- m.msg_control = (void *)cm;
- m.msg_controllen = CONTROLLEN;
-
- cc = recvmsg(s, &m, 0);
- if (cc < 0) {
- if (errno != EINTR) {
- warn("recvmsg");
- sleep(1);
+ /*
+ * receive control messages only. Process the
+ * exceptions (currently the only possibility is
+ * a path MTU notification.)
+ */
+ if ((mtu = get_pathmtu(&m)) > 0) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("new path MTU (%d) is "
+ "notified\n", mtu);
+ }
+ }
+ continue;
+ } else {
+ /*
+ * an ICMPv6 message (probably an echoreply)
+ * arrived.
+ */
+ pr_pack(packet, cc, &m);
}
- continue;
- } else if (cc == 0) {
- int mtu;
-
+ if (((options & F_ONCE) != 0 && nreceived > 0) ||
+ (npackets > 0 && nreceived >= npackets))
+ break;
+ }
+ if (n == 0 || (options & F_FLOOD)) {
+ if (npackets == 0 || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
/*
- * receive control messages only. Process the
- * exceptions (currently the only possiblity is
- * a path MTU notification.)
+ * If we're not transmitting any more packets,
+ * change the timer to wait two round-trip times
+ * if we've received any packets or (waittime)
+ * milliseconds if we haven't.
*/
- if ((mtu = get_pathmtu(&m)) > 0) {
- if ((options & F_VERBOSE) != 0) {
- printf("new path MTU (%d) is "
- "notified\n", mtu);
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (intvl.tv_sec == 0)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
}
}
- continue;
- } else {
- /*
- * an ICMPv6 message (probably an echoreply) arrived.
- */
- pr_pack(packet, cc, &m);
- }
- if (((options & F_ONCE) != 0 && nreceived > 0) ||
- (npackets > 0 && nreceived >= npackets))
- break;
- if (ntransmitted - nreceived - 1 > nmissedmax) {
- nmissedmax = ntransmitted - nreceived - 1;
- if (options & F_MISSED)
- (void)write(STDOUT_FILENO, &BBELL, 1);
+ gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ }
}
}
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+ si_sa.sa_handler = SIG_IGN;
+ sigaction(SIGINT, &si_sa, 0);
+ sigaction(SIGALRM, &si_sa, 0);
summary();
- if (res != NULL) {
- freeaddrinfo(res);
- res = NULL;
- }
-
- if(packet != NULL) {
+ if(packet != NULL)
free(packet);
- packet = NULL;
- }
-
-#ifndef HAVE_POLL_H
- if(fdmaskp != NULL)
- free(fdmaskp);
-#endif
exit(nreceived == 0 ? 2 : 0);
}
-void
+static void
onsignal(int sig)
{
switch (sig) {
- case SIGALRM:
- seenalrm++;
- break;
case SIGINT:
+ case SIGALRM:
seenint++;
break;
#ifdef SIGINFO
@@ -1325,38 +1288,6 @@ onsignal(int sig)
}
/*
- * retransmit --
- * This routine transmits another ping6.
- */
-void
-retransmit(void)
-{
- struct itimerval itimer;
-
- if (pinger() == 0)
- return;
-
- /*
- * If we're not transmitting any more packets, change the timer
- * to wait two round-trip times if we've received any packets or
- * ten seconds if we haven't.
- */
-#define MAXWAIT 10
- if (nreceived) {
- itimer.it_value.tv_sec = 2 * tmax / 1000;
- if (itimer.it_value.tv_sec == 0)
- itimer.it_value.tv_sec = 1;
- } else
- itimer.it_value.tv_sec = MAXWAIT;
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = 0;
- itimer.it_value.tv_usec = 0;
-
- (void)signal(SIGALRM, onsignal);
- (void)setitimer(ITIMER_REAL, &itimer, NULL);
-}
-
-/*
* pinger --
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
@@ -1364,7 +1295,7 @@ retransmit(void)
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
*/
-size_t
+static size_t
pingerlen(void)
{
size_t l;
@@ -1383,7 +1314,7 @@ pingerlen(void)
return l;
}
-int
+static int
pinger(void)
{
struct icmp6_hdr *icp;
@@ -1498,7 +1429,7 @@ pinger(void)
return(0);
}
-int
+static int
myechoreply(const struct icmp6_hdr *icp)
{
if (ntohs(icp->icmp6_id) == ident)
@@ -1507,7 +1438,7 @@ myechoreply(const struct icmp6_hdr *icp)
return 0;
}
-int
+static int
mynireply(const struct icmp6_nodeinfo *nip)
{
if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
@@ -1518,7 +1449,7 @@ mynireply(const struct icmp6_nodeinfo *nip)
return 0;
}
-char *
+static char *
dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
size_t bufsiz)
/*base for compressed name*/
@@ -1562,7 +1493,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
while (i-- > 0 && cp < ep) {
l = snprintf(cresult, sizeof(cresult),
isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
- if (l >= sizeof(cresult) || l < 0)
+ if ((size_t)l >= sizeof(cresult) || l < 0)
return NULL;
if (strlcat(buf, cresult, bufsiz) >= bufsiz)
return NULL; /*result overrun*/
@@ -1585,7 +1516,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
*/
-void
+static void
pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
{
#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
@@ -1617,7 +1548,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
}
from = (struct sockaddr *)mhdr->msg_name;
fromlen = mhdr->msg_namelen;
- if (cc < sizeof(struct icmp6_hdr)) {
+ if (cc < (int)sizeof(struct icmp6_hdr)) {
if (options & F_VERBOSE)
warnx("packet too short (%d bytes) from %s", cc,
pr_addr(from, fromlen));
@@ -1669,6 +1600,11 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
if (options & F_QUIET)
return;
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
if (options & F_FLOOD)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
@@ -1866,7 +1802,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
#undef safeputc
}
-void
+static void
pr_exthdrs(struct msghdr *mhdr)
{
ssize_t bufsize;
@@ -1904,7 +1840,7 @@ pr_exthdrs(struct msghdr *mhdr)
}
#ifdef USE_RFC2292BIS
-void
+static void
pr_ip6opt(void *extbuf, size_t bufsize)
{
struct ip6_hbh *ext;
@@ -1967,7 +1903,7 @@ pr_ip6opt(void *extbuf, size_t bufsize)
}
#else /* !USE_RFC2292BIS */
/* ARGSUSED */
-void
+static void
pr_ip6opt(void *extbuf, size_t bufsize __unused)
{
putchar('\n');
@@ -1976,7 +1912,7 @@ pr_ip6opt(void *extbuf, size_t bufsize __unused)
#endif /* USE_RFC2292BIS */
#ifdef USE_RFC2292BIS
-void
+static void
pr_rthdr(void *extbuf, size_t bufsize)
{
struct in6_addr *in6;
@@ -2033,7 +1969,7 @@ pr_rthdr(void *extbuf, size_t bufsize)
#else /* !USE_RFC2292BIS */
/* ARGSUSED */
-void
+static void
pr_rthdr(void *extbuf, size_t bufsize __unused)
{
putchar('\n');
@@ -2041,7 +1977,7 @@ pr_rthdr(void *extbuf, size_t bufsize __unused)
}
#endif /* USE_RFC2292BIS */
-int
+static int
pr_bitrange(u_int32_t v, int soff, int ii)
{
int off;
@@ -2087,7 +2023,7 @@ pr_bitrange(u_int32_t v, int soff, int ii)
return ii;
}
-void
+static void
pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
/* ni->qtype must be SUPTYPES */
{
@@ -2153,7 +2089,7 @@ pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
}
}
-void
+static void
pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
/* ni->qtype must be NODEADDR */
{
@@ -2219,7 +2155,7 @@ pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
}
}
-int
+static int
get_hoplim(struct msghdr *mhdr)
{
struct cmsghdr *cm;
@@ -2238,7 +2174,7 @@ get_hoplim(struct msghdr *mhdr)
return(-1);
}
-struct in6_pktinfo *
+static struct in6_pktinfo *
get_rcvpktinfo(struct msghdr *mhdr)
{
struct cmsghdr *cm;
@@ -2257,7 +2193,7 @@ get_rcvpktinfo(struct msghdr *mhdr)
return(NULL);
}
-int
+static int
get_pathmtu(struct msghdr *mhdr)
{
#ifdef IPV6_RECVPATHMTU
@@ -2317,7 +2253,7 @@ get_pathmtu(struct msghdr *mhdr)
* Subtract 2 timeval structs: out = out - in. Out is assumed to
* be >= in.
*/
-void
+static void
tvsub(struct timeval *out, struct timeval *in)
{
if ((out->tv_usec -= in->tv_usec) < 0) {
@@ -2332,34 +2268,22 @@ tvsub(struct timeval *out, struct timeval *in)
* SIGINT handler.
*/
/* ARGSUSED */
-void
+static void
onint(int notused __unused)
{
- summary();
-
- if (res != NULL)
- freeaddrinfo(res);
-
- if(packet != NULL)
- free(packet);
-
-#ifndef HAVE_POLL_H
- if(fdmaskp != NULL)
- free(fdmaskp);
-#endif
-
- (void)signal(SIGINT, SIG_DFL);
- (void)kill(getpid(), SIGINT);
-
- /* NOTREACHED */
- exit(1);
+ /*
+ * When doing reverse DNS lookups, the seenint flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if ((options & F_HOSTNAME) && seenint != 0)
+ _exit(nreceived ? 0 : 2);
}
/*
* summary --
* Print out statistics.
*/
-void
+static void
summary(void)
{
@@ -2376,6 +2300,8 @@ summary(void)
((((double)ntransmitted - nreceived) * 100.0) /
ntransmitted));
}
+ if (nrcvtimeout)
+ printf(", %ld packets out of wait time", nrcvtimeout);
(void)putchar('\n');
if (nreceived && timing) {
/* Only display average to microseconds */
@@ -2407,7 +2333,7 @@ static const char *nircode[] = {
* pr_icmph --
* Print a descriptive string about an ICMP header.
*/
-void
+static void
pr_icmph(struct icmp6_hdr *icp, u_char *end)
{
char ntop_buf[INET6_ADDRSTRLEN];
@@ -2622,7 +2548,7 @@ pr_icmph(struct icmp6_hdr *icp, u_char *end)
break;
}
if (options & F_VERBOSE) {
- if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
+ if (ni->ni_code > nitems(nircode))
printf(", invalid");
else
printf(", %s", nircode[ni->ni_code]);
@@ -2637,7 +2563,7 @@ pr_icmph(struct icmp6_hdr *icp, u_char *end)
* pr_iph --
* Print an IP6 header.
*/
-void
+static void
pr_iph(struct ip6_hdr *ip6)
{
u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
@@ -2665,7 +2591,7 @@ pr_iph(struct ip6_hdr *ip6)
* Return an ascii host address as a dotted quad and optionally with
* a hostname.
*/
-const char *
+static const char *
pr_addr(struct sockaddr *addr, int addrlen)
{
static char buf[NI_MAXHOST];
@@ -2684,13 +2610,13 @@ pr_addr(struct sockaddr *addr, int addrlen)
* pr_retip --
* Dump some info on a returned (via ICMPv6) IPv6 packet.
*/
-void
+static void
pr_retip(struct ip6_hdr *ip6, u_char *end)
{
u_char *cp = (u_char *)ip6, nh;
int hlen;
- if (end - (u_char *)ip6 < sizeof(*ip6)) {
+ if ((size_t)(end - (u_char *)ip6) < sizeof(*ip6)) {
printf("IP6");
goto trunc;
}
@@ -2764,7 +2690,7 @@ pr_retip(struct ip6_hdr *ip6, u_char *end)
return;
}
-void
+static void
fill(char *bp, char *patp)
{
int ii, jj, kk;
@@ -2772,7 +2698,11 @@ fill(char *bp, char *patp)
char *cp;
for (cp = patp; *cp; cp++)
- if (!isxdigit((unsigned char) *cp))
+#ifndef __rtems__
+ if (!isxdigit(*cp))
+#else /* __rtems__ */
+ if (!isxdigit((unsigned char)*cp))
+#endif /* __rtems__ */
errx(1, "patterns must be specified as hex digits");
ii = sscanf(patp,
"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
@@ -2783,7 +2713,7 @@ fill(char *bp, char *patp)
/* xxx */
if (ii > 0)
for (kk = 0;
- kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
+ (size_t)kk <= MAXDATALEN - 8 + sizeof(struct tv32) + ii;
kk += ii)
for (jj = 0; jj < ii; ++jj)
bp[jj + kk] = pat[jj];
@@ -2797,7 +2727,7 @@ fill(char *bp, char *patp)
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
-int
+static int
setpolicy(int so __unused, char *policy)
{
char *buf;
@@ -2818,7 +2748,7 @@ setpolicy(int so __unused, char *policy)
#endif
#endif
-char *
+static char *
nigroup(char *name, int nig_oldmcprefix)
{
char *p;
@@ -2877,7 +2807,7 @@ nigroup(char *name, int nig_oldmcprefix)
return strdup(hbuf);
}
-void
+static void
usage(void)
{
(void)fprintf(stderr,
@@ -2901,6 +2831,7 @@ usage(void)
#endif
"\n"
" [-p pattern] [-S sourceaddr] [-s packetsize] "
- "[hops ...] host\n");
+ "[-x waittime]\n"
+ " [-X timeout] [hops ...] host\n");
exit(1);
}
diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-data.h b/freebsd/sbin/ping6/rtems-bsd-ping6-data.h
new file mode 100644
index 00000000..40e781b8
--- /dev/null
+++ b/freebsd/sbin/ping6/rtems-bsd-ping6-data.h
@@ -0,0 +1,4 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+/* ping6.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, extern u_int options);
diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h b/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h
new file mode 100644
index 00000000..8b875692
--- /dev/null
+++ b/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h
@@ -0,0 +1,3 @@
+/* generated by userspace-header-gen.py */
+/* ping6.c */
+#define options _bsd_ping6_options
diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h b/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h
new file mode 100644
index 00000000..54444845
--- /dev/null
+++ b/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h
@@ -0,0 +1,40 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-ping6-data.h"
+/* ping6.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int mx_dup_ck);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct sockaddr_in6 dst);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct sockaddr_in6 src);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static socklen_t srclen);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static size_t datalen);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int s);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char BSPACE);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char BBELL);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char DOT);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char *hostname);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int ident);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int hoplimit);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_char *packet);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nmissedmax);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int npackets);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nreceived);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nrepeats);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int ntransmitted);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int interval);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int waittime);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nrcvtimeout);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int timing);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tmin);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tmax);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tsum);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tsumsq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_short naflags);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct msghdr smsghdr);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct iovec smsgiov);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char *scmsg);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static sig_atomic_t volatile seenint);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char rcvd_tbl[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_char outpack[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_int8_t nonce[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char const *niqcode[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char const *nircode[]);
diff --git a/freebsd/sbin/route/keywords b/freebsd/sbin/route/keywords
index 676f781d..82edc466 100644
--- a/freebsd/sbin/route/keywords
+++ b/freebsd/sbin/route/keywords
@@ -4,7 +4,6 @@
4
6
add
-atalk
blackhole
change
cloning
diff --git a/freebsd/sbin/route/route.c b/freebsd/sbin/route/route.c
index f2d73587..76c609af 100644
--- a/freebsd/sbin/route/route.c
+++ b/freebsd/sbin/route/route.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-route-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1983, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
@@ -41,24 +45,15 @@ static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95";
#endif
#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#ifdef __rtems__
#define __need_getopt_newlib
#include <getopt.h>
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#include <machine/rtems-bsd-commands.h>
-#endif
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#endif /* __rtems__ */
#include <rtems/bsd/sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
@@ -79,20 +74,18 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
+#include <time.h>
#include <unistd.h>
#include <ifaddrs.h>
-
-static const struct keytab {
- const char *kt_cp;
- int kt_i;
-} keywords[] = {
-#include "keywords.h"
- {0, 0}
-};
+#ifdef __rtems__
+#include "rtems-bsd-route-route-data.h"
+#endif /* __rtems__ */
struct fibl {
TAILQ_ENTRY(fibl) fl_next;
@@ -102,152 +95,120 @@ struct fibl {
int fl_errno;
};
-struct rt_ctx {
- union sockunion {
- struct sockaddr sa;
- struct sockaddr_in sin;
-#ifdef INET6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_dl sdl;
- struct sockaddr_inarp sinarp;
- struct sockaddr_storage ss; /* added to avoid memory overrun */
- } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
-
- int pid, rtm_addrs;
- int s;
- int forcehost, forcenet, nflag, af, qflag, tflag;
- int verbose, aflen;
- int locking, lockrest, debugonly;
- struct rt_metrics rt_metrics;
- u_long rtm_inits;
- uid_t uid;
- int defaultfib;
- int numfibs;
- char domain[MAXHOSTNAMELEN + 1];
- int domain_initialized;
- int rtm_seq;
- char rt_line[MAXHOSTNAMELEN + 1];
- char net_line[MAXHOSTNAMELEN + 1];
- struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
- } m_rtmsg;
- TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
+static struct keytab {
+ const char *kt_cp;
+ int kt_i;
+} const keywords[] = {
+#include "keywords.h"
+ {0, 0}
};
+static struct sockaddr_storage so[RTAX_MAX];
+static int pid, rtm_addrs;
+static int s;
+static int nflag, af, qflag, tflag;
+static int verbose, aflen;
+static int locking, lockrest, debugonly;
+static struct rt_metrics rt_metrics;
+static u_long rtm_inits;
+static uid_t uid;
+static int defaultfib;
+static int numfibs;
+static char domain[MAXHOSTNAMELEN + 1];
+static bool domain_initialized;
+static int rtm_seq;
+static char rt_line[NI_MAXHOST];
+static char net_line[MAXHOSTNAMELEN + 1];
+
#ifndef __rtems__
-struct rt_ctx rt_ctx;
+static struct {
+#else /* __rtems__ */
+static struct m_rtmsg {
#endif /* __rtems__ */
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
-typedef union sockunion *sup;
+static TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
-static void bprintf(FILE *, int, const char *);
-static void flushroutes(struct rt_ctx *, int argc, char *argv[]);
-static int flushroutes_fib(struct rt_ctx *, int);
-static int getaddr(struct rt_ctx *, int, char *, struct hostent **, int);
+static void printb(int, const char *);
+static void flushroutes(int argc, char *argv[]);
+static int flushroutes_fib(int);
+static int getaddr(int, char *, struct hostent **, int);
static int keyword(const char *);
-static void inet_makenetandmask(struct rt_ctx *, u_long, struct sockaddr_in *, u_long);
+#ifdef INET
+static void inet_makenetandmask(u_long, struct sockaddr_in *,
+ struct sockaddr_in *, u_long);
+#endif
#ifdef INET6
-static int inet6_makenetandmask(struct rt_ctx *, struct sockaddr_in6 *, const char *);
+static int inet6_makenetandmask(struct sockaddr_in6 *, const char *);
#endif
-static void interfaces(struct rt_ctx *);
-static void mask_addr(struct rt_ctx *);
-static void monitor(struct rt_ctx *, int, char *[]);
-static const char *netname(struct rt_ctx *, struct sockaddr *);
-static void newroute(struct rt_ctx *, int, char **);
-static int newroute_fib(struct rt_ctx *, int, char *, int);
-static void pmsg_addrs(struct rt_ctx *, char *, int, size_t);
-static void pmsg_common(struct rt_ctx *, struct rt_msghdr *, size_t);
-static int prefixlen(struct rt_ctx *, const char *);
-static void print_getmsg(struct rt_ctx *, struct rt_msghdr *, int, int);
-static void print_rtmsg(struct rt_ctx *, struct rt_msghdr *, size_t);
-static const char *routename(struct rt_ctx *, struct sockaddr *);
-static int rtmsg(struct rt_ctx *, int, int, int);
-static void set_metric(struct rt_ctx *, char *, int);
-static int set_sofib(struct rt_ctx *, int);
-static int set_procfib(int);
-static void sockaddr(char *, struct sockaddr *);
-static void sodump(sup, const char *);
-extern char *iso_ntoa(void);
-
-static int fiboptlist_csv(struct rt_ctx *, const char *, struct fibl_head_t *);
-static int fiboptlist_range(struct rt_ctx *, const char *, struct fibl_head_t *);
+static void interfaces(void);
+static void monitor(int, char*[]);
+static const char *netname(struct sockaddr *);
+static void newroute(int, char **);
+static int newroute_fib(int, char *, int);
+static void pmsg_addrs(char *, int, size_t);
+static void pmsg_common(struct rt_msghdr *, size_t);
+static int prefixlen(const char *);
+static void print_getmsg(struct rt_msghdr *, int, int);
+static void print_rtmsg(struct rt_msghdr *, size_t);
+static const char *routename(struct sockaddr *);
+static int rtmsg(int, int, int);
+static void set_metric(char *, int);
+static int set_sofib(int);
+static void sockaddr(char *, struct sockaddr *, size_t);
+static void sodump(struct sockaddr *, const char *);
+static int fiboptlist_csv(const char *, struct fibl_head_t *);
+static int fiboptlist_range(const char *, struct fibl_head_t *);
static void usage(const char *) __dead2;
-void
+#define READ_TIMEOUT 10
+static volatile sig_atomic_t stop_read;
+
+static void
+stopit(int sig __unused)
+{
+
+ stop_read = 1;
+}
+
+static void
usage(const char *cp)
{
if (cp != NULL)
warnx("bad keyword: %s", cp);
- (void) fprintf(stderr,
- "usage: route [-46dnqtv] command [[modifiers] args]\n");
- exit(EX_USAGE);
+ errx(EX_USAGE, "usage: route [-46dnqtv] command [[modifiers] args]");
/* NOTREACHED */
}
#ifdef __rtems__
-static int main(int argc, char **argv, struct rt_ctx *c);
+static int main(int argc, char *argv[]);
-struct main_ctx {
- int argc;
- char **argv;
- struct rt_ctx *c;
-};
+RTEMS_LINKER_RWSET(bsd_prog_route, char);
-static int
-call_main(void *ctx)
-{
- const struct main_ctx *mc = ctx;
-
- return main(mc->argc, mc->argv, mc->c);
-}
-
-int rtems_bsd_command_route(int argc, char *argv[])
+int
+rtems_bsd_command_route(int argc, char *argv[])
{
- struct rt_ctx *c;
int exit_code;
+ void *data_begin;
+ size_t data_size;
- c = calloc(1, sizeof(*c));
- if (c != NULL) {
- struct main_ctx mc;
- struct fibl *fl;
- struct fibl *tfl;
-
- mc.argc = argc;
- mc.argv = argv;
- mc.c = c;
-
- c->s = -1;
- c->aflen = sizeof(struct sockaddr_in);
- TAILQ_INIT(&c->fibl_head);
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_route);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_route);
- exit_code = rtems_bsd_program_call("route", call_main, &mc);
-
- close(c->s);
-
- TAILQ_FOREACH_SAFE(fl, &c->fibl_head, fl_next, tfl) {
- free(fl);
- }
-
- free(c);
- } else {
- exit_code = EXIT_FAILURE;
- }
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("route",
+ main, argc, argv, data_begin, data_size);
+ rtems_bsd_program_unlock();
return exit_code;
}
-
-int
-main(int argc, char **argv, struct rt_ctx *c)
-{
-#else /* __rtems__ */
+#endif /* __rtems__ */
int
main(int argc, char **argv)
{
- struct rt_ctx *c;
-#endif /* __rtems__ */
int ch;
size_t len;
#ifdef __rtems__
@@ -260,11 +221,6 @@ main(int argc, char **argv)
#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
#endif /* __rtems__ */
-#ifndef __rtems__
- c = &rt_ctx;
- c->aflen = sizeof (struct sockaddr_in);
-#endif /* __rtems__ */
-
if (argc < 2)
usage(NULL);
@@ -272,34 +228,34 @@ main(int argc, char **argv)
switch(ch) {
case '4':
#ifdef INET
- c->af = AF_INET;
- c->aflen = sizeof(struct sockaddr_in);
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
#else
errx(1, "IPv4 support is not compiled in");
#endif
break;
case '6':
#ifdef INET6
- c->af = AF_INET6;
- c->aflen = sizeof(struct sockaddr_in6);
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
#else
errx(1, "IPv6 support is not compiled in");
#endif
break;
case 'n':
- c->nflag = 1;
+ nflag = 1;
break;
case 'q':
- c->qflag = 1;
+ qflag = 1;
break;
case 'v':
- c->verbose = 1;
+ verbose = 1;
break;
case 't':
- c->tflag = 1;
+ tflag = 1;
break;
case 'd':
- c->debugonly = 1;
+ debugonly = 1;
break;
case '?':
default:
@@ -308,45 +264,45 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- c->pid = getpid();
- c->uid = geteuid();
- if (c->tflag)
- c->s = open(_PATH_DEVNULL, O_WRONLY, 0);
+ pid = getpid();
+ uid = geteuid();
+ if (tflag)
+ s = open(_PATH_DEVNULL, O_WRONLY, 0);
else
- c->s = socket(PF_ROUTE, SOCK_RAW, 0);
- if (c->s < 0)
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
err(EX_OSERR, "socket");
- len = sizeof(c->numfibs);
- if (sysctlbyname("net.fibs", (void *)&c->numfibs, &len, NULL, 0) == -1)
- c->numfibs = -1;
+ len = sizeof(numfibs);
+ if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1)
+ numfibs = -1;
- len = sizeof(c->defaultfib);
- if (c->numfibs != -1 &&
- sysctlbyname("net.my_fibnum", (void *)&c->defaultfib, &len, NULL,
+ len = sizeof(defaultfib);
+ if (numfibs != -1 &&
+ sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL,
0) == -1)
- c->defaultfib = -1;
+ defaultfib = -1;
if (*argv != NULL)
switch (keyword(*argv)) {
case K_GET:
case K_SHOW:
- c->uid = 0;
+ uid = 0;
/* FALLTHROUGH */
case K_CHANGE:
case K_ADD:
case K_DEL:
case K_DELETE:
- newroute(c, argc, argv);
+ newroute(argc, argv);
/* NOTREACHED */
case K_MONITOR:
- monitor(c, argc, argv);
+ monitor(argc, argv);
/* NOTREACHED */
case K_FLUSH:
- flushroutes(c, argc, argv);
+ flushroutes(argc, argv);
exit(0);
/* NOTREACHED */
}
@@ -355,26 +311,17 @@ main(int argc, char **argv)
}
static int
-set_sofib(struct rt_ctx *c, int fib)
+set_sofib(int fib)
{
if (fib < 0)
return (0);
- return (setsockopt(c->s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
+ return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,
sizeof(fib)));
}
static int
-set_procfib(int fib)
-{
-
- if (fib < 0)
- return (0);
- return (setfib(fib));
-}
-
-static int
-fiboptlist_range(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
+fiboptlist_range(const char *arg, struct fibl_head_t *flh)
{
struct fibl *fl;
char *str0, *str, *token, *endptr;
@@ -392,7 +339,7 @@ fiboptlist_range(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
if (errno == 0) {
if (*endptr != '\0' ||
fib[i] < 0 ||
- (c->numfibs != -1 && fib[i] > c->numfibs - 1))
+ (numfibs != -1 && fib[i] > numfibs - 1))
errno = EINVAL;
}
if (errno)
@@ -425,20 +372,21 @@ fiboptlist_range_ret:
#define ALLSTRLEN 64
static int
-fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
+fiboptlist_csv(const char *arg, struct fibl_head_t *flh)
{
struct fibl *fl;
char *str0, *str, *token, *endptr;
int fib, error;
+ str0 = str = NULL;
if (strcmp("all", arg) == 0) {
- str0 = str = calloc(1, ALLSTRLEN);
+ str = calloc(1, ALLSTRLEN);
if (str == NULL) {
error = 1;
goto fiboptlist_csv_ret;
}
- if (c->numfibs > 1)
- snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, c->numfibs - 1);
+ if (numfibs > 1)
+ snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1);
else
snprintf(str, ALLSTRLEN - 1, "%d", 0);
} else if (strcmp("default", arg) == 0) {
@@ -447,14 +395,14 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
error = 1;
goto fiboptlist_csv_ret;
}
- snprintf(str, ALLSTRLEN - 1, "%d", c->defaultfib);
+ snprintf(str, ALLSTRLEN - 1, "%d", defaultfib);
} else
str0 = str = strdup(arg);
error = 0;
while ((token = strsep(&str, ",")) != NULL) {
if (*token != '-' && strchr(token, '-') != NULL) {
- error = fiboptlist_range(c, token, flh);
+ error = fiboptlist_range(token, flh);
if (error)
goto fiboptlist_csv_ret;
} else {
@@ -463,7 +411,7 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
if (errno == 0) {
if (*endptr != '\0' ||
fib < 0 ||
- (c->numfibs != -1 && fib > c->numfibs - 1))
+ (numfibs != -1 && fib > numfibs - 1))
errno = EINVAL;
}
if (errno) {
@@ -480,7 +428,8 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh)
}
}
fiboptlist_csv_ret:
- free(str0);
+ if (str0 != NULL)
+ free(str0);
return (error);
}
@@ -489,43 +438,41 @@ fiboptlist_csv_ret:
* associated with network interfaces.
*/
static void
-flushroutes(struct rt_ctx *c, int argc, char *argv[])
+flushroutes(int argc, char *argv[])
{
struct fibl *fl;
int error;
- if (c->uid != 0 && !c->debugonly) {
+ if (uid != 0 && !debugonly && !tflag)
errx(EX_NOPERM, "must be root to alter routing table");
- }
- shutdown(c->s, SHUT_RD); /* Don't want to read back our messages */
+ shutdown(s, SHUT_RD); /* Don't want to read back our messages */
- TAILQ_INIT(&c->fibl_head);
+ TAILQ_INIT(&fibl_head);
while (argc > 1) {
argc--;
argv++;
if (**argv != '-')
usage(*argv);
switch (keyword(*argv + 1)) {
+#ifdef INET
case K_4:
case K_INET:
- c->af = AF_INET;
+ af = AF_INET;
break;
+#endif
#ifdef INET6
case K_6:
case K_INET6:
- c->af = AF_INET6;
+ af = AF_INET6;
break;
#endif
- case K_ATALK:
- c->af = AF_APPLETALK;
- break;
case K_LINK:
- c->af = AF_LINK;
+ af = AF_LINK;
break;
case K_FIB:
if (!--argc)
usage(*argv);
- error = fiboptlist_csv(c, *++argv, &c->fibl_head);
+ error = fiboptlist_csv(*++argv, &fibl_head);
if (error)
errx(EX_USAGE, "invalid fib number: %s", *argv);
break;
@@ -533,26 +480,25 @@ flushroutes(struct rt_ctx *c, int argc, char *argv[])
usage(*argv);
}
}
- if (TAILQ_EMPTY(&c->fibl_head)) {
- error = fiboptlist_csv(c, "default", &c->fibl_head);
+ if (TAILQ_EMPTY(&fibl_head)) {
+ error = fiboptlist_csv("default", &fibl_head);
if (error)
errx(EX_OSERR, "fiboptlist_csv failed.");
}
- TAILQ_FOREACH(fl, &c->fibl_head, fl_next)
- flushroutes_fib(c, fl->fl_num);
+ TAILQ_FOREACH(fl, &fibl_head, fl_next)
+ flushroutes_fib(fl->fl_num);
}
static int
-flushroutes_fib(struct rt_ctx *c, int fib)
+flushroutes_fib(int fib)
{
struct rt_msghdr *rtm;
size_t needed;
char *buf, *next, *lim;
- int mib[6], rlen, seqno, count = 0;
+ int mib[7], rlen, seqno, count = 0;
int error;
- error = set_sofib(c, fib);
- error += set_procfib(fib);
+ error = set_sofib(fib);
if (error) {
warn("fib number %d is ignored", fib);
return (error);
@@ -562,14 +508,15 @@ retry:
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
- mib[3] = 0; /* wildcard address family */
+ mib[3] = AF_UNSPEC;
mib[4] = NET_RT_DUMP;
mib[5] = 0; /* no flags */
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ mib[6] = fib;
+ if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
err(EX_OSERR, "route-sysctl-estimate");
- if ((buf = malloc(needed)) == NULL && needed != 0)
+ if ((buf = malloc(needed)) == NULL)
errx(EX_OSERR, "malloc failed");
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
if (errno == ENOMEM && count++ < 10) {
warnx("Routing table grew, retrying");
sleep(1);
@@ -579,145 +526,158 @@ retry:
err(EX_OSERR, "route-sysctl-get");
}
lim = buf + needed;
- if (c->verbose)
- (void) printf("Examining routing table from sysctl\n");
+ if (verbose)
+ (void)printf("Examining routing table from sysctl\n");
seqno = 0; /* ??? */
for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
- if (c->verbose)
- print_rtmsg(c, rtm, rtm->rtm_msglen);
+ rtm = (struct rt_msghdr *)(void *)next;
+ if (verbose)
+ print_rtmsg(rtm, rtm->rtm_msglen);
if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
continue;
- if (c->af != 0) {
+ if (af != 0) {
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
- if (sa->sa_family != c->af)
+ if (sa->sa_family != af)
continue;
}
- if (c->debugonly)
+ if (debugonly)
continue;
rtm->rtm_type = RTM_DELETE;
rtm->rtm_seq = seqno;
- rlen = write(c->s, next, rtm->rtm_msglen);
+ rlen = write(s, next, rtm->rtm_msglen);
if (rlen < 0 && errno == EPERM)
err(1, "write to routing socket");
if (rlen < (int)rtm->rtm_msglen) {
warn("write to routing socket");
- (void) printf("got only %d for rlen\n", rlen);
+ (void)printf("got only %d for rlen\n", rlen);
free(buf);
goto retry;
break;
}
seqno++;
- if (c->qflag)
+ if (qflag)
continue;
- if (c->verbose)
- print_rtmsg(c, rtm, rlen);
+ if (verbose)
+ print_rtmsg(rtm, rlen);
else {
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
- routename(c, sa) : netname(c, sa));
+ routename(sa) : netname(sa));
sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
- printf("%-20.20s ", routename(c, sa));
+ printf("%-20.20s ", routename(sa));
if (fib >= 0)
printf("-fib %-3d ", fib);
printf("done\n");
}
}
- free(buf);
return (error);
}
static const char *
-routename(struct rt_ctx *c, struct sockaddr *sa)
+routename(struct sockaddr *sa)
{
+ struct sockaddr_dl *sdl;
const char *cp;
- struct hostent *hp;
int n;
- if (c->domain_initialized) {
- c->domain_initialized = 1;
- if (gethostname(c->domain, MAXHOSTNAMELEN) == 0 &&
- (cp = strchr(c->domain, '.'))) {
- c->domain[MAXHOSTNAMELEN] = '\0';
- (void) strcpy(c->domain, cp + 1);
+ if (!domain_initialized) {
+ domain_initialized = true;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = strchr(domain, '.'))) {
+ domain[MAXHOSTNAMELEN] = '\0';
+ (void)strcpy(domain, cp + 1);
} else
- c->domain[0] = 0;
+ domain[0] = '\0';
}
- if (sa->sa_len == 0)
- strcpy(c->rt_line, "default");
- else switch (sa->sa_family) {
-
+ /* If the address is zero-filled, use "default". */
+ if (sa->sa_len == 0 && nflag == 0)
+ return ("default");
+#if defined(INET) || defined(INET6)
+ switch (sa->sa_family) {
+#ifdef INET
case AF_INET:
- { struct in_addr in;
- in = ((struct sockaddr_in *)sa)->sin_addr;
-
- cp = NULL;
- if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
- cp = "default";
- if (cp == NULL && !c->nflag) {
- hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
- AF_INET);
- if (hp != NULL) {
- char *cptr;
- cptr = strchr(hp->h_name, '.');
- if (cptr != NULL &&
- strcmp(cptr + 1, c->domain) == 0)
- *cptr = '\0';
- cp = hp->h_name;
- }
- }
- if (cp != NULL) {
- strncpy(c->rt_line, cp, sizeof(c->rt_line) - 1);
- c->rt_line[sizeof(c->rt_line) - 1] = '\0';
- } else
- (void) sprintf(c->rt_line, "%s", inet_ntoa(in));
+ /* If the address is zero-filled, use "default". */
+ if (nflag == 0 &&
+ ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr ==
+ INADDR_ANY)
+ return("default");
break;
- }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ /* If the address is zero-filled, use "default". */
+ if (nflag == 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr))
+ return("default");
+ break;
+#endif
+ }
+#endif
+ switch (sa->sa_family) {
+#if defined(INET) || defined(INET6)
+#ifdef INET
+ case AF_INET:
+#endif
#ifdef INET6
case AF_INET6:
+#endif
{
- struct sockaddr_in6 sin6; /* use static var for safety */
- int niflags = 0;
+ struct sockaddr_storage ss;
+ int error;
+ char *p;
- memset(&sin6, 0, sizeof(sin6));
- memcpy(&sin6, sa, sa->sa_len);
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_family = AF_INET6;
-#ifdef __KAME__
- if (sa->sa_len == sizeof(struct sockaddr_in6) &&
- (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) &&
- sin6.sin6_scope_id == 0) {
- sin6.sin6_scope_id =
- ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
- sin6.sin6_addr.s6_addr[2] = 0;
- sin6.sin6_addr.s6_addr[3] = 0;
+ memset(&ss, 0, sizeof(ss));
+ if (sa->sa_len == 0)
+ ss.ss_family = sa->sa_family;
+ else
+ memcpy(&ss, sa, sa->sa_len);
+ /* Expand sa->sa_len because it could be shortened. */
+ if (sa->sa_family == AF_INET)
+ ss.ss_len = sizeof(struct sockaddr_in);
+ else if (sa->sa_family == AF_INET6)
+ ss.ss_len = sizeof(struct sockaddr_in6);
+ error = getnameinfo((struct sockaddr *)&ss, ss.ss_len,
+ rt_line, sizeof(rt_line), NULL, 0,
+ (nflag == 0) ? 0 : NI_NUMERICHOST);
+ if (error) {
+ warnx("getnameinfo(): %s", gai_strerror(error));
+ strncpy(rt_line, "invalid", sizeof(rt_line));
}
-#endif
- if (c->nflag)
- niflags |= NI_NUMERICHOST;
- if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
- c->rt_line, sizeof(c->rt_line), NULL, 0, niflags) != 0)
- strncpy(c->rt_line, "invalid", sizeof(c->rt_line));
- return(c->rt_line);
+ /* Remove the domain part if any. */
+ p = strchr(rt_line, '.');
+ if (p != NULL && strcmp(p + 1, domain) == 0)
+ *p = '\0';
+
+ return (rt_line);
+ break;
}
#endif
-
case AF_LINK:
- return (link_ntoa((struct sockaddr_dl *)sa));
+ sdl = (struct sockaddr_dl *)(void *)sa;
+
+ if (sdl->sdl_nlen == 0 &&
+ sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ n = snprintf(rt_line, sizeof(rt_line), "link#%d",
+ sdl->sdl_index);
+ if (n > (int)sizeof(rt_line))
+ rt_line[0] = '\0';
+ return (rt_line);
+ } else
+ return (link_ntoa(sdl));
+ break;
default:
{
- u_short *sp = (u_short *)sa;
+ u_short *sp = (u_short *)(void *)sa;
u_short *splim = sp + ((sa->sa_len + 1) >> 1);
- char *cps = c->rt_line + sprintf(c->rt_line, "(%d)", sa->sa_family);
- char *cpe = c->rt_line + sizeof(c->rt_line);
+ char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family);
+ char *cpe = rt_line + sizeof(rt_line);
while (++sp < splim && cps < cpe) /* start with sa->sa_data */
if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0)
@@ -727,118 +687,98 @@ routename(struct rt_ctx *c, struct sockaddr *sa)
break;
}
}
- return (c->rt_line);
+ return (rt_line);
}
/*
* Return the name of the network whose address is given.
- * The address is assumed to be that of a net or subnet, not a host.
+ * The address is assumed to be that of a net, not a host.
*/
-const char *
-netname(struct rt_ctx *c, struct sockaddr *sa)
+static const char *
+netname(struct sockaddr *sa)
{
- const char *cp = NULL;
+ struct sockaddr_dl *sdl;
+ int n;
+#ifdef INET
struct netent *np = NULL;
- u_long net, mask;
+ const char *cp = NULL;
u_long i;
- int n, subnetshift;
+#endif
switch (sa->sa_family) {
-
+#ifdef INET
case AF_INET:
- { struct in_addr in;
- in = ((struct sockaddr_in *)sa)->sin_addr;
+ {
+ struct in_addr in;
+ in = ((struct sockaddr_in *)(void *)sa)->sin_addr;
i = in.s_addr = ntohl(in.s_addr);
if (in.s_addr == 0)
cp = "default";
- else if (!c->nflag) {
- if (IN_CLASSA(i)) {
- mask = IN_CLASSA_NET;
- subnetshift = 8;
- } else if (IN_CLASSB(i)) {
- mask = IN_CLASSB_NET;
- subnetshift = 8;
- } else {
- mask = IN_CLASSC_NET;
- subnetshift = 4;
- }
- /*
- * If there are more bits than the standard mask
- * would suggest, subnets must be in use.
- * Guess at the subnet mask, assuming reasonable
- * width subnet fields.
- */
- while (in.s_addr &~ mask)
- mask = (long)mask >> subnetshift;
- net = in.s_addr & mask;
- while ((mask & 1) == 0)
- mask >>= 1, net >>= 1;
- np = getnetbyaddr(net, AF_INET);
+ else if (!nflag) {
+ np = getnetbyaddr(i, AF_INET);
if (np != NULL)
cp = np->n_name;
}
#define C(x) (unsigned)((x) & 0xff)
if (cp != NULL)
- strncpy(c->net_line, cp, sizeof(c->net_line));
+ strncpy(net_line, cp, sizeof(net_line));
else if ((in.s_addr & 0xffffff) == 0)
- (void) sprintf(c->net_line, "%u", C(in.s_addr >> 24));
+ (void)sprintf(net_line, "%u", C(in.s_addr >> 24));
else if ((in.s_addr & 0xffff) == 0)
- (void) sprintf(c->net_line, "%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(net_line, "%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16));
else if ((in.s_addr & 0xff) == 0)
- (void) sprintf(c->net_line, "%u.%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(net_line, "%u.%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16), C(in.s_addr >> 8));
else
- (void) sprintf(c->net_line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(net_line, "%u.%u.%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16), C(in.s_addr >> 8),
C(in.s_addr));
#undef C
break;
- }
-
+ }
+#endif
#ifdef INET6
case AF_INET6:
{
- struct sockaddr_in6 sin6; /* use static var for safety */
+ struct sockaddr_in6 sin6;
int niflags = 0;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6, sa, sa->sa_len);
- sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
-#ifdef __KAME__
- if (sa->sa_len == sizeof(struct sockaddr_in6) &&
- (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) &&
- sin6.sin6_scope_id == 0) {
- sin6.sin6_scope_id =
- ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
- sin6.sin6_addr.s6_addr[2] = 0;
- sin6.sin6_addr.s6_addr[3] = 0;
- }
-#endif
- if (c->nflag)
+ if (nflag)
niflags |= NI_NUMERICHOST;
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
- c->net_line, sizeof(c->net_line), NULL, 0, niflags) != 0)
- strncpy(c->net_line, "invalid", sizeof(c->net_line));
+ net_line, sizeof(net_line), NULL, 0, niflags) != 0)
+ strncpy(net_line, "invalid", sizeof(net_line));
- return(c->net_line);
+ return(net_line);
}
#endif
-
case AF_LINK:
- return (link_ntoa((struct sockaddr_dl *)sa));
-
+ sdl = (struct sockaddr_dl *)(void *)sa;
+
+ if (sdl->sdl_nlen == 0 &&
+ sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ n = snprintf(net_line, sizeof(net_line), "link#%d",
+ sdl->sdl_index);
+ if (n > (int)sizeof(net_line))
+ net_line[0] = '\0';
+ return (net_line);
+ } else
+ return (link_ntoa(sdl));
+ break;
default:
{
- u_short *sp = (u_short *)sa->sa_data;
+ u_short *sp = (u_short *)(void *)sa->sa_data;
u_short *splim = sp + ((sa->sa_len + 1)>>1);
- char *cps = c->net_line + sprintf(c->net_line, "af %d:", sa->sa_family);
- char *cpe = c->net_line + sizeof(c->net_line);
+ char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family);
+ char *cpe = net_line + sizeof(net_line);
while (sp < splim && cps < cpe)
if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0)
@@ -848,17 +788,18 @@ netname(struct rt_ctx *c, struct sockaddr *sa)
break;
}
}
- return (c->net_line);
+ return (net_line);
}
static void
-set_metric(struct rt_ctx *c, char *value, int key)
+set_metric(char *value, int key)
{
int flag = 0;
+ char *endptr;
u_long noval, *valp = &noval;
switch (key) {
-#define caseof(x, y, z) case x: valp = &c->rt_metrics.z; flag = y; break
+#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break
caseof(K_MTU, RTV_MTU, rmx_mtu);
caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
@@ -869,12 +810,23 @@ set_metric(struct rt_ctx *c, char *value, int key)
caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight);
}
- c->rtm_inits |= flag;
- if (c->lockrest || c->locking)
- c->rt_metrics.rmx_locks |= flag;
- if (c->locking)
- c->locking = 0;
- *valp = atoi(value);
+ rtm_inits |= flag;
+ if (lockrest || locking)
+ rt_metrics.rmx_locks |= flag;
+ if (locking)
+ locking = 0;
+ errno = 0;
+ *valp = strtol(value, &endptr, 0);
+ if (errno == 0 && *endptr != '\0')
+ errno = EINVAL;
+ if (errno)
+ err(EX_USAGE, "%s", value);
+ if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) {
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME_FAST, &ts);
+ *valp += ts.tv_sec;
+ }
}
#define F_ISHOST 0x01
@@ -884,51 +836,57 @@ set_metric(struct rt_ctx *c, char *value, int key)
#define F_INTERFACE 0x10
static void
-newroute(struct rt_ctx *c, int argc, char **argv)
+newroute(int argc, char **argv)
{
+ struct sigaction sa;
struct hostent *hp;
struct fibl *fl;
char *cmd;
const char *dest, *gateway, *errmsg;
int key, error, flags, nrflags, fibnum;
- if (c->uid != 0) {
+ if (uid != 0 && !debugonly && !tflag)
errx(EX_NOPERM, "must be root to alter routing table");
- }
-
dest = NULL;
gateway = NULL;
flags = RTF_STATIC;
nrflags = 0;
hp = NULL;
- TAILQ_INIT(&c->fibl_head);
+ TAILQ_INIT(&fibl_head);
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = stopit;
+ if (sigaction(SIGALRM, &sa, 0) == -1)
+ warn("sigaction SIGALRM");
cmd = argv[0];
if (*cmd != 'g' && *cmd != 's')
- shutdown(c->s, SHUT_RD); /* Don't want to read back our messages */
-
+ shutdown(s, SHUT_RD); /* Don't want to read back our messages */
while (--argc > 0) {
if (**(++argv)== '-') {
switch (key = keyword(1 + *argv)) {
case K_LINK:
- c->af = AF_LINK;
- c->aflen = sizeof(struct sockaddr_dl);
+ af = AF_LINK;
+ aflen = sizeof(struct sockaddr_dl);
break;
+#ifdef INET
case K_4:
case K_INET:
- c->af = AF_INET;
- c->aflen = sizeof(struct sockaddr_in);
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
break;
+#endif
#ifdef INET6
case K_6:
case K_INET6:
- c->af = AF_INET6;
- c->aflen = sizeof(struct sockaddr_in6);
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
break;
#endif
case K_SA:
- c->af = PF_ROUTE;
- c->aflen = sizeof(union sockunion);
+ af = PF_ROUTE;
+ aflen = sizeof(struct sockaddr_storage);
break;
case K_IFACE:
case K_INTERFACE:
@@ -938,10 +896,10 @@ newroute(struct rt_ctx *c, int argc, char **argv)
flags &= ~RTF_STATIC;
break;
case K_LOCK:
- c->locking = 1;
+ locking = 1;
break;
case K_LOCKREST:
- c->lockrest = 1;
+ lockrest = 1;
break;
case K_HOST:
nrflags |= F_FORCEHOST;
@@ -976,7 +934,7 @@ newroute(struct rt_ctx *c, int argc, char **argv)
case K_FIB:
if (!--argc)
usage(NULL);
- error = fiboptlist_csv(c, *++argv, &c->fibl_head);
+ error = fiboptlist_csv(*++argv, &fibl_head);
if (error)
errx(EX_USAGE,
"invalid fib number: %s", *argv);
@@ -984,35 +942,35 @@ newroute(struct rt_ctx *c, int argc, char **argv)
case K_IFA:
if (!--argc)
usage(NULL);
- getaddr(c, RTA_IFA, *++argv, 0, nrflags);
+ getaddr(RTAX_IFA, *++argv, 0, nrflags);
break;
case K_IFP:
if (!--argc)
usage(NULL);
- getaddr(c, RTA_IFP, *++argv, 0, nrflags);
+ getaddr(RTAX_IFP, *++argv, 0, nrflags);
break;
case K_GENMASK:
if (!--argc)
usage(NULL);
- getaddr(c, RTA_GENMASK, *++argv, 0, nrflags);
+ getaddr(RTAX_GENMASK, *++argv, 0, nrflags);
break;
case K_GATEWAY:
if (!--argc)
usage(NULL);
- getaddr(c, RTA_GATEWAY, *++argv, 0, nrflags);
+ getaddr(RTAX_GATEWAY, *++argv, 0, nrflags);
gateway = *argv;
break;
case K_DST:
if (!--argc)
usage(NULL);
- if (getaddr(c, RTA_DST, *++argv, &hp, nrflags))
+ if (getaddr(RTAX_DST, *++argv, &hp, nrflags))
nrflags |= F_ISHOST;
dest = *argv;
break;
case K_NETMASK:
if (!--argc)
usage(NULL);
- getaddr(c, RTA_NETMASK, *++argv, 0, nrflags);
+ getaddr(RTAX_NETMASK, *++argv, 0, nrflags);
/* FALLTHROUGH */
case K_NET:
nrflags |= F_FORCENET;
@@ -1020,7 +978,7 @@ newroute(struct rt_ctx *c, int argc, char **argv)
case K_PREFIXLEN:
if (!--argc)
usage(NULL);
- if (prefixlen(c, *++argv) == -1) {
+ if (prefixlen(*++argv) == -1) {
nrflags &= ~F_FORCENET;
nrflags |= F_ISHOST;
} else {
@@ -1039,32 +997,44 @@ newroute(struct rt_ctx *c, int argc, char **argv)
case K_WEIGHT:
if (!--argc)
usage(NULL);
- set_metric(c, *++argv, key);
+ set_metric(*++argv, key);
break;
default:
usage(1+*argv);
}
} else {
- if ((c->rtm_addrs & RTA_DST) == 0) {
+ if ((rtm_addrs & RTA_DST) == 0) {
dest = *argv;
- if (getaddr(c, RTA_DST, *argv, &hp, nrflags))
+ if (getaddr(RTAX_DST, *argv, &hp, nrflags))
nrflags |= F_ISHOST;
- } else if ((c->rtm_addrs & RTA_GATEWAY) == 0) {
+ } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
gateway = *argv;
- getaddr(c, RTA_GATEWAY, *argv, &hp, nrflags);
+ getaddr(RTAX_GATEWAY, *argv, &hp, nrflags);
} else {
- getaddr(c, RTA_NETMASK, *argv, 0, nrflags);
+ getaddr(RTAX_NETMASK, *argv, 0, nrflags);
nrflags |= F_FORCENET;
}
}
}
+ /* Do some sanity checks on resulting request */
+ if (so[RTAX_DST].ss_len == 0) {
+ warnx("destination parameter required");
+ usage(NULL);
+ }
+
+ if (so[RTAX_NETMASK].ss_len != 0 &&
+ so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) {
+ warnx("destination and netmask family need to be the same");
+ usage(NULL);
+ }
+
if (nrflags & F_FORCEHOST) {
nrflags |= F_ISHOST;
#ifdef INET6
- if (c->af == AF_INET6) {
- c->rtm_addrs &= ~RTA_NETMASK;
- memset((void *)&c->so_mask, 0, sizeof(c->so_mask));
+ if (af == AF_INET6) {
+ rtm_addrs &= ~RTA_NETMASK;
+ memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK]));
}
#endif
}
@@ -1075,23 +1045,21 @@ newroute(struct rt_ctx *c, int argc, char **argv)
flags |= RTF_HOST;
if ((nrflags & F_INTERFACE) == 0)
flags |= RTF_GATEWAY;
- if (nrflags & F_PROXY) {
- c->so_dst.sinarp.sin_other = SIN_PROXY;
+ if (nrflags & F_PROXY)
flags |= RTF_ANNOUNCE;
- }
if (dest == NULL)
dest = "";
if (gateway == NULL)
gateway = "";
- if (TAILQ_EMPTY(&c->fibl_head)) {
- error = fiboptlist_csv(c, "default", &c->fibl_head);
+ if (TAILQ_EMPTY(&fibl_head)) {
+ error = fiboptlist_csv("default", &fibl_head);
if (error)
errx(EX_OSERR, "fiboptlist_csv failed.");
}
error = 0;
- TAILQ_FOREACH(fl, &c->fibl_head, fl_next) {
- fl->fl_error = newroute_fib(c, fl->fl_num, cmd, flags);
+ TAILQ_FOREACH(fl, &fibl_head, fl_next) {
+ fl->fl_error = newroute_fib(fl->fl_num, cmd, flags);
if (fl->fl_error)
fl->fl_errno = errno;
error += fl->fl_error;
@@ -1100,9 +1068,9 @@ newroute(struct rt_ctx *c, int argc, char **argv)
exit(error);
error = 0;
- if (!c->qflag) {
+ if (!qflag) {
fibnum = 0;
- TAILQ_FOREACH(fl, &c->fibl_head, fl_next) {
+ TAILQ_FOREACH(fl, &fibl_head, fl_next) {
if (fl->fl_error == 0)
fibnum++;
}
@@ -1114,8 +1082,8 @@ newroute(struct rt_ctx *c, int argc, char **argv)
if (*gateway)
printf(": gateway %s", gateway);
- if (c->numfibs > 1) {
- TAILQ_FOREACH(fl, &c->fibl_head, fl_next) {
+ if (numfibs > 1) {
+ TAILQ_FOREACH(fl, &fibl_head, fl_next) {
if (fl->fl_error == 0
&& fl->fl_num >= 0) {
if (firstfib) {
@@ -1132,7 +1100,7 @@ newroute(struct rt_ctx *c, int argc, char **argv)
}
fibnum = 0;
- TAILQ_FOREACH(fl, &c->fibl_head, fl_next) {
+ TAILQ_FOREACH(fl, &fibl_head, fl_next) {
if (fl->fl_error != 0) {
printf("%s %s %s", cmd, (nrflags & F_ISHOST)
? "host" : "net", dest);
@@ -1175,47 +1143,45 @@ newroute(struct rt_ctx *c, int argc, char **argv)
}
static int
-newroute_fib(struct rt_ctx *c, int fib, char *cmd, int flags)
+newroute_fib(int fib, char *cmd, int flags)
{
int error;
- error = set_sofib(c, fib);
+ error = set_sofib(fib);
if (error) {
warn("fib number %d is ignored", fib);
return (error);
}
- error = rtmsg(c, *cmd, flags, fib);
+ error = rtmsg(*cmd, flags, fib);
return (error);
}
+#ifdef INET
static void
-inet_makenetandmask(struct rt_ctx *c, u_long net, struct sockaddr_in *sin, u_long bits)
+inet_makenetandmask(u_long net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, u_long bits)
{
- u_long addr, mask = 0;
- char *cp;
+ u_long mask = 0;
+
+ rtm_addrs |= RTA_NETMASK;
- c->rtm_addrs |= RTA_NETMASK;
/*
- * XXX: This approach unable to handle 0.0.0.1/32 correctly
- * as inet_network() converts 0.0.0.1 and 1 equally.
+ * MSB of net should be meaningful. 0/0 is exception.
*/
- if (net <= 0xff)
- addr = net << IN_CLASSA_NSHIFT;
- else if (net <= 0xffff)
- addr = net << IN_CLASSB_NSHIFT;
- else if (net <= 0xffffff)
- addr = net << IN_CLASSC_NSHIFT;
- else
- addr = net;
+ if (net > 0)
+ while ((net & 0xff000000) == 0)
+ net <<= 8;
+
/*
* If no /xx was specified we must calculate the
* CIDR address.
*/
- if ((bits == 0) && (addr != 0)) {
+ if ((bits == 0) && (net != 0)) {
u_long i, j;
- for(i=0,j=0xff; i<4; i++) {
- if (addr & j) {
+
+ for(i = 0, j = 0xff; i < 4; i++) {
+ if (net & j) {
break;
}
j <<= 8;
@@ -1226,43 +1192,31 @@ inet_makenetandmask(struct rt_ctx *c, u_long net, struct sockaddr_in *sin, u_lon
if (bits != 0)
mask = 0xffffffff << (32 - bits);
- sin->sin_addr.s_addr = htonl(addr);
- sin = &c->so_mask.sin;
- sin->sin_addr.s_addr = htonl(mask);
- sin->sin_len = 0;
- sin->sin_family = 0;
- cp = (char *)(&sin->sin_addr + 1);
- while (*--cp == 0 && cp > (char *)sin)
- ;
- sin->sin_len = 1 + cp - (char *)sin;
+ sin->sin_addr.s_addr = htonl(net);
+ sin_mask->sin_addr.s_addr = htonl(mask);
+ sin_mask->sin_len = sizeof(struct sockaddr_in);
+ sin_mask->sin_family = AF_INET;
}
+#endif
#ifdef INET6
/*
* XXX the function may need more improvement...
*/
static int
-inet6_makenetandmask(struct rt_ctx *c, struct sockaddr_in6 *sin6, const char *plen)
+inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
{
- struct in6_addr in6;
if (plen == NULL) {
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
- sin6->sin6_scope_id == 0) {
+ sin6->sin6_scope_id == 0)
plen = "0";
- } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
- /* aggregatable global unicast - RFC2374 */
- memset(&in6, 0, sizeof(in6));
- if (!memcmp(&sin6->sin6_addr.s6_addr[8],
- &in6.s6_addr[8], 8))
- plen = "64";
- }
}
if (plen == NULL || strcmp(plen, "128") == 0)
return (1);
- c->rtm_addrs |= RTA_NETMASK;
- prefixlen(c, plen);
+ rtm_addrs |= RTA_NETMASK;
+ prefixlen(plen);
return (0);
}
#endif
@@ -1272,33 +1226,50 @@ inet6_makenetandmask(struct rt_ctx *c, struct sockaddr_in6 *sin6, const char *pl
* returning 1 if a host address, 0 if a network address.
*/
static int
-getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflags)
+getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
{
- sup su;
+ struct sockaddr *sa;
+#if defined(INET)
+ struct sockaddr_in *sin;
struct hostent *hp;
struct netent *np;
u_long val;
char *q;
- int afamily; /* local copy of af so we can change it */
+#elif defined(INET6)
+ char *q;
+#endif
- if (c->af == 0) {
- c->af = AF_INET;
- c->aflen = sizeof(struct sockaddr_in);
+ if (idx < 0 || idx >= RTAX_MAX)
+ usage("internal error");
+ if (af == 0) {
+#if defined(INET)
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+#elif defined(INET6)
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+#else
+ af = AF_LINK;
+ aflen = sizeof(struct sockaddr_dl);
+#endif
}
- afamily = c->af;
- c->rtm_addrs |= which;
- switch (which) {
- case RTA_DST:
- su = &c->so_dst;
- break;
- case RTA_GATEWAY:
- su = &c->so_gate;
+#ifndef INET
+ hpp = NULL;
+#endif
+ rtm_addrs |= (1 << idx);
+ sa = (struct sockaddr *)&so[idx];
+ sa->sa_family = af;
+ sa->sa_len = aflen;
+
+ switch (idx) {
+ case RTAX_GATEWAY:
if (nrflags & F_INTERFACE) {
struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa;
struct sockaddr_dl *sdl = NULL;
if (getifaddrs(&ifap))
- err(1, "getifaddrs");
+ err(EX_OSERR, "getifaddrs");
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != AF_LINK)
@@ -1307,63 +1278,41 @@ getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflag
if (strcmp(str, ifa->ifa_name) != 0)
continue;
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
}
/* If we found it, then use it */
if (sdl != NULL) {
/*
- * Copy is safe since we have a
- * sockaddr_storage member in sockunion{}.
* Note that we need to copy before calling
* freeifaddrs().
*/
- memcpy(&su->sdl, sdl, sdl->sdl_len);
+ memcpy(sdl0, sdl, sdl->sdl_len);
}
freeifaddrs(ifap);
if (sdl != NULL)
return(1);
+ else
+ errx(EX_DATAERR,
+ "interface '%s' does not exist", str);
}
break;
- case RTA_NETMASK:
- su = &c->so_mask;
+ case RTAX_IFP:
+ sa->sa_family = AF_LINK;
break;
- case RTA_GENMASK:
- su = &c->so_genmask;
- break;
- case RTA_IFP:
- su = &c->so_ifp;
- afamily = AF_LINK;
- break;
- case RTA_IFA:
- su = &c->so_ifa;
- break;
- default:
- usage("internal error");
- /*NOTREACHED*/
}
- su->sa.sa_len = c->aflen;
- su->sa.sa_family = afamily; /* cases that don't want it have left already */
if (strcmp(str, "default") == 0) {
/*
* Default is net 0.0.0.0/0
*/
- switch (which) {
- case RTA_DST:
- c->forcenet++;
-#if 0
- bzero(su, sizeof(*su)); /* for readability */
-#endif
- getaddr(c, RTA_NETMASK, str, 0, nrflags);
+ switch (idx) {
+ case RTAX_DST:
+ nrflags |= F_FORCENET;
+ getaddr(RTAX_NETMASK, str, 0, nrflags);
break;
-#if 0
- case RTA_NETMASK:
- case RTA_GENMASK:
- bzero(su, sizeof(*su)); /* for readability */
-#endif
}
return (0);
}
- switch (afamily) {
+ switch (sa->sa_family) {
#ifdef INET6
case AF_INET6:
{
@@ -1371,129 +1320,130 @@ getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflag
int ecode;
q = NULL;
- if (which == RTA_DST && (q = strchr(str, '/')) != NULL)
+ if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL)
*q = '\0';
memset(&hints, 0, sizeof(hints));
- hints.ai_family = afamily; /*AF_INET6*/
- hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_family = sa->sa_family;
+ hints.ai_socktype = SOCK_DGRAM;
ecode = getaddrinfo(str, NULL, &hints, &res);
if (ecode != 0 || res->ai_family != AF_INET6 ||
- res->ai_addrlen != sizeof(su->sin6)) {
- (void) fprintf(stderr, "%s: %s\n", str,
- gai_strerror(ecode));
- exit(1);
- }
- memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
-#ifdef __KAME__
- if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) ||
- IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr)) &&
- su->sin6.sin6_scope_id) {
- *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
- htons(su->sin6.sin6_scope_id);
- su->sin6.sin6_scope_id = 0;
- }
-#endif
+ res->ai_addrlen != sizeof(struct sockaddr_in6))
+ errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode));
+ memcpy(sa, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
if (q != NULL)
*q++ = '/';
- if (which == RTA_DST)
- return (inet6_makenetandmask(c, &su->sin6, q));
+ if (idx == RTAX_DST)
+ return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q));
return (0);
}
#endif /* INET6 */
-
case AF_LINK:
- link_addr(str, &su->sdl);
+ link_addr(str, (struct sockaddr_dl *)(void *)sa);
return (1);
-
case PF_ROUTE:
- su->sa.sa_len = sizeof(*su);
- sockaddr(str, &su->sa);
+ sockaddr(str, sa, sizeof(struct sockaddr_storage));
return (1);
-
+#ifdef INET
case AF_INET:
+#endif
default:
break;
}
+#ifdef INET
+ sin = (struct sockaddr_in *)(void *)sa;
if (hpp == NULL)
hpp = &hp;
*hpp = NULL;
q = strchr(str,'/');
- if (q != NULL && which == RTA_DST) {
+ if (q != NULL && idx == RTAX_DST) {
*q = '\0';
if ((val = inet_network(str)) != INADDR_NONE) {
- inet_makenetandmask(
- c, val, &su->sin, strtoul(q+1, 0, 0));
+ inet_makenetandmask(val, sin,
+ (struct sockaddr_in *)&so[RTAX_NETMASK],
+ strtoul(q+1, 0, 0));
return (0);
}
*q = '/';
}
- if ((which != RTA_DST || c->forcenet == 0) &&
- inet_aton(str, &su->sin.sin_addr)) {
- val = su->sin.sin_addr.s_addr;
- if (which != RTA_DST || c->forcehost ||
- inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
+ if ((idx != RTAX_DST || (nrflags & F_FORCENET) == 0) &&
+ inet_aton(str, &sin->sin_addr)) {
+ val = sin->sin_addr.s_addr;
+ if (idx != RTAX_DST || nrflags & F_FORCEHOST ||
+ inet_lnaof(sin->sin_addr) != INADDR_ANY)
return (1);
else {
val = ntohl(val);
goto netdone;
}
}
- if (which == RTA_DST && c->forcehost == 0 &&
+ if (idx == RTAX_DST && (nrflags & F_FORCEHOST) == 0 &&
((val = inet_network(str)) != INADDR_NONE ||
((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) {
netdone:
- inet_makenetandmask(c, val, &su->sin, 0);
+ inet_makenetandmask(val, sin,
+ (struct sockaddr_in *)&so[RTAX_NETMASK], 0);
return (0);
}
hp = gethostbyname(str);
if (hp != NULL) {
*hpp = hp;
- su->sin.sin_family = hp->h_addrtype;
- memmove((char *)&su->sin.sin_addr, hp->h_addr,
- MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr)));
+ sin->sin_family = hp->h_addrtype;
+ memmove((char *)&sin->sin_addr, hp->h_addr,
+ MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
return (1);
}
+#endif
errx(EX_NOHOST, "bad address: %s", str);
}
static int
-prefixlen(struct rt_ctx *c, const char *str)
+prefixlen(const char *str)
{
int len = atoi(str), q, r;
int max;
char *p;
- c->rtm_addrs |= RTA_NETMASK;
- switch (c->af) {
+ rtm_addrs |= RTA_NETMASK;
+ switch (af) {
#ifdef INET6
case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)&so[RTAX_NETMASK];
+
max = 128;
- p = (char *)&c->so_mask.sin6.sin6_addr;
+ p = (char *)&sin6->sin6_addr;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
break;
+ }
#endif
+#ifdef INET
case AF_INET:
+ {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)&so[RTAX_NETMASK];
+
max = 32;
- p = (char *)&c->so_mask.sin.sin_addr;
+ p = (char *)&sin->sin_addr;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
break;
+ }
+#endif
default:
- fprintf(stderr, "prefixlen not supported in this af\n");
- exit(1);
+ errx(EX_OSERR, "prefixlen not supported in this af");
}
- if (len < 0 || max < len) {
- fprintf(stderr, "%s: bad value\n", str);
- exit(1);
- }
+ if (len < 0 || max < len)
+ errx(EX_USAGE, "%s: invalid prefixlen", str);
q = len >> 3;
r = len & 7;
- c->so_mask.sa.sa_family = c->af;
- c->so_mask.sa.sa_len = c->aflen;
memset((void *)p, 0, max / 8);
if (q > 0)
memset((void *)p, 0xff, q);
@@ -1506,7 +1456,7 @@ prefixlen(struct rt_ctx *c, const char *str)
}
static void
-interfaces(struct rt_ctx *c)
+interfaces(void)
{
size_t needed;
int mib[6];
@@ -1517,14 +1467,14 @@ retry2:
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
- mib[3] = 0; /* wildcard address family */
+ mib[3] = AF_UNSPEC;
mib[4] = NET_RT_IFLIST;
mib[5] = 0; /* no flags */
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
err(EX_OSERR, "route-sysctl-estimate");
- if ((buf = malloc(needed)) == NULL && needed != 0)
+ if ((buf = malloc(needed)) == NULL)
errx(EX_OSERR, "malloc failed");
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
if (errno == ENOMEM && count++ < 10) {
warnx("Routing table grew, retrying");
sleep(1);
@@ -1535,19 +1485,18 @@ retry2:
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
- print_rtmsg(c, rtm, rtm->rtm_msglen);
+ rtm = (struct rt_msghdr *)(void *)next;
+ print_rtmsg(rtm, rtm->rtm_msglen);
}
- free(buf);
}
static void
-monitor(struct rt_ctx *c, int argc, char *argv[])
+monitor(int argc, char *argv[])
{
int n, fib, error;
char msg[2048], *endptr;
- fib = c->defaultfib;
+ fib = defaultfib;
while (argc > 1) {
argc--;
argv++;
@@ -1562,7 +1511,7 @@ monitor(struct rt_ctx *c, int argc, char *argv[])
if (errno == 0) {
if (*endptr != '\0' ||
fib < 0 ||
- (c->numfibs != -1 && fib > c->numfibs - 1))
+ (numfibs != -1 && fib > numfibs - 1))
errno = EINVAL;
}
if (errno)
@@ -1572,124 +1521,115 @@ monitor(struct rt_ctx *c, int argc, char *argv[])
usage(*argv);
}
}
- error = set_sofib(c, fib);
+ error = set_sofib(fib);
if (error)
errx(EX_USAGE, "invalid fib number: %d", fib);
- c->verbose = 1;
- if (c->debugonly) {
- interfaces(c);
+ verbose = 1;
+ if (debugonly) {
+ interfaces();
exit(0);
}
for (;;) {
time_t now;
- n = read(c->s, msg, 2048);
+ n = read(s, msg, 2048);
now = time(NULL);
- (void) printf("\ngot message of size %d on %s", n, ctime(&now));
- print_rtmsg(c, (struct rt_msghdr *)msg, n);
+ (void)printf("\ngot message of size %d on %s", n, ctime(&now));
+ print_rtmsg((struct rt_msghdr *)(void *)msg, n);
}
}
static int
-rtmsg(struct rt_ctx *c, int cmd, int flags, int fib)
+rtmsg(int cmd, int flags, int fib)
{
int rlen;
- char *cp = c->m_rtmsg.m_space;
+ char *cp = m_rtmsg.m_space;
int l;
-#define NEXTADDR(w, u) \
- if (c->rtm_addrs & (w)) {\
- l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\
- if (c->verbose) sodump(&(u),#u);\
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) { \
+ l = (((struct sockaddr *)&(u))->sa_len == 0) ? \
+ sizeof(long) : \
+ 1 + ((((struct sockaddr *)&(u))->sa_len - 1) \
+ | (sizeof(long) - 1)); \
+ memmove(cp, (char *)&(u), l); \
+ cp += l; \
+ if (verbose) \
+ sodump((struct sockaddr *)&(u), #w); \
}
errno = 0;
- memset(&c->m_rtmsg, 0, sizeof(c->m_rtmsg));
+ memset(&m_rtmsg, 0, sizeof(m_rtmsg));
if (cmd == 'a')
cmd = RTM_ADD;
else if (cmd == 'c')
cmd = RTM_CHANGE;
else if (cmd == 'g' || cmd == 's') {
cmd = RTM_GET;
- if (c->so_ifp.sa.sa_family == 0) {
- c->so_ifp.sa.sa_family = AF_LINK;
- c->so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
- c->rtm_addrs |= RTA_IFP;
+ if (so[RTAX_IFP].ss_family == 0) {
+ so[RTAX_IFP].ss_family = AF_LINK;
+ so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl);
+ rtm_addrs |= RTA_IFP;
}
} else
cmd = RTM_DELETE;
-#define rtm c->m_rtmsg.m_rtm
+#define rtm m_rtmsg.m_rtm
rtm.rtm_type = cmd;
rtm.rtm_flags = flags;
rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++c->rtm_seq;
- rtm.rtm_addrs = c->rtm_addrs;
- rtm.rtm_rmx = c->rt_metrics;
- rtm.rtm_inits = c->rtm_inits;
-
- if (c->rtm_addrs & RTA_NETMASK)
- mask_addr(c);
- NEXTADDR(RTA_DST, c->so_dst);
- NEXTADDR(RTA_GATEWAY, c->so_gate);
- NEXTADDR(RTA_NETMASK, c->so_mask);
- NEXTADDR(RTA_GENMASK, c->so_genmask);
- NEXTADDR(RTA_IFP, c->so_ifp);
- NEXTADDR(RTA_IFA, c->so_ifa);
- rtm.rtm_msglen = l = cp - (char *)&c->m_rtmsg;
- if (c->verbose)
- print_rtmsg(c, &rtm, l);
- if (c->debugonly)
+ rtm.rtm_seq = ++rtm_seq;
+ rtm.rtm_addrs = rtm_addrs;
+ rtm.rtm_rmx = rt_metrics;
+ rtm.rtm_inits = rtm_inits;
+
+ NEXTADDR(RTA_DST, so[RTAX_DST]);
+ NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]);
+ NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]);
+ NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]);
+ NEXTADDR(RTA_IFP, so[RTAX_IFP]);
+ NEXTADDR(RTA_IFA, so[RTAX_IFA]);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ if (verbose)
+ print_rtmsg(&rtm, l);
+ if (debugonly)
return (0);
- if ((rlen = write(c->s, (char *)&c->m_rtmsg, l)) < 0) {
- if (errno == EPERM)
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ switch (errno) {
+ case EPERM:
err(1, "writing to routing socket");
- warn("writing to routing socket");
+ break;
+ case ESRCH:
+ warnx("route has not been found");
+ break;
+ case EEXIST:
+ /* Handled by newroute() */
+ break;
+ default:
+ warn("writing to routing socket");
+ }
return (-1);
}
if (cmd == RTM_GET) {
+ stop_read = 0;
+ alarm(READ_TIMEOUT);
do {
- l = read(c->s, (char *)&c->m_rtmsg, sizeof(c->m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != c->rtm_seq || rtm.rtm_pid != c->pid));
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && stop_read == 0 &&
+ (rtm.rtm_seq != rtm_seq || rtm.rtm_pid != pid));
+ if (stop_read != 0) {
+ warnx("read from routing socket timed out");
+ return (-1);
+ } else
+ alarm(0);
if (l < 0)
warn("read from routing socket");
else
- print_getmsg(c, &rtm, l, fib);
+ print_getmsg(&rtm, l, fib);
}
#undef rtm
return (0);
}
-static void
-mask_addr(struct rt_ctx *c)
-{
- int olen = c->so_mask.sa.sa_len;
- char *cp1 = olen + (char *)&c->so_mask, *cp2;
-
- for (c->so_mask.sa.sa_len = 0; cp1 > (char *)&c->so_mask; )
- if (*--cp1 != 0) {
- c->so_mask.sa.sa_len = 1 + cp1 - (char *)&c->so_mask;
- break;
- }
- if ((c->rtm_addrs & RTA_DST) == 0)
- return;
- switch (c->so_dst.sa.sa_family) {
- case AF_INET:
-#ifdef INET6
- case AF_INET6:
-#endif
- case AF_APPLETALK:
- case 0:
- return;
- }
- cp1 = c->so_mask.sa.sa_len + 1 + (char *)&c->so_dst;
- cp2 = c->so_dst.sa.sa_len + 1 + (char *)&c->so_dst;
- while (cp2 > cp1)
- *--cp2 = 0;
- cp2 = c->so_mask.sa.sa_len + 1 + (char *)&c->so_mask;
- while (cp1 > c->so_dst.sa.sa_data)
- *--cp1 &= *--cp2;
-}
-
static const char *const msgtypes[] = {
"",
"RTM_ADD: Add Route",
@@ -1713,25 +1653,25 @@ static const char *const msgtypes[] = {
};
static const char metricnames[] =
-"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
-"\1mtu";
+ "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
+ "\1mtu";
static const char routeflags[] =
-"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
-"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
-"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
-"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
+ "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
+ "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
+ "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
+ "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
static const char ifnetflags[] =
-"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
-"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
-"\017LINK2\020MULTICAST";
+ "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
+ "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
+ "\017LINK2\020MULTICAST";
static const char addrnames[] =
-"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+ "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
static const char errfmt[] =
-"\n%s: truncated route message, only %zu bytes left\n";
+ "\n%s: truncated route message, only %zu bytes left\n";
static void
-print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
+print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
{
struct if_msghdr *ifm;
struct ifa_msghdr *ifam;
@@ -1741,14 +1681,14 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
struct if_announcemsghdr *ifan;
const char *state;
- if (c->verbose == 0)
+ if (verbose == 0)
return;
if (rtm->rtm_version != RTM_VERSION) {
- (void) printf("routing message version %d not understood\n",
+ (void)printf("routing message version %d not understood\n",
rtm->rtm_version);
return;
}
- if (rtm->rtm_type < sizeof(msgtypes) / sizeof(msgtypes[0]))
+ if (rtm->rtm_type < nitems(msgtypes))
(void)printf("%s: ", msgtypes[rtm->rtm_type]);
else
(void)printf("unknown type %d: ", rtm->rtm_type);
@@ -1765,7 +1705,7 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
case RTM_IFINFO:
REQUIRE(struct if_msghdr);
ifm = (struct if_msghdr *)rtm;
- (void) printf("if# %d, ", ifm->ifm_index);
+ (void)printf("if# %d, ", ifm->ifm_index);
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
state = "down";
@@ -1777,33 +1717,33 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
state = "unknown";
break;
}
- (void) printf("link: %s, flags:", state);
- bprintf(stdout, ifm->ifm_flags, ifnetflags);
- pmsg_addrs(c, (char *)(ifm + 1), ifm->ifm_addrs, msglen);
+ (void)printf("link: %s, flags:", state);
+ printb(ifm->ifm_flags, ifnetflags);
+ pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen);
break;
case RTM_NEWADDR:
case RTM_DELADDR:
REQUIRE(struct ifa_msghdr);
ifam = (struct ifa_msghdr *)rtm;
- (void) printf("metric %d, flags:", ifam->ifam_metric);
- bprintf(stdout, ifam->ifam_flags, routeflags);
- pmsg_addrs(c, (char *)(ifam + 1), ifam->ifam_addrs, msglen);
+ (void)printf("metric %d, flags:", ifam->ifam_metric);
+ printb(ifam->ifam_flags, routeflags);
+ pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen);
break;
#ifdef RTM_NEWMADDR
case RTM_NEWMADDR:
case RTM_DELMADDR:
REQUIRE(struct ifma_msghdr);
ifmam = (struct ifma_msghdr *)rtm;
- pmsg_addrs(c, (char *)(ifmam + 1), ifmam->ifmam_addrs, msglen);
+ pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen);
break;
#endif
case RTM_IFANNOUNCE:
REQUIRE(struct if_announcemsghdr);
ifan = (struct if_announcemsghdr *)rtm;
- (void) printf("if# %d, what: ", ifan->ifan_index);
+ (void)printf("if# %d, what: ", ifan->ifan_index);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
- printf("arrival");
+ (void)printf("arrival");
break;
case IFAN_DEPARTURE:
printf("departure");
@@ -1817,10 +1757,10 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
break;
default:
- (void) printf("pid: %ld, seq %d, errno %d, flags:",
+ printf("pid: %ld, seq %d, errno %d, flags:",
(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
- bprintf(stdout, rtm->rtm_flags, routeflags);
- pmsg_common(c, rtm, msglen);
+ printb(rtm->rtm_flags, routeflags);
+ pmsg_common(rtm, msglen);
}
return;
@@ -1831,16 +1771,16 @@ badlen:
}
static void
-print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib)
+print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
{
- struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
- struct sockaddr_dl *ifp = NULL;
- struct sockaddr *sa;
+ struct sockaddr *sp[RTAX_MAX];
+ struct timespec ts;
char *cp;
int i;
- (void) printf(" route to: %s\n",
- routename(c, (struct sockaddr *)&c->so_dst));
+ memset(sp, 0, sizeof(sp));
+ (void)printf(" route to: %s\n",
+ routename((struct sockaddr *)&so[RTAX_DST]));
if (rtm->rtm_version != RTM_VERSION) {
warnx("routing message version %d not understood",
rtm->rtm_version);
@@ -1849,6 +1789,7 @@ print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib)
if (rtm->rtm_msglen > msglen) {
warnx("message length mismatch, in packet %d, returned %d",
rtm->rtm_msglen, msglen);
+ return;
}
if (rtm->rtm_errno) {
errno = rtm->rtm_errno;
@@ -1856,122 +1797,105 @@ print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib)
return;
}
cp = ((char *)(rtm + 1));
- if (rtm->rtm_addrs)
- for (i = 1; i; i <<= 1)
- if (i & rtm->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- switch (i) {
- case RTA_DST:
- dst = sa;
- break;
- case RTA_GATEWAY:
- gate = sa;
- break;
- case RTA_NETMASK:
- mask = sa;
- break;
- case RTA_IFP:
- if (sa->sa_family == AF_LINK &&
- ((struct sockaddr_dl *)sa)->sdl_nlen)
- ifp = (struct sockaddr_dl *)sa;
- break;
- }
- cp += SA_SIZE(sa);
- }
- if (dst && mask)
- mask->sa_family = dst->sa_family; /* XXX */
- if (dst)
- (void)printf("destination: %s\n", routename(c, dst));
- if (mask) {
- int savenflag = c->nflag;
-
- c->nflag = 1;
- (void)printf(" mask: %s\n", routename(c, mask));
- c->nflag = savenflag;
- }
- if (gate && rtm->rtm_flags & RTF_GATEWAY)
- (void)printf(" gateway: %s\n", routename(c, gate));
+ for (i = 0; i < RTAX_MAX; i++)
+ if (rtm->rtm_addrs & (1 << i)) {
+ sp[i] = (struct sockaddr *)cp;
+ cp += SA_SIZE((struct sockaddr *)cp);
+ }
+ if ((rtm->rtm_addrs & RTA_IFP) &&
+ (sp[RTAX_IFP]->sa_family != AF_LINK ||
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0))
+ sp[RTAX_IFP] = NULL;
+ if (sp[RTAX_DST])
+ (void)printf("destination: %s\n", routename(sp[RTAX_DST]));
+ if (sp[RTAX_NETMASK])
+ (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK]));
+ if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY))
+ (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY]));
if (fib >= 0)
(void)printf(" fib: %u\n", (unsigned int)fib);
- if (ifp)
+ if (sp[RTAX_IFP])
(void)printf(" interface: %.*s\n",
- ifp->sdl_nlen, ifp->sdl_data);
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen,
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data);
(void)printf(" flags: ");
- bprintf(stdout, rtm->rtm_flags, routeflags);
+ printb(rtm->rtm_flags, routeflags);
#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
#define msec(u) (((u) + 500) / 1000) /* usec to msec */
-
- (void) printf("\n%s\n", "\
- recvpipe sendpipe ssthresh rtt,msec mtu weight expire");
- printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
- printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
- if (rtm->rtm_rmx.rmx_expire)
- rtm->rtm_rmx.rmx_expire -= time(0);
- printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+ printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe",
+ "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire");
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
+ printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
+ if (rtm->rtm_rmx.rmx_expire > 0)
+ clock_gettime(CLOCK_REALTIME_FAST, &ts);
+ else
+ ts.tv_sec = 0;
+ printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec),
+ lock(EXPIRE));
#undef lock
#undef msec
#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
- if (c->verbose)
- pmsg_common(c, rtm, msglen);
+ if (verbose)
+ pmsg_common(rtm, msglen);
else if (rtm->rtm_addrs &~ RTA_IGN) {
- (void) printf("sockaddrs: ");
- bprintf(stdout, rtm->rtm_addrs, addrnames);
+ (void)printf("sockaddrs: ");
+ printb(rtm->rtm_addrs, addrnames);
putchar('\n');
}
#undef RTA_IGN
}
static void
-pmsg_common(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen)
+pmsg_common(struct rt_msghdr *rtm, size_t msglen)
{
- (void) printf("\nlocks: ");
- bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
- (void) printf(" inits: ");
- bprintf(stdout, rtm->rtm_inits, metricnames);
+
+ (void)printf("\nlocks: ");
+ printb(rtm->rtm_rmx.rmx_locks, metricnames);
+ (void)printf(" inits: ");
+ printb(rtm->rtm_inits, metricnames);
if (msglen > sizeof(struct rt_msghdr))
- pmsg_addrs(c, ((char *)(rtm + 1)), rtm->rtm_addrs,
+ pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs,
msglen - sizeof(struct rt_msghdr));
else
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
static void
-pmsg_addrs(struct rt_ctx *c, char *cp, int addrs, size_t len)
+pmsg_addrs(char *cp, int addrs, size_t len)
{
struct sockaddr *sa;
int i;
if (addrs == 0) {
- (void) putchar('\n');
+ (void)putchar('\n');
return;
}
- (void) printf("\nsockaddrs: ");
- bprintf(stdout, addrs, addrnames);
- (void) putchar('\n');
- for (i = 1; i != 0; i <<= 1)
- if (i & addrs) {
+ (void)printf("\nsockaddrs: ");
+ printb(addrs, addrnames);
+ putchar('\n');
+ for (i = 0; i < RTAX_MAX; i++)
+ if (addrs & (1 << i)) {
sa = (struct sockaddr *)cp;
if (len == 0 || len < SA_SIZE(sa)) {
- (void) printf(errfmt, __func__, len);
+ (void)printf(errfmt, __func__, len);
break;
}
- (void) printf(" %s", routename(c, sa));
+ (void)printf(" %s", routename(sa));
len -= SA_SIZE(sa);
cp += SA_SIZE(sa);
}
- (void) putchar('\n');
- (void) fflush(stdout);
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
static void
-bprintf(FILE *fp, int b, const char *sstr)
+printb(int b, const char *str)
{
- const u_char *str = (const u_char *) sstr;
int i;
int gotsome = 0;
@@ -1983,16 +1907,16 @@ bprintf(FILE *fp, int b, const char *sstr)
i = '<';
else
i = ',';
- (void) putc(i, fp);
+ putchar(i);
gotsome = 1;
for (; (i = *str) > 32; str++)
- (void) putc(i, fp);
+ putchar(i);
} else
while (*str > 32)
str++;
}
if (gotsome)
- (void) putc('>', fp);
+ putchar('>');
}
int
@@ -2006,19 +1930,32 @@ keyword(const char *cp)
}
static void
-sodump(sup su, const char *which)
+sodump(struct sockaddr *sa, const char *which)
{
- switch (su->sa.sa_family) {
+#ifdef INET6
+ char nbuf[INET6_ADDRSTRLEN];
+#endif
+
+ switch (sa->sa_family) {
case AF_LINK:
- (void) printf("%s: link %s; ",
- which, link_ntoa(&su->sdl));
+ (void)printf("%s: link %s; ", which,
+ link_ntoa((struct sockaddr_dl *)(void *)sa));
break;
+#ifdef INET
case AF_INET:
- (void) printf("%s: inet %s; ",
- which, inet_ntoa(su->sin.sin_addr));
+ (void)printf("%s: inet %s; ", which,
+ inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr));
break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family,
+ &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf,
+ sizeof(nbuf)));
+ break;
+#endif
}
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
/* States*/
@@ -2031,10 +1968,9 @@ sodump(sup su, const char *which)
#define DELIM (4*2)
static void
-sockaddr(char *addr, struct sockaddr *sa)
+sockaddr(char *addr, struct sockaddr *sa, size_t size)
{
char *cp = (char *)sa;
- int size = sa->sa_len;
char *cplim = cp + size;
int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
diff --git a/freebsd/sbin/route/rtems-bsd-route-data.h b/freebsd/sbin/route/rtems-bsd-route-data.h
new file mode 100644
index 00000000..b3854595
--- /dev/null
+++ b/freebsd/sbin/route/rtems-bsd-route-data.h
@@ -0,0 +1,3 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+/* route.c */
diff --git a/freebsd/sbin/route/rtems-bsd-route-namespace.h b/freebsd/sbin/route/rtems-bsd-route-namespace.h
new file mode 100644
index 00000000..4f49513e
--- /dev/null
+++ b/freebsd/sbin/route/rtems-bsd-route-namespace.h
@@ -0,0 +1,2 @@
+/* generated by userspace-header-gen.py */
+/* route.c */
diff --git a/freebsd/sbin/route/rtems-bsd-route-route-data.h b/freebsd/sbin/route/rtems-bsd-route-route-data.h
new file mode 100644
index 00000000..8b54078f
--- /dev/null
+++ b/freebsd/sbin/route/rtems-bsd-route-route-data.h
@@ -0,0 +1,30 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-route-data.h"
+/* route.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int pid);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int rtm_addrs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int s);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int nflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int af);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int qflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int tflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int verbose);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int aflen);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int locking);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int lockrest);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int debugonly);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct rt_metrics rt_metrics);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static u_long rtm_inits);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static uid_t uid);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int defaultfib);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int numfibs);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static _Bool domain_initialized);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int rtm_seq);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct m_rtmsg m_rtmsg);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct fibl_head_t fibl_head);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static sig_atomic_t volatile stop_read);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct sockaddr_storage so[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char domain[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char rt_line[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char net_line[]);
diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h
new file mode 100644
index 00000000..8746008a
--- /dev/null
+++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h
@@ -0,0 +1,3 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+/* sysctl.c */
diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h
new file mode 100644
index 00000000..858b515f
--- /dev/null
+++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h
@@ -0,0 +1,2 @@
+/* generated by userspace-header-gen.py */
+/* sysctl.c */
diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h
new file mode 100644
index 00000000..6c6b3453
--- /dev/null
+++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h
@@ -0,0 +1,23 @@
+/* generated by userspace-header-gen.py */
+#include <rtems/linkersets.h>
+#include "rtems-bsd-sysctl-data.h"
+/* sysctl.c */
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static char const *conffile);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int aflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int bflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Bflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int dflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int eflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int hflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int iflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Nflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int nflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int oflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int qflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int tflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Tflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Wflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int xflag);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int ctl_sign[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int ctl_size[]);
+RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static char const *ctl_typename[]);
diff --git a/freebsd/sbin/sysctl/sysctl.c b/freebsd/sbin/sysctl/sysctl.c
index 87d9da32..fdbecd5f 100644
--- a/freebsd/sbin/sysctl/sysctl.c
+++ b/freebsd/sbin/sysctl/sysctl.c
@@ -1,5 +1,9 @@
#include <machine/rtems-bsd-user-space.h>
+#ifdef __rtems__
+#include "rtems-bsd-sysctl-namespace.h"
+#endif /* __rtems__ */
+
/*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@@ -42,22 +46,13 @@ static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93";
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
+
#ifdef __rtems__
#define __need_getopt_newlib
#include <getopt.h>
-#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP
-#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP
-#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP
#include <machine/rtems-bsd-program.h>
#include <machine/rtems-bsd-commands.h>
#endif /* __rtems__ */
-
#include <rtems/bsd/sys/param.h>
#include <sys/time.h>
#include <rtems/bsd/sys/resource.h>
@@ -65,6 +60,16 @@ static const char rcsid[] =
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
+#ifdef __amd64__
+#include <sys/efi.h>
+#include <machine/metadata.h>
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+#include <machine/pc/bios.h>
+#endif
+
+#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
@@ -73,71 +78,112 @@ static const char rcsid[] =
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
+#ifdef __rtems__
+#include "rtems-bsd-sysctl-sysctl-data.h"
+#endif /* __rtems__ */
+
+static const char *conffile;
-static int aflag, bflag, dflag, eflag, hflag, iflag;
-static int Nflag, nflag, oflag, qflag, xflag, warncount;
+static int aflag, bflag, Bflag, dflag, eflag, hflag, iflag;
+static int Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag;
static int oidfmt(int *, int, char *, u_int *);
-static void parse(const char *);
+static int parsefile(const char *);
+static int parse(const char *, int);
static int show_var(int *, int);
static int sysctl_all(int *oid, int len);
-static int name2oid(char *, int *);
+static int name2oid(const char *, int *);
-static int set_IK(const char *, int *);
+static int strIKtoi(const char *, char **, const char *);
+
+static int ctl_sign[CTLTYPE+1] = {
+ [CTLTYPE_INT] = 1,
+ [CTLTYPE_LONG] = 1,
+ [CTLTYPE_S8] = 1,
+ [CTLTYPE_S16] = 1,
+ [CTLTYPE_S32] = 1,
+ [CTLTYPE_S64] = 1,
+};
+
+static int ctl_size[CTLTYPE+1] = {
+ [CTLTYPE_INT] = sizeof(int),
+ [CTLTYPE_UINT] = sizeof(u_int),
+ [CTLTYPE_LONG] = sizeof(long),
+ [CTLTYPE_ULONG] = sizeof(u_long),
+ [CTLTYPE_S8] = sizeof(int8_t),
+ [CTLTYPE_S16] = sizeof(int16_t),
+ [CTLTYPE_S32] = sizeof(int32_t),
+ [CTLTYPE_S64] = sizeof(int64_t),
+ [CTLTYPE_U8] = sizeof(uint8_t),
+ [CTLTYPE_U16] = sizeof(uint16_t),
+ [CTLTYPE_U32] = sizeof(uint32_t),
+ [CTLTYPE_U64] = sizeof(uint64_t),
+};
+
+static const char *ctl_typename[CTLTYPE+1] = {
+ [CTLTYPE_INT] = "integer",
+ [CTLTYPE_UINT] = "unsigned integer",
+ [CTLTYPE_LONG] = "long integer",
+ [CTLTYPE_ULONG] = "unsigned long",
+ [CTLTYPE_U8] = "uint8_t",
+ [CTLTYPE_U16] = "uint16_t",
+ [CTLTYPE_U32] = "uint16_t",
+ [CTLTYPE_U64] = "uint64_t",
+ [CTLTYPE_S8] = "int8_t",
+ [CTLTYPE_S16] = "int16_t",
+ [CTLTYPE_S32] = "int32_t",
+ [CTLTYPE_S64] = "int64_t",
+ [CTLTYPE_NODE] = "node",
+ [CTLTYPE_STRING] = "string",
+ [CTLTYPE_OPAQUE] = "opaque",
+};
static void
usage(void)
{
(void)fprintf(stderr, "%s\n%s\n",
- "usage: sysctl [-bdehiNnoqx] name[=value] ...",
- " sysctl [-bdehNnoqx] -a");
+ "usage: sysctl [-bdehiNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...",
+ " sysctl [-bdehNnoqTtWx] [ -B <bufsize> ] -a");
exit(1);
}
#ifdef __rtems__
-static int main(int argc, char **argv);
+static int main(int argc, char *argv[]);
+
+RTEMS_LINKER_RWSET(bsd_prog_sysctl, char);
-int rtems_bsd_command_sysctl(int argc, char *argv[])
+int
+rtems_bsd_command_sysctl(int argc, char *argv[])
{
int exit_code;
+ void *data_begin;
+ size_t data_size;
- rtems_bsd_program_lock();
-
- aflag = bflag = dflag = eflag = hflag = iflag = 0;
- Nflag = nflag = oflag = qflag = xflag = warncount = 0;
-
- exit_code = rtems_bsd_program_call_main("sysctl", main, argc, argv);
+ data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_sysctl);
+ data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_sysctl);
+ rtems_bsd_program_lock();
+ exit_code = rtems_bsd_program_call_main_with_data_restore("sysctl",
+ main, argc, argv, data_begin, data_size);
rtems_bsd_program_unlock();
return exit_code;
}
#endif /* __rtems__ */
-
int
main(int argc, char **argv)
{
int ch;
+ int warncount = 0;
-#ifdef __rtems__
- struct getopt_data getopt_data;
- memset(&getopt_data, 0, sizeof(getopt_data));
-#define optind getopt_data.optind
-#define optarg getopt_data.optarg
-#define opterr getopt_data.opterr
-#define optopt getopt_data.optopt
-#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data)
-#endif /* __rtems__ */
-
-#ifndef __rtems__
setlocale(LC_NUMERIC, "");
setbuf(stdout,0);
setbuf(stderr,0);
-#endif /* __rtems__ */
- while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) {
+ while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) {
switch (ch) {
case 'A':
/* compatibility */
@@ -149,12 +195,18 @@ main(int argc, char **argv)
case 'b':
bflag = 1;
break;
+ case 'B':
+ Bflag = strtol(optarg, NULL, 0);
+ break;
case 'd':
dflag = 1;
break;
case 'e':
eflag = 1;
break;
+ case 'f':
+ conffile = optarg;
+ break;
case 'h':
hflag = 1;
break;
@@ -173,10 +225,19 @@ main(int argc, char **argv)
case 'q':
qflag = 1;
break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'T':
+ Tflag = 1;
+ break;
case 'w':
/* compatibility */
/* ignored */
break;
+ case 'W':
+ Wflag = 1;
+ break;
case 'X':
/* compatibility */
aflag = xflag = 1;
@@ -195,13 +256,17 @@ main(int argc, char **argv)
usage();
if (aflag && argc == 0)
exit(sysctl_all(0, 0));
- if (argc == 0)
+ if (argc == 0 && conffile == NULL)
usage();
warncount = 0;
+ if (conffile != NULL)
+ warncount += parsefile(conffile);
+
while (argc-- > 0)
- parse(*argv++);
- exit(warncount);
+ warncount += parse(*argv++, 0);
+
+ return (warncount);
}
/*
@@ -209,47 +274,91 @@ main(int argc, char **argv)
* Lookup and print out the MIB entry if it exists.
* Set a new value if requested.
*/
-static void
-parse(const char *string)
+static int
+parse(const char *string, int lineno)
{
int len, i, j;
- void *newval = 0;
+ const void *newval;
+ const char *newvalstr = NULL;
+ int8_t i8val;
+ uint8_t u8val;
+ int16_t i16val;
+ uint16_t u16val;
+ int32_t i32val;
+ uint32_t u32val;
int intval;
unsigned int uintval;
long longval;
unsigned long ulongval;
- size_t newsize = 0;
+ size_t newsize = Bflag;
int64_t i64val;
uint64_t u64val;
int mib[CTL_MAXNAME];
- char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ];
+ char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ];
u_int kind;
+ if (lineno)
+ snprintf(line, sizeof(line), " at line %d", lineno);
+ else
+ line[0] = '\0';
+
cp = buf;
- if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
- errx(1, "oid too long: '%s'", string);
- bufp = strsep(&cp, "=");
+ if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
+ warnx("oid too long: '%s'%s", string, line);
+ return (1);
+ }
+ bufp = strsep(&cp, "=:");
if (cp != NULL) {
+ /* Tflag just lists tunables, do not allow assignment */
+ if (Tflag || Wflag) {
+ warnx("Can't set variables when using -T or -W");
+ usage();
+ }
while (isspace(*cp))
cp++;
- newval = cp;
+ /* Strip a pair of " or ' if any. */
+ switch (*cp) {
+ case '\"':
+ case '\'':
+ if (cp[strlen(cp) - 1] == *cp)
+ cp[strlen(cp) - 1] = '\0';
+ cp++;
+ }
+ newvalstr = cp;
newsize = strlen(cp);
}
+ /* Trim spaces */
+ cp = bufp + strlen(bufp) - 1;
+ while (cp >= bufp && isspace((int)*cp)) {
+ *cp = '\0';
+ cp--;
+ }
len = name2oid(bufp, mib);
if (len < 0) {
if (iflag)
- return;
+ return (0);
if (qflag)
- exit(1);
- else
- errx(1, "unknown oid '%s'", bufp);
+ return (1);
+ else {
+ if (errno == ENOENT) {
+ warnx("unknown oid '%s'%s", bufp, line);
+ } else {
+ warn("unknown oid '%s'%s", bufp, line);
+ }
+ return (1);
+ }
}
- if (oidfmt(mib, len, fmt, &kind))
- err(1, "couldn't find format of oid '%s'", bufp);
+ if (oidfmt(mib, len, fmt, &kind)) {
+ warn("couldn't find format of oid '%s'%s", bufp, line);
+ if (iflag)
+ return (1);
+ else
+ exit(1);
+ }
- if (newval == NULL || dflag) {
+ if (newvalstr == NULL || dflag) {
if ((kind & CTLTYPE) == CTLTYPE_NODE) {
if (dflag) {
i = show_var(mib, len);
@@ -263,92 +372,131 @@ parse(const char *string)
putchar('\n');
}
} else {
- if ((kind & CTLTYPE) == CTLTYPE_NODE)
- errx(1, "oid '%s' isn't a leaf node", bufp);
+ if ((kind & CTLTYPE) == CTLTYPE_NODE) {
+ warnx("oid '%s' isn't a leaf node%s", bufp, line);
+ return (1);
+ }
if (!(kind & CTLFLAG_WR)) {
if (kind & CTLFLAG_TUN) {
- warnx("oid '%s' is a read only tunable", bufp);
- errx(1, "Tunable values are set in /boot/loader.conf");
- } else {
- errx(1, "oid '%s' is read only", bufp);
- }
+ warnx("oid '%s' is a read only tunable%s", bufp, line);
+ warnx("Tunable values are set in /boot/loader.conf");
+ } else
+ warnx("oid '%s' is read only%s", bufp, line);
+ return (1);
}
- if ((kind & CTLTYPE) == CTLTYPE_INT ||
- (kind & CTLTYPE) == CTLTYPE_UINT ||
- (kind & CTLTYPE) == CTLTYPE_LONG ||
- (kind & CTLTYPE) == CTLTYPE_ULONG ||
- (kind & CTLTYPE) == CTLTYPE_S64 ||
- (kind & CTLTYPE) == CTLTYPE_U64) {
- if (strlen(newval) == 0)
- errx(1, "empty numeric value");
+ switch (kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ case CTLTYPE_UINT:
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ case CTLTYPE_S8:
+ case CTLTYPE_S16:
+ case CTLTYPE_S32:
+ case CTLTYPE_S64:
+ case CTLTYPE_U8:
+ case CTLTYPE_U16:
+ case CTLTYPE_U32:
+ case CTLTYPE_U64:
+ if (strlen(newvalstr) == 0) {
+ warnx("empty numeric value");
+ return (1);
+ }
+ /* FALLTHROUGH */
+ case CTLTYPE_STRING:
+ break;
+ default:
+ warnx("oid '%s' is type %d,"
+ " cannot set that%s", bufp,
+ kind & CTLTYPE, line);
+ return (1);
}
+ errno = 0;
+
switch (kind & CTLTYPE) {
case CTLTYPE_INT:
- if (strcmp(fmt, "IK") == 0) {
- if (!set_IK(newval, &intval))
- errx(1, "invalid value '%s'",
- (char *)newval);
- } else {
- intval = (int)strtol(newval, &endptr,
+ if (strncmp(fmt, "IK", 2) == 0)
+ intval = strIKtoi(newvalstr, &endptr, fmt);
+ else
+ intval = (int)strtol(newvalstr, &endptr,
0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid integer '%s'",
- (char *)newval);
- }
newval = &intval;
newsize = sizeof(intval);
break;
case CTLTYPE_UINT:
- uintval = (int) strtoul(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid unsigned integer '%s'",
- (char *)newval);
+ uintval = (int) strtoul(newvalstr, &endptr, 0);
newval = &uintval;
newsize = sizeof(uintval);
break;
case CTLTYPE_LONG:
- longval = strtol(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid long integer '%s'",
- (char *)newval);
+ longval = strtol(newvalstr, &endptr, 0);
newval = &longval;
newsize = sizeof(longval);
break;
case CTLTYPE_ULONG:
- ulongval = strtoul(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid unsigned long integer"
- " '%s'", (char *)newval);
+ ulongval = strtoul(newvalstr, &endptr, 0);
newval = &ulongval;
newsize = sizeof(ulongval);
break;
case CTLTYPE_STRING:
+ newval = newvalstr;
+ break;
+ case CTLTYPE_S8:
+ i8val = (int8_t)strtol(newvalstr, &endptr, 0);
+ newval = &i8val;
+ newsize = sizeof(i8val);
+ break;
+ case CTLTYPE_S16:
+ i16val = (int16_t)strtol(newvalstr, &endptr,
+ 0);
+ newval = &i16val;
+ newsize = sizeof(i16val);
+ break;
+ case CTLTYPE_S32:
+ i32val = (int32_t)strtol(newvalstr, &endptr,
+ 0);
+ newval = &i32val;
+ newsize = sizeof(i32val);
break;
case CTLTYPE_S64:
- i64val = strtoimax(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid int64_t '%s'",
- (char *)newval);
+ i64val = strtoimax(newvalstr, &endptr, 0);
newval = &i64val;
newsize = sizeof(i64val);
break;
+ case CTLTYPE_U8:
+ u8val = (uint8_t)strtoul(newvalstr, &endptr, 0);
+ newval = &u8val;
+ newsize = sizeof(u8val);
+ break;
+ case CTLTYPE_U16:
+ u16val = (uint16_t)strtoul(newvalstr, &endptr,
+ 0);
+ newval = &u16val;
+ newsize = sizeof(u16val);
+ break;
+ case CTLTYPE_U32:
+ u32val = (uint32_t)strtoul(newvalstr, &endptr,
+ 0);
+ newval = &u32val;
+ newsize = sizeof(u32val);
+ break;
case CTLTYPE_U64:
- u64val = strtoumax(newval, &endptr, 0);
- if (endptr == newval || *endptr != '\0')
- errx(1, "invalid uint64_t '%s'",
- (char *)newval);
+ u64val = strtoumax(newvalstr, &endptr, 0);
newval = &u64val;
newsize = sizeof(u64val);
break;
- case CTLTYPE_OPAQUE:
- /* FALLTHROUGH */
default:
- errx(1, "oid '%s' is type %d,"
- " cannot set that", bufp,
- kind & CTLTYPE);
+ /* NOTREACHED */
+ abort();
+ }
+
+ if (errno != 0 || endptr == newvalstr ||
+ (endptr != NULL && *endptr != '\0')) {
+ warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE],
+ newvalstr, line);
+ return (1);
}
i = show_var(mib, len);
@@ -357,18 +505,20 @@ parse(const char *string)
putchar('\n');
switch (errno) {
case EOPNOTSUPP:
- errx(1, "%s: value is not available",
- string);
+ warnx("%s: value is not available%s",
+ string, line);
+ return (1);
case ENOTDIR:
- errx(1, "%s: specification is incomplete",
- string);
+ warnx("%s: specification is incomplete%s",
+ string, line);
+ return (1);
case ENOMEM:
- errx(1, "%s: type is unknown to this program",
- string);
+ warnx("%s: type is unknown to this program%s",
+ string, line);
+ return (1);
default:
- warn("%s", string);
- warncount++;
- return;
+ warn("%s%s", string, line);
+ return (1);
}
}
if (!bflag)
@@ -380,34 +530,86 @@ parse(const char *string)
putchar('\n');
nflag = i;
}
+
+ return (0);
+}
+
+static int
+parsefile(const char *filename)
+{
+ FILE *file;
+ char line[BUFSIZ], *p, *pq, *pdq;
+ int warncount = 0, lineno = 0;
+
+ file = fopen(filename, "r");
+ if (file == NULL)
+ err(EX_NOINPUT, "%s", filename);
+ while (fgets(line, sizeof(line), file) != NULL) {
+ lineno++;
+ p = line;
+ pq = strchr(line, '\'');
+ pdq = strchr(line, '\"');
+ /* Replace the first # with \0. */
+ while((p = strchr(p, '#')) != NULL) {
+ if (pq != NULL && p > pq) {
+ if ((p = strchr(pq+1, '\'')) != NULL)
+ *(++p) = '\0';
+ break;
+ } else if (pdq != NULL && p > pdq) {
+ if ((p = strchr(pdq+1, '\"')) != NULL)
+ *(++p) = '\0';
+ break;
+ } else if (p == line || *(p-1) != '\\') {
+ *p = '\0';
+ break;
+ }
+ p++;
+ }
+ /* Trim spaces */
+ p = line + strlen(line) - 1;
+ while (p >= line && isspace((int)*p)) {
+ *p = '\0';
+ p--;
+ }
+ p = line;
+ while (isspace((int)*p))
+ p++;
+ if (*p == '\0')
+ continue;
+ else
+ warncount += parse(p, lineno);
+ }
+ fclose(file);
+
+ return (warncount);
}
/* These functions will dump out various interesting structures. */
+#ifndef __rtems__
static int
-S_clockinfo(int l2, void *p)
+S_clockinfo(size_t l2, void *p)
{
-#ifndef __rtems__
struct clockinfo *ci = (struct clockinfo*)p;
if (l2 != sizeof(*ci)) {
- warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
+ warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci));
return (1);
}
printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
"{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
ci->hz, ci->tick, ci->profhz, ci->stathz);
-#endif /* __rtems__ */
return (0);
}
+#endif /* __rtems__ */
static int
-S_loadavg(int l2, void *p)
+S_loadavg(size_t l2, void *p)
{
struct loadavg *tv = (struct loadavg*)p;
if (l2 != sizeof(*tv)) {
- warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
+ warnx("S_loadavg %zu != %zu", l2, sizeof(*tv));
return (1);
}
printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
@@ -418,14 +620,14 @@ S_loadavg(int l2, void *p)
}
static int
-S_timeval(int l2, void *p)
+S_timeval(size_t l2, void *p)
{
struct timeval *tv = (struct timeval*)p;
time_t tv_sec;
char *p1, *p2;
if (l2 != sizeof(*tv)) {
- warnx("S_timeval %d != %zu", l2, sizeof(*tv));
+ warnx("S_timeval %zu != %zu", l2, sizeof(*tv));
return (1);
}
printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
@@ -442,13 +644,13 @@ S_timeval(int l2, void *p)
}
static int
-S_vmtotal(int l2, void *p)
+S_vmtotal(size_t l2, void *p)
{
struct vmtotal *v = (struct vmtotal *)p;
int pageKilo = getpagesize() / 1024;
if (l2 != sizeof(*v)) {
- warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
+ warnx("S_vmtotal %zu != %zu", l2, sizeof(*v));
return (1);
}
@@ -461,44 +663,179 @@ S_vmtotal(int l2, void *p)
"%hd Sleep: %hd)\n",
v->t_rq, v->t_dw, v->t_pw, v->t_sl);
printf(
- "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
- v->t_vm * pageKilo, v->t_avm * pageKilo);
- printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
- v->t_rm * pageKilo, v->t_arm * pageKilo);
- printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
- v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
- printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
- v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
- printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
+ "Virtual Memory:\t\t(Total: %jdK Active: %jdK)\n",
+ (intmax_t)v->t_vm * pageKilo, (intmax_t)v->t_avm * pageKilo);
+ printf("Real Memory:\t\t(Total: %jdK Active: %jdK)\n",
+ (intmax_t)v->t_rm * pageKilo, (intmax_t)v->t_arm * pageKilo);
+ printf("Shared Virtual Memory:\t(Total: %jdK Active: %jdK)\n",
+ (intmax_t)v->t_vmshr * pageKilo, (intmax_t)v->t_avmshr * pageKilo);
+ printf("Shared Real Memory:\t(Total: %jdK Active: %jdK)\n",
+ (intmax_t)v->t_rmshr * pageKilo, (intmax_t)v->t_armshr * pageKilo);
+ printf("Free Memory:\t%jdK", (intmax_t)v->t_free * pageKilo);
return (0);
}
+#ifdef __amd64__
+#define efi_next_descriptor(ptr, size) \
+ ((struct efi_md *)(((uint8_t *) ptr) + size))
+
static int
-set_IK(const char *str, int *val)
+S_efi_map(size_t l2, void *p)
{
- float temp;
- int len, kelv;
- const char *p;
- char *endptr;
+ struct efi_map_header *efihdr;
+ struct efi_md *map;
+ const char *type;
+ size_t efisz;
+ int ndesc, i;
+
+ static const char *types[] = {
+ "Reserved",
+ "LoaderCode",
+ "LoaderData",
+ "BootServicesCode",
+ "BootServicesData",
+ "RuntimeServicesCode",
+ "RuntimeServicesData",
+ "ConventionalMemory",
+ "UnusableMemory",
+ "ACPIReclaimMemory",
+ "ACPIMemoryNVS",
+ "MemoryMappedIO",
+ "MemoryMappedIOPortSpace",
+ "PalCode"
+ };
+
+ /*
+ * Memory map data provided by UEFI via the GetMemoryMap
+ * Boot Services API.
+ */
+ if (l2 < sizeof(*efihdr)) {
+ warnx("S_efi_map length less than header");
+ return (1);
+ }
+ efihdr = p;
+ efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
+ map = (struct efi_md *)((uint8_t *)efihdr + efisz);
- if ((len = strlen(str)) == 0)
+ if (efihdr->descriptor_size == 0)
return (0);
+ if (l2 != efisz + efihdr->memory_size) {
+ warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz +
+ efihdr->memory_size);
+ return (1);
+ }
+ ndesc = efihdr->memory_size / efihdr->descriptor_size;
+
+ printf("\n%23s %12s %12s %8s %4s",
+ "Type", "Physical", "Virtual", "#Pages", "Attr");
+
+ for (i = 0; i < ndesc; i++,
+ map = efi_next_descriptor(map, efihdr->descriptor_size)) {
+ if (map->md_type <= EFI_MD_TYPE_PALCODE)
+ type = types[map->md_type];
+ else
+ type = "<INVALID>";
+ printf("\n%23s %012lx %12p %08lx ", type, map->md_phys,
+ map->md_virt, map->md_pages);
+ if (map->md_attr & EFI_MD_ATTR_UC)
+ printf("UC ");
+ if (map->md_attr & EFI_MD_ATTR_WC)
+ printf("WC ");
+ if (map->md_attr & EFI_MD_ATTR_WT)
+ printf("WT ");
+ if (map->md_attr & EFI_MD_ATTR_WB)
+ printf("WB ");
+ if (map->md_attr & EFI_MD_ATTR_UCE)
+ printf("UCE ");
+ if (map->md_attr & EFI_MD_ATTR_WP)
+ printf("WP ");
+ if (map->md_attr & EFI_MD_ATTR_RP)
+ printf("RP ");
+ if (map->md_attr & EFI_MD_ATTR_XP)
+ printf("XP ");
+ if (map->md_attr & EFI_MD_ATTR_RT)
+ printf("RUNTIME");
+ }
+ return (0);
+}
+#endif
+
+#if defined(__amd64__) || defined(__i386__)
+static int
+S_bios_smap_xattr(size_t l2, void *p)
+{
+ struct bios_smap_xattr *smap, *end;
+
+ if (l2 % sizeof(*smap) != 0) {
+ warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2,
+ sizeof(*smap));
+ return (1);
+ }
+
+ end = (struct bios_smap_xattr *)((char *)p + l2);
+ for (smap = p; smap < end; smap++)
+ printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx",
+ smap->type, smap->xattr, (uintmax_t)smap->base,
+ (uintmax_t)smap->length);
+ return (0);
+}
+#endif
+
+static int
+strIKtoi(const char *str, char **endptrp, const char *fmt)
+{
+ int kelv;
+ float temp;
+ size_t len;
+ const char *p;
+ int prec, i;
+
+ assert(errno == 0);
+
+ len = strlen(str);
+ /* caller already checked this */
+ assert(len > 0);
+
+ /*
+ * A format of "IK" is in deciKelvin. A format of "IK3" is in
+ * milliKelvin. The single digit following IK is log10 of the
+ * multiplying factor to convert Kelvin into the untis of this sysctl,
+ * or the dividing factor to convert the sysctl value to Kelvin. Numbers
+ * larger than 6 will run into precision issues with 32-bit integers.
+ * Characters that aren't ASCII digits after the 'K' are ignored. No
+ * localization is present because this is an interface from the kernel
+ * to this program (eg not an end-user interface), so isdigit() isn't
+ * used here.
+ */
+ if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9')
+ prec = fmt[2] - '0';
+ else
+ prec = 1;
p = &str[len - 1];
- if (*p == 'C' || *p == 'F') {
- temp = strtof(str, &endptr);
- if (endptr == str || endptr != p)
- return (0);
- if (*p == 'F')
- temp = (temp - 32) * 5 / 9;
- kelv = temp * 10 + 2732;
+ if (*p == 'C' || *p == 'F' || *p == 'K') {
+ temp = strtof(str, endptrp);
+ if (*endptrp != str && *endptrp == p && errno == 0) {
+ if (*p == 'F')
+ temp = (temp - 32) * 5 / 9;
+ *endptrp = NULL;
+ if (*p != 'K')
+ temp += 273.15;
+ for (i = 0; i < prec; i++)
+ temp *= 10.0;
+ return ((int)(temp + 0.5));
+ }
} else {
- kelv = (int)strtol(str, &endptr, 10);
- if (endptr == str || *endptr != '\0')
- return (0);
+ /* No unit specified -> treat it as a raw number */
+ kelv = (int)strtol(str, endptrp, 10);
+ if (*endptrp != str && *endptrp == p && errno == 0) {
+ *endptrp = NULL;
+ return (kelv);
+ }
}
- *val = kelv;
- return (1);
+
+ errno = ERANGE;
+ return (0);
}
/*
@@ -511,7 +848,7 @@ set_IK(const char *str, int *val)
*/
static int
-name2oid(char *name, int *oidp)
+name2oid(const char *name, int *oidp)
{
int oid[2];
int i;
@@ -553,21 +890,6 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind)
return (0);
}
-static int ctl_sign[CTLTYPE+1] = {
- [CTLTYPE_INT] = 1,
- [CTLTYPE_LONG] = 1,
- [CTLTYPE_S64] = 1,
-};
-
-static int ctl_size[CTLTYPE+1] = {
- [CTLTYPE_INT] = sizeof(int),
- [CTLTYPE_UINT] = sizeof(u_int),
- [CTLTYPE_LONG] = sizeof(long),
- [CTLTYPE_ULONG] = sizeof(u_long),
- [CTLTYPE_S64] = sizeof(int64_t),
- [CTLTYPE_U64] = sizeof(int64_t),
-};
-
/*
* This formats and outputs the value of one variable
*
@@ -579,8 +901,8 @@ static int
show_var(int *oid, int nlen)
{
u_char buf[BUFSIZ], *val, *oval, *p;
- char name[BUFSIZ], *fmt;
- const char *sep, *sep1;
+ char name[BUFSIZ], fmt[BUFSIZ];
+ const char *sep, *sep1, *prntype;
int qoid[CTL_MAXNAME+2];
uintmax_t umv;
intmax_t mv;
@@ -588,12 +910,15 @@ show_var(int *oid, int nlen)
size_t intlen;
size_t j, len;
u_int kind;
- int (*func)(int, void *);
+ float base;
+ int (*func)(size_t, void *);
+ int prec;
/* Silence GCC. */
umv = mv = intlen = 0;
bzero(buf, BUFSIZ);
+ bzero(fmt, BUFSIZ);
bzero(name, BUFSIZ);
qoid[0] = 0;
memcpy(qoid + 2, oid, nlen * sizeof(int));
@@ -604,6 +929,15 @@ show_var(int *oid, int nlen)
if (i || !j)
err(1, "sysctl name %d %zu %d", i, j, errno);
+ oidfmt(oid, nlen, fmt, &kind);
+ /* if Wflag then only list sysctls that are writeable and not stats. */
+ if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0))
+ return 1;
+
+ /* if Tflag then only list sysctls that are tuneables. */
+ if (Tflag && (kind & CTLFLAG_TUN) == 0)
+ return 1;
+
if (Nflag) {
printf("%s", name);
return (0);
@@ -614,19 +948,34 @@ show_var(int *oid, int nlen)
else
sep = ": ";
- if (dflag) { /* just print description */
+ ctltype = (kind & CTLTYPE);
+ if (tflag || dflag) {
+ if (!nflag)
+ printf("%s%s", name, sep);
+ if (ctl_typename[ctltype] != NULL)
+ prntype = ctl_typename[ctltype];
+ else
+ prntype = "unknown";
+ if (tflag && dflag)
+ printf("%s%s", prntype, sep);
+ else if (tflag) {
+ printf("%s", prntype);
+ return (0);
+ }
qoid[1] = 5;
j = sizeof(buf);
i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
- if (!nflag)
- printf("%s%s", name, sep);
printf("%s", buf);
return (0);
}
/* find an estimate of how much we need for this var */
- j = 0;
- i = sysctl(oid, nlen, 0, &j, 0, 0);
- j += j; /* we want to be sure :-) */
+ if (Bflag)
+ j = Bflag;
+ else {
+ j = 0;
+ i = sysctl(oid, nlen, 0, &j, 0, 0);
+ j += j; /* we want to be sure :-) */
+ }
val = oval = malloc(j + 1);
if (val == NULL) {
@@ -635,7 +984,7 @@ show_var(int *oid, int nlen)
}
len = j;
i = sysctl(oid, nlen, val, &len, 0, 0);
- if (i || !len) {
+ if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) {
free(oval);
return (1);
}
@@ -646,10 +995,7 @@ show_var(int *oid, int nlen)
return (0);
}
val[len] = '\0';
- fmt = buf;
- oidfmt(oid, nlen, fmt, &kind);
p = val;
- ctltype = (kind & CTLTYPE);
sign = ctl_sign[ctltype];
intlen = ctl_size[ctltype];
@@ -665,7 +1011,13 @@ show_var(int *oid, int nlen)
case CTLTYPE_UINT:
case CTLTYPE_LONG:
case CTLTYPE_ULONG:
+ case CTLTYPE_S8:
+ case CTLTYPE_S16:
+ case CTLTYPE_S32:
case CTLTYPE_S64:
+ case CTLTYPE_U8:
+ case CTLTYPE_U16:
+ case CTLTYPE_U32:
case CTLTYPE_U64:
if (!nflag)
printf("%s%s", name, sep);
@@ -683,6 +1035,21 @@ show_var(int *oid, int nlen)
umv = *(u_long *)p;
mv = *(long *)p;
break;
+ case CTLTYPE_S8:
+ case CTLTYPE_U8:
+ umv = *(uint8_t *)p;
+ mv = *(int8_t *)p;
+ break;
+ case CTLTYPE_S16:
+ case CTLTYPE_U16:
+ umv = *(uint16_t *)p;
+ mv = *(int16_t *)p;
+ break;
+ case CTLTYPE_S32:
+ case CTLTYPE_U32:
+ umv = *(uint32_t *)p;
+ mv = *(int32_t *)p;
+ break;
case CTLTYPE_S64:
case CTLTYPE_U64:
umv = *(uint64_t *)p;
@@ -697,8 +1064,19 @@ show_var(int *oid, int nlen)
else if (fmt[1] == 'K') {
if (mv < 0)
printf("%jd", mv);
- else
- printf("%.1fC", (mv - 2732.0) / 10);
+ else {
+ /*
+ * See strIKtoi for details on fmt.
+ */
+ prec = 1;
+ if (fmt[2] != '\0')
+ prec = fmt[2] - '0';
+ base = 1.0;
+ for (int i = 0; i < prec; i++)
+ base *= 10.0;
+ printf("%.*fC", prec,
+ (float)mv / base - 273.15);
+ }
} else
printf(hflag ? "%'jd" : "%jd", mv);
sep1 = " ";
@@ -711,13 +1089,25 @@ show_var(int *oid, int nlen)
case CTLTYPE_OPAQUE:
i = 0;
if (strcmp(fmt, "S,clockinfo") == 0)
+#ifndef __rtems__
func = S_clockinfo;
+#else /* __rtems__ */
+ func = NULL;
+#endif /* __rtems__ */
else if (strcmp(fmt, "S,timeval") == 0)
func = S_timeval;
else if (strcmp(fmt, "S,loadavg") == 0)
func = S_loadavg;
else if (strcmp(fmt, "S,vmtotal") == 0)
func = S_vmtotal;
+#ifdef __amd64__
+ else if (strcmp(fmt, "S,efi_map_header") == 0)
+ func = S_efi_map;
+#endif
+#if defined(__amd64__) || defined(__i386__)
+ else if (strcmp(fmt, "S,bios_smap_xattr") == 0)
+ func = S_bios_smap_xattr;
+#endif
else
func = NULL;
if (func) {