aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2012-11-04 02:52:03 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2012-11-04 02:52:03 +0000
commit23090366f729c56cab62de74c7a51792357e98a9 (patch)
treec511c885796e28ec571b5267e8f11f3b103d35e9 /sbin
parent7750ad47a9a7dbc83f87158464170c8640723293 (diff)
parent22ff74b2f44234d31540b1f7fd6c91489c37cad3 (diff)
downloadsrc-23090366f729c56cab62de74c7a51792357e98a9.tar.gz
src-23090366f729c56cab62de74c7a51792357e98a9.zip
Sync from head
Notes
Notes: svn path=/projects/bmake/; revision=242545
Diffstat (limited to 'sbin')
-rw-r--r--sbin/Makefile2
-rw-r--r--sbin/Makefile.amd641
-rw-r--r--sbin/Makefile.i3861
-rw-r--r--sbin/adjkerntz/adjkerntz.c5
-rw-r--r--sbin/camcontrol/Makefile2
-rw-r--r--sbin/camcontrol/camcontrol.811
-rw-r--r--sbin/camcontrol/camcontrol.c262
-rw-r--r--sbin/camcontrol/camcontrol.h7
-rw-r--r--sbin/camcontrol/fwdownload.c215
-rw-r--r--sbin/camcontrol/modeedit.c2
-rw-r--r--sbin/camcontrol/progress.c186
-rw-r--r--sbin/camcontrol/progress.h60
-rw-r--r--sbin/ccdconfig/ccdconfig.c9
-rw-r--r--sbin/ddb/ddb.c2
-rw-r--r--sbin/devd/devd.cc4
-rw-r--r--sbin/devd/devd.conf.52
-rw-r--r--sbin/devfs/devfs.812
-rw-r--r--sbin/dhclient/dhclient.c11
-rw-r--r--sbin/dhclient/dhcpd.h1
-rw-r--r--sbin/dump/traverse.c11
-rw-r--r--sbin/dumpfs/dumpfs.c7
-rw-r--r--sbin/dumpon/dumpon.810
-rw-r--r--sbin/dumpon/dumpon.c43
-rw-r--r--sbin/etherswitchcfg/etherswitchcfg.c4
-rw-r--r--sbin/etherswitchcfg/ifmedia.c4
-rw-r--r--sbin/fsck/Makefile1
-rw-r--r--sbin/fsck/fsck.c31
-rw-r--r--sbin/fsck/fsutil.c33
-rw-r--r--sbin/fsck/fsutil.h11
-rw-r--r--sbin/fsck/preen.c16
-rw-r--r--sbin/fsck_ffs/fsck.h2
-rw-r--r--sbin/fsck_ffs/fsutil.c11
-rw-r--r--sbin/fsck_ffs/gjournal.c6
-rw-r--r--sbin/fsck_ffs/inode.c11
-rw-r--r--sbin/fsck_ffs/main.c57
-rw-r--r--sbin/fsck_ffs/pass1.c8
-rw-r--r--sbin/fsck_ffs/pass2.c20
-rw-r--r--sbin/fsck_ffs/pass4.c6
-rw-r--r--sbin/fsck_ffs/suj.c153
-rw-r--r--sbin/fsck_msdosfs/Makefile1
-rw-r--r--sbin/fsck_msdosfs/boot.c16
-rw-r--r--sbin/fsck_msdosfs/check.c5
-rw-r--r--sbin/fsck_msdosfs/dir.c33
-rw-r--r--sbin/fsck_msdosfs/ext.h2
-rw-r--r--sbin/fsck_msdosfs/fat.c36
-rw-r--r--sbin/fsdb/fsdb.c26
-rw-r--r--sbin/fsdb/fsdbutil.c13
-rw-r--r--sbin/fsirand/fsirand.c4
-rw-r--r--sbin/geom/class/eli/geli.8228
-rw-r--r--sbin/geom/class/multipath/geom_multipath.c26
-rw-r--r--sbin/geom/class/multipath/gmultipath.89
-rw-r--r--sbin/geom/class/part/gpart.85
-rw-r--r--sbin/geom/class/raid/graid.88
-rw-r--r--sbin/geom/class/sched/gsched.814
-rw-r--r--sbin/geom/class/virstor/gvirstor.89
-rw-r--r--sbin/geom/core/geom.c2
-rw-r--r--sbin/ggate/ggatec/ggatec.c2
-rw-r--r--sbin/ggate/ggated/ggated.c6
-rw-r--r--sbin/ggate/ggatel/ggatel.c2
-rw-r--r--sbin/ggate/shared/ggate.h4
-rw-r--r--sbin/growfs/growfs.c9
-rw-r--r--sbin/gvinum/Makefile2
-rw-r--r--sbin/hastd/hast.conf.58
-rw-r--r--sbin/hastd/primary.c83
-rw-r--r--sbin/hastd/proto_common.c2
-rw-r--r--sbin/hastd/synch.h2
-rw-r--r--sbin/ifconfig/af_inet6.c2
-rw-r--r--sbin/ifconfig/ifconfig.810
-rw-r--r--sbin/ifconfig/ifconfig.c4
-rw-r--r--sbin/ipf/ipf/Makefile4
-rw-r--r--sbin/ipfw/dummynet.c14
-rw-r--r--sbin/ipfw/ipfw.8142
-rw-r--r--sbin/ipfw/ipfw2.c8
-rw-r--r--sbin/ipfw/ipv6.c54
-rw-r--r--sbin/ipfw/nat.c8
-rw-r--r--sbin/md5/Makefile6
-rw-r--r--sbin/md5/md5.118
-rw-r--r--sbin/md5/md5.c22
-rw-r--r--sbin/mdconfig/Makefile1
-rw-r--r--sbin/mdconfig/mdconfig.811
-rw-r--r--sbin/mdconfig/mdconfig.c55
-rw-r--r--sbin/mount/getmntopts.34
-rw-r--r--sbin/mount/mount.818
-rw-r--r--sbin/mount/mount.c4
-rw-r--r--sbin/mount_fusefs/Makefile33
-rw-r--r--sbin/mount_fusefs/mount_fusefs.8363
-rw-r--r--sbin/mount_fusefs/mount_fusefs.c499
-rw-r--r--sbin/natd/natd.812
-rw-r--r--sbin/natd/natd.c4
-rw-r--r--sbin/newfs/mkfs.c4
-rw-r--r--sbin/newfs/newfs.c2
-rw-r--r--sbin/newfs/newfs.h1
-rw-r--r--sbin/nvmecontrol/Makefile6
-rw-r--r--sbin/nvmecontrol/nvmecontrol.886
-rw-r--r--sbin/nvmecontrol/nvmecontrol.c600
-rw-r--r--sbin/pfctl/Makefile14
-rw-r--r--sbin/pfctl/missing/altq/altq.h204
-rw-r--r--sbin/pfctl/missing/altq/altq_cbq.h232
-rw-r--r--sbin/pfctl/missing/altq/altq_classq.h203
-rw-r--r--sbin/pfctl/missing/altq/altq_hfsc.h325
-rw-r--r--sbin/pfctl/missing/altq/altq_priq.h172
-rw-r--r--sbin/pfctl/missing/altq/altq_red.h199
-rw-r--r--sbin/pfctl/missing/altq/altq_rio.h145
-rw-r--r--sbin/pfctl/missing/altq/altq_rmclass.h263
-rw-r--r--sbin/pfctl/missing/altq/altq_rmclass_debug.h113
-rw-r--r--sbin/pfctl/missing/altq/altq_var.h267
-rw-r--r--sbin/pfctl/missing/altq/altq_wfq.h129
-rw-r--r--sbin/pfctl/parse.y6038
-rw-r--r--sbin/pfctl/pf_print_state.c362
-rw-r--r--sbin/pfctl/pfctl.8687
-rw-r--r--sbin/pfctl/pfctl.c2391
-rw-r--r--sbin/pfctl/pfctl.h130
-rw-r--r--sbin/pfctl/pfctl_altq.c1258
-rw-r--r--sbin/pfctl/pfctl_optimize.c1655
-rw-r--r--sbin/pfctl/pfctl_osfp.c1108
-rw-r--r--sbin/pfctl/pfctl_parser.c1746
-rw-r--r--sbin/pfctl/pfctl_parser.h305
-rw-r--r--sbin/pfctl/pfctl_qstats.c449
-rw-r--r--sbin/pfctl/pfctl_radix.c585
-rw-r--r--sbin/pfctl/pfctl_table.c634
-rw-r--r--sbin/ping/ping.c5
-rw-r--r--sbin/ping6/ping6.c6
-rw-r--r--sbin/quotacheck/quotacheck.c10
-rw-r--r--sbin/rcorder/rcorder.c2
-rw-r--r--sbin/restore/dirs.c14
-rw-r--r--sbin/restore/interactive.c4
-rw-r--r--sbin/restore/restore.c17
-rw-r--r--sbin/restore/symtab.c7
-rw-r--r--sbin/restore/tape.c34
-rw-r--r--sbin/setkey/setkey.84
-rw-r--r--sbin/shutdown/shutdown.c6
-rw-r--r--sbin/tunefs/tunefs.c31
132 files changed, 20539 insertions, 3007 deletions
diff --git a/sbin/Makefile b/sbin/Makefile
index fcdb5672c53d..16d006da790c 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -49,9 +49,9 @@ SUBDIR=adjkerntz \
mksnap_ffs \
mount \
mount_cd9660 \
+ mount_fusefs \
mount_msdosfs \
mount_nfs \
- mount_ntfs \
mount_nullfs \
mount_udf \
mount_unionfs \
diff --git a/sbin/Makefile.amd64 b/sbin/Makefile.amd64
index 2d231b0cb2b0..d3cf350ee2cc 100644
--- a/sbin/Makefile.amd64
+++ b/sbin/Makefile.amd64
@@ -2,3 +2,4 @@
SUBDIR += bsdlabel
SUBDIR += fdisk
+SUBDIR += nvmecontrol
diff --git a/sbin/Makefile.i386 b/sbin/Makefile.i386
index 4135c44082c9..0ced312832f8 100644
--- a/sbin/Makefile.i386
+++ b/sbin/Makefile.i386
@@ -2,4 +2,5 @@
SUBDIR += bsdlabel
SUBDIR += fdisk
+SUBDIR += nvmecontrol
SUBDIR += sconfig
diff --git a/sbin/adjkerntz/adjkerntz.c b/sbin/adjkerntz/adjkerntz.c
index 35d8da9d6c51..c42379d71915 100644
--- a/sbin/adjkerntz/adjkerntz.c
+++ b/sbin/adjkerntz/adjkerntz.c
@@ -315,10 +315,7 @@ recalculate:
* restoring disrtcset, since we don't clean up
* anything.
*/
- if (gettimeofday(&tv, (struct timezone *)NULL)) {
- syslog(LOG_ERR, "gettimeofday: %m");
- return 1;
- }
+ (void)gettimeofday(&tv, NULL);
tv.tv_sec += diff;
stv = &tv;
}
diff --git a/sbin/camcontrol/Makefile b/sbin/camcontrol/Makefile
index 0cbde1226e33..68633757c3df 100644
--- a/sbin/camcontrol/Makefile
+++ b/sbin/camcontrol/Makefile
@@ -3,7 +3,7 @@
PROG= camcontrol
SRCS= camcontrol.c util.c
.if !defined(RELEASE_CRUNCH)
-SRCS+= fwdownload.c modeedit.c
+SRCS+= fwdownload.c modeedit.c progress.c
.else
CFLAGS+= -DMINIMALISTIC
.endif
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index fdcec66cec60..66a45eb7af1d 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 24, 2011
+.Dd June 4, 2012
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -175,6 +175,7 @@
.Op Fl S
.Op Fl X
.Op Fl c
+.Op Fl p
.Aq all|off|bus Ns Op :target Ns Op :lun
.Nm
.Ic tags
@@ -496,6 +497,8 @@ is specified,
.Nm
will print out the number of defects given in the READ DEFECT DATA header
returned from the drive.
+Some drives will report 0 defects if neither the primary or grown defect
+lists are requested.
.It Ic modepage
Allows the user to display and optionally edit a SCSI mode page.
The mode
@@ -737,7 +740,7 @@ Set the partial pathway timeout value, in microseconds.
See the
.Tn ANSI
.Tn SAS
-Protcol Layer (SPL)
+Protocol Layer (SPL)
specification for more information on this field.
.It Fl a Ar enable|disable
Enable or disable SATA slumber phy power conditions.
@@ -796,6 +799,8 @@ Enable CAM_DEBUG_XPT printfs.
Enable CAM_DEBUG_CDB printfs.
This will cause the kernel to print out the
SCSI CDBs sent to the specified device(s).
+.It Fl p
+Enable CAM_DEBUG_PROBE printfs.
.It all
Enable debugging for all devices.
.It off
@@ -1106,7 +1111,7 @@ Do not ask for confirmation.
Run in simulation mode.
Packet sizes that will be sent are shown, but no actual packet is sent to the
device.
-No confimation is asked in simulation mode.
+No confirmation is asked in simulation mode.
.It Fl v
Besides showing sense information in case of a failure, the verbose option
causes
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index e24fff1f13ef..a3c7f0515c9d 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -123,6 +123,7 @@ typedef enum {
CAM_ARG_DEBUG_CDB = 0x08000000,
CAM_ARG_DEBUG_XPT = 0x10000000,
CAM_ARG_DEBUG_PERIPH = 0x20000000,
+ CAM_ARG_DEBUG_PROBE = 0x40000000,
} cam_argmask;
struct camcontrol_opts {
@@ -176,7 +177,7 @@ static struct camcontrol_opts option_table[] = {
{"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
{"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
- {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"},
+ {"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"},
{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
@@ -1025,11 +1026,11 @@ camxferrate(struct cam_device *device)
if (sas->valid & CTS_SAS_VALID_SPEED)
speed = sas->bitrate;
} else if (ccb->cts.transport == XPORT_ATA) {
- struct ccb_trans_settings_ata *ata =
+ struct ccb_trans_settings_pata *pata =
&ccb->cts.xport_specific.ata;
- if (ata->valid & CTS_ATA_VALID_MODE)
- speed = ata_mode2speed(ata->mode);
+ if (pata->valid & CTS_ATA_VALID_MODE)
+ speed = ata_mode2speed(pata->mode);
} else if (ccb->cts.transport == XPORT_SATA) {
struct ccb_trans_settings_sata *sata =
&ccb->cts.xport_specific.sata;
@@ -1072,16 +1073,16 @@ camxferrate(struct cam_device *device)
fprintf(stdout, ")");
}
} else if (ccb->cts.transport == XPORT_ATA) {
- struct ccb_trans_settings_ata *ata =
+ struct ccb_trans_settings_pata *pata =
&ccb->cts.xport_specific.ata;
printf(" (");
- if (ata->valid & CTS_ATA_VALID_MODE)
- printf("%s, ", ata_mode2string(ata->mode));
- if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
- printf("ATAPI %dbytes, ", ata->atapi);
- if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
- printf("PIO %dbytes", ata->bytecount);
+ if (pata->valid & CTS_ATA_VALID_MODE)
+ printf("%s, ", ata_mode2string(pata->mode));
+ if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
+ printf("ATAPI %dbytes, ", pata->atapi);
+ if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
+ printf("PIO %dbytes", pata->bytecount);
printf(")");
} else if (ccb->cts.transport == XPORT_SATA) {
struct ccb_trans_settings_sata *sata =
@@ -1798,13 +1799,14 @@ readdefects(struct cam_device *device, int argc, char **argv,
union ccb *ccb = NULL;
struct scsi_read_defect_data_10 *rdd_cdb;
u_int8_t *defect_list = NULL;
- u_int32_t dlist_length = 65000;
+ u_int32_t max_dlist_length = SRDD10_MAX_LENGTH, dlist_length = 0;
u_int32_t returned_length = 0;
u_int32_t num_returned = 0;
u_int8_t returned_format;
unsigned int i;
int c, error = 0;
- int lists_specified = 0;
+ int lists_specified;
+ int get_length = 1;
while ((c = getopt(argc, argv, combinedopt)) != -1) {
switch(c){
@@ -1841,20 +1843,33 @@ readdefects(struct cam_device *device, int argc, char **argv,
ccb = cam_getccb(device);
/*
- * Hopefully 65000 bytes is enough to hold the defect list. If it
- * isn't, the disk is probably dead already. We'd have to go with
- * 12 byte command (i.e. alloc_length is 32 bits instead of 16)
- * to hold them all.
+ * Eventually we should probably support the 12 byte READ DEFECT
+ * DATA command. It supports a longer parameter list, which may be
+ * necessary on newer drives with lots of defects. According to
+ * the SBC-3 spec, drives are supposed to return an illegal request
+ * if they have more defect data than will fit in 64K.
*/
- defect_list = malloc(dlist_length);
+ defect_list = malloc(max_dlist_length);
if (defect_list == NULL) {
warnx("can't malloc memory for defect list");
error = 1;
goto defect_bailout;
}
+ /*
+ * We start off asking for just the header to determine how much
+ * defect data is available. Some Hitachi drives return an error
+ * if you ask for more data than the drive has. Once we know the
+ * length, we retry the command with the returned length.
+ */
+ dlist_length = sizeof(struct scsi_read_defect_data_hdr_10);
+
rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
+retry:
+
+ lists_specified = 0;
+
/*
* cam_getccb() zeros the CCB header only. So we need to zero the
* payload portion of the ccb.
@@ -1916,6 +1931,51 @@ readdefects(struct cam_device *device, int argc, char **argv,
returned_length = scsi_2btoul(((struct
scsi_read_defect_data_hdr_10 *)defect_list)->length);
+ if (get_length != 0) {
+ get_length = 0;
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
+ CAM_SCSI_STATUS_ERROR) {
+ struct scsi_sense_data *sense;
+ int error_code, sense_key, asc, ascq;
+
+ sense = &ccb->csio.sense_data;
+ scsi_extract_sense_len(sense, ccb->csio.sense_len -
+ ccb->csio.sense_resid, &error_code, &sense_key,
+ &asc, &ascq, /*show_errors*/ 1);
+
+ /*
+ * If the drive is reporting that it just doesn't
+ * support the defect list format, go ahead and use
+ * the length it reported. Otherwise, the length
+ * may not be valid, so use the maximum.
+ */
+ if ((sense_key == SSD_KEY_RECOVERED_ERROR)
+ && (asc == 0x1c) && (ascq == 0x00)
+ && (returned_length > 0)) {
+ dlist_length = returned_length +
+ sizeof(struct scsi_read_defect_data_hdr_10);
+ dlist_length = min(dlist_length,
+ SRDD10_MAX_LENGTH);
+ } else
+ dlist_length = max_dlist_length;
+ } else if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
+ CAM_REQ_CMP){
+ error = 1;
+ warnx("Error reading defect header");
+ if (arglist & CAM_ARG_VERBOSE)
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ goto defect_bailout;
+ } else {
+ dlist_length = returned_length +
+ sizeof(struct scsi_read_defect_data_hdr_10);
+ dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
+ }
+
+ goto retry;
+ }
+
returned_format = ((struct scsi_read_defect_data_hdr_10 *)
defect_list)->format;
@@ -2640,6 +2700,10 @@ camdebug(int argc, char **argv, char *combinedopt)
arglist |= CAM_ARG_DEBUG_CDB;
ccb.cdbg.flags |= CAM_DEBUG_CDB;
break;
+ case 'p':
+ arglist |= CAM_ARG_DEBUG_PROBE;
+ ccb.cdbg.flags |= CAM_DEBUG_PROBE;
+ break;
default:
break;
}
@@ -2669,7 +2733,7 @@ camdebug(int argc, char **argv, char *combinedopt)
ccb.cdbg.flags = CAM_DEBUG_NONE;
arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
- CAM_ARG_DEBUG_XPT);
+ CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
} else if (strncmp(tstr, "all", 3) != 0) {
tmpstr = (char *)strtok(tstr, ":");
if ((tmpstr != NULL) && (*tmpstr != '\0')){
@@ -2891,21 +2955,45 @@ cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
"enabled" : "disabled");
}
}
+ if (cts->transport == XPORT_FC) {
+ struct ccb_trans_settings_fc *fc =
+ &cts->xport_specific.fc;
+
+ if (fc->valid & CTS_FC_VALID_WWNN)
+ fprintf(stdout, "%sWWNN: 0x%llx", pathstr,
+ (long long) fc->wwnn);
+ if (fc->valid & CTS_FC_VALID_WWPN)
+ fprintf(stdout, "%sWWPN: 0x%llx", pathstr,
+ (long long) fc->wwpn);
+ if (fc->valid & CTS_FC_VALID_PORT)
+ fprintf(stdout, "%sPortID: 0x%x", pathstr, fc->port);
+ if (fc->valid & CTS_FC_VALID_SPEED)
+ fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
+ pathstr, fc->bitrate / 1000, fc->bitrate % 1000);
+ }
+ if (cts->transport == XPORT_SAS) {
+ struct ccb_trans_settings_sas *sas =
+ &cts->xport_specific.sas;
+
+ if (sas->valid & CTS_SAS_VALID_SPEED)
+ fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
+ pathstr, sas->bitrate / 1000, sas->bitrate % 1000);
+ }
if (cts->transport == XPORT_ATA) {
- struct ccb_trans_settings_ata *ata =
+ struct ccb_trans_settings_pata *pata =
&cts->xport_specific.ata;
- if ((ata->valid & CTS_ATA_VALID_MODE) != 0) {
+ if ((pata->valid & CTS_ATA_VALID_MODE) != 0) {
fprintf(stdout, "%sATA mode: %s\n", pathstr,
- ata_mode2string(ata->mode));
+ ata_mode2string(pata->mode));
}
- if ((ata->valid & CTS_ATA_VALID_ATAPI) != 0) {
+ if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) {
fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
- ata->atapi);
+ pata->atapi);
}
- if ((ata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
+ if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
fprintf(stdout, "%sPIO transaction length: %d\n",
- pathstr, ata->bytecount);
+ pathstr, pata->bytecount);
}
}
if (cts->transport == XPORT_SATA) {
@@ -2941,12 +3029,22 @@ cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
sata->caps);
}
}
+ if (cts->protocol == PROTO_ATA) {
+ struct ccb_trans_settings_ata *ata=
+ &cts->proto_specific.ata;
+
+ if (ata->valid & CTS_ATA_VALID_TQ) {
+ fprintf(stdout, "%stagged queueing: %s\n", pathstr,
+ (ata->flags & CTS_ATA_FLAGS_TAG_ENB) ?
+ "enabled" : "disabled");
+ }
+ }
if (cts->protocol == PROTO_SCSI) {
struct ccb_trans_settings_scsi *scsi=
&cts->proto_specific.scsi;
if (scsi->valid & CTS_SCSI_VALID_TQ) {
- fprintf(stdout, "%stagged queueing is %s\n", pathstr,
+ fprintf(stdout, "%stagged queueing: %s\n", pathstr,
(scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
"enabled" : "disabled");
}
@@ -3032,6 +3130,26 @@ get_cgd_bailout:
return(retval);
}
+/* return the type of disk (really the command type) */
+static const char *
+get_disk_type(struct cam_device *device)
+{
+ struct ccb_getdev cgd;
+
+ (void) memset(&cgd, 0x0, sizeof(cgd));
+ get_cgd(device, &cgd);
+ switch(cgd.protocol) {
+ case PROTO_SCSI:
+ return "scsi";
+ case PROTO_ATA:
+ case PROTO_ATAPI:
+ case PROTO_SATAPM:
+ return "ata";
+ default:
+ return "unknown";
+ }
+}
+
static void
cpi_print(struct ccb_pathinq *cpi)
{
@@ -3384,16 +3502,19 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
if (change_settings) {
int didsettings = 0;
struct ccb_trans_settings_spi *spi = NULL;
- struct ccb_trans_settings_ata *ata = NULL;
+ struct ccb_trans_settings_pata *pata = NULL;
struct ccb_trans_settings_sata *sata = NULL;
+ struct ccb_trans_settings_ata *ata = NULL;
struct ccb_trans_settings_scsi *scsi = NULL;
if (ccb->cts.transport == XPORT_SPI)
spi = &ccb->cts.xport_specific.spi;
if (ccb->cts.transport == XPORT_ATA)
- ata = &ccb->cts.xport_specific.ata;
+ pata = &ccb->cts.xport_specific.ata;
if (ccb->cts.transport == XPORT_SATA)
sata = &ccb->cts.xport_specific.sata;
+ if (ccb->cts.protocol == PROTO_ATA)
+ ata = &ccb->cts.proto_specific.ata;
if (ccb->cts.protocol == PROTO_SCSI)
scsi = &ccb->cts.proto_specific.scsi;
ccb->cts.xport_specific.valid = 0;
@@ -3406,19 +3527,28 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
didsettings++;
}
- if (scsi && tag_enable != -1) {
+ if (tag_enable != -1) {
if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
warnx("HBA does not support tagged queueing, "
"so you cannot modify tag settings");
retval = 1;
goto ratecontrol_bailout;
}
- scsi->valid |= CTS_SCSI_VALID_TQ;
- if (tag_enable == 0)
- scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
- else
- scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
- didsettings++;
+ if (ata) {
+ ata->valid |= CTS_SCSI_VALID_TQ;
+ if (tag_enable == 0)
+ ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
+ else
+ ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
+ didsettings++;
+ } else if (scsi) {
+ scsi->valid |= CTS_SCSI_VALID_TQ;
+ if (tag_enable == 0)
+ scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+ else
+ scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
+ didsettings++;
+ }
}
if (spi && offset != -1) {
if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
@@ -3465,6 +3595,12 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
retval = 1;
goto ratecontrol_bailout;
}
+ if (!user_settings) {
+ warnx("You can modify only user rate "
+ "settings for SATA");
+ retval = 1;
+ goto ratecontrol_bailout;
+ }
sata->revision = ata_speed2revision(syncrate * 100);
if (sata->revision < 0) {
warnx("Invalid rate %f", syncrate);
@@ -3474,16 +3610,22 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
sata->valid |= CTS_SATA_VALID_REVISION;
didsettings++;
}
- if ((ata || sata) && mode != -1) {
+ if ((pata || sata) && mode != -1) {
if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
warnx("HBA is not capable of changing "
"transfer rates");
retval = 1;
goto ratecontrol_bailout;
}
- if (ata) {
- ata->mode = mode;
- ata->valid |= CTS_ATA_VALID_MODE;
+ if (!user_settings) {
+ warnx("You can modify only user mode "
+ "settings for ATA/SATA");
+ retval = 1;
+ goto ratecontrol_bailout;
+ }
+ if (pata) {
+ pata->mode = mode;
+ pata->valid |= CTS_ATA_VALID_MODE;
} else {
sata->mode = mode;
sata->valid |= CTS_SATA_VALID_MODE;
@@ -3530,11 +3672,6 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
if (didsettings == 0) {
goto ratecontrol_bailout;
}
- if (!user_settings && (ata || sata)) {
- warnx("You can modify only user settings for ATA/SATA");
- retval = 1;
- goto ratecontrol_bailout;
- }
ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
if (cam_send_ccb(device, ccb) < 0) {
perror("error sending XPT_SET_TRAN_SETTINGS CCB");
@@ -3566,13 +3703,10 @@ ratecontrol(struct cam_device *device, int retry_count, int timeout,
fprintf(stderr, "Test Unit Ready failed\n");
goto ratecontrol_bailout;
}
- /*
- * If the user wants things quiet, there's no sense in
- * getting the transfer settings, if we're not going
- * to print them.
- */
- if (quiet != 0)
- goto ratecontrol_bailout;
+ }
+ if ((change_settings || send_tur) && !quiet &&
+ (ccb->cts.transport == XPORT_ATA ||
+ ccb->cts.transport == XPORT_SATA || send_tur)) {
fprintf(stdout, "New parameters:\n");
retval = get_print_cts(device, user_settings, 0, NULL);
}
@@ -4330,7 +4464,7 @@ static int
smpcmd(struct cam_device *device, int argc, char **argv, char *combinedopt,
int retry_count, int timeout)
{
- int c, error;
+ int c, error = 0;
union ccb *ccb;
uint8_t *smp_request = NULL, *smp_response = NULL;
int request_size = 0, response_size = 0;
@@ -4624,7 +4758,10 @@ try_long:
smp_report_general_sbuf(response, sizeof(*response), sb);
- sbuf_finish(sb);
+ if (sbuf_finish(sb) != 0) {
+ warnx("%s: sbuf_finish", __func__);
+ goto bailout;
+ }
printf("%s", sbuf_data(sb));
@@ -4995,7 +5132,10 @@ smpmaninfo(struct cam_device *device, int argc, char **argv,
smp_report_manuf_info_sbuf(&response, sizeof(response), sb);
- sbuf_finish(sb);
+ if (sbuf_finish(sb) != 0) {
+ warnx("%s: sbuf_finish", __func__);
+ goto bailout;
+ }
printf("%s", sbuf_data(sb));
@@ -5325,6 +5465,7 @@ smpphylist(struct cam_device *device, int argc, char **argv,
bzero(&(&ccb->ccb_h)[1],
sizeof(union ccb) - sizeof(struct ccb_hdr));
+ STAILQ_INIT(&devlist.dev_queue);
rgrequest = malloc(sizeof(*rgrequest));
if (rgrequest == NULL) {
@@ -5393,7 +5534,6 @@ smpphylist(struct cam_device *device, int argc, char **argv,
goto bailout;
}
- STAILQ_INIT(&devlist.dev_queue);
devlist.path_id = device->path_id;
retval = buildbusdevlist(&devlist);
@@ -5643,9 +5783,10 @@ bailout:
#endif /* MINIMALISTIC */
void
-usage(int verbose)
+usage(int printlong)
{
- fprintf(verbose ? stdout : stderr,
+
+ fprintf(printlong ? stdout : stderr,
"usage: camcontrol <command> [device id][generic args][command args]\n"
" camcontrol devlist [-v]\n"
#ifndef MINIMALISTIC
@@ -5694,7 +5835,7 @@ usage(int verbose)
" camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
#endif /* MINIMALISTIC */
" camcontrol help\n");
- if (!verbose)
+ if (!printlong)
return;
#ifndef MINIMALISTIC
fprintf(stdout,
@@ -6142,7 +6283,8 @@ main(int argc, char **argv)
break;
case CAM_CMD_DOWNLOAD_FW:
error = fwdownload(cam_dev, argc, argv, combinedopt,
- arglist & CAM_ARG_VERBOSE, retry_count, timeout);
+ arglist & CAM_ARG_VERBOSE, retry_count, timeout,
+ get_disk_type(cam_dev));
break;
#endif /* MINIMALISTIC */
case CAM_CMD_USAGE:
diff --git a/sbin/camcontrol/camcontrol.h b/sbin/camcontrol/camcontrol.h
index 189d74c856d7..616236a8b762 100644
--- a/sbin/camcontrol/camcontrol.h
+++ b/sbin/camcontrol/camcontrol.h
@@ -40,8 +40,11 @@ struct get_hook
int got;
};
+extern int verbose;
+
int fwdownload(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int verbose, int retry_count, int timeout);
+ char *combinedopt, int printerrors, int retry_count, int timeout,
+ const char */*type*/);
void mode_sense(struct cam_device *device, int mode_page, int page_control,
int dbd, int retry_count, int timeout, u_int8_t *data,
int datalen);
@@ -57,5 +60,5 @@ char *cget(void *hook, char *name);
int iget(void *hook, char *name);
void arg_put(void *hook, int letter, void *arg, int count, char *name);
int get_confirmation(void);
-void usage(int verbose);
+void usage(int printlong);
#endif /* _CAMCONTROL_H */
diff --git a/sbin/camcontrol/fwdownload.c b/sbin/camcontrol/fwdownload.c
index abb3726fa297..daa1520eb471 100644
--- a/sbin/camcontrol/fwdownload.c
+++ b/sbin/camcontrol/fwdownload.c
@@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_message.h>
#include <camlib.h>
+#include "progress.h"
+
#include "camcontrol.h"
#define CMD_TIMEOUT 50000 /* 50 seconds */
@@ -73,6 +75,7 @@ typedef enum {
VENDOR_HP,
VENDOR_IBM,
VENDOR_PLEXTOR,
+ VENDOR_QUALSTAR,
VENDOR_QUANTUM,
VENDOR_SEAGATE,
VENDOR_UNKNOWN
@@ -93,17 +96,43 @@ static const struct fw_vendor vendors_list[] = {
{VENDOR_HP, "HP", 0x8000, 0x07, 0x07, 0, 1},
{VENDOR_IBM, "IBM", 0x8000, 0x05, 0x05, 1, 0},
{VENDOR_PLEXTOR, "PLEXTOR", 0x2000, 0x04, 0x05, 0, 1},
+ {VENDOR_QUALSTAR, "QUALSTAR", 0x2030, 0x05, 0x05, 0, 0},
{VENDOR_QUANTUM, "QUANTUM", 0x2000, 0x04, 0x05, 0, 1},
{VENDOR_SEAGATE, "SEAGATE", 0x8000, 0x07, 0x07, 0, 1},
+ /* the next 2 are SATA disks going through SAS HBA */
+ {VENDOR_SEAGATE, "ATA ST", 0x8000, 0x07, 0x07, 0, 1},
+ {VENDOR_HITACHI, "ATA HDS", 0x8000, 0x05, 0x05, 1, 0},
{VENDOR_UNKNOWN, NULL, 0x0000, 0x00, 0x00, 0, 0}
};
+#ifndef ATA_DOWNLOAD_MICROCODE
+#define ATA_DOWNLOAD_MICROCODE 0x92
+#endif
+
+#define USE_OFFSETS_FEATURE 0x3
+
+#ifndef LOW_SECTOR_SIZE
+#define LOW_SECTOR_SIZE 512
+#endif
+
+#define ATA_MAKE_LBA(o, p) \
+ ((((((o) / LOW_SECTOR_SIZE) >> 8) & 0xff) << 16) | \
+ ((((o) / LOW_SECTOR_SIZE) & 0xff) << 8) | \
+ ((((p) / LOW_SECTOR_SIZE) >> 8) & 0xff))
+
+#define ATA_MAKE_SECTORS(p) (((p) / 512) & 0xff)
+
+#ifndef UNKNOWN_MAX_PKT_SIZE
+#define UNKNOWN_MAX_PKT_SIZE 0x8000
+#endif
+
static const struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev);
static char *fw_read_img(const char *fw_img_path,
const struct fw_vendor *vp, int *num_bytes);
static int fw_download_img(struct cam_device *cam_dev,
const struct fw_vendor *vp, char *buf, int img_size,
- int sim_mode, int verbose, int retry_count, int timeout);
+ int sim_mode, int printerrors, int retry_count, int timeout,
+ const char */*name*/, const char */*type*/);
/*
* Find entry in vendors list that belongs to
@@ -173,6 +202,9 @@ fw_read_img(const char *fw_img_path, const struct fw_vendor *vp, int *num_bytes)
(img_size % 512 == 80))
skip_bytes = 80;
break;
+ case VENDOR_QUALSTAR:
+ skip_bytes = img_size % 1030;
+ break;
default:
break;
}
@@ -206,28 +238,59 @@ bailout1:
*/
static int
fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp,
- char *buf, int img_size, int sim_mode, int verbose, int retry_count,
- int timeout)
+ char *buf, int img_size, int sim_mode, int printerrors, int retry_count,
+ int timeout, const char *imgname, const char *type)
{
struct scsi_write_buffer cdb;
+ progress_t progress;
+ int size;
union ccb *ccb;
int pkt_count = 0;
+ int max_pkt_size;
u_int32_t pkt_size = 0;
char *pkt_ptr = buf;
u_int32_t offset;
int last_pkt = 0;
+ int16_t *ptr;
if ((ccb = cam_getccb(cam_dev)) == NULL) {
warnx("Could not allocate CCB");
return (1);
}
- scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
- SSD_FULL_SIZE, 5000);
+ if (strcmp(type, "scsi") == 0) {
+ scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
+ SSD_FULL_SIZE, 5000);
+ } else if (strcmp(type, "ata") == 0) {
+ /* cam_getccb cleans up the header, caller has to zero the payload */
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+
+ ptr = (uint16_t *)malloc(sizeof(struct ata_params));
+
+ if (ptr == NULL) {
+ cam_freeccb(ccb);
+ warnx("can't malloc memory for identify\n");
+ return(1);
+ }
+ bzero(ptr, sizeof(struct ata_params));
+ cam_fill_ataio(&ccb->ataio,
+ 1,
+ NULL,
+ /*flags*/CAM_DIR_IN,
+ MSG_SIMPLE_Q_TAG,
+ /*data_ptr*/(uint8_t *)ptr,
+ /*dxfer_len*/sizeof(struct ata_params),
+ timeout ? timeout : 30 * 1000);
+ ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
+ } else {
+ warnx("weird disk type '%s'", type);
+ return 1;
+ }
/* Disable freezing the device queue. */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
if (cam_send_ccb(cam_dev, ccb) < 0) {
- warnx("Error sending test unit ready");
- if (verbose)
+ warnx("Error sending identify/test unit ready");
+ if (printerrors)
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
cam_freeccb(ccb);
@@ -235,89 +298,108 @@ fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp,
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
warnx("Device is not ready");
- if (verbose)
+ if (printerrors)
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
cam_freeccb(ccb);
return (1);
}
- pkt_size = vp->max_pkt_size;
- if (verbose || sim_mode) {
- fprintf(stdout,
- "--------------------------------------------------\n");
- fprintf(stdout,
- "PktNo. PktSize BytesRemaining LastPkt\n");
- fprintf(stdout,
- "--------------------------------------------------\n");
+ max_pkt_size = vp->max_pkt_size;
+ if (vp->max_pkt_size == 0 && strcmp(type, "ata") == 0) {
+ max_pkt_size = UNKNOWN_MAX_PKT_SIZE;
}
+ pkt_size = vp->max_pkt_size;
+ progress_init(&progress, imgname, size = img_size);
/* Download single fw packets. */
do {
- if (img_size <= vp->max_pkt_size) {
+ if (img_size <= max_pkt_size) {
last_pkt = 1;
pkt_size = img_size;
}
- if (verbose || sim_mode)
- fprintf(stdout, "%3u %5u (0x%05X) %7u (0x%06X) "
- "%d\n", pkt_count, pkt_size, pkt_size,
- img_size - pkt_size, img_size - pkt_size,
- last_pkt);
+ progress_update(&progress, size - img_size);
+ progress_draw(&progress);
bzero(&cdb, sizeof(cdb));
- cdb.opcode = WRITE_BUFFER;
- cdb.control = 0;
- /* Parameter list length. */
- scsi_ulto3b(pkt_size, &cdb.length[0]);
- offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
- scsi_ulto3b(offset, &cdb.offset[0]);
- cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
- cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
- /* Zero out payload of ccb union after ccb header. */
- bzero((u_char *)ccb + sizeof(struct ccb_hdr),
- sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
- /* Copy previously constructed cdb into ccb_scsiio struct. */
- bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
- sizeof(struct scsi_write_buffer));
- /* Fill rest of ccb_scsiio struct. */
+ if (strcmp(type, "scsi") == 0) {
+ cdb.opcode = WRITE_BUFFER;
+ cdb.control = 0;
+ /* Parameter list length. */
+ scsi_ulto3b(pkt_size, &cdb.length[0]);
+ offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
+ scsi_ulto3b(offset, &cdb.offset[0]);
+ cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
+ cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
+ /* Zero out payload of ccb union after ccb header. */
+ bzero((u_char *)ccb + sizeof(struct ccb_hdr),
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+ /* Copy previously constructed cdb into ccb_scsiio struct. */
+ bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
+ sizeof(struct scsi_write_buffer));
+ /* Fill rest of ccb_scsiio struct. */
+ if (!sim_mode) {
+ cam_fill_csio(&ccb->csio, /* ccb_scsiio */
+ retry_count, /* retries */
+ NULL, /* cbfcnp */
+ CAM_DIR_OUT | CAM_DEV_QFRZDIS, /* flags */
+ CAM_TAG_ACTION_NONE, /* tag_action */
+ (u_char *)pkt_ptr, /* data_ptr */
+ pkt_size, /* dxfer_len */
+ SSD_FULL_SIZE, /* sense_len */
+ sizeof(struct scsi_write_buffer), /* cdb_len */
+ timeout ? timeout : CMD_TIMEOUT); /* timeout */
+ }
+ } else if (strcmp(type, "ata") == 0) {
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+ if (!sim_mode) {
+ uint32_t off;
+
+ cam_fill_ataio(&ccb->ataio,
+ (last_pkt) ? 256 : retry_count,
+ NULL,
+ /*flags*/CAM_DIR_OUT | CAM_DEV_QFRZDIS,
+ CAM_TAG_ACTION_NONE,
+ /*data_ptr*/(uint8_t *)pkt_ptr,
+ /*dxfer_len*/pkt_size,
+ timeout ? timeout : 30 * 1000);
+ off = (uint32_t)(pkt_ptr - buf);
+ ata_28bit_cmd(&ccb->ataio, ATA_DOWNLOAD_MICROCODE,
+ USE_OFFSETS_FEATURE,
+ ATA_MAKE_LBA(off, pkt_size),
+ ATA_MAKE_SECTORS(pkt_size));
+ }
+ }
if (!sim_mode) {
- cam_fill_csio(&ccb->csio, /* ccb_scsiio */
- retry_count, /* retries */
- NULL, /* cbfcnp */
- CAM_DIR_OUT | CAM_DEV_QFRZDIS, /* flags */
- CAM_TAG_ACTION_NONE, /* tag_action */
- (u_char *)pkt_ptr, /* data_ptr */
- pkt_size, /* dxfer_len */
- SSD_FULL_SIZE, /* sense_len */
- sizeof(struct scsi_write_buffer), /* cdb_len */
- timeout ? timeout : CMD_TIMEOUT); /* timeout */
/* Execute the command. */
if (cam_send_ccb(cam_dev, ccb) < 0) {
warnx("Error writing image to device");
- if (verbose)
+ if (printerrors)
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
- CAM_EPF_ALL, stderr);
+ CAM_EPF_ALL, stderr);
goto bailout;
}
+ if (ccb->ataio.res.status != 0 /*&& !last_pkt*/) {
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
}
/* Prepare next round. */
pkt_count++;
pkt_ptr += pkt_size;
img_size -= pkt_size;
} while(!last_pkt);
- if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- if (verbose)
- cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
- CAM_EPF_ALL, stderr);
- goto bailout;
- }
+ progress_complete(&progress, size - img_size);
cam_freeccb(ccb);
return (0);
bailout:
+ progress_complete(&progress, size - img_size);
cam_freeccb(ccb);
return (1);
}
int
fwdownload(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int verbose, int retry_count, int timeout)
+ char *combinedopt, int printerrors, int retry_count, int timeout,
+ const char *type)
{
const struct fw_vendor *vp;
char *fw_img_path = NULL;
@@ -345,12 +427,13 @@ fwdownload(struct cam_device *device, int argc, char **argv,
}
if (fw_img_path == NULL)
- errx(1,
- "you must specify a firmware image file using -f option");
+ errx(1, "you must specify a firmware image file using -f option");
vp = fw_get_vendor(device);
- if (vp == NULL || vp->type == VENDOR_UNKNOWN)
- errx(1, "Unsupported device");
+ if (vp == NULL)
+ errx(1, "NULL vendor");
+ if (vp->type == VENDOR_UNKNOWN)
+ warnx("Unsupported device - flashing through an HBA?");
buf = fw_read_img(fw_img_path, vp, &img_size);
if (buf == NULL)
@@ -360,11 +443,6 @@ fwdownload(struct cam_device *device, int argc, char **argv,
fprintf(stdout, "You are about to download firmware image (%s)"
" into the following device:\n",
fw_img_path);
- if (scsidoinquiry(device, argc, argv, combinedopt, 0,
- 5000) != 0) {
- warnx("Error sending inquiry");
- goto fail;
- }
fprintf(stdout, "\nIt may damage your drive. ");
if (!get_confirmation())
goto fail;
@@ -372,11 +450,12 @@ fwdownload(struct cam_device *device, int argc, char **argv,
if (sim_mode)
fprintf(stdout, "Running in simulation mode\n");
- if (fw_download_img(device, vp, buf, img_size, sim_mode, verbose,
- retry_count, timeout) != 0) {
+ if (fw_download_img(device, vp, buf, img_size, sim_mode, printerrors,
+ retry_count, timeout, fw_img_path, type) != 0) {
fprintf(stderr, "Firmware download failed\n");
goto fail;
- } else
+ }
+ else
fprintf(stdout, "Firmware download successful\n");
free(buf);
diff --git a/sbin/camcontrol/modeedit.c b/sbin/camcontrol/modeedit.c
index 6a628e897911..8504208cfcc4 100644
--- a/sbin/camcontrol/modeedit.c
+++ b/sbin/camcontrol/modeedit.c
@@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$");
#include <camlib.h>
#include "camcontrol.h"
-int verbose = 0;
-
#define DEFAULT_SCSI_MODE_DB "/usr/share/misc/scsi_modes"
#define DEFAULT_EDITOR "vi"
#define MAX_FORMAT_SPEC 4096 /* Max CDB format specifier. */
diff --git a/sbin/camcontrol/progress.c b/sbin/camcontrol/progress.c
new file mode 100644
index 000000000000..dc6109f48806
--- /dev/null
+++ b/sbin/camcontrol/progress.c
@@ -0,0 +1,186 @@
+/* $NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "progress.h"
+
+static const char * const suffixes[] = {
+ "", /* 2^0 (byte) */
+ "KiB", /* 2^10 Kibibyte */
+ "MiB", /* 2^20 Mebibyte */
+ "GiB", /* 2^30 Gibibyte */
+ "TiB", /* 2^40 Tebibyte */
+ "PiB", /* 2^50 Pebibyte */
+ "EiB", /* 2^60 Exbibyte */
+};
+
+#define NSUFFIXES (sizeof(suffixes) / sizeof(suffixes[0]))
+#define SECSPERHOUR (60 * 60)
+#define DEFAULT_TTYWIDTH 80
+
+/* initialise progress meter structure */
+int
+progress_init(progress_t *prog, const char *prefix, uint64_t total)
+{
+ struct winsize winsize;
+ int oerrno = errno;
+
+ (void) memset(prog, 0x0, sizeof(*prog));
+ prog->size = total;
+ prog->prefix = strdup(prefix);
+ prog->start = time(NULL);
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
+ winsize.ws_col != 0) {
+ prog->ttywidth = winsize.ws_col;
+ } else {
+ prog->ttywidth = DEFAULT_TTYWIDTH;
+ }
+ errno = oerrno;
+ return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_update(progress_t *prog, uint64_t done)
+{
+ prog->done = done;
+ prog->percent = (prog->done * 100) / prog->size;
+ prog->now = time(NULL);
+ prog->elapsed = prog->now - prog->start;
+ if (done == 0 || prog->elapsed == 0 || prog->done / prog->elapsed == 0) {
+ prog->eta = 0;
+ } else {
+ prog->eta = prog->size / (prog->done / prog->elapsed) - prog->elapsed;
+ }
+ return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_reset_size(progress_t *prog, uint64_t size)
+{
+ prog->size = size;
+ return 1;
+}
+
+/* make it look pretty at the end - display done bytes (usually total) */
+int
+progress_complete(progress_t *prog, uint64_t done)
+{
+ progress_update(prog, done);
+ progress_draw(prog);
+ printf("\n");
+ return 1;
+}
+
+/* draw the progress meter */
+int
+progress_draw(progress_t *prog)
+{
+#define BAROVERHEAD 45 /* non `*' portion of progress bar */
+ /*
+ * stars should contain at least
+ * sizeof(buf) - BAROVERHEAD entries
+ */
+ static const char stars[] =
+"*****************************************************************************"
+"*****************************************************************************"
+"*****************************************************************************";
+ unsigned bytesabbrev;
+ unsigned bpsabbrev;
+ int64_t secs;
+ uint64_t bytespersec;
+ uint64_t abbrevsize;
+ int64_t secsleft;
+ size_t barlength;
+ size_t starc;
+ char hours[12];
+ char buf[256];
+ int len;
+
+ barlength = MIN(sizeof(buf) - 1, (unsigned)prog->ttywidth) - BAROVERHEAD - strlen(prog->prefix);
+ starc = (barlength * prog->percent) / 100;
+ abbrevsize = prog->done;
+ for (bytesabbrev = 0; abbrevsize >= 100000 && bytesabbrev < NSUFFIXES; bytesabbrev++) {
+ abbrevsize >>= 10;
+ }
+ if (bytesabbrev == NSUFFIXES) {
+ bytesabbrev--;
+ }
+ bytespersec = 0;
+ if (prog->done > 0) {
+ bytespersec = prog->done;
+ if (prog->elapsed > 0) {
+ bytespersec /= prog->elapsed;
+ }
+ }
+ for (bpsabbrev = 1; bytespersec >= 1024000 && bpsabbrev < NSUFFIXES; bpsabbrev++) {
+ bytespersec >>= 10;
+ }
+ if (prog->done == 0 || prog->elapsed <= 0 || prog->done > prog->size) {
+ secsleft = 0;
+ } else {
+ secsleft = prog->eta;
+ }
+ if ((secs = secsleft / SECSPERHOUR) > 0) {
+ (void) snprintf(hours, sizeof(hours), "%2lld:", (long long)secs);
+ } else {
+ (void) snprintf(hours, sizeof(hours), " ");
+ }
+ secs = secsleft % SECSPERHOUR;
+ len = snprintf(buf, sizeof(buf),
+ "\r%s %3lld%% |%.*s%*s| %5lld %-3s %3lld.%02d %.2sB/s %s%02d:%02d ETA",
+ (prog->prefix) ? prog->prefix : "",
+ (long long)prog->percent,
+ (int)starc, stars, (int)(barlength - starc), "",
+ (long long)abbrevsize,
+ suffixes[bytesabbrev],
+ (long long)(bytespersec / 1024),
+ (int)((bytespersec % 1024) * 100 / 1024),
+ suffixes[bpsabbrev],
+ hours,
+ (int)secs / 60, (int)secs % 60);
+ return (int)write(STDOUT_FILENO, buf, len);
+}
diff --git a/sbin/camcontrol/progress.h b/sbin/camcontrol/progress.h
new file mode 100644
index 000000000000..a457c328eb2b
--- /dev/null
+++ b/sbin/camcontrol/progress.h
@@ -0,0 +1,60 @@
+/* $NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1997-2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 PROGRESS_H_
+#define PROGRESS_H_ 20100228
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+
+/* structure used to display a progress meter */
+typedef struct progress_t {
+ char *prefix; /* any prefix explanation */
+ uint64_t size; /* total of bytes/units to be counted */
+ uint64_t done; /* number of units counted to date */
+ uint64_t percent; /* cache the percentage complete */
+ time_t start; /* time we started this */
+ time_t now; /* time now */
+ time_t eta; /* estimated # of secs until completion */
+ int64_t elapsed; /* cached # of elapsed seconds */
+ int32_t ttywidth; /* width of tty in columns */
+} progress_t;
+
+int progress_init(progress_t */*meter*/, const char */*prefix*/, uint64_t /*size*/);
+int progress_update(progress_t */*meter*/, uint64_t /*done*/);
+int progress_draw(progress_t */*meter*/);
+int progress_reset_size(progress_t */*meter*/, uint64_t /*size*/);
+int progress_complete(progress_t */*meter*/, uint64_t /*done*/);
+
+#endif
diff --git a/sbin/ccdconfig/ccdconfig.c b/sbin/ccdconfig/ccdconfig.c
index 6324150b0ff7..76867ba8ff07 100644
--- a/sbin/ccdconfig/ccdconfig.c
+++ b/sbin/ccdconfig/ccdconfig.c
@@ -288,13 +288,16 @@ do_all(int action)
rval = 0;
egid = getegid();
- setegid(getgid());
+ if (setegid(getgid()) != 0)
+ err(1, "setegid failed");
if ((f = fopen(ccdconf, "r")) == NULL) {
- setegid(egid);
+ if (setegid(egid) != 0)
+ err(1, "setegid failed");
warn("fopen: %s", ccdconf);
return (1);
}
- setegid(egid);
+ if (setegid(egid) != 0)
+ err(1, "setegid failed");
while (fgets(line, sizeof(line), f) != NULL) {
argc = 0;
diff --git a/sbin/ddb/ddb.c b/sbin/ddb/ddb.c
index 901d494aa28a..edba7f8509a5 100644
--- a/sbin/ddb/ddb.c
+++ b/sbin/ddb/ddb.c
@@ -80,7 +80,7 @@ ddb_readfile(char *filename)
argc++;
spn = strcspn(argv[0], WHITESP);
- argv[1] = argv[0] + spn + strspn(argv[0] + spn, WHITESP);;
+ argv[1] = argv[0] + spn + strspn(argv[0] + spn, WHITESP);
argv[0][spn] = '\0';
if (*argv[1] != '\0')
argc++;
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index 453d3df35b81..772471985a13 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -855,11 +855,9 @@ event_loop(void)
timeval tv;
fd_set fds;
- fd = open(PATH_DEVCTL, O_RDONLY);
+ fd = open(PATH_DEVCTL, O_RDONLY | O_CLOEXEC);
if (fd == -1)
err(1, "Can't open devctl device %s", PATH_DEVCTL);
- if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0)
- err(1, "Can't set close-on-exec flag on devctl");
server_fd = create_socket(PIPE);
max_fd = max(fd, server_fd) + 1;
while (1) {
diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5
index 944bdbbcef8e..4c1893d366f7 100644
--- a/sbin/devd/devd.conf.5
+++ b/sbin/devd/devd.conf.5
@@ -323,6 +323,8 @@ Button state ($notify=0x00 is power, 0x01 is sleep).
Battery events.
.It Li Lid
Lid state ($notify=0x00 is closed, 0x01 is open).
+.It Li PROCESSOR
+Processor state/configuration ($notify=0x81 is a change in available Cx states).
.It Li Thermal
Thermal zone events.
.El
diff --git a/sbin/devfs/devfs.8 b/sbin/devfs/devfs.8
index aa2f81abd239..8c41b13f37d6 100644
--- a/sbin/devfs/devfs.8
+++ b/sbin/devfs/devfs.8
@@ -52,7 +52,7 @@ most of the commands related to the rule subsystem must be preceded by the
.Cm rule
keyword.
The following flags are common to all keywords:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
.It Fl m Ar mount-point
Operate on
.Ar mount-point ,
@@ -88,7 +88,7 @@ Rule manipulation commands follow the
.Cm rule
keyword.
The following flags are common to all of the rule manipulation commands:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
.It Fl s Ar ruleset
Operate on the ruleset with the number
.Ar ruleset .
@@ -98,7 +98,7 @@ specified mount-point.
.El
.Pp
The following commands are recognized:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
.It Cm rule add Oo Ar rulenum Oc Ar rulespec
Add the rule described by
.Ar rulespec
@@ -156,7 +156,7 @@ is ignored.
The following conditions are recognized.
Conditions are ANDed together when matching a device;
if OR is desired, multiple rules can be written.
-.Bl -tag -offset indent
+.Bl -tag -width 15n
.It Cm path Ar pattern
Matches any node with a path that matches
.Ar pattern ,
@@ -175,7 +175,7 @@ and
The following actions are recognized.
Although there is no explicit delimiter between conditions and actions,
they may not be intermixed.
-.Bl -tag -offset indent
+.Bl -tag -width 15n
.It Cm group Ar gid
Set the GID of the node to
.Ar gid ,
@@ -238,7 +238,7 @@ will return the same information regardless of the mount-point specified with
The mount-point is only relevant when changing what its current ruleset is
or when using one of the apply commands.
.Sh FILES
-.Bl -tag -compact
+.Bl -tag -width "Pa /usr/share/examples/etc/devfs.conf" -compact
.It Pa /etc/defaults/devfs.rules
Default
.Nm
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 4f2405a3409e..f71c8c836050 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -218,6 +218,7 @@ routehandler(struct protocol *p)
struct sockaddr *sa;
struct iaddr a;
ssize_t n;
+ int linkstat;
n = read(routefd, &msg, sizeof(msg));
rtm = (struct rt_msghdr *)msg;
@@ -278,6 +279,15 @@ routehandler(struct protocol *p)
ifi->name);
goto die;
}
+ linkstat = interface_link_status(ifi->name);
+ if (linkstat != ifi->linkstat) {
+ debug("%s link state %s -> %s", ifi->name,
+ ifi->linkstat ? "up" : "down",
+ linkstat ? "up" : "down");
+ ifi->linkstat = linkstat;
+ if (linkstat)
+ state_reboot(ifi);
+ }
break;
case RTM_IFANNOUNCE:
ifan = (struct if_announcemsghdr *)rtm;
@@ -430,6 +440,7 @@ main(int argc, char *argv[])
}
fprintf(stderr, " got link\n");
}
+ ifi->linkstat = 1;
if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1)
error("cannot open %s: %m", _PATH_DEVNULL);
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index 1334a7c4a055..4762cbd05f86 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -208,6 +208,7 @@ struct interface_info {
int errors;
int dead;
u_int16_t index;
+ int linkstat;
};
struct timeout {
diff --git a/sbin/dump/traverse.c b/sbin/dump/traverse.c
index f593244f40d1..8258f079c0ed 100644
--- a/sbin/dump/traverse.c
+++ b/sbin/dump/traverse.c
@@ -197,8 +197,8 @@ mapfiles(ino_t maxino, long *tapesize)
(mode & IFMT) == 0)
continue;
if (ino >= maxino) {
- msg("Skipping inode %d >= maxino %d\n",
- ino, maxino);
+ msg("Skipping inode %ju >= maxino %ju\n",
+ (uintmax_t)ino, (uintmax_t)maxino);
continue;
}
/*
@@ -400,15 +400,16 @@ searchdir(
for (loc = 0; loc < size; ) {
dp = (struct direct *)(dblk + loc);
if (dp->d_reclen == 0) {
- msg("corrupted directory, inumber %d\n", ino);
+ msg("corrupted directory, inumber %ju\n",
+ (uintmax_t)ino);
break;
}
loc += dp->d_reclen;
if (dp->d_ino == 0)
continue;
if (dp->d_ino >= maxino) {
- msg("corrupted directory entry, d_ino %d >= %d\n",
- dp->d_ino, maxino);
+ msg("corrupted directory entry, d_ino %ju >= %ju\n",
+ (uintmax_t)dp->d_ino, (uintmax_t)maxino);
break;
}
if (dp->d_name[0] == '.') {
diff --git a/sbin/dumpfs/dumpfs.c b/sbin/dumpfs/dumpfs.c
index 2926d1ad90fc..a41ca4dda719 100644
--- a/sbin/dumpfs/dumpfs.c
+++ b/sbin/dumpfs/dumpfs.c
@@ -277,8 +277,9 @@ dumpfs(const char *name)
printf("unknown flags (%#x)", fsflags);
putchar('\n');
printf("fsmnt\t%s\n", afs.fs_fsmnt);
- printf("volname\t%s\tswuid\t%ju\n",
- afs.fs_volname, (uintmax_t)afs.fs_swuid);
+ printf("volname\t%s\tswuid\t%ju\tprovidersize\t%ju\n",
+ afs.fs_volname, (uintmax_t)afs.fs_swuid,
+ (uintmax_t)afs.fs_providersize);
printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
afs.fs_csp = calloc(1, afs.fs_cssize);
if (bread(&disk, fsbtodb(&afs, afs.fs_csaddr), afs.fs_csp, afs.fs_cssize) == -1)
@@ -419,6 +420,8 @@ marshal(const char *name)
/* -i is dumb */
if (fs->fs_flags & FS_SUJ)
printf("-j ");
+ if (fs->fs_flags & FS_GJOURNAL)
+ printf("-J ");
/* -k..l unimplemented */
printf("-m %d ", fs->fs_minfree);
/* -n unimplemented */
diff --git a/sbin/dumpon/dumpon.8 b/sbin/dumpon/dumpon.8
index ff47bcb19479..2c09e85cda85 100644
--- a/sbin/dumpon/dumpon.8
+++ b/sbin/dumpon/dumpon.8
@@ -41,6 +41,9 @@
.Nm
.Op Fl v
.Cm off
+.Nm
+.Op Fl v
+.Fl l
.Sh DESCRIPTION
The
.Nm
@@ -72,6 +75,13 @@ total amount of physical memory as reported by the
variable.
.Pp
The
+.Fl l
+flag causes
+.Nm
+to print the current dump device or _PATH_DEVNULL ("/dev/null") if no device is
+configured.
+.Pp
+The
.Fl v
flag causes
.Nm
diff --git a/sbin/dumpon/dumpon.c b/sbin/dumpon/dumpon.c
index 73d46b00eb3c..eebcc694e68d 100644
--- a/sbin/dumpon/dumpon.c
+++ b/sbin/dumpon/dumpon.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <err.h>
+#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdint.h>
@@ -60,9 +61,10 @@ static int verbose;
static void
usage(void)
{
- fprintf(stderr, "%s\n%s\n",
+ fprintf(stderr, "%s\n%s\n%s\n",
"usage: dumpon [-v] special_file",
- " dumpon [-v] off");
+ " dumpon [-v] off",
+ " dumpon [-v] -l");
exit(EX_USAGE);
}
@@ -92,15 +94,45 @@ check_size(int fd, const char *fn)
}
}
+static void
+listdumpdev(void)
+{
+ char dumpdev[PATH_MAX];
+ size_t len;
+ const char *sysctlname = "kern.shutdown.dumpdevname";
+
+ len = sizeof(dumpdev);
+ if (sysctlbyname(sysctlname, &dumpdev, &len, NULL, 0) != 0) {
+ if (errno == ENOMEM) {
+ err(EX_OSERR, "Kernel returned too large of a buffer for '%s'\n",
+ sysctlname);
+ } else {
+ err(EX_OSERR, "Sysctl get '%s'\n", sysctlname);
+ }
+ }
+ if (verbose) {
+ printf("kernel dumps on ");
+ }
+ if (strlen(dumpdev) == 0) {
+ printf("%s\n", _PATH_DEVNULL);
+ } else {
+ printf("%s\n", dumpdev);
+ }
+}
+
int
main(int argc, char *argv[])
{
int ch;
int i, fd;
u_int u;
+ int do_listdumpdev = 0;
- while ((ch = getopt(argc, argv, "v")) != -1)
+ while ((ch = getopt(argc, argv, "lv")) != -1)
switch((char)ch) {
+ case 'l':
+ do_listdumpdev = 1;
+ break;
case 'v':
verbose = 1;
break;
@@ -111,6 +143,11 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
+ if (do_listdumpdev) {
+ listdumpdev();
+ exit(EX_OK);
+ }
+
if (argc != 1)
usage();
diff --git a/sbin/etherswitchcfg/etherswitchcfg.c b/sbin/etherswitchcfg/etherswitchcfg.c
index e6129f3e4ad3..ea2cec8bd7e7 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.c
+++ b/sbin/etherswitchcfg/etherswitchcfg.c
@@ -79,7 +79,7 @@ struct cmds {
int args;
void (*f)(struct cfg *, char *argv[]);
};
-struct cmds cmds[];
+static struct cmds cmds[];
static void usage(void);
@@ -501,7 +501,7 @@ main(int argc, char *argv[])
return (0);
}
-struct cmds cmds[] = {
+static struct cmds cmds[] = {
{ MODE_PORT, "vlangroup", 1, set_port_vlangroup },
{ MODE_PORT, "media", 1, set_port_media },
{ MODE_PORT, "mediaopt", 1, set_port_mediaopt },
diff --git a/sbin/etherswitchcfg/ifmedia.c b/sbin/etherswitchcfg/ifmedia.c
index 258c3d5b9ed3..b9bd3b9c56ff 100644
--- a/sbin/etherswitchcfg/ifmedia.c
+++ b/sbin/etherswitchcfg/ifmedia.c
@@ -396,10 +396,10 @@ static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
-struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
-struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
static struct ifmedia_description ifm_subtype_atm_descriptions[] =
diff --git a/sbin/fsck/Makefile b/sbin/fsck/Makefile
index bc445fda26f7..22de03c4da78 100644
--- a/sbin/fsck/Makefile
+++ b/sbin/fsck/Makefile
@@ -3,7 +3,6 @@
PROG= fsck
SRCS= fsck.c fsutil.c preen.c
-WARNS?= 2
MAN= fsck.8
.include <bsd.prog.mk>
diff --git a/sbin/fsck/fsck.c b/sbin/fsck/fsck.c
index 768e670d6672..6bc702e90280 100644
--- a/sbin/fsck/fsck.c
+++ b/sbin/fsck/fsck.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fsck.c,v 1.21 1999/04/22 04:20:53 abs Exp $ */
+/* $NetBSD: fsck.c,v 1.30 2003/08/07 10:04:15 agc Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
@@ -13,11 +13,7 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -35,7 +31,7 @@
*
* From: @(#)mount.c 8.19 (Berkeley) 4/19/94
* From: $NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
- * $NetBSD: fsck.c,v 1.21 1999/04/22 04:20:53 abs Exp $
+ * $NetBSD: fsck.c,v 1.30 2003/08/07 10:04:15 agc Exp $
*/
#include <sys/cdefs.h>
@@ -77,14 +73,14 @@ static char *options = NULL;
static int flags = 0;
static int forceflag = 0;
-static int checkfs(const char *, const char *, const char *, char *, pid_t *);
+static int checkfs(const char *, const char *, const char *, const char *, pid_t *);
static int selected(const char *);
static void addoption(char *);
static const char *getoptions(const char *);
static void addentry(struct fstypelist *, const char *, const char *);
static void maketypelist(char *);
static void catopt(char **, const char *);
-static void mangle(char *, int *, const char ***, int *);
+static void mangle(char *, int *, const char ** volatile *, int *);
static const char *getfslab(const char *);
static void usage(void) __dead2;
static int isok(struct fstab *);
@@ -191,6 +187,7 @@ main(int argc, char *argv[])
char device[MAXPATHLEN];
struct statfs *mntp;
+ mntpt = NULL;
spec = *argv;
cp = strrchr(spec, '/');
if (cp == 0) {
@@ -289,9 +286,9 @@ isok(struct fstab *fs)
static int
checkfs(const char *pvfstype, const char *spec, const char *mntpt,
- char *auxopt, pid_t *pidp)
+ const char *auxopt, pid_t *pidp)
{
- const char **argv;
+ const char ** volatile argv;
pid_t pid;
int argc, i, status, maxargc;
char *optbuf, execbase[MAXPATHLEN];
@@ -315,8 +312,8 @@ checkfs(const char *pvfstype, const char *spec, const char *mntpt,
*/
vfstype = strdup(pvfstype);
if (vfstype == NULL)
- perror("strdup(pvfstype)");
- for (i = 0; i < strlen(vfstype); i++) {
+ perr("strdup(pvfstype)");
+ for (i = 0; i < (int)strlen(vfstype); i++) {
vfstype[i] = tolower(vfstype[i]);
if (vfstype[i] == ' ')
vfstype[i] = '_';
@@ -365,7 +362,7 @@ checkfs(const char *pvfstype, const char *spec, const char *mntpt,
_exit(0);
/* Go find an executable. */
- execvP(execbase, _PATH_SYSPATH, (char * const *)argv);
+ execvP(execbase, _PATH_SYSPATH, __DECONST(char * const *, argv));
if (spec)
warn("exec %s for %s in %s", execbase, spec, _PATH_SYSPATH);
else
@@ -502,7 +499,7 @@ catopt(char **sp, const char *o)
static void
-mangle(char *options, int *argcp, const char ***argvp, int *maxargcp)
+mangle(char *opts, int *argcp, const char ** volatile *argvp, int *maxargcp)
{
char *p, *s;
int argc, maxargc;
@@ -512,7 +509,7 @@ mangle(char *options, int *argcp, const char ***argvp, int *maxargcp)
argv = *argvp;
maxargc = *maxargcp;
- for (s = options; (p = strsep(&s, ",")) != NULL;) {
+ for (s = opts; (p = strsep(&s, ",")) != NULL;) {
/* Always leave space for one more argument and the NULL. */
if (argc >= maxargc - 3) {
maxargc <<= 1;
@@ -539,7 +536,7 @@ mangle(char *options, int *argcp, const char ***argvp, int *maxargcp)
}
-const static char *
+static const char *
getfslab(const char *str)
{
struct disklabel dl;
diff --git a/sbin/fsck/fsutil.c b/sbin/fsck/fsutil.c
index a4578bd63eb6..935992e9bda4 100644
--- a/sbin/fsck/fsutil.c
+++ b/sbin/fsck/fsutil.c
@@ -1,4 +1,4 @@
-/* $NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej Exp $ */
+/* $NetBSD: fsutil.c,v 1.15 2006/06/05 16:52:05 christos Exp $ */
/*
* Copyright (c) 1990, 1993
@@ -12,7 +12,7 @@
* 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.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej Exp $");
+__RCSID("$NetBSD: fsutil.c,v 1.15 2006/06/05 16:52:05 christos Exp $");
#endif /* not lint */
__FBSDID("$FreeBSD$");
@@ -110,9 +110,13 @@ pwarn(const char *fmt, ...)
}
void
-perror(const char *s)
+perr(const char *fmt, ...)
{
- pfatal("%s (%s)", s, strerror(errno));
+ va_list ap;
+
+ va_start(ap, fmt);
+ vmsg(1, fmt, ap);
+ va_end(ap);
}
void
@@ -132,18 +136,15 @@ devcheck(const char *origname)
struct stat stslash, stchar;
if (stat("/", &stslash) < 0) {
- perror("/");
- printf("Can't stat root\n");
+ perr("Can't stat `/'");
return (origname);
}
if (stat(origname, &stchar) < 0) {
- perror(origname);
- printf("Can't stat %s\n", origname);
+ perr("Can't stat %s\n", origname);
return (origname);
}
if (!S_ISCHR(stchar.st_mode)) {
- perror(origname);
- printf("%s is not a char device\n", origname);
+ perr("%s is not a char device\n", origname);
}
return (origname);
}
@@ -156,7 +157,7 @@ getmntpt(const char *name)
{
struct stat devstat, mntdevstat;
char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
- char *devname;
+ char *dev_name;
struct statfs *mntbuf, *statfsp;
int i, mntsize, isdev;
@@ -169,10 +170,10 @@ getmntpt(const char *name)
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
for (i = 0; i < mntsize; i++) {
statfsp = &mntbuf[i];
- devname = statfsp->f_mntfromname;
- if (*devname != '/') {
+ dev_name = statfsp->f_mntfromname;
+ if (*dev_name != '/') {
strcpy(device, _PATH_DEV);
- strcat(device, devname);
+ strcat(device, dev_name);
strcpy(statfsp->f_mntfromname, device);
}
if (isdev == 0) {
@@ -180,7 +181,7 @@ getmntpt(const char *name)
continue;
return (statfsp);
}
- if (stat(devname, &mntdevstat) == 0 &&
+ if (stat(dev_name, &mntdevstat) == 0 &&
mntdevstat.st_rdev == devstat.st_rdev)
return (statfsp);
}
diff --git a/sbin/fsck/fsutil.h b/sbin/fsck/fsutil.h
index 657668ede4ce..013b821b29d0 100644
--- a/sbin/fsck/fsutil.h
+++ b/sbin/fsck/fsutil.h
@@ -1,4 +1,4 @@
-/* $NetBSD: fsutil.h,v 1.4 1998/07/26 20:02:36 mycroft Exp $ */
+/* $NetBSD: fsutil.h,v 1.114 2009/10/21 01:07:46 snj Exp $ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
@@ -11,11 +11,6 @@
* 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.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christos Zoulas.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -31,9 +26,9 @@
* $FreeBSD$
*/
-void perror(const char *);
void pfatal(const char *, ...) __printflike(1, 2);
void pwarn(const char *, ...) __printflike(1, 2);
+void perr(const char *, ...) __printflike(1, 2);
void panic(const char *, ...) __dead2 __printflike(1, 2);
const char *devcheck(const char *);
const char *cdevname(void);
@@ -52,4 +47,4 @@ char *estrdup(const char *);
struct fstab;
int checkfstab(int, int (*)(struct fstab *),
- int (*) (const char *, const char *, const char *, char *, pid_t *));
+ int (*) (const char *, const char *, const char *, const char *, pid_t *));
diff --git a/sbin/fsck/preen.c b/sbin/fsck/preen.c
index 787bed0e2713..18f280197895 100644
--- a/sbin/fsck/preen.c
+++ b/sbin/fsck/preen.c
@@ -78,12 +78,12 @@ static int nrun = 0, ndisks = 0;
static struct diskentry *finddisk(const char *);
static void addpart(const char *, const char *, const char *);
static int startdisk(struct diskentry *,
- int (*)(const char *, const char *, const char *, char *, pid_t *));
+ int (*)(const char *, const char *, const char *, const char *, pid_t *));
static void printpart(void);
int
checkfstab(int flags, int (*docheck)(struct fstab *),
- int (*checkit)(const char *, const char *, const char *, char *, pid_t *))
+ int (*checkit)(const char *, const char *, const char *, const char *, pid_t *))
{
struct fstab *fs;
struct diskentry *d, *nextdisk;
@@ -295,19 +295,19 @@ printpart(void)
static void
-addpart(const char *type, const char *devname, const char *mntpt)
+addpart(const char *type, const char *dev, const char *mntpt)
{
- struct diskentry *d = finddisk(devname);
+ struct diskentry *d = finddisk(dev);
struct partentry *p;
TAILQ_FOREACH(p, &d->d_part, p_entries)
- if (strcmp(p->p_devname, devname) == 0) {
- warnx("%s in fstab more than once!\n", devname);
+ if (strcmp(p->p_devname, dev) == 0) {
+ warnx("%s in fstab more than once!\n", dev);
return;
}
p = emalloc(sizeof(*p));
- p->p_devname = estrdup(devname);
+ p->p_devname = estrdup(dev);
p->p_mntpt = estrdup(mntpt);
p->p_type = estrdup(type);
@@ -317,7 +317,7 @@ addpart(const char *type, const char *devname, const char *mntpt)
static int
startdisk(struct diskentry *d, int (*checkit)(const char *, const char *,
- const char *, char *, pid_t *))
+ const char *, const char *, pid_t *))
{
struct partentry *p = TAILQ_FIRST(&d->d_part);
int rv;
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 6ac004e4fb52..4717760acad9 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -337,7 +337,7 @@ void blkerror(ino_t ino, const char *type, ufs2_daddr_t blk);
char *blockcheck(char *name);
int blread(int fd, char *buf, ufs2_daddr_t blk, long size);
void bufinit(void);
-void blwrite(int fd, char *buf, ufs2_daddr_t blk, long size);
+void blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size);
void blerase(int fd, ufs2_daddr_t blk, long size);
void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 59b73c81ad21..9bf61d136333 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -137,7 +137,8 @@ inoinfo(ino_t inum)
int iloff;
if (inum > maxino)
- errx(EEXIT, "inoinfo: inumber %d out of range", inum);
+ errx(EEXIT, "inoinfo: inumber %ju out of range",
+ (uintmax_t)inum);
ilp = &inostathead[inum / sblock.fs_ipg];
iloff = inum % sblock.fs_ipg;
if (iloff >= ilp->il_numalloced)
@@ -245,7 +246,7 @@ flush(int fd, struct bufarea *bp)
(bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
(long long)bp->b_bno);
bp->b_errs = 0;
- blwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
+ blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size);
if (bp != &sblk)
return;
for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
@@ -392,7 +393,7 @@ blread(int fd, char *buf, ufs2_daddr_t blk, long size)
}
void
-blwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
+blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size)
{
int i;
char *cp;
@@ -404,7 +405,7 @@ blwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
offset *= dev_bsize;
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK BLK", blk);
- else if (write(fd, buf, (int)size) == size) {
+ else if (write(fd, buf, size) == size) {
fsmodified = 1;
return;
}
@@ -414,7 +415,7 @@ blwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
rwerror("SEEK BLK", blk);
printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
- if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
+ if (write(fd, cp, dev_bsize) != dev_bsize) {
(void)lseek(fd, offset + i + dev_bsize, 0);
printf(" %jd,", (intmax_t)blk + i / dev_bsize);
}
diff --git a/sbin/fsck_ffs/gjournal.c b/sbin/fsck_ffs/gjournal.c
index e8ecaf0c1bbf..ba8dc3416a96 100644
--- a/sbin/fsck_ffs/gjournal.c
+++ b/sbin/fsck_ffs/gjournal.c
@@ -448,7 +448,8 @@ gjournal_check(const char *filesys)
if (isclr(inosused, cino))
continue;
if (getino(disk, &p, ino, &mode) == -1)
- err(1, "getino(cg=%d ino=%d)", cg, ino);
+ err(1, "getino(cg=%d ino=%ju)",
+ cg, (uintmax_t)ino);
dino = p;
/* Not a regular file nor directory? Skip it. */
if (!S_ISREG(dino->di_mode) && !S_ISDIR(dino->di_mode))
@@ -480,7 +481,8 @@ gjournal_check(const char *filesys)
*dino = ufs2_zino;
/* Write the inode back. */
if (putino(disk) == -1)
- err(1, "putino(cg=%d ino=%d)", cg, ino);
+ err(1, "putino(cg=%d ino=%ju)",
+ cg, (uintmax_t)ino);
if (cgp->cg_unrefs == 0) {
//printf("No more unreferenced inodes in cg=%d.\n", cg);
break;
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 4ef70fce3d55..389150a3d5f2 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -285,7 +285,8 @@ ginode(ino_t inumber)
ufs2_daddr_t iblk;
if (inumber < ROOTINO || inumber > maxino)
- errx(EEXIT, "bad inode number %d to ginode", inumber);
+ errx(EEXIT, "bad inode number %ju to ginode",
+ (uintmax_t)inumber);
if (startinum == 0 ||
inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
iblk = ino_to_fsba(&sblock, inumber);
@@ -319,7 +320,8 @@ getnextinode(ino_t inumber, int rebuildcg)
static caddr_t nextinop;
if (inumber != nextino++ || inumber > lastvalidinum)
- errx(EEXIT, "bad inode number %d to nextinode", inumber);
+ errx(EEXIT, "bad inode number %ju to nextinode",
+ (uintmax_t)inumber);
if (inumber >= lastinum) {
readcnt++;
dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
@@ -398,7 +400,8 @@ setinodebuf(ino_t inum)
{
if (inum % sblock.fs_ipg != 0)
- errx(EEXIT, "bad inode number %d to setinodebuf", inum);
+ errx(EEXIT, "bad inode number %ju to setinodebuf",
+ (uintmax_t)inum);
lastvalidinum = inum + sblock.fs_ipg - 1;
startinum = 0;
nextino = inum;
@@ -489,7 +492,7 @@ getinoinfo(ino_t inumber)
continue;
return (inp);
}
- errx(EEXIT, "cannot find inode %d", inumber);
+ errx(EEXIT, "cannot find inode %ju", (uintmax_t)inumber);
return ((struct inoinfo *)0);
}
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 37258f73ed01..69f157ab195e 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -210,12 +210,11 @@ checkfilesys(char *filesys)
struct statfs *mntp;
struct stat snapdir;
struct group *grp;
- ufs2_daddr_t blks;
struct iovec *iov;
char errmsg[255];
int iovlen;
int cylno;
- ino_t files;
+ intmax_t blks, files;
size_t size;
iov = NULL;
@@ -279,8 +278,8 @@ checkfilesys(char *filesys)
exit(0);
exit(4);
} else {
- pfatal("UNEXPECTED INCONSISTENCY, %s\n",
- "CANNOT RUN FAST FSCK\n");
+ pfatal(
+ "UNEXPECTED INCONSISTENCY, CANNOT RUN FAST FSCK\n");
}
}
}
@@ -297,8 +296,8 @@ checkfilesys(char *filesys)
pfatal("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n");
} else if ((mntp->f_flags & MNT_SOFTDEP) == 0) {
bkgrdflag = 0;
- pfatal("NOT USING SOFT UPDATES, %s\n",
- "CANNOT RUN IN BACKGROUND");
+ pfatal(
+ "NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n");
} else if ((mntp->f_flags & MNT_RDONLY) != 0) {
bkgrdflag = 0;
pfatal("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n");
@@ -306,8 +305,8 @@ checkfilesys(char *filesys)
if (readsb(0) != 0) {
if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) {
bkgrdflag = 0;
- pfatal("UNEXPECTED INCONSISTENCY, %s\n",
- "CANNOT RUN IN BACKGROUND\n");
+ pfatal(
+ "UNEXPECTED INCONSISTENCY, CANNOT RUN IN BACKGROUND\n");
}
if ((sblock.fs_flags & FS_UNCLEAN) == 0 &&
skipclean && ckclean) {
@@ -315,8 +314,8 @@ checkfilesys(char *filesys)
* file system is clean;
* skip snapshot and report it clean
*/
- pwarn("FILE SYSTEM CLEAN; %s\n",
- "SKIPPING CHECKS");
+ pwarn(
+ "FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
goto clean;
}
}
@@ -328,24 +327,23 @@ checkfilesys(char *filesys)
if (stat(snapname, &snapdir) < 0) {
if (errno != ENOENT) {
bkgrdflag = 0;
- pfatal("CANNOT FIND %s %s: %s, %s\n",
- "SNAPSHOT DIRECTORY",
- snapname, strerror(errno),
- "CANNOT RUN IN BACKGROUND");
+ pfatal(
+ "CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n",
+ snapname, strerror(errno));
} else if ((grp = getgrnam("operator")) == 0 ||
mkdir(snapname, 0770) < 0 ||
chown(snapname, -1, grp->gr_gid) < 0 ||
chmod(snapname, 0770) < 0) {
bkgrdflag = 0;
- pfatal("CANNOT CREATE %s %s: %s, %s\n",
- "SNAPSHOT DIRECTORY",
- snapname, strerror(errno),
- "CANNOT RUN IN BACKGROUND");
+ pfatal(
+ "CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n",
+ snapname, strerror(errno));
}
} else if (!S_ISDIR(snapdir.st_mode)) {
bkgrdflag = 0;
- pfatal("%s IS NOT A DIRECTORY, %s\n", snapname,
- "CANNOT RUN IN BACKGROUND");
+ pfatal(
+ "%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n",
+ snapname);
}
}
if (bkgrdflag) {
@@ -383,9 +381,9 @@ checkfilesys(char *filesys)
clean:
pwarn("clean, %ld free ", (long)(sblock.fs_cstotal.cs_nffree +
sblock.fs_frag * sblock.fs_cstotal.cs_nbfree));
- printf("(%lld frags, %lld blocks, %.1f%% fragmentation)\n",
- (long long)sblock.fs_cstotal.cs_nffree,
- (long long)sblock.fs_cstotal.cs_nbfree,
+ printf("(%jd frags, %jd blocks, %.1f%% fragmentation)\n",
+ (intmax_t)sblock.fs_cstotal.cs_nffree,
+ (intmax_t)sblock.fs_cstotal.cs_nbfree,
sblock.fs_cstotal.cs_nffree * 100.0 / sblock.fs_dsize);
return (0);
}
@@ -482,8 +480,8 @@ checkfilesys(char *filesys)
blks = maxfsblock - (n_ffree + sblock.fs_frag * n_bfree) - blks;
if (bkgrdflag && (files > 0 || blks > 0)) {
countdirs = sblock.fs_cstotal.cs_ndir - countdirs;
- pwarn("Reclaimed: %ld directories, %ld files, %lld fragments\n",
- countdirs, (long)files - countdirs, (long long)blks);
+ pwarn("Reclaimed: %ld directories, %jd files, %jd fragments\n",
+ countdirs, files - countdirs, blks);
}
pwarn("%ld files, %jd used, %ju free ",
(long)n_files, (intmax_t)n_blks,
@@ -493,13 +491,13 @@ checkfilesys(char *filesys)
n_ffree * 100.0 / sblock.fs_dsize);
if (debug) {
if (files < 0)
- printf("%d inodes missing\n", -files);
+ printf("%jd inodes missing\n", -files);
if (blks < 0)
- printf("%lld blocks missing\n", -(long long)blks);
+ printf("%jd blocks missing\n", -blks);
if (duplist != NULL) {
printf("The following duplicate blocks remain:");
for (dp = duplist; dp; dp = dp->next)
- printf(" %lld,", (long long)dp->dup);
+ printf(" %jd,", (intmax_t)dp->dup);
printf("\n");
}
}
@@ -636,8 +634,7 @@ static void
usage(void)
{
(void) fprintf(stderr,
- "usage: %s [-BEFfnpry] [-b block] [-c level] [-m mode] "
- "filesystem ...\n",
+"usage: %s [-BEFfnpry] [-b block] [-c level] [-m mode] filesystem ...\n",
getprogname());
exit(1);
}
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index fa30bb2018ca..08e84b94aff1 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -99,10 +99,10 @@ pass1(void)
if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
inosused = cgrp.cg_initediblk;
if (inosused > sblock.fs_ipg) {
- pfatal("%s (%d > %d) %s %d\nReset to %d\n",
- "Too many initialized inodes", inosused,
- sblock.fs_ipg, "in cylinder group", c,
- sblock.fs_ipg);
+ pfatal(
+"Too many initialized inodes (%ju > %d) in cylinder group %d\nReset to %d\n",
+ (uintmax_t)inosused,
+ sblock.fs_ipg, c, sblock.fs_ipg);
inosused = sblock.fs_ipg;
}
} else {
diff --git a/sbin/fsck_ffs/pass2.c b/sbin/fsck_ffs/pass2.c
index bd9bf97e92c8..82c3b947fc63 100644
--- a/sbin/fsck_ffs/pass2.c
+++ b/sbin/fsck_ffs/pass2.c
@@ -223,13 +223,14 @@ pass2(void)
* inp->i_parent is directory to which ".." should point.
*/
getpathname(pathbuf, inp->i_parent, inp->i_number);
- printf("BAD INODE NUMBER FOR '..' in DIR I=%d (%s)\n",
- inp->i_number, pathbuf);
+ printf("BAD INODE NUMBER FOR '..' in DIR I=%ju (%s)\n",
+ (uintmax_t)inp->i_number, pathbuf);
getpathname(pathbuf, inp->i_dotdot, inp->i_dotdot);
- printf("CURRENTLY POINTS TO I=%d (%s), ", inp->i_dotdot,
- pathbuf);
+ printf("CURRENTLY POINTS TO I=%ju (%s), ",
+ (uintmax_t)inp->i_dotdot, pathbuf);
getpathname(pathbuf, inp->i_parent, inp->i_parent);
- printf("SHOULD POINT TO I=%d (%s)", inp->i_parent, pathbuf);
+ printf("SHOULD POINT TO I=%ju (%s)",
+ (uintmax_t)inp->i_parent, pathbuf);
if (cursnapshot != 0) {
/*
* We need to:
@@ -443,8 +444,8 @@ again:
} else {
getpathname(dirname, idesc->id_number,
dirp->d_ino);
- pwarn("ZERO LENGTH DIRECTORY %s I=%d",
- dirname, dirp->d_ino);
+ pwarn("ZERO LENGTH DIRECTORY %s I=%ju",
+ dirname, (uintmax_t)dirp->d_ino);
/*
* We need to:
* setcwd(idesc->id_parent);
@@ -507,8 +508,9 @@ again:
break;
default:
- errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
- inoinfo(dirp->d_ino)->ino_state, dirp->d_ino);
+ errx(EEXIT, "BAD STATE %d FOR INODE I=%ju",
+ inoinfo(dirp->d_ino)->ino_state,
+ (uintmax_t)dirp->d_ino);
}
}
if (n == 0)
diff --git a/sbin/fsck_ffs/pass4.c b/sbin/fsck_ffs/pass4.c
index 4b2af7be89de..80a32c14b14c 100644
--- a/sbin/fsck_ffs/pass4.c
+++ b/sbin/fsck_ffs/pass4.c
@@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <ufs/ffs/fs.h>
#include <err.h>
+#include <stdint.h>
#include <string.h>
#include "fsck.h"
@@ -114,8 +115,9 @@ pass4(void)
break;
default:
- errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
- inoinfo(inumber)->ino_state, inumber);
+ errx(EEXIT, "BAD STATE %d FOR INODE I=%ju",
+ inoinfo(inumber)->ino_state,
+ (uintmax_t)inumber);
}
}
}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index b784519062b2..0800a5c7b6eb 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -831,8 +831,8 @@ ino_clrat(ino_t parent, off_t diroff, ino_t child)
int doff;
if (debug)
- printf("Clearing inode %d from parent %d at offset %jd\n",
- child, parent, diroff);
+ printf("Clearing inode %ju from parent %ju at offset %jd\n",
+ (uintmax_t)child, (uintmax_t)parent, diroff);
lbn = lblkno(fs, diroff);
doff = blkoff(fs, diroff);
@@ -842,8 +842,8 @@ ino_clrat(ino_t parent, off_t diroff, ino_t child)
block = dblk_read(blk, blksize);
dp = (struct direct *)&block[doff];
if (dp->d_ino != child)
- errx(1, "Inode %d does not exist in %d at %jd",
- child, parent, diroff);
+ errx(1, "Inode %ju does not exist in %ju at %jd",
+ (uintmax_t)child, (uintmax_t)parent, diroff);
dp->d_ino = 0;
dblk_dirty(blk);
/*
@@ -879,10 +879,11 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
* was reallocated.
*/
if (*mode != 0)
- printf("Directory %d has bad mode %o\n",
- parent, *mode);
+ printf("Directory %ju has bad mode %o\n",
+ (uintmax_t)parent, *mode);
else
- printf("Directory %d zero inode\n", parent);
+ printf("Directory %ju has zero mode\n",
+ (uintmax_t)parent);
}
return (0);
}
@@ -891,15 +892,16 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
blksize = sblksize(fs, DIP(dip, di_size), lbn);
if (diroff + DIRECTSIZ(1) > DIP(dip, di_size) || doff >= blksize) {
if (debug)
- printf("ino %d absent from %d due to offset %jd"
+ printf("ino %ju absent from %ju due to offset %jd"
" exceeding size %jd\n",
- child, parent, diroff, DIP(dip, di_size));
+ (uintmax_t)child, (uintmax_t)parent, diroff,
+ DIP(dip, di_size));
return (0);
}
blk = ino_blkatoff(dip, parent, lbn, &frags);
if (blk <= 0) {
if (debug)
- printf("Sparse directory %d", parent);
+ printf("Sparse directory %ju", (uintmax_t)parent);
return (0);
}
block = dblk_read(blk, blksize);
@@ -918,12 +920,13 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
dpoff += dp->d_reclen;
} while (dpoff <= doff);
if (dpoff > fs->fs_bsize)
- err_suj("Corrupt directory block in dir ino %d\n", parent);
+ err_suj("Corrupt directory block in dir ino %ju\n",
+ (uintmax_t)parent);
/* Not found. */
if (dpoff != doff) {
if (debug)
- printf("ino %d not found in %d, lbn %jd, dpoff %d\n",
- child, parent, lbn, dpoff);
+ printf("ino %ju not found in %ju, lbn %jd, dpoff %d\n",
+ (uintmax_t)child, (uintmax_t)parent, lbn, dpoff);
return (0);
}
/*
@@ -940,8 +943,8 @@ ino_isat(ino_t parent, off_t diroff, ino_t child, int *mode, int *isdot)
return (1);
}
if (debug)
- printf("ino %d doesn't match dirent ino %d in parent %d\n",
- child, dp->d_ino, parent);
+ printf("ino %ju doesn't match dirent ino %ju in parent %ju\n",
+ (uintmax_t)child, (uintmax_t)dp->d_ino, (uintmax_t)parent);
return (0);
}
@@ -977,8 +980,8 @@ indir_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, uint64_t *frags,
err_suj("Invalid level for lbn %jd\n", lbn);
if ((flags & VISIT_ROOT) == 0 && blk_isindir(blk, ino, lbn) == 0) {
if (debug)
- printf("blk %jd ino %d lbn %jd(%d) is not indir.\n",
- blk, ino, lbn, level);
+ printf("blk %jd ino %ju lbn %jd(%d) is not indir.\n",
+ blk, (uintmax_t)ino, lbn, level);
goto out;
}
lbnadd = 1;
@@ -1131,8 +1134,8 @@ ino_adjblks(struct suj_ino *sino)
if (blocks == DIP(ip, di_blocks))
return;
if (debug)
- printf("ino %d adjusting block count from %jd to %jd\n",
- ino, DIP(ip, di_blocks), blocks);
+ printf("ino %ju adjusting block count from %jd to %jd\n",
+ (uintmax_t)ino, DIP(ip, di_blocks), blocks);
DIP_SET(ip, di_blocks, blocks);
ino_dirty(ino);
}
@@ -1264,8 +1267,8 @@ ino_free_children(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags)
if (isdotdot && skipparent == 1)
continue;
if (debug)
- printf("Directory %d removing ino %d name %s\n",
- ino, dp->d_ino, dp->d_name);
+ printf("Directory %ju removing ino %ju name %s\n",
+ (uintmax_t)ino, (uintmax_t)dp->d_ino, dp->d_name);
diroff = lblktosize(fs, lbn) + dpoff;
ino_remref(ino, dp->d_ino, diroff, isdotdot);
}
@@ -1283,8 +1286,8 @@ ino_reclaim(union dinode *ip, ino_t ino, int mode)
if (ino == ROOTINO)
err_suj("Attempting to free ROOTINO\n");
if (debug)
- printf("Truncating and freeing ino %d, nlink %d, mode %o\n",
- ino, DIP(ip, di_nlink), DIP(ip, di_mode));
+ printf("Truncating and freeing ino %ju, nlink %d, mode %o\n",
+ (uintmax_t)ino, DIP(ip, di_nlink), DIP(ip, di_mode));
/* We are freeing an inode or directory. */
if ((DIP(ip, di_mode) & IFMT) == IFDIR)
@@ -1328,8 +1331,8 @@ ino_decr(ino_t ino)
reqlink = 1;
if (nlink < reqlink) {
if (debug)
- printf("ino %d not enough links to live %d < %d\n",
- ino, nlink, reqlink);
+ printf("ino %ju not enough links to live %d < %d\n",
+ (uintmax_t)ino, nlink, reqlink);
ino_reclaim(ip, ino, mode);
return;
}
@@ -1374,7 +1377,7 @@ ino_adjust(struct suj_ino *sino)
break;
}
if (srec == NULL)
- errx(1, "Directory %d name not found", ino);
+ errx(1, "Directory %ju name not found", (uintmax_t)ino);
}
/*
* If it's a directory with no real names pointing to it go ahead
@@ -1398,21 +1401,22 @@ ino_adjust(struct suj_ino *sino)
ip = ino_read(ino);
mode = DIP(ip, di_mode) & IFMT;
if (nlink > LINK_MAX)
- err_suj(
- "ino %d nlink manipulation error, new link %d, old link %d\n",
- ino, nlink, DIP(ip, di_nlink));
+ err_suj("ino %ju nlink manipulation error, new %d, old %d\n",
+ (uintmax_t)ino, nlink, DIP(ip, di_nlink));
if (debug)
- printf("Adjusting ino %d, nlink %d, old link %d lastmode %o\n",
- ino, nlink, DIP(ip, di_nlink), sino->si_mode);
+ printf("Adjusting ino %ju, nlink %d, old link %d lastmode %o\n",
+ (uintmax_t)ino, nlink, DIP(ip, di_nlink), sino->si_mode);
if (mode == 0) {
if (debug)
- printf("ino %d, zero inode freeing bitmap\n", ino);
+ printf("ino %ju, zero inode freeing bitmap\n",
+ (uintmax_t)ino);
ino_free(ino, sino->si_mode);
return;
}
/* XXX Should be an assert? */
if (mode != sino->si_mode && debug)
- printf("ino %d, mode %o != %o\n", ino, mode, sino->si_mode);
+ printf("ino %ju, mode %o != %o\n",
+ (uintmax_t)ino, mode, sino->si_mode);
if ((mode & IFMT) == IFDIR)
reqlink = 2;
else
@@ -1420,15 +1424,16 @@ ino_adjust(struct suj_ino *sino)
/* If the inode doesn't have enough links to live, free it. */
if (nlink < reqlink) {
if (debug)
- printf("ino %d not enough links to live %d < %d\n",
- ino, nlink, reqlink);
+ printf("ino %ju not enough links to live %d < %d\n",
+ (uintmax_t)ino, nlink, reqlink);
ino_reclaim(ip, ino, mode);
return;
}
/* If required write the updated link count. */
if (DIP(ip, di_nlink) == nlink) {
if (debug)
- printf("ino %d, link matches, skipping.\n", ino);
+ printf("ino %ju, link matches, skipping.\n",
+ (uintmax_t)ino);
return;
}
DIP_SET(ip, di_nlink, nlink);
@@ -1527,8 +1532,8 @@ ino_trunc(ino_t ino, off_t size)
mode = DIP(ip, di_mode) & IFMT;
cursize = DIP(ip, di_size);
if (debug)
- printf("Truncating ino %d, mode %o to size %jd from size %jd\n",
- ino, mode, size, cursize);
+ printf("Truncating ino %ju, mode %o to size %jd from size %jd\n",
+ (uintmax_t)ino, mode, size, cursize);
/* Skip datablocks for short links and devices. */
if (mode == 0 || mode == IFBLK || mode == IFCHR ||
@@ -1586,7 +1591,8 @@ ino_trunc(ino_t ino, off_t size)
bn = DIP(ip, di_db[visitlbn]);
if (bn == 0)
- err_suj("Bad blk at ino %d lbn %jd\n", ino, visitlbn);
+ err_suj("Bad blk at ino %ju lbn %jd\n",
+ (uintmax_t)ino, visitlbn);
oldspace = sblksize(fs, cursize, visitlbn);
newspace = sblksize(fs, size, visitlbn);
if (oldspace != newspace) {
@@ -1610,8 +1616,8 @@ ino_trunc(ino_t ino, off_t size)
bn = ino_blkatoff(ip, ino, visitlbn, &frags);
if (bn == 0)
- err_suj("Block missing from ino %d at lbn %jd\n",
- ino, visitlbn);
+ err_suj("Block missing from ino %ju at lbn %jd\n",
+ (uintmax_t)ino, visitlbn);
clrsize = frags * fs->fs_fsize;
buf = dblk_read(bn, clrsize);
clrsize -= off;
@@ -1656,11 +1662,11 @@ ino_check(struct suj_ino *sino)
err_suj("Inode mode/directory type mismatch %o != %o\n",
mode, rrec->jr_mode);
if (debug)
- printf("jrefrec: op %d ino %d, nlink %d, parent %d, "
+ printf("jrefrec: op %d ino %ju, nlink %d, parent %d, "
"diroff %jd, mode %o, isat %d, isdot %d\n",
- rrec->jr_op, rrec->jr_ino, rrec->jr_nlink,
- rrec->jr_parent, rrec->jr_diroff, rrec->jr_mode,
- isat, isdot);
+ rrec->jr_op, (uintmax_t)rrec->jr_ino,
+ rrec->jr_nlink, rrec->jr_parent, rrec->jr_diroff,
+ rrec->jr_mode, isat, isdot);
mode = rrec->jr_mode & IFMT;
if (rrec->jr_op == JOP_REMREF)
removes++;
@@ -1676,8 +1682,8 @@ ino_check(struct suj_ino *sino)
* by one.
*/
if (debug)
- printf("ino %d nlink %d newlinks %d removes %d dotlinks %d\n",
- ino, nlink, newlinks, removes, dotlinks);
+ printf("ino %ju nlink %d newlinks %d removes %d dotlinks %d\n",
+ (uintmax_t)ino, nlink, newlinks, removes, dotlinks);
nlink += newlinks;
nlink -= removes;
sino->si_linkadj = 1;
@@ -1718,9 +1724,9 @@ blk_check(struct suj_blk *sblk)
sino->si_blkadj = 1;
}
if (debug)
- printf("op %d blk %jd ino %d lbn %jd frags %d isat %d (%d)\n",
- brec->jb_op, blk, brec->jb_ino, brec->jb_lbn,
- brec->jb_frags, isat, frags);
+ printf("op %d blk %jd ino %ju lbn %jd frags %d isat %d (%d)\n",
+ brec->jb_op, blk, (uintmax_t)brec->jb_ino,
+ brec->jb_lbn, brec->jb_frags, isat, frags);
/*
* If we found the block at this address we still have to
* determine if we need to free the tail end that was
@@ -1789,6 +1795,20 @@ cg_trunc(struct suj_cg *sc)
}
}
+static void
+cg_adj_blk(struct suj_cg *sc)
+{
+ struct suj_ino *sino;
+ int i;
+
+ for (i = 0; i < SUJ_HASHSIZE; i++) {
+ LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
+ if (sino->si_blkadj)
+ ino_adjblks(sino);
+ }
+ }
+}
+
/*
* Free any partially allocated blocks and then resolve inode block
* counts.
@@ -1923,12 +1943,12 @@ ino_unlinked(void)
*/
if (DIP(ip, di_nlink) == 0) {
if (debug)
- printf("Freeing unlinked ino %d mode %o\n",
- ino, mode);
+ printf("Freeing unlinked ino %ju mode %o\n",
+ (uintmax_t)ino, mode);
ino_reclaim(ip, ino, mode);
} else if (debug)
- printf("Skipping ino %d mode %o with link %d\n",
- ino, mode, DIP(ip, di_nlink));
+ printf("Skipping ino %ju mode %o with link %d\n",
+ (uintmax_t)ino, mode, DIP(ip, di_nlink));
ino = inon;
}
}
@@ -2351,27 +2371,27 @@ suj_verifyino(union dinode *ip)
{
if (DIP(ip, di_nlink) != 1) {
- printf("Invalid link count %d for journal inode %d\n",
- DIP(ip, di_nlink), sujino);
+ printf("Invalid link count %d for journal inode %ju\n",
+ DIP(ip, di_nlink), (uintmax_t)sujino);
return (-1);
}
if ((DIP(ip, di_flags) & (SF_IMMUTABLE | SF_NOUNLINK)) !=
(SF_IMMUTABLE | SF_NOUNLINK)) {
- printf("Invalid flags 0x%X for journal inode %d\n",
- DIP(ip, di_flags), sujino);
+ printf("Invalid flags 0x%X for journal inode %ju\n",
+ DIP(ip, di_flags), (uintmax_t)sujino);
return (-1);
}
if (DIP(ip, di_mode) != (IFREG | IREAD)) {
- printf("Invalid mode %o for journal inode %d\n",
- DIP(ip, di_mode), sujino);
+ printf("Invalid mode %o for journal inode %ju\n",
+ DIP(ip, di_mode), (uintmax_t)sujino);
return (-1);
}
- if (DIP(ip, di_size) < SUJ_MIN || DIP(ip, di_size) > SUJ_MAX) {
- printf("Invalid size %jd for journal inode %d\n",
- DIP(ip, di_size), sujino);
+ if (DIP(ip, di_size) < SUJ_MIN) {
+ printf("Invalid size %jd for journal inode %ju\n",
+ DIP(ip, di_size), (uintmax_t)sujino);
return (-1);
}
@@ -2699,12 +2719,12 @@ suj_check(const char *filesys)
* Build a list of journal blocks in jblocks before parsing the
* available journal blocks in with suj_read().
*/
- printf("** Reading %jd byte journal from inode %d.\n",
- DIP(jip, di_size), sujino);
+ printf("** Reading %jd byte journal from inode %ju.\n",
+ DIP(jip, di_size), (uintmax_t)sujino);
suj_jblocks = jblocks_create();
blocks = ino_visit(jip, sujino, suj_add_block, 0);
if (blocks != numfrags(fs, DIP(jip, di_size))) {
- printf("Sparse journal inode %d.\n", sujino);
+ printf("Sparse journal inode %ju.\n", (uintmax_t)sujino);
return (-1);
}
suj_read();
@@ -2720,6 +2740,7 @@ suj_check(const char *filesys)
printf("** Processing journal entries.\n");
cg_apply(cg_trunc);
cg_apply(cg_check_blk);
+ cg_apply(cg_adj_blk);
cg_apply(cg_check_ino);
}
if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0)
diff --git a/sbin/fsck_msdosfs/Makefile b/sbin/fsck_msdosfs/Makefile
index ddb8e8a255f0..f9dd9fae401b 100644
--- a/sbin/fsck_msdosfs/Makefile
+++ b/sbin/fsck_msdosfs/Makefile
@@ -9,6 +9,5 @@ MAN= fsck_msdosfs.8
SRCS= main.c check.c boot.c fat.c dir.c fsutil.c
CFLAGS+= -I${FSCK}
-WARNS?= 2
.include <bsd.prog.mk>
diff --git a/sbin/fsck_msdosfs/boot.c b/sbin/fsck_msdosfs/boot.c
index fe60f3a49994..319518349eb3 100644
--- a/sbin/fsck_msdosfs/boot.c
+++ b/sbin/fsck_msdosfs/boot.c
@@ -26,7 +26,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: boot.c,v 1.9 2003/07/24 19:25:46 ws Exp $");
+__RCSID("$NetBSD: boot.c,v 1.11 2006/06/05 16:51:18 christos Exp ");
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
@@ -48,8 +48,8 @@ readboot(int dosfs, struct bootblock *boot)
int ret = FSOK;
int i;
- if (read(dosfs, block, sizeof block) != sizeof block) {
- perror("could not read boot block");
+ if ((size_t)read(dosfs, block, sizeof block) != sizeof block) {
+ perr("could not read boot block");
return FSFATAL;
}
@@ -103,7 +103,7 @@ readboot(int dosfs, struct bootblock *boot)
if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec,
SEEK_SET) != boot->bpbFSInfo * boot->bpbBytesPerSec
|| read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
- perror("could not read fsinfo block");
+ perr("could not read fsinfo block");
return FSFATAL;
}
if (memcmp(fsinfo, "RRaA", 4)
@@ -131,7 +131,7 @@ readboot(int dosfs, struct bootblock *boot)
!= boot->bpbFSInfo * boot->bpbBytesPerSec
|| write(dosfs, fsinfo, sizeof fsinfo)
!= sizeof fsinfo) {
- perror("Unable to write bpbFSInfo");
+ perr("Unable to write bpbFSInfo");
return FSFATAL;
}
ret = FSBOOTMOD;
@@ -151,7 +151,7 @@ readboot(int dosfs, struct bootblock *boot)
SEEK_SET)
!= boot->bpbBackup * boot->bpbBytesPerSec
|| read(dosfs, backup, sizeof backup) != sizeof backup) {
- perror("could not read backup bootblock");
+ perr("could not read backup bootblock");
return FSFATAL;
}
backup[65] = block[65]; /* XXX */
@@ -242,7 +242,7 @@ writefsinfo(int dosfs, struct bootblock *boot)
if (lseek(dosfs, boot->bpbFSInfo * boot->bpbBytesPerSec, SEEK_SET)
!= boot->bpbFSInfo * boot->bpbBytesPerSec
|| read(dosfs, fsinfo, sizeof fsinfo) != sizeof fsinfo) {
- perror("could not read fsinfo block");
+ perr("could not read fsinfo block");
return FSFATAL;
}
fsinfo[0x1e8] = (u_char)boot->FSFree;
@@ -257,7 +257,7 @@ writefsinfo(int dosfs, struct bootblock *boot)
!= boot->bpbFSInfo * boot->bpbBytesPerSec
|| write(dosfs, fsinfo, sizeof fsinfo)
!= sizeof fsinfo) {
- perror("Unable to write bpbFSInfo");
+ perr("Unable to write bpbFSInfo");
return FSFATAL;
}
/*
diff --git a/sbin/fsck_msdosfs/check.c b/sbin/fsck_msdosfs/check.c
index 2f558bd5f7e6..1fb005ddd8d8 100644
--- a/sbin/fsck_msdosfs/check.c
+++ b/sbin/fsck_msdosfs/check.c
@@ -26,7 +26,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: check.c,v 1.10 2000/04/25 23:02:51 jdolecek Exp $");
+__RCSID("$NetBSD: check.c,v 1.14 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
@@ -67,7 +67,8 @@ checkfilesys(const char *fname)
printf("\n");
if (dosfs < 0) {
- perror("Can't open");
+ perr("Can't open `%s'", fname);
+ printf("\n");
return 8;
}
diff --git a/sbin/fsck_msdosfs/dir.c b/sbin/fsck_msdosfs/dir.c
index 1dc4456bc3f3..008d0b3398f1 100644
--- a/sbin/fsck_msdosfs/dir.c
+++ b/sbin/fsck_msdosfs/dir.c
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: dir.c,v 1.14 1998/08/25 19:18:15 ross Exp $");
+__RCSID("$NetBSD: dir.c,v 1.20 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
@@ -218,25 +218,26 @@ resetDosDirSection(struct bootblock *boot, struct fatEntry *fat)
int b1, b2;
cl_t cl;
int ret = FSOK;
+ size_t len;
b1 = boot->bpbRootDirEnts * 32;
b2 = boot->bpbSecPerClust * boot->bpbBytesPerSec;
- if ((buffer = malloc( b1 > b2 ? b1 : b2)) == NULL) {
- perror("No space for directory buffer");
+ if ((buffer = malloc(len = b1 > b2 ? b1 : b2)) == NULL) {
+ perr("No space for directory buffer (%zu)", len);
return FSFATAL;
}
- if ((delbuf = malloc(b2)) == NULL) {
+ if ((delbuf = malloc(len = b2)) == NULL) {
free(buffer);
- perror("No space for directory delbuf");
+ perr("No space for directory delbuf (%zu)", len);
return FSFATAL;
}
if ((rootDir = newDosDirEntry()) == NULL) {
free(buffer);
free(delbuf);
- perror("No space for directory entry");
+ perr("No space for directory entry");
return FSFATAL;
}
@@ -328,7 +329,7 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
off *= boot->bpbBytesPerSec;
if (lseek(f, off, SEEK_SET) != off
|| read(f, delbuf, clsz) != clsz) {
- perror("Unable to read directory");
+ perr("Unable to read directory");
return FSFATAL;
}
while (s < e) {
@@ -337,7 +338,7 @@ delete(int f, struct bootblock *boot, struct fatEntry *fat, cl_t startcl,
}
if (lseek(f, off, SEEK_SET) != off
|| write(f, delbuf, clsz) != clsz) {
- perror("Unable to write directory");
+ perr("Unable to write directory");
return FSFATAL;
}
if (startcl == endcl)
@@ -475,7 +476,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
off *= boot->bpbBytesPerSec;
if (lseek(f, off, SEEK_SET) != off
|| read(f, buffer, last) != last) {
- perror("Unable to read directory");
+ perr("Unable to read directory");
return FSFATAL;
}
last /= 32;
@@ -821,7 +822,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
/* create directory tree node */
if (!(d = newDosDirEntry())) {
- perror("No space for directory");
+ perr("No space for directory");
return FSFATAL;
}
memcpy(d, &dirent, sizeof(struct dosDirEntry));
@@ -830,7 +831,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
/* Enter this directory into the todo list */
if (!(n = newDirTodo())) {
- perror("No space for todo list");
+ perr("No space for todo list");
return FSFATAL;
}
n->next = pendingDirectories;
@@ -851,7 +852,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
last *= 32;
if (lseek(f, off, SEEK_SET) != off
|| write(f, buffer, last) != last) {
- perror("Unable to write directory");
+ perr("Unable to write directory");
return FSFATAL;
}
mod &= ~THISMOD;
@@ -870,7 +871,7 @@ readDosDirSection(int f, struct bootblock *boot, struct fatEntry *fat,
last *= 32;
if (lseek(f, off, SEEK_SET) != off
|| write(f, buffer, last) != last) {
- perror("Unable to write directory");
+ perr("Unable to write directory");
return FSFATAL;
}
mod &= ~THISMOD;
@@ -941,7 +942,7 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
if (!lfbuf) {
lfbuf = malloc(boot->ClusterSize);
if (!lfbuf) {
- perror("No space for buffer");
+ perr("No space for buffer");
return FSFATAL;
}
p = NULL;
@@ -965,7 +966,7 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
+ boot->ClusterOffset * boot->bpbBytesPerSec;
if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
|| (size_t)read(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
- perror("could not read LOST.DIR");
+ perr("could not read LOST.DIR");
return FSFATAL;
}
p = lfbuf;
@@ -995,7 +996,7 @@ reconnect(int dosfs, struct bootblock *boot, struct fatEntry *fat, cl_t head)
fat[head].flags |= FAT_USED;
if (lseek(dosfs, lfoff, SEEK_SET) != lfoff
|| (size_t)write(dosfs, lfbuf, boot->ClusterSize) != boot->ClusterSize) {
- perror("could not write LOST.DIR");
+ perr("could not write LOST.DIR");
return FSFATAL;
}
return FSDIRMOD;
diff --git a/sbin/fsck_msdosfs/ext.h b/sbin/fsck_msdosfs/ext.h
index a4fd19b8cd72..681cde998e28 100644
--- a/sbin/fsck_msdosfs/ext.h
+++ b/sbin/fsck_msdosfs/ext.h
@@ -133,7 +133,7 @@ void finishlf(void);
/*
* Return the type of a reserved cluster as text
*/
-char *rsrvdcltype(cl_t);
+const char *rsrvdcltype(cl_t);
/*
* Clear a cluster chain in a FAT
diff --git a/sbin/fsck_msdosfs/fat.c b/sbin/fsck_msdosfs/fat.c
index 7a6368c025f6..d2d144449ec5 100644
--- a/sbin/fsck_msdosfs/fat.c
+++ b/sbin/fsck_msdosfs/fat.c
@@ -26,7 +26,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: fat.c,v 1.12 2000/10/10 20:24:52 is Exp $");
+__RCSID("$NetBSD: fat.c,v 1.18 2006/06/05 16:51:18 christos Exp $");
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
@@ -69,6 +69,7 @@ checkdirty(int fs, struct bootblock *boot)
off_t off;
u_char *buffer;
int ret = 0;
+ size_t len;
if (boot->ClustMask != CLUST16_MASK && boot->ClustMask != CLUST32_MASK)
return 0;
@@ -76,20 +77,20 @@ checkdirty(int fs, struct bootblock *boot)
off = boot->bpbResSectors;
off *= boot->bpbBytesPerSec;
- buffer = malloc(boot->bpbBytesPerSec);
+ buffer = malloc(len = boot->bpbBytesPerSec);
if (buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", len);
return 1;
}
if (lseek(fs, off, SEEK_SET) != off) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
if ((size_t)read(fs, buffer, boot->bpbBytesPerSec) !=
boot->bpbBytesPerSec) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
@@ -163,10 +164,11 @@ static int
_readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer)
{
off_t off;
+ size_t len;
- *buffer = malloc(boot->FATsecs * boot->bpbBytesPerSec);
+ *buffer = malloc(len = boot->FATsecs * boot->bpbBytesPerSec);
if (*buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", len);
return 0;
}
@@ -174,13 +176,13 @@ _readfat(int fs, struct bootblock *boot, u_int no, u_char **buffer)
off *= boot->bpbBytesPerSec;
if (lseek(fs, off, SEEK_SET) != off) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
if ((size_t)read(fs, *buffer, boot->FATsecs * boot->bpbBytesPerSec)
!= boot->FATsecs * boot->bpbBytesPerSec) {
- perror("Unable to read FAT");
+ perr("Unable to read FAT");
goto err;
}
@@ -207,10 +209,10 @@ readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
if (!_readfat(fs, boot, no, &buffer))
return FSFATAL;
-
+
fat = malloc(len = boot->NumClusters * sizeof(struct fatEntry));
if (fat == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT clusters (%zu)", len);
free(buffer);
return FSFATAL;
}
@@ -318,7 +320,7 @@ readfat(int fs, struct bootblock *boot, u_int no, struct fatEntry **fp)
/*
* Get type of reserved cluster
*/
-char *
+const char *
rsrvdcltype(cl_t cl)
{
if (cl == CLUST_FREE)
@@ -428,13 +430,13 @@ clearchain(struct bootblock *boot, struct fatEntry *fat, cl_t head)
}
int
-tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *trunc)
+tryclear(struct bootblock *boot, struct fatEntry *fat, cl_t head, cl_t *truncp)
{
if (ask(0, "Clear chain starting at %u", head)) {
clearchain(boot, fat, head);
return FSFATMOD;
} else if (ask(0, "Truncate")) {
- *trunc = CLUST_EOF;
+ *truncp = CLUST_EOF;
return FSFATMOD;
} else
return FSERROR;
@@ -549,7 +551,7 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
buffer = malloc(fatsz = boot->FATsecs * boot->bpbBytesPerSec);
if (buffer == NULL) {
- perror("No space for FAT");
+ perr("No space for FAT sectors (%zu)", fatsz);
return FSFATAL;
}
memset(buffer, 0, fatsz);
@@ -598,7 +600,7 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
free(old_fat);
p += count;
}
-
+
for (cl = CLUST_FIRST; cl < boot->NumClusters; cl++) {
switch (boot->ClustMask) {
case CLUST32_MASK:
@@ -634,7 +636,7 @@ writefat(int fs, struct bootblock *boot, struct fatEntry *fat, int correct_fat)
off *= boot->bpbBytesPerSec;
if (lseek(fs, off, SEEK_SET) != off
|| (size_t)write(fs, buffer, fatsz) != fatsz) {
- perror("Unable to write FAT");
+ perr("Unable to write FAT");
ret = FSFATAL; /* Return immediately? XXX */
}
}
diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c
index 172265368208..e169061e9f65 100644
--- a/sbin/fsdb/fsdb.c
+++ b/sbin/fsdb/fsdb.c
@@ -39,6 +39,7 @@ static const char rcsid[] =
#include <grp.h>
#include <histedit.h>
#include <pwd.h>
+#include <stdint.h>
#include <string.h>
#include <time.h>
#include <timeconv.h>
@@ -211,7 +212,8 @@ char *
prompt(EditLine *el)
{
static char pstring[64];
- snprintf(pstring, sizeof(pstring), "fsdb (inum: %d)> ", curinum);
+ snprintf(pstring, sizeof(pstring), "fsdb (inum: %ju)> ",
+ (uintmax_t)curinum);
return pstring;
}
@@ -298,8 +300,8 @@ ino_t curinum, ocurrent;
#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \
if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \
- printf("inode %d out of range; range is [%d,%d]\n", \
- inum, ROOTINO, maxino); \
+ printf("inode %ju out of range; range is [%ju,%ju]\n", \
+ (uintmax_t)inum, (uintmax_t)ROOTINO, (uintmax_t)maxino); \
return 1; \
}
@@ -364,7 +366,8 @@ CMDFUNCSTART(uplink)
if (!checkactive())
return 1;
DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1);
- printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
+ printf("inode %ju link count now %d\n",
+ (uintmax_t)curinum, DIP(curinode, di_nlink));
inodirty();
return 0;
}
@@ -374,7 +377,8 @@ CMDFUNCSTART(downlink)
if (!checkactive())
return 1;
DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1);
- printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink));
+ printf("inode %ju link count now %d\n",
+ (uintmax_t)curinum, DIP(curinode, di_nlink));
inodirty();
return 0;
}
@@ -493,11 +497,11 @@ CMDFUNCSTART(findblk)
if (is_ufs2 ?
compare_blk64(wantedblk64, ino_to_fsba(&sblock, inum)) :
compare_blk32(wantedblk32, ino_to_fsba(&sblock, inum))) {
- printf("block %llu: inode block (%d-%d)\n",
+ printf("block %llu: inode block (%ju-%ju)\n",
(unsigned long long)fsbtodb(&sblock,
ino_to_fsba(&sblock, inum)),
- (inum / INOPB(&sblock)) * INOPB(&sblock),
- (inum / INOPB(&sblock) + 1) * INOPB(&sblock));
+ (uintmax_t)(inum / INOPB(&sblock)) * INOPB(&sblock),
+ (uintmax_t)(inum / INOPB(&sblock) + 1) * INOPB(&sblock));
findblk_numtofind--;
if (findblk_numtofind == 0)
goto end;
@@ -593,8 +597,8 @@ static int
founddatablk(uint64_t blk)
{
- printf("%llu: data block of inode %d\n",
- (unsigned long long)fsbtodb(&sblock, blk), curinum);
+ printf("%llu: data block of inode %ju\n",
+ (unsigned long long)fsbtodb(&sblock, blk), (uintmax_t)curinum);
findblk_numtofind--;
if (findblk_numtofind == 0)
return 1;
@@ -753,7 +757,7 @@ CMDFUNCSTART(ln)
return 1;
rval = makeentry(curinum, inum, argv[2]);
if (rval)
- printf("Ino %d entered as `%s'\n", inum, argv[2]);
+ printf("Ino %ju entered as `%s'\n", (uintmax_t)inum, argv[2]);
else
printf("could not enter name? weird.\n");
curinode = ginode(curinum);
diff --git a/sbin/fsdb/fsdbutil.c b/sbin/fsdb/fsdbutil.c
index 5d6f16d5d864..eaea3db79fd5 100644
--- a/sbin/fsdb/fsdbutil.c
+++ b/sbin/fsdb/fsdbutil.c
@@ -152,7 +152,7 @@ printstat(const char *cp, ino_t inum, union dinode *dp)
puts("fifo");
break;
}
- printf("I=%lu MODE=%o SIZE=%ju", (u_long)inum, DIP(dp, di_mode),
+ printf("I=%ju MODE=%o SIZE=%ju", (uintmax_t)inum, DIP(dp, di_mode),
(uintmax_t)DIP(dp, di_size));
if (sblock.fs_magic != FS_UFS1_MAGIC) {
t = _time64_to_time(dp->dp2.di_birthtime);
@@ -290,7 +290,7 @@ printblocks(ino_t inum, union dinode *dp)
long ndb, offset;
ufs2_daddr_t blkno;
- printf("Blocks for inode %d:\n", inum);
+ printf("Blocks for inode %ju:\n", (uintmax_t)inum);
printf("Direct blocks:\n");
ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
for (i = 0; i < NDADDR && i < ndb; i++) {
@@ -338,7 +338,7 @@ checkactivedir(void)
return 0;
}
if ((DIP(curinode, di_mode) & IFMT) != IFDIR) {
- warnx("inode %d not a directory", curinum);
+ warnx("inode %ju not a directory", (uintmax_t)curinum);
return 0;
}
return 1;
@@ -363,11 +363,12 @@ printactive(int doblocks)
printstat("current inode", curinum, curinode);
break;
case 0:
- printf("current inode %d: unallocated inode\n", curinum);
+ printf("current inode %ju: unallocated inode\n", (uintmax_t)curinum);
break;
default:
- printf("current inode %d: screwy itype 0%o (mode 0%o)?\n",
- curinum, DIP(curinode, di_mode) & IFMT, DIP(curinode, di_mode));
+ printf("current inode %ju: screwy itype 0%o (mode 0%o)?\n",
+ (uintmax_t)curinum, DIP(curinode, di_mode) & IFMT,
+ DIP(curinode, di_mode));
break;
}
return 0;
diff --git a/sbin/fsirand/fsirand.c b/sbin/fsirand/fsirand.c
index ca7841a46f3e..c373c5bb56f5 100644
--- a/sbin/fsirand/fsirand.c
+++ b/sbin/fsirand/fsirand.c
@@ -274,8 +274,8 @@ fsirand(char *device)
dp2 = &((struct ufs2_dinode *)inodebuf)[n];
if (inumber >= ROOTINO) {
if (printonly)
- (void)printf("ino %d gen %08x\n",
- inumber,
+ (void)printf("ino %ju gen %08x\n",
+ (uintmax_t)inumber,
sblock->fs_magic == FS_UFS1_MAGIC ?
dp1->di_gen : dp2->di_gen);
else if (sblock->fs_magic == FS_UFS1_MAGIC)
diff --git a/sbin/geom/class/eli/geli.8 b/sbin/geom/class/eli/geli.8
index 0803480450f1..3cb1f211769f 100644
--- a/sbin/geom/class/eli/geli.8
+++ b/sbin/geom/class/eli/geli.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 28, 2012
+.Dd June 18, 2012
.Dt GELI 8
.Os
.Sh NAME
@@ -186,14 +186,15 @@ one of the following algorithms:
or
.Nm HMAC/SHA512 .
.It
-Can create a key from a couple of components (user entered passphrase, random
-bits from a file, etc.).
+Can create a User Key from up to two, piecewise components: a passphrase
+entered via prompt or read from one or more passfiles; a keyfile read from
+one or more files.
.It
Allows encryption of the root partition.
The user will be asked for the
passphrase before the root file system is mounted.
.It
-The passphrase of the user is strengthened with:
+Strengthens the passphrase component of the User Key with:
.Rs
.%A B. Kaliski
.%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
@@ -201,7 +202,7 @@ The passphrase of the user is strengthened with:
.%N 2898
.Re
.It
-Allows the use of two independent keys (e.g., a
+Allows the use of two independent User Keys (e.g., a
.Qq "user key"
and a
.Qq "company key" ) .
@@ -210,8 +211,8 @@ It is fast -
.Nm
performs simple sector-to-sector encryption.
.It
-Allows Master Keys to be backed up and restored,
-so that if a user has to quickly destroy his keys,
+Allows the encrypted Master Key to be backed up and restored,
+so that if a user has to quickly destroy key material,
it is possible to get the data back by restoring keys from
backup.
.It
@@ -219,8 +220,8 @@ Providers can be configured to automatically detach on last close
(so users do not have to remember to detach providers after unmounting
the file systems).
.It
-Allows attaching a provider with a random, one-time key - useful for swap
-partitions and temporary file systems.
+Allows attaching a provider with a random, one-time Master Key -
+useful for swap partitions and temporary file systems.
.It
Allows verification of data integrity (data authentication).
.It
@@ -233,7 +234,8 @@ indicates an action to be performed:
.Bl -tag -width ".Cm configure"
.It Cm init
Initialize the provider which needs to be encrypted.
-Here you can set up the cryptographic algorithm to use, key length, etc.
+Here you can set up the cryptographic algorithm to use, Data Key length,
+etc.
The last sector of the provider is used to store metadata.
The
.Cm init
@@ -289,37 +291,58 @@ and
The default and recommended algorithm is
.Nm AES-XTS .
.It Fl i Ar iterations
-Number of iterations to use with PKCS#5v2.
+Number of iterations to use with PKCS#5v2 when processing User Key
+passphrase component.
If this option is not specified,
.Nm
will find the number of iterations which is equal to 2 seconds of crypto work.
If 0 is given, PKCS#5v2 will not be used.
+PKCS#5v2 processing is performed once, after all parts of the passphrase
+component have been read.
.It Fl J Ar newpassfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
If
.Ar newpassfile
is given as -, standard input will be used.
Only the first line (excluding new-line character) is taken from the given file.
-This argument can be specified multiple times.
+This argument can be specified multiple times, which has the effect of
+reassembling a single passphrase split across multiple files.
+Cannot be combined with the
+.Fl P
+option.
.It Fl K Ar newkeyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
If
.Ar newkeyfile
is given as -, standard input will be used.
-This argument can be specified multiple times.
+This argument can be specified multiple times, which has the effect of
+reassembling a single keyfile split across multiple keyfile parts.
.It Fl l Ar keylen
-Key length to use with the given cryptographic algorithm.
-If not given, the default key length for the given algorithm is used, which is:
-128 for
-.Nm AES-XTS ,
-.Nm AES-CBC ,
-.Nm Blowfish-CBC
-and
-.Nm Camellia-CBC
-and 192 for
-.Nm 3DES-CBC .
+Data Key length to use with the given cryptographic algorithm.
+If the length is not specified, the selected algorithm uses its
+.Em default
+key length.
+.Bl -ohang -offset indent
+.It Nm AES-XTS
+.Em 128 ,
+256
+.It Nm AES-CBC , Nm Camilla-CBC
+.Em 128 ,
+192,
+256
+.It Nm Blowfish-CBC
+.Em 128
++ n * 32, for n=[0..10]
+.It Nm 3DES-CBC
+.Em 192
+.El
.It Fl P
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl J
+option.
.It Fl s Ar sectorsize
Change decrypted provider's sector size.
Increasing the sector size allows increased performance,
@@ -337,9 +360,9 @@ Note that using older metadata version may limit numer of features available.
.El
.It Cm attach
Attach the given provider.
-The master key will be decrypted using the given
-passphrase/keyfile and a new GEOM provider will be created using the given
-provider's name with an
+The encrypted Master Key will be loaded from the metadata and decrypted
+using the given passphrase/keyfile and a new GEOM provider will be created
+using the given provider's name with an
.Qq .eli
suffix.
.Pp
@@ -357,28 +380,33 @@ option for the
.Cm detach
subcommand.
.It Fl j Ar passfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
For more information see the description of the
.Fl J
option for the
.Cm init
subcommand.
.It Fl k Ar keyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
For more information see the description of the
.Fl K
option for the
.Cm init
subcommand.
.It Fl p
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl j
+option.
.It Fl r
Attach read-only provider.
It will not be opened for writing.
.El
.It Cm detach
Detach the given providers, which means remove the devfs entry
-and clear the keys from memory.
+and clear the Master Key and Data Keys from memory.
.Pp
Additional options include:
.Bl -tag -width ".Fl f"
@@ -391,7 +419,7 @@ while it is open, but will be automatically detached when it is closed for the
last time even if it was only opened for reading.
.El
.It Cm onetime
-Attach the given providers with random, one-time keys.
+Attach the given providers with a random, one-time (ephemeral) Master Key.
The command can be used to encrypt swap partitions or temporary file systems.
.Pp
Additional options include:
@@ -415,7 +443,7 @@ For more information, see the description of the
.Cm attach
subcommand.
.It Fl l Ar keylen
-Key length to use with the given cryptographic algorithm.
+Data Key length to use with the given cryptographic algorithm.
For more information, see the description of the
.Cm init
subcommand.
@@ -439,15 +467,18 @@ subcommand.
Remove the BOOT flag from the given providers.
.El
.It Cm setkey
-Change or setup (if not yet initialized) selected key.
-There is one master key, which can be encrypted with two independent user keys.
+Install a copy of the Master Key into the selected slot, encrypted with
+a new User Key.
+If the selected slot is populated, replace the existing copy.
+A provider has one Master Key, which can be stored in one or both slots,
+each encrypted with an independent User Key.
With the
.Cm init
subcommand, only key number 0 is initialized.
-The key can always be changed: for an attached provider,
+The User Key can be changed at any time: for an attached provider,
for a detached provider, or on the backup file.
When a provider is attached, the user does not have to provide
-an old passphrase/keyfile.
+an existing passphrase/keyfile.
.Pp
Additional options include:
.Bl -tag -width ".Fl J Ar newpassfile"
@@ -458,44 +489,54 @@ To be able to use this option with the
.Cm setkey
subcommand, only one key has to be defined and this key must be changed.
.It Fl j Ar passfile
-Specifies a file which contains the old passphrase or its part.
+Specifies a file which contains the passphrase component of a current User Key
+(or part of it).
.It Fl J Ar newpassfile
-Specifies a file which contains the new passphrase or its part.
+Specifies a file which contains the passphrase component of the new User Key
+(or part of it).
.It Fl k Ar keyfile
-Specifies a file which contains part of the old key.
+Specifies a file which contains the keyfile component of a current User Key
+(or part of it).
.It Fl K Ar newkeyfile
-Specifies a file which contains part of the new key.
+Specifies a file which contains the keyfile component of the new User Key
+(or part of it).
.It Fl n Ar keyno
-Specifies the number of the key to change (could be 0 or 1).
+Specifies the index number of the Master Key copy to change (could be 0 or 1).
If the provider is attached and no key number is given, the key
used for attaching the provider will be changed.
If the provider is detached (or we are operating on a backup file)
-and no key number is given, the key decrypted with the passphrase/keyfile
-will be changed.
+and no key number is given, the first Master Key copy to be successfully
+decrypted with the provided User Key passphrase/keyfile will be changed.
.It Fl p
-Do not use passphrase as the old key component.
+Do not use a passphrase as a component of the current User Key.
+Cannot be combined with the
+.Fl j
+option.
.It Fl P
-Do not use passphrase as the new key component.
+Do not use a passphrase as a component of the new User Key.
+Cannot be combined with the
+.Fl J
+option.
.El
.It Cm delkey
-Destroy (overwrite with random data) the selected key.
+Destroy (overwrite with random data) the selected Master Key copy.
If one is destroying keys for an attached provider, the provider
-will not be detached even if all keys are destroyed.
+will not be detached even if all copies of the Master Key are destroyed.
It can even be rescued with the
.Cm setkey
-subcommand.
+subcommand because the Master Key is still in memory.
.Pp
Additional options include:
.Bl -tag -width ".Fl a Ar keyno"
.It Fl a
-Destroy all keys (does not need
+Destroy all copies of the Master Key (does not need
.Fl f
option).
.It Fl f
Force key destruction.
-This option is needed to destroy the last key.
+This option is needed to destroy the last copy of the Master Key.
.It Fl n Ar keyno
-Specifies the key number.
+Specifies the index number of the Master Key copy.
If the provider is attached and no key number is given, the key
used for attaching the provider will be destroyed.
If provider is detached (or we are operating on a backup file) the key number
@@ -503,8 +544,8 @@ has to be given.
.El
.It Cm kill
This command should be used only in emergency situations.
-It will destroy all the keys on a given provider and will detach it forcibly
-(if it is attached).
+It will destroy all copies of the Master Key on a given provider and will
+detach it forcibly (if it is attached).
This is absolutely a one-way command - if you do not have a metadata
backup, your data is gone for good.
In case the provider was attached with the
@@ -542,8 +583,8 @@ and
.El
.It Cm suspend
Suspend device by waiting for all inflight requests to finish, clearing all
-sensitive information (like keys) from kernel memory, and blocking all
-further I/O requests until the
+sensitive information (like the Master Key and Data Keys) from kernel memory,
+and blocking all further I/O requests until the
.Cm resume
subcommand is executed.
This functionality is useful for laptops: when one wants to suspend a
@@ -553,8 +594,8 @@ on an encrypted device, unmounting the file system, and detaching the device,
the
.Cm suspend
subcommand can be used.
-Any access to the encrypted device will be blocked until the keys are
-recovered through the
+Any access to the encrypted device will be blocked until the Master Key is
+reloaded through the
.Cm resume
subcommand.
Thus there is no need to close nor unmount anything.
@@ -584,21 +625,26 @@ utility is stored is bad idea.
Additional options include:
.Bl -tag -width ".Fl j Ar passfile"
.It Fl j Ar passfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
For more information see the description of the
.Fl J
option for the
.Cm init
subcommand.
.It Fl k Ar keyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
For more information see the description of the
.Fl K
option for the
.Cm init
subcommand.
.It Fl p
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl j
+option.
.El
.It Cm resize
Inform
@@ -626,6 +672,9 @@ If GEOM providers are specified, the
subcommand will print metadata version used by each of them.
.It Cm clear
Clear metadata from the given providers.
+.Em WARNING :
+This will erase with zeros the encrypted Master Key copies stored in the
+metadata.
.It Cm dump
Dump metadata stored on the given providers.
.It Cm list
@@ -647,6 +696,36 @@ Additional options include:
.It Fl v
Be more verbose.
.El
+.Sh KEY SUMMARY
+.Ss Master Key
+Upon
+.Cm init ,
+the
+.Nm
+utility generates a random Master Key for the provider.
+The Master Key never changes during the lifetime of the provider.
+Each copy of the provider metadata, active or backed up to a file, can store
+up to two, independently-encrypted copies of the Master Key.
+.Ss User Key
+Each stored copy of the Master Key is encrypted with a User Key, which
+is generated by the
+.Nm
+utility from a passphrase and/or a keyfile.
+The
+.Nm
+utility first reads all parts of the keyfile in the order specified on the
+command line, then reads all parts of the stored passphrase in the order
+specified on the command line.
+If no passphrase parts are specified, the system prompts the user to enter
+the passphrase.
+The passphrase is optionally strengthened by PKCS#5v2.
+The User Key is a digest computed over the concatenated keyfile and passphrase.
+.Ss Data Key
+During operation, one or more Data Keys are deterministically derived by
+the kernel from the Master Key and cached in memory.
+The number of Data Keys used by a given provider, and the way they are
+derived, depend on the GELI version and whether the provider is configured to
+use data authentication.
.Sh SYSCTL VARIABLES
The following
.Xr sysctl 8
@@ -677,7 +756,7 @@ If set to 0, attaching providers on boot will be disabled.
This variable should be set in
.Pa /boot/loader.conf .
.It Va kern.geom.eli.overwrites : No 5
-Specifies how many times the Master-Key will be overwritten
+Specifies how many times the Master Key will be overwritten
with random values when it is destroyed.
After this operation it is filled with zeros.
.It Va kern.geom.eli.visible_passphrase : No 0
@@ -699,18 +778,19 @@ Batching reduces the number of interrupts by responding to a group of
crypto requests with one interrupt.
The crypto card and the driver has to support this feature.
.It Va kern.geom.eli.key_cache_limit : No 8192
-Specifies how many encryption keys to cache.
+Specifies how many Data Keys to cache.
The default limit
(8192 keys) will allow caching of all keys for a 4TB provider with 512 byte
sectors and will take around 1MB of memory.
.It Va kern.geom.eli.key_cache_hits
-Reports how many times we were looking up a key and it was already in cache.
-This sysctl is not updated for providers that need less keys than the limit
-specified in
+Reports how many times we were looking up a Data Key and it was already in
+cache.
+This sysctl is not updated for providers that need fewer Data Keys than
+the limit specified in
.Va kern.geom.eli.key_cache_limit .
.It Va kern.geom.eli.key_cache_misses
-Reports how many times we were looking up a key and it was not in cache.
-This sysctl is not updated for providers that need fewer keys than the limit
+Reports how many times we were looking up a Data Key and it was not in cache.
+This sysctl is not updated for providers that need fewer Data Keys than the limit
specified in
.Va kern.geom.eli.key_cache_limit .
.El
@@ -738,7 +818,7 @@ Enter passphrase:
# geli detach da2.eli
.Ed
.Pp
-Create an encrypted provider, but use two keys:
+Create an encrypted provider, but use two User Keys:
one for your employee and one for you as the company's security officer
(so it's not a tragedy if the employee
.Qq accidentally
@@ -760,7 +840,7 @@ forget their passphrases, so backup the Master Key with your own random key:
# dd if=/dev/random of=/mnt/pendrive/keys/`hostname` bs=64 count=1
# geli init -P -K /mnt/pendrive/keys/`hostname` /dev/ad0s1e
# geli backup /dev/ad0s1e /mnt/pendrive/backups/`hostname`
-(use key number 0, so the encrypted Master Key will be overwritten by this)
+(use key number 0, so the encrypted Master Key will be re-encrypted by this)
# geli setkey -n 0 -k /mnt/pendrive/keys/`hostname` /dev/ad0s1e
(allow the user to enter his passphrase)
Enter new passphrase:
@@ -776,8 +856,8 @@ Encrypted swap partition setup:
.Pp
The example below shows how to configure two providers which will be attached
on boot (before the root file system is mounted).
-One of them is using passphrase and three keyfiles and the other is using only a
-keyfile:
+One of them is using passphrase and three keyfile parts and the other is
+using only a keyfile in one part:
.Bd -literal -offset indent
# dd if=/dev/random of=/dev/da0 bs=1m
# dd if=/dev/random of=/boot/keys/da0.key0 bs=32k count=1
diff --git a/sbin/geom/class/multipath/geom_multipath.c b/sbin/geom/class/multipath/geom_multipath.c
index a821951d3bee..cdf35d0381ec 100644
--- a/sbin/geom/class/multipath/geom_multipath.c
+++ b/sbin/geom/class/multipath/geom_multipath.c
@@ -49,6 +49,7 @@ uint32_t version = G_MULTIPATH_VERSION;
static void mp_main(struct gctl_req *, unsigned int);
static void mp_label(struct gctl_req *);
static void mp_clear(struct gctl_req *);
+static void mp_prefer(struct gctl_req *);
struct g_command class_commands[] = {
{
@@ -87,6 +88,10 @@ struct g_command class_commands[] = {
"[-v] name prov"
},
{
+ "prefer", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,
+ "[-v] prov ..."
+ },
+ {
"fail", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
"[-v] name prov"
},
@@ -131,6 +136,8 @@ mp_main(struct gctl_req *req, unsigned int flags __unused)
mp_label(req);
} else if (strcmp(name, "clear") == 0) {
mp_clear(req);
+ } else if (strcmp(name, "prefer") == 0) {
+ mp_prefer(req);
} else {
gctl_error(req, "Unknown command: %s.", name);
}
@@ -294,3 +301,22 @@ mp_clear(struct gctl_req *req)
}
}
+static void
+mp_prefer(struct gctl_req *req)
+{
+ const char *name, *comp, *errstr;
+ int nargs;
+
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs != 2) {
+ gctl_error(req, "Usage: prefer GEOM PROVIDER");
+ return;
+ }
+ name = gctl_get_ascii(req, "arg0");
+ comp = gctl_get_ascii(req, "arg1");
+ errstr = gctl_issue (req);
+ if (errstr != NULL) {
+ fprintf(stderr, "Can't set %s preferred provider to %s: %s.\n",
+ name, comp, errstr);
+ }
+}
diff --git a/sbin/geom/class/multipath/gmultipath.8 b/sbin/geom/class/multipath/gmultipath.8
index 55a86f339314..81b85ddbd642 100644
--- a/sbin/geom/class/multipath/gmultipath.8
+++ b/sbin/geom/class/multipath/gmultipath.8
@@ -66,6 +66,11 @@
.Op Fl v
.Ar name
.Nm
+.Cm prefer
+.Op Fl v
+.Ar name
+.Ar prov
+.Nm
.Cm getactive
.Op Fl v
.Ar name
@@ -171,7 +176,9 @@ If there are other paths present, new requests will be forwarded there.
Mark specified provider as a path of the specified multipath device as
operational, allowing it to handle requests.
.It Cm rotate
-Change the active provider/path in Active/Passive mode.
+Change the active provider/path to the next available provider in Active/Passive mode.
+.It Cm prefer
+Change the active provider/path to the specified provider in Active/Passive mode.
.It Cm getactive
Get the currently active provider(s)/path(s).
.It Cm destroy
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 2e745c40fca3..7a91d3dbc07c 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -1006,11 +1006,12 @@ or
but smaller than 545 kB since the first-stage loader will load the
entire partition into memory during boot, regardless of how much data
it actually contains.
-This example uses 94 blocks (47 kB) so the next partition will be
+This example uses 88 blocks (44 kB) so the next partition will be
aligned on a 64 kB boundary without the need to specify an explicit
offset or alignment.
+The boot partition itself is aligned on a 4 kB boundary.
.Bd -literal -offset indent
-/sbin/gpart add -b 34 -s 94 -t freebsd-boot ad0
+/sbin/gpart add -b 40 -s 88 -t freebsd-boot ad0
/sbin/gpart bootcode -p /boot/gptboot -i 1 ad0
.Ed
.Pp
diff --git a/sbin/geom/class/raid/graid.8 b/sbin/geom/class/raid/graid.8
index 6b8cd61dbf56..630cd018e621 100644
--- a/sbin/geom/class/raid/graid.8
+++ b/sbin/geom/class/raid/graid.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 6, 2012
+.Dd September 13, 2012
.Dt GRAID 8
.Os
.Sh NAME
@@ -85,7 +85,7 @@ utility is used to manage software RAID configurations, supported by the
GEOM RAID class.
GEOM RAID class uses on-disk metadata to provide access to software-RAID
volumes defined by different RAID BIOSes.
-Depending on RAID BIOS type and it's metadata format, different subsets of
+Depending on RAID BIOS type and its metadata format, different subsets of
configurations and features are supported.
To allow booting from RAID volume, the metadata format should match the
RAID BIOS type and its capabilities.
@@ -293,6 +293,8 @@ Mark volume as clean when idle for the specified number of seconds.
Debug level of the
.Nm RAID
GEOM class.
+.It Va kern.geom.raid.enable : No 1
+Enable on-disk metadata taste.
.It Va kern.geom.raid.idle_threshold : No 1000000
Time in microseconds to consider a volume idle for rebuild purposes.
.It Va kern.geom.raid.name_format : No 0
@@ -302,6 +304,8 @@ Number of read errors equated to disk failure.
Write errors are always considered as disk failures.
.It Va kern.geom.raid.start_timeout : No 30
Time to wait for missing array components on startup.
+.It Va kern.geom.raid. Ns Ar X Ns Va .enable : No 1
+Enable taste for specific metadata or transformation module.
.El
.Sh EXIT STATUS
Exit status is 0 on success, and non-zero if the command fails.
diff --git a/sbin/geom/class/sched/gsched.8 b/sbin/geom/class/sched/gsched.8
index bb3c1cfe5cb5..ae04865a21b1 100644
--- a/sbin/geom/class/sched/gsched.8
+++ b/sbin/geom/class/sched/gsched.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 29, 2010
+.Dd July 26, 2012
.Dt GSCHED 8
.Os
.Sh NAME
@@ -135,19 +135,19 @@ maximum amount of debug information is printed.
Exit status is 0 on success, and 1 if the command fails.
.Sh EXAMPLES
The following example shows how to create a scheduling provider for disk
-.Pa /dev/ad0 ,
+.Pa /dev/ada0 ,
and how to destroy it.
.Bd -literal -offset indent
# Load the geom_sched module:
kldload geom_sched
# Load some scheduler classes used by geom_sched:
kldload gsched_rr
-# Configure device ad0 to use scheduler "rr":
-geom sched insert -a rr ad0
-# Now provider ad0 uses the "rr" algorithm;
-# the new geom is ad0.sched.
+# Configure device ada0 to use scheduler "rr":
+geom sched insert -a rr ada0
+# Now provider ada0 uses the "rr" algorithm;
+# the new geom is ada0.sched.
# Remove the scheduler on the device:
-geom sched destroy -v ad0.sched.
+geom sched destroy -v ada0.sched.
.Ed
.Sh SEE ALSO
.Xr geom 4 ,
diff --git a/sbin/geom/class/virstor/gvirstor.8 b/sbin/geom/class/virstor/gvirstor.8
index cdb50b1d0f53..99eff52fe571 100644
--- a/sbin/geom/class/virstor/gvirstor.8
+++ b/sbin/geom/class/virstor/gvirstor.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 24, 2011
+.Dd August 3, 2012
.Dt GVIRSTOR 8
.Os
.Sh NAME
@@ -43,6 +43,10 @@
.Op Fl fv
.Ar name ...
.Nm
+.Cm destroy
+.Op Fl fv
+.Ar name ...
+.Nm
.Cm add
.Op Fl vh
.Ar name prov ...
@@ -107,6 +111,9 @@ Turn off an existing virtual device with the given
.Ar name .
This command does not touch on-disk metadata.
As with other GEOM classes, stopped geoms cannot be started manually.
+.It Cm destroy
+Same as
+.Cm stop.
.It Cm add
Adds new components to existing virtual device with the given
.Ar name .
diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c
index 770e960f3c05..8c15c2143e1e 100644
--- a/sbin/geom/core/geom.c
+++ b/sbin/geom/core/geom.c
@@ -74,7 +74,7 @@ static void std_status(struct gctl_req *req, unsigned flags);
static void std_load(struct gctl_req *req, unsigned flags);
static void std_unload(struct gctl_req *req, unsigned flags);
-struct g_command std_commands[] = {
+static struct g_command std_commands[] = {
{ "help", 0, std_help, G_NULL_OPTS, NULL },
{ "list", 0, std_list,
{
diff --git a/sbin/ggate/ggatec/ggatec.c b/sbin/ggate/ggatec/ggatec.c
index 660bd8ab469b..6f9263c8c30d 100644
--- a/sbin/ggate/ggatec/ggatec.c
+++ b/sbin/ggate/ggatec/ggatec.c
@@ -55,7 +55,7 @@
#include "ggate.h"
-enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
+static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
static const char *path = NULL;
static const char *host = NULL;
diff --git a/sbin/ggate/ggated/ggated.c b/sbin/ggate/ggated/ggated.c
index 2997a9cf2c69..01aa00aca645 100644
--- a/sbin/ggate/ggated/ggated.c
+++ b/sbin/ggate/ggated/ggated.c
@@ -92,12 +92,12 @@ struct ggd_export {
static const char *exports_file = GGATED_EXPORT_FILE;
static int got_sighup = 0;
-in_addr_t bindaddr;
+static in_addr_t bindaddr;
static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue);
static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue);
-pthread_mutex_t inqueue_mtx, outqueue_mtx;
-pthread_cond_t inqueue_cond, outqueue_cond;
+static pthread_mutex_t inqueue_mtx, outqueue_mtx;
+static pthread_cond_t inqueue_cond, outqueue_cond;
static SLIST_HEAD(, ggd_export) exports = SLIST_HEAD_INITIALIZER(exports);
static LIST_HEAD(, ggd_connection) connections = LIST_HEAD_INITIALIZER(connections);
diff --git a/sbin/ggate/ggatel/ggatel.c b/sbin/ggate/ggatel/ggatel.c
index d9e49db074a2..abfe7c18e41d 100644
--- a/sbin/ggate/ggatel/ggatel.c
+++ b/sbin/ggate/ggatel/ggatel.c
@@ -47,7 +47,7 @@
#include "ggate.h"
-enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
+static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
static const char *path = NULL;
static int unit = G_GATE_UNIT_AUTO;
diff --git a/sbin/ggate/shared/ggate.h b/sbin/ggate/shared/ggate.h
index 3e26253c360c..898efea6507e 100644
--- a/sbin/ggate/shared/ggate.h
+++ b/sbin/ggate/shared/ggate.h
@@ -95,8 +95,8 @@ struct g_gate_hdr {
void g_gate_vlog(int priority, const char *message, va_list ap);
void g_gate_log(int priority, const char *message, ...);
-void g_gate_xvlog(const char *message, va_list ap);
-void g_gate_xlog(const char *message, ...);
+void g_gate_xvlog(const char *message, va_list ap) __dead2;
+void g_gate_xlog(const char *message, ...) __dead2;
off_t g_gate_mediasize(int fd);
unsigned g_gate_sectorsize(int fd);
void g_gate_open_device(void);
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c
index b610bd2f8c8f..ad837a82f52e 100644
--- a/sbin/growfs/growfs.c
+++ b/sbin/growfs/growfs.c
@@ -324,6 +324,7 @@ initcg(int cylno, time_t modtime, int fso, unsigned int Nflag)
DBG_FUNC("initcg")
static caddr_t iobuf;
long blkno, start;
+ ino_t ino;
ufs2_daddr_t i, cbase, dmax;
struct ufs1_dinode *dp1;
struct csum *cs;
@@ -392,8 +393,8 @@ initcg(int cylno, time_t modtime, int fso, unsigned int Nflag)
}
acg.cg_cs.cs_nifree += sblock.fs_ipg;
if (cylno == 0)
- for (i = 0; i < ROOTINO; i++) {
- setbit(cg_inosused(&acg), i);
+ for (ino = 0; ino < ROOTINO; ino++) {
+ setbit(cg_inosused(&acg), ino);
acg.cg_cs.cs_nifree--;
}
/*
@@ -803,7 +804,6 @@ updcsloc(time_t modtime, int fsi, int fso, unsigned int Nflag)
DBG_FUNC("updcsloc")
struct csum *cs;
int ocscg, ncscg;
- int blocks;
ufs2_daddr_t d;
int lcs = 0;
int block;
@@ -820,8 +820,6 @@ updcsloc(time_t modtime, int fsi, int fso, unsigned int Nflag)
}
ocscg = dtog(&osblock, osblock.fs_csaddr);
cs = fscs + ocscg;
- blocks = 1 + howmany(sblock.fs_cssize, sblock.fs_bsize) -
- howmany(osblock.fs_cssize, osblock.fs_bsize);
/*
* Read original cylinder group from disk, and make a copy.
@@ -1500,6 +1498,7 @@ main(int argc, char **argv)
}
sblock.fs_size = dbtofsb(&osblock, size / DEV_BSIZE);
+ sblock.fs_providersize = dbtofsb(&osblock, mediasize / DEV_BSIZE);
/*
* Are we really growing?
diff --git a/sbin/gvinum/Makefile b/sbin/gvinum/Makefile
index 8cccf56ecdbb..c9716e94670c 100644
--- a/sbin/gvinum/Makefile
+++ b/sbin/gvinum/Makefile
@@ -5,7 +5,7 @@ SRCS= gvinum.c gvinum.h geom_vinum_share.c
MAN= gvinum.8
WARNS?= 2
-CFLAGS= -I${.CURDIR}/../../sys -I${DESTDIR}/${INCLUDEDIR}/edit
+CFLAGS+= -I${.CURDIR}/../../sys -I${DESTDIR}/${INCLUDEDIR}/edit
DPADD= ${LIBEDIT} ${LIBTERMCAP} ${LIBDEVSTAT} ${LIBKVM} ${LIBGEOM}
LDADD= -ledit -ltermcap -ldevstat -lkvm -lgeom
diff --git a/sbin/hastd/hast.conf.5 b/sbin/hastd/hast.conf.5
index d78f539500c8..f6368bcf913e 100644
--- a/sbin/hastd/hast.conf.5
+++ b/sbin/hastd/hast.conf.5
@@ -63,7 +63,7 @@ checksum <algorithm>
compression <algorithm>
timeout <seconds>
exec <path>
-metaflush "on" | "off"
+metaflush on | off
pidfile <path>
on <node> {
@@ -89,14 +89,14 @@ resource <name> {
local <path>
timeout <seconds>
exec <path>
- metaflush "on" | "off"
+ metaflush on | off
on <node> {
# Resource-node section
name <name>
# Required
local <path>
- metaflush "on" | "off"
+ metaflush on | off
# Required
remote <addr>
source <addr>
@@ -106,7 +106,7 @@ resource <name> {
name <name>
# Required
local <path>
- metaflush "on" | "off"
+ metaflush on | off
# Required
remote <addr>
source <addr>
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
index 81d08eb648ad..88159cb6bec1 100644
--- a/sbin/hastd/primary.c
+++ b/sbin/hastd/primary.c
@@ -543,6 +543,27 @@ primary_connect(struct hast_resource *res, struct proto_conn **connp)
return (0);
}
+
+/*
+ * Function instructs GEOM_GATE to handle reads directly from within the kernel.
+ */
+static void
+enable_direct_reads(struct hast_resource *res)
+{
+ struct g_gate_ctl_modify ggiomodify;
+
+ bzero(&ggiomodify, sizeof(ggiomodify));
+ ggiomodify.gctl_version = G_GATE_VERSION;
+ ggiomodify.gctl_unit = res->hr_ggateunit;
+ ggiomodify.gctl_modify = GG_MODIFY_READPROV | GG_MODIFY_READOFFSET;
+ strlcpy(ggiomodify.gctl_readprov, res->hr_localpath,
+ sizeof(ggiomodify.gctl_readprov));
+ ggiomodify.gctl_readoffset = res->hr_localoff;
+ if (ioctl(res->hr_ggatefd, G_GATE_CMD_MODIFY, &ggiomodify) == 0)
+ pjdlog_debug(1, "Direct reads enabled.");
+ else
+ pjdlog_errno(LOG_WARNING, "Failed to enable direct reads");
+}
static int
init_remote(struct hast_resource *res, struct proto_conn **inp,
@@ -692,6 +713,8 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
res->hr_secondary_localcnt = nv_get_uint64(nvin, "localcnt");
res->hr_secondary_remotecnt = nv_get_uint64(nvin, "remotecnt");
res->hr_syncsrc = nv_get_uint8(nvin, "syncsrc");
+ if (res->hr_syncsrc == HAST_SYNCSRC_PRIMARY)
+ enable_direct_reads(res);
if (nv_exists(nvin, "virgin")) {
/*
* Secondary was reinitialized, bump localcnt if it is 0 as
@@ -990,36 +1013,33 @@ reqlog(int loglevel, int debuglevel, struct g_gate_ctl_io *ggio, const char *fmt
{
char msg[1024];
va_list ap;
- int len;
va_start(ap, fmt);
- len = vsnprintf(msg, sizeof(msg), fmt, ap);
+ (void)vsnprintf(msg, sizeof(msg), fmt, ap);
va_end(ap);
- if ((size_t)len < sizeof(msg)) {
- switch (ggio->gctl_cmd) {
- case BIO_READ:
- (void)snprintf(msg + len, sizeof(msg) - len,
- "READ(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
- break;
- case BIO_DELETE:
- (void)snprintf(msg + len, sizeof(msg) - len,
- "DELETE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
- break;
- case BIO_FLUSH:
- (void)snprintf(msg + len, sizeof(msg) - len, "FLUSH.");
- break;
- case BIO_WRITE:
- (void)snprintf(msg + len, sizeof(msg) - len,
- "WRITE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
- break;
- default:
- (void)snprintf(msg + len, sizeof(msg) - len,
- "UNKNOWN(%u).", (unsigned int)ggio->gctl_cmd);
- break;
- }
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ (void)snprlcat(msg, sizeof(msg), "READ(%ju, %ju).",
+ (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ case BIO_DELETE:
+ (void)snprlcat(msg, sizeof(msg), "DELETE(%ju, %ju).",
+ (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ case BIO_FLUSH:
+ (void)snprlcat(msg, sizeof(msg), "FLUSH.");
+ break;
+ case BIO_WRITE:
+ (void)snprlcat(msg, sizeof(msg), "WRITE(%ju, %ju).",
+ (uintmax_t)ggio->gctl_offset,
+ (uintmax_t)ggio->gctl_length);
+ break;
+ default:
+ (void)snprlcat(msg, sizeof(msg), "UNKNOWN(%u).",
+ (unsigned int)ggio->gctl_cmd);
+ break;
}
pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
}
@@ -1792,13 +1812,14 @@ sync_thread(void *arg __unused)
struct timeval tstart, tend, tdiff;
unsigned int ii, ncomp, ncomps;
off_t offset, length, synced;
- bool dorewind;
+ bool dorewind, directreads;
int syncext;
ncomps = HAST_NCOMPONENTS;
dorewind = true;
synced = 0;
offset = -1;
+ directreads = false;
for (;;) {
mtx_lock(&sync_lock);
@@ -1870,6 +1891,8 @@ sync_thread(void *arg __unused)
event_send(res, EVENT_SYNCDONE);
}
mtx_lock(&metadata_lock);
+ if (res->hr_syncsrc == HAST_SYNCSRC_SECONDARY)
+ directreads = true;
res->hr_syncsrc = HAST_SYNCSRC_UNDEF;
res->hr_primary_localcnt =
res->hr_secondary_remotecnt;
@@ -1883,6 +1906,10 @@ sync_thread(void *arg __unused)
mtx_unlock(&metadata_lock);
}
rw_unlock(&hio_remote_lock[ncomp]);
+ if (directreads) {
+ directreads = false;
+ enable_direct_reads(res);
+ }
continue;
}
pjdlog_debug(2, "sync: Taking free request.");
diff --git a/sbin/hastd/proto_common.c b/sbin/hastd/proto_common.c
index 59b1e39bb2fb..843366bda228 100644
--- a/sbin/hastd/proto_common.c
+++ b/sbin/hastd/proto_common.c
@@ -181,7 +181,7 @@ proto_descriptor_recv(int sock, int *fdp)
return (errno);
cmsg = CMSG_FIRSTHDR(&msg);
- if (cmsg->cmsg_level != SOL_SOCKET ||
+ if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
cmsg->cmsg_type != SCM_RIGHTS) {
return (EINVAL);
}
diff --git a/sbin/hastd/synch.h b/sbin/hastd/synch.h
index 36e19278921d..65360fd493ef 100644
--- a/sbin/hastd/synch.h
+++ b/sbin/hastd/synch.h
@@ -168,7 +168,7 @@ cv_timedwait(pthread_cond_t *cv, pthread_mutex_t *lock, int timeout)
return (false);
}
- error = clock_gettime(CLOCK_MONOTONIC, &ts);
+ error = clock_gettime(CLOCK_MONOTONIC, &ts);
PJDLOG_ASSERT(error == 0);
ts.tv_sec += timeout;
error = pthread_cond_timedwait(cv, lock, &ts);
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 0731238bf9bc..d74b0d21492b 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -509,8 +509,6 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
- DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE, setnd6flags),
- DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags),
DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
DEF_CMD_ARG("pltime", setip6pltime),
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 975605521513..f22cc50598ca 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd May 27, 2012
+.Dd July 9, 2012
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -716,12 +716,6 @@ Set a flag to enable Neighbor Unreachability Detection.
.It Cm -nud
Clear a flag
.Cm nud .
-.It Cm prefer_source
-Set a flag to prefer addresses on the interface as candidates of the
-source address for outgoing packets.
-.It Cm -prefer_source
-Clear a flag
-.Cm prefer_source .
.El
.Pp
The following parameters are specific to cloning
@@ -2051,7 +2045,7 @@ Send broadcast path requests every two seconds.
Nodes on the mesh without a path to this root mesh station with try to
discover a path to us.
.It Cm PROACTIVE
-Send broadcast path requests every two seconds and every node must reply with
+Send broadcast path requests every two seconds and every node must reply
with a path reply even if it already has a path to this root mesh station.
.It Cm RANN
Send broadcast root announcement (RANN) frames.
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 082e15d61e2a..870acdd0445c 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -916,7 +916,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
#define IFCAPBITS \
"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
"\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
-"\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
+"\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
"\26RXCSUM_IPV6\27TXCSUM_IPV6"
/*
@@ -1212,6 +1212,8 @@ static struct cmd basic_cmds[] = {
DEF_CMD("-tso4", -IFCAP_TSO4, setifcap),
DEF_CMD("tso", IFCAP_TSO, setifcap),
DEF_CMD("-tso", -IFCAP_TSO, setifcap),
+ DEF_CMD("toe", IFCAP_TOE, setifcap),
+ DEF_CMD("-toe", -IFCAP_TOE, setifcap),
DEF_CMD("lro", IFCAP_LRO, setifcap),
DEF_CMD("-lro", -IFCAP_LRO, setifcap),
DEF_CMD("wol", IFCAP_WOL, setifcap),
diff --git a/sbin/ipf/ipf/Makefile b/sbin/ipf/ipf/Makefile
index 0a5f4a82c3a2..62a9b47d6cca 100644
--- a/sbin/ipf/ipf/Makefile
+++ b/sbin/ipf/ipf/Makefile
@@ -2,8 +2,8 @@
PROG= ipf
SRCS= ${GENHDRS} ipf.c ipfcomp.c ipf_y.c ipf_l.c bpf_filter.c
-MAN= ipf.8 ipf.4 ipf.5 ipl.4
-MLINKS= ipl.4 ipfilter.4 ipf.5 ipf.conf.5 ipf.5 ipf6.conf.5
+MAN= ipfilter.4 ipfilter.5 ipf.8 ipf.4 ipf.5 ipl.4
+MLINKS= ipf.5 ipf.conf.5 ipf.5 ipf6.conf.5
CFLAGS+= -I. -DIPFILTER_BPF
GENHDRS= ipf_l.h ipf_y.h
diff --git a/sbin/ipfw/dummynet.c b/sbin/ipfw/dummynet.c
index 3719e9b5cd88..28dc2c77a020 100644
--- a/sbin/ipfw/dummynet.c
+++ b/sbin/ipfw/dummynet.c
@@ -759,7 +759,8 @@ load_extra_delays(const char *filename, struct dn_profile *p,
void
ipfw_config_pipe(int ac, char **av)
{
- int i, j;
+ int i;
+ u_int j;
char *end;
struct dn_id *buf, *base;
struct dn_sch *sch = NULL;
@@ -1282,8 +1283,8 @@ parse_range(int ac, char *av[], uint32_t *v, int len)
av--;
}
if (v[1] < v[0] ||
- v[1] < 0 || v[1] >= DN_MAX_ID-1 ||
- v[0] < 0 || v[1] >= DN_MAX_ID-1) {
+ v[1] >= DN_MAX_ID-1 ||
+ v[1] >= DN_MAX_ID-1) {
continue; /* invalid entry */
}
n++;
@@ -1310,11 +1311,12 @@ void
dummynet_list(int ac, char *av[], int show_counters)
{
struct dn_id *oid, *x = NULL;
- int ret, i, l;
+ int ret, i;
int n; /* # of ranges */
- int buflen;
- int max_size; /* largest obj passed up */
+ u_int buflen, l;
+ u_int max_size; /* largest obj passed up */
+ (void)show_counters; // XXX unused, but we should use it.
ac--;
av++; /* skip 'list' | 'show' word */
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 5d1625ea60a2..db0dfc0a505e 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 9, 2012
+.Dd October 25, 2012
.Dt IPFW 8
.Os
.Sh NAME
@@ -141,7 +141,7 @@ the firewall will have a
.Em stateful
behaviour, i.e., upon a match it will create
.Em dynamic rules ,
-i.e. rules that match packets with the same 5-tuple
+i.e., rules that match packets with the same 5-tuple
(protocol, source and destination addresses and ports)
as the packet which caused their creation.
Dynamic rules, which have a limited lifetime, are checked
@@ -223,14 +223,15 @@ When listing and
is specified, also show expired dynamic rules.
.It Fl f
Do not ask for confirmation for commands that can cause problems
-if misused,
-.No i.e. Cm flush .
+if misused, i.e.,
+.Cm flush .
If there is no tty associated with the process, this is implied.
.It Fl i
When listing a table (see the
.Sx LOOKUP TABLES
section below for more information on lookup tables), format values
-as IP addresses. By default, values are shown as integers.
+as IP addresses.
+By default, values are shown as integers.
.It Fl n
Only check syntax of the command strings, without actually passing
them to the kernel.
@@ -421,7 +422,7 @@ Keywords are case-sensitive, whereas arguments may
or may not be case-sensitive depending on their nature
(e.g.\& uid's are, hostnames are not).
.Pp
-Some arguments (e.g. port or address lists) are comma-separated
+Some arguments (e.g., port or address lists) are comma-separated
lists of values.
In this case, spaces after commas ',' are allowed to make
the line more readable.
@@ -560,7 +561,22 @@ is set to 0 (default), one can use
.Xr bpf 4
attached to the
.Li ipfw0
-pseudo interface. There is no overhead if no
+pseudo interface.
+This pseudo interface can be created after a boot
+manually by using the following command:
+.Bd -literal -offset indent
+# ifconfig ipfw0 create
+.Ed
+.Pp
+Or, automatically at boot time by adding the following
+line to the
+.Xr rc.conf 5
+file:
+.Bd -literal -offset indent
+firewall_logif="YES"
+.Ed
+.Pp
+There is no overhead if no
.Xr bpf 4
is attached to the pseudo interface.
.Pp
@@ -758,11 +774,6 @@ This makes the
.Xr netstat 1
entry look rather weird but is intended for
use with transparent proxy servers.
-.Pp
-To enable
-.Cm fwd
-a custom kernel needs to be compiled with the option
-.Cd "options IPFIREWALL_FORWARD" .
.It Cm nat Ar nat_nr | tablearg
Pass packet to a
nat instance
@@ -858,7 +869,8 @@ Takes rule number saved to internal stack by the last
action and returns ruleset processing to the first rule
with number greater than number of corresponding
.Cm call
-rule. See description of the
+rule.
+See description of the
.Cm call
action for more details.
.Pp
@@ -940,28 +952,36 @@ actions.
The packet is tagged so as to use the FIB (routing table)
.Ar fibnum
in any subsequent forwarding decisions.
-Initially this is limited to the values 0 through 15, see
-.Xr setfib 1 .
+In the current implementation, this is limited to the values 0 through 15, see
+.Xr setfib 2 .
Processing continues at the next rule.
It is possible to use the
.Cm tablearg
-keyword with a setfib. If tablearg value is not within compiled FIB range packet fib is set to 0.
+keyword with setfib.
+If the tablearg value is not within the compiled range of fibs,
+the packet's fib is set to 0.
.It Cm reass
-Queue and reassemble ip fragments.
-If the packet is not fragmented, counters are updated and processing continues with the next rule.
+Queue and reassemble IP fragments.
+If the packet is not fragmented, counters are updated and
+processing continues with the next rule.
If the packet is the last logical fragment, the packet is reassembled and, if
.Va net.inet.ip.fw.one_pass
-is set to 0, processing continues with the next rule, else packet is allowed to pass and search terminates.
-If the packet is a fragment in the middle, it is consumed and processing stops immediately.
+is set to 0, processing continues with the next rule.
+Otherwise, the packet is allowed to pass and the search terminates.
+If the packet is a fragment in the middle of a logical group of fragments,
+it is consumed and
+processing stops immediately.
.Pp
-Fragments handling can be tuned via
+Fragment handling can be tuned via
.Va net.inet.ip.maxfragpackets
and
.Va net.inet.ip.maxfragsperpacket
-which limit, respectively, the maximum number of processable fragments (default: 800) and
+which limit, respectively, the maximum number of processable
+fragments (default: 800) and
the maximum number of fragments per packet (default: 16).
.Pp
-NOTA BENE: since fragments do not contain port numbers, they should be avoided with the
+NOTA BENE: since fragments do not contain port numbers,
+they should be avoided with the
.Nm reass
rule.
Alternatively, direction-based (like
@@ -1581,7 +1601,8 @@ This is the short form of
.It Cm sockarg
Matches packets that are associated to a local socket and
for which the SO_USER_COOKIE socket option has been set
-to a non-zero value. As a side effect, the value of the
+to a non-zero value.
+As a side effect, the value of the
option is made available as
.Cm tablearg
value, which in turn can be used as
@@ -1731,9 +1752,9 @@ connected networks instead of all source addresses.
.El
.Sh LOOKUP TABLES
Lookup tables are useful to handle large sparse sets of
-addresses or other search keys (e.g. ports, jail IDs, interface names).
+addresses or other search keys (e.g., ports, jail IDs, interface names).
In the rest of this section we will use the term ``address''.
-There may be up to 4096 different lookup tables, numbered 0 to 4095.
+There may be up to 65535 different lookup tables, numbered 0 to 65534.
.Pp
Each entry is represented by an
.Ar addr Ns Op / Ns Ar masklen
@@ -1769,7 +1790,8 @@ the routing table (see
.Xr route 4 ) .
.Pp
Lookup tables currently support only ports, jail IDs, IPv4/IPv6 addresses
-and interface names. Wildcards is not supported for interface names.
+and interface names.
+Wildcards is not supported for interface names.
.Pp
The
.Cm tablearg
@@ -1798,7 +1820,8 @@ Section for example usage of tables and the tablearg keyword.
When used with the
.Cm skipto
action, the user should be aware that the code will walk the ruleset
-up to a rule equal to, or past, the given number, and should therefore try keep the
+up to a rule equal to, or past, the given number,
+and should therefore try keep the
ruleset compact between the skipto and the target rules.
.Sh SETS OF RULES
Each rule belongs to one of 32 different
@@ -2006,10 +2029,12 @@ As an example, using ``src-ip 0xffffff00'' creates one instance
for each /24 destination subnet.
.Pp
The FLOW_MASK, together with the SCHED_MASK, is used to split
-packets into flows. As an example, using
+packets into flows.
+As an example, using
``src-ip 0x000000ff''
together with the previous SCHED_MASK makes a flow for
-each individual source address. In turn, flows for each /24
+each individual source address.
+In turn, flows for each /24
subnet will be sent to the same scheduler instance.
.Pp
The above diagram holds even for the
@@ -2128,12 +2153,13 @@ A file specifying the additional overhead incurred in the transmission
of a packet on the link.
.Pp
Some link types introduce extra delays in the transmission
-of a packet, e.g. because of MAC level framing, contention on
+of a packet, e.g., because of MAC level framing, contention on
the use of the channel, MAC level retransmissions and so on.
From our point of view, the channel is effectively unavailable
for this extra time, which is constant or variable depending
-on the link type. Additionally, packets may be dropped after this
-time (e.g. on a wireless link after too many retransmissions).
+on the link type.
+Additionally, packets may be dropped after this
+time (e.g., on a wireless link after too many retransmissions).
We can model the additional delay with an empirical curve
that represents its distribution.
.Bd -literal -offset indent
@@ -2169,7 +2195,7 @@ If not specified here, it must be present
explicitly as a configuration parameter for the pipe;
.It Cm loss-level Ar L
the probability above which packets are lost.
-(0.0 <= L <= 1.0, default 1.0 i.e. no loss);
+(0.0 <= L <= 1.0, default 1.0 i.e., no loss);
.It Cm samples Ar N
the number of samples used in the internal
representation of the curve (2..1024; default 100);
@@ -2218,22 +2244,24 @@ Specifies the weight to be used for flows matching this queue.
The weight must be in the range 1..100, and defaults to 1.
.El
.Pp
-The following parameters can be configured for a scheduler:
+The following case-insensitive parameters can be configured for a
+scheduler:
.Pp
.Bl -tag -width indent -compact
-.It Cm type Ar {fifo | wf2qp | rr | qfq}
+.It Cm type Ar {fifo | wf2q+ | rr | qfq}
specifies the scheduling algorithm to use.
.Bl -tag -width indent -compact
-.It cm fifo
+.It Cm fifo
is just a FIFO scheduler (which means that all packets
are stored in the same queue as they arrive to the scheduler).
FIFO has O(1) per-packet time complexity, with very low
constants (estimate 60-80ns on a 2GHz desktop machine)
but gives no service guarantees.
-.It Cm wf2qp
+.It Cm wf2q+
implements the WF2Q+ algorithm, which is a Weighted Fair Queueing
algorithm which permits flows to share bandwidth according to
-their weights. Note that weights are not priorities; even a flow
+their weights.
+Note that weights are not priorities; even a flow
with a minuscule weight will never starve.
WF2Q+ has O(log N) per-packet processing cost, where N is the number
of flows, and is the default algorithm used by previous versions
@@ -2519,7 +2547,8 @@ in
.Xr natd 8
for more information.
.It Cm tablearg
-Uses argument supplied in lookup table. See
+Uses argument supplied in lookup table.
+See
.Sx LOOKUP TABLES
section below for more information on lookup tables.
.El
@@ -2581,11 +2610,13 @@ or
before ipfw module gets loaded.
.Bl -tag -width indent
.It Va net.inet.ip.fw.default_to_accept: No 0
-Defines ipfw last rule behavior. This value overrides
+Defines ipfw last rule behavior.
+This value overrides
.Cd "options IPFW_DEFAULT_TO_(ACCEPT|DENY)"
from kernel configuration file.
.It Va net.inet.ip.fw.tables_max: No 128
-Defines number of tables available in ipfw. Number cannot exceed 65534.
+Defines number of tables available in ipfw.
+Number cannot exceed 65534.
.El
.Sh SYSCTL VARIABLES
A set of
@@ -2615,12 +2646,14 @@ Option 1 should never be selected as this forms a security risk.
An attacker can
establish multiple fake associations by sending AddIP messages.
.It Va net.inet.ip.alias.sctp.chunk_proc_limit: No 5
-Defines the maximum number of chunks in an SCTP packet that will be parsed for a
+Defines the maximum number of chunks in an SCTP packet that will be
+parsed for a
packet that matches an existing association.
This value is enforced to be greater or equal than
.Cm net.inet.ip.alias.sctp.initialising_chunk_proc_limit .
A high value is
-a DoS risk yet setting too low a value may result in important control chunks in
+a DoS risk yet setting too low a value may result in
+important control chunks in
the packet not being located and parsed.
.It Va net.inet.ip.alias.sctp.error_on_ootb: No 1
Defines when the
@@ -2642,7 +2675,8 @@ This value is only useful if the
.Nm nat
is tracking global IP addresses.
.It Cm 3
-ErrorM is sent in response to all OOTB packets on both the local and global side
+ErrorM is sent in response to all OOTB packets on both
+the local and global side
(DoS risk).
.El
.Pp
@@ -2693,12 +2727,14 @@ will only be an INIT or ASCONF-AddIP packet.
A higher value may become a DoS
risk as malformed packets can consume processing resources.
.It Va net.inet.ip.alias.sctp.param_proc_limit: No 25
-Defines the maximum number of parameters within a chunk that will be parsed in a
+Defines the maximum number of parameters within a chunk that will be
+parsed in a
packet.
As for other similar sysctl variables, larger values pose a DoS risk.
.It Va net.inet.ip.alias.sctp.log_level: No 0
Level of detail in the system log messages (0 \- minimal, 1 \- event,
-2 \- info, 3 \- detail, 4 \- debug, 5 \- max debug). May be a good
+2 \- info, 3 \- detail, 4 \- debug, 5 \- max debug).
+May be a good
option in high loss environments.
.It Va net.inet.ip.alias.sctp.shutdown_time: No 15
Timeout value while waiting for SHUTDOWN-COMPLETE.
@@ -2717,7 +2753,8 @@ association is limited to this value
.El
.Pp
This variable is fully dynamic, the new value will be adopted for all newly
-arriving associations, existing associations are treated as they were previously.
+arriving associations, existing associations are treated
+as they were previously.
Global tracking will decrease the number of collisions within the
.Nm nat
at a cost
@@ -2951,9 +2988,11 @@ This will let the firewall install dynamic rules only for
those connection which start with a regular SYN packet coming
from the inside of our network.
Dynamic rules are checked when encountering the first
-.Cm check-state
-or
+occurrence of a
+.Cm check-state ,
.Cm keep-state
+or
+.Cm limit
rule.
A
.Cm check-state
@@ -3262,7 +3301,8 @@ Some early work (1999-2000) on the
traffic shaper supported by Akamba Corp.
.Pp
The ipfw core (ipfw2) has been completely redesigned and
-reimplemented by Luigi Rizzo in summer 2002. Further
+reimplemented by Luigi Rizzo in summer 2002.
+Further
actions and
options have been added by various developer over the years.
.Pp
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index dd22ad0c6e4a..530f3195a1f2 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -412,7 +412,7 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
* and calls setsockopt().
* Function returns 0 on success or -1 otherwise.
*/
-int
+static int
do_setcmd3(int optname, void *optval, socklen_t optlen)
{
socklen_t len;
@@ -976,8 +976,9 @@ print_icmptypes(ipfw_insn_u32 *cmd)
#define HAVE_OPTIONS 0x8000
static void
-show_prerequisites(int *flags, int want, int cmd __unused)
+show_prerequisites(int *flags, int want, int cmd)
{
+ (void)cmd; /* UNUSED */
if (co.comment_only)
return;
if ( (*flags & HAVE_IP) == HAVE_IP)
@@ -3930,6 +3931,7 @@ ipfw_table_handler(int ac, char *av[])
uint32_t a, type, mask, addrlen;
uint32_t tables_max;
+ mask = 0; // XXX uninitialized ?
len = sizeof(tables_max);
if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
NULL, 0) == -1)
@@ -4135,7 +4137,7 @@ table_list(uint16_t num, int need_header)
if (sz < xent->len)
break;
sz -= xent->len;
- xent = (void *)xent + xent->len;
+ xent = (ipfw_table_xentry *)((char *)xent + xent->len);
}
free(tbl);
diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c
index ee93d989aed2..6326590a46af 100644
--- a/sbin/ipfw/ipv6.c
+++ b/sbin/ipfw/ipv6.c
@@ -336,24 +336,40 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
* Note d[1] points to struct in6_add r mask6 of cmd
*/
- cmd->o.len &= ~F_LEN_MASK; /* zero len */
+ cmd->o.len &= ~F_LEN_MASK; /* zero len */
- if (strcmp(av, "any") == 0)
- return (1);
+ if (strcmp(av, "any") == 0)
+ return (1);
- if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
- cmd->o.len |= F_INSN_SIZE(ipfw_insn);
- return (1);
- }
+ if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ return (1);
+ }
- if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/
- cmd->o.len |= F_INSN_SIZE(ipfw_insn);
- return (1);
- }
+ if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ return (1);
+ }
+
+ if (strncmp(av, "table(", 6) == 0) {
+ char *p = strchr(av + 6, ',');
+ uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d;
+
+ if (p)
+ *p++ = '\0';
+ cmd->o.opcode = O_IP_DST_LOOKUP;
+ cmd->o.arg1 = strtoul(av + 6, NULL, 0);
+ if (p) {
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
+ dm[0] = strtoul(p, NULL, 0);
+ } else
+ cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ return (1);
+ }
- av = strdup(av);
- while (av) {
+ av = strdup(av);
+ while (av) {
/*
* After the address we can have '/' indicating a mask,
* or ',' indicating another address follows.
@@ -469,7 +485,11 @@ add_srcip6(ipfw_insn *cmd, char *av)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av);
- if (F_LEN(cmd) == 0) { /* any */
+ if (cmd->opcode == O_IP_DST_SET) /* set */
+ cmd->opcode = O_IP_SRC_SET;
+ else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
+ cmd->opcode = O_IP_SRC_LOOKUP;
+ else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_SRC_ME;
} else if (F_LEN(cmd) ==
@@ -487,7 +507,11 @@ add_dstip6(ipfw_insn *cmd, char *av)
{
fill_ip6((ipfw_insn_ip6 *)cmd, av);
- if (F_LEN(cmd) == 0) { /* any */
+ if (cmd->opcode == O_IP_DST_SET) /* set */
+ ;
+ else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
+ ;
+ else if (F_LEN(cmd) == 0) { /* any */
} else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
cmd->opcode = O_IP6_DST_ME;
} else if (F_LEN(cmd) ==
diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c
index 6bec36c27396..bff28e156c77 100644
--- a/sbin/ipfw/nat.c
+++ b/sbin/ipfw/nat.c
@@ -318,6 +318,7 @@ estimate_redir_addr(int *ac, char ***av)
char *sep = **av;
u_int c = 0;
+ (void)ac; /* UNUSED */
while ((sep = strchr(sep, ',')) != NULL) {
c++;
sep++;
@@ -379,6 +380,7 @@ estimate_redir_port(int *ac, char ***av)
char *sep = **av;
u_int c = 0;
+ (void)ac; /* UNUSED */
while ((sep = strchr(sep, ',')) != NULL) {
c++;
sep++;
@@ -419,7 +421,7 @@ setup_redir_port(char *buf, int *ac, char ***av)
/*
* Extract local address.
*/
- if ((sep = strchr(**av, ',')) != NULL) {
+ if (strchr(**av, ',') != NULL) {
r->laddr.s_addr = INADDR_NONE;
r->lport = ~0;
numLocalPorts = 1;
@@ -452,7 +454,7 @@ setup_redir_port(char *buf, int *ac, char ***av)
/*
* Extract public port and optionally address.
*/
- if ((sep = strchr(**av, ':')) != NULL) {
+ if (strchr(**av, ':') != NULL) {
if (StrToAddrAndPortRange(**av, &r->paddr, protoName,
&portRange) != 0)
errx(EX_DATAERR, "redirect_port: "
@@ -480,7 +482,7 @@ setup_redir_port(char *buf, int *ac, char ***av)
* option for this redirect entry, else stop here processing arg[cv].
*/
if (*ac != 0 && isdigit(***av)) {
- if ((sep = strchr(**av, ':')) != NULL) {
+ if (strchr(**av, ':') != NULL) {
if (StrToAddrAndPortRange(**av, &r->raddr, protoName,
&portRange) != 0)
errx(EX_DATAERR, "redirect_port: "
diff --git a/sbin/md5/Makefile b/sbin/md5/Makefile
index 7df4d859c93b..c3c5a9fe77fd 100644
--- a/sbin/md5/Makefile
+++ b/sbin/md5/Makefile
@@ -5,11 +5,13 @@ PROG= md5
LINKS= ${BINDIR}/md5 ${BINDIR}/rmd160 \
${BINDIR}/md5 ${BINDIR}/sha1 \
- ${BINDIR}/md5 ${BINDIR}/sha256
+ ${BINDIR}/md5 ${BINDIR}/sha256 \
+ ${BINDIR}/md5 ${BINDIR}/sha512
MLINKS= md5.1 rmd160.1 \
md5.1 sha1.1 \
- md5.1 sha256.1
+ md5.1 sha256.1 \
+ md5.1 sha512.1
WFORMAT?= 1
diff --git a/sbin/md5/md5.1 b/sbin/md5/md5.1
index 0dfb145669d6..04efa3750d06 100644
--- a/sbin/md5/md5.1
+++ b/sbin/md5/md5.1
@@ -1,9 +1,9 @@
.\" $FreeBSD$
-.Dd September 7, 2008
+.Dd July 31, 2012
.Dt MD5 1
.Os
.Sh NAME
-.Nm md5 , sha1 , sha256 , rmd160
+.Nm md5 , sha1 , sha256 , sha512, rmd160
.Nd calculate a message-digest fingerprint (checksum) for a file
.Sh SYNOPSIS
.Nm md5
@@ -21,6 +21,11 @@
.Op Fl c Ar string
.Op Fl s Ar string
.Op Ar
+.Nm sha512
+.Op Fl pqrtx
+.Op Fl c Ar string
+.Op Fl s Ar string
+.Op Ar
.Nm rmd160
.Op Fl pqrtx
.Op Fl c Ar string
@@ -28,7 +33,7 @@
.Op Ar
.Sh DESCRIPTION
The
-.Nm md5 , sha1 , sha256
+.Nm md5 , sha1 , sha256 , sha512
and
.Nm rmd160
utilities take as input a message of arbitrary length and produce as
@@ -41,7 +46,7 @@ It is conjectured that it is computationally infeasible to
produce two messages having the same message digest, or to produce any
message having a given prespecified target message digest.
The
-.Tn MD5 , SHA-1 , SHA-256
+.Tn MD5 , SHA-1 , SHA-256 , SHA-512
and
.Tn RIPEMD-160
algorithms are intended for digital signature applications, where a
@@ -104,7 +109,7 @@ Run a built-in test script.
.El
.Sh EXIT STATUS
The
-.Nm md5 , sha1 , sha256
+.Nm md5 , sha1 , sha256 , sha512
and
.Nm rmd160
utilities exit 0 on success,
@@ -115,7 +120,8 @@ and 2 if at least one file does not have the same hash as the -c option.
.Xr md5 3 ,
.Xr ripemd 3 ,
.Xr sha 3 ,
-.Xr sha256 3
+.Xr sha256 3 ,
+.Xr sha512 3
.Rs
.%A R. Rivest
.%T The MD5 Message-Digest Algorithm
diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c
index 29d50bb708fc..823d09b2c08a 100644
--- a/sbin/md5/md5.c
+++ b/sbin/md5/md5.c
@@ -28,6 +28,7 @@ __FBSDID("$FreeBSD$");
#include <ripemd.h>
#include <sha.h>
#include <sha256.h>
+#include <sha512.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -54,6 +55,7 @@ typedef char *(DIGEST_End)(void *, char *);
extern const char *MD5TestOutput[MDTESTCOUNT];
extern const char *SHA1_TestOutput[MDTESTCOUNT];
extern const char *SHA256_TestOutput[MDTESTCOUNT];
+extern const char *SHA512_TestOutput[MDTESTCOUNT];
extern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
typedef struct Algorithm_t {
@@ -78,12 +80,14 @@ typedef union {
MD5_CTX md5;
SHA1_CTX sha1;
SHA256_CTX sha256;
+ SHA512_CTX sha512;
RIPEMD160_CTX ripemd160;
} DIGEST_CTX;
/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
- SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
-#define HEX_DIGEST_LENGTH 65
+ SHA256_DIGEST_LENGTH, SHA512_DIGEST_LENGTH,
+ RIPEMD160_DIGEST_LENGTH)*2+1 */
+#define HEX_DIGEST_LENGTH 129
/* algorithm function table */
@@ -97,6 +101,9 @@ struct Algorithm_t Algorithm[] = {
{ "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init,
(DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End,
&SHA256_Data, &SHA256_File },
+ { "sha512", "SHA512", &SHA512_TestOutput, (DIGEST_Init*)&SHA512_Init,
+ (DIGEST_Update*)&SHA512_Update, (DIGEST_End*)&SHA512_End,
+ &SHA512_Data, &SHA512_File },
{ "rmd160", "RMD160", &RIPEMD160_TestOutput,
(DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
(DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
@@ -320,6 +327,17 @@ const char *SHA256_TestOutput[MDTESTCOUNT] = {
"e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f"
};
+const char *SHA512_TestOutput[MDTESTCOUNT] = {
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+ "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+ "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c",
+ "4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1",
+ "1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894",
+ "72ec1ef1124a45b047e8b7c75a932195135bb61de24ec0d1914042246e0aec3a2354e093d76f3048b456764346900cb130d2a4fd5dd16abb5e30bcb850dee843",
+ "e8a835195e039708b13d9131e025f4441dbdc521ce625f245a436dcd762f54bf5cb298d96235e6c6a304e087ec8189b9512cbdf6427737ea82793460c367b9c3"
+};
+
const char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
"9c1185a5c5e9fc54612808977ee8f548b2258d31",
"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
diff --git a/sbin/mdconfig/Makefile b/sbin/mdconfig/Makefile
index f4d8adcfde8d..be8b1b556dde 100644
--- a/sbin/mdconfig/Makefile
+++ b/sbin/mdconfig/Makefile
@@ -2,7 +2,6 @@
PROG= mdconfig
MAN= mdconfig.8
-MLINKS= mdconfig.8 vnconfig.8
DPADD= ${LIBUTIL} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF}
LDADD= -lutil -lgeom -lbsdxml -lsbuf
diff --git a/sbin/mdconfig/mdconfig.8 b/sbin/mdconfig/mdconfig.8
index 41141370bbc9..89f150e8d1a4 100644
--- a/sbin/mdconfig/mdconfig.8
+++ b/sbin/mdconfig/mdconfig.8
@@ -41,7 +41,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 21, 2012
+.Dd June 27, 2012
.Dt MDCONFIG 8
.Os
.Sh NAME
@@ -64,6 +64,11 @@
.Fl u Ar unit
.Op Fl o Oo Cm no Oc Ns Ar force
.Nm
+.Fl r
+.Fl u Ar unit
+.Fl s Ar size
+.Op Fl o Oo Cm no Oc Ns Ar force
+.Nm
.Fl l
.Op Fl n
.Op Fl v
@@ -85,6 +90,8 @@ This will configure and attach a memory disk with the
parameters specified and attach it to the system.
.It Fl d
Detach a memory disk from the system and release all resources.
+.It Fl r
+Resize a memory disk.
.It Fl t Ar type
Select the type of the memory disk.
.Bl -tag -width "malloc"
@@ -148,7 +155,7 @@ and
.Fl t Ar swap
options are implied if not specified.
.It Fl S Ar sectorsize
-Sectorsize to use for malloc backed device.
+Sectorsize to use for the memory disk, in bytes.
.It Fl x Ar sectors/track
See the description of the
.Fl y
diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c
index 122fc7d09c06..55d1567ca970 100644
--- a/sbin/mdconfig/mdconfig.c
+++ b/sbin/mdconfig/mdconfig.c
@@ -54,7 +54,7 @@
#include <unistd.h>
static struct md_ioctl mdio;
-static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET;
+static enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET;
static int nflag;
static void usage(void);
@@ -81,6 +81,7 @@ usage(void)
" [-s size] [-S sectorsize] [-u unit]\n"
" [-x sectors/track] [-y heads/cylinder]\n"
" mdconfig -d -u unit [-o [no]force]\n"
+" mdconfig -r -u unit -s size [-o [no]force]\n"
" mdconfig -l [-v] [-n] [-u unit]\n"
" mdconfig file\n");
fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
@@ -96,7 +97,7 @@ main(int argc, char **argv)
{
int ch, fd, i, vflag;
char *p;
- char *fflag = NULL, *tflag = NULL, *uflag = NULL;
+ char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL;
bzero(&mdio, sizeof(mdio));
mdio.md_file = malloc(PATH_MAX);
@@ -108,25 +109,32 @@ main(int argc, char **argv)
if (argc == 1)
usage();
- while ((ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:vx:y:")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:")) != -1) {
switch (ch) {
case 'a':
if (action != UNSET && action != ATTACH)
- errx(1,
- "-a is mutually exclusive with -d and -l");
+ errx(1, "-a is mutually exclusive "
+ "with -d, -r, and -l");
action = ATTACH;
break;
case 'd':
if (action != UNSET && action != DETACH)
- errx(1,
- "-d is mutually exclusive with -a and -l");
+ errx(1, "-d is mutually exclusive "
+ "with -a, -r, and -l");
action = DETACH;
mdio.md_options |= MD_AUTOUNIT;
break;
+ case 'r':
+ if (action != UNSET && action != RESIZE)
+ errx(1, "-r is mutually exclusive "
+ "with -a, -d, and -l");
+ action = RESIZE;
+ mdio.md_options |= MD_AUTOUNIT;
+ break;
case 'l':
if (action != UNSET && action != LIST)
- errx(1,
- "-l is mutually exclusive with -a and -d");
+ errx(1, "-l is mutually exclusive "
+ "with -a, -r, and -d");
action = LIST;
mdio.md_options |= MD_AUTOUNIT;
break;
@@ -188,6 +196,9 @@ main(int argc, char **argv)
mdio.md_sectorsize = strtoul(optarg, &p, 0);
break;
case 's':
+ if (sflag != NULL)
+ errx(1, "-s can be passed only once");
+ sflag = optarg;
mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
if (p == NULL || *p == '\0')
mdio.md_mediasize *= DEV_BSIZE;
@@ -242,7 +253,7 @@ main(int argc, char **argv)
mdio.md_type = MD_VNODE;
mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
MD_COMPRESS;
- } else if (mdio.md_mediasize != 0) {
+ } else if (sflag != NULL) {
/* Imply ``-t swap'' */
mdio.md_type = MD_SWAP;
mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
@@ -276,15 +287,15 @@ main(int argc, char **argv)
}
if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) &&
- mdio.md_mediasize == 0)
+ sflag == NULL)
errx(1, "must specify -s for -t malloc or -t swap");
if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
errx(1, "must specify -f for -t vnode");
} else {
if (mdio.md_sectorsize != 0)
errx(1, "-S can only be used with -a");
- if (mdio.md_mediasize != 0)
- errx(1, "-s can only be used with -a");
+ if (action != RESIZE && sflag != NULL)
+ errx(1, "-s can only be used with -a and -r");
if (mdio.md_fwsectors != 0)
errx(1, "-x can only be used with -a");
if (mdio.md_fwheads != 0)
@@ -295,13 +306,20 @@ main(int argc, char **argv)
errx(1, "-t can only be used with -a");
if (argc > 0)
errx(1, "file can only be used with -a");
- if (action != DETACH && (mdio.md_options & ~MD_AUTOUNIT) != 0)
- errx(1, "-o can only be used with -a and -d");
+ if ((action != DETACH && action != RESIZE) &&
+ (mdio.md_options & ~MD_AUTOUNIT) != 0)
+ errx(1, "-o can only be used with -a, -d, and -r");
if (action == DETACH &&
(mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0)
errx(1, "only -o [no]force can be used with -d");
+ if (action == RESIZE &&
+ (mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0)
+ errx(1, "only -o [no]force and -o [no]reserve can be used with -r");
}
+ if (action == RESIZE && sflag == NULL)
+ errx(1, "must specify -s for -r");
+
if (action != LIST && vflag == OPT_VERBOSE)
errx(1, "-v can only be used with -l");
@@ -333,6 +351,12 @@ main(int argc, char **argv)
i = ioctl(fd, MDIOCDETACH, &mdio);
if (i < 0)
err(1, "ioctl(/dev/%s)", MDCTL_NAME);
+ } else if (action == RESIZE) {
+ if (mdio.md_options & MD_AUTOUNIT)
+ errx(1, "-r requires -u");
+ i = ioctl(fd, MDIOCRESIZE, &mdio);
+ if (i < 0)
+ err(1, "ioctl(/dev/%s)", MDCTL_NAME);
} else if (action == LIST) {
if (mdio.md_options & MD_AUTOUNIT) {
/*
@@ -342,7 +366,6 @@ main(int argc, char **argv)
md_list(NULL, OPT_LIST | vflag);
} else
return (md_query(uflag));
-
} else
usage();
close(fd);
diff --git a/sbin/mount/getmntopts.3 b/sbin/mount/getmntopts.3
index b8380adb7267..48c69404572b 100644
--- a/sbin/mount/getmntopts.3
+++ b/sbin/mount/getmntopts.3
@@ -70,8 +70,8 @@ has the following format:
.Bd -literal
struct mntopt {
char *m_option; /* option name */
- int m_inverse; /* is this a negative option, e.g. "dev" */
- int m_flag; /* bit to set, e.g. MNT_RDONLY */
+ int m_inverse; /* is this a negative option, e.g., "dev" */
+ int m_flag; /* bit to set, e.g., MNT_RDONLY */
int m_altloc; /* non-zero to use altflagp rather than flagp */
};
.Ed
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index e1673780f8df..6bc4b5cc565b 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
-.Dd June 6, 2011
+.Dd July 12, 2012
.Dt MOUNT 8
.Os
.Sh NAME
@@ -145,6 +145,11 @@ When used with the
.Fl u
flag, this is the same as specifying the options currently in effect for
the mounted file system.
+.It Cm failok
+If this option is specified,
+.Nm
+will return 0 even if an error occurs
+during the mount of the filesystem.
.It Cm force
The same as
.Fl f ;
@@ -171,7 +176,8 @@ Force
.Nm
to use the specified program to mount the file system, instead of calling
.Xr nmount 2
-directly. For example:
+directly.
+For example:
.Bd -literal
mount -t foofs -o mountprog=/mydir/fooprog /dev/acd0 /mnt
.Ed
@@ -440,12 +446,8 @@ However, for the following file system types:
.Cm mfs ,
.Cm msdosfs ,
.Cm nfs ,
-.Cm ntfs ,
-.Cm nwfs ,
.Cm nullfs ,
.Cm oldnfs ,
-.Cm portalfs ,
-.Cm smbfs ,
.Cm udf ,
and
.Cm unionfs .
@@ -539,11 +541,7 @@ support for a particular file system might be provided either on a static
.Xr mount_cd9660 8 ,
.Xr mount_msdosfs 8 ,
.Xr mount_nfs 8 ,
-.Xr mount_ntfs 8 ,
.Xr mount_nullfs 8 ,
-.Xr mount_nwfs 8 ,
-.Xr mount_portalfs 8 ,
-.Xr mount_smbfs 8 ,
.Xr mount_udf 8 ,
.Xr mount_unionfs 8 ,
.Xr umount 8 ,
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
index ca81795c0d69..1984eaced0f7 100644
--- a/sbin/mount/mount.c
+++ b/sbin/mount/mount.c
@@ -142,8 +142,8 @@ use_mountprog(const char *vfstype)
*/
unsigned int i;
const char *fs[] = {
- "cd9660", "mfs", "msdosfs", "nfs", "ntfs",
- "nwfs", "nullfs", "oldnfs", "portalfs", "smbfs", "udf", "unionfs",
+ "cd9660", "mfs", "msdosfs", "nfs",
+ "nullfs", "oldnfs", "udf", "unionfs",
NULL
};
diff --git a/sbin/mount_fusefs/Makefile b/sbin/mount_fusefs/Makefile
new file mode 100644
index 000000000000..0af8a80c8c99
--- /dev/null
+++ b/sbin/mount_fusefs/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+.if defined(DEBUG)
+DEBUG_FLAGS+= -D_DEBUG -g
+.endif
+
+.if defined(DEBUG2G)
+DEBUG_FLAGS+= -D_DEBUG2G -g
+.endif
+
+.if defined(DEBUG3G)
+DEBUG_FLAGS+= -D_DEBUG3G -g
+.endif
+
+.if defined(DEBUG_MSG)
+DEBUG_FLAGS+= -D_DEBUG_MSG
+.endif
+
+.if defined(F4BVERS)
+DEBUG_FLAGS+= -DFUSE4BSD_VERSION="\"${F4BVERS}\""
+.endif
+
+PROG= mount_fusefs
+SRCS= mount_fusefs.c getmntopts.c
+MAN8= mount_fusefs.8
+NO_MANCOMPRESS?= yes
+
+MOUNT= ${.CURDIR}/../mount
+CFLAGS+= -I${MOUNT}
+
+.PATH: ${MOUNT}
+
+.include <bsd.prog.mk>
diff --git a/sbin/mount_fusefs/mount_fusefs.8 b/sbin/mount_fusefs/mount_fusefs.8
new file mode 100644
index 000000000000..7c8bb67a7771
--- /dev/null
+++ b/sbin/mount_fusefs/mount_fusefs.8
@@ -0,0 +1,363 @@
+.\" Copyright (c) 1980, 1989, 1991, 1993
+.\" The Regents of the University of California.
+.\" Copyright (c) 2005, 2006 Csaba Henk
+.\" 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.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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$
+.\"
+.Dd October 11, 2012
+.Dt MOUNT_FUSEFS 8
+.Os
+.Sh NAME
+.Nm mount_fusefs
+.Nd mount a Fuse file system daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl A
+.Op Fl S
+.Op Fl v
+.Op Fl D Ar fuse_daemon
+.Op Fl O Ar daemon_opts
+.Op Fl s Ar special
+.Op Fl m Ar node
+.Op Fl h
+.Op Fl V
+.Op Fl o Ar option ...
+.Ar special node
+.Op Ar fuse_daemon ...
+.Sh DESCRIPTION
+Basic usage is to start a fuse daemon on the given
+.Ar special
+file. In practice, the daemon is assigned a
+.Ar special
+file automatically, which can then be indentified via
+.Xr fstat 1 .
+That special file can then be mounted by
+.Nm .
+.Pp
+However, the procedure of spawning a daemon will usually be automated
+so that it is performed by
+.Nm .
+If the command invoking a given
+.Ar fuse_daemon
+is appended to the list of arguments,
+.Nm
+will call the
+.Ar fuse_daemon
+via that command. In that way the
+.Ar fuse_daemon
+will be instructed to attach itself to
+.Ar special .
+From that on mounting goes as in the simple case. (See
+.Sx DAEMON MOUNTS . )
+.Pp
+The
+.Ar special
+argument will normally be treated as the path of the special file to mount.
+.Pp
+However, if
+.Pa auto
+is passed as
+.Ar special ,
+then
+.Nm
+will look for a suitable free fuse device by itself.
+.Pp
+Finally, if
+.Ar special
+is an integer it will be interpreted as the number
+of the file descriptor of an already open fuse device
+(used when the Fuse library invokes
+.Nm .
+(See
+.Sx DAEMON MOUNTS ) .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A , Ic --reject-allow_other
+Prohibit the
+.Cm allow_other
+mount flag. Intended for use in scripts and the
+.Xr sudoers 5
+file.
+.It Fl S , Ic --safe
+Run in safe mode (i.e. reject invoking a filesystem daemon)
+.It Fl v
+Be verbose
+.It Fl D, Ic --daemon Ar daemon
+Call the specified
+.Ar daemon
+.It Fl O, Ic --daemon_opts Ar opts
+Add
+.Ar opts
+to the daemon's command line
+.It Fl s, Ic --special Ar special
+Use
+.Ar special
+as special
+.It Fl m, Ic --mountpath Ar node
+Mount on
+.Ar node
+.It Fl h, Ic --help
+Show help
+.It Fl V, Ic --version
+Show version information
+.It Fl o
+Mount options are specified via
+.Fl o .
+The following options are available (and also their negated versions,
+by prefixing them with
+.Dq no ) :
+.Bl -tag -width indent
+.It Cm default_permissions
+Enable traditional (file mode based) permission checking in kernel
+.It Cm allow_other
+Do not apply
+.Sx STRICT ACCESS POLICY .
+Only root can use this option
+.It Cm max_read Ns = Ns Ar n
+Limit size of read requests to
+.Ar n
+.It Cm private
+Refuse shared mounting of the daemon. This is the default behaviour,
+to allow sharing, expicitly use
+.Fl o Cm noprivate
+.It Cm neglect_shares
+Do not refuse unmounting if there are secondary mounts
+.It Cm push_symlinks_in
+Prefix absolute symlinks with the mountpoint
+.El
+.Pp
+.El
+.Pp
+Besides the above mount options, there is a set of pseudo-mount options which
+are supported by the Fuse library. One can list these by passing
+.Fl h
+to a Fuse daemon. Most of these options have effect only on the behaviour of
+the daemon (that is, their scope is limited to userspace). However,
+there are some which do require in-kernel support.
+Currently the options supported by the kernel are:
+.Bl -tag -width indent
+.It Cm direct_io
+Bypass the buffer cache system
+.It Cm kernel_cache
+By default cached buffers of a given file are flushed at each
+.Xr open 2 .
+This option disables this behaviour
+.El
+.Sh DAEMON MOUNTS
+Usually users do not need to use
+.Nm
+directly, as the Fuse library enables Fuse daemons to invoke
+.Nm .
+That is,
+.Pp
+.Dl fuse_daemon device mountpoint
+.Pp
+has the same effect as
+.Pp
+.Dl mount_fusefs auto mountpoint fuse_daemon
+.Pp
+This is the recommended usage when you want basic usage
+(eg, run the daemon at a low privilege level but mount it as root).
+.Sh STRICT ACCESS POLICY
+The strict access policy for Fuse filesystems lets one to use the filesystem
+only if the filesystem daemon has the same credentials (uid, real uid, gid,
+real gid) as the user.
+.Pp
+This is applied for Fuse mounts by default and only root can mount without
+the strict access policy (ie. the
+.Cm allow_other
+mount option).
+.Pp
+This is to shield users from the daemon
+.Dq spying
+on their I/O activities.
+.Pp
+Users might opt to willingly relax strict access policy (as far they
+are concerned) by doing their own secondary mount (See
+.Sx SHARED MOUNTS ) .
+.Sh SHARED MOUNTS
+A Fuse daemon can be shared (ie. mounted multiple times).
+When doing the first (primary) mount, the spawner and the mounter of the daemon
+must have the same uid, or the mounter should be the superuser.
+.Pp
+After the primary mount is in place, secondary mounts can be done by anyone
+unless this feature is disabled by
+.Cm private .
+The behaviour of a secondary mount is analogous to that of symbolic
+links: they redirect all filesystem operations to the primary mount.
+.Pp
+Doing a secondary mount is like signing an agreement: by this action, the mounter
+agrees that the Fuse daemon can trace her I/O activities. From then on
+she is not banned from using the filesystem (either via her own mount or
+via the primary mount), regardless whether
+.Cm allow_other
+is used or not.
+.Pp
+The device name of a secondary mount is the device name of the corresponding
+primary mount, followed by a '#' character and the index of the secondary
+mount; e.g.
+.Pa /dev/fuse0#3 .
+.Sh SECURITY
+System administrators might want to use a custom mount policy (ie., one going
+beyond the
+.Va vfs.usermount
+sysctl). The primary tool for such purposes is
+.Xr sudo 8 .
+However, given that
+.Nm
+is capable of invoking an arbitrary program, one must be careful when doing this.
+.Nm
+is designed in a way such that it makes that easy. For this purpose,
+there are options which disable certain risky features (ie.
+.Fl S
+and
+.Fl A ) ,
+and command line parsing is done in a flexible way: mixing options and
+non-options is allowed, but processing them stops at the third non-option
+argument (after the first two has been utilized as device and mountpoint).
+The rest of the command line specifies the daemon and its arguments.
+(Alternatively, the daemon, the special and the mount path can be
+specified using the respective options.) Note that
+.Nm
+ignores the environment variable
+.Ev POSIXLY_CORRECT
+and always behaves as described.
+.Pp
+In general, to be as scripting /
+.Xr sudoers 5
+friendly as possible, no information has a fixed
+position in the command line, but once a given piece of information is
+provided, subsequent arguments/options cannot override it (with the
+exception of some non-critical ones).
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev MOUNT_FUSEFS_SAFE"
+.It Ev MOUNT_FUSEFS_SAFE
+This has the same effect as the
+.Fl S
+option.
+.It Ev MOUNT_FUSEFS_VERBOSE
+This has the same effect as the
+.Fl v
+option.
+.It Ev MOUNT_FUSEFS_IGNORE_UNKNOWN
+If set,
+.Nm
+will ignore uknown mount options.
+.It Ev MOUNT_FUSEFS_CALL_BY_LIB
+Adjust behaviour to the needs of the FUSE library. Currently it effects
+help output.
+.El
+.Pp
+Although the following variables do not have any effect on
+.Nm
+itself, they affect the behaviour of fuse daemons:
+.Bl -tag -width ".Ev FUSE_DEV_NAME"
+.It Ev FUSE_DEV_NAME
+Device to attach. If not set, the multiplexer path
+.Ar /dev/fuse
+is used.
+.It Ev FUSE_DEV_FD
+File desciptor of an opened Fuse device to use. Overrides
+.Ev FUSE_DEV_NAME .
+.It Ev FUSE_NO_MOUNT
+If set, the library will not attempt to mount the filesystem, even
+if a mountpoint argument is supplied.
+.El
+.Sh FILES
+.Bl -tag -width /dev/fuse
+.It Pa /dev/fuse
+Fuse device with which the kernel and Fuse daemons can communicate.
+.It Pa /dev/fuse
+The multiplexer path. An
+.Xr open 2
+performed on it automatically is passed to a free Fuse device by the kernel
+(which might be created just for this puprose).
+.El
+.Sh EXAMPLES
+Mount the example filesystem in the Fuse distribution (from its directory):
+either
+.Pp
+.Dl ./fusexmp /mnt/fuse
+.Pp
+or
+.Pp
+.Dl mount_fusefs auto /mnt/fuse ./fusexmp
+.Pp
+Doing the same in two steps, using
+.Pa /dev/fuse0 :
+.Pp
+.Dl FUSE_DEV_NAME=/dev/fuse ./fusexmp &&
+.Dl mount_fusefs /dev/fuse /mnt/fuse
+.Pp
+A script wrapper for fusexmp which ensures that
+.Nm
+does not call any external utility and also provides a hacky
+(non race-free) automatic device selection:
+.Pp
+.Dl #!/bin/sh -e
+.Pp
+.Dl FUSE_DEV_NAME=/dev/fuse fusexmp
+.Dl mount_fusefs -S /dev/fuse /mnt/fuse \(lq$@\(rq
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr mount 8 ,
+.Xr umount 8 ,
+.Xr sudo 8
+.Sh HISTORY
+.Nm
+appears as the part of the FreeBSD implementation of the Fuse userspace filesystem
+framework (see http://fuse.sourceforge.net). This user interface is FreeBSD specific.
+.Sh CAVEATS
+Secondary mounts should be unmounted via their device name. If an attempt is
+made to be unmount them via their filesystem root path, the unmount request
+will be forwarded to the primary mount path.
+In general, unmounting by device name is less error-prone than by mount path
+(although the latter will also work under normal circumstances).
+.Pp
+If the daemon is specified via the
+.Fl D
+and
+.Fl O
+options, it will be invoked via
+.Xr system 3 ,
+and the daemon's command line will also have an
+.Dq &
+control operator appended, so that we do not have to wait for its termination.
+You should use a simple command line when invoking the daemon via these options.
+.Sh BUGS
+.Ar special
+is treated as a multiplexer if and only if it is literally the same as
+.Pa auto
+or
+.Pa /dev/fuse .
+Other paths which are equivalent with
+.Pa /dev/fuse
+(eg.,
+.Pa /../dev/fuse )
+are not.
diff --git a/sbin/mount_fusefs/mount_fusefs.c b/sbin/mount_fusefs/mount_fusefs.c
new file mode 100644
index 000000000000..797aba7228a4
--- /dev/null
+++ b/sbin/mount_fusefs/mount_fusefs.c
@@ -0,0 +1,499 @@
+/*-
+ * Copyright (c) 2005 Jean-Sebastien Pedron
+ * Copyright (c) 2005 Csaba Henk
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <getopt.h>
+#include <limits.h>
+#include <osreldate.h>
+#include <paths.h>
+
+#include "mntopts.h"
+
+#ifndef FUSE4BSD_VERSION
+#define FUSE4BSD_VERSION "0.3.9-pre1"
+#endif
+
+void __usage_short(void);
+void usage(void);
+void helpmsg(void);
+void showversion(void);
+int init_backgrounded(void);
+
+static struct mntopt mopts[] = {
+ #define ALTF_PRIVATE 0x01
+ { "private", 0, ALTF_PRIVATE, 1 },
+ { "neglect_shares", 0, 0x02, 1 },
+ { "push_symlinks_in", 0, 0x04, 1 },
+ { "allow_other", 0, 0x08, 1 },
+ { "default_permissions", 0, 0x10, 1 },
+ #define ALTF_MAXREAD 0x20
+ { "max_read=", 0, ALTF_MAXREAD, 1 },
+ #define ALTF_SUBTYPE 0x40
+ { "subtype=", 0, ALTF_SUBTYPE, 1 },
+ #define ALTF_SYNC_UNMOUNT 0x80
+ { "sync_unmount", 0, ALTF_SYNC_UNMOUNT, 1 },
+ /* Linux specific options, we silently ignore them */
+ { "fsname=", 0, 0x00, 1 },
+ { "fd=", 0, 0x00, 1 },
+ { "rootmode=", 0, 0x00, 1 },
+ { "user_id=", 0, 0x00, 1 },
+ { "group_id=", 0, 0x00, 1 },
+ { "large_read", 0, 0x00, 1 },
+ /* "nonempty", just the first two chars are stripped off during parsing */
+ { "nempty", 0, 0x00, 1 },
+ MOPT_STDOPTS,
+ MOPT_END
+};
+
+struct mntval {
+ int mv_flag;
+ void *mv_value;
+ int mv_len;
+};
+
+static struct mntval mvals[] = {
+ { ALTF_MAXREAD, NULL, 0 },
+ { ALTF_SUBTYPE, NULL, 0 },
+ { 0, NULL, 0 }
+};
+
+#define DEFAULT_MOUNT_FLAGS ALTF_PRIVATE | ALTF_SYNC_UNMOUNT
+
+int
+main(int argc, char *argv[])
+{
+ struct iovec *iov;
+ int mntflags, iovlen, verbose = 0;
+ char *dev = NULL, *dir = NULL, mntpath[MAXPATHLEN];
+ char *devo = NULL, *diro = NULL;
+ char ndev[128], fdstr[15];
+ int i, done = 0, reject_allow_other = 0, safe_level = 0;
+ int altflags = DEFAULT_MOUNT_FLAGS;
+ int __altflags = DEFAULT_MOUNT_FLAGS;
+ int ch = 0;
+ struct mntopt *mo;
+ struct mntval *mv;
+ static struct option longopts[] = {
+ {"reject-allow_other", no_argument, NULL, 'A'},
+ {"safe", no_argument, NULL, 'S'},
+ {"daemon", required_argument, NULL, 'D'},
+ {"daemon_opts", required_argument, NULL, 'O'},
+ {"special", required_argument, NULL, 's'},
+ {"mountpath", required_argument, NULL, 'm'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'h'},
+ {0,0,0,0}
+ };
+ int pid = 0;
+ int fd = -1, fdx;
+ char *ep;
+ char *daemon_str = NULL, *daemon_opts = NULL;
+
+ /*
+ * We want a parsing routine which is not sensitive to
+ * the position of args/opts; it should extract the
+ * first two args and stop at the beginning of the rest.
+ * (This makes it easier to call mount_fusefs from external
+ * utils than it is with a strict "util flags args" syntax.)
+ */
+
+ iov = NULL;
+ iovlen = 0;
+ mntflags = 0;
+ /* All in all, I feel it more robust this way... */
+ unsetenv("POSIXLY_CORRECT");
+ if (getenv("MOUNT_FUSEFS_IGNORE_UNKNOWN"))
+ getmnt_silent = 1;
+ if (getenv("MOUNT_FUSEFS_VERBOSE"))
+ verbose = 1;
+
+ do {
+ for (i = 0; i < 3; i++) {
+ if (optind < argc && argv[optind][0] != '-') {
+ if (dir) {
+ done = 1;
+ break;
+ }
+ if (dev)
+ dir = argv[optind];
+ else
+ dev = argv[optind];
+ optind++;
+ }
+ }
+ switch(ch) {
+ case 'A':
+ reject_allow_other = 1;
+ break;
+ case 'S':
+ safe_level = 1;
+ break;
+ case 'D':
+ if (daemon_str)
+ errx(1, "daemon specified inconsistently");
+ daemon_str = optarg;
+ break;
+ case 'O':
+ if (daemon_opts)
+ errx(1, "daemon opts specified inconsistently");
+ daemon_opts = optarg;
+ break;
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags, &altflags);
+ for (mv = mvals; mv->mv_flag; ++mv) {
+ if (! (altflags & mv->mv_flag))
+ continue;
+ for (mo = mopts; mo->m_flag; ++mo) {
+ char *p, *q;
+
+ if (mo->m_flag != mv->mv_flag)
+ continue;
+ p = strstr(optarg, mo->m_option);
+ if (p) {
+ p += strlen(mo->m_option);
+ q = p;
+ while (*q != '\0' && *q != ',')
+ q++;
+ mv->mv_len = q - p + 1;
+ mv->mv_value = malloc(mv->mv_len);
+ memcpy(mv->mv_value, p, mv->mv_len - 1);
+ ((char *)mv->mv_value)[mv->mv_len - 1] = '\0';
+ break;
+ }
+ }
+ }
+ break;
+ case 's':
+ if (devo)
+ errx(1, "special specified inconsistently");
+ devo = optarg;
+ break;
+ case 'm':
+ if (diro)
+ errx(1, "mount path specified inconsistently");
+ diro = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'h':
+ helpmsg();
+ break;
+ case 'V':
+ showversion();
+ break;
+ case '\0':
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ if (done)
+ break;
+ } while ((ch = getopt_long(argc, argv, "AvVho:SD:O:s:m:", longopts, NULL)) != -1);
+
+ argc -= optind;
+ argv += optind;
+
+ if (devo) {
+ if (dev)
+ errx(1, "special specified inconsistently");
+ dev = devo;
+ } else if (diro)
+ errx(1, "if mountpoint is given via an option, special should also be given via an option");
+
+ if (diro) {
+ if (dir)
+ errx(1, "mount path specified inconsistently");
+ dir = diro;
+ }
+
+ if ((! dev) && argc > 0) {
+ dev = *argv++;
+ argc--;
+ }
+
+ if ((! dir) && argc > 0) {
+ dir = *argv++;
+ argc--;
+ }
+
+ if (! (dev && dir))
+ errx(1, "missing special and/or mountpoint");
+
+ for (mo = mopts; mo->m_flag; ++mo) {
+ if (altflags & mo->m_flag) {
+ int iov_done = 0;
+
+ if (reject_allow_other &&
+ strcmp(mo->m_option, "allow_other") == 0)
+ /*
+ * reject_allow_other is stronger than a
+ * negative of allow_other: if this is set,
+ * allow_other is blocked, period.
+ */
+ errx(1, "\"allow_other\" usage is banned by respective option");
+
+ for (mv = mvals; mv->mv_flag; ++mv) {
+ if (mo->m_flag != mv->mv_flag)
+ continue;
+ if (mv->mv_value) {
+ build_iovec(&iov, &iovlen, mo->m_option, mv->mv_value, mv->mv_len);
+ iov_done = 1;
+ break;
+ }
+ }
+ if (! iov_done)
+ build_iovec(&iov, &iovlen, mo->m_option,
+ __DECONST(void *, ""), -1);
+ }
+ if (__altflags & mo->m_flag) {
+ char *uscore_opt;
+
+ if (asprintf(&uscore_opt, "__%s", mo->m_option) == -1)
+ err(1, "failed to allocate memory");
+ build_iovec(&iov, &iovlen, uscore_opt,
+ __DECONST(void *, ""), -1);
+ free(uscore_opt);
+ }
+ }
+
+ if (getenv("MOUNT_FUSEFS_SAFE"))
+ safe_level = 1;
+
+ if (safe_level > 0 && (argc > 0 || daemon_str || daemon_opts))
+ errx(1, "safe mode, spawning daemon not allowed");
+
+ if ((argc > 0 && (daemon_str || daemon_opts)) ||
+ (daemon_opts && ! daemon_str))
+ errx(1, "daemon specified inconsistently");
+
+ /*
+ * Resolve the mountpoint with realpath(3) and remove unnecessary
+ * slashes from the devicename if there are any.
+ */
+ if (checkpath(dir, mntpath) != 0)
+ err(1, "%s", mntpath);
+ (void)rmslashes(dev, dev);
+
+ if (strcmp(dev, "auto") == 0)
+ dev = __DECONST(char *, "/dev/fuse");
+
+ if (strcmp(dev, "/dev/fuse") == 0) {
+ if (! (argc > 0 || daemon_str)) {
+ fprintf(stderr, "Please also specify the fuse daemon to run when mounting via the multiplexer!\n");
+ usage();
+ }
+ if ((fd = open(dev, O_RDWR)) < 0)
+ err(1, "failed to open fuse device");
+ } else {
+ fdx = strtol(dev, &ep, 10);
+ if (*ep == '\0')
+ fd = fdx;
+ }
+
+ /* Identifying device */
+ if (fd >= 0) {
+ struct stat sbuf;
+ char *ndevbas, *lep;
+
+ if (fstat(fd, &sbuf) == -1)
+ err(1, "cannot stat device file descriptor");
+
+ strcpy(ndev, _PATH_DEV);
+ ndevbas = ndev + strlen(_PATH_DEV);
+ devname_r(sbuf.st_rdev, S_IFCHR, ndevbas,
+ sizeof(ndev) - strlen(_PATH_DEV));
+
+ if (strncmp(ndevbas, "fuse", 4))
+ errx(1, "mounting inappropriate device");
+
+ strtol(ndevbas + 4, &lep, 10);
+ if (*lep != '\0')
+ errx(1, "mounting inappropriate device");
+
+ dev = ndev;
+ }
+
+ if (argc > 0 || daemon_str) {
+ char *fds;
+
+ if (fd < 0 && (fd = open(dev, O_RDWR)) < 0)
+ err(1, "failed to open fuse device");
+
+ if (asprintf(&fds, "%d", fd) == -1)
+ err(1, "failed to allocate memory");
+ setenv("FUSE_DEV_FD", fds, 1);
+ free(fds);
+ setenv("FUSE_NO_MOUNT", "1", 1);
+
+ if (daemon_str) {
+ char *bgdaemon;
+ int len;
+
+ if (! daemon_opts)
+ daemon_opts = __DECONST(char *, "");
+
+ len = strlen(daemon_str) + 1 + strlen(daemon_opts) +
+ 2 + 1;
+ bgdaemon = calloc(1, len);
+
+ if (! bgdaemon)
+ err(1, "failed to allocate memory");
+
+ strlcpy(bgdaemon, daemon_str, len);
+ strlcat(bgdaemon, " ", len);
+ strlcat(bgdaemon, daemon_opts, len);
+ strlcat(bgdaemon, " &", len);
+
+ if (system(bgdaemon))
+ err(1, "failed to call fuse daemon");
+ } else {
+ if ((pid = fork()) < 0)
+ err(1, "failed to fork for fuse daemon");
+
+ if (pid == 0) {
+ execvp(argv[0], argv);
+ err(1, "failed to exec fuse daemon");
+ }
+ }
+ }
+
+ if (fd >= 0 && ! init_backgrounded() && close(fd) < 0) {
+ if (pid)
+ kill(pid, SIGKILL);
+ err(1, "failed to close fuse device");
+ }
+
+ /* Prepare the options vector for nmount(). build_iovec() is declared
+ * in mntopts.h. */
+ sprintf(fdstr, "%d", fd);
+ build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1);
+ build_iovec(&iov, &iovlen, "fspath", mntpath, -1);
+ build_iovec(&iov, &iovlen, "from", dev, -1);
+ build_iovec(&iov, &iovlen, "fd", fdstr, -1);
+
+ if (verbose)
+ fprintf(stderr, "mounting fuse daemon on device %s\n", dev);
+
+ if (nmount(iov, iovlen, mntflags) < 0)
+ err(EX_OSERR, "%s on %s", dev, mntpath);
+
+ exit(0);
+}
+
+void
+__usage_short(void) {
+ fprintf(stderr,
+ "usage:\n%s [-A|-S|-v|-V|-h|-D daemon|-O args|-s special|-m node|-o option...] special node [daemon args...]\n\n",
+ getprogname());
+}
+
+void
+usage(void)
+{
+ struct mntopt *mo;
+
+ __usage_short();
+
+ fprintf(stderr, "known options:\n");
+ for (mo = mopts; mo->m_flag; ++mo)
+ fprintf(stderr, "\t%s\n", mo->m_option);
+
+ fprintf(stderr, "\n(use -h for a detailed description of these options)\n");
+ exit(EX_USAGE);
+}
+
+void
+helpmsg(void)
+{
+ if (! getenv("MOUNT_FUSEFS_CALL_BY_LIB")) {
+ __usage_short();
+ fprintf(stderr, "description of options:\n");
+ }
+
+ /*
+ * The main use case of this function is giving info embedded in general
+ * FUSE lib help output. Therefore the style and the content of the output
+ * tries to fit there as much as possible.
+ */
+ fprintf(stderr,
+ " -o allow_other allow access to other users\n"
+ /* " -o nonempty allow mounts over non-empty file/dir\n" */
+ " -o default_permissions enable permission checking by kernel\n"
+ /*
+ " -o fsname=NAME set filesystem name\n"
+ " -o large_read issue large read requests (2.4 only)\n"
+ */
+ " -o subtype=NAME set filesystem type\n"
+ " -o max_read=N set maximum size of read requests\n"
+ " -o noprivate allow secondary mounting of the filesystem\n"
+ " -o neglect_shares don't report EBUSY when unmount attempted\n"
+ " in presence of secondary mounts\n"
+ " -o push_symlinks_in prefix absolute symlinks with mountpoint\n"
+ " -o sync_unmount do unmount synchronously\n"
+ );
+ exit(EX_USAGE);
+}
+
+void
+showversion(void)
+{
+ puts("mount_fusefs [fuse4bsd] version: " FUSE4BSD_VERSION);
+ exit(EX_USAGE);
+}
+
+int
+init_backgrounded(void)
+{
+ int ibg;
+ size_t len;
+
+ len = sizeof(ibg);
+
+ if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
+ return (0);
+
+ return (ibg);
+}
diff --git a/sbin/natd/natd.8 b/sbin/natd/natd.8
index cba4ed4a48d2..b4b37ed1fb5d 100644
--- a/sbin/natd/natd.8
+++ b/sbin/natd/natd.8
@@ -130,9 +130,9 @@ According to RFC 1918, unregistered source addresses are 10.0.0.0/8,
172.16.0.0/12 and 192.168.0.0/16.
.It Fl redirect_port Ar proto Xo
.Ar targetIP Ns : Ns Xo
-.Ar targetPORT Ns Op - Ns Ar targetPORT Xc
-.Op Ar aliasIP Ns : Ns Xo
-.Ar aliasPORT Ns Op - Ns Ar aliasPORT Xc
+.Ar targetPORT Ns Oo - Ns Ar targetPORT Oc Xc
+.Oo Ar aliasIP Ns : Oc Ns Xo
+.Ar aliasPORT Ns Oo - Ns Ar aliasPORT Oc Xc
.Oo Ar remoteIP Ns Oo : Ns
.Ar remotePORT Ns Op - Ns Ar remotePORT
.Oc Oc
@@ -247,10 +247,8 @@ to appear from the specified
.Ar targetIP Ns : Ns Xo
.Ar targetPORT Ns Oo , Ns
.Ar ...\&
-.Oc Oc
-.Xc
-.Xc
-.Op Ar aliasIP Ns : Ns Xo
+.Oc Xc Oc Xc
+.Oo Ar aliasIP Ns : Oc Ns Xo
.Ar aliasPORT
.Xc
.Oo Ar remoteIP Ns
diff --git a/sbin/natd/natd.c b/sbin/natd/natd.c
index 3dbfef0fe958..959e1eeaf52c 100644
--- a/sbin/natd/natd.c
+++ b/sbin/natd/natd.c
@@ -1330,7 +1330,7 @@ static void ParseOption (const char* option, const char* parms)
struct in_addr addrValue;
int max;
char* end;
- CODE* fac_record = NULL;
+ const CODE* fac_record = NULL;
/*
* Find option from table.
*/
@@ -1509,7 +1509,7 @@ static void ParseOption (const char* option, const char* parms)
break;
case LogIpfwDenied:
- logIpfwDenied = yesNoValue;;
+ logIpfwDenied = yesNoValue;
break;
case PidFile:
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c
index 5e2a57955907..0a547f90e3bc 100644
--- a/sbin/newfs/mkfs.c
+++ b/sbin/newfs/mkfs.c
@@ -263,6 +263,7 @@ restart:
}
sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
+ sblock.fs_providersize = dbtofsb(&sblock, mediasize / sectorsize);
/*
* Before the filesystem is finally initialized, mark it
@@ -1003,7 +1004,8 @@ iput(union dinode *ip, ino_t ino)
sblock.fs_cstotal.cs_nifree--;
fscs[0].cs_nifree--;
if (ino >= (unsigned long)sblock.fs_ipg * sblock.fs_ncg) {
- printf("fsinit: inode value out of range (%d).\n", ino);
+ printf("fsinit: inode value out of range (%ju).\n",
+ (uintmax_t)ino);
exit(32);
}
d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c
index 61637749c212..3ce0be75f687 100644
--- a/sbin/newfs/newfs.c
+++ b/sbin/newfs/newfs.c
@@ -94,6 +94,7 @@ int lflag; /* enable multilabel for file system */
int nflag; /* do not create .snap directory */
int tflag; /* enable TRIM */
intmax_t fssize; /* file system size */
+off_t mediasize; /* device size */
int sectorsize; /* bytes/sector */
int realsectorsize; /* bytes/sector in hardware */
int fsize = 0; /* fragment size */
@@ -135,7 +136,6 @@ main(int argc, char *argv[])
char *cp, *special;
intmax_t reserved;
int ch, i, rval;
- off_t mediasize;
char part_name; /* partition name, default to full disk */
part_name = 'c';
diff --git a/sbin/newfs/newfs.h b/sbin/newfs/newfs.h
index 25bfcc8f68fa..9e1da0db8924 100644
--- a/sbin/newfs/newfs.h
+++ b/sbin/newfs/newfs.h
@@ -88,6 +88,7 @@ extern int lflag; /* enable multilabel MAC for file system */
extern int nflag; /* do not create .snap directory */
extern int tflag; /* enable TRIM */
extern intmax_t fssize; /* file system size */
+extern off_t mediasize; /* device size */
extern int sectorsize; /* bytes/sector */
extern int realsectorsize; /* bytes/sector in hardware*/
extern int fsize; /* fragment size */
diff --git a/sbin/nvmecontrol/Makefile b/sbin/nvmecontrol/Makefile
new file mode 100644
index 000000000000..04cefaaa191e
--- /dev/null
+++ b/sbin/nvmecontrol/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG= nvmecontrol
+MAN= nvmecontrol.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
new file mode 100644
index 000000000000..e726cbc08927
--- /dev/null
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -0,0 +1,86 @@
+.\"
+.\" Copyright (c) 2012 Intel Corporation
+.\" 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,
+.\" without modification.
+.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
+.\" substantially similar to the "NO WARRANTY" disclaimer below
+.\" ("Disclaimer") and any redistribution must be conditioned upon
+.\" including a substantially similar Disclaimer requirement for further
+.\" binary redistribution.
+.\"
+.\" NO WARRANTY
+.\" 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 MERCHANTIBILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+.\"
+.\" nvmecontrol man page.
+.\"
+.\" Author: Jim Harris <jimharris@FreeBSD.org>
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 17, 2012
+.Dt NVMECONTROL 8
+.Os
+.Sh NAME
+.Nm nvmecontrol
+.Nd NVM Express control utility
+.Sh SYNOPSIS
+.Nm
+.Ic devlist
+.Nm
+.Ic identify
+.Op Fl v
+.Op Fl x
+.Aq device id
+.Nm
+.Ic perftest
+.Aq Fl n Ar num_threads
+.Aq Fl o Ar read|write
+.Op Fl p
+.Aq Fl s Ar size_in_bytes
+.Aq Fl t Ar time_in_sec
+.Aq device id
+.Sh DESCRIPTION
+NVM Express (NVMe) is a storage protocol standard, for SSDs and other
+high-speed storage devices over PCI Express.
+.Sh EXAMPLES
+.Dl nvmecontrol devlist
+.Pp
+Display a list of NVMe controllers and namespaces along with their device nodes.
+.Dl nvmecontrol identify nvme0
+.Pp
+Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data.
+.Pp
+.Dl nvmecontrol identify -x -v nvme0ns1
+.Pp
+Display a hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace
+1.
+.Pp
+.Dl nvmecontrol perftest -n 32 -o read -s 512 -t 30 nvme0ns1
+.Pp
+Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. Each
+thread will issue a single 512 byte read command. Results are printed to
+stdout when 30 seconds expires.
+.Sh AUTHORS
+.An -nosplit
+.Nm
+was developed by Intel and originally written by
+.An Jim Harris Aq jimharris@FreeBSD.org .
+.Pp
+This man page was written by
+.An Jim Harris Aq jimharris@FreeBSD.org .
diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c
new file mode 100644
index 000000000000..6abd3f5d1d7a
--- /dev/null
+++ b/sbin/nvmecontrol/nvmecontrol.c
@@ -0,0 +1,600 @@
+/*-
+ * Copyright (C) 2012 Intel Corporation
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+
+#include <dev/nvme/nvme.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#define DEVLIST_USAGE \
+" nvmecontrol devlist\n"
+
+#define IDENTIFY_USAGE \
+" nvmecontrol identify <controller id|namespace id>\n"
+
+#define PERFTEST_USAGE \
+" nvmecontrol perftest <-n num_threads> <-o read|write>\n" \
+" <-s size_in_bytes> <-t time_in_seconds>\n" \
+" <-i intr|wait> [-f refthread] [-p]\n" \
+" <namespace id>\n"
+
+static void perftest_usage(void);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, DEVLIST_USAGE);
+ fprintf(stderr, IDENTIFY_USAGE);
+ fprintf(stderr, PERFTEST_USAGE);
+ exit(EX_USAGE);
+}
+
+static void
+print_controller_hex(struct nvme_controller_data *cdata, uint32_t length)
+{
+ uint32_t *p;
+ uint32_t i, j;
+
+ p = (uint32_t *)cdata;
+ length /= sizeof(uint32_t);
+
+ for (i = 0; i < length; i+=8) {
+ printf("%03x: ", i*4);
+ for (j = 0; j < 8; j++)
+ printf("%08x ", p[i+j]);
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+static void
+print_controller(struct nvme_controller_data *cdata)
+{
+ printf("Controller Capabilities/Features\n");
+ printf("================================\n");
+ printf("Vendor ID: %04x\n", cdata->vid);
+ printf("Subsystem Vendor ID: %04x\n", cdata->ssvid);
+ printf("Serial Number: %s\n", cdata->sn);
+ printf("Model Number: %s\n", cdata->mn);
+ printf("Firmware Version: %s\n", cdata->fr);
+ printf("Recommended Arb Burst: %d\n", cdata->rab);
+ printf("IEEE OUI Identifier: %02x %02x %02x\n",
+ cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
+ printf("Multi-Interface Cap: %02x\n", cdata->mic);
+ /* TODO: Use CAP.MPSMIN to determine true memory page size. */
+ printf("Max Data Transfer Size: ");
+ if (cdata->mdts == 0)
+ printf("Unlimited\n");
+ else
+ printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
+ printf("\n");
+
+ printf("Admin Command Set Attributes\n");
+ printf("============================\n");
+ printf("Security Send/Receive: %s\n",
+ cdata->oacs.security ? "Supported" : "Not Supported");
+ printf("Format NVM: %s\n",
+ cdata->oacs.format ? "Supported" : "Not Supported");
+ printf("Firmware Activate/Download: %s\n",
+ cdata->oacs.firmware ? "Supported" : "Not Supported");
+ printf("Abort Command Limit: %d\n", cdata->acl+1);
+ printf("Async Event Request Limit: %d\n", cdata->aerl+1);
+ printf("Number of Firmware Slots: ");
+ if (cdata->oacs.firmware != 0)
+ printf("%d\n", cdata->frmw.num_slots);
+ else
+ printf("N/A\n");
+ printf("Firmware Slot 1 Read-Only: ");
+ if (cdata->oacs.firmware != 0)
+ printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
+ else
+ printf("N/A\n");
+ printf("Per-Namespace SMART Log: %s\n",
+ cdata->lpa.ns_smart ? "Yes" : "No");
+ printf("Error Log Page Entries: %d\n", cdata->elpe+1);
+ printf("Number of Power States: %d\n", cdata->npss+1);
+ printf("\n");
+
+ printf("NVM Command Set Attributes\n");
+ printf("==========================\n");
+ printf("Submission Queue Entry Size\n");
+ printf(" Max: %d\n", 1 << cdata->sqes.max);
+ printf(" Min: %d\n", 1 << cdata->sqes.min);
+ printf("Completion Queue Entry Size\n");
+ printf(" Max: %d\n", 1 << cdata->cqes.max);
+ printf(" Min: %d\n", 1 << cdata->cqes.min);
+ printf("Number of Namespaces: %d\n", cdata->nn);
+ printf("Compare Command: %s\n",
+ cdata->oncs.compare ? "Supported" : "Not Supported");
+ printf("Write Uncorrectable Command: %s\n",
+ cdata->oncs.write_unc ? "Supported" : "Not Supported");
+ printf("Dataset Management Command: %s\n",
+ cdata->oncs.dsm ? "Supported" : "Not Supported");
+ printf("Volatile Write Cache: %s\n",
+ cdata->vwc.present ? "Present" : "Not Present");
+}
+
+static void
+print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
+{
+ uint32_t *p;
+ uint32_t i, j;
+
+ p = (uint32_t *)nsdata;
+ length /= sizeof(uint32_t);
+
+ for (i = 0; i < length; i+=8) {
+ printf("%03x: ", i*4);
+ for (j = 0; j < 8; j++)
+ printf("%08x ", p[i+j]);
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+static void
+print_namespace(struct nvme_namespace_data *nsdata)
+{
+ uint32_t i;
+
+ printf("Size (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nsze,
+ (long long)nsdata->nsze / 1024 / 1024);
+ printf("Capacity (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->ncap,
+ (long long)nsdata->ncap / 1024 / 1024);
+ printf("Utilization (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nuse,
+ (long long)nsdata->nuse / 1024 / 1024);
+ printf("Thin Provisioning: %s\n",
+ nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
+ printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1);
+ printf("Current LBA Format: LBA Format #%d\n",
+ nsdata->flbas.format);
+ for (i = 0; i <= nsdata->nlbaf; i++) {
+ printf("LBA Format #%d:\n", i);
+ printf(" LBA Data Size: %d\n",
+ 1 << nsdata->lbaf[i].lbads);
+ }
+}
+
+static uint32_t
+ns_get_sector_size(struct nvme_namespace_data *nsdata)
+{
+
+ return (1 << nsdata->lbaf[0].lbads);
+}
+
+
+static void
+devlist(int argc, char *argv[])
+{
+ struct nvme_controller_data cdata;
+ struct nvme_namespace_data nsdata;
+ struct stat devstat;
+ char name[64], path[64];
+ uint32_t i;
+ int ch, ctrlr, exit_code, fd, found;
+
+ exit_code = EX_OK;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch ((char)ch) {
+ default:
+ usage();
+ }
+ }
+
+ ctrlr = -1;
+ found = 0;
+
+ while (1) {
+ ctrlr++;
+ sprintf(name, "nvme%d", ctrlr);
+ sprintf(path, "/dev/%s", name);
+
+ if (stat(path, &devstat) != 0)
+ break;
+
+ found++;
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s.\n", path);
+ exit_code = EX_NOPERM;
+ continue;
+ }
+
+ if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
+ printf("ioctl to %s failed.\n", path);
+ exit_code = EX_IOERR;
+ continue;
+ }
+
+ printf("%6s: %s\n", name, cdata.mn);
+
+ for (i = 0; i < cdata.nn; i++) {
+ sprintf(name, "nvme%dns%d", ctrlr, i+1);
+ sprintf(path, "/dev/%s", name);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s.\n", path);
+ exit_code = EX_NOPERM;
+ continue;
+ }
+ if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
+ printf("ioctl to %s failed.\n", path);
+ exit_code = EX_IOERR;
+ continue;
+ }
+ printf(" %10s (%lldGB)\n",
+ name,
+ nsdata.nsze *
+ (long long)ns_get_sector_size(&nsdata) /
+ 1024 / 1024 / 1024);
+ }
+ }
+
+ if (found == 0)
+ printf("No NVMe controllers found.\n");
+
+ exit(exit_code);
+}
+
+static void
+identify_ctrlr(int argc, char *argv[])
+{
+ struct nvme_controller_data cdata;
+ struct stat devstat;
+ char path[64];
+ int ch, fd, hexflag = 0, hexlength;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch ((char)ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ sprintf(path, "/dev/%s", argv[optind]);
+
+ if (stat(path, &devstat) != 0) {
+ printf("Invalid device node '%s'.\n", path);
+ exit(EX_IOERR);
+ }
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s.\n", path);
+ exit(EX_NOPERM);
+ }
+
+ if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
+ printf("ioctl to %s failed.\n", path);
+ exit(EX_IOERR);
+ }
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvme_controller_data);
+ else
+ hexlength = offsetof(struct nvme_controller_data,
+ reserved5);
+ print_controller_hex(&cdata, hexlength);
+ exit(EX_OK);
+ }
+
+ if (verboseflag == 1) {
+ printf("-v not currently supported without -x.\n");
+ usage();
+ }
+
+ print_controller(&cdata);
+ exit(EX_OK);
+}
+
+static void
+identify_ns(int argc, char *argv[])
+{
+ struct nvme_namespace_data nsdata;
+ struct stat devstat;
+ char path[64];
+ int ch, fd, hexflag = 0, hexlength;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch ((char)ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ sprintf(path, "/dev/%s", argv[optind]);
+
+ if (stat(path, &devstat) != 0) {
+ printf("Invalid device node '%s'.\n", path);
+ exit(EX_IOERR);
+ }
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s.\n", path);
+ exit(EX_NOPERM);
+ }
+
+ if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
+ printf("ioctl to %s failed.\n", path);
+ exit(EX_IOERR);
+ }
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvme_namespace_data);
+ else
+ hexlength = offsetof(struct nvme_namespace_data,
+ reserved6);
+ print_namespace_hex(&nsdata, hexlength);
+ exit(EX_OK);
+ }
+
+ if (verboseflag == 1) {
+ printf("-v not currently supported without -x.\n");
+ usage();
+ }
+
+ print_namespace(&nsdata);
+ exit(EX_OK);
+}
+
+static void
+identify(int argc, char *argv[])
+{
+ char *target;
+
+ if (argc < 2)
+ usage();
+
+ while (getopt(argc, argv, "vx") != -1) ;
+
+ target = argv[optind];
+
+ /* Specified device node must have "nvme" in it. */
+ if (strstr(argv[optind], "nvme") == NULL) {
+ printf("Invalid device node '%s'.\n", argv[optind]);
+ exit(EX_IOERR);
+ }
+
+ optreset = 1;
+ optind = 1;
+
+ /*
+ * If devicde node contains "ns", we consider it a namespace,
+ * otherwise, consider it a controller.
+ */
+ if (strstr(target, "ns") == NULL)
+ identify_ctrlr(argc, argv);
+ else
+ identify_ns(argc, argv);
+}
+
+static void
+print_perftest(struct nvme_io_test *io_test, bool perthread)
+{
+ uint32_t i, io_completed = 0, iops, mbps;
+
+ for (i = 0; i < io_test->num_threads; i++)
+ io_completed += io_test->io_completed[i];
+
+ iops = io_completed/io_test->time;
+ mbps = iops * io_test->size / (1024*1024);
+
+ printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
+ io_test->num_threads, io_test->size,
+ io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
+ io_test->time, iops, mbps);
+
+ if (perthread)
+ for (i = 0; i < io_test->num_threads; i++)
+ printf("\t%3d: %8d IO/s\n", i,
+ io_test->io_completed[i]/io_test->time);
+
+ exit(1);
+}
+
+static void
+perftest_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, PERFTEST_USAGE);
+ exit(EX_USAGE);
+}
+
+static void
+perftest(int argc, char *argv[])
+{
+ struct nvme_io_test io_test;
+ int fd;
+ char ch;
+ char *p;
+ const char *name;
+ char path[64];
+ u_long ioctl_cmd = NVME_IO_TEST;
+ bool nflag, oflag, sflag, tflag;
+ int err, perthread = 0;
+
+ nflag = oflag = sflag = tflag = false;
+ name = NULL;
+
+ memset(&io_test, 0, sizeof(io_test));
+
+ while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
+ switch (ch) {
+ case 'f':
+ if (!strcmp(optarg, "refthread"))
+ io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
+ break;
+ case 'i':
+ if (!strcmp(optarg, "bio") ||
+ !strcmp(optarg, "wait"))
+ ioctl_cmd = NVME_BIO_TEST;
+ else if (!strcmp(optarg, "io") ||
+ !strcmp(optarg, "intr"))
+ ioctl_cmd = NVME_IO_TEST;
+ break;
+ case 'n':
+ nflag = true;
+ io_test.num_threads = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ } else if (io_test.num_threads == 0 ||
+ io_test.num_threads > 128) {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'o':
+ oflag = true;
+ if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
+ io_test.opc = NVME_OPC_READ;
+ else if (!strcmp(optarg, "write") ||
+ !strcmp(optarg, "WRITE"))
+ io_test.opc = NVME_OPC_WRITE;
+ else {
+ fprintf(stderr, "\"%s\" not valid opcode.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'p':
+ perthread = 1;
+ break;
+ case 's':
+ sflag = true;
+ io_test.size = strtoul(optarg, &p, 0);
+ if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
+ // do nothing
+ } else if (toupper(*p) == 'K') {
+ io_test.size *= 1024;
+ } else if (toupper(*p) == 'M') {
+ io_test.size *= 1024 * 1024;
+ } else {
+ fprintf(stderr, "\"%s\" not valid size.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 't':
+ tflag = true;
+ io_test.time = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid time duration.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ }
+ }
+
+ name = argv[optind];
+
+ if (!nflag || !oflag || !sflag || !tflag || name == NULL)
+ perftest_usage();
+
+ sprintf(path, "/dev/%s", name);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "%s not valid device.\n", path);
+ perftest_usage();
+ }
+
+ err = ioctl(fd, ioctl_cmd, &io_test);
+
+ if (err) {
+ fprintf(stderr, "NVME_IO_TEST returned %d\n", errno);
+ exit(EX_IOERR);
+ }
+
+ print_perftest(&io_test, perthread);
+ exit(EX_OK);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ if (argc < 2)
+ usage();
+
+ if (strcmp(argv[1], "devlist") == 0)
+ devlist(argc-1, &argv[1]);
+ else if (strcmp(argv[1], "identify") == 0)
+ identify(argc-1, &argv[1]);
+ else if (strcmp(argv[1], "perftest") == 0)
+ perftest(argc-1, &argv[1]);
+
+ usage();
+
+ return (0);
+}
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 2475baf94818..26c2258a5dd4 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -1,11 +1,10 @@
# $FreeBSD$
-.PATH: ${.CURDIR}/../../contrib/pf/pfctl
-.PATH: ${.CURDIR}/../../sys/contrib/pf/net
-.PATH: ${.CURDIR}/../../contrib/pf/man
+# pf_ruleset.c is shared between kernel and pfctl
+.PATH: ${.CURDIR}/../../sys/netpfil/pf
PROG= pfctl
-MAN= pfctl.8 pf.4 pflog.4 pfsync.4 pf.conf.5 pf.os.5
+MAN= pfctl.8
SRCS = pfctl.c parse.y pfctl_parser.c pf_print_state.c pfctl_altq.c
SRCS+= pfctl_osfp.c pfctl_radix.c pfctl_table.c pfctl_qstats.c
@@ -14,11 +13,8 @@ SRCS+= pf_ruleset.c
WARNS?= 2
CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
-CFLAGS+= -Wstrict-prototypes -I${.CURDIR}/../../contrib/pf/pfctl
-
-# XXX ALTQ
-CFLAGS+= -DENABLE_ALTQ
-#CFLAGS+= -I${.CURDIR}/missing
+CFLAGS+= -Wstrict-prototypes
+CFLAGS+= -DENABLE_ALTQ -I${.CURDIR}
YFLAGS=
diff --git a/sbin/pfctl/missing/altq/altq.h b/sbin/pfctl/missing/altq/altq.h
deleted file mode 100644
index c740ed359ad1..000000000000
--- a/sbin/pfctl/missing/altq/altq.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq.h,v 1.10 2003/07/10 12:07:47 kjc Exp $ */
-
-/*
- * Copyright (C) 1998-2003
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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 _ALTQ_ALTQ_H_
-#define _ALTQ_ALTQ_H_
-
-#if 0
-/*
- * allow altq-3 (altqd(8) and /dev/altq) to coexist with the new pf-based altq.
- * altq3 is mainly for research experiments. pf-based altq is for daily use.
- */
-#define ALTQ3_COMPAT /* for compatibility with altq-3 */
-#define ALTQ3_CLFIER_COMPAT /* for compatibility with altq-3 classifier */
-#endif
-
-#ifdef ALTQ3_COMPAT
-#include <sys/param.h>
-#include <sys/ioccom.h>
-#include <sys/queue.h>
-#include <netinet/in.h>
-
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-#endif /* ALTQ3_COMPAT */
-
-/* altq discipline type */
-#define ALTQT_NONE 0 /* reserved */
-#define ALTQT_CBQ 1 /* cbq */
-#define ALTQT_WFQ 2 /* wfq */
-#define ALTQT_AFMAP 3 /* afmap */
-#define ALTQT_FIFOQ 4 /* fifoq */
-#define ALTQT_RED 5 /* red */
-#define ALTQT_RIO 6 /* rio */
-#define ALTQT_LOCALQ 7 /* local use */
-#define ALTQT_HFSC 8 /* hfsc */
-#define ALTQT_CDNR 9 /* traffic conditioner */
-#define ALTQT_BLUE 10 /* blue */
-#define ALTQT_PRIQ 11 /* priority queue */
-#define ALTQT_JOBS 12 /* JoBS */
-#define ALTQT_MAX 13 /* should be max discipline type + 1 */
-
-#ifdef ALTQ3_COMPAT
-struct altqreq {
- char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */
- u_long arg; /* request-specific argument */
-};
-#endif
-
-/* simple token backet meter profile */
-struct tb_profile {
- u_int rate; /* rate in bit-per-sec */
- u_int depth; /* depth in bytes */
-};
-
-#ifdef ALTQ3_COMPAT
-struct tbrreq {
- char ifname[IFNAMSIZ]; /* if name, e.g. "en0" */
- struct tb_profile tb_prof; /* token bucket profile */
-};
-
-#ifdef ALTQ3_CLFIER_COMPAT
-/*
- * common network flow info structure
- */
-struct flowinfo {
- u_char fi_len; /* total length */
- u_char fi_family; /* address family */
- u_int8_t fi_data[46]; /* actually longer; address family
- specific flow info. */
-};
-
-/*
- * flow info structure for internet protocol family.
- * (currently this is the only protocol family supported)
- */
-struct flowinfo_in {
- u_char fi_len; /* sizeof(struct flowinfo_in) */
- u_char fi_family; /* AF_INET */
- u_int8_t fi_proto; /* IPPROTO_XXX */
- u_int8_t fi_tos; /* type-of-service */
- struct in_addr fi_dst; /* dest address */
- struct in_addr fi_src; /* src address */
- u_int16_t fi_dport; /* dest port */
- u_int16_t fi_sport; /* src port */
- u_int32_t fi_gpi; /* generalized port id for ipsec */
- u_int8_t _pad[28]; /* make the size equal to
- flowinfo_in6 */
-};
-
-#ifdef SIN6_LEN
-struct flowinfo_in6 {
- u_char fi6_len; /* sizeof(struct flowinfo_in6) */
- u_char fi6_family; /* AF_INET6 */
- u_int8_t fi6_proto; /* IPPROTO_XXX */
- u_int8_t fi6_tclass; /* traffic class */
- u_int32_t fi6_flowlabel; /* ipv6 flowlabel */
- u_int16_t fi6_dport; /* dest port */
- u_int16_t fi6_sport; /* src port */
- u_int32_t fi6_gpi; /* generalized port id */
- struct in6_addr fi6_dst; /* dest address */
- struct in6_addr fi6_src; /* src address */
-};
-#endif /* INET6 */
-
-/*
- * flow filters for AF_INET and AF_INET6
- */
-struct flow_filter {
- int ff_ruleno;
- struct flowinfo_in ff_flow;
- struct {
- struct in_addr mask_dst;
- struct in_addr mask_src;
- u_int8_t mask_tos;
- u_int8_t _pad[3];
- } ff_mask;
- u_int8_t _pad2[24]; /* make the size equal to flow_filter6 */
-};
-
-#ifdef SIN6_LEN
-struct flow_filter6 {
- int ff_ruleno;
- struct flowinfo_in6 ff_flow6;
- struct {
- struct in6_addr mask6_dst;
- struct in6_addr mask6_src;
- u_int8_t mask6_tclass;
- u_int8_t _pad[3];
- } ff_mask6;
-};
-#endif /* INET6 */
-#endif /* ALTQ3_CLFIER_COMPAT */
-#endif /* ALTQ3_COMPAT */
-
-/*
- * generic packet counter
- */
-struct pktcntr {
- u_int64_t packets;
- u_int64_t bytes;
-};
-
-#define PKTCNTR_ADD(cntr, len) \
- do { (cntr)->packets++; (cntr)->bytes += len; } while (/*CONSTCOND*/ 0)
-
-#ifdef ALTQ3_COMPAT
-/*
- * altq related ioctls
- */
-#define ALTQGTYPE _IOWR('q', 0, struct altqreq) /* get queue type */
-#if 0
-/*
- * these ioctls are currently discipline-specific but could be shared
- * in the future.
- */
-#define ALTQATTACH _IOW('q', 1, struct altqreq) /* attach discipline */
-#define ALTQDETACH _IOW('q', 2, struct altqreq) /* detach discipline */
-#define ALTQENABLE _IOW('q', 3, struct altqreq) /* enable discipline */
-#define ALTQDISABLE _IOW('q', 4, struct altqreq) /* disable discipline*/
-#define ALTQCLEAR _IOW('q', 5, struct altqreq) /* (re)initialize */
-#define ALTQCONFIG _IOWR('q', 6, struct altqreq) /* set config params */
-#define ALTQADDCLASS _IOWR('q', 7, struct altqreq) /* add a class */
-#define ALTQMODCLASS _IOWR('q', 8, struct altqreq) /* modify a class */
-#define ALTQDELCLASS _IOWR('q', 9, struct altqreq) /* delete a class */
-#define ALTQADDFILTER _IOWR('q', 10, struct altqreq) /* add a filter */
-#define ALTQDELFILTER _IOWR('q', 11, struct altqreq) /* delete a filter */
-#define ALTQGETSTATS _IOWR('q', 12, struct altqreq) /* get statistics */
-#define ALTQGETCNTR _IOWR('q', 13, struct altqreq) /* get a pkt counter */
-#endif /* 0 */
-#define ALTQTBRSET _IOW('q', 14, struct tbrreq) /* set tb regulator */
-#define ALTQTBRGET _IOWR('q', 15, struct tbrreq) /* get tb regulator */
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-#include <altq/altq_var.h>
-#endif
-
-#endif /* _ALTQ_ALTQ_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_cbq.h b/sbin/pfctl/missing/altq/altq_cbq.h
deleted file mode 100644
index 3c41c6bd836f..000000000000
--- a/sbin/pfctl/missing/altq/altq_cbq.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_cbq.h,v 1.10 2003/08/20 23:30:23 itojun Exp $ */
-
-/*
- * Copyright (c) Sun Microsystems, Inc. 1993-1998 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.
- *
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the SMCC Technology
- * Development Group at Sun Microsystems, Inc.
- *
- * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
- * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is
- * provided "as is" without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this software.
- */
-
-#ifndef _ALTQ_ALTQ_CBQ_H_
-#define _ALTQ_ALTQ_CBQ_H_
-
-#include <altq/altq.h>
-#include <altq/altq_rmclass.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
-
-/* #pragma ident "@(#)cbq.h 1.18 98/05/13 SMI" */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Define a well known class handles
- */
-#define NULL_CLASS_HANDLE 0xffffffff
-#define ROOT_CLASS_HANDLE 0xfffffffe
-#define DEFAULT_CLASS_HANDLE 0xfffffffd
-#ifdef ALTQ3_COMPAT
-#define CTL_CLASS_HANDLE 0xfffffffc
-#endif
-
-/* class flags shoud be same as class flags in rm_class.h */
-#define CBQCLF_RED 0x0001 /* use RED */
-#define CBQCLF_ECN 0x0002 /* use RED/ECN */
-#define CBQCLF_RIO 0x0004 /* use RIO */
-#define CBQCLF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */
-#define CBQCLF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
-#define CBQCLF_BORROW 0x0020 /* borrow from parent */
-
-/* class flags only for root class */
-#define CBQCLF_WRR 0x0100 /* weighted-round robin */
-#define CBQCLF_EFFICIENT 0x0200 /* work-conserving */
-
-/* class flags for special classes */
-#define CBQCLF_ROOTCLASS 0x1000 /* root class */
-#define CBQCLF_DEFCLASS 0x2000 /* default class */
-#ifdef ALTQ3_COMPAT
-#define CBQCLF_CTLCLASS 0x4000 /* control class */
-#endif
-#define CBQCLF_CLASSMASK 0xf000 /* class mask */
-
-#define CBQ_MAXQSIZE 200
-#define CBQ_MAXPRI RM_MAXPRIO
-
-typedef struct _cbq_class_stats_ {
- u_int32_t handle;
- u_int depth;
-
- struct pktcntr xmit_cnt; /* packets sent in this class */
- struct pktcntr drop_cnt; /* dropped packets */
- u_int over; /* # times went over limit */
- u_int borrows; /* # times tried to borrow */
- u_int overactions; /* # times invoked overlimit action */
- u_int delays; /* # times invoked delay actions */
-
- /* other static class parameters useful for debugging */
- int priority;
- int maxidle;
- int minidle;
- int offtime;
- int qmax;
- int ns_per_byte;
- int wrr_allot;
-
- int qcnt; /* # packets in queue */
- int avgidle;
-
- /* red and rio related info */
- int qtype;
- struct redstats red[3];
-} class_stats_t;
-
-#ifdef ALTQ3_COMPAT
-/*
- * Define structures associated with IOCTLS for cbq.
- */
-
-/*
- * Define the CBQ interface structure. This must be included in all
- * IOCTL's such that the CBQ driver may find the appropriate CBQ module
- * associated with the network interface to be affected.
- */
-struct cbq_interface {
- char cbq_ifacename[IFNAMSIZ];
-};
-
-typedef struct cbq_class_spec {
- u_int priority;
- u_int nano_sec_per_byte;
- u_int maxq;
- u_int maxidle;
- int minidle;
- u_int offtime;
- u_int32_t parent_class_handle;
- u_int32_t borrow_class_handle;
-
- u_int pktsize;
- int flags;
-} cbq_class_spec_t;
-
-struct cbq_add_class {
- struct cbq_interface cbq_iface;
-
- cbq_class_spec_t cbq_class;
- u_int32_t cbq_class_handle;
-};
-
-struct cbq_delete_class {
- struct cbq_interface cbq_iface;
- u_int32_t cbq_class_handle;
-};
-
-struct cbq_modify_class {
- struct cbq_interface cbq_iface;
-
- cbq_class_spec_t cbq_class;
- u_int32_t cbq_class_handle;
-};
-
-struct cbq_add_filter {
- struct cbq_interface cbq_iface;
- u_int32_t cbq_class_handle;
- struct flow_filter cbq_filter;
-
- u_long cbq_filter_handle;
-};
-
-struct cbq_delete_filter {
- struct cbq_interface cbq_iface;
- u_long cbq_filter_handle;
-};
-
-/* number of classes are returned in nclasses field */
-struct cbq_getstats {
- struct cbq_interface iface;
- int nclasses;
- class_stats_t *stats;
-};
-
-/*
- * Define IOCTLs for CBQ.
- */
-#define CBQ_IF_ATTACH _IOW('Q', 1, struct cbq_interface)
-#define CBQ_IF_DETACH _IOW('Q', 2, struct cbq_interface)
-#define CBQ_ENABLE _IOW('Q', 3, struct cbq_interface)
-#define CBQ_DISABLE _IOW('Q', 4, struct cbq_interface)
-#define CBQ_CLEAR_HIERARCHY _IOW('Q', 5, struct cbq_interface)
-#define CBQ_ADD_CLASS _IOWR('Q', 7, struct cbq_add_class)
-#define CBQ_DEL_CLASS _IOW('Q', 8, struct cbq_delete_class)
-#define CBQ_MODIFY_CLASS _IOWR('Q', 9, struct cbq_modify_class)
-#define CBQ_ADD_FILTER _IOWR('Q', 10, struct cbq_add_filter)
-#define CBQ_DEL_FILTER _IOW('Q', 11, struct cbq_delete_filter)
-#define CBQ_GETSTATS _IOWR('Q', 12, struct cbq_getstats)
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-/*
- * Define macros only good for kernel drivers and modules.
- */
-#define CBQ_WATCHDOG (hz / 20)
-#define CBQ_TIMEOUT 10
-#define CBQ_LS_TIMEOUT (20 * hz / 1000)
-
-#define CBQ_MAX_CLASSES 256
-
-#ifdef ALTQ3_COMPAT
-#define CBQ_MAX_FILTERS 256
-
-#define DISABLE 0x00
-#define ENABLE 0x01
-#endif /* ALTQ3_COMPAT */
-
-/*
- * Define State structures.
- */
-typedef struct cbqstate {
-#ifdef ALTQ3_COMPAT
- struct cbqstate *cbq_next;
-#endif
- int cbq_qlen; /* # of packets in cbq */
- struct rm_class *cbq_class_tbl[CBQ_MAX_CLASSES];
-
- struct rm_ifdat ifnp;
- struct callout cbq_callout; /* for timeouts */
-#ifdef ALTQ3_CLFIER_COMPAT
- struct acc_classifier cbq_classifier;
-#endif
-} cbq_state_t;
-
-#endif /* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_ALTQ_ALTQ_CBQ_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_classq.h b/sbin/pfctl/missing/altq/altq_classq.h
deleted file mode 100644
index 43045b25a630..000000000000
--- a/sbin/pfctl/missing/altq/altq_classq.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_classq.h,v 1.6 2003/01/07 07:33:38 kjc Exp $ */
-
-/*
- * Copyright (c) 1991-1997 Regents of the University of California.
- * 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.
- * 4. Neither the name of the University nor of the Laboratory may be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-/*
- * class queue definitions extracted from rm_class.h.
- */
-#ifndef _ALTQ_ALTQ_CLASSQ_H_
-#define _ALTQ_ALTQ_CLASSQ_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Packet Queue types: RED or DROPHEAD.
- */
-#define Q_DROPHEAD 0x00
-#define Q_RED 0x01
-#define Q_RIO 0x02
-#define Q_DROPTAIL 0x03
-
-#ifdef _KERNEL
-
-/*
- * Packet Queue structures and macros to manipulate them.
- */
-struct _class_queue_ {
- struct mbuf *tail_; /* Tail of packet queue */
- int qlen_; /* Queue length (in number of packets) */
- int qlim_; /* Queue limit (in number of packets*) */
- int qtype_; /* Queue type */
-};
-
-typedef struct _class_queue_ class_queue_t;
-
-#define qtype(q) (q)->qtype_ /* Get queue type */
-#define qlimit(q) (q)->qlim_ /* Max packets to be queued */
-#define qlen(q) (q)->qlen_ /* Current queue length. */
-#define qtail(q) (q)->tail_ /* Tail of the queue */
-#define qhead(q) ((q)->tail_ ? (q)->tail_->m_nextpkt : NULL)
-
-#define qempty(q) ((q)->qlen_ == 0) /* Is the queue empty?? */
-#define q_is_red(q) ((q)->qtype_ == Q_RED) /* Is the queue a red queue */
-#define q_is_rio(q) ((q)->qtype_ == Q_RIO) /* Is the queue a rio queue */
-#define q_is_red_or_rio(q) ((q)->qtype_ == Q_RED || (q)->qtype_ == Q_RIO)
-
-#if !defined(__GNUC__) || defined(ALTQ_DEBUG)
-
-extern void _addq(class_queue_t *, struct mbuf *);
-extern struct mbuf *_getq(class_queue_t *);
-extern struct mbuf *_getq_tail(class_queue_t *);
-extern struct mbuf *_getq_random(class_queue_t *);
-extern void _removeq(class_queue_t *, struct mbuf *);
-extern void _flushq(class_queue_t *);
-
-#else /* __GNUC__ && !ALTQ_DEBUG */
-/*
- * inlined versions
- */
-static __inline void
-_addq(class_queue_t *q, struct mbuf *m)
-{
- struct mbuf *m0;
-
- if ((m0 = qtail(q)) != NULL)
- m->m_nextpkt = m0->m_nextpkt;
- else
- m0 = m;
- m0->m_nextpkt = m;
- qtail(q) = m;
- qlen(q)++;
-}
-
-static __inline struct mbuf *
-_getq(class_queue_t *q)
-{
- struct mbuf *m, *m0;
-
- if ((m = qtail(q)) == NULL)
- return (NULL);
- if ((m0 = m->m_nextpkt) != m)
- m->m_nextpkt = m0->m_nextpkt;
- else
- qtail(q) = NULL;
- qlen(q)--;
- m0->m_nextpkt = NULL;
- return (m0);
-}
-
-/* drop a packet at the tail of the queue */
-static __inline struct mbuf *
-_getq_tail(class_queue_t *q)
-{
- struct mbuf *m, *m0, *prev;
-
- if ((m = m0 = qtail(q)) == NULL)
- return NULL;
- do {
- prev = m0;
- m0 = m0->m_nextpkt;
- } while (m0 != m);
- prev->m_nextpkt = m->m_nextpkt;
- if (prev == m)
- qtail(q) = NULL;
- else
- qtail(q) = prev;
- qlen(q)--;
- m->m_nextpkt = NULL;
- return (m);
-}
-
-/* randomly select a packet in the queue */
-static __inline struct mbuf *
-_getq_random(class_queue_t *q)
-{
- struct mbuf *m;
- int i, n;
-
- if ((m = qtail(q)) == NULL)
- return NULL;
- if (m->m_nextpkt == m)
- qtail(q) = NULL;
- else {
- struct mbuf *prev = NULL;
-
- n = random() % qlen(q) + 1;
- for (i = 0; i < n; i++) {
- prev = m;
- m = m->m_nextpkt;
- }
- prev->m_nextpkt = m->m_nextpkt;
- if (m == qtail(q))
- qtail(q) = prev;
- }
- qlen(q)--;
- m->m_nextpkt = NULL;
- return (m);
-}
-
-static __inline void
-_removeq(class_queue_t *q, struct mbuf *m)
-{
- struct mbuf *m0, *prev;
-
- m0 = qtail(q);
- do {
- prev = m0;
- m0 = m0->m_nextpkt;
- } while (m0 != m);
- prev->m_nextpkt = m->m_nextpkt;
- if (prev == m)
- qtail(q) = NULL;
- else if (qtail(q) == m)
- qtail(q) = prev;
- qlen(q)--;
-}
-
-static __inline void
-_flushq(class_queue_t *q)
-{
- struct mbuf *m;
-
- while ((m = _getq(q)) != NULL)
- m_freem(m);
-}
-
-#endif /* __GNUC__ && !ALTQ_DEBUG */
-
-#endif /* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ALTQ_ALTQ_CLASSQ_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_hfsc.h b/sbin/pfctl/missing/altq/altq_hfsc.h
deleted file mode 100644
index ac242114c084..000000000000
--- a/sbin/pfctl/missing/altq/altq_hfsc.h
+++ /dev/null
@@ -1,325 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_hfsc.h,v 1.10 2003/07/10 12:07:48 kjc Exp $ */
-
-/*
- * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation is hereby granted (including for commercial or
- * for-profit use), provided that both the copyright notice and this
- * permission notice appear in all copies of the software, derivative
- * works, or modified versions, and any portions thereof, and that
- * both notices appear in supporting documentation, and that credit
- * is given to Carnegie Mellon University in all publications reporting
- * on direct or indirect use of this code or its derivatives.
- *
- * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF
- * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS
- * SOFTWARE IN ITS ``AS IS'' CONDITION, 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 CARNEGIE MELLON UNIVERSITY 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.
- *
- * Carnegie Mellon encourages (but does not require) users of this
- * software to return any improvements or extensions that they make,
- * and to grant Carnegie Mellon the rights to redistribute these
- * changes without encumbrance.
- */
-#ifndef _ALTQ_ALTQ_HFSC_H_
-#define _ALTQ_ALTQ_HFSC_H_
-
-#include <altq/altq.h>
-#include <altq/altq_classq.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct service_curve {
- u_int m1; /* slope of the first segment in bits/sec */
- u_int d; /* the x-projection of the first segment in msec */
- u_int m2; /* slope of the second segment in bits/sec */
-};
-
-/* special class handles */
-#define HFSC_NULLCLASS_HANDLE 0
-#define HFSC_ROOTCLASS_HANDLE 1
-#define HFSC_MAX_CLASSES 64
-
-/* hfsc class flags */
-#define HFCF_RED 0x0001 /* use RED */
-#define HFCF_ECN 0x0002 /* use RED/ECN */
-#define HFCF_RIO 0x0004 /* use RIO */
-#define HFCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
-#define HFCF_DEFAULTCLASS 0x1000 /* default class */
-
-/* service curve types */
-#define HFSC_REALTIMESC 1
-#define HFSC_LINKSHARINGSC 2
-#define HFSC_UPPERLIMITSC 4
-#define HFSC_DEFAULTSC (HFSC_REALTIMESC|HFSC_LINKSHARINGSC)
-
-struct hfsc_classstats {
- u_int class_id;
- u_int32_t class_handle;
- struct service_curve rsc;
- struct service_curve fsc;
- struct service_curve usc; /* upper limit service curve */
-
- u_int64_t total; /* total work in bytes */
- u_int64_t cumul; /* cumulative work in bytes
- done by real-time criteria */
- u_int64_t d; /* deadline */
- u_int64_t e; /* eligible time */
- u_int64_t vt; /* virtual time */
- u_int64_t f; /* fit time for upper-limit */
-
- /* info helpful for debugging */
- u_int64_t initvt; /* init virtual time */
- u_int64_t vtoff; /* cl_vt_ipoff */
- u_int64_t cvtmax; /* cl_maxvt */
- u_int64_t myf; /* cl_myf */
- u_int64_t cfmin; /* cl_mincf */
- u_int64_t cvtmin; /* cl_mincvt */
- u_int64_t myfadj; /* cl_myfadj */
- u_int64_t vtadj; /* cl_vtadj */
- u_int64_t cur_time;
- u_int32_t machclk_freq;
-
- u_int qlength;
- u_int qlimit;
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
- u_int period;
-
- u_int vtperiod; /* vt period sequence no */
- u_int parentperiod; /* parent's vt period seqno */
- int nactive; /* number of active children */
-
- /* red and rio related info */
- int qtype;
- struct redstats red[3];
-};
-
-#ifdef ALTQ3_COMPAT
-struct hfsc_interface {
- char hfsc_ifname[IFNAMSIZ]; /* interface name (e.g., fxp0) */
-};
-
-struct hfsc_attach {
- struct hfsc_interface iface;
- u_int bandwidth; /* link bandwidth in bits/sec */
-};
-
-struct hfsc_add_class {
- struct hfsc_interface iface;
- u_int32_t parent_handle;
- struct service_curve service_curve;
- int qlimit;
- int flags;
-
- u_int32_t class_handle; /* return value */
-};
-
-struct hfsc_delete_class {
- struct hfsc_interface iface;
- u_int32_t class_handle;
-};
-
-struct hfsc_modify_class {
- struct hfsc_interface iface;
- u_int32_t class_handle;
- struct service_curve service_curve;
- int sctype;
-};
-
-struct hfsc_add_filter {
- struct hfsc_interface iface;
- u_int32_t class_handle;
- struct flow_filter filter;
-
- u_long filter_handle; /* return value */
-};
-
-struct hfsc_delete_filter {
- struct hfsc_interface iface;
- u_long filter_handle;
-};
-
-struct hfsc_class_stats {
- struct hfsc_interface iface;
- int nskip; /* skip # of classes */
- int nclasses; /* # of class stats (WR) */
- u_int64_t cur_time; /* current time */
- u_int32_t machclk_freq; /* machine clock frequency */
- u_int hif_classes; /* # of classes in the tree */
- u_int hif_packets; /* # of packets in the tree */
- struct hfsc_classstats *stats; /* pointer to stats array */
-};
-
-#define HFSC_IF_ATTACH _IOW('Q', 1, struct hfsc_attach)
-#define HFSC_IF_DETACH _IOW('Q', 2, struct hfsc_interface)
-#define HFSC_ENABLE _IOW('Q', 3, struct hfsc_interface)
-#define HFSC_DISABLE _IOW('Q', 4, struct hfsc_interface)
-#define HFSC_CLEAR_HIERARCHY _IOW('Q', 5, struct hfsc_interface)
-#define HFSC_ADD_CLASS _IOWR('Q', 7, struct hfsc_add_class)
-#define HFSC_DEL_CLASS _IOW('Q', 8, struct hfsc_delete_class)
-#define HFSC_MOD_CLASS _IOW('Q', 9, struct hfsc_modify_class)
-#define HFSC_ADD_FILTER _IOWR('Q', 10, struct hfsc_add_filter)
-#define HFSC_DEL_FILTER _IOW('Q', 11, struct hfsc_delete_filter)
-#define HFSC_GETSTATS _IOWR('Q', 12, struct hfsc_class_stats)
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-/*
- * kernel internal service curve representation
- * coordinates are given by 64 bit unsigned integers.
- * x-axis: unit is clock count. for the intel x86 architecture,
- * the raw Pentium TSC (Timestamp Counter) value is used.
- * virtual time is also calculated in this time scale.
- * y-axis: unit is byte.
- *
- * the service curve parameters are converted to the internal
- * representation.
- * the slope values are scaled to avoid overflow.
- * the inverse slope values as well as the y-projection of the 1st
- * segment are kept in order to to avoid 64-bit divide operations
- * that are expensive on 32-bit architectures.
- *
- * note: Intel Pentium TSC never wraps around in several thousands of years.
- * x-axis doesn't wrap around for 1089 years with 1GHz clock.
- * y-axis doesn't wrap around for 4358 years with 1Gbps bandwidth.
- */
-
-/* kernel internal representation of a service curve */
-struct internal_sc {
- u_int64_t sm1; /* scaled slope of the 1st segment */
- u_int64_t ism1; /* scaled inverse-slope of the 1st segment */
- u_int64_t dx; /* the x-projection of the 1st segment */
- u_int64_t dy; /* the y-projection of the 1st segment */
- u_int64_t sm2; /* scaled slope of the 2nd segment */
- u_int64_t ism2; /* scaled inverse-slope of the 2nd segment */
-};
-
-/* runtime service curve */
-struct runtime_sc {
- u_int64_t x; /* current starting position on x-axis */
- u_int64_t y; /* current starting position on x-axis */
- u_int64_t sm1; /* scaled slope of the 1st segment */
- u_int64_t ism1; /* scaled inverse-slope of the 1st segment */
- u_int64_t dx; /* the x-projection of the 1st segment */
- u_int64_t dy; /* the y-projection of the 1st segment */
- u_int64_t sm2; /* scaled slope of the 2nd segment */
- u_int64_t ism2; /* scaled inverse-slope of the 2nd segment */
-};
-
-/* for TAILQ based ellist and actlist implementation */
-struct hfsc_class;
-typedef TAILQ_HEAD(_eligible, hfsc_class) ellist_t;
-typedef TAILQ_ENTRY(hfsc_class) elentry_t;
-typedef TAILQ_HEAD(_active, hfsc_class) actlist_t;
-typedef TAILQ_ENTRY(hfsc_class) actentry_t;
-#define ellist_first(s) TAILQ_FIRST(s)
-#define actlist_first(s) TAILQ_FIRST(s)
-#define actlist_last(s) TAILQ_LAST(s, _active)
-
-struct hfsc_class {
- u_int cl_id; /* class id (just for debug) */
- u_int32_t cl_handle; /* class handle */
- struct hfsc_if *cl_hif; /* back pointer to struct hfsc_if */
- int cl_flags; /* misc flags */
-
- struct hfsc_class *cl_parent; /* parent class */
- struct hfsc_class *cl_siblings; /* sibling classes */
- struct hfsc_class *cl_children; /* child classes */
-
- class_queue_t *cl_q; /* class queue structure */
- struct red *cl_red; /* RED state */
- struct altq_pktattr *cl_pktattr; /* saved header used by ECN */
-
- u_int64_t cl_total; /* total work in bytes */
- u_int64_t cl_cumul; /* cumulative work in bytes
- done by real-time criteria */
- u_int64_t cl_d; /* deadline */
- u_int64_t cl_e; /* eligible time */
- u_int64_t cl_vt; /* virtual time */
- u_int64_t cl_f; /* time when this class will fit for
- link-sharing, max(myf, cfmin) */
- u_int64_t cl_myf; /* my fit-time (as calculated from this
- class's own upperlimit curve) */
- u_int64_t cl_myfadj; /* my fit-time adjustment
- (to cancel history dependence) */
- u_int64_t cl_cfmin; /* earliest children's fit-time (used
- with cl_myf to obtain cl_f) */
- u_int64_t cl_cvtmin; /* minimal virtual time among the
- children fit for link-sharing
- (monotonic within a period) */
- u_int64_t cl_vtadj; /* intra-period cumulative vt
- adjustment */
- u_int64_t cl_vtoff; /* inter-period cumulative vt offset */
- u_int64_t cl_cvtmax; /* max child's vt in the last period */
-
- u_int64_t cl_initvt; /* init virtual time (for debugging) */
-
- struct internal_sc *cl_rsc; /* internal real-time service curve */
- struct internal_sc *cl_fsc; /* internal fair service curve */
- struct internal_sc *cl_usc; /* internal upperlimit service curve */
- struct runtime_sc cl_deadline; /* deadline curve */
- struct runtime_sc cl_eligible; /* eligible curve */
- struct runtime_sc cl_virtual; /* virtual curve */
- struct runtime_sc cl_ulimit; /* upperlimit curve */
-
- u_int cl_vtperiod; /* vt period sequence no */
- u_int cl_parentperiod; /* parent's vt period seqno */
- int cl_nactive; /* number of active children */
- actlist_t *cl_actc; /* active children list */
-
- actentry_t cl_actlist; /* active children list entry */
- elentry_t cl_ellist; /* eligible list entry */
-
- struct {
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
- u_int period;
- } cl_stats;
-};
-
-/*
- * hfsc interface state
- */
-struct hfsc_if {
- struct hfsc_if *hif_next; /* interface state list */
- struct ifaltq *hif_ifq; /* backpointer to ifaltq */
- struct hfsc_class *hif_rootclass; /* root class */
- struct hfsc_class *hif_defaultclass; /* default class */
- struct hfsc_class *hif_class_tbl[HFSC_MAX_CLASSES];
- struct hfsc_class *hif_pollcache; /* cache for poll operation */
-
- u_int hif_classes; /* # of classes in the tree */
- u_int hif_packets; /* # of packets in the tree */
- u_int hif_classid; /* class id sequence number */
-
- ellist_t *hif_eligible; /* eligible list */
-
-#ifdef ALTQ3_CLFIER_COMPAT
- struct acc_classifier hif_classifier;
-#endif
-};
-
-#endif /* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ALTQ_ALTQ_HFSC_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_priq.h b/sbin/pfctl/missing/altq/altq_priq.h
deleted file mode 100644
index 526b09235e39..000000000000
--- a/sbin/pfctl/missing/altq/altq_priq.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_priq.h,v 1.5 2003/07/10 12:07:48 kjc Exp $ */
-/*
- * Copyright (C) 2000-2003
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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 _ALTQ_ALTQ_PRIQ_H_
-#define _ALTQ_ALTQ_PRIQ_H_
-
-#include <altq/altq.h>
-#include <altq/altq_classq.h>
-#include <altq/altq_red.h>
-#include <altq/altq_rio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PRIQ_MAXPRI 16 /* upper limit of the number of priorities */
-#define PRIQ_MAXQID 256 /* upper limit of queues */
-
-#ifdef ALTQ3_COMPAT
-struct priq_interface {
- char ifname[IFNAMSIZ]; /* interface name (e.g., fxp0) */
- u_long arg; /* request-specific argument */
-};
-
-struct priq_add_class {
- struct priq_interface iface;
- int pri; /* priority (0 is the lowest) */
- int qlimit; /* queue size limit */
- int flags; /* misc flags (see below) */
-
- u_int32_t class_handle; /* return value */
-};
-#endif /* ALTQ3_COMPAT */
-
-/* priq class flags */
-#define PRCF_RED 0x0001 /* use RED */
-#define PRCF_ECN 0x0002 /* use RED/ECN */
-#define PRCF_RIO 0x0004 /* use RIO */
-#define PRCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
-#define PRCF_DEFAULTCLASS 0x1000 /* default class */
-
-/* special class handles */
-#define PRIQ_NULLCLASS_HANDLE 0
-
-#ifdef ALTQ3_COMPAT
-struct priq_delete_class {
- struct priq_interface iface;
- u_int32_t class_handle;
-};
-
-struct priq_modify_class {
- struct priq_interface iface;
- u_int32_t class_handle;
- int pri;
- int qlimit;
- int flags;
-};
-
-struct priq_add_filter {
- struct priq_interface iface;
- u_int32_t class_handle;
- struct flow_filter filter;
-
- u_long filter_handle; /* return value */
-};
-
-struct priq_delete_filter {
- struct priq_interface iface;
- u_long filter_handle;
-};
-#endif /* ALTQ3_COMPAT */
-
-struct priq_classstats {
- u_int32_t class_handle;
-
- u_int qlength;
- u_int qlimit;
- u_int period;
- struct pktcntr xmitcnt; /* transmitted packet counter */
- struct pktcntr dropcnt; /* dropped packet counter */
-
- /* red and rio related info */
- int qtype;
- struct redstats red[3]; /* rio has 3 red stats */
-};
-
-#ifdef ALTQ3_COMPAT
-struct priq_class_stats {
- struct priq_interface iface;
- int maxpri; /* in/out */
-
- struct priq_classstats *stats; /* pointer to stats array */
-};
-
-#define PRIQ_IF_ATTACH _IOW('Q', 1, struct priq_interface)
-#define PRIQ_IF_DETACH _IOW('Q', 2, struct priq_interface)
-#define PRIQ_ENABLE _IOW('Q', 3, struct priq_interface)
-#define PRIQ_DISABLE _IOW('Q', 4, struct priq_interface)
-#define PRIQ_CLEAR _IOW('Q', 5, struct priq_interface)
-#define PRIQ_ADD_CLASS _IOWR('Q', 7, struct priq_add_class)
-#define PRIQ_DEL_CLASS _IOW('Q', 8, struct priq_delete_class)
-#define PRIQ_MOD_CLASS _IOW('Q', 9, struct priq_modify_class)
-#define PRIQ_ADD_FILTER _IOWR('Q', 10, struct priq_add_filter)
-#define PRIQ_DEL_FILTER _IOW('Q', 11, struct priq_delete_filter)
-#define PRIQ_GETSTATS _IOWR('Q', 12, struct priq_class_stats)
-
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-
-struct priq_class {
- u_int32_t cl_handle; /* class handle */
- class_queue_t *cl_q; /* class queue structure */
- struct red *cl_red; /* RED state */
- int cl_pri; /* priority */
- int cl_flags; /* class flags */
- struct priq_if *cl_pif; /* back pointer to pif */
- struct altq_pktattr *cl_pktattr; /* saved header used by ECN */
-
- /* statistics */
- u_int cl_period; /* backlog period */
- struct pktcntr cl_xmitcnt; /* transmitted packet counter */
- struct pktcntr cl_dropcnt; /* dropped packet counter */
-};
-
-/*
- * priq interface state
- */
-struct priq_if {
- struct priq_if *pif_next; /* interface state list */
- struct ifaltq *pif_ifq; /* backpointer to ifaltq */
- u_int pif_bandwidth; /* link bandwidth in bps */
- int pif_maxpri; /* max priority in use */
- struct priq_class *pif_default; /* default class */
- struct priq_class *pif_classes[PRIQ_MAXPRI]; /* classes */
-#ifdef ALTQ3_CLFIER_COMPAT
- struct acc_classifier pif_classifier; /* classifier */
-#endif
-};
-
-#endif /* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ALTQ_ALTQ_PRIQ_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_red.h b/sbin/pfctl/missing/altq/altq_red.h
deleted file mode 100644
index 96e3fae94fc6..000000000000
--- a/sbin/pfctl/missing/altq/altq_red.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_red.h,v 1.8 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
- * Copyright (C) 1997-2003
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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 _ALTQ_ALTQ_RED_H_
-#define _ALTQ_ALTQ_RED_H_
-
-#include <altq/altq_classq.h>
-
-#ifdef ALTQ3_COMPAT
-struct red_interface {
- char red_ifname[IFNAMSIZ];
-};
-
-struct red_stats {
- struct red_interface iface;
- int q_len;
- int q_avg;
-
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
- u_int drop_forced;
- u_int drop_unforced;
- u_int marked_packets;
-
- /* static red parameters */
- int q_limit;
- int weight;
- int inv_pmax;
- int th_min;
- int th_max;
-
- /* flowvalve related stuff */
- u_int fv_flows;
- u_int fv_pass;
- u_int fv_predrop;
- u_int fv_alloc;
- u_int fv_escape;
-};
-
-struct red_conf {
- struct red_interface iface;
- int red_weight; /* weight for EWMA */
- int red_inv_pmax; /* inverse of max drop probability */
- int red_thmin; /* red min threshold */
- int red_thmax; /* red max threshold */
- int red_limit; /* max queue length */
- int red_pkttime; /* average packet time in usec */
- int red_flags; /* see below */
-};
-#endif /* ALTQ3_COMPAT */
-
-/* red flags */
-#define REDF_ECN4 0x01 /* use packet marking for IPv4 packets */
-#define REDF_ECN6 0x02 /* use packet marking for IPv6 packets */
-#define REDF_ECN (REDF_ECN4 | REDF_ECN6)
-#define REDF_FLOWVALVE 0x04 /* use flowvalve (aka penalty-box) */
-
-/*
- * simpler versions of red parameters and statistics used by other
- * disciplines (e.g., CBQ)
- */
-struct redparams {
- int th_min; /* red min threshold */
- int th_max; /* red max threshold */
- int inv_pmax; /* inverse of max drop probability */
-};
-
-struct redstats {
- int q_avg;
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
- u_int drop_forced;
- u_int drop_unforced;
- u_int marked_packets;
-};
-
-#ifdef ALTQ3_COMPAT
-/*
- * IOCTLs for RED
- */
-#define RED_IF_ATTACH _IOW('Q', 1, struct red_interface)
-#define RED_IF_DETACH _IOW('Q', 2, struct red_interface)
-#define RED_ENABLE _IOW('Q', 3, struct red_interface)
-#define RED_DISABLE _IOW('Q', 4, struct red_interface)
-#define RED_CONFIG _IOWR('Q', 6, struct red_conf)
-#define RED_GETSTATS _IOWR('Q', 12, struct red_stats)
-#define RED_SETDEFAULTS _IOW('Q', 30, struct redparams)
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-
-#ifdef ALTQ3_COMPAT
-struct flowvalve;
-#endif
-
-/* weight table structure for idle time calibration */
-struct wtab {
- struct wtab *w_next;
- int w_weight;
- int w_param_max;
- int w_refcount;
- int32_t w_tab[32];
-};
-
-typedef struct red {
- int red_pkttime; /* average packet time in micro sec
- used for idle calibration */
- int red_flags; /* red flags */
-
- /* red parameters */
- int red_weight; /* weight for EWMA */
- int red_inv_pmax; /* inverse of max drop probability */
- int red_thmin; /* red min threshold */
- int red_thmax; /* red max threshold */
-
- /* variables for internal use */
- int red_wshift; /* log(red_weight) */
- int red_thmin_s; /* th_min scaled by avgshift */
- int red_thmax_s; /* th_max scaled by avgshift */
- int red_probd; /* drop probability denominator */
-
- int red_avg; /* queue len avg scaled by avgshift */
- int red_count; /* packet count since last dropped/
- marked packet */
- int red_idle; /* queue was empty */
- int red_old; /* avg is above th_min */
- struct wtab *red_wtab; /* weight table */
- struct timeval red_last; /* time when the queue becomes idle */
-
-#ifdef ALTQ3_COMPAT
- struct flowvalve *red_flowvalve; /* flowvalve state */
-#endif
-
- struct {
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
- u_int drop_forced;
- u_int drop_unforced;
- u_int marked_packets;
- } red_stats;
-} red_t;
-
-#ifdef ALTQ3_COMPAT
-typedef struct red_queue {
- struct red_queue *rq_next; /* next red_state in the list */
- struct ifaltq *rq_ifq; /* backpointer to ifaltq */
-
- class_queue_t *rq_q;
-
- red_t *rq_red;
-} red_queue_t;
-#endif /* ALTQ3_COMPAT */
-
-/* red drop types */
-#define DTYPE_NODROP 0 /* no drop */
-#define DTYPE_FORCED 1 /* a "forced" drop */
-#define DTYPE_EARLY 2 /* an "unforced" (early) drop */
-
-extern red_t *red_alloc(int, int, int, int, int, int);
-extern void red_destroy(red_t *);
-extern void red_getstats(red_t *, struct redstats *);
-extern int red_addq(red_t *, class_queue_t *, struct mbuf *,
- struct altq_pktattr *);
-extern struct mbuf *red_getq(red_t *, class_queue_t *);
-extern int drop_early(int, int, int);
-extern int mark_ecn(struct mbuf *, struct altq_pktattr *, int);
-extern struct wtab *wtab_alloc(int);
-extern int wtab_destroy(struct wtab *);
-extern int32_t pow_w(struct wtab *, int);
-
-#endif /* _KERNEL */
-
-#endif /* _ALTQ_ALTQ_RED_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_rio.h b/sbin/pfctl/missing/altq/altq_rio.h
deleted file mode 100644
index eda338ae2f1d..000000000000
--- a/sbin/pfctl/missing/altq/altq_rio.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_rio.h,v 1.9 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
- * Copyright (C) 1998-2003
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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 _ALTQ_ALTQ_RIO_H_
-#define _ALTQ_ALTQ_RIO_H_
-
-#include <altq/altq_classq.h>
-
-/*
- * RIO: RED with IN/OUT bit
- * (extended to support more than 2 drop precedence values)
- */
-#define RIO_NDROPPREC 3 /* number of drop precedence values */
-
-#ifdef ALTQ3_COMPAT
-struct rio_interface {
- char rio_ifname[IFNAMSIZ];
-};
-
-struct rio_stats {
- struct rio_interface iface;
- int q_len[RIO_NDROPPREC];
- struct redstats q_stats[RIO_NDROPPREC];
-
- /* static red parameters */
- int q_limit;
- int weight;
- int flags;
- struct redparams q_params[RIO_NDROPPREC];
-};
-
-struct rio_conf {
- struct rio_interface iface;
- struct redparams q_params[RIO_NDROPPREC];
- int rio_weight; /* weight for EWMA */
- int rio_limit; /* max queue length */
- int rio_pkttime; /* average packet time in usec */
- int rio_flags; /* see below */
-};
-#endif /* ALTQ3_COMPAT */
-
-/* rio flags */
-#define RIOF_ECN4 0x01 /* use packet marking for IPv4 packets */
-#define RIOF_ECN6 0x02 /* use packet marking for IPv6 packets */
-#define RIOF_ECN (RIOF_ECN4 | RIOF_ECN6)
-#define RIOF_CLEARDSCP 0x200 /* clear diffserv codepoint */
-
-#ifdef ALTQ3_COMPAT
-/*
- * IOCTLs for RIO
- */
-#define RIO_IF_ATTACH _IOW('Q', 1, struct rio_interface)
-#define RIO_IF_DETACH _IOW('Q', 2, struct rio_interface)
-#define RIO_ENABLE _IOW('Q', 3, struct rio_interface)
-#define RIO_DISABLE _IOW('Q', 4, struct rio_interface)
-#define RIO_CONFIG _IOWR('Q', 6, struct rio_conf)
-#define RIO_GETSTATS _IOWR('Q', 12, struct rio_stats)
-#define RIO_SETDEFAULTS _IOW('Q', 30, struct redparams[RIO_NDROPPREC])
-#endif /* ALTQ3_COMPAT */
-
-#ifdef _KERNEL
-
-typedef struct rio {
- /* per drop precedence structure */
- struct dropprec_state {
- /* red parameters */
- int inv_pmax; /* inverse of max drop probability */
- int th_min; /* red min threshold */
- int th_max; /* red max threshold */
-
- /* variables for internal use */
- int th_min_s; /* th_min scaled by avgshift */
- int th_max_s; /* th_max scaled by avgshift */
- int probd; /* drop probability denominator */
-
- int qlen; /* queue length */
- int avg; /* (scaled) queue length average */
- int count; /* packet count since the last dropped/
- marked packet */
- int idle; /* queue was empty */
- int old; /* avg is above th_min */
- struct timeval last; /* timestamp when queue becomes idle */
- } rio_precstate[RIO_NDROPPREC];
-
- int rio_wshift; /* log(red_weight) */
- int rio_weight; /* weight for EWMA */
- struct wtab *rio_wtab; /* weight table */
-
- int rio_pkttime; /* average packet time in micro sec
- used for idle calibration */
- int rio_flags; /* rio flags */
-
- u_int8_t rio_codepoint; /* codepoint value to tag packets */
- u_int8_t rio_codepointmask; /* codepoint mask bits */
-
- struct redstats q_stats[RIO_NDROPPREC]; /* statistics */
-} rio_t;
-
-#ifdef ALTQ3_COMPAT
-typedef struct rio_queue {
- struct rio_queue *rq_next; /* next red_state in the list */
- struct ifaltq *rq_ifq; /* backpointer to ifaltq */
-
- class_queue_t *rq_q;
-
- rio_t *rq_rio;
-} rio_queue_t;
-#endif /* ALTQ3_COMPAT */
-
-extern rio_t *rio_alloc(int, struct redparams *, int, int);
-extern void rio_destroy(rio_t *);
-extern void rio_getstats(rio_t *, struct redstats *);
-extern int rio_addq(rio_t *, class_queue_t *, struct mbuf *,
- struct altq_pktattr *);
-extern struct mbuf *rio_getq(rio_t *, class_queue_t *);
-
-#endif /* _KERNEL */
-
-#endif /* _ALTQ_ALTQ_RIO_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_rmclass.h b/sbin/pfctl/missing/altq/altq_rmclass.h
deleted file mode 100644
index 87e3e630bb8a..000000000000
--- a/sbin/pfctl/missing/altq/altq_rmclass.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_rmclass.h,v 1.10 2003/08/20 23:30:23 itojun Exp $ */
-
-/*
- * Copyright (c) 1991-1997 Regents of the University of California.
- * 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.
- * 4. Neither the name of the University nor of the Laboratory may be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 _ALTQ_ALTQ_RMCLASS_H_
-#define _ALTQ_ALTQ_RMCLASS_H_
-
-#include <altq/altq_classq.h>
-
-/* #pragma ident "@(#)rm_class.h 1.20 97/10/23 SMI" */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RM_MAXPRIO 8 /* Max priority */
-
-#ifdef _KERNEL
-
-typedef struct mbuf mbuf_t;
-typedef struct rm_ifdat rm_ifdat_t;
-typedef struct rm_class rm_class_t;
-
-struct red;
-
-/*
- * Macros for dealing with time values. We assume all times are
- * 'timevals'. `microtime' is used to get the best available clock
- * resolution. If `microtime' *doesn't* return a value that's about
- * ten times smaller than the average packet time on the fastest
- * link that will use these routines, a slightly different clock
- * scheme than this one should be used.
- * (Bias due to truncation error in this scheme will overestimate utilization
- * and discriminate against high bandwidth classes. To remove this bias an
- * integrator needs to be added. The simplest integrator uses a history of
- * 10 * avg.packet.time / min.tick.time packet completion entries. This is
- * straight forward to add but we don't want to pay the extra memory
- * traffic to maintain it if it's not necessary (occasionally a vendor
- * accidentally builds a workstation with a decent clock - e.g., Sun & HP).)
- */
-
-#define RM_GETTIME(now) microtime(&now)
-
-#define TV_LT(a, b) (((a)->tv_sec < (b)->tv_sec) || \
- (((a)->tv_usec < (b)->tv_usec) && ((a)->tv_sec <= (b)->tv_sec)))
-
-#define TV_DELTA(a, b, delta) { \
- register int xxs; \
- \
- delta = (a)->tv_usec - (b)->tv_usec; \
- if ((xxs = (a)->tv_sec - (b)->tv_sec)) { \
- switch (xxs) { \
- default: \
- /* if (xxs < 0) \
- printf("rm_class: bogus time values\n"); */ \
- delta = 0; \
- /* fall through */ \
- case 2: \
- delta += 1000000; \
- /* fall through */ \
- case 1: \
- delta += 1000000; \
- break; \
- } \
- } \
-}
-
-#define TV_ADD_DELTA(a, delta, res) { \
- register int xxus = (a)->tv_usec + (delta); \
- \
- (res)->tv_sec = (a)->tv_sec; \
- while (xxus >= 1000000) { \
- ++((res)->tv_sec); \
- xxus -= 1000000; \
- } \
- (res)->tv_usec = xxus; \
-}
-
-#define RM_TIMEOUT 2 /* 1 Clock tick. */
-
-#if 1
-#define RM_MAXQUEUED 1 /* this isn't used in ALTQ/CBQ */
-#else
-#define RM_MAXQUEUED 16 /* Max number of packets downstream of CBQ */
-#endif
-#define RM_MAXQUEUE 64 /* Max queue length */
-#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */
-#define RM_POWER (1 << RM_FILTER_GAIN)
-#define RM_MAXDEPTH 32
-#define RM_NS_PER_SEC (1000000000)
-
-typedef struct _rm_class_stats_ {
- u_int handle;
- u_int depth;
-
- struct pktcntr xmit_cnt; /* packets sent in this class */
- struct pktcntr drop_cnt; /* dropped packets */
- u_int over; /* # times went over limit */
- u_int borrows; /* # times tried to borrow */
- u_int overactions; /* # times invoked overlimit action */
- u_int delays; /* # times invoked delay actions */
-} rm_class_stats_t;
-
-/*
- * CBQ Class state structure
- */
-struct rm_class {
- class_queue_t *q_; /* Queue of packets */
- rm_ifdat_t *ifdat_;
- int pri_; /* Class priority. */
- int depth_; /* Class depth */
- u_int ns_per_byte_; /* NanoSeconds per byte. */
- u_int maxrate_; /* Bytes per second for this class. */
- u_int allotment_; /* Fraction of link bandwidth. */
- u_int w_allotment_; /* Weighted allotment for WRR */
- int bytes_alloc_; /* Allocation for round of WRR */
-
- int avgidle_;
- int maxidle_;
- int minidle_;
- int offtime_;
- int sleeping_; /* != 0 if delaying */
- int qthresh_; /* Queue threshold for formal link sharing */
- int leaf_; /* Note whether leaf class or not.*/
-
- rm_class_t *children_; /* Children of this class */
- rm_class_t *next_; /* Next pointer, used if child */
-
- rm_class_t *peer_; /* Peer class */
- rm_class_t *borrow_; /* Borrow class */
- rm_class_t *parent_; /* Parent class */
-
- void (*overlimit)(struct rm_class *, struct rm_class *);
- void (*drop)(struct rm_class *); /* Class drop action. */
-
- struct red *red_; /* RED state pointer */
- struct altq_pktattr *pktattr_; /* saved hdr used by RED/ECN */
- int flags_;
-
- int last_pkttime_; /* saved pkt_time */
- struct timeval undertime_; /* time can next send */
- struct timeval last_; /* time last packet sent */
- struct timeval overtime_;
- struct callout callout_; /* for timeout() calls */
-
- rm_class_stats_t stats_; /* Class Statistics */
-};
-
-/*
- * CBQ Interface state
- */
-struct rm_ifdat {
- int queued_; /* # pkts queued downstream */
- int efficient_; /* Link Efficency bit */
- int wrr_; /* Enable Weighted Round-Robin */
- u_long ns_per_byte_; /* Link byte speed. */
- int maxqueued_; /* Max packets to queue */
- int maxpkt_; /* Max packet size. */
- int qi_; /* In/out pointers for downstream */
- int qo_; /* packets */
-
- /*
- * Active class state and WRR state.
- */
- rm_class_t *active_[RM_MAXPRIO]; /* Active cl's in each pri */
- int na_[RM_MAXPRIO]; /* # of active cl's in a pri */
- int num_[RM_MAXPRIO]; /* # of cl's per pri */
- int alloc_[RM_MAXPRIO]; /* Byte Allocation */
- u_long M_[RM_MAXPRIO]; /* WRR weights. */
-
- /*
- * Network Interface/Solaris Queue state pointer.
- */
- struct ifaltq *ifq_;
- rm_class_t *default_; /* Default Pkt class, BE */
- rm_class_t *root_; /* Root Link class. */
- rm_class_t *ctl_; /* Control Traffic class. */
- void (*restart)(struct ifaltq *); /* Restart routine. */
-
- /*
- * Current packet downstream packet state and dynamic state.
- */
- rm_class_t *borrowed_[RM_MAXQUEUED]; /* Class borrowed last */
- rm_class_t *class_[RM_MAXQUEUED]; /* class sending */
- int curlen_[RM_MAXQUEUED]; /* Current pktlen */
- struct timeval now_[RM_MAXQUEUED]; /* Current packet time. */
- int is_overlimit_[RM_MAXQUEUED];/* Current packet time. */
-
- int cutoff_; /* Cut-off depth for borrowing */
-
- struct timeval ifnow_; /* expected xmit completion time */
-#if 1 /* ALTQ4PPP */
- int maxiftime_; /* max delay inside interface */
-#endif
- rm_class_t *pollcache_; /* cached rm_class by poll operation */
-};
-
-/* flags for rmc_init and rmc_newclass */
-/* class flags */
-#define RMCF_RED 0x0001
-#define RMCF_ECN 0x0002
-#define RMCF_RIO 0x0004
-#define RMCF_FLOWVALVE 0x0008 /* use flowvalve (aka penalty-box) */
-#define RMCF_CLEARDSCP 0x0010 /* clear diffserv codepoint */
-
-/* flags for rmc_init */
-#define RMCF_WRR 0x0100
-#define RMCF_EFFICIENT 0x0200
-
-#define is_a_parent_class(cl) ((cl)->children_ != NULL)
-
-extern rm_class_t *rmc_newclass(int, struct rm_ifdat *, u_int,
- void (*)(struct rm_class *, struct rm_class *),
- int, struct rm_class *, struct rm_class *,
- u_int, int, u_int, int, int);
-extern void rmc_delete_class(struct rm_ifdat *, struct rm_class *);
-extern int rmc_modclass(struct rm_class *, u_int, int,
- u_int, int, u_int, int);
-extern void rmc_init(struct ifaltq *, struct rm_ifdat *, u_int,
- void (*)(struct ifaltq *),
- int, int, u_int, int, u_int, int);
-extern int rmc_queue_packet(struct rm_class *, mbuf_t *);
-extern mbuf_t *rmc_dequeue_next(struct rm_ifdat *, int);
-extern void rmc_update_class_util(struct rm_ifdat *);
-extern void rmc_delay_action(struct rm_class *, struct rm_class *);
-extern void rmc_dropall(struct rm_class *);
-extern int rmc_get_weight(struct rm_ifdat *, int);
-
-#endif /* _KERNEL */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ALTQ_ALTQ_RMCLASS_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_rmclass_debug.h b/sbin/pfctl/missing/altq/altq_rmclass_debug.h
deleted file mode 100644
index 7fcc86ba129b..000000000000
--- a/sbin/pfctl/missing/altq/altq_rmclass_debug.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_rmclass_debug.h,v 1.3 2002/11/29 04:36:24 kjc Exp $ */
-
-/*
- * Copyright (c) Sun Microsystems, Inc. 1998 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.
- *
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the SMCC Technology
- * Development Group at Sun Microsystems, Inc.
- *
- * 4. The name of the Sun Microsystems, Inc nor may not be used to endorse or
- * promote products derived from this software without specific prior
- * written permission.
- *
- * SUN MICROSYSTEMS DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE OR THE
- * SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The software is
- * provided "as is" without express or implied warranty of any kind.
- *
- * These notices must be retained in any copies of any part of this software.
- */
-
-#ifndef _ALTQ_ALTQ_RMCLASS_DEBUG_H_
-#define _ALTQ_ALTQ_RMCLASS_DEBUG_H_
-
-/* #pragma ident "@(#)rm_class_debug.h 1.7 98/05/04 SMI" */
-
-/*
- * Cbq debugging macros
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef CBQ_TRACE
-#ifndef NCBQTRACE
-#define NCBQTRACE (16 * 1024)
-#endif
-
-/*
- * To view the trace output, using adb, type:
- * adb -k /dev/ksyms /dev/mem <cr>, then type
- * cbqtrace_count/D to get the count, then type
- * cbqtrace_buffer,0tcount/Dp4C" "Xn
- * This will dump the trace buffer from 0 to count.
- */
-/*
- * in ALTQ, "call cbqtrace_dump(N)" from DDB to display 20 events
- * from Nth event in the circular buffer.
- */
-
-struct cbqtrace {
- int count;
- int function; /* address of function */
- int trace_action; /* descriptive 4 characters */
- int object; /* object operated on */
-};
-
-extern struct cbqtrace cbqtrace_buffer[];
-extern struct cbqtrace *cbqtrace_ptr;
-extern int cbqtrace_count;
-
-#define CBQTRACEINIT() { \
- if (cbqtrace_ptr == NULL) \
- cbqtrace_ptr = cbqtrace_buffer; \
- else { \
- cbqtrace_ptr = cbqtrace_buffer; \
- bzero((void *)cbqtrace_ptr, sizeof(cbqtrace_buffer)); \
- cbqtrace_count = 0; \
- } \
-}
-
-#define LOCK_TRACE() splimp()
-#define UNLOCK_TRACE(x) splx(x)
-
-#define CBQTRACE(func, act, obj) { \
- int __s = LOCK_TRACE(); \
- int *_p = &cbqtrace_ptr->count; \
- *_p++ = ++cbqtrace_count; \
- *_p++ = (int)(func); \
- *_p++ = (int)(act); \
- *_p++ = (int)(obj); \
- if ((struct cbqtrace *)(void *)_p >= &cbqtrace_buffer[NCBQTRACE])\
- cbqtrace_ptr = cbqtrace_buffer; \
- else \
- cbqtrace_ptr = (struct cbqtrace *)(void *)_p; \
- UNLOCK_TRACE(__s); \
- }
-#else
-
-/* If no tracing, define no-ops */
-#define CBQTRACEINIT()
-#define CBQTRACE(a, b, c)
-
-#endif /* !CBQ_TRACE */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _ALTQ_ALTQ_RMCLASS_DEBUG_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_var.h b/sbin/pfctl/missing/altq/altq_var.h
deleted file mode 100644
index 165b5afe3204..000000000000
--- a/sbin/pfctl/missing/altq/altq_var.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_var.h,v 1.15 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
- * Copyright (C) 1998-2003
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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 _ALTQ_ALTQ_VAR_H_
-#define _ALTQ_ALTQ_VAR_H_
-
-#ifdef _KERNEL
-
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/queue.h>
-
-#ifdef ALTQ3_CLFIER_COMPAT
-/*
- * filter structure for altq common classifier
- */
-struct acc_filter {
- LIST_ENTRY(acc_filter) f_chain;
- void *f_class; /* pointer to the class */
- u_long f_handle; /* filter id */
- u_int32_t f_fbmask; /* filter bitmask */
- struct flow_filter f_filter; /* filter value */
-};
-
-/*
- * XXX ACC_FILTER_TABLESIZE can't be larger than 2048 unless we fix
- * the handle assignment.
- */
-#define ACC_FILTER_TABLESIZE (256+1)
-#define ACC_FILTER_MASK (ACC_FILTER_TABLESIZE - 2)
-#define ACC_WILDCARD_INDEX (ACC_FILTER_TABLESIZE - 1)
-#ifdef __GNUC__
-#define ACC_GET_HASH_INDEX(addr) \
- ({int x = (addr) + ((addr) >> 16); (x + (x >> 8)) & ACC_FILTER_MASK;})
-#else
-#define ACC_GET_HASH_INDEX(addr) \
- (((addr) + ((addr) >> 8) + ((addr) >> 16) + ((addr) >> 24)) \
- & ACC_FILTER_MASK)
-#endif
-#define ACC_GET_HINDEX(handle) ((handle) >> 20)
-
-#if (__FreeBSD_version > 500000)
-#define ACC_LOCK_INIT(ac) mtx_init(&(ac)->acc_mtx, "classifier", MTX_DEF)
-#define ACC_LOCK_DESTROY(ac) mtx_destroy(&(ac)->acc_mtx)
-#define ACC_LOCK(ac) mtx_lock(&(ac)->acc_mtx)
-#define ACC_UNLOCK(ac) mtx_unlock(&(ac)->acc_mtx)
-#else
-#define ACC_LOCK_INIT(ac)
-#define ACC_LOCK_DESTROY(ac)
-#define ACC_LOCK(ac)
-#define ACC_UNLOCK(ac)
-#endif
-
-struct acc_classifier {
- u_int32_t acc_fbmask;
- LIST_HEAD(filt, acc_filter) acc_filters[ACC_FILTER_TABLESIZE];
-
-#if (__FreeBSD_version > 500000)
- struct mtx acc_mtx;
-#endif
-};
-
-/*
- * flowinfo mask bits used by classifier
- */
-/* for ipv4 */
-#define FIMB4_PROTO 0x0001
-#define FIMB4_TOS 0x0002
-#define FIMB4_DADDR 0x0004
-#define FIMB4_SADDR 0x0008
-#define FIMB4_DPORT 0x0010
-#define FIMB4_SPORT 0x0020
-#define FIMB4_GPI 0x0040
-#define FIMB4_ALL 0x007f
-/* for ipv6 */
-#define FIMB6_PROTO 0x0100
-#define FIMB6_TCLASS 0x0200
-#define FIMB6_DADDR 0x0400
-#define FIMB6_SADDR 0x0800
-#define FIMB6_DPORT 0x1000
-#define FIMB6_SPORT 0x2000
-#define FIMB6_GPI 0x4000
-#define FIMB6_FLABEL 0x8000
-#define FIMB6_ALL 0xff00
-
-#define FIMB_ALL (FIMB4_ALL|FIMB6_ALL)
-
-#define FIMB4_PORTS (FIMB4_DPORT|FIMB4_SPORT|FIMB4_GPI)
-#define FIMB6_PORTS (FIMB6_DPORT|FIMB6_SPORT|FIMB6_GPI)
-#endif /* ALTQ3_CLFIER_COMPAT */
-
-/*
- * machine dependent clock
- * a 64bit high resolution time counter.
- */
-extern int machclk_usepcc;
-extern u_int32_t machclk_freq;
-extern u_int32_t machclk_per_tick;
-extern void init_machclk(void);
-extern u_int64_t read_machclk(void);
-
-/*
- * debug support
- */
-#ifdef ALTQ_DEBUG
-#ifdef __STDC__
-#define ASSERT(e) ((e) ? (void)0 : altq_assert(__FILE__, __LINE__, #e))
-#else /* PCC */
-#define ASSERT(e) ((e) ? (void)0 : altq_assert(__FILE__, __LINE__, "e"))
-#endif
-#else
-#define ASSERT(e) ((void)0)
-#endif
-
-/*
- * misc stuff for compatibility
- */
-/* ioctl cmd type */
-#if defined(__FreeBSD__) && (__FreeBSD__ < 3)
-typedef int ioctlcmd_t;
-#else
-typedef u_long ioctlcmd_t;
-#endif
-
-/*
- * queue macros:
- * the interface of TAILQ_LAST macro changed after the introduction
- * of softupdate. redefine it here to make it work with pre-2.2.7.
- */
-#undef TAILQ_LAST
-#define TAILQ_LAST(head, headname) \
- (*(((struct headname *)((head)->tqh_last))->tqh_last))
-
-#ifndef TAILQ_EMPTY
-#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
-#endif
-#ifndef TAILQ_FOREACH
-#define TAILQ_FOREACH(var, head, field) \
- for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field))
-#endif
-
-/* macro for timeout/untimeout */
-#if (__FreeBSD_version > 300000) || defined(__NetBSD__)
-/* use callout */
-#include <sys/callout.h>
-
-#if (__FreeBSD_version > 500000)
-#define CALLOUT_INIT(c) callout_init((c), 0)
-#else
-#define CALLOUT_INIT(c) callout_init((c))
-#endif
-#define CALLOUT_RESET(c,t,f,a) callout_reset((c),(t),(f),(a))
-#define CALLOUT_STOP(c) callout_stop((c))
-#ifndef CALLOUT_INITIALIZER
-#define CALLOUT_INITIALIZER { { { NULL } }, 0, NULL, NULL, 0 }
-#endif
-#elif defined(__OpenBSD__)
-#include <sys/timeout.h>
-/* callout structure as a wrapper of struct timeout */
-struct callout {
- struct timeout c_to;
-};
-#define CALLOUT_INIT(c) do { bzero((c), sizeof(*(c))); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_RESET(c,t,f,a) do { if (!timeout_initialized(&(c)->c_to)) \
- timeout_set(&(c)->c_to, (f), (a)); \
- timeout_add(&(c)->c_to, (t)); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_STOP(c) timeout_del(&(c)->c_to)
-#define CALLOUT_INITIALIZER { { { NULL }, NULL, NULL, 0, 0 } }
-#else
-/* use old-style timeout/untimeout */
-/* dummy callout structure */
-struct callout {
- void *c_arg; /* function argument */
- void (*c_func)(void *); /* functiuon to call */
-};
-#define CALLOUT_INIT(c) do { bzero((c), sizeof(*(c))); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_RESET(c,t,f,a) do { (c)->c_arg = (a); \
- (c)->c_func = (f); \
- timeout((f),(a),(t)); } while (/*CONSTCOND*/ 0)
-#define CALLOUT_STOP(c) untimeout((c)->c_func,(c)->c_arg)
-#define CALLOUT_INITIALIZER { NULL, NULL }
-#endif
-#if !defined(__FreeBSD__)
-typedef void (timeout_t)(void *);
-#endif
-
-#define m_pktlen(m) ((m)->m_pkthdr.len)
-
-extern int pfaltq_running;
-
-struct ifnet; struct mbuf;
-struct pf_altq;
-#ifdef ALTQ3_CLFIER_COMPAT
-struct flowinfo;
-#endif
-
-void *altq_lookup(char *, int);
-#ifdef ALTQ3_CLFIER_COMPAT
-int altq_extractflow(struct mbuf *, int, struct flowinfo *, u_int32_t);
-int acc_add_filter(struct acc_classifier *, struct flow_filter *,
- void *, u_long *);
-int acc_delete_filter(struct acc_classifier *, u_long);
-int acc_discard_filters(struct acc_classifier *, void *, int);
-void *acc_classify(void *, struct mbuf *, int);
-#endif
-u_int8_t read_dsfield(struct mbuf *, struct altq_pktattr *);
-void write_dsfield(struct mbuf *, struct altq_pktattr *, u_int8_t);
-void altq_assert(const char *, int, const char *);
-int tbr_set(struct ifaltq *, struct tb_profile *);
-int tbr_get(struct ifaltq *, struct tb_profile *);
-
-int altq_pfattach(struct pf_altq *);
-int altq_pfdetach(struct pf_altq *);
-int altq_add(struct pf_altq *);
-int altq_remove(struct pf_altq *);
-int altq_add_queue(struct pf_altq *);
-int altq_remove_queue(struct pf_altq *);
-int altq_getqstats(struct pf_altq *, void *, int *);
-
-int cbq_pfattach(struct pf_altq *);
-int cbq_add_altq(struct pf_altq *);
-int cbq_remove_altq(struct pf_altq *);
-int cbq_add_queue(struct pf_altq *);
-int cbq_remove_queue(struct pf_altq *);
-int cbq_getqstats(struct pf_altq *, void *, int *);
-
-int priq_pfattach(struct pf_altq *);
-int priq_add_altq(struct pf_altq *);
-int priq_remove_altq(struct pf_altq *);
-int priq_add_queue(struct pf_altq *);
-int priq_remove_queue(struct pf_altq *);
-int priq_getqstats(struct pf_altq *, void *, int *);
-
-int hfsc_pfattach(struct pf_altq *);
-int hfsc_add_altq(struct pf_altq *);
-int hfsc_remove_altq(struct pf_altq *);
-int hfsc_add_queue(struct pf_altq *);
-int hfsc_remove_queue(struct pf_altq *);
-int hfsc_getqstats(struct pf_altq *, void *, int *);
-
-#endif /* _KERNEL */
-#endif /* _ALTQ_ALTQ_VAR_H_ */
diff --git a/sbin/pfctl/missing/altq/altq_wfq.h b/sbin/pfctl/missing/altq/altq_wfq.h
deleted file mode 100644
index ca163cf3652d..000000000000
--- a/sbin/pfctl/missing/altq/altq_wfq.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* $FreeBSD$ */
-/* $KAME: altq_wfq.h,v 1.8 2003/07/10 12:07:49 kjc Exp $ */
-
-/*
- * Copyright (C) 1997-2002
- * Sony Computer Science Laboratories Inc. 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 SONY CSL 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 SONY CSL 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.
- */
-/*
- * March 27, 1997. Written by Hiroshi Kyusojin of Keio University
- * (kyu@mt.cs.keio.ac.jp).
- */
-
-#ifndef _ALTQ_ALTQ_WFQ_H_
-#define _ALTQ_ALTQ_WFQ_H_
-
-#include <altq/altq.h>
-
-#define DEFAULT_QSIZE 256
-#define MAX_QSIZE 2048
-
-struct wfq_interface{
- char wfq_ifacename[IFNAMSIZ];
-};
-
-struct wfq_getqid{
- struct wfq_interface iface;
-#ifdef ALTQ3_CLFIER_COMPAT
- struct flowinfo flow;
-#endif
- u_long qid;
-};
-
-struct wfq_setweight {
- struct wfq_interface iface;
- int qid;
- int weight;
-};
-
-typedef struct each_queue_stats {
- int bytes; /* bytes in this queue */
- int weight; /* weight in percent */
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
-} queue_stats;
-
-struct wfq_getstats {
- struct wfq_interface iface;
- int qid;
- queue_stats stats;
-};
-
-struct wfq_conf {
- struct wfq_interface iface;
- int hash_policy; /* hash policy */
- int nqueues; /* number of queues */
- int qlimit; /* queue size in bytes */
-};
-
-#define WFQ_HASH_DSTADDR 0 /* hash by dst address */
-#define WFQ_HASH_SRCPORT 1 /* hash by src port */
-#define WFQ_HASH_FULL 2 /* hash by all fields */
-
-#define WFQ_IF_ATTACH _IOW('Q', 1, struct wfq_interface)
-#define WFQ_IF_DETACH _IOW('Q', 2, struct wfq_interface)
-#define WFQ_ENABLE _IOW('Q', 3, struct wfq_interface)
-#define WFQ_DISABLE _IOW('Q', 4, struct wfq_interface)
-#define WFQ_CONFIG _IOWR('Q', 6, struct wfq_conf)
-#define WFQ_GET_STATS _IOWR('Q', 12, struct wfq_getstats)
-#define WFQ_GET_QID _IOWR('Q', 30, struct wfq_getqid)
-#define WFQ_SET_WEIGHT _IOWR('Q', 31, struct wfq_setweight)
-
-#ifdef _KERNEL
-
-#define HWM (64 * 1024)
-#define WFQ_QUOTA 512 /* quota bytes to send at a time */
-#define WFQ_ADDQUOTA(q) ((q)->quota += WFQ_QUOTA * (q)->weight / 100)
-#define ENABLE 0
-#define DISABLE 1
-
-typedef struct weighted_fair_queue{
- struct weighted_fair_queue *next, *prev;
- struct mbuf *head, *tail;
- int bytes; /* bytes in this queue */
- int quota; /* bytes sent in this round */
- int weight; /* weight in percent */
-
- struct pktcntr xmit_cnt;
- struct pktcntr drop_cnt;
-} wfq;
-
-
-typedef struct wfqstate {
- struct wfqstate *next; /* for wfqstate list */
- struct ifaltq *ifq;
- int nums; /* number of queues */
- int hwm; /* high water mark */
- int bytes; /* total bytes in all the queues */
- wfq *rrp; /* round robin pointer */
- wfq *queue; /* pointer to queue list */
-#ifdef ALTQ3_CLFIER_COMPAT
- u_long (*hash_func)(struct flowinfo *, int);
-#endif
- u_int32_t fbmask; /* filter bitmask */
-} wfq_state_t;
-
-#endif /* _KERNEL */
-
-#endif /* _ALTQ_ALTQ_WFQ_H */
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
new file mode 100644
index 000000000000..99c26c0a33df
--- /dev/null
+++ b/sbin/pfctl/parse.y
@@ -0,0 +1,6038 @@
+/* $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.
+ */
+%{
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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 <altq/altq.h>
+#include <altq/altq_cbq.h>
+#include <altq/altq_priq.h>
+#include <altq/altq_hfsc.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"
+
+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;
+
+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);
+
+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;
+};
+
+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;
+};
+
+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
+ 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;
+ struct {
+ struct node_host *addr;
+ u_int16_t port;
+ } divert;
+} filter_opts;
+
+struct antispoof_opts {
+ char *label;
+ u_int rtableid;
+} antispoof_opts;
+
+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;
+
+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;
+
+struct table_opts {
+ int flags;
+ int init_addr;
+ struct node_tinithead init_nodes;
+} table_opts;
+
+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;
+
+
+struct node_hfsc_opts hfsc_opts;
+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);
+
+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;
+ } 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 PRIQ HFSC BANDWIDTH TBRSIZE LINKSHARE REALTIME UPPERLIMIT
+%token QUEUE PRIORITY QLIMIT RTABLE
+%token LOAD RULESET_OPTIMIZATION
+%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
+%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.queue_bwspec> bandwidth
+%type <v.filter_opts> filter_opts filter_opt filter_opts_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;
+
+ 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 { $$ = PFRULE_FRAGCROP; }
+ | FRAGMENT FRAGDROP { $$ = PFRULE_FRAGDROP; }
+ ;
+
+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) {
+ 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 (!strcmp(cp, "b"))
+ ; /* nothing */
+ else if (!strcmp(cp, "Kb"))
+ bps *= 1000;
+ else if (!strcmp(cp, "Mb"))
+ bps *= 1000 * 1000;
+ else if (!strcmp(cp, "Gb"))
+ 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;
+ }
+ ;
+
+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 {
+ 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 {
+ 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 {
+ yyerror("unknown hfsc flag \"%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;
+
+ 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;
+ }
+ | 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
+ }
+ ;
+
+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
+ $$ = 0; /* flag bad argument */
+ if (!$$ || $$ > 255) {
+ yyerror("illegal tos value %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ | NUMBER {
+ $$ = $1;
+ if (!$$ || $$ > 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);
+ }
+ ;
+
+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; }
+ ;
+
+%%
+
+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);
+ 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);
+ 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},
+ { "cbq", CBQ},
+ { "code", CODE},
+ { "crop", FRAGCROP},
+ { "debug", DEBUG},
+ { "divert-reply", DIVERTREPLY},
+ { "divert-to", DIVERTTO},
+ { "drop", DROP},
+ { "drop-ovl", FRAGDROP},
+ { "dup-to", DUPTO},
+ { "fastroute", FASTROUTE},
+ { "file", FILENAME},
+ { "fingerprints", FINGERPRINTS},
+ { "flags", FLAGS},
+ { "floating", FLOATING},
+ { "flush", FLUSH},
+ { "for", FOR},
+ { "fragment", FRAGMENT},
+ { "from", FROM},
+ { "global", GLOBAL},
+ { "group", GROUP},
+ { "hfsc", HFSC},
+ { "hostid", HOSTID},
+ { "icmp-type", ICMPTYPE},
+ { "icmp6-type", ICMP6TYPE},
+ { "if-bound", IFBOUND},
+ { "in", IN},
+ { "include", INCLUDE},
+ { "inet", INET},
+ { "inet6", INET6},
+ { "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},
+ { "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},
+ { "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
+
+char *parsebuf;
+int parseindex;
+char pushback_buffer[MAXPUSHBACK];
+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 grammer.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
new file mode 100644
index 000000000000..d4a2c1d2939b
--- /dev/null
+++ b/sbin/pfctl/pf_print_state.c
@@ -0,0 +1,362 @@
+/* $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$");
+
+#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"
+
+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 *sk, *nk;
+ struct protoent *p;
+ int min, sec;
+
+ if (s->direction == PF_OUT) {
+ src = &s->src;
+ dst = &s->dst;
+ sk = &s->key[PF_SK_STACK];
+ nk = &s->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 = &s->key[PF_SK_WIRE];
+ nk = &s->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]);
+ } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
+ dst->state < PFOTHERS_NSTATES) {
+ /* 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/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
new file mode 100644
index 000000000000..5c0e7b37f4de
--- /dev/null
+++ b/sbin/pfctl/pfctl.8
@@ -0,0 +1,687 @@
+.\" $OpenBSD: pfctl.8,v 1.138 2008/06/10 20:55:02 mcbride Exp $
+.\"
+.\" Copyright (c) 2001 Kjell Wooding. 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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 21, 2011
+.Dt PFCTL 8
+.Os
+.Sh NAME
+.Nm pfctl
+.Nd control the packet filter (PF) device
+.Sh SYNOPSIS
+.Nm pfctl
+.Bk -words
+.Op Fl AdeghmNnOPqRrvz
+.Op Fl a Ar anchor
+.Oo Fl D Ar macro Ns =
+.Ar value Oc
+.Op Fl F Ar modifier
+.Op Fl f Ar file
+.Op Fl i Ar interface
+.Op Fl K Ar host | network
+.Xo
+.Oo Fl k
+.Ar host | network | label | id
+.Oc Xc
+.Op Fl o Ar level
+.Op Fl p Ar device
+.Op Fl s Ar modifier
+.Xo
+.Oo Fl t Ar table
+.Fl T Ar command
+.Op Ar address ...
+.Oc Xc
+.Op Fl x Ar level
+.Ek
+.Sh DESCRIPTION
+The
+.Nm
+utility communicates with the packet filter device using the
+ioctl interface described in
+.Xr pf 4 .
+It allows ruleset and parameter configuration and retrieval of status
+information from the packet filter.
+.Pp
+Packet filtering restricts the types of packets that pass through
+network interfaces entering or leaving the host based on filter
+rules as described in
+.Xr pf.conf 5 .
+The packet filter can also replace addresses and ports of packets.
+Replacing source addresses and ports of outgoing packets is called
+NAT (Network Address Translation) and is used to connect an internal
+network (usually reserved address space) to an external one (the
+Internet) by making all connections to external hosts appear to
+come from the gateway.
+Replacing destination addresses and ports of incoming packets
+is used to redirect connections to different hosts and/or ports.
+A combination of both translations, bidirectional NAT, is also
+supported.
+Translation rules are described in
+.Xr pf.conf 5 .
+.Pp
+When the variable
+.Va pf
+is set to
+.Dv YES
+in
+.Xr rc.conf 5 ,
+the rule file specified with the variable
+.Va pf_rules
+is loaded automatically by the
+.Xr rc 8
+scripts and the packet filter is enabled.
+.Pp
+The packet filter does not itself forward packets between interfaces.
+Forwarding can be enabled by setting the
+.Xr sysctl 8
+variables
+.Em net.inet.ip.forwarding
+and/or
+.Em net.inet6.ip6.forwarding
+to 1.
+Set them permanently in
+.Xr sysctl.conf 5 .
+.Pp
+The
+.Nm
+utility provides several commands.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl A
+Load only the queue rules present in the rule file.
+Other rules and options are ignored.
+.It Fl a Ar anchor
+Apply flags
+.Fl f ,
+.Fl F ,
+and
+.Fl s
+only to the rules in the specified
+.Ar anchor .
+In addition to the main ruleset,
+.Nm
+can load and manipulate additional rulesets by name,
+called anchors.
+The main ruleset is the default anchor.
+.Pp
+Anchors are referenced by name and may be nested,
+with the various components of the anchor path separated by
+.Sq /
+characters, similar to how file system hierarchies are laid out.
+The last component of the anchor path is where ruleset operations are
+performed.
+.Pp
+Evaluation of
+.Ar anchor
+rules from the main ruleset is described in
+.Xr pf.conf 5 .
+.Pp
+For example, the following will show all filter rules (see the
+.Fl s
+flag below) inside the anchor
+.Dq authpf/smith(1234) ,
+which would have been created for user
+.Dq smith
+by
+.Xr authpf 8 ,
+PID 1234:
+.Bd -literal -offset indent
+# pfctl -a "authpf/smith(1234)" -s rules
+.Ed
+.Pp
+Private tables can also be put inside anchors, either by having table
+statements in the
+.Xr pf.conf 5
+file that is loaded in the anchor, or by using regular table commands, as in:
+.Bd -literal -offset indent
+# pfctl -a foo/bar -t mytable -T add 1.2.3.4 5.6.7.8
+.Ed
+.Pp
+When a rule referring to a table is loaded in an anchor, the rule will use the
+private table if one is defined, and then fall back to the table defined in the
+main ruleset, if there is one.
+This is similar to C rules for variable scope.
+It is possible to create distinct tables with the same name in the global
+ruleset and in an anchor, but this is often bad design and a warning will be
+issued in that case.
+.Pp
+By default, recursive inline printing of anchors applies only to unnamed
+anchors specified inline in the ruleset.
+If the anchor name is terminated with a
+.Sq *
+character, the
+.Fl s
+flag will recursively print all anchors in a brace delimited block.
+For example the following will print the
+.Dq authpf
+ruleset recursively:
+.Bd -literal -offset indent
+# pfctl -a 'authpf/*' -sr
+.Ed
+.Pp
+To print the main ruleset recursively, specify only
+.Sq *
+as the anchor name:
+.Bd -literal -offset indent
+# pfctl -a '*' -sr
+.Ed
+.It Fl D Ar macro Ns = Ns Ar value
+Define
+.Ar macro
+to be set to
+.Ar value
+on the command line.
+Overrides the definition of
+.Ar macro
+in the ruleset.
+.It Fl d
+Disable the packet filter.
+.It Fl e
+Enable the packet filter.
+.It Fl F Ar modifier
+Flush the filter parameters specified by
+.Ar modifier
+(may be abbreviated):
+.Pp
+.Bl -tag -width xxxxxxxxxxxx -compact
+.It Fl F Cm nat
+Flush the NAT rules.
+.It Fl F Cm queue
+Flush the queue rules.
+.It Fl F Cm rules
+Flush the filter rules.
+.It Fl F Cm states
+Flush the state table (NAT and filter).
+.It Fl F Cm Sources
+Flush the source tracking table.
+.It Fl F Cm info
+Flush the filter information (statistics that are not bound to rules).
+.It Fl F Cm Tables
+Flush the tables.
+.It Fl F Cm osfp
+Flush the passive operating system fingerprints.
+.It Fl F Cm all
+Flush all of the above.
+.El
+.It Fl f Ar file
+Load the rules contained in
+.Ar file .
+This
+.Ar file
+may contain macros, tables, options, and normalization, queueing,
+translation, and filtering rules.
+With the exception of macros and tables, the statements must appear in that
+order.
+.It Fl g
+Include output helpful for debugging.
+.It Fl h
+Help.
+.It Fl i Ar interface
+Restrict the operation to the given
+.Ar interface .
+.It Fl K Ar host | network
+Kill all of the source tracking entries originating from the specified
+.Ar host
+or
+.Ar network .
+A second
+.Fl K Ar host
+or
+.Fl K Ar network
+option may be specified, which will kill all the source tracking
+entries from the first host/network to the second.
+.It Xo
+.Fl k
+.Ar host | network | label | id
+.Xc
+Kill all of the state entries matching the specified
+.Ar host ,
+.Ar network ,
+.Ar label ,
+or
+.Ar id .
+.Pp
+For example, to kill all of the state entries originating from
+.Dq host :
+.Pp
+.Dl # pfctl -k host
+.Pp
+A second
+.Fl k Ar host
+or
+.Fl k Ar network
+option may be specified, which will kill all the state entries
+from the first host/network to the second.
+To kill all of the state entries from
+.Dq host1
+to
+.Dq host2 :
+.Pp
+.Dl # pfctl -k host1 -k host2
+.Pp
+To kill all states originating from 192.168.1.0/24 to 172.16.0.0/16:
+.Pp
+.Dl # pfctl -k 192.168.1.0/24 -k 172.16.0.0/16
+.Pp
+A network prefix length of 0 can be used as a wildcard.
+To kill all states with the target
+.Dq host2 :
+.Pp
+.Dl # pfctl -k 0.0.0.0/0 -k host2
+.Pp
+It is also possible to kill states by rule label or state ID.
+In this mode the first
+.Fl k
+argument is used to specify the type
+of the second argument.
+The following command would kill all states that have been created
+from rules carrying the label
+.Dq foobar :
+.Pp
+.Dl # pfctl -k label -k foobar
+.Pp
+To kill one specific state by its unique state ID
+(as shown by pfctl -s state -vv),
+use the
+.Ar id
+modifier and as a second argument the state ID and optional creator ID.
+To kill a state with ID 4823e84500000003 use:
+.Pp
+.Dl # pfctl -k id -k 4823e84500000003
+.Pp
+To kill a state with ID 4823e84500000018 created from a backup
+firewall with hostid 00000002 use:
+.Pp
+.Dl # pfctl -k id -k 4823e84500000018/2
+.Pp
+.It Fl m
+Merge in explicitly given options without resetting those
+which are omitted.
+Allows single options to be modified without disturbing the others:
+.Bd -literal -offset indent
+# echo "set loginterface fxp0" | pfctl -mf -
+.Ed
+.It Fl N
+Load only the NAT rules present in the rule file.
+Other rules and options are ignored.
+.It Fl n
+Do not actually load rules, just parse them.
+.It Fl O
+Load only the options present in the rule file.
+Other rules and options are ignored.
+.It Fl o Ar level
+Control the ruleset optimizer, overriding any rule file settings.
+.Pp
+.Bl -tag -width xxxxxxxxxxxx -compact
+.It Fl o Cm none
+Disable the ruleset optimizer.
+.It Fl o Cm basic
+Enable basic ruleset optimizations.
+This is the default behaviour.
+.It Fl o Cm profile
+Enable basic ruleset optimizations with profiling.
+.El
+For further information on the ruleset optimizer, see
+.Xr pf.conf 5 .
+.It Fl P
+Do not perform service name lookup for port specific rules,
+instead display the ports numerically.
+.It Fl p Ar device
+Use the device file
+.Ar device
+instead of the default
+.Pa /dev/pf .
+.It Fl q
+Only print errors and warnings.
+.It Fl R
+Load only the filter rules present in the rule file.
+Other rules and options are ignored.
+.It Fl r
+Perform reverse DNS lookups on states when displaying them.
+.It Fl s Ar modifier
+Show the filter parameters specified by
+.Ar modifier
+(may be abbreviated):
+.Pp
+.Bl -tag -width xxxxxxxxxxxxx -compact
+.It Fl s Cm nat
+Show the currently loaded NAT rules.
+.It Fl s Cm queue
+Show the currently loaded queue rules.
+When used together with
+.Fl v ,
+per-queue statistics are also shown.
+When used together with
+.Fl v v ,
+.Nm
+will loop and show updated queue statistics every five seconds, including
+measured bandwidth and packets per second.
+.It Fl s Cm rules
+Show the currently loaded filter rules.
+When used together with
+.Fl v ,
+the per-rule statistics (number of evaluations,
+packets and bytes) are also shown.
+Note that the
+.Dq skip step
+optimization done automatically by the kernel
+will skip evaluation of rules where possible.
+Packets passed statefully are counted in the rule that created the state
+(even though the rule isn't evaluated more than once for the entire
+connection).
+.It Fl s Cm Anchors
+Show the currently loaded anchors directly attached to the main ruleset.
+If
+.Fl a Ar anchor
+is specified as well, the anchors loaded directly below the given
+.Ar anchor
+are shown instead.
+If
+.Fl v
+is specified, all anchors attached under the target anchor will be
+displayed recursively.
+.It Fl s Cm states
+Show the contents of the state table.
+.It Fl s Cm Sources
+Show the contents of the source tracking table.
+.It Fl s Cm info
+Show filter information (statistics and counters).
+When used together with
+.Fl v ,
+source tracking statistics are also shown.
+.It Fl s Cm labels
+Show per-rule statistics (label, evaluations, packets total, bytes total,
+packets in, bytes in, packets out, bytes out, state creations) of
+filter rules with labels, useful for accounting.
+.It Fl s Cm timeouts
+Show the current global timeouts.
+.It Fl s Cm memory
+Show the current pool memory hard limits.
+.It Fl s Cm Tables
+Show the list of tables.
+.It Fl s Cm osfp
+Show the list of operating system fingerprints.
+.It Fl s Cm Interfaces
+Show the list of interfaces and interface drivers available to PF.
+When used together with
+.Fl v ,
+it additionally lists which interfaces have skip rules activated.
+When used together with
+.Fl vv ,
+interface statistics are also shown.
+.Fl i
+can be used to select an interface or a group of interfaces.
+.It Fl s Cm all
+Show all of the above, except for the lists of interfaces and operating
+system fingerprints.
+.El
+.It Fl T Ar command Op Ar address ...
+Specify the
+.Ar command
+(may be abbreviated) to apply to the table.
+Commands include:
+.Pp
+.Bl -tag -width xxxxxxxxxxxx -compact
+.It Fl T Cm kill
+Kill a table.
+.It Fl T Cm flush
+Flush all addresses of a table.
+.It Fl T Cm add
+Add one or more addresses in a table.
+Automatically create a nonexisting table.
+.It Fl T Cm delete
+Delete one or more addresses from a table.
+.It Fl T Cm expire Ar number
+Delete addresses which had their statistics cleared more than
+.Ar number
+seconds ago.
+For entries which have never had their statistics cleared,
+.Ar number
+refers to the time they were added to the table.
+.It Fl T Cm replace
+Replace the addresses of the table.
+Automatically create a nonexisting table.
+.It Fl T Cm show
+Show the content (addresses) of a table.
+.It Fl T Cm test
+Test if the given addresses match a table.
+.It Fl T Cm zero
+Clear all the statistics of a table.
+.It Fl T Cm load
+Load only the table definitions from
+.Xr pf.conf 5 .
+This is used in conjunction with the
+.Fl f
+flag, as in:
+.Bd -literal -offset indent
+# pfctl -Tl -f pf.conf
+.Ed
+.El
+.Pp
+For the
+.Cm add ,
+.Cm delete ,
+.Cm replace ,
+and
+.Cm test
+commands, the list of addresses can be specified either directly on the command
+line and/or in an unformatted text file, using the
+.Fl f
+flag.
+Comments starting with a
+.Sq #
+are allowed in the text file.
+With these commands, the
+.Fl v
+flag can also be used once or twice, in which case
+.Nm
+will print the
+detailed result of the operation for each individual address, prefixed by
+one of the following letters:
+.Pp
+.Bl -tag -width XXX -compact
+.It A
+The address/network has been added.
+.It C
+The address/network has been changed (negated).
+.It D
+The address/network has been deleted.
+.It M
+The address matches
+.Po
+.Cm test
+operation only
+.Pc .
+.It X
+The address/network is duplicated and therefore ignored.
+.It Y
+The address/network cannot be added/deleted due to conflicting
+.Sq \&!
+attributes.
+.It Z
+The address/network has been cleared (statistics).
+.El
+.Pp
+Each table can maintain a set of counters that can be retrieved using the
+.Fl v
+flag of
+.Nm .
+For example, the following commands define a wide open firewall which will keep
+track of packets going to or coming from the
+.Ox
+FTP server.
+The following commands configure the firewall and send 10 pings to the FTP
+server:
+.Bd -literal -offset indent
+# printf "table <test> counters { ftp.openbsd.org }\en \e
+ pass out to <test>\en" | pfctl -f-
+# ping -qc10 ftp.openbsd.org
+.Ed
+.Pp
+We can now use the table
+.Cm show
+command to output, for each address and packet direction, the number of packets
+and bytes that are being passed or blocked by rules referencing the table.
+The time at which the current accounting started is also shown with the
+.Dq Cleared
+line.
+.Bd -literal -offset indent
+# pfctl -t test -vTshow
+ 129.128.5.191
+ Cleared: Thu Feb 13 18:55:18 2003
+ In/Block: [ Packets: 0 Bytes: 0 ]
+ In/Pass: [ Packets: 10 Bytes: 840 ]
+ Out/Block: [ Packets: 0 Bytes: 0 ]
+ Out/Pass: [ Packets: 10 Bytes: 840 ]
+.Ed
+.Pp
+Similarly, it is possible to view global information about the tables
+by using the
+.Fl v
+modifier twice and the
+.Fl s
+.Cm Tables
+command.
+This will display the number of addresses on each table,
+the number of rules which reference the table, and the global
+packet statistics for the whole table:
+.Bd -literal -offset indent
+# pfctl -vvsTables
+--a-r-C test
+ Addresses: 1
+ Cleared: Thu Feb 13 18:55:18 2003
+ References: [ Anchors: 0 Rules: 1 ]
+ Evaluations: [ NoMatch: 3496 Match: 1 ]
+ In/Block: [ Packets: 0 Bytes: 0 ]
+ In/Pass: [ Packets: 10 Bytes: 840 ]
+ In/XPass: [ Packets: 0 Bytes: 0 ]
+ Out/Block: [ Packets: 0 Bytes: 0 ]
+ Out/Pass: [ Packets: 10 Bytes: 840 ]
+ Out/XPass: [ Packets: 0 Bytes: 0 ]
+.Ed
+.Pp
+As we can see here, only one packet \- the initial ping request \- matched the
+table, but all packets passing as the result of the state are correctly
+accounted for.
+Reloading the table(s) or ruleset will not affect packet accounting in any way.
+The two
+.Dq XPass
+counters are incremented instead of the
+.Dq Pass
+counters when a
+.Dq stateful
+packet is passed but doesn't match the table anymore.
+This will happen in our example if someone flushes the table while the
+.Xr ping 8
+command is running.
+.Pp
+When used with a single
+.Fl v ,
+.Nm
+will only display the first line containing the table flags and name.
+The flags are defined as follows:
+.Pp
+.Bl -tag -width XXX -compact
+.It c
+For constant tables, which cannot be altered outside
+.Xr pf.conf 5 .
+.It p
+For persistent tables, which don't get automatically killed when no rules
+refer to them.
+.It a
+For tables which are part of the
+.Em active
+tableset.
+Tables without this flag do not really exist, cannot contain addresses, and are
+only listed if the
+.Fl g
+flag is given.
+.It i
+For tables which are part of the
+.Em inactive
+tableset.
+This flag can only be witnessed briefly during the loading of
+.Xr pf.conf 5 .
+.It r
+For tables which are referenced (used) by rules.
+.It h
+This flag is set when a table in the main ruleset is hidden by one or more
+tables of the same name from anchors attached below it.
+.It C
+This flag is set when per-address counters are enabled on the table.
+.El
+.It Fl t Ar table
+Specify the name of the table.
+.It Fl v
+Produce more verbose output.
+A second use of
+.Fl v
+will produce even more verbose output including ruleset warnings.
+See the previous section for its effect on table commands.
+.It Fl x Ar level
+Set the debug
+.Ar level
+(may be abbreviated) to one of the following:
+.Pp
+.Bl -tag -width xxxxxxxxxxxx -compact
+.It Fl x Cm none
+Don't generate debug messages.
+.It Fl x Cm urgent
+Generate debug messages only for serious errors.
+.It Fl x Cm misc
+Generate debug messages for various errors.
+.It Fl x Cm loud
+Generate debug messages for common conditions.
+.El
+.It Fl z
+Clear per-rule statistics.
+.El
+.Sh FILES
+.Bl -tag -width "/etc/pf.conf" -compact
+.It Pa /etc/pf.conf
+Packet filter rules file.
+.It Pa /etc/pf.os
+Passive operating system fingerprint database.
+.El
+.Sh SEE ALSO
+.Xr pf 4 ,
+.Xr pf.conf 5 ,
+.Xr pf.os 5 ,
+.Xr rc.conf 5 ,
+.Xr services 5 ,
+.Xr sysctl.conf 5 ,
+.Xr authpf 8 ,
+.Xr ftp-proxy 8 ,
+.Xr rc 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+program and the
+.Xr pf 4
+filter mechanism first appeared in
+.Ox 3.0 .
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
new file mode 100644
index 000000000000..90a2bb5b7c7d
--- /dev/null
+++ b/sbin/pfctl/pfctl.c
@@ -0,0 +1,2391 @@
+/* $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$");
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <net/pfvar.h>
+#include <arpa/inet.h>
+#include <altq/altq.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pfctl_parser.h"
+#include "pfctl.h"
+
+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 *, unsigned int);
+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 **);
+
+struct pf_anchor_global pf_anchors;
+struct pf_anchor pf_main_anchor;
+
+const char *clearopt;
+char *rulesopt;
+const char *showopt;
+const char *debugopt;
+char *anchoropt;
+const char *optiopt = NULL;
+char *pf_device = "/dev/pf";
+char *ifaceopt;
+char *tableopt;
+const char *tblcmdopt;
+int src_node_killers;
+char *src_node_kill[2];
+int state_killers;
+char *state_kill[2];
+int loadopt;
+int altqsupport;
+
+int dev = -1;
+int first_title = 1;
+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 *clearopt_list[] = {
+ "nat", "queue", "rules", "Sources",
+ "states", "info", "Tables", "osfp", "all", NULL
+};
+
+static const char *showopt_list[] = {
+ "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
+ "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
+ "all", NULL
+};
+
+static const char *tblcmdopt_list[] = {
+ "kill", "flush", "add", "delete", "load", "replace", "show",
+ "test", "zero", "expire", NULL
+};
+
+static const char *debugopt_list[] = {
+ "none", "urgent", "misc", "loud", NULL
+};
+
+static const char *optiopt_list[] = {
+ "none", "basic", "profile", NULL
+};
+
+void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname);
+ fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
+ fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n");
+ fprintf(stderr, "\t[-k host | network | label | id] ");
+ fprintf(stderr, "[-o level] [-p device]\n");
+ fprintf(stderr, "\t[-s modifier] ");
+ fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n");
+ exit(1);
+}
+
+int
+pfctl_enable(int dev, int opts)
+{
+ if (ioctl(dev, DIOCSTART)) {
+ if (errno == EEXIST)
+ errx(1, "pf already enabled");
+#ifdef __FreeBSD__
+ else if (errno == ESRCH)
+ errx(1, "pfil registeration failed");
+#endif
+ 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: %-6u]\n",
+ (unsigned long long)rule->evaluations,
+ (unsigned long long)(rule->packets[0] +
+ rule->packets[1]),
+ (unsigned long long)(rule->bytes[0] +
+ rule->bytes[1]), rule->states_cur);
+ if (!(opts & PF_OPT_DEBUG))
+ printf(" [ Inserted: uid %u pid %u "
+ "State Creations: %-6u]\n",
+ (unsigned)rule->cuid, (unsigned)rule->cpid,
+ rule->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 %llu\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],
+ (unsigned long long)pr.rule.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;
+ static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT };
+ 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;
+
+ 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_QUIET))
+ 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 **list)
+{
+ if (cmd != NULL && *cmd)
+ for (; *list; list++)
+ if (!strncmp(cmd, *list, strlen(cmd)))
+ return (*list);
+ return (NULL);
+}
+
+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;
+
+ 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)