diff options
author | dr146992 <none@none> | 2006-10-20 16:37:58 -0700 |
---|---|---|
committer | dr146992 <none@none> | 2006-10-20 16:37:58 -0700 |
commit | 381a2a9a387f449fab7d0c7e97c4184c26963abf (patch) | |
tree | 9beb8c59e549aba6f888d2adc733dae7e248d9e2 /usr/src | |
parent | f273041ff6419d6156c10c02bb1a527bfcfdc457 (diff) | |
download | illumos-joyent-381a2a9a387f449fab7d0c7e97c4184c26963abf.tar.gz |
PSARC/2005/334 Packet Filtering Hooks
PSARC/2006/321 ARP packet filtering Hooks
6401219 use of pullupmsg() considered destructive - clears h/w checksum flags
6418698 PSARC/2005/334 - Packet Filtering Hooks API
6449290 package prototype files in usr/src/pkgdefs/SUNWipfr missing CDDL
6449292 package prototype files in usr/src/pkgdefs/SUNWipfu missing CDDL
6449296 Makefiles for ipf kernel module building missing CDDL
6473996 "fastroute" + "nat" packets cause memory leaks in ipfilter
--HG--
rename : usr/src/cmd/ipf/etc/pfil.ap.sh => deleted_files/usr/src/cmd/ipf/etc/pfil.ap.sh
rename : usr/src/cmd/ipf/pfild/Makefile => deleted_files/usr/src/cmd/ipf/pfild/Makefile
rename : usr/src/cmd/ipf/pfild/pfild.c => deleted_files/usr/src/cmd/ipf/pfild/pfild.c
rename : usr/src/cmd/ipf/pfild/vas.c => deleted_files/usr/src/cmd/ipf/pfild/vas.c
rename : usr/src/cmd/ipf/svc/pfil => deleted_files/usr/src/cmd/ipf/svc/pfil
rename : usr/src/cmd/ipf/svc/pfil.xml => deleted_files/usr/src/cmd/ipf/svc/pfil.xml
rename : usr/src/uts/common/inet/pfil/compat.h => deleted_files/usr/src/uts/common/inet/pfil/compat.h
rename : usr/src/uts/common/inet/pfil/ndd.c => deleted_files/usr/src/uts/common/inet/pfil/ndd.c
rename : usr/src/uts/common/inet/pfil/os.h => deleted_files/usr/src/uts/common/inet/pfil/os.h
rename : usr/src/uts/common/inet/pfil/pfil.c => deleted_files/usr/src/uts/common/inet/pfil/pfil.c
rename : usr/src/uts/common/inet/pfil/pfil.conf => deleted_files/usr/src/uts/common/inet/pfil/pfil.conf
rename : usr/src/uts/common/inet/pfil/pfil.h => deleted_files/usr/src/uts/common/inet/pfil/pfil.h
rename : usr/src/uts/common/inet/pfil/pfild.h => deleted_files/usr/src/uts/common/inet/pfil/pfild.h
rename : usr/src/uts/common/inet/pfil/pfildrv.c => deleted_files/usr/src/uts/common/inet/pfil/pfildrv.c
rename : usr/src/uts/common/inet/pfil/pfilstream.c => deleted_files/usr/src/uts/common/inet/pfil/pfilstream.c
rename : usr/src/uts/common/inet/pfil/pkt.c => deleted_files/usr/src/uts/common/inet/pfil/pkt.c
rename : usr/src/uts/common/inet/pfil/qif.c => deleted_files/usr/src/uts/common/inet/pfil/qif.c
rename : usr/src/uts/common/inet/pfil/qif.h => deleted_files/usr/src/uts/common/inet/pfil/qif.h
rename : usr/src/uts/intel/pfil/Makefile => deleted_files/usr/src/uts/intel/pfil/Makefile
rename : usr/src/uts/sparc/pfil/Makefile => deleted_files/usr/src/uts/sparc/pfil/Makefile
rename : usr/src/uts/common/inet/pfil/misc.c => usr/src/uts/common/inet/ipf/misc.c
Diffstat (limited to 'usr/src')
124 files changed, 8398 insertions, 7885 deletions
diff --git a/usr/src/cmd/devfsadm/misc_link.c b/usr/src/cmd/devfsadm/misc_link.c index 0766c3dc28..4ad6e87777 100644 --- a/usr/src/cmd/devfsadm/misc_link.c +++ b/usr/src/cmd/devfsadm/misc_link.c @@ -110,7 +110,7 @@ static devfsadm_create_t misc_cbt[] = { TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name }, { "pseudo", "ddi_pseudo", - "(^pfil$)|(^ipf$)|(^ipnat$)|(^ipstate$)|(^ipauth$)|" + "(^ipf$)|(^ipnat$)|(^ipstate$)|(^ipauth$)|" "(^ipsync$)|(^ipscan$)|(^iplookup$)", TYPE_EXACT | DRV_RE, ILEVEL_0, minor_name, }, diff --git a/usr/src/cmd/ipf/Makefile b/usr/src/cmd/ipf/Makefile index b5376faba1..953beb9fec 100644 --- a/usr/src/cmd/ipf/Makefile +++ b/usr/src/cmd/ipf/Makefile @@ -1,5 +1,25 @@ # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -9,7 +29,7 @@ SUBDIRS= etc examples \ lib svc .WAIT \ - pfild tools + tools LINTCLEAN= LINTSUBDIRS= diff --git a/usr/src/cmd/ipf/etc/Makefile b/usr/src/cmd/ipf/etc/Makefile index 0971010338..afe39fa704 100644 --- a/usr/src/cmd/ipf/etc/Makefile +++ b/usr/src/cmd/ipf/etc/Makefile @@ -1,5 +1,25 @@ # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -7,9 +27,8 @@ #cmd/ipf/etc/Makefile # -PFILAP= pfil.ap IPFCONF= ipf.conf -IPFPROG= $(PFILAP) $(IPFCONF) +IPFPROG= $(IPFCONF) include ../../Makefile.cmd diff --git a/usr/src/cmd/ipf/etc/pfil.ap.sh b/usr/src/cmd/ipf/etc/pfil.ap.sh deleted file mode 100644 index 6bf62c9ad3..0000000000 --- a/usr/src/cmd/ipf/etc/pfil.ap.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/sbin/sh -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. - -#ident "%Z%%M% %I% %E% SMI" - -case "$MACH" in - "i386" ) - echo "# IP Filter pfil autopush setup -# -# See the autopush(1M) manpage for more information. -# -# Format of the entries in this file is: -# -#major minor lastminor modules - -#iprb -1 0 pfil -#elxl -1 0 pfil -#e1000g -1 0 pfil -#bge -1 0 pfil -#nf -1 0 pfil -#fa -1 0 pfil -#ci -1 0 pfil -#el -1 0 pfil -#ipdptp -1 0 pfil -#lane -1 0 pfil -#dnet -1 0 pfil -#pcelx -1 0 pfil -#spwr -1 0 pfil -#ce -1 0 pfil - -" > pfil.ap - ;; - "sparc" ) - echo "# IP Filter pfil autopush setup -# -# See autopush(1M) manpage for more information. -# -# Format of the entries in this file is: -# -#major minor lastminor modules - -#le -1 0 pfil -#qe -1 0 pfil -#hme -1 0 pfil -#qfe -1 0 pfil -#eri -1 0 pfil -#ce -1 0 pfil -#e1000g -1 0 pfil -#bge -1 0 pfil -#be -1 0 pfil -#vge -1 0 pfil -#ge -1 0 pfil -#nf -1 0 pfil -#fa -1 0 pfil -#ci -1 0 pfil -#el -1 0 pfil -#ipdptp -1 0 pfil -#lane -1 0 pfil -#dmfe -1 0 pfil -" >pfil.ap - ;; - * ) - echo "Unknown architecture." - exit 1 - ;; -esac - diff --git a/usr/src/cmd/ipf/lib/common/getifname.c b/usr/src/cmd/ipf/lib/common/getifname.c index a42a4e089b..ec3ae926b2 100644 --- a/usr/src/cmd/ipf/lib/common/getifname.c +++ b/usr/src/cmd/ipf/lib/common/getifname.c @@ -10,17 +10,19 @@ #pragma ident "%Z%%M% %I% %E% SMI" #include "ipf.h" -#include "qif.h" #include "kmem.h" /* * Given a pointer to an interface in the kernel, return a pointer to a * string which is the interface name. + * + * The same code is used to run in two different environments: in ipfstat + * and in ipftest. In ipftest, kmemcpy is wrapper for bcopy but in ipfstat, + * it is used as an interface to libkvm. */ char *getifname(ptr) struct ifnet *ptr; { -#if SOLARIS || defined(__hpux) # if SOLARIS # include <sys/mutex.h> # include <sys/condvar.h> @@ -28,23 +30,6 @@ struct ifnet *ptr; # ifdef __hpux # include "compat.h" # endif - char *ifname; - qif_t qif; - - if ((void *)ptr == (void *)-1) - return "!"; - if (ptr == NULL) - return "-"; - - if (kmemcpy((char *)&qif, (u_long)ptr, sizeof(qif)) == -1) - return "X"; - ifname = strdup(qif.qf_name); - if ((ifname != NULL) && (*ifname == '\0')) { - free(ifname); - return "!"; - } - return ifname; -#else # if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ defined(__OpenBSD__) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) @@ -54,6 +39,11 @@ struct ifnet *ptr; # endif struct ifnet netif; +# ifdef SOLARIS_PFHOOKS + if ((opts & OPT_DONOTHING) == 0) + return "@"; +# endif + if ((void *)ptr == (void *)-1) return "!"; if (ptr == NULL) @@ -80,5 +70,4 @@ struct ifnet *ptr; sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); return strdup(buf); # endif -#endif } diff --git a/usr/src/cmd/ipf/lib/common/getsumd.c b/usr/src/cmd/ipf/lib/common/getsumd.c index 346c445ff8..bcf0945497 100644 --- a/usr/src/cmd/ipf/lib/common/getsumd.c +++ b/usr/src/cmd/ipf/lib/common/getsumd.c @@ -1,3 +1,15 @@ +/* + * Copyright (C) 1993-2001 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + #include "ipf.h" char *getsumd(sum) @@ -5,9 +17,6 @@ u_32_t sum; { static char sumdbuf[17]; - if (sum & NAT_HW_CKSUM) - sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff); - else - sprintf(sumdbuf, "%#0x", sum); + sprintf(sumdbuf, "%#0x", sum); return sumdbuf; } diff --git a/usr/src/cmd/ipf/pfild/Makefile b/usr/src/cmd/ipf/pfild/Makefile deleted file mode 100644 index 0b14c9f50b..0000000000 --- a/usr/src/cmd/ipf/pfild/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# -#pragma ident "%Z%%M% %I% %E% SMI" -# - -PROG= pfild - -OBJS= pfild.o vas.o -SRCS= $(OBJS:.o=.c) - -include ../../Makefile.cmd -include ../Makefile.ipf - -LDLIBS += $(LIBBPF) -lsocket -lnsl -CFLAGS += -DNDEBUG -D_XOPEN_SOURCE=500 -D__EXTENSIONS__ -CPPFLAGS += -I. -DIPFILTER_LOOKUP -DIPFILTER_LOG -CLEANFILES += $(OBJS) - -.KEEP_STATE: - -all: $(PROG) - -$(PROG): $(OBJS) - $(LINK.c) $(OBJS) -o $@ $(LDLIBS) - $(POST_PROCESS) - -install: all $(ROOTUSRSBINPROG) - -clean: - -$(RM) $(OBJS) $(PROG) - -lint: lint_SRCS - -include ../../Makefile.targ diff --git a/usr/src/cmd/ipf/pfild/pfild.c b/usr/src/cmd/ipf/pfild/pfild.c deleted file mode 100644 index f811694340..0000000000 --- a/usr/src/cmd/ipf/pfild/pfild.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <net/if.h> -#include <net/route.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <malloc.h> -#include <stropts.h> -#include <stdlib.h> -#include <netinet/ip.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include "pfild.h" - -extern int vas(const struct pfil_ifaddrs *, int); - -/* - * pfild.c: interface data and packet transmission daemon for pfil - * - * pfild provides the pfil kernel module with certain data that are not - * directly available to kernel code using supported OS interfaces. pfild - * accesses the routing tables and network interface parameters using - * interfaces readily available to a user space daemon, copies the data into - * the kernel via /dev/pfil, and waits for any changes to the data. - * - * pfild also provides a way for the kernel module to originate IP packets - * without resorting to unsupported kernel interfaces. If the kernel - * sends up an M_DATA message, pfild sends it on a raw IP socket so that it - * gets routed and transmitted as a normal packet. - */ - - -/* file descriptors for talking to pfil, ifnet, routing kernel modules */ -static int pfil_fd, ip_fd, icmp6_ip6_fd, tcp_ip6_fd, route_fd; - -/* - * flag indicates that some interface or routing data have changed since - * last update. - */ -static int flag = 1; -/* - * debuglevel indicates to what level debugging messages should be emitted. - */ -static int debuglevel = 0; - -/* Wait for this many ms of quiet time after changes before doing an update. */ -#define QUIETTIME 200 - - -/* - * Send a message to the pfil kernel module. - * Returns zero for success, otherwise non-zero with errror in errno. - */ -int -pfil_msg(uint32_t cmd, void *buf, size_t len) -{ - int error; - - if (debuglevel > 0) - (void) fprintf(stderr, "pfil_msg(%x,%p,%d)\n", cmd, buf, len); - - if (pfil_fd >= 0) { - struct strbuf ctl, data; - - ctl.buf = (void *)&cmd; - ctl.len = sizeof (cmd); - data.buf = buf; - data.len = len; - - error = putmsg(pfil_fd, &ctl, &data, 0); - if (debuglevel > 0) - (void) fprintf(stderr, - "pfild:pfil_msg():putmsg(%d,%p,%p,0) = %d\n", - pfil_fd, &ctl, &data, 0, error); - } else { - error = 0; - if (debuglevel > 0) - (void) fprintf(stderr, - "pfild:pfil_msg():pfil_fd < 0\n"); - } - - return (error); -} - - -/* - * Handle a PF_ROUTE message. If an address has been added or deleted, treat - * this as an indication that some interface data has been udpated. If a route - * has been added or deleted, treat this as an indication that the routing - * table has been updated. The current implementation completely updates both - * sets of data when either kind of change is indicated. - * - * p points to, and size indicates the size of, the message. - */ -static void -handle_msg(const ifa_msghdr_t *p, size_t size) -{ - if (size < sizeof (*p) || - size < p->ifam_msglen || - p->ifam_version != RTM_VERSION) { - if (debuglevel > 0) - (void) fprintf(stderr, - "Not a valid version %u RTM message - " - "%u bytes version %u\n", - RTM_VERSION, size, p->ifam_version); - return; - } - - switch (p->ifam_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - case RTM_ADD: - case RTM_DELETE: - flag = 1; - break; - default: - break; - } - - if (debuglevel > 0) - (void) fprintf(stderr, - "pfild:handle_msg(): msg rcvd %d flag %d\n", - p->ifam_type, flag); -} - - -#include <arpa/inet.h> -static const char * -dumpaddr(void *p) -{ - static char buf[INET6_ADDRSTRLEN]; - struct sockaddr_in *sin = p; - struct sockaddr_in6 *sin6 = p; - switch (sin->sin_family) { - case AF_INET: - return (inet_ntop(sin->sin_family, &sin->sin_addr, buf, - sizeof (buf))); - case AF_INET6: - return (inet_ntop(sin6->sin6_family, &sin6->sin6_addr, buf, - sizeof (buf))); - default: - return ("<none>"); - } -} - - -#define ERRBUFSIZE 100 -static char errbuf[ERRBUFSIZE]; - -#define LIFN_MARGIN 5 /* a few extra in case things are changing */ - -/* - * Fetch the address configuration data for all interfaces and push it into - * the pfil kernel module. Fetch the routing table, compute the valid address - * set data for all interfaces and push it into the pfil kernel module. - */ -static int -do_update(void) -{ - int numifs, i; - struct lifreq *lifrbuf; - struct lifconf lifc; - struct pfil_ifaddrs *ifaddrlist; - struct lifnum lifn; - const int lifc_flags = 0; - void *buf; - size_t bufsize; - - flag = 0; - - lifn.lifn_family = AF_UNSPEC; - lifn.lifn_flags = lifc_flags; - if (ioctl(ip_fd, SIOCGLIFNUM, (char *)&lifn) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFNUM: %s", - strerror(errno)); - return (-1); - } - - bufsize = (lifn.lifn_count + LIFN_MARGIN) * sizeof (struct lifreq); - buf = malloc(bufsize); - if (buf == NULL) { - (void) snprintf(errbuf, ERRBUFSIZE, "malloc: %s", - strerror(errno)); - return (-1); - } - lifrbuf = buf; - lifc.lifc_family = AF_UNSPEC; - lifc.lifc_flags = lifc_flags; - lifc.lifc_buf = buf; - lifc.lifc_len = bufsize; - if (ioctl(ip_fd, SIOCGLIFCONF, (char *)&lifc) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFCONF: %s", - strerror(errno)); - free(buf); - return (-1); - } - - numifs = lifc.lifc_len / sizeof (struct lifreq); - - /* Allocate memory for the number of interfaces retrieved. */ - ifaddrlist = calloc(numifs, sizeof (struct pfil_ifaddrs)); - if (ifaddrlist == NULL) { - (void) snprintf(errbuf, ERRBUFSIZE, "calloc: %s", - strerror(errno)); - free(buf); - return (-1); - } - - /* Populate the interface entries in the ifaddrlist. */ - for (i = 0; i < numifs; i++) { - int isv6 = (lifrbuf[i].lifr_addr.ss_family == AF_INET6); - int fd = (isv6 ? icmp6_ip6_fd : ip_fd); - - (void) strncpy(ifaddrlist[i].name, lifrbuf[i].lifr_name, - LIFNAMSIZ); - (void) memcpy(&ifaddrlist[i].localaddr, &lifrbuf[i].lifr_addr, - sizeof (ifaddrlist[i].localaddr)); - - if (ioctl(fd, SIOCGLIFNETMASK, &lifrbuf[i]) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, - "SIOCGLIFNETMASK %.*s: %s", - LIFNAMSIZ, ifaddrlist[i].name, strerror(errno)); - free(ifaddrlist); - free(buf); - return (-1); - } - (void) memcpy(&ifaddrlist[i].netmask, &lifrbuf[i].lifr_addr, - sizeof (ifaddrlist[i].netmask)); - - if (ioctl(fd, SIOCGLIFBRDADDR, &lifrbuf[i]) < 0) { - if (errno != EADDRNOTAVAIL) { - (void) snprintf(errbuf, ERRBUFSIZE, - "SIOCGLIFBRDADDR %.*s: %s", - LIFNAMSIZ, ifaddrlist[i].name, - strerror(errno)); - free(ifaddrlist); - free(buf); - return (-1); - } - } else { - (void) memcpy(&ifaddrlist[i].broadaddr, - &lifrbuf[i].lifr_broadaddr, - sizeof (ifaddrlist[i].broadaddr)); - } - - if (ioctl(fd, SIOCGLIFDSTADDR, &lifrbuf[i]) < 0) { - if (errno != EADDRNOTAVAIL) { - (void) snprintf(errbuf, ERRBUFSIZE, - "SIOCGLIFDSTADDR %.*s: %s", - LIFNAMSIZ, ifaddrlist[i].name, - strerror(errno)); - free(ifaddrlist); - free(buf); - return (-1); - } - } else { - (void) memcpy(&ifaddrlist[i].dstaddr, - &lifrbuf[i].lifr_dstaddr, - sizeof (ifaddrlist[i].dstaddr)); - } - - if (ioctl(fd, SIOCGLIFMTU, &lifrbuf[i]) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, - "SIOCGLIFDSTADDR %.*s: %s", - LIFNAMSIZ, ifaddrlist[i].name, - strerror(errno)); - free(ifaddrlist); - free(buf); - return (-1); - } else { - ifaddrlist[i].mtu = lifrbuf[i].lifr_mtu; - } - - if (debuglevel > 0) { - (void) fprintf(stderr, "%.*s:\n", - LIFNAMSIZ, ifaddrlist[i].name); - (void) fprintf(stderr, " localaddr %s (%d)\n", - dumpaddr(&ifaddrlist[i].localaddr), - ifaddrlist[i].localaddr.in.sin_family); - (void) fprintf(stderr, " netmask %s (%d)\n", - dumpaddr(&ifaddrlist[i].netmask), - ifaddrlist[i].netmask.in.sin_family); - (void) fprintf(stderr, " broadaddr %s (%d)\n", - dumpaddr(&ifaddrlist[i].broadaddr), - ifaddrlist[i].broadaddr.in.sin_family); - (void) fprintf(stderr, " dstaddr %s (%d)\n", - dumpaddr(&ifaddrlist[i].dstaddr), - ifaddrlist[i].dstaddr.in.sin_family); - (void) fprintf(stderr, " mtu %u\n", - ifaddrlist[i].mtu); - } - } - - free(buf); - - /* - * Now send this table of interfaces and addresses down into - * the pfil kernel module. - */ - if (pfil_msg(PFILCMD_IFADDRS, - ifaddrlist, i * sizeof (struct pfil_ifaddrs)) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, - "PFILCMD_IFADDRS: %s", strerror(errno)); - free(ifaddrlist); - return (-1); - } - - /* - * Next, compute and send the table of valid addresses. - */ - - if (vas(ifaddrlist, numifs) < 0) { - (void) snprintf(errbuf, ERRBUFSIZE, - "PFILCMD_IFADDRSET: %s", strerror(errno)); - free(ifaddrlist); - return (-1); - } - - free(ifaddrlist); - - return (0); -} - - -/* - * Send an IPv6 packet out from the system using sendmsg on the raw IP socket - * through the ancillary data. - */ -static int -send_ip6_pkt(const void *pkt, size_t len) -{ - const struct ip6_hdr *iph = pkt; - - struct sockaddr_in6 sin6; - struct iovec iovec; - struct msghdr msghdr; - struct cmsghdr *cmsgp; - struct in6_pktinfo *pktinfop; - unsigned char ancdatabuf[sizeof (*cmsgp) + sizeof (*pktinfop) + 100]; - size_t ancdatalen; - int fd; - - cmsgp = (struct cmsghdr *)ancdatabuf; - pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); - cmsgp->cmsg_len = ((char *)(pktinfop + 1) - (char *)cmsgp); - cmsgp->cmsg_level = IPPROTO_IPV6; - cmsgp->cmsg_type = IPV6_PKTINFO; - memcpy(&pktinfop->ipi6_addr, &iph->ip6_src, - sizeof (pktinfop->ipi6_addr)); - pktinfop->ipi6_ifindex = 0; - ancdatalen = ((char *)(pktinfop + 1) - (char *)cmsgp); - - sin6.sin6_family = AF_INET6; - memcpy(&sin6.sin6_addr, &iph->ip6_dst, sizeof (sin6.sin6_addr)); - sin6.sin6_port = 0; - sin6.sin6_scope_id = 0; - sin6.sin6_flowinfo = iph->ip6_flow & IPV6_FLOWINFO_TCLASS; - - iovec.iov_base = (char *)(iph + 1); - iovec.iov_len = len - sizeof (*iph); - msghdr.msg_name = &sin6; - msghdr.msg_namelen = sizeof (sin6); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = ancdatabuf; - msghdr.msg_controllen = ancdatalen; - msghdr.msg_flags = 0; - - if (iph->ip6_nxt == IPPROTO_ICMPV6) - fd = icmp6_ip6_fd; - else if (iph->ip6_nxt == IPPROTO_TCP) - fd = tcp_ip6_fd; - else { - errno = EPROTONOSUPPORT; - return (-1); - } - return (sendmsg(fd, &msghdr, 0)); -} - - -/* - * Send an arbitrary IP packet out from the system using sendto/sendmsg on the - * raw IP socket. Due to the awkwardness of the IPv6 socket API, IPv6 packets - * are limited to ICMP and TCP; other protocols are dropped. - */ -static void -sendpkt(const void *buf, int len) -{ - const struct ip *iph = buf; - int n; - - if (debuglevel > 0) { - fprintf(stderr, "pfild sendpkt %u bytes:\n", len); - fprintf(stderr, " %08X %08X %08X %08X\n", - ((uint32_t *)buf)[0], - ((uint32_t *)buf)[1], - ((uint32_t *)buf)[2], - ((uint32_t *)buf)[3]); - fprintf(stderr, " %08X %08X %08X %08X\n", - ((uint32_t *)buf)[4], - ((uint32_t *)buf)[5], - ((uint32_t *)buf)[6], - ((uint32_t *)buf)[7]); - fprintf(stderr, " %08X %08X %08X %08X\n", - ((uint32_t *)buf)[8], - ((uint32_t *)buf)[9], - ((uint32_t *)buf)[10], - ((uint32_t *)buf)[11]); - } - - if (iph->ip_v == 4 && len >= 20) { - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = 0; - sin.sin_addr = iph->ip_dst; - n = sendto(ip_fd, buf, len, 0, (void *)&sin, sizeof (sin)); - } else if (iph->ip_v == 6 && len > 40) { - n = send_ip6_pkt(buf, len); - } else { - n = -1; - errno = EINVAL; - } - - if (n < 0) - perror("pfild: raw socket send"); -} - - -static void usage(const char *prog) -{ - fprintf(stderr, "%s: [-d]\n", prog); - exit(1); -} - - -int -main(int argc, char *argv[]) -{ - int c, n; - const int on = 1; - int make_daemon = 1; - struct pollfd pollfds[2]; - union { char bytes[1024]; ifa_msghdr_t msg; } buffer; - int pid; - struct icmp6_filter filter; - - while ((c = getopt(argc, argv, "d")) != -1) { - switch (c) { - case '?' : - usage(argv[0]); - break; - case 'd' : - make_daemon = 0; - debuglevel++; - break; - } - } - - pfil_fd = open("/dev/pfil", O_RDWR); - if (pfil_fd < 0) { - perror("pfild: open(/dev/pfil)"); - return (1); - } - - ip_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (ip_fd < 0) { - perror("pfild: inet socket"); - return (1); - } - if (setsockopt(ip_fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) { - perror("pfild: inet socket IP_HDRINCL option"); - return (1); - } - - icmp6_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - if (icmp6_ip6_fd < 0) { - perror("pfild: inet6 ICMP6 socket"); - return (1); - } - /* - * ICMPv6 raw socket by default passes all ICMPv6 message received - * to the application. We don't care about them, so simply block them - * all. - */ - ICMP6_FILTER_SETBLOCKALL(&filter); - if (setsockopt(icmp6_ip6_fd, IPPROTO_ICMPV6, ICMP6_FILTER, - &filter, sizeof (filter)) < 0) { - perror("pfild: inet6 ICMP6 socket type filtering option"); - return (1); - } - - tcp_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP); - if (tcp_ip6_fd < 0) { - perror("pfild: inet6 TCP socket"); - return (1); - } - - route_fd = socket(PF_ROUTE, SOCK_RAW, 0); - if (route_fd < 0) { - perror("pfild: socket(PF_ROUTE)"); - return (1); - } - - if (make_daemon) { - /* Background */ - if ((pid = fork()) > 0) - return (0); - if (pid < 0) { - (void) fprintf(stderr, "%s: fork() failed %s\n", - argv[0], strerror(errno)); - return (1); - /* NOTREACHED */ - } - (void) setsid(); - (void) close(0); - (void) close(1); - (void) close(2); - (void) open("/dev/null", O_RDWR); - (void) dup(0); - (void) dup(0); - (void) chdir("/"); - } - - /* - * Main loop: Poll for messages from PF_ROUTE socket or pfil stream. - * PF_ROUTE messages may indicate a need to update the kernel module's - * interface data. pfil messages contain packets to be transmitted. - * Errors in processing don't terminate the program, but errors in - * polling will terminate the program to avoid busy looping. - */ - - pollfds[0].fd = route_fd; - pollfds[0].events = POLLRDNORM; - pollfds[1].fd = pfil_fd; - pollfds[1].events = POLLRDNORM; - - while (1) { - if (flag) { - /* Wait for a moment of quiet, then do the update. */ - n = poll(pollfds, 1, QUIETTIME); - if (n < 1 || !(pollfds[0].revents & POLLRDNORM)) { - if (do_update() != 0 && make_daemon == 0) - (void) fprintf(stderr, "pfild: %s\n", - errbuf); - } - } - - if (poll(pollfds, 2, -1) < 0) { - perror("pfild: poll()"); - return (1); - } - - /* Check for route_fd message. */ - if (pollfds[0].revents & POLLRDNORM) { - n = read(route_fd, &buffer, sizeof (buffer)); - - if (n < 1) { - if (n < 0) - perror("pfild: read(PF_ROUTE)"); - else - (void) fprintf(stderr, - "pfild: read(PF_ROUTE) EOF\n"); - return (1); - } - - handle_msg(&buffer.msg, n); - } - - /* Check for pfil_fd message. */ - if (pollfds[1].revents & POLLRDNORM) { - char pktbuf[IP_MAXPACKET]; - struct strbuf ctl, data; - int flags; - - ctl.maxlen = 0; /* We don't want any control message. */ - ctl.buf = pktbuf; - data.maxlen = sizeof (pktbuf); - data.buf = pktbuf; - flags = 0; - - n = getmsg(pfil_fd, &ctl, &data, &flags); - - if (n < 0) { - perror("pfild: getmsg(pfil)"); - return (1); - } - if (n > 0) { - fprintf(stderr, - "pfild: invalid packet from kernel " - "n=%d ctl.len=%u data.len=%u\n", - n, ctl.len, data.len); - return (1); - } - - sendpkt(data.buf, data.len); - } - } - - /* NOTREACHED */ -} diff --git a/usr/src/cmd/ipf/pfild/vas.c b/usr/src/cmd/ipf/pfild/vas.c deleted file mode 100644 index 25d200a3d7..0000000000 --- a/usr/src/cmd/ipf/pfild/vas.c +++ /dev/null @@ -1,1258 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/stream.h> -#include <stropts.h> -#include <sys/strstat.h> -#include <sys/sysmacros.h> -#include <sys/tihdr.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <net/if.h> -#include <net/route.h> -#include <inet/common.h> -#include <inet/mib2.h> -#include <inet/ip.h> -#include <inet/ip6.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <fcntl.h> -#include <sys/systeminfo.h> -#include <arpa/inet.h> -#include "pfild.h" - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - -extern int pfil_msg(uint32_t, void *, size_t); - -/* - * vas.c: Valid Address Set computation and communication for pfild - * - * pfild computes a "valid source address set" for each interface and hands the - * resulting data to the pfil module which makes it available to pfil clients. - * The ipf module uses the valid address sets to implement the fr_chksrc - * feature (automatic protection from source address spoofing). - * - * A valid source address for a packet received on given interface is defined - * as an address which, if used as a destination, would be routed to that - * interface. This code assumes that only inbound traffic will be tested - * against the valid address sets; thus all local and loopback addresses are - * considered invalid. - * - * The TPI MIB interface is used to read the current routing table. A - * request (T_SVR4_OPTMGMT_REQ) is sent to /dev/arp and the replies are read, - * discarding most of them, but saving the two that contain the IPv4 and IPv6 - * routing tables. Also inspected are two other messages that each happen to - * contain a constant needed to parse the routing table messages. - * - * An address set is represented as a sorted list of mutually discontiguous - * non-empty inclusive spans. In the kernel, this list can be efficiently - * binary-searched. In user space, we can compute unions and intersections of - * address sets. In either case, IPv4 addresses are stored in host byte order - * for efficient numerical comparisons. IPv6 addresses will be compared - * byte-at-a-time so they are kept in conventional struct in6_addr form - * (network byte order). - */ - - -/* - * Defining macro used in IPv6 address comparation, add/minus, - * increase/decrease. - */ - -typedef union i6addr { - uint32_t i6[4]; -} i6addr_t; - -#define I60(x) (((i6addr_t *)(x))->i6[0]) -#define I61(x) (((i6addr_t *)(x))->i6[1]) -#define I62(x) (((i6addr_t *)(x))->i6[2]) -#define I63(x) (((i6addr_t *)(x))->i6[3]) - -#define HI60(x) ntohl(((i6addr_t *)(x))->i6[0]) -#define HI61(x) ntohl(((i6addr_t *)(x))->i6[1]) -#define HI62(x) ntohl(((i6addr_t *)(x))->i6[2]) -#define HI63(x) ntohl(((i6addr_t *)(x))->i6[3]) - -#define IP6_EQ(a, b) (IN6_ARE_ADDR_EQUAL(a, b)) -#define IP6_GT(a, b) (HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \ - (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \ - (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \ - HI63(a) > HI63(b))))))) -#define IP6_LT(a, b) (HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \ - (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \ - (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \ - HI63(a) < HI63(b))))))) -#define IP6_GE(a, b) (IP6_EQ(a, b) || IP6_GT(a, b)) -#define IP6_LE(a, b) (IP6_EQ(a, b) || IP6_LT(a, b)) - -#define NLADD(n, x) htonl(ntohl(n) + (x)) -#define NLMIN(n, x) htonl(ntohl(n) - (x)) -#define IP6_INC(a) \ - { i6addr_t *_i6 = (i6addr_t *)(a); \ - _i6->i6[3] = NLADD(_i6->i6[3], 1); \ - if (_i6->i6[3] == 0) { \ - _i6->i6[2] = NLADD(_i6->i6[2], 1); \ - if (_i6->i6[2] == 0) { \ - _i6->i6[1] = NLADD(_i6->i6[1], 1); \ - if (_i6->i6[1] == 0) { \ - _i6->i6[0] = NLADD(_i6->i6[0], 1); \ - } \ - } \ - } \ - } -#define IP6_DEC(a) \ - { i6addr_t *_i6 = (i6addr_t *)(a); \ - _i6->i6[3] = NLMIN(_i6->i6[3], 1); \ - if (_i6->i6[3] == 0xFFFFFFFFU) { \ - _i6->i6[2] = NLMIN(_i6->i6[2], 1); \ - if (_i6->i6[2] == 0xFFFFFFFFU) { \ - _i6->i6[1] = NLMIN(_i6->i6[1], 1); \ - if (_i6->i6[1] == 0xFFFFFFFFU) { \ - _i6->i6[0] = NLMIN(_i6->i6[0], 1); \ - } \ - } \ - } \ - } - -#define IP6_FIRST(a, m) \ - { if ((m) > 96) { \ - I63(a) = ntohl(I63(a)); \ - I63(a) &= (0xFFFFFFFF << (128 - (m))); \ - I63(a) = htonl(I63(a)); \ - } else if ((m) > 64) { \ - I62(a) = ntohl(I62(a)); \ - I62(a) &= (0xFFFFFFFF << (96 - (m))); \ - I62(a) = htonl(I62(a)); \ - I63(a) = 0; \ - } else if ((m) > 32) { \ - I61(a) = ntohl(I61(a)); \ - I61(a) &= (0xFFFFFFFF << (64 - (m))); \ - I61(a) = htonl(I61(a)); \ - I62(a) = 0; \ - I63(a) = 0; \ - } else if ((m) > 0) { \ - I60(a) = ntohl(I60(a)); \ - I60(a) &= (0xFFFFFFFF << (32 - (m))); \ - I60(a) = htonl(I60(a)); \ - I61(a) = 0; \ - I62(a) = 0; \ - I63(a) = 0; \ - } else { \ - I60(a) = 0; \ - I61(a) = 0; \ - I62(a) = 0; \ - I63(a) = 0; \ - } \ - } -#define IP6_LAST(a, m) \ - { if ((m) == 128) { \ - } else if ((m) >= 96) { \ - I63(a) = ntohl(I63(a)); \ - I63(a) |= (0xFFFFFFFF >> ((m) - 96)); \ - I63(a) = htonl(I63(a)); \ - } else if ((m) >= 64) { \ - I62(a) = ntohl(I62(a)); \ - I62(a) |= (0xFFFFFFFF >> ((m) - 64)); \ - I62(a) = htonl(I62(a)); \ - I63(a) = 0xFFFFFFFFU; \ - } else if ((m) >= 32) { \ - I61(a) = ntohl(I61(a)); \ - I61(a) |= (0xFFFFFFFF >> ((m) - 32)); \ - I61(a) = htonl(I61(a)); \ - I62(a) = 0xFFFFFFFFU; \ - I63(a) = 0xFFFFFFFFU; \ - } else if ((m) >= 0) { \ - I60(a) = ntohl(I60(a)); \ - I60(a) |= (0xFFFFFFFF >> (m)); \ - I60(a) = htonl(I60(a)); \ - I61(a) = 0xFFFFFFFFU; \ - I62(a) = 0xFFFFFFFFU; \ - I63(a) = 0xFFFFFFFFU; \ - } \ - } - - -/* - * User space uses a linked list of spans, rather than the array that is - * used in the kernel and in the /dev/pfil messages. - */ - -struct spannode { - struct spannode *next; - union { - struct pfil_v4span v4; - struct pfil_v6span v6; - } span; -}; - -struct addrset { - const char *name; - uint8_t af; - struct spannode *head; -}; - -/* - * Allocate and initialize a new struct addrset. - * Returns pointer to new instance or NULL for allocation failure. - */ -static struct addrset * -new_addrset(const char *name, uint8_t af) -{ - struct addrset *asp = malloc(sizeof (*asp)); - - if (asp == NULL) - return (NULL); - - asp->name = name; - asp->af = af; - asp->head = NULL; - - return (asp); -} - -/* - * Free an addrset instance. - */ -static void -delete_addrset(struct addrset *asp) -{ - struct spannode *tmp; - while (asp->head != NULL) { - tmp = asp->head->next; - free(asp->head); - asp->head = tmp; - } - free(asp); -} - -/* - * Add a single IPv4 address or a prefix to a set. - * Returns 0 for success, non-zero for failure (allocation error). - * addr and mask are passed in network byte order, but immediately converted - * to host byte order for comparisons. - */ -static int -addrset_add_v4(struct addrset *asp, ipaddr_t addr, ipaddr_t mask) -{ - struct spannode **ptpn, *p; - uint32_t first, last; /* host byte order */ - - assert(asp->af == AF_INET); - - first = ntohl(addr & mask); - last = ntohl(addr | ~mask); - - /* - * Search through the list linearly, looking for either: an entry - * contiguous to the one being added (with which we will merge) or a - * discontiguous entry with a higher address (before which we will - * insert). If no match, we will append at the end. - */ - for (ptpn = &asp->head; (p = *ptpn) != NULL; ptpn = &p->next) { - if (first > 0 && first-1 > p->span.v4.last) - continue; - if (last == 0xFFFFFFFF || last+1 >= p->span.v4.first) { - /* Merge with this entry. */ - if (first < p->span.v4.first) - p->span.v4.first = first; - while (last > p->span.v4.last) { - struct spannode *next = p->next; - - if (next != NULL && - last >= next->span.v4.first - 1) { - /* Merge this span with the next. */ - p->span.v4.last = next->span.v4.last; - p->next = next->next; - free(next); - } else { - p->span.v4.last = last; - } - } - return (0); - } else { - /* Found the insertion point; exit the loop. */ - break; - } - } - - /* ptpn now points to the "previous next" where we need to insert. */ - - p = malloc(sizeof (*p)); - if (p == NULL) - return (1); - p->span.v4.first = first; - p->span.v4.last = last; - p->next = *ptpn; - *ptpn = p; - - return (0); -} - -/* - * Remove one range of IPv4 addresses from a set. - */ -static int -addrset_delete_v4(struct addrset *asp, uint32_t first, uint32_t last) -{ - struct spannode **ptpn, *p; - - /* - * Search through the list linearly, looking for any of: an entry - * entirely contained with the range being deleted (which we will - * delete from the list) or an entry overlapping the first address of - * the range (which we will truncate at its end) or an entry - * overlapping the last address of the range (which we will truncate at - * its beginning) or an entry which entirely contains the range being - * deleted plus at least one address beyond in each direction (which we - * will split into two entries) or an entry with a higher address than - * we are deleting (at which point we are done). - */ - for (ptpn = &asp->head; (p = *ptpn) != NULL; ptpn = &p->next) { - if (p->span.v4.first > last) - return (0); /* all done */ - if (p->span.v4.last < first) - continue; /* keep searching */ - while (p->span.v4.first >= first && - p->span.v4.last <= last) { - /* Delete a span entirely. */ - *ptpn = p->next; - free(p); - p = *ptpn; - if (p == NULL || p->span.v4.first > last) - return (0); /* all done */ - } - if (p->span.v4.first >= first) { - /* Truncate a span at its beginning. */ - p->span.v4.first = last + 1; - } else if (p->span.v4.last <= last) { - /* Truncate a span at its end. */ - p->span.v4.last = first - 1; - } else { - /* Split a span into two. */ - struct spannode *p2 = malloc(sizeof (*p2)); - if (p2 == NULL) - return (1); - p2->span.v4.first = last + 1; - p2->span.v4.last = p->span.v4.last; - p2->next = p->next; - p->span.v4.last = first - 1; - p->next = p2; - } - } - - return (0); -} - -/* - * Add a single IPv6 address or a prefix to a set. - * Returns 0 for success, non-zero for failure (allocation error). - * addr is passed in network byte order, but keep this order. - * prefixlen is the prefix length. - */ -static int -addrset_add_v6(struct addrset *asp, in6_addr_t addr, int prefixlen) -{ - struct spannode **ptpn, *p; - in6_addr_t first, last, temp; - const in6_addr_t ipv6_all_zeros = IN6ADDR_ANY_INIT; - const in6_addr_t ipv6_all_ones = { 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff }; - - assert(asp->af == AF_INET6); - assert((prefixlen >= 0) && (prefixlen <= 128)); - - first = addr; - last = addr; - IP6_FIRST(&first, prefixlen); - IP6_LAST(&last, prefixlen); - - /* - * Search through the list linearly, looking for either: an entry - * contiguous to the one being added (with which we will merge) or a - * discontiguous entry with a higher address (before which we will - * insert). If no match, we will append at the end. - */ - for (ptpn = &asp->head; (p = *ptpn) != NULL; ptpn = &p->next) { - temp = first; - IP6_DEC(&temp); - if (IP6_GT(&first, &ipv6_all_zeros) && - IP6_GT(&temp, &p->span.v6.last)) - continue; - temp = last; - IP6_INC(&temp); - if (IP6_EQ(&last, &ipv6_all_ones) || - IP6_GE(&temp, &p->span.v6.first)) { - /* Merge with this entry. */ - if (IP6_LT(&first, &p->span.v6.first)) - p->span.v6.first = first; - while (IP6_GT(&last, &p->span.v6.last)) { - struct spannode *next = p->next; - - if (next == NULL) { - p->span.v6.last = last; - break; - } - - temp = next->span.v6.first; - IP6_DEC(&temp); - if (IP6_GE(&last, &temp)) { - /* Merge this span with the next. */ - p->span.v6.last = next->span.v6.last; - p->next = next->next; - free(next); - } else { - p->span.v6.last = last; - } - } - return (0); - } else { - /* Found the insertion point; exit the loop. */ - break; - } - } - - /* ptpn now points to the "previous next" where we need to insert. */ - - p = malloc(sizeof (*p)); - if (p == NULL) - return (1); - p->span.v6.first = first; - p->span.v6.last = last; - p->next = *ptpn; - *ptpn = p; - - return (0); -} - -/* - * Remove one range of IPv6 addresses from a set. - */ -static int -addrset_delete_v6(struct addrset *asp, in6_addr_t first, in6_addr_t last) -{ - struct spannode **ptpn, *p; - in6_addr_t temp; - - /* - * Search through the list linearly, looking for any of: an entry - * entirely contained with the range being deleted (which we will - * delete from the list) or an entry overlapping the first address of - * the range (which we will truncate at its end) or an entry - * overlapping the last address of the range (which we will truncate at - * its beginning) or an entry which entirely contains the range being - * deleted plus at least one address beyond in each direction (which we - * will split into two entries) or an entry with a higher address than - * we are deleting (at which point we are done). - */ - for (ptpn = &asp->head; (p = *ptpn) != NULL; ptpn = &p->next) { - if (IP6_GT(&p->span.v6.first, &last)) - return (0); /* all done */ - if (IP6_LT(&p->span.v6.last, &first)) - continue; /* keep searching */ - while (IP6_GE(&p->span.v6.first, &first) && - IP6_LE(&p->span.v6.last, &last)) { - /* Delete a span entirely. */ - *ptpn = p->next; - free(p); - p = *ptpn; - if (p == NULL || IP6_GT(&p->span.v6.first, &last)) - return (0); /* all done */ - } - if (IP6_GE(&p->span.v6.first, &first)) { - /* Truncate a span at its beginning. */ - temp = last; - IP6_INC(&temp); - p->span.v6.first = temp; - } else if (IP6_LE(&p->span.v6.last, &last)) { - /* Truncate a span at its end. */ - temp = first; - IP6_DEC(&temp); - p->span.v6.last = temp; - } else { - /* Split a span into two. */ - struct spannode *p2 = malloc(sizeof (*p2)); - if (p2 == NULL) - return (1); - temp = last; - IP6_INC(&temp); - p2->span.v6.first = temp; - p2->span.v6.last = p->span.v6.last; - p2->next = p->next; - temp = first; - IP6_DEC(&temp); - p->span.v6.last = temp; - p->next = p2; - } - } - - return (0); -} - -/* - * Compute the set difference (remove elements in set 2 from set 1). - */ -static void -addrset_diff(struct addrset *asp1, struct addrset *asp2) -{ - struct spannode *p; - - if (asp1->af != asp2->af) - return; - - /* For each span in set 2, delete it from set 1. */ - if (asp1->af == AF_INET) - for (p = asp2->head; p; p = p->next) - (void) addrset_delete_v4(asp1, - p->span.v4.first, p->span.v4.last); - else if (asp1->af == AF_INET6) - for (p = asp2->head; p; p = p->next) - (void) addrset_delete_v6(asp1, - p->span.v6.first, p->span.v6.last); -} - - -typedef struct mib_item_s { - int group; - int mib_id; - void *valp; - size_t length; -} mib_item_t; - -static void mibload(int sd); -static void mibfree(mib_item_t *item); -static void mib_get_constants(mib_item_t *item); - -static int ipRouteEntrySize; -static int ipv6RouteEntrySize; - -static mib_item_t *ipv4Table; -static mib_item_t *ipv6Table; - -/* - * Copy and NUL-terminate a MIB octet-string. - */ -static void -octetstr(Octet_t *op, char *dst, uint_t dstlen) -{ - size_t n = MIN(dstlen - 1, op->o_length); - memcpy(dst, op->o_bytes, n); - dst[n] = '\0'; -} - -/* - * Read the whole IP MIB, looking for the routing related entries. - * Save the IPv4 and IPv6 route table items and peek into a couple other - * items to learn the increments between records in the route table items. - */ -static void -mibload(int sd) -{ - /* - * buf is an automatic for this function, so the - * compiler has complete control over its alignment; - * it is assumed this alignment is satisfactory for - * it to be casted to certain other struct pointers - * here, such as struct T_optmgmt_ack * . - */ - uintptr_t buf[512 / sizeof (uintptr_t)]; - int flags; - int j, getcode; - struct strbuf ctlbuf, databuf; - struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf; - struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf; - struct T_error_ack *tea = (struct T_error_ack *)buf; - struct opthdr *req; - mib_item_t *temp; - - ipv4Table = NULL; - ipv6Table = NULL; - - tor->PRIM_type = T_SVR4_OPTMGMT_REQ; - tor->OPT_offset = sizeof (struct T_optmgmt_req); - tor->OPT_length = sizeof (struct opthdr); - tor->MGMT_flags = T_CURRENT; - req = (struct opthdr *)&tor[1]; - req->level = MIB2_IP; /* any MIB2_xxx value ok here */ - req->name = 0; - req->len = 0; - - ctlbuf.buf = (char *)buf; - ctlbuf.len = tor->OPT_length + tor->OPT_offset; - flags = 0; - if (putmsg(sd, &ctlbuf, (struct strbuf *)0, flags) == -1) { - perror("mibget: putmsg(ctl) failed"); - goto error_exit; - } - - /* - * Each reply consists of a ctl part for one fixed structure - * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK, - * containing an opthdr structure. level/name identify the entry, - * len is the size of the data part of the message. - */ - req = (struct opthdr *)&toa[1]; - ctlbuf.maxlen = sizeof (buf); - j = 1; - for (;;) { - flags = 0; - getcode = getmsg(sd, &ctlbuf, (struct strbuf *)0, &flags); - if (getcode == -1) { - perror("mibget getmsg(ctl) failed"); - goto error_exit; - } - if (getcode == 0 && - ctlbuf.len >= sizeof (struct T_optmgmt_ack) && - toa->PRIM_type == T_OPTMGMT_ACK && - toa->MGMT_flags == T_SUCCESS && - req->len == 0) - return; - - if (ctlbuf.len >= sizeof (struct T_error_ack) && - tea->PRIM_type == T_ERROR_ACK) { - (void) fprintf(stderr, - "mibget %d gives T_ERROR_ACK: TLI_error = 0x%lx, " - "UNIX_error = 0x%lx\n", - j, tea->TLI_error, tea->UNIX_error); - - errno = (tea->TLI_error == TSYSERR) ? - tea->UNIX_error : EPROTO; - goto error_exit; - } - - if (getcode != MOREDATA || - ctlbuf.len < sizeof (struct T_optmgmt_ack) || - toa->PRIM_type != T_OPTMGMT_ACK || - toa->MGMT_flags != T_SUCCESS) { - (void) printf("mibget getmsg(ctl) %d returned %d, " - "ctlbuf.len = %d, PRIM_type = %ld\n", - j, getcode, ctlbuf.len, toa->PRIM_type); - - if (toa->PRIM_type == T_OPTMGMT_ACK) - (void) printf("T_OPTMGMT_ACK: " - "MGMT_flags = 0x%lx, req->len = %ld\n", - toa->MGMT_flags, req->len); - errno = ENOMSG; - goto error_exit; - } - - temp = malloc(sizeof (mib_item_t)); - if (temp == NULL) { - perror("mibget malloc failed"); - goto error_exit; - } - temp->group = req->level; - temp->mib_id = req->name; - temp->length = req->len; - temp->valp = malloc(req->len); - if (temp->valp == NULL) { - free(temp); - goto error_exit; - } - - databuf.maxlen = temp->length; - databuf.buf = temp->valp; - databuf.len = 0; - flags = 0; - getcode = getmsg(sd, (struct strbuf *)0, &databuf, &flags); - if (getcode == -1) { - perror("mibload getmsg(data) failed"); - mibfree(temp); - goto error_exit; - } else if (getcode != 0) { - (void) printf("mibload getmsg(data) returned %d, " - "databuf.maxlen = %d, databuf.len = %d\n", - getcode, databuf.maxlen, databuf.len); - mibfree(temp); - goto error_exit; - } - - j++; - - if (temp->group != MIB2_IP && - temp->group != MIB2_IP6) { - mibfree(temp); - continue; - } - - switch (temp->mib_id) { - case MIB2_IP_ROUTE: - if (ipv4Table) - mibfree(ipv4Table); - ipv4Table = temp; - break; - case MIB2_IP6_ROUTE: - if (ipv6Table) - mibfree(ipv6Table); - ipv6Table = temp; - break; - case 0: - mib_get_constants(temp); - /* FALLTHROUGH */ - default: - mibfree(temp); - break; - } - } - /* NOTREACHED */ - -error_exit:; -} - -/* - * mibfree: frees a (mib_item_t *) loaded by mibload() - */ -static void -mibfree(mib_item_t *item) -{ - if (item->valp != NULL) - free(item->valp); - free(item); -} - -#define IPROUTEENTRYALIGNMENT 4 -#define IP6ROUTEENTRYALIGNMENT 4 - -/* Extract constant sizes. */ -static void -mib_get_constants(mib_item_t *item) -{ - switch (item->group) { - case MIB2_IP: { - mib2_ip_t *ip = item->valp; - - ipRouteEntrySize = ip->ipRouteEntrySize; - assert(IS_P2ALIGNED(ipRouteEntrySize, IPROUTEENTRYALIGNMENT)); - break; - } - case MIB2_IP6: { - mib2_ipv6IfStatsEntry_t *ip6 = item->valp; - /* Just use the first entry */ - - ipv6RouteEntrySize = ip6->ipv6RouteEntrySize; - assert(IS_P2ALIGNED(ipv6RouteEntrySize, - IP6ROUTEENTRYALIGNMENT)); - break; - } - } -} - - -/* - * Compose a PFILCMD_IFADDRSET message for each interface and deliver them to - * pfil. Returns 0 for success, non-zero for failure. - */ -static int -pfil_ifaddrset_msg(struct addrset **ifs, int numifs) -{ - int status = 0, i; - struct pfil_ifaddrset *ifaddrset = NULL; - - for (i = 0; i < numifs; i++) - if (ifs[i]->af == AF_INET) { - struct spannode *p1; - struct pfil_v4span *p2; - int nspans = 0; - size_t size; - - for (p1 = ifs[i]->head; p1; p1 = p1->next) - nspans++; - size = sizeof (struct pfil_ifaddrset) + - nspans * sizeof (struct pfil_v4span); - ifaddrset = realloc(ifaddrset, size); - if (ifaddrset == NULL) - return (-1); - - (void) strlcpy(ifaddrset->name, ifs[i]->name, - LIFNAMSIZ); - ifaddrset->af = ifs[i]->af; - ifaddrset->nspans = nspans; - p2 = (struct pfil_v4span *)(ifaddrset + 1); - for (p1 = ifs[i]->head; p1; p1 = p1->next) { - p2->first = p1->span.v4.first; - p2->last = p1->span.v4.last; - ++p2; - } - - status = pfil_msg(PFILCMD_IFADDRSET, ifaddrset, size); - if (status != 0) - break; - } else if (ifs[i]->af == AF_INET6) { - struct spannode *p1; - struct pfil_v6span *p2; - int nspans = 0; - size_t size; - - for (p1 = ifs[i]->head; p1; p1 = p1->next) - nspans++; - size = sizeof (struct pfil_ifaddrset) + - nspans * sizeof (struct pfil_v6span); - ifaddrset = realloc(ifaddrset, size); - if (ifaddrset == NULL) - return (-1); - - (void) strlcpy(ifaddrset->name, ifs[i]->name, - LIFNAMSIZ); - ifaddrset->af = ifs[i]->af; - ifaddrset->nspans = nspans; - p2 = (struct pfil_v6span *)(ifaddrset + 1); - for (p1 = ifs[i]->head; p1; p1 = p1->next) { - p2->first = p1->span.v6.first; - p2->last = p1->span.v6.last; - ++p2; - } - - status = pfil_msg(PFILCMD_IFADDRSET, ifaddrset, size); - if (status != 0) - break; - } - - if (ifaddrset != NULL) - free(ifaddrset); - - return (status); -} - -/* - * Find an interface through which the gateway is reachable and return its - * name in the specififed buffer. - */ -static void -findgwif_v4(in_addr_t gw, char outif[], size_t size) -{ - mib2_ipRouteEntry_t *rp; - - for (rp = ipv4Table->valp; - (char *)rp < (char *)ipv4Table->valp + ipv4Table->length; - rp = (mib2_ipRouteEntry_t *) - ((char *)rp + ipRouteEntrySize)) { - if ((rp->ipRouteInfo.re_ire_type & IRE_INTERFACE) && - (rp->ipRouteIfIndex.o_length > 0) && - ((gw & rp->ipRouteMask) == rp->ipRouteDest)) { - octetstr(&rp->ipRouteIfIndex, - outif, size); - return; - } - } - outif[0] = '\0'; -} - -/* - * Find an interface through which the gateway is reachable and return its - * name in the specififed buffer. - */ -static void -findgwif_v6(in6_addr_t gw, char outif[], size_t size) -{ - mib2_ipv6RouteEntry_t *rp; - in6_addr_t temp; - - for (rp = ipv6Table->valp; - (char *)rp < (char *)ipv6Table->valp + ipv6Table->length; - rp = (mib2_ipv6RouteEntry_t *) - ((char *)rp + ipv6RouteEntrySize)) { - temp = gw; - IP6_FIRST(&temp, rp->ipv6RoutePfxLength); - if ((rp->ipv6RouteInfo.re_ire_type & IRE_INTERFACE) && - (rp->ipv6RouteIfIndex.o_length > 0) && - (IP6_EQ(&temp, &rp->ipv6RouteDest))) { - octetstr(&rp->ipv6RouteIfIndex, - outif, size); - return; - } - } - outif[0] = '\0'; -} - -/* - * Compute the valid address sets for the specified interfaces, then compose a - * series of PFILCMD_IFADDRSET messages and deliver them to pfil. Returns 0 for - * success, non-zero for failure. - */ -int -vas(const struct pfil_ifaddrs *ifaddrlist, int numifs) -{ - const in6_addr_t ipv6_unspecified = IN6ADDR_ANY_INIT; - const in6_addr_t ipv6_loopback_addr = IN6ADDR_LOOPBACK_INIT; - const in6_addr_t ipv6_multi_addr = { 0xffU, 0x00U, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 }; - - struct addrset **ifs = NULL, *illegal_v4 = NULL, *illegal_v6 = NULL; - int sd, i, status; - - sd = open("/dev/arp", O_RDWR); - if (sd == -1) - return (-1); - mibload(sd); - (void) close(sd); - - ifs = calloc(numifs, sizeof (*ifs)); - if (ifs == NULL) - goto err; - for (i = 0; i < numifs; i++) { - /* - * in.sin_family works for in6.sin6_family too. - * Both are located in the same address. - */ - ifs[i] = new_addrset(ifaddrlist[i].name, - ifaddrlist[i].localaddr.in.sin_family); - if (ifs[i] == NULL) - goto err; - } - - illegal_v4 = new_addrset("[illegal]", AF_INET); - if (illegal_v4 == NULL) - goto err; - - /* Multicast addresses are always illegal as source address. */ - if (addrset_add_v4(illegal_v4, - htonl(INADDR_UNSPEC_GROUP), htonl(IN_CLASSD_NET))) - goto err; - - /* Loopback addresses are illegal on non-loopback interfaces. */ - if (addrset_add_v4(illegal_v4, - htonl(INADDR_LOOPBACK), htonl(IN_CLASSA_NET))) - goto err; - - illegal_v6 = new_addrset("[illegal]", AF_INET6); - if (illegal_v6 == NULL) - goto err; - - /* Multicast addresses are always illegal as source address. */ - if (addrset_add_v6(illegal_v6, ipv6_multi_addr, 8)) - goto err; - - /* Loopback addresses are illegal on non-loopback interfaces. */ - if (addrset_add_v6(illegal_v6, ipv6_loopback_addr, 128)) - goto err; - - /* Unspecified addresses are always illegal as source address. */ - if (addrset_add_v6(illegal_v6, ipv6_unspecified, 128)) - goto err; - - if (ipRouteEntrySize < sizeof (mib2_ipRouteEntry_t) || - ipv6RouteEntrySize < sizeof (mib2_ipv6RouteEntry_t) || - (!ipv4Table && !ipv6Table)) { - errno = ENOENT; -err: - status = -1; - goto done; - } - - if (ipv4Table != NULL) { - mib2_ipRouteEntry_t *rp; - - for (rp = ipv4Table->valp; - (char *)rp < (char *)ipv4Table->valp + ipv4Table->length; - rp = (mib2_ipRouteEntry_t *) - ((char *)rp + ipRouteEntrySize)) { - struct addrset *asp = NULL; - char outif[LIFNAMSIZ + 1]; - - switch (rp->ipRouteInfo.re_ire_type) { - case IRE_CACHE: - continue; - case IRE_BROADCAST: - case IRE_LOCAL: - asp = illegal_v4; - break; - default: - if (rp->ipRouteIfIndex.o_length > 0) { - octetstr(&rp->ipRouteIfIndex, - outif, sizeof (outif)); - } else { - findgwif_v4(rp->ipRouteNextHop, - outif, sizeof (outif)); - } - if (outif[0] != '\0') { - for (i = 0; i < numifs; i++) { - if (ifs[i]->af == AF_INET && - strncmp(outif, ifs[i]->name, - LIFNAMSIZ) == 0) { - asp = ifs[i]; - break; - } - } - } - break; - } - if (asp != NULL && - addrset_add_v4(asp, - rp->ipRouteDest, rp->ipRouteMask) != 0) - goto err; - } - } - - if (ipv6Table != NULL) { - mib2_ipv6RouteEntry_t *rp; - - for (rp = ipv6Table->valp; - (char *)rp < (char *)ipv6Table->valp + ipv6Table->length; - rp = (mib2_ipv6RouteEntry_t *) - ((char *)rp + ipv6RouteEntrySize)) { - struct addrset *asp = NULL; - char outif[LIFNAMSIZ + 1]; - - switch (rp->ipv6RouteInfo.re_ire_type) { - case IRE_CACHE: - continue; - case IRE_BROADCAST: - case IRE_LOCAL: - asp = illegal_v6; - break; - default: - if (rp->ipv6RouteIfIndex.o_length > 0) { - octetstr(&rp->ipv6RouteIfIndex, - outif, sizeof (outif)); - } else { - findgwif_v6(rp->ipv6RouteNextHop, - outif, sizeof (outif)); - } - if (outif[0] != '\0') { - for (i = 0; i < numifs; i++) { - if (ifs[i]->af == AF_INET6 && - strncmp(outif, ifs[i]->name, - LIFNAMSIZ) == 0) { - asp = ifs[i]; - break; - } - } - } - break; - } - if (asp != NULL && - addrset_add_v6(asp, rp->ipv6RouteDest, - rp->ipv6RoutePfxLength) != 0) - goto err; - } - } - - for (i = 0; i < numifs; i++) { - if (ifs[i]->af == AF_INET) - addrset_diff(ifs[i], illegal_v4); - else if (ifs[i]->af == AF_INET6) - addrset_diff(ifs[i], illegal_v6); - } - - status = pfil_ifaddrset_msg(ifs, numifs); -#ifdef DEBUG - pfil_ifaddrset_msg(&illegal_v4, 1); - pfil_ifaddrset_msg(&illegal_v6, 1); -#endif - -done: - if (ipv4Table != NULL) - mibfree(ipv4Table); - if (ipv6Table != NULL) - mibfree(ipv6Table); - - for (i = 0; i < numifs; i++) - if (ifs[i] != NULL) - delete_addrset(ifs[i]); - free(ifs); - if (illegal_v4 != NULL) - delete_addrset(illegal_v4); - if (illegal_v6 != NULL) - delete_addrset(illegal_v6); - - return (status); -} - -#ifdef DEBUG -static void -fatal(int errcode, char *format, ...) -{ - va_list argp; - - if (format == NULL) - return; - - va_start(argp, format); - (void) vfprintf(stderr, format, argp); - va_end(argp); - - exit(errcode); -} - -static void -pr_span(uint8_t af, const struct spannode *p, char *buf, size_t size) -{ - char buf1[INET6_ADDRSTRLEN], buf2[INET6_ADDRSTRLEN]; - - if (af == AF_INET) { - ipaddr_t addr; - - addr = htonl(p->span.v4.first); - (void) inet_ntop(AF_INET, &addr, buf1, sizeof (buf1)); - - if (p->span.v4.first == p->span.v4.last) { - (void) strncpy(buf, buf1, size); - } else { - addr = htonl(p->span.v4.last); - (void) inet_ntop(AF_INET, &addr, buf2, sizeof (buf2)); - (void) snprintf(buf, size, "%s - %s", buf1, buf2); - } - } else if (af == AF_INET6) { - in6_addr_t addr6; - - addr6 = p->span.v6.first; - (void) inet_ntop(AF_INET6, &addr6, buf1, sizeof (buf1)); - - if (IP6_EQ(&p->span.v6.first, &p->span.v6.last)) { - (void) strncpy(buf, buf1, size); - } else { - addr6 = p->span.v6.last; - (void) inet_ntop(AF_INET6, &addr6, buf2, sizeof (buf2)); - (void) snprintf(buf, size, "%s - %s", buf1, buf2); - } - } -} - -static void -pr_addrset(const struct addrset *asp) -{ - struct spannode *p; - - (void) printf("addrset %s (%u):\n", asp->name, asp->af); - - if (asp->head == 0) { - (void) puts(" [empty]"); - return; - } - - p = asp->head; - while (p != NULL) { - char buf[100]; - - (void) putchar(' '); - pr_span(asp->af, p, buf, sizeof (buf)); - (void) fputs(buf, stdout); - if (p->next) - (void) putchar(','); - p = p->next; - } - (void) putchar('\n'); -} - -static void -pr_ifaddrset(const struct pfil_ifaddrset *asp) -{ - int i; - - (void) printf("addrset %s (%u):\n", asp->name, asp->af); - - if (asp->nspans == 0) { - (void) puts(" [empty]"); - return; - } - - if (asp->af == AF_INET) { - struct pfil_v4span *p = (struct pfil_v4span *)(asp + 1); - - for (i = 0; i < asp->nspans; i++) { - ipaddr_t addr; - char buf[INET_ADDRSTRLEN]; - - addr = htonl(p->first); - (void) inet_ntop(AF_INET, &addr, buf, sizeof (buf)); - (void) printf(" %s", buf); - - if (p->first != p->last) { - addr = htonl(p->last); - (void) inet_ntop(AF_INET, &addr, - buf, sizeof (buf)); - (void) printf(" - %s", buf); - } - - if (i+1 < asp->nspans) - (void) putchar(','); - p++; - } - (void) putchar('\n'); - } else if (asp->af == AF_INET6) { - struct pfil_v6span *p = (struct pfil_v6span *)(asp + 1); - - for (i = 0; i < asp->nspans; i++) { - char buf[INET6_ADDRSTRLEN]; - - (void) inet_ntop(AF_INET6, &p->first, - buf, sizeof (buf)); - (void) printf(" %s", buf); - - if (!IP6_EQ(&p->first, &p->last)) { - (void) inet_ntop(AF_INET6, &p->last, - buf, sizeof (buf)); - (void) printf(" - %s", buf); - } - - if (i + 1 < asp->nspans) - (void) putchar(','); - p++; - } - (void) putchar('\n'); - } -} - -int -pfil_msg(uint32_t cmd, void *buf, size_t len) -{ - struct pfil_ifaddrset *ifaddrset = buf; - pr_ifaddrset(ifaddrset); - return (0); -} - -int -main(int argc, char *argv[]) -{ - int numifs, i; - struct pfil_ifaddrs *ifaddrlist; - - numifs = argc-1; - if ((ifaddrlist = calloc(numifs, sizeof (ifaddrlist[0]))) == NULL) - return (-1); - - for (i = 0; i < numifs; i++) { - (void) strlcpy(ifaddrlist[i].name, argv[i+1], LIFNAMSIZ); - ifaddrlist[i].localaddr.in.sin_family = AF_INET; - } - - if (vas(ifaddrlist, numifs) != 0) { - free(ifaddrlist); - return (-1); - } - - for (i = 0; i < numifs; i++) { - (void) strlcpy(ifaddrlist[i].name, argv[i+1], LIFNAMSIZ); - ifaddrlist[i].localaddr.in6.sin6_family = AF_INET6; - } - if (vas(ifaddrlist, numifs) != 0) { - free(ifaddrlist); - return (-1); - } - - free(ifaddrlist); - return (0); -} -#endif diff --git a/usr/src/cmd/ipf/svc/Makefile b/usr/src/cmd/ipf/svc/Makefile index ec1c98c92d..403db5ce4e 100644 --- a/usr/src/cmd/ipf/svc/Makefile +++ b/usr/src/cmd/ipf/svc/Makefile @@ -1,12 +1,32 @@ # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -MANIFEST= ipfilter.xml pfil.xml -SVCMETHOD= ipfilter pfil +MANIFEST= ipfilter.xml +SVCMETHOD= ipfilter include $(SRC)/cmd/Makefile.cmd diff --git a/usr/src/cmd/ipf/svc/ipfilter b/usr/src/cmd/ipf/svc/ipfilter index 97a7d704d8..a34efe3781 100644 --- a/usr/src/cmd/ipf/svc/ipfilter +++ b/usr/src/cmd/ipf/svc/ipfilter @@ -1,5 +1,25 @@ #!/sbin/sh # +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# # ident "%Z%%M% %I% %E% SMI" # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. @@ -22,7 +42,6 @@ if [ -f $PIDFILE ] ; then else pid=`pgrep ipmon` fi -pfildpid=`pgrep pfild` logmsg() { @@ -30,31 +49,9 @@ logmsg() echo "$1" >&2 } -checkpfil() -{ - if [ $PFILCHECKED = yes ] ; then - return - fi - /usr/sbin/ndd /dev/pfil \? 2>&1 > /dev/null - if [ $? -ne 0 ] ; then - logmsg "pfil not available to support ipfilter" - exit $SMF_EXIT_ERR_CONFIG - fi - realnic=`/sbin/ifconfig -a modlist 2>/dev/null | grep -c pfil` - if [ $realnic -eq 0 ] ; then - logmsg "pfil not plumbed on any network interfaces." - logmsg "No network traffic will be filtered." - logmsg "See ipfilter(5) for more information." - exit $SMF_EXIT_ERR_CONFIG - fi - PFILCHECKED=yes -} - - load_ipf() { bad=0 if [ -r ${IPFILCONF} ]; then - checkpfil ipf -IFa -f ${IPFILCONF} >/dev/null if [ $? != 0 ]; then echo "$0: load of ${IPFILCONF} into alternate set failed" @@ -62,7 +59,6 @@ load_ipf() { fi fi if [ -r ${IP6FILCONF} ]; then - checkpfil ipf -6IFa -f ${IP6FILCONF} >/dev/null if [ $? != 0 ]; then echo "$0: load of ${IPFILCONF} into alternate set failed" @@ -81,7 +77,6 @@ load_ipf() { load_ipnat() { if [ -r ${IPNATCONF} ]; then - checkpfil ipnat -CF -f ${IPNATCONF} >/dev/null if [ $? != 0 ]; then echo "$0: load of ${IPNATCONF} failed" @@ -98,7 +93,6 @@ load_ipnat() { load_ippool() { if [ -r ${IPPOOLCONF} ]; then - checkpfil ippool -F >/dev/null ippool -f ${IPPOOLCONF} >/dev/null if [ $? != 0 ]; then @@ -116,9 +110,7 @@ load_ippool() { case "$1" in start) [ ! -f ${IPFILCONF} ] && exit 0 - [ -n "$pfildpid" ] && kill -TERM $pfildpid 2>/dev/null [ -n "$pid" ] && kill -TERM $pid 2>/dev/null - /usr/sbin/pfild >/dev/null if load_ippool && load_ipf && load_ipnat ; then /usr/sbin/ipmon -Ds else @@ -127,7 +119,6 @@ case "$1" in ;; stop) - [ -n "$pfildpid" ] && kill -TERM $pfildpid [ -n "$pid" ] && kill -TERM $pid ;; diff --git a/usr/src/cmd/ipf/svc/ipfilter.xml b/usr/src/cmd/ipf/svc/ipfilter.xml index 81fddd2809..f9d34ea7d9 100644 --- a/usr/src/cmd/ipf/svc/ipfilter.xml +++ b/usr/src/cmd/ipf/svc/ipfilter.xml @@ -1,8 +1,27 @@ <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- - Copyright 2004 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. + Copyright 2006 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + 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] + + CDDL HEADER END ident "%Z%%M% %I% %E% SMI" @@ -42,14 +61,6 @@ </dependency> <dependency - name='pfil' - grouping='require_all' - restart_on='restart' - type='service'> - <service_fmri value='svc:/network/pfil' /> - </dependency> - - <dependency name='physical' grouping='require_all' restart_on='restart' diff --git a/usr/src/cmd/ipf/svc/pfil b/usr/src/cmd/ipf/svc/pfil deleted file mode 100755 index b2db444ffe..0000000000 --- a/usr/src/cmd/ipf/svc/pfil +++ /dev/null @@ -1,43 +0,0 @@ -#!/sbin/sh -# -# ident "%Z%%M% %I% %E% SMI" -# -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -# -# Autopush pfil on to filtering interfaces and restrict -# network traffic during startup -# - - -PFILAP=/etc/ipf/pfil.ap - -case "$1" in -'start') - /sbin/autopush -f ${PFILAP} - enabled=`svcprop -c -p general/enabled svc:/network/ipfilter:default` - - # To avoid a window of vulnerability during the time that networking - # is being initialized but before the full ipf.conf configuration is - # loaded, install a temporary, restrictive rule set now, early in - # boot. This gets replaced by the contents of ipf.conf when the - # svc:/network/ipfilter service is started. Note that if /usr is not - # mounted, the window of vulnerability still exists because we can't - # run the ipf command this early. - - if [ -x /usr/sbin/ipf ] && [ "$enabled" = "true" ]; then - echo "block in all" | /usr/sbin/ipf -Fa -f - - echo "block out all" | /usr/sbin/ipf -f - - echo "pass out from any to any port = 53 keep state" \ - | /usr/sbin/ipf -f - - fi - ;; - -*) - echo "Usage: $0 start" - exit 1 - ;; -esac -exit 0 diff --git a/usr/src/cmd/ipf/svc/pfil.xml b/usr/src/cmd/ipf/svc/pfil.xml deleted file mode 100644 index 7d69af24b2..0000000000 --- a/usr/src/cmd/ipf/svc/pfil.xml +++ /dev/null @@ -1,86 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> -<!-- - Copyright 2004 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. - - ident "%Z%%M% %I% %E% SMI" - - NOTE: This service manifest is not editable; its contents will - be overwritten by package or patch operations, including - operating system upgrade. Make customizations in a different - file. - - Service manifest for the pfil (packet filter) service. ---> - -<service_bundle type='manifest' name='SUNWipfr:pfil'> - -<service - name='network/pfil' - type='service' - version='1'> - - <create_default_instance enabled='true' /> - - <single_instance /> - - <dependent - name='pfil_network' - grouping='optional_all' - restart_on='none'> - <service_fmri value='svc:/network/physical' /> - </dependent> - - <dependent - name='pfil_sysid' - grouping='optional_all' - restart_on='none'> - <service_fmri value='svc:/system/sysidtool:net' /> - </dependent> - - <!-- - The stop method really should deconfigure pfil from sad(7D), - but autopush(1M) doesn't have the ability to remove entries - based on a file in the same format as it uses to add them. - --> - <exec_method - type='method' - name='stop' - exec=':true' - timeout_seconds='0' > - </exec_method> - - <exec_method - type='method' - name='start' - exec='/lib/svc/method/pfil start' - timeout_seconds='0' > - </exec_method> - - <property_group - name='startd' - type='framework'> - <propval name='duration' type='astring' value='transient' /> - </property_group> - - <stability value='Unstable' /> - - <template> - <common_name> - <loctext xml:lang='C'>packet filter</loctext> - </common_name> - <description> - <loctext xml:lang='C'> - Packet filter interface; autopushes the pfil STREAMS - module on network devices. - </loctext> - </description> - <documentation> - <manpage title='ipfilter' section='5' - manpath='/usr/share/man' /> - </documentation> - </template> -</service> - -</service_bundle> diff --git a/usr/src/cmd/ipf/tools/ip_fil.c b/usr/src/cmd/ipf/tools/ip_fil.c index 0011968b9a..4aaa9935be 100644 --- a/usr/src/cmd/ipf/tools/ip_fil.c +++ b/usr/src/cmd/ipf/tools/ip_fil.c @@ -410,7 +410,7 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - frsync(NULL); + frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL); } break; default : @@ -455,7 +455,7 @@ void *ifp; f->fr_ifa = (void *)-1; #endif RWLOCK_EXIT(&ipf_mutex); - fr_natsync(ifp); + fr_natifpsync(IPFSYNC_OLDIFP, ifp, NULL); } @@ -614,7 +614,7 @@ int v; *addr++ = '\0'; for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { - COPYIFNAME(ifp, ifname); + COPYIFNAME(ifp, ifname, 0); if (!strcmp(name, ifname)) { if (addr != NULL) fr_setifpaddr(ifp, addr); @@ -781,8 +781,10 @@ int dst; } -void frsync(ifp) -void *ifp; +void frsync(command, version, nic, data) +int command, version; +void *nic; +char *data; { return; } diff --git a/usr/src/cmd/ipf/tools/ipf_y.y b/usr/src/cmd/ipf/tools/ipf_y.y index 93e6d27da9..940790493a 100644 --- a/usr/src/cmd/ipf/tools/ipf_y.y +++ b/usr/src/cmd/ipf/tools/ipf_y.y @@ -177,6 +177,7 @@ static int set_ipv6_addr = 0; %token IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN %token IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG +%token IPFY_SET_LOOPBACK IPFY_SET %% file: line | assign @@ -194,6 +195,7 @@ line: xx rule { while ((fr = frtop) != NULL) { resetlexer(); } | YY_COMMENT + | set ; xx: { newrule(); } @@ -210,6 +212,28 @@ assigning: '=' { yyvarnext = 1; } ; +set: + IPFY_SET IPFY_SET_LOOPBACK YY_STR ';' + { + int data; + if (frold != NULL) { + yyerror("ipf rules before \"set\""); + return 0; + } + if (!strcmp($3, "true")) + data = 1; + else if (!strcmp($3, "false")) + data = 0; + else { + yyerror("invalid argument for ipf_loopback"); + return 0; + } + if (((opts & OPT_DONOTHING) == 0) && + (ioctl(ipffd, SIOCIPFLP, &data) == -1)) + perror("ioctl(SIOCIPFLP)"); + } + ; + rule: inrule eol | outrule eol ; @@ -1560,6 +1584,7 @@ static struct wordtab ipfwords[95] = { { "icmp-type", IPFY_ICMPTYPE }, { "in", IPFY_IN }, { "in-via", IPFY_INVIA }, + { "intercept_loopback", IPFY_SET_LOOPBACK }, { "ipopt", IPFY_IPOPTS }, { "ipopts", IPFY_IPOPTS }, { "keep", IPFY_KEEP }, @@ -1600,6 +1625,7 @@ static struct wordtab ipfwords[95] = { { "route-to", IPFY_ROUTETO }, { "sec-class", IPFY_SECCLASS }, { "set-tag", IPFY_SETTAG }, + { "set", IPFY_SET }, { "skip", IPFY_SKIP }, { "short", IPFY_SHORT }, { "state", IPFY_STATE }, diff --git a/usr/src/cmd/mdb/Makefile.common b/usr/src/cmd/mdb/Makefile.common index 329176e35b..4f2adfeb9b 100644 --- a/usr/src/cmd/mdb/Makefile.common +++ b/usr/src/cmd/mdb/Makefile.common @@ -57,6 +57,8 @@ COMMON_MODULES_KVM = \ crypto \ dtrace \ genunix \ + hook \ + neti \ ip \ ipc \ ipp \ diff --git a/usr/src/cmd/mdb/common/modules/arp/arp.c b/usr/src/cmd/mdb/common/modules/arp/arp.c index 06bd8887e0..c02c20a268 100644 --- a/usr/src/cmd/mdb/common/modules/arp/arp.c +++ b/usr/src/cmd/mdb/common/modules/arp/arp.c @@ -30,6 +30,8 @@ #include <sys/stropts.h> #include <sys/stream.h> #include <sys/dlpi.h> +#include <sys/hook.h> +#include <sys/hook_event.h> #include <inet/led.h> #include <inet/common.h> #include <inet/mi.h> diff --git a/usr/src/cmd/mdb/common/modules/hook/hook.c b/usr/src/cmd/mdb/common/modules/hook/hook.c new file mode 100644 index 0000000000..d9ab29eb24 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/hook/hook.c @@ -0,0 +1,252 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/rwlock.h> +#include <mdb/mdb_modapi.h> +#include <sys/queue.h> +#include <sys/hook.h> +#include <sys/hook_impl.h> + +#define MAX_LENGTH 64 + +/* + * List pfhooks hook list information. + */ +/*ARGSUSED*/ +int +hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + hook_event_int_t hr; + hook_int_t hl, *hlp; + char hrstr[MAX_LENGTH]; + GElf_Sym sym; + char buf[MDB_SYM_NAMLEN + 1]; + + if (argc) + return (DCMD_USAGE); + + if (mdb_vread((void *)&hr, sizeof (hr), (uintptr_t)addr) == -1) { + mdb_warn("couldn't read hook register at %p", addr); + return (DCMD_ERR); + } + + mdb_printf("%<u>%?s %10s %20s %?s%</u>\n", + "ADDR", "FLAG", "FUNC", "NAME"); + hlp = TAILQ_FIRST(&hr.hei_head); + while (hlp) { + if (mdb_vread((void *)&hl, sizeof (hl), + (uintptr_t)hlp) == -1) { + mdb_warn("couldn't read hook list at %p", + hlp); + return (DCMD_ERR); + } + if (!hl.hi_hook.h_name) { + mdb_warn("hook list at %p has null role", + hl.hi_hook); + return (DCMD_ERR); + } + if (mdb_readstr((char *)hrstr, sizeof (hrstr), + (uintptr_t)hl.hi_hook.h_name) == -1) { + mdb_warn("couldn't read list role at %p", + hl.hi_hook.h_name); + return (DCMD_ERR); + } + if (mdb_lookup_by_addr((uintptr_t)hl.hi_hook.h_func, + MDB_SYM_EXACT, buf, sizeof (buf), &sym) == -1) + mdb_printf("%0?p %10x %0?p %10s\n", + hlp, hl.hi_hook.h_flags, hl.hi_hook.h_func, hrstr); + else + mdb_printf("%0?p %10x %20s %10s\n", + hlp, hl.hi_hook.h_flags, buf, hrstr); + hlp = TAILQ_NEXT(&hl, hi_entry); + } + return (DCMD_OK); +} + + +/* + * List pfhooks event information. + * List the hooks information in verbose mode as well. + */ +/*ARGSUSED*/ +int +hookeventlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + hook_family_int_t hf; + hook_event_int_t hr, *hrp; + hook_event_t hp; + char hprstr[MAX_LENGTH]; + + if (argc) + return (DCMD_USAGE); + + if (mdb_vread((void *)&hf, sizeof (hf), (uintptr_t)addr) == -1) { + mdb_warn("couldn't read hook family at %p", addr); + return (DCMD_ERR); + } + + mdb_printf("%<u>%?s %10s %20s%</u>\n", "ADDR", "FLAG", "NAME"); + hrp = SLIST_FIRST(&hf.hfi_head); + while (hrp) { + if (mdb_vread((void *)&hr, sizeof (hr), (uintptr_t)hrp) == -1) { + mdb_warn("couldn't read hook register at %p", hrp); + return (DCMD_ERR); + } + if (!hr.hei_event) { + mdb_warn("hook register at %p has no hook provider", + hrp); + return (DCMD_ERR); + } + if (mdb_vread((void *)&hp, sizeof (hp), + (uintptr_t)hr.hei_event) == -1) { + mdb_warn("hook provider at %p has null role", + hr.hei_event); + return (DCMD_ERR); + } + if (!hp.he_name) { + mdb_warn("hook provider at %p has null role", + hr.hei_event); + return (DCMD_ERR); + } + if (mdb_readstr((char *)hprstr, sizeof (hprstr), + (uintptr_t)hp.he_name) == -1) { + mdb_warn("couldn't read provider role at %p", + hp.he_name); + return (DCMD_ERR); + } + mdb_printf("%0?p %10x %20s\n", hrp, hp.he_flags, hprstr); + hrp = SLIST_NEXT(&hr, hei_entry); + } + + return (DCMD_OK); +} + +/* + * List pfhooks family information. + */ +/*ARGSUSED*/ +int +hookrootlist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + hook_family_int_head_t hfh; + hook_family_int_t hf, *hfp; + char hrrstr[MAX_LENGTH]; + + if (argc) + return (DCMD_USAGE); + + if (mdb_readvar(&hfh, "familylist") == -1) { + mdb_warn("couldn't read symbol 'familylist'"); + return (DCMD_ERR); + } + + mdb_printf("%<u>%?s %10s%</u>\n", "ADDR", "FAMILY"); + hfp = SLIST_FIRST(&hfh); + while (hfp) { + if (mdb_vread((void *)&hf, sizeof (hf), (uintptr_t)hfp) == -1) { + mdb_warn("couldn't read hook family at %p", hfp); + return (DCMD_ERR); + } + if (!hf.hfi_family.hf_name) { + mdb_warn("hook root at %p has null role", + hf.hfi_family); + return (DCMD_ERR); + } + if (mdb_readstr((char *)hrrstr, sizeof (hrrstr), + (uintptr_t)hf.hfi_family.hf_name) == -1) { + mdb_warn("couldn't read root role at %p", + hf.hfi_family.hf_name); + return (DCMD_ERR); + } + mdb_printf("%0?p %10s\n", hfp, hrrstr); + hfp = SLIST_NEXT(&hf, hfi_entry); + } + + return (DCMD_OK); +} + + +static int +hookevent_walk_init(mdb_walk_state_t *wsp) +{ + hook_family_int_t hf; + + if (wsp->walk_addr == NULL) { + mdb_warn("global walk not supported\n"); + return (WALK_ERR); + } + + if (mdb_vread((void *)&hf, sizeof (hf), + (uintptr_t)wsp->walk_addr) == -1) { + mdb_warn("couldn't read hook family at %p", wsp->walk_addr); + return (DCMD_ERR); + } + wsp->walk_addr = (uintptr_t)SLIST_FIRST(&hf.hfi_head); + return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data, + wsp->walk_cbdata)); +} + +static int +hookevent_walk_step(mdb_walk_state_t *wsp) +{ + hook_event_int_t hr; + + if (mdb_vread((void *)&hr, sizeof (hr), + (uintptr_t)wsp->walk_addr) == -1) { + mdb_warn("couldn't read hook event at %p", wsp->walk_addr); + return (DCMD_ERR); + } + wsp->walk_addr = (uintptr_t)SLIST_NEXT(&hr, hei_entry); + if (wsp->walk_addr == NULL) + return (WALK_DONE); + return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data, + wsp->walk_cbdata)); +} + + +static const mdb_dcmd_t dcmds[] = { + { "hookrootlist", "", "display hook family information", hookrootlist }, + { "hookeventlist", "", "display hook event information", + hookeventlist, NULL }, + { "hooklist", "", "display hooks", hooklist }, + { NULL } +}; + +static const mdb_walker_t walkers[] = { + { "hookevent", "walk a list of hooks", + hookevent_walk_init, hookevent_walk_step, NULL }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +} diff --git a/usr/src/cmd/mdb/common/modules/neti/neti.c b/usr/src/cmd/mdb/common/modules/neti/neti.c new file mode 100644 index 0000000000..788099b048 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/neti/neti.c @@ -0,0 +1,103 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/rwlock.h> +#include <mdb/mdb_modapi.h> +#include <sys/queue.h> +#include <sys/neti.h> + + +/* + * PROT_LENGTH is the max length. If the true length is bigger + * it is truncated. + */ +#define PROT_LENGTH 32 + +LIST_HEAD(netd_listhead, net_data); + +/* + * List pfhooks netinfo information. + */ +/*ARGSUSED*/ +int +netinfolist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + struct netd_listhead nlh; + struct net_data nd, *p; + char str[PROT_LENGTH]; + + if (argc) + return (DCMD_USAGE); + + if (mdb_readvar(&nlh, "netd_head") == -1) { + mdb_warn("couldn't read symbol 'netd_head'"); + return (DCMD_ERR); + } + mdb_printf("%<u>%?s %?s %10s%</u>\n", + "ADDR(netinfo)", "ADDR(hookevent)", "netinfo"); + p = LIST_FIRST(&nlh); + while (p) { + if (mdb_vread((void *)&nd, sizeof (nd), (uintptr_t)p) == -1) { + mdb_warn("couldn't read netinfo at %p", p); + return (DCMD_ERR); + } + if (!nd.netd_info.neti_protocol) { + mdb_warn("netinfo at %p has null protocol", + nd.netd_info.neti_protocol); + return (DCMD_ERR); + } + if (mdb_readstr((char *)str, sizeof (str), + (uintptr_t)nd.netd_info.neti_protocol) == -1) { + mdb_warn("couldn't read protocol at %p", + nd.netd_info.neti_protocol); + return (DCMD_ERR); + } + + mdb_printf("%0?p %0?p %10s\n", + (char *)p + (uintptr_t)&((struct net_data *)0)->netd_info, + nd.netd_hooks, str); + + p = LIST_NEXT(&nd, netd_list); + } + + return (DCMD_OK); +} + +static const mdb_dcmd_t dcmds[] = { + { "netinfolist", "", "display netinfo information", + netinfolist, NULL }, + { NULL } +}; + +static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds }; + +const mdb_modinfo_t * +_mdb_init(void) +{ + return (&modinfo); +} diff --git a/usr/src/cmd/mdb/intel/amd64/hook/Makefile b/usr/src/cmd/mdb/intel/amd64/hook/Makefile new file mode 100644 index 0000000000..457244bd5d --- /dev/null +++ b/usr/src/cmd/mdb/intel/amd64/hook/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = hook.so +MDBTGT = kvm + +MODSRCS = hook.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module diff --git a/usr/src/cmd/mdb/intel/amd64/neti/Makefile b/usr/src/cmd/mdb/intel/amd64/neti/Makefile new file mode 100644 index 0000000000..141c284897 --- /dev/null +++ b/usr/src/cmd/mdb/intel/amd64/neti/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = neti.so +MDBTGT = kvm + +MODSRCS = neti.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.amd64 +include ../../../Makefile.module diff --git a/usr/src/uts/common/inet/pfil/pfil.conf b/usr/src/cmd/mdb/intel/ia32/hook/Makefile index 1cf479a0d6..fb06c57cec 100644 --- a/usr/src/uts/common/inet/pfil/pfil.conf +++ b/usr/src/cmd/mdb/intel/ia32/hook/Makefile @@ -22,7 +22,13 @@ # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" +#ident "%Z%%M% %I% %E% SMI" -name="pfil" parent="pseudo" instance=0; +MODULE = hook.so +MDBTGT = kvm +MODSRCS = hook.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module diff --git a/usr/src/cmd/mdb/intel/ia32/neti/Makefile b/usr/src/cmd/mdb/intel/ia32/neti/Makefile new file mode 100644 index 0000000000..370d3ba2d3 --- /dev/null +++ b/usr/src/cmd/mdb/intel/ia32/neti/Makefile @@ -0,0 +1,34 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = neti.so +MDBTGT = kvm + +MODSRCS = neti.c + +include ../../../../Makefile.cmd +include ../../Makefile.ia32 +include ../../../Makefile.module diff --git a/usr/src/cmd/mdb/sparc/v9/hook/Makefile b/usr/src/cmd/mdb/sparc/v9/hook/Makefile new file mode 100644 index 0000000000..1c2c6453a9 --- /dev/null +++ b/usr/src/cmd/mdb/sparc/v9/hook/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = hook.so +MDBTGT = kvm + +MODSRCS = hook.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.sparcv9 +include ../../../Makefile.module diff --git a/usr/src/cmd/mdb/sparc/v9/neti/Makefile b/usr/src/cmd/mdb/sparc/v9/neti/Makefile new file mode 100644 index 0000000000..8879100579 --- /dev/null +++ b/usr/src/cmd/mdb/sparc/v9/neti/Makefile @@ -0,0 +1,35 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" + +MODULE = neti.so +MDBTGT = kvm + +MODSRCS = neti.c + +include ../../../../Makefile.cmd +include ../../../../Makefile.cmd.64 +include ../../Makefile.sparcv9 +include ../../../Makefile.module diff --git a/usr/src/cmd/svc/prophist/prophist.SUNWcsr b/usr/src/cmd/svc/prophist/prophist.SUNWcsr index 44978057e8..77bf3a49a8 100644 --- a/usr/src/cmd/svc/prophist/prophist.SUNWcsr +++ b/usr/src/cmd/svc/prophist/prophist.SUNWcsr @@ -3,9 +3,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -21,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -412,9 +411,6 @@ prophist_adddpt svc:/network/ntp ntp_multi-user optional_all none \ instance_refresh svc:/network/ntp:default instance_refresh svc:/milestone/multi-user:default -prophist_upgrade network/pfil start exec \ - "/lib/svc/method/pfil start" "/sbin/autopush -f /etc/ipf/pfil.ap" - prophist_upgrade network/rarp start timeout_seconds 60 3 prophist_upgrade network/rarp stop timeout_seconds 60 3 prophist_adddpt svc:/network/rarp rarp_multi-user-server optional_all none \ diff --git a/usr/src/cmd/svc/seed/Makefile b/usr/src/cmd/svc/seed/Makefile index 5d6a2e5a04..37da95d671 100644 --- a/usr/src/cmd/svc/seed/Makefile +++ b/usr/src/cmd/svc/seed/Makefile @@ -75,8 +75,7 @@ GLOBAL_ZONE_DESCRIPTIONS = \ ../milestone/multi-user-server.xml \ ../../cmd-inet/usr.lib/inetd/inetd-upgrade.xml \ ../../utmpd/utmp.xml \ - ../../lvm/util/metainit.xml \ - ../../ipf/svc/pfil.xml + ../../lvm/util/metainit.xml # # Additional manifests for a Solaris zone diff --git a/usr/src/cmd/svc/seed/inc.flg b/usr/src/cmd/svc/seed/inc.flg index c8adc2a41f..8224abb7f3 100644 --- a/usr/src/cmd/svc/seed/inc.flg +++ b/usr/src/cmd/svc/seed/inc.flg @@ -3,9 +3,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -21,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -32,5 +31,4 @@ echo_file usr/src/cmd/rpcbind/bind.xml echo_file usr/src/cmd/utmpd/utmp.xml echo_file usr/src/cmd/lvm/util/metainit.xml echo_file usr/src/cmd/lvm/md_monitord/mdmonitor.xml -echo_file usr/src/cmd/ipf/svc/pfil.xml find_files "s.*.xml" usr/src/cmd/svc/milestone diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt index 6cbee3ea1f..07dc34f7bb 100644 --- a/usr/src/lib/libsecdb/exec_attr.txt +++ b/usr/src/lib/libsecdb/exec_attr.txt @@ -107,7 +107,6 @@ IP Filter Management:solaris:cmd:::/usr/sbin/ipmon:privs=sys_net_config IP Filter Management:solaris:cmd:::/usr/sbin/ipfstat:privs=sys_net_config;gid=sys IP Filter Management:solaris:cmd:::/usr/sbin/ipnat:privs=sys_net_config;gid=sys IP Filter Management:solaris:cmd:::/usr/sbin/ippool:privs=sys_net_config;gid=sys -IP Filter Management:solaris:cmd:::/usr/sbin/pfild:uid=0 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/krb5kdc:uid=0 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/kadmind:uid=0 Kerberos Server Management:solaris:cmd:::/usr/lib/krb5/kprop:euid=0;privs=none diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386 index f3a0b360da..839daf5e94 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 @@ -159,6 +159,7 @@ l none kernel/misc/des=../../kernel/crypto/des f none kernel/misc/dls 755 root sys f none kernel/misc/fssnap_if 755 root sys f none kernel/misc/gld 755 root sys +f none kernel/misc/hook 755 root sys f none kernel/misc/hpcsvc 755 root sys f none kernel/misc/i2o_msg 755 root sys f none kernel/misc/ipc 755 root sys @@ -168,6 +169,7 @@ f none kernel/misc/kmdbmod 755 root sys f none kernel/misc/krtld 755 root sys f none kernel/misc/mac 755 root sys l none kernel/misc/md5=../../kernel/crypto/md5 +f none kernel/misc/neti 755 root sys f none kernel/misc/pcicfg 755 root sys f none kernel/misc/pcihp 755 root sys f none kernel/misc/pcmcia 755 root sys @@ -333,6 +335,7 @@ l none kernel/misc/amd64/des=../../../kernel/crypto/amd64/des f none kernel/misc/amd64/dls 755 root sys f none kernel/misc/amd64/fssnap_if 755 root sys f none kernel/misc/amd64/gld 755 root sys +f none kernel/misc/amd64/hook 755 root sys f none kernel/misc/amd64/hpcsvc 755 root sys f none kernel/misc/amd64/ipc 755 root sys f none kernel/misc/amd64/kbtrans 755 root sys @@ -341,6 +344,7 @@ f none kernel/misc/amd64/kmdbmod 755 root sys f none kernel/misc/amd64/krtld 755 root sys f none kernel/misc/amd64/mac 755 root sys l none kernel/misc/amd64/md5=../../../kernel/crypto/amd64/md5 +f none kernel/misc/amd64/neti 755 root sys f none kernel/misc/amd64/pcicfg 755 root sys f none kernel/misc/amd64/pcihp 755 root sys f none kernel/misc/amd64/pcmcia 755 root sys diff --git a/usr/src/pkgdefs/SUNWckr/prototype_sparc b/usr/src/pkgdefs/SUNWckr/prototype_sparc index 062109cbf3..a5a01f4126 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWckr/prototype_sparc @@ -168,6 +168,7 @@ l none kernel/misc/sparcv9/des=../../../kernel/crypto/sparcv9/des f none kernel/misc/sparcv9/dls 755 root sys f none kernel/misc/sparcv9/fssnap_if 755 root sys f none kernel/misc/sparcv9/gld 755 root sys +f none kernel/misc/sparcv9/hook 755 root sys f none kernel/misc/sparcv9/hpcsvc 755 root sys f none kernel/misc/sparcv9/ipc 755 root sys f none kernel/misc/sparcv9/kbtrans 755 root sys @@ -175,6 +176,7 @@ f none kernel/misc/sparcv9/kcf 755 root sys f none kernel/misc/sparcv9/krtld 755 root sys f none kernel/misc/sparcv9/mac 755 root sys l none kernel/misc/sparcv9/md5=../../../kernel/crypto/sparcv9/md5 +f none kernel/misc/sparcv9/neti 755 root sys f none kernel/misc/sparcv9/pcie 755 root sys f none kernel/misc/sparcv9/pcihp 755 root sys f none kernel/misc/sparcv9/pciehpc 755 root sys diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index 33ecce0f6f..4331dbb4d1 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -139,6 +139,7 @@ f none usr/include/inet/ip_if.h 644 root bin f none usr/include/inet/ip_ire.h 644 root bin f none usr/include/inet/ip_ftable.h 644 root bin f none usr/include/inet/ip_multi.h 644 root bin +f none usr/include/inet/ip_netinfo.h 644 root bin f none usr/include/inet/ip_rts.h 644 root bin f none usr/include/inet/ip6.h 644 root bin f none usr/include/inet/ip6_asp.h 644 root bin @@ -750,6 +751,9 @@ f none usr/include/sys/fstyp.h 644 root bin f none usr/include/sys/ftrace.h 644 root bin f none usr/include/sys/gfs.h 644 root bin f none usr/include/sys/hdio.h 644 root bin +f none usr/include/sys/hook.h 644 root bin +f none usr/include/sys/hook_event.h 644 root bin +f none usr/include/sys/hook_impl.h 644 root bin f none usr/include/sys/hwconf.h 644 root bin f none usr/include/sys/ia.h 644 root bin f none usr/include/sys/iapriocntl.h 644 root bin @@ -892,6 +896,7 @@ f none usr/include/sys/netconfig.h 644 root bin f none usr/include/sys/nexusdefs.h 644 root bin f none usr/include/sys/ndifm.h 644 root bin f none usr/include/sys/ndi_impldefs.h 644 root bin +f none usr/include/sys/neti.h 644 root bin f none usr/include/sys/note.h 644 root bin f none usr/include/sys/nvpair.h 644 root bin f none usr/include/sys/nvpair_impl.h 644 root bin @@ -960,6 +965,7 @@ f none usr/include/sys/psw.h 644 root bin f none usr/include/sys/ptem.h 644 root bin f none usr/include/sys/ptms.h 644 root bin f none usr/include/sys/ptyvar.h 644 root bin +f none usr/include/sys/queue.h 644 root bin f none usr/include/sys/raidioctl.h 644 root bin f none usr/include/sys/ramdisk.h 644 root bin f none usr/include/sys/random.h 644 root bin diff --git a/usr/src/pkgdefs/SUNWipfr/prototype_com b/usr/src/pkgdefs/SUNWipfr/prototype_com index 227230ca02..a0d550faba 100644 --- a/usr/src/pkgdefs/SUNWipfr/prototype_com +++ b/usr/src/pkgdefs/SUNWipfr/prototype_com @@ -1,4 +1,24 @@ # +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -28,16 +48,13 @@ i i.preserve # d none etc 755 root sys d none etc/ipf 755 root sys -e preserve etc/ipf/pfil.ap 644 root sys e preserve etc/ipf/ipf.conf 644 root sys d none lib 755 root bin d none lib/svc 0755 root bin d none lib/svc/method 0755 root bin f none lib/svc/method/ipfilter 0555 root bin -f none lib/svc/method/pfil 0555 root bin d none kernel 755 root sys d none kernel/drv 755 root sys -f none kernel/drv/pfil.conf 644 root sys d none kernel/strmod 755 root sys d none var 755 root sys d none var/db 755 root sys @@ -45,5 +62,4 @@ d none var/db/ipf 755 root sys d none var/svc 755 root sys d none var/svc/manifest 755 root sys d none var/svc/manifest/network 755 root sys -f manifest var/svc/manifest/network/pfil.xml 444 root sys f manifest var/svc/manifest/network/ipfilter.xml 444 root sys diff --git a/usr/src/pkgdefs/SUNWipfr/prototype_i386 b/usr/src/pkgdefs/SUNWipfr/prototype_i386 index 5695a692e2..f745fb3564 100644 --- a/usr/src/pkgdefs/SUNWipfr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWipfr/prototype_i386 @@ -1,5 +1,25 @@ # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -28,9 +48,3 @@ # # SUNWipfr # -f none kernel/drv/pfil 755 root sys -l none kernel/strmod/pfil=../../kernel/drv/pfil -d none kernel/drv/amd64 755 root sys -f none kernel/drv/amd64/pfil 755 root sys -d none kernel/strmod/amd64 755 root sys -l none kernel/strmod/amd64/pfil=../../../kernel/drv/amd64/pfil diff --git a/usr/src/pkgdefs/SUNWipfr/prototype_sparc b/usr/src/pkgdefs/SUNWipfr/prototype_sparc index 60ff96c3c5..d082baa2bd 100644 --- a/usr/src/pkgdefs/SUNWipfr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWipfr/prototype_sparc @@ -1,5 +1,25 @@ # -# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -23,10 +43,6 @@ # # List files which are SPARC specific here # -d none kernel/drv/sparcv9 755 root sys -f none kernel/drv/sparcv9/pfil 755 root sys -d none kernel/strmod/sparcv9 755 root sys -l none kernel/strmod/sparcv9/pfil=../../../kernel/drv/sparcv9/pfil # # source locations relative to the prototype file # diff --git a/usr/src/pkgdefs/SUNWipfu/prototype_com b/usr/src/pkgdefs/SUNWipfu/prototype_com index cf4f0f6d32..26372d31d0 100644 --- a/usr/src/pkgdefs/SUNWipfu/prototype_com +++ b/usr/src/pkgdefs/SUNWipfu/prototype_com @@ -1,5 +1,25 @@ # -# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -28,8 +48,8 @@ d none usr/lib 755 root bin d none usr/lib/ipf 755 root bin f none usr/lib/ipf/IPFILTER.LICENCE 644 root bin l none usr/lib/ipf/ipftest=../../../usr/lib/isaexec -d none usr/kernel 755 root sys -d none usr/kernel/drv 755 root sys +d none usr/kernel 755 root sys +d none usr/kernel/drv 755 root sys f none usr/kernel/drv/ipf.conf 644 root sys d none usr/sbin 755 root bin l none usr/sbin/ipf=../../usr/lib/isaexec @@ -38,7 +58,6 @@ l none usr/sbin/ipfstat=../../usr/lib/isaexec l none usr/sbin/ipmon=../../usr/lib/isaexec l none usr/sbin/ipnat=../../usr/lib/isaexec l none usr/sbin/ippool=../../usr/lib/isaexec -f none usr/sbin/pfild 555 root bin d none usr/share 755 root sys d none usr/share/ipfilter 755 root bin d none usr/share/ipfilter/examples 755 root bin diff --git a/usr/src/pkgdefs/SUNWipfu/prototype_i386 b/usr/src/pkgdefs/SUNWipfu/prototype_i386 index eada1517e0..4be9267375 100644 --- a/usr/src/pkgdefs/SUNWipfu/prototype_i386 +++ b/usr/src/pkgdefs/SUNWipfu/prototype_i386 @@ -1,5 +1,25 @@ # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/pkgdefs/SUNWipfu/prototype_sparc b/usr/src/pkgdefs/SUNWipfu/prototype_sparc index 797561e8c6..543bfb36a4 100644 --- a/usr/src/pkgdefs/SUNWipfu/prototype_sparc +++ b/usr/src/pkgdefs/SUNWipfu/prototype_sparc @@ -1,5 +1,25 @@ # -# Copyright 2003 Sun Microsystems, Inc. All rights reserved. +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" diff --git a/usr/src/pkgdefs/SUNWmdb/prototype_i386 b/usr/src/pkgdefs/SUNWmdb/prototype_i386 index ff996ca924..b84b6dc728 100644 --- a/usr/src/pkgdefs/SUNWmdb/prototype_i386 +++ b/usr/src/pkgdefs/SUNWmdb/prototype_i386 @@ -53,6 +53,8 @@ f none usr/lib/mdb/kvm/amd64/cpc.so 555 root sys f none usr/lib/mdb/kvm/amd64/crypto.so 555 root sys f none usr/lib/mdb/kvm/amd64/genunix.so 555 root sys f none usr/lib/mdb/kvm/amd64/ip.so 555 root sys +f none usr/lib/mdb/kvm/amd64/hook.so 555 root sys +f none usr/lib/mdb/kvm/amd64/neti.so 555 root sys f none usr/lib/mdb/kvm/amd64/ipc.so 555 root sys f none usr/lib/mdb/kvm/amd64/ipp.so 555 root sys f none usr/lib/mdb/kvm/amd64/krtld.so 555 root sys @@ -78,6 +80,8 @@ f none usr/lib/mdb/kvm/cpc.so 555 root sys f none usr/lib/mdb/kvm/crypto.so 555 root sys f none usr/lib/mdb/kvm/genunix.so 555 root sys f none usr/lib/mdb/kvm/ip.so 555 root sys +f none usr/lib/mdb/kvm/hook.so 555 root sys +f none usr/lib/mdb/kvm/neti.so 555 root sys f none usr/lib/mdb/kvm/ipc.so 555 root sys f none usr/lib/mdb/kvm/ipp.so 555 root sys f none usr/lib/mdb/kvm/krtld.so 555 root sys diff --git a/usr/src/pkgdefs/SUNWmdb/prototype_sparc b/usr/src/pkgdefs/SUNWmdb/prototype_sparc index f597cae61d..240d6c0cd4 100644 --- a/usr/src/pkgdefs/SUNWmdb/prototype_sparc +++ b/usr/src/pkgdefs/SUNWmdb/prototype_sparc @@ -45,6 +45,8 @@ f none usr/lib/mdb/kvm/sparcv9/crypto.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/genunix.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/intr.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/ip.so 555 root sys +f none usr/lib/mdb/kvm/sparcv9/hook.so 555 root sys +f none usr/lib/mdb/kvm/sparcv9/neti.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/ipc.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/ipp.so 555 root sys f none usr/lib/mdb/kvm/sparcv9/isp.so 555 root sys diff --git a/usr/src/pkgdefs/SUNWmdbr/prototype_i386 b/usr/src/pkgdefs/SUNWmdbr/prototype_i386 index 53758ed816..82cb3fd4d8 100644 --- a/usr/src/pkgdefs/SUNWmdbr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWmdbr/prototype_i386 @@ -34,6 +34,8 @@ f none kernel/kmdb/amd64/cpc 555 root sys f none kernel/kmdb/amd64/crypto 555 root sys f none kernel/kmdb/amd64/genunix 555 root sys f none kernel/kmdb/amd64/ip 555 root sys +f none kernel/kmdb/amd64/hook 555 root sys +f none kernel/kmdb/amd64/neti 555 root sys f none kernel/kmdb/amd64/ipc 555 root sys f none kernel/kmdb/amd64/ipp 555 root sys f none kernel/kmdb/amd64/krtld 555 root sys @@ -59,6 +61,8 @@ f none kernel/kmdb/cpc 555 root sys f none kernel/kmdb/crypto 555 root sys f none kernel/kmdb/genunix 555 root sys f none kernel/kmdb/ip 555 root sys +f none kernel/kmdb/hook 555 root sys +f none kernel/kmdb/neti 555 root sys f none kernel/kmdb/ipc 555 root sys f none kernel/kmdb/ipp 555 root sys f none kernel/kmdb/krtld 555 root sys diff --git a/usr/src/pkgdefs/SUNWmdbr/prototype_sparc b/usr/src/pkgdefs/SUNWmdbr/prototype_sparc index bfb6414a25..df345ad032 100644 --- a/usr/src/pkgdefs/SUNWmdbr/prototype_sparc +++ b/usr/src/pkgdefs/SUNWmdbr/prototype_sparc @@ -35,6 +35,8 @@ f none kernel/kmdb/sparcv9/crypto 555 root sys f none kernel/kmdb/sparcv9/genunix 555 root sys f none kernel/kmdb/sparcv9/intr 555 root sys f none kernel/kmdb/sparcv9/ip 555 root sys +f none kernel/kmdb/sparcv9/hook 555 root sys +f none kernel/kmdb/sparcv9/neti 555 root sys f none kernel/kmdb/sparcv9/ipc 555 root sys f none kernel/kmdb/sparcv9/ipp 555 root sys f none kernel/kmdb/sparcv9/isp 555 root sys diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh index 7494a69102..c1fa6b528c 100644 --- a/usr/src/tools/scripts/bfu.sh +++ b/usr/src/tools/scripts/bfu.sh @@ -316,7 +316,6 @@ superfluous_local_zone_files=" lib/libmeta.so lib/libmeta.so.1 lib/svc/method/ipfilter - lib/svc/method/pfil lib/svc/method/sf880dr lib/svc/method/svc-cvcd lib/svc/method/svc-dcs @@ -377,7 +376,6 @@ superfluous_local_zone_files=" var/db/ipf var/log/pool var/svc/manifest/network/ipfilter.xml - var/svc/manifest/network/pfil.xml var/svc/manifest/network/rpc/mdcomm.xml var/svc/manifest/network/rpc/meta.xml var/svc/manifest/network/rpc/metamed.xml @@ -893,7 +891,6 @@ smf_obsolete_rc_files=" etc/init.d/nodename etc/init.d/nscd etc/init.d/perf - etc/init.d/pfil etc/init.d/picld etc/init.d/power etc/init.d/rcapd @@ -1052,7 +1049,6 @@ smf_obsolete_rc_files=" etc/rcS.d/K43inet etc/rcS.d/K99libc.mount etc/rcS.d/S10cvc - etc/rcS.d/S10pfil etc/rcS.d/S28network.sh etc/rcS.d/S29nodename.sh etc/rcS.d/S30rootusr.sh @@ -1071,6 +1067,7 @@ smf_obsolete_manifests=" var/svc/manifest/network/tftp.xml var/svc/manifest/network/lp.xml var/svc/manifest/system/filesystem/volfs.xml + var/svc/manifest/network/pfil.xml " # smf services whose manifests have been renamed @@ -1083,6 +1080,7 @@ smf_renamed_manifests=" smf_obsolete_methods=" lib/svc/method/print-server lib/svc/method/svc-volfs + lib/svc/method/pfil " smf_cleanup () { @@ -1706,47 +1704,32 @@ EOFA fi # If we're in the global zone, and using an alternate root, see if - # we are in an smf root. If so, import pfil and name-service-cache. - # If we're not bfu'ing an alternate root, and we're post-smf, - # import pfil and name-service-cache. This is to get pfil and - # name-service-cache(with correct dependencies) in the repository - # before reboot. If we're bfu'ing from pre-smf, this isn't an - # issue, as pfil is in the seed repository, and name-service-cache - # will be installed with correct dependencies. + # we are in an smf root. If so, import name-service-cache. If we're + # not bfu'ing an alternate root, and we're post-smf, import + # name-service-cache. This is to get name-service-cache(with correct + # dependencies) in the repository before reboot. If we're bfu'ing + # from pre-smf, this isn't an issue, as name-service-cache will be + # installed with correct dependencies. if [[ $zone = global && - -f $rootprefix/var/svc/manifest/network/pfil.xml ]]; then + -f $rootprefix/var/svc/manifest/system/name-service-cache.xml ]]; + then if [[ -n $rootprefix ]]; then if [ -x /usr/sbin/svccfg ]; then SVCCFG_REPOSITORY=$rootprefix/etc/svc/repository.db /usr/sbin/svccfg import \ - $rootprefix/var/svc/manifest/network/pfil.xml - /usr/sbin/svccfg import \ $rootprefix/var/svc/manifest/system/name-service-cache.xml else - echo "Warning: This system does not have SMF, so I" - echo "cannot ensure the pre-import of pfil and" - echo "name-service-cache. If ipfilter or name-service-" - echo "cache do not work, reboot your alternate root to" - echo "fix it." + echo "Warning: This system does not have SMF, so I " + echo "cannot ensure the pre-import of " + echo "name-service-cache. If name-service-cache does " + echo "not work, reboot your alternate root to fix it." fi elif [ -x /tmp/bfubin/svccfg ]; then /tmp/bfubin/svccfg import \ - /var/svc/manifest/network/pfil.xml - /tmp/bfubin/svccfg import \ /var/svc/manifest/system/name-service-cache.xml fi fi - # Remove pfil from the non-global repository. - if [[ $zone != global ]]; then - cat >> $rootprefix/var/svc/profile/upgrade << EOF - svcprop -q -p start/exec network/pfil - if [[ \$? = 0 ]]; then - /usr/sbin/svccfg delete -f network/pfil - fi -EOF - fi - # If we're in the global zone, and using an alternate root, see if # we are in an smf root. If so, import datalink and aggregation svcs. # If we're not bfu'ing an alternate root, and we're post-smf, @@ -5992,6 +5975,13 @@ mondo_loop() { rm -f $root/platform/i86pc/kernel/drv/amd64/bscv rm -f $root/platform/i86pc/kernel/drv/amd64/bscbus + # Remove obsolete pfil modules, binaries, and configuration files + rm -f $root/kernel/drv/pfil + rm -f $root/kernel/drv/pfil.conf + rm -f $root/kernel/drv/sparcv9/pfil + rm -f $root/kernel/drv/amd64/pfil + rm -f $root/usr/sbin/pfild + # Remove obsolete atomic_prim.h file. rm -f $usr/include/v9/sys/atomic_prim.h diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 70b93c0e10..e8dc6b6f60 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -430,7 +430,7 @@ TOKENMT_OBJS += tokenmt.o tokenmtddi.o TSWTCL_OBJS += tswtcl.o tswtclddi.o -ARP_OBJS += arpddi.o arp.o +ARP_OBJS += arpddi.o arp.o arp_netinfo.o ICMP_OBJS += icmpddi.o icmp.o icmp_opt_data.o @@ -447,7 +447,7 @@ IP_SCTP_OBJS = sctp_crc32.o sctp.o sctp_opt_data.o sctp_output.o \ sctp_param.o sctp_shutdown.o sctp_common.o \ sctp_timer.o sctp_heartbeat.o sctp_hash.o \ sctp_ioc.o sctp_bind.o sctp_notify.o sctp_asconf.o \ - sctp_addr.o tn_ipopt.o tnet.o + sctp_addr.o tn_ipopt.o tnet.o ip_netinfo.o IP_OBJS += igmp.o ip.o ip6.o ip6_asp.o ip6_if.o ip6_ire.o ip6_rts.o \ ip_cksum.o ip_if.o ip_ire.o ip_listutils.o ip_mroute.o \ @@ -461,6 +461,10 @@ IP_OBJS += igmp.o ip.o ip6.o ip6_asp.o ip6_if.o ip6_ire.o ip6_rts.o \ IP6_OBJS += ip6ddi.o +HOOK_OBJS += hook.o + +NETI_OBJS += neti.o + KEYSOCK_OBJS += keysockddi.o keysock.o keysock_opt_data.o SPDSOCK_OBJS += spdsockddi.o spdsock.o spdsock_opt_data.o @@ -956,7 +960,7 @@ LDTERM_OBJS += ldterm.o uwidth.o PCKT_OBJS += pckt.o -PFMOD_OBJS += pfmod.o +PFMOD_OBJS += pfmod.o PTEM_OBJS += ptem.o @@ -1242,10 +1246,8 @@ PHX_OBJS += phx.o IPF_OBJS += ip_fil_solaris.o fil.o solaris.o ip_state.o ip_frag.o ip_nat.o \ ip_proxy.o ip_auth.o ip_pool.o ip_htable.o ip_lookup.o \ - ip_log.o + ip_log.o misc.o -PFIL_OBJS += pfil.o qif.o pfildrv.o pfilstream.o pkt.o misc.o ndd.o - IBD_OBJS += ibd.o VNI_OBJS += vni.o diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index 82b1840f00..64994fabb1 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -370,9 +370,8 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/inet/tcp/%.c $(CTFCONVERT_O) -IPFFLAGS=-I $(UTSBASE)/common/inet/pfil $(OBJS_DIR)/%.o: $(UTSBASE)/common/inet/ipf/%.c - $(COMPILE.c) $(IPFFLAGS) -o $@ $< + $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) $(OBJS_DIR)/%.o: $(COMMONBASE)/net/patricia/%.c diff --git a/usr/src/uts/common/conf/param.c b/usr/src/uts/common/conf/param.c index 6519a36a30..c236d570be 100644 --- a/usr/src/uts/common/conf/param.c +++ b/usr/src/uts/common/conf/param.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. diff --git a/usr/src/uts/common/inet/Makefile b/usr/src/uts/common/inet/Makefile index 7b0cdbc607..8f6c111896 100644 --- a/usr/src/uts/common/inet/Makefile +++ b/usr/src/uts/common/inet/Makefile @@ -29,11 +29,12 @@ # include global definitions include ../../../Makefile.master -HDRS= arp.h common.h ipclassifier.h ip.h ip6.h ipdrop.h ipsecah.h ipsecesp.h \ - ipsec_info.h ip6_asp.h ip_if.h ip_ire.h ip_multi.h ip_ndp.h ip_rts.h \ - ipsec_impl.h keysock.h led.h mi.h mib2.h nd.h optcom.h sadb.h \ - sctp_itf.h snmpcom.h tcp.h tcp_sack.h tun.h udp_impl.h arp_impl.h \ - rawip_impl.h ipp_common.h ip_ftable.h ip_impl.h tcp_impl.h wifi_ioctl.h +HDRS= arp.h arp_impl.h common.h ipclassifier.h ip.h ip6.h ipdrop.h ipsecah.h \ + ipsecesp.h ipsec_info.h ip6_asp.h ip_if.h ip_ire.h ip_multi.h \ + ip_netinfo.h ip_ndp.h ip_rts.h ipsec_impl.h keysock.h led.h mi.h \ + mib2.h nd.h optcom.h sadb.h sctp_itf.h snmpcom.h tcp.h tcp_sack.h \ + tun.h udp_impl.h rawip_impl.h ipp_common.h ip_ftable.h ip_impl.h \ + tcp_impl.h wifi_ioctl.h ROOTDIRS= $(ROOT)/usr/include/inet diff --git a/usr/src/uts/common/inet/arp/arp.c b/usr/src/uts/common/inet/arp/arp.c index 17c81b9513..97528cf323 100644 --- a/usr/src/uts/common/inet/arp/arp.c +++ b/usr/src/uts/common/inet/arp/arp.c @@ -41,6 +41,7 @@ #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/cmn_err.h> +#include <sys/sdt.h> #include <sys/vtrace.h> #include <sys/strsun.h> #include <sys/policy.h> @@ -48,6 +49,7 @@ #include <sys/zone.h> #include <sys/random.h> #include <sys/sdt.h> +#include <sys/hook_event.h> #include <inet/common.h> #include <inet/optcom.h> @@ -304,7 +306,17 @@ struct streamtab arpinfo = { static void *ar_g_head; /* AR Instance Data List Head */ static caddr_t ar_g_nd; /* AR Named Dispatch Head */ -static arl_t *arl_g_head; /* ARL List Head */ + +/* + * With the introduction of netinfo (neti kernel module), it is now possible + * to access data structures in the ARP module without the code being + * executed in the context of the IP module, thus there is no locking being + * enforced through the use of STREAMS. + * + * + */ +krwlock_t arl_g_lock; +arl_t *arl_g_head; /* ARL List Head */ /* * TODO: we need a better mechanism to set the ARP hardware type since @@ -326,6 +338,9 @@ static ace_t *ar_ce_hash_tbl[ARP_HASH_SIZE]; static ace_t *ar_ce_mask_entries; /* proto_mask not all ones */ +static uint32_t arp_index_counter = 1; +static uint32_t arp_counter_wrapped = 0; + /* * Note that all routines which need to queue the message for later * processing have to be ioctl_aware to be able to queue the complete message. @@ -953,17 +968,20 @@ static int ar_close(queue_t *q) { ar_t *ar = (ar_t *)q->q_ptr; + char name[LIFNAMSIZ]; arl_t *arl; arl_t **arlp; cred_t *cr; arc_t *arc; mblk_t *mp1; + int index; TRACE_1(TR_FAC_ARP, TR_ARP_CLOSE, "arp_close: q %p", q); arl = ar->ar_arl; if (arl == NULL) { + index = 0; /* * If this is the <ARP-IP-Driver> stream send down * a closing message to IP and wait for IP to send @@ -992,6 +1010,8 @@ ar_close(queue_t *q) */ ar_ll_cleanup_arl_queue(q); } else { + index = arl->arl_index; + (void) strcpy(name, arl->arl_name); arl->arl_closing = 1; while (arl->arl_queue != NULL) qwait(arl->arl_rq); @@ -1010,16 +1030,19 @@ ar_close(queue_t *q) ar_ce_walk(ar_ce_delete_per_arl, arl); /* Free any messages waiting for a bind_ack */ /* Get the arl out of the chain. */ - for (arlp = &arl_g_head; arlp[0]; arlp = &arlp[0]->arl_next) { - if (arlp[0] == arl) { - arlp[0] = arl->arl_next; + rw_enter(&arl_g_lock, RW_WRITER); + for (arlp = &arl_g_head; *arlp; arlp = &(*arlp)->arl_next) { + if (*arlp == arl) { + *arlp = arl->arl_next; break; } } ASSERT(arl->arl_dlpi_deferred == NULL); - mi_free((char *)arl); ar->ar_arl = NULL; + rw_exit(&arl_g_lock); + + mi_free((char *)arl); } /* Let's break the association between an ARL and IP instance */ if (ar->ar_arl_ip_assoc != NULL) { @@ -1034,6 +1057,17 @@ ar_close(queue_t *q) ar_cleanup(); qprocsoff(q); crfree(cr); + + if (index != 0) { + hook_nic_event_t info; + + info.hne_nic = index; + info.hne_lif = 0; + info.hne_event = NE_UNPLUMB; + info.hne_data = name; + info.hne_datalen = strlen(name); + (void) hook_run(arpnicevents, (hook_data_t)&info); + } return (0); } @@ -2116,8 +2150,9 @@ ar_ll_lookup_by_name(const char *name) arl_t *arl; for (arl = arl_g_head; arl; arl = arl->arl_next) { - if (strcmp(arl->arl_name, name) == 0) + if (strcmp(arl->arl_name, name) == 0) { return (arl); + } } return (NULL); } @@ -2158,6 +2193,43 @@ ar_ll_init(ar_t *ar, mblk_t *mp) arl->arl_link_up = B_TRUE; ar->ar_arl = arl; + + /* + * If/when ARP gets pushed into the IP module then this code to make + * a number uniquely identify an ARP instance can be removed and the + * ifindex from IP used. Rather than try and reinvent or copy the + * code used by IP for the purpose of allocating an index number + * (and trying to keep the number small), just allocate it in an + * ever increasing manner. This index number isn't ever exposed to + * users directly, its only use is for providing the pfhooks interface + * with a number it can use to uniquely identify an interface in time. + * + * Using a 32bit counter, over 136 plumbs would need to be done every + * second of every day (non-leap year) for it to wrap around and the + * for() loop below to kick in as a performance concern. + */ + if (arp_counter_wrapped) { + arl_t *as; + + do { + for (as = arl_g_head; as != NULL; as = as->arl_next) + if (as->arl_index == arp_index_counter) { + arp_index_counter++; + if (arp_index_counter == 0) { + arp_counter_wrapped++; + arp_index_counter = 1; + } + break; + } + } while (as != NULL); + } else { + arl->arl_index = arp_index_counter; + } + arp_index_counter++; + if (arp_index_counter == 0) { + arp_counter_wrapped++; + arp_index_counter = 1; + } } /* @@ -2527,6 +2599,7 @@ ar_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) ar_cleanup(); return (err); } + /* * We are D_MTPERMOD so it is safe to do qprocson before * the instance data has been initialized. @@ -3137,6 +3210,18 @@ ar_rput(queue_t *q, mblk_t *mp) * We should check here, but don't. */ DTRACE_PROBE2(rput_normal, arl_t *, arl, arh_t *, arh); + + DTRACE_PROBE3(arp__physical__in__start, + arl_t *, arl, arh_t *, arh, mblk_t *, mp); + + ARP_HOOK_IN(arp_physical_in_event, arp_physical_in, + arl->arl_index, arh, mp, mp1); + + DTRACE_PROBE1(arp__physical__in__end, mblk_t *, mp); + + if (mp == NULL) + return; + proto = (uint32_t)BE16_TO_U16(arh->arh_proto); src_haddr = (uchar_t *)arh; src_haddr = &src_haddr[ARH_FIXED_LEN]; @@ -3511,6 +3596,7 @@ ar_slifname(queue_t *q, mblk_t *mp_orig) arl_t *old_arl; mblk_t *ioccpy; struct iocblk *iocp; + hook_nic_event_t info; if (ar->ar_on_ill_stream) { /* @@ -3572,7 +3658,23 @@ ar_slifname(queue_t *q, mblk_t *mp_orig) /* The ppa is sent down by ifconfig */ arl->arl_ppa = lifr->lifr_ppa; + + /* + * A network device is not considered to be fully plumb'd until + * its name has been set using SIOCSLIFNAME. Once it has + * been set, it cannot be set again (see code above), so there + * is currently no danger in this function causing two NE_PLUMB + * events without an intervening NE_UNPLUMB. + */ + info.hne_nic = arl->arl_index; + info.hne_lif = 0; + info.hne_event = NE_PLUMB; + info.hne_data = arl->arl_name; + info.hne_datalen = strlen(arl->arl_name); + (void) hook_run(arpnicevents, (hook_data_t)&info); + /* Chain in the new arl. */ + rw_enter(&arl_g_lock, RW_WRITER); arl->arl_next = arl_g_head; arl_g_head = arl; DTRACE_PROBE1(slifname_set, arl_t *, arl); @@ -3588,6 +3690,8 @@ ar_slifname(queue_t *q, mblk_t *mp_orig) iocp->ioc_count = msgsize(ioccpy->b_cont); ioccpy->b_wptr = (uchar_t *)(iocp + 1); putnext(arl->arl_wq, ioccpy); + rw_exit(&arl_g_lock); + return (0); } @@ -3648,8 +3752,11 @@ ar_set_ppa(queue_t *q, mblk_t *mp_orig) arl->arl_ppa = ppa; DTRACE_PROBE1(setppa_done, arl_t *, arl); /* Chain in the new arl. */ + rw_enter(&arl_g_lock, RW_WRITER); arl->arl_next = arl_g_head; arl_g_head = arl; + rw_exit(&arl_g_lock); + return (0); } @@ -4355,6 +4462,18 @@ ar_xmit(arl_t *arl, uint32_t operation, uint32_t proto, uint32_t plen, bcopy(paddr2, cp, plen); cp += plen; mp->b_cont->b_wptr = cp; + + DTRACE_PROBE3(arp__physical__out__start, + arl_t *, arl, arh_t *, arh, mblk_t *, mp); + + ARP_HOOK_OUT(arp_physical_out_event, arp_physical_out, + arl->arl_index, arh, mp, mp->b_cont); + + DTRACE_PROBE1(arp__physical__out__end, mblk_t *, mp); + + if (mp == NULL) + return; + /* Ship it out. */ if (canputnext(arl->arl_wq)) putnext(arl->arl_wq, mp); diff --git a/usr/src/uts/common/inet/arp/arp_netinfo.c b/usr/src/uts/common/inet/arp/arp_netinfo.c new file mode 100644 index 0000000000..49dd1ef78a --- /dev/null +++ b/usr/src/uts/common/inet/arp/arp_netinfo.c @@ -0,0 +1,338 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/cmn_err.h> +#include <sys/stream.h> +#include <sys/sunddi.h> +#include <sys/hook.h> +#include <sys/hook_impl.h> +#include <net/if.h> + +#include <sys/neti.h> +#include <sys/hook_event.h> +#include <inet/arp_impl.h> + +/* + * ARP netinfo entry point declarations. + */ +static int arp_getifname(phy_if_t, char *, const size_t); +static int arp_getmtu(phy_if_t, lif_if_t); +static int arp_getpmtuenabled(void); +static int arp_getlifaddr(phy_if_t, lif_if_t, size_t, + net_ifaddr_t [], void *); +static phy_if_t arp_phygetnext(phy_if_t); +static phy_if_t arp_phylookup(const char *); +static lif_if_t arp_lifgetnext(phy_if_t, lif_if_t); +static int arp_inject(inject_t, net_inject_t *); +static phy_if_t arp_routeto(struct sockaddr *); +static int arp_ispartialchecksum(mblk_t *); +static int arp_isvalidchecksum(mblk_t *); + +static net_info_t arp_netinfo = { + NETINFO_VERSION, + NHF_ARP, + arp_getifname, + arp_getmtu, + arp_getpmtuenabled, + arp_getlifaddr, + arp_phygetnext, + arp_phylookup, + arp_lifgetnext, + arp_inject, + arp_routeto, + arp_ispartialchecksum, + arp_isvalidchecksum +}; + +static hook_family_t arproot; + +/* + * Hooks for ARP + */ + +hook_event_t arp_physical_in_event; +hook_event_t arp_physical_out_event; +hook_event_t arp_nic_events; + +hook_event_token_t arp_physical_in; +hook_event_token_t arp_physical_out; +hook_event_token_t arpnicevents; + +net_data_t arp = NULL; + +/* + * Register ARP netinfo functions. + */ +void +arp_net_init() +{ + + arp = net_register(&arp_netinfo); + ASSERT(arp != NULL); +} + +/* + * Unregister ARP netinfo functions. + */ +void +arp_net_destroy() +{ + + (void) net_unregister(arp); +} + +/* + * Initialize ARP hook family and events + */ +void +arp_hook_init() +{ + + HOOK_FAMILY_INIT(&arproot, Hn_ARP); + if (net_register_family(arp, &arproot) != 0) { + cmn_err(CE_NOTE, "arp_hook_init: " + "net_register_family failed for arp"); + } + + HOOK_EVENT_INIT(&arp_physical_in_event, NH_PHYSICAL_IN); + arp_physical_in = net_register_event(arp, &arp_physical_in_event); + if (arp_physical_in == NULL) { + cmn_err(CE_NOTE, "arp_hook_init: " + "net_register_event failed for arp/physical_in"); + } + + HOOK_EVENT_INIT(&arp_physical_out_event, NH_PHYSICAL_OUT); + arp_physical_out = net_register_event(arp, &arp_physical_out_event); + if (arp_physical_out == NULL) { + cmn_err(CE_NOTE, "arp_hook_init: " + "net_register_event failed for arp/physical_out"); + } + + HOOK_EVENT_INIT(&arp_nic_events, NH_NIC_EVENTS); + arpnicevents = net_register_event(arp, &arp_nic_events); + if (arpnicevents == NULL) { + cmn_err(CE_NOTE, "arp_hook_init: " + "net_register_event failed for arp/nic_events"); + } +} + + +void +arp_hook_destroy() +{ + if (arpnicevents != NULL) { + if (net_unregister_event(arp, &arp_nic_events) == 0) + arpnicevents = NULL; + } + + if (arp_physical_out != NULL) { + if (net_unregister_event(arp, &arp_physical_out_event) == 0) + arp_physical_out = NULL; + } + + if (arp_physical_in != NULL) { + if (net_unregister_event(arp, &arp_physical_in_event) == 0) + arp_physical_in = NULL; + } + + (void) net_unregister_family(arp, &arproot); +} + + +/* + * Determine the name of the lower level interface + */ +int +arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen) +{ + arl_t *arl; + + ASSERT(buffer != NULL); + + rw_enter(&arl_g_lock, RW_READER); + for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) { + if (arl->arl_index == phy_ifdata) { + (void) strlcpy(buffer, arl->arl_name, buflen); + rw_exit(&arl_g_lock); + return (0); + } + } + rw_exit(&arl_g_lock); + + return (1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + return (-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_getpmtuenabled(void) +{ + + return (-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, + net_ifaddr_t type[], void *storage) +{ + + return (-1); +} + + +/* + * Determine the instance number of the next lower level interface + */ +phy_if_t +arp_phygetnext(phy_if_t phy_ifdata) +{ + arl_t *arl; + int index; + + rw_enter(&arl_g_lock, RW_READER); + if (phy_ifdata == 0) { + arl = arl_g_head; + } else { + for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) { + if (arl->arl_index == phy_ifdata) { + arl = arl->arl_next; + break; + } + } + } + + index = (arl != NULL) ? arl->arl_index : 0; + + rw_exit(&arl_g_lock); + + return (index); +} + + +/* + * Given a network interface name, find its ARP layer instance number. + */ +phy_if_t +arp_phylookup(const char *name) +{ + arl_t *arl; + int index; + + ASSERT(name != NULL); + + index = 0; + + rw_enter(&arl_g_lock, RW_READER); + for (arl = arl_g_head; arl != NULL; arl = arl->arl_next) { + if (strcmp(name, arl->arl_name) == 0) { + index = arl->arl_index; + break; + } + } + rw_exit(&arl_g_lock); + + return (index); + +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +lif_if_t +arp_lifgetnext(phy_if_t ifp, lif_if_t lif) +{ + return (lif_if_t)(-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_inject(inject_t injection, net_inject_t *neti) +{ + return (-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +phy_if_t +arp_routeto(struct sockaddr *addr) +{ + return (phy_if_t)(-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_ispartialchecksum(mblk_t *mb) +{ + return (-1); +} + + +/* + * Unsupported with ARP. + */ +/*ARGSUSED*/ +int +arp_isvalidchecksum(mblk_t *mb) +{ + return (-1); +} diff --git a/usr/src/uts/common/inet/arp/arpddi.c b/usr/src/uts/common/inet/arp/arpddi.c index da5052c512..7443d0a9bd 100644 --- a/usr/src/uts/common/inet/arp/arpddi.c +++ b/usr/src/uts/common/inet/arp/arpddi.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 1992-2002 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -30,8 +29,10 @@ #include <sys/types.h> #include <sys/conf.h> #include <sys/modctl.h> +#include <sys/ksynch.h> #include <inet/common.h> #include <inet/ip.h> +#include <inet/arp_impl.h> #define INET_NAME "arp" #define INET_MODDESC "ARP STREAMS module %I%" @@ -41,19 +42,34 @@ #define INET_DEVMTFLAGS IP_DEVMTFLAGS /* since as a driver we're ip */ #define INET_MODMTFLAGS (D_MP | D_MTPERMOD) +static void arp_ddi_destroy(); +static void arp_ddi_init(); + #include "../inetddi.c" int _init(void) { + int error; + + arp_ddi_init(); INET_BECOME_IP(); - return (mod_install(&modlinkage)); + + error = mod_install(&modlinkage); + if (error != 0) + arp_ddi_destroy(); + return error; } int _fini(void) { - return (mod_remove(&modlinkage)); + int error; + + error = mod_remove(&modlinkage); + if (error == 0) + arp_ddi_destroy(); + return error; } int @@ -61,3 +77,21 @@ _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } + + +static void +arp_ddi_init() +{ + rw_init(&arl_g_lock, "ARP ARl lock", RW_DRIVER, NULL); + arp_net_init(); + arp_hook_init(); +} + + +static void +arp_ddi_destroy() +{ + arp_hook_destroy(); + arp_net_destroy(); + rw_destroy(&arl_g_lock); +} diff --git a/usr/src/uts/common/inet/arp_impl.h b/usr/src/uts/common/inet/arp_impl.h index e87fc69ab3..a95a335e7f 100644 --- a/usr/src/uts/common/inet/arp_impl.h +++ b/usr/src/uts/common/inet/arp_impl.h @@ -72,8 +72,12 @@ typedef struct arl_s { arl_closing : 1, /* stream is closing */ arl_notifies : 1, /* handles DL_NOTE_LINK */ arl_link_up : 1; /* DL_NOTE status */ + uint32_t arl_index; /* instance number */ } arl_t; +extern arl_t *arl_g_head; /* ARL chain head */ +extern krwlock_t arl_g_lock; + #define ARL_F_NOARP 0x01 #define ARL_S_DOWN 0x00 @@ -113,6 +117,74 @@ typedef struct ace_s { int ace_xmit_count; } ace_t; +/* + * Hooks structures used inside of arp + */ +extern hook_event_token_t arp_physical_in; +extern hook_event_token_t arp_physical_out; +extern hook_event_token_t arpnicevents; + +extern hook_event_t arp_physical_in_event; +extern hook_event_t arp_physical_out_event; +extern hook_event_t arp_nic_events; + +#define ARPHOOK_INTERESTED_PHYSICAL_IN \ + (arp_physical_in_event.he_interested) +#define ARPHOOK_INTERESTED_PHYSICAL_OUT \ + (arp_physical_out_event.he_interested) + +#define ARP_HOOK_IN(_hook, _event, _ilp, _hdr, _fm, _m) \ + \ + if ((_hook).he_interested) { \ + hook_pkt_event_t info; \ + \ + info.hpe_ifp = _ilp; \ + info.hpe_ofp = 0; \ + info.hpe_hdr = _hdr; \ + info.hpe_mp = &(_fm); \ + info.hpe_mb = _m; \ + if (hook_run(_event, (hook_data_t)&info) != 0) {\ + if (_fm != NULL) { \ + freemsg(_fm); \ + _fm = NULL; \ + } \ + _hdr = NULL; \ + _m = NULL; \ + } else { \ + _hdr = info.hpe_hdr; \ + _m = info.hpe_mb; \ + } \ + } + +#define ARP_HOOK_OUT(_hook, _event, _olp, _hdr, _fm, _m) \ + \ + if ((_hook).he_interested) { \ + hook_pkt_event_t info; \ + \ + info.hpe_ifp = 0; \ + info.hpe_ofp = _olp; \ + info.hpe_hdr = _hdr; \ + info.hpe_mp = &(_fm); \ + info.hpe_mb = _m; \ + if (hook_run(_event, \ + (hook_data_t)&info) != 0) { \ + if (_fm != NULL) { \ + freemsg(_fm); \ + _fm = NULL; \ + } \ + _hdr = NULL; \ + _m = NULL; \ + } else { \ + _hdr = info.hpe_hdr; \ + _m = info.hpe_mb; \ + } \ + } + +extern void arp_hook_init(); +extern void arp_hook_destroy(); +extern void arp_net_init(); +extern void arp_net_destroy(); + #endif /* _KERNEL */ #ifdef __cplusplus diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index 672da54818..2fa1281806 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -43,6 +43,10 @@ extern "C" { #include <net/if.h> #include <netinet/ip.h> #include <netinet/igmp.h> +#include <sys/neti.h> +#include <sys/hook.h> +#include <sys/hook_event.h> +#include <sys/hook_impl.h> #ifdef _KERNEL #include <netinet/ip6.h> @@ -1832,6 +1836,11 @@ typedef struct ill_s { int ill_ip_muxid; /* muxid returned from plink for ip */ /* + * NIC event information attached, to be used by nic event hooks. + */ + hook_nic_event_t *ill_nic_event_info; + + /* * Used for IP frag reassembly throttling on a per ILL basis. * * Note: frag_count is approximate, its added to and subtracted from @@ -2917,6 +2926,145 @@ extern timeout_id_t mld_slowtimeout_id; extern uint_t loopback_packets; /* + * Hooks structures used inside of ip + */ +extern hook_event_token_t ipv4firewall_physical_in; +extern hook_event_token_t ipv4firewall_physical_out; +extern hook_event_token_t ipv4firewall_forwarding; +extern hook_event_token_t ipv4firewall_loopback_in; +extern hook_event_token_t ipv4firewall_loopback_out; +extern hook_event_token_t ipv4nicevents; + +extern hook_event_token_t ipv6firewall_physical_in; +extern hook_event_token_t ipv6firewall_physical_out; +extern hook_event_token_t ipv6firewall_forwarding; +extern hook_event_token_t ipv6firewall_loopback_in; +extern hook_event_token_t ipv6firewall_loopback_out; +extern hook_event_token_t ipv6nicevents; + +extern hook_event_t ip4_physical_in_event; +extern hook_event_t ip4_physical_out_event; +extern hook_event_t ip4_forwarding_event; +extern hook_event_t ip4_loopback_in_event; +extern hook_event_t ip4_loopback_out_event; +extern hook_event_t ip4_nic_events; + +extern hook_event_t ip6_physical_in_event; +extern hook_event_t ip6_physical_out_event; +extern hook_event_t ip6_forwarding_event; +extern hook_event_t ip6_loopback_in_event; +extern hook_event_t ip6_loopback_out_event; +extern hook_event_t ip6_nic_events; + +#define HOOKS4_INTERESTED_PHYSICAL_IN \ + (ip4_physical_in_event.he_interested) +#define HOOKS6_INTERESTED_PHYSICAL_IN \ + (ip6_physical_in_event.he_interested) +#define HOOKS4_INTERESTED_PHYSICAL_OUT \ + (ip4_physical_out_event.he_interested) +#define HOOKS6_INTERESTED_PHYSICAL_OUT \ + (ip6_physical_out_event.he_interested) +#define HOOKS4_INTERESTED_FORWARDING \ + (ip4_forwarding_event.he_interested) +#define HOOKS6_INTERESTED_FORWARDING \ + (ip6_forwarding_event.he_interested) +#define HOOKS4_INTERESTED_LOOPBACK_IN \ + (ip4_loopback_in_event.he_interested) +#define HOOKS6_INTERESTED_LOOPBACK_IN \ + (ip6_loopback_in_event.he_interested) +#define HOOKS4_INTERESTED_LOOPBACK_OUT \ + (ip4_loopback_out_event.he_interested) +#define HOOKS6_INTERESTED_LOOPBACK_OUT \ + (ip6_loopback_out_event.he_interested) + +/* + * Hooks marcos used inside of ip + */ +#define IPHA_VHL ipha_version_and_hdr_length + +#define FW_HOOKS(_hook, _event, _flag, _ilp, _olp, _iph, _fm, _m) \ + \ + if ((_hook).he_interested) { \ + hook_pkt_event_t info; \ + \ + _NOTE(CONSTCOND) \ + ASSERT((_ilp != NULL) || (_olp != NULL)); \ + \ + _NOTE(CONSTCOND) \ + if ((_ilp != NULL) && \ + (((ill_t *)(_ilp))->ill_phyint != NULL)) \ + info.hpe_ifp = (phy_if_t)((ill_t *) \ + (_ilp))->ill_phyint->phyint_ifindex; \ + else \ + info.hpe_ifp = 0; \ + \ + _NOTE(CONSTCOND) \ + if ((_olp != NULL) && \ + (((ill_t *)(_olp))->ill_phyint != NULL)) \ + info.hpe_ofp = (phy_if_t)((ill_t *) \ + (_olp))->ill_phyint->phyint_ifindex; \ + else \ + info.hpe_ofp = 0; \ + info.hpe_hdr = _iph; \ + info.hpe_mp = &(_fm); \ + info.hpe_mb = _m; \ + if (hook_run(_event, (hook_data_t)&info) != 0) { \ + ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\ + (_hook).he_name, (void *)_fm, (void *)_m)); \ + if (_fm != NULL) { \ + freemsg(_fm); \ + _fm = NULL; \ + } \ + _iph = NULL; \ + _m = NULL; \ + } else { \ + _iph = info.hpe_hdr; \ + _m = info.hpe_mb; \ + } \ + } + +#define FW_HOOKS6(_hook, _event, _flag, _ilp, _olp, _iph, _fm, _m) \ + \ + if ((_hook).he_interested) { \ + hook_pkt_event_t info; \ + \ + _NOTE(CONSTCOND) \ + ASSERT((_ilp != NULL) || (_olp != NULL)); \ + \ + _NOTE(CONSTCOND) \ + if ((_ilp != NULL) && \ + (((ill_t *)(_ilp))->ill_phyint != NULL)) \ + info.hpe_ifp = (phy_if_t)((ill_t *) \ + (_ilp))->ill_phyint->phyint_ifindex; \ + else \ + info.hpe_ifp = 0; \ + \ + _NOTE(CONSTCOND) \ + if ((_olp != NULL) && \ + (((ill_t *)(_olp))->ill_phyint != NULL)) \ + info.hpe_ofp = (phy_if_t)((ill_t *) \ + (_olp))->ill_phyint->phyint_ifindex; \ + else \ + info.hpe_ofp = 0; \ + info.hpe_hdr = _iph; \ + info.hpe_mp = &(_fm); \ + info.hpe_mb = _m; \ + if (hook_run(_event, (hook_data_t)&info) != 0) { \ + ip2dbg(("%s hook dropped mblk chain %p hdr %p\n",\ + (_hook).he_name, (void *)_fm, (void *)_m)); \ + if (_fm != NULL) { \ + freemsg(_fm); \ + _fm = NULL; \ + } \ + _iph = NULL; \ + _m = NULL; \ + } else { \ + _iph = info.hpe_hdr; \ + _m = info.hpe_mb; \ + } \ + } + +/* * Network byte order macros */ #ifdef _BIG_ENDIAN @@ -3049,6 +3197,9 @@ extern struct qinit winit_tcp; extern struct qinit rinit_acceptor_tcp; extern struct qinit winit_acceptor_tcp; +extern net_data_t ipv4; +extern net_data_t ipv6; + extern void conn_drain_insert(conn_t *connp); extern int conn_ipsec_length(conn_t *connp); extern void ip_wput_ipsec_out(queue_t *, mblk_t *, ipha_t *, ill_t *, diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c index 9547087c94..e0dc4bf667 100644 --- a/usr/src/uts/common/inet/ip/ip.c +++ b/usr/src/uts/common/inet/ip/ip.c @@ -51,6 +51,7 @@ #include <sys/systm.h> #include <sys/param.h> #include <sys/kmem.h> +#include <sys/sdt.h> #include <sys/socket.h> #include <sys/vtrace.h> #include <sys/isa_defs.h> @@ -99,6 +100,7 @@ #include <sys/iphada.h> #include <inet/tun.h> #include <inet/ipdrop.h> +#include <inet/ip_netinfo.h> #include <sys/ethernet.h> #include <net/if_types.h> @@ -115,6 +117,7 @@ #include <inet/sctp_ip.h> #include <inet/sctp/sctp_impl.h> #include <inet/udp_impl.h> +#include <sys/sunddi.h> #include <sys/tsol/label.h> #include <sys/tsol/tnet.h> @@ -1469,6 +1472,9 @@ nv_t *ire_nv_tbl = ire_nv_arr; /* Defined in ip_if.c, protect the list of IPsec capable ills */ extern krwlock_t ipsec_capab_ills_lock; +/* Defined in ip_netinfo.c */ +extern ddi_taskq_t *eventq_queue_nic; + /* Packet dropper for IP IPsec processing failures */ ipdropper_t ip_dropper; @@ -5338,6 +5344,7 @@ ip_modclose(ill_t *ill) ipsq_t *ipsq; ipif_t *ipif; queue_t *q = ill->ill_rq; + hook_nic_event_t *info; /* * Forcibly enter the ipsq after some delay. This is to take @@ -5436,6 +5443,21 @@ ip_modclose(ill_t *ill) if (ill->ill_credp != NULL) crfree(ill->ill_credp); + /* + * Unhook the nic event message from the ill and enqueue it into the nic + * event taskq. + */ + if ((info = ill->ill_nic_event_info) != NULL) { + if (ddi_taskq_dispatch(eventq_queue_nic, ip_ne_queue_func, + (void *)info, DDI_SLEEP) == DDI_FAILURE) { + ip2dbg(("ip_ioctl_finish:ddi_taskq_dispatch failed\n")); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + ill->ill_nic_event_info = NULL; + } + mi_close_free((IDP)ill); q->q_ptr = WR(q)->q_ptr = NULL; @@ -5701,6 +5723,10 @@ ip_csum_hdr(ipha_t *ipha) void ip_ddi_destroy(void) { + ipv4_hook_destroy(); + ipv6_hook_destroy(); + ip_net_destroy(); + tnet_fini(); tcp_ddi_destroy(); sctp_ddi_destroy(); @@ -5794,6 +5820,10 @@ ip_ddi_init(void) icmp_kstat_init(); ipsec_loader_start(); tnet_init(); + + ip_net_init(); + ipv4_hook_init(); + ipv6_hook_init(); } /* @@ -7200,6 +7230,7 @@ ip_mrtun_forward(ire_t *ire, ill_t *in_ill, mblk_t *mp) mblk_t *first_mp; uint32_t ill_index; ipxmit_state_t pktxmit_state; + ill_t *out_ill; ASSERT(ire != NULL); ASSERT(ire->ire_ipif->ipif_net_type == IRE_IF_NORESOLVER); @@ -7259,6 +7290,26 @@ ip_mrtun_forward(ire_t *ire, ill_t *in_ill, mblk_t *mp) ill_index = ire->ire_ipif->ipif_ill->ill_phyint->phyint_ifindex; /* + * This location is chosen for the placement of the forwarding hook + * because at this point we know that we have a path out for the + * packet but haven't yet applied any logic (such as fragmenting) + * that happen as part of transmitting the packet out. + */ + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip4__forwarding__start, + ill_t *, in_ill, ill_t *, out_ill, ipha_t *, ipha, mblk_t *, mp); + + FW_HOOKS(ip4_forwarding_event, ipv4firewall_forwarding, + MSG_FWCOOKED_FORWARD, in_ill, out_ill, ipha, mp, mp); + + DTRACE_PROBE1(ip4__forwarding__end, mblk_t *, mp); + + if (mp == NULL) + return; + pkt_len = ntohs(ipha->ipha_length); + + /* * ip_mrtun_forward is only used by foreign agent to reverse * tunnel the incoming packet. So it does not do any option * processing for source routing. @@ -7302,6 +7353,14 @@ ip_mrtun_forward(ire_t *ire, ill_t *in_ill, mblk_t *mp) ASSERT(ire->ire_ipif != NULL); + DTRACE_PROBE4(ip4__physical__out__start, ill_t *, NULL, + ill_t *, ire->ire_ipif->ipif_ill, ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp == NULL) + return; + /* Now send the packet to the tunnel interface */ mp->b_prev = SET_BPREV_FLAG(IPP_FWD_OUT); q = ire->ire_stq; @@ -13523,14 +13582,6 @@ ip_rput_notforus(queue_t **qp, mblk_t *mp, ire_t *ire, ill_t *ill) return (B_FALSE); } -#define SEND_PKT(ire, mp) \ -{ \ - UPDATE_IB_PKT_COUNT(ire); \ - (ire)->ire_last_used_time = lbolt; \ - BUMP_MIB(&ip_mib, ipForwDatagrams); \ - putnext((ire)->ire_stq, mp); \ -} - ire_t * ip_fast_forward(ire_t *ire, ipaddr_t dst, ill_t *ill, mblk_t *mp) { @@ -13616,6 +13667,17 @@ ip_fast_forward(ire_t *ire, ipaddr_t dst, ill_t *ill, mblk_t *mp) return (ire); } + DTRACE_PROBE4(ip4__forwarding__start, + ill_t *, ill, ill_t *, stq_ill, ipha_t *, ipha, mblk_t *, mp); + + FW_HOOKS(ip4_forwarding_event, ipv4firewall_forwarding, + MSG_FWCOOKED_FORWARD, ill, stq_ill, ipha, mp, mp); + + DTRACE_PROBE1(ip4__forwarding__end, mblk_t *, mp); + + if (mp == NULL) + goto drop; + mp->b_datap->db_struioun.cksum.flags = 0; /* Adjust the checksum to reflect the ttl decrement. */ sum = (int)ipha->ipha_hdr_checksum + IP_HDR_CSUM_TTL_ADJUST; @@ -13632,9 +13694,25 @@ ip_fast_forward(ire_t *ire, ipaddr_t dst, ill_t *ill, mblk_t *mp) MBLKL(ire->ire_nce->nce_fp_mp) : 0; if (hlen != 0 || ire->ire_nce->nce_res_mp != NULL) { - mp = ip_wput_attach_llhdr(mp, ire, 0, 0); + mblk_t *mpip = mp; + + mp = ip_wput_attach_llhdr(mpip, ire, 0, 0); if (mp != NULL) { - SEND_PKT(ire, mp); + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, ill_t *, stq_ill, + ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, + ipv4firewall_physical_out, MSG_FWCOOKED_OUT, NULL, + stq_ill, ipha, mp, mpip); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, + mp); + if (mp == NULL) + goto drop; + + UPDATE_IB_PKT_COUNT(ire); + ire->ire_last_used_time = lbolt; + BUMP_MIB(&ip_mib, ipForwDatagrams); + putnext(ire->ire_stq, mp); return (ire); } } @@ -14492,6 +14570,30 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, } } + /* + * The event for packets being received from a 'physical' + * interface is placed before validation of the source and/or + * destination address as being local so that packets such as + * these that are found on the network can be observed via + * this interface. The checks prior to this have all been + * to do with validating the sanity of the packet - length + * fields vs data in the buffer, buffer size, etc, otherwise + * uninteresting packet flaws that will always lead to them + * being discarded. + */ + DTRACE_PROBE4(ip4__physical__in__start, + ill_t *, ill, ill_t *, NULL, + ipha_t *, ipha, mblk_t *, first_mp); + + FW_HOOKS(ip4_physical_in_event, ipv4firewall_physical_in, + MSG_FWCOOKED_IN, ill, NULL, ipha, first_mp, mp); + + DTRACE_PROBE1(ip4__physical__in__end, mblk_t *, first_mp); + + if (first_mp == NULL) { + continue; + } + /* Obtain the dst of the current packet */ dst = ipha->ipha_dst; @@ -14505,6 +14607,26 @@ ip_input(ill_t *ill, ill_rx_ring_t *ip_ring, mblk_t *mp_chain, } /* + * The event for packets being received from a 'physical' + * interface is placed after validation of the source and/or + * destination address as being local so that packets can be + * redirected to loopback addresses using ipnat. + */ + DTRACE_PROBE4(ip4__physical__in__start, + ill_t *, ill, ill_t *, NULL, + ipha_t *, ipha, mblk_t *, first_mp); + + FW_HOOKS(ip4_physical_in_event, ipv4firewall_physical_in, + MSG_FWCOOKED_IN, ill, NULL, ipha, first_mp, mp); + + DTRACE_PROBE1(ip4__physical__in__end, mblk_t *, first_mp); + + if (first_mp == NULL) { + continue; + } + dst = ipha->ipha_dst; + + /* * Attach any necessary label information to * this packet */ @@ -15007,6 +15129,7 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) boolean_t success; boolean_t ioctl_aborted = B_FALSE; boolean_t log = B_TRUE; + hook_nic_event_t *info; ip1dbg(("ip_rput_dlpi_writer ..")); ill = (ill_t *)q->q_ptr; @@ -15247,7 +15370,33 @@ ip_rput_dlpi_writer(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *dummy_arg) ip1dbg(("ip_rput_dlpi: bind_ack %s\n", ill->ill_name)); mutex_enter(&ill->ill_lock); + ill->ill_dl_up = 1; + + if ((info = ill->ill_nic_event_info) != NULL) { + ip2dbg(("ip_rput_dlpi_writer: unexpected nic event %d " + "attached for %s\n", info->hne_event, + ill->ill_name)); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + + info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP); + if (info != NULL) { + info->hne_nic = ill->ill_phyint->phyint_ifindex; + info->hne_lif = 0; + info->hne_event = NE_UP; + info->hne_data = NULL; + info->hne_datalen = 0; + info->hne_family = ill->ill_isv6 ? ipv6 : ipv4; + } else + ip2dbg(("ip_rput_dlpi_writer: could not attach UP nic " + "event information for %s (ENOMEM)\n", + ill->ill_name)); + + ill->ill_nic_event_info = info; + mutex_exit(&ill->ill_lock); /* @@ -16068,6 +16217,7 @@ ip_rput_forward(ire_t *ire, ipha_t *ipha, mblk_t *mp, ill_t *in_ill) #define rptr ((uchar_t *)ipha) uint32_t max_frag; uint32_t ill_index; + ill_t *out_ill; /* Get the ill_index of the incoming ILL */ ill_index = (in_ill != NULL) ? in_ill->ill_phyint->phyint_ifindex : 0; @@ -16122,6 +16272,20 @@ ip_rput_forward(ire_t *ire, ipha_t *ipha, mblk_t *mp, ill_t *in_ill) /* Get the ill_index of the outgoing ILL */ ill_index = ire->ire_ipif->ipif_ill->ill_phyint->phyint_ifindex; + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip4__forwarding__start, + ill_t *, in_ill, ill_t *, out_ill, ipha_t *, ipha, mblk_t *, mp); + + FW_HOOKS(ip4_forwarding_event, ipv4firewall_forwarding, + MSG_FWCOOKED_FORWARD, in_ill, out_ill, ipha, mp, mp); + + DTRACE_PROBE1(ip4__forwarding__end, mblk_t *, mp); + + if (mp == NULL) + return; + pkt_len = ntohs(ipha->ipha_length); + if (is_system_labeled()) { mblk_t *mp1; @@ -16174,6 +16338,15 @@ ip_rput_forward(ire_t *ire, ipha_t *ipha, mblk_t *mp, ill_t *in_ill) ip2dbg(("ip_rput_forward:sent to ip_wput_frag\n")); return; } + + DTRACE_PROBE4(ip4__physical__out__start, ill_t *, NULL, + ill_t *, ire->ire_ipif->ipif_ill, ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp == NULL) + return; + mp->b_prev = (mblk_t *)IPP_FWD_OUT; ip1dbg(("ip_rput_forward: Calling ip_xmit_v4\n")); (void) ip_xmit_v4(mp, ire, NULL, B_FALSE); @@ -21242,6 +21415,7 @@ ip_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller, ill_t *conn_outgoing_ill = NULL; ill_t *ire_ill; ill_t *ire1_ill; + ill_t *out_ill; uint32_t ill_index = 0; boolean_t multirt_send = B_FALSE; int err; @@ -21772,6 +21946,16 @@ another:; multirt_send = B_FALSE; } } + + DTRACE_PROBE4(ip4__physical__out__start, ill_t *, NULL, + ill_t *, ire->ire_ipif->ipif_ill, ipha_t *, ipha, + mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, ire->ire_ipif->ipif_ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp == NULL) + goto release_ire_and_ill; + mp->b_prev = SET_BPREV_FLAG(IPP_LOCAL_OUT); DTRACE_PROBE2(ip__xmit__1, mblk_t *, mp, ire_t *, ire); pktxmit_state = ip_xmit_v4(mp, ire, NULL, B_TRUE); @@ -21779,6 +21963,7 @@ another:; (pktxmit_state == LLHDR_RESLV_FAILED)) { ip2dbg(("ip_wput_ire: ip_xmit_v4 failed" "- packet dropped\n")); +release_ire_and_ill: ire_refrele(ire); if (next_mp != NULL) { freemsg(next_mp); @@ -22347,6 +22532,20 @@ broadcast: } } + out_ill = ire->ire_ipif->ipif_ill; + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, + ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, + ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, + ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, + mblk_t *, mp); + if (mp == NULL) + goto release_ire_and_ill_2; + ASSERT(ipsec_len == 0); mp->b_prev = SET_BPREV_FLAG(IPP_LOCAL_OUT); @@ -22356,6 +22555,7 @@ broadcast: NULL, B_TRUE); if ((pktxmit_state == SEND_FAILED) || (pktxmit_state == LLHDR_RESLV_FAILED)) { +release_ire_and_ill_2: if (next_mp) { freemsg(next_mp); ire_refrele(ire1); @@ -22510,18 +22710,54 @@ broadcast: ire->ire_last_used_time = lbolt; ASSERT(ire->ire_ipif != NULL); if (!next_mp) { + /* + * Is there an "in" and "out" for traffic local + * to a host (loopback)? The code in Solaris doesn't + * explicitly draw a line in its code for in vs out, + * so we've had to draw a line in the sand: ip_wput_ire + * is considered to be the "output" side and + * ip_wput_local to be the "input" side. + */ + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip4__loopback__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, first_mp); + + FW_HOOKS(ip4_loopback_out_event, + ipv4firewall_loopback_out, MSG_FWCOOKED_OUT, + NULL, out_ill, ipha, first_mp, mp); + + DTRACE_PROBE1(ip4__loopback__out_end, + mblk_t *, first_mp); + TRACE_2(TR_FAC_IP, TR_IP_WPUT_IRE_END, "ip_wput_ire_end: q %p (%S)", q, "local address"); - ip_wput_local(q, ire->ire_ipif->ipif_ill, ipha, - first_mp, ire, 0, ire->ire_zoneid); + + if (first_mp != NULL) + ip_wput_local(q, out_ill, ipha, + first_mp, ire, 0, ire->ire_zoneid); ire_refrele(ire); if (conn_outgoing_ill != NULL) ill_refrele(conn_outgoing_ill); return; } - ip_wput_local(q, ire->ire_ipif->ipif_ill, ipha, first_mp, - ire, 0, ire->ire_zoneid); + + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip4__loopback__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, first_mp); + + FW_HOOKS(ip4_loopback_out_event, ipv4firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, first_mp, mp); + + DTRACE_PROBE1(ip4__loopback__out__end, mblk_t *, first_mp); + + if (first_mp != NULL) + ip_wput_local(q, out_ill, ipha, + first_mp, ire, 0, ire->ire_zoneid); } next: /* @@ -23072,13 +23308,14 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, ipha_t *ipha; int ip_data_end; int len; - mblk_t *mp = mp_orig; + mblk_t *mp = mp_orig, *mp1; int offset; queue_t *q; uint32_t v_hlen_tos_len; mblk_t *first_mp; boolean_t mctl_present; ill_t *ill; + ill_t *out_ill; mblk_t *xmit_mp; mblk_t *carve_mp; ire_t *ire1 = NULL; @@ -23440,13 +23677,27 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, UNLOCK_IRE_FP_MP(ire); q = ire->ire_stq; BUMP_MIB(&ip_mib, ipFragCreates); - putnext(q, xmit_mp); - if (pkt_type != OB_PKT) { - /* - * Update the packet count of trailing - * RTF_MULTIRT ires. - */ - UPDATE_OB_PKT_COUNT(ire); + + out_ill = (ill_t *)q->q_ptr; + + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, xmit_mp); + + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, xmit_mp, mp); + + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, xmit_mp); + + if (xmit_mp != NULL) { + putnext(q, xmit_mp); + if (pkt_type != OB_PKT) { + /* + * Update the packet count of trailing + * RTF_MULTIRT ires. + */ + UPDATE_OB_PKT_COUNT(ire); + } } if (multirt_send) { @@ -23709,14 +23960,36 @@ ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, } UNLOCK_IRE_FP_MP(ire); BUMP_MIB(&ip_mib, ipFragCreates); - putnext(q, xmit_mp); - if (pkt_type != OB_PKT) { - /* - * Update the packet count of trailing - * RTF_MULTIRT ires. - */ - UPDATE_OB_PKT_COUNT(ire); + mp1 = mp; + out_ill = (ill_t *)q->q_ptr; + + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, xmit_mp); + + FW_HOOKS(ip4_physical_out_event, + ipv4firewall_physical_out, MSG_FWCOOKED_OUT, + NULL, out_ill, ipha, xmit_mp, mp); + + DTRACE_PROBE1(ip4__physical__out__end, + mblk_t *, xmit_mp); + + if (mp != mp1 && hdr_mp == mp1) + hdr_mp = mp; + if (mp != mp1 && mp_orig == mp1) + mp_orig = mp; + + if (xmit_mp != NULL) { + putnext(q, xmit_mp); + + if (pkt_type != OB_PKT) { + /* + * Update the packet count of trailing + * RTF_MULTIRT ires. + */ + UPDATE_OB_PKT_COUNT(ire); + } } /* All done if we just consumed the hdr_mp. */ @@ -23901,6 +24174,18 @@ ip_wput_local(queue_t *q, ill_t *ill, ipha_t *ipha, mblk_t *mp, ire_t *ire, mctl_present = B_FALSE; } + DTRACE_PROBE4(ip4__loopback__in__start, + ill_t *, ill, ill_t *, NULL, + ipha_t *, ipha, mblk_t *, first_mp); + + FW_HOOKS(ip4_loopback_in_event, ipv4firewall_loopback_in, + MSG_FWCOOKED_IN, ill, NULL, ipha, first_mp, mp); + + DTRACE_PROBE1(ip4__loopback__in__end, mblk_t *, first_mp); + + if (first_mp == NULL) + return; + loopback_packets++; ip2dbg(("ip_wput_local: from 0x%x to 0x%x in zone %d\n", @@ -24447,6 +24732,7 @@ ip_wput_ipsec_out_v6(queue_t *q, mblk_t *ipsec_mp, ip6_t *ip6h, ill_t *ill, zoneid_t zoneid; boolean_t ill_need_rele = B_FALSE; boolean_t ire_need_rele = B_FALSE; + ill_t *out_ill; mp = ipsec_mp->b_cont; io = (ipsec_out_t *)ipsec_mp->b_rptr; @@ -24605,8 +24891,23 @@ send: /* Local delivery */ if (ire->ire_stq == NULL) { ASSERT(q != NULL); - ip_wput_local_v6(RD(q), ire->ire_ipif->ipif_ill, ip6h, ipsec_mp, - ire, 0); + + /* PFHooks: LOOPBACK_OUT */ + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip6__loopback__out__start, + ill_t *, NULL, ill_t *, out_ill, + ip6_t *, ip6h, mblk_t *, ipsec_mp); + + FW_HOOKS6(ip6_loopback_out_event, ipv6firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ip6h, + ipsec_mp, mp); + + DTRACE_PROBE1(ip6__loopback__out__end, mblk_t *, ipsec_mp); + + if (ipsec_mp != NULL) + ip_wput_local_v6(RD(q), out_ill, + ip6h, ipsec_mp, ire, 0); if (ire_need_rele) ire_refrele(ire); return; @@ -24734,6 +25035,7 @@ ip_wput_ipsec_out(queue_t *q, mblk_t *ipsec_mp, ipha_t *ipha, ill_t *ill, uint32_t cksum; uint16_t *up; ipxmit_state_t pktxmit_state; + ill_t *out_ill; #ifdef _BIG_ENDIAN #define LENGTH (v_hlen_tos_len & 0xFFFF) #else @@ -24950,8 +25252,22 @@ send: ire->ire_last_used_time = lbolt; if (ipha->ipha_src == 0) ipha->ipha_src = ire->ire_src_addr; - ip_wput_local(RD(q), ire->ire_ipif->ipif_ill, ipha, ipsec_mp, - ire, 0, zoneid); + + /* PFHooks: LOOPBACK_OUT */ + out_ill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip4__loopback__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, ipsec_mp); + + FW_HOOKS(ip4_loopback_out_event, ipv4firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, ipsec_mp, mp); + + DTRACE_PROBE1(ip4__loopback__out__end, mblk_t *, ipsec_mp); + + if (ipsec_mp != NULL) + ip_wput_local(RD(q), out_ill, + ipha, ipsec_mp, ire, 0, zoneid); if (ire_need_rele) ire_refrele(ire); goto done; @@ -25155,6 +25471,15 @@ send: goto drop_pkt; } + DTRACE_PROBE4(ip4__physical__out__start, ill_t *, NULL, + ill_t *, ire->ire_ipif->ipif_ill, ipha_t *, ipha, + mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp == NULL) + goto drop_pkt; + ip1dbg(("ip_wput_ipsec_out: calling ip_xmit_v4\n")); pktxmit_state = ip_xmit_v4(mp, ire, (io->ipsec_out_accelerated ? io : NULL), B_FALSE); @@ -25947,6 +26272,7 @@ ip_ioctl_finish(queue_t *q, mblk_t *mp, int err, int mode, ipif_t *ipif, ipsq_t *ipsq) { conn_t *connp = NULL; + hook_nic_event_t *info; if (err == EINPROGRESS) return; @@ -25986,6 +26312,26 @@ ip_ioctl_finish(queue_t *q, mblk_t *mp, int err, int mode, if (ipif != NULL) { mutex_enter(&(ipif)->ipif_ill->ill_lock); ipif->ipif_state_flags &= ~IPIF_CHANGING; + + /* + * Unhook the nic event message from the ill and enqueue it into + * the nic event taskq. + */ + if ((info = ipif->ipif_ill->ill_nic_event_info) != NULL) { + if (ddi_taskq_dispatch(eventq_queue_nic, + ip_ne_queue_func, (void *)info, DDI_SLEEP) + == DDI_FAILURE) { + ip2dbg(("ip_ioctl_finish: ddi_taskq_dispatch" + "failed\n")); + if (info->hne_data != NULL) + kmem_free(info->hne_data, + info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + + ipif->ipif_ill->ill_nic_event_info = NULL; + } + mutex_exit(&(ipif)->ipif_ill->ill_lock); } @@ -28305,9 +28651,10 @@ ip_xmit_v4(mblk_t *mp, ire_t *ire, ipsec_out_t *io, boolean_t flow_ctl_enabled) nce_t *arpce; queue_t *q; int ill_index; - mblk_t *nxt_mp; + mblk_t *nxt_mp, *first_mp; boolean_t xmit_drop = B_FALSE; ip_proc_t proc; + ill_t *out_ill; arpce = ire->ire_nce; ASSERT(arpce != NULL); @@ -28343,10 +28690,11 @@ ip_xmit_v4(mblk_t *mp, ire_t *ire, ipsec_out_t *io, boolean_t flow_ctl_enabled) mp->b_prev = NULL; /* set up ill index for outbound qos processing */ - ill_index = - ire->ire_ipif->ipif_ill->ill_phyint->phyint_ifindex; - mp = ip_wput_attach_llhdr(mp, ire, proc, ill_index); - if (mp == NULL) { + out_ill = ire->ire_ipif->ipif_ill; + ill_index = out_ill->ill_phyint->phyint_ifindex; + first_mp = ip_wput_attach_llhdr(mp, ire, proc, + ill_index); + if (first_mp == NULL) { xmit_drop = B_TRUE; if (proc == IPP_FWD_OUT) { BUMP_MIB(&ip_mib, ipInDiscards); @@ -28366,28 +28714,20 @@ ip_xmit_v4(mblk_t *mp, ire_t *ire, ipsec_out_t *io, boolean_t flow_ctl_enabled) } ire->ire_last_used_time = lbolt; - if (flow_ctl_enabled) { - /* - * We are here from ip_wout_ire - * which has already done canput - * check and has enabled flow - * control, so skip the canputnext - * check. - */ - putnext(q, mp); - goto next_mp; - } - if (canputnext(q)) { + if (flow_ctl_enabled || canputnext(q)) { if (proc == IPP_FWD_OUT) { BUMP_MIB(&ip_mib, ipForwDatagrams); } - putnext(q, mp); + + if (mp == NULL) + goto next_mp; + putnext(q, first_mp); } else { BUMP_MIB(&ip_mib, ipOutDiscards); xmit_drop = B_TRUE; - freemsg(mp); + freemsg(first_mp); } } else { /* diff --git a/usr/src/uts/common/inet/ip/ip6.c b/usr/src/uts/common/inet/ip/ip6.c index 2e9cc4afc6..bc4176dbbd 100644 --- a/usr/src/uts/common/inet/ip/ip6.c +++ b/usr/src/uts/common/inet/ip/ip6.c @@ -42,8 +42,11 @@ #include <sys/sunddi.h> #include <sys/cmn_err.h> #include <sys/debug.h> +#include <sys/sdt.h> #include <sys/kobj.h> #include <sys/zone.h> +#include <sys/neti.h> +#include <sys/hook.h> #include <sys/kmem.h> #include <sys/systm.h> @@ -273,7 +276,7 @@ static void ip_wput_ire_v6(queue_t *, mblk_t *, ire_t *, int, int, conn_t *, int, int, int, zoneid_t); static boolean_t ip_ulp_cando_pkt2big(int); -static void ip_rput_v6(queue_t *, mblk_t *); +void ip_rput_v6(queue_t *, mblk_t *); static void ip_wput_v6(queue_t *, mblk_t *); /* @@ -6692,7 +6695,10 @@ ip_process_rthdr(queue_t *q, mblk_t *mp, ip6_t *ip6h, ip6_rthdr_t *rth, B_FALSE, B_FALSE, GLOBAL_ZONEID); return; } - ip_rput_data_v6(q, ill, mp, ip6h, flags, hada_mp, dl_mp); + if (ip_check_v6_mblk(mp, ill) == 0) { + ip6h = (ip6_t *)mp->b_rptr; + ip_rput_data_v6(q, ill, mp, ip6h, flags, hada_mp, dl_mp); + } return; hada_drop: /* IPsec kstats: bean counter? */ @@ -6703,7 +6709,7 @@ hada_drop: /* * Read side put procedure for IPv6 module. */ -static void +void ip_rput_v6(queue_t *q, mblk_t *mp) { mblk_t *first_mp; @@ -6901,17 +6907,23 @@ ip_rput_v6(queue_t *q, mblk_t *mp) mp = first_mp->b_cont; } + if (ip_check_v6_mblk(mp, ill) == -1) + return; + ip6h = (ip6_t *)mp->b_rptr; - /* check for alignment and full IPv6 header */ - if (!OK_32PTR((uchar_t *)ip6h) || - (mp->b_wptr - (uchar_t *)ip6h) < IPV6_HDR_LEN) { - if (!pullupmsg(mp, IPV6_HDR_LEN)) { - ip1dbg(("ip_rput_v6: pullupmsg failed\n")); - goto discard; - } - ip6h = (ip6_t *)mp->b_rptr; - } + DTRACE_PROBE4(ip6__physical__in__start, + ill_t *, ill, ill_t *, NULL, + ip6_t *, ip6h, mblk_t *, first_mp); + + FW_HOOKS6(ip6_physical_in_event, ipv6firewall_physical_in, + MSG_FWCOOKED_IN, ill, NULL, ip6h, first_mp, mp); + + DTRACE_PROBE1(ip6__physical__in__end, mblk_t *, first_mp); + + if (first_mp == NULL) + return; + if ((ip6h->ip6_vcf & IPV6_VERS_AND_FLOW_MASK) == IPV6_DEFAULT_VERS_AND_FLOW) { /* @@ -7137,6 +7149,62 @@ ipsec_early_ah_v6(queue_t *q, mblk_t *first_mp, boolean_t mctl_present, } /* + * Validate the IPv6 mblk for alignment. + */ +int +ip_check_v6_mblk(mblk_t *mp, ill_t *ill) +{ + int pkt_len, ip6_len; + ip6_t *ip6h = (ip6_t *)mp->b_rptr; + + /* check for alignment and full IPv6 header */ + if (!OK_32PTR((uchar_t *)ip6h) || + (mp->b_wptr - (uchar_t *)ip6h) < IPV6_HDR_LEN) { + if (!pullupmsg(mp, IPV6_HDR_LEN)) { + BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards); + ip1dbg(("ip_rput_v6: pullupmsg failed\n")); + freemsg(mp); + return (-1); + } + ip6h = (ip6_t *)mp->b_rptr; + } + + ASSERT(OK_32PTR((uchar_t *)ip6h) && + (mp->b_wptr - (uchar_t *)ip6h) >= IPV6_HDR_LEN); + + if (mp->b_cont == NULL) + pkt_len = mp->b_wptr - mp->b_rptr; + else + pkt_len = msgdsize(mp); + ip6_len = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; + + /* + * Check for bogus (too short packet) and packet which + * was padded by the link layer. + */ + if (ip6_len != pkt_len) { + ssize_t diff; + + if (ip6_len > pkt_len) { + ip1dbg(("ip_rput_data_v6: packet too short %d %d\n", + ip6_len, pkt_len)); + BUMP_MIB(ill->ill_ip6_mib, ipv6InTruncatedPkts); + freemsg(mp); + return (-1); + } + diff = (ssize_t)(pkt_len - ip6_len); + + if (!adjmsg(mp, -diff)) { + ip1dbg(("ip_rput_data_v6: adjmsg failed\n")); + BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards); + freemsg(mp); + return (-1); + } + } + return (0); +} + +/* * ip_rput_data_v6 -- received IPv6 packets in M_DATA messages show up here. * ip_rput_v6 has already verified alignment, the min length, the version, * and db_ref = 1. @@ -7157,6 +7225,7 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, ire_t *ire = NULL; queue_t *rq; ill_t *ill = inill; + ill_t *outill; ipif_t *ipif; uint8_t *whereptr; uint8_t nexthdr; @@ -7201,41 +7270,9 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, ASSERT(mp->b_datap->db_type != M_CTL); } - ASSERT(OK_32PTR((uchar_t *)ip6h) && - (mp->b_wptr - (uchar_t *)ip6h) >= IPV6_HDR_LEN); - - if (mp->b_cont == NULL) - pkt_len = mp->b_wptr - mp->b_rptr; - else - pkt_len = msgdsize(mp); + ip6h = (ip6_t *)mp->b_rptr; ip6_len = ntohs(ip6h->ip6_plen) + IPV6_HDR_LEN; - - /* - * Check for bogus (too short packet) and packet which - * was padded by the link layer. - */ - if (ip6_len != pkt_len) { - ssize_t diff; - - if (ip6_len > pkt_len) { - ip1dbg(("ip_rput_data_v6: packet too short %d %lu\n", - ip6_len, pkt_len)); - BUMP_MIB(ill->ill_ip6_mib, ipv6InTruncatedPkts); - freemsg(hada_mp); - freemsg(first_mp); - return; - } - diff = (ssize_t)(pkt_len - ip6_len); - - if (!adjmsg(mp, -diff)) { - ip1dbg(("ip_rput_data_v6: adjmsg failed\n")); - BUMP_MIB(ill->ill_ip6_mib, ipv6InDiscards); - freemsg(hada_mp); - freemsg(first_mp); - return; - } - pkt_len -= diff; - } + pkt_len = ip6_len; if (ILL_HCKSUM_CAPABLE(ill) && !mctl_present && dohwcksum) hck_flags = DB_CKSUMFLAGS(mp); @@ -7593,10 +7630,24 @@ ip_rput_data_v6(queue_t *q, ill_t *inill, mblk_t *mp, ip6_t *ip6h, forward: /* Hoplimit verified above */ ip6h->ip6_hops--; - UPDATE_IB_PKT_COUNT(ire); - ire->ire_last_used_time = lbolt; - BUMP_MIB(ill->ill_ip6_mib, ipv6OutForwDatagrams); - ip_xmit_v6(mp, ire, 0, NULL, B_FALSE, NULL); + + outill = ire->ire_ipif->ipif_ill; + + DTRACE_PROBE4(ip6__forwarding__start, + ill_t *, inill, ill_t *, outill, + ip6_t *, ip6h, mblk_t *, mp); + + FW_HOOKS6(ip6_forwarding_event, ipv6firewall_forwarding, + MSG_FWCOOKED_FORWARD, inill, outill, ip6h, mp, mp); + + DTRACE_PROBE1(ip6__forwarding__end, mblk_t *, mp); + + if (mp != NULL) { + UPDATE_IB_PKT_COUNT(ire); + ire->ire_last_used_time = lbolt; + BUMP_MIB(ill->ill_ip6_mib, ipv6OutForwDatagrams); + ip_xmit_v6(mp, ire, 0, NULL, B_FALSE, NULL); + } IRE_REFRELE(ire); return; } @@ -10544,6 +10595,20 @@ ip_wput_local_v6(queue_t *q, ill_t *ill, ip6_t *ip6h, mblk_t *first_mp, } + DTRACE_PROBE4(ip6__loopback__in__start, + ill_t *, ill, ill_t *, NULL, + ip6_t *, ip6h, mblk_t *, first_mp); + + FW_HOOKS6(ip6_loopback_in_event, ipv6firewall_loopback_in, + MSG_FWCOOKED_IN, ill, NULL, ip6h, first_mp, mp); + + DTRACE_PROBE1(ip6__loopback__in__end, mblk_t *, first_mp); + + if (first_mp == NULL) + return; + + nexthdr = ip6h->ip6_nxt; + UPDATE_OB_PKT_COUNT(ire); ire->ire_last_used_time = lbolt; @@ -10909,20 +10974,45 @@ ip_wput_ire_v6(queue_t *q, mblk_t *mp, ire_t *ire, int unspec_src, nmp = ip_copymsg(first_mp); if (nmp != NULL) { ip6_t *nip6h; + mblk_t *mp_ip6h; if (mctl_present) { nip6h = (ip6_t *) nmp->b_cont->b_rptr; + mp_ip6h = nmp->b_cont; } else { nip6h = (ip6_t *)nmp->b_rptr; + mp_ip6h = nmp; + } + + DTRACE_PROBE4( + ip6__loopback__out__start, + ill_t *, NULL, + ill_t *, ill, + ip6_t *, nip6h, + mblk_t *, nmp); + + FW_HOOKS6(ip6_loopback_out_event, + ipv6firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, ill, + nip6h, nmp, mp_ip6h); + + DTRACE_PROBE1( + ip6__loopback__out__end, + mblk_t *, nmp); + + if (nmp != NULL) { + /* + * Deliver locally and to + * every local zone, except + * the sending zone when + * IPV6_MULTICAST_LOOP is + * disabled. + */ + ip_wput_local_v6(RD(q), ill, + nip6h, nmp, + ire, fanout_flags); } - /* - * Deliver locally and to every local - * zone, except the sending zone when - * IPV6_MULTICAST_LOOP is disabled. - */ - ip_wput_local_v6(RD(q), ill, nip6h, nmp, - ire, fanout_flags); } else { BUMP_MIB(mibptr, ipv6OutDiscards); ip1dbg(("ip_wput_ire_v6: " @@ -11336,7 +11426,14 @@ ip_wput_ire_v6(queue_t *q, mblk_t *mp, ire_t *ire, int unspec_src, ASSERT(mp == first_mp); ip_xmit_v6(mp, ire, reachable, connp, caller, NULL); } else { - ip_wput_local_v6(RD(q), ill, ip6h, first_mp, ire, 0); + DTRACE_PROBE4(ip6__loopback__out__start, + ill_t *, NULL, ill_t *, ill, + ip6_t *, ip6h, mblk_t *, first_mp); + FW_HOOKS6(ip6_loopback_out_event, ipv6firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, ill, ip6h, first_mp, mp); + DTRACE_PROBE1(ip6__loopback__out__end, mblk_t *, first_mp); + if (first_mp != NULL) + ip_wput_local_v6(RD(q), ill, ip6h, first_mp, ire, 0); } } @@ -11871,6 +11968,7 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, mblk_t *mp1; nce_t *nce = ire->ire_nce; ill_t *ill; + ill_t *out_ill; uint64_t delta; ip6_t *ip6h; queue_t *stq = ire->ire_stq; @@ -11994,7 +12092,7 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, } do { - boolean_t qos_done = B_FALSE; + mblk_t *mp_ip6h; if (multirt_send) { irb_t *irb; @@ -12055,6 +12153,23 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, ill_index = ((ill_t *)stq->q_ptr)->ill_phyint->phyint_ifindex; + /* Initiate IPPF processing */ + if (IP6_OUT_IPP(flags)) { + ip_process(IPP_LOCAL_OUT, &mp, ill_index); + if (mp == NULL) { + BUMP_MIB(ill->ill_ip6_mib, + ipv6OutDiscards); + if (next_mp != NULL) + freemsg(next_mp); + if (ire != save_ire) { + ire_refrele(ire); + } + return; + } + ip6h = (ip6_t *)mp->b_rptr; + } + mp_ip6h = mp; + /* * Check for fastpath, we need to hold nce_lock to * prevent fastpath update from chaining nce_fp_mp. @@ -12066,39 +12181,6 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, uint32_t hlen; uchar_t *rptr; - /* Initiate IPPF processing */ - if (IP6_OUT_IPP(flags)) { - /* - * We have to release the nce lock since - * IPPF components use - * ill_lookup_on_ifindex(), - * which takes the ill_g_lock and the - * ill_lock locks. - */ - mutex_exit(&nce->nce_lock); - ip_process(IPP_LOCAL_OUT, &mp, - ill_index); - if (mp == NULL) { - BUMP_MIB( - ill->ill_ip6_mib, - ipv6OutDiscards); - if (next_mp != NULL) - freemsg(next_mp); - if (ire != save_ire) { - ire_refrele(ire); - } - return; - } - mutex_enter(&nce->nce_lock); - if ((mp1 = nce->nce_fp_mp) == NULL) { - /* - * Probably disappeared during - * IPQoS processing. - */ - qos_done = B_TRUE; - goto prepend_unitdata; - } - } hlen = MBLKL(mp1); rptr = mp->b_rptr - hlen; /* @@ -12107,8 +12189,8 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, */ if (rptr < mp->b_datap->db_base) { mp1 = copyb(mp1); + mutex_exit(&nce->nce_lock); if (mp1 == NULL) { - mutex_exit(&nce->nce_lock); BUMP_MIB(ill->ill_ip6_mib, ipv6OutDiscards); freemsg(mp); @@ -12131,15 +12213,15 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, * header */ bcopy(mp1->b_rptr, rptr, hlen); + mutex_exit(&nce->nce_lock); } - - mutex_exit(&nce->nce_lock); - } else { - prepend_unitdata: - mutex_exit(&nce->nce_lock); + /* + * Get the DL_UNITDATA_REQ. + */ mp1 = nce->nce_res_mp; if (mp1 == NULL) { + mutex_exit(&nce->nce_lock); ip1dbg(("ip_xmit_v6: No resolution " "block ire = %p\n", (void *)ire)); freemsg(mp); @@ -12154,6 +12236,7 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, * Prepend the DL_UNITDATA_REQ. */ mp1 = copyb(mp1); + mutex_exit(&nce->nce_lock); if (mp1 == NULL) { BUMP_MIB(ill->ill_ip6_mib, ipv6OutDiscards); @@ -12166,24 +12249,47 @@ ip_xmit_v6(mblk_t *mp, ire_t *ire, uint_t flags, conn_t *connp, return; } mp1->b_cont = mp; + + /* Get the priority marking, if any */ + mp1->b_band = mp->b_band; mp = mp1; - /* - * Initiate IPPF processing, if it is - * already done, bypass. - */ - if (!qos_done && IP6_OUT_IPP(flags)) { - ip_process(IPP_LOCAL_OUT, &mp, - ill_index); - if (mp == NULL) { - BUMP_MIB(ill->ill_ip6_mib, - ipv6OutDiscards); - if (next_mp != NULL) - freemsg(next_mp); - if (ire != save_ire) { - ire_refrele(ire); - } - return; + } + + out_ill = (ill_t *)stq->q_ptr; + + DTRACE_PROBE4(ip6__physical__out__start, + ill_t *, NULL, ill_t *, out_ill, + ip6_t *, ip6h, mblk_t *, mp); + + FW_HOOKS6(ip6_physical_out_event, + ipv6firewall_physical_out, MSG_FWCOOKED_OUT, + NULL, out_ill, ip6h, mp, mp_ip6h); + + DTRACE_PROBE1(ip6__physical__out__end, mblk_t *, mp); + + if (mp == NULL) { + if (multirt_send) { + ASSERT(ire1 != NULL); + if (ire != save_ire) { + ire_refrele(ire); } + /* + * Proceed with the next RTF_MULTIRT + * ire, also set up the send-to queue + * accordingly. + */ + ire = ire1; + ire1 = NULL; + stq = ire->ire_stq; + nce = ire->ire_nce; + ill = ire_to_ill(ire); + mp = next_mp; + next_mp = NULL; + continue; + } else { + ASSERT(next_mp == NULL); + ASSERT(ire1 == NULL); + break; } } diff --git a/usr/src/uts/common/inet/ip/ip_ftable.c b/usr/src/uts/common/inet/ip/ip_ftable.c index 145f1435b7..ae30aab09b 100644 --- a/usr/src/uts/common/inet/ip/ip_ftable.c +++ b/usr/src/uts/common/inet/ip/ip_ftable.c @@ -1293,6 +1293,7 @@ ipfil_sendpkt(const struct sockaddr *dst_addr, mblk_t *mp, uint_t ifindex, ire = ire_route_lookup(dst, 0, 0, 0, supplied_ipif, &sire, zoneid, MBLK_GETLABEL(mp), match_flags); + ipif_refrele(supplied_ipif); ill_refrele(ill); } @@ -1325,7 +1326,7 @@ ipfil_sendpkt(const struct sockaddr *dst_addr, mblk_t *mp, uint_t ifindex, goto discard; } - ASSERT(ire->ire_nce != NULL); + ASSERT(ire->ire_type != IRE_CACHE || ire->ire_nce != NULL); /* * If needed, we will create the ire cache entry for the * nexthop, resolve its link-layer address and then send diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c index 583444ce8f..7804fdcb2f 100644 --- a/usr/src/uts/common/inet/ip/ip_if.c +++ b/usr/src/uts/common/inet/ip/ip_if.c @@ -81,6 +81,7 @@ #include <inet/ip_impl.h> #include <inet/tun.h> #include <inet/sctp_ip.h> +#include <inet/ip_netinfo.h> #include <net/pfkeyv2.h> #include <inet/ipsec_info.h> @@ -4207,16 +4208,35 @@ ill_delete_interface_type(ill_if_t *interface) mi_free(interface); } +/* Defined in ip_netinfo.c */ +extern ddi_taskq_t *eventq_queue_nic; + /* * remove ill from the global list. */ static void ill_glist_delete(ill_t *ill) { + char *nicname; + size_t nicnamelen; + hook_nic_event_t *info; + if (ill == NULL) return; rw_enter(&ill_g_lock, RW_WRITER); + + if (ill->ill_name != NULL) { + nicname = kmem_alloc(ill->ill_name_length, KM_NOSLEEP); + if (nicname != NULL) { + bcopy(ill->ill_name, nicname, ill->ill_name_length); + nicnamelen = ill->ill_name_length; + } + } else { + nicname = NULL; + nicnamelen = 0; + } + /* * If the ill was never inserted into the AVL tree * we skip the if branch. @@ -4243,7 +4263,56 @@ ill_glist_delete(ill_t *ill) ill->ill_name[0] = '\0'; ill->ill_ppa = UINT_MAX; } + + /* + * Run the unplumb hook after the NIC has disappeared from being + * visible so that attempts to revalidate its existance will fail. + * + * This needs to be run inside the ill_g_lock perimeter to ensure + * that the ordering of delivered events to listeners matches the + * order of them in the kernel. + */ + if ((info = ill->ill_nic_event_info) != NULL) { + if (info->hne_event != NE_DOWN) { + ip2dbg(("ill_glist_delete: unexpected nic event %d " + "attached for %s\n", info->hne_event, + ill->ill_name)); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } else { + if (ddi_taskq_dispatch(eventq_queue_nic, + ip_ne_queue_func, (void *)info, DDI_SLEEP) + == DDI_FAILURE) { + ip2dbg(("ill_glist_delete: ddi_taskq_dispatch " + "failed\n")); + if (info->hne_data != NULL) + kmem_free(info->hne_data, + info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + } + } + + info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP); + if (info != NULL) { + info->hne_nic = ill->ill_phyint->phyint_ifindex; + info->hne_lif = 0; + info->hne_event = NE_UNPLUMB; + info->hne_data = nicname; + info->hne_datalen = nicnamelen; + info->hne_family = ill->ill_isv6 ? ipv6 : ipv4; + } else { + ip2dbg(("ill_glist_delete: could not attach UNPLUMB nic event " + "information for %s (ENOMEM)\n", ill->ill_name)); + if (nicname != NULL) + kmem_free(nicname, nicnamelen); + } + + ill->ill_nic_event_info = info; + ill_phyint_free(ill); + rw_exit(&ill_g_lock); } @@ -4996,6 +5065,88 @@ ill_lookup_on_ifindex(uint_t index, boolean_t isv6, queue_t *q, mblk_t *mp, } /* + * Return the ifindex next in sequence after the passed in ifindex. + * If there is no next ifindex for the given protocol, return 0. + */ +uint_t +ill_get_next_ifindex(uint_t index, boolean_t isv6) +{ + phyint_t *phyi; + phyint_t *phyi_initial; + uint_t ifindex; + + rw_enter(&ill_g_lock, RW_READER); + + if (index == 0) { + phyi = avl_first(&phyint_g_list.phyint_list_avl_by_index); + } else { + phyi = phyi_initial = avl_find( + &phyint_g_list.phyint_list_avl_by_index, + (void *) &index, NULL); + } + + for (; phyi != NULL; + phyi = avl_walk(&phyint_g_list.phyint_list_avl_by_index, + phyi, AVL_AFTER)) { + /* + * If we're not returning the first interface in the tree + * and we still haven't moved past the phyint_t that + * corresponds to index, avl_walk needs to be called again + */ + if (!((index != 0) && (phyi == phyi_initial))) { + if (isv6) { + if ((phyi->phyint_illv6) && + ILL_CAN_LOOKUP(phyi->phyint_illv6) && + (phyi->phyint_illv6->ill_isv6 == 1)) + break; + } else { + if ((phyi->phyint_illv4) && + ILL_CAN_LOOKUP(phyi->phyint_illv4) && + (phyi->phyint_illv4->ill_isv6 == 0)) + break; + } + } + } + + rw_exit(&ill_g_lock); + + if (phyi != NULL) + ifindex = phyi->phyint_ifindex; + else + ifindex = 0; + + return (ifindex); +} + + +/* + * Return the ifindex for the named interface. + * If there is no next ifindex for the interface, return 0. + */ +uint_t +ill_get_ifindex_by_name(char *name) +{ + phyint_t *phyi; + avl_index_t where = 0; + uint_t ifindex; + + rw_enter(&ill_g_lock, RW_READER); + + if ((phyi = avl_find(&phyint_g_list.phyint_list_avl_by_name, + name, &where)) == NULL) { + rw_exit(&ill_g_lock); + return (0); + } + + ifindex = phyi->phyint_ifindex; + + rw_exit(&ill_g_lock); + + return (ifindex); +} + + +/* * Obtain a reference to the ill. The ill_refcnt is a dynamic refcnt * that gives a running thread a reference to the ill. This reference must be * released by the thread when it is done accessing the ill and related @@ -10821,10 +10972,12 @@ ip_sioctl_addr_tail(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, in6_addr_t v6addr; ipaddr_t addr; sin6_t *sin6; + int sinlen; int err = 0; ill_t *ill = ipif->ipif_ill; boolean_t need_dl_down; boolean_t need_arp_down; + struct iocblk *iocp = (struct iocblk *)mp->b_rptr; ip1dbg(("ip_sioctl_addr_tail(%s:%u %p)\n", ill->ill_name, ipif->ipif_id, (void *)ipif)); @@ -10838,9 +10991,11 @@ ip_sioctl_addr_tail(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, if (ipif->ipif_isv6) { sin6 = (sin6_t *)sin; v6addr = sin6->sin6_addr; + sinlen = sizeof (struct sockaddr_in6); } else { addr = sin->sin_addr.s_addr; IN6_IPADDR_TO_V4MAPPED(addr, &v6addr); + sinlen = sizeof (struct sockaddr_in); } mutex_enter(&ill->ill_lock); ipif->ipif_v6lcl_addr = v6addr; @@ -10897,7 +11052,53 @@ ip_sioctl_addr_tail(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp, } ipif_set_default(ipif); - mutex_exit(&ill->ill_lock); + + /* + * When publishing an interface address change event, we only notify + * the event listeners of the new address. It is assumed that if they + * actively care about the addresses assigned that they will have + * already discovered the previous address assigned (if there was one.) + * + * Don't attach nic event message for SIOCLIFADDIF ioctl. + */ + if (iocp->ioc_cmd != SIOCLIFADDIF) { + hook_nic_event_t *info; + if ((info = ipif->ipif_ill->ill_nic_event_info) != NULL) { + ip2dbg(("ip_sioctl_addr_tail: unexpected nic event %d " + "attached for %s\n", info->hne_event, + ill->ill_name)); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + + info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP); + if (info != NULL) { + info->hne_nic = + ipif->ipif_ill->ill_phyint->phyint_ifindex; + info->hne_lif = MAP_IPIF_ID(ipif->ipif_id); + info->hne_event = NE_ADDRESS_CHANGE; + info->hne_family = ipif->ipif_isv6 ? ipv6 : ipv4; + info->hne_data = kmem_alloc(sinlen, KM_NOSLEEP); + if (info->hne_data != NULL) { + info->hne_datalen = sinlen; + bcopy(sin, info->hne_data, sinlen); + } else { + ip2dbg(("ip_sioctl_addr_tail: could not attach " + "address information for ADDRESS_CHANGE nic" + " event of %s (ENOMEM)\n", + ipif->ipif_ill->ill_name)); + kmem_free(info, sizeof (hook_nic_event_t)); + } + } else + ip2dbg(("ip_sioctl_addr_tail: could not attach " + "ADDRESS_CHANGE nic event information for %s " + "(ENOMEM)\n", ipif->ipif_ill->ill_name)); + + ipif->ipif_ill->ill_nic_event_info = info; + } + + mutex_exit(&ipif->ipif_ill->ill_lock); if (need_up) { /* @@ -17669,6 +17870,7 @@ ill_dl_down(ill_t *ill) * is brought up. */ mblk_t *mp = ill->ill_unbind_mp; + hook_nic_event_t *info; ip1dbg(("ill_dl_down(%s)\n", ill->ill_name)); @@ -17695,7 +17897,31 @@ ill_dl_down(ill_t *ill) ill_leave_multicast(ill); mutex_enter(&ill->ill_lock); + ill->ill_dl_up = 0; + + if ((info = ill->ill_nic_event_info) != NULL) { + ip2dbg(("ill_dl_down:unexpected nic event %d attached for %s\n", + info->hne_event, ill->ill_name)); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + + info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP); + if (info != NULL) { + info->hne_nic = ill->ill_phyint->phyint_ifindex; + info->hne_lif = 0; + info->hne_event = NE_DOWN; + info->hne_data = NULL; + info->hne_datalen = 0; + info->hne_family = ill->ill_isv6 ? ipv6 : ipv4; + } else + ip2dbg(("ill_dl_down: could not attach DOWN nic event " + "information for %s (ENOMEM)\n", ill->ill_name)); + + ill->ill_nic_event_info = info; + mutex_exit(&ill->ill_lock); } @@ -19746,8 +19972,8 @@ ipif_up_done(ipif_t *ipif) rw_enter(&ill_g_lock, RW_READER); mutex_enter(&ip_addr_avail_lock); /* Mark it up, and increment counters. */ - ill->ill_ipif_up_count++; ipif->ipif_flags |= IPIF_UP; + ill->ill_ipif_up_count++; err = ip_addr_availability_check(ipif); mutex_exit(&ip_addr_avail_lock); rw_exit(&ill_g_lock); @@ -22110,6 +22336,57 @@ ill_phyint_reinit(ill_t *ill) ill->ill_phyint->phyint_ifindex; } + /* + * Generate an event within the hooks framework to indicate that + * a new interface has just been added to IP. For this event to + * be generated, the network interface must, at least, have an + * ifindex assigned to it. + * + * This needs to be run inside the ill_g_lock perimeter to ensure + * that the ordering of delivered events to listeners matches the + * order of them in the kernel. + * + * This function could be called from ill_lookup_on_name. In that case + * the interface is loopback "lo", which will not generate a NIC event. + */ + if (ill->ill_name_length <= 2 || + ill->ill_name[0] != 'l' || ill->ill_name[1] != 'o') { + hook_nic_event_t *info; + if ((info = ill->ill_nic_event_info) != NULL) { + ip2dbg(("ill_phyint_reinit: unexpected nic event %d " + "attached for %s\n", info->hne_event, + ill->ill_name)); + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(info, sizeof (hook_nic_event_t)); + } + + info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP); + if (info != NULL) { + info->hne_nic = ill->ill_phyint->phyint_ifindex; + info->hne_lif = 0; + info->hne_event = NE_PLUMB; + info->hne_family = ill->ill_isv6 ? ipv6 : ipv4; + info->hne_data = kmem_alloc(ill->ill_name_length, + KM_NOSLEEP); + if (info->hne_data != NULL) { + info->hne_datalen = ill->ill_name_length; + bcopy(ill->ill_name, info->hne_data, + info->hne_datalen); + } else { + ip2dbg(("ill_phyint_reinit: could not attach " + "ill_name information for PLUMB nic event " + "of %s (ENOMEM)\n", ill->ill_name)); + kmem_free(info, sizeof (hook_nic_event_t)); + } + } else + ip2dbg(("ill_phyint_reinit: could not attach PLUMB nic " + "event information for %s (ENOMEM)\n", + ill->ill_name)); + + ill->ill_nic_event_info = info; + } + RELEASE_ILL_LOCKS(ill, ill_other); mutex_exit(&phyi->phyint_lock); } @@ -23599,3 +23876,40 @@ ill_is_probeonly(ill_t *ill) return (B_FALSE); } + +/* + * Return a pointer to an ipif_t given a combination of (ill_idx,ipif_id) + * If a pointer to an ipif_t is returned then the caller will need to do + * an ill_refrele(). + */ +ipif_t * +ipif_getby_indexes(uint_t ifindex, uint_t lifidx, boolean_t isv6) +{ + ipif_t *ipif; + ill_t *ill; + + ill = ill_lookup_on_ifindex(ifindex, isv6, NULL, NULL, NULL, NULL); + + if (ill == NULL) + return (NULL); + + mutex_enter(&ill->ill_lock); + if (ill->ill_state_flags & ILL_CONDEMNED) { + mutex_exit(&ill->ill_lock); + ill_refrele(ill); + return (NULL); + } + + for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) { + if (!IPIF_CAN_LOOKUP(ipif)) + continue; + if (lifidx == ipif->ipif_id) { + ipif_refhold_locked(ipif); + break; + } + } + + mutex_exit(&ill->ill_lock); + ill_refrele(ill); + return (ipif); +} diff --git a/usr/src/uts/common/inet/ip/ip_multi.c b/usr/src/uts/common/inet/ip/ip_multi.c index f6fe60db0d..ae2d6e8abd 100644 --- a/usr/src/uts/common/inet/ip/ip_multi.c +++ b/usr/src/uts/common/inet/ip/ip_multi.c @@ -33,6 +33,7 @@ #include <sys/strsun.h> #include <sys/ddi.h> #include <sys/cmn_err.h> +#include <sys/sdt.h> #include <sys/zone.h> #include <sys/param.h> @@ -1181,6 +1182,7 @@ ip_multicast_loopback(queue_t *q, ill_t *ill, mblk_t *mp_orig, int fanout_flags, { mblk_t *mp; mblk_t *ipsec_mp; + ipha_t *iph; if (DB_TYPE(mp_orig) == M_DATA && ((ipha_t *)mp_orig->b_rptr)->ipha_protocol == IPPROTO_UDP) { @@ -1217,8 +1219,21 @@ ip_multicast_loopback(queue_t *q, ill_t *ill, mblk_t *mp_orig, int fanout_flags, } else { ipsec_mp = mp; } - ip_wput_local(q, ill, (ipha_t *)mp->b_rptr, ipsec_mp, NULL, - fanout_flags, zoneid); + + iph = (ipha_t *)mp->b_rptr; + + DTRACE_PROBE4(ip4__loopback__out__start, + ill_t *, NULL, ill_t *, ill, + ipha_t *, iph, mblk_t *, ipsec_mp); + + FW_HOOKS(ip4_loopback_out_event, ipv4firewall_loopback_out, + MSG_FWCOOKED_OUT, NULL, ill, iph, ipsec_mp, mp); + + DTRACE_PROBE1(ip4__loopback__out__end, mblk_t *, ipsec_mp); + + if (ipsec_mp != NULL) + ip_wput_local(q, ill, iph, ipsec_mp, NULL, + fanout_flags, zoneid); } static area_t ip_aresq_template = { diff --git a/usr/src/uts/common/inet/ip/ip_ndp.c b/usr/src/uts/common/inet/ip/ip_ndp.c index de75be651d..0eccc9d360 100644 --- a/usr/src/uts/common/inet/ip/ip_ndp.c +++ b/usr/src/uts/common/inet/ip/ip_ndp.c @@ -526,9 +526,8 @@ ndp_inactive(nce_t *nce) mp = *mpp; *mpp = mp->b_next; - mp->b_next = NULL; - mp->b_prev = NULL; - freemsg(mp); + + inet_freemsg(mp); } } while (mpp++ != &nce->nce_last_mp_to_free); @@ -551,7 +550,8 @@ ndp_inactive(nce_t *nce) mutex_exit(&ill->ill_lock); } mutex_destroy(&nce->nce_lock); - freeb(nce->nce_mp); + if (nce->nce_mp != NULL) + inet_freemsg(nce->nce_mp); } /* @@ -836,26 +836,31 @@ ndp_process(nce_t *nce, uchar_t *hw_addr, uint32_t flag, boolean_t is_adv) nce->nce_qd_mp = NULL; mutex_exit(&nce->nce_lock); while (mp != NULL) { - mblk_t *nxt_mp; + mblk_t *nxt_mp, *data_mp; nxt_mp = mp->b_next; mp->b_next = NULL; - if (mp->b_prev != NULL) { + + if (mp->b_datap->db_type == M_CTL) + data_mp = mp->b_cont; + else + data_mp = mp; + if (data_mp->b_prev != NULL) { ill_t *inbound_ill; queue_t *fwdq = NULL; uint_t ifindex; - ifindex = (uint_t)(uintptr_t)mp->b_prev; + ifindex = (uint_t)(uintptr_t)data_mp->b_prev; inbound_ill = ill_lookup_on_ifindex(ifindex, B_TRUE, NULL, NULL, NULL, NULL); if (inbound_ill == NULL) { - mp->b_prev = NULL; + data_mp->b_prev = NULL; freemsg(mp); return; } else { fwdq = inbound_ill->ill_rq; } - mp->b_prev = NULL; + data_mp->b_prev = NULL; /* * Send a forwarded packet back into ip_rput_v6 * just as in ire_send_v6(). @@ -867,7 +872,9 @@ ndp_process(nce_t *nce, uchar_t *hw_addr, uint32_t flag, boolean_t is_adv) * Forwarded packets hop count will * get decremented in ip_rput_data_v6 */ - put(fwdq, mp); + if (data_mp != mp) + freeb(mp); + put(fwdq, data_mp); } else { /* * Send locally originated packets back diff --git a/usr/src/uts/common/inet/ip/ip_netinfo.c b/usr/src/uts/common/inet/ip/ip_netinfo.c new file mode 100644 index 0000000000..bad11757c5 --- /dev/null +++ b/usr/src/uts/common/inet/ip/ip_netinfo.c @@ -0,0 +1,1321 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/stream.h> +#include <sys/strsubr.h> +#include <sys/pattr.h> +#include <sys/dlpi.h> +#include <sys/atomic.h> +#include <sys/sunddi.h> +#include <sys/socket.h> +#include <sys/neti.h> + +#include <netinet/in.h> +#include <inet/common.h> +#include <inet/mib2.h> +#include <inet/ip.h> +#include <inet/ip6.h> +#include <inet/ip_if.h> +#include <inet/ip_ire.h> +#include <inet/ip_impl.h> +#include <inet/ip_ndp.h> +#include <inet/ipclassifier.h> +#include <inet/ipp_common.h> +#include <inet/ip_ftable.h> + +/* + * IPv4 netinfo entry point declarations. + */ +static int ip_getifname(phy_if_t, char *, const size_t); +static int ip_getmtu(phy_if_t, lif_if_t); +static int ip_getpmtuenabled(void); +static int ip_getlifaddr(phy_if_t, lif_if_t, size_t, + net_ifaddr_t [], void *); +static phy_if_t ip_phygetnext(phy_if_t); +static phy_if_t ip_phylookup(const char *); +static lif_if_t ip_lifgetnext(phy_if_t, lif_if_t); +static int ip_inject(inject_t, net_inject_t *); +static phy_if_t ip_routeto(struct sockaddr *); +static int ip_ispartialchecksum(mblk_t *); +static int ip_isvalidchecksum(mblk_t *); + +static int ipv6_getifname(phy_if_t, char *, const size_t); +static int ipv6_getmtu(phy_if_t, lif_if_t); +static int ipv6_getlifaddr(phy_if_t, lif_if_t, size_t, + net_ifaddr_t [], void *); +static phy_if_t ipv6_phygetnext(phy_if_t); +static phy_if_t ipv6_phylookup(const char *); +static lif_if_t ipv6_lifgetnext(phy_if_t, lif_if_t); +static int ipv6_inject(inject_t, net_inject_t *); +static phy_if_t ipv6_routeto(struct sockaddr *); +static int ipv6_isvalidchecksum(mblk_t *); + +/* Netinfo private functions */ +static int ip_getifname_impl(phy_if_t, char *, + const size_t, boolean_t); +static int ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t); +static phy_if_t ip_phylookup_impl(const char *, boolean_t); +static lif_if_t ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t); +static int ip_inject_impl(inject_t, net_inject_t *, boolean_t); +static int ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t, + void *); +static phy_if_t ip_routeto_impl(struct sockaddr *); +static int ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t, + size_t, net_ifaddr_t [], struct sockaddr *); +static void ip_ni_queue_in_func(void *); +static void ip_ni_queue_out_func(void *); +static void ip_ni_queue_func_impl(injection_t *, boolean_t); + + +static net_info_t ipv4info = { + NETINFO_VERSION, + NHF_INET, + ip_getifname, + ip_getmtu, + ip_getpmtuenabled, + ip_getlifaddr, + ip_phygetnext, + ip_phylookup, + ip_lifgetnext, + ip_inject, + ip_routeto, + ip_ispartialchecksum, + ip_isvalidchecksum +}; + + +static net_info_t ipv6info = { + NETINFO_VERSION, + NHF_INET6, + ipv6_getifname, + ipv6_getmtu, + ip_getpmtuenabled, + ipv6_getlifaddr, + ipv6_phygetnext, + ipv6_phylookup, + ipv6_lifgetnext, + ipv6_inject, + ipv6_routeto, + ip_ispartialchecksum, + ipv6_isvalidchecksum +}; + +/* + * The taskq eventq_queue_in is used to process the upside inject messages. + * The taskq eventq_queue_out is used to process the downside inject messages. + * The taskq eventq_queue_nic is used to process the nic event messages. + */ +static ddi_taskq_t *eventq_queue_in = NULL; +static ddi_taskq_t *eventq_queue_out = NULL; +ddi_taskq_t *eventq_queue_nic = NULL; + +static hook_family_t ipv4root; +static hook_family_t ipv6root; + +/* + * Hooks for firewalling + */ +hook_event_t ip4_physical_in_event; +hook_event_t ip4_physical_out_event; +hook_event_t ip4_forwarding_event; +hook_event_t ip4_loopback_in_event; +hook_event_t ip4_loopback_out_event; +hook_event_t ip4_nic_events; +hook_event_t ip6_physical_in_event; +hook_event_t ip6_physical_out_event; +hook_event_t ip6_forwarding_event; +hook_event_t ip6_loopback_in_event; +hook_event_t ip6_loopback_out_event; +hook_event_t ip6_nic_events; + +hook_event_token_t ipv4firewall_physical_in; +hook_event_token_t ipv4firewall_physical_out; +hook_event_token_t ipv4firewall_forwarding; +hook_event_token_t ipv4firewall_loopback_in; +hook_event_token_t ipv4firewall_loopback_out; +hook_event_token_t ipv4nicevents; +hook_event_token_t ipv6firewall_physical_in; +hook_event_token_t ipv6firewall_physical_out; +hook_event_token_t ipv6firewall_forwarding; +hook_event_token_t ipv6firewall_loopback_in; +hook_event_token_t ipv6firewall_loopback_out; +hook_event_token_t ipv6nicevents; + +net_data_t ipv4 = NULL; +net_data_t ipv6 = NULL; + + +/* + * Register IPv4 and IPv6 netinfo functions and initialize queues for inject. + */ +void +ip_net_init() +{ + + ipv4 = net_register(&ipv4info); + ASSERT(ipv4 != NULL); + + ipv6 = net_register(&ipv6info); + ASSERT(ipv6 != NULL); + + if (eventq_queue_out == NULL) { + eventq_queue_out = ddi_taskq_create(NULL, + "IP_INJECT_QUEUE_OUT", 1, TASKQ_DEFAULTPRI, 0); + + if (eventq_queue_out == NULL) + cmn_err(CE_NOTE, "ipv4_net_init: " + "ddi_taskq_create failed for IP_INJECT_QUEUE_OUT"); + } + + if (eventq_queue_in == NULL) { + eventq_queue_in = ddi_taskq_create(NULL, + "IP_INJECT_QUEUE_IN", 1, TASKQ_DEFAULTPRI, 0); + + if (eventq_queue_in == NULL) + cmn_err(CE_NOTE, "ipv4_net_init: " + "ddi_taskq_create failed for IP_INJECT_QUEUE_IN"); + } + + if (eventq_queue_nic == NULL) { + eventq_queue_nic = ddi_taskq_create(NULL, + "IP_NIC_EVENT_QUEUE", 1, TASKQ_DEFAULTPRI, 0); + + if (eventq_queue_nic == NULL) + cmn_err(CE_NOTE, "ipv4_net_init: " + "ddi_taskq_create failed for IP_NIC_EVENT_QUEUE"); + } +} + + +/* + * Unregister IPv4 and IPv6 functions and inject queues + */ +void +ip_net_destroy() +{ + + if (eventq_queue_nic != NULL) { + ddi_taskq_destroy(eventq_queue_nic); + eventq_queue_nic = NULL; + } + + if (eventq_queue_in != NULL) { + ddi_taskq_destroy(eventq_queue_in); + eventq_queue_in = NULL; + } + + if (eventq_queue_out != NULL) { + ddi_taskq_destroy(eventq_queue_out); + eventq_queue_out = NULL; + } + + if (ipv4 != NULL) { + if (net_unregister(ipv4) == 0) + ipv4 = NULL; + } + + if (ipv6 != NULL) { + if (net_unregister(ipv6) == 0) + ipv6 = NULL; + } +} + + +/* + * Initialize IPv4 hooks family the event + */ +void +ipv4_hook_init() +{ + + HOOK_FAMILY_INIT(&ipv4root, Hn_IPV4); + if (net_register_family(ipv4, &ipv4root) != 0) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_family failed for ipv4"); + } + + HOOK_EVENT_INIT(&ip4_physical_in_event, NH_PHYSICAL_IN); + ipv4firewall_physical_in = net_register_event(ipv4, + &ip4_physical_in_event); + if (ipv4firewall_physical_in == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/physical_in"); + } + + HOOK_EVENT_INIT(&ip4_physical_out_event, NH_PHYSICAL_OUT); + ipv4firewall_physical_out = net_register_event(ipv4, + &ip4_physical_out_event); + if (ipv4firewall_physical_out == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/physical_out"); + } + + HOOK_EVENT_INIT(&ip4_forwarding_event, NH_FORWARDING); + ipv4firewall_forwarding = net_register_event(ipv4, + &ip4_forwarding_event); + if (ipv4firewall_forwarding == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/forwarding"); + } + + HOOK_EVENT_INIT(&ip4_loopback_in_event, NH_LOOPBACK_IN); + ipv4firewall_loopback_in = net_register_event(ipv4, + &ip4_loopback_in_event); + if (ipv4firewall_loopback_in == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/loopback_in"); + } + + HOOK_EVENT_INIT(&ip4_loopback_out_event, NH_LOOPBACK_OUT); + ipv4firewall_loopback_out = net_register_event(ipv4, + &ip4_loopback_out_event); + if (ipv4firewall_loopback_out == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/loopback_out"); + } + + HOOK_EVENT_INIT(&ip4_nic_events, NH_NIC_EVENTS); + ip4_nic_events.he_flags = HOOK_RDONLY; + ipv4nicevents = net_register_event(ipv4, &ip4_nic_events); + if (ipv4nicevents == NULL) { + cmn_err(CE_NOTE, "ipv4_hook_init: " + "net_register_event failed for ipv4/nic_events"); + } +} + + +void +ipv4_hook_destroy() +{ + if (ipv4firewall_forwarding != NULL) { + if (net_unregister_event(ipv4, &ip4_forwarding_event) == 0) + ipv4firewall_forwarding = NULL; + } + + if (ipv4firewall_physical_in != NULL) { + if (net_unregister_event(ipv4, &ip4_physical_in_event) == 0) + ipv4firewall_physical_in = NULL; + } + + if (ipv4firewall_physical_out != NULL) { + if (net_unregister_event(ipv4, &ip4_physical_out_event) == 0) + ipv4firewall_physical_out = NULL; + } + + if (ipv4firewall_loopback_in != NULL) { + if (net_unregister_event(ipv4, &ip4_loopback_in_event) == 0) + ipv4firewall_loopback_in = NULL; + } + + if (ipv4firewall_loopback_out != NULL) { + if (net_unregister_event(ipv4, &ip4_loopback_out_event) == 0) + ipv4firewall_loopback_out = NULL; + } + + if (ipv4nicevents != NULL) { + if (net_unregister_event(ipv4, &ip4_nic_events) == 0) + ipv4nicevents = NULL; + } + + (void) net_unregister_family(ipv4, &ipv4root); +} + + +/* + * Initialize IPv6 hooks family and event + */ +void +ipv6_hook_init() +{ + + HOOK_FAMILY_INIT(&ipv6root, Hn_IPV6); + if (net_register_family(ipv6, &ipv6root) != 0) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_family failed for ipv6"); + } + + HOOK_EVENT_INIT(&ip6_physical_in_event, NH_PHYSICAL_IN); + ipv6firewall_physical_in = net_register_event(ipv6, + &ip6_physical_in_event); + if (ipv6firewall_physical_in == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/physical_in"); + } + + HOOK_EVENT_INIT(&ip6_physical_out_event, NH_PHYSICAL_OUT); + ipv6firewall_physical_out = net_register_event(ipv6, + &ip6_physical_out_event); + if (ipv6firewall_physical_out == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/physical_out"); + } + + HOOK_EVENT_INIT(&ip6_forwarding_event, NH_FORWARDING); + ipv6firewall_forwarding = net_register_event(ipv6, + &ip6_forwarding_event); + if (ipv6firewall_forwarding == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/forwarding"); + } + + HOOK_EVENT_INIT(&ip6_loopback_in_event, NH_LOOPBACK_IN); + ipv6firewall_loopback_in = net_register_event(ipv6, + &ip6_loopback_in_event); + if (ipv6firewall_loopback_in == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/loopback_in"); + } + + HOOK_EVENT_INIT(&ip6_loopback_out_event, NH_LOOPBACK_OUT); + ipv6firewall_loopback_out = net_register_event(ipv6, + &ip6_loopback_out_event); + if (ipv6firewall_loopback_out == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/loopback_out"); + } + + HOOK_EVENT_INIT(&ip6_nic_events, NH_NIC_EVENTS); + ip6_nic_events.he_flags = HOOK_RDONLY; + ipv6nicevents = net_register_event(ipv6, &ip6_nic_events); + if (ipv6nicevents == NULL) { + cmn_err(CE_NOTE, "ipv6_hook_init: " + "net_register_event failed for ipv6/nic_events"); + } +} + + +void +ipv6_hook_destroy() +{ + if (ipv6firewall_forwarding != NULL) { + if (net_unregister_event(ipv6, &ip6_forwarding_event) == 0) + ipv6firewall_forwarding = NULL; + } + + if (ipv6firewall_physical_in != NULL) { + if (net_unregister_event(ipv6, &ip6_physical_in_event) == 0) + ipv6firewall_physical_in = NULL; + } + + if (ipv6firewall_physical_out != NULL) { + if (net_unregister_event(ipv6, &ip6_physical_out_event) == 0) + ipv6firewall_physical_out = NULL; + } + + if (ipv6firewall_loopback_in != NULL) { + if (net_unregister_event(ipv6, &ip6_loopback_in_event) == 0) + ipv6firewall_loopback_in = NULL; + } + + if (ipv6firewall_loopback_out != NULL) { + if (net_unregister_event(ipv6, &ip6_loopback_out_event) == 0) + ipv6firewall_loopback_out = NULL; + } + + if (ipv6nicevents != NULL) { + if (net_unregister_event(ipv6, &ip6_nic_events) == 0) + ipv6nicevents = NULL; + } + + (void) net_unregister_family(ipv6, &ipv6root); +} + + +/* + * Determine the name of an IPv4 interface + */ +static int +ip_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen) +{ + + return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE)); +} + + +/* + * Determine the name of an IPv6 interface + */ +static int +ipv6_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen) +{ + + return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE)); +} + + +/* + * Shared implementation to determine the name of a given network interface + */ +/* ARGSUSED */ +static int +ip_getifname_impl(phy_if_t phy_ifdata, + char *buffer, const size_t buflen, boolean_t isv6) +{ + ill_t *ill; + + ASSERT(buffer != NULL); + + ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, NULL, NULL, + NULL, NULL); + if (ill == NULL) + return (1); + + if (ill->ill_name != NULL) { + (void) strlcpy(buffer, ill->ill_name, buflen); + ill_refrele(ill); + return (0); + } else { + ill_refrele(ill); + return (1); + } + +} + + +/* + * Determine the MTU of an IPv4 network interface + */ +static int +ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE)); +} + + +/* + * Determine the MTU of an IPv6 network interface + */ +static int +ipv6_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE)); +} + + +/* + * Shared implementation to determine the MTU of a network interface + */ +/* ARGSUSED */ +static int +ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6) +{ + lif_if_t ipifid; + ipif_t *ipif; + int mtu; + + ipifid = UNMAP_IPIF_ID(ifdata); + + ipif = ipif_getby_indexes((uint_t)phy_ifdata, (uint_t)ipifid, isv6); + if (ipif == NULL) + return (0); + + mtu = ipif->ipif_mtu; + ipif_refrele(ipif); + + if (mtu == 0) { + ill_t *ill; + + if ((ill = ill_lookup_on_ifindex((uint_t)phy_ifdata, isv6, + NULL, NULL, NULL, NULL)) == NULL) { + return (0); + } + mtu = ill->ill_max_frag; + ill_refrele(ill); + } + + return (mtu); +} + + +/* + * Determine if path MTU discovery is enabled for IP + */ +static int +ip_getpmtuenabled(void) +{ + + return (ip_path_mtu_discovery); +} + + +/* + * Get next interface from the current list of IPv4 physical network interfaces + */ +static phy_if_t +ip_phygetnext(phy_if_t phy_ifdata) +{ + + return (ill_get_next_ifindex(phy_ifdata, B_FALSE)); +} + + +/* + * Get next interface from the current list of IPv6 physical network interfaces + */ +static phy_if_t +ipv6_phygetnext(phy_if_t phy_ifdata) +{ + + return (ill_get_next_ifindex(phy_ifdata, B_TRUE)); +} + + +/* + * Determine if a network interface name exists for IPv4 + */ +static phy_if_t +ip_phylookup(const char *name) +{ + + return (ip_phylookup_impl(name, B_FALSE)); + +} + + +/* + * Determine if a network interface name exists for IPv6 + */ +static phy_if_t +ipv6_phylookup(const char *name) +{ + + return (ip_phylookup_impl(name, B_TRUE)); +} + + +/* + * Implement looking up an ill_t based on the name supplied and matching + * it up with either IPv4 or IPv6. ill_get_ifindex_by_name() is not used + * because it does not match on the address family in addition to the name. + */ +static phy_if_t +ip_phylookup_impl(const char *name, boolean_t isv6) +{ + phy_if_t phy; + ill_t *ill; + + ill = ill_lookup_on_name((char *)name, B_FALSE, isv6, NULL, NULL, + NULL, NULL, NULL); + + if (ill == NULL) + return (0); + + phy = ill->ill_phyint->phyint_ifindex; + + ill_refrele(ill); + + return (phy); +} + + +/* + * Get next interface from the current list of IPv4 logical network interfaces + */ +static lif_if_t +ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE)); +} + + +/* + * Get next interface from the current list of IPv6 logical network interfaces + */ +static lif_if_t +ipv6_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE)); +} + + +/* + * Shared implementation to get next interface from the current list of + * logical network interfaces + */ +static lif_if_t +ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6) +{ + lif_if_t newidx, oldidx; + boolean_t nextok; + ipif_t *ipif; + ill_t *ill; + + ill = ill_lookup_on_ifindex(phy_ifdata, isv6, NULL, NULL, NULL, NULL); + if (ill == NULL) + return (0); + + if (ifdata != 0) { + oldidx = UNMAP_IPIF_ID(ifdata); + nextok = B_FALSE; + } else { + oldidx = 0; + nextok = B_TRUE; + } + + mutex_enter(&ill->ill_lock); + if (ill->ill_state_flags & ILL_CONDEMNED) { + mutex_exit(&ill->ill_lock); + ill_refrele(ill); + return (0); + } + + /* + * It's safe to iterate the ill_ipif list when holding an ill_lock. + * And it's also safe to access ipif_id without ipif refhold. + * See ipif_get_id(). + */ + for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) { + if (!IPIF_CAN_LOOKUP(ipif)) + continue; + if (nextok) { + ipif_refhold_locked(ipif); + break; + } else if (oldidx == ipif->ipif_id) { + nextok = B_TRUE; + } + } + + mutex_exit(&ill->ill_lock); + ill_refrele(ill); + + if (ipif == NULL) + return (0); + + newidx = ipif->ipif_id; + ipif_refrele(ipif); + + return (MAP_IPIF_ID(newidx)); +} + + +/* + * Inject an IPv4 packet to or from an interface + */ +static int +ip_inject(inject_t style, net_inject_t *packet) +{ + + return (ip_inject_impl(style, packet, B_FALSE)); +} + + +/* + * Inject an IPv6 packet to or from an interface + */ +static int +ipv6_inject(inject_t style, net_inject_t *packet) +{ + + return (ip_inject_impl(style, packet, B_TRUE)); +} + + +/* + * Shared implementation to inject a packet to or from an interface + * Return value: + * 0: successful + * -1: memory allocation failed + * 1: other errors + */ +static int +ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6) +{ + struct sockaddr_in6 *sin6; + ddi_taskq_t *tq = NULL; + void (* func)(void*); + injection_t *inject; + ip6_t *ip6h; + ire_t *ire; + mblk_t *mp; + + ASSERT(packet != NULL); + ASSERT(packet->ni_packet != NULL); + ASSERT(packet->ni_packet->b_datap->db_type == M_DATA); + + switch (style) { + case NI_QUEUE_IN: + inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); + if (inject == NULL) + return (-1); + inject->inj_data = *packet; + inject->inj_isv6 = isv6; + /* + * deliver up into the kernel, immitating its reception by a + * network interface, add to list and schedule timeout + */ + func = ip_ni_queue_in_func; + tq = eventq_queue_in; + break; + + case NI_QUEUE_OUT: + inject = kmem_alloc(sizeof (*inject), KM_NOSLEEP); + if (inject == NULL) + return (-1); + inject->inj_data = *packet; + inject->inj_isv6 = isv6; + /* + * deliver out of the kernel, as if it were being sent via a + * raw socket so that IPFilter will see it again, add to list + * and schedule timeout + */ + func = ip_ni_queue_out_func; + tq = eventq_queue_out; + break; + + case NI_DIRECT_OUT: + /* + * Note: + * For IPv4, the code path below will be greatly simplified + * with the delivery of surya - it will become a single + * function call to X. A follow on project is aimed to + * provide similar functionality for IPv6. + */ + mp = packet->ni_packet; + + if (!isv6) { + struct sockaddr *sock; + + sock = (struct sockaddr *)&packet->ni_addr; + /* + * ipfil_sendpkt was provided by surya to ease the + * problems associated with sending out a packet. + * Currently this function only supports IPv4. + */ + switch (ipfil_sendpkt(sock, mp, packet->ni_physical, + ALL_ZONES)) { + case 0 : + case EINPROGRESS: + return (0); + case ECOMM : + case ENONET : + return (1); + default : + return (1); + } + /* NOTREACHED */ + + } + + ip6h = (ip6_t *)mp->b_rptr; + sin6 = (struct sockaddr_in6 *)&packet->ni_addr; + ASSERT(sin6->sin6_family == AF_INET6); + + ire = ire_route_lookup_v6(&sin6->sin6_addr, 0, 0, 0, + NULL, NULL, ALL_ZONES, NULL, + MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); + + if (ire == NULL) { + ip2dbg(("ip_inject: ire_cache_lookup failed\n")); + freemsg(mp); + return (1); + } + + if (ire->ire_stq == NULL) { + /* Send to loopback destination. */ + if (ire->ire_rfq == NULL) { + ip2dbg(("ip_inject: bad nexthop\n")); + ire_refrele(ire); + freemsg(mp); + return (1); + } + ip_wput_local_v6(ire->ire_rfq, + ire->ire_ipif->ipif_ill, ip6h, mp, ire, 0); + ire_refrele(ire); + return (0); + } + + mp->b_queue = ire->ire_stq; + + if (ire->ire_nce == NULL || + ire->ire_nce->nce_fp_mp == NULL && + ire->ire_nce->nce_res_mp == NULL) { + ip_newroute_v6(ire->ire_stq, mp, + &sin6->sin6_addr, NULL, NULL, ALL_ZONES); + + ire_refrele(ire); + return (0); + } else { + /* prepend L2 header for IPv6 packets. */ + mblk_t *llmp; + + /* + * Lock IREs, see 6420438 + */ + mutex_enter(&ire->ire_lock); + llmp = ire->ire_nce->nce_fp_mp ? + ire->ire_nce->nce_fp_mp : + ire->ire_nce->nce_res_mp; + + if ((mp = dupb(llmp)) == NULL && + (mp = copyb(llmp)) == NULL) { + ip2dbg(("ip_inject: llhdr failed\n")); + mutex_exit(&ire->ire_lock); + ire_refrele(ire); + freemsg(mp); + return (1); + } + mutex_exit(&ire->ire_lock); + linkb(mp, packet->ni_packet); + } + + mp->b_queue = ire->ire_stq; + + break; + default: + freemsg(packet->ni_packet); + return (1); + } + + if (tq) { + if (ddi_taskq_dispatch(tq, func, (void *)inject, + DDI_SLEEP) == DDI_FAILURE) { + ip2dbg(("ip_inject: ddi_taskq_dispatch failed\n")); + freemsg(packet->ni_packet); + return (1); + } + } else { + putnext(ire->ire_stq, mp); + ire_refrele(ire); + } + + return (0); +} + + +/* + * Find the interface used for traffic to a given IPv4 address + */ +static phy_if_t +ip_routeto(struct sockaddr *address) +{ + + ASSERT(address != NULL); + + if (address->sa_family != AF_INET) + return (0); + return (ip_routeto_impl(address)); +} + + +/* + * Find the interface used for traffic to a given IPv6 address + */ +static phy_if_t +ipv6_routeto(struct sockaddr *address) +{ + + ASSERT(address != NULL); + + if (address->sa_family != AF_INET6) + return (0); + return (ip_routeto_impl(address)); +} + + +/* + * Find the interface used for traffic to an address + */ +static phy_if_t +ip_routeto_impl(struct sockaddr *address) +{ + ire_t *ire; + ill_t *ill; + phy_if_t phy_if; + + if (address->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; + ire = ire_route_lookup_v6(&sin6->sin6_addr, NULL, + 0, 0, NULL, NULL, ALL_ZONES, NULL, + MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); + } else { + struct sockaddr_in *sin = (struct sockaddr_in *)address; + ire = ire_route_lookup(sin->sin_addr.s_addr, 0, + 0, 0, NULL, NULL, ALL_ZONES, NULL, + MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); + } + + if (ire == NULL) + return (0); + + ill = ire_to_ill(ire); + if (ill == NULL) + return (0); + + ASSERT(ill != NULL); + phy_if = (phy_if_t)ill->ill_phyint->phyint_ifindex; + ire_refrele(ire); + + return (phy_if); +} + + +/* + * Determine if checksumming is being used for the given packet. + * + * Return value: + * NET_HCK_NONE: full checksum recalculation is required + * NET_HCK_L3_FULL: full layer 3 checksum + * NET_HCK_L4_FULL: full layer 4 checksum + * NET_HCK_L4_PART: partial layer 4 checksum + */ +static int +ip_ispartialchecksum(mblk_t *mp) +{ + int ret = 0; + + ASSERT(mp != NULL); + + if ((DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) != 0) { + ret |= (int)NET_HCK_L4_FULL; + if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0) + ret |= (int)NET_HCK_L3_FULL; + } + if ((DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM) != 0) { + ret |= (int)NET_HCK_L4_PART; + if ((DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) != 0) + ret |= (int)NET_HCK_L3_FULL; + } + + return (ret); +} + + +/* + * Return true or false, indicating whether the network and transport + * headers are correct. Use the capabilities flags and flags set in the + * dblk_t to determine whether or not the checksum is valid. + * + * Return: + * 0: the checksum was incorrect + * 1: the original checksum was correct + */ +static int +ip_isvalidchecksum(mblk_t *mp) +{ + unsigned char *wptr; + ipha_t *ipha = (ipha_t *)mp->b_rptr; + int hlen; + int ret; + + ASSERT(mp != NULL); + + if (dohwcksum && + DB_CKSUM16(mp) != 0xFFFF && + (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) && + (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM_OK) && + (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM)) + return (1); + + hlen = (ipha->ipha_version_and_hdr_length & 0x0F) << 2; + + /* + * Check that the mblk being passed in has enough data in it + * before blindly checking ip_cksum. + */ + if (msgdsize(mp) < hlen) + return (0); + + if (mp->b_wptr < mp->b_rptr + hlen) { + if (pullupmsg(mp, hlen) == 0) + return (0); + wptr = mp->b_wptr; + } else { + wptr = mp->b_wptr; + mp->b_wptr = mp->b_rptr + hlen; + } + + if (ipha->ipha_hdr_checksum == ip_cksum(mp, 0, ipha->ipha_hdr_checksum)) + ret = 1; + else + ret = 0; + mp->b_wptr = wptr; + + return (ret); +} + + +/* + * Unsupported with IPv6 + */ +/*ARGSUSED*/ +static int +ipv6_isvalidchecksum(mblk_t *mp) +{ + + return (-1); +} + +/* + * Determine the network addresses for an IPv4 interface + */ +static int +ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, + net_ifaddr_t type[], void *storage) +{ + + return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata, + nelem, type, storage)); +} + + +/* + * Determine the network addresses for an IPv6 interface + */ +static int +ipv6_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem, + net_ifaddr_t type[], void *storage) +{ + + return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata, + nelem, type, storage)); +} + + +/* + * Shared implementation to determine the network addresses for an interface + */ +/* ARGSUSED */ +static int +ip_getlifaddr_impl(sa_family_t family, phy_if_t phy_ifdata, + lif_if_t ifdata, size_t nelem, net_ifaddr_t type[], + struct sockaddr *storage) +{ + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + lif_if_t ipifid; + ipif_t *ipif; + int i; + + ASSERT(type != NULL); + ASSERT(storage != NULL); + + ipifid = UNMAP_IPIF_ID(ifdata); + + if (family == AF_INET) { + if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata, + (uint_t)ipifid, B_FALSE)) == NULL) + return (1); + + sin = (struct sockaddr_in *)storage; + for (i = 0; i < nelem; i++, sin++) { + if (ip_getifaddr_type(AF_INET, ipif, type[i], + &sin->sin_addr) < 0) { + ip2dbg(("ip_getlifaddr_impl failed type %d\n", + type[i])); + ipif_refrele(ipif); + return (1); + } + } + } else { + if ((ipif = ipif_getby_indexes((uint_t)phy_ifdata, + (uint_t)ipifid, B_TRUE)) == NULL) + return (1); + + sin6 = (struct sockaddr_in6 *)storage; + for (i = 0; i < nelem; i++, sin6++) { + if (ip_getifaddr_type(AF_INET6, ipif, type[i], + &sin6->sin6_addr) < 0) { + ip2dbg(("ip_getlifaddr_impl failed type %d\n", + type[i])); + ipif_refrele(ipif); + return (1); + } + } + } + ipif_refrele(ipif); + return (0); +} + +/* + * ip_getlifaddr private function + */ +static int +ip_getifaddr_type(sa_family_t family, ipif_t *ill_ipif, + lif_if_t type, void *storage) +{ + void *src_addr; + int mem_size; + + ASSERT(ill_ipif != NULL); + ASSERT(storage != NULL); + + if (family == AF_INET) { + mem_size = sizeof (struct in_addr); + + switch (type) { + case NA_ADDRESS: + src_addr = &(ill_ipif->ipif_lcl_addr); + break; + case NA_PEER: + src_addr = &(ill_ipif->ipif_pp_dst_addr); + break; + case NA_BROADCAST: + src_addr = &(ill_ipif->ipif_brd_addr); + break; + case NA_NETMASK: + src_addr = &(ill_ipif->ipif_net_mask); + break; + default: + return (-1); + /*NOTREACHED*/ + } + } else { + mem_size = sizeof (struct in6_addr); + + switch (type) { + case NA_ADDRESS: + src_addr = &(ill_ipif->ipif_v6lcl_addr); + break; + case NA_PEER: + src_addr = &(ill_ipif->ipif_v6pp_dst_addr); + break; + case NA_BROADCAST: + src_addr = &(ill_ipif->ipif_v6brd_addr); + break; + case NA_NETMASK: + src_addr = &(ill_ipif->ipif_v6net_mask); + break; + default: + return (-1); + /*NOTREACHED*/ + } + } + + (void) memcpy(storage, src_addr, mem_size); + return (1); +} + + +/* + * Deliver packet up into the kernel, immitating its reception by a + * network interface. + */ +static void +ip_ni_queue_in_func(void *inject) +{ + + ip_ni_queue_func_impl(inject, B_FALSE); +} + + +/* + * Deliver out of the kernel, as if it were being sent via a + * raw socket so that IPFilter will see it again. + */ +static void +ip_ni_queue_out_func(void *inject) +{ + + ip_ni_queue_func_impl(inject, B_TRUE); +} + + +/* + * Shared implementation for inject via ip_output and ip_input + */ +static void +ip_ni_queue_func_impl(injection_t *inject, boolean_t out) +{ + net_inject_t *packet; + conn_t *conn; + ill_t *ill; + + ASSERT(inject != NULL); + packet = &inject->inj_data; + ASSERT(packet->ni_packet != NULL); + + if ((ill = ill_lookup_on_ifindex((uint_t)packet->ni_physical, + B_FALSE, NULL, NULL, NULL, NULL)) == NULL) { + kmem_free(inject, sizeof (*inject)); + return; + } + + if (out == 0) { + if (inject->inj_isv6) { + ip_rput_v6(ill->ill_rq, packet->ni_packet); + } else { + ip_input(ill, NULL, packet->ni_packet, 0); + } + kmem_free(inject, sizeof (*inject)); + ill_refrele(ill); + return; + } + + /* + * Even though ipcl_conn_create requests that it be passed + * a different value for "TCP", in this case there may not + * be a TCP connection backing the packet and more than + * likely, non-TCP packets will go here too. + */ + conn = ipcl_conn_create(IPCL_IPCCONN, KM_NOSLEEP); + if (conn != NULL) { + if (inject->inj_isv6) { + conn->conn_flags |= IPCL_ISV6; + conn->conn_af_isv6 = B_TRUE; + conn->conn_src_preferences = IPV6_PREFER_SRC_DEFAULT; + conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; + ip_output_v6(conn, packet->ni_packet, ill->ill_wq, + IP_WPUT); + } else { + conn->conn_af_isv6 = B_FALSE; + conn->conn_pkt_isv6 = B_FALSE; + conn->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; + ip_output(conn, packet->ni_packet, ill->ill_wq, + IP_WPUT); + } + + CONN_DEC_REF(conn); + } + + kmem_free(inject, sizeof (*inject)); + ill_refrele(ill); +} + +/* + * taskq function for nic events. + */ +void +ip_ne_queue_func(void *arg) +{ + + hook_event_int_t *hr; + hook_nic_event_t *info = (hook_nic_event_t *)arg; + + hr = (info->hne_family == ipv6) ? ipv6nicevents : ipv4nicevents; + (void) hook_run(hr, (hook_data_t)info); + + if (info->hne_data != NULL) + kmem_free(info->hne_data, info->hne_datalen); + kmem_free(arg, sizeof (hook_nic_event_t)); +} diff --git a/usr/src/uts/common/inet/ip6.h b/usr/src/uts/common/inet/ip6.h index eb80877b21..966983bb20 100644 --- a/usr/src/uts/common/inet/ip6.h +++ b/usr/src/uts/common/inet/ip6.h @@ -366,6 +366,7 @@ extern int ip_hdr_complete_v6(ip6_t *, zoneid_t); extern boolean_t ip_hdr_length_nexthdr_v6(mblk_t *, ip6_t *, uint16_t *, uint8_t **); extern int ip_hdr_length_v6(mblk_t *, ip6_t *); +extern int ip_check_v6_mblk(mblk_t *, ill_t *); extern uint32_t ip_massage_options_v6(ip6_t *, ip6_rthdr_t *); extern void ip_wput_frag_v6(mblk_t *, ire_t *, uint_t, conn_t *, int, int); extern void ip_wput_ipsec_out_v6(queue_t *, mblk_t *, ip6_t *, ill_t *, @@ -378,6 +379,7 @@ extern void ip_wput_md_v6(queue_t *, mblk_t *, conn_t *); extern void ip_output_v6(void *, mblk_t *, void *, int); extern void ip_xmit_v6(mblk_t *, ire_t *, uint_t, conn_t *, int, struct ipsec_out_s *); +extern void ip_rput_v6(queue_t *, mblk_t *); extern void ip_rput_data_v6(queue_t *, ill_t *, mblk_t *, ip6_t *, uint_t, mblk_t *, mblk_t *); extern void mld_input(queue_t *, mblk_t *, ill_t *); diff --git a/usr/src/uts/common/inet/ip_if.h b/usr/src/uts/common/inet/ip_if.h index 96841cca5d..e32ba29a8e 100644 --- a/usr/src/uts/common/inet/ip_if.h +++ b/usr/src/uts/common/inet/ip_if.h @@ -164,6 +164,9 @@ extern ill_t *ill_lookup_on_ifindex(uint_t, boolean_t, queue_t *, mblk_t *, ipsq_func_t, int *); extern ill_t *ill_lookup_on_name(char *, boolean_t, boolean_t, queue_t *, mblk_t *, ipsq_func_t, int *, boolean_t *); +extern uint_t ill_get_next_ifindex(uint_t, boolean_t); +extern uint_t ill_get_ifindex_by_name(char *); +extern ill_t *ill_get_first(boolean_t isv6); extern void ill_ipif_cache_delete(ire_t *, char *); extern void ill_delete(ill_t *); extern void ill_delete_tail(ill_t *); @@ -205,6 +208,7 @@ extern int ill_up_ipifs(ill_t *, queue_t *, mblk_t *); extern boolean_t ill_is_probeonly(ill_t *); extern char *ipif_get_name(const ipif_t *, char *, int); +extern ipif_t *ipif_getby_indexes(uint_t, uint_t, boolean_t); extern void ipif_init(void); extern ipif_t *ipif_lookup_addr(ipaddr_t, ill_t *, zoneid_t, queue_t *, mblk_t *, ipsq_func_t, int *); diff --git a/usr/src/uts/common/inet/ip_impl.h b/usr/src/uts/common/inet/ip_impl.h index f86839d5b9..57be18aed4 100644 --- a/usr/src/uts/common/inet/ip_impl.h +++ b/usr/src/uts/common/inet/ip_impl.h @@ -41,6 +41,8 @@ extern "C" { #ifdef _KERNEL +#include <sys/sdt.h> + #define IP_MOD_ID 5701 #ifdef _BIG_ENDIAN @@ -480,13 +482,20 @@ typedef struct ip_pdescinfo_s PDESCINFO_STRUCT(2) ip_pdescinfo_t; * Macro that hands off one or more messages directly to DLD * when the interface is marked with ILL_CAPAB_POLL. */ -#define IP_DLS_ILL_TX(ill, mp) { \ - ill_dls_capab_t *ill_dls = ill->ill_dls_capab; \ +#define IP_DLS_ILL_TX(ill, ipha, mp) { \ + ill_dls_capab_t *ill_dls = ill->ill_dls_capab; \ ASSERT(ILL_DLS_CAPABLE(ill)); \ ASSERT(ill_dls != NULL); \ ASSERT(ill_dls->ill_tx != NULL); \ - ASSERT(ill_dls->ill_tx_handle != NULL); \ - ill_dls->ill_tx(ill_dls->ill_tx_handle, mp); \ + ASSERT(ill_dls->ill_tx_handle != NULL); \ + DTRACE_PROBE4(ip4__physical__out__start, \ + ill_t *, NULL, ill_t *, ill, \ + ipha_t *, ipha, mblk_t *, mp); \ + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, \ + MSG_FWCOOKED_OUT, NULL, ill, ipha, mp, mp); \ + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); \ + if (mp != NULL) \ + ill_dls->ill_tx(ill_dls->ill_tx_handle, mp); \ } extern int ip_wput_frag_mdt_min; diff --git a/usr/src/uts/common/inet/ip_ire.h b/usr/src/uts/common/inet/ip_ire.h index b52b9492f4..b32847944e 100644 --- a/usr/src/uts/common/inet/ip_ire.h +++ b/usr/src/uts/common/inet/ip_ire.h @@ -380,9 +380,6 @@ extern void ire_fastpath_list_dispatch(ill_t *, boolean_t (*)(ire_t *, void *), void *); extern void ire_fastpath_list_delete(ill_t *, ire_t *); -extern mblk_t *ip_nexthop_route(const struct sockaddr *, char *); -extern mblk_t *ip_nexthop(const struct sockaddr *, const char *); - extern ire_t *ire_get_next_bcast_ire(ire_t *, ire_t *); extern ire_t *ire_get_next_default_ire(ire_t *, ire_t *); diff --git a/usr/src/uts/common/inet/ip_netinfo.h b/usr/src/uts/common/inet/ip_netinfo.h new file mode 100644 index 0000000000..8523f8afea --- /dev/null +++ b/usr/src/uts/common/inet/ip_netinfo.h @@ -0,0 +1,52 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _INET_IP_NETINFO_H +#define _INET_IP_NETINFO_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _KERNEL + +extern void ip_net_init(); +extern void ip_net_destroy(); +extern void ipv4_hook_init(); +extern void ipv6_hook_init(); +extern void ipv4_hook_destroy(); +extern void ipv6_hook_destroy(); +extern void ip_ne_queue_func(void *); + +#endif /* _KERNEL */ + +#ifdef __cplusplus +} +#endif + +#endif /* _INET_IP_NETINFO_H */ diff --git a/usr/src/uts/common/inet/ipf/fil.c b/usr/src/uts/common/inet/ipf/fil.c index 1dd95e9ba5..40443d5ab5 100644 --- a/usr/src/uts/common/inet/ipf/fil.c +++ b/usr/src/uts/common/inet/ipf/fil.c @@ -184,6 +184,9 @@ u_long fr_frouteok[2] = {0, 0}; u_long fr_userifqs = 0; u_long fr_badcoalesces[2] = {0, 0}; u_char ipf_iss_secret[32]; +#if SOLARIS2 >= 10 +int ipf_loopback = 0; +#endif #if defined(IPFILTER_DEFAULT_BLOCK) int fr_pass = FR_BLOCK|FR_NOMATCH; #else @@ -241,7 +244,9 @@ static INLINE int fr_updateipid __P((fr_info_t *)); static int fr_grpmapinit __P((frentry_t *fr)); static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *)); #endif -static void frsynclist __P((frentry_t *, void *)); +static void frsynclist __P((int, int, void *, char *, frentry_t *)); +static void *fr_ifsync __P((int, int, char *, char *, + void *, void *)); static ipftuneable_t *fr_findtunebyname __P((const char *)); static ipftuneable_t *fr_findtunebycookie __P((void *, void **)); @@ -2367,8 +2372,8 @@ int out; bzero((char *)fin, sizeof(*fin)); # ifdef MENTAT - if (qpi->qpi_flags & QF_GROUP) - fin->fin_flx |= FI_MBCAST; + if (qpi->qpi_flags & QPI_NOCKSUM) + fin->fin_flx |= FI_NOCKSUM; m = qpi->qpi_m; fin->fin_qfm = m; fin->fin_qpi = qpi; @@ -3611,10 +3616,63 @@ u_32_t *msk; /* ------------------------------------------------------------------------ */ +/* Function: fr_ifsync */ +/* Returns: void * - new interface identifier */ +/* Parameters: action(I) - type of synchronisation to do */ +/* v(I) - IP version being sync'd (v4 or v6) */ +/* newifp(I) - interface identifier being introduced/removed */ +/* oldifp(I) - interface identifier in a filter rule */ +/* newname(I) - name associated with oldifp interface */ +/* oldname(I) - name associated with newifp interface */ +/* */ +/* This function returns what the new value for "oldifp" should be for its */ +/* caller. In some cases it will not change, in some it will. */ +/* action == IPFSYNC_RESYNC */ +/* a new value for oldifp will always be looked up, according to oldname, */ +/* the values of newname and newifp are ignored. */ +/* action == IPFSYNC_NEWIFP */ +/* if oldname matches newname then we are doing a sync for the matching */ +/* interface, so we return newifp to be used in place of oldifp. If the */ +/* the names don't match, just return oldifp. */ +/* action == IPFSYNC_OLDIFP */ +/* if oldifp matches newifp then we are are doing a sync to remove any */ +/* references to oldifp, so we return "-1". */ +/* ------------------------------------------------------------------------ */ +static void *fr_ifsync(action, v, newname, oldname, newifp, oldifp) +int action, v; +char *newname, *oldname; +void *newifp, *oldifp; +{ + void *rval = oldifp; + + switch (action) + { + case IPFSYNC_RESYNC : + if (oldname[0] != '\0') { + rval = fr_resolvenic(oldname, v); + } + break; + case IPFSYNC_NEWIFP : + if (!strncmp(newname, oldname, LIFNAMSIZ)) + rval = newifp; + break; + case IPFSYNC_OLDIFP : + if (newifp == oldifp) + rval = (void *)-1; + break; + } + + return rval; +} + + +/* ------------------------------------------------------------------------ */ /* Function: frsynclist */ /* Returns: void */ -/* Parameters: fr(I) - start of filter list to sync interface names for */ -/* ifp(I) - interface pointer for limiting sync lookups */ +/* Parameters: action(I) - type of synchronisation to do */ +/* v(I) - IP version being sync'd (v4 or v6) */ +/* ifp(I) - interface identifier associated with action */ +/* name(I) - name associated with ifp parameter */ /* Write Locks: ipf_mutex */ /* */ /* Walk through a list of filter rules and resolve any interface names into */ @@ -3622,15 +3680,19 @@ u_32_t *msk; /* used in the rule. The interface pointer is used to limit the lookups to */ /* a specific set of matching names if it is non-NULL. */ /* ------------------------------------------------------------------------ */ -static void frsynclist(fr, ifp) -frentry_t *fr; +static void frsynclist(action, v, ifp, ifname, fr) +int action, v; void *ifp; +char *ifname; +frentry_t *fr; { frdest_t *fdp; - int v, i; + int rv, i; for (; fr; fr = fr->fr_next) { - v = fr->fr_v; + rv = fr->fr_v; + if (v != 0 && v != rv) + continue; /* * Lookup all the interface names that are part of the rule. @@ -3638,42 +3700,41 @@ void *ifp; for (i = 0; i < 4; i++) { if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) continue; - fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v); + fr->fr_ifas[i] = fr_ifsync(action, rv, ifname, + fr->fr_ifnames[i], + ifp, fr->fr_ifas[i]); } + fdp = &fr->fr_tifs[0]; + fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, + ifp, fdp->fd_ifp); + + fdp = &fr->fr_tifs[1]; + fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, + ifp, fdp->fd_ifp); + + fdp = &fr->fr_dif; + fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, + ifp, fdp->fd_ifp); + + if (action != IPFSYNC_RESYNC) + return; + if (fr->fr_type == FR_T_IPF) { if (fr->fr_satype != FRI_NORMAL && fr->fr_satype != FRI_LOOKUP) { - (void)fr_ifpaddr(v, fr->fr_satype, + (void)fr_ifpaddr(rv, fr->fr_satype, fr->fr_ifas[fr->fr_sifpidx], &fr->fr_src, &fr->fr_smsk); } if (fr->fr_datype != FRI_NORMAL && fr->fr_datype != FRI_LOOKUP) { - (void)fr_ifpaddr(v, fr->fr_datype, + (void)fr_ifpaddr(rv, fr->fr_datype, fr->fr_ifas[fr->fr_difpidx], &fr->fr_dst, &fr->fr_dmsk); } } - fdp = &fr->fr_tifs[0]; - if ((ifp == NULL) || (fdp->fd_ifp == ifp)) - fr_resolvedest(fdp, v); - - fdp = &fr->fr_tifs[1]; - if ((ifp == NULL) || (fdp->fd_ifp == ifp)) - fr_resolvedest(fdp, v); - - fdp = &fr->fr_dif; - if ((ifp == NULL) || (fdp->fd_ifp == ifp)) { - fr_resolvedest(fdp, v); - - fr->fr_flags &= ~FR_DUP; - if ((fdp->fd_ifp != (void *)-1) && - (fdp->fd_ifp != NULL)) - fr->fr_flags |= FR_DUP; - } - #ifdef IPFILTER_LOOKUP if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && fr->fr_srcptr == NULL) { @@ -3696,40 +3757,45 @@ void *ifp; /* ------------------------------------------------------------------------ */ /* Function: frsync */ /* Returns: void */ -/* Parameters: Nil */ +/* Parameters: action(I) - type of synchronisation to do */ +/* v(I) - IP version being sync'd (v4 or v6) */ +/* ifp(I) - interface identifier associated with action */ +/* name(I) - name associated with ifp parameter */ /* */ /* frsync() is called when we suspect that the interface list or */ /* information about interfaces (like IP#) has changed. Go through all */ /* filter rules, NAT entries and the state table and check if anything */ /* needs to be changed/updated. */ -/* ------------------------------------------------------------------------ */ -void frsync(ifp) +/* With the filtering hooks added to Solaris, we needed to change the manner*/ +/* in which this was done to support three different types of sync: */ +/* - complete resync of all interface name/identifiers */ +/* - new interface being announced with its name and identifier */ +/* - interface removal being announced by only its identifier */ +/* ------------------------------------------------------------------------ */ +void frsync(action, v, ifp, name) +int action, v; void *ifp; +char *name; { int i; -# if !SOLARIS - fr_natsync(ifp); - fr_statesync(ifp); -# endif - WRITE_ENTER(&ipf_mutex); - frsynclist(ipacct[0][fr_active], ifp); - frsynclist(ipacct[1][fr_active], ifp); - frsynclist(ipfilter[0][fr_active], ifp); - frsynclist(ipfilter[1][fr_active], ifp); - frsynclist(ipacct6[0][fr_active], ifp); - frsynclist(ipacct6[1][fr_active], ifp); - frsynclist(ipfilter6[0][fr_active], ifp); - frsynclist(ipfilter6[1][fr_active], ifp); + frsynclist(action, v, ifp, name, ipacct[0][fr_active]); + frsynclist(action, v, ifp, name, ipacct[1][fr_active]); + frsynclist(action, v, ifp, name, ipfilter[0][fr_active]); + frsynclist(action, v, ifp, name, ipfilter[1][fr_active]); + frsynclist(action, v, ifp, name, ipacct6[0][fr_active]); + frsynclist(action, v, ifp, name, ipacct6[1][fr_active]); + frsynclist(action, v, ifp, name, ipfilter6[0][fr_active]); + frsynclist(action, v, ifp, name, ipfilter6[1][fr_active]); for (i = 0; i < IPL_LOGSIZE; i++) { frgroup_t *g; for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next) - frsynclist(g->fg_start, ifp); + frsynclist(action, v, ifp, name, g->fg_start); for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next) - frsynclist(g->fg_start, ifp); + frsynclist(action, v, ifp, name, g->fg_start); } RWLOCK_EXIT(&ipf_mutex); } @@ -4292,7 +4358,7 @@ caddr_t data; /* * Lookup all the interface names that are part of the rule. */ - frsynclist(fp, NULL); + frsynclist(0, 0, NULL, NULL, fp); fp->fr_statecnt = 0; /* @@ -5549,6 +5615,14 @@ fr_info_t *fin; udphdr_t *udp; int dosum; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + net_data_t net_data_p; + if (fin->fin_v == 4) + net_data_p = ipf_ipv4; + else + net_data_p = ipf_ipv6; +#endif + if ((fin->fin_flx & FI_NOCKSUM) != 0) return 0; @@ -5565,10 +5639,12 @@ fr_info_t *fin; dosum = 0; sum = 0; -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) - if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) { - hdrsum = 0; - sum = 0; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + ASSERT(fin->fin_m != NULL); + if (NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m) || + NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { + hdrsum = 0; + sum = 0; } else { #endif switch (fin->fin_p) @@ -5602,7 +5678,7 @@ fr_info_t *fin; if (dosum) sum = fr_cksum(fin->fin_m, fin->fin_ip, fin->fin_p, fin->fin_dp); -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) } #endif #if !defined(_KERNEL) @@ -5817,6 +5893,10 @@ ipftuneable_t ipf_tuneables[] = { sizeof(fr_icmpminfragmtu), 0 }, { { &fr_pass }, "fr_pass", 0, 0xffffffff, sizeof(fr_pass), 0 }, +#if SOLARIS2 >= 10 + { { &ipf_loopback}, "ipf_loopback", 0, 1, + sizeof(ipf_loopback), IPFT_WRDISABLED }, +#endif /* state */ { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff, sizeof(fr_tcpidletimeout), IPFT_WRDISABLED }, @@ -6338,17 +6418,13 @@ void fr_resolvedest(fdp, v) frdest_t *fdp; int v; { - void *ifp; - - ifp = NULL; - v = v; /* LINT */ + fdp->fd_ifp = NULL; - if (*fdp->fd_ifname != '\0') { - ifp = GETIFP(fdp->fd_ifname, v); - if (ifp == NULL) - ifp = (void *)-1; + if (*fdp->fd_ifname != '\0') { + fdp->fd_ifp = GETIFP(fdp->fd_ifname, v); + if (fdp->fd_ifp == NULL) + fdp->fd_ifp = (void *)-1; } - fdp->fd_ifp = ifp; } #endif /* _KERNEL */ diff --git a/usr/src/uts/common/inet/ipf/ip_auth.c b/usr/src/uts/common/inet/ipf/ip_auth.c index b6f0844354..bf2afb2ba4 100644 --- a/usr/src/uts/common/inet/ipf/ip_auth.c +++ b/usr/src/uts/common/inet/ipf/ip_auth.c @@ -3,6 +3,14 @@ * * See the IPFILTER.LICENCE file for details on licencing. */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + #if defined(KERNEL) || defined(_KERNEL) # undef KERNEL # undef _KERNEL @@ -49,6 +57,7 @@ struct file; # endif # include <sys/stream.h> # include <sys/kmem.h> +# include <sys/neti.h> #endif #if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) # include <sys/queue.h> @@ -141,6 +150,10 @@ frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL, *fr_authlist = NULL; +#if SOLARIS2 >= 10 +extern net_data_t ipf_ipv4; +extern net_data_t ipf_ipv6; +#endif int fr_authinit() { @@ -341,7 +354,6 @@ fr_info_t *fin; #if SOLARIS && defined(_KERNEL) m->b_rptr -= qpi->qpi_off; fr_authpkts[i] = *(mblk_t **)fin->fin_mp; - fra->fra_q = qpi->qpi_q; /* The queue can disappear! */ cv_signal(&ipfauthwait); #else # if defined(BSD) && !defined(sparc) && (BSD >= 199306) @@ -371,6 +383,9 @@ int mode; frauth_t auth, *au = &auth, *fra; int i, error = 0, len; char *t; + net_data_t net_data_p; + net_inject_t inj_data; + int ret; switch (cmd) { @@ -498,10 +513,33 @@ fr_authioctlloop: fra->fra_pass = au->fra_pass; fr_authpkts[i] = NULL; RWLOCK_EXIT(&ipf_auth); + #ifdef _KERNEL + if (fra->fra_info.fin_v == 4) { + net_data_p = ipf_ipv4; + } else if (fra->fra_info.fin_v == 6) { + net_data_p = ipf_ipv6; + } else { + return (-1); + } + + /* + * We're putting the packet back on the same interface + * queue that it was originally seen on so that it can + * progress through the system properly, with the result + * of the auth check done. + */ + inj_data.ni_physical = (phy_if_t)fra->fra_info.fin_ifp; + if ((m != NULL) && (au->fra_info.fin_out != 0)) { # ifdef MENTAT - error = !putq(fra->fra_q, m); + inj_data.ni_packet = m; + ret = net_inject(net_data_p, NI_QUEUE_OUT, &inj_data); + + if (ret < 0) + fr_authstats.fas_sendfail++; + else + fr_authstats.fas_sendok++; # else /* MENTAT */ # if defined(linux) || defined(AIX) # else @@ -513,15 +551,16 @@ fr_authioctlloop: # else error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); # endif -# endif /* Linux */ -# endif /* MENTAT */ if (error != 0) fr_authstats.fas_sendfail++; else fr_authstats.fas_sendok++; +# endif /* Linux */ +# endif /* MENTAT */ } else if (m) { # ifdef MENTAT - error = !putq(fra->fra_q, m); + inj_data.ni_packet = m; + ret = net_inject(net_data_p, NI_QUEUE_IN, &inj_data); # else /* MENTAT */ # if defined(linux) || defined(AIX) # else diff --git a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c index 851ae007f9..5380f0f773 100644 --- a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c +++ b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c @@ -60,6 +60,7 @@ static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21 #include <inet/ip_ire.h> #include <sys/md5.h> +#include <sys/neti.h> extern int fr_flags, fr_active; #if SOLARIS2 >= 7 @@ -67,9 +68,36 @@ timeout_id_t fr_timer_id; #else int fr_timer_id; #endif +#if SOLARIS2 >= 10 +extern int ipf_loopback; +#endif +static int fr_setipfloopback __P((int)); static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); +static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t)); +static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t)); +static int ipf_hook_out __P((hook_event_token_t, hook_data_t)); +static int ipf_hook_in __P((hook_event_token_t, hook_data_t)); +static int ipf_hook_loop_out __P((hook_event_token_t, hook_data_t)); +static int ipf_hook_loop_in __P((hook_event_token_t, hook_data_t)); +static int ipf_hook __P((hook_data_t, int, int)); + +static hook_t ipfhook_in; +static hook_t ipfhook_out; +static hook_t ipfhook_nicevents; + +/* flags to indicate whether hooks are registered. */ +static boolean_t hook4_physical_in = B_FALSE; +static boolean_t hook4_physical_out = B_FALSE; +static boolean_t hook4_nic_events = B_FALSE; +static boolean_t hook4_loopback_in = B_FALSE; +static boolean_t hook4_loopback_out = B_FALSE; +static boolean_t hook6_physical_in = B_FALSE; +static boolean_t hook6_physical_out = B_FALSE; +static boolean_t hook6_nic_events = B_FALSE; +static boolean_t hook6_loopback_in = B_FALSE; +static boolean_t hook6_loopback_out = B_FALSE; ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; @@ -94,6 +122,10 @@ u_long *ip_mtudisc = NULL; u_long *ip_forwarding = NULL; #endif #endif +#if SOLARIS2 >= 10 +extern net_data_t ipf_ipv4; +extern net_data_t ipf_ipv6; +#endif int ipf_locks_done = 0; @@ -125,10 +157,79 @@ int ipldetach() } #endif + /* + * This lock needs to be dropped around the net_unregister_hook calls + * because we can deadlock here with: + * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs + * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) + */ + RWLOCK_EXIT(&ipf_global); + + /* + * Remove IPv6 Hooks + */ + if (ipf_ipv6 != NULL) { + if (hook6_physical_in) { + hook6_physical_in = (net_unregister_hook(ipf_ipv6, + NH_PHYSICAL_IN, &ipfhook_in) != 0); + } + if (hook6_physical_out) { + hook6_physical_out = (net_unregister_hook(ipf_ipv6, + NH_PHYSICAL_OUT, &ipfhook_out) != 0); + } + if (hook6_nic_events) { + hook6_nic_events = (net_unregister_hook(ipf_ipv6, + NH_NIC_EVENTS, &ipfhook_nicevents) != 0); + } + if (hook6_loopback_in) { + hook6_loopback_in = (net_unregister_hook(ipf_ipv6, + NH_LOOPBACK_IN, &ipfhook_in) != 0); + } + if (hook6_loopback_out) { + hook6_loopback_out = (net_unregister_hook(ipf_ipv6, + NH_LOOPBACK_OUT, &ipfhook_out) != 0); + } + + if (net_release(ipf_ipv6) != 0) + goto detach_failed; + ipf_ipv6 = NULL; + } + + /* + * Remove IPv4 Hooks + */ + if (ipf_ipv4 != NULL) { + if (hook4_physical_in) { + hook4_physical_in = (net_unregister_hook(ipf_ipv4, + NH_PHYSICAL_IN, &ipfhook_in) != 0); + } + if (hook4_physical_out) { + hook4_physical_out = (net_unregister_hook(ipf_ipv4, + NH_PHYSICAL_OUT, &ipfhook_out) != 0); + } + if (hook4_nic_events) { + hook4_nic_events = (net_unregister_hook(ipf_ipv4, + NH_NIC_EVENTS, &ipfhook_nicevents) != 0); + } + if (hook4_loopback_in) { + hook4_loopback_in = (net_unregister_hook(ipf_ipv4, + NH_LOOPBACK_IN, &ipfhook_in) != 0); + } + if (hook4_loopback_out) { + hook4_loopback_out = (net_unregister_hook(ipf_ipv4, + NH_LOOPBACK_OUT, &ipfhook_out) != 0); + } + + if (net_release(ipf_ipv4) != 0) + goto detach_failed; + ipf_ipv4 = NULL; + } + #ifdef IPFDEBUG cmn_err(CE_CONT, "ipldetach()\n"); #endif + WRITE_ENTER(&ipf_global); fr_deinitialise(); (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); @@ -140,7 +241,18 @@ int ipldetach() RW_DESTROY(&ipf_ipidfrag); ipf_locks_done = 0; } + + if (hook4_physical_in || hook4_physical_out || hook4_nic_events || + hook4_loopback_in || hook4_loopback_out || hook6_nic_events || + hook6_physical_in || hook6_physical_out || hook6_loopback_in || + hook6_loopback_out) + return -1; + return 0; + +detach_failed: + WRITE_ENTER(&ipf_global); + return -1; } @@ -165,6 +277,101 @@ int iplattach __P((void)) if (fr_initialise() < 0) return -1; + HOOK_INIT(&ipfhook_nicevents, ipf_nic_event_v4, + "ipfilter_hook_nicevents"); + HOOK_INIT(&ipfhook_in, ipf_hook_in, "ipfilter_hook_in"); + HOOK_INIT(&ipfhook_out, ipf_hook_out, "ipfilter_hook_out"); + + /* + * If we hold this lock over all of the net_register_hook calls, we + * can cause a deadlock to occur with the following lock ordering: + * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs + * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) + */ + RWLOCK_EXIT(&ipf_global); + + /* + * Add IPv4 hooks + */ + ipf_ipv4 = net_lookup(NHF_INET); + if (ipf_ipv4 == NULL) + goto hookup_failed; + + hook4_nic_events = (net_register_hook(ipf_ipv4, NH_NIC_EVENTS, + &ipfhook_nicevents) == 0); + if (!hook4_nic_events) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_in; + hook4_physical_in = (net_register_hook(ipf_ipv4, NH_PHYSICAL_IN, + &ipfhook_in) == 0); + if (!hook4_physical_in) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_out; + hook4_physical_out = (net_register_hook(ipf_ipv4, NH_PHYSICAL_OUT, + &ipfhook_out) == 0); + if (!hook4_physical_out) + goto hookup_failed; + + if (ipf_loopback) { + ipfhook_in.h_func = ipf_hook_loop_in; + hook4_loopback_in = (net_register_hook(ipf_ipv4, + NH_LOOPBACK_IN, &ipfhook_in) == 0); + if (!hook4_loopback_in) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_loop_out; + hook4_loopback_out = (net_register_hook(ipf_ipv4, + NH_LOOPBACK_OUT, &ipfhook_out) == 0); + if (!hook4_loopback_out) + goto hookup_failed; + } + /* + * Add IPv6 hooks + */ + ipf_ipv6 = net_lookup(NHF_INET6); + if (ipf_ipv6 == NULL) + goto hookup_failed; + + HOOK_INIT(&ipfhook_nicevents, ipf_nic_event_v6, + "ipfilter_hook_nicevents"); + hook6_nic_events = (net_register_hook(ipf_ipv6, NH_NIC_EVENTS, + &ipfhook_nicevents) == 0); + if (!hook6_nic_events) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_in; + hook6_physical_in = (net_register_hook(ipf_ipv6, NH_PHYSICAL_IN, + &ipfhook_in) == 0); + if (!hook6_physical_in) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_out; + hook6_physical_out = (net_register_hook(ipf_ipv6, NH_PHYSICAL_OUT, + &ipfhook_out) == 0); + if (!hook6_physical_out) + goto hookup_failed; + + if (ipf_loopback) { + ipfhook_in.h_func = ipf_hook_loop_in; + hook6_loopback_in = (net_register_hook(ipf_ipv6, + NH_LOOPBACK_IN, &ipfhook_in) == 0); + if (!hook6_loopback_in) + goto hookup_failed; + + ipfhook_in.h_func = ipf_hook_loop_out; + hook6_loopback_out = (net_register_hook(ipf_ipv6, + NH_LOOPBACK_OUT, &ipfhook_out) == 0); + if (!hook6_loopback_out) + goto hookup_failed; + } + + /* + * Reacquire ipf_global, now it is safe. + */ + WRITE_ENTER(&ipf_global); + /* Do not use private interface ip_params_arr[] in Solaris 10 */ #if SOLARIS2 < 10 @@ -218,6 +425,64 @@ int iplattach __P((void)) #endif return 0; +hookup_failed: + WRITE_ENTER(&ipf_global); + return -1; +} + +static int fr_setipfloopback(set) +int set; +{ + if (ipf_ipv4 == NULL || ipf_ipv6 == NULL) + return EFAULT; + + if (set && !ipf_loopback) { + ipf_loopback = 1; + + hook4_loopback_in = (net_register_hook(ipf_ipv4, + NH_LOOPBACK_IN, &ipfhook_in) == 0); + if (!hook4_loopback_in) + return EINVAL; + + hook4_loopback_out = (net_register_hook(ipf_ipv4, + NH_LOOPBACK_OUT, &ipfhook_out) == 0); + if (!hook4_loopback_out) + return EINVAL; + + hook6_loopback_in = (net_register_hook(ipf_ipv6, + NH_LOOPBACK_IN, &ipfhook_in) == 0); + if (!hook6_loopback_in) + return EINVAL; + + hook6_loopback_out = (net_register_hook(ipf_ipv6, + NH_LOOPBACK_OUT, &ipfhook_out) == 0); + if (!hook6_loopback_out) + return EINVAL; + + } else if (!set && ipf_loopback) { + ipf_loopback = 0; + + hook4_loopback_in = (net_unregister_hook(ipf_ipv4, + NH_LOOPBACK_IN, &ipfhook_in) != 0); + if (hook4_loopback_in) + return EBUSY; + + hook4_loopback_out = (net_unregister_hook(ipf_ipv4, + NH_LOOPBACK_OUT, &ipfhook_out) != 0); + if (hook4_loopback_out) + return EBUSY; + + hook6_loopback_in = (net_unregister_hook(ipf_ipv6, + NH_LOOPBACK_IN, &ipfhook_in) != 0); + if (hook6_loopback_in) + return EBUSY; + + hook6_loopback_out = (net_unregister_hook(ipf_ipv6, + NH_LOOPBACK_OUT, &ipfhook_out) != 0); + if (hook6_loopback_out) + return EBUSY; + } + return 0; } @@ -319,6 +584,14 @@ int *rp; error = EFAULT; } break; + case SIOCIPFLP : + error = COPYIN((caddr_t)data, (caddr_t)&tmp, + sizeof(tmp)); + if (error != 0) + error = EFAULT; + else + error = fr_setipfloopback(tmp); + break; case SIOCGETFF : error = COPYOUT((caddr_t)&fr_flags, (caddr_t)data, sizeof(fr_flags)); @@ -435,7 +708,12 @@ int *rp; else { RWLOCK_EXIT(&ipf_global); WRITE_ENTER(&ipf_global); - error = ipfsync(); + + frsync(IPFSYNC_RESYNC, 0, NULL, NULL); + fr_natifpsync(IPFSYNC_RESYNC, NULL, NULL); + fr_nataddrsync(NULL, NULL); + fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL); + error = 0; } break; case SIOCGFRST : @@ -461,26 +739,25 @@ int *rp; } -void *get_unit(name, v) -char *name; -int v; +phy_if_t get_unit(name, v) +char *name; +int v; { - qif_t *qf; - int sap; - - if (v == 4) - sap = 0x0800; - else if (v == 6) - sap = 0x86dd; - else - return NULL; - rw_enter(&pfil_rw, RW_READER); - qf = qif_iflookup(name, sap); - rw_exit(&pfil_rw); - return qf; + phy_if_t phy; + net_data_t nif; + + if (v == 4) + nif = ipf_ipv4; + else if (v == 6) + nif = ipf_ipv6; + else + return 0; + + phy = net_phylookup(nif, name); + + return (phy); } - /* * routines below for saving IP headers to buffer */ @@ -675,7 +952,6 @@ mblk_t *m, **mpp; { qpktinfo_t qpi, *qpip; fr_info_t fnew; - qif_t *qif; ip_t *ip; int i, hlen; @@ -698,8 +974,8 @@ mblk_t *m, **mpp; fnew.fin_v = 4; #if SOLARIS2 >= 10 ip->ip_ttl = 255; - - ip->ip_off = htons(IP_DF); + if (net_getpmtuenabled(ipf_ipv4) == 1) + ip->ip_off = htons(IP_DF); #else if (ip_ttl_ptr != NULL) ip->ip_ttl = (u_char)(*ip_ttl_ptr); @@ -724,17 +1000,8 @@ mblk_t *m, **mpp; } qpip = fin->fin_qpi; - qpi.qpi_q = qpip->qpi_q; qpi.qpi_off = 0; - qpi.qpi_name = qpip->qpi_name; - qif = qpip->qpi_real; - qpi.qpi_real = qif; - qpi.qpi_ill = qif->qf_ill; - qpi.qpi_hl = qif->qf_hl; - qpi.qpi_ppa = qif->qf_ppa; - qpi.qpi_num = qif->qf_num; - qpi.qpi_flags = qif->qf_flags; - qpi.qpi_max_frag = qif->qf_max_frag; + qpi.qpi_ill = qpip->qpi_ill; qpi.qpi_m = m; qpi.qpi_data = ip; fnew.fin_qpi = &qpi; @@ -761,6 +1028,7 @@ int dst; struct icmp *icmp; qpktinfo_t *qpi; int hlen, code; + phy_if_t phy; u_short sz; #ifdef USE_INET6 mblk_t *mb; @@ -830,11 +1098,10 @@ int dst; icmp = (struct icmp *)(m->b_rptr + hlen); icmp->icmp_type = type & 0xff; icmp->icmp_code = code & 0xff; -#ifdef icmp_nextmtu - if (type == ICMP_UNREACH && (qpi->qpi_max_frag != 0) && + phy = (phy_if_t)qpi->qpi_ill; + if (type == ICMP_UNREACH && (phy != 0) && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) - icmp->icmp_nextmtu = htons(qpi->qpi_max_frag); -#endif + icmp->icmp_nextmtu = net_getmtu(ipf_ipv4, phy,0 ); #ifdef USE_INET6 if (fin->fin_v == 6) { @@ -842,8 +1109,8 @@ int dst; int csz; if (dst == 0) { - if (fr_ifpaddr(6, FRI_NORMAL, qpi->qpi_real, - (struct in_addr *)&dst6, NULL) == -1) { + if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, + (void *)&dst6, NULL) == -1) { FREE_MB_T(m); return -1; } @@ -870,13 +1137,14 @@ int dst; ip->ip_tos = fin->fin_ip->ip_tos; ip->ip_len = (u_short)sz; if (dst == 0) { - if (fr_ifpaddr(4, FRI_NORMAL, qpi->qpi_real, - &dst4, NULL) == -1) { + if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, + (void *)&dst4, NULL) == -1) { FREE_MB_T(m); return -1; } - } else + } else { dst4 = fin->fin_dst; + } ip->ip_src = dst4; ip->ip_dst = fin->fin_src; bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, @@ -896,7 +1164,6 @@ int dst; return fr_send_ip(fin, m, &m); } -#ifdef IRE_ILL_CN #include <sys/time.h> #include <sys/varargs.h> @@ -940,120 +1207,68 @@ static void rate_limit_message(int rate, const char *message, ...) #endif } } -#endif /* * return the first IP Address associated with an interface */ /*ARGSUSED*/ -int fr_ifpaddr(v, atype, qifptr, inp, inpmask) +int fr_ifpaddr(v, atype, ifptr, inp, inpmask) int v, atype; -void *qifptr; -struct in_addr *inp, *inpmask; +void *ifptr; +struct in_addr *inp, *inpmask; { -#ifdef USE_INET6 - struct sockaddr_in6 sin6, mask6; -#endif - struct sockaddr_in sin, mask; - qif_t *qif; + struct sockaddr_in6 v6addr[2]; + struct sockaddr_in v4addr[2]; + net_ifaddr_t type[2]; + net_data_t net_data; + phy_if_t phyif; + void *array; + + switch (v) + { + case 4: + net_data = ipf_ipv4; + array = v4addr; + break; + case 6: + net_data = ipf_ipv6; + array = v6addr; + break; + default: + net_data = NULL; + break; + } -#ifdef USE_INET6 -#ifdef IRE_ILL_CN - s_ill_t *ill; -#endif -#endif - if ((qifptr == NULL) || (qifptr == (void *)-1)) + if (net_data == NULL) return -1; - qif = qifptr; - -#ifdef USE_INET6 -#ifdef IRE_ILL_CN - ill = qif->qf_ill; -#endif -#endif - -#ifdef USE_INET6 - if (v == 6) { -#ifndef IRE_ILL_CN - in6_addr_t *inp6; - ipif_t *ipif; - ill_t *ill; - - ill = qif->qf_ill; - - /* - * First is always link local. - */ - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { - inp6 = &ipif->ipif_v6lcl_addr; - if (!IN6_IS_ADDR_LINKLOCAL(inp6) && - !IN6_IS_ADDR_LOOPBACK(inp6)) - break; - } - if (ipif == NULL) - return -1; - - mask6.sin6_addr = ipif->ipif_v6net_mask; - if (atype == FRI_BROADCAST) - sin6.sin6_addr = ipif->ipif_v6brd_addr; - else if (atype == FRI_PEERADDR) - sin6.sin6_addr = ipif->ipif_v6pp_dst_addr; - else - sin6.sin6_addr = *inp6; -#else /* IRE_ILL_CN */ - if (IN6_IS_ADDR_UNSPECIFIED(&ill->netmask.in6.sin6_addr) || - IN6_IS_ADDR_UNSPECIFIED(&ill->localaddr.in6.sin6_addr)) { - rate_limit_message(NULLADDR_RATE_LIMIT, - "Check pfild is running: IP#/netmask is 0 on %s.\n", - ill->ill_name); - return -1; - } - mask6 = ill->netmask.in6; - if (atype == FRI_BROADCAST) - sin6 = ill->broadaddr.in6; - else if (atype == FRI_PEERADDR) - sin6 = ill->dstaddr.in6; - else - sin6 = ill->localaddr.in6; -#endif /* IRE_ILL_CN */ - return fr_ifpfillv6addr(atype, &sin6, &mask6, inp, inpmask); - } -#endif - -#ifndef IRE_ILL_CN + phyif = (phy_if_t)ifptr; switch (atype) { - case FRI_BROADCAST : - sin.sin_addr.s_addr = QF_V4_BROADCAST(qif); - break; case FRI_PEERADDR : - sin.sin_addr.s_addr = QF_V4_PEERADDR(qif); + type[0] = NA_PEER; break; + + case FRI_BROADCAST : + type[0] = NA_BROADCAST; + break; + default : - sin.sin_addr.s_addr = QF_V4_ADDR(qif); + type[0] = NA_ADDRESS; break; } - mask.sin_addr.s_addr = QF_V4_NETMASK(qif); -#else - if (ill->netmask.in.sin_addr.s_addr == 0 || - ill->localaddr.in.sin_addr.s_addr == 0) { - rate_limit_message(NULLADDR_RATE_LIMIT, - "Check pfild is running: IP#/netmask is 0 on %s.\n", - ill->ill_name); + type[1] = NA_NETMASK; + + if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) return -1; + + if (v == 6) { + return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], + inp, inpmask); } - mask = ill->netmask.in; - if (atype == FRI_BROADCAST) - sin = ill->broadaddr.in; - else if (atype == FRI_PEERADDR) - sin = ill->dstaddr.in; - else - sin = ill->localaddr.in; -#endif /* IRE_ILL_CN */ - return fr_ifpfillv4addr(atype, &sin, &mask, inp, inpmask); + return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); } @@ -1154,42 +1369,6 @@ fr_info_t *fin; #endif /* USE_INET6 */ -/* - * Function: fr_verifysrc - * Returns: int (really boolean) - * Parameters: fin - packet information - * - * Check whether the packet has a valid source address for the interface on - * which the packet arrived, implementing the "fr_chksrc" feature. - * Returns true iff the packet's source address is valid. - * Pre-Solaris 10, we call into the routing code to make the determination. - * On Solaris 10 and later, we have a valid address set from pfild to check - * against. - */ -int fr_verifysrc(fin) -fr_info_t *fin; -{ - ire_t *dir; - int result; - -#if SOLARIS2 >= 6 - dir = ire_route_lookup(fin->fin_saddr, 0xffffffff, 0, 0, NULL, - NULL, NULL, NULL, MATCH_IRE_DSTONLY| - MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); -#else - dir = ire_lookup(fin->fin_saddr); -#endif - - if (!dir) - return 0; - result = (ire_to_ill(dir) == fin->fin_ifp); -#if SOLARIS2 >= 8 - ire_refrele(dir); -#endif - return result; -} - - #if (SOLARIS2 < 7) void fr_slowtimer() #else @@ -1223,63 +1402,190 @@ void fr_slowtimer __P((void *ptr)) } +/* ------------------------------------------------------------------------ */ +/* Function: fr_pullup */ +/* Returns: NULL == pullup failed, else pointer to protocol header */ +/* Parameters: m(I) - pointer to buffer where data packet starts */ +/* fin(I) - pointer to packet information */ +/* len(I) - number of bytes to pullup */ +/* */ +/* Attempt to move at least len bytes (from the start of the buffer) into a */ +/* single buffer for ease of access. Operating system native functions are */ +/* used to manage buffers - if necessary. If the entire packet ends up in */ +/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ +/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ +/* and ONLY if the pullup succeeds. */ +/* */ +/* We assume that 'min' is a pointer to a buffer that is part of the chain */ +/* of buffers that starts at *fin->fin_mp. */ +/* ------------------------------------------------------------------------ */ +void *fr_pullup(min, fin, len) +mb_t *min; +fr_info_t *fin; +int len; +{ + qpktinfo_t *qpi = fin->fin_qpi; + int out = fin->fin_out, dpoff, ipoff; + mb_t *m = min, *m1, *m2; + char *ip; + + if (m == NULL) + return NULL; + + ip = (char *)fin->fin_ip; + if ((fin->fin_flx & FI_COALESCE) != 0) + return ip; + + ipoff = fin->fin_ipoff; + if (fin->fin_dp != NULL) + dpoff = (char *)fin->fin_dp - (char *)ip; + else + dpoff = 0; + + if (M_LEN(m) < len) { + + /* + * pfil_precheck ensures the IP header is on a 32bit + * aligned address so simply fail if that isn't currently + * the case (should never happen). + */ + int inc = 0; + + if (ipoff > 0) { + if ((ipoff & 3) != 0) { + inc = 4 - (ipoff & 3); + if (m->b_rptr - inc >= m->b_datap->db_base) + m->b_rptr -= inc; + else + inc = 0; + } + } + + /* + * XXX This is here as a work around for a bug with DEBUG + * XXX Solaris kernels. The problem is b_prev is used by IP + * XXX code as a way to stash the phyint_index for a packet, + * XXX this doesn't get reset by IP but freeb does an ASSERT() + * XXX for both of these to be NULL. See 6442390. + */ + m1 = m; + m2 = m->b_prev; + + do { + m1->b_next = NULL; + m1->b_prev = NULL; + m1 = m1->b_cont; + } while (m1); + if (pullupmsg(m, len + ipoff + inc) == 0) { + ATOMIC_INCL(frstats[out].fr_pull[1]); + FREE_MB_T(*fin->fin_mp); + *fin->fin_mp = NULL; + fin->fin_m = NULL; + fin->fin_ip = NULL; + fin->fin_dp = NULL; + qpi->qpi_data = NULL; + return NULL; + } + m->b_prev = m2; + m->b_rptr += inc; + fin->fin_m = m; + ip = MTOD(m, char *) + ipoff; + qpi->qpi_data = ip; + } + + ATOMIC_INCL(frstats[out].fr_pull[0]); + fin->fin_ip = (ip_t *)ip; + if (fin->fin_dp != NULL) + fin->fin_dp = (char *)fin->fin_ip + dpoff; + + if (len == fin->fin_plen) + fin->fin_flx |= FI_COALESCE; + return ip; +} + + /* - * Function: fr_fastroute - * Returns: 0: success; - * -1: failed + * Function: fr_verifysrc + * Returns: int (really boolean) + * Parameters: fin - packet information + * + * Check whether the packet has a valid source address for the interface on + * which the packet arrived, implementing the "fr_chksrc" feature. + * Returns true iff the packet's source address is valid. + */ +int fr_verifysrc(fin) +fr_info_t *fin; +{ + net_data_t net_data_p; + phy_if_t phy_ifdata_routeto; + struct sockaddr sin; + + if (fin->fin_v == 4) { + net_data_p = ipf_ipv4; + } else if (fin->fin_v == 6) { + net_data_p = ipf_ipv6; + } else { + return (0); + } + + /* Get the index corresponding to the if name */ + sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; + bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); + phy_ifdata_routeto = net_routeto(net_data_p, &sin); + + return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); +} + + +/* + * Function: fr_fastroute + * Returns: 0: success; + * -1: failed * Parameters: - * mb: the message block where ip head starts - * mpp: the pointer to the pointer of the orignal - * packet message - * fin: packet information - * fdp: destination interface information - * if it is NULL, no interface information provided. + * mb: the message block where ip head starts + * mpp: the pointer to the pointer of the orignal + * packet message + * fin: packet information + * fdp: destination interface information + * if it is NULL, no interface information provided. * * This function is for fastroute/to/dup-to rules. It calls * pfil_make_lay2_packet to search route, make lay-2 header * ,and identify output queue for the IP packet. * The destination address depends on the following conditions: * 1: for fastroute rule, fdp is passed in as NULL, so the - * destination address is the IP Packet's destination address + * destination address is the IP Packet's destination address * 2: for to/dup-to rule, if an ip address is specified after - * the interface name, this address is the as destination - * address. Otherwise IP Packet's destination address is used + * the interface name, this address is the as destination + * address. Otherwise IP Packet's destination address is used */ int fr_fastroute(mb, mpp, fin, fdp) mblk_t *mb, **mpp; fr_info_t *fin; frdest_t *fdp; { - struct in_addr dst; -#ifndef IRE_ILL_CN - size_t hlen = 0; - ill_t *ifp; - ire_t *dir; - u_char *s; - frdest_t fd; -#ifdef USE_INET6 - ip6_t *ip6 = (ip6_t *)fin->fin_ip; -#endif -#else - void *target = NULL; - char *ifname = NULL; -#endif - queue_t *q = NULL; + net_data_t net_data_p; + net_inject_t inj_data; mblk_t *mp = NULL; + frentry_t *fr = fin->fin_fr; qpktinfo_t *qpi; - frentry_t *fr; - qif_t *qif; ip_t *ip; + + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + struct sockaddr *sinp; #ifndef sparc u_short __iplen, __ipoff; #endif -#ifdef USE_INET6 - struct in6_addr dst6; -#endif -#ifndef IRE_ILL_CN - dir = NULL; -#endif - fr = fin->fin_fr; + + if (fin->fin_v == 4) { + net_data_p = ipf_ipv4; + } else if (fin->fin_v == 6) { + net_data_p = ipf_ipv6; + } else { + return (-1); + } + ip = fin->fin_ip; qpi = fin->fin_qpi; @@ -1287,14 +1593,16 @@ frdest_t *fdp; * If this is a duplicate mblk then we want ip to point at that * data, not the original, if and only if it is already pointing at * the current mblk data. - * Otherwise, If it's not a duplicate, and we're not already pointing + * + * Otherwise, if it's not a duplicate, and we're not already pointing * at the current mblk data, then we want to ensure that the data * points at ip. */ - if (ip == (ip_t *)qpi->qpi_m->b_rptr && qpi->qpi_m != mb) + + if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { ip = (ip_t *)mb->b_rptr; - else if (qpi->qpi_m == mb && ip != (ip_t *)qpi->qpi_m->b_rptr) { - qpi->qpi_m->b_rptr = (u_char *)ip; + } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { + qpi->qpi_m->b_rptr = (uchar_t *)ip; qpi->qpi_off = 0; } @@ -1307,326 +1615,297 @@ frdest_t *fdp; *mpp = mp; } - /* - * If the fdp is NULL then there is no set route for this packet. - */ - if (fdp == NULL) { - qif = fin->fin_ifp; -#ifndef IRE_ILL_CN - switch (fin->fin_v) - { - case 4 : - fd.fd_ip = ip->ip_dst; - break; -#ifdef USE_INET6 - case 6 : - fd.fd_ip6.in6 = ip6->ip6_dst; - break; -#endif - } - fdp = &fd; -#endif - } else { - qif = fdp->fd_ifp; - - if (qif == NULL || qif == (void *)-1) - goto bad_fastroute; - } + sinp = (struct sockaddr *)&inj_data.ni_addr; + sin = (struct sockaddr_in *)sinp; + sin6 = (struct sockaddr_in6 *)sinp; + bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); + inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; + inj_data.ni_packet = mb; /* * In case we're here due to "to <if>" being used with * "keep state", check that we're going in the correct * direction. */ - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((qif != NULL) && (fdp == &fr->fr_tif)) - return -1; - dst.s_addr = fin->fin_fi.fi_daddr; - } else { + if (fdp != NULL) { + if ((fr != NULL) && (fdp->fd_ifp != NULL) && + (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) + goto bad_fastroute; + inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; if (fin->fin_v == 4) { - if (fdp && fdp->fd_ip.s_addr != 0) { - dst = fdp->fd_ip; -#ifdef IRE_ILL_CN - target = &dst; -#endif - } else - dst.s_addr = fin->fin_fi.fi_daddr; + sin->sin_addr = fdp->fd_ip; + } else { + sin6->sin6_addr = fdp->fd_ip6.in6; } -#ifdef USE_INET6 - else if (fin->fin_v == 6) { - if (fdp && IP6_NOTZERO(&fdp->fd_ip)) { - dst6 = fdp->fd_ip6.in6; -#ifdef IRE_ILL_CN - target = &dst6; -#endif - } else - dst6 = fin->fin_dst6; + } else { + if (fin->fin_v == 4) { + sin->sin_addr = ip->ip_dst; + } else { + sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; } -#endif - else - goto bad_fastroute; + inj_data.ni_physical = net_routeto(net_data_p, sinp); } -#ifndef IRE_ILL_CN -#if SOLARIS2 >= 6 - if (fin->fin_v == 4) { - dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, - NULL, NULL, MATCH_IRE_DSTONLY| - MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); - } -# ifdef USE_INET6 - else if (fin->fin_v == 6) { - dir = ire_route_lookup_v6(&ip6->ip6_dst, NULL, 0, 0, - NULL, NULL, NULL, MATCH_IRE_DSTONLY| - MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); - } -# endif -#else - dir = ire_lookup(dst.s_addr); -#endif -#if SOLARIS2 < 8 - if (dir != NULL) - if (dir->ire_ll_hdr_mp == NULL || dir->ire_ll_hdr_length == 0) - dir = NULL; - -#elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) - if (dir != NULL) { - if (dir->ire_fp_mp == NULL || dir->ire_dlureq_mp == NULL) { - ire_refrele(dir); - dir = NULL; - } - } -#else + /* disable hardware checksum */ + DB_CKSUMFLAGS(mb) = 0; - if (dir != NULL) - if (dir->ire_nce && dir->ire_nce->nce_state != ND_REACHABLE) { - ire_refrele(dir); - dir = NULL; - } -#endif -#else /* IRE_ILL_CN */ - if (fdp && fdp->fd_ifname[0] != 0) - ifname = fdp->fd_ifname; + *mpp = mb; - DB_CKSUMFLAGS(mb) = 0; /* disable hardware checksum */ - mp = pfil_make_dl_packet(mb, ip, target, ifname, &q); - if (mp == NULL) - { - goto bad_fastroute; - } - mb = mp; -#endif /* IRE_ILL_CN */ + if (fin->fin_out == 0) { + void *saveifp; + u_32_t pass; -#ifdef IRE_ILL_CN - if (mp != NULL) { -#else - if (dir != NULL) { -#if SOLARIS2 < 8 - mp = dir->ire_ll_hdr_mp; - hlen = dir->ire_ll_hdr_length; -#elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) - mp = dir->ire_fp_mp; - hlen = mp ? mp->b_wptr - mp->b_rptr : 0; - if (mp == NULL) - mp = dir->ire_dlureq_mp; -#else - mp = dir->ire_nce->nce_fp_mp; - hlen = mp ? mp->b_wptr - mp->b_rptr : 0; - if (mp == NULL) - mp = dir->ire_nce->nce_res_mp; -#endif -#endif - if (fin->fin_out == 0) { - void *saveqif; - u_32_t pass; - - saveqif = fin->fin_ifp; - fin->fin_ifp = qif; - fin->fin_out = 1; - (void)fr_acctpkt(fin, &pass); - fin->fin_fr = NULL; - if (!fr || !(fr->fr_flags & FR_RETMASK)) - (void) fr_checkstate(fin, &pass); - - switch (fr_checknatout(fin, NULL)) - { - /* FALLTHROUGH */ - case 0 : - case 1 : - break; - case -1 : - goto bad_fastroute; - } - - fin->fin_out = 0; - fin->fin_ifp = saveqif; + saveifp = fin->fin_ifp; + fin->fin_ifp = (void *)inj_data.ni_physical; + fin->fin_out = 1; + (void) fr_acctpkt(fin, &pass); + fin->fin_fr = NULL; + if (!fr || !(fr->fr_flags & FR_RETMASK)) + (void) fr_checkstate(fin, &pass); + switch (fr_checknatout(fin, NULL)) + { + /* FALLTHROUGH */ + case 0 : + case 1 : + break; + case -1 : + goto bad_fastroute; } -#ifndef sparc - if (fin->fin_v == 4) { - __iplen = (u_short)ip->ip_len, - __ipoff = (u_short)ip->ip_off; + fin->fin_out = 0; + fin->fin_ifp = saveifp; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); - } -#endif -#ifndef IRE_ILL_CN - ifp = qif->qf_ill; - - if (mp != NULL) { - s = mb->b_rptr; - if ( -#if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) - (dohwcksum && - ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC) || -#endif - (hlen && (s - mb->b_datap->db_base) >= hlen)) { - s -= hlen; - mb->b_rptr = (u_char *)s; - bcopy((char *)mp->b_rptr, (char *)s, hlen); - } else { - mblk_t *mp2; + if (fin->fin_nat != NULL) + fr_natderef((nat_t **)&fin->fin_nat); + } +#ifndef sparc + if (fin->fin_v == 4) { + __iplen = (u_short)ip->ip_len, + __ipoff = (u_short)ip->ip_off; - mp2 = copyb(mp); - if (mp2 == NULL) - goto bad_fastroute; - linkb(mp2, mb); - mb = mp2; - } - } - *mpp = mb; - - if (dir->ire_stq != NULL) - q = dir->ire_stq; - else if (dir->ire_rfq != NULL) - q = WR(dir->ire_rfq); - if (q != NULL) - q = q->q_next; - if (q != NULL) { - RWLOCK_EXIT(&ipf_global); -#if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) - if ((fin->fin_p == IPPROTO_TCP) && dohwcksum && - (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { - tcphdr_t *tcp; - u_32_t t; - - tcp = (tcphdr_t *)((char *)ip + fin->fin_hlen); - t = ip->ip_src.s_addr; - t += ip->ip_dst.s_addr; - t += 30; - t = (t & 0xffff) + (t >> 16); - tcp->th_sum = t & 0xffff; - } -#endif - putnext(q, mb); - ATOMIC_INCL(fr_frouteok[0]); -#if SOLARIS2 >= 8 - ire_refrele(dir); + ip->ip_len = htons(__iplen); + ip->ip_off = htons(__ipoff); + } #endif - READ_ENTER(&ipf_global); - return 0; + + if (net_data_p) { + if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { + return (-1); } -#else /* IRE_ILL_CN */ - mb->b_queue = q; - *mpp = mb; - pfil_send_dl_packet(q, mb); - ATOMIC_INCL(fr_frouteok[0]); - return 0; -#endif /* IRE_ILL_CN */ } + + fr_frouteok[0]++; + return 0; bad_fastroute: -#ifndef IRE_ILL_CN -#if SOLARIS2 >= 8 - if (dir != NULL) - ire_refrele(dir); -#endif -#endif freemsg(mb); - ATOMIC_INCL(fr_frouteok[1]); + fr_frouteok[1]++; return -1; } /* ------------------------------------------------------------------------ */ -/* Function: fr_pullup */ -/* Returns: NULL == pullup failed, else pointer to protocol header */ -/* Parameters: m(I) - pointer to buffer where data packet starts */ -/* fin(I) - pointer to packet information */ -/* len(I) - number of bytes to pullup */ +/* Function: ipf_hook_out */ +/* Returns: int - 0 == packet ok, else problem, free packet if not done */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to hook information for firewalling */ /* */ -/* Attempt to move at least len bytes (from the start of the buffer) into a */ -/* single buffer for ease of access. Operating system native functions are */ -/* used to manage buffers - if necessary. If the entire packet ends up in */ -/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ -/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ -/* and ONLY if the pullup succeeds. */ +/* Calling ipf_hook. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +int ipf_hook_out(hook_event_token_t token, hook_data_t info) +{ + return ipf_hook(info, 1, 0); +} + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_hook_in */ +/* Returns: int - 0 == packet ok, else problem, free packet if not done */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to hook information for firewalling */ /* */ -/* We assume that 'min' is a pointer to a buffer that is part of the chain */ -/* of buffers that starts at *fin->fin_mp. */ +/* Calling ipf_hook. */ /* ------------------------------------------------------------------------ */ -void *fr_pullup(min, fin, len) -mb_t *min; -fr_info_t *fin; -int len; +/*ARGSUSED*/ +int ipf_hook_in(hook_event_token_t token, hook_data_t info) { - qpktinfo_t *qpi = fin->fin_qpi; - int out = fin->fin_out, dpoff, ipoff; - mb_t *m = min; - char *ip; + return ipf_hook(info, 0, 0); +} - if (m == NULL) - return NULL; - ip = (char *)fin->fin_ip; - if ((fin->fin_flx & FI_COALESCE) != 0) - return ip; +/* ------------------------------------------------------------------------ */ +/* Function: ipf_hook_loop_out */ +/* Returns: int - 0 == packet ok, else problem, free packet if not done */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to hook information for firewalling */ +/* */ +/* Calling ipf_hook. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +int ipf_hook_loop_out(hook_event_token_t token, hook_data_t info) +{ + return ipf_hook(info, 1, 1); +} - ipoff = fin->fin_ipoff; - if (fin->fin_dp != NULL) - dpoff = (char *)fin->fin_dp - (char *)ip; +/* ------------------------------------------------------------------------ */ +/* Function: ipf_hook_loop_in */ +/* Returns: int - 0 == packet ok, else problem, free packet if not done */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to hook information for firewalling */ +/* */ +/* Calling ipf_hook. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info) +{ + return ipf_hook(info, 0, 1); +} + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_hook */ +/* Returns: int - 0 == packet ok, else problem, free packet if not done */ +/* Parameters: info(I) - pointer to hook information for firewalling */ +/* out(I) - whether packet is going in or out */ +/* loopback(I) - whether packet is a loopback packet or not */ +/* */ +/* Stepping stone function between the IP mainline and IPFilter. Extracts */ +/* parameters out of the info structure and forms them up to be useful for */ +/* calling ipfilter. */ +/* ------------------------------------------------------------------------ */ +int ipf_hook(hook_data_t info, int out, int loopback) +{ + hook_pkt_event_t *fw; + int rval, v, hlen; + qpktinfo_t qpi; + u_short swap; + phy_if_t phy; + ip_t *ip; + + fw = (hook_pkt_event_t *)info; + + ASSERT(fw != NULL); + phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; + + ip = fw->hpe_hdr; + v = ip->ip_v; + if (v == IPV4_VERSION) { + swap = ntohs(ip->ip_len); + ip->ip_len = swap; + swap = ntohs(ip->ip_off); + ip->ip_off = swap; + + hlen = IPH_HDR_LENGTH(ip); + } else + hlen = sizeof (ip6_t); + + bzero(&qpi, sizeof (qpktinfo_t)); + + qpi.qpi_m = fw->hpe_mb; + qpi.qpi_data = fw->hpe_hdr; + qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; + qpi.qpi_ill = (void *)phy; + if (loopback) + qpi.qpi_flags = QPI_NOCKSUM; else - dpoff = 0; + qpi.qpi_flags = 0; + + rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, &qpi, fw->hpe_mp); + + /* For fastroute cases, fr_check returns 0 with mp set to NULL */ + if (rval == 0 && *(fw->hpe_mp) == NULL) + rval = 1; + + /* Notify IP the packet mblk_t and IP header pointers. */ + fw->hpe_mb = qpi.qpi_m; + fw->hpe_hdr = qpi.qpi_data; + if ((rval == 0) && (v == IPV4_VERSION)) { + ip = qpi.qpi_data; + swap = ntohs(ip->ip_len); + ip->ip_len = swap; + swap = ntohs(ip->ip_off); + ip->ip_off = swap; + } + return rval; - if (M_LEN(m) < len) { +} - /* - * pfil_precheck ensures the IP header is on a 32bit - * aligned address so simply fail if that isn't currently - * the case (should never happen). - */ - int inc = 0; - if (ipoff > 0) { - if ((ipoff & 3) != 0) { - inc = 4 - (ipoff & 3); - if (m->b_rptr - inc >= m->b_datap->db_base) - m->b_rptr -= inc; - else - inc = 0; - } - } - if (pullupmsg(m, len + ipoff + inc) == 0) { - ATOMIC_INCL(frstats[out].fr_pull[1]); - FREE_MB_T(*fin->fin_mp); - *fin->fin_mp = NULL; - fin->fin_m = NULL; - fin->fin_ip = NULL; - fin->fin_dp = NULL; - qpi->qpi_data = NULL; - return NULL; - } - m->b_rptr += inc; - fin->fin_m = m; - ip = MTOD(m, char *) + ipoff; - qpi->qpi_data = ip; +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nic_event_v4 */ +/* Returns: int - 0 == no problems encountered */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to information about a NIC event */ +/* */ +/* Function to receive asynchronous NIC events from IP */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info) +{ + struct sockaddr_in *sin; + hook_nic_event_t *hn; + + hn = (hook_nic_event_t *)info; + + switch (hn->hne_event) + { + case NE_PLUMB : + frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data); + fr_natifpsync(IPFSYNC_NEWIFP, (void *)hn->hne_nic, + hn->hne_data); + fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, + hn->hne_data); + break; + + case NE_UNPLUMB : + frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL); + fr_natifpsync(IPFSYNC_OLDIFP, (void *)hn->hne_nic, NULL); + fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL); + break; + + case NE_ADDRESS_CHANGE : + sin = hn->hne_data; + fr_nataddrsync((void *)hn->hne_nic, &sin->sin_addr); + break; + + default : + break; } - ATOMIC_INCL(frstats[out].fr_pull[0]); - fin->fin_ip = (ip_t *)ip; - if (fin->fin_dp != NULL) - fin->fin_dp = (char *)fin->fin_ip + dpoff; + return 0; +} - if (len == fin->fin_plen) - fin->fin_flx |= FI_COALESCE; - return ip; + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nic_event_v6 */ +/* Returns: int - 0 == no problems encountered */ +/* Parameters: event(I) - pointer to event */ +/* info(I) - pointer to information about a NIC event */ +/* */ +/* Function to receive asynchronous NIC events from IP */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info) +{ + hook_nic_event_t *hn; + + hn = (hook_nic_event_t *)info; + + switch (hn->hne_event) + { + case NE_PLUMB : + frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, hn->hne_data); + fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, + hn->hne_data); + break; + + case NE_UNPLUMB : + frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL); + fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL); + break; + + case NE_ADDRESS_CHANGE : + break; + default : + break; + } + + return 0; } diff --git a/usr/src/uts/common/inet/ipf/ip_log.c b/usr/src/uts/common/inet/ipf/ip_log.c index 364b2e08e5..380bf597ba 100644 --- a/usr/src/uts/common/inet/ipf/ip_log.c +++ b/usr/src/uts/common/inet/ipf/ip_log.c @@ -254,15 +254,16 @@ u_int flags; ipflog_t ipfl; u_char p; mb_t *m; -# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) -# ifndef IRE_ILL_CN +# if SOLARIS && defined(_KERNEL) + net_data_t nif; + void *ifp; +# else +# if defined(__hpux) && defined(_KERNEL) qif_t *ifp; # else - s_ill_t *ifp; -# endif /* IRE_ILL_CN */ -# else struct ifnet *ifp; -# endif /* SOLARIS || __hpux */ +# endif +# endif /* SOLARIS */ ipfl.fl_nattag.ipt_num[0] = 0; m = fin->fin_m; @@ -328,27 +329,42 @@ u_int flags; * Get the interface number and name to which this packet is * currently associated. */ -# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) +# if SOLARIS && defined(_KERNEL) ipfl.fl_unit = (u_int)0; - (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); + nif = NULL; + if (fin->fin_fi.fi_v == 4) + nif = ipf_ipv4; + else if (fin->fin_fi.fi_v == 6) + nif = ipf_ipv6; + if (nif != NULL) { + if (net_getifname(nif, (phy_if_t)ifp, + ipfl.fl_ifname, sizeof(ipfl.fl_ifname)) != 0) + return (-1); + } + # else -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ - (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) - COPYIFNAME(ifp, ipfl.fl_ifname); +# if defined(__hpux) && defined(_KERNEL) + ipfl.fl_unit = (u_int)0; + (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); # else +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + COPYIFNAME(ifp, ipfl.fl_ifname); +# else ipfl.fl_unit = (u_int)ifp->if_unit; -# if defined(_KERNEL) +# if defined(_KERNEL) if ((ipfl.fl_ifname[0] = ifp->if_name[0])) if ((ipfl.fl_ifname[1] = ifp->if_name[1])) if ((ipfl.fl_ifname[2] = ifp->if_name[2])) ipfl.fl_ifname[3] = ifp->if_name[3]; -# else +# else (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname)); ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0'; +# endif # endif -# endif -# endif /* __hpux || SOLARIS */ +# endif /* __hpux */ +# endif /* SOLARIS */ mlen = fin->fin_plen - hlen; if (!ipl_logall) { mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; @@ -617,26 +633,30 @@ struct uio *uio; */ iplt[unit] = ipl->ipl_next; iplused[unit] -= dlen; + if (iplt[unit] == NULL) { + iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; + } MUTEX_EXIT(&ipl_mutex); SPL_X(s); error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); if (error) { SPL_NET(s); MUTEX_ENTER(&ipl_mutex); + iplused[unit] += dlen; ipl->ipl_next = iplt[unit]; iplt[unit] = ipl; - iplused[unit] += dlen; + ipll[unit] = ipl; + if (iplh[unit] == &iplt[unit]) { + *iplh[unit] = ipl; + iplh[unit] = &ipl->ipl_next; + } break; } MUTEX_ENTER(&ipl_mutex); KFREES((caddr_t)ipl, dlen); SPL_NET(s); } - if (!iplt[unit]) { - iplused[unit] = 0; - iplh[unit] = &iplt[unit]; - ipll[unit] = NULL; - } MUTEX_EXIT(&ipl_mutex); SPL_X(s); diff --git a/usr/src/uts/common/inet/ipf/ip_nat.c b/usr/src/uts/common/inet/ipf/ip_nat.c index ceaa980158..a4e2cecf31 100644 --- a/usr/src/uts/common/inet/ipf/ip_nat.c +++ b/usr/src/uts/common/inet/ipf/ip_nat.c @@ -171,9 +171,6 @@ u_long fr_defnatage = DEF_NAT_AGE, natstat_t nat_stats; int fr_nat_lock = 0; int fr_nat_init = 0; -#if SOLARIS -extern int pfil_delayed_copy; -#endif static int nat_flushtable __P((void)); static int nat_clearlist __P((void)); @@ -199,7 +196,7 @@ static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, tcphdr_t *, nat_t **, int)); static void nat_resolverule __P((ipnat_t *)); static nat_t *fr_natclone __P((fr_info_t *, nat_t *)); -static void nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *)); +static void nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *)); static INLINE int nat_wildok __P((nat_t *, int, int, int, int)); @@ -497,14 +494,12 @@ struct hostmap *hm; /* ------------------------------------------------------------------------ */ /* Function: fix_outcksum */ /* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* sp(I) - location of 16bit checksum to update */ +/* Parameters: sp(I) - location of 16bit checksum to update */ /* n((I) - amount to adjust checksum by */ /* */ /* Adjusts the 16bit checksum by "n" for packets going out. */ /* ------------------------------------------------------------------------ */ -void fix_outcksum(fin, sp, n) -fr_info_t *fin; +void fix_outcksum(sp, n) u_short *sp; u_32_t n; { @@ -514,13 +509,6 @@ u_32_t n; if (n == 0) return; - if (n & NAT_HW_CKSUM) { - n &= 0xffff; - n += fin->fin_dlen; - n = (n & 0xffff) + (n >> 16); - *sp = n & 0xffff; - return; - } sum1 = (~ntohs(*sp)) & 0xffff; sum1 += (n); sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -534,14 +522,12 @@ u_32_t n; /* ------------------------------------------------------------------------ */ /* Function: fix_incksum */ /* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* sp(I) - location of 16bit checksum to update */ +/* Parameters: sp(I) - location of 16bit checksum to update */ /* n((I) - amount to adjust checksum by */ /* */ /* Adjusts the 16bit checksum by "n" for packets going in. */ /* ------------------------------------------------------------------------ */ -void fix_incksum(fin, sp, n) -fr_info_t *fin; +void fix_incksum(sp, n) u_short *sp; u_32_t n; { @@ -551,13 +537,6 @@ u_32_t n; if (n == 0) return; - if (n & NAT_HW_CKSUM) { - n &= 0xffff; - n += fin->fin_dlen; - n = (n & 0xffff) + (n >> 16); - *sp = n & 0xffff; - return; - } sum1 = (~ntohs(*sp)) & 0xffff; sum1 += ~(n) & 0xffff; sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -980,9 +959,6 @@ int getlock; } n = NULL; nat_stats.ns_rules++; -#if SOLARIS - pfil_delayed_copy = 0; -#endif if (getlock) { RWLOCK_EXIT(&ipf_nat); /* WRITE */ } @@ -1067,10 +1043,6 @@ int getlock; appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; -#if SOLARIS - if (nat_stats.ns_rules == 0) - pfil_delayed_copy = 1; -#endif } else { n->in_flags |= IPN_DELETE; n->in_next = NULL; @@ -1602,10 +1574,6 @@ int logtype; appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; -#if SOLARIS - if (nat_stats.ns_rules == 0) - pfil_delayed_copy = 1; -#endif } } @@ -1695,9 +1663,6 @@ static int nat_clearlist() } i++; } -#if SOLARIS - pfil_delayed_copy = 1; -#endif nat_masks = 0; rdr_masks = 0; return i; @@ -2147,9 +2112,6 @@ int direction; natinfo_t ni; u_32_t sumd; int move; -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) - qpktinfo_t *qpi = fin->fin_qpi; -#endif if (nat_stats.ns_inuse >= ipf_nattable_max) { nat_stats.ns_memfail++; @@ -2272,23 +2234,24 @@ int direction; dport = 0; } + /* + * nat_sumd[0] stores adjustment value including both IP address and + * port number changes. nat_sumd[1] stores adjustment value only for + * IP address changes, to be used for pseudo header adjustment, in + * case hardware partial checksum offload is offered. + */ CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) - if ((flags & IPN_TCP) && dohwcksum && -#ifndef IRE_ILL_CN - (((ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { -#else - (((s_ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { -#endif /* IRE_ILL_CN */ +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if (flags & IPN_TCPUDP) { + ni.nai_sum1 = LONG_SUM(in.s_addr); if (direction == NAT_OUTBOUND) - ni.nai_sum1 = LONG_SUM(in.s_addr); + ni.nai_sum2 = LONG_SUM(ntohl(fin->fin_saddr)); else - ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr)); - ni.nai_sum1 += LONG_SUM(ntohl(fin->fin_daddr)); - ni.nai_sum1 += 30; - ni.nai_sum1 = (ni.nai_sum1 & 0xffff) + (ni.nai_sum1 >> 16); - nat->nat_sumd[1] = NAT_HW_CKSUM|(ni.nai_sum1 & 0xffff); + ni.nai_sum2 = LONG_SUM(ntohl(fin->fin_daddr)); + + CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd); + nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16); } else #endif nat->nat_sumd[1] = nat->nat_sumd[0]; @@ -2357,12 +2320,8 @@ int direction; np = ni->nai_np; - if (np->in_ifps[0] != NULL) { - (void) COPYIFNAME(np->in_ifps[0], nat->nat_ifnames[0]); - } - if (np->in_ifps[1] != NULL) { - (void) COPYIFNAME(np->in_ifps[1], nat->nat_ifnames[1]); - } + COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v); + #ifdef IPFILTER_SYNC if ((nat->nat_flags & SI_CLONE) == 0) nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); @@ -2880,7 +2839,7 @@ int dir; if (sumd2 != 0) { sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); - fix_incksum(fin, &icmp->icmp_cksum, sumd2); + fix_incksum(&icmp->icmp_cksum, sumd2); } return nat; } @@ -3674,10 +3633,19 @@ u_32_t nflags; { icmphdr_t *icmp; u_short *csump; + u_32_t sumd; tcphdr_t *tcp; ipnat_t *np; int i; +#if SOLARIS && defined(_KERNEL) + net_data_t net_data_p; + if (fin->fin_v == 4) + net_data_p = ipf_ipv4; + else + net_data_p = ipf_ipv6; +#endif + tcp = NULL; icmp = NULL; csump = NULL; @@ -3690,7 +3658,7 @@ u_32_t nflags; nat->nat_bytes[1] += fin->fin_plen; nat->nat_pkts[1]++; MUTEX_EXIT(&nat->nat_lock); - + /* * Fix up checksums, not by recalculating them, but * simply computing adjustments. @@ -3699,14 +3667,16 @@ u_32_t nflags; * IPFilter is called before the checksum needs calculating so there * is no call to modify whatever is in the header now. */ - if (fin->fin_v == 4) { + ASSERT(fin->fin_m != NULL); + if (fin->fin_v == 4 && !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m)) { if (nflags == IPN_ICMPERR) { - u_32_t s1, s2, sumd; + u_32_t s1, s2; s1 = LONG_SUM(ntohl(fin->fin_saddr)); s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); CALC_SUMD(s1, s2, sumd); - fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd); + + fix_outcksum(&fin->fin_ip->ip_sum, sumd); } #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ defined(linux) || defined(BRIDGE_IPF) @@ -3718,11 +3688,11 @@ u_32_t nflags; * to do NAT as a bridge, that code doesn't exist. */ if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, &fin->fin_ip->ip_sum, - nat->nat_ipsumd); - else - fix_incksum(fin, &fin->fin_ip->ip_sum, + fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); + else + fix_incksum(&fin->fin_ip->ip_sum, + nat->nat_ipsumd); } #endif } @@ -3750,11 +3720,17 @@ u_32_t nflags; /* * The above comments do not hold for layer 4 (or higher) checksums... */ - if (csump != NULL) { + if (csump != NULL && !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m)) { + if (nflags & IPN_TCPUDP && + NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) + sumd = nat->nat_sumd[1]; + else + sumd = nat->nat_sumd[0]; + if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(fin, csump, nat->nat_sumd[1]); + fix_outcksum(csump, sumd); else - fix_incksum(fin, csump, nat->nat_sumd[1]); + fix_incksum(csump, sumd); } #ifdef IPFILTER_SYNC ipfsync_update(SMC_NAT, fin, nat->nat_sync); @@ -3968,11 +3944,20 @@ int natadd; u_32_t nflags; { icmphdr_t *icmp; - u_short *csump; + u_short *csump, *csump1; + u_32_t sumd; tcphdr_t *tcp; ipnat_t *np; int i; +#if SOLARIS && defined(_KERNEL) + net_data_t net_data_p; + if (fin->fin_v == 4) + net_data_p = ipf_ipv4; + else + net_data_p = ipf_ipv6; +#endif + tcp = NULL; csump = NULL; np = nat->nat_ptr; @@ -4027,9 +4012,9 @@ u_32_t nflags; #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ defined(__osf__) || defined(linux) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); + fix_incksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); + fix_outcksum(&fin->fin_ip->ip_sum, nat->nat_ipsumd); #endif if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { @@ -4050,14 +4035,30 @@ u_32_t nflags; nat_update(fin, nat, np); +#if SOLARIS && defined(_KERNEL) + if (nflags & IPN_TCPUDP && + NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { + sumd = nat->nat_sumd[1]; + csump1 = &(fin->fin_m->b_datap->db_struioun.cksum.cksum_val.u16); + if (csump1 != NULL) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(csump1, sumd); + else + fix_outcksum(csump1, sumd); + } + } else +#endif + sumd = nat->nat_sumd[0]; + /* - * The above comments do not hold for layer 4 (or higher) checksums... + * Inbound packets always need to have their address adjusted in case + * code following this validates it. */ if (csump != NULL) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(fin, csump, nat->nat_sumd[0]); + fix_incksum(csump, sumd); else - fix_outcksum(fin, csump, nat->nat_sumd[0]); + fix_outcksum(csump, sumd); } ATOMIC_INCL(nat_stats.ns_mapped[0]); fin->fin_flx |= FI_NATED; @@ -4110,7 +4111,7 @@ u_int nflags; * only deal IPv4 for now. */ if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0) - nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump); + nat_mssclamp(tcp, nat->nat_mssclamp, csump); break; @@ -4265,32 +4266,28 @@ void fr_natexpire() /* ------------------------------------------------------------------------ */ -/* Function: fr_natsync */ +/* Function: fr_nataddrsync */ /* Returns: Nil */ -/* Parameters: ifp(I) - pointer to network interface */ +/* Parameters: ifp(I) - pointer to network interface */ +/* addr(I) - pointer to new network address */ /* */ /* Walk through all of the currently active NAT sessions, looking for those */ -/* which need to have their translated address updated. */ +/* which need to have their translated address updated (where the interface */ +/* matches the one passed in) and change it, recalculating the checksum sum */ +/* difference too. */ /* ------------------------------------------------------------------------ */ -void fr_natsync(ifp) +void fr_nataddrsync(ifp, addr) void *ifp; +struct in_addr *addr; { u_32_t sum1, sum2, sumd; - struct in_addr in; - ipnat_t *n; nat_t *nat; - void *ifp2; + ipnat_t *np; SPL_INT(s); if (fr_running <= 0) return; - /* - * Change IP addresses for NAT sessions for any protocol except TCP - * since it will break the TCP connection anyway. The only rules - * which will get changed are those which are "map ... -> 0/32", - * where the rule specifies the address is taken from the interface. - */ SPL_NET(s); WRITE_ENTER(&ipf_nat); @@ -4299,23 +4296,19 @@ void *ifp; return; } + /* + * Change IP addresses for NAT sessions for any protocol except TCP + * since it will break the TCP connection anyway. The only rules + * which will get changed are those which are "map ... -> 0/32", + * where the rule specifies the address is taken from the interface. + */ for (nat = nat_instances; nat; nat = nat->nat_next) { - if ((nat->nat_flags & IPN_TCP) != 0) - continue; - n = nat->nat_ptr; - if ((n == NULL) || - (n->in_outip != 0) || (n->in_outmsk != 0xffffffff)) - continue; - if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || - (ifp == nat->nat_ifps[1]))) { - nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); - if (nat->nat_ifnames[1][0] != '\0') { - nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], - 4); - } else - nat->nat_ifps[1] = nat->nat_ifps[0]; - ifp2 = nat->nat_ifps[0]; - if (ifp2 == NULL) + if (addr != NULL) { + if (((ifp != NULL) && ifp != (nat->nat_ifps[0])) || + ((nat->nat_flags & IPN_TCP) != 0)) + continue; + if (((np = nat->nat_ptr) == NULL) || + (np->in_nip || (np->in_outmsk != 0xffffffff))) continue; /* @@ -4323,31 +4316,145 @@ void *ifp; * new one. */ sum1 = nat->nat_outip.s_addr; - if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1) - nat->nat_outip = in; + nat->nat_outip = *addr; sum2 = nat->nat_outip.s_addr; - if (sum1 == sum2) - continue; + } else if (((ifp == NULL) || (ifp == nat->nat_ifps[0])) && + !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && + (np->in_outmsk == 0xffffffff) && !np->in_nip) { + struct in_addr in; + /* - * Readjust the checksum adjustment to take into - * account the new IP#. - */ - CALC_SUMD(sum1, sum2, sumd); - /* XXX - dont change for TCP when solaris does - * hardware checksumming. + * Change the map-to address to be the same as the + * new one. */ - sumd += nat->nat_sumd[0]; - nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); - nat->nat_sumd[1] = nat->nat_sumd[0]; + sum1 = nat->nat_outip.s_addr; + if (fr_ifpaddr(4, FRI_NORMAL, nat->nat_ifps[0], + &in, NULL) != -1) + nat->nat_outip = in; + sum2 = nat->nat_outip.s_addr; + } else { + continue; } + + if (sum1 == sum2) + continue; + /* + * Readjust the checksum adjustment to take into + * account the new IP#. + */ + CALC_SUMD(sum1, sum2, sumd); + /* XXX - dont change for TCP when solaris does + * hardware checksumming. + */ + sumd += nat->nat_sumd[0]; + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; } - for (n = nat_list; (n != NULL); n = n->in_next) { - if ((ifp == NULL) || (n->in_ifps[0] == ifp)) - n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); - if ((ifp == NULL) || (n->in_ifps[1] == ifp)) - n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4); + RWLOCK_EXIT(&ipf_nat); + SPL_X(s); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_natifpsync */ +/* Returns: Nil */ +/* Parameters: action(I) - how we are syncing */ +/* ifp(I) - pointer to network interface */ +/* name(I) - name of interface to sync to */ +/* */ +/* This function is used to resync the mapping of interface names and their */ +/* respective 'pointers'. For "action == IPFSYNC_RESYNC", resync all */ +/* interfaces by doing a new lookup of name to 'pointer'. For "action == */ +/* IPFSYNC_NEWIFP", treat ifp as the new pointer value associated with */ +/* "name" and for "action == IPFSYNC_OLDIFP", ifp is a pointer for which */ +/* there is no longer any interface associated with it. */ +/* ------------------------------------------------------------------------ */ +void fr_natifpsync(action, ifp, name) +int action; +void *ifp; +char *name; +{ +#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) + int s; +#endif + nat_t *nat; + ipnat_t *n; + + if (fr_running <= 0) + return; + + SPL_NET(s); + WRITE_ENTER(&ipf_nat); + + if (fr_running <= 0) { + RWLOCK_EXIT(&ipf_nat); + return; + } + + switch (action) + { + case IPFSYNC_RESYNC : + for (nat = nat_instances; nat; nat = nat->nat_next) { + if ((ifp == nat->nat_ifps[0]) || + (nat->nat_ifps[0] == (void *)-1)) { + nat->nat_ifps[0] = + fr_resolvenic(nat->nat_ifnames[0], 4); + } + + if ((ifp == nat->nat_ifps[1]) || + (nat->nat_ifps[1] == (void *)-1)) { + nat->nat_ifps[1] = + fr_resolvenic(nat->nat_ifnames[1], 4); + } + } + + for (n = nat_list; (n != NULL); n = n->in_next) { + if (n->in_ifps[0] == ifp || + n->in_ifps[0] == (void *)-1) { + n->in_ifps[0] = + fr_resolvenic(n->in_ifnames[0], 4); + } + if (n->in_ifps[1] == ifp || + n->in_ifps[1] == (void *)-1) { + n->in_ifps[1] = + fr_resolvenic(n->in_ifnames[1], 4); + } + } + break; + case IPFSYNC_NEWIFP : + for (nat = nat_instances; nat; nat = nat->nat_next) { + if (!strncmp(name, nat->nat_ifnames[0], + sizeof(nat->nat_ifnames[0]))) + nat->nat_ifps[0] = ifp; + if (!strncmp(name, nat->nat_ifnames[1], + sizeof(nat->nat_ifnames[1]))) + nat->nat_ifps[1] = ifp; + } + for (n = nat_list; (n != NULL); n = n->in_next) { + if (!strncmp(name, n->in_ifnames[0], + sizeof(n->in_ifnames[0]))) + n->in_ifps[0] = ifp; + if (!strncmp(name, n->in_ifnames[1], + sizeof(n->in_ifnames[1]))) + n->in_ifps[1] = ifp; + } + break; + case IPFSYNC_OLDIFP : + for (nat = nat_instances; nat; nat = nat->nat_next) { + if (ifp == nat->nat_ifps[0]) + nat->nat_ifps[0] = (void *)-1; + if (ifp == nat->nat_ifps[1]) + nat->nat_ifps[1] = (void *)-1; + } + for (n = nat_list; (n != NULL); n = n->in_next) { + if (n->in_ifps[0] == ifp) + n->in_ifps[0] = (void *)-1; + if (n->in_ifps[1] == ifp) + n->in_ifps[1] = (void *)-1; + } + break; } RWLOCK_EXIT(&ipf_nat); SPL_X(s); @@ -4638,17 +4745,15 @@ int dir; /* Returns: Nil */ /* Parameters: tcp(I) - pointer to TCP header */ /* maxmss(I) - value to clamp the TCP MSS to */ -/* fin(I) - pointer to packet information */ /* csump(I) - pointer to TCP checksum */ /* */ /* Check for MSS option and clamp it if necessary. If found and changed, */ /* then the TCP header checksum will be updated to reflect the change in */ /* the MSS. */ /* ------------------------------------------------------------------------ */ -static void nat_mssclamp(tcp, maxmss, fin, csump) +static void nat_mssclamp(tcp, maxmss, csump) tcphdr_t *tcp; u_32_t maxmss; -fr_info_t *fin; u_short *csump; { u_char *cp, *ep, opt; @@ -4684,7 +4789,7 @@ u_short *csump; cp[2] = maxmss / 256; cp[3] = maxmss & 0xff; CALC_SUMD(mss, maxmss, sumd); - fix_outcksum(fin, csump, sumd); + fix_outcksum(csump, sumd); } break; default: diff --git a/usr/src/uts/common/inet/ipf/ip_proxy.c b/usr/src/uts/common/inet/ipf/ip_proxy.c index 99f8a14b88..d48e83ff74 100644 --- a/usr/src/uts/common/inet/ipf/ip_proxy.c +++ b/usr/src/uts/common/inet/ipf/ip_proxy.c @@ -462,10 +462,8 @@ int appr_check(fin, nat) fr_info_t *fin; nat_t *nat; { -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) -# if defined(ICK_VALID) +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) mb_t *m; -# endif int dosum = 1; #endif tcphdr_t *tcp = NULL; @@ -478,6 +476,13 @@ nat_t *nat; #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) u_32_t s1, s2, sd; #endif +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + net_data_t net_data_p; + if (fin->fin_v == 4) + net_data_p = ipf_ipv4; + else + net_data_p = ipf_ipv6; +#endif if (fin->fin_flx & FI_BAD) { if (ipf_proxy_debug > 0) @@ -564,15 +569,17 @@ nat_t *nat; * If err != 0 then the data size of the packet has changed * so we need to recalculate the header checksums for the * packet. + * inbound packets always need to be adjusted. */ #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) - if (err != 0) { + if (err != 0 && (!fin->fin_out || + !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m))) { short adjlen = err & 0xffff; s1 = LONG_SUM(ip->ip_len - adjlen); s2 = LONG_SUM(ip->ip_len); CALC_SUMD(s1, s2, sd); - fix_outcksum(fin, &ip->ip_sum, sd); + fix_outcksum(&ip->ip_sum, sd); } #endif @@ -588,7 +595,9 @@ nat_t *nat; if (tcp != NULL) { err = appr_fixseqack(fin, ip, aps, APR_INC(err)); #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if (dosum) + if (!fin->fin_out || + !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m) && + !NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) tcp->th_sum = fr_cksum(fin->fin_qfm, ip, IPPROTO_TCP, tcp); #else @@ -597,7 +606,9 @@ nat_t *nat; #endif } else if ((udp != NULL) && (udp->uh_sum != 0)) { #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if (dosum) + if (!fin->fin_out || + !NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m) && + !NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) udp->uh_sum = fr_cksum(fin->fin_qfm, ip, IPPROTO_UDP, udp); #else diff --git a/usr/src/uts/common/inet/ipf/ip_state.c b/usr/src/uts/common/inet/ipf/ip_state.c index ec63d80736..83cd7ebbc8 100644 --- a/usr/src/uts/common/inet/ipf/ip_state.c +++ b/usr/src/uts/common/inet/ipf/ip_state.c @@ -1092,15 +1092,15 @@ u_int flags; if (((ifp = fr->fr_ifas[1]) != NULL) && (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1]); + COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1], fr->fr_v); } if (((ifp = fr->fr_ifas[2]) != NULL) && (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1]); + COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1], fr->fr_v); } if (((ifp = fr->fr_ifas[3]) != NULL) && (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1]); + COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1], fr->fr_v); } } else { pass = fr_flags; @@ -1109,7 +1109,7 @@ u_int flags; is->is_ifp[out << 1] = fin->fin_ifp; if (fin->fin_ifp != NULL) { - COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); + COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1], fr->fr_v); } /* @@ -1864,7 +1864,7 @@ u_32_t cmask; if (is->is_ifp[idx] == NULL && (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) { is->is_ifp[idx] = ifp; - COPYIFNAME(ifp, is->is_ifname[idx]); + COPYIFNAME(ifp, is->is_ifname[idx], fin->fin_v); } fin->fin_rev = rev; return is; @@ -2610,7 +2610,7 @@ ipstate_t *is; seq = ntohl(tcp->th_seq); seq += is->is_isninc[0]; tcp->th_seq = htonl(seq); - fix_outcksum(fin, &tcp->th_sum, is->is_sumd[0]); + fix_outcksum(&tcp->th_sum, is->is_sumd[0]); } } if ((is->is_flags & IS_ISNACK) != 0) { @@ -2618,7 +2618,7 @@ ipstate_t *is; seq = ntohl(tcp->th_seq); seq += is->is_isninc[1]; tcp->th_seq = htonl(seq); - fix_outcksum(fin, &tcp->th_sum, is->is_sumd[1]); + fix_outcksum(&tcp->th_sum, is->is_sumd[1]); } } } @@ -2648,7 +2648,7 @@ ipstate_t *is; ack = ntohl(tcp->th_ack); ack -= is->is_isninc[0]; tcp->th_ack = htonl(ack); - fix_incksum(fin, &tcp->th_sum, is->is_sumd[0]); + fix_incksum(&tcp->th_sum, is->is_sumd[0]); } } if ((is->is_flags & IS_ISNACK) != 0) { @@ -2656,7 +2656,7 @@ ipstate_t *is; ack = ntohl(tcp->th_ack); ack -= is->is_isninc[1]; tcp->th_ack = htonl(ack); - fix_incksum(fin, &tcp->th_sum, is->is_sumd[1]); + fix_incksum(&tcp->th_sum, is->is_sumd[1]); } } } @@ -2665,7 +2665,10 @@ ipstate_t *is; /* ------------------------------------------------------------------------ */ /* Function: fr_statesync */ /* Returns: Nil */ -/* Parameters: ifp(I) - pointer to interface */ +/* Parameters: action(I) - type of synchronisation to do */ +/* v(I) - IP version being sync'd (v4 or v6) */ +/* ifp(I) - interface identifier associated with action */ +/* name(I) - name associated with ifp parameter */ /* */ /* Walk through all state entries and if an interface pointer match is */ /* found then look it up again, based on its name in case the pointer has */ @@ -2674,8 +2677,10 @@ ipstate_t *is; /* If ifp is passed in as being non-null then we are only doing updates for */ /* existing, matching, uses of it. */ /* ------------------------------------------------------------------------ */ -void fr_statesync(ifp) +void fr_statesync(action, v, ifp, name) +int action, v; void *ifp; +char *name; { ipstate_t *is; int i; @@ -2690,15 +2695,48 @@ void *ifp; return; } - for (is = ips_list; is; is = is->is_next) { - /* - * Look up all the interface names in the state entry. - */ - for (i = 0; i < 4; i++) { - if (ifp == NULL || ifp == is->is_ifp[i]) + switch (action) + { + case IPFSYNC_RESYNC : + for (is = ips_list; is; is = is->is_next) { + if (v != 0 && is->is_v != v) + continue; + /* + * Look up all the interface names in the state entry. + */ + for (i = 0; i < 4; i++) { is->is_ifp[i] = fr_resolvenic(is->is_ifname[i], is->is_v); + } } + break; + case IPFSYNC_NEWIFP : + for (is = ips_list; is; is = is->is_next) { + if (v != 0 && is->is_v != v) + continue; + /* + * Look up all the interface names in the state entry. + */ + for (i = 0; i < 4; i++) { + if (!strncmp(is->is_ifname[i], name, + sizeof(is->is_ifname[i]))) + is->is_ifp[i] = ifp; + } + } + break; + case IPFSYNC_OLDIFP : + for (is = ips_list; is; is = is->is_next) { + if (v != 0 && is->is_v != v) + continue; + /* + * Look up all the interface names in the state entry. + */ + for (i = 0; i < 4; i++) { + if (is->is_ifp[i] == ifp) + is->is_ifp[i] = (void *)-1; + } + } + break; } RWLOCK_EXIT(&ipf_state); } diff --git a/usr/src/uts/common/inet/pfil/misc.c b/usr/src/uts/common/inet/ipf/misc.c index 2a8c84dd4c..a49a0ca5c5 100644 --- a/usr/src/uts/common/inet/pfil/misc.c +++ b/usr/src/uts/common/inet/ipf/misc.c @@ -3,17 +3,22 @@ * * See the IPFILTER.LICENCE file for details on licencing. */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ #ifndef __hpux #pragma ident "@(#)$Id: misc.c,v 1.12 2003/11/29 07:11:03 darrenr Exp $" #else struct uio; #endif +#pragma ident "%Z%%M% %I% %E% SMI" + #include <sys/systm.h> #include <sys/types.h> #include <sys/stream.h> - -#include "compat.h" +#include <sys/ddi.h> #ifdef __hpux # define BCOPY(a,b,c) bcopy((caddr_t)a, (caddr_t)b, c) @@ -32,11 +37,11 @@ char *buf; mblk_t *m; for (m = min; (m != NULL) && (len > 0); m = m->b_cont) { - if (MTYPE(m) != M_DATA) + if (m->b_datap->db_type != M_DATA) continue; s = m->b_rptr; mlen = m->b_wptr - s; - olen = MIN(off, mlen); + olen = min(off, mlen); if ((olen == mlen) || (olen < off)) { off -= olen; continue; @@ -45,7 +50,7 @@ char *buf; s += olen; mlen -= olen; } - clen = MIN(mlen, len); + clen = min(mlen, len); BCOPY(s, bp, clen); len -= clen; bp += clen; @@ -64,12 +69,12 @@ char *buf; for (m = min, mp = NULL; (m != NULL) && (len > 0); m = m->b_cont) { mp = m; - if (MTYPE(m) != M_DATA) + if (m->b_datap->db_type != M_DATA) continue; s = m->b_rptr; mlen = m->b_wptr - s; - olen = MIN(off, mlen); + olen = min(off, mlen); if ((olen == mlen) || (olen < off)) { off -= olen; continue; @@ -78,7 +83,7 @@ char *buf; s += olen; mlen -= olen; } - clen = MIN(mlen, len); + clen = min(mlen, len); BCOPY(bp, s, clen); len -= clen; bp += clen; @@ -90,7 +95,7 @@ char *buf; if (mlen > 0) { if (mlen > len) mlen = len; - bcopy((char *)bp, (char *)mp->b_wptr, mlen); + BCOPY(bp, mp->b_wptr, mlen); bp += mlen; len -= mlen; mp->b_wptr += mlen; @@ -106,7 +111,7 @@ char *buf; if (len > 0) { m = allocb(len, BPRI_MED); if (m != NULL) { - bcopy((char *)bp, (char *)m->b_wptr, len); + BCOPY(bp, m->b_wptr, len); m->b_band = mp->b_band; m->b_wptr += len; linkb(mp, m); diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_compat.h b/usr/src/uts/common/inet/ipf/netinet/ip_compat.h index bf6b8f67b0..365e3b010e 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_compat.h +++ b/usr/src/uts/common/inet/ipf/netinet/ip_compat.h @@ -202,6 +202,28 @@ struct ip6_ext { }; # endif /* SOLARIS2 >= 8 */ +# ifdef FW_HOOKS + +# define SOLARIS_PFHOOKS 1 + +typedef struct qpktinfo { + /* data that changes per-packet */ + void *qpi_ill; /* COPIED */ + mblk_t *qpi_m; + void *qpi_data; /* where layer 3 header starts */ + size_t qpi_off; + int qpi_flags; +} qpktinfo_t; + +#define QPI_NOCKSUM 0x01 + +extern net_data_t ipf_ipv4; +extern net_data_t ipf_ipv6; + +extern void mb_copydata __P((mblk_t *, size_t , size_t, char *)); +extern void mb_copyback __P((mblk_t *, size_t , size_t, char *)); +# endif + # if SOLARIS2 >= 6 # include <sys/atomic.h> typedef uint32_t u_32_t; @@ -213,8 +235,6 @@ typedef unsigned int u_32_t; # ifdef _KERNEL # define KRWLOCK_T krwlock_t # define KMUTEX_T kmutex_t -# include "qif.h" -# include "pfil.h" # if SOLARIS2 >= 6 # if SOLARIS2 == 6 # define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) @@ -269,16 +289,12 @@ typedef unsigned int u_32_t; # define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) # define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) # define GET_MINOR(x) getminor(x) -extern void *get_unit __P((char *, int)); -# define GETIFP(n, v) get_unit(n, v) -# define IFNAME(x) ((qif_t *)x)->qf_name -# define COPYIFNAME(x, b) \ - (void) strncpy(b, ((qif_t *)x)->qf_name, \ - LIFNAMSIZ) -#ifdef IRE_ILL_CN -extern kmutex_t s_ill_g_head_lock; -extern struct s_ill_s *s_ill_g_head; /* ILL List Head */ -#endif /* IRE_ILL_CN */ +extern phy_if_t get_unit __P((char *, int)); +# define GETIFP(n, v) (void *)get_unit(n, v) +# define IFNAME(x) ((ill_t *)x)->ill_name +# define COPYIFNAME(x, b, v) (void) net_getifname(((v) == 4) ? \ + ipf_ipv4 : ipf_ipv6, \ + (phy_if_t)(x), (b), sizeof(b)) # define GETKTIME(x) uniqtime((struct timeval *)x) # define MSGDSIZE(x) msgdsize(x) # define M_LEN(x) ((x)->b_wptr - (x)->b_rptr) @@ -287,7 +303,7 @@ extern struct s_ill_s *s_ill_g_head; /* ILL List Head */ # define MTYPE(m) ((m)->b_datap->db_type) # define FREE_MB_T(m) freemsg(m) # define m_next b_cont -# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) +# define CACHE_HASH(x) (((phy_if_t)(x)->fin_ifp) & 7) # define IPF_PANIC(x,y) if (x) { printf y; cmn_err(CE_PANIC, "ipf_panic"); } typedef mblk_t mb_t; # endif /* _KERNEL */ @@ -446,9 +462,9 @@ typedef struct iplog_select_s { extern void *get_unit __P((char *, int)); # define GETIFP(n, v) get_unit(n, v) # define IFNAME(x, b) ((ill_t *)x)->ill_name -# define COPYIFNAME(x, b) \ - (void) strncpy(b, ((qif_t *)x)->qf_name, \ - LIFNAMSIZ) +# define COPYIFNAME(x, b, v) \ + strncpy(b, ((ifinfo_t *)x)->ifi_name, \ + LIFNAMSIZ) # define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) # define SLEEP(id, n) { lock_t *_l = get_sleep_lock((caddr_t)id); \ sleep(id, PZERO+1); \ @@ -472,7 +488,7 @@ extern void *get_unit __P((char *, int)); # define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } typedef mblk_t mb_t; -# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7) +# define CACHE_HASH(x) (((phy_if_t)(x)->fin_ifp) & 7) # include "qif.h" # include "pfil.h" @@ -759,7 +775,7 @@ typedef struct mbuf mb_t; # endif /* _KERNEL */ # if (NetBSD <= 1991011) && (NetBSD >= 199606) # define IFNAME(x) ((struct ifnet *)x)->if_xname -# define COPYIFNAME(x, b) \ +# define COPYIFNAME(x, b, v) \ (void) strncpy(b, \ ((struct ifnet *)x)->if_xname, \ LIFNAMSIZ) @@ -980,7 +996,7 @@ typedef struct mbuf mb_t; # endif /* _KERNEL */ # if (OpenBSD >= 199603) # define IFNAME(x, b) ((struct ifnet *)x)->if_xname -# define COPYIFNAME(x, b) \ +# define COPYIFNAME(x, b, v) \ (void) strncpy(b, \ ((struct ifnet *)x)->if_xname, \ LIFNAMSIZ) @@ -1500,6 +1516,15 @@ extern void eMrwlock_read_enter __P((eMrwlock_t *, char *, int)); extern void eMrwlock_write_enter __P((eMrwlock_t *, char *, int)); extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int)); +#undef NET_IS_HCK_L3_FULL +#define NET_IS_HCK_L3_FULL(n, x) (0) +#undef NET_IS_HCK_L3_PART +#define NET_IS_HCK_L3_PART(n, x) (0) +#undef NET_IS_HCK_L4_FULL +#define NET_IS_HCK_L4_FULL(n, x) (0) +#undef NET_IS_HCK_L4_PART +#define NET_IS_HCK_L4_PART(n, x) (0) + #endif #define MAX_IPV4HDR ((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8) @@ -1638,7 +1663,7 @@ MALLOC_DECLARE(M_IPFILTER); #ifndef COPYIFNAME # define NEED_FRGETIFNAME extern char *fr_getifname __P((struct ifnet *, char *)); -# define COPYIFNAME(x, b) \ +# define COPYIFNAME(x, b, v) \ fr_getifname((struct ifnet *)x, b) #endif diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h index e7ec154f4f..7fc1712dd0 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h +++ b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h @@ -61,6 +61,7 @@ # define SIOCIPFGET _IOWR('r', 88, struct ipfobj) # define SIOCIPFSET _IOWR('r', 89, struct ipfobj) # define SIOCIPFL6 _IOWR('r', 90, int) +# define SIOCIPFLP _IOWR('r', 91, int) #else # define SIOCADAFR _IOW(r, 60, struct ipfobj) # define SIOCRMAFR _IOW(r, 61, struct ipfobj) @@ -93,6 +94,7 @@ # define SIOCIPFGET _IOWR(r, 88, struct ipfobj) # define SIOCIPFSET _IOWR(r, 89, struct ipfobj) # define SIOCIPFL6 _IOWR(r, 90, int) +# define SIOCIPFLP _IOWR(r, 91, int) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR @@ -1147,6 +1149,14 @@ typedef struct ipftune { /* + * sync commands + */ +#define IPFSYNC_RESYNC 0 +#define IPFSYNC_NEWIFP 1 +#define IPFSYNC_OLDIFP 2 + + +/* ** HPUX Port */ #ifdef __hpux @@ -1352,7 +1362,7 @@ extern int fr_addipftune __P((ipftuneable_t *)); extern int fr_delipftune __P((ipftuneable_t *)); extern int frflush __P((minor_t, int, int)); -extern void frsync __P((void *)); +extern void frsync __P((int, int, void *, char *)); extern frgroup_t *fr_addgroup __P((char *, void *, u_32_t, minor_t, int)); extern int fr_derefrule __P((frentry_t **)); extern void fr_delgroup __P((char *, minor_t, int)); diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_irc_pxy.c b/usr/src/uts/common/inet/ipf/netinet/ip_irc_pxy.c index 4b7a139048..a0b784053a 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_irc_pxy.c +++ b/usr/src/uts/common/inet/ipf/netinet/ip_irc_pxy.c @@ -369,7 +369,7 @@ nat_t *nat; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(fin, &ip->ip_sum, sum2); + fix_outcksum(&ip->ip_sum, sum2); #endif ip->ip_len += inc; } diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h index 930e8aa103..9b47591591 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h +++ b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h @@ -79,7 +79,6 @@ #ifndef APR_LABELLEN #define APR_LABELLEN 16 #endif -#define NAT_HW_CKSUM 0x80000000 #define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ @@ -428,7 +427,8 @@ extern u_int ipf_hostmap_sz; extern u_int fr_nat_maxbucket; extern u_int fr_nat_maxbucket_reset; extern int fr_nat_lock; -extern void fr_natsync __P((void *)); +extern void fr_nataddrsync __P((void *, struct in_addr *)); +extern void fr_natifpsync __P((int, void *, char *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; extern u_long fr_defnatipage; @@ -468,8 +468,8 @@ extern int fr_natin __P((fr_info_t *, nat_t *, int, u_32_t)); extern void fr_natunload __P((void)); extern void fr_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); -extern void fix_incksum __P((fr_info_t *, u_short *, u_32_t)); -extern void fix_outcksum __P((fr_info_t *, u_short *, u_32_t)); +extern void fix_incksum __P((u_short *, u_32_t)); +extern void fix_outcksum __P((u_short *, u_32_t)); extern void fr_natderef __P((nat_t **)); extern u_short *nat_proto __P((fr_info_t *, nat_t *, u_int)); extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *)); diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_state.h b/usr/src/uts/common/inet/ipf/netinet/ip_state.h index 7b5891d86d..5f35878d89 100644 --- a/usr/src/uts/common/inet/ipf/netinet/ip_state.h +++ b/usr/src/uts/common/inet/ipf/netinet/ip_state.h @@ -248,7 +248,7 @@ extern int fr_stateinit __P((void)); extern ipstate_t *fr_addstate __P((fr_info_t *, ipstate_t **, u_int)); extern frentry_t *fr_checkstate __P((struct fr_info *, u_32_t *)); extern ipstate_t *fr_stlookup __P((fr_info_t *, tcphdr_t *, ipftq_t **)); -extern void fr_statesync __P((void *)); +extern void fr_statesync __P((int, int, void *, char *)); extern void fr_timeoutstate __P((void)); extern int fr_tcp_age __P((struct ipftqent *, struct fr_info *, struct ipftq *, int)); diff --git a/usr/src/uts/common/inet/ipf/solaris.c b/usr/src/uts/common/inet/ipf/solaris.c index 0c21d1f15f..9fe1660077 100644 --- a/usr/src/uts/common/inet/ipf/solaris.c +++ b/usr/src/uts/common/inet/ipf/solaris.c @@ -25,7 +25,6 @@ #include <sys/stat.h> #include <sys/cred.h> #include <sys/dditypes.h> -#include <sys/stream.h> #include <sys/poll.h> #include <sys/autoconf.h> #include <sys/byteorder.h> @@ -34,6 +33,8 @@ #include <sys/stropts.h> #include <sys/kstat.h> #include <sys/sockio.h> +#include <sys/neti.h> +#include <sys/hook.h> #include <net/if.h> #if SOLARIS2 >= 6 # include <net/if_types.h> @@ -59,7 +60,6 @@ #include "netinet/ip_auth.h" #include "netinet/ip_state.h" - extern struct filterstats frstats[]; extern int fr_running; extern int fr_flags; @@ -74,7 +74,6 @@ static int ipf_identify __P((dev_info_t *)); #endif static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t)); static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t)); -static int fr_qifsync __P((ip_t *, int, void *, int, void *, mblk_t **)); static int ipf_property_update __P((dev_info_t *)); static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, @@ -223,6 +222,9 @@ static const filter_kstats_t ipf_kstat_tmp = { { "ip upd. fail", KSTAT_DATA_ULONG } }; +net_data_t ipf_ipv4; +net_data_t ipf_ipv6; + kstat_t *ipf_kstatp[2] = {NULL, NULL}; static int ipf_kstat_update(kstat_t *ksp, int rwflag); @@ -312,7 +314,9 @@ int _init() int ipfinst; ipf_kstat_init(); + ipfinst = mod_install(&modlink1); + if (ipfinst != 0) ipf_kstat_fini(); #ifdef IPFDEBUG @@ -332,6 +336,7 @@ int _fini(void) #endif if (ipfinst == 0) ipf_kstat_fini(); + return ipfinst; } @@ -375,12 +380,6 @@ ddi_attach_cmd_t cmd; cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd); #endif - if ((pfilinterface != PFIL_INTERFACE) || (PFIL_INTERFACE < 2000000)) { - cmn_err(CE_NOTE, "pfilinterface(%d) != %d\n", pfilinterface, - PFIL_INTERFACE); - return EINVAL; - } - switch (cmd) { case DDI_ATTACH: @@ -427,18 +426,6 @@ ddi_attach_cmd_t cmd; goto attach_failed; } - if (pfil_add_hook(fr_check, PFIL_IN|PFIL_OUT, &pfh_inet4)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_inet4) failed", - "pfil_add_hook"); -#ifdef USE_INET6 - if (pfil_add_hook(fr_check, PFIL_IN|PFIL_OUT, &pfh_inet6)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_inet6) failed", - "pfil_add_hook"); -#endif - if (pfil_add_hook(fr_qifsync, PFIL_IN|PFIL_OUT, &pfh_sync)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_sync) failed", - "pfil_add_hook"); - fr_timer_id = timeout(fr_slowtimer, NULL, drv_usectohz(500000)); @@ -481,7 +468,7 @@ ddi_detach_cmd_t cmd; if (fr_refcnt != 0) return DDI_FAILURE; - if (fr_running == -2 || fr_running == 0) + if (fr_running == -2) break; /* * Make sure we're the only one's modifying things. With @@ -492,20 +479,16 @@ ddi_detach_cmd_t cmd; RWLOCK_EXIT(&ipf_global); return DDI_FAILURE; } + /* + * Make sure there is no active filter rule. + */ + if (ipfilter[0][fr_active] || ipfilter[1][fr_active] || + ipfilter6[0][fr_active] || ipfilter6[1][fr_active]) { + RWLOCK_EXIT(&ipf_global); + return DDI_FAILURE; + } fr_running = -2; - if (pfil_remove_hook(fr_check, PFIL_IN|PFIL_OUT, &pfh_inet4)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_inet4) failed", - "pfil_remove_hook"); -#ifdef USE_INET6 - if (pfil_remove_hook(fr_check, PFIL_IN|PFIL_OUT, &pfh_inet6)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_inet6) failed", - "pfil_add_hook"); -#endif - if (pfil_remove_hook(fr_qifsync, PFIL_IN|PFIL_OUT, &pfh_sync)) - cmn_err(CE_WARN, "IP Filter: %s(pfh_sync) failed", - "pfil_remove_hook"); - RWLOCK_EXIT(&ipf_global); if (fr_timer_id != 0) { @@ -577,41 +560,6 @@ void *arg, **result; /* - * look for bad consistancies between the list of interfaces the filter knows - * about and those which are currently configured. - */ -/*ARGSUSED*/ -static int fr_qifsync(ip, hlen, il, out, qif, mp) -ip_t *ip; -int hlen; -void *il; -int out; -void *qif; -mblk_t **mp; -{ - - frsync(qif); - /* - * Resync. any NAT `connections' using this interface and its IP #. - */ - fr_natsync(qif); - fr_statesync(qif); - return 0; -} - - -/* - * look for bad consistancies between the list of interfaces the filter knows - * about and those which are currently configured. - */ -int ipfsync() -{ - frsync(NULL); - return 0; -} - - -/* * Fetch configuration file values that have been entered into the ipf.conf * driver file. */ diff --git a/usr/src/uts/common/inet/pfil/compat.h b/usr/src/uts/common/inet/pfil/compat.h deleted file mode 100644 index ddaa3354e2..0000000000 --- a/usr/src/uts/common/inet/pfil/compat.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifdef DEBUG -# define PFILDEBUG -#endif - -#include "os.h" - -#ifndef MTYPE -# define MTYPE(m) ((m)->b_datap->db_type) -#endif - -#ifndef MLEN -# define MLEN(m) ((m)->b_wptr - (m)->b_rptr) -#endif - -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef ALIGN32 -# define ALIGN32(x) (x) -#endif - -#ifdef PFILDEBUG -# define PRINT(l,x) do {if ((l) <= pfildebug) cmn_err x; } while (0) -# define QTONM(x) (((x) && (x)->q_ptr) ? \ - ((qif_t *)(x)->q_ptr)->qf_name : "??") -#else -# define PRINT(l,x) ; -#endif - -#ifndef LIFNAMSIZ -# define LIFNAMSIZ 32 -#endif - -#ifndef ASSERT -# define ASSERT(x) -#endif - -/* - * The list of SAPs below all come from Sun's <atm/iftypes.h> file. It's not - * yet clear whether pfil should deal with any of these or not. - */ -#ifndef IFMP_SAP -# define IFMP_SAP 0x0065 -#endif - -#ifndef LANER_SAP -# define LANER_SAP 0x9999 -#endif - -#ifndef SNMP_SAP -# define SNMP_SAP 0x999a -#endif - -#ifndef ILMI_SAP -# define ILMI_SAP 0x999b -#endif - -#ifndef SIG_SAP -# define SIG_SAP 0x999c -#endif - -#ifndef Q93B_MGMT_SAP -# define Q93B_MGMT_SAP 0x999d -#endif - -#ifndef UTIL_SAP -# define UTIL_SAP 0x999e -#endif - -#ifndef ERROR_SAP -# define ERROR_SAP 0x999f -#endif diff --git a/usr/src/uts/common/inet/pfil/ndd.c b/usr/src/uts/common/inet/pfil/ndd.c deleted file mode 100644 index ce85cc0091..0000000000 --- a/usr/src/uts/common/inet/pfil/ndd.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/cmn_err.h> -#include <sys/stream.h> -#include <sys/errno.h> -#include <sys/socket.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> - -#include "compat.h" -#include "qif.h" -#include "pfil.h" - -caddr_t pfil_nd; - -#if !defined(sun) || SOLARIS2 <= 8 -static int qif_report(queue_t *, mblk_t *, caddr_t); -static int sill_report(queue_t *, mblk_t *, caddr_t); -static int qif_ipmp_report(queue_t *, mblk_t *, caddr_t); -static int qif_ipmp_set(queue_t *, mblk_t *, char *, caddr_t); -static int pfil_hl_set(queue_t *, mblk_t *, char *, caddr_t); - -extern int pfil_report(queue_t *, mblk_t *, caddr_t); -#else -static int qif_report(queue_t *, mblk_t *, caddr_t, cred_t *); -static int sill_report(queue_t *, mblk_t *, caddr_t, cred_t *); -static int qif_ipmp_report(queue_t *, mblk_t *, caddr_t, cred_t *); -static int qif_ipmp_set(queue_t *, mblk_t *, char *, caddr_t , cred_t *); -static int pfil_hl_set(queue_t *, mblk_t *, char *, caddr_t , cred_t *); - -extern int pfil_report(queue_t *, mblk_t *, caddr_t, cred_t *); -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_nd_get */ -/* Returns: int - 0 == success */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* ptr(I) - pointer to value to retrieve */ -/* cred(I) - pointer to credential information */ -/* */ -/* Given a pointer "ptr" to some data to return, copy it into the mblk that */ -/* has been provided. */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -int pfil_nd_get(queue_t *q, mblk_t *mp, caddr_t ptr) -#else -/*ARGSUSED*/ -int pfil_nd_get(queue_t *q, mblk_t *mp, caddr_t ptr, cred_t *cred) -#endif -{ - int *ip; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(2,(CE_CONT, "pfil_nd_get(%p,%p,%p)\n", - (void *)q, (void *)mp, (void *)ptr)); - ip = (int *)ptr; - (void) mi_mpprintf(mp, "%d", *ip); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_nd_set */ -/* Returns: int - 0 == success, > 0 error occurred */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* str(I) - pointer to new value as a string */ -/* ptr(I) - pointer to value to be stored */ -/* cred(I) - pointer to credential information */ -/* */ -/* Given a pointer "ptr" to a location to store the new value represented */ -/* by the string "str", check to see if we allow setting that variable and */ -/* if the new value is within the definable ranges understood for it. */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -int pfil_nd_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr) -#else -/*ARGSUSED*/ -int pfil_nd_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr, cred_t *cred) -#endif -{ - char *end; - long i; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(2, (CE_CONT, "pfil_nd_set(%p,%p,%s[%p],%p)\n", - (void *)q, (void *)mp, str, (void *)str, - (void *)ptr)); - -#if (SOLARIS2 >= 10) - if (ddi_strtol(str, &end, 10, &i) != 0) - return (EINVAL); -#else - i = mi_strtol(str, &end, 10); -#endif - - if (ptr == (caddr_t)&pfildebug) { -#ifdef PFILDEBUG -#if (SOLARIS2 >= 10) - if ((end == str) || (i < 0) || (i > 100)) -#else - if (i < 0 || i > 1) -#endif -#endif - return EINVAL; - } else if (ptr == (caddr_t)&qif_verbose) { - if ((end == str) || (i < 0) || (i > 1)) - return EINVAL; - } - *((int *)ptr) = i; - return 0; -} - - - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_ioctl_nd */ -/* Returns: int - B_TRUE == success, B_FALSE == getset error */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* */ -/* Handle both incoming ndd set and get requests but only if they're not */ -/* destined for another STREAMS module (ie. there is no next queue for this */ -/* message.) */ -/* ------------------------------------------------------------------------ */ -int pfil_ioctl_nd(queue_t *q, mblk_t *mp) -{ - return (nd_getset(q, pfil_nd, mp)); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_nd_init */ -/* Returns: int - 0 == success, -1 == error */ -/* Parameters: None. */ -/* */ -/* Perform any initialisation required for processing ndd ioctl messages. */ -/* ------------------------------------------------------------------------ */ -int pfil_nd_init() -{ - -#ifdef PFILDEBUG - if (!nd_load(&pfil_nd, "pfildebug", pfil_nd_get, pfil_nd_set, - (caddr_t)&pfildebug)) { - nd_free(&pfil_nd); - return -1; - } -#endif - - if (!nd_load(&pfil_nd, "pfil_delayed_copy", pfil_nd_get, pfil_nd_set, - (caddr_t)&pfil_delayed_copy)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "pfil_interface", pfil_nd_get, NULL, - (caddr_t)&pfilinterface)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "qif_status", qif_report, NULL, NULL)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "sill_status", sill_report, NULL, NULL)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "qif_ipmp_status", qif_ipmp_report, NULL, - NULL)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "qif_ipmp_set", NULL, qif_ipmp_set, NULL)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "qif_verbose", pfil_nd_get, pfil_nd_set, - (caddr_t)&qif_verbose)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "pfil_inet4", pfil_report, NULL, - (void *)&pfh_inet4)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "pfil_inet6", pfil_report, NULL, - (void *)&pfh_inet6)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "pfil_sync", pfil_report, NULL, - (void *)&pfh_sync)) { - nd_free(&pfil_nd); - return -1; - } - - if (!nd_load(&pfil_nd, "pfil_hl", NULL, pfil_hl_set, NULL)) { - nd_free(&pfil_nd); - return -1; - } - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_nd_fini */ -/* Returns: void */ -/* Parameters: None. */ -/* */ -/* Clean up any data structures related to ndd processing in preparation */ -/* for the module being unloaded. */ -/* ------------------------------------------------------------------------ */ -void pfil_nd_fini() -{ - - nd_free(&pfil_nd); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_report */ -/* Returns: int */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* ptr(I) - pointer to value to retrieve */ -/* cred(I) - pointer to credential information */ -/* */ -/* Fills the mblk with any qif data that happens to be currently available. */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -static int qif_report(queue_t *q, mblk_t *mp, caddr_t arg) -#else -/*ARGSUSED*/ -static int qif_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *cred) -#endif -{ - qif_t *qif; - - (void) mi_mpprintf(mp, - "ifname ill q OTHERQ ipmp num sap hl nr nw bad copy copyfail drop notip nodata notdata"); - READ_ENTER(&pfil_rw); - for (qif = qif_head ; qif; qif = qif->qf_next) - (void) mi_mpprintf(mp, - "%s %p %p %p %p %d %x %d %lu %lu %lu %lu %lu %lu %lu %lu %lu", - qif->qf_name, (void *)qif->qf_ill, - (void *)qif->qf_q, (void *)qif->qf_oq, - (void *)qif->qf_ipmp, qif->qf_num, - qif->qf_sap, (int)qif->qf_hl, - qif->qf_nr, qif->qf_nw, qif->qf_bad, - qif->qf_copy, qif->qf_copyfail, - qif->qf_drop, qif->qf_notip, - qif->qf_nodata, qif->qf_notdata); - RW_EXIT(&pfil_rw); - return 0; -} - - - -/* ------------------------------------------------------------------------ */ -/* Function: sill_report */ -/* Returns: int */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* ptr(I) - pointer to value to retrieve */ -/* cred(I) - pointer to credential information */ -/* */ -/* Fills the mblk with any shadow ill (s_illt) data that happens to be */ -/* currently available. */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -static int sill_report(queue_t *q, mblk_t *mp, caddr_t arg) -#else -/*ARGSUSED*/ -static int sill_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *cred) -#endif -{ - s_ill_t *sill; - - (void) mi_mpprintf(mp, - "sill name sap mtu localaddr netmask broadaddr dstaddr"); - READ_ENTER(&pfil_rw); - for (sill = s_ill_g_head ; sill; sill = sill->ill_next) - (void) mi_mpprintf(mp, "%p %s %x %u %x %x %x %x", - (void *)sill, sill->ill_name, sill->ill_sap, - sill->mtu, - sill->localaddr.in.sin_addr.s_addr, - sill->netmask.in.sin_addr.s_addr, - sill->broadaddr.in.sin_addr.s_addr, - sill->dstaddr.in.sin_addr.s_addr); - RW_EXIT(&pfil_rw); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_report */ -/* Returns: int */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* ptr(I) - pointer to value to retrieve */ -/* cred(I) - pointer to credential information */ -/* */ -/* Fills the mblk with any qif data that happens to be currently available. */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -static int qif_ipmp_report(queue_t *q, mblk_t *mp, caddr_t arg) -#else -/*ARGSUSED*/ -static int qif_ipmp_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *cred) -#endif -{ - qif_t *qif; - - (void) mi_mpprintf(mp, "ifname members"); - READ_ENTER(&pfil_rw); - for (qif = qif_head ; qif; qif = qif->qf_next) { - if ((qif->qf_flags & QF_IPMP) == 0) - continue; - (void) mi_mpprintf(mp, "%s %s", qif->qf_name, qif->qf_members); - } - RW_EXIT(&pfil_rw); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_set */ -/* Returns: int - 0 == success, > 0 error occurred */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* str(I) - pointer to new value as a string */ -/* ptr(I) - pointer to value to be stored */ -/* cred(I) - pointer to credential information */ -/* */ -/* This function is a wrapper for qif_ipmp_update(), providing a run-time */ -/* interactive way to configure the IPMP configuration for pfil without */ -/* needing to load/unload the module to reread the config file (or is there */ -/* a way to do that once loaded, anyway?) */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -static int qif_ipmp_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr) -#else -/*ARGSUSED*/ -static int qif_ipmp_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr, - cred_t *cred) -#endif -{ - char *s, *t; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(2, (CE_CONT, "qif_ipmp_set(0x%p,0x%p,0x%s[%p],0x%p)\n", - (void *)q, (void *)mp, str, (void *)str, (void *)ptr)); - - t = NULL; - s = str; - do { - if (t != NULL) - s = t + 1; - t = strchr(s, ';'); - if (t != NULL) - *t = '\0'; - qif_ipmp_update(s); - } while (t != NULL); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_hl_set */ -/* Returns: int - 0 == success, > 0 error occurred */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* str(I) - pointer to new value as a string */ -/* ptr(I) - pointer to value to be stored */ -/* cred(I) - pointer to credential information */ -/* */ -/* Explicitly set the header length (hl) field of the qif structure. This */ -/* is used in situations where pfil cannot, for some reason, automatically */ -/* determine it via either ioctl snooping or looking at passing messages. */ -/* ndd -set /dev/pfil pfil_hl ipmp0=14 or v4:ipmp0=14 */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || SOLARIS2 <= 8 -/*ARGSUSED*/ -static int pfil_hl_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr) -#else -/*ARGSUSED*/ -static int pfil_hl_set(queue_t *q, mblk_t *mp, char *str, caddr_t ptr, - cred_t *cred) -#endif -{ - char *s, *t; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(2, (CE_CONT, "pfil_hl_set(0x%lx,0x%lx,0x%lx[%s],0x%lx)\n", - (u_long)q, (u_long)mp, (u_long)str, str, (u_long)ptr)); - - t = NULL; - s = str; - do { - if (t != NULL) - s = t + 1; - t = strchr(s, ';'); - if (t != NULL) - *t = '\0'; - qif_hl_set(s); - } while (t != NULL); - - return 0; -} diff --git a/usr/src/uts/common/inet/pfil/os.h b/usr/src/uts/common/inet/pfil/os.h deleted file mode 100644 index b7a77e130e..0000000000 --- a/usr/src/uts/common/inet/pfil/os.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#include <sys/sunddi.h> -#include <sys/ddi.h> -#if SOLARIS2 >= 6 -# include <net/if_types.h> -#endif -#undef IPOPT_EOL -#undef IPOPT_NOP -#undef IPOPT_LSRR -#undef IPOPT_RR -#undef IPOPT_SSRR - -#include <inet/common.h> -#include <inet/mi.h> -#include <inet/led.h> -#include <inet/nd.h> -#if SOLARIS2 >= 8 -# include <netinet/ip6.h> -#endif -#include <inet/ip.h> - -#define MUTEX_ENTER(x) mutex_enter(x) -#define MUTEX_EXIT(x) mutex_exit(x) -#define READ_ENTER(x) rw_enter(x, RW_READER) -#define WRITE_ENTER(x) rw_enter(x, RW_WRITER) -#define RW_DOWNGRADE(x) rw_downgrade(x) -#define RW_EXIT(x) rw_exit(x) -#define KMALLOC(v,t,z,w) (v) = (t)kmem_zalloc(z, w) -#define KMFREE(v, z) kmem_free(v, z) - -extern caddr_t pfil_nd; - -#if defined(atomic_add_long) && (SOLARIS2 < 7) -# undef atomic_add_long -# define atomic_add_long(x,y) atomic_add_32((uint32_t *)x, y) -#endif diff --git a/usr/src/uts/common/inet/pfil/pfil.c b/usr/src/uts/common/inet/pfil/pfil.c deleted file mode 100644 index d44f1ac5bc..0000000000 --- a/usr/src/uts/common/inet/pfil/pfil.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2000, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * ident "@(#)$Id: pfil.c,v 1.27 2003/11/30 09:45:57 darrenr Exp $" - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -#ifndef __hpux -#pragma ident "%Z%%M% %I% %E% SMI" -#else -struct uio; -#endif - -#include <sys/systm.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/errno.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/conf.h> -#include <sys/cmn_err.h> -#include <sys/stat.h> -#include <sys/stream.h> -#include <sys/poll.h> -#include <sys/byteorder.h> -#include <sys/socket.h> -#ifdef sun -# include <sys/kmem.h> -#endif -#include <sys/dlpi.h> -#include <sys/lock.h> -#include <sys/stropts.h> -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#ifdef sun -# include <inet/common.h> -# if SOLARIS2 >= 8 -# include <netinet/ip6.h> -# endif -# undef IPOPT_EOL -# undef IPOPT_NOP -# undef IPOPT_LSRR -# undef IPOPT_SSRR -# undef IPOPT_RR -# include <inet/ip.h> -#endif - -#include "compat.h" -#include "qif.h" -#include "pfil.h" - - -int pfil_delayed_copy = 1; -int pfilinterface = PFIL_INTERFACE; -/* -** HPUX Port -** Align these structs to 16 bytes -** so that the embedded locks (first member) -** are 16 byte aligned -*/ -#ifdef __hpux -#pragma align 16 -struct pfil_head pfh_inet4 = { 0, NULL, NULL, 0 }; -#pragma align 16 -struct pfil_head pfh_inet6 = { 0, NULL, NULL, 0 }; -#pragma align 16 -struct pfil_head pfh_sync = { 0, NULL, NULL, 0 }; -#else -struct pfil_head pfh_inet4; -struct pfil_head pfh_inet6; -struct pfil_head pfh_sync; -#endif - - -static int pfil_list_add(pfil_list_t *, - int (*) __P((struct ip *, int, void *, int, - void *, mblk_t **)), - int); -static int pfil_list_remove(pfil_list_t *, - int (*) __P((struct ip *, int, void *, int, - void *, mblk_t **))); - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_report */ -/* Returns: int - always returns 0 */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to mblk */ -/* arg(I) - pointer to value to retrieve */ -/* cred(I) - pointer to credential information */ -/* */ -/* Returns a list of the registered callbacks for processing packets going */ -/* in and out on a particular filtering head structure */ -/* ------------------------------------------------------------------------ */ -#if !defined(sun) || (SOLARIS2 <= 8) -/*ARGSUSED*/ -int pfil_report(queue_t *q, mblk_t *mp, caddr_t arg) -#else -/*ARGSUSED*/ -int pfil_report(queue_t *q, mblk_t *mp, caddr_t arg, cred_t *cred) -#endif -{ - packet_filter_hook_t *p; - pfil_head_t *ph; - - ph = (pfil_head_t *)arg; - - READ_ENTER(&ph->ph_lock); - - (void) mi_mpprintf(mp, "in"); - (void) mi_mpprintf(mp, "function\tflags"); - for (p = ph->ph_in.pfl_top; p; p = p->pfil_next) - (void) mi_mpprintf(mp,"%p\t%x", - (void *)p->pfil_func, p->pfil_flags); - - (void) mi_mpprintf(mp, "out"); - (void) mi_mpprintf(mp, "function\tflags"); - for (p = ph->ph_out.pfl_top; p; p = p->pfil_next) - (void) mi_mpprintf(mp,"%p\t%x", - (void *)p->pfil_func, p->pfil_flags); - - RW_EXIT(&ph->ph_lock); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_init */ -/* Returns: void */ -/* Parameters: ph(I) - pointer to pfil head structure */ -/* */ -/* Initialise a pfil_head structure. */ -/* ------------------------------------------------------------------------ */ -void -pfil_init(ph) - struct pfil_head *ph; -{ -#ifdef sun - rw_init(&ph->ph_lock, "pfil head", RW_DRIVER, NULL); -#endif -#ifdef __hpux - initlock(&ph->ph_lock, PFIL_SMAJ, 1020, "pfil head"); -#endif - ph->ph_in.pfl_top = NULL; - ph->ph_in.pfl_tail = &ph->ph_in.pfl_top; - ph->ph_out.pfl_top = NULL; - ph->ph_out.pfl_tail = &ph->ph_out.pfl_top; - ph->ph_init = 1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_add_hook */ -/* Returns: int - 0 == success, else error. */ -/* Parameters: func(I) - function pointer to add */ -/* flags(I) - flags describing for which events to call the */ -/* passed function */ -/* ph(I) - pointer to callback head structure */ -/* */ -/* This function is the public interface for adding a callback function to */ -/* a list of callbacks for a particular protocol head (ph). */ -/* */ -/* pfil_add_hook() adds a function to the packet filter hook. the */ -/* flags are: */ -/* PFIL_IN call me on incoming packets */ -/* PFIL_OUT call me on outgoing packets */ -/* PFIL_WAITOK OK to call malloc and wait whilst adding this hook */ -/* ------------------------------------------------------------------------ */ -int -pfil_add_hook(func, flags, ph) - int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)); - int flags; - struct pfil_head *ph; -{ - int err = 0; - - ASSERT((flags & ~(PFIL_IN|PFIL_OUT|PFIL_WAITOK)) == 0); - - if (ph->ph_init == 0) - pfil_init(ph); - - WRITE_ENTER(&ph->ph_lock); - - if (flags & PFIL_IN) - err = pfil_list_add(&ph->ph_in, func, flags); - - if ((err == 0) && (flags & PFIL_OUT)) - err = pfil_list_add(&ph->ph_out, func, flags); - - RW_EXIT(&ph->ph_lock); - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_list_add */ -/* Returns: int - 0 == success, else error. */ -/* Parameters: list(I) - pfil list pointer */ -/* func(I) - function pointer to add */ -/* flags(I) - flags describing for which events to call the */ -/* passed function */ -/* Write Locks: list's owner */ -/* */ -/* Adds the function (func) to the end of the list of functions. */ -/* ------------------------------------------------------------------------ */ -static int -pfil_list_add(list, func, flags) - pfil_list_t *list; - int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)); - int flags; -{ - struct packet_filter_hook *pfh; - int wait; - - for (pfh = list->pfl_top; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func == func) - return EEXIST; - - wait = flags & PFIL_WAITOK ? KM_SLEEP : KM_NOSLEEP; - - KMALLOC(pfh, struct packet_filter_hook *, sizeof(*pfh), wait); - if (pfh == NULL) - return ENOMEM; - pfh->pfil_func = func; - pfh->pfil_flags = flags; - - /* - * insert the input list in reverse order of the output list - * so that the hooks are called in the reverse order for each - * direction. So if it was A,B,C for input, it is C,B,A for output. - */ - - if (flags & PFIL_OUT) { - pfh->pfil_pnext = list->pfl_tail; - *list->pfl_tail = pfh; - list->pfl_tail = &pfh->pfil_next; - } else if (flags & PFIL_IN) { - pfh->pfil_pnext = &list->pfl_top; - pfh->pfil_next = list->pfl_top; - list->pfl_top = pfh; - if (pfh->pfil_next == NULL) - list->pfl_tail = &pfh->pfil_next; - } - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_remove_hook */ -/* Returns: int - 0 == success, else error. */ -/* Parameters: func(I) - function pointer to remove */ -/* flags(I) - flags describing for which events to call the */ -/* passed function */ -/* ph(I) - pointer to callback head structure */ -/* */ -/* pfil_remove_hook removes a specific function from a particular */ -/* pfil_head's list of callbacks as given by which flags have been passed. */ -/* ------------------------------------------------------------------------ */ -int -pfil_remove_hook(func, flags, ph) - int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)); - int flags; - struct pfil_head *ph; -{ - int err = 0; - - ASSERT((flags & ~(PFIL_IN|PFIL_OUT)) == 0); - - if (ph->ph_init == 0) - pfil_init(ph); - - WRITE_ENTER(&ph->ph_lock); - - if (flags & PFIL_IN) - err = pfil_list_remove(&ph->ph_in, func); - - if ((err == 0) && (flags & PFIL_OUT)) - err = pfil_list_remove(&ph->ph_out, func); - - RW_EXIT(&ph->ph_lock); - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_list_remove */ -/* Returns: int - 0 == success, else error. */ -/* Parameters: list(I) - pfil list pointer */ -/* func(I) - function pointer to remove */ -/* Write Locks: list's owner */ -/* */ -/* pfil_list_remove is an internal function that takes a function off the */ -/* specified pfil list, providing that a match for func is found. */ -/* ------------------------------------------------------------------------ */ -static int -pfil_list_remove(list, func) - pfil_list_t *list; - int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)); -{ - struct packet_filter_hook *pfh; - - for (pfh = list->pfl_top; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func == func) { - *pfh->pfil_pnext = pfh->pfil_next; - if (list->pfl_tail == &pfh->pfil_next) - list->pfl_tail = pfh->pfil_pnext; - KMFREE(pfh, sizeof(*pfh)); - return 0; - } - - return ESRCH; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_hook_get */ -/* Returns: struct packet_filter_hook * - pointer to first member in */ -/* list of callbacks or NULL if */ -/* if there are none. */ -/* Parameters: flags(I) - indicates which callback list to return */ -/* ph(I) - pointer to callback head structure */ -/* Locks: READ(ph->ph_lock) */ -/* */ -/* Returns the first pointer of the list associated with "flags" or NULL if */ -/* flags is not a recognised value. */ -/* ------------------------------------------------------------------------ */ -struct packet_filter_hook * -pfil_hook_get(flag, ph) - int flag; - struct pfil_head *ph; -{ - - /* ASSERT(rw_read_locked(&ph->ph_lock) != 0); */ - - if (ph->ph_init != 0) { - switch (flag) - { - case PFIL_IN: - return ph->ph_in.pfl_top; - case PFIL_OUT: - return ph->ph_out.pfl_top; - } - } - return NULL; -} diff --git a/usr/src/uts/common/inet/pfil/pfil.h b/usr/src/uts/common/inet/pfil/pfil.h deleted file mode 100644 index 97f926da8b..0000000000 --- a/usr/src/uts/common/inet/pfil/pfil.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifndef _NET_PFIL_H_ -#define _NET_PFIL_H_ - -#define PFIL_RELEASE "2.1.6" -#define PFIL_VERSION 2010600 -#define PFIL_INTERFACE 2000000 - -#ifndef __P -# ifdef __STDC__ -# define __P(x) x -# else -# define __P(x) () -# endif -#endif - -#ifdef sun -# include <inet/ip.h> -# if SOLARIS2 < 9 -# include <netinet/in_systm.h> -# undef IPOPT_EOL -# undef IPOPT_NOP -# undef IPOPT_RR -# undef IPOPT_LSRR -# undef IPOPT_SSRR -# include <netinet/ip.h> -# endif -#endif -#ifdef __hpux -# include <netinet/in_systm.h> -# include <netinet/in.h> -# include <netinet/ip.h> -#endif - - -typedef struct packet_filter_hook { - struct packet_filter_hook *pfil_next; - struct packet_filter_hook **pfil_pnext; - int (*pfil_func) __P((struct ip *, int, void *, int, - void *, mblk_t **)); - int pfil_flags; -} packet_filter_hook_t; - - -typedef struct pfil_list { - struct packet_filter_hook *pfl_top; - struct packet_filter_hook **pfl_tail; -} pfil_list_t; - - -/* -** HP Port -** spinlocks should be the first member for -** alignment reason. Spinlocks need to be 16 byte -** aligned. The struct itself is aligned during -** allocation so that the spinlock starts at a -** 16 byte boundary -*/ -typedef struct pfil_head { - krwlock_t ph_lock; - pfil_list_t ph_in; - pfil_list_t ph_out; - int ph_init; -} pfil_head_t; - - -#define PFIL_IN 0x00000001 -#define PFIL_OUT 0x00000002 -#define PFIL_INOUT (PFIL_IN|PFIL_OUT) -#define PFIL_WAITOK 0x00000004 -#define PFIL_GROUP 0x00000008 -#define PFIL_ALL (PFIL_IN|PFIL_OUT) - -/* HPUX Port Major no. for pfil spinlocks */ -#define PFIL_SMAJ 0 - -void pfil_init __P((struct pfil_head *)); -struct packet_filter_hook *pfil_hook_get __P((int, struct pfil_head *)); -int pfil_add_hook __P((int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)), int, - struct pfil_head *)); -int pfil_remove_hook __P((int (*func) __P((struct ip *, int, void *, int, - void *, mblk_t **)), int, - struct pfil_head *)); -int pfil_sendbuf(mblk_t *); -mblk_t *pfil_make_dl_packet __P((mblk_t *, struct ip *, void *, - char *, queue_t **)); -void pfil_send_dl_packet __P((queue_t *, mblk_t *)); - - -extern int pfilinterface; -extern int pfil_delayed_copy; -extern int pfildebug; -extern struct pfil_head pfh_inet4; /* IPv4 packet processing */ -extern struct pfil_head pfh_inet6; /* IPv6 packet processing */ -extern struct pfil_head pfh_sync; /* Notification of interface */ - /* naming/address changes. */ -extern krwlock_t qif_rwlock; -extern krwlock_t pfil_rw; - -/* - * NOTE: On Solaris, even though pfilwput(), etc, are prototyped as returning - * an int, the return value is never checked and much code ignores it, anyway, - * so for performance reasonsm, various functions return void instead of int. - */ -extern void pfilwput __P((queue_t *q, mblk_t *mp)); -extern void pfil_ioctl __P((queue_t *q, mblk_t *mp)); -extern int pfil_ioctl_nd __P((queue_t *q, mblk_t *mp)); -extern int pfil_nd_init __P((void)); -extern void pfil_nd_fini __P((void)); -extern int pfil_precheck __P((queue_t *, mblk_t **, int, struct qif *)); -extern void pfil_startup __P((void)); -extern void pfilmodrput __P((queue_t *q, mblk_t *mp)); -extern void pfilmodwput __P((queue_t *q, mblk_t *mp)); -extern void pfilmodwsrv __P((queue_t *q)); -#ifdef USE_SERVICE_ROUTINE -extern int pfilmodrsrv __P((queue_t *q)); -#else -#define pfilmodrsrv NULL -#endif - -#ifdef IRE_ILL_CN -void pfil_addif(queue_t *, const char *, int); -#endif - -extern void mb_copydata __P((mblk_t *, size_t , size_t, char *)); -extern void mb_copyback __P((mblk_t *, size_t , size_t, char *)); -extern int pfildebug; - -void pfil_update_ifaddr(mblk_t * mp); -#endif /* _NET_PFIL_H_ */ diff --git a/usr/src/uts/common/inet/pfil/pfild.h b/usr/src/uts/common/inet/pfil/pfild.h deleted file mode 100644 index e866e514ae..0000000000 --- a/usr/src/uts/common/inet/pfil/pfild.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/types.h> -#include <sys/socket.h> -#include <net/if.h> -#include <netinet/in.h> - -/* - * STREAMS control messages used to communicate between pfild and pfil. - * Messages are sent down to /dev/pfil as M_PROTO->M_DATA. - * M_PROTO block contains uint32_t command code. - * M_DATA block contains [an array of] the corresponding data structure. - */ - -/* - * Data structure used to pass interface configuration information from - * pfild to the pfil kernel module. - */ -#define PFILCMD_IFADDRS 1 -struct pfil_ifaddrs { - char name[LIFNAMSIZ]; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } localaddr; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } netmask; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } broadaddr; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } dstaddr; - uint_t mtu; -}; - -/* - * Data structure used to pass interface valid source address set information - * from pfild to the pfil kernel module. - */ -#define PFILCMD_IFADDRSET 2 -struct pfil_ifaddrset { - char name[LIFNAMSIZ]; - uint8_t af; - uint32_t nspans; -}; -struct pfil_v4span { - uint32_t first, last; /* in host byte order! */ -}; -struct pfil_v6span { - struct in6_addr first, last; -}; diff --git a/usr/src/uts/common/inet/pfil/pfildrv.c b/usr/src/uts/common/inet/pfil/pfildrv.c deleted file mode 100644 index 45d694d304..0000000000 --- a/usr/src/uts/common/inet/pfil/pfildrv.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* - * Copyright (C) 2000, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/conf.h> -#include <sys/debug.h> -#include <sys/atomic.h> -#include <sys/ethernet.h> -#include <sys/stream.h> -#include <sys/errno.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <sys/cred.h> -#include <sys/modctl.h> -#include <sys/devops.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/stat.h> -#include <sys/cmn_err.h> -#include <sys/dlpi.h> -#include <sys/kmem.h> -#include <sys/strsun.h> -#include <net/if.h> -#include <net/if_dl.h> -#include <inet/common.h> -#include <inet/nd.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> -#if SOLARIS2 >= 8 -# include <netinet/ip6.h> -#endif -#undef IPOPT_EOL -#undef IPOPT_NOP -#undef IPOPT_RR -#undef IPOPT_LSRR -#undef IPOPT_SSRR -#include <inet/ip.h> -#include <inet/ip_if.h> - -#include "compat.h" -#include "qif.h" -#include "pfil.h" - - -#undef USE_SERVICE_ROUTINE - -#define MINSDUSZ 1 -#define MAXSDUSZ INFPSZ - -char _depends_on[] = "drv/ip"; - -static struct module_info pfil_minfo = { - 0x534b, "pfil", MINSDUSZ, MAXSDUSZ, 0, 0 -}; - -krwlock_t pfil_rw; -int pfildebug = 0; -int pfil_installed = 0; - -#ifdef IRE_ILL_CN -kmutex_t s_ill_g_head_lock; -s_ill_t * s_ill_g_head = NULL; -queue_t *pfildq; /* pfild's read queue for packets */ -#endif - -/************************************************************************ - * STREAMS device information (/dev/pfil) - */ -static int pfildevopen(queue_t *, dev_t *, int, int, cred_t *); -static int pfildevclose(queue_t *, int, cred_t *); - -#ifdef IRE_ILL_CN -static void pfil_remif(queue_t *q); -static void _dump_s_ill(s_ill_t *); -static void _dump_s_ill_all(void); -#endif - -static struct qinit pfil_rinit = { - NULL, NULL, pfildevopen, pfildevclose, NULL, &pfil_minfo, NULL -}; - -static struct qinit pfil_winit = { - (pfi_t)pfilwput, NULL, NULL, NULL, NULL, &pfil_minfo, NULL -}; - -struct streamtab pfil_dev_strtab = { - &pfil_rinit, &pfil_winit -}; - -extern int nulldev(); -extern int nodev(); - -void pfil_donotip(int, qif_t *, queue_t *, mblk_t *, mblk_t *, struct ip *, size_t); -static int pfil_info(dev_info_t *, ddi_info_cmd_t , void *, void **); -static int pfil_attach(dev_info_t *, ddi_attach_cmd_t); -#if SOLARIS2 < 10 -static int pfil_identify(dev_info_t *); -#endif -static int pfil_detach(dev_info_t *, ddi_detach_cmd_t); - -#ifdef DDI_DEFINE_STREAM_OPS -DDI_DEFINE_STREAM_OPS(pfil_devops, nulldev, nulldev, pfil_attach, pfil_detach, - nulldev, pfil_info, D_MP, &pfil_dev_strtab); - -#else -static struct cb_ops pfil_ops = { - nodev, /* cb_open */ - nodev, /* cb_close */ - nodev, /* cb_strategy */ - nodev, /* cb_print */ - nodev, /* cb_dump */ - nodev, /* cb_read */ - nodev, /* cb_write */ - nodev, /* cb_ioctl */ - nodev, /* cb_devmap */ - nodev, /* cb_mmap */ - nodev, /* cb_segmap */ - nochpoll, /* cb_chpoll */ - ddi_prop_op, /* cb_prop_op */ - &pfilinfo, /* cb_stream */ - D_MP /* cb_flag */ -}; - -static struct dev_ops pfil_devops = -{ - DEVO_REV, /* devo_rev */ - 0, /* devo_refcnt */ - pfil_info, /* devo_getinfo */ -#if SOLARIS2 >= 10 - nulldev, -#else - pfil_identify, /* devo_identify */ -#endif - nulldev, /* devo_probe */ - pfil_attach, /* devo_attach */ - pfil_detach, /* devo_detach */ - nodev, /* devo_reset */ - &pfil_ops, /* devo_cb_ops */ - NULL /* devo_bus_ops */ -}; -#endif - -static struct modldrv modldrv = { - &mod_driverops, "pfil Streams driver "/**/PFIL_RELEASE, &pfil_devops -}; - -/************************************************************************ - * STREAMS module information - */ -static int pfilmodopen(queue_t *, dev_t *, int, int, cred_t *); -static int pfilmodclose(queue_t *, int, cred_t *); - -static struct qinit pfilmod_rinit = { - (pfi_t)pfilmodrput, NULL, pfilmodopen, pfilmodclose, - NULL, &pfil_minfo, NULL -}; - -static struct qinit pfilmod_winit = { - (pfi_t)pfilmodwput, NULL, NULL, NULL, NULL, &pfil_minfo, NULL -}; - -struct streamtab pfil_mod_strtab = { - &pfilmod_rinit, &pfilmod_winit -}; - -static struct fmodsw fsw = { - "pfil", &pfil_mod_strtab, D_MP -}; - -static struct modlstrmod modlstrmod = { - &mod_strmodops, "pfil Streams module "/**/PFIL_RELEASE, - &fsw -}; - -/************************************************************************ - * STREAMS externally visible information for _init() and _info () - */ -static struct modlinkage modlinkage = { - MODREV_1, - { (void *)&modlstrmod, (void *)&modldrv, NULL } -}; - -/************************************************************************ - * STREAMS device functions - */ -static dev_info_t *pfil_dev_info; - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_attach */ -/* Returns: int - DDI_SUCCESS for success, otherwise DDI_FAILURE */ -/* Parameters: devi(I) - pointer to packet information */ -/* cmd(I) - DDI command to process */ -/* */ -/* Called when the driver has been attached, just create the device file. */ -/* ------------------------------------------------------------------------ */ -/*ARGUSED*/ -static int pfil_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfil_attach(%p,%x)\n", (void *)devi, cmd)); - - if (cmd != DDI_ATTACH) - return (DDI_FAILURE); - - pfil_dev_info = devi; - -#if SOLARIS2 >= 8 - return (ddi_create_minor_node(devi, "pfil", S_IFCHR, 0, DDI_PSEUDO, 0)); -#else - return (ddi_create_minor_node(devi, "pfil", S_IFCHR, 0, NULL, 0)); -#endif -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_detach */ -/* Returns: int - DDI_SUCCESS for success, otherwise DDI_FAILURE */ -/* Parameters: devi(I) - pointer to device information */ -/* cmd(I) - DDI command to process */ -/* */ -/* Nothing to do here(?) except return that everything is ok. */ -/* ------------------------------------------------------------------------ */ -/*ARGUSED*/ -static int pfil_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) -{ - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfil_detach(%p,%x)\n", (void *)devi, cmd)); - - if (cmd != DDI_DETACH) - return (DDI_FAILURE); - - ASSERT(devi == pfil_dev_info); - - ddi_remove_minor_node(devi, NULL); - return (DDI_SUCCESS); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_info */ -/* Returns: int - DDI_SUCCESS (success), DDI_FAILURE (failure) */ -/* Parameters: dip(I) - pointer to device information */ -/* cmd(I) - DDI command to process */ -/* arg(I) - paramter to the command to be processed */ -/* res(O) - pointer to storage for returning results */ -/* */ -/* Handles information queries made by the kernel of the STREAMS device. */ -/* ------------------------------------------------------------------------ */ -/*ARGUSED*/ -static int pfil_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, - void **res) -{ - int result = DDI_FAILURE; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfil_info(%p,%x,%p,%p)\n", (void *)dip, infocmd, - arg, (void *)res)); - - switch (infocmd) - { - case DDI_INFO_DEVT2DEVINFO: - if (pfil_dev_info != NULL) { - *res = (void *)pfil_dev_info; - result = DDI_SUCCESS; - } - break; - case DDI_INFO_DEVT2INSTANCE: - *res = NULL; - result = DDI_SUCCESS; - break; - default : - break; - } - return result; -} - - -#if SOLARIS2 < 10 -/* ------------------------------------------------------------------------ */ -/* Function: pfil_identify */ -/* Returns: int - DDI_IDENTIFIED (success), DDI_NOT_IDENTIFIED (failure)*/ -/* Parameters: devi(I) - pointer to a dev_info structure */ -/* */ -/* Check to see if this module is correctly associated with the device info */ -/* structure passed in. */ -/* ------------------------------------------------------------------------ */ -static int pfil_identify(dev_info_t *devi) -{ - int result = DDI_NOT_IDENTIFIED; - - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(3,(CE_CONT, "!pfil_identify(%p)\n", (void *)devi)); - if (strcmp((char *)ddi_get_name(devi), "!pfil") == 0) - result = DDI_IDENTIFIED; - - return result; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: pfildevopen */ -/* Returns: int - 0 == sucess, else failure */ -/* Parameters: q(I) - pointer to STREAMS queue */ -/* devp(I) - pointer to a device number */ -/* oflag(I) - file mode open flags (always 0 for module opens) */ -/* sflag(I) - flag indicating how the open is being made */ -/* crp(I) - pointer to message credentials from the user */ -/* */ -/* Perform any action required to open the STREAMS device, supporting it */ -/* being opened in a cloning fashion. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int pfildevopen(queue_t *q, dev_t *devp, int oflag, int sflag, - cred_t *crp) -{ - int result = 0; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfildevopen(%p,%p,%x,%x,%p) [%s]\n", - (void *)q, (void *)devp, oflag, sflag, (void *)crp, QTONM(q))); - /* - * As per recommendation on man page open(9e) - */ - if ((sflag & MODOPEN) != 0) - result = ENXIO; - - if (result == 0) - qprocson(q); - - return result; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfildevclose */ -/* Returns: int - always returns 0. */ -/* Parameters: q(I) - pointer to STREAMS queue */ -/* flag(I) - file status flag */ -/* crp(I) - pointer to message credentials from the user */ -/* */ -/* Perform any action required to close the STREAMS device. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int pfildevclose(queue_t *q, int flag, cred_t *crp) -{ - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfildevclose(%p,%x,%p) [%s]\n", - (void *)q, flag, (void *)crp, QTONM(q))); - qprocsoff(q); - -#ifdef IRE_ILL_CN - if (q == pfildq) - pfildq = NULL; -#endif - - return 0; -} - -/************************************************************************ - * STREAMS module functions - */ -/* ------------------------------------------------------------------------ */ -/* Function: pfilmodopen */ -/* Returns: int - 0 == success, else error */ -/* Parameters: q(I) - pointer to read-side STREAMS queue */ -/* devp(I) - pointer to a device number */ -/* oflag(I) - file status open flags (always 0 for module open)*/ -/* sflag(I) - flag indicating how the open is being made */ -/* crp(I) - pointer to message credentials from the user */ -/* */ -/* open() entry hook for the STREAMS module. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int pfilmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, - cred_t *crp) -{ - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfilmodopen(%p,%p,%x,%x,%p) [%s]\n", - (void *)q, (void *)devp, oflag, sflag, (void *)crp, QTONM(q))); - - /* - * As per recommendation on man page open(9e) - */ - if (sflag != MODOPEN) - return ENXIO; - - q->q_ptr = qif_new(q, KM_SLEEP); - WR(q)->q_ptr = q->q_ptr; - qprocson(q); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfilmodclose */ -/* Returns: int - always returns 0. */ -/* Parameters: q(I) - pointer to read-side STREAMS queue */ -/* flag(I) - file status flag */ -/* crp(I) - pointer to message credentials from the user */ -/* */ -/* close() entry hook for the STREAMS module. qif_delete() takes care of */ -/* setting q_ptr back to NULL for both this and the write side queue. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -static int pfilmodclose(queue_t *q, int flag, cred_t *crp) -{ - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfilmodclose(%p,%x,%p) [%s]\n", - (void *)q, flag, (void *)crp, QTONM(q))); - - qprocsoff(q); - -#ifdef IRE_ILL_CN - pfil_remif(q); -#endif - qif_delete(q->q_ptr, q); - return 0; -} - -/************************************************************************ - * other support functions - */ - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_precheck */ -/* Returns: int - < 0 pass packet because it's not a type subject to */ -/* firewall rules (i.e. internal STREAMS messages), */ -/* 0 == pass packet, else > 0 indicates passing */ -/* prohibited (possibly due to an error occuring in */ -/* this function.) */ -/* Parameters: q(I) - pointer to STREAMS queue */ -/* mp(I) - pointer to STREAMS message */ -/* qif(I) - pointer to per-queue interface information */ -/* Locks: pfil_rw */ -/* */ -/* In here we attempt to determine if there is an IP packet within an mblk */ -/* that is being passed along and if there is, ensure that it falls on a 32 */ -/* bit aligned address and at least all of the layer 3 header is in one */ -/* buffer, preferably all the layer 4 too if we recognise it. Finally, if */ -/* we can be sure that the buffer passes some sanity checks, pass it on to */ -/* the registered callbacks for the particular protocol/direction. */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -int pfil_precheck(queue_t *q, mblk_t **mp, int flags, qif_t *qif) -{ - register struct ip *ip; - size_t hlen, len, off, mlen, iphlen, plen; - packet_filter_hook_t *pfh; - qpktinfo_t qpkt, *qpi; - struct pfil_head *ph; - mblk_t *m, *mt = *mp; - int err, out, sap; - u_char *bp; -#if SOLARIS2 >= 8 - ip6_t *ip6; -#endif -#ifndef sparc - u_short __ipoff, __iplen; -#endif - - qpi = &qpkt; - qpi->qpi_q = q; - qpi->qpi_off = 0; - qpi->qpi_name = qif->qf_name; - qpi->qpi_real = qif; - qpi->qpi_ill = qif->qf_ill; - qpi->qpi_hl = qif->qf_hl; - qpi->qpi_ppa = qif->qf_ppa; - qpi->qpi_num = qif->qf_num; - qpi->qpi_flags = qif->qf_flags; - qpi->qpi_max_frag = qif->qf_max_frag; - if ((flags & PFIL_GROUP) != 0) - qpi->qpi_flags |= QF_GROUP; - - /* - * If there is only M_DATA for a packet going out, then any header - * information (which would otherwise appear in an M_PROTO mblk before - * the M_DATA) is prepended before the IP header. We need to set the - * offset to account for this. - */ - out = (flags & PFIL_OUT) ? 1 : 0; - off = (out) ? qpi->qpi_hl : 0; - - ip = NULL; - m = NULL; -#if SOLARIS2 >= 8 - ip6 = NULL; -#endif - - /* - * If the message protocol block indicates that there isn't a data - * block following it, just return back. - */ - bp = (u_char *)ALIGN32(mt->b_rptr); - - switch (MTYPE(mt)) - { - case M_PROTO : - case M_PCPROTO : - { - dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp; - if ((dl->dl_primitive != DL_UNITDATA_IND) && - (dl->dl_primitive != DL_UNITDATA_REQ)) { - ip = (struct ip *)dl; - if ((ip->ip_v == IPVERSION) && - (ip->ip_hl == (sizeof(*ip) >> 2)) && - (ntohs(ip->ip_len) == mt->b_wptr - mt->b_rptr)) { - off = 0; - m = mt; - } else { - atomic_add_long(&qif->qf_notdata, 1); - return -1; - } - } else { - m = mt->b_cont; - if (m == NULL) { - atomic_add_long(&qif->qf_nodata, 1); - return -3; /* No data blocks */ - } - } - break; - } - case M_DATA : - m = mt; - break; - default : - atomic_add_long(&qif->qf_notdata, 1); - return -2; - } - - /* - * Find the first data block, count the data blocks in this chain and - * the total amount of data. - */ - if (ip == NULL) - for (m = mt; m && (MTYPE(m) != M_DATA); m = m->b_cont) - off = 0; /* Any non-M_DATA cancels the offset */ - - if (m == NULL) { - atomic_add_long(&qif->qf_nodata, 1); - return -3; /* No data blocks */ - } - - /* - * This is a complete kludge to try and work around some bizarre - * packets which drop through into pfil_donotip. - */ - if ((mt != m) && (MTYPE(mt) == M_PROTO || MTYPE(mt) == M_PCPROTO)) { - dl_unitdata_ind_t *dl = (dl_unitdata_ind_t *)bp; - - if ((dl->dl_primitive == DL_UNITDATA_IND) && - (dl->dl_group_address == 1)) { - qpi->qpi_flags |= QF_GROUP; - if (((*((u_char *)m->b_rptr) == 0x0) && - ((*((u_char *)m->b_rptr + 2) == 0x45)))) - off += 2; - } - - } - - /* - * We might have a 1st data block which is really M_PROTO, i.e. it is - * only big enough for the link layer header - */ - while ((len = m->b_wptr - m->b_rptr) <= off) { - off -= len; - m = m->b_cont; - if (m == NULL) { - atomic_add_long(&qif->qf_nodata, 1); - return -4; /* not enough data for IP */ - } - } - - ip = (struct ip *)(m->b_rptr + off); - len = m->b_wptr - m->b_rptr - off; - mlen = msgdsize(m); - -#ifdef IRE_ILL_CN - sap = ((s_ill_t *)qif->qf_ill)->ill_sap; -#else - sap = ((ill_t *)qif->qf_ill)->ill_sap; -#endif - - if (mlen == 0) - mlen = m->b_wptr - m->b_rptr; - mlen -= off; - -#ifdef PFILDEBUG - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(10,(CE_CONT, - "!IP Filter[%s]: out %d len %ld/%ld sap %d ip %p b_rptr %p off %ld m %p/%d/%d/%p mt %p/%d/%d/%p\n", - qif->qf_name, out, len, mlen, sap, - (void *)ip, (void *)m->b_rptr, off, - (void *)m, MTYPE(m), (int)MLEN(m), (void *)m->b_cont, - (void *)mt, MTYPE(mt), (int)MLEN(mt), (void *)mt->b_cont)); -#endif - - /* - * If there is more than one copy of this message traversing the - * STREAMS stack (ie the packet is being used for snoop data), the - * IP header isn't on a 32bit aligned address, or the IP header - * isn't contain within a single block, then make a copy which - * meets our requirements and do a freemsg on the one passed in - * since we're no longer using it or passing it up. - */ - - if ((pfil_delayed_copy == 0 && m->b_datap->db_ref > 1) - || ((uintptr_t)ip & 0x3) || len < sizeof(*ip) - || (sap != IP_DL_SAP -#if SOLARIS2 >= 8 - && sap != IP6_DL_SAP -#endif - )) { - mblk_t *b; - mblk_t *nm; - mblk_t *nmt; - mblk_t *previous_nm; - -forced_copy: - nmt = NULL; - previous_nm = NULL; - - /* - * Duplicate the message block descriptors up to (and - * including if the offset is non-zero) the block where - * IP begins. - */ - for (b = mt; b != m || off; b = b->b_cont) { - nm = dupb(b); - if (nm == NULL) { - atomic_add_long(&qif->qf_copyfail, 1); - if (nmt) - freemsg(nmt); - return ENOBUFS; - } - - nm->b_cont = NULL; - if (nmt) - linkb(previous_nm, nm); - else - nmt = nm; - previous_nm = nm; - - /* - * Set the length so the block only contains what - * appears before IP. - */ - if (b == m) { - nm->b_wptr = nm->b_rptr + off; - break; - } - } - - m->b_rptr += off; - nm = msgpullup(m, -1); - m->b_rptr -= off; - - if (nm == NULL) { - atomic_add_long(&qif->qf_copyfail, 1); - if (nmt) - freemsg(nmt); - return ENOBUFS; - } - - if (nmt) - linkb(previous_nm, nm); - else - nmt = nm; - - freemsg(mt); - - *mp = nmt; - mt = nmt; - m = nm; - - ip = (struct ip *)m->b_rptr; - len = m->b_wptr - m->b_rptr; - mlen = len; - off = 0; - } - - if (sap == IP_DL_SAP) { - u_short tlen; - - hlen = sizeof(*ip); - - /* XXX - might not be aligned (from ppp?) */ - ((char *)&tlen)[0] = ((char *)&ip->ip_len)[0]; - ((char *)&tlen)[1] = ((char *)&ip->ip_len)[1]; - plen = ntohs(tlen); - - ph = &pfh_inet4; - } -#if SOLARIS2 >= 8 - else if (sap == IP6_DL_SAP) { - u_short tlen; - - hlen = sizeof(ip6_t); - ip6 = (ip6_t *)ip; - - /* XXX - might not be aligned (from ppp?) */ - ((char *)&tlen)[0] = ((char *)&ip6->ip6_plen)[0]; - ((char *)&tlen)[1] = ((char *)&ip6->ip6_plen)[1]; - plen = ntohs(tlen); - if (plen == 0) - return EMSGSIZE; /* Jumbo gram */ - - ph = &pfh_inet6; - } -#endif - else { - sap = -1; - } - - if (((sap == IP_DL_SAP) && (ip->ip_v != IPVERSION)) -#if SOLARIS2 >= 8 - || ((sap == IP6_DL_SAP) && (((ip6->ip6_vfc) & 0xf0) != 0x60)) -#endif - || sap == -1 - ) { - atomic_add_long(&qif->qf_notip, 1); -#ifdef PFILDEBUG - pfil_donotip(out, qif, q, m, mt, ip, off); -#endif - return EINVAL; - } - - if (sap == IP_DL_SAP) - iphlen = ip->ip_hl << 2; -#if SOLARIS2 >= 8 - else if (sap == IP6_DL_SAP) - iphlen = sizeof(ip6_t); -#endif - - if (( -#if SOLARIS2 >= 8 - (sap == IP6_DL_SAP) && (mlen < plen)) || - ((sap == IP_DL_SAP) && -#endif - ((iphlen < hlen) || (iphlen > plen) || (mlen < plen)))) { - /* - * Bad IP packet or not enough data/data length mismatches - */ - atomic_add_long(&qif->qf_bad, 1); - return EINVAL; - } - - /* - * If we don't have enough data in the mblk or we haven't yet copied - * enough (above), then copy some more. - */ - if ((iphlen > len)) { - if (m->b_datap->db_ref > 1) - goto forced_copy; - if (!pullupmsg(m, (int)iphlen + off)) { - atomic_add_long(&qif->qf_nodata, 1); - return ENOBUFS; - } - ip = (struct ip *)ALIGN32(m->b_rptr + off); - } - - /* - * Discard any excess data. - */ - if (sap == IP6_DL_SAP && len > iphlen + plen) - m->b_wptr = m->b_rptr + off + plen + iphlen; - else if (sap == IP_DL_SAP && len > plen) - m->b_wptr = m->b_rptr + off + plen; - - /* - * The code in IPFilter assumes that both the ip_off and ip_len - * fields are in host byte order, so convert them here to fulfill - * that expectation. - * - * If the target compile host is non-SPARC, assume it is a little - * endian machine, requiring the conversion of offset/length fields - * to both be host byte ordered. - */ -#ifndef sparc - if (sap == IP_DL_SAP) { - __ipoff = (u_short)ip->ip_off; - ip->ip_len = plen; - ip->ip_off = ntohs(__ipoff); - } -#endif - - qpi->qpi_m = m; - qpi->qpi_off = off; - qpi->qpi_data = ip; - - if (qif->qf_ipmp != NULL) - qif = qif->qf_ipmp; - - READ_ENTER(&ph->ph_lock); - - pfh = pfil_hook_get(flags & PFIL_INOUT, ph); - err = 0; - - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(8,(CE_CONT, "!pfil_hook_get(%x,%p) = %p\n", - flags, (void *)ph, (void *)pfh)); - for (; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func) { - err = (*pfh->pfil_func)(ip, iphlen, qif, out, qpi, mp); - if (err || !*mp) - break; - /* - * fr_pullup may have allocated a new buffer. - */ - ip = qpi->qpi_data; - } - RW_EXIT(&ph->ph_lock); - - /* - * Functions called via pfil_func should only return values >= 0, so - * convert any that are < 0 to be > 0 and preserve the absolute value. - */ - if (err < 0) - err = -err; - - /* - * If we still have a STREAMS message after calling the filtering - * hooks, return the byte order of the fields changed above on - * platforms where this is required. They are refetched from the - * packet headers because the callback (pfil_func) may have changed - * them in some way. - */ -#ifndef sparc - if ((err == 0) && (*mp != NULL)) { - if (sap == IP_DL_SAP) { - __iplen = (u_short)ip->ip_len; - __ipoff = (u_short)ip->ip_off; - ip->ip_len = htons(__iplen); - ip->ip_off = htons(__ipoff); - } - } -#endif - return err; -} - - -/************************************************************************ - * kernel module initialization - */ - - -/* ------------------------------------------------------------------------ */ -/* Function: _init */ -/* Returns: int - DDI_SUCCESS == success, else failure */ -/* Parameters: Nil. */ -/* */ -/* Initialise the kernel module and if that succeeds, call other init */ -/* routines, elsewhere, that handle initialisation of the more generic */ -/* components. */ -/* ------------------------------------------------------------------------ */ -int _init(void) -{ - int result; - - result = pfil_nd_init(); - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(2,(CE_CONT, "pfil_nd_init():%d\n", result)); - if (result != 0) - return DDI_FAILURE; - - if (qif_startup() == -1) - return DDI_FAILURE; - - rw_init(&pfil_rw, "pfil_rw", RW_DRIVER, 0); -#ifdef IRE_ILL_CN - mutex_init(&s_ill_g_head_lock, NULL, MUTEX_DRIVER, NULL); -#endif - pfil_startup(); - - result = mod_install(&modlinkage); - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(1,(CE_CONT, "_init():%d\n", result)); - - return result; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: _fini */ -/* Returns: int - DDI_SUCCESS == success, else failure */ -/* Parameters: Nil. */ -/* */ -/* Called when the OS attempts to unload the module, it should only be */ -/* allowed to succeed if pfil is not currently in the middle of any STREAMS */ -/* "connections". If it isn't then turn ourselves off and remove the module*/ -/* ------------------------------------------------------------------------ */ -int _fini(void) -{ - int result; - - if (qif_head != NULL) - return EBUSY; - result = mod_remove(&modlinkage); - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(1,(CE_CONT, "_fini():%d\n", result)); - - if (result == DDI_SUCCESS) { - pfil_nd_fini(); - qif_stop(); -#ifdef IRE_ILL_CN - mutex_destroy(&s_ill_g_head_lock); -#endif - pfil_installed = 0; - } - return result; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: _info */ -/* Returns: int - DDI_SUCCESS == success, else failure */ -/* Parameters: modinfop(I) - pointer to module informatio buffer */ -/* */ -/* Standard _info() implementation that just calls mod_info on its linkage */ -/* structure so information can be copied back into the modinfop struct. */ -/* ------------------------------------------------------------------------ */ -int _info(struct modinfo *modinfop) -{ - int result; - - result = mod_info(&modlinkage, modinfop); - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "_info(%p):%x\n", (void *)modinfop, result)); - return result; -} - - -/************************************************************************ - * Sun Solaris ON build specific routines follow here. - */ -#ifdef IRE_ILL_CN -static void _dump_s_ill(s_ill_t *ts) -{ - cmn_err(CE_NOTE, "s_ill next = 0x%p", (void *)ts->ill_next); - cmn_err(CE_NOTE, "s_ill sap = 0x%x", ts->ill_sap); - cmn_err(CE_NOTE, "s_ill name = %s", ts->ill_name); - cmn_err(CE_NOTE, "s_ill rq = 0x%p", (void *)ts->ill_rq); -} - -static void -_dump_s_ill_all(void) -{ - s_ill_t *ill; - /* who care locks */ - if (pfildebug > 10) { - cmn_err(CE_NOTE, "s_ill_g_head = 0x%p\n", (void *)s_ill_g_head); - for (ill = s_ill_g_head; ill; ill = ill->ill_next) { - _dump_s_ill(ill); - } - cmn_err(CE_NOTE, "s_ill_g_head done\n"); - } -} - - -/* - * Allocate an s_ill_t for this interface (name) if needed. - * Populate the read queue pointer. - */ -void pfil_addif(queue_t *rq, const char *name, int sap) -{ - s_ill_t *ill; - - mutex_enter(&s_ill_g_head_lock); - - /* XXX: Need to check for duplicate */ - /* If replumbed, rq will be updated */ - for (ill = s_ill_g_head; ill; ill = ill->ill_next) { - - if (ill->ill_sap == sap && - strncmp(name, ill->ill_name, LIFNAMSIZ) == 0) { - /* interface already there */ - break; - } - } - - if (!ill) { - ill = kmem_zalloc(sizeof(s_ill_t), KM_NOSLEEP); - if (!ill) { - cmn_err(CE_NOTE, "PFIL: malloc(%d) for ill failed", - (int)sizeof(s_ill_t)); - mutex_exit(&s_ill_g_head_lock); - return; - } - ill->ill_sap = sap; - (void) strncpy(ill->ill_name, name, LIFNAMSIZ); - ill->ill_name[sizeof(ill->ill_name) - 1] = '\0'; - ill->ill_next = s_ill_g_head; - s_ill_g_head = ill; - } - - ASSERT(ill != NULL); - ill->ill_rq = rq; - _dump_s_ill_all(); - mutex_exit(&s_ill_g_head_lock); -} - - -/* - * Deactivate any s_ill_t for this interface (queue pair). - * Called when a module is being closed (popped). - */ -static void pfil_remif(queue_t *rq) -{ - s_ill_t *ill; - - WRITE_ENTER(&pfil_rw); - mutex_enter(&s_ill_g_head_lock); - - for (ill = s_ill_g_head; ill; ill = ill->ill_next) - if (ill->ill_rq == rq) - ill->ill_rq = 0; - _dump_s_ill_all(); - mutex_exit(&s_ill_g_head_lock); - RW_EXIT(&pfil_rw); -} -#endif /* IRE_ILL_CN */ - - -/************************************************************************ - * - */ -#ifdef PFILDEBUG -/* ------------------------------------------------------------------------ */ -/* Function: pfil_donotip */ -/* Returns: Nil */ -/* Parameters: out(I) - in(0)/out(1) flag for direction of message */ -/* qif(I) - pointer to per-queue interface information */ -/* q(I) - pointer to STREAMS queue */ -/* m(I) - pointer to STREAMS message block where IP starts */ -/* mt(I) - pointer to the start of the STREAMS message */ -/* ip(I) - pointer to the start of the IP header */ -/* off(I) - offset from start of message to start of IP header */ -/* */ -/* This function is here solely for dumping out the contents of an mblk and */ -/* showing what related information is known about it, to aid in debugging */ -/* processing of messages going by that fail to be recognised properly. */ -/* ------------------------------------------------------------------------ */ -void pfil_donotip(int out, qif_t *qif, queue_t *q, mblk_t *m, mblk_t *mt, struct ip *ip, size_t off) -{ - u_char *s, outb[256], *t; - int i; - - outb[0] = '\0'; - outb[1] = '\0'; - outb[2] = '\0'; - outb[3] = '\0'; - s = ip ? (u_char *)ip : outb; - if (!ip && (m == mt) && m->b_cont && (MTYPE(m) != M_DATA)) - m = m->b_cont; - - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(9,(CE_CONT, - "!IP %s:%d %ld %p %p %p ip %p b_rptr %p off %ld m %p/%d/%d/%p mt %p/%d/%d/%p\n", - qif ? qif->qf_name : "?", out, qif ? qif->qf_hl : -1, - (void *)q, q ? q->q_ptr : NULL, q ? (void *)q->q_qinfo : NULL, - (void *)ip, (void *)m->b_rptr, off, - (void *)m, MTYPE(m), (int)MLEN(m), (void *)m->b_cont, - (void *)mt, MTYPE(mt), (int)MLEN(mt), (void *)mt->b_cont)); - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(9,(CE_CONT, "%02x%02x%02x%02x\n", *s, *(s+1), *(s+2), *(s+3))); - while (m != mt) { - i = 0; - t = outb; - - s = mt->b_rptr; - (void)sprintf((char *)t, "%d:", MTYPE(mt)); - t += strlen((char *)t); - for (; (i < 100) && (s < mt->b_wptr); i++) { - (void)sprintf((char *)t, "%02x%s", *s++, - ((i & 3) == 3) ? " " : ""); - t += ((i & 3) == 3) ? 3 : 2; - } - *t++ = '\n'; - *t = '\0'; - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(50,(CE_CONT, "%s", outb)); - mt = mt->b_cont; - } - i = 0; - t = outb; - s = m->b_rptr; - (void)sprintf((char *)t, "%d:", MTYPE(m)); - t += strlen((char *)t); - for (; (i < 100) && (s < m->b_wptr); i++) { - (void)sprintf((char *)t, "%02x%s", *s++, - ((i & 3) == 3) ? " " : ""); - t += ((i & 3) == 3) ? 3 : 2; - } - *t++ = '\n'; - *t = '\0'; - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(50,(CE_CONT, "%s", outb)); -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_property_update */ -/* Returns: int - DDI_SUCCESS == success, else failure */ -/* Parameters: modinfop(I) - pointer to module informatio buffer */ -/* */ -/* Fetch configuration file values that have been entered into the */ -/* pfil.conf driver file. */ -/* ------------------------------------------------------------------------ */ -static int pfil_property_update(dev_info_t *dip) -{ - char *list, *s, *t; - int err; - - if (ddi_prop_update_int(DDI_DEV_T_ANY, dip, - "ddi-no-autodetach", 1) == -1) { - cmn_err(CE_WARN, "!updating ddi-no-authdetach failed"); - return DDI_FAILURE; - } - - list = NULL; - err = ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, - 0, "qif_ipmp_set", &list); -#ifdef IPFDEBUG - cmn_err(CE_CONT, "IP Filter: lookup_string(pfil_ipmp_list) = %d\n", - err); -#endif - if (err == DDI_SUCCESS) { - t = NULL; - s = list; - do { - if (t != NULL) - s = t + 1; - t = strchr(s, ';'); - if (t != NULL) - *t = '\0'; - qif_ipmp_update(s); - } while (t != NULL); - - ddi_prop_free(list); - } - - return DDI_SUCCESS; -} - - -#if SOLARIS2 == 8 -int miocpullup(mblk_t *m, size_t len) -{ - if (m->b_cont == NULL) - return 0; - return pullupmsg(m->b_cont, len); -} -#endif diff --git a/usr/src/uts/common/inet/pfil/pfilstream.c b/usr/src/uts/common/inet/pfil/pfilstream.c deleted file mode 100644 index 51d1b30d5a..0000000000 --- a/usr/src/uts/common/inet/pfil/pfilstream.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * Copyright (C) 2000, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -struct uio; -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/errno.h> -#include <sys/stream.h> -#ifdef HPUX_1111 -# include <sys/cred.h> -#endif -#include <sys/dlpi.h> -#include <sys/cmn_err.h> -#ifdef sun -# include <sys/atomic.h> -# include <sys/sockio.h> -# include <sys/ksynch.h> -# include <sys/strsubr.h> -# include <sys/strsun.h> -#endif -#ifdef __hpux -# include <sys/dlpi_ext.h> -# include <net/mtcp.h> -#endif -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <net/if.h> -#include <netinet/if_ether.h> -#ifdef sun -# include <inet/common.h> -# if SOLARIS2 >= 8 -# include <netinet/ip6.h> -# else -# include <net/if_dl.h> -# endif -# if SOLARIS2 >= 10 -# include <sys/policy.h> -# endif -# undef IPOPT_EOL -# undef IPOPT_NOP -# undef IPOPT_LSRR -# undef IPOPT_SSRR -# undef IPOPT_RR -# include <inet/ip.h> -# include <inet/ip_if.h> -#endif - -#include "compat.h" -#include "qif.h" -#include "pfil.h" -#include "pfild.h" - -#if SOLARIS2 >= 10 -extern queue_t *pfildq; -#endif - -#undef IEEESAP_SNAP -#define IEEESAP_SNAP 0xAA /* SNAP SAP */ - -#ifdef PFILDEBUG -# define PRINT(l,x) do {if ((l) <= pfildebug) cmn_err x; } while (0) -# define QTONM(x) (((x) && (x)->q_ptr) ? \ - ((qif_t *)(x)->q_ptr)->qf_name : "??") -#else -# define PRINT(l,x) ; -#endif - -#ifndef IP_DL_SAP -# define IP_DL_SAP 0x800 -#endif - -#define AFtoSAP(af) (((af) == AF_INET6) ? IP6_DL_SAP : IP_DL_SAP) - -static int pfil_drv_priv __P((cred_t *)); - - -#ifdef PFILDEBUG -/* ------------------------------------------------------------------------ */ -/* Function: pfil_printmchain */ -/* Returns: void */ -/* Parameters: mp(I) - pointer to mblk message */ -/* */ -/* This is primarly for debugging purposes - print out the contents of a */ -/* STREAMS mblk message, just by data block type or also contents (in hex) */ -/* if the value of pfil_debug has been turned up enough. */ -/* ------------------------------------------------------------------------ */ -void pfil_printmchain(mblk_t *mp) -{ - char buf[80], cbuf[17], *t; - u_char c, *s, *r; - mblk_t *mc; - int i; - - for (mc = mp; mc; mc = mc->b_cont) { - i = mc->b_wptr - mc->b_rptr; - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(50,(CE_CONT, "m(%p):%d len %d cont %p\n", - (void *)mc, MTYPE(mc), i, (void *)mc->b_cont)); - s = (u_char *)mc->b_rptr; - r = (u_char *)cbuf; - for (i = 0, t = buf; s < mc->b_wptr; ) { - c = *s++; - if (c >= 0x20 && c < 0x7f) - *r++ = c; - else - *r++ = '.'; - *r = '\0'; -#ifdef __hpux - sprintf(t, 4, "%02x", c); -#else - (void)sprintf(t, "%02x", c); -#endif - t += 2; - i++; - if ((i & 15) == 0) { - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(99,(CE_CONT, "%03d:%s %s\n", i - 16, - buf, cbuf)); - t = buf; - r = (u_char *)cbuf; - } else if ((i & 3) == 0) - *t++ = ' '; - } - if (t > buf) { - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(99,(CE_CONT, "%03d:%s %s\n", i - (i & 15), buf, - cbuf)); - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_printioctl */ -/* Returns: void */ -/* Parameters: mp(I) - pointer to mblk message with ioctl */ -/* */ -/* This is primarly for debugging purposes - print out in a more legible */ -/* format what an ioctl is. */ -/* ------------------------------------------------------------------------ */ -static void pfil_printioctl(mblk_t *mp) -{ - struct iocblk *iocp; - int cmd, num; - char buf[80], l; - - if (!mp || !mp->b_datap || !mp->b_datap->db_base) - return; - iocp = (struct iocblk *)mp->b_rptr; - cmd = iocp->ioc_cmd; - -#ifdef __hpux - sprintf(buf, sizeof(buf), "0x%x=_IO", cmd); -#else - (void)sprintf(buf, "0x%x=_IO", cmd); -#endif - switch (cmd >> 24) - { - case 0x20: - (void)strcat(buf, "V("); - break; - case 0x40: - (void)strcat(buf, "R("); - break; - case 0x80: - (void)strcat(buf, "W("); - break; - case 0xc0: - (void)strcat(buf, "WR("); - break; - default : -#ifdef __hpux - sprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "0x%x(", cmd >> 24); -#else - (void)sprintf(buf + strlen(buf), "0x%x(", cmd >> 24); -#endif - break; - } - - cmd &= 0x00ffffff; - num = cmd & 0xff; - l = (cmd >> 8) & 0xff; -#ifdef __hpux - sprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%c,%d,%d)", l, num, (cmd >> 16) & 0xff); -#else - (void)sprintf(buf + strlen(buf), "%c,%d,%d)", - l, num, (cmd >> 16) & 0xff); -#endif - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(3,(CE_CONT, - "!pfil_printioctl: %s (%d) cr %p id %d flag 0x%x count %ld error %d rval %d\n", - buf, (int)sizeof(*iocp), (void *)iocp->ioc_cr, iocp->ioc_id, - iocp->ioc_flag, iocp->ioc_count, iocp->ioc_error, - iocp->ioc_rval)); - pfil_printmchain(mp); -} -#endif /* PFILDEBUG */ - - -/* ------------------------------------------------------------------------ */ -/* Function: pfilbind */ -/* Returns: int - 0 == success, else error */ -/* Parameters: q(I) - pointer to queue */ -/* */ -/* Check to see if a queue (or the otherside of it) is missing a qif_t */ -/* structure. If neither have one then allocate a new one, else copy the */ -/* q_ptr from one to the other. */ -/* ------------------------------------------------------------------------ */ -int pfilbind(queue_t *q) -{ - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!pfilbind(%p) ptr %p O %p\n", - (void *)q, (void *)q->q_ptr, (void *)OTHERQ(q))); - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, "!R %p %p W %p %p\n", - (void *)RD(q), (void *)RD(q)->q_ptr, - (void *)WR(q), (void *)WR(q)->q_ptr)); - - return qif_attach(q); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfilwput_ioctl */ -/* Returns: void */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to STREAMS message */ -/* */ -/* Handles ioctls for both the STREAMS module and driver. */ -/* ------------------------------------------------------------------------ */ -void pfilwput_ioctl(queue_t *q, mblk_t *mp) -{ - struct iocblk *iocp = (struct iocblk *)mp->b_rptr; - qif_t *qif; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT, - "!pfilwput_ioctl(%p,%p) ioctl(%x,%d,%x,%ld,%d,%d) [%s]\n", - (void *)q, (void *)mp, iocp->ioc_cmd, iocp->ioc_id, - iocp->ioc_flag, iocp->ioc_count, iocp->ioc_rval, - iocp->ioc_error, QTONM(q))); -#ifdef PFILDEBUG - pfil_printioctl(mp); -#endif - - if (iocp->ioc_cr && pfil_drv_priv(iocp->ioc_cr) != 0 ) { - putnext(q, mp); - return; - } - - switch (iocp->ioc_cmd) - { - case DL_IOC_HDR_INFO : - qif = q->q_ptr; - - /* - * Fastpath information ioctl. Update the expected size for - * headers on this queue using to match that in this message. - * Whilst this may not be an IOCACK with the header attached, - * it can also be an indication that something has changed so - * doing an update may not be a bad idea. - * If fastpath headers ever have variable length, this will - * not work. - */ - WRITE_ENTER(&pfil_rw); - qif_update(qif, mp); - RW_EXIT(&pfil_rw); - if (qif->qf_ill != NULL) { - packet_filter_hook_t *pfh; - - READ_ENTER(&pfh_sync.ph_lock); - pfh = pfil_hook_get(PFIL_IN, &pfh_sync); - for (; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func) - (void) (*pfh->pfil_func)(NULL, 0, - qif->qf_ill, - 0, qif, NULL); - RW_EXIT(&pfh_sync.ph_lock); - } - break; - -#if SOLARIS2 >= 10 -#ifdef SIOCSLIFNAME - case SIOCSLIFNAME : - if (miocpullup(mp, sizeof(struct lifreq)) == 0) { - struct lifreq *lifr; - int sap; - - lifr = (struct lifreq *)mp->b_cont->b_rptr; -# ifdef ILLF_IPV6 - sap = (lifr->lifr_flags & ILLF_IPV6) ? IP6_DL_SAP : - IP_DL_SAP; -# else - sap = IP_DL_SAP; -# endif - pfil_addif(RD(q), lifr->lifr_name, sap); - miocack(q, mp, 0, 0); - return; - } - break; -#endif -#else /* pre-S10 */ -#ifdef SIOCGTUNPARAM - case SIOCGTUNPARAM : - qif_attach(q); - break; -#endif -#endif /* pre-S10 */ -#ifdef __hpux - case ND_SET : - case ND_GET : - if (pfil_ioctl_nd(q, mp)) { - if (iocp->ioc_error) - iocp->ioc_count = 0; - mp->b_datap->db_type = M_IOCACK; - qreply(q, mp); - } else { - miocnak(q, mp, 0, EINVAL); - } - return; - break; -#endif - default : - break; - } - - putnext(q, mp); - return; -} - - -#if SOLARIS2 >= 10 -/* - * Update interface configuration data from pfild message. - */ -static void -pfil_update_ifaddrs(mblk_t *mp) -{ - s_ill_t *ill; - int i; - struct pfil_ifaddrs *ifaddrslist = (struct pfil_ifaddrs *)mp->b_rptr; - int numifs; - - if (MLEN(mp) < sizeof(struct pfil_ifaddrs)) - return; - - numifs = MLEN(mp) / sizeof (struct pfil_ifaddrs); - mutex_enter(&s_ill_g_head_lock); - - for (i = 0; i < numifs; i++) { - int sap = AFtoSAP(ifaddrslist[i].localaddr.in.sin_family); - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(3,(CE_CONT,"ifs# %d sin_family %d sap %x\n", i, - ifaddrslist[i].localaddr.in.sin_family, sap)); - - for (ill = s_ill_g_head; ill; ill = ill->ill_next) { - if (strncmp(ifaddrslist[i].name, ill->ill_name, - LIFNAMSIZ) == 0 && - sap == ill->ill_sap) { - bcopy(&ifaddrslist[i].localaddr, - &ill->localaddr, - sizeof (ifaddrslist[i].localaddr)); - bcopy(&ifaddrslist[i].netmask, &ill->netmask, - sizeof (ifaddrslist[i].netmask)); - bcopy(&ifaddrslist[i].broadaddr, - &ill->broadaddr, - sizeof (ifaddrslist[i].broadaddr)); - bcopy(&ifaddrslist[i].dstaddr, &ill->dstaddr, - sizeof (ifaddrslist[i].dstaddr)); - ill->mtu = ifaddrslist[i].mtu; - } - } - } - - mutex_exit(&s_ill_g_head_lock); -} - - -/* - * Update valid address set data from pfild message. - */ -static void pfil_update_ifaddrset(mblk_t *mp) -{ - struct pfil_ifaddrset *ifaddrset = (struct pfil_ifaddrset *)mp->b_rptr; - int sap; - qif_t *qp; - - if (MLEN(mp) < sizeof(struct pfil_ifaddrset)) - return; - - sap = AFtoSAP(ifaddrset->af); - - READ_ENTER(&pfil_rw); - - qp = qif_iflookup(ifaddrset->name, sap); - if (qp != NULL) { - if (qp->qf_addrset != NULL) - freeb(qp->qf_addrset); - qp->qf_addrset = dupb(mp); - } - - RW_EXIT(&pfil_rw); -} -#endif /* SOLARIS2 >= 10 */ - - -/************************************************************************ - * STREAMS device functions - */ -/* ------------------------------------------------------------------------ */ -/* Function: pfilwput */ -/* Returns: void */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to STREAMS message */ -/* */ -/* This is only called for interaction with pfil itself, as the driver */ -/* /dev/pfil, not the STREAMS module pushed on another queue. As it does */ -/* not do any IO, this should never be called except to handle ioctl's and */ -/* so all other messages are free'd and no reply sent back. */ -/* The only ioctls handled by the driver are ND_GET/ND_SET. */ -/* pfilwput also handles PFILCMD_IFADDRS and PFILCMD_IFADDRSET messages. */ -/* NOTE: HP-UX does not need or have pfil implemented as a STREAMS device. */ -/* ------------------------------------------------------------------------ */ -#ifdef sun -void pfilwput(queue_t *q, mblk_t *mp) -{ - struct iocblk *iocp; - uint32_t cmd; - -# ifdef PFILDEBUG - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(9,(CE_CONT, "!pfilwput(%p,%p) [%s] qif %p\n", - (void *)q, (void *)mp, QTONM(q), (void *)q->q_ptr)); -# endif - - switch (MTYPE(mp)) - { -#if SOLARIS2 >= 10 - case M_PROTO: - /* - * Is it a valid PFILCMD message? - */ - if (MLEN(mp) < sizeof(uint32_t) || (mp->b_cont == NULL)) { - /*LINTED: E_CONSTANT_CONDITION*/ - PRINT(10, (CE_NOTE, "invalid PFILCMD")); - break; - } - - /* - * It's a message from pfild. Remember pfild's read queue for - * later use when sending packets; then process this message. - */ - pfildq = RD(q); - cmd = *((uint32_t *)mp->b_rptr); - switch (cmd) { - case PFILCMD_IFADDRS: - pfil_update_ifaddrs(mp->b_cont); - break; - case PFILCMD_IFADDRSET: - pfil_update_ifaddrset(mp->b_cont); - break; - default: - break; - } - break; -#endif - case M_IOCTL: - iocp = (struct iocblk *)mp->b_rptr; - switch (iocp->ioc_cmd) - { - case ND_SET : - case ND_GET : - if (pfil_ioctl_nd(q, mp)) { - if (iocp->ioc_error) - iocp->ioc_count = 0; - mp->b_datap->db_type = M_IOCACK; - qreply(q, mp); - } else { - miocnak(q, mp, 0, EINVAL); - } - break; - - default : - miocnak(q, mp, 0, EINVAL); - break; - } - return; - - default : - break; - } - - freemsg(mp); -} -#endif - - -/************************************************************************ - * STREAMS module functions - */ -/* ------------------------------------------------------------------------ */ -/* Function: pfilmodwput */ -/* Returns: void */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to STREAMS message */ -/* */ -/* This function is called as part of the STREAMS module message processing */ -/* for messages going down to the device drivers. */ -/* ------------------------------------------------------------------------ */ -void pfilmodwput(queue_t *q, mblk_t *mp) -{ - union DL_primitives *dl; - qif_t *qif; - - qif = q->q_ptr; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(9,(CE_CONT, "!pfilmodwput(%p,%p) T:%d [%s,%s] qif %p %p\n", - (void *)q, (void *)mp, MTYPE(mp), QTONM(q), QTONM(OTHERQ(q)), - (void *)qif, (void *)qif->qf_ill)); - - switch (MTYPE(mp)) - { - case M_PROTO : - case M_PCPROTO : - dl = (union DL_primitives *)mp->b_rptr; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(7,(CE_CONT, "!pfilmodwput: %p dl_primitive:%d\n", - (void *)mp, dl->dl_primitive)); - - if ((MLEN(mp) < sizeof(dl_unitdata_req_t)) || - (dl->dl_primitive != DL_UNITDATA_REQ)) { - break; - } - - /*FALLTHROUGH*/ - case M_DATA : - atomic_add_long(&qif->qf_nw, 1); - - if (qif->qf_ill != NULL) { - int i; - - i = pfil_precheck(q, &mp, PFIL_OUT, qif); - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(9, (CE_CONT, "!%s: pfil_precheck=%d mp %p\n", - "pfilmodwput", i, (void *)mp)); - if (mp == NULL) - return; - else if (i > 0) { - freemsg(mp); - return; - } - } - break; - - case M_IOCTL : - pfilwput_ioctl(q, mp); - return; - - default : - break; - } - - putnext(q, mp); - return; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfilmodrput */ -/* Returns: void */ -/* Parameters: q(I) - pointer to queue */ -/* mp(I) - pointer to STREAMS message */ -/* */ -/* This function is called as part of the STREAMS module message processing */ -/* for messages going up to the protocol stack. */ -/* ------------------------------------------------------------------------ */ -void pfilmodrput(queue_t *q, mblk_t *mp) -{ - union DL_primitives *dl; - dl_bind_ack_t *b; - int i, flags; - qif_t *qif; - - flags = 0; - qif = q->q_ptr; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(9,(CE_CONT, "!pfilmodrput(%p,%p) T:%d [%s,%s] qif %p %p\n", - (void *)q, (void *)mp, mp->b_datap->db_type, QTONM(q), - QTONM(OTHERQ(q)), (void *)qif, - (void *)qif->qf_ill)); - - switch (MTYPE(mp)) - { -#ifdef DL_IOC_HDR_INFO - case M_IOCACK : - { - struct iocblk *iocp = (struct iocblk *)mp->b_rptr; - - if (iocp->ioc_cmd == DL_IOC_HDR_INFO) { - WRITE_ENTER(&pfil_rw); - qif_update(qif, mp); - RW_EXIT(&pfil_rw); - } - /*FALLTHROUGH*/ - } -#endif /* DL_IOC_HDR_INFO */ -#ifdef PFILDEBUG - case M_IOCNAK : - case M_IOCTL : - pfil_printioctl(mp); -#endif - break; - - case M_PROTO : - case M_PCPROTO : - - dl = (union DL_primitives *)mp->b_rptr; - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(7,(CE_CONT, "!mp:%p pfilmodrput:dl_primitive:%d\n", - (void *)mp, dl->dl_primitive)); - - switch (dl->dl_primitive) - { - case DL_UNITDATA_IND : - if ((MLEN(mp) >= sizeof(dl_unitdata_ind_t)) && - (dl->unitdata_ind.dl_group_address)) - flags |= PFIL_GROUP; - break; - - case DL_SUBS_BIND_ACK : - if (qif->qf_waitack > 0) { - dl_subs_bind_ack_t *c; - - c = (dl_subs_bind_ack_t *)dl; - if (qif->qf_sap == 0) { -#if 0 - qif->qf_sap = c->dl_sap; - if (qif->qf_sap < 0) - qif->qf_sap = -qif->qf_sap; -#else - cmn_err(CE_NOTE, "c:off %u len %u", - c->dl_subs_sap_offset, - c->dl_subs_sap_length); -#endif - } - - (void) pfilbind(q); - if (qif->qf_waitack > 0) - qif->qf_waitack--; - } - break; - - case DL_BIND_ACK : - b = (dl_bind_ack_t *)dl; - if (qif->qf_sap == 0) { - qif->qf_sap = b->dl_sap; - if (qif->qf_sap < 0) - qif->qf_sap = -qif->qf_sap; - } - - if (b->dl_sap == IEEESAP_SNAP) { - qif->qf_waitack++; - break; - } - - if (!b->dl_sap || b->dl_sap == IP_DL_SAP || - b->dl_sap == IP6_DL_SAP) - (void) pfilbind(q); - break; - - default : - break; - } - - if ((MLEN(mp) < sizeof(dl_unitdata_ind_t)) || - (dl->dl_primitive != DL_UNITDATA_IND)) - break; - - /*FALLTHROUGH*/ - case M_DATA : - atomic_add_long(&qif->qf_nr, 1); - - if (qif->qf_ill != NULL) { - flags |= PFIL_IN; - i = pfil_precheck(q, &mp, flags, qif); - - /* LINTED: E_CONSTANT_CONDITION */ - PRINT(9, (CE_CONT, - "!pfilmodrput: mp %p pfil_precheck=%d\n", - (void *)mp, i)); - if (mp == NULL) - return; - else if (i > 0) { - freemsg(mp); - return; - } - } - break; - - default : - break; - } - - putnext(q, mp); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_drv_priv */ -/* Returns: int - 0 == success, EPERM for error. */ -/* Parameters: cr(I) - pointer to credential information */ -/* */ -/* Checks to see if the caller has enough credentials. */ -/* ------------------------------------------------------------------------ */ -static int pfil_drv_priv(cred_t *cr) -{ -#if SOLARIS2 >= 10 - return (secpolicy_net_config(cr, B_TRUE)); -#else -# ifdef sun - return (suser(cr) ? 0 : EPERM); -# else - return (suser() ? 0 : EPERM); -# endif -#endif -} - - -/************************************************************************ - * kernel module initialization - */ -/* ------------------------------------------------------------------------ */ -/* Function: pfil_startup */ -/* Returns: void */ -/* Parameters: None. */ -/* */ -/* Initialise pfil data strutures. */ -/* ------------------------------------------------------------------------ */ -void pfil_startup() -{ - pfil_init(&pfh_inet4); - pfil_init(&pfh_inet6); - pfil_init(&pfh_sync); -} diff --git a/usr/src/uts/common/inet/pfil/pkt.c b/usr/src/uts/common/inet/pfil/pkt.c deleted file mode 100644 index 5c0bd72ddc..0000000000 --- a/usr/src/uts/common/inet/pfil/pkt.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2000, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef __hpux -#pragma ident "%Z%%M% %I% %E% SMI" -#endif - -#include <sys/types.h> -#include <sys/stream.h> -#include <sys/cmn_err.h> -#include <sys/ddi.h> -#include <sys/rwlock.h> -#include <sys/socket.h> - -#include <net/if.h> -#include <netinet/in_systm.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#if SOLARIS2 >= 8 -# include <netinet/ip6.h> -#else -# include <net/if_dl.h> -#endif - -#undef IPOPT_EOL -#undef IPOPT_NOP -#undef IPOPT_RR -#undef IPOPT_LSRR -#undef IPOPT_SSRR -#include <inet/common.h> -#include <inet/ip.h> -#if SOLARIS2 >= 8 -#include <inet/ip6.h> -#endif -#include <inet/ip_ire.h> -#include <inet/ip_if.h> - -#include "compat.h" -#include "qif.h" - - -extern krwlock_t pfil_rw; -extern queue_t *pfildq; - -#if 1 -/* ------------------------------------------------------------------------ */ -/* Function: pfil_make_dl_packet (mb, ip, dst, ifname, output_q) */ -/* Returns: On success, datalink msg block. */ -/* On failure, NULL. */ -/* Parameters: */ -/* mblk_t *mb: IP message block */ -/* struct ip *ip: ip header start pointer */ -/* void *dst: destination address. */ -/* if it is null, destination address is in ip */ -/* for IPV4, the parameter should be an instance of in_addr */ -/* for IPV6, the parameter should be an instance of in6_addr */ -/* char *ifname: output interface name */ -/* if neither of dst and ifname is NULL, the routing for dst */ -/* should have same interface name as ifname; */ -/* If ifname is NULL, output interface name is not specified */ -/* so it is decided by routing table. */ -/* if dst is NULL(ifname is not NULL), destination address */ -/* in IP packet will be used for routing lookup, and the packet */ -/* will be send out to interface ifname */ -/* queue_t **output_q: the write queue of pfil module where the */ -/* returned message block can be putnext */ -/* */ -/* This function is called to make a datalink message based on the IP */ -/* message block mb, If the function successfully returns, output_q */ -/* is set to the pfil module's write queue of output interface. Please use */ -/* pfil_send_dl_packet to putnext the returned packet to output_q. */ -/* */ -/* This function will return with a 'lock' held on the qif structure via */ -/* the PT_ENTER_READ() macro if qif_iflookup succeeds. This lock is then */ -/* intended to be released when the queue returned is no longer referenced. */ -/* */ -/* fr_fastroute, fr_send_icmp_err, fr_send_reset will call this func to */ -/* prepare packet. */ -/* */ -/* ip_nexthop[_route] is called to search routing info in this func. */ -/* ------------------------------------------------------------------------ */ -mblk_t *pfil_make_dl_packet(mb, ip, dst, ifname, output_q) -mblk_t *mb; -struct ip *ip; -void *dst; -char *ifname; -queue_t **output_q; -{ - mblk_t *mp; - qif_t *qif; - int ip_inf_bind = 0; - char out_ifname_buf[LIFNAMSIZ]; - struct sockaddr_storage target; - int sap; - - if (ip->ip_v == IPV4_VERSION) { - struct sockaddr_in *target_in; - target_in = (struct sockaddr_in *)⌖ - sap = IP_DL_SAP; - target_in->sin_family = AF_INET; - if (dst == NULL) - target_in->sin_addr = ip->ip_dst; - else { - target_in->sin_addr.s_addr = *(ipaddr_t *)dst; - if (ifname != NULL) - ip_inf_bind = 1; - } - } -#ifdef USE_INET6 - else if (ip->ip_v == IPV6_VERSION) { - struct sockaddr_in6 *target_in6; - target_in6 = (struct sockaddr_in6 *)⌖ - sap = IP6_DL_SAP; - target_in6->sin6_family = AF_INET6; - if (dst == NULL) - target_in6->sin6_addr = ((ip6_t *)ip)->ip6_dst; - else { - bcopy(dst, &target_in6->sin6_addr, - sizeof(struct in6_addr)); - if (ifname != NULL) - ip_inf_bind = 1; - } - } -#endif - - if (ip_inf_bind) - mp = ip_nexthop((struct sockaddr *)&target, ifname); - else { - mp = ip_nexthop_route((struct sockaddr *)&target, - out_ifname_buf); - if (ifname == NULL) - ifname = out_ifname_buf; - } - - if (mp == NULL) - return NULL; - - /* - * Sometimes the ip_nexthop* functions can't give us a usable packet - * header, for example, when the (nexthop) destination is in need of - * address resolution. We'd like to punt our packet up to pfild and - * let it send the packet through the normal IP mechanisms, which will - * handle ARP/ND, but if the packet is being sent to an explicit router - * there is no way pfild can indicate that to the IP stack. So in - * desperation, we discard the packet we are working on and instead - * construct an IP packet with ip_p == 0 to the nexthop router and let - * pfild send that. This will start the ARP/ND resolution process - * so that next time we need to send a packet to that router, the IRE - * cache is all ready to go. - */ - if ((MTYPE(mp) == M_PROTO) && (dst != NULL)) - if ((ip->ip_v == IPV4_VERSION) && - (ip->ip_dst.s_addr != *(ipaddr_t *)dst)) { - - ASSERT(MTYPE(mb) == M_DATA); - if (mb->b_cont != NULL) { - freemsg(mb->b_cont); - mb->b_cont = NULL; - } - - /* - * We don't bother to calculate the IP checksum, raw - * socket will finally do it. - */ - ip = (struct ip *)mb->b_rptr; - ip->ip_hl = 5; - ip->ip_tos = 0; - ip->ip_len = sizeof (struct ip); - ip->ip_id = 0; - ip->ip_off = 0; - ip->ip_ttl = 1; - ip->ip_p = 0; - ip->ip_src = *(struct in_addr *)dst; - ip->ip_dst = *(struct in_addr *)dst; - - mb->b_wptr = mb->b_rptr + sizeof (struct ip); - } - - /* look for output queue */ - rw_enter(&pfil_rw, RW_READER); - qif = (qif_t *)qif_iflookup(ifname, sap); - if (qif == NULL) { - rw_exit(&pfil_rw); - freeb(mp); - return NULL; - } - - PT_ENTER_READ(&qif->qf_ptl); - *output_q = WR(qif->qf_q); - rw_exit(&pfil_rw); - - /* OK, by now, we can link the IP message to lay2 header */ - linkb(mp, mb); - mb = mp; - - return mb; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_send_dl_packet (output_q, mb) */ -/* Returns: void */ -/* Parameters: */ -/* queue_t *output_q: pfil module's write queue */ -/* mblk_t *mb: Lay2 message block. This parameter should be the return */ -/* value of pfil_make_layer2_packet */ -/* This function is called to send the packet returned by */ -/* pfil_make_dl_packet. */ -/* In this function, PT_EXIT_READ is used after the putnext call to release */ -/* the qif structure held by function pfil_make_layer2_packet. */ -/* ------------------------------------------------------------------------ */ -void pfil_send_dl_packet(output_q, mb) -queue_t *output_q; -mblk_t *mb; -{ - qif_t *qif; - - /* - * NOTE: It is not permitted to hold a lock across putnext() so we - * use a semaphore-like operation to signal when it is ok to delete - * the qif structure. With the current locking structure, putnext() - * may be called here after qprocsoff() has been called on output_q, - * but before the queue was completely closed. See pfilmodclose(). - */ - - if (MTYPE(mb) == M_PROTO && pfildq != NULL) { - /* - * If pfil_make_dl_packet() returned an M_PROTO message it's - * probably an ARP AR_ENTRY_QUERY message, which we can't - * handle, so we just send the IP packet up to pfild to - * transmit it via a raw socket. - */ - putnext(pfildq, mb->b_cont); - mb->b_cont = NULL; - freemsg(mb); - } else { - putnext(output_q, mb); - } - - qif = output_q->q_ptr; - PT_EXIT_READ(&qif->qf_ptl); -} - -#else /* pfil_sendbuf implementation for no IRE_ILL_CN definition */ - -/* ------------------------------------------------------------------------ */ -/* Function: pfil_sendbuf */ -/* Returns: int - 0 == success, 1 == failure */ -/* Parameters: m(I) - pointer to streams message */ -/* */ -/* Output an IPv4 packet to whichever interface has the correct route. */ -/* ------------------------------------------------------------------------ */ -int pfil_sendbuf(m) -mblk_t *m; -{ - queue_t *q = NULL; - struct ip *ip; - size_t hlen; - ire_t *dir; - u_char *s; - ill_t *il; - - ip = (struct ip *)m->b_rptr; - -#ifdef MATCH_IRE_DSTONLY - dir = ire_route_lookup(ip->ip_dst.s_addr, 0xffffffff, 0, 0, - NULL, NULL, NULL, - MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT| - MATCH_IRE_RECURSIVE); -#else - dir = ire_lookup(ip->ip_dst.s_addr); -#endif - - if (dir) { -#if SOLARIS2 < 8 - if (!dir->ire_ll_hdr_mp || !dir->ire_ll_hdr_length) -#elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) - if (!dir->ire_fp_mp || !dir->ire_dlureq_mp) -#else - if (dir->ire_nce && dir->ire_nce->nce_state != ND_REACHABLE) -#endif - return 2; - } - - if (dir) { - mblk_t *mp, *mp2; - - il = ire_to_ill(dir); - if (!il) - return 2; -#if SOLARIS2 < 8 - mp = dir->ire_ll_hdr_mp; - hlen = dir->ire_ll_hdr_length; - -#elif ((SOLARIS2 >= 8) && (SOLARIS2 <= 10) - mp = dir->ire_fp_mp; - hlen = mp ? mp->b_wptr - mp->b_rptr : 0; - mp = dir->ire_dlureq_mp; -#else - mp = dir->ire_nce->nce_fp_mp; - hlen = mp ? mp->b_wptr - mp->b_rptr : 0; - mp = dir->ire_nce->nce_res_mp; -#endif - s = (u_char *)ip; - - if (hlen && -#ifdef ICK_M_CTL_MAGIC - (il->ill_ick.ick_magic != ICK_M_CTL_MAGIC) && -#endif - (s - m->b_datap->db_base) >= hlen) { - s -= hlen; - m->b_rptr = (u_char *)s; - bcopy((char *)mp->b_rptr, (char *)s, hlen); - } else { - mp2 = copyb(mp); - if (!mp2) - goto bad_nexthop; - mp2->b_cont = m; - m = mp2; - } - - if (dir->ire_stq) - q = dir->ire_stq; - else if (dir->ire_rfq) - q = WR(dir->ire_rfq); - if (q) - q = q->q_next; - if (q) { - RW_EXIT(&pfil_rw); - putnext(q, m); - READ_ENTER(&pfil_rw); - return 0; - } - } -bad_nexthop: - freemsg(m); - return 1; -} -#endif /* 1 */ diff --git a/usr/src/uts/common/inet/pfil/qif.c b/usr/src/uts/common/inet/pfil/qif.c deleted file mode 100644 index ec1ec676f2..0000000000 --- a/usr/src/uts/common/inet/pfil/qif.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Copyright (C) 2000, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/systm.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/errno.h> -#include <sys/uio.h> -#include <sys/buf.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/modctl.h> -#include <sys/open.h> -#include <sys/kmem.h> -#include <sys/conf.h> -#include <sys/cmn_err.h> -#include <sys/stat.h> -#include <sys/cred.h> -#include <sys/dditypes.h> -#include <sys/stream.h> -#include <sys/poll.h> -#include <sys/autoconf.h> -#include <sys/byteorder.h> -#include <sys/socket.h> -#include <sys/dlpi.h> -#include <sys/stropts.h> -#include <sys/sockio.h> -#include <sys/ethernet.h> -#include <net/if.h> -#if SOLARIS2 >= 6 -# include <net/if_types.h> -# if SOLARIS2 >= 8 -# include <netinet/ip6.h> -# endif -# include <net/if_dl.h> -#endif -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <inet/common.h> -#undef IPOPT_EOL -#undef IPOPT_NOP -#undef IPOPT_LSRR -#undef IPOPT_SSRR -#undef IPOPT_RR -#include <inet/ip.h> -#include <inet/ip_if.h> -#include <inet/ip_ire.h> - -#include "compat.h" -#include "qif.h" -#include "pfil.h" - - -#if SOLARIS2 >= 6 -static size_t hdrsizes[57][2] = { - { 0, 0 }, - { IFT_OTHER, 0 }, - { IFT_1822, 0 }, - { IFT_HDH1822, 0 }, - { IFT_X25DDN, 0 }, - { IFT_X25, 0 }, - { IFT_ETHER, 14 }, - { IFT_ISO88023, 0 }, - { IFT_ISO88024, 0 }, - { IFT_ISO88025, 0 }, - { IFT_ISO88026, 0 }, - { IFT_STARLAN, 0 }, - { IFT_P10, 0 }, - { IFT_P80, 0 }, - { IFT_HY, 0 }, - { IFT_FDDI, 24 }, - { IFT_LAPB, 0 }, - { IFT_SDLC, 0 }, - { IFT_T1, 0 }, - { IFT_CEPT, 0 }, - { IFT_ISDNBASIC, 0 }, - { IFT_ISDNPRIMARY, 0 }, - { IFT_PTPSERIAL, 0 }, - { IFT_PPP, 0 }, - { IFT_LOOP, 0 }, - { IFT_EON, 0 }, - { IFT_XETHER, 0 }, - { IFT_NSIP, 0 }, - { IFT_SLIP, 0 }, - { IFT_ULTRA, 0 }, - { IFT_DS3, 0 }, - { IFT_SIP, 0 }, - { IFT_FRELAY, 0 }, - { IFT_RS232, 0 }, - { IFT_PARA, 0 }, - { IFT_ARCNET, 0 }, - { IFT_ARCNETPLUS, 0 }, - { IFT_ATM, 0 }, - { IFT_MIOX25, 0 }, - { IFT_SONET, 0 }, - { IFT_X25PLE, 0 }, - { IFT_ISO88022LLC, 0 }, - { IFT_LOCALTALK, 0 }, - { IFT_SMDSDXI, 0 }, - { IFT_FRELAYDCE, 0 }, - { IFT_V35, 0 }, - { IFT_HSSI, 0 }, - { IFT_HIPPI, 0 }, - { IFT_MODEM, 0 }, - { IFT_AAL5, 0 }, - { IFT_SONETPATH, 0 }, - { IFT_SONETVT, 0 }, - { IFT_SMDSICIP, 0 }, - { IFT_PROPVIRTUAL, 0 }, - { IFT_PROPMUX, 0 }, -}; -#endif /* SOLARIS2 >= 6 */ - - -#if SOLARIS2 <= 6 -# include <sys/kmem_impl.h> -#endif -#if SOLARIS2 >= 10 -extern krwlock_t ill_g_lock; -#endif - -#define SAPNAME(x) ((x)->qf_sap == 0x0800 ? "IPv4" : \ - (x)->qf_sap == 0x86dd ? "IPv6" : "??") - -static int qif_num = 0; -static kmem_cache_t *qif_cache = NULL; - -qif_t *qif_head; -int qif_verbose = 0; - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_startup */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: None. */ -/* */ -/* Perform any initialisation of data structures related to managing qif's */ -/* that is deemed necessary. */ -/* ------------------------------------------------------------------------ */ -int qif_startup() -{ - - qif_head = NULL; - qif_cache = kmem_cache_create("qif_head_cache", sizeof(qif_t), 8, - NULL, NULL, NULL, NULL, NULL, 0); - if (qif_cache == NULL) { - cmn_err(CE_NOTE, "qif_startup:kmem_cache_create failed"); - return -1; - } - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_stop */ -/* Returns: void */ -/* Parameters: None. */ -/* */ -/* Deallocate all qif_t's allocated and clean up any other data structures */ -/* required in order to 'shut down' this part of the pfil module. */ -/* ------------------------------------------------------------------------ */ -void qif_stop() -{ - kmem_cache_destroy(qif_cache); - qif_cache = NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: q_to_ill */ -/* Returns: void * - NULL == failure, else pointer to ill */ -/* Parameters: rq(I) - pointer to STREAMS read queue */ -/* Locks: pfil_rw */ -/* */ -/* Given a pointer to a queue, try and find the ill which owns it. */ -/* ------------------------------------------------------------------------ */ -void *q_to_ill(rq) -queue_t *rq; -{ -#ifndef IRE_ILL_CN - ill_t *ill = NULL; - queue_t *qu, *wq; - - wq = OTHERQ(rq); - if (rq) { -#if SOLARIS2 >= 10 - ill_walk_context_t ctx; - - rw_enter(&ill_g_lock, RW_READER); - for (ill = ILL_START_WALK_ALL(&ctx); ill != NULL; - ill = ill_next(&ctx, ill)) -#else - for (ill = ill_g_head; ill != NULL; ill = ill->ill_next) -#endif - { - if (ill->ill_rq == NULL || ill->ill_wq == NULL) - continue; - if (ill->ill_rq == RD(rq)->q_next) - break; - for (qu = WR(ill->ill_rq); qu; qu = qu->q_next) - if ((qu->q_ptr == rq->q_ptr) || (qu == wq)) - break; - if (qu != NULL) - break; - for (qu = ill->ill_rq; qu; qu = qu->q_next) - if (qu->q_ptr == rq->q_ptr) - break; - if (qu != NULL) - break; - } - } -#if SOLARIS2 >= 10 - rw_exit(&ill_g_lock); -#endif - return ill; -#else /* IRE_ILL_CN */ - s_ill_t *ill = NULL; - - if (!rq) - return 0; - - ASSERT(rq->q_flag & QREADR); - - mutex_enter(&s_ill_g_head_lock); - for (ill = s_ill_g_head; ill; ill = ill->ill_next) - if (ill->ill_rq == rq) - break; - mutex_exit(&s_ill_g_head_lock); - - return ill; -#endif -} - - -#ifndef IRE_ILL_CN -/* ------------------------------------------------------------------------ */ -/* Function: qif_ire_walker */ -/* Returns: void */ -/* Parameters: ire(I) - pointer to an ire_t */ -/* arg(I) - pointer to a qif */ -/* */ -/* This function gets called by the ire-walking function for each ire in */ -/* table. We enumerate through the ire looking for cached fastpath headers */ -/* on a given NIC (the qif) so we can update qf_hl from its size. */ -/* ------------------------------------------------------------------------ */ -void -qif_ire_walker(ire, arg) - ire_t *ire; - void *arg; -{ - qif_t *qif = arg; - - if ((ire->ire_type == IRE_CACHE) && -#if SOLARIS2 >= 6 - (ire->ire_ipif != NULL) && - (ire->ire_ipif->ipif_ill == qif->qf_ill) -#else - (ire_to_ill(ire) == qif->qf_ill) -#endif - ) { -#if SOLARIS2 < 8 - mblk_t *m = ire->ire_ll_hdr_mp; -#elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) - mblk_t *m = ire->ire_fp_mp; -#else - mblk_t *m = ire->ire_nce->nce_fp_mp; -#endif - if (m != NULL) - qif->qf_hl = m->b_wptr - m->b_rptr; - } -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_attach */ -/* Returns: int - 0 == success, -1 == error in attaching qif_t to q */ -/* Parameters: rq(I) - pointer to STREAMS read queue */ -/* Write Lock: pfil_rw */ -/* */ -/* Attempt to bind a qif_t structure to a specific interface given the */ -/* queue pointer. Assumes the queue already has a qif_t structure tagged */ -/* against it. */ -/* ------------------------------------------------------------------------ */ -int -qif_attach(rq) - queue_t *rq; -{ - packet_filter_hook_t *pfh; - qif_t *qif; -#ifdef IRE_ILL_CN - s_ill_t *ill; -#else - ill_t *ill; -#endif - - WRITE_ENTER(&pfil_rw); - /* - * Can we map the queue to a specific ill? If not, go no futher, we - * are only interested in being associated with queues that we can - * recognise as being used for IP communication of some sort. - */ - ill = q_to_ill(rq); - if (ill == NULL) { - if (qif_verbose > 0) - cmn_err(CE_NOTE, - "PFIL: cannot find interface for rq %p", - (void *)rq); - RW_EXIT(&pfil_rw); - return -1; - } - - qif = rq->q_ptr; -#ifndef IRE_ILL_CN -#if SOLARIS2 < 8 - qif->qf_hl = ill->ill_hdr_length; -#else - if ((ill->ill_type > 0) && (ill->ill_type < 0x37) && - (hdrsizes[ill->ill_type][0] == ill->ill_type)) - qif->qf_hl = hdrsizes[ill->ill_type][1]; - - if (qif->qf_hl == 0 && ill->ill_type != IFT_OTHER) { - cmn_err(CE_WARN, - "!Unknown layer 2 header size for %s type %d sap %x\n", - qif->qf_name, ill->ill_type, ill->ill_sap); - } -#endif -#endif /* IRE_ILL_CN */ - - /* - * Protect against the qif_t being bound against an interface, twice - * by getting a lock on setting qf_bound and don't release it until - * all the information has been set with qf_bound finally set to 1 - * after that. - */ - if (qif->qf_bound == 1) { - RW_EXIT(&pfil_rw); - return 0; - } - - qif->qf_sap = ill->ill_sap; -#ifndef IRE_ILL_CN - qif->qf_ppa = ill->ill_ppa; -#endif -#ifdef icmp_nextmtu - qif->qf_max_frag = ill->ill_max_frag; -#endif - (void) strncpy(qif->qf_name, ill->ill_name, sizeof(qif->qf_name)); - qif->qf_name[sizeof(qif->qf_name) - 1] = '\0'; - qif->qf_ill = ill; - qif->qf_bound = 1; - qif_ipmp_syncslave(qif, qif->qf_sap); - RW_EXIT(&pfil_rw); - - READ_ENTER(&pfh_sync.ph_lock); - - pfh = pfil_hook_get(PFIL_IN, &pfh_sync); - for (; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func) - (void) (*pfh->pfil_func)(NULL, 0, qif, 0, qif, NULL); - - RW_EXIT(&pfh_sync.ph_lock); - - if (qif_verbose > 0) - cmn_err(CE_NOTE, "PFIL: attaching [%s] - %s", qif->qf_name, - SAPNAME(qif)); -#if SOLARIS2 <= 8 - ire_walk(qif_ire_walker, qif); -#else -# ifndef IRE_ILL_CN - ire_walk(qif_ire_walker, (char *)qif); -# endif -#endif - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_new */ -/* Returns: qif_t * - NULL == failure, else pointer to qif_t */ -/* Parameters: q(I) - pointer to STREAMS queue */ -/* */ -/* Allocate a new qif struct, give it a unique number and add it to the */ -/* list of registered qif_t's for the given queue. Along the way, if we */ -/* find an existing qif_t for this queue, return that instead. */ -/* ------------------------------------------------------------------------ */ -qif_t * -qif_new(q, mflags) - queue_t *q; - int mflags; -{ - qif_t *qif; - - qif = kmem_cache_alloc(qif_cache, mflags); - if (qif == NULL) { - cmn_err(CE_NOTE, "PFIL: malloc(%d) for qif_t failed", - (int)sizeof(qif_t)); - return NULL; - } - - bzero((char *)qif, sizeof(*qif)); - mutex_init(&qif->qf_ptl.pt_lock, NULL, MUTEX_DRIVER, NULL); - cv_init(&qif->qf_ptl.pt_cv, NULL, CV_DRIVER, NULL); - qif->qf_qifsz = sizeof(*qif); - qif->qf_q = q; - qif->qf_oq = OTHERQ(q); - WRITE_ENTER(&pfil_rw); - qif->qf_num = qif_num++; - qif->qf_next = qif_head; - qif_head = qif; - RW_EXIT(&pfil_rw); - (void) sprintf(qif->qf_name, "QIF%x", qif->qf_num); - return qif; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_delete */ -/* Returns: void */ -/* Parameters: None. */ -/* Write Locks: pfil_rw */ -/* */ -/* Remove a qif structure from the list of recognised qif's. */ -/* */ -/* NOTE: The locking structure used here on qif's is to protect their use */ -/* by the pkt.c functions for sending out a packet. It is possible that a */ -/* packet will be processed on one queue and need to be output on another */ -/* and given we cannot hold a lock across putnext() we need to use a P-V */ -/* like algorithm for locking. The PT_* macros come from the PTY code. */ -/* In the fullness of time, this function should be rewritten to make sure */ -/* that it is not posible to find the qif before we call the PT_* macros */ -/* and call qprocsoff(). */ -/* ------------------------------------------------------------------------ */ -/*ARGSUSED*/ -void qif_delete(qif, q) -qif_t *qif; -queue_t *q; -{ - packet_filter_hook_t *pfh; - qif_t **qp; - int rm = 0; - - if (qif == NULL) - return; - - WRITE_ENTER(&pfil_rw); - PT_ENTER_WRITE(&qif->qf_ptl); - - if (qif->qf_bound == 1 && qif_verbose > 0) - cmn_err(CE_NOTE, "PFIL: detaching [%s] - %s", qif->qf_name, - SAPNAME(qif)); - - for (qp = &qif_head; *qp; qp = &(*qp)->qf_next) - if (*qp == qif) { - *qp = qif->qf_next; - rm = 1; - break; - } - PT_EXIT_WRITE(&qif->qf_ptl); - RW_EXIT(&pfil_rw); - - if (qif->qf_ill) { - READ_ENTER(&pfh_sync.ph_lock); - pfh = pfil_hook_get(PFIL_OUT, &pfh_sync); - for (; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func) - (void) (*pfh->pfil_func)(NULL, 0, qif, - 1, qif, NULL); - RW_EXIT(&pfh_sync.ph_lock); - } - - if (rm) { - if (qif->qf_addrset != NULL) - freeb(qif->qf_addrset); - mutex_destroy(&qif->qf_ptl.pt_lock); - cv_destroy(&qif->qf_ptl.pt_cv); - - if (qif->qf_qifsz == sizeof(*qif)) - kmem_cache_free(qif_cache, qif); - else { - KMFREE(qif, qif->qf_qifsz); - } - } - return; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_iflookup */ -/* Returns: void * - NULL == search failed, else pointer to qif_t */ -/* Parameters: name(I) - pointer to the name */ -/* sap(I) - SAP value */ -/* Locks: pfil_rw */ -/* */ -/* Search the list of registered qif_t's for a match based on the name and */ -/* the SAP and return a pointer to the matching entry. */ -/* ------------------------------------------------------------------------ */ -void *qif_iflookup(char *name, int sap) -{ - qif_t *qif; - - for (qif = qif_head; qif; qif = qif->qf_next) - if ((!sap || (qif->qf_sap == sap)) && - !strcmp(qif->qf_name, name)) - break; - return qif; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_update */ -/* Returns: void */ -/* Parameters: qif(I) - pointer to qif_t structure */ -/* mp(I) - pointer to STREAMS message */ -/* Locks: pfil_rw */ -/* */ -/* This function attempts to force an update of the qf_sap and qf_hl fields */ -/* using information that is in the STREAMS message and/or the ill_t. This */ -/* function should only be called if the mblk is a DL_IOC_HDR_INFO message. */ -/* ------------------------------------------------------------------------ */ -void qif_update(qif, mp) -qif_t *qif; -mblk_t *mp; -{ -#ifdef IRE_ILL_CN - s_ill_t *ill; -#else - ill_t *ill; -#endif - - ill = qif->qf_ill; - if (ill == NULL) - return; - - if (mp->b_datap->db_type == M_IOCACK && mp->b_cont) { - mp = mp->b_cont; - if (mp->b_datap->db_type == M_PROTO && mp->b_cont) { - mp = mp->b_cont; - if (mp->b_datap->db_type == M_DATA) { - qif->qf_hl = mp->b_wptr - mp->b_rptr; - } - } - } - - /* - * If we still have a 0 size expected fasthpath header length, check - * the ill structure to see if we can use it to now make a better - * guess about what to use. - */ - qif->qf_sap = ill->ill_sap; -#ifndef IRE_ILL_CN - if (qif->qf_hl == 0) { -#if SOLARIS2 < 8 - qif->qf_hl = ill->ill_hdr_length; -#else - if ((ill->ill_type > 0) && (ill->ill_type < 0x37) && - (hdrsizes[ill->ill_type][0] == ill->ill_type)) - qif->qf_hl = hdrsizes[ill->ill_type][1]; -#endif - } -#endif -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_walk */ -/* Returns: qif_t * - NULL == search failed, else pointer to qif_t */ -/* Parameters: qfp(IO) - pointer to the name */ -/* */ -/* NOTE: it is assumed the caller has a lock on pfil_rw */ -/* */ -/* Provide a function to enable the caller to enumerate through all of the */ -/* qif_t's without being aware of the internal data structure used to store */ -/* them in. */ -/* ------------------------------------------------------------------------ */ -qif_t *qif_walk(qif_t **qfp) -{ - struct qif *qf, *qf2; - - if (qfp == NULL) - return NULL; - - qf = *qfp; - if (qf == NULL) - *qfp = qif_head; - else { - /* - * Make sure the pointer being passed in exists as a current - * object before returning its next value. - */ - for (qf2 = qif_head; qf2 != NULL; qf2 = qf2->qf_next) - if (qf2 == qf) - break; - if (qf2 == NULL) - *qfp = NULL; - else - *qfp = qf->qf_next; - } - return *qfp; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_update */ -/* Returns: void */ -/* Parameters: ipmpconf(I) - pointer to an ill to match against */ -/* */ -/* Take an IPMP configuration string passed in to update the pfil config. */ -/* The string may either indicate that an IPMP interface is to be deleted */ -/* ("ipmp0=" - no NICs after the right of the '=') or created/changed if */ -/* there is text after the '='. */ -/* ------------------------------------------------------------------------ */ -void qif_ipmp_update(char *ipmpconf) -{ - qif_t *qif, *qf; - int len, sap; - char *s; - - sap = ETHERTYPE_IP; - if (!strncmp(ipmpconf, "v4:", 3)) { - ipmpconf += 3; - } else if (!strncmp(ipmpconf, "v6:", 3)) { -#if SOLARIS2 >= 8 - sap = IP6_DL_SAP; - ipmpconf += 3; -#else - return; -#endif - } - - s = strchr(ipmpconf, '='); - if (s != NULL) { - if (*(s + 1) == '\0') - *s = '\0'; - else - *s++ = '\0'; - } - if (s == NULL || *s == NULL) { - qif_ipmp_delete(ipmpconf); - return; - } - - len = sizeof(qif_t) + strlen(s) + 1; - KMALLOC(qif, qif_t *, len, KM_NOSLEEP); - if (qif == NULL) { - cmn_err(CE_NOTE, "PFIL: malloc(%d) for qif_t failed", len); - return; - } - - WRITE_ENTER(&pfil_rw); - for (qf = qif_head; qf; qf = qf->qf_next) - if (strcmp(qf->qf_name, ipmpconf) == 0) - break; - - if (qf == NULL) { - qf = qif; - qif->qf_next = qif_head; - qif_head = qif; - - qif->qf_sap = sap; - qif->qf_flags |= QF_IPMP; - qif->qf_qifsz = len; - qif->qf_members = (char *)qif + sizeof(*qif); - (void) strcpy(qif->qf_name, ipmpconf); - } else { - KMFREE(qif, len); - qif = qf; - } - - (void) strcpy(qif->qf_members, s); - - qif_ipmp_syncmaster(qif, sap); - - RW_EXIT(&pfil_rw); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_delete */ -/* Returns: void */ -/* Parameters: qifname(I) - pointer to name of qif to delete */ -/* */ -/* Search for a qif structure that is named to match qifname, remove all */ -/* references to it by others, delink and free it. */ -/* ------------------------------------------------------------------------ */ -void qif_ipmp_delete(char *qifname) -{ - packet_filter_hook_t *pfh; - qif_t *qf, **qfp, *qif; - - WRITE_ENTER(&pfil_rw); - for (qfp = &qif_head; (qif = *qfp) != NULL; qfp = &qif->qf_next) { - if ((qif->qf_flags & QF_IPMP) == 0) - continue; - if (strcmp(qif->qf_name, qifname) == 0) { - *qfp = qif->qf_next; - for (qf = qif_head; qf != NULL; qf = qf->qf_next) - if (qf->qf_ipmp == qif) - qf->qf_ipmp = NULL; - break; - } - } - RW_EXIT(&pfil_rw); - - if (qif != NULL) { - pfh = pfil_hook_get(PFIL_OUT, &pfh_sync); - for (; pfh; pfh = pfh->pfil_next) - if (pfh->pfil_func) - (void) (*pfh->pfil_func)(NULL, 0, qif, 1, - qif, NULL); - - KMFREE(qif, qif->qf_qifsz); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_syncmaster */ -/* Returns: void */ -/* Parameters: updated(I) - pointer to updated qif structure */ -/* Locks: pfil_rw */ -/* */ -/* This function rechecks all the qif structures that aren't defined for */ -/* IPMP to see if they are indeed members of the group pointed to by */ -/* updated. Ones that currently claim to be in updated are reset and */ -/* rechecked in case they have become excluded. This function should be */ -/* called for any new IPMP qif's created or when an IPMP qif changes. */ -/* ------------------------------------------------------------------------ */ -void qif_ipmp_syncmaster(qif_t *updated, const int sap) -{ - char *s, *t; - qif_t *qf; - - for (qf = qif_head; qf != NULL; qf = qf->qf_next) { - if ((qf->qf_flags & QF_IPMP) != 0) - continue; - if (qf->qf_sap != sap) - continue; - if (qf->qf_ipmp == updated) - qf->qf_ipmp = NULL; - for (s = updated->qf_members; s != NULL; ) { - t = strchr(s, ','); - if (t != NULL) - *t = '\0'; - if (strcmp(qf->qf_name, s) == 0) - qf->qf_ipmp = updated; - if (t != NULL) - *t++ = ','; - s = t; - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_ipmp_syncslave */ -/* Returns: void */ -/* Parameters: target(I) - pointer to updated qif structure */ -/* Locks: pfil_rw */ -/* */ -/* Check through the list of qif's to see if there is an IPMP with a member */ -/* list that includes the one named by target. */ -/* ------------------------------------------------------------------------ */ -void qif_ipmp_syncslave(qif_t *target, const int sap) -{ - char *s, *t; - qif_t *qf; - - target->qf_ipmp = NULL; - - /* - * Recheck the entire list of qif's for any references to the one - * we have just created/updated (updated). - */ - for (qf = qif_head; qf != NULL; qf = qf->qf_next) { - if ((qf->qf_flags & QF_IPMP) == 0) - continue; - if (qf->qf_sap != sap) - continue; - for (s = qf->qf_members; s != NULL; ) { - t = strchr(s, ','); - if (t != NULL) - *t = '\0'; - if (strcmp(target->qf_name, s) == 0) - target->qf_ipmp = qf; - if (t != NULL) - *t++ = ','; - s = t; - if (target->qf_ipmp == qf) - break; - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: qif_hl_set */ -/* Returns: void */ -/* Parameters: ipmpconf(I) - string with header length setting for NIC */ -/* */ -/* For NICs that we cannot automatically determine the MAC header length of */ -/* we provide a manual crook to achieve that with. The input syntax for */ -/* the string is "[v4:|v6:]<ifname>=<length>" */ -/* ------------------------------------------------------------------------ */ -void qif_hl_set(char *ipmpconf) -{ - qif_t *qf; - char *s; - - if (!strncmp(ipmpconf, "v4:", 3)) { - ipmpconf += 3; - } else if (!strncmp(ipmpconf, "v6:", 3)) { -#if SOLARIS2 >= 8 - ipmpconf += 3; -#else - return; -#endif - } - - s = strchr(ipmpconf, '='); - if (s != NULL) { - if (*(s + 1) == '\0') - *s = '\0'; - else - *s++ = '\0'; - } - if (s == NULL || *s == NULL) - return; - - READ_ENTER(&pfil_rw); - for (qf = qif_head; qf; qf = qf->qf_next) - if (strcmp(qf->qf_name, ipmpconf) == 0) - break; - - if (qf != NULL) { - int hl = 0; - - for (; *s != '\0'; s++) { - char c = *s; - - if (c < '0' || c > '9') - return; - hl *= 10; - hl += c - '0'; - } - qf->qf_hl = hl; - } - - RW_EXIT(&pfil_rw); -} diff --git a/usr/src/uts/common/inet/pfil/qif.h b/usr/src/uts/common/inet/pfil/qif.h deleted file mode 100644 index 7371ab420a..0000000000 --- a/usr/src/uts/common/inet/pfil/qif.h +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef sun -# include <sys/dditypes.h> -# include <sys/ptms.h> -#endif - - -#ifdef IRE_ILL_CN -typedef union { - struct sockaddr_in qfa_in; - struct sockaddr_in6 qfa_in6; -} qfa_t; -# define qfa_family qfa_in.sin_family -# define qfa_v4addr qfa_in.sin_addr -# define qfa_v6addr qfa_in6.sin6_addr -#else -# define QF_IPIF(x) ((ill_t *)(x)->qf_ill)->ill_ipif -# define qf_netmask QF_IPIF->ipif_net_mask -# define qf_dstaddr QF_IPIF->ipif_pp_dst_addr -# if SOLARIS2 <= 7 -# define qf_localaddr QF_IPIF->ipif_local_addr -# define qf_broadaddr QF_IPIF->ipif_broadcast_addr -# else -# define qf_localaddr QF_IPIF->ipif_lcl_addr -# define qf_broadaddr QF_IPIF->ipif_brd_addr -# endif -# ifdef USE_INET6 -# define qf_v6netmask QF_IPIF->ipif_v6net_mask -# define qf_v6broadaddr QF_IPIF->ipif_v6brd_addr -# define qf_v6dstaddr QF_IPIF->ipif_v6pp_dst_addr -# endif -#endif - -typedef struct s_ill_s { - struct s_ill_s *ill_next; /* Chained in at s_ill_g_head. */ - kmutex_t s_ill_lock; - char ill_name[LIFNAMSIZ]; /* Our name. */ - t_uscalar_t ill_sap; /* IP_DL_SAP or IP6_DL_SAP */ - queue_t *ill_rq; /* lower stream read queue */ - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } localaddr; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } netmask; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } broadaddr; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } dstaddr; - uint_t mtu; -} s_ill_t; - -typedef struct qif { - /* for alignment reasons, the lock is first. */ - kmutex_t qf_lock; - struct qifplock { - kmutex_t pt_lock; -#ifdef sun - kcondvar_t pt_cv; -#endif - int pt_refcnt; - int pt_access; - } qf_ptl; - struct qif *qf_next; - struct qif *qf_ipmp; /* Pointer to group qif */ - void *qf_ill; - queue_t *qf_q; - queue_t *qf_oq; - /* statistical data */ - u_long qf_nr; - u_long qf_nw; - u_long qf_bad; - u_long qf_copy; - u_long qf_copyfail; - u_long qf_drop; - u_long qf_notip; - u_long qf_nodata; - u_long qf_notdata; - /* other data for the NIC on this queue */ - size_t qf_qifsz; - size_t qf_hl; /* header length */ - u_int qf_num; - u_int qf_ppa; /* Physical Point of Attachment */ - int qf_sap; /* Service Access Point */ - int qf_bound; - int qf_flags; - int qf_waitack; - int qf_max_frag; /* MTU for interface */ - char qf_name[LIFNAMSIZ]; - char *qf_members; - - /* ON(10, NV) specific */ - mblk_t *qf_addrset; - size_t qf_off; - mblk_t *qf_m; - void *qf_data; -} qif_t; - - -typedef struct qpktinfo { - /* data that changes per-packet */ - qif_t *qpi_real; /* the real one on the STREAM */ - void *qpi_ill; /* COPIED */ - mblk_t *qpi_m; - queue_t *qpi_q; - char *qpi_name; /* points to qf_real->qf_name */ - void *qpi_data; /* where layer 3 header starts */ - size_t qpi_off; - size_t qpi_hl; /* COPIED */ - u_int qpi_ppa; /* COPIED */ - u_int qpi_num; /* COPIED */ - int qpi_flags; /* COPIED */ - int qpi_max_frag; /* COPIED */ -} qpktinfo_t; - - -#ifdef sun -# if SOLARIS2 <= 7 -# define QF_V4_ADDR(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_local_addr -# define QF_V4_BROADCAST(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_broadcast_addr -# else -# define QF_V4_ADDR(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_lcl_addr -# define QF_V4_BROADCAST(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_brd_addr -# endif -# define QF_V4_NETMASK(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_net_mask -# define QF_V4_PEERADDR(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_pp_dst_addr -# ifdef USE_INET6 -# define QF_V6_BROADCAST(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_v6brd_addr -# define QF_V6_NETMASK(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_v6net_mask -# define QF_V6_PEERADDR(x) \ - ((ill_t *)(x)->qf_ill)->ill_ipif->ipif_v6pp_dst_addr -# endif -#endif - -#ifdef __hpux -# define QF_V4_ADDR(x) ((ifinfo_t *)(x)->qf_ill)->ifi_addr[0] -# define QF_V4_BROADCAST(x) 0 -# define QF_V4_NETMASK(x) 0xffffffff -# define QF_V4_PEERADDR(x) 0 -# ifdef USE_INET6 -# define QF_V6_BROADCAST(x) 0 -# define QF_V6_NETMASK(x) 0 -# define QF_V6_PEERADDR(x) 0 -# endif -#endif - - -#define QF_GROUP 0x0001 -#define QF_IPMP 0x0002 - -extern void *q_to_ill(queue_t *); -extern struct qif *qif_new(queue_t *, int); -extern int qif_attach(queue_t *); -extern void qif_delete(struct qif *, queue_t *); -extern int qif_startup(void); -extern void qif_stop(void); -extern void *qif_iflookup(char *, int); - -#ifdef __hpux -struct irinfo_s; -extern void *ir_to_ill(struct irinfo_s *ir); -#endif -extern struct qif *qif_walk(struct qif **); -extern struct qif *qif_head; -extern int qif_verbose; -extern void qif_update(struct qif *, mblk_t *); -extern void qif_nd_init(void); -extern void qif_hl_set(char *); -extern void qif_ipmp_delete(char *); -extern void qif_ipmp_update(char *); -extern void qif_ipmp_syncmaster(struct qif *, const int); -extern void qif_ipmp_syncslave(struct qif *, const int); - -#ifndef IRE_ILL_CN -extern void qif_ire_walker(ire_t *, void *); -#endif - -extern kmutex_t s_ill_g_head_lock; -extern s_ill_t *s_ill_g_head; diff --git a/usr/src/uts/common/inet/tcp.h b/usr/src/uts/common/inet/tcp.h index cede68250d..54d46f7f1b 100644 --- a/usr/src/uts/common/inet/tcp.h +++ b/usr/src/uts/common/inet/tcp.h @@ -568,6 +568,9 @@ extern void *tcp_get_conn(void *arg); extern void tcp_time_wait_collector(void *arg); extern int tcp_snmp_get(queue_t *, mblk_t *); extern int tcp_snmp_set(queue_t *, int, int, uchar_t *, int len); +extern mblk_t *tcp_xmit_mp(tcp_t *tcp, mblk_t *mp, int32_t max_to_send, + int32_t *offset, mblk_t **end_mp, uint32_t seq, + boolean_t sendall, uint32_t *seg_len, boolean_t rexmit); /* * The TCP Fanout structure. * The hash tables and their linkage (tcp_*_hash_next, tcp_ptp*hn) are diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index d5890ec810..2361fcaacc 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -45,6 +45,7 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; #include <sys/xti_inet.h> #include <sys/cmn_err.h> #include <sys/debug.h> +#include <sys/sdt.h> #include <sys/vtrace.h> #include <sys/kmem.h> #include <sys/ethernet.h> @@ -95,6 +96,7 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; #include <inet/ip_ftable.h> #include <inet/ip_if.h> #include <inet/ipp_common.h> +#include <inet/ip_netinfo.h> #include <sys/squeue.h> #include <inet/kssl/ksslapi.h> #include <sys/tsol/label.h> @@ -222,6 +224,13 @@ const char tcp_version[] = "%Z%%M% %I% %E% SMI"; * only exception is tcp_xmit_listeners_reset() which is called * directly from IP and needs to policy check to see if TH_RST * can be sent out. + * + * PFHooks notes : + * + * For mdt case, one meta buffer contains multiple packets. Mblks for every + * packet are assembled and passed to the hooks. When packets are blocked, + * or boundary of any packet is changed, the mdt processing is stopped, and + * packets of the meta buffer are send to the IP path one by one. */ extern major_t TCP6_MAJ; @@ -919,9 +928,6 @@ static void tcp_fill_header(tcp_t *tcp, uchar_t *rptr, clock_t now, int num_sack_blk); static void tcp_wsrv(queue_t *q); static int tcp_xmit_end(tcp_t *tcp); -static mblk_t *tcp_xmit_mp(tcp_t *tcp, mblk_t *mp, int32_t max_to_send, - int32_t *offset, mblk_t **end_mp, uint32_t seq, - boolean_t sendall, uint32_t *seg_len, boolean_t rexmit); static void tcp_ack_timer(void *arg); static mblk_t *tcp_ack_mp(tcp_t *tcp); static void tcp_xmit_early_reset(char *str, mblk_t *mp, @@ -18482,9 +18488,17 @@ tcp_send_data(tcp_t *tcp, queue_t *q, mblk_t *mp) * depending on the availability of transmit resources at * the media layer. */ - IP_DLS_ILL_TX(ill, mp); + IP_DLS_ILL_TX(ill, ipha, mp); } else { - putnext(ire->ire_stq, mp); + ill_t *out_ill = (ill_t *)ire->ire_stq->q_ptr; + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, ill_t *, out_ill, + ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, out_ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp != NULL) + putnext(ire->ire_stq, mp); } IRE_REFRELE(ire); } @@ -19099,6 +19113,7 @@ tcp_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, int pbuf_idx, pbuf_idx_nxt; int seg_len, len, spill, af; boolean_t add_buffer, zcopy, clusterwide; + boolean_t buf_trunked = B_FALSE; boolean_t rconfirm = B_FALSE; boolean_t done = B_FALSE; uint32_t cksum; @@ -19112,6 +19127,8 @@ tcp_multisend(queue_t *q, tcp_t *tcp, const int mss, const int tcp_hdr_len, uint16_t *up; int err; conn_t *connp; + mblk_t *mp, *mp1, *fw_mp_head = NULL; + uchar_t *pld_start; #ifdef _BIG_ENDIAN #define IPVER(ip6h) ((((uint32_t *)ip6h)[0] >> 28) & 0x7) @@ -20056,6 +20073,117 @@ legacy_send_no_md: } } + if (af == AF_INET && HOOKS4_INTERESTED_PHYSICAL_OUT|| + af == AF_INET6 && HOOKS6_INTERESTED_PHYSICAL_OUT) { + /* build header(IP/TCP) mblk for this segment */ + if ((mp = dupb(md_hbuf)) == NULL) + goto legacy_send; + + mp->b_rptr = pkt_info->hdr_rptr; + mp->b_wptr = pkt_info->hdr_wptr; + + /* build payload mblk for this segment */ + if ((mp1 = dupb(*xmit_tail)) == NULL) { + freemsg(mp); + goto legacy_send; + } + mp1->b_wptr = md_pbuf->b_rptr + cur_pld_off; + mp1->b_rptr = mp1->b_wptr - + tcp->tcp_last_sent_len; + linkb(mp, mp1); + + pld_start = mp1->b_rptr; + + if (af == AF_INET) { + DTRACE_PROBE4( + ip4__physical__out__start, + ill_t *, NULL, + ill_t *, ill, + ipha_t *, ipha, + mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, + ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, ill, ipha, + mp, mp); + DTRACE_PROBE1( + ip4__physical__out__end, + mblk_t *, mp); + } else { + DTRACE_PROBE4( + ip6__physical__out_start, + ill_t *, NULL, + ill_t *, ill, + ip6_t *, ip6h, + mblk_t *, mp); + FW_HOOKS6(ip6_physical_out_event, + ipv6firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, ill, ip6h, + mp, mp); + DTRACE_PROBE1( + ip6__physical__out__end, + mblk_t *, mp); + } + + if (buf_trunked && mp != NULL) { + /* + * Need to pass it to normal path. + */ + CALL_IP_WPUT(tcp->tcp_connp, q, mp); + } else if (mp == NULL || + mp->b_rptr != pkt_info->hdr_rptr || + mp->b_wptr != pkt_info->hdr_wptr || + (mp1 = mp->b_cont) == NULL || + mp1->b_rptr != pld_start || + mp1->b_wptr != pld_start + + tcp->tcp_last_sent_len || + mp1->b_cont != NULL) { + /* + * Need to pass all packets of this + * buffer to normal path, either when + * packet is blocked, or when boundary + * of header buffer or payload buffer + * has been changed by FW_HOOKS[6]. + */ + buf_trunked = B_TRUE; + if (md_mp_head != NULL) { + err = (intptr_t)rmvb(md_mp_head, + md_mp); + if (err == 0) + md_mp_head = NULL; + } + + /* send down what we've got so far */ + if (md_mp_head != NULL) { + tcp_multisend_data(tcp, ire, + ill, md_mp_head, obsegs, + obbytes, &rconfirm); + } + md_mp_head = NULL; + + if (mp != NULL) + CALL_IP_WPUT(tcp->tcp_connp, + q, mp); + + mp1 = fw_mp_head; + do { + mp = mp1; + mp1 = mp1->b_next; + mp->b_next = NULL; + mp->b_prev = NULL; + CALL_IP_WPUT(tcp->tcp_connp, + q, mp); + } while (mp1 != NULL); + + fw_mp_head = NULL; + } else { + if (fw_mp_head == NULL) + fw_mp_head = mp; + else + fw_mp_head->b_prev->b_next = mp; + fw_mp_head->b_prev = mp; + } + } + /* advance header offset */ cur_hdr_off += hdr_frag_sz; @@ -20098,12 +20226,26 @@ legacy_send_no_md: *tail_unsent = (int)MBLKL(*xmit_tail); add_buffer = B_TRUE; } + + while (fw_mp_head) { + mp = fw_mp_head; + fw_mp_head = fw_mp_head->b_next; + mp->b_prev = mp->b_next = NULL; + freemsg(mp); + } + if (buf_trunked) { + TCP_STAT(tcp_mdt_discarded); + freeb(md_mp); + buf_trunked = B_FALSE; + } } while (!done && *usable > 0 && num_burst_seg > 0 && (tcp_mdt_chain || max_pld > 0)); - /* send everything down */ - tcp_multisend_data(tcp, ire, ill, md_mp_head, obsegs, obbytes, - &rconfirm); + if (md_mp_head != NULL) { + /* send everything down */ + tcp_multisend_data(tcp, ire, ill, md_mp_head, obsegs, obbytes, + &rconfirm); + } #undef PREP_NEW_MULTIDATA #undef PREP_NEW_PBUF @@ -21926,7 +22068,7 @@ tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len, zoneid_t zoneid) * be adjusted by *offset. And after dupb(), the offset and the ending mblk * of the original mblk chain will be returned in *offset and *end_mp. */ -static mblk_t * +mblk_t * tcp_xmit_mp(tcp_t *tcp, mblk_t *mp, int32_t max_to_send, int32_t *offset, mblk_t **end_mp, uint32_t seq, boolean_t sendall, uint32_t *seg_len, boolean_t rexmit) diff --git a/usr/src/uts/common/inet/tcp/tcp_fusion.c b/usr/src/uts/common/inet/tcp/tcp_fusion.c index a6c1fe1ea1..7cca7bda15 100644 --- a/usr/src/uts/common/inet/tcp/tcp_fusion.c +++ b/usr/src/uts/common/inet/tcp/tcp_fusion.c @@ -30,6 +30,7 @@ #include <sys/strsun.h> #include <sys/strsubr.h> #include <sys/debug.h> +#include <sys/sdt.h> #include <sys/cmn_err.h> #include <sys/tihdr.h> @@ -463,6 +464,14 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) uint_t max_unread; boolean_t flow_stopped; boolean_t urgent = (DB_TYPE(mp) != M_DATA); + mblk_t *mp1 = mp; + ill_t *ilp, *olp; + ipha_t *ipha; + ip6_t *ip6h; + tcph_t *tcph; + uint_t ip_hdr_len; + uint32_t seq; + uint32_t recv_size = send_size; ASSERT(tcp->tcp_fused); ASSERT(peer_tcp != NULL && peer_tcp->tcp_loopback_peer == tcp); @@ -476,8 +485,7 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) if (TCP_LOOPBACK_IP(tcp) || TCP_LOOPBACK_IP(peer_tcp) || IPP_ENABLED(IPP_LOCAL_OUT|IPP_LOCAL_IN)) { TCP_STAT(tcp_fusion_aborted); - tcp_unfuse(tcp); - return (B_FALSE); + goto unfuse; } if (send_size == 0) { @@ -500,6 +508,93 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) */ TCP_FUSE_SYNCSTR_PLUG_DRAIN(peer_tcp); tcp_fuse_output_urg(tcp, mp); + + mp1 = mp->b_cont; + } + + if (tcp->tcp_ipversion == IPV4_VERSION && + (HOOKS4_INTERESTED_LOOPBACK_IN || + HOOKS4_INTERESTED_LOOPBACK_OUT) || + tcp->tcp_ipversion == IPV6_VERSION && + (HOOKS6_INTERESTED_LOOPBACK_IN || + HOOKS6_INTERESTED_LOOPBACK_OUT)) { + /* + * Build ip and tcp header to satisfy FW_HOOKS. + * We only build it when any hook is present. + */ + if ((mp1 = tcp_xmit_mp(tcp, mp1, tcp->tcp_mss, NULL, NULL, + tcp->tcp_snxt, B_TRUE, NULL, B_FALSE)) == NULL) + /* If tcp_xmit_mp fails, use regular path */ + goto unfuse; + + ASSERT(peer_tcp->tcp_connp->conn_ire_cache->ire_ipif != NULL); + olp = peer_tcp->tcp_connp->conn_ire_cache->ire_ipif->ipif_ill; + /* PFHooks: LOOPBACK_OUT */ + if (tcp->tcp_ipversion == IPV4_VERSION) { + ipha = (ipha_t *)mp1->b_rptr; + + DTRACE_PROBE4(ip4__loopback__out__start, + ill_t *, NULL, ill_t *, olp, + ipha_t *, ipha, mblk_t *, mp1); + FW_HOOKS(ip4_loopback_out_event, + ipv4firewall_loopback_out, MSG_FWCOOKED_OUT, NULL, + olp, ipha, mp1, mp1); + DTRACE_PROBE1(ip4__loopback__out__end, mblk_t *, mp1); + } else { + ip6h = (ip6_t *)mp1->b_rptr; + + DTRACE_PROBE4(ip6__loopback__out__start, + ill_t *, NULL, ill_t *, olp, + ip6_t *, ip6h, mblk_t *, mp1); + FW_HOOKS6(ip6_loopback_out_event, + ipv6firewall_loopback_out, MSG_FWCOOKED_OUT, NULL, + olp, ip6h, mp1, mp1); + DTRACE_PROBE1(ip6__loopback__out__end, mblk_t *, mp1); + } + if (mp1 == NULL) + goto unfuse; + + + /* PFHooks: LOOPBACK_IN */ + ASSERT(tcp->tcp_connp->conn_ire_cache->ire_ipif != NULL); + ilp = tcp->tcp_connp->conn_ire_cache->ire_ipif->ipif_ill; + + if (tcp->tcp_ipversion == IPV4_VERSION) { + DTRACE_PROBE4(ip4__loopback__in__start, + ill_t *, ilp, ill_t *, NULL, + ipha_t *, ipha, mblk_t *, mp1); + FW_HOOKS(ip4_loopback_in_event, + ipv4firewall_loopback_in, MSG_FWCOOKED_IN, ilp, + NULL, ipha, mp1, mp1); + DTRACE_PROBE1(ip4__loopback__in__end, mblk_t *, mp1); + if (mp1 == NULL) + goto unfuse; + + ip_hdr_len = IPH_HDR_LENGTH(ipha); + } else { + DTRACE_PROBE4(ip6__loopback__in__start, + ill_t *, ilp, ill_t *, NULL, + ip6_t *, ip6h, mblk_t *, mp1); + FW_HOOKS6(ip6_loopback_in_event, + ipv6firewall_loopback_in, MSG_FWCOOKED_IN, ilp, + NULL, ip6h, mp1, mp1); + DTRACE_PROBE1(ip6__loopback__in__end, mblk_t *, mp1); + if (mp1 == NULL) + goto unfuse; + + ip_hdr_len = ip_hdr_length_v6(mp1, ip6h); + } + + /* Data length might be changed by FW_HOOKS */ + tcph = (tcph_t *)&mp1->b_rptr[ip_hdr_len]; + seq = ABE32_TO_U32(tcph->th_seq); + recv_size += seq - tcp->tcp_snxt; + + /* + * The message duplicated by tcp_xmit_mp is freed. + * Note: the original message passed in remains unchanged. + */ + freemsg(mp1); } mutex_enter(&peer_tcp->tcp_fuse_lock); @@ -528,10 +623,10 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) * Enqueue data into the peer's receive list; we may or may not * drain the contents depending on the conditions below. */ - tcp_rcv_enqueue(peer_tcp, mp, send_size); + tcp_rcv_enqueue(peer_tcp, mp, recv_size); /* In case it wrapped around and also to keep it constant */ - peer_tcp->tcp_rwnd += send_size; + peer_tcp->tcp_rwnd += recv_size; /* * Exercise flow-control when needed; we will get back-enabled @@ -574,7 +669,7 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) /* Need to adjust the following SNMP MIB-related variables */ tcp->tcp_snxt += send_size; tcp->tcp_suna = tcp->tcp_snxt; - peer_tcp->tcp_rnxt += send_size; + peer_tcp->tcp_rnxt += recv_size; peer_tcp->tcp_rack = peer_tcp->tcp_rnxt; BUMP_MIB(&tcp_mib, tcpOutDataSegs); @@ -620,6 +715,9 @@ tcp_fuse_output(tcp_t *tcp, mblk_t *mp, uint32_t send_size) } } return (B_TRUE); +unfuse: + tcp_unfuse(tcp); + return (B_FALSE); } /* diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c index 95f2d9b64b..ae99e06f72 100644 --- a/usr/src/uts/common/inet/udp/udp.c +++ b/usr/src/uts/common/inet/udp/udp.c @@ -53,6 +53,7 @@ const char udp_version[] = "%Z%%M% %I% %E% SMI"; #include <sys/socket.h> #include <sys/sockio.h> #include <sys/vtrace.h> +#include <sys/sdt.h> #include <sys/debug.h> #include <sys/isa_defs.h> #include <sys/random.h> @@ -6722,9 +6723,16 @@ udp_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha) * depending on the availability of transmit resources at * the media layer. */ - IP_DLS_ILL_TX(ill, mp); + IP_DLS_ILL_TX(ill, ipha, mp); } else { - putnext(ire->ire_stq, mp); + DTRACE_PROBE4(ip4__physical__out__start, + ill_t *, NULL, ill_t *, ill, + ipha_t *, ipha, mblk_t *, mp); + FW_HOOKS(ip4_physical_out_event, ipv4firewall_physical_out, + MSG_FWCOOKED_OUT, NULL, ill, ipha, mp, mp); + DTRACE_PROBE1(ip4__physical__out__end, mblk_t *, mp); + if (mp != NULL) + putnext(ire->ire_stq, mp); } if (ipif != NULL) diff --git a/usr/src/uts/common/io/bge/bge_send.c b/usr/src/uts/common/io/bge/bge_send.c index d886d19636..0a29b29510 100644 --- a/usr/src/uts/common/io/bge/bge_send.c +++ b/usr/src/uts/common/io/bge/bge_send.c @@ -409,23 +409,12 @@ bge_send(bge_t *bgep, mblk_t *mp) if (ehp->ether_tpid == htons(ETHERTYPE_VLAN)) { if (MBLKL(mp) < sizeof (struct ether_vlan_header)) { - uint32_t pflags; - - /* - * Need to preserve checksum flags across pullup. - */ - hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, - NULL, &pflags); - if (!pullupmsg(mp, sizeof (struct ether_vlan_header))) { BGE_DEBUG(("bge_send: pullup failure")); bgep->resched_needed = B_TRUE; return (B_FALSE); } - - (void) hcksum_assoc(mp, NULL, NULL, NULL, NULL, NULL, - NULL, pflags, KM_NOSLEEP); } ehp = (struct ether_vlan_header *)mp->b_rptr; diff --git a/usr/src/uts/common/io/hook.c b/usr/src/uts/common/io/hook.c new file mode 100644 index 0000000000..7e791647e4 --- /dev/null +++ b/usr/src/uts/common/io/hook.c @@ -0,0 +1,685 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/kmem.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/modctl.h> +#include <sys/hook_impl.h> +#include <sys/sdt.h> + +/* + * This file provides kernel hook framework. + */ + +static struct modldrv modlmisc = { + &mod_miscops, /* drv_modops */ + "Hooks Interface v1.0", /* drv_linkinfo */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, /* ml_rev */ + &modlmisc, /* ml_linkage */ + NULL +}; + +/* + * Hook internal functions + */ +static hook_int_t *hook_copy(hook_t *src); +static hook_event_int_t *hook_event_checkdup(hook_event_t *he); +static hook_event_int_t *hook_event_copy(hook_event_t *src); +static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event); +static void hook_event_free(hook_event_int_t *hei); +static hook_family_int_t *hook_family_copy(hook_family_t *src); +static hook_family_int_t *hook_family_find(char *family); +static void hook_family_free(hook_family_int_t *hfi); +static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h); +static void hook_free(hook_int_t *hi); +static void hook_init(void); + +static cvwaitlock_t familylock; /* global lock */ +static hook_family_int_head_t familylist; /* family list head */ + +/* + * Module entry points. + */ +int +_init(void) +{ + hook_init(); + return (mod_install(&modlinkage)); +} + + +int +_fini(void) +{ + return (mod_remove(&modlinkage)); +} + + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&modlinkage, modinfop)); +} + + +/* + * Function: hook_init + * Returns: None + * Parameters: None + * + * Initialize hooks + */ +static void +hook_init(void) +{ + CVW_INIT(&familylock); + SLIST_INIT(&familylist); +} + + +/* + * Function: hook_run + * Returns: int - return value according to callback func + * Parameters: token(I) - event pointer + * info(I) - message + * + * Run hooks for specific provider. The hooks registered are stepped through + * until either the end of the list is reached or a hook function returns a + * non-zero value. If a non-zero value is returned from a hook function, we + * return that value back to our caller. By design, a hook function can be + * called more than once, simultaneously. + */ +int +hook_run(hook_event_token_t token, hook_data_t info) +{ + hook_int_t *hi; + hook_event_int_t *hei; + int rval = 0; + + ASSERT(token != NULL); + + hei = (hook_event_int_t *)token; + DTRACE_PROBE2(hook__run__start, + hook_event_token_t, token, + hook_data_t, info); + + /* Hold global read lock to ensure event will not be deleted */ + CVW_ENTER_READ(&familylock); + + /* Hold event read lock to ensure hook will not be changed */ + CVW_ENTER_READ(&hei->hei_lock); + + TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { + ASSERT(hi->hi_hook.h_func != NULL); + DTRACE_PROBE3(hook__func__start, + hook_event_token_t, token, + hook_data_t, info, + hook_int_t *, hi); + rval = (*hi->hi_hook.h_func)(token, info); + DTRACE_PROBE4(hook__func__end, + hook_event_token_t, token, + hook_data_t, info, + hook_int_t *, hi, + int, rval); + if (rval != 0) + break; + } + + CVW_EXIT_READ(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + + DTRACE_PROBE3(hook__run__end, + hook_event_token_t, token, + hook_data_t, info, + hook_int_t *, hi); + + return (rval); +} + + +/* + * Function: hook_family_add + * Returns: internal family pointer - NULL = Fail + * Parameters: hf(I) - family pointer + * + * Add new family to family list + */ +hook_family_int_t * +hook_family_add(hook_family_t *hf) +{ + hook_family_int_t *hfi, *new; + + ASSERT(hf != NULL); + ASSERT(hf->hf_name != NULL); + + new = hook_family_copy(hf); + if (new == NULL) + return (NULL); + + CVW_ENTER_WRITE(&familylock); + + /* search family list */ + hfi = hook_family_find(hf->hf_name); + if (hfi != NULL) { + CVW_EXIT_WRITE(&familylock); + hook_family_free(new); + return (NULL); + } + + /* Add to family list head */ + SLIST_INSERT_HEAD(&familylist, new, hfi_entry); + + CVW_EXIT_WRITE(&familylock); + return (new); +} + + +/* + * Function: hook_family_remove + * Returns: int - 0 = Succ, Else = Fail + * Parameters: hfi(I) - internal family pointer + * + * Remove family from family list + */ +int +hook_family_remove(hook_family_int_t *hfi) +{ + + ASSERT(hfi != NULL); + + CVW_ENTER_WRITE(&familylock); + + /* Check if there are events */ + if (!SLIST_EMPTY(&hfi->hfi_head)) { + CVW_EXIT_WRITE(&familylock); + return (EBUSY); + } + + /* Remove from family list */ + SLIST_REMOVE(&familylist, hfi, hook_family_int, hfi_entry); + + CVW_EXIT_WRITE(&familylock); + hook_family_free(hfi); + + return (0); +} + + +/* + * Function: hook_family_copy + * Returns: internal family pointer - NULL = Failed + * Parameters: src(I) - family pointer + * + * Allocate internal family block and duplicate incoming family + * No locks should be held across this function as it may sleep. + */ +static hook_family_int_t * +hook_family_copy(hook_family_t *src) +{ + hook_family_int_t *new; + hook_family_t *dst; + + ASSERT(src != NULL); + ASSERT(src->hf_name != NULL); + + new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); + + /* Copy body */ + SLIST_INIT(&new->hfi_head); + dst = &new->hfi_family; + *dst = *src; + + /* Copy name */ + dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP); + (void) strcpy(dst->hf_name, src->hf_name); + + return (new); +} + + +/* + * Function: hook_family_find + * Returns: internal family pointer - NULL = Not match + * Parameters: family(I) - family name string + * + * Search family list with family name + * A lock on familylock must be held when called. + */ +static hook_family_int_t * +hook_family_find(char *family) +{ + hook_family_int_t *hfi = NULL; + + ASSERT(family != NULL); + + SLIST_FOREACH(hfi, &familylist, hfi_entry) { + if (strcmp(hfi->hfi_family.hf_name, family) == 0) + break; + } + return (hfi); +} + + +/* + * Function: hook_family_free + * Returns: None + * Parameters: hfi(I) - internal family pointer + * + * Free alloc memory for family + */ +static void +hook_family_free(hook_family_int_t *hfi) +{ + ASSERT(hfi != NULL); + + /* Free name space */ + if (hfi->hfi_family.hf_name != NULL) { + kmem_free(hfi->hfi_family.hf_name, + strlen(hfi->hfi_family.hf_name) + 1); + } + + /* Free container */ + kmem_free(hfi, sizeof (*hfi)); +} + + +/* + * Function: hook_event_add + * Returns: internal event pointer - NULL = Fail + * Parameters: hfi(I) - internal family pointer + * he(I) - event pointer + * + * Add new event to event list on specific family. + * This function can fail to return successfully if (1) it cannot allocate + * enough memory for its own internal data structures, (2) the event has + * already been registered (for any hook family.) + */ +hook_event_int_t * +hook_event_add(hook_family_int_t *hfi, hook_event_t *he) +{ + hook_event_int_t *hei, *new; + + ASSERT(hfi != NULL); + ASSERT(he != NULL); + ASSERT(he->he_name != NULL); + + new = hook_event_copy(he); + if (new == NULL) + return (NULL); + + CVW_ENTER_WRITE(&familylock); + + /* Check whether this event pointer is already registered */ + hei = hook_event_checkdup(he); + if (hei != NULL) { + CVW_EXIT_WRITE(&familylock); + hook_event_free(new); + return (NULL); + } + + /* Add to event list head */ + SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry); + + CVW_EXIT_WRITE(&familylock); + return (new); +} + + +/* + * Function: hook_event_remove + * Returns: int - 0 = Succ, Else = Fail + * Parameters: hfi(I) - internal family pointer + * he(I) - event pointer + * + * Remove event from event list on specific family + */ +int +hook_event_remove(hook_family_int_t *hfi, hook_event_t *he) +{ + hook_event_int_t *hei; + + ASSERT(hfi != NULL); + ASSERT(he != NULL); + + CVW_ENTER_WRITE(&familylock); + + hei = hook_event_find(hfi, he->he_name); + if (hei == NULL) { + CVW_EXIT_WRITE(&familylock); + return (ENXIO); + } + + /* Check if there are registered hooks for this event */ + if (!TAILQ_EMPTY(&hei->hei_head)) { + CVW_EXIT_WRITE(&familylock); + return (EBUSY); + } + + /* Remove from event list */ + SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry); + + CVW_EXIT_WRITE(&familylock); + hook_event_free(hei); + + return (0); +} + + +/* + * Function: hook_event_checkdup + * Returns: internal event pointer - NULL = Not match + * Parameters: he(I) - event pointer + * + * Search whole list with event pointer + * A lock on familylock must be held when called. + */ +static hook_event_int_t * +hook_event_checkdup(hook_event_t *he) +{ + hook_family_int_t *hfi; + hook_event_int_t *hei; + + ASSERT(he != NULL); + + SLIST_FOREACH(hfi, &familylist, hfi_entry) { + SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { + if (hei->hei_event == he) + return (hei); + } + } + + return (NULL); +} + + +/* + * Function: hook_event_copy + * Returns: internal event pointer - NULL = Failed + * Parameters: src(I) - event pointer + * + * Allocate internal event block and duplicate incoming event + * No locks should be held across this function as it may sleep. + */ +static hook_event_int_t * +hook_event_copy(hook_event_t *src) +{ + hook_event_int_t *new; + + ASSERT(src != NULL); + ASSERT(src->he_name != NULL); + + new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); + + /* Copy body */ + TAILQ_INIT(&new->hei_head); + new->hei_event = src; + + return (new); +} + + +/* + * Function: hook_event_find + * Returns: internal event pointer - NULL = Not match + * Parameters: hfi(I) - internal family pointer + * event(I) - event name string + * + * Search event list with event name + * A lock on familylock must be held when called. + */ +static hook_event_int_t * +hook_event_find(hook_family_int_t *hfi, char *event) +{ + hook_event_int_t *hei = NULL; + + ASSERT(hfi != NULL); + ASSERT(event != NULL); + + SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) { + if (strcmp(hei->hei_event->he_name, event) == 0) + break; + } + return (hei); +} + + +/* + * Function: hook_event_free + * Returns: None + * Parameters: hei(I) - internal event pointer + * + * Free alloc memory for event + */ +static void +hook_event_free(hook_event_int_t *hei) +{ + ASSERT(hei != NULL); + + /* Free container */ + kmem_free(hei, sizeof (*hei)); +} + + +/* + * Function: hook_register + * Returns: int- 0 = Succ, Else = Fail + * Parameters: hfi(I) - internal family pointer + * event(I) - event name string + * h(I) - hook pointer + * + * Add new hook to hook list on spefic family, event + */ +int +hook_register(hook_family_int_t *hfi, char *event, hook_t *h) +{ + hook_event_int_t *hei; + hook_int_t *hi, *new; + + ASSERT(hfi != NULL); + ASSERT(event != NULL); + ASSERT(h != NULL); + + /* Alloc hook_int_t and copy hook */ + new = hook_copy(h); + if (new == NULL) + return (ENOMEM); + + /* + * Since hook add/remove only impact event, so it is unnecessary + * to hold global family write lock. Just get read lock here to + * ensure event will not be removed when doing hooks operation + */ + CVW_ENTER_READ(&familylock); + + hei = hook_event_find(hfi, event); + if (hei == NULL) { + CVW_EXIT_READ(&familylock); + hook_free(new); + return (ENXIO); + } + + CVW_ENTER_WRITE(&hei->hei_lock); + + /* Multiple hooks are only allowed for read-only events. */ + if (((hei->hei_event->he_flags & HOOK_RDONLY) == 0) && + (!TAILQ_EMPTY(&hei->hei_head))) { + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + hook_free(new); + return (EEXIST); + } + + hi = hook_find(hei, h); + if (hi != NULL) { + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + hook_free(new); + return (EEXIST); + } + + /* Add to hook list head */ + TAILQ_INSERT_HEAD(&hei->hei_head, new, hi_entry); + hei->hei_event->he_interested = B_TRUE; + + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + return (0); +} + + +/* + * Function: hook_unregister + * Returns: int - 0 = Succ, Else = Fail + * Parameters: hfi(I) - internal family pointer + * event(I) - event name string + * h(I) - hook pointer + * + * Remove hook from hook list on specific family, event + */ +int +hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h) +{ + hook_event_int_t *hei; + hook_int_t *hi; + + ASSERT(hfi != NULL); + ASSERT(h != NULL); + + CVW_ENTER_READ(&familylock); + + hei = hook_event_find(hfi, event); + if (hei == NULL) { + CVW_EXIT_READ(&familylock); + return (ENXIO); + } + + /* Hold write lock for event */ + CVW_ENTER_WRITE(&hei->hei_lock); + + hi = hook_find(hei, h); + if (hi == NULL) { + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + return (ENXIO); + } + + /* Remove from hook list */ + TAILQ_REMOVE(&hei->hei_head, hi, hi_entry); + if (TAILQ_EMPTY(&hei->hei_head)) { + hei->hei_event->he_interested = B_FALSE; + } + + CVW_EXIT_WRITE(&hei->hei_lock); + CVW_EXIT_READ(&familylock); + + hook_free(hi); + return (0); +} + + +/* + * Function: hook_find + * Returns: internal hook pointer - NULL = Not match + * Parameters: hei(I) - internal event pointer + * h(I) - hook pointer + * + * Search hook list + * A lock on familylock must be held when called. + */ +static hook_int_t * +hook_find(hook_event_int_t *hei, hook_t *h) +{ + hook_int_t *hi; + + ASSERT(hei != NULL); + ASSERT(h != NULL); + + TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) { + if (strcmp(hi->hi_hook.h_name, h->h_name) == 0) + break; + } + return (hi); +} + + +/* + * Function: hook_copy + * Returns: internal hook pointer - NULL = Failed + * Parameters: src(I) - hook pointer + * + * Allocate internal hook block and duplicate incoming hook. + * No locks should be held across this function as it may sleep. + */ +static hook_int_t * +hook_copy(hook_t *src) +{ + hook_int_t *new; + hook_t *dst; + + ASSERT(src != NULL); + ASSERT(src->h_name != NULL); + + new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP); + + /* Copy body */ + dst = &new->hi_hook; + *dst = *src; + + /* Copy name */ + dst->h_name = (char *)kmem_alloc(strlen(src->h_name) + 1, KM_SLEEP); + (void) strcpy(dst->h_name, src->h_name); + + return (new); +} + +/* + * Function: hook_free + * Returns: None + * Parameters: hi(I) - internal hook pointer + * + * Free alloc memory for hook + */ +static void +hook_free(hook_int_t *hi) +{ + ASSERT(hi != NULL); + + /* Free name space */ + if (hi->hi_hook.h_name != NULL) { + kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1); + } + + /* Free container */ + kmem_free(hi, sizeof (*hi)); +} diff --git a/usr/src/uts/common/io/neti.c b/usr/src/uts/common/io/neti.c new file mode 100644 index 0000000000..3f7ae3c611 --- /dev/null +++ b/usr/src/uts/common/io/neti.c @@ -0,0 +1,509 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/param.h> +#include <sys/atomic.h> +#include <sys/kmem.h> +#include <sys/rwlock.h> +#include <sys/errno.h> +#include <sys/queue.h> +#include <inet/common.h> +#include <inet/led.h> +#include <inet/ip.h> +#include <sys/modctl.h> +#include <sys/neti.h> + + +static krwlock_t netlock; +static LIST_HEAD(netd_listhead, net_data) netd_head; /* list of net_data_t */ + +static void net_init(); +static net_data_t net_find(const char *protocol); + +/* + * Module linkage information for the kernel. + */ +static struct modldrv modlmisc = { + &mod_miscops, /* drv_modops */ + "netinfo module 1.0", /* drv_linkinfo */ +}; + +static struct modlinkage modlinkage = { + MODREV_1, /* ml_rev */ + &modlmisc, /* ml_linkage */ + NULL +}; + +/* + * Module entry points. + */ +int +_init(void) +{ + net_init(); + return (mod_install(&modlinkage)); +} + + +int +_fini(void) +{ + + return (mod_remove(&modlinkage)); +} + + +int +_info(struct modinfo *modinfop) +{ + + return (mod_info(&modlinkage, modinfop)); +} + + +static void +net_init() +{ + + rw_init(&netlock, NULL, RW_DRIVER, NULL); + LIST_INIT(&netd_head); +} + + +static net_data_t +net_find(const char *protocol) +{ + struct net_data *n; + + ASSERT(protocol != NULL); + + LIST_FOREACH(n, &netd_head, netd_list) { + ASSERT(n->netd_info.neti_protocol != NULL); + if (strcmp(n->netd_info.neti_protocol, protocol) == 0) { + break; + } + } + + return (n); +} + + +net_data_t +net_register(const net_info_t *info) +{ + struct net_data *n, *new; + + ASSERT(info != NULL); + + new = kmem_alloc(sizeof (*new), KM_SLEEP); + new->netd_refcnt = 0; + new->netd_hooks = NULL; + new->netd_info = *info; + + rw_enter(&netlock, RW_WRITER); + n = net_find(info->neti_protocol); + if (n != NULL) { + rw_exit(&netlock); + kmem_free(new, sizeof (*new)); + return (NULL); + } + + if (LIST_EMPTY(&netd_head)) + LIST_INSERT_HEAD(&netd_head, new, netd_list); + else + LIST_INSERT_AFTER(LIST_FIRST(&netd_head), new, netd_list); + + rw_exit(&netlock); + return (new); +} + + +int +net_unregister(net_data_t info) +{ + + ASSERT(info != NULL); + + rw_enter(&netlock, RW_WRITER); + if (info->netd_refcnt != 0) { + rw_exit(&netlock); + return (EBUSY); + } + + LIST_REMOVE(info, netd_list); + + rw_exit(&netlock); + + kmem_free(info, sizeof (struct net_data)); + return (0); +} + + +net_data_t +net_lookup(const char *protocol) +{ + struct net_data *n; + + ASSERT(protocol != NULL); + + rw_enter(&netlock, RW_READER); + n = net_find(protocol); + if (n != NULL) + atomic_add_32((uint_t *)&n->netd_refcnt, 1); + rw_exit(&netlock); + return (n); +} + +/* + * Note: the man page specifies "returns -1 if the value passed in is unknown + * to this framework". We are not doing a lookup in this function, just a + * simply add to the netd_refcnt of the net_data_t passed in, so -1 is never a + * return value. + */ +int +net_release(net_data_t info) +{ + ASSERT(info != NULL); + + rw_enter(&netlock, RW_READER); + ASSERT(info->netd_refcnt > 0); + atomic_add_32((uint_t *)&info->netd_refcnt, -1); + + /* net_release has been called too many times */ + if (info->netd_refcnt < 0) { + rw_exit(&netlock); + return (1); + } + rw_exit(&netlock); + return (0); +} + + +net_data_t +net_walk(net_data_t info) +{ + struct net_data *n = NULL; + boolean_t found = B_FALSE; + + if (info == NULL) + found = B_TRUE; + + rw_enter(&netlock, RW_READER); + LIST_FOREACH(n, &netd_head, netd_list) { + if (found) + break; + if (n == info) + found = B_TRUE; + } + + if (info != NULL) { + ASSERT(info->netd_refcnt > 0); + atomic_add_32((uint_t *)&info->netd_refcnt, -1); + } + if (n != NULL) + atomic_add_32((uint_t *)&n->netd_refcnt, 1); + + rw_exit(&netlock); + return (n); +} + + +/* + * Public accessor functions + */ +int +net_getifname(net_data_t info, phy_if_t phy_ifdata, + char *buffer, const size_t buflen) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_getifname(phy_ifdata, buffer, buflen)); +} + + +int +net_getmtu(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_getmtu(phy_ifdata, ifdata)); +} + + +int +net_getpmtuenabled(net_data_t info) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_getpmtuenabled()); +} + + +int +net_getlifaddr(net_data_t info, phy_if_t phy_ifdata, lif_if_t ifdata, + int nelem, net_ifaddr_t type[], void *storage) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_getlifaddr(phy_ifdata, ifdata, + nelem, type, storage)); +} + + +phy_if_t +net_phygetnext(net_data_t info, phy_if_t phy_ifdata) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_phygetnext(phy_ifdata)); +} + + +phy_if_t +net_phylookup(net_data_t info, const char *name) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_phylookup(name)); +} + + +lif_if_t +net_lifgetnext(net_data_t info, phy_if_t ifidx, lif_if_t ifdata) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_lifgetnext(ifidx, ifdata)); +} + + +int +net_inject(net_data_t info, inject_t style, net_inject_t *packet) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_inject(style, packet)); +} + + +phy_if_t +net_routeto(net_data_t info, struct sockaddr *address) +{ + + ASSERT(info != NULL); + + return (info->netd_info.neti_routeto(address)); +} + + +int +net_ispartialchecksum(net_data_t info, mblk_t *mp) +{ + + ASSERT(info != NULL); + ASSERT(mp != NULL); + + return (info->netd_info.neti_ispartialchecksum(mp)); +} + + +int +net_isvalidchecksum(net_data_t info, mblk_t *mp) +{ + + ASSERT(info != NULL); + ASSERT(mp != NULL); + + return (info->netd_info.neti_isvalidchecksum(mp)); +} + + +/* + * Hooks related functions + */ + +/* + * Function: net_register_family + * Returns: int - 0 = Succ, Else = Fail + * Parameters: info(I) - protocol + * hf(I) - family pointer + * + * Call hook_family_add to register family + */ +int +net_register_family(net_data_t info, hook_family_t *hf) +{ + hook_family_int_t *hfi; + + ASSERT(info != NULL); + ASSERT(hf != NULL); + + if (info->netd_hooks != NULL) + return (EEXIST); + + hfi = hook_family_add(hf); + if (hfi == NULL) + return (EEXIST); + + info->netd_hooks = hfi; + return (0); +} + + +/* + * Function: net_unregister_family + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * hf(I) - family pointer + * + * Call hook_family_remove to unregister family + */ +int +net_unregister_family(net_data_t info, hook_family_t *hf) +{ + int ret; + + ASSERT(info != NULL); + ASSERT(hf != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + if (strcmp(info->netd_hooks->hfi_family.hf_name, + hf->hf_name) != 0) + return (EINVAL); + + ret = hook_family_remove(info->netd_hooks); + if (ret == 0) + info->netd_hooks = NULL; + + return (ret); +} + + +/* + * Function: net_register_event + * Returns: internal event pointer - NULL = Fail + * Parameters: info(I) - protocol + * he(I) - event pointer + * + * Call hook_event_add to register event on specific family + * Internal event pointer is returned so caller can get + * handle to run hooks + */ +hook_event_token_t +net_register_event(net_data_t info, hook_event_t *he) +{ + hook_event_int_t *hei; + + ASSERT(info != NULL); + ASSERT(he != NULL); + + if (info->netd_hooks == NULL) + return (NULL); + + hei = hook_event_add(info->netd_hooks, he); + return ((hook_event_token_t)hei); +} + + +/* + * Function: net_unregister_event + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * he(I) - event pointer + * + * Call hook_event_remove to unregister event on specific family + */ +int +net_unregister_event(net_data_t info, hook_event_t *he) +{ + + ASSERT(info != NULL); + ASSERT(he != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_event_remove(info->netd_hooks, he)); +} + + +/* + * Function: net_register_hook + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * event(I) - event name + * h(I) - hook pointer + * + * Call hook_register to add hook on specific family/event + */ +int +net_register_hook(net_data_t info, char *event, hook_t *h) +{ + + ASSERT(info != NULL); + ASSERT(event != NULL); + ASSERT(h != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_register(info->netd_hooks, event, h)); +} + + +/* + * Function: net_unregister_hook + * Returns: int - transparent value, explained by caller + * Parameters: info(I) - protocol + * event(I) - event name + * h(I) - hook pointer + * + * Call hook_unregister to remove hook on specific family/event + */ +int +net_unregister_hook(net_data_t info, char *event, hook_t *h) +{ + + ASSERT(info != NULL); + ASSERT(event != NULL); + ASSERT(h != NULL); + + if (info->netd_hooks == NULL) + return (ENXIO); + + return (hook_unregister(info->netd_hooks, event, h)); +} diff --git a/usr/src/uts/common/io/stream.c b/usr/src/uts/common/io/stream.c index 4f7e330b39..ec18ed82e3 100644 --- a/usr/src/uts/common/io/stream.c +++ b/usr/src/uts/common/io/stream.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -24,7 +23,7 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1378,6 +1377,7 @@ pullupmsg(mblk_t *mp, ssize_t len) mblk_t *bp, *b_cont; dblk_t *dbp; ssize_t n; + uint32_t start, stuff, end, value, flags; ASSERT(mp->b_datap->db_ref > 0); ASSERT(mp->b_next == NULL && mp->b_prev == NULL); @@ -1421,6 +1421,13 @@ pullupmsg(mblk_t *mp, ssize_t len) bp->b_datap->db_mblk = bp; mp->b_rptr = mp->b_wptr = dbp->db_base; + /* + * Need to preserve checksum information by copying them + * to mp which heads the pulluped message. + */ + hcksum_retrieve(bp, NULL, NULL, &start, &stuff, &end, &value, &flags); + (void) hcksum_assoc(mp, NULL, NULL, start, stuff, end, value, flags, 0); + do { ASSERT(bp->b_datap->db_ref > 0); ASSERT(bp->b_wptr >= bp->b_rptr); @@ -1453,6 +1460,7 @@ msgpullup(mblk_t *mp, ssize_t len) mblk_t *newmp; ssize_t totlen; ssize_t n; + uint32_t start, stuff, end, value, flags; /* * We won't handle Multidata message, since it contains @@ -1481,6 +1489,14 @@ msgpullup(mblk_t *mp, ssize_t len) newmp->b_flag = mp->b_flag; newmp->b_band = mp->b_band; + /* + * Need to preserve checksum information by copying them + * to newmp which heads the pulluped message. + */ + hcksum_retrieve(mp, NULL, NULL, &start, &stuff, &end, &value, &flags); + (void) hcksum_assoc(newmp, NULL, NULL, start, stuff, end, + value, flags, 0); + while (len > 0) { n = mp->b_wptr - mp->b_rptr; ASSERT(n >= 0); /* allow zero-length mblk_t's */ diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index e133c8a49e..4239f7bf6f 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -246,6 +246,9 @@ CHKHDRS= \ gld.h \ gldpriv.h \ hdio.h \ + hook.h \ + hook_event.h \ + hook_impl.h \ hwconf.h \ ia.h \ iapriocntl.h \ @@ -339,6 +342,7 @@ CHKHDRS= \ ndifm.h \ ndi_impldefs.h \ netconfig.h \ + neti.h \ nexusdefs.h \ note.h \ nvpair.h \ @@ -353,6 +357,7 @@ CHKHDRS= \ pathconf.h \ pathname.h \ pattr.h \ + queue.h \ serializer.h \ pbio.h \ pccard.h \ diff --git a/usr/src/uts/common/sys/condvar_impl.h b/usr/src/uts/common/sys/condvar_impl.h index f94a6cb54e..15adcedb93 100644 --- a/usr/src/uts/common/sys/condvar_impl.h +++ b/usr/src/uts/common/sys/condvar_impl.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -19,9 +18,10 @@ * * CDDL HEADER END */ + /* - * Copyright (c) 1991-1997 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_CONDVAR_IMPL_H @@ -56,6 +56,52 @@ typedef struct _condvar_impl { #endif /* _ASM */ + +typedef struct cvwaitlock_s { + kmutex_t cvw_lock; + kcondvar_t cvw_waiter; + int cvw_refcnt; +} cvwaitlock_t; + + +#define CVW_INIT(_c) { \ + mutex_init(&(_c)->cvw_lock, NULL, MUTEX_DRIVER, NULL); \ + cv_init(&(_c)->cvw_waiter, NULL, CV_DRIVER, NULL); \ + (_c)->cvw_refcnt = 0; \ +} + +#define CVW_ENTER_READ(_c) { \ + mutex_enter(&(_c)->cvw_lock); \ + while ((_c)->cvw_refcnt < 0) \ + cv_wait(&((_c)->cvw_waiter), &(_c)->cvw_lock); \ + (_c)->cvw_refcnt++; \ + mutex_exit(&(_c)->cvw_lock); \ +} + +#define CVW_ENTER_WRITE(_c) { \ + mutex_enter(&(_c)->cvw_lock); \ + while ((_c)->cvw_refcnt != 0) \ + cv_wait(&((_c)->cvw_waiter), &(_c)->cvw_lock); \ + (_c)->cvw_refcnt = -1; \ + mutex_exit(&(_c)->cvw_lock); \ +} + +#define CVW_EXIT_READ(_c) { \ + mutex_enter(&(_c)->cvw_lock); \ + ASSERT((_c)->cvw_refcnt > 0); \ + if ((--((_c)->cvw_refcnt)) == 0) \ + cv_broadcast(&(_c)->cvw_waiter); \ + mutex_exit(&(_c)->cvw_lock); \ +} + +#define CVW_EXIT_WRITE(_c) { \ + mutex_enter(&(_c)->cvw_lock); \ + ASSERT((_c)->cvw_refcnt == -1); \ + (_c)->cvw_refcnt = 0; \ + cv_broadcast(&(_c)->cvw_waiter); \ + mutex_exit(&(_c)->cvw_lock); \ +} + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/hook.h b/usr/src/uts/common/sys/hook.h new file mode 100644 index 0000000000..c7a6779dc5 --- /dev/null +++ b/usr/src/uts/common/sys/hook.h @@ -0,0 +1,115 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file includes definitions of kernel hook framework components + */ + +#ifndef _SYS_HOOK_H +#define _SYS_HOOK_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/queue.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Definition exposed to hook provider and consumer + */ + +#define HOOK_VERSION 1 + +typedef uintptr_t hook_data_t; + +struct hook_event_int; +typedef struct hook_event_int *hook_event_token_t; + +typedef int (* hook_func_t)(hook_event_token_t, hook_data_t); + +/* + * Hook + */ +typedef struct hook { + int32_t h_version; /* version number */ + hook_func_t h_func; /* callback func */ + char *h_name; /* name of this hook */ + int h_flags; /* extra hook properties */ +} hook_t; + +#define HOOK_INIT(x, fn, r) \ + do { \ + (x)->h_version = HOOK_VERSION; \ + (x)->h_func = (fn); \ + (x)->h_name = (r); \ + (x)->h_flags = 0; \ + _NOTE(CONSTCOND) \ + } while (0) + +/* + * Family + */ +typedef struct hook_family { + int32_t hf_version; /* version number */ + char *hf_name; /* family name */ +} hook_family_t; + +#define HOOK_FAMILY_INIT(x, y) \ + do { \ + (x)->hf_version = HOOK_VERSION; \ + (x)->hf_name = (y); \ + _NOTE(CONSTCOND) \ + } while (0) + +/* + * Event + */ +typedef struct hook_event { + int32_t he_version; /* version number */ + char *he_name; /* name of this hook list */ + int he_flags; /* 1 = multiple entries allowed */ + boolean_t he_interested; /* true if callback exist */ +} hook_event_t; + +#define HOOK_RDONLY 0x1 /* Callbacks must not change data */ + /* Multiple callbacks are allowed */ + +#define HOOK_EVENT_INIT(x, y) \ + do { \ + (x)->he_version = HOOK_VERSION; \ + (x)->he_name = (y); \ + (x)->he_flags = 0; \ + (x)->he_interested = B_FALSE; \ + _NOTE(CONSTCOND) \ + } while (0) + + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_HOOK_H */ diff --git a/usr/src/uts/common/sys/hook_event.h b/usr/src/uts/common/sys/hook_event.h new file mode 100644 index 0000000000..7ad1214223 --- /dev/null +++ b/usr/src/uts/common/sys/hook_event.h @@ -0,0 +1,100 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file include definition of message passed from hook provider + * to hook consumer. If necessary, each hook provider can add its + * own message definition here. + */ + +#ifndef _SYS_HOOK_EVENT_H +#define _SYS_HOOK_EVENT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/neti.h> +#include <sys/hook.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The hook_pkt_event_t structure is supplied with packet events on + * associated network interfaces. + * + * The members of this structure are defined as follows: + * hpe_ifp - "in" interface for packets coming into the system or forwarded + * hpe_ofp - "out" interface for packets being transmitted or forwarded + * hpe_hdr - pointer to protocol header within the packet + * hpe_mp - pointer to the mblk pointer starting the chain for this packet + * hpe_mb - pointer to the mblk that contains hpe_hdr + */ +typedef struct hook_pkt_event { + phy_if_t hpe_ifp; + phy_if_t hpe_ofp; + void *hpe_hdr; + mblk_t **hpe_mp; + mblk_t *hpe_mb; +} hook_pkt_event_t; + +/* + * NIC events hook provider + */ +typedef enum nic_event { + NE_PLUMB = 1, + NE_UNPLUMB, + NE_UP, + NE_DOWN, + NE_ADDRESS_CHANGE +} nic_event_t; + +typedef void *nic_event_data_t; + +/* + * The hook_nic_event data structure is provided with all network interface + * events. + * + * hne_family - network family of events, returned from net_lookup + * hne_nic - physical interface associated with event + * hne_lif - logical interface (if any) associated with event + * hne_event - type of event occuring + * hne_data - pointer to extra data about event or NULL if none + * hne_datalen - size of data pointed to by hne_data (can be 0) + */ +typedef struct hook_nic_event { + net_data_t hne_family; + phy_if_t hne_nic; + lif_if_t hne_lif; + nic_event_t hne_event; + nic_event_data_t hne_data; + size_t hne_datalen; +} hook_nic_event_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_HOOK_EVENT_H */ diff --git a/usr/src/uts/common/sys/hook_impl.h b/usr/src/uts/common/sys/hook_impl.h new file mode 100644 index 0000000000..d8e169b2ae --- /dev/null +++ b/usr/src/uts/common/sys/hook_impl.h @@ -0,0 +1,136 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file include internal used definition and data structure of hooks + */ + +#ifndef _SYS_HOOK_IMPL_H +#define _SYS_HOOK_IMPL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/hook.h> +#include <sys/condvar_impl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The following diagram describes the linking together of data structures + * used in this implementation of callback hooks. The start of it all is + * the "familylist" variable in hook.c. The relationships between data + * structures is: + * - there is a list of hook families; + * - each hook family can have a list of hook events; + * - each hook_event_t must be uniquely associated with one family and event; + * - each hook event can have a list of registered hooks to call. + * + * familylist +--------------+ + * | | hook_event_t |<--\ + * | +--------------+ | + * V | + * +-------------------+ ->+------------------+ | ->+--------------+ + * | hook_family_int_t | / | hook_event_int_t | | / | hook_int_t | + * | +---------------+ | / | | / / | +----------+ | + * | | hook_family_t | | / | hei_event---------/ / | | hook_t | | + * | +---------------+ | / | | / | +----------+ | + * | | / | | / | | + * | hfi_head------------/ | hei_head-----------/ | hi_entry--\ | + * | hfi_entry--\ | | hei_entry--\ | +-----------|--+ + * +------------|------+ +------------|-----+ | + * | | | + * V V V + * +-------------------+ +------------------+ +--------------+ + * | hook_family_int_t | | hook_event_int_t | | hook_int_t | + * ... + */ + +/* + * hook_int: internal storage of hook + */ +typedef struct hook_int { + TAILQ_ENTRY(hook_int) hi_entry; + hook_t hi_hook; +} hook_int_t; + +/* + * Hook_int_head: tail queue of hook_int + */ +TAILQ_HEAD(hook_int_head, hook_int); +typedef struct hook_int_head hook_int_head_t; + +/* + * hook_event_int: internal storage of hook_event + */ +typedef struct hook_event_int { + cvwaitlock_t hei_lock; + SLIST_ENTRY(hook_event_int) hei_entry; + hook_event_t *hei_event; + hook_int_head_t hei_head; +} hook_event_int_t; + +/* + * hook_event_int_head: singly-linked list of hook_event_int + */ +SLIST_HEAD(hook_event_int_head, hook_event_int); +typedef struct hook_event_int_head hook_event_int_head_t; + +/* + * hook_family_int: internal storage of hook_family + */ +typedef struct hook_family_int { + SLIST_ENTRY(hook_family_int) hfi_entry; + hook_event_int_head_t hfi_head; + hook_family_t hfi_family; +} hook_family_int_t; + +/* + * hook_family_int_head: singly-linked list of hook_family + */ +SLIST_HEAD(hook_family_int_head, hook_family_int); +typedef struct hook_family_int_head hook_family_int_head_t; + +/* + * Names of hooks families currently defined by Solaris + */ +#define Hn_ARP "arp" +#define Hn_IPV4 "inet" +#define Hn_IPV6 "inet6" + +extern hook_family_int_t *hook_family_add(hook_family_t *); +extern int hook_family_remove(hook_family_int_t *); +extern hook_event_int_t *hook_event_add(hook_family_int_t *, hook_event_t *); +extern int hook_event_remove(hook_family_int_t *, hook_event_t *); +extern int hook_register(hook_family_int_t *, char *, hook_t *); +extern int hook_unregister(hook_family_int_t *, char *, hook_t *); +extern int hook_run(hook_event_token_t, hook_data_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_HOOK_IMPL_H */ diff --git a/usr/src/uts/common/sys/neti.h b/usr/src/uts/common/sys/neti.h new file mode 100644 index 0000000000..552ac25e93 --- /dev/null +++ b/usr/src/uts/common/sys/neti.h @@ -0,0 +1,197 @@ +/* + * CDDL HEADER START + * + * 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] + * + * CDDL HEADER END + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_NETI_H +#define _SYS_NETI_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <netinet/in.h> +#include <sys/int_types.h> +#include <sys/queue.h> +#include <sys/hook_impl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define NETINFO_VERSION 1 + +/* + * Network hooks framework stack protocol name + */ +#define NHF_INET "NHF_INET" +#define NHF_INET6 "NHF_INET6" +#define NHF_ARP "NHF_ARP" + +/* + * Event identification + */ +#define NH_PHYSICAL_IN "PHYSICAL_IN" +#define NH_PHYSICAL_OUT "PHYSICAL_OUT" +#define NH_FORWARDING "FORWARDING" +#define NH_LOOPBACK_IN "LOOPBACK_IN" +#define NH_LOOPBACK_OUT "LOOPBACK_OUT" +#define NH_NIC_EVENTS "NIC_EVENTS" + +/* + * Network NIC hardware checksum capability + */ +#define NET_HCK_NONE 0x00 +#define NET_HCK_L3_FULL 0x01 +#define NET_HCK_L3_PART 0x02 +#define NET_HCK_L4_FULL 0x10 +#define NET_HCK_L4_PART 0x20 + +#define NET_IS_HCK_L3_FULL(n, x) \ + ((net_ispartialchecksum(n, x) & NET_HCK_L3_FULL) == NET_HCK_L3_FULL) +#define NET_IS_HCK_L3_PART(n, x) \ + ((net_ispartialchecksum(n, x) & NET_HCK_L3_PART) == NET_HCK_L3_PART) +#define NET_IS_HCK_L4_FULL(n, x) \ + ((net_ispartialchecksum(n, x) & NET_HCK_L4_FULL) == NET_HCK_L4_FULL) +#define NET_IS_HCK_L4_PART(n, x) \ + ((net_ispartialchecksum(n, x) & NET_HCK_L4_PART) == NET_HCK_L4_PART) +#define NET_IS_HCK_L34_FULL(n, x) \ + ((net_ispartialchecksum(n, x) & (NET_HCK_L3_FULL|NET_HCK_L4_FULL)) \ + == (NET_HCK_L3_FULL | NET_HCK_L4_FULL)) + +typedef uintptr_t phy_if_t; +typedef intptr_t lif_if_t; +typedef uintptr_t net_ifdata_t; + +struct net_data; +typedef struct net_data *net_data_t; + +/* + * Netinfo interface specification + * + * Netinfo provides an extensible and easy to use interface for + * accessing data and functionality already embedded within network + * code that exists within the kernel. + */ +typedef enum net_ifaddr { + NA_ADDRESS = 1, + NA_PEER, + NA_BROADCAST, + NA_NETMASK +} net_ifaddr_t; + + +typedef enum inject { + NI_QUEUE_IN = 1, + NI_QUEUE_OUT, + NI_DIRECT_OUT +} inject_t; + +typedef struct net_inject { + mblk_t *ni_packet; + struct sockaddr_storage ni_addr; + phy_if_t ni_physical; +} net_inject_t; + + +/* + * net_info_t public interface + */ +typedef struct net_info { + int neti_version; + char *neti_protocol; + int (*neti_getifname)(phy_if_t, char *, const size_t); + int (*neti_getmtu)(phy_if_t, lif_if_t); + int (*neti_getpmtuenabled)(void); + int (*neti_getlifaddr)(phy_if_t, lif_if_t, size_t, + net_ifaddr_t [], void *); + phy_if_t (*neti_phygetnext)(phy_if_t); + phy_if_t (*neti_phylookup)(const char *); + lif_if_t (*neti_lifgetnext)(phy_if_t, lif_if_t); + int (*neti_inject)(inject_t, net_inject_t *); + phy_if_t (*neti_routeto)(struct sockaddr *); + int (*neti_ispartialchecksum)(mblk_t *); + int (*neti_isvalidchecksum)(mblk_t *); +} net_info_t; + + +/* + * Private data structures + */ +struct net_data { + LIST_ENTRY(net_data) netd_list; + net_info_t netd_info; + int netd_refcnt; + hook_family_int_t *netd_hooks; +}; + + +typedef struct injection_s { + net_inject_t inj_data; + boolean_t inj_isv6; +} injection_t; + +/* + * The ipif_id space is [0,MAX) but this interface wants to return [1,MAX] as + * a valid range of logical interface numbers so that it can return 0 to mean + * "end of list" with net_lifgetnext. Changing ipif_id's to use the [1,MAX] + * space is something to be considered for the future, if it is worthwhile. + */ +#define MAP_IPIF_ID(x) ((x) + 1) +#define UNMAP_IPIF_ID(x) (((x) > 0) ? (x) - 1 : (x)) + + +/* + * Data management functions + */ +extern net_data_t net_register(const net_info_t *); +extern int net_unregister(net_data_t); +extern net_data_t net_lookup(const char *); +extern int net_release(net_data_t); +extern net_data_t net_walk(net_data_t); + +/* + * Accessor functions + */ +extern int net_register_family(net_data_t, hook_family_t *); +extern int net_unregister_family(net_data_t, hook_family_t *); +extern hook_event_token_t net_register_event(net_data_t, hook_event_t *); +extern int net_unregister_event(net_data_t, hook_event_t *); +extern int net_register_hook(net_data_t, char *, hook_t *); +extern int net_unregister_hook(net_data_t, char *, hook_t *); +extern int net_getifname(net_data_t, phy_if_t, char *, const size_t); +extern int net_getmtu(net_data_t, phy_if_t, lif_if_t); +extern int net_getpmtuenabled(net_data_t); +extern int net_getlifaddr(net_data_t, phy_if_t, lif_if_t, + int, net_ifaddr_t [], void *); +extern phy_if_t net_phygetnext(net_data_t, phy_if_t); +extern phy_if_t net_phylookup(net_data_t, const char *); +extern lif_if_t net_lifgetnext(net_data_t, phy_if_t, lif_if_t); +extern int net_inject(net_data_t, inject_t, net_inject_t *); +extern phy_if_t net_routeto(net_data_t, struct sockaddr *); +extern int net_ispartialchecksum(net_data_t, mblk_t *); +extern int net_isvalidchecksum(net_data_t, mblk_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_NETI_H */ diff --git a/usr/src/uts/common/sys/queue.h b/usr/src/uts/common/sys/queue.h new file mode 100644 index 0000000000..cb814390a9 --- /dev/null +++ b/usr/src/uts/common/sys/queue.h @@ -0,0 +1,667 @@ +/* $NetBSD: queue.h,v 1.42 2005/07/13 15:08:24 wiz Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _SYS_QUEUE_H +#define _SYS_QUEUE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/note.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + panic("LIST_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + panic("LIST_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.le_prev != (elm)) \ + panic("LIST_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ + _NOTE(CONSTCOND) \ +} while (0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) \ + == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) \ + == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ + _NOTE(CONSTCOND) \ +} while (0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ + _NOTE(CONSTCOND) \ +} while (0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type) \ +struct name { \ + type *tqh_first; /* first element */ \ + type **tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type) \ +struct { \ + type *tqe_next; /* next element */ \ + type **tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type) + +/* + * Tail queue functions. + */ +#if defined(_KERNEL) && defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + panic("TAILQ_INSERT_HEAD %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + panic("TAILQ_INSERT_TAIL %p %s:%d", (head), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + panic("TAILQ_* forw %p %s:%d", (elm), __FILE__, __LINE__);\ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("TAILQ_* back %p %s:%d", (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + panic("TAILQ_PREREMOVE head %p elm %p %s:%d", \ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\ + (var); \ + (var) = \ + (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _NOTE(CONSTCOND) \ +} while (0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#ifdef __cplusplus +} +#endif + +#endif /* !_SYS_QUEUE_H */ diff --git a/usr/src/uts/common/sys/stream.h b/usr/src/uts/common/sys/stream.h index cb5a92b7d3..642cd276bf 100644 --- a/usr/src/uts/common/sys/stream.h +++ b/usr/src/uts/common/sys/stream.h @@ -393,8 +393,8 @@ typedef struct bcache { /* * db_flags values (all implementation private!) */ -#define DBLK_REFMIN 0x01 /* min refcnt stored in low bit */ -#define DBLK_COOKED 0x02 /* message has been processed once */ +#define DBLK_REFMIN 0x01 /* min refcnt stored in low bit */ +#define DBLK_COOKED 0x02 /* message has been processed once */ /* * db_struioflag values: diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared index e0064013fe..2c3f70e909 100644 --- a/usr/src/uts/intel/Makefile.intel.shared +++ b/usr/src/uts/intel/Makefile.intel.shared @@ -258,7 +258,6 @@ DRV_KMODS += mm DRV_KMODS += mouse8042 DRV_KMODS += nca DRV_KMODS += openeepr -DRV_KMODS += pfil DRV_KMODS += pm DRV_KMODS += poll DRV_KMODS += pool @@ -478,6 +477,7 @@ MISC_KMODS += fssnap_if MISC_KMODS += gda MISC_KMODS += gld MISC_KMODS += hidparser +MISC_KMODS += hook MISC_KMODS += hpcsvc MISC_KMODS_32 += i2o_msg MISC_KMODS += ibcm @@ -495,6 +495,7 @@ MISC_KMODS += mac MISC_KMODS += mixer MISC_KMODS += nfs_dlboot MISC_KMODS += nfssrv +MISC_KMODS += neti MISC_KMODS += pcicfg MISC_KMODS += pcihp MISC_KMODS += pcmcia diff --git a/usr/src/uts/intel/arp/Makefile b/usr/src/uts/intel/arp/Makefile index ba352e8dc8..62adad839b 100644 --- a/usr/src/uts/intel/arp/Makefile +++ b/usr/src/uts/intel/arp/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -22,7 +21,7 @@ # # uts/intel/arp/Makefile # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -69,7 +68,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) # # depends on ip # -LDFLAGS += -dy -Ndrv/ip +LDFLAGS += -dy -Ndrv/ip -Ndrv/hook -Nmisc/neti # # Default build targets. diff --git a/usr/src/uts/intel/pfil/Makefile b/usr/src/uts/intel/hook/Makefile index 14556577bf..9fa6442003 100644 --- a/usr/src/uts/intel/pfil/Makefile +++ b/usr/src/uts/intel/hook/Makefile @@ -19,17 +19,16 @@ # CDDL HEADER END # # +# uts/intel/hook/Makefile +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # -# uts/intel/pfil/Makefile -# -# This makefile drives the production of the pfil driver -# kernel module. +# This makefile drives the production of the hook driver kernel module. # -# intel architecture dependent +# INTEL implementation architecture dependent # # @@ -40,12 +39,11 @@ UTSBASE = ../.. # # Define the module and object file sets. # -MODULE = pfil -OBJECTS = $(PFIL_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PFIL_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) -ROOTLINK = $(ROOT_STRMOD_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/common/inet/pfil +MODULE = hook +OBJECTS = $(HOOK_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(HOOK_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) + # # Include common rules. @@ -55,13 +53,10 @@ include $(UTSBASE)/intel/Makefile.intel # # Define targets # -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) -MINOR= echo $(RELEASE) | cut -d. -f2 -CPPFLAGS += -DSUNDDI -DSOLARIS2=$(MINOR:sh) -DIRE_ILL_CN -DSOLARIS -DUSE_INET6 -LDFLAGS += -dy -Ndrv/ip # # Default build targets. @@ -84,8 +79,6 @@ clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -$(ROOTLINK): $(ROOT_STRMOD_DIR) $(ROOTMODULE) - -$(RM) $@; ln $(ROOTMODULE) $@ # # Include common targets. diff --git a/usr/src/uts/intel/ip/Makefile b/usr/src/uts/intel/ip/Makefile index f1af1c3d9e..2df8555cce 100644 --- a/usr/src/uts/intel/ip/Makefile +++ b/usr/src/uts/intel/ip/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -67,7 +66,7 @@ CFLAGS += $(CINLINEFLAGS) # swrand as it needs random numbers early on during boot before # kCF subsystem can load swrand. # -LDFLAGS += -dy -Nmisc/md5 -Ncrypto/swrand +LDFLAGS += -dy -Nmisc/md5 -Ncrypto/swrand -Nmisc/hook -Nmisc/neti # # Default build targets. diff --git a/usr/src/uts/intel/ipf/Makefile b/usr/src/uts/intel/ipf/Makefile index 84d447a2cc..122a9d66f7 100644 --- a/usr/src/uts/intel/ipf/Makefile +++ b/usr/src/uts/intel/ipf/Makefile @@ -1,4 +1,24 @@ # +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -41,7 +61,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) MINOR= echo $(RELEASE) | cut -d. -f2 CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP -DUSE_INET6 CPPFLAGS += -DSUNDDI -DSOLARIS2=$(MINOR:sh) -DIRE_ILL_CN -LDFLAGS += -dy -Ndrv/ip -Ndrv/pfil -Nmisc/md5 +LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti INC_PATH += -I$(UTSBASE)/common/inet/ipf diff --git a/usr/src/uts/intel/neti/Makefile b/usr/src/uts/intel/neti/Makefile new file mode 100644 index 0000000000..069cacc8d2 --- /dev/null +++ b/usr/src/uts/intel/neti/Makefile @@ -0,0 +1,86 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# +# uts/intel/neti/Makefile +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the neti driver kernel module. +# +# INTEL implementation architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = neti +OBJECTS = $(NETI_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NETI_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/intel/Makefile.intel + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +LDFLAGS += -dy -Nmisc/hook + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/intel/Makefile.targ diff --git a/usr/src/uts/intel/os/device_policy b/usr/src/uts/intel/os/device_policy index 77d9b9520f..184ac3454d 100644 --- a/usr/src/uts/intel/os/device_policy +++ b/usr/src/uts/intel/os/device_policy @@ -84,5 +84,4 @@ aggr:ctl read_priv_set=sys_net_config write_priv_set=sys_net_config # IP Filter # ipf read_priv_set=sys_net_config write_priv_set=sys_net_config -pfil read_priv_set=net_rawaccess write_priv_set=net_rawaccess diff --git a/usr/src/uts/intel/os/minor_perm b/usr/src/uts/intel/os/minor_perm index 3929c6f960..582bdecb60 100644 --- a/usr/src/uts/intel/os/minor_perm +++ b/usr/src/uts/intel/os/minor_perm @@ -107,7 +107,6 @@ ramdisk:ctl 0644 root sys cryptoadm:cryptoadm 0644 root sys crypto:crypto 0666 root sys ipf:* 0666 root sys -pfil:* 0666 root sys bl:* 0666 root sys sctp:* 0666 root sys sctp6:* 0666 root sys diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major index 1bd224f2d5..9133b5f4d3 100644 --- a/usr/src/uts/intel/os/name_to_major +++ b/usr/src/uts/intel/os/name_to_major @@ -98,7 +98,6 @@ bscv 161 pool 163 zcons 164 ipf 165 -pfil 166 fasttrap 167 bl 168 mpt 169 diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared index 0aee1eae57..2f9a657cbd 100644 --- a/usr/src/uts/sparc/Makefile.sparc.shared +++ b/usr/src/uts/sparc/Makefile.sparc.shared @@ -234,7 +234,7 @@ DRV_KMODS += spdsock DRV_KMODS += tcp tcp6 tl tnf ttymux udp udp6 wc winlock zcons DRV_KMODS += ippctl sctp sctp6 DRV_KMODS += dld -DRV_KMODS += ipf pfil +DRV_KMODS += ipf DRV_KMODS += rpcib DRV_KMODS += vni DRV_KMODS += xge @@ -371,6 +371,8 @@ MISC_KMODS += ibcm MISC_KMODS += ibdm MISC_KMODS += ibmf MISC_KMODS += ibtl +MISC_KMODS += hook +MISC_KMODS += neti MISC_KMODS += ctf MISC_KMODS += zmod MISC_KMODS += mac dls diff --git a/usr/src/uts/sparc/arp/Makefile b/usr/src/uts/sparc/arp/Makefile index 80ca383b2c..6f97e434d1 100644 --- a/usr/src/uts/sparc/arp/Makefile +++ b/usr/src/uts/sparc/arp/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -21,7 +20,7 @@ # # # uts/sparc/arp/Makefile -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -73,7 +72,7 @@ CFLAGS += $(CCVERBOSE) # # depends on ip # -LDFLAGS += -dy -Ndrv/ip +LDFLAGS += -dy -Ndrv/ip -Ndrv/hook -Nmisc/neti # # Default build targets. diff --git a/usr/src/uts/sparc/hook/Makefile b/usr/src/uts/sparc/hook/Makefile new file mode 100644 index 0000000000..53a95c8d1b --- /dev/null +++ b/usr/src/uts/sparc/hook/Makefile @@ -0,0 +1,88 @@ +# +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# +# uts/sparc/hook/Makefile +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +#ident "%Z%%M% %I% %E% SMI" +# +# This makefile drives the production of the hook driver kernel module. +# +# SPARC architecture dependent +# + +# +# Path to the base of the uts directory tree (usually /usr/src/uts). +# +UTSBASE = ../.. + +# +# Define the module and object file sets. +# +MODULE = hook +OBJECTS = $(HOOK_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(HOOK_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) + +# +# Include common rules. +# +include $(UTSBASE)/sparc/Makefile.sparc + +# +# Define targets +# +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) + +# +# lint pass one enforcement +# +CFLAGS += $(CCVERBOSE) + +# +# Default build targets. +# +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +# +# Include common targets. +# +include $(UTSBASE)/sparc/Makefile.targ diff --git a/usr/src/uts/sparc/ip/Makefile b/usr/src/uts/sparc/ip/Makefile index aff0025a14..150ebca372 100644 --- a/usr/src/uts/sparc/ip/Makefile +++ b/usr/src/uts/sparc/ip/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -69,7 +68,7 @@ CFLAGS += -xinline=tcp_set_ws_value # swrand as it needs random numbers early on during boot before # kCF subsystem can load swrand. # -LDFLAGS += -dy -Nmisc/md5 -Ncrypto/swrand +LDFLAGS += -dy -Nmisc/md5 -Ncrypto/swrand -Nmisc/hook -Nmisc/neti # # Default build targets. diff --git a/usr/src/uts/sparc/ipf/Makefile b/usr/src/uts/sparc/ipf/Makefile index c0400bb4c4..0fedfdc8a9 100644 --- a/usr/src/uts/sparc/ipf/Makefile +++ b/usr/src/uts/sparc/ipf/Makefile @@ -1,4 +1,24 @@ # +# CDDL HEADER START +# +# 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] +# +# CDDL HEADER END +# +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -46,7 +66,7 @@ MINOR= echo $(RELEASE) | cut -d. -f2 CFLAGS += $(CCVERBOSE) CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP CPPFLAGS += -DSUNDDI -DSOLARIS2=$(MINOR:sh) -DIRE_ILL_CN -DUSE_INET6 -LDFLAGS += -dy -Ndrv/ip -Ndrv/pfil -Nmisc/md5 +LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti INC_PATH += -I$(UTSBASE)/common/inet/ipf diff --git a/usr/src/uts/sparc/pfil/Makefile b/usr/src/uts/sparc/neti/Makefile index fae0500ce1..9b5985c734 100644 --- a/usr/src/uts/sparc/pfil/Makefile +++ b/usr/src/uts/sparc/neti/Makefile @@ -19,17 +19,16 @@ # CDDL HEADER END # # +# uts/sparc/neti/Makefile +# # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # -# uts/sparc/pfil/Makefile -# -# This makefile drives the production of the pfil driver -# kernel module. +# This makefile drives the production of the neti driver kernel module. # -# sparc architecture dependent +# SPARC implementation architecture dependent # # @@ -40,12 +39,10 @@ UTSBASE = ../.. # # Define the module and object file sets. # -MODULE = pfil -OBJECTS = $(PFIL_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(PFIL_OBJS:%.o=$(LINTS_DIR)/%.ln) -ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) -ROOTLINK = $(ROOT_STRMOD_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/common/inet/pfil +MODULE = neti +OBJECTS = $(NETI_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(NETI_OBJS:%.o=$(LINTS_DIR)/%.ln) +ROOTMODULE = $(ROOT_MISC_DIR)/$(MODULE) # # Include common rules. @@ -55,17 +52,16 @@ include $(UTSBASE)/sparc/Makefile.sparc # # Define targets # -ALL_TARGET = $(BINARY) $(SRC_CONFFILE) +ALL_TARGET = $(BINARY) LINT_TARGET = $(MODULE).lint -INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) $(ROOT_CONFFILE) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOTLINK) # -# lint pass one enforcement and OS version +# lint pass one enforcement # -MINOR= echo $(RELEASE) | cut -d. -f2 CFLAGS += $(CCVERBOSE) -CPPFLAGS += -DSUNDDI -DSOLARIS2=$(MINOR:sh) -DIRE_ILL_CN -DSOLARIS -DUSE_INET6 -LDFLAGS += -dy -Ndrv/ip + +LDFLAGS += -dy -Nmisc/hook # # Default build targets. @@ -82,15 +78,12 @@ clobber: $(CLOBBER_DEPS) lint: $(LINT_DEPS) -modlintlib: $(MODLINTLIB_DEPS) lint64 +modlintlib: $(MODLINTLIB_DEPS) clean.lint: $(CLEAN_LINT_DEPS) install: $(INSTALL_DEPS) -$(ROOTLINK): $(ROOT_STRMOD_DIR) $(ROOTMODULE) - -$(RM) $@; ln $(ROOTMODULE) $@ - # # Include common targets. # diff --git a/usr/src/uts/sparc/os/device_policy b/usr/src/uts/sparc/os/device_policy index dc961eaccb..0e8e3f5b13 100644 --- a/usr/src/uts/sparc/os/device_policy +++ b/usr/src/uts/sparc/os/device_policy @@ -90,5 +90,4 @@ aggr:ctl read_priv_set=sys_net_config write_priv_set=sys_net_config # IP Filter # ipf read_priv_set=sys_net_config write_priv_set=sys_net_config -pfil read_priv_set=net_rawaccess write_priv_set=net_rawaccess diff --git a/usr/src/uts/sparc/os/minor_perm b/usr/src/uts/sparc/os/minor_perm index 7c5c275982..bd165cbef9 100644 --- a/usr/src/uts/sparc/os/minor_perm +++ b/usr/src/uts/sparc/os/minor_perm @@ -136,7 +136,6 @@ ramdisk:ctl 0644 root sys cryptoadm:cryptoadm 0644 root sys crypto:crypto 0666 root sys ipf:* 0666 root sys -pfil:* 0666 root sys bl:* 0666 root sys sctp:* 0666 root sys sctp6:* 0666 root sys diff --git a/usr/src/uts/sparc/os/name_to_major b/usr/src/uts/sparc/os/name_to_major index 6953ae6833..f500ac8dca 100644 --- a/usr/src/uts/sparc/os/name_to_major +++ b/usr/src/uts/sparc/os/name_to_major @@ -175,7 +175,6 @@ todds1307 225 pool 226 zcons 227 ipf 228 -pfil 229 ctsmc 230 bl 231 ibd 232 |