diff options
499 files changed, 26532 insertions, 9991 deletions
@@ -22,6 +22,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 9.x IS SLOW: machines to maximize performance. (To disable malloc debugging, run ln -s aj /etc/malloc.conf.) +20110628: + The packet filter (pf) code has been updated to OpenBSD 4.5. + You need to update userland tools to be in sync with kernel. + This update breaks backward compatibility with earlier pfsync(4) + versions. Care must be taken when updating redundant firewall setups. + 20110608: The following sysctls and tunables are retired on x86 platforms: machdep.hlt_cpus diff --git a/bin/rcp/rcp.c b/bin/rcp/rcp.c index 2c27b63..4577b20 100644 --- a/bin/rcp/rcp.c +++ b/bin/rcp/rcp.c @@ -71,7 +71,6 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <string.h> #include <unistd.h> #include "extern.h" diff --git a/bin/realpath/realpath.1 b/bin/realpath/realpath.1 index cf904ed..8df1047 100644 --- a/bin/realpath/realpath.1 +++ b/bin/realpath/realpath.1 @@ -33,7 +33,7 @@ .\" From: src/bin/pwd/pwd.1,v 1.11 2000/11/20 11:39:39 ru Exp .\" $FreeBSD$ .\" -.Dd November 24, 2000 +.Dd June 21, 2011 .Dt REALPATH 1 .Os .Sh NAME @@ -42,8 +42,7 @@ .Sh SYNOPSIS .Nm .Op Fl q -.Ar path -.Op Ar ... +.Op Ar path ... .Sh DESCRIPTION The .Nm @@ -57,6 +56,11 @@ and .Pa /../ in .Ar path . +If +.Ar path +is absent, the current working directory +.Pq Sq Pa .\& +is assumed. .Pp If .Fl q diff --git a/bin/realpath/realpath.c b/bin/realpath/realpath.c index 99f5a9d5..a2ae06b 100644 --- a/bin/realpath/realpath.c +++ b/bin/realpath/realpath.c @@ -44,7 +44,8 @@ main(int argc, char *argv[]) { char buf[PATH_MAX]; char *p; - int ch, i, qflag, rval; + const char *path; + int ch, qflag, rval; qflag = 0; while ((ch = getopt(argc, argv, "q")) != -1) { @@ -59,17 +60,16 @@ main(int argc, char *argv[]) } argc -= optind; argv += optind; - if (argc < 1) - usage(); + path = *argv != NULL ? *argv++ : "."; rval = 0; - for (i = 0; i < argc; i++) { - if ((p = realpath(argv[i], buf)) == NULL) { + do { + if ((p = realpath(path, buf)) == NULL) { if (!qflag) - warn("%s", argv[i]); + warn("%s", path); rval = 1; } else (void)printf("%s\n", p); - } + } while ((path = *argv++) != NULL); exit(rval); } @@ -77,6 +77,6 @@ static void usage(void) { - (void)fprintf(stderr, "usage: realpath [-q] path [...]\n"); + (void)fprintf(stderr, "usage: realpath [-q] [path ...]\n"); exit(1); } diff --git a/bin/sh/arith_yacc.c b/bin/sh/arith_yacc.c index f1ac59e..041e638 100644 --- a/bin/sh/arith_yacc.c +++ b/bin/sh/arith_yacc.c @@ -35,7 +35,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/limits.h> +#include <limits.h> #include <errno.h> #include <inttypes.h> #include <stdlib.h> diff --git a/bin/sh/mkinit.c b/bin/sh/mkinit.c index 866b238..1d1d93e 100644 --- a/bin/sh/mkinit.c +++ b/bin/sh/mkinit.c @@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$"); */ -#include <sys/cdefs.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index e318216..4a9fe06 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -32,7 +32,7 @@ .\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95 .\" $FreeBSD$ .\" -.Dd June 18, 2011 +.Dd June 24, 2011 .Dt SH 1 .Os .Sh NAME @@ -994,11 +994,22 @@ described later), separated by .Ql \&| characters. +Tilde expansion, parameter expansion, command substitution, +arithmetic expansion and quote removal are applied to the word. +Then, each pattern is expanded in turn using tilde expansion, +parameter expansion, command substitution and arithmetic expansion and +the expanded form of the word is checked against it. +If a match is found, the corresponding list is executed. If the selected list is terminated by the control operator .Ql ;& instead of .Ql ;; , -execution continues with the next list. +execution continues with the next list, +continuing until a list terminated with +.Ql ;; +or the end of the +.Ic case +command. The exit code of the .Ic case command is the exit code of the last command executed in the list or @@ -1618,15 +1629,15 @@ There are two restrictions on this: first, a pattern cannot match a string containing a slash, and second, a pattern cannot match a string starting with a period unless the first character of the pattern is a period. -The next section describes the patterns used for both -Pathname Expansion and the +The next section describes the patterns used for +Pathname Expansion, +the four varieties of parameter expansion for substring processing and the .Ic case command. .Ss Shell Patterns A pattern consists of normal characters, which match themselves, and meta-characters. The meta-characters are -.Ql \&! , .Ql * , .Ql \&? , and @@ -1656,7 +1667,7 @@ matches a .Ql \&[ rather than introducing a character class. A character class matches any of the characters between the square brackets. -A range of characters may be specified using a minus sign. +A locale-dependent range of characters may be specified using a minus sign. A named class of characters (see .Xr wctype 3 ) may be specified by surrounding the name with @@ -1669,12 +1680,17 @@ is a shell pattern that matches a single letter. The character class may be complemented by making an exclamation point .Pq Ql !\& the first character of the character class. +A caret +.Pq Ql ^ +has the same effect but is non-standard. .Pp To include a .Ql \&] in a character class, make it the first character listed (after the -.Ql \&! , +.Ql \&! +or +.Ql ^ , if any). To include a .Ql - , diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 index 0d40a90..e5d8590 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs.8 +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs.8 @@ -6,6 +6,7 @@ .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. .\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with .\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] +.\" Copyright 2011 by Delphix. All rights reserved. .TH zfs 1M "24 Sep 2009" "SunOS 5.11" "System Administration Commands" .SH NAME zfs \- configures ZFS file systems @@ -389,7 +390,7 @@ This property can also be referred to by its shortened column name, \fBavail\fR. .ad .sp .6 .RS 4n -The compression ratio achieved for this dataset, expressed as a multiplier. Compression can be turned on by running: \fBzfs set compression=on \fIdataset\fR\fR. The default value is \fBoff\fR. +For non-snapshots, the compression ratio achieved for the \fBused\fR space of this dataset, expressed as a multiplier. The \fBused\fR property includes descendant datasets, and, for clones, does not include the space shared with the origin snapshot. For snapshots, the \fBcompressratio\fR is the same as the \fBrefcompressratio\fR property. Compression can be turned on by running: \fBzfs set compression=on \fIdataset\fR\fR. The default value is \fBoff\fR. .RE .sp @@ -453,6 +454,17 @@ This property can also be referred to by its shortened column name, \fBrefer\fR. .ne 2 .mk .na +\fB\fBrefcompressratio\fR\fR +.ad +.sp .6 +.RS 4n +The compression ratio achieved for the \fBreferenced\fR space of this dataset, expressed as a multiplier. See also the \fBcompressratio\fR property. +.RE + +.sp +.ne 2 +.mk +.na \fB\fBtype\fR\fR .ad .sp .6 @@ -1278,7 +1290,7 @@ Recursively destroy all dependents, including cloned file systems outside the ta Force an unmount of any file systems using the \fBunmount -f\fR command. This option has no effect on non-file systems or unmounted file systems. .RE -Extreme care should be taken when applying either the \fB-r\fR or the \fB-f\fR options, as they can destroy large portions of a pool and cause unexpected behavior for mounted file systems in use. +Extreme care should be taken when applying either the \fB-r\fR or the \fB-R\fR options, as they can destroy large portions of a pool and cause unexpected behavior for mounted file systems in use. .RE .sp diff --git a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c index 8383dbc..bc5a662 100644 --- a/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c +++ b/cddl/contrib/opensolaris/cmd/zfs/zfs_main.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2010 Nexenta Systems, Inc. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. */ #include <assert.h> @@ -1292,7 +1292,7 @@ static int zfs_do_get(int argc, char **argv) { zprop_get_cbdata_t cb = { 0 }; - int i, c, flags = 0; + int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS; char *value, *fields; int ret; int limit = 0; diff --git a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c index 824834e..82f4925 100644 --- a/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c +++ b/cddl/contrib/opensolaris/lib/libzfs/common/libzfs_dataset.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2010 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ #include <ctype.h> @@ -2038,6 +2039,7 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen, } break; + case ZFS_PROP_REFRATIO: case ZFS_PROP_COMPRESSRATIO: if (get_numeric_property(zhp, prop, src, &source, &val) != 0) return (-1); diff --git a/contrib/binutils/gas/config/tc-arm.c b/contrib/binutils/gas/config/tc-arm.c index 683e6ee..c48a758 100644 --- a/contrib/binutils/gas/config/tc-arm.c +++ b/contrib/binutils/gas/config/tc-arm.c @@ -9974,6 +9974,13 @@ do_t_rbit (void) } static void +do_t_rd_rm (void) +{ + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].reg; +} + +static void do_t_rev (void) { if (inst.operands[0].reg <= 7 && inst.operands[1].reg <= 7 @@ -14901,6 +14908,9 @@ static const struct asm_opcode insns[] = TCE(rsb, 0600000, ebc00000, 3, (RR, oRR, SH), arit, t_rsb), TC3(rsbs, 0700000, ebd00000, 3, (RR, oRR, SH), arit, t_rsb), + TCE(rrx, 1a00060, ea4f0030, 2, (RR, RR), rd_rm, t_rd_rm), + TCE(rrxs, 1b00060, ea5f0030, 2, (RR, RR), rd_rm, t_rd_rm), + #undef THUMB_VARIANT #define THUMB_VARIANT &arm_ext_v6 TCE(cpy, 1a00000, 4600, 2, (RR, RR), rd_rm, t_cpy), diff --git a/contrib/libpcap/bpf/net/bpf_filter.c b/contrib/libpcap/bpf/net/bpf_filter.c index db12bb2..f172384 100644 --- a/contrib/libpcap/bpf/net/bpf_filter.c +++ b/contrib/libpcap/bpf/net/bpf_filter.c @@ -405,7 +405,18 @@ bpf_filter(pc, p, wirelen, buflen) continue; case BPF_JMP|BPF_JA: +#if defined(KERNEL) || defined(_KERNEL) + /* + * No backward jumps allowed. + */ pc += pc->k; +#else + /* + * XXX - we currently implement "ip6 protochain" + * with backward jumps, so sign-extend pc->k. + */ + pc += (bpf_int32)pc->k; +#endif continue; case BPF_JMP|BPF_JGT|BPF_K: diff --git a/contrib/ntp/ntpd/ntp_config.c b/contrib/ntp/ntpd/ntp_config.c index beb4c48..99af999 100644 --- a/contrib/ntp/ntpd/ntp_config.c +++ b/contrib/ntp/ntpd/ntp_config.c @@ -414,7 +414,7 @@ enum gnn_type { static int getnetnum P((const char *, struct sockaddr_storage *, int, enum gnn_type)); static void save_resolve P((char *, int, int, int, int, u_int, int, - keyid_t, u_char *)); + keyid_t, u_char *, u_char)); static void do_resolve_internal P((void)); static void abort_resolve P((void)); #if !defined(VMS) && !defined(SYS_WINNT) @@ -870,9 +870,9 @@ getconfig( stoa(&peeraddr)); } } else if (errflg == -1) { - save_resolve(tokens[1], hmode, peerversion, + save_resolve(tokens[istart - 1], hmode, peerversion, minpoll, maxpoll, peerflags, ttl, - peerkey, peerkeystr); + peerkey, peerkeystr, peeraddr.ss_family); } break; @@ -2325,7 +2325,8 @@ save_resolve( u_int flags, int ttl, keyid_t keyid, - u_char *keystr + u_char *keystr, + u_char peeraf ) { #ifndef SYS_VXWORKS @@ -2365,11 +2366,11 @@ save_resolve( } #endif - (void)fprintf(res_fp, "%s %d %d %d %d %d %d %u %s\n", name, + (void)fprintf(res_fp, "%s %u %d %d %d %d %d %d %u %s\n", name, peeraf, mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); #ifdef DEBUG if (debug > 1) - printf("config: %s %d %d %d %d %x %d %u %s\n", name, mode, + printf("config: %s %u %d %d %d %d %x %d %u %s\n", name, peeraf, mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); #endif diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c index 5facc85..e18888f 100644 --- a/contrib/ntp/ntpd/ntp_intres.c +++ b/contrib/ntp/ntpd/ntp_intres.c @@ -29,6 +29,7 @@ #include <stdio.h> #include <ctype.h> +#include <resolv.h> #include <signal.h> /**/ @@ -111,15 +112,16 @@ static int resolve_value; /* next value of resolve timer */ * is supposed to consist of entries in the following order */ #define TOK_HOSTNAME 0 -#define TOK_HMODE 1 -#define TOK_VERSION 2 -#define TOK_MINPOLL 3 -#define TOK_MAXPOLL 4 -#define TOK_FLAGS 5 -#define TOK_TTL 6 -#define TOK_KEYID 7 -#define TOK_KEYSTR 8 -#define NUMTOK 9 +#define TOK_PEERAF 1 +#define TOK_HMODE 2 +#define TOK_VERSION 3 +#define TOK_MINPOLL 4 +#define TOK_MAXPOLL 5 +#define TOK_FLAGS 6 +#define TOK_TTL 7 +#define TOK_KEYID 8 +#define TOK_KEYSTR 9 +#define NUMTOK 10 #define MAXLINESIZE 512 @@ -140,7 +142,7 @@ char *req_file; /* name of the file with configuration info */ static void checkparent P((void)); static void removeentry P((struct conf_entry *)); static void addentry P((char *, int, int, int, int, u_int, - int, keyid_t, char *)); + int, keyid_t, char *, u_char)); static int findhostaddr P((struct conf_entry *)); static void openntp P((void)); static int request P((struct conf_peer *)); @@ -397,7 +399,8 @@ addentry( u_int flags, int ttl, keyid_t keyid, - char *keystr + char *keystr, + u_char peeraf ) { register char *cp; @@ -407,7 +410,7 @@ addentry( #ifdef DEBUG if (debug > 1) msyslog(LOG_INFO, - "intres: <%s> %d %d %d %d %x %d %x %s\n", name, + "intres: <%s> %u %d %d %d %d %x %d %x %s\n", name, peeraf, mode, version, minpoll, maxpoll, flags, ttl, keyid, keystr); #endif @@ -422,6 +425,7 @@ addentry( ce->ce_peeraddr6 = in6addr_any; #endif ANYSOCK(&ce->peer_store); + ce->peer_store.ss_family = peeraf; /* Save AF for getaddrinfo hints. */ ce->ce_hmode = (u_char)mode; ce->ce_version = (u_char)version; ce->ce_minpoll = (u_char)minpoll; @@ -482,7 +486,8 @@ findhostaddr( entry->ce_name)); memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; + hints.ai_family = entry->peer_store.ss_family; + hints.ai_socktype = SOCK_DGRAM; /* * If the IPv6 stack is not available look only for IPv4 addresses */ @@ -1051,6 +1056,13 @@ readconf( } } + if (intval[TOK_PEERAF] != AF_UNSPEC && intval[TOK_PEERAF] != + AF_INET && intval[TOK_PEERAF] != AF_INET6) { + msyslog(LOG_ERR, "invalid peer address family (%u) in " + "file %s", intval[TOK_PEERAF], name); + exit(1); + } + if (intval[TOK_HMODE] != MODE_ACTIVE && intval[TOK_HMODE] != MODE_CLIENT && intval[TOK_HMODE] != MODE_BROADCAST) { @@ -1107,7 +1119,7 @@ readconf( addentry(token[TOK_HOSTNAME], (int)intval[TOK_HMODE], (int)intval[TOK_VERSION], (int)intval[TOK_MINPOLL], (int)intval[TOK_MAXPOLL], flags, (int)intval[TOK_TTL], - intval[TOK_KEYID], token[TOK_KEYSTR]); + intval[TOK_KEYID], token[TOK_KEYSTR], (u_char)intval[TOK_PEERAF]); } } @@ -1129,6 +1141,9 @@ doconfigure( dores ? "with" : "without" ); #endif + if (dores) /* Reload /etc/resolv.conf - bug 1226 */ + res_init(); + ce = confentries; while (ce != NULL) { #ifdef DEBUG diff --git a/contrib/ntp/ntpd/ntp_io.c b/contrib/ntp/ntpd/ntp_io.c index 8dac3c4..2d5572a 100644 --- a/contrib/ntp/ntpd/ntp_io.c +++ b/contrib/ntp/ntpd/ntp_io.c @@ -2716,14 +2716,14 @@ sendpkt( for (slot = ERRORCACHESIZE; --slot >= 0; ) if(dest->ss_family == AF_INET) { - if (badaddrs[slot].port == ((struct sockaddr_in*)dest)->sin_port && + if (badaddrs[slot].port == SRCPORT(dest) && badaddrs[slot].addr.s_addr == ((struct sockaddr_in*)dest)->sin_addr.s_addr) break; } #ifdef INCLUDE_IPV6_SUPPORT else if (dest->ss_family == AF_INET6) { - if (badaddrs6[slot].port == ((struct sockaddr_in6*)dest)->sin6_port && - badaddrs6[slot].addr.s6_addr == ((struct sockaddr_in6*)dest)->sin6_addr.s6_addr) + if (badaddrs6[slot].port == SRCPORT(dest) && + !memcmp(&badaddrs6[slot].addr, &((struct sockaddr_in6*)dest)->sin6_addr, sizeof(struct in6_addr))) break; } #endif /* INCLUDE_IPV6_SUPPORT */ diff --git a/contrib/pf/authpf/authpf.8 b/contrib/pf/authpf/authpf.8 index bd4ff40..d365057 100644 --- a/contrib/pf/authpf/authpf.8 +++ b/contrib/pf/authpf/authpf.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $OpenBSD: authpf.8,v 1.43 2007/02/24 17:21:04 beck Exp $ +.\" $OpenBSD: authpf.8,v 1.47 2009/01/06 03:11:50 mcbride Exp $ .\" .\" Copyright (c) 1998-2007 Bob Beck (beck@openbsd.org>. All rights reserved. .\" @@ -15,14 +15,16 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd March 28, 2006 +.Dd January 6 2009 .Dt AUTHPF 8 .Os .Sh NAME -.Nm authpf +.Nm authpf , +.Nm authpf-noip .Nd authenticating gateway user shell .Sh SYNOPSIS .Nm authpf +.Nm authpf-noip .Sh DESCRIPTION .Nm is a user shell for authenticating gateways. @@ -31,47 +33,63 @@ It is used to change rules when a user authenticates and starts a session with .Xr sshd 8 and to undo these changes when the user's session exits. -It is designed for changing filter and translation rules for an individual -source IP address as long as a user maintains an active -.Xr ssh 1 -session. Typical use would be for a gateway that authenticates users before allowing them Internet use, or a gateway that allows different users into different places. +Combined with properly set up filter rules and secure switches, .Nm -logs the successful start and end of a session to -.Xr syslogd 8 . -This, combined with properly set up filter rules and secure switches, can be used to ensure users are held accountable for their network traffic. +It is meant to be used with users who can connect via +.Xr ssh 1 +only, and requires the +.Xr pf 4 +subsystem to be enabled. .Pp +.Nm authpf-noip +is a user shell +which allows multiple connections to take +place from the same IP address. +It is useful primarily in cases where connections are tunneled via +the gateway system, and can be directly associated with the user name. +It cannot ensure accountability when +classifying connections by IP address; +in this case the client's IP address +is not provided to the packet filter via the +.Ar client_ip +macro or the +.Ar authpf_users +table. +Additionally, states associated with the client IP address +are not purged when the session is ended. +.Pp +To use either .Nm -can add filter and translation rules using the syntax described in -.Xr pf.conf 5 . -.Nm -requires that the -.Xr pf 4 -system be enabled and a -.Xr fdescfs 5 -file system be mounted at -.Pa /dev/fd -before use. -.Nm -can also maintain the list of IP address of connected users -in the "authpf_users" -.Pa table . +or +.Nm authpf-noip , +the user's shell needs to be set to +.Pa /usr/sbin/authpf +or +.Pa /usr/sbin/authpf-noip . .Pp .Nm -is meant to be used with users who can connect via +uses the +.Xr pf.conf 5 +syntax to change filter and translation rules for an individual +user or client IP address as long as a user maintains an active .Xr ssh 1 -only. -On startup, +session, and logs the successful start and end of a session to +.Xr syslogd 8 . .Nm retrieves the client's connecting IP address via the .Ev SSH_CLIENT environment variable and, after performing additional access checks, reads a template file to determine what filter and translation rules -(if any) to add. -On session exit the same rules that were added at startup are removed. +(if any) to add, and +maintains the list of IP addresses of connected users in the +.Ar authpf_users +table. +On session exit the same rules and table entries that were added at startup +are removed, and all states associated with the client's IP address are purged. .Pp Each .Nm @@ -185,6 +203,9 @@ It is also possible to configure to only allow specific users access. This is done by listing their login names, one per line, in .Pa /etc/authpf/authpf.allow . +A group of users can also be indicated by prepending "%" to the group name, +and all members of a login class can be indicated by prepending "@" to the +login class name. If "*" is found on a line, then all usernames match. If .Nm @@ -297,7 +318,8 @@ They have a wireless network which they would like to protect from unauthorized use. To accomplish this, they create the file .Pa /etc/authpf/authpf.allow -which lists their login ids, one per line. +which lists their login ids, group prepended with "%", or login class +prepended with "@", one per line. At this point, even if eve could authenticate to .Xr sshd 8 , she would not be allowed to use the gateway. @@ -501,6 +523,31 @@ table <authpf_users> persist anchor "authpf/*" from <authpf_users> rdr-anchor "authpf/*" from <authpf_users> .Ed +.Pp +.Sy Tunneled users +\- normally +.Nm +allows only one session per client IP address. +However in some cases, such as when connections are tunneled via +.Xr ssh 1 +or +.Xr ipsec 4 , +the connections can be authorized based on the userid of the user instead of +the client IP address. +In this case it is appropriate to use +.Nm authpf-noip +to allow multiple users behind a NAT gateway to connect. +In the +.Pa /etc/authpf/authpf.rules +example below, the remote user could tunnel a remote desktop session to their +workstation: +.Bd -literal +internal_if="bge0" +workstation_ip="10.2.3.4" + +pass out on $internal_if from (self) to $workstation_ip port 3389 \e + user $user_id +.Ed .Sh FILES .Bl -tag -width "/etc/authpf/authpf.conf" -compact .It Pa /etc/authpf/authpf.conf @@ -512,7 +559,6 @@ rdr-anchor "authpf/*" from <authpf_users> .Sh SEE ALSO .Xr pf 4 , .Xr pf.conf 5 , -.Xr fdescfs 5 , .Xr securelevel 7 , .Xr ftp-proxy 8 .Sh HISTORY diff --git a/contrib/pf/authpf/authpf.c b/contrib/pf/authpf/authpf.c index 56d7728..ac5d85b 100644 --- a/contrib/pf/authpf/authpf.c +++ b/contrib/pf/authpf/authpf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authpf.c,v 1.104 2007/02/24 17:35:08 beck Exp $ */ +/* $OpenBSD: authpf.c,v 1.112 2009/01/10 19:08:53 miod Exp $ */ /* * Copyright (C) 1998 - 2007 Bob Beck (beck@openbsd.org). @@ -19,7 +19,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> +#include <sys/types.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #endif #include <login_cap.h> #include <pwd.h> +#include <grp.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -48,10 +49,11 @@ __FBSDID("$FreeBSD$"); #include "pathnames.h" static int read_config(FILE *); -static void print_message(char *); -static int allowed_luser(char *); -static int check_luser(char *, char *); +static void print_message(const char *); +static int allowed_luser(struct passwd *); +static int check_luser(const char *, char *); static int remove_stale_rulesets(void); +static int recursive_ruleset_purge(char *, char *); static int change_filter(int, const char *, const char *); static int change_table(int, const char *); static void authpf_kill_states(void); @@ -60,8 +62,10 @@ int dev; /* pf device */ char anchorname[PF_ANCHOR_NAME_SIZE] = "authpf"; char rulesetname[MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 2]; char tablename[PF_TABLE_NAME_SIZE] = "authpf_users"; +int user_ip = 1; /* controls whether $user_ip is set */ FILE *pidfp; +int pidfd = -1; char luser[MAXLOGNAME]; /* username */ char ipsrc[256]; /* ip as a string */ char pidfile[MAXPATHLEN]; /* we save pid in this file. */ @@ -75,6 +79,7 @@ static __dead2 void do_death(int); #else static __dead void do_death(int); #endif +extern char *__progname; /* program name */ /* * User shell for authenticating gateways. Sole purpose is to allow @@ -83,21 +88,24 @@ static __dead void do_death(int); * up. Meant to be used only from ssh(1) connections. */ int -main(int argc, char *argv[]) +main(void) { - int lockcnt = 0, n, pidfd; + int lockcnt = 0, n; FILE *config; struct in6_addr ina; struct passwd *pw; char *cp; gid_t gid; uid_t uid; - char *shell; + const char *shell; login_cap_t *lc; + if (strcmp(__progname, "-authpf-noip") == 0) + user_ip = 0; + config = fopen(PATH_CONFFILE, "r"); if (config == NULL) { - syslog(LOG_ERR, "can not open %s (%m)", PATH_CONFFILE); + syslog(LOG_ERR, "cannot open %s (%m)", PATH_CONFFILE); exit(1); } @@ -142,23 +150,34 @@ main(int argc, char *argv[]) } if ((lc = login_getclass(pw->pw_class)) != NULL) - shell = (char *)login_getcapstr(lc, "shell", pw->pw_shell, + shell = login_getcapstr(lc, "shell", pw->pw_shell, pw->pw_shell); else shell = pw->pw_shell; +#ifndef __FreeBSD__ login_close(lc); +#endif - if (strcmp(shell, PATH_AUTHPF_SHELL)) { + if (strcmp(shell, PATH_AUTHPF_SHELL) && + strcmp(shell, PATH_AUTHPF_SHELL_NOIP)) { syslog(LOG_ERR, "wrong shell for user %s, uid %u", pw->pw_name, pw->pw_uid); +#ifdef __FreeBSD__ + login_close(lc); +#else if (shell != pw->pw_shell) free(shell); +#endif goto die; } +#ifdef __FreeBSD__ + login_close(lc); +#else if (shell != pw->pw_shell) free(shell); +#endif /* * Paranoia, but this data _does_ come from outside authpf, and @@ -181,13 +200,22 @@ main(int argc, char *argv[]) } - /* Make our entry in /var/authpf as /var/authpf/ipaddr */ - n = snprintf(pidfile, sizeof(pidfile), "%s/%s", PATH_PIDFILE, ipsrc); + /* Make our entry in /var/authpf as ipaddr or username */ + n = snprintf(pidfile, sizeof(pidfile), "%s/%s", + PATH_PIDFILE, user_ip ? ipsrc : luser); if (n < 0 || (u_int)n >= sizeof(pidfile)) { syslog(LOG_ERR, "path to pidfile too long"); goto die; } + signal(SIGTERM, need_death); + signal(SIGINT, need_death); + signal(SIGALRM, need_death); + signal(SIGPIPE, need_death); + signal(SIGHUP, need_death); + signal(SIGQUIT, need_death); + signal(SIGTSTP, need_death); + /* * If someone else is already using this ip, then this person * wants to switch users - so kill the old process and exit @@ -241,15 +269,17 @@ main(int argc, char *argv[]) } /* - * we try to kill the previous process and acquire the lock + * We try to kill the previous process and acquire the lock * for 10 seconds, trying once a second. if we can't after - * 10 attempts we log an error and give up + * 10 attempts we log an error and give up. */ - if (++lockcnt > 10) { - syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", - otherpid); + if (want_death || ++lockcnt > 10) { + if (!want_death) + syslog(LOG_ERR, "cannot kill previous authpf (pid %d)", + otherpid); fclose(pidfp); pidfp = NULL; + pidfd = -1; goto dogdeath; } sleep(1); @@ -260,6 +290,7 @@ main(int argc, char *argv[]) */ fclose(pidfp); pidfp = NULL; + pidfd = -1; } while (1); /* whack the group list */ @@ -277,7 +308,7 @@ main(int argc, char *argv[]) } openlog("authpf", LOG_PID | LOG_NDELAY, LOG_DAEMON); - if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(luser)) { + if (!check_luser(PATH_BAN_DIR, luser) || !allowed_luser(pw)) { syslog(LOG_INFO, "user %s prohibited", luser); do_death(0); } @@ -302,19 +333,12 @@ main(int argc, char *argv[]) printf("Unable to modify filters\r\n"); do_death(0); } - if (change_table(1, ipsrc) == -1) { + if (user_ip && change_table(1, ipsrc) == -1) { printf("Unable to modify table\r\n"); change_filter(0, luser, ipsrc); do_death(0); } - signal(SIGTERM, need_death); - signal(SIGINT, need_death); - signal(SIGALRM, need_death); - signal(SIGPIPE, need_death); - signal(SIGHUP, need_death); - signal(SIGQUIT, need_death); - signal(SIGTSTP, need_death); while (1) { printf("\r\nHello %s. ", luser); printf("You are authenticated from host \"%s\"\r\n", ipsrc); @@ -337,8 +361,6 @@ dogdeath: sleep(180); /* them lusers read reaaaaal slow */ die: do_death(0); - - /* NOTREACHED */ } /* @@ -361,6 +383,8 @@ read_config(FILE *f) } i++; len = strlen(buf); + if (len == 0) + continue; if (buf[len - 1] != '\n' && !feof(f)) { syslog(LOG_ERR, "line %d too long in %s", i, PATH_CONFFILE); @@ -413,7 +437,7 @@ parse_error: * they've been bad or we're unavailable. */ static void -print_message(char *filename) +print_message(const char *filename) { char buf[1024]; FILE *f; @@ -436,6 +460,7 @@ print_message(char *filename) * allowed_luser checks to see if user "luser" is allowed to * use this gateway by virtue of being listed in an allowed * users file, namely /etc/authpf/authpf.allow . + * Users may be listed by <username>, %<group>, or @<login_class>. * * If /etc/authpf/authpf.allow does not exist, then we assume that * all users who are allowed in by sshd(8) are permitted to @@ -444,9 +469,9 @@ print_message(char *filename) * the session terminates in the same manner as being banned. */ static int -allowed_luser(char *luser) +allowed_luser(struct passwd *pw) { - char *buf, *lbuf; + char *buf,*lbuf; int matched; size_t len; FILE *f; @@ -476,8 +501,14 @@ allowed_luser(char *luser) * "public" gateway, such as it is, so let * everyone use it. */ + int gl_init = 0, ngroups = NGROUPS + 1; + gid_t groups[NGROUPS + 1]; + lbuf = NULL; + matched = 0; + while ((buf = fgetln(f, &len))) { + if (buf[len - 1] == '\n') buf[len - 1] = '\0'; else { @@ -488,7 +519,40 @@ allowed_luser(char *luser) buf = lbuf; } - matched = strcmp(luser, buf) == 0 || strcmp("*", buf) == 0; + if (buf[0] == '@') { + /* check login class */ + if (strcmp(pw->pw_class, buf + 1) == 0) + matched++; + } else if (buf[0] == '%') { + /* check group membership */ + int cnt; + struct group *group; + + if ((group = getgrnam(buf + 1)) == NULL) { + syslog(LOG_ERR, + "invalid group '%s' in %s (%s)", + buf + 1, PATH_ALLOWFILE, + strerror(errno)); + return (0); + } + + if (!gl_init) { + (void) getgrouplist(pw->pw_name, + pw->pw_gid, groups, &ngroups); + gl_init++; + } + + for ( cnt = 0; cnt < ngroups; cnt++) { + if (group->gr_gid == groups[cnt]) { + matched++; + break; + } + } + } else { + /* check username and wildcard */ + matched = strcmp(pw->pw_name, buf) == 0 || + strcmp("*", buf) == 0; + } if (lbuf != NULL) { free(lbuf); @@ -496,13 +560,13 @@ allowed_luser(char *luser) } if (matched) - return (1); /* matched an allowed username */ + return (1); /* matched an allowed user/group */ } syslog(LOG_INFO, "denied access to %s: not listed in %s", - luser, PATH_ALLOWFILE); + pw->pw_name, PATH_ALLOWFILE); /* reuse buf */ - buf = "\n\nSorry, you are not allowed to use this facility!\n"; + sprintf(buf, "%s", "\n\nSorry, you are not allowed to use this facility!\n"); fputs(buf, stdout); } fflush(stdout); @@ -520,13 +584,13 @@ allowed_luser(char *luser) * going to be un-banned.) */ static int -check_luser(char *luserdir, char *luser) +check_luser(const char *luserdir, char *l_user) { FILE *f; int n; char tmp[MAXPATHLEN]; - n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, luser); + n = snprintf(tmp, sizeof(tmp), "%s/%s", luserdir, l_user); if (n < 0 || (u_int)n >= sizeof(tmp)) { syslog(LOG_ERR, "provided banned directory line too long (%s)", luserdir); @@ -555,7 +619,7 @@ check_luser(char *luserdir, char *luser) * tell what they can do and where they can go. */ syslog(LOG_INFO, "denied access to %s: %s exists", - luser, tmp); + l_user, tmp); /* reuse tmp */ strlcpy(tmp, "\n\n-**- Sorry, you have been banned! -**-\n\n", @@ -581,7 +645,7 @@ static int remove_stale_rulesets(void) { struct pfioc_ruleset prs; - u_int32_t nr, mnr; + u_int32_t nr; memset(&prs, 0, sizeof(prs)); strlcpy(prs.path, anchorname, sizeof(prs.path)); @@ -592,13 +656,12 @@ remove_stale_rulesets(void) return (1); } - mnr = prs.nr; - nr = 0; - while (nr < mnr) { + nr = prs.nr; + while (nr) { char *s, *t; pid_t pid; - prs.nr = nr; + prs.nr = nr - 1; if (ioctl(dev, DIOCGETRULESET, &prs)) return (1); errno = 0; @@ -610,119 +673,159 @@ remove_stale_rulesets(void) if (!prs.name[0] || errno || (*s && (t == prs.name || *s != ')'))) return (1); - if (kill(pid, 0) && errno != EPERM) { - int i; - struct pfioc_trans_e t_e[PF_RULESET_MAX+1]; - struct pfioc_trans t; - - bzero(&t, sizeof(t)); - bzero(t_e, sizeof(t_e)); - t.size = PF_RULESET_MAX+1; - t.esize = sizeof(t_e[0]); - t.array = t_e; - for (i = 0; i < PF_RULESET_MAX+1; ++i) { - t_e[i].rs_num = i; - snprintf(t_e[i].anchor, sizeof(t_e[i].anchor), - "%s/%s", anchorname, prs.name); - } - t_e[PF_RULESET_MAX].rs_num = PF_RULESET_TABLE; - if ((ioctl(dev, DIOCXBEGIN, &t) || - ioctl(dev, DIOCXCOMMIT, &t)) && - errno != EINVAL) + if ((kill(pid, 0) && errno != EPERM) || pid == getpid()) { + if (recursive_ruleset_purge(anchorname, prs.name)) return (1); - mnr--; - } else - nr++; + } + nr--; } return (0); } +static int +recursive_ruleset_purge(char *an, char *rs) +{ + struct pfioc_trans_e *t_e = NULL; + struct pfioc_trans *t = NULL; + struct pfioc_ruleset *prs = NULL; + int i; + + + /* purge rules */ + errno = 0; + if ((t = calloc(1, sizeof(struct pfioc_trans))) == NULL) + goto no_mem; + if ((t_e = calloc(PF_RULESET_MAX+1, + sizeof(struct pfioc_trans_e))) == NULL) + goto no_mem; + t->size = PF_RULESET_MAX+1; + t->esize = sizeof(struct pfioc_trans_e); + t->array = t_e; + for (i = 0; i < PF_RULESET_MAX+1; ++i) { + t_e[i].rs_num = i; + snprintf(t_e[i].anchor, sizeof(t_e[i].anchor), "%s/%s", an, rs); + } + t_e[PF_RULESET_MAX].rs_num = PF_RULESET_TABLE; + if ((ioctl(dev, DIOCXBEGIN, t) || + ioctl(dev, DIOCXCOMMIT, t)) && + errno != EINVAL) + goto cleanup; + + /* purge any children */ + if ((prs = calloc(1, sizeof(struct pfioc_ruleset))) == NULL) + goto no_mem; + snprintf(prs->path, sizeof(prs->path), "%s/%s", an, rs); + if (ioctl(dev, DIOCGETRULESETS, prs)) { + if (errno != EINVAL) + goto cleanup; + errno = 0; + } else { + int nr = prs->nr; + + while (nr) { + prs->nr = 0; + if (ioctl(dev, DIOCGETRULESET, prs)) + goto cleanup; + + if (recursive_ruleset_purge(prs->path, prs->name)) + goto cleanup; + nr--; + } + } + +no_mem: + if (errno == ENOMEM) + syslog(LOG_ERR, "calloc failed"); + +cleanup: + free(t); + free(t_e); + free(prs); + return (errno); +} + /* * Add/remove filter entries for user "luser" from ip "ipsrc" */ static int -change_filter(int add, const char *luser, const char *ipsrc) +change_filter(int add, const char *l_user, const char *ip_src) { - char *pargv[13] = { - "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset", - "-D", "user_ip=X", "-D", "user_id=X", "-f", - "file", NULL - }; char *fdpath = NULL, *userstr = NULL, *ipstr = NULL; char *rsn = NULL, *fn = NULL; pid_t pid; gid_t gid; int s; - if (luser == NULL || !luser[0] || ipsrc == NULL || !ipsrc[0]) { - syslog(LOG_ERR, "invalid luser/ipsrc"); - goto error; - } - - if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1) - goto no_mem; - if (asprintf(&fdpath, "/dev/fd/%d", dev) == -1) - goto no_mem; - if (asprintf(&ipstr, "user_ip=%s", ipsrc) == -1) - goto no_mem; - if (asprintf(&userstr, "user_id=%s", luser) == -1) - goto no_mem; - if (add) { struct stat sb; + char *pargv[13] = { + "pfctl", "-p", "/dev/pf", "-q", "-a", "anchor/ruleset", + "-D", "user_id=X", "-D", "user_ip=X", "-f", "file", NULL + }; + + if (l_user == NULL || !l_user[0] || ip_src == NULL || !ip_src[0]) { + syslog(LOG_ERR, "invalid luser/ipsrc"); + goto error; + } - if (asprintf(&fn, "%s/%s/authpf.rules", PATH_USER_DIR, luser) - == -1) + if (asprintf(&rsn, "%s/%s", anchorname, rulesetname) == -1) + goto no_mem; + if (asprintf(&fdpath, "/dev/fd/%d", dev) == -1) + goto no_mem; + if (asprintf(&ipstr, "user_ip=%s", ip_src) == -1) + goto no_mem; + if (asprintf(&userstr, "user_id=%s", l_user) == -1) + goto no_mem; + if (asprintf(&fn, "%s/%s/authpf.rules", + PATH_USER_DIR, l_user) == -1) goto no_mem; if (stat(fn, &sb) == -1) { free(fn); if ((fn = strdup(PATH_PFRULES)) == NULL) goto no_mem; } - } - pargv[2] = fdpath; - pargv[5] = rsn; - pargv[7] = userstr; - pargv[9] = ipstr; - if (!add) - pargv[11] = "/dev/null"; - else - pargv[11] = fn; - - switch (pid = fork()) { - case -1: - syslog(LOG_ERR, "fork failed"); - goto error; - case 0: - /* revoke group privs before exec */ - gid = getgid(); - if (setregid(gid, gid) == -1) { - err(1, "setregid"); + pargv[2] = fdpath; + pargv[5] = rsn; + pargv[7] = userstr; + if (user_ip) { + pargv[9] = ipstr; + pargv[11] = fn; + } else { + pargv[8] = "-f"; + pargv[9] = fn; + pargv[10] = NULL; } - execvp(PATH_PFCTL, pargv); - warn("exec of %s failed", PATH_PFCTL); - _exit(1); - } - /* parent */ - waitpid(pid, &s, 0); - if (s != 0) { - syslog(LOG_ERR, "pfctl exited abnormally"); - goto error; - } + switch (pid = fork()) { + case -1: + syslog(LOG_ERR, "fork failed"); + goto error; + case 0: + /* revoke group privs before exec */ + gid = getgid(); + if (setregid(gid, gid) == -1) { + err(1, "setregid"); + } + execvp(PATH_PFCTL, pargv); + warn("exec of %s failed", PATH_PFCTL); + _exit(1); + } + + /* parent */ + waitpid(pid, &s, 0); + if (s != 0) { + syslog(LOG_ERR, "pfctl exited abnormally"); + goto error; + } - if (add) { gettimeofday(&Tstart, NULL); - syslog(LOG_INFO, "allowing %s, user %s", ipsrc, luser); + syslog(LOG_INFO, "allowing %s, user %s", ip_src, l_user); } else { + remove_stale_rulesets(); + gettimeofday(&Tend, NULL); -#ifdef __FreeBSD__ - syslog(LOG_INFO, "removed %s, user %s - duration %jd seconds", - ipsrc, luser, (intmax_t)(Tend.tv_sec - Tstart.tv_sec)); -#else - syslog(LOG_INFO, "removed %s, user %s - duration %ld seconds", - ipsrc, luser, Tend.tv_sec - Tstart.tv_sec); -#endif + syslog(LOG_INFO, "removed %s, user %s - duration %ju seconds", + ip_src, l_user, (uintmax_t)(Tend.tv_sec - Tstart.tv_sec)); } return (0); no_mem: @@ -740,7 +843,7 @@ error: * Add/remove this IP from the "authpf_users" table. */ static int -change_table(int add, const char *ipsrc) +change_table(int add, const char *ip_src) { struct pfioc_table io; struct pfr_addr addr; @@ -753,12 +856,12 @@ change_table(int add, const char *ipsrc) io.pfrio_size = 1; bzero(&addr, sizeof(addr)); - if (ipsrc == NULL || !ipsrc[0]) + if (ip_src == NULL || !ip_src[0]) return (-1); - if (inet_pton(AF_INET, ipsrc, &addr.pfra_ip4addr) == 1) { + if (inet_pton(AF_INET, ip_src, &addr.pfra_ip4addr) == 1) { addr.pfra_af = AF_INET; addr.pfra_net = 32; - } else if (inet_pton(AF_INET6, ipsrc, &addr.pfra_ip6addr) == 1) { + } else if (inet_pton(AF_INET6, ip_src, &addr.pfra_ip6addr) == 1) { addr.pfra_af = AF_INET6; addr.pfra_net = 128; } else { @@ -769,7 +872,7 @@ change_table(int add, const char *ipsrc) if (ioctl(dev, add ? DIOCRADDADDRS : DIOCRDELADDRS, &io) && errno != ESRCH) { syslog(LOG_ERR, "cannot %s %s from table %s: %s", - add ? "add" : "remove", ipsrc, tablename, + add ? "add" : "remove", ip_src, tablename, strerror(errno)); return (-1); } @@ -821,7 +924,7 @@ authpf_kill_states(void) /* signal handler that makes us go away properly */ static void -need_death(int signo) +need_death(int signo __unused) { want_death = 1; } @@ -840,11 +943,12 @@ do_death(int active) if (active) { change_filter(0, luser, ipsrc); - change_table(0, ipsrc); - authpf_kill_states(); - remove_stale_rulesets(); + if (user_ip) { + change_table(0, ipsrc); + authpf_kill_states(); + } } - if (pidfile[0] && (pidfp != NULL)) + if (pidfile[0] && pidfd != -1) if (unlink(pidfile) == -1) syslog(LOG_ERR, "cannot unlink %s (%m)", pidfile); exit(ret); diff --git a/contrib/pf/authpf/pathnames.h b/contrib/pf/authpf/pathnames.h index 358bfd0..e02cf77 100644 --- a/contrib/pf/authpf/pathnames.h +++ b/contrib/pf/authpf/pathnames.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pathnames.h,v 1.7 2004/04/25 18:40:42 beck Exp $ */ +/* $OpenBSD: pathnames.h,v 1.8 2008/02/14 01:49:17 mcbride Exp $ */ /* * Copyright (C) 2002 Chris Kuethe (ckuethe@ualberta.ca) @@ -35,4 +35,5 @@ #define PATH_DEVFILE "/dev/pf" #define PATH_PIDFILE "/var/authpf" #define PATH_AUTHPF_SHELL "/usr/sbin/authpf" +#define PATH_AUTHPF_SHELL_NOIP "/usr/sbin/authpf-noip" #define PATH_PFCTL "/sbin/pfctl" diff --git a/contrib/pf/ftp-proxy/filter.c b/contrib/pf/ftp-proxy/filter.c index f86429d..f575db1 100644 --- a/contrib/pf/ftp-proxy/filter.c +++ b/contrib/pf/ftp-proxy/filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: filter.c,v 1.5 2006/12/01 07:31:21 camield Exp $ */ +/* $OpenBSD: filter.c,v 1.8 2008/06/13 07:25:26 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> @@ -53,7 +53,7 @@ static struct pfioc_rule pfr; static struct pfioc_trans pft; static struct pfioc_trans_e pfte[TRANS_SIZE]; static int dev, rule_log; -static char *qname; +static const char *qname, *tagname; int add_filter(u_int32_t id, u_int8_t dir, struct sockaddr *src, @@ -159,11 +159,12 @@ do_rollback(void) } void -init_filter(char *opt_qname, int opt_verbose) +init_filter(const char *opt_qname, const char *opt_tagname, int opt_verbose) { struct pf_status status; qname = opt_qname; + tagname = opt_tagname; if (opt_verbose == 1) rule_log = PF_LOG; @@ -172,7 +173,7 @@ init_filter(char *opt_qname, int opt_verbose) dev = open("/dev/pf", O_RDWR); if (dev == -1) - err(1, "/dev/pf"); + err(1, "open /dev/pf"); if (ioctl(dev, DIOCGETSTATUS, &status) == -1) err(1, "DIOCGETSTATUS"); if (!status.running) @@ -280,9 +281,9 @@ prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src, switch (rs_num) { case PF_RULESET_FILTER: /* - * pass quick [log] inet[6] proto tcp \ + * pass [quick] [log] inet[6] proto tcp \ * from $src to $dst port = $d_port flags S/SA keep state - * (max 1) [queue qname] + * (max 1) [queue qname] [tag tagname] */ pfr.rule.action = PF_PASS; pfr.rule.quick = 1; @@ -293,6 +294,11 @@ prepare_rule(u_int32_t id, int rs_num, struct sockaddr *src, pfr.rule.max_states = 1; if (qname != NULL) strlcpy(pfr.rule.qname, qname, sizeof pfr.rule.qname); + if (tagname != NULL) { + pfr.rule.quick = 0; + strlcpy(pfr.rule.tagname, tagname, + sizeof pfr.rule.tagname); + } break; case PF_RULESET_NAT: /* diff --git a/contrib/pf/ftp-proxy/filter.h b/contrib/pf/ftp-proxy/filter.h index 6779c59..3b48898 100644 --- a/contrib/pf/ftp-proxy/filter.h +++ b/contrib/pf/ftp-proxy/filter.h @@ -1,4 +1,4 @@ -/* $OpenBSD: filter.h,v 1.3 2005/06/07 14:12:07 camield Exp $ */ +/* $OpenBSD: filter.h,v 1.4 2007/08/01 09:31:41 henning Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> @@ -26,6 +26,6 @@ int add_rdr(u_int32_t, struct sockaddr *, struct sockaddr *, u_int16_t, struct sockaddr *, u_int16_t); int do_commit(void); int do_rollback(void); -void init_filter(char *, int); +void init_filter(const char *, const char *, int); int prepare_commit(u_int32_t); int server_lookup(struct sockaddr *, struct sockaddr *, struct sockaddr *); diff --git a/contrib/pf/ftp-proxy/ftp-proxy.8 b/contrib/pf/ftp-proxy/ftp-proxy.8 index 69c848e..d4dd030 100644 --- a/contrib/pf/ftp-proxy/ftp-proxy.8 +++ b/contrib/pf/ftp-proxy/ftp-proxy.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ftp-proxy.8,v 1.7 2006/12/30 13:01:54 camield Exp $ +.\" $OpenBSD: ftp-proxy.8,v 1.11 2008/02/26 18:52:53 henning Exp $ .\" .\" Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> .\" @@ -16,14 +16,15 @@ .\" .\" $FreeBSD$ .\" -.Dd November 28, 2004 +.Dd February 26, 2008 .Dt FTP-PROXY 8 .Os .Sh NAME .Nm ftp-proxy .Nd Internet File Transfer Protocol proxy daemon .Sh SYNOPSIS -.Nm ftp-proxy +.Nm +.Bk -words .Op Fl 6Adrv .Op Fl a Ar address .Op Fl b Ar address @@ -33,7 +34,9 @@ .Op Fl p Ar port .Op Fl q Ar queue .Op Fl R Ar address +.Op Fl T Ar tag .Op Fl t Ar timeout +.Ek .Sh DESCRIPTION .Nm is a proxy for the Internet File Transfer Protocol. @@ -58,7 +61,7 @@ facility for this. Assuming the FTP control connection is from $client to $server, the proxy connected to the server using the $proxy source address, and $port is negotiated, then -.Nm ftp-proxy +.Nm adds the following rules to the various anchors. (These example rules use inet, but the proxy also supports inet6.) .Pp @@ -130,6 +133,20 @@ connections to another proxy. .It Fl r Rewrite sourceport to 20 in active mode to suit ancient clients that insist on this RFC property. +.It Fl T Ar tag +The filter rules will add tag +.Ar tag +to data connections, and not match quick. +This way alternative rules that use the +.Ar tagged +keyword can be implemented following the +.Nm +anchor. +These rules can use special +.Xr pf 4 +features like route-to, reply-to, label, rtable, overload, etc. that +.Nm +does not implement itself. .It Fl t Ar timeout Number of seconds that the control connection can be idle, before the proxy will disconnect. @@ -172,7 +189,7 @@ does not allow the ruleset to be modified if the system is running at a .Xr securelevel 7 higher than 1. At that level -.Nm ftp-proxy +.Nm cannot add rules to the anchors and FTP data connections may get blocked. .Pp Negotiated data connection ports below 1024 are not allowed. @@ -181,5 +198,5 @@ The negotiated IP address for active modes is ignored for security reasons. This makes third party file transfers impossible. .Pp -.Nm ftp-proxy +.Nm chroots to "/var/empty" and changes to user "proxy" to drop privileges. diff --git a/contrib/pf/ftp-proxy/ftp-proxy.c b/contrib/pf/ftp-proxy/ftp-proxy.c index 06c8487..26de75a 100644 --- a/contrib/pf/ftp-proxy/ftp-proxy.c +++ b/contrib/pf/ftp-proxy/ftp-proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ftp-proxy.c,v 1.13 2006/12/30 13:24:00 camield Exp $ */ +/* $OpenBSD: ftp-proxy.c,v 1.19 2008/06/13 07:25:26 claudio Exp $ */ /* * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> @@ -61,6 +61,14 @@ __FBSDID("$FreeBSD$"); #define PF_NAT_PROXY_PORT_LOW 50001 #define PF_NAT_PROXY_PORT_HIGH 65535 +#ifndef LIST_END +#define LIST_END(a) NULL +#endif + +#ifndef getrtable +#define getrtable(a) 0 +#endif + #define sstosa(ss) ((struct sockaddr *)(ss)) enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV }; @@ -94,7 +102,7 @@ int client_parse_cmd(struct session *s); void client_read(struct bufferevent *, void *); int drop_privs(void); void end_session(struct session *); -int exit_daemon(void); +void exit_daemon(void); int getline(char *, size_t *); void handle_connection(const int, short, void *); void handle_signal(int, short, void *); @@ -105,6 +113,7 @@ u_int16_t pick_proxy_port(void); void proxy_reply(int, struct sockaddr *, u_int16_t); void server_error(struct bufferevent *, short, void *); int server_parse(struct session *s); +int allow_data_connection(struct session *s); void server_read(struct bufferevent *, void *); const char *sock_ntop(struct sockaddr *); void usage(void); @@ -115,14 +124,14 @@ size_t linelen; char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN]; struct sockaddr_storage fixed_server_ss, fixed_proxy_ss; -char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, - *qname; +const char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port, + *qname, *tagname; int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions, rfc_mode, session_count, timeout, verbose; extern char *__progname; void -client_error(struct bufferevent *bufev, short what, void *arg) +client_error(struct bufferevent *bufev __unused, short what, void *arg) { struct session *s = arg; @@ -152,8 +161,19 @@ client_parse(struct session *s) return (1); if (linebuf[0] == 'P' || linebuf[0] == 'p' || - linebuf[0] == 'E' || linebuf[0] == 'e') - return (client_parse_cmd(s)); + linebuf[0] == 'E' || linebuf[0] == 'e') { + if (!client_parse_cmd(s)) + return (0); + + /* + * Allow active mode connections immediately, instead of + * waiting for a positive reply from the server. Some + * rare servers/proxies try to probe or setup the data + * connection before an actual transfer request. + */ + if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) + return (allow_data_connection(s)); + } if (anonymous_only && (linebuf[0] == 'U' || linebuf[0] == 'u')) return (client_parse_anon(s)); @@ -220,14 +240,14 @@ void client_read(struct bufferevent *bufev, void *arg) { struct session *s = arg; - size_t buf_avail, read; + size_t buf_avail, clientread; int n; do { buf_avail = sizeof s->cbuf - s->cbuf_valid; - read = bufferevent_read(bufev, s->cbuf + s->cbuf_valid, + clientread = bufferevent_read(bufev, s->cbuf + s->cbuf_valid, buf_avail); - s->cbuf_valid += read; + s->cbuf_valid += clientread; while ((n = getline(s->cbuf, &s->cbuf_valid)) > 0) { logmsg(LOG_DEBUG, "#%d client: %s", s->id, linebuf); @@ -244,7 +264,7 @@ client_read(struct bufferevent *bufev, void *arg) end_session(s); return; } - } while (read == buf_avail); + } while (clientread == buf_avail); } int @@ -269,10 +289,16 @@ drop_privs(void) void end_session(struct session *s) { - int err; + int serr; logmsg(LOG_INFO, "#%d ending session", s->id); + /* Flush output buffers. */ + if (s->client_bufev && s->client_fd != -1) + evbuffer_write(s->client_bufev->output, s->client_fd); + if (s->server_bufev && s->server_fd != -1) + evbuffer_write(s->server_bufev->output, s->server_fd); + if (s->client_fd != -1) close(s->client_fd); if (s->server_fd != -1) @@ -284,33 +310,29 @@ end_session(struct session *s) bufferevent_free(s->server_bufev); /* Remove rulesets by commiting empty ones. */ - err = 0; + serr = 0; if (prepare_commit(s->id) == -1) - err = errno; + serr = errno; else if (do_commit() == -1) { - err = errno; + serr = errno; do_rollback(); } - if (err) + if (serr) logmsg(LOG_ERR, "#%d pf rule removal failed: %s", s->id, - strerror(err)); + strerror(serr)); LIST_REMOVE(s, entry); free(s); session_count--; } -int +void exit_daemon(void) { struct session *s, *next; -#ifdef __FreeBSD__ - LIST_FOREACH_SAFE(s, &sessions, entry, next) { -#else for (s = LIST_FIRST(&sessions); s != LIST_END(&sessions); s = next) { next = LIST_NEXT(s, entry); -#endif end_session(s); } @@ -318,9 +340,6 @@ exit_daemon(void) closelog(); exit(0); - - /* NOTREACHED */ - return (-1); } int @@ -361,7 +380,7 @@ getline(char *buf, size_t *valid) } void -handle_connection(const int listen_fd, short event, void *ev) +handle_connection(const int listen_fd, short event __unused, void *ev __unused) { struct sockaddr_storage tmp_ss; struct sockaddr *client_sa, *server_sa, *fixed_server_sa; @@ -508,13 +527,13 @@ handle_connection(const int listen_fd, short event, void *ev) } void -handle_signal(int sig, short event, void *arg) +handle_signal(int sig, short event __unused, void *arg __unused) { /* * Signal handler rules don't apply, libevent decouples for us. */ - logmsg(LOG_ERR, "%s exiting on signal %d", __progname, sig); + logmsg(LOG_ERR, "exiting on signal %d", sig); exit_daemon(); } @@ -567,10 +586,7 @@ logmsg(int pri, const char *message, ...) /* We don't care about truncation. */ vsnprintf(buf, sizeof buf, message, ap); #ifdef __FreeBSD__ - /* XXX: strnvis might be nice to have */ - strvisx(visbuf, buf, - MIN((sizeof(visbuf) / 4) - 1, strlen(buf)), - VIS_CSTYLE | VIS_NL); + strvis(visbuf, buf, VIS_CSTYLE | VIS_NL); #else strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL); #endif @@ -602,6 +618,7 @@ main(int argc, char *argv[]) max_sessions = 100; qname = NULL; rfc_mode = 0; + tagname = NULL; timeout = 24 * 3600; verbose = 0; @@ -609,7 +626,7 @@ main(int argc, char *argv[]) id_count = 1; session_count = 0; - while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rt:v")) != -1) { + while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) { switch (ch) { case '6': ipv6_mode = 1; @@ -654,6 +671,11 @@ main(int argc, char *argv[]) case 'r': rfc_mode = 1; break; + case 'T': + if (strlen(optarg) >= PF_TAG_NAME_SIZE) + errx(1, "tagname too long"); + tagname = optarg; + break; case 't': timeout = strtonum(optarg, 0, 86400, &errstr); if (errstr) @@ -734,7 +756,7 @@ main(int argc, char *argv[]) freeaddrinfo(res); /* Initialize pf. */ - init_filter(qname, verbose); + init_filter(qname, tagname, verbose); if (daemonize) { if (daemon(0, 0) == -1) @@ -830,14 +852,15 @@ u_int16_t pick_proxy_port(void) { /* Random should be good enough for avoiding port collisions. */ - return (IPPORT_HIFIRSTAUTO + (arc4random() % - (IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO))); + return (IPPORT_HIFIRSTAUTO + + arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO)); } void proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port) { - int i, r; + u_int i; + int r = 0; switch (cmd) { case CMD_PORT: @@ -864,7 +887,7 @@ proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port) break; } - if (r < 0 || r >= sizeof linebuf) { + if (r < 0 || ((u_int)r) >= sizeof linebuf) { logmsg(LOG_ERR, "proxy_reply failed: %d", r); linebuf[0] = '\0'; linelen = 0; @@ -881,7 +904,7 @@ proxy_reply(int cmd, struct sockaddr *sa, u_int16_t port) } void -server_error(struct bufferevent *bufev, short what, void *arg) +server_error(struct bufferevent *bufev __unused, short what, void *arg) { struct session *s = arg; @@ -902,12 +925,26 @@ server_error(struct bufferevent *bufev, short what, void *arg) int server_parse(struct session *s) { - struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa; - int prepared = 0; - if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2') goto out; + if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) || + (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) + return (allow_data_connection(s)); + + out: + s->cmd = CMD_NONE; + s->port = 0; + + return (1); +} + +int +allow_data_connection(struct session *s) +{ + struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa; + int prepared = 0; + /* * The pf rules below do quite some NAT rewriting, to keep up * appearances. Points to keep in mind: @@ -932,8 +969,7 @@ server_parse(struct session *s) orig_sa = sstosa(&s->server_ss); /* Passive modes. */ - if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) || - (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) { + if (s->cmd == CMD_PASV || s->cmd == CMD_EPSV) { s->port = parse_port(s->cmd); if (s->port < MIN_PORT) { logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, @@ -974,8 +1010,7 @@ server_parse(struct session *s) } /* Active modes. */ - if ((s->cmd == CMD_PORT || s->cmd == CMD_EPRT) && - strncmp("200 ", linebuf, 4) == 0) { + if (s->cmd == CMD_PORT || s->cmd == CMD_EPRT) { logmsg(LOG_INFO, "#%d active: server to client port %d" " via port %d", s->id, s->port, s->proxy_port); @@ -1025,7 +1060,6 @@ server_parse(struct session *s) goto fail; } - out: s->cmd = CMD_NONE; s->port = 0; @@ -1042,16 +1076,16 @@ void server_read(struct bufferevent *bufev, void *arg) { struct session *s = arg; - size_t buf_avail, read; + size_t buf_avail, srvread; int n; bufferevent_settimeout(bufev, timeout, 0); do { buf_avail = sizeof s->sbuf - s->sbuf_valid; - read = bufferevent_read(bufev, s->sbuf + s->sbuf_valid, + srvread = bufferevent_read(bufev, s->sbuf + s->sbuf_valid, buf_avail); - s->sbuf_valid += read; + s->sbuf_valid += srvread; while ((n = getline(s->sbuf, &s->sbuf_valid)) > 0) { logmsg(LOG_DEBUG, "#%d server: %s", s->id, linebuf); @@ -1068,7 +1102,7 @@ server_read(struct bufferevent *bufev, void *arg) end_session(s); return; } - } while (read == buf_avail); + } while (srvread == buf_avail); } const char * @@ -1102,6 +1136,7 @@ usage(void) { fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]" " [-D level] [-m maxsessions]\n [-P port]" - " [-p port] [-q queue] [-R address] [-t timeout]\n", __progname); + " [-p port] [-q queue] [-R address] [-T tag]\n" + " [-t timeout]\n", __progname); exit(1); } diff --git a/contrib/pf/man/pf.4 b/contrib/pf/man/pf.4 index 16e74ab..75e421d 100644 --- a/contrib/pf/man/pf.4 +++ b/contrib/pf/man/pf.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.4,v 1.58 2007/02/09 11:39:06 henning Exp $ +.\" $OpenBSD: pf.4,v 1.62 2008/09/10 14:57:37 jmc Exp $ .\" .\" Copyright (C) 2001, Kjell Wooding. All rights reserved. .\" @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 7, 2005 +.Dd September 10 2008 .Dt PF 4 .Os .Sh NAME @@ -294,14 +294,17 @@ if another process is concurrently updating a ruleset. Add a state entry. .Bd -literal struct pfioc_state { - u_int32_t nr; - struct pf_state state; + struct pfsync_state state; }; .Ed .It Dv DIOCGETSTATE Fa "struct pfioc_state *ps" -Extract the entry with the specified number -.Va nr -from the state table. +Extract the entry identified by the +.Va id +and +.Va creatorid +fields of the +.Va state +structure from the state table. .It Dv DIOCKILLSTATES Fa "struct pfioc_state_kill *psk" Remove matching entries from the state table. This ioctl returns the number of killed states in @@ -1049,12 +1052,14 @@ internal interface description. The filtering process is the same as for .Dv DIOCIGETIFACES . .Bd -literal -#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */ +#define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */ .Ed .It Dv DIOCCLRIFFLAG Fa "struct pfioc_iface *io" Works as .Dv DIOCSETIFFLAG above but clears the flags. +.It Dv DIOCKILLSRCNODES Fa "struct pfioc_iface *io" +Explicitly remove source tracking nodes. .El .Sh FILES .Bl -tag -width /dev/pf -compact @@ -1133,6 +1138,7 @@ main(int argc, char *argv[]) .Xr altq 4 , .Xr if_bridge 4 , .Xr pflog 4 , +.Xr pflow 4 , .Xr pfsync 4 , .Xr pfctl 8 , .Xr altq 9 diff --git a/contrib/pf/man/pf.conf.5 b/contrib/pf/man/pf.conf.5 index 98c3d0e..dfec264 100644 --- a/contrib/pf/man/pf.conf.5 +++ b/contrib/pf/man/pf.conf.5 @@ -1,5 +1,5 @@ -.\" $FreeBSD$ -.\" $OpenBSD: pf.conf.5,v 1.393 2008/02/11 07:46:32 jmc Exp $ +.\" $FreeBSD$ +.\" $OpenBSD: pf.conf.5,v 1.406 2009/01/31 19:37:12 sobrado Exp $ .\" .\" Copyright (c) 2002, Daniel Hartmeier .\" All rights reserved. @@ -28,7 +28,7 @@ .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd June 10, 2008 +.Dd January 31 2009 .Dt PF.CONF 5 .Os .Sh NAME @@ -79,6 +79,17 @@ By default enforces this order (see .Ar set require-order below). +.Pp +Comments can be put anywhere in the file using a hash mark +.Pq Sq # , +and extend to the end of the current line. +.Pp +Additional configuration files can be included with the +.Ic include +keyword, for example: +.Bd -literal -offset indent +include "/etc/pf/sub.filter.conf" +.Ed .Sh MACROS Macros can be defined that will later be expanded in context. Macro names must start with a letter, and may contain letters, digits @@ -154,7 +165,7 @@ A table initialized with the empty list, will be cleared on load. .El .Pp -Tables may be defined with the following two attributes: +Tables may be defined with the following attributes: .Bl -tag -width persist .It Ar persist The @@ -173,6 +184,11 @@ can be used to add or remove addresses from the table at any time, even when running with .Xr securelevel 7 = 2. +.It Ar counters +The +.Ar counters +flag enables per-address packet and byte counters which can be displayed with +.Xr pfctl 8 . .El .Pp For example, @@ -328,7 +344,8 @@ With 9000 state table entries, the timeout values are scaled to 50% (tcp.first 60, tcp.established 43200). .Pp .It Ar set loginterface -Enable collection of packet and byte count statistics for the given interface. +Enable collection of packet and byte count statistics for the given +interface or interface group. These statistics can be viewed using .Bd -literal -offset indent # pfctl -s info @@ -403,9 +420,10 @@ set limit { states 20000, frags 20000, src-nodes 2000 } .Bl -tag -width xxxxxxxx -compact .It Ar none Disable the ruleset optimizer. -This is the default behaviour. .It Ar basic -Enable basic ruleset optimization, which does four things to improve the +Enable basic ruleset optimization. +This is the default behaviour. +Basic ruleset optimization does four things to improve the performance of ruleset evaluations: .Pp .Bl -enum -compact @@ -500,6 +518,16 @@ For example: .Bd -literal -offset indent set state-policy if-bound .Ed +.It Ar set state-defaults +The +.Ar state-defaults +option sets the state options for states created from rules +without an explicit +.Ar keep state . +For example: +.Bd -literal -offset indent +set state-defaults pflow, no-sync +.Ed .It Ar set hostid The 32-bit .Ar hostid @@ -617,6 +645,19 @@ modifier to ensure unique IP identifiers. Enforces a minimum TTL for matching IP packets. .It Ar max-mss Aq Ar number Enforces a maximum MSS for matching TCP packets. +.It Xo Ar set-tos Aq Ar string +.No \*(Ba Aq Ar number +.Xc +Enforces a +.Em TOS +for matching IP packets. +.Em TOS +may be +given as one of +.Ar lowdelay , +.Ar throughput , +.Ar reliability , +or as either hex or decimal. .It Ar random-id Replaces the IP identification field with random values to compensate for predictable values generated by many hosts. @@ -725,7 +766,7 @@ much in the same way as works in the packet filter (see below). This mechanism should be used when it is necessary to exclude specific packets from broader scrub rules. -.Sh QUEUEING/ALTQ +.Sh QUEUEING The ALTQ system is currently not available in the GENERIC kernel nor as loadable modules. In order to use the herein after called queueing options one has to use a @@ -816,7 +857,7 @@ assigned. .Ar Priority mainly controls the time packets take to get sent out, while .Ar bandwidth -has primarily effects on throughput. +primarily affects throughput. .Ar hfsc supports both link-sharing and guaranteed real-time services. It employs a service curve based QoS model, @@ -879,7 +920,7 @@ Defines a list of subqueues to create on an interface. .El .Pp In the following example, the interface dc0 -should queue up to 5 Mbit/s in four second-level queues using +should queue up to 5Mbps in four second-level queues using Class Based Queueing. Those four queues will be shown in a later example. .Bd -literal -offset indent @@ -1171,7 +1212,7 @@ or to the firewall itself. Note that redirecting external incoming connections to the loopback address, as in .Bd -literal -offset indent -rdr on ne3 inet proto tcp to port spamd -\*(Gt 127.0.0.1 port smtp +rdr on ne3 inet proto tcp to port smtp -\*(Gt 127.0.0.1 port spamd .Ed .Pp will effectively allow an external host to connect to daemons @@ -1256,7 +1297,7 @@ block all .Ed .It Ar pass The packet is passed; -state is created state unless the +state is created unless the .Ar no state option is specified. .El @@ -1432,7 +1473,8 @@ This rule applies only to packets with the specified source and destination addresses and ports. .Pp Addresses can be specified in CIDR notation (matching netblocks), as -symbolic host names or interface names, or as any of the following keywords: +symbolic host names, interface names or interface group names, or as any +of the following keywords: .Pp .Bl -tag -width xxxxxxxxxxxxxx -compact .It Ar any @@ -1454,7 +1496,15 @@ the route back to the packet's source address. Any address that matches the given table. .El .Pp -Interface names can have modifiers appended: +Ranges of addresses are specified by using the +.Sq - +operator. +For instance: +.Dq 10.1.1.10 - 10.1.1.12 +means all addresses from 10.1.1.10 to 10.1.1.12, +hence addresses 10.1.1.10, 10.1.1.11, and 10.1.1.12. +.Pp +Interface names and interface group names can have modifiers appended: .Pp .Bl -tag -width xxxxxxxxxxxx -compact .It Ar :network @@ -1462,7 +1512,7 @@ Translates to the network(s) attached to the interface. .It Ar :broadcast Translates to the interface's broadcast address(es). .It Ar :peer -Translates to the point to point interface's peer address(es). +Translates to the point-to-point interface's peer address(es). .It Ar :0 Do not include interface aliases. .El @@ -1552,17 +1602,6 @@ This is equivalent to "from any to any". Similar to .Ar user , this rule only applies to packets of sockets owned by the specified group. -.Pp -The use of -.Ar group -or -.Ar user -in -.Va debug.mpsafenet Ns = Ns 1 -environments may result in a deadlock. -Please see the -.Sx BUGS -section for details. .It Ar user Aq Ar user This rule only applies to packets of sockets owned by the specified user. For outgoing connections initiated from the firewall, this is the user @@ -1628,7 +1667,7 @@ Flags not specified in are ignored. For stateful connections, the default is .Ar flags S/SA . -To indicate that flags should not be checkd at all, specify +To indicate that flags should not be checked at all, specify .Ar flags any . The flags are: (F)IN, (S)YN, (R)ST, (P)USH, (A)CK, (U)RG, (E)CE, and C(W)R. .Bl -tag -width Fl @@ -1780,7 +1819,7 @@ of .Em lowdelay and TCP ACKs with no data payload will be assigned to the second one. See -.Sx QUEUEING/ALTQ +.Sx QUEUEING for setup details. .Pp For example: @@ -1811,7 +1850,8 @@ or rules in addition to filter rules. Tags take the same macros as labels (see above). .It Ar tagged Aq Ar string -Used with filter or translation rules to specify that packets must already +Used with filter, translation or scrub rules +to specify that packets must already be tagged with the given tag in order to match the rule. Inverse tag matching can also be done by specifying the @@ -1822,6 +1862,22 @@ keyword. .It Ar rtable Aq Ar number Used to select an alternate routing table for the routing lookup. Only effective before the route lookup happened, i.e. when filtering inbound. +.It Xo Ar divert-to Aq Ar host +.Ar port Aq Ar port +.Xc +Used to redirect packets to a local socket bound to +.Ar host +and +.Ar port . +The packets will not be modified, so +.Xr getsockname 2 +on the socket will return the original destination address of the packet. +.It Ar divert-reply +Used to receive replies for sockets that are bound to addresses +which are not local to the machine. +See +.Xr setsockopt 2 +for information on how to bind these sockets. .It Ar probability Aq Ar number A probability attribute can be attached to a rule, with a value set between 0 and 1, bounds not included. @@ -1940,7 +1996,7 @@ pool options. Note that by default these associations are destroyed as soon as there are no longer states which refer to them; in order to make the mappings last beyond the lifetime of the states, increase the global options with -.Ar set timeout source-track +.Ar set timeout src.track . See .Sx STATEFUL TRACKING OPTIONS for more ways to control the source tracking. @@ -2026,7 +2082,7 @@ Rules with will not work if .Xr pf 4 operates on a -.Xr if_bridge 4 . +.Xr bridge 4 . .Pp Example: .Bd -literal -offset indent @@ -2046,8 +2102,8 @@ must be specified explicitly to apply options to a rule. .Bl -tag -width xxxx -compact .It Ar max Aq Ar number Limits the number of concurrent states the rule may create. -When this limit is reached, further packets matching the rule that would -create state are dropped, until existing states time out. +When this limit is reached, further packets that would create +state will not match this rule until existing states time out. .It Ar no-sync Prevent state changes for states created by this rule from appearing on the .Xr pfsync 4 @@ -2064,8 +2120,12 @@ Uses a sloppy TCP connection tracker that does not check sequence numbers at all, which makes insertion and ICMP teardown attacks way easier. This is intended to be used in situations where one does not see all -packets of a connection, i.e. in asymmetric routing situations. +packets of a connection, e.g. in asymmetric routing situations. Cannot be used with modulate or synproxy state. +.It Ar pflow +States created by this rule are exported on the +.Xr pflow 4 +interface. .El .Pp Multiple options can be specified, separated by commas: @@ -2472,10 +2532,8 @@ into the anchor. .Pp Optionally, .Ar anchor -rules can specify the parameter's -direction, interface, address family, protocol and source/destination -address/port -using the same syntax as filter rules. +rules can specify packet filtering parameters using the same syntax as +filter rules. When parameters are used, the .Ar anchor rule is only evaluated for matching packets. @@ -2779,10 +2837,11 @@ in BNF: .Bd -literal line = ( option | pf-rule | nat-rule | binat-rule | rdr-rule | antispoof-rule | altq-rule | queue-rule | trans-anchors | - anchor-rule | anchor-close | load-anchor | table-rule | ) + anchor-rule | anchor-close | load-anchor | table-rule | + include ) option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] | - [ "ruleset-optimization" [ "none" | "basic" | "profile" ]] | + [ "ruleset-optimization" [ "none" | "basic" | "profile" ]] | [ "optimization" [ "default" | "normal" | "high-latency" | "satellite" | "aggressive" | "conservative" ] ] @@ -2790,9 +2849,10 @@ option = "set" ( [ "timeout" ( timeout | "{" timeout-list "}" ) ] | [ "loginterface" ( interface-name | "none" ) ] | [ "block-policy" ( "drop" | "return" ) ] | [ "state-policy" ( "if-bound" | "floating" ) ] + [ "state-defaults" state-opts ] [ "require-order" ( "yes" | "no" ) ] [ "fingerprints" filename ] | - [ "skip on" ( interface-name | "{" interface-list "}" ) ] | + [ "skip on" ifspec ] | [ "debug" ( "none" | "urgent" | "misc" | "loud" ) ] ) pf-rule = action [ ( "in" | "out" ) ] @@ -2804,10 +2864,10 @@ logopts = logopt [ "," logopts ] logopt = "all" | "user" | "to" interface-name filteropt-list = filteropt-list filteropt | filteropt -filteropt = user | group | flags | icmp-type | icmp6-type | tos | +filteropt = user | group | flags | icmp-type | icmp6-type | "tos" tos | ( "no" | "keep" | "modulate" | "synproxy" ) "state" [ "(" state-opts ")" ] | - "fragment" | "no-df" | "min-ttl" number | + "fragment" | "no-df" | "min-ttl" number | "set-tos" tos | "max-mss" number | "random-id" | "reassemble tcp" | fragmentation | "allow-opts" | "label" string | "tag" string | [ ! ] "tagged" string | @@ -2834,17 +2894,16 @@ rdr-rule = [ "no" ] "rdr" [ "pass" [ "log" [ "(" logopts ")" ] ] ] [ portspec ] [ pooltype ] ] antispoof-rule = "antispoof" [ "log" ] [ "quick" ] - "for" ( interface-name | "{" interface-list "}" ) - [ af ] [ "label" string ] + "for" ifspec [ af ] [ "label" string ] table-rule = "table" "\*(Lt" string "\*(Gt" [ tableopts-list ] tableopts-list = tableopts-list tableopts | tableopts -tableopts = "persist" | "const" | "file" string | +tableopts = "persist" | "const" | "counters" | "file" string | "{" [ tableaddr-list ] "}" tableaddr-list = tableaddr-list [ "," ] tableaddr-spec | tableaddr-spec tableaddr-spec = [ "!" ] tableaddr [ "/" mask-bits ] -tableaddr = hostname | ipv4-dotted-quad | ipv6-coloned-hex | - interface-name | "self" +tableaddr = hostname | ifspec | "self" | + ipv4-dotted-quad | ipv6-coloned-hex altq-rule = "altq on" interface-name queueopts-list "queue" subqueue @@ -2852,7 +2911,7 @@ queue-rule = "queue" string [ "on" interface-name ] queueopts-list subqueue anchor-rule = "anchor" [ string ] [ ( "in" | "out" ) ] [ "on" ifspec ] - [ af ] [ protospec ] [ hosts ] [ "{" ] + [ af ] [ protospec ] [ hosts ] [ filteropt-list ] [ "{" ] anchor-close = "}" @@ -2875,8 +2934,10 @@ return = "drop" | "return" | "return-rst" [ "( ttl" number ")" ] | icmpcode = ( icmp-code-name | icmp-code-number ) icmp6code = ( icmp6-code-name | icmp6-code-number ) -ifspec = ( [ "!" ] interface-name ) | "{" interface-list "}" -interface-list = [ "!" ] interface-name [ [ "," ] interface-list ] +ifspec = ( [ "!" ] ( interface-name | interface-group ) ) | + "{" interface-list "}" +interface-list = [ "!" ] ( interface-name | interface-group ) + [ [ "," ] interface-list ] route = ( "route-to" | "reply-to" | "dup-to" ) ( routehost | "{" routehost-list "}" ) [ pooltype ] @@ -2896,8 +2957,9 @@ ipspec = "any" | host | "{" host-list "}" host = [ "!" ] ( address [ "/" mask-bits ] | "\*(Lt" string "\*(Gt" ) redirhost = address [ "/" mask-bits ] routehost = "(" interface-name [ address [ "/" mask-bits ] ] ")" -address = ( interface-name | "(" interface-name ")" | hostname | - ipv4-dotted-quad | ipv6-coloned-hex ) +address = ( interface-name | interface-group | + "(" ( interface-name | interface-group ) ")" | + hostname | ipv4-dotted-quad | ipv6-coloned-hex ) host-list = host [ [ "," ] host-list ] redirhost-list = redirhost [ [ "," ] redirhost-list ] routehost-list = routehost [ [ "," ] routehost-list ] @@ -2926,11 +2988,11 @@ icmp-type-code = ( icmp-type-name | icmp-type-number ) [ "code" ( icmp-code-name | icmp-code-number ) ] icmp-list = icmp-type-code [ [ "," ] icmp-list ] -tos = "tos" ( "lowdelay" | "throughput" | "reliability" | +tos = ( "lowdelay" | "throughput" | "reliability" | [ "0x" ] number ) state-opts = state-opt [ [ "," ] state-opts ] -state-opt = ( "max" number | "no-sync" | timeout | sloppy | +state-opt = ( "max" number | "no-sync" | timeout | "sloppy" | "pflow" | "source-track" [ ( "rule" | "global" ) ] | "max-src-nodes" number | "max-src-states" number | "max-src-conn" number | @@ -2971,9 +3033,10 @@ realtime-sc = "realtime" sc-spec upperlimit-sc = "upperlimit" sc-spec sc-spec = ( bandwidth-spec | "(" bandwidth-spec number bandwidth-spec ")" ) +include = "include" filename .Ed .Sh FILES -.Bl -tag -width "/usr/share/examples/pf" -compact +.Bl -tag -width "/etc/protocols" -compact .It Pa /etc/hosts Host name database. .It Pa /etc/pf.conf @@ -2984,8 +3047,6 @@ Default location of OS fingerprints. Protocol name database. .It Pa /etc/services Service name database. -.It Pa /usr/share/examples/pf -Example rulesets. .El .Sh BUGS Due to a lock order reversal (LOR) with the socket layer, the use of the @@ -3017,6 +3078,7 @@ Rules with a route label do not match any traffic. .Xr ip 4 , .Xr ip6 4 , .Xr pf 4 , +.Xr pflow 4 , .Xr pfsync 4 , .Xr route 4 , .Xr tcp 4 , diff --git a/contrib/pf/man/pf.os.5 b/contrib/pf/man/pf.os.5 index ac2b7a8..5930525 100644 --- a/contrib/pf/man/pf.os.5 +++ b/contrib/pf/man/pf.os.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pf.os.5,v 1.7 2005/11/16 20:07:18 stevesk Exp $ +.\" $OpenBSD: pf.os.5,v 1.8 2007/05/31 19:19:58 jmc Exp $ .\" .\" Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> .\" @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 18, 2003 +.Dd May 31 2007 .Dt PF.OS 5 .Os .Sh NAME @@ -217,7 +217,7 @@ almost translates into the following fingerprint 57344:64:1:44:M1460: exampleOS:1.0::exampleOS 1.0 .Ed .Sh SEE ALSO -.Xr tcpdump 1 , .Xr pf 4 , .Xr pf.conf 5 , -.Xr pfctl 8 +.Xr pfctl 8 , +.Xr tcpdump 1 diff --git a/contrib/pf/man/pflog.4 b/contrib/pf/man/pflog.4 index 7ab96e9..c1039a3 100644 --- a/contrib/pf/man/pflog.4 +++ b/contrib/pf/man/pflog.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pflog.4,v 1.9 2006/10/25 12:51:31 jmc Exp $ +.\" $OpenBSD: pflog.4,v 1.10 2007/05/31 19:19:51 jmc Exp $ .\" .\" Copyright (c) 2001 Tobias Weingartner .\" All rights reserved. @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 10, 2001 +.Dd May 31 2007 .Dt PFLOG 4 .Os .Sh NAME @@ -36,7 +36,7 @@ .Sh DESCRIPTION The .Nm pflog -interface is a pseudo-device which makes visible all packets logged by +interface is a device which makes visible all packets logged by the packet filter, .Xr pf 4 . Logged packets can easily be monitored in real @@ -91,13 +91,13 @@ and monitor all packets logged on it: # tcpdump -n -e -ttt -i pflog1 .Ed .Sh SEE ALSO -.Xr tcpdump 1 .Xr inet 4 , .Xr inet6 4 , .Xr netintro 4 , .Xr pf 4 , .Xr ifconfig 8 , -.Xr pflogd 8 +.Xr pflogd 8 , +.Xr tcpdump 1 .Sh HISTORY The .Nm diff --git a/contrib/pf/man/pfsync.4 b/contrib/pf/man/pfsync.4 index 63adca9..92534f7 100644 --- a/contrib/pf/man/pfsync.4 +++ b/contrib/pf/man/pfsync.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfsync.4,v 1.24 2006/10/23 07:05:49 jmc Exp $ +.\" $OpenBSD: pfsync.4,v 1.28 2009/02/17 10:05:18 dlg Exp $ .\" .\" Copyright (c) 2002 Michael Shalayeff .\" Copyright (c) 2003-2004 Ryan McBride @@ -26,12 +26,12 @@ .\" .\" $FreeBSD$ .\" -.Dd June 6, 2006 +.Dd February 17 2009 .Dt PFSYNC 4 .Os .Sh NAME .Nm pfsync -.Nd packet filter state table logging interface +.Nd packet filter state table sychronisation interface .Sh SYNOPSIS .Cd "device pfsync" .Sh DESCRIPTION @@ -40,26 +40,25 @@ The interface is a pseudo-device which exposes certain changes to the state table used by .Xr pf 4 . -.\" XXX: not yet! -.\" State changes can be viewed by invoking -.\" .Xr tcpdump 1 -.\" on the -.\" .Nm -.\" interface. +State changes can be viewed by invoking +.Xr tcpdump 1 +on the +.Nm +interface. If configured with a physical synchronisation interface, .Nm -will send state changes out on that interface using IP multicast, +will also send state changes out on that interface, and insert state changes received on that interface from other systems into the state table. .Pp By default, all local changes to the state table are exposed via .Nm . -However, state changes from packets received by +State changes from packets received by .Nm over the network are not rebroadcast. -States created by a rule marked with the +Updates to states created by a rule marked with the .Ar no-sync -keyword are omitted from the +keyword are ignored by the .Nm interface (see .Xr pf.conf 5 @@ -67,33 +66,19 @@ for details). .Pp The .Nm -interface will attempt to collapse multiple updates of the same -state into one message where possible. -The maximum number of times this can be done before the update is sent out -is controlled by the +interface will attempt to collapse multiple state updates into a single +packet where possible. +The maximum number of times a single state can be updated before a +.Nm +packet will be sent out is controlled by the .Ar maxupd parameter to ifconfig (see .Xr ifconfig 8 and the example below for more details). -.Pp -Each packet retrieved on this interface has a header associated -with it of length -.Dv PFSYNC_HDRLEN . -The header indicates the version of the protocol, address family, -action taken on the following states, and the number of state -table entries attached in this packet. -This structure is defined in -.Aq Pa net/if_pfsync.h -as: -.Bd -literal -offset indent -struct pfsync_header { - u_int8_t version; - u_int8_t af; - u_int8_t action; - u_int8_t count; -}; -.Ed +The sending out of a +.Nm +packet will be delayed by a maximum of one second. .Sh NETWORK SYNCHRONISATION States can be synchronised between two or more firewalls using this interface, by specifying a synchronisation interface using @@ -104,18 +89,16 @@ interface: # ifconfig pfsync0 syncdev fxp0 .Ed .Pp -It is important that the underlying synchronisation interface is up -and has an IP address assigned. -.Pp By default, state change messages are sent out on the synchronisation -interface using IP multicast packets. -The protocol is IP protocol 240, PFSYNC, and the multicast group -used is 224.0.0.240. -When a peer address is specified using the +interface using IP multicast packets to the 244.0.0.240 group address. +An alternative destination address for +.Nm +packets can be specified using the .Ic syncpeer -keyword, the peer address is used as a destination for the pfsync traffic, -and the traffic can then be protected using -.Xr ipsec 4 . +keyword. +This can be used in combination with +.Xr ipsec 4 +to protect the synchronisation traffic. In such a configuration, the syncdev should be set to the .Xr enc 4 interface, as this is where the traffic arrives when it is decapsulated, @@ -127,50 +110,19 @@ e.g.: It is important that the pfsync traffic be well secured as there is no authentication on the protocol and it would be trivial to spoof packets which create states, bypassing the pf ruleset. -Either run the pfsync protocol on a trusted network \- ideally a network +Either run the pfsync protocol on a trusted network \- ideally a network dedicated to pfsync messages such as a crossover cable between two firewalls, or specify a peer address and protect the traffic with .Xr ipsec 4 . -.Pp -For -.Nm -to start its operation automatically at the system boot time, -.Va pfsync_enable -and -.Va pfsync_syncdev -variables should be used in -.Xr rc.conf 5 . -It is not advisable to set up -.Nm -with common network interface configuration variables of -.Xr rc.conf 5 -because -.Nm -must start after its -.Cm syncdev , -which cannot be always ensured in the latter case. -.\" XXX: not yet! -.\" .Pp -.\" There is a one-to-one correspondence between packets seen by -.\" .Xr bpf 4 -.\" on the -.\" .Nm -.\" interface, and packets sent out on the synchronisation interface, i.e.\& -.\" a packet with 4 state deletion messages on -.\" .Nm -.\" means that the same 4 deletions were sent out on the synchronisation -.\" interface. -.\" However, the actual packet contents may differ as the messages -.\" sent over the network are "compressed" where possible, containing -.\" only the necessary information. .Sh EXAMPLES .Nm and .Xr carp 4 can be used together to provide automatic failover of a pair of firewalls configured in parallel. -One firewall handles all traffic \- if it dies or -is shut down, the second firewall takes over automatically. +One firewall will handle all traffic until it dies, is shut down, or is +manually demoted, at which point the second firewall will take over +automatically. .Pp Both firewalls in this example have three .Xr sis 4 @@ -208,12 +160,12 @@ traffic through. The following should be added to the top of .Pa /etc/pf.conf : .Bd -literal -offset indent -pass quick on { sis2 } proto pfsync -pass on { sis0 sis1 } proto carp +pass quick on { sis2 } proto pfsync keep state (no-sync) +pass on { sis0 sis1 } proto carp keep state (no-sync) .Ed .Pp -If it is preferable that one firewall handle the traffic, -the +It is preferable that one firewall handle the forwarding of all the traffic, +therefore the .Ar advskew on the backup firewall's .Xr carp 4 @@ -221,6 +173,7 @@ interfaces should be set to something higher than the primary's. For example, if firewall B is the backup, its carp1 configuration would look like this: +would look like this: .Bd -literal -offset indent ifconfig_carp1="vhid 2 pass bar advskew 100 192.168.0.1/24" .Ed @@ -230,16 +183,10 @@ The following must also be added to .Bd -literal -offset indent net.inet.carp.preempt=1 .Ed -.Sh BUGS -Possibility to view state changes using -.Xr tcpdump 1 -has not been ported from -.Ox -yet. .Sh SEE ALSO .Xr bpf 4 , .Xr carp 4 , -.Xr ifconfig 8 , +.Xr enc 4 , .Xr inet 4 , .Xr inet6 4 , .Xr ipsec 4 , @@ -247,16 +194,20 @@ yet. .Xr pf 4 , .Xr pf.conf 5 , .Xr protocols 5 , -.Xr rc.conf 5 +.Xr rc.conf 5 , .Xr ifconfig 8 , .Xr ifstated 8 , -.Xr tcpdump 8 +.Xr tcpdump 1 .Sh HISTORY The .Nm device first appeared in .Ox 3.3 . +.Pp The .Nm -device was imported to -.Fx 5.3 . +protocol and kernel implementation were significantly modified between +.Ox 4.4 +and +.Ox 4.5 . +The two protocols are incompatible and will not interoperate. diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y index c22a0b6..440692e 100644 --- a/contrib/pf/pfctl/parse.y +++ b/contrib/pf/pfctl/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.517 2007/02/03 23:26:40 dhartmei Exp $ */ +/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ /* * Copyright (c) 2001 Markus Friedl. All rights reserved. @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> +#include <sys/stat.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -46,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include <altq/altq_hfsc.h> #include <stdio.h> +#include <unistd.h> #include <stdlib.h> #include <netdb.h> #include <stdarg.h> @@ -62,15 +64,8 @@ __FBSDID("$FreeBSD$"); #include "pfctl_parser.h" #include "pfctl.h" -#ifdef __FreeBSD__ -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - static struct pfctl *pf = NULL; -static FILE *fin = NULL; static int debug = 0; -static int lineno = 1; -static int errors = 0; static int rulestate = 0; static u_int16_t returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; @@ -80,6 +75,39 @@ 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, @@ -128,7 +156,8 @@ 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 }; + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, + PF_STATE_OPT_PFLOW }; enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; @@ -206,26 +235,34 @@ struct filter_opts { char *tag; char *match_tag; u_int8_t match_tag_not; - int rtableid; + u_int rtableid; + struct { + struct node_host *addr; + u_int16_t port; + } divert; } filter_opts; struct antispoof_opts { char *label; - int rtableid; + u_int rtableid; } antispoof_opts; struct scrub_opts { - int marker; + int marker; #define SOM_MINTTL 0x01 #define SOM_MAXMSS 0x02 #define SOM_FRAGCACHE 0x04 - int nodf; - int minttl; - int maxmss; - int fragcache; - int randomid; - int reassemble_tcp; - int rtableid; +#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 { @@ -260,63 +297,45 @@ struct pool_opts { } pool_opts; -struct node_hfsc_opts hfsc_opts; - -int yyerror(const char *, ...); -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 *); -int yyparse(void); -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 *); +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 kw_cmp(const void *, const void *); -int lookup(char *); -int lgetc(FILE *); -int lungetc(int); -int findeol(void); -int yylex(void); -int atoul(char *, u_long *); int getservice(char *); int rule_label(struct pf_rule *, char *); -TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); -struct sym { - TAILQ_ENTRY(sym) entries; - int used; - int persist; - char *nam; - char *val; -}; - - -int symset(const char *, const char *, int); -char *symget(const char *); - 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 *); @@ -334,10 +353,11 @@ struct loadanchors { typedef struct { union { - u_int32_t number; + int64_t number; + double probability; int i; char *string; - int rtableid; + u_int rtableid; struct { u_int8_t b1; u_int8_t b2; @@ -403,6 +423,10 @@ typedef struct { 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]))) @@ -417,32 +441,37 @@ typedef struct { %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 +%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 ROUTE +%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW +%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 natpass scrubaction +%type <v.b> action nataction natpasslog scrubaction %type <v.b> flags flag blockspec -%type <v.range> port rport +%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 xhost host dynaddr host_list +%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 @@ -451,7 +480,8 @@ typedef struct { %type <v.gid> gids gid_list gid_item %type <v.route> route %type <v.redirection> redirection redirpool -%type <v.string> label string tag anchorname +%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 @@ -474,6 +504,7 @@ typedef struct { %% ruleset : /* empty */ + | ruleset include '\n' | ruleset '\n' | ruleset option '\n' | ruleset scrubrule '\n' @@ -488,7 +519,22 @@ ruleset : /* empty */ | ruleset antispoof '\n' | ruleset tabledef '\n' | '{' fakeanchor '}' '\n'; - | ruleset error '\n' { errors++; } + | 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'); + } ; /* @@ -511,7 +557,7 @@ optimizer : string { else if (!strcmp($1, "profile")) $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; else { - yyerror("unknown ruleset-optimization %s", $$); + yyerror("unknown ruleset-optimization %s", $1); YYERROR; } } @@ -536,10 +582,10 @@ option : SET OPTIMIZATION STRING { } } | SET TIMEOUT timeout_spec - | SET TIMEOUT '{' timeout_list '}' + | SET TIMEOUT '{' optnl timeout_list '}' | SET LIMIT limit_spec - | SET LIMIT '{' limit_list '}' - | SET LOGINTERFACE STRING { + | SET LIMIT '{' optnl limit_list '}' + | SET LOGINTERFACE stringall { if (check_rulestate(PFCTL_STATE_OPTION)) { free($3); YYERROR; @@ -552,7 +598,7 @@ option : SET OPTIMIZATION STRING { free($3); } | SET HOSTID number { - if ($3 == 0) { + if ($3 == 0 || $3 > UINT_MAX) { yyerror("hostid must be non-zero"); YYERROR; } @@ -629,9 +675,24 @@ option : SET OPTIMIZATION STRING { YYERROR; } } + | SET STATEDEFAULTS state_opt_list { + if (keep_state_defaults != NULL) { + yyerror("cannot redefine state-defaults"); + YYERROR; + } + keep_state_defaults = $3; + } ; -string : string STRING { +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); @@ -640,7 +701,27 @@ string : string STRING { | STRING ; -varset : STRING '=' 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) @@ -654,14 +735,10 @@ anchorname : STRING { $$ = $1; } | /* empty */ { $$ = NULL; } ; -optnl : optnl '\n' - | - ; - -pfa_anchorlist : pfrule optnl - | anchorrule optnl - | pfa_anchorlist pfrule optnl - | pfa_anchorlist anchorrule optnl +pfa_anchorlist : /* empty */ + | pfa_anchorlist '\n' + | pfa_anchorlist pfrule '\n' + | pfa_anchorlist anchorrule '\n' ; pfa_anchor : '{' @@ -694,6 +771,7 @@ 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) @@ -744,6 +822,55 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto 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) { @@ -758,8 +885,8 @@ anchorrule : ANCHOR anchorname dir quick interface af proto fromto expand_rule(&r, $5, NULL, $7, $8.src_os, $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, - 0, 0, 0, pf->astack[pf->asd + 1] ? - pf->alast->name : $2); + $9.uid, $9.gid, $9.icmpspec, + pf->astack[pf->asd + 1] ? pf->alast->name : $2); free($2); pf->astack[pf->asd + 1] = NULL; } @@ -939,8 +1066,20 @@ scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts 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, @@ -973,30 +1112,38 @@ scrub_opt : NODF { } scrub_opts.nodf = 1; } - | MINTTL number { + | MINTTL NUMBER { if (scrub_opts.marker & SOM_MINTTL) { yyerror("min-ttl cannot be respecified"); YYERROR; } - if ($2 > 255) { + if ($2 < 0 || $2 > 255) { yyerror("illegal min-ttl value %d", $2); YYERROR; } scrub_opts.marker |= SOM_MINTTL; scrub_opts.minttl = $2; } - | MAXMSS number { + | MAXMSS NUMBER { if (scrub_opts.marker & SOM_MAXMSS) { yyerror("max-mss cannot be respecified"); YYERROR; } - if ($2 > 65535) { + 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"); @@ -1026,15 +1173,17 @@ scrub_opt : NODF { } scrub_opts.randomid = 1; } - | RTABLE number { -#ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */) { yyerror("invalid rtable id"); YYERROR; } -#endif scrub_opts.rtableid = $2; } + | not TAGGED string { + scrub_opts.match_tag = $3; + scrub_opts.match_tag_not = $1; + } ; fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } @@ -1108,6 +1257,7 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { 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)) @@ -1128,20 +1278,20 @@ antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { } ; -antispoof_ifspc : FOR antispoof_if { $$ = $2; } - | FOR '{' antispoof_iflst '}' { $$ = $3; } +antispoof_ifspc : FOR antispoof_if { $$ = $2; } + | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } ; -antispoof_iflst : antispoof_if { $$ = $1; } - | antispoof_iflst comma antispoof_if { +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 ')' { +antispoof_if : if_item { $$ = $1; } + | '(' if_item ')' { $2->dynamic = 1; $$ = $2; } @@ -1171,13 +1321,11 @@ antispoof_opt : label { } antispoof_opts.label = $1; } - | RTABLE number { -#ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) { yyerror("invalid rtable id"); YYERROR; } -#endif antispoof_opts.rtableid = $2; } ; @@ -1239,6 +1387,8 @@ table_opt : STRING { 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); @@ -1246,15 +1396,19 @@ table_opt : STRING { } free($1); } - | '{' '}' { table_opts.init_addr = 1; } - | '{' host_list '}' { + | '{' optnl '}' { table_opts.init_addr = 1; } + | '{' optnl host_list '}' { struct node_host *n; struct node_tinit *ti; - for (n = $2; n != NULL; n = n->next) { + 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"); @@ -1278,7 +1432,7 @@ table_opt : STRING { } if (!(ti = calloc(1, sizeof(*ti)))) err(1, "table_opt: calloc"); - ti->host = $2; + ti->host = $3; SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, entries); table_opts.init_addr = 1; @@ -1387,24 +1541,24 @@ queue_opt : BANDWIDTH bandwidth { queue_opts.marker |= QOM_BWSPEC; queue_opts.queue_bwspec = $2; } - | PRIORITY number { + | PRIORITY NUMBER { if (queue_opts.marker & QOM_PRIORITY) { yyerror("priority cannot be respecified"); YYERROR; } - if ($2 > 255) { + if ($2 < 0 || $2 > 255) { yyerror("priority out of range: max 255"); YYERROR; } queue_opts.marker |= QOM_PRIORITY; queue_opts.priority = $2; } - | QLIMIT number { + | QLIMIT NUMBER { if (queue_opts.marker & QOM_QLIMIT) { yyerror("qlimit cannot be respecified"); YYERROR; } - if ($2 > 65535) { + if ($2 < 0 || $2 > 65535) { yyerror("qlimit out of range: max 65535"); YYERROR; } @@ -1419,12 +1573,12 @@ queue_opt : BANDWIDTH bandwidth { queue_opts.marker |= QOM_SCHEDULER; queue_opts.scheduler = $1; } - | TBRSIZE number { + | TBRSIZE NUMBER { if (queue_opts.marker & QOM_TBRSIZE) { yyerror("tbrsize cannot be respecified"); YYERROR; } - if ($2 > 65535) { + if ($2 < 0 || $2 > 65535) { yyerror("tbrsize too big: max 65535"); YYERROR; } @@ -1467,6 +1621,14 @@ bandwidth : STRING { 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 { @@ -1563,8 +1725,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.linkshare.m2 = $2; hfsc_opts.linkshare.used = 1; } - | LINKSHARE '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1582,8 +1748,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.realtime.m2 = $2; hfsc_opts.realtime.used = 1; } - | REALTIME '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1601,8 +1771,12 @@ hfscopts_item : LINKSHARE bandwidth { hfsc_opts.upperlimit.m2 = $2; hfsc_opts.upperlimit.used = 1; } - | UPPERLIMIT '(' bandwidth comma number comma bandwidth ')' + | 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; @@ -1632,11 +1806,11 @@ hfscopts_item : LINKSHARE bandwidth { qassign : /* empty */ { $$ = NULL; } | qassign_item { $$ = $1; } - | '{' qassign_list '}' { $$ = $2; } + | '{' optnl qassign_list '}' { $$ = $3; } ; -qassign_list : qassign_item { $$ = $1; } - | qassign_list comma qassign_item { +qassign_list : qassign_item optnl { $$ = $1; } + | qassign_list comma qassign_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -1670,6 +1844,7 @@ pfrule : action dir logquick interface route af proto fromto int srctrack = 0; int statelock = 0; int adaptive = 0; + int defaults = 0; if (check_rulestate(PFCTL_STATE_FILTER)) YYERROR; @@ -1752,13 +1927,16 @@ pfrule : action dir logquick interface route af proto fromto 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)) + !($9.marker & FOM_KEEP)) { r.keep_state = PF_STATE_NORMAL; + o = keep_state_defaults; + defaults = 1; + } - o = $9.keep.options; while (o) { struct node_state_opt *p = o; @@ -1899,6 +2077,15 @@ pfrule : action dir logquick interface route af proto fromto } r.rule_flag |= PFRULE_STATESLOPPY; break; + case PF_STATE_OPT_PFLOW: + if (r.rule_flag & PFRULE_PFLOW) { + yyerror("state pflow " + "option: multiple " + "definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_PFLOW; + break; case PF_STATE_OPT_TIMEOUT: if (o->data.timeout.number == PFTM_ADAPTIVE_START || @@ -1916,7 +2103,8 @@ pfrule : action dir logquick interface route af proto fromto o->data.timeout.seconds; } o = o->next; - free(p); + if (!defaults) + free(p); } /* 'flags S/SA' by default on stateful rules */ @@ -2035,6 +2223,34 @@ pfrule : action dir logquick interface route af proto fromto } 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, @@ -2088,13 +2304,13 @@ filter_opt : USER uids { filter_opts.marker |= FOM_ICMP; filter_opts.icmpspec = $1; } - | tos { + | TOS tos { if (filter_opts.marker & FOM_TOS) { yyerror("tos cannot be redefined"); YYERROR; } filter_opts.marker |= FOM_TOS; - filter_opts.tos = $1; + filter_opts.tos = $2; } | keep { if (filter_opts.marker & FOM_KEEP) { @@ -2132,39 +2348,84 @@ filter_opt : USER uids { filter_opts.match_tag = $3; filter_opts.match_tag_not = $1; } - | PROBABILITY STRING { - char *e; - double p = strtod($2, &e); + | PROBABILITY probability { + double p; - if (*e == '%') { - p *= 0.01; - e++; + p = floor($2 * UINT_MAX + 0.5); + if (p < 0.0 || p > UINT_MAX) { + yyerror("invalid probability: %lf", p); + YYERROR; } - if (*e) { - yyerror("invalid probability: %s", $2); - free($2); + 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; } - p = floor(p * (UINT_MAX+1.0) + 0.5); - if (p < 1.0 || p >= (UINT_MAX+1.0)) { - yyerror("invalid probability: %s", $2); - free($2); + 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; } - filter_opts.prob = (u_int32_t)p; - free($2); +#endif } - | RTABLE number { + | DIVERTTO STRING PORT portplain { #ifndef __FreeBSD__ - if ($2 > RT_TABLEID_MAX || $2 < 0) { - yyerror("invalid rtable id"); + if ((filter_opts.divert.addr = host($2)) == NULL) { + yyerror("could not parse divert address: %s", + $2); + free($2); YYERROR; } +#else + if ($2) +#endif + free($2); + filter_opts.divert.port = $4.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs($4.a)); + YYERROR; + } + } + | DIVERTREPLY { +#ifdef __FreeBSD__ + yyerror("divert-reply has no meaning in FreeBSD pf(4)"); + YYERROR; +#else + filter_opts.divert.port = 1; /* some random value */ #endif - filter_opts.rtableid = $2; } ; +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; } ; @@ -2184,8 +2445,8 @@ blockspec : /* empty */ { $$.w = 0; $$.w2 = 0; } - | RETURNRST '(' TTL number ')' { - if ($4 > 255) { + | RETURNRST '(' TTL NUMBER ')' { + if ($4 < 0 || $4 > 255) { yyerror("illegal ttl value %d", $4); YYERROR; } @@ -2203,34 +2464,20 @@ blockspec : /* empty */ { $$.w = returnicmpdefault; $$.w2 = returnicmp6default; } - | RETURNICMP '(' STRING ')' { + | RETURNICMP '(' reticmpspec ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET))) { - free($3); - YYERROR; - } - free($3); - $$.w2 = returnicmp6default; + $$.w = $3; + $$.w2 = returnicmpdefault; } - | RETURNICMP6 '(' STRING ')' { + | RETURNICMP6 '(' reticmp6spec ')' { $$.b2 = PFRULE_RETURNICMP; $$.w = returnicmpdefault; - if (!($$.w2 = parseicmpspec($3, AF_INET6))) { - free($3); - YYERROR; - } - free($3); + $$.w2 = $3; } - | RETURNICMP '(' STRING comma STRING ')' { + | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { $$.b2 = PFRULE_RETURNICMP; - if (!($$.w = parseicmpspec($3, AF_INET)) || - !($$.w2 = parseicmpspec($5, AF_INET6))) { - free($3); - free($5); - YYERROR; - } - free($3); - free($5); + $$.w = $3; + $$.w2 = $5; } | RETURN { $$.b2 = PFRULE_RETURN; @@ -2239,7 +2486,45 @@ blockspec : /* empty */ { } ; -dir : /* empty */ { $$ = 0; } +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; } ; @@ -2297,11 +2582,11 @@ logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } interface : /* empty */ { $$ = NULL; } | ON if_item_not { $$ = $2; } - | ON '{' if_list '}' { $$ = $3; } + | ON '{' optnl if_list '}' { $$ = $4; } ; -if_list : if_item_not { $$ = $1; } - | if_list comma if_item_not { +if_list : if_item_not optnl { $$ = $1; } + | if_list comma if_item_not optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2340,42 +2625,23 @@ af : /* empty */ { $$ = 0; } | INET6 { $$ = AF_INET6; } ; -proto : /* empty */ { $$ = NULL; } - | PROTO proto_item { $$ = $2; } - | PROTO '{' proto_list '}' { $$ = $3; } +proto : /* empty */ { $$ = NULL; } + | PROTO proto_item { $$ = $2; } + | PROTO '{' optnl proto_list '}' { $$ = $4; } ; -proto_list : proto_item { $$ = $1; } - | proto_list comma proto_item { +proto_list : proto_item optnl { $$ = $1; } + | proto_list comma proto_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -proto_item : STRING { +proto_item : protoval { u_int8_t pr; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("protocol outside range"); - free($1); - YYERROR; - } - pr = (u_int8_t)ulval; - } else { - struct protoent *p; - - p = getprotobyname($1); - if (p == NULL) { - yyerror("unknown protocol %s", $1); - free($1); - YYERROR; - } - pr = p->p_proto; - } - free($1); + pr = (u_int8_t)$1; if (pr == 0) { yyerror("proto 0 cannot be used"); YYERROR; @@ -2389,6 +2655,26 @@ proto_item : STRING { } ; +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; @@ -2405,7 +2691,7 @@ fromto : ALL { os : /* empty */ { $$ = NULL; } | OS xos { $$ = $2; } - | OS '{' os_list '}' { $$ = $3; } + | OS '{' optnl os_list '}' { $$ = $4; } ; xos : STRING { @@ -2417,8 +2703,8 @@ xos : STRING { } ; -os_list : xos { $$ = $1; } - | os_list comma xos { +os_list : xos optnl { $$ = $1; } + | os_list comma xos optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2460,13 +2746,21 @@ ipportspec : ipspec { } ; +optnl : '\n' optnl + | + ; + ipspec : ANY { $$ = NULL; } | xhost { $$ = $1; } - | '{' host_list '}' { $$ = $2; } + | '{' optnl host_list '}' { $$ = $3; } + ; + +toipspec : TO ipspec { $$ = $2; } + | /* empty */ { $$ = NULL; } ; -host_list : ipspec { $$ = $1; } - | host_list comma ipspec { +host_list : ipspec optnl { $$ = $1; } + | host_list comma ipspec optnl { if ($3 == NULL) $$ = $1; else if ($1 == NULL) @@ -2516,10 +2810,43 @@ host : STRING { free($1); } - | STRING '/' number { + | 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/%u", $1, $3) == -1) + if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) err(1, "host: asprintf"); free($1); if (($$ = host(buf)) == NULL) { @@ -2530,10 +2857,32 @@ host : STRING { } 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 { + | 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); @@ -2578,7 +2927,8 @@ host : STRING { } ; -number : STRING { +number : NUMBER + | STRING { u_long ulval; if (atoul($1, &ulval) == -1) { @@ -2646,18 +2996,18 @@ dynaddr : '(' STRING ')' { ; portspec : port_item { $$ = $1; } - | '{' port_list '}' { $$ = $2; } + | '{' optnl port_list '}' { $$ = $3; } ; -port_list : port_item { $$ = $1; } - | port_list comma port_item { +port_list : port_item optnl { $$ = $1; } + | port_list comma port_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -port_item : port { +port_item : portrange { $$ = calloc(1, sizeof(struct node_port)); if ($$ == NULL) err(1, "port_item: calloc"); @@ -2670,7 +3020,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | unaryop port { + | unaryop portrange { if ($2.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2685,7 +3035,7 @@ port_item : port { $$->next = NULL; $$->tail = $$; } - | port PORTBINARY port { + | portrange PORTBINARY portrange { if ($1.t || $3.t) { yyerror("':' cannot be used with an other " "port operator"); @@ -2702,38 +3052,30 @@ port_item : port { } ; -port : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else { - int port[2]; +portplain : numberstring { + if (parseport($1, &$$, 0) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; - *p++ = 0; - if ((port[0] = getservice($1)) == -1 || - (port[1] = getservice(p)) == -1) { - free($1); - YYERROR; - } - $$.a = port[0]; - $$.b = port[1]; - $$.t = PF_OP_RRG; +portrange : numberstring { + if (parseport($1, &$$, PPORT_RANGE) == -1) { + free($1); + YYERROR; } free($1); } ; uids : uid_item { $$ = $1; } - | '{' uid_list '}' { $$ = $2; } + | '{' optnl uid_list '}' { $$ = $3; } ; -uid_list : uid_item { $$ = $1; } - | uid_list comma uid_item { +uid_list : uid_item optnl { $$ = $1; } + | uid_list comma uid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2783,39 +3125,35 @@ uid_item : uid { ; uid : STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - if (!strcmp($1, "unknown")) - $$ = UID_MAX; - else { - struct passwd *pw; + 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; - } - } else { - if (ulval >= UID_MAX) { + if ((pw = getpwnam($1)) == NULL) { + yyerror("unknown user %s", $1); free($1); - yyerror("illegal uid value %lu", ulval); YYERROR; } - $$ = ulval; + $$ = pw->pw_uid; } free($1); } + | NUMBER { + if ($1 < 0 || $1 >= UID_MAX) { + yyerror("illegal uid value %lu", $1); + YYERROR; + } + $$ = $1; + } ; gids : gid_item { $$ = $1; } - | '{' gid_list '}' { $$ = $2; } + | '{' optnl gid_list '}' { $$ = $3; } ; -gid_list : gid_item { $$ = $1; } - | gid_list comma gid_item { +gid_list : gid_item optnl { $$ = $1; } + | gid_list comma gid_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2865,31 +3203,27 @@ gid_item : gid { ; gid : STRING { - u_long ulval; - - if (atoul($1, &ulval) == -1) { - if (!strcmp($1, "unknown")) - $$ = GID_MAX; - else { - struct group *grp; + 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; - } - } else { - if (ulval >= GID_MAX) { - yyerror("illegal gid value %lu", ulval); + if ((grp = getgrnam($1)) == NULL) { + yyerror("unknown group %s", $1); free($1); YYERROR; } - $$ = ulval; + $$ = grp->gr_gid; } free($1); } + | NUMBER { + if ($1 < 0 || $1 >= GID_MAX) { + yyerror("illegal gid value %lu", $1); + YYERROR; + } + $$ = $1; + } ; flag : STRING { @@ -2910,22 +3244,22 @@ flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } ; -icmpspec : ICMPTYPE icmp_item { $$ = $2; } - | ICMPTYPE '{' icmp_list '}' { $$ = $3; } - | ICMP6TYPE icmp6_item { $$ = $2; } - | ICMP6TYPE '{' icmp6_list '}' { $$ = $3; } +icmpspec : ICMPTYPE icmp_item { $$ = $2; } + | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } + | ICMP6TYPE icmp6_item { $$ = $2; } + | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } ; -icmp_list : icmp_item { $$ = $1; } - | icmp_list comma icmp_item { +icmp_list : icmp_item optnl { $$ = $1; } + | icmp_list comma icmp_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; } ; -icmp6_list : icmp6_item { $$ = $1; } - | icmp6_list comma icmp6_item { +icmp6_list : icmp6_item optnl { $$ = $1; } + | icmp6_list comma icmp6_item optnl { $1->tail->next = $3; $1->tail = $3; $$ = $1; @@ -2944,29 +3278,33 @@ icmp_item : icmptype { } | icmptype CODE STRING { const struct icmpcodeent *p; - u_long ulval; - if (atoul($3, &ulval) == 0) { - if (ulval > 255) { - free($3); - yyerror("illegal icmp-code %lu", ulval); - YYERROR; - } - } else { - if ((p = geticmpcodebyname($1-1, $3, - AF_INET)) == NULL) { - yyerror("unknown icmp-code %s", $3); - free($3); - YYERROR; - } - ulval = p->code; + 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 = ulval + 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 = $$; @@ -2985,30 +3323,33 @@ icmp6_item : icmp6type { } | icmp6type CODE STRING { const struct icmpcodeent *p; - u_long ulval; - if (atoul($3, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp6-code %lu", - ulval); - free($3); - YYERROR; - } - } else { - if ((p = geticmpcodebyname($1-1, $3, - AF_INET6)) == NULL) { - yyerror("unknown icmp6-code %s", $3); - free($3); - YYERROR; - } - ulval = p->code; + 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 = ulval + 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 = $$; @@ -3017,70 +3358,69 @@ icmp6_item : icmp6type { icmptype : STRING { const struct icmptypeent *p; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp-type %lu", ulval); - free($1); - YYERROR; - } - $$ = ulval + 1; - } else { - if ((p = geticmptypebyname($1, AF_INET)) == - NULL) { - yyerror("unknown icmp-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; + 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; - u_long ulval; - if (atoul($1, &ulval) == 0) { - if (ulval > 255) { - yyerror("illegal icmp6-type %lu", - ulval); - free($1); - YYERROR; - } - $$ = ulval + 1; - } else { - if ((p = geticmptypebyname($1, AF_INET6)) == - NULL) { - yyerror("unknown icmp6-type %s", $1); - free($1); - YYERROR; - } - $$ = p->type + 1; + 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 : TOS STRING { - if (!strcmp($2, "lowdelay")) +tos : STRING { + if (!strcmp($1, "lowdelay")) $$ = IPTOS_LOWDELAY; - else if (!strcmp($2, "throughput")) + else if (!strcmp($1, "throughput")) $$ = IPTOS_THROUGHPUT; - else if (!strcmp($2, "reliability")) + else if (!strcmp($1, "reliability")) $$ = IPTOS_RELIABILITY; - else if ($2[0] == '0' && $2[1] == 'x') - $$ = strtoul($2, NULL, 16); + else if ($1[0] == '0' && $1[1] == 'x') + $$ = strtoul($1, NULL, 16); else - $$ = strtoul($2, NULL, 10); + $$ = 0; /* flag bad argument */ if (!$$ || $$ > 255) { - yyerror("illegal tos value %s", $2); - free($2); + yyerror("illegal tos value %s", $1); + free($1); + YYERROR; + } + free($1); + } + | NUMBER { + $$ = $1; + if (!$$ || $$ > 255) { + yyerror("illegal tos value %s", $1); YYERROR; } - free($2); } ; @@ -3134,7 +3474,11 @@ state_opt_list : state_opt_item { $$ = $1; } } ; -state_opt_item : MAXIMUM number { +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"); @@ -3151,7 +3495,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCSTATES number { + | 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"); @@ -3160,7 +3508,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCCONN number { + | 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"); @@ -3169,7 +3521,12 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCCONNRATE number '/' number { + | 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"); @@ -3197,7 +3554,11 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | MAXSRCNODES number { + | 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"); @@ -3232,9 +3593,21 @@ state_opt_item : MAXIMUM number { $$->next = NULL; $$->tail = $$; } - | STRING number { + | PFLOW { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_PFLOW; + $$->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 */ @@ -3267,9 +3640,11 @@ label : LABEL STRING { qname : QUEUE STRING { $$.qname = $2; + $$.pqname = NULL; } | QUEUE '(' STRING ')' { $$.qname = $3; + $$.pqname = NULL; } | QUEUE '(' STRING comma STRING ')' { $$.qname = $3; @@ -3281,44 +3656,21 @@ no : /* empty */ { $$ = 0; } | NO { $$ = 1; } ; -rport : STRING { - char *p = strchr($1, ':'); - - if (p == NULL) { - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = $$.t = 0; - } else if (!strcmp(p+1, "*")) { - *p = 0; - if (($$.a = getservice($1)) == -1) { - free($1); - YYERROR; - } - $$.b = 0; - $$.t = 1; - } else { - *p++ = 0; - if (($$.a = getservice($1)) == -1 || - ($$.b = getservice(p)) == -1) { - free($1); - YYERROR; - } - if ($$.a == $$.b) - $$.b = 0; - $$.t = 0; +portstar : numberstring { + if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { + free($1); + YYERROR; } free($1); } ; redirspec : host { $$ = $1; } - | '{' redir_host_list '}' { $$ = $2; } + | '{' optnl redir_host_list '}' { $$ = $3; } ; -redir_host_list : host { $$ = $1; } - | redir_host_list comma host { +redir_host_list : host optnl { $$ = $1; } + | redir_host_list comma host optnl { $1->tail->next = $3; $1->tail = $3->tail; $$ = $1; @@ -3333,7 +3685,7 @@ redirpool : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW redirspec PORT rport { + | ARROW redirspec PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3459,7 +3811,7 @@ redirection : /* empty */ { $$ = NULL; } $$->host = $2; $$->rport.a = $$->rport.b = $$->rport.t = 0; } - | ARROW host PORT rport { + | ARROW host PORT portstar { $$ = calloc(1, sizeof(struct redirection)); if ($$ == NULL) err(1, "redirection: calloc"); @@ -3468,17 +3820,13 @@ redirection : /* empty */ { $$ = NULL; } } ; -/* ifdef __FreeBSD__ */ -natpass : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } +natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } -/* else -natpass : empty { $$.b1 = $$.b2 = 0; } - | PASS { $$.b1 = 1; $$.b2 = 0; } - * endif */ | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } + | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } ; -nataction : no NAT natpass { +nataction : no NAT natpasslog { if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); YYERROR; @@ -3491,7 +3839,7 @@ nataction : no NAT natpass { $$.w = $3.b2; $$.w2 = $3.w2; } - | no RDR natpass { + | no RDR natpasslog { if ($1 && $3.b1) { yyerror("\"pass\" not valid with \"no\""); YYERROR; @@ -3665,7 +4013,7 @@ natrule : nataction interface af proto fromto tag tagged rtable } ; -binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag +binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection { struct pf_rule binat; @@ -3673,7 +4021,7 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag if (check_rulestate(PFCTL_STATE_NAT)) YYERROR; - if (disallow_urpf_failed($10, "\"urpf-failed\" is not " + if (disallow_urpf_failed($9, "\"urpf-failed\" is not " "permitted as a binat destination")) YYERROR; @@ -3693,11 +4041,11 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag binat.af = $5; if (!binat.af && $8 != NULL && $8->af) binat.af = $8->af; - if (!binat.af && $10 != NULL && $10->af) - binat.af = $10->af; + if (!binat.af && $9 != NULL && $9->af) + binat.af = $9->af; - if (!binat.af && $14 != NULL && $14->host) - binat.af = $14->host->af; + if (!binat.af && $13 != NULL && $13->host) + binat.af = $13->host->af; if (!binat.af) { yyerror("address family (inet/inet6) " "undefined"); @@ -3711,22 +4059,22 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag free($4); } - if ($11 != NULL) - if (strlcpy(binat.tagname, $11, + 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 ($12.name) - if (strlcpy(binat.match_tagname, $12.name, + 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 = $12.neg; - binat.rtableid = $13; + binat.match_tag_not = $11.neg; + binat.rtableid = $12; if ($6 != NULL) { binat.proto = $6->proto; @@ -3740,12 +4088,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag "interface (%s) as the source address of a binat " "rule")) YYERROR; - if ($14 != NULL && $14->host != NULL && disallow_table( - $14->host, "invalid use of table <%s> as the " + 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 ($14 != NULL && $14->host != NULL && disallow_alias( - $14->host, "invalid use of interface (%s) as the " + if ($13 != NULL && $13->host != NULL && disallow_alias( + $13->host, "invalid use of interface (%s) as the " "redirect address of a binat rule")) YYERROR; @@ -3766,51 +4114,51 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag sizeof(binat.src.addr)); free($8); } - if ($10 != NULL) { - if ($10->next) { + if ($9 != NULL) { + if ($9->next) { yyerror("multiple binat ip addresses"); YYERROR; } - if ($10->af != binat.af && $10->af) { + if ($9->af != binat.af && $9->af) { yyerror("binat ip versions must match"); YYERROR; } - if (check_netmask($10, binat.af)) + if (check_netmask($9, binat.af)) YYERROR; - memcpy(&binat.dst.addr, &$10->addr, + memcpy(&binat.dst.addr, &$9->addr, sizeof(binat.dst.addr)); - binat.dst.neg = $10->not; - free($10); + binat.dst.neg = $9->not; + free($9); } if (binat.action == PF_NOBINAT) { - if ($14 != NULL) { + if ($13 != NULL) { yyerror("'no binat' rule does not need" " '->'"); YYERROR; } } else { - if ($14 == NULL || $14->host == NULL) { + if ($13 == NULL || $13->host == NULL) { yyerror("'binat' rule requires" " '-> address'"); YYERROR; } - remove_invalid_hosts(&$14->host, &binat.af); - if (invalid_redirect($14->host, binat.af)) + remove_invalid_hosts(&$13->host, &binat.af); + if (invalid_redirect($13->host, binat.af)) YYERROR; - if ($14->host->next != NULL) { + if ($13->host->next != NULL) { yyerror("binat rule must redirect to " "a single address"); YYERROR; } - if (check_netmask($14->host, binat.af)) + 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, - &$14->host->addr.v.a.mask, binat.af)) { + &$13->host->addr.v.a.mask, binat.af)) { yyerror("'binat' source mask and " "redirect mask must be the same"); YYERROR; @@ -3820,12 +4168,12 @@ binatrule : no BINAT natpass interface af proto FROM host TO ipspec tag pa = calloc(1, sizeof(struct pf_pooladdr)); if (pa == NULL) err(1, "binat: calloc"); - pa->addr = $14->host->addr; + pa->addr = $13->host->addr; pa->ifname[0] = 0; TAILQ_INSERT_TAIL(&binat.rpool.list, pa, entries); - free($14); + free($13); } pfctl_add_rule(pf, &binat, ""); @@ -3841,17 +4189,12 @@ tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } ; rtable : /* empty */ { $$ = -1; } - | RTABLE number { -#ifdef __FreeBSD__ - yyerror("rtable id not supported in FreeBSD, yet"); - YYERROR; -#else - if ($2 > RT_TABLEID_MAX || $2 < 0) { + | RTABLE NUMBER { + if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) { yyerror("invalid rtable id"); YYERROR; } $$ = $2; -#endif } ; @@ -3870,8 +4213,8 @@ route_host : STRING { } ; -route_host_list : route_host { $$ = $1; } - | route_host_list comma route_host { +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) { @@ -3886,7 +4229,7 @@ route_host_list : route_host { $$ = $1; } ; routespec : route_host { $$ = $1; } - | '{' route_host_list '}' { $$ = $2; } + | '{' optnl route_host_list '}' { $$ = $3; } ; route : /* empty */ { @@ -3922,12 +4265,16 @@ route : /* empty */ { } ; -timeout_spec : STRING number +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); @@ -3937,16 +4284,20 @@ timeout_spec : STRING number } ; -timeout_list : timeout_list comma timeout_spec - | timeout_spec +timeout_list : timeout_list comma timeout_spec optnl + | timeout_spec optnl ; -limit_spec : STRING number +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); @@ -3956,8 +4307,8 @@ limit_spec : STRING number } ; -limit_list : limit_list comma limit_spec - | limit_spec +limit_list : limit_list comma limit_spec optnl + | limit_spec optnl ; comma : ',' @@ -3992,11 +4343,10 @@ int yyerror(const char *fmt, ...) { va_list ap; - extern char *infile; - errors = 1; + file->errors++; va_start(ap, fmt); - fprintf(stderr, "%s:%d: ", infile, yylval.lineno); + fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); @@ -4914,6 +5264,8 @@ lookup(char *s) { "code", CODE}, { "crop", FRAGCROP}, { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, { "drop", DROP}, { "drop-ovl", FRAGDROP}, { "dup-to", DUPTO}, @@ -4934,6 +5286,7 @@ lookup(char *s) { "icmp6-type", ICMP6TYPE}, { "if-bound", IFBOUND}, { "in", IN}, + { "include", INCLUDE}, { "inet", INET}, { "inet6", INET6}, { "keep", KEEP}, @@ -4963,6 +5316,7 @@ lookup(char *s) { "out", OUT}, { "overload", OVERLOAD}, { "pass", PASS}, + { "pflow", PFLOW}, { "port", PORT}, { "priority", PRIORITY}, { "priq", PRIQ}, @@ -4991,11 +5345,13 @@ lookup(char *s) { "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}, @@ -5036,9 +5392,9 @@ char pushback_buffer[MAXPUSHBACK]; int pushback_index = 0; int -lgetc(FILE *f) +lgetc(int quotec) { - int c, next; + int c, next; if (parsebuf) { /* Read character from the parsebuffer instead of input. */ @@ -5054,24 +5410,31 @@ lgetc(FILE *f) if (pushback_index) return (pushback_buffer[--pushback_index]); - while ((c = getc(f)) == '\\') { - next = getc(f); + 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 = lineno; - lineno++; - } - if (c == '\t' || c == ' ') { - /* Compress blanks to a single space. */ - do { - c = getc(f); - } while (c == '\t' || c == ' '); - ungetc(c, f); - c = ' '; + yylval.lineno = file->lineno; + file->lineno++; } + while (c == EOF) { + if (popfile() == EOF) + return (EOF); + c = getc(file->stream); + } return (c); } @@ -5097,13 +5460,15 @@ findeol(void) int c; parsebuf = NULL; - pushback_index = 0; /* skip to either EOF or the first real EOL */ while (1) { - c = lgetc(fin); + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); if (c == '\n') { - lineno++; + file->lineno++; break; } if (c == EOF) @@ -5117,21 +5482,21 @@ yylex(void) { char buf[8096]; char *p, *val; - int endc, c, next; + int quotec, next, c; int token; top: p = buf; - while ((c = lgetc(fin)) == ' ') + while ((c = lgetc(0)) == ' ' || c == '\t') ; /* nothing */ - yylval.lineno = lineno; + yylval.lineno = file->lineno; if (c == '#') - while ((c = lgetc(fin)) != '\n' && c != EOF) + while ((c = lgetc(0)) != '\n' && c != EOF) ; /* nothing */ if (c == '$' && parsebuf == NULL) { while (1) { - if ((c = lgetc(fin)) == EOF) + if ((c = lgetc(0)) == EOF) return (0); if (p + 1 >= buf + sizeof(buf) - 1) { @@ -5159,17 +5524,25 @@ top: switch (c) { case '\'': case '"': - endc = c; + quotec = c; while (1) { - if ((c = lgetc(fin)) == EOF) + if ((c = lgetc(quotec)) == EOF) return (0); - if (c == endc) { - *p = '\0'; - break; - } if (c == '\n') { - lineno++; + 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"); @@ -5182,7 +5555,7 @@ top: err(1, "yylex: strdup"); return (STRING); case '<': - next = lgetc(fin); + next = lgetc(0); if (next == '>') { yylval.v.i = PF_OP_XRG; return (PORTBINARY); @@ -5190,7 +5563,7 @@ top: lungetc(next); break; case '>': - next = lgetc(fin); + next = lgetc(0); if (next == '<') { yylval.v.i = PF_OP_IRG; return (PORTBINARY); @@ -5198,13 +5571,49 @@ top: lungetc(next); break; case '-': - next = lgetc(fin); + 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 != '>' && \ @@ -5218,7 +5627,7 @@ top: yyerror("string too long"); return (findeol()); } - } while ((c = lgetc(fin)) != EOF && (allowed_in_string(c))); + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); lungetc(c); *p = '\0'; if ((token = lookup(buf)) == STRING) @@ -5227,8 +5636,8 @@ top: return (token); } if (c == '\n') { - yylval.lineno = lineno; - lineno++; + yylval.lineno = file->lineno; + file->lineno++; } if (c == EOF) return (0); @@ -5236,13 +5645,84 @@ top: } int -parse_rules(FILE *input, struct pfctl *xpf) +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 sym *sym, *next; + 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; - fin = input; pf = xpf; - lineno = 1; errors = 0; rulestate = PFCTL_STATE_NONE; returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; @@ -5251,34 +5731,36 @@ parse_rules(FILE *input, struct pfctl *xpf) 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. */ - for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { - next = TAILQ_NEXT(sym, entries); + 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, entries); + TAILQ_REMOVE(&symhead, sym, entry); free(sym); } return (errors ? -1 : 0); } -/* - * Over-designed efficiency is a French and German concept, so how about - * we wait until they discover this ugliness and make it all fancy. - */ 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, entries)) + sym = TAILQ_NEXT(sym, entry)) ; /* nothing */ if (sym != NULL) { @@ -5287,7 +5769,7 @@ symset(const char *nam, const char *val, int persist) else { free(sym->nam); free(sym->val); - TAILQ_REMOVE(&symhead, sym, entries); + TAILQ_REMOVE(&symhead, sym, entry); free(sym); } } @@ -5307,7 +5789,7 @@ symset(const char *nam, const char *val, int persist) } sym->used = 0; sym->persist = persist; - TAILQ_INSERT_TAIL(&symhead, sym, entries); + TAILQ_INSERT_TAIL(&symhead, sym, entry); return (0); } @@ -5336,7 +5818,7 @@ symget(const char *nam) { struct sym *sym; - TAILQ_FOREACH(sym, &symhead, entries) + TAILQ_FOREACH(sym, &symhead, entry) if (strcmp(nam, sym->nam) == 0) { sym->used = 1; return (sym->val); @@ -5519,20 +6001,50 @@ parseicmpspec(char *w, sa_family_t af) } 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; - FILE *fin; TAILQ_FOREACH(la, &loadanchorshead, entries) { if (pf->opts & PF_OPT_VERBOSE) fprintf(stderr, "\nLoading anchor %s from %s\n", la->anchorname, la->filename); - if ((fin = pfctl_fopen(la->filename, "r")) == NULL) { - warn("%s", la->filename); - continue; - } - if (pfctl_rules(dev, la->filename, fin, pf->opts, pf->optimize, + if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, la->anchorname, trans) == -1) return (-1); } diff --git a/contrib/pf/pfctl/pf_print_state.c b/contrib/pf/pfctl/pf_print_state.c index 02a39b3..0698516 100644 --- a/contrib/pf/pfctl/pf_print_state.c +++ b/contrib/pf/pfctl/pf_print_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_print_state.c,v 1.44 2007/03/01 17:20:53 deraadt Exp $ */ +/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,7 +35,10 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> +#ifdef __FreeBSD__ #include <sys/endian.h> +#define betoh64 be64toh +#endif #include <net/if.h> #define TCPSTATES #include <netinet/tcp_fsm.h> @@ -83,6 +86,19 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) 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)) @@ -112,7 +128,8 @@ print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) } /* mask if not _both_ address and mask are zero */ - if (!(PF_AZERO(&addr->v.a.addr, AF_INET6) && + 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); @@ -155,17 +172,15 @@ print_name(struct pf_addr *addr, sa_family_t af) } void -print_host(struct pf_state_host *h, sa_family_t af, int opts) +print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) { - u_int16_t p = ntohs(h->port); - if (opts & PF_OPT_USEDNS) - print_name(&h->addr, af); + print_name(addr, af); else { struct pf_addr_wrap aw; memset(&aw, 0, sizeof(aw)); - aw.v.a.addr = h->addr; + aw.v.a.addr = *addr; if (af == AF_INET) aw.v.a.mask.addr32[0] = 0xffffffff; else { @@ -175,57 +190,72 @@ print_host(struct pf_state_host *h, sa_family_t af, int opts) print_addr(&aw, af, opts & PF_OPT_VERBOSE2); } - if (p) { + if (port) { if (af == AF_INET) - printf(":%u", p); + printf(":%u", ntohs(port)); else - printf("[%u]", p); + printf("[%u]", ntohs(port)); } } void -print_seq(struct pf_state_peer *p) +print_seq(struct pfsync_state_peer *p) { if (p->seqdiff) - printf("[%u + %u](+%u)", p->seqlo, p->seqhi - p->seqlo, - p->seqdiff); + printf("[%u + %u](+%u)", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); else - printf("[%u + %u]", p->seqlo, p->seqhi - p->seqlo); + printf("[%u + %u]", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo)); } void -print_state(struct pf_state *s, int opts) +print_state(struct pfsync_state *s, int opts) { - struct pf_state_peer *src, *dst; + 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->u.ifname); + printf("%s ", s->ifname); if ((p = getprotobynumber(s->proto)) != NULL) printf("%s ", p->p_name); else printf("%u ", s->proto); - if (PF_ANEQ(&s->lan.addr, &s->gwy.addr, s->af) || - (s->lan.port != s->gwy.port)) { - print_host(&s->lan, s->af, opts); - if (s->direction == PF_OUT) - printf(" -> "); - else - printf(" <- "); + + 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(")"); } - print_host(&s->gwy, s->af, opts); if (s->direction == PF_OUT) printf(" -> "); else printf(" <- "); - print_host(&s->ext, s->af, opts); + 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) { @@ -271,45 +301,63 @@ print_state(struct pf_state *s, int opts) } if (opts & PF_OPT_VERBOSE) { - sec = s->creation % 60; - s->creation /= 60; - min = s->creation % 60; - s->creation /= 60; - printf(" age %.2u:%.2u:%.2u", s->creation, min, sec); - sec = s->expire % 60; - s->expire /= 60; - min = s->expire % 60; - s->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", s->expire, min, sec); + 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(", %llu:%llu pkts, %llu:%llu bytes", #ifdef __FreeBSD__ - (unsigned long long)s->packets[0], - (unsigned long long)s->packets[1], - (unsigned long long)s->bytes[0], - (unsigned long long)s->bytes[1]); + (unsigned long long)betoh64(packets[0]), + (unsigned long long)betoh64(packets[1]), + (unsigned long long)betoh64(bytes[0]), + (unsigned long long)betoh64(bytes[1])); #else - s->packets[0], s->packets[1], s->bytes[0], s->bytes[1]); + betoh64(packets[0]), + betoh64(packets[1]), + betoh64(bytes[0]), + betoh64(bytes[1])); #endif - if (s->anchor.nr != -1) - printf(", anchor %u", s->anchor.nr); - if (s->rule.nr != -1) - printf(", rule %u", s->rule.nr); + 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->src_node != NULL) + if (s->state_flags & PFSTATE_PFLOW) + printf(", pflow"); + if (s->sync_flags & PFSYNC_FLAG_SRCNODE) printf(", source-track"); - if (s->nat_src_node != NULL) + if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) printf(", sticky-address"); printf("\n"); } if (opts & PF_OPT_VERBOSE2) { - printf(" id: %016llx creatorid: %08x%s\n", + u_int64_t id; + + bcopy(&s->id, &id, sizeof(u_int64_t)); + printf(" id: %016llx creatorid: %08x", #ifdef __FreeBSD__ - (unsigned long long)be64toh(s->id), ntohl(s->creatorid), + (unsigned long long)betoh64(id), ntohl(s->creatorid)); #else - betoh64(s->id), ntohl(s->creatorid), + betoh64(id), ntohl(s->creatorid)); #endif - ((s->sync_flags & PFSTATE_NOSYNC) ? " (no-sync)" : "")); + printf("\n"); } } diff --git a/contrib/pf/pfctl/pfctl.8 b/contrib/pf/pfctl/pfctl.8 index 917a859..0730443 100644 --- a/contrib/pf/pfctl/pfctl.8 +++ b/contrib/pf/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.128 2007/01/30 21:01:56 jmc Exp $ +.\" $OpenBSD: pfctl.8,v 1.138 2008/06/10 20:55:02 mcbride Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -26,12 +26,12 @@ .\" .\" $FreeBSD$ .\" -.Dd June 13, 2011 +.Dd June 21, 2011 .Dt PFCTL 8 .Os .Sh NAME .Nm pfctl -.Nd "control the packet filter (PF) and network address translation (NAT) device" +.Nd control the packet filter (PF) device .Sh SYNOPSIS .Nm pfctl .Bk -words @@ -43,15 +43,18 @@ .Op Fl f Ar file .Op Fl i Ar interface .Op Fl K Ar host | network -.Op Fl k Ar host | network -.Op Fl o Op Ar level +.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 -.Oo -.Fl t Ar table +.Xo +.Oo Fl t Ar table .Fl T Ar command -.Op Ar address ... -.Oc +.Op Ar address ... Oc +.Xc .Op Fl x Ar level .Ek .Sh DESCRIPTION @@ -85,7 +88,7 @@ When the variable is set to .Dv YES in -.Xr rc.conf.local 5 , +.Xr rc.conf.local 8 , the rule file specified with the variable .Va pf_rules is loaded automatically by the @@ -211,7 +214,7 @@ Flush the NAT rules. Flush the queue rules. .It Fl F Cm rules Flush the filter rules. -.It Fl F Cm state +.It Fl F Cm states Flush the state table (NAT and filter). .It Fl F Cm Sources Flush the source tracking table. @@ -251,22 +254,28 @@ 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 Fl k Ar host | network -Kill all of the state entries originating from the specified -.Ar host +.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 network . +.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. -For example, to kill all of the state entries originating from -.Dq host : -.Pp -.Dl # pfctl -k host -.Pp To kill all of the state entries from .Dq host1 to @@ -283,6 +292,32 @@ 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. @@ -298,58 +333,20 @@ 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 Op Ar level -Control the ruleset optimizer. -The ruleset optimizer attempts to improve rulesets by removing rule -duplication and making better use of rule ordering. +.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 -.Pp -.Cm basic -optimization does does four things: -.Pp -.Bl -enum -compact -.It -remove duplicate rules -.It -remove rules that are a subset of another rule -.It -combine multiple rules into a table when advantageous -.It -re-order the rules to improve evaluation performance -.El -.Pp -If -.Cm profile -is specified, the currently loaded ruleset will be examined as a feedback -profile to tailor the optimization of the -.Ar quick -rules to the actual network behavior. -.Pp -It is important to note that the ruleset optimizer will modify the ruleset -to improve performance. -A side effect of the ruleset modification is that per-rule accounting -statistics will have different meanings than before. -If per-rule accounting is important for billing purposes or whatnot, either -the ruleset optimizer should not be used or a -.Ar label -field should be added to all of the accounting rules to act as optimization -barriers. -.Pp -To retain compatibility with previous behaviour, a single -.Fl o -without any options will enable -.Cm basic -optimizations, and a second -.Fl o -will enable profiling. +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. @@ -407,7 +404,7 @@ If .Fl v is specified, all anchors attached under the target anchor will be displayed recursively. -.It Fl s Cm state +.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. @@ -418,7 +415,7 @@ When used together with 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) of +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. @@ -529,7 +526,7 @@ attributes. The address/network has been cleared (statistics). .El .Pp -Each table maintains a set of counters that can be retrieved using the +Each table can maintain a set of counters that can be retrieved using the .Fl v flag of .Nm . @@ -540,7 +537,7 @@ FTP server. The following commands configure the firewall and send 10 pings to the FTP server: .Bd -literal -offset indent -# printf "table <test> { ftp.openbsd.org }\en \e +# printf "table <test> counters { ftp.openbsd.org }\en \e pass out to <test>\en" | pfctl -f- # ping -qc10 ftp.openbsd.org .Ed @@ -574,7 +571,7 @@ 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- test +--a-r-C test Addresses: 1 Cleared: Thu Feb 13 18:55:18 2003 References: [ Anchors: 0 Rules: 1 ] @@ -634,6 +631,8 @@ 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. diff --git a/contrib/pf/pfctl/pfctl.c b/contrib/pf/pfctl/pfctl.c index e76261b..8b07a2b 100644 --- a/contrib/pf/pfctl/pfctl.c +++ b/contrib/pf/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.262 2007/03/01 17:20:53 deraadt Exp $ */ +/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -39,6 +39,10 @@ __FBSDID("$FreeBSD$"); #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> @@ -59,10 +63,6 @@ __FBSDID("$FreeBSD$"); #include "pfctl_parser.h" #include "pfctl.h" -#ifdef __FreeBSD__ -#define HTONL(x) (x) = htonl((__uint32_t)(x)) -#endif - void usage(void); int pfctl_enable(int, int); int pfctl_disable(int, int); @@ -75,7 +75,9 @@ 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_kill_states(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); @@ -126,8 +128,6 @@ int dev = -1; int first_title = 1; int labels = 0; -const char *infile; - #define INDENT(d, o) do { \ if (o) { \ int i; \ @@ -208,11 +208,11 @@ static const struct { static const char *clearopt_list[] = { "nat", "queue", "rules", "Sources", - "state", "info", "Tables", "osfp", "all", NULL + "states", "info", "Tables", "osfp", "all", NULL }; static const char *showopt_list[] = { - "nat", "queue", "rules", "Anchors", "Sources", "state", "info", + "nat", "queue", "rules", "Anchors", "Sources", "states", "info", "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", "all", NULL }; @@ -227,7 +227,7 @@ static const char *debugopt_list[] = { }; static const char *optiopt_list[] = { - "o", "none", "basic", "profile", NULL + "none", "basic", "profile", NULL }; void @@ -237,10 +237,11 @@ usage(void) 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] "); - fprintf(stderr, "[-k host | network ]\n"); - fprintf(stderr, "\t[-o [level]] [-p device] [-s modifier ]\n"); - fprintf(stderr, "\t[-t table -T command [address ...]] [-x level]\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); } @@ -389,7 +390,7 @@ pfctl_clear_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCCLRSTATES, &psk)) err(1, "DIOCCLRSTATES"); if ((opts & PF_OPT_QUIET) == 0) - fprintf(stderr, "%d states cleared\n", psk.psk_af); + fprintf(stderr, "%d states cleared\n", psk.psk_killed); return (0); } @@ -528,17 +529,13 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = resp[1]->ai_family; + killed += psnk.psnk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) err(1, "DIOCKILLSRCNODES"); - killed += psnk.psnk_af; - /* fixup psnk.psnk_af */ - psnk.psnk_af = res[0]->ai_family; + killed += psnk.psnk_killed; } } @@ -551,7 +548,7 @@ pfctl_kill_src_nodes(int dev, const char *iface, int opts) } int -pfctl_kill_states(int dev, const char *iface, int opts) +pfctl_net_kill_states(int dev, const char *iface, int opts) { struct pfioc_state_kill psk; struct addrinfo *res[2], *resp[2]; @@ -638,17 +635,13 @@ pfctl_kill_states(int dev, const char *iface, int opts) if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = resp[1]->ai_family; + killed += psk.psk_killed; } freeaddrinfo(res[1]); } else { if (ioctl(dev, DIOCKILLSTATES, &psk)) err(1, "DIOCKILLSTATES"); - killed += psk.psk_af; - /* fixup psk.psk_af */ - psk.psk_af = res[0]->ai_family; + killed += psk.psk_killed; } } @@ -661,6 +654,68 @@ pfctl_kill_states(int dev, const char *iface, int opts) } 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) { @@ -747,10 +802,12 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts) (unsigned long long)(rule->packets[0] + rule->packets[1]), (unsigned long long)(rule->bytes[0] + - rule->bytes[1]), rule->states); + rule->bytes[1]), rule->states_cur); if (!(opts & PF_OPT_DEBUG)) - printf(" [ Inserted: uid %u pid %u ]\n", - (unsigned)rule->cuid, (unsigned)rule->cpid); + printf(" [ Inserted: uid %u pid %u " + "State Creations: %-6u]\n", + (unsigned)rule->cuid, (unsigned)rule->cpid, + rule->states_tot); } } @@ -818,19 +875,6 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: - if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", - (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]); - } break; case PFCTL_SHOW_RULES: if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) @@ -864,8 +908,9 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, switch (format) { case PFCTL_SHOW_LABELS: if (pr.rule.label[0]) { - printf("%s ", pr.rule.label); - printf("%llu %llu %llu %llu %llu %llu %llu\n", + 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]), @@ -874,7 +919,8 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, (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.bytes[1], + (unsigned long long)pr.rule.states_tot); } break; case PFCTL_SHOW_RULES: @@ -967,7 +1013,7 @@ pfctl_show_src_nodes(int dev, int opts) struct pfioc_src_nodes psn; struct pf_src_node *p; char *inbuf = NULL, *newinbuf = NULL; - unsigned len = 0; + unsigned int len = 0; int i; memset(&psn, 0, sizeof(psn)); @@ -1010,9 +1056,9 @@ int pfctl_show_states(int dev, const char *iface, int opts) { struct pfioc_states ps; - struct pf_state *p; + struct pfsync_state *p; char *inbuf = NULL, *newinbuf = NULL; - unsigned len = 0; + unsigned int len = 0; int i, dotitle = (opts & PF_OPT_SHOWALL); memset(&ps, 0, sizeof(ps)); @@ -1041,7 +1087,7 @@ pfctl_show_states(int dev, const char *iface, int opts) } p = ps.ps_states; for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { - if (iface != NULL && strcmp(p->u.ifname, iface)) + if (iface != NULL && strcmp(p->ifname, iface)) continue; if (dotitle) { pfctl_print_title("STATES:"); @@ -1163,7 +1209,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) 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"); + errx(1, "pfctl_add_rule: strlcpy"); if ((p = strrchr(anchor_call, '/')) != NULL) { if (!strlen(p)) err(1, "pfctl_add_rule: bad anchor name %s", @@ -1172,7 +1218,7 @@ pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) p = (char *)anchor_call; if (strlcpy(r->anchor->name, p, sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) - errx(1, "pfctl_add_rule: strlcpy"); + errx(1, "pfctl_add_rule: strlcpy"); } if ((rule = calloc(1, sizeof(*rule))) == NULL) @@ -1197,7 +1243,7 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) return (1); } if (a == pf->astack[0] && ((altqsupport && - (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { + (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) return (2); } @@ -1350,7 +1396,7 @@ pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) } int -pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, +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) @@ -1386,7 +1432,6 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, if (strlcpy(trs.pfrt_anchor, anchorname, sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) ERRX("pfctl_rules: strlcpy"); - infile = filename; pf.dev = dev; pf.opts = opts; pf.optimize = optimize; @@ -1430,7 +1475,7 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); } - if (parse_rules(fin, &pf) < 0) { + if (parse_config(filename, &pf) < 0) { if ((opts & PF_OPT_NOACTION) == 0) ERRX("Syntax error in config file: " "pf rules not loaded"); @@ -1456,11 +1501,6 @@ pfctl_rules(int dev, char *filename, FILE *fin, int opts, int optimize, if (check_commit_altq(dev, opts) != 0) ERRX("errors in altq config"); - if (fin != stdin) { - fclose(fin); - fin = NULL; - } - /* process "load anchor" directives */ if (!anchorname[0]) if (pfctl_load_anchors(dev, &pf, t) == -1) @@ -1482,8 +1522,6 @@ _error: err(1, "DIOCXROLLBACK"); exit(1); } else { /* sub ruleset */ - if (fin != NULL && fin != stdin) - fclose(fin); return (-1); } @@ -1515,7 +1553,8 @@ pfctl_fopen(const char *name, const char *mode) void pfctl_init_options(struct pfctl *pf) { - int mib[2], mem; + int64_t mem; + int mib[2]; size_t size; pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; @@ -1546,9 +1585,14 @@ pfctl_init_options(struct pfctl *pf) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; mib[0] = CTL_HW; +#ifdef __FreeBSD__ mib[1] = HW_PHYSMEM; +#else + mib[1] = HW_PHYSMEM64; +#endif size = sizeof(mem); - (void) sysctl(mib, 2, &mem, &size, NULL, 0); + if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) + err(1, "sysctl"); if (mem <= 100*1024*1024) pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; @@ -1572,7 +1616,7 @@ pfctl_load_options(struct pfctl *pf) } /* - * If we've set the limit, but havn't explicitly set adaptive + * 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] && @@ -1897,9 +1941,6 @@ pfctl_debug(int dev, u_int32_t level, int opts) int pfctl_test_altqsupport(int dev, int opts) { -#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) - return (0); -#else struct pfioc_altq pa; if (ioctl(dev, DIOCGETALTQS, &pa)) { @@ -1912,7 +1953,6 @@ pfctl_test_altqsupport(int dev, int opts) err(1, "DIOCGETALTQS"); } return (1); -#endif } int @@ -1971,16 +2011,15 @@ main(int argc, char *argv[]) int ch; int mode = O_RDONLY; int opts = 0; - int optimize = 0; + int optimize = PF_OPTIMIZE_BASIC; char anchorname[MAXPATHLEN]; char *path; - FILE *fin = NULL; if (argc < 2) usage(); while ((ch = getopt(argc, argv, - "a:AdD:eqf:F:ghi:k:K:mnNOo::Pp:rRs:t:T:vx:z")) != -1) { + "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) { switch (ch) { case 'a': anchoropt = optarg; @@ -2056,24 +2095,11 @@ main(int argc, char *argv[]) loadopt |= PFCTL_FLAG_FILTER; break; case 'o': - if (optarg) { - optiopt = pfctl_lookup_option(optarg, - optiopt_list); - if (optiopt == NULL) { - warnx("Unknown optimization '%s'", - optarg); - usage(); - } - } - if (opts & PF_OPT_OPTIMIZE) { - if (optiopt != NULL) { - warnx("Cannot specify -o multiple times" - "with optimizer level"); - usage(); - } - optimize |= PF_OPTIMIZE_PROFILE; + optiopt = pfctl_lookup_option(optarg, optiopt_list); + if (optiopt == NULL) { + warnx("Unknown optimization '%s'", optarg); + usage(); } - optimize |= PF_OPTIMIZE_BASIC; opts |= PF_OPT_OPTIMIZE; break; case 'O': @@ -2303,8 +2329,14 @@ main(int argc, char *argv[]) break; } } - if (state_killers) - pfctl_kill_states(dev, ifaceopt, opts); + if (state_killers) { + if (!strcmp(state_kill[0], "label")) + pfctl_label_kill_states(dev, ifaceopt, opts); + else if (!strcmp(state_kill[0], "id")) + pfctl_id_kill_states(dev, ifaceopt, opts); + else + pfctl_net_kill_states(dev, ifaceopt, opts); + } if (src_node_killers) pfctl_kill_src_nodes(dev, ifaceopt, opts); @@ -2329,15 +2361,6 @@ main(int argc, char *argv[]) } } - if (rulesopt != NULL) { - if (strcmp(rulesopt, "-") == 0) { - fin = stdin; - rulesopt = "stdin"; - } else { - if ((fin = pfctl_fopen(rulesopt, "r")) == NULL) - err(1, "%s", rulesopt); - } - } if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && !anchorname[0]) if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) @@ -2352,7 +2375,7 @@ main(int argc, char *argv[]) if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) errx(1, "anchor names beginning with '_' cannot " "be modified from the command line"); - if (pfctl_rules(dev, rulesopt, fin, opts, optimize, + if (pfctl_rules(dev, rulesopt, opts, optimize, anchorname, NULL)) error = 1; else if (!(opts & PF_OPT_NOACTION) && diff --git a/contrib/pf/pfctl/pfctl.h b/contrib/pf/pfctl/pfctl.h index 98a1bef..2c69bc2 100644 --- a/contrib/pf/pfctl/pfctl.h +++ b/contrib/pf/pfctl/pfctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.h,v 1.40 2007/02/09 11:25:27 henning Exp $ */ +/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -49,7 +49,6 @@ struct pfr_buffer { (var) != NULL; \ (var) = pfr_buf_next((buf), (var))) -void pfr_set_fd(int); int pfr_get_fd(void); int pfr_clr_tables(struct pfr_table *, int *, int); int pfr_add_tables(struct pfr_table *, int, int *, int); @@ -64,9 +63,7 @@ int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int *, int *, int *, int); int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int); int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int); -int pfr_clr_astats(struct pfr_table *, struct pfr_addr *, int, int *, int); int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); -int pfr_set_tflags(struct pfr_table *, int, int, int, int *, int *, int); int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, int *, int, int); void pfr_buf_clear(struct pfr_buffer *); @@ -91,6 +88,8 @@ FILE *pfctl_fopen(const char *, const char *); #ifdef __FreeBSD__ extern int altqsupport; +extern int dummynetsupport; +#define HTONL(x) (x) = htonl((__uint32_t)(x)) #endif #ifndef DEFAULT_PRIORITY @@ -117,9 +116,9 @@ struct pf_altq *pfaltq_lookup(const char *); char *rate2str(double); void print_addr(struct pf_addr_wrap *, sa_family_t, int); -void print_host(struct pf_state_host *, sa_family_t, int); -void print_seq(struct pf_state_peer *); -void print_state(struct pf_state *, int); +void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int); +void print_seq(struct pfsync_state_peer *); +void print_state(struct pfsync_state *, int); int unmask(struct pf_addr *, sa_family_t); int pfctl_cmdline_symset(char *); diff --git a/contrib/pf/pfctl/pfctl_altq.c b/contrib/pf/pfctl/pfctl_altq.c index b90e7c6..40e11d5 100644 --- a/contrib/pf/pfctl/pfctl_altq.c +++ b/contrib/pf/pfctl/pfctl_altq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_altq.c,v 1.91 2006/11/28 00:08:50 henning Exp $ */ +/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ /* * Copyright (c) 2002 @@ -21,7 +21,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> +#include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -78,7 +78,7 @@ static int gsc_add_seg(struct gen_sc *, double, double, double, static double sc_x2y(struct service_curve *, double); #ifdef __FreeBSD__ -u_int32_t getifspeed(int, char *); +u_int32_t getifspeed(int, char *); #else u_int32_t getifspeed(char *); #endif @@ -145,8 +145,8 @@ qname_to_qid(const char *qname) } void -print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, - struct node_queue_opt *qopts) +print_altq(const struct pf_altq *a, unsigned int level, + struct node_queue_bw *bw, struct node_queue_opt *qopts) { if (a->qname[0] != 0) { print_queue(a, level, bw, 1, qopts); @@ -157,6 +157,7 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) printf("INACTIVE "); #endif + printf("altq on %s ", a->ifname); switch (a->scheduler) { @@ -186,10 +187,11 @@ print_altq(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, } void -print_queue(const struct pf_altq *a, unsigned level, struct node_queue_bw *bw, - int print_interface, struct node_queue_opt *qopts) +print_queue(const struct pf_altq *a, unsigned int level, + struct node_queue_bw *bw, int print_interface, + struct node_queue_opt *qopts) { - unsigned i; + unsigned int i; #ifdef __FreeBSD__ if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) @@ -893,9 +895,6 @@ print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) /* * admission control using generalized service curve */ -#ifndef INFINITY -#define INFINITY HUGE_VAL /* positive infinity defined in <math.h> */ -#endif /* add a new service curve to a generalized service curve */ static void @@ -1132,8 +1131,6 @@ getifspeed(char *ifname) ifr.ifr_data = (caddr_t)&ifrdat; if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) err(1, "SIOCGIFDATA"); - if (shutdown(s, SHUT_RDWR) == -1) - err(1, "shutdown"); if (close(s)) err(1, "close"); return ((u_int32_t)ifrdat.ifi_baudrate); @@ -1158,8 +1155,6 @@ getifmtu(char *ifname) #else err(1, "SIOCGIFMTU"); #endif - if (shutdown(s, SHUT_RDWR) == -1) - err(1, "shutdown"); if (close(s)) err(1, "close"); if (ifr.ifr_mtu > 0) diff --git a/contrib/pf/pfctl/pfctl_optimize.c b/contrib/pf/pfctl/pfctl_optimize.c index 0514e81..9511720 100644 --- a/contrib/pf/pfctl/pfctl_optimize.c +++ b/contrib/pf/pfctl/pfctl_optimize.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_optimize.c,v 1.13 2006/10/31 14:17:45 mcbride Exp $ */ +/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */ /* * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> @@ -185,7 +185,8 @@ struct pf_rule_field { PF_RULE_FIELD(packets, DC), PF_RULE_FIELD(bytes, DC), PF_RULE_FIELD(kif, DC), - PF_RULE_FIELD(states, DC), + PF_RULE_FIELD(states_cur, DC), + PF_RULE_FIELD(states_tot, DC), PF_RULE_FIELD(src_nodes, DC), PF_RULE_FIELD(nr, DC), PF_RULE_FIELD(entries, DC), @@ -201,6 +202,7 @@ struct pf_rule_field { PF_RULE_FIELD(natpass, NEVER), PF_RULE_FIELD(max_mss, NEVER), PF_RULE_FIELD(min_ttl, NEVER), + PF_RULE_FIELD(set_tos, NEVER), }; @@ -398,7 +400,7 @@ optimize_superblock(struct pfctl *pf, struct superblock *block) * out rules. */ - /* shortcut. there will be alot of 1-rule superblocks */ + /* shortcut. there will be a lot of 1-rule superblocks */ if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry)) return (0); @@ -1320,8 +1322,9 @@ again: if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, - pf->anchor->name, tbl->pt_buf, pf->anchor->ruleset.tticket)) { - warn("failed to create table %s", tbl->pt_name); + pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) { + warn("failed to create table %s in %s", + tbl->pt_name, pf->astack[0]->name); return (1); } return (0); @@ -1424,7 +1427,7 @@ superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) return (0); /* - * Have to handle interface groups seperately. Consider the following + * Have to handle interface groups separately. Consider the following * rules: * block on EXTIFS to any port 22 * pass on em0 to any port 22 diff --git a/contrib/pf/pfctl/pfctl_osfp.c b/contrib/pf/pfctl/pfctl_osfp.c index 7018d6c..df78981 100644 --- a/contrib/pf/pfctl/pfctl_osfp.c +++ b/contrib/pf/pfctl/pfctl_osfp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_osfp.c,v 1.15 2006/12/13 05:10:15 itojun Exp $ */ +/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> diff --git a/contrib/pf/pfctl/pfctl_parser.c b/contrib/pf/pfctl/pfctl_parser.c index 7dc0c59..d45b9b7 100644 --- a/contrib/pf/pfctl/pfctl_parser.c +++ b/contrib/pf/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.234 2006/10/31 23:46:24 mcbride Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <string.h> #include <ctype.h> -#include <limits.h> #include <netdb.h> #include <stdarg.h> #include <errno.h> @@ -500,7 +499,7 @@ print_status(struct pf_status *s, int opts) running = s->running ? "Enabled" : "Disabled"; if (s->since) { - unsigned sec, min, hrs, day = runtime; + unsigned int sec, min, hrs, day = runtime; sec = day % 60; day /= 60; @@ -581,7 +580,11 @@ print_status(struct pf_status *s, int opts) s->src_nodes, ""); for (i = 0; i < SCNT_MAX; i++) { printf(" %-25s %14lld ", pf_scounters[i], - (unsigned long long)s->scounters[i]); +#ifdef __FreeBSD__ + (long long)s->scounters[i]); +#else + s->scounters[i]); +#endif if (runtime > 0) printf("%14.1f/s\n", (double)s->scounters[i] / (double)runtime); @@ -952,6 +955,12 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) printf("sloppy"); opts = 0; } + if (r->rule_flag & PFRULE_PFLOW) { + if (!opts) + printf(", "); + printf("pflow"); + opts = 0; + } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; @@ -979,6 +988,8 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) printf(" min-ttl %d", r->min_ttl); if (r->max_mss) printf(" max-mss %d", r->max_mss); + if (r->rule_flag & PFRULE_SET_TOS) + printf(" set-tos 0x%2.2x", r->set_tos); if (r->allow_opts) printf(" allow-opts"); if (r->action == PF_SCRUB) { @@ -1007,6 +1018,26 @@ print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) } if (r->rtableid != -1) printf(" rtable %u", r->rtableid); + if (r->divert.port) { +#ifdef __FreeBSD__ + printf(" divert-to %u", ntohs(r->divert.port)); +#else + if (PF_AZERO(&r->divert.addr, r->af)) { + printf(" divert-reply"); + } else { + /* XXX cut&paste from print_addr */ + char buf[48]; + + printf(" divert-to "); + if (inet_ntop(r->af, &r->divert.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + printf(" port %u", ntohs(r->divert.port)); + } +#endif + } if (!anchor_call[0] && (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR)) { printf(" -> "); @@ -1027,6 +1058,8 @@ print_tabledef(const char *name, int flags, int addrs, printf(" const"); if (flags & PFR_TFLAG_PERSIST) printf(" persist"); + if (flags & PFR_TFLAG_COUNTERS) + printf(" counters"); SIMPLEQ_FOREACH(ti, nodes, entries) { if (ti->file) { printf(" file \"%s\"", ti->file); diff --git a/contrib/pf/pfctl/pfctl_parser.h b/contrib/pf/pfctl/pfctl_parser.h index ab9017e..4560d66 100644 --- a/contrib/pf/pfctl/pfctl_parser.h +++ b/contrib/pf/pfctl/pfctl_parser.h @@ -172,10 +172,10 @@ struct node_queue_opt { #define SIMPLEQ_END(head) NULL #define SIMPLEQ_EMPTY STAILQ_EMPTY #define SIMPLEQ_NEXT STAILQ_NEXT -/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/ -#define SIMPLEQ_FOREACH(var, head, field) \ - for((var) = SIMPLEQ_FIRST(head); \ - (var) != SIMPLEQ_END(head); \ +/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/ +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ (var) = SIMPLEQ_NEXT(var, field)) #define SIMPLEQ_INIT STAILQ_INIT #define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD @@ -213,7 +213,7 @@ struct pf_opt_rule { TAILQ_HEAD(pf_opt_queue, pf_opt_rule); -int pfctl_rules(int, char *, FILE *, int, int, char *, struct pfr_buffer *); +int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *); int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); @@ -230,7 +230,7 @@ int pfctl_set_hostid(struct pfctl *, u_int32_t); int pfctl_set_debug(struct pfctl *, char *); int pfctl_set_interface_flags(struct pfctl *, char *, int, int); -int parse_rules(FILE *, struct pfctl *); +int parse_config(char *, struct pfctl *); int parse_flags(char *); int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); diff --git a/contrib/pf/pfctl/pfctl_qstats.c b/contrib/pf/pfctl/pfctl_qstats.c index d4089d6..95371e4 100644 --- a/contrib/pf/pfctl/pfctl_qstats.c +++ b/contrib/pf/pfctl/pfctl_qstats.c @@ -73,7 +73,7 @@ void pfctl_insert_altq_node(struct pf_altq_node **, struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *, const char *, const char *); void pfctl_print_altq_node(int, const struct pf_altq_node *, - unsigned, int); + unsigned, int); void print_cbqstats(struct queue_stats); void print_priqstats(struct queue_stats); void print_hfscstats(struct queue_stats); @@ -185,8 +185,8 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) } } #ifdef __FreeBSD__ - else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { - memset(&qstats.data, 0, sizeof(qstats.data)); + else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { + memset(&qstats.data, 0, sizeof(qstats.data)); if ((node = pfctl_find_altq_node(*root, pa.altq.qname, pa.altq.ifname)) != NULL) { memcpy(&node->qstats.data, &qstats.data, @@ -194,7 +194,7 @@ pfctl_update_qstats(int dev, struct pf_altq_node **root) update_avg(node); } else { pfctl_insert_altq_node(root, pa.altq, qstats); - } + } } #endif } @@ -262,8 +262,8 @@ pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, } void -pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level, - int opts) +pfctl_print_altq_node(int dev, const struct pf_altq_node *node, + unsigned int level, int opts) { const struct pf_altq_node *child; @@ -302,11 +302,11 @@ pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) { if (a->altq.qid == 0) return; + #ifdef __FreeBSD__ if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) return; #endif - switch (a->altq.scheduler) { case ALTQT_CBQ: print_cbqstats(a->qstats); diff --git a/contrib/pf/pfctl/pfctl_radix.c b/contrib/pf/pfctl/pfctl_radix.c index 01ad475..38f16c4 100644 --- a/contrib/pf/pfctl/pfctl_radix.c +++ b/contrib/pf/pfctl/pfctl_radix.c @@ -30,6 +30,9 @@ * */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -300,29 +303,6 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, } int -pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *nzero, int flags) -{ - struct pfioc_table io; - - if (tbl == NULL || size < 0 || (size && addr == NULL)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_table = *tbl; - io.pfrio_buffer = addr; - io.pfrio_esize = sizeof(*addr); - io.pfrio_size = size; - if (ioctl(dev, DIOCRCLRASTATS, &io)) - return (-1); - if (nzero != NULL) - *nzero = io.pfrio_nzero; - return (0); -} - -int pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfioc_table io; @@ -344,32 +324,6 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) } int -pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, - int *nchange, int *ndel, int flags) -{ - struct pfioc_table io; - - if (size < 0 || (size && !tbl)) { - errno = EINVAL; - return (-1); - } - bzero(&io, sizeof io); - io.pfrio_flags = flags; - io.pfrio_buffer = tbl; - io.pfrio_esize = sizeof(*tbl); - io.pfrio_size = size; - io.pfrio_setflag = setflag; - io.pfrio_clrflag = clrflag; - if (ioctl(dev, DIOCRSETTFLAGS, &io)) - return (-1); - if (nchange) - *nchange = io.pfrio_nchange; - if (ndel) - *ndel = io.pfrio_ndel; - return (0); -} - -int pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, int *nmatch, int flags) { diff --git a/contrib/pf/pfctl/pfctl_table.c b/contrib/pf/pfctl/pfctl_table.c index 3d54466..257c014 100644 --- a/contrib/pf/pfctl/pfctl_table.c +++ b/contrib/pf/pfctl/pfctl_table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_table.c,v 1.66 2007/03/01 17:20:54 deraadt Exp $ */ +/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -275,12 +275,14 @@ pfctl_table(int argc, char *argv[], char *tname, const char *command, if (b.pfrb_size <= b.pfrb_msize) break; } - PFRB_FOREACH(p, &b) + PFRB_FOREACH(p, &b) { + ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > - lifetime) + lifetime) if (pfr_buf_add(&b2, &((struct pfr_astats *)p)->pfras_a)) err(1, "duplicate buffer"); + } if (opts & PF_OPT_VERBOSE) flags |= PFR_FLAG_FEEDBACK; @@ -367,13 +369,14 @@ print_table(struct pfr_table *ta, int verbose, int debug) if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) return; if (verbose) { - printf("%c%c%c%c%c%c\t%s", + printf("%c%c%c%c%c%c%c\t%s", (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', + (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', ta->pfrt_name); if (ta->pfrt_anchor[0]) printf("\t%s", ta->pfrt_anchor); @@ -428,7 +431,7 @@ void print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) { char ch, buf[256] = "{error}"; - char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y' }; + char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; unsigned int fback, hostnet; fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; @@ -477,6 +480,8 @@ print_astats(struct pfr_astats *as, int dns) print_addrx(&as->pfras_a, NULL, dns); printf("\tCleared: %s", ctime(&time)); + if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) + return; for (dir = 0; dir < PFR_DIR_MAX; dir++) for (op = 0; op < PFR_OP_ADDR_MAX; op++) printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", diff --git a/contrib/pf/pflogd/pflogd.8 b/contrib/pf/pflogd/pflogd.8 index 22643fc..38c954c 100644 --- a/contrib/pf/pflogd/pflogd.8 +++ b/contrib/pf/pflogd/pflogd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pflogd.8,v 1.32 2006/12/08 10:26:38 joel Exp $ +.\" $OpenBSD: pflogd.8,v 1.37 2008/10/22 08:16:49 henning Exp $ .\" .\" Copyright (c) 2001 Can Erkin Acar. All rights reserved. .\" @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 9, 2001 +.Dd October 22 2008 .Dt PFLOGD 8 .Os .Sh NAME @@ -34,12 +34,14 @@ .Nd packet filter logging daemon .Sh SYNOPSIS .Nm pflogd +.Bk -words .Op Fl Dx .Op Fl d Ar delay .Op Fl f Ar filename .Op Fl i Ar interface .Op Fl s Ar snaplen .Op Ar expression +.Ek .Sh DESCRIPTION .Nm is a background daemon which reads packets logged by @@ -94,6 +96,13 @@ or a .Dv SIGALRM is received. .Pp +.Nm +will also log the pcap statistics for the +.Xr pflog 4 +interface to syslog when a +.Dv SIGUSR1 +is received. +.Pp The options are as follows: .Bl -tag -width Ds .It Fl D @@ -116,6 +125,11 @@ By default, .Nm will use .Ar pflog0 . +Writes a file containing the process ID of the program to +.Pa /var/run . +The file name has the form +The default is +.Ar pflogd . .It Fl s Ar snaplen Analyze at most the first .Ar snaplen @@ -204,12 +218,12 @@ the wi0 interface: # tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0 .Ed .Sh SEE ALSO -.Xr tcpdump 1 , .Xr pcap 3 , .Xr pf 4 , .Xr pflog 4 , .Xr pf.conf 5 , -.Xr newsyslog 8 +.Xr newsyslog 8 , +.Xr tcpdump 1 .Sh HISTORY The .Nm diff --git a/contrib/pf/pflogd/pflogd.c b/contrib/pf/pflogd/pflogd.c index b470ae1..2fc2338 100644 --- a/contrib/pf/pflogd/pflogd.c +++ b/contrib/pf/pflogd/pflogd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pflogd.c,v 1.37 2006/10/26 13:34:47 jmc Exp $ */ +/* $OpenBSD: pflogd.c,v 1.46 2008/10/22 08:16:49 henning Exp $ */ /* * Copyright (c) 2001 Theo de Raadt @@ -37,9 +37,8 @@ __FBSDID("$FreeBSD$"); #include <sys/ioctl.h> #include <sys/file.h> #include <sys/stat.h> -#ifdef __FreeBSD__ -#include <net/bpf.h> /* BIOCLOCK */ -#endif +#include <sys/socket.h> +#include <net/if.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -48,15 +47,16 @@ __FBSDID("$FreeBSD$"); #include <pcap.h> #include <syslog.h> #include <signal.h> +#include <err.h> #include <errno.h> #include <stdarg.h> #include <fcntl.h> #ifdef __FreeBSD__ +#include <ifaddrs.h> #include "pidfile.h" #else #include <util.h> #endif - #include "pflogd.h" pcap_t *hpcap; @@ -66,7 +66,7 @@ int Debug = 0; static int snaplen = DEF_SNAPLEN; static int cur_snaplen = DEF_SNAPLEN; -volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup; +volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1; char *filename = PFLOGD_LOG_FILE; char *interface = PFLOGD_DEFAULT_IF; @@ -80,7 +80,9 @@ unsigned int delay = FLUSH_DELAY; char *copy_argv(char * const *); void dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *); void dump_packet_nobuf(u_char *, const struct pcap_pkthdr *, const u_char *); +void log_pcap_stats(void); int flush_buffer(FILE *); +int if_exists(char *); int init_pcap(void); void logmsg(int, const char *, ...); void purge_buffer(void); @@ -89,6 +91,7 @@ int scan_dump(FILE *, off_t); int set_snaplen(int); void set_suspended(int); void sig_alrm(int); +void sig_usr1(int); void sig_close(int); void sig_hup(int); void usage(void); @@ -166,8 +169,8 @@ __dead void usage(void) { fprintf(stderr, "usage: pflogd [-Dx] [-d delay] [-f filename]"); - fprintf(stderr, " [-i interface] [-s snaplen]\n"); - fprintf(stderr, " [expression]\n"); + fprintf(stderr, " [-i interface] [-p pidfile]\n"); + fprintf(stderr, " [-s snaplen] [expression]\n"); exit(1); } @@ -190,6 +193,12 @@ sig_alrm(int sig) } void +sig_usr1(int sig) +{ + gotsig_usr1 = 1; +} + +void set_pcap_filter(void) { struct bpf_program bprog; @@ -204,6 +213,51 @@ set_pcap_filter(void) } int +if_exists(char *ifname) +{ +#ifdef __FreeBSD__ + struct ifaddrs *ifdata, *mb; + int exists = 0; + + getifaddrs(&ifdata); + if (ifdata == NULL) + return (0); + + for (mb = ifdata; mb != NULL; mb = mb->ifa_next) { + if (mb == NULL) + continue; + if (strlen(ifname) != strlen(mb->ifa_name)) + continue; + if (strncmp(ifname, mb->ifa_name, strlen(ifname)) != 0) + continue; + exists = 1; + break; + } + freeifaddrs(ifdata); + + return (exists); +#else + int s; + struct ifreq ifr; + struct if_data ifrdat; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + bzero(&ifr, sizeof(ifr)); + if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= + sizeof(ifr.ifr_name)) + errx(1, "main ifr_name: strlcpy"); + ifr.ifr_data = (caddr_t)&ifrdat; + if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) + return (0); + if (close(s)) + err(1, "close"); + + return (1); +#endif +} + +int init_pcap(void) { hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf); @@ -554,10 +608,10 @@ dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) return; } - append: + append: #ifdef __FreeBSD__ - sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec; - sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec; + sh.ts.tv_sec = (bpf_int32)h->ts.tv_sec; + sh.ts.tv_usec = (bpf_int32)h->ts.tv_usec; sh.caplen = h->caplen; sh.len = h->len; @@ -575,17 +629,31 @@ dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp) return; } +void +log_pcap_stats(void) +{ + struct pcap_stat pstat; + if (pcap_stats(hpcap, &pstat) < 0) + logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap)); + else + logmsg(LOG_NOTICE, + "%u packets received, %u/%u dropped (kernel/pflogd)", + pstat.ps_recv, pstat.ps_drop, packets_dropped); +} + int main(int argc, char **argv) { - struct pcap_stat pstat; - int ch, np, Xflag = 0; + int ch, np, ret, Xflag = 0; pcap_handler phandler = dump_packet; const char *errstr = NULL; + char *pidf = NULL; + + ret = 0; closefrom(STDERR_FILENO + 1); - while ((ch = getopt(argc, argv, "Dxd:f:i:s:")) != -1) { + while ((ch = getopt(argc, argv, "Dxd:f:i:p:s:")) != -1) { switch (ch) { case 'D': Debug = 1; @@ -601,6 +669,9 @@ main(int argc, char **argv) case 'i': interface = optarg; break; + case 'p': + pidf = optarg; + break; case 's': snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN, &errstr); @@ -622,13 +693,21 @@ main(int argc, char **argv) argc -= optind; argv += optind; + /* does interface exist */ + if (!if_exists(interface)) { + warn("Failed to initialize: %s", interface); + logmsg(LOG_ERR, "Failed to initialize: %s", interface); + logmsg(LOG_ERR, "Exiting, init failure"); + exit(1); + } + if (!Debug) { openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON); if (daemon(0, 0)) { logmsg(LOG_WARNING, "Failed to become daemon: %s", strerror(errno)); } - pidfile(NULL); + pidfile(pidf); } tzset(); @@ -659,6 +738,7 @@ main(int argc, char **argv) signal(SIGINT, sig_close); signal(SIGQUIT, sig_close); signal(SIGALRM, sig_alrm); + signal(SIGUSR1, sig_usr1); signal(SIGHUP, sig_hup); alarm(delay); @@ -686,13 +766,12 @@ main(int argc, char **argv) np = pcap_dispatch(hpcap, PCAP_NUM_PKTS, phandler, (u_char *)dpcap); if (np < 0) { -#ifdef __FreeBSD__ - if (errno == ENXIO) { - logmsg(LOG_ERR, - "Device not/no longer configured"); + if (!if_exists(interface) == -1) { + logmsg(LOG_NOTICE, "interface %s went away", + interface); + ret = -1; break; } -#endif logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap)); } @@ -715,6 +794,11 @@ main(int argc, char **argv) gotsig_alrm = 0; alarm(delay); } + + if (gotsig_usr1) { + log_pcap_stats(); + gotsig_usr1 = 0; + } } logmsg(LOG_NOTICE, "Exiting"); @@ -724,15 +808,9 @@ main(int argc, char **argv) } purge_buffer(); - if (pcap_stats(hpcap, &pstat) < 0) - logmsg(LOG_WARNING, "Reading stats: %s", pcap_geterr(hpcap)); - else - logmsg(LOG_NOTICE, - "%u packets received, %u/%u dropped (kernel/pflogd)", - pstat.ps_recv, pstat.ps_drop, packets_dropped); - + log_pcap_stats(); pcap_close(hpcap); if (!Debug) closelog(); - return (0); + return (ret); } diff --git a/contrib/pf/pflogd/privsep.c b/contrib/pf/pflogd/privsep.c index a07d141..2e3895d 100644 --- a/contrib/pf/pflogd/privsep.c +++ b/contrib/pf/pflogd/privsep.c @@ -23,6 +23,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> +#include <sys/ioctl.h> #include <net/if.h> #include <net/bpf.h> @@ -31,20 +32,13 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <fcntl.h> #include <limits.h> -#ifndef __FreeBSD__ #include <pcap.h> #include <pcap-int.h> -#endif #include <pwd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#ifdef __FreeBSD__ -/* XXX: pcap pollutes namespace with strlcpy if not present previously */ -#include <pcap.h> -#include <pcap-int.h> -#endif #include <syslog.h> #include <unistd.h> #include "pflogd.h" diff --git a/contrib/pf/pflogd/privsep_fdpass.c b/contrib/pf/pflogd/privsep_fdpass.c index 50afdfc..0e6c3c4 100644 --- a/contrib/pf/pflogd/privsep_fdpass.c +++ b/contrib/pf/pflogd/privsep_fdpass.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep_fdpass.c,v 1.2 2004/08/13 02:51:48 djm Exp $ */ +/* $OpenBSD: privsep_fdpass.c,v 1.5 2008/03/24 16:11:08 deraadt Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -50,7 +50,10 @@ void send_fd(int sock, int fd) { struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; struct cmsghdr *cmsg; struct iovec vec; int result = 0; @@ -59,8 +62,8 @@ send_fd(int sock, int fd) memset(&msg, 0, sizeof(msg)); if (fd >= 0) { - msg.msg_control = (caddr_t)tmp; - msg.msg_controllen = CMSG_LEN(sizeof(int)); + msg.msg_control = (caddr_t)&cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; @@ -86,7 +89,10 @@ int receive_fd(int sock) { struct msghdr msg; - char tmp[CMSG_SPACE(sizeof(int))]; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; struct cmsghdr *cmsg; struct iovec vec; ssize_t n; @@ -98,8 +104,8 @@ receive_fd(int sock) vec.iov_len = sizeof(int); msg.msg_iov = &vec; msg.msg_iovlen = 1; - msg.msg_control = tmp; - msg.msg_controllen = sizeof(tmp); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); if ((n = recvmsg(sock, &msg, 0)) == -1) warn("%s: recvmsg", __func__); diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c index 2a5fea2..1c98262 100644 --- a/contrib/traceroute/traceroute.c +++ b/contrib/traceroute/traceroute.c @@ -1618,7 +1618,7 @@ gethostinfo(register char *hostname) register char **p; register u_int32_t addr, *ap; - if (strlen(hostname) > 64) { + if (strlen(hostname) >= MAXHOSTNAMELEN) { Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", prog, hostname); exit(1); diff --git a/contrib/tzdata/antarctica b/contrib/tzdata/antarctica index 629b2d7..d19fbde 100644 --- a/contrib/tzdata/antarctica +++ b/contrib/tzdata/antarctica @@ -1,5 +1,5 @@ # <pre> -# @(#)antarctica 8.8 +# @(#)antarctica 8.9 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. @@ -19,18 +19,6 @@ # I made up all time zone abbreviations mentioned here; corrections welcome! # FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited. -# These rules are stolen from the `europe' file. -# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S -Rule RussAQ 1981 1984 - Apr 1 0:00 1:00 S -Rule RussAQ 1981 1983 - Oct 1 0:00 0 - -Rule RussAQ 1984 1991 - Sep lastSun 2:00s 0 - -Rule RussAQ 1985 1991 - Mar lastSun 2:00s 1:00 S -Rule RussAQ 1992 only - Mar lastSat 23:00 1:00 S -Rule RussAQ 1992 only - Sep lastSat 23:00 0 - -Rule RussAQ 1993 max - Mar lastSun 2:00s 1:00 S -Rule RussAQ 1993 1995 - Sep lastSun 2:00s 0 - -Rule RussAQ 1996 max - Oct lastSun 2:00s 0 - - # These rules are stolen from the `southamerica' file. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule ArgAQ 1964 1966 - Mar 1 0:00 0 - diff --git a/contrib/tzdata/asia b/contrib/tzdata/asia index d415ba8..1fc61f0 100644 --- a/contrib/tzdata/asia +++ b/contrib/tzdata/asia @@ -1,4 +1,4 @@ -# @(#)asia 8.64 +# @(#)asia 8.65 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. @@ -77,6 +77,10 @@ Rule RussiaAsia 1993 max - Mar lastSun 2:00s 1:00 S Rule RussiaAsia 1993 1995 - Sep lastSun 2:00s 0 - Rule RussiaAsia 1996 max - Oct lastSun 2:00s 0 - +# From Arthur David Olson (2011-06-15): +# While Russia abandoned DST in 2011, Armenia may choose to +# follow Russia's "old" rules. + # Afghanistan # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Kabul 4:36:48 - LMT 1890 diff --git a/contrib/tzdata/europe b/contrib/tzdata/europe index f7fc189..aab6833 100644 --- a/contrib/tzdata/europe +++ b/contrib/tzdata/europe @@ -1,5 +1,5 @@ # <pre> -# @(#)europe 8.32 +# @(#)europe 8.33 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. @@ -565,6 +565,26 @@ Rule Russia 1993 max - Mar lastSun 2:00s 1:00 S Rule Russia 1993 1995 - Sep lastSun 2:00s 0 - Rule Russia 1996 max - Oct lastSun 2:00s 0 - +# From Alexander Krivenyshev (2011-06-14): +# According to Kremlin press service, Russian President Dmitry Medvedev +# signed a federal law "On calculation of time" on June 9, 2011. +# According to the law Russia is abolishing daylight saving time. +# +# Medvedev signed a law "On the Calculation of Time" (in russian): +# <a href="http://bmockbe.ru/events/?ID=7583"> +# http://bmockbe.ru/events/?ID=7583 +# </a> +# +# Medvedev signed a law on the calculation of the time (in russian): +# <a href="http://www.regnum.ru/news/polit/1413906.html"> +# http://www.regnum.ru/news/polit/1413906.html +# </a> + +# From Arthur David Olson (2011-06-15): +# Take "abolishing daylight saving time" to mean that time is now considered +# to be standard. +# At least for now, keep the "old" Russia rules for the benefit of Belarus. + # These are for backward compatibility with older versions. # Zone NAME GMTOFF RULES FORMAT [UNTIL] @@ -2013,7 +2033,8 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr 1:00 C-Eur CE%sT 1945 2:00 Poland CE%sT 1946 3:00 Russia MSK/MSD 1991 Mar 31 2:00s - 2:00 Russia EE%sT + 2:00 Russia EE%sT 2011 Mar 27 2:00s + 3:00 - EET # # From Oscar van Vlijmen (2001-08-25): [This region consists of] # Respublika Adygeya, Arkhangel'skaya oblast', @@ -2042,7 +2063,8 @@ Zone Europe/Moscow 2:30:20 - LMT 1880 2:00 - EET 1930 Jun 21 3:00 Russia MSK/MSD 1991 Mar 31 2:00s 2:00 Russia EE%sT 1992 Jan 19 2:00s - 3:00 Russia MSK/MSD + 3:00 Russia MSK/MSD 2011 Mar 27 2:00s + 4:00 - MSK # # Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast', # Volgogradskaya oblast'. Shanks & Pottenger say Kirov is still at +0400 @@ -2055,7 +2077,8 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 4:00 Russia VOL%sT 1989 Mar 26 2:00s # Volgograd T 3:00 Russia VOL%sT 1991 Mar 31 2:00s 4:00 - VOLT 1992 Mar 29 2:00s - 3:00 Russia VOL%sT + 3:00 Russia VOL%sT 2011 Mar 27 2:00s + 4:00 - VOLT # # From Oscar van Vlijmen (2001-08-25): [This region consists of] # Samarskaya oblast', Udmyrtskaya respublika @@ -2067,7 +2090,8 @@ Zone Europe/Samara 3:20:36 - LMT 1919 Jul 1 2:00 2:00 Russia KUY%sT 1991 Sep 29 2:00s 3:00 - KUYT 1991 Oct 20 3:00 4:00 Russia SAM%sT 2010 Mar 28 2:00s # Samara Time - 3:00 Russia SAM%sT + 3:00 Russia SAM%sT 2011 Mar 27 2:00s + 4:00 - SAMT # # From Oscar van Vlijmen (2001-08-25): [This region consists of] @@ -2080,7 +2104,8 @@ Zone Asia/Yekaterinburg 4:02:24 - LMT 1919 Jul 15 4:00 4:00 - SVET 1930 Jun 21 # Sverdlovsk Time 5:00 Russia SVE%sT 1991 Mar 31 2:00s 4:00 Russia SVE%sT 1992 Jan 19 2:00s - 5:00 Russia YEK%sT # Yekaterinburg Time + 5:00 Russia YEK%sT 2011 Mar 27 2:00s + 6:00 - YEKT # Yekaterinburg Time # # From Oscar van Vlijmen (2001-08-25): [This region consists of] # Respublika Altaj, Altajskij kraj, Omskaya oblast'. @@ -2088,7 +2113,8 @@ Zone Asia/Omsk 4:53:36 - LMT 1919 Nov 14 5:00 - OMST 1930 Jun 21 # Omsk TIme 6:00 Russia OMS%sT 1991 Mar 31 2:00s 5:00 Russia OMS%sT 1992 Jan 19 2:00s - 6:00 Russia OMS%sT + 6:00 Russia OMS%sT 2011 Mar 27 2:00s + 7:00 - OMST # # From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's # not clear when it switched from +7 to +6. @@ -2098,7 +2124,8 @@ Zone Asia/Novosibirsk 5:31:40 - LMT 1919 Dec 14 6:00 7:00 Russia NOV%sT 1991 Mar 31 2:00s 6:00 Russia NOV%sT 1992 Jan 19 2:00s 7:00 Russia NOV%sT 1993 May 23 # say Shanks & P. - 6:00 Russia NOV%sT + 6:00 Russia NOV%sT 2011 Mar 27 2:00s + 7:00 - NOVT # From Alexander Krivenyshev (2009-10-13): # Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on @@ -2131,7 +2158,8 @@ Zone Asia/Novokuznetsk 5:48:48 - NMT 1920 Jan 6 7:00 Russia KRA%sT 1991 Mar 31 2:00s 6:00 Russia KRA%sT 1992 Jan 19 2:00s 7:00 Russia KRA%sT 2010 Mar 28 2:00s - 6:00 Russia NOV%sT # Novosibirsk/Novokuznetsk Time + 6:00 Russia NOV%sT 2011 Mar 27 2:00s + 7:00 - NOVT # Novosibirsk/Novokuznetsk Time # # From Oscar van Vlijmen (2001-08-25): [This region consists of] @@ -2142,7 +2170,8 @@ Zone Asia/Krasnoyarsk 6:11:20 - LMT 1920 Jan 6 6:00 - KRAT 1930 Jun 21 # Krasnoyarsk Time 7:00 Russia KRA%sT 1991 Mar 31 2:00s 6:00 Russia KRA%sT 1992 Jan 19 2:00s - 7:00 Russia KRA%sT + 7:00 Russia KRA%sT 2011 Mar 27 2:00s + 8:00 - KRAT # # From Oscar van Vlijmen (2001-08-25): [This region consists of] # Respublika Buryatiya, Irkutskaya oblast', @@ -2152,7 +2181,8 @@ Zone Asia/Irkutsk 6:57:20 - LMT 1880 7:00 - IRKT 1930 Jun 21 # Irkutsk Time 8:00 Russia IRK%sT 1991 Mar 31 2:00s 7:00 Russia IRK%sT 1992 Jan 19 2:00s - 8:00 Russia IRK%sT + 8:00 Russia IRK%sT 2011 Mar 27 2:00s + 9:00 - IRKT # # From Oscar van Vlijmen (2003-10-18): [This region consists of] # Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast', @@ -2175,7 +2205,8 @@ Zone Asia/Yakutsk 8:38:40 - LMT 1919 Dec 15 8:00 - YAKT 1930 Jun 21 # Yakutsk Time 9:00 Russia YAK%sT 1991 Mar 31 2:00s 8:00 Russia YAK%sT 1992 Jan 19 2:00s - 9:00 Russia YAK%sT + 9:00 Russia YAK%sT 2011 Mar 27 2:00s + 10:00 - YAKT # # From Oscar van Vlijmen (2003-10-18): [This region consists of] # Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj, @@ -2188,7 +2219,8 @@ Zone Asia/Vladivostok 8:47:44 - LMT 1922 Nov 15 9:00 - VLAT 1930 Jun 21 # Vladivostok Time 10:00 Russia VLA%sT 1991 Mar 31 2:00s 9:00 Russia VLA%sST 1992 Jan 19 2:00s - 10:00 Russia VLA%sT + 10:00 Russia VLA%sT 2011 Mar 27 2:00s + 11:00 - VLAT # # Sakhalinskaya oblast'. # The Zone name should be Yuzhno-Sakhalinsk, but that's too long. @@ -2198,7 +2230,8 @@ Zone Asia/Sakhalin 9:30:48 - LMT 1905 Aug 23 11:00 Russia SAK%sT 1991 Mar 31 2:00s # Sakhalin T. 10:00 Russia SAK%sT 1992 Jan 19 2:00s 11:00 Russia SAK%sT 1997 Mar lastSun 2:00s - 10:00 Russia SAK%sT + 10:00 Russia SAK%sT 2011 Mar 27 2:00s + 11:00 - SAKT # # From Oscar van Vlijmen (2003-10-18): [This region consists of] # Magadanskaya oblast', Respublika Sakha (Yakutiya). @@ -2211,7 +2244,8 @@ Zone Asia/Magadan 10:03:12 - LMT 1924 May 2 10:00 - MAGT 1930 Jun 21 # Magadan Time 11:00 Russia MAG%sT 1991 Mar 31 2:00s 10:00 Russia MAG%sT 1992 Jan 19 2:00s - 11:00 Russia MAG%sT + 11:00 Russia MAG%sT 2011 Mar 27 2:00s + 12:00 - MAGT # # From Oscar van Vlijmen (2001-08-25): [This region consists of] # Kamchatskaya oblast', Koryakskij avtonomnyj okrug. @@ -2222,7 +2256,8 @@ Zone Asia/Kamchatka 10:34:36 - LMT 1922 Nov 10 12:00 Russia PET%sT 1991 Mar 31 2:00s 11:00 Russia PET%sT 1992 Jan 19 2:00s 12:00 Russia PET%sT 2010 Mar 28 2:00s - 11:00 Russia PET%sT + 11:00 Russia PET%sT 2011 Mar 27 2:00s + 12:00 - PETT # # Chukotskij avtonomnyj okrug Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 @@ -2231,7 +2266,8 @@ Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 12:00 Russia ANA%sT 1991 Mar 31 2:00s 11:00 Russia ANA%sT 1992 Jan 19 2:00s 12:00 Russia ANA%sT 2010 Mar 28 2:00s - 11:00 Russia ANA%sT + 11:00 Russia ANA%sT 2011 Mar 27 2:00s + 12:00 - ANAT # Serbia # Zone NAME GMTOFF RULES FORMAT [UNTIL] diff --git a/contrib/tzdata/southamerica b/contrib/tzdata/southamerica index 919dc25..90f531d 100644 --- a/contrib/tzdata/southamerica +++ b/contrib/tzdata/southamerica @@ -1,5 +1,5 @@ # <pre> -# @(#)southamerica 8.49 +# @(#)southamerica 8.50 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. @@ -1276,6 +1276,14 @@ Zone America/Curacao -4:35:44 - LMT 1912 Feb 12 # Willemstad -4:30 - ANT 1965 # Netherlands Antilles Time -4:00 - AST +# From Arthur David Olson (2011-06-15): +# At least for now, use links for places with new iso3166 codes. +# The name "Lower Prince's Quarter" is both longer than fourteen charaters +# and contains an apostrophe; use "Lower_Princes" below. + +Link America/Curacao America/Lower_Princes # Sint Maarten +Link America/Curacao America/Kralendijk # Bonaire, Sint Estatius and Saba + # Ecuador # # From Paul Eggert (2007-03-04): diff --git a/contrib/tzdata/zone.tab b/contrib/tzdata/zone.tab index f4afae6..2517764 100644 --- a/contrib/tzdata/zone.tab +++ b/contrib/tzdata/zone.tab @@ -1,5 +1,5 @@ # <pre> -# @(#)zone.tab 8.43 +# @(#)zone.tab 8.45 # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # @@ -32,7 +32,6 @@ AG +1703-06148 America/Antigua AI +1812-06304 America/Anguilla AL +4120+01950 Europe/Tirane AM +4011+04430 Asia/Yerevan -AN +1211-06900 America/Curacao AO -0848+01314 Africa/Luanda AQ -7750+16636 Antarctica/McMurdo McMurdo Station, Ross Island AQ -9000+00000 Antarctica/South_Pole Amundsen-Scott Station, South Pole @@ -87,6 +86,7 @@ BL +1753-06251 America/St_Barthelemy BM +3217-06446 Atlantic/Bermuda BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz +BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands BR -0127-04829 America/Belem Amapa, E Para BR -0343-03830 America/Fortaleza NE Brazil (MA, PI, CE, RN, PB) @@ -155,6 +155,7 @@ CO +0436-07405 America/Bogota CR +0956-08405 America/Costa_Rica CU +2308-08222 America/Havana CV +1455-02331 Atlantic/Cape_Verde +CW +1211-06900 America/Curacao CX -1025+10543 Indian/Christmas CY +3510+03322 Asia/Nicosia CZ +5005+01426 Europe/Prague @@ -362,6 +363,7 @@ SO +0204+04522 Africa/Mogadishu SR +0550-05510 America/Paramaribo ST +0020+00644 Africa/Sao_Tome SV +1342-08912 America/El_Salvador +SX +180305-0630250 America/Lower_Princes SY +3330+03618 Asia/Damascus SZ -2618+03106 Africa/Mbabane TC +2128-07108 America/Grand_Turk diff --git a/etc/devd/Makefile b/etc/devd/Makefile index ad434f2..8d7246a 100644 --- a/etc/devd/Makefile +++ b/etc/devd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -FILES= asus.conf uath.conf +FILES= asus.conf uath.conf usb.conf NO_OBJ= FILESDIR= /etc/devd diff --git a/etc/devd/uath.conf b/etc/devd/uath.conf index dc4019c..9f0cb93 100644 --- a/etc/devd/uath.conf +++ b/etc/devd/uath.conf @@ -3,13 +3,13 @@ # Atheros USB wireless network device specific devd events # Accton -# SMCWUSB-G and SMCWUSBT-G2 +# SMCWUSBT-G2 notify 100 { match "system" "USB"; match "subsystem" "DEVICE"; match "type" "ATTACH"; match "vendor" "0x083a"; - match "product" "(0x4505|0x4507)"; + match "product" "0x4507"; action "/usr/sbin/uathload -d /dev/$cdev"; }; diff --git a/etc/devd/usb.conf b/etc/devd/usb.conf new file mode 100644 index 0000000..568be15 --- /dev/null +++ b/etc/devd/usb.conf @@ -0,0 +1,4267 @@ +# +# $FreeBSD$ +# +# This file was automatically generated by "tools/bus_autoconf.sh". +# Please do not edit! +# + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "0x1290"; + match "intclass" "0xff"; + match "intsubclass" "0xfd"; + match "intprotocol" "0x01"; + action "kldload if_ipheth"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "0x1292"; + match "intclass" "0xff"; + match "intsubclass" "0xfd"; + match "intprotocol" "0x01"; + action "kldload if_ipheth"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "0x1294"; + match "intclass" "0xff"; + match "intsubclass" "0xfd"; + match "intprotocol" "0x01"; + action "kldload if_ipheth"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "0x1297"; + match "intclass" "0xff"; + match "intsubclass" "0xfd"; + match "intprotocol" "0x01"; + action "kldload if_ipheth"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0104"; + match "product" "0x00be"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0123"; + match "product" "0x0001"; + action "kldload uep"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03e8"; + match "product" "0x0008"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03eb"; + match "product" "0x2109"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "0x0121"; + action "kldload ugensa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "(0x1016|0x1116|0x1216)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "(0x1b1d|0x1e1d)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "(0x2016|0x2116|0x2216|0x3016|0x3116|0x3216)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "0x3524"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "(0x4016|0x4116|0x4216|0x5016|0x5116|0x5216)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "0x811c"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x03f0"; + match "product" "0xca02"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0402"; + match "product" "0x5632"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0403"; + match "product" "(0x6001|0x6004|0x6010|0x6011|0x8372|0x9e90|0xcc48|0xcc49|0xcc4a|0xd678|0xe6c8|0xe888|0xe889|0xe88a|0xe88b|0xe88c|0xee18|0xf608|0xf60b|0xf850|0xfa00|0xfa01|0xfa02|0xfa03|0xfa04|0xfc08|0xfc09|0xfc0b|0xfc0c|0xfc0d|0xfc82)"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0408"; + match "product" "0x0304"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0408"; + match "product" "(0x1000|0xea02|0xea03|0xea04|0xea05|0xea06)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0409"; + match "product" "(0x00d5|0x00d6|0x00d7|0x8024|0x8025)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x0001|0x0005|0x0009)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x0012"; + action "kldload if_rue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x003d"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x005e|0x0066|0x0067)"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x006e"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x008b"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x00b3"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x00d8|0x00d9)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x00da"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x00e8"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x0116|0x0119)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x012e"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "0x0137"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x0148|0x0150|0x015d|0x016f)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0413"; + match "product" "0x2101"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0423"; + match "product" "(0x000a|0x000c)"; + action "kldload if_cue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x043e"; + match "product" "0x9c01"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x045a"; + match "product" "(0x5001|0x5002)"; + action "kldload urio"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x045b"; + match "product" "0x0053"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x045e"; + match "product" "0x0079"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x045e"; + match "product" "0x007a"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x045e"; + match "product" "(0x00ce|0x0400|0x0401|0x0402|0x0403|0x0404|0x0405|0x0406|0x0407|0x0408|0x0409|0x040a|0x040b|0x040c|0x040d|0x040e|0x040f|0x0410|0x0411|0x0412|0x0413|0x0414|0x0415|0x0416|0x0417|0x0432|0x0433|0x0434|0x0435|0x0436|0x0437|0x0438|0x0439|0x043a|0x043b|0x043c|0x043d|0x043e|0x043f|0x0440|0x0441|0x0442|0x0443|0x0444|0x0445|0x0446|0x0447|0x0448|0x0449|0x044a|0x044b|0x044c|0x044d|0x044e|0x044f|0x0450|0x0451|0x0452|0x0453|0x0454|0x0455|0x0456|0x0457|0x0458|0x0459|0x045a|0x045b|0x045c|0x045d|0x045e|0x045f|0x0460|0x0461|0x0462|0x0463|0x0464|0x0465|0x0466|0x0467|0x0468|0x0469|0x046a|0x046b|0x046c|0x046d|0x046e|0x046f|0x0470|0x0471|0x0472|0x0473|0x0474|0x0475|0x0476|0x0477|0x0478|0x0479|0x047a|0x047b|0x04c8|0x04c9|0x04ca|0x04cb|0x04cc|0x04cd|0x04ce|0x04d7|0x04d8|0x04d9|0x04da|0x04db|0x04dc|0x04dd|0x04de|0x04df|0x04e0|0x04e1|0x04e2|0x04e3|0x04e4|0x04e5|0x04e6|0x04e7|0x04e8|0x04e9|0x04ea)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0471"; + match "product" "0x066a"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0471"; + match "product" "0x1236"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0471"; + match "product" "0x200f"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0482"; + match "product" "0x0203"; + action "kldload umodem"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0489"; + match "product" "(0xe000|0xe003)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x049f"; + match "product" "(0x0003|0x0032)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x049f"; + match "product" "0x505a"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04a4"; + match "product" "0x0014"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04a5"; + match "product" "0x4027"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04a5"; + match "product" "0x4068"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04ad"; + match "product" "(0x0301|0x0302|0x0303|0x0306)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04b4"; + match "product" "0x1002"; + action "kldload ufm"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04b7"; + match "product" "0x0531"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04b8"; + match "product" "(0x0521|0x0522)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "0x0901"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "(0x0904|0x0913)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "0x0930"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "(0x0944|0x0945|0x0947|0x0948)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "(0x0a03|0x0a0e)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bf"; + match "product" "(0x0115|0x0117)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04c5"; + match "product" "(0x1058|0x1079)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04da"; + match "product" "0x2500"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04da"; + match "product" "0x3900"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04dd"; + match "product" "(0x8004|0x8005|0x8006|0x8007|0x9031)"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04dd"; + match "product" "(0x9102|0x9121|0x9123|0x9151|0x91ac|0x9242)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04e8"; + match "product" "(0x5f00|0x5f01|0x5f02|0x5f03|0x5f04)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04e8"; + match "product" "0x6601"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04e8"; + match "product" "(0x6611|0x6613|0x6615|0x6617|0x6619|0x661b|0x662e|0x6630|0x6632)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04e8"; + match "product" "0x8001"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04f1"; + match "product" "0x3008"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04f1"; + match "product" "(0x3011|0x3012)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0502"; + match "product" "(0x1631|0x1632|0x16e1|0x16e2|0x16e3)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0506"; + match "product" "(0x03e8|0x11f8)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0506"; + match "product" "0x4601"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x0103"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x0109"; + action "kldload umct"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x0121"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x0257"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x0409"; + action "kldload umct"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x1203"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x4050"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x5055"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x7050"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "(0x7050|0x7051)"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x705a"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x705c"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x705e"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "(0x8053|0x805c|0x815c|0x825a)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x905b"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x050d"; + match "product" "0x935a"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0525"; + match "product" "0x1080"; + action "kldload udbp"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0525"; + match "product" "0xa4a2"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0536"; + match "product" "0x01a0"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0543"; + match "product" "(0x0ed9|0x1527|0x1529|0x152b|0x152e|0x1921|0x1922|0x1923)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0547"; + match "product" "0x2008"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0547"; + match "product" "0x2720"; + action "kldload udbp"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x054c"; + match "product" "(0x0038|0x0066|0x0095|0x009a|0x00da|0x0169)"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x054c"; + match "product" "0x0437"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0557"; + match "product" "0x2002"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0557"; + match "product" "0x2007"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0557"; + match "product" "0x2008"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0557"; + match "product" "0x2009"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0557"; + match "product" "0x4000"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x055d"; + match "product" "0x2018"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0565"; + match "product" "0x0001"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0565"; + match "product" "(0x0002|0x0003|0x0005)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0567"; + match "product" "(0x2000|0x2002)"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x056c"; + match "product" "0x8007"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x056e"; + match "product" "(0x200c|0x4002|0x4005|0x400b|0x4010)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x056e"; + match "product" "(0x5003|0x5004)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x056e"; + match "product" "0xabc1"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x057c"; + match "product" "(0x2200|0x3800)"; + action "kldload ng_ubt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0584"; + match "product" "0xb000"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0584"; + match "product" "0xb020"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0586"; + match "product" "(0x3401|0x3407|0x3409|0x340a|0x340f|0x3410)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0586"; + match "product" "(0x3416|0x341a)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x058f"; + match "product" "0x9720"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05a6"; + match "product" "0x0101"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "(0x020d|0x020e|0x020f|0x0215|0x0217|0x0218|0x0219|0x021a|0x021b|0x021c|0x0229|0x022a|0x022b|0x030a|0x030b)"; + action "kldload atp"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ac"; + match "product" "0x1402"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05ad"; + match "product" "0x0fba"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05c6"; + match "product" "(0x6000|0x6613)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05cc"; + match "product" "0x3000"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05db"; + match "product" "(0x0003|0x0005|0x0009|0x000a|0x0011)"; + action "kldload uvscom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05e0"; + match "product" "(0x2000|0x2001|0x2002|0x2003|0x2004|0x2005|0x2006|0x2007|0x2008|0x2009|0x200a)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05e3"; + match "product" "0x0501"; + action "kldload udbp"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x05e9"; + match "product" "(0x0008|0x0009)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x066b"; + match "product" "(0x200c|0x2202)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x066b"; + match "product" "0x2202"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x066b"; + match "product" "(0x2203|0x2204|0x2206|0x400b)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0675"; + match "product" "0x0550"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067b"; + match "product" "(0x0000|0x0001)"; + action "kldload udbp"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067b"; + match "product" "(0x04bb|0x0609|0x0611|0x0612|0x1234|0x206a|0x2303)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067b"; + match "product" "0x2501"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067b"; + match "product" "(0x331a|0xaaa0|0xaaa2)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067c"; + match "product" "0x1001"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x067e"; + match "product" "0x1001"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0681"; + match "product" "0x3c06"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x06e1"; + match "product" "(0x0008|0x0009)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x06f8"; + match "product" "0xe000"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x06f8"; + match "product" "(0xe010|0xe020)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x06f8"; + match "product" "0xe030"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0707"; + match "product" "0x0100"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0707"; + match "product" "(0x0200|0x0201)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0707"; + match "product" "0xee13"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0707"; + match "product" "0xee13"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0711"; + match "product" "(0x0200|0x0210|0x0230)"; + action "kldload umct"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0731"; + match "product" "(0x0528|0x2003)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0745"; + match "product" "0x0001"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0745"; + match "product" "0x1000"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0769"; + match "product" "0x11f2"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0769"; + match "product" "0x11f3"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0769"; + match "product" "0x31f3"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x077b"; + match "product" "0x2226"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0789"; + match "product" "0x010c"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0789"; + match "product" "0x0160"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0789"; + match "product" "(0x0162|0x0163|0x0164)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x078b"; + match "product" "0x1234"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x079b"; + match "product" "0x0027"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x079b"; + match "product" "(0x004a|0x0062)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07a6"; + match "product" "(0x07c2|0x0986|0x8511|0x8513|0x8515)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "0x0001"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "(0x0004|0x000d)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "0x0017"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "0x002a"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "(0x002d|0x002e)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "(0x002f|0x003c|0x003f|0x0041|0x0042)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07aa"; + match "product" "0x9601"; + action "kldload if_udav"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "(0x110c|0x200c)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "(0x2770|0x2870|0x3070|0x3071|0x3072)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "0x4000"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "(0x4002|0x4003|0x4004|0x4007|0x400b|0x400c|0x4102|0x4104)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "0x420a"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "0x6001"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "0xabc1"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07b8"; + match "product" "(0xb21b|0xb21c|0xb21d|0xb21e|0xb21f)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07c9"; + match "product" "0xb100"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07cf"; + match "product" "(0x2001|0x2002|0x2003)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07d1"; + match "product" "0x3a0c"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07d1"; + match "product" "(0x3c03|0x3c04|0x3c06|0x3c07)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x07d1"; + match "product" "(0x3c09|0x3c0a|0x3c0b|0x3c0d|0x3c0e|0x3c0f|0x3c11|0x3c13|0x3c15|0x3c16)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x081e"; + match "product" "0xdf00"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x082d"; + match "product" "(0x0100|0x0200|0x0300)"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0830"; + match "product" "(0x0001|0x0002|0x0003|0x0020|0x0031|0x0040|0x0050|0x0060|0x0061|0x0070)"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0833"; + match "product" "(0x012e|0x039f)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "0x1046"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "(0x4505|0x4506)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "0x4508"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "0x4521"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "0x5046"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "(0x6618|0x7511|0x7512|0x7522|0x8522|0xa512|0xa618|0xa701|0xa702|0xb522|0xc522|0xd522)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x083a"; + match "product" "0xe501"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0841"; + match "product" "0x0001"; + action "kldload urio"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "(0x1001|0x1002)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "0x1020"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "0x1040"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "0x4240"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "0x4260"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "0x4300"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0846"; + match "product" "(0x6100|0x6a00)"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0856"; + match "product" "0xac01"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x085a"; + match "product" "(0x0008|0x0009)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x086e"; + match "product" "0x1920"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x087d"; + match "product" "0x5704"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08d1"; + match "product" "0x0001"; + action "kldload if_cue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08d1"; + match "product" "0x0003"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08dd"; + match "product" "(0x0986|0x0987|0x0988|0x8511)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08dd"; + match "product" "0x90ff"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08e6"; + match "product" "0x5501"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x08fd"; + match "product" "0x000a"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0915"; + match "product" "(0x2000|0x2002)"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x091e"; + match "product" "0x0004"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0921"; + match "product" "0x1001"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0930"; + match "product" "(0x0700|0x0705|0x0706|0x0707|0x0708|0x0709|0x070a|0x070b)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0930"; + match "product" "0x0a07"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0930"; + match "product" "(0x0d45|0x1302)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x093c"; + match "product" "(0x0601|0x0701)"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x094b"; + match "product" "0x0001"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0951"; + match "product" "0x0008"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0951"; + match "product" "0x000a"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x095a"; + match "product" "0x3003"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0960"; + match "product" "(0x0065|0x0066|0x0067)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0961"; + match "product" "0x0010"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x099e"; + match "product" "(0x0052|0x4000)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x09aa"; + match "product" "0x1000"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x09d7"; + match "product" "0x0100"; + action "kldload ugensa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0a46"; + match "product" "(0x0268|0x8515|0x9601)"; + action "kldload if_udav"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0a5c"; + match "product" "0x2033"; + action "kldload ubtbcmfw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0ace"; + match "product" "(0x1211|0x1215)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "(0x5000|0x6000|0x6050|0x6100|0x6150|0x6200|0x6250|0x6300|0x6350|0x6500|0x6501|0x6600|0x6601|0x6701|0x6721|0x6741|0x6761|0x6800|0x6901)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x6911"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x6971"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x6971"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x7001"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x7011"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "(0x7021|0x7041|0x7061|0x7100|0x7201|0x7211)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "(0x7251|0x7301|0x7361|0x7381|0x7401|0x7501)"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0x7601"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "(0x7601|0xc031|0xd013|0xd031)"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "0xd033"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0af0"; + match "product" "(0xd033|0xd055|0xd055)"; + action "kldload uhso"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "(0x1706|0x1707)"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "(0x170c|0x171b)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "0x171d"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "(0x1723|0x1724)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "(0x1731|0x1732|0x1742|0x1760|0x1761|0x1784|0x1790)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "(0x4200|0x4201|0x4202|0x420f|0x9200|0x9202)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b39"; + match "product" "0x0109"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b39"; + match "product" "0x0421"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b3b"; + match "product" "(0x1630|0x5630|0x6630)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b41"; + match "product" "0x0011"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b63"; + match "product" "0x6530"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b8c"; + match "product" "0x2303"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b95"; + match "product" "(0x1720|0x1780|0x7720|0x772a)"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0baf"; + match "product" "0x0118"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0baf"; + match "product" "0x0121"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bb2"; + match "product" "0x6098"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bb4"; + match "product" "(0x00ce|0x00cf|0x00cf|0x0a01|0x0a02|0x0a03|0x0a04|0x0a05|0x0a06|0x0a07|0x0a08|0x0a09|0x0a0a|0x0a0b|0x0a0c|0x0a0d|0x0a0e|0x0a0f|0x0a10|0x0a11|0x0a12|0x0a13|0x0a14|0x0a15|0x0a16|0x0a17|0x0a18|0x0a19|0x0a1a|0x0a1b|0x0a1c|0x0a1d|0x0a1e|0x0a1f|0x0a20|0x0a21|0x0a22|0x0a23|0x0a24|0x0a25|0x0a26|0x0a27|0x0a28|0x0a29|0x0a2a|0x0a2b|0x0a2c|0x0a2d|0x0a2e|0x0a2f|0x0a30|0x0a31|0x0a32|0x0a33|0x0a34|0x0a35|0x0a36|0x0a37|0x0a38|0x0a39|0x0a3a|0x0a3b|0x0a3c|0x0a3d|0x0a3e|0x0a3f|0x0a40|0x0a41|0x0a42|0x0a43|0x0a44|0x0a45|0x0a46|0x0a47|0x0a48|0x0a49|0x0a4a|0x0a4b|0x0a4c|0x0a4d|0x0a4e|0x0a4f|0x0a50|0x0a51|0x0a52|0x0a53|0x0a54|0x0a55|0x0a56|0x0a57|0x0a58|0x0a59|0x0a5a|0x0a5b|0x0a5c|0x0a5d|0x0a5e|0x0a5f|0x0a60|0x0a61|0x0a62|0x0a63|0x0a64|0x0a65|0x0a66|0x0a67|0x0a68|0x0a69|0x0a6a|0x0a6b|0x0a6c|0x0a6d|0x0a6e|0x0a6f|0x0a70|0x0a71|0x0a72|0x0a73|0x0a74|0x0a75|0x0a76|0x0a77|0x0a78|0x0a79|0x0a7a|0x0a7b|0x0a7c|0x0a7d|0x0a7e|0x0a7f|0x0a80|0x0a81|0x0a82|0x0a83|0x0a84|0x0a85|0x0a86|0x0a87|0x0a88|0x0a89|0x0a8a|0x0a8b|0x0a8c|0x0a8d|0x0a8e|0x0a8f|0x0a90|0x0a91|0x0a92|0x0a93|0x0a94|0x0a95|0x0a96|0x0a97|0x0a98|0x0a99|0x0a9a|0x0a9b|0x0a9c|0x0a9d|0x0a9e|0x0a9f|0x0bce)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bda"; + match "product" "0x8150"; + action "kldload if_rue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bda"; + match "product" "(0x8187|0x8189|0x8197|0x8198)"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bed"; + match "product" "(0x1100|0x1101)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bf8"; + match "product" "0x1001"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0bf8"; + match "product" "0x1009"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0c44"; + match "product" "0x03a2"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0c88"; + match "product" "0x17da"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0c88"; + match "product" "0x17da"; + action "kldload ugensa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0c88"; + match "product" "0x180a"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0c8e"; + match "product" "0x6000"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cad"; + match "product" "0x9001"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "0x0008"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "0x0011"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "0x0012"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "0x0015"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "0x001a"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cde"; + match "product" "(0x0022|0x0025)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0cf3"; + match "product" "(0x0001|0x0003|0x0005)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0d8e"; + match "product" "0x3762"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0d8e"; + match "product" "(0x7801|0x7811)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db0"; + match "product" "(0x3820|0x3821|0x3822|0x3870|0x3871)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db0"; + match "product" "(0x6861|0x6865|0x6869)"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db0"; + match "product" "(0x6874|0x6877)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db0"; + match "product" "(0x6899|0x821a|0x822a|0x870a|0x871a|0x899a)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db0"; + match "product" "(0xa861|0xa874)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0db7"; + match "product" "0x0002"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x000d"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x0017"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x0021"; + action "kldload if_mos"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x0028"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "(0x002b|0x002c|0x002d|0x0039|0x003b|0x003c|0x003d|0x003e|0x003f|0x0040|0x0041|0x0042|0x0047|0x0048|0x004a|0x004d)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x061c"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "(0x9071|0x9075)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "(0x90ac|0x9712)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df7"; + match "product" "0x0620"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e0b"; + match "product" "(0x9031|0x9041)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e55"; + match "product" "0x110b"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e66"; + match "product" "(0x0001|0x0003|0x0009|0x000b)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e66"; + match "product" "0x400c"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e67"; + match "product" "0x0002"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0e7e"; + match "product" "0x1001"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0ea0"; + match "product" "0x6858"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0eab"; + match "product" "0xc893"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0eb0"; + match "product" "0x9020"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0eb0"; + match "product" "0x9021"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0eba"; + match "product" "(0x1080|0x2080)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0eef"; + match "product" "(0x0001|0x0002)"; + action "kldload uep"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f3d"; + match "product" "0x0112"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f3d"; + match "product" "0x0112"; + action "kldload ugensa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f4e"; + match "product" "0x0200"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f88"; + match "product" "0x3012"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f88"; + match "product" "0x3014"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f94"; + match "product" "0x0001"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0f98"; + match "product" "0x0201"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0fb8"; + match "product" "(0x3001|0x3002|0x3003|0x4001)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0fcf"; + match "product" "(0x1003|0x1004|0x1006)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0fe6"; + match "product" "(0x8101|0x9700)"; + action "kldload if_udav"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x100d"; + match "product" "(0x9031|0x9032)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1011"; + match "product" "0x3198"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1044"; + match "product" "0x8001"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1044"; + match "product" "0x8002"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1044"; + match "product" "0x8007"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1044"; + match "product" "(0x8008|0x800a)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1044"; + match "product" "(0x800b|0x800c|0x800d)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1066"; + match "product" "(0x00ce|0x0300|0x0500|0x0600|0x0700)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x106c"; + match "product" "0x3701"; + action "kldload umodem"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10a6"; + match "product" "0xaa26"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10ab"; + match "product" "0x10c5"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10b5"; + match "product" "0xac70"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10b5"; + match "product" "0xac70"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10bd"; + match "product" "0x1427"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10c4"; + match "product" "(0x0f91|0x1101|0x1601|0x800a|0x803b|0x8043|0x8044)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10c4"; + match "product" "0x8053"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10c4"; + match "product" "(0x8066|0x806f|0x807a|0x80ca|0x80dd|0x80ed|0x80f6|0x8115|0x813d|0x813f|0x814a|0x814a|0x814b|0x8156|0x815e|0x818b|0x819f|0x81a6|0x81ac|0x81ad|0x81c8|0x81e2|0x81e7|0x81e8|0x81f2|0x8218|0x822b|0x826b|0x8293|0x82f9|0x8341|0x8382|0x83a8|0x8411|0x846e|0x8477|0xea60|0xea61|0xea71|0xf001|0xf002|0xf003|0xf004)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10c5"; + match "product" "0xea61"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x10ce"; + match "product" "0xea61"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1114"; + match "product" "(0x0001|0x0004|0x0006)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x114b"; + match "product" "0x0110"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x114b"; + match "product" "0x0150"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1163"; + match "product" "0x0100"; + action "kldload ucycom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1182"; + match "product" "0x1388"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1186"; + match "product" "0x3e04"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1189"; + match "product" "0x0893"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1199"; + match "product" "(0x0017|0x0018|0x0019|0x0020|0x0021|0x0022|0x0023|0x0024|0x0025|0x0026|0x0027|0x0028|0x0029|0x0112|0x0120|0x0218)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1199"; + match "product" "0x0218"; + action "kldload umodem"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1199"; + match "product" "(0x0220|0x0224|0x0fff|0x6802|0x6803|0x6804|0x6805|0x6808|0x6809|0x6812|0x6813|0x6815|0x6816|0x6820|0x6821|0x6822|0x6832|0x6833|0x6834|0x6835|0x6838|0x6839|0x683a|0x683b|0x683c|0x683d|0x683e|0x6850|0x6851|0x6852|0x6853|0x6855|0x6856|0x6859|0x685a|0x6880|0x6890|0x6891|0x6892|0x6893|0x68a3)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x11ad"; + match "product" "0x0701"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x11d9"; + match "product" "(0x1002|0x1003)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x11f5"; + match "product" "(0x0001|0x0003|0x0004|0x0005)"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x11f6"; + match "product" "0x2001"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x11f7"; + match "product" "0x02df"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1231"; + match "product" "(0xce01|0xce02)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x126f"; + match "product" "0xa006"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x129b"; + match "product" "0x1666"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x129b"; + match "product" "0x1828"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x12d1"; + match "product" "(0x1001|0x1003|0x1004|0x1401|0x1402|0x1403|0x1404|0x1405|0x1406|0x1407|0x1408|0x1409|0x140a|0x140b|0x140c|0x140d|0x140e|0x140f|0x1410|0x1411|0x1412|0x1413|0x1414|0x1415|0x1416|0x1417|0x1418|0x1419|0x141a|0x141b|0x141c|0x141d|0x141e|0x141f|0x1420|0x1421|0x1422|0x1423|0x1424|0x1425|0x1426|0x1427|0x1428|0x1429|0x142a|0x142b|0x142c|0x142d|0x142e|0x142f|0x1430|0x1431|0x1432|0x1433|0x1434|0x1435|0x1436|0x1437|0x1438|0x1439|0x143a|0x143b|0x143c|0x143d|0x143e|0x143f|0x1446|0x1465|0x14ac|0x1520)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x12ef"; + match "product" "0x0100"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1342"; + match "product" "0x0204"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1371"; + match "product" "(0x9022|0x9032)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1371"; + match "product" "0x9401"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1385"; + match "product" "(0x4250|0x5f00|0x5f02)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13ad"; + match "product" "0x9999"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "0x000c"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "(0x000d|0x0011)"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "0x0018"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "0x001a"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "(0x0020|0x0023)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "0x0024"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13d2"; + match "product" "0x0400"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13d3"; + match "product" "(0x3247|0x3262|0x3273|0x3284|0x3305)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1410"; + match "product" "(0x1100|0x1110|0x1120|0x1130|0x1400|0x1410|0x1420|0x1430|0x1450|0x2100|0x2110|0x2120|0x2130|0x2400|0x2410|0x2420|0x4100|0x4400|0x5010|0x5100|0x6000|0x6002|0x7042)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1416"; + match "product" "0x1110"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1435"; + match "product" "0x0427"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1435"; + match "product" "0x0711"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1435"; + match "product" "(0x0826|0x082a)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1453"; + match "product" "0x4026"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1472"; + match "product" "0x0009"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1482"; + match "product" "0x3c09"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1485"; + match "product" "(0x0001|0x0002)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "0x1706"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "0x2070"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "0x2570"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "(0x2573|0x2671)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "(0x2770|0x2870|0x3070|0x3071|0x3072|0x3370|0x3572|0x8070)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "0x9020"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x148f"; + match "product" "0x9021"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14b2"; + match "product" "0x3c02"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14b2"; + match "product" "(0x3c06|0x3c07|0x3c08|0x3c09|0x3c11|0x3c12)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14b2"; + match "product" "0x3c22"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14b2"; + match "product" "(0x3c23|0x3c25|0x3c25|0x3c27|0x3c28)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14ea"; + match "product" "0xab10"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14ea"; + match "product" "0xab11"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x14ea"; + match "product" "0xab13"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1555"; + match "product" "0x0004"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1557"; + match "product" "0x7720"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1557"; + match "product" "0x8150"; + action "kldload if_rue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x157e"; + match "product" "0x3006"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x157e"; + match "product" "(0x300a|0x300b|0x300d)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x157e"; + match "product" "0x300e"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x157e"; + match "product" "0x3204"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x157e"; + match "product" "0x3205"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1582"; + match "product" "0x6003"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x15a9"; + match "product" "0x0004"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x15a9"; + match "product" "(0x0006|0x0010)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x15c5"; + match "product" "0x0008"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x15e8"; + match "product" "(0x9100|0x9110)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1614"; + match "product" "(0x0800|0x0802|0x7002)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1631"; + match "product" "0x6200"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1631"; + match "product" "0xc019"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1645"; + match "product" "(0x0005|0x0008|0x8005)"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x166a"; + match "product" "0x0303"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x167b"; + match "product" "0x4001"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x168c"; + match "product" "0x0001"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1690"; + match "product" "0x0601"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1690"; + match "product" "(0x0710|0x0712)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1690"; + match "product" "0x0722"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1690"; + match "product" "(0x0740|0x0744)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16ab"; + match "product" "(0x7801|0x7811)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d5"; + match "product" "(0x6202|0x6501)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d5"; + match "product" "0x6501"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d5"; + match "product" "0x6502"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d5"; + match "product" "0x6502"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d6"; + match "product" "(0x0001|0x0001)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d8"; + match "product" "(0x6006|0x6280)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16d8"; + match "product" "0x6280"; + action "kldload ugensa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x16dc"; + match "product" "(0x0010|0x0011|0x0012|0x0015)"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1726"; + match "product" "0x1000"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1726"; + match "product" "0x1000"; + action "kldload ubsa"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1737"; + match "product" "0x0039"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1737"; + match "product" "(0x0070|0x0071)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1737"; + match "product" "0x0073"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1737"; + match "product" "(0x0077|0x0078|0x0079)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1740"; + match "product" "(0x0605|0x0615)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1740"; + match "product" "0x2000"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1740"; + match "product" "(0x9701|0x9702|0x9703|0x9705|0x9706|0x9707|0x9708|0x9709|0x9801)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1761"; + match "product" "0x0b05"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x177f"; + match "product" "(0x0153|0x0302|0x0313)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x17f4"; + match "product" "0xaaaa"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1843"; + match "product" "0x0200"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18c5"; + match "product" "0x0002"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18c5"; + match "product" "(0x0008|0x0012)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18e8"; + match "product" "(0x6196|0x6229)"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18e8"; + match "product" "0x6232"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18e8"; + match "product" "0x6238"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18e8"; + match "product" "0x6259"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x18ef"; + match "product" "0xe00f"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x19d2"; + match "product" "(0x0001|0x0002|0x0003|0x0004|0x0005|0x0006|0x0007|0x0008|0x0009|0x000a|0x000b|0x000c|0x000d|0x000e|0x000f|0x0010|0x0011|0x0012|0x0013|0x0014|0x0015|0x0016|0x0017|0x0018|0x0019|0x0020|0x0021|0x0022|0x0023|0x0024|0x0025|0x0026|0x0027|0x0028|0x0029|0x0030|0x0031|0x0032|0x0033|0x0037|0x0039|0x0042|0x0043|0x0048|0x0049|0x0051|0x0052|0x0053|0x0054|0x0055|0x0057|0x0058|0x0059|0x0060|0x0061|0x0062|0x0063|0x0064|0x0066|0x0069|0x0070|0x0073|0x0076|0x0078|0x0082|0x0086|0x0117|0x2000|0x2002|0x2003|0xfff1|0xfff5|0xfffe)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1a86"; + match "product" "0x7523"; + action "kldload uchcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1a8d"; + match "product" "(0x1002|0x1003|0x1004|0x1005|0x1006|0x1007|0x1008|0x1009|0x100a|0x100b|0x100c|0x100d|0x100e|0x100f|0x1010|0x1011|0x1012)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1b3d"; + match "product" "0x0153"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1b75"; + match "product" "0x3072"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1b75"; + match "product" "0x8187"; + action "kldload if_urtw"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1bbb"; + match "product" "(0x0000|0xf000)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1bc7"; + match "product" "(0x1003|0x1004)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1be3"; + match "product" "0x07a6"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1c9e"; + match "product" "(0x6061|0x9603|0xf000)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1cf1"; + match "product" "(0x0001|0x0004)"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1d09"; + match "product" "0x4000"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1d4d"; + match "product" "(0x0002|0x000c|0x000e|0x0010)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1da5"; + match "product" "(0x4512|0x4515|0x4519|0x4523)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1e0e"; + match "product" "(0x9000|0x9200|0xce16)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1eda"; + match "product" "0x2310"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x1a00"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x200c"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "(0x3a00|0x3a02|0x3a04)"; + action "kldload if_uath"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x3c00"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x3c05"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "(0x3c09|0x3c0a)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "0x4000"; + action "kldload if_kue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2001"; + match "product" "(0x4001|0x4002|0x4003|0x400b|0x4102|0xabc1)"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "0x5303"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "0xab01"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "(0xab24|0xab25)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "0xab50"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "(0xc007|0xed01)"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "0xed02"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2019"; + match "product" "(0xed06|0xed14)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x203d"; + match "product" "(0x1480|0x14a1|0x14a9)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x20b8"; + match "product" "0x8888"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x20b9"; + match "product" "0x1682"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x22b8"; + match "product" "(0x4204|0x4214|0x4224|0x4234|0x4244)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x22b8"; + match "product" "(0x600c|0x6027)"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2478"; + match "product" "0x2008"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x3334"; + match "product" "0x1701"; + action "kldload if_aue"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x3340"; + match "product" "(0x011c|0x0326|0x0426|0x043a|0x051c|0x053a|0x071c|0x0b1c|0x0e3a|0x0f1c|0x0f3a|0x1326|0x191c|0x2326|0x3326)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x3708"; + match "product" "(0x20ce|0x21ce)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x4113"; + match "product" "(0x0210|0x0211|0x0400|0x0410)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x413c"; + match "product" "(0x4001|0x4002|0x4003|0x4004|0x4005|0x4006|0x4007|0x4008|0x4009)"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x413c"; + match "product" "(0x8102|0x8104)"; + action "kldload if_upgt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x413c"; + match "product" "(0x8114|0x8115|0x8116|0x8117|0x8118|0x8128|0x8129|0x8133|0x8134|0x8135|0x8136|0x8137|0x8138|0x8180|0x8181|0x8182)"; + action "kldload u3g"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x413c"; + match "product" "0x9500"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x4348"; + match "product" "0x5523"; + action "kldload uchcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x4505"; + match "product" "0x0010"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x4766"; + match "product" "0x0001"; + action "kldload uvisor"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x5173"; + match "product" "0x1809"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x5372"; + match "product" "0x2303"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x5a57"; + match "product" "0x0260"; + action "kldload if_ural"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x5a57"; + match "product" "(0x0280|0x0282|0x0283|0x0284|0x5257)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x5e04"; + match "product" "0xce00"; + action "kldload uipaq"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x6189"; + match "product" "0x182d"; + action "kldload if_axe"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x6189"; + match "product" "0x2068"; + action "kldload uplcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x6547"; + match "product" "0x0232"; + action "kldload uark"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x6891"; + match "product" "0xa727"; + action "kldload if_zyd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x7392"; + match "product" "0x7318"; + action "kldload if_rum"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x7392"; + match "product" "(0x7711|0x7717|0x7718)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x8516"; + match "product" "(0x2070|0x2770|0x2870|0x3070|0x3071|0x3072|0x3572)"; + action "kldload if_run"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9710"; + match "product" "0x7703"; + action "kldload umoscom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9710"; + match "product" "0x7730"; + action "kldload if_mos"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9710"; + match "product" "0x7820"; + action "kldload umcs"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9710"; + match "product" "0x7830"; + action "kldload if_mos"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9710"; + match "product" "0x7840"; + action "kldload umcs"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x9e88"; + match "product" "0x9e8f"; + action "kldload uftdi"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0xdaae"; + match "product" "0xead6"; + action "kldload uslcom"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x02"; + match "intsubclass" "0x02"; + match "intprotocol" "0x01"; + action "kldload umodem"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x03"; + match "intsubclass" "0x01"; + match "intprotocol" "0x01"; + action "kldload ukbd"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x03"; + match "intsubclass" "0x01"; + match "intprotocol" "0x02"; + action "kldload ums"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x07"; + match "intsubclass" "0x01"; + match "intprotocol" "0x01"; + action "kldload ulpt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x07"; + match "intsubclass" "0x01"; + match "intprotocol" "0x02"; + action "kldload ulpt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x07"; + match "intsubclass" "0x01"; + match "intprotocol" "0x03"; + action "kldload ulpt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0xe0"; + match "intsubclass" "0x01"; + match "intprotocol" "0x01"; + action "kldload ng_ubt"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0xff"; + match "intsubclass" "0x5d"; + match "intprotocol" "0x01"; + action "kldload uhid"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x01"; + match "intsubclass" "0x01"; + action "kldload snd_uaudio"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x01"; + match "intsubclass" "0x03"; + action "kldload snd_uaudio"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "(host|device)"; + match "intclass" "0x02"; + match "intsubclass" "0x06"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "(host|device)"; + match "intclass" "0x02"; + match "intsubclass" "0x0a"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "(host|device)"; + match "intclass" "0x02"; + match "intsubclass" "0x0d"; + action "kldload if_cdce"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x02"; + match "intsubclass" "0x88"; + action "kldload ufoma"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x03"; + action "kldload uhid"; +}; + +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "intclass" "0x08"; + action "kldload umass"; +}; + +# 1634 USB entries processed + diff --git a/etc/network.subr b/etc/network.subr index f9a1f88..44a5892 100644 --- a/etc/network.subr +++ b/etc/network.subr @@ -94,7 +94,7 @@ ifconfig_up() # ifconfig_IF ifconfig_args=`ifconfig_getargs $1` if [ -n "${ifconfig_args}" ]; then - ifconfig $1 ${ifconfig_args} + eval ifconfig $1 ${ifconfig_args} _cfg=0 fi diff --git a/etc/rc.d/netwait b/etc/rc.d/netwait index d7a5184..1d3556a 100755 --- a/etc/rc.d/netwait +++ b/etc/rc.d/netwait @@ -14,7 +14,8 @@ . /etc/rc.subr name="netwait" -rc_var=`set_rcvar` +rcvar=`set_rcvar` + start_cmd="${name}_start" stop_cmd=":" diff --git a/etc/rc.d/quota b/etc/rc.d/quota index 6432f50..edc90ef 100755 --- a/etc/rc.d/quota +++ b/etc/rc.d/quota @@ -14,6 +14,7 @@ name="quota" rcvar=`set_rcvar` +load_rc_config $name start_cmd="quota_start" stop_cmd="/usr/sbin/quotaoff ${quotaoff_flags}" @@ -30,5 +31,4 @@ quota_start() echo ' done.' } -load_rc_config $name run_rc_command "$1" diff --git a/etc/regdomain.xml b/etc/regdomain.xml index d95000c..9b40605 100644 --- a/etc/regdomain.xml +++ b/etc/regdomain.xml @@ -83,7 +83,7 @@ <flags>IEEE80211_CHAN_HT20</flags> </band> <band> - <freqband ref="F1_2412_2462"/> + <freqband ref="H4_2412_2462"/> <maxpower>30</maxpower> <flags>IEEE80211_CHAN_G</flags> <flags>IEEE80211_CHAN_HT40</flags> @@ -96,7 +96,7 @@ <flags>IEEE80211_CHAN_HT20</flags> </band> <band> - <freqband ref="F1_5180_5240"/> + <freqband ref="H4_5180_5240"/> <maxpower>17</maxpower> <flags>IEEE80211_CHAN_HT40</flags> </band> @@ -106,7 +106,7 @@ <flags>IEEE80211_CHAN_HT20</flags> </band> <band> - <freqband ref="F1_5745_5805"/> + <freqband ref="H4_5745_5805"/> <maxpower>23</maxpower> <flags>IEEE80211_CHAN_HT40</flags> </band> @@ -138,6 +138,24 @@ <maxpower>17</maxpower> </band> <band> + <freqband ref="F1_5260_5320"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="F1_5500_5580"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="F1_5660_5700"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> <freqband ref="F1_5745_5805"/> <maxpower>23</maxpower> <flags>IEEE80211_CHAN_PASSIVE</flags> @@ -176,6 +194,48 @@ <flags>IEEE80211_CHAN_HT40</flags> </band> <band> + <freqband ref="F1_5260_5320"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT20</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="H4_5260_5320"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT40</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="F1_5500_5580"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT20</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="H4_5500_5580"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT40</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="F1_5660_5700"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT20</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> + <freqband ref="H4_5660_5700"/> + <maxpower>23</maxpower> + <flags>IEEE80211_CHAN_HT40</flags> + <flags>IEEE80211_CHAN_PASSIVE</flags> + <flags>IEEE80211_CHAN_DFS</flags> + </band> + <band> <freqband ref="F1_5745_5805"/> <maxpower>23</maxpower> <flags>IEEE80211_CHAN_HT20</flags> @@ -231,7 +291,7 @@ <flags>IEEE80211_CHAN_HT20</flags> </band> <band> - <freqband ref="F1_2412_2462"/> + <freqband ref="H4_2412_2462"/> <maxpower>30</maxpower> <flags>IEEE80211_CHAN_G</flags> <flags>IEEE80211_CHAN_HT40</flags> @@ -321,9 +381,9 @@ <sku>0x30</sku> <netband mode="11b"> <band> - <freqband ref="F1_2412_2472"/> - <maxpower>30</maxpower> - <flags>IEEE80211_CHAN_B</flags> + <freqband ref="F1_2412_2472"/> + <maxpower>30</maxpower> + <flags>IEEE80211_CHAN_B</flags> </band> </netband> <netband mode="11g"> @@ -1624,6 +1684,16 @@ <chanwidth>40</chanwidth> <chansep>20</chansep> <flags>IEEE80211_CHAN_A</flags> </freqband> +<freqband id="F1_5500_5580"> + <freqstart>5500</freqstart> <freqend>5580</freqend> + <chanwidth>20</chanwidth> <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> +</freqband> +<freqband id="H4_5500_5580"> + <freqstart>5500</freqstart> <freqend>5580</freqend> + <chanwidth>40</chanwidth> <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> +</freqband> <freqband id="F1_5500_5620"> <freqstart>5500</freqstart> <freqend>5620</freqend> <chanwidth>20</chanwidth> <chansep>20</chansep> @@ -1644,6 +1714,16 @@ <chanwidth>20</chanwidth> <chansep>20</chansep> <flags>IEEE80211_CHAN_A</flags> </freqband> +<freqband id="F1_5660_5700"> + <freqstart>5660</freqstart> <freqend>5700</freqend> + <chanwidth>20</chanwidth> <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> +</freqband> +<freqband id="H4_5660_5700"> + <freqstart>5660</freqstart> <freqend>5700</freqend> + <chanwidth>40</chanwidth> <chansep>20</chansep> + <flags>IEEE80211_CHAN_A</flags> +</freqband> <freqband id="H4_5725_5825"> <freqstart>5725</freqstart> <freqend>5825</freqend> <chanwidth>40</chanwidth> <chansep>20</chansep> diff --git a/kerberos5/Makefile b/kerberos5/Makefile index 366540c..d87fa16 100644 --- a/kerberos5/Makefile +++ b/kerberos5/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -SUBDIR= doc tools lib libexec usr.bin usr.sbin +SUBDIR= doc lib libexec usr.bin usr.sbin # These are the programs which depend on Kerberos. KPROGS= lib/libpam \ diff --git a/lib/csu/powerpc64/Makefile b/lib/csu/powerpc64/Makefile index 04926ad..095a9ad 100644 --- a/lib/csu/powerpc64/Makefile +++ b/lib/csu/powerpc64/Makefile @@ -4,15 +4,14 @@ SRCS= crt1.c crti.S crtn.S OBJS= ${SRCS:N*.h:R:S/$/.o/g} -OBJS+= gcrt1.o -CFLAGS+= -Wall -Wno-unused \ - -I${.CURDIR}/../common \ +OBJS+= Scrt1.o gcrt1.o +CFLAGS+= -I${.CURDIR}/../common \ -I${.CURDIR}/../../libc/include all: ${OBJS} CLEANFILES= ${OBJS} -CLEANFILES+= crt1.s gcrt1.s +CLEANFILES+= crt1.s gcrt1.s Scrt1.s # See the comment in lib/csu/common/crtbrand.c for the reason crt1.c is not # directly compiled to .o files. @@ -31,6 +30,13 @@ gcrt1.s: crt1.c gcrt1.o: gcrt1.s ${CC} ${CFLAGS} -c -o ${.TARGET} gcrt1.s +Scrt1.s: crt1.c + ${CC} ${CFLAGS} -fPIC -DPIC -S -o ${.TARGET} ${.CURDIR}/crt1.c + sed -i "" -e '/\.note\.ABI-tag/s/progbits/note/' ${.TARGET} + +Scrt1.o: Scrt1.s + ${CC} ${CFLAGS} -c -o ${.TARGET} Scrt1.s + realinstall: ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \ ${OBJS} ${DESTDIR}${LIBDIR} diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 5c8b793..1920555 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -175,7 +175,7 @@ prefix, corresponding with the device used to facilitate the user login session. If no TTY character device is used, this field is left blank. This field is only applicable to entries of type -.Dv USER_PROCESS +.Dv USER_PROCESS and .Dv LOGIN_PROCESS . .It Fa ut_host @@ -473,7 +473,7 @@ are extensions. .Sh HISTORY These functions appeared in .Fx 9.0 . -They replaced the +They replaced the .In utmp.h interface. .Sh AUTHORS diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3 index 3d902bf..73359b4 100644 --- a/lib/libc/gen/posix_spawn.3 +++ b/lib/libc/gen/posix_spawn.3 @@ -167,7 +167,7 @@ group IDs for the child process are changed as specified in the attributes object referenced by .Fa attrp . .It -The file actions specified by the spawn file actions object are +The file actions specified by the spawn file actions object are performed in the order in which they were added to the spawn file actions object. .It diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c index 58044b3..e4ceb20 100644 --- a/lib/libc/gen/posix_spawn.c +++ b/lib/libc/gen/posix_spawn.c @@ -182,7 +182,7 @@ process_file_actions(const posix_spawn_file_actions_t fa) if (error) return (error); } - return (0); + return (0); } static int @@ -193,7 +193,7 @@ do_posix_spawn(pid_t *pid, const char *path, { pid_t p; volatile int error = 0; - + p = vfork(); switch (p) { case -1: diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index 4caa00c..0cc7a01 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -57,7 +57,7 @@ futx_open(const char *file) errno = EFTYPE; return (NULL); } - + fp = fdopen(fd, "r+"); if (fp == NULL) { _close(fd); @@ -103,7 +103,7 @@ utx_active_add(const struct futx *fu) /* Allow us to overwrite unused records. */ if (partial == -1) { partial = ftello(fp); - /* + /* * Distinguish errors from valid values so we * don't overwrite good data by accident. */ diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 48d9c14..5290512 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -234,7 +234,7 @@ __FBSDID("$FreeBSD$"); #ifdef __sparc64__ # define LG_QUANTUM 4 # define LG_SIZEOF_PTR 3 -# define TLS_MODEL /* default */ +# define TLS_MODEL __attribute__((tls_model("initial-exec"))) #endif #ifdef __amd64__ # define LG_QUANTUM 4 diff --git a/lib/libc/stdlib/ptsname.c b/lib/libc/stdlib/ptsname.c index fc3b719..40b140d 100644 --- a/lib/libc/stdlib/ptsname.c +++ b/lib/libc/stdlib/ptsname.c @@ -82,7 +82,7 @@ ptsname(int fildes) /* Make sure fildes points to a master device. */ if (__isptmaster(fildes) != 0) goto done; - + if (fdevname_r(fildes, pt_slave + (sizeof _PATH_DEV - 1), sizeof pt_slave - (sizeof _PATH_DEV - 1)) != NULL) ret = pt_slave; diff --git a/lib/libmd/sha256.3 b/lib/libmd/sha256.3 index fb96100..f40e6df 100644 --- a/lib/libmd/sha256.3 +++ b/lib/libmd/sha256.3 @@ -127,7 +127,7 @@ argument is non-null it must point to at least 65 characters of buffer space. .Xr sha 3 .Sh HISTORY These functions appeared in -.Fx 4.0 . +.Fx 6.0 . .Sh AUTHORS The core hash routines were implemented by Colin Percival based on the published diff --git a/lib/libmd/sha512.3 b/lib/libmd/sha512.3 index 45a4096..953ee25 100644 --- a/lib/libmd/sha512.3 +++ b/lib/libmd/sha512.3 @@ -127,7 +127,7 @@ argument is non-null it must point to at least 65 characters of buffer space. .Xr sha 3 .Sh HISTORY These functions appeared in -.Fx 4.0 . +.Fx 9.0 . .Sh AUTHORS The core hash routines were implemented by Colin Percival based on the published diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile index e509169..05a64e7 100644 --- a/lib/libprocstat/Makefile +++ b/lib/libprocstat/Makefile @@ -19,6 +19,8 @@ INCS= libprocstat.h CFLAGS+= -I. -I${.CURDIR} -D_KVM_VNODE SHLIB_MAJOR= 1 WITHOUT_MAN= yes +DPADD= ${LIBKVM} ${LIBUTIL} +LDADD= -lkvm -lutil .if ${MK_NCP} != "no" CFLAGS+= -DLIBPROCSTAT_NWFS diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c index 54e184c..bf92c04 100644 --- a/lib/libstand/tftp.c +++ b/lib/libstand/tftp.c @@ -64,13 +64,13 @@ struct tftp_handle; static int tftp_open(const char *path, struct open_file *f); static int tftp_close(struct open_file *f); -static void tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len); +static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len); static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid); static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t tftp_seek(struct open_file *f, off_t offset, int where); static int tftp_set_blksize(struct tftp_handle *h, const char *str); static int tftp_stat(struct open_file *f, struct stat *sb); -static ssize_t sendrecv_tftp(struct tftp_handle *h, +static ssize_t sendrecv_tftp(struct tftp_handle *h, ssize_t (*sproc)(struct iodesc *, void *, size_t), void *sbuf, size_t ssize, ssize_t (*rproc)(struct tftp_handle *h, void *, ssize_t, time_t, unsigned short *), @@ -93,7 +93,7 @@ static int tftpport = 2000; static int is_open = 0; /* - * The legacy TFTP_BLKSIZE value was 512. + * The legacy TFTP_BLKSIZE value was SEGSIZE(512). * TFTP_REQUESTED_BLKSIZE of 1428 is (Ethernet MTU, less the TFTP, UDP and * IP header lengths). */ @@ -102,7 +102,7 @@ static int is_open = 0; /* * Choose a blksize big enough so we can test with Ethernet * Jumbo frames in the future. - */ + */ #define TFTP_MAX_BLKSIZE 9008 struct tftp_handle { @@ -113,7 +113,7 @@ struct tftp_handle { int off; char *path; /* saved for re-requests */ unsigned int tftp_blksize; - unsigned long tftp_tsize; + unsigned long tftp_tsize; struct { u_char header[HEADER_SIZE]; struct tftphdr t; @@ -121,7 +121,8 @@ struct tftp_handle { } __packed __aligned(4) lastdata; }; -static const int tftperrors[8] = { +#define TFTP_MAX_ERRCODE EOPTNEG +static const int tftperrors[TFTP_MAX_ERRCODE + 1] = { 0, /* ??? */ ENOENT, EPERM, @@ -129,10 +130,57 @@ static const int tftperrors[8] = { EINVAL, /* ??? */ EINVAL, /* ??? */ EEXIST, - EINVAL /* ??? */ + EINVAL, /* ??? */ + EINVAL, /* Option negotiation failed. */ }; -static ssize_t +static int tftp_getnextblock(struct tftp_handle *h); + +/* send error message back. */ +static void +tftp_senderr(struct tftp_handle *h, u_short errcode, const char *msg) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + u_char space[63]; /* +1 from t */ + } __packed __aligned(4) wbuf; + char *wtail; + int len; + + len = strlen(msg); + if (len > sizeof(wbuf.space)) + len = sizeof(wbuf.space); + + wbuf.t.th_opcode = htons((u_short) ERROR); + wbuf.t.th_code = htons(errcode); + + wtail = wbuf.t.th_msg; + bcopy(msg, wtail, len); + wtail[len] = '\0'; + wtail += len + 1; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); +} + +static void +tftp_sendack(struct tftp_handle *h) +{ + struct { + u_char header[HEADER_SIZE]; + struct tftphdr t; + } __packed __aligned(4) wbuf; + char *wtail; + + wbuf.t.th_opcode = htons((u_short) ACK); + wtail = (char *) &wbuf.t.th_block; + wbuf.t.th_block = htons((u_short) h->currblock); + wtail += 2; + + sendudp(h->iodesc, &wbuf.t, wtail - (char *) &wbuf.t); +} + +static ssize_t recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, unsigned short *rtype) { @@ -170,7 +218,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, return got; } case ERROR: - if ((unsigned) ntohs(t->th_code) >= 8) { + if ((unsigned) ntohs(t->th_code) > TFTP_MAX_ERRCODE) { printf("illegal tftp error %d\n", ntohs(t->th_code)); errno = EIO; } else { @@ -182,14 +230,30 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, return (-1); case OACK: { struct udphdr *uh; - int tftp_oack_len = len - sizeof(t->th_opcode); - tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len); + int tftp_oack_len; + + /* + * Unexpected OACK. TFTP transfer already in progress. + * Drop the pkt. + */ + if (d->xid != 1) { + return (-1); + } + /* - * Remember which port this OACK came from, - * because we need to send the ACK back to it. + * Remember which port this OACK came from, because we need + * to send the ACK or errors back to it. */ uh = (struct udphdr *) pkt - 1; d->destport = uh->uh_sport; + + /* Parse options ACK-ed by the server. */ + tftp_oack_len = len - sizeof(t->th_opcode); + if (tftp_parse_oack(h, t->th_u.tu_stuff, tftp_oack_len) != 0) { + tftp_senderr(h, EOPTNEG, "Malformed OACK"); + errno = EIO; + return (-1); + } return (0); } default: @@ -201,7 +265,7 @@ recvtftp(struct tftp_handle *h, void *pkt, ssize_t len, time_t tleft, } /* send request, expect first block (or error) */ -static int +static int tftp_makereq(struct tftp_handle *h) { struct { @@ -250,26 +314,28 @@ tftp_makereq(struct tftp_handle *h) h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->xid = 1; /* expected block */ + h->currblock = 0; + h->islastblock = 0; + h->validsize = 0; + res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype); - if (rtype == OACK) { - wbuf.t.th_opcode = htons((u_short)ACK); - wtail = (char *) &wbuf.t.th_block; - wbuf.t.th_block = htons(0); - wtail += 2; - rtype = 0; - res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, - &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype); - } + if (rtype == OACK) + return (tftp_getnextblock(h)); + + /* Server ignored our blksize request, revert to TFTP default. */ + h->tftp_blksize = SEGSIZE; switch (rtype) { case DATA: { h->currblock = 1; h->validsize = res; h->islastblock = 0; - if (res < h->tftp_blksize) + if (res < h->tftp_blksize) { h->islastblock = 1; /* very short file */ + tftp_sendack(h); + } return (0); } case ERROR: @@ -320,7 +386,7 @@ tftp_getnextblock(struct tftp_handle *h) return (0); } -static int +static int tftp_open(const char *path, struct open_file *f) { struct tftp_handle *tftpfile; @@ -365,7 +431,7 @@ tftp_open(const char *path, struct open_file *f) return (0); } -static int +static int tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid /* out */) { @@ -381,9 +447,11 @@ tftp_read(struct open_file *f, void *addr, size_t size, needblock = tftpfile->off / tftpfile->tftp_blksize + 1; - if (tftpfile->currblock > needblock) /* seek backwards */ + if (tftpfile->currblock > needblock) { /* seek backwards */ + tftp_senderr(tftpfile, 0, "No error: read aborted"); tftp_makereq(tftpfile); /* no error check, it worked * for open */ + } while (tftpfile->currblock < needblock) { int res; @@ -452,7 +520,7 @@ tftp_close(struct open_file *f) return (0); } -static int +static int tftp_write(struct open_file *f __unused, void *start __unused, size_t size __unused, size_t *resid __unused /* out */) { @@ -473,7 +541,7 @@ tftp_stat(struct open_file *f, struct stat *sb) return (0); } -static off_t +static off_t tftp_seek(struct open_file *f, off_t offset, int where) { struct tftp_handle *tftpfile; @@ -494,7 +562,7 @@ tftp_seek(struct open_file *f, off_t offset, int where) } static ssize_t -sendrecv_tftp(struct tftp_handle *h, +sendrecv_tftp(struct tftp_handle *h, ssize_t (*sproc)(struct iodesc *, void *, size_t), void *sbuf, size_t ssize, ssize_t (*rproc)(struct tftp_handle *, void *, ssize_t, time_t, unsigned short *), @@ -562,9 +630,9 @@ tftp_set_blksize(struct tftp_handle *h, const char *str) /* * Only accept blksize value if it is numeric. - * RFC2348 specifies that acceptable valuesare 8-65464 - * 8-65464 . Let's choose a limit less than MAXRSPACE - */ + * RFC2348 specifies that acceptable values are 8-65464. + * Let's choose a limit less than MAXRSPACE. + */ if (*endptr == '\0' && new_blksize >= 8 && new_blksize <= TFTP_MAX_BLKSIZE) { h->tftp_blksize = new_blksize; @@ -597,13 +665,12 @@ tftp_set_blksize(struct tftp_handle *h, const char *str) * optN, valueN * The final option/value acknowledgment pair. */ -static void +static int tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) { /* * We parse the OACK strings into an array * of name-value pairs. - * */ char *tftp_options[128] = { 0 }; char *val = buf; @@ -612,18 +679,22 @@ tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) int blksize_is_set = 0; int tsize = 0; - - while ( option_idx < 128 && i < len ) { - if (buf[i] == '\0') { - if (&buf[i] > val) { - tftp_options[option_idx] = val; - val = &buf[i] + 1; - ++option_idx; - } - } - ++i; + unsigned int orig_blksize; + + while (option_idx < 128 && i < len) { + if (buf[i] == '\0') { + if (&buf[i] > val) { + tftp_options[option_idx] = val; + val = &buf[i] + 1; + ++option_idx; + } + } + ++i; } + /* Save the block size we requested for sanity check later. */ + orig_blksize = h->tftp_blksize; + /* * Parse individual TFTP options. * * "blksize" is specified in RFC2348. @@ -631,27 +702,37 @@ tftp_parse_oack(struct tftp_handle *h, char *buf, size_t len) */ for (i = 0; i < option_idx; i += 2) { if (strcasecmp(tftp_options[i], "blksize") == 0) { - if (i + 1 < option_idx) { + if (i + 1 < option_idx) blksize_is_set = tftp_set_blksize(h, tftp_options[i + 1]); - } } else if (strcasecmp(tftp_options[i], "tsize") == 0) { - if (i + 1 < option_idx) { + if (i + 1 < option_idx) tsize = strtol(tftp_options[i + 1], (char **)NULL, 10); - } + } else { + /* Do not allow any options we did not expect to be ACKed. */ + printf("unexpected tftp option '%s'\n", tftp_options[i]); + return (-1); } } if (!blksize_is_set) { /* * If TFTP blksize was not set, try defaulting - * to the legacy TFTP blksize of 512 + * to the legacy TFTP blksize of SEGSIZE(512) */ - h->tftp_blksize = 512; + h->tftp_blksize = SEGSIZE; + } else if (h->tftp_blksize > orig_blksize) { + /* + * Server should not be proposing block sizes that + * exceed what we said we can handle. + */ + printf("unexpected blksize %u\n", h->tftp_blksize); + return (-1); } #ifdef TFTP_DEBUG printf("tftp_blksize: %u\n", h->tftp_blksize); printf("tftp_tsize: %lu\n", h->tftp_tsize); #endif + return 0; } diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile index debbfa2..f438cff 100644 --- a/lib/libusb/Makefile +++ b/lib/libusb/Makefile @@ -22,7 +22,7 @@ MLINKS+= libusb.3 usb.3 # libusb 0.1 compat INCS+= usb.h -SRCS+= libusb20_compat01.c +SRCS+= libusb01.c # libusb 1.0 compat INCS+= libusb.h @@ -184,6 +184,8 @@ MLINKS += libusb20.3 libusb20_dev_get_device_desc.3 MLINKS += libusb20.3 libusb20_dev_alloc_config.3 MLINKS += libusb20.3 libusb20_dev_alloc.3 MLINKS += libusb20.3 libusb20_dev_get_address.3 +MLINKS += libusb20.3 libusb20_dev_get_parent_address.3 +MLINKS += libusb20.3 libusb20_dev_get_parent_port.3 MLINKS += libusb20.3 libusb20_dev_get_bus_number.3 MLINKS += libusb20.3 libusb20_dev_get_mode.3 MLINKS += libusb20.3 libusb20_dev_get_speed.3 diff --git a/lib/libusb/libusb20_compat01.c b/lib/libusb/libusb01.c index 4124ef6..4124ef6 100644 --- a/lib/libusb/libusb20_compat01.c +++ b/lib/libusb/libusb01.c diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c index fa50ea7..737e610 100644 --- a/lib/libusb/libusb10.c +++ b/lib/libusb/libusb10.c @@ -636,7 +636,7 @@ libusb_clear_halt(struct libusb20_device *pdev, uint8_t endpoint) return (LIBUSB_ERROR_INVALID_PARAM); CTX_LOCK(dev->ctx); - err = libusb20_tr_open(xfer, 0, 0, endpoint); + err = libusb20_tr_open(xfer, 0, 1, endpoint); CTX_UNLOCK(dev->ctx); if (err != 0 && err != LIBUSB20_ERROR_BUSY) diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3 index 93dfe18..042f885 100644 --- a/lib/libusb/libusb20.3 +++ b/lib/libusb/libusb20.3 @@ -159,6 +159,10 @@ USB access library (libusb -lusb) .Ft uint8_t .Fn libusb20_dev_get_address "struct libusb20_device *pdev" .Ft uint8_t +.Fn libusb20_dev_get_parent_address "struct libusb20_device *pdev" +.Ft uint8_t +.Fn libusb20_dev_get_parent_port "struct libusb20_device *pdev" +.Ft uint8_t .Fn libusb20_dev_get_bus_number "struct libusb20_device *pdev" .Ft uint8_t .Fn libusb20_dev_get_mode "struct libusb20_device *pdev" @@ -756,12 +760,31 @@ is an internal function to allocate a new USB device. .Fn libusb20_dev_get_address returns the internal and not necessarily the real hardware address of the given USB device. +Valid addresses start at one. +. +.Pp +. +.Fn libusb20_dev_get_parent_address +returns the internal and not necessarily the real hardware address of +the given parent USB HUB device. +This value is zero for the root HUB which usually has a device address +equal to one. +Valid addresses start at one. +. +.Pp +. +.Fn libusb20_dev_get_parent_port +returns the port number on the parent USB HUB device. +This value is zero for the root HUB which usually has a device address +equal to one. +Valid port numbers start at one. . .Pp . .Fn libusb20_dev_get_bus_number returns the internal bus number which the given USB device belongs to. +Valid bus numbers start at zero. . .Pp . diff --git a/lib/libusb/libusb20.c b/lib/libusb/libusb20.c index bcaa1e4..716f540 100644 --- a/lib/libusb/libusb20.c +++ b/lib/libusb/libusb20.c @@ -1057,6 +1057,18 @@ libusb20_dev_get_address(struct libusb20_device *pdev) } uint8_t +libusb20_dev_get_parent_address(struct libusb20_device *pdev) +{ + return (pdev->parent_address); +} + +uint8_t +libusb20_dev_get_parent_port(struct libusb20_device *pdev) +{ + return (pdev->parent_port); +} + +uint8_t libusb20_dev_get_bus_number(struct libusb20_device *pdev) { return (pdev->bus_number); diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h index 958a379..22a2899 100644 --- a/lib/libusb/libusb20.h +++ b/lib/libusb/libusb20.h @@ -262,6 +262,8 @@ struct LIBUSB20_DEVICE_DESC_DECODED *libusb20_dev_get_device_desc(struct libusb2 struct libusb20_config *libusb20_dev_alloc_config(struct libusb20_device *pdev, uint8_t config_index); struct libusb20_device *libusb20_dev_alloc(void); uint8_t libusb20_dev_get_address(struct libusb20_device *pdev); +uint8_t libusb20_dev_get_parent_address(struct libusb20_device *pdev); +uint8_t libusb20_dev_get_parent_port(struct libusb20_device *pdev); uint8_t libusb20_dev_get_bus_number(struct libusb20_device *pdev); uint8_t libusb20_dev_get_mode(struct libusb20_device *pdev); uint8_t libusb20_dev_get_speed(struct libusb20_device *pdev); diff --git a/lib/libusb/libusb20_int.h b/lib/libusb/libusb20_int.h index 2ecfb47..bef4d02 100644 --- a/lib/libusb/libusb20_int.h +++ b/lib/libusb/libusb20_int.h @@ -226,6 +226,8 @@ struct libusb20_device { uint8_t usb_mode; uint8_t usb_speed; uint8_t is_opened; + uint8_t parent_address; + uint8_t parent_port; char usb_desc[96]; }; diff --git a/lib/libusb/libusb20_ugen20.c b/lib/libusb/libusb20_ugen20.c index 933d728..307ed96 100644 --- a/lib/libusb/libusb20_ugen20.c +++ b/lib/libusb/libusb20_ugen20.c @@ -195,6 +195,11 @@ ugen20_enumerate(struct libusb20_device *pdev, const char *id) break; } + /* get parent HUB index and port */ + + pdev->parent_address = devinfo.udi_hubindex; + pdev->parent_port = devinfo.udi_hubport; + /* generate a nice description for printout */ snprintf(pdev->usb_desc, sizeof(pdev->usb_desc), diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c index 21c218e..5894f3c 100644 --- a/libexec/ftpd/ftpd.c +++ b/libexec/ftpd/ftpd.c @@ -1191,9 +1191,9 @@ end_login(void) ftpd_logwtmp(wtmpid, NULL, NULL); pw = NULL; #ifdef LOGIN_CAP - setusercontext(NULL, getpwuid(0), 0, - LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK| - LOGIN_SETMAC); + setusercontext(NULL, getpwuid(0), 0, LOGIN_SETALL & ~(LOGIN_SETLOGIN | + LOGIN_SETUSER | LOGIN_SETGROUP | LOGIN_SETPATH | + LOGIN_SETENV)); #endif #ifdef USE_PAM if (pamh) { @@ -1465,9 +1465,8 @@ skip: return; } } - setusercontext(lc, pw, 0, - LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY| - LOGIN_SETRESOURCES|LOGIN_SETUMASK|LOGIN_SETMAC); + setusercontext(lc, pw, 0, LOGIN_SETALL & + ~(LOGIN_SETUSER | LOGIN_SETPATH | LOGIN_SETENV)); #else setlogin(pw->pw_name); (void) initgroups(pw->pw_name, pw->pw_gid); diff --git a/libexec/tftpd/tftp-file.c b/libexec/tftpd/tftp-file.c index 1ef8820..6b8fb6e 100644 --- a/libexec/tftpd/tftp-file.c +++ b/libexec/tftpd/tftp-file.c @@ -27,6 +27,8 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> #include <sys/stat.h> #include <netinet/in.h> @@ -249,9 +251,34 @@ read_close(void) } +/* When an error has occurred, it is possible that the two sides + * are out of synch. Ie: that what I think is the other side's + * response to packet N is really their response to packet N-1. + * + * So, to try to prevent that, we flush all the input queued up + * for us on the network connection on our host. + * + * We return the number of packets we flushed (mostly for reporting + * when trace is active). + */ + int -synchnet(int peer __unused) +synchnet(int peer) /* socket to flush */ { - - return 0; + int i, j = 0; + char rbuf[MAXPKTSIZE]; + struct sockaddr_storage from; + socklen_t fromlen; + + while (1) { + (void) ioctl(peer, FIONREAD, &i); + if (i) { + j++; + fromlen = sizeof from; + (void) recvfrom(peer, rbuf, sizeof (rbuf), 0, + (struct sockaddr *)&from, &fromlen); + } else { + return(j); + } + } } diff --git a/libexec/tftpd/tftpd.8 b/libexec/tftpd/tftpd.8 index 3bac492..96bd24c 100644 --- a/libexec/tftpd/tftpd.8 +++ b/libexec/tftpd/tftpd.8 @@ -32,7 +32,7 @@ .\" @(#)tftpd.8 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd September 14, 2000 +.Dd June 22, 2011 .Dt TFTPD 8 .Os .Sh NAME @@ -150,9 +150,27 @@ compatible format string for the creation of the suffix if .Fl W is specified. By default the string "%Y%m%d" is used. -.It Fl d +.It Fl d, d Ar [value] Enables debug output. -If specified twice, it will log DATA and ACK packets too. +If +.Ar value +is not specified, then the debug level is increased by one +for each instance of +.Fl d +which is specified. +.Pp +If +.Ar value +is specified, then the debug level is set to +.Ar value . +The debug level is a bitmask implemented in +.Pa src/libexec/tftpd/tftp-utils.h . +Valid values are 0 (DEBUG_NONE), 1 (DEBUG_PACKETS), 2, (DEBUG_SIMPLE), +4 (DEBUG_OPTIONS), and 8 (DEBUG_ACCESS). Multiple debug values can be combined +in the bitmask by logically OR'ing the values. For example, specifying +.Fl d +.Ar 15 +will enable all the debug values. .It Fl l Log all requests using .Xr syslog 3 @@ -217,12 +235,34 @@ option. .Xr services 5 , .Xr syslog.conf 5 , .Xr inetd 8 +.Pp +The following RFC's are supported: .Rs -.%A K. R. Sollins +RFC 1350 .%T The TFTP Protocol (Revision 2) -.%D July 1992 -.%O RFC 1350, STD 33 .Re +.Rs +RFC 2347 +.%T TFTP Option Extension +.Re +.Rs +RFC 2348 +.%T TFTP Blocksize Option +.Re +.Rs +RFC 2349 +.%T TFTP Timeout Interval and Transfer Size Options +.Re +.Pp +The non-standard +.Cm rollover +and +.Cm blksize2 +TFTP options are mentioned here: +.Rs +.%T Extending TFTP +.%U http://www.compuphase.com/tftp.htm +.Re .Sh HISTORY The .Nm @@ -253,9 +293,15 @@ was introduced in support for the TFTP Blocksize Option (RFC2348) and the blksize2 option was introduced in .Fx 7.4 . +.Pp +Edwin Groothuis <edwin@FreeBSD.org> performed a major rewrite of the +.Nm +and +.Xr tftp 1 +code to support RFC2348. .Sh NOTES Files larger than 33488896 octets (65535 blocks) cannot be transferred -without client and server supporting the the TFTP blocksize option (RFC2348), +without client and server supporting the TFTP blocksize option (RFC2348), or the non-standard TFTP rollover option. .Pp Many tftp clients will not transfer files over 16744448 octets (32767 blocks). diff --git a/libexec/ulog-helper/Makefile b/libexec/ulog-helper/Makefile index 3c1770c..c1697c8 100644 --- a/libexec/ulog-helper/Makefile +++ b/libexec/ulog-helper/Makefile @@ -5,7 +5,7 @@ BINOWN= root BINMODE=4555 NO_MAN= -DPADD= ${LIBULOG} ${LIBMD} -LDADD= -lulog -lmd +DPADD= ${LIBULOG} +LDADD= -lulog .include <bsd.prog.mk> diff --git a/libexec/ulog-helper/ulog-helper.c b/libexec/ulog-helper/ulog-helper.c index eaef778..31b40e9 100644 --- a/libexec/ulog-helper/ulog-helper.c +++ b/libexec/ulog-helper/ulog-helper.c @@ -36,11 +36,11 @@ __FBSDID("$FreeBSD$"); /* * This setuid helper utility writes user login records to disk. - * Unprivileged processes are not capable of writing records to utmp, - * wtmp and lastlog, but we do want to allow this for pseudo-terminals. - * Because a file descriptor to a pseudo-terminal master device can only - * be obtained by processes using the pseudo-terminal, we expect such a - * descriptor on stdin. + * Unprivileged processes are not capable of writing records to utmpx, + * but we do want to allow this for pseudo-terminals. Because a file + * descriptor to a pseudo-terminal master device can only be obtained by + * processes using the pseudo-terminal, we expect such a descriptor on + * stdin. * * It uses the real user ID of the calling process to determine the * username. It does allow users to log arbitrary hostnames. @@ -49,26 +49,22 @@ __FBSDID("$FreeBSD$"); int main(int argc, char *argv[]) { - const char *line; + const char *line, *user, *host; /* Device line name. */ if ((line = ptsname(STDIN_FILENO)) == NULL) return (EX_USAGE); if ((argc == 2 || argc == 3) && strcmp(argv[1], "login") == 0) { - struct passwd *pwd; - const char *host = NULL; - /* Username. */ - pwd = getpwuid(getuid()); - if (pwd == NULL) + user = user_from_uid(getuid(), 1); + if (user == NULL) return (EX_OSERR); /* Hostname. */ - if (argc == 3) - host = argv[2]; + host = argc == 3 ? argv[2] : NULL; - ulog_login(line, pwd->pw_name, host); + ulog_login(line, user, host); return (EX_OK); } else if (argc == 2 && strcmp(argv[1], "logout") == 0) { ulog_logout(line); diff --git a/release/doc/en_US.ISO8859-1/readme/article.sgml b/release/doc/en_US.ISO8859-1/readme/article.sgml index 33ae82c..f8ba3aa 100644 --- a/release/doc/en_US.ISO8859-1/readme/article.sgml +++ b/release/doc/en_US.ISO8859-1/readme/article.sgml @@ -184,8 +184,7 @@ <para>Lists of locations that mirror &os; can be found in the <ulink url="&url.books.handbook;/mirrors-ftp.html">FTP - Sites</ulink> section of the Handbook, or on the <ulink - url="http://mirrorlist.FreeBSD.org/"></ulink> Web pages. + Sites</ulink> section of the Handbook. Finding a close (in networking terms) mirror from which to download the distribution is highly recommended.</para> diff --git a/release/doc/share/sgml/release.ent b/release/doc/share/sgml/release.ent index 0a4c1ce..60b7130 100644 --- a/release/doc/share/sgml/release.ent +++ b/release/doc/share/sgml/release.ent @@ -36,8 +36,8 @@ <!-- The manpaths for man page references --> <!ENTITY release.man.url "http://www.FreeBSD.org/cgi/man.cgi"> -<!ENTITY release.manpath.xorg "7.4"> -<!ENTITY release.manpath.netbsd "5.0.1"> +<!ENTITY release.manpath.xorg "7.5.1"> +<!ENTITY release.manpath.netbsd "5.1"> <!ENTITY release.manpath.freebsd-ports "Ports"> <!ENTITY release.manpath.freebsd "9-current"> diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c index b4aa679..ec8b5ab 100644 --- a/sbin/fsck_ffs/suj.c +++ b/sbin/fsck_ffs/suj.c @@ -2261,6 +2261,7 @@ suj_build(void) blk_build((struct jblkrec *)rec); break; case JOP_TRUNC: + case JOP_SYNC: ino_build_trunc((struct jtrncrec *)rec); break; default: diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c index eaf5845..a456911 100644 --- a/sbin/geom/class/part/geom_part.c +++ b/sbin/geom/class/part/geom_part.c @@ -362,7 +362,7 @@ gpart_autofill_resize(struct gctl_req *req) goto done; } - offset = pp->lg_stripeoffset / pp->lg_sectorsize; + offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { s = find_provcfg(pp, "index"); @@ -497,10 +497,10 @@ gpart_autofill(struct gctl_req *req) alignment = len; /* Adjust parameters to stripeoffset */ - offset = pp->lg_stripeoffset / pp->lg_sectorsize; + offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment; start = ALIGNUP(start + offset, alignment); - if (size + offset > alignment) - size = ALIGNDOWN(size + offset, alignment); + if (size > alignment) + size = ALIGNDOWN(size, alignment); first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0); last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0); @@ -1208,8 +1208,11 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl) if (idx == 0) errx(EXIT_FAILURE, "missing -i option"); gpart_write_partcode(gp, idx, partcode, partsize); - } else + } else { + if (partsize != VTOC_BOOTSIZE) + errx(EXIT_FAILURE, "invalid bootcode"); gpart_write_partcode_vtoc8(gp, idx, partcode); + } } else if (bootcode == NULL) errx(EXIT_FAILURE, "no -b nor -p"); diff --git a/sbin/growfs/growfs.8 b/sbin/growfs/growfs.8 index 2e90c79..819e0bd 100644 --- a/sbin/growfs/growfs.8 +++ b/sbin/growfs/growfs.8 @@ -37,12 +37,12 @@ .\" $TSHeader: src/sbin/growfs/growfs.8,v 1.3 2000/12/12 19:31:00 tomsoft Exp $ .\" $FreeBSD$ .\" -.Dd May 8, 2011 +.Dd June 29, 2011 .Dt GROWFS 8 .Os .Sh NAME .Nm growfs -.Nd grow size of an existing UFS file system +.Nd expand an existing UFS file system .Sh SYNOPSIS .Nm .Op Fl Ny @@ -60,11 +60,11 @@ the disk must be labeled to a bigger size using .Xr bsdlabel 8 . If you wish to grow a file system beyond the boundary of the slice it resides in, you must re-size the slice using -.Xr fdisk 8 +.Xr gpart 8 before running .Nm . If you are using volumes you must enlarge them by using -.Xr vinum 8 . +.Xr gvinum 8 . The .Nm utility extends the size of the file system on the specified special file. @@ -119,12 +119,12 @@ up to 2GB if there is enough space in .Sh SEE ALSO .Xr bsdlabel 8 , .Xr dumpfs 8 , -.Xr fdisk 8 , .Xr ffsinfo 8 , .Xr fsck 8 , +.Xr gpart 8 , +.Xr gvinum 8 , .Xr newfs 8 , -.Xr tunefs 8 , -.Xr vinum 8 +.Xr tunefs 8 .Sh HISTORY The .Nm diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index 45a7237..148f8ca 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -2146,8 +2146,8 @@ main(int argc, char **argv) if(ExpertFlag == 0) { for(j=0; j<FSMAXSNAP; j++) { if(sblock.fs_snapinum[j]) { - errx(1, "active snapshot found in file system\n" - " please remove all snapshots before " + errx(1, "active snapshot found in file system; " + "please remove all snapshots before " "using growfs"); } if(!sblock.fs_snapinum[j]) { /* list is dense */ @@ -2159,16 +2159,16 @@ main(int argc, char **argv) if (ExpertFlag == 0 && Nflag == 0) { printf("We strongly recommend you to make a backup " - "before growing the Filesystem\n\n" - " Did you backup your data (Yes/No) ? "); + "before growing the file system.\n" + "Did you backup your data (Yes/No)? "); fgets(reply, (int)sizeof(reply), stdin); if (strcmp(reply, "Yes\n")){ - printf("\n Nothing done \n"); + printf("\nNothing done\n"); exit (0); } } - printf("new file systemsize is: %jd frags\n", (intmax_t)sblock.fs_size); + printf("New file system size is %jd frags\n", (intmax_t)sblock.fs_size); /* * Try to access our new last block in the file system. Even if we diff --git a/sbin/hastctl/Makefile b/sbin/hastctl/Makefile index b7b1db9..af946a2 100644 --- a/sbin/hastctl/Makefile +++ b/sbin/hastctl/Makefile @@ -21,6 +21,7 @@ MAN= hastctl.8 NO_WFORMAT= CFLAGS+=-I${.CURDIR}/../hastd +CFLAGS+=-DHAVE_CAPSICUM CFLAGS+=-DINET .if ${MK_INET6_SUPPORT} != "no" CFLAGS+=-DINET6 diff --git a/sbin/hastd/Makefile b/sbin/hastd/Makefile index 1ffd0a2..3c4eef1 100644 --- a/sbin/hastd/Makefile +++ b/sbin/hastd/Makefile @@ -20,8 +20,9 @@ SRCS+= y.tab.h MAN= hastd.8 hast.conf.5 NO_WFORMAT= -CFLAGS+=-DPROTO_TCP_DEFAULT_PORT=8457 CFLAGS+=-I${.CURDIR} +CFLAGS+=-DHAVE_CAPSICUM +CFLAGS+=-DPROTO_TCP_DEFAULT_PORT=8457 CFLAGS+=-DINET .if ${MK_INET6_SUPPORT} != "no" CFLAGS+=-DINET6 diff --git a/sbin/hastd/activemap.c b/sbin/hastd/activemap.c index 2777ac5..127b2c8 100644 --- a/sbin/hastd/activemap.c +++ b/sbin/hastd/activemap.c @@ -205,7 +205,7 @@ keepdirty_find(struct activemap *amp, int extent) return (kd); } -static void +static bool keepdirty_add(struct activemap *amp, int extent) { struct keepdirty *kd; @@ -217,7 +217,7 @@ keepdirty_add(struct activemap *amp, int extent) */ TAILQ_REMOVE(&->am_keepdirty, kd, kd_next); TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); - return; + return (false); } /* * Add new element, but first remove the most unused one if @@ -238,6 +238,8 @@ keepdirty_add(struct activemap *amp, int extent) amp->am_nkeepdirty++; TAILQ_INSERT_HEAD(&->am_keepdirty, kd, kd_next); } + + return (true); } static void @@ -308,9 +310,9 @@ activemap_write_start(struct activemap *amp, off_t offset, off_t length) assert(!bit_test(amp->am_memmap, ext)); bit_set(amp->am_memmap, ext); amp->am_ndirty++; - modified = true; } - keepdirty_add(amp, ext); + if (keepdirty_add(amp, ext)) + modified = true; } return (modified); @@ -345,7 +347,8 @@ activemap_write_complete(struct activemap *amp, off_t offset, off_t length) if (--amp->am_memtab[ext] == 0) { bit_clear(amp->am_memmap, ext); amp->am_ndirty--; - modified = true; + if (keepdirty_find(amp, ext) == NULL) + modified = true; } } diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c index af0f353..e1f2ba4 100644 --- a/sbin/hastd/primary.c +++ b/sbin/hastd/primary.c @@ -1687,8 +1687,11 @@ ggate_send_thread(void *arg) } if (ggio->gctl_error == 0 && ggio->gctl_cmd == BIO_WRITE) { mtx_lock(&res->hr_amp_lock); - activemap_write_complete(res->hr_amp, - ggio->gctl_offset, ggio->gctl_length); + if (activemap_write_complete(res->hr_amp, + ggio->gctl_offset, ggio->gctl_length)) { + res->hr_stat_activemap_update++; + (void)hast_activemap_flush(res); + } mtx_unlock(&res->hr_amp_lock); } if (ggio->gctl_cmd == BIO_WRITE) { diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c index 806338b..89ffda0 100644 --- a/sbin/hastd/subr.c +++ b/sbin/hastd/subr.c @@ -31,7 +31,9 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#ifdef HAVE_CAPSICUM #include <sys/capability.h> +#endif #include <sys/param.h> #include <sys/disk.h> #include <sys/ioctl.h> @@ -230,9 +232,15 @@ drop_privs(struct hast_resource *res) * ioctls and secondary uses ioctls to handle BIO_DELETE and BIO_FLUSH. * For now capsicum is only used to sandbox hastctl. */ - if (res == NULL) +#ifdef HAVE_CAPSICUM + if (res == NULL) { capsicum = (cap_enter() == 0); - else + if (!capsicum) { + pjdlog_common(LOG_DEBUG, 1, errno, + "Unable to sandbox using capsicum"); + } + } else +#endif capsicum = false; /* diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 4a22320..6fc12c8 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 14, 2011 +.Dd June 29, 2011 .Dt IPFW 8 .Os .Sh NAME @@ -822,6 +822,78 @@ skipto, but care should be used, as no destination caching is possible in this case so the rules are always walked to find it, starting from the .Cm skipto . +.It Cm call Ar number | tablearg +The current rule number is saved in the internal stack and +ruleset processing continues with the first rule numbered +.Ar number +or higher. +If later a rule with the +.Cm return +action is encountered, the processing returns to the first rule +with number of this +.Cm call +rule plus one or higher +(the same behaviour as with packets returning from +.Xr divert 4 +socket after a +.Cm divert +action). +This could be used to make somewhat like an assembly language +.Dq subroutine +calls to rules with common checks for different interfaces, etc. +.Pp +Rule with any number could be called, not just forward jumps as with +.Cm skipto . +So, to prevent endless loops in case of mistakes, both +.Cm call +and +.Cm return +actions don't do any jumps and simply go to the next rule if memory +can't be allocated or stack overflowed/undeflowed. +.Pp +Internally stack for rule numbers is implemented using +.Xr mbuf_tags 9 +facility and currently has size of 16 entries. +As mbuf tags are lost when packet leaves the kernel, +.Cm divert +should not be used in subroutines to avoid endless loops +and other undesired effects. +.It Cm return +Takes rule number saved to internal stack by the last +.Cm call +action and returns ruleset processing to the first rule +with number greater than number of corresponding +.Cm call +rule. See description of the +.Cm call +action for more details. +.Pp +Note that +.Cm return +rules usually end a +.Dq subroutine +and thus are unconditional, but +.Nm +command-line utility currently requires every action except +.Cm check-state +to have body. +While it is sometimes useful to return only on some packets, +usually you want to print just +.Dq return +for readability. +A workaround for this is to use new syntax and +.Fl c +switch: +.Pp +.Bd -literal -offset indent +# Add a rule without actual body +ipfw add 2999 return via any + +# List rules without "from any to any" part +ipfw -c list +.Ed +.Pp +This cosmetic annoyance may be fixed in future releases. .It Cm tee Ar port Send a copy of packets matching this rule to the .Xr divert 4 @@ -3253,3 +3325,18 @@ for the respective conversations. To avoid failures of network error detection and path MTU discovery, ICMP error messages may need to be allowed explicitly through static rules. +.Pp +Rules using +.Cm call +and +.Cm return +actions may lead to confusing behaviour if ruleset has mistakes, +and/or interaction with other subsystems (netgraph, dummynet, etc.) is used. +One possible case for this is packet leaving +.Nm +in subroutine on the input pass, while later on output encountering unpaired +.Cm return +first. +As the call stack is kept intact after input pass, packet will suddenly +return to the rule number used on input pass, not on output one. +Order of processing should be checked carefully to avoid such mistakes. diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 64e5eb1..e259f5e 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -214,6 +214,8 @@ static struct _s_x rule_actions[] = { { "nat", TOK_NAT }, { "reass", TOK_REASS }, { "setfib", TOK_SETFIB }, + { "call", TOK_CALL }, + { "return", TOK_RETURN }, { NULL, 0 } /* terminator */ }; @@ -1136,6 +1138,13 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) printf("reass"); break; + case O_CALLRETURN: + if (cmd->len & F_NOT) + printf("return"); + else + PRINT_UINT_ARG("call ", cmd->arg1); + break; + default: printf("** unrecognized action %d len %d ", cmd->opcode, cmd->len); @@ -2771,6 +2780,9 @@ ipfw_add(char *av[]) goto chkarg; case TOK_TEE: action->opcode = O_TEE; + goto chkarg; + case TOK_CALL: + action->opcode = O_CALLRETURN; chkarg: if (!av[0]) errx(EX_USAGE, "missing argument for %s", *(av - 1)); @@ -2863,6 +2875,10 @@ chkarg: action->opcode = O_REASS; break; + case TOK_RETURN: + fill_cmd(action, O_CALLRETURN, F_NOT, 0); + break; + default: errx(EX_DATAERR, "invalid action %s\n", av[-1]); } diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 9562f32..bade0dd 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -99,6 +99,8 @@ enum tokens { TOK_CHECKSTATE, TOK_NAT, TOK_REASS, + TOK_CALL, + TOK_RETURN, TOK_ALTQ, TOK_LOG, diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c index 109b62b..433ce7d 100644 --- a/sbin/ipfw/main.c +++ b/sbin/ipfw/main.c @@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav) save_av = av; optind = optreset = 1; /* restart getopt() */ - while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1) + while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1) switch (ch) { case 'a': do_acct = 1; @@ -306,6 +306,10 @@ ipfw_main(int oldac, char **oldav) co.do_resolv = 1; break; + case 'p': + errx(EX_USAGE, "An absolute pathname must be used " + "with -p option."); + case 'q': co.do_quiet = 1; break; @@ -603,9 +607,12 @@ main(int ac, char *av[]) * as a file to be preprocessed. */ - if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) - ipfw_readfile(ac, av); - else { + if (ac > 1 && av[ac - 1][0] == '/') { + if (access(av[ac - 1], R_OK) == 0) + ipfw_readfile(ac, av); + else + err(EX_USAGE, "pathname: %s", av[ac - 1]); + } else { if (ipfw_main(ac, av)) { errx(EX_USAGE, "usage: ipfw [options]\n" diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c index ecb5d8a..c95a625 100644 --- a/sbin/ipfw/nat.c +++ b/sbin/ipfw/nat.c @@ -738,7 +738,8 @@ ipfw_config_nat(int ac, char **av) char *id, *buf, **av1, *end; size_t len; - av++; ac--; + av++; + ac--; /* Nat id. */ if (ac == 0) errx(EX_DATAERR, "missing nat id"); @@ -746,7 +747,8 @@ ipfw_config_nat(int ac, char **av) i = (int)strtol(id, &end, 0); if (i <= 0 || *end != '\0') errx(EX_DATAERR, "illegal nat id: %s", id); - av++; ac--; + av++; + ac--; if (ac == 0) errx(EX_DATAERR, "missing option"); @@ -755,11 +757,13 @@ ipfw_config_nat(int ac, char **av) av1 = av; while (ac1 > 0) { tok = match_token(nat_params, *av1); - ac1--; av1++; + ac1--; + av1++; switch (tok) { case TOK_IP: case TOK_IF: - ac1--; av1++; + ac1--; + av1++; break; case TOK_ALOG: case TOK_DENY_INC: @@ -775,30 +779,40 @@ ipfw_config_nat(int ac, char **av) errx(EX_DATAERR, "redirect_addr: " "not enough arguments"); len += estimate_redir_addr(&ac1, &av1); - av1 += 2; ac1 -= 2; + av1 += 2; + ac1 -= 2; break; case TOK_REDIR_PORT: if (ac1 < 3) errx(EX_DATAERR, "redirect_port: " "not enough arguments"); - av1++; ac1--; + av1++; + ac1--; len += estimate_redir_port(&ac1, &av1); - av1 += 2; ac1 -= 2; + av1 += 2; + ac1 -= 2; /* Skip optional remoteIP/port */ - if (ac1 != 0 && isdigit(**av1)) - av1++; ac1--; + if (ac1 != 0 && isdigit(**av1)) { + av1++; + ac1--; + } break; case TOK_REDIR_PROTO: if (ac1 < 2) errx(EX_DATAERR, "redirect_proto: " "not enough arguments"); len += sizeof(struct cfg_redir); - av1 += 2; ac1 -= 2; + av1 += 2; + ac1 -= 2; /* Skip optional remoteIP/port */ - if (ac1 != 0 && isdigit(**av1)) - av1++; ac1--; - if (ac1 != 0 && isdigit(**av1)) - av1++; ac1--; + if (ac1 != 0 && isdigit(**av1)) { + av1++; + ac1--; + } + if (ac1 != 0 && isdigit(**av1)) { + av1++; + ac1--; + } break; default: errx(EX_DATAERR, "unrecognised option ``%s''", av1[-1]); @@ -816,7 +830,8 @@ ipfw_config_nat(int ac, char **av) while (ac > 0) { tok = match_token(nat_params, *av); - ac--; av++; + ac--; + av++; switch (tok) { case TOK_IP: if (ac == 0) @@ -824,13 +839,15 @@ ipfw_config_nat(int ac, char **av) if (!inet_aton(av[0], &(n->ip))) errx(EX_DATAERR, "bad ip address ``%s''", av[0]); - ac--; av++; + ac--; + av++; break; case TOK_IF: if (ac == 0) errx(EX_DATAERR, "missing option"); set_addr_dynamic(av[0], n); - ac--; av++; + ac--; + av++; break; case TOK_ALOG: n->mode |= PKT_ALIAS_LOG; @@ -909,7 +926,8 @@ ipfw_show_nat(int ac, char **av) data = NULL; frule = 0; lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */ - ac--; av++; + ac--; + av++; if (co.test_only) return; diff --git a/sbin/newfs/newfs.8 b/sbin/newfs/newfs.8 index 9d454cf..7cfdfd1 100644 --- a/sbin/newfs/newfs.8 +++ b/sbin/newfs/newfs.8 @@ -28,7 +28,7 @@ .\" @(#)newfs.8 8.6 (Berkeley) 5/3/95 .\" $FreeBSD$ .\" -.Dd May 25, 2011 +.Dd June 22, 2011 .Dt NEWFS 8 .Os .Sh NAME @@ -297,6 +297,7 @@ on file systems that contain many small files. .Xr dumpfs 8 , .Xr fsck 8 , .Xr gjournal 8 , +.Xr growfs 8 , .Xr makefs 8 , .Xr mount 8 , .Xr tunefs 8 , diff --git a/sbin/pflogd/Makefile b/sbin/pflogd/Makefile index ecd06f4..ea37bd1 100644 --- a/sbin/pflogd/Makefile +++ b/sbin/pflogd/Makefile @@ -8,7 +8,7 @@ MAN= pflogd.8 CFLAGS+=-include ${.CURDIR}/../../lib/libpcap/config.h -LDADD= -lpcap -lutil +LDADD= -lpcap DPADD= ${LIBPCAP} ${LIBUTIL} WARNS?= 2 diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c index d54fcf5..ea715f3 100644 --- a/sbin/savecore/savecore.c +++ b/sbin/savecore/savecore.c @@ -66,7 +66,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/disk.h> #include <sys/kerneldump.h> -#include <sys/param.h> #include <sys/mount.h> #include <sys/stat.h> #include <errno.h> diff --git a/sbin/tunefs/tunefs.8 b/sbin/tunefs/tunefs.8 index 3b4e944..5b522e5 100644 --- a/sbin/tunefs/tunefs.8 +++ b/sbin/tunefs/tunefs.8 @@ -28,7 +28,7 @@ .\" @(#)tunefs.8 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd May 8, 2011 +.Dd June 22, 2011 .Dt TUNEFS 8 .Os .Sh NAME @@ -165,6 +165,7 @@ specified mount point. .Xr fs 5 , .Xr dumpfs 8 , .Xr gjournal 8 , +.Xr growfs 8 , .Xr newfs 8 .Rs .%A M. McKusick diff --git a/share/man/man4/jme.4 b/share/man/man4/jme.4 index 4220ab5..0bcf652 100644 --- a/share/man/man4/jme.4 +++ b/share/man/man4/jme.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 20, 2010 +.Dd June 29, 2011 .Dt JME 4 .Os .Sh NAME @@ -178,3 +178,17 @@ address once station address is reprogrammed via eFuse. It is highly recommended not to reprogram station address and it is responsibility of administrator to store original station address into a safe place when station address should be changed. +.Pp +There are two known 1000baseT link establishment issues with JMC25x. +If the full mask revision number of JMC25x controller is less than +or equal to 4 and link partner enabled IEEE 802.3az Energy Efficient +Ethernet feature, the controller would not be able to establish a +1000baseT link. +Also if the length of cable is longer than 120 meters, controller +can not establish a 1000baseT link. +The known workaround for the issue is to force manual link +configuration with 100baseTX instead of relying on auto-negotiation. +The full mask revision number of controller could be checked with +verbose kernel boot option. +Use lower nibble of chip revision number to get full mask revision of +the controller. diff --git a/share/man/man4/ng_ether.4 b/share/man/man4/ng_ether.4 index 9fd409d..6ca5c11 100644 --- a/share/man/man4/ng_ether.4 +++ b/share/man/man4/ng_ether.4 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 4, 2006 +.Dd June 23, 2011 .Dt NG_ETHER 4 .Os .Sh NAME @@ -183,7 +183,6 @@ Detach from underlying Ethernet interface and shut down node. Upon receipt of the .Dv NGM_SHUTDOWN control message, all hooks are disconnected, promiscuous mode is disabled, -and the source address override flag is re-enabled, but the node is not removed. Node can be shut down only using .Dv NGM_ETHER_DETACH diff --git a/share/misc/iso3166 b/share/misc/iso3166 index d8d5972..23c9bd6 100644 --- a/share/misc/iso3166 +++ b/share/misc/iso3166 @@ -176,7 +176,6 @@ NA NAM 516 Namibia NR NRU 520 Nauru NP NPL 524 Nepal NL NLD 528 Netherlands -AN ANT 530 Netherlands Antilles NC NCL 540 New Caledonia NZ NZL 554 New Zealand NI NIC 558 Nicaragua diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index a589fba..ee78619 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -63,6 +63,15 @@ # SHAREMODE ASCII text file mode. [${NOBINMODE}] # # +# CONFDIR Base path for configuration files. [/etc] +# +# CONFOWN Configuration file owner. [root] +# +# CONFGRP Configuration file group. [wheel] +# +# CONFMODE Configuration file mode. [644] +# +# # DOCDIR Base path for system documentation (e.g. PSD, USD, # handbook, FAQ etc.). [${SHAREDIR}/doc] # @@ -145,6 +154,11 @@ SHAREOWN?= root SHAREGRP?= wheel SHAREMODE?= ${NOBINMODE} +CONFDIR?= /etc +CONFOWN?= root +CONFGRP?= wheel +CONFMODE?= 644 + MANDIR?= ${SHAREDIR}/man/man MANOWN?= ${SHAREOWN} MANGRP?= ${SHAREGRP} diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 025ca5f..941e85e 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -2847,8 +2847,8 @@ pmap_remove_all(vm_page_t m) vm_offset_t va; vm_page_t free; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m)); diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c index fa895f3..17eada1 100644 --- a/sys/amd64/amd64/sys_machdep.c +++ b/sys/amd64/amd64/sys_machdep.c @@ -33,7 +33,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_capabilities.h" +#include "opt_capsicum.h" #include <sys/param.h> #include <sys/systm.h> @@ -180,28 +180,30 @@ sysarch(td, uap) uint64_t a64base; struct i386_ioperm_args iargs; -#ifdef CAPABILITIES +#ifdef CAPABILITY_MODE /* - * Whitelist of operations which are safe enough for capability mode. + * When adding new operations, add a new case statement here to + * explicitly indicate whether or not the operation is safe to + * perform in capability mode. */ if (IN_CAPABILITY_MODE(td)) { switch (uap->op) { - case I386_GET_LDT: - case I386_SET_LDT: - case I386_GET_IOPERM: - case I386_GET_FSBASE: - case I386_SET_FSBASE: - case I386_GET_GSBASE: - case I386_SET_GSBASE: - case AMD64_GET_FSBASE: - case AMD64_SET_FSBASE: - case AMD64_GET_GSBASE: - case AMD64_SET_GSBASE: - break; + case I386_GET_LDT: + case I386_SET_LDT: + case I386_GET_IOPERM: + case I386_GET_FSBASE: + case I386_SET_FSBASE: + case I386_GET_GSBASE: + case I386_SET_GSBASE: + case AMD64_GET_FSBASE: + case AMD64_SET_FSBASE: + case AMD64_GET_GSBASE: + case AMD64_SET_GSBASE: + break; - case I386_SET_IOPERM: - default: - return (ECAPMODE); + case I386_SET_IOPERM: + default: + return (ECAPMODE); } } #endif diff --git a/sys/amd64/include/pci_cfgreg.h b/sys/amd64/include/pci_cfgreg.h index 7588282..717d5cc 100644 --- a/sys/amd64/include/pci_cfgreg.h +++ b/sys/amd64/include/pci_cfgreg.h @@ -1,43 +1,6 @@ /*- - * Copyright (c) 1997, Stefan Esser <se@freebsd.org> - * 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 unmodified, 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. - * - * $FreeBSD$ - * + * This file is in the public domain. */ +/* $FreeBSD$ */ -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc - -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7f000000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul - -int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus); -int pci_cfgregopen(void); -u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); -void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); +#include <x86/pci_cfgreg.h> diff --git a/sys/amd64/pci/pci_bus.c b/sys/amd64/pci/pci_bus.c deleted file mode 100644 index 7c377ac..0000000 --- a/sys/amd64/pci/pci_bus.c +++ /dev/null @@ -1,425 +0,0 @@ -/*- - * Copyright (c) 1997, Stefan Esser <se@freebsd.org> - * 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 unmodified, 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 "opt_cpu.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/rman.h> -#include <sys/sysctl.h> - -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#include <dev/pci/pcib_private.h> -#include <isa/isavar.h> -#include <machine/legacyvar.h> -#include <machine/pci_cfgreg.h> -#include <machine/resource.h> - -#include "pcib_if.h" - -int -legacy_pcib_maxslots(device_t dev) -{ - return 31; -} - -/* read configuration space register */ - -uint32_t -legacy_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, - u_int reg, int bytes) -{ - return(pci_cfgregread(bus, slot, func, reg, bytes)); -} - -/* write configuration space register */ - -void -legacy_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, - u_int reg, uint32_t data, int bytes) -{ - pci_cfgregwrite(bus, slot, func, reg, data, bytes); -} - -/* route interrupt */ - -static int -legacy_pcib_route_interrupt(device_t pcib, device_t dev, int pin) -{ - - /* No routing possible */ - return (PCI_INVALID_IRQ); -} - -/* Pass MSI requests up to the nexus. */ - -static int -legacy_pcib_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, - int *irqs) -{ - device_t bus; - - bus = device_get_parent(pcib); - return (PCIB_ALLOC_MSI(device_get_parent(bus), dev, count, maxcount, - irqs)); -} - -static int -legacy_pcib_alloc_msix(device_t pcib, device_t dev, int *irq) -{ - device_t bus; - - bus = device_get_parent(pcib); - return (PCIB_ALLOC_MSIX(device_get_parent(bus), dev, irq)); -} - -static int -legacy_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, - uint32_t *data) -{ - device_t bus; - - bus = device_get_parent(pcib); - return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); -} - -static const char * -legacy_pcib_is_host_bridge(int bus, int slot, int func, - uint32_t id, uint8_t class, uint8_t subclass, - uint8_t *busnum) -{ - const char *s = NULL; - - *busnum = 0; - if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) - s = "Host to PCI bridge"; - return s; -} - -/* - * Scan the first pci bus for host-pci bridges and add pcib instances - * to the nexus for each bridge. - */ -static void -legacy_pcib_identify(driver_t *driver, device_t parent) -{ - int bus, slot, func; - u_int8_t hdrtype; - int found = 0; - int pcifunchigh; - int found824xx = 0; - int found_orion = 0; - device_t child; - devclass_t pci_devclass; - - if (pci_cfgregopen() == 0) - return; - /* - * Check to see if we haven't already had a PCI bus added - * via some other means. If we have, bail since otherwise - * we're going to end up duplicating it. - */ - if ((pci_devclass = devclass_find("pci")) && - devclass_get_device(pci_devclass, 0)) - return; - - - bus = 0; - retry: - for (slot = 0; slot <= PCI_SLOTMAX; slot++) { - func = 0; - hdrtype = legacy_pcib_read_config(0, bus, slot, func, - PCIR_HDRTYPE, 1); - /* - * When enumerating bus devices, the standard says that - * one should check the header type and ignore the slots whose - * header types that the software doesn't know about. We use - * this to filter out devices. - */ - if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) - continue; - if ((hdrtype & PCIM_MFDEV) && - (!found_orion || hdrtype != 0xff)) - pcifunchigh = PCI_FUNCMAX; - else - pcifunchigh = 0; - for (func = 0; func <= pcifunchigh; func++) { - /* - * Read the IDs and class from the device. - */ - u_int32_t id; - u_int8_t class, subclass, busnum; - const char *s; - device_t *devs; - int ndevs, i; - - id = legacy_pcib_read_config(0, bus, slot, func, - PCIR_DEVVENDOR, 4); - if (id == -1) - continue; - class = legacy_pcib_read_config(0, bus, slot, func, - PCIR_CLASS, 1); - subclass = legacy_pcib_read_config(0, bus, slot, func, - PCIR_SUBCLASS, 1); - - s = legacy_pcib_is_host_bridge(bus, slot, func, - id, class, subclass, - &busnum); - if (s == NULL) - continue; - - /* - * Check to see if the physical bus has already - * been seen. Eg: hybrid 32 and 64 bit host - * bridges to the same logical bus. - */ - if (device_get_children(parent, &devs, &ndevs) == 0) { - for (i = 0; s != NULL && i < ndevs; i++) { - if (strcmp(device_get_name(devs[i]), - "pcib") != 0) - continue; - if (legacy_get_pcibus(devs[i]) == busnum) - s = NULL; - } - free(devs, M_TEMP); - } - - if (s == NULL) - continue; - /* - * Add at priority 100 to make sure we - * go after any motherboard resources - */ - child = BUS_ADD_CHILD(parent, 100, - "pcib", busnum); - device_set_desc(child, s); - legacy_set_pcibus(child, busnum); - - found = 1; - if (id == 0x12258086) - found824xx = 1; - if (id == 0x84c48086) - found_orion = 1; - } - } - if (found824xx && bus == 0) { - bus++; - goto retry; - } - - /* - * Make sure we add at least one bridge since some old - * hardware doesn't actually have a host-pci bridge device. - * Note that pci_cfgregopen() thinks we have PCI devices.. - */ - if (!found) { - if (bootverbose) - printf( - "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n"); - child = BUS_ADD_CHILD(parent, 100, "pcib", 0); - legacy_set_pcibus(child, 0); - } -} - -static int -legacy_pcib_probe(device_t dev) -{ - - if (pci_cfgregopen() == 0) - return ENXIO; - return -100; -} - -static int -legacy_pcib_attach(device_t dev) -{ - int bus; - - bus = pcib_get_bus(dev); - device_add_child(dev, "pci", bus); - return bus_generic_attach(dev); -} - -int -legacy_pcib_read_ivar(device_t dev, device_t child, int which, - uintptr_t *result) -{ - - switch (which) { - case PCIB_IVAR_DOMAIN: - *result = 0; - return 0; - case PCIB_IVAR_BUS: - *result = legacy_get_pcibus(dev); - return 0; - } - return ENOENT; -} - -int -legacy_pcib_write_ivar(device_t dev, device_t child, int which, - uintptr_t value) -{ - - switch (which) { - case PCIB_IVAR_DOMAIN: - return EINVAL; - case PCIB_IVAR_BUS: - legacy_set_pcibus(dev, value); - return 0; - } - return ENOENT; -} - -SYSCTL_DECL(_hw_pci); - -static unsigned long legacy_host_mem_start = 0x80000000; -TUNABLE_ULONG("hw.pci.host_mem_start", &legacy_host_mem_start); -SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RDTUN, - &legacy_host_mem_start, 0x80000000, - "Limit the host bridge memory to being above this address. Must be\n\ -set at boot via a tunable."); - -struct resource * -legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) -{ - /* - * If no memory preference is given, use upper 32MB slot most - * bioses use for their memory window. Typically other bridges - * before us get in the way to assert their preferences on memory. - * Hardcoding like this sucks, so a more MD/MI way needs to be - * found to do it. This is typically only used on older laptops - * that don't have pci busses behind pci bridge, so assuming > 32MB - * is liekly OK. - * - * However, this can cause problems for other chipsets, so we make - * this tunable by hw.pci.host_mem_start. - */ - if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) - start = legacy_host_mem_start; - if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) - start = 0x1000; - return (bus_generic_alloc_resource(dev, child, type, rid, start, end, - count, flags)); -} - -static device_method_t legacy_pcib_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, legacy_pcib_identify), - DEVMETHOD(device_probe, legacy_pcib_probe), - DEVMETHOD(device_attach, legacy_pcib_attach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - DEVMETHOD(bus_read_ivar, legacy_pcib_read_ivar), - DEVMETHOD(bus_write_ivar, legacy_pcib_write_ivar), - DEVMETHOD(bus_alloc_resource, legacy_pcib_alloc_resource), - DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), - DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - /* pcib interface */ - DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), - DEVMETHOD(pcib_read_config, legacy_pcib_read_config), - DEVMETHOD(pcib_write_config, legacy_pcib_write_config), - DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), - DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), - DEVMETHOD(pcib_release_msi, pcib_release_msi), - DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), - DEVMETHOD(pcib_release_msix, pcib_release_msix), - DEVMETHOD(pcib_map_msi, legacy_pcib_map_msi), - - { 0, 0 } -}; - -static devclass_t hostb_devclass; - -DEFINE_CLASS_0(pcib, legacy_pcib_driver, legacy_pcib_methods, 1); -DRIVER_MODULE(pcib, legacy, legacy_pcib_driver, hostb_devclass, 0, 0); - - -/* - * Install placeholder to claim the resources owned by the - * PCI bus interface. This could be used to extract the - * config space registers in the extreme case where the PnP - * ID is available and the PCI BIOS isn't, but for now we just - * eat the PnP ID and do nothing else. - * - * XXX we should silence this probe, as it will generally confuse - * people. - */ -static struct isa_pnp_id pcibus_pnp_ids[] = { - { 0x030ad041 /* PNP0A03 */, "PCI Bus" }, - { 0x080ad041 /* PNP0A08 */, "PCIe Bus" }, - { 0 } -}; - -static int -pcibus_pnp_probe(device_t dev) -{ - int result; - - if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0) - device_quiet(dev); - return(result); -} - -static int -pcibus_pnp_attach(device_t dev) -{ - return(0); -} - -static device_method_t pcibus_pnp_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, pcibus_pnp_probe), - DEVMETHOD(device_attach, pcibus_pnp_attach), - DEVMETHOD(device_detach, bus_generic_detach), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - { 0, 0 } -}; - -static devclass_t pcibus_pnp_devclass; - -DEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1); -DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c index cecf363..f684402 100644 --- a/sys/arm/arm/pmap.c +++ b/sys/arm/arm/pmap.c @@ -3120,8 +3120,8 @@ pmap_remove_all(vm_page_t m) pmap_t curpm; int flags = 0; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); if (TAILQ_EMPTY(&m->md.pv_list)) return; vm_page_lock_queues(); diff --git a/sys/arm/arm/sys_machdep.c b/sys/arm/arm/sys_machdep.c index 89e5227..4c3e350 100644 --- a/sys/arm/arm/sys_machdep.c +++ b/sys/arm/arm/sys_machdep.c @@ -36,7 +36,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_capabilities.h" +#include "opt_capsicum.h" #include <sys/param.h> #include <sys/systm.h> @@ -107,20 +107,22 @@ sysarch(td, uap) { int error; -#ifdef CAPABILITIES +#ifdef CAPABILITY_MODE /* - * Whitelist of operations which are safe enough for capability mode. + * When adding new operations, add a new case statement here to + * explicitly indicate whether or not the operation is safe to + * perform in capability mode. */ if (IN_CAPABILITY_MODE(td)) { switch (uap->op) { - case ARM_SYNC_ICACHE: - case ARM_DRAIN_WRITEBUF: - case ARM_SET_TP: - case ARM_GET_TP: - break; - - default: - return (ECAPMODE); + case ARM_SYNC_ICACHE: + case ARM_DRAIN_WRITEBUF: + case ARM_SET_TP: + case ARM_GET_TP: + break; + + default: + return (ECAPMODE); } } #endif diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index 717e7c2..a7eb5f6 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -91,7 +91,6 @@ __FBSDID("$FreeBSD$"); #include <arm/at91/at91var.h> #include <arm/at91/at91rm92reg.h> #include <arm/at91/at91sam9g20reg.h> -#include <arm/at91/at91board.h> #define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ #define KERNEL_PT_KERN 1 diff --git a/sys/arm/conf/CAMBRIA b/sys/arm/conf/CAMBRIA index 6862129..befe28a 100644 --- a/sys/arm/conf/CAMBRIA +++ b/sys/arm/conf/CAMBRIA @@ -130,7 +130,7 @@ options ATH_DIAGAPI #options ATH_TX99_DIAG device ath_rate_sample # SampleRate tx rate control for ath -options AH_DEBUG +#options AH_DEBUG #options AH_ASSERT options AH_PRIVATE_DIAG #device ath_ar5210 diff --git a/sys/arm/mv/common.c b/sys/arm/mv/common.c index 16bd325..09da857 100644 --- a/sys/arm/mv/common.c +++ b/sys/arm/mv/common.c @@ -122,7 +122,7 @@ static struct soc_node_spec soc_nodes[] = { { "mrvl,sata", &decode_win_sata_setup, NULL }, { "mrvl,xor", &decode_win_xor_setup, &decode_win_xor_dump }, { "mrvl,idma", &decode_win_idma_setup, &decode_win_idma_dump }, - { "mvrl,pcie", &decode_win_pcie_setup, NULL }, + { "mrvl,pcie", &decode_win_pcie_setup, NULL }, { NULL, NULL, NULL }, }; diff --git a/sys/arm/sa11x0/assabet_machdep.c b/sys/arm/sa11x0/assabet_machdep.c index 87788f0..61c5056 100644 --- a/sys/arm/sa11x0/assabet_machdep.c +++ b/sys/arm/sa11x0/assabet_machdep.c @@ -77,7 +77,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm.h> #include <vm/pmap.h> -#include <vm/vm.h> #include <vm/vm_object.h> #include <vm/vm_page.h> #include <vm/vm_pager.h> diff --git a/sys/arm/sa11x0/sa11x0.c b/sys/arm/sa11x0/sa11x0.c index bfffe6a..7b83f95 100644 --- a/sys/arm/sa11x0/sa11x0.c +++ b/sys/arm/sa11x0/sa11x0.c @@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/reboot.h> #include <sys/malloc.h> -#include <sys/bus.h> #include <sys/interrupt.h> #include <sys/module.h> #include <sys/rman.h> @@ -74,7 +73,6 @@ __FBSDID("$FreeBSD$"); #include <arm/sa11x0/sa11x0_dmacreg.h> #include <arm/sa11x0/sa11x0_ppcreg.h> #include <arm/sa11x0/sa11x0_gpioreg.h> -#include <machine/bus.h> extern void sa11x0_activateirqs(void); diff --git a/sys/boot/Makefile b/sys/boot/Makefile index cfc82b9..06cffb1 100644 --- a/sys/boot/Makefile +++ b/sys/boot/Makefile @@ -8,10 +8,6 @@ SUBDIR+= ficl .endif -.if ${MK_FDT} != "no" -SUBDIR+= fdt -.endif - # Pick the machine-dependent subdir based on the target architecture. ADIR= ${MACHINE:S/amd64/i386/:S/powerpc64/powerpc/} .if exists(${.CURDIR}/${ADIR}/.) diff --git a/sys/boot/Makefile.amd64 b/sys/boot/Makefile.amd64 index 256201d..b9e1609 100644 --- a/sys/boot/Makefile.amd64 +++ b/sys/boot/Makefile.amd64 @@ -2,3 +2,4 @@ SUBDIR+= efi SUBDIR+= zfs +SUBDIR+= userboot diff --git a/sys/boot/Makefile.arm b/sys/boot/Makefile.arm index f96104d..46fc574 100644 --- a/sys/boot/Makefile.arm +++ b/sys/boot/Makefile.arm @@ -1,3 +1,7 @@ # $FreeBSD$ +.if ${MK_FDT} != "no" +SUBDIR+= fdt +.endif + SUBDIR+= uboot diff --git a/sys/boot/Makefile.powerpc b/sys/boot/Makefile.powerpc index ca8c331..b7660f4 100644 --- a/sys/boot/Makefile.powerpc +++ b/sys/boot/Makefile.powerpc @@ -1,4 +1,8 @@ # $FreeBSD$ +.if ${MK_FDT} != "no" +SUBDIR+= fdt +.endif + SUBDIR+= ofw SUBDIR+= uboot diff --git a/sys/boot/common/Makefile.inc b/sys/boot/common/Makefile.inc index be6c3301..ad9535c 100644 --- a/sys/boot/common/Makefile.inc +++ b/sys/boot/common/Makefile.inc @@ -1,6 +1,6 @@ # $FreeBSD$ -SRCS+= boot.c commands.c console.c devopen.c interp.c +SRCS+= boot.c commands.c console.c devopen.c disk.c interp.c SRCS+= interp_backslash.c interp_parse.c ls.c misc.c SRCS+= module.c panic.c diff --git a/sys/boot/common/disk.c b/sys/boot/common/disk.c new file mode 100644 index 0000000..40dbc8a --- /dev/null +++ b/sys/boot/common/disk.c @@ -0,0 +1,788 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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$"); + +/* + * MBR/GPT partitioned disk device handling. + * + * Ideas and algorithms from: + * + * - NetBSD libi386/biosdisk.c + * - FreeBSD biosboot/disk.c + * + */ + +#include <stand.h> + +#include <sys/diskmbr.h> +#include <sys/disklabel.h> +#include <sys/gpt.h> + +#include <stdarg.h> +#include <uuid.h> + +#include <bootstrap.h> + +#include "disk.h" + +#ifdef DISK_DEBUG +# define DEBUG(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) +#else +# define DEBUG(fmt, args...) +#endif + +/* + * Search for a slice with the following preferences: + * + * 1: Active FreeBSD slice + * 2: Non-active FreeBSD slice + * 3: Active Linux slice + * 4: non-active Linux slice + * 5: Active FAT/FAT32 slice + * 6: non-active FAT/FAT32 slice + */ +#define PREF_RAWDISK 0 +#define PREF_FBSD_ACT 1 +#define PREF_FBSD 2 +#define PREF_LINUX_ACT 3 +#define PREF_LINUX 4 +#define PREF_DOS_ACT 5 +#define PREF_DOS 6 +#define PREF_NONE 7 + +#ifdef LOADER_GPT_SUPPORT + +struct gpt_part { + int gp_index; + uuid_t gp_type; + uint64_t gp_start; + uint64_t gp_end; +}; + +static uuid_t efi = GPT_ENT_TYPE_EFI; +static uuid_t freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; +static uuid_t freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; +static uuid_t freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static uuid_t freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; +static uuid_t ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; + +#endif + +/* Given a size in 512 byte sectors, convert it to a human-readable number. */ +static char * +display_size(uint64_t size) +{ + static char buf[80]; + char unit; + + size /= 2; + unit = 'K'; + if (size >= 10485760000LL) { + size /= 1073741824; + unit = 'T'; + } else if (size >= 10240000) { + size /= 1048576; + unit = 'G'; + } else if (size >= 10000) { + size /= 1024; + unit = 'M'; + } + sprintf(buf, "%.6ld%cB", (long)size, unit); + return (buf); +} + +static void +disk_checkextended(struct disk_devdesc *dev, + struct dos_partition *slicetab, int slicenum, int *nslicesp) +{ + uint8_t buf[DISK_SECSIZE]; + struct dos_partition *dp; + uint32_t base; + int rc, i, start, end; + + dp = &slicetab[slicenum]; + start = *nslicesp; + + if (dp->dp_size == 0) + goto done; + if (dp->dp_typ != DOSPTYP_EXT) + goto done; + rc = dev->d_dev->dv_strategy(dev, F_READ, dp->dp_start, DISK_SECSIZE, + (char *) buf, NULL); + if (rc) + goto done; + if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) { + DEBUG("no magic in extended table"); + goto done; + } + base = dp->dp_start; + dp = (struct dos_partition *) &buf[DOSPARTOFF]; + for (i = 0; i < NDOSPART; i++, dp++) { + if (dp->dp_size == 0) + continue; + if (*nslicesp == NEXTDOSPART) + goto done; + dp->dp_start += base; + bcopy(dp, &slicetab[*nslicesp], sizeof(*dp)); + (*nslicesp)++; + } + end = *nslicesp; + + /* + * now, recursively check the slices we just added + */ + for (i = start; i < end; i++) + disk_checkextended(dev, slicetab, i, nslicesp); +done: + return; +} + +static int +disk_readslicetab(struct disk_devdesc *dev, + struct dos_partition **slicetabp, int *nslicesp) +{ + struct dos_partition *slicetab = NULL; + int nslices, i; + int rc; + uint8_t buf[DISK_SECSIZE]; + + /* + * Find the slice in the DOS slice table. + */ + rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE, + (char *) buf, NULL); + if (rc) { + DEBUG("error reading MBR"); + return (rc); + } + + /* + * Check the slice table magic. + */ + if (buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) { + DEBUG("no slice table/MBR (no magic)"); + return (rc); + } + + /* + * copy the partition table, then pick up any extended partitions. + */ + slicetab = malloc(NEXTDOSPART * sizeof(struct dos_partition)); + bcopy(buf + DOSPARTOFF, slicetab, + sizeof(struct dos_partition) * NDOSPART); + nslices = NDOSPART; /* extended slices start here */ + for (i = 0; i < NDOSPART; i++) + disk_checkextended(dev, slicetab, i, &nslices); + + *slicetabp = slicetab; + *nslicesp = nslices; + return (0); +} + +/* + * Search for the best MBR slice (typically the first FreeBSD slice). + */ +static int +disk_bestslice(struct dos_partition *slicetab, int nslices) +{ + struct dos_partition *dp; + int pref, preflevel; + int i, prefslice; + + prefslice = 0; + preflevel = PREF_NONE; + + dp = &slicetab[0]; + for (i = 0; i < nslices; i++, dp++) { + switch (dp->dp_typ) { + case DOSPTYP_386BSD: /* FreeBSD */ + pref = dp->dp_flag & 0x80 ? PREF_FBSD_ACT : PREF_FBSD; + break; + + case DOSPTYP_LINUX: + pref = dp->dp_flag & 0x80 ? PREF_LINUX_ACT : PREF_LINUX; + break; + + case 0x01: /* DOS/Windows */ + case 0x04: + case 0x06: + case 0x0b: + case 0x0c: + case 0x0e: + pref = dp->dp_flag & 0x80 ? PREF_DOS_ACT : PREF_DOS; + break; + + default: + pref = PREF_NONE; + } + if (pref < preflevel) { + preflevel = pref; + prefslice = i + 1; + } + } + return (prefslice); +} + +static int +disk_openmbr(struct disk_devdesc *dev) +{ + struct dos_partition *slicetab = NULL, *dptr; + int nslices, sector, slice; + int rc; + uint8_t buf[DISK_SECSIZE]; + struct disklabel *lp; + + /* + * Following calculations attempt to determine the correct value + * for dev->d_offset by looking for the slice and partition specified, + * or searching for reasonable defaults. + */ + rc = disk_readslicetab(dev, &slicetab, &nslices); + if (rc) + return (rc); + + /* + * if a slice number was supplied but not found, this is an error. + */ + if (dev->d_slice > 0) { + slice = dev->d_slice - 1; + if (slice >= nslices) { + DEBUG("slice %d not found", slice); + rc = EPART; + goto out; + } + } + + /* + * Check for the historically bogus MBR found on true dedicated disks + */ + if (slicetab[3].dp_typ == DOSPTYP_386BSD && + slicetab[3].dp_start == 0 && slicetab[3].dp_size == 50000) { + sector = 0; + goto unsliced; + } + + /* + * Try to auto-detect the best slice; this should always give + * a slice number + */ + if (dev->d_slice == 0) { + slice = disk_bestslice(slicetab, nslices); + if (slice == -1) { + rc = ENOENT; + goto out; + } + dev->d_slice = slice; + } + + /* + * Accept the supplied slice number unequivocally (we may be looking + * at a DOS partition). + * Note: we number 1-4, offsets are 0-3 + */ + dptr = &slicetab[dev->d_slice - 1]; + sector = dptr->dp_start; + DEBUG("slice entry %d at %d, %d sectors", + dev->d_slice - 1, sector, dptr->dp_size); + +unsliced: + /* + * Now we have the slice offset, look for the partition in the + * disklabel if we have a partition to start with. + * + * XXX we might want to check the label checksum. + */ + if (dev->d_partition < 0) { + /* no partition, must be after the slice */ + DEBUG("opening raw slice"); + dev->d_offset = sector; + rc = 0; + goto out; + } + + rc = dev->d_dev->dv_strategy(dev, F_READ, sector + LABELSECTOR, + DISK_SECSIZE, (char *) buf, NULL); + if (rc) { + DEBUG("error reading disklabel"); + goto out; + } + + lp = (struct disklabel *) buf; + + if (lp->d_magic != DISKMAGIC) { + DEBUG("no disklabel"); + rc = ENOENT; + goto out; + } + if (dev->d_partition >= lp->d_npartitions) { + DEBUG("partition '%c' exceeds partitions in table (a-'%c')", + 'a' + dev->d_partition, + 'a' + lp->d_npartitions); + rc = EPART; + goto out; + } + + dev->d_offset = + lp->d_partitions[dev->d_partition].p_offset - + lp->d_partitions[RAW_PART].p_offset + + sector; + rc = 0; + +out: + if (slicetab) + free(slicetab); + return (rc); +} + +/* + * Print out each valid partition in the disklabel of a FreeBSD slice. + * For size calculations, we assume a 512 byte sector size. + */ +static void +disk_printbsdslice(struct disk_devdesc *dev, daddr_t offset, + char *prefix, int verbose) +{ + char line[80]; + char buf[DISK_SECSIZE]; + struct disklabel *lp; + int i, rc, fstype; + + /* read disklabel */ + rc = dev->d_dev->dv_strategy(dev, F_READ, offset + LABELSECTOR, + DISK_SECSIZE, (char *) buf, NULL); + if (rc) + return; + lp =(struct disklabel *)(&buf[0]); + if (lp->d_magic != DISKMAGIC) { + sprintf(line, "%s: FFS bad disklabel\n", prefix); + pager_output(line); + return; + } + + /* Print partitions */ + for (i = 0; i < lp->d_npartitions; i++) { + /* + * For each partition, make sure we know what type of fs it + * is. If not, then skip it. + */ + fstype = lp->d_partitions[i].p_fstype; + if (fstype != FS_BSDFFS && + fstype != FS_SWAP && + fstype != FS_VINUM) + continue; + + /* Only print out statistics in verbose mode */ + if (verbose) + sprintf(line, " %s%c: %s %s (%d - %d)\n", + prefix, 'a' + i, + (fstype == FS_SWAP) ? "swap " : + (fstype == FS_VINUM) ? "vinum" : + "FFS ", + display_size(lp->d_partitions[i].p_size), + lp->d_partitions[i].p_offset, + (lp->d_partitions[i].p_offset + + lp->d_partitions[i].p_size)); + else + sprintf(line, " %s%c: %s\n", prefix, 'a' + i, + (fstype == FS_SWAP) ? "swap" : + (fstype == FS_VINUM) ? "vinum" : + "FFS"); + pager_output(line); + } +} + +static void +disk_printslice(struct disk_devdesc *dev, int slice, + struct dos_partition *dp, char *prefix, int verbose) +{ + char stats[80]; + char line[80]; + + if (verbose) + sprintf(stats, " %s (%d - %d)", display_size(dp->dp_size), + dp->dp_start, dp->dp_start + dp->dp_size); + else + stats[0] = '\0'; + + switch (dp->dp_typ) { + case DOSPTYP_386BSD: + disk_printbsdslice(dev, (daddr_t)dp->dp_start, + prefix, verbose); + return; + case DOSPTYP_LINSWP: + sprintf(line, "%s: Linux swap%s\n", prefix, stats); + break; + case DOSPTYP_LINUX: + /* + * XXX + * read the superblock to confirm this is an ext2fs partition? + */ + sprintf(line, "%s: ext2fs%s\n", prefix, stats); + break; + case 0x00: /* unused partition */ + case DOSPTYP_EXT: + return; + case 0x01: + sprintf(line, "%s: FAT-12%s\n", prefix, stats); + break; + case 0x04: + case 0x06: + case 0x0e: + sprintf(line, "%s: FAT-16%s\n", prefix, stats); + break; + case 0x07: + sprintf(line, "%s: NTFS/HPFS%s\n", prefix, stats); + break; + case 0x0b: + case 0x0c: + sprintf(line, "%s: FAT-32%s\n", prefix, stats); + break; + default: + sprintf(line, "%s: Unknown fs: 0x%x %s\n", prefix, dp->dp_typ, + stats); + } + pager_output(line); +} + +int +disk_printmbr(struct disk_devdesc *dev, char *prefix, int verbose) +{ + struct dos_partition *slicetab; + int nslices, i; + int rc; + char line[80]; + + rc = disk_readslicetab(dev, &slicetab, &nslices); + if (rc) + return (rc); + for (i = 0; i < nslices; i++) { + sprintf(line, "%ss%d", prefix, i + 1); + disk_printslice(dev, i, &slicetab[i], line, verbose); + } + free(slicetab); + return (0); +} + +#ifdef LOADER_GPT_SUPPORT + +static int +disk_readgpt(struct disk_devdesc *dev, struct gpt_part **gptp, int *ngptp) +{ + struct dos_partition *dp; + struct gpt_hdr *hdr; + struct gpt_ent *ent; + struct gpt_part *gptab = NULL; + int entries_per_sec, rc, i, part; + daddr_t lba, elba; + uint8_t gpt[DISK_SECSIZE], tbl[DISK_SECSIZE]; + + /* + * Following calculations attempt to determine the correct value + * for dev->d_offset by looking for the slice and partition specified, + * or searching for reasonable defaults. + */ + rc = 0; + + /* First, read the MBR and see if we have a PMBR. */ + rc = dev->d_dev->dv_strategy(dev, F_READ, 0, DISK_SECSIZE, + (char *) tbl, NULL); + if (rc) { + DEBUG("error reading MBR"); + return (EIO); + } + + /* Check the slice table magic. */ + if (tbl[0x1fe] != 0x55 || tbl[0x1ff] != 0xaa) + return (ENXIO); + + /* Check for GPT slice. */ + part = 0; + dp = (struct dos_partition *)(tbl + DOSPARTOFF); + for (i = 0; i < NDOSPART; i++) { + if (dp[i].dp_typ == 0xee) + part++; + else if ((part != 1) && (dp[i].dp_typ != 0x00)) + return (EINVAL); + } + if (part != 1) + return (EINVAL); + + /* Read primary GPT table header. */ + rc = dev->d_dev->dv_strategy(dev, F_READ, 1, DISK_SECSIZE, + (char *) gpt, NULL); + if (rc) { + DEBUG("error reading GPT header"); + return (EIO); + } + hdr = (struct gpt_hdr *)gpt; + if (bcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0 || + hdr->hdr_lba_self != 1 || hdr->hdr_revision < 0x00010000 || + hdr->hdr_entsz < sizeof(*ent) || + DISK_SECSIZE % hdr->hdr_entsz != 0) { + DEBUG("Invalid GPT header\n"); + return (EINVAL); + } + + /* Walk the partition table to count valid partitions. */ + part = 0; + entries_per_sec = DISK_SECSIZE / hdr->hdr_entsz; + elba = hdr->hdr_lba_table + hdr->hdr_entries / entries_per_sec; + for (lba = hdr->hdr_lba_table; lba < elba; lba++) { + rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE, + (char *) tbl, NULL); + if (rc) { + DEBUG("error reading GPT table"); + return (EIO); + } + for (i = 0; i < entries_per_sec; i++) { + ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); + if (uuid_is_nil(&ent->ent_type, NULL) || + ent->ent_lba_start == 0 || + ent->ent_lba_end < ent->ent_lba_start) + continue; + part++; + } + } + + /* Save the important information about all the valid partitions. */ + if (part != 0) { + gptab = malloc(part * sizeof(struct gpt_part)); + part = 0; + for (lba = hdr->hdr_lba_table; lba < elba; lba++) { + rc = dev->d_dev->dv_strategy(dev, F_READ, lba, DISK_SECSIZE, + (char *) tbl, NULL); + if (rc) { + DEBUG("error reading GPT table"); + free(gptab); + return (EIO); + } + for (i = 0; i < entries_per_sec; i++) { + ent = (struct gpt_ent *)(tbl + i * hdr->hdr_entsz); + if (uuid_is_nil(&ent->ent_type, NULL) || + ent->ent_lba_start == 0 || + ent->ent_lba_end < ent->ent_lba_start) + continue; + gptab[part].gp_index = (lba - hdr->hdr_lba_table) * + entries_per_sec + i + 1; + gptab[part].gp_type = ent->ent_type; + gptab[part].gp_start = ent->ent_lba_start; + gptab[part].gp_end = ent->ent_lba_end; + part++; + } + } + } + + *gptp = gptab; + *ngptp = part; + return (0); +} + +static struct gpt_part * +disk_bestgpt(struct gpt_part *gpt, int ngpt) +{ + struct gpt_part *gp, *prefpart; + int i, pref, preflevel; + + prefpart = NULL; + preflevel = PREF_NONE; + + gp = gpt; + for (i = 0; i < ngpt; i++, gp++) { + /* Windows. XXX: Also Linux. */ + if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL)) + pref = PREF_DOS; + /* FreeBSD */ + else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL) || + uuid_equal(&gp->gp_type, &freebsd_zfs, NULL)) + pref = PREF_FBSD; + else + pref = PREF_NONE; + if (pref < preflevel) { + preflevel = pref; + prefpart = gp; + } + } + return (prefpart); +} + +int +disk_opengpt(struct disk_devdesc *dev) +{ + struct gpt_part *gpt = NULL, *gp; + int rc, ngpt, i; + + rc = disk_readgpt(dev, &gpt, &ngpt); + if (rc) + return (rc); + + /* Is this a request for the whole disk? */ + if (dev->d_slice < 0) { + dev->d_offset = 0; + rc = 0; + goto out; + } + + /* + * If a partition number was supplied, then the user is trying to use + * an MBR address rather than a GPT address, so fail. + */ + if (dev->d_partition != 0xff) { + rc = ENOENT; + goto out; + } + + /* If a slice number was supplied but not found, this is an error. */ + gp = NULL; + if (dev->d_slice > 0) { + for (i = 0; i < ngpt; i++) { + if (gpt[i].gp_index == dev->d_slice) { + gp = &gpt[i]; + break; + } + } + if (gp == NULL) { + DEBUG("partition %d not found", dev->d_slice); + rc = ENOENT; + goto out; + } + } + + /* Try to auto-detect the best partition. */ + if (dev->d_slice == 0) { + gp = disk_bestgpt(gpt, ngpt); + if (gp == NULL) { + rc = ENOENT; + goto out; + } + dev->d_slice = gp->gp_index; + } + + dev->d_offset = gp->gp_start; + rc = 0; + +out: + if (gpt) + free(gpt); + return (rc); +} + +static void +disk_printgptpart(struct disk_devdesc *dev, struct gpt_part *gp, + char *prefix, int verbose) +{ + char stats[80]; + char line[96]; + + if (verbose) + sprintf(stats, " %s", + display_size(gp->gp_end + 1 - gp->gp_start)); + else + stats[0] = '\0'; + + if (uuid_equal(&gp->gp_type, &efi, NULL)) + sprintf(line, "%s: EFI %s\n", prefix, stats); + else if (uuid_equal(&gp->gp_type, &ms_basic_data, NULL)) + sprintf(line, "%s: FAT/NTFS %s\n", prefix, stats); + else if (uuid_equal(&gp->gp_type, &freebsd_boot, NULL)) + sprintf(line, "%s: FreeBSD boot%s\n", prefix, stats); + else if (uuid_equal(&gp->gp_type, &freebsd_ufs, NULL)) + sprintf(line, "%s: FreeBSD UFS %s\n", prefix, stats); + else if (uuid_equal(&gp->gp_type, &freebsd_zfs, NULL)) + sprintf(line, "%s: FreeBSD ZFS %s\n", prefix, stats); + else if (uuid_equal(&gp->gp_type, &freebsd_swap, NULL)) + sprintf(line, "%s: FreeBSD swap%s\n", prefix, stats); + else + sprintf(line, + "%s: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%s\n", + prefix, + gp->gp_type.time_low, gp->gp_type.time_mid, + gp->gp_type.time_hi_and_version, + gp->gp_type.clock_seq_hi_and_reserved, + gp->gp_type.clock_seq_low, + gp->gp_type.node[0], + gp->gp_type.node[1], + gp->gp_type.node[2], + gp->gp_type.node[3], + gp->gp_type.node[4], + gp->gp_type.node[5], + stats); + pager_output(line); +} + +static int +disk_printgpt(struct disk_devdesc *dev, char *prefix, int verbose) +{ + struct gpt_part *gpt = NULL; + int rc, ngpt, i; + char line[80]; + + rc = disk_readgpt(dev, &gpt, &ngpt); + if (rc) + return (rc); + for (i = 0; i < ngpt; i++) { + sprintf(line, "%sp%d", prefix, i + 1); + disk_printgptpart(dev, &gpt[i], line, verbose); + } + free(gpt); + return (0); +} + +#endif + +int +disk_open(struct disk_devdesc *dev) +{ + int rc; + + /* + * While we are reading disk metadata, make sure we do it relative + * to the start of the disk + */ + dev->d_offset = 0; + +#ifdef LOADER_GPT_SUPPORT + rc = disk_opengpt(dev); + if (rc) +#endif + rc = disk_openmbr(dev); + + return (rc); +} + +void +disk_print(struct disk_devdesc *dev, char *prefix, int verbose) +{ + int rc; + +#ifdef LOADER_GPT_SUPPORT + rc = disk_printgpt(dev, prefix, verbose); + if (rc == 0) + return; +#endif + disk_printmbr(dev, prefix, verbose); +} diff --git a/sys/boot/common/disk.h b/sys/boot/common/disk.h new file mode 100644 index 0000000..0fc7e91 --- /dev/null +++ b/sys/boot/common/disk.h @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2011 Google, 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 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. + * + * $FreeBSD$ + */ + +/* + * Device descriptor for partitioned disks. We assume that all disk addresses + * are 512 byte block offsets from the start of the disk. To use, set the + * d_slice and d_partition variables as follows: + * + * Whole disk access: + * + * d_slice = -1 + * d_partition = -1 + * + * Whole MBR slice: + * + * d_slice = MBR slice number (typically 1..4) + * d_partition = -1 + * + * BSD disklabel partition within an MBR slice: + * + * d_slice = MBR slice number (typically 1..4) + * d_partition = disklabel partition (typically 0..7) + * + * GPT partition: + * + * d_slice = GPT partition number (typically 1..N) + * d_partition = 255 + * + * For both MBR and GPT, to automatically find the 'best' slice or partition, + * set d_slice to zero. This uses the partition type to decide which partition + * to use according to the following list of preferences: + * + * FreeBSD (active) + * FreeBSD (inactive) + * Linux (active) + * Linux (inactive) + * DOS/Windows (active) + * DOS/Windows (inactive) + * + * Active MBR slices (marked as bootable) are preferred over inactive. GPT + * doesn't have the concept of active/inactive partitions. In both MBR and GPT, + * if there are multiple slices/partitions of a given type, the first one + * is chosen. + * + * The low-level disk device will typically call slice_open() from its open + * method to interpret the disk partition tables according to the rules above. + * This will initialize d_offset to the block offset of the start of the + * selected partition - this offset should be added to the offset passed to + * the device's strategy method. + */ + +#define DISK_SECSIZE 512 + +struct disk_devdesc +{ + struct devsw *d_dev; + int d_type; + int d_unit; + void *d_opendata; + int d_slice; + int d_partition; + int d_offset; +}; + +/* + * Parse disk metadata and initialise dev->d_offset. + */ +extern int disk_open(struct disk_devdesc * dev); + +/* + * Print information about slices on a disk. For the size calculations we + * assume a 512 byte sector. + */ +extern void disk_print(struct disk_devdesc *dev, char *prefix, int verbose); diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c index ee6389f..bf095bb 100644 --- a/sys/boot/common/load_elf.c +++ b/sys/boot/common/load_elf.c @@ -260,7 +260,7 @@ __elfN(loadimage)(struct preloaded_file *fp, elf_file_t ef, u_int64_t off) firstaddr = lastaddr = 0; ehdr = ef->ehdr; if (ef->kernel) { -#ifdef __i386__ +#if defined(__i386__) || defined(__amd64__) #if __ELF_WORD_SIZE == 64 off = - (off & 0xffffffffff000000ull);/* x86_64 relocates after locore */ #else diff --git a/sys/boot/common/reloc_elf.c b/sys/boot/common/reloc_elf.c index 43b7cbf..b614091 100644 --- a/sys/boot/common/reloc_elf.c +++ b/sys/boot/common/reloc_elf.c @@ -78,7 +78,7 @@ __elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, } return (0); -#elif defined(__i386__) && __ELF_WORD_SIZE == 64 +#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 Elf64_Addr *where, val; Elf_Addr addend, addr; Elf_Size rtype, symidx; diff --git a/sys/boot/ficl/amd64/sysdep.c b/sys/boot/ficl/amd64/sysdep.c new file mode 100644 index 0000000..00b0d4a --- /dev/null +++ b/sys/boot/ficl/amd64/sysdep.c @@ -0,0 +1,101 @@ +/******************************************************************* +** s y s d e p . c +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Implementations of FICL external interface functions... +** +*******************************************************************/ + +/* $FreeBSD$ */ + +#ifdef TESTMAIN +#include <stdio.h> +#include <stdlib.h> +#else +#include <stand.h> +#endif +#include "ficl.h" + +/* +******************* FreeBSD P O R T B E G I N S H E R E ******************** Michael Smith +*/ + +#if PORTABLE_LONGMULDIV == 0 +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y) +{ + DPUNS q; + u_int64_t qx; + + qx = (u_int64_t)x * (u_int64_t) y; + + q.hi = (u_int32_t)( qx >> 32 ); + q.lo = (u_int32_t)( qx & 0xFFFFFFFFL); + + return q; +} + +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y) +{ + UNSQR result; + u_int64_t qx, qh; + + qh = q.hi; + qx = (qh << 32) | q.lo; + + result.quot = qx / y; + result.rem = qx % y; + + return result; +} +#endif + +void ficlTextOut(FICL_VM *pVM, char *msg, int fNewline) +{ + IGNORE(pVM); + + while(*msg != 0) + putchar(*(msg++)); + if (fNewline) + putchar('\n'); + + return; +} + +void *ficlMalloc (size_t size) +{ + return malloc(size); +} + +void *ficlRealloc (void *p, size_t size) +{ + return realloc(p, size); +} + +void ficlFree (void *p) +{ + free(p); +} + + +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** is guaranteed to be bracketed as follows: +** ficlLockDictionary(TRUE); +** <code that updates dictionary> +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** befor timeout (optional - could also block forever) +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock) +{ + IGNORE(fLock); + return 0; +} +#endif /* FICL_MULTITHREAD */ + + diff --git a/sys/boot/ficl/amd64/sysdep.h b/sys/boot/ficl/amd64/sysdep.h new file mode 100644 index 0000000..08bc0e1 --- /dev/null +++ b/sys/boot/ficl/amd64/sysdep.h @@ -0,0 +1,434 @@ +/******************************************************************* + s y s d e p . h +** Forth Inspired Command Language +** Author: John Sadler (john_sadler@alum.mit.edu) +** Created: 16 Oct 1997 +** Ficl system dependent types and prototypes... +** +** Note: Ficl also depends on the use of "assert" when +** FICL_ROBUST is enabled. This may require some consideration +** in firmware systems since assert often +** assumes stderr/stdout. +** $Id: sysdep.h,v 1.11 2001/12/05 07:21:34 jsadler Exp $ +*******************************************************************/ +/* +** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu) +** All rights reserved. +** +** Get the latest Ficl release at http://ficl.sourceforge.net +** +** I am interested in hearing from anyone who uses ficl. If you have +** a problem, a success story, a defect, an enhancement request, or +** if you would like to contribute to the ficl release, please +** contact me by email at the address above. +** +** L I C E N S E and D I S C L A I M E R +** +** 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. +** +** $Id: sysdep.h,v 1.6 2001-04-26 21:41:55-07 jsadler Exp jsadler $ +*/ + +/* $FreeBSD$ */ + +#if !defined (__SYSDEP_H__) +#define __SYSDEP_H__ + +#include <sys/types.h> + +#include <stddef.h> /* size_t, NULL */ +#include <setjmp.h> +#include <assert.h> + +#if !defined IGNORE /* Macro to silence unused param warnings */ +#define IGNORE(x) &x +#endif + +/* +** TRUE and FALSE for C boolean operations, and +** portable 32 bit types for CELLs +** +*/ +#if !defined TRUE +#define TRUE 1 +#endif +#if !defined FALSE +#define FALSE 0 +#endif + +/* +** System dependent data type declarations... +*/ +#if !defined INT32 +#define INT32 int +#endif + +#if !defined UNS32 +#define UNS32 unsigned int +#endif + +#if !defined UNS16 +#define UNS16 unsigned short +#endif + +#if !defined UNS8 +#define UNS8 unsigned char +#endif + +#if !defined NULL +#define NULL ((void *)0) +#endif + +/* +** FICL_UNS and FICL_INT must have the same size as a void* on +** the target system. A CELL is a union of void*, FICL_UNS, and +** FICL_INT. +** (11/2000: same for FICL_FLOAT) +*/ +#if !defined FICL_INT +#define FICL_INT long +#endif + +#if !defined FICL_UNS +#define FICL_UNS unsigned long +#endif + +#if !defined FICL_FLOAT +#define FICL_FLOAT float +#endif + +/* +** Ficl presently supports values of 32 and 64 for BITS_PER_CELL +*/ +#if !defined BITS_PER_CELL +#define BITS_PER_CELL 64 +#endif + +#if ((BITS_PER_CELL != 32) && (BITS_PER_CELL != 64)) + Error! +#endif + +typedef struct +{ + FICL_UNS hi; + FICL_UNS lo; +} DPUNS; + +typedef struct +{ + FICL_UNS quot; + FICL_UNS rem; +} UNSQR; + +typedef struct +{ + FICL_INT hi; + FICL_INT lo; +} DPINT; + +typedef struct +{ + FICL_INT quot; + FICL_INT rem; +} INTQR; + + +/* +** B U I L D C O N T R O L S +*/ + +#if !defined (FICL_MINIMAL) +#define FICL_MINIMAL 0 +#endif +#if (FICL_MINIMAL) +#define FICL_WANT_SOFTWORDS 0 +#define FICL_WANT_FILE 0 +#define FICL_WANT_FLOAT 0 +#define FICL_WANT_USER 0 +#define FICL_WANT_LOCALS 0 +#define FICL_WANT_DEBUGGER 0 +#define FICL_WANT_OOP 0 +#define FICL_PLATFORM_EXTEND 0 +#define FICL_MULTITHREAD 0 +#define FICL_ROBUST 0 +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** FICL_PLATFORM_EXTEND +** Includes words defined in ficlCompilePlatform +*/ +#if !defined (FICL_PLATFORM_EXTEND) +#define FICL_PLATFORM_EXTEND 1 +#endif + + +/* +** FICL_WANT_FILE +** Includes the FILE and FILE-EXT wordset and associated code. Turn this off if you do not +** have a filesystem! +** Contributed by Larry Hastings +*/ +#if !defined (FICL_WANT_FILE) +#define FICL_WANT_FILE 0 +#endif + +/* +** FICL_WANT_FLOAT +** Includes a floating point stack for the VM, and words to do float operations. +** Contributed by Guy Carver +*/ +#if !defined (FICL_WANT_FLOAT) +#define FICL_WANT_FLOAT 0 +#endif + +/* +** FICL_WANT_DEBUGGER +** Inludes a simple source level debugger +*/ +#if !defined (FICL_WANT_DEBUGGER) +#define FICL_WANT_DEBUGGER 1 +#endif + +/* +** FICL_EXTENDED_PREFIX enables a bunch of extra prefixes in prefix.c and prefix.fr (if +** included as part of softcore.c) +*/ +#if !defined FICL_EXTENDED_PREFIX +#define FICL_EXTENDED_PREFIX 0 +#endif + +/* +** User variables: per-instance variables bound to the VM. +** Kinda like thread-local storage. Could be implemented in a +** VM private dictionary, but I've chosen the lower overhead +** approach of an array of CELLs instead. +*/ +#if !defined FICL_WANT_USER +#define FICL_WANT_USER 1 +#endif + +#if !defined FICL_USER_CELLS +#define FICL_USER_CELLS 16 +#endif + +/* +** FICL_WANT_LOCALS controls the creation of the LOCALS wordset and +** a private dictionary for local variable compilation. +*/ +#if !defined FICL_WANT_LOCALS +#define FICL_WANT_LOCALS 1 +#endif + +/* Max number of local variables per definition */ +#if !defined FICL_MAX_LOCALS +#define FICL_MAX_LOCALS 16 +#endif + +/* +** FICL_WANT_OOP +** Inludes object oriented programming support (in softwords) +** OOP support requires locals and user variables! +*/ +#if !(FICL_WANT_LOCALS) || !(FICL_WANT_USER) +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 0 +#endif +#endif + +#if !defined (FICL_WANT_OOP) +#define FICL_WANT_OOP 1 +#endif + +/* +** FICL_WANT_SOFTWORDS +** Controls inclusion of all softwords in softcore.c +*/ +#if !defined (FICL_WANT_SOFTWORDS) +#define FICL_WANT_SOFTWORDS 1 +#endif + +/* +** FICL_MULTITHREAD enables dictionary mutual exclusion +** wia the ficlLockDictionary system dependent function. +** Note: this implementation is experimental and poorly +** tested. Further, it's unnecessary unless you really +** intend to have multiple SESSIONS (poor choice of name +** on my part) - that is, threads that modify the dictionary +** at the same time. +*/ +#if !defined FICL_MULTITHREAD +#define FICL_MULTITHREAD 0 +#endif + +/* +** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be +** defined in C in sysdep.c. Use this if you cannot easily +** generate an inline asm definition +*/ +#if !defined (PORTABLE_LONGMULDIV) +#define PORTABLE_LONGMULDIV 0 +#endif + +/* +** INLINE_INNER_LOOP causes the inner interpreter to be inline code +** instead of a function call. This is mainly because MS VC++ 5 +** chokes with an internal compiler error on the function version. +** in release mode. Sheesh. +*/ +#if !defined INLINE_INNER_LOOP +#if defined _DEBUG +#define INLINE_INNER_LOOP 0 +#else +#define INLINE_INNER_LOOP 1 +#endif +#endif + +/* +** FICL_ROBUST enables bounds checking of stacks and the dictionary. +** This will detect stack over and underflows and dictionary overflows. +** Any exceptional condition will result in an assertion failure. +** (As generated by the ANSI assert macro) +** FICL_ROBUST == 1 --> stack checking in the outer interpreter +** FICL_ROBUST == 2 also enables checking in many primitives +*/ + +#if !defined FICL_ROBUST +#define FICL_ROBUST 2 +#endif + +/* +** FICL_DEFAULT_STACK Specifies the default size (in CELLs) of +** a new virtual machine's stacks, unless overridden at +** create time. +*/ +#if !defined FICL_DEFAULT_STACK +#define FICL_DEFAULT_STACK 128 +#endif + +/* +** FICL_DEFAULT_DICT specifies the number of CELLs to allocate +** for the system dictionary by default. The value +** can be overridden at startup time as well. +** FICL_DEFAULT_ENV specifies the number of cells to allot +** for the environment-query dictionary. +*/ +#if !defined FICL_DEFAULT_DICT +#define FICL_DEFAULT_DICT 12288 +#endif + +#if !defined FICL_DEFAULT_ENV +#define FICL_DEFAULT_ENV 260 +#endif + +/* +** FICL_DEFAULT_VOCS specifies the maximum number of wordlists in +** the dictionary search order. See Forth DPANS sec 16.3.3 +** (file://dpans16.htm#16.3.3) +*/ +#if !defined FICL_DEFAULT_VOCS +#define FICL_DEFAULT_VOCS 16 +#endif + +/* +** FICL_MAX_PARSE_STEPS controls the size of an array in the FICL_SYSTEM structure +** that stores pointers to parser extension functions. I would never expect to have +** more than 8 of these, so that's the default limit. Too many of these functions +** will probably exact a nasty performance penalty. +*/ +#if !defined FICL_MAX_PARSE_STEPS +#define FICL_MAX_PARSE_STEPS 8 +#endif + +/* +** FICL_ALIGN is the power of two to which the dictionary +** pointer address must be aligned. This value is usually +** either 1 or 2, depending on the memory architecture +** of the target system; 2 is safe on any 16 or 32 bit +** machine. 3 would be appropriate for a 64 bit machine. +*/ +#if !defined FICL_ALIGN +#define FICL_ALIGN 3 +#define FICL_ALIGN_ADD ((1 << FICL_ALIGN) - 1) +#endif + +/* +** System dependent routines -- +** edit the implementations in sysdep.c to be compatible +** with your runtime environment... +** ficlTextOut sends a NULL terminated string to the +** default output device - used for system error messages +** ficlMalloc and ficlFree have the same semantics as malloc and free +** in standard C +** ficlLongMul multiplies two UNS32s and returns a 64 bit unsigned +** product +** ficlLongDiv divides an UNS64 by an UNS32 and returns UNS32 quotient +** and remainder +*/ +struct vm; +void ficlTextOut(struct vm *pVM, char *msg, int fNewline); +void *ficlMalloc (size_t size); +void ficlFree (void *p); +void *ficlRealloc(void *p, size_t size); +/* +** Stub function for dictionary access control - does nothing +** by default, user can redefine to guarantee exclusive dict +** access to a single thread for updates. All dict update code +** must be bracketed as follows: +** ficlLockDictionary(TRUE); +** <code that updates dictionary> +** ficlLockDictionary(FALSE); +** +** Returns zero if successful, nonzero if unable to acquire lock +** before timeout (optional - could also block forever) +** +** NOTE: this function must be implemented with lock counting +** semantics: nested calls must behave properly. +*/ +#if FICL_MULTITHREAD +int ficlLockDictionary(short fLock); +#else +#define ficlLockDictionary(x) 0 /* ignore */ +#endif + +/* +** 64 bit integer math support routines: multiply two UNS32s +** to get a 64 bit product, & divide the product by an UNS32 +** to get an UNS32 quotient and remainder. Much easier in asm +** on a 32 bit CPU than in C, which usually doesn't support +** the double length result (but it should). +*/ +DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y); +UNSQR ficlLongDiv(DPUNS q, FICL_UNS y); + + +/* +** FICL_HAVE_FTRUNCATE indicates whether the current OS supports +** the ftruncate() function (available on most UNIXes). This +** function is necessary to provide the complete File-Access wordset. +*/ +#if !defined (FICL_HAVE_FTRUNCATE) +#define FICL_HAVE_FTRUNCATE 0 +#endif + + +#endif /*__SYSDEP_H__*/ diff --git a/sys/boot/i386/libi386/bioscd.c b/sys/boot/i386/libi386/bioscd.c index a6dba0c..a3abf34 100644 --- a/sys/boot/i386/libi386/bioscd.c +++ b/sys/boot/i386/libi386/bioscd.c @@ -117,6 +117,7 @@ bc_bios2unit(int biosdev) int i; DEBUG("looking for bios device 0x%x", biosdev); + printf("looking for bios device 0x%x, nbcinfo=%d\n", biosdev, nbcinfo); for (i = 0; i < nbcinfo; i++) { DEBUG("bc unit %d is BIOS device 0x%x", i, bcinfo[i].bc_unit); if (bcinfo[i].bc_unit == biosdev) @@ -148,6 +149,7 @@ bc_init(void) int bc_add(int biosdev) { + printf("bc_add(%d)\n", biosdev); if (nbcinfo >= MAXBCDEV) return (-1); @@ -159,8 +161,10 @@ bc_add(int biosdev) v86.ds = VTOPSEG(&bcinfo[nbcinfo].bc_sp); v86.esi = VTOPOFF(&bcinfo[nbcinfo].bc_sp); v86int(); - if ((v86.eax & 0xff00) != 0) + if ((v86.eax & 0xff00) != 0) { + printf("CD probe failed, eax=0x%08x\n", v86.eax); return (-1); + } printf("BIOS CD is cd%d\n", nbcinfo); nbcinfo++; diff --git a/sys/boot/i386/zfsboot/zfsldr.S b/sys/boot/i386/zfsboot/zfsldr.S index 182d88e..b8be282 100644 --- a/sys/boot/i386/zfsboot/zfsldr.S +++ b/sys/boot/i386/zfsboot/zfsldr.S @@ -16,7 +16,6 @@ */ /* Memory Locations */ - .set MEM_REL,0x700 # Relocation address .set MEM_ARG,0x900 # Arguments .set MEM_ORG,0x7c00 # Origin .set MEM_BUF,0x8000 # Load area @@ -38,43 +37,6 @@ .globl start .code16 -start: jmp main # Start recognizably - -/* - * This is the start of a standard BIOS Parameter Block (BPB). Most bootable - * FAT disks have this at the start of their MBR. While normal BIOS's will - * work fine without this section, IBM's El Torito emulation "fixes" up the - * BPB by writing into the memory copy of the MBR. Rather than have data - * written into our code, we'll define a BPB to work around it. - * The data marked with (T) indicates a field required for a ThinkPad to - * recognize the disk and (W) indicates fields written from IBM BIOS code. - * The use of the BPB is based on what OpenBSD and NetBSD implemented in - * their boot code but the required fields were determined by trial and error. - * - * Note: If additional space is needed in boot1, one solution would be to - * move the "prompt" message data (below) to replace the OEM ID. - */ - .org 0x03, 0x00 -oemid: .space 0x08, 0x00 # OEM ID - - .org 0x0b, 0x00 -bpb: .word 512 # sector size (T) - .byte 0 # sectors/clustor - .word 0 # reserved sectors - .byte 0 # number of FATs - .word 0 # root entries - .word 0 # small sectors - .byte 0 # media type (W) - .word 0 # sectors/fat - .word 18 # sectors per track (T) - .word 2 # number of heads (T) - .long 0 # hidden sectors (W) - .long 0 # large sectors - - .org 0x24, 0x00 -ebpb: .byte 0 # BIOS physical drive number (W) - - .org 0x25,0x90 /* * Load the rest of zfsboot2 and BTX up, copy the parts to the right locations, * and start it all up. @@ -84,33 +46,24 @@ ebpb: .byte 0 # BIOS physical drive number (W) * Setup the segment registers to flat addressing (segment 0) and setup the * stack to end just below the start of our code. */ -main: cld # String ops inc +start: cld # String ops inc xor %cx,%cx # Zero mov %cx,%es # Address mov %cx,%ds # data mov %cx,%ss # Set up mov $start,%sp # stack /* - * Relocate ourself to MEM_REL. Since %cx == 0, the inc %ch sets - * %cx == 0x100. - */ - mov %sp,%si # Source - mov $MEM_REL,%di # Destination - incb %ch # Word count - rep # Copy - movsw # code -/* - * If we are on a hard drive, then load the MBR and look for the first - * FreeBSD slice. We use the fake partition entry below that points to - * the MBR when we call nread. The first pass looks for the first active - * FreeBSD slice. The second pass looks for the first non-active FreeBSD - * slice if the first one fails. + * Load the MBR and look for the first FreeBSD slice. We use the fake + * partition entry below that points to the MBR when we call read. + * The first pass looks for the first active FreeBSD slice. The + * second pass looks for the first non-active FreeBSD slice if the + * first one fails. */ - mov $part4,%si # Partition - cmpb $0x80,%dl # Hard drive? - jb main.4 # No - movb $0x1,%dh # Block count - callw nread # Read MBR + call check_edd # Make sure EDD works + mov $part4,%si # Dummy partition + xor %eax,%eax # Read MBR + movl $MEM_BUF,%ebx # from first + call read # sector mov $0x1,%cx # Two passes main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table movb $0x1,%dh # Partition @@ -131,60 +84,55 @@ main.3: add $0x10,%si # Next entry */ mov $msg_part,%si # Message jmp error # Error -/* - * Floppies use partition 0 of drive 0. - */ -main.4: xor %dx,%dx # Partition:drive /* * Ok, we have a slice and drive in %dx now, so use that to locate and * load boot2. %si references the start of the slice we are looking - * for, so go ahead and load up the 64 sectors starting at sector 1024 + * for, so go ahead and load up the 128 sectors starting at sector 1024 * (i.e. after the two vdev labels). We don't have do anything fancy * here to allow for an extra copy of boot1 and a partition table * (compare to this section of the UFS bootstrap) so we just load it - * all at 0x8000. The first part of boot2 is BTX, which wants to run + * all at 0x9000. The first part of boot2 is BTX, which wants to run * at 0x9000. The boot2.bin binary starts right after the end of BTX, * so we have to figure out where the start of it is and then move the - * binary to 0xc000. After we have moved the client, we relocate BTX - * itself to 0x9000 - doing it in this order means that none of the - * memcpy regions overlap which would corrupt the copy. Normally, BTX - * clients start at MEM_USR, or 0xa000, but when we use btxld to - * create zfsboot2, we use an entry point of 0x2000. That entry point is - * relative to MEM_USR; thus boot2.bin starts at 0xc000. + * binary to 0xc000. Normally, BTX clients start at MEM_USR, or 0xa000, + * but when we use btxld to create zfsboot2, we use an entry point of + * 0x2000. That entry point is relative to MEM_USR; thus boot2.bin + * starts at 0xc000. * * The load area and the target area for the client overlap so we have * to use a decrementing string move. We also play segment register * games with the destination address for the move so that the client * can be larger than 16k (which would overflow the zero segment since - * the client starts at 0xc000). Relocating BTX is easy since the load - * area and target area do not overlap. + * the client starts at 0xc000). */ main.5: mov %dx,MEM_ARG # Save args - movb $NSECT,%dh # Sector count + mov $NSECT,%cx # Sector count movl $1024,%eax # Offset to boot2 - callw nread.1 # Read disk -main.6: mov $MEM_BUF,%si # BTX (before reloc) - mov 0xa(%si),%bx # Get BTX length and set + mov $MEM_BTX,%ebx # Destination buffer +main.6: pushal # Save params + call read # Read disk + popal # Restore + incl %eax # Advance to + add $SIZ_SEC,%ebx # next sector + loop main.6 # If not last, read another + mov MEM_BTX+0xa,%bx # Get BTX length mov $NSECT*SIZ_SEC-1,%di # Size of load area (less one) - mov %di,%si # End of load - add $MEM_BUF,%si # area + mov %di,%si # End of load area, 0x9000 rel sub %bx,%di # End of client, 0xc000 rel mov %di,%cx # Size of inc %cx # client + mov $(MEM_BTX)>>4,%dx # Segment + mov %dx,%ds # addressing 0x9000 mov $(MEM_USR+2*SIZ_PAG)>>4,%dx # Segment mov %dx,%es # addressing 0xc000 std # Move with decrement rep # Relocate movsb # client - mov %ds,%dx # Back to - mov %dx,%es # zero segment - mov $MEM_BUF,%si # BTX (before reloc) - mov $MEM_BTX,%di # BTX - mov %bx,%cx # Get BTX length - cld # Increment this time - rep # Relocate - movsb # BTX + cld # Back to increment + xor %dx,%dx # Back + mov %ds,%dx # to zero + mov %dx,%es # segment /* * Enable A20 so we can access memory above 1 meg. @@ -210,33 +158,37 @@ seta20.3: sti # Enable interrupts /* - * Trampoline used to call read from within zfsldr. Sets up an EDD - * packet on the stack and passes it to read. + * Read a sector from the disk. Sets up an EDD packet on the stack + * and passes it to read. We assume that the destination address is + * always segment-aligned. * * %eax - int - LBA to read in relative to partition start + * %ebx - ptr - destination address * %dl - byte - drive to read from - * %dh - byte - num sectors to read * %si - ptr - MBR partition entry */ -nread: xor %eax,%eax # Sector offset in partition -nread.1: xor %ecx,%ecx # Get +read: xor %ecx,%ecx # Get addl 0x8(%si),%eax # LBA adc $0,%ecx pushl %ecx # Starting absolute block pushl %eax # block number - push %es # Address of - push $MEM_BUF # transfer buffer - xor %ax,%ax # Number of - movb %dh,%al # blocks to - push %ax # transfer + shr $4,%ebx # Convert to segment + push %bx # Address of + push $0 # transfer buffer + push $0x1 # Read 1 sector push $0x10 # Size of packet - mov %sp,%bp # Packet pointer - callw read # Read from disk - lea 0x10(%bp),%sp # Clear stack - jnc return # If success, return - mov $msg_read,%si # Otherwise, set the error - # message and fall through to - # the error routine + mov %sp,%si # Packet pointer + mov $0x42,%ah # BIOS: Extended + int $0x13 # read + jc read.1 # If error, fail + lea 0x10(%si),%sp # Clear stack + ret # If success, return +read.1: mov %ah,%al # Format + mov $read_err,%di # error + call hex8 # code + mov $msg_read,%si # Set the error message and + # fall through to the error + # routine /* * Print out the error message pointed to by %ds:(%si) followed * by a prompt, wait for a keypress, and then reboot the machine. @@ -257,51 +209,49 @@ putstr.0: mov $0x7,%bx # Page:attribute putstr: lodsb # Get char testb %al,%al # End of string? jne putstr.0 # No - + ret # To caller /* - * Overused return code. ereturn is used to return an error from the - * read function. Since we assume putstr succeeds, we (ab)use the - * same code when we return from putstr. - */ -ereturn: movb $0x1,%ah # Invalid - stc # argument -return: retw # To caller -/* - * Reads sectors from the disk. If EDD is enabled, then check if it is - * installed and use it if it is. If it is not installed or not enabled, then - * fall back to using CHS. Since we use a LBA, if we are using CHS, we have to - * fetch the drive parameters from the BIOS and divide it out ourselves. - * Call with: - * - * %dl - byte - drive number - * stack - 10 bytes - EDD Packet + * Check to see if the disk supports EDD. zfsboot requires EDD and does not + * support older C/H/S disk I/O. */ -read: cmpb $0x80,%dl # Hard drive? - jb read.1 # No, use CHS +check_edd: cmpb $0x80,%dl # Hard drive? + jb check_edd.1 # No, fail to boot mov $0x55aa,%bx # Magic push %dx # Save movb $0x41,%ah # BIOS: Check int $0x13 # extensions present pop %dx # Restore - jc read.1 # If error, use CHS + jc check_edd.1 # If error, fail cmp $0xaa55,%bx # Magic? - jne read.1 # No, so use CHS + jne check_edd.1 # No, so fail testb $0x1,%cl # Packet interface? - jz read.1 # No, so use CHS - mov %bp,%si # Disk packet - movb $0x42,%ah # BIOS: Extended - int $0x13 # read - retw # To caller -read.1: mov $msg_chs,%si - jmp error -msg_chs: .asciz "CHS not supported" + jz check_edd.1 # No, so fail + ret # EDD ok, keep booting +check_edd.1: mov $msg_chs,%si # Warn that CHS is + jmp error # unsupported and fail +/* + * AL to hex, saving the result to [EDI]. + */ +hex8: push %ax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + pop %ax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) /* Messages */ -msg_read: .asciz "Read" -msg_part: .asciz "Boot" +msg_chs: .asciz "CHS not supported" +msg_read: .ascii "Read error: " +read_err: .asciz "XX" +msg_part: .asciz "Boot error" -prompt: .asciz " error\r\n" +prompt: .asciz "\r\n" .org PRT_OFF,0x90 diff --git a/sys/boot/userboot/Makefile b/sys/boot/userboot/Makefile new file mode 100644 index 0000000..f15c905 --- /dev/null +++ b/sys/boot/userboot/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.include <bsd.own.mk> + +SUBDIR= ficl libstand test userboot + +.include <bsd.subdir.mk> + diff --git a/sys/boot/userboot/ficl/Makefile b/sys/boot/userboot/ficl/Makefile new file mode 100644 index 0000000..af5d1461 --- /dev/null +++ b/sys/boot/userboot/ficl/Makefile @@ -0,0 +1,73 @@ +# $FreeBSD$ +# +.include <bsd.own.mk> +MK_SSP= no + +.PATH: ${.CURDIR}/../../ficl +.PATH: ${.CURDIR}/../../ficl/${MACHINE_CPUARCH} +BASE_SRCS= dict.c ficl.c fileaccess.c float.c loader.c math64.c \ + prefix.c search.c stack.c tools.c vm.c words.c + +SRCS= ${BASE_SRCS} sysdep.c softcore.c +CLEANFILES= softcore.c testmain testmain.o +CFLAGS+= -ffreestanding -fPIC +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" +CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 +.endif +.if ${MACHINE_CPUARCH} == "i386" +CFLAGS+= -mpreferred-stack-boundary=2 +CFLAGS+= -mno-sse3 +.endif +.if ${MACHINE_CPUARCH} == "powerpc" || ${MACHINE_CPUARCH} == "arm" +CFLAGS+= -msoft-float +.endif +.if ${MACHINE} == "pc98" +CFLAGS+= -Os -DPC98 +.endif +.if HAVE_PNP +CFLAGS+= -DHAVE_PNP +.endif +.ifmake testmain +CFLAGS+= -DTESTMAIN -D_TESTMAIN +SRCS+= testmain.c +PROG= testmain +.include <bsd.prog.mk> +.else +LIB= ficl +INTERNALLIB= +.include <bsd.lib.mk> +.endif + +# Standard softwords +.PATH: ${.CURDIR}/../../ficl/softwords +SOFTWORDS= softcore.fr jhlocal.fr marker.fr freebsd.fr ficllocal.fr \ + ifbrack.fr +# Optional OO extension softwords +#SOFTWORDS+= oo.fr classes.fr + +#.if ${MACHINE_CPUARCH} == "amd64" +#CFLAGS+= -m32 -march=i386 -I. +#.endif + +.if ${MACHINE_ARCH} == "powerpc64" +CFLAGS+= -m32 -mcpu=powerpc -I. +.endif + +CFLAGS+= -I${.CURDIR}/../../ficl +CFLAGS+= -I${.CURDIR}/../../ficl/${MACHINE_CPUARCH} +CFLAGS+= -I${.CURDIR}/../../common + +softcore.c: ${SOFTWORDS} softcore.awk + (cd ${.CURDIR}/../../ficl/softwords; cat ${SOFTWORDS} \ + | awk -f softcore.awk -v datestamp="`LC_ALL=C date`") > ${.TARGET} + +#.if ${MACHINE_CPUARCH} == "amd64" +#${SRCS:M*.c:R:S/$/.o/g}: machine +# +#beforedepend ${OBJS}: machine +# +#machine: +# ln -sf ${.CURDIR}/../../i386/include machine +# +#CLEANFILES+= machine +#.endif diff --git a/sys/boot/userboot/libstand/Makefile b/sys/boot/userboot/libstand/Makefile new file mode 100644 index 0000000..9e71a24 --- /dev/null +++ b/sys/boot/userboot/libstand/Makefile @@ -0,0 +1,161 @@ +# $FreeBSD$ +# Originally from $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $ +# +# Notes: +# - We don't use the libc strerror/sys_errlist because the string table is +# quite large. +# + +WITHOUT_SSP= +NO_MAN= + +.include <bsd.own.mk> + +S= ${.CURDIR}/../../../../lib/libstand + +.PATH: ${S} +LIB= stand +INTERNALLIB= +NO_PROFILE= +NO_PIC= + +WARNS?= 0 + +CFLAGS+= -ffreestanding -Wformat -fPIC +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand + +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64" +CFLAGS+= -mno-mmx -mno-3dnow -mno-sse -mno-sse2 +.endif +.if ${MACHINE_CPUARCH} == "i386" +CFLAGS+= -mpreferred-stack-boundary=2 +CFLAGS+= -mno-sse3 +.endif +.if ${MACHINE} == "pc98" +CFLAGS+= -Os +.endif +.if ${MACHINE_CPUARCH} == "powerpc" +CFLAGS+= -msoft-float -D_STANDALONE -DNETIF_DEBUG +.endif +.if ${MACHINE_CPUARCH} == "arm" +CFLAGS+= -msoft-float -D_STANDALONE +.endif + +# standalone components and stuff we have modified locally +SRCS+= zutil.h __main.c assert.c bcd.c bswap.c environment.c getopt.c gets.c \ + globals.c pager.c printf.c strdup.c strerror.c strtol.c random.c \ + sbrk.c twiddle.c zalloc.c zalloc_malloc.c + +# private (pruned) versions of libc string functions +SRCS+= strcasecmp.c + +LIBC= ${.CURDIR}/../../../../lib/libc + +.PATH: ${LIBC}/net + +SRCS+= ntoh.c + +# string functions from libc +.PATH: ${LIBC}/string +.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "powerpc" || \ + ${MACHINE_CPUARCH} == "sparc64" || ${MACHINE_CPUARCH} == "amd64" || \ + ${MACHINE_CPUARCH} == "arm" +SRCS+= bcmp.c bcopy.c bzero.c ffs.c index.c memccpy.c memchr.c memcmp.c \ + memcpy.c memmove.c memset.c qdivrem.c rindex.c strcat.c strchr.c \ + strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c \ + strpbrk.c strrchr.c strsep.c strspn.c strstr.c strtok.c swab.c +.endif +.if ${MACHINE_CPUARCH} == "arm" +.PATH: ${LIBC}/arm/gen +SRCS+= divsi3.S +.endif +.if ${MACHINE_CPUARCH} == "ia64" +.PATH: ${LIBC}/ia64/string +SRCS+= bcmp.c bcopy.S bzero.S ffs.S index.c memccpy.c memchr.c memcmp.c \ + memcpy.S memmove.S memset.c rindex.c strcat.c strchr.c \ + strcmp.c strcpy.c strcspn.c strlen.c \ + strncat.c strncmp.c strncpy.c strpbrk.c strrchr.c strsep.c \ + strspn.c strstr.c strtok.c swab.c + +.PATH: ${LIBC}/ia64/gen +SRCS+= __divdi3.S __divsi3.S __moddi3.S __modsi3.S +SRCS+= __udivdi3.S __udivsi3.S __umoddi3.S __umodsi3.S +.endif +.if ${MACHINE_CPUARCH} == "powerpc" +.PATH: ${LIBC}/libc/quad +SRCS+= ashldi3.c ashrdi3.c +.PATH: ${LIBC}/powerpc/gen +SRCS+= syncicache.c +.endif + +# uuid functions from libc +.PATH: ${LIBC}/uuid +SRCS+= uuid_equal.c uuid_is_nil.c + +# _setjmp/_longjmp +.if ${MACHINE_CPUARCH} == "amd64" +.PATH: ${.CURDIR}/amd64 +.elif ${MACHINE_ARCH} == "powerpc64" +.PATH: ${S}/powerpc +.else +.PATH: ${S}/${MACHINE_CPUARCH} +.endif +SRCS+= _setjmp.S + +# decompression functionality from libbz2 +# NOTE: to actually test this functionality after libbz2 upgrade compile +# loader(8) with LOADER_BZIP2_SUPPORT defined +.PATH: ${.CURDIR}/../../../../contrib/bzip2 +CFLAGS+= -DBZ_NO_STDIO -DBZ_NO_COMPRESS +SRCS+= libstand_bzlib_private.h + +.for file in bzlib.c crctable.c decompress.c huffman.c randtable.c +SRCS+= _${file} +CLEANFILES+= _${file} + +_${file}: ${file} + sed "s|bzlib_private\.h|libstand_bzlib_private.h|" ${.ALLSRC} > ${.TARGET} +.endfor + +CLEANFILES+= libstand_bzlib_private.h +libstand_bzlib_private.h: bzlib_private.h + sed -e 's|<stdlib.h>|"stand.h"|' \ + ${.ALLSRC} > ${.TARGET} + +# decompression functionality from libz +.PATH: ${.CURDIR}/../../../../lib/libz +CFLAGS+=-DHAVE_MEMCPY -I${.CURDIR}/../../../../lib/libz +SRCS+= adler32.c crc32.c libstand_zutil.h + +.for file in infback.c inffast.c inflate.c inftrees.c zutil.c +SRCS+= _${file} +CLEANFILES+= _${file} + +_${file}: ${file} + sed "s|zutil\.h|libstand_zutil.h|" ${.ALLSRC} > ${.TARGET} +.endfor + +# depend on stand.h being able to be included multiple times +CLEANFILES+= libstand_zutil.h +libstand_zutil.h: zutil.h + sed -e 's|<stddef.h>|"stand.h"|' \ + -e 's|<string.h>|"stand.h"|' \ + -e 's|<stdlib.h>|"stand.h"|' \ + ${.ALLSRC} > ${.TARGET} + +# io routines +SRCS+= closeall.c dev.c ioctl.c nullfs.c stat.c \ + fstat.c close.c lseek.c open.c read.c write.c readdir.c + +# network routines +SRCS+= arp.c ether.c inet_ntoa.c in_cksum.c net.c udp.c netif.c rpc.c + +# network info services: +SRCS+= bootp.c rarp.c bootparam.c + +# boot filesystems +SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c +SRCS+= dosfs.c ext2fs.c +SRCS+= splitfs.c + +.include <bsd.lib.mk> diff --git a/sys/boot/userboot/libstand/amd64/_setjmp.S b/sys/boot/userboot/libstand/amd64/_setjmp.S new file mode 100644 index 0000000..e841f49 --- /dev/null +++ b/sys/boot/userboot/libstand/amd64/_setjmp.S @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) + .asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90" +#endif /* LIBC_SCCS and not lint */ +#include <machine/asm.h> +__FBSDID("$FreeBSD$"); + +/* + * C library -- _setjmp, _longjmp + * + * _longjmp(a,v) + * will generate a "return(v)" from the last call to + * _setjmp(a) + * by restoring registers from the environment 'a'. + * The previous signal state is NOT restored. + */ + +ENTRY(_setjmp) + movq %rdi,%rax + movq 0(%rsp),%rdx /* retval */ + movq %rdx, 0(%rax) /* 0; retval */ + movq %rbx, 8(%rax) /* 1; rbx */ + movq %rsp,16(%rax) /* 2; rsp */ + movq %rbp,24(%rax) /* 3; rbp */ + movq %r12,32(%rax) /* 4; r12 */ + movq %r13,40(%rax) /* 5; r13 */ + movq %r14,48(%rax) /* 6; r14 */ + movq %r15,56(%rax) /* 7; r15 */ + fnstcw 64(%rax) /* 8; fpu cw */ + stmxcsr 68(%rax) /* and mxcsr */ + xorq %rax,%rax + ret +END(_setjmp) + + .weak CNAME(_longjmp) +ENTRY(_longjmp) + movq %rdi,%rdx + /* Restore the mxcsr, but leave exception flags intact. */ + stmxcsr -4(%rsp) + movl 68(%rdx),%eax + andl $0xffffffc0,%eax + movl -4(%rsp),%edi + andl $0x3f,%edi + xorl %eax,%edi + movl %edi,-4(%rsp) + ldmxcsr -4(%rsp) + movq %rsi,%rax /* retval */ + movq 0(%rdx),%rcx + movq 8(%rdx),%rbx + movq 16(%rdx),%rsp + movq 24(%rdx),%rbp + movq 32(%rdx),%r12 + movq 40(%rdx),%r13 + movq 48(%rdx),%r14 + movq 56(%rdx),%r15 + fldcw 64(%rdx) + testq %rax,%rax + jnz 1f + incq %rax +1: movq %rcx,0(%rsp) + ret +END(_longjmp) diff --git a/sys/boot/userboot/test/Makefile b/sys/boot/userboot/test/Makefile new file mode 100644 index 0000000..24d89b7 --- /dev/null +++ b/sys/boot/userboot/test/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + + +NO_MAN= +WITHOUT_SSP= + +.include <bsd.own.mk> + +PROG= test +INTERNALPROG= + +CFLAGS+= -I${.CURDIR}/.. +CFLAGS+= -I${.CURDIR}/../../.. + +.include <bsd.prog.mk> diff --git a/sys/boot/userboot/test/test.c b/sys/boot/userboot/test/test.c new file mode 100644 index 0000000..a752a80 --- /dev/null +++ b/sys/boot/userboot/test/test.c @@ -0,0 +1,428 @@ +/*- + * Copyright (c) 2011 Google, 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 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. + * + * $FreeBSD$ + */ + +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <dirent.h> +#include <dlfcn.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> + +#include <boot/userboot/userboot.h> + +char *host_base = NULL; +struct termios term, oldterm; +char *image; +size_t image_size; +int disk_fd = -1; + +uint64_t regs[16]; +uint64_t pc; + +void test_exit(void *arg, int v); + +/* + * Console i/o + */ + +void +test_putc(void *arg, int ch) +{ + char c = ch; + + write(1, &c, 1); +} + +int +test_getc(void *arg) +{ + char c; + + if (read(0, &c, 1) == 1) + return c; + return -1; +} + +int +test_poll(void *arg) +{ + int n; + + if (ioctl(0, FIONREAD, &n) >= 0) + return (n > 0); + return (0); +} + +/* + * Host filesystem i/o + */ + +struct test_file { + int tf_isdir; + size_t tf_size; + struct stat tf_stat; + union { + int fd; + DIR *dir; + } tf_u; +}; + +int +test_open(void *arg, const char *filename, void **h_return) +{ + struct stat st; + struct test_file *tf; + char path[PATH_MAX]; + + if (!host_base) + return (ENOENT); + + strlcpy(path, host_base, PATH_MAX); + if (path[strlen(path) - 1] == '/') + path[strlen(path) - 1] = 0; + strlcat(path, filename, PATH_MAX); + tf = malloc(sizeof(struct test_file)); + if (stat(path, &tf->tf_stat) < 0) { + free(tf); + return (errno); + } + + tf->tf_size = st.st_size; + if (S_ISDIR(tf->tf_stat.st_mode)) { + tf->tf_isdir = 1; + tf->tf_u.dir = opendir(path); + if (!tf->tf_u.dir) + goto out; + *h_return = tf; + return (0); + } + if (S_ISREG(tf->tf_stat.st_mode)) { + tf->tf_isdir = 0; + tf->tf_u.fd = open(path, O_RDONLY); + if (tf->tf_u.fd < 0) + goto out; + *h_return = tf; + return (0); + } + +out: + free(tf); + return (EINVAL); +} + +int +test_close(void *arg, void *h) +{ + struct test_file *tf = h; + + if (tf->tf_isdir) + closedir(tf->tf_u.dir); + else + close(tf->tf_u.fd); + free(tf); + + return (0); +} + +int +test_isdir(void *arg, void *h) +{ + struct test_file *tf = h; + + return (tf->tf_isdir); +} + +int +test_read(void *arg, void *h, void *dst, size_t size, size_t *resid_return) +{ + struct test_file *tf = h; + ssize_t sz; + + if (tf->tf_isdir) + return (EINVAL); + sz = read(tf->tf_u.fd, dst, size); + if (sz < 0) + return (EINVAL); + *resid_return = size - sz; + return (0); +} + +int +test_readdir(void *arg, void *h, uint32_t *fileno_return, uint8_t *type_return, + size_t *namelen_return, char *name) +{ + struct test_file *tf = h; + struct dirent *dp; + + if (!tf->tf_isdir) + return (EINVAL); + + dp = readdir(tf->tf_u.dir); + if (!dp) + return (ENOENT); + + /* + * Note: d_namlen is in the range 0..255 and therefore less + * than PATH_MAX so we don't need to test before copying. + */ + *fileno_return = dp->d_fileno; + *type_return = dp->d_type; + *namelen_return = dp->d_namlen; + memcpy(name, dp->d_name, dp->d_namlen); + name[dp->d_namlen] = 0; + + return (0); +} + +int +test_seek(void *arg, void *h, uint64_t offset, int whence) +{ + struct test_file *tf = h; + + if (tf->tf_isdir) + return (EINVAL); + if (lseek(tf->tf_u.fd, offset, whence) < 0) + return (errno); + return (0); +} + +int +test_stat(void *arg, void *h, int *mode_return, int *uid_return, int *gid_return, + uint64_t *size_return) +{ + struct test_file *tf = h; + + *mode_return = tf->tf_stat.st_mode; + *uid_return = tf->tf_stat.st_uid; + *gid_return = tf->tf_stat.st_gid; + *size_return = tf->tf_stat.st_size; + return (0); +} + +/* + * Disk image i/o + */ + +int +test_diskread(void *arg, int unit, uint64_t offset, void *dst, size_t size, + size_t *resid_return) +{ + ssize_t n; + + if (unit != 0 || disk_fd == -1) + return (EIO); + n = pread(disk_fd, dst, size, offset); + if (n < 0) + return (errno); + *resid_return = size - n; + return (0); +} + +/* + * Guest virtual machine i/o + * + * Note: guest addresses are kernel virtual + */ + +int +test_copyin(void *arg, const void *from, uint64_t to, size_t size) +{ + + to &= 0x7fffffff; + if (to > image_size) + return (EFAULT); + if (to + size > image_size) + size = image_size - to; + memcpy(&image[to], from, size); +} + +int +test_copyout(void *arg, uint64_t from, void *to, size_t size) +{ + + from &= 0x7fffffff; + if (from > image_size) + return (EFAULT); + if (from + size > image_size) + size = image_size - from; + memcpy(to, &image[from], size); +} + +void +test_setreg(void *arg, int r, uint64_t v) +{ + + if (r < 0 || r >= 16) + return; + regs[r] = v; +} + +void +test_setmsr(void *arg, int r, uint64_t v) +{ +} + +void +test_setcr(void *arg, int r, uint64_t v) +{ +} + +void +test_setgdt(void *arg, uint64_t v, size_t sz) +{ +} + +void +test_exec(void *arg, uint64_t pc) +{ + printf("Execute at 0x%llx\n", pc); + test_exit(arg, 0); +} + +/* + * Misc + */ + +void +test_delay(void *arg, int usec) +{ + + usleep(usec); +} + +void +test_exit(void *arg, int v) +{ + + tcsetattr(0, TCSAFLUSH, &oldterm); + exit(v); +} + +void +test_getmem(void *arg, uint64_t *lowmem, uint64_t *highmem) +{ + + *lowmem = 128*1024*1024; + *highmem = 0; +} + +struct loader_callbacks_v1 cb = { + .putc = test_putc, + .getc = test_getc, + .poll = test_poll, + + .open = test_open, + .close = test_close, + .isdir = test_isdir, + .read = test_read, + .readdir = test_readdir, + .seek = test_seek, + .stat = test_stat, + + .diskread = test_diskread, + + .copyin = test_copyin, + .copyout = test_copyout, + .setreg = test_setreg, + .setmsr = test_setmsr, + .setcr = test_setcr, + .setgdt = test_setgdt, + .exec = test_exec, + + .delay = test_delay, + .exit = test_exit, + .getmem = test_getmem, +}; + +void +usage() +{ + + printf("usage: %s [-d <disk image path>] [-h <host filesystem path>\n"); + exit(1); +} + +int +main(int argc, char** argv) +{ + void *h; + void (*func)(struct loader_callbacks_v1 *, void *, int, int); + int opt; + char *disk_image = NULL; + + while ((opt = getopt(argc, argv, "d:h:")) != -1) { + switch (opt) { + case 'd': + disk_image = optarg; + break; + + case 'h': + host_base = optarg; + break; + + case '?': + usage(); + } + } + + h = dlopen("/boot/userboot.so", + RTLD_LOCAL); + if (!h) { + printf("%s\n", dlerror()); + return (1); + } + func = dlsym(h, "loader_main"); + if (!func) { + printf("%s\n", dlerror()); + return (1); + } + + image_size = 128*1024*1024; + image = malloc(image_size); + if (disk_image) { + disk_fd = open(disk_image, O_RDONLY); + if (disk_fd < 0) + err(1, "Can't open disk image '%s'", disk_image); + } + + tcgetattr(0, &term); + oldterm = term; + term.c_iflag &= ~(ICRNL); + term.c_lflag &= ~(ICANON|ECHO); + tcsetattr(0, TCSAFLUSH, &term); + + func(&cb, NULL, USERBOOT_VERSION_1, disk_fd >= 0); +} diff --git a/sys/boot/userboot/userboot.h b/sys/boot/userboot/userboot.h new file mode 100644 index 0000000..7d8263e --- /dev/null +++ b/sys/boot/userboot/userboot.h @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 2011 Doug Rabson + * 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. + * + * $FreeBSD$ + */ + +/* + * USERBOOT interface versions + */ +#define USERBOOT_VERSION_1 1 + +/* + * Exit codes from the loader + */ +#define USERBOOT_EXIT_QUIT 1 +#define USERBOOT_EXIT_REBOOT 2 + +struct loader_callbacks_v1 { + /* + * Console i/o + */ + + /* + * Wait until a key is pressed on the console and then return it + */ + int (*getc)(void *arg); + + /* + * Write the character ch to the console + */ + void (*putc)(void *arg, int ch); + + /* + * Return non-zero if a key can be read from the console + */ + int (*poll)(void *arg); + + /* + * Host filesystem i/o + */ + + /* + * Open a file in the host filesystem + */ + int (*open)(void *arg, const char *filename, void **h_return); + + /* + * Close a file + */ + int (*close)(void *arg, void *h); + + /* + * Return non-zero if the file is a directory + */ + int (*isdir)(void *arg, void *h); + + /* + * Read size bytes from a file. The number of bytes remaining + * in dst after reading is returned in *resid_return + */ + int (*read)(void *arg, void *h, void *dst, size_t size, + size_t *resid_return); + + /* + * Read an entry from a directory. The entry's inode number is + * returned in *fileno_return, its type in *type_return and + * the name length in *namelen_return. The name itself is + * copied to the buffer name which must be at least PATH_MAX + * in size. + */ + int (*readdir)(void *arg, void *h, uint32_t *fileno_return, + uint8_t *type_return, size_t *namelen_return, char *name); + + /* + * Seek to a location within an open file + */ + int (*seek)(void *arg, void *h, uint64_t offset, + int whence); + + /* + * Return some stat(2) related information about the file + */ + int (*stat)(void *arg, void *h, int *mode_return, + int *uid_return, int *gid_return, uint64_t *size_return); + + /* + * Disk image i/o + */ + + /* + * Read from a disk image at the given offset + */ + int (*diskread)(void *arg, int unit, uint64_t offset, + void *dst, size_t size, size_t *resid_return); + + /* + * Guest virtual machine i/o + */ + + /* + * Copy to the guest address space + */ + int (*copyin)(void *arg, const void *from, + uint64_t to, size_t size); + + /* + * Copy from the guest address space + */ + int (*copyout)(void *arg, uint64_t from, + void *to, size_t size); + + /* + * Set a guest register value + */ + void (*setreg)(void *arg, int, uint64_t); + + /* + * Set a guest MSR value + */ + void (*setmsr)(void *arg, int, uint64_t); + + /* + * Set a guest CR value + */ + void (*setcr)(void *arg, int, uint64_t); + + /* + * Set the guest GDT address + */ + void (*setgdt)(void *arg, uint64_t, size_t); + + /* + * Transfer control to the guest at the given address + */ + void (*exec)(void *arg, uint64_t pc); + + /* + * Misc + */ + + /* + * Sleep for usec microseconds + */ + void (*delay)(void *arg, int usec); + + /* + * Exit with the given exit code + */ + void (*exit)(void *arg, int v); + + /* + * Return guest physical memory map details + */ + void (*getmem)(void *arg, uint64_t *lowmem, + uint64_t *highmem); +}; diff --git a/sys/boot/userboot/userboot/Makefile b/sys/boot/userboot/userboot/Makefile new file mode 100644 index 0000000..7271fa7 --- /dev/null +++ b/sys/boot/userboot/userboot/Makefile @@ -0,0 +1,61 @@ +# $FreeBSD$ + +NO_MAN= +WITHOUT_SSP= + +.include <bsd.own.mk> + +SHLIB_NAME= userboot.so +NO_CTF= yes +STRIP= +LIBDIR= /boot + +SRCS= autoload.c +SRCS+= bootinfo.c +SRCS+= bootinfo32.c +SRCS+= bootinfo64.c +SRCS+= conf.c +SRCS+= console.c +SRCS+= copy.c +SRCS+= devicename.c +SRCS+= elf32_freebsd.c +SRCS+= elf64_freebsd.c +SRCS+= host.c +SRCS+= main.c +SRCS+= userboot_cons.c +SRCS+= userboot_disk.c +SRCS+= vers.c + +CFLAGS+= -Wall +CFLAGS+= -I${.CURDIR}/.. +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I${.CURDIR}/../../.. +CFLAGS+= -I${.CURDIR}/../../../../lib/libstand +CFLAGS+= -ffreestanding -I. +CFLAGS+= -DLOADER_GPT_SUPPORT + +LDFLAGS+= -nostdlib -Wl,-Bsymbolic + +NEWVERSWHAT= "User boot" ${MACHINE_CPUARCH} + +vers.c: ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version + sh ${.CURDIR}/../../common/newvers.sh ${.CURDIR}/version ${NEWVERSWHAT} + +CLEANFILES= vers.c + +.if ${MK_FORTH} != "no" +BOOT_FORTH= yes +CFLAGS+= -DBOOT_FORTH -I${.CURDIR}/../../ficl -I${.CURDIR}/../../ficl/i386 +LIBFICL= ${.OBJDIR}/../ficl/libficl.a +LIBSTAND= ${.OBJDIR}/../libstand/libstand.a +.endif + +# Always add MI sources +.PATH: ${.CURDIR}/../../common +.include "${.CURDIR}/../../common/Makefile.inc" +CFLAGS+= -I${.CURDIR}/../../common +CFLAGS+= -I. +DPADD= ${LIBFICL} ${LIBSTAND} +LDADD= ${LIBFICL} ${LIBSTAND} + +.include <bsd.lib.mk> diff --git a/sys/boot/userboot/userboot/autoload.c b/sys/boot/userboot/userboot/autoload.c new file mode 100644 index 0000000..a86afcf --- /dev/null +++ b/sys/boot/userboot/userboot/autoload.c @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2011 Google, 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 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$"); + +int +userboot_autoload(void) +{ + + return (0); +} diff --git a/sys/boot/userboot/userboot/bootinfo.c b/sys/boot/userboot/userboot/bootinfo.c new file mode 100644 index 0000000..75ad5e7 --- /dev/null +++ b/sys/boot/userboot/userboot/bootinfo.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +/* + * Return a 'boothowto' value corresponding to the kernel arguments in + * (kargs) and any relevant environment variables. + */ +static struct +{ + const char *ev; + int mask; +} howto_names[] = { + {"boot_askname", RB_ASKNAME}, + {"boot_cdrom", RB_CDROM}, + {"boot_ddb", RB_KDB}, + {"boot_dfltroot", RB_DFLTROOT}, + {"boot_gdb", RB_GDB}, + {"boot_multicons", RB_MULTIPLE}, + {"boot_mute", RB_MUTE}, + {"boot_pause", RB_PAUSE}, + {"boot_serial", RB_SERIAL}, + {"boot_single", RB_SINGLE}, + {"boot_verbose", RB_VERBOSE}, + {NULL, 0} +}; + +int +bi_getboothowto(char *kargs) +{ + char *cp; + char *curpos, *next, *string; + int howto; + int active; + int i; + int vidconsole; + + /* Parse kargs */ + howto = 0; + if (kargs != NULL) { + cp = kargs; + active = 0; + while (*cp != 0) { + if (!active && (*cp == '-')) { + active = 1; + } else if (active) + switch (*cp) { + case 'a': + howto |= RB_ASKNAME; + break; + case 'C': + howto |= RB_CDROM; + break; + case 'd': + howto |= RB_KDB; + break; + case 'D': + howto |= RB_MULTIPLE; + break; + case 'm': + howto |= RB_MUTE; + break; + case 'g': + howto |= RB_GDB; + break; + case 'h': + howto |= RB_SERIAL; + break; + case 'p': + howto |= RB_PAUSE; + break; + case 'r': + howto |= RB_DFLTROOT; + break; + case 's': + howto |= RB_SINGLE; + break; + case 'v': + howto |= RB_VERBOSE; + break; + default: + active = 0; + break; + } + cp++; + } + } + /* get equivalents from the environment */ + for (i = 0; howto_names[i].ev != NULL; i++) + if (getenv(howto_names[i].ev) != NULL) + howto |= howto_names[i].mask; + + /* Enable selected consoles */ + string = next = strdup(getenv("console")); + vidconsole = 0; + while (next != NULL) { + curpos = strsep(&next, " ,"); + if (*curpos == '\0') + continue; + if (!strcmp(curpos, "vidconsole")) + vidconsole = 1; + else if (!strcmp(curpos, "comconsole")) + howto |= RB_SERIAL; + else if (!strcmp(curpos, "nullconsole")) + howto |= RB_MUTE; + } + + if (vidconsole && (howto & RB_SERIAL)) + howto |= RB_MULTIPLE; + + /* + * XXX: Note that until the kernel is ready to respect multiple consoles + * for the boot messages, the first named console is the primary console + */ + if (!strcmp(string, "vidconsole")) + howto &= ~RB_SERIAL; + + free(string); + + return(howto); +} + +void +bi_setboothowto(int howto) +{ + int i; + + for (i = 0; howto_names[i].ev != NULL; i++) + if (howto & howto_names[i].mask) + setenv(howto_names[i].ev, "YES", 1); +} + +/* + * Copy the environment into the load area starting at (addr). + * Each variable is formatted as <name>=<value>, with a single nul + * separating each variable, and a double nul terminating the environment. + */ +vm_offset_t +bi_copyenv(vm_offset_t addr) +{ + struct env_var *ep; + + /* traverse the environment */ + for (ep = environ; ep != NULL; ep = ep->ev_next) { + CALLBACK(copyin, ep->ev_name, addr, strlen(ep->ev_name)); + addr += strlen(ep->ev_name); + CALLBACK(copyin, "=", addr, 1); + addr++; + if (ep->ev_value != NULL) { + CALLBACK(copyin, ep->ev_value, addr, strlen(ep->ev_value)); + addr += strlen(ep->ev_value); + } + CALLBACK(copyin, "", addr, 1); + addr++; + } + CALLBACK(copyin, "", addr, 1); + addr++; + return(addr); +} diff --git a/sys/boot/userboot/userboot/bootinfo32.c b/sys/boot/userboot/userboot/bootinfo32.c new file mode 100644 index 0000000..00784c9 --- /dev/null +++ b/sys/boot/userboot/userboot/bootinfo32.c @@ -0,0 +1,264 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <i386/include/bootinfo.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +static struct bootinfo bi; + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + CALLBACK(copyin, &x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + CALLBACK(copyin, s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_long));\ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + CALLBACK(copyin, &s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_long)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + CALLBACK(copyin, mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_long));\ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules32(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + MOD_ADDR(addr, fp->f_addr, c); + MOD_SIZE(addr, fp->f_size, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +/* + * Load the information expected by an i386 kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, vm_offset_t *modulep, vm_offset_t *kernendp) +{ + struct preloaded_file *xp, *kfp; + struct i386_devdesc *rootdev; + struct file_metadata *md; + vm_offset_t addr; + vm_offset_t kernend; + vm_offset_t envp; + vm_offset_t size; + vm_offset_t ssym, esym; + char *rootdevname; + int bootdevnr, i, howto; + char *kernelname; + const char *kernelpath; + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + userboot_getdev((void **)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { /* bad $rootdev/$currdev */ + printf("can't determine root device\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(userboot_fmtdev((void *)rootdev)); + + bootdevnr = 0; +#if 0 + if (bootdevnr == -1) { + printf("root device %s invalid\n", i386_fmtdev(rootdev)); + return (EINVAL); + } +#endif + free(rootdev); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = bi_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf32 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); +#if 0 + bios_addsmapdata(kfp); +#endif + + /* Figure out the size and location of the metadata */ + *modulep = addr; + size = bi_copymodules32(0); + kernend = roundup(addr + size, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + + /* copy module list and metadata */ + (void)bi_copymodules32(addr); + + ssym = esym = 0; + md = file_findmetadata(kfp, MODINFOMD_SSYM); + if (md != NULL) + ssym = *((vm_offset_t *)&(md->md_data)); + md = file_findmetadata(kfp, MODINFOMD_ESYM); + if (md != NULL) + esym = *((vm_offset_t *)&(md->md_data)); + if (ssym == 0 || esym == 0) + ssym = esym = 0; /* sanity */ + + /* legacy bootinfo structure */ + kernelname = getenv("kernelname"); + userboot_getdev(NULL, kernelname, &kernelpath); + bi.bi_version = BOOTINFO_VERSION; + bi.bi_kernelname = 0; /* XXX char * -> kernel name */ + bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */ + bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */ +#if 0 + for (i = 0; i < N_BIOS_GEOM; i++) + bi.bi_bios_geom[i] = bd_getbigeom(i); +#endif + bi.bi_size = sizeof(bi); + bi.bi_memsizes_valid = 1; +#if 0 + bi.bi_basemem = bios_basemem / 1024; + bi.bi_extmem = bios_extmem / 1024; +#endif + bi.bi_envp = envp; + bi.bi_modulep = *modulep; + bi.bi_kernend = kernend; + bi.bi_symtab = ssym; /* XXX this is only the primary kernel symtab */ + bi.bi_esymtab = esym; + + /* + * Copy the legacy bootinfo and kernel name to the guest at 0x2000 + */ + bi.bi_kernelname = (char *) (0x2000 + sizeof(bi)); + CALLBACK(copyin, &bi, 0x2000, sizeof(bi)); + CALLBACK(copyin, kernelname, 0x2000 + sizeof(bi), strlen(kernelname) + 1); + + /* legacy boot arguments */ + *howtop = howto | RB_BOOTINFO; + *bootdevp = bootdevnr; + *bip = 0x2000; + + return(0); +} diff --git a/sys/boot/userboot/userboot/bootinfo64.c b/sys/boot/userboot/userboot/bootinfo64.c new file mode 100644 index 0000000..fc7c14d --- /dev/null +++ b/sys/boot/userboot/userboot/bootinfo64.c @@ -0,0 +1,304 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <stand.h> +#include <sys/param.h> +#include <sys/reboot.h> +#include <sys/linker.h> +#include <i386/include/bootinfo.h> +#include <machine/cpufunc.h> +#include <machine/psl.h> +#include <machine/specialreg.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +/* + * Copy module-related data into the load area, where it can be + * used as a directory for loaded modules. + * + * Module data is presented in a self-describing format. Each datum + * is preceded by a 32-bit identifier and a 32-bit size field. + * + * Currently, the following data are saved: + * + * MOD_NAME (variable) module name (string) + * MOD_TYPE (variable) module type (string) + * MOD_ARGS (variable) module parameters (string) + * MOD_ADDR sizeof(vm_offset_t) module load address + * MOD_SIZE sizeof(size_t) module size + * MOD_METADATA (variable) type-specific metadata + */ +#define COPY32(v, a, c) { \ + u_int32_t x = (v); \ + if (c) \ + CALLBACK(copyin, &x, a, sizeof(x)); \ + a += sizeof(x); \ +} + +#define MOD_STR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(strlen(s) + 1, a, c); \ + if (c) \ + CALLBACK(copyin, s, a, strlen(s) + 1); \ + a += roundup(strlen(s) + 1, sizeof(u_int64_t));\ +} + +#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c) +#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c) +#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c) + +#define MOD_VAR(t, a, s, c) { \ + COPY32(t, a, c); \ + COPY32(sizeof(s), a, c); \ + if (c) \ + CALLBACK(copyin, &s, a, sizeof(s)); \ + a += roundup(sizeof(s), sizeof(u_int64_t)); \ +} + +#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c) +#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c) + +#define MOD_METADATA(a, mm, c) { \ + COPY32(MODINFO_METADATA | mm->md_type, a, c); \ + COPY32(mm->md_size, a, c); \ + if (c) \ + CALLBACK(copyin, mm->md_data, a, mm->md_size); \ + a += roundup(mm->md_size, sizeof(u_int64_t));\ +} + +#define MOD_END(a, c) { \ + COPY32(MODINFO_END, a, c); \ + COPY32(0, a, c); \ +} + +static vm_offset_t +bi_copymodules64(vm_offset_t addr) +{ + struct preloaded_file *fp; + struct file_metadata *md; + int c; + u_int64_t v; + + c = addr != 0; + /* start with the first module on the list, should be the kernel */ + for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) { + + MOD_NAME(addr, fp->f_name, c); /* this field must come first */ + MOD_TYPE(addr, fp->f_type, c); + if (fp->f_args) + MOD_ARGS(addr, fp->f_args, c); + v = fp->f_addr; + MOD_ADDR(addr, v, c); + v = fp->f_size; + MOD_SIZE(addr, v, c); + for (md = fp->f_metadata; md != NULL; md = md->md_next) + if (!(md->md_type & MODINFOMD_NOCOPY)) + MOD_METADATA(addr, md, c); + } + MOD_END(addr, c); + return(addr); +} + +/* + * Check to see if this CPU supports long mode. + */ +static int +bi_checkcpu(void) +{ +#if 0 + char *cpu_vendor; + int vendor[3]; + int eflags, regs[4]; + + /* Check for presence of "cpuid". */ + eflags = read_eflags(); + write_eflags(eflags ^ PSL_ID); + if (!((eflags ^ read_eflags()) & PSL_ID)) + return (0); + + /* Fetch the vendor string. */ + do_cpuid(0, regs); + vendor[0] = regs[1]; + vendor[1] = regs[3]; + vendor[2] = regs[2]; + cpu_vendor = (char *)vendor; + + /* Check for vendors that support AMD features. */ + if (strncmp(cpu_vendor, INTEL_VENDOR_ID, 12) != 0 && + strncmp(cpu_vendor, AMD_VENDOR_ID, 12) != 0 && + strncmp(cpu_vendor, CENTAUR_VENDOR_ID, 12) != 0) + return (0); + + /* Has to support AMD features. */ + do_cpuid(0x80000000, regs); + if (!(regs[0] >= 0x80000001)) + return (0); + + /* Check for long mode. */ + do_cpuid(0x80000001, regs); + return (regs[3] & AMDID_LM); +#else + return (1); +#endif +} + +struct smap { + uint64_t base; + uint64_t length; + uint32_t type; +} __packed; + +/* From FreeBSD <machine/pc/bios.h> */ +#define SMAP_TYPE_MEMORY 1 + +#define GB (1024UL * 1024 * 1024) + +#define MODINFOMD_SMAP 0x1001 + +static void +bios_addsmapdata(struct preloaded_file *kfp) +{ + uint64_t lowmem, highmem; + int smapnum, len; + struct smap smap[3], *sm; + + CALLBACK(getmem, &lowmem, &highmem); + + sm = &smap[0]; + + sm->base = 0; /* base memory */ + sm->length = 640 * 1024; + sm->type = SMAP_TYPE_MEMORY; + sm++; + + sm->base = 0x100000; /* extended memory */ + sm->length = lowmem - 0x100000; + sm->type = SMAP_TYPE_MEMORY; + sm++; + + smapnum = 2; + + if (highmem != 0) { + sm->base = 4 * GB; + sm->length = highmem; + sm->type = SMAP_TYPE_MEMORY; + smapnum++; + } + + len = smapnum * sizeof (struct smap); + file_addmetadata(kfp, MODINFOMD_SMAP, len, &smap[0]); +} + +/* + * Load the information expected by an amd64 kernel. + * + * - The 'boothowto' argument is constructed + * - The 'bootdev' argument is constructed + * - The 'bootinfo' struct is constructed, and copied into the kernel space. + * - The kernel environment is copied into kernel space. + * - Module metadata are formatted and placed in kernel space. + */ +int +bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernendp) +{ + struct preloaded_file *xp, *kfp; + struct userboot_devdesc *rootdev; + struct file_metadata *md; + vm_offset_t addr; + u_int64_t kernend; + u_int64_t envp; + vm_offset_t size; + char *rootdevname; + int howto; + + if (!bi_checkcpu()) { + printf("CPU doesn't support long mode\n"); + return (EINVAL); + } + + howto = bi_getboothowto(args); + + /* + * Allow the environment variable 'rootdev' to override the supplied device + * This should perhaps go to MI code and/or have $rootdev tested/set by + * MI code before launching the kernel. + */ + rootdevname = getenv("rootdev"); + userboot_getdev((void **)(&rootdev), rootdevname, NULL); + if (rootdev == NULL) { /* bad $rootdev/$currdev */ + printf("can't determine root device\n"); + return(EINVAL); + } + + /* Try reading the /etc/fstab file to select the root device */ + getrootmount(userboot_fmtdev((void *)rootdev)); + + /* find the last module in the chain */ + addr = 0; + for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) { + if (addr < (xp->f_addr + xp->f_size)) + addr = xp->f_addr + xp->f_size; + } + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + /* copy our environment */ + envp = addr; + addr = bi_copyenv(addr); + + /* pad to a page boundary */ + addr = roundup(addr, PAGE_SIZE); + + kfp = file_findfile(NULL, "elf kernel"); + if (kfp == NULL) + kfp = file_findfile(NULL, "elf64 kernel"); + if (kfp == NULL) + panic("can't find kernel file"); + kernend = 0; /* fill it in later */ + file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto); + file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp); + file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend); + bios_addsmapdata(kfp); + + /* Figure out the size and location of the metadata */ + *modulep = addr; + size = bi_copymodules64(0); + kernend = roundup(addr + size, PAGE_SIZE); + *kernendp = kernend; + + /* patch MODINFOMD_KERNEND */ + md = file_findmetadata(kfp, MODINFOMD_KERNEND); + bcopy(&kernend, md->md_data, sizeof kernend); + + /* copy module list and metadata */ + (void)bi_copymodules64(addr); + + return(0); +} diff --git a/sys/boot/userboot/userboot/conf.c b/sys/boot/userboot/userboot/conf.c new file mode 100644 index 0000000..0c57eba --- /dev/null +++ b/sys/boot/userboot/userboot/conf.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1997 + * Matthias Drochner. 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 for the NetBSD Project + * by Matthias Drochner. + * 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 + * 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. + * + * $NetBSD: conf.c,v 1.2 1997/03/22 09:03:29 thorpej Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stand.h> + +#include "libuserboot.h" + +/* + * We could use linker sets for some or all of these, but + * then we would have to control what ended up linked into + * the bootstrap. So it's easier to conditionalise things + * here. + * + * XXX rename these arrays to be consistent and less namespace-hostile + */ + +/* Exported for libstand */ +struct devsw *devsw[] = { + &host_dev, + &userboot_disk, + NULL +}; + +struct fs_ops *file_system[] = { + &host_fsops, + &ufs_fsops, + &gzipfs_fsops, + NULL +}; + +/* Exported for i386 only */ +/* + * Sort formats so that those that can detect based on arguments + * rather than reading the file go first. + */ +extern struct file_format i386_elf; +extern struct file_format i386_elf_obj; +extern struct file_format amd64_elf; +extern struct file_format amd64_elf_obj; + +struct file_format *file_formats[] = { + &i386_elf, + &i386_elf_obj, + &amd64_elf, + &amd64_elf_obj, + NULL +}; + +/* + * Consoles + * + * We don't prototype these in libuserboot.h because they require + * data structures from bootstrap.h as well. + */ +extern struct console userboot_console; + +struct console *consoles[] = { + &userboot_console, + NULL +}; diff --git a/sys/boot/userboot/userboot/copy.c b/sys/boot/userboot/userboot/copy.c new file mode 100644 index 0000000..94548f2 --- /dev/null +++ b/sys/boot/userboot/userboot/copy.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2011 Google, 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 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 <stand.h> + +#include "libuserboot.h" + +ssize_t +userboot_copyin(const void *src, vm_offset_t va, size_t len) +{ + + CALLBACK(copyin, src, va, len); + return (len); +} + +ssize_t +userboot_copyout(vm_offset_t va, void *dst, size_t len) +{ + + CALLBACK(copyout, va, dst, len); + return (len); +} + +ssize_t +userboot_readin(int fd, vm_offset_t va, size_t len) +{ + void *pa; + ssize_t res, s; + size_t sz; + char buf[4096]; + + res = 0; + while (len > 0) { + sz = len; + if (sz > sizeof(buf)) + sz = sizeof(buf); + s = read(fd, buf, sz); + if (s == 0) + break; + if (s < 0) + return (s); + CALLBACK(copyin, buf, va, s); + len -= s; + res += s; + va += s; + } + return (res); +} diff --git a/sys/boot/userboot/userboot/devicename.c b/sys/boot/userboot/userboot/devicename.c new file mode 100644 index 0000000..24c5179 --- /dev/null +++ b/sys/boot/userboot/userboot/devicename.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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 <stand.h> +#include <string.h> +#include <sys/disklabel.h> + +#include "bootstrap.h" +#include "disk.h" +#include "libuserboot.h" + +static int userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path); + +/* + * Point (dev) at an allocated device specifier for the device matching the + * path in (devspec). If it contains an explicit device specification, + * use that. If not, use the default device. + */ +int +userboot_getdev(void **vdev, const char *devspec, const char **path) +{ + struct disk_devdesc **dev = (struct disk_devdesc **)vdev; + int rv; + + /* + * If it looks like this is just a path and no + * device, go with the current device. + */ + if ((devspec == NULL) || + (devspec[0] == '/') || + (strchr(devspec, ':') == NULL)) { + + if (((rv = userboot_parsedev(dev, getenv("currdev"), NULL)) == 0) && + (path != NULL)) + *path = devspec; + return(rv); + } + + /* + * Try to parse the device name off the beginning of the devspec + */ + return(userboot_parsedev(dev, devspec, path)); +} + +/* + * Point (dev) at an allocated device specifier matching the string version + * at the beginning of (devspec). Return a pointer to the remaining + * text in (path). + * + * In all cases, the beginning of (devspec) is compared to the names + * of known devices in the device switch, and then any following text + * is parsed according to the rules applied to the device type. + * + * For disk-type devices, the syntax is: + * + * disk<unit>[s<slice>][<partition>]: + * + */ +static int +userboot_parsedev(struct disk_devdesc **dev, const char *devspec, const char **path) +{ + struct disk_devdesc *idev; + struct devsw *dv; + int i, unit, slice, partition, err; + char *cp; + const char *np; + + /* minimum length check */ + if (strlen(devspec) < 2) + return(EINVAL); + + /* look for a device that matches */ + for (i = 0, dv = NULL; devsw[i] != NULL; i++) { + if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { + dv = devsw[i]; + break; + } + } + if (dv == NULL) + return(ENOENT); + idev = malloc(sizeof(struct disk_devdesc)); + err = 0; + np = (devspec + strlen(dv->dv_name)); + + switch(dv->dv_type) { + case DEVT_NONE: /* XXX what to do here? Do we care? */ + break; + + case DEVT_DISK: + unit = -1; + slice = -1; + partition = -1; + if (*np && (*np != ':')) { + unit = strtol(np, &cp, 10); /* next comes the unit number */ + if (cp == np) { + err = EUNIT; + goto fail; + } +#ifdef LOADER_GPT_SUPPORT + if (*cp == 'p') { /* got a GPT partition */ + np = cp + 1; + slice = strtol(np, &cp, 10); + if (cp == np) { + err = ESLICE; + goto fail; + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + partition = 0xff; + } else { +#endif + if (*cp == 's') { /* got a slice number */ + np = cp + 1; + slice = strtol(np, &cp, 10); + if (cp == np) { + err = ESLICE; + goto fail; + } + } + if (*cp && (*cp != ':')) { + partition = *cp - 'a'; /* got a partition number */ + if ((partition < 0) || (partition >= MAXPARTITIONS)) { + err = EPART; + goto fail; + } + cp++; + } +#ifdef LOADER_GPT_SUPPORT + } +#endif + } else { + cp = np; + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + idev->d_slice = slice; + idev->d_partition = partition; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + case DEVT_CD: + case DEVT_NET: + case DEVT_ZFS: + unit = 0; + + if (*np && (*np != ':')) { + unit = strtol(np, &cp, 0); /* get unit number if present */ + if (cp == np) { + err = EUNIT; + goto fail; + } + } else { + cp = np; + } + if (*cp && (*cp != ':')) { + err = EINVAL; + goto fail; + } + + idev->d_unit = unit; + if (path != NULL) + *path = (*cp == 0) ? cp : cp + 1; + break; + + default: + err = EINVAL; + goto fail; + } + idev->d_dev = dv; + idev->d_type = dv->dv_type; + if (dev == NULL) { + free(idev); + } else { + *dev = idev; + } + return(0); + + fail: + free(idev); + return(err); +} + + +char * +userboot_fmtdev(void *vdev) +{ + struct disk_devdesc *dev = (struct disk_devdesc *)vdev; + static char buf[128]; /* XXX device length constant? */ + char *cp; + + switch(dev->d_type) { + case DEVT_NONE: + strcpy(buf, "(no device)"); + break; + + case DEVT_CD: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + + case DEVT_DISK: + cp = buf; + cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit); +#ifdef LOADER_GPT_SUPPORT + if (dev->d_partition == 0xff) { + cp += sprintf(cp, "p%d", dev->d_slice); + } else { +#endif + if (dev->d_slice > 0) + cp += sprintf(cp, "s%d", dev->d_slice); + if (dev->d_partition >= 0) + cp += sprintf(cp, "%c", dev->d_partition + 'a'); +#ifdef LOADER_GPT_SUPPORT + } +#endif + strcat(cp, ":"); + break; + + case DEVT_NET: + case DEVT_ZFS: + sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); + break; + } + return(buf); +} + + +/* + * Set currdev to suit the value being supplied in (value) + */ +int +userboot_setcurrdev(struct env_var *ev, int flags, const void *value) +{ + struct disk_devdesc *ncurr; + int rv; + + if ((rv = userboot_parsedev(&ncurr, value, NULL)) != 0) + return(rv); + free(ncurr); + env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); + return(0); +} diff --git a/sys/boot/userboot/userboot/elf32_freebsd.c b/sys/boot/userboot/userboot/elf32_freebsd.c new file mode 100644 index 0000000..8489385 --- /dev/null +++ b/sys/boot/userboot/userboot/elf32_freebsd.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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/exec.h> +#include <sys/linker.h> +#include <string.h> +#include <i386/include/bootinfo.h> +#include <i386/include/elf.h> +#include <stand.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +static int elf32_exec(struct preloaded_file *amp); +static int elf32_obj_exec(struct preloaded_file *amp); + +struct file_format i386_elf = { elf32_loadfile, elf32_exec }; +struct file_format i386_elf_obj = { elf32_obj_loadfile, elf32_obj_exec }; + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf32_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t entry, bootinfop, modulep, kernend; + int boothowto, err, bootdev; + uint32_t stack[1024]; + + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); + if (err != 0) + return(err); + entry = ehdr->e_entry & 0xffffff; + +#ifdef DEBUG + printf("Start @ 0x%lx ...\n", entry); +#endif + + dev_cleanup(); + + /* + * Build a scratch stack at physical 0x1000 + */ + stack[0] = boothowto; + stack[1] = bootdev; + stack[2] = 0; + stack[3] = 0; + stack[4] = 0; + stack[5] = bootinfop; + stack[6] = modulep; + stack[7] = kernend; + CALLBACK(copyin, stack, 0x1000, sizeof(stack)); + CALLBACK(setreg, 4, 0x1000); + CALLBACK(exec, entry); + + panic("exec returned"); +} + +static int +elf32_obj_exec(struct preloaded_file *fp) +{ + return (EFTYPE); +} diff --git a/sys/boot/userboot/userboot/elf64_freebsd.c b/sys/boot/userboot/userboot/elf64_freebsd.c new file mode 100644 index 0000000..36129ef --- /dev/null +++ b/sys/boot/userboot/userboot/elf64_freebsd.c @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * 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$"); + +#define __ELF_WORD_SIZE 64 +#include <sys/param.h> +#include <sys/exec.h> +#include <sys/linker.h> +#include <string.h> +#include <i386/include/bootinfo.h> +#include <machine/elf.h> +#include <stand.h> + +#include "bootstrap.h" +#include "libuserboot.h" + +static int elf64_exec(struct preloaded_file *amp); +static int elf64_obj_exec(struct preloaded_file *amp); + +struct file_format amd64_elf = { elf64_loadfile, elf64_exec }; +struct file_format amd64_elf_obj = { elf64_obj_loadfile, elf64_obj_exec }; + +#define MSR_EFER 0xc0000080 +#define EFER_LME 0x00000100 +#define EFER_LMA 0x00000400 /* Long mode active (R) */ +#define CR4_PAE 0x00000020 +#define CR4_VMXE (1UL << 13) +#define CR4_PSE 0x00000010 +#define CR0_PG 0x80000000 +#define CR0_PE 0x00000001 /* Protected mode Enable */ +#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */ + +#define PG_V 0x001 +#define PG_RW 0x002 +#define PG_U 0x004 +#define PG_PS 0x080 + +typedef u_int64_t p4_entry_t; +typedef u_int64_t p3_entry_t; +typedef u_int64_t p2_entry_t; + +#define GUEST_NULL_SEL 0 +#define GUEST_CODE_SEL 1 +#define GUEST_DATA_SEL 2 +#define GUEST_GDTR_LIMIT (3 * 8 - 1) + +static void +setup_freebsd_gdt(uint64_t *gdtr) +{ + gdtr[GUEST_NULL_SEL] = 0; + gdtr[GUEST_CODE_SEL] = 0x0020980000000000; + gdtr[GUEST_DATA_SEL] = 0x0000900000000000; +} + +/* + * There is an ELF kernel and one or more ELF modules loaded. + * We wish to start executing the kernel image, so make such + * preparations as are required, and do so. + */ +static int +elf64_exec(struct preloaded_file *fp) +{ + struct file_metadata *md; + Elf_Ehdr *ehdr; + vm_offset_t modulep, kernend; + int err; + int i; + uint32_t stack[1024]; + p4_entry_t PT4[512]; + p3_entry_t PT3[512]; + p2_entry_t PT2[512]; + uint64_t gdtr[3]; + + if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL) + return(EFTYPE); + ehdr = (Elf_Ehdr *)&(md->md_data); + + err = bi_load64(fp->f_args, &modulep, &kernend); + if (err != 0) + return(err); + + bzero(PT4, PAGE_SIZE); + bzero(PT3, PAGE_SIZE); + bzero(PT2, PAGE_SIZE); + + /* + * Build a scratch stack at physical 0x1000, page tables: + * PT4 at 0x2000, + * PT3 at 0x3000, + * PT2 at 0x4000, + * gdtr at 0x5000, + */ + + /* + * This is kinda brutal, but every single 1GB VM memory segment + * points to the same first 1GB of physical memory. But it is + * more than adequate. + */ + for (i = 0; i < 512; i++) { + /* Each slot of the level 4 pages points to the same level 3 page */ + PT4[i] = (p4_entry_t) 0x3000; + PT4[i] |= PG_V | PG_RW | PG_U; + + /* Each slot of the level 3 pages points to the same level 2 page */ + PT3[i] = (p3_entry_t) 0x4000; + PT3[i] |= PG_V | PG_RW | PG_U; + + /* The level 2 page slots are mapped with 2MB pages for 1GB. */ + PT2[i] = i * (2 * 1024 * 1024); + PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; + } + +#ifdef DEBUG + printf("Start @ %#llx ...\n", ehdr->e_entry); +#endif + + dev_cleanup(); + + stack[0] = 0; /* return address */; + stack[1] = modulep; + stack[2] = kernend; + CALLBACK(copyin, stack, 0x1000, sizeof(stack)); + CALLBACK(copyin, PT4, 0x2000, sizeof(PT4)); + CALLBACK(copyin, PT3, 0x3000, sizeof(PT3)); + CALLBACK(copyin, PT2, 0x4000, sizeof(PT2)); + CALLBACK(setreg, 4, 0x1000); + + CALLBACK(setmsr, MSR_EFER, EFER_LMA | EFER_LME); + CALLBACK(setcr, 4, CR4_PAE | CR4_VMXE); + CALLBACK(setcr, 3, 0x2000); + CALLBACK(setcr, 0, CR0_PG | CR0_PE | CR0_NE); + + setup_freebsd_gdt(gdtr); + CALLBACK(copyin, gdtr, 0x5000, sizeof(gdtr)); + CALLBACK(setgdt, 0x5000, sizeof(gdtr)); + + CALLBACK(exec, ehdr->e_entry); + + panic("exec returned"); +} + +static int +elf64_obj_exec(struct preloaded_file *fp) +{ + + return (EFTYPE); +} diff --git a/sys/boot/userboot/userboot/host.c b/sys/boot/userboot/userboot/host.c new file mode 100644 index 0000000..81858a9 --- /dev/null +++ b/sys/boot/userboot/userboot/host.c @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 2011 Google, 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 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$"); + +/* + * Read from the host filesystem + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <stddef.h> +#include <stdarg.h> +#include <string.h> +#include <stand.h> +#include <bootstrap.h> + +#include "libuserboot.h" + +/* + * Open a file. + */ +static int +host_open(const char *upath, struct open_file *f) +{ + + if (f->f_dev != &host_dev) + return (EINVAL); + + return (CALLBACK(open, upath, &f->f_fsdata)); +} + +static int +host_close(struct open_file *f) +{ + + CALLBACK(close, f->f_fsdata); + f->f_fsdata = (void *)0; + + return (0); +} + +/* + * Copy a portion of a file into memory. + */ +static int +host_read(struct open_file *f, void *start, size_t size, size_t *resid) +{ + + return (CALLBACK(read, f->f_fsdata, start, size, resid)); +} + +/* + * Don't be silly - the bootstrap has no business writing anything. + */ +static int +host_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + + return (EROFS); +} + +static off_t +host_seek(struct open_file *f, off_t offset, int where) +{ + + return (CALLBACK(seek, f->f_fsdata, offset, where)); +} + +static int +host_stat(struct open_file *f, struct stat *sb) +{ + int mode; + int uid; + int gid; + uint64_t size; + + CALLBACK(stat, f->f_fsdata, &mode, &uid, &gid, &size); + sb->st_mode = mode; + sb->st_uid = uid; + sb->st_gid = gid; + sb->st_size = size; + return (0); +} + +static int +host_readdir(struct open_file *f, struct dirent *d) +{ + uint32_t fileno; + uint8_t type; + size_t namelen; + int rc; + + rc = CALLBACK(readdir, f->f_fsdata, &fileno, &type, &namelen, + d->d_name); + if (rc) + return (rc); + + d->d_fileno = fileno; + d->d_type = type; + d->d_namlen = namelen; + + return (0); +} + +static int +host_dev_init(void) +{ + + return (0); +} + +static void +host_dev_print(int verbose) +{ + char line[80]; + + sprintf(line, " host%d: Host filesystem\n", 0); + pager_output(line); +} + +/* + * 'Open' the host device. + */ +static int +host_dev_open(struct open_file *f, ...) +{ + va_list args; + struct devdesc *dev; + + va_start(args, f); + dev = va_arg(args, struct devdesc*); + va_end(args); + + return (0); +} + +static int +host_dev_close(struct open_file *f) +{ + + return (0); +} + +static int +host_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + + return (ENOSYS); +} + +struct fs_ops host_fsops = { + "host", + host_open, + host_close, + host_read, + host_write, + host_seek, + host_stat, + host_readdir +}; + +struct devsw host_dev = { + .dv_name = "host", + .dv_type = DEVT_NET, + .dv_init = host_dev_init, + .dv_strategy = host_dev_strategy, + .dv_open = host_dev_open, + .dv_close = host_dev_close, + .dv_ioctl = noioctl, + .dv_print = host_dev_print, + .dv_cleanup = NULL +}; diff --git a/sys/boot/userboot/userboot/libuserboot.h b/sys/boot/userboot/userboot/libuserboot.h new file mode 100644 index 0000000..0aa1a3f --- /dev/null +++ b/sys/boot/userboot/userboot/libuserboot.h @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2011 Google, 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 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. + * + * $FreeBSD$ + */ + +#include "userboot.h" + +extern struct loader_callbacks_v1 *callbacks; +extern void *callbacks_arg; + +#define CALLBACK(fn, args...) (callbacks->fn(callbacks_arg , ##args)) + +#define MAXDEV 31 /* maximum number of distinct devices */ + +typedef unsigned long physaddr_t; + +/* exported devices */ +extern struct devsw userboot_disk; +extern int userboot_disk_maxunit; +extern struct devsw host_dev; + +/* access to host filesystem */ +struct fs_ops host_fsops; + +struct bootinfo; +struct preloaded_file; +extern int bi_load(struct bootinfo *, struct preloaded_file *); + +extern void delay(int); + +extern int userboot_autoload(void); +extern ssize_t userboot_copyin(const void *, vm_offset_t, size_t); +extern ssize_t userboot_copyout(vm_offset_t, void *, size_t); +extern ssize_t userboot_readin(int, vm_offset_t, size_t); +extern int userboot_getdev(void **, const char *, const char **); +char *userboot_fmtdev(void *vdev); +int userboot_setcurrdev(struct env_var *ev, int flags, const void *value); + +int bi_getboothowto(char *kargs); +void bi_setboothowto(int howto); +vm_offset_t bi_copyenv(vm_offset_t addr); +int bi_load32(char *args, int *howtop, int *bootdevp, vm_offset_t *bip, + vm_offset_t *modulep, vm_offset_t *kernend); +int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend); diff --git a/sys/boot/userboot/userboot/main.c b/sys/boot/userboot/userboot/main.c new file mode 100644 index 0000000..d01d95e --- /dev/null +++ b/sys/boot/userboot/userboot/main.c @@ -0,0 +1,177 @@ +/*- + * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> + * Copyright (c) 1998,2000 Doug Rabson <dfr@freebsd.org> + * 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 <stand.h> +#include <string.h> +#include <setjmp.h> + +#include "bootstrap.h" +#include "disk.h" +#include "libuserboot.h" + +struct loader_callbacks_v1 *callbacks; +void *callbacks_arg; + +extern char bootprog_name[]; +extern char bootprog_rev[]; +extern char bootprog_date[]; +extern char bootprog_maker[]; +static jmp_buf jb; + +struct arch_switch archsw; /* MI/MD interface boundary */ + +static void extract_currdev(void); + +void +delay(int usec) +{ + + CALLBACK(delay, usec); +} + +void +exit(int v) +{ + + CALLBACK(exit, v); + longjmp(jb, 1); +} + +void +loader_main(struct loader_callbacks_v1 *cb, void *arg, int version, int ndisks) +{ + static char malloc[512*1024]; + int i; + + if (version != USERBOOT_VERSION_1) + abort(); + + callbacks = cb; + callbacks_arg = arg; + userboot_disk_maxunit = ndisks; + + /* + * initialise the heap as early as possible. Once this is done, + * alloc() is usable. The stack is buried inside us, so this is + * safe. + */ + setheap((void *)malloc, (void *)(malloc + 512*1024)); + + /* + * Hook up the console + */ + cons_probe(); + + /* + * March through the device switch probing for things. + */ + for (i = 0; devsw[i] != NULL; i++) + if (devsw[i]->dv_init != NULL) + (devsw[i]->dv_init)(); + + printf("\n"); + printf("%s, Revision %s\n", bootprog_name, bootprog_rev); + printf("(%s, %s)\n", bootprog_maker, bootprog_date); +#if 0 + printf("Memory: %ld k\n", memsize() / 1024); +#endif + + setenv("LINES", "24", 1); /* optional */ + + archsw.arch_autoload = userboot_autoload; + archsw.arch_getdev = userboot_getdev; + archsw.arch_copyin = userboot_copyin; + archsw.arch_copyout = userboot_copyout; + archsw.arch_readin = userboot_readin; + + extract_currdev(); + + if (setjmp(jb)) + return; + + interact(); /* doesn't return */ + + exit(0); +} + +/* + * Set the 'current device' by (if possible) recovering the boot device as + * supplied by the initial bootstrap. + */ +static void +extract_currdev(void) +{ + struct disk_devdesc dev; + + //bzero(&dev, sizeof(dev)); + + if (userboot_disk_maxunit > 0) { + dev.d_dev = &userboot_disk; + dev.d_type = dev.d_dev->dv_type; + dev.d_unit = 0; + dev.d_slice = 0; + dev.d_partition = 0; + /* + * Figure out if we are using MBR or GPT - for GPT we + * set the partition to 0 since everything is a GPT slice. + */ + if (dev.d_dev->dv_open(NULL, &dev)) + dev.d_partition = 255; + } else { + dev.d_dev = &host_dev; + dev.d_type = dev.d_dev->dv_type; + dev.d_unit = 0; + } + + env_setenv("currdev", EV_VOLATILE, userboot_fmtdev(&dev), + userboot_setcurrdev, env_nounset); + env_setenv("loaddev", EV_VOLATILE, userboot_fmtdev(&dev), + env_noset, env_nounset); +} + +COMMAND_SET(quit, "quit", "exit the loader", command_quit); + +static int +command_quit(int argc, char *argv[]) +{ + + exit(USERBOOT_EXIT_QUIT); + return (CMD_OK); +} + +COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot); + +static int +command_reboot(int argc, char *argv[]) +{ + + exit(USERBOOT_EXIT_REBOOT); + return (CMD_OK); +} diff --git a/sys/boot/userboot/userboot/userboot_cons.c b/sys/boot/userboot/userboot/userboot_cons.c new file mode 100644 index 0000000..5ecb7c8 --- /dev/null +++ b/sys/boot/userboot/userboot/userboot_cons.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2011 Google, 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 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 <stand.h> +#include "bootstrap.h" +#include "libuserboot.h" + +int console; + +static void userboot_cons_probe(struct console *cp); +static int userboot_cons_init(int); +static void userboot_cons_putchar(int); +static int userboot_cons_getchar(void); +static int userboot_cons_poll(void); + +struct console userboot_console = { + "userboot", + "userboot", + 0, + userboot_cons_probe, + userboot_cons_init, + userboot_cons_putchar, + userboot_cons_getchar, + userboot_cons_poll, +}; + +static void +userboot_cons_probe(struct console *cp) +{ + + cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); +} + +static int +userboot_cons_init(int arg) +{ + + return (0); +} + +static void +userboot_cons_putchar(int c) +{ + + CALLBACK(putc, c); +} + +static int +userboot_cons_getchar() +{ + + return (CALLBACK(getc)); +} + +static int +userboot_cons_poll() +{ + + return (CALLBACK(poll)); +} diff --git a/sys/boot/userboot/userboot/userboot_disk.c b/sys/boot/userboot/userboot/userboot_disk.c new file mode 100644 index 0000000..074d3e1 --- /dev/null +++ b/sys/boot/userboot/userboot/userboot_disk.c @@ -0,0 +1,146 @@ +/*- + * Copyright (c) 2011 Google, 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 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$"); + +/* + * Userboot disk image handling. + */ + +#include <stand.h> + +#include <stdarg.h> +#include <uuid.h> + +#include <bootstrap.h> + +#include "disk.h" +#include "libuserboot.h" + +int userboot_disk_maxunit = 0; + +static int userdisk_init(void); +static int userdisk_strategy(void *devdata, int flag, daddr_t dblk, + size_t size, char *buf, size_t *rsize); +static int userdisk_open(struct open_file *f, ...); +static int userdisk_close(struct open_file *f); +static void userdisk_print(int verbose); + +struct devsw userboot_disk = { + "disk", + DEVT_DISK, + userdisk_init, + userdisk_strategy, + userdisk_open, + userdisk_close, + noioctl, + userdisk_print, + NULL +}; + +/* + * Nothing to do here. + */ +static int +userdisk_init(void) +{ + + return(0); +} + +/* + * Print information about disks + */ +static void +userdisk_print(int verbose) +{ + int i; + char line[80]; + struct disk_devdesc dev; + + for (i = 0; i < userboot_disk_maxunit; i++) { + sprintf(line, " disk%d: Guest drive image\n", i); + pager_output(line); + dev.d_dev = &userboot_disk; + dev.d_unit = i; + dev.d_slice = -1; + dev.d_partition = -1; + dev.d_offset = 0; + sprintf(line, " disk%d", i); + disk_print(&dev, line, verbose); + } +} + +/* + * Attempt to open the disk described by (dev) for use by (f). + */ +static int +userdisk_open(struct open_file *f, ...) +{ + va_list ap; + struct disk_devdesc *dev; + + va_start(ap, f); + dev = va_arg(ap, struct disk_devdesc *); + va_end(ap); + + if (dev->d_unit < 0 || dev->d_unit >= userboot_disk_maxunit) + return (EIO); + + return (disk_open(dev)); +} + +static int +userdisk_close(struct open_file *f) +{ + + return(0); +} + +static int +userdisk_strategy(void *devdata, int rw, daddr_t dblk, size_t size, + char *buf, size_t *rsize) +{ + struct disk_devdesc *dev = devdata; + uint64_t off; + size_t resid; + int rc; + + if (rw == F_WRITE) + return (EROFS); + if (rw != F_READ) + return (EINVAL); + if (rsize) + *rsize = 0; + off = (dblk + dev->d_offset) * DISK_SECSIZE; + rc = CALLBACK(diskread, dev->d_unit, off, buf, size, &resid); + if (rc) + return (rc); + if (rsize) + *rsize = size - resid; + return (0); +} diff --git a/sys/boot/userboot/userboot/version b/sys/boot/userboot/userboot/version new file mode 100644 index 0000000..ce6e270 --- /dev/null +++ b/sys/boot/userboot/userboot/version @@ -0,0 +1,4 @@ +$FreeBSD$ + +1.1: Initial userland boot + diff --git a/sys/cam/ata/ata_xpt.c b/sys/cam/ata/ata_xpt.c index d02b36f..84ab46b 100644 --- a/sys/cam/ata/ata_xpt.c +++ b/sys/cam/ata/ata_xpt.c @@ -1601,6 +1601,34 @@ ata_device_transport(struct cam_path *path) } static void +ata_dev_advinfo(union ccb *start_ccb) +{ + struct cam_ed *device; + struct ccb_dev_advinfo *cdai; + off_t amt; + + start_ccb->ccb_h.status = CAM_REQ_INVALID; + device = start_ccb->ccb_h.path->device; + cdai = &start_ccb->cdai; + switch(cdai->buftype) { + case CDAI_TYPE_SERIAL_NUM: + if (cdai->flags & CDAI_FLAG_STORE) + break; + start_ccb->ccb_h.status = CAM_REQ_CMP; + cdai->provsiz = device->serial_num_len; + if (device->serial_num_len == 0) + break; + amt = device->serial_num_len; + if (cdai->provsiz > cdai->bufsiz) + amt = cdai->bufsiz; + memcpy(cdai->buf, device->serial_num, amt); + break; + default: + break; + } +} + +static void ata_action(union ccb *start_ccb) { @@ -1650,7 +1678,13 @@ ata_action(union ccb *start_ccb) xpt_done(start_ccb); break; } - /* FALLTHROUGH */ + xpt_action_default(start_ccb); + break; + } + case XPT_DEV_ADVINFO: + { + ata_dev_advinfo(start_ccb); + break; } default: xpt_action_default(start_ccb); diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index f234076..013c415 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -4894,8 +4894,8 @@ camisr_runqueue(void *V_queue) && (--dev->tag_delay_count == 0)) xpt_start_tags(ccb_h->path); if (!device_is_send_queued(dev)) { - runq = xpt_schedule_dev_sendq(ccb_h->path->bus, - dev); + (void)xpt_schedule_dev_sendq(ccb_h->path->bus, + dev); } } diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c index c1951ff..91384b7 100644 --- a/sys/cam/scsi/scsi_cd.c +++ b/sys/cam/scsi/scsi_cd.c @@ -687,6 +687,10 @@ cdregister(struct cam_periph *periph, void *arg) else softc->minimum_command_size = 6; + /* + * Refcount and block open attempts until we are setup + * Can't block + */ (void)cam_periph_hold(periph, PRIBIO); cam_periph_unlock(periph); /* @@ -747,7 +751,6 @@ cdregister(struct cam_periph *periph, void *arg) softc->disk->d_hba_subdevice = cpi.hba_subdevice; disk_create(softc->disk, DISK_VERSION); cam_periph_lock(periph); - cam_periph_unhold(periph); /* * Add an async callback so that we get @@ -972,12 +975,6 @@ cdregister(struct cam_periph *periph, void *arg) cdregisterexit: - /* - * Refcount and block open attempts until we are setup - * Can't block - */ - (void)cam_periph_hold(periph, PRIBIO); - if ((softc->flags & CD_FLAG_CHANGER) == 0) xpt_schedule(periph, CAM_PRIORITY_DEV); else diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c index 1b507ca..c1f713b 100644 --- a/sys/cam/scsi/scsi_xpt.c +++ b/sys/cam/scsi/scsi_xpt.c @@ -2440,12 +2440,13 @@ scsi_dev_advinfo(union ccb *start_ccb) struct ccb_dev_advinfo *cdai; off_t amt; + start_ccb->ccb_h.status = CAM_REQ_INVALID; device = start_ccb->ccb_h.path->device; cdai = &start_ccb->cdai; switch(cdai->buftype) { case CDAI_TYPE_SCSI_DEVID: if (cdai->flags & CDAI_FLAG_STORE) - break; + return; cdai->provsiz = device->device_id_len; if (device->device_id_len == 0) break; @@ -2456,7 +2457,7 @@ scsi_dev_advinfo(union ccb *start_ccb) break; case CDAI_TYPE_SERIAL_NUM: if (cdai->flags & CDAI_FLAG_STORE) - break; + return; cdai->provsiz = device->serial_num_len; if (device->serial_num_len == 0) break; @@ -2490,7 +2491,7 @@ scsi_dev_advinfo(union ccb *start_ccb) } break; default: - break; + return; } start_ccb->ccb_h.status = CAM_REQ_CMP; diff --git a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c index 434b482..4fa75195 100644 --- a/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c +++ b/sys/cddl/contrib/opensolaris/common/zfs/zfs_prop.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -311,6 +312,9 @@ zfs_prop_init(void) zprop_register_number(ZFS_PROP_COMPRESSRATIO, "compressratio", 0, PROP_READONLY, ZFS_TYPE_DATASET, "<1.00x or higher if compressed>", "RATIO"); + zprop_register_number(ZFS_PROP_REFRATIO, "refcompressratio", 0, + PROP_READONLY, ZFS_TYPE_DATASET, + "<1.00x or higher if compressed>", "REFRATIO"); zprop_register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize", ZVOL_DEFAULT_BLOCKSIZE, PROP_ONETIME, ZFS_TYPE_VOLUME, "512 to 128k, power of 2", "VOLBLOCK"); diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c index 7170aba..498352e 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dsl_dataset.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ #include <sys/dmu_objset.h> @@ -2150,7 +2151,7 @@ dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) void dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) { - uint64_t refd, avail, uobjs, aobjs; + uint64_t refd, avail, uobjs, aobjs, ratio; dsl_dir_stats(ds->ds_dir, nv); @@ -2177,6 +2178,11 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, DS_IS_DEFER_DESTROY(ds) ? 1 : 0); + ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : + (ds->ds_phys->ds_uncompressed_bytes * 100 / + ds->ds_phys->ds_compressed_bytes); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); + if (ds->ds_phys->ds_next_snap_obj) { /* * This is a snapshot; override the dd's space used with @@ -2184,10 +2190,7 @@ dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) */ dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, ds->ds_phys->ds_unique_bytes); - dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, - ds->ds_phys->ds_compressed_bytes == 0 ? 100 : - (ds->ds_phys->ds_uncompressed_bytes * 100 / - ds->ds_phys->ds_compressed_bytes)); + dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); } } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c index 7978d61..ef9d4b5 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_cache.c @@ -71,9 +71,16 @@ * 1<<zfs_vdev_cache_bshift byte reads by the vdev_cache (aka software * track buffer). At most zfs_vdev_cache_size bytes will be kept in each * vdev's vdev_cache. + * + * TODO: Note that with the current ZFS code, it turns out that the + * vdev cache is not helpful, and in some cases actually harmful. It + * is better if we disable this. Once some time has passed, we should + * actually remove this to simplify the code. For now we just disable + * it by setting the zfs_vdev_cache_size to zero. Note that Solaris 11 + * has made these same changes. */ int zfs_vdev_cache_max = 1<<14; /* 16KB */ -int zfs_vdev_cache_size = 10ULL << 20; /* 10MB */ +int zfs_vdev_cache_size = 0; int zfs_vdev_cache_bshift = 16; #define VCBS (1 << zfs_vdev_cache_bshift) /* 64KB */ diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h index edc26cd..e4070c2 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011 by Delphix. All rights reserved. */ /* Portions Copyright 2010 Robert Milkowski */ @@ -124,6 +125,7 @@ typedef enum { ZFS_PROP_DEDUP, ZFS_PROP_MLSLABEL, ZFS_PROP_SYNC, + ZFS_PROP_REFRATIO, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/sys/conf/NOTES b/sys/conf/NOTES index b84d0c5..835c30b 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -1162,7 +1162,7 @@ options MAC_STUB options MAC_TEST # Support for Capsicum -options CAPABILITIES +options CAPABILITY_MODE ##################################################################### diff --git a/sys/conf/files b/sys/conf/files index a62e1a6..853c0c8 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -386,14 +386,14 @@ contrib/pf/net/pf_if.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/net/pf_ioctl.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" +contrib/pf/net/pf_lb.c optional pf inet \ + compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/net/pf_norm.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/net/pf_osfp.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/net/pf_ruleset.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" -contrib/pf/net/pf_subr.c optional pf inet \ - compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/net/pf_table.c optional pf inet \ compile-with "${NORMAL_C} -I$S/contrib/pf" contrib/pf/netinet/in4_cksum.c optional pf inet @@ -1552,6 +1552,7 @@ dev/pci/isa_pci.c optional pci isa dev/pci/pci.c optional pci dev/pci/pci_if.m standard dev/pci/pci_pci.c optional pci +dev/pci/pci_subr.c optional pci dev/pci/pci_user.c optional pci dev/pci/pcib_if.m standard dev/pci/vga_pci.c optional pci @@ -1991,8 +1992,12 @@ dev/usb/quirk/usb_quirk.c optional usb # # USB templates # -dev/usb/template/usb_template.c optional usb_template +dev/usb/template/usb_template.c optional usb_template +dev/usb/template/usb_template_audio.c optional usb_template dev/usb/template/usb_template_cdce.c optional usb_template +dev/usb/template/usb_template_kbd.c optional usb_template +dev/usb/template/usb_template_modem.c optional usb_template +dev/usb/template/usb_template_mouse.c optional usb_template dev/usb/template/usb_template_msc.c optional usb_template dev/usb/template/usb_template_mtp.c optional usb_template # diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 index 4fe5e15..401705a 100644 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -128,7 +128,6 @@ amd64/amd64/trap.c standard amd64/amd64/uio_machdep.c standard amd64/amd64/uma_machdep.c standard amd64/amd64/vm_machdep.c standard -amd64/pci/pci_bus.c optional pci amd64/pci/pci_cfgreg.c optional pci crypto/aesni/aesencdec_amd64.S optional aesni crypto/aesni/aeskeys_amd64.S optional aesni @@ -320,7 +319,8 @@ x86/isa/isa.c standard x86/isa/isa_dma.c standard x86/isa/nmi.c standard x86/isa/orm.c optional isa -x86/pci/qpi.c standard +x86/pci/pci_bus.c optional pci +x86/pci/qpi.c optional pci x86/x86/busdma_machdep.c standard x86/x86/dump_machdep.c standard x86/x86/io_apic.c standard diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 4f0d0d0..41a1772 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -352,7 +352,6 @@ i386/linux/linux_support.s optional compat_linux \ dependency "linux_assym.h" i386/linux/linux_sysent.c optional compat_linux i386/linux/linux_sysvec.c optional compat_linux -i386/pci/pci_bus.c optional pci i386/pci/pci_cfgreg.c optional pci i386/pci/pci_pir.c optional pci i386/svr4/svr4_locore.s optional compat_svr4 \ @@ -405,7 +404,8 @@ x86/isa/isa.c optional isa x86/isa/isa_dma.c optional isa x86/isa/nmi.c standard x86/isa/orm.c optional isa -x86/pci/qpi.c standard +x86/pci/pci_bus.c optional pci +x86/pci/qpi.c optional pci x86/x86/busdma_machdep.c standard x86/x86/dump_machdep.c standard x86/x86/io_apic.c optional apic diff --git a/sys/conf/files.ia64 b/sys/conf/files.ia64 index 15ef939..e341230 100644 --- a/sys/conf/files.ia64 +++ b/sys/conf/files.ia64 @@ -120,6 +120,7 @@ ia64/pci/pci_cfgreg.c optional pci isa/syscons_isa.c optional sc isa/vga_isa.c optional vga kern/imgact_elf32.c optional compat_freebsd32 +kern/kern_clocksource.c standard libkern/bcmp.c standard libkern/ffsl.c standard libkern/fls.c standard diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 5db5421..e034601 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -199,7 +199,6 @@ i386/linux/linux_support.s optional compat_linux \ dependency "linux_assym.h" i386/linux/linux_sysent.c optional compat_linux i386/linux/linux_sysvec.c optional compat_linux -i386/pci/pci_bus.c optional pci i386/pci/pci_cfgreg.c optional pci i386/pci/pci_pir.c optional pci i386/svr4/svr4_locore.s optional compat_svr4 \ @@ -249,6 +248,7 @@ pc98/pc98/pc98_machdep.c standard x86/isa/atpic.c optional atpic x86/isa/clock.c standard x86/isa/isa.c optional isa +x86/pci/pci_bus.c optional pci x86/x86/busdma_machdep.c standard x86/x86/dump_machdep.c standard x86/x86/io_apic.c optional apic diff --git a/sys/conf/options b/sys/conf/options index ee696a8..35c0dfc 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -63,7 +63,7 @@ SYSCTL_DEBUG opt_sysctl.h ADAPTIVE_LOCKMGRS ALQ AUDIT opt_global.h -CAPABILITIES opt_capabilities.h +CAPABILITY_MODE opt_capsicum.h CODA_COMPAT_5 opt_coda.h COMPAT_43 opt_compat.h COMPAT_43TTY opt_compat.h @@ -773,7 +773,8 @@ ATH_TXBUF opt_ath.h ATH_RXBUF opt_ath.h ATH_DIAGAPI opt_ath.h ATH_TX99_DIAG opt_ath.h -ATH_ENABLE_11N opt_ah.h +ATH_ENABLE_11N opt_ath.h +ATH_ENABLE_DFS opt_ath.h # options for the Atheros hal AH_SUPPORT_AR5416 opt_ah.h diff --git a/sys/contrib/altq/altq/altq_red.c b/sys/contrib/altq/altq/altq_red.c index cd216bd..b461ce0 100644 --- a/sys/contrib/altq/altq/altq_red.c +++ b/sys/contrib/altq/altq/altq_red.c @@ -514,11 +514,9 @@ mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags) struct mbuf *m0; struct pf_mtag *at; void *hdr; - int af; at = pf_find_mtag(m); if (at != NULL) { - af = at->af; hdr = at->hdr; #ifdef ALTQ3_COMPAT } else if (pktattr != NULL) { @@ -528,9 +526,6 @@ mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags) } else return (0); - if (af != AF_INET && af != AF_INET6) - return (0); - /* verify that pattr_hdr is within the mbuf data */ for (m0 = m; m0 != NULL; m0 = m0->m_next) if (((caddr_t)hdr >= m0->m_data) && @@ -541,8 +536,8 @@ mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags) return (0); } - switch (af) { - case AF_INET: + switch (((struct ip *)hdr)->ip_v) { + case IPVERSION: if (flags & REDF_ECN4) { struct ip *ip = hdr; u_int8_t otos; @@ -575,7 +570,7 @@ mark_ecn(struct mbuf *m, struct altq_pktattr *pktattr, int flags) } break; #ifdef INET6 - case AF_INET6: + case (IPV6_VERSION >> 4): if (flags & REDF_ECN6) { struct ip6_hdr *ip6 = hdr; u_int32_t flowlabel; diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c index d16a09b..0893e8d 100644 --- a/sys/contrib/pf/net/if_pflog.c +++ b/sys/contrib/pf/net/if_pflog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */ +/* $OpenBSD: if_pflog.c,v 1.26 2007/10/18 21:58:18 mpf Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), * Angelos D. Keromytis (kermit@csd.uch.gr) and @@ -99,11 +99,11 @@ __FBSDID("$FreeBSD$"); #include <net/pfvar.h> #include <net/if_pflog.h> -#ifdef INET #ifdef __FreeBSD__ +#ifdef INET #include <machine/in_cksum.h> -#endif -#endif +#endif /* INET */ +#endif /* __FreeBSD__ */ #define PFLOGMTU (32768 + MHLEN + MLEN) @@ -115,7 +115,11 @@ __FBSDID("$FreeBSD$"); void pflogattach(int); int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, - struct route *); +#ifdef __FreeBSD__ + struct route *); +#else + struct rtentry *); +#endif int pflogioctl(struct ifnet *, u_long, caddr_t); void pflogstart(struct ifnet *); #ifdef __FreeBSD__ @@ -128,7 +132,7 @@ int pflog_clone_destroy(struct ifnet *); LIST_HEAD(, pflog_softc) pflogif_list; #ifdef __FreeBSD__ -IFC_SIMPLE_DECLARE(pflog, 1); +IFC_SIMPLE_DECLARE(pflog, 1); #else struct if_clone pflog_cloner = IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); @@ -136,10 +140,6 @@ struct if_clone pflog_cloner = struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ -#ifndef __FreeBSD__ -extern int ifqmaxlen; -#endif - void pflogattach(int npflog) { @@ -147,9 +147,6 @@ pflogattach(int npflog) LIST_INIT(&pflogif_list); for (i = 0; i < PFLOGIFS_MAX; i++) pflogifs[i] = NULL; -#ifndef __FreeBSD__ - (void) pflog_clone_create(&pflog_cloner, 0); -#endif if_clone_attach(&pflog_cloner); } @@ -168,9 +165,9 @@ pflog_clone_create(struct if_clone *ifc, int unit) if (unit >= PFLOGIFS_MAX) return (EINVAL); - if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL) + if ((pflogif = malloc(sizeof(*pflogif), + M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) return (ENOMEM); - bzero(pflogif, sizeof(*pflogif)); pflogif->sc_unit = unit; #ifdef __FreeBSD__ @@ -209,6 +206,7 @@ pflog_clone_create(struct if_clone *ifc, int unit) s = splnet(); #ifdef __FreeBSD__ + /* XXX: Why pf(4) lock?! Better add a pflog lock?! */ PF_LOCK(); #endif LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); @@ -289,7 +287,11 @@ pflogstart(struct ifnet *ifp) int pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, - struct route *ro) +#ifdef __FreeBSD__ + struct route *rt) +#else + struct rtentry *rt) +#endif { m_freem(m); return (0); @@ -300,9 +302,6 @@ int pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { switch (cmd) { - case SIOCSIFADDR: - case SIOCAIFADDR: - case SIOCSIFDSTADDR: case SIOCSIFFLAGS: #ifdef __FreeBSD__ if (ifp->if_flags & IFF_UP) @@ -317,7 +316,7 @@ pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) #endif break; default: - return (EINVAL); + return (ENOTTY); } return (0); @@ -333,7 +332,7 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, struct pfloghdr hdr; if (kif == NULL || m == NULL || rm == NULL || pd == NULL) - return (-1); + return ( 1); if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) return (0); @@ -347,7 +346,7 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, if (am == NULL) { hdr.rulenr = htonl(rm->nr); - hdr.subrulenr = -1; + hdr.subrulenr = 1; } else { hdr.rulenr = htonl(am->nr); hdr.subrulenr = htonl(rm->nr); @@ -357,11 +356,11 @@ pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, } if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) #ifdef __FreeBSD__ - /* + /* * XXX: This should not happen as we force an early lookup * via debug.pfugidhack */ - ; /* empty */ + ; /* empty */ #else pd->lookup.done = pf_socket_lookup(dir, pd); #endif diff --git a/sys/contrib/pf/net/if_pflog.h b/sys/contrib/pf/net/if_pflog.h index a3c74d1..5f48f6c 100644 --- a/sys/contrib/pf/net/if_pflog.h +++ b/sys/contrib/pf/net/if_pflog.h @@ -1,5 +1,4 @@ -/* $FreeBSD$ */ -/* $OpenBSD: if_pflog.h,v 1.14 2006/10/25 11:27:01 henning Exp $ */ +/* $OpenBSD: if_pflog.h,v 1.13 2006/10/23 12:46:09 henning Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -26,11 +25,10 @@ */ #ifndef _NET_IF_PFLOG_H_ -#define _NET_IF_PFLOG_H_ +#define _NET_IF_PFLOG_H_ #define PFLOGIFS_MAX 16 -#ifdef _KERNEL struct pflog_softc { #ifdef __FreeBSD__ struct ifnet *sc_ifp; /* the interface pointer */ @@ -40,9 +38,8 @@ struct pflog_softc { int sc_unit; LIST_ENTRY(pflog_softc) sc_list; }; -#endif /* _KERNEL */ -#define PFLOG_RULESET_NAME_SIZE 16 +#define PFLOG_RULESET_NAME_SIZE 16 struct pfloghdr { u_int8_t length; @@ -61,9 +58,9 @@ struct pfloghdr { u_int8_t pad[3]; }; -#define PFLOG_HDRLEN sizeof(struct pfloghdr) +#define PFLOG_HDRLEN sizeof(struct pfloghdr) /* minus pad, also used as a signature */ -#define PFLOG_REAL_HDRLEN offsetof(struct pfloghdr, pad) +#define PFLOG_REAL_HDRLEN offsetof(struct pfloghdr, pad) /* XXX remove later when old format logs are no longer needed */ struct old_pfloghdr { @@ -74,23 +71,24 @@ struct old_pfloghdr { u_short action; u_short dir; }; -#define OLD_PFLOG_HDRLEN sizeof(struct old_pfloghdr) +#define OLD_PFLOG_HDRLEN sizeof(struct old_pfloghdr) #ifdef _KERNEL - #ifdef __FreeBSD__ struct pf_rule; struct pf_ruleset; struct pfi_kif; struct pf_pdesc; +#if 0 typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *, struct pf_pdesc *); extern pflog_packet_t *pflog_packet_ptr; -#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) do { \ - if (pflog_packet_ptr != NULL) \ - pflog_packet_ptr(i,a,b,c,d,e,f,g,h); \ +#endif +#define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) do { \ + if (pflog_packet_ptr != NULL) \ + pflog_packet_ptr(i,a,b,c,d,e,f,g,h); \ } while (0) #else /* ! __FreeBSD__ */ #if NPFLOG > 0 @@ -98,6 +96,6 @@ extern pflog_packet_t *pflog_packet_ptr; #else #define PFLOG_PACKET(i,x,a,b,c,d,e,f,g,h) ((void)0) #endif /* NPFLOG > 0 */ -#endif /* __FreeBSD__ */ +#endif #endif /* _KERNEL */ #endif /* _NET_IF_PFLOG_H_ */ diff --git a/sys/contrib/pf/net/if_pflow.h b/sys/contrib/pf/net/if_pflow.h new file mode 100644 index 0000000..35ccbeb --- /dev/null +++ b/sys/contrib/pf/net/if_pflow.h @@ -0,0 +1,126 @@ +/* $OpenBSD: if_pflow.h,v 1.5 2009/02/27 11:09:36 gollo Exp $ */ + +/* + * Copyright (c) 2008 Henning Brauer <henning@openbsd.org> + * Copyright (c) 2008 Joerg Goltermann <jg@osn.de> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _NET_IF_PFLOW_H_ +#define _NET_IF_PFLOW_H_ + +#define PFLOW_ID_LEN sizeof(u_int64_t) + +#define PFLOW_MAXFLOWS 30 +#define PFLOW_VERSION 5 +#define PFLOW_ENGINE_TYPE 42 +#define PFLOW_ENGINE_ID 42 +#define PFLOW_MAXBYTES 0xffffffff +#define PFLOW_TIMEOUT 30 + +struct pflow_flow { + u_int32_t src_ip; + u_int32_t dest_ip; + u_int32_t nexthop_ip; + u_int16_t if_index_in; + u_int16_t if_index_out; + u_int32_t flow_packets; + u_int32_t flow_octets; + u_int32_t flow_start; + u_int32_t flow_finish; + u_int16_t src_port; + u_int16_t dest_port; + u_int8_t pad1; + u_int8_t tcp_flags; + u_int8_t protocol; + u_int8_t tos; + u_int16_t src_as; + u_int16_t dest_as; + u_int8_t src_mask; + u_int8_t dest_mask; + u_int16_t pad2; +} __packed; + +#ifdef _KERNEL + +extern int pflow_ok; + +struct pflow_softc { + struct ifnet sc_if; + struct ifnet *sc_pflow_ifp; + + unsigned int sc_count; + unsigned int sc_maxcount; + u_int64_t sc_gcounter; + struct ip_moptions sc_imo; +#ifdef __FreeBSD__ + struct callout sc_tmo; +#else + struct timeout sc_tmo; +#endif + struct in_addr sc_sender_ip; + u_int16_t sc_sender_port; + struct in_addr sc_receiver_ip; + u_int16_t sc_receiver_port; + struct mbuf *sc_mbuf; /* current cumulative mbuf */ + SLIST_ENTRY(pflow_softc) sc_next; +}; + +extern struct pflow_softc *pflowif; + +#endif /* _KERNEL */ + +struct pflow_header { + u_int16_t version; + u_int16_t count; + u_int32_t uptime_ms; + u_int32_t time_sec; + u_int32_t time_nanosec; + u_int32_t flow_sequence; + u_int8_t engine_type; + u_int8_t engine_id; + u_int8_t reserved1; + u_int8_t reserved2; +} __packed; + +#define PFLOW_HDRLEN sizeof(struct pflow_header) + +struct pflowstats { + u_int64_t pflow_flows; + u_int64_t pflow_packets; + u_int64_t pflow_onomem; + u_int64_t pflow_oerrors; +}; + +/* + * Configuration structure for SIOCSETPFLOW SIOCGETPFLOW + */ +struct pflowreq { + struct in_addr sender_ip; + struct in_addr receiver_ip; + u_int16_t receiver_port; + u_int16_t addrmask; +#define PFLOW_MASK_SRCIP 0x01 +#define PFLOW_MASK_DSTIP 0x02 +#define PFLOW_MASK_DSTPRT 0x04 +}; + +#ifdef _KERNEL +int export_pflow(struct pf_state *); +int pflow_sysctl(int *, u_int, void *, size_t *, void *, size_t); +#endif /* _KERNEL */ + +#endif /* _NET_IF_PFLOW_H_ */ diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c index 9466118..ba8a348 100644 --- a/sys/contrib/pf/net/if_pfsync.c +++ b/sys/contrib/pf/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.73 2006/11/16 13:13:38 henning Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.110 2009/02/24 05:39:19 dlg Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -26,10 +26,25 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #ifdef __FreeBSD__ #include "opt_inet.h" #include "opt_inet6.h" -#include "opt_carp.h" #include "opt_bpf.h" #include "opt_pf.h" @@ -56,7 +71,10 @@ __FBSDID("$FreeBSD$"); #endif /* __FreeBSD__ */ #include <sys/param.h> +#include <sys/kernel.h> #ifdef __FreeBSD__ +#include <sys/bus.h> +#include <sys/interrupt.h> #include <sys/priv.h> #endif #include <sys/proc.h> @@ -72,12 +90,14 @@ __FBSDID("$FreeBSD$"); #include <sys/taskqueue.h> #include <sys/lock.h> #include <sys/mutex.h> -#include <sys/sysctl.h> #else #include <sys/ioctl.h> #include <sys/timeout.h> #endif -#include <sys/kernel.h> +#include <sys/sysctl.h> +#ifndef __FreeBSD__ +#include <sys/pool.h> +#endif #include <net/if.h> #ifdef __FreeBSD__ @@ -86,6 +106,11 @@ __FBSDID("$FreeBSD$"); #include <net/if_types.h> #include <net/route.h> #include <net/bpf.h> +#include <net/netisr.h> +#ifdef __FreeBSD__ +#include <net/vnet.h> +#endif + #include <netinet/in.h> #include <netinet/if_ether.h> #include <netinet/tcp.h> @@ -117,23 +142,191 @@ __FBSDID("$FreeBSD$"); #include "pfsync.h" #endif -#define PFSYNC_MINMTU \ - (sizeof(struct pfsync_header) + sizeof(struct pf_state)) +#define PFSYNC_MINPKT ( \ + sizeof(struct ip) + \ + sizeof(struct pfsync_header) + \ + sizeof(struct pfsync_subheader) + \ + sizeof(struct pfsync_eof)) + +struct pfsync_pkt { + struct ip *ip; + struct in_addr src; + u_int8_t flags; +}; + +int pfsync_input_hmac(struct mbuf *, int); + +int pfsync_upd_tcp(struct pf_state *, struct pfsync_state_peer *, + struct pfsync_state_peer *); + +int pfsync_in_clr(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_ins(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_iack(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_upd(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_upd_c(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_ureq(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_del(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_del_c(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_bus(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_tdb(struct pfsync_pkt *, struct mbuf *, int, int); +int pfsync_in_eof(struct pfsync_pkt *, struct mbuf *, int, int); + +int pfsync_in_error(struct pfsync_pkt *, struct mbuf *, int, int); + +int (*pfsync_acts[])(struct pfsync_pkt *, struct mbuf *, int, int) = { + pfsync_in_clr, /* PFSYNC_ACT_CLR */ + pfsync_in_ins, /* PFSYNC_ACT_INS */ + pfsync_in_iack, /* PFSYNC_ACT_INS_ACK */ + pfsync_in_upd, /* PFSYNC_ACT_UPD */ + pfsync_in_upd_c, /* PFSYNC_ACT_UPD_C */ + pfsync_in_ureq, /* PFSYNC_ACT_UPD_REQ */ + pfsync_in_del, /* PFSYNC_ACT_DEL */ + pfsync_in_del_c, /* PFSYNC_ACT_DEL_C */ + pfsync_in_error, /* PFSYNC_ACT_INS_F */ + pfsync_in_error, /* PFSYNC_ACT_DEL_F */ + pfsync_in_bus, /* PFSYNC_ACT_BUS */ + pfsync_in_tdb, /* PFSYNC_ACT_TDB */ + pfsync_in_eof /* PFSYNC_ACT_EOF */ +}; + +struct pfsync_q { + int (*write)(struct pf_state *, struct mbuf *, int); + size_t len; + u_int8_t action; +}; + +/* we have one of these for every PFSYNC_S_ */ +int pfsync_out_state(struct pf_state *, struct mbuf *, int); +int pfsync_out_iack(struct pf_state *, struct mbuf *, int); +int pfsync_out_upd_c(struct pf_state *, struct mbuf *, int); +int pfsync_out_del(struct pf_state *, struct mbuf *, int); + +struct pfsync_q pfsync_qs[] = { + { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_INS }, + { pfsync_out_iack, sizeof(struct pfsync_ins_ack), PFSYNC_ACT_INS_ACK }, + { pfsync_out_state, sizeof(struct pfsync_state), PFSYNC_ACT_UPD }, + { pfsync_out_upd_c, sizeof(struct pfsync_upd_c), PFSYNC_ACT_UPD_C }, + { pfsync_out_del, sizeof(struct pfsync_del_c), PFSYNC_ACT_DEL_C } +}; + +void pfsync_q_ins(struct pf_state *, int); +void pfsync_q_del(struct pf_state *); + +struct pfsync_upd_req_item { + TAILQ_ENTRY(pfsync_upd_req_item) ur_entry; + struct pfsync_upd_req ur_msg; +}; +TAILQ_HEAD(pfsync_upd_reqs, pfsync_upd_req_item); + +struct pfsync_deferral { + TAILQ_ENTRY(pfsync_deferral) pd_entry; + struct pf_state *pd_st; + struct mbuf *pd_m; +#ifdef __FreeBSD__ + struct callout pd_tmo; +#else + struct timeout pd_tmo; +#endif +}; +TAILQ_HEAD(pfsync_deferrals, pfsync_deferral); + +#define PFSYNC_PLSIZE MAX(sizeof(struct pfsync_upd_req_item), \ + sizeof(struct pfsync_deferral)) + +#ifdef notyet +int pfsync_out_tdb(struct tdb *, struct mbuf *, int); +#endif -#ifdef PFSYNCDEBUG -#define DPRINTF(x) do { if (pfsyncdebug) printf x ; } while (0) -int pfsyncdebug; +struct pfsync_softc { +#ifdef __FreeBSD__ + struct ifnet *sc_ifp; +#else + struct ifnet sc_if; +#endif + struct ifnet *sc_sync_if; + +#ifdef __FreeBSD__ + uma_zone_t sc_pool; #else -#define DPRINTF(x) + struct pool sc_pool; #endif + struct ip_moptions sc_imo; + + struct in_addr sc_sync_peer; + u_int8_t sc_maxupdates; +#ifdef __FreeBSD__ + int pfsync_sync_ok; +#endif + + struct ip sc_template; + + struct pf_state_queue sc_qs[PFSYNC_S_COUNT]; + size_t sc_len; + + struct pfsync_upd_reqs sc_upd_req_list; + + struct pfsync_deferrals sc_deferrals; + u_int sc_deferred; + + void *sc_plus; + size_t sc_pluslen; + + u_int32_t sc_ureq_sent; + int sc_bulk_tries; +#ifdef __FreeBSD__ + struct callout sc_bulkfail_tmo; +#else + struct timeout sc_bulkfail_tmo; +#endif + + u_int32_t sc_ureq_received; + struct pf_state *sc_bulk_next; + struct pf_state *sc_bulk_last; +#ifdef __FreeBSD__ + struct callout sc_bulk_tmo; +#else + struct timeout sc_bulk_tmo; +#endif + + TAILQ_HEAD(, tdb) sc_tdb_q; + +#ifdef __FreeBSD__ + struct callout sc_tmo; +#else + struct timeout sc_tmo; +#endif +#ifdef __FreeBSD__ + eventhandler_tag sc_detachtag; +#endif + +}; + +#ifdef __FreeBSD__ +static VNET_DEFINE(struct pfsync_softc *, pfsyncif) = NULL; +#define V_pfsyncif VNET(pfsyncif) + +static VNET_DEFINE(struct pfsyncstats, pfsyncstats); +#define V_pfsyncstats VNET(pfsyncstats) + +SYSCTL_NODE(_net, OID_AUTO, pfsync, CTLFLAG_RW, 0, "PFSYNC"); +SYSCTL_VNET_STRUCT(_net_pfsync, OID_AUTO, stats, CTLFLAG_RW, + &VNET_NAME(pfsyncstats), pfsyncstats, + "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); +#else struct pfsync_softc *pfsyncif = NULL; struct pfsyncstats pfsyncstats; +#define V_pfsyncstats pfsyncstats +#endif + #ifdef __FreeBSD__ -SYSCTL_DECL(_net_inet_pfsync); -SYSCTL_STRUCT(_net_inet_pfsync, 0, stats, CTLFLAG_RW, - &pfsyncstats, pfsyncstats, - "PFSYNC statistics (struct pfsyncstats, net/if_pfsync.h)"); +static void pfsyncintr(void *); +struct pfsync_swi { + void * pfsync_swi_cookie; +}; +static struct pfsync_swi pfsync_swi; +#define schednetisr(p) swi_sched(pfsync_swi.pfsync_swi_cookie, 0) +#define NETISR_PFSYNC #endif void pfsyncattach(int); @@ -144,45 +337,53 @@ void pfsync_clone_destroy(struct ifnet *); int pfsync_clone_create(struct if_clone *, int); int pfsync_clone_destroy(struct ifnet *); #endif -void pfsync_setmtu(struct pfsync_softc *, int); int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, struct pf_state_peer *); -int pfsync_insert_net_state(struct pfsync_state *, u_int8_t); -#ifdef PFSYNC_TDB void pfsync_update_net_tdb(struct pfsync_tdb *); -#endif int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, +#ifdef __FreeBSD__ struct route *); +#else + struct rtentry *); +#endif int pfsyncioctl(struct ifnet *, u_long, caddr_t); void pfsyncstart(struct ifnet *); -struct mbuf *pfsync_get_mbuf(struct pfsync_softc *, u_int8_t, void **); -int pfsync_request_update(struct pfsync_state_upd *, struct in_addr *); -int pfsync_sendout(struct pfsync_softc *); -#ifdef PFSYNC_TDB +struct mbuf *pfsync_if_dequeue(struct ifnet *); +struct mbuf *pfsync_get_mbuf(struct pfsync_softc *); + +void pfsync_deferred(struct pf_state *, int); +void pfsync_undefer(struct pfsync_deferral *, int); +void pfsync_defer_tmo(void *); + +void pfsync_request_update(u_int32_t, u_int64_t); +void pfsync_update_state_req(struct pf_state *); + +void pfsync_drop(struct pfsync_softc *); +void pfsync_sendout(void); +void pfsync_send_plus(void *, size_t); int pfsync_tdb_sendout(struct pfsync_softc *); -#endif int pfsync_sendout_mbuf(struct pfsync_softc *, struct mbuf *); void pfsync_timeout(void *); -#ifdef PFSYNC_TDB void pfsync_tdb_timeout(void *); -#endif void pfsync_send_bus(struct pfsync_softc *, u_int8_t); + +void pfsync_bulk_start(void); +void pfsync_bulk_status(u_int8_t); void pfsync_bulk_update(void *); -void pfsync_bulkfail(void *); +void pfsync_bulk_fail(void *); #ifdef __FreeBSD__ void pfsync_ifdetach(void *, struct ifnet *); -void pfsync_senddef(void *, int); /* XXX: ugly */ #define betoh64 (unsigned long long)be64toh #define timeout_del callout_stop #endif -int pfsync_sync_ok; +#define PFSYNC_MAX_BULKTRIES 12 #ifndef __FreeBSD__ -extern int ifqmaxlen; +int pfsync_sync_ok; #endif #ifdef __FreeBSD__ @@ -197,7 +398,6 @@ pfsyncattach(int npfsync) { if_clone_attach(&pfsync_cloner); } - int #ifdef __FreeBSD__ pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) @@ -205,95 +405,103 @@ pfsync_clone_create(struct if_clone *ifc, int unit, caddr_t param) pfsync_clone_create(struct if_clone *ifc, int unit) #endif { + struct pfsync_softc *sc; struct ifnet *ifp; + int q; if (unit != 0) return (EINVAL); +#ifndef __FreeBSD__ pfsync_sync_ok = 1; - if ((pfsyncif = malloc(sizeof(*pfsyncif), M_DEVBUF, M_NOWAIT)) == NULL) +#endif + + sc = malloc(sizeof(struct pfsync_softc), M_DEVBUF, M_NOWAIT | M_ZERO); + if (sc == NULL) return (ENOMEM); - bzero(pfsyncif, sizeof(*pfsyncif)); + + for (q = 0; q < PFSYNC_S_COUNT; q++) + TAILQ_INIT(&sc->sc_qs[q]); + #ifdef __FreeBSD__ - if ((pfsyncif->sc_imo.imo_membership = (struct in_multi **)malloc( - (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF, - M_NOWAIT)) == NULL) { - free(pfsyncif, M_DEVBUF); - return (ENOSPC); + sc->pfsync_sync_ok = 1; + sc->sc_pool = uma_zcreate("pfsync", PFSYNC_PLSIZE, + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + if (sc->sc_pool == NULL) { + free(sc, M_DEVBUF); + return (ENOMEM); } - pfsyncif->sc_imo.imo_mfilters = NULL; - pfsyncif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; - pfsyncif->sc_imo.imo_multicast_vif = -1; +#else + pool_init(&sc->sc_pool, PFSYNC_PLSIZE, 0, 0, 0, "pfsync", NULL); +#endif + TAILQ_INIT(&sc->sc_upd_req_list); + TAILQ_INIT(&sc->sc_deferrals); + sc->sc_deferred = 0; + + TAILQ_INIT(&sc->sc_tdb_q); - ifp = pfsyncif->sc_ifp = if_alloc(IFT_PFSYNC); + sc->sc_len = PFSYNC_MINPKT; + sc->sc_maxupdates = 128; + +#ifdef __FreeBSD__ + sc->sc_imo.imo_membership = (struct in_multi **)malloc( + (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_DEVBUF, + M_NOWAIT | M_ZERO); + sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; + sc->sc_imo.imo_multicast_vif = -1; +#else + sc->sc_imo.imo_membership = (struct in_multi **)malloc( + (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS, + M_WAITOK | M_ZERO); + sc->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS; +#endif + +#ifdef __FreeBSD__ + ifp = sc->sc_ifp = if_alloc(IFT_PFSYNC); if (ifp == NULL) { - free(pfsyncif->sc_imo.imo_membership, M_DEVBUF); - free(pfsyncif, M_DEVBUF); + free(sc->sc_imo.imo_membership, M_DEVBUF); + uma_zdestroy(sc->sc_pool); + free(sc, M_DEVBUF); return (ENOSPC); } if_initname(ifp, ifc->ifc_name, unit); - pfsyncif->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, + sc->sc_detachtag = EVENTHANDLER_REGISTER(ifnet_departure_event, +#ifdef __FreeBSD__ + pfsync_ifdetach, V_pfsyncif, EVENTHANDLER_PRI_ANY); +#else pfsync_ifdetach, pfsyncif, EVENTHANDLER_PRI_ANY); - if (pfsyncif->sc_detachtag == NULL) { +#endif + if (sc->sc_detachtag == NULL) { if_free(ifp); - free(pfsyncif->sc_imo.imo_membership, M_DEVBUF); - free(pfsyncif, M_DEVBUF); + free(sc->sc_imo.imo_membership, M_DEVBUF); + uma_zdestroy(sc->sc_pool); + free(sc, M_DEVBUF); return (ENOSPC); } - - pfsyncif->sc_ifq.ifq_maxlen = ifqmaxlen; - mtx_init(&pfsyncif->sc_ifq.ifq_mtx, ifp->if_xname, - "pfsync send queue", MTX_DEF); - TASK_INIT(&pfsyncif->sc_send_task, 0, pfsync_senddef, pfsyncif); -#endif - pfsyncif->sc_mbuf = NULL; - pfsyncif->sc_mbuf_net = NULL; -#ifdef PFSYNC_TDB - pfsyncif->sc_mbuf_tdb = NULL; -#endif - pfsyncif->sc_statep.s = NULL; - pfsyncif->sc_statep_net.s = NULL; -#ifdef PFSYNC_TDB - pfsyncif->sc_statep_tdb.t = NULL; -#endif - pfsyncif->sc_maxupdates = 128; -#ifdef __FreeBSD__ - pfsyncif->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); - pfsyncif->sc_sendaddr.s_addr = htonl(INADDR_PFSYNC_GROUP); #else - pfsyncif->sc_sync_peer.s_addr = INADDR_PFSYNC_GROUP; - pfsyncif->sc_sendaddr.s_addr = INADDR_PFSYNC_GROUP; -#endif - pfsyncif->sc_ureq_received = 0; - pfsyncif->sc_ureq_sent = 0; - pfsyncif->sc_bulk_send_next = NULL; - pfsyncif->sc_bulk_terminator = NULL; -#ifndef __FreeBSD__ - ifp = &pfsyncif->sc_if; + ifp = &sc->sc_if; snprintf(ifp->if_xname, sizeof ifp->if_xname, "pfsync%d", unit); #endif - ifp->if_softc = pfsyncif; + ifp->if_softc = sc; ifp->if_ioctl = pfsyncioctl; ifp->if_output = pfsyncoutput; ifp->if_start = pfsyncstart; ifp->if_type = IFT_PFSYNC; ifp->if_snd.ifq_maxlen = ifqmaxlen; - ifp->if_hdrlen = PFSYNC_HDRLEN; - pfsync_setmtu(pfsyncif, ETHERMTU); + ifp->if_hdrlen = sizeof(struct pfsync_header); + ifp->if_mtu = 1500; /* XXX */ #ifdef __FreeBSD__ - callout_init(&pfsyncif->sc_tmo, CALLOUT_MPSAFE); -#ifdef PFSYNC_TDB - callout_init(&pfsyncif->sc_tdb_tmo, CALLOUT_MPSAFE); -#endif - callout_init(&pfsyncif->sc_bulk_tmo, CALLOUT_MPSAFE); - callout_init(&pfsyncif->sc_bulkfail_tmo, CALLOUT_MPSAFE); + callout_init(&sc->sc_tmo, CALLOUT_MPSAFE); + callout_init(&sc->sc_bulk_tmo, CALLOUT_MPSAFE); + callout_init(&sc->sc_bulkfail_tmo, CALLOUT_MPSAFE); #else - timeout_set(&pfsyncif->sc_tmo, pfsync_timeout, pfsyncif); - timeout_set(&pfsyncif->sc_tdb_tmo, pfsync_tdb_timeout, pfsyncif); - timeout_set(&pfsyncif->sc_bulk_tmo, pfsync_bulk_update, pfsyncif); - timeout_set(&pfsyncif->sc_bulkfail_tmo, pfsync_bulkfail, pfsyncif); + ifp->if_hardmtu = MCLBYTES; /* XXX */ + timeout_set(&sc->sc_tmo, pfsync_timeout, sc); + timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc); + timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc); #endif + if_attach(ifp); #ifndef __FreeBSD__ if_alloc_sadl(ifp); @@ -307,10 +515,16 @@ pfsync_clone_create(struct if_clone *ifc, int unit) #ifdef __FreeBSD__ bpfattach(ifp, DLT_PFSYNC, PFSYNC_HDRLEN); #else - bpfattach(&pfsyncif->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); + bpfattach(&sc->sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN); #endif #endif +#ifdef __FreeBSD__ + V_pfsyncif = sc; +#else + pfsyncif = sc; +#endif + return (0); } @@ -321,60 +535,92 @@ int #endif pfsync_clone_destroy(struct ifnet *ifp) { + struct pfsync_softc *sc = ifp->if_softc; + #ifdef __FreeBSD__ - EVENTHANDLER_DEREGISTER(ifnet_departure_event, pfsyncif->sc_detachtag); - callout_stop(&pfsyncif->sc_tmo); -#ifdef PFSYNC_TDB - callout_stop(&pfsyncif->sc_tdb_tmo); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, sc->sc_detachtag); +#endif + timeout_del(&sc->sc_bulk_tmo); + timeout_del(&sc->sc_tmo); +#if NCARP > 0 +#ifdef notyet +#ifdef __FreeBSD__ + if (!sc->pfsync_sync_ok) +#else + if (!pfsync_sync_ok) +#endif + carp_group_demote_adj(&sc->sc_if, -1); #endif - callout_stop(&pfsyncif->sc_bulk_tmo); - callout_stop(&pfsyncif->sc_bulkfail_tmo); - /* XXX: more? */ #endif - #if NBPFILTER > 0 bpfdetach(ifp); #endif if_detach(ifp); + + pfsync_drop(sc); + + while (sc->sc_deferred > 0) + pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); + +#ifdef __FreeBSD__ + UMA_DESTROY(sc->sc_pool); +#else + pool_destroy(&sc->sc_pool); +#endif #ifdef __FreeBSD__ if_free(ifp); - free(pfsyncif->sc_imo.imo_membership, M_DEVBUF); + free(sc->sc_imo.imo_membership, M_DEVBUF); +#else + free(sc->sc_imo.imo_membership, M_IPMOPTS); #endif - free(pfsyncif, M_DEVBUF); + free(sc, M_DEVBUF); + +#ifdef __FreeBSD__ + V_pfsyncif = NULL; +#else pfsyncif = NULL; +#endif + #ifndef __FreeBSD__ return (0); #endif } -/* - * Start output on the pfsync interface. - */ -void -pfsyncstart(struct ifnet *ifp) +struct mbuf * +pfsync_if_dequeue(struct ifnet *ifp) { struct mbuf *m; #ifndef __FreeBSD__ int s; #endif - for (;;) { #ifdef __FreeBSD__ - IF_LOCK(&ifp->if_snd); - _IF_DROP(&ifp->if_snd); - _IF_DEQUEUE(&ifp->if_snd, m); - IF_UNLOCK(&ifp->if_snd); + IF_LOCK(&ifp->if_snd); + _IF_DROP(&ifp->if_snd); + _IF_DEQUEUE(&ifp->if_snd, m); + IF_UNLOCK(&ifp->if_snd); #else - s = splnet(); - IF_DROP(&ifp->if_snd); - IF_DEQUEUE(&ifp->if_snd, m); - splx(s); + s = splnet(); + IF_DEQUEUE(&ifp->if_snd, m); + splx(s); #endif - if (m == NULL) - return; - else - m_freem(m); + return (m); +} + +/* + * Start output on the pfsync interface. + */ +void +pfsyncstart(struct ifnet *ifp) +{ + struct mbuf *m; + + while ((m = pfsync_if_dequeue(ifp)) != NULL) { +#ifndef __FreeBSD__ + IF_DROP(&ifp->if_snd); +#endif + m_freem(m); } } @@ -383,85 +629,196 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, struct pf_state_peer *d) { if (s->scrub.scrub_flag && d->scrub == NULL) { - d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + d->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); +#else + d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); +#endif if (d->scrub == NULL) return (ENOMEM); - bzero(d->scrub, sizeof(*d->scrub)); } return (0); } +#ifndef __FreeBSD__ +void +pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) +{ + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; + sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; + sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; + sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; + sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; + sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; + sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; + sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; + sp->proto = st->key[PF_SK_WIRE]->proto; + sp->af = st->key[PF_SK_WIRE]->af; + + /* copy from state */ + strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); + bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + sp->creation = htonl(time_second - st->creation); + sp->expire = pf_state_expires(st); + if (sp->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(sp->expire - time_second); + + sp->direction = st->direction; + sp->log = st->log; + sp->timeout = st->timeout; + sp->state_flags = st->state_flags; + if (st->src_node) + sp->sync_flags |= PFSYNC_FLAG_SRCNODE; + if (st->nat_src_node) + sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; + + bcopy(&st->id, &sp->id, sizeof(sp->id)); + sp->creatorid = st->creatorid; + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); + + if (st->rule.ptr == NULL) + sp->rule = htonl(-1); + else + sp->rule = htonl(st->rule.ptr->nr); + if (st->anchor.ptr == NULL) + sp->anchor = htonl(-1); + else + sp->anchor = htonl(st->anchor.ptr->nr); + if (st->nat_rule.ptr == NULL) + sp->nat_rule = htonl(-1); + else + sp->nat_rule = htonl(st->nat_rule.ptr->nr); + + pf_state_counter_hton(st->packets[0], sp->packets[0]); + pf_state_counter_hton(st->packets[1], sp->packets[1]); + pf_state_counter_hton(st->bytes[0], sp->bytes[0]); + pf_state_counter_hton(st->bytes[1], sp->bytes[1]); + +} +#endif + int -pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) +pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) { struct pf_state *st = NULL; + struct pf_state_key *skw = NULL, *sks = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; + int pool_flags; + int error; +#ifdef __FreeBSD__ + if (sp->creatorid == 0 && V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { - printf("pfsync_insert_net_state: invalid creator id:" +#endif + printf("pfsync_state_import: invalid creator id:" " %08x\n", ntohl(sp->creatorid)); return (EINVAL); } - kif = pfi_kif_get(sp->ifname); - if (kif == NULL) { + if ((kif = pfi_kif_get(sp->ifname)) == NULL) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert_net_state: " +#endif + printf("pfsync_state_import: " "unknown interface: %s\n", sp->ifname); - /* skip this state */ - return (0); + if (flags & PFSYNC_SI_IOCTL) + return (EINVAL); + return (0); /* skip this state */ } /* - * If the ruleset checksums match, it's safe to associate the state - * with the rule of that number. + * If the ruleset checksums match or the state is coming from the ioctl, + * it's safe to associate the state with the rule of that number. */ - if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag) + if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && + (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < + pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) r = pf_main_ruleset.rules[ PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; else +#ifdef __FreeBSD__ + r = &V_pf_default_rule; +#else r = &pf_default_rule; +#endif - if (!r->max_states || r->states < r->max_states) - st = pool_get(&pf_state_pl, PR_NOWAIT); - if (st == NULL) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - return (ENOMEM); - } - bzero(st, sizeof(*st)); + if ((r->max_states && r->states_cur >= r->max_states)) + goto cleanup; - /* allocate memory for scrub info */ - if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || - pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); - pool_put(&pf_state_pl, st); - return (ENOMEM); - } +#ifdef __FreeBSD__ + if (flags & PFSYNC_SI_IOCTL) + pool_flags = PR_WAITOK | PR_ZERO; + else + pool_flags = PR_ZERO; - st->rule.ptr = r; - /* XXX get pointers to nat_rule and anchor */ + if ((st = pool_get(&V_pf_state_pl, pool_flags)) == NULL) + goto cleanup; +#else + if (flags & PFSYNC_SI_IOCTL) + pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; + else + pool_flags = PR_LIMITFAIL | PR_ZERO; - /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ - r->states++; + if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) + goto cleanup; +#endif - /* fill in the rest of the state entry */ - pf_state_host_ntoh(&sp->lan, &st->lan); - pf_state_host_ntoh(&sp->gwy, &st->gwy); - pf_state_host_ntoh(&sp->ext, &st->ext); + if ((skw = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); + if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], + &sp->key[PF_SK_STACK].addr[0], sp->af) || + PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], + &sp->key[PF_SK_STACK].addr[1], sp->af) || + sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || + sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { + if ((sks = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; + } else + sks = skw; + /* allocate memory for scrub info */ + if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || + pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) + goto cleanup; + + /* copy to state key(s) */ + skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; + skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; + skw->port[0] = sp->key[PF_SK_WIRE].port[0]; + skw->port[1] = sp->key[PF_SK_WIRE].port[1]; + skw->proto = sp->proto; + skw->af = sp->af; + if (sks != skw) { + sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; + sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; + sks->port[0] = sp->key[PF_SK_STACK].port[0]; + sks->port[1] = sp->key[PF_SK_STACK].port[1]; + sks->proto = sp->proto; + sks->af = sp->af; + } + + /* copy to state */ bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); st->creation = time_second - ntohl(sp->creation); - st->expire = ntohl(sp->expire) + time_second; + st->expire = time_second; + if (sp->expire) { + /* XXX No adaptive scaling. */ + st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); + } - st->af = sp->af; - st->proto = sp->proto; + st->expire = ntohl(sp->expire) + time_second; st->direction = sp->direction; st->log = sp->log; st->timeout = sp->timeout; @@ -469,21 +826,74 @@ pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) bcopy(sp->id, &st->id, sizeof(st->id)); st->creatorid = sp->creatorid; - st->sync_flags = PFSTATE_FROMSYNC; + pf_state_peer_ntoh(&sp->src, &st->src); + pf_state_peer_ntoh(&sp->dst, &st->dst); + + st->rule.ptr = r; + st->nat_rule.ptr = NULL; + st->anchor.ptr = NULL; + st->rt_kif = NULL; - if (pf_insert_state(kif, st)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + st->pfsync_time = time_second; + st->sync_state = PFSYNC_S_NONE; + + /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ + r->states_cur++; + r->states_tot++; + + if (!ISSET(flags, PFSYNC_SI_IOCTL)) + SET(st->state_flags, PFSTATE_NOSYNC); + + if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ - r->states--; + r->states_cur--; + goto cleanup_state; + } + + if (!ISSET(flags, PFSYNC_SI_IOCTL)) { + CLR(st->state_flags, PFSTATE_NOSYNC); + if (ISSET(st->state_flags, PFSTATE_ACK)) { + pfsync_q_ins(st, PFSYNC_S_IACK); + schednetisr(NETISR_PFSYNC); + } + } + CLR(st->state_flags, PFSTATE_ACK); + + return (0); + +cleanup: + error = ENOMEM; + if (skw == sks) + sks = NULL; +#ifdef __FreeBSD__ + if (skw != NULL) + pool_put(&V_pf_state_key_pl, skw); + if (sks != NULL) + pool_put(&V_pf_state_key_pl, sks); +#else + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); +#endif + +cleanup_state: /* pf_state_insert frees the state keys */ + if (st) { +#ifdef __FreeBSD__ + if (st->dst.scrub) + pool_put(&V_pf_state_scrub_pl, st->dst.scrub); + if (st->src.scrub) + pool_put(&V_pf_state_scrub_pl, st->src.scrub); + pool_put(&V_pf_state_pl, st); +#else if (st->dst.scrub) pool_put(&pf_state_scrub_pl, st->dst.scrub); if (st->src.scrub) pool_put(&pf_state_scrub_pl, st->src.scrub); pool_put(&pf_state_pl, st); - return (EINVAL); +#endif } - - return (0); + return (error); } void @@ -493,597 +903,865 @@ pfsync_input(struct mbuf *m, __unused int off) pfsync_input(struct mbuf *m, ...) #endif { - struct ip *ip = mtod(m, struct ip *); - struct pfsync_header *ph; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else struct pfsync_softc *sc = pfsyncif; - struct pf_state *st; - struct pf_state_cmp key; - struct pfsync_state *sp; - struct pfsync_state_upd *up; - struct pfsync_state_del *dp; - struct pfsync_state_clr *cp; - struct pfsync_state_upd_req *rup; - struct pfsync_state_bus *bus; -#ifdef PFSYNC_TDB - struct pfsync_tdb *pt; #endif - struct in_addr src; - struct mbuf *mp; - int iplen, action, error, i, s, count, offp, sfail, stale = 0; - u_int8_t chksum_flag = 0; + struct pfsync_pkt pkt; + struct ip *ip = mtod(m, struct ip *); + struct pfsync_header *ph; + struct pfsync_subheader subh; + + int offset; + int rv; - pfsyncstats.pfsyncs_ipackets++; + V_pfsyncstats.pfsyncs_ipackets++; /* verify that we have a sync interface configured */ - if (!sc || !sc->sc_sync_ifp || !pf_status.running) +#ifdef __FreeBSD__ + if (!sc || !sc->sc_sync_if || !V_pf_status.running) +#else + if (!sc || !sc->sc_sync_if || !pf_status.running) +#endif goto done; /* verify that the packet came in on the right interface */ - if (sc->sc_sync_ifp != m->m_pkthdr.rcvif) { - pfsyncstats.pfsyncs_badif++; + if (sc->sc_sync_if != m->m_pkthdr.rcvif) { + V_pfsyncstats.pfsyncs_badif++; goto done; } - /* verify that the IP TTL is 255. */ +#ifdef __FreeBSD__ + sc->sc_ifp->if_ipackets++; + sc->sc_ifp->if_ibytes += m->m_pkthdr.len; +#else + sc->sc_if.if_ipackets++; + sc->sc_if.if_ibytes += m->m_pkthdr.len; +#endif + /* verify that the IP TTL is 255. */ if (ip->ip_ttl != PFSYNC_DFLTTL) { - pfsyncstats.pfsyncs_badttl++; + V_pfsyncstats.pfsyncs_badttl++; goto done; } - iplen = ip->ip_hl << 2; - - if (m->m_pkthdr.len < iplen + sizeof(*ph)) { - pfsyncstats.pfsyncs_hdrops++; + offset = ip->ip_hl << 2; + if (m->m_pkthdr.len < offset + sizeof(*ph)) { + V_pfsyncstats.pfsyncs_hdrops++; goto done; } - if (iplen + sizeof(*ph) > m->m_len) { - if ((m = m_pullup(m, iplen + sizeof(*ph))) == NULL) { - pfsyncstats.pfsyncs_hdrops++; - goto done; + if (offset + sizeof(*ph) > m->m_len) { + if (m_pullup(m, offset + sizeof(*ph)) == NULL) { + V_pfsyncstats.pfsyncs_hdrops++; + return; } ip = mtod(m, struct ip *); } - ph = (struct pfsync_header *)((char *)ip + iplen); + ph = (struct pfsync_header *)((char *)ip + offset); /* verify the version */ if (ph->version != PFSYNC_VERSION) { - pfsyncstats.pfsyncs_badver++; + V_pfsyncstats.pfsyncs_badver++; goto done; } - action = ph->action; - count = ph->count; - - /* make sure it's a valid action code */ - if (action >= PFSYNC_ACT_MAX) { - pfsyncstats.pfsyncs_badact++; +#if 0 + if (pfsync_input_hmac(m, offset) != 0) { + /* XXX stats */ goto done; } +#endif /* Cheaper to grab this now than having to mess with mbufs later */ - src = ip->ip_src; - - if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) - chksum_flag++; - - switch (action) { - case PFSYNC_ACT_CLR: { - struct pf_state *nexts; - struct pfi_kif *kif; - u_int32_t creatorid; - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - sizeof(*cp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; + pkt.ip = ip; + pkt.src = ip->ip_src; + pkt.flags = 0; + +#ifdef __FreeBSD__ + if (!bcmp(&ph->pfcksum, &V_pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) +#else + if (!bcmp(&ph->pfcksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) +#endif + pkt.flags |= PFSYNC_SI_CKSUM; + + offset += sizeof(*ph); + for (;;) { + m_copydata(m, offset, sizeof(subh), (caddr_t)&subh); + offset += sizeof(subh); + + if (subh.action >= PFSYNC_ACT_MAX) { + V_pfsyncstats.pfsyncs_badact++; + goto done; } - cp = (struct pfsync_state_clr *)(mp->m_data + offp); - creatorid = cp->creatorid; - s = splsoftnet(); + rv = (*pfsync_acts[subh.action])(&pkt, m, offset, + ntohs(subh.count)); + if (rv == -1) + return; + + offset += rv; + } + +done: + m_freem(m); +} + +int +pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct pfsync_clr *clr; + struct mbuf *mp; + int len = sizeof(*clr) * count; + int i, offp; + + struct pf_state *st, *nexts; + struct pf_state_key *sk, *nextsk; + struct pf_state_item *si; + u_int32_t creatorid; + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + clr = (struct pfsync_clr *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - if (cp->ifname[0] == '\0') { + for (i = 0; i < count; i++) { + creatorid = clr[i].creatorid; + + if (clr[i].ifname[0] == '\0') { +#ifdef __FreeBSD__ + for (st = RB_MIN(pf_state_tree_id, &V_tree_id); + st; st = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, st); +#else for (st = RB_MIN(pf_state_tree_id, &tree_id); st; st = nexts) { nexts = RB_NEXT(pf_state_tree_id, &tree_id, st); +#endif if (st->creatorid == creatorid) { - st->sync_flags |= PFSTATE_FROMSYNC; + SET(st->state_flags, PFSTATE_NOSYNC); pf_unlink_state(st); } } } else { - if ((kif = pfi_kif_get(cp->ifname)) == NULL) { + if (pfi_kif_get(clr[i].ifname) == NULL) + continue; + + /* XXX correct? */ #ifdef __FreeBSD__ - PF_UNLOCK(); + for (sk = RB_MIN(pf_state_tree, &V_pf_statetbl); +#else + for (sk = RB_MIN(pf_state_tree, &pf_statetbl); #endif - splx(s); - return; - } - for (st = RB_MIN(pf_state_tree_lan_ext, - &kif->pfik_lan_ext); st; st = nexts) { - nexts = RB_NEXT(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, st); - if (st->creatorid == creatorid) { - st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + sk; sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree, +#ifdef __FreeBSD__ + &V_pf_statetbl, sk); +#else + &pf_statetbl, sk); +#endif + TAILQ_FOREACH(si, &sk->states, entry) { + if (si->s->creatorid == creatorid) { + SET(si->s->state_flags, + PFSTATE_NOSYNC); + pf_unlink_state(si->s); + } } } } + } #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); + splx(s); - break; + return (len); +} + +int +pfsync_in_ins(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct mbuf *mp; + struct pfsync_state *sa, *sp; + int len = sizeof(*sp) * count; + int i, offp; + + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); } - case PFSYNC_ACT_INS: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } + sa = (struct pfsync_state *)(mp->m_data + offp); - s = splsoftnet(); + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - /* check for invalid values */ - if (sp->timeout >= PFTM_MAX || - sp->src.state > PF_TCPS_PROXY_DST || - sp->dst.state > PF_TCPS_PROXY_DST || - sp->direction > PF_OUT || - (sp->af != AF_INET && sp->af != AF_INET6)) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_INS: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; - } + for (i = 0; i < count; i++) { + sp = &sa[i]; - if ((error = pfsync_insert_net_state(sp, - chksum_flag))) { - if (error == ENOMEM) { + /* check for invalid values */ + if (sp->timeout >= PFTM_MAX || + sp->src.state > PF_TCPS_PROXY_DST || + sp->dst.state > PF_TCPS_PROXY_DST || + sp->direction > PF_OUT || + (sp->af != AF_INET && sp->af != AF_INET6)) { #ifdef __FreeBSD__ - PF_UNLOCK(); + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { #endif - splx(s); - goto done; - } - continue; + printf("pfsync_input: PFSYNC5_ACT_INS: " + "invalid value\n"); } + V_pfsyncstats.pfsyncs_badval++; + continue; } + + if (pfsync_state_import(sp, pkt->flags) == ENOMEM) { + /* drop out, but process the rest of the actions */ + break; + } + } #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); - break; - case PFSYNC_ACT_UPD: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } + splx(s); + + return (len); +} + +int +pfsync_in_iack(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct pfsync_ins_ack *ia, *iaa; + struct pf_state_cmp id_key; + struct pf_state *st; - s = splsoftnet(); + struct mbuf *mp; + int len = count * sizeof(*ia); + int offp, i; + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + iaa = (struct pfsync_ins_ack *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - int flags = PFSYNC_FLAG_STALE; - - /* check for invalid values */ - if (sp->timeout >= PFTM_MAX || - sp->src.state > PF_TCPS_PROXY_DST || - sp->dst.state > PF_TCPS_PROXY_DST) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_UPD: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; - } + for (i = 0; i < count; i++) { + ia = &iaa[i]; - bcopy(sp->id, &key.id, sizeof(key.id)); - key.creatorid = sp->creatorid; + bcopy(&ia->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = ia->creatorid; - st = pf_find_state_byid(&key); - if (st == NULL) { - /* insert the update */ - if (pfsync_insert_net_state(sp, chksum_flag)) - pfsyncstats.pfsyncs_badstate++; - continue; - } - sfail = 0; - if (st->proto == IPPROTO_TCP) { - /* - * The state should never go backwards except - * for syn-proxy states. Neither should the - * sequence window slide backwards. - */ - if (st->src.state > sp->src.state && - (st->src.state < PF_TCPS_PROXY_SRC || - sp->src.state >= PF_TCPS_PROXY_SRC)) - sfail = 1; - else if (SEQ_GT(st->src.seqlo, - ntohl(sp->src.seqlo))) - sfail = 3; - else if (st->dst.state > sp->dst.state) { - /* There might still be useful - * information about the src state here, - * so import that part of the update, - * then "fail" so we send the updated - * state back to the peer who is missing - * our what we know. */ - pf_state_peer_ntoh(&sp->src, &st->src); - /* XXX do anything with timeouts? */ - sfail = 7; - flags = 0; - } else if (st->dst.state >= TCPS_SYN_SENT && - SEQ_GT(st->dst.seqlo, ntohl(sp->dst.seqlo))) - sfail = 4; - } else { - /* - * Non-TCP protocol state machine always go - * forwards - */ - if (st->src.state > sp->src.state) - sfail = 5; - else if (st->dst.state > sp->dst.state) - sfail = 6; - } - if (sfail) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: %s stale update " - "(%d) id: %016llx " - "creatorid: %08x\n", - (sfail < 7 ? "ignoring" - : "partial"), sfail, - betoh64(st->id), - ntohl(st->creatorid)); - pfsyncstats.pfsyncs_badstate++; - - if (!(sp->sync_flags & PFSTATE_STALE)) { - /* we have a better state, send it */ - if (sc->sc_mbuf != NULL && !stale) - pfsync_sendout(sc); - stale++; - if (!st->sync_flags) - pfsync_pack_state( - PFSYNC_ACT_UPD, st, flags); - } - continue; - } - pfsync_alloc_scrub_memory(&sp->dst, &st->dst); - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - st->expire = ntohl(sp->expire) + time_second; - st->timeout = sp->timeout; - } - if (stale && sc->sc_mbuf != NULL) - pfsync_sendout(sc); + st = pf_find_state_byid(&id_key); + if (st == NULL) + continue; + + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_deferred(st, 0); + } #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); - break; + splx(s); /* - * It's not strictly necessary for us to support the "uncompressed" - * delete action, but it's relatively simple and maintains consistency. + * XXX this is not yet implemented, but we know the size of the + * message so we can skip it. */ - case PFSYNC_ACT_DEL: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*sp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - s = splsoftnet(); + return (count * sizeof(struct pfsync_ins_ack)); +} + +int +pfsync_upd_tcp(struct pf_state *st, struct pfsync_state_peer *src, + struct pfsync_state_peer *dst) +{ + int sfail = 0; + + /* + * The state should never go backwards except + * for syn-proxy states. Neither should the + * sequence window slide backwards. + */ + if (st->src.state > src->state && + (st->src.state < PF_TCPS_PROXY_SRC || + src->state >= PF_TCPS_PROXY_SRC)) + sfail = 1; + else if (SEQ_GT(st->src.seqlo, ntohl(src->seqlo))) + sfail = 3; + else if (st->dst.state > dst->state) { + /* There might still be useful + * information about the src state here, + * so import that part of the update, + * then "fail" so we send the updated + * state back to the peer who is missing + * our what we know. */ + pf_state_peer_ntoh(src, &st->src); + /* XXX do anything with timeouts? */ + sfail = 7; + } else if (st->dst.state >= TCPS_SYN_SENT && + SEQ_GT(st->dst.seqlo, ntohl(dst->seqlo))) + sfail = 4; + + return (sfail); +} + +int +pfsync_in_upd(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct pfsync_state *sa, *sp; + struct pf_state_cmp id_key; + struct pf_state_key *sk; + struct pf_state *st; + int sfail; + + struct mbuf *mp; + int len = count * sizeof(*sp); + int offp, i; + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + sa = (struct pfsync_state *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - for (i = 0, sp = (struct pfsync_state *)(mp->m_data + offp); - i < count; i++, sp++) { - bcopy(sp->id, &key.id, sizeof(key.id)); - key.creatorid = sp->creatorid; + for (i = 0; i < count; i++) { + sp = &sa[i]; - st = pf_find_state_byid(&key); - if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; - continue; + /* check for invalid values */ + if (sp->timeout >= PFTM_MAX || + sp->src.state > PF_TCPS_PROXY_DST || + sp->dst.state > PF_TCPS_PROXY_DST) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif + printf("pfsync_input: PFSYNC_ACT_UPD: " + "invalid value\n"); } - st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + V_pfsyncstats.pfsyncs_badval++; + continue; + } + + bcopy(sp->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = sp->creatorid; + + st = pf_find_state_byid(&id_key); + if (st == NULL) { + /* insert the update */ + if (pfsync_state_import(sp, 0)) + V_pfsyncstats.pfsyncs_badstate++; + continue; } + + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_deferred(st, 1); + + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ + sfail = 0; + if (sk->proto == IPPROTO_TCP) + sfail = pfsync_upd_tcp(st, &sp->src, &sp->dst); + else { + /* + * Non-TCP protocol state machine always go + * forwards + */ + if (st->src.state > sp->src.state) + sfail = 5; + else if (st->dst.state > sp->dst.state) + sfail = 6; + } + + if (sfail) { #ifdef __FreeBSD__ - PF_UNLOCK(); + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { #endif - splx(s); - break; - case PFSYNC_ACT_UPD_C: { - int update_requested = 0; + printf("pfsync: %s stale update (%d)" + " id: %016llx creatorid: %08x\n", + (sfail < 7 ? "ignoring" : "partial"), + sfail, betoh64(st->id), + ntohl(st->creatorid)); + } + V_pfsyncstats.pfsyncs_stale++; - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*up), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; + pfsync_update_state(st); + schednetisr(NETISR_PFSYNC); + continue; } + pfsync_alloc_scrub_memory(&sp->dst, &st->dst); + pf_state_peer_ntoh(&sp->src, &st->src); + pf_state_peer_ntoh(&sp->dst, &st->dst); + st->expire = ntohl(sp->expire) + time_second; + st->timeout = sp->timeout; + st->pfsync_time = time_second; + } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + splx(s); + + return (len); +} + +int +pfsync_in_upd_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct pfsync_upd_c *ua, *up; + struct pf_state_key *sk; + struct pf_state_cmp id_key; + struct pf_state *st; + + int len = count * sizeof(*up); + int sfail; + + struct mbuf *mp; + int offp, i; + int s; - s = splsoftnet(); + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + ua = (struct pfsync_upd_c *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - for (i = 0, up = (struct pfsync_state_upd *)(mp->m_data + offp); - i < count; i++, up++) { - /* check for invalid values */ - if (up->timeout >= PFTM_MAX || - up->src.state > PF_TCPS_PROXY_DST || - up->dst.state > PF_TCPS_PROXY_DST) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: " - "PFSYNC_ACT_UPD_C: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - continue; + for (i = 0; i < count; i++) { + up = &ua[i]; + + /* check for invalid values */ + if (up->timeout >= PFTM_MAX || + up->src.state > PF_TCPS_PROXY_DST || + up->dst.state > PF_TCPS_PROXY_DST) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif + printf("pfsync_input: " + "PFSYNC_ACT_UPD_C: " + "invalid value\n"); } + V_pfsyncstats.pfsyncs_badval++; + continue; + } - bcopy(up->id, &key.id, sizeof(key.id)); - key.creatorid = up->creatorid; + bcopy(&up->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = up->creatorid; - st = pf_find_state_byid(&key); - if (st == NULL) { - /* We don't have this state. Ask for it. */ - error = pfsync_request_update(up, &src); - if (error == ENOMEM) { + st = pf_find_state_byid(&id_key); + if (st == NULL) { + /* We don't have this state. Ask for it. */ + pfsync_request_update(id_key.creatorid, id_key.id); + continue; + } + + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_deferred(st, 1); + + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ + sfail = 0; + if (sk->proto == IPPROTO_TCP) + sfail = pfsync_upd_tcp(st, &up->src, &up->dst); + else { + /* + * Non-TCP protocol state machine always go forwards + */ + if (st->src.state > up->src.state) + sfail = 5; + else if (st->dst.state > up->dst.state) + sfail = 6; + } + + if (sfail) { #ifdef __FreeBSD__ - PF_UNLOCK(); + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { #endif - splx(s); - goto done; - } - update_requested = 1; - pfsyncstats.pfsyncs_badstate++; - continue; - } - sfail = 0; - if (st->proto == IPPROTO_TCP) { - /* - * The state should never go backwards except - * for syn-proxy states. Neither should the - * sequence window slide backwards. - */ - if (st->src.state > up->src.state && - (st->src.state < PF_TCPS_PROXY_SRC || - up->src.state >= PF_TCPS_PROXY_SRC)) - sfail = 1; - else if (st->dst.state > up->dst.state) - sfail = 2; - else if (SEQ_GT(st->src.seqlo, - ntohl(up->src.seqlo))) - sfail = 3; - else if (st->dst.state >= TCPS_SYN_SENT && - SEQ_GT(st->dst.seqlo, ntohl(up->dst.seqlo))) - sfail = 4; - } else { - /* - * Non-TCP protocol state machine always go - * forwards - */ - if (st->src.state > up->src.state) - sfail = 5; - else if (st->dst.state > up->dst.state) - sfail = 6; + printf("pfsync: ignoring stale update " + "(%d) id: %016llx " + "creatorid: %08x\n", sfail, + betoh64(st->id), + ntohl(st->creatorid)); } - if (sfail) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: ignoring stale update " - "(%d) id: %016llx " - "creatorid: %08x\n", sfail, - betoh64(st->id), - ntohl(st->creatorid)); - pfsyncstats.pfsyncs_badstate++; - - /* we have a better state, send it out */ - if ((!stale || update_requested) && - sc->sc_mbuf != NULL) { - pfsync_sendout(sc); - update_requested = 0; - } - stale++; - if (!st->sync_flags) - pfsync_pack_state(PFSYNC_ACT_UPD, st, - PFSYNC_FLAG_STALE); - continue; - } - pfsync_alloc_scrub_memory(&up->dst, &st->dst); - pf_state_peer_ntoh(&up->src, &st->src); - pf_state_peer_ntoh(&up->dst, &st->dst); - st->expire = ntohl(up->expire) + time_second; - st->timeout = up->timeout; + V_pfsyncstats.pfsyncs_stale++; + + pfsync_update_state(st); + schednetisr(NETISR_PFSYNC); + continue; } - if ((update_requested || stale) && sc->sc_mbuf) - pfsync_sendout(sc); + pfsync_alloc_scrub_memory(&up->dst, &st->dst); + pf_state_peer_ntoh(&up->src, &st->src); + pf_state_peer_ntoh(&up->dst, &st->dst); + st->expire = ntohl(up->expire) + time_second; + st->timeout = up->timeout; + st->pfsync_time = time_second; + } #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); - break; + splx(s); + + return (len); +} + +int +pfsync_in_ureq(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct pfsync_upd_req *ur, *ura; + struct mbuf *mp; + int len = count * sizeof(*ur); + int i, offp; + + struct pf_state_cmp id_key; + struct pf_state *st; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); } - case PFSYNC_ACT_DEL_C: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*dp), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } + ura = (struct pfsync_upd_req *)(mp->m_data + offp); - s = splsoftnet(); -#ifdef __FreeBSD__ - PF_LOCK(); -#endif - for (i = 0, dp = (struct pfsync_state_del *)(mp->m_data + offp); - i < count; i++, dp++) { - bcopy(dp->id, &key.id, sizeof(key.id)); - key.creatorid = dp->creatorid; + for (i = 0; i < count; i++) { + ur = &ura[i]; + + bcopy(&ur->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = ur->creatorid; - st = pf_find_state_byid(&key); + if (id_key.id == 0 && id_key.creatorid == 0) + pfsync_bulk_start(); + else { + st = pf_find_state_byid(&id_key); if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; + V_pfsyncstats.pfsyncs_badstate++; continue; } - st->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + if (ISSET(st->state_flags, PFSTATE_NOSYNC)) + continue; + + pfsync_update_state_req(st); } + } + + return (len); +} + +int +pfsync_in_del(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct mbuf *mp; + struct pfsync_state *sa, *sp; + struct pf_state_cmp id_key; + struct pf_state *st; + int len = count * sizeof(*sp); + int offp, i; + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + sa = (struct pfsync_state *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_LOCK(); #endif - splx(s); - break; - case PFSYNC_ACT_INS_F: - case PFSYNC_ACT_DEL_F: - /* not implemented */ - break; - case PFSYNC_ACT_UREQ: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*rup), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; + for (i = 0; i < count; i++) { + sp = &sa[i]; + + bcopy(sp->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = sp->creatorid; + + st = pf_find_state_byid(&id_key); + if (st == NULL) { + V_pfsyncstats.pfsyncs_badstate++; + continue; } + SET(st->state_flags, PFSTATE_NOSYNC); + pf_unlink_state(st); + } +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + splx(s); + + return (len); +} + +int +pfsync_in_del_c(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + struct mbuf *mp; + struct pfsync_del_c *sa, *sp; + struct pf_state_cmp id_key; + struct pf_state *st; + int len = count * sizeof(*sp); + int offp, i; + int s; - s = splsoftnet(); + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + sa = (struct pfsync_del_c *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - for (i = 0, - rup = (struct pfsync_state_upd_req *)(mp->m_data + offp); - i < count; i++, rup++) { - bcopy(rup->id, &key.id, sizeof(key.id)); - key.creatorid = rup->creatorid; - - if (key.id == 0 && key.creatorid == 0) { - sc->sc_ureq_received = time_uptime; - if (sc->sc_bulk_send_next == NULL) - sc->sc_bulk_send_next = - TAILQ_FIRST(&state_list); - sc->sc_bulk_terminator = sc->sc_bulk_send_next; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received " - "bulk update request\n"); - pfsync_send_bus(sc, PFSYNC_BUS_START); -#ifdef __FreeBSD__ - callout_reset(&sc->sc_bulk_tmo, 1 * hz, - pfsync_bulk_update, pfsyncif); -#else - timeout_add(&sc->sc_bulk_tmo, 1 * hz); -#endif - } else { - st = pf_find_state_byid(&key); - if (st == NULL) { - pfsyncstats.pfsyncs_badstate++; - continue; - } - if (!st->sync_flags) - pfsync_pack_state(PFSYNC_ACT_UPD, - st, 0); - } + for (i = 0; i < count; i++) { + sp = &sa[i]; + + bcopy(&sp->id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = sp->creatorid; + + st = pf_find_state_byid(&id_key); + if (st == NULL) { + V_pfsyncstats.pfsyncs_badstate++; + continue; } - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); + + SET(st->state_flags, PFSTATE_NOSYNC); + pf_unlink_state(st); + } #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_LOCK(); #endif - splx(s); - break; - case PFSYNC_ACT_BUS: - /* If we're not waiting for a bulk update, who cares. */ - if (sc->sc_ureq_sent == 0) - break; + splx(s); - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - sizeof(*bus), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - bus = (struct pfsync_state_bus *)(mp->m_data + offp); - switch (bus->status) { - case PFSYNC_BUS_START: + return (len); +} + +int +pfsync_in_bus(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ #ifdef __FreeBSD__ - callout_reset(&sc->sc_bulkfail_tmo, - pf_pool_limits[PF_LIMIT_STATES].limit / - (PFSYNC_BULKPACKETS * sc->sc_maxcount), - pfsync_bulkfail, pfsyncif); + struct pfsync_softc *sc = V_pfsyncif; #else - timeout_add(&sc->sc_bulkfail_tmo, - pf_pool_limits[PF_LIMIT_STATES].limit / - (PFSYNC_BULKPACKETS * sc->sc_maxcount)); + struct pfsync_softc *sc = pfsyncif; #endif - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received bulk " - "update start\n"); - break; - case PFSYNC_BUS_END: - if (time_uptime - ntohl(bus->endtime) >= - sc->sc_ureq_sent) { - /* that's it, we're happy */ - sc->sc_ureq_sent = 0; - sc->sc_bulk_tries = 0; - timeout_del(&sc->sc_bulkfail_tmo); + struct pfsync_bus *bus; + struct mbuf *mp; + int len = count * sizeof(*bus); + int offp; + + /* If we're not waiting for a bulk update, who cares. */ + if (sc->sc_ureq_sent == 0) + return (len); + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + bus = (struct pfsync_bus *)(mp->m_data + offp); + + switch (bus->status) { + case PFSYNC_BUS_START: +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, + V_pfsyncif); +#else + timeout_add_sec(&sc->sc_bulkfail_tmo, 5); /* XXX magic */ +#endif +#ifdef XXX + pf_pool_limits[PF_LIMIT_STATES].limit / + (PFSYNC_BULKPACKETS * sc->sc_maxcount)); +#endif +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) +#endif + printf("pfsync: received bulk update start\n"); + break; + + case PFSYNC_BUS_END: + if (time_uptime - ntohl(bus->endtime) >= + sc->sc_ureq_sent) { + /* that's it, we're happy */ + sc->sc_ureq_sent = 0; + sc->sc_bulk_tries = 0; + timeout_del(&sc->sc_bulkfail_tmo); #if NCARP > 0 - if (!pfsync_sync_ok) +#ifdef notyet #ifdef __FreeBSD__ -#ifdef CARP_ADVANCED - carp_group_demote_adj(sc->sc_ifp, -1); + if (!sc->pfsync_sync_ok) +#else + if (!pfsync_sync_ok) +#endif + carp_group_demote_adj(&sc->sc_if, -1); #endif +#endif +#ifdef __FreeBSD__ + sc->pfsync_sync_ok = 1; #else - carp_group_demote_adj(&sc->sc_if, -1); + pfsync_sync_ok = 1; #endif +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) #endif - pfsync_sync_ok = 1; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received valid " - "bulk update end\n"); - } else { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: received invalid " - "bulk update end: bad timestamp\n"); - } - break; + printf("pfsync: received valid " + "bulk update end\n"); + } else { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) +#endif + printf("pfsync: received invalid " + "bulk update end: bad timestamp\n"); } break; -#ifdef PFSYNC_TDB - case PFSYNC_ACT_TDB_UPD: - if ((mp = m_pulldown(m, iplen + sizeof(*ph), - count * sizeof(*pt), &offp)) == NULL) { - pfsyncstats.pfsyncs_badlen++; - return; - } - s = splsoftnet(); + } + + return (len); +} + +int +pfsync_in_tdb(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + int len = count * sizeof(struct pfsync_tdb); + +#if defined(IPSEC) + struct pfsync_tdb *tp; + struct mbuf *mp; + int offp; + int i; + int s; + + mp = m_pulldown(m, offset, len, &offp); + if (mp == NULL) { + V_pfsyncstats.pfsyncs_badlen++; + return (-1); + } + tp = (struct pfsync_tdb *)(mp->m_data + offp); + + s = splsoftnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - for (i = 0, pt = (struct pfsync_tdb *)(mp->m_data + offp); - i < count; i++, pt++) - pfsync_update_net_tdb(pt); + for (i = 0; i < count; i++) + pfsync_update_net_tdb(&tp[i]); #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); - break; + splx(s); #endif + + return (len); +} + +#if defined(IPSEC) +/* Update an in-kernel tdb. Silently fail if no tdb is found. */ +void +pfsync_update_net_tdb(struct pfsync_tdb *pt) +{ + struct tdb *tdb; + int s; + + /* check for invalid values */ + if (ntohl(pt->spi) <= SPI_RESERVED_MAX || + (pt->dst.sa.sa_family != AF_INET && + pt->dst.sa.sa_family != AF_INET6)) + goto bad; + + s = spltdb(); + tdb = gettdb(pt->spi, &pt->dst, pt->sproto); + if (tdb) { + pt->rpl = ntohl(pt->rpl); + pt->cur_bytes = betoh64(pt->cur_bytes); + + /* Neither replay nor byte counter should ever decrease. */ + if (pt->rpl < tdb->tdb_rpl || + pt->cur_bytes < tdb->tdb_cur_bytes) { + splx(s); + goto bad; + } + + tdb->tdb_rpl = pt->rpl; + tdb->tdb_cur_bytes = pt->cur_bytes; } + splx(s); + return; -done: - if (m) - m_freem(m); +bad: +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) +#endif + printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " + "invalid value\n"); + V_pfsyncstats.pfsyncs_badstate++; + return; +} +#endif + + +int +pfsync_in_eof(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + /* check if we are at the right place in the packet */ + if (offset != m->m_pkthdr.len - sizeof(struct pfsync_eof)) + V_pfsyncstats.pfsyncs_badact++; + + /* we're done. free and let the caller return */ + m_freem(m); + return (-1); +} + +int +pfsync_in_error(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) +{ + V_pfsyncstats.pfsyncs_badact++; + + m_freem(m); + return (-1); } int pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, - struct route *ro) +#ifdef __FreeBSD__ + struct route *rt) +#else + struct rtentry *rt) +#endif { m_freem(m); return (0); @@ -1101,12 +1779,15 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct ip_moptions *imo = &sc->sc_imo; struct pfsyncreq pfsyncr; struct ifnet *sifp; + struct ip *ip; int s, error; switch (cmd) { +#if 0 case SIOCSIFADDR: case SIOCAIFADDR: case SIOCSIFDSTADDR: +#endif case SIOCSIFFLAGS: #ifdef __FreeBSD__ if (ifp->if_flags & IFF_UP) @@ -1121,32 +1802,33 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) #endif break; case SIOCSIFMTU: - if (ifr->ifr_mtu < PFSYNC_MINMTU) + if (ifr->ifr_mtu <= PFSYNC_MINPKT) return (EINVAL); - if (ifr->ifr_mtu > MCLBYTES) + if (ifr->ifr_mtu > MCLBYTES) /* XXX could be bigger */ ifr->ifr_mtu = MCLBYTES; - s = splnet(); + if (ifr->ifr_mtu < ifp->if_mtu) { + s = splnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_LOCK(); #endif - if (ifr->ifr_mtu < ifp->if_mtu) - pfsync_sendout(sc); - pfsync_setmtu(sc, ifr->ifr_mtu); + pfsync_sendout(); #ifdef __FreeBSD__ - PF_UNLOCK(); + PF_UNLOCK(); #endif - splx(s); + splx(s); + } + ifp->if_mtu = ifr->ifr_mtu; break; case SIOCGETPFSYNC: bzero(&pfsyncr, sizeof(pfsyncr)); - if (sc->sc_sync_ifp) + if (sc->sc_sync_if) { strlcpy(pfsyncr.pfsyncr_syncdev, - sc->sc_sync_ifp->if_xname, IFNAMSIZ); + sc->sc_sync_if->if_xname, IFNAMSIZ); + } pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; - if ((error = copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr)))) - return (error); - break; + return (copyout(&pfsyncr, ifr->ifr_data, sizeof(pfsyncr))); + case SIOCSETPFSYNC: #ifdef __FreeBSD__ if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) @@ -1182,20 +1864,13 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; if (pfsyncr.pfsyncr_syncdev[0] == 0) { - sc->sc_sync_ifp = NULL; - if (sc->sc_mbuf_net != NULL) { - /* Don't keep stale pfsync packets around. */ - s = splnet(); - m_freem(sc->sc_mbuf_net); - sc->sc_mbuf_net = NULL; - sc->sc_statep_net.s = NULL; - splx(s); - } + sc->sc_sync_if = NULL; #ifdef __FreeBSD__ PF_UNLOCK(); #endif if (imo->imo_num_memberships > 0) { - in_delmulti(imo->imo_membership[--imo->imo_num_memberships]); + in_delmulti(imo->imo_membership[ + --imo->imo_num_memberships]); imo->imo_multicast_ifp = NULL; } break; @@ -1206,27 +1881,21 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) #endif if ((sifp = ifunit(pfsyncr.pfsyncr_syncdev)) == NULL) return (EINVAL); + #ifdef __FreeBSD__ PF_LOCK(); #endif - s = splnet(); #ifdef __FreeBSD__ if (sifp->if_mtu < sc->sc_ifp->if_mtu || #else if (sifp->if_mtu < sc->sc_if.if_mtu || #endif - (sc->sc_sync_ifp != NULL && - sifp->if_mtu < sc->sc_sync_ifp->if_mtu) || + (sc->sc_sync_if != NULL && + sifp->if_mtu < sc->sc_sync_if->if_mtu) || sifp->if_mtu < MCLBYTES - sizeof(struct ip)) - pfsync_sendout(sc); - sc->sc_sync_ifp = sifp; - -#ifdef __FreeBSD__ - pfsync_setmtu(sc, sc->sc_ifp->if_mtu); -#else - pfsync_setmtu(sc, sc->sc_if.if_mtu); -#endif + pfsync_sendout(); + sc->sc_sync_if = sifp; if (imo->imo_num_memberships > 0) { #ifdef __FreeBSD__ @@ -1239,7 +1908,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) imo->imo_multicast_ifp = NULL; } - if (sc->sc_sync_ifp && + if (sc->sc_sync_if && #ifdef __FreeBSD__ sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { #else @@ -1247,8 +1916,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) #endif struct in_addr addr; - if (!(sc->sc_sync_ifp->if_flags & IFF_MULTICAST)) { - sc->sc_sync_ifp = NULL; + if (!(sc->sc_sync_if->if_flags & IFF_MULTICAST)) { + sc->sc_sync_if = NULL; #ifdef __FreeBSD__ PF_UNLOCK(); #endif @@ -1266,8 +1935,8 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) PF_UNLOCK(); #endif if ((imo->imo_membership[0] = - in_addmulti(&addr, sc->sc_sync_ifp)) == NULL) { - sc->sc_sync_ifp = NULL; + in_addmulti(&addr, sc->sc_sync_if)) == NULL) { + sc->sc_sync_if = NULL; splx(s); return (ENOBUFS); } @@ -1275,47 +1944,54 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) PF_LOCK(); #endif imo->imo_num_memberships++; - imo->imo_multicast_ifp = sc->sc_sync_ifp; + imo->imo_multicast_ifp = sc->sc_sync_if; imo->imo_multicast_ttl = PFSYNC_DFLTTL; imo->imo_multicast_loop = 0; } - if (sc->sc_sync_ifp || -#ifdef __FreeBSD__ - sc->sc_sendaddr.s_addr != htonl(INADDR_PFSYNC_GROUP)) { -#else - sc->sc_sendaddr.s_addr != INADDR_PFSYNC_GROUP) { -#endif + ip = &sc->sc_template; + bzero(ip, sizeof(*ip)); + ip->ip_v = IPVERSION; + ip->ip_hl = sizeof(sc->sc_template) >> 2; + ip->ip_tos = IPTOS_LOWDELAY; + /* len and id are set later */ + ip->ip_off = htons(IP_DF); + ip->ip_ttl = PFSYNC_DFLTTL; + ip->ip_p = IPPROTO_PFSYNC; + ip->ip_src.s_addr = INADDR_ANY; + ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; + + if (sc->sc_sync_if) { /* Request a full state table update. */ sc->sc_ureq_sent = time_uptime; #if NCARP > 0 - if (pfsync_sync_ok) +#ifdef notyet #ifdef __FreeBSD__ -#ifdef CARP_ADVANCED - carp_group_demote_adj(sc->sc_ifp, 1); -#endif + if (sc->pfsync_sync_ok) #else + if (pfsync_sync_ok) +#endif carp_group_demote_adj(&sc->sc_if, 1); #endif #endif +#ifdef __FreeBSD__ + sc->pfsync_sync_ok = 0; +#else pfsync_sync_ok = 0; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: requesting bulk update\n"); +#endif #ifdef __FreeBSD__ - callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, - pfsync_bulkfail, pfsyncif); + if (V_pf_status.debug >= PF_DEBUG_MISC) #else - timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); + if (pf_status.debug >= PF_DEBUG_MISC) #endif - error = pfsync_request_update(NULL, NULL); - if (error == ENOMEM) { + printf("pfsync: requesting bulk update\n"); #ifdef __FreeBSD__ - PF_UNLOCK(); + callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, + pfsync_bulk_fail, V_pfsyncif); +#else + timeout_add_sec(&sc->sc_bulkfail_tmo, 5); #endif - splx(s); - return (ENOMEM); - } - pfsync_sendout(sc); + pfsync_request_update(0, 0); } #ifdef __FreeBSD__ PF_UNLOCK(); @@ -1331,34 +2007,158 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return (0); } -void -pfsync_setmtu(struct pfsync_softc *sc, int mtu_req) +int +pfsync_out_state(struct pf_state *st, struct mbuf *m, int offset) { - int mtu; + struct pfsync_state *sp = (struct pfsync_state *)(m->m_data + offset); + + pfsync_state_export(sp, st); + + return (sizeof(*sp)); +} - if (sc->sc_sync_ifp && sc->sc_sync_ifp->if_mtu < mtu_req) - mtu = sc->sc_sync_ifp->if_mtu; +int +pfsync_out_iack(struct pf_state *st, struct mbuf *m, int offset) +{ + struct pfsync_ins_ack *iack = + (struct pfsync_ins_ack *)(m->m_data + offset); + + iack->id = st->id; + iack->creatorid = st->creatorid; + + return (sizeof(*iack)); +} + +int +pfsync_out_upd_c(struct pf_state *st, struct mbuf *m, int offset) +{ + struct pfsync_upd_c *up = (struct pfsync_upd_c *)(m->m_data + offset); + + up->id = st->id; + pf_state_peer_hton(&st->src, &up->src); + pf_state_peer_hton(&st->dst, &up->dst); + up->creatorid = st->creatorid; + + up->expire = pf_state_expires(st); + if (up->expire <= time_second) + up->expire = htonl(0); else - mtu = mtu_req; + up->expire = htonl(up->expire - time_second); + up->timeout = st->timeout; + + bzero(up->_pad, sizeof(up->_pad)); /* XXX */ + + return (sizeof(*up)); +} + +int +pfsync_out_del(struct pf_state *st, struct mbuf *m, int offset) +{ + struct pfsync_del_c *dp = (struct pfsync_del_c *)(m->m_data + offset); + + dp->id = st->id; + dp->creatorid = st->creatorid; - sc->sc_maxcount = (mtu - sizeof(struct pfsync_header)) / - sizeof(struct pfsync_state); - if (sc->sc_maxcount > 254) - sc->sc_maxcount = 254; + SET(st->state_flags, PFSTATE_NOSYNC); + + return (sizeof(*dp)); +} + +void +pfsync_drop(struct pfsync_softc *sc) +{ + struct pf_state *st; + struct pfsync_upd_req_item *ur; +#ifdef notyet + struct tdb *t; +#endif + int q; + + for (q = 0; q < PFSYNC_S_COUNT; q++) { + if (TAILQ_EMPTY(&sc->sc_qs[q])) + continue; + + TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { +#ifdef PFSYNC_DEBUG #ifdef __FreeBSD__ - sc->sc_ifp->if_mtu = sizeof(struct pfsync_header) + + KASSERT(st->sync_state == q, + ("%s: st->sync_state == q", + __FUNCTION__)); #else - sc->sc_if.if_mtu = sizeof(struct pfsync_header) + + KASSERT(st->sync_state == q); +#endif #endif - sc->sc_maxcount * sizeof(struct pfsync_state); + st->sync_state = PFSYNC_S_NONE; + } + TAILQ_INIT(&sc->sc_qs[q]); + } + + while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { + TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); + pool_put(&sc->sc_pool, ur); + } + + sc->sc_plus = NULL; + +#ifdef notyet + if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { + TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) + CLR(t->tdb_flags, TDBF_PFSYNC); + + TAILQ_INIT(&sc->sc_tdb_q); + } +#endif + + sc->sc_len = PFSYNC_MINPKT; } -struct mbuf * -pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) +void +pfsync_sendout(void) { - struct pfsync_header *h; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; +#endif +#if NBPFILTER > 0 +#ifdef __FreeBSD__ + struct ifnet *ifp = sc->sc_ifp; +#else + struct ifnet *ifp = &sc->sc_if; +#endif struct mbuf *m; - int len; +#endif + struct ip *ip; + struct pfsync_header *ph; + struct pfsync_subheader *subh; + struct pf_state *st; + struct pfsync_upd_req_item *ur; +#ifdef notyet + struct tdb *t; +#endif +#ifdef __FreeBSD__ + size_t pktlen; +#endif + int offset; + int q, count = 0; + +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#else + splassert(IPL_NET); +#endif + + if (sc == NULL || sc->sc_len == PFSYNC_MINPKT) + return; + +#if NBPFILTER > 0 + if (ifp->if_bpf == NULL && sc->sc_sync_if == NULL) { +#else + if (sc->sc_sync_if == NULL) { +#endif + pfsync_drop(sc); + return; + } MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { @@ -1367,874 +2167,1136 @@ pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action, void **sp) #else sc->sc_if.if_oerrors++; #endif - return (NULL); + V_pfsyncstats.pfsyncs_onomem++; + pfsync_drop(sc); + return; } - switch (action) { - case PFSYNC_ACT_CLR: - len = sizeof(struct pfsync_header) + - sizeof(struct pfsync_state_clr); - break; - case PFSYNC_ACT_UPD_C: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_DEL_C: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_del)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_UREQ: - len = (sc->sc_maxcount * sizeof(struct pfsync_state_upd_req)) + - sizeof(struct pfsync_header); - break; - case PFSYNC_ACT_BUS: - len = sizeof(struct pfsync_header) + - sizeof(struct pfsync_state_bus); - break; -#ifdef PFSYNC_TDB - case PFSYNC_ACT_TDB_UPD: - len = (sc->sc_maxcount * sizeof(struct pfsync_tdb)) + - sizeof(struct pfsync_header); - break; +#ifdef __FreeBSD__ + pktlen = max_linkhdr + sc->sc_len; + if (pktlen > MHLEN) { + /* Find the right pool to allocate from. */ + /* XXX: This is ugly. */ + m_cljget(m, M_DONTWAIT, pktlen <= MSIZE ? MSIZE : + pktlen <= MCLBYTES ? MCLBYTES : +#if MJUMPAGESIZE != MCLBYTES + pktlen <= MJUMPAGESIZE ? MJUMPAGESIZE : #endif - default: - len = (sc->sc_maxcount * sizeof(struct pfsync_state)) + - sizeof(struct pfsync_header); - break; - } - - if (len > MHLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { + pktlen <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); +#else + if (max_linkhdr + sc->sc_len > MHLEN) { + MCLGETI(m, M_DONTWAIT, NULL, max_linkhdr + sc->sc_len); +#endif + if (!ISSET(m->m_flags, M_EXT)) { m_free(m); #ifdef __FreeBSD__ sc->sc_ifp->if_oerrors++; #else sc->sc_if.if_oerrors++; #endif - return (NULL); + V_pfsyncstats.pfsyncs_onomem++; + pfsync_drop(sc); + return; } - m->m_data += (MCLBYTES - len) &~ (sizeof(long) - 1); - } else - MH_ALIGN(m, len); + } + m->m_data += max_linkhdr; + m->m_len = m->m_pkthdr.len = sc->sc_len; - m->m_pkthdr.rcvif = NULL; - m->m_pkthdr.len = m->m_len = sizeof(struct pfsync_header); - h = mtod(m, struct pfsync_header *); - h->version = PFSYNC_VERSION; - h->af = 0; - h->count = 0; - h->action = action; -#ifndef PFSYNC_TDB - if (action != PFSYNC_ACT_TDB_UPD) -#endif - bcopy(&pf_status.pf_chksum, &h->pf_chksum, - PF_MD5_DIGEST_LENGTH); + /* build the ip header */ + ip = (struct ip *)m->m_data; + bcopy(&sc->sc_template, ip, sizeof(*ip)); + offset = sizeof(*ip); - *sp = (void *)((char *)h + PFSYNC_HDRLEN); -#ifdef PFSYNC_TDB - if (action == PFSYNC_ACT_TDB_UPD) -#ifdef __FreeBSD__ - callout_reset(&sc->sc_tdb_tmo, hz, pfsync_tdb_timeout, - pfsyncif); -#else - timeout_add(&sc->sc_tdb_tmo, hz); -#endif - else -#endif -#ifdef __FreeBSD__ - callout_reset(&sc->sc_tmo, hz, pfsync_timeout, pfsyncif); -#else - timeout_add(&sc->sc_tmo, hz); -#endif - return (m); -} + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_id = htons(ip_randomid()); -int -pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) -{ - struct ifnet *ifp = NULL; - struct pfsync_softc *sc = pfsyncif; - struct pfsync_header *h, *h_net; - struct pfsync_state *sp = NULL; - struct pfsync_state_upd *up = NULL; - struct pfsync_state_del *dp = NULL; - struct pf_rule *r; - u_long secs; - int s, ret = 0; - u_int8_t i = 255, newaction = 0; + /* build the pfsync header */ + ph = (struct pfsync_header *)(m->m_data + offset); + bzero(ph, sizeof(*ph)); + offset += sizeof(*ph); - if (sc == NULL) - return (0); + ph->version = PFSYNC_VERSION; + ph->len = htons(sc->sc_len - sizeof(*ip)); #ifdef __FreeBSD__ - ifp = sc->sc_ifp; + bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); #else - ifp = &sc->sc_if; + bcopy(pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); #endif - /* - * If a packet falls in the forest and there's nobody around to - * hear, does it make a sound? - */ - if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && -#ifdef __FreeBSD__ - sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { -#else - sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { -#endif - /* Don't leave any stale pfsync packets hanging around. */ - if (sc->sc_mbuf != NULL) { - m_freem(sc->sc_mbuf); - sc->sc_mbuf = NULL; - sc->sc_statep.s = NULL; - } - return (0); - } + /* walk the queues */ + for (q = 0; q < PFSYNC_S_COUNT; q++) { + if (TAILQ_EMPTY(&sc->sc_qs[q])) + continue; - if (action >= PFSYNC_ACT_MAX) - return (EINVAL); + subh = (struct pfsync_subheader *)(m->m_data + offset); + offset += sizeof(*subh); - s = splnet(); + count = 0; + TAILQ_FOREACH(st, &sc->sc_qs[q], sync_list) { +#ifdef PFSYNC_DEBUG #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + KASSERT(st->sync_state == q, + ("%s: st->sync_state == q", + __FUNCTION__)); +#else + KASSERT(st->sync_state == q); #endif - if (sc->sc_mbuf == NULL) { - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, - (void *)&sc->sc_statep.s)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } else { - h = mtod(sc->sc_mbuf, struct pfsync_header *); - if (h->action != action) { - pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, action, - (void *)&sc->sc_statep.s)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } else { - /* - * If it's an update, look in the packet to see if - * we already have an update for the state. - */ - if (action == PFSYNC_ACT_UPD && sc->sc_maxupdates) { - struct pfsync_state *usp = - (void *)((char *)h + PFSYNC_HDRLEN); - - for (i = 0; i < h->count; i++) { - if (!memcmp(usp->id, &st->id, - PFSYNC_ID_LEN) && - usp->creatorid == st->creatorid) { - sp = usp; - sp->updates++; - break; - } - usp++; - } - } +#endif + + offset += pfsync_qs[q].write(st, m, offset); + st->sync_state = PFSYNC_S_NONE; + count++; } + TAILQ_INIT(&sc->sc_qs[q]); + + bzero(subh, sizeof(*subh)); + subh->action = pfsync_qs[q].action; + subh->count = htons(count); } - secs = time_second; + if (!TAILQ_EMPTY(&sc->sc_upd_req_list)) { + subh = (struct pfsync_subheader *)(m->m_data + offset); + offset += sizeof(*subh); - st->pfsync_time = time_uptime; + count = 0; + while ((ur = TAILQ_FIRST(&sc->sc_upd_req_list)) != NULL) { + TAILQ_REMOVE(&sc->sc_upd_req_list, ur, ur_entry); - if (sp == NULL) { - /* not a "duplicate" update */ - i = 255; - sp = sc->sc_statep.s++; - sc->sc_mbuf->m_pkthdr.len = - sc->sc_mbuf->m_len += sizeof(struct pfsync_state); - h->count++; - bzero(sp, sizeof(*sp)); + bcopy(&ur->ur_msg, m->m_data + offset, + sizeof(ur->ur_msg)); + offset += sizeof(ur->ur_msg); - bcopy(&st->id, sp->id, sizeof(sp->id)); - sp->creatorid = st->creatorid; + pool_put(&sc->sc_pool, ur); - strlcpy(sp->ifname, st->u.s.kif->pfik_name, sizeof(sp->ifname)); - pf_state_host_hton(&st->lan, &sp->lan); - pf_state_host_hton(&st->gwy, &sp->gwy); - pf_state_host_hton(&st->ext, &sp->ext); + count++; + } - bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + bzero(subh, sizeof(*subh)); + subh->action = PFSYNC_ACT_UPD_REQ; + subh->count = htons(count); + } - sp->creation = htonl(secs - st->creation); - pf_state_counter_hton(st->packets[0], sp->packets[0]); - pf_state_counter_hton(st->packets[1], sp->packets[1]); - pf_state_counter_hton(st->bytes[0], sp->bytes[0]); - pf_state_counter_hton(st->bytes[1], sp->bytes[1]); - if ((r = st->rule.ptr) == NULL) - sp->rule = htonl(-1); - else - sp->rule = htonl(r->nr); - if ((r = st->anchor.ptr) == NULL) - sp->anchor = htonl(-1); - else - sp->anchor = htonl(r->nr); - sp->af = st->af; - sp->proto = st->proto; - sp->direction = st->direction; - sp->log = st->log; - sp->state_flags = st->state_flags; - sp->timeout = st->timeout; + /* has someone built a custom region for us to add? */ + if (sc->sc_plus != NULL) { + bcopy(sc->sc_plus, m->m_data + offset, sc->sc_pluslen); + offset += sc->sc_pluslen; - if (flags & PFSYNC_FLAG_STALE) - sp->sync_flags |= PFSTATE_STALE; + sc->sc_plus = NULL; } - pf_state_peer_hton(&st->src, &sp->src); - pf_state_peer_hton(&st->dst, &sp->dst); +#ifdef notyet + if (!TAILQ_EMPTY(&sc->sc_tdb_q)) { + subh = (struct pfsync_subheader *)(m->m_data + offset); + offset += sizeof(*subh); - if (st->expire <= secs) - sp->expire = htonl(0); - else - sp->expire = htonl(st->expire - secs); + count = 0; + TAILQ_FOREACH(t, &sc->sc_tdb_q, tdb_sync_entry) { + offset += pfsync_out_tdb(t, m, offset); + CLR(t->tdb_flags, TDBF_PFSYNC); - /* do we need to build "compressed" actions for network transfer? */ - if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { - switch (action) { - case PFSYNC_ACT_UPD: - newaction = PFSYNC_ACT_UPD_C; - break; - case PFSYNC_ACT_DEL: - newaction = PFSYNC_ACT_DEL_C; - break; - default: - /* by default we just send the uncompressed states */ - break; + count++; } + TAILQ_INIT(&sc->sc_tdb_q); + + bzero(subh, sizeof(*subh)); + subh->action = PFSYNC_ACT_TDB; + subh->count = htons(count); } +#endif - if (newaction) { - if (sc->sc_mbuf_net == NULL) { - if ((sc->sc_mbuf_net = pfsync_get_mbuf(sc, newaction, - (void *)&sc->sc_statep_net.s)) == NULL) { - splx(s); - return (ENOMEM); - } - } - h_net = mtod(sc->sc_mbuf_net, struct pfsync_header *); - - switch (newaction) { - case PFSYNC_ACT_UPD_C: - if (i != 255) { - up = (void *)((char *)h_net + - PFSYNC_HDRLEN + (i * sizeof(*up))); - up->updates++; - } else { - h_net->count++; - sc->sc_mbuf_net->m_pkthdr.len = - sc->sc_mbuf_net->m_len += sizeof(*up); - up = sc->sc_statep_net.u++; - - bzero(up, sizeof(*up)); - bcopy(&st->id, up->id, sizeof(up->id)); - up->creatorid = st->creatorid; - } - up->timeout = st->timeout; - up->expire = sp->expire; - up->src = sp->src; - up->dst = sp->dst; - break; - case PFSYNC_ACT_DEL_C: - sc->sc_mbuf_net->m_pkthdr.len = - sc->sc_mbuf_net->m_len += sizeof(*dp); - dp = sc->sc_statep_net.d++; - h_net->count++; - - bzero(dp, sizeof(*dp)); - bcopy(&st->id, dp->id, sizeof(dp->id)); - dp->creatorid = st->creatorid; - break; - } + subh = (struct pfsync_subheader *)(m->m_data + offset); + offset += sizeof(*subh); + + bzero(subh, sizeof(*subh)); + subh->action = PFSYNC_ACT_EOF; + subh->count = htons(1); + + /* XXX write checksum in EOF here */ + + /* we're done, let's put it on the wire */ +#if NBPFILTER > 0 + if (ifp->if_bpf) { + m->m_data += sizeof(*ip); + m->m_len = m->m_pkthdr.len = sc->sc_len - sizeof(*ip); +#ifdef __FreeBSD__ + BPF_MTAP(ifp, m); +#else + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); +#endif + m->m_data -= sizeof(*ip); + m->m_len = m->m_pkthdr.len = sc->sc_len; } - if (h->count == sc->sc_maxcount || - (sc->sc_maxupdates && (sp->updates >= sc->sc_maxupdates))) - ret = pfsync_sendout(sc); + if (sc->sc_sync_if == NULL) { + sc->sc_len = PFSYNC_MINPKT; + m_freem(m); + return; + } +#endif - splx(s); - return (ret); +#ifdef __FreeBSD__ + sc->sc_ifp->if_opackets++; + sc->sc_ifp->if_obytes += m->m_pkthdr.len; +#else + sc->sc_if.if_opackets++; + sc->sc_if.if_obytes += m->m_pkthdr.len; +#endif + +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL) == 0) +#ifdef __FreeBSD__ + { + PF_LOCK(); +#endif + V_pfsyncstats.pfsyncs_opackets++; +#ifdef __FreeBSD__ + } +#endif + else +#ifdef __FreeBSD__ + { + PF_LOCK(); +#endif + V_pfsyncstats.pfsyncs_oerrors++; +#ifdef __FreeBSD__ + } +#endif + + /* start again */ + sc->sc_len = PFSYNC_MINPKT; } -/* This must be called in splnet() */ -int -pfsync_request_update(struct pfsync_state_upd *up, struct in_addr *src) +void +pfsync_insert_state(struct pf_state *st) { - struct ifnet *ifp = NULL; - struct pfsync_header *h; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else struct pfsync_softc *sc = pfsyncif; - struct pfsync_state_upd_req *rup; - int ret = 0; - - if (sc == NULL) - return (0); +#endif #ifdef __FreeBSD__ - ifp = sc->sc_ifp; + PF_ASSERT(MA_OWNED); #else - ifp = &sc->sc_if; + splassert(IPL_SOFTNET); #endif - if (sc->sc_mbuf == NULL) { - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, - (void *)&sc->sc_statep.s)) == NULL) - return (ENOMEM); - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } else { - h = mtod(sc->sc_mbuf, struct pfsync_header *); - if (h->action != PFSYNC_ACT_UREQ) { - pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_UREQ, - (void *)&sc->sc_statep.s)) == NULL) - return (ENOMEM); - h = mtod(sc->sc_mbuf, struct pfsync_header *); - } - } - if (src != NULL) - sc->sc_sendaddr = *src; - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*rup); - h->count++; - rup = sc->sc_statep.r++; - bzero(rup, sizeof(*rup)); - if (up != NULL) { - bcopy(up->id, rup->id, sizeof(rup->id)); - rup->creatorid = up->creatorid; + if (ISSET(st->rule.ptr->rule_flag, PFRULE_NOSYNC) || + st->key[PF_SK_WIRE]->proto == IPPROTO_PFSYNC) { + SET(st->state_flags, PFSTATE_NOSYNC); + return; } - if (h->count == sc->sc_maxcount) - ret = pfsync_sendout(sc); + if (sc == NULL || ISSET(st->state_flags, PFSTATE_NOSYNC)) + return; - return (ret); +#ifdef PFSYNC_DEBUG +#ifdef __FreeBSD__ + KASSERT(st->sync_state == PFSYNC_S_NONE, + ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); +#else + KASSERT(st->sync_state == PFSYNC_S_NONE); +#endif +#endif + + if (sc->sc_len == PFSYNC_MINPKT) +#ifdef __FreeBSD__ + callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, + V_pfsyncif); +#else + timeout_add_sec(&sc->sc_tmo, 1); +#endif + + pfsync_q_ins(st, PFSYNC_S_INS); + + if (ISSET(st->state_flags, PFSTATE_ACK)) + schednetisr(NETISR_PFSYNC); + else + st->sync_updates = 0; } +int defer = 10; + int -pfsync_clear_states(u_int32_t creatorid, char *ifname) +pfsync_defer(struct pf_state *st, struct mbuf *m) { - struct ifnet *ifp = NULL; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else struct pfsync_softc *sc = pfsyncif; - struct pfsync_state_clr *cp; - int s, ret; +#endif + struct pfsync_deferral *pd; - if (sc == NULL) +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#else + splassert(IPL_SOFTNET); +#endif + + if (sc->sc_deferred >= 128) + pfsync_undefer(TAILQ_FIRST(&sc->sc_deferrals), 0); + + pd = pool_get(&sc->sc_pool, M_NOWAIT); + if (pd == NULL) return (0); + sc->sc_deferred++; #ifdef __FreeBSD__ - ifp = sc->sc_ifp; + m->m_flags |= M_SKIP_FIREWALL; #else - ifp = &sc->sc_if; + m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; #endif + SET(st->state_flags, PFSTATE_ACK); + + pd->pd_st = st; + pd->pd_m = m; + + TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry); #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + callout_init(&pd->pd_tmo, CALLOUT_MPSAFE); + callout_reset(&pd->pd_tmo, defer, pfsync_defer_tmo, + pd); +#else + timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd); + timeout_add(&pd->pd_tmo, defer); #endif - s = splnet(); - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - if ((sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR, - (void *)&sc->sc_statep.c)) == NULL) { - splx(s); - return (ENOMEM); - } - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*cp); - cp = sc->sc_statep.c; - cp->creatorid = creatorid; - if (ifname != NULL) - strlcpy(cp->ifname, ifname, IFNAMSIZ); - ret = (pfsync_sendout(sc)); - splx(s); - return (ret); + return (1); } void -pfsync_timeout(void *v) +pfsync_undefer(struct pfsync_deferral *pd, int drop) { - struct pfsync_softc *sc = v; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; +#endif int s; - s = splnet(); #ifdef __FreeBSD__ - PF_LOCK(); + PF_ASSERT(MA_OWNED); +#else + splassert(IPL_SOFTNET); #endif - pfsync_sendout(sc); + + TAILQ_REMOVE(&sc->sc_deferrals, pd, pd_entry); + sc->sc_deferred--; + + CLR(pd->pd_st->state_flags, PFSTATE_ACK); + timeout_del(&pd->pd_tmo); /* bah */ + if (drop) + m_freem(pd->pd_m); + else { + s = splnet(); #ifdef __FreeBSD__ - PF_UNLOCK(); + /* XXX: use pf_defered?! */ + PF_UNLOCK(); #endif - splx(s); + ip_output(pd->pd_m, (void *)NULL, (void *)NULL, 0, + (void *)NULL, (void *)NULL); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + splx(s); + } + + pool_put(&sc->sc_pool, pd); } -#ifdef PFSYNC_TDB void -pfsync_tdb_timeout(void *v) +pfsync_defer_tmo(void *arg) { - struct pfsync_softc *sc = v; +#if defined(__FreeBSD__) && defined(VIMAGE) + struct pfsync_deferral *pd = arg; +#endif int s; - s = splnet(); + s = splsoftnet(); #ifdef __FreeBSD__ + CURVNET_SET(pd->pd_m->m_pkthdr.rcvif->if_vnet); /* XXX */ PF_LOCK(); #endif - pfsync_tdb_sendout(sc); + pfsync_undefer(arg, 0); #ifdef __FreeBSD__ PF_UNLOCK(); + CURVNET_RESTORE(); #endif splx(s); } + +void +pfsync_deferred(struct pf_state *st, int drop) +{ +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif + struct pfsync_deferral *pd; + + TAILQ_FOREACH(pd, &sc->sc_deferrals, pd_entry) { + if (pd->pd_st == st) { + pfsync_undefer(pd, drop); + return; + } + } + + panic("pfsync_send_deferred: unable to find deferred state"); +} + +u_int pfsync_upds = 0; -/* This must be called in splnet() */ void -pfsync_send_bus(struct pfsync_softc *sc, u_int8_t status) +pfsync_update_state(struct pf_state *st) { - struct pfsync_state_bus *bus; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; +#endif + int sync = 0; #ifdef __FreeBSD__ PF_ASSERT(MA_OWNED); +#else + splassert(IPL_SOFTNET); #endif - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - if (pfsync_sync_ok && - (sc->sc_mbuf = pfsync_get_mbuf(sc, PFSYNC_ACT_BUS, - (void *)&sc->sc_statep.b)) != NULL) { - sc->sc_mbuf->m_pkthdr.len = sc->sc_mbuf->m_len += sizeof(*bus); - bus = sc->sc_statep.b; - bus->creatorid = pf_status.hostid; - bus->status = status; - bus->endtime = htonl(time_uptime - sc->sc_ureq_received); - pfsync_sendout(sc); + if (sc == NULL) + return; + + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_deferred(st, 0); + if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { + if (st->sync_state != PFSYNC_S_NONE) + pfsync_q_del(st); + return; + } + + if (sc->sc_len == PFSYNC_MINPKT) +#ifdef __FreeBSD__ + callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, + V_pfsyncif); +#else + timeout_add_sec(&sc->sc_tmo, 1); +#endif + + switch (st->sync_state) { + case PFSYNC_S_UPD_C: + case PFSYNC_S_UPD: + case PFSYNC_S_INS: + /* we're already handling it */ + + st->sync_updates++; + if (st->sync_updates >= sc->sc_maxupdates) + sync = 1; + break; + + case PFSYNC_S_IACK: + pfsync_q_del(st); + case PFSYNC_S_NONE: + pfsync_q_ins(st, PFSYNC_S_UPD_C); + st->sync_updates = 0; + break; + + default: + panic("pfsync_update_state: unexpected sync state %d", + st->sync_state); + } + + if (sync || (time_second - st->pfsync_time) < 2) { + pfsync_upds++; + schednetisr(NETISR_PFSYNC); } } void -pfsync_bulk_update(void *v) +pfsync_request_update(u_int32_t creatorid, u_int64_t id) { - struct pfsync_softc *sc = v; - int s, i = 0; - struct pf_state *state; - - s = splnet(); #ifdef __FreeBSD__ - PF_LOCK(); + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); + struct pfsync_upd_req_item *item; + size_t nlen = sizeof(struct pfsync_upd_req); + int s; /* - * Grab at most PFSYNC_BULKPACKETS worth of states which have not - * been sent since the latest request was made. + * this code does nothing to prevent multiple update requests for the + * same state being generated. */ - state = sc->sc_bulk_send_next; - if (state) - do { - /* send state update if syncable and not already sent */ - if (!state->sync_flags - && state->timeout < PFTM_MAX - && state->pfsync_time <= sc->sc_ureq_received) { - pfsync_pack_state(PFSYNC_ACT_UPD, state, 0); - i++; - } - /* figure next state to send */ - state = TAILQ_NEXT(state, u.s.entry_list); - - /* wrap to start of list if we hit the end */ - if (!state) - state = TAILQ_FIRST(&state_list); - } while (i < sc->sc_maxcount * PFSYNC_BULKPACKETS && - state != sc->sc_bulk_terminator); - - if (!state || state == sc->sc_bulk_terminator) { - /* we're done */ - pfsync_send_bus(sc, PFSYNC_BUS_END); - sc->sc_ureq_received = 0; - sc->sc_bulk_send_next = NULL; - sc->sc_bulk_terminator = NULL; - timeout_del(&sc->sc_bulk_tmo); - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: bulk update complete\n"); - } else { - /* look again for more in a bit */ + item = pool_get(&sc->sc_pool, PR_NOWAIT); + if (item == NULL) { + /* XXX stats */ + return; + } + + item->ur_msg.id = id; + item->ur_msg.creatorid = creatorid; + + if (TAILQ_EMPTY(&sc->sc_upd_req_list)) + nlen += sizeof(struct pfsync_subheader); + #ifdef __FreeBSD__ - callout_reset(&sc->sc_bulk_tmo, 1, pfsync_bulk_update, - pfsyncif); + if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { #else - timeout_add(&sc->sc_bulk_tmo, 1); + if (sc->sc_len + nlen > sc->sc_if.if_mtu) { #endif - sc->sc_bulk_send_next = state; + s = splnet(); + pfsync_sendout(); + splx(s); + + nlen = sizeof(struct pfsync_subheader) + + sizeof(struct pfsync_upd_req); } - if (sc->sc_mbuf != NULL) - pfsync_sendout(sc); - splx(s); + + TAILQ_INSERT_TAIL(&sc->sc_upd_req_list, item, ur_entry); + sc->sc_len += nlen; + + schednetisr(NETISR_PFSYNC); +} + +void +pfsync_update_state_req(struct pf_state *st) +{ #ifdef __FreeBSD__ - PF_UNLOCK(); + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif + + if (sc == NULL) + panic("pfsync_update_state_req: nonexistant instance"); + + if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { + if (st->sync_state != PFSYNC_S_NONE) + pfsync_q_del(st); + return; + } + + switch (st->sync_state) { + case PFSYNC_S_UPD_C: + case PFSYNC_S_IACK: + pfsync_q_del(st); + case PFSYNC_S_NONE: + pfsync_q_ins(st, PFSYNC_S_UPD); + schednetisr(NETISR_PFSYNC); + return; + + case PFSYNC_S_INS: + case PFSYNC_S_UPD: + case PFSYNC_S_DEL: + /* we're already handling it */ + return; + + default: + panic("pfsync_update_state_req: unexpected sync state %d", + st->sync_state); + } } void -pfsync_bulkfail(void *v) +pfsync_delete_state(struct pf_state *st) { - struct pfsync_softc *sc = v; - int s, error; - #ifdef __FreeBSD__ - PF_LOCK(); + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif - if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { - /* Try again in a bit */ + #ifdef __FreeBSD__ - callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulkfail, - pfsyncif); + PF_ASSERT(MA_OWNED); #else - timeout_add(&sc->sc_bulkfail_tmo, 5 * hz); + splassert(IPL_SOFTNET); #endif - s = splnet(); - error = pfsync_request_update(NULL, NULL); - if (error == ENOMEM) { - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: cannot allocate mbufs for " - "bulk update\n"); - } else - pfsync_sendout(sc); - splx(s); - } else { - /* Pretend like the transfer was ok */ - sc->sc_ureq_sent = 0; - sc->sc_bulk_tries = 0; -#if NCARP > 0 - if (!pfsync_sync_ok) + + if (sc == NULL) + return; + + if (ISSET(st->state_flags, PFSTATE_ACK)) + pfsync_deferred(st, 1); + if (ISSET(st->state_flags, PFSTATE_NOSYNC)) { + if (st->sync_state != PFSYNC_S_NONE) + pfsync_q_del(st); + return; + } + + if (sc->sc_len == PFSYNC_MINPKT) #ifdef __FreeBSD__ -#ifdef CARP_ADVANCED - carp_group_demote_adj(sc->sc_ifp, -1); -#endif + callout_reset(&sc->sc_tmo, 1 * hz, pfsync_timeout, + V_pfsyncif); #else - carp_group_demote_adj(&sc->sc_if, -1); + timeout_add_sec(&sc->sc_tmo, 1); #endif -#endif - pfsync_sync_ok = 1; - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync: failed to receive " - "bulk update status\n"); - timeout_del(&sc->sc_bulkfail_tmo); + + switch (st->sync_state) { + case PFSYNC_S_INS: + /* we never got to tell the world so just forget about it */ + pfsync_q_del(st); + return; + + case PFSYNC_S_UPD_C: + case PFSYNC_S_UPD: + case PFSYNC_S_IACK: + pfsync_q_del(st); + /* FALLTHROUGH to putting it on the del list */ + + case PFSYNC_S_NONE: + pfsync_q_ins(st, PFSYNC_S_DEL); + return; + + default: + panic("pfsync_delete_state: unexpected sync state %d", + st->sync_state); } +} + +void +pfsync_clear_states(u_int32_t creatorid, const char *ifname) +{ + struct { + struct pfsync_subheader subh; + struct pfsync_clr clr; + } __packed r; + #ifdef __FreeBSD__ - PF_UNLOCK(); + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif + +#ifdef __FreeBSD__ + PF_ASSERT(MA_OWNED); +#else + splassert(IPL_SOFTNET); +#endif + + if (sc == NULL) + return; + + bzero(&r, sizeof(r)); + + r.subh.action = PFSYNC_ACT_CLR; + r.subh.count = htons(1); + + strlcpy(r.clr.ifname, ifname, sizeof(r.clr.ifname)); + r.clr.creatorid = creatorid; + + pfsync_send_plus(&r, sizeof(r)); } -/* This must be called in splnet() */ -int -pfsync_sendout(struct pfsync_softc *sc) +void +pfsync_q_ins(struct pf_state *st, int q) { -#if NBPFILTER > 0 #ifdef __FreeBSD__ - struct ifnet *ifp = sc->sc_ifp; + struct pfsync_softc *sc = V_pfsyncif; #else - struct ifnet *ifp = &sc->sc_if; -#endif + struct pfsync_softc *sc = pfsyncif; #endif - struct mbuf *m; + size_t nlen = pfsync_qs[q].len; + int s; #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + KASSERT(st->sync_state == PFSYNC_S_NONE, + ("%s: st->sync_state == PFSYNC_S_NONE", __FUNCTION__)); +#else + KASSERT(st->sync_state == PFSYNC_S_NONE); #endif - timeout_del(&sc->sc_tmo); - if (sc->sc_mbuf == NULL) - return (0); - m = sc->sc_mbuf; - sc->sc_mbuf = NULL; - sc->sc_statep.s = NULL; +#if 1 || defined(PFSYNC_DEBUG) + if (sc->sc_len < PFSYNC_MINPKT) +#ifdef __FreeBSD__ + panic("pfsync pkt len is too low %zu", sc->sc_len); +#else + panic("pfsync pkt len is too low %d", sc->sc_len); +#endif +#endif + if (TAILQ_EMPTY(&sc->sc_qs[q])) + nlen += sizeof(struct pfsync_subheader); -#if NBPFILTER > 0 - if (ifp->if_bpf) #ifdef __FreeBSD__ - BPF_MTAP(ifp, m); + if (sc->sc_len + nlen > sc->sc_ifp->if_mtu) { #else - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); + if (sc->sc_len + nlen > sc->sc_if.if_mtu) { +#endif + s = splnet(); +#ifdef __FreeBSD__ + PF_LOCK(); #endif + pfsync_sendout(); +#ifdef __FreeBSD__ + PF_UNLOCK(); #endif + splx(s); - if (sc->sc_mbuf_net) { - m_freem(m); - m = sc->sc_mbuf_net; - sc->sc_mbuf_net = NULL; - sc->sc_statep_net.s = NULL; + nlen = sizeof(struct pfsync_subheader) + pfsync_qs[q].len; } - return pfsync_sendout_mbuf(sc, m); + sc->sc_len += nlen; + TAILQ_INSERT_TAIL(&sc->sc_qs[q], st, sync_list); + st->sync_state = q; } -#ifdef PFSYNC_TDB -int -pfsync_tdb_sendout(struct pfsync_softc *sc) +void +pfsync_q_del(struct pf_state *st) { -#if NBPFILTER > 0 #ifdef __FreeBSD__ - struct ifnet *ifp = sc->sc_ifp; + struct pfsync_softc *sc = V_pfsyncif; #else - struct ifnet *ifp = &sc->sc_if; -#endif + struct pfsync_softc *sc = pfsyncif; #endif - struct mbuf *m; + int q = st->sync_state; #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + KASSERT(st->sync_state != PFSYNC_S_NONE, + ("%s: st->sync_state != PFSYNC_S_NONE", __FUNCTION__)); +#else + KASSERT(st->sync_state != PFSYNC_S_NONE); #endif - timeout_del(&sc->sc_tdb_tmo); - if (sc->sc_mbuf_tdb == NULL) - return (0); - m = sc->sc_mbuf_tdb; - sc->sc_mbuf_tdb = NULL; - sc->sc_statep_tdb.t = NULL; + sc->sc_len -= pfsync_qs[q].len; + TAILQ_REMOVE(&sc->sc_qs[q], st, sync_list); + st->sync_state = PFSYNC_S_NONE; -#if NBPFILTER > 0 - if (ifp->if_bpf) + if (TAILQ_EMPTY(&sc->sc_qs[q])) + sc->sc_len -= sizeof(struct pfsync_subheader); +} + +#ifdef notyet +void +pfsync_update_tdb(struct tdb *t, int output) +{ #ifdef __FreeBSD__ - BPF_MTAP(ifp, m); + struct pfsync_softc *sc = V_pfsyncif; #else - bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); -#endif + struct pfsync_softc *sc = pfsyncif; #endif + size_t nlen = sizeof(struct pfsync_tdb); + int s; + + if (sc == NULL) + return; + + if (!ISSET(t->tdb_flags, TDBF_PFSYNC)) { + if (TAILQ_EMPTY(&sc->sc_tdb_q)) + nlen += sizeof(struct pfsync_subheader); - return pfsync_sendout_mbuf(sc, m); + if (sc->sc_len + nlen > sc->sc_if.if_mtu) { + s = splnet(); + pfsync_sendout(); + splx(s); + + nlen = sizeof(struct pfsync_subheader) + + sizeof(struct pfsync_tdb); + } + + sc->sc_len += nlen; + TAILQ_INSERT_TAIL(&sc->sc_tdb_q, t, tdb_sync_entry); + SET(t->tdb_flags, TDBF_PFSYNC); + t->tdb_updates = 0; + } else { + if (++t->tdb_updates >= sc->sc_maxupdates) + schednetisr(NETISR_PFSYNC); + } + + if (output) + SET(t->tdb_flags, TDBF_PFSYNC_RPL); + else + CLR(t->tdb_flags, TDBF_PFSYNC_RPL); } + +void +pfsync_delete_tdb(struct tdb *t) +{ +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif + if (sc == NULL || !ISSET(t->tdb_flags, TDBF_PFSYNC)) + return; + + sc->sc_len -= sizeof(struct pfsync_tdb); + TAILQ_REMOVE(&sc->sc_tdb_q, t, tdb_sync_entry); + CLR(t->tdb_flags, TDBF_PFSYNC); + + if (TAILQ_EMPTY(&sc->sc_tdb_q)) + sc->sc_len -= sizeof(struct pfsync_subheader); +} + int -pfsync_sendout_mbuf(struct pfsync_softc *sc, struct mbuf *m) +pfsync_out_tdb(struct tdb *t, struct mbuf *m, int offset) { - struct sockaddr sa; - struct ip *ip; + struct pfsync_tdb *ut = (struct pfsync_tdb *)(m->m_data + offset); + + bzero(ut, sizeof(*ut)); + ut->spi = t->tdb_spi; + bcopy(&t->tdb_dst, &ut->dst, sizeof(ut->dst)); + /* + * When a failover happens, the master's rpl is probably above + * what we see here (we may be up to a second late), so + * increase it a bit for outbound tdbs to manage most such + * situations. + * + * For now, just add an offset that is likely to be larger + * than the number of packets we can see in one second. The RFC + * just says the next packet must have a higher seq value. + * + * XXX What is a good algorithm for this? We could use + * a rate-determined increase, but to know it, we would have + * to extend struct tdb. + * XXX pt->rpl can wrap over MAXINT, but if so the real tdb + * will soon be replaced anyway. For now, just don't handle + * this edge case. + */ +#define RPL_INCR 16384 + ut->rpl = htonl(t->tdb_rpl + (ISSET(t->tdb_flags, TDBF_PFSYNC_RPL) ? + RPL_INCR : 0)); + ut->cur_bytes = htobe64(t->tdb_cur_bytes); + ut->sproto = t->tdb_sproto; + return (sizeof(*ut)); +} +#endif + +void +pfsync_bulk_start(void) +{ #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; #endif - if (sc->sc_sync_ifp || + + sc->sc_ureq_received = time_uptime; + + if (sc->sc_bulk_next == NULL) #ifdef __FreeBSD__ - sc->sc_sync_peer.s_addr != htonl(INADDR_PFSYNC_GROUP)) { + sc->sc_bulk_next = TAILQ_FIRST(&V_state_list); #else - sc->sc_sync_peer.s_addr != INADDR_PFSYNC_GROUP) { + sc->sc_bulk_next = TAILQ_FIRST(&state_list); #endif - M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); - if (m == NULL) { - pfsyncstats.pfsyncs_onomem++; - return (0); + sc->sc_bulk_last = sc->sc_bulk_next; + +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) +#endif + printf("pfsync: received bulk update request\n"); + + pfsync_bulk_status(PFSYNC_BUS_START); + pfsync_bulk_update(sc); +} + +void +pfsync_bulk_update(void *arg) +{ + struct pfsync_softc *sc = arg; + struct pf_state *st = sc->sc_bulk_next; + int i = 0; + int s; + + s = splsoftnet(); +#ifdef __FreeBSD__ + CURVNET_SET(sc->sc_ifp->if_vnet); + PF_LOCK(); +#endif + do { + if (st->sync_state == PFSYNC_S_NONE && + st->timeout < PFTM_MAX && + st->pfsync_time <= sc->sc_ureq_received) { + pfsync_update_state_req(st); + i++; } - ip = mtod(m, struct ip *); - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_tos = IPTOS_LOWDELAY; + + st = TAILQ_NEXT(st, entry_list); + if (st == NULL) #ifdef __FreeBSD__ - ip->ip_len = m->m_pkthdr.len; + st = TAILQ_FIRST(&V_state_list); #else - ip->ip_len = htons(m->m_pkthdr.len); + st = TAILQ_FIRST(&state_list); #endif - ip->ip_id = htons(ip_randomid()); + + if (i > 0 && TAILQ_EMPTY(&sc->sc_qs[PFSYNC_S_UPD])) { + sc->sc_bulk_next = st; #ifdef __FreeBSD__ - ip->ip_off = IP_DF; + callout_reset(&sc->sc_bulk_tmo, 1, + pfsync_bulk_fail, sc); #else - ip->ip_off = htons(IP_DF); + timeout_add(&sc->sc_bulk_tmo, 1); #endif - ip->ip_ttl = PFSYNC_DFLTTL; - ip->ip_p = IPPROTO_PFSYNC; - ip->ip_sum = 0; + goto out; + } + } while (st != sc->sc_bulk_last); - bzero(&sa, sizeof(sa)); - ip->ip_src.s_addr = INADDR_ANY; + /* we're done */ + sc->sc_bulk_next = NULL; + sc->sc_bulk_last = NULL; + pfsync_bulk_status(PFSYNC_BUS_END); +out: #ifdef __FreeBSD__ - if (sc->sc_sendaddr.s_addr == htonl(INADDR_PFSYNC_GROUP)) + PF_UNLOCK(); + CURVNET_RESTORE(); +#endif + splx(s); +} + +void +pfsync_bulk_status(u_int8_t status) +{ + struct { + struct pfsync_subheader subh; + struct pfsync_bus bus; + } __packed r; + +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; #else - if (sc->sc_sendaddr.s_addr == INADDR_PFSYNC_GROUP) + struct pfsync_softc *sc = pfsyncif; #endif - m->m_flags |= M_MCAST; - ip->ip_dst = sc->sc_sendaddr; - sc->sc_sendaddr.s_addr = sc->sc_sync_peer.s_addr; - pfsyncstats.pfsyncs_opackets++; + bzero(&r, sizeof(r)); + + r.subh.action = PFSYNC_ACT_BUS; + r.subh.count = htons(1); #ifdef __FreeBSD__ - if (!IF_HANDOFF(&sc->sc_ifq, m, NULL)) - pfsyncstats.pfsyncs_oerrors++; - taskqueue_enqueue(taskqueue_thread, &pfsyncif->sc_send_task); + r.bus.creatorid = V_pf_status.hostid; #else - if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) - pfsyncstats.pfsyncs_oerrors++; + r.bus.creatorid = pf_status.hostid; #endif - } else - m_freem(m); + r.bus.endtime = htonl(time_uptime - sc->sc_ureq_received); + r.bus.status = status; - return (0); + pfsync_send_plus(&r, sizeof(r)); } -#ifdef PFSYNC_TDB -/* Update an in-kernel tdb. Silently fail if no tdb is found. */ void -pfsync_update_net_tdb(struct pfsync_tdb *pt) +pfsync_bulk_fail(void *arg) { - struct tdb *tdb; - int s; + struct pfsync_softc *sc = arg; - /* check for invalid values */ - if (ntohl(pt->spi) <= SPI_RESERVED_MAX || - (pt->dst.sa.sa_family != AF_INET && - pt->dst.sa.sa_family != AF_INET6)) - goto bad; +#ifdef __FreeBSD__ + CURVNET_SET(sc->sc_ifp->if_vnet); +#endif - s = spltdb(); - tdb = gettdb(pt->spi, &pt->dst, pt->sproto); - if (tdb) { - pt->rpl = ntohl(pt->rpl); - pt->cur_bytes = betoh64(pt->cur_bytes); + if (sc->sc_bulk_tries++ < PFSYNC_MAX_BULKTRIES) { + /* Try again */ +#ifdef __FreeBSD__ + callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, + pfsync_bulk_fail, V_pfsyncif); +#else + timeout_add_sec(&sc->sc_bulkfail_tmo, 5); +#endif + pfsync_request_update(0, 0); + } else { + /* Pretend like the transfer was ok */ + sc->sc_ureq_sent = 0; + sc->sc_bulk_tries = 0; +#if NCARP > 0 +#ifdef notyet +#ifdef __FreeBSD__ + if (!sc->pfsync_sync_ok) +#else + if (!pfsync_sync_ok) +#endif + carp_group_demote_adj(&sc->sc_if, -1); +#endif +#endif +#ifdef __FreeBSD__ + sc->pfsync_sync_ok = 1; +#else + pfsync_sync_ok = 1; +#endif +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else + if (pf_status.debug >= PF_DEBUG_MISC) +#endif + printf("pfsync: failed to receive bulk update\n"); + } - /* Neither replay nor byte counter should ever decrease. */ - if (pt->rpl < tdb->tdb_rpl || - pt->cur_bytes < tdb->tdb_cur_bytes) { - splx(s); - goto bad; - } +#ifdef __FreeBSD__ + CURVNET_RESTORE(); +#endif +} - tdb->tdb_rpl = pt->rpl; - tdb->tdb_cur_bytes = pt->cur_bytes; +void +pfsync_send_plus(void *plus, size_t pluslen) +{ +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else + struct pfsync_softc *sc = pfsyncif; +#endif + int s; + +#ifdef __FreeBSD__ + if (sc->sc_len + pluslen > sc->sc_ifp->if_mtu) { +#else + if (sc->sc_len + pluslen > sc->sc_if.if_mtu) { +#endif + s = splnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + pfsync_sendout(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + splx(s); } - splx(s); - return; - bad: - if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert: PFSYNC_ACT_TDB_UPD: " - "invalid value\n"); - pfsyncstats.pfsyncs_badstate++; - return; + sc->sc_plus = plus; + sc->sc_len += (sc->sc_pluslen = pluslen); + + s = splnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + pfsync_sendout(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + splx(s); } -/* One of our local tdbs have been updated, need to sync rpl with others */ int -pfsync_update_tdb(struct tdb *tdb, int output) +pfsync_up(void) { - struct ifnet *ifp = NULL; +#ifdef __FreeBSD__ + struct pfsync_softc *sc = V_pfsyncif; +#else struct pfsync_softc *sc = pfsyncif; - struct pfsync_header *h; - struct pfsync_tdb *pt = NULL; - int s, i, ret; - - if (sc == NULL) - return (0); +#endif #ifdef __FreeBSD__ - ifp = sc->sc_ifp; + if (sc == NULL || !ISSET(sc->sc_ifp->if_flags, IFF_DRV_RUNNING)) #else - ifp = &sc->sc_if; + if (sc == NULL || !ISSET(sc->sc_if.if_flags, IFF_RUNNING)) #endif - if (ifp->if_bpf == NULL && sc->sc_sync_ifp == NULL && + return (0); + + return (1); +} + +int +pfsync_state_in_use(struct pf_state *st) +{ #ifdef __FreeBSD__ - sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { + struct pfsync_softc *sc = V_pfsyncif; #else - sc->sc_sync_peer.s_addr == INADDR_PFSYNC_GROUP) { + struct pfsync_softc *sc = pfsyncif; #endif - /* Don't leave any stale pfsync packets hanging around. */ - if (sc->sc_mbuf_tdb != NULL) { - m_freem(sc->sc_mbuf_tdb); - sc->sc_mbuf_tdb = NULL; - sc->sc_statep_tdb.t = NULL; - } + + if (sc == NULL) return (0); - } + + if (st->sync_state != PFSYNC_S_NONE) + return (1); + + if (sc->sc_bulk_next == NULL && sc->sc_bulk_last == NULL) + return (0); + + return (1); +} + +u_int pfsync_ints; +u_int pfsync_tmos; + +void +pfsync_timeout(void *arg) +{ +#if defined(__FreeBSD__) && defined(VIMAGE) + struct pfsync_softc *sc = arg; +#endif + int s; #ifdef __FreeBSD__ - PF_ASSERT(MA_OWNED); + CURVNET_SET(sc->sc_ifp->if_vnet); #endif + + pfsync_tmos++; + s = splnet(); - if (sc->sc_mbuf_tdb == NULL) { - if ((sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, PFSYNC_ACT_TDB_UPD, - (void *)&sc->sc_statep_tdb.t)) == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - } else { - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - if (h->action != PFSYNC_ACT_TDB_UPD) { - /* - * XXX will never happen as long as there's - * only one "TDB action". - */ - pfsync_tdb_sendout(sc); - sc->sc_mbuf_tdb = pfsync_get_mbuf(sc, - PFSYNC_ACT_TDB_UPD, (void *)&sc->sc_statep_tdb.t); - if (sc->sc_mbuf_tdb == NULL) { - splx(s); - return (ENOMEM); - } - h = mtod(sc->sc_mbuf_tdb, struct pfsync_header *); - } else if (sc->sc_maxupdates) { - /* - * If it's an update, look in the packet to see if - * we already have an update for the state. - */ - struct pfsync_tdb *u = - (void *)((char *)h + PFSYNC_HDRLEN); - - for (i = 0; !pt && i < h->count; i++) { - if (tdb->tdb_spi == u->spi && - tdb->tdb_sproto == u->sproto && - !bcmp(&tdb->tdb_dst, &u->dst, - SA_LEN(&u->dst.sa))) { - pt = u; - pt->updates++; - } - u++; - } - } - } +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + pfsync_sendout(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif + splx(s); - if (pt == NULL) { - /* not a "duplicate" update */ - pt = sc->sc_statep_tdb.t++; - sc->sc_mbuf_tdb->m_pkthdr.len = - sc->sc_mbuf_tdb->m_len += sizeof(struct pfsync_tdb); - h->count++; - bzero(pt, sizeof(*pt)); +#ifdef __FreeBSD__ + CURVNET_RESTORE(); +#endif +} - pt->spi = tdb->tdb_spi; - memcpy(&pt->dst, &tdb->tdb_dst, sizeof pt->dst); - pt->sproto = tdb->tdb_sproto; - } +/* this is a softnet/netisr handler */ +void +#ifdef __FreeBSD__ +pfsyncintr(void *arg) +#else +pfsyncintr(void) +#endif +{ +#ifdef __FreeBSD__ + struct pfsync_softc *sc = arg; +#endif + int s; - /* - * When a failover happens, the master's rpl is probably above - * what we see here (we may be up to a second late), so - * increase it a bit for outbound tdbs to manage most such - * situations. - * - * For now, just add an offset that is likely to be larger - * than the number of packets we can see in one second. The RFC - * just says the next packet must have a higher seq value. - * - * XXX What is a good algorithm for this? We could use - * a rate-determined increase, but to know it, we would have - * to extend struct tdb. - * XXX pt->rpl can wrap over MAXINT, but if so the real tdb - * will soon be replaced anyway. For now, just don't handle - * this edge case. - */ -#define RPL_INCR 16384 - pt->rpl = htonl(tdb->tdb_rpl + (output ? RPL_INCR : 0)); - pt->cur_bytes = htobe64(tdb->tdb_cur_bytes); +#ifdef __FreeBSD__ + if (sc == NULL) + return; - if (h->count == sc->sc_maxcount || - (sc->sc_maxupdates && (pt->updates >= sc->sc_maxupdates))) - ret = pfsync_tdb_sendout(sc); + CURVNET_SET(sc->sc_ifp->if_vnet); +#endif + pfsync_ints++; + s = splnet(); +#ifdef __FreeBSD__ + PF_LOCK(); +#endif + pfsync_sendout(); +#ifdef __FreeBSD__ + PF_UNLOCK(); +#endif splx(s); - return (ret); + +#ifdef __FreeBSD__ + CURVNET_RESTORE(); +#endif +} + +int +pfsync_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, + size_t newlen) +{ + +#ifdef notyet + /* All sysctl names at this level are terminal. */ + if (namelen != 1) + return (ENOTDIR); + + switch (name[0]) { + case PFSYNCCTL_STATS: + if (newp != NULL) + return (EPERM); + return (sysctl_struct(oldp, oldlenp, newp, newlen, + &V_pfsyncstats, sizeof(V_pfsyncstats))); + } +#endif + return (ENOPROTOOPT); } -#endif /* PFSYNC_TDB */ #ifdef __FreeBSD__ void @@ -2243,18 +3305,15 @@ pfsync_ifdetach(void *arg, struct ifnet *ifp) struct pfsync_softc *sc = (struct pfsync_softc *)arg; struct ip_moptions *imo; - if (sc == NULL || sc->sc_sync_ifp != ifp) + if (sc == NULL || sc->sc_sync_if != ifp) return; /* not for us; unlocked read */ + CURVNET_SET(sc->sc_ifp->if_vnet); + PF_LOCK(); /* Deal with a member interface going away from under us. */ - sc->sc_sync_ifp = NULL; - if (sc->sc_mbuf_net != NULL) { - m_freem(sc->sc_mbuf_net); - sc->sc_mbuf_net = NULL; - sc->sc_statep_net.s = NULL; - } + sc->sc_sync_if = NULL; imo = &sc->sc_imo; if (imo->imo_num_memberships > 0) { KASSERT(imo->imo_num_memberships == 1, @@ -2272,29 +3331,73 @@ pfsync_ifdetach(void *arg, struct ifnet *ifp) } PF_UNLOCK(); + + CURVNET_RESTORE(); } -void -pfsync_senddef(void *arg, __unused int pending) +static int +vnet_pfsync_init(const void *unused) { - struct pfsync_softc *sc = (struct pfsync_softc *)arg; - struct mbuf *m; + int error = 0; - for(;;) { - IF_DEQUEUE(&sc->sc_ifq, m); - if (m == NULL) - break; - /* Deal with a member interface going away from under us. */ - if (sc->sc_sync_ifp == NULL) { - pfsyncstats.pfsyncs_oerrors++; - m_freem(m); - continue; - } - if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL)) - pfsyncstats.pfsyncs_oerrors++; - } + pfsyncattach(0); + + error = swi_add(NULL, "pfsync", pfsyncintr, V_pfsyncif, + SWI_NET, INTR_MPSAFE, &pfsync_swi.pfsync_swi_cookie); + if (error) + panic("%s: swi_add %d", __func__, error); + + pfsync_state_import_ptr = pfsync_state_import; + pfsync_up_ptr = pfsync_up; + pfsync_insert_state_ptr = pfsync_insert_state; + pfsync_update_state_ptr = pfsync_update_state; + pfsync_delete_state_ptr = pfsync_delete_state; + pfsync_clear_states_ptr = pfsync_clear_states; + pfsync_state_in_use_ptr = pfsync_state_in_use; + pfsync_defer_ptr = pfsync_defer; + + return (0); +} + +static int +vnet_pfsync_uninit(const void *unused) +{ + + swi_remove(pfsync_swi.pfsync_swi_cookie); + + pfsync_state_import_ptr = NULL; + pfsync_up_ptr = NULL; + pfsync_insert_state_ptr = NULL; + pfsync_update_state_ptr = NULL; + pfsync_delete_state_ptr = NULL; + pfsync_clear_states_ptr = NULL; + pfsync_state_in_use_ptr = NULL; + pfsync_defer_ptr = NULL; + + if_clone_detach(&pfsync_cloner); + + return (0); } +/* Define startup order. */ +#define PFSYNC_SYSINIT_ORDER SI_SUB_PROTO_BEGIN +#define PFSYNC_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ +#define PFSYNC_VNET_ORDER (PFSYNC_MODEVENT_ORDER + 2) /* Later still. */ + +/* + * Starting up. + * VNET_SYSINIT is called for each existing vnet and each new vnet. + */ +VNET_SYSINIT(vnet_pfsync_init, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, + vnet_pfsync_init, NULL); + +/* + * Closing up shop. These are done in REVERSE ORDER, + * Not called on reboot. + * VNET_SYSUNINIT is called for each exiting vnet as it exits. + */ +VNET_SYSUNINIT(vnet_pfsync_uninit, PFSYNC_SYSINIT_ORDER, PFSYNC_VNET_ORDER, + vnet_pfsync_uninit, NULL); static int pfsync_modevent(module_t mod, int type, void *data) { @@ -2302,10 +3405,14 @@ pfsync_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: +#ifndef __FreeBSD__ pfsyncattach(0); +#endif break; case MOD_UNLOAD: +#ifndef __FreeBSD__ if_clone_detach(&pfsync_cloner); +#endif break; default: error = EINVAL; @@ -2325,5 +3432,5 @@ static moduledata_t pfsync_mod = { DECLARE_MODULE(pfsync, pfsync_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); MODULE_VERSION(pfsync, PFSYNC_MODVER); -MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); +MODULE_DEPEND(pfsync, pf, PF_MODVER, PF_MODVER, PF_MODVER); #endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/if_pfsync.h b/sys/contrib/pf/net/if_pfsync.h index f306610..17259b7 100644 --- a/sys/contrib/pf/net/if_pfsync.h +++ b/sys/contrib/pf/net/if_pfsync.h @@ -1,5 +1,4 @@ -/* $FreeBSD$ */ -/* $OpenBSD: if_pfsync.h,v 1.30 2006/10/31 14:49:01 henning Exp $ */ +/* $OpenBSD: if_pfsync.h,v 1.35 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2001 Michael Shalayeff @@ -27,227 +26,217 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * Copyright (c) 2008 David Gwynne <dlg@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + #ifndef _NET_IF_PFSYNC_H_ -#define _NET_IF_PFSYNC_H_ +#define _NET_IF_PFSYNC_H_ +#define PFSYNC_VERSION 5 +#define PFSYNC_DFLTTL 255 -#define PFSYNC_ID_LEN sizeof(u_int64_t) +#define PFSYNC_ACT_CLR 0 /* clear all states */ +#define PFSYNC_ACT_INS 1 /* insert state */ +#define PFSYNC_ACT_INS_ACK 2 /* ack of insterted state */ +#define PFSYNC_ACT_UPD 3 /* update state */ +#define PFSYNC_ACT_UPD_C 4 /* "compressed" update state */ +#define PFSYNC_ACT_UPD_REQ 5 /* request "uncompressed" state */ +#define PFSYNC_ACT_DEL 6 /* delete state */ +#define PFSYNC_ACT_DEL_C 7 /* "compressed" delete state */ +#define PFSYNC_ACT_INS_F 8 /* insert fragment */ +#define PFSYNC_ACT_DEL_F 9 /* delete fragments */ +#define PFSYNC_ACT_BUS 10 /* bulk update status */ +#define PFSYNC_ACT_TDB 11 /* TDB replay counter update */ +#define PFSYNC_ACT_EOF 12 /* end of frame */ +#define PFSYNC_ACT_MAX 13 + +#define PFSYNC_ACTIONS "CLR ST", \ + "INS ST", \ + "INS ST ACK", \ + "UPD ST", \ + "UPD ST COMP", \ + "UPD ST REQ", \ + "DEL ST", \ + "DEL ST COMP", \ + "INS FR", \ + "DEL FR", \ + "BULK UPD STAT", \ + "TDB UPD", \ + "EOF" + +#define PFSYNC_HMAC_LEN 20 -struct pfsync_state_scrub { - u_int16_t pfss_flags; - u_int8_t pfss_ttl; /* stashed TTL */ -#define PFSYNC_SCRUB_FLAG_VALID 0x01 - u_int8_t scrub_flag; - u_int32_t pfss_ts_mod; /* timestamp modulation */ -} __packed; +/* + * A pfsync frame is built from a header followed by several sections which + * are all prefixed with their own subheaders. Frames must be terminated with + * an EOF subheader. + * + * | ... | + * | IP header | + * +============================+ + * | pfsync_header | + * +----------------------------+ + * | pfsync_subheader | + * +----------------------------+ + * | first action fields | + * | ... | + * +----------------------------+ + * | pfsync_subheader | + * +----------------------------+ + * | second action fields | + * | ... | + * +----------------------------+ + * | EOF pfsync_subheader | + * +----------------------------+ + * | HMAC | + * +============================+ + */ -struct pfsync_state_host { - struct pf_addr addr; - u_int16_t port; - u_int16_t pad[3]; +/* + * Frame header + */ + +struct pfsync_header { + u_int8_t version; + u_int8_t _pad; + u_int16_t len; + u_int8_t pfcksum[PF_MD5_DIGEST_LENGTH]; } __packed; -struct pfsync_state_peer { - struct pfsync_state_scrub scrub; /* state is scrubbed */ - u_int32_t seqlo; /* Max sequence number sent */ - u_int32_t seqhi; /* Max the other end ACKd + win */ - u_int32_t seqdiff; /* Sequence number modulator */ - u_int16_t max_win; /* largest window (pre scaling) */ - u_int16_t mss; /* Maximum segment size option */ - u_int8_t state; /* active state level */ - u_int8_t wscale; /* window scaling factor */ - u_int8_t pad[6]; +/* + * Frame region subheader + */ + +struct pfsync_subheader { + u_int8_t action; + u_int8_t _pad; + u_int16_t count; } __packed; -struct pfsync_state { - u_int32_t id[2]; - char ifname[IFNAMSIZ]; - struct pfsync_state_host lan; - struct pfsync_state_host gwy; - struct pfsync_state_host ext; - struct pfsync_state_peer src; - struct pfsync_state_peer dst; - struct pf_addr rt_addr; - u_int32_t rule; - u_int32_t anchor; - u_int32_t nat_rule; - u_int32_t creation; - u_int32_t expire; - u_int32_t packets[2][2]; - u_int32_t bytes[2][2]; - u_int32_t creatorid; - sa_family_t af; - u_int8_t proto; - u_int8_t direction; - u_int8_t log; - u_int8_t state_flags; - u_int8_t timeout; - u_int8_t sync_flags; - u_int8_t updates; +/* + * CLR + */ + +struct pfsync_clr { + char ifname[IFNAMSIZ]; + u_int32_t creatorid; } __packed; -#define PFSYNC_FLAG_COMPRESS 0x01 -#define PFSYNC_FLAG_STALE 0x02 +/* + * INS, UPD, DEL + */ + +/* these use struct pfsync_state in pfvar.h */ -#ifdef PFSYNC_TDB -struct pfsync_tdb { - u_int32_t spi; - union sockaddr_union dst; - u_int32_t rpl; - u_int64_t cur_bytes; - u_int8_t sproto; - u_int8_t updates; - u_int8_t pad[2]; +/* + * INS_ACK + */ + +struct pfsync_ins_ack { + u_int64_t id; + u_int32_t creatorid; } __packed; -#endif -struct pfsync_state_upd { - u_int32_t id[2]; +/* + * UPD_C + */ + +struct pfsync_upd_c { + u_int64_t id; struct pfsync_state_peer src; struct pfsync_state_peer dst; - u_int32_t creatorid; - u_int32_t expire; - u_int8_t timeout; - u_int8_t updates; - u_int8_t pad[6]; + u_int32_t creatorid; + u_int32_t expire; + u_int8_t timeout; + u_int8_t _pad[3]; } __packed; -struct pfsync_state_del { - u_int32_t id[2]; - u_int32_t creatorid; - struct { - u_int8_t state; - } src; - struct { - u_int8_t state; - } dst; - u_int8_t pad[2]; -} __packed; +/* + * UPD_REQ + */ -struct pfsync_state_upd_req { - u_int32_t id[2]; - u_int32_t creatorid; - u_int32_t pad; +struct pfsync_upd_req { + u_int64_t id; + u_int32_t creatorid; } __packed; -struct pfsync_state_clr { - char ifname[IFNAMSIZ]; - u_int32_t creatorid; - u_int32_t pad; -} __packed; +/* + * DEL_C + */ -struct pfsync_state_bus { - u_int32_t creatorid; - u_int32_t endtime; - u_int8_t status; -#define PFSYNC_BUS_START 1 -#define PFSYNC_BUS_END 2 - u_int8_t pad[7]; +struct pfsync_del_c { + u_int64_t id; + u_int32_t creatorid; } __packed; -#ifdef _KERNEL - -union sc_statep { - struct pfsync_state *s; - struct pfsync_state_upd *u; - struct pfsync_state_del *d; - struct pfsync_state_clr *c; - struct pfsync_state_bus *b; - struct pfsync_state_upd_req *r; -}; +/* + * INS_F, DEL_F + */ -#ifdef PFSYNC_TDB -union sc_tdb_statep { - struct pfsync_tdb *t; -}; -#endif +/* not implemented (yet) */ -extern int pfsync_sync_ok; +/* + * BUS + */ -struct pfsync_softc { -#ifdef __FreeBSD__ - struct ifnet *sc_ifp; -#else - struct ifnet sc_if; -#endif - struct ifnet *sc_sync_ifp; +struct pfsync_bus { + u_int32_t creatorid; + u_int32_t endtime; + u_int8_t status; +#define PFSYNC_BUS_START 1 +#define PFSYNC_BUS_END 2 + u_int8_t _pad[3]; +} __packed; - struct ip_moptions sc_imo; -#ifdef __FreeBSD__ - struct callout sc_tmo; -#ifdef PFSYNC_TDB - struct callout sc_tdb_tmo; -#endif - struct callout sc_bulk_tmo; - struct callout sc_bulkfail_tmo; -#else - struct timeout sc_tmo; - struct timeout sc_tdb_tmo; - struct timeout sc_bulk_tmo; - struct timeout sc_bulkfail_tmo; -#endif - struct in_addr sc_sync_peer; - struct in_addr sc_sendaddr; - struct mbuf *sc_mbuf; /* current cumulative mbuf */ - struct mbuf *sc_mbuf_net; /* current cumulative mbuf */ -#ifdef PFSYNC_TDB - struct mbuf *sc_mbuf_tdb; /* dito for TDB updates */ -#endif -#ifdef __FreeBSD__ - struct ifqueue sc_ifq; - struct task sc_send_task; -#endif - union sc_statep sc_statep; - union sc_statep sc_statep_net; -#ifdef PFSYNC_TDB - union sc_tdb_statep sc_statep_tdb; -#endif - u_int32_t sc_ureq_received; - u_int32_t sc_ureq_sent; - struct pf_state *sc_bulk_send_next; - struct pf_state *sc_bulk_terminator; - int sc_bulk_tries; - int sc_maxcount; /* number of states in mtu */ - int sc_maxupdates; /* number of updates/state */ -#ifdef __FreeBSD__ - eventhandler_tag sc_detachtag; -#endif -}; +/* + * TDB + */ -extern struct pfsync_softc *pfsyncif; -#endif +struct pfsync_tdb { + u_int32_t spi; + union sockaddr_union dst; + u_int32_t rpl; + u_int64_t cur_bytes; + u_int8_t sproto; + u_int8_t updates; + u_int8_t _pad[2]; +} __packed; +/* + * EOF + */ -struct pfsync_header { - u_int8_t version; -#define PFSYNC_VERSION 3 - u_int8_t af; - u_int8_t action; -#define PFSYNC_ACT_CLR 0 /* clear all states */ -#define PFSYNC_ACT_INS 1 /* insert state */ -#define PFSYNC_ACT_UPD 2 /* update state */ -#define PFSYNC_ACT_DEL 3 /* delete state */ -#define PFSYNC_ACT_UPD_C 4 /* "compressed" state update */ -#define PFSYNC_ACT_DEL_C 5 /* "compressed" state delete */ -#define PFSYNC_ACT_INS_F 6 /* insert fragment */ -#define PFSYNC_ACT_DEL_F 7 /* delete fragments */ -#define PFSYNC_ACT_UREQ 8 /* request "uncompressed" state */ -#define PFSYNC_ACT_BUS 9 /* Bulk Update Status */ -#define PFSYNC_ACT_TDB_UPD 10 /* TDB replay counter update */ -#define PFSYNC_ACT_MAX 11 - u_int8_t count; - u_int8_t pf_chksum[PF_MD5_DIGEST_LENGTH]; +struct pfsync_eof { + u_int8_t hmac[PFSYNC_HMAC_LEN]; } __packed; -#define PFSYNC_BULKPACKETS 1 /* # of packets per timeout */ -#define PFSYNC_MAX_BULKTRIES 12 -#define PFSYNC_HDRLEN sizeof(struct pfsync_header) -#define PFSYNC_ACTIONS \ - "CLR ST", "INS ST", "UPD ST", "DEL ST", \ - "UPD ST COMP", "DEL ST COMP", "INS FR", "DEL FR", \ - "UPD REQ", "BLK UPD STAT", "TDB UPD" +#define PFSYNC_HDRLEN sizeof(struct pfsync_header) + -#define PFSYNC_DFLTTL 255 + +/* + * Names for PFSYNC sysctl objects + */ +#define PFSYNCCTL_STATS 1 /* PFSYNC stats */ +#define PFSYNCCTL_MAXID 2 + +#define PFSYNCCTL_NAMES { \ + { 0, 0 }, \ + { "stats", CTLTYPE_STRUCT }, \ +} struct pfsyncstats { u_int64_t pfsyncs_ipackets; /* total input packets, IPv4 */ @@ -280,96 +269,56 @@ struct pfsyncreq { }; #ifdef __FreeBSD__ -#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) -#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq) +#define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) +#define SIOCGETPFSYNC _IOWR('i', 248, struct ifreq) #endif -#define pf_state_peer_hton(s,d) do { \ - (d)->seqlo = htonl((s)->seqlo); \ - (d)->seqhi = htonl((s)->seqhi); \ - (d)->seqdiff = htonl((s)->seqdiff); \ - (d)->max_win = htons((s)->max_win); \ - (d)->mss = htons((s)->mss); \ - (d)->state = (s)->state; \ - (d)->wscale = (s)->wscale; \ - if ((s)->scrub) { \ - (d)->scrub.pfss_flags = \ - htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \ - (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \ - (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\ - (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \ - } \ -} while (0) - -#define pf_state_peer_ntoh(s,d) do { \ - (d)->seqlo = ntohl((s)->seqlo); \ - (d)->seqhi = ntohl((s)->seqhi); \ - (d)->seqdiff = ntohl((s)->seqdiff); \ - (d)->max_win = ntohs((s)->max_win); \ - (d)->mss = ntohs((s)->mss); \ - (d)->state = (s)->state; \ - (d)->wscale = (s)->wscale; \ - if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ - (d)->scrub != NULL) { \ - (d)->scrub->pfss_flags = \ - ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \ - (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \ - (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\ - } \ -} while (0) - -#define pf_state_host_hton(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ -} while (0) - -#define pf_state_host_ntoh(s,d) do { \ - bcopy(&(s)->addr, &(d)->addr, sizeof((d)->addr)); \ - (d)->port = (s)->port; \ -} while (0) - -#define pf_state_counter_hton(s,d) do { \ - d[0] = htonl((s>>32)&0xffffffff); \ - d[1] = htonl(s&0xffffffff); \ -} while (0) - -#define pf_state_counter_ntoh(s,d) do { \ - d = ntohl(s[0]); \ - d = d<<32; \ - d += ntohl(s[1]); \ -} while (0) - #ifdef _KERNEL + +/* + * this shows where a pf state is with respect to the syncing. + */ +#define PFSYNC_S_INS 0x00 +#define PFSYNC_S_IACK 0x01 +#define PFSYNC_S_UPD 0x02 +#define PFSYNC_S_UPD_C 0x03 +#define PFSYNC_S_DEL 0x04 +#define PFSYNC_S_COUNT 0x05 + +#define PFSYNC_S_DEFER 0xfe +#define PFSYNC_S_NONE 0xff + #ifdef __FreeBSD__ -void pfsync_input(struct mbuf *, __unused int); +void pfsync_input(struct mbuf *, __unused int); #else -void pfsync_input(struct mbuf *, ...); +void pfsync_input(struct mbuf *, ...); #endif -int pfsync_clear_states(u_int32_t, char *); -int pfsync_pack_state(u_int8_t, struct pf_state *, int); -#define pfsync_insert_state(st) do { \ - if ((st->rule.ptr->rule_flag & PFRULE_NOSYNC) || \ - (st->proto == IPPROTO_PFSYNC)) \ - st->sync_flags |= PFSTATE_NOSYNC; \ - else if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_INS, (st), \ - PFSYNC_FLAG_COMPRESS); \ - st->sync_flags &= ~PFSTATE_FROMSYNC; \ -} while (0) -#define pfsync_update_state(st) do { \ - if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_UPD, (st), \ - PFSYNC_FLAG_COMPRESS); \ - st->sync_flags &= ~PFSTATE_FROMSYNC; \ -} while (0) -#define pfsync_delete_state(st) do { \ - if (!st->sync_flags) \ - pfsync_pack_state(PFSYNC_ACT_DEL, (st), \ - PFSYNC_FLAG_COMPRESS); \ -} while (0) -#ifdef PFSYNC_TDB -int pfsync_update_tdb(struct tdb *, int); +int pfsync_sysctl(int *, u_int, void *, size_t *, + void *, size_t); + +#define PFSYNC_SI_IOCTL 0x01 +#define PFSYNC_SI_CKSUM 0x02 +#define PFSYNC_SI_ACK 0x04 +int pfsync_state_import(struct pfsync_state *, u_int8_t); +#ifndef __FreeBSD__ +void pfsync_state_export(struct pfsync_state *, + struct pf_state *); #endif + +void pfsync_insert_state(struct pf_state *); +void pfsync_update_state(struct pf_state *); +void pfsync_delete_state(struct pf_state *); +void pfsync_clear_states(u_int32_t, const char *); + +#ifdef notyet +void pfsync_update_tdb(struct tdb *, int); +void pfsync_delete_tdb(struct tdb *); +#endif + +int pfsync_defer(struct pf_state *, struct mbuf *); + +int pfsync_up(void); +int pfsync_state_in_use(struct pf_state *); #endif #endif /* _NET_IF_PFSYNC_H_ */ diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c index 135d734..5efd651 100644 --- a/sys/contrib/pf/net/pf.c +++ b/sys/contrib/pf/net/pf.c @@ -1,9 +1,8 @@ -/* $OpenBSD: pf.c,v 1.527 2007/02/22 15:23:23 pyr Exp $ */ -/* add: $OpenBSD: pf.c,v 1.559 2007/09/18 18:45:59 markus Exp $ */ +/* $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier - * Copyright (c) 2002,2003 Henning Brauer + * Copyright (c) 2002 - 2008 Henning Brauer * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,10 +65,17 @@ __FBSDID("$FreeBSD$"); #define NPFSYNC 0 #endif +#ifdef DEV_PFLOW +#define NPFLOW DEV_PFLOW +#else +#define NPFLOW 0 +#endif + #else #include "bpfilter.h" #include "pflog.h" #include "pfsync.h" +#include "pflow.h" #endif #include <sys/param.h> @@ -81,8 +87,10 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/time.h> #ifdef __FreeBSD__ +#include <sys/random.h> #include <sys/sysctl.h> #include <sys/endian.h> +#define betoh64 be64toh #else #include <sys/pool.h> #endif @@ -95,11 +103,21 @@ __FBSDID("$FreeBSD$"); #include <sys/rwlock.h> #endif +#ifdef __FreeBSD__ +#include <sys/md5.h> +#else +#include <crypto/md5.h> +#endif + #include <net/if.h> #include <net/if_types.h> #include <net/bpf.h> #include <net/route.h> -#ifndef __FreeBSD__ +#ifdef __FreeBSD__ +#ifdef RADIX_MPATH +#include <net/radix_mpath.h> +#endif +#else #include <net/radix_mpath.h> #endif @@ -118,16 +136,18 @@ __FBSDID("$FreeBSD$"); #include <netinet/udp_var.h> #include <netinet/icmp_var.h> #include <netinet/if_ether.h> +#ifdef __FreeBSD__ +#include <netinet/ip_fw.h> +#include <netinet/ipfw/ip_fw_private.h> /* XXX: only for DIR_IN/DIR_OUT */ +#endif #ifndef __FreeBSD__ #include <dev/rndvar.h> #endif #include <net/pfvar.h> #include <net/if_pflog.h> - -#if NPFSYNC > 0 +#include <net/if_pflow.h> #include <net/if_pfsync.h> -#endif /* NPFSYNC > 0 */ #ifdef INET6 #include <netinet/ip6.h> @@ -147,15 +167,61 @@ __FBSDID("$FreeBSD$"); #include <security/mac/mac_framework.h> extern int ip_optcopy(struct ip *, struct ip *); -extern int debug_pfugidhack; #endif -#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x +#ifdef __FreeBSD__ +#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x +#else +#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x +#endif /* * Global variables */ +/* state tables */ +#ifdef __FreeBSD__ +VNET_DEFINE(struct pf_state_tree, pf_statetbl); + +VNET_DEFINE(struct pf_altqqueue, pf_altqs[2]); +VNET_DEFINE(struct pf_palist, pf_pabuf); +VNET_DEFINE(struct pf_altqqueue *, pf_altqs_active); +VNET_DEFINE(struct pf_altqqueue *, pf_altqs_inactive); +VNET_DEFINE(struct pf_status, pf_status); + +VNET_DEFINE(u_int32_t, ticket_altqs_active); +VNET_DEFINE(u_int32_t, ticket_altqs_inactive); +VNET_DEFINE(int, altqs_inactive_open); +VNET_DEFINE(u_int32_t, ticket_pabuf); + +VNET_DEFINE(MD5_CTX, pf_tcp_secret_ctx); +#define V_pf_tcp_secret_ctx VNET(pf_tcp_secret_ctx) +VNET_DEFINE(u_char, pf_tcp_secret[16]); +#define V_pf_tcp_secret VNET(pf_tcp_secret) +VNET_DEFINE(int, pf_tcp_secret_init); +#define V_pf_tcp_secret_init VNET(pf_tcp_secret_init) +VNET_DEFINE(int, pf_tcp_iss_off); +#define V_pf_tcp_iss_off VNET(pf_tcp_iss_off) + +struct pf_anchor_stackframe { + struct pf_ruleset *rs; + struct pf_rule *r; + struct pf_anchor_node *parent; + struct pf_anchor *child; +}; +VNET_DEFINE(struct pf_anchor_stackframe, pf_anchor_stack[64]); +#define V_pf_anchor_stack VNET(pf_anchor_stack) + +VNET_DEFINE(uma_zone_t, pf_src_tree_pl); +VNET_DEFINE(uma_zone_t, pf_rule_pl); +VNET_DEFINE(uma_zone_t, pf_pooladdr_pl); +VNET_DEFINE(uma_zone_t, pf_state_pl); +VNET_DEFINE(uma_zone_t, pf_state_key_pl); +VNET_DEFINE(uma_zone_t, pf_state_item_pl); +VNET_DEFINE(uma_zone_t, pf_altq_pl); +#else +struct pf_state_tree pf_statetbl; + struct pf_altqqueue pf_altqs[2]; struct pf_palist pf_pabuf; struct pf_altqqueue *pf_altqs_active; @@ -167,6 +233,11 @@ u_int32_t ticket_altqs_inactive; int altqs_inactive_open; u_int32_t ticket_pabuf; +MD5_CTX pf_tcp_secret_ctx; +u_char pf_tcp_secret[16]; +int pf_tcp_secret_init; +int pf_tcp_iss_off; + struct pf_anchor_stackframe { struct pf_ruleset *rs; struct pf_rule *r; @@ -174,16 +245,11 @@ struct pf_anchor_stackframe { struct pf_anchor *child; } pf_anchor_stack[64]; -#ifdef __FreeBSD__ -uma_zone_t pf_src_tree_pl, pf_rule_pl; -uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; -#else -struct pool pf_src_tree_pl, pf_rule_pl; -struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +struct pool pf_src_tree_pl, pf_rule_pl, pf_pooladdr_pl; +struct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl; +struct pool pf_altq_pl; #endif -void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); - void pf_init_threshold(struct pf_threshold *, u_int32_t, u_int32_t); void pf_add_threshold(struct pf_threshold *); @@ -212,27 +278,12 @@ void pf_send_tcp(const struct pf_rule *, sa_family_t, u_int16_t, u_int16_t, u_int32_t, u_int32_t, u_int8_t, u_int16_t, u_int16_t, u_int8_t, int, u_int16_t, struct ether_header *, struct ifnet *); -void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, +static void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t, sa_family_t, struct pf_rule *); -struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *, - int, int, struct pfi_kif *, - struct pf_addr *, u_int16_t, struct pf_addr *, - u_int16_t, int); -struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, - int, int, struct pfi_kif *, struct pf_src_node **, - struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t *); -int pf_test_tcp(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, - void *, struct pf_pdesc *, struct pf_rule **, -#ifdef __FreeBSD__ - struct pf_ruleset **, struct ifqueue *, - struct inpcb *); -#else - struct pf_ruleset **, struct ifqueue *); -#endif -int pf_test_udp(struct pf_rule **, struct pf_state **, +void pf_detach_state(struct pf_state *); +void pf_state_key_detach(struct pf_state *, int); +u_int32_t pf_tcp_iss(struct pf_pdesc *); +int pf_test_rule(struct pf_rule **, struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, struct pf_rule **, #ifdef __FreeBSD__ @@ -241,14 +292,14 @@ int pf_test_udp(struct pf_rule **, struct pf_state **, #else struct pf_ruleset **, struct ifqueue *); #endif -int pf_test_icmp(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, - void *, struct pf_pdesc *, struct pf_rule **, - struct pf_ruleset **, struct ifqueue *); -int pf_test_other(struct pf_rule **, struct pf_state **, - int, struct pfi_kif *, struct mbuf *, int, void *, - struct pf_pdesc *, struct pf_rule **, - struct pf_ruleset **, struct ifqueue *); +static __inline int pf_create_state(struct pf_rule *, struct pf_rule *, + struct pf_rule *, struct pf_pdesc *, + struct pf_src_node *, struct pf_state_key *, + struct pf_state_key *, struct pf_state_key *, + struct pf_state_key *, struct mbuf *, int, + u_int16_t, u_int16_t, int *, struct pfi_kif *, + struct pf_state **, int, u_int16_t, u_int16_t, + int); int pf_test_fragment(struct pf_rule **, int, struct pfi_kif *, struct mbuf *, void *, struct pf_pdesc *, struct pf_rule **, @@ -257,7 +308,7 @@ int pf_tcp_track_full(struct pf_state_peer *, struct pf_state_peer *, struct pf_state **, struct pfi_kif *, struct mbuf *, int, struct pf_pdesc *, u_short *, int *); -int pf_tcp_track_sloppy(struct pf_state_peer *, +int pf_tcp_track_sloppy(struct pf_state_peer *, struct pf_state_peer *, struct pf_state **, struct pf_pdesc *, u_short *); int pf_test_state_tcp(struct pf_state **, int, @@ -270,30 +321,14 @@ int pf_test_state_icmp(struct pf_state **, int, struct pfi_kif *, struct mbuf *, int, void *, struct pf_pdesc *, u_short *); int pf_test_state_other(struct pf_state **, int, - struct pfi_kif *, struct pf_pdesc *); -int pf_match_tag(struct mbuf *, struct pf_rule *, - struct pf_mtag *, int *); -int pf_step_out_of_anchor(int *, struct pf_ruleset **, - int, struct pf_rule **, struct pf_rule **, - int *); -void pf_hash(struct pf_addr *, struct pf_addr *, - struct pf_poolhashkey *, sa_family_t); -int pf_map_addr(u_int8_t, struct pf_rule *, - struct pf_addr *, struct pf_addr *, - struct pf_addr *, struct pf_src_node **); -int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, - struct pf_addr *, struct pf_addr *, u_int16_t, - struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, - struct pf_src_node **); + struct pfi_kif *, struct mbuf *, struct pf_pdesc *); void pf_route(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *, struct pf_pdesc *); void pf_route6(struct mbuf **, struct pf_rule *, int, struct ifnet *, struct pf_state *, struct pf_pdesc *); -#ifdef __FreeBSD__ -/* XXX: import */ -#else +#ifndef __FreeBSD__ int pf_socket_lookup(int, struct pf_pdesc *); #endif u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t, @@ -306,19 +341,32 @@ void pf_set_rt_ifp(struct pf_state *, struct pf_addr *); int pf_check_proto_cksum(struct mbuf *, int, int, u_int8_t, sa_family_t); +#ifndef __FreeBSD__ +struct pf_divert *pf_get_divert(struct mbuf *); +#endif +void pf_print_state_parts(struct pf_state *, + struct pf_state_key *, struct pf_state_key *); int pf_addr_wrap_neq(struct pf_addr_wrap *, struct pf_addr_wrap *); -struct pf_state *pf_find_state_recurse(struct pfi_kif *, - struct pf_state_cmp *, u_int8_t); +int pf_compare_state_keys(struct pf_state_key *, + struct pf_state_key *, struct pfi_kif *, u_int); +#ifdef __FreeBSD__ +struct pf_state *pf_find_state(struct pfi_kif *, + struct pf_state_key_cmp *, u_int, struct mbuf *, + struct pf_mtag *); +#else +struct pf_state *pf_find_state(struct pfi_kif *, + struct pf_state_key_cmp *, u_int, struct mbuf *); +#endif int pf_src_connlimit(struct pf_state **); int pf_check_congestion(struct ifqueue *); #ifdef __FreeBSD__ int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len); -extern int pf_end_threads; +VNET_DECLARE(int, pf_end_threads); -struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; +VNET_DEFINE(struct pf_pool_limit, pf_pool_limits[PF_LIMIT_MAX]); #else extern struct pool pfr_ktable_pl; extern struct pool pfr_kentry_pl; @@ -332,80 +380,101 @@ struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { }; #endif -#define STATE_LOOKUP() \ +#ifdef __FreeBSD__ +#define PPACKET_LOOPED() \ + (pd->pf_mtag->flags & PF_PACKET_LOOPED) + +#define PACKET_LOOPED() \ + (pd.pf_mtag->flags & PF_PACKET_LOOPED) + +#define STATE_LOOKUP(i, k, d, s, m, pt) \ do { \ - if (direction == PF_IN) \ - *state = pf_find_state_recurse( \ - kif, &key, PF_EXT_GWY); \ - else \ - *state = pf_find_state_recurse( \ - kif, &key, PF_LAN_EXT); \ - if (*state == NULL || (*state)->timeout == PFTM_PURGE) \ + s = pf_find_state(i, k, d, m, pt); \ + if (s == NULL || (s)->timeout == PFTM_PURGE) \ return (PF_DROP); \ - if (direction == PF_OUT && \ - (((*state)->rule.ptr->rt == PF_ROUTETO && \ - (*state)->rule.ptr->direction == PF_OUT) || \ - ((*state)->rule.ptr->rt == PF_REPLYTO && \ - (*state)->rule.ptr->direction == PF_IN)) && \ - (*state)->rt_kif != NULL && \ - (*state)->rt_kif != kif) \ + if (PPACKET_LOOPED()) \ + return (PF_PASS); \ + if (d == PF_OUT && \ + (((s)->rule.ptr->rt == PF_ROUTETO && \ + (s)->rule.ptr->direction == PF_OUT) || \ + ((s)->rule.ptr->rt == PF_REPLYTO && \ + (s)->rule.ptr->direction == PF_IN)) && \ + (s)->rt_kif != NULL && \ + (s)->rt_kif != i) \ return (PF_PASS); \ } while (0) +#else +#define STATE_LOOKUP(i, k, d, s, m) \ + do { \ + s = pf_find_state(i, k, d, m); \ + if (s == NULL || (s)->timeout == PFTM_PURGE) \ + return (PF_DROP); \ + if (d == PF_OUT && \ + (((s)->rule.ptr->rt == PF_ROUTETO && \ + (s)->rule.ptr->direction == PF_OUT) || \ + ((s)->rule.ptr->rt == PF_REPLYTO && \ + (s)->rule.ptr->direction == PF_IN)) && \ + (s)->rt_kif != NULL && \ + (s)->rt_kif != i) \ + return (PF_PASS); \ + } while (0) +#endif -#define STATE_TRANSLATE(s) \ - (s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \ - ((s)->af == AF_INET6 && \ - ((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \ - (s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \ - (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ - (s)->lan.port != (s)->gwy.port - -#define BOUND_IFACE(r, k) \ +#ifdef __FreeBSD__ +#define BOUND_IFACE(r, k) \ + ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : V_pfi_all +#else +#define BOUND_IFACE(r, k) \ ((r)->rule_flag & PFRULE_IFBOUND) ? (k) : pfi_all +#endif -#define STATE_INC_COUNTERS(s) \ +#define STATE_INC_COUNTERS(s) \ do { \ - s->rule.ptr->states++; \ - if (s->anchor.ptr != NULL) \ - s->anchor.ptr->states++; \ - if (s->nat_rule.ptr != NULL) \ - s->nat_rule.ptr->states++; \ + s->rule.ptr->states_cur++; \ + s->rule.ptr->states_tot++; \ + if (s->anchor.ptr != NULL) { \ + s->anchor.ptr->states_cur++; \ + s->anchor.ptr->states_tot++; \ + } \ + if (s->nat_rule.ptr != NULL) { \ + s->nat_rule.ptr->states_cur++; \ + s->nat_rule.ptr->states_tot++; \ + } \ } while (0) -#define STATE_DEC_COUNTERS(s) \ +#define STATE_DEC_COUNTERS(s) \ do { \ if (s->nat_rule.ptr != NULL) \ - s->nat_rule.ptr->states--; \ + s->nat_rule.ptr->states_cur--; \ if (s->anchor.ptr != NULL) \ - s->anchor.ptr->states--; \ - s->rule.ptr->states--; \ + s->anchor.ptr->states_cur--; \ + s->rule.ptr->states_cur--; \ } while (0) +static __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *); +static __inline int pf_state_compare_key(struct pf_state_key *, + struct pf_state_key *); +static __inline int pf_state_compare_id(struct pf_state *, + struct pf_state *); + +#ifdef __FreeBSD__ +VNET_DEFINE(struct pf_src_tree, tree_src_tracking); + +VNET_DEFINE(struct pf_state_tree_id, tree_id); +VNET_DEFINE(struct pf_state_queue, state_list); +#else struct pf_src_tree tree_src_tracking; struct pf_state_tree_id tree_id; struct pf_state_queue state_list; - -#ifdef __FreeBSD__ -static int pf_src_compare(struct pf_src_node *, struct pf_src_node *); -static int pf_state_compare_lan_ext(struct pf_state *, struct pf_state *); -static int pf_state_compare_ext_gwy(struct pf_state *, struct pf_state *); -static int pf_state_compare_id(struct pf_state *, struct pf_state *); #endif RB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare); -RB_GENERATE(pf_state_tree_lan_ext, pf_state, - u.s.entry_lan_ext, pf_state_compare_lan_ext); -RB_GENERATE(pf_state_tree_ext_gwy, pf_state, - u.s.entry_ext_gwy, pf_state_compare_ext_gwy); +RB_GENERATE(pf_state_tree, pf_state_key, entry, pf_state_compare_key); RB_GENERATE(pf_state_tree_id, pf_state, - u.s.entry_id, pf_state_compare_id); + entry_id, pf_state_compare_id); -#ifdef __FreeBSD__ -static int -#else static __inline int -#endif pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) { int diff; @@ -449,169 +518,6 @@ pf_src_compare(struct pf_src_node *a, struct pf_src_node *b) return (0); } -#ifdef __FreeBSD__ -static int -#else -static __inline int -#endif -pf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b) -{ - int diff; - - if ((diff = a->proto - b->proto) != 0) - return (diff); - if ((diff = a->af - b->af) != 0) - return (diff); - switch (a->af) { -#ifdef INET - case AF_INET: - if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0]) - return (1); - if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0]) - return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3]) - return (1); - if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3]) - return (-1); - if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3]) - return (1); - if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3]) - return (-1); - if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2]) - return (1); - if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2]) - return (-1); - if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2]) - return (1); - if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2]) - return (-1); - if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1]) - return (1); - if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1]) - return (-1); - if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1]) - return (1); - if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1]) - return (-1); - if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0]) - return (1); - if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0]) - return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - break; -#endif /* INET6 */ - } - - if ((diff = a->lan.port - b->lan.port) != 0) - return (diff); - if ((diff = a->ext.port - b->ext.port) != 0) - return (diff); - - return (0); -} - -#ifdef __FreeBSD__ -static int -#else -static __inline int -#endif -pf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b) -{ - int diff; - - if ((diff = a->proto - b->proto) != 0) - return (diff); - if ((diff = a->af - b->af) != 0) - return (diff); - switch (a->af) { -#ifdef INET - case AF_INET: - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0]) - return (1); - if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0]) - return (-1); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3]) - return (1); - if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3]) - return (-1); - if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3]) - return (1); - if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3]) - return (-1); - if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2]) - return (1); - if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2]) - return (-1); - if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2]) - return (1); - if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2]) - return (-1); - if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1]) - return (1); - if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1]) - return (-1); - if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1]) - return (1); - if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1]) - return (-1); - if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0]) - return (1); - if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0]) - return (-1); - if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0]) - return (1); - if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0]) - return (-1); - break; -#endif /* INET6 */ - } - - if ((diff = a->ext.port - b->ext.port) != 0) - return (diff); - if ((diff = a->gwy.port - b->gwy.port) != 0) - return (diff); - - return (0); -} - -#ifdef __FreeBSD__ -static int -#else -static __inline int -#endif -pf_state_compare_id(struct pf_state *a, struct pf_state *b) -{ - if (a->id > b->id) - return (1); - if (a->id < b->id) - return (-1); - if (a->creatorid > b->creatorid) - return (1); - if (a->creatorid < b->creatorid) - return (-1); - - return (0); -} - #ifdef INET6 void pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) @@ -632,80 +538,6 @@ pf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af) } #endif /* INET6 */ -struct pf_state * -pf_find_state_byid(struct pf_state_cmp *key) -{ - pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); -} - -struct pf_state * -pf_find_state_recurse(struct pfi_kif *kif, struct pf_state_cmp *key, u_int8_t tree) -{ - struct pf_state *s; - - pf_status.fcounters[FCNT_STATE_SEARCH]++; - - switch (tree) { - case PF_LAN_EXT: - if ((s = RB_FIND(pf_state_tree_lan_ext, &kif->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_lan_ext, &pfi_all->pfik_lan_ext, - (struct pf_state *)key)) != NULL) - return (s); - return (NULL); - case PF_EXT_GWY: - if ((s = RB_FIND(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); - if ((s = RB_FIND(pf_state_tree_ext_gwy, &pfi_all->pfik_ext_gwy, - (struct pf_state *)key)) != NULL) - return (s); - return (NULL); - default: - panic("pf_find_state_recurse"); - } -} - -struct pf_state * -pf_find_state_all(struct pf_state_cmp *key, u_int8_t tree, int *more) -{ - struct pf_state *s, *ss = NULL; - struct pfi_kif *kif; - - pf_status.fcounters[FCNT_STATE_SEARCH]++; - - switch (tree) { - case PF_LAN_EXT: - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_lan_ext, - &kif->pfik_lan_ext, (struct pf_state *)key); - if (s == NULL) - continue; - if (more == NULL) - return (s); - ss = s; - (*more)++; - } - return (ss); - case PF_EXT_GWY: - TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) { - s = RB_FIND(pf_state_tree_ext_gwy, - &kif->pfik_ext_gwy, (struct pf_state *)key); - if (s == NULL) - continue; - if (more == NULL) - return (s); - ss = s; - (*more)++; - } - return (ss); - default: - panic("pf_find_state_all"); - } -} - void pf_init_threshold(struct pf_threshold *threshold, u_int32_t limit, u_int32_t seconds) @@ -739,7 +571,6 @@ pf_check_threshold(struct pf_threshold *threshold) int pf_src_connlimit(struct pf_state **state) { - struct pf_state *s; int bad = 0; (*state)->src_node->conn++; @@ -749,13 +580,21 @@ pf_src_connlimit(struct pf_state **state) if ((*state)->rule.ptr->max_src_conn && (*state)->rule.ptr->max_src_conn < (*state)->src_node->conn) { +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_SRCCONN]++; +#else pf_status.lcounters[LCNT_SRCCONN]++; +#endif bad++; } if ((*state)->rule.ptr->max_src_conn_rate.limit && pf_check_threshold(&(*state)->src_node->conn_rate)) { +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_SRCCONNRATE]++; +#else pf_status.lcounters[LCNT_SRCCONNRATE]++; +#endif bad++; } @@ -766,16 +605,21 @@ pf_src_connlimit(struct pf_state **state) struct pfr_addr p; u_int32_t killed = 0; +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_OVERLOAD_TABLE]++; + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else pf_status.lcounters[LCNT_OVERLOAD_TABLE]++; if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf_src_connlimit: blocking address "); pf_print_host(&(*state)->src_node->addr, 0, - (*state)->af); + (*state)->key[PF_SK_WIRE]->af); } bzero(&p, sizeof(p)); - p.pfra_af = (*state)->af; - switch ((*state)->af) { + p.pfra_af = (*state)->key[PF_SK_WIRE]->af; + switch ((*state)->key[PF_SK_WIRE]->af) { #ifdef INET case AF_INET: p.pfra_net = 32; @@ -795,34 +639,51 @@ pf_src_connlimit(struct pf_state **state) /* kill existing states if that's required. */ if ((*state)->rule.ptr->flush) { - pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; + struct pf_state_key *sk; + struct pf_state *st; - RB_FOREACH(s, pf_state_tree_id, &tree_id) { +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; + RB_FOREACH(st, pf_state_tree_id, &V_tree_id) { +#else + pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++; + RB_FOREACH(st, pf_state_tree_id, &tree_id) { +#endif + sk = st->key[PF_SK_WIRE]; /* * Kill states from this source. (Only those * from the same rule if PF_FLUSH_GLOBAL is not * set) */ - if (s->af == (*state)->af && + if (sk->af == + (*state)->key[PF_SK_WIRE]->af && (((*state)->direction == PF_OUT && PF_AEQ(&(*state)->src_node->addr, - &s->lan.addr, s->af)) || + &sk->addr[0], sk->af)) || ((*state)->direction == PF_IN && PF_AEQ(&(*state)->src_node->addr, - &s->ext.addr, s->af))) && + &sk->addr[1], sk->af))) && ((*state)->rule.ptr->flush & PF_FLUSH_GLOBAL || - (*state)->rule.ptr == s->rule.ptr)) { - s->timeout = PFTM_PURGE; - s->src.state = s->dst.state = + (*state)->rule.ptr == st->rule.ptr)) { + st->timeout = PFTM_PURGE; + st->src.state = st->dst.state = TCPS_CLOSED; killed++; } } +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else if (pf_status.debug >= PF_DEBUG_MISC) +#endif printf(", %u states killed", killed); } +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) +#else if (pf_status.debug >= PF_DEBUG_MISC) +#endif printf("\n"); } @@ -846,18 +707,30 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, k.rule.ptr = rule; else k.rule.ptr = NULL; +#ifdef __FreeBSD__ + V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; + *sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k); +#else pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); +#endif } if (*sn == NULL) { if (!rule->max_src_nodes || rule->src_nodes < rule->max_src_nodes) - (*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + (*sn) = pool_get(&V_pf_src_tree_pl, PR_NOWAIT | PR_ZERO); +#else + (*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT | PR_ZERO); +#endif else +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_SRCNODES]++; +#else pf_status.lcounters[LCNT_SRCNODES]++; +#endif if ((*sn) == NULL) return (-1); - bzero(*sn, sizeof(struct pf_src_node)); pf_init_threshold(&(*sn)->conn_rate, rule->max_src_conn_rate.limit, @@ -871,109 +744,590 @@ pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, (*sn)->rule.ptr = NULL; PF_ACPY(&(*sn)->addr, src, af); if (RB_INSERT(pf_src_tree, +#ifdef __FreeBSD__ + &V_tree_src_tracking, *sn) != NULL) { + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else &tree_src_tracking, *sn) != NULL) { if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: src_tree insert failed: "); pf_print_host(&(*sn)->addr, 0, af); printf("\n"); } +#ifdef __FreeBSD__ + pool_put(&V_pf_src_tree_pl, *sn); +#else pool_put(&pf_src_tree_pl, *sn); +#endif return (-1); } (*sn)->creation = time_second; (*sn)->ruletype = rule->action; if ((*sn)->rule.ptr != NULL) (*sn)->rule.ptr->src_nodes++; +#ifdef __FreeBSD__ + V_pf_status.scounters[SCNT_SRC_NODE_INSERT]++; + V_pf_status.src_nodes++; +#else pf_status.scounters[SCNT_SRC_NODE_INSERT]++; pf_status.src_nodes++; +#endif } else { if (rule->max_src_states && (*sn)->states >= rule->max_src_states) { +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_SRCSTATES]++; +#else pf_status.lcounters[LCNT_SRCSTATES]++; +#endif return (-1); } } return (0); } +/* state table stuff */ + +static __inline int +pf_state_compare_key(struct pf_state_key *a, struct pf_state_key *b) +{ + int diff; + + if ((diff = a->proto - b->proto) != 0) + return (diff); + if ((diff = a->af - b->af) != 0) + return (diff); + switch (a->af) { +#ifdef INET + case AF_INET: + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return (1); + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return (-1); + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return (1); + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return (-1); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (a->addr[0].addr32[3] > b->addr[0].addr32[3]) + return (1); + if (a->addr[0].addr32[3] < b->addr[0].addr32[3]) + return (-1); + if (a->addr[1].addr32[3] > b->addr[1].addr32[3]) + return (1); + if (a->addr[1].addr32[3] < b->addr[1].addr32[3]) + return (-1); + if (a->addr[0].addr32[2] > b->addr[0].addr32[2]) + return (1); + if (a->addr[0].addr32[2] < b->addr[0].addr32[2]) + return (-1); + if (a->addr[1].addr32[2] > b->addr[1].addr32[2]) + return (1); + if (a->addr[1].addr32[2] < b->addr[1].addr32[2]) + return (-1); + if (a->addr[0].addr32[1] > b->addr[0].addr32[1]) + return (1); + if (a->addr[0].addr32[1] < b->addr[0].addr32[1]) + return (-1); + if (a->addr[1].addr32[1] > b->addr[1].addr32[1]) + return (1); + if (a->addr[1].addr32[1] < b->addr[1].addr32[1]) + return (-1); + if (a->addr[0].addr32[0] > b->addr[0].addr32[0]) + return (1); + if (a->addr[0].addr32[0] < b->addr[0].addr32[0]) + return (-1); + if (a->addr[1].addr32[0] > b->addr[1].addr32[0]) + return (1); + if (a->addr[1].addr32[0] < b->addr[1].addr32[0]) + return (-1); + break; +#endif /* INET6 */ + } + + if ((diff = a->port[0] - b->port[0]) != 0) + return (diff); + if ((diff = a->port[1] - b->port[1]) != 0) + return (diff); + + return (0); +} + +static __inline int +pf_state_compare_id(struct pf_state *a, struct pf_state *b) +{ + if (a->id > b->id) + return (1); + if (a->id < b->id) + return (-1); + if (a->creatorid > b->creatorid) + return (1); + if (a->creatorid < b->creatorid) + return (-1); + + return (0); +} + int -pf_insert_state(struct pfi_kif *kif, struct pf_state *state) +pf_state_key_attach(struct pf_state_key *sk, struct pf_state *s, int idx) { - /* Thou MUST NOT insert multiple duplicate keys */ - state->u.s.kif = kif; - if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) { - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf: state insert failed: tree_lan_ext"); - printf(" lan: "); - pf_print_host(&state->lan.addr, state->lan.port, - state->af); - printf(" gwy: "); - pf_print_host(&state->gwy.addr, state->gwy.port, - state->af); - printf(" ext: "); - pf_print_host(&state->ext.addr, state->ext.port, - state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); - printf("\n"); - } + struct pf_state_item *si; + struct pf_state_key *cur; + struct pf_state *olds = NULL; + +#ifdef __FreeBSD__ + KASSERT(s->key[idx] == NULL, ("%s: key is null!", __FUNCTION__)); +#else + KASSERT(s->key[idx] == NULL); /* XXX handle this? */ +#endif + +#ifdef __FreeBSD__ + if ((cur = RB_INSERT(pf_state_tree, &V_pf_statetbl, sk)) != NULL) { +#else + if ((cur = RB_INSERT(pf_state_tree, &pf_statetbl, sk)) != NULL) { +#endif + /* key exists. check for same kif, if none, add to key */ + TAILQ_FOREACH(si, &cur->states, entry) + if (si->s->kif == s->kif && + si->s->direction == s->direction) { + if (sk->proto == IPPROTO_TCP && + si->s->src.state >= TCPS_FIN_WAIT_2 && + si->s->dst.state >= TCPS_FIN_WAIT_2) { + si->s->src.state = si->s->dst.state = + TCPS_CLOSED; + /* unlink late or sks can go away */ + olds = si->s; + } else { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif + printf("pf: %s key attach " + "failed on %s: ", + (idx == PF_SK_WIRE) ? + "wire" : "stack", + s->kif->pfik_name); + pf_print_state_parts(s, + (idx == PF_SK_WIRE) ? + sk : NULL, + (idx == PF_SK_STACK) ? + sk : NULL); + printf(", existing: "); + pf_print_state_parts(si->s, + (idx == PF_SK_WIRE) ? + sk : NULL, + (idx == PF_SK_STACK) ? + sk : NULL); + printf("\n"); + } +#ifdef __FreeBSD__ + pool_put(&V_pf_state_key_pl, sk); +#else + pool_put(&pf_state_key_pl, sk); +#endif + return (-1); /* collision! */ + } + } +#ifdef __FreeBSD__ + pool_put(&V_pf_state_key_pl, sk); +#else + pool_put(&pf_state_key_pl, sk); +#endif + s->key[idx] = cur; + } else + s->key[idx] = sk; + +#ifdef __FreeBSD__ + if ((si = pool_get(&V_pf_state_item_pl, PR_NOWAIT)) == NULL) { +#else + if ((si = pool_get(&pf_state_item_pl, PR_NOWAIT)) == NULL) { +#endif + pf_state_key_detach(s, idx); return (-1); } + si->s = s; - if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) { - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf: state insert failed: tree_ext_gwy"); - printf(" lan: "); - pf_print_host(&state->lan.addr, state->lan.port, - state->af); - printf(" gwy: "); - pf_print_host(&state->gwy.addr, state->gwy.port, - state->af); - printf(" ext: "); - pf_print_host(&state->ext.addr, state->ext.port, - state->af); - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); - printf("\n"); + /* list is sorted, if-bound states before floating */ +#ifdef __FreeBSD__ + if (s->kif == V_pfi_all) +#else + if (s->kif == pfi_all) +#endif + TAILQ_INSERT_TAIL(&s->key[idx]->states, si, entry); + else + TAILQ_INSERT_HEAD(&s->key[idx]->states, si, entry); + + if (olds) + pf_unlink_state(olds); + + return (0); +} + +void +pf_detach_state(struct pf_state *s) +{ + if (s->key[PF_SK_WIRE] == s->key[PF_SK_STACK]) + s->key[PF_SK_WIRE] = NULL; + + if (s->key[PF_SK_STACK] != NULL) + pf_state_key_detach(s, PF_SK_STACK); + + if (s->key[PF_SK_WIRE] != NULL) + pf_state_key_detach(s, PF_SK_WIRE); +} + +void +pf_state_key_detach(struct pf_state *s, int idx) +{ + struct pf_state_item *si; + + si = TAILQ_FIRST(&s->key[idx]->states); + while (si && si->s != s) + si = TAILQ_NEXT(si, entry); + + if (si) { + TAILQ_REMOVE(&s->key[idx]->states, si, entry); +#ifdef __FreeBSD__ + pool_put(&V_pf_state_item_pl, si); +#else + pool_put(&pf_state_item_pl, si); +#endif + } + + if (TAILQ_EMPTY(&s->key[idx]->states)) { +#ifdef __FreeBSD__ + RB_REMOVE(pf_state_tree, &V_pf_statetbl, s->key[idx]); +#else + RB_REMOVE(pf_state_tree, &pf_statetbl, s->key[idx]); +#endif + if (s->key[idx]->reverse) + s->key[idx]->reverse->reverse = NULL; +#ifdef __FreeBSD__ + /* XXX: implement this */ +#else + if (s->key[idx]->inp) + s->key[idx]->inp->inp_pf_sk = NULL; +#endif +#ifdef __FreeBSD__ + pool_put(&V_pf_state_key_pl, s->key[idx]); +#else + pool_put(&pf_state_key_pl, s->key[idx]); +#endif + } + s->key[idx] = NULL; +} + +struct pf_state_key * +pf_alloc_state_key(int pool_flags) +{ + struct pf_state_key *sk; + +#ifdef __FreeBSD__ + if ((sk = pool_get(&V_pf_state_key_pl, pool_flags)) == NULL) +#else + if ((sk = pool_get(&pf_state_key_pl, pool_flags)) == NULL) +#endif + return (NULL); + TAILQ_INIT(&sk->states); + + return (sk); +} + +int +pf_state_key_setup(struct pf_pdesc *pd, struct pf_rule *nr, + struct pf_state_key **skw, struct pf_state_key **sks, + struct pf_state_key **skp, struct pf_state_key **nkp, + struct pf_addr *saddr, struct pf_addr *daddr, + u_int16_t sport, u_int16_t dport) +{ +#ifdef __FreeBSD__ + KASSERT((*skp == NULL && *nkp == NULL), + ("%s: skp == NULL && nkp == NULL", __FUNCTION__)); +#else + KASSERT((*skp == NULL && *nkp == NULL)); +#endif + + if ((*skp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) + return (ENOMEM); + + PF_ACPY(&(*skp)->addr[pd->sidx], saddr, pd->af); + PF_ACPY(&(*skp)->addr[pd->didx], daddr, pd->af); + (*skp)->port[pd->sidx] = sport; + (*skp)->port[pd->didx] = dport; + (*skp)->proto = pd->proto; + (*skp)->af = pd->af; + + if (nr != NULL) { + if ((*nkp = pf_alloc_state_key(PR_NOWAIT | PR_ZERO)) == NULL) + return (ENOMEM); /* caller must handle cleanup */ + + /* XXX maybe just bcopy and TAILQ_INIT(&(*nkp)->states) */ + PF_ACPY(&(*nkp)->addr[0], &(*skp)->addr[0], pd->af); + PF_ACPY(&(*nkp)->addr[1], &(*skp)->addr[1], pd->af); + (*nkp)->port[0] = (*skp)->port[0]; + (*nkp)->port[1] = (*skp)->port[1]; + (*nkp)->proto = pd->proto; + (*nkp)->af = pd->af; + } else + *nkp = *skp; + + if (pd->dir == PF_IN) { + *skw = *skp; + *sks = *nkp; + } else { + *sks = *skp; + *skw = *nkp; + } + return (0); +} + + +int +pf_state_insert(struct pfi_kif *kif, struct pf_state_key *skw, + struct pf_state_key *sks, struct pf_state *s) +{ +#ifndef __FreeBSD__ + splassert(IPL_SOFTNET); +#endif + + s->kif = kif; + + if (skw == sks) { + if (pf_state_key_attach(skw, s, PF_SK_WIRE)) + return (-1); + s->key[PF_SK_STACK] = s->key[PF_SK_WIRE]; + } else { + if (pf_state_key_attach(skw, s, PF_SK_WIRE)) { +#ifdef __FreeBSD__ + pool_put(&V_pf_state_key_pl, sks); +#else + pool_put(&pf_state_key_pl, sks); +#endif + return (-1); + } + if (pf_state_key_attach(sks, s, PF_SK_STACK)) { + pf_state_key_detach(s, PF_SK_WIRE); + return (-1); } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); - return (-1); } - if (state->id == 0 && state->creatorid == 0) { - state->id = htobe64(pf_status.stateid++); - state->creatorid = pf_status.hostid; + if (s->id == 0 && s->creatorid == 0) { +#ifdef __FreeBSD__ + s->id = htobe64(V_pf_status.stateid++); + s->creatorid = V_pf_status.hostid; +#else + s->id = htobe64(pf_status.stateid++); + s->creatorid = pf_status.hostid; +#endif } - if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) { - if (pf_status.debug >= PF_DEBUG_MISC) { #ifdef __FreeBSD__ - printf("pf: state insert failed: " - "id: %016llx creatorid: %08x", - (long long)be64toh(state->id), - ntohl(state->creatorid)); + if (RB_INSERT(pf_state_tree_id, &V_tree_id, s) != NULL) { + if (V_pf_status.debug >= PF_DEBUG_MISC) { #else + if (RB_INSERT(pf_state_tree_id, &tree_id, s) != NULL) { + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: state insert failed: " "id: %016llx creatorid: %08x", - betoh64(state->id), ntohl(state->creatorid)); +#ifdef __FreeBSD__ + (unsigned long long)betoh64(s->id), ntohl(s->creatorid)); +#else + betoh64(s->id), ntohl(s->creatorid)); #endif - if (state->sync_flags & PFSTATE_FROMSYNC) - printf(" (from sync)"); printf("\n"); } - RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state); - RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state); + pf_detach_state(s); return (-1); } - TAILQ_INSERT_TAIL(&state_list, state, u.s.entry_list); +#ifdef __FreeBSD__ + TAILQ_INSERT_TAIL(&V_state_list, s, entry_list); + V_pf_status.fcounters[FCNT_STATE_INSERT]++; + V_pf_status.states++; +#else + TAILQ_INSERT_TAIL(&state_list, s, entry_list); pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; +#endif pfi_kif_ref(kif, PFI_KIF_REF_STATE); -#if NPFSYNC - pfsync_insert_state(state); +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_insert_state_ptr != NULL) + pfsync_insert_state_ptr(s); +#else + pfsync_insert_state(s); +#endif #endif return (0); } +struct pf_state * +pf_find_state_byid(struct pf_state_cmp *key) +{ +#ifdef __FreeBSD__ + V_pf_status.fcounters[FCNT_STATE_SEARCH]++; + + return (RB_FIND(pf_state_tree_id, &V_tree_id, (struct pf_state *)key)); +#else + pf_status.fcounters[FCNT_STATE_SEARCH]++; + + return (RB_FIND(pf_state_tree_id, &tree_id, (struct pf_state *)key)); +#endif +} + +/* XXX debug function, intended to be removed one day */ +int +pf_compare_state_keys(struct pf_state_key *a, struct pf_state_key *b, + struct pfi_kif *kif, u_int dir) +{ + /* a (from hdr) and b (new) must be exact opposites of each other */ + if (a->af == b->af && a->proto == b->proto && + PF_AEQ(&a->addr[0], &b->addr[1], a->af) && + PF_AEQ(&a->addr[1], &b->addr[0], a->af) && + a->port[0] == b->port[1] && + a->port[1] == b->port[0]) + return (0); + else { + /* mismatch. must not happen. */ + printf("pf: state key linking mismatch! dir=%s, " + "if=%s, stored af=%u, a0: ", + dir == PF_OUT ? "OUT" : "IN", kif->pfik_name, a->af); + pf_print_host(&a->addr[0], a->port[0], a->af); + printf(", a1: "); + pf_print_host(&a->addr[1], a->port[1], a->af); + printf(", proto=%u", a->proto); + printf(", found af=%u, a0: ", b->af); + pf_print_host(&b->addr[0], b->port[0], b->af); + printf(", a1: "); + pf_print_host(&b->addr[1], b->port[1], b->af); + printf(", proto=%u", b->proto); + printf(".\n"); + return (-1); + } +} + +struct pf_state * +#ifdef __FreeBSD__ +pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir, + struct mbuf *m, struct pf_mtag *pftag) +#else +pf_find_state(struct pfi_kif *kif, struct pf_state_key_cmp *key, u_int dir, + struct mbuf *m) +#endif +{ + struct pf_state_key *sk; + struct pf_state_item *si; + +#ifdef __FreeBSD__ + V_pf_status.fcounters[FCNT_STATE_SEARCH]++; +#else + pf_status.fcounters[FCNT_STATE_SEARCH]++; +#endif + +#ifdef __FreeBSD__ + if (dir == PF_OUT && pftag->statekey && + ((struct pf_state_key *)pftag->statekey)->reverse) + sk = ((struct pf_state_key *)pftag->statekey)->reverse; + else { +#ifdef __FreeBSD__ + if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl, +#else + if ((sk = RB_FIND(pf_state_tree, &pf_statetbl, +#endif + (struct pf_state_key *)key)) == NULL) + return (NULL); + if (dir == PF_OUT && pftag->statekey && + pf_compare_state_keys(pftag->statekey, sk, + kif, dir) == 0) { + ((struct pf_state_key *) + pftag->statekey)->reverse = sk; + sk->reverse = pftag->statekey; + } + } +#else + if (dir == PF_OUT && m->m_pkthdr.pf.statekey && + ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse) + sk = ((struct pf_state_key *)m->m_pkthdr.pf.statekey)->reverse; + else { +#ifdef __FreeBSD__ + if ((sk = RB_FIND(pf_state_tree, &V_pf_statetbl, +#else + if ((sk = RB_FIND(pf_state_tree, &pf_statetbl, +#endif + (struct pf_state_key *)key)) == NULL) + return (NULL); + if (dir == PF_OUT && m->m_pkthdr.pf.statekey && + pf_compare_state_keys(m->m_pkthdr.pf.statekey, sk, + kif, dir) == 0) { + ((struct pf_state_key *) + m->m_pkthdr.pf.statekey)->reverse = sk; + sk->reverse = m->m_pkthdr.pf.statekey; + } + } +#endif + + if (dir == PF_OUT) +#ifdef __FreeBSD__ + pftag->statekey = NULL; +#else + m->m_pkthdr.pf.statekey = NULL; +#endif + + /* list is sorted, if-bound states before floating ones */ + TAILQ_FOREACH(si, &sk->states, entry) +#ifdef __FreeBSD__ + if ((si->s->kif == V_pfi_all || si->s->kif == kif) && +#else + if ((si->s->kif == pfi_all || si->s->kif == kif) && +#endif + sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : + si->s->key[PF_SK_STACK])) + return (si->s); + + return (NULL); +} + +struct pf_state * +pf_find_state_all(struct pf_state_key_cmp *key, u_int dir, int *more) +{ + struct pf_state_key *sk; + struct pf_state_item *si, *ret = NULL; + +#ifdef __FreeBSD__ + V_pf_status.fcounters[FCNT_STATE_SEARCH]++; +#else + pf_status.fcounters[FCNT_STATE_SEARCH]++; +#endif + +#ifdef __FreeBSD__ + sk = RB_FIND(pf_state_tree, &V_pf_statetbl, (struct pf_state_key *)key); +#else + sk = RB_FIND(pf_state_tree, &pf_statetbl, (struct pf_state_key *)key); +#endif + if (sk != NULL) { + TAILQ_FOREACH(si, &sk->states, entry) + if (dir == PF_INOUT || + (sk == (dir == PF_IN ? si->s->key[PF_SK_WIRE] : + si->s->key[PF_SK_STACK]))) { + if (more == NULL) + return (si->s); + + if (ret) + (*more)++; + else + ret = si; + } + } + return (ret ? ret->s : NULL); +} + +/* END state table stuff */ + + void pf_purge_thread(void *v) { @@ -982,61 +1336,61 @@ pf_purge_thread(void *v) int locked; #endif + CURVNET_SET((struct vnet *)v); + for (;;) { tsleep(pf_purge_thread, PWAIT, "pftm", 1 * hz); #ifdef __FreeBSD__ - sx_slock(&pf_consistency_lock); + sx_slock(&V_pf_consistency_lock); + PF_LOCK(); + locked = 0; + + if (V_pf_end_threads) { + PF_UNLOCK(); + sx_sunlock(&V_pf_consistency_lock); + sx_xlock(&V_pf_consistency_lock); PF_LOCK(); - locked = 0; - if (pf_end_threads) { - PF_UNLOCK(); - sx_sunlock(&pf_consistency_lock); - sx_xlock(&pf_consistency_lock); - PF_LOCK(); - pf_purge_expired_states(pf_status.states, 1); - pf_purge_expired_fragments(); - pf_purge_expired_src_nodes(1); - pf_end_threads++; + pf_purge_expired_states(V_pf_status.states, 1); + pf_purge_expired_fragments(); + pf_purge_expired_src_nodes(1); + V_pf_end_threads++; - sx_xunlock(&pf_consistency_lock); - PF_UNLOCK(); - wakeup(pf_purge_thread); - kproc_exit(0); - } + sx_xunlock(&V_pf_consistency_lock); + PF_UNLOCK(); + wakeup(pf_purge_thread); + kproc_exit(0); + } #endif s = splsoftnet(); /* process a fraction of the state table every second */ #ifdef __FreeBSD__ - if(!pf_purge_expired_states(1 + (pf_status.states - / pf_default_rule.timeout[PFTM_INTERVAL]), 0)) { - PF_UNLOCK(); - sx_sunlock(&pf_consistency_lock); - sx_xlock(&pf_consistency_lock); - PF_LOCK(); - locked = 1; + if (!pf_purge_expired_states(1 + (V_pf_status.states / + V_pf_default_rule.timeout[PFTM_INTERVAL]), 0)) { + PF_UNLOCK(); + sx_sunlock(&V_pf_consistency_lock); + sx_xlock(&V_pf_consistency_lock); + PF_LOCK(); + locked = 1; - pf_purge_expired_states(1 + (pf_status.states - / pf_default_rule.timeout[PFTM_INTERVAL]), 1); - } + pf_purge_expired_states(1 + (V_pf_status.states / + V_pf_default_rule.timeout[PFTM_INTERVAL]), 1); + } #else pf_purge_expired_states(1 + (pf_status.states / pf_default_rule.timeout[PFTM_INTERVAL])); #endif /* purge other expired types every PFTM_INTERVAL seconds */ +#ifdef __FreeBSD__ + if (++nloops >= V_pf_default_rule.timeout[PFTM_INTERVAL]) { +#else if (++nloops >= pf_default_rule.timeout[PFTM_INTERVAL]) { +#endif pf_purge_expired_fragments(); - if (!pf_purge_expired_src_nodes(locked)) { - PF_UNLOCK(); - sx_sunlock(&pf_consistency_lock); - sx_xlock(&pf_consistency_lock); - PF_LOCK(); - locked = 1; - pf_purge_expired_src_nodes(1); - } + pf_purge_expired_src_nodes(0); nloops = 0; } @@ -1044,11 +1398,12 @@ pf_purge_thread(void *v) #ifdef __FreeBSD__ PF_UNLOCK(); if (locked) - sx_xunlock(&pf_consistency_lock); + sx_xunlock(&V_pf_consistency_lock); else - sx_sunlock(&pf_consistency_lock); + sx_sunlock(&V_pf_consistency_lock); #endif } + CURVNET_RESTORE(); } u_int32_t @@ -1064,7 +1419,7 @@ pf_state_expires(const struct pf_state *state) return (time_second); if (state->timeout == PFTM_UNTIL_PACKET) return (0); -#ifdef __FreeBSD__ +#ifdef __FreeBSD__ KASSERT(state->timeout != PFTM_UNLINKED, ("pf_state_expires: timeout == PFTM_UNLINKED")); KASSERT((state->timeout < PFTM_MAX), @@ -1075,15 +1430,25 @@ pf_state_expires(const struct pf_state *state) #endif timeout = state->rule.ptr->timeout[state->timeout]; if (!timeout) +#ifdef __FreeBSD__ + timeout = V_pf_default_rule.timeout[state->timeout]; +#else timeout = pf_default_rule.timeout[state->timeout]; +#endif start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START]; if (start) { end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END]; - states = state->rule.ptr->states; + states = state->rule.ptr->states_cur; } else { +#ifdef __FreeBSD__ + start = V_pf_default_rule.timeout[PFTM_ADAPTIVE_START]; + end = V_pf_default_rule.timeout[PFTM_ADAPTIVE_END]; + states = V_pf_status.states; +#else start = pf_default_rule.timeout[PFTM_ADAPTIVE_START]; end = pf_default_rule.timeout[PFTM_ADAPTIVE_END]; states = pf_status.states; +#endif } if (end && states > start && start < end) { if (states < end) @@ -1103,46 +1468,61 @@ void pf_purge_expired_src_nodes(int waslocked) #endif { - struct pf_src_node *cur, *next; - int locked = waslocked; - - for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) { - next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); + struct pf_src_node *cur, *next; + int locked = waslocked; - if (cur->states <= 0 && cur->expire <= time_second) { - if (! locked) { #ifdef __FreeBSD__ - if (!sx_try_upgrade(&pf_consistency_lock)) - return (0); + for (cur = RB_MIN(pf_src_tree, &V_tree_src_tracking); cur; cur = next) { + next = RB_NEXT(pf_src_tree, &V_tree_src_tracking, cur); #else - rw_enter_write(&pf_consistency_lock); + for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) { + next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur); #endif - next = RB_NEXT(pf_src_tree, - &tree_src_tracking, cur); - locked = 1; - } - if (cur->rule.ptr != NULL) { - cur->rule.ptr->src_nodes--; - if (cur->rule.ptr->states <= 0 && - cur->rule.ptr->max_src_nodes <= 0) - pf_rm_rule(NULL, cur->rule.ptr); - } - RB_REMOVE(pf_src_tree, &tree_src_tracking, cur); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, cur); - } - } - if (locked && !waslocked) + if (cur->states <= 0 && cur->expire <= time_second) { + if (! locked) { #ifdef __FreeBSD__ - sx_downgrade(&pf_consistency_lock); + if (!sx_try_upgrade(&V_pf_consistency_lock)) + return (0); #else - rw_exit_write(&pf_consistency_lock); + rw_enter_write(&pf_consistency_lock); +#endif + next = RB_NEXT(pf_src_tree, +#ifdef __FreeBSD__ + &V_tree_src_tracking, cur); +#else + &tree_src_tracking, cur); +#endif + locked = 1; + } + if (cur->rule.ptr != NULL) { + cur->rule.ptr->src_nodes--; + if (cur->rule.ptr->states_cur <= 0 && + cur->rule.ptr->max_src_nodes <= 0) + pf_rm_rule(NULL, cur->rule.ptr); + } +#ifdef __FreeBSD__ + RB_REMOVE(pf_src_tree, &V_tree_src_tracking, cur); + V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + V_pf_status.src_nodes--; + pool_put(&V_pf_src_tree_pl, cur); +#else + RB_REMOVE(pf_src_tree, &tree_src_tracking, cur); + pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + pf_status.src_nodes--; + pool_put(&pf_src_tree_pl, cur); #endif + } + } + if (locked && !waslocked) #ifdef __FreeBSD__ + { + sx_downgrade(&V_pf_consistency_lock); + } return (1); +#else + rw_exit_write(&pf_consistency_lock); #endif } @@ -1152,15 +1532,17 @@ pf_src_tree_remove_state(struct pf_state *s) u_int32_t timeout; if (s->src_node != NULL) { - if (s->proto == IPPROTO_TCP) { - if (s->src.tcp_est) - --s->src_node->conn; - } + if (s->src.tcp_est) + --s->src_node->conn; if (--s->src_node->states <= 0) { timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; if (!timeout) timeout = +#ifdef __FreeBSD__ + V_pf_default_rule.timeout[PFTM_SRC_NODE]; +#else pf_default_rule.timeout[PFTM_SRC_NODE]; +#endif s->src_node->expire = time_second + timeout; } } @@ -1169,7 +1551,11 @@ pf_src_tree_remove_state(struct pf_state *s) timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; if (!timeout) timeout = +#ifdef __FreeBSD__ + V_pf_default_rule.timeout[PFTM_SRC_NODE]; +#else pf_default_rule.timeout[PFTM_SRC_NODE]; +#endif s->nat_src_node->expire = time_second + timeout; } } @@ -1184,29 +1570,49 @@ pf_unlink_state(struct pf_state *cur) if (cur->local_flags & PFSTATE_EXPIRING) return; cur->local_flags |= PFSTATE_EXPIRING; +#else + splassert(IPL_SOFTNET); #endif + if (cur->src.state == PF_TCPS_PROXY_DST) { + /* XXX wire key the right one? */ #ifdef __FreeBSD__ - pf_send_tcp(NULL, cur->rule.ptr, cur->af, + pf_send_tcp(NULL, cur->rule.ptr, cur->key[PF_SK_WIRE]->af, #else - pf_send_tcp(cur->rule.ptr, cur->af, + pf_send_tcp(cur->rule.ptr, cur->key[PF_SK_WIRE]->af, #endif - &cur->ext.addr, &cur->lan.addr, - cur->ext.port, cur->lan.port, + &cur->key[PF_SK_WIRE]->addr[1], + &cur->key[PF_SK_WIRE]->addr[0], + cur->key[PF_SK_WIRE]->port[1], + cur->key[PF_SK_WIRE]->port[0], cur->src.seqhi, cur->src.seqlo + 1, TH_RST|TH_ACK, 0, 0, 0, 1, cur->tag, NULL, NULL); } - RB_REMOVE(pf_state_tree_ext_gwy, - &cur->u.s.kif->pfik_ext_gwy, cur); - RB_REMOVE(pf_state_tree_lan_ext, - &cur->u.s.kif->pfik_lan_ext, cur); +#ifdef __FreeBSD__ + RB_REMOVE(pf_state_tree_id, &V_tree_id, cur); +#else RB_REMOVE(pf_state_tree_id, &tree_id, cur); -#if NPFSYNC - if (cur->creatorid == pf_status.hostid) - pfsync_delete_state(cur); +#endif +#if NPFLOW > 0 + if (cur->state_flags & PFSTATE_PFLOW) +#ifdef __FreeBSD__ + if (export_pflow_ptr != NULL) + export_pflow_ptr(cur); +#else + export_pflow(cur); +#endif +#endif +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_delete_state_ptr != NULL) + pfsync_delete_state_ptr(cur); +#else + pfsync_delete_state(cur); +#endif #endif cur->timeout = PFTM_UNLINKED; pf_src_tree_remove_state(cur); + pf_detach_state(cur); } /* callers should be at splsoftnet and hold the @@ -1214,10 +1620,17 @@ pf_unlink_state(struct pf_state *cur) void pf_free_state(struct pf_state *cur) { -#if NPFSYNC - if (pfsyncif != NULL && - (pfsyncif->sc_bulk_send_next == cur || - pfsyncif->sc_bulk_terminator == cur)) +#ifndef __FreeBSD__ + splassert(IPL_SOFTNET); +#endif + +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_state_in_use_ptr != NULL) + pfsync_state_in_use_ptr(cur); +#else + if (pfsync_state_in_use(cur)) +#endif return; #endif #ifdef __FreeBSD__ @@ -1226,24 +1639,34 @@ pf_free_state(struct pf_state *cur) #else KASSERT(cur->timeout == PFTM_UNLINKED); #endif - if (--cur->rule.ptr->states <= 0 && + if (--cur->rule.ptr->states_cur <= 0 && cur->rule.ptr->src_nodes <= 0) pf_rm_rule(NULL, cur->rule.ptr); if (cur->nat_rule.ptr != NULL) - if (--cur->nat_rule.ptr->states <= 0 && + if (--cur->nat_rule.ptr->states_cur <= 0 && cur->nat_rule.ptr->src_nodes <= 0) pf_rm_rule(NULL, cur->nat_rule.ptr); if (cur->anchor.ptr != NULL) - if (--cur->anchor.ptr->states <= 0) + if (--cur->anchor.ptr->states_cur <= 0) pf_rm_rule(NULL, cur->anchor.ptr); pf_normalize_tcp_cleanup(cur); - pfi_kif_unref(cur->u.s.kif, PFI_KIF_REF_STATE); - TAILQ_REMOVE(&state_list, cur, u.s.entry_list); + pfi_kif_unref(cur->kif, PFI_KIF_REF_STATE); +#ifdef __FreeBSD__ + TAILQ_REMOVE(&V_state_list, cur, entry_list); +#else + TAILQ_REMOVE(&state_list, cur, entry_list); +#endif if (cur->tag) pf_tag_unref(cur->tag); +#ifdef __FreeBSD__ + pool_put(&V_pf_state_pl, cur); + V_pf_status.fcounters[FCNT_STATE_REMOVALS]++; + V_pf_status.states--; +#else pool_put(&pf_state_pl, cur); pf_status.fcounters[FCNT_STATE_REMOVALS]++; pf_status.states--; +#endif } #ifdef __FreeBSD__ @@ -1257,28 +1680,32 @@ pf_purge_expired_states(u_int32_t maxcheck) static struct pf_state *cur = NULL; struct pf_state *next; #ifdef __FreeBSD__ - int locked = waslocked; + int locked = waslocked; #else - int locked = 0; + int locked = 0; #endif while (maxcheck--) { /* wrap to start of list when we hit the end */ if (cur == NULL) { +#ifdef __FreeBSD__ + cur = TAILQ_FIRST(&V_state_list); +#else cur = TAILQ_FIRST(&state_list); +#endif if (cur == NULL) break; /* list empty */ } /* get next state, as cur may get deleted */ - next = TAILQ_NEXT(cur, u.s.entry_list); + next = TAILQ_NEXT(cur, entry_list); if (cur->timeout == PFTM_UNLINKED) { /* free unlinked state */ if (! locked) { #ifdef __FreeBSD__ - if (!sx_try_upgrade(&pf_consistency_lock)) - return (0); + if (!sx_try_upgrade(&V_pf_consistency_lock)) + return (0); #else rw_enter_write(&pf_consistency_lock); #endif @@ -1290,8 +1717,8 @@ pf_purge_expired_states(u_int32_t maxcheck) pf_unlink_state(cur); if (! locked) { #ifdef __FreeBSD__ - if (!sx_try_upgrade(&pf_consistency_lock)) - return (0); + if (!sx_try_upgrade(&V_pf_consistency_lock)) + return (0); #else rw_enter_write(&pf_consistency_lock); #endif @@ -1304,7 +1731,7 @@ pf_purge_expired_states(u_int32_t maxcheck) #ifdef __FreeBSD__ if (!waslocked && locked) - sx_downgrade(&pf_consistency_lock); + sx_downgrade(&V_pf_consistency_lock); return (1); #else @@ -1318,7 +1745,7 @@ pf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw) { if (aw->type != PF_ADDR_TABLE) return (0); - if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL) + if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname, 1)) == NULL) return (1); return (0); } @@ -1365,34 +1792,33 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) #ifdef INET6 case AF_INET6: { u_int16_t b; - u_int8_t i, curstart = 255, curend = 0, - maxstart = 0, maxend = 0; + u_int8_t i, curstart, curend, maxstart, maxend; + curstart = curend = maxstart = maxend = 255; for (i = 0; i < 8; i++) { if (!addr->addr16[i]) { if (curstart == 255) curstart = i; - else - curend = i; + curend = i; } else { - if (curstart) { - if ((curend - curstart) > - (maxend - maxstart)) { - maxstart = curstart; - maxend = curend; - curstart = 255; - } + if ((curend - curstart) > + (maxend - maxstart)) { + maxstart = curstart; + maxend = curend; } + curstart = curend = 255; } } + if ((curend - curstart) > + (maxend - maxstart)) { + maxstart = curstart; + maxend = curend; + } for (i = 0; i < 8; i++) { if (i >= maxstart && i <= maxend) { - if (maxend != 7) { - if (i == maxstart) - printf(":"); - } else { - if (i == maxend) - printf(":"); - } + if (i == 0) + printf(":"); + if (i == maxend) + printf(":"); } else { b = ntohs(addr->addr16[i]); printf("%x", b); @@ -1413,39 +1839,87 @@ pf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af) void pf_print_state(struct pf_state *s) { - switch (s->proto) { + pf_print_state_parts(s, NULL, NULL); +} + +void +pf_print_state_parts(struct pf_state *s, + struct pf_state_key *skwp, struct pf_state_key *sksp) +{ + struct pf_state_key *skw, *sks; + u_int8_t proto, dir; + + /* Do our best to fill these, but they're skipped if NULL */ + skw = skwp ? skwp : (s ? s->key[PF_SK_WIRE] : NULL); + sks = sksp ? sksp : (s ? s->key[PF_SK_STACK] : NULL); + proto = skw ? skw->proto : (sks ? sks->proto : 0); + dir = s ? s->direction : 0; + + switch (proto) { + case IPPROTO_IPV4: + printf("IPv4"); + break; + case IPPROTO_IPV6: + printf("IPv6"); + break; case IPPROTO_TCP: - printf("TCP "); + printf("TCP"); break; case IPPROTO_UDP: - printf("UDP "); + printf("UDP"); break; case IPPROTO_ICMP: - printf("ICMP "); + printf("ICMP"); break; case IPPROTO_ICMPV6: - printf("ICMPV6 "); + printf("ICMPv6"); break; default: - printf("%u ", s->proto); + printf("%u", skw->proto); break; } - pf_print_host(&s->lan.addr, s->lan.port, s->af); - printf(" "); - pf_print_host(&s->gwy.addr, s->gwy.port, s->af); - printf(" "); - pf_print_host(&s->ext.addr, s->ext.port, s->af); - printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo, - s->src.seqhi, s->src.max_win, s->src.seqdiff); - if (s->src.wscale && s->dst.wscale) - printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK); - printf("]"); - printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo, - s->dst.seqhi, s->dst.max_win, s->dst.seqdiff); - if (s->src.wscale && s->dst.wscale) - printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK); - printf("]"); - printf(" %u:%u", s->src.state, s->dst.state); + switch (dir) { + case PF_IN: + printf(" in"); + break; + case PF_OUT: + printf(" out"); + break; + } + if (skw) { + printf(" wire: "); + pf_print_host(&skw->addr[0], skw->port[0], skw->af); + printf(" "); + pf_print_host(&skw->addr[1], skw->port[1], skw->af); + } + if (sks) { + printf(" stack: "); + if (sks != skw) { + pf_print_host(&sks->addr[0], sks->port[0], sks->af); + printf(" "); + pf_print_host(&sks->addr[1], sks->port[1], sks->af); + } else + printf("-"); + } + if (s) { + if (proto == IPPROTO_TCP) { + printf(" [lo=%u high=%u win=%u modulator=%u", + s->src.seqlo, s->src.seqhi, + s->src.max_win, s->src.seqdiff); + if (s->src.wscale && s->dst.wscale) + printf(" wscale=%u", + s->src.wscale & PF_WSCALE_MASK); + printf("]"); + printf(" [lo=%u high=%u win=%u modulator=%u", + s->dst.seqlo, s->dst.seqhi, + s->dst.max_win, s->dst.seqdiff); + if (s->src.wscale && s->dst.wscale) + printf(" wscale=%u", + s->dst.wscale & PF_WSCALE_MASK); + printf("]"); + } + printf(" %u:%u", s->src.state, s->dst.state); + } } void @@ -1528,6 +2002,7 @@ pf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2) return (1); switch (aw1->type) { case PF_ADDR_ADDRMASK: + case PF_ADDR_RANGE: if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0)) return (1); if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0)) @@ -1651,12 +2126,13 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, struct pf_addr oia, ooa; PF_ACPY(&oia, ia, af); - PF_ACPY(&ooa, oa, af); + if (oa) + PF_ACPY(&ooa, oa, af); /* Change inner protocol port, fix inner protocol checksum. */ if (ip != NULL) { u_int16_t oip = *ip; - u_int32_t opc = 0; /* make the compiler happy */ + u_int32_t opc; if (pc != NULL) opc = *pc; @@ -1700,31 +2176,33 @@ pf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa, break; #endif /* INET6 */ } - /* Change outer ip address, fix outer ip or icmpv6 checksum. */ - PF_ACPY(oa, na, af); - switch (af) { + /* Outer ip address, fix outer ip or icmpv6 checksum, if necessary. */ + if (oa) { + PF_ACPY(oa, na, af); + switch (af) { #ifdef INET - case AF_INET: - *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, - ooa.addr16[0], oa->addr16[0], 0), - ooa.addr16[1], oa->addr16[1], 0); - break; + case AF_INET: + *hc = pf_cksum_fixup(pf_cksum_fixup(*hc, + ooa.addr16[0], oa->addr16[0], 0), + ooa.addr16[1], oa->addr16[1], 0); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( - pf_cksum_fixup(pf_cksum_fixup(*ic, - ooa.addr16[0], oa->addr16[0], u), - ooa.addr16[1], oa->addr16[1], u), - ooa.addr16[2], oa->addr16[2], u), - ooa.addr16[3], oa->addr16[3], u), - ooa.addr16[4], oa->addr16[4], u), - ooa.addr16[5], oa->addr16[5], u), - ooa.addr16[6], oa->addr16[6], u), - ooa.addr16[7], oa->addr16[7], u); - break; + case AF_INET6: + *ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup( + pf_cksum_fixup(pf_cksum_fixup(*ic, + ooa.addr16[0], oa->addr16[0], u), + ooa.addr16[1], oa->addr16[1], u), + ooa.addr16[2], oa->addr16[2], u), + ooa.addr16[3], oa->addr16[3], u), + ooa.addr16[4], oa->addr16[4], u), + ooa.addr16[5], oa->addr16[5], u), + ooa.addr16[6], oa->addr16[6], u), + ooa.addr16[7], oa->addr16[7], u); + break; #endif /* INET6 */ + } } } @@ -1746,7 +2224,7 @@ pf_modulate_sack(struct mbuf *m, int off, struct pf_pdesc *pd, int copyback = 0, i, olen; struct sackblk sack; -#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) +#define TCPOLEN_SACKLEN (TCPOLEN_SACK + 2) if (hlen < TCPOLEN_SACKLEN || !pf_pull_hdr(m, off + sizeof(*th), opts, hlen, NULL, NULL, pd->af)) return 0; @@ -1815,9 +2293,9 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, #endif /* INET6 */ struct tcphdr *th; char *opt; - struct pf_mtag *pf_mtag; - #ifdef __FreeBSD__ + struct pf_mtag *pf_mtag; + KASSERT( #ifdef INET af == AF_INET @@ -1839,7 +2317,7 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, #ifdef INET6 h6 = NULL; #endif -#endif +#endif /* __FreeBSD__ */ /* maximum segment size tcp option */ tlen = sizeof(struct tcphdr); @@ -1865,42 +2343,46 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, return; #ifdef __FreeBSD__ #ifdef MAC - if (replyto) - mac_netinet_firewall_reply(replyto, m); - else - mac_netinet_firewall_send(m); -#else - (void)replyto; -#endif + mac_netinet_firewall_send(m); #endif if ((pf_mtag = pf_get_mtag(m)) == NULL) { m_freem(m); return; } +#endif if (tag) #ifdef __FreeBSD__ m->m_flags |= M_SKIP_FIREWALL; + pf_mtag->tag = rtag; #else - pf_mtag->flags |= PF_TAG_GENERATED; + m->m_pkthdr.pf.flags |= PF_TAG_GENERATED; + m->m_pkthdr.pf.tag = rtag; #endif - pf_mtag->tag = rtag; - if (r != NULL && r->rtableid >= 0) #ifdef __FreeBSD__ { M_SETFIB(m, r->rtableid); -#endif pf_mtag->rtableid = r->rtableid; +#else + m->m_pkthdr.pf.rtableid = r->rtableid; +#endif #ifdef __FreeBSD__ } #endif + #ifdef ALTQ if (r != NULL && r->qid) { +#ifdef __FreeBSD__ pf_mtag->qid = r->qid; + /* add hints for ecn */ - pf_mtag->af = af; pf_mtag->hdr = mtod(m, struct ip *); +#else + m->m_pkthdr.pf.qid = r->qid; + /* add hints for ecn */ + m->m_pkthdr.pf.hdr = mtod(m, struct ip *); +#endif } #endif /* ALTQ */ m->m_data += max_linkhdr; @@ -1966,18 +2448,19 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, #ifdef __FreeBSD__ h->ip_off = V_path_mtu_discovery ? IP_DF : 0; h->ip_len = len; + h->ip_ttl = ttl ? ttl : V_ip_defttl; #else - h->ip_off = htons(ip_mtudisc ? IP_DF : 0); h->ip_len = htons(len); + h->ip_off = htons(ip_mtudisc ? IP_DF : 0); + h->ip_ttl = ttl ? ttl : ip_defttl; #endif - h->ip_ttl = ttl ? ttl : V_ip_defttl; h->ip_sum = 0; if (eh == NULL) { #ifdef __FreeBSD__ - PF_UNLOCK(); - ip_output(m, (void *)NULL, (void *)NULL, 0, - (void *)NULL, (void *)NULL); - PF_LOCK(); + PF_UNLOCK(); + ip_output(m, (void *)NULL, (void *)NULL, 0, + (void *)NULL, (void *)NULL); + PF_LOCK(); #else /* ! __FreeBSD__ */ ip_output(m, (void *)NULL, (void *)NULL, 0, (void *)NULL, (void *)NULL); @@ -2025,23 +2508,23 @@ pf_send_tcp(const struct pf_rule *r, sa_family_t af, ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); PF_LOCK(); #else - ip6_output(m, NULL, NULL, 0, NULL, NULL); + ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); #endif break; #endif /* INET6 */ } } -void +static void pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, struct pf_rule *r) { - struct pf_mtag *pf_mtag; struct mbuf *m0; #ifdef __FreeBSD__ #ifdef INET struct ip *ip; #endif + struct pf_mtag *pf_mtag; #endif #ifdef __FreeBSD__ @@ -2049,33 +2532,42 @@ pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af, if (m0 == NULL) return; #else - m0 = m_copy(m, 0, M_COPYALL); + if ((m0 = m_copy(m, 0, M_COPYALL)) == NULL) + return; #endif + +#ifdef __FreeBSD__ if ((pf_mtag = pf_get_mtag(m0)) == NULL) return; -#ifdef __FreeBSD__ /* XXX: revisit */ m0->m_flags |= M_SKIP_FIREWALL; #else - pf_mtag->flags |= PF_TAG_GENERATED; + m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; #endif if (r->rtableid >= 0) #ifdef __FreeBSD__ { M_SETFIB(m0, r->rtableid); -#endif pf_mtag->rtableid = r->rtableid; +#else + m0->m_pkthdr.pf.rtableid = r->rtableid; +#endif #ifdef __FreeBSD__ } #endif #ifdef ALTQ if (r->qid) { +#ifdef __FreeBSD__ pf_mtag->qid = r->qid; /* add hints for ecn */ - pf_mtag->af = af; pf_mtag->hdr = mtod(m0, struct ip *); +#else + m0->m_pkthdr.pf.qid = r->qid; + /* add hints for ecn */ + m0->m_pkthdr.pf.hdr = mtod(m0, struct ip *); +#endif } #endif /* ALTQ */ @@ -2155,6 +2647,44 @@ pf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m, } } +/* + * Return 1 if b <= a <= e, otherwise return 0. + */ +int +pf_match_addr_range(struct pf_addr *b, struct pf_addr *e, + struct pf_addr *a, sa_family_t af) +{ + switch (af) { +#ifdef INET + case AF_INET: + if ((a->addr32[0] < b->addr32[0]) || + (a->addr32[0] > e->addr32[0])) + return (0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: { + int i; + + /* check a >= b */ + for (i = 0; i < 4; ++i) + if (a->addr32[i] > b->addr32[i]) + break; + else if (a->addr32[i] < b->addr32[i]) + return (0); + /* check a <= e */ + for (i = 0; i < 4; ++i) + if (a->addr32[i] < e->addr32[i]) + break; + else if (a->addr32[i] > e->addr32[i]) + return (0); + break; + } +#endif /* INET6 */ + } + return (1); +} + int pf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p) { @@ -2206,88 +2736,80 @@ pf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g) return (pf_match(op, a1, a2, g)); } -#ifndef __FreeBSD__ -struct pf_mtag * -pf_find_mtag(struct mbuf *m) -{ - struct m_tag *mtag; - - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) - return (NULL); - - return ((struct pf_mtag *)(mtag + 1)); -} - -struct pf_mtag * -pf_get_mtag(struct mbuf *m) -{ - struct m_tag *mtag; - - if ((mtag = m_tag_find(m, PACKET_TAG_PF, NULL)) == NULL) { - mtag = m_tag_get(PACKET_TAG_PF, sizeof(struct pf_mtag), - M_NOWAIT); - if (mtag == NULL) - return (NULL); - bzero(mtag + 1, sizeof(struct pf_mtag)); - m_tag_prepend(m, mtag); - } - - return ((struct pf_mtag *)(mtag + 1)); -} -#endif - int -pf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_mtag *pf_mtag, - int *tag) +#ifdef __FreeBSD__ +pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag, + struct pf_mtag *pf_mtag) +#else +pf_match_tag(struct mbuf *m, struct pf_rule *r, int *tag) +#endif { if (*tag == -1) +#ifdef __FreeBSD__ *tag = pf_mtag->tag; +#else + *tag = m->m_pkthdr.pf.tag; +#endif return ((!r->match_tag_not && r->match_tag == *tag) || (r->match_tag_not && r->match_tag != *tag)); } int -pf_tag_packet(struct mbuf *m, struct pf_mtag *pf_mtag, int tag, int rtableid) +#ifdef __FreeBSD__ +pf_tag_packet(struct mbuf *m, int tag, int rtableid, + struct pf_mtag *pf_mtag) +#else +pf_tag_packet(struct mbuf *m, int tag, int rtableid) +#endif { if (tag <= 0 && rtableid < 0) return (0); - if (pf_mtag == NULL) - if ((pf_mtag = pf_get_mtag(m)) == NULL) - return (1); if (tag > 0) +#ifdef __FreeBSD__ pf_mtag->tag = tag; +#else + m->m_pkthdr.pf.tag = tag; +#endif if (rtableid >= 0) #ifdef __FreeBSD__ { M_SETFIB(m, rtableid); -#endif - pf_mtag->rtableid = rtableid; -#ifdef __FreeBSD__ } +#else + m->m_pkthdr.pf.rtableid = rtableid; #endif return (0); } -static void +void pf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n, - struct pf_rule **r, struct pf_rule **a, int *match) + struct pf_rule **r, struct pf_rule **a, int *match) { struct pf_anchor_stackframe *f; (*r)->anchor->match = 0; if (match) *match = 0; +#ifdef __FreeBSD__ + if (*depth >= sizeof(V_pf_anchor_stack) / + sizeof(V_pf_anchor_stack[0])) { +#else if (*depth >= sizeof(pf_anchor_stack) / sizeof(pf_anchor_stack[0])) { +#endif printf("pf_step_into_anchor: stack overflow\n"); *r = TAILQ_NEXT(*r, entries); return; } else if (*depth == 0 && a != NULL) *a = *r; +#ifdef __FreeBSD__ + f = V_pf_anchor_stack + (*depth)++; +#else f = pf_anchor_stack + (*depth)++; +#endif f->rs = *rs; f->r = *r; if ((*r)->anchor_wildcard) { @@ -2316,7 +2838,11 @@ pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, do { if (*depth <= 0) break; +#ifdef __FreeBSD__ + f = V_pf_anchor_stack + *depth - 1; +#else f = pf_anchor_stack + *depth - 1; +#endif if (f->parent != NULL && f->child != NULL) { if (f->child->match || (match != NULL && *match)) { @@ -2337,7 +2863,7 @@ pf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n, if (*depth == 0 && a != NULL) *a = NULL; *rs = f->rs; - if (f->r->anchor->match || (match != NULL && *match)) + if (f->r->anchor->match || (match != NULL && *match)) quick = f->r->quick; *r = TAILQ_NEXT(f->r, entries); } while (*r == NULL); @@ -2402,567 +2928,6 @@ pf_addr_inc(struct pf_addr *addr, sa_family_t af) } #endif /* INET6 */ -#define mix(a,b,c) \ - do { \ - a -= b; a -= c; a ^= (c >> 13); \ - b -= c; b -= a; b ^= (a << 8); \ - c -= a; c -= b; c ^= (b >> 13); \ - a -= b; a -= c; a ^= (c >> 12); \ - b -= c; b -= a; b ^= (a << 16); \ - c -= a; c -= b; c ^= (b >> 5); \ - a -= b; a -= c; a ^= (c >> 3); \ - b -= c; b -= a; b ^= (a << 10); \ - c -= a; c -= b; c ^= (b >> 15); \ - } while (0) - -/* - * hash function based on bridge_hash in if_bridge.c - */ -void -pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, - struct pf_poolhashkey *key, sa_family_t af) -{ - u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0]; - - switch (af) { -#ifdef INET - case AF_INET: - a += inaddr->addr32[0]; - b += key->key32[1]; - mix(a, b, c); - hash->addr32[0] = c + key->key32[2]; - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - a += inaddr->addr32[0]; - b += inaddr->addr32[2]; - mix(a, b, c); - hash->addr32[0] = c; - a += inaddr->addr32[1]; - b += inaddr->addr32[3]; - c += key->key32[1]; - mix(a, b, c); - hash->addr32[1] = c; - a += inaddr->addr32[2]; - b += inaddr->addr32[1]; - c += key->key32[2]; - mix(a, b, c); - hash->addr32[2] = c; - a += inaddr->addr32[3]; - b += inaddr->addr32[0]; - c += key->key32[3]; - mix(a, b, c); - hash->addr32[3] = c; - break; -#endif /* INET6 */ - } -} - -int -pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, - struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn) -{ - unsigned char hash[16]; - struct pf_pool *rpool = &r->rpool; - struct pf_addr *raddr = &rpool->cur->addr.v.a.addr; - struct pf_addr *rmask = &rpool->cur->addr.v.a.mask; - struct pf_pooladdr *acur = rpool->cur; - struct pf_src_node k; - - if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && - (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { - k.af = af; - PF_ACPY(&k.addr, saddr, af); - if (r->rule_flag & PFRULE_RULESRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) - k.rule.ptr = r; - else - k.rule.ptr = NULL; - pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; - *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); - if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) { - PF_ACPY(naddr, &(*sn)->raddr, af); - if (pf_status.debug >= PF_DEBUG_MISC) { - printf("pf_map_addr: src tracking maps "); - pf_print_host(&k.addr, 0, af); - printf(" to "); - pf_print_host(naddr, 0, af); - printf("\n"); - } - return (0); - } - } - - if (rpool->cur->addr.type == PF_ADDR_NOROUTE) - return (1); - if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - switch (af) { -#ifdef INET - case AF_INET: - if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 && - (rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) - return (1); - raddr = &rpool->cur->addr.p.dyn->pfid_addr4; - rmask = &rpool->cur->addr.p.dyn->pfid_mask4; - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 && - (rpool->opts & PF_POOL_TYPEMASK) != - PF_POOL_ROUNDROBIN) - return (1); - raddr = &rpool->cur->addr.p.dyn->pfid_addr6; - rmask = &rpool->cur->addr.p.dyn->pfid_mask6; - break; -#endif /* INET6 */ - } - } else if (rpool->cur->addr.type == PF_ADDR_TABLE) { - if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) - return (1); /* unsupported */ - } else { - raddr = &rpool->cur->addr.v.a.addr; - rmask = &rpool->cur->addr.v.a.mask; - } - - switch (rpool->opts & PF_POOL_TYPEMASK) { - case PF_POOL_NONE: - PF_ACPY(naddr, raddr, af); - break; - case PF_POOL_BITMASK: - PF_POOLMASK(naddr, raddr, rmask, saddr, af); - break; - case PF_POOL_RANDOM: - if (init_addr != NULL && PF_AZERO(init_addr, af)) { - switch (af) { -#ifdef INET - case AF_INET: - rpool->counter.addr32[0] = htonl(arc4random()); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (rmask->addr32[3] != 0xffffffff) - rpool->counter.addr32[3] = - htonl(arc4random()); - else - break; - if (rmask->addr32[2] != 0xffffffff) - rpool->counter.addr32[2] = - htonl(arc4random()); - else - break; - if (rmask->addr32[1] != 0xffffffff) - rpool->counter.addr32[1] = - htonl(arc4random()); - else - break; - if (rmask->addr32[0] != 0xffffffff) - rpool->counter.addr32[0] = - htonl(arc4random()); - break; -#endif /* INET6 */ - } - PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); - PF_ACPY(init_addr, naddr, af); - - } else { - PF_AINC(&rpool->counter, af); - PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); - } - break; - case PF_POOL_SRCHASH: - pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); - PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af); - break; - case PF_POOL_ROUNDROBIN: - if (rpool->cur->addr.type == PF_ADDR_TABLE) { - if (!pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) - goto get_addr; - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) - goto get_addr; - } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) - goto get_addr; - - try_next: - if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL) - rpool->cur = TAILQ_FIRST(&rpool->list); - if (rpool->cur->addr.type == PF_ADDR_TABLE) { - rpool->tblidx = -1; - if (pfr_pool_get(rpool->cur->addr.p.tbl, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) { - /* table contains no address of type 'af' */ - if (rpool->cur != acur) - goto try_next; - return (1); - } - } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { - rpool->tblidx = -1; - if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, - &rpool->tblidx, &rpool->counter, - &raddr, &rmask, af)) { - /* table contains no address of type 'af' */ - if (rpool->cur != acur) - goto try_next; - return (1); - } - } else { - raddr = &rpool->cur->addr.v.a.addr; - rmask = &rpool->cur->addr.v.a.mask; - PF_ACPY(&rpool->counter, raddr, af); - } - - get_addr: - PF_ACPY(naddr, &rpool->counter, af); - if (init_addr != NULL && PF_AZERO(init_addr, af)) - PF_ACPY(init_addr, naddr, af); - PF_AINC(&rpool->counter, af); - break; - } - if (*sn != NULL) - PF_ACPY(&(*sn)->raddr, naddr, af); - - if (pf_status.debug >= PF_DEBUG_MISC && - (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { - printf("pf_map_addr: selected address "); - pf_print_host(naddr, 0, af); - printf("\n"); - } - - return (0); -} - -int -pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, - struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, - struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, - struct pf_src_node **sn) -{ - struct pf_state_cmp key; - struct pf_addr init_addr; - u_int16_t cut; - - bzero(&init_addr, sizeof(init_addr)); - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) - return (1); - - if (proto == IPPROTO_ICMP) { - low = 1; - high = 65535; - } - - do { - key.af = af; - key.proto = proto; - PF_ACPY(&key.ext.addr, daddr, key.af); - PF_ACPY(&key.gwy.addr, naddr, key.af); - key.ext.port = dport; - - /* - * port search; start random, step; - * similar 2 portloop in in_pcbbind - */ - if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || - proto == IPPROTO_ICMP)) { - key.gwy.port = dport; - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) - return (0); - } else if (low == 0 && high == 0) { - key.gwy.port = *nport; - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) - return (0); - } else if (low == high) { - key.gwy.port = htons(low); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) { - *nport = htons(low); - return (0); - } - } else { - u_int16_t tmp; - - if (low > high) { - tmp = low; - low = high; - high = tmp; - } - /* low < high */ - cut = htonl(arc4random()) % (1 + high - low) + low; - /* low <= cut <= high */ - for (tmp = cut; tmp <= high; ++(tmp)) { - key.gwy.port = htons(tmp); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == - NULL) { - *nport = htons(tmp); - return (0); - } - } - for (tmp = cut - 1; tmp >= low; --(tmp)) { - key.gwy.port = htons(tmp); - if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == - NULL) { - *nport = htons(tmp); - return (0); - } - } - } - - switch (r->rpool.opts & PF_POOL_TYPEMASK) { - case PF_POOL_RANDOM: - case PF_POOL_ROUNDROBIN: - if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) - return (1); - break; - case PF_POOL_NONE: - case PF_POOL_SRCHASH: - case PF_POOL_BITMASK: - default: - return (1); - } - } while (! PF_AEQ(&init_addr, naddr, af) ); - - return (1); /* none available */ -} - -struct pf_rule * -pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, - int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport, - struct pf_addr *daddr, u_int16_t dport, int rs_num) -{ - struct pf_rule *r, *rm = NULL; - struct pf_ruleset *ruleset = NULL; - int tag = -1; - int rtableid = -1; - int asd = 0; - - r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); - while (r && rm == NULL) { - struct pf_rule_addr *src = NULL, *dst = NULL; - struct pf_addr_wrap *xdst = NULL; - - if (r->action == PF_BINAT && direction == PF_IN) { - src = &r->dst; - if (r->rpool.cur != NULL) - xdst = &r->rpool.cur->addr; - } else { - src = &r->src; - dst = &r->dst; - } - - r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) - r = r->skip[PF_SKIP_IFP].ptr; - else if (r->direction && r->direction != direction) - r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != pd->af) - r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != pd->proto) - r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, - src->neg, kif)) - r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR : - PF_SKIP_DST_ADDR].ptr; - else if (src->port_op && !pf_match_port(src->port_op, - src->port[0], src->port[1], sport)) - r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT : - PF_SKIP_DST_PORT].ptr; - else if (dst != NULL && - PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL)) - r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, - 0, NULL)) - r = TAILQ_NEXT(r, entries); - else if (dst != NULL && dst->port_op && - !pf_match_port(dst->port_op, dst->port[0], - dst->port[1], dport)) - r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) - r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto != - IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m, - off, pd->hdr.tcp), r->os_fingerprint))) - r = TAILQ_NEXT(r, entries); - else { - if (r->tag) - tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; - if (r->anchor == NULL) { - rm = r; - } else - pf_step_into_anchor(&asd, &ruleset, rs_num, - &r, NULL, NULL); - } - if (r == NULL) - pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, - NULL, NULL); - } - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) - return (NULL); - if (rm != NULL && (rm->action == PF_NONAT || - rm->action == PF_NORDR || rm->action == PF_NOBINAT)) - return (NULL); - return (rm); -} - -struct pf_rule * -pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, - struct pfi_kif *kif, struct pf_src_node **sn, - struct pf_addr *saddr, u_int16_t sport, - struct pf_addr *daddr, u_int16_t dport, - struct pf_addr *naddr, u_int16_t *nport) -{ - struct pf_rule *r = NULL; - - if (direction == PF_OUT) { - r = pf_match_translation(pd, m, off, direction, kif, saddr, - sport, daddr, dport, PF_RULESET_BINAT); - if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, - saddr, sport, daddr, dport, PF_RULESET_NAT); - } else { - r = pf_match_translation(pd, m, off, direction, kif, saddr, - sport, daddr, dport, PF_RULESET_RDR); - if (r == NULL) - r = pf_match_translation(pd, m, off, direction, kif, - saddr, sport, daddr, dport, PF_RULESET_BINAT); - } - - if (r != NULL) { - switch (r->action) { - case PF_NONAT: - case PF_NOBINAT: - case PF_NORDR: - return (NULL); - case PF_NAT: - if (pf_get_sport(pd->af, pd->proto, r, saddr, - daddr, dport, naddr, nport, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], sn)) { - DPFPRINTF(PF_DEBUG_MISC, - ("pf: NAT proxy port allocation " - "(%u-%u) failed\n", - r->rpool.proxy_port[0], - r->rpool.proxy_port[1])); - return (NULL); - } - break; - case PF_BINAT: - switch (direction) { - case PF_OUT: - if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ - switch (pd->af) { -#ifdef INET - case AF_INET: - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr4, - &r->rpool.cur->addr.p.dyn-> - pfid_mask4, - saddr, AF_INET); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (r->rpool.cur->addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->rpool.cur->addr.p.dyn-> - pfid_addr6, - &r->rpool.cur->addr.p.dyn-> - pfid_mask6, - saddr, AF_INET6); - break; -#endif /* INET6 */ - } - } else - PF_POOLMASK(naddr, - &r->rpool.cur->addr.v.a.addr, - &r->rpool.cur->addr.v.a.mask, - saddr, pd->af); - break; - case PF_IN: - if (r->src.addr.type == PF_ADDR_DYNIFTL) { - switch (pd->af) { -#ifdef INET - case AF_INET: - if (r->src.addr.p.dyn-> - pfid_acnt4 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr4, - &r->src.addr.p.dyn-> - pfid_mask4, - daddr, AF_INET); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (r->src.addr.p.dyn-> - pfid_acnt6 < 1) - return (NULL); - PF_POOLMASK(naddr, - &r->src.addr.p.dyn-> - pfid_addr6, - &r->src.addr.p.dyn-> - pfid_mask6, - daddr, AF_INET6); - break; -#endif /* INET6 */ - } - } else - PF_POOLMASK(naddr, - &r->src.addr.v.a.addr, - &r->src.addr.v.a.mask, daddr, - pd->af); - break; - } - break; - case PF_RDR: { - if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn)) - return (NULL); - if ((r->rpool.opts & PF_POOL_TYPEMASK) == - PF_POOL_BITMASK) - PF_POOLMASK(naddr, naddr, - &r->rpool.cur->addr.v.a.mask, daddr, - pd->af); - - if (r->rpool.proxy_port[1]) { - u_int32_t tmp_nport; - - tmp_nport = ((ntohs(dport) - - ntohs(r->dst.port[0])) % - (r->rpool.proxy_port[1] - - r->rpool.proxy_port[0] + 1)) + - r->rpool.proxy_port[0]; - - /* wrap around if necessary */ - if (tmp_nport > 65535) - tmp_nport -= 65535; - *nport = htons((u_int16_t)tmp_nport); - } else if (r->rpool.proxy_port[0]) - *nport = htons(r->rpool.proxy_port[0]); - break; - } - default: - return (NULL); - } - } - - return (r); -} - int #ifdef __FreeBSD__ pf_socket_lookup(int direction, struct pf_pdesc *pd, struct inpcb *inp_arg) @@ -2983,7 +2948,8 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) return (-1); pd->lookup.uid = UID_MAX; pd->lookup.gid = GID_MAX; - pd->lookup.pid = NO_PID; /* XXX: revisit */ + pd->lookup.pid = NO_PID; + #ifdef __FreeBSD__ if (inp_arg != NULL) { INP_LOCK_ASSERT(inp_arg); @@ -2992,6 +2958,7 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) return (1); } #endif + switch (pd->proto) { case IPPROTO_TCP: if (pd->hdr.tcp == NULL) @@ -3050,7 +3017,8 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) #else inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport); if (inp == NULL) { - inp = in_pcblookup_listen(tb, daddr->v4, dport, 0); + inp = in_pcblookup_listen(tb, daddr->v4, dport, 0, + NULL); if (inp == NULL) return (-1); } @@ -3077,7 +3045,8 @@ pf_socket_lookup(int direction, struct pf_pdesc *pd) inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6, dport); if (inp == NULL) { - inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0); + inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0, + NULL); if (inp == NULL) return (-1); } @@ -3147,7 +3116,11 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af) int hlen; u_int8_t hdr[60]; u_int8_t *opt, optlen; +#ifdef __FreeBSD__ u_int16_t mss = V_tcp_mssdflt; +#else + u_int16_t mss = tcp_mssdflt; +#endif hlen = th_off << 2; /* hlen <= sizeof(hdr) */ if (hlen <= sizeof(struct tcphdr)) @@ -3191,8 +3164,13 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) struct route_in6 ro6; #endif /* INET6 */ struct rtentry *rt = NULL; - int hlen = 0; /* make the compiler happy */ +#ifdef __FreeBSD__ + int hlen = 0; u_int16_t mss = V_tcp_mssdflt; +#else + int hlen; + u_int16_t mss = tcp_mssdflt; +#endif switch (af) { #ifdef INET @@ -3240,7 +3218,11 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer) if (rt && rt->rt_ifp) { mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr); +#ifdef __FreeBSD__ mss = max(V_tcp_mssdflt, mss); +#else + mss = max(tcp_mssdflt, mss); +#endif RTFREE(rt); } mss = min(mss, offer); @@ -3252,55 +3234,113 @@ void pf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr) { struct pf_rule *r = s->rule.ptr; + struct pf_src_node *sn = NULL; s->rt_kif = NULL; if (!r->rt || r->rt == PF_FASTROUTE) return; - switch (s->af) { + switch (s->key[PF_SK_WIRE]->af) { #ifdef INET case AF_INET: - pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, - &s->nat_src_node); + pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL, &sn); s->rt_kif = r->rpool.cur->kif; break; #endif /* INET */ #ifdef INET6 case AF_INET6: - pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, - &s->nat_src_node); + pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL, &sn); s->rt_kif = r->rpool.cur->kif; break; #endif /* INET6 */ } } +u_int32_t +pf_tcp_iss(struct pf_pdesc *pd) +{ + MD5_CTX ctx; + u_int32_t digest[4]; + +#ifdef __FreeBSD__ + if (V_pf_tcp_secret_init == 0) { + read_random(&V_pf_tcp_secret, sizeof(V_pf_tcp_secret)); + MD5Init(&V_pf_tcp_secret_ctx); + MD5Update(&V_pf_tcp_secret_ctx, V_pf_tcp_secret, + sizeof(V_pf_tcp_secret)); + V_pf_tcp_secret_init = 1; + } + + ctx = V_pf_tcp_secret_ctx; +#else + if (pf_tcp_secret_init == 0) { + arc4random_buf(pf_tcp_secret, sizeof(pf_tcp_secret)); + MD5Init(&pf_tcp_secret_ctx); + MD5Update(&pf_tcp_secret_ctx, pf_tcp_secret, + sizeof(pf_tcp_secret)); + pf_tcp_secret_init = 1; + } + + ctx = pf_tcp_secret_ctx; +#endif + + MD5Update(&ctx, (char *)&pd->hdr.tcp->th_sport, sizeof(u_short)); + MD5Update(&ctx, (char *)&pd->hdr.tcp->th_dport, sizeof(u_short)); + if (pd->af == AF_INET6) { + MD5Update(&ctx, (char *)&pd->src->v6, sizeof(struct in6_addr)); + MD5Update(&ctx, (char *)&pd->dst->v6, sizeof(struct in6_addr)); + } else { + MD5Update(&ctx, (char *)&pd->src->v4, sizeof(struct in_addr)); + MD5Update(&ctx, (char *)&pd->dst->v4, sizeof(struct in_addr)); + } + MD5Final((u_char *)digest, &ctx); +#ifdef __FreeBSD__ + V_pf_tcp_iss_off += 4096; +#define ISN_RANDOM_INCREMENT (4096 - 1) + return (digest[0] + (arc4random() & ISN_RANDOM_INCREMENT) + + V_pf_tcp_iss_off); +#undef ISN_RANDOM_INCREMENT +#else + pf_tcp_iss_off += 4096; + return (digest[0] + tcp_iss + pf_tcp_iss_off); +#endif +} + int -pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, +pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, -#ifdef __FreeBSD__ struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, +#ifdef __FreeBSD__ struct ifqueue *ifq, struct inpcb *inp) #else - struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) #endif { struct pf_rule *nr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst; - struct tcphdr *th = pd->hdr.tcp; - u_int16_t bport, nport = 0; sa_family_t af = pd->af; struct pf_rule *r, *a = NULL; struct pf_ruleset *ruleset = NULL; struct pf_src_node *nsn = NULL; + struct tcphdr *th = pd->hdr.tcp; + struct pf_state_key *skw = NULL, *sks = NULL; + struct pf_state_key *sk = NULL, *nk = NULL; u_short reason; - int rewrite = 0; + int rewrite = 0, hdrlen = 0; int tag = -1, rtableid = -1; - u_int16_t mss = V_tcp_mssdflt; int asd = 0; int match = 0; + int state_icmp = 0; +#ifdef __FreeBSD__ + u_int16_t sport = 0, dport = 0; + u_int16_t bproto_sum = 0, bip_sum = 0; +#else + u_int16_t sport, dport; + u_int16_t bproto_sum = 0, bip_sum; +#endif + u_int8_t icmptype = 0, icmpcode = 0; - if (pf_check_congestion(ifq)) { + + if (direction == PF_IN && pf_check_congestion(ifq)) { REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); } @@ -3308,44 +3348,193 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, #ifdef __FreeBSD__ if (inp != NULL) pd->lookup.done = pf_socket_lookup(direction, pd, inp); - else if (debug_pfugidhack) { + else if (V_debug_pfugidhack) { PF_UNLOCK(); DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n")); - pd->lookup.done = pf_socket_lookup(direction, pd, inp); + pd->lookup.done = pf_socket_lookup(direction, pd, inp); PF_LOCK(); } #endif + switch (pd->proto) { + case IPPROTO_TCP: + sport = th->th_sport; + dport = th->th_dport; + hdrlen = sizeof(*th); + break; + case IPPROTO_UDP: + sport = pd->hdr.udp->uh_sport; + dport = pd->hdr.udp->uh_dport; + hdrlen = sizeof(*pd->hdr.udp); + break; +#ifdef INET + case IPPROTO_ICMP: + if (pd->af != AF_INET) + break; + sport = dport = pd->hdr.icmp->icmp_id; + hdrlen = sizeof(*pd->hdr.icmp); + icmptype = pd->hdr.icmp->icmp_type; + icmpcode = pd->hdr.icmp->icmp_code; + + if (icmptype == ICMP_UNREACH || + icmptype == ICMP_SOURCEQUENCH || + icmptype == ICMP_REDIRECT || + icmptype == ICMP_TIMXCEED || + icmptype == ICMP_PARAMPROB) + state_icmp++; + break; +#endif /* INET */ +#ifdef INET6 + case IPPROTO_ICMPV6: + if (af != AF_INET6) + break; + sport = dport = pd->hdr.icmp6->icmp6_id; + hdrlen = sizeof(*pd->hdr.icmp6); + icmptype = pd->hdr.icmp6->icmp6_type; + icmpcode = pd->hdr.icmp6->icmp6_code; + + if (icmptype == ICMP6_DST_UNREACH || + icmptype == ICMP6_PACKET_TOO_BIG || + icmptype == ICMP6_TIME_EXCEEDED || + icmptype == ICMP6_PARAM_PROB) + state_icmp++; + break; +#endif /* INET6 */ + default: + sport = dport = hdrlen = 0; + break; + } + r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - if (direction == PF_OUT) { - bport = nport = th->th_sport; - /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, th->th_sport, daddr, th->th_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); - pf_change_ap(saddr, &th->th_sport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); - rewrite++; - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; + /* check packet for BINAT/NAT/RDR */ + if ((nr = pf_get_translation(pd, m, off, direction, kif, &nsn, + &skw, &sks, &sk, &nk, saddr, daddr, sport, dport)) != NULL) { + if (nk == NULL || sk == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto cleanup; } - } else { - bport = nport = th->th_dport; - /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, th->th_sport, daddr, th->th_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); - pf_change_ap(daddr, &th->th_dport, pd->ip_sum, - &th->th_sum, &pd->naddr, nport, 0, af); + + if (pd->ip_sum) + bip_sum = *pd->ip_sum; + + switch (pd->proto) { + case IPPROTO_TCP: + bproto_sum = th->th_sum; + pd->proto_sum = &th->th_sum; + + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + nk->port[pd->sidx] != sport) { + pf_change_ap(saddr, &th->th_sport, pd->ip_sum, + &th->th_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 0, af); + pd->sport = &th->th_sport; + sport = th->th_sport; + } + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + nk->port[pd->didx] != dport) { + pf_change_ap(daddr, &th->th_dport, pd->ip_sum, + &th->th_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 0, af); + dport = th->th_dport; + pd->dport = &th->th_dport; + } + rewrite++; + break; + case IPPROTO_UDP: + bproto_sum = pd->hdr.udp->uh_sum; + pd->proto_sum = &pd->hdr.udp->uh_sum; + + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], af) || + nk->port[pd->sidx] != sport) { + pf_change_ap(saddr, &pd->hdr.udp->uh_sport, + pd->ip_sum, &pd->hdr.udp->uh_sum, + &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, af); + sport = pd->hdr.udp->uh_sport; + pd->sport = &pd->hdr.udp->uh_sport; + } + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], af) || + nk->port[pd->didx] != dport) { + pf_change_ap(daddr, &pd->hdr.udp->uh_dport, + pd->ip_sum, &pd->hdr.udp->uh_sum, + &nk->addr[pd->didx], + nk->port[pd->didx], 1, af); + dport = pd->hdr.udp->uh_dport; + pd->dport = &pd->hdr.udp->uh_dport; + } rewrite++; - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; + break; +#ifdef INET + case IPPROTO_ICMP: + nk->port[0] = nk->port[1]; + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET)) + pf_change_a(&saddr->v4.s_addr, pd->ip_sum, + nk->addr[pd->sidx].v4.s_addr, 0); + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET)) + pf_change_a(&daddr->v4.s_addr, pd->ip_sum, + nk->addr[pd->didx].v4.s_addr, 0); + + if (nk->port[1] != pd->hdr.icmp->icmp_id) { + pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( + pd->hdr.icmp->icmp_cksum, sport, + nk->port[1], 0); + pd->hdr.icmp->icmp_id = nk->port[1]; + pd->sport = &pd->hdr.icmp->icmp_id; + } + m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); + break; +#endif /* INET */ +#ifdef INET6 + case IPPROTO_ICMPV6: + nk->port[0] = nk->port[1]; + if (PF_ANEQ(saddr, &nk->addr[pd->sidx], AF_INET6)) + pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->sidx], 0); + + if (PF_ANEQ(daddr, &nk->addr[pd->didx], AF_INET6)) + pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->didx], 0); + rewrite++; + break; +#endif /* INET */ + default: + switch (af) { +#ifdef INET + case AF_INET: + if (PF_ANEQ(saddr, + &nk->addr[pd->sidx], AF_INET)) + pf_change_a(&saddr->v4.s_addr, + pd->ip_sum, + nk->addr[pd->sidx].v4.s_addr, 0); + + if (PF_ANEQ(daddr, + &nk->addr[pd->didx], AF_INET)) + pf_change_a(&daddr->v4.s_addr, + pd->ip_sum, + nk->addr[pd->didx].v4.s_addr, 0); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (PF_ANEQ(saddr, + &nk->addr[pd->sidx], AF_INET6)) + PF_ACPY(saddr, &nk->addr[pd->sidx], af); + + if (PF_ANEQ(daddr, + &nk->addr[pd->didx], AF_INET6)) + PF_ACPY(saddr, &nk->addr[pd->didx], af); + break; +#endif /* INET */ + } + break; } + if (nr->natpass) + r = NULL; + pd->nat_rule = nr; } while (r != NULL) { @@ -3356,26 +3545,36 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, r = r->skip[PF_SKIP_DIR].ptr; else if (r->af && r->af != af) r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != IPPROTO_TCP) + else if (r->proto && r->proto != pd->proto) r = r->skip[PF_SKIP_PROTO].ptr; else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg, kif)) r = r->skip[PF_SKIP_SRC_ADDR].ptr; + /* tcp/udp only. port_op always 0 in other cases */ else if (r->src.port_op && !pf_match_port(r->src.port_op, - r->src.port[0], r->src.port[1], th->th_sport)) + r->src.port[0], r->src.port[1], sport)) r = r->skip[PF_SKIP_SRC_PORT].ptr; else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg, NULL)) r = r->skip[PF_SKIP_DST_ADDR].ptr; + /* tcp/udp only. port_op always 0 in other cases */ else if (r->dst.port_op && !pf_match_port(r->dst.port_op, - r->dst.port[0], r->dst.port[1], th->th_dport)) + r->dst.port[0], r->dst.port[1], dport)) r = r->skip[PF_SKIP_DST_PORT].ptr; + /* icmp only. type always 0 in other cases */ + else if (r->type && r->type != icmptype + 1) + r = TAILQ_NEXT(r, entries); + /* icmp only. type always 0 in other cases */ + else if (r->code && r->code != icmpcode + 1) + r = TAILQ_NEXT(r, entries); else if (r->tos && !(r->tos == pd->tos)) r = TAILQ_NEXT(r, entries); else if (r->rule_flag & PFRULE_FRAGMENT) r = TAILQ_NEXT(r, entries); - else if ((r->flagset & th->th_flags) != r->flags) + else if (pd->proto == IPPROTO_TCP && + (r->flagset & th->th_flags) != r->flags) r = TAILQ_NEXT(r, entries); + /* tcp/udp only. uid.op always 0 in other cases */ else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = #ifdef __FreeBSD__ pf_socket_lookup(direction, pd, inp), 1)) && @@ -3385,6 +3584,7 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], pd->lookup.uid)) r = TAILQ_NEXT(r, entries); + /* tcp/udp only. gid.op always 0 in other cases */ else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = #ifdef __FreeBSD__ pf_socket_lookup(direction, pd, inp), 1)) && @@ -3394,12 +3594,23 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], pd->lookup.gid)) r = TAILQ_NEXT(r, entries); - else if (r->prob && r->prob <= arc4random()) + else if (r->prob && +#ifdef __FreeBSD__ + r->prob <= arc4random()) +#else + r->prob <= arc4random_uniform(UINT_MAX - 1) + 1) +#endif r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) +#ifdef __FreeBSD__ + else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) +#else + else if (r->match_tag && !pf_match_tag(m, r, &tag)) +#endif r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match( - pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint)) + else if (r->os_fingerprint != PF_OSFP_ANY && + (pd->proto != IPPROTO_TCP || !pf_osfp_match( + pf_osfp_fingerprint(pd, m, off, th), + r->os_fingerprint))) r = TAILQ_NEXT(r, entries); else { if (r->tag) @@ -3428,13 +3639,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, REASON_SET(&reason, PFRES_MATCH); - if (r->log || (nr != NULL && nr->natpass && nr->log)) { + if (r->log || (nr != NULL && nr->log)) { if (rewrite) -#ifdef __FreeBSD__ - m_copyback(m, off, sizeof(*th), (caddr_t)th); -#else - m_copyback(m, off, sizeof(*th), th); -#endif + m_copyback(m, off, hdrlen, pd->hdr.any); PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, a, ruleset, pd); } @@ -3445,161 +3652,233 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction, (r->rule_flag & PFRULE_RETURN))) { /* undo NAT changes, if they have taken place */ if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &th->th_sport, pd->ip_sum, - &th->th_sum, &pd->baddr, bport, 0, af); - rewrite++; - } else { - pf_change_ap(daddr, &th->th_dport, pd->ip_sum, - &th->th_sum, &pd->baddr, bport, 0, af); - rewrite++; - } - } - if (((r->rule_flag & PFRULE_RETURNRST) || + PF_ACPY(saddr, &sk->addr[pd->sidx], af); + PF_ACPY(daddr, &sk->addr[pd->didx], af); + if (pd->sport) + *pd->sport = sk->port[pd->sidx]; + if (pd->dport) + *pd->dport = sk->port[pd->didx]; + if (pd->proto_sum) + *pd->proto_sum = bproto_sum; + if (pd->ip_sum) + *pd->ip_sum = bip_sum; + m_copyback(m, off, hdrlen, pd->hdr.any); + } + if (pd->proto == IPPROTO_TCP && + ((r->rule_flag & PFRULE_RETURNRST) || (r->rule_flag & PFRULE_RETURN)) && !(th->th_flags & TH_RST)) { - u_int32_t ack = ntohl(th->th_seq) + pd->p_len; + u_int32_t ack = ntohl(th->th_seq) + pd->p_len; + int len = 0; +#ifdef INET + struct ip *h4; +#endif +#ifdef INET6 + struct ip6_hdr *h6; +#endif + + switch (af) { +#ifdef INET + case AF_INET: + h4 = mtod(m, struct ip *); + len = ntohs(h4->ip_len) - off; + break; +#endif +#ifdef INET6 + case AF_INET6: + h6 = mtod(m, struct ip6_hdr *); + len = ntohs(h6->ip6_plen) - (off - sizeof(*h6)); + break; +#endif + } - if (th->th_flags & TH_SYN) - ack++; - if (th->th_flags & TH_FIN) - ack++; + if (pf_check_proto_cksum(m, off, len, IPPROTO_TCP, af)) + REASON_SET(&reason, PFRES_PROTCKSUM); + else { + if (th->th_flags & TH_SYN) + ack++; + if (th->th_flags & TH_FIN) + ack++; #ifdef __FreeBSD__ - pf_send_tcp(m, r, af, pd->dst, + pf_send_tcp(m, r, af, pd->dst, #else - pf_send_tcp(r, af, pd->dst, + pf_send_tcp(r, af, pd->dst, #endif - pd->src, th->th_dport, th->th_sport, - ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, - r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); - } else if ((af == AF_INET) && r->return_icmp) + pd->src, th->th_dport, th->th_sport, + ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0, + r->return_ttl, 1, 0, pd->eh, kif->pfik_ifp); + } + } else if (pd->proto != IPPROTO_ICMP && af == AF_INET && + r->return_icmp) pf_send_icmp(m, r->return_icmp >> 8, r->return_icmp & 255, af, r); - else if ((af == AF_INET6) && r->return_icmp6) + else if (pd->proto != IPPROTO_ICMPV6 && af == AF_INET6 && + r->return_icmp6) pf_send_icmp(m, r->return_icmp6 >> 8, r->return_icmp6 & 255, af, r); } if (r->action == PF_DROP) - return (PF_DROP); + goto cleanup; - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { +#ifdef __FreeBSD__ + if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag)) { +#else + if (pf_tag_packet(m, tag, rtableid)) { +#endif REASON_SET(&reason, PFRES_MEMORY); - return (PF_DROP); + goto cleanup; } - if (r->keep_state || nr != NULL || - (pd->flags & PFDESC_TCP_NORM)) { - /* create new state */ - u_int16_t len; - struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; + if (!state_icmp && (r->keep_state || nr != NULL || + (pd->flags & PFDESC_TCP_NORM))) { + int action; + action = pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m, + off, sport, dport, &rewrite, kif, sm, tag, bproto_sum, + bip_sum, hdrlen); + if (action != PF_PASS) + return (action); + } else { +#ifdef __FreeBSD__ + if (sk != NULL) + pool_put(&V_pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&V_pf_state_key_pl, nk); +#else + if (sk != NULL) + pool_put(&pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&pf_state_key_pl, nk); +#endif + } - len = pd->tot_len - off - (th->th_off << 2); + /* copy back packet headers if we performed NAT operations */ + if (rewrite) + m_copyback(m, off, hdrlen, pd->hdr.any); + +#if NPFSYNC > 0 + if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) && +#ifdef __FreeBSD__ + direction == PF_OUT && pfsync_up_ptr != NULL && pfsync_up_ptr()) { +#else + direction == PF_OUT && pfsync_up()) { +#endif + /* + * We want the state created, but we dont + * want to send this in case a partner + * firewall has to know about it to allow + * replies through it. + */ +#ifdef __FreeBSD__ + if (pfsync_defer_ptr != NULL) + pfsync_defer_ptr(*sm, m); +#else + if (pfsync_defer(*sm, m)) +#endif + return (PF_DEFER); + } +#endif + + return (PF_PASS); - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) { - pf_status.lcounters[LCNT_STATES]++; - REASON_SET(&reason, PFRES_MAXSTATES); - goto cleanup; - } - /* src node for filter rule */ - if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&sn, r, saddr, af) != 0) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - s = pool_get(&pf_state_pl, PR_NOWAIT); - if (s == NULL) { - REASON_SET(&reason, PFRES_MEMORY); cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } - return (PF_DROP); - } - bzero(s, sizeof(*s)); - s->rule.ptr = r; - s->nat_rule.ptr = nr; - s->anchor.ptr = a; - STATE_INC_COUNTERS(s); - if (r->allow_opts) - s->state_flags |= PFSTATE_ALLOWOPTS; - if (r->rule_flag & PFRULE_STATESLOPPY) - s->state_flags |= PFSTATE_SLOPPY; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; - s->proto = IPPROTO_TCP; - s->direction = direction; - s->af = af; - if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = th->th_sport; /* sport */ - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = th->th_dport; - if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; - } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; - } - } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = th->th_dport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = th->th_sport; - if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; - } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; - } - } +#ifdef __FreeBSD__ + if (sk != NULL) + pool_put(&V_pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&V_pf_state_key_pl, nk); +#else + if (sk != NULL) + pool_put(&pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&pf_state_key_pl, nk); +#endif + return (PF_DROP); +} +static __inline int +pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a, + struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw, + struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk, + struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite, + struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum, + u_int16_t bip_sum, int hdrlen) +{ + struct pf_state *s = NULL; + struct pf_src_node *sn = NULL; + struct tcphdr *th = pd->hdr.tcp; +#ifdef __FreeBSD__ + u_int16_t mss = V_tcp_mssdflt; +#else + u_int16_t mss = tcp_mssdflt; +#endif + u_short reason; + + /* check maximums */ + if (r->max_states && (r->states_cur >= r->max_states)) { +#ifdef __FreeBSD__ + V_pf_status.lcounters[LCNT_STATES]++; +#else + pf_status.lcounters[LCNT_STATES]++; +#endif + REASON_SET(&reason, PFRES_MAXSTATES); + return (PF_DROP); + } + /* src node for filter rule */ + if ((r->rule_flag & PFRULE_SRCTRACK || + r->rpool.opts & PF_POOL_STICKYADDR) && + pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) { + REASON_SET(&reason, PFRES_SRCLIMIT); + goto csfailed; + } + /* src node for translation rule */ + if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && + pf_insert_src_node(&nsn, nr, &sk->addr[pd->sidx], pd->af)) { + REASON_SET(&reason, PFRES_SRCLIMIT); + goto csfailed; + } +#ifdef __FreeBSD__ + s = pool_get(&V_pf_state_pl, PR_NOWAIT | PR_ZERO); +#else + s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO); +#endif + if (s == NULL) { + REASON_SET(&reason, PFRES_MEMORY); + goto csfailed; + } + s->rule.ptr = r; + s->nat_rule.ptr = nr; + s->anchor.ptr = a; + STATE_INC_COUNTERS(s); + if (r->allow_opts) + s->state_flags |= PFSTATE_ALLOWOPTS; + if (r->rule_flag & PFRULE_STATESLOPPY) + s->state_flags |= PFSTATE_SLOPPY; + if (r->rule_flag & PFRULE_PFLOW) + s->state_flags |= PFSTATE_PFLOW; + s->log = r->log & PF_LOG_ALL; + s->sync_state = PFSYNC_S_NONE; + if (nr != NULL) + s->log |= nr->log & PF_LOG_ALL; + switch (pd->proto) { + case IPPROTO_TCP: s->src.seqlo = ntohl(th->th_seq); - s->src.seqhi = s->src.seqlo + len + 1; + s->src.seqhi = s->src.seqlo + pd->p_len + 1; if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && r->keep_state == PF_STATE_MODULATE) { /* Generate sequence number modulator */ -#ifdef __FreeBSD__ - while ((s->src.seqdiff = - pf_new_isn(s) - s->src.seqlo) == 0) - ; -#else - while ((s->src.seqdiff = - tcp_rndiss_next() - s->src.seqlo) == 0) - ; -#endif + if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) == + 0) + s->src.seqdiff = 1; pf_change_a(&th->th_seq, &th->th_sum, htonl(s->src.seqlo + s->src.seqdiff), 0); - rewrite = 1; + *rewrite = 1; } else s->src.seqdiff = 0; if (th->th_flags & TH_SYN) { s->src.seqhi++; - s->src.wscale = pf_get_wscale(m, off, th->th_off, af); + s->src.wscale = pf_get_wscale(m, off, + th->th_off, pd->af); } s->src.max_win = MAX(ntohs(th->th_win), 1); if (s->src.wscale & PF_WSCALE_MASK) { @@ -3615,994 +3894,173 @@ cleanup: s->dst.max_win = 1; s->src.state = TCPS_SYN_SENT; s->dst.state = TCPS_CLOSED; - s->creation = time_second; - s->expire = time_second; s->timeout = PFTM_TCP_FIRST_PACKET; - pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } + break; + case IPPROTO_UDP: + s->src.state = PFUDPS_SINGLE; + s->dst.state = PFUDPS_NO_TRAFFIC; + s->timeout = PFTM_UDP_FIRST_PACKET; + break; + case IPPROTO_ICMP: +#ifdef INET6 + case IPPROTO_ICMPV6: +#endif + s->timeout = PFTM_ICMP_FIRST_PACKET; + break; + default: + s->src.state = PFOTHERS_SINGLE; + s->dst.state = PFOTHERS_NO_TRAFFIC; + s->timeout = PFTM_OTHER_FIRST_PACKET; + } + + s->creation = time_second; + s->expire = time_second; + + if (sn != NULL) { + s->src_node = sn; + s->src_node->states++; + } + if (nsn != NULL) { + /* XXX We only modify one side for now. */ + PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); + s->nat_src_node = nsn; + s->nat_src_node->states++; + } + if (pd->proto == IPPROTO_TCP) { if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, off, pd, th, &s->src, &s->dst)) { REASON_SET(&reason, PFRES_MEMORY); pf_src_tree_remove_state(s); STATE_DEC_COUNTERS(s); +#ifdef __FreeBSD__ + pool_put(&V_pf_state_pl, s); +#else pool_put(&pf_state_pl, s); +#endif return (PF_DROP); } if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub && pf_normalize_tcp_stateful(m, off, pd, &reason, th, s, - &s->src, &s->dst, &rewrite)) { + &s->src, &s->dst, rewrite)) { /* This really shouldn't happen!!! */ DPFPRINTF(PF_DEBUG_URGENT, ("pf_normalize_tcp_stateful failed on first pkt")); pf_normalize_tcp_cleanup(s); pf_src_tree_remove_state(s); STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { - pf_normalize_tcp_cleanup(s); - REASON_SET(&reason, PFRES_STATEINS); - pf_src_tree_remove_state(s); - STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); - } else - *sm = s; - if (tag > 0) { - pf_tag_ref(tag); - s->tag = tag; - } - if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN && - r->keep_state == PF_STATE_SYNPROXY) { - s->src.state = PF_TCPS_PROXY_SRC; - if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &th->th_sport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - } else { - pf_change_ap(daddr, &th->th_dport, - pd->ip_sum, &th->th_sum, &pd->baddr, - bport, 0, af); - } - } - s->src.seqhi = htonl(arc4random()); - /* Find mss option */ - mss = pf_get_mss(m, off, th->th_off, af); - mss = pf_calc_mss(saddr, af, mss); - mss = pf_calc_mss(daddr, af, mss); - s->src.mss = mss; #ifdef __FreeBSD__ - pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport, + pool_put(&V_pf_state_pl, s); #else - pf_send_tcp(r, af, daddr, saddr, th->th_dport, + pool_put(&pf_state_pl, s); #endif - th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, - TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); - REASON_SET(&reason, PFRES_SYNPROXY); - return (PF_SYNPROXY_DROP); + return (PF_DROP); } } + s->direction = pd->dir; - /* copy back packet headers if we performed NAT operations */ - if (rewrite) - m_copyback(m, off, sizeof(*th), (caddr_t)th); - - return (PF_PASS); -} + if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk, + pd->src, pd->dst, sport, dport)) + goto csfailed; -int -pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction, - struct pfi_kif *kif, struct mbuf *m, int off, void *h, + if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) { + if (pd->proto == IPPROTO_TCP) + pf_normalize_tcp_cleanup(s); + REASON_SET(&reason, PFRES_STATEINS); + pf_src_tree_remove_state(s); + STATE_DEC_COUNTERS(s); #ifdef __FreeBSD__ - struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, - struct ifqueue *ifq, struct inpcb *inp) + pool_put(&V_pf_state_pl, s); #else - struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, - struct ifqueue *ifq) + pool_put(&pf_state_pl, s); #endif -{ - struct pf_rule *nr = NULL; - struct pf_addr *saddr = pd->src, *daddr = pd->dst; - struct udphdr *uh = pd->hdr.udp; - u_int16_t bport, nport = 0; - sa_family_t af = pd->af; - struct pf_rule *r, *a = NULL; - struct pf_ruleset *ruleset = NULL; - struct pf_src_node *nsn = NULL; - u_short reason; - int rewrite = 0; - int tag = -1, rtableid = -1; - int asd = 0; - int match = 0; - - if (pf_check_congestion(ifq)) { - REASON_SET(&reason, PFRES_CONGEST); return (PF_DROP); - } + } else + *sm = s; -#ifdef __FreeBSD__ - if (inp != NULL) - pd->lookup.done = pf_socket_lookup(direction, pd, inp); - else if (debug_pfugidhack) { - PF_UNLOCK(); - DPFPRINTF(PF_DEBUG_MISC, ("pf: unlocked lookup\n")); - pd->lookup.done = pf_socket_lookup(direction, pd, inp); - PF_LOCK(); + pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */ + if (tag > 0) { + pf_tag_ref(tag); + s->tag = tag; } + if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) == + TH_SYN && r->keep_state == PF_STATE_SYNPROXY) { + s->src.state = PF_TCPS_PROXY_SRC; + /* undo NAT changes, if they have taken place */ + if (nr != NULL) { + struct pf_state_key *skt = s->key[PF_SK_WIRE]; + if (pd->dir == PF_OUT) + skt = s->key[PF_SK_STACK]; + PF_ACPY(pd->src, &skt->addr[pd->sidx], pd->af); + PF_ACPY(pd->dst, &skt->addr[pd->didx], pd->af); + if (pd->sport) + *pd->sport = skt->port[pd->sidx]; + if (pd->dport) + *pd->dport = skt->port[pd->didx]; + if (pd->proto_sum) + *pd->proto_sum = bproto_sum; + if (pd->ip_sum) + *pd->ip_sum = bip_sum; + m_copyback(m, off, hdrlen, pd->hdr.any); + } + s->src.seqhi = htonl(arc4random()); + /* Find mss option */ + mss = pf_get_mss(m, off, th->th_off, pd->af); + mss = pf_calc_mss(pd->src, pd->af, mss); + mss = pf_calc_mss(pd->dst, pd->af, mss); + s->src.mss = mss; +#ifdef __FreeBSD__ + pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport, +#else + pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport, #endif - - r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - - if (direction == PF_OUT) { - bport = nport = uh->uh_sport; - /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, uh->uh_sport, daddr, uh->uh_dport, - &pd->naddr, &nport)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); - pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &pd->naddr, nport, 1, af); - rewrite++; - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } else { - bport = nport = uh->uh_dport; - /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr, - &nport)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); - pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &pd->naddr, nport, 1, af); - rewrite++; - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } + th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1, + TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL); + REASON_SET(&reason, PFRES_SYNPROXY); + return (PF_SYNPROXY_DROP); } - while (r != NULL) { - r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) - r = r->skip[PF_SKIP_IFP].ptr; - else if (r->direction && r->direction != direction) - r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != af) - r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != IPPROTO_UDP) - r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, - r->src.neg, kif)) - r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (r->src.port_op && !pf_match_port(r->src.port_op, - r->src.port[0], r->src.port[1], uh->uh_sport)) - r = r->skip[PF_SKIP_SRC_PORT].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, - r->dst.neg, NULL)) - r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (r->dst.port_op && !pf_match_port(r->dst.port_op, - r->dst.port[0], r->dst.port[1], uh->uh_dport)) - r = r->skip[PF_SKIP_DST_PORT].ptr; - else if (r->tos && !(r->tos == pd->tos)) - r = TAILQ_NEXT(r, entries); - else if (r->rule_flag & PFRULE_FRAGMENT) - r = TAILQ_NEXT(r, entries); - else if (r->uid.op && (pd->lookup.done || (pd->lookup.done = + return (PF_PASS); + +csfailed: #ifdef __FreeBSD__ - pf_socket_lookup(direction, pd, inp), 1)) && + if (sk != NULL) + pool_put(&V_pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&V_pf_state_key_pl, nk); #else - pf_socket_lookup(direction, pd), 1)) && + if (sk != NULL) + pool_put(&pf_state_key_pl, sk); + if (nk != NULL) + pool_put(&pf_state_key_pl, nk); #endif - !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1], - pd->lookup.uid)) - r = TAILQ_NEXT(r, entries); - else if (r->gid.op && (pd->lookup.done || (pd->lookup.done = + + if (sn != NULL && sn->states == 0 && sn->expire == 0) { #ifdef __FreeBSD__ - pf_socket_lookup(direction, pd, inp), 1)) && + RB_REMOVE(pf_src_tree, &V_tree_src_tracking, sn); + V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + V_pf_status.src_nodes--; + pool_put(&V_pf_src_tree_pl, sn); #else - pf_socket_lookup(direction, pd), 1)) && + RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); + pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + pf_status.src_nodes--; + pool_put(&pf_src_tree_pl, sn); #endif - !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1], - pd->lookup.gid)) - r = TAILQ_NEXT(r, entries); - else if (r->prob && r->prob <= arc4random()) - r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) - r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY) - r = TAILQ_NEXT(r, entries); - else { - if (r->tag) - tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; - if (r->anchor == NULL) { - match = 1; - *rm = r; - *am = a; - *rsm = ruleset; - if ((*rm)->quick) - break; - r = TAILQ_NEXT(r, entries); - } else - pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); - } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; } - r = *rm; - a = *am; - ruleset = *rsm; - - REASON_SET(&reason, PFRES_MATCH); - - if (r->log || (nr != NULL && nr->natpass && nr->log)) { - if (rewrite) + if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { #ifdef __FreeBSD__ - m_copyback(m, off, sizeof(*uh), (caddr_t)uh); + RB_REMOVE(pf_src_tree, &V_tree_src_tracking, nsn); + V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + V_pf_status.src_nodes--; + pool_put(&V_pf_src_tree_pl, nsn); #else - m_copyback(m, off, sizeof(*uh), uh); + RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); + pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; + pf_status.src_nodes--; + pool_put(&pf_src_tree_pl, nsn); #endif - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); - } - - if ((r->action == PF_DROP) && - ((r->rule_flag & PFRULE_RETURNICMP) || - (r->rule_flag & PFRULE_RETURN))) { - /* undo NAT changes, if they have taken place */ - if (nr != NULL) { - if (direction == PF_OUT) { - pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &pd->baddr, bport, 1, af); - rewrite++; - } else { - pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &pd->baddr, bport, 1, af); - rewrite++; - } - } - if ((af == AF_INET) && r->return_icmp) - pf_send_icmp(m, r->return_icmp >> 8, - r->return_icmp & 255, af, r); - else if ((af == AF_INET6) && r->return_icmp6) - pf_send_icmp(m, r->return_icmp6 >> 8, - r->return_icmp6 & 255, af, r); - } - - if (r->action == PF_DROP) - return (PF_DROP); - - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { - REASON_SET(&reason, PFRES_MEMORY); - return (PF_DROP); - } - - if (r->keep_state || nr != NULL) { - /* create new state */ - struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) { - pf_status.lcounters[LCNT_STATES]++; - REASON_SET(&reason, PFRES_MAXSTATES); - goto cleanup; - } - /* src node for filter rule */ - if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&sn, r, saddr, af) != 0) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - s = pool_get(&pf_state_pl, PR_NOWAIT); - if (s == NULL) { - REASON_SET(&reason, PFRES_MEMORY); -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } - return (PF_DROP); - } - bzero(s, sizeof(*s)); - s->rule.ptr = r; - s->nat_rule.ptr = nr; - s->anchor.ptr = a; - STATE_INC_COUNTERS(s); - if (r->allow_opts) - s->state_flags |= PFSTATE_ALLOWOPTS; - if (r->rule_flag & PFRULE_STATESLOPPY) - s->state_flags |= PFSTATE_SLOPPY; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; - s->proto = IPPROTO_UDP; - s->direction = direction; - s->af = af; - if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = uh->uh_sport; - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = uh->uh_dport; - if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; - } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; - } - } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = uh->uh_dport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = uh->uh_sport; - if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; - } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; - } - } - s->src.state = PFUDPS_SINGLE; - s->dst.state = PFUDPS_NO_TRAFFIC; - s->creation = time_second; - s->expire = time_second; - s->timeout = PFTM_UDP_FIRST_PACKET; - pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { - REASON_SET(&reason, PFRES_STATEINS); - pf_src_tree_remove_state(s); - STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); - } else - *sm = s; - if (tag > 0) { - pf_tag_ref(tag); - s->tag = tag; - } - } - - /* copy back packet headers if we performed NAT operations */ - if (rewrite) - m_copyback(m, off, sizeof(*uh), (caddr_t)uh); - - return (PF_PASS); -} - -int -pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction, - struct pfi_kif *kif, struct mbuf *m, int off, void *h, - struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm, - struct ifqueue *ifq) -{ - struct pf_rule *nr = NULL; - struct pf_addr *saddr = pd->src, *daddr = pd->dst; - struct pf_rule *r, *a = NULL; - struct pf_ruleset *ruleset = NULL; - struct pf_src_node *nsn = NULL; - u_short reason; - u_int16_t icmpid = 0, bport, nport = 0; - sa_family_t af = pd->af; - u_int8_t icmptype = 0; /* make the compiler happy */ - u_int8_t icmpcode = 0; /* make the compiler happy */ - int state_icmp = 0; - int tag = -1, rtableid = -1; -#ifdef INET6 - int rewrite = 0; -#endif /* INET6 */ - int asd = 0; - int match = 0; - - if (pf_check_congestion(ifq)) { - REASON_SET(&reason, PFRES_CONGEST); - return (PF_DROP); - } - - switch (pd->proto) { -#ifdef INET - case IPPROTO_ICMP: - icmptype = pd->hdr.icmp->icmp_type; - icmpcode = pd->hdr.icmp->icmp_code; - icmpid = pd->hdr.icmp->icmp_id; - - if (icmptype == ICMP_UNREACH || - icmptype == ICMP_SOURCEQUENCH || - icmptype == ICMP_REDIRECT || - icmptype == ICMP_TIMXCEED || - icmptype == ICMP_PARAMPROB) - state_icmp++; - break; -#endif /* INET */ -#ifdef INET6 - case IPPROTO_ICMPV6: - icmptype = pd->hdr.icmp6->icmp6_type; - icmpcode = pd->hdr.icmp6->icmp6_code; - icmpid = pd->hdr.icmp6->icmp6_id; - - if (icmptype == ICMP6_DST_UNREACH || - icmptype == ICMP6_PACKET_TOO_BIG || - icmptype == ICMP6_TIME_EXCEEDED || - icmptype == ICMP6_PARAM_PROB) - state_icmp++; - break; -#endif /* INET6 */ - } - - r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - - if (direction == PF_OUT) { - bport = nport = icmpid; - /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) != - NULL) { - PF_ACPY(&pd->baddr, saddr, af); - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); - pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, icmpid, nport, 0); - pd->hdr.icmp->icmp_id = nport; - m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); - rewrite++; - break; -#endif /* INET6 */ - } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } else { - bport = nport = icmpid; - /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) != - NULL) { - PF_ACPY(&pd->baddr, daddr, af); - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &pd->naddr, 0); - rewrite++; - break; -#endif /* INET6 */ - } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } - - while (r != NULL) { - r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) - r = r->skip[PF_SKIP_IFP].ptr; - else if (r->direction && r->direction != direction) - r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != af) - r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != pd->proto) - r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, saddr, af, - r->src.neg, kif)) - r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, - r->dst.neg, NULL)) - r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (r->type && r->type != icmptype + 1) - r = TAILQ_NEXT(r, entries); - else if (r->code && r->code != icmpcode + 1) - r = TAILQ_NEXT(r, entries); - else if (r->tos && !(r->tos == pd->tos)) - r = TAILQ_NEXT(r, entries); - else if (r->rule_flag & PFRULE_FRAGMENT) - r = TAILQ_NEXT(r, entries); - else if (r->prob && r->prob <= arc4random()) - r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) - r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY) - r = TAILQ_NEXT(r, entries); - else { - if (r->tag) - tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; - if (r->anchor == NULL) { - match = 1; - *rm = r; - *am = a; - *rsm = ruleset; - if ((*rm)->quick) - break; - r = TAILQ_NEXT(r, entries); - } else - pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); - } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; - } - r = *rm; - a = *am; - ruleset = *rsm; - - REASON_SET(&reason, PFRES_MATCH); - - if (r->log || (nr != NULL && nr->natpass && nr->log)) { -#ifdef INET6 - if (rewrite) - m_copyback(m, off, sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); -#endif /* INET6 */ - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); - } - - if (r->action != PF_PASS) - return (PF_DROP); - - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { - REASON_SET(&reason, PFRES_MEMORY); - return (PF_DROP); - } - - if (!state_icmp && (r->keep_state || nr != NULL)) { - /* create new state */ - struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) { - pf_status.lcounters[LCNT_STATES]++; - REASON_SET(&reason, PFRES_MAXSTATES); - goto cleanup; - } - /* src node for filter rule */ - if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&sn, r, saddr, af) != 0) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - s = pool_get(&pf_state_pl, PR_NOWAIT); - if (s == NULL) { - REASON_SET(&reason, PFRES_MEMORY); -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } - return (PF_DROP); - } - bzero(s, sizeof(*s)); - s->rule.ptr = r; - s->nat_rule.ptr = nr; - s->anchor.ptr = a; - STATE_INC_COUNTERS(s); - if (r->allow_opts) - s->state_flags |= PFSTATE_ALLOWOPTS; - if (r->rule_flag & PFRULE_STATESLOPPY) - s->state_flags |= PFSTATE_SLOPPY; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; - s->proto = pd->proto; - s->direction = direction; - s->af = af; - if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - s->gwy.port = nport; - PF_ACPY(&s->ext.addr, daddr, af); - s->ext.port = 0; - if (nr != NULL) { - PF_ACPY(&s->lan.addr, &pd->baddr, af); - s->lan.port = bport; - } else { - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - s->lan.port = s->gwy.port; - } - } else { - PF_ACPY(&s->lan.addr, daddr, af); - s->lan.port = nport; - PF_ACPY(&s->ext.addr, saddr, af); - s->ext.port = 0; - if (nr != NULL) { - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - s->gwy.port = bport; - } else { - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - s->gwy.port = s->lan.port; - } - } - s->creation = time_second; - s->expire = time_second; - s->timeout = PFTM_ICMP_FIRST_PACKET; - pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { - REASON_SET(&reason, PFRES_STATEINS); - pf_src_tree_remove_state(s); - STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); - } else - *sm = s; - if (tag > 0) { - pf_tag_ref(tag); - s->tag = tag; - } - } - -#ifdef INET6 - /* copy back packet headers if we performed IPv6 NAT operations */ - if (rewrite) - m_copyback(m, off, sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); -#endif /* INET6 */ - - return (PF_PASS); -} - -int -pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction, - struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, - struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq) -{ - struct pf_rule *nr = NULL; - struct pf_rule *r, *a = NULL; - struct pf_ruleset *ruleset = NULL; - struct pf_src_node *nsn = NULL; - struct pf_addr *saddr = pd->src, *daddr = pd->dst; - sa_family_t af = pd->af; - u_short reason; - int tag = -1, rtableid = -1; - int asd = 0; - int match = 0; - - if (pf_check_congestion(ifq)) { - REASON_SET(&reason, PFRES_CONGEST); - return (PF_DROP); - } - - r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr); - - if (direction == PF_OUT) { - /* check outgoing packet for BINAT/NAT */ - if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, saddr, af); - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - pd->naddr.v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(saddr, &pd->naddr, af); - break; -#endif /* INET6 */ - } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } else { - /* check incoming packet for BINAT/RDR */ - if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn, - saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) { - PF_ACPY(&pd->baddr, daddr, af); - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&daddr->v4.s_addr, - pd->ip_sum, pd->naddr.v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(daddr, &pd->naddr, af); - break; -#endif /* INET6 */ - } - if (nr->natpass) - r = NULL; - pd->nat_rule = nr; - } - } - - while (r != NULL) { - r->evaluations++; - if (pfi_kif_match(r->kif, kif) == r->ifnot) - r = r->skip[PF_SKIP_IFP].ptr; - else if (r->direction && r->direction != direction) - r = r->skip[PF_SKIP_DIR].ptr; - else if (r->af && r->af != af) - r = r->skip[PF_SKIP_AF].ptr; - else if (r->proto && r->proto != pd->proto) - r = r->skip[PF_SKIP_PROTO].ptr; - else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, - r->src.neg, kif)) - r = r->skip[PF_SKIP_SRC_ADDR].ptr; - else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, - r->dst.neg, NULL)) - r = r->skip[PF_SKIP_DST_ADDR].ptr; - else if (r->tos && !(r->tos == pd->tos)) - r = TAILQ_NEXT(r, entries); - else if (r->rule_flag & PFRULE_FRAGMENT) - r = TAILQ_NEXT(r, entries); - else if (r->prob && r->prob <= arc4random()) - r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) - r = TAILQ_NEXT(r, entries); - else if (r->os_fingerprint != PF_OSFP_ANY) - r = TAILQ_NEXT(r, entries); - else { - if (r->tag) - tag = r->tag; - if (r->rtableid >= 0) - rtableid = r->rtableid; - if (r->anchor == NULL) { - match = 1; - *rm = r; - *am = a; - *rsm = ruleset; - if ((*rm)->quick) - break; - r = TAILQ_NEXT(r, entries); - } else - pf_step_into_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match); - } - if (r == NULL && pf_step_out_of_anchor(&asd, &ruleset, - PF_RULESET_FILTER, &r, &a, &match)) - break; - } - r = *rm; - a = *am; - ruleset = *rsm; - - REASON_SET(&reason, PFRES_MATCH); - - if (r->log || (nr != NULL && nr->natpass && nr->log)) - PFLOG_PACKET(kif, h, m, af, direction, reason, r->log ? r : nr, - a, ruleset, pd); - - if ((r->action == PF_DROP) && - ((r->rule_flag & PFRULE_RETURNICMP) || - (r->rule_flag & PFRULE_RETURN))) { - struct pf_addr *a = NULL; - - if (nr != NULL) { - if (direction == PF_OUT) - a = saddr; - else - a = daddr; - } - if (a != NULL) { - switch (af) { -#ifdef INET - case AF_INET: - pf_change_a(&a->v4.s_addr, pd->ip_sum, - pd->baddr.v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(a, &pd->baddr, af); - break; -#endif /* INET6 */ - } - } - if ((af == AF_INET) && r->return_icmp) - pf_send_icmp(m, r->return_icmp >> 8, - r->return_icmp & 255, af, r); - else if ((af == AF_INET6) && r->return_icmp6) - pf_send_icmp(m, r->return_icmp6 >> 8, - r->return_icmp6 & 255, af, r); - } - - if (r->action != PF_PASS) - return (PF_DROP); - - if (pf_tag_packet(m, pd->pf_mtag, tag, rtableid)) { - REASON_SET(&reason, PFRES_MEMORY); - return (PF_DROP); - } - - if (r->keep_state || nr != NULL) { - /* create new state */ - struct pf_state *s = NULL; - struct pf_src_node *sn = NULL; - - /* check maximums */ - if (r->max_states && (r->states >= r->max_states)) { - pf_status.lcounters[LCNT_STATES]++; - REASON_SET(&reason, PFRES_MAXSTATES); - goto cleanup; - } - /* src node for filter rule */ - if ((r->rule_flag & PFRULE_SRCTRACK || - r->rpool.opts & PF_POOL_STICKYADDR) && - pf_insert_src_node(&sn, r, saddr, af) != 0) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - /* src node for translation rule */ - if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) && - ((direction == PF_OUT && - pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) || - (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) { - REASON_SET(&reason, PFRES_SRCLIMIT); - goto cleanup; - } - s = pool_get(&pf_state_pl, PR_NOWAIT); - if (s == NULL) { - REASON_SET(&reason, PFRES_MEMORY); -cleanup: - if (sn != NULL && sn->states == 0 && sn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, sn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, sn); - } - if (nsn != sn && nsn != NULL && nsn->states == 0 && - nsn->expire == 0) { - RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn); - pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++; - pf_status.src_nodes--; - pool_put(&pf_src_tree_pl, nsn); - } - return (PF_DROP); - } - bzero(s, sizeof(*s)); - s->rule.ptr = r; - s->nat_rule.ptr = nr; - s->anchor.ptr = a; - STATE_INC_COUNTERS(s); - if (r->allow_opts) - s->state_flags |= PFSTATE_ALLOWOPTS; - if (r->rule_flag & PFRULE_STATESLOPPY) - s->state_flags |= PFSTATE_SLOPPY; - s->log = r->log & PF_LOG_ALL; - if (nr != NULL) - s->log |= nr->log & PF_LOG_ALL; - s->proto = pd->proto; - s->direction = direction; - s->af = af; - if (direction == PF_OUT) { - PF_ACPY(&s->gwy.addr, saddr, af); - PF_ACPY(&s->ext.addr, daddr, af); - if (nr != NULL) - PF_ACPY(&s->lan.addr, &pd->baddr, af); - else - PF_ACPY(&s->lan.addr, &s->gwy.addr, af); - } else { - PF_ACPY(&s->lan.addr, daddr, af); - PF_ACPY(&s->ext.addr, saddr, af); - if (nr != NULL) - PF_ACPY(&s->gwy.addr, &pd->baddr, af); - else - PF_ACPY(&s->gwy.addr, &s->lan.addr, af); - } - s->src.state = PFOTHERS_SINGLE; - s->dst.state = PFOTHERS_NO_TRAFFIC; - s->creation = time_second; - s->expire = time_second; - s->timeout = PFTM_OTHER_FIRST_PACKET; - pf_set_rt_ifp(s, saddr); - if (sn != NULL) { - s->src_node = sn; - s->src_node->states++; - } - if (nsn != NULL) { - PF_ACPY(&nsn->raddr, &pd->naddr, af); - s->nat_src_node = nsn; - s->nat_src_node->states++; - } - if (pf_insert_state(BOUND_IFACE(r, kif), s)) { - REASON_SET(&reason, PFRES_STATEINS); - pf_src_tree_remove_state(s); - STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); - } else - *sm = s; - if (tag > 0) { - pf_tag_ref(tag); - s->tag = tag; - } } - - return (PF_PASS); + return (PF_DROP); } int @@ -4649,9 +4107,14 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, pd->proto == IPPROTO_ICMPV6) && (r->type || r->code)) r = TAILQ_NEXT(r, entries); - else if (r->prob && r->prob <= arc4random()) + else if (r->prob && r->prob <= + (arc4random() % (UINT_MAX - 1) + 1)) r = TAILQ_NEXT(r, entries); - else if (r->match_tag && !pf_match_tag(m, r, pd->pf_mtag, &tag)) +#ifdef __FreeBSD__ + else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) +#else + else if (r->match_tag && !pf_match_tag(m, r, &tag)) +#endif r = TAILQ_NEXT(r, entries); else { if (r->anchor == NULL) { @@ -4683,7 +4146,11 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, if (r->action != PF_PASS) return (PF_DROP); - if (pf_tag_packet(m, pd->pf_mtag, tag, -1)) { +#ifdef __FreeBSD__ + if (pf_tag_packet(m, tag, -1, pd->pf_mtag)) { +#else + if (pf_tag_packet(m, tag, -1)) { +#endif REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -4696,11 +4163,11 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, struct pf_state **state, struct pfi_kif *kif, struct mbuf *m, int off, struct pf_pdesc *pd, u_short *reason, int *copyback) { - struct tcphdr *th = pd->hdr.tcp; - u_int16_t win = ntohs(th->th_win); - u_int32_t ack, end, seq, orig_seq; - u_int8_t sws, dws; - int ackskew; + struct tcphdr *th = pd->hdr.tcp; + u_int16_t win = ntohs(th->th_win); + u_int32_t ack, end, seq, orig_seq; + u_int8_t sws, dws; + int ackskew; if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) { sws = src->wscale & PF_WSCALE_MASK; @@ -4728,13 +4195,9 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, /* Deferred generation of sequence number modulator */ if (dst->seqdiff && !src->seqdiff) { -#ifdef __FreeBSD__ - while ((src->seqdiff = pf_new_isn(*state) - seq) == 0) - ; -#else - while ((src->seqdiff = tcp_rndiss_next() - seq) == 0) + /* use random iss for the TCP server */ + while ((src->seqdiff = arc4random() - seq) == 0) ; -#endif ack = ntohl(th->th_ack) - dst->seqdiff; pf_change_a(&th->th_seq, &th->th_sum, htonl(seq + src->seqdiff), 0); @@ -4841,7 +4304,7 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, } -#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ +#define MAXACKWINDOW (0xffff + 1500) /* 1500 is an arbitrary fudge factor */ if (SEQ_GEQ(src->seqhi, end) && /* Last octet inside other's window space */ SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) && @@ -4851,7 +4314,8 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, (ackskew <= (MAXACKWINDOW << sws)) && /* Acking not more than one window forward */ ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo || - (orig_seq == src->seqlo + 1) || (pd->flags & PFDESC_IP_REAS) == 0)) { + (orig_seq == src->seqlo + 1) || (orig_seq + 1 == src->seqlo) || + (pd->flags & PFDESC_IP_REAS) == 0)) { /* Require an exact/+1 sequence match on resets when possible */ if (dst->scrub || src->scrub) { @@ -4941,19 +4405,25 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, * and keep updating the state TTL. */ +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: loose state match: "); pf_print_state(*state); pf_print_flags(th->th_flags); printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " - "pkts=%llu:%llu\n", seq, orig_seq, ack, pd->p_len, + "pkts=%llu:%llu dir=%s,%s\n", seq, orig_seq, ack, #ifdef __FreeBSD__ - ackskew, (unsigned long long)(*state)->packets[0], - (unsigned long long)(*state)->packets[1]); + pd->p_len, ackskew, (unsigned long long)(*state)->packets[0], + (unsigned long long)(*state)->packets[1], #else - ackskew, (*state)->packets[0], - (*state)->packets[1]); + pd->p_len, ackskew, (*state)->packets[0], + (*state)->packets[1], #endif + pd->dir == PF_IN ? "in" : "out", + pd->dir == (*state)->direction ? "fwd" : "rev"); } if (dst->scrub || src->scrub) { @@ -4991,7 +4461,7 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, /* Send RST for state mismatches during handshake */ if (!(th->th_flags & TH_RST)) #ifdef __FreeBSD__ - pf_send_tcp(m, (*state)->rule.ptr, pd->af, + pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, #else pf_send_tcp((*state)->rule.ptr, pd->af, #endif @@ -5003,16 +4473,16 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, src->seqlo = 0; src->seqhi = 1; src->max_win = 1; +#ifdef __FreeBSD__ + } else if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else } else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: BAD state: "); pf_print_state(*state); pf_print_flags(th->th_flags); printf(" seq=%u (%u) ack=%u len=%u ackskew=%d " -#ifdef notyet "pkts=%llu:%llu dir=%s,%s\n", -#else - "pkts=%llu:%llu%s\n", -#endif seq, orig_seq, ack, pd->p_len, ackskew, #ifdef __FreeBSD__ (unsigned long long)(*state)->packets[0], @@ -5020,12 +4490,8 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, #else (*state)->packets[0], (*state)->packets[1], #endif -#ifdef notyet - direction == PF_IN ? "in" : "out", - direction == (*state)->direction ? "fwd" : "rev"); -#else - ""); -#endif + pd->dir == PF_IN ? "in" : "out", + pd->dir == (*state)->direction ? "fwd" : "rev"); printf("pf: State failure on: %c %c %c %c | %c %c\n", SEQ_GEQ(src->seqhi, end) ? ' ' : '1', SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ? @@ -5039,7 +4505,6 @@ pf_tcp_track_full(struct pf_state_peer *src, struct pf_state_peer *dst, return (PF_DROP); } - /* Any packets which have gotten here are to be passed */ return (PF_PASS); } @@ -5114,32 +4579,36 @@ pf_tcp_track_sloppy(struct pf_state_peer *src, struct pf_state_peer *dst, return (PF_PASS); } - int pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_state_cmp key; + struct pf_state_key_cmp key; struct tcphdr *th = pd->hdr.tcp; int copyback = 0; struct pf_state_peer *src, *dst; + struct pf_state_key *sk; key.af = pd->af; key.proto = IPPROTO_TCP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = th->th_sport; - key.gwy.port = th->th_dport; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = th->th_sport; - key.ext.port = th->th_dport; + if (direction == PF_IN) { /* wire side, straight */ + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = th->th_sport; + key.port[1] = th->th_dport; + } else { /* stack side, reverse */ + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = th->th_sport; + key.port[0] = th->th_dport; } - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif if (direction == (*state)->direction) { src = &(*state)->src; @@ -5149,6 +4618,8 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, dst = &(*state)->src; } + sk = (*state)->key[pd->didx]; + if ((*state)->src.state == PF_TCPS_PROXY_SRC) { if (direction != (*state)->direction) { REASON_SET(reason, PFRES_SYNPROXY); @@ -5183,15 +4654,6 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->src.state = PF_TCPS_PROXY_DST; } if ((*state)->src.state == PF_TCPS_PROXY_DST) { - struct pf_state_host *src, *dst; - - if (direction == PF_OUT) { - src = &(*state)->gwy; - dst = &(*state)->ext; - } else { - src = &(*state)->ext; - dst = &(*state)->lan; - } if (direction == (*state)->direction) { if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || @@ -5204,11 +4666,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->dst.seqhi = htonl(arc4random()); #ifdef __FreeBSD__ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, - &src->addr, #else - pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, + pf_send_tcp((*state)->rule.ptr, pd->af, #endif - &dst->addr, src->port, dst->port, + &sk->addr[pd->sidx], &sk->addr[pd->didx], + sk->port[pd->sidx], sk->port[pd->didx], (*state)->dst.seqhi, 0, TH_SYN, 0, (*state)->src.mss, 0, 0, (*state)->tag, NULL, NULL); REASON_SET(reason, PFRES_SYNPROXY); @@ -5232,11 +4694,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->tag, NULL, NULL); #ifdef __FreeBSD__ pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, - &src->addr, #else - pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr, + pf_send_tcp((*state)->rule.ptr, pd->af, #endif - &dst->addr, src->port, dst->port, + &sk->addr[pd->sidx], &sk->addr[pd->didx], + sk->port[pd->sidx], sk->port[pd->didx], (*state)->src.seqhi + 1, (*state)->src.seqlo + 1, TH_ACK, (*state)->dst.max_win, 0, 0, 1, 0, NULL, NULL); @@ -5259,7 +4721,11 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) && dst->state >= TCPS_FIN_WAIT_2 && src->state >= TCPS_FIN_WAIT_2) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: state reuse "); pf_print_state(*state); pf_print_flags(th->th_flags); @@ -5282,21 +4748,31 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif, } /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { - if (direction == PF_OUT) + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != th->th_sport) pf_change_ap(pd->src, &th->th_sport, pd->ip_sum, - &th->th_sum, &(*state)->gwy.addr, - (*state)->gwy.port, 0, pd->af); - else + &th->th_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 0, pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != th->th_dport) pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum, - &th->th_sum, &(*state)->lan.addr, - (*state)->lan.port, 0, pd->af); - m_copyback(m, off, sizeof(*th), (caddr_t)th); - } else if (copyback) { - /* Copyback sequence modulation or stateful scrub changes */ - m_copyback(m, off, sizeof(*th), (caddr_t)th); + &th->th_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 0, pd->af); + copyback = 1; } + /* Copyback sequence modulation or stateful scrub changes if needed */ + if (copyback) +#ifdef __FreeBSD__ + m_copyback(m, off, sizeof(*th), (caddr_t)th); +#else + m_copyback(m, off, sizeof(*th), th); +#endif + return (PF_PASS); } @@ -5305,24 +4781,28 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state_key_cmp key; struct udphdr *uh = pd->hdr.udp; key.af = pd->af; key.proto = IPPROTO_UDP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = uh->uh_sport; - key.gwy.port = uh->uh_dport; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = uh->uh_sport; - key.ext.port = uh->uh_dport; + if (direction == PF_IN) { /* wire side, straight */ + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = uh->uh_sport; + key.port[1] = uh->uh_dport; + } else { /* stack side, reverse */ + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = uh->uh_sport; + key.port[0] = uh->uh_dport; } - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif if (direction == (*state)->direction) { src = &(*state)->src; @@ -5346,16 +4826,25 @@ pf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_UDP_SINGLE; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { - if (direction == PF_OUT) + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], pd->af) || + nk->port[pd->sidx] != uh->uh_sport) pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum, - &uh->uh_sum, &(*state)->gwy.addr, - (*state)->gwy.port, 1, pd->af); - else + &uh->uh_sum, &nk->addr[pd->sidx], + nk->port[pd->sidx], 1, pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], pd->af) || + nk->port[pd->didx] != uh->uh_dport) pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum, - &uh->uh_sum, &(*state)->lan.addr, - (*state)->lan.port, 1, pd->af); + &uh->uh_sum, &nk->addr[pd->didx], + nk->port[pd->didx], 1, pd->af); +#ifdef __FreeBSD__ m_copyback(m, off, sizeof(*uh), (caddr_t)uh); +#else + m_copyback(m, off, sizeof(*uh), uh); +#endif } return (PF_PASS); @@ -5365,12 +4854,15 @@ int pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason) { - struct pf_addr *saddr = pd->src, *daddr = pd->dst; - u_int16_t icmpid = 0; /* make the compiler happy */ - u_int16_t *icmpsum = NULL; /* make the compiler happy */ - u_int8_t icmptype = 0; /* make the compiler happy */ + struct pf_addr *saddr = pd->src, *daddr = pd->dst; +#ifdef __FreeBSD__ + u_int16_t icmpid = 0, *icmpsum; +#else + u_int16_t icmpid, *icmpsum; +#endif + u_int8_t icmptype; int state_icmp = 0; - struct pf_state_cmp key; + struct pf_state_key_cmp key; switch (pd->proto) { #ifdef INET @@ -5410,84 +4902,84 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, */ key.af = pd->af; key.proto = pd->proto; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = 0; - key.gwy.port = icmpid; - } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = icmpid; - key.ext.port = 0; + key.port[0] = key.port[1] = icmpid; + if (direction == PF_IN) { /* wire side, straight */ + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + } else { /* stack side, reverse */ + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); } - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif (*state)->expire = time_second; (*state)->timeout = PFTM_ICMP_ERROR_REPLY; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { - if (direction == PF_OUT) { - switch (pd->af) { + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + + switch (pd->af) { #ifdef INET - case AF_INET: + case AF_INET: + if (PF_ANEQ(pd->src, + &nk->addr[pd->sidx], AF_INET)) pf_change_a(&saddr->v4.s_addr, pd->ip_sum, - (*state)->gwy.addr.v4.s_addr, 0); - pd->hdr.icmp->icmp_cksum = - pf_cksum_fixup( - pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->gwy.port, 0); - pd->hdr.icmp->icmp_id = - (*state)->gwy.port; - m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - pf_change_a6(saddr, - &pd->hdr.icmp6->icmp6_cksum, - &(*state)->gwy.addr, 0); - m_copyback(m, off, - sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); - break; -#endif /* INET6 */ - } - } else { - switch (pd->af) { -#ifdef INET - case AF_INET: + nk->addr[pd->sidx].v4.s_addr, 0); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], + AF_INET)) pf_change_a(&daddr->v4.s_addr, pd->ip_sum, - (*state)->lan.addr.v4.s_addr, 0); + nk->addr[pd->didx].v4.s_addr, 0); + + if (nk->port[0] != + pd->hdr.icmp->icmp_id) { pd->hdr.icmp->icmp_cksum = pf_cksum_fixup( pd->hdr.icmp->icmp_cksum, icmpid, - (*state)->lan.port, 0); + nk->port[pd->sidx], 0); pd->hdr.icmp->icmp_id = - (*state)->lan.port; - m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); - break; + nk->port[pd->sidx]; + } + + m_copyback(m, off, ICMP_MINLEN, +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: + case AF_INET6: + if (PF_ANEQ(pd->src, + &nk->addr[pd->sidx], AF_INET6)) + pf_change_a6(saddr, + &pd->hdr.icmp6->icmp6_cksum, + &nk->addr[pd->sidx], 0); + + if (PF_ANEQ(pd->dst, + &nk->addr[pd->didx], AF_INET6)) pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum, - &(*state)->lan.addr, 0); - m_copyback(m, off, - sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); - break; + &nk->addr[pd->didx], 0); + + m_copyback(m, off, + sizeof(struct icmp6_hdr), +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp6); + break; #endif /* INET6 */ - } } } - return (PF_PASS); } else { @@ -5497,6 +4989,9 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, */ struct pf_pdesc pd2; +#ifdef __FreeBSD__ + bzero(&pd2, sizeof pd2); +#endif #ifdef INET struct ip h2; #endif /* INET */ @@ -5504,10 +4999,18 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, struct ip6_hdr h2_6; int terminal = 0; #endif /* INET6 */ - int ipoff2 = 0; /* make the compiler happy */ - int off2 = 0; /* make the compiler happy */ +#ifdef __FreeBSD__ + int ipoff2 = 0; + int off2 = 0; +#else + int ipoff2; + int off2; +#endif pd2.af = pd->af; + /* Payload packet is from the opposite direction. */ + pd2.sidx = (direction == PF_IN) ? 1 : 0; + pd2.didx = (direction == PF_IN) ? 0 : 1; switch (pd->af) { #ifdef INET case AF_INET: @@ -5593,10 +5096,6 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } while (!terminal); break; #endif /* INET6 */ -#ifdef __FreeBSD__ - default: - panic("AF not supported: %d", pd->af); -#endif } switch (pd2.proto) { @@ -5622,19 +5121,16 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_TCP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = th.th_dport; - key.gwy.port = th.th_sport; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = th.th_dport; - key.ext.port = th.th_sport; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[pd2.sidx] = th.th_sport; + key.port[pd2.didx] = th.th_dport; - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif if (direction == (*state)->direction) { src = &(*state)->dst; @@ -5660,7 +5156,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, if (!((*state)->state_flags & PFSTATE_SLOPPY) && (!SEQ_GEQ(src->seqhi, seq) || !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)))) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif printf("pf: BAD ICMP %d:%d ", icmptype, pd->hdr.icmp->icmp_code); pf_print_host(pd->src, 0, pd->af); @@ -5672,22 +5172,47 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, } REASON_SET(reason, PFRES_BADSTATE); return (PF_DROP); + } else { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif + printf("pf: OK ICMP %d:%d ", + icmptype, pd->hdr.icmp->icmp_code); + pf_print_host(pd->src, 0, pd->af); + printf(" -> "); + pf_print_host(pd->dst, 0, pd->af); + printf(" state: "); + pf_print_state(*state); + printf(" seq=%u\n", seq); + } } - if (STATE_TRANSLATE(*state)) { - if (direction == PF_IN) { + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != th.th_sport) pf_change_icmp(pd2.src, &th.th_sport, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != th.th_dport) pf_change_icmp(pd2.dst, &th.th_dport, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } copyback = 1; } @@ -5696,22 +5221,38 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp); m_copyback(m, ipoff2, sizeof(h2), - (caddr_t)&h2); +#ifdef __FreeBSD__ + (caddr_t) +#endif + &h2); break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - (caddr_t)&h2_6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + &h2_6); break; #endif /* INET6 */ } +#ifdef __FreeBSD__ m_copyback(m, off2, 8, (caddr_t)&th); +#else + m_copyback(m, off2, 8, &th); +#endif } return (PF_PASS); @@ -5730,57 +5271,79 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_UDP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = uh.uh_dport; - key.gwy.port = uh.uh_sport; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = uh.uh_dport; - key.ext.port = uh.uh_sport; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[pd2.sidx] = uh.uh_sport; + key.port[pd2.didx] = uh.uh_dport; - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif - if (STATE_TRANSLATE(*state)) { - if (direction == PF_IN) { + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != uh.uh_sport) pf_change_icmp(pd2.src, &uh.uh_sport, - daddr, &(*state)->lan.addr, - (*state)->lan.port, &uh.uh_sum, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != uh.uh_dport) pf_change_icmp(pd2.dst, &uh.uh_dport, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, &uh.uh_sum, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], &uh.uh_sum, pd2.ip_sum, icmpsum, pd->ip_sum, 1, pd2.af); - } + switch (pd2.af) { #ifdef INET case AF_INET: m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), - (caddr_t)&h2); +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp); +#ifdef __FreeBSD__ + m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); +#else + m_copyback(m, ipoff2, sizeof(h2), &h2); +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - (caddr_t)&h2_6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + &h2_6); break; #endif /* INET6 */ } - m_copyback(m, off2, sizeof(uh), - (caddr_t)&uh); +#ifdef __FreeBSD__ + m_copyback(m, off2, sizeof(uh), (caddr_t)&uh); +#else + m_copyback(m, off2, sizeof(uh), &uh); +#endif } - return (PF_PASS); break; } @@ -5798,42 +5361,51 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_ICMP; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = 0; - key.gwy.port = iih.icmp_id; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = iih.icmp_id; - key.ext.port = 0; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = iih.icmp_id; - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif - if (STATE_TRANSLATE(*state)) { - if (direction == PF_IN) { + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; + + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != iih.icmp_id) pf_change_icmp(pd2.src, &iih.icmp_id, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != iih.icmp_id) pf_change_icmp(pd2.dst, &iih.icmp_id, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET); - } - m_copyback(m, off, ICMP_MINLEN, - (caddr_t)pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), - (caddr_t)&h2); - m_copyback(m, off2, ICMP_MINLEN, - (caddr_t)&iih); - } +#ifdef __FreeBSD__ + m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); + m_copyback(m, off2, ICMP_MINLEN, (caddr_t)&iih); +#else + m_copyback(m, off, ICMP_MINLEN, pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), &h2); + m_copyback(m, off2, ICMP_MINLEN, &iih); +#endif + } return (PF_PASS); break; } @@ -5852,42 +5424,55 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, key.af = pd2.af; key.proto = IPPROTO_ICMPV6; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = 0; - key.gwy.port = iih.icmp6_id; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = iih.icmp6_id; - key.ext.port = 0; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = iih.icmp6_id; - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif + + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; - if (STATE_TRANSLATE(*state)) { - if (direction == PF_IN) { + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af) || + nk->port[pd2.sidx] != iih.icmp6_id) pf_change_icmp(pd2.src, &iih.icmp6_id, - daddr, &(*state)->lan.addr, - (*state)->lan.port, NULL, + daddr, &nk->addr[pd2.sidx], + nk->port[pd2.sidx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); - } else { + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af) || + nk->port[pd2.didx] != iih.icmp6_id) pf_change_icmp(pd2.dst, &iih.icmp6_id, - saddr, &(*state)->gwy.addr, - (*state)->gwy.port, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], + nk->port[pd2.didx], NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, AF_INET6); - } + +#ifdef __FreeBSD__ m_copyback(m, off, sizeof(struct icmp6_hdr), (caddr_t)pd->hdr.icmp6); - m_copyback(m, ipoff2, sizeof(h2_6), - (caddr_t)&h2_6); + m_copyback(m, ipoff2, sizeof(h2_6), (caddr_t)&h2_6); m_copyback(m, off2, sizeof(struct icmp6_hdr), (caddr_t)&iih); +#else + m_copyback(m, off, sizeof(struct icmp6_hdr), + pd->hdr.icmp6); + m_copyback(m, ipoff2, sizeof(h2_6), &h2_6); + m_copyback(m, off2, sizeof(struct icmp6_hdr), + &iih); +#endif } - return (PF_PASS); break; } @@ -5895,55 +5480,68 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, default: { key.af = pd2.af; key.proto = pd2.proto; - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd2.dst, key.af); - PF_ACPY(&key.gwy.addr, pd2.src, key.af); - key.ext.port = 0; - key.gwy.port = 0; - } else { - PF_ACPY(&key.lan.addr, pd2.dst, key.af); - PF_ACPY(&key.ext.addr, pd2.src, key.af); - key.lan.port = 0; - key.ext.port = 0; - } + PF_ACPY(&key.addr[pd2.sidx], pd2.src, key.af); + PF_ACPY(&key.addr[pd2.didx], pd2.dst, key.af); + key.port[0] = key.port[1] = 0; + +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif - STATE_LOOKUP(); + /* translate source/destination address, if necessary */ + if ((*state)->key[PF_SK_WIRE] != + (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = + (*state)->key[pd->didx]; - if (STATE_TRANSLATE(*state)) { - if (direction == PF_IN) { - pf_change_icmp(pd2.src, NULL, - daddr, &(*state)->lan.addr, - 0, NULL, + if (PF_ANEQ(pd2.src, + &nk->addr[pd2.sidx], pd2.af)) + pf_change_icmp(pd2.src, NULL, daddr, + &nk->addr[pd2.sidx], 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } else { - pf_change_icmp(pd2.dst, NULL, - saddr, &(*state)->gwy.addr, - 0, NULL, + + if (PF_ANEQ(pd2.dst, + &nk->addr[pd2.didx], pd2.af)) + pf_change_icmp(pd2.src, NULL, + NULL, /* XXX Inbound NAT? */ + &nk->addr[pd2.didx], 0, NULL, pd2.ip_sum, icmpsum, pd->ip_sum, 0, pd2.af); - } + switch (pd2.af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ m_copyback(m, off, ICMP_MINLEN, (caddr_t)pd->hdr.icmp); - m_copyback(m, ipoff2, sizeof(h2), - (caddr_t)&h2); + m_copyback(m, ipoff2, sizeof(h2), (caddr_t)&h2); +#else + m_copyback(m, off, ICMP_MINLEN, + pd->hdr.icmp); + m_copyback(m, ipoff2, sizeof(h2), &h2); +#endif break; #endif /* INET */ #ifdef INET6 case AF_INET6: m_copyback(m, off, sizeof(struct icmp6_hdr), - (caddr_t)pd->hdr.icmp6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + pd->hdr.icmp6); m_copyback(m, ipoff2, sizeof(h2_6), - (caddr_t)&h2_6); +#ifdef __FreeBSD__ + (caddr_t) +#endif + &h2_6); break; #endif /* INET6 */ } } - return (PF_PASS); break; } @@ -5953,26 +5551,28 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif, int pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, - struct pf_pdesc *pd) + struct mbuf *m, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_state_cmp key; + struct pf_state_key_cmp key; key.af = pd->af; key.proto = pd->proto; if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, pd->src, key.af); - PF_ACPY(&key.gwy.addr, pd->dst, key.af); - key.ext.port = 0; - key.gwy.port = 0; + PF_ACPY(&key.addr[0], pd->src, key.af); + PF_ACPY(&key.addr[1], pd->dst, key.af); + key.port[0] = key.port[1] = 0; } else { - PF_ACPY(&key.lan.addr, pd->src, key.af); - PF_ACPY(&key.ext.addr, pd->dst, key.af); - key.lan.port = 0; - key.ext.port = 0; + PF_ACPY(&key.addr[1], pd->src, key.af); + PF_ACPY(&key.addr[0], pd->dst, key.af); + key.port[1] = key.port[0] = 0; } - STATE_LOOKUP(); +#ifdef __FreeBSD__ + STATE_LOOKUP(kif, &key, direction, *state, m, pd->pf_mtag); +#else + STATE_LOOKUP(kif, &key, direction, *state, m); +#endif if (direction == (*state)->direction) { src = &(*state)->src; @@ -5996,39 +5596,48 @@ pf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif, (*state)->timeout = PFTM_OTHER_SINGLE; /* translate source/destination address, if necessary */ - if (STATE_TRANSLATE(*state)) { - if (direction == PF_OUT) - switch (pd->af) { + if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { + struct pf_state_key *nk = (*state)->key[pd->didx]; + +#ifdef __FreeBSD__ + KASSERT(nk, ("%s: nk is null", __FUNCTION__)); + KASSERT(pd, ("%s: pd is null", __FUNCTION__)); + KASSERT(pd->src, ("%s: pd->src is null", __FUNCTION__)); + KASSERT(pd->dst, ("%s: pd->dst is null", __FUNCTION__)); +#else + KASSERT(nk); + KASSERT(pd); + KASSERT(pd->src); + KASSERT(pd->dst); +#endif + switch (pd->af) { #ifdef INET - case AF_INET: + case AF_INET: + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) pf_change_a(&pd->src->v4.s_addr, - pd->ip_sum, (*state)->gwy.addr.v4.s_addr, + pd->ip_sum, + nk->addr[pd->sidx].v4.s_addr, 0); - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af); - break; -#endif /* INET6 */ - } - else - switch (pd->af) { -#ifdef INET - case AF_INET: + + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) pf_change_a(&pd->dst->v4.s_addr, - pd->ip_sum, (*state)->lan.addr.v4.s_addr, + pd->ip_sum, + nk->addr[pd->didx].v4.s_addr, 0); + break; #endif /* INET */ #ifdef INET6 - case AF_INET6: - PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af); - break; + case AF_INET6: + if (PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) + PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); + + if (PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) + PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); #endif /* INET6 */ - } + } } - return (PF_PASS); } @@ -6086,6 +5695,11 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len, int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) { +#ifdef __FreeBSD__ +#ifdef RADIX_MPATH + struct radix_node_head *rnh; +#endif +#endif struct sockaddr_in *dst; int ret = 1; int check_mpath; @@ -6106,6 +5720,14 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) struct ifnet *ifp; check_mpath = 0; +#ifdef __FreeBSD__ +#ifdef RADIX_MPATH + /* XXX: stick to table 0 for now */ + rnh = rt_tables_get_rnh(0, af); + if (rnh != NULL && rn_mpath_capable(rnh)) + check_mpath = 1; +#endif +#endif bzero(&ro, sizeof(ro)); switch (af) { case AF_INET: @@ -6113,18 +5735,24 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); dst->sin_addr = addr->v4; -#ifndef __FreeBSD__ /* MULTIPATH_ROUTING */ +#ifndef __FreeBSD__ if (ipmultipath) check_mpath = 1; #endif break; #ifdef INET6 case AF_INET6: + /* + * Skip check for addresses with embedded interface scope, + * as they would always match anyway. + */ + if (IN6_IS_SCOPE_EMBED(&addr->v6)) + goto out; dst6 = (struct sockaddr_in6 *)&ro.ro_dst; dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = addr->v6; -#ifndef __FreeBSD__ /* MULTIPATH_ROUTING */ +#ifndef __FreeBSD__ if (ip6_multipath) check_mpath = 1; #endif @@ -6174,11 +5802,13 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif) if (kif->pfik_ifp == ifp) ret = 1; -#ifdef __FreeBSD__ /* MULTIPATH_ROUTING */ - rn = NULL; -#else +#ifdef __FreeBSD__ +#ifdef RADIX_MPATH rn = rn_mpath_next(rn); #endif +#else + rn = rn_mpath_next(rn, 0); +#endif } while (check_mpath == 1 && rn != NULL && ret == 0); } else ret = 0; @@ -6249,7 +5879,6 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw) } #ifdef INET - void pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct pf_state *s, struct pf_pdesc *pd) @@ -6274,7 +5903,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); +#ifdef __FreeBSD__ if (pd->pf_mtag->routed++ > 3) { +#else + if ((*m)->m_pkthdr.pf.routed++ > 3) { +#endif m0 = *m; *m = NULL; goto bad; @@ -6309,9 +5942,17 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, dst->sin_addr = ip->ip_dst; if (r->rt == PF_FASTROUTE) { +#ifdef __FreeBSD__ in_rtalloc(ro, 0); +#else + rtalloc(ro); +#endif if (ro->ro_rt == 0) { +#ifdef __FreeBSD__ KMOD_IPSTAT_INC(ips_noroute); +#else + ipstat.ips_noroute++; +#endif goto bad; } @@ -6377,7 +6018,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least) */ NTOHS(ip->ip_len); - NTOHS(ip->ip_off); /* XXX: needed? */ + NTOHS(ip->ip_off); /* XXX: needed? */ in_delayed_cksum(m0); HTONS(ip->ip_len); HTONS(ip->ip_off); @@ -6386,9 +6027,8 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, m0->m_pkthdr.csum_flags &= ifp->if_hwassist; if (ntohs(ip->ip_len) <= ifp->if_mtu || - (m0->m_pkthdr.csum_flags & ifp->if_hwassist & CSUM_TSO) != 0 || (ifp->if_hwassist & CSUM_FRAGMENT && - ((ip->ip_off & htons(IP_DF)) == 0))) { + ((ip->ip_off & htons(IP_DF)) == 0))) { /* * ip->ip_len = htons(ip->ip_len); * ip->ip_off = htons(ip->ip_off); @@ -6408,7 +6048,6 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, PF_LOCK(); goto done; } - #else /* Copied from ip_output. */ #ifdef IPSEC @@ -6429,25 +6068,28 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum_flags &= ~M_TCPV4_CSUM_OUT; /* Clr */ } } else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) { if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) || ifp->if_bridge != NULL) { in_delayed_cksum(m0); - m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clear */ + m0->m_pkthdr.csum_flags &= ~M_UDPV4_CSUM_OUT; /* Clr */ } } if (ntohs(ip->ip_len) <= ifp->if_mtu) { + ip->ip_sum = 0; if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && ifp->if_bridge == NULL) { m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; +#ifdef __FreeBSD__ KMOD_IPSTAT_INC(ips_outhwcsum); - } else { - ip->ip_sum = 0; +#else + ipstat.ips_outhwcsum++; +#endif + } else ip->ip_sum = in_cksum(m0, ip->ip_hl << 2); - } /* Update relevant hardware checksum stats for TCP/UDP */ if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) KMOD_TCPSTAT_INC(tcps_outhwcsum); @@ -6457,12 +6099,17 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, goto done; } #endif + /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. */ - if (ip->ip_off & htons(IP_DF) || (m0->m_pkthdr.csum_flags & CSUM_TSO)) { + if (ip->ip_off & htons(IP_DF)) { +#ifdef __FreeBSD__ KMOD_IPSTAT_INC(ips_cantfrag); +#else + ipstat.ips_cantfrag++; +#endif if (r->rt != PF_DUPTO) { #ifdef __FreeBSD__ /* icmp_error() expects host byte ordering */ @@ -6493,7 +6140,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, error = ip_fragment(m0, ifp, ifp->if_mtu); #endif if (error) { -#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ +#ifndef __FreeBSD__ /* ip_fragment does not do m_freem() on FreeBSD */ m0 = NULL; #endif goto bad; @@ -6519,7 +6166,11 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, } if (error == 0) +#ifdef __FreeBSD__ KMOD_IPSTAT_INC(ips_fragmented); +#else + ipstat.ips_fragmented++; +#endif done: if (r->rt != PF_DUPTO) @@ -6547,13 +6198,16 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, struct ifnet *ifp = NULL; struct pf_addr naddr; struct pf_src_node *sn = NULL; - int error = 0; if (m == NULL || *m == NULL || r == NULL || (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route6: invalid parameters"); +#ifdef __FreeBSD__ if (pd->pf_mtag->routed++ > 3) { +#else + if ((*m)->m_pkthdr.pf.routed++ > 3) { +#endif m0 = *m; *m = NULL; goto bad; @@ -6592,14 +6246,9 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, m0->m_flags |= M_SKIP_FIREWALL; PF_UNLOCK(); ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); - PF_LOCK(); #else - mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); - if (mtag == NULL) - goto bad; - m_tag_prepend(m0, mtag); - pd->pf_mtag->flags |= PF_TAG_GENERATED; - ip6_output(m0, NULL, NULL, 0, NULL, NULL); + m0->m_pkthdr.pf.flags |= PF_TAG_GENERATED; + ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL); #endif return; } @@ -6660,7 +6309,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, #ifdef __FreeBSD__ PF_UNLOCK(); #endif - error = nd6_output(ifp, ifp, m0, dst, NULL); + nd6_output(ifp, ifp, m0, dst, NULL); #ifdef __FreeBSD__ PF_LOCK(); #endif @@ -6671,7 +6320,7 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp, PF_UNLOCK(); icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); PF_LOCK(); - } else + } else #else if (r->rt != PF_DUPTO) icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); @@ -6691,7 +6340,6 @@ bad: } #endif /* INET6 */ - #ifdef __FreeBSD__ /* * FreeBSD supports cksum offloads for the following drivers. @@ -6729,10 +6377,10 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { sum = m->m_pkthdr.csum_data; } else { - ip = mtod(m, struct ip *); + ip = mtod(m, struct ip *); sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htonl((u_short)len + - m->m_pkthdr.csum_data + IPPROTO_TCP)); + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_TCP)); } sum ^= 0xffff; ++hw_assist; @@ -6743,14 +6391,14 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) { sum = m->m_pkthdr.csum_data; } else { - ip = mtod(m, struct ip *); + ip = mtod(m, struct ip *); sum = in_pseudo(ip->ip_src.s_addr, - ip->ip_dst.s_addr, htonl((u_short)len + - m->m_pkthdr.csum_data + IPPROTO_UDP)); + ip->ip_dst.s_addr, htonl((u_short)len + + m->m_pkthdr.csum_data + IPPROTO_UDP)); } sum ^= 0xffff; ++hw_assist; - } + } break; case IPPROTO_ICMP: #ifdef INET6 @@ -6827,6 +6475,7 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t a return (0); } #else /* !__FreeBSD__ */ + /* * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag * off is the offset where the protocol header starts @@ -6919,7 +6568,37 @@ pf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, m->m_pkthdr.csum_flags |= flag_ok; return (0); } -#endif /* __FreeBSD__ */ +#endif + +#ifndef __FreeBSD__ +struct pf_divert * +pf_find_divert(struct mbuf *m) +{ + struct m_tag *mtag; + + if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) + return (NULL); + + return ((struct pf_divert *)(mtag + 1)); +} + +struct pf_divert * +pf_get_divert(struct mbuf *m) +{ + struct m_tag *mtag; + + if ((mtag = m_tag_find(m, PACKET_TAG_PF_DIVERT, NULL)) == NULL) { + mtag = m_tag_get(PACKET_TAG_PF_DIVERT, sizeof(struct pf_divert), + M_NOWAIT); + if (mtag == NULL) + return (NULL); + bzero(mtag + 1, sizeof(struct pf_divert)); + m_tag_prepend(m, mtag); + } + + return ((struct pf_divert *)(mtag + 1)); +} +#endif #ifdef INET int @@ -6934,8 +6613,14 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, struct pfi_kif *kif; u_short action, reason = 0, log = 0; struct mbuf *m = *m0; - struct ip *h = NULL; /* make the compiler happy */ +#ifdef __FreeBSD__ + struct ip *h = NULL; + struct m_tag *ipfwtag; + struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; +#else + struct ip *h; struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; +#endif struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; @@ -6943,44 +6628,32 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, #ifdef __FreeBSD__ PF_LOCK(); -#endif - if (!pf_status.running) -#ifdef __FreeBSD__ + if (!V_pf_status.running) { PF_UNLOCK(); -#endif return (PF_PASS); -#ifdef __FreeBSD__ } +#else + if (!pf_status.running) + return (PF_PASS); #endif memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { #ifdef __FreeBSD__ + if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { PF_UNLOCK(); -#endif DPFPRINTF(PF_DEBUG_URGENT, ("pf_test: pf_get_mtag returned NULL\n")); return (PF_DROP); } -#ifdef __FreeBSD__ - if (m->m_flags & M_SKIP_FIREWALL) { - PF_UNLOCK(); - return (PF_PASS); - } -#else - if (pd.pf_mtag->flags & PF_TAG_GENERATED) - return (PF_PASS); #endif - -#ifdef __FreeBSD__ - /* XXX_IMPORT: later */ -#else +#ifndef __FreeBSD__ if (ifp->if_type == IFT_CARP && ifp->if_carpdev) - ifp = ifp->if_carpdev; + kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; + else #endif + kif = (struct pfi_kif *)ifp->if_pf_kif; - kif = (struct pfi_kif *)ifp->if_pf_kif; if (kif == NULL) { #ifdef __FreeBSD__ PF_UNLOCK(); @@ -6989,12 +6662,15 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) { + if (kif->pfik_flags & PFI_IFLAG_SKIP) #ifdef __FreeBSD__ + { PF_UNLOCK(); #endif return (PF_PASS); +#ifdef __FreeBSD__ } +#endif #ifdef __FreeBSD__ M_ASSERTPKTHDR(m); @@ -7003,7 +6679,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, if ((m->m_flags & M_PKTHDR) == 0) panic("non-M_PKTHDR is passed to pf_test"); #endif /* DIAGNOSTIC */ -#endif /* __FreeBSD__ */ +#endif if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; @@ -7012,12 +6688,36 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, goto done; } +#ifdef __FreeBSD__ + if (m->m_flags & M_SKIP_FIREWALL) { + PF_UNLOCK(); + return (PF_PASS); + } +#else + if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) + return (PF_PASS); +#endif + +#ifdef __FreeBSD__ + if (ip_divert_ptr != NULL && + ((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) { + struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1); + if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) { + pd.pf_mtag->flags |= PF_PACKET_LOOPED; + m_tag_delete(m, ipfwtag); + } + if (pd.pf_mtag->flags & PF_FASTFWD_OURS_PRESENT) { + m->m_flags |= M_FASTFWD_OURS; + pd.pf_mtag->flags &= ~PF_FASTFWD_OURS_PRESENT; + } + } else +#endif /* We do IP header normalization and packet reassembly here */ if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) { action = PF_DROP; goto done; } - m = *m0; + m = *m0; /* pf_normalize messes with m0 */ h = mtod(m, struct ip *); off = h->ip_hl << 2; @@ -7030,9 +6730,13 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, pd.src = (struct pf_addr *)&h->ip_src; pd.dst = (struct pf_addr *)&h->ip_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET); + pd.sport = pd.dport = NULL; pd.ip_sum = &h->ip_sum; + pd.proto_sum = NULL; pd.proto = h->ip_p; + pd.dir = dir; + pd.sidx = (dir == PF_IN) ? 0 : 1; + pd.didx = (dir == PF_IN) ? 1 : 0; pd.af = AF_INET; pd.tos = h->ip_tos; pd.tot_len = ntohs(h->ip_len); @@ -7056,12 +6760,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(m, off, - ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) { - REASON_SET(&reason, PFRES_PROTCKSUM); - action = PF_DROP; - goto done; - } pd.p_len = pd.tot_len - off - (th.th_off << 2); if ((th.th_flags & TH_ACK) && pd.p_len == 0) pqid = 1; @@ -7071,18 +6769,23 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_tcp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_tcp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); #endif break; @@ -7097,12 +6800,6 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m, - off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); - goto done; - } if (uh.uh_dport == 0 || ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { @@ -7112,18 +6809,23 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_udp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_udp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); #endif break; @@ -7138,47 +6840,60 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(m, off, - ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); - goto done; - } action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_icmp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset, NULL); + action = pf_test_rule(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_icmp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); #endif break; } +#ifdef INET6 + case IPPROTO_ICMPV6: { + action = PF_DROP; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: dropping IPv4 packet with ICMPv6 payload\n")); + goto done; + } +#endif + default: - action = pf_test_state_other(&s, dir, kif, &pd); + action = pf_test_state_other(&s, dir, kif, m, &pd); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_other(&r, &s, dir, kif, m, off, h, - &pd, &a, &ruleset, NULL); + action = pf_test_rule(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_other(&r, &s, dir, kif, m, off, h, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ipintrq); #endif break; @@ -7195,17 +6910,37 @@ done: } if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); +#ifdef __FreeBSD__ + pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); +#else + pf_tag_packet(m, s ? s->tag : 0, r->rtableid); +#endif + + if (dir == PF_IN && s && s->key[PF_SK_STACK]) +#ifdef __FreeBSD__ + pd.pf_mtag->statekey = s->key[PF_SK_STACK]; +#else + m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; +#endif #ifdef ALTQ if (action == PF_PASS && r->qid) { +#ifdef __FreeBSD__ if (pqid || (pd.tos & IPTOS_LOWDELAY)) pd.pf_mtag->qid = r->pqid; else pd.pf_mtag->qid = r->qid; /* add hints for ecn */ - pd.pf_mtag->af = AF_INET; pd.pf_mtag->hdr = h; + +#else + if (pqid || (pd.tos & IPTOS_LOWDELAY)) + m->m_pkthdr.pf.qid = r->pqid; + else + m->m_pkthdr.pf.qid = r->qid; + /* add hints for ecn */ + m->m_pkthdr.pf.hdr = h; +#endif } #endif /* ALTQ */ @@ -7219,7 +6954,55 @@ done: (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; +#ifdef __FreeBSD__ + m->m_flags |= M_SKIP_FIREWALL; +#else + m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; +#endif + +#ifdef __FreeBSD__ + if (action == PF_PASS && r->divert.port && + ip_divert_ptr != NULL && !PACKET_LOOPED()) { + + ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0, + sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO); + if (ipfwtag != NULL) { + ((struct ipfw_rule_ref *)(ipfwtag+1))->info = r->divert.port; + ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir; + + m_tag_prepend(m, ipfwtag); + + PF_UNLOCK(); + + if (m->m_flags & M_FASTFWD_OURS) { + pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT; + m->m_flags &= ~M_FASTFWD_OURS; + } + + ip_divert_ptr(*m0, + dir == PF_IN ? DIR_IN : DIR_OUT); + *m0 = NULL; + return (action); + } else { + /* XXX: ipfw has the same behaviour! */ + action = PF_DROP; + REASON_SET(&reason, PFRES_MEMORY); + log = 1; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: failed to allocate divert tag\n")); + } + } +#else + if (dir == PF_IN && action == PF_PASS && r->divert.port) { + struct pf_divert *divert; + + if ((divert = pf_get_divert(m))) { + m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; + divert->port = r->divert.port; + divert->addr.ipv4 = r->divert.addr.v4; + } + } +#endif if (log) { struct pf_rule *lr; @@ -7263,53 +7046,44 @@ done: } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - if (x == &pd.baddr || s == NULL) { - /* we need to change the address */ - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } +#ifdef __FreeBSD__ + if (nr != NULL && r == &V_pf_default_rule) +#else + if (nr != NULL && r == &pf_default_rule) +#endif + tr = nr; if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.neg); + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL) ? pd.src : + &s->key[(s->direction == PF_IN)]-> + addr[(s->direction == PF_OUT)], + pd.af, pd.tot_len, dir == PF_OUT, + r->action == PF_PASS, tr->src.neg); if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.neg); + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL) ? pd.dst : + &s->key[(s->direction == PF_IN)]-> + addr[(s->direction == PF_IN)], + pd.af, pd.tot_len, dir == PF_OUT, + r->action == PF_PASS, tr->dst.neg); } - - if (action == PF_SYNPROXY_DROP) { + switch (action) { + case PF_SYNPROXY_DROP: m_freem(*m0); + case PF_DEFER: *m0 = NULL; action = PF_PASS; - } else if (r->rt) + break; + default: /* pf_route can free the mbuf causing *m0 to become NULL */ - pf_route(m0, r, dir, ifp, s, &pd); - + if (r->rt) + pf_route(m0, r, dir, kif->pfik_ifp, s, &pd); + break; + } #ifdef __FreeBSD__ PF_UNLOCK(); #endif - return (action); } #endif /* INET */ @@ -7327,8 +7101,13 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, struct pfi_kif *kif; u_short action, reason = 0, log = 0; struct mbuf *m = *m0, *n = NULL; +#ifdef __FreeBSD__ + struct ip6_hdr *h = NULL; + struct pf_rule *a = NULL, *r = &V_pf_default_rule, *tr, *nr; +#else struct ip6_hdr *h; struct pf_rule *a = NULL, *r = &pf_default_rule, *tr, *nr; +#endif struct pf_state *s = NULL; struct pf_ruleset *ruleset = NULL; struct pf_pdesc pd; @@ -7336,38 +7115,31 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, #ifdef __FreeBSD__ PF_LOCK(); -#endif - - if (!pf_status.running) -#ifdef __FreeBSD__ - { + if (!V_pf_status.running) { PF_UNLOCK(); -#endif return (PF_PASS); -#ifdef __FreeBSD__ } +#else + if (!pf_status.running) + return (PF_PASS); #endif memset(&pd, 0, sizeof(pd)); - if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { #ifdef __FreeBSD__ + if ((pd.pf_mtag = pf_get_mtag(m)) == NULL) { PF_UNLOCK(); -#endif DPFPRINTF(PF_DEBUG_URGENT, - ("pf_test6: pf_get_mtag returned NULL\n")); + ("pf_test: pf_get_mtag returned NULL\n")); return (PF_DROP); } - if (pd.pf_mtag->flags & PF_TAG_GENERATED) - return (PF_PASS); - -#ifdef __FreeBSD__ - /* XXX_IMPORT: later */ -#else +#endif +#ifndef __FreeBSD__ if (ifp->if_type == IFT_CARP && ifp->if_carpdev) - ifp = ifp->if_carpdev; + kif = (struct pfi_kif *)ifp->if_carpdev->if_pf_kif; + else #endif + kif = (struct pfi_kif *)ifp->if_pf_kif; - kif = (struct pfi_kif *)ifp->if_pf_kif; if (kif == NULL) { #ifdef __FreeBSD__ PF_UNLOCK(); @@ -7376,12 +7148,15 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname)); return (PF_DROP); } - if (kif->pfik_flags & PFI_IFLAG_SKIP) { + if (kif->pfik_flags & PFI_IFLAG_SKIP) #ifdef __FreeBSD__ + { PF_UNLOCK(); #endif return (PF_PASS); +#ifdef __FreeBSD__ } +#endif #ifdef __FreeBSD__ M_ASSERTPKTHDR(m); @@ -7392,10 +7167,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, #endif /* DIAGNOSTIC */ #endif -#ifdef __FreeBSD__ - h = NULL; /* make the compiler happy */ -#endif - if (m->m_pkthdr.len < (int)sizeof(*h)) { action = PF_DROP; REASON_SET(&reason, PFRES_SHORT); @@ -7403,12 +7174,19 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, goto done; } +#ifdef __FreeBSD__ + if (pd.pf_mtag->flags & PF_TAG_GENERATED) +#else + if (m->m_pkthdr.pf.flags & PF_TAG_GENERATED) +#endif + return (PF_PASS); + /* We do IP header normalization and packet reassembly here */ if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) { action = PF_DROP; goto done; } - m = *m0; + m = *m0; /* pf_normalize messes with m0 */ h = mtod(m, struct ip6_hdr *); #if 1 @@ -7425,8 +7203,12 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, pd.src = (struct pf_addr *)&h->ip6_src; pd.dst = (struct pf_addr *)&h->ip6_dst; - PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6); + pd.sport = pd.dport = NULL; pd.ip_sum = NULL; + pd.proto_sum = NULL; + pd.dir = dir; + pd.sidx = (dir == PF_IN) ? 0 : 1; + pd.didx = (dir == PF_IN) ? 1 : 0; pd.af = AF_INET6; pd.tos = 0; pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr); @@ -7470,7 +7252,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = 1; goto done; } - /* fallthrough */ + /* FALLTHROUGH */ } case IPPROTO_AH: case IPPROTO_HOPOPTS: @@ -7515,13 +7297,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, - ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), - IPPROTO_TCP, AF_INET6)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); - goto done; - } pd.p_len = pd.tot_len - off - (th.th_off << 2); action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd); if (action == PF_DROP) @@ -7529,18 +7304,23 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_tcp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_tcp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); #endif break; @@ -7555,13 +7335,6 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(n, - off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), - IPPROTO_UDP, AF_INET6)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); - goto done; - } if (uh.uh_dport == 0 || ntohs(uh.uh_ulen) > m->m_pkthdr.len - off || ntohs(uh.uh_ulen) < sizeof(struct udphdr)) { @@ -7571,23 +7344,35 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, } action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_udp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_udp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); #endif break; } + case IPPROTO_ICMP: { + action = PF_DROP; + DPFPRINTF(PF_DEBUG_MISC, + ("pf: dropping IPv6 packet with ICMPv4 payload\n")); + goto done; + } + case IPPROTO_ICMPV6: { struct icmp6_hdr ih; @@ -7597,54 +7382,62 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0, log = action != PF_PASS; goto done; } - if (dir == PF_IN && pf_check_proto_cksum(n, off, - ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)), - IPPROTO_ICMPV6, AF_INET6)) { - action = PF_DROP; - REASON_SET(&reason, PFRES_PROTCKSUM); - goto done; - } action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd, &reason); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_icmp(&r, &s, dir, kif, - m, off, h, &pd, &a, &ruleset, NULL); + action = pf_test_rule(&r, &s, dir, kif, + m, off, h, &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_icmp(&r, &s, dir, kif, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); #endif break; } default: - action = pf_test_state_other(&s, dir, kif, &pd); + action = pf_test_state_other(&s, dir, kif, m, &pd); if (action == PF_PASS) { -#if NPFSYNC +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_update_state_ptr != NULL) + pfsync_update_state_ptr(s); +#else pfsync_update_state(s); +#endif #endif /* NPFSYNC */ r = s->rule.ptr; a = s->anchor.ptr; log = s->log; } else if (s == NULL) #ifdef __FreeBSD__ - action = pf_test_other(&r, &s, dir, kif, m, off, h, - &pd, &a, &ruleset, NULL); + action = pf_test_rule(&r, &s, dir, kif, m, off, h, + &pd, &a, &ruleset, NULL, inp); #else - action = pf_test_other(&r, &s, dir, kif, m, off, h, + action = pf_test_rule(&r, &s, dir, kif, m, off, h, &pd, &a, &ruleset, &ip6intrq); #endif break; } done: + if (n != m) { + m_freem(n); + n = NULL; + } + /* handle dangerous IPv6 extension headers. */ if (action == PF_PASS && rh_cnt && !((s && s->state_flags & PFSTATE_ALLOWOPTS) || r->allow_opts)) { @@ -7656,17 +7449,36 @@ done: } if ((s && s->tag) || r->rtableid) - pf_tag_packet(m, pd.pf_mtag, s ? s->tag : 0, r->rtableid); +#ifdef __FreeBSD__ + pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag); +#else + pf_tag_packet(m, s ? s->tag : 0, r->rtableid); +#endif + + if (dir == PF_IN && s && s->key[PF_SK_STACK]) +#ifdef __FreeBSD__ + pd.pf_mtag->statekey = s->key[PF_SK_STACK]; +#else + m->m_pkthdr.pf.statekey = s->key[PF_SK_STACK]; +#endif #ifdef ALTQ if (action == PF_PASS && r->qid) { +#ifdef __FreeBSD__ if (pd.tos & IPTOS_LOWDELAY) pd.pf_mtag->qid = r->pqid; else pd.pf_mtag->qid = r->qid; /* add hints for ecn */ - pd.pf_mtag->af = AF_INET6; pd.pf_mtag->hdr = h; +#else + if (pd.tos & IPTOS_LOWDELAY) + m->m_pkthdr.pf.qid = r->pqid; + else + m->m_pkthdr.pf.qid = r->qid; + /* add hints for ecn */ + m->m_pkthdr.pf.hdr = h; +#endif } #endif /* ALTQ */ @@ -7675,7 +7487,27 @@ done: (s->nat_rule.ptr->action == PF_RDR || s->nat_rule.ptr->action == PF_BINAT) && IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) - pd.pf_mtag->flags |= PF_TAG_TRANSLATE_LOCALHOST; +#ifdef __FreeBSD__ + m->m_flags |= M_SKIP_FIREWALL; +#else + m->m_pkthdr.pf.flags |= PF_TAG_TRANSLATE_LOCALHOST; +#endif + +#ifdef __FreeBSD__ + /* XXX: Anybody working on it?! */ + if (r->divert.port) + printf("pf: divert(9) is not supported for IPv6\n"); +#else + if (dir == PF_IN && action == PF_PASS && r->divert.port) { + struct pf_divert *divert; + + if ((divert = pf_get_divert(m))) { + m->m_pkthdr.pf.flags |= PF_TAG_DIVERTED; + divert->port = r->divert.port; + divert->addr.ipv6 = r->divert.addr.v6; + } + } +#endif if (log) { struct pf_rule *lr; @@ -7719,48 +7551,39 @@ done: } tr = r; nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule; - if (nr != NULL) { - struct pf_addr *x; - /* - * XXX: we need to make sure that the addresses - * passed to pfr_update_stats() are the same than - * the addresses used during matching (pfr_match) - */ - if (r == &pf_default_rule) { - tr = nr; - x = (s == NULL || s->direction == dir) ? - &pd.baddr : &pd.naddr; - } else { - x = (s == NULL || s->direction == dir) ? - &pd.naddr : &pd.baddr; - } - if (x == &pd.baddr || s == NULL) { - if (dir == PF_OUT) - pd.src = x; - else - pd.dst = x; - } - } +#ifdef __FreeBSD__ + if (nr != NULL && r == &V_pf_default_rule) +#else + if (nr != NULL && r == &pf_default_rule) +#endif + tr = nr; if (tr->src.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->src.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.src : pd.dst, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->src.neg); + pfr_update_stats(tr->src.addr.p.tbl, + (s == NULL) ? pd.src : + &s->key[(s->direction == PF_IN)]->addr[0], + pd.af, pd.tot_len, dir == PF_OUT, + r->action == PF_PASS, tr->src.neg); if (tr->dst.addr.type == PF_ADDR_TABLE) - pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL || - s->direction == dir) ? pd.dst : pd.src, pd.af, - pd.tot_len, dir == PF_OUT, r->action == PF_PASS, - tr->dst.neg); + pfr_update_stats(tr->dst.addr.p.tbl, + (s == NULL) ? pd.dst : + &s->key[(s->direction == PF_IN)]->addr[1], + pd.af, pd.tot_len, dir == PF_OUT, + r->action == PF_PASS, tr->dst.neg); } - - if (action == PF_SYNPROXY_DROP) { + switch (action) { + case PF_SYNPROXY_DROP: m_freem(*m0); + case PF_DEFER: *m0 = NULL; action = PF_PASS; - } else if (r->rt) + break; + default: /* pf_route6 can free the mbuf causing *m0 to become NULL */ - pf_route6(m0, r, dir, ifp, s, &pd); + if (r->rt) + pf_route6(m0, r, dir, kif->pfik_ifp, s, &pd); + break; + } #ifdef __FreeBSD__ PF_UNLOCK(); @@ -7782,3 +7605,20 @@ pf_check_congestion(struct ifqueue *ifq) return (0); #endif } + +/* + * must be called whenever any addressing information such as + * address, port, protocol has changed + */ +void +pf_pkt_addr_changed(struct mbuf *m) +{ +#ifdef __FreeBSD__ + struct pf_mtag *pf_tag; + + if ((pf_tag = pf_find_mtag(m)) != NULL) + pf_tag->statekey = NULL; +#else + m->m_pkthdr.pf.statekey = NULL; +#endif +} diff --git a/sys/contrib/pf/net/pf_if.c b/sys/contrib/pf/net/pf_if.c index 156fb22..6336c79 100644 --- a/sys/contrib/pf/net/pf_if.c +++ b/sys/contrib/pf/net/pf_if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_if.c,v 1.46 2006/12/13 09:01:59 itojun Exp $ */ +/* $OpenBSD: pf_if.c,v 1.54 2008/06/14 16:55:28 mk Exp $ */ /* * Copyright 2005 Henning Brauer <henning@openbsd.org> @@ -54,6 +54,9 @@ __FBSDID("$FreeBSD$"); #include <sys/device.h> #endif #include <sys/time.h> +#ifndef __FreeBSD__ +#include <sys/pool.h> +#endif #include <net/if.h> #include <net/if_types.h> @@ -73,25 +76,35 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip6.h> #endif /* INET6 */ -struct pfi_kif *pfi_all = NULL; -struct pfi_statehead pfi_statehead; #ifdef __FreeBSD__ -uma_zone_t pfi_addr_pl; +VNET_DEFINE(struct pfi_kif *, pfi_all); +VNET_DEFINE(uma_zone_t, pfi_addr_pl); +VNET_DEFINE(struct pfi_ifhead, pfi_ifs); +#define V_pfi_ifs VNET(pfi_ifs) +VNET_DEFINE(long, pfi_update); +#define V_pfi_update VNET(pfi_update) +VNET_DEFINE(struct pfr_addr *, pfi_buffer); +#define V_pfi_buffer VNET(pfi_buffer) +VNET_DEFINE(int, pfi_buffer_cnt); +#define V_pfi_buffer_cnt VNET(pfi_buffer_cnt) +VNET_DEFINE(int, pfi_buffer_max); +#define V_pfi_buffer_max VNET(pfi_buffer_max) #else +struct pfi_kif *pfi_all = NULL; struct pool pfi_addr_pl; -#endif struct pfi_ifhead pfi_ifs; long pfi_update = 1; struct pfr_addr *pfi_buffer; int pfi_buffer_cnt; int pfi_buffer_max; +#endif #ifdef __FreeBSD__ -eventhandler_tag pfi_attach_cookie = NULL; -eventhandler_tag pfi_detach_cookie = NULL; -eventhandler_tag pfi_attach_group_cookie = NULL; -eventhandler_tag pfi_change_group_cookie = NULL; -eventhandler_tag pfi_detach_group_cookie = NULL; -eventhandler_tag pfi_ifaddr_event_cookie = NULL; +eventhandler_tag pfi_attach_cookie; +eventhandler_tag pfi_detach_cookie; +eventhandler_tag pfi_attach_group_cookie; +eventhandler_tag pfi_change_group_cookie; +eventhandler_tag pfi_detach_group_cookie; +eventhandler_tag pfi_ifaddr_event_cookie; #endif void pfi_kif_update(struct pfi_kif *); @@ -107,11 +120,10 @@ int pfi_unmask(void *); #ifdef __FreeBSD__ void pfi_attach_ifnet_event(void * __unused, struct ifnet *); void pfi_detach_ifnet_event(void * __unused, struct ifnet *); -void pfi_attach_group_event(void * __unused, struct ifg_group *); -void pfi_change_group_event(void * __unused, char *); -void pfi_detach_group_event(void * __unused, struct ifg_group *); +void pfi_attach_group_event(void *, struct ifg_group *); +void pfi_change_group_event(void *, char *); +void pfi_detach_group_event(void *, struct ifg_group *); void pfi_ifaddr_event(void * __unused, struct ifnet *); - #endif RB_PROTOTYPE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); @@ -123,22 +135,31 @@ RB_GENERATE(pfi_ifhead, pfi_kif, pfik_tree, pfi_if_compare); void pfi_initialize(void) { - +#ifdef __FreeBSD__ + if (V_pfi_all != NULL) /* already initialized */ +#else if (pfi_all != NULL) /* already initialized */ +#endif return; - TAILQ_INIT(&pfi_statehead); #ifndef __FreeBSD__ - pool_init(&pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, + pool_init(&V_pfi_addr_pl, sizeof(struct pfi_dynaddr), 0, 0, 0, "pfiaddrpl", &pool_allocator_nointr); #endif +#ifdef __FreeBSD__ + V_pfi_buffer_max = 64; + V_pfi_buffer = malloc(V_pfi_buffer_max * sizeof(*V_pfi_buffer), + PFI_MTYPE, M_WAITOK); + + if ((V_pfi_all = pfi_kif_get(IFG_ALL)) == NULL) +#else pfi_buffer_max = 64; pfi_buffer = malloc(pfi_buffer_max * sizeof(*pfi_buffer), PFI_MTYPE, M_WAITOK); if ((pfi_all = pfi_kif_get(IFG_ALL)) == NULL) +#endif panic("pfi_kif_get for pfi_all failed"); - #ifdef __FreeBSD__ struct ifg_group *ifg; struct ifnet *ifp; @@ -155,11 +176,11 @@ pfi_initialize(void) pfi_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, pfi_detach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY); pfi_attach_group_cookie = EVENTHANDLER_REGISTER(group_attach_event, - pfi_attach_group_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_attach_group_event, curvnet, EVENTHANDLER_PRI_ANY); pfi_change_group_cookie = EVENTHANDLER_REGISTER(group_change_event, - pfi_change_group_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_change_group_event, curvnet, EVENTHANDLER_PRI_ANY); pfi_detach_group_cookie = EVENTHANDLER_REGISTER(group_detach_event, - pfi_detach_group_event, NULL, EVENTHANDLER_PRI_ANY); + pfi_detach_group_event, curvnet, EVENTHANDLER_PRI_ANY); pfi_ifaddr_event_cookie = EVENTHANDLER_REGISTER(ifaddr_event, pfi_ifaddr_event, NULL, EVENTHANDLER_PRI_ANY); #endif @@ -180,18 +201,18 @@ pfi_cleanup(void) EVENTHANDLER_DEREGISTER(ifaddr_event, pfi_ifaddr_event_cookie); PF_LOCK(); - pfi_all = NULL; - while ((p = RB_MIN(pfi_ifhead, &pfi_ifs))) { + V_pfi_all = NULL; + while ((p = RB_MIN(pfi_ifhead, &V_pfi_ifs))) { if (p->pfik_rules || p->pfik_states) { printf("pfi_cleanup: dangling refs for %s\n", p->pfik_name); } - RB_REMOVE(pfi_ifhead, &pfi_ifs, p); + RB_REMOVE(pfi_ifhead, &V_pfi_ifs, p); free(p, PFI_MTYPE); } - free(pfi_buffer, PFI_MTYPE); + free(V_pfi_buffer, PFI_MTYPE); } #endif @@ -203,18 +224,21 @@ pfi_kif_get(const char *kif_name) bzero(&s, sizeof(s)); strlcpy(s.pfik_name, kif_name, sizeof(s.pfik_name)); +#ifdef __FreeBSD__ + if ((kif = RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&s)) != NULL) +#else if ((kif = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&s)) != NULL) +#endif return (kif); /* create new one */ #ifdef __FreeBSD__ - if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT)) == NULL) + if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_NOWAIT | M_ZERO)) == NULL) #else - if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT)) == NULL) + if ((kif = malloc(sizeof(*kif), PFI_MTYPE, M_DONTWAIT|M_ZERO)) == NULL) #endif return (NULL); - bzero(kif, sizeof(*kif)); strlcpy(kif->pfik_name, kif_name, sizeof(kif->pfik_name)); #ifdef __FreeBSD__ /* @@ -230,7 +254,12 @@ pfi_kif_get(const char *kif_name) #endif TAILQ_INIT(&kif->pfik_dynaddrs); +#ifdef __FreeBSD__ + RB_INSERT(pfi_ifhead, &V_pfi_ifs, kif); +#else RB_INSERT(pfi_ifhead, &pfi_ifs, kif); +#endif + return (kif); } @@ -242,8 +271,7 @@ pfi_kif_ref(struct pfi_kif *kif, enum pfi_kif_refs what) kif->pfik_rules++; break; case PFI_KIF_REF_STATE: - if (!kif->pfik_states++) - TAILQ_INSERT_TAIL(&pfi_statehead, kif, pfik_w_states); + kif->pfik_states++; break; default: panic("pfi_kif_ref with unknown type"); @@ -271,20 +299,27 @@ pfi_kif_unref(struct pfi_kif *kif, enum pfi_kif_refs what) printf("pfi_kif_unref: state refcount <= 0\n"); return; } - if (!--kif->pfik_states) - TAILQ_REMOVE(&pfi_statehead, kif, pfik_w_states); + kif->pfik_states--; break; default: panic("pfi_kif_unref with unknown type"); } +#ifdef __FreeBSD__ + if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == V_pfi_all) +#else if (kif->pfik_ifp != NULL || kif->pfik_group != NULL || kif == pfi_all) +#endif return; if (kif->pfik_rules || kif->pfik_states) return; +#ifdef __FreeBSD__ + RB_REMOVE(pfi_ifhead, &V_pfi_ifs, kif); +#else RB_REMOVE(pfi_ifhead, &pfi_ifs, kif); +#endif free(kif, PFI_MTYPE); } @@ -312,7 +347,11 @@ pfi_attach_ifnet(struct ifnet *ifp) pfi_initialize(); s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif if ((kif = pfi_kif_get(ifp->if_xname)) == NULL) panic("pfi_kif_get failed"); @@ -341,7 +380,11 @@ pfi_detach_ifnet(struct ifnet *ifp) return; s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif #ifndef __FreeBSD__ hook_disestablish(ifp->if_addrhooks, kif->pfik_ah_cookie); #endif @@ -361,7 +404,11 @@ pfi_attach_ifgroup(struct ifg_group *ifg) pfi_initialize(); s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif if ((kif = pfi_kif_get(ifg->ifg_group)) == NULL) panic("pfi_kif_get failed"); @@ -381,7 +428,11 @@ pfi_detach_ifgroup(struct ifg_group *ifg) return; s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif kif->pfik_group = NULL; ifg->ifg_pf_kif = NULL; @@ -396,7 +447,11 @@ pfi_group_change(const char *group) int s; s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif if ((kif = pfi_kif_get(group)) == NULL) panic("pfi_kif_get failed"); @@ -450,9 +505,14 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) if (aw->type != PF_ADDR_DYNIFTL) return (0); - if ((dyn = pool_get(&pfi_addr_pl, PR_NOWAIT)) == NULL) +#ifdef __FreeBSD__ + /* XXX: revisit! */ + if ((dyn = pool_get(&V_pfi_addr_pl, PR_WAITOK | PR_ZERO)) +#else + if ((dyn = pool_get(&pfi_addr_pl, PR_WAITOK | PR_LIMITFAIL | PR_ZERO)) +#endif + == NULL) return (1); - bzero(dyn, sizeof(*dyn)); s = splsoftnet(); if (!strcmp(aw->v.ifname, "self")) @@ -485,7 +545,7 @@ pfi_dynaddr_setup(struct pf_addr_wrap *aw, sa_family_t af) goto _bad; } - if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname)) == NULL) { + if ((dyn->pfid_kt = pfr_attach_table(ruleset, tblname, 1)) == NULL) { rv = 1; goto _bad; } @@ -507,7 +567,11 @@ _bad: pf_remove_if_empty_ruleset(ruleset); if (dyn->pfid_kif != NULL) pfi_kif_unref(dyn->pfid_kif, PFI_KIF_REF_RULE); +#ifdef __FreeBSD__ + pool_put(&V_pfi_addr_pl, dyn); +#else pool_put(&pfi_addr_pl, dyn); +#endif splx(s); return (rv); } @@ -541,10 +605,18 @@ pfi_dynaddr_update(struct pfi_dynaddr *dyn) kif = dyn->pfid_kif; kt = dyn->pfid_kt; +#ifdef __FreeBSD__ + if (kt->pfrkt_larg != V_pfi_update) { +#else if (kt->pfrkt_larg != pfi_update) { +#endif /* this table needs to be brought up-to-date */ pfi_table_update(kt, kif, dyn->pfid_net, dyn->pfid_iflags); +#ifdef __FreeBSD__ + kt->pfrkt_larg = V_pfi_update; +#else kt->pfrkt_larg = pfi_update; +#endif } pfr_dynaddr_update(kt, dyn); } @@ -555,7 +627,11 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) int e, size2 = 0; struct ifg_member *ifgm; +#ifdef __FreeBSD__ + V_pfi_buffer_cnt = 0; +#else pfi_buffer_cnt = 0; +#endif if (kif->pfik_ifp != NULL) pfi_instance_add(kif->pfik_ifp, net, flags); @@ -563,10 +639,17 @@ pfi_table_update(struct pfr_ktable *kt, struct pfi_kif *kif, int net, int flags) TAILQ_FOREACH(ifgm, &kif->pfik_group->ifg_members, ifgm_next) pfi_instance_add(ifgm->ifgm_ifp, net, flags); +#ifdef __FreeBSD__ + if ((e = pfr_set_addrs(&kt->pfrkt_t, V_pfi_buffer, V_pfi_buffer_cnt, &size2, + NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) + printf("pfi_table_update: cannot set %d new addresses " + "into table %s: %d\n", V_pfi_buffer_cnt, kt->pfrkt_name, e); +#else if ((e = pfr_set_addrs(&kt->pfrkt_t, pfi_buffer, pfi_buffer_cnt, &size2, NULL, NULL, NULL, 0, PFR_TFLAG_ALLMASK))) printf("pfi_table_update: cannot set %d new addresses " "into table %s: %d\n", pfi_buffer_cnt, kt->pfrkt_name, e); +#endif } void @@ -587,9 +670,9 @@ pfi_instance_add(struct ifnet *ifp, int net, int flags) #ifdef __FreeBSD__ /* * XXX: For point-to-point interfaces, (ifname:0) and IPv4, - * jump over addresses without a proper route to work - * around a problem with ppp not fully removing the - * address used during IPCP. + * jump over addresses without a proper route to work + * around a problem with ppp not fully removing the + * address used during IPCP. */ if ((ifp->if_flags & IFF_POINTOPOINT) && !(ia->ifa_flags & IFA_ROUTE) && @@ -644,15 +727,24 @@ pfi_address_add(struct sockaddr *sa, int af, int net) struct pfr_addr *p; int i; +#ifdef __FreeBSD__ + if (V_pfi_buffer_cnt >= V_pfi_buffer_max) { + int new_max = V_pfi_buffer_max * 2; +#else if (pfi_buffer_cnt >= pfi_buffer_max) { int new_max = pfi_buffer_max * 2; +#endif if (new_max > PFI_BUFFER_MAX) { printf("pfi_address_add: address buffer full (%d/%d)\n", +#ifdef __FreeBSD__ + V_pfi_buffer_cnt, PFI_BUFFER_MAX); +#else pfi_buffer_cnt, PFI_BUFFER_MAX); +#endif return; } - p = malloc(new_max * sizeof(*pfi_buffer), PFI_MTYPE, + p = malloc(new_max * sizeof(*V_pfi_buffer), PFI_MTYPE, #ifdef __FreeBSD__ M_NOWAIT); #else @@ -660,18 +752,34 @@ pfi_address_add(struct sockaddr *sa, int af, int net) #endif if (p == NULL) { printf("pfi_address_add: no memory to grow buffer " +#ifdef __FreeBSD__ + "(%d/%d)\n", V_pfi_buffer_cnt, PFI_BUFFER_MAX); +#else "(%d/%d)\n", pfi_buffer_cnt, PFI_BUFFER_MAX); +#endif return; } - memcpy(p, pfi_buffer, pfi_buffer_max * sizeof(*pfi_buffer)); +#ifdef __FreeBSD__ + memcpy(V_pfi_buffer, p, V_pfi_buffer_cnt * sizeof(*V_pfi_buffer)); + /* no need to zero buffer */ + free(V_pfi_buffer, PFI_MTYPE); + V_pfi_buffer = p; + V_pfi_buffer_max = new_max; +#else + memcpy(pfi_buffer, p, pfi_buffer_cnt * sizeof(*pfi_buffer)); /* no need to zero buffer */ free(pfi_buffer, PFI_MTYPE); pfi_buffer = p; pfi_buffer_max = new_max; +#endif } if (af == AF_INET && net > 32) net = 128; +#ifdef __FreeBSD__ + p = V_pfi_buffer + V_pfi_buffer_cnt++; +#else p = pfi_buffer + pfi_buffer_cnt++; +#endif bzero(p, sizeof(*p)); p->pfra_af = af; p->pfra_net = net; @@ -704,7 +812,11 @@ pfi_dynaddr_remove(struct pf_addr_wrap *aw) aw->p.dyn->pfid_kif = NULL; pfr_detach_table(aw->p.dyn->pfid_kt); aw->p.dyn->pfid_kt = NULL; +#ifdef __FreeBSD__ + pool_put(&V_pfi_addr_pl, aw->p.dyn); +#else pool_put(&pfi_addr_pl, aw->p.dyn); +#endif aw->p.dyn = NULL; splx(s); } @@ -725,7 +837,11 @@ pfi_kifaddr_update(void *v) struct pfi_kif *kif = (struct pfi_kif *)v; s = splsoftnet(); +#ifdef __FreeBSD__ + V_pfi_update++; +#else pfi_update++; +#endif pfi_kif_update(kif); splx(s); } @@ -737,49 +853,61 @@ pfi_if_compare(struct pfi_kif *p, struct pfi_kif *q) } void -pfi_fill_oldstatus(struct pf_status *pfs) +pfi_update_status(const char *name, struct pf_status *pfs) { struct pfi_kif *p; - struct pfi_kif_cmp key; + struct pfi_kif_cmp key; + struct ifg_member p_member, *ifgm; + TAILQ_HEAD(, ifg_member) ifg_members; int i, j, k, s; - strlcpy(key.pfik_name, pfs->ifname, sizeof(key.pfik_name)); + strlcpy(key.pfik_name, name, sizeof(key.pfik_name)); s = splsoftnet(); +#ifdef __FreeBSD__ + p = RB_FIND(pfi_ifhead, &V_pfi_ifs, (struct pfi_kif *)&key); +#else p = RB_FIND(pfi_ifhead, &pfi_ifs, (struct pfi_kif *)&key); +#endif if (p == NULL) { splx(s); return; } - bzero(pfs->pcounters, sizeof(pfs->pcounters)); - bzero(pfs->bcounters, sizeof(pfs->bcounters)); - for (i = 0; i < 2; i++) - for (j = 0; j < 2; j++) - for (k = 0; k < 2; k++) { - pfs->pcounters[i][j][k] = - p->pfik_packets[i][j][k]; - pfs->bcounters[i][j] += - p->pfik_bytes[i][j][k]; - } - splx(s); -} - -int -pfi_clr_istats(const char *name) -{ - struct pfi_kif *p; - int s; + if (p->pfik_group != NULL) { + bcopy(&p->pfik_group->ifg_members, &ifg_members, + sizeof(ifg_members)); + } else { + /* build a temporary list for p only */ + bzero(&p_member, sizeof(p_member)); + p_member.ifgm_ifp = p->pfik_ifp; + TAILQ_INIT(&ifg_members); + TAILQ_INSERT_TAIL(&ifg_members, &p_member, ifgm_next); + } + if (pfs) { + bzero(pfs->pcounters, sizeof(pfs->pcounters)); + bzero(pfs->bcounters, sizeof(pfs->bcounters)); + } + TAILQ_FOREACH(ifgm, &ifg_members, ifgm_next) { + if (ifgm->ifgm_ifp == NULL) + continue; + p = (struct pfi_kif *)ifgm->ifgm_ifp->if_pf_kif; - s = splsoftnet(); - RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { - if (pfi_skip_if(name, p)) + /* just clear statistics */ + if (pfs == NULL) { + bzero(p->pfik_packets, sizeof(p->pfik_packets)); + bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); + p->pfik_tzero = time_second; continue; - bzero(p->pfik_packets, sizeof(p->pfik_packets)); - bzero(p->pfik_bytes, sizeof(p->pfik_bytes)); - p->pfik_tzero = time_second; + } + for (i = 0; i < 2; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) { + pfs->pcounters[i][j][k] += + p->pfik_packets[i][j][k]; + pfs->bcounters[i][j] += + p->pfik_bytes[i][j][k]; + } } splx(s); - - return (0); } int @@ -792,8 +920,13 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) #endif s = splsoftnet(); +#ifdef __FreeBSD__ + for (p = RB_MIN(pfi_ifhead, &V_pfi_ifs); p; p = nextp) { + nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); +#else for (p = RB_MIN(pfi_ifhead, &pfi_ifs); p; p = nextp) { nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); +#endif if (pfi_skip_if(name, p)) continue; if (*size > n++) { @@ -810,7 +943,11 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) splx(s); return (EFAULT); } +#ifdef __FreeBSD__ + nextp = RB_NEXT(pfi_ifhead, &V_pfi_ifs, p); +#else nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); +#endif pfi_kif_unref(p, PFI_KIF_REF_RULE); } } @@ -845,7 +982,11 @@ pfi_set_flags(const char *name, int flags) int s; s = splsoftnet(); +#ifdef __FreeBSD__ + RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { +#else RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { +#endif if (pfi_skip_if(name, p)) continue; p->pfik_flags |= flags; @@ -861,7 +1002,11 @@ pfi_clear_flags(const char *name, int flags) int s; s = splsoftnet(); +#ifdef __FreeBSD__ + RB_FOREACH(p, pfi_ifhead, &V_pfi_ifs) { +#else RB_FOREACH(p, pfi_ifhead, &pfi_ifs) { +#endif if (pfi_skip_if(name, p)) continue; p->pfik_flags &= ~flags; @@ -894,55 +1039,73 @@ pfi_unmask(void *addr) void pfi_attach_ifnet_event(void *arg __unused, struct ifnet *ifp) { + + CURVNET_SET(ifp->if_vnet); PF_LOCK(); pfi_attach_ifnet(ifp); #ifdef ALTQ pf_altq_ifnet_event(ifp, 0); #endif PF_UNLOCK(); + CURVNET_RESTORE(); } void pfi_detach_ifnet_event(void *arg __unused, struct ifnet *ifp) { + + CURVNET_SET(ifp->if_vnet); PF_LOCK(); pfi_detach_ifnet(ifp); #ifdef ALTQ pf_altq_ifnet_event(ifp, 1); #endif PF_UNLOCK(); + CURVNET_RESTORE(); } void -pfi_attach_group_event(void *arg __unused, struct ifg_group *ifg) +pfi_attach_group_event(void *arg , struct ifg_group *ifg) { + + CURVNET_SET((struct vnet *)arg); PF_LOCK(); pfi_attach_ifgroup(ifg); PF_UNLOCK(); + CURVNET_RESTORE(); } void -pfi_change_group_event(void *arg __unused, char *gname) +pfi_change_group_event(void *arg, char *gname) { + + CURVNET_SET((struct vnet *)arg); PF_LOCK(); pfi_group_change(gname); PF_UNLOCK(); + CURVNET_RESTORE(); } void -pfi_detach_group_event(void *arg __unused, struct ifg_group *ifg) +pfi_detach_group_event(void *arg, struct ifg_group *ifg) { + + CURVNET_SET((struct vnet *)arg); PF_LOCK(); pfi_detach_ifgroup(ifg); PF_UNLOCK(); + CURVNET_RESTORE(); } void pfi_ifaddr_event(void *arg __unused, struct ifnet *ifp) { + + CURVNET_SET(ifp->if_vnet); PF_LOCK(); if (ifp && ifp->if_pf_kif) pfi_kifaddr_update(ifp->if_pf_kif); PF_UNLOCK(); + CURVNET_RESTORE(); } #endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c index c41fcc6..2ca1630 100644 --- a/sys/contrib/pf/net/pf_ioctl.c +++ b/sys/contrib/pf/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.175 2007/02/26 22:47:43 deraadt Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.213 2009/02/15 21:46:12 mbalmer Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -45,27 +45,26 @@ __FBSDID("$FreeBSD$"); #include "opt_pf.h" #ifdef DEV_BPF -#define NBPFILTER DEV_BPF +#define NBPFILTER DEV_BPF #else -#define NBPFILTER 0 +#define NBPFILTER 0 #endif #ifdef DEV_PFLOG -#define NPFLOG DEV_PFLOG +#define NPFLOG DEV_PFLOG #else -#define NPFLOG 0 +#define NPFLOG 0 #endif #ifdef DEV_PFSYNC -#define NPFSYNC DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC #else -#define NPFSYNC 0 +#define NPFSYNC 0 #endif #else -#include "bpfilter.h" -#include "pflog.h" #include "pfsync.h" +#include "pflog.h" #endif #include <sys/param.h> @@ -77,8 +76,9 @@ __FBSDID("$FreeBSD$"); #include <sys/socketvar.h> #include <sys/kernel.h> #include <sys/time.h> -#include <sys/malloc.h> #ifdef __FreeBSD__ +#include <sys/ucred.h> +#include <sys/jail.h> #include <sys/module.h> #include <sys/conf.h> #include <sys/proc.h> @@ -100,6 +100,7 @@ __FBSDID("$FreeBSD$"); #ifdef __FreeBSD__ #include <net/vnet.h> #endif +#include <net/route.h> #include <netinet/in.h> #include <netinet/in_var.h> @@ -116,11 +117,11 @@ __FBSDID("$FreeBSD$"); #endif #include <net/pfvar.h> -#if NPFSYNC > 0 #include <net/if_pfsync.h> -#endif /* NPFSYNC > 0 */ +#if NPFLOG > 0 #include <net/if_pflog.h> +#endif /* NPFLOG > 0 */ #ifdef INET6 #include <netinet/ip6.h> @@ -156,7 +157,7 @@ void pf_empty_pool(struct pf_palist *); #ifdef __FreeBSD__ int pfioctl(struct cdev *, u_long, caddr_t, int, struct thread *); #else -int pfioctl(struct cdev *, u_long, caddr_t, int, struct proc *); +int pfioctl(dev_t, u_long, caddr_t, int, struct proc *); #endif #ifdef ALTQ int pf_begin_altq(u_int32_t *); @@ -171,25 +172,43 @@ int pf_setup_pfsync_matching(struct pf_ruleset *); void pf_hash_rule(MD5_CTX *, struct pf_rule *); void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); int pf_commit_rules(u_int32_t, int, char *); +int pf_addr_setup(struct pf_ruleset *, + struct pf_addr_wrap *, sa_family_t); +void pf_addr_copyout(struct pf_addr_wrap *); + +#define TAGID_MAX 50000 -struct pf_rule pf_default_rule; #ifdef __FreeBSD__ -struct sx pf_consistency_lock; -SX_SYSINIT(pf_consistency_lock, &pf_consistency_lock, "pf_statetbl_lock"); -#else -struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER; +VNET_DEFINE(struct pf_rule, pf_default_rule); +VNET_DEFINE(struct sx, pf_consistency_lock); + +#ifdef ALTQ +static VNET_DEFINE(int, pf_altq_running); +#define V_pf_altq_running VNET(pf_altq_running) #endif + +TAILQ_HEAD(pf_tags, pf_tagname); + +#define V_pf_tags VNET(pf_tags) +VNET_DEFINE(struct pf_tags, pf_tags); +#define V_pf_qids VNET(pf_qids) +VNET_DEFINE(struct pf_tags, pf_qids); + +#else /* !__FreeBSD__ */ +struct pf_rule pf_default_rule; +struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); #ifdef ALTQ static int pf_altq_running; #endif -#define TAGID_MAX 50000 TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags), pf_qids = TAILQ_HEAD_INITIALIZER(pf_qids); +#endif /* __FreeBSD__ */ #if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE) #error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE #endif + u_int16_t tagname2tag(struct pf_tags *, char *); void tag2tagname(struct pf_tags *, u_int16_t, char *); void tag_unref(struct pf_tags *, u_int16_t); @@ -197,12 +216,15 @@ int pf_rtlabel_add(struct pf_addr_wrap *); void pf_rtlabel_remove(struct pf_addr_wrap *); void pf_rtlabel_copyout(struct pf_addr_wrap *); +#ifdef __FreeBSD__ +#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x +#else #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x - +#endif #ifdef __FreeBSD__ -static struct cdev *pf_dev; - +struct cdev *pf_dev; + /* * XXX - These are new and need to be checked when moveing to a new version */ @@ -218,22 +240,22 @@ static void pf_clear_srcnodes(void); */ #ifdef INET static int pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir, struct inpcb *inp); + int dir, struct inpcb *inp); static int pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir, struct inpcb *inp); + int dir, struct inpcb *inp); #endif #ifdef INET6 static int pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir, struct inpcb *inp); + int dir, struct inpcb *inp); static int pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, - int dir, struct inpcb *inp); + int dir, struct inpcb *inp); #endif - -static int hook_pf(void); -static int dehook_pf(void); -static int shutdown_pf(void); -static int pf_load(void); -static int pf_unload(void); + +static int hook_pf(void); +static int dehook_pf(void); +static int shutdown_pf(void); +static int pf_load(void); +static int pf_unload(void); static struct cdevsw pf_cdevsw = { .d_ioctl = pfioctl, @@ -241,78 +263,97 @@ static struct cdevsw pf_cdevsw = { .d_version = D_VERSION, }; -static volatile int pf_pfil_hooked = 0; -int pf_end_threads = 0; -struct mtx pf_task_mtx; -pflog_packet_t *pflog_packet_ptr = NULL; - -int debug_pfugidhack = 0; -SYSCTL_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, &debug_pfugidhack, 0, - "Enable/disable pf user/group rules mpsafe hack"); +static volatile VNET_DEFINE(int, pf_pfil_hooked); +#define V_pf_pfil_hooked VNET(pf_pfil_hooked) +VNET_DEFINE(int, pf_end_threads); +VNET_DEFINE(struct mtx, pf_task_mtx); + +/* pfsync */ +pfsync_state_import_t *pfsync_state_import_ptr = NULL; +pfsync_insert_state_t *pfsync_insert_state_ptr = NULL; +pfsync_update_state_t *pfsync_update_state_ptr = NULL; +pfsync_delete_state_t *pfsync_delete_state_ptr = NULL; +pfsync_clear_states_t *pfsync_clear_states_ptr = NULL; +pfsync_state_in_use_t *pfsync_state_in_use_ptr = NULL; +pfsync_defer_t *pfsync_defer_ptr = NULL; +pfsync_up_t *pfsync_up_ptr = NULL; +/* pflow */ +export_pflow_t *export_pflow_ptr = NULL; +/* pflog */ +pflog_packet_t *pflog_packet_ptr = NULL; + +VNET_DEFINE(int, debug_pfugidhack); +SYSCTL_VNET_INT(_debug, OID_AUTO, pfugidhack, CTLFLAG_RW, + &VNET_NAME(debug_pfugidhack), 0, + "Enable/disable pf user/group rules mpsafe hack"); void init_pf_mutex(void) { - mtx_init(&pf_task_mtx, "pf task mtx", NULL, MTX_DEF); + + mtx_init(&V_pf_task_mtx, "pf task mtx", NULL, MTX_DEF); } void destroy_pf_mutex(void) { - mtx_destroy(&pf_task_mtx); -} + mtx_destroy(&V_pf_task_mtx); +} void init_zone_var(void) { - pf_src_tree_pl = pf_rule_pl = NULL; - pf_state_pl = pf_altq_pl = pf_pooladdr_pl = NULL; - pf_frent_pl = pf_frag_pl = pf_cache_pl = pf_cent_pl = NULL; - pf_state_scrub_pl = NULL; - pfr_ktable_pl = pfr_kentry_pl = NULL; + V_pf_src_tree_pl = V_pf_rule_pl = NULL; + V_pf_state_pl = V_pf_state_key_pl = V_pf_state_item_pl = NULL; + V_pf_altq_pl = V_pf_pooladdr_pl = NULL; + V_pf_frent_pl = V_pf_frag_pl = V_pf_cache_pl = V_pf_cent_pl = NULL; + V_pf_state_scrub_pl = NULL; + V_pfr_ktable_pl = V_pfr_kentry_pl = NULL; } void cleanup_pf_zone(void) { - UMA_DESTROY(pf_src_tree_pl); - UMA_DESTROY(pf_rule_pl); - UMA_DESTROY(pf_state_pl); - UMA_DESTROY(pf_altq_pl); - UMA_DESTROY(pf_pooladdr_pl); - UMA_DESTROY(pf_frent_pl); - UMA_DESTROY(pf_frag_pl); - UMA_DESTROY(pf_cache_pl); - UMA_DESTROY(pf_cent_pl); - UMA_DESTROY(pfr_ktable_pl); - UMA_DESTROY(pfr_kentry_pl2); - UMA_DESTROY(pfr_kentry_pl); - UMA_DESTROY(pf_state_scrub_pl); - UMA_DESTROY(pfi_addr_pl); + UMA_DESTROY(V_pf_src_tree_pl); + UMA_DESTROY(V_pf_rule_pl); + UMA_DESTROY(V_pf_state_pl); + UMA_DESTROY(V_pf_state_key_pl); + UMA_DESTROY(V_pf_state_item_pl); + UMA_DESTROY(V_pf_altq_pl); + UMA_DESTROY(V_pf_pooladdr_pl); + UMA_DESTROY(V_pf_frent_pl); + UMA_DESTROY(V_pf_frag_pl); + UMA_DESTROY(V_pf_cache_pl); + UMA_DESTROY(V_pf_cent_pl); + UMA_DESTROY(V_pfr_ktable_pl); + UMA_DESTROY(V_pfr_kentry_pl); + UMA_DESTROY(V_pf_state_scrub_pl); + UMA_DESTROY(V_pfi_addr_pl); } int pfattach(void) { - u_int32_t *my_timeout = pf_default_rule.timeout; + u_int32_t *my_timeout = V_pf_default_rule.timeout; int error = 1; do { - UMA_CREATE(pf_src_tree_pl,struct pf_src_node, "pfsrctrpl"); - UMA_CREATE(pf_rule_pl, struct pf_rule, "pfrulepl"); - UMA_CREATE(pf_state_pl, struct pf_state, "pfstatepl"); - UMA_CREATE(pf_altq_pl, struct pf_altq, "pfaltqpl"); - UMA_CREATE(pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); - UMA_CREATE(pfr_ktable_pl, struct pfr_ktable, "pfrktable"); - UMA_CREATE(pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); - UMA_CREATE(pfr_kentry_pl2, struct pfr_kentry, "pfrkentry2"); - UMA_CREATE(pf_frent_pl, struct pf_frent, "pffrent"); - UMA_CREATE(pf_frag_pl, struct pf_fragment, "pffrag"); - UMA_CREATE(pf_cache_pl, struct pf_fragment, "pffrcache"); - UMA_CREATE(pf_cent_pl, struct pf_frcache, "pffrcent"); - UMA_CREATE(pf_state_scrub_pl, struct pf_state_scrub, + UMA_CREATE(V_pf_src_tree_pl, struct pf_src_node, "pfsrctrpl"); + UMA_CREATE(V_pf_rule_pl, struct pf_rule, "pfrulepl"); + UMA_CREATE(V_pf_state_pl, struct pf_state, "pfstatepl"); + UMA_CREATE(V_pf_state_key_pl, struct pf_state, "pfstatekeypl"); + UMA_CREATE(V_pf_state_item_pl, struct pf_state, "pfstateitempl"); + UMA_CREATE(V_pf_altq_pl, struct pf_altq, "pfaltqpl"); + UMA_CREATE(V_pf_pooladdr_pl, struct pf_pooladdr, "pfpooladdrpl"); + UMA_CREATE(V_pfr_ktable_pl, struct pfr_ktable, "pfrktable"); + UMA_CREATE(V_pfr_kentry_pl, struct pfr_kentry, "pfrkentry"); + UMA_CREATE(V_pf_frent_pl, struct pf_frent, "pffrent"); + UMA_CREATE(V_pf_frag_pl, struct pf_fragment, "pffrag"); + UMA_CREATE(V_pf_cache_pl, struct pf_fragment, "pffrcache"); + UMA_CREATE(V_pf_cent_pl, struct pf_frcache, "pffrcent"); + UMA_CREATE(V_pf_state_scrub_pl, struct pf_state_scrub, "pfstatescrub"); - UMA_CREATE(pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); + UMA_CREATE(V_pfi_addr_pl, struct pfi_dynaddr, "pfiaddrpl"); error = 0; } while(0); if (error) { @@ -327,34 +368,35 @@ pfattach(void) return (error); } - pf_pool_limits[PF_LIMIT_STATES].pp = pf_state_pl; - pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; - pf_pool_limits[PF_LIMIT_SRC_NODES].pp = pf_src_tree_pl; - pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; - pf_pool_limits[PF_LIMIT_FRAGS].pp = pf_frent_pl; - pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; - pf_pool_limits[PF_LIMIT_TABLES].pp = pfr_ktable_pl; - pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT; - pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = pfr_kentry_pl; - pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; - uma_zone_set_max(pf_pool_limits[PF_LIMIT_STATES].pp, - pf_pool_limits[PF_LIMIT_STATES].limit); - - RB_INIT(&tree_src_tracking); - RB_INIT(&pf_anchors); + V_pf_pool_limits[PF_LIMIT_STATES].pp = V_pf_state_pl; + V_pf_pool_limits[PF_LIMIT_STATES].limit = PFSTATE_HIWAT; + V_pf_pool_limits[PF_LIMIT_SRC_NODES].pp = V_pf_src_tree_pl; + V_pf_pool_limits[PF_LIMIT_SRC_NODES].limit = PFSNODE_HIWAT; + V_pf_pool_limits[PF_LIMIT_FRAGS].pp = V_pf_frent_pl; + V_pf_pool_limits[PF_LIMIT_FRAGS].limit = PFFRAG_FRENT_HIWAT; + V_pf_pool_limits[PF_LIMIT_TABLES].pp = V_pfr_ktable_pl; + V_pf_pool_limits[PF_LIMIT_TABLES].limit = PFR_KTABLE_HIWAT; + V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].pp = V_pfr_kentry_pl; + V_pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT; + uma_zone_set_max(V_pf_pool_limits[PF_LIMIT_STATES].pp, + V_pf_pool_limits[PF_LIMIT_STATES].limit); + + RB_INIT(&V_tree_src_tracking); + RB_INIT(&V_pf_anchors); pf_init_ruleset(&pf_main_ruleset); - TAILQ_INIT(&pf_altqs[0]); - TAILQ_INIT(&pf_altqs[1]); - TAILQ_INIT(&pf_pabuf); - pf_altqs_active = &pf_altqs[0]; - pf_altqs_inactive = &pf_altqs[1]; - TAILQ_INIT(&state_list); + + TAILQ_INIT(&V_pf_altqs[0]); + TAILQ_INIT(&V_pf_altqs[1]); + TAILQ_INIT(&V_pf_pabuf); + V_pf_altqs_active = &V_pf_altqs[0]; + V_pf_altqs_inactive = &V_pf_altqs[1]; + TAILQ_INIT(&V_state_list); /* default rule should never be garbage collected */ - pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next; - pf_default_rule.action = PF_PASS; - pf_default_rule.nr = -1; - pf_default_rule.rtableid = -1; + V_pf_default_rule.entries.tqe_prev = &V_pf_default_rule.entries.tqe_next; + V_pf_default_rule.action = PF_PASS; + V_pf_default_rule.nr = -1; + V_pf_default_rule.rtableid = -1; /* initialize default timeouts */ my_timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; @@ -379,20 +421,24 @@ pfattach(void) my_timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; pf_normalize_init(); - bzero(&pf_status, sizeof(pf_status)); - pf_status.debug = PF_DEBUG_URGENT; - pf_pfil_hooked = 0; + bzero(&V_pf_status, sizeof(V_pf_status)); + V_pf_status.debug = PF_DEBUG_URGENT; + + V_pf_pfil_hooked = 0; /* XXX do our best to avoid a conflict */ - pf_status.hostid = arc4random(); + V_pf_status.hostid = arc4random(); - if (kproc_create(pf_purge_thread, NULL, NULL, 0, 0, "pfpurge")) + if (kproc_create(pf_purge_thread, curvnet, NULL, 0, 0, "pfpurge")) return (ENXIO); + m_addr_chg_pf_p = pf_pkt_addr_changed; + return (error); } #else /* !__FreeBSD__ */ + void pfattach(int num) { @@ -404,6 +450,10 @@ pfattach(int num) "pfsrctrpl", NULL); pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", NULL); + pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0, + "pfstatekeypl", NULL); + pool_init(&pf_state_item_pl, sizeof(struct pf_state_item), 0, 0, 0, + "pfstateitempl", NULL); pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", &pool_allocator_nointr); pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, @@ -415,7 +465,7 @@ pfattach(int num) pool_sethardlimit(pf_pool_limits[PF_LIMIT_STATES].pp, pf_pool_limits[PF_LIMIT_STATES].limit, NULL, 0); - if (ctob(physmem) <= 100*1024*1024) + if (physmem <= atop(100*1024*1024)) pf_pool_limits[PF_LIMIT_TABLE_ENTRIES].limit = PFR_KENTRY_HIWAT_SMALL; @@ -465,32 +515,32 @@ pfattach(int num) pf_status.hostid = arc4random(); /* require process context to purge states, so perform in a thread */ - kproc_create_deferred(pf_thread_create, NULL); + kthread_create_deferred(pf_thread_create, NULL); } void pf_thread_create(void *v) { - if (kproc_create(pf_purge_thread, NULL, NULL, "pfpurge")) + if (kthread_create(pf_purge_thread, NULL, NULL, "pfpurge")) panic("pfpurge thread"); } int -pfopen(struct cdev *dev, int flags, int fmt, struct proc *p) +pfopen(dev_t dev, int flags, int fmt, struct proc *p) { - if (dev2unit(dev) >= 1) + if (minor(dev) >= 1) return (ENXIO); return (0); } int -pfclose(struct cdev *dev, int flags, int fmt, struct proc *p) +pfclose(dev_t dev, int flags, int fmt, struct proc *p) { - if (dev2unit(dev) >= 1) + if (minor(dev) >= 1) return (ENXIO); return (0); } -#endif /* __FreeBSD__ */ +#endif struct pf_pool * pf_get_pool(char *anchor, u_int32_t ticket, u_int8_t rule_action, @@ -557,7 +607,11 @@ pf_empty_pool(struct pf_palist *poola) pf_tbladdr_remove(&empty_pool_pa->addr); pfi_kif_unref(empty_pool_pa->kif, PFI_KIF_REF_RULE); TAILQ_REMOVE(poola, empty_pool_pa, entries); +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, empty_pool_pa); +#else pool_put(&pf_pooladdr_pl, empty_pool_pa); +#endif } } @@ -565,7 +619,7 @@ void pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) { if (rulequeue != NULL) { - if (rule->states <= 0) { + if (rule->states_cur <= 0) { /* * XXX - we need to remove the table *before* detaching * the rule to make sure the table code does not delete @@ -581,7 +635,7 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) rule->nr = -1; } - if (rule->states > 0 || rule->src_nodes > 0 || + if (rule->states_cur > 0 || rule->src_nodes > 0 || rule->entries.tqe_prev != NULL) return; pf_tag_unref(rule->tag); @@ -604,7 +658,11 @@ pf_rm_rule(struct pf_rulequeue *rulequeue, struct pf_rule *rule) pfi_kif_unref(rule->kif, PFI_KIF_REF_RULE); pf_anchor_remove(rule); pf_empty_pool(&rule->rpool.list); +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, rule); +#else pool_put(&pf_rule_pl, rule); +#endif } u_int16_t @@ -635,11 +693,9 @@ tagname2tag(struct pf_tags *head, char *tagname) return (0); /* allocate and fill new struct pf_tagname */ - tag = (struct pf_tagname *)malloc(sizeof(struct pf_tagname), - M_TEMP, M_NOWAIT); + tag = malloc(sizeof(*tag), M_TEMP, M_NOWAIT|M_ZERO); if (tag == NULL) return (0); - bzero(tag, sizeof(struct pf_tagname)); strlcpy(tag->name, tagname, sizeof(tag->name)); tag->tag = new_tagid; tag->ref++; @@ -687,13 +743,21 @@ tag_unref(struct pf_tags *head, u_int16_t tag) u_int16_t pf_tagname2tag(char *tagname) { +#ifdef __FreeBSD__ + return (tagname2tag(&V_pf_tags, tagname)); +#else return (tagname2tag(&pf_tags, tagname)); +#endif } void pf_tag2tagname(u_int16_t tagid, char *p) { +#ifdef __FreeBSD__ + tag2tagname(&V_pf_tags, tagid, p); +#else tag2tagname(&pf_tags, tagid, p); +#endif } void @@ -701,7 +765,11 @@ pf_tag_ref(u_int16_t tag) { struct pf_tagname *t; +#ifdef __FreeBSD__ + TAILQ_FOREACH(t, &V_pf_tags, entries) +#else TAILQ_FOREACH(t, &pf_tags, entries) +#endif if (t->tag == tag) break; if (t != NULL) @@ -711,7 +779,11 @@ pf_tag_ref(u_int16_t tag) void pf_tag_unref(u_int16_t tag) { +#ifdef __FreeBSD__ + tag_unref(&V_pf_tags, tag); +#else tag_unref(&pf_tags, tag); +#endif } int @@ -764,19 +836,31 @@ pf_rtlabel_copyout(struct pf_addr_wrap *a) u_int32_t pf_qname2qid(char *qname) { +#ifdef __FreeBSD__ + return ((u_int32_t)tagname2tag(&V_pf_qids, qname)); +#else return ((u_int32_t)tagname2tag(&pf_qids, qname)); +#endif } void pf_qid2qname(u_int32_t qid, char *p) { +#ifdef __FreeBSD__ + tag2tagname(&V_pf_qids, (u_int16_t)qid, p); +#else tag2tagname(&pf_qids, (u_int16_t)qid, p); +#endif } void pf_qid_unref(u_int32_t qid) { +#ifdef __FreeBSD__ + tag_unref(&V_pf_qids, (u_int16_t)qid); +#else tag_unref(&pf_qids, (u_int16_t)qid); +#endif } int @@ -786,24 +870,35 @@ pf_begin_altq(u_int32_t *ticket) int error = 0; /* Purge the old altq list */ - while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { - TAILQ_REMOVE(pf_altqs_inactive, altq, entries); #ifdef __FreeBSD__ + while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); if (altq->qname[0] == 0 && (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { #else + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); if (altq->qname[0] == 0) { #endif /* detach and destroy the discipline */ error = altq_remove(altq); } else pf_qid_unref(altq->qid); +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, altq); +#else pool_put(&pf_altq_pl, altq); +#endif } if (error) return (error); +#ifdef __FreeBSD__ + *ticket = ++V_ticket_altqs_inactive; + V_altqs_inactive_open = 1; +#else *ticket = ++ticket_altqs_inactive; altqs_inactive_open = 1; +#endif return (0); } @@ -813,24 +908,37 @@ pf_rollback_altq(u_int32_t ticket) struct pf_altq *altq; int error = 0; +#ifdef __FreeBSD__ + if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) + return (0); + /* Purge the old altq list */ + while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { +#else if (!altqs_inactive_open || ticket != ticket_altqs_inactive) return (0); /* Purge the old altq list */ while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { TAILQ_REMOVE(pf_altqs_inactive, altq, entries); -#ifdef __FreeBSD__ - if (altq->qname[0] == 0 && - (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { -#else if (altq->qname[0] == 0) { #endif /* detach and destroy the discipline */ error = altq_remove(altq); } else pf_qid_unref(altq->qid); +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, altq); +#else pool_put(&pf_altq_pl, altq); +#endif } +#ifdef __FreeBSD__ + V_altqs_inactive_open = 0; +#else altqs_inactive_open = 0; +#endif return (error); } @@ -841,27 +949,43 @@ pf_commit_altq(u_int32_t ticket) struct pf_altq *altq; int s, err, error = 0; +#ifdef __FreeBSD__ + if (!V_altqs_inactive_open || ticket != V_ticket_altqs_inactive) +#else if (!altqs_inactive_open || ticket != ticket_altqs_inactive) +#endif return (EBUSY); /* swap altqs, keep the old. */ s = splsoftnet(); +#ifdef __FreeBSD__ + old_altqs = V_pf_altqs_active; + V_pf_altqs_active = V_pf_altqs_inactive; + V_pf_altqs_inactive = old_altqs; + V_ticket_altqs_active = V_ticket_altqs_inactive; +#else old_altqs = pf_altqs_active; pf_altqs_active = pf_altqs_inactive; pf_altqs_inactive = old_altqs; ticket_altqs_active = ticket_altqs_inactive; +#endif /* Attach new disciplines */ - TAILQ_FOREACH(altq, pf_altqs_active, entries) { #ifdef __FreeBSD__ - if (altq->qname[0] == 0 && - (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { + TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { + if (altq->qname[0] == 0 && + (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { #else + TAILQ_FOREACH(altq, pf_altqs_active, entries) { if (altq->qname[0] == 0) { #endif /* attach the discipline */ error = altq_pfattach(altq); +#ifdef __FreeBSD__ + if (error == 0 && V_pf_altq_running) +#else if (error == 0 && pf_altq_running) +#endif error = pf_enable_altq(altq); if (error != 0) { splx(s); @@ -871,16 +995,22 @@ pf_commit_altq(u_int32_t ticket) } /* Purge the old altq list */ - while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { - TAILQ_REMOVE(pf_altqs_inactive, altq, entries); #ifdef __FreeBSD__ + while ((altq = TAILQ_FIRST(V_pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(V_pf_altqs_inactive, altq, entries); if (altq->qname[0] == 0 && (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { #else + while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) { + TAILQ_REMOVE(pf_altqs_inactive, altq, entries); if (altq->qname[0] == 0) { #endif /* detach and destroy the discipline */ +#ifdef __FreeBSD__ + if (V_pf_altq_running) +#else if (pf_altq_running) +#endif error = pf_disable_altq(altq); err = altq_pfdetach(altq); if (err != 0 && error == 0) @@ -890,11 +1020,19 @@ pf_commit_altq(u_int32_t ticket) error = err; } else pf_qid_unref(altq->qid); +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, altq); +#else pool_put(&pf_altq_pl, altq); +#endif } splx(s); +#ifdef __FreeBSD__ + V_altqs_inactive_open = 0; +#else altqs_inactive_open = 0; +#endif return (error); } @@ -969,22 +1107,32 @@ pf_disable_altq(struct pf_altq *altq) void pf_altq_ifnet_event(struct ifnet *ifp, int remove) { - struct ifnet *ifp1; - struct pf_altq *a1, *a2, *a3; - u_int32_t ticket; - int error = 0; + struct ifnet *ifp1; + struct pf_altq *a1, *a2, *a3; + u_int32_t ticket; + int error = 0; /* Interrupt userland queue modifications */ +#ifdef __FreeBSD__ + if (V_altqs_inactive_open) + pf_rollback_altq(V_ticket_altqs_inactive); +#else if (altqs_inactive_open) pf_rollback_altq(ticket_altqs_inactive); +#endif /* Start new altq ruleset */ if (pf_begin_altq(&ticket)) return; /* Copy the current active set */ +#ifdef __FreeBSD__ + TAILQ_FOREACH(a1, V_pf_altqs_active, entries) { + a2 = pool_get(&V_pf_altq_pl, PR_NOWAIT); +#else TAILQ_FOREACH(a1, pf_altqs_active, entries) { a2 = pool_get(&pf_altq_pl, PR_NOWAIT); +#endif if (a2 == NULL) { error = ENOMEM; break; @@ -994,11 +1142,19 @@ pf_altq_ifnet_event(struct ifnet *ifp, int remove) if (a2->qname[0] != 0) { if ((a2->qid = pf_qname2qid(a2->qname)) == 0) { error = EBUSY; +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, a2); +#else pool_put(&pf_altq_pl, a2); +#endif break; } a2->altq_disc = NULL; +#ifdef __FreeBSD__ + TAILQ_FOREACH(a3, V_pf_altqs_inactive, entries) { +#else TAILQ_FOREACH(a3, pf_altqs_inactive, entries) { +#endif if (strncmp(a3->ifname, a2->ifname, IFNAMSIZ) == 0 && a3->qname[0] == 0) { a2->altq_disc = a3->altq_disc; @@ -1016,23 +1172,35 @@ pf_altq_ifnet_event(struct ifnet *ifp, int remove) error = altq_add(a2); PF_LOCK(); +#ifdef __FreeBSD__ + if (ticket != V_ticket_altqs_inactive) +#else if (ticket != ticket_altqs_inactive) +#endif error = EBUSY; if (error) { +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, a2); +#else pool_put(&pf_altq_pl, a2); +#endif break; } } +#ifdef __FreeBSD__ + TAILQ_INSERT_TAIL(V_pf_altqs_inactive, a2, entries); +#else TAILQ_INSERT_TAIL(pf_altqs_inactive, a2, entries); +#endif } if (error != 0) pf_rollback_altq(ticket); else pf_commit_altq(ticket); -} + } #endif #endif /* ALTQ */ @@ -1252,11 +1420,34 @@ pf_setup_pfsync_matching(struct pf_ruleset *rs) } MD5Final(digest, &ctx); +#ifdef __FreeBSD__ + memcpy(V_pf_status.pf_chksum, digest, sizeof(V_pf_status.pf_chksum)); +#else memcpy(pf_status.pf_chksum, digest, sizeof(pf_status.pf_chksum)); +#endif return (0); } int +pf_addr_setup(struct pf_ruleset *ruleset, struct pf_addr_wrap *addr, + sa_family_t af) +{ + if (pfi_dynaddr_setup(addr, af) || + pf_tbladdr_setup(ruleset, addr)) + return (EINVAL); + + return (0); +} + +void +pf_addr_copyout(struct pf_addr_wrap *addr) +{ + pfi_dynaddr_copyout(addr); + pf_tbladdr_copyout(addr); + pf_rtlabel_copyout(addr); +} + +int #ifdef __FreeBSD__ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td) #else @@ -1270,6 +1461,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #endif int error = 0; + CURVNET_SET(TD_TO_VNET(td)); + /* XXX keep in sync with switch() below */ #ifdef __FreeBSD__ if (securelevel_gt(td->td_ucred, 2)) @@ -1373,7 +1566,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } return (EACCES); case DIOCGETRULE: - if (((struct pfioc_rule *)addr)->action == PF_GET_CLR_CNTR) + if (((struct pfioc_rule *)addr)->action == + PF_GET_CLR_CNTR) return (EACCES); break; default: @@ -1382,9 +1576,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (flags & FWRITE) #ifdef __FreeBSD__ - sx_xlock(&pf_consistency_lock); + sx_xlock(&V_pf_consistency_lock); else - sx_slock(&pf_consistency_lock); + sx_slock(&V_pf_consistency_lock); #else rw_enter_write(&pf_consistency_lock); else @@ -1399,7 +1593,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) switch (cmd) { case DIOCSTART: +#ifdef __FreeBSD__ + if (V_pf_status.running) +#else if (pf_status.running) +#endif error = EEXIST; else { #ifdef __FreeBSD__ @@ -1411,33 +1609,48 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) ("pf: pfil registeration fail\n")); break; } -#endif + V_pf_status.running = 1; + V_pf_status.since = time_second; + + if (V_pf_status.stateid == 0) { + V_pf_status.stateid = time_second; + V_pf_status.stateid = V_pf_status.stateid << 32; + } +#else pf_status.running = 1; pf_status.since = time_second; + if (pf_status.stateid == 0) { pf_status.stateid = time_second; pf_status.stateid = pf_status.stateid << 32; } +#endif DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); } break; case DIOCSTOP: - if (!pf_status.running) +#ifdef __FreeBSD__ + if (!V_pf_status.running) error = ENOENT; else { - pf_status.running = 0; -#ifdef __FreeBSD__ + V_pf_status.running = 0; PF_UNLOCK(); error = dehook_pf(); PF_LOCK(); if (error) { - pf_status.running = 1; + V_pf_status.running = 1; DPFPRINTF(PF_DEBUG_MISC, - ("pf: pfil unregisteration failed\n")); + ("pf: pfil unregisteration failed\n")); } -#endif + V_pf_status.since = time_second; +#else + if (!pf_status.running) + error = ENOENT; + else { + pf_status.running = 0; pf_status.since = time_second; +#endif DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); } break; @@ -1473,16 +1686,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; break; } - if (pr->pool_ticket != ticket_pabuf) { #ifdef __FreeBSD__ + if (pr->pool_ticket != V_ticket_pabuf) { DPFPRINTF(PF_DEBUG_MISC, ("pool_ticket: %d != %d\n", pr->pool_ticket, - ticket_pabuf)); + V_ticket_pabuf)); +#else + if (pr->pool_ticket != ticket_pabuf) { #endif error = EBUSY; break; } - rule = pool_get(&pf_rule_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + rule = pool_get(&V_pf_rule_pl, PR_NOWAIT); +#else + rule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); +#endif if (rule == NULL) { error = ENOMEM; break; @@ -1499,19 +1718,27 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) rule->kif = NULL; TAILQ_INIT(&rule->rpool.list); /* initialize refcounting */ - rule->states = 0; + rule->states_cur = 0; rule->src_nodes = 0; rule->entries.tqe_prev = NULL; #ifndef INET if (rule->af == AF_INET) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, rule); +#else pool_put(&pf_rule_pl, rule); +#endif error = EAFNOSUPPORT; break; } #endif /* INET */ #ifndef INET6 if (rule->af == AF_INET6) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, rule); +#else pool_put(&pf_rule_pl, rule); +#endif error = EAFNOSUPPORT; break; } @@ -1525,7 +1752,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (rule->ifname[0]) { rule->kif = pfi_kif_get(rule->ifname); if (rule->kif == NULL) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, rule); +#else pool_put(&pf_rule_pl, rule); +#endif error = EINVAL; break; } @@ -1562,40 +1793,42 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (rule->rt && !rule->direction) error = EINVAL; #if NPFLOG > 0 -#ifdef __FreeBSD__ if (!rule->log) rule->logif = 0; -#endif if (rule->logif >= PFLOGIFS_MAX) error = EINVAL; #endif if (pf_rtlabel_add(&rule->src.addr) || pf_rtlabel_add(&rule->dst.addr)) error = EBUSY; - if (pfi_dynaddr_setup(&rule->src.addr, rule->af)) + if (pf_addr_setup(ruleset, &rule->src.addr, rule->af)) error = EINVAL; - if (pfi_dynaddr_setup(&rule->dst.addr, rule->af)) - error = EINVAL; - if (pf_tbladdr_setup(ruleset, &rule->src.addr)) - error = EINVAL; - if (pf_tbladdr_setup(ruleset, &rule->dst.addr)) + if (pf_addr_setup(ruleset, &rule->dst.addr, rule->af)) error = EINVAL; if (pf_anchor_setup(rule, ruleset, pr->anchor_call)) error = EINVAL; +#ifdef __FreeBSD__ + TAILQ_FOREACH(pa, &V_pf_pabuf, entries) +#else TAILQ_FOREACH(pa, &pf_pabuf, entries) +#endif if (pf_tbladdr_setup(ruleset, &pa->addr)) error = EINVAL; if (rule->overload_tblname[0]) { if ((rule->overload_tbl = pfr_attach_table(ruleset, - rule->overload_tblname)) == NULL) + rule->overload_tblname, 0)) == NULL) error = EINVAL; else rule->overload_tbl->pfrkt_flags |= PFR_TFLAG_ACTIVE; } +#ifdef __FreeBSD__ + pf_mv_pool(&V_pf_pabuf, &rule->rpool.list); +#else pf_mv_pool(&pf_pabuf, &rule->rpool.list); +#endif if (((((rule->action == PF_NAT) || (rule->action == PF_RDR) || (rule->action == PF_BINAT)) && rule->anchor == NULL) || (rule->rt > PF_FASTROUTE)) && @@ -1608,14 +1841,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #ifdef __FreeBSD__ - if (!debug_pfugidhack && (rule->uid.op || rule->gid.op || + if (!V_debug_pfugidhack && (rule->uid.op || rule->gid.op || rule->log & PF_LOG_SOCKET_LOOKUP)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: debug.pfugidhack enabled\n")); - debug_pfugidhack = 1; + V_debug_pfugidhack = 1; } #endif - rule->rpool.cur = TAILQ_FIRST(&rule->rpool.list); rule->evaluations = rule->packets[0] = rule->packets[1] = rule->bytes[0] = rule->bytes[1] = 0; @@ -1685,12 +1917,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; break; } - pfi_dynaddr_copyout(&pr->rule.src.addr); - pfi_dynaddr_copyout(&pr->rule.dst.addr); - pf_tbladdr_copyout(&pr->rule.src.addr); - pf_tbladdr_copyout(&pr->rule.dst.addr); - pf_rtlabel_copyout(&pr->rule.src.addr); - pf_rtlabel_copyout(&pr->rule.dst.addr); + pf_addr_copyout(&pr->rule.src.addr); + pf_addr_copyout(&pr->rule.dst.addr); for (i = 0; i < PF_SKIP_COUNT; ++i) if (rule->skip[i].ptr == NULL) pr->rule.skip[i].nr = -1; @@ -1702,6 +1930,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) rule->evaluations = 0; rule->packets[0] = rule->packets[1] = 0; rule->bytes[0] = rule->bytes[1] = 0; + rule->states_tot = 0; } break; } @@ -1715,7 +1944,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (!(pcr->action == PF_CHANGE_REMOVE || pcr->action == PF_CHANGE_GET_TICKET) && +#ifdef __FreeBSD__ + pcr->pool_ticket != V_ticket_pabuf) { +#else pcr->pool_ticket != ticket_pabuf) { +#endif error = EBUSY; break; } @@ -1752,7 +1985,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } if (pcr->action != PF_CHANGE_REMOVE) { - newrule = pool_get(&pf_rule_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + newrule = pool_get(&V_pf_rule_pl, PR_NOWAIT); +#else + newrule = pool_get(&pf_rule_pl, PR_WAITOK|PR_LIMITFAIL); +#endif if (newrule == NULL) { error = ENOMEM; break; @@ -1767,18 +2004,26 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #endif TAILQ_INIT(&newrule->rpool.list); /* initialize refcounting */ - newrule->states = 0; + newrule->states_cur = 0; newrule->entries.tqe_prev = NULL; #ifndef INET if (newrule->af == AF_INET) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, newrule); +#else pool_put(&pf_rule_pl, newrule); +#endif error = EAFNOSUPPORT; break; } #endif /* INET */ #ifndef INET6 if (newrule->af == AF_INET6) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, newrule); +#else pool_put(&pf_rule_pl, newrule); +#endif error = EAFNOSUPPORT; break; } @@ -1786,7 +2031,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (newrule->ifname[0]) { newrule->kif = pfi_kif_get(newrule->ifname); if (newrule->kif == NULL) { +#ifdef __FreeBSD__ + pool_put(&V_pf_rule_pl, newrule); +#else pool_put(&pf_rule_pl, newrule); +#endif error = EINVAL; break; } @@ -1826,34 +2075,32 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; if (newrule->rt && !newrule->direction) error = EINVAL; -#ifdef __FreeBSD__ #if NPFLOG > 0 if (!newrule->log) newrule->logif = 0; if (newrule->logif >= PFLOGIFS_MAX) error = EINVAL; #endif -#endif if (pf_rtlabel_add(&newrule->src.addr) || pf_rtlabel_add(&newrule->dst.addr)) error = EBUSY; - if (pfi_dynaddr_setup(&newrule->src.addr, newrule->af)) - error = EINVAL; - if (pfi_dynaddr_setup(&newrule->dst.addr, newrule->af)) + if (pf_addr_setup(ruleset, &newrule->src.addr, newrule->af)) error = EINVAL; - if (pf_tbladdr_setup(ruleset, &newrule->src.addr)) - error = EINVAL; - if (pf_tbladdr_setup(ruleset, &newrule->dst.addr)) + if (pf_addr_setup(ruleset, &newrule->dst.addr, newrule->af)) error = EINVAL; if (pf_anchor_setup(newrule, ruleset, pcr->anchor_call)) error = EINVAL; +#ifdef __FreeBSD__ + TAILQ_FOREACH(pa, &V_pf_pabuf, entries) +#else TAILQ_FOREACH(pa, &pf_pabuf, entries) +#endif if (pf_tbladdr_setup(ruleset, &pa->addr)) error = EINVAL; if (newrule->overload_tblname[0]) { if ((newrule->overload_tbl = pfr_attach_table( - ruleset, newrule->overload_tblname)) == + ruleset, newrule->overload_tblname, 0)) == NULL) error = EINVAL; else @@ -1861,7 +2108,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) PFR_TFLAG_ACTIVE; } +#ifdef __FreeBSD__ + pf_mv_pool(&V_pf_pabuf, &newrule->rpool.list); +#else pf_mv_pool(&pf_pabuf, &newrule->rpool.list); +#endif if (((((newrule->action == PF_NAT) || (newrule->action == PF_RDR) || (newrule->action == PF_BINAT) || @@ -1876,12 +2127,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } #ifdef __FreeBSD__ - if (!debug_pfugidhack && (newrule->uid.op || + if (!V_debug_pfugidhack && (newrule->uid.op || newrule->gid.op || newrule->log & PF_LOG_SOCKET_LOOKUP)) { DPFPRINTF(PF_DEBUG_MISC, ("pf: debug.pfugidhack enabled\n")); - debug_pfugidhack = 1; + V_debug_pfugidhack = 1; } #endif @@ -1890,7 +2141,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) newrule->packets[0] = newrule->packets[1] = 0; newrule->bytes[0] = newrule->bytes[1] = 0; } +#ifdef __FreeBSD__ + pf_empty_pool(&V_pf_pabuf); +#else pf_empty_pool(&pf_pabuf); +#endif if (pcr->action == PF_CHANGE_ADD_HEAD) oldrule = TAILQ_FIRST( @@ -1943,166 +2198,164 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRSTATES: { - struct pf_state *state, *nexts; + struct pf_state *s, *nexts; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; - int killed = 0; + u_int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); +#ifdef __FreeBSD__ + for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; s = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); +#else + for (s = RB_MIN(pf_state_tree_id, &tree_id); s; s = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); +#endif if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name)) { -#if NPFSYNC + s->kif->pfik_name)) { +#if NPFSYNC > 0 /* don't send out individual delete messages */ - state->sync_flags = PFSTATE_NOSYNC; + SET(s->state_flags, PFSTATE_NOSYNC); #endif - pf_unlink_state(state); + pf_unlink_state(s); killed++; } } - psk->psk_af = killed; -#if NPFSYNC + psk->psk_killed = killed; +#if NPFSYNC > 0 +#ifdef __FreeBSD__ + if (pfsync_clear_states_ptr != NULL) + pfsync_clear_states_ptr(V_pf_status.hostid, psk->psk_ifname); +#else pfsync_clear_states(pf_status.hostid, psk->psk_ifname); #endif +#endif break; } case DIOCKILLSTATES: { - struct pf_state *state, *nexts; - struct pf_state_host *src, *dst; + struct pf_state *s, *nexts; + struct pf_state_key *sk; + struct pf_addr *srcaddr, *dstaddr; + u_int16_t srcport, dstport; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; - int killed = 0; + u_int killed = 0; + + if (psk->psk_pfcmp.id) { + if (psk->psk_pfcmp.creatorid == 0) +#ifdef __FreeBSD__ + psk->psk_pfcmp.creatorid = V_pf_status.hostid; +#else + psk->psk_pfcmp.creatorid = pf_status.hostid; +#endif + if ((s = pf_find_state_byid(&psk->psk_pfcmp))) { + pf_unlink_state(s); + psk->psk_killed = 1; + } + break; + } - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); +#ifdef __FreeBSD__ + for (s = RB_MIN(pf_state_tree_id, &V_tree_id); s; + s = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &V_tree_id, s); +#else + for (s = RB_MIN(pf_state_tree_id, &tree_id); s; + s = nexts) { + nexts = RB_NEXT(pf_state_tree_id, &tree_id, s); +#endif + sk = s->key[PF_SK_WIRE]; - if (state->direction == PF_OUT) { - src = &state->lan; - dst = &state->ext; + if (s->direction == PF_OUT) { + srcaddr = &sk->addr[1]; + dstaddr = &sk->addr[0]; + srcport = sk->port[0]; + dstport = sk->port[0]; } else { - src = &state->ext; - dst = &state->lan; + srcaddr = &sk->addr[0]; + dstaddr = &sk->addr[1]; + srcport = sk->port[0]; + dstport = sk->port[0]; } - if ((!psk->psk_af || state->af == psk->psk_af) + if ((!psk->psk_af || sk->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == - state->proto) && + sk->proto) && PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr, &psk->psk_src.addr.v.a.mask, - &src->addr, state->af) && + srcaddr, sk->af) && PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr, &psk->psk_dst.addr.v.a.mask, - &dst->addr, state->af) && + dstaddr, sk->af) && (psk->psk_src.port_op == 0 || pf_match_port(psk->psk_src.port_op, psk->psk_src.port[0], psk->psk_src.port[1], - src->port)) && + srcport)) && (psk->psk_dst.port_op == 0 || pf_match_port(psk->psk_dst.port_op, psk->psk_dst.port[0], psk->psk_dst.port[1], - dst->port)) && + dstport)) && + (!psk->psk_label[0] || (s->rule.ptr->label[0] && + !strcmp(psk->psk_label, s->rule.ptr->label))) && (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name))) { -#if NPFSYNC > 0 - /* send immediate delete of state */ - pfsync_delete_state(state); - state->sync_flags |= PFSTATE_NOSYNC; -#endif - pf_unlink_state(state); + s->kif->pfik_name))) { + pf_unlink_state(s); killed++; } } - psk->psk_af = killed; + psk->psk_killed = killed; break; } case DIOCADDSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; - struct pfi_kif *kif; + struct pfsync_state *sp = &ps->state; - if (ps->state.timeout >= PFTM_MAX && - ps->state.timeout != PFTM_UNTIL_PACKET) { + if (sp->timeout >= PFTM_MAX && + sp->timeout != PFTM_UNTIL_PACKET) { error = EINVAL; break; } - state = pool_get(&pf_state_pl, PR_NOWAIT); - if (state == NULL) { - error = ENOMEM; - break; - } - kif = pfi_kif_get(ps->state.u.ifname); - if (kif == NULL) { - pool_put(&pf_state_pl, state); - error = ENOENT; - break; - } - bcopy(&ps->state, state, sizeof(struct pf_state)); - bzero(&state->u, sizeof(state->u)); - state->rule.ptr = &pf_default_rule; - state->nat_rule.ptr = NULL; - state->anchor.ptr = NULL; - state->rt_kif = NULL; - state->creation = time_second; - state->pfsync_time = 0; - state->packets[0] = state->packets[1] = 0; - state->bytes[0] = state->bytes[1] = 0; - - if (pf_insert_state(kif, state)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - pool_put(&pf_state_pl, state); - error = ENOMEM; - } +#ifdef __FreeBSD__ + if (pfsync_state_import_ptr != NULL) + error = pfsync_state_import_ptr(sp, PFSYNC_SI_IOCTL); +#else + error = pfsync_state_import(sp, PFSYNC_SI_IOCTL); +#endif break; } case DIOCGETSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; - u_int32_t nr; - int secs; + struct pf_state *s; + struct pf_state_cmp id_key; - nr = 0; - RB_FOREACH(state, pf_state_tree_id, &tree_id) { - if (nr >= ps->nr) - break; - nr++; - } - if (state == NULL) { - error = EBUSY; + bcopy(ps->state.id, &id_key.id, sizeof(id_key.id)); + id_key.creatorid = ps->state.creatorid; + + s = pf_find_state_byid(&id_key); + if (s == NULL) { + error = ENOENT; break; } - secs = time_second; - bcopy(state, &ps->state, sizeof(ps->state)); - strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name, - sizeof(ps->state.u.ifname)); - ps->state.rule.nr = state->rule.ptr->nr; - ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? - -1 : state->nat_rule.ptr->nr; - ps->state.anchor.nr = (state->anchor.ptr == NULL) ? - -1 : state->anchor.ptr->nr; - ps->state.creation = secs - ps->state.creation; - ps->state.expire = pf_state_expires(state); - if (ps->state.expire > secs) - ps->state.expire -= secs; - else - ps->state.expire = 0; + + pfsync_state_export(&ps->state, s); break; } case DIOCGETSTATES: { struct pfioc_states *ps = (struct pfioc_states *)addr; struct pf_state *state; - struct pf_state *p, *pstore; + struct pfsync_state *p, *pstore; u_int32_t nr = 0; - int space = ps->ps_len; - if (space == 0) { + if (ps->ps_len == 0) { +#ifdef __FreeBSD__ + nr = V_pf_status.states; +#else nr = pf_status.states; - ps->ps_len = sizeof(struct pf_state) * nr; +#endif + ps->ps_len = sizeof(struct pfsync_state) * nr; break; } @@ -2116,29 +2369,16 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) p = ps->ps_states; +#ifdef __FreeBSD__ + state = TAILQ_FIRST(&V_state_list); +#else state = TAILQ_FIRST(&state_list); +#endif while (state) { if (state->timeout != PFTM_UNLINKED) { - int secs = time_second; - if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; - - bcopy(state, pstore, sizeof(*pstore)); - strlcpy(pstore->u.ifname, - state->u.s.kif->pfik_name, - sizeof(pstore->u.ifname)); - pstore->rule.nr = state->rule.ptr->nr; - pstore->nat_rule.nr = (state->nat_rule.ptr == - NULL) ? -1 : state->nat_rule.ptr->nr; - pstore->anchor.nr = (state->anchor.ptr == - NULL) ? -1 : state->anchor.ptr->nr; - pstore->creation = secs - pstore->creation; - pstore->expire = pf_state_expires(state); - if (pstore->expire > secs) - pstore->expire -= secs; - else - pstore->expire = 0; + pfsync_state_export(pstore, state); #ifdef __FreeBSD__ PF_COPYOUT(pstore, p, sizeof(*p), error); #else @@ -2151,10 +2391,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) p++; nr++; } - state = TAILQ_NEXT(state, u.s.entry_list); + state = TAILQ_NEXT(state, entry_list); } - ps->ps_len = sizeof(struct pf_state) * nr; + ps->ps_len = sizeof(struct pfsync_state) * nr; free(pstore, M_TEMP); break; @@ -2162,8 +2402,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATUS: { struct pf_status *s = (struct pf_status *)addr; +#ifdef __FreeBSD__ + bcopy(&V_pf_status, s, sizeof(struct pf_status)); +#else bcopy(&pf_status, s, sizeof(struct pf_status)); - pfi_fill_oldstatus(s); +#endif + pfi_update_status(s->ifname, s); break; } @@ -2171,35 +2415,51 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_if *pi = (struct pfioc_if *)addr; if (pi->ifname[0] == 0) { +#ifdef __FreeBSD__ + bzero(V_pf_status.ifname, IFNAMSIZ); +#else bzero(pf_status.ifname, IFNAMSIZ); +#endif break; } - if (ifunit(pi->ifname) == NULL) { - error = EINVAL; - break; - } +#ifdef __FreeBSD__ + strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); +#else strlcpy(pf_status.ifname, pi->ifname, IFNAMSIZ); +#endif break; } case DIOCCLRSTATUS: { +#ifdef __FreeBSD__ + bzero(V_pf_status.counters, sizeof(V_pf_status.counters)); + bzero(V_pf_status.fcounters, sizeof(V_pf_status.fcounters)); + bzero(V_pf_status.scounters, sizeof(V_pf_status.scounters)); + V_pf_status.since = time_second; + if (*V_pf_status.ifname) + pfi_update_status(V_pf_status.ifname, NULL); +#else bzero(pf_status.counters, sizeof(pf_status.counters)); bzero(pf_status.fcounters, sizeof(pf_status.fcounters)); bzero(pf_status.scounters, sizeof(pf_status.scounters)); pf_status.since = time_second; if (*pf_status.ifname) - pfi_clr_istats(pf_status.ifname); + pfi_update_status(pf_status.ifname, NULL); +#endif break; } case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; + struct pf_state_key *sk; struct pf_state *state; - struct pf_state_cmp key; + struct pf_state_key_cmp key; int m = 0, direction = pnl->direction; + int sidx, didx; - key.af = pnl->af; - key.proto = pnl->proto; + /* NATLOOK src and dst are reversed, so reverse sidx/didx */ + sidx = (direction == PF_IN) ? 1 : 0; + didx = (direction == PF_IN) ? 0 : 1; if (!pnl->proto || PF_AZERO(&pnl->saddr, pnl->af) || @@ -2209,43 +2469,23 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) (!pnl->dport || !pnl->sport))) error = EINVAL; else { - /* - * userland gives us source and dest of connection, - * reverse the lookup so we ask for what happens with - * the return traffic, enabling us to find it in the - * state tree. - */ - if (direction == PF_IN) { - PF_ACPY(&key.ext.addr, &pnl->daddr, pnl->af); - key.ext.port = pnl->dport; - PF_ACPY(&key.gwy.addr, &pnl->saddr, pnl->af); - key.gwy.port = pnl->sport; - state = pf_find_state_all(&key, PF_EXT_GWY, &m); - } else { - PF_ACPY(&key.lan.addr, &pnl->daddr, pnl->af); - key.lan.port = pnl->dport; - PF_ACPY(&key.ext.addr, &pnl->saddr, pnl->af); - key.ext.port = pnl->sport; - state = pf_find_state_all(&key, PF_LAN_EXT, &m); - } + key.af = pnl->af; + key.proto = pnl->proto; + PF_ACPY(&key.addr[sidx], &pnl->saddr, pnl->af); + key.port[sidx] = pnl->sport; + PF_ACPY(&key.addr[didx], &pnl->daddr, pnl->af); + key.port[didx] = pnl->dport; + + state = pf_find_state_all(&key, direction, &m); + if (m > 1) error = E2BIG; /* more than one state */ else if (state != NULL) { - if (direction == PF_IN) { - PF_ACPY(&pnl->rsaddr, &state->lan.addr, - state->af); - pnl->rsport = state->lan.port; - PF_ACPY(&pnl->rdaddr, &pnl->daddr, - pnl->af); - pnl->rdport = pnl->dport; - } else { - PF_ACPY(&pnl->rdaddr, &state->gwy.addr, - state->af); - pnl->rdport = state->gwy.port; - PF_ACPY(&pnl->rsaddr, &pnl->saddr, - pnl->af); - pnl->rsport = pnl->sport; - } + sk = state->key[sidx]; + PF_ACPY(&pnl->rsaddr, &sk->addr[sidx], sk->af); + pnl->rsport = sk->port[sidx]; + PF_ACPY(&pnl->rdaddr, &sk->addr[didx], sk->af); + pnl->rdport = sk->port[didx]; } else error = ENOENT; } @@ -2261,10 +2501,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } +#ifdef __FreeBSD__ + old = V_pf_default_rule.timeout[pt->timeout]; +#else old = pf_default_rule.timeout[pt->timeout]; +#endif if (pt->timeout == PFTM_INTERVAL && pt->seconds == 0) pt->seconds = 1; +#ifdef __FreeBSD__ + V_pf_default_rule.timeout[pt->timeout] = pt->seconds; +#else pf_default_rule.timeout[pt->timeout] = pt->seconds; +#endif if (pt->timeout == PFTM_INTERVAL && pt->seconds < old) wakeup(pf_purge_thread); pt->seconds = old; @@ -2278,7 +2526,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } +#ifdef __FreeBSD__ + pt->seconds = V_pf_default_rule.timeout[pt->timeout]; +#else pt->seconds = pf_default_rule.timeout[pt->timeout]; +#endif break; } @@ -2289,7 +2541,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } +#ifdef __FreeBSD__ + pl->limit = V_pf_pool_limits[pl->index].limit; +#else pl->limit = pf_pool_limits[pl->index].limit; +#endif break; } @@ -2298,29 +2554,40 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) int old_limit; if (pl->index < 0 || pl->index >= PF_LIMIT_MAX || +#ifdef __FreeBSD__ + V_pf_pool_limits[pl->index].pp == NULL) { +#else pf_pool_limits[pl->index].pp == NULL) { +#endif error = EINVAL; goto fail; } #ifdef __FreeBSD__ - uma_zone_set_max(pf_pool_limits[pl->index].pp, pl->limit); + uma_zone_set_max(V_pf_pool_limits[pl->index].pp, pl->limit); + old_limit = V_pf_pool_limits[pl->index].limit; + V_pf_pool_limits[pl->index].limit = pl->limit; + pl->limit = old_limit; #else if (pool_sethardlimit(pf_pool_limits[pl->index].pp, pl->limit, NULL, 0) != 0) { error = EBUSY; goto fail; } -#endif old_limit = pf_pool_limits[pl->index].limit; pf_pool_limits[pl->index].limit = pl->limit; pl->limit = old_limit; +#endif break; } case DIOCSETDEBUG: { u_int32_t *level = (u_int32_t *)addr; +#ifdef __FreeBSD__ + V_pf_status.debug = *level; +#else pf_status.debug = *level; +#endif break; } @@ -2363,11 +2630,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_altq *altq; /* enable all altq interfaces on active list */ - TAILQ_FOREACH(altq, pf_altqs_active, entries) { #ifdef __FreeBSD__ + TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { if (altq->qname[0] == 0 && (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { #else + TAILQ_FOREACH(altq, pf_altqs_active, entries) { if (altq->qname[0] == 0) { #endif error = pf_enable_altq(altq); @@ -2376,7 +2644,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } if (error == 0) +#ifdef __FreeBSD__ + V_pf_altq_running = 1; +#else pf_altq_running = 1; +#endif DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n")); break; } @@ -2385,11 +2657,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_altq *altq; /* disable all altq interfaces on active list */ - TAILQ_FOREACH(altq, pf_altqs_active, entries) { #ifdef __FreeBSD__ + TAILQ_FOREACH(altq, V_pf_altqs_active, entries) { if (altq->qname[0] == 0 && (altq->local_flags & PFALTQ_FLAG_IF_REMOVED) == 0) { #else + TAILQ_FOREACH(altq, pf_altqs_active, entries) { if (altq->qname[0] == 0) { #endif error = pf_disable_altq(altq); @@ -2398,7 +2671,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } } if (error == 0) +#ifdef __FreeBSD__ + V_pf_altq_running = 0; +#else pf_altq_running = 0; +#endif DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n")); break; } @@ -2407,11 +2684,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pfioc_altq *pa = (struct pfioc_altq *)addr; struct pf_altq *altq, *a; +#ifdef __FreeBSD__ + if (pa->ticket != V_ticket_altqs_inactive) { +#else if (pa->ticket != ticket_altqs_inactive) { +#endif error = EBUSY; break; } - altq = pool_get(&pf_altq_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + altq = pool_get(&V_pf_altq_pl, PR_NOWAIT); +#else + altq = pool_get(&pf_altq_pl, PR_WAITOK|PR_LIMITFAIL); +#endif if (altq == NULL) { error = ENOMEM; break; @@ -2428,11 +2713,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (altq->qname[0] != 0) { if ((altq->qid = pf_qname2qid(altq->qname)) == 0) { error = EBUSY; +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, altq); +#else pool_put(&pf_altq_pl, altq); +#endif break; } altq->altq_disc = NULL; +#ifdef __FreeBSD__ + TAILQ_FOREACH(a, V_pf_altqs_inactive, entries) { +#else TAILQ_FOREACH(a, pf_altqs_inactive, entries) { +#endif if (strncmp(a->ifname, altq->ifname, IFNAMSIZ) == 0 && a->qname[0] == 0) { altq->altq_disc = a->altq_disc; @@ -2448,18 +2741,26 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) altq->local_flags |= PFALTQ_FLAG_IF_REMOVED; } else { PF_UNLOCK(); -#endif +#endif error = altq_add(altq); #ifdef __FreeBSD__ PF_LOCK(); } #endif if (error) { +#ifdef __FreeBSD__ + pool_put(&V_pf_altq_pl, altq); +#else pool_put(&pf_altq_pl, altq); +#endif break; } +#ifdef __FreeBSD__ + TAILQ_INSERT_TAIL(V_pf_altqs_inactive, altq, entries); +#else TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries); +#endif bcopy(altq, &pa->altq, sizeof(struct pf_altq)); break; } @@ -2469,9 +2770,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_altq *altq; pa->nr = 0; +#ifdef __FreeBSD__ + TAILQ_FOREACH(altq, V_pf_altqs_active, entries) + pa->nr++; + pa->ticket = V_ticket_altqs_active; +#else TAILQ_FOREACH(altq, pf_altqs_active, entries) pa->nr++; pa->ticket = ticket_altqs_active; +#endif break; } @@ -2480,12 +2787,20 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_altq *altq; u_int32_t nr; +#ifdef __FreeBSD__ + if (pa->ticket != V_ticket_altqs_active) { +#else if (pa->ticket != ticket_altqs_active) { +#endif error = EBUSY; break; } nr = 0; +#ifdef __FreeBSD__ + altq = TAILQ_FIRST(V_pf_altqs_active); +#else altq = TAILQ_FIRST(pf_altqs_active); +#endif while ((altq != NULL) && (nr < pa->nr)) { altq = TAILQ_NEXT(altq, entries); nr++; @@ -2509,13 +2824,21 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) u_int32_t nr; int nbytes; +#ifdef __FreeBSD__ + if (pq->ticket != V_ticket_altqs_active) { +#else if (pq->ticket != ticket_altqs_active) { +#endif error = EBUSY; break; } nbytes = pq->nbytes; nr = 0; +#ifdef __FreeBSD__ + altq = TAILQ_FIRST(V_pf_altqs_active); +#else altq = TAILQ_FIRST(pf_altqs_active); +#endif while ((altq != NULL) && (nr < pq->nr)) { altq = TAILQ_NEXT(altq, entries); nr++; @@ -2524,6 +2847,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EBUSY; break; } + #ifdef __FreeBSD__ if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) { error = ENXIO; @@ -2546,15 +2870,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCBEGINADDRS: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; +#ifdef __FreeBSD__ + pf_empty_pool(&V_pf_pabuf); + pp->ticket = ++V_ticket_pabuf; +#else pf_empty_pool(&pf_pabuf); pp->ticket = ++ticket_pabuf; +#endif break; } case DIOCADDADDR: { struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr; +#ifdef __FreeBSD__ + if (pp->ticket != V_ticket_pabuf) { +#else if (pp->ticket != ticket_pabuf) { +#endif error = EBUSY; break; } @@ -2576,7 +2909,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; break; } - pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + pa = pool_get(&V_pf_pooladdr_pl, PR_NOWAIT); +#else + pa = pool_get(&pf_pooladdr_pl, PR_WAITOK|PR_LIMITFAIL); +#endif if (pa == NULL) { error = ENOMEM; break; @@ -2585,7 +2922,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pa->ifname[0]) { pa->kif = pfi_kif_get(pa->ifname); if (pa->kif == NULL) { +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, pa); +#else pool_put(&pf_pooladdr_pl, pa); +#endif error = EINVAL; break; } @@ -2594,11 +2935,19 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pfi_dynaddr_setup(&pa->addr, pp->af)) { pfi_dynaddr_remove(&pa->addr); pfi_kif_unref(pa->kif, PFI_KIF_REF_RULE); +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, pa); +#else pool_put(&pf_pooladdr_pl, pa); +#endif error = EINVAL; break; } +#ifdef __FreeBSD__ + TAILQ_INSERT_TAIL(&V_pf_pabuf, pa, entries); +#else TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries); +#endif break; } @@ -2637,9 +2986,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr)); - pfi_dynaddr_copyout(&pp->addr.addr); - pf_tbladdr_copyout(&pp->addr.addr); - pf_rtlabel_copyout(&pp->addr.addr); + pf_addr_copyout(&pp->addr.addr); break; } @@ -2672,7 +3019,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; } if (pca->action != PF_CHANGE_REMOVE) { - newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + newpa = pool_get(&V_pf_pooladdr_pl, + PR_NOWAIT); +#else + newpa = pool_get(&pf_pooladdr_pl, + PR_WAITOK|PR_LIMITFAIL); +#endif if (newpa == NULL) { error = ENOMEM; break; @@ -2680,14 +3033,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) bcopy(&pca->addr, newpa, sizeof(struct pf_pooladdr)); #ifndef INET if (pca->af == AF_INET) { +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, newpa); +#else pool_put(&pf_pooladdr_pl, newpa); +#endif error = EAFNOSUPPORT; break; } #endif /* INET */ #ifndef INET6 if (pca->af == AF_INET6) { +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, newpa); +#else pool_put(&pf_pooladdr_pl, newpa); +#endif error = EAFNOSUPPORT; break; } @@ -2695,7 +3056,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (newpa->ifname[0]) { newpa->kif = pfi_kif_get(newpa->ifname); if (newpa->kif == NULL) { +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, newpa); +#else pool_put(&pf_pooladdr_pl, newpa); +#endif error = EINVAL; break; } @@ -2706,7 +3071,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pf_tbladdr_setup(ruleset, &newpa->addr)) { pfi_dynaddr_remove(&newpa->addr); pfi_kif_unref(newpa->kif, PFI_KIF_REF_RULE); +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, newpa); +#else pool_put(&pf_pooladdr_pl, newpa); +#endif error = EINVAL; break; } @@ -2735,7 +3104,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pfi_dynaddr_remove(&oldpa->addr); pf_tbladdr_remove(&oldpa->addr); pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); +#ifdef __FreeBSD__ + pool_put(&V_pf_pooladdr_pl, oldpa); +#else pool_put(&pf_pooladdr_pl, oldpa); +#endif } else { if (oldpa == NULL) TAILQ_INSERT_TAIL(&pool->list, newpa, entries); @@ -2766,7 +3139,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pr->nr = 0; if (ruleset->anchor == NULL) { /* XXX kludge for pf_main_ruleset */ +#ifdef __FreeBSD__ + RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) +#else RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) +#endif if (anchor->parent == NULL) pr->nr++; } else { @@ -2791,7 +3168,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pr->name[0] = 0; if (ruleset->anchor == NULL) { /* XXX kludge for pf_main_ruleset */ +#ifdef __FreeBSD__ + RB_FOREACH(anchor, pf_anchor_global, &V_pf_anchors) +#else RB_FOREACH(anchor, pf_anchor_global, &pf_anchors) +#endif if (anchor->parent == NULL && nr++ == pr->nr) { strlcpy(pr->name, anchor->name, sizeof(pr->name)); @@ -3036,17 +3417,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #ifdef __FreeBSD__ PF_UNLOCK(); #endif - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); + ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); + table = malloc(sizeof(*table), M_TEMP, M_WAITOK); #ifdef __FreeBSD__ PF_LOCK(); #endif for (i = 0; i < io->size; i++) { #ifdef __FreeBSD__ - PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); - if (error) { + PF_COPYIN(io->array+i, ioe, sizeof(*ioe), error); + if (error) { #else if (copyin(io->array+i, ioe, sizeof(*ioe))) { #endif @@ -3122,10 +3501,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #ifdef __FreeBSD__ PF_UNLOCK(); #endif - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); + ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); + table = malloc(sizeof(*table), M_TEMP, M_WAITOK); #ifdef __FreeBSD__ PF_LOCK(); #endif @@ -3197,10 +3574,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #ifdef __FreeBSD__ PF_UNLOCK(); #endif - ioe = (struct pfioc_trans_e *)malloc(sizeof(*ioe), - M_TEMP, M_WAITOK); - table = (struct pfr_table *)malloc(sizeof(*table), - M_TEMP, M_WAITOK); + ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); + table = malloc(sizeof(*table), M_TEMP, M_WAITOK); #ifdef __FreeBSD__ PF_LOCK(); #endif @@ -3226,8 +3601,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = EINVAL; goto fail; } +#ifdef __FreeBSD__ + if (!V_altqs_inactive_open || ioe->ticket != + V_ticket_altqs_inactive) { +#else if (!altqs_inactive_open || ioe->ticket != ticket_altqs_inactive) { +#endif free(table, M_TEMP); free(ioe, M_TEMP); error = EBUSY; @@ -3238,7 +3618,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case PF_RULESET_TABLE: rs = pf_find_ruleset(ioe->anchor); if (rs == NULL || !rs->topen || ioe->ticket != - rs->tticket) { + rs->tticket) { free(table, M_TEMP); free(ioe, M_TEMP); error = EBUSY; @@ -3322,7 +3702,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) int space = psn->psn_len; if (space == 0) { +#ifdef __FreeBSD__ + RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) +#else RB_FOREACH(n, pf_src_tree, &tree_src_tracking) +#endif nr++; psn->psn_len = sizeof(struct pf_src_node) * nr; break; @@ -3335,9 +3719,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) #ifdef __FreeBSD__ PF_LOCK(); #endif - p = psn->psn_src_nodes; +#ifdef __FreeBSD__ + RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { +#else RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { +#endif int secs = time_second, diff; if ((nr + 1) * sizeof(*p) > (unsigned)psn->psn_len) @@ -3383,39 +3770,59 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_src_node *n; struct pf_state *state; +#ifdef __FreeBSD__ + RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { +#else RB_FOREACH(state, pf_state_tree_id, &tree_id) { +#endif state->src_node = NULL; state->nat_src_node = NULL; } +#ifdef __FreeBSD__ + RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { +#else RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { +#endif n->expire = 1; n->states = 0; } pf_purge_expired_src_nodes(1); +#ifdef __FreeBSD__ + V_pf_status.src_nodes = 0; +#else pf_status.src_nodes = 0; +#endif break; } case DIOCKILLSRCNODES: { struct pf_src_node *sn; struct pf_state *s; - struct pfioc_src_node_kill *psnk = \ - (struct pfioc_src_node_kill *) addr; - int killed = 0; + struct pfioc_src_node_kill *psnk = + (struct pfioc_src_node_kill *)addr; + u_int killed = 0; +#ifdef __FreeBSD__ + RB_FOREACH(sn, pf_src_tree, &V_tree_src_tracking) { +#else RB_FOREACH(sn, pf_src_tree, &tree_src_tracking) { - if (PF_MATCHA(psnk->psnk_src.neg, \ - &psnk->psnk_src.addr.v.a.addr, \ - &psnk->psnk_src.addr.v.a.mask, \ - &sn->addr, sn->af) && - PF_MATCHA(psnk->psnk_dst.neg, \ - &psnk->psnk_dst.addr.v.a.addr, \ - &psnk->psnk_dst.addr.v.a.mask, \ - &sn->raddr, sn->af)) { +#endif + if (PF_MATCHA(psnk->psnk_src.neg, + &psnk->psnk_src.addr.v.a.addr, + &psnk->psnk_src.addr.v.a.mask, + &sn->addr, sn->af) && + PF_MATCHA(psnk->psnk_dst.neg, + &psnk->psnk_dst.addr.v.a.addr, + &psnk->psnk_dst.addr.v.a.mask, + &sn->raddr, sn->af)) { /* Handle state to src_node linkage */ if (sn->states != 0) { - RB_FOREACH(s, pf_state_tree_id, + RB_FOREACH(s, pf_state_tree_id, +#ifdef __FreeBSD__ + &V_tree_id) { +#else &tree_id) { +#endif if (s->src_node == sn) s->src_node = NULL; if (s->nat_src_node == sn) @@ -3431,17 +3838,24 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (killed > 0) pf_purge_expired_src_nodes(1); - psnk->psnk_af = killed; + psnk->psnk_killed = killed; break; } case DIOCSETHOSTID: { u_int32_t *hostid = (u_int32_t *)addr; +#ifdef __FreeBSD__ + if (*hostid == 0) + V_pf_status.hostid = arc4random(); + else + V_pf_status.hostid = *hostid; +#else if (*hostid == 0) pf_status.hostid = arc4random(); else pf_status.hostid = *hostid; +#endif break; } @@ -3484,43 +3898,110 @@ fail: PF_UNLOCK(); if (flags & FWRITE) - sx_xunlock(&pf_consistency_lock); + sx_xunlock(&V_pf_consistency_lock); else - sx_sunlock(&pf_consistency_lock); + sx_sunlock(&V_pf_consistency_lock); #else splx(s); - /* XXX: Lock order? */ if (flags & FWRITE) rw_exit_write(&pf_consistency_lock); else rw_exit_read(&pf_consistency_lock); #endif + + CURVNET_RESTORE(); + return (error); } #ifdef __FreeBSD__ +void +pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) +{ + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; + sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; + sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; + sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; + sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; + sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; + sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; + sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; + sp->proto = st->key[PF_SK_WIRE]->proto; + sp->af = st->key[PF_SK_WIRE]->af; + + /* copy from state */ + strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); + bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + sp->creation = htonl(time_second - st->creation); + sp->expire = pf_state_expires(st); + if (sp->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(sp->expire - time_second); + + sp->direction = st->direction; + sp->log = st->log; + sp->timeout = st->timeout; + sp->state_flags = st->state_flags; + if (st->src_node) + sp->sync_flags |= PFSYNC_FLAG_SRCNODE; + if (st->nat_src_node) + sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; + + bcopy(&st->id, &sp->id, sizeof(sp->id)); + sp->creatorid = st->creatorid; + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); + + if (st->rule.ptr == NULL) + sp->rule = htonl(-1); + else + sp->rule = htonl(st->rule.ptr->nr); + if (st->anchor.ptr == NULL) + sp->anchor = htonl(-1); + else + sp->anchor = htonl(st->anchor.ptr->nr); + if (st->nat_rule.ptr == NULL) + sp->nat_rule = htonl(-1); + else + sp->nat_rule = htonl(st->nat_rule.ptr->nr); + + pf_state_counter_hton(st->packets[0], sp->packets[0]); + pf_state_counter_hton(st->packets[1], sp->packets[1]); + pf_state_counter_hton(st->bytes[0], sp->bytes[0]); + pf_state_counter_hton(st->bytes[1], sp->bytes[1]); + +} + /* * XXX - Check for version missmatch!!! */ static void pf_clear_states(void) { - struct pf_state *state; - + struct pf_state *state; + +#ifdef __FreeBSD__ + RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { +#else RB_FOREACH(state, pf_state_tree_id, &tree_id) { +#endif state->timeout = PFTM_PURGE; #if NPFSYNC /* don't send out individual delete messages */ - state->sync_flags = PFSTATE_NOSYNC; + state->sync_state = PFSTATE_NOSYNC; #endif pf_unlink_state(state); } - + #if 0 /* NPFSYNC */ /* * XXX This is called on module unload, we do not want to sync that over? */ */ - pfsync_clear_states(pf_status.hostid, psk->psk_ifname); + pfsync_clear_states(V_pf_status.hostid, psk->psk_ifname); #endif } @@ -3544,11 +4025,19 @@ pf_clear_srcnodes(void) struct pf_src_node *n; struct pf_state *state; +#ifdef __FreeBSD__ + RB_FOREACH(state, pf_state_tree_id, &V_tree_id) { +#else RB_FOREACH(state, pf_state_tree_id, &tree_id) { +#endif state->src_node = NULL; state->nat_src_node = NULL; } +#ifdef __FreeBSD__ + RB_FOREACH(n, pf_src_tree, &V_tree_src_tracking) { +#else RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { +#endif n->expire = 1; n->states = 0; } @@ -3566,8 +4055,8 @@ shutdown_pf(void) int error = 0; u_int32_t t[5]; char nn = '\0'; - - pf_status.running = 0; + + V_pf_status.running = 0; do { if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn)) != 0) { @@ -3577,22 +4066,22 @@ shutdown_pf(void) if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn)) != 0) { DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: FILTER\n")); - break; /* XXX: rollback? */ + break; /* XXX: rollback? */ } if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn)) != 0) { DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: NAT\n")); - break; /* XXX: rollback? */ + break; /* XXX: rollback? */ } if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn)) != 0) { DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: BINAT\n")); - break; /* XXX: rollback? */ + break; /* XXX: rollback? */ } if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn)) != 0) { DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: RDR\n")); - break; /* XXX: rollback? */ + break; /* XXX: rollback? */ } /* XXX: these should always succeed here */ @@ -3605,13 +4094,13 @@ shutdown_pf(void) if ((error = pf_clear_tables()) != 0) break; -#ifdef ALTQ + #ifdef ALTQ if ((error = pf_begin_altq(&t[0])) != 0) { DPFPRINTF(PF_DEBUG_MISC, ("shutdown_pf: ALTQ\n")); break; } pf_commit_altq(t[0]); -#endif + #endif pf_clear_states(); @@ -3621,7 +4110,7 @@ shutdown_pf(void) /* fingerprints and interfaces have thier own cleanup code */ } while(0); - return (error); + return (error); } #ifdef INET @@ -3643,10 +4132,12 @@ pf_check_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, if ((*m)->m_pkthdr.len >= (int)sizeof(struct ip)) { /* if m_pkthdr.len is less than ip header, pf will handle. */ h = mtod(*m, struct ip *); - HTONS(h->ip_len); - HTONS(h->ip_off); + HTONS(h->ip_len); + HTONS(h->ip_off); } + CURVNET_SET(ifp->if_vnet); chk = pf_test(PF_IN, ifp, m, NULL, inp); + CURVNET_RESTORE(); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3683,10 +4174,12 @@ pf_check_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, if ((*m)->m_pkthdr.len >= (int)sizeof(*h)) { /* if m_pkthdr.len is less than ip header, pf will handle. */ h = mtod(*m, struct ip *); - HTONS(h->ip_len); - HTONS(h->ip_off); + HTONS(h->ip_len); + HTONS(h->ip_off); } + CURVNET_SET(ifp->if_vnet); chk = pf_test(PF_OUT, ifp, m, NULL, inp); + CURVNET_RESTORE(); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3717,8 +4210,10 @@ pf_check6_in(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, * order to support scoped addresses. In order to support stateful * filtering we have change this to lo0 as it is the case in IPv4. */ + CURVNET_SET(ifp->if_vnet); chk = pf_test6(PF_IN, (*m)->m_flags & M_LOOP ? V_loif : ifp, m, NULL, inp); + CURVNET_RESTORE(); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3743,7 +4238,9 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, #endif (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } + CURVNET_SET(ifp->if_vnet); chk = pf_test6(PF_OUT, ifp, m, NULL, inp); + CURVNET_RESTORE(); if (chk && *m) { m_freem(*m); *m = NULL; @@ -3755,20 +4252,22 @@ pf_check6_out(void *arg, struct mbuf **m, struct ifnet *ifp, int dir, static int hook_pf(void) { +#ifdef INET struct pfil_head *pfh_inet; +#endif #ifdef INET6 struct pfil_head *pfh_inet6; #endif - + PF_ASSERT(MA_NOTOWNED); - if (pf_pfil_hooked) + if (V_pf_pfil_hooked) return (0); - + +#ifdef INET pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (pfh_inet == NULL) return (ESRCH); /* XXX */ -#ifdef INET pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); #endif @@ -3787,27 +4286,29 @@ hook_pf(void) pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); #endif - pf_pfil_hooked = 1; + V_pf_pfil_hooked = 1; return (0); } static int dehook_pf(void) { +#ifdef INET struct pfil_head *pfh_inet; +#endif #ifdef INET6 struct pfil_head *pfh_inet6; #endif PF_ASSERT(MA_NOTOWNED); - if (pf_pfil_hooked == 0) + if (V_pf_pfil_hooked == 0) return (0); +#ifdef INET pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (pfh_inet == NULL) return (ESRCH); /* XXX */ -#ifdef INET pfil_remove_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); pfil_remove_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, @@ -3823,21 +4324,69 @@ dehook_pf(void) pfh_inet6); #endif - pf_pfil_hooked = 0; + V_pf_pfil_hooked = 0; return (0); } +/* Vnet accessors */ +static int +vnet_pf_init(const void *unused) +{ + + V_pf_pfil_hooked = 0; + V_pf_end_threads = 0; + + V_debug_pfugidhack = 0; + + TAILQ_INIT(&V_pf_tags); + TAILQ_INIT(&V_pf_qids); + + pf_load(); + + return (0); +} + +static int +vnet_pf_uninit(const void *unused) +{ + + pf_unload(); + + return (0); +} + +/* Define startup order. */ +#define PF_SYSINIT_ORDER SI_SUB_PROTO_BEGIN +#define PF_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ +#define PF_VNET_ORDER (PF_MODEVENT_ORDER + 2) /* Later still. */ + +/* + * Starting up. + * VNET_SYSINIT is called for each existing vnet and each new vnet. + */ +VNET_SYSINIT(vnet_pf_init, PF_SYSINIT_ORDER, PF_VNET_ORDER, + vnet_pf_init, NULL); + +/* + * Closing up shop. These are done in REVERSE ORDER, + * Not called on reboot. + * VNET_SYSUNINIT is called for each exiting vnet as it exits. + */ +VNET_SYSUNINIT(vnet_pf_uninit, PF_SYSINIT_ORDER, PF_VNET_ORDER, + vnet_pf_uninit, NULL); + static int pf_load(void) { + init_zone_var(); + sx_init(&V_pf_consistency_lock, "pf_statetbl_lock"); init_pf_mutex(); - pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); if (pfattach() < 0) { - destroy_dev(pf_dev); destroy_pf_mutex(); return (ENOMEM); } + return (0); } @@ -3847,7 +4396,7 @@ pf_unload(void) int error = 0; PF_LOCK(); - pf_status.running = 0; + V_pf_status.running = 0; PF_UNLOCK(); error = dehook_pf(); if (error) { @@ -3861,18 +4410,18 @@ pf_unload(void) } PF_LOCK(); shutdown_pf(); - pf_end_threads = 1; - while (pf_end_threads < 2) { + V_pf_end_threads = 1; + while (V_pf_end_threads < 2) { wakeup_one(pf_purge_thread); - msleep(pf_purge_thread, &pf_task_mtx, 0, "pftmo", hz); + msleep(pf_purge_thread, &V_pf_task_mtx, 0, "pftmo", hz); } pfi_cleanup(); pf_osfp_flush(); pf_osfp_cleanup(); cleanup_pf_zone(); PF_UNLOCK(); - destroy_dev(pf_dev); destroy_pf_mutex(); + sx_destroy(&V_pf_consistency_lock); return error; } @@ -3883,11 +4432,10 @@ pf_modevent(module_t mod, int type, void *data) switch(type) { case MOD_LOAD: - error = pf_load(); + pf_dev = make_dev(&pf_cdevsw, 0, 0, 0, 0600, PF_NAME); break; - case MOD_UNLOAD: - error = pf_unload(); + destroy_dev(pf_dev); break; default: error = EINVAL; @@ -3895,7 +4443,7 @@ pf_modevent(module_t mod, int type, void *data) } return error; } - + static moduledata_t pf_mod = { "pf", pf_modevent, @@ -3904,4 +4452,4 @@ static moduledata_t pf_mod = { DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST); MODULE_VERSION(pf, PF_MODVER); -#endif /* __FreeBSD__ */ +#endif /* __FreeBSD__ */ diff --git a/sys/contrib/pf/net/pf_lb.c b/sys/contrib/pf/net/pf_lb.c new file mode 100644 index 0000000..f4c9a00 --- /dev/null +++ b/sys/contrib/pf/net/pf_lb.c @@ -0,0 +1,792 @@ +/* $OpenBSD: pf_lb.c,v 1.2 2009/02/12 02:13:15 sthen Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002 - 2008 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. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + */ + +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#endif + +#ifdef __FreeBSD__ +#include "opt_bpf.h" +#include "opt_pf.h" + +#ifdef DEV_BPF +#define NBPFILTER DEV_BPF +#else +#define NBPFILTER 0 +#endif + +#ifdef DEV_PFLOG +#define NPFLOG DEV_PFLOG +#else +#define NPFLOG 0 +#endif + +#ifdef DEV_PFSYNC +#define NPFSYNC DEV_PFSYNC +#else +#define NPFSYNC 0 +#endif + +#ifdef DEV_PFLOW +#define NPFLOW DEV_PFLOW +#else +#define NPFLOW 0 +#endif + +#else +#include "bpfilter.h" +#include "pflog.h" +#include "pfsync.h" +#include "pflow.h" +#endif + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/filio.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/kernel.h> +#include <sys/time.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#endif +#ifndef __FreeBSD__ +#include <sys/pool.h> +#endif +#include <sys/proc.h> +#ifdef __FreeBSD__ +#include <sys/kthread.h> +#include <sys/lock.h> +#include <sys/sx.h> +#else +#include <sys/rwlock.h> +#endif + +#ifdef __FreeBSD__ +#include <sys/md5.h> +#else +#include <crypto/md5.h> +#endif + +#include <net/if.h> +#include <net/if_types.h> +#include <net/bpf.h> +#include <net/route.h> +#include <net/radix_mpath.h> + +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_seq.h> +#include <netinet/udp.h> +#include <netinet/ip_icmp.h> +#include <netinet/in_pcb.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/udp_var.h> +#include <netinet/icmp_var.h> +#include <netinet/if_ether.h> + +#ifndef __FreeBSD__ +#include <dev/rndvar.h> +#endif +#include <net/pfvar.h> +#include <net/if_pflog.h> +#include <net/if_pflow.h> + +#if NPFSYNC > 0 +#include <net/if_pfsync.h> +#endif /* NPFSYNC > 0 */ + +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet/in_pcb.h> +#include <netinet/icmp6.h> +#include <netinet6/nd6.h> +#endif /* INET6 */ + + +#ifdef __FreeBSD__ +#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x +#else +#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x +#endif + +/* + * Global variables + */ + +void pf_hash(struct pf_addr *, struct pf_addr *, + struct pf_poolhashkey *, sa_family_t); +struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *, + int, int, struct pfi_kif *, + struct pf_addr *, u_int16_t, struct pf_addr *, + u_int16_t, int); +int pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *, + struct pf_addr *, struct pf_addr *, u_int16_t, + struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t, + struct pf_src_node **); + +#define mix(a,b,c) \ + do { \ + a -= b; a -= c; a ^= (c >> 13); \ + b -= c; b -= a; b ^= (a << 8); \ + c -= a; c -= b; c ^= (b >> 13); \ + a -= b; a -= c; a ^= (c >> 12); \ + b -= c; b -= a; b ^= (a << 16); \ + c -= a; c -= b; c ^= (b >> 5); \ + a -= b; a -= c; a ^= (c >> 3); \ + b -= c; b -= a; b ^= (a << 10); \ + c -= a; c -= b; c ^= (b >> 15); \ + } while (0) + +/* + * hash function based on bridge_hash in if_bridge.c + */ +void +pf_hash(struct pf_addr *inaddr, struct pf_addr *hash, + struct pf_poolhashkey *key, sa_family_t af) +{ + u_int32_t a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0]; + + switch (af) { +#ifdef INET + case AF_INET: + a += inaddr->addr32[0]; + b += key->key32[1]; + mix(a, b, c); + hash->addr32[0] = c + key->key32[2]; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + a += inaddr->addr32[0]; + b += inaddr->addr32[2]; + mix(a, b, c); + hash->addr32[0] = c; + a += inaddr->addr32[1]; + b += inaddr->addr32[3]; + c += key->key32[1]; + mix(a, b, c); + hash->addr32[1] = c; + a += inaddr->addr32[2]; + b += inaddr->addr32[1]; + c += key->key32[2]; + mix(a, b, c); + hash->addr32[2] = c; + a += inaddr->addr32[3]; + b += inaddr->addr32[0]; + c += key->key32[3]; + mix(a, b, c); + hash->addr32[3] = c; + break; +#endif /* INET6 */ + } +} + +struct pf_rule * +pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off, + int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport, + struct pf_addr *daddr, u_int16_t dport, int rs_num) +{ + struct pf_rule *r, *rm = NULL; + struct pf_ruleset *ruleset = NULL; + int tag = -1; + int rtableid = -1; + int asd = 0; + + r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr); + while (r && rm == NULL) { + struct pf_rule_addr *src = NULL, *dst = NULL; + struct pf_addr_wrap *xdst = NULL; + + if (r->action == PF_BINAT && direction == PF_IN) { + src = &r->dst; + if (r->rpool.cur != NULL) + xdst = &r->rpool.cur->addr; + } else { + src = &r->src; + dst = &r->dst; + } + + r->evaluations++; + if (pfi_kif_match(r->kif, kif) == r->ifnot) + r = r->skip[PF_SKIP_IFP].ptr; + else if (r->direction && r->direction != direction) + r = r->skip[PF_SKIP_DIR].ptr; + else if (r->af && r->af != pd->af) + r = r->skip[PF_SKIP_AF].ptr; + else if (r->proto && r->proto != pd->proto) + r = r->skip[PF_SKIP_PROTO].ptr; + else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, + src->neg, kif)) + r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR : + PF_SKIP_DST_ADDR].ptr; + else if (src->port_op && !pf_match_port(src->port_op, + src->port[0], src->port[1], sport)) + r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT : + PF_SKIP_DST_PORT].ptr; + else if (dst != NULL && + PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL)) + r = r->skip[PF_SKIP_DST_ADDR].ptr; + else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, + 0, NULL)) + r = TAILQ_NEXT(r, entries); + else if (dst != NULL && dst->port_op && + !pf_match_port(dst->port_op, dst->port[0], + dst->port[1], dport)) + r = r->skip[PF_SKIP_DST_PORT].ptr; +#ifdef __FreeBSD__ + else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) +#else + else if (r->match_tag && !pf_match_tag(m, r, &tag)) +#endif + r = TAILQ_NEXT(r, entries); + else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto != + IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m, + off, pd->hdr.tcp), r->os_fingerprint))) + r = TAILQ_NEXT(r, entries); + else { + if (r->tag) + tag = r->tag; + if (r->rtableid >= 0) + rtableid = r->rtableid; + if (r->anchor == NULL) { + rm = r; + } else + pf_step_into_anchor(&asd, &ruleset, rs_num, + &r, NULL, NULL); + } + if (r == NULL) + pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, + NULL, NULL); + } +#ifdef __FreeBSD__ + if (pf_tag_packet(m, tag, rtableid, pd->pf_mtag)) +#else + if (pf_tag_packet(m, tag, rtableid)) +#endif + return (NULL); + if (rm != NULL && (rm->action == PF_NONAT || + rm->action == PF_NORDR || rm->action == PF_NOBINAT)) + return (NULL); + return (rm); +} + +int +pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r, + struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport, + struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high, + struct pf_src_node **sn) +{ + struct pf_state_key_cmp key; + struct pf_addr init_addr; + u_int16_t cut; + + bzero(&init_addr, sizeof(init_addr)); + if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + return (1); + + if (proto == IPPROTO_ICMP) { + low = 1; + high = 65535; + } + + do { + key.af = af; + key.proto = proto; + PF_ACPY(&key.addr[1], daddr, key.af); + PF_ACPY(&key.addr[0], naddr, key.af); + key.port[1] = dport; + + /* + * port search; start random, step; + * similar 2 portloop in in_pcbbind + */ + if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP || + proto == IPPROTO_ICMP)) { + key.port[0] = dport; + if (pf_find_state_all(&key, PF_IN, NULL) == NULL) + return (0); + } else if (low == 0 && high == 0) { + key.port[0] = *nport; + if (pf_find_state_all(&key, PF_IN, NULL) == NULL) + return (0); + } else if (low == high) { + key.port[0] = htons(low); + if (pf_find_state_all(&key, PF_IN, NULL) == NULL) { + *nport = htons(low); + return (0); + } + } else { + u_int16_t tmp; + + if (low > high) { + tmp = low; + low = high; + high = tmp; + } + /* low < high */ +#ifdef __FreeBSD__ + cut = htonl(arc4random()) % (1 + high - low) + low; +#else + cut = arc4random_uniform(1 + high - low) + low; +#endif + /* low <= cut <= high */ + for (tmp = cut; tmp <= high; ++(tmp)) { + key.port[0] = htons(tmp); + if (pf_find_state_all(&key, PF_IN, NULL) == +#ifdef __FreeBSD__ + NULL) { +#else + NULL && !in_baddynamic(tmp, proto)) { +#endif + *nport = htons(tmp); + return (0); + } + } + for (tmp = cut - 1; tmp >= low; --(tmp)) { + key.port[0] = htons(tmp); + if (pf_find_state_all(&key, PF_IN, NULL) == +#ifdef __FreeBSD__ + NULL) { +#else + NULL && !in_baddynamic(tmp, proto)) { +#endif + *nport = htons(tmp); + return (0); + } + } + } + + switch (r->rpool.opts & PF_POOL_TYPEMASK) { + case PF_POOL_RANDOM: + case PF_POOL_ROUNDROBIN: + if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn)) + return (1); + break; + case PF_POOL_NONE: + case PF_POOL_SRCHASH: + case PF_POOL_BITMASK: + default: + return (1); + } + } while (! PF_AEQ(&init_addr, naddr, af) ); + return (1); /* none available */ +} + +int +pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, + struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn) +{ + unsigned char hash[16]; + struct pf_pool *rpool = &r->rpool; + struct pf_addr *raddr = &rpool->cur->addr.v.a.addr; + struct pf_addr *rmask = &rpool->cur->addr.v.a.mask; + struct pf_pooladdr *acur = rpool->cur; + struct pf_src_node k; + + if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR && + (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { + k.af = af; + PF_ACPY(&k.addr, saddr, af); + if (r->rule_flag & PFRULE_RULESRCTRACK || + r->rpool.opts & PF_POOL_STICKYADDR) + k.rule.ptr = r; + else + k.rule.ptr = NULL; +#ifdef __FreeBSD__ + V_pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; + *sn = RB_FIND(pf_src_tree, &V_tree_src_tracking, &k); +#else + pf_status.scounters[SCNT_SRC_NODE_SEARCH]++; + *sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k); +#endif + if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) { + PF_ACPY(naddr, &(*sn)->raddr, af); +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else + if (pf_status.debug >= PF_DEBUG_MISC) { +#endif + printf("pf_map_addr: src tracking maps "); + pf_print_host(&k.addr, 0, af); + printf(" to "); + pf_print_host(naddr, 0, af); + printf("\n"); + } + return (0); + } + } + + if (rpool->cur->addr.type == PF_ADDR_NOROUTE) + return (1); + if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { + switch (af) { +#ifdef INET + case AF_INET: + if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 && + (rpool->opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) + return (1); + raddr = &rpool->cur->addr.p.dyn->pfid_addr4; + rmask = &rpool->cur->addr.p.dyn->pfid_mask4; + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 && + (rpool->opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) + return (1); + raddr = &rpool->cur->addr.p.dyn->pfid_addr6; + rmask = &rpool->cur->addr.p.dyn->pfid_mask6; + break; +#endif /* INET6 */ + } + } else if (rpool->cur->addr.type == PF_ADDR_TABLE) { + if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN) + return (1); /* unsupported */ + } else { + raddr = &rpool->cur->addr.v.a.addr; + rmask = &rpool->cur->addr.v.a.mask; + } + + switch (rpool->opts & PF_POOL_TYPEMASK) { + case PF_POOL_NONE: + PF_ACPY(naddr, raddr, af); + break; + case PF_POOL_BITMASK: + PF_POOLMASK(naddr, raddr, rmask, saddr, af); + break; + case PF_POOL_RANDOM: + if (init_addr != NULL && PF_AZERO(init_addr, af)) { + switch (af) { +#ifdef INET + case AF_INET: + rpool->counter.addr32[0] = htonl(arc4random()); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (rmask->addr32[3] != 0xffffffff) + rpool->counter.addr32[3] = + htonl(arc4random()); + else + break; + if (rmask->addr32[2] != 0xffffffff) + rpool->counter.addr32[2] = + htonl(arc4random()); + else + break; + if (rmask->addr32[1] != 0xffffffff) + rpool->counter.addr32[1] = + htonl(arc4random()); + else + break; + if (rmask->addr32[0] != 0xffffffff) + rpool->counter.addr32[0] = + htonl(arc4random()); + break; +#endif /* INET6 */ + } + PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); + PF_ACPY(init_addr, naddr, af); + + } else { + PF_AINC(&rpool->counter, af); + PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af); + } + break; + case PF_POOL_SRCHASH: + pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af); + PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af); + break; + case PF_POOL_ROUNDROBIN: + if (rpool->cur->addr.type == PF_ADDR_TABLE) { + if (!pfr_pool_get(rpool->cur->addr.p.tbl, + &rpool->tblidx, &rpool->counter, + &raddr, &rmask, af)) + goto get_addr; + } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { + if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, + &rpool->tblidx, &rpool->counter, + &raddr, &rmask, af)) + goto get_addr; + } else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af)) + goto get_addr; + + try_next: + if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL) + rpool->cur = TAILQ_FIRST(&rpool->list); + if (rpool->cur->addr.type == PF_ADDR_TABLE) { + rpool->tblidx = -1; + if (pfr_pool_get(rpool->cur->addr.p.tbl, + &rpool->tblidx, &rpool->counter, + &raddr, &rmask, af)) { + /* table contains no address of type 'af' */ + if (rpool->cur != acur) + goto try_next; + return (1); + } + } else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) { + rpool->tblidx = -1; + if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt, + &rpool->tblidx, &rpool->counter, + &raddr, &rmask, af)) { + /* table contains no address of type 'af' */ + if (rpool->cur != acur) + goto try_next; + return (1); + } + } else { + raddr = &rpool->cur->addr.v.a.addr; + rmask = &rpool->cur->addr.v.a.mask; + PF_ACPY(&rpool->counter, raddr, af); + } + + get_addr: + PF_ACPY(naddr, &rpool->counter, af); + if (init_addr != NULL && PF_AZERO(init_addr, af)) + PF_ACPY(init_addr, naddr, af); + PF_AINC(&rpool->counter, af); + break; + } + if (*sn != NULL) + PF_ACPY(&(*sn)->raddr, naddr, af); + +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC && +#else + if (pf_status.debug >= PF_DEBUG_MISC && +#endif + (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) { + printf("pf_map_addr: selected address "); + pf_print_host(naddr, 0, af); + printf("\n"); + } + + return (0); +} + +struct pf_rule * +pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction, + struct pfi_kif *kif, struct pf_src_node **sn, + struct pf_state_key **skw, struct pf_state_key **sks, + struct pf_state_key **skp, struct pf_state_key **nkp, + struct pf_addr *saddr, struct pf_addr *daddr, + u_int16_t sport, u_int16_t dport) +{ + struct pf_rule *r = NULL; + + + if (direction == PF_OUT) { + r = pf_match_translation(pd, m, off, direction, kif, saddr, + sport, daddr, dport, PF_RULESET_BINAT); + if (r == NULL) + r = pf_match_translation(pd, m, off, direction, kif, + saddr, sport, daddr, dport, PF_RULESET_NAT); + } else { + r = pf_match_translation(pd, m, off, direction, kif, saddr, + sport, daddr, dport, PF_RULESET_RDR); + if (r == NULL) + r = pf_match_translation(pd, m, off, direction, kif, + saddr, sport, daddr, dport, PF_RULESET_BINAT); + } + + if (r != NULL) { + struct pf_addr *naddr; + u_int16_t *nport; + + if (pf_state_key_setup(pd, r, skw, sks, skp, nkp, + saddr, daddr, sport, dport)) + return r; + + /* XXX We only modify one side for now. */ + naddr = &(*nkp)->addr[1]; + nport = &(*nkp)->port[1]; + + switch (r->action) { + case PF_NONAT: + case PF_NOBINAT: + case PF_NORDR: + return (NULL); + case PF_NAT: + if (pf_get_sport(pd->af, pd->proto, r, saddr, + daddr, dport, naddr, nport, r->rpool.proxy_port[0], + r->rpool.proxy_port[1], sn)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: NAT proxy port allocation " + "(%u-%u) failed\n", + r->rpool.proxy_port[0], + r->rpool.proxy_port[1])); + return (NULL); + } + break; + case PF_BINAT: + switch (direction) { + case PF_OUT: + if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){ + switch (pd->af) { +#ifdef INET + case AF_INET: + if (r->rpool.cur->addr.p.dyn-> + pfid_acnt4 < 1) + return (NULL); + PF_POOLMASK(naddr, + &r->rpool.cur->addr.p.dyn-> + pfid_addr4, + &r->rpool.cur->addr.p.dyn-> + pfid_mask4, + saddr, AF_INET); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (r->rpool.cur->addr.p.dyn-> + pfid_acnt6 < 1) + return (NULL); + PF_POOLMASK(naddr, + &r->rpool.cur->addr.p.dyn-> + pfid_addr6, + &r->rpool.cur->addr.p.dyn-> + pfid_mask6, + saddr, AF_INET6); + break; +#endif /* INET6 */ + } + } else + PF_POOLMASK(naddr, + &r->rpool.cur->addr.v.a.addr, + &r->rpool.cur->addr.v.a.mask, + saddr, pd->af); + break; + case PF_IN: + if (r->src.addr.type == PF_ADDR_DYNIFTL) { + switch (pd->af) { +#ifdef INET + case AF_INET: + if (r->src.addr.p.dyn-> + pfid_acnt4 < 1) + return (NULL); + PF_POOLMASK(naddr, + &r->src.addr.p.dyn-> + pfid_addr4, + &r->src.addr.p.dyn-> + pfid_mask4, + daddr, AF_INET); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (r->src.addr.p.dyn-> + pfid_acnt6 < 1) + return (NULL); + PF_POOLMASK(naddr, + &r->src.addr.p.dyn-> + pfid_addr6, + &r->src.addr.p.dyn-> + pfid_mask6, + daddr, AF_INET6); + break; +#endif /* INET6 */ + } + } else + PF_POOLMASK(naddr, + &r->src.addr.v.a.addr, + &r->src.addr.v.a.mask, daddr, + pd->af); + break; + } + break; + case PF_RDR: { + if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn)) + return (NULL); + if ((r->rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_BITMASK) + PF_POOLMASK(naddr, naddr, + &r->rpool.cur->addr.v.a.mask, daddr, + pd->af); + + if (r->rpool.proxy_port[1]) { + u_int32_t tmp_nport; + + tmp_nport = ((ntohs(dport) - + ntohs(r->dst.port[0])) % + (r->rpool.proxy_port[1] - + r->rpool.proxy_port[0] + 1)) + + r->rpool.proxy_port[0]; + + /* wrap around if necessary */ + if (tmp_nport > 65535) + tmp_nport -= 65535; + *nport = htons((u_int16_t)tmp_nport); + } else if (r->rpool.proxy_port[0]) + *nport = htons(r->rpool.proxy_port[0]); + break; + } + default: + return (NULL); + } + /* + * Translation was a NOP. + * Pretend there was no match. + */ + if (!bcmp(*skp, *nkp, sizeof(struct pf_state_key_cmp))) { +#ifdef __FreeBSD__ + pool_put(&V_pf_state_key_pl, *nkp); + pool_put(&V_pf_state_key_pl, *skp); +#else + pool_put(&pf_state_key_pl, *nkp); + pool_put(&pf_state_key_pl, *skp); +#endif + *skw = *sks = *nkp = *skp = NULL; + return (NULL); + } + } + + return (r); +} + diff --git a/sys/contrib/pf/net/pf_mtag.h b/sys/contrib/pf/net/pf_mtag.h index a0ebf7e..141a867 100644 --- a/sys/contrib/pf/net/pf_mtag.h +++ b/sys/contrib/pf/net/pf_mtag.h @@ -37,15 +37,17 @@ #define PF_TAG_GENERATED 0x01 #define PF_TAG_FRAGCACHE 0x02 #define PF_TAG_TRANSLATE_LOCALHOST 0x04 +#define PF_PACKET_LOOPED 0x08 +#define PF_FASTFWD_OURS_PRESENT 0x10 struct pf_mtag { void *hdr; /* saved hdr pos in mbuf, for ECN */ - u_int rtableid; /* alternate routing table id */ + void *statekey; /* pf stackside statekey */ u_int32_t qid; /* queue id */ + u_int rtableid; /* alternate routing table id */ u_int16_t tag; /* tag id */ u_int8_t flags; u_int8_t routed; - sa_family_t af; /* for ECN */ }; static __inline struct pf_mtag *pf_find_mtag(struct mbuf *); diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c index cd6d65a..6c04eee 100644 --- a/sys/contrib/pf/net/pf_norm.c +++ b/sys/contrib/pf/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.107 2006/04/16 00:59:52 pascoe Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.114 2009/01/29 14:11:45 henning Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -34,9 +34,9 @@ __FBSDID("$FreeBSD$"); #ifdef DEV_PFLOG -#define NPFLOG DEV_PFLOG +#define NPFLOG DEV_PFLOG #else -#define NPFLOG 0 +#define NPFLOG 0 #endif #else #include "pflog.h" @@ -78,8 +78,6 @@ __FBSDID("$FreeBSD$"); #include <net/pfvar.h> #ifndef __FreeBSD__ -#include <inttypes.h> - struct pf_frent { LIST_ENTRY(pf_frent) fr_next; struct ip *fr_ip; @@ -118,17 +116,35 @@ struct pf_fragment { }; #endif +#ifdef __FreeBSD__ +TAILQ_HEAD(pf_fragqueue, pf_fragment); +TAILQ_HEAD(pf_cachequeue, pf_fragment); +VNET_DEFINE(struct pf_fragqueue, pf_fragqueue); +#define V_pf_fragqueue VNET(pf_fragqueue) +VNET_DEFINE(struct pf_cachequeue, pf_cachequeue); +#define V_pf_cachequeue VNET(pf_cachequeue) +#else TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue; TAILQ_HEAD(pf_cachequeue, pf_fragment) pf_cachequeue; +#endif #ifndef __FreeBSD__ static __inline int pf_frag_compare(struct pf_fragment *, struct pf_fragment *); #else -static int pf_frag_compare(struct pf_fragment *, +static int pf_frag_compare(struct pf_fragment *, struct pf_fragment *); #endif + +#ifdef __FreeBSD__ +RB_HEAD(pf_frag_tree, pf_fragment); +VNET_DEFINE(struct pf_frag_tree, pf_frag_tree); +#define V_pf_frag_tree VNET(pf_frag_tree) +VNET_DEFINE(struct pf_frag_tree, pf_cache_tree); +#define V_pf_cache_tree VNET(pf_cache_tree) +#else RB_HEAD(pf_frag_tree, pf_fragment) pf_frag_tree, pf_cache_tree; +#endif RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); @@ -143,24 +159,45 @@ struct mbuf *pf_reassemble(struct mbuf **, struct pf_fragment **, struct mbuf *pf_fragcache(struct mbuf **, struct ip*, struct pf_fragment **, int, int, int *); int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, - struct tcphdr *, int); - + struct tcphdr *, int, sa_family_t); +void pf_scrub_ip(struct mbuf **, u_int32_t, u_int8_t, + u_int8_t); +#ifdef INET6 +void pf_scrub_ip6(struct mbuf **, u_int8_t); +#endif +#ifdef __FreeBSD__ +#define DPFPRINTF(x) do { \ + if (V_pf_status.debug >= PF_DEBUG_MISC) { \ + printf("%s: ", __func__); \ + printf x ; \ + } \ +} while(0) +#else #define DPFPRINTF(x) do { \ if (pf_status.debug >= PF_DEBUG_MISC) { \ printf("%s: ", __func__); \ printf x ; \ } \ } while(0) +#endif /* Globals */ #ifdef __FreeBSD__ -uma_zone_t pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl; -uma_zone_t pf_state_scrub_pl; +VNET_DEFINE(uma_zone_t, pf_frent_pl); +VNET_DEFINE(uma_zone_t, pf_frag_pl); +VNET_DEFINE(uma_zone_t, pf_cache_pl); +VNET_DEFINE(uma_zone_t, pf_cent_pl); +VNET_DEFINE(uma_zone_t, pf_state_scrub_pl); + +VNET_DEFINE(int, pf_nfrents); +#define V_pf_nfrents VNET(pf_nfrents) +VNET_DEFINE(int, pf_ncache); +#define V_pf_ncache VNET(pf_ncache) #else struct pool pf_frent_pl, pf_frag_pl, pf_cache_pl, pf_cent_pl; struct pool pf_state_scrub_pl; -#endif int pf_nfrents, pf_ncache; +#endif void pf_normalize_init(void) @@ -171,9 +208,9 @@ pf_normalize_init(void) * No high water mark support(It's hint not hard limit). * uma_zone_set_max(pf_frag_pl, PFFRAG_FRAG_HIWAT); */ - uma_zone_set_max(pf_frent_pl, PFFRAG_FRENT_HIWAT); - uma_zone_set_max(pf_cache_pl, PFFRAG_FRCACHE_HIWAT); - uma_zone_set_max(pf_cent_pl, PFFRAG_FRCENT_HIWAT); + uma_zone_set_max(V_pf_frent_pl, PFFRAG_FRENT_HIWAT); + uma_zone_set_max(V_pf_cache_pl, PFFRAG_FRCACHE_HIWAT); + uma_zone_set_max(V_pf_cent_pl, PFFRAG_FRCENT_HIWAT); #else pool_init(&pf_frent_pl, sizeof(struct pf_frent), 0, 0, 0, "pffrent", NULL); @@ -192,8 +229,13 @@ pf_normalize_init(void) pool_sethardlimit(&pf_cent_pl, PFFRAG_FRCENT_HIWAT, NULL, 0); #endif +#ifdef __FreeBSD__ + TAILQ_INIT(&V_pf_fragqueue); + TAILQ_INIT(&V_pf_cachequeue); +#else TAILQ_INIT(&pf_fragqueue); TAILQ_INIT(&pf_cachequeue); +#endif } #ifdef __FreeBSD__ @@ -224,14 +266,20 @@ void pf_purge_expired_fragments(void) { struct pf_fragment *frag; +#ifdef __FreeBSD__ + u_int32_t expire = time_second - + V_pf_default_rule.timeout[PFTM_FRAG]; +#else u_int32_t expire = time_second - pf_default_rule.timeout[PFTM_FRAG]; +#endif - while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) { #ifdef __FreeBSD__ + while ((frag = TAILQ_LAST(&V_pf_fragqueue, pf_fragqueue)) != NULL) { KASSERT((BUFFER_FRAGMENTS(frag)), - ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__)); + ("BUFFER_FRAGMENTS(frag) == 0: %s", __FUNCTION__)); #else + while ((frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue)) != NULL) { KASSERT(BUFFER_FRAGMENTS(frag)); #endif if (frag->fr_timeout > expire) @@ -241,11 +289,12 @@ pf_purge_expired_fragments(void) pf_free_fragment(frag); } - while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) { #ifdef __FreeBSD__ + while ((frag = TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue)) != NULL) { KASSERT((!BUFFER_FRAGMENTS(frag)), - ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__)); + ("BUFFER_FRAGMENTS(frag) != 0: %s", __FUNCTION__)); #else + while ((frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue)) != NULL) { KASSERT(!BUFFER_FRAGMENTS(frag)); #endif if (frag->fr_timeout > expire) @@ -254,8 +303,8 @@ pf_purge_expired_fragments(void) DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag)); pf_free_fragment(frag); #ifdef __FreeBSD__ - KASSERT((TAILQ_EMPTY(&pf_cachequeue) || - TAILQ_LAST(&pf_cachequeue, pf_cachequeue) != frag), + KASSERT((TAILQ_EMPTY(&V_pf_cachequeue) || + TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue) != frag), ("!(TAILQ_EMPTY() || TAILQ_LAST() == farg): %s", __FUNCTION__)); #else @@ -275,22 +324,44 @@ pf_flush_fragments(void) struct pf_fragment *frag; int goal; +#ifdef __FreeBSD__ + goal = V_pf_nfrents * 9 / 10; + DPFPRINTF(("trying to free > %d frents\n", + V_pf_nfrents - goal)); + while (goal < V_pf_nfrents) { +#else goal = pf_nfrents * 9 / 10; DPFPRINTF(("trying to free > %d frents\n", pf_nfrents - goal)); while (goal < pf_nfrents) { +#endif +#ifdef __FreeBSD__ + frag = TAILQ_LAST(&V_pf_fragqueue, pf_fragqueue); +#else frag = TAILQ_LAST(&pf_fragqueue, pf_fragqueue); +#endif if (frag == NULL) break; pf_free_fragment(frag); } +#ifdef __FreeBSD__ + goal = V_pf_ncache * 9 / 10; + DPFPRINTF(("trying to free > %d cache entries\n", + V_pf_ncache - goal)); + while (goal < V_pf_ncache) { +#else goal = pf_ncache * 9 / 10; DPFPRINTF(("trying to free > %d cache entries\n", pf_ncache - goal)); while (goal < pf_ncache) { +#endif +#ifdef __FreeBSD__ + frag = TAILQ_LAST(&V_pf_cachequeue, pf_cachequeue); +#else frag = TAILQ_LAST(&pf_cachequeue, pf_cachequeue); +#endif if (frag == NULL) break; pf_free_fragment(frag); @@ -312,8 +383,13 @@ pf_free_fragment(struct pf_fragment *frag) LIST_REMOVE(frent, fr_next); m_freem(frent->fr_m); +#ifdef __FreeBSD__ + pool_put(&V_pf_frent_pl, frent); + V_pf_nfrents--; +#else pool_put(&pf_frent_pl, frent); pf_nfrents--; +#endif } } else { for (frcache = LIST_FIRST(&frag->fr_cache); frcache; @@ -325,15 +401,18 @@ pf_free_fragment(struct pf_fragment *frag) LIST_FIRST(&frag->fr_cache)->fr_off > frcache->fr_end), ("! (LIST_EMPTY() || LIST_FIRST()->fr_off >" - " frcache->fr_end): %s", __FUNCTION__)); + " frcache->fr_end): %s", __FUNCTION__)); + + pool_put(&V_pf_cent_pl, frcache); + V_pf_ncache--; #else KASSERT(LIST_EMPTY(&frag->fr_cache) || LIST_FIRST(&frag->fr_cache)->fr_off > frcache->fr_end); -#endif pool_put(&pf_cent_pl, frcache); pf_ncache--; +#endif } } @@ -362,11 +441,21 @@ pf_find_fragment(struct ip *ip, struct pf_frag_tree *tree) /* XXX Are we sure we want to update the timeout? */ frag->fr_timeout = time_second; if (BUFFER_FRAGMENTS(frag)) { +#ifdef __FreeBSD__ + TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); + TAILQ_INSERT_HEAD(&V_pf_fragqueue, frag, frag_next); +#else TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next); +#endif } else { +#ifdef __FreeBSD__ + TAILQ_REMOVE(&V_pf_cachequeue, frag, frag_next); + TAILQ_INSERT_HEAD(&V_pf_cachequeue, frag, frag_next); +#else TAILQ_REMOVE(&pf_cachequeue, frag, frag_next); TAILQ_INSERT_HEAD(&pf_cachequeue, frag, frag_next); +#endif } } @@ -379,13 +468,25 @@ void pf_remove_fragment(struct pf_fragment *frag) { if (BUFFER_FRAGMENTS(frag)) { +#ifdef __FreeBSD__ + RB_REMOVE(pf_frag_tree, &V_pf_frag_tree, frag); + TAILQ_REMOVE(&V_pf_fragqueue, frag, frag_next); + pool_put(&V_pf_frag_pl, frag); +#else RB_REMOVE(pf_frag_tree, &pf_frag_tree, frag); TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); pool_put(&pf_frag_pl, frag); +#endif } else { +#ifdef __FreeBSD__ + RB_REMOVE(pf_frag_tree, &V_pf_cache_tree, frag); + TAILQ_REMOVE(&V_pf_cachequeue, frag, frag_next); + pool_put(&V_pf_cache_pl, frag); +#else RB_REMOVE(pf_frag_tree, &pf_cache_tree, frag); TAILQ_REMOVE(&pf_cachequeue, frag, frag_next); pool_put(&pf_cache_pl, frag); +#endif } } @@ -416,10 +517,18 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, /* Create a new reassembly queue for this packet */ if (*frag == NULL) { +#ifdef __FreeBSD__ + *frag = pool_get(&V_pf_frag_pl, PR_NOWAIT); +#else *frag = pool_get(&pf_frag_pl, PR_NOWAIT); +#endif if (*frag == NULL) { pf_flush_fragments(); +#ifdef __FreeBSD__ + *frag = pool_get(&V_pf_frag_pl, PR_NOWAIT); +#else *frag = pool_get(&pf_frag_pl, PR_NOWAIT); +#endif if (*frag == NULL) goto drop_fragment; } @@ -433,8 +542,13 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, (*frag)->fr_timeout = time_second; LIST_INIT(&(*frag)->fr_queue); +#ifdef __FreeBSD__ + RB_INSERT(pf_frag_tree, &V_pf_frag_tree, *frag); + TAILQ_INSERT_HEAD(&V_pf_fragqueue, *frag, frag_next); +#else RB_INSERT(pf_frag_tree, &pf_frag_tree, *frag); TAILQ_INSERT_HEAD(&pf_fragqueue, *frag, frag_next); +#endif /* We do not have a previous fragment */ frep = NULL; @@ -499,8 +613,13 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, next = LIST_NEXT(frea, fr_next); m_freem(frea->fr_m); LIST_REMOVE(frea, fr_next); +#ifdef __FreeBSD__ + pool_put(&V_pf_frent_pl, frea); + V_pf_nfrents--; +#else pool_put(&pf_frent_pl, frea); pf_nfrents--; +#endif } insert: @@ -560,26 +679,36 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, m2 = m->m_next; m->m_next = NULL; m_cat(m, m2); +#ifdef __FreeBSD__ + pool_put(&V_pf_frent_pl, frent); + V_pf_nfrents--; +#else pool_put(&pf_frent_pl, frent); pf_nfrents--; +#endif for (frent = next; frent != NULL; frent = next) { next = LIST_NEXT(frent, fr_next); m2 = frent->fr_m; +#ifdef __FreeBSD__ + pool_put(&V_pf_frent_pl, frent); + V_pf_nfrents--; +#else pool_put(&pf_frent_pl, frent); pf_nfrents--; +#endif #ifdef __FreeBSD__ m->m_pkthdr.csum_flags &= m2->m_pkthdr.csum_flags; m->m_pkthdr.csum_data += m2->m_pkthdr.csum_data; #endif m_cat(m, m2); } + #ifdef __FreeBSD__ while (m->m_pkthdr.csum_data & 0xffff0000) m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) + (m->m_pkthdr.csum_data >> 16); #endif - ip->ip_src = (*frag)->fr_src; ip->ip_dst = (*frag)->fr_dst; @@ -606,8 +735,13 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment **frag, drop_fragment: /* Oops - fail safe - drop packet */ +#ifdef __FreeBSD__ + pool_put(&V_pf_frent_pl, frent); + V_pf_nfrents--; +#else pool_put(&pf_frent_pl, frent); pf_nfrents--; +#endif m_freem(m); return (NULL); } @@ -632,22 +766,40 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, /* Create a new range queue for this packet */ if (*frag == NULL) { +#ifdef __FreeBSD__ + *frag = pool_get(&V_pf_cache_pl, PR_NOWAIT); +#else *frag = pool_get(&pf_cache_pl, PR_NOWAIT); +#endif if (*frag == NULL) { pf_flush_fragments(); +#ifdef __FreeBSD__ + *frag = pool_get(&V_pf_cache_pl, PR_NOWAIT); +#else *frag = pool_get(&pf_cache_pl, PR_NOWAIT); +#endif if (*frag == NULL) goto no_mem; } /* Get an entry for the queue */ +#ifdef __FreeBSD__ + cur = pool_get(&V_pf_cent_pl, PR_NOWAIT); + if (cur == NULL) { + pool_put(&V_pf_cache_pl, *frag); +#else cur = pool_get(&pf_cent_pl, PR_NOWAIT); if (cur == NULL) { pool_put(&pf_cache_pl, *frag); +#endif *frag = NULL; goto no_mem; } +#ifdef __FreeBSD__ + V_pf_ncache++; +#else pf_ncache++; +#endif (*frag)->fr_flags = PFFRAG_NOBUFFER; (*frag)->fr_max = 0; @@ -662,8 +814,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, LIST_INIT(&(*frag)->fr_cache); LIST_INSERT_HEAD(&(*frag)->fr_cache, cur, fr_next); +#ifdef __FreeBSD__ + RB_INSERT(pf_frag_tree, &V_pf_cache_tree, *frag); + TAILQ_INSERT_HEAD(&V_pf_cachequeue, *frag, frag_next); +#else RB_INSERT(pf_frag_tree, &pf_cache_tree, *frag); TAILQ_INSERT_HEAD(&pf_cachequeue, *frag, frag_next); +#endif DPFPRINTF(("fragcache[%d]: new %d-%d\n", h->ip_id, off, max)); @@ -782,10 +939,18 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, h->ip_id, -precut, frp->fr_off, frp->fr_end, off, max)); +#ifdef __FreeBSD__ + cur = pool_get(&V_pf_cent_pl, PR_NOWAIT); +#else cur = pool_get(&pf_cent_pl, PR_NOWAIT); +#endif if (cur == NULL) goto no_mem; +#ifdef __FreeBSD__ + V_pf_ncache++; +#else pf_ncache++; +#endif cur->fr_off = off; cur->fr_end = max; @@ -842,10 +1007,18 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, h->ip_id, -aftercut, off, max, fra->fr_off, fra->fr_end)); +#ifdef __FreeBSD__ + cur = pool_get(&V_pf_cent_pl, PR_NOWAIT); +#else cur = pool_get(&pf_cent_pl, PR_NOWAIT); +#endif if (cur == NULL) goto no_mem; +#ifdef __FreeBSD__ + V_pf_ncache++; +#else pf_ncache++; +#endif cur->fr_off = off; cur->fr_end = max; @@ -863,8 +1036,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, max, fra->fr_off, fra->fr_end)); fra->fr_off = cur->fr_off; LIST_REMOVE(cur, fr_next); +#ifdef __FreeBSD__ + pool_put(&V_pf_cent_pl, cur); + V_pf_ncache--; +#else pool_put(&pf_cent_pl, cur); pf_ncache--; +#endif cur = NULL; } else if (frp && fra->fr_off <= frp->fr_end) { @@ -881,8 +1059,13 @@ pf_fragcache(struct mbuf **m0, struct ip *h, struct pf_fragment **frag, int mff, max, fra->fr_off, fra->fr_end)); fra->fr_off = frp->fr_off; LIST_REMOVE(frp, fr_next); +#ifdef __FreeBSD__ + pool_put(&V_pf_cent_pl, frp); + V_pf_ncache--; +#else pool_put(&pf_cent_pl, frp); pf_ncache--; +#endif frp = NULL; } @@ -965,6 +1148,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, u_int16_t max; int ip_len; int ip_off; + int tag = -1; r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_SCRUB].active.ptr); while (r != NULL) { @@ -985,6 +1169,12 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, (struct pf_addr *)&h->ip_dst.s_addr, AF_INET, r->dst.neg, NULL)) r = r->skip[PF_SKIP_DST_ADDR].ptr; +#ifdef __FreeBSD__ + else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag)) +#else + else if (r->match_tag && !pf_match_tag(m, r, &tag)) +#endif + r = TAILQ_NEXT(r, entries); else break; } @@ -1043,7 +1233,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) { /* Fully buffer all of the fragments */ +#ifdef __FreeBSD__ + frag = pf_find_fragment(h, &V_pf_frag_tree); +#else frag = pf_find_fragment(h, &pf_frag_tree); +#endif /* Check if we saw the last fragment already */ if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) && @@ -1051,12 +1245,20 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, goto bad; /* Get an entry for the fragment queue */ +#ifdef __FreeBSD__ + frent = pool_get(&V_pf_frent_pl, PR_NOWAIT); +#else frent = pool_get(&pf_frent_pl, PR_NOWAIT); +#endif if (frent == NULL) { REASON_SET(reason, PFRES_MEMORY); return (PF_DROP); } +#ifdef __FreeBSD__ + V_pf_nfrents++; +#else pf_nfrents++; +#endif frent->fr_ip = h; frent->fr_m = m; @@ -1087,7 +1289,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, /* non-buffering fragment cache (drops or masks overlaps) */ int nomem = 0; +#ifdef __FreeBSD__ if (dir == PF_OUT && pd->pf_mtag->flags & PF_TAG_FRAGCACHE) { +#else + if (dir == PF_OUT && m->m_pkthdr.pf.flags & PF_TAG_FRAGCACHE) { +#endif /* * Already passed the fragment cache in the * input direction. If we continued, it would @@ -1096,7 +1302,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, goto fragment_pass; } +#ifdef __FreeBSD__ + frag = pf_find_fragment(h, &V_pf_cache_tree); +#else frag = pf_find_fragment(h, &pf_cache_tree); +#endif /* Check if we saw the last fragment already */ if (frag != NULL && (frag->fr_flags & PFFRAG_SEENLAST) && @@ -1127,7 +1337,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, } #endif if (dir == PF_IN) +#ifdef __FreeBSD__ pd->pf_mtag->flags |= PF_TAG_FRAGCACHE; +#else + m->m_pkthdr.pf.flags |= PF_TAG_FRAGCACHE; +#endif if (frag != NULL && (frag->fr_flags & PFFRAG_DROP)) goto drop; @@ -1143,33 +1357,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason, h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0); } - /* Enforce a minimum ttl, may cause endless packet loops */ - if (r->min_ttl && h->ip_ttl < r->min_ttl) { - u_int16_t ip_ttl = h->ip_ttl; - - h->ip_ttl = r->min_ttl; - h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0); - } - - if (r->rule_flag & PFRULE_RANDOMID) { - u_int16_t ip_id = h->ip_id; - - h->ip_id = ip_randomid(); - h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0); - } - if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) - pd->flags |= PFDESC_IP_REAS; - - return (PF_PASS); + /* not missing a return here */ fragment_pass: - /* Enforce a minimum ttl, may cause endless packet loops */ - if (r->min_ttl && h->ip_ttl < r->min_ttl) { - u_int16_t ip_ttl = h->ip_ttl; + pf_scrub_ip(&m, r->rule_flag, r->min_ttl, r->set_tos); - h->ip_ttl = r->min_ttl; - h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0); - } if ((r->rule_flag & (PFRULE_FRAGCROP|PFRULE_FRAGDROP)) == 0) pd->flags |= PFDESC_IP_REAS; return (PF_PASS); @@ -1339,9 +1531,7 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif, if (sizeof(struct ip6_hdr) + plen > m->m_pkthdr.len) goto shortpkt; - /* Enforce a minimum ttl, may cause endless packet loops */ - if (r->min_ttl && h->ip6_hlim < r->min_ttl) - h->ip6_hlim = r->min_ttl; + pf_scrub_ip6(&m, r->min_ttl); return (PF_PASS); @@ -1479,12 +1669,16 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff, } /* Process options */ - if (r->max_mss && pf_normalize_tcpopt(r, m, th, off)) + if (r->max_mss && pf_normalize_tcpopt(r, m, th, off, pd->af)) rewrite = 1; /* copy back packet headers if we sanitized */ if (rewrite) +#ifdef __FreeBSD__ m_copyback(m, off, sizeof(*th), (caddr_t)th); +#else + m_copyback(m, off, sizeof(*th), th); +#endif return (PF_PASS); @@ -1506,11 +1700,13 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, #ifdef __FreeBSD__ KASSERT((src->scrub == NULL), ("pf_normalize_tcp_init: src->scrub != NULL")); + + src->scrub = pool_get(&V_pf_state_scrub_pl, PR_NOWAIT); #else KASSERT(src->scrub == NULL); -#endif src->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); +#endif if (src->scrub == NULL) return (1); bzero(src->scrub, sizeof(*src->scrub)); @@ -1586,10 +1782,17 @@ pf_normalize_tcp_init(struct mbuf *m, int off, struct pf_pdesc *pd, void pf_normalize_tcp_cleanup(struct pf_state *state) { +#ifdef __FreeBSD__ + if (state->src.scrub) + pool_put(&V_pf_state_scrub_pl, state->src.scrub); + if (state->dst.scrub) + pool_put(&V_pf_state_scrub_pl, state->dst.scrub); +#else if (state->src.scrub) pool_put(&pf_state_scrub_pl, state->src.scrub); if (state->dst.scrub) pool_put(&pf_state_scrub_pl, state->dst.scrub); +#endif /* Someday... flush the TCP segment reassembly descriptors. */ } @@ -1667,7 +1870,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, if (got_ts) { /* Huh? Multiple timestamps!? */ +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif DPFPRINTF(("multiple TS??")); pf_print_state(state); printf("\n"); @@ -1736,7 +1943,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, if (src->scrub && (src->scrub->pfss_flags & PFSS_PAWS) && (uptime.tv_sec - src->scrub->pfss_last.tv_sec > TS_MAX_IDLE || time_second - state->creation > TS_MAX_CONN)) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif DPFPRINTF(("src idled out of PAWS\n")); pf_print_state(state); printf("\n"); @@ -1746,7 +1957,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, } if (dst->scrub && (dst->scrub->pfss_flags & PFSS_PAWS) && uptime.tv_sec - dst->scrub->pfss_last.tv_sec > TS_MAX_IDLE) { +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif DPFPRINTF(("dst idled out of PAWS\n")); pf_print_state(state); printf("\n"); @@ -1807,7 +2022,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, * network conditions that re-order packets and * cause our view of them to decrease. For now the * only lowerbound we can safely determine is that - * the TS echo will never be less than the orginal + * the TS echo will never be less than the original * TS. XXX There is probably a better lowerbound. * Remove TS_MAX_CONN with better lowerbound check. * tescr >= other original TS @@ -1830,7 +2045,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, * this packet. */ if ((ts_fudge = state->rule.ptr->timeout[PFTM_TS_DIFF]) == 0) +#ifdef __FreeBSD__ + ts_fudge = V_pf_default_rule.timeout[PFTM_TS_DIFF]; +#else ts_fudge = pf_default_rule.timeout[PFTM_TS_DIFF]; +#endif /* Calculate max ticks since the last timestamp */ @@ -1838,7 +2057,7 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, #define TS_MICROSECS 1000000 /* microseconds per second */ #ifdef __FreeBSD__ #ifndef timersub -#define timersub(tvp, uvp, vvp) \ +#define timersub(tvp, uvp, vvp) \ do { \ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ @@ -1895,7 +2114,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, "\n", dst->scrub->pfss_tsval, dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0)); #endif +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif pf_print_state(state); pf_print_flags(th->th_flags); printf("\n"); @@ -1943,7 +2166,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, * Hey! Someone tried to sneak a packet in. Or the * stack changed its RFC1323 behavior?!?! */ +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC) { +#else if (pf_status.debug >= PF_DEBUG_MISC) { +#endif DPFPRINTF(("Did not receive expected RFC1323 " "timestamp\n")); pf_print_state(state); @@ -1970,7 +2197,11 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, src->scrub->pfss_flags |= PFSS_DATA_TS; else { src->scrub->pfss_flags |= PFSS_DATA_NOTS; +#ifdef __FreeBSD__ + if (V_pf_status.debug >= PF_DEBUG_MISC && dst->scrub && +#else if (pf_status.debug >= PF_DEBUG_MISC && dst->scrub && +#endif (dst->scrub->pfss_flags & PFSS_TIMESTAMP)) { /* Don't warn if other host rejected RFC1323 */ DPFPRINTF(("Broken RFC1323 stack did not " @@ -2018,17 +2249,25 @@ pf_normalize_tcp_stateful(struct mbuf *m, int off, struct pf_pdesc *pd, int pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th, - int off) + int off, sa_family_t af) { u_int16_t *mss; int thoff; int opt, cnt, optlen = 0; int rewrite = 0; - u_char *optp; +#ifdef __FreeBSD__ + u_char opts[TCP_MAXOLEN]; +#else + u_char opts[MAX_TCPOPTLEN]; +#endif + u_char *optp = opts; thoff = th->th_off << 2; cnt = thoff - sizeof(struct tcphdr); - optp = mtod(m, caddr_t) + off + sizeof(struct tcphdr); + + if (cnt > 0 && !pf_pull_hdr(m, off + sizeof(*th), opts, cnt, + NULL, NULL, af)) + return (rewrite); for (; cnt > 0; cnt -= optlen, optp += optlen) { opt = optp[0]; @@ -2058,5 +2297,63 @@ pf_normalize_tcpopt(struct pf_rule *r, struct mbuf *m, struct tcphdr *th, } } + if (rewrite) + m_copyback(m, off + sizeof(*th), thoff - sizeof(*th), opts); + return (rewrite); } + +void +pf_scrub_ip(struct mbuf **m0, u_int32_t flags, u_int8_t min_ttl, u_int8_t tos) +{ + struct mbuf *m = *m0; + struct ip *h = mtod(m, struct ip *); + + /* Clear IP_DF if no-df was requested */ + if (flags & PFRULE_NODF && h->ip_off & htons(IP_DF)) { + u_int16_t ip_off = h->ip_off; + + h->ip_off &= htons(~IP_DF); + h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_off, h->ip_off, 0); + } + + /* Enforce a minimum ttl, may cause endless packet loops */ + if (min_ttl && h->ip_ttl < min_ttl) { + u_int16_t ip_ttl = h->ip_ttl; + + h->ip_ttl = min_ttl; + h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_ttl, h->ip_ttl, 0); + } + + /* Enforce tos */ + if (flags & PFRULE_SET_TOS) { + u_int16_t ov, nv; + + ov = *(u_int16_t *)h; + h->ip_tos = tos; + nv = *(u_int16_t *)h; + + h->ip_sum = pf_cksum_fixup(h->ip_sum, ov, nv, 0); + } + + /* random-id, but not for fragments */ + if (flags & PFRULE_RANDOMID && !(h->ip_off & ~htons(IP_DF))) { + u_int16_t ip_id = h->ip_id; + + h->ip_id = ip_randomid(); + h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0); + } +} + +#ifdef INET6 +void +pf_scrub_ip6(struct mbuf **m0, u_int8_t min_ttl) +{ + struct mbuf *m = *m0; + struct ip6_hdr *h = mtod(m, struct ip6_hdr *); + + /* Enforce a minimum ttl, may cause endless packet loops */ + if (min_ttl && h->ip6_hlim < min_ttl) + h->ip6_hlim = min_ttl; +} +#endif diff --git a/sys/contrib/pf/net/pf_osfp.c b/sys/contrib/pf/net/pf_osfp.c index 225528d..dcd8af7 100644 --- a/sys/contrib/pf/net/pf_osfp.c +++ b/sys/contrib/pf/net/pf_osfp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_osfp.c,v 1.12 2006/12/13 18:14:10 itojun Exp $ */ +/* $OpenBSD: pf_osfp.c,v 1.14 2008/06/12 18:17:01 henning Exp $ */ /* * Copyright (c) 2003 Mike Frantzen <frantzen@w4g.org> @@ -25,7 +25,10 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/socket.h> #ifdef _KERNEL -# include <sys/systm.h> +#include <sys/systm.h> +#ifndef __FreeBSD__ +#include <sys/pool.h> +#endif #endif /* _KERNEL */ #include <sys/mbuf.h> @@ -42,10 +45,17 @@ __FBSDID("$FreeBSD$"); #include <netinet6/in6_var.h> #endif + #ifdef _KERNEL -# define DPFPRINTF(format, x...) \ +#ifdef __FreeBSD__ +#define DPFPRINTF(format, x...) \ + if (V_pf_status.debug >= PF_DEBUG_NOISY) \ + printf(format , ##x) +#else +#define DPFPRINTF(format, x...) \ if (pf_status.debug >= PF_DEBUG_NOISY) \ printf(format , ##x) +#endif #ifdef __FreeBSD__ typedef uma_zone_t pool_t; #else @@ -55,33 +65,43 @@ typedef struct pool pool_t; #else /* Userland equivalents so we can lend code to tcpdump et al. */ -# include <arpa/inet.h> -# include <errno.h> -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# include <netdb.h> -# define pool_t int -# define pool_get(pool, flags) malloc(*(pool)) -# define pool_put(pool, item) free(item) -# define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size) - -# ifdef __FreeBSD__ -# define NTOHS(x) (x) = ntohs((u_int16_t)(x)) -# endif - -# ifdef PFDEBUG -# include <sys/stdarg.h> -# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) -# else -# define DPFPRINTF(format, x...) ((void)0) -# endif /* PFDEBUG */ +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#define pool_t int +#define pool_get(pool, flags) malloc(*(pool)) +#define pool_put(pool, item) free(item) +#define pool_init(pool, size, a, ao, f, m, p) (*(pool)) = (size) + +#ifdef __FreeBSD__ +#define NTOHS(x) (x) = ntohs((u_int16_t)(x)) +#endif + +#ifdef PFDEBUG +#include <sys/stdarg.h> +#define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) +#else +#define DPFPRINTF(format, x...) ((void)0) +#endif /* PFDEBUG */ #endif /* _KERNEL */ +#ifdef __FreeBSD__ +SLIST_HEAD(pf_osfp_list, pf_os_fingerprint); +VNET_DEFINE(struct pf_osfp_list, pf_osfp_list); +#define V_pf_osfp_list VNET(pf_osfp_list) +VNET_DEFINE(pool_t, pf_osfp_entry_pl); +#define pf_osfp_entry_pl VNET(pf_osfp_entry_pl) +VNET_DEFINE(pool_t, pf_osfp_pl); +#define pf_osfp_pl VNET(pf_osfp_pl) +#else SLIST_HEAD(pf_osfp_list, pf_os_fingerprint) pf_osfp_list; pool_t pf_osfp_entry_pl; pool_t pf_osfp_pl; +#endif struct pf_os_fingerprint *pf_osfp_find(struct pf_osfp_list *, struct pf_os_fingerprint *, u_int8_t); @@ -264,7 +284,11 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const st (fp.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", fp.fp_wscale); +#ifdef __FreeBSD__ + if ((fpresult = pf_osfp_find(&V_pf_osfp_list, &fp, +#else if ((fpresult = pf_osfp_find(&pf_osfp_list, &fp, +#endif PF_OSFP_MAXTTL_OFFSET))) return (&fpresult->fp_oses); return (NULL); @@ -310,20 +334,23 @@ pf_osfp_initialize(void) { #if defined(__FreeBSD__) && defined(_KERNEL) int error = ENOMEM; - + do { pf_osfp_entry_pl = pf_osfp_pl = NULL; UMA_CREATE(pf_osfp_entry_pl, struct pf_osfp_entry, "pfospfen"); UMA_CREATE(pf_osfp_pl, struct pf_os_fingerprint, "pfosfp"); error = 0; } while(0); + + SLIST_INIT(&V_pf_osfp_list); #else pool_init(&pf_osfp_entry_pl, sizeof(struct pf_osfp_entry), 0, 0, 0, "pfosfpen", &pool_allocator_nointr); pool_init(&pf_osfp_pl, sizeof(struct pf_os_fingerprint), 0, 0, 0, "pfosfp", &pool_allocator_nointr); -#endif SLIST_INIT(&pf_osfp_list); +#endif + #ifdef __FreeBSD__ #ifdef _KERNEL return (error); @@ -337,6 +364,7 @@ pf_osfp_initialize(void) void pf_osfp_cleanup(void) { + UMA_DESTROY(pf_osfp_entry_pl); UMA_DESTROY(pf_osfp_pl); } @@ -349,8 +377,13 @@ pf_osfp_flush(void) struct pf_os_fingerprint *fp; struct pf_osfp_entry *entry; +#ifdef __FreeBSD__ + while ((fp = SLIST_FIRST(&V_pf_osfp_list))) { + SLIST_REMOVE_HEAD(&V_pf_osfp_list, fp_next); +#else while ((fp = SLIST_FIRST(&pf_osfp_list))) { SLIST_REMOVE_HEAD(&pf_osfp_list, fp_next); +#endif while ((entry = SLIST_FIRST(&fp->fp_oses))) { SLIST_REMOVE_HEAD(&fp->fp_oses, fp_entry); pool_put(&pf_osfp_entry_pl, entry); @@ -377,6 +410,7 @@ pf_osfp_add(struct pf_osfp_ioctl *fpioc) fpadd.fp_wscale = fpioc->fp_wscale; fpadd.fp_ttl = fpioc->fp_ttl; +#if 0 /* XXX RYAN wants to fix logging */ DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d " "(TS=%s,M=%s%d,W=%s%d) %x\n", fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm, @@ -400,17 +434,31 @@ pf_osfp_add(struct pf_osfp_ioctl *fpioc) (fpadd.fp_flags & PF_OSFP_WSCALE_DC) ? "*" : "", fpadd.fp_wscale, fpioc->fp_os.fp_os); +#endif - +#ifdef __FreeBSD__ + if ((fp = pf_osfp_find_exact(&V_pf_osfp_list, &fpadd))) { +#else if ((fp = pf_osfp_find_exact(&pf_osfp_list, &fpadd))) { +#endif SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { if (PF_OSFP_ENTRY_EQ(entry, &fpioc->fp_os)) return (EEXIST); } - if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL) + if ((entry = pool_get(&pf_osfp_entry_pl, +#ifdef __FreeBSD__ + PR_NOWAIT)) == NULL) +#else + PR_WAITOK|PR_LIMITFAIL)) == NULL) +#endif return (ENOMEM); } else { - if ((fp = pool_get(&pf_osfp_pl, PR_NOWAIT)) == NULL) + if ((fp = pool_get(&pf_osfp_pl, +#ifdef __FreeBSD__ + PR_NOWAIT)) == NULL) +#else + PR_WAITOK|PR_LIMITFAIL)) == NULL) +#endif return (ENOMEM); memset(fp, 0, sizeof(*fp)); fp->fp_tcpopts = fpioc->fp_tcpopts; @@ -422,11 +470,20 @@ pf_osfp_add(struct pf_osfp_ioctl *fpioc) fp->fp_wscale = fpioc->fp_wscale; fp->fp_ttl = fpioc->fp_ttl; SLIST_INIT(&fp->fp_oses); - if ((entry = pool_get(&pf_osfp_entry_pl, PR_NOWAIT)) == NULL) { + if ((entry = pool_get(&pf_osfp_entry_pl, +#ifdef __FreeBSD__ + PR_NOWAIT)) == NULL) { +#else + PR_WAITOK|PR_LIMITFAIL)) == NULL) { +#endif pool_put(&pf_osfp_pl, fp); return (ENOMEM); } +#ifdef __FreeBSD__ + pf_osfp_insert(&V_pf_osfp_list, fp); +#else pf_osfp_insert(&pf_osfp_list, fp); +#endif } memcpy(entry, &fpioc->fp_os, sizeof(*entry)); @@ -452,7 +509,7 @@ pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, { struct pf_os_fingerprint *f; -#define MATCH_INT(_MOD, _DC, _field) \ +#define MATCH_INT(_MOD, _DC, _field) \ if ((f->fp_flags & _DC) == 0) { \ if ((f->fp_flags & _MOD) == 0) { \ if (f->_field != find->_field) \ @@ -480,10 +537,11 @@ pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, if (find->fp_mss == 0) continue; -/* Some "smart" NAT devices and DSL routers will tweak the MSS size and +/* + * Some "smart" NAT devices and DSL routers will tweak the MSS size and * will set it to whatever is suitable for the link type. */ -#define SMART_MSS 1460 +#define SMART_MSS 1460 if ((find->fp_wsize % find->fp_mss || find->fp_wsize / find->fp_mss != f->fp_wsize) && @@ -495,8 +553,8 @@ pf_osfp_find(struct pf_osfp_list *list, struct pf_os_fingerprint *find, if (find->fp_mss == 0) continue; -#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) -#define SMART_MTU (SMART_MSS + MTUOFF) +#define MTUOFF (sizeof(struct ip) + sizeof(struct tcphdr)) +#define SMART_MTU (SMART_MSS + MTUOFF) if ((find->fp_wsize % (find->fp_mss + MTUOFF) || find->fp_wsize / (find->fp_mss + MTUOFF) != f->fp_wsize) && @@ -567,7 +625,11 @@ pf_osfp_get(struct pf_osfp_ioctl *fpioc) memset(fpioc, 0, sizeof(*fpioc)); +#ifdef __FreeBSD__ + SLIST_FOREACH(fp, &V_pf_osfp_list, fp_next) { +#else SLIST_FOREACH(fp, &pf_osfp_list, fp_next) { +#endif SLIST_FOREACH(entry, &fp->fp_oses, fp_entry) { if (i++ == num) { fpioc->fp_mss = fp->fp_mss; @@ -594,7 +656,11 @@ pf_osfp_validate(void) { struct pf_os_fingerprint *f, *f2, find; +#ifdef __FreeBSD__ + SLIST_FOREACH(f, &V_pf_osfp_list, fp_next) { +#else SLIST_FOREACH(f, &pf_osfp_list, fp_next) { +#endif memcpy(&find, f, sizeof(find)); /* We do a few MSS/th_win percolations to make things unique */ @@ -606,7 +672,11 @@ pf_osfp_validate(void) find.fp_wsize *= (find.fp_mss + 40); else if (f->fp_flags & PF_OSFP_WSIZE_MOD) find.fp_wsize *= 2; +#ifdef __FreeBSD__ + if (f != (f2 = pf_osfp_find(&V_pf_osfp_list, &find, 0))) { +#else if (f != (f2 = pf_osfp_find(&pf_osfp_list, &find, 0))) { +#endif if (f2) printf("Found \"%s %s %s\" instead of " "\"%s %s %s\"\n", diff --git a/sys/contrib/pf/net/pf_ruleset.c b/sys/contrib/pf/net/pf_ruleset.c index 7ff6a77..ca8667c 100644 --- a/sys/contrib/pf/net/pf_ruleset.c +++ b/sys/contrib/pf/net/pf_ruleset.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ruleset.c,v 1.1 2006/10/27 13:56:51 mcbride Exp $ */ +/* $OpenBSD: pf_ruleset.c,v 1.2 2008/12/18 15:31:37 dhill Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -61,48 +61,55 @@ __FBSDID("$FreeBSD$"); #ifdef _KERNEL -# define DPFPRINTF(format, x...) \ - if (pf_status.debug >= PF_DEBUG_NOISY) \ +#ifdef __FreeBSD__ +#define DPFPRINTF(format, x...) \ + if (V_pf_status.debug >= PF_DEBUG_NOISY) \ + printf(format , ##x) +#else +#define DPFPRINTF(format, x...) \ + if (pf_status.debug >= PF_DEBUG_NOISY) \ printf(format , ##x) +#endif #ifdef __FreeBSD__ -#define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT) +#define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO) #else -#define rs_malloc(x) malloc(x, M_TEMP, M_WAITOK) +#define rs_malloc(x) malloc(x, M_TEMP, M_WAITOK|M_CANFAIL|M_ZERO) #endif #define rs_free(x) free(x, M_TEMP) #else /* Userland equivalents so we can lend code to pfctl et al. */ -# include <arpa/inet.h> -# include <errno.h> -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# define rs_malloc(x) malloc(x) -# define rs_free(x) free(x) - -# ifdef PFDEBUG -# include <sys/stdarg.h> -# define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) -# else -# define DPFPRINTF(format, x...) ((void)0) -# endif /* PFDEBUG */ +#include <arpa/inet.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define rs_malloc(x) calloc(1, x) +#define rs_free(x) free(x) + +#ifdef PFDEBUG +#include <sys/stdarg.h> +#define DPFPRINTF(format, x...) fprintf(stderr, format , ##x) +#else +#define DPFPRINTF(format, x...) ((void)0) +#endif /* PFDEBUG */ #endif /* _KERNEL */ +#if defined(__FreeBSD__) && !defined(_KERNEL) +#undef V_pf_anchors +#define V_pf_anchors pf_anchors + +#undef pf_main_ruleset +#define pf_main_ruleset pf_main_anchor.ruleset +#endif +#if defined(__FreeBSD__) && defined(_KERNEL) +VNET_DEFINE(struct pf_anchor_global, pf_anchors); +VNET_DEFINE(struct pf_anchor, pf_main_anchor); +#else struct pf_anchor_global pf_anchors; struct pf_anchor pf_main_anchor; - -#ifndef __FreeBSD__ -/* XXX: hum? */ -int pf_get_ruleset_number(u_int8_t); -void pf_init_ruleset(struct pf_ruleset *); -int pf_anchor_setup(struct pf_rule *, - const struct pf_ruleset *, const char *); -int pf_anchor_copyout(const struct pf_ruleset *, - const struct pf_rule *, struct pfioc_rule *); -void pf_anchor_remove(struct pf_rule *); #endif static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *); @@ -168,9 +175,14 @@ pf_find_anchor(const char *path) struct pf_anchor *key, *found; key = (struct pf_anchor *)rs_malloc(sizeof(*key)); - memset(key, 0, sizeof(*key)); + if (key == NULL) + return (NULL); strlcpy(key->path, path, sizeof(key->path)); +#ifdef __FreeBSD__ + found = RB_FIND(pf_anchor_global, &V_pf_anchors, key); +#else found = RB_FIND(pf_anchor_global, &pf_anchors, key); +#endif rs_free(key); return (found); } @@ -210,7 +222,8 @@ pf_find_or_create_ruleset(const char *path) if (ruleset != NULL) return (ruleset); p = (char *)rs_malloc(MAXPATHLEN); - bzero(p, MAXPATHLEN); + if (p == NULL) + return (NULL); strlcpy(p, path, MAXPATHLEN); while (parent == NULL && (q = strrchr(p, '/')) != NULL) { *q = 0; @@ -242,7 +255,6 @@ pf_find_or_create_ruleset(const char *path) rs_free(p); return (NULL); } - memset(anchor, 0, sizeof(*anchor)); RB_INIT(&anchor->children); strlcpy(anchor->name, q, sizeof(anchor->name)); if (parent != NULL) { @@ -251,7 +263,11 @@ pf_find_or_create_ruleset(const char *path) strlcat(anchor->path, "/", sizeof(anchor->path)); } strlcat(anchor->path, anchor->name, sizeof(anchor->path)); +#ifdef __FreeBSD__ + if ((dup = RB_INSERT(pf_anchor_global, &V_pf_anchors, anchor)) != +#else if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) != +#endif NULL) { printf("pf_find_or_create_ruleset: RB_INSERT1 " "'%s' '%s' collides with '%s' '%s'\n", @@ -268,7 +284,11 @@ pf_find_or_create_ruleset(const char *path) "RB_INSERT2 '%s' '%s' collides with " "'%s' '%s'\n", anchor->path, anchor->name, dup->path, dup->name); +#ifdef __FreeBSD__ + RB_REMOVE(pf_anchor_global, &V_pf_anchors, +#else RB_REMOVE(pf_anchor_global, &pf_anchors, +#endif anchor); rs_free(anchor); rs_free(p); @@ -304,7 +324,11 @@ pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset) !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) || ruleset->rules[i].inactive.open) return; +#ifdef __FreeBSD__ + RB_REMOVE(pf_anchor_global, &V_pf_anchors, ruleset->anchor); +#else RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor); +#endif if ((parent = ruleset->anchor->parent) != NULL) RB_REMOVE(pf_anchor_node, &parent->children, ruleset->anchor); @@ -328,7 +352,8 @@ pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s, if (!name[0]) return (0); path = (char *)rs_malloc(MAXPATHLEN); - bzero(path, MAXPATHLEN); + if (path == NULL) + return (1); if (name[0] == '/') strlcpy(path, name + 1, MAXPATHLEN); else { @@ -386,7 +411,8 @@ pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r, int i; a = (char *)rs_malloc(MAXPATHLEN); - bzero(a, MAXPATHLEN); + if (a == NULL) + return (1); if (rs->anchor == NULL) a[0] = 0; else diff --git a/sys/contrib/pf/net/pf_subr.c b/sys/contrib/pf/net/pf_subr.c deleted file mode 100644 index 07f5295..0000000 --- a/sys/contrib/pf/net/pf_subr.c +++ /dev/null @@ -1,168 +0,0 @@ -/*- - * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 - * The 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 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. - * - */ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/kernel.h> -#include <sys/libkern.h> -#include <sys/mbuf.h> -#include <sys/md5.h> -#include <sys/time.h> -#include <sys/random.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/systm.h> -#include <sys/time.h> - -#include <net/if.h> -#include <net/if_types.h> -#include <net/bpf.h> -#include <net/route.h> - -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#include <netinet/tcp_seq.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> -#include <netinet/in_pcb.h> -#include <netinet/tcp_timer.h> -#include <netinet/tcp_var.h> -#include <netinet/if_ether.h> -#include <net/pfvar.h> - -/* - * Following is where TCP initial sequence number generation occurs. - * - * There are two places where we must use initial sequence numbers: - * 1. In SYN-ACK packets. - * 2. In SYN packets. - * - * All ISNs for SYN-ACK packets are generated by the syncache. See - * tcp_syncache.c for details. - * - * The ISNs in SYN packets must be monotonic; TIME_WAIT recycling - * depends on this property. In addition, these ISNs should be - * unguessable so as to prevent connection hijacking. To satisfy - * the requirements of this situation, the algorithm outlined in - * RFC 1948 is used, with only small modifications. - * - * Implementation details: - * - * Time is based off the system timer, and is corrected so that it - * increases by one megabyte per second. This allows for proper - * recycling on high speed LANs while still leaving over an hour - * before rollover. - * - * As reading the *exact* system time is too expensive to be done - * whenever setting up a TCP connection, we increment the time - * offset in two ways. First, a small random positive increment - * is added to isn_offset for each connection that is set up. - * Second, the function tcp_isn_tick fires once per clock tick - * and increments isn_offset as necessary so that sequence numbers - * are incremented at approximately ISN_BYTES_PER_SECOND. The - * random positive increments serve only to ensure that the same - * exact sequence number is never sent out twice (as could otherwise - * happen when a port is recycled in less than the system tick - * interval.) - * - * net.inet.tcp.isn_reseed_interval controls the number of seconds - * between seeding of isn_secret. This is normally set to zero, - * as reseeding should not be necessary. - * - * Locking of the global variables isn_secret, isn_last_reseed, isn_offset, - * isn_offset_old, and isn_ctx is performed using the TCP pcbinfo lock. In - * general, this means holding an exclusive (write) lock. - */ - -#define ISN_BYTES_PER_SECOND 1048576 -#define ISN_STATIC_INCREMENT 4096 -#define ISN_RANDOM_INCREMENT (4096 - 1) - -static u_char pf_isn_secret[32]; -static int pf_isn_last_reseed; -static u_int32_t pf_isn_offset; - -u_int32_t -pf_new_isn(struct pf_state *s) -{ - MD5_CTX isn_ctx; - u_int32_t md5_buffer[4]; - u_int32_t new_isn; - struct pf_state_host *src, *dst; - - /* Seed if this is the first use, reseed if requested. */ - if (pf_isn_last_reseed == 0) { - read_random(&pf_isn_secret, sizeof(pf_isn_secret)); - pf_isn_last_reseed = ticks; - } - - if (s->direction == PF_IN) { - src = &s->ext; - dst = &s->gwy; - } else { - src = &s->lan; - dst = &s->ext; - } - - /* Compute the md5 hash and return the ISN. */ - MD5Init(&isn_ctx); - MD5Update(&isn_ctx, (u_char *) &dst->port, sizeof(u_short)); - MD5Update(&isn_ctx, (u_char *) &src->port, sizeof(u_short)); -#ifdef INET6 - if (s->af == AF_INET6) { - MD5Update(&isn_ctx, (u_char *) &dst->addr, - sizeof(struct in6_addr)); - MD5Update(&isn_ctx, (u_char *) &src->addr, - sizeof(struct in6_addr)); - } else -#endif - { - MD5Update(&isn_ctx, (u_char *) &dst->addr, - sizeof(struct in_addr)); - MD5Update(&isn_ctx, (u_char *) &src->addr, - sizeof(struct in_addr)); - } - MD5Update(&isn_ctx, (u_char *) &pf_isn_secret, sizeof(pf_isn_secret)); - MD5Final((u_char *) &md5_buffer, &isn_ctx); - new_isn = (tcp_seq) md5_buffer[0]; - pf_isn_offset += ISN_STATIC_INCREMENT + - (arc4random() & ISN_RANDOM_INCREMENT); - new_isn += pf_isn_offset; - return (new_isn); -} diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c index 40c9f67..010dc50 100644 --- a/sys/contrib/pf/net/pf_table.c +++ b/sys/contrib/pf/net/pf_table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $ */ +/* $OpenBSD: pf_table.c,v 1.79 2008/10/08 06:24:50 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -43,10 +43,10 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/mbuf.h> #include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/rwlock.h> #ifdef __FreeBSD__ #include <sys/malloc.h> +#else +#include <sys/pool.h> #endif #include <net/if.h> @@ -55,10 +55,9 @@ __FBSDID("$FreeBSD$"); #ifndef __FreeBSD__ #include <netinet/ip_ipsp.h> #endif - #include <net/pfvar.h> -#define ACCEPT_FLAGS(oklist) \ +#define ACCEPT_FLAGS(flags, oklist) \ do { \ if ((flags & ~(oklist)) & \ PFR_FLAG_ALLMASK) \ @@ -90,28 +89,26 @@ _copyout(const void *uaddr, void *kaddr, size_t len) return (r); } -#define COPYIN(from, to, size) \ +#define COPYIN(from, to, size, flags) \ ((flags & PFR_FLAG_USERIOCTL) ? \ _copyin((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) -#define COPYOUT(from, to, size) \ +#define COPYOUT(from, to, size, flags) \ ((flags & PFR_FLAG_USERIOCTL) ? \ _copyout((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) #else - -#define COPYIN(from, to, size) \ +#define COPYIN(from, to, size, flags) \ ((flags & PFR_FLAG_USERIOCTL) ? \ copyin((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) -#define COPYOUT(from, to, size) \ +#define COPYOUT(from, to, size, flags) \ ((flags & PFR_FLAG_USERIOCTL) ? \ copyout((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) - #endif #define FILLIN_SIN(sin, addr) \ @@ -128,26 +125,26 @@ _copyout(const void *uaddr, void *kaddr, size_t len) (sin6).sin6_addr = (addr); \ } while (0) -#define SWAP(type, a1, a2) \ +#define SWAP(type, a1, a2) \ do { \ type tmp = a1; \ a1 = a2; \ a2 = tmp; \ } while (0) -#define SUNION2PF(su, af) (((af)==AF_INET) ? \ +#define SUNION2PF(su, af) (((af)==AF_INET) ? \ (struct pf_addr *)&(su)->sin.sin_addr : \ (struct pf_addr *)&(su)->sin6.sin6_addr) #define AF_BITS(af) (((af)==AF_INET)?32:128) #define ADDR_NETWORK(ad) ((ad)->pfra_net < AF_BITS((ad)->pfra_af)) #define KENTRY_NETWORK(ke) ((ke)->pfrke_net < AF_BITS((ke)->pfrke_af)) -#define KENTRY_RNF_ROOT(ke) \ +#define KENTRY_RNF_ROOT(ke) \ ((((struct radix_node *)(ke))->rn_flags & RNF_ROOT) != 0) -#define NO_ADDRESSES (-1) -#define ENQUEUE_UNMARKED_ONLY (1) -#define INVERT_NEG_FLAG (1) +#define NO_ADDRESSES (-1) +#define ENQUEUE_UNMARKED_ONLY (1) +#define INVERT_NEG_FLAG (1) struct pfr_walktree { enum pfrw_op { @@ -169,28 +166,37 @@ struct pfr_walktree { int pfrw_free; int pfrw_flags; }; -#define pfrw_addr pfrw_1.pfrw1_addr -#define pfrw_astats pfrw_1.pfrw1_astats -#define pfrw_workq pfrw_1.pfrw1_workq -#define pfrw_kentry pfrw_1.pfrw1_kentry -#define pfrw_dyn pfrw_1.pfrw1_dyn -#define pfrw_cnt pfrw_free +#define pfrw_addr pfrw_1.pfrw1_addr +#define pfrw_astats pfrw_1.pfrw1_astats +#define pfrw_workq pfrw_1.pfrw1_workq +#define pfrw_kentry pfrw_1.pfrw1_kentry +#define pfrw_dyn pfrw_1.pfrw1_dyn +#define pfrw_cnt pfrw_free -#define senderr(e) do { rv = (e); goto _bad; } while (0) +#define senderr(e) do { rv = (e); goto _bad; } while (0) #ifdef __FreeBSD__ -uma_zone_t pfr_ktable_pl; -uma_zone_t pfr_kentry_pl; -uma_zone_t pfr_kentry_pl2; +VNET_DEFINE(uma_zone_t, pfr_ktable_pl); +VNET_DEFINE(uma_zone_t, pfr_kentry_pl); +VNET_DEFINE(uma_zone_t, pfr_kcounters_pl); +#define V_pfr_kcounters_pl VNET(pfr_kcounters_pl) +VNET_DEFINE(struct sockaddr_in, pfr_sin); +#define V_pfr_sin VNET(pfr_sin) +VNET_DEFINE(struct sockaddr_in6, pfr_sin6); +#define V_pfr_sin6 VNET(pfr_sin6) +VNET_DEFINE(union sockaddr_union, pfr_mask); +#define V_pfr_mask VNET(pfr_mask) +VNET_DEFINE(struct pf_addr, pfr_ffaddr); +#define V_pfr_ffaddr VNET(pfr_ffaddr) #else struct pool pfr_ktable_pl; struct pool pfr_kentry_pl; -struct pool pfr_kentry_pl2; -#endif +struct pool pfr_kcounters_pl; struct sockaddr_in pfr_sin; struct sockaddr_in6 pfr_sin6; union sockaddr_union pfr_mask; struct pf_addr pfr_ffaddr; +#endif void pfr_copyout_addr(struct pfr_addr *, struct pfr_kentry *ke); @@ -226,7 +232,7 @@ void pfr_setflags_ktable(struct pfr_ktable *, int); void pfr_clstats_ktables(struct pfr_ktableworkq *, long, int); void pfr_clstats_ktable(struct pfr_ktable *, long, int); -struct pfr_ktable *pfr_create_ktable(struct pfr_table *, long, int); +struct pfr_ktable *pfr_create_ktable(struct pfr_table *, long, int, int); void pfr_destroy_ktables(struct pfr_ktableworkq *, int); void pfr_destroy_ktable(struct pfr_ktable *, int); int pfr_ktable_compare(struct pfr_ktable *, @@ -251,12 +257,11 @@ pfr_initialize(void) { #ifndef __FreeBSD__ pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, - "pfrktable", &pool_allocator_oldnointr); + "pfrktable", NULL); pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, - "pfrkentry", &pool_allocator_oldnointr); - pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0, - "pfrkentry2", NULL); -#endif + "pfrkentry", NULL); + pool_init(&pfr_kcounters_pl, sizeof(struct pfr_kcounters), 0, 0, 0, + "pfrkcounters", NULL); pfr_sin.sin_len = sizeof(pfr_sin); pfr_sin.sin_family = AF_INET; @@ -264,6 +269,14 @@ pfr_initialize(void) pfr_sin6.sin6_family = AF_INET6; memset(&pfr_ffaddr, 0xff, sizeof(pfr_ffaddr)); +#else + V_pfr_sin.sin_len = sizeof(V_pfr_sin); + V_pfr_sin.sin_family = AF_INET; + V_pfr_sin6.sin6_len = sizeof(V_pfr_sin6); + V_pfr_sin6.sin6_family = AF_INET6; + + memset(&V_pfr_ffaddr, 0xff, sizeof(V_pfr_ffaddr)); +#endif } int @@ -273,7 +286,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) struct pfr_kentryworkq workq; int s; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -284,7 +297,6 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) pfr_enqueue_addrs(kt, &workq, ndel, 0); if (!(flags & PFR_FLAG_DUMMY)) { - s = 0; if (flags & PFR_FLAG_ATOMIC) s = splsoftnet(); pfr_remove_kentries(kt, &workq); @@ -307,10 +319,11 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s = 0, xadd = 0; + int i, rv, s, xadd = 0; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -318,12 +331,13 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ESRCH); if (kt->pfrkt_flags & PFR_TFLAG_CONST) return (EPERM); - tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); + tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0, + !(flags & PFR_FLAG_USERIOCTL)); if (tmpkt == NULL) return (ENOMEM); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) senderr(EFAULT); if (pfr_validate_addr(&ad)) senderr(EINVAL); @@ -340,7 +354,8 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, ad.pfra_fback = PFR_FB_NONE; } if (p == NULL && q == NULL) { - p = pfr_create_kentry(&ad, 0); + p = pfr_create_kentry(&ad, + !(flags & PFR_FLAG_USERIOCTL)); if (p == NULL) senderr(ENOMEM); if (pfr_route_kentry(tmpkt, p)) { @@ -351,10 +366,9 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, xadd++; } } - if (flags & PFR_FLAG_FEEDBACK) { - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (flags & PFR_FLAG_FEEDBACK) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) senderr(EFAULT); - } } pfr_clean_node_mask(tmpkt, &workq); if (!(flags & PFR_FLAG_DUMMY)) { @@ -386,9 +400,10 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s = 0, xdel = 0, log = 1; + int i, rv, s, xdel = 0, log = 1; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -415,7 +430,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, } else { /* iterate over addresses to delete */ for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) return (EFAULT); if (pfr_validate_addr(&ad)) return (EINVAL); @@ -426,7 +441,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, } SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) senderr(EFAULT); if (pfr_validate_addr(&ad)) senderr(EINVAL); @@ -448,7 +463,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, xdel++; } if (flags & PFR_FLAG_FEEDBACK) - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) senderr(EFAULT); } if (!(flags & PFR_FLAG_DUMMY)) { @@ -476,10 +491,11 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq addq, delq, changeq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0; + int i, rv, s, xadd = 0, xdel = 0, xchange = 0; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); @@ -488,7 +504,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ESRCH); if (kt->pfrkt_flags & PFR_TFLAG_CONST) return (EPERM); - tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0); + tmpkt = pfr_create_ktable(&pfr_nulltable, 0, 0, + !(flags & PFR_FLAG_USERIOCTL)); if (tmpkt == NULL) return (ENOMEM); pfr_mark_addrs(kt); @@ -496,7 +513,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, SLIST_INIT(&delq); SLIST_INIT(&changeq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) senderr(EFAULT); if (pfr_validate_addr(&ad)) senderr(EINVAL); @@ -519,7 +536,8 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, ad.pfra_fback = PFR_FB_DUPLICATE; goto _skip; } - p = pfr_create_kentry(&ad, 0); + p = pfr_create_kentry(&ad, + !(flags & PFR_FLAG_USERIOCTL)); if (p == NULL) senderr(ENOMEM); if (pfr_route_kentry(tmpkt, p)) { @@ -533,7 +551,7 @@ pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, } _skip: if (flags & PFR_FLAG_FEEDBACK) - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) senderr(EFAULT); } pfr_enqueue_addrs(kt, &delq, &xdel, ENQUEUE_UNMARKED_ONLY); @@ -546,7 +564,7 @@ _skip: SLIST_FOREACH(p, &delq, pfrke_workq) { pfr_copyout_addr(&ad, p); ad.pfra_fback = PFR_FB_DELETED; - if (COPYOUT(&ad, addr+size+i, sizeof(ad))) + if (COPYOUT(&ad, addr+size+i, sizeof(ad), flags)) senderr(EFAULT); i++; } @@ -590,7 +608,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_addr ad; int i, xmatch = 0; - ACCEPT_FLAGS(PFR_FLAG_REPLACE); + ACCEPT_FLAGS(flags, PFR_FLAG_REPLACE); if (pfr_validate_table(tbl, 0, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -598,7 +616,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ESRCH); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) return (EFAULT); if (pfr_validate_addr(&ad)) return (EINVAL); @@ -611,7 +629,7 @@ pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, (p->pfrke_not ? PFR_FB_NOTMATCH : PFR_FB_MATCH); if (p != NULL && !p->pfrke_not) xmatch++; - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) return (EFAULT); } if (nmatch != NULL) @@ -627,7 +645,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, struct pfr_walktree w; int rv; - ACCEPT_FLAGS(0); + ACCEPT_FLAGS(flags, 0); if (pfr_validate_table(tbl, 0, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -650,7 +668,7 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, #endif if (!rv) #ifdef __FreeBSD__ - rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); #else rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); @@ -674,10 +692,11 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, struct pfr_ktable *kt; struct pfr_walktree w; struct pfr_kentryworkq workq; - int rv, s = 0; + int rv, s; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ + /* XXX PFR_FLAG_CLSTATS disabled */ + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC); if (pfr_validate_table(tbl, 0, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -733,9 +752,10 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s = 0, xzero = 0; + int i, rv, s, xzero = 0; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, 0)) return (EINVAL); kt = pfr_lookup_table(tbl); @@ -743,7 +763,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, return (ESRCH); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) senderr(EFAULT); if (pfr_validate_addr(&ad)) senderr(EINVAL); @@ -751,7 +771,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, if (flags & PFR_FLAG_FEEDBACK) { ad.pfra_fback = (p != NULL) ? PFR_FB_CLEARED : PFR_FB_NONE; - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) senderr(EFAULT); } if (p != NULL) { @@ -866,7 +886,11 @@ struct pfr_kentry * pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) { union sockaddr_union sa, mask; - struct radix_node_head *head = NULL; /* make the compiler happy */ +#ifdef __FreeBSD__ + struct radix_node_head *head = NULL; +#else + struct radix_node_head *head; +#endif struct pfr_kentry *ke; int s; @@ -904,12 +928,19 @@ pfr_create_kentry(struct pfr_addr *ad, int intr) struct pfr_kentry *ke; if (intr) - ke = pool_get(&pfr_kentry_pl2, PR_NOWAIT); +#ifdef __FreeBSD__ + ke = pool_get(&V_pfr_kentry_pl, PR_NOWAIT | PR_ZERO); +#else + ke = pool_get(&pfr_kentry_pl, PR_NOWAIT | PR_ZERO); +#endif else - ke = pool_get(&pfr_kentry_pl, PR_NOWAIT); +#ifdef __FreeBSD__ + ke = pool_get(&V_pfr_kentry_pl, PR_WAITOK|PR_ZERO); +#else + ke = pool_get(&pfr_kentry_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL); +#endif if (ke == NULL) return (NULL); - bzero(ke, sizeof(*ke)); if (ad->pfra_af == AF_INET) FILLIN_SIN(ke->pfrke_sa.sin, ad->pfra_ip4addr); @@ -918,7 +949,6 @@ pfr_create_kentry(struct pfr_addr *ad, int intr) ke->pfrke_af = ad->pfra_af; ke->pfrke_net = ad->pfra_net; ke->pfrke_not = ad->pfra_not; - ke->pfrke_intrpool = intr; return (ke); } @@ -936,10 +966,14 @@ pfr_destroy_kentries(struct pfr_kentryworkq *workq) void pfr_destroy_kentry(struct pfr_kentry *ke) { - if (ke->pfrke_intrpool) - pool_put(&pfr_kentry_pl2, ke); - else - pool_put(&pfr_kentry_pl, ke); + if (ke->pfrke_counters) +#ifdef __FreeBSD__ + pool_put(&V_pfr_kcounters_pl, ke->pfrke_counters); + pool_put(&V_pfr_kentry_pl, ke); +#else + pool_put(&pfr_kcounters_pl, ke->pfrke_counters); + pool_put(&pfr_kentry_pl, ke); +#endif } void @@ -1020,8 +1054,14 @@ pfr_clstats_kentries(struct pfr_kentryworkq *workq, long tzero, int negchange) s = splsoftnet(); if (negchange) p->pfrke_not = !p->pfrke_not; - bzero(p->pfrke_packets, sizeof(p->pfrke_packets)); - bzero(p->pfrke_bytes, sizeof(p->pfrke_bytes)); + if (p->pfrke_counters) { +#ifdef __FreeBSD__ + pool_put(&V_pfr_kcounters_pl, p->pfrke_counters); +#else + pool_put(&pfr_kcounters_pl, p->pfrke_counters); +#endif + p->pfrke_counters = NULL; + } splx(s); p->pfrke_tzero = tzero; } @@ -1034,10 +1074,10 @@ pfr_reset_feedback(struct pfr_addr *addr, int size, int flags) int i; for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) break; ad.pfra_fback = PFR_FB_NONE; - if (COPYOUT(&ad, addr+i, sizeof(ad))) + if (COPYOUT(&ad, addr+i, sizeof(ad), flags)) break; } } @@ -1072,7 +1112,11 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head = NULL; /* make the compiler happy */ +#ifdef __FreeBSD__ + struct radix_node_head *head = NULL; +#else + struct radix_node_head *head; +#endif int s; bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); @@ -1087,9 +1131,17 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) #endif if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); +#ifdef __FreeBSD__ rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); +#else + rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node, 0); +#endif } else +#ifdef __FreeBSD__ rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); +#else + rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node, 0); +#endif splx(s); return (rn == NULL ? -1 : 0); @@ -1100,7 +1152,11 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head = NULL; /* make the compiler happy */ +#ifdef __FreeBSD__ + struct radix_node_head *head = NULL; +#else + struct radix_node_head *head; +#endif int s; if (ke->pfrke_af == AF_INET) @@ -1173,7 +1229,7 @@ pfr_walktree(struct radix_node *rn, void *arg) struct pfr_addr ad; pfr_copyout_addr(&ad, ke); - if (COPYOUT(&ad, w->pfrw_addr, sizeof(ad))) + if (copyout(&ad, w->pfrw_addr, sizeof(ad))) return (EFAULT); w->pfrw_addr++; } @@ -1185,14 +1241,20 @@ pfr_walktree(struct radix_node *rn, void *arg) pfr_copyout_addr(&as.pfras_a, ke); s = splsoftnet(); - bcopy(ke->pfrke_packets, as.pfras_packets, - sizeof(as.pfras_packets)); - bcopy(ke->pfrke_bytes, as.pfras_bytes, - sizeof(as.pfras_bytes)); + if (ke->pfrke_counters) { + bcopy(ke->pfrke_counters->pfrkc_packets, + as.pfras_packets, sizeof(as.pfras_packets)); + bcopy(ke->pfrke_counters->pfrkc_bytes, + as.pfras_bytes, sizeof(as.pfras_bytes)); + } else { + bzero(as.pfras_packets, sizeof(as.pfras_packets)); + bzero(as.pfras_bytes, sizeof(as.pfras_bytes)); + as.pfras_a.pfra_fback = PFR_FB_NOCOUNT; + } splx(s); as.pfras_tzero = ke->pfrke_tzero; - if (COPYOUT(&as, w->pfrw_astats, sizeof(as))) + if (COPYOUT(&as, w->pfrw_astats, sizeof(as), flags)) return (EFAULT); w->pfrw_astats++; } @@ -1209,19 +1271,35 @@ pfr_walktree(struct radix_node *rn, void *arg) if (ke->pfrke_af == AF_INET) { if (w->pfrw_dyn->pfid_acnt4++ > 0) break; +#ifdef __FreeBSD__ + pfr_prepare_network(&V_pfr_mask, AF_INET, ke->pfrke_net); +#else pfr_prepare_network(&pfr_mask, AF_INET, ke->pfrke_net); +#endif w->pfrw_dyn->pfid_addr4 = *SUNION2PF( &ke->pfrke_sa, AF_INET); w->pfrw_dyn->pfid_mask4 = *SUNION2PF( +#ifdef __FreeBSD__ + &V_pfr_mask, AF_INET); +#else &pfr_mask, AF_INET); +#endif } else if (ke->pfrke_af == AF_INET6){ if (w->pfrw_dyn->pfid_acnt6++ > 0) break; +#ifdef __FreeBSD__ + pfr_prepare_network(&V_pfr_mask, AF_INET6, ke->pfrke_net); +#else pfr_prepare_network(&pfr_mask, AF_INET6, ke->pfrke_net); +#endif w->pfrw_dyn->pfid_addr6 = *SUNION2PF( &ke->pfrke_sa, AF_INET6); w->pfrw_dyn->pfid_mask6 = *SUNION2PF( +#ifdef __FreeBSD__ + &V_pfr_mask, AF_INET6); +#else &pfr_mask, AF_INET6); +#endif } break; } @@ -1233,9 +1311,10 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p; - int s = 0, xdel = 0; + int s, xdel = 0; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_ALLRSETS); if (pfr_fix_anchor(filter->pfrt_anchor)) return (EINVAL); if (pfr_table_count(filter, flags) < 0) @@ -1270,14 +1349,14 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) { struct pfr_ktableworkq addq, changeq; struct pfr_ktable *p, *q, *r, key; - int i, rv, s = 0, xadd = 0; + int i, rv, s, xadd = 0; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); SLIST_INIT(&addq); SLIST_INIT(&changeq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) + if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) senderr(EFAULT); if (pfr_validate_table(&key.pfrkt_t, PFR_TFLAG_USRMASK, flags & PFR_FLAG_USERIOCTL)) @@ -1285,7 +1364,8 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) key.pfrkt_flags |= PFR_TFLAG_ACTIVE; p = RB_FIND(pfr_ktablehead, &pfr_ktables, &key); if (p == NULL) { - p = pfr_create_ktable(&key.pfrkt_t, tzero, 1); + p = pfr_create_ktable(&key.pfrkt_t, tzero, 1, + !(flags & PFR_FLAG_USERIOCTL)); if (p == NULL) senderr(ENOMEM); SLIST_FOREACH(q, &addq, pfrkt_workq) { @@ -1311,7 +1391,8 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) } } key.pfrkt_flags = 0; - r = pfr_create_ktable(&key.pfrkt_t, 0, 1); + r = pfr_create_ktable(&key.pfrkt_t, 0, 1, + !(flags & PFR_FLAG_USERIOCTL)); if (r == NULL) senderr(ENOMEM); SLIST_INSERT_HEAD(&addq, r, pfrkt_workq); @@ -1350,12 +1431,12 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s = 0, xdel = 0; + int i, s, xdel = 0; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) + if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) return (EFAULT); if (pfr_validate_table(&key.pfrkt_t, 0, flags & PFR_FLAG_USERIOCTL)) @@ -1392,7 +1473,7 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, struct pfr_ktable *p; int n, nn; - ACCEPT_FLAGS(PFR_FLAG_ALLRSETS); + ACCEPT_FLAGS(flags, PFR_FLAG_ALLRSETS); if (pfr_fix_anchor(filter->pfrt_anchor)) return (EINVAL); n = nn = pfr_table_count(filter, flags); @@ -1407,7 +1488,7 @@ pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, continue; if (n-- <= 0) continue; - if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl))) + if (COPYOUT(&p->pfrkt_t, tbl++, sizeof(*tbl), flags)) return (EFAULT); } if (n) { @@ -1424,11 +1505,11 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, { struct pfr_ktable *p; struct pfr_ktableworkq workq; - int s = 0, n, nn; + int s, n, nn; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); - /* XXX PFR_FLAG_CLSTATS disabled */ + /* XXX PFR_FLAG_CLSTATS disabled */ + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_ALLRSETS); if (pfr_fix_anchor(filter->pfrt_anchor)) return (EINVAL); n = nn = pfr_table_count(filter, flags); @@ -1448,9 +1529,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, continue; if (!(flags & PFR_FLAG_ATOMIC)) s = splsoftnet(); - if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { - if (!(flags & PFR_FLAG_ATOMIC)) - splx(s); + if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl), flags)) { + splx(s); return (EFAULT); } if (!(flags & PFR_FLAG_ATOMIC)) @@ -1475,13 +1555,14 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, key; - int i, s = 0, xzero = 0; + int i, s, xzero = 0; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY | + PFR_FLAG_ADDRSTOO); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) + if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) return (EFAULT); if (pfr_validate_table(&key.pfrkt_t, 0, 0)) return (EINVAL); @@ -1509,16 +1590,16 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s = 0, xchange = 0, xdel = 0; + int i, s, xchange = 0, xdel = 0; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); if ((setflag & ~PFR_TFLAG_USRMASK) || (clrflag & ~PFR_TFLAG_USRMASK) || (setflag & clrflag)) return (EINVAL); SLIST_INIT(&workq); for (i = 0; i < size; i++) { - if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t))) + if (COPYIN(tbl+i, &key.pfrkt_t, sizeof(key.pfrkt_t), flags)) return (EFAULT); if (pfr_validate_table(&key.pfrkt_t, 0, flags & PFR_FLAG_USERIOCTL)) @@ -1565,7 +1646,7 @@ pfr_ina_begin(struct pfr_table *trs, u_int32_t *ticket, int *ndel, int flags) struct pf_ruleset *rs; int xdel = 0; - ACCEPT_FLAGS(PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); rs = pf_find_or_create_ruleset(trs->pfrt_anchor); if (rs == NULL) return (ENOMEM); @@ -1602,7 +1683,7 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pf_ruleset *rs; int i, rv, xadd = 0, xaddr = 0; - ACCEPT_FLAGS(PFR_FLAG_DUMMY|PFR_FLAG_ADDRSTOO); + ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY | PFR_FLAG_ADDRSTOO); if (size && !(flags & PFR_FLAG_ADDRSTOO)) return (EINVAL); if (pfr_validate_table(tbl, PFR_TFLAG_USRMASK, @@ -1615,7 +1696,8 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, SLIST_INIT(&tableq); kt = RB_FIND(pfr_ktablehead, &pfr_ktables, (struct pfr_ktable *)tbl); if (kt == NULL) { - kt = pfr_create_ktable(tbl, 0, 1); + kt = pfr_create_ktable(tbl, 0, 1, + !(flags & PFR_FLAG_USERIOCTL)); if (kt == NULL) return (ENOMEM); SLIST_INSERT_HEAD(&tableq, kt, pfrkt_workq); @@ -1631,7 +1713,8 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, kt->pfrkt_root = rt; goto _skip; } - rt = pfr_create_ktable(&key.pfrkt_t, 0, 1); + rt = pfr_create_ktable(&key.pfrkt_t, 0, 1, + !(flags & PFR_FLAG_USERIOCTL)); if (rt == NULL) { pfr_destroy_ktables(&tableq, 0); return (ENOMEM); @@ -1641,14 +1724,14 @@ pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, } else if (!(kt->pfrkt_flags & PFR_TFLAG_INACTIVE)) xadd++; _skip: - shadow = pfr_create_ktable(tbl, 0, 0); + shadow = pfr_create_ktable(tbl, 0, 0, !(flags & PFR_FLAG_USERIOCTL)); if (shadow == NULL) { pfr_destroy_ktables(&tableq, 0); return (ENOMEM); } SLIST_INIT(&addrq); for (i = 0; i < size; i++) { - if (COPYIN(addr+i, &ad, sizeof(ad))) + if (COPYIN(addr+i, &ad, sizeof(ad), flags)) senderr(EFAULT); if (pfr_validate_addr(&ad)) senderr(EINVAL); @@ -1698,7 +1781,7 @@ pfr_ina_rollback(struct pfr_table *trs, u_int32_t ticket, int *ndel, int flags) struct pf_ruleset *rs; int xdel = 0; - ACCEPT_FLAGS(PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_DUMMY); rs = pf_find_ruleset(trs->pfrt_anchor); if (rs == NULL || !rs->topen || ticket != rs->tticket) return (0); @@ -1728,10 +1811,10 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, struct pfr_ktable *p, *q; struct pfr_ktableworkq workq; struct pf_ruleset *rs; - int s = 0, xadd = 0, xchange = 0; + int s, xadd = 0, xchange = 0; long tzero = time_second; - ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); + ACCEPT_FLAGS(flags, PFR_FLAG_ATOMIC | PFR_FLAG_DUMMY); rs = pf_find_ruleset(trs->pfrt_anchor); if (rs == NULL || !rs->topen || ticket != rs->tticket) return (EBUSY); @@ -1992,15 +2075,26 @@ pfr_clstats_ktable(struct pfr_ktable *kt, long tzero, int recurse) } struct pfr_ktable * -pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset) +pfr_create_ktable(struct pfr_table *tbl, long tzero, int attachruleset, + int intr) { struct pfr_ktable *kt; struct pf_ruleset *rs; - kt = pool_get(&pfr_ktable_pl, PR_NOWAIT); + if (intr) +#ifdef __FreeBSD__ + kt = pool_get(&V_pfr_ktable_pl, PR_NOWAIT|PR_ZERO); +#else + kt = pool_get(&pfr_ktable_pl, PR_NOWAIT|PR_ZERO|PR_LIMITFAIL); +#endif + else +#ifdef __FreeBSD__ + kt = pool_get(&V_pfr_ktable_pl, PR_WAITOK|PR_ZERO); +#else + kt = pool_get(&pfr_ktable_pl, PR_WAITOK|PR_ZERO|PR_LIMITFAIL); +#endif if (kt == NULL) return (NULL); - bzero(kt, sizeof(*kt)); kt->pfrkt_t = *tbl; if (attachruleset) { @@ -2067,7 +2161,11 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) kt->pfrkt_rs->tables--; pf_remove_if_empty_ruleset(kt->pfrkt_rs); } +#ifdef __FreeBSD__ + pool_put(&V_pfr_ktable_pl, kt); +#else pool_put(&pfr_ktable_pl, kt); +#endif } int @@ -2102,16 +2200,26 @@ pfr_match_addr(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af) switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + V_pfr_sin.sin_addr.s_addr = a->addr32[0]; + ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4); +#else pfr_sin.sin_addr.s_addr = a->addr32[0]; ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); +#endif if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr)); + ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6); +#else bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); +#endif if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -2139,16 +2247,26 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + V_pfr_sin.sin_addr.s_addr = a->addr32[0]; + ke = (struct pfr_kentry *)rn_match(&V_pfr_sin, kt->pfrkt_ip4); +#else pfr_sin.sin_addr.s_addr = a->addr32[0]; ke = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); +#endif if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + bcopy(a, &V_pfr_sin6.sin6_addr, sizeof(V_pfr_sin6.sin6_addr)); + ke = (struct pfr_kentry *)rn_match(&V_pfr_sin6, kt->pfrkt_ip6); +#else bcopy(a, &pfr_sin6.sin6_addr, sizeof(pfr_sin6.sin6_addr)); ke = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); +#endif if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; break; @@ -2163,14 +2281,24 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af, } kt->pfrkt_packets[dir_out][op_pass]++; kt->pfrkt_bytes[dir_out][op_pass] += len; - if (ke != NULL && op_pass != PFR_OP_XPASS) { - ke->pfrke_packets[dir_out][op_pass]++; - ke->pfrke_bytes[dir_out][op_pass] += len; + if (ke != NULL && op_pass != PFR_OP_XPASS && + (kt->pfrkt_flags & PFR_TFLAG_COUNTERS)) { + if (ke->pfrke_counters == NULL) +#ifdef __FreeBSD__ + ke->pfrke_counters = pool_get(&V_pfr_kcounters_pl, +#else + ke->pfrke_counters = pool_get(&pfr_kcounters_pl, +#endif + PR_NOWAIT | PR_ZERO); + if (ke->pfrke_counters != NULL) { + ke->pfrke_counters->pfrkc_packets[dir_out][op_pass]++; + ke->pfrke_counters->pfrkc_bytes[dir_out][op_pass] += len; + } } } struct pfr_ktable * -pfr_attach_table(struct pf_ruleset *rs, char *name) +pfr_attach_table(struct pf_ruleset *rs, char *name, int intr) { struct pfr_ktable *kt, *rt; struct pfr_table tbl; @@ -2182,14 +2310,14 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); kt = pfr_lookup_table(&tbl); if (kt == NULL) { - kt = pfr_create_ktable(&tbl, time_second, 1); + kt = pfr_create_ktable(&tbl, time_second, 1, intr); if (kt == NULL) return (NULL); if (ac != NULL) { bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor)); rt = pfr_lookup_table(&tbl); if (rt == NULL) { - rt = pfr_create_ktable(&tbl, 0, 1); + rt = pfr_create_ktable(&tbl, 0, 1, intr); if (rt == NULL) { pfr_destroy_ktable(kt, 0); return (NULL); @@ -2215,20 +2343,31 @@ pfr_detach_table(struct pfr_ktable *kt) pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); } - int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) { +#ifdef __FreeBSD__ struct pfr_kentry *ke, *ke2 = NULL; struct pf_addr *addr = NULL; +#else + struct pfr_kentry *ke, *ke2; + struct pf_addr *addr; +#endif union sockaddr_union mask; int idx = -1, use_counter = 0; +#ifdef __FreeBSD__ + if (af == AF_INET) + addr = (struct pf_addr *)&V_pfr_sin.sin_addr; + else if (af == AF_INET6) + addr = (struct pf_addr *)&V_pfr_sin6.sin6_addr; +#else if (af == AF_INET) addr = (struct pf_addr *)&pfr_sin.sin_addr; else if (af == AF_INET6) addr = (struct pf_addr *)&pfr_sin6.sin6_addr; +#endif if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL) kt = kt->pfrkt_root; if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -2243,11 +2382,21 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, _next_block: ke = pfr_kentry_byidx(kt, idx, af); - if (ke == NULL) + if (ke == NULL) { + kt->pfrkt_nomatch++; return (1); + } +#ifdef __FreeBSD__ + pfr_prepare_network(&V_pfr_mask, af, ke->pfrke_net); +#else pfr_prepare_network(&pfr_mask, af, ke->pfrke_net); +#endif *raddr = SUNION2PF(&ke->pfrke_sa, af); +#ifdef __FreeBSD__ + *rmask = SUNION2PF(&V_pfr_mask, af); +#else *rmask = SUNION2PF(&pfr_mask, af); +#endif if (use_counter) { /* is supplied address within block? */ @@ -2267,27 +2416,42 @@ _next_block: /* this is a single IP address - no possible nested block */ PF_ACPY(counter, addr, af); *pidx = idx; + kt->pfrkt_match++; return (0); } for (;;) { /* we don't want to use a nested block */ +#ifdef __FreeBSD__ + if (af == AF_INET) + ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin, + kt->pfrkt_ip4); + else if (af == AF_INET6) + ke2 = (struct pfr_kentry *)rn_match(&V_pfr_sin6, + kt->pfrkt_ip6); +#else if (af == AF_INET) ke2 = (struct pfr_kentry *)rn_match(&pfr_sin, kt->pfrkt_ip4); else if (af == AF_INET6) ke2 = (struct pfr_kentry *)rn_match(&pfr_sin6, kt->pfrkt_ip6); +#endif /* no need to check KENTRY_RNF_ROOT() here */ if (ke2 == ke) { /* lookup return the same block - perfect */ PF_ACPY(counter, addr, af); *pidx = idx; + kt->pfrkt_match++; return (0); } /* we need to increase the counter past the nested block */ pfr_prepare_network(&mask, AF_INET, ke2->pfrke_net); +#ifdef __FreeBSD__ + PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &V_pfr_ffaddr, af); +#else PF_POOLMASK(addr, addr, SUNION2PF(&mask, af), &pfr_ffaddr, af); +#endif PF_AINC(addr, af); if (!PF_MATCHA(0, *raddr, *rmask, addr, af)) { /* ok, we reached the end of our main block */ diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h index de175b1..2aa4bbf 100644 --- a/sys/contrib/pf/net/pfvar.h +++ b/sys/contrib/pf/net/pfvar.h @@ -1,5 +1,4 @@ -/* $FreeBSD$ */ -/* $OpenBSD: pfvar.h,v 1.244 2007/02/23 21:31:51 deraadt Exp $ */ +/* $OpenBSD: pfvar.h,v 1.282 2009/01/29 15:12:28 pyr Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -78,9 +77,8 @@ struct inpcb; #endif enum { PF_INOUT, PF_IN, PF_OUT }; -enum { PF_LAN_EXT, PF_EXT_GWY, PF_ID }; enum { PF_PASS, PF_DROP, PF_SCRUB, PF_NOSCRUB, PF_NAT, PF_NONAT, - PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP }; + PF_BINAT, PF_NOBINAT, PF_RDR, PF_NORDR, PF_SYNPROXY_DROP, PF_DEFER }; enum { PF_RULESET_SCRUB, PF_RULESET_FILTER, PF_RULESET_NAT, PF_RULESET_BINAT, PF_RULESET_RDR, PF_RULESET_MAX }; enum { PF_OP_NONE, PF_OP_IRG, PF_OP_EQ, PF_OP_NE, PF_OP_LT, @@ -90,6 +88,7 @@ enum { PF_CHANGE_NONE, PF_CHANGE_ADD_HEAD, PF_CHANGE_ADD_TAIL, PF_CHANGE_ADD_BEFORE, PF_CHANGE_ADD_AFTER, PF_CHANGE_REMOVE, PF_CHANGE_GET_TICKET }; enum { PF_GET_NONE, PF_GET_CLR_CNTR }; +enum { PF_SK_WIRE, PF_SK_STACK, PF_SK_BOTH }; /* * Note about PFTM_*: real indices into pf_rule.timeout[] come before @@ -132,7 +131,8 @@ enum { PF_LIMIT_STATES, PF_LIMIT_SRC_NODES, PF_LIMIT_FRAGS, enum { PF_POOL_NONE, PF_POOL_BITMASK, PF_POOL_RANDOM, PF_POOL_SRCHASH, PF_POOL_ROUNDROBIN }; enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL, - PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED }; + PF_ADDR_TABLE, PF_ADDR_RTLABEL, PF_ADDR_URPFFAILED, + PF_ADDR_RANGE }; #define PF_POOL_TYPEMASK 0x0f #define PF_POOL_STICKYADDR 0x20 #define PF_WSCALE_FLAG 0x80 @@ -212,87 +212,106 @@ struct pfi_dynaddr { */ #ifdef __FreeBSD__ -#define splsoftnet() splnet() +#define splsoftnet() splnet() #define HTONL(x) (x) = htonl((__uint32_t)(x)) #define HTONS(x) (x) = htons((__uint16_t)(x)) #define NTOHL(x) (x) = ntohl((__uint32_t)(x)) #define NTOHS(x) (x) = ntohs((__uint16_t)(x)) -#define PF_NAME "pf" +#define PF_NAME "pf" -#define PR_NOWAIT M_NOWAIT -#define pool_get(p, f) uma_zalloc(*(p), (f)) -#define pool_put(p, o) uma_zfree(*(p), (o)) +#define PR_NOWAIT M_NOWAIT +#define PR_WAITOK M_WAIT +#define PR_ZERO M_ZERO +#define pool_get(p, f) uma_zalloc(*(p), (f)) +#define pool_put(p, o) uma_zfree(*(p), (o)) -#define UMA_CREATE(var, type, desc) \ - var = uma_zcreate(desc, sizeof(type), \ - NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); \ - if (var == NULL) break -#define UMA_DESTROY(var) \ - if(var) uma_zdestroy(var) +#define UMA_CREATE(var, type, desc) \ + var = uma_zcreate(desc, sizeof(type), \ + NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); \ + if (var == NULL) \ + break +#define UMA_DESTROY(var) \ + if (var) \ + uma_zdestroy(var) +#ifdef __FreeBSD__ +VNET_DECLARE(struct mtx, pf_task_mtx); +#define V_pf_task_mtx VNET(pf_task_mtx) + +#define PF_ASSERT(h) mtx_assert(&V_pf_task_mtx, (h)) + +#define PF_LOCK() do { \ + PF_ASSERT(MA_NOTOWNED); \ + mtx_lock(&V_pf_task_mtx); \ +} while(0) +#define PF_UNLOCK() do { \ + PF_ASSERT(MA_OWNED); \ + mtx_unlock(&V_pf_task_mtx); \ +} while(0) +#else extern struct mtx pf_task_mtx; -#define PF_ASSERT(h) mtx_assert(&pf_task_mtx, (h)) +#define PF_ASSERT(h) mtx_assert(&pf_task_mtx, (h)) -#define PF_LOCK() do { \ - PF_ASSERT(MA_NOTOWNED); \ - mtx_lock(&pf_task_mtx); \ +#define PF_LOCK() do { \ + PF_ASSERT(MA_NOTOWNED); \ + mtx_lock(&pf_task_mtx); \ } while(0) -#define PF_UNLOCK() do { \ - PF_ASSERT(MA_OWNED); \ - mtx_unlock(&pf_task_mtx); \ +#define PF_UNLOCK() do { \ + PF_ASSERT(MA_OWNED); \ + mtx_unlock(&pf_task_mtx); \ } while(0) +#endif -#define PF_COPYIN(uaddr, kaddr, len, r) do { \ - PF_UNLOCK(); \ - r = copyin((uaddr), (kaddr), (len)); \ - PF_LOCK(); \ +#define PF_COPYIN(uaddr, kaddr, len, r) do { \ + PF_UNLOCK(); \ + r = copyin((uaddr), (kaddr), (len)); \ + PF_LOCK(); \ } while(0) -#define PF_COPYOUT(kaddr, uaddr, len, r) do { \ - PF_UNLOCK(); \ - r = copyout((kaddr), (uaddr), (len)); \ - PF_LOCK(); \ +#define PF_COPYOUT(kaddr, uaddr, len, r) do { \ + PF_UNLOCK(); \ + r = copyout((kaddr), (uaddr), (len)); \ + PF_LOCK(); \ } while(0) extern void init_pf_mutex(void); extern void destroy_pf_mutex(void); -#define PF_MODVER 1 -#define PFLOG_MODVER 1 -#define PFSYNC_MODVER 1 - -#define PFLOG_MINVER 1 -#define PFLOG_PREFVER PFLOG_MODVER -#define PFLOG_MAXVER 1 -#define PFSYNC_MINVER 1 -#define PFSYNC_PREFVER PFSYNC_MODVER -#define PFSYNC_MAXVER 1 -#endif /* __FreeBSD__ */ - +#define PF_MODVER 1 +#define PFLOG_MODVER 1 +#define PFSYNC_MODVER 1 + +#define PFLOG_MINVER 1 +#define PFLOG_PREFVER PFLOG_MODVER +#define PFLOG_MAXVER 1 +#define PFSYNC_MINVER 1 +#define PFSYNC_PREFVER PFSYNC_MODVER +#define PFSYNC_MAXVER 1 +#endif /* __FreeBSD__ */ #ifdef INET #ifndef INET6 -#define PF_INET_ONLY +#define PF_INET_ONLY #endif /* ! INET6 */ #endif /* INET */ #ifdef INET6 #ifndef INET -#define PF_INET6_ONLY +#define PF_INET6_ONLY #endif /* ! INET */ #endif /* INET6 */ #ifdef INET #ifdef INET6 -#define PF_INET_INET6 +#define PF_INET_INET6 #endif /* INET6 */ #endif /* INET */ #else -#define PF_INET_INET6 +#define PF_INET_INET6 #endif /* _KERNEL */ @@ -412,7 +431,10 @@ extern void destroy_pf_mutex(void); ((aw)->type == PF_ADDR_TABLE && \ !pfr_match_addr((aw)->p.tbl, (x), (af))) || \ ((aw)->type == PF_ADDR_DYNIFTL && \ - !pfi_match_addr((aw)->p.dyn, (x), (af))) || \ + !pfi_match_addr((aw)->p.dyn, (x), (af))) || \ + ((aw)->type == PF_ADDR_RANGE && \ + !pf_match_addr_range(&(aw)->v.a.addr, \ + &(aw)->v.a.mask, (x), (af))) || \ ((aw)->type == PF_ADDR_ADDRMASK && \ !PF_AZERO(&(aw)->v.a.mask, (af)) && \ !PF_MATCHA(0, &(aw)->v.a.addr, \ @@ -619,12 +641,13 @@ struct pf_rule { int rtableid; u_int32_t timeout[PFTM_MAX]; - u_int32_t states; + u_int32_t states_cur; + u_int32_t states_tot; u_int32_t max_states; u_int32_t src_nodes; u_int32_t max_src_nodes; u_int32_t max_src_states; - u_int32_t spare1; /* netgraph */ + u_int32_t spare1; /* netgraph */ u_int32_t max_src_conn; struct { u_int32_t limit; @@ -643,7 +666,7 @@ struct pf_rule { u_int16_t max_mss; u_int16_t tag; u_int16_t match_tag; - u_int16_t spare2; /* netgraph */ + u_int16_t spare2; /* netgraph */ struct pf_rule_uid uid; struct pf_rule_gid gid; @@ -673,12 +696,18 @@ struct pf_rule { u_int8_t rt; u_int8_t return_ttl; u_int8_t tos; + u_int8_t set_tos; u_int8_t anchor_relative; u_int8_t anchor_wildcard; #define PF_FLUSH 0x01 #define PF_FLUSH_GLOBAL 0x02 u_int8_t flush; + + struct { + struct pf_addr addr; + u_int16_t port; + } divert; }; /* rule flags */ @@ -697,10 +726,12 @@ struct pf_rule { #define PFRULE_FRAGDROP 0x0400 /* drop funny fragments */ #define PFRULE_RANDOMID 0x0800 #define PFRULE_REASSEMBLE_TCP 0x1000 +#define PFRULE_SET_TOS 0x2000 /* rule flags again */ #define PFRULE_IFBOUND 0x00010000 /* if-bound */ #define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */ +#define PFRULE_PFLOW 0x00040000 #define PFSTATE_HIWAT 10000 /* default state table size */ #define PFSTATE_ADAPT_START 6000 /* default adaptive timeout start */ @@ -758,83 +789,268 @@ struct pf_state_host { }; struct pf_state_peer { + struct pf_state_scrub *scrub; /* state is scrubbed */ u_int32_t seqlo; /* Max sequence number sent */ u_int32_t seqhi; /* Max the other end ACKd + win */ u_int32_t seqdiff; /* Sequence number modulator */ u_int16_t max_win; /* largest window (pre scaling) */ + u_int16_t mss; /* Maximum segment size option */ u_int8_t state; /* active state level */ u_int8_t wscale; /* window scaling factor */ - u_int16_t mss; /* Maximum segment size option */ u_int8_t tcp_est; /* Did we reach TCPS_ESTABLISHED */ - struct pf_state_scrub *scrub; /* state is scrubbed */ - u_int8_t pad[3]; + u_int8_t pad[1]; }; TAILQ_HEAD(pf_state_queue, pf_state); -/* keep synced with struct pf_state, used in RB_FIND */ -struct pf_state_cmp { - u_int64_t id; - u_int32_t creatorid; - struct pf_state_host lan; - struct pf_state_host gwy; - struct pf_state_host ext; +/* keep synced with struct pf_state_key, used in RB_FIND */ +struct pf_state_key_cmp { + struct pf_addr addr[2]; + u_int16_t port[2]; sa_family_t af; u_int8_t proto; - u_int8_t direction; - u_int8_t pad; + u_int8_t pad[2]; +}; + +struct pf_state_item { + TAILQ_ENTRY(pf_state_item) entry; + struct pf_state *s; +}; + +TAILQ_HEAD(pf_statelisthead, pf_state_item); + +struct pf_state_key { + struct pf_addr addr[2]; + u_int16_t port[2]; + sa_family_t af; + u_int8_t proto; + u_int8_t pad[2]; + + RB_ENTRY(pf_state_key) entry; + struct pf_statelisthead states; + struct pf_state_key *reverse; + struct inpcb *inp; +}; + +/* keep synced with struct pf_state, used in RB_FIND */ +struct pf_state_cmp { + u_int64_t id; + u_int32_t creatorid; + u_int8_t direction; + u_int8_t pad[3]; }; struct pf_state { - u_int64_t id; + u_int64_t id; + u_int32_t creatorid; + u_int8_t direction; +#ifdef __FreeBSD__ + u_int8_t pad[2]; + u_int8_t local_flags; +#define PFSTATE_EXPIRING 0x01 +#else + u_int8_t pad[3]; +#endif + + TAILQ_ENTRY(pf_state) sync_list; + TAILQ_ENTRY(pf_state) entry_list; + RB_ENTRY(pf_state) entry_id; + struct pf_state_peer src; + struct pf_state_peer dst; + union pf_rule_ptr rule; + union pf_rule_ptr anchor; + union pf_rule_ptr nat_rule; + struct pf_addr rt_addr; + struct pf_state_key *key[2]; /* addresses stack and wire */ + struct pfi_kif *kif; + struct pfi_kif *rt_kif; + struct pf_src_node *src_node; + struct pf_src_node *nat_src_node; + u_int64_t packets[2]; + u_int64_t bytes[2]; + u_int32_t creation; + u_int32_t expire; + u_int32_t pfsync_time; + u_int16_t tag; + u_int8_t log; + u_int8_t state_flags; +#define PFSTATE_ALLOWOPTS 0x01 +#define PFSTATE_SLOPPY 0x02 +#define PFSTATE_PFLOW 0x04 +#define PFSTATE_NOSYNC 0x08 +#define PFSTATE_ACK 0x10 + u_int8_t timeout; + u_int8_t sync_state; /* PFSYNC_S_x */ + + /* XXX */ + u_int8_t sync_updates; + u_int8_t _tail[3]; +}; + +/* + * Unified state structures for pulling states out of the kernel + * used by pfsync(4) and the pf(4) ioctl. + */ +struct pfsync_state_scrub { + u_int16_t pfss_flags; + u_int8_t pfss_ttl; /* stashed TTL */ +#define PFSYNC_SCRUB_FLAG_VALID 0x01 + u_int8_t scrub_flag; + u_int32_t pfss_ts_mod; /* timestamp modulation */ +} __packed; + +struct pfsync_state_peer { + struct pfsync_state_scrub scrub; /* state is scrubbed */ + u_int32_t seqlo; /* Max sequence number sent */ + u_int32_t seqhi; /* Max the other end ACKd + win */ + u_int32_t seqdiff; /* Sequence number modulator */ + u_int16_t max_win; /* largest window (pre scaling) */ + u_int16_t mss; /* Maximum segment size option */ + u_int8_t state; /* active state level */ + u_int8_t wscale; /* window scaling factor */ + u_int8_t pad[6]; +} __packed; + +struct pfsync_state_key { + struct pf_addr addr[2]; + u_int16_t port[2]; +}; + +struct pfsync_state { + u_int32_t id[2]; + char ifname[IFNAMSIZ]; + struct pfsync_state_key key[2]; + struct pfsync_state_peer src; + struct pfsync_state_peer dst; + struct pf_addr rt_addr; + u_int32_t rule; + u_int32_t anchor; + u_int32_t nat_rule; + u_int32_t creation; + u_int32_t expire; + u_int32_t packets[2][2]; + u_int32_t bytes[2][2]; u_int32_t creatorid; - struct pf_state_host lan; - struct pf_state_host gwy; - struct pf_state_host ext; sa_family_t af; u_int8_t proto; u_int8_t direction; #ifdef __FreeBSD__ u_int8_t local_flags; -#define PFSTATE_EXPIRING 0x01 -#else +#define PFSTATE_EXPIRING 0x01 u_int8_t pad; #endif u_int8_t log; u_int8_t state_flags; -#define PFSTATE_ALLOWOPTS 0x01 -#define PFSTATE_SLOPPY 0x02 u_int8_t timeout; u_int8_t sync_flags; -#define PFSTATE_NOSYNC 0x01 -#define PFSTATE_FROMSYNC 0x02 -#define PFSTATE_STALE 0x04 - union { - struct { - RB_ENTRY(pf_state) entry_lan_ext; - RB_ENTRY(pf_state) entry_ext_gwy; - RB_ENTRY(pf_state) entry_id; - TAILQ_ENTRY(pf_state) entry_list; - struct pfi_kif *kif; - } s; - char ifname[IFNAMSIZ]; - } u; - struct pf_state_peer src; - struct pf_state_peer dst; - union pf_rule_ptr rule; - union pf_rule_ptr anchor; - union pf_rule_ptr nat_rule; - struct pf_addr rt_addr; - struct pfi_kif *rt_kif; - struct pf_src_node *src_node; - struct pf_src_node *nat_src_node; - u_int64_t packets[2]; - u_int64_t bytes[2]; - u_int32_t creation; - u_int32_t expire; - u_int32_t pfsync_time; - u_int16_t tag; -}; + u_int8_t updates; +} __packed; + +#ifdef __FreeBSD__ +#ifdef _KERNEL +/* pfsync */ +typedef int pfsync_state_import_t(struct pfsync_state *, u_int8_t); +typedef void pfsync_insert_state_t(struct pf_state *); +typedef void pfsync_update_state_t(struct pf_state *); +typedef void pfsync_delete_state_t(struct pf_state *); +typedef void pfsync_clear_states_t(u_int32_t, const char *); +typedef int pfsync_state_in_use_t(struct pf_state *); +typedef int pfsync_defer_t(struct pf_state *, struct mbuf *); +typedef int pfsync_up_t(void); + +extern pfsync_state_import_t *pfsync_state_import_ptr; +extern pfsync_insert_state_t *pfsync_insert_state_ptr; +extern pfsync_update_state_t *pfsync_update_state_ptr; +extern pfsync_delete_state_t *pfsync_delete_state_ptr; +extern pfsync_clear_states_t *pfsync_clear_states_ptr; +extern pfsync_state_in_use_t *pfsync_state_in_use_ptr; +extern pfsync_defer_t *pfsync_defer_ptr; +extern pfsync_up_t *pfsync_up_ptr; + +void pfsync_state_export(struct pfsync_state *, + struct pf_state *); + +/* pflow */ +typedef int export_pflow_t(struct pf_state *); + +extern export_pflow_t *export_pflow_ptr; + +/* pflog */ +struct pf_ruleset; +struct pf_pdesc; +typedef int pflog_packet_t(struct pfi_kif *, struct mbuf *, sa_family_t, + u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *, + struct pf_ruleset *, struct pf_pdesc *); + +extern pflog_packet_t *pflog_packet_ptr; + +/* pf uid hack */ +VNET_DECLARE(int, debug_pfugidhack); +#define V_debug_pfugidhack VNET(debug_pfugidhack) + +#define V_pf_end_threads VNET(pf_end_threads) +#endif + +/* Macros to set/clear/test flags. */ +#ifdef _KERNEL +#define SET(t, f) ((t) |= (f)) +#define CLR(t, f) ((t) &= ~(f)) +#define ISSET(t, f) ((t) & (f)) +#endif +#endif + +#define PFSYNC_FLAG_SRCNODE 0x04 +#define PFSYNC_FLAG_NATSRCNODE 0x08 + +/* for copies to/from network byte order */ +/* ioctl interface also uses network byte order */ +#define pf_state_peer_hton(s,d) do { \ + (d)->seqlo = htonl((s)->seqlo); \ + (d)->seqhi = htonl((s)->seqhi); \ + (d)->seqdiff = htonl((s)->seqdiff); \ + (d)->max_win = htons((s)->max_win); \ + (d)->mss = htons((s)->mss); \ + (d)->state = (s)->state; \ + (d)->wscale = (s)->wscale; \ + if ((s)->scrub) { \ + (d)->scrub.pfss_flags = \ + htons((s)->scrub->pfss_flags & PFSS_TIMESTAMP); \ + (d)->scrub.pfss_ttl = (s)->scrub->pfss_ttl; \ + (d)->scrub.pfss_ts_mod = htonl((s)->scrub->pfss_ts_mod);\ + (d)->scrub.scrub_flag = PFSYNC_SCRUB_FLAG_VALID; \ + } \ +} while (0) + +#define pf_state_peer_ntoh(s,d) do { \ + (d)->seqlo = ntohl((s)->seqlo); \ + (d)->seqhi = ntohl((s)->seqhi); \ + (d)->seqdiff = ntohl((s)->seqdiff); \ + (d)->max_win = ntohs((s)->max_win); \ + (d)->mss = ntohs((s)->mss); \ + (d)->state = (s)->state; \ + (d)->wscale = (s)->wscale; \ + if ((s)->scrub.scrub_flag == PFSYNC_SCRUB_FLAG_VALID && \ + (d)->scrub != NULL) { \ + (d)->scrub->pfss_flags = \ + ntohs((s)->scrub.pfss_flags) & PFSS_TIMESTAMP; \ + (d)->scrub->pfss_ttl = (s)->scrub.pfss_ttl; \ + (d)->scrub->pfss_ts_mod = ntohl((s)->scrub.pfss_ts_mod);\ + } \ +} while (0) + +#define pf_state_counter_hton(s,d) do { \ + d[0] = htonl((s>>32)&0xffffffff); \ + d[1] = htonl(s&0xffffffff); \ +} while (0) + +#define pf_state_counter_from_pfsync(s) \ + (((u_int64_t)(s[0])<<32) | (u_int64_t)(s[1])) + +#define pf_state_counter_ntoh(s,d) do { \ + d = ntohl(s[0]); \ + d = d<<32; \ + d += ntohl(s[1]); \ +} while (0) TAILQ_HEAD(pf_rulequeue, pf_rule); @@ -881,9 +1097,11 @@ RB_PROTOTYPE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare); #define PFR_TFLAG_INACTIVE 0x00000008 #define PFR_TFLAG_REFERENCED 0x00000010 #define PFR_TFLAG_REFDANCHOR 0x00000020 -#define PFR_TFLAG_USRMASK 0x00000003 +#define PFR_TFLAG_COUNTERS 0x00000040 +/* Adjust masks below when adding flags. */ +#define PFR_TFLAG_USRMASK 0x00000043 #define PFR_TFLAG_SETMASK 0x0000003C -#define PFR_TFLAG_ALLMASK 0x0000003F +#define PFR_TFLAG_ALLMASK 0x0000007F struct pfr_table { char pfrt_anchor[MAXPATHLEN]; @@ -894,7 +1112,7 @@ struct pfr_table { enum { PFR_FB_NONE, PFR_FB_MATCH, PFR_FB_ADDED, PFR_FB_DELETED, PFR_FB_CHANGED, PFR_FB_CLEARED, PFR_FB_DUPLICATE, - PFR_FB_NOTMATCH, PFR_FB_CONFLICT, PFR_FB_MAX }; + PFR_FB_NOTMATCH, PFR_FB_CONFLICT, PFR_FB_NOCOUNT, PFR_FB_MAX }; struct pfr_addr { union { @@ -944,20 +1162,32 @@ union sockaddr_union { }; #endif /* _SOCKADDR_UNION_DEFINED */ +struct pfr_kcounters { + u_int64_t pfrkc_packets[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; + u_int64_t pfrkc_bytes[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; +}; + SLIST_HEAD(pfr_kentryworkq, pfr_kentry); struct pfr_kentry { struct radix_node pfrke_node[2]; union sockaddr_union pfrke_sa; - u_int64_t pfrke_packets[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; - u_int64_t pfrke_bytes[PFR_DIR_MAX][PFR_OP_ADDR_MAX]; SLIST_ENTRY(pfr_kentry) pfrke_workq; + union { + + struct pfr_kcounters *pfrke_counters; +#if 0 + struct pfr_kroute *pfrke_route; +#endif + } u; long pfrke_tzero; u_int8_t pfrke_af; u_int8_t pfrke_net; u_int8_t pfrke_not; u_int8_t pfrke_mark; - u_int8_t pfrke_intrpool; }; +#define pfrke_counters u.pfrke_counters +#define pfrke_route u.pfrke_route + SLIST_HEAD(pfr_ktableworkq, pfr_ktable); RB_HEAD(pfr_ktablehead, pfr_ktable); @@ -986,17 +1216,25 @@ struct pfr_ktable { #define pfrkt_nomatch pfrkt_ts.pfrts_nomatch #define pfrkt_tzero pfrkt_ts.pfrts_tzero -RB_HEAD(pf_state_tree_lan_ext, pf_state); -RB_PROTOTYPE(pf_state_tree_lan_ext, pf_state, - u.s.entry_lan_ext, pf_state_compare_lan_ext); +RB_HEAD(pf_state_tree, pf_state_key); +RB_PROTOTYPE(pf_state_tree, pf_state_key, entry, pf_state_compare_key); -RB_HEAD(pf_state_tree_ext_gwy, pf_state); -RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state, - u.s.entry_ext_gwy, pf_state_compare_ext_gwy); +RB_HEAD(pf_state_tree_ext_gwy, pf_state_key); +RB_PROTOTYPE(pf_state_tree_ext_gwy, pf_state_key, + entry_ext_gwy, pf_state_compare_ext_gwy); -TAILQ_HEAD(pfi_statehead, pfi_kif); RB_HEAD(pfi_ifhead, pfi_kif); +/* state tables */ +#ifdef __FreeBSD__ +#ifdef _KERNEL +VNET_DECLARE(struct pf_state_tree, pf_statetbl); +#define V_pf_statetbl VNET(pf_statetbl) +#endif +#else +extern struct pf_state_tree pf_statetbl; +#endif + /* keep synced with pfi_kif, used in RB_FIND */ struct pfi_kif_cmp { char pfik_name[IFNAMSIZ]; @@ -1009,12 +1247,7 @@ struct pfi_kif { u_int64_t pfik_bytes[2][2][2]; u_int32_t pfik_tzero; int pfik_flags; - struct pf_state_tree_lan_ext pfik_lan_ext; - struct pf_state_tree_ext_gwy pfik_ext_gwy; - TAILQ_ENTRY(pfi_kif) pfik_w_states; -#ifndef __FreeBSD__ void *pfik_ah_cookie; -#endif struct ifnet *pfik_ifp; struct ifg_group *pfik_group; int pfik_states; @@ -1029,9 +1262,6 @@ enum pfi_kif_refs { }; #define PFI_IFLAG_SKIP 0x0100 /* skip filtering on interface */ -/* XXX: revisist */ -#define PFI_IFLAG_SETABLE_MASK 0x0100 /* setable via DIOC{SET,CLR}IFFLAG */ -#define PFI_IFLAG_PLACEHOLDER 0x8000 /* placeholder group/interface */ struct pf_pdesc { struct { @@ -1050,16 +1280,22 @@ struct pf_pdesc { #endif /* INET6 */ void *any; } hdr; - struct pf_addr baddr; /* address before translation */ - struct pf_addr naddr; /* address after translation */ + struct pf_rule *nat_rule; /* nat/rdr rule applied to packet */ - struct pf_addr *src; - struct pf_addr *dst; struct ether_header *eh; + struct pf_addr *src; /* src address */ + struct pf_addr *dst; /* dst address */ + u_int16_t *sport; + u_int16_t *dport; +#ifdef __FreeBSD__ struct pf_mtag *pf_mtag; - u_int16_t *ip_sum; +#endif + u_int32_t p_len; /* total length of payload */ + + u_int16_t *ip_sum; + u_int16_t *proto_sum; u_int16_t flags; /* Let SCRUB trigger behavior in * state code. Easier than tags */ #define PFDESC_TCP_NORM 0x0001 /* TCP shall be statefully scrubbed */ @@ -1067,6 +1303,9 @@ struct pf_pdesc { sa_family_t af; u_int8_t proto; u_int8_t tos; + u_int8_t dir; /* direction */ + u_int8_t sidx; /* key index for source */ + u_int8_t didx; /* key index for destination */ }; /* flags for RDR options */ @@ -1175,6 +1414,15 @@ struct pf_pdesc { *(a) = (x); \ } while (0) +#ifdef __FreeBSD__ +#define REASON_SET(a, x) \ + do { \ + if ((a) != NULL) \ + *(a) = (x); \ + if (x < PFRES_MAX) \ + V_pf_status.counters[x]++; \ + } while (0) +#else #define REASON_SET(a, x) \ do { \ if ((a) != NULL) \ @@ -1182,6 +1430,7 @@ struct pf_pdesc { if (x < PFRES_MAX) \ pf_status.counters[x]++; \ } while (0) +#endif struct pf_status { u_int64_t counters[PFRES_MAX]; @@ -1265,27 +1514,6 @@ struct pf_altq { u_int32_t qid; /* return value */ }; -#ifndef __FreeBSD__ - -#define PF_TAG_GENERATED 0x01 -#define PF_TAG_FRAGCACHE 0x02 -#define PF_TAG_TRANSLATE_LOCALHOST 0x04 - -struct pf_mtag { - void *hdr; /* saved hdr pos in mbuf, for ECN */ - u_int rtableid; /* alternate routing table id */ - u_int32_t qid; /* queue id */ - u_int16_t tag; /* tag id */ - u_int8_t flags; - u_int8_t routed; - sa_family_t af; /* for ECN */ -}; -#endif - -struct pf_tag { - u_int16_t tag; /* tag id */ -}; - struct pf_tagname { TAILQ_ENTRY(pf_tagname) entries; char name[PF_TAG_NAME_SIZE]; @@ -1293,6 +1521,14 @@ struct pf_tagname { int ref; }; +struct pf_divert { + union { + struct in_addr ipv4; + struct in6_addr ipv6; + } addr; + u_int16_t port; +}; + #define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ #define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ #define PFFRAG_FRCENT_HIWAT 50000 /* Number of fragment cache entries */ @@ -1343,31 +1579,32 @@ struct pfioc_natlook { }; struct pfioc_state { - u_int32_t nr; - struct pf_state state; + struct pfsync_state state; }; struct pfioc_src_node_kill { - /* XXX returns the number of src nodes killed in psnk_af */ sa_family_t psnk_af; struct pf_rule_addr psnk_src; struct pf_rule_addr psnk_dst; + u_int psnk_killed; }; struct pfioc_state_kill { - /* XXX returns the number of states killed in psk_af */ + struct pf_state_cmp psk_pfcmp; sa_family_t psk_af; int psk_proto; struct pf_rule_addr psk_src; struct pf_rule_addr psk_dst; char psk_ifname[IFNAMSIZ]; + char psk_label[PF_RULE_LABEL_SIZE]; + u_int psk_killed; }; struct pfioc_states { int ps_len; union { - caddr_t psu_buf; - struct pf_state *psu_states; + caddr_t psu_buf; + struct pfsync_state *psu_states; } ps_u; #define ps_buf ps_u.psu_buf #define ps_states ps_u.psu_states @@ -1518,55 +1755,97 @@ struct pfioc_iface { #define DIOCRDELTABLES _IOWR('D', 62, struct pfioc_table) #define DIOCRGETTABLES _IOWR('D', 63, struct pfioc_table) #define DIOCRGETTSTATS _IOWR('D', 64, struct pfioc_table) -#define DIOCRCLRTSTATS _IOWR('D', 65, struct pfioc_table) +#define DIOCRCLRTSTATS _IOWR('D', 65, struct pfioc_table) #define DIOCRCLRADDRS _IOWR('D', 66, struct pfioc_table) #define DIOCRADDADDRS _IOWR('D', 67, struct pfioc_table) #define DIOCRDELADDRS _IOWR('D', 68, struct pfioc_table) #define DIOCRSETADDRS _IOWR('D', 69, struct pfioc_table) #define DIOCRGETADDRS _IOWR('D', 70, struct pfioc_table) #define DIOCRGETASTATS _IOWR('D', 71, struct pfioc_table) -#define DIOCRCLRASTATS _IOWR('D', 72, struct pfioc_table) +#define DIOCRCLRASTATS _IOWR('D', 72, struct pfioc_table) #define DIOCRTSTADDRS _IOWR('D', 73, struct pfioc_table) #define DIOCRSETTFLAGS _IOWR('D', 74, struct pfioc_table) -#define DIOCRINADEFINE _IOWR('D', 77, struct pfioc_table) -#define DIOCOSFPFLUSH _IO('D', 78) -#define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl) -#define DIOCOSFPGET _IOWR('D', 80, struct pf_osfp_ioctl) -#define DIOCXBEGIN _IOWR('D', 81, struct pfioc_trans) -#define DIOCXCOMMIT _IOWR('D', 82, struct pfioc_trans) -#define DIOCXROLLBACK _IOWR('D', 83, struct pfioc_trans) -#define DIOCGETSRCNODES _IOWR('D', 84, struct pfioc_src_nodes) -#define DIOCCLRSRCNODES _IO('D', 85) -#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t) -#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface) -#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface) -#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface) -#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill) +#define DIOCRINADEFINE _IOWR('D', 77, struct pfioc_table) +#define DIOCOSFPFLUSH _IO('D', 78) +#define DIOCOSFPADD _IOWR('D', 79, struct pf_osfp_ioctl) +#define DIOCOSFPGET _IOWR('D', 80, struct pf_osfp_ioctl) +#define DIOCXBEGIN _IOWR('D', 81, struct pfioc_trans) +#define DIOCXCOMMIT _IOWR('D', 82, struct pfioc_trans) +#define DIOCXROLLBACK _IOWR('D', 83, struct pfioc_trans) +#define DIOCGETSRCNODES _IOWR('D', 84, struct pfioc_src_nodes) +#define DIOCCLRSRCNODES _IO('D', 85) +#define DIOCSETHOSTID _IOWR('D', 86, u_int32_t) +#define DIOCIGETIFACES _IOWR('D', 87, struct pfioc_iface) +#define DIOCSETIFFLAG _IOWR('D', 89, struct pfioc_iface) +#define DIOCCLRIFFLAG _IOWR('D', 90, struct pfioc_iface) +#define DIOCKILLSRCNODES _IOWR('D', 91, struct pfioc_src_node_kill) #ifdef __FreeBSD__ struct pf_ifspeed { char ifname[IFNAMSIZ]; u_int32_t baudrate; }; -#define DIOCGIFSPEED _IOWR('D', 92, struct pf_ifspeed) +#define DIOCGIFSPEED _IOWR('D', 92, struct pf_ifspeed) #endif #ifdef _KERNEL RB_HEAD(pf_src_tree, pf_src_node); RB_PROTOTYPE(pf_src_tree, pf_src_node, entry, pf_src_compare); +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_src_tree, tree_src_tracking); +#define V_tree_src_tracking VNET(tree_src_tracking) +#else extern struct pf_src_tree tree_src_tracking; +#endif RB_HEAD(pf_state_tree_id, pf_state); RB_PROTOTYPE(pf_state_tree_id, pf_state, entry_id, pf_state_compare_id); +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_state_tree_id, tree_id); +#define V_tree_id VNET(tree_id) +VNET_DECLARE(struct pf_state_queue, state_list); +#define V_state_list VNET(state_list) +#else extern struct pf_state_tree_id tree_id; extern struct pf_state_queue state_list; +#endif TAILQ_HEAD(pf_poolqueue, pf_pool); +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_poolqueue, pf_pools[2]); +#define V_pf_pools VNET(pf_pools) +#else extern struct pf_poolqueue pf_pools[2]; +#endif TAILQ_HEAD(pf_altqqueue, pf_altq); +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_altqqueue, pf_altqs[2]); +#define V_pf_altqs VNET(pf_altqs) +VNET_DECLARE(struct pf_palist, pf_pabuf); +#define V_pf_pabuf VNET(pf_pabuf) +#else extern struct pf_altqqueue pf_altqs[2]; extern struct pf_palist pf_pabuf; +#endif +#ifdef __FreeBSD__ +VNET_DECLARE(u_int32_t, ticket_altqs_active); +#define V_ticket_altqs_active VNET(ticket_altqs_active) +VNET_DECLARE(u_int32_t, ticket_altqs_inactive); +#define V_ticket_altqs_inactive VNET(ticket_altqs_inactive) +VNET_DECLARE(int, altqs_inactive_open); +#define V_altqs_inactive_open VNET(altqs_inactive_open) +VNET_DECLARE(u_int32_t, ticket_pabuf); +#define V_ticket_pabuf VNET(ticket_pabuf) +VNET_DECLARE(struct pf_altqqueue *, pf_altqs_active); +#define V_pf_altqs_active VNET(pf_altqs_active) +VNET_DECLARE(struct pf_altqqueue *, pf_altqs_inactive); +#define V_pf_altqs_inactive VNET(pf_altqs_inactive) +VNET_DECLARE(struct pf_poolqueue *, pf_pools_active); +#define V_pf_pools_active VNET(pf_pools_active) +VNET_DECLARE(struct pf_poolqueue *, pf_pools_inactive); +#define V_pf_pools_inactive VNET(pf_pools_inactive) +#else extern u_int32_t ticket_altqs_active; extern u_int32_t ticket_altqs_inactive; extern int altqs_inactive_open; @@ -1575,6 +1854,7 @@ extern struct pf_altqqueue *pf_altqs_active; extern struct pf_altqqueue *pf_altqs_inactive; extern struct pf_poolqueue *pf_pools_active; extern struct pf_poolqueue *pf_pools_inactive; +#endif extern int pf_tbladdr_setup(struct pf_ruleset *, struct pf_addr_wrap *); extern void pf_tbladdr_remove(struct pf_addr_wrap *); @@ -1582,49 +1862,82 @@ extern void pf_tbladdr_copyout(struct pf_addr_wrap *); extern void pf_calc_skip_steps(struct pf_rulequeue *); #ifdef __FreeBSD__ #ifdef ALTQ -extern void pf_altq_ifnet_event(struct ifnet *, int); +extern void pf_altq_ifnet_event(struct ifnet *, int); #endif -extern uma_zone_t pf_src_tree_pl, pf_rule_pl; -extern uma_zone_t pf_state_pl, pf_altq_pl, pf_pooladdr_pl; -extern uma_zone_t pfr_ktable_pl, pfr_kentry_pl, pfr_kentry_pl2; -extern uma_zone_t pf_cache_pl, pf_cent_pl; -extern uma_zone_t pf_state_scrub_pl; -extern uma_zone_t pfi_addr_pl; +VNET_DECLARE(uma_zone_t, pf_src_tree_pl); +#define V_pf_src_tree_pl VNET(pf_src_tree_pl) +VNET_DECLARE(uma_zone_t, pf_rule_pl); +#define V_pf_rule_pl VNET(pf_rule_pl) +VNET_DECLARE(uma_zone_t, pf_state_pl); +#define V_pf_state_pl VNET(pf_state_pl) +VNET_DECLARE(uma_zone_t, pf_state_key_pl); +#define V_pf_state_key_pl VNET(pf_state_key_pl) +VNET_DECLARE(uma_zone_t, pf_state_item_pl); +#define V_pf_state_item_pl VNET(pf_state_item_pl) +VNET_DECLARE(uma_zone_t, pf_altq_pl); +#define V_pf_altq_pl VNET(pf_altq_pl) +VNET_DECLARE(uma_zone_t, pf_pooladdr_pl); +#define V_pf_pooladdr_pl VNET(pf_pooladdr_pl) +VNET_DECLARE(uma_zone_t, pfr_ktable_pl); +#define V_pfr_ktable_pl VNET(pfr_ktable_pl) +VNET_DECLARE(uma_zone_t, pfr_kentry_pl); +#define V_pfr_kentry_pl VNET(pfr_kentry_pl) +VNET_DECLARE(uma_zone_t, pf_cache_pl); +#define V_pf_cache_pl VNET(pf_cache_pl) +VNET_DECLARE(uma_zone_t, pf_cent_pl); +#define V_pf_cent_pl VNET(pf_cent_pl) +VNET_DECLARE(uma_zone_t, pf_state_scrub_pl); +#define V_pf_state_scrub_pl VNET(pf_state_scrub_pl) +VNET_DECLARE(uma_zone_t, pfi_addr_pl); +#define V_pfi_addr_pl VNET(pfi_addr_pl) #else extern struct pool pf_src_tree_pl, pf_rule_pl; -extern struct pool pf_state_pl, pf_altq_pl, pf_pooladdr_pl; +extern struct pool pf_state_pl, pf_state_key_pl, pf_state_item_pl, + pf_altq_pl, pf_pooladdr_pl; extern struct pool pf_state_scrub_pl; #endif extern void pf_purge_thread(void *); #ifdef __FreeBSD__ extern int pf_purge_expired_src_nodes(int); -extern int pf_purge_expired_states(u_int32_t, int); +extern int pf_purge_expired_states(u_int32_t , int); #else extern void pf_purge_expired_src_nodes(int); extern void pf_purge_expired_states(u_int32_t); #endif extern void pf_unlink_state(struct pf_state *); extern void pf_free_state(struct pf_state *); -extern int pf_insert_state(struct pfi_kif *, +extern int pf_state_insert(struct pfi_kif *, + struct pf_state_key *, + struct pf_state_key *, struct pf_state *); extern int pf_insert_src_node(struct pf_src_node **, struct pf_rule *, struct pf_addr *, sa_family_t); void pf_src_tree_remove_state(struct pf_state *); extern struct pf_state *pf_find_state_byid(struct pf_state_cmp *); -extern struct pf_state *pf_find_state_all(struct pf_state_cmp *key, - u_int8_t tree, int *more); +extern struct pf_state *pf_find_state_all(struct pf_state_key_cmp *, + u_int, int *); extern void pf_print_state(struct pf_state *); extern void pf_print_flags(u_int8_t); extern u_int16_t pf_cksum_fixup(u_int16_t, u_int16_t, u_int16_t, u_int8_t); +#ifdef __FreeBSD__ +VNET_DECLARE(struct ifnet *, sync_ifp); +#define V_sync_ifp VNET(sync_ifp); +VNET_DECLARE(struct pf_rule, pf_default_rule); +#define V_pf_default_rule VNET(pf_default_rule) +#else extern struct ifnet *sync_ifp; extern struct pf_rule pf_default_rule; +#endif extern void pf_addrcpy(struct pf_addr *, struct pf_addr *, u_int8_t); void pf_rm_rule(struct pf_rulequeue *, struct pf_rule *); +#ifndef __FreeBSD__ +struct pf_divert *pf_find_divert(struct mbuf *); +#endif #ifdef INET #ifdef __FreeBSD__ @@ -1656,8 +1969,11 @@ void pf_change_a(void *, u_int16_t *, u_int32_t, u_int8_t); int pflog_packet(struct pfi_kif *, struct mbuf *, sa_family_t, u_int8_t, u_int8_t, struct pf_rule *, struct pf_rule *, struct pf_ruleset *, struct pf_pdesc *); +void pf_send_deferred_syn(struct pf_state *); int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *, struct pf_addr *, sa_family_t); +int pf_match_addr_range(struct pf_addr *, struct pf_addr *, + struct pf_addr *, sa_family_t); int pf_match(u_int8_t, u_int32_t, u_int32_t, u_int32_t); int pf_match_port(u_int8_t, u_int16_t, u_int16_t, u_int16_t); int pf_match_uid(u_int8_t, uid_t, uid_t, uid_t); @@ -1682,10 +1998,13 @@ void pf_purge_expired_fragments(void); int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *); int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *); #ifdef __FreeBSD__ -int pf_socket_lookup(int, struct pf_pdesc *, struct inpcb *); +int pf_socket_lookup(int, struct pf_pdesc *, struct inpcb *); #else int pf_socket_lookup(int, struct pf_pdesc *); #endif +struct pf_state_key *pf_alloc_state_key(int); +void pf_pkt_addr_changed(struct mbuf *); +int pf_state_key_attach(struct pf_state_key *, struct pf_state *, int); void pfr_initialize(void); int pfr_match_addr(struct pfr_ktable *, struct pf_addr *, sa_family_t); void pfr_update_stats(struct pfr_ktable *, struct pf_addr *, sa_family_t, @@ -1694,7 +2013,7 @@ int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, struct pf_addr **, struct pf_addr **, sa_family_t); void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *); struct pfr_ktable * - pfr_attach_table(struct pf_ruleset *, char *); + pfr_attach_table(struct pf_ruleset *, char *, int); void pfr_detach_table(struct pfr_ktable *); int pfr_clr_tables(struct pfr_table *, int *, int); int pfr_add_tables(struct pfr_table *, int, int *, int); @@ -1723,8 +2042,12 @@ int pfr_ina_commit(struct pfr_table *, u_int32_t, int *, int *, int); int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, int *, u_int32_t, int); -extern struct pfi_statehead pfi_statehead; +#ifdef __FreeBSD__ +VNET_DECLARE(struct pfi_kif *, pfi_all); +#define V_pfi_all VNET(pfi_all) +#else extern struct pfi_kif *pfi_all; +#endif void pfi_initialize(void); #ifdef __FreeBSD__ @@ -1744,30 +2067,44 @@ int pfi_match_addr(struct pfi_dynaddr *, struct pf_addr *, int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t); void pfi_dynaddr_remove(struct pf_addr_wrap *); void pfi_dynaddr_copyout(struct pf_addr_wrap *); -void pfi_fill_oldstatus(struct pf_status *); -int pfi_clr_istats(const char *); +void pfi_update_status(const char *, struct pf_status *); int pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_set_flags(const char *, int); int pfi_clear_flags(const char *, int); +#ifdef __FreeBSD__ +int pf_match_tag(struct mbuf *, struct pf_rule *, int *, + struct pf_mtag *); +#else +int pf_match_tag(struct mbuf *, struct pf_rule *, int *); +#endif u_int16_t pf_tagname2tag(char *); void pf_tag2tagname(u_int16_t, char *); void pf_tag_ref(u_int16_t); void pf_tag_unref(u_int16_t); -int pf_tag_packet(struct mbuf *, struct pf_mtag *, int, int); +#ifdef __FreeBSD__ +int pf_tag_packet(struct mbuf *, int, int, struct pf_mtag *); +#else +int pf_tag_packet(struct mbuf *, int, int); +#endif u_int32_t pf_qname2qid(char *); void pf_qid2qname(u_int32_t, char *); void pf_qid_unref(u_int32_t); -#ifndef __FreeBSD__ -struct pf_mtag *pf_find_mtag(struct mbuf *); -struct pf_mtag *pf_get_mtag(struct mbuf *); -#endif +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_status, pf_status); +#define V_pf_status VNET(pf_status) +#else extern struct pf_status pf_status; +#endif #ifdef __FreeBSD__ -extern uma_zone_t pf_frent_pl, pf_frag_pl; -extern struct sx pf_consistency_lock; +VNET_DECLARE(uma_zone_t, pf_frent_pl); +#define V_pf_frent_pl VNET(pf_frent_pl) +VNET_DECLARE(uma_zone_t, pf_frag_pl); +#define V_pf_frag_pl VNET(pf_frag_pl) +VNET_DECLARE(struct sx, pf_consistency_lock); +#define V_pf_consistency_lock VNET(pf_consistency_lock) #else extern struct pool pf_frent_pl, pf_frag_pl; extern struct rwlock pf_consistency_lock; @@ -1777,7 +2114,12 @@ struct pf_pool_limit { void *pp; unsigned limit; }; +#ifdef __FreeBSD__ +VNET_DECLARE(struct pf_pool_limit, pf_pool_limits[PF_LIMIT_MAX]); +#define V_pf_pool_limits VNET(pf_pool_limits) +#else extern struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX]; +#endif #ifdef __FreeBSD__ struct pf_frent { @@ -1788,34 +2130,44 @@ struct pf_frent { struct pf_frcache { LIST_ENTRY(pf_frcache) fr_next; - uint16_t fr_off; - uint16_t fr_end; + uint16_t fr_off; + uint16_t fr_end; }; struct pf_fragment { RB_ENTRY(pf_fragment) fr_entry; TAILQ_ENTRY(pf_fragment) frag_next; - struct in_addr fr_src; - struct in_addr fr_dst; - u_int8_t fr_p; /* protocol of this fragment */ - u_int8_t fr_flags; /* status flags */ - u_int16_t fr_id; /* fragment id for reassemble */ - u_int16_t fr_max; /* fragment data max */ - u_int32_t fr_timeout; -#define fr_queue fr_u.fru_queue -#define fr_cache fr_u.fru_cache + struct in_addr fr_src; + struct in_addr fr_dst; + u_int8_t fr_p; /* protocol of this fragment */ + u_int8_t fr_flags; /* status flags */ + u_int16_t fr_id; /* fragment id for reassemble */ + u_int16_t fr_max; /* fragment data max */ + u_int32_t fr_timeout; +#define fr_queue fr_u.fru_queue +#define fr_cache fr_u.fru_cache union { - LIST_HEAD(pf_fragq, pf_frent) fru_queue; /* buffering */ - LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */ + LIST_HEAD(pf_fragq, pf_frent) fru_queue; /* buffering */ + LIST_HEAD(pf_cacheq, pf_frcache) fru_cache; /* non-buf */ } fr_u; }; #endif /* (__FreeBSD__) */ #endif /* _KERNEL */ -extern struct pf_anchor_global pf_anchors; -extern struct pf_anchor pf_main_anchor; +#ifdef __FreeBSD__ +#ifdef _KERNEL +VNET_DECLARE(struct pf_anchor_global, pf_anchors); +#define V_pf_anchors VNET(pf_anchors) +VNET_DECLARE(struct pf_anchor, pf_main_anchor); +#define V_pf_main_anchor VNET(pf_main_anchor) +#define pf_main_ruleset V_pf_main_anchor.ruleset +#endif +#else +extern struct pf_anchor_global pf_anchors; +extern struct pf_anchor pf_main_anchor; #define pf_main_ruleset pf_main_anchor.ruleset +#endif /* these ruleset functions can be linked into userland programs (pfctl) */ int pf_get_ruleset_number(u_int8_t); @@ -1832,7 +2184,6 @@ struct pf_ruleset *pf_find_or_create_ruleset(const char *); void pf_rs_initialize(void); #ifndef __FreeBSD__ -/* ?!? */ #ifdef _KERNEL int pf_anchor_copyout(const struct pf_ruleset *, const struct pf_rule *, struct pfioc_rule *); @@ -1863,4 +2214,31 @@ int pf_osfp_match(struct pf_osfp_enlist *, pf_osfp_t); struct pf_os_fingerprint * pf_osfp_validate(void); +#ifdef _KERNEL +void pf_print_host(struct pf_addr *, u_int16_t, u_int8_t); + +void pf_step_into_anchor(int *, struct pf_ruleset **, int, + struct pf_rule **, struct pf_rule **, int *); +int pf_step_out_of_anchor(int *, struct pf_ruleset **, + int, struct pf_rule **, struct pf_rule **, + int *); + +int pf_map_addr(u_int8_t, struct pf_rule *, + struct pf_addr *, struct pf_addr *, + struct pf_addr *, struct pf_src_node **); +struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *, + int, int, struct pfi_kif *, struct pf_src_node **, + struct pf_state_key **, struct pf_state_key **, + struct pf_state_key **, struct pf_state_key **, + struct pf_addr *, struct pf_addr *, + u_int16_t, u_int16_t); + +int pf_state_key_setup(struct pf_pdesc *, struct pf_rule *, + struct pf_state_key **, struct pf_state_key **, + struct pf_state_key **, struct pf_state_key **, + struct pf_addr *, struct pf_addr *, + u_int16_t, u_int16_t); +#endif /* _KERNEL */ + + #endif /* _NET_PFVAR_H_ */ diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 84f65bd..9352be9 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1244,7 +1244,7 @@ acpi_alloc_resource(device_t bus, device_t child, int type, int *rid, /* * First attempt at allocating the resource. For direct children, * use resource_list_alloc() to handle reserved resources. For - * other dveices, pass the request up to our parent. + * other devices, pass the request up to our parent. */ if (bus == device_get_parent(child)) { ad = device_get_ivars(child); diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c index 8cb6858..d26903d 100644 --- a/sys/dev/acpica/acpi_cpu.c +++ b/sys/dev/acpica/acpi_cpu.c @@ -856,6 +856,8 @@ acpi_cpu_cx_list(struct acpi_cpu_softc *sc) sbuf_printf(&sb, "C%d/%d ", i + 1, sc->cpu_cx_states[i].trans_lat); if (sc->cpu_cx_states[i].type < ACPI_STATE_C3) sc->cpu_non_c3 = i; + else + cpu_can_deep_sleep = 1; } sbuf_trim(&sb); sbuf_finish(&sb); @@ -925,11 +927,9 @@ acpi_cpu_idle() /* Find the lowest state that has small enough latency. */ cx_next_idx = 0; -#ifndef __ia64__ if (cpu_disable_deep_sleep) i = min(sc->cpu_cx_lowest, sc->cpu_non_c3); else -#endif i = sc->cpu_cx_lowest; for (; i >= 0; i--) { if (sc->cpu_cx_states[i].trans_lat * 3 <= sc->cpu_prev_sleep) { diff --git a/sys/dev/acpica/acpi_pcib_acpi.c b/sys/dev/acpica/acpi_pcib_acpi.c index e4efeff..73b2f70 100644 --- a/sys/dev/acpica/acpi_pcib_acpi.c +++ b/sys/dev/acpica/acpi_pcib_acpi.c @@ -357,32 +357,14 @@ acpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); } -static u_long acpi_host_mem_start = 0x80000000; -TUNABLE_ULONG("hw.acpi.host_mem_start", &acpi_host_mem_start); - struct resource * acpi_pcib_acpi_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { - /* - * If no memory preference is given, use upper 32MB slot most - * bioses use for their memory window. Typically other bridges - * before us get in the way to assert their preferences on memory. - * Hardcoding like this sucks, so a more MD/MI way needs to be - * found to do it. This is typically only used on older laptops - * that don't have pci busses behind pci bridge, so assuming > 32MB - * is likely OK. - * - * PCI-PCI bridges may allocate smaller ranges for their windows, - * but the heuristics here should apply to those, so we allow - * several different end addresses. - */ - if (type == SYS_RES_MEMORY && start == 0UL && (end == ~0UL || - end == 0xffffffff)) - start = acpi_host_mem_start; - if (type == SYS_RES_IOPORT && start == 0UL && (end == ~0UL || - end == 0xffff || end == 0xffffffff)) - start = 0x1000; + +#if defined(__i386__) || defined(__amd64__) + start = hostb_alloc_start(type, start, end, count); +#endif return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } diff --git a/sys/dev/acpica/acpi_resource.c b/sys/dev/acpica/acpi_resource.c index c83b679..ce6732f 100644 --- a/sys/dev/acpica/acpi_resource.c +++ b/sys/dev/acpica/acpi_resource.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/bus.h> +#include <sys/limits.h> #include <sys/malloc.h> #include <sys/module.h> @@ -139,332 +140,278 @@ acpi_config_intr(device_t dev, ACPI_RESOURCE *res) INTR_POLARITY_HIGH : INTR_POLARITY_LOW); } -/* - * Fetch a device's resources and associate them with the device. - * - * Note that it might be nice to also locate ACPI-specific resource items, such - * as GPE bits. - * - * We really need to split the resource-fetching code out from the - * resource-parsing code, since we may want to use the parsing - * code for _PRS someday. - */ -ACPI_STATUS -acpi_parse_resources(device_t dev, ACPI_HANDLE handle, - struct acpi_parse_resource_set *set, void *arg) -{ - ACPI_BUFFER buf; - ACPI_RESOURCE *res; - char *curr, *last; - ACPI_STATUS status; - void *context; +struct acpi_resource_context { + struct acpi_parse_resource_set *set; + device_t dev; + void *context; +}; - ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); +#ifdef ACPI_DEBUG_OUTPUT +static const char * +acpi_address_range_name(UINT8 ResourceType) +{ + static char buf[16]; + + switch (ResourceType) { + case ACPI_MEMORY_RANGE: + return ("Memory"); + case ACPI_IO_RANGE: + return ("IO"); + case ACPI_BUS_NUMBER_RANGE: + return ("Bus Number"); + default: + snprintf(buf, sizeof(buf), "type %u", ResourceType); + return (buf); + } +} +#endif + +static ACPI_STATUS +acpi_parse_resource(ACPI_RESOURCE *res, void *context) +{ + struct acpi_parse_resource_set *set; + struct acpi_resource_context *arc; + UINT64 min, max, length, gran; + const char *name; + device_t dev; - /* - * Special-case some devices that abuse _PRS/_CRS to mean - * something other than "I consume this resource". - * - * XXX do we really need this? It's only relevant once - * we start always-allocating these resources, and even - * then, the only special-cased device is likely to be - * the PCI interrupt link. - */ + arc = context; + dev = arc->dev; + set = arc->set; - /* Fetch the device's current resources. */ - buf.Length = ACPI_ALLOCATE_BUFFER; - if (ACPI_FAILURE((status = AcpiGetCurrentResources(handle, &buf)))) { - if (status != AE_NOT_FOUND && status != AE_TYPE) - printf("can't fetch resources for %s - %s\n", - acpi_name(handle), AcpiFormatException(status)); - return_ACPI_STATUS (status); - } - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s - got %ld bytes of resources\n", - acpi_name(handle), (long)buf.Length)); - set->set_init(dev, arg, &context); - - /* Iterate through the resources */ - curr = buf.Pointer; - last = (char *)buf.Pointer + buf.Length; - while (curr < last) { - res = (ACPI_RESOURCE *)curr; - curr += res->Length; - - /* Handle the individual resource types */ - switch(res->Type) { - case ACPI_RESOURCE_TYPE_END_TAG: - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); - curr = last; + switch (res->Type) { + case ACPI_RESOURCE_TYPE_END_TAG: + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "EndTag\n")); + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + if (res->Data.FixedIo.AddressLength <= 0) break; - case ACPI_RESOURCE_TYPE_FIXED_IO: - if (res->Data.FixedIo.AddressLength <= 0) - break; - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", - res->Data.FixedIo.Address, - res->Data.FixedIo.AddressLength)); - set->set_ioport(dev, context, - res->Data.FixedIo.Address, - res->Data.FixedIo.AddressLength); + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedIo 0x%x/%d\n", + res->Data.FixedIo.Address, res->Data.FixedIo.AddressLength)); + set->set_ioport(dev, arc->context, res->Data.FixedIo.Address, + res->Data.FixedIo.AddressLength); + break; + case ACPI_RESOURCE_TYPE_IO: + if (res->Data.Io.AddressLength <= 0) break; - case ACPI_RESOURCE_TYPE_IO: - if (res->Data.Io.AddressLength <= 0) - break; - if (res->Data.Io.Minimum == res->Data.Io.Maximum) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", - res->Data.Io.Minimum, - res->Data.Io.AddressLength)); - set->set_ioport(dev, context, - res->Data.Io.Minimum, - res->Data.Io.AddressLength); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", - res->Data.Io.Minimum, - res->Data.Io.Maximum, - res->Data.Io.AddressLength)); - set->set_iorange(dev, context, - res->Data.Io.Minimum, - res->Data.Io.Maximum, - res->Data.Io.AddressLength, - res->Data.Io.Alignment); - } + if (res->Data.Io.Minimum == res->Data.Io.Maximum) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x/%d\n", + res->Data.Io.Minimum, res->Data.Io.AddressLength)); + set->set_ioport(dev, arc->context, res->Data.Io.Minimum, + res->Data.Io.AddressLength); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Io 0x%x-0x%x/%d\n", + res->Data.Io.Minimum, res->Data.Io.Maximum, + res->Data.Io.AddressLength)); + set->set_iorange(dev, arc->context, res->Data.Io.Minimum, + res->Data.Io.Maximum, res->Data.Io.AddressLength, + res->Data.Io.Alignment); + } + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + if (res->Data.FixedMemory32.AddressLength <= 0) break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - if (res->Data.FixedMemory32.AddressLength <= 0) - break; - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", - res->Data.FixedMemory32.Address, - res->Data.FixedMemory32.AddressLength)); - set->set_memory(dev, context, - res->Data.FixedMemory32.Address, - res->Data.FixedMemory32.AddressLength); + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "FixedMemory32 0x%x/%d\n", + res->Data.FixedMemory32.Address, + res->Data.FixedMemory32.AddressLength)); + set->set_memory(dev, arc->context, res->Data.FixedMemory32.Address, + res->Data.FixedMemory32.AddressLength); + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + if (res->Data.Memory32.AddressLength <= 0) break; - case ACPI_RESOURCE_TYPE_MEMORY32: - if (res->Data.Memory32.AddressLength <= 0) - break; - if (res->Data.Memory32.Minimum == - res->Data.Memory32.Maximum) { - - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", - res->Data.Memory32.Minimum, - res->Data.Memory32.AddressLength)); - set->set_memory(dev, context, - res->Data.Memory32.Minimum, - res->Data.Memory32.AddressLength); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", - res->Data.Memory32.Minimum, - res->Data.Memory32.Maximum, - res->Data.Memory32.AddressLength)); - set->set_memoryrange(dev, context, - res->Data.Memory32.Minimum, - res->Data.Memory32.Maximum, - res->Data.Memory32.AddressLength, - res->Data.Memory32.Alignment); - } + if (res->Data.Memory32.Minimum == res->Data.Memory32.Maximum) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x/%d\n", + res->Data.Memory32.Minimum, res->Data.Memory32.AddressLength)); + set->set_memory(dev, arc->context, res->Data.Memory32.Minimum, + res->Data.Memory32.AddressLength); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory32 0x%x-0x%x/%d\n", + res->Data.Memory32.Minimum, res->Data.Memory32.Maximum, + res->Data.Memory32.AddressLength)); + set->set_memoryrange(dev, arc->context, res->Data.Memory32.Minimum, + res->Data.Memory32.Maximum, res->Data.Memory32.AddressLength, + res->Data.Memory32.Alignment); + } + break; + case ACPI_RESOURCE_TYPE_MEMORY24: + if (res->Data.Memory24.AddressLength <= 0) break; - case ACPI_RESOURCE_TYPE_MEMORY24: - if (res->Data.Memory24.AddressLength <= 0) - break; - if (res->Data.Memory24.Minimum == - res->Data.Memory24.Maximum) { - - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", - res->Data.Memory24.Minimum, - res->Data.Memory24.AddressLength)); - set->set_memory(dev, context, res->Data.Memory24.Minimum, - res->Data.Memory24.AddressLength); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", - res->Data.Memory24.Minimum, - res->Data.Memory24.Maximum, - res->Data.Memory24.AddressLength)); - set->set_memoryrange(dev, context, - res->Data.Memory24.Minimum, - res->Data.Memory24.Maximum, - res->Data.Memory24.AddressLength, - res->Data.Memory24.Alignment); - } + if (res->Data.Memory24.Minimum == res->Data.Memory24.Maximum) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x/%d\n", + res->Data.Memory24.Minimum, res->Data.Memory24.AddressLength)); + set->set_memory(dev, arc->context, res->Data.Memory24.Minimum, + res->Data.Memory24.AddressLength); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "Memory24 0x%x-0x%x/%d\n", + res->Data.Memory24.Minimum, res->Data.Memory24.Maximum, + res->Data.Memory24.AddressLength)); + set->set_memoryrange(dev, arc->context, res->Data.Memory24.Minimum, + res->Data.Memory24.Maximum, res->Data.Memory24.AddressLength, + res->Data.Memory24.Alignment); + } + break; + case ACPI_RESOURCE_TYPE_IRQ: + /* + * from 1.0b 6.4.2 + * "This structure is repeated for each separate interrupt + * required" + */ + set->set_irq(dev, arc->context, res->Data.Irq.Interrupts, + res->Data.Irq.InterruptCount, res->Data.Irq.Triggering, + res->Data.Irq.Polarity); + break; + case ACPI_RESOURCE_TYPE_DMA: + /* + * from 1.0b 6.4.3 + * "This structure is repeated for each separate DMA channel + * required" + */ + set->set_drq(dev, arc->context, res->Data.Dma.Channels, + res->Data.Dma.ChannelCount); + break; + case ACPI_RESOURCE_TYPE_START_DEPENDENT: + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n")); + set->set_start_dependent(dev, arc->context, + res->Data.StartDpf.CompatibilityPriority); + break; + case ACPI_RESOURCE_TYPE_END_DEPENDENT: + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n")); + set->set_end_dependent(dev, arc->context); + break; + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: + switch (res->Type) { + case ACPI_RESOURCE_TYPE_ADDRESS16: + gran = res->Data.Address16.Granularity; + min = res->Data.Address16.Minimum; + max = res->Data.Address16.Maximum; + length = res->Data.Address16.AddressLength; + name = "Address16"; break; - case ACPI_RESOURCE_TYPE_IRQ: - /* - * from 1.0b 6.4.2 - * "This structure is repeated for each separate interrupt - * required" - */ - set->set_irq(dev, context, res->Data.Irq.Interrupts, - res->Data.Irq.InterruptCount, res->Data.Irq.Triggering, - res->Data.Irq.Polarity); + case ACPI_RESOURCE_TYPE_ADDRESS32: + gran = res->Data.Address32.Granularity; + min = res->Data.Address32.Minimum; + max = res->Data.Address32.Maximum; + length = res->Data.Address32.AddressLength; + name = "Address32"; break; - case ACPI_RESOURCE_TYPE_DMA: - /* - * from 1.0b 6.4.3 - * "This structure is repeated for each separate dma channel - * required" - */ - set->set_drq(dev, context, res->Data.Dma.Channels, - res->Data.Dma.ChannelCount); + case ACPI_RESOURCE_TYPE_ADDRESS64: + gran = res->Data.Address64.Granularity; + min = res->Data.Address64.Minimum; + max = res->Data.Address64.Maximum; + length = res->Data.Address64.AddressLength; + name = "Address64"; break; - case ACPI_RESOURCE_TYPE_START_DEPENDENT: - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "start dependent functions\n")); - set->set_start_dependent(dev, context, - res->Data.StartDpf.CompatibilityPriority); + default: + KASSERT(res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64, + ("should never happen")); + gran = res->Data.ExtAddress64.Granularity; + min = res->Data.ExtAddress64.Minimum; + max = res->Data.ExtAddress64.Maximum; + length = res->Data.ExtAddress64.AddressLength; + name = "ExtAddress64"; break; - case ACPI_RESOURCE_TYPE_END_DEPENDENT: - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "end dependent functions\n")); - set->set_end_dependent(dev, context); + } + if (length <= 0) break; - case ACPI_RESOURCE_TYPE_ADDRESS32: - if (res->Data.Address32.AddressLength <= 0) - break; - if (res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "ignored Address32 %s producer\n", - res->Data.Address32.ResourceType == ACPI_IO_RANGE ? - "IO" : "Memory")); - break; - } - if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE && - res->Data.Address32.ResourceType != ACPI_IO_RANGE) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "ignored Address32 for non-memory, non-I/O\n")); - break; - } + if (res->Data.Address.ProducerConsumer != ACPI_CONSUMER) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "ignored %s %s producer\n", name, + acpi_address_range_name(res->Data.Address.ResourceType))); + break; + } + if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && + res->Data.Address.ResourceType != ACPI_IO_RANGE) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "ignored %s for non-memory, non-I/O\n", name)); + break; + } - if (res->Data.Address32.MinAddressFixed == ACPI_ADDRESS_FIXED && - res->Data.Address32.MaxAddressFixed == ACPI_ADDRESS_FIXED) { - - if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address32/Memory 0x%x/%d\n", - res->Data.Address32.Minimum, - res->Data.Address32.AddressLength)); - set->set_memory(dev, context, - res->Data.Address32.Minimum, - res->Data.Address32.AddressLength); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address32/IO 0x%x/%d\n", - res->Data.Address32.Minimum, - res->Data.Address32.AddressLength)); - set->set_ioport(dev, context, - res->Data.Address32.Minimum, - res->Data.Address32.AddressLength); - } - } else { - if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address32/Memory 0x%x-0x%x/%d\n", - res->Data.Address32.Minimum, - res->Data.Address32.Maximum, - res->Data.Address32.AddressLength)); - set->set_memoryrange(dev, context, - res->Data.Address32.Minimum, - res->Data.Address32.Maximum, - res->Data.Address32.AddressLength, - res->Data.Address32.Granularity); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address32/IO 0x%x-0x%x/%d\n", - res->Data.Address32.Minimum, - res->Data.Address32.Maximum, - res->Data.Address32.AddressLength)); - set->set_iorange(dev, context, - res->Data.Address32.Minimum, - res->Data.Address32.Maximum, - res->Data.Address32.AddressLength, - res->Data.Address32.Granularity); - } - } +#ifdef __i386__ + if (min > ULONG_MAX || (res->Data.Address.MaxAddressFixed && max > + ULONG_MAX)) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored %s above 4G\n", + name)); break; - case ACPI_RESOURCE_TYPE_ADDRESS16: - if (res->Data.Address16.AddressLength <= 0) - break; - if (res->Data.Address16.ProducerConsumer != ACPI_CONSUMER) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "ignored Address16 %s producer\n", - res->Data.Address16.ResourceType == ACPI_IO_RANGE ? - "IO" : "Memory")); - break; + } + if (max > ULONG_MAX) + max = ULONG_MAX; +#endif + if (res->Data.Address.MinAddressFixed == ACPI_ADDRESS_FIXED && + res->Data.Address.MaxAddressFixed == ACPI_ADDRESS_FIXED) { + if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/Memory 0x%jx/%ju\n", + name, (uintmax_t)min, (uintmax_t)length)); + set->set_memory(dev, arc->context, min, length); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx/%ju\n", name, + (uintmax_t)min, (uintmax_t)length)); + set->set_ioport(dev, arc->context, min, length); } - if (res->Data.Address16.ResourceType != ACPI_MEMORY_RANGE && - res->Data.Address16.ResourceType != ACPI_IO_RANGE) { + } else { + if (res->Data.Address32.ResourceType == ACPI_MEMORY_RANGE) { ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "ignored Address16 for non-memory, non-I/O\n")); - break; - } - - if (res->Data.Address16.MinAddressFixed == ACPI_ADDRESS_FIXED && - res->Data.Address16.MaxAddressFixed == ACPI_ADDRESS_FIXED) { - - if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address16/Memory 0x%x/%d\n", - res->Data.Address16.Minimum, - res->Data.Address16.AddressLength)); - set->set_memory(dev, context, - res->Data.Address16.Minimum, - res->Data.Address16.AddressLength); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address16/IO 0x%x/%d\n", - res->Data.Address16.Minimum, - res->Data.Address16.AddressLength)); - set->set_ioport(dev, context, - res->Data.Address16.Minimum, - res->Data.Address16.AddressLength); - } + "%s/Memory 0x%jx-0x%jx/%ju\n", name, (uintmax_t)min, + (uintmax_t)max, (uintmax_t)length)); + set->set_memoryrange(dev, arc->context, min, max, length, gran); } else { - if (res->Data.Address16.ResourceType == ACPI_MEMORY_RANGE) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address16/Memory 0x%x-0x%x/%d\n", - res->Data.Address16.Minimum, - res->Data.Address16.Maximum, - res->Data.Address16.AddressLength)); - set->set_memoryrange(dev, context, - res->Data.Address16.Minimum, - res->Data.Address16.Maximum, - res->Data.Address16.AddressLength, - res->Data.Address16.Granularity); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "Address16/IO 0x%x-0x%x/%d\n", - res->Data.Address16.Minimum, - res->Data.Address16.Maximum, - res->Data.Address16.AddressLength)); - set->set_iorange(dev, context, - res->Data.Address16.Minimum, - res->Data.Address16.Maximum, - res->Data.Address16.AddressLength, - res->Data.Address16.Granularity); - } - } - break; - case ACPI_RESOURCE_TYPE_ADDRESS64: - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "unimplemented Address64 resource\n")); - break; - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "ignored ExtIRQ producer\n")); - break; + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "%s/IO 0x%jx-0x%jx/%ju\n", + name, (uintmax_t)min, (uintmax_t)max, (uintmax_t)length)); + set->set_iorange(dev, arc->context, min, max, length, gran); } - set->set_ext_irq(dev, context, res->Data.ExtendedIrq.Interrupts, - res->Data.ExtendedIrq.InterruptCount, - res->Data.ExtendedIrq.Triggering, - res->Data.ExtendedIrq.Polarity); - break; - case ACPI_RESOURCE_TYPE_VENDOR: - ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, - "unimplemented VendorSpecific resource\n")); - break; - default: + } + break; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + if (res->Data.ExtendedIrq.ProducerConsumer != ACPI_CONSUMER) { + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, "ignored ExtIRQ producer\n")); break; } - } + set->set_ext_irq(dev, arc->context, res->Data.ExtendedIrq.Interrupts, + res->Data.ExtendedIrq.InterruptCount, + res->Data.ExtendedIrq.Triggering, res->Data.ExtendedIrq.Polarity); + break; + case ACPI_RESOURCE_TYPE_VENDOR: + ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, + "unimplemented VendorSpecific resource\n")); + break; + default: + break; + } + return (AE_OK); +} + +/* + * Fetch a device's resources and associate them with the device. + * + * Note that it might be nice to also locate ACPI-specific resource items, such + * as GPE bits. + * + * We really need to split the resource-fetching code out from the + * resource-parsing code, since we may want to use the parsing + * code for _PRS someday. + */ +ACPI_STATUS +acpi_parse_resources(device_t dev, ACPI_HANDLE handle, + struct acpi_parse_resource_set *set, void *arg) +{ + struct acpi_resource_context arc; + ACPI_STATUS status; - AcpiOsFree(buf.Pointer); - set->set_done(dev, context); + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + set->set_init(dev, arg, &arc.context); + arc.set = set; + arc.dev = dev; + status = AcpiWalkResources(handle, "_CRS", acpi_parse_resource, &arc); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printf("can't fetch resources for %s - %s\n", + acpi_name(handle), AcpiFormatException(status)); + return_ACPI_STATUS (status); + } + set->set_done(dev, arc.context); return_ACPI_STATUS (AE_OK); } @@ -475,20 +422,20 @@ acpi_parse_resources(device_t dev, ACPI_HANDLE handle, static void acpi_res_set_init(device_t dev, void *arg, void **context); static void acpi_res_set_done(device_t dev, void *context); static void acpi_res_set_ioport(device_t dev, void *context, - u_int32_t base, u_int32_t length); + uint64_t base, uint64_t length); static void acpi_res_set_iorange(device_t dev, void *context, - u_int32_t low, u_int32_t high, - u_int32_t length, u_int32_t align); + uint64_t low, uint64_t high, + uint64_t length, uint64_t align); static void acpi_res_set_memory(device_t dev, void *context, - u_int32_t base, u_int32_t length); + uint64_t base, uint64_t length); static void acpi_res_set_memoryrange(device_t dev, void *context, - u_int32_t low, u_int32_t high, - u_int32_t length, u_int32_t align); -static void acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, + uint64_t low, uint64_t high, + uint64_t length, uint64_t align); +static void acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count, int trig, int pol); static void acpi_res_set_ext_irq(device_t dev, void *context, - u_int32_t *irq, int count, int trig, int pol); -static void acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, + uint32_t *irq, int count, int trig, int pol); +static void acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count); static void acpi_res_set_start_dependent(device_t dev, void *context, int preference); @@ -539,8 +486,8 @@ acpi_res_set_done(device_t dev, void *context) } static void -acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, - u_int32_t length) +acpi_res_set_ioport(device_t dev, void *context, uint64_t base, + uint64_t length) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -550,8 +497,8 @@ acpi_res_set_ioport(device_t dev, void *context, u_int32_t base, } static void -acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, - u_int32_t high, u_int32_t length, u_int32_t align) +acpi_res_set_iorange(device_t dev, void *context, uint64_t low, + uint64_t high, uint64_t length, uint64_t align) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -561,8 +508,8 @@ acpi_res_set_iorange(device_t dev, void *context, u_int32_t low, } static void -acpi_res_set_memory(device_t dev, void *context, u_int32_t base, - u_int32_t length) +acpi_res_set_memory(device_t dev, void *context, uint64_t base, + uint64_t length) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -573,8 +520,8 @@ acpi_res_set_memory(device_t dev, void *context, u_int32_t base, } static void -acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, - u_int32_t high, u_int32_t length, u_int32_t align) +acpi_res_set_memoryrange(device_t dev, void *context, uint64_t low, + uint64_t high, uint64_t length, uint64_t align) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -584,7 +531,7 @@ acpi_res_set_memoryrange(device_t dev, void *context, u_int32_t low, } static void -acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, int count, +acpi_res_set_irq(device_t dev, void *context, uint8_t *irq, int count, int trig, int pol) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -600,7 +547,7 @@ acpi_res_set_irq(device_t dev, void *context, u_int8_t *irq, int count, } static void -acpi_res_set_ext_irq(device_t dev, void *context, u_int32_t *irq, int count, +acpi_res_set_ext_irq(device_t dev, void *context, uint32_t *irq, int count, int trig, int pol) { struct acpi_res_context *cp = (struct acpi_res_context *)context; @@ -616,7 +563,7 @@ acpi_res_set_ext_irq(device_t dev, void *context, u_int32_t *irq, int count, } static void -acpi_res_set_drq(device_t dev, void *context, u_int8_t *drq, int count) +acpi_res_set_drq(device_t dev, void *context, uint8_t *drq, int count) { struct acpi_res_context *cp = (struct acpi_res_context *)context; diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c index 7226b6c..18996bd 100644 --- a/sys/dev/acpica/acpi_thermal.c +++ b/sys/dev/acpica/acpi_thermal.c @@ -36,7 +36,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kthread.h> #include <sys/malloc.h> #include <sys/module.h> -#include <sys/bus.h> #include <sys/proc.h> #include <sys/reboot.h> #include <sys/sysctl.h> diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index a74cd75..8735776 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -355,19 +355,19 @@ BOOLEAN acpi_MatchHid(ACPI_HANDLE h, const char *hid); struct acpi_parse_resource_set { void (*set_init)(device_t dev, void *arg, void **context); void (*set_done)(device_t dev, void *context); - void (*set_ioport)(device_t dev, void *context, uint32_t base, - uint32_t length); - void (*set_iorange)(device_t dev, void *context, uint32_t low, - uint32_t high, uint32_t length, uint32_t align); - void (*set_memory)(device_t dev, void *context, uint32_t base, - uint32_t length); - void (*set_memoryrange)(device_t dev, void *context, uint32_t low, - uint32_t high, uint32_t length, uint32_t align); - void (*set_irq)(device_t dev, void *context, u_int8_t *irq, + void (*set_ioport)(device_t dev, void *context, uint64_t base, + uint64_t length); + void (*set_iorange)(device_t dev, void *context, uint64_t low, + uint64_t high, uint64_t length, uint64_t align); + void (*set_memory)(device_t dev, void *context, uint64_t base, + uint64_t length); + void (*set_memoryrange)(device_t dev, void *context, uint64_t low, + uint64_t high, uint64_t length, uint64_t align); + void (*set_irq)(device_t dev, void *context, uint8_t *irq, int count, int trig, int pol); - void (*set_ext_irq)(device_t dev, void *context, u_int32_t *irq, + void (*set_ext_irq)(device_t dev, void *context, uint32_t *irq, int count, int trig, int pol); - void (*set_drq)(device_t dev, void *context, u_int8_t *drq, + void (*set_drq)(device_t dev, void *context, uint8_t *drq, int count); void (*set_start_dependent)(device_t dev, void *context, int preference); diff --git a/sys/dev/an/if_an.c b/sys/dev/an/if_an.c index 645fe41..0898961 100644 --- a/sys/dev/an/if_an.c +++ b/sys/dev/an/if_an.c @@ -102,7 +102,6 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/module.h> -#include <sys/sysctl.h> #include <sys/bus.h> #include <machine/bus.h> #include <sys/rman.h> diff --git a/sys/dev/ath/ah_osdep.c b/sys/dev/ath/ah_osdep.c index b14bba0..cfcfc4a 100644 --- a/sys/dev/ath/ah_osdep.c +++ b/sys/dev/ath/ah_osdep.c @@ -81,29 +81,10 @@ SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0, "Atheros HAL parameters"); #ifdef AH_DEBUG int ath_hal_debug = 0; SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RW, &ath_hal_debug, - 0, "Atheros HAL debugging printfs"); + 0, "Atheros HAL debugging printfs"); TUNABLE_INT("hw.ath.hal.debug", &ath_hal_debug); #endif /* AH_DEBUG */ -int ath_hal_ar5416_biasadj = 0; -SYSCTL_INT(_hw_ath_hal, OID_AUTO, ar5416_biasadj, CTLFLAG_RW, - &ath_hal_ar5416_biasadj, 0, "Enable 2ghz AR5416 direction sensitivity" - " bias adjust"); - -/* NB: these are deprecated; they exist for now for compatibility */ -int ath_hal_dma_beacon_response_time = 2; /* in TU's */ -SYSCTL_INT(_hw_ath_hal, OID_AUTO, dma_brt, CTLFLAG_RW, - &ath_hal_dma_beacon_response_time, 0, - "Atheros HAL DMA beacon response time"); -int ath_hal_sw_beacon_response_time = 10; /* in TU's */ -SYSCTL_INT(_hw_ath_hal, OID_AUTO, sw_brt, CTLFLAG_RW, - &ath_hal_sw_beacon_response_time, 0, - "Atheros HAL software beacon response time"); -int ath_hal_additional_swba_backoff = 0; /* in TU's */ -SYSCTL_INT(_hw_ath_hal, OID_AUTO, swba_backoff, CTLFLAG_RW, - &ath_hal_additional_swba_backoff, 0, - "Atheros HAL additional SWBA backoff time"); - MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data"); void* @@ -146,7 +127,7 @@ ath_hal_ether_sprintf(const u_int8_t *mac) void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...) { - if ((mask == HAL_DEBUG_UNMASKABLE) || (ath_hal_debug & mask)) { + if ((mask == HAL_DEBUG_UNMASKABLE) || (ah->ah_config.ah_debug & mask)) { __va_list ap; va_start(ap, fmt); ath_hal_vprintf(ah, fmt, ap); diff --git a/sys/dev/ath/ath_hal/ah.h b/sys/dev/ath/ath_hal/ah.h index 7a01be3..f81e6aa 100644 --- a/sys/dev/ath/ath_hal/ah.h +++ b/sys/dev/ath/ath_hal/ah.h @@ -756,6 +756,17 @@ struct dfs_event { }; typedef struct dfs_event HAL_DFS_EVENT; +typedef struct +{ + int ah_debug; /* only used if AH_DEBUG is defined */ + int ah_ar5416_biasadj; /* enable AR2133 radio specific bias fiddling */ + + /* NB: these are deprecated; they exist for now for compatibility */ + int ah_dma_beacon_response_time;/* in TU's */ + int ah_sw_beacon_response_time; /* in TU's */ + int ah_additional_swba_backoff; /* in TU's */ +}HAL_OPS_CONFIG; + /* * Hardware Access Layer (HAL) API. * @@ -784,6 +795,7 @@ struct ath_hal { uint16_t *ah_eepromdata; /* eeprom buffer, if needed */ + HAL_OPS_CONFIG ah_config; const HAL_RATE_TABLE *__ahdecl(*ah_getRateTable)(struct ath_hal *, u_int mode); void __ahdecl(*ah_detach)(struct ath_hal*); diff --git a/sys/dev/ath/ath_hal/ah_eeprom_9287.h b/sys/dev/ath/ath_hal/ah_eeprom_9287.h index d429c39..ff8080a 100644 --- a/sys/dev/ath/ath_hal/ah_eeprom_9287.h +++ b/sys/dev/ath/ath_hal/ah_eeprom_9287.h @@ -31,6 +31,8 @@ #define AR9287_EEP_MINOR_VER_b AR9287_EEP_MINOR_VER #define AR9287_EEP_NO_BACK_VER AR9287_EEP_MINOR_VER_1 +#define AR9287_RDEXT_DEFAULT 0x1F + #define AR9287_EEP_START_LOC 128 #define AR9287_HTC_EEP_START_LOC 256 #define AR9287_NUM_2G_CAL_PIERS 3 diff --git a/sys/dev/ath/ath_hal/ah_internal.h b/sys/dev/ath/ath_hal/ah_internal.h index d66c9d8..120620c 100644 --- a/sys/dev/ath/ath_hal/ah_internal.h +++ b/sys/dev/ath/ath_hal/ah_internal.h @@ -475,12 +475,6 @@ isBigEndian(void) #define OS_A_REG_RMW_FIELD(_a, _r, _f, _v) \ do { OS_REG_WRITE(_a, _r, (OS_REG_READ(_a, _r) &~ (_f)) | (((_v) << _f##_S) & (_f))) ; OS_DELAY(100); } while (0) -/* system-configurable parameters */ -extern int ath_hal_dma_beacon_response_time; /* in TU's */ -extern int ath_hal_sw_beacon_response_time; /* in TU's */ -extern int ath_hal_additional_swba_backoff; /* in TU's */ -extern int ath_hal_ar5416_biasadj; /* 1 or 0 */ - /* wait for the register contents to have the specified value */ extern HAL_BOOL ath_hal_wait(struct ath_hal *, u_int reg, uint32_t mask, uint32_t val); @@ -504,11 +498,29 @@ extern void ath_hal_free(void *); /* common debugging interfaces */ #ifdef AH_DEBUG #include "ah_debug.h" -extern int ath_hal_debug; +extern int ath_hal_debug; /* Global debug flags */ + +/* + * This is used for global debugging, when ahp doesn't yet have the + * related debugging state. For example, during probe/attach. + */ +#define HALDEBUG_G(_ah, __m, ...) \ + do { \ + if ((__m) == HAL_DEBUG_UNMASKABLE || \ + ath_hal_debug & (__m)) { \ + DO_HALDEBUG((_ah), (__m), __VA_ARGS__); \ + } \ + } while (0); + +/* + * This is used for local debugging, when ahp isn't NULL and + * thus may have debug flags set. + */ #define HALDEBUG(_ah, __m, ...) \ do { \ if ((__m) == HAL_DEBUG_UNMASKABLE || \ - (ath_hal_debug & (__m))) { \ + ath_hal_debug & (__m) || \ + (_ah)->ah_config.ah_debug & (__m)) { \ DO_HALDEBUG((_ah), (__m), __VA_ARGS__); \ } \ } while(0); @@ -516,7 +528,8 @@ extern int ath_hal_debug; extern void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...) __printflike(3,4); #else -#define HALDEBUG(_ah, __m, _fmt, ...) +#define HALDEBUG(_ah, __m, ...) +#define HALDEBUG_G(_ah, __m, ...) #endif /* AH_DEBUG */ /* diff --git a/sys/dev/ath/ath_hal/ah_regdomain.c b/sys/dev/ath/ath_hal/ah_regdomain.c index c17d0f6..9aae332 100644 --- a/sys/dev/ath/ath_hal/ah_regdomain.c +++ b/sys/dev/ath/ath_hal/ah_regdomain.c @@ -167,7 +167,7 @@ isEepromValid(struct ath_hal *ah) if (regDomainPairs[i].regDmnEnum == rd) return AH_TRUE; } - HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, + HALDEBUG_G(ah, HAL_DEBUG_REGDOMAIN, "%s: invalid regulatory domain/country code 0x%x\n", __func__, rd); return AH_FALSE; } @@ -609,7 +609,7 @@ ath_hal_mapgsm(int sku, int freq) return 1544 + freq; if (sku == SKU_SR9) return 3344 - freq; - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot map freq %u unknown gsm sku %u\n", __func__, freq, sku); return freq; diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c index 2068733..41d957a 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_attach.c @@ -181,14 +181,14 @@ ar5210Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS ecode; int i; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: devid 0x%x sc %p st %p sh %p\n", __func__, devid, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof (struct ath_hal_5210)); if (ahp == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: no memory for state block\n", __func__); ecode = HAL_ENOMEM; goto bad; diff --git a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c index dbd059e..a613c9c 100644 --- a/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c +++ b/sys/dev/ath/ath_hal/ar5210/ar5210_beacon.c @@ -56,9 +56,9 @@ ar5210BeaconInit(struct ath_hal *ah, if (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA) { bt.bt_nextdba = (next_beacon - - ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ bt.bt_nextswba = (next_beacon - - ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ /* * The SWBA interrupt is not used for beacons in ad hoc mode * as we don't yet support ATIMs. So since the beacon never diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c index 308ecc9..14daa0b 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_attach.c @@ -200,13 +200,13 @@ ar5211Attach(uint16_t devid, HAL_SOFTC sc, uint16_t eeval; HAL_STATUS ecode; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof (struct ath_hal_5211)); if (ahp == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); ecode = HAL_ENOMEM; goto bad; diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c index 669b8f6..31e9c5d 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_beacon.c @@ -71,9 +71,9 @@ ar5211BeaconInit(struct ath_hal *ah, case HAL_M_IBSS: case HAL_M_HOSTAP: bt.bt_nextdba = (next_beacon - - ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ bt.bt_nextswba = (next_beacon - - ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ break; } /* diff --git a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c index 3af314f..e1e7f73 100644 --- a/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c +++ b/sys/dev/ath/ath_hal/ar5211/ar5211_xmit.c @@ -345,8 +345,9 @@ ar5211ResetTxQueue(struct ath_hal *ah, u_int q) | AR_Q_MISC_CBR_INCR_DIS0 | AR_Q_MISC_RDYTIME_EXP_POLICY); value = (ahp->ah_beaconInterval - - (ath_hal_sw_beacon_response_time - ath_hal_dma_beacon_response_time) - - ath_hal_additional_swba_backoff) * 1024; + - (ah->ah_config.ah_sw_beacon_response_time + - ah->ah_config.ah_dma_beacon_response_time) + - ah->ah_config.ah_additional_swba_backoff) * 1024; OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_EN); /* Configure DCU for CAB */ diff --git a/sys/dev/ath/ath_hal/ar5212/ar5112.c b/sys/dev/ath/ath_hal/ar5212/ar5112.c index c1920b9..1003068 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5112.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5112.c @@ -611,7 +611,7 @@ getFullPwrTable(uint16_t numPcdacs, uint16_t *pcdacs, int16_t *power, int16_t ma uint16_t idxR = 1; if (numPcdacs < 2) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: at least 2 pcdac values needed [%d]\n", __func__, numPcdacs); return AH_FALSE; diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c index 8e7f3cb..01c0e2c 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_attach.c @@ -317,13 +317,13 @@ ar5212Attach(uint16_t devid, HAL_SOFTC sc, uint16_t eeval; HAL_STATUS ecode; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof (struct ath_hal_5212)); if (ahp == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c index 538f8b8..bf0b38a 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_beacon.c @@ -84,9 +84,9 @@ ar5212BeaconInit(struct ath_hal *ah, case HAL_M_HOSTAP: case HAL_M_IBSS: bt.bt_nextdba = (next_beacon - - ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ bt.bt_nextswba = (next_beacon - - ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ break; } /* diff --git a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c index 4fbce31..3c6ddc0 100644 --- a/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c +++ b/sys/dev/ath/ath_hal/ar5212/ar5212_xmit.c @@ -416,9 +416,9 @@ ar5212ResetTxQueue(struct ath_hal *ah, u_int q) * here solely for backwards compatibility. */ value = (ahp->ah_beaconInterval - - (ath_hal_sw_beacon_response_time - - ath_hal_dma_beacon_response_time) - - ath_hal_additional_swba_backoff) * 1024; + - (ah->ah_config.ah_sw_beacon_response_time - + ah->ah_config.ah_dma_beacon_response_time) + - ah->ah_config.ah_additional_swba_backoff) * 1024; OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_ENA); } dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, diff --git a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c index 4ca1a4d..d1689d5 100644 --- a/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c +++ b/sys/dev/ath/ath_hal/ar5312/ar5312_attach.c @@ -71,13 +71,13 @@ ar5312Attach(uint16_t devid, HAL_SOFTC sc, uint16_t eeval; HAL_STATUS ecode; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, st, (void*) sh); /* NB: memory is returned zero'd */ ahp = ath_hal_malloc(sizeof (struct ath_hal_5212)); if (ahp == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar5416/ar2133.c b/sys/dev/ath/ath_hal/ar5416/ar2133.c index f92ea00..f25c108 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar2133.c +++ b/sys/dev/ath/ath_hal/ar5416/ar2133.c @@ -185,7 +185,7 @@ ar2133SetChannel(struct ath_hal *ah, const struct ieee80211_channel *chan) } /* Workaround for hw bug - AR5416 specific */ - if (AR_SREV_OWL(ah) && ath_hal_ar5416_biasadj) + if (AR_SREV_OWL(ah) && ah->ah_config.ah_ar5416_biasadj) ar2133ForceBias(ah, freq); reg32 = (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c index e636325..607f97a 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_attach.c @@ -241,7 +241,7 @@ ar5416Attach(uint16_t devid, HAL_SOFTC sc, HAL_STATUS ecode; HAL_BOOL rfStatus; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ @@ -250,7 +250,7 @@ ar5416Attach(uint16_t devid, HAL_SOFTC sc, sizeof(ar5416Addac) ); if (ahp5416 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c index 358a0ee..66b5053 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_beacon.c @@ -93,9 +93,9 @@ ar5416BeaconInit(struct ath_hal *ah, /* fall thru... */ case HAL_M_HOSTAP: bt.bt_nextdba = (next_beacon - - ath_hal_dma_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_dma_beacon_response_time) << 3; /* 1/8 TU */ bt.bt_nextswba = (next_beacon - - ath_hal_sw_beacon_response_time) << 3; /* 1/8 TU */ + ah->ah_config.ah_sw_beacon_response_time) << 3; /* 1/8 TU */ bt.bt_flags |= AR_TIMER_MODE_TBTT | AR_TIMER_MODE_DBA | AR_TIMER_MODE_SWBA; diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c index 2332656..6266b58 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_misc.c @@ -288,7 +288,7 @@ ar5416SetQuiet(struct ath_hal *ah, uint32_t period, uint32_t duration, nextStart_us += OS_REG_READ(ah, AR_TSF_L32); } if (flag & HAL_QUIET_ADD_SWBA_RESP_TIME) { - nextStart_us += ath_hal_sw_beacon_response_time; + nextStart_us += ah->ah_config.ah_sw_beacon_response_time; } OS_REG_RMW_FIELD(ah, AR_QUIET1, AR_QUIET1_QUIET_ACK_CTS_ENABLE, 1); OS_REG_WRITE(ah, AR_QUIET2, SM(duration, AR_QUIET2_QUIET_DUR)); diff --git a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c index 48956c5..20791e8 100644 --- a/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c +++ b/sys/dev/ath/ath_hal/ar5416/ar5416_xmit.c @@ -1035,9 +1035,9 @@ ar5416ResetTxQueue(struct ath_hal *ah, u_int q) * here solely for backwards compatibility. */ value = (ahp->ah_beaconInterval - - (ath_hal_sw_beacon_response_time - - ath_hal_dma_beacon_response_time) - - ath_hal_additional_swba_backoff) * 1024; + - (ah->ah_config.ah_sw_beacon_response_time - + ah->ah_config.ah_dma_beacon_response_time) + - ah->ah_config.ah_additional_swba_backoff) * 1024; OS_REG_WRITE(ah, AR_QRDYTIMECFG(q), value | AR_Q_RDYTIMECFG_ENA); } dmisc |= SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, diff --git a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c index 2a3f3f0..518ed85 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9130_attach.c @@ -78,13 +78,13 @@ ar9130Attach(uint16_t devid, HAL_SOFTC sc, HAL_STATUS ecode; HAL_BOOL rfStatus; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); if (ahp5416 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c index 44a549d..a87d1ad 100644 --- a/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c +++ b/sys/dev/ath/ath_hal/ar9001/ar9160_attach.c @@ -101,13 +101,13 @@ ar9160Attach(uint16_t devid, HAL_SOFTC sc, HAL_STATUS ecode; HAL_BOOL rfStatus; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp5416 = ath_hal_malloc(sizeof (struct ath_hal_5416)); if (ahp5416 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c index ebe3be1..3743c21 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9280_attach.c @@ -120,13 +120,13 @@ ar9280Attach(uint16_t devid, HAL_SOFTC sc, int8_t pwr_table_offset; uint8_t pwr; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); if (ahp9280 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c index 9120313..2547148 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9285_attach.c @@ -118,13 +118,13 @@ ar9285Attach(uint16_t devid, HAL_SOFTC sc, HAL_STATUS ecode; HAL_BOOL rfStatus; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); if (ahp9285 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; diff --git a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c index 9cbe0a5..ed9feb8 100644 --- a/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c +++ b/sys/dev/ath/ath_hal/ar9002/ar9287_attach.c @@ -119,13 +119,13 @@ ar9287Attach(uint16_t devid, HAL_SOFTC sc, HAL_BOOL rfStatus; int8_t pwr_table_offset; - HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", + HALDEBUG_G(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9287 = ath_hal_malloc(sizeof (struct ath_hal_9287)); if (ahp9287 == AH_NULL) { - HALDEBUG(AH_NULL, HAL_DEBUG_ANY, + HALDEBUG_G(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; @@ -320,6 +320,7 @@ ar9287Attach(uint16_t devid, HAL_SOFTC sc, /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); + AH_PRIVATE(ah)->ah_currentRDext = AR9287_RDEXT_DEFAULT; /* * ah_miscMode is populated by ar5416FillCapabilityInfo() diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 6c7b0e7..35592d9 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -528,6 +528,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ | IEEE80211_C_BGSCAN /* capable of bg scanning */ | IEEE80211_C_TXFRAG /* handle tx frags */ +#ifdef ATH_ENABLE_DFS + | IEEE80211_C_DFS /* Enable DFS radar detection */ +#endif ; /* * Query the hal to figure out h/w crypto support. @@ -738,6 +741,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) */ ath_sysctlattach(sc); ath_sysctl_stats_attach(sc); + ath_sysctl_hal_attach(sc); if (bootverbose) ieee80211_announce(ic); @@ -1286,6 +1290,8 @@ ath_resume(struct ath_softc *sc) HAL_GPIO_MUX_MAC_NETWORK_LED); ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon); } + + /* XXX beacons ? */ } void @@ -1588,6 +1594,12 @@ ath_init(void *arg) sc->sc_lastani = 0; sc->sc_lastshortcal = 0; sc->sc_doresetcal = AH_FALSE; + /* + * Beacon timers were cleared here; give ath_newstate() + * a hint that the beacon timers should be poked when + * things transition to the RUN state. + */ + sc->sc_beacons = 0; /* * Setup the hardware after reset: the key cache @@ -4464,6 +4476,19 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) ath_chan_change(sc, chan); /* + * Reset clears the beacon timers; reset them + * here if needed. + */ + if (sc->sc_beacons) { /* restart beacons */ +#ifdef IEEE80211_SUPPORT_TDMA + if (sc->sc_tdma) + ath_tdma_config(sc, NULL); + else +#endif + ath_beacon_config(sc, NULL); + } + + /* * Re-enable interrupts. */ ath_hal_intrset(ah, sc->sc_imask); @@ -4668,6 +4693,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct ieee80211_node *ni = NULL; int i, error, stamode; u_int32_t rfilt; + int csa_run_transition = 0; static const HAL_LED_STATE leds[] = { HAL_LED_INIT, /* IEEE80211_S_INIT */ HAL_LED_SCAN, /* IEEE80211_S_SCAN */ @@ -4683,6 +4709,9 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) ieee80211_state_name[vap->iv_state], ieee80211_state_name[nstate]); + if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN) + csa_run_transition = 1; + callout_drain(&sc->sc_cal_ch); ath_hal_setledstate(ah, leds[nstate]); /* set LED */ @@ -4789,8 +4818,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) * Defer beacon timer configuration to the next * beacon frame so we have a current TSF to use * (any TSF collected when scanning is likely old). + * However if it's due to a CSA -> RUN transition, + * force a beacon update so we pick up a lack of + * beacons from an AP in CAC and thus force a + * scan. */ sc->sc_syncbeacon = 1; + if (csa_run_transition) + ath_beacon_config(sc, vap); break; case IEEE80211_M_MONITOR: /* diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c index 6c1a6b2..e3c9966 100644 --- a/sys/dev/ath/if_ath_sysctl.c +++ b/sys/dev/ath/if_ath_sysctl.c @@ -719,3 +719,43 @@ ath_sysctl_stats_attach(struct ath_softc *sc) /* Attach the RX phy error array */ ath_sysctl_stats_attach_rxphyerr(sc, child); } + +/* + * This doesn't necessarily belong here (because it's HAL related, not + * driver related). + */ +void +ath_sysctl_hal_attach(struct ath_softc *sc) +{ + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + + tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "hal", CTLFLAG_RD, + NULL, "Atheros HAL parameters"); + child = SYSCTL_CHILDREN(tree); + + sc->sc_ah->ah_config.ah_debug = 0; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_debug, 0, "Atheros HAL debugging printfs"); + + sc->sc_ah->ah_config.ah_ar5416_biasadj = 0; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "ar5416_biasadj", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_ar5416_biasadj, 0, + "Enable 2ghz AR5416 direction sensitivity bias adjust"); + + sc->sc_ah->ah_config.ah_dma_beacon_response_time = 2; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "dma_brt", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_dma_beacon_response_time, 0, + "Atheros HAL DMA beacon response time"); + + sc->sc_ah->ah_config.ah_sw_beacon_response_time = 10; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "sw_brt", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_sw_beacon_response_time, 0, + "Atheros HAL software beacon response time"); + + sc->sc_ah->ah_config.ah_additional_swba_backoff = 0; + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "swba_backoff", CTLFLAG_RW, + &sc->sc_ah->ah_config.ah_additional_swba_backoff, 0, + "Atheros HAL additional SWBA backoff time"); +} diff --git a/sys/dev/ath/if_ath_sysctl.h b/sys/dev/ath/if_ath_sysctl.h index f96a73e..1fef2be 100644 --- a/sys/dev/ath/if_ath_sysctl.h +++ b/sys/dev/ath/if_ath_sysctl.h @@ -34,5 +34,5 @@ extern void ath_sysctlattach(struct ath_softc *); extern void ath_sysctl_stats_attach(struct ath_softc *sc); - +extern void ath_sysctl_hal_attach(struct ath_softc *sc); #endif diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index 3352a56..ca1ef4b 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -369,6 +369,14 @@ decode_tuple_end(device_t cbdev, device_t child, int id, * Functions to read the a tuple from the card */ +/* + * Read CIS bytes out of the config space. We have to read it 4 bytes at a + * time and do the usual mask and shift to return the bytes. The standard + * defines the byte order to be little endian. pci_read_config converts it to + * host byte order. This is why we have no endian conversion functions: the + * shifts wind up being endian neutral. This is also why we avoid the obvious + * memcpy optimization. + */ static int cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) @@ -379,12 +387,11 @@ cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, loc = start + *off; - e = pci_read_config(child, loc - loc % 4, 4); - for (j = loc % 4; j > 0; j--) - e >>= 8; + e = pci_read_config(child, loc & ~0x3, 4); + e >>= 8 * (loc & 0x3); *len = 0; for (i = loc, j = -2; j < *len; j++, i++) { - if (i % 4 == 0) + if ((i & 0x3) == 0) e = pci_read_config(child, i, 4); if (j == -2) *tupleid = 0xff & e; @@ -398,6 +405,10 @@ cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start, return (0); } +/* + * Read the CIS data out of memroy. We indirect through the bus space + * routines to ensure proper byte ordering conversions when necessary. + */ static int cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start, uint32_t *off, int *tupleid, int *len, uint8_t *tupledata) @@ -580,7 +591,7 @@ cardbus_parse_cis(device_t cbdev, device_t child, expect_linktarget = TRUE; if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) { DEVPRINTF((cbdev, "Warning: CIS pointer is 0: (no CIS)\n")); - return (ENXIO); + return (0); } DEVPRINTF((cbdev, "CIS pointer is %#x\n", start)); off = 0; diff --git a/sys/dev/dc/dcphy.c b/sys/dev/dc/dcphy.c index f4fc512..5c60ad5 100644 --- a/sys/dev/dc/dcphy.c +++ b/sys/dev/dc/dcphy.c @@ -62,7 +62,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/resource.h> -#include <sys/bus.h> #include <dev/pci/pcivar.h> diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 772eede..b9567de 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -1385,7 +1385,7 @@ dc_netcfg_wait(struct dc_softc *sc) break; DELAY(10); } - if (i == DC_TIMEOUT) { + if (i == DC_TIMEOUT && bus_child_present(sc->dc_dev)) { if (!(isr & DC_ISR_TX_IDLE) && !DC_IS_ASIX(sc)) device_printf(sc->dc_dev, "%s: failed to force tx to idle state\n", __func__); diff --git a/sys/dev/dc/pnphy.c b/sys/dev/dc/pnphy.c index 6468fbf..6546acd 100644 --- a/sys/dev/dc/pnphy.c +++ b/sys/dev/dc/pnphy.c @@ -60,7 +60,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/resource.h> -#include <sys/bus.h> #include <dev/dc/if_dcreg.h> diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c index 156f8b2..4d8ba65 100644 --- a/sys/dev/e1000/if_em.c +++ b/sys/dev/e1000/if_em.c @@ -330,42 +330,71 @@ MODULE_DEPEND(em, ether, 1, 1, 1); #define CSUM_TSO 0 #endif +SYSCTL_NODE(_hw, OID_AUTO, em, CTLFLAG_RD, 0, "EM driver parameters"); + static int em_tx_int_delay_dflt = EM_TICKS_TO_USECS(EM_TIDV); static int em_rx_int_delay_dflt = EM_TICKS_TO_USECS(EM_RDTR); TUNABLE_INT("hw.em.tx_int_delay", &em_tx_int_delay_dflt); TUNABLE_INT("hw.em.rx_int_delay", &em_rx_int_delay_dflt); +SYSCTL_INT(_hw_em, OID_AUTO, tx_int_delay, CTLFLAG_RDTUN, &em_tx_int_delay_dflt, + 0, "Default transmit interrupt delay in usecs"); +SYSCTL_INT(_hw_em, OID_AUTO, rx_int_delay, CTLFLAG_RDTUN, &em_rx_int_delay_dflt, + 0, "Default receive interrupt delay in usecs"); static int em_tx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_TADV); static int em_rx_abs_int_delay_dflt = EM_TICKS_TO_USECS(EM_RADV); TUNABLE_INT("hw.em.tx_abs_int_delay", &em_tx_abs_int_delay_dflt); TUNABLE_INT("hw.em.rx_abs_int_delay", &em_rx_abs_int_delay_dflt); +SYSCTL_INT(_hw_em, OID_AUTO, tx_abs_int_delay, CTLFLAG_RDTUN, + &em_tx_abs_int_delay_dflt, 0, + "Default transmit interrupt delay limit in usecs"); +SYSCTL_INT(_hw_em, OID_AUTO, rx_abs_int_delay, CTLFLAG_RDTUN, + &em_rx_abs_int_delay_dflt, 0, + "Default receive interrupt delay limit in usecs"); static int em_rxd = EM_DEFAULT_RXD; static int em_txd = EM_DEFAULT_TXD; TUNABLE_INT("hw.em.rxd", &em_rxd); TUNABLE_INT("hw.em.txd", &em_txd); +SYSCTL_INT(_hw_em, OID_AUTO, rxd, CTLFLAG_RDTUN, &em_rxd, 0, + "Number of receive descriptors per queue"); +SYSCTL_INT(_hw_em, OID_AUTO, txd, CTLFLAG_RDTUN, &em_txd, 0, + "Number of transmit descriptors per queue"); static int em_smart_pwr_down = FALSE; TUNABLE_INT("hw.em.smart_pwr_down", &em_smart_pwr_down); +SYSCTL_INT(_hw_em, OID_AUTO, smart_pwr_down, CTLFLAG_RDTUN, &em_smart_pwr_down, + 0, "Set to true to leave smart power down enabled on newer adapters"); /* Controls whether promiscuous also shows bad packets */ static int em_debug_sbp = FALSE; TUNABLE_INT("hw.em.sbp", &em_debug_sbp); +SYSCTL_INT(_hw_em, OID_AUTO, sbp, CTLFLAG_RDTUN, &em_debug_sbp, 0, + "Show bad packets in promiscuous mode"); static int em_enable_msix = TRUE; TUNABLE_INT("hw.em.enable_msix", &em_enable_msix); +SYSCTL_INT(_hw_em, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &em_enable_msix, 0, + "Enable MSI-X interrupts"); /* How many packets rxeof tries to clean at a time */ static int em_rx_process_limit = 100; TUNABLE_INT("hw.em.rx_process_limit", &em_rx_process_limit); +SYSCTL_INT(_hw_em, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, + &em_rx_process_limit, 0, + "Maximum number of received packets to process at a time, -1 means unlimited"); /* Flow control setting - default to FULL */ static int em_fc_setting = e1000_fc_full; TUNABLE_INT("hw.em.fc_setting", &em_fc_setting); +SYSCTL_INT(_hw_em, OID_AUTO, fc_setting, CTLFLAG_RDTUN, &em_fc_setting, 0, + "Flow control"); /* Energy efficient ethernet - default to OFF */ static int eee_setting = 0; TUNABLE_INT("hw.em.eee_setting", &eee_setting); +SYSCTL_INT(_hw_em, OID_AUTO, eee_setting, CTLFLAG_RDTUN, &eee_setting, 0, + "Enable Energy Efficient Ethernet"); /* Global used in WOL setup with multiport cards */ static int global_quad_port_a = 0; diff --git a/sys/dev/e1000/if_igb.c b/sys/dev/e1000/if_igb.c index 08735ac..972b745 100644 --- a/sys/dev/e1000/if_igb.c +++ b/sys/dev/e1000/if_igb.c @@ -300,11 +300,17 @@ MODULE_DEPEND(igb, ether, 1, 1, 1); * Tunable default values. *********************************************************************/ +SYSCTL_NODE(_hw, OID_AUTO, igb, CTLFLAG_RD, 0, "IGB driver parameters"); + /* Descriptor defaults */ static int igb_rxd = IGB_DEFAULT_RXD; static int igb_txd = IGB_DEFAULT_TXD; TUNABLE_INT("hw.igb.rxd", &igb_rxd); TUNABLE_INT("hw.igb.txd", &igb_txd); +SYSCTL_INT(_hw_igb, OID_AUTO, rxd, CTLFLAG_RDTUN, &igb_rxd, 0, + "Number of receive descriptors per queue"); +SYSCTL_INT(_hw_igb, OID_AUTO, txd, CTLFLAG_RDTUN, &igb_txd, 0, + "Number of transmit descriptors per queue"); /* ** AIM: Adaptive Interrupt Moderation @@ -314,6 +320,8 @@ TUNABLE_INT("hw.igb.txd", &igb_txd); */ static int igb_enable_aim = TRUE; TUNABLE_INT("hw.igb.enable_aim", &igb_enable_aim); +SYSCTL_INT(_hw_igb, OID_AUTO, enable_aim, CTLFLAG_RW, &igb_enable_aim, 0, + "Enable adaptive interrupt moderation"); /* * MSIX should be the default for best performance, @@ -321,12 +329,16 @@ TUNABLE_INT("hw.igb.enable_aim", &igb_enable_aim); */ static int igb_enable_msix = 1; TUNABLE_INT("hw.igb.enable_msix", &igb_enable_msix); +SYSCTL_INT(_hw_igb, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &igb_enable_msix, 0, + "Enable MSI-X interrupts"); /* ** Tuneable Interrupt rate */ static int igb_max_interrupt_rate = 8000; TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate); +SYSCTL_INT(_hw_igb, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, + &igb_max_interrupt_rate, 0, "Maximum interrupts per second"); /* ** Header split causes the packet header to @@ -338,6 +350,8 @@ TUNABLE_INT("hw.igb.max_interrupt_rate", &igb_max_interrupt_rate); */ static bool igb_header_split = FALSE; TUNABLE_INT("hw.igb.hdr_split", &igb_header_split); +SYSCTL_INT(_hw_igb, OID_AUTO, header_split, CTLFLAG_RDTUN, &igb_header_split, 0, + "Enable receive mbuf header split"); /* ** This will autoconfigure based on @@ -345,6 +359,15 @@ TUNABLE_INT("hw.igb.hdr_split", &igb_header_split); */ static int igb_num_queues = 0; TUNABLE_INT("hw.igb.num_queues", &igb_num_queues); +SYSCTL_INT(_hw_igb, OID_AUTO, num_queues, CTLFLAG_RDTUN, &igb_num_queues, 0, + "Number of queues to configure, 0 indicates autoconfigure"); + +/* How many packets rxeof tries to clean at a time */ +static int igb_rx_process_limit = 100; +TUNABLE_INT("hw.igb.rx_process_limit", &igb_rx_process_limit); +SYSCTL_INT(_hw_igb, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, + &igb_rx_process_limit, 0, + "Maximum number of received packets to process at a time, -1 means unlimited"); /********************************************************************* * Device identification routine @@ -431,10 +454,9 @@ igb_attach(device_t dev) OID_AUTO, "nvm", CTLTYPE_INT|CTLFLAG_RW, adapter, 0, igb_sysctl_nvm_info, "I", "NVM Information"); - SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "enable_aim", CTLTYPE_INT|CTLFLAG_RW, - &igb_enable_aim, 1, "Interrupt Moderation"); + igb_set_sysctl_value(adapter, "enable_aim", + "Interrupt Moderation", &adapter->enable_aim, + igb_enable_aim); SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), @@ -465,7 +487,7 @@ igb_attach(device_t dev) /* Sysctl for limiting the amount of work done in the taskqueue */ igb_set_sysctl_value(adapter, "rx_processing_limit", "max number of rx packets to process", - &adapter->rx_process_limit, 100); + &adapter->rx_process_limit, igb_rx_process_limit); /* * Validate number of transmit and receive descriptors. It @@ -1494,7 +1516,7 @@ igb_msix_que(void *arg) more_rx = igb_rxeof(que, adapter->rx_process_limit, NULL); - if (igb_enable_aim == FALSE) + if (adapter->enable_aim == FALSE) goto no_calc; /* ** Do Adaptive Interrupt Moderation: diff --git a/sys/dev/e1000/if_igb.h b/sys/dev/e1000/if_igb.h index f0ab685..80abf6e 100644 --- a/sys/dev/e1000/if_igb.h +++ b/sys/dev/e1000/if_igb.h @@ -402,6 +402,7 @@ struct adapter { u16 link_duplex; u32 smartspeed; u32 dmac; + int enable_aim; /* Interface queues */ struct igb_queue *queues; diff --git a/sys/dev/en/if_en_pci.c b/sys/dev/en/if_en_pci.c index 09ba8bc..3886c9e 100644 --- a/sys/dev/en/if_en_pci.c +++ b/sys/dev/en/if_en_pci.c @@ -44,9 +44,6 @@ __FBSDID("$FreeBSD$"); * thanks to Matt Thomas for figuring out FreeBSD vs NetBSD vs etc.. diffs. */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> diff --git a/sys/dev/et/if_et.c b/sys/dev/et/if_et.c index 82c6217..9bd68e8 100644 --- a/sys/dev/et/if_et.c +++ b/sys/dev/et/if_et.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include <net/if_types.h> #include <net/bpf.h> #include <net/if_arp.h> -#include <net/if_dl.h> #include <net/if_media.h> #include <net/if_vlan_var.h> diff --git a/sys/dev/fdc/fdc_pccard.c b/sys/dev/fdc/fdc_pccard.c index 72a3568..d959060 100644 --- a/sys/dev/fdc/fdc_pccard.c +++ b/sys/dev/fdc/fdc_pccard.c @@ -38,8 +38,6 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <machine/bus.h> -#include <machine/bus.h> - #include <dev/fdc/fdcvar.h> #include <dev/pccard/pccardvar.h> #include "pccarddevs.h" diff --git a/sys/dev/firewire/fwohci.c b/sys/dev/firewire/fwohci.c index cccbc8c..4b147b2 100644 --- a/sys/dev/firewire/fwohci.c +++ b/sys/dev/firewire/fwohci.c @@ -2072,8 +2072,9 @@ fwohci_check_stat(struct fwohci_softc *sc) FW_GLOCK_ASSERT(&sc->fc); stat = OREAD(sc, FWOHCI_INTSTAT); if (stat == 0xffffffff) { - device_printf(sc->fc.dev, - "device physically ejected?\n"); + if (!bus_child_present(sc->fc.dev)) + return (FILTER_HANDLED); + device_printf(sc->fc.dev, "device physically ejected?\n"); return (FILTER_STRAY); } if (stat) diff --git a/sys/dev/fxp/if_fxp.c b/sys/dev/fxp/if_fxp.c index e02d580..62c8dc2 100644 --- a/sys/dev/fxp/if_fxp.c +++ b/sys/dev/fxp/if_fxp.c @@ -3012,8 +3012,10 @@ static uint32_t fxp_ucode_d101a[] = D101_A_RCVBUNDLE_UCODE; static uint32_t fxp_ucode_d101b0[] = D101_B0_RCVBUNDLE_UCODE; static uint32_t fxp_ucode_d101ma[] = D101M_B_RCVBUNDLE_UCODE; static uint32_t fxp_ucode_d101s[] = D101S_RCVBUNDLE_UCODE; +#ifdef notyet static uint32_t fxp_ucode_d102[] = D102_B_RCVBUNDLE_UCODE; static uint32_t fxp_ucode_d102c[] = D102_C_RCVBUNDLE_UCODE; +#endif static uint32_t fxp_ucode_d102e[] = D102_E_RCVBUNDLE_UCODE; #define UCODE(x) x, sizeof(x)/sizeof(uint32_t) @@ -3031,12 +3033,16 @@ static const struct ucode { D101M_CPUSAVER_DWORD, D101M_CPUSAVER_BUNDLE_MAX_DWORD }, { FXP_REV_82559S_A, UCODE(fxp_ucode_d101s), D101S_CPUSAVER_DWORD, D101S_CPUSAVER_BUNDLE_MAX_DWORD }, +#ifdef notyet { FXP_REV_82550, UCODE(fxp_ucode_d102), D102_B_CPUSAVER_DWORD, D102_B_CPUSAVER_BUNDLE_MAX_DWORD }, { FXP_REV_82550_C, UCODE(fxp_ucode_d102c), D102_C_CPUSAVER_DWORD, D102_C_CPUSAVER_BUNDLE_MAX_DWORD }, +#endif { FXP_REV_82551_F, UCODE(fxp_ucode_d102e), D102_E_CPUSAVER_DWORD, D102_E_CPUSAVER_BUNDLE_MAX_DWORD }, + { FXP_REV_82551_10, UCODE(fxp_ucode_d102e), + D102_E_CPUSAVER_DWORD, D102_E_CPUSAVER_BUNDLE_MAX_DWORD }, { 0, NULL, 0, 0, 0 } }; diff --git a/sys/dev/gem/if_gem.c b/sys/dev/gem/if_gem.c index 9ee43f2..7f44f22 100644 --- a/sys/dev/gem/if_gem.c +++ b/sys/dev/gem/if_gem.c @@ -121,7 +121,7 @@ static void gem_rint_timeout(void *arg); #endif static inline void gem_rxcksum(struct mbuf *m, uint64_t flags); static void gem_rxdrain(struct gem_softc *sc); -static void gem_setladrf(struct gem_softc *sc); +static void gem_setladrf(struct gem_softc *sc, u_int enable); static void gem_start(struct ifnet *ifp); static void gem_start_locked(struct ifnet *ifp); static void gem_stop(struct ifnet *ifp, int disable); @@ -705,7 +705,7 @@ gem_reset_rx(struct gem_softc *sc) * Resetting while DMA is in progress can cause a bus hang, so we * disable DMA first. */ - gem_disable_rx(sc); + (void)gem_disable_rx(sc); GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, 0); GEM_BANK1_BARRIER(sc, GEM_RX_CONFIG, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); @@ -715,7 +715,7 @@ gem_reset_rx(struct gem_softc *sc) /* Wait 5ms extra. */ DELAY(5000); - /* Finally, reset the ERX. */ + /* Reset the ERX. */ GEM_BANK2_WRITE_4(sc, GEM_RESET, GEM_RESET_RX); GEM_BANK2_BARRIER(sc, GEM_RESET, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); @@ -724,6 +724,16 @@ gem_reset_rx(struct gem_softc *sc) device_printf(sc->sc_dev, "cannot reset receiver\n"); return (1); } + + /* Finally, reset RX MAC. */ + GEM_BANK1_WRITE_4(sc, GEM_MAC_RXRESET, 1); + GEM_BANK1_BARRIER(sc, GEM_MAC_RXRESET, 4, + BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); + if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RXRESET, 1, 0)) { + device_printf(sc->sc_dev, "cannot reset RX MAC\n"); + return (1); + } + return (0); } @@ -766,12 +776,17 @@ gem_reset_rxdma(struct gem_softc *sc) GEM_BANK1_WRITE_4(sc, GEM_RX_PAUSE_THRESH, (3 * sc->sc_rxfifosize / 256) | ((sc->sc_rxfifosize / 256) << 12)); + /* + * Clear the RX filter and reprogram it. This will also set the + * current RX MAC configuration. + */ + gem_setladrf(sc, 0); GEM_BANK1_WRITE_4(sc, GEM_RX_CONFIG, GEM_BANK1_READ_4(sc, GEM_RX_CONFIG) | GEM_RX_CONFIG_RXDMA_EN); GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_MASK, GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, - GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG) | GEM_MAC_RX_ENABLE); + sc->sc_mac_rxcfg | GEM_MAC_RX_ENABLE); } static int @@ -782,7 +797,7 @@ gem_reset_tx(struct gem_softc *sc) * Resetting while DMA is in progress can cause a bus hang, so we * disable DMA first. */ - gem_disable_tx(sc); + (void)gem_disable_tx(sc); GEM_BANK1_WRITE_4(sc, GEM_TX_CONFIG, 0); GEM_BANK1_BARRIER(sc, GEM_TX_CONFIG, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); @@ -812,8 +827,10 @@ gem_disable_rx(struct gem_softc *sc) GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG) & ~GEM_MAC_RX_ENABLE); GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - return (GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, - 0)); + if (GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) + return (1); + device_printf(sc->sc_dev, "cannot disable RX MAC\n"); + return (0); } static int @@ -824,8 +841,10 @@ gem_disable_tx(struct gem_softc *sc) GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG) & ~GEM_MAC_TX_ENABLE); GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - return (GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, - 0)); + if (GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) + return (1); + device_printf(sc->sc_dev, "cannot disable TX MAC\n"); + return (0); } static int @@ -960,7 +979,7 @@ gem_init_locked(struct gem_softc *sc) gem_init_regs(sc); /* step 5. RX MAC registers & counters */ - gem_setladrf(sc); + gem_setladrf(sc, 0); /* step 6 & 7. Program Descriptor Ring Base Addresses. */ /* NOTE: we use only 32-bit DMA addresses here. */ @@ -1050,21 +1069,14 @@ gem_init_locked(struct gem_softc *sc) /* step 12. RX_MAC Configuration Register */ v = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); v |= GEM_MAC_RX_ENABLE | GEM_MAC_RX_STRIP_CRC; - GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 0); - GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) - device_printf(sc->sc_dev, "cannot configure RX MAC\n"); + (void)gem_disable_rx(sc); + sc->sc_mac_rxcfg = v & ~GEM_MAC_RX_ENABLE; GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); /* step 13. TX_MAC Configuration Register */ v = GEM_BANK1_READ_4(sc, GEM_MAC_TX_CONFIG); v |= GEM_MAC_TX_ENABLE; - GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 0); - GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) - device_printf(sc->sc_dev, "cannot configure TX MAC\n"); + (void)gem_disable_tx(sc); GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, v); /* step 14. Issue Transmit Pending command. */ @@ -1588,7 +1600,7 @@ gem_rint(struct gem_softc *sc) * the buffer that's already attached to this descriptor. */ if (gem_add_rxbuf(sc, sc->sc_rxptr) != 0) { - ifp->if_ierrors++; + ifp->if_iqdrops++; GEM_INIT_RXDESC(sc, sc->sc_rxptr); m = NULL; } @@ -2028,8 +2040,8 @@ gem_mii_statchg(device_t dev) * the GEM Gigabit Ethernet ASIC Specification. */ - rxcfg = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); - rxcfg &= ~(GEM_MAC_RX_CARR_EXTEND | GEM_MAC_RX_ENABLE); + rxcfg = sc->sc_mac_rxcfg; + rxcfg &= ~GEM_MAC_RX_CARR_EXTEND; txcfg = GEM_MAC_TX_ENA_IPG0 | GEM_MAC_TX_NGU | GEM_MAC_TX_NGU_LIMIT; if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0) txcfg |= GEM_MAC_TX_IGN_CARRIER | GEM_MAC_TX_IGN_COLLIS; @@ -2037,17 +2049,9 @@ gem_mii_statchg(device_t dev) rxcfg |= GEM_MAC_RX_CARR_EXTEND; txcfg |= GEM_MAC_TX_CARR_EXTEND; } - GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, 0); - GEM_BANK1_BARRIER(sc, GEM_MAC_TX_CONFIG, 4, - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) - device_printf(sc->sc_dev, "cannot disable TX MAC\n"); + (void)gem_disable_tx(sc); GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, txcfg); - GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, 0); - GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, - BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) - device_printf(sc->sc_dev, "cannot disable RX MAC\n"); + (void)gem_disable_rx(sc); GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, rxcfg); v = GEM_BANK1_READ_4(sc, GEM_MAC_CONTROL_CONFIG) & @@ -2092,6 +2096,7 @@ gem_mii_statchg(device_t dev) v |= GEM_MAC_XIF_FDPLX_LED; GEM_BANK1_WRITE_4(sc, GEM_MAC_XIF_CONFIG, v); + sc->sc_mac_rxcfg = rxcfg; if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && (sc->sc_flags & GEM_LINK) != 0) { GEM_BANK1_WRITE_4(sc, GEM_MAC_TX_CONFIG, @@ -2147,7 +2152,7 @@ gem_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 && ((ifp->if_flags ^ sc->sc_ifflags) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) - gem_setladrf(sc); + gem_setladrf(sc, 1); else gem_init_locked(sc); } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) @@ -2164,7 +2169,8 @@ gem_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) case SIOCADDMULTI: case SIOCDELMULTI: GEM_LOCK(sc); - gem_setladrf(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + gem_setladrf(sc, 1); GEM_UNLOCK(sc); break; case SIOCGIFMEDIA: @@ -2189,7 +2195,7 @@ gem_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } static void -gem_setladrf(struct gem_softc *sc) +gem_setladrf(struct gem_softc *sc, u_int enable) { struct ifnet *ifp = sc->sc_ifp; struct ifmultiaddr *inm; @@ -2199,24 +2205,20 @@ gem_setladrf(struct gem_softc *sc) GEM_LOCK_ASSERT(sc, MA_OWNED); - /* Get the current RX configuration. */ - v = GEM_BANK1_READ_4(sc, GEM_MAC_RX_CONFIG); - /* - * Turn off promiscuous mode, promiscuous group mode (all multicast), - * and hash filter. Depending on the case, the right bit will be - * enabled. + * Turn off the RX MAC and the hash filter as required by the Sun GEM + * programming restrictions. */ - v &= ~(GEM_MAC_RX_PROMISCUOUS | GEM_MAC_RX_HASH_FILTER | - GEM_MAC_RX_PROMISC_GRP); - + v = sc->sc_mac_rxcfg & ~GEM_MAC_RX_HASH_FILTER; GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); GEM_BANK1_BARRIER(sc, GEM_MAC_RX_CONFIG, 4, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); - if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_HASH_FILTER, - 0)) - device_printf(sc->sc_dev, "cannot disable RX hash filter\n"); + if (!GEM_BANK1_BITWAIT(sc, GEM_MAC_RX_CONFIG, GEM_MAC_RX_HASH_FILTER | + GEM_MAC_RX_ENABLE, 0)) + device_printf(sc->sc_dev, + "cannot disable RX MAC or hash filter\n"); + v &= ~(GEM_MAC_RX_PROMISCUOUS | GEM_MAC_RX_PROMISC_GRP); if ((ifp->if_flags & IFF_PROMISC) != 0) { v |= GEM_MAC_RX_PROMISCUOUS; goto chipit; @@ -2262,5 +2264,8 @@ gem_setladrf(struct gem_softc *sc) hash[i]); chipit: + sc->sc_mac_rxcfg = v; + if (enable) + v |= GEM_MAC_RX_ENABLE; GEM_BANK1_WRITE_4(sc, GEM_MAC_RX_CONFIG, v); } diff --git a/sys/dev/gem/if_gemvar.h b/sys/dev/gem/if_gemvar.h index 59cb582..d89a322 100644 --- a/sys/dev/gem/if_gemvar.h +++ b/sys/dev/gem/if_gemvar.h @@ -173,6 +173,8 @@ struct gem_softc { u_int sc_rxptr; /* next ready RX descriptor/state */ u_int sc_rxfifosize; /* RX FIFO size (bytes) */ + uint32_t sc_mac_rxcfg; /* RX MAC conf. % GEM_MAC_RX_ENABLE */ + int sc_ifflags; u_long sc_csum_features; }; diff --git a/sys/dev/iicbus/if_ic.c b/sys/dev/iicbus/if_ic.c index 4a05b16..6ac6401 100644 --- a/sys/dev/iicbus/if_ic.c +++ b/sys/dev/iicbus/if_ic.c @@ -49,9 +49,6 @@ __FBSDID("$FreeBSD$"); #include <net/if_types.h> #include <net/netisr.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <net/netisr.h> #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> diff --git a/sys/dev/mfi/mfi_cam.c b/sys/dev/mfi/mfi_cam.c index 5137c36..747b6c0 100644 --- a/sys/dev/mfi/mfi_cam.c +++ b/sys/dev/mfi/mfi_cam.c @@ -54,12 +54,9 @@ __FBSDID("$FreeBSD$"); #include <cam/scsi/scsi_all.h> #include <cam/scsi/scsi_message.h> -#include <sys/bus.h> -#include <sys/conf.h> #include <machine/md_var.h> #include <machine/bus.h> #include <machine/resource.h> -#include <sys/rman.h> #include <dev/mfi/mfireg.h> #include <dev/mfi/mfi_ioctl.h> diff --git a/sys/dev/mii/e1000phy.c b/sys/dev/mii/e1000phy.c index b0d7069..e657592 100644 --- a/sys/dev/mii/e1000phy.c +++ b/sys/dev/mii/e1000phy.c @@ -107,6 +107,7 @@ static const struct mii_phydesc e1000phys[] = { MII_PHY_DESC(xxMARVELL, E1116), MII_PHY_DESC(xxMARVELL, E1116R), MII_PHY_DESC(xxMARVELL, E1118), + MII_PHY_DESC(xxMARVELL, E1149R), MII_PHY_DESC(xxMARVELL, E3016), MII_PHY_DESC(xxMARVELL, PHYG65G), MII_PHY_END @@ -147,6 +148,7 @@ e1000phy_attach(device_t dev) sc->mii_flags |= MIIF_HAVEFIBER; break; case MII_MODEL_xxMARVELL_E1149: + case MII_MODEL_xxMARVELL_E1149R: /* * Some 88E1149 PHY's page select is initialized to * point to other bank instead of copper/fiber bank @@ -208,6 +210,7 @@ e1000phy_reset(struct mii_softc *sc) case MII_MODEL_xxMARVELL_E1116: case MII_MODEL_xxMARVELL_E1118: case MII_MODEL_xxMARVELL_E1149: + case MII_MODEL_xxMARVELL_E1149R: case MII_MODEL_xxMARVELL_PHYG65G: /* Disable energy detect mode. */ reg &= ~E1000_SCR_EN_DETECT_MASK; @@ -240,7 +243,8 @@ e1000phy_reset(struct mii_softc *sc) PHY_WRITE(sc, E1000_SCR, reg); if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1116 || - sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149) { + sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149 || + sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1149R) { PHY_WRITE(sc, E1000_EADR, 2); reg = PHY_READ(sc, E1000_SCR); reg |= E1000_SCR_RGMII_POWER_UP; diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs index 5274940..1b98542 100644 --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -248,6 +248,7 @@ model xxMARVELL E1111 0x000c Marvell 88E1111 Gigabit PHY model xxMARVELL E1116 0x0021 Marvell 88E1116 Gigabit PHY model xxMARVELL E1116R 0x0024 Marvell 88E1116R Gigabit PHY model xxMARVELL E1118 0x0022 Marvell 88E1118 Gigabit PHY +model xxMARVELL E1149R 0x0025 Marvell 88E1149R Quad Gigabit PHY model xxMARVELL E3016 0x0026 Marvell 88E3016 10/100 Fast Ethernet PHY model xxMARVELL PHYG65G 0x0027 Marvell PHYG65G Gigabit PHY model MARVELL E1000 0x0005 Marvell 88E1000 Gigabit PHY diff --git a/sys/dev/my/if_my.c b/sys/dev/my/if_my.c index 951473a..4b59c48 100644 --- a/sys/dev/my/if_my.c +++ b/sys/dev/my/if_my.c @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/queue.h> #include <sys/types.h> -#include <sys/bus.h> #include <sys/module.h> #include <sys/lock.h> #include <sys/mutex.h> diff --git a/sys/dev/pccbb/pccbb_pci.c b/sys/dev/pccbb/pccbb_pci.c index c89e5ad..6cdc4e4 100644 --- a/sys/dev/pccbb/pccbb_pci.c +++ b/sys/dev/pccbb/pccbb_pci.c @@ -658,6 +658,12 @@ cbb_pci_shutdown(device_t brdev) struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); /* + * We're about to pull the rug out from the card, so mark it as + * gone to prevent harm. + */ + sc->cardok = 0; + + /* * Place the cards in reset, turn off the interrupts and power * down the socket. */ diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 9cd5a1c..b346dd3 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -297,7 +297,7 @@ static int pci_usb_takeover = 1; static int pci_usb_takeover = 0; #endif TUNABLE_INT("hw.pci.usb_early_takeover", &pci_usb_takeover); -SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RD | CTLFLAG_TUN, +SYSCTL_INT(_hw_pci, OID_AUTO, usb_early_takeover, CTLFLAG_RDTUN, &pci_usb_takeover, 1, "Enable early takeover of USB controllers.\n\ Disable this if you depend on BIOS emulation of USB devices, that is\n\ you use USB devices (like keyboard or mouse) but do not load USB drivers"); @@ -2482,7 +2482,8 @@ pci_write_bar(device_t dev, struct pci_map *pm, pci_addr_t base) pci_write_config(dev, pm->pm_reg + 4, base >> 32, 4); pm->pm_value = pci_read_config(dev, pm->pm_reg, 4); if (ln2range == 64) - pm->pm_value |= (pci_addr_t)pci_read_config(dev, pm->pm_reg + 4, 4) << 32; + pm->pm_value |= (pci_addr_t)pci_read_config(dev, + pm->pm_reg + 4, 4) << 32; } struct pci_map * @@ -2680,7 +2681,7 @@ pci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, count = (pci_addr_t)1 << mapsize; if (basezero || base == pci_mapbase(testval)) { start = 0; /* Let the parent decide. */ - end = ~0ULL; + end = ~0ul; } else { start = base; end = base + count - 1; diff --git a/sys/dev/pci/pci_pci.c b/sys/dev/pci/pci_pci.c index da8465c..93bbf3a 100644 --- a/sys/dev/pci/pci_pci.c +++ b/sys/dev/pci/pci_pci.c @@ -38,16 +38,12 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/bus.h> #include <sys/kernel.h> -#include <sys/libkern.h> #include <sys/malloc.h> #include <sys/module.h> #include <sys/rman.h> #include <sys/sysctl.h> #include <sys/systm.h> -#include <machine/bus.h> -#include <machine/resource.h> - #include <dev/pci/pcivar.h> #include <dev/pci/pcireg.h> #include <dev/pci/pci_private.h> @@ -1432,91 +1428,3 @@ pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) bus = device_get_parent(pcib); return (PCIB_POWER_FOR_SLEEP(bus, dev, pstate)); } - -/* - * Try to read the bus number of a host-PCI bridge using appropriate config - * registers. - */ -int -host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, - uint8_t *busnum) -{ - uint32_t id; - - id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); - if (id == 0xffffffff) - return (0); - - switch (id) { - case 0x12258086: - /* Intel 824?? */ - /* XXX This is a guess */ - /* *busnum = read_config(bus, slot, func, 0x41, 1); */ - *busnum = bus; - break; - case 0x84c48086: - /* Intel 82454KX/GX (Orion) */ - *busnum = read_config(bus, slot, func, 0x4a, 1); - break; - case 0x84ca8086: - /* - * For the 450nx chipset, there is a whole bundle of - * things pretending to be host bridges. The MIOC will - * be seen first and isn't really a pci bridge (the - * actual busses are attached to the PXB's). We need to - * read the registers of the MIOC to figure out the - * bus numbers for the PXB channels. - * - * Since the MIOC doesn't have a pci bus attached, we - * pretend it wasn't there. - */ - return (0); - case 0x84cb8086: - switch (slot) { - case 0x12: - /* Intel 82454NX PXB#0, Bus#A */ - *busnum = read_config(bus, 0x10, func, 0xd0, 1); - break; - case 0x13: - /* Intel 82454NX PXB#0, Bus#B */ - *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; - break; - case 0x14: - /* Intel 82454NX PXB#1, Bus#A */ - *busnum = read_config(bus, 0x10, func, 0xd3, 1); - break; - case 0x15: - /* Intel 82454NX PXB#1, Bus#B */ - *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; - break; - } - break; - - /* ServerWorks -- vendor 0x1166 */ - case 0x00051166: - case 0x00061166: - case 0x00081166: - case 0x00091166: - case 0x00101166: - case 0x00111166: - case 0x00171166: - case 0x01011166: - case 0x010f1014: - case 0x01101166: - case 0x02011166: - case 0x02251166: - case 0x03021014: - *busnum = read_config(bus, slot, func, 0x44, 1); - break; - - /* Compaq/HP -- vendor 0x0e11 */ - case 0x60100e11: - *busnum = read_config(bus, slot, func, 0xc8, 1); - break; - default: - /* Don't know how to read bus number. */ - return 0; - } - - return 1; -} diff --git a/sys/dev/pci/pci_subr.c b/sys/dev/pci/pci_subr.c new file mode 100644 index 0000000..7f0c806 --- /dev/null +++ b/sys/dev/pci/pci_subr.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2011 Advanced Computing Technologies LLC + * Written by: John H. Baldwin <jhb@FreeBSD.org> + * 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$"); + +/* + * Support APIs for Host to PCI bridge drivers and drivers that + * provide PCI domains. + */ + +#include <sys/types.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcib_private.h> + +/* + * Try to read the bus number of a host-PCI bridge using appropriate config + * registers. + */ +int +host_pcib_get_busno(pci_read_config_fn read_config, int bus, int slot, int func, + uint8_t *busnum) +{ + uint32_t id; + + id = read_config(bus, slot, func, PCIR_DEVVENDOR, 4); + if (id == 0xffffffff) + return (0); + + switch (id) { + case 0x12258086: + /* Intel 824?? */ + /* XXX This is a guess */ + /* *busnum = read_config(bus, slot, func, 0x41, 1); */ + *busnum = bus; + break; + case 0x84c48086: + /* Intel 82454KX/GX (Orion) */ + *busnum = read_config(bus, slot, func, 0x4a, 1); + break; + case 0x84ca8086: + /* + * For the 450nx chipset, there is a whole bundle of + * things pretending to be host bridges. The MIOC will + * be seen first and isn't really a pci bridge (the + * actual busses are attached to the PXB's). We need to + * read the registers of the MIOC to figure out the + * bus numbers for the PXB channels. + * + * Since the MIOC doesn't have a pci bus attached, we + * pretend it wasn't there. + */ + return (0); + case 0x84cb8086: + switch (slot) { + case 0x12: + /* Intel 82454NX PXB#0, Bus#A */ + *busnum = read_config(bus, 0x10, func, 0xd0, 1); + break; + case 0x13: + /* Intel 82454NX PXB#0, Bus#B */ + *busnum = read_config(bus, 0x10, func, 0xd1, 1) + 1; + break; + case 0x14: + /* Intel 82454NX PXB#1, Bus#A */ + *busnum = read_config(bus, 0x10, func, 0xd3, 1); + break; + case 0x15: + /* Intel 82454NX PXB#1, Bus#B */ + *busnum = read_config(bus, 0x10, func, 0xd4, 1) + 1; + break; + } + break; + + /* ServerWorks -- vendor 0x1166 */ + case 0x00051166: + case 0x00061166: + case 0x00081166: + case 0x00091166: + case 0x00101166: + case 0x00111166: + case 0x00171166: + case 0x01011166: + case 0x010f1014: + case 0x01101166: + case 0x02011166: + case 0x02251166: + case 0x03021014: + *busnum = read_config(bus, slot, func, 0x44, 1); + break; + + /* Compaq/HP -- vendor 0x0e11 */ + case 0x60100e11: + *busnum = read_config(bus, slot, func, 0xc8, 1); + break; + default: + /* Don't know how to read bus number. */ + return 0; + } + + return 1; +} diff --git a/sys/dev/pty/pty.c b/sys/dev/pty/pty.c index 5a542cb..5e2d822 100644 --- a/sys/dev/pty/pty.c +++ b/sys/dev/pty/pty.c @@ -79,7 +79,7 @@ ptydev_fdopen(struct cdev *dev, int fflags, struct thread *td, struct file *fp) /* Raise a warning when a legacy PTY has been allocated. */ if (pty_warningcnt > 0) { pty_warningcnt--; - log(LOG_INFO, "pid %d (%s) is using legacy pty devices%s\n", + log(LOG_INFO, "pid %d (%s) is using legacy pty devices%s\n", td->td_proc->p_pid, td->td_name, pty_warningcnt ? "" : " - not logging anymore"); } @@ -139,8 +139,8 @@ static int pty_modevent(module_t mod, int type, void *data) { - switch(type) { - case MOD_LOAD: + switch(type) { + case MOD_LOAD: EVENTHANDLER_REGISTER(dev_clone, pty_clone, 0, 1000); make_dev_credf(MAKEDEV_ETERNAL_KLD, &ptmx_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0666, "ptmx"); diff --git a/sys/dev/sis/if_sis.c b/sys/dev/sis/if_sis.c index 63417a0..9290ff7 100644 --- a/sys/dev/sis/if_sis.c +++ b/sys/dev/sis/if_sis.c @@ -87,7 +87,6 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/resource.h> -#include <sys/bus.h> #include <sys/rman.h> #include <dev/mii/mii.h> diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c index 37d9965..b05ad2a 100644 --- a/sys/dev/snp/snp.c +++ b/sys/dev/snp/snp.c @@ -158,7 +158,7 @@ snp_read(struct cdev *dev, struct uio *uio, int flag) error = devfs_get_cdevpriv((void **)&ss); if (error != 0) return (error); - + tp = ss->snp_tty; if (tp == NULL || tty_gone(tp)) return (EIO); @@ -198,7 +198,7 @@ snp_write(struct cdev *dev, struct uio *uio, int flag) error = devfs_get_cdevpriv((void **)&ss); if (error != 0) return (error); - + tp = ss->snp_tty; if (tp == NULL || tty_gone(tp)) return (EIO); diff --git a/sys/dev/sound/macio/i2s.c b/sys/dev/sound/macio/i2s.c index d1a5463..e35a262 100644 --- a/sys/dev/sound/macio/i2s.c +++ b/sys/dev/sound/macio/i2s.c @@ -158,6 +158,8 @@ static int i2s_probe(device_t self) { const char *name; + phandle_t subchild; + char subchildname[255]; name = ofw_bus_get_name(self); if (!name) @@ -165,6 +167,16 @@ i2s_probe(device_t self) if (strcmp(name, "i2s") != 0) return (ENXIO); + + /* + * Do not attach to "lightshow" I2S devices on Xserves. This controller + * is used there to control the LEDs on the front panel, and this + * driver can't handle it. + */ + subchild = OF_child(OF_child(ofw_bus_get_node(self))); + if (subchild != 0 && OF_getprop(subchild, "name", subchildname, + sizeof(subchildname)) > 0 && strcmp(subchildname, "lightshow") == 0) + return (ENXIO); device_set_desc(self, "Apple I2S Audio Controller"); diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 4f8670a..f40ada7 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -531,6 +531,15 @@ static driver_t uaudio_driver = { .size = sizeof(struct uaudio_softc), }; +static const STRUCT_USB_HOST_ID __used uaudio_devs[] = { + /* Generic USB audio class match */ + {USB_IFACE_CLASS(UICLASS_AUDIO), + USB_IFACE_SUBCLASS(UISUBCLASS_AUDIOCONTROL),}, + /* Generic USB MIDI class match */ + {USB_IFACE_CLASS(UICLASS_AUDIO), + USB_IFACE_SUBCLASS(UISUBCLASS_MIDISTREAM),}, +}; + static int uaudio_probe(device_t dev) { diff --git a/sys/dev/syscons/scterm-teken.c b/sys/dev/syscons/scterm-teken.c index 1d110ab9..725f9f5 100644 --- a/sys/dev/syscons/scterm-teken.c +++ b/sys/dev/syscons/scterm-teken.c @@ -643,7 +643,7 @@ scteken_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) while (src < end) { sc_vtb_move(&scp->vtb, src, dst, width); - + src += scp->xsize; dst += scp->xsize; } @@ -658,7 +658,7 @@ scteken_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) while (src >= end) { sc_vtb_move(&scp->vtb, src, dst, width); - + src -= scp->xsize; dst -= scp->xsize; } diff --git a/sys/dev/tdfx/tdfx_pci.c b/sys/dev/tdfx/tdfx_pci.c index 770c672..27308a9 100644 --- a/sys/dev/tdfx/tdfx_pci.c +++ b/sys/dev/tdfx/tdfx_pci.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/bus.h> -#include <sys/cdefs.h> #include <sys/conf.h> #include <sys/fcntl.h> #include <sys/file.h> diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index 48a134b..c479022 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -113,6 +113,8 @@ static struct pci_id pci_ns8250_ids[] = { { 0x9710, 0x9820, 0x1000, 1, "NetMos NM9820 Serial Port", 0x10 }, { 0x9710, 0x9835, 0x1000, 1, "NetMos NM9835 Serial Port", 0x10 }, { 0x9710, 0x9865, 0xa000, 0x1000, "NetMos NM9865 Serial Port", 0x10 }, +{ 0x9710, 0x9900, 0xa000, 0x1000, + "MosChip MCS9900 PCIe to Peripheral Controller", 0x10 }, { 0x9710, 0x9901, 0xa000, 0x1000, "MosChip MCS9901 PCIe to Peripheral Controller", 0x10 }, { 0xdeaf, 0x9051, 0xffff, 0, "Middle Digital PC Weasel Serial Port", 0x10 }, diff --git a/sys/dev/usb/input/atp.c b/sys/dev/usb/input/atp.c index fab60a2..9a17950 100644 --- a/sys/dev/usb/input/atp.c +++ b/sys/dev/usb/input/atp.c @@ -240,7 +240,7 @@ struct atp_dev_params { }, }; -static const struct usb_device_id atp_devs[] = { +static const STRUCT_USB_HOST_ID atp_devs[] = { /* Core Duo MacBook & MacBook Pro */ { USB_VPI(USB_VENDOR_APPLE, 0x0217, ATP_DEV_PARAMS_0) }, { USB_VPI(USB_VENDOR_APPLE, 0x0218, ATP_DEV_PARAMS_0) }, diff --git a/sys/dev/usb/input/uep.c b/sys/dev/usb/input/uep.c index 048452d..e90298b 100644 --- a/sys/dev/usb/input/uep.c +++ b/sys/dev/usb/input/uep.c @@ -288,6 +288,12 @@ static const struct usb_config uep_config[UEP_N_TRANSFER] = { }, }; +static const STRUCT_USB_HOST_ID uep_devs[] = { + {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL, 0)}, + {USB_VPI(USB_VENDOR_EGALAX, USB_PRODUCT_EGALAX_TPANEL2, 0)}, + {USB_VPI(USB_VENDOR_EGALAX2, USB_PRODUCT_EGALAX2_TPANEL, 0)}, +}; + static int uep_probe(device_t dev) { @@ -295,17 +301,12 @@ uep_probe(device_t dev) if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); + if (uaa->info.bConfigIndex != 0) + return (ENXIO); + if (uaa->info.bIfaceIndex != 0) + return (ENXIO); - if ((uaa->info.idVendor == USB_VENDOR_EGALAX) && - ((uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL) || - (uaa->info.idProduct == USB_PRODUCT_EGALAX_TPANEL2))) - return (BUS_PROBE_SPECIFIC); - - if ((uaa->info.idVendor == USB_VENDOR_EGALAX2) && - (uaa->info.idProduct == USB_PRODUCT_EGALAX2_TPANEL)) - return (BUS_PROBE_SPECIFIC); - - return (ENXIO); + return (usbd_lookup_id_by_uaa(uep_devs, sizeof(uep_devs), uaa)); } static int diff --git a/sys/dev/usb/input/uhid.c b/sys/dev/usb/input/uhid.c index a7fd899..1da1203 100644 --- a/sys/dev/usb/input/uhid.c +++ b/sys/dev/usb/input/uhid.c @@ -607,29 +607,33 @@ uhid_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, return (error); } +static const STRUCT_USB_HOST_ID uhid_devs[] = { + /* generic HID class */ + {USB_IFACE_CLASS(UICLASS_HID),}, + /* the Xbox 360 gamepad doesn't use the HID class */ + {USB_IFACE_CLASS(UICLASS_VENDOR), + USB_IFACE_SUBCLASS(UISUBCLASS_XBOX360_CONTROLLER), + USB_IFACE_PROTOCOL(UIPROTO_XBOX360_GAMEPAD),}, +}; + static int uhid_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); + int error; DPRINTFN(11, "\n"); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } - if (uaa->info.bInterfaceClass != UICLASS_HID) { - /* the Xbox 360 gamepad doesn't use the HID class */ + error = usbd_lookup_id_by_uaa(uhid_devs, sizeof(uhid_devs), uaa); + if (error) + return (error); - if ((uaa->info.bInterfaceClass != UICLASS_VENDOR) || - (uaa->info.bInterfaceSubClass != UISUBCLASS_XBOX360_CONTROLLER) || - (uaa->info.bInterfaceProtocol != UIPROTO_XBOX360_GAMEPAD)) { - return (ENXIO); - } - } - if (usb_test_quirk(uaa, UQ_HID_IGNORE)) { + if (usb_test_quirk(uaa, UQ_HID_IGNORE)) return (ENXIO); - } + return (BUS_PROBE_GENERIC); } diff --git a/sys/dev/usb/input/ukbd.c b/sys/dev/usb/input/ukbd.c index 9182663..b03f884 100644 --- a/sys/dev/usb/input/ukbd.c +++ b/sys/dev/usb/input/ukbd.c @@ -745,6 +745,13 @@ static const struct usb_config ukbd_config[UKBD_N_TRANSFER] = { }, }; +/* A match on these entries will load ukbd */ +static const STRUCT_USB_HOST_ID __used ukbd_devs[] = { + {USB_IFACE_CLASS(UICLASS_HID), + USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), + USB_IFACE_PROTOCOL(UIPROTO_BOOT_KEYBOARD),}, +}; + static int ukbd_probe(device_t dev) { diff --git a/sys/dev/usb/input/ums.c b/sys/dev/usb/input/ums.c index af9aa1f..3c4f36e 100644 --- a/sys/dev/usb/input/ums.c +++ b/sys/dev/usb/input/ums.c @@ -355,6 +355,13 @@ static const struct usb_config ums_config[UMS_N_TRANSFER] = { }, }; +/* A match on these entries will load ums */ +static const STRUCT_USB_HOST_ID __used ums_devs[] = { + {USB_IFACE_CLASS(UICLASS_HID), + USB_IFACE_SUBCLASS(UISUBCLASS_BOOT), + USB_IFACE_PROTOCOL(UIPROTO_MOUSE),}, +}; + static int ums_probe(device_t dev) { diff --git a/sys/dev/usb/misc/udbp.c b/sys/dev/usb/misc/udbp.c index 38a4fee..1a72cae 100644 --- a/sys/dev/usb/misc/udbp.c +++ b/sys/dev/usb/misc/udbp.c @@ -288,40 +288,27 @@ udbp_modload(module_t mod, int event, void *data) return (error); } +static const STRUCT_USB_HOST_ID udbp_devs[] = { + {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_TURBOCONNECT, 0)}, + {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301, 0)}, + {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302, 0)}, + {USB_VPI(USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_EZLINK, 0)}, + {USB_VPI(USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB, 0)}, +}; + static int udbp_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != 0) + return (ENXIO); + if (uaa->info.bIfaceIndex != 0) return (ENXIO); - } - /* - * XXX Julian, add the id of the device if you have one to test - * things with. run 'usbdevs -v' and note the 3 ID's that appear. - * The Vendor Id and Product Id are in hex and the Revision Id is in - * bcd. But as usual if the revision is 0x101 then you should - * compare the revision id in the device descriptor with 0x101 Or go - * search the file usbdevs.h. Maybe the device is already in there. - */ - if (((uaa->info.idVendor == USB_VENDOR_NETCHIP) && - (uaa->info.idProduct == USB_PRODUCT_NETCHIP_TURBOCONNECT))) - return (0); - - if (((uaa->info.idVendor == USB_VENDOR_PROLIFIC) && - ((uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2301) || - (uaa->info.idProduct == USB_PRODUCT_PROLIFIC_PL2302)))) - return (0); - - if ((uaa->info.idVendor == USB_VENDOR_ANCHOR) && - (uaa->info.idProduct == USB_PRODUCT_ANCHOR_EZLINK)) - return (0); - - if ((uaa->info.idVendor == USB_VENDOR_GENESYS) && - (uaa->info.idProduct == USB_PRODUCT_GENESYS_GL620USB)) - return (0); - return (ENXIO); + return (usbd_lookup_id_by_uaa(udbp_devs, sizeof(udbp_devs), uaa)); } static int diff --git a/sys/dev/usb/misc/ufm.c b/sys/dev/usb/misc/ufm.c index 75e2b7f..11bea65 100644 --- a/sys/dev/usb/misc/ufm.c +++ b/sys/dev/usb/misc/ufm.c @@ -118,19 +118,23 @@ DRIVER_MODULE(ufm, uhub, ufm_driver, ufm_devclass, NULL, 0); MODULE_DEPEND(ufm, usb, 1, 1, 1); MODULE_VERSION(ufm, 1); +static const STRUCT_USB_HOST_ID ufm_devs[] = { + {USB_VPI(USB_VENDOR_CYPRESS, USB_PRODUCT_CYPRESS_FMRADIO, 0)}, +}; + static int ufm_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } - if ((uaa->info.idVendor == USB_VENDOR_CYPRESS) && - (uaa->info.idProduct == USB_PRODUCT_CYPRESS_FMRADIO)) { - return (0); - } - return (ENXIO); + if (uaa->info.bConfigIndex != 0) + return (ENXIO); + if (uaa->info.bIfaceIndex != 0) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(ufm_devs, sizeof(ufm_devs), uaa)); } static int diff --git a/sys/dev/usb/net/if_aue.c b/sys/dev/usb/net/if_aue.c index 3716844..71871de 100644 --- a/sys/dev/usb/net/if_aue.c +++ b/sys/dev/usb/net/if_aue.c @@ -110,7 +110,7 @@ SYSCTL_INT(_hw_usb_aue, OID_AUTO, debug, CTLFLAG_RW, &aue_debug, 0, /* * Various supported device vendors/products. */ -static const struct usb_device_id aue_devs[] = { +static const STRUCT_USB_HOST_ID aue_devs[] = { #define AUE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } AUE_DEV(3COM, 3C460B, AUE_FLAG_PII), AUE_DEV(ABOCOM, DSB650TX_PNA, 0), diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c index 00d1c0b..5c94e91 100644 --- a/sys/dev/usb/net/if_axe.c +++ b/sys/dev/usb/net/if_axe.c @@ -133,7 +133,7 @@ SYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0, /* * Various supported device vendors/products. */ -static const struct usb_device_id axe_devs[] = { +static const STRUCT_USB_HOST_ID axe_devs[] = { #define AXE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } AXE_DEV(ABOCOM, UF200, 0), AXE_DEV(ACERCM, EP1427X2, 0), diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index b48e79d..12e6f67 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -263,7 +263,7 @@ static const struct usb_ether_methods cdce_ue_methods = { .ue_setpromisc = cdce_setpromisc, }; -static const struct usb_device_id cdce_devs[] = { +static const STRUCT_USB_HOST_ID cdce_host_devs[] = { {USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)}, {USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)}, {USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)}, @@ -277,7 +277,9 @@ static const struct usb_device_id cdce_devs[] = { {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, +}; +static const STRUCT_USB_DUAL_ID cdce_dual_devs[] = { {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)}, {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)}, {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)}, @@ -472,8 +474,12 @@ static int cdce_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); + int error; - return (usbd_lookup_id_by_uaa(cdce_devs, sizeof(cdce_devs), uaa)); + error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa); + if (error) + error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa); + return (error); } static void diff --git a/sys/dev/usb/net/if_cue.c b/sys/dev/usb/net/if_cue.c index fae8f70..90a18f3 100644 --- a/sys/dev/usb/net/if_cue.c +++ b/sys/dev/usb/net/if_cue.c @@ -88,7 +88,7 @@ __FBSDID("$FreeBSD$"); /* Belkin F5U111 adapter covered by NETMATE entry */ -static const struct usb_device_id cue_devs[] = { +static const STRUCT_USB_HOST_ID cue_devs[] = { #define CUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } CUE_DEV(CATC, NETMATE), CUE_DEV(CATC, NETMATE2), diff --git a/sys/dev/usb/net/if_ipheth.c b/sys/dev/usb/net/if_ipheth.c index c8a348a..d666835 100644 --- a/sys/dev/usb/net/if_ipheth.c +++ b/sys/dev/usb/net/if_ipheth.c @@ -148,7 +148,7 @@ static const struct usb_ether_methods ipheth_ue_methods = { USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \ USB_IFACE_PROTOCOL(pt) -static const struct usb_device_id ipheth_devs[] = { +static const STRUCT_USB_HOST_ID ipheth_devs[] = { {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO)}, diff --git a/sys/dev/usb/net/if_kue.c b/sys/dev/usb/net/if_kue.c index 6c97d28..5480a5d 100644 --- a/sys/dev/usb/net/if_kue.c +++ b/sys/dev/usb/net/if_kue.c @@ -100,7 +100,7 @@ __FBSDID("$FreeBSD$"); /* * Various supported device vendors/products. */ -static const struct usb_device_id kue_devs[] = { +static const STRUCT_USB_HOST_ID kue_devs[] = { #define KUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } KUE_DEV(3COM, 3C19250), KUE_DEV(3COM, 3C460), diff --git a/sys/dev/usb/net/if_mos.c b/sys/dev/usb/net/if_mos.c index a0e453c..1e884f9 100644 --- a/sys/dev/usb/net/if_mos.c +++ b/sys/dev/usb/net/if_mos.c @@ -146,7 +146,7 @@ SYSCTL_INT(_hw_usb_mos, OID_AUTO, debug, CTLFLAG_RW, &mos_debug, 0, /* Various supported device vendors/products. */ -static const struct usb_device_id mos_devs[] = { +static const STRUCT_USB_HOST_ID mos_devs[] = { {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730, MCS7730)}, {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830, MCS7830)}, {USB_VPI(USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030, MCS7830)}, diff --git a/sys/dev/usb/net/if_rue.c b/sys/dev/usb/net/if_rue.c index 1dadd57..afd2f4d 100644 --- a/sys/dev/usb/net/if_rue.c +++ b/sys/dev/usb/net/if_rue.c @@ -108,7 +108,7 @@ SYSCTL_INT(_hw_usb_rue, OID_AUTO, debug, CTLFLAG_RW, * Various supported device vendors/products. */ -static const struct usb_device_id rue_devs[] = { +static const STRUCT_USB_HOST_ID rue_devs[] = { {USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)}, {USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)}, {USB_VPI(USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01, 0)}, diff --git a/sys/dev/usb/net/if_udav.c b/sys/dev/usb/net/if_udav.c index a6598ef..d2cceaa 100644 --- a/sys/dev/usb/net/if_udav.c +++ b/sys/dev/usb/net/if_udav.c @@ -199,7 +199,7 @@ SYSCTL_INT(_hw_usb_udav, OID_AUTO, debug, CTLFLAG_RW, &udav_debug, 0, #define UDAV_CLRBIT(sc, reg, x) \ udav_csr_write1(sc, reg, udav_csr_read1(sc, reg) & ~(x)) -static const struct usb_device_id udav_devs[] = { +static const STRUCT_USB_HOST_ID udav_devs[] = { /* ShanTou DM9601 USB NIC */ {USB_VPI(USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_DM9601, 0)}, /* ShanTou ST268 USB NIC */ diff --git a/sys/dev/usb/net/uhso.c b/sys/dev/usb/net/uhso.c index 06ac416..ab13093 100644 --- a/sys/dev/usb/net/uhso.c +++ b/sys/dev/usb/net/uhso.c @@ -247,7 +247,7 @@ static char *uhso_port_type_sysctl[] = { /* ifnet device unit allocations */ static struct unrhdr *uhso_ifnet_unit = NULL; -static const struct usb_device_id uhso_devs[] = { +static const STRUCT_USB_HOST_ID uhso_devs[] = { #define UHSO_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } /* Option GlobeSurfer iCON 7.2 */ UHSO_DEV(OPTION, GSICON72, UHSO_STATIC_IFACE), diff --git a/sys/dev/usb/serial/u3g.c b/sys/dev/usb/serial/u3g.c index c332bfb..31e8e11 100644 --- a/sys/dev/usb/serial/u3g.c +++ b/sys/dev/usb/serial/u3g.c @@ -182,7 +182,7 @@ MODULE_DEPEND(u3g, ucom, 1, 1, 1); MODULE_DEPEND(u3g, usb, 1, 1, 1); MODULE_VERSION(u3g, 1); -static const struct usb_device_id u3g_devs[] = { +static const STRUCT_USB_HOST_ID u3g_devs[] = { #define U3G_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } U3G_DEV(ACERP, H10, 0), U3G_DEV(AIRPLUS, MCD650, 0), diff --git a/sys/dev/usb/serial/uark.c b/sys/dev/usb/serial/uark.c index 75100f2..2c3943d 100644 --- a/sys/dev/usb/serial/uark.c +++ b/sys/dev/usb/serial/uark.c @@ -170,7 +170,7 @@ MODULE_DEPEND(uark, ucom, 1, 1, 1); MODULE_DEPEND(uark, usb, 1, 1, 1); MODULE_VERSION(uark, 1); -static const struct usb_device_id uark_devs[] = { +static const STRUCT_USB_HOST_ID uark_devs[] = { {USB_VPI(USB_VENDOR_ARKMICRO, USB_PRODUCT_ARKMICRO_ARK3116, 0)}, }; diff --git a/sys/dev/usb/serial/ubsa.c b/sys/dev/usb/serial/ubsa.c index 1a5a75a..6afe05b 100644 --- a/sys/dev/usb/serial/ubsa.c +++ b/sys/dev/usb/serial/ubsa.c @@ -239,7 +239,7 @@ static const struct ucom_callback ubsa_callback = { .ucom_poll = &ubsa_poll, }; -static const struct usb_device_id ubsa_devs[] = { +static const STRUCT_USB_HOST_ID ubsa_devs[] = { /* AnyData ADU-500A */ {USB_VPI(USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A, 0)}, /* AnyData ADU-E100A/H */ diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c index 60fa9e0..3f69c4d 100644 --- a/sys/dev/usb/serial/uchcom.c +++ b/sys/dev/usb/serial/uchcom.c @@ -204,7 +204,7 @@ static const struct uchcom_divider_record dividers[] = #define NUM_DIVIDERS (sizeof (dividers) / sizeof (dividers[0])) -static const struct usb_device_id uchcom_devs[] = { +static const STRUCT_USB_HOST_ID uchcom_devs[] = { {USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)}, {USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)}, }; diff --git a/sys/dev/usb/serial/ucycom.c b/sys/dev/usb/serial/ucycom.c index a58398a..8fef219 100644 --- a/sys/dev/usb/serial/ucycom.c +++ b/sys/dev/usb/serial/ucycom.c @@ -180,7 +180,7 @@ MODULE_VERSION(ucycom, 1); /* * Supported devices */ -static const struct usb_device_id ucycom_devs[] = { +static const STRUCT_USB_HOST_ID ucycom_devs[] = { {USB_VPI(USB_VENDOR_DELORME, USB_PRODUCT_DELORME_EARTHMATE, MODEL_CY7C64013)}, }; diff --git a/sys/dev/usb/serial/ufoma.c b/sys/dev/usb/serial/ufoma.c index a32fd47..31be85c 100644 --- a/sys/dev/usb/serial/ufoma.c +++ b/sys/dev/usb/serial/ufoma.c @@ -327,6 +327,11 @@ MODULE_DEPEND(ufoma, ucom, 1, 1, 1); MODULE_DEPEND(ufoma, usb, 1, 1, 1); MODULE_VERSION(ufoma, 1); +static const STRUCT_USB_HOST_ID ufoma_devs[] = { + {USB_IFACE_CLASS(UICLASS_CDC), + USB_IFACE_SUBCLASS(UISUBCLASS_MCPC),}, +}; + static int ufoma_probe(device_t dev) { @@ -334,30 +339,31 @@ ufoma_probe(device_t dev) struct usb_interface_descriptor *id; struct usb_config_descriptor *cd; usb_mcpc_acm_descriptor *mad; + int error; - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } + + error = usbd_lookup_id_by_uaa(ufoma_devs, sizeof(ufoma_devs), uaa); + if (error) + return (error); + id = usbd_get_interface_descriptor(uaa->iface); cd = usbd_get_config_descriptor(uaa->device); - if ((id == NULL) || - (cd == NULL) || - (id->bInterfaceClass != UICLASS_CDC) || - (id->bInterfaceSubClass != UISUBCLASS_MCPC)) { + if (id == NULL || cd == NULL) return (ENXIO); - } + mad = ufoma_get_intconf(cd, id, UDESC_VS_INTERFACE, UDESCSUB_MCPC_ACM); - if (mad == NULL) { + if (mad == NULL) return (ENXIO); - } + #ifndef UFOMA_HANDSFREE if ((mad->bType == UMCPC_ACM_TYPE_AB5) || - (mad->bType == UMCPC_ACM_TYPE_AB6)) { + (mad->bType == UMCPC_ACM_TYPE_AB6)) return (ENXIO); - } #endif - return (0); + return (BUS_PROBE_GENERIC); } static int diff --git a/sys/dev/usb/serial/uftdi.c b/sys/dev/usb/serial/uftdi.c index b196862..1c88063 100644 --- a/sys/dev/usb/serial/uftdi.c +++ b/sys/dev/usb/serial/uftdi.c @@ -206,7 +206,7 @@ MODULE_DEPEND(uftdi, ucom, 1, 1, 1); MODULE_DEPEND(uftdi, usb, 1, 1, 1); MODULE_VERSION(uftdi, 1); -static struct usb_device_id uftdi_devs[] = { +static STRUCT_USB_HOST_ID uftdi_devs[] = { #define UFTDI_DEV(v,p,t) \ { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, UFTDI_TYPE_##t) } UFTDI_DEV(ATMEL, STK541, 8U232AM), diff --git a/sys/dev/usb/serial/ugensa.c b/sys/dev/usb/serial/ugensa.c index 0c2f2c4..6b0955e 100644 --- a/sys/dev/usb/serial/ugensa.c +++ b/sys/dev/usb/serial/ugensa.c @@ -154,7 +154,7 @@ MODULE_DEPEND(ugensa, ucom, 1, 1, 1); MODULE_DEPEND(ugensa, usb, 1, 1, 1); MODULE_VERSION(ugensa, 1); -static const struct usb_device_id ugensa_devs[] = { +static const STRUCT_USB_HOST_ID ugensa_devs[] = { {USB_VPI(USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220, 0)}, {USB_VPI(USB_VENDOR_CMOTECH, USB_PRODUCT_CMOTECH_CDMA_MODEM1, 0)}, {USB_VPI(USB_VENDOR_KYOCERA2, USB_PRODUCT_KYOCERA2_CDMA_MSM_K, 0)}, diff --git a/sys/dev/usb/serial/uipaq.c b/sys/dev/usb/serial/uipaq.c index 6f96164..d038e17 100644 --- a/sys/dev/usb/serial/uipaq.c +++ b/sys/dev/usb/serial/uipaq.c @@ -153,7 +153,7 @@ static const struct ucom_callback uipaq_callback = { * support the same hardware. Numeric values are used where no usbdevs * entries exist. */ -static const struct usb_device_id uipaq_devs[] = { +static const STRUCT_USB_HOST_ID uipaq_devs[] = { /* Socket USB Sync */ {USB_VPI(0x0104, 0x00be, 0)}, /* USB Sync 0301 */ diff --git a/sys/dev/usb/serial/ulpt.c b/sys/dev/usb/serial/ulpt.c index ec1aa24..def2ae5 100644 --- a/sys/dev/usb/serial/ulpt.c +++ b/sys/dev/usb/serial/ulpt.c @@ -483,24 +483,39 @@ ulpt_ioctl(struct usb_fifo *fifo, u_long cmd, void *data, return (ENODEV); } +static const STRUCT_USB_HOST_ID ulpt_devs[] = { + /* Uni-directional USB printer */ + {USB_IFACE_CLASS(UICLASS_PRINTER), + USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER), + USB_IFACE_PROTOCOL(UIPROTO_PRINTER_UNI)}, + + /* Bi-directional USB printer */ + {USB_IFACE_CLASS(UICLASS_PRINTER), + USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER), + USB_IFACE_PROTOCOL(UIPROTO_PRINTER_BI)}, + + /* 1284 USB printer */ + {USB_IFACE_CLASS(UICLASS_PRINTER), + USB_IFACE_SUBCLASS(UISUBCLASS_PRINTER), + USB_IFACE_PROTOCOL(UIPROTO_PRINTER_1284)}, +}; + static int ulpt_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); + int error; DPRINTFN(11, "\n"); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } - if ((uaa->info.bInterfaceClass == UICLASS_PRINTER) && - (uaa->info.bInterfaceSubClass == UISUBCLASS_PRINTER) && - ((uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_UNI) || - (uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_BI) || - (uaa->info.bInterfaceProtocol == UIPROTO_PRINTER_1284))) { - return (0); - } - return (ENXIO); + + error = usbd_lookup_id_by_uaa(ulpt_devs, sizeof(ulpt_devs), uaa); + if (error) + return (error); + + return (BUS_PROBE_GENERIC); } static int diff --git a/sys/dev/usb/serial/umcs.c b/sys/dev/usb/serial/umcs.c index c74044e..94ed4d9 100644 --- a/sys/dev/usb/serial/umcs.c +++ b/sys/dev/usb/serial/umcs.c @@ -253,7 +253,7 @@ static struct ucom_callback umcs7840_callback = { .ucom_poll = &umcs7840_poll, }; -static const struct usb_device_id umcs7840_devs[] = { +static const STRUCT_USB_HOST_ID umcs7840_devs[] = { {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7820, 0)}, {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7840, 0)}, }; diff --git a/sys/dev/usb/serial/umct.c b/sys/dev/usb/serial/umct.c index 39dc9d7..16dd4a1 100644 --- a/sys/dev/usb/serial/umct.c +++ b/sys/dev/usb/serial/umct.c @@ -192,7 +192,7 @@ static const struct ucom_callback umct_callback = { .ucom_poll = &umct_poll, }; -static const struct usb_device_id umct_devs[] = { +static const STRUCT_USB_HOST_ID umct_devs[] = { {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_USB232, 0)}, {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_SITECOM_USB232, 0)}, {USB_VPI(USB_VENDOR_MCT, USB_PRODUCT_MCT_DU_H3SP_USB232, 0)}, diff --git a/sys/dev/usb/serial/umodem.c b/sys/dev/usb/serial/umodem.c index c6d517b..ed5162f 100644 --- a/sys/dev/usb/serial/umodem.c +++ b/sys/dev/usb/serial/umodem.c @@ -123,7 +123,7 @@ SYSCTL_INT(_hw_usb_umodem, OID_AUTO, debug, CTLFLAG_RW, &umodem_debug, 0, "Debug level"); #endif -static const struct usb_device_id umodem_devs[] = { +static const STRUCT_USB_HOST_ID umodem_devs[] = { /* Generic Modem class match */ {USB_IFACE_CLASS(UICLASS_CDC), USB_IFACE_SUBCLASS(UISUBCLASS_ABSTRACT_CONTROL_MODEL), @@ -276,11 +276,14 @@ umodem_probe(device_t dev) DPRINTFN(11, "\n"); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } + error = usbd_lookup_id_by_uaa(umodem_devs, sizeof(umodem_devs), uaa); - return (error); + if (error) + return (error); + + return (BUS_PROBE_GENERIC); } static int diff --git a/sys/dev/usb/serial/umoscom.c b/sys/dev/usb/serial/umoscom.c index 4ab6cc0..c346ae6 100644 --- a/sys/dev/usb/serial/umoscom.c +++ b/sys/dev/usb/serial/umoscom.c @@ -280,7 +280,7 @@ MODULE_DEPEND(umoscom, ucom, 1, 1, 1); MODULE_DEPEND(umoscom, usb, 1, 1, 1); MODULE_VERSION(umoscom, 1); -static const struct usb_device_id umoscom_devs[] = { +static const STRUCT_USB_HOST_ID umoscom_devs[] = { {USB_VPI(USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7703, 0)} }; diff --git a/sys/dev/usb/serial/uplcom.c b/sys/dev/usb/serial/uplcom.c index 108ee7b..4af0537 100644 --- a/sys/dev/usb/serial/uplcom.c +++ b/sys/dev/usb/serial/uplcom.c @@ -247,7 +247,7 @@ static struct ucom_callback uplcom_callback = { #define UPLCOM_DEV(v,p) \ { USB_VENDOR(USB_VENDOR_##v), USB_PRODUCT(USB_PRODUCT_##v##_##p) } -static const struct usb_device_id uplcom_devs[] = { +static const STRUCT_USB_HOST_ID uplcom_devs[] = { UPLCOM_DEV(ACERP, S81), /* BenQ S81 phone */ UPLCOM_DEV(ADLINK, ND6530), /* ADLINK ND-6530 USB-Serial */ UPLCOM_DEV(ALCATEL, OT535), /* Alcatel One Touch 535/735 */ diff --git a/sys/dev/usb/serial/uslcom.c b/sys/dev/usb/serial/uslcom.c index 1357c8d..6eaec83 100644 --- a/sys/dev/usb/serial/uslcom.c +++ b/sys/dev/usb/serial/uslcom.c @@ -173,7 +173,7 @@ static struct ucom_callback uslcom_callback = { .ucom_poll = &uslcom_poll, }; -static const struct usb_device_id uslcom_devs[] = { +static const STRUCT_USB_HOST_ID uslcom_devs[] = { #define USLCOM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } USLCOM_DEV(BALTECH, CARDREADER), USLCOM_DEV(CLIPSAL, 5500PCU), diff --git a/sys/dev/usb/serial/uvisor.c b/sys/dev/usb/serial/uvisor.c index 3efef5d..976ea19 100644 --- a/sys/dev/usb/serial/uvisor.c +++ b/sys/dev/usb/serial/uvisor.c @@ -253,7 +253,7 @@ MODULE_DEPEND(uvisor, ucom, 1, 1, 1); MODULE_DEPEND(uvisor, usb, 1, 1, 1); MODULE_VERSION(uvisor, 1); -static const struct usb_device_id uvisor_devs[] = { +static const STRUCT_USB_HOST_ID uvisor_devs[] = { #define UVISOR_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) } UVISOR_DEV(ACEECA, MEZ1000, UVISOR_FLAG_PALM4), UVISOR_DEV(ALPHASMART, DANA_SYNC, UVISOR_FLAG_PALM4), diff --git a/sys/dev/usb/serial/uvscom.c b/sys/dev/usb/serial/uvscom.c index d883190..52e02ad 100644 --- a/sys/dev/usb/serial/uvscom.c +++ b/sys/dev/usb/serial/uvscom.c @@ -233,7 +233,7 @@ static const struct ucom_callback uvscom_callback = { .ucom_poll = &uvscom_poll, }; -static const struct usb_device_id uvscom_devs[] = { +static const STRUCT_USB_HOST_ID uvscom_devs[] = { /* SUNTAC U-Cable type A4 */ {USB_VPI(USB_VENDOR_SUNTAC, USB_PRODUCT_SUNTAC_AS144L4, 0)}, /* SUNTAC U-Cable type D2 */ diff --git a/sys/dev/usb/storage/umass.c b/sys/dev/usb/storage/umass.c index 158d843..9292c84 100644 --- a/sys/dev/usb/storage/umass.c +++ b/sys/dev/usb/storage/umass.c @@ -721,6 +721,11 @@ MODULE_VERSION(umass, 1); * USB device probe/attach/detach */ +static const STRUCT_USB_HOST_ID __used umass_devs[] = { + /* generic mass storage class */ + {USB_IFACE_CLASS(UICLASS_MASS),}, +}; + static uint16_t umass_get_proto(struct usb_interface *iface) { diff --git a/sys/dev/usb/storage/urio.c b/sys/dev/usb/storage/urio.c index ee93439..6687173 100644 --- a/sys/dev/usb/storage/urio.c +++ b/sys/dev/usb/storage/urio.c @@ -198,22 +198,25 @@ DRIVER_MODULE(urio, uhub, urio_driver, urio_devclass, NULL, 0); MODULE_DEPEND(urio, usb, 1, 1, 1); MODULE_VERSION(urio, 1); +static const STRUCT_USB_HOST_ID urio_devs[] = { + {USB_VPI(USB_VENDOR_DIAMOND, USB_PRODUCT_DIAMOND_RIO500USB, 0)}, + {USB_VPI(USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO600USB, 0)}, + {USB_VPI(USB_VENDOR_DIAMOND2, USB_PRODUCT_DIAMOND2_RIO800USB, 0)}, +}; + static int urio_probe(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); - if (uaa->usb_mode != USB_MODE_HOST) { + if (uaa->usb_mode != USB_MODE_HOST) return (ENXIO); - } - if ((((uaa->info.idVendor == USB_VENDOR_DIAMOND) && - (uaa->info.idProduct == USB_PRODUCT_DIAMOND_RIO500USB)) || - ((uaa->info.idVendor == USB_VENDOR_DIAMOND2) && - ((uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO600USB) || - (uaa->info.idProduct == USB_PRODUCT_DIAMOND2_RIO800USB))))) - return (0); - else + if (uaa->info.bConfigIndex != 0) return (ENXIO); + if (uaa->info.bIfaceIndex != 0) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(urio_devs, sizeof(urio_devs), uaa)); } static int diff --git a/sys/dev/usb/template/usb_template.c b/sys/dev/usb/template/usb_template.c index 7bf17fe..cf97482 100644 --- a/sys/dev/usb/template/usb_template.c +++ b/sys/dev/usb/template/usb_template.c @@ -49,6 +49,7 @@ #include <sys/priv.h> #include <dev/usb/usb.h> +#include <dev/usb/usb_ioctl.h> #include <dev/usb/usbdi.h> #include <dev/usb/usbdi_util.h> #include "usbdevs.h" @@ -141,6 +142,31 @@ usb_make_raw_desc(struct usb_temp_setup *temp, ud->bSlaveInterface[0] += temp->bInterfaceNumber; } + + /* check if we have got an interface association descriptor */ + + if ((raw[0] >= sizeof(struct usb_interface_assoc_descriptor)) && + (raw[1] == UDESC_IFACE_ASSOC)) { + struct usb_interface_assoc_descriptor *iad = (void *)dst; + + /* update the interface number */ + + iad->bFirstInterface += + temp->bInterfaceNumber; + } + + /* check if we have got a call management descriptor */ + + if ((raw[0] >= sizeof(struct usb_cdc_cm_descriptor)) && + (raw[1] == UDESC_CS_INTERFACE) && + (raw[2] == UDESCSUB_CDC_CM)) { + struct usb_cdc_cm_descriptor *ccd = (void *)dst; + + /* update the interface number */ + + ccd->bDataInterface += + temp->bInterfaceNumber; + } } temp->size += len; } @@ -476,6 +502,10 @@ usb_make_device_desc(struct usb_temp_setup *temp, USETW(utd->udd.bcdUSB, 0x0250); utd->udd.bMaxPacketSize = 255; /* 512 bytes */ break; + case USB_SPEED_SUPER: + USETW(utd->udd.bcdUSB, 0x0300); + utd->udd.bMaxPacketSize = 9; /* 2**9 = 512 bytes */ + break; default: temp->err = USB_ERR_INVAL; break; @@ -1303,15 +1333,27 @@ usb_temp_setup_by_index(struct usb_device *udev, uint16_t index) usb_error_t err; switch (index) { - case 0: + case USB_TEMP_MSC: err = usb_temp_setup(udev, &usb_template_msc); break; - case 1: + case USB_TEMP_CDCE: err = usb_temp_setup(udev, &usb_template_cdce); break; - case 2: + case USB_TEMP_MTP: err = usb_temp_setup(udev, &usb_template_mtp); break; + case USB_TEMP_MODEM: + err = usb_temp_setup(udev, &usb_template_modem); + break; + case USB_TEMP_AUDIO: + err = usb_temp_setup(udev, &usb_template_audio); + break; + case USB_TEMP_KBD: + err = usb_temp_setup(udev, &usb_template_kbd); + break; + case USB_TEMP_MOUSE: + err = usb_temp_setup(udev, &usb_template_mouse); + break; default: return (USB_ERR_INVAL); } diff --git a/sys/dev/usb/template/usb_template.h b/sys/dev/usb/template/usb_template.h index 2473af3..b05272f 100644 --- a/sys/dev/usb/template/usb_template.h +++ b/sys/dev/usb/template/usb_template.h @@ -30,6 +30,10 @@ #ifndef _USB_TEMPLATE_H_ #define _USB_TEMPLATE_H_ +#ifndef USB_TEMPLATE_VENDOR +#define USB_TEMPLATE_VENDOR 0x0001 +#endif + typedef const void *(usb_temp_get_string_desc_t)(uint16_t lang_id, uint8_t string_index); typedef const void *(usb_temp_get_vendor_desc_t)(const struct usb_device_request *req, uint16_t *plen); @@ -94,10 +98,14 @@ struct usb_temp_data { /* prototypes */ +extern const struct usb_temp_device_desc usb_template_audio; extern const struct usb_temp_device_desc usb_template_cdce; -extern const struct usb_temp_device_desc usb_template_msc; /* Mass Storage Class */ -extern const struct usb_temp_device_desc usb_template_mtp; /* Message Transfer - * Protocol */ +extern const struct usb_temp_device_desc usb_template_kbd; +extern const struct usb_temp_device_desc usb_template_modem; +extern const struct usb_temp_device_desc usb_template_mouse; +extern const struct usb_temp_device_desc usb_template_msc; +extern const struct usb_temp_device_desc usb_template_mtp; + usb_error_t usb_temp_setup(struct usb_device *, const struct usb_temp_device_desc *); void usb_temp_unsetup(struct usb_device *); diff --git a/sys/dev/usb/template/usb_template_audio.c b/sys/dev/usb/template/usb_template_audio.c new file mode 100644 index 0000000..8e9e7f0 --- /dev/null +++ b/sys/dev/usb/template/usb_template_audio.c @@ -0,0 +1,405 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010 Hans Petter Selasky. 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. + */ + +/* + * This file contains the USB template for an USB Audio Device. + */ + +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_cdc.h> + +#include <dev/usb/template/usb_template.h> + +enum { + INDEX_AUDIO_LANG, + INDEX_AUDIO_MIXER, + INDEX_AUDIO_RECORD, + INDEX_AUDIO_PLAYBACK, + INDEX_AUDIO_PRODUCT, + INDEX_AUDIO_MAX, +}; + +#define STRING_LANG \ + 0x09, 0x04, /* American English */ + +#define STRING_AUDIO_PRODUCT \ + 'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0, ' ', 0, \ + 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, + +#define STRING_AUDIO_MIXER \ + 'M', 0, 'i', 0, 'x', 0, 'e', 0, 'r', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + +#define STRING_AUDIO_RECORD \ + 'R', 0, 'e', 0, 'c', 0, 'o', 0, 'r', 0, 'd', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + +#define STRING_AUDIO_PLAYBACK \ + 'P', 0, 'l', 0, 'a', 0, 'y', 0, 'b', 0, 'a', 0, 'c', 0, 'k', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + + +/* make the real string descriptors */ + +USB_MAKE_STRING_DESC(STRING_LANG, string_lang); +USB_MAKE_STRING_DESC(STRING_AUDIO_MIXER, string_audio_mixer); +USB_MAKE_STRING_DESC(STRING_AUDIO_RECORD, string_audio_record); +USB_MAKE_STRING_DESC(STRING_AUDIO_PLAYBACK, string_audio_playback); +USB_MAKE_STRING_DESC(STRING_AUDIO_PRODUCT, string_audio_product); + +/* prototypes */ + +/* + * Audio Mixer description structures + * + * Some of the audio descriptors were dumped + * from a Creative Labs USB audio device. + */ + +static const uint8_t audio_raw_desc_0[] = { + 0x0a, 0x24, 0x01, 0x00, 0x01, 0xa9, 0x00, 0x02, + 0x01, 0x02 +}; + +static const uint8_t audio_raw_desc_1[] = { + 0x0c, 0x24, 0x02, 0x01, 0x01, 0x01, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_2[] = { + 0x0c, 0x24, 0x02, 0x02, 0x01, 0x02, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_3[] = { + 0x0c, 0x24, 0x02, 0x03, 0x03, 0x06, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_4[] = { + 0x0c, 0x24, 0x02, 0x04, 0x05, 0x06, 0x00, 0x02, + 0x03, 0x00, 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_5[] = { + 0x09, 0x24, 0x03, 0x05, 0x05, 0x06, 0x00, 0x01, + 0x00 +}; + +static const uint8_t audio_raw_desc_6[] = { + 0x09, 0x24, 0x03, 0x06, 0x01, 0x03, 0x00, 0x09, + 0x00 +}; + +static const uint8_t audio_raw_desc_7[] = { + 0x09, 0x24, 0x03, 0x07, 0x01, 0x01, 0x00, 0x08, + 0x00 +}; + +static const uint8_t audio_raw_desc_8[] = { + 0x09, 0x24, 0x05, 0x08, 0x03, 0x0a, 0x0b, 0x0c, + 0x00 +}; + +static const uint8_t audio_raw_desc_9[] = { + 0x0a, 0x24, 0x06, 0x09, 0x0f, 0x01, 0x01, 0x02, + 0x02, 0x00 +}; + +static const uint8_t audio_raw_desc_10[] = { + 0x0a, 0x24, 0x06, 0x0a, 0x02, 0x01, 0x43, 0x00, + 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_11[] = { + 0x0a, 0x24, 0x06, 0x0b, 0x03, 0x01, 0x01, 0x02, + 0x02, 0x00 +}; + +static const uint8_t audio_raw_desc_12[] = { + 0x0a, 0x24, 0x06, 0x0c, 0x04, 0x01, 0x01, 0x00, + 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_13[] = { + 0x0a, 0x24, 0x06, 0x0d, 0x02, 0x01, 0x03, 0x00, + 0x00, 0x00 +}; + +static const uint8_t audio_raw_desc_14[] = { + 0x0a, 0x24, 0x06, 0x0e, 0x03, 0x01, 0x01, 0x02, + 0x02, 0x00 +}; + +static const uint8_t audio_raw_desc_15[] = { + 0x0f, 0x24, 0x04, 0x0f, 0x03, 0x01, 0x0d, 0x0e, + 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const void *audio_raw_iface_0_desc[] = { + audio_raw_desc_0, + audio_raw_desc_1, + audio_raw_desc_2, + audio_raw_desc_3, + audio_raw_desc_4, + audio_raw_desc_5, + audio_raw_desc_6, + audio_raw_desc_7, + audio_raw_desc_8, + audio_raw_desc_9, + audio_raw_desc_10, + audio_raw_desc_11, + audio_raw_desc_12, + audio_raw_desc_13, + audio_raw_desc_14, + audio_raw_desc_15, + NULL, +}; + +static const struct usb_temp_interface_desc audio_iface_0 = { + .ppEndpoints = NULL, /* no endpoints */ + .ppRawDesc = audio_raw_iface_0_desc, + .bInterfaceClass = 1, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .iInterface = INDEX_AUDIO_MIXER, +}; + +static const uint8_t audio_raw_desc_20[] = { + 0x07, 0x24, 0x01, 0x01, 0x03, 0x01, 0x00 + +}; + +static const uint8_t audio_raw_desc_21[] = { + 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, + /* 48kHz */ + 0x80, 0xbb, 0x00 +}; + +static const uint8_t audio_raw_desc_22[] = { + 0x07, 0x25, 0x01, 0x00, 0x01, 0x04, 0x00 +}; + +static const void *audio_raw_iface_1_desc[] = { + audio_raw_desc_20, + audio_raw_desc_21, + NULL, +}; + +static const void *audio_raw_ep_1_desc[] = { + audio_raw_desc_22, + NULL, +}; + +static const struct usb_temp_packet_size audio_isoc_mps = { + .mps[USB_SPEED_FULL] = 0xC8, + .mps[USB_SPEED_HIGH] = 0xC8, +}; + +static const struct usb_temp_interval audio_isoc_interval = { + .bInterval[USB_SPEED_FULL] = 1, /* 1:1 */ + .bInterval[USB_SPEED_HIGH] = 4, /* 1:8 */ +}; + +static const struct usb_temp_endpoint_desc audio_isoc_out_ep = { + .ppRawDesc = audio_raw_ep_1_desc, + .pPacketSize = &audio_isoc_mps, + .pIntervals = &audio_isoc_interval, + .bEndpointAddress = UE_DIR_OUT, + .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, +}; + +static const struct usb_temp_endpoint_desc *audio_iface_1_ep[] = { + &audio_isoc_out_ep, + NULL, +}; + +static const struct usb_temp_interface_desc audio_iface_1_alt_0 = { + .ppEndpoints = NULL, /* no endpoints */ + .ppRawDesc = NULL, /* no raw descriptors */ + .bInterfaceClass = 1, + .bInterfaceSubClass = 2, + .bInterfaceProtocol = 0, + .iInterface = INDEX_AUDIO_PLAYBACK, +}; + +static const struct usb_temp_interface_desc audio_iface_1_alt_1 = { + .ppEndpoints = audio_iface_1_ep, + .ppRawDesc = audio_raw_iface_1_desc, + .bInterfaceClass = 1, + .bInterfaceSubClass = 2, + .bInterfaceProtocol = 0, + .iInterface = INDEX_AUDIO_PLAYBACK, + .isAltInterface = 1, /* this is an alternate setting */ +}; + +static const uint8_t audio_raw_desc_30[] = { + 0x07, 0x24, 0x01, 0x07, 0x01, 0x01, 0x00 + +}; + +static const uint8_t audio_raw_desc_31[] = { + 0x0b, 0x24, 0x02, 0x01, 0x02, 0x02, 0x10, 0x01, + /* 48kHz */ + 0x80, 0xbb, 0x00 +}; + +static const uint8_t audio_raw_desc_32[] = { + 0x07, 0x25, 0x01, 0x01, 0x00, 0x00, 0x00 +}; + +static const void *audio_raw_iface_2_desc[] = { + audio_raw_desc_30, + audio_raw_desc_31, + NULL, +}; + +static const void *audio_raw_ep_2_desc[] = { + audio_raw_desc_32, + NULL, +}; + +static const struct usb_temp_endpoint_desc audio_isoc_in_ep = { + .ppRawDesc = audio_raw_ep_2_desc, + .pPacketSize = &audio_isoc_mps, + .pIntervals = &audio_isoc_interval, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_ISOCHRONOUS | UE_ISO_ADAPT, +}; + +static const struct usb_temp_endpoint_desc *audio_iface_2_ep[] = { + &audio_isoc_in_ep, + NULL, +}; + +static const struct usb_temp_interface_desc audio_iface_2_alt_0 = { + .ppEndpoints = NULL, /* no endpoints */ + .ppRawDesc = NULL, /* no raw descriptors */ + .bInterfaceClass = 1, + .bInterfaceSubClass = 2, + .bInterfaceProtocol = 0, + .iInterface = INDEX_AUDIO_RECORD, +}; + +static const struct usb_temp_interface_desc audio_iface_2_alt_1 = { + .ppEndpoints = audio_iface_2_ep, + .ppRawDesc = audio_raw_iface_2_desc, + .bInterfaceClass = 1, + .bInterfaceSubClass = 2, + .bInterfaceProtocol = 0, + .iInterface = INDEX_AUDIO_RECORD, + .isAltInterface = 1, /* this is an alternate setting */ +}; + +static const struct usb_temp_interface_desc *audio_interfaces[] = { + &audio_iface_0, + &audio_iface_1_alt_0, + &audio_iface_1_alt_1, + &audio_iface_2_alt_0, + &audio_iface_2_alt_1, + NULL, +}; + +static const struct usb_temp_config_desc audio_config_desc = { + .ppIfaceDesc = audio_interfaces, + .bmAttributes = UC_BUS_POWERED, + .bMaxPower = 25, /* 50 mA */ + .iConfiguration = INDEX_AUDIO_PRODUCT, +}; + +static const struct usb_temp_config_desc *audio_configs[] = { + &audio_config_desc, + NULL, +}; + +static usb_temp_get_string_desc_t audio_get_string_desc; + +const struct usb_temp_device_desc usb_template_audio = { + .getStringDesc = &audio_get_string_desc, + .ppConfigDesc = audio_configs, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x000A, + .bcdDevice = 0x0100, + .bDeviceClass = UDCLASS_COMM, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .iManufacturer = 0, + .iProduct = INDEX_AUDIO_PRODUCT, + .iSerialNumber = 0, +}; + +/*------------------------------------------------------------------------* + * audio_get_string_desc + * + * Return values: + * NULL: Failure. No such string. + * Else: Success. Pointer to string descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +audio_get_string_desc(uint16_t lang_id, uint8_t string_index) +{ + static const void *ptr[INDEX_AUDIO_MAX] = { + [INDEX_AUDIO_LANG] = &string_lang, + [INDEX_AUDIO_MIXER] = &string_audio_mixer, + [INDEX_AUDIO_RECORD] = &string_audio_record, + [INDEX_AUDIO_PLAYBACK] = &string_audio_playback, + [INDEX_AUDIO_PRODUCT] = &string_audio_product, + }; + + if (string_index == 0) { + return (&string_lang); + } + if (lang_id != 0x0409) { + return (NULL); + } + if (string_index < INDEX_AUDIO_MAX) { + return (ptr[string_index]); + } + return (NULL); +} diff --git a/sys/dev/usb/template/usb_template_cdce.c b/sys/dev/usb/template/usb_template_cdce.c index c8b2c6c..481a69c 100644 --- a/sys/dev/usb/template/usb_template_cdce.c +++ b/sys/dev/usb/template/usb_template_cdce.c @@ -264,7 +264,7 @@ static const struct usb_temp_config_desc *eth_configs[] = { const struct usb_temp_device_desc usb_template_cdce = { .getStringDesc = ð_get_string_desc, .ppConfigDesc = eth_configs, - .idVendor = 0x0001, + .idVendor = USB_TEMPLATE_VENDOR, .idProduct = 0x0001, .bcdDevice = 0x0100, .bDeviceClass = UDCLASS_COMM, diff --git a/sys/dev/usb/template/usb_template_kbd.c b/sys/dev/usb/template/usb_template_kbd.c new file mode 100644 index 0000000..8928c06 --- /dev/null +++ b/sys/dev/usb/template/usb_template_kbd.c @@ -0,0 +1,224 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010 Hans Petter Selasky. 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. + */ + +/* + * This file contains the USB template for an USB Keyboard Device. + */ + +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_cdc.h> + +#include <dev/usb/template/usb_template.h> + +enum { + INDEX_LANG, + INDEX_KEYBOARD, + INDEX_PRODUCT, + INDEX_MAX, +}; + +#define STRING_LANG \ + 0x09, 0x04, /* American English */ + +#define STRING_PRODUCT \ + 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, \ + 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, + +#define STRING_KEYBOARD \ + 'K', 0, 'e', 0, 'y', 0, 'b', 0, 'o', 0, 'a', 0, 'r', 0, 'd', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + +/* make the real string descriptors */ + +USB_MAKE_STRING_DESC(STRING_LANG, string_lang); +USB_MAKE_STRING_DESC(STRING_KEYBOARD, string_keyboard); +USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); + +/* prototypes */ + +static const struct usb_temp_packet_size keyboard_intr_mps = { + .mps[USB_SPEED_LOW] = 16, + .mps[USB_SPEED_FULL] = 16, + .mps[USB_SPEED_HIGH] = 16, +}; + +static const struct usb_temp_interval keyboard_intr_interval = { + .bInterval[USB_SPEED_LOW] = 2, /* ms */ + .bInterval[USB_SPEED_FULL] = 2, + .bInterval[USB_SPEED_HIGH] = 2 * 8, +}; + +/* The following HID descriptor was dumped from a HP keyboard. */ + +static uint8_t keyboard_hid_descriptor[] = { + 0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, + 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00, 0x25, 0x01, + 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, + 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, + 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, + 0x75, 0x08, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05, + 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, + 0xc0 +}; + +static const struct usb_temp_endpoint_desc keyboard_ep_0 = { + .ppRawDesc = NULL, /* no raw descriptors */ + .pPacketSize = &keyboard_intr_mps, + .pIntervals = &keyboard_intr_interval, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_INTERRUPT, +}; + +static const struct usb_temp_endpoint_desc *keyboard_endpoints[] = { + &keyboard_ep_0, + NULL, +}; + +static const uint8_t keyboard_raw_desc[] = { + 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(keyboard_hid_descriptor), + 0x00 +}; + +static const void *keyboard_iface_0_desc[] = { + keyboard_raw_desc, + NULL, +}; + +static const struct usb_temp_interface_desc keyboard_iface_0 = { + .ppRawDesc = keyboard_iface_0_desc, + .ppEndpoints = keyboard_endpoints, + .bInterfaceClass = 3, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, + .iInterface = INDEX_KEYBOARD, +}; + +static const struct usb_temp_interface_desc *keyboard_interfaces[] = { + &keyboard_iface_0, + NULL, +}; + +static const struct usb_temp_config_desc keyboard_config_desc = { + .ppIfaceDesc = keyboard_interfaces, + .bmAttributes = UC_BUS_POWERED, + .bMaxPower = 25, /* 50 mA */ + .iConfiguration = INDEX_PRODUCT, +}; + +static const struct usb_temp_config_desc *keyboard_configs[] = { + &keyboard_config_desc, + NULL, +}; + +static usb_temp_get_string_desc_t keyboard_get_string_desc; +static usb_temp_get_vendor_desc_t keyboard_get_vendor_desc; + +const struct usb_temp_device_desc usb_template_kbd = { + .getStringDesc = &keyboard_get_string_desc, + .getVendorDesc = &keyboard_get_vendor_desc, + .ppConfigDesc = keyboard_configs, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x00CB, + .bcdDevice = 0x0100, + .bDeviceClass = UDCLASS_COMM, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .iManufacturer = 0, + .iProduct = INDEX_PRODUCT, + .iSerialNumber = 0, +}; + +/*------------------------------------------------------------------------* + * keyboard_get_vendor_desc + * + * Return values: + * NULL: Failure. No such vendor descriptor. + * Else: Success. Pointer to vendor descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +keyboard_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) +{ + if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) && + (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) && + (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) { + + *plen = sizeof(keyboard_hid_descriptor); + return (keyboard_hid_descriptor); + } + return (NULL); +} + +/*------------------------------------------------------------------------* + * keyboard_get_string_desc + * + * Return values: + * NULL: Failure. No such string. + * Else: Success. Pointer to string descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +keyboard_get_string_desc(uint16_t lang_id, uint8_t string_index) +{ + static const void *ptr[INDEX_MAX] = { + [INDEX_LANG] = &string_lang, + [INDEX_KEYBOARD] = &string_keyboard, + [INDEX_PRODUCT] = &string_product, + }; + + if (string_index == 0) { + return (&string_lang); + } + if (lang_id != 0x0409) { + return (NULL); + } + if (string_index < INDEX_MAX) { + return (ptr[string_index]); + } + return (NULL); +} diff --git a/sys/dev/usb/template/usb_template_modem.c b/sys/dev/usb/template/usb_template_modem.c new file mode 100644 index 0000000..6e0f940 --- /dev/null +++ b/sys/dev/usb/template/usb_template_modem.c @@ -0,0 +1,252 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010 Hans Petter Selasky. 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. + */ + +/* + * This file contains the USB template for an USB Modem Device. + */ + +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_cdc.h> + +#include <dev/usb/template/usb_template.h> + +enum { + INDEX_LANG, + INDEX_MODEM, + INDEX_PRODUCT, + INDEX_MAX, +}; + +#define STRING_LANG \ + 0x09, 0x04, /* American English */ + +#define STRING_PRODUCT \ + 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ + 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, + +#define STRING_MODEM \ + 'M', 0, 'o', 0, 'd', 0, 'e', 0, 'm', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + +/* make the real string descriptors */ + +USB_MAKE_STRING_DESC(STRING_LANG, string_lang); +USB_MAKE_STRING_DESC(STRING_MODEM, string_modem); +USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); + +#define MODEM_IFACE_0 0 +#define MODEM_IFACE_1 1 + +/* prototypes */ + +static const struct usb_temp_packet_size modem_bulk_mps = { + .mps[USB_SPEED_LOW] = 8, + .mps[USB_SPEED_FULL] = 64, + .mps[USB_SPEED_HIGH] = 512, +}; + +static const struct usb_temp_packet_size modem_intr_mps = { + .mps[USB_SPEED_LOW] = 8, + .mps[USB_SPEED_FULL] = 8, + .mps[USB_SPEED_HIGH] = 8, +}; + +static const struct usb_temp_interval modem_intr_interval = { + .bInterval[USB_SPEED_LOW] = 10, + .bInterval[USB_SPEED_FULL] = 10, + .bInterval[USB_SPEED_HIGH] = 10 * 8, +}; + +static const struct usb_temp_endpoint_desc modem_ep_0 = { + .pPacketSize = &modem_intr_mps, + .pIntervals = &modem_intr_interval, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_INTERRUPT, +}; + +static const struct usb_temp_endpoint_desc modem_ep_1 = { + .pPacketSize = &modem_bulk_mps, + .bEndpointAddress = UE_DIR_OUT, + .bmAttributes = UE_BULK, +}; + +static const struct usb_temp_endpoint_desc modem_ep_2 = { + .pPacketSize = &modem_bulk_mps, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_BULK, +}; + +static const struct usb_temp_endpoint_desc *modem_iface_0_ep[] = { + &modem_ep_0, + NULL, +}; + +static const struct usb_temp_endpoint_desc *modem_iface_1_ep[] = { + &modem_ep_1, + &modem_ep_2, + NULL, +}; + +static const uint8_t modem_raw_desc_0[] = { + 0x05, 0x24, 0x00, 0x10, 0x01 +}; + +static const uint8_t modem_raw_desc_1[] = { + 0x05, 0x24, 0x06, MODEM_IFACE_0, MODEM_IFACE_1 +}; + +static const uint8_t modem_raw_desc_2[] = { + 0x05, 0x24, 0x01, 0x03, MODEM_IFACE_1 +}; + +static const uint8_t modem_raw_desc_3[] = { + 0x04, 0x24, 0x02, 0x07 +}; + +static const void *modem_iface_0_desc[] = { + &modem_raw_desc_0, + &modem_raw_desc_1, + &modem_raw_desc_2, + &modem_raw_desc_3, + NULL, +}; + +static const struct usb_temp_interface_desc modem_iface_0 = { + .ppRawDesc = modem_iface_0_desc, + .ppEndpoints = modem_iface_0_ep, + .bInterfaceClass = 2, + .bInterfaceSubClass = 2, + .bInterfaceProtocol = 1, + .iInterface = INDEX_MODEM, +}; + +static const struct usb_temp_interface_desc modem_iface_1 = { + .ppEndpoints = modem_iface_1_ep, + .bInterfaceClass = 10, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = INDEX_MODEM, +}; + +static const struct usb_temp_interface_desc *modem_interfaces[] = { + &modem_iface_0, + &modem_iface_1, + NULL, +}; + +static const struct usb_temp_config_desc modem_config_desc = { + .ppIfaceDesc = modem_interfaces, + .bmAttributes = UC_BUS_POWERED, + .bMaxPower = 25, /* 50 mA */ + .iConfiguration = INDEX_PRODUCT, +}; + +static const struct usb_temp_config_desc *modem_configs[] = { + &modem_config_desc, + NULL, +}; + +static usb_temp_get_string_desc_t modem_get_string_desc; +static usb_temp_get_vendor_desc_t modem_get_vendor_desc; + +const struct usb_temp_device_desc usb_template_modem = { + .getStringDesc = &modem_get_string_desc, + .getVendorDesc = &modem_get_vendor_desc, + .ppConfigDesc = modem_configs, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x000E, + .bcdDevice = 0x0100, + .bDeviceClass = UDCLASS_COMM, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .iManufacturer = 0, + .iProduct = INDEX_PRODUCT, + .iSerialNumber = 0, +}; + +/*------------------------------------------------------------------------* + * modem_get_vendor_desc + * + * Return values: + * NULL: Failure. No such vendor descriptor. + * Else: Success. Pointer to vendor descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +modem_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) +{ + return (NULL); +} + +/*------------------------------------------------------------------------* + * modem_get_string_desc + * + * Return values: + * NULL: Failure. No such string. + * Else: Success. Pointer to string descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +modem_get_string_desc(uint16_t lang_id, uint8_t string_index) +{ + static const void *ptr[INDEX_MAX] = { + [INDEX_LANG] = &string_lang, + [INDEX_MODEM] = &string_modem, + [INDEX_PRODUCT] = &string_product, + }; + + if (string_index == 0) { + return (&string_lang); + } + if (lang_id != 0x0409) { + return (NULL); + } + if (string_index < INDEX_MAX) { + return (ptr[string_index]); + } + return (NULL); +} diff --git a/sys/dev/usb/template/usb_template_mouse.c b/sys/dev/usb/template/usb_template_mouse.c new file mode 100644 index 0000000..3ff0fb0 --- /dev/null +++ b/sys/dev/usb/template/usb_template_mouse.c @@ -0,0 +1,222 @@ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/*- + * Copyright (c) 2010 Hans Petter Selasky. 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. + */ + +/* + * This file contains the USB template for an USB Mouse Device. + */ + +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usb_cdc.h> + +#include <dev/usb/template/usb_template.h> + +enum { + INDEX_LANG, + INDEX_MOUSE, + INDEX_PRODUCT, + INDEX_MAX, +}; + +#define STRING_LANG \ + 0x09, 0x04, /* American English */ + +#define STRING_PRODUCT \ + 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \ + 'T', 0, 'e', 0, 's', 0, 't', 0, ' ', 0, \ + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, + +#define STRING_MOUSE \ + 'M', 0, 'o', 0, 'u', 0, 's', 0, 'e', 0, ' ', 0, \ + 'i', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0, + +/* make the real string descriptors */ + +USB_MAKE_STRING_DESC(STRING_LANG, string_lang); +USB_MAKE_STRING_DESC(STRING_MOUSE, string_mouse); +USB_MAKE_STRING_DESC(STRING_PRODUCT, string_product); + +/* prototypes */ + +/* The following HID descriptor was dumped from a HP mouse. */ + +static uint8_t mouse_hid_descriptor[] = { + 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, + 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, + 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, + 0x81, 0x02, 0x95, 0x05, 0x81, 0x03, 0x05, 0x01, + 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, + 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, + 0xc0, 0xc0 +}; + +static const struct usb_temp_packet_size mouse_intr_mps = { + .mps[USB_SPEED_LOW] = 8, + .mps[USB_SPEED_FULL] = 8, + .mps[USB_SPEED_HIGH] = 8, +}; + +static const struct usb_temp_interval mouse_intr_interval = { + .bInterval[USB_SPEED_LOW] = 2, + .bInterval[USB_SPEED_FULL] = 2, + .bInterval[USB_SPEED_HIGH] = 2 * 8, +}; + +static const struct usb_temp_endpoint_desc mouse_ep_0 = { + .ppRawDesc = NULL, /* no raw descriptors */ + .pPacketSize = &mouse_intr_mps, + .pIntervals = &mouse_intr_interval, + .bEndpointAddress = UE_DIR_IN, + .bmAttributes = UE_INTERRUPT, +}; + +static const struct usb_temp_endpoint_desc *mouse_endpoints[] = { + &mouse_ep_0, + NULL, +}; + +static const uint8_t mouse_raw_desc[] = { + 0x09, 0x21, 0x10, 0x01, 0x00, 0x01, 0x22, sizeof(mouse_hid_descriptor), + 0x00 +}; + +static const void *mouse_iface_0_desc[] = { + mouse_raw_desc, + NULL, +}; + +static const struct usb_temp_interface_desc mouse_iface_0 = { + .ppRawDesc = mouse_iface_0_desc, + .ppEndpoints = mouse_endpoints, + .bInterfaceClass = 3, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 2, + .iInterface = INDEX_MOUSE, +}; + +static const struct usb_temp_interface_desc *mouse_interfaces[] = { + &mouse_iface_0, + NULL, +}; + +static const struct usb_temp_config_desc mouse_config_desc = { + .ppIfaceDesc = mouse_interfaces, + .bmAttributes = UC_BUS_POWERED, + .bMaxPower = 25, /* 50 mA */ + .iConfiguration = INDEX_PRODUCT, +}; + +static const struct usb_temp_config_desc *mouse_configs[] = { + &mouse_config_desc, + NULL, +}; + +static usb_temp_get_string_desc_t mouse_get_string_desc; +static usb_temp_get_vendor_desc_t mouse_get_vendor_desc; + +const struct usb_temp_device_desc usb_template_mouse = { + .getStringDesc = &mouse_get_string_desc, + .getVendorDesc = &mouse_get_vendor_desc, + .ppConfigDesc = mouse_configs, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x00AE, + .bcdDevice = 0x0100, + .bDeviceClass = UDCLASS_COMM, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .iManufacturer = 0, + .iProduct = INDEX_PRODUCT, + .iSerialNumber = 0, +}; + +/*------------------------------------------------------------------------* + * mouse_get_vendor_desc + * + * Return values: + * NULL: Failure. No such vendor descriptor. + * Else: Success. Pointer to vendor descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +mouse_get_vendor_desc(const struct usb_device_request *req, uint16_t *plen) +{ + if ((req->bmRequestType == 0x81) && (req->bRequest == 0x06) && + (req->wValue[0] == 0x00) && (req->wValue[1] == 0x22) && + (req->wIndex[1] == 0) && (req->wIndex[0] == 0)) { + + *plen = sizeof(mouse_hid_descriptor); + return (mouse_hid_descriptor); + } + return (NULL); +} + +/*------------------------------------------------------------------------* + * mouse_get_string_desc + * + * Return values: + * NULL: Failure. No such string. + * Else: Success. Pointer to string descriptor is returned. + *------------------------------------------------------------------------*/ +static const void * +mouse_get_string_desc(uint16_t lang_id, uint8_t string_index) +{ + static const void *ptr[INDEX_MAX] = { + [INDEX_LANG] = &string_lang, + [INDEX_MOUSE] = &string_mouse, + [INDEX_PRODUCT] = &string_product, + }; + + if (string_index == 0) { + return (&string_lang); + } + if (lang_id != 0x0409) { + return (NULL); + } + if (string_index < INDEX_MAX) { + return (ptr[string_index]); + } + return (NULL); +} diff --git a/sys/dev/usb/template/usb_template_msc.c b/sys/dev/usb/template/usb_template_msc.c index 598c9fd..5c05ffe 100644 --- a/sys/dev/usb/template/usb_template_msc.c +++ b/sys/dev/usb/template/usb_template_msc.c @@ -173,8 +173,8 @@ static const struct usb_temp_config_desc *msc_configs[] = { const struct usb_temp_device_desc usb_template_msc = { .getStringDesc = &msc_get_string_desc, .ppConfigDesc = msc_configs, - .idVendor = 0x0001, - .idProduct = 0x0001, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x0012, .bcdDevice = 0x0100, .bDeviceClass = UDCLASS_COMM, .bDeviceSubClass = 0, diff --git a/sys/dev/usb/template/usb_template_mtp.c b/sys/dev/usb/template/usb_template_mtp.c index ad09b58..f48fbf4 100644 --- a/sys/dev/usb/template/usb_template_mtp.c +++ b/sys/dev/usb/template/usb_template_mtp.c @@ -191,8 +191,8 @@ const struct usb_temp_device_desc usb_template_mtp = { .getStringDesc = &mtp_get_string_desc, .getVendorDesc = &mtp_get_vendor_desc, .ppConfigDesc = mtp_configs, - .idVendor = 0x0001, - .idProduct = 0x0001, + .idVendor = USB_TEMPLATE_VENDOR, + .idProduct = 0x0011, .bcdDevice = 0x0100, .bDeviceClass = 0, .bDeviceSubClass = 0, diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 893e79d..932c022 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1297,6 +1297,21 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index) usb_init_attach_arg(udev, &uaa); + /* + * If the whole USB device is targeted, invoke the USB event + * handler(s): + */ + if (iface_index == USB_IFACE_INDEX_ANY) { + + EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa); + + if (uaa.dev_state != UAA_DEV_READY) { + /* leave device unconfigured */ + usb_unconfigure(udev, 0); + goto done; + } + } + /* Check if only one interface should be probed: */ if (iface_index != USB_IFACE_INDEX_ANY) { i = iface_index; @@ -1343,17 +1358,18 @@ usb_probe_and_attach(struct usb_device *udev, uint8_t iface_index) uaa.info.bIfaceIndex, uaa.info.bIfaceNum); - if (usb_probe_and_attach_sub(udev, &uaa)) { - /* ignore */ - } - } - - if (uaa.temp_dev) { - /* remove the last created child; it is unused */ + usb_probe_and_attach_sub(udev, &uaa); - if (device_delete_child(udev->parent_dev, uaa.temp_dev)) { + /* + * Remove the leftover child, if any, to enforce that + * a new nomatch devd event is generated for the next + * interface if no driver is found: + */ + if (uaa.temp_dev == NULL) + continue; + if (device_delete_child(udev->parent_dev, uaa.temp_dev)) DPRINTFN(0, "device delete child failed\n"); - } + uaa.temp_dev = NULL; } done: if (do_unlock) @@ -1526,7 +1542,7 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus, /* initialise our SX-lock */ sx_init_flags(&udev->enum_sx, "USB config SX lock", SX_DUPOK); - sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_DUPOK); + sx_init_flags(&udev->sr_sx, "USB suspend and resume SX lock", SX_NOWITNESS); cv_init(&udev->ctrlreq_cv, "WCTRL"); cv_init(&udev->ref_cv, "UGONE"); @@ -1834,11 +1850,6 @@ repeat_set_config: } } } - EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa); - if (uaa.dev_state != UAA_DEV_READY) { - /* leave device unconfigured */ - usb_unconfigure(udev, 0); - } config_done: DPRINTF("new dev (addr %d), udev=%p, parent_hub=%p\n", diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 351b134..12898ec 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -1334,15 +1334,19 @@ uhub_child_pnpinfo_string(device_t parent, device_t child, "devclass=0x%02x devsubclass=0x%02x " "sernum=\"%s\" " "release=0x%04x " - "intclass=0x%02x intsubclass=0x%02x" "%s%s", + "mode=%s " + "intclass=0x%02x intsubclass=0x%02x " + "intprotocol=0x%02x " "%s%s", UGETW(res.udev->ddesc.idVendor), UGETW(res.udev->ddesc.idProduct), res.udev->ddesc.bDeviceClass, res.udev->ddesc.bDeviceSubClass, usb_get_serial(res.udev), UGETW(res.udev->ddesc.bcdDevice), + (res.udev->flags.usb_mode == USB_MODE_HOST) ? "host" : "device", iface->idesc->bInterfaceClass, iface->idesc->bInterfaceSubClass, + iface->idesc->bInterfaceProtocol, iface->pnpinfo ? " " : "", iface->pnpinfo ? iface->pnpinfo : ""); } else { diff --git a/sys/dev/usb/usb_ioctl.h b/sys/dev/usb/usb_ioctl.h index 452de94..d35fa10 100644 --- a/sys/dev/usb/usb_ioctl.h +++ b/sys/dev/usb/usb_ioctl.h @@ -39,6 +39,20 @@ #define USB_DEVICE_NAME "usbctl" #define USB_DEVICE_DIR "usb" #define USB_GENERIC_NAME "ugen" +#define USB_TEMPLATE_SYSCTL "hw.usb.template" /* integer type */ + +/* Definition of valid template sysctl values */ + +enum { + USB_TEMP_MSC, /* USB Mass Storage */ + USB_TEMP_CDCE, /* USB CDC Ethernet */ + USB_TEMP_MTP, /* Message Transfer Protocol */ + USB_TEMP_MODEM, /* USB CDC Modem */ + USB_TEMP_AUDIO, /* USB Audio */ + USB_TEMP_KBD, /* USB Keyboard */ + USB_TEMP_MOUSE, /* USB Mouse */ + USB_TEMP_MAX, +}; struct usb_read_dir { #ifdef COMPAT_32BIT diff --git a/sys/dev/usb/usb_lookup.c b/sys/dev/usb/usb_lookup.c index ced925e..e03f9b6 100644 --- a/sys/dev/usb/usb_lookup.c +++ b/sys/dev/usb/usb_lookup.c @@ -42,6 +42,8 @@ #include <sys/callout.h> #include <sys/malloc.h> #include <sys/priv.h> +#include <sys/limits.h> +#include <sys/endian.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> @@ -105,13 +107,6 @@ usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id, (id->bDeviceProtocol != info->bDeviceProtocol)) { continue; } - if ((info->bDeviceClass == 0xFF) && - (!(id->match_flag_vendor)) && - ((id->match_flag_int_class) || - (id->match_flag_int_subclass) || - (id->match_flag_int_protocol))) { - continue; - } if ((id->match_flag_int_class) && (id->bInterfaceClass != info->bInterfaceClass)) { continue; @@ -151,3 +146,108 @@ usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, } return (ENXIO); } + +/*------------------------------------------------------------------------* + * Export the USB device ID format we use to userspace tools. + *------------------------------------------------------------------------*/ +#if BYTE_ORDER == BIG_ENDIAN +#define U16_XOR "8" +#define U32_XOR "12" +#define U64_XOR "56" +#define U8_BITFIELD_XOR "7" +#define U16_BITFIELD_XOR "15" +#define U32_BITFIELD_XOR "31" +#define U64_BITFIELD_XOR "63" +#else +#define U16_XOR "0" +#define U32_XOR "0" +#define U64_XOR "0" +#define U8_BITFIELD_XOR "0" +#define U16_BITFIELD_XOR "0" +#define U32_BITFIELD_XOR "0" +#define U64_BITFIELD_XOR "0" +#endif + +#if USB_HAVE_COMPAT_LINUX +#define MFL_SIZE "1" +#else +#define MFL_SIZE "0" +#endif + +#ifdef KLD_MODULE +static const char __section("bus_autoconf_format") __used usb_id_format[] = { + + /* Declare that three different sections use the same format */ + + "usb_host_id{256,:}" + "usb_device_id{256,:}" + "usb_dual_id{256,:}" + + /* List size of fields in the usb_device_id structure */ + +#if ULONG_MAX >= 0xFFFFFFFFUL + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#endif +#else +#error "Please update code." +#endif + + "idVendor[0]{" U16_XOR ",8}" + "idVendor[1]{" U16_XOR ",8}" + "idProduct[0]{" U16_XOR ",8}" + "idProduct[1]{" U16_XOR ",8}" + "bcdDevice_lo[0]{" U16_XOR ",8}" + "bcdDevice_lo[1]{" U16_XOR ",8}" + "bcdDevice_hi[0]{" U16_XOR ",8}" + "bcdDevice_hi[1]{" U16_XOR ",8}" + + "bDeviceClass{0,8}" + "bDeviceSubClass{0,8}" + "bDeviceProtocol{0,8}" + "bInterfaceClass{0,8}" + "bInterfaceSubClass{0,8}" + "bInterfaceProtocol{0,8}" + + "mf_vendor{" U8_BITFIELD_XOR ",1}" + "mf_product{" U8_BITFIELD_XOR ",1}" + "mf_dev_lo{" U8_BITFIELD_XOR ",1}" + "mf_dev_hi{" U8_BITFIELD_XOR ",1}" + + "mf_dev_class{" U8_BITFIELD_XOR ",1}" + "mf_dev_subclass{" U8_BITFIELD_XOR ",1}" + "mf_dev_protocol{" U8_BITFIELD_XOR ",1}" + "mf_int_class{" U8_BITFIELD_XOR ",1}" + + "mf_int_subclass{" U8_BITFIELD_XOR ",1}" + "mf_int_protocol{" U8_BITFIELD_XOR ",1}" + "unused{" U8_BITFIELD_XOR ",6}" + + "mfl_vendor{" U16_XOR "," MFL_SIZE "}" + "mfl_product{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}" + + "mfl_dev_class{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}" + "mfl_int_class{" U16_XOR "," MFL_SIZE "}" + + "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" +}; +#endif diff --git a/sys/dev/usb/usb_msctest.c b/sys/dev/usb/usb_msctest.c index 909615e..0b6024b 100644 --- a/sys/dev/usb/usb_msctest.c +++ b/sys/dev/usb/usb_msctest.c @@ -62,7 +62,6 @@ #include <dev/usb/usb_transfer.h> #include <dev/usb/usb_msctest.h> #include <dev/usb/usb_debug.h> -#include <dev/usb/usb_busdma.h> #include <dev/usb/usb_device.h> #include <dev/usb/usb_request.h> #include <dev/usb/usb_util.h> @@ -489,6 +488,24 @@ bbb_attach(struct usb_device *udev, uint8_t iface_index) struct usb_interface_descriptor *id; struct bbb_transfer *sc; usb_error_t err; + uint8_t do_unlock; + + /* automatic locking */ + if (usbd_enum_is_locked(udev)) { + do_unlock = 0; + } else { + do_unlock = 1; + usbd_enum_lock(udev); + } + + /* + * Make sure any driver which is hooked up to this interface, + * like umass is gone: + */ + usb_detach_device(udev, iface_index, 0); + + if (do_unlock) + usbd_enum_unlock(udev); iface = usbd_get_iface(udev, iface_index); if (iface == NULL) diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index 91cd3fa..d832c32 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -228,6 +228,18 @@ struct usb_config { }; /* + * Use these macro when defining USB device ID arrays if you want to + * have your driver module automatically loaded in host, device or + * both modes respectivly: + */ +#define STRUCT_USB_HOST_ID \ + struct usb_device_id __section("usb_host_id") +#define STRUCT_USB_DEVICE_ID \ + struct usb_device_id __section("usb_device_id") +#define STRUCT_USB_DUAL_ID \ + struct usb_device_id __section("usb_dual_id") + +/* * The following structure is used when looking up an USB driver for * an USB device. It is inspired by the Linux structure called * "usb_device_id". @@ -258,12 +270,15 @@ struct usb_device_id { uint8_t match_flag_product:1; uint8_t match_flag_dev_lo:1; uint8_t match_flag_dev_hi:1; + uint8_t match_flag_dev_class:1; uint8_t match_flag_dev_subclass:1; uint8_t match_flag_dev_protocol:1; uint8_t match_flag_int_class:1; + uint8_t match_flag_int_subclass:1; uint8_t match_flag_int_protocol:1; + uint8_t match_flag_unused:6; #if USB_HAVE_COMPAT_LINUX /* which fields to match against */ @@ -279,7 +294,10 @@ struct usb_device_id { #define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 #endif -}; +} __aligned(32); + +/* check that the size of the structure above is correct */ +extern char usb_device_id_assert[(sizeof(struct usb_device_id) == 32) ? 1 : -1]; #define USB_VENDOR(vend) \ .match_flag_vendor = 1, .idVendor = (vend) diff --git a/sys/dev/usb/wlan/if_rum.c b/sys/dev/usb/wlan/if_rum.c index 63b314d..5a69792 100644 --- a/sys/dev/usb/wlan/if_rum.c +++ b/sys/dev/usb/wlan/if_rum.c @@ -85,7 +85,7 @@ SYSCTL_INT(_hw_usb_rum, OID_AUTO, debug, CTLFLAG_RW, &rum_debug, 0, "Debug level"); #endif -static const struct usb_device_id rum_devs[] = { +static const STRUCT_USB_HOST_ID rum_devs[] = { #define RUM_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } RUM_DEV(ABOCOM, HWU54DM), RUM_DEV(ABOCOM, RT2573_2), diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 2cd147c..47823b9 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -96,7 +96,7 @@ SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, */ #define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) -static const struct usb_device_id run_devs[] = { +static const STRUCT_USB_HOST_ID run_devs[] = { #define RUN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } RUN_DEV(ABOCOM, RT2770), RUN_DEV(ABOCOM, RT2870), diff --git a/sys/dev/usb/wlan/if_uath.c b/sys/dev/usb/wlan/if_uath.c index 35202a9..328dc4f 100644 --- a/sys/dev/usb/wlan/if_uath.c +++ b/sys/dev/usb/wlan/if_uath.c @@ -167,9 +167,8 @@ enum { (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) /* recognized device vendors/products */ -static const struct usb_device_id uath_devs[] = { +static const STRUCT_USB_HOST_ID uath_devs[] = { #define UATH_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } - UATH_DEV(ACCTON, SMCWUSBG), UATH_DEV(ACCTON, SMCWUSBTG2), UATH_DEV(ATHEROS, AR5523), UATH_DEV(ATHEROS2, AR5523_1), diff --git a/sys/dev/usb/wlan/if_upgt.c b/sys/dev/usb/wlan/if_upgt.c index d704cec..b9381a2 100644 --- a/sys/dev/usb/wlan/if_upgt.c +++ b/sys/dev/usb/wlan/if_upgt.c @@ -170,7 +170,7 @@ static int upgt_tx_start(struct upgt_softc *, struct mbuf *, static const char *upgt_fwname = "upgt-gw3887"; -static const struct usb_device_id upgt_devs_2[] = { +static const STRUCT_USB_HOST_ID upgt_devs[] = { #define UPGT_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } /* version 2 devices */ UPGT_DEV(ACCTON, PRISM_GT), @@ -236,7 +236,7 @@ upgt_match(device_t dev) if (uaa->info.bIfaceIndex != UPGT_IFACE_INDEX) return (ENXIO); - return (usbd_lookup_id_by_uaa(upgt_devs_2, sizeof(upgt_devs_2), uaa)); + return (usbd_lookup_id_by_uaa(upgt_devs, sizeof(upgt_devs), uaa)); } static int diff --git a/sys/dev/usb/wlan/if_ural.c b/sys/dev/usb/wlan/if_ural.c index 65d974a..048392d 100644 --- a/sys/dev/usb/wlan/if_ural.c +++ b/sys/dev/usb/wlan/if_ural.c @@ -91,7 +91,7 @@ SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &ural_debug, 0, ((rssi) - (RAL_NOISE_FLOOR + RAL_RSSI_CORR)) : 0) /* various supported device vendors/products */ -static const struct usb_device_id ural_devs[] = { +static const STRUCT_USB_HOST_ID ural_devs[] = { #define URAL_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } URAL_DEV(ASUS, WL167G), URAL_DEV(ASUS, RT2570), diff --git a/sys/dev/usb/wlan/if_urtw.c b/sys/dev/usb/wlan/if_urtw.c index 3de2273..6ae7e16 100644 --- a/sys/dev/usb/wlan/if_urtw.c +++ b/sys/dev/usb/wlan/if_urtw.c @@ -102,7 +102,7 @@ TUNABLE_INT("hw.usb.urtw.preamble_mode", &urtw_preamble_mode); { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTW_REV_RTL8187L) } #define URTW_REV_RTL8187B 0 #define URTW_REV_RTL8187L 1 -static const struct usb_device_id urtw_devs[] = { +static const STRUCT_USB_HOST_ID urtw_devs[] = { URTW_DEV_B(NETGEAR, WG111V3), URTW_DEV_B(REALTEK, RTL8187B_0), URTW_DEV_B(REALTEK, RTL8187B_1), @@ -115,7 +115,7 @@ static const struct usb_device_id urtw_devs[] = { URTW_DEV_L(REALTEK, RTL8187), URTW_DEV_L(SITECOMEU, WL168V1), URTW_DEV_L(SURECOM, EP9001G2A), - { USB_VPI(0x1b75, 0x8187, URTW_REV_RTL8187L) }, + { USB_VPI(USB_VENDOR_OVISLINK, 0x8187, URTW_REV_RTL8187L) }, { USB_VPI(USB_VENDOR_DICKSMITH, 0x9401, URTW_REV_RTL8187L) }, { USB_VPI(USB_VENDOR_HP, 0xca02, URTW_REV_RTL8187L) }, { USB_VPI(USB_VENDOR_LOGITEC, 0x010c, URTW_REV_RTL8187L) }, diff --git a/sys/dev/usb/wlan/if_zyd.c b/sys/dev/usb/wlan/if_zyd.c index 43ec6ca..f8d905e 100644 --- a/sys/dev/usb/wlan/if_zyd.c +++ b/sys/dev/usb/wlan/if_zyd.c @@ -200,7 +200,7 @@ static const struct zyd_phy_pair zyd_def_phyB[] = ZYD_DEF_PHYB; { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211) } #define ZYD_ZD1211B_DEV(v,p) \ { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, ZYD_ZD1211B) } -static const struct usb_device_id zyd_devs[] = { +static const STRUCT_USB_HOST_ID zyd_devs[] = { /* ZYD_ZD1211 */ ZYD_ZD1211_DEV(3COM2, 3CRUSB10075), ZYD_ZD1211_DEV(ABOCOM, WL54), diff --git a/sys/dev/vr/if_vr.c b/sys/dev/vr/if_vr.c index 906ee1c..1c2aac2 100644 --- a/sys/dev/vr/if_vr.c +++ b/sys/dev/vr/if_vr.c @@ -185,7 +185,6 @@ static int vr_miibus_readreg(device_t, int, int); static int vr_miibus_writereg(device_t, int, int, int); static void vr_miibus_statchg(device_t); -static void vr_link_task(void *, int); static void vr_cam_mask(struct vr_softc *, uint32_t, int); static int vr_cam_data(struct vr_softc *, int, int, uint8_t *); static void vr_set_filter(struct vr_softc *); @@ -226,7 +225,6 @@ static device_method_t vr_methods[] = { DEVMETHOD(miibus_readreg, vr_miibus_readreg), DEVMETHOD(miibus_writereg, vr_miibus_writereg), DEVMETHOD(miibus_statchg, vr_miibus_statchg), - DEVMETHOD(miibus_linkchg, vr_miibus_statchg), { NULL, NULL } }; @@ -290,22 +288,13 @@ vr_miibus_writereg(device_t dev, int phy, int reg, int data) return (0); } -static void -vr_miibus_statchg(device_t dev) -{ - struct vr_softc *sc; - - sc = device_get_softc(dev); - taskqueue_enqueue(taskqueue_swi, &sc->vr_link_task); -} - /* * In order to fiddle with the * 'full-duplex' and '100Mbps' bits in the netconfig register, we * first have to put the transmit and/or receive logic in the idle state. */ static void -vr_link_task(void *arg, int pending) +vr_miibus_statchg(device_t dev) { struct vr_softc *sc; struct mii_data *mii; @@ -313,22 +302,25 @@ vr_link_task(void *arg, int pending) int lfdx, mfdx; uint8_t cr0, cr1, fc; - sc = (struct vr_softc *)arg; - - VR_LOCK(sc); + sc = device_get_softc(dev); mii = device_get_softc(sc->vr_miibus); ifp = sc->vr_ifp; if (mii == NULL || ifp == NULL || - (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { - VR_UNLOCK(sc); + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; - } - if (mii->mii_media_status & IFM_ACTIVE) { - if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->vr_link = 0; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + case IFM_100_TX: sc->vr_link = 1; - } else - sc->vr_link = 0; + break; + default: + break; + } + } if (sc->vr_link != 0) { cr0 = CSR_READ_1(sc, VR_CR0); @@ -384,11 +376,8 @@ vr_link_task(void *arg, int pending) "%s: Tx/Rx shutdown error -- resetting\n", __func__); sc->vr_flags |= VR_F_RESTART; - VR_UNLOCK(sc); - return; } } - VR_UNLOCK(sc); } @@ -621,7 +610,6 @@ vr_attach(device_t dev) mtx_init(&sc->vr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->vr_stat_callout, &sc->vr_mtx, 0); - TASK_INIT(&sc->vr_link_task, 0, vr_link_task, sc); SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0, @@ -841,7 +829,6 @@ vr_detach(device_t dev) vr_stop(sc); VR_UNLOCK(sc); callout_drain(&sc->vr_stat_callout); - taskqueue_drain(taskqueue_swi, &sc->vr_link_task); ether_ifdetach(ifp); } if (sc->vr_miibus) @@ -1559,6 +1546,8 @@ vr_tick(void *xsc) mii = device_get_softc(sc->vr_miibus); mii_tick(mii); + if (sc->vr_link == 0) + vr_miibus_statchg(sc->vr_dev); vr_watchdog(sc); callout_reset(&sc->vr_stat_callout, hz, vr_tick, sc); } @@ -2161,6 +2150,10 @@ vr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) sc = ifp->if_softc; mii = device_get_softc(sc->vr_miibus); VR_LOCK(sc); + if ((ifp->if_flags & IFF_UP) == 0) { + VR_UNLOCK(sc); + return; + } mii_pollstat(mii); VR_UNLOCK(sc); ifmr->ifm_active = mii->mii_media_active; diff --git a/sys/dev/vr/if_vrreg.h b/sys/dev/vr/if_vrreg.h index d686bdd..5e2b6b8 100644 --- a/sys/dev/vr/if_vrreg.h +++ b/sys/dev/vr/if_vrreg.h @@ -723,7 +723,6 @@ struct vr_softc { uint8_t vr_flags; /* See VR_F_* below */ #define VR_F_RESTART 0x01 /* Restart unit on next tick */ int vr_if_flags; - struct task vr_link_task; struct vr_chain_data vr_cdata; struct vr_ring_data vr_rdata; struct vr_statistics vr_stat; diff --git a/sys/dev/xl/if_xl.c b/sys/dev/xl/if_xl.c index f1c1d02..e09e434 100644 --- a/sys/dev/xl/if_xl.c +++ b/sys/dev/xl/if_xl.c @@ -334,7 +334,7 @@ xl_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) * only a finite amount of time to avoid getting caught in an * infinite loop. Normally this delay routine would be a macro, * but it isn't called during normal operation so we can afford - * to make it a function. + * to make it a function. Suppress warning when card gone. */ static void xl_wait(struct xl_softc *sc) @@ -346,7 +346,7 @@ xl_wait(struct xl_softc *sc) break; } - if (i == XL_TIMEOUT) + if (i == XL_TIMEOUT && bus_child_present(sc->xl_dev)) device_printf(sc->xl_dev, "command never completed!\n"); } diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c index df23e49..f658ac8 100644 --- a/sys/fs/nfs/nfs_commonkrpc.c +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -526,6 +526,20 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, else secflavour = RPCSEC_GSS_KRB5; srv_principal = NFSMNT_SRVKRBNAME(nmp); + } else if (nmp != NULL && !NFSHASKERB(nmp) && + nd->nd_procnum != NFSPROC_NULL && + (nd->nd_flag & ND_USEGSSNAME) != 0) { + /* + * Use the uid that did the mount when the RPC is doing + * NFSv4 system operations, as indicated by the + * ND_USEGSSNAME flag, for the AUTH_SYS case. + */ + saved_uid = cred->cr_uid; + if (nmp->nm_uid != (uid_t)-1) + cred->cr_uid = nmp->nm_uid; + else + cred->cr_uid = 0; + set_uid = 1; } if (nmp != NULL) { @@ -719,6 +733,8 @@ tryagain: while (NFSD_MONOSEC < waituntil) (void) nfs_catnap(PZERO, 0, "nfstry"); trylater_delay *= 2; + m_freem(nd->nd_mrep); + nd->nd_mrep = NULL; goto tryagain; } diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h index a15f93b..5ae2e3d 100644 --- a/sys/fs/nfs/nfsproto.h +++ b/sys/fs/nfs/nfsproto.h @@ -868,15 +868,24 @@ struct nfsv3_sattr { * NFSATTRBIT_WRITEGETATTR0 - bits 0<->31 */ #define NFSATTRBIT_WRITEGETATTR0 \ - (NFSATTRBM_CHANGE | \ + (NFSATTRBM_SUPPORTEDATTRS | \ + NFSATTRBM_TYPE | \ + NFSATTRBM_CHANGE | \ NFSATTRBM_SIZE | \ - NFSATTRBM_FSID) + NFSATTRBM_FSID | \ + NFSATTRBM_FILEID | \ + NFSATTRBM_MAXREAD) /* * NFSATTRBIT_WRITEGETATTR1 - bits 32<->63 */ #define NFSATTRBIT_WRITEGETATTR1 \ - (NFSATTRBM_TIMEMETADATA | \ + (NFSATTRBM_MODE | \ + NFSATTRBM_NUMLINKS | \ + NFSATTRBM_RAWDEV | \ + NFSATTRBM_SPACEUSED | \ + NFSATTRBM_TIMEACCESS | \ + NFSATTRBM_TIMEMETADATA | \ NFSATTRBM_TIMEMODIFY) /* diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 0538382..4a95887 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -388,6 +388,7 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper, np->n_vattr.na_mtime = nap->na_mtime; np->n_vattr.na_ctime = nap->na_ctime; np->n_vattr.na_fsid = nap->na_fsid; + np->n_vattr.na_mode = nap->na_mode; } else { NFSBCOPY((caddr_t)nap, (caddr_t)&np->n_vattr, sizeof (struct nfsvattr)); diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 5d83d0b..ee73882 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -1527,8 +1527,8 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, * deadlock, is that the upcall times out and allows * the write to complete. However, progress is so slow * that it might just as well be deadlocked. - * So, we just get the attributes that change with each - * write Op. + * As such, we get the rest of the attributes, but not + * Owner or Owner_group. * nb: nfscl_loadattrcache() needs to be told that these * partial attributes from a write rpc are being * passed in, via a argument flag. diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index fc296c0..64aafb4 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -172,11 +172,12 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, fhandle_t fh; int at_root = 0, error = 0, supports_nfsv4acls; struct nfsreferral *refp; - nfsattrbit_t attrbits; + nfsattrbit_t attrbits, tmpbits; struct mount *mp; struct vnode *tvp = NULL; struct vattr va; uint64_t mounted_on_fileno = 0; + accmode_t accmode; if (nd->nd_repstat) return (0); @@ -197,11 +198,20 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, vput(vp); return (0); } - if (!nd->nd_repstat) - nd->nd_repstat = nfsvno_accchk(vp, - VREAD_ATTRIBUTES, - nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, - NFSACCCHK_VPISLOCKED, NULL); + if (nd->nd_repstat == 0) { + accmode = 0; + NFSSET_ATTRBIT(&tmpbits, &attrbits); + if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { + NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); + accmode |= VREAD_ACL; + } + if (NFSNONZERO_ATTRBIT(&tmpbits)) + accmode |= VREAD_ATTRIBUTES; + if (accmode != 0) + nd->nd_repstat = nfsvno_accchk(vp, accmode, + nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, + NFSACCCHK_VPISLOCKED, NULL); + } } if (!nd->nd_repstat) nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index 5a07a45..e9324cf 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -926,7 +926,7 @@ tmpfs_reg_resize(struct vnode *vp, off_t newsize) if (newpages < oldpages) { swap_pager_freespace(uobj, newpages, oldpages - newpages); - vm_object_page_remove(uobj, newpages, 0, FALSE); + vm_object_page_remove(uobj, newpages, 0, 0); } /* diff --git a/sys/geom/part/g_part_ebr.c b/sys/geom/part/g_part_ebr.c index 8ea9b47..85b8a8a 100644 --- a/sys/geom/part/g_part_ebr.c +++ b/sys/geom/part/g_part_ebr.c @@ -59,6 +59,9 @@ FEATURE(geom_part_ebr_compat, struct g_part_ebr_table { struct g_part_table base; +#ifndef GEOM_PART_EBR_COMPAT + u_char ebr[EBRSIZE]; +#endif }; struct g_part_ebr_entry { @@ -459,7 +462,7 @@ g_part_ebr_read(struct g_part_table *basetable, struct g_consumer *cp) u_char *buf; off_t ofs, msize; u_int lba; - int error, index, sum; + int error, index; pp = cp->provider; table = (struct g_part_ebr_table *)basetable; @@ -482,20 +485,11 @@ g_part_ebr_read(struct g_part_table *basetable, struct g_consumer *cp) printf("GEOM: %s: invalid entries in the EBR ignored.\n", pp->name); } - /* We do not support bootcode for EBR. If bootcode area is - * not zeroes, then mark this EBR as corrupt to do not break - * anything for another OS'es. - */ - if (lba == 0) { - sum = 0; - for (index = 0; index < DOSPARTOFF; index++) - sum += buf[index]; - if (sum != 0) { - basetable->gpt_corrupt = 1; - printf("GEOM: %s: EBR has non empty bootcode.\n", - pp->name); - } - } +#ifndef GEOM_PART_EBR_COMPAT + /* Save the first EBR, it can contain a boot code */ + if (lba == 0) + bcopy(buf, table->ebr, sizeof(table->ebr)); +#endif g_free(buf); if (ent[0].dp_typ == 0) @@ -583,6 +577,9 @@ g_part_ebr_type(struct g_part_table *basetable, struct g_part_entry *baseentry, static int g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp) { +#ifndef GEOM_PART_EBR_COMPAT + struct g_part_ebr_table *table; +#endif struct g_provider *pp; struct g_part_entry *baseentry, *next; struct g_part_ebr_entry *entry; @@ -592,6 +589,10 @@ g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp) pp = cp->provider; buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO); +#ifndef GEOM_PART_EBR_COMPAT + table = (struct g_part_ebr_table *)basetable; + bcopy(table->ebr, buf, DOSPARTOFF); +#endif le16enc(buf + DOSMAGICOFFSET, DOSMAGIC); baseentry = LIST_FIRST(&basetable->gpt_entry); @@ -644,7 +645,10 @@ g_part_ebr_write(struct g_part_table *basetable, struct g_consumer *cp) error = g_write_data(cp, baseentry->gpe_start * pp->sectorsize, buf, pp->sectorsize); - +#ifndef GEOM_PART_EBR_COMPAT + if (baseentry->gpe_start == 0) + bzero(buf, DOSPARTOFF); +#endif baseentry = next; } while (!error && baseentry != NULL); diff --git a/sys/geom/part/g_part_gpt.c b/sys/geom/part/g_part_gpt.c index 9e897a4..667a8d6 100644 --- a/sys/geom/part/g_part_gpt.c +++ b/sys/geom/part/g_part_gpt.c @@ -88,6 +88,7 @@ struct g_part_gpt_entry { static void g_gpt_printf_utf16(struct sbuf *, uint16_t *, size_t); static void g_gpt_utf8_to_utf16(const uint8_t *, uint16_t *, size_t); +static void g_gpt_set_defaults(struct g_part_table *, struct g_provider *); static int g_part_gpt_add(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); @@ -493,12 +494,7 @@ g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) table->mbr[DOSPARTOFF + 6] = 0xff; /* esect */ table->mbr[DOSPARTOFF + 7] = 0xff; /* ecyl */ le32enc(table->mbr + DOSPARTOFF + 8, 1); /* start */ - le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, 0xffffffffLL)); - - table->lba[GPT_ELT_PRIHDR] = 1; - table->lba[GPT_ELT_PRITBL] = 2; - table->lba[GPT_ELT_SECHDR] = last; - table->lba[GPT_ELT_SECTBL] = last - tblsz; + le32enc(table->mbr + DOSPARTOFF + 12, MIN(last, UINT32_MAX)); /* Allocate space for the header */ table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO); @@ -506,14 +502,11 @@ g_part_gpt_create(struct g_part_table *basetable, struct g_part_parms *gpp) bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig)); table->hdr->hdr_revision = GPT_HDR_REVISION; table->hdr->hdr_size = offsetof(struct gpt_hdr, padding); - table->hdr->hdr_lba_start = 2 + tblsz; - table->hdr->hdr_lba_end = last - tblsz - 1; kern_uuidgen(&table->hdr->hdr_uuid, 1); table->hdr->hdr_entries = basetable->gpt_entries; table->hdr->hdr_entsz = sizeof(struct gpt_ent); - basetable->gpt_first = table->hdr->hdr_lba_start; - basetable->gpt_last = table->hdr->hdr_lba_end; + g_gpt_set_defaults(basetable, pp); return (0); } @@ -815,32 +808,10 @@ g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp) static int g_part_gpt_recover(struct g_part_table *basetable) { - struct g_part_gpt_table *table; - struct g_provider *pp; - uint64_t last; - size_t tblsz; - - table = (struct g_part_gpt_table *)basetable; - pp = LIST_FIRST(&basetable->gpt_gp->consumer)->provider; - last = pp->mediasize / pp->sectorsize - 1; - tblsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz + - pp->sectorsize - 1) / pp->sectorsize; - - table->lba[GPT_ELT_PRIHDR] = 1; - table->lba[GPT_ELT_PRITBL] = 2; - table->lba[GPT_ELT_SECHDR] = last; - table->lba[GPT_ELT_SECTBL] = last - tblsz; - table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK; - table->state[GPT_ELT_PRITBL] = GPT_STATE_OK; - table->state[GPT_ELT_SECHDR] = GPT_STATE_OK; - table->state[GPT_ELT_SECTBL] = GPT_STATE_OK; - table->hdr->hdr_lba_start = 2 + tblsz; - table->hdr->hdr_lba_end = last - tblsz - 1; - basetable->gpt_first = table->hdr->hdr_lba_start; - basetable->gpt_last = table->hdr->hdr_lba_end; + g_gpt_set_defaults(basetable, + LIST_FIRST(&basetable->gpt_gp->consumer)->provider); basetable->gpt_corrupt = 0; - return (0); } @@ -1039,6 +1010,34 @@ g_part_gpt_write(struct g_part_table *basetable, struct g_consumer *cp) } static void +g_gpt_set_defaults(struct g_part_table *basetable, struct g_provider *pp) +{ + struct g_part_gpt_table *table; + quad_t last; + size_t tblsz; + + table = (struct g_part_gpt_table *)basetable; + last = pp->mediasize / pp->sectorsize - 1; + tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) + + pp->sectorsize - 1) / pp->sectorsize; + + table->lba[GPT_ELT_PRIHDR] = 1; + table->lba[GPT_ELT_PRITBL] = 2; + table->lba[GPT_ELT_SECHDR] = last; + table->lba[GPT_ELT_SECTBL] = last - tblsz; + table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK; + table->state[GPT_ELT_PRITBL] = GPT_STATE_OK; + table->state[GPT_ELT_SECHDR] = GPT_STATE_OK; + table->state[GPT_ELT_SECTBL] = GPT_STATE_OK; + + table->hdr->hdr_lba_start = 2 + tblsz; + table->hdr->hdr_lba_end = last - tblsz - 1; + + basetable->gpt_first = table->hdr->hdr_lba_start; + basetable->gpt_last = table->hdr->hdr_lba_end; +} + +static void g_gpt_printf_utf16(struct sbuf *sb, uint16_t *str, size_t len) { u_int bo; diff --git a/sys/geom/part/g_part_mbr.c b/sys/geom/part/g_part_mbr.c index 825a109..bebdfee 100644 --- a/sys/geom/part/g_part_mbr.c +++ b/sys/geom/part/g_part_mbr.c @@ -237,14 +237,16 @@ static int g_part_mbr_bootcode(struct g_part_table *basetable, struct g_part_parms *gpp) { struct g_part_mbr_table *table; - size_t codesz; + uint32_t dsn; + + if (gpp->gpp_codesize != MBRSIZE) + return (ENODEV); - codesz = DOSPARTOFF; table = (struct g_part_mbr_table *)basetable; - bzero(table->mbr, codesz); - codesz = MIN(codesz, gpp->gpp_codesize); - if (codesz > 0) - bcopy(gpp->gpp_codeptr, table->mbr, codesz); + dsn = *(uint32_t *)(table->mbr + DOSDSNOFF); + bcopy(gpp->gpp_codeptr, table->mbr, DOSPARTOFF); + if (dsn != 0) + *(uint32_t *)(table->mbr + DOSDSNOFF) = dsn; return (0); } diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index 3f9248d..45d19b2 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -2927,8 +2927,8 @@ pmap_remove_all(vm_page_t m) vm_offset_t va; vm_page_t free; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); sched_pin(); diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c index 6a761bf..8370516 100644 --- a/sys/i386/i386/sys_machdep.c +++ b/sys/i386/i386/sys_machdep.c @@ -32,7 +32,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_capabilities.h" +#include "opt_capsicum.h" #include "opt_kstack_pages.h" #include <sys/param.h> @@ -111,24 +111,26 @@ sysarch(td, uap) AUDIT_ARG_CMD(uap->op); -#ifdef CAPABILITIES +#ifdef CAPABILITY_MODE /* - * Whitelist of operations which are safe enough for capability mode. + * When adding new operations, add a new case statement here to + * explicitly indicate whether or not the operation is safe to + * perform in capability mode. */ if (IN_CAPABILITY_MODE(td)) { switch (uap->op) { - case I386_GET_LDT: - case I386_SET_LDT: - case I386_GET_IOPERM: - case I386_GET_FSBASE: - case I386_SET_FSBASE: - case I386_GET_GSBASE: - case I386_SET_GSBASE: - break; + case I386_GET_LDT: + case I386_SET_LDT: + case I386_GET_IOPERM: + case I386_GET_FSBASE: + case I386_SET_FSBASE: + case I386_GET_GSBASE: + case I386_SET_GSBASE: + break; - case I386_SET_IOPERM: - default: - return (ECAPMODE); + case I386_SET_IOPERM: + default: + return (ECAPMODE); } } #endif diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h index 11ac12e..d95fcf3 100644 --- a/sys/i386/include/param.h +++ b/sys/i386/include/param.h @@ -56,6 +56,7 @@ #define __HAVE_ACPI +#define __HAVE_PIR #define __PCI_REROUTE_INTERRUPT #ifndef MACHINE diff --git a/sys/i386/include/pci_cfgreg.h b/sys/i386/include/pci_cfgreg.h index bc72418..717d5cc 100644 --- a/sys/i386/include/pci_cfgreg.h +++ b/sys/i386/include/pci_cfgreg.h @@ -1,52 +1,6 @@ /*- - * Copyright (c) 1997, Stefan Esser <se@freebsd.org> - * 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 unmodified, 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. - * - * $FreeBSD$ - * + * This file is in the public domain. */ +/* $FreeBSD$ */ -#define CONF1_ADDR_PORT 0x0cf8 -#define CONF1_DATA_PORT 0x0cfc - -#define CONF1_ENABLE 0x80000000ul -#define CONF1_ENABLE_CHK 0x80000000ul -#define CONF1_ENABLE_MSK 0x7f000000ul -#define CONF1_ENABLE_CHK1 0xff000001ul -#define CONF1_ENABLE_MSK1 0x80000001ul -#define CONF1_ENABLE_RES1 0x80000000ul - -#define CONF2_ENABLE_PORT 0x0cf8 -#define CONF2_FORWARD_PORT 0x0cfa - -#define CONF2_ENABLE_CHK 0x0e -#define CONF2_ENABLE_RES 0x0e - -int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus); -int pci_cfgregopen(void); -u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); -void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); -void pci_pir_open(void); -int pci_pir_probe(int bus, int require_parse); -int pci_pir_route_interrupt(int bus, int device, int func, int pin); +#include <x86/pci_cfgreg.h> diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c index 3efa4f1..a23ae6d 100644 --- a/sys/i386/xen/pmap.c +++ b/sys/i386/xen/pmap.c @@ -2421,8 +2421,8 @@ pmap_remove_all(vm_page_t m) pt_entry_t *pte, tpte; vm_page_t free; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); free = NULL; vm_page_lock_queues(); sched_pin(); diff --git a/sys/ia64/conf/NOTES b/sys/ia64/conf/NOTES index 3f38218..0f8a4e7 100644 --- a/sys/ia64/conf/NOTES +++ b/sys/ia64/conf/NOTES @@ -25,7 +25,7 @@ options LOG2_ID_PAGE_SIZE=27 # 128M # option: LOG2_PAGE_SIZE # Specify the log2 size of the page to be used for virtual memory management. # The page size being equal to 1<<LOG2_PAGE_SIZE. -options LOG2_PAGE_SIZE=15 # 32K +options LOG2_PAGE_SIZE=14 # 16K # option: SKI # Build support for running under the ski simulator. diff --git a/sys/ia64/ia64/clock.c b/sys/ia64/ia64/clock.c index 33dbb2e..96d07c4 100644 --- a/sys/ia64/ia64/clock.c +++ b/sys/ia64/ia64/clock.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Marcel Moolenaar + * Copyright (c) 2005, 2009-2011 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,9 +32,11 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/interrupt.h> #include <sys/priority.h> +#include <sys/proc.h> #include <sys/queue.h> #include <sys/sysctl.h> #include <sys/systm.h> +#include <sys/timeet.h> #include <sys/timetc.h> #include <sys/pcpu.h> @@ -45,26 +47,12 @@ __FBSDID("$FreeBSD$"); #include <machine/md_var.h> #include <machine/smp.h> -SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics"); - -static int adjust_edges = 0; -SYSCTL_INT(_debug_clock, OID_AUTO, adjust_edges, CTLFLAG_RD, - &adjust_edges, 0, "Number of times ITC got more than 12.5% behind"); - -static int adjust_excess = 0; -SYSCTL_INT(_debug_clock, OID_AUTO, adjust_excess, CTLFLAG_RD, - &adjust_excess, 0, "Total number of ignored ITC interrupts"); - -static int adjust_lost = 0; -SYSCTL_INT(_debug_clock, OID_AUTO, adjust_lost, CTLFLAG_RD, - &adjust_lost, 0, "Total number of lost ITC interrupts"); - -static int adjust_ticks = 0; -SYSCTL_INT(_debug_clock, OID_AUTO, adjust_ticks, CTLFLAG_RD, - &adjust_ticks, 0, "Total number of ITC interrupts with adjustment"); +#define CLOCK_ET_OFF 0 +#define CLOCK_ET_PERIODIC 1 +#define CLOCK_ET_ONESHOT 2 +static struct eventtimer ia64_clock_et; static u_int ia64_clock_xiv; -static uint64_t ia64_clock_reload; #ifndef SMP static timecounter_get_t ia64_get_timecount; @@ -87,75 +75,100 @@ ia64_get_timecount(struct timecounter* tc) static u_int ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf) { - uint64_t adj, clk, itc; - int64_t delta; - int count; + struct eventtimer *et; + uint64_t itc, load; + uint32_t mode; PCPU_INC(md.stats.pcs_nclks); + intrcnt[INTRCNT_CLOCK]++; - if (PCPU_GET(cpuid) == 0) { - /* - * Clock processing on the BSP. - */ - intrcnt[INTRCNT_CLOCK]++; + itc = ia64_get_itc(); + PCPU_SET(md.clock, itc); - itc = ia64_get_itc(); + mode = PCPU_GET(md.clock_mode); + if (mode == CLOCK_ET_PERIODIC) { + load = PCPU_GET(md.clock_load); + ia64_set_itm(itc + load); + } else + ia64_set_itv((1 << 16) | xiv); + ia64_srlz_d(); - adj = PCPU_GET(md.clockadj); - clk = PCPU_GET(md.clock); + et = &ia64_clock_et; + if (et->et_active) + et->et_event_cb(et, et->et_arg); + return (0); +} - delta = itc - clk; - count = 0; - while (delta >= ia64_clock_reload) { -#ifdef SMP - ipi_all_but_self(ia64_clock_xiv); -#endif - hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf)); - if (profprocs != 0) - profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf)); - statclock(TRAPF_USERMODE(tf)); - delta -= ia64_clock_reload; - clk += ia64_clock_reload; - if (adj != 0) - adjust_ticks++; - count++; - } - ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj); - ia64_srlz_d(); - if (count > 0) { - adjust_lost += count - 1; - if (delta > (ia64_clock_reload >> 3)) { - if (adj == 0) - adjust_edges++; - adj = ia64_clock_reload >> 4; - } else - adj = 0; - } else { - adj = 0; - adjust_excess++; - } - PCPU_SET(md.clock, clk); - PCPU_SET(md.clockadj, adj); +/* + * Event timer start method. + */ +static int +ia64_clock_start(struct eventtimer *et, struct bintime *first, + struct bintime *period) +{ + u_long itc, load; + register_t is; + + if (period != NULL) { + PCPU_SET(md.clock_mode, CLOCK_ET_PERIODIC); + load = (et->et_frequency * (period->frac >> 32)) >> 32; + if (period->sec > 0) + load += et->et_frequency * period->sec; } else { - /* - * Clock processing on the BSP. - */ - hardclock_cpu(TRAPF_USERMODE(tf)); - if (profprocs != 0) - profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf)); - statclock(TRAPF_USERMODE(tf)); + PCPU_SET(md.clock_mode, CLOCK_ET_ONESHOT); + load = 0; } + PCPU_SET(md.clock_load, load); + + if (first != NULL) { + load = (et->et_frequency * (first->frac >> 32)) >> 32; + if (first->sec > 0) + load += et->et_frequency * first->sec; + } + + is = intr_disable(); + itc = ia64_get_itc(); + ia64_set_itm(itc + load); + ia64_set_itv(ia64_clock_xiv); + ia64_srlz_d(); + intr_restore(is); return (0); } /* - * Start the real-time and statistics clocks. We use ar.itc and cr.itm - * to implement a 1000hz clock. + * Event timer stop method. + */ +static int +ia64_clock_stop(struct eventtimer *et) +{ + + ia64_set_itv((1 << 16) | ia64_clock_xiv); + ia64_srlz_d(); + PCPU_SET(md.clock_mode, CLOCK_ET_OFF); + PCPU_SET(md.clock_load, 0); + return (0); +} + +/* + * We call cpu_initclocks() on the APs as well. It allows us to + * group common initialization in the same function. */ void cpu_initclocks() { + + ia64_clock_stop(NULL); + if (PCPU_GET(cpuid) == 0) + cpu_initclocks_bsp(); + else + cpu_initclocks_ap(); +} + +static void +clock_configure(void *dummy) +{ + struct eventtimer *et; u_long itc_freq; ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, @@ -165,31 +178,23 @@ cpu_initclocks() itc_freq = (u_long)ia64_itc_freq() * 1000000ul; - stathz = hz; - ia64_clock_reload = (itc_freq + hz/2) / hz; + et = &ia64_clock_et; + et->et_name = "ITC"; + et->et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; + et->et_quality = 1000; + et->et_frequency = itc_freq; + et->et_min_period.sec = 0; + et->et_min_period.frac = (0x8000000000000000ul / (u_long)(10*hz)) << 1; + et->et_max_period.sec = 0xffffffff; + et->et_max_period.frac = ((0xfffffffeul << 32) / itc_freq) << 32; + et->et_start = ia64_clock_start; + et->et_stop = ia64_clock_stop; + et->et_priv = NULL; + et_register(et); #ifndef SMP ia64_timecounter.tc_frequency = itc_freq; tc_init(&ia64_timecounter); #endif - - PCPU_SET(md.clockadj, 0); - PCPU_SET(md.clock, ia64_get_itc()); - ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload); - ia64_set_itv(ia64_clock_xiv); - ia64_srlz_d(); -} - -void -cpu_startprofclock(void) -{ - - /* nothing to do */ -} - -void -cpu_stopprofclock(void) -{ - - /* nothing to do */ } +SYSINIT(clkcfg, SI_SUB_CONFIGURE, SI_ORDER_SECOND, clock_configure, NULL); diff --git a/sys/ia64/ia64/db_machdep.c b/sys/ia64/ia64/db_machdep.c index 9d583a1..b689a3c 100644 --- a/sys/ia64/ia64/db_machdep.c +++ b/sys/ia64/ia64/db_machdep.c @@ -578,11 +578,13 @@ db_show_mdpcpu(struct pcpu *pc) { struct pcpu_md *md = &pc->pc_md; - db_printf("MD: vhpt = %#lx\n", md->vhpt); - db_printf("MD: lid = %#lx\n", md->lid); - db_printf("MD: clock = %#lx/%#lx\n", md->clock, md->clockadj); - db_printf("MD: stats = %p\n", &md->stats); - db_printf("MD: pmap = %p\n", md->current_pmap); + db_printf("MD: vhpt = %#lx\n", md->vhpt); + db_printf("MD: lid = %#lx\n", md->lid); + db_printf("MD: clock = %#lx\n", md->clock); + db_printf("MD: clock_mode = %u\n", md->clock_mode); + db_printf("MD: clock_load = %#lx\n", md->clock_load); + db_printf("MD: stats = %p\n", &md->stats); + db_printf("MD: pmap = %p\n", md->current_pmap); } void diff --git a/sys/ia64/ia64/interrupt.c b/sys/ia64/ia64/interrupt.c index adb16ec..27d5e60 100644 --- a/sys/ia64/ia64/interrupt.c +++ b/sys/ia64/ia64/interrupt.c @@ -1,41 +1,33 @@ -/* $FreeBSD$ */ -/* $NetBSD: interrupt.c,v 1.23 1998/02/24 07:38:01 thorpej Exp $ */ - /*- - * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. + * Copyright (c) 2010-2011 Marcel Moolenaar * All rights reserved. * - * Authors: Keith Bostic, Chris G. Demetriou - * - * Permission to use, copy, modify and distribute this software and - * its documentation is hereby granted, 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. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND - * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 + * 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. * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ -/*- - * Additional Copyright (c) 1997 by Matthew Jacob for NASA/Ames Research Center. - * Redistribute and modify at will, leaving only this additional copyright - * notice. + * 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 "opt_ddb.h" -#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> @@ -309,6 +301,7 @@ void ia64_handle_intr(struct trapframe *tf) { struct thread *td; + struct trapframe *stf; u_int xiv; td = curthread; @@ -323,17 +316,20 @@ ia64_handle_intr(struct trapframe *tf) } critical_enter(); + stf = td->td_intr_frame; + td->td_intr_frame = tf; do { + ia64_set_eoi(0); + ia64_srlz_d(); CTR2(KTR_INTR, "INTR: ITC=%u, XIV=%u", (u_int)tf->tf_special.ifa, xiv); (ia64_handler[xiv])(td, xiv, tf); - ia64_set_eoi(0); - ia64_srlz_d(); xiv = ia64_get_ivr(); ia64_srlz_d(); } while (xiv != 15); + td->td_intr_frame = stf; critical_exit(); out: diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index f3105fc..2bfd62e 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -347,6 +347,11 @@ cpu_startup(void *dummy) SYSCTL_ADD_ULONG(&pc->pc_md.sysctl_ctx, SYSCTL_CHILDREN(pc->pc_md.sysctl_tree), OID_AUTO, + "nhardclocks", CTLFLAG_RD, &pcs->pcs_nhardclocks, + "Number of IPI_HARDCLOCK interrupts"); + + SYSCTL_ADD_ULONG(&pc->pc_md.sysctl_ctx, + SYSCTL_CHILDREN(pc->pc_md.sysctl_tree), OID_AUTO, "nhighfps", CTLFLAG_RD, &pcs->pcs_nhighfps, "Number of IPI_HIGH_FP interrupts"); @@ -416,12 +421,10 @@ cpu_idle(int busy) { register_t ie; -#if 0 if (!busy) { critical_enter(); cpu_idleclock(); } -#endif ie = intr_disable(); KASSERT(ie != 0, ("%s called with interrupts disabled\n", __func__)); @@ -436,12 +439,10 @@ cpu_idle(int busy) ia64_enable_intr(); } -#if 0 if (!busy) { cpu_activeclock(); critical_exit(); } -#endif } int @@ -470,12 +471,12 @@ cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx) if (PCPU_GET(fpcurthread) == old) old->td_frame->tf_special.psr |= IA64_PSR_DFH; if (!savectx(oldpcb)) { - atomic_store_rel_ptr(&old->td_lock, mtx); - newpcb = new->td_pcb; oldpcb->pcb_current_pmap = pmap_switch(newpcb->pcb_current_pmap); + atomic_store_rel_ptr(&old->td_lock, mtx); + #if defined(SCHED_ULE) && defined(SMP) while (atomic_load_acq_ptr(&new->td_lock) == &blocked_lock) cpu_spinwait(); diff --git a/sys/ia64/ia64/mp_machdep.c b/sys/ia64/ia64/mp_machdep.c index 15afea0..59b14d0 100644 --- a/sys/ia64/ia64/mp_machdep.c +++ b/sys/ia64/ia64/mp_machdep.c @@ -77,6 +77,7 @@ void ia64_ap_startup(void); struct ia64_ap_state ia64_ap_state; int ia64_ipi_ast; +int ia64_ipi_hardclock; int ia64_ipi_highfp; int ia64_ipi_nmi; int ia64_ipi_preempt; @@ -108,6 +109,16 @@ ia64_ih_ast(struct thread *td, u_int xiv, struct trapframe *tf) } static u_int +ia64_ih_hardclock(struct thread *td, u_int xiv, struct trapframe *tf) +{ + + PCPU_INC(md.stats.pcs_nhardclocks); + CTR1(KTR_SMP, "IPI_HARDCLOCK, cpuid=%d", PCPU_GET(cpuid)); + hardclockintr(); + return (0); +} + +static u_int ia64_ih_highfp(struct thread *td, u_int xiv, struct trapframe *tf) { @@ -233,10 +244,11 @@ ia64_ap_startup(void) CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid)); - /* Mask interval timer interrupts on APs. */ - ia64_set_itv(0x10000); + cpu_initclocks(); + ia64_set_tpr(0); ia64_srlz_d(); + ia64_enable_intr(); sched_throw(NULL); @@ -413,6 +425,8 @@ cpu_mp_unleash(void *dummy) /* Allocate XIVs for IPIs */ ia64_ipi_ast = ia64_xiv_alloc(PI_DULL, IA64_XIV_IPI, ia64_ih_ast); + ia64_ipi_hardclock = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI, + ia64_ih_hardclock); ia64_ipi_highfp = ia64_xiv_alloc(PI_AV, IA64_XIV_IPI, ia64_ih_highfp); ia64_ipi_preempt = ia64_xiv_alloc(PI_SOFT, IA64_XIV_IPI, ia64_ih_preempt); diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c index 625d0af7..b36f813 100644 --- a/sys/ia64/ia64/pmap.c +++ b/sys/ia64/ia64/pmap.c @@ -1424,8 +1424,8 @@ pmap_remove_all(vm_page_t m) pmap_t oldpmap; pv_entry_t pv; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); vm_page_lock_queues(); while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) { struct ia64_lpte *pte; diff --git a/sys/ia64/include/pcpu.h b/sys/ia64/include/pcpu.h index 05e2cc1..5ad61ba 100644 --- a/sys/ia64/include/pcpu.h +++ b/sys/ia64/include/pcpu.h @@ -37,6 +37,7 @@ struct pcpu_stats { u_long pcs_nasts; /* IPI_AST counter. */ u_long pcs_nclks; /* Clock interrupt counter. */ u_long pcs_nextints; /* ExtINT counter. */ + u_long pcs_nhardclocks; /* IPI_HARDCLOCK counter. */ u_long pcs_nhighfps; /* IPI_HIGH_FP counter. */ u_long pcs_nhwints; /* Hardware int. counter. */ u_long pcs_npreempts; /* IPI_PREEMPT counter. */ @@ -51,7 +52,8 @@ struct pcpu_md { vm_offset_t vhpt; /* Address of VHPT */ uint64_t lid; /* local CPU ID */ uint64_t clock; /* Clock counter. */ - uint64_t clockadj; /* Clock adjust. */ + uint64_t clock_load; /* Clock reload value. */ + uint32_t clock_mode; /* Clock ET mode */ uint32_t awake:1; /* CPU is awake? */ struct pcpu_stats stats; /* Interrupt stats. */ #ifdef _KERNEL diff --git a/sys/ia64/include/smp.h b/sys/ia64/include/smp.h index d2aff76..b80d6a0 100644 --- a/sys/ia64/include/smp.h +++ b/sys/ia64/include/smp.h @@ -7,6 +7,7 @@ #ifdef _KERNEL #define IPI_AST ia64_ipi_ast +#define IPI_HARDCLOCK ia64_ipi_hardclock #define IPI_PREEMPT ia64_ipi_preempt #define IPI_RENDEZVOUS ia64_ipi_rndzvs #define IPI_STOP ia64_ipi_stop @@ -37,6 +38,7 @@ struct ia64_ap_state { }; extern int ia64_ipi_ast; +extern int ia64_ipi_hardclock; extern int ia64_ipi_highfp; extern int ia64_ipi_nmi; extern int ia64_ipi_preempt; diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index b41741a..ad79360 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -31,10 +31,12 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_compat.h" #include "opt_core.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/exec.h> #include <sys/fcntl.h> #include <sys/imgact.h> @@ -578,6 +580,15 @@ __elfN(load_file)(struct proc *p, const char *file, u_long *addr, u_long base_addr = 0; int vfslocked, error, i, numsegs; +#ifdef CAPABILITY_MODE + /* + * XXXJA: This check can go away once we are sufficiently confident + * that the checks in namei() are correct. + */ + if (IN_CAPABILITY_MODE(curthread)) + return (ECAPMODE); +#endif + tempdata = malloc(sizeof(*tempdata), M_TEMP, M_WAITOK); nd = &tempdata->nd; attr = &tempdata->attr; diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c index dd8bab5..ecfd408 100644 --- a/sys/kern/kern_clocksource.c +++ b/sys/kern/kern_clocksource.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); cyclic_clock_func_t cyclic_clock_func = NULL; #endif +int cpu_can_deep_sleep = 0; /* C3 state is available. */ int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */ static void setuptimer(void); diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 180d598..7f32d47 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1561,54 +1561,85 @@ fdavail(struct thread *td, int n) int falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags) { - struct proc *p = td->td_proc; struct file *fp; - int error, i; + int error, fd; + + error = falloc_noinstall(td, &fp); + if (error) + return (error); /* no reference held on error */ + + error = finstall(td, fp, &fd, flags); + if (error) { + fdrop(fp, td); /* one reference (fp only) */ + return (error); + } + + if (resultfp != NULL) + *resultfp = fp; /* copy out result */ + else + fdrop(fp, td); /* release local reference */ + + if (resultfd != NULL) + *resultfd = fd; + + return (0); +} + +/* + * Create a new open file structure without allocating a file descriptor. + */ +int +falloc_noinstall(struct thread *td, struct file **resultfp) +{ + struct file *fp; int maxuserfiles = maxfiles - (maxfiles / 20); static struct timeval lastfail; static int curfail; - fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO); + KASSERT(resultfp != NULL, ("%s: resultfp == NULL", __func__)); + if ((openfiles >= maxuserfiles && priv_check(td, PRIV_MAXFILES) != 0) || openfiles >= maxfiles) { if (ppsratecheck(&lastfail, &curfail, 1)) { - printf("kern.maxfiles limit exceeded by uid %i, please see tuning(7).\n", - td->td_ucred->cr_ruid); + printf("kern.maxfiles limit exceeded by uid %i, " + "please see tuning(7).\n", td->td_ucred->cr_ruid); } - uma_zfree(file_zone, fp); return (ENFILE); } atomic_add_int(&openfiles, 1); - - /* - * If the process has file descriptor zero open, add the new file - * descriptor to the list of open files at that point, otherwise - * put it at the front of the list of open files. - */ + fp = uma_zalloc(file_zone, M_WAITOK | M_ZERO); refcount_init(&fp->f_count, 1); - if (resultfp) - fhold(fp); fp->f_cred = crhold(td->td_ucred); fp->f_ops = &badfileops; fp->f_data = NULL; fp->f_vnode = NULL; - FILEDESC_XLOCK(p->p_fd); - if ((error = fdalloc(td, 0, &i))) { - FILEDESC_XUNLOCK(p->p_fd); - fdrop(fp, td); - if (resultfp) - fdrop(fp, td); + *resultfp = fp; + return (0); +} + +/* + * Install a file in a file descriptor table. + */ +int +finstall(struct thread *td, struct file *fp, int *fd, int flags) +{ + struct filedesc *fdp = td->td_proc->p_fd; + int error; + + KASSERT(fd != NULL, ("%s: fd == NULL", __func__)); + KASSERT(fp != NULL, ("%s: fp == NULL", __func__)); + + FILEDESC_XLOCK(fdp); + if ((error = fdalloc(td, 0, fd))) { + FILEDESC_XUNLOCK(fdp); return (error); } - p->p_fd->fd_ofiles[i] = fp; + fhold(fp); + fdp->fd_ofiles[*fd] = fp; if ((flags & O_CLOEXEC) != 0) - p->p_fd->fd_ofileflags[i] |= UF_EXCLOSE; - FILEDESC_XUNLOCK(p->p_fd); - if (resultfp) - *resultfp = fp; - if (resultfd) - *resultfd = i; + fdp->fd_ofileflags[*fd] |= UF_EXCLOSE; + FILEDESC_XUNLOCK(fdp); return (0); } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index c51cc39..f30f89a 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -27,12 +27,14 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_hwpmc_hooks.h" #include "opt_kdtrace.h" #include "opt_ktrace.h" #include "opt_vm.h" #include <sys/param.h> +#include <sys/capability.h> #include <sys/systm.h> #include <sys/eventhandler.h> #include <sys/lock.h> @@ -415,6 +417,18 @@ do_execve(td, args, mac_p) interpret: if (args->fname != NULL) { +#ifdef CAPABILITY_MODE + /* + * While capability mode can't reach this point via direct + * path arguments to execve(), we also don't allow + * interpreters to be used in capability mode (for now). + * Catch indirect lookups and return a permissions error. + */ + if (IN_CAPABILITY_MODE(td)) { + error = ECAPMODE; + goto exec_fail; + } +#endif error = namei(&nd); if (error) goto exec_fail; @@ -631,6 +645,13 @@ interpret: * Don't honor setuid/setgid if the filesystem prohibits it or if * the process is being traced. * + * We disable setuid/setgid/etc in compatibility mode on the basis + * that most setugid applications are not written with that + * environment in mind, and will therefore almost certainly operate + * incorrectly. In principle there's no reason that setugid + * applications might not be useful in capability mode, so we may want + * to reconsider this conservative design choice in the future. + * * XXXMAC: For the time being, use NOSUID to also prohibit * transitions on the file system. */ @@ -646,6 +667,9 @@ interpret: #endif if (credential_changing && +#ifdef CAPABILITY_MODE + ((oldcred->cr_flags & CRED_FLAG_CAPMODE) == 0) && +#endif (imgp->vp->v_mount->mnt_flag & MNT_NOSUID) == 0 && (p->p_flag & P_TRACED) == 0) { /* diff --git a/sys/kern/subr_kdb.c b/sys/kern/subr_kdb.c index c2f6e99..2bc5ab2 100644 --- a/sys/kern/subr_kdb.c +++ b/sys/kern/subr_kdb.c @@ -88,20 +88,6 @@ SYSCTL_PROC(_debug_kdb, OID_AUTO, trap_code, CTLTYPE_INT | CTLFLAG_RW, NULL, 0, kdb_sysctl_trap_code, "I", "set to cause a page fault via code access"); /* - * Flag indicating whether or not to IPI the other CPUs to stop them on - * entering the debugger. Sometimes, this will result in a deadlock as - * stop_cpus() waits for the other cpus to stop, so we allow it to be - * disabled. In order to maximize the chances of success, use a hard - * stop for that. - */ -#ifdef SMP -static int kdb_stop_cpus = 1; -SYSCTL_INT(_debug_kdb, OID_AUTO, stop_cpus, CTLFLAG_RW | CTLFLAG_TUN, - &kdb_stop_cpus, 0, "stop other CPUs when entering the debugger"); -TUNABLE_INT("debug.kdb.stop_cpus", &kdb_stop_cpus); -#endif - -/* * Flag to indicate to debuggers why the debugger was entered. */ const char * volatile kdb_why = KDB_WHY_UNSET; @@ -515,9 +501,6 @@ kdb_trap(int type, int code, struct trapframe *tf) { struct kdb_dbbe *be; register_t intr; -#ifdef SMP - int did_stop_cpus; -#endif int handled; be = kdb_dbbe; @@ -531,8 +514,7 @@ kdb_trap(int type, int code, struct trapframe *tf) intr = intr_disable(); #ifdef SMP - if ((did_stop_cpus = kdb_stop_cpus) != 0) - stop_cpus_hard(PCPU_GET(other_cpus)); + stop_cpus_hard(PCPU_GET(other_cpus)); #endif kdb_active++; @@ -558,8 +540,7 @@ kdb_trap(int type, int code, struct trapframe *tf) kdb_active--; #ifdef SMP - if (did_stop_cpus) - restart_cpus(stopped_cpus); + restart_cpus(stopped_cpus); #endif intr_restore(intr); diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c index c38177b..0929ab9 100644 --- a/sys/kern/subr_smp.c +++ b/sys/kern/subr_smp.c @@ -236,12 +236,10 @@ generic_stop_cpus(cpuset_t map, u_int type) /* spin */ cpu_spinwait(); i++; -#ifdef DIAGNOSTIC - if (i == 100000) { + if (i == 100000000) { printf("timeout stopping cpus\n"); break; } -#endif } stopping_cpu = NOCPU; diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 0113d7b..3527ed1 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -44,7 +44,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include "opt_capabilities.h" +#include "opt_capsicum.h" #include "opt_ktrace.h" #include "opt_kdtrace.h" #include "opt_sched.h" @@ -313,7 +313,7 @@ syscallenter(struct thread *td, struct syscall_args *sa) goto retval; } -#ifdef CAPABILITIES +#ifdef CAPABILITY_MODE /* * In capability mode, we only allow access to system calls * flagged with SYF_CAPENABLED. diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 89dc923..a19e881 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -36,7 +36,7 @@ * */ -#include "opt_capabilities.h" +#include "opt_capsicum.h" #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -59,18 +59,11 @@ __FBSDID("$FreeBSD$"); #include <vm/uma.h> #include <vm/vm.h> -#ifdef CAPABILITIES +#ifdef CAPABILITY_MODE FEATURE(security_capabilities, "Capsicum Capability Mode"); /* - * We don't currently have any MIB entries for sysctls, but we do expose - * security.capabilities so that it's easy to tell if options CAPABILITIES is - * compiled into the kernel. - */ -SYSCTL_NODE(_security, OID_AUTO, capabilities, CTLFLAG_RW, 0, "Capsicum"); - -/* * System call to enter capability mode for the process. */ int @@ -106,7 +99,7 @@ cap_getmode(struct thread *td, struct cap_getmode_args *uap) return (copyout(&i, uap->modep, sizeof(i))); } -#else /* !CAPABILITIES */ +#else /* !CAPABILITY_MODE */ int cap_enter(struct thread *td, struct cap_enter_args *uap) @@ -122,4 +115,4 @@ cap_getmode(struct thread *td, struct cap_getmode_args *uap) return (ENOSYS); } -#endif /* CAPABILITIES */ +#endif /* CAPABILITY_MODE */ diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 8aa3af2..f6475cb 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -470,10 +470,10 @@ ttydev_write(struct cdev *dev, struct uio *uio, int ioflag) if (error) goto done; } - - tp->t_flags |= TF_BUSY_OUT; + + tp->t_flags |= TF_BUSY_OUT; error = ttydisc_write(tp, uio, ioflag); - tp->t_flags &= ~TF_BUSY_OUT; + tp->t_flags &= ~TF_BUSY_OUT; cv_signal(&tp->t_outserwait); } @@ -1054,7 +1054,7 @@ tty_rel_pgrp(struct tty *tp, struct pgrp *pg) if (tp->t_pgrp == pg) tp->t_pgrp = NULL; - + tty_unlock(tp); } @@ -1241,7 +1241,7 @@ tty_signal_sessleader(struct tty *tp, int sig) /* Make signals start output again. */ tp->t_flags &= ~TF_STOPPED; - + if (tp->t_session != NULL && tp->t_session->s_leader != NULL) { p = tp->t_session->s_leader; PROC_LOCK(p); @@ -1305,7 +1305,7 @@ tty_wait(struct tty *tp, struct cv *cv) /* Restart the system call when we may have been revoked. */ if (tp->t_revokecnt != revokecnt) return (ERESTART); - + /* Bail out when the device slipped away. */ if (tty_gone(tp)) return (ENXIO); @@ -1327,7 +1327,7 @@ tty_timedwait(struct tty *tp, struct cv *cv, int hz) /* Restart the system call when we may have been revoked. */ if (tp->t_revokecnt != revokecnt) return (ERESTART); - + /* Bail out when the device slipped away. */ if (tty_gone(tp)) return (ENXIO); @@ -1469,7 +1469,7 @@ tty_generic_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, return (error); /* XXX: CLOCAL? */ - + tp->t_termios.c_cflag = t->c_cflag & ~CIGNORE; tp->t_termios.c_ispeed = t->c_ispeed; tp->t_termios.c_ospeed = t->c_ospeed; @@ -1708,7 +1708,7 @@ tty_ioctl(struct tty *tp, u_long cmd, void *data, int fflag, struct thread *td) if (tty_gone(tp)) return (ENXIO); - + error = ttydevsw_ioctl(tp, cmd, data, td); if (error == ENOIOCTL) error = tty_generic_ioctl(tp, cmd, data, fflag, td); @@ -1786,7 +1786,7 @@ ttyhook_defrint(struct tty *tp, char c, int flags) if (ttyhook_rint_bypass(tp, &c, 1) != 1) return (-1); - + return (0); } @@ -1812,7 +1812,7 @@ ttyhook_register(struct tty **rtp, struct proc *p, int fd, error = EBADF; goto done1; } - + /* * Make sure the vnode is bound to a character device. * Unlocked check for the vnode type is ok there, because we @@ -1910,7 +1910,7 @@ ttyconsdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) /* System console has no TTY associated. */ if (dev_console->si_drv1 == NULL) return (ENXIO); - + return (ttydev_open(dev, oflags, devtype, td)); } diff --git a/sys/kern/tty_inq.c b/sys/kern/tty_inq.c index b0e9b18..0c39a29 100644 --- a/sys/kern/tty_inq.c +++ b/sys/kern/tty_inq.c @@ -142,7 +142,7 @@ void ttyinq_free(struct ttyinq *ti) { struct ttyinq_block *tib; - + ttyinq_flush(ti); ti->ti_quota = 0; @@ -276,7 +276,7 @@ ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote) struct ttyinq_block *tib; unsigned int boff; size_t l; - + while (nbytes > 0) { boff = ti->ti_end % TTYINQ_DATASIZE; @@ -313,7 +313,7 @@ ttyinq_write(struct ttyinq *ti, const void *buf, size_t nbytes, int quote) nbytes -= l; ti->ti_end += l; } - + return (cbuf - (const char *)buf); } @@ -397,7 +397,7 @@ ttyinq_peekchar(struct ttyinq *ti, char *c, int *quote) *c = tib->tib_data[boff]; *quote = GETBIT(tib, boff); - + return (0); } diff --git a/sys/kern/tty_outq.c b/sys/kern/tty_outq.c index d5ed221..5d40abe 100644 --- a/sys/kern/tty_outq.c +++ b/sys/kern/tty_outq.c @@ -119,7 +119,7 @@ void ttyoutq_free(struct ttyoutq *to) { struct ttyoutq_block *tob; - + ttyoutq_flush(to); to->to_quota = 0; diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c index d89c183..a3db59b 100644 --- a/sys/kern/tty_pts.c +++ b/sys/kern/tty_pts.c @@ -295,7 +295,7 @@ ptsdev_ioctl(struct file *fp, u_long cmd, void *data, return (EINVAL); return copyout(p, fgn->buf, i); } - + /* * We need to implement TIOCGPGRP and TIOCGSID here again. When * called on the pseudo-terminal master, it should not check if @@ -563,7 +563,7 @@ ptsdev_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, sb->st_uid = dev->si_uid; sb->st_gid = dev->si_gid; sb->st_mode = dev->si_mode | S_IFCHR; - + return (0); } @@ -823,7 +823,7 @@ posix_openpt(struct thread *td, struct posix_openpt_args *uap) */ if (uap->flags & ~(O_RDWR|O_NOCTTY)) return (EINVAL); - + error = falloc(td, &fp, &fd, 0); if (error) return (error); diff --git a/sys/kern/tty_ttydisc.c b/sys/kern/tty_ttydisc.c index 6afac8d..2a0bb4b 100644 --- a/sys/kern/tty_ttydisc.c +++ b/sys/kern/tty_ttydisc.c @@ -270,13 +270,13 @@ ttydisc_read_raw_interbyte_timer(struct tty *tp, struct uio *uio, int ioflag) MPASS(tp->t_termios.c_cc[VMIN] != 0); MPASS(tp->t_termios.c_cc[VTIME] != 0); - + /* * When using the interbyte timer, the timer should be started * after the first byte has been received. We just call into the * generic read timer code after we've received the first byte. */ - + for (;;) { error = ttyinq_read_uio(&tp->t_inq, tp, uio, uio->uio_resid, 0); @@ -331,7 +331,7 @@ ttydisc_read(struct tty *tp, struct uio *uio, int ioflag) /* Unset the input watermark when we've got enough space. */ tty_hiwat_in_unblock(tp); } - + return (error); } @@ -521,7 +521,7 @@ ttydisc_write(struct tty *tp, struct uio *uio, int ioflag) error = EWOULDBLOCK; goto done; } - + /* * The driver may write back the data * synchronously. Be sure to check the high @@ -567,7 +567,7 @@ ttydisc_optimize(struct tty *tp) } else if (!CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) && (!CMP_FLAG(i, BRKINT) || CMP_FLAG(i, IGNBRK)) && (!CMP_FLAG(i, PARMRK) || - CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) && + CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) && !CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) { tp->t_flags |= TF_BYPASS; } else { @@ -583,7 +583,7 @@ ttydisc_modem(struct tty *tp, int open) if (open) cv_broadcast(&tp->t_dcdwait); - + /* * Ignore modem status lines when CLOCAL is turned on, but don't * enter the zombie state when the TTY isn't opened, because @@ -834,7 +834,7 @@ ttydisc_rint(struct tty *tp, char c, int flags) if (ttyhook_hashook(tp, rint)) return ttyhook_rint(tp, c, flags); - + if (tp->t_flags & TF_BYPASS) goto processed; @@ -1072,7 +1072,7 @@ ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len) size_t ret; tty_lock_assert(tp, MA_OWNED); - + MPASS(tp->t_flags & TF_BYPASS); atomic_add_long(&tty_nin, len); @@ -1122,7 +1122,7 @@ ttydisc_rint_poll(struct tty *tp) l = ttyinq_bytesleft(&tp->t_inq); if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0) return (1); - + return (l); } @@ -1201,7 +1201,7 @@ ttydisc_getc_uio(struct tty *tp, struct uio *uio) tty_unlock(tp); error = uiomove(buf, len, uio); tty_lock(tp); - + if (error != 0) break; } diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c index 00496af..0414f12 100644 --- a/sys/kern/uipc_shm.c +++ b/sys/kern/uipc_shm.c @@ -55,7 +55,10 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" + #include <sys/param.h> +#include <sys/capability.h> #include <sys/fcntl.h> #include <sys/file.h> #include <sys/filedesc.h> @@ -264,7 +267,7 @@ shm_dotruncate(struct shmfd *shmfd, off_t length) /* Toss in memory pages. */ if (nobjsize < object->size) vm_object_page_remove(object, nobjsize, object->size, - FALSE); + 0); /* Toss pages from swap. */ if (object->type == OBJT_SWAP) @@ -486,6 +489,14 @@ shm_open(struct thread *td, struct shm_open_args *uap) mode_t cmode; int fd, error; +#ifdef CAPABILITY_MODE + /* + * shm_open(2) is only allowed for anonymous objects. + */ + if (IN_CAPABILITY_MODE(td) && (uap->path != SHM_ANON)) + return (ECAPMODE); +#endif + if ((uap->flags & O_ACCMODE) != O_RDONLY && (uap->flags & O_ACCMODE) != O_RDWR) return (EINVAL); diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index 19aaee0..c434973 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -35,6 +35,7 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_capsicum.h" #include "opt_inet.h" #include "opt_inet6.h" #include "opt_sctp.h" @@ -43,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/kernel.h> #include <sys/lock.h> #include <sys/mutex.h> @@ -675,6 +677,11 @@ sendit(td, s, mp, flags) struct sockaddr *to; int error; +#ifdef CAPABILITY_MODE + if (IN_CAPABILITY_MODE(td) && (mp->msg_name != NULL)) + return (ECAPMODE); +#endif + if (mp->msg_name != NULL) { error = getsockaddr(&to, mp->msg_name, mp->msg_namelen); if (error) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 741061d..934745b 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1190,8 +1190,8 @@ bufobj_invalbuf(struct bufobj *bo, int flags, int slpflag, int slptimeo) */ if (bo->bo_object != NULL && (flags & (V_ALT | V_NORMAL)) == 0) { VM_OBJECT_LOCK(bo->bo_object); - vm_object_page_remove(bo->bo_object, 0, 0, - (flags & V_SAVE) ? TRUE : FALSE); + vm_object_page_remove(bo->bo_object, 0, 0, (flags & V_SAVE) ? + OBJPR_CLEANONLY : 0); VM_OBJECT_UNLOCK(bo->bo_object); } @@ -3590,9 +3590,6 @@ vn_isdisk(struct vnode *vp, int *errp) * and optional call-by-reference privused argument allowing vaccess() * to indicate to the caller whether privilege was used to satisfy the * request (obsoleted). Returns 0 on success, or an errno on failure. - * - * The ifdef'd CAPABILITIES version is here for reference, but is not - * actually used. */ int vaccess(enum vtype type, mode_t file_mode, uid_t file_uid, gid_t file_gid, diff --git a/sys/mips/atheros/ar71xx_chip.c b/sys/mips/atheros/ar71xx_chip.c index 4a489a1..7f9792f 100644 --- a/sys/mips/atheros/ar71xx_chip.c +++ b/sys/mips/atheros/ar71xx_chip.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -50,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> +#include <machine/cpuregs.h> #include <machine/hwfunc.h> #include <machine/md_var.h> #include <machine/trap.h> @@ -61,6 +57,8 @@ __FBSDID("$FreeBSD$"); #include <mips/atheros/ar71xx_cpudef.h> +#include <mips/sentry5/s5reg.h> + /* XXX these should replace the current definitions in ar71xxreg.h */ /* XXX perhaps an ar71xx_chip.h header file? */ #define AR71XX_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 diff --git a/sys/mips/atheros/ar71xx_machdep.c b/sys/mips/atheros/ar71xx_machdep.c index 60e28a4..1789994 100644 --- a/sys/mips/atheros/ar71xx_machdep.c +++ b/sys/mips/atheros/ar71xx_machdep.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -50,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> +#include <machine/cpuregs.h> #include <machine/hwfunc.h> #include <machine/md_var.h> #include <machine/trap.h> @@ -60,6 +56,8 @@ __FBSDID("$FreeBSD$"); #include <mips/atheros/ar71xx_setup.h> #include <mips/atheros/ar71xx_cpudef.h> +#include <mips/sentry5/s5reg.h> + extern char edata[], end[]; uint32_t ar711_base_mac[ETHER_ADDR_LEN]; diff --git a/sys/mips/atheros/ar71xx_ohci.c b/sys/mips/atheros/ar71xx_ohci.c index acccd85..bee353e 100644 --- a/sys/mips/atheros/ar71xx_ohci.c +++ b/sys/mips/atheros/ar71xx_ohci.c @@ -49,8 +49,6 @@ __FBSDID("$FreeBSD$"); #include <dev/usb/controller/ohci.h> #include <dev/usb/controller/ohcireg.h> -#include <sys/rman.h> - static int ar71xx_ohci_attach(device_t dev); static int ar71xx_ohci_detach(device_t dev); static int ar71xx_ohci_probe(device_t dev); diff --git a/sys/mips/atheros/ar71xx_setup.c b/sys/mips/atheros/ar71xx_setup.c index 0720d52..ce600e4 100644 --- a/sys/mips/atheros/ar71xx_setup.c +++ b/sys/mips/atheros/ar71xx_setup.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -50,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> +#include <machine/cpuregs.h> #include <machine/hwfunc.h> #include <machine/md_var.h> #include <machine/trap.h> @@ -64,6 +60,8 @@ __FBSDID("$FreeBSD$"); #include <mips/atheros/ar724x_chip.h> #include <mips/atheros/ar91xx_chip.h> +#include <mips/sentry5/s5reg.h> + #define AR71XX_SYS_TYPE_LEN 128 static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN]; diff --git a/sys/mips/atheros/ar724x_chip.c b/sys/mips/atheros/ar724x_chip.c index 75c5b38..edd1a9ad 100644 --- a/sys/mips/atheros/ar724x_chip.c +++ b/sys/mips/atheros/ar724x_chip.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -50,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> +#include <machine/cpuregs.h> #include <machine/hwfunc.h> #include <machine/md_var.h> #include <machine/trap.h> @@ -62,6 +58,8 @@ __FBSDID("$FreeBSD$"); #include <mips/atheros/ar71xx_setup.h> #include <mips/atheros/ar724x_chip.h> +#include <mips/sentry5/s5reg.h> + static void ar724x_chip_detect_mem_size(void) { diff --git a/sys/mips/atheros/ar91xx_chip.c b/sys/mips/atheros/ar91xx_chip.c index 9cf60bc..6761e89 100644 --- a/sys/mips/atheros/ar91xx_chip.c +++ b/sys/mips/atheros/ar91xx_chip.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -50,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/clock.h> #include <machine/cpu.h> +#include <machine/cpuregs.h> #include <machine/hwfunc.h> #include <machine/md_var.h> #include <machine/trap.h> @@ -61,6 +57,8 @@ __FBSDID("$FreeBSD$"); #include <mips/atheros/ar71xx_cpudef.h> #include <mips/atheros/ar91xx_chip.h> +#include <mips/sentry5/s5reg.h> + static void ar91xx_chip_detect_mem_size(void) { diff --git a/sys/mips/mips/genassym.c b/sys/mips/mips/genassym.c index fd168bc..2cb046d 100644 --- a/sys/mips/mips/genassym.c +++ b/sys/mips/mips/genassym.c @@ -53,7 +53,6 @@ __FBSDID("$FreeBSD$"); #include <vm/vm_param.h> #include <vm/pmap.h> #include <vm/vm_map.h> -#include <sys/proc.h> #include <machine/cpuregs.h> #include <machine/pcb.h> #include <machine/sigframe.h> diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index f7ea660..1d4d411 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -1711,8 +1711,8 @@ pmap_remove_all(vm_page_t m) pv_entry_t pv; pt_entry_t *pte, tpte; - KASSERT((m->flags & PG_FICTITIOUS) == 0, - ("pmap_remove_all: page %p is fictitious", m)); + KASSERT((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0, + ("pmap_remove_all: page %p is not managed", m)); vm_page_lock_queues(); if (m->md.pv_flags & PV_TABLE_REF) diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 35b8030..c800e71 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -91,10 +91,6 @@ __FBSDID("$FreeBSD$"); #include <sys/kdb.h> #endif -#include <sys/cdefs.h> -#include <sys/syslog.h> - - #ifdef TRAP_DEBUG int trap_debug = 0; SYSCTL_INT(_machdep, OID_AUTO, trap_debug, CTLFLAG_RW, diff --git a/sys/mips/rmi/dev/xlr/rge.c b/sys/mips/rmi/dev/xlr/rge.c index 274a934..1af97c2 100644 --- a/sys/mips/rmi/dev/xlr/rge.c +++ b/sys/mips/rmi/dev/xlr/rge.c @@ -78,8 +78,6 @@ __FBSDID("$FreeBSD$"); #include <machine/cpu.h> #include <machine/mips_opcode.h> #include <machine/asm.h> -#include <mips/rmi/rmi_mips_exts.h> -#include <machine/cpuregs.h> #include <machine/param.h> #include <machine/intr_machdep.h> diff --git a/sys/mips/rmi/fmn.c b/sys/mips/rmi/fmn.c index f7686cb..9a6c486 100644 --- a/sys/mips/rmi/fmn.c +++ b/sys/mips/rmi/fmn.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #include <sys/ktr.h> #include <sys/kernel.h> #include <sys/kthread.h> -#include <sys/proc.h> #include <sys/resourcevar.h> #include <sys/sched.h> #include <sys/unistd.h> diff --git a/sys/mips/rmi/iodi.c b/sys/mips/rmi/iodi.c index 3c09984..8952fcd 100644 --- a/sys/mips/rmi/iodi.c +++ b/sys/mips/rmi/iodi.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <sys/rman.h> #include <sys/types.h> #include <sys/malloc.h> -#include <sys/bus.h> #include <sys/interrupt.h> #include <sys/module.h> diff --git a/sys/mips/sentry5/s5_machdep.c b/sys/mips/sentry5/s5_machdep.c index 4491b93..134f05b 100644 --- a/sys/mips/sentry5/s5_machdep.c +++ b/sys/mips/sentry5/s5_machdep.c @@ -27,11 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> -#include <machine/cpuregs.h> - -#include <mips/sentry5/s5reg.h> - #include "opt_ddb.h" #include <sys/param.h> @@ -75,6 +70,8 @@ __FBSDID("$FreeBSD$"); #include <machine/trap.h> #include <machine/vmparam.h> +#include <mips/sentry5/s5reg.h> + #ifdef CFE #include <dev/cfe/cfe_api.h> #endif diff --git a/sys/mips/sibyte/sb_machdep.c b/sys/mips/sibyte/sb_machdep.c index ac30451..b6d395f 100644 --- a/sys/mips/sibyte/sb_machdep.c +++ b/sys/mips/sibyte/sb_machdep.c @@ -27,8 +27,6 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <sys/param.h> - #include "opt_ddb.h" #include "opt_kdb.h" diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 8775e19..2777e22 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -242,6 +242,7 @@ SUBDIR= ${_3dfx} \ pcn \ ${_pf} \ ${_pflog} \ + ${_pfsync} \ plip \ ${_pmc} \ portalfs \ @@ -384,6 +385,9 @@ _netgraph= netgraph ${MK_INET6_SUPPORT} != "no")) || defined(ALL_MODULES) _pf= pf _pflog= pflog +.if ${MK_INET_SUPPORT} != "no" +_pfsync= pfsync +.endif .endif .if ${MACHINE_CPUARCH} == "i386" diff --git a/sys/modules/cxgbe/if_cxgbe/Makefile b/sys/modules/cxgbe/if_cxgbe/Makefile index ac1d22c..e4e69e6 100644 --- a/sys/modules/cxgbe/if_cxgbe/Makefile +++ b/sys/modules/cxgbe/if_cxgbe/Makefile @@ -10,6 +10,7 @@ SRCS = t4_main.c t4_sge.c t4_l2t.c SRCS+= t4_hw.c SRCS+= device_if.h bus_if.h pci_if.h SRCS+= opt_inet.h +SRCS+= opt_ofed.h CFLAGS+= -I${CXGBE} diff --git a/sys/modules/ipdivert/Makefile b/sys/modules/ipdivert/Makefile index 203b4bf..886802a 100644 --- a/sys/modules/ipdivert/Makefile +++ b/sys/modules/ipdivert/Makefile @@ -3,6 +3,11 @@ .PATH: ${.CURDIR}/../../netinet KMOD= ipdivert -SRCS= ip_divert.c +SRCS= ip_divert.c opt_inet6.h + +.if !defined(KERNBUILDDIR) +opt_inet6.h: + echo "#define INET6 1" > ${.TARGET} +.endif .include <bsd.kmod.mk> diff --git a/sys/modules/nfscl/Makefile b/sys/modules/nfscl/Makefile index 46fa327..a9b2003 100644 --- a/sys/modules/nfscl/Makefile +++ b/sys/modules/nfscl/Makefile @@ -14,13 +14,14 @@ SRCS= vnode_if.h \ nfs_clsubs.c \ nfs_clvfsops.c \ nfs_clvnops.c \ + opt_bootp.h \ opt_inet.h \ opt_inet6.h \ - opt_bootp.h \ - opt_nfsroot.h \ + opt_kdtrace.h \ + opt_kgssapi.h \ opt_nfs.h \ - opt_ufs.h \ - opt_kgssapi.h + opt_nfsroot.h \ + opt_ufs.h .if !defined(KERNBUILDDIR) NFS_INET?= 1 # 0/1 - requires INET to be configured in kernel diff --git a/sys/modules/nfscommon/Makefile b/sys/modules/nfscommon/Makefile index a3d75a7..2a6b8f7 100644 --- a/sys/modules/nfscommon/Makefile +++ b/sys/modules/nfscommon/Makefile @@ -7,9 +7,10 @@ SRCS= vnode_if.h \ nfs_commonkrpc.c \ nfs_commonport.c \ nfs_commonsubs.c \ - opt_kgssapi.h \ - opt_ufs.h \ opt_inet6.h \ - opt_nfs.h + opt_kdtrace.h \ + opt_kgssapi.h \ + opt_nfs.h \ + opt_ufs.h .include <bsd.kmod.mk> diff --git a/sys/modules/pf/Makefile b/sys/modules/pf/Makefile index 78aa564..d4b01da 100644 --- a/sys/modules/pf/Makefile +++ b/sys/modules/pf/Makefile @@ -6,16 +6,18 @@ .PATH: ${.CURDIR}/../../contrib/pf/netinet KMOD= pf -SRCS = pf.c pf_if.c pf_subr.c pf_osfp.c pf_ioctl.c pf_norm.c pf_table.c \ +SRCS= pf.c pf_if.c pf_lb.c pf_osfp.c pf_ioctl.c pf_norm.c pf_table.c \ pf_ruleset.c \ in4_cksum.c \ - opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h + opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h opt_global.h -CFLAGS+= -I${.CURDIR}/../../contrib/pf +CFLAGS+= -I${.CURDIR}/../../contrib/pf .if !defined(KERNBUILDDIR) +.if ${MK_INET_SUPPORT} != "no" opt_inet.h: echo "#define INET 1" > ${.TARGET} +.endif .if ${MK_INET6_SUPPORT} != "no" opt_inet6.h: @@ -26,9 +28,17 @@ opt_bpf.h: echo "#define DEV_BPF 1" > ${.TARGET} # pflog can be loaded as a module, have the additional checks turned on +# pfsync can be loaded as a module, have the additional checks turned on opt_pf.h: echo "#define DEV_PF 1" > ${.TARGET} echo "#define DEV_PFLOG 1" >> ${.TARGET} + echo "#define DEV_PFSYNC 1" >> ${.TARGET} + echo "#define DEV_PFLOW 1" >> ${.TARGET} + +.if defined(VIMAGE) +opt_global.h: + echo "#define VIMAGE 1" >> ${.TARGET} +.endif .endif .include <bsd.kmod.mk> diff --git a/sys/modules/pflog/Makefile b/sys/modules/pflog/Makefile index 2dbbd6c..0e8339e 100644 --- a/sys/modules/pflog/Makefile +++ b/sys/modules/pflog/Makefile @@ -5,14 +5,19 @@ .PATH: ${.CURDIR}/../../contrib/pf/net KMOD= pflog -SRCS = if_pflog.c \ +SRCS= if_pflog.c \ opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h -CFLAGS+= -I${.CURDIR}/../../contrib/pf +CFLAGS+= -I${.CURDIR}/../../contrib/pf +SRCS+= bus_if.h device_if.h -.if !defined(KERNBUILDDIR) +.if defined(KERNBUILDDIR) +MKDEP+= -include ${KERNBUILDDIR}/opt_global.h +.else +.if ${MK_INET_SUPPORT} != "no" opt_inet.h: echo "#define INET 1" > ${.TARGET} +.endif .if ${MK_INET6_SUPPORT} != "no" opt_inet6.h: @@ -21,6 +26,13 @@ opt_inet6.h: opt_bpf.h: echo "#define DEV_BPF 1" > ${.TARGET} + +.if defined(VIMAGE) +opt_global.h: + echo "#define VIMAGE 1" >> ${.TARGET} +CFLAGS+= -include opt_global.h +MKDEP+= -include opt_global.h +.endif .endif .include <bsd.kmod.mk> diff --git a/sys/modules/pfsync/Makefile b/sys/modules/pfsync/Makefile new file mode 100644 index 0000000..ad08b45 --- /dev/null +++ b/sys/modules/pfsync/Makefile @@ -0,0 +1,38 @@ +# $FreeBSD$ + +.include <bsd.own.mk> + +.PATH: ${.CURDIR}/../../contrib/pf/net + +KMOD= pfsync +SRCS= if_pfsync.c \ + opt_pf.h opt_inet.h opt_inet6.h opt_bpf.h + +CFLAGS+= -I${.CURDIR}/../../contrib/pf +SRCS+= bus_if.h device_if.h + +.if defined(KERNBUILDDIR) +MKDEP+= -include ${KERNBUILDDIR}/opt_global.h +.else +.if ${MK_INET_SUPPORT} != "no" +opt_inet.h: + echo "#define INET 1" > ${.TARGET} +.endif + +.if ${MK_INET6_SUPPORT} != "no" +opt_inet6.h: + echo "#define INET6 1" > ${.TARGET} +.endif + +opt_bpf.h: + echo "#define DEV_BPF 1" > ${.TARGET} + +.if defined(VIMAGE) +opt_global.h: + echo "#define VIMAGE 1" >> ${.TARGET} +CFLAGS+= -include opt_global.h +MKDEP+= -include opt_global.h +.endif +.endif + +.include <bsd.kmod.mk> diff --git a/sys/modules/usb/template/Makefile b/sys/modules/usb/template/Makefile index 362da9d..e67303e 100644 --- a/sys/modules/usb/template/Makefile +++ b/sys/modules/usb/template/Makefile @@ -31,6 +31,13 @@ S= ${.CURDIR}/../../.. KMOD= usb_template SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h vnode_if.h usbdevs.h \ - usb_template.c usb_template_cdce.c usb_template_msc.c usb_template_mtp.c + usb_template.c \ + usb_template_audio.c \ + usb_template_cdce.c \ + usb_template_kbd.c \ + usb_template_modem.c \ + usb_template_mouse.c \ + usb_template_msc.c \ + usb_template_mtp.c .include <bsd.kmod.mk> diff --git a/sys/net/if.c b/sys/net/if.c index b7c2ad1..a5a3a8e 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -2467,6 +2467,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) error = ifconf(SIOCGIFCONF, (void *)&ifc); CURVNET_RESTORE(); + if (error == 0) + ifc32->ifc_len = ifc.ifc_len; return (error); } #endif diff --git a/sys/net/route.c b/sys/net/route.c index a6f910e..9c7dfac 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -116,12 +116,6 @@ VNET_DEFINE(int, rttrash); /* routes not in table but not freed */ static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ #define V_rtzone VNET(rtzone) -#if 0 -/* default fib for tunnels to use */ -u_int tunnel_fib = 0; -SYSCTL_INT(_net, OID_AUTO, tunnelfib, CTLFLAG_RD, &tunnel_fib, 0, ""); -#endif - /* * handler for net.my_fibnum */ diff --git a/sys/net/route.h b/sys/net/route.h index 5031533..0bc72d7 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -108,8 +108,6 @@ struct rt_metrics { #endif extern u_int rt_numfibs; /* number fo usable routing tables */ -extern u_int tunnel_fib; /* tunnels use these */ -extern u_int fwd_fib; /* packets being forwarded use these routes */ /* * XXX kernel function pointer `rt_output' is visible to applications. */ diff --git a/sys/net80211/ieee80211_dfs.c b/sys/net80211/ieee80211_dfs.c index e15445d..19e552d 100644 --- a/sys/net80211/ieee80211_dfs.c +++ b/sys/net80211/ieee80211_dfs.c @@ -320,6 +320,8 @@ ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *ch * on the NOL to expire. */ /*XXX*/ + if_printf(ic->ic_ifp, "%s: No free channels; waiting for entry " + "on NOL to expire\n", __func__); } } else { /* diff --git a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c index a13ef4d..d3f8fd3 100644 --- a/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c +++ b/sys/netgraph/bluetooth/drivers/ubt/ng_ubt.c @@ -382,14 +382,14 @@ static const struct usb_config ubt_config[UBT_N_TRANSFER] = * where VENDOR_ID and PRODUCT_ID are hex numbers. */ -static const struct usb_device_id ubt_ignore_devs[] = +static const STRUCT_USB_HOST_ID ubt_ignore_devs[] = { /* AVM USB Bluetooth-Adapter BlueFritz! v1.0 */ { USB_VPI(USB_VENDOR_AVM, 0x2200, 0) }, }; /* List of supported bluetooth devices */ -static const struct usb_device_id ubt_devs[] = +static const STRUCT_USB_HOST_ID ubt_devs[] = { /* Generic Bluetooth class devices */ { USB_IFACE_CLASS(UDCLASS_WIRELESS), diff --git a/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c b/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c index 3d8a05e..da00e05 100644 --- a/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c +++ b/sys/netgraph/bluetooth/drivers/ubtbcmfw/ubtbcmfw.c @@ -180,7 +180,7 @@ MODULE_DEPEND(ubtbcmfw, usb, 1, 1, 1); static int ubtbcmfw_probe(device_t dev) { - const struct usb_device_id devs[] = { + static const STRUCT_USB_HOST_ID devs[] = { /* Broadcom BCM2033 devices only */ { USB_VPI(USB_VENDOR_BROADCOM, USB_PRODUCT_BROADCOM_BCM2033, 0) }, }; diff --git a/sys/netgraph/ng_ether.c b/sys/netgraph/ng_ether.c index 5abc5aa..b51d048 100644 --- a/sys/netgraph/ng_ether.c +++ b/sys/netgraph/ng_ether.c @@ -718,7 +718,6 @@ ng_ether_shutdown(node_p node) (void)ifpromisc(priv->ifp, 0); priv->promisc = 0; } - priv->autoSrcAddr = 1; /* reset auto-src-addr flag */ NG_NODE_REVIVE(node); /* Signal ng_rmnode we are persisant */ return (0); diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 6c60390..22f35df 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -256,6 +256,8 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m) #endif } + m_addr_changed(m); + error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL); if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) && diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 527ce56..29a5d42 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #error "IPDIVERT requires INET." #endif #endif +#include "opt_inet6.h" #include <sys/param.h> #include <sys/kernel.h> @@ -62,6 +63,10 @@ __FBSDID("$FreeBSD$"); #include <netinet/in_var.h> #include <netinet/ip.h> #include <netinet/ip_var.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif #ifdef SCTP #include <netinet/sctp_crc32.h> #endif @@ -312,10 +317,10 @@ static int div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, struct mbuf *control) { + struct ip *const ip = mtod(m, struct ip *); struct m_tag *mtag; struct ipfw_rule_ref *dt; int error = 0; - struct mbuf *options; /* * An mbuf may hasn't come from userland, but we pretend @@ -367,71 +372,103 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, /* Reinject packet into the system as incoming or outgoing */ if (!sin || sin->sin_addr.s_addr == 0) { - struct ip *const ip = mtod(m, struct ip *); + struct mbuf *options = NULL; struct inpcb *inp; dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT; inp = sotoinpcb(so); INP_RLOCK(inp); - /* - * Don't allow both user specified and setsockopt options, - * and don't allow packet length sizes that will crash - */ - if (((ip->ip_hl != (sizeof (*ip) >> 2)) && inp->inp_options) || - ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { - error = EINVAL; - INP_RUNLOCK(inp); - m_freem(m); - } else { + switch (ip->ip_v) { + case IPVERSION: + /* + * Don't allow both user specified and setsockopt + * options, and don't allow packet length sizes that + * will crash. + */ + if ((((ip->ip_hl << 2) != sizeof(struct ip)) && + inp->inp_options != NULL) || + ((u_short)ntohs(ip->ip_len) > m->m_pkthdr.len)) { + error = EINVAL; + INP_RUNLOCK(inp); + goto cantsend; + } + /* Convert fields to host order for ip_output() */ ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + { + struct ip6_hdr *const ip6 = mtod(m, struct ip6_hdr *); + + /* Don't allow packet length sizes that will crash */ + if (((u_short)ntohs(ip6->ip6_plen) > m->m_pkthdr.len)) { + error = EINVAL; + INP_RUNLOCK(inp); + goto cantsend; + } - /* Send packet to output processing */ - KMOD_IPSTAT_INC(ips_rawout); /* XXX */ + ip6->ip6_plen = ntohs(ip6->ip6_plen); + } +#endif + default: + error = EINVAL; + INP_RUNLOCK(inp); + goto cantsend; + } + + /* Send packet to output processing */ + KMOD_IPSTAT_INC(ips_rawout); /* XXX */ #ifdef MAC - mac_inpcb_create_mbuf(inp, m); + mac_inpcb_create_mbuf(inp, m); #endif - /* - * Get ready to inject the packet into ip_output(). - * Just in case socket options were specified on the - * divert socket, we duplicate them. This is done - * to avoid having to hold the PCB locks over the call - * to ip_output(), as doing this results in a number of - * lock ordering complexities. - * - * Note that we set the multicast options argument for - * ip_output() to NULL since it should be invariant that - * they are not present. - */ - KASSERT(inp->inp_moptions == NULL, - ("multicast options set on a divert socket")); - options = NULL; - /* - * XXXCSJP: It is unclear to me whether or not it makes - * sense for divert sockets to have options. However, - * for now we will duplicate them with the INP locks - * held so we can use them in ip_output() without - * requring a reference to the pcb. - */ - if (inp->inp_options != NULL) { - options = m_dup(inp->inp_options, M_DONTWAIT); - if (options == NULL) - error = ENOBUFS; - } - INP_RUNLOCK(inp); - if (error == ENOBUFS) { - m_freem(m); - return (error); + /* + * Get ready to inject the packet into ip_output(). + * Just in case socket options were specified on the + * divert socket, we duplicate them. This is done + * to avoid having to hold the PCB locks over the call + * to ip_output(), as doing this results in a number of + * lock ordering complexities. + * + * Note that we set the multicast options argument for + * ip_output() to NULL since it should be invariant that + * they are not present. + */ + KASSERT(inp->inp_moptions == NULL, + ("multicast options set on a divert socket")); + /* + * XXXCSJP: It is unclear to me whether or not it makes + * sense for divert sockets to have options. However, + * for now we will duplicate them with the INP locks + * held so we can use them in ip_output() without + * requring a reference to the pcb. + */ + if (inp->inp_options != NULL) { + options = m_dup(inp->inp_options, M_NOWAIT); + if (options == NULL) { + INP_RUNLOCK(inp); + error = ENOBUFS; + goto cantsend; } + } + INP_RUNLOCK(inp); + + switch (ip->ip_v) { + case IPVERSION: error = ip_output(m, options, NULL, - ((so->so_options & SO_DONTROUTE) ? - IP_ROUTETOIF : 0) | IP_ALLOWBROADCAST | - IP_RAWOUTPUT, NULL, NULL); - if (options != NULL) - m_freem(options); + ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0) + | IP_ALLOWBROADCAST | IP_RAWOUTPUT, NULL, NULL); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + break; +#endif } + if (options != NULL) + m_freem(options); } else { dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN; if (m->m_pkthdr.rcvif == NULL) { @@ -456,14 +493,26 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin, mac_socket_create_mbuf(so, m); #endif /* Send packet to input processing via netisr */ - netisr_queue_src(NETISR_IP, (uintptr_t)so, m); + switch (ip->ip_v) { + case IPVERSION: + netisr_queue_src(NETISR_IP, (uintptr_t)so, m); + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + netisr_queue_src(NETISR_IPV6, (uintptr_t)so, m); + break; +#endif + default: + error = EINVAL; + goto cantsend; + } } - return error; + return (error); cantsend: m_freem(m); - return error; + return (error); } static int diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 06e107c..ff3a67f 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -57,6 +57,12 @@ #define IP_FW_TABLEARG 65535 /* XXX should use 0 */ /* + * Number of entries in the call stack of the call/return commands. + * Call stack currently is an uint16_t array with rule numbers. + */ +#define IPFW_CALLSTACK_SIZE 16 + +/* * The kernel representation of ipfw rules is made of a list of * 'instructions' (for all practical purposes equivalent to BPF * instructions), which specify which fields of the packet @@ -195,6 +201,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_SOCKARG, /* socket argument */ + O_CALLRETURN, /* arg1=called rule number */ + O_LAST_OPCODE /* not an opcode! */ }; diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 3542aa1..ec8a2f0 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -675,6 +675,8 @@ icmp_reflect(struct mbuf *m) goto done; /* Ip_output() will check for broadcast */ } + m_addr_changed(m); + t = ip->ip_dst; ip->ip_dst = ip->ip_src; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index e993279..cd30093 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -286,6 +286,7 @@ enum { }; #define MTAG_IPFW 1148380143 /* IPFW-tagged cookie */ #define MTAG_IPFW_RULE 1262273568 /* rule reference */ +#define MTAG_IPFW_CALL 1308397630 /* call stack */ struct ip_fw_args; typedef int (*ip_fw_chk_ptr_t)(struct ip_fw_args *args); diff --git a/sys/netinet/ipfw/ip_dn_io.c b/sys/netinet/ipfw/ip_dn_io.c index bcb12ae..6766416 100644 --- a/sys/netinet/ipfw/ip_dn_io.c +++ b/sys/netinet/ipfw/ip_dn_io.c @@ -668,7 +668,6 @@ dummynet_send(struct mbuf *m) break; case DIR_OUT | PROTO_IPV6: - SET_HOST_IPLEN(mtod(m, struct ip *)); ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL); break; #endif diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c index 9e5c737..4e25f9a 100644 --- a/sys/netinet/ipfw/ip_fw2.c +++ b/sys/netinet/ipfw/ip_fw2.c @@ -1670,10 +1670,6 @@ do { \ break; } at->qid = altq->qid; - if (is_ipv4) - at->af = AF_INET; - else - at->af = AF_LINK; at->hdr = ip; break; } @@ -2099,6 +2095,123 @@ do { \ continue; break; /* not reached */ + case O_CALLRETURN: { + /* + * Implementation of `subroutine' call/return, + * in the stack carried in an mbuf tag. This + * is different from `skipto' in that any call + * address is possible (`skipto' must prevent + * backward jumps to avoid endless loops). + * We have `return' action when F_NOT flag is + * present. The `m_tag_id' field is used as + * stack pointer. + */ + struct m_tag *mtag; + uint16_t jmpto, *stack; + +#define IS_CALL ((cmd->len & F_NOT) == 0) +#define IS_RETURN ((cmd->len & F_NOT) != 0) + /* + * Hand-rolled version of m_tag_locate() with + * wildcard `type'. + * If not already tagged, allocate new tag. + */ + mtag = m_tag_first(m); + while (mtag != NULL) { + if (mtag->m_tag_cookie == + MTAG_IPFW_CALL) + break; + mtag = m_tag_next(m, mtag); + } + if (mtag == NULL && IS_CALL) { + mtag = m_tag_alloc(MTAG_IPFW_CALL, 0, + IPFW_CALLSTACK_SIZE * + sizeof(uint16_t), M_NOWAIT); + if (mtag != NULL) + m_tag_prepend(m, mtag); + } + + /* + * On error both `call' and `return' just + * continue with next rule. + */ + if (IS_RETURN && (mtag == NULL || + mtag->m_tag_id == 0)) { + l = 0; /* exit inner loop */ + break; + } + if (IS_CALL && (mtag == NULL || + mtag->m_tag_id >= IPFW_CALLSTACK_SIZE)) { + printf("ipfw: call stack error, " + "go to next rule\n"); + l = 0; /* exit inner loop */ + break; + } + + f->pcnt++; /* update stats */ + f->bcnt += pktlen; + f->timestamp = time_uptime; + stack = (uint16_t *)(mtag + 1); + + /* + * The `call' action may use cached f_pos + * (in f->next_rule), whose version is written + * in f->next_rule. + * The `return' action, however, doesn't have + * fixed jump address in cmd->arg1 and can't use + * cache. + */ + if (IS_CALL) { + stack[mtag->m_tag_id] = f->rulenum; + mtag->m_tag_id++; + if (cmd->arg1 != IP_FW_TABLEARG && + (uintptr_t)f->x_next == chain->id) { + f_pos = (uintptr_t)f->next_rule; + } else { + jmpto = (cmd->arg1 == + IP_FW_TABLEARG) ? tablearg: + cmd->arg1; + f_pos = ipfw_find_rule(chain, + jmpto, 0); + /* update the cache */ + if (cmd->arg1 != + IP_FW_TABLEARG) { + f->next_rule = + (void *)(uintptr_t) + f_pos; + f->x_next = + (void *)(uintptr_t) + chain->id; + } + } + } else { /* `return' action */ + mtag->m_tag_id--; + jmpto = stack[mtag->m_tag_id] + 1; + f_pos = ipfw_find_rule(chain, jmpto, 0); + } + + /* + * Skip disabled rules, and re-enter + * the inner loop with the correct + * f_pos, f, l and cmd. + * Also clear cmdlen and skip_or + */ + for (; f_pos < chain->n_rules - 1 && + (V_set_disable & + (1 << chain->map[f_pos]->set)); f_pos++) + ; + /* Re-enter the inner loop at the dest rule. */ + f = chain->map[f_pos]; + l = f->cmd_len; + cmd = f->cmd; + cmdlen = 0; + skip_or = 0; + continue; + break; /* NOTREACHED */ + } +#undef IS_CALL +#undef IS_RETURN + case O_REJECT: /* * Drop the packet and send a reject notice diff --git a/sys/netinet/ipfw/ip_fw_log.c b/sys/netinet/ipfw/ip_fw_log.c index 3560e13..2b55a38 100644 --- a/sys/netinet/ipfw/ip_fw_log.c +++ b/sys/netinet/ipfw/ip_fw_log.c @@ -304,6 +304,13 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, case O_REASS: action = "Reass"; break; + case O_CALLRETURN: + if (cmd->len & F_NOT) + action = "Return"; + else + snprintf(SNPARGS(action2, 0), "Call %d", + cmd->arg1); + break; default: action = "UNKNOWN"; break; diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c index 248e4dd..736615b 100644 --- a/sys/netinet/ipfw/ip_fw_pfil.c +++ b/sys/netinet/ipfw/ip_fw_pfil.c @@ -58,6 +58,10 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_fw.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif #include <netinet/ipfw/ip_fw_private.h> #include <netgraph/ng_ipfw.h> @@ -127,8 +131,9 @@ again: args.rule = *((struct ipfw_rule_ref *)(tag+1)); m_tag_delete(*m0, tag); if (args.rule.info & IPFW_ONEPASS) { - SET_HOST_IPLEN(mtod(*m0, struct ip *)); - return 0; + if (mtod(*m0, struct ip *)->ip_v == 4) + SET_HOST_IPLEN(mtod(*m0, struct ip *)); + return (0); } } @@ -264,7 +269,7 @@ ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule, * If not tee, consume packet and send it to divert socket. */ struct mbuf *clone; - struct ip *ip; + struct ip *ip = mtod(*m0, struct ip *); struct m_tag *tag; /* Cloning needed for tee? */ @@ -288,8 +293,9 @@ ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule, * Note that we now have the 'reass' ipfw option so if we care * we can do it before a 'tee'. */ - ip = mtod(clone, struct ip *); - if (!tee && ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) { + if (!tee) switch (ip->ip_v) { + case IPVERSION: + if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK)) { int hlen; struct mbuf *reass; @@ -311,7 +317,26 @@ ipfw_divert(struct mbuf **m0, int incoming, struct ipfw_rule_ref *rule, else ip->ip_sum = in_cksum(reass, hlen); clone = reass; + } + break; +#ifdef INET6 + case IPV6_VERSION >> 4: + { + struct ip6_hdr *const ip6 = mtod(clone, struct ip6_hdr *); + + if (ip6->ip6_nxt == IPPROTO_FRAGMENT) { + int nxt, off; + + off = sizeof(struct ip6_hdr); + nxt = frag6_input(&clone, &off, 0); + if (nxt == IPPROTO_DONE) + return (0); + } + break; + } +#endif } + /* attach a tag to the packet with the reinject info */ tag = m_tag_alloc(MTAG_IPFW_RULE, 0, sizeof(struct ipfw_rule_ref), M_NOWAIT); diff --git a/sys/netinet/ipfw/ip_fw_sockopt.c b/sys/netinet/ipfw/ip_fw_sockopt.c index 2347456..1432858 100644 --- a/sys/netinet/ipfw/ip_fw_sockopt.c +++ b/sys/netinet/ipfw/ip_fw_sockopt.c @@ -752,6 +752,7 @@ check_ipfw_struct(struct ip_fw *rule, int size) #endif case O_SKIPTO: case O_REASS: + case O_CALLRETURN: check_size: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c index 9b30793..4e0837f 100644 --- a/sys/netinet/libalias/alias_db.c +++ b/sys/netinet/libalias/alias_db.c @@ -552,10 +552,6 @@ static void IncrementalCleanup(struct libalias *); static void DeleteLink(struct alias_link *); static struct alias_link * -AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr, - u_short, u_short, int, int); - -static struct alias_link * ReLink(struct alias_link *, struct in_addr, struct in_addr, struct in_addr, u_short, u_short, int, int); @@ -572,9 +568,6 @@ static struct alias_link * #define ALIAS_PORT_MASK_EVEN 0x07ffe #define GET_NEW_PORT_MAX_ATTEMPTS 20 -#define GET_ALIAS_PORT -1 -#define GET_ALIAS_ID GET_ALIAS_PORT - #define FIND_EVEN_ALIAS_BASE 1 /* GetNewPort() allocates port numbers. Note that if a port number @@ -937,17 +930,12 @@ DeleteLink(struct alias_link *lnk) } -static struct alias_link * -AddLink(struct libalias *la, struct in_addr src_addr, - struct in_addr dst_addr, - struct in_addr alias_addr, - u_short src_port, - u_short dst_port, - int alias_port_param, /* if less than zero, alias */ - int link_type) -{ /* port will be automatically *//* chosen. - * If greater than */ - u_int start_point; /* zero, equal to alias port */ +struct alias_link * +AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, + struct in_addr alias_addr, u_short src_port, u_short dst_port, + int alias_port_param, int link_type) +{ + u_int start_point; struct alias_link *lnk; LIBALIAS_LOCK_ASSERT(la); diff --git a/sys/netinet/libalias/alias_ftp.c b/sys/netinet/libalias/alias_ftp.c index ef0e52c..8e7d05b 100644 --- a/sys/netinet/libalias/alias_ftp.c +++ b/sys/netinet/libalias/alias_ftp.c @@ -100,38 +100,68 @@ __FBSDID("$FreeBSD$"); #define FTP_CONTROL_PORT_NUMBER 21 static void -AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *, - int maxpacketsize); +AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *, + int maxpacketsize); +static void +AliasHandleFtpIn(struct libalias *, struct ip *, struct alias_link *); -static int -fingerprint(struct libalias *la, struct alias_data *ah) +static int +fingerprint_out(struct libalias *la, struct alias_data *ah) { - if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL || - ah->maxpktsize == 0) + if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL || + ah->maxpktsize == 0) return (-1); - if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER - || ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER) + if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER || + ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER) return (0); return (-1); } -static int -protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah) +static int +fingerprint_in(struct libalias *la, struct alias_data *ah) +{ + + if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL) + return (-1); + if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER || + ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER) + return (0); + return (-1); +} + +static int +protohandler_out(struct libalias *la, struct ip *pip, struct alias_data *ah) { - + AliasHandleFtpOut(la, pip, ah->lnk, ah->maxpktsize); return (0); } + +static int +protohandler_in(struct libalias *la, struct ip *pip, struct alias_data *ah) +{ + + AliasHandleFtpIn(la, pip, ah->lnk); + return (0); +} + struct proto_handler handlers[] = { - { - .pri = 80, - .dir = OUT, - .proto = TCP, - .fingerprint = &fingerprint, - .protohandler = &protohandler - }, + { + .pri = 80, + .dir = OUT, + .proto = TCP, + .fingerprint = &fingerprint_out, + .protohandler = &protohandler_out + }, + { + .pri = 80, + .dir = IN, + .proto = TCP, + .fingerprint = &fingerprint_in, + .protohandler = &protohandler_in + }, { EOH } }; @@ -256,6 +286,57 @@ AliasHandleFtpOut( } } +static void +AliasHandleFtpIn(struct libalias *la, + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *lnk) /* The link to go through (aliased port) */ +{ + int hlen, tlen, dlen, pflags; + char *sptr; + struct tcphdr *tc; + + /* Calculate data length of TCP packet */ + tc = (struct tcphdr *)ip_next(pip); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + /* Place string pointer and beginning of data */ + sptr = (char *)pip; + sptr += hlen; + + /* + * Check that data length is not too long and previous message was + * properly terminated with CRLF. + */ + pflags = GetProtocolFlags(lnk); + if (dlen <= MAX_MESSAGE_SIZE && (pflags & WAIT_CRLF) == 0 && + ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER && + (ParseFtpPortCommand(la, sptr, dlen) != 0 || + ParseFtpEprtCommand(la, sptr, dlen) != 0)) { + /* + * Alias active mode client requesting data from server + * behind NAT. We need to alias server->client connection + * to external address client is connecting to. + */ + AddLink(la, GetOriginalAddress(lnk), la->true_addr, + GetAliasAddress(lnk), htons(FTP_CONTROL_PORT_NUMBER - 1), + htons(la->true_port), GET_ALIAS_PORT, IPPROTO_TCP); + } + /* Track the msgs which are CRLF term'd for PORT/PASV FW breach */ + if (dlen) { + sptr = (char *)pip; /* start over at beginning */ + tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may + * have grown. + */ + if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n') + pflags &= ~WAIT_CRLF; + else + pflags |= WAIT_CRLF; + SetProtocolFlags(lnk, pflags); + } +} + static int ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen) { @@ -576,9 +657,10 @@ NewFtpMessage(struct libalias *la, struct ip *pip, if (la->true_port < IPPORT_RESERVED) return; -/* Establish link to address and port found in FTP control message. */ - ftp_lnk = FindUdpTcpOut(la, la->true_addr, GetDestAddress(lnk), - htons(la->true_port), 0, IPPROTO_TCP, 1); + /* Establish link to address and port found in FTP control message. */ + ftp_lnk = AddLink(la, la->true_addr, GetDestAddress(lnk), + GetAliasAddress(lnk), htons(la->true_port), 0, GET_ALIAS_PORT, + IPPROTO_TCP); if (ftp_lnk != NULL) { int slen, hlen, tlen, dlen; diff --git a/sys/netinet/libalias/alias_local.h b/sys/netinet/libalias/alias_local.h index e201394..c291a37 100644 --- a/sys/netinet/libalias/alias_local.h +++ b/sys/netinet/libalias/alias_local.h @@ -67,6 +67,9 @@ #define LINK_TABLE_OUT_SIZE 4001 #define LINK_TABLE_IN_SIZE 4001 +#define GET_ALIAS_PORT -1 +#define GET_ALIAS_ID GET_ALIAS_PORT + struct proxy_entry; struct libalias { @@ -249,6 +252,10 @@ DifferentialChecksum(u_short * _cksum, void * _new, void * _old, int _n); /* Internal data access */ struct alias_link * +AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, + struct in_addr alias_addr, u_short src_port, u_short dst_port, + int alias_param, int link_type); +struct alias_link * FindIcmpIn(struct libalias *la, struct in_addr _dst_addr, struct in_addr _alias_addr, u_short _id_alias, int _create); struct alias_link * diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3 index 31702e8..fb63a4c 100644 --- a/sys/netinet/libalias/libalias.3 +++ b/sys/netinet/libalias/libalias.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 1, 2006 +.Dd June 22, 2011 .Dt LIBALIAS 3 .Os .Sh NAME @@ -257,6 +257,16 @@ Normal packet aliasing is not performed. See .Fn LibAliasProxyRule below for details. +.It Dv PKT_ALIAS_SKIP_GLOBAL +This option is used by +.Pa ipfw_nat +only. Specifying it as a flag to +.Fn LibAliasSetMode +has no effect. See section +.Sx NETWORK ADDRESS TRANSLATION +in +.Xr ipfw 8 +for more details. .El .Ed .Pp @@ -814,6 +824,17 @@ argument is the pointer to a header fragment used as a template, and is the pointer to the packet to be de-aliased. .Ed .Sh MISCELLANEOUS FUNCTIONS +.Ft struct alias_link * +.Fn AddLink "struct libalias *" "struct in_addr src_addr" "struct in_addr dst_addr" \ +"struct in_addr alias_addr" "u_short src_port" "u_short dst_port" \ +"int alias_param" "int link_type" +.Bd -ragged -offset indent +This function adds new state to instance hash table. +Zero can be specified instead of dst_address and/or dst port. +This makes link partially specified dynamic. +However due to hashing method such links can be resolved on inbound (ext -> int) only. +.Ed +.Pp .Ft void .Fn LibAliasSetTarget "struct libalias *" "struct in_addr addr" .Bd -ragged -offset indent diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index e754b88..1a8e537 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -100,6 +100,9 @@ void (*ip_divert_ptr)(struct mbuf *, int); int (*ng_ipfw_input_p)(struct mbuf **, int, struct ip_fw_args *, int); +/* Hook for telling pf that the destination address changed */ +void (*m_addr_chg_pf_p)(struct mbuf *m); + #ifdef INET /* * Hooks for multicast routing. They all default to NULL, so leave them not diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index a798682..d3b186d 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -251,12 +251,13 @@ struct sctp_snd_all_completes { /* for the endpoint */ /* The lower byte is an enumeration of PR-SCTP policies */ +#define SCTP_PR_SCTP_NONE 0x0000/* Reliable transfer */ #define SCTP_PR_SCTP_TTL 0x0001/* Time based PR-SCTP */ #define SCTP_PR_SCTP_BUF 0x0002/* Buffer based PR-SCTP */ #define SCTP_PR_SCTP_RTX 0x0003/* Number of retransmissions based PR-SCTP */ #define PR_SCTP_POLICY(x) ((x) & 0x0f) -#define PR_SCTP_ENABLED(x) (PR_SCTP_POLICY(x) != 0) +#define PR_SCTP_ENABLED(x) (PR_SCTP_POLICY(x) != SCTP_PR_SCTP_NONE) #define PR_SCTP_TTL_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_TTL) #define PR_SCTP_BUF_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_BUF) #define PR_SCTP_RTX_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_RTX) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 952b38a..6a2da07 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1177,6 +1177,8 @@ icmp6_notify_error(struct mbuf **mp, int off, int icmp6len, int code) ip6cp.ip6c_src = &icmp6src; ip6cp.ip6c_nxt = nxt; + m_addr_changed(m); + if (icmp6type == ICMP6_PACKET_TOO_BIG) { notifymtu = ntohl(icmp6->icmp6_mtu); ip6cp.ip6c_cmdarg = (void *)¬ifymtu; @@ -2299,6 +2301,8 @@ icmp6_reflect(struct mbuf *m, size_t off) m->m_flags &= ~(M_BCAST|M_MCAST); + m_addr_changed(m); + ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); if (outif) icmp6_ifoutstat_inc(outif, type, code); diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index e786836..961fc77 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -262,6 +262,8 @@ in6_gif_output(struct ifnet *ifp, #endif } + m_addr_changed(m); + #ifdef IPV6_MINMTU /* * force fragmentation to minimum MTU, to avoid path MTU discovery. diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c index a004aef..8b53bf4 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -473,6 +473,8 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, key_sa_recordxfer(sav, m); /* record data transfer */ + m_addr_changed(m); + #ifdef DEV_ENC encif->if_ipackets++; encif->if_ibytes += m->m_pkthdr.len; diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index d10523d..77897ed 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -191,6 +191,8 @@ ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) } key_sa_recordxfer(sav, m); /* record data transfer */ + m_addr_changed(m); + /* * We're done with IPsec processing, transmit the packet using the * appropriate network protocol (IP or IPv6). SPD lookup will be diff --git a/sys/netipsec/xform_ipip.c b/sys/netipsec/xform_ipip.c index 8639c82..0eb8b6a 100644 --- a/sys/netipsec/xform_ipip.c +++ b/sys/netipsec/xform_ipip.c @@ -392,6 +392,8 @@ _ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp) panic("%s: bogus ip version %u", __func__, v>>4); } + m_addr_changed(m); + if (netisr_queue(isr, m)) { /* (0) on success. */ V_ipipstat.ipips_qfull++; DPRINTF(("%s: packet dropped because of full queue\n", diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c index ca90089..bd4a826 100644 --- a/sys/nfs/bootp_subr.c +++ b/sys/nfs/bootp_subr.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include "opt_bootp.h" +#include "opt_nfs.h" #include <sys/param.h> #include <sys/systm.h> @@ -1699,6 +1700,9 @@ bootpc_init(void) } rootdevnames[0] = "nfs:"; +#ifdef NFSCLIENT + rootdevnames[1] = "oldnfs:"; +#endif mountopts(&nd->root_args, NULL); for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) diff --git a/sys/powerpc/aim/copyinout.c b/sys/powerpc/aim/copyinout.c index 3592691..69ba431 100644 --- a/sys/powerpc/aim/copyinout.c +++ b/sys/powerpc/aim/copyinout.c @@ -142,7 +142,7 @@ copyout(const void *kaddr, void *udaddr, size_t len) char *up, *p; size_t l; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; if (setfault(env)) { @@ -183,7 +183,7 @@ copyin(const void *udaddr, void *kaddr, size_t len) char *kp, *p; size_t l; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; if (setfault(env)) { @@ -225,7 +225,7 @@ copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) size_t l; int rv, c; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; if (setfault(env)) { @@ -267,7 +267,7 @@ subyte(void *addr, int byte) faultbuf env; char *p; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (char *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -293,7 +293,7 @@ suword32(void *addr, int word) faultbuf env; int *p; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (int *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -319,7 +319,7 @@ suword(void *addr, long word) faultbuf env; long *p; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -359,7 +359,7 @@ fubyte(const void *addr) u_char *p; int val; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (u_char *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -385,7 +385,7 @@ fuword32(const void *addr) faultbuf env; int32_t *p, val; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (int32_t *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -411,7 +411,7 @@ fuword(const void *addr) faultbuf env; long *p, val; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -444,7 +444,7 @@ casuword32(volatile uint32_t *addr, uint32_t old, uint32_t new) faultbuf env; uint32_t *p, val; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (uint32_t *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); @@ -489,7 +489,7 @@ casuword(volatile u_long *addr, u_long old, u_long new) faultbuf env; u_long *p, val; - td = PCPU_GET(curthread); + td = curthread; pm = &td->td_proc->p_vmspace->vm_pmap; p = (u_long *)(USER_ADDR + ((uintptr_t)addr & ~SEGMENT_MASK)); diff --git a/sys/powerpc/aim/locore32.S b/sys/powerpc/aim/locore32.S index 35ea99b..d0a3778 100644 --- a/sys/powerpc/aim/locore32.S +++ b/sys/powerpc/aim/locore32.S @@ -181,8 +181,7 @@ setfault: mflr 0 mfcr 12 mfsprg 4,0 - lwz 4,PC_CURTHREAD(4) - lwz 4,TD_PCB(4) + lwz 4,TD_PCB(2) /* curthread = r2 */ stw 3,PCB_ONFAULT(4) stw 0,0(3) stw 1,4(3) diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S index c200b4c..5af5e3a 100644 --- a/sys/powerpc/aim/locore64.S +++ b/sys/powerpc/aim/locore64.S @@ -203,8 +203,7 @@ ASENTRY(setfault) mflr 0 mfcr 12 mfsprg 4,0 - ld 4,PC_CURTHREAD(4) - ld 4,TD_PCB(4) + ld 4,TD_PCB(13) /* curthread = r13 */ std 3,PCB_ONFAULT(4) std 0,0(3) std 1,8(3) diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 3ccae91..c368c68 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -303,7 +303,7 @@ powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel, */ pc = __pcpu; pcpu_init(pc, 0, sizeof(struct pcpu)); - pc->pc_curthread = &thread0; + curthread_reg = pc->pc_curthread = &thread0; pc->pc_cpuid = 0; __asm __volatile("mtsprg 0, %0" :: "r"(pc)); @@ -745,7 +745,7 @@ kcopy(const void *src, void *dst, size_t len) faultbuf env, *oldfault; int rv; - td = PCPU_GET(curthread); + td = curthread; oldfault = td->td_pcb->pcb_onfault; if ((rv = setfault(env)) != 0) { td->td_pcb->pcb_onfault = oldfault; diff --git a/sys/powerpc/aim/mmu_oea64.c b/sys/powerpc/aim/mmu_oea64.c index 291d89b..8f4028f 100644 --- a/sys/powerpc/aim/mmu_oea64.c +++ b/sys/powerpc/aim/mmu_oea64.c @@ -1715,7 +1715,7 @@ moea64_kextract(mmu_t mmu, vm_offset_t va) pvo = moea64_pvo_find_va(kernel_pmap, va); KASSERT(pvo != NULL, ("moea64_kextract: no addr found for %#" PRIxPTR, va)); - pa = (pvo->pvo_pte.lpte.pte_lo & LPTE_RPGN) + (va - PVO_VADDR(pvo)); + pa = (pvo->pvo_pte.lpte.pte_lo & LPTE_RPGN) | (va - PVO_VADDR(pvo)); PMAP_UNLOCK(kernel_pmap); return (pa); } diff --git a/sys/powerpc/aim/mp_cpudep.c b/sys/powerpc/aim/mp_cpudep.c index d617fde..68fe517 100644 --- a/sys/powerpc/aim/mp_cpudep.c +++ b/sys/powerpc/aim/mp_cpudep.c @@ -88,7 +88,7 @@ cpudep_ap_bootstrap(void) msr = PSL_KERNSET & ~PSL_EE; mtmsr(msr); - pcpup->pc_curthread = pcpup->pc_idlethread; + curthread_reg = pcpup->pc_curthread = pcpup->pc_idlethread; pcpup->pc_curpcb = pcpup->pc_curthread->td_pcb; sp = pcpup->pc_curpcb->pcb_sp; diff --git a/sys/powerpc/aim/swtch32.S b/sys/powerpc/aim/swtch32.S index cd141aa..a44b861 100644 --- a/sys/powerpc/aim/swtch32.S +++ b/sys/powerpc/aim/swtch32.S @@ -69,7 +69,7 @@ * void cpu_throw(struct thread *old, struct thread *new) */ ENTRY(cpu_throw) - mr %r15, %r4 + mr %r2, %r4 b cpu_switchin /* @@ -89,10 +89,9 @@ ENTRY(cpu_switch) mflr %r16 /* Save the link register */ stw %r16,PCB_LR(%r6) stw %r1,PCB_SP(%r6) /* Save the stack pointer */ - stw %r2,PCB_TOC(%r6) /* Save the TOC pointer */ mr %r14,%r3 /* Copy the old thread ptr... */ - mr %r15,%r4 /* and the new thread ptr in scratch */ + mr %r2,%r4 /* and the new thread ptr in curthread */ mr %r16,%r5 /* and the new lock */ mr %r17,%r6 /* and the PCB */ @@ -122,24 +121,24 @@ cpu_switchin: lis %r6,blocked_lock@ha addi %r6,%r6,blocked_lock@l blocked_loop: - lwz %r7,TD_LOCK(%r15) + lwz %r7,TD_LOCK(%r2) cmpw %r6,%r7 beq blocked_loop #endif mfsprg %r7,0 /* Get the pcpu pointer */ - stw %r15,PC_CURTHREAD(%r7) /* Store new current thread */ - lwz %r17,TD_PCB(%r15) /* Store new current PCB */ + stw %r2,PC_CURTHREAD(%r7) /* Store new current thread */ + lwz %r17,TD_PCB(%r2) /* Store new current PCB */ stw %r17,PC_CURPCB(%r7) - mr %r3,%r15 /* Get new thread ptr */ + mr %r3,%r2 /* Get new thread ptr */ bl pmap_activate /* Activate the new address space */ lwz %r6, PCB_FLAGS(%r17) /* Restore FPU context if needed */ andi. %r6, %r6, PCB_FPU beq .L3 - mr %r3,%r15 /* Pass curthread to enable_fpu */ + mr %r3,%r2 /* Pass curthread to enable_fpu */ bl enable_fpu .L3: @@ -147,7 +146,7 @@ blocked_loop: /* Restore Altivec context if needed */ andi. %r6, %r6, PCB_VEC beq .L4 - mr %r3,%r15 /* Pass curthread to enable_vec */ + mr %r3,%r2 /* Pass curthread to enable_vec */ bl enable_vec /* thread to restore is in r3 */ @@ -163,7 +162,6 @@ blocked_loop: mtsr USER_SR,%r5 isync lwz %r1,PCB_SP(%r3) /* Load the stack pointer */ - lwz %r2,PCB_TOC(%r3) /* Load the TOC pointer */ /* * Perform a dummy stwcx. to clear any reservations we may have * inherited from the previous thread. It doesn't matter if the diff --git a/sys/powerpc/aim/swtch64.S b/sys/powerpc/aim/swtch64.S index 1877e8d..c5cdcbc 100644 --- a/sys/powerpc/aim/swtch64.S +++ b/sys/powerpc/aim/swtch64.S @@ -69,7 +69,7 @@ * void cpu_throw(struct thread *old, struct thread *new) */ ENTRY(cpu_throw) - mr %r15, %r4 + mr %r13, %r4 b cpu_switchin /* @@ -83,7 +83,6 @@ ENTRY(cpu_switch) ld %r6,TD_PCB(%r3) /* Get the old thread's PCB ptr */ std %r12,PCB_CONTEXT(%r6) /* Save the non-volatile GP regs. These can now be used for scratch */ - std %r13,PCB_CONTEXT+1*8(%r6) std %r14,PCB_CONTEXT+2*8(%r6) std %r15,PCB_CONTEXT+3*8(%r6) std %r16,PCB_CONTEXT+4*8(%r6) @@ -111,7 +110,7 @@ ENTRY(cpu_switch) std %r2,PCB_TOC(%r6) /* Save the TOC pointer */ mr %r14,%r3 /* Copy the old thread ptr... */ - mr %r15,%r4 /* and the new thread ptr in scratch */ + mr %r13,%r4 /* and the new thread ptr in curthread*/ mr %r16,%r5 /* and the new lock */ mr %r17,%r6 /* and the PCB */ @@ -148,19 +147,19 @@ cpu_switchin: lis %r6,blocked_lock@ha addi %r6,%r6,blocked_lock@l blocked_loop: - ld %r7,TD_LOCK(%r15) + ld %r7,TD_LOCK(%r13) cmpd %r6,%r7 beq blocked_loop #endif mfsprg %r7,0 /* Get the pcpu pointer */ - std %r15,PC_CURTHREAD(%r7) /* Store new current thread */ - ld %r17,TD_PCB(%r15) /* Store new current PCB */ + std %r13,PC_CURTHREAD(%r7) /* Store new current thread */ + ld %r17,TD_PCB(%r13) /* Store new current PCB */ std %r17,PC_CURPCB(%r7) stdu %r1,-48(%r1) - mr %r3,%r15 /* Get new thread ptr */ + mr %r3,%r13 /* Get new thread ptr */ bl pmap_activate /* Activate the new address space */ nop @@ -168,7 +167,7 @@ blocked_loop: /* Restore FPU context if needed */ andi. %r6, %r6, PCB_FPU beq .L3 - mr %r3,%r15 /* Pass curthread to enable_fpu */ + mr %r3,%r13 /* Pass curthread to enable_fpu */ bl enable_fpu nop @@ -177,7 +176,7 @@ blocked_loop: /* Restore Altivec context if needed */ andi. %r6, %r6, PCB_VEC beq .L4 - mr %r3,%r15 /* Pass curthread to enable_vec */ + mr %r3,%r13 /* Pass curthread to enable_vec */ bl enable_vec nop @@ -186,7 +185,6 @@ blocked_loop: addi %r1,%r1,48 mr %r3,%r17 /* Recover PCB ptr */ ld %r12,PCB_CONTEXT(%r3) /* Load the non-volatile GP regs. */ - ld %r13,PCB_CONTEXT+1*8(%r3) ld %r14,PCB_CONTEXT+2*8(%r3) ld %r15,PCB_CONTEXT+3*8(%r3) ld %r16,PCB_CONTEXT+4*8(%r3) diff --git a/sys/powerpc/aim/trap.c b/sys/powerpc/aim/trap.c index 60c0f3b..51dee0e 100644 --- a/sys/powerpc/aim/trap.c +++ b/sys/powerpc/aim/trap.c @@ -149,7 +149,7 @@ trap(struct trapframe *frame) PCPU_INC(cnt.v_trap); - td = PCPU_GET(curthread); + td = curthread; p = td->td_proc; type = ucode = frame->exc; @@ -452,7 +452,7 @@ syscall(struct trapframe *frame) struct syscall_args sa; int error; - td = PCPU_GET(curthread); + td = curthread; td->td_frame = frame; #ifdef __powerpc64__ @@ -600,7 +600,7 @@ badaddr_read(void *addr, size_t size, int *rptr) /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = 0; diff --git a/sys/powerpc/aim/trap_subr32.S b/sys/powerpc/aim/trap_subr32.S index 7c154a8..172150e 100644 --- a/sys/powerpc/aim/trap_subr32.S +++ b/sys/powerpc/aim/trap_subr32.S @@ -155,9 +155,15 @@ stw %r28,FRAME_AIM_DAR+8(1); \ stw %r29,FRAME_AIM_DSISR+8(1); /* save dsisr/srr0/srr1 */ \ stw %r30,FRAME_SRR0+8(1); \ - stw %r31,FRAME_SRR1+8(1) + stw %r31,FRAME_SRR1+8(1); \ + lwz %r2,PC_CURTHREAD(%r2) /* set curthread pointer */ #define FRAME_LEAVE(savearea) \ +/* Disable exceptions: */ \ + mfmsr %r2; \ + andi. %r2,%r2,~PSL_EE@l; \ + mtmsr %r2; \ + isync; \ /* Now restore regs: */ \ lwz %r2,FRAME_SRR0+8(%r1); \ lwz %r3,FRAME_SRR1+8(%r1); \ @@ -209,7 +215,7 @@ mtsprg3 %r3; \ /* Disable translation, machine check and recoverability: */ \ mfmsr %r2; \ - andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_EE|PSL_ME|PSL_RI)@l; \ + andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ mtmsr %r2; \ isync; \ /* Decide whether we return to user mode: */ \ @@ -762,8 +768,8 @@ CNAME(trapexit): bf 17,1f /* branch if PSL_PR is false */ GET_CPUINFO(%r3) /* get per-CPU pointer */ - lwz %r4, PC_CURTHREAD(%r3) /* deref to get curthread */ - lwz %r4, TD_FLAGS(%r4) /* get thread flags value */ + lwz %r4, TD_FLAGS(%r2) /* get thread flags value + * (r2 is curthread) */ lis %r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@h ori %r5,%r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@l and. %r4,%r4,%r5 diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S index 5d4148a..111d516 100644 --- a/sys/powerpc/aim/trap_subr64.S +++ b/sys/powerpc/aim/trap_subr64.S @@ -179,9 +179,15 @@ restore_kernsrs: std %r28,FRAME_AIM_DAR+48(1); \ std %r29,FRAME_AIM_DSISR+48(1); /* save dsisr/srr0/srr1 */ \ std %r30,FRAME_SRR0+48(1); \ - std %r31,FRAME_SRR1+48(1) + std %r31,FRAME_SRR1+48(1); \ + ld %r13,PC_CURTHREAD(%r2) /* set kernel curthread */ #define FRAME_LEAVE(savearea) \ +/* Disable exceptions: */ \ + mfmsr %r2; \ + andi. %r2,%r2,~PSL_EE@l; \ + mtmsr %r2; \ + isync; \ /* Now restore regs: */ \ ld %r2,FRAME_SRR0+48(%r1); \ ld %r3,FRAME_SRR1+48(%r1); \ @@ -233,7 +239,7 @@ restore_kernsrs: mtsprg3 %r3; \ /* Disable translation, machine check and recoverability: */ \ mfmsr %r2; \ - andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_EE|PSL_ME|PSL_RI)@l; \ + andi. %r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l; \ mtmsr %r2; \ isync; \ /* Decide whether we return to user mode: */ \ @@ -524,8 +530,7 @@ CNAME(trapexit): bf 17,1f /* branch if PSL_PR is false */ GET_CPUINFO(%r3) /* get per-CPU pointer */ - ld %r4, PC_CURTHREAD(%r3) /* deref to get curthread */ - lwz %r4, TD_FLAGS(%r4) /* get thread flags value */ + lwz %r4, TD_FLAGS(%r13) /* get thread flags value */ lis %r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@h ori %r5,%r5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@l and. %r4,%r4,%r5 diff --git a/sys/powerpc/booke/copyinout.c b/sys/powerpc/booke/copyinout.c index 91195dd..011b8bd 100644 --- a/sys/powerpc/booke/copyinout.c +++ b/sys/powerpc/booke/copyinout.c @@ -87,7 +87,7 @@ copyout(const void *kaddr, void *udaddr, size_t len) if (!is_uaddr(udaddr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -109,7 +109,7 @@ copyin(const void *udaddr, void *kaddr, size_t len) if (!is_uaddr(udaddr) || is_uaddr(kaddr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -135,7 +135,7 @@ copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done) if (!is_uaddr(udaddr) || is_uaddr(kaddr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -175,7 +175,7 @@ subyte(void *addr, int byte) if (!is_uaddr(addr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -197,7 +197,7 @@ suword(void *addr, long word) if (!is_uaddr(addr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -228,7 +228,7 @@ fubyte(const void *addr) if (!is_uaddr(addr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -251,7 +251,7 @@ fuword(const void *addr) if (!is_uaddr(addr)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; @@ -288,7 +288,7 @@ casuword(volatile u_long *addr, u_long old, u_long new) if (!((vm_offset_t)addr <= VM_MAXUSER_ADDRESS)) return (EFAULT); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = NULL; diff --git a/sys/powerpc/booke/interrupt.c b/sys/powerpc/booke/interrupt.c index c0bdee1..e268537 100644 --- a/sys/powerpc/booke/interrupt.c +++ b/sys/powerpc/booke/interrupt.c @@ -118,7 +118,7 @@ powerpc_decr_interrupt(struct trapframe *framep) struct thread *td; struct trapframe *oldframe; - td = PCPU_GET(curthread); + td = curthread; critical_enter(); atomic_add_int(&td->td_intr_nesting_level, 1); oldframe = td->td_intr_frame; diff --git a/sys/powerpc/booke/trap.c b/sys/powerpc/booke/trap.c index a2d0d70..fc506bd 100644 --- a/sys/powerpc/booke/trap.c +++ b/sys/powerpc/booke/trap.c @@ -145,7 +145,7 @@ trap(struct trapframe *frame) PCPU_INC(cnt.v_trap); - td = PCPU_GET(curthread); + td = curthread; p = td->td_proc; type = frame->exc; @@ -382,7 +382,7 @@ syscall(struct trapframe *frame) struct syscall_args sa; int error; - td = PCPU_GET(curthread); + td = curthread; td->td_frame = frame; error = syscallenter(td, &sa); @@ -480,7 +480,7 @@ badaddr_read(void *addr, size_t size, int *rptr) /* Get rid of any stale machine checks that have been waiting. */ __asm __volatile ("sync; isync"); - td = PCPU_GET(curthread); + td = curthread; if (setfault(env)) { td->td_pcb->pcb_onfault = 0; diff --git a/sys/powerpc/include/pcpu.h b/sys/powerpc/include/pcpu.h index 949bbf3..631abd2 100644 --- a/sys/powerpc/include/pcpu.h +++ b/sys/powerpc/include/pcpu.h @@ -135,6 +135,14 @@ struct pmap; #ifdef _KERNEL #define pcpup ((struct pcpu *) powerpc_get_pcpup()) +#ifdef __powerpc64__ +register struct thread *curthread_reg __asm("%r13"); +#else +register struct thread *curthread_reg __asm("%r2"); +#endif +#ifdef AIM /* Book-E not yet adapted */ +#define curthread curthread_reg +#endif #define PCPU_GET(member) (pcpup->pc_ ## member) diff --git a/sys/powerpc/ofw/ofwcall32.S b/sys/powerpc/ofw/ofwcall32.S index 06cc105..d2ba70f 100644 --- a/sys/powerpc/ofw/ofwcall32.S +++ b/sys/powerpc/ofw/ofwcall32.S @@ -87,10 +87,11 @@ ASENTRY(ofwcall) * later. */ mr %r5,%r1 - lis %r1,(ofwstk+OFWSTKSZ-16)@ha - addi %r1,%r1,(ofwstk+OFWSTKSZ-16)@l - stw %r5,8(%r1) /* Save real stack pointer */ - stw %r6,12(%r1) /* Save old MSR */ + lis %r1,(ofwstk+OFWSTKSZ-32)@ha + addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l + stw %r5,20(%r1) /* Save real stack pointer */ + stw %r2,24(%r1) /* Save curthread */ + stw %r6,28(%r1) /* Save old MSR */ li %r5,0 stw %r5,4(%r1) stw %r5,0(%r1) @@ -100,8 +101,9 @@ ASENTRY(ofwcall) bctrl /* Reload stack pointer and MSR from the OFW stack */ - lwz %r6,12(%r1) - lwz %r1,8(%r1) + lwz %r6,28(%r1) + lwz %r2,24(%r1) + lwz %r1,20(%r1) /* Now set the real MSR */ mtmsr %r6 diff --git a/sys/powerpc/ofw/rtas.c b/sys/powerpc/ofw/rtas.c index 59692c9..66ce12f 100644 --- a/sys/powerpc/ofw/rtas.c +++ b/sys/powerpc/ofw/rtas.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include <sys/lock.h> #include <sys/mutex.h> #include <sys/systm.h> +#include <sys/proc.h> #include <vm/vm.h> #include <vm/vm_page.h> @@ -39,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <machine/bus.h> #include <machine/md_var.h> +#include <machine/pcb.h> #include <machine/pmap.h> #include <machine/rtas.h> #include <machine/stdarg.h> @@ -60,6 +62,8 @@ int rtascall(vm_offset_t callbuffer, uintptr_t rtas_privdat); extern uintptr_t rtas_entry; extern register_t rtasmsr; +int setfault(faultbuf); /* defined in locore.S */ + /* * After the VM is up, allocate RTAS memory and instantiate it */ @@ -188,6 +192,7 @@ int rtas_call_method(cell_t token, int nargs, int nreturns, ...) { vm_offset_t argsptr; + faultbuf env; va_list ap; struct { cell_t token; @@ -213,7 +218,19 @@ rtas_call_method(cell_t token, int nargs, int nreturns, ...) args.args_n_results[n] = va_arg(ap, cell_t); argsptr = rtas_real_map(&args, sizeof(args)); - result = rtascall(argsptr, rtas_private_data); + + /* Get rid of any stale machine checks that have been waiting. */ + __asm __volatile ("sync; isync"); + if (!setfault(env)) { + __asm __volatile ("sync"); + result = rtascall(argsptr, rtas_private_data); + __asm __volatile ("sync; isync"); + } else { + result = RTAS_HW_ERROR; + } + curthread->td_pcb->pcb_onfault = 0; + __asm __volatile ("sync"); + rtas_real_unmap(argsptr, &args, sizeof(args)); mtx_unlock(&rtas_mtx); diff --git a/sys/powerpc/powermac/fcu.c b/sys/powerpc/powermac/fcu.c index 7ac9b1b..eb43ff2 100644 --- a/sys/powerpc/powermac/fcu.c +++ b/sys/powerpc/powermac/fcu.c @@ -510,7 +510,7 @@ fcu_fill_fan_prop(device_t dev) sc->sc_fans[j].fan.set = (int (*)(struct pmac_fan *, int))(fcu_fan_set_rpm); } else { - sc->sc_fans[j].fan.min_rpm = 40; /* Percent */ + sc->sc_fans[j].fan.min_rpm = 30; /* Percent */ sc->sc_fans[j].fan.max_rpm = 100; sc->sc_fans[j].fan.read = NULL; sc->sc_fans[j].fan.set = diff --git a/sys/powerpc/powerpc/db_trace.c b/sys/powerpc/powerpc/db_trace.c index f783781..20de0ec 100644 --- a/sys/powerpc/powerpc/db_trace.c +++ b/sys/powerpc/powerpc/db_trace.c @@ -200,7 +200,7 @@ db_backtrace(struct thread *td, db_addr_t fp, int count) } #ifdef __powerpc64__ - db_printf("0x%16lx: ", stackframe); + db_printf("0x%016lx: ", stackframe); #else db_printf("0x%08x: ", stackframe); #endif diff --git a/sys/powerpc/powerpc/mp_machdep.c b/sys/powerpc/powerpc/mp_machdep.c index 62a97e9..3563376 100644 --- a/sys/powerpc/powerpc/mp_machdep.c +++ b/sys/powerpc/powerpc/mp_machdep.c @@ -96,10 +96,6 @@ machdep_ap_bootstrap(void) printf("SMP: AP CPU #%d launched\n", PCPU_GET(cpuid)); mtx_unlock_spin(&ap_boot_mtx); - /* Initialize curthread */ - PCPU_SET(curthread, PCPU_GET(idlethread)); - PCPU_SET(curpcb, curthread->td_pcb); - /* Start per-CPU event timers. */ cpu_initclocks_ap(); diff --git a/sys/powerpc/ps3/ps3-hvcall.h b/sys/powerpc/ps3/ps3-hvcall.h index 912158b..0875a62 100644 --- a/sys/powerpc/ps3/ps3-hvcall.h +++ b/sys/powerpc/ps3/ps3-hvcall.h @@ -11,6 +11,34 @@ enum lpar_id { PS3_LPAR_ID_PME = 0x01, }; +/* Return codes from hypercalls */ +#define LV1_SUCCESS 0 +#define LV1_RESOURCE_SHORTAGE -2 +#define LV1_NO_PRIVILEGE -3 +#define LV1_DENIED_BY_POLICY -4 +#define LV1_ACCESS_VIOLATION -5 +#define LV1_NO_ENTRY -6 +#define LV1_DUPLICATE_ENTRY -7 +#define LV1_TYPE_MISMATCH -8 +#define LV1_BUSY -9 +#define LV1_EMPTY -10 +#define LV1_WRONG_STATE -11 +#define LV1_NO_MATCH -13 +#define LV1_ALREADY_CONNECTED -14 +#define LV1_UNSUPPORTED_PARAMETER_VALUE -15 +#define LV1_CONDITION_NOT_SATISFIED -16 +#define LV1_ILLEGAL_PARAMETER_VALUE -17 +#define LV1_BAD_OPTION -18 +#define LV1_IMPLEMENTATION_LIMITATION -19 +#define LV1_NOT_IMPLEMENTED -20 +#define LV1_INVALID_CLASS_ID -21 +#define LV1_CONSTRAINT_NOT_SATISFIED -22 +#define LV1_ALIGNMENT_ERROR -23 +#define LV1_HARDWARE_ERROR -24 +#define LV1_INVALID_DATA_FORMAT -25 +#define LV1_INVALID_OPERATION -26 +#define LV1_INTERNAL_ERROR -32768 + static inline uint64_t lv1_repository_string(const char *str) { diff --git a/sys/powerpc/ps3/ps3-hvcall.master b/sys/powerpc/ps3/ps3-hvcall.master index d53a32e..a9abe94 100644 --- a/sys/powerpc/ps3/ps3-hvcall.master +++ b/sys/powerpc/ps3/ps3-hvcall.master @@ -11,6 +11,34 @@ enum lpar_id { PS3_LPAR_ID_PME = 0x01, }; +/* Return codes from hypercalls */ +#define LV1_SUCCESS 0 +#define LV1_RESOURCE_SHORTAGE -2 +#define LV1_NO_PRIVILEGE -3 +#define LV1_DENIED_BY_POLICY -4 +#define LV1_ACCESS_VIOLATION -5 +#define LV1_NO_ENTRY -6 +#define LV1_DUPLICATE_ENTRY -7 +#define LV1_TYPE_MISMATCH -8 +#define LV1_BUSY -9 +#define LV1_EMPTY -10 +#define LV1_WRONG_STATE -11 +#define LV1_NO_MATCH -13 +#define LV1_ALREADY_CONNECTED -14 +#define LV1_UNSUPPORTED_PARAMETER_VALUE -15 +#define LV1_CONDITION_NOT_SATISFIED -16 +#define LV1_ILLEGAL_PARAMETER_VALUE -17 +#define LV1_BAD_OPTION -18 +#define LV1_IMPLEMENTATION_LIMITATION -19 +#define LV1_NOT_IMPLEMENTED -20 +#define LV1_INVALID_CLASS_ID -21 +#define LV1_CONSTRAINT_NOT_SATISFIED -22 +#define LV1_ALIGNMENT_ERROR -23 +#define LV1_HARDWARE_ERROR -24 +#define LV1_INVALID_DATA_FORMAT -25 +#define LV1_INVALID_OPERATION -26 +#define LV1_INTERNAL_ERROR -32768 + static inline uint64_t lv1_repository_string(const char *str) { diff --git a/sys/powerpc/ps3/ps3bus.c b/sys/powerpc/ps3/ps3bus.c index 2fe303d..90f0e87 100644 --- a/sys/powerpc/ps3/ps3bus.c +++ b/sys/powerpc/ps3/ps3bus.c @@ -629,7 +629,7 @@ ps3bus_get_dma_tag(device_t dev, device_t child) { struct ps3bus_devinfo *dinfo = device_get_ivars(child); struct ps3bus_softc *sc = device_get_softc(dev); - int i, err, flags; + int i, err, flags, pagesize; if (dinfo->bustype != PS3_BUSTYPE_SYSBUS && dinfo->bustype != PS3_BUSTYPE_STORAGE) @@ -646,9 +646,13 @@ ps3bus_get_dma_tag(device_t dev, device_t child) dinfo->devtype == PS3_DEVTYPE_USB) flags = 2; /* 8-bit mode */ + pagesize = 24; /* log_2(16 MB) */ + if (dinfo->bustype == PS3_BUSTYPE_STORAGE) + pagesize = 12; /* 4 KB */ + for (i = 0; i < sc->rcount; i++) { err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev, - sc->regions[i].mr_size, 24 /* log_2(16 MB) */, flags, + sc->regions[i].mr_size, pagesize, flags, &dinfo->dma_base[i]); if (err != 0) { device_printf(child, @@ -672,7 +676,15 @@ ps3bus_get_dma_tag(device_t dev, device_t child) NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &dinfo->dma_tag); - bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo); + /* + * Note: storage devices have IOMMU mappings set up by the hypervisor, + * but use physical, non-translated addresses. The above IOMMU + * initialization is necessary for the hypervisor to be able to set up + * the mappings, but actual DMA mappings should not use the IOMMU + * routines. + */ + if (dinfo->bustype != PS3_BUSTYPE_STORAGE) + bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo); fail: mtx_unlock(&dinfo->iommu_mtx); diff --git a/sys/powerpc/ps3/ps3disk.c b/sys/powerpc/ps3/ps3disk.c index 5390f50..3bab0f2 100644 --- a/sys/powerpc/ps3/ps3disk.c +++ b/sys/powerpc/ps3/ps3disk.c @@ -116,39 +116,25 @@ struct ps3disk_softc { struct disk **sc_disk; struct bio_queue_head sc_bioq; + struct bio_queue_head sc_deferredq; + struct proc *sc_task; - struct proc *sc_task; - - int sc_bounce_maxblocks; - bus_dma_tag_t sc_bounce_dmatag; - bus_dmamap_t sc_bounce_dmamap; - bus_addr_t sc_bounce_dmaphys; - char *sc_bounce; - uint64_t sc_bounce_lpar; - int sc_bounce_busy; - uint64_t sc_bounce_tag; - uint64_t sc_bounce_status; + bus_dma_tag_t sc_dmatag; int sc_running; - int sc_debug; }; static int ps3disk_open(struct disk *dp); static int ps3disk_close(struct disk *dp); static void ps3disk_strategy(struct bio *bp); -static void ps3disk_task(void *arg); -static int ps3disk_intr_filter(void *arg); +static void ps3disk_task(void *arg); static void ps3disk_intr(void *arg); -static void ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error); static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc); static int ps3disk_enum_regions(struct ps3disk_softc *sc); -static int ps3disk_read(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data); -static int ps3disk_write(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data); -static int ps3disk_flush(struct ps3disk_softc *sc); +static void ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, + int error); static void ps3disk_sysctlattach(struct ps3disk_softc *sc); @@ -172,6 +158,7 @@ ps3disk_attach(device_t dev) struct ps3disk_softc *sc; struct disk *d; intmax_t mb; + uint64_t junk; char unit; int i, err; @@ -205,7 +192,6 @@ ps3disk_attach(device_t dev) } /* Setup interrupt handler */ - sc->sc_irqid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqid, RF_ACTIVE); @@ -217,52 +203,24 @@ ps3disk_attach(device_t dev) err = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_BIO | INTR_MPSAFE | INTR_ENTROPY, - ps3disk_intr_filter, ps3disk_intr, sc, &sc->sc_irqctx); + NULL, ps3disk_intr, sc, &sc->sc_irqctx); if (err) { device_printf(dev, "Could not setup IRQ\n"); err = ENXIO; goto fail_release_intr; } - /* Setup DMA bounce buffer */ - - sc->sc_bounce_maxblocks = DFLTPHYS / sc->sc_blksize; - + /* Setup DMA */ err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, - sc->sc_bounce_maxblocks * sc->sc_blksize, 1, - sc->sc_bounce_maxblocks * sc->sc_blksize, - 0, NULL, NULL, &sc->sc_bounce_dmatag); + BUS_SPACE_UNRESTRICTED, 1, PAGE_SIZE, 0, + busdma_lock_mutex, &sc->sc_mtx, &sc->sc_dmatag); if (err) { - device_printf(dev, "Could not create DMA tag for bounce buffer\n"); + device_printf(dev, "Could not create DMA tag\n"); err = ENXIO; goto fail_teardown_intr; } - err = bus_dmamem_alloc(sc->sc_bounce_dmatag, (void **) &sc->sc_bounce, - BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, - &sc->sc_bounce_dmamap); - if (err) { - device_printf(dev, "Could not allocate DMA memory for bounce buffer\n"); - err = ENXIO; - goto fail_destroy_dmatag; - } - - err = bus_dmamap_load(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - sc->sc_bounce, sc->sc_bounce_maxblocks * sc->sc_blksize, - ps3disk_getphys, &sc->sc_bounce_dmaphys, 0); - if (err) { - device_printf(dev, "Could not load DMA map for bounce buffer\n"); - err = ENXIO; - goto fail_free_dmamem; - } - - sc->sc_bounce_lpar = vtophys(sc->sc_bounce); - - if (bootverbose) - device_printf(dev, "bounce buffer lpar address 0x%016lx\n", - sc->sc_bounce_lpar); - /* Setup disks */ sc->sc_disk = malloc(sc->sc_nregs * sizeof(struct disk *), @@ -270,7 +228,7 @@ ps3disk_attach(device_t dev) if (!sc->sc_disk) { device_printf(dev, "Could not allocate disk(s)\n"); err = ENOMEM; - goto fail_unload_dmamem; + goto fail_teardown_intr; } for (i = 0; i < sc->sc_nregs; i++) { @@ -282,7 +240,7 @@ ps3disk_attach(device_t dev) d->d_strategy = ps3disk_strategy; d->d_name = "ps3disk"; d->d_drv1 = sc; - d->d_maxsize = DFLTPHYS; + d->d_maxsize = PAGE_SIZE; d->d_sectorsize = sc->sc_blksize; d->d_unit = i; d->d_mediasize = sc->sc_reg[i].r_size * sc->sc_blksize; @@ -297,53 +255,32 @@ ps3disk_attach(device_t dev) /* Test to see if we can read this region */ err = lv1_storage_read(ps3bus_get_device(dev), d->d_unit, - 0, 1, rp->r_flags, sc->sc_bounce_lpar, &sc->sc_bounce_tag); + 0, 0, rp->r_flags, 0, &junk); device_printf(dev, "region %d %ju%cB%s\n", i, mb, unit, - (err == 0) ? "" : " (hypervisor protected)"); + (err == LV1_DENIED_BY_POLICY) ? " (hypervisor protected)" + : ""); - if (err == 0) + if (err != LV1_DENIED_BY_POLICY) disk_create(d, DISK_VERSION); } err = 0; bioq_init(&sc->sc_bioq); + bioq_init(&sc->sc_deferredq); + kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "ps3disk"); ps3disk_sysctlattach(sc); - sc->sc_running = 1; - - kproc_create(&ps3disk_task, sc, &sc->sc_task, 0, 0, "task: ps3disk"); - return (0); -fail_unload_dmamem: - - bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); - -fail_free_dmamem: - - bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); - -fail_destroy_dmatag: - - bus_dma_tag_destroy(sc->sc_bounce_dmatag); - fail_teardown_intr: - bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); - fail_release_intr: - bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); - fail_free_regions: - free(sc->sc_reg, M_PS3DISK); - fail_destroy_lock: - PS3DISK_LOCK_DESTROY(sc); - return (err); } @@ -353,28 +290,15 @@ ps3disk_detach(device_t dev) struct ps3disk_softc *sc = device_get_softc(dev); int i; - PS3DISK_LOCK(sc); - sc->sc_running = 0; - wakeup(sc); - PS3DISK_UNLOCK(sc); - - PS3DISK_LOCK(sc); - while (sc->sc_running != -1) - msleep(sc, &sc->sc_mtx, PRIBIO, "detach", 0); - PS3DISK_UNLOCK(sc); - for (i = 0; i < sc->sc_nregs; i++) disk_destroy(sc->sc_disk[i]); - bus_dmamap_unload(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap); - bus_dmamem_free(sc->sc_bounce_dmatag, sc->sc_bounce, sc->sc_bounce_dmamap); - bus_dma_tag_destroy(sc->sc_bounce_dmatag); + bus_dma_tag_destroy(sc->sc_dmatag); bus_teardown_intr(dev, sc->sc_irq, sc->sc_irqctx); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqid, sc->sc_irq); free(sc->sc_disk, M_PS3DISK); - free(sc->sc_reg, M_PS3DISK); PS3DISK_LOCK_DESTROY(sc); @@ -394,127 +318,94 @@ ps3disk_close(struct disk *dp) return (0); } -static void -ps3disk_strategy(struct bio *bp) -{ - struct ps3disk_softc *sc = (struct ps3disk_softc *) bp->bio_disk->d_drv1; - - if (!sc) { - bp->bio_flags |= BIO_ERROR; - bp->bio_error = EINVAL; - biodone(bp); - return; - } - - PS3DISK_LOCK(sc); - bioq_disksort(&sc->sc_bioq, bp); - if (!sc->sc_bounce_busy) - wakeup(sc); - PS3DISK_UNLOCK(sc); -} - +/* Process deferred blocks */ static void ps3disk_task(void *arg) { struct ps3disk_softc *sc = (struct ps3disk_softc *) arg; struct bio *bp; - daddr_t block, end; - u_long nblocks; - char *data; - int err; - while (sc->sc_running) { + + while (1) { + kproc_suspend_check(sc->sc_task); + tsleep(&sc->sc_deferredq, PRIBIO, "ps3disk", 10); + PS3DISK_LOCK(sc); - do { - bp = bioq_first(&sc->sc_bioq); - if (bp == NULL) - msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0); - } while (bp == NULL && sc->sc_running); - if (bp) - bioq_remove(&sc->sc_bioq, bp); + bp = bioq_takefirst(&sc->sc_deferredq); PS3DISK_UNLOCK(sc); - if (!sc->sc_running) - break; + if (bp == NULL) + continue; - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n", - __func__, bp->bio_cmd); + if (bp->bio_driver1 != NULL) { + bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + } - if (bp->bio_cmd == BIO_FLUSH) { - err = ps3disk_flush(sc); + ps3disk_strategy(bp); + } - if (err) { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - } else { - bp->bio_error = 0; - bp->bio_flags |= BIO_DONE; - } - } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { - end = bp->bio_pblkno + (bp->bio_bcount / sc->sc_blksize); - - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_pblkno %ld bio_bcount %ld\n", - __func__, bp->bio_pblkno, bp->bio_bcount); - - for (block = bp->bio_pblkno; block < end;) { - data = bp->bio_data + - (block - bp->bio_pblkno) * sc->sc_blksize; - - nblocks = end - block; - if (nblocks > sc->sc_bounce_maxblocks) - nblocks = sc->sc_bounce_maxblocks; - - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: nblocks %lu\n", - __func__, nblocks); - - if (bp->bio_cmd == BIO_READ) { - err = ps3disk_read(sc, bp->bio_disk->d_unit, - block, nblocks, data); - } else { - err = ps3disk_write(sc, bp->bio_disk->d_unit, - block, nblocks, data); - } - - if (err) - break; - - block += nblocks; - } + kproc_exit(0); +} - bp->bio_resid = (end - block) * sc->sc_blksize; - if (bp->bio_resid) { - bp->bio_error = EIO; - bp->bio_flags |= BIO_ERROR; - } else { - bp->bio_error = 0; - bp->bio_flags |= BIO_DONE; - } +static void +ps3disk_strategy(struct bio *bp) +{ + struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1; + int err; + + if (sc == NULL) { + bp->bio_flags |= BIO_ERROR; + bp->bio_error = EINVAL; + biodone(bp); + return; + } + + PS3DISK_LOCK(sc); + bp->bio_resid = bp->bio_bcount; + bioq_insert_tail(&sc->sc_bioq, bp); - DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_resid %ld\n", - __func__, bp->bio_resid); + DPRINTF(sc, PS3DISK_DEBUG_TASK, "%s: bio_cmd 0x%02x\n", + __func__, bp->bio_cmd); + + err = 0; + if (bp->bio_cmd == BIO_FLUSH) { + bp->bio_driver1 = 0; + err = lv1_storage_send_device_command( + ps3bus_get_device(sc->sc_dev), LV1_STORAGE_ATA_HDDOUT, + 0, 0, 0, 0, (uint64_t *)&bp->bio_driver2); + if (err == LV1_BUSY) + err = EAGAIN; + } else if (bp->bio_cmd == BIO_READ || bp->bio_cmd == BIO_WRITE) { + if (bp->bio_bcount % sc->sc_blksize != 0) { + err = EINVAL; } else { - bp->bio_error = EINVAL; - bp->bio_flags |= BIO_ERROR; + bus_dmamap_create(sc->sc_dmatag, BUS_DMA_COHERENT, + (bus_dmamap_t *)(&bp->bio_driver1)); + err = bus_dmamap_load(sc->sc_dmatag, + (bus_dmamap_t)(bp->bio_driver1), bp->bio_data, + bp->bio_bcount, ps3disk_transfer, bp, 0); + if (err == EINPROGRESS) + err = 0; } + } else { + err = EINVAL; + } - if (bp->bio_flags & BIO_ERROR) - disk_err(bp, "hard error", -1, 1); - + if (err == EAGAIN) { + bioq_remove(&sc->sc_bioq, bp); + bioq_insert_tail(&sc->sc_deferredq, bp); + } else if (err != 0) { + bp->bio_error = err; + bp->bio_flags |= BIO_ERROR; + bioq_remove(&sc->sc_bioq, bp); + disk_err(bp, "hard error", -1, 1); biodone(bp); } - PS3DISK_LOCK(sc); - sc->sc_running = -1; - wakeup(sc); PS3DISK_UNLOCK(sc); - - kproc_exit(0); -} - -static int -ps3disk_intr_filter(void *arg) -{ - return (FILTER_SCHEDULE_THREAD); } static void @@ -523,50 +414,55 @@ ps3disk_intr(void *arg) struct ps3disk_softc *sc = (struct ps3disk_softc *) arg; device_t dev = sc->sc_dev; uint64_t devid = ps3bus_get_device(dev); + struct bio *bp; uint64_t tag, status; - int err; + if (lv1_storage_get_async_status(devid, &tag, &status) != 0) + return; + PS3DISK_LOCK(sc); - err = lv1_storage_get_async_status(devid, &tag, &status); - - DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: err %d tag 0x%016lx status 0x%016lx\n", - __func__, err, tag, status); - - if (err) - goto out; + DPRINTF(sc, PS3DISK_DEBUG_INTR, "%s: tag 0x%016lx " + "status 0x%016lx\n", __func__, tag, status); - if (!sc->sc_bounce_busy) { - device_printf(dev, "Got interrupt while no request pending\n"); - goto out; - } - - if (tag != sc->sc_bounce_tag) - device_printf(dev, "Tag mismatch, got 0x%016lx expected 0x%016lx\n", - tag, sc->sc_bounce_tag); + /* Locate the matching request */ + TAILQ_FOREACH(bp, &sc->sc_bioq.queue, bio_queue) { + if ((uint64_t)bp->bio_driver2 != tag) + continue; - if (status) - device_printf(dev, "Request completed with status 0x%016lx\n", status); + if (status != 0) { + device_printf(sc->sc_dev, "%s error (%#lx)\n", + (bp->bio_cmd == BIO_READ) ? "Read" : "Write", + status); + bp->bio_error = EIO; + bp->bio_flags |= BIO_ERROR; + } else { + bp->bio_error = 0; + bp->bio_resid = 0; + bp->bio_flags |= BIO_DONE; + } - sc->sc_bounce_status = status; - sc->sc_bounce_busy = 0; + if (bp->bio_driver1 != NULL) { + if (bp->bio_cmd == BIO_READ) + bus_dmamap_sync(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + } - wakeup(sc); + bioq_remove(&sc->sc_bioq, bp); + biodone(bp); + break; + } -out: + if (bioq_first(&sc->sc_deferredq) != NULL) + wakeup(&sc->sc_deferredq); PS3DISK_UNLOCK(sc); } -static void -ps3disk_getphys(void *arg, bus_dma_segment_t *segs, int nsegs, int error) -{ - if (error != 0) - return; - - *(bus_addr_t *) arg = segs[0].ds_addr; -} - static int ps3disk_get_disk_geometry(struct ps3disk_softc *sc) { @@ -582,8 +478,7 @@ ps3disk_get_disk_geometry(struct ps3disk_softc *sc) lv1_repository_string("blk_size"), 0, &sc->sc_blksize, &junk); if (err) { device_printf(dev, "Could not get block size (0x%08x)\n", err); - err = ENXIO; - goto out; + return (ENXIO); } err = lv1_get_repository_node_value(PS3_LPAR_ID_PME, @@ -591,16 +486,11 @@ ps3disk_get_disk_geometry(struct ps3disk_softc *sc) lv1_repository_string("dev") | dev_index, lv1_repository_string("n_blocks"), 0, &sc->sc_nblocks, &junk); if (err) { - device_printf(dev, "Could not get total number of blocks (0x%08x)\n", - err); + device_printf(dev, "Could not get total number of blocks " + "(0x%08x)\n", err); err = ENXIO; - goto out; } - err = 0; - -out: - return (err); } @@ -655,10 +545,11 @@ ps3disk_enum_regions(struct ps3disk_softc *sc) (lv1_repository_string("bus") >> 32) | bus_index, lv1_repository_string("dev") | dev_index, lv1_repository_string("region") | i, - lv1_repository_string("start"), &sc->sc_reg[i].r_start, &junk); + lv1_repository_string("start"), &sc->sc_reg[i].r_start, + &junk); if (err) { - device_printf(dev, "Could not get region start (0x%08x)\n", - err); + device_printf(dev, "Could not get region start " + "(0x%08x)\n", err); err = ENXIO; goto fail; } @@ -667,16 +558,16 @@ ps3disk_enum_regions(struct ps3disk_softc *sc) (lv1_repository_string("bus") >> 32) | bus_index, lv1_repository_string("dev") | dev_index, lv1_repository_string("region") | i, - lv1_repository_string("size"), &sc->sc_reg[i].r_size, &junk); + lv1_repository_string("size"), &sc->sc_reg[i].r_size, + &junk); if (err) { - device_printf(dev, "Could not get region size (0x%08x)\n", - err); + device_printf(dev, "Could not get region size " + "(0x%08x)\n", err); err = ENXIO; goto fail; } if (i == 0) - /* disables HV access control and grants access to whole disk */ sc->sc_reg[i].r_flags = 0x2; else sc->sc_reg[i].r_flags = 0; @@ -693,160 +584,70 @@ fail: return (err); } -static int -ps3disk_read(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data) -{ - device_t dev = sc->sc_dev; - struct ps3disk_region *rp = &sc->sc_reg[regidx]; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); - - if (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - sc->sc_bounce_busy = 1; - - err = lv1_storage_read(devid, rp->r_id, - start_sector, sector_count, rp->r_flags, - sc->sc_bounce_lpar, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not read sectors (0x%08x)\n", err); - err = EIO; - goto out; - } - - DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); - - err = msleep(sc, &sc->sc_mtx, PRIBIO, "read", hz); - if (err) { - device_printf(dev, "Read request timed out\n"); - err = EIO; - goto out; - } - - if (sc->sc_bounce_busy || sc->sc_bounce_status) { - err = EIO; - } else { - bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - BUS_DMASYNC_POSTREAD); - memcpy(data, sc->sc_bounce, sector_count * sc->sc_blksize); - err = 0; - } - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); -} - -static int -ps3disk_write(struct ps3disk_softc *sc, int regidx, - uint64_t start_sector, uint64_t sector_count, char *data) +static void +ps3disk_transfer(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { - device_t dev = sc->sc_dev; - struct ps3disk_region *rp = &sc->sc_reg[regidx]; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); - - if (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - memcpy(sc->sc_bounce, data, sector_count * sc->sc_blksize); - - bus_dmamap_sync(sc->sc_bounce_dmatag, sc->sc_bounce_dmamap, - BUS_DMASYNC_PREWRITE); - - sc->sc_bounce_busy = 1; - - err = lv1_storage_write(devid, rp->r_id, - start_sector, sector_count, rp->r_flags, - sc->sc_bounce_lpar, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not write sectors (0x%08x)\n", err); - err = EIO; - goto out; - } + struct bio *bp = (struct bio *)(arg); + struct ps3disk_softc *sc = (struct ps3disk_softc *)bp->bio_disk->d_drv1; + struct ps3disk_region *rp = &sc->sc_reg[bp->bio_disk->d_unit]; + uint64_t devid = ps3bus_get_device(sc->sc_dev); + uint64_t block; + int i, err; - DPRINTF(sc, PS3DISK_DEBUG_WRITE, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); + /* Locks already held by busdma */ + PS3DISK_ASSERT_LOCKED(sc); - err = msleep(sc, &sc->sc_mtx, PRIBIO, "write", hz); - if (err) { - device_printf(dev, "Write request timed out\n"); - err = EIO; - goto out; + if (error) { + bp->bio_error = error; + bp->bio_flags |= BIO_ERROR; + bioq_remove(&sc->sc_bioq, bp); + biodone(bp); + return; } - err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); -} - -static int -ps3disk_flush(struct ps3disk_softc *sc) -{ - device_t dev = sc->sc_dev; - uint64_t devid = ps3bus_get_device(dev); - int err; - - PS3DISK_LOCK(sc); + block = bp->bio_pblkno; + for (i = 0; i < nsegs; i++) { + KASSERT((segs[i].ds_len % sc->sc_blksize) == 0, + ("DMA fragments not blocksize multiples")); - if (sc->sc_bounce_busy) { - device_printf(dev, "busy\n"); - PS3DISK_UNLOCK(sc); - return EIO; - } - - sc->sc_bounce_busy = 1; + if (bp->bio_cmd == BIO_READ) { + err = lv1_storage_read(devid, rp->r_id, + block, segs[i].ds_len/sc->sc_blksize, + rp->r_flags, segs[i].ds_addr, + (uint64_t *)&bp->bio_driver2); + } else { + bus_dmamap_sync(sc->sc_dmatag, + (bus_dmamap_t)bp->bio_driver1, + BUS_DMASYNC_PREWRITE); + err = lv1_storage_write(devid, rp->r_id, + block, segs[i].ds_len/sc->sc_blksize, + rp->r_flags, segs[i].ds_addr, + (uint64_t *)&bp->bio_driver2); + } - err = lv1_storage_send_device_command(devid, LV1_STORAGE_ATA_HDDOUT, - 0, 0, 0, 0, &sc->sc_bounce_tag); - if (err) { - device_printf(dev, "Could not flush (0x%08x)\n", err); - err = EIO; - goto out; - } + if (err) { + if (err == LV1_BUSY) { + bioq_remove(&sc->sc_bioq, bp); + bioq_insert_tail(&sc->sc_deferredq, bp); + } else { + bus_dmamap_unload(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + bus_dmamap_destroy(sc->sc_dmatag, (bus_dmamap_t) + bp->bio_driver1); + device_printf(sc->sc_dev, "Could not read " + "sectors (0x%08x)\n", err); + bp->bio_error = EINVAL; + bp->bio_flags |= BIO_ERROR; + bioq_remove(&sc->sc_bioq, bp); + biodone(bp); + } - DPRINTF(sc, PS3DISK_DEBUG_FLUSH, "%s: tag 0x%016lx\n", - __func__, sc->sc_bounce_tag); + break; + } - err = msleep(sc, &sc->sc_mtx, PRIBIO, "flush", hz); - if (err) { - device_printf(dev, "Flush request timed out\n"); - err = EIO; - goto out; + DPRINTF(sc, PS3DISK_DEBUG_READ, "%s: tag 0x%016lx\n", + __func__, sc->sc_bounce_tag); } - - err = (sc->sc_bounce_busy || sc->sc_bounce_status) ? EIO : 0; - -out: - - sc->sc_bounce_busy = 0; - - PS3DISK_UNLOCK(sc); - - return (err); } #ifdef PS3DISK_DEBUG diff --git a/sys/powerpc/ps3/ps3pic.c b/sys/powerpc/ps3/ps3pic.c index c00585b..3a62e3c 100644 --- a/sys/powerpc/ps3/ps3pic.c +++ b/sys/powerpc/ps3/ps3pic.c @@ -56,10 +56,10 @@ static void ps3pic_mask(device_t, u_int); static void ps3pic_unmask(device_t, u_int); struct ps3pic_softc { - uint64_t *bitmap_thread0; - uint64_t *mask_thread0; - uint64_t *bitmap_thread1; - uint64_t *mask_thread1; + volatile uint64_t *bitmap_thread0; + volatile uint64_t *mask_thread0; + volatile uint64_t *bitmap_thread1; + volatile uint64_t *mask_thread1; uint64_t sc_ipi_outlet[2]; int sc_vector[64]; @@ -219,8 +219,8 @@ ps3pic_mask(device_t dev, u_int irq) if (irq == sc->sc_ipi_outlet[0]) return; - sc->mask_thread0[0] &= ~(1UL << (63 - irq)); - sc->mask_thread1[0] &= ~(1UL << (63 - irq)); + atomic_clear_64(&sc->mask_thread0[0], 1UL << (63 - irq)); + atomic_clear_64(&sc->mask_thread1[0], 1UL << (63 - irq)); lv1_get_logical_ppe_id(&ppe); lv1_did_update_interrupt_mask(ppe, 0); @@ -234,8 +234,8 @@ ps3pic_unmask(device_t dev, u_int irq) uint64_t ppe; sc = device_get_softc(dev); - sc->mask_thread0[0] |= (1UL << (63 - irq)); - sc->mask_thread1[0] |= (1UL << (63 - irq)); + atomic_set_64(&sc->mask_thread0[0], 1UL << (63 - irq)); + atomic_set_64(&sc->mask_thread1[0], 1UL << (63 - irq)); lv1_get_logical_ppe_id(&ppe); lv1_did_update_interrupt_mask(ppe, 0); diff --git a/sys/sparc64/include/tsb.h b/sys/sparc64/include/tsb.h index 5fa1190..1fd1e8f 100644 --- a/sys/sparc64/include/tsb.h +++ b/sys/sparc64/include/tsb.h @@ -50,7 +50,6 @@ extern struct tte *tsb_kernel; extern vm_size_t tsb_kernel_mask; extern vm_size_t tsb_kernel_size; extern vm_paddr_t tsb_kernel_phys; -extern u_int tsb_kernel_ldd_phys; static __inline struct tte * tsb_vpntobucket(pmap_t pm, vm_offset_t vpn) diff --git a/sys/sparc64/include/vmparam.h b/sys/sparc64/include/vmparam.h index 1b9e537..a0d5ac4 100644 --- a/sys/sparc64/include/vmparam.h +++ b/sys/sparc64/include/vmparam.h @@ -70,7 +70,7 @@ * The number of PHYSSEG entries must be one greater than the number * of phys_avail entries because the phys_avail entry that spans the * largest physical address that is accessible by ISA DMA is split - * into two PHYSSEG entries. + * into two PHYSSEG entries. */ #define VM_PHYSSEG_MAX 64 @@ -136,13 +136,13 @@ * 43 bits of user address space is considered to be "enough", so we ignore it. * * Upper region: 0xffffffffffffffff - * 0xfffff80000000000 - * + * 0xfffff80000000000 + * * Hole: 0xfffff7ffffffffff - * 0x0000080000000000 + * 0x0000080000000000 * * Lower region: 0x000007ffffffffff - * 0x0000000000000000 + * 0x0000000000000000 * * In general we ignore the upper region, and use the lower region as mappable * space. @@ -218,7 +218,7 @@ * is the total KVA space allocated for kmem_map. */ #ifndef VM_KMEM_SIZE_SCALE -#define VM_KMEM_SIZE_SCALE (3) +#define VM_KMEM_SIZE_SCALE (tsb_kernel_ldd_phys == 0 ? 3 : 1) #endif /* @@ -238,6 +238,7 @@ #define UMA_MD_SMALL_ALLOC +extern u_int tsb_kernel_ldd_phys; extern vm_offset_t vm_max_kernel_address; /* diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c index 876dce3..f917af9 100644 --- a/sys/sparc64/sparc64/pmap.c +++ b/sys/sparc64/sparc64/pmap.c @@ -384,11 +384,12 @@ pmap_bootstrap(u_int cpu_impl) * public documentation is available for these, the latter just might * not support it, yet. */ - virtsz = roundup(physsz, PAGE_SIZE_4M << (PAGE_SHIFT - TTE_SHIFT)); if (cpu_impl == CPU_IMPL_SPARC64V || - cpu_impl >= CPU_IMPL_ULTRASPARCIIIp) + cpu_impl >= CPU_IMPL_ULTRASPARCIIIp) { tsb_kernel_ldd_phys = 1; - else { + virtsz = roundup(5 / 3 * physsz, PAGE_SIZE_4M << + (PAGE_SHIFT - TTE_SHIFT)); + } else { dtlb_slots_avail = 0; for (i = 0; i < dtlb_slots; i++) { data = dtlb_get_data(i); @@ -401,6 +402,8 @@ pmap_bootstrap(u_int cpu_impl) if (cpu_impl >= CPU_IMPL_ULTRASPARCI && cpu_impl < CPU_IMPL_ULTRASPARCIII) dtlb_slots_avail /= 2; + virtsz = roundup(physsz, PAGE_SIZE_4M << + (PAGE_SHIFT - TTE_SHIFT)); virtsz = MIN(virtsz, (dtlb_slots_avail * PAGE_SIZE_4M) << (PAGE_SHIFT - TTE_SHIFT)); } diff --git a/sys/sparc64/sparc64/sys_machdep.c b/sys/sparc64/sparc64/sys_machdep.c index 9ac5fbc..530ff95 100644 --- a/sys/sparc64/sparc64/sys_machdep.c +++ b/sys/sparc64/sparc64/sys_machdep.c @@ -26,8 +26,11 @@ * $FreeBSD$ */ +#include "opt_capsicum.h" + #include <sys/param.h> #include <sys/systm.h> +#include <sys/capability.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mutex.h> @@ -53,6 +56,24 @@ sysarch(struct thread *td, struct sysarch_args *uap) { int error; +#ifdef CAPABILITY_MODE + /* + * When adding new operations, add a new case statement here to + * explicitly indicate whether or not the operation is safe to + * perform in capability mode. + */ + if (IN_CAPABILITY_MODE(td)) { + switch (uap->op) { + case SPARC_SIGTRAMP_INSTALL: + case SPARC_UTRAP_INSTALL: + break; + + default: + return (ECAPMODE); + } + } +#endif + mtx_lock(&Giant); switch (uap->op) { case SPARC_SIGTRAMP_INSTALL: diff --git a/sys/sys/diskmbr.h b/sys/sys/diskmbr.h index 5aa275c..5b62e64 100644 --- a/sys/sys/diskmbr.h +++ b/sys/sys/diskmbr.h @@ -36,6 +36,7 @@ #include <sys/ioccom.h> #define DOSBBSECTOR 0 /* DOS boot block relative sector number */ +#define DOSDSNOFF 440 /* WinNT/2K/XP Drive Serial Number offset */ #define DOSPARTOFF 446 #define DOSPARTSIZE 16 #define NDOSPART 4 diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 33dddca..2dab741 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -113,6 +113,8 @@ int dupfdopen(struct thread *td, struct filedesc *fdp, int indx, int dfd, int mode, int error); int falloc(struct thread *td, struct file **resultfp, int *resultfd, int flags); +int falloc_noinstall(struct thread *td, struct file **resultfp); +int finstall(struct thread *td, struct file *fp, int *resultfp, int flags); int fdalloc(struct thread *td, int minfd, int *result); int fdavail(struct thread *td, int n); int fdcheckstd(struct thread *td); diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index c2b7081..b186f79 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -695,6 +695,16 @@ m_last(struct mbuf *m) return (m); } +extern void (*m_addr_chg_pf_p)(struct mbuf *m); + +static __inline void +m_addr_changed(struct mbuf *m) +{ + + if (m_addr_chg_pf_p) + m_addr_chg_pf_p(m); +} + /* * mbuf, cluster, and external object allocation macros (for compatibility * purposes). diff --git a/sys/sys/param.h b/sys/sys/param.h index 589a0f7..4f54eac 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 900038 /* Master, propagated to newvers */ +#define __FreeBSD_version 900039 /* Master, propagated to newvers */ #ifdef _KERNEL #define P_OSREL_SIGSEGV 700004 diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h index a6817df..2916287 100644 --- a/sys/sys/soundcard.h +++ b/sys/sys/soundcard.h @@ -311,8 +311,7 @@ typedef struct _snd_capabilities { * IOCTL Commands for /dev/sequencer */ -#define SNDCTL_SEQ_HALT _IO ('Q', 0) -#define SNDCTL_SEQ_RESET SNDCTL_SEQ_HALT /* Historic interface */ +#define SNDCTL_SEQ_RESET _IO ('Q', 0) #define SNDCTL_SEQ_SYNC _IO ('Q', 1) #define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info) #define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer res.(hz) */ @@ -776,7 +775,8 @@ typedef struct { * IOCTL commands for /dev/dsp and /dev/audio */ -#define SNDCTL_DSP_RESET _IO ('P', 0) +#define SNDCTL_DSP_HALT _IO ('P', 0) +#define SNDCTL_DSP_RESET SNDCTL_DSP_HALT #define SNDCTL_DSP_SYNC _IO ('P', 1) #define SNDCTL_DSP_SPEED _IOWR('P', 2, int) #define SNDCTL_DSP_STEREO _IOWR('P', 3, int) diff --git a/sys/sys/systm.h b/sys/sys/systm.h index e563a5a..35d34e4 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -253,6 +253,7 @@ void cpu_startprofclock(void); void cpu_stopprofclock(void); void cpu_idleclock(void); void cpu_activeclock(void); +extern int cpu_can_deep_sleep; extern int cpu_disable_deep_sleep; int cr_cansee(struct ucred *u1, struct ucred *u2); diff --git a/sys/teken/demo/teken_demo.c b/sys/teken/demo/teken_demo.c index 0700763..16bb4b7 100644 --- a/sys/teken/demo/teken_demo.c +++ b/sys/teken/demo/teken_demo.c @@ -88,7 +88,7 @@ printchar(const teken_pos_t *p) getyx(stdscr, y, x); - px = &buffer[p->tp_col][p->tp_row]; + px = &buffer[p->tp_col][p->tp_row]; /* Convert Unicode to UTF-8. */ if (px->c < 0x80) { @@ -169,10 +169,10 @@ test_copy(void *s __unused, const teken_rect_t *r, const teken_pos_t *p) * Copying is a little tricky. We must make sure we do it in * correct order, to make sure we don't overwrite our own data. */ - + nrow = r->tr_end.tp_row - r->tr_begin.tp_row; ncol = r->tr_end.tp_col - r->tr_begin.tp_col; - + if (p->tp_row < r->tr_begin.tp_row) { /* Copy from top to bottom. */ if (p->tp_col < r->tr_begin.tp_col) { diff --git a/sys/teken/gensequences b/sys/teken/gensequences index 86c7979..e0fccd4 100644 --- a/sys/teken/gensequences +++ b/sys/teken/gensequences @@ -3,7 +3,7 @@ #- # Copyright (c) 2008-2009 Ed Schouten <ed@FreeBSD.org> # All rights reserved. -# +# # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: @@ -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. -# +# # 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 diff --git a/sys/teken/libteken/teken.3 b/sys/teken/libteken/teken.3 index 2a9b291..1c2ebbe 100644 --- a/sys/teken/libteken/teken.3 +++ b/sys/teken/libteken/teken.3 @@ -148,7 +148,7 @@ These defaults can be modified using and .Fn teken_set_defattr . .Pp -The +The .Fn teken_get_sequence function is a utility function that can be used to obtain escape sequences of special keyboard keys, generated by user input. diff --git a/sys/teken/teken.c b/sys/teken/teken.c index cdc2cb3..8ca88d2 100644 --- a/sys/teken/teken.c +++ b/sys/teken/teken.c @@ -526,7 +526,7 @@ teken_get_sequence(teken_t *t, unsigned int k) /* Default xterm sequences. */ if (k < sizeof special_strings_normal / sizeof(char *)) return (special_strings_normal[k]); - + return (NULL); } diff --git a/sys/teken/teken_subr.h b/sys/teken/teken_subr.h index 2934bcc..f4c78f4 100644 --- a/sys/teken/teken_subr.h +++ b/sys/teken/teken_subr.h @@ -260,7 +260,7 @@ teken_subr_cursor_backward_tabulation(teken_t *t, unsigned int ntabs) break; t->t_cursor.tp_col--; - + /* Tab marker set. */ if (teken_tab_isset(t, t->t_cursor.tp_col)) ntabs--; @@ -303,7 +303,7 @@ teken_subr_cursor_forward_tabulation(teken_t *t, unsigned int ntabs) break; t->t_cursor.tp_col++; - + /* Tab marker set. */ if (teken_tab_isset(t, t->t_cursor.tp_col)) ntabs--; diff --git a/sys/ufs/ffs/ffs_inode.c b/sys/ufs/ffs/ffs_inode.c index a7b43e2..62fa8e0 100644 --- a/sys/ufs/ffs/ffs_inode.c +++ b/sys/ufs/ffs/ffs_inode.c @@ -128,7 +128,7 @@ ffs_pages_remove(struct vnode *vp, vm_pindex_t start, vm_pindex_t end) if ((object = vp->v_object) == NULL) return; VM_OBJECT_LOCK(object); - vm_object_page_remove(object, start, end, FALSE); + vm_object_page_remove(object, start, end, 0); VM_OBJECT_UNLOCK(object); } diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index a10104d..9af5f67 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -12081,6 +12081,7 @@ top: continue; case D_FREEWORK: + case D_FREEDEP: continue; default: diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 7568f57..55abe86 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -1095,8 +1095,7 @@ vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len, * required in order to call vm_page_dirty(). See * vm_page_clear_dirty_mask(). */ -#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) || \ - defined(__mips__) +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) vm_page_dirty(*mp); #else vm_page_lock_queues(); diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 752354a..31886af 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2708,7 +2708,15 @@ vm_map_entry_delete(vm_map_t map, vm_map_entry_t entry) ((object->flags & (OBJ_NOSPLIT|OBJ_ONEMAPPING)) == OBJ_ONEMAPPING || object == kernel_object || object == kmem_object)) { vm_object_collapse(object); - vm_object_page_remove(object, offidxstart, offidxend, FALSE); + + /* + * The option OBJPR_NOTMAPPED can be passed here + * because vm_map_delete() already performed + * pmap_remove() on the only mapping to this range + * of pages. + */ + vm_object_page_remove(object, offidxstart, offidxend, + OBJPR_NOTMAPPED); if (object->type == OBJT_SWAP) swap_pager_freespace(object, offidxstart, count); if (offidxend >= object->size && diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c index 1a3d398..b5788f5 100644 --- a/sys/vm/vm_object.c +++ b/sys/vm/vm_object.c @@ -923,6 +923,10 @@ vm_object_page_collect_flush(vm_object_t object, vm_page_t p, int pagerflags, * We invalidate (remove) all pages from the address space * for semantic correctness. * + * If the backing object is a device object with unmanaged pages, then any + * mappings to the specified range of pages must be removed before this + * function is called. + * * Note: certain anonymous maps, such as MAP_NOSYNC maps, * may start out with a NULL object. */ @@ -978,12 +982,19 @@ vm_object_sync(vm_object_t object, vm_ooffset_t offset, vm_size_t size, } if ((object->type == OBJT_VNODE || object->type == OBJT_DEVICE) && invalidate) { - boolean_t purge; - purge = old_msync || (object->type == OBJT_DEVICE); - vm_object_page_remove(object, - OFF_TO_IDX(offset), - OFF_TO_IDX(offset + size + PAGE_MASK), - purge ? FALSE : TRUE); + if (object->type == OBJT_DEVICE) + /* + * The option OBJPR_NOTMAPPED must be passed here + * because vm_object_page_remove() cannot remove + * unmanaged mappings. + */ + flags = OBJPR_NOTMAPPED; + else if (old_msync) + flags = 0; + else + flags = OBJPR_CLEANONLY; + vm_object_page_remove(object, OFF_TO_IDX(offset), + OFF_TO_IDX(offset + size + PAGE_MASK), flags); } VM_OBJECT_UNLOCK(object); } @@ -1754,76 +1765,70 @@ vm_object_collapse(vm_object_t object) * vm_object_page_remove: * * For the given object, either frees or invalidates each of the - * specified pages. In general, a page is freed. However, if a - * page is wired for any reason other than the existence of a - * managed, wired mapping, then it may be invalidated but not - * removed from the object. Pages are specified by the given - * range ["start", "end") and Boolean "clean_only". As a - * special case, if "end" is zero, then the range extends from - * "start" to the end of the object. If "clean_only" is TRUE, - * then only the non-dirty pages within the specified range are - * affected. + * specified pages. In general, a page is freed. However, if a page is + * wired for any reason other than the existence of a managed, wired + * mapping, then it may be invalidated but not removed from the object. + * Pages are specified by the given range ["start", "end") and the option + * OBJPR_CLEANONLY. As a special case, if "end" is zero, then the range + * extends from "start" to the end of the object. If the option + * OBJPR_CLEANONLY is specified, then only the non-dirty pages within the + * specified range are affected. If the option OBJPR_NOTMAPPED is + * specified, then the pages within the specified range must have no + * mappings. Otherwise, if this option is not specified, any mappings to + * the specified pages are removed before the pages are freed or + * invalidated. * - * In general, this operation should only be performed on objects - * that contain managed pages. There are two exceptions. First, - * it may be performed on the kernel and kmem objects. Second, - * it may be used by msync(..., MS_INVALIDATE) to invalidate - * device-backed pages. In both of these cases, "clean_only" - * must be FALSE. + * In general, this operation should only be performed on objects that + * contain managed pages. There are, however, two exceptions. First, it + * is performed on the kernel and kmem objects by vm_map_entry_delete(). + * Second, it is used by msync(..., MS_INVALIDATE) to invalidate device- + * backed pages. In both of these cases, the option OBJPR_CLEANONLY must + * not be specified and the option OBJPR_NOTMAPPED must be specified. * * The object must be locked. */ void vm_object_page_remove(vm_object_t object, vm_pindex_t start, vm_pindex_t end, - boolean_t clean_only) + int options) { vm_page_t p, next; int wirings; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); + KASSERT((object->type != OBJT_DEVICE && object->type != OBJT_PHYS) || + (options & (OBJPR_CLEANONLY | OBJPR_NOTMAPPED)) == OBJPR_NOTMAPPED, + ("vm_object_page_remove: illegal options for object %p", object)); if (object->resident_page_count == 0) goto skipmemq; - - /* - * Since physically-backed objects do not use managed pages, we can't - * remove pages from the object (we must instead remove the page - * references, and then destroy the object). - */ - KASSERT(object->type != OBJT_PHYS || object == kernel_object || - object == kmem_object, - ("attempt to remove pages from a physical object")); - vm_object_pip_add(object, 1); again: p = vm_page_find_least(object, start); /* - * Assert: the variable p is either (1) the page with the - * least pindex greater than or equal to the parameter pindex - * or (2) NULL. + * Here, the variable "p" is either (1) the page with the least pindex + * greater than or equal to the parameter "start" or (2) NULL. */ - for (; - p != NULL && (p->pindex < end || end == 0); - p = next) { + for (; p != NULL && (p->pindex < end || end == 0); p = next) { next = TAILQ_NEXT(p, listq); /* - * If the page is wired for any reason besides the - * existence of managed, wired mappings, then it cannot - * be freed. For example, fictitious pages, which - * represent device memory, are inherently wired and - * cannot be freed. They can, however, be invalidated - * if "clean_only" is FALSE. + * If the page is wired for any reason besides the existence + * of managed, wired mappings, then it cannot be freed. For + * example, fictitious pages, which represent device memory, + * are inherently wired and cannot be freed. They can, + * however, be invalidated if the option OBJPR_CLEANONLY is + * not specified. */ vm_page_lock(p); if ((wirings = p->wire_count) != 0 && (wirings = pmap_page_wired_mappings(p)) != p->wire_count) { - /* Fictitious pages do not have managed mappings. */ - if ((p->flags & PG_FICTITIOUS) == 0) + if ((options & OBJPR_NOTMAPPED) == 0) { pmap_remove_all(p); - /* Account for removal of managed, wired mappings. */ - p->wire_count -= wirings; - if (!clean_only) { + /* Account for removal of wired mappings. */ + if (wirings != 0) + p->wire_count -= wirings; + } + if ((options & OBJPR_CLEANONLY) == 0) { p->valid = 0; vm_page_undirty(p); } @@ -1834,17 +1839,20 @@ again: goto again; KASSERT((p->flags & PG_FICTITIOUS) == 0, ("vm_object_page_remove: page %p is fictitious", p)); - if (clean_only && p->valid) { - pmap_remove_write(p); + if ((options & OBJPR_CLEANONLY) != 0 && p->valid != 0) { + if ((options & OBJPR_NOTMAPPED) == 0) + pmap_remove_write(p); if (p->dirty) { vm_page_unlock(p); continue; } } - pmap_remove_all(p); - /* Account for removal of managed, wired mappings. */ - if (wirings != 0) - p->wire_count -= wirings; + if ((options & OBJPR_NOTMAPPED) == 0) { + pmap_remove_all(p); + /* Account for removal of wired mappings. */ + if (wirings != 0) + p->wire_count -= wirings; + } vm_page_free(p); vm_page_unlock(p); } @@ -1991,9 +1999,8 @@ vm_object_coalesce(vm_object_t prev_object, vm_ooffset_t prev_offset, * deallocation. */ if (next_pindex < prev_object->size) { - vm_object_page_remove(prev_object, - next_pindex, - next_pindex + next_size, FALSE); + vm_object_page_remove(prev_object, next_pindex, next_pindex + + next_size, 0); if (prev_object->type == OBJT_SWAP) swap_pager_freespace(prev_object, next_pindex, next_size); diff --git a/sys/vm/vm_object.h b/sys/vm/vm_object.h index 0f4f47d..a11f144 100644 --- a/sys/vm/vm_object.h +++ b/sys/vm/vm_object.h @@ -168,6 +168,12 @@ struct vm_object { #define OBJPC_INVAL 0x2 /* invalidate */ #define OBJPC_NOSYNC 0x4 /* skip if PG_NOSYNC */ +/* + * The following options are supported by vm_object_page_remove(). + */ +#define OBJPR_CLEANONLY 0x1 /* Don't remove dirty pages. */ +#define OBJPR_NOTMAPPED 0x2 /* Don't unmap pages. */ + TAILQ_HEAD(object_q, vm_object); extern struct object_q vm_object_list; /* list of allocated objects */ @@ -219,7 +225,8 @@ void vm_object_set_writeable_dirty (vm_object_t); void vm_object_init (void); void vm_object_page_clean(vm_object_t object, vm_ooffset_t start, vm_ooffset_t end, int flags); -void vm_object_page_remove (vm_object_t, vm_pindex_t, vm_pindex_t, boolean_t); +void vm_object_page_remove(vm_object_t object, vm_pindex_t start, + vm_pindex_t end, int options); boolean_t vm_object_populate(vm_object_t, vm_pindex_t, vm_pindex_t); void vm_object_print(long addr, boolean_t have_addr, long count, char *modif); void vm_object_reference (vm_object_t); diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index 033c4c9..8e0c8bb 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -2336,8 +2336,7 @@ vm_page_clear_dirty_mask(vm_page_t m, int pagebits) if ((m->oflags & VPO_BUSY) == 0 && (m->flags & PG_WRITEABLE) == 0) m->dirty &= ~pagebits; else { -#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) || \ - defined(__mips__) +#if defined(__amd64__) || defined(__i386__) || defined(__ia64__) /* * On the aforementioned architectures, the page queues lock * is not required by the following read-modify-write diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index a8eca20..23ade63 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -387,7 +387,7 @@ vnode_pager_setsize(vp, nsize) */ if (nobjsize < object->size) vm_object_page_remove(object, nobjsize, object->size, - FALSE); + 0); /* * this gets rid of garbage at the end of a page that is now * only partially backed by the vnode. diff --git a/sys/x86/include/pci_cfgreg.h b/sys/x86/include/pci_cfgreg.h new file mode 100644 index 0000000..ea5e319 --- /dev/null +++ b/sys/x86/include/pci_cfgreg.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1997, Stefan Esser <se@freebsd.org> + * 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 unmodified, 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. + * + * $FreeBSD$ + * + */ + +#ifndef __X86_PCI_CFGREG_H__ +#define __X86_PCI_CFGREG_H__ + +#define CONF1_ADDR_PORT 0x0cf8 +#define CONF1_DATA_PORT 0x0cfc + +#define CONF1_ENABLE 0x80000000ul +#define CONF1_ENABLE_CHK 0x80000000ul +#define CONF1_ENABLE_MSK 0x7f000000ul +#define CONF1_ENABLE_CHK1 0xff000001ul +#define CONF1_ENABLE_MSK1 0x80000001ul +#define CONF1_ENABLE_RES1 0x80000000ul + +#define CONF2_ENABLE_PORT 0x0cf8 +#define CONF2_FORWARD_PORT 0x0cfa + +#define CONF2_ENABLE_CHK 0x0e +#define CONF2_ENABLE_RES 0x0e + +u_long hostb_alloc_start(int type, u_long start, u_long end, u_long count); +int pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus); +int pci_cfgregopen(void); +u_int32_t pci_cfgregread(int bus, int slot, int func, int reg, int bytes); +void pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes); +#ifdef __HAVE_PIR +void pci_pir_open(void); +int pci_pir_probe(int bus, int require_parse); +int pci_pir_route_interrupt(int bus, int device, int func, int pin); +#endif + +#endif /* !__X86_PCI_CFGREG_H__ */ diff --git a/sys/i386/pci/pci_bus.c b/sys/x86/pci/pci_bus.c index 61dab3f..0efac6e 100644 --- a/sys/i386/pci/pci_bus.c +++ b/sys/x86/pci/pci_bus.c @@ -51,9 +51,6 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" -static int pcibios_pcib_route_interrupt(device_t pcib, device_t dev, - int pin); - int legacy_pcib_maxslots(device_t dev) { @@ -62,7 +59,7 @@ legacy_pcib_maxslots(device_t dev) /* read configuration space register */ -u_int32_t +uint32_t legacy_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { @@ -73,11 +70,26 @@ legacy_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func, void legacy_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func, - u_int reg, u_int32_t data, int bytes) + u_int reg, uint32_t data, int bytes) { pci_cfgregwrite(bus, slot, func, reg, data, bytes); } +/* route interrupt */ + +static int +legacy_pcib_route_interrupt(device_t pcib, device_t dev, int pin) +{ + +#ifdef __HAVE_PIR + return (pci_pir_route_interrupt(pci_get_bus(dev), pci_get_slot(dev), + pci_get_function(dev), pin)); +#else + /* No routing possible */ + return (PCI_INVALID_IRQ); +#endif +} + /* Pass MSI requests up to the nexus. */ static int @@ -115,6 +127,7 @@ legacy_pcib_is_host_bridge(int bus, int slot, int func, uint32_t id, uint8_t class, uint8_t subclass, uint8_t *busnum) { +#ifdef __i386__ const char *s = NULL; static uint8_t pxb[4]; /* hack for 450nx */ @@ -332,6 +345,14 @@ legacy_pcib_is_host_bridge(int bus, int slot, int func, } return s; +#else + const char *s = NULL; + + *busnum = 0; + if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) + s = "Host to PCI bridge"; + return s; +#endif } /* @@ -342,7 +363,7 @@ static void legacy_pcib_identify(driver_t *driver, device_t parent) { int bus, slot, func; - u_int8_t hdrtype; + uint8_t hdrtype; int found = 0; int pcifunchigh; int found824xx = 0; @@ -385,8 +406,8 @@ legacy_pcib_identify(driver_t *driver, device_t parent) /* * Read the IDs and class from the device. */ - u_int32_t id; - u_int8_t class, subclass, busnum; + uint32_t id; + uint8_t class, subclass, busnum; const char *s; device_t *devs; int ndevs, i; @@ -471,19 +492,23 @@ legacy_pcib_probe(device_t dev) static int legacy_pcib_attach(device_t dev) { +#ifdef __HAVE_PIR device_t pir; +#endif int bus; + bus = pcib_get_bus(dev); +#ifdef __HAVE_PIR /* * Look for a PCI BIOS interrupt routing table as that will be * our method of routing interrupts if we have one. */ - bus = pcib_get_bus(dev); if (pci_pir_probe(bus, 0)) { pir = BUS_ADD_CHILD(device_get_parent(dev), 0, "pir", 0); if (pir != NULL) device_probe_and_attach(pir); } +#endif device_add_child(dev, "pci", bus); return bus_generic_attach(dev); } @@ -519,35 +544,45 @@ legacy_pcib_write_ivar(device_t dev, device_t child, int which, return ENOENT; } +/* + * Helper routine for x86 Host-PCI bridge driver resource allocation. + * This is used to adjust the start address of wildcard allocation + * requests to avoid low addresses that are known to be problematic. + * + * If no memory preference is given, use upper 32MB slot most BIOSes + * use for their memory window. This is typically only used on older + * laptops that don't have PCI busses behind a PCI bridge, so assuming + * > 32MB is likely OK. + * + * However, this can cause problems for other chipsets, so we make + * this tunable by hw.pci.host_mem_start. + */ SYSCTL_DECL(_hw_pci); -static unsigned long legacy_host_mem_start = 0x80000000; -TUNABLE_ULONG("hw.pci.host_mem_start", &legacy_host_mem_start); -SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RDTUN, - &legacy_host_mem_start, 0x80000000, - "Limit the host bridge memory to being above this address. Must be\n\ -set at boot via a tunable."); +static unsigned long host_mem_start = 0x80000000; +TUNABLE_ULONG("hw.pci.host_mem_start", &host_mem_start); +SYSCTL_ULONG(_hw_pci, OID_AUTO, host_mem_start, CTLFLAG_RDTUN, &host_mem_start, + 0, "Limit the host bridge memory to being above this address."); + +u_long +hostb_alloc_start(int type, u_long start, u_long end, u_long count) +{ + + if (start + count - 1 != end) { + if (type == SYS_RES_MEMORY && start < host_mem_start) + start = host_mem_start; + if (type == SYS_RES_IOPORT && start < 0x1000) + start = 0x1000; + } + return (start); +} struct resource * legacy_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { - /* - * If no memory preference is given, use upper 32MB slot most - * bioses use for their memory window. Typically other bridges - * before us get in the way to assert their preferences on memory. - * Hardcoding like this sucks, so a more MD/MI way needs to be - * found to do it. This is typically only used on older laptops - * that don't have pci busses behind pci bridge, so assuming > 32MB - * is liekly OK. - * - * However, this can cause problems for other chipsets, so we make - * this tunable by hw.pci.host_mem_start. - */ - if (type == SYS_RES_MEMORY && start == 0UL && end == ~0UL) - start = legacy_host_mem_start; - if (type == SYS_RES_IOPORT && start == 0UL && end == ~0UL) - start = 0x1000; + + start = hostb_alloc_start(type, start, end, count); return (bus_generic_alloc_resource(dev, child, type, rid, start, end, count, flags)); } @@ -577,7 +612,7 @@ static device_method_t legacy_pcib_methods[] = { DEVMETHOD(pcib_maxslots, legacy_pcib_maxslots), DEVMETHOD(pcib_read_config, legacy_pcib_read_config), DEVMETHOD(pcib_write_config, legacy_pcib_write_config), - DEVMETHOD(pcib_route_interrupt, pcibios_pcib_route_interrupt), + DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), DEVMETHOD(pcib_release_msi, pcib_release_msi), DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), @@ -641,7 +676,7 @@ static devclass_t pcibus_pnp_devclass; DEFINE_CLASS_0(pcibus_pnp, pcibus_pnp_driver, pcibus_pnp_methods, 1); DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0); - +#ifdef __HAVE_PIR /* * Provide a PCI-PCI bridge driver for PCI busses behind PCI-PCI bridges * that appear in the PCIBIOS Interrupt Routing Table to use the routing @@ -654,7 +689,7 @@ static device_method_t pcibios_pcib_pci_methods[] = { DEVMETHOD(device_probe, pcibios_pcib_probe), /* pcib interface */ - DEVMETHOD(pcib_route_interrupt, pcibios_pcib_route_interrupt), + DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt), {0, 0} }; @@ -681,10 +716,4 @@ pcibios_pcib_probe(device_t dev) device_set_desc(dev, "PCIBIOS PCI-PCI bridge"); return (-2000); } - -static int -pcibios_pcib_route_interrupt(device_t pcib, device_t dev, int pin) -{ - return (pci_pir_route_interrupt(pci_get_bus(dev), pci_get_slot(dev), - pci_get_function(dev), pin)); -} +#endif diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c index 9501eee..5f17f62 100644 --- a/sys/x86/x86/tsc.c +++ b/sys/x86/x86/tsc.c @@ -444,6 +444,19 @@ init_TSC_tc(void) goto init; } + /* + * We cannot use the TSC if it stops incrementing in deep sleep. + * Currently only Intel CPUs are known for this problem unless + * the invariant TSC bit is set. + */ + if (cpu_can_deep_sleep && cpu_vendor_id == CPU_VENDOR_INTEL && + (amd_pminfo & AMDPM_TSC_INVARIANT) == 0) { + tsc_timecounter.tc_quality = -1000; + if (bootverbose) + printf("TSC timecounter disabled: C3 enabled.\n"); + goto init; + } + #ifdef SMP /* * We can not use the TSC in SMP mode unless the TSCs on all CPUs are diff --git a/tools/regression/bin/sh/builtins/case10.0 b/tools/regression/bin/sh/builtins/case10.0 new file mode 100644 index 0000000..a627b5c --- /dev/null +++ b/tools/regression/bin/sh/builtins/case10.0 @@ -0,0 +1,16 @@ +# $FreeBSD$ + +case ! in +[\!!]) ;; +*) echo Failed at $LINENO ;; +esac + +case ! in +['!'!]) ;; +*) echo Failed at $LINENO ;; +esac + +case ! in +["!"!]) ;; +*) echo Failed at $LINENO ;; +esac diff --git a/tools/tools/bus_autoconf/Makefile b/tools/tools/bus_autoconf/Makefile new file mode 100644 index 0000000..c7104de --- /dev/null +++ b/tools/tools/bus_autoconf/Makefile @@ -0,0 +1,46 @@ +# $FreeBSD$ +# +# Copyright (c) 2011 Hans Petter Selasky. 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. +# + +# +# Example on how to use: +# +# make clean all install +# +# ./bus_autoconf.sh /boot/kernel/*.ko | less +# + +PROG= bus_autoconf +MAN= +BINDIR?= /usr/local/bin + +SRCS+= bus_autoconf.c +SRCS+= bus_load_file.c +SRCS+= bus_sections.c +SRCS+= bus_usb.c + +WARNS= 6 + +.include <bsd.prog.mk> diff --git a/tools/tools/bus_autoconf/bus_autoconf.c b/tools/tools/bus_autoconf/bus_autoconf.c new file mode 100644 index 0000000..adbf6e4 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_autoconf.c @@ -0,0 +1,125 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. 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. + */ + +/* + * Disclaimer: This utility and format is subject to change and not a + * comitted interface. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> + +#include "bus_autoconf.h" +#include "bus_sections.h" +#include "bus_load_file.h" +#include "bus_usb.h" + +static void +usage(void) +{ + fprintf(stderr, + "bus_autoconf - devd config file generator\n" + " -i <structure_type,module.ko>\n" + " -F <format_file>\n" + " -h show usage\n" + ); + exit(EX_USAGE); +} + +int +main(int argc, char **argv) +{ + const char *params = "i:F:h"; + char *fname; + char *section; + char *module; + char *postfix; + uint8_t *ptr; + uint32_t len; + int c; + int any_opt = 0; + + while ((c = getopt(argc, argv, params)) != -1) { + switch (c) { + case 'i': + fname = optarg; + load_file(fname, &ptr, &len); + + module = strchr(fname, ','); + if (module == NULL) { + errx(EX_USAGE, "Invalid input " + "file name '%s'", fname); + } + /* split module and section */ + *module++ = 0; + + /* remove postfix */ + postfix = strchr(module, '.'); + if (postfix) + *postfix = 0; + + /* get section name */ + section = fname; + + /* check section type */ + if (strncmp(section, "usb_", 4) == 0) + usb_import_entries(section, module, ptr, len); + else + errx(EX_USAGE, "Invalid section '%s'", section); + + free(ptr); + + any_opt = 1; + break; + + case 'F': + fname = optarg; + load_file(fname, &ptr, &len); + format_parse_entries(ptr, len); + free(ptr); + + any_opt = 1; + break; + + default: + usage(); + break; + } + } + + if (any_opt == 0) + usage(); + + usb_dump_entries(); + + return (0); +} diff --git a/tools/tools/bus_autoconf/bus_autoconf.h b/tools/tools/bus_autoconf/bus_autoconf.h new file mode 100644 index 0000000..0a1ca3f --- /dev/null +++ b/tools/tools/bus_autoconf/bus_autoconf.h @@ -0,0 +1,31 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_AUTOCONF_H_ +#define _BUS_AUTOCONF_H_ + +#endif /* _BUS_AUTOCONF_H_ */ diff --git a/tools/tools/bus_autoconf/bus_autoconf.sh b/tools/tools/bus_autoconf/bus_autoconf.sh new file mode 100644 index 0000000..c99df91 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_autoconf.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# $FreeBSD$ +# +# Copyright (c) 2011 Hans Petter Selasky. 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. +# + +OS=FreeBSD +DOLLAR=$ +OBJCOPY=objcopy + +cat <<EOF +# +# ${DOLLAR}${OS}${DOLLAR} +# +# This file was automatically generated by "tools/bus_autoconf.sh". +# Please do not edit! +# + +EOF + +rm -f bus_autoconf_format.bin +rm -f bus_autoconf_args.txt +rm -f bus_autoconf.ids + +for F in $* +do + +G=$(basename ${F}) + +# Format information +${OBJCOPY} -j bus_autoconf_format -O binary ${F} bus_autoconf.ids 2> /dev/null +[ -f bus_autoconf.ids ] && cat bus_autoconf.ids >> bus_autoconf_format.bin + +# USB Host mode +${OBJCOPY} -j usb_host_id -O binary ${F} "usb_host_id,${G}" 2> /dev/null +[ -f "usb_host_id,${G}" ] && (echo -n " -i usb_host_id,${G}" >> bus_autoconf_args.txt) + +# USB Device mode +${OBJCOPY} -j usb_device_id -O binary ${F} "usb_device_id,${G}" 2> /dev/null +[ -f "usb_device_id,${G}" ] && (echo -n " -i usb_device_id,${G}" >> bus_autoconf_args.txt) + +# USB Dual mode +${OBJCOPY} -j usb_dual_id -O binary ${F} "usb_dual_id,${G}" 2> /dev/null +[ -f "usb_dual_id,${G}" ] && (echo -n " -i usb_dual_id,${G}" >> bus_autoconf_args.txt) + +done + +# Dump all data +bus_autoconf -F bus_autoconf_format.bin $(cat bus_autoconf_args.txt) + +# Cleanup +rm -f -- \ + $(cat bus_autoconf_args.txt) \ + bus_autoconf_args.txt \ + bus_autoconf_format.bin \ + bus_autoconf.ids diff --git a/tools/tools/bus_autoconf/bus_autoconf_format_example.txt b/tools/tools/bus_autoconf/bus_autoconf_format_example.txt new file mode 100644 index 0000000..e118f1f --- /dev/null +++ b/tools/tools/bus_autoconf/bus_autoconf_format_example.txt @@ -0,0 +1,111 @@ +/* $FreeBSD$ */ + +#if BYTE_ORDER == BIG_ENDIAN +#define U16_XOR "8" +#define U32_XOR "12" +#define U64_XOR "56" +#define U8_BITFIELD_XOR "7" +#define U16_BITFIELD_XOR "15" +#define U32_BITFIELD_XOR "31" +#define U64_BITFIELD_XOR "63" +#else +#define U16_XOR "0" +#define U32_XOR "0" +#define U64_XOR "0" +#define U8_BITFIELD_XOR "0" +#define U16_BITFIELD_XOR "0" +#define U32_BITFIELD_XOR "0" +#define U64_BITFIELD_XOR "0" +#endif + +#if USB_HAVE_COMPAT_LINUX +#define MFL_SIZE "1" +#else +#define MFL_SIZE "0" +#endif + +static const char __section("bus_autoconf_format") __used usb_id_format[] = { + + /* + * Declare three different sections that use the same format. + * All sizes are in bits. Fields cannot be greater than + * 8 bits in size. Bitfields having a size greater than 1 + * must fit within the byte in which the bitfield is defined. + */ + + "usb_host_id{256,:}" + "usb_device_id{256,:}" + "usb_dual_id{256,:}" + + /* + * Describe all fields in the usb_device_id structure + * which is found in sys/dev/usb/usbdi.h. + */ + +#if BITS_PER_LONG == 32 || BITS_PER_LONG == 64 + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#if BITS_PER_LONG == 64 + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#endif +#else +#error "Please update code." +#endif + + "idVendor[0]{" U16_XOR ",8}" + "idVendor[1]{" U16_XOR ",8}" + "idProduct[0]{" U16_XOR ",8}" + "idProduct[1]{" U16_XOR ",8}" + "bcdDevice_lo[0]{" U16_XOR ",8}" + "bcdDevice_lo[1]{" U16_XOR ",8}" + "bcdDevice_hi[0]{" U16_XOR ",8}" + "bcdDevice_hi[1]{" U16_XOR ",8}" + + "bDeviceClass{0,8}" + "bDeviceSubClass{0,8}" + "bDeviceProtocol{0,8}" + "bInterfaceClass{0,8}" + "bInterfaceSubClass{0,8}" + "bInterfaceProtocol{0,8}" + +/* NOTE: On big endian machines bitfields are bitreversed. */ + + "mf_vendor{" U8_BITFIELD_XOR ",1}" + "mf_product{" U8_BITFIELD_XOR ",1}" + "mf_dev_lo{" U8_BITFIELD_XOR ",1}" + "mf_dev_hi{" U8_BITFIELD_XOR ",1}" + + "mf_dev_class{" U8_BITFIELD_XOR ",1}" + "mf_dev_subclass{" U8_BITFIELD_XOR ",1}" + "mf_dev_protocol{" U8_BITFIELD_XOR ",1}" + "mf_int_class{" U8_BITFIELD_XOR ",1}" + + "mf_int_subclass{" U8_BITFIELD_XOR ",1}" + "mf_int_protocol{" U8_BITFIELD_XOR ",1}" + "unused{" U8_BITFIELD_XOR ",6}" + + "mfl_vendor{" U16_XOR "," MFL_SIZE "}" + "mfl_product{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}" + + "mfl_dev_class{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}" + "mfl_int_class{" U16_XOR "," MFL_SIZE "}" + + "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" +}; diff --git a/tools/tools/bus_autoconf/bus_load_file.c b/tools/tools/bus_autoconf/bus_load_file.c new file mode 100644 index 0000000..527e5bc --- /dev/null +++ b/tools/tools/bus_autoconf/bus_load_file.c @@ -0,0 +1,76 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <fcntl.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> + +#include "bus_load_file.h" + +void +load_file(const char *fname, uint8_t **pptr, uint32_t *plen) +{ + uint8_t *ptr; + uint32_t len; + off_t off; + int f; + + f = open(fname, O_RDONLY); + if (f < 0) + err(EX_NOINPUT, "Cannot open file '%s'", fname); + + off = lseek(f, 0, SEEK_END); + if (off < 0) { + err(EX_NOINPUT, "Cannot seek to " + "end of file '%s'", fname); + } + + if (lseek(f, 0, SEEK_SET) < 0) { + err(EX_NOINPUT, "Cannot seek to " + "beginning of file '%s'", fname); + } + + len = off; + if (len != off) + err(EX_NOINPUT, "File '%s' is too big", fname); + + ptr = malloc(len); + if (ptr == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + if (read(f, ptr, len) != len) + err(EX_NOINPUT, "Cannot read all data"); + + close(f); + + *pptr = ptr; + *plen = len; +} diff --git a/tools/tools/bus_autoconf/bus_load_file.h b/tools/tools/bus_autoconf/bus_load_file.h new file mode 100644 index 0000000..57e7739 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_load_file.h @@ -0,0 +1,33 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_LOAD_FILE_H_ +#define _BUS_LOAD_FILE_H_ + +void load_file(const char *, uint8_t **, uint32_t *); + +#endif /* _BUS_LOAD_FILE_H_ */ diff --git a/tools/tools/bus_autoconf/bus_sections.c b/tools/tools/bus_autoconf/bus_sections.c new file mode 100644 index 0000000..c326048 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_sections.c @@ -0,0 +1,223 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <sysexits.h> +#include <err.h> +#include <string.h> + +#include <sys/queue.h> + +#include "bus_sections.h" + +#define MAX_STRING 64 + +struct format_info; +typedef TAILQ_HEAD(,format_info) format_info_head_t; +typedef TAILQ_ENTRY(format_info) format_info_entry_t; + +static format_info_head_t format_head = TAILQ_HEAD_INITIALIZER(format_head); + +struct format_info { + format_info_entry_t entry; + format_info_head_t fields; + char name[MAX_STRING]; + uint16_t bit_offset; + uint16_t bit_size; +}; + +static struct format_info * +format_info_new(char *pstr, uint16_t bo, uint16_t bs) +{ + struct format_info *pfi; + + pfi = malloc(sizeof(*pfi)); + if (pfi == NULL) + errx(EX_SOFTWARE, "Out of memory."); + + memset(pfi, 0, sizeof(*pfi)); + + TAILQ_INIT(&pfi->fields); + + strlcpy(pfi->name, pstr, sizeof(pfi->name)); + pfi->bit_offset = bo; + pfi->bit_size = bs; + return (pfi); +} + +static const struct format_info * +format_get_section(const char *section) +{ + const struct format_info *psub; + static const struct format_info *psub_last; + static const char *psub_cache; + + if (psub_cache && strcmp(psub_cache, section) == 0) + return (psub_last); + + TAILQ_FOREACH(psub, &format_head, entry) { + if (strcmp(section, psub->name) == 0) { + psub_cache = section; + psub_last = psub; + return (psub); + } + } + warnx("Section '%s' not found", section); + psub_cache = section; + psub_last = psub; + return (NULL); +} + +uint16_t +format_get_section_size(const char *section) +{ + const struct format_info *pfi; + + pfi = format_get_section(section); + if (pfi == NULL) + return (0); + + return ((pfi->bit_offset + 7) / 8); +} + + +uint8_t +format_get_field(const char *section, const char *field, + const uint8_t *ptr, uint16_t size) +{ + const struct format_info *pfi; + const struct format_info *psub; + uint16_t rem; + uint16_t off; + uint16_t sz; + + pfi = format_get_section(section); + if (pfi == NULL) + return (0); + + /* skip until we find the fields */ + while (pfi && TAILQ_FIRST(&pfi->fields) == NULL) + pfi = TAILQ_NEXT(pfi, entry); + + if (pfi == NULL) + return (0); + + TAILQ_FOREACH(psub, &pfi->fields, entry) { + if (strcmp(field, psub->name) == 0) { + + /* range check */ + if (((psub->bit_offset + psub->bit_size) / 8) > size) + return (0); + + /* compute byte offset */ + rem = psub->bit_offset & 7; + off = psub->bit_offset / 8; + sz = psub->bit_size; + + /* extract bit-field */ + return ((ptr[off] >> rem) & ((1 << sz) - 1)); + } + } + warnx("Field '%s' not found in '%s'", field, pfi->name); + return (0); +} + +void +format_parse_entries(const uint8_t *ptr, uint32_t len) +{ + static const char *command_list = "012345678:"; + const char *cmd; + struct format_info *pfi; + struct format_info *pfi_last = NULL; + char linebuf[3][MAX_STRING]; + uint32_t off = 0; + uint16_t bit_offset = 0; + uint8_t state = 0; + uint8_t cmd_index; + int c; + + /* + * The format we are parsing: + * <string>{string,string}<next_string>{...} + */ + while (len--) { + c = *(ptr++); + + /* skip some characters */ + if (c == 0 || c == '\n' || c == '\r' || c == ' ' || c == '\t') + continue; + + /* accumulate non-field delimiters */ + if (strchr("{,}", c) == NULL) { + if (off < (MAX_STRING - 1)) { + linebuf[state][off] = c; + off++; + } + continue; + } + /* parse keyword */ + linebuf[state][off] = 0; + off = 0; + state++; + if (state == 3) { + /* check for command in command list */ + cmd = strchr(command_list, linebuf[2][0]); + if (cmd != NULL) + cmd_index = cmd - command_list; + else + cmd_index = 255; + + /* + * Check for new field, format is: + * + * <field_name>{bit_offset_xor, bit_size} + */ + if (cmd_index < 9 && pfi_last != NULL) { + pfi = format_info_new(linebuf[0], bit_offset ^ + atoi(linebuf[1]), cmd_index); + TAILQ_INSERT_TAIL(&pfi_last->fields, pfi, entry); + bit_offset += cmd_index; + } + /* + * Check for new section, format is: + * + * <section_name>{section_bit_size, :} + */ + if (cmd_index == 9) { + pfi_last = format_info_new(linebuf[0], + atoi(linebuf[1]), cmd_index); + TAILQ_INSERT_TAIL(&format_head, pfi_last, entry); + bit_offset = 0; + } + state = 0; + continue; + } + } +} diff --git a/tools/tools/bus_autoconf/bus_sections.h b/tools/tools/bus_autoconf/bus_sections.h new file mode 100644 index 0000000..2c4c6fc --- /dev/null +++ b/tools/tools/bus_autoconf/bus_sections.h @@ -0,0 +1,35 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_SECTIONS_H_ +#define _BUS_SECTIONS_H_ + +uint16_t format_get_section_size(const char *); +uint8_t format_get_field(const char *, const char *, const uint8_t *, uint16_t); +void format_parse_entries(const uint8_t *, uint32_t); + +#endif /* _BUS_SECTIONS_H_ */ diff --git a/tools/tools/bus_autoconf/bus_usb.c b/tools/tools/bus_autoconf/bus_usb.c new file mode 100644 index 0000000..ab794c1 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_usb.c @@ -0,0 +1,386 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> +#include <sys/queue.h> + +#include "bus_autoconf.h" +#include "bus_sections.h" +#include "bus_usb.h" + +struct usb_blob; +typedef TAILQ_HEAD(,usb_blob) usb_blob_head_t; +typedef TAILQ_ENTRY(usb_blob) usb_blob_entry_t; + +static usb_blob_head_t usb_blob_head = TAILQ_HEAD_INITIALIZER(usb_blob_head); +static uint32_t usb_blob_count; + +struct usb_blob { + usb_blob_entry_t entry; + struct usb_device_id temp; +}; + +/* + * To ensure that the correct USB driver is loaded, the driver having + * the most information about the device must be probed first. Then + * more generic drivers shall be probed. + */ +static int +usb_compare(const void *_a, const void *_b) +{ + const struct usb_device_id *a = _a; + const struct usb_device_id *b = _b; + int retval; + + /* vendor matches first */ + + if (a->match_flag_vendor > b->match_flag_vendor) + return (-1); + if (a->match_flag_vendor < b->match_flag_vendor) + return (1); + + /* product matches first */ + + if (a->match_flag_product > b->match_flag_product) + return (-1); + if (a->match_flag_product < b->match_flag_product) + return (1); + + /* device class matches first */ + + if (a->match_flag_dev_class > b->match_flag_dev_class) + return (-1); + if (a->match_flag_dev_class < b->match_flag_dev_class) + return (1); + + if (a->match_flag_dev_subclass > b->match_flag_dev_subclass) + return (-1); + if (a->match_flag_dev_subclass < b->match_flag_dev_subclass) + return (1); + + /* interface class matches first */ + + if (a->match_flag_int_class > b->match_flag_int_class) + return (-1); + if (a->match_flag_int_class < b->match_flag_int_class) + return (1); + + if (a->match_flag_int_subclass > b->match_flag_int_subclass) + return (-1); + if (a->match_flag_int_subclass < b->match_flag_int_subclass) + return (1); + + if (a->match_flag_int_protocol > b->match_flag_int_protocol) + return (-1); + if (a->match_flag_int_protocol < b->match_flag_int_protocol) + return (1); + + /* then sort according to value */ + + if (a->idVendor > b->idVendor) + return (1); + if (a->idVendor < b->idVendor) + return (-1); + if (a->idProduct > b->idProduct) + return (1); + if (a->idProduct < b->idProduct) + return (-1); + if (a->bDeviceClass > b->bDeviceClass) + return (1); + if (a->bDeviceClass < b->bDeviceClass) + return (-1); + if (a->bDeviceSubClass > b->bDeviceSubClass) + return (1); + if (a->bDeviceSubClass < b->bDeviceSubClass) + return (-1); + if (a->bDeviceProtocol > b->bDeviceProtocol) + return (1); + if (a->bDeviceProtocol < b->bDeviceProtocol) + return (-1); + if (a->bInterfaceClass > b->bInterfaceClass) + return (1); + if (a->bInterfaceClass < b->bInterfaceClass) + return (-1); + if (a->bInterfaceSubClass > b->bInterfaceSubClass) + return (1); + if (a->bInterfaceSubClass < b->bInterfaceSubClass) + return (-1); + if (a->bInterfaceProtocol > b->bInterfaceProtocol) + return (1); + if (a->bInterfaceProtocol < b->bInterfaceProtocol) + return (-1); + + /* in the end sort by module name and mode */ + + retval = strcmp(a->module_name, b->module_name); + if (retval == 0) + retval = strcmp(a->module_mode, b->module_mode); + return (retval); +} + +static void +usb_sort_entries(struct usb_device_id *id, uint32_t nid) +{ + qsort(id, nid, sizeof(*id), &usb_compare); +} + +static void +usb_import_entry(struct usb_device_id *id, const char *type, + const char *module, const uint8_t *ptr, uint16_t size) +{ + const char *mode; + + if (strstr(type, "_host_")) + mode = "host"; + else if (strstr(type, "_device_")) + mode = "device"; + else + mode = "(host|device)"; + + strlcpy(id->module_name, module, sizeof(id->module_name)); + strlcpy(id->module_mode, mode, sizeof(id->module_mode)); + + /* import data from binary object */ + + if (format_get_field(type, "mfl_vendor", ptr, size)) + id->match_flag_vendor = 1; + if (format_get_field(type, "mfl_product", ptr, size)) + id->match_flag_product = 1; + if (format_get_field(type, "mfl_dev_lo", ptr, size)) + id->match_flag_dev_lo = 1; + if (format_get_field(type, "mfl_dev_hi", ptr, size)) + id->match_flag_dev_hi = 1; + if (format_get_field(type, "mfl_dev_class", ptr, size)) + id->match_flag_dev_class = 1; + if (format_get_field(type, "mfl_dev_subclass", ptr, size)) + id->match_flag_dev_subclass = 1; + if (format_get_field(type, "mfl_dev_protocol", ptr, size)) + id->match_flag_dev_protocol = 1; + if (format_get_field(type, "mfl_int_class", ptr, size)) + id->match_flag_int_class = 1; + if (format_get_field(type, "mfl_int_subclass", ptr, size)) + id->match_flag_int_subclass = 1; + if (format_get_field(type, "mfl_int_protocol", ptr, size)) + id->match_flag_int_protocol = 1; + + id->idVendor = format_get_field(type, "idVendor[0]", ptr, size) | + (format_get_field(type, "idVendor[1]", ptr, size) << 8); + id->idProduct = format_get_field(type, "idProduct[0]", ptr, size) | + (format_get_field(type, "idProduct[1]", ptr, size) << 8); + + id->bcdDevice_lo = format_get_field(type, "bcdDevice_lo[0]", ptr, size) | + (format_get_field(type, "bcdDevice_lo[1]", ptr, size) << 8); + + id->bcdDevice_hi = format_get_field(type, "bcdDevice_hi[0]", ptr, size) | + (format_get_field(type, "bcdDevice_hi[1]", ptr, size) << 8); + + id->bDeviceClass = format_get_field(type, "bDeviceClass", ptr, size); + id->bDeviceSubClass = format_get_field(type, "bDeviceSubClass", ptr, size); + id->bDeviceProtocol = format_get_field(type, "bDeviceProtocol", ptr, size); + + id->bInterfaceClass = format_get_field(type, "bInterfaceClass", ptr, size); + id->bInterfaceSubClass = format_get_field(type, "bInterfaceSubClass", ptr, size); + id->bInterfaceProtocol = format_get_field(type, "bInterfaceProtocol", ptr, size); + + if (format_get_field(type, "mf_vendor", ptr, size)) + id->match_flag_vendor = 1; + if (format_get_field(type, "mf_product", ptr, size)) + id->match_flag_product = 1; + if (format_get_field(type, "mf_dev_lo", ptr, size)) + id->match_flag_dev_lo = 1; + if (format_get_field(type, "mf_dev_hi", ptr, size)) + id->match_flag_dev_hi = 1; + if (format_get_field(type, "mf_dev_class", ptr, size)) + id->match_flag_dev_class = 1; + if (format_get_field(type, "mf_dev_subclass", ptr, size)) + id->match_flag_dev_subclass = 1; + if (format_get_field(type, "mf_dev_protocol", ptr, size)) + id->match_flag_dev_protocol = 1; + if (format_get_field(type, "mf_int_class", ptr, size)) + id->match_flag_int_class = 1; + if (format_get_field(type, "mf_int_subclass", ptr, size)) + id->match_flag_int_subclass = 1; + if (format_get_field(type, "mf_int_protocol", ptr, size)) + id->match_flag_int_protocol = 1; + + /* compute some internal fields */ + id->is_iface = id->match_flag_int_class | + id->match_flag_int_protocol | + id->match_flag_int_subclass; + + id->is_dev = id->match_flag_dev_class | + id->match_flag_dev_subclass; + + id->is_vp = id->match_flag_vendor | + id->match_flag_product; + + id->is_any = id->is_vp + id->is_dev + id->is_iface; +} + +static uint32_t +usb_dump(struct usb_device_id *id, uint32_t nid) +{ + uint32_t n = 1; + + if (id->is_any) { + printf("nomatch 32 {\n" + " match \"bus\" \"uhub[0-9]+\";\n" + " match \"mode\" \"%s\";\n", id->module_mode); + } else { + printf("# skipped entry on module %s\n", + id->module_name); + return (n); + } + + if (id->match_flag_vendor) { + printf(" match \"vendor\" \"0x%04x\";\n", + id->idVendor); + } + if (id->match_flag_product) { + uint32_t x; + + if (id->is_any == 1 && id->is_vp == 1) { + /* try to join similar entries */ + while (n < nid) { + if (id[n].is_any != 1 || id[n].is_vp != 1) + break; + if (id[n].idVendor != id[0].idVendor) + break; + if (strcmp(id[n].module_name, id[0].module_name)) + break; + if (strcmp(id[n].module_mode, id[0].module_mode)) + break; + n++; + } + } + if (n == 1) { + printf(" match \"product\" \"0x%04x\";\n", + id->idProduct); + } else { + printf(" match \"product\" \"("); + + for (x = 0; x != n; x++) { + printf("0x%04x%s", id[x].idProduct, + (x == (n - 1)) ? "" : "|"); + } + + printf(")\";\n"); + } + } + if (id->match_flag_dev_class) { + printf(" match \"devclass\" \"0x%02x\";\n", + id->bDeviceClass); + } + if (id->match_flag_dev_subclass) { + printf(" match \"devsubclass\" \"0x%02x\";\n", + id->bDeviceSubClass); + } + if (id->match_flag_int_class) { + printf(" match \"intclass\" \"0x%02x\";\n", + id->bInterfaceClass); + } + if (id->match_flag_int_subclass) { + printf(" match \"intsubclass\" \"0x%02x\";\n", + id->bInterfaceSubClass); + } + if (id->match_flag_int_protocol) { + printf(" match \"intprotocol\" \"0x%02x\";\n", + id->bInterfaceProtocol); + } + printf(" action \"kldload %s\";\n" + "};\n\n", id->module_name); + + return (n); +} + +void +usb_import_entries(const char *section, const char *module, + const uint8_t *ptr, uint32_t len) +{ + struct usb_blob *pub; + uint32_t section_size; + uint32_t off; + + section_size = format_get_section_size(section); + if (section_size == 0) { + errx(EX_DATAERR, "Invalid or non-existing " + "section format '%s'", section); + } + if (len % section_size) { + errx(EX_DATAERR, "Length %d is not " + "divisible by %d. Section format '%s'", + len, section_size, section); + } + for (off = 0; off != len; off += section_size) { + pub = malloc(sizeof(*pub)); + if (pub == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + memset(pub, 0, sizeof(*pub)); + + usb_import_entry(&pub->temp, section, + module, ptr + off, section_size); + + TAILQ_INSERT_TAIL(&usb_blob_head, pub, entry); + + usb_blob_count++; + if (usb_blob_count == 0) + errx(EX_SOFTWARE, "Too many entries"); + } +} + +void +usb_dump_entries(void) +{ + struct usb_blob *pub; + struct usb_device_id *id; + uint32_t x; + + id = malloc(usb_blob_count * sizeof(*id)); + if (id == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + /* make linear array of all USB blobs */ + x = 0; + TAILQ_FOREACH(pub, &usb_blob_head, entry) + id[x++] = pub->temp; + + usb_sort_entries(id, usb_blob_count); + + for (x = 0; x != usb_blob_count;) + x += usb_dump(id + x, usb_blob_count - x); + + free(id); + + printf("# %d USB entries processed\n\n", usb_blob_count); +} diff --git a/tools/tools/bus_autoconf/bus_usb.h b/tools/tools/bus_autoconf/bus_usb.h new file mode 100644 index 0000000..378df9a --- /dev/null +++ b/tools/tools/bus_autoconf/bus_usb.h @@ -0,0 +1,73 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_USB_H_ +#define _BUS_USB_H_ + +struct usb_device_id { + + /* Internal fields */ + char module_name[32]; + char module_mode[32]; + uint8_t is_iface; + uint8_t is_vp; + uint8_t is_dev; + uint8_t is_any; + + /* Used for product specific matches; the BCD range is inclusive */ + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice_lo; + uint16_t bcdDevice_hi; + + /* Used for device class matches */ + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + + /* Used for interface class matches */ + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + + /* Select which fields to match against */ + uint8_t match_flag_vendor:1; + uint8_t match_flag_product:1; + uint8_t match_flag_dev_lo:1; + uint8_t match_flag_dev_hi:1; + uint8_t match_flag_dev_class:1; + uint8_t match_flag_dev_subclass:1; + uint8_t match_flag_dev_protocol:1; + uint8_t match_flag_int_class:1; + uint8_t match_flag_int_subclass:1; + uint8_t match_flag_int_protocol:1; +}; + +void usb_import_entries(const char *, const char *, const uint8_t *, uint32_t); +void usb_dump_entries(void); + +#endif /* _BUS_USB_H_ */ diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd index 957dafd..bf15da7 100644 --- a/usr.bin/calendar/calendars/calendar.freebsd +++ b/usr.bin/calendar/calendars/calendar.freebsd @@ -289,7 +289,7 @@ 10/18 Sheldon Hearn <sheldonh@FreeBSD.org> born in Cape Town, Western Cape, South Africa, 1974 10/19 Nicholas Souchu <nsouch@FreeBSD.org> born in Suresnes, Hauts-de-Seine, France, 1972 10/19 Nick Barkas <snb@FreeBSD.org> born in Longview, Washington, United States, 1981 -10/20 Joel Dahl <joel@FreeBSD.org> born in Lidkoping, Sweden, 1983 +10/20 Joel Dahl <joel@FreeBSD.org> born in Bitterna, Skaraborg, Sweden, 1983 10/20 Dmitry Marakasov <amdmi3@FreeBSD.org> born in Moscow, Russian Federation, 1984 10/21 Ben Smithurst <ben@FreeBSD.org> born in Sheffield, South Yorkshire, United Kingdom, 1981 10/22 Jean-Sebastien Pedron <dumbbell@FreeBSD.org> born in Redon, Ille-et-Vilaine, France, 1980 diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all index b2de01e..25b7b59 100644 --- a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all +++ b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all @@ -10,7 +10,6 @@ #include <ru_RU.KOI8-R/calendar.common> #include <ru_RU.KOI8-R/calendar.holiday> #include <ru_RU.KOI8-R/calendar.military> -#include <ru_RU.KOI8-R/calendar.msk> #include <ru_RU.KOI8-R/calendar.orthodox> #include <ru_RU.KOI8-R/calendar.pagan> diff --git a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk b/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk deleted file mode 100644 index 5e27985..0000000 --- a/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Перевод часов для московской временной зоны - * - * $FreeBSD$ - */ - -#ifndef _ru_RU_KOI8_R_msk_ -#define _ru_RU_KOI8_R_msk_ - -LANG=ru_RU.KOI8-R - -03/SunLast Начало московского летнего времени; часы переводятся вперед -10/SunLast Конец московского летнего времени; часы переводятся назад - -#endif /* !_ru_RU_KOI8_R_msk_ */ - diff --git a/usr.bin/cmp/regular.c b/usr.bin/cmp/regular.c index e88b2c0..7ed83c1 100644 --- a/usr.bin/cmp/regular.c +++ b/usr.bin/cmp/regular.c @@ -41,12 +41,10 @@ __FBSDID("$FreeBSD$"); #include <sys/stat.h> #include <err.h> -#include <errno.h> #include <limits.h> #include <signal.h> #include <stdlib.h> #include <stdio.h> -#include <string.h> #include <unistd.h> #include "extern.h" diff --git a/usr.bin/cmp/special.c b/usr.bin/cmp/special.c index 08fc887..8225185 100644 --- a/usr.bin/cmp/special.c +++ b/usr.bin/cmp/special.c @@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$"); #include <err.h> #include <stdlib.h> #include <stdio.h> -#include <string.h> #include "extern.h" diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c index ca98674..2b18b0f 100644 --- a/usr.bin/finger/net.c +++ b/usr.bin/finger/net.c @@ -226,7 +226,7 @@ trying(const struct addrinfo *ai) printf("Trying %s...\n", buf); } -void +static void cleanup(int sig __unused) { #define ERRSTR "Timed out.\n" diff --git a/usr.bin/ktrace/ktrace.c b/usr.bin/ktrace/ktrace.c index fa2fa1a..4490849 100644 --- a/usr.bin/ktrace/ktrace.c +++ b/usr.bin/ktrace/ktrace.c @@ -51,7 +51,6 @@ __FBSDID("$FreeBSD$"); #include <sys/ktrace.h> #include <err.h> -#include <stdlib.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c index 8852081..e140c70 100644 --- a/usr.bin/lastcomm/lastcomm.c +++ b/usr.bin/lastcomm/lastcomm.c @@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <err.h> #include <errno.h> -#include <fcntl.h> -#include <grp.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> diff --git a/usr.bin/lastcomm/readrec.c b/usr.bin/lastcomm/readrec.c index 4883b2a..5de7c5c 100644 --- a/usr.bin/lastcomm/readrec.c +++ b/usr.bin/lastcomm/readrec.c @@ -33,13 +33,9 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/acct.h> -#include <ctype.h> -#include <err.h> #include <errno.h> -#include <fcntl.h> #include <stddef.h> #include <stdio.h> -#include <stdlib.h> #include <string.h> int readrec_forward(FILE *f, struct acctv2 *av2); diff --git a/usr.bin/ncplogin/ncplogin.c b/usr.bin/ncplogin/ncplogin.c index 05b95c1..edb903e 100644 --- a/usr.bin/ncplogin/ncplogin.c +++ b/usr.bin/ncplogin/ncplogin.c @@ -42,8 +42,6 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdlib.h> -#include <string.h> #include <sysexits.h> #include <unistd.h> diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c index 6cc3517..67d9c5a 100644 --- a/usr.bin/quota/quota.c +++ b/usr.bin/quota/quota.c @@ -264,8 +264,11 @@ prthumanval(int len, u_int64_t bytes) { char buf[len + 1]; - humanize_number(buf, sizeof(buf), bytes, "", HN_AUTOSCALE, - HN_B | HN_NOSPACE | HN_DECIMAL); + /* + * Limit the width to 5 bytes as that is what users expect. + */ + humanize_number(buf, sizeof(buf) < 5 ? sizeof(buf) : 5, bytes, "", + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); (void)printf(" %*s", len, buf); } @@ -352,10 +355,13 @@ showquotas(int type, u_long id, const char *name) prthumanval(7, dbtob(qup->dqblk.dqb_bhardlimit)); } else { printf(" %7ju%c %7ju %7ju", - dbtob(1024) * (uintmax_t)qup->dqblk.dqb_curblocks, + (uintmax_t)dbtob(qup->dqblk.dqb_curblocks) + / 1024, (msgb == NULL) ? ' ' : '*', - dbtob(1024) * (uintmax_t)qup->dqblk.dqb_bsoftlimit, - dbtob(1024) * (uintmax_t)qup->dqblk.dqb_bhardlimit); + (uintmax_t)dbtob(qup->dqblk.dqb_bsoftlimit) + / 1024, + (uintmax_t)dbtob(qup->dqblk.dqb_bhardlimit) + / 1024); } if (msgb != NULL) bgrace = timeprt(qup->dqblk.dqb_btime); diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c index 2f8ca0a..b1c6dc9 100644 --- a/usr.bin/systat/netstat.c +++ b/usr.bin/systat/netstat.c @@ -63,7 +63,6 @@ static const char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; #define TCPSTATES #include <netinet/tcp_fsm.h> #include <netinet/tcp_timer.h> -#include <netinet/tcp_var.h> #include <netinet/tcp_debug.h> #include <netinet/udp.h> #include <netinet/udp_var.h> diff --git a/usr.bin/tar/util.c b/usr.bin/tar/util.c index 858d472..4177e9c 100644 --- a/usr.bin/tar/util.c +++ b/usr.bin/tar/util.c @@ -226,7 +226,11 @@ yes(const char *fmt, ...) fflush(stderr); l = read(2, buff, sizeof(buff) - 1); - if (l <= 0) + if (l < 0) { + fprintf(stderr, "Keyboard read failed\n"); + exit(1); + } + if (l == 0) return (0); buff[l] = 0; diff --git a/usr.bin/tar/write.c b/usr.bin/tar/write.c index e59f647..9d9025a 100644 --- a/usr.bin/tar/write.c +++ b/usr.bin/tar/write.c @@ -752,6 +752,9 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) break; } + if (bsdtar->option_no_subdirs) + descend = 0; + /* * Are we about to cross to a new filesystem? */ @@ -764,7 +767,6 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) } else if (descend == 0) { /* We're not descending, so no need to check. */ } else if (bsdtar->option_dont_traverse_mounts) { - /* User has asked us not to cross mount points. */ descend = 0; } else { /* We're prepared to cross a mount point. */ @@ -791,8 +793,15 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) * In -u mode, check that the file is newer than what's * already in the archive; in all modes, obey --newerXXX flags. */ - if (!new_enough(bsdtar, name, st)) + if (!new_enough(bsdtar, name, st)) { + if (!descend) + continue; + if (bsdtar->option_interactive && + !yes("add '%s'", name)) + continue; + tree_descend(tree); continue; + } archive_entry_free(entry); entry = archive_entry_new(); @@ -868,8 +877,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) !yes("add '%s'", name)) continue; - /* Note: if user vetoes, we won't descend. */ - if (descend && !bsdtar->option_no_subdirs) + if (descend) tree_descend(tree); /* @@ -919,6 +927,7 @@ write_entry_backend(struct bsdtar *bsdtar, struct archive *a, const char *pathname = archive_entry_sourcepath(entry); fd = open(pathname, O_RDONLY | O_BINARY); if (fd == -1) { + bsdtar->return_value = 1; if (!bsdtar->verbose) bsdtar_warnc(errno, "%s: could not open file", pathname); @@ -1020,6 +1029,12 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, progress += bytes_written; bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN); } + if (bytes_read < 0) { + bsdtar_warnc(errno, + "%s: Read error", + archive_entry_pathname(entry)); + bsdtar->return_value = 1; + } return 0; } diff --git a/usr.bin/tftp/main.c b/usr.bin/tftp/main.c index 2bdcf5f..da0e5df 100644 --- a/usr.bin/tftp/main.c +++ b/usr.bin/tftp/main.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/file.h> -#include <sys/param.h> #include <sys/stat.h> #include <netinet/in.h> diff --git a/usr.bin/tftp/tftp.1 b/usr.bin/tftp/tftp.1 index bf8720b..02709c0 100644 --- a/usr.bin/tftp/tftp.1 +++ b/usr.bin/tftp/tftp.1 @@ -28,7 +28,7 @@ .\" @(#)tftp.1 8.2 (Berkeley) 4/18/94 .\" $FreeBSD$ .\" -.Dd October 1, 2003 +.Dd June 22, 2011 .Dt TFTP 1 .Os .Sh NAME @@ -70,6 +70,21 @@ Shorthand for "mode ascii" .It Cm binary Shorthand for "mode binary" .Pp +.It Cm blocksize Ar [size] +Sets the TFTP blksize option in TFTP Read Request or Write Request packets +to +.Ar [size] +as specified in RFC 2348. Valid values are between 8 and 65464. +If no blocksize is specified, then by default a blocksize of 512 bytes +will be used. +.Pp +.It Cm blocksize2 Ar [size] +Sets the TFTP blksize2 option in TFTP Read Request or Write Request packets +to +.Ar [size] . +Values are restricted to powers of 2 between 8 and 32768. This is a +non-standard TFTP option. +.Pp .It Cm connect Ar host Op Ar port Set the .Ar host @@ -93,6 +108,14 @@ or .Cm put commands. .Pp +.It Cm debug Ar level +Enable or disable debugging levels during verbose output. The value of +.Ar level +can be one of +.Cm packet, simple, options, +or +.Cm access. +.Pp .It Cm get Oo Ar host : Oc Ns Ar file Op Ar localname .It Cm get Xo .Oo Ar host1 : Oc Ns Ar file1 @@ -130,6 +153,11 @@ or The default is .Em ascii . .Pp +.It Cm packetdrop [arg] +Randomly drop +.Ar arg +out of 100 packets during a transfer. This is a debugging feature. +.Pp .It Cm put Ar file Op Oo Ar host : Oc Ns Ar remotename .It Cm put Ar file1 file2 ... fileN Op Oo Ar host : Oc Ns Ar remote-directory Put a file or set of files to the remote host. @@ -149,6 +177,17 @@ see the example under the .Cm get command. .Pp +.It Cm options Ar [arg] +Enable or disable support for TFTP options. The valid values of +.Ar arg +are +.Cm on +(enable RFC 2347 options), +.Cm off +(disable RFC 2347 options), and +.Cm extra +(toggle support for non-RFC defined options). +.Pp .It Cm quit Exit .Nm . @@ -157,6 +196,15 @@ An end of file also exits. .It Cm rexmt Ar retransmission-timeout Set the per-packet retransmission timeout, in seconds. .Pp +.It Cm rollover [arg] +Specify the rollover option in TFTP Read Request or Write +Request packets. After 65535 packets have been transmitted, set the block +counter to +.Ar arg . +Valid values of +.Ar arg +are 0 and 1. This is a non-standard TFTP option. +.Pp .It Cm status Show current status. .Pp @@ -169,11 +217,51 @@ Toggle packet tracing. .It Cm verbose Toggle verbose mode. .El +.Sh SEE ALSO +.Xr tftpd 8 +.Pp +The following RFC's are supported: +.Rs +RFC 1350 +.%T The TFTP Protocol (Revision 2) +.Re +.Rs +RFC 2347 +.%T TFTP Option Extension +.Re +.Rs +RFC 2348 +.%T TFTP Blocksize Option +.Re +.Rs +RFC 2349 +.%T TFTP Timeout Interval and Transfer Size Options +.Re +.Rs +RFC 3617 +.%T Uniform Resource Identifier (URI) Scheme and Applicability Statement for the Trivial File Transfer Protocol (TFTP) +.Re +.Pp +The non-standard +.Cm rollover +and +.Cm blksize2 +TFTP options are mentioned here: +.Rs +.%T Extending TFTP +.%U http://www.compuphase.com/tftp.htm +.Re .Sh HISTORY The .Nm command appeared in .Bx 4.3 . +.Pp +Edwin Groothuis <edwin@FreeBSD.org> performed a major rewrite of the +.Xr tftpd 8 +and +.Nm +code to support RFC2348. .Sh NOTES Because there is no user-login or validation within the diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index cda77ad..d31fdb5 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -43,7 +43,6 @@ static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/time.h> #include <sys/proc.h> #include <sys/uio.h> #include <sys/namei.h> diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c index 008970d..4a11453 100644 --- a/usr.sbin/ancontrol/ancontrol.c +++ b/usr.sbin/ancontrol/ancontrol.c @@ -40,7 +40,6 @@ static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\ __FBSDID("$FreeBSD$"); #include <sys/types.h> -#include <sys/cdefs.h> #include <sys/socket.h> #include <sys/ioctl.h> diff --git a/usr.sbin/ftp-proxy/ftp-proxy/Makefile b/usr.sbin/ftp-proxy/ftp-proxy/Makefile index 773c25d..c21a107 100644 --- a/usr.sbin/ftp-proxy/ftp-proxy/Makefile +++ b/usr.sbin/ftp-proxy/ftp-proxy/Makefile @@ -5,14 +5,14 @@ PROG= ftp-proxy MAN= ftp-proxy.8 -SRCS= ftp-proxy.c filter.c +SRCS= ftp-proxy.c filter.c CFLAGS+= -I${.CURDIR}/../../../contrib/pf/libevent CFLAGS+= -I${.CURDIR}/../../../sys/contrib/pf -DPADD= ${LIBEVENT} -LDADD= ${LIBEVENT} +LDADD+= ${LIBEVENT} +DPADD+= ${LIBEVENT} -WARNS?= 2 +WARNS?= 3 .include <bsd.prog.mk> diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c index e45e36d..5ee4328 100644 --- a/usr.sbin/ifmcstat/ifmcstat.c +++ b/usr.sbin/ifmcstat/ifmcstat.c @@ -72,7 +72,6 @@ __FBSDID("$FreeBSD$"); #include <stddef.h> #include <stdarg.h> -#include <stdlib.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> diff --git a/usr.sbin/mtest/mtest.c b/usr.sbin/mtest/mtest.c index 442c3c4..60f7e09 100644 --- a/usr.sbin/mtest/mtest.c +++ b/usr.sbin/mtest/mtest.c @@ -204,14 +204,16 @@ main(int argc, char **argv) s6 = -1; #ifdef INET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (s == -1) + if (s == -1 && errno != EPROTONOSUPPORT) err(1, "can't open IPv4 socket"); #endif #ifdef INET6 s6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); - if (s6 == -1) + if (s6 == -1 && errno != EPROTONOSUPPORT) err(1, "can't open IPv6 socket"); #endif + if (s == -1 && s6 == -1) + errc(1, EPROTONOSUPPORT, "can't open socket"); if (argc < 2) { if (isatty(STDIN_FILENO)) { @@ -371,7 +373,7 @@ af2socklen(const int af) } static void -process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) +process_cmd(char *cmd, int s, int s6, FILE *fp __unused) { char str1[STR_SIZE]; char str2[STR_SIZE]; @@ -457,7 +459,10 @@ process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) optval = (void *)&mr.mr; optlen = sizeof(mr.mr); } - if (setsockopt(s, level, optname, optval, + if (s < 0) { + warnc(EPROTONOSUPPORT, "setsockopt %s", + toptname); + } else if (setsockopt(s, level, optname, optval, optlen) == 0) { printf("ok\n"); break; @@ -496,7 +501,10 @@ process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) optval = (void *)&mr.mr6; optlen = sizeof(mr.mr6); } - if (setsockopt(s6, level, optname, optval, + if (s6 < 0) { + warnc(EPROTONOSUPPORT, "setsockopt %s", + toptname); + } else if (setsockopt(s6, level, optname, optval, optlen) == 0) { printf("ok\n"); break; @@ -534,6 +542,10 @@ process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) break; } af = su.sa.sa_family; + if (af2sock(af, s, s6) == -1) { + warnc(EPROTONOSUPPORT, "setsourcefilter"); + break; + } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_NUMERICHOST; @@ -593,6 +605,10 @@ process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) break; } af = su.sa.sa_family; + if (af2sock(af, s, s6) == -1) { + warnc(EPROTONOSUPPORT, "getsourcefilter"); + break; + } /* First determine our current filter mode. */ n = 0; @@ -700,6 +716,10 @@ process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused) } af = su.sa.sa_family; + if (af2sock(af, s, s6) == -1) { + warnc(EPROTONOSUPPORT, "getsourcefilter"); + break; + } nsrc = nreqsrc; if (getsourcefilter(af2sock(af, s, s6), ifindex, &su.sa, su.sa.sa_len, &fmode, &nsrc, &sources[0].ss) != 0) { diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c index 656cb14..c5cec5e 100644 --- a/usr.sbin/nfsd/nfsd.c +++ b/usr.sbin/nfsd/nfsd.c @@ -71,7 +71,6 @@ static const char rcsid[] = #include <stdlib.h> #include <string.h> #include <unistd.h> -#include <netdb.h> /* Global defs */ #ifdef DEBUG diff --git a/usr.sbin/nfsuserd/nfsuserd.c b/usr.sbin/nfsuserd/nfsuserd.c index 9dd6396..35e2849 100644 --- a/usr.sbin/nfsuserd/nfsuserd.c +++ b/usr.sbin/nfsuserd/nfsuserd.c @@ -76,6 +76,8 @@ static bool_t xdr_retval(XDR *, caddr_t); #define MAXNAME 1024 #define MAXNFSUSERD 20 #define DEFNFSUSERD 4 +#define MAXUSERMAX 100000 +#define MINUSERMAX 10 #define DEFUSERMAX 200 #define DEFUSERTIMEOUT (1 * 60) struct info { @@ -96,8 +98,8 @@ pid_t slaves[MAXNFSUSERD]; int main(int argc, char *argv[]) { - int i; - int error, len, mustfreeai = 0; + int i, j; + int error, fnd_dup, len, mustfreeai = 0, start_uidpos; struct nfsd_idargs nid; struct passwd *pwd; struct group *grp; @@ -107,6 +109,7 @@ main(int argc, char *argv[]) sigset_t signew; char hostname[MAXHOSTNAMELEN + 1], *cp; struct addrinfo *aip, hints; + static uid_t check_dups[MAXUSERMAX]; if (modfind("nfscommon") < 0) { /* Not present in kernel, try loading it */ @@ -163,9 +166,10 @@ main(int argc, char *argv[]) argc--; argv++; i = atoi(*argv); - if (i < 10 || i > 100000) { + if (i < MINUSERMAX || i > MAXUSERMAX) { fprintf(stderr, - "usermax %d out of range 10<->100000\n", i); + "usermax %d out of range %d<->%d\n", i, + MINUSERMAX, MAXUSERMAX); usage(); } nid.nid_usermax = i; @@ -326,8 +330,25 @@ main(int argc, char *argv[]) /* * Loop around adding all users. */ + start_uidpos = i; setpwent(); while (i < nid.nid_usermax && (pwd = getpwent())) { + fnd_dup = 0; + /* + * Yes, this is inefficient, but it is only done once when + * the daemon is started and will run in a fraction of a second + * for nid_usermax at 10000. If nid_usermax is cranked up to + * 100000, it will take several seconds, depending on the CPU. + */ + for (j = 0; j < (i - start_uidpos); j++) + if (check_dups[j] == pwd->pw_uid) { + /* Found another entry for uid, so skip it */ + fnd_dup = 1; + break; + } + if (fnd_dup != 0) + continue; + check_dups[i - start_uidpos] = pwd->pw_uid; nid.nid_uid = pwd->pw_uid; nid.nid_name = pwd->pw_name; nid.nid_namelen = strlen(pwd->pw_name); diff --git a/usr.sbin/pmcstat/pmcpl_calltree.c b/usr.sbin/pmcstat/pmcpl_calltree.c index c647a32..af3317a 100644 --- a/usr.sbin/pmcstat/pmcpl_calltree.c +++ b/usr.sbin/pmcstat/pmcpl_calltree.c @@ -46,7 +46,6 @@ __FBSDID("$FreeBSD$"); #include <fcntl.h> #include <pmc.h> #include <pmclog.h> -#include <sysexits.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> diff --git a/usr.sbin/ppp/nat_cmd.c b/usr.sbin/ppp/nat_cmd.c index 48f894a..accb149 100644 --- a/usr.sbin/ppp/nat_cmd.c +++ b/usr.sbin/ppp/nat_cmd.c @@ -32,7 +32,6 @@ #include <arpa/inet.h> #include <netdb.h> #include <netinet/in_systm.h> -#include <netinet/in.h> #include <netinet/ip.h> #include <sys/socket.h> #include <sys/un.h> diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c index 8c89691..38719c4 100644 --- a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c +++ b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include <signal.h> #include <stdio.h> #include <stdlib.h> /* getenv, exit */ -#include <string.h> #include <string.h> /* strcmp */ #include <syslog.h> #include <unistd.h> diff --git a/usr.sbin/rpc.ypupdated/update.c b/usr.sbin/rpc.ypupdated/update.c index 72a7128..956b057 100644 --- a/usr.sbin/rpc.ypupdated/update.c +++ b/usr.sbin/rpc.ypupdated/update.c @@ -57,7 +57,6 @@ static const char rcsid[] = #include <pwd.h> #include <string.h> #include <sys/resource.h> -#include <stdlib.h> #include "ypupdated_extern.h" #ifdef YP diff --git a/usr.sbin/rpc.ypupdated/ypupdated_main.c b/usr.sbin/rpc.ypupdated/ypupdated_main.c index c13af7d..92d8374 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_main.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_main.c @@ -50,7 +50,6 @@ __FBSDID("$FreeBSD$"); #include <sys/wait.h> #include <errno.h> #include <err.h> -#include <stdlib.h> #include <unistd.h> #include "ypupdated_extern.h" #include "yp_extern.h" diff --git a/usr.sbin/rpc.ypupdated/ypupdated_server.c b/usr.sbin/rpc.ypupdated/ypupdated_server.c index c9a50dd..c4e163a 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_server.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_server.c @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> #include <rpc/key_prot.h> #include <sys/param.h> -#include <sys/cdefs.h> #include <rpcsvc/yp.h> #include "ypupdate_prot.h" #include "ypupdated_extern.h" diff --git a/usr.sbin/sysinstall/modules.c b/usr.sbin/sysinstall/modules.c index e9bdb0f..9c9875f 100644 --- a/usr.sbin/sysinstall/modules.c +++ b/usr.sbin/sysinstall/modules.c @@ -32,7 +32,6 @@ #include <sys/types.h> #include <sys/param.h> #include <sys/linker.h> -#include <fcntl.h> #include <dirent.h> #include <fcntl.h> #include <fnmatch.h> diff --git a/usr.sbin/wpa/ndis_events/ndis_events.c b/usr.sbin/wpa/ndis_events/ndis_events.c index e3cd9b5..9c6e9de 100644 --- a/usr.sbin/wpa/ndis_events/ndis_events.c +++ b/usr.sbin/wpa/ndis_events/ndis_events.c @@ -42,11 +42,9 @@ __FBSDID("$FreeBSD$"); */ #include <sys/types.h> -#include <sys/cdefs.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <sys/socket.h> #include <sys/errno.h> #include <sys/sysctl.h> #include <net/if.h> diff --git a/usr.sbin/wpa/wpa_supplicant/Packet32.c b/usr.sbin/wpa/wpa_supplicant/Packet32.c index 07da359..876417e 100644 --- a/usr.sbin/wpa/wpa_supplicant/Packet32.c +++ b/usr.sbin/wpa/wpa_supplicant/Packet32.c @@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <sys/socket.h> #include <sys/errno.h> #include <sys/sysctl.h> #include <sys/fcntl.h> |