summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorDarren Reed <Darren.Reed@Sun.COM>2008-09-08 14:46:50 -0700
committerDarren Reed <Darren.Reed@Sun.COM>2008-09-08 14:46:50 -0700
commit7ddc9b1afd18f260b9fb78ec7732facd91769131 (patch)
tree1a305ae7471e9362c1ba0ea3d32834448059eb00 /usr/src
parent7739299d04f7910358ca2ad79106f174022a9ab2 (diff)
downloadillumos-gate-7ddc9b1afd18f260b9fb78ec7732facd91769131.tar.gz
PSARC/2008/219 Committed API for packet interception
PSARC/2008/335 Corrections for Committed API for packet interception PSARC/2008/557 Revision to net instance notification API 4844507 Solaris needs stable interface for packet filtering software 6705155 ipf_stack_init() assumes kmem_alloc with KM_NOSLEEP never fails
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/ipf/tools/ip_fil.c7
-rw-r--r--usr/src/cmd/ipf/tools/ipftest.c18
-rw-r--r--usr/src/cmd/mdb/common/modules/hook/hook.c48
-rw-r--r--usr/src/cmd/mdb/common/modules/neti/neti.c12
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/inet/arp/arp.c27
-rw-r--r--usr/src/uts/common/inet/arp/arp_netinfo.c96
-rw-r--r--usr/src/uts/common/inet/arp_impl.h18
-rw-r--r--usr/src/uts/common/inet/ip.h14
-rw-r--r--usr/src/uts/common/inet/ip/ip.c16
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c54
-rw-r--r--usr/src/uts/common/inet/ip/ip_netinfo.c358
-rw-r--r--usr/src/uts/common/inet/ip_stack.h6
-rw-r--r--usr/src/uts/common/inet/ipf/fil.c2
-rw-r--r--usr/src/uts/common/inet/ipf/ip_auth.c2
-rw-r--r--usr/src/uts/common/inet/ipf/ip_fil_solaris.c457
-rw-r--r--usr/src/uts/common/inet/ipf/ip_log.c6
-rw-r--r--usr/src/uts/common/inet/ipf/ip_nat.c4
-rw-r--r--usr/src/uts/common/inet/ipf/ip_nat6.c6
-rw-r--r--usr/src/uts/common/inet/ipf/ip_proxy.c2
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_fil.h3
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ipf_stack.h30
-rw-r--r--usr/src/uts/common/inet/ipf/solaris.c195
-rw-r--r--usr/src/uts/common/io/hook.c1659
-rw-r--r--usr/src/uts/common/io/neti.c636
-rw-r--r--usr/src/uts/common/io/neti_impl.c621
-rw-r--r--usr/src/uts/common/io/neti_mod.c80
-rw-r--r--usr/src/uts/common/io/neti_stack.c840
-rw-r--r--usr/src/uts/common/os/netstack.c9
-rw-r--r--usr/src/uts/common/sys/condvar_impl.h12
-rw-r--r--usr/src/uts/common/sys/hook.h59
-rw-r--r--usr/src/uts/common/sys/hook_event.h19
-rw-r--r--usr/src/uts/common/sys/hook_impl.h135
-rw-r--r--usr/src/uts/common/sys/neti.h191
-rw-r--r--usr/src/uts/common/sys/netstack.h43
-rw-r--r--usr/src/uts/intel/hook/hook.global-objs.debug645
-rw-r--r--usr/src/uts/intel/ipf/Makefile4
-rw-r--r--usr/src/uts/intel/ipf/ipf.global-objs.debug644
-rw-r--r--usr/src/uts/intel/neti/neti.global-objs.debug646
-rw-r--r--usr/src/uts/sparc/hook/hook.global-objs.debug645
-rw-r--r--usr/src/uts/sparc/ipf/Makefile4
-rw-r--r--usr/src/uts/sparc/ipf/ipf.global-objs.debug644
-rw-r--r--usr/src/uts/sparc/neti/Makefile4
-rw-r--r--usr/src/uts/sparc/neti/neti.global-objs.debug646
44 files changed, 4195 insertions, 1534 deletions
diff --git a/usr/src/cmd/ipf/tools/ip_fil.c b/usr/src/cmd/ipf/tools/ip_fil.c
index 29d69a8b07..a9824140d8 100644
--- a/usr/src/cmd/ipf/tools/ip_fil.c
+++ b/usr/src/cmd/ipf/tools/ip_fil.c
@@ -7,8 +7,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#if !defined(lint)
static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.133.2.9 2005/01/08 14:22:18 darrenr Exp $";
@@ -175,9 +173,8 @@ static int write_output __P((struct ifnet *, struct mbuf *,
#endif
-int iplattach(ifs, ns)
+int iplattach(ifs)
ipf_stack_t *ifs;
-netstack_t *ns;
{
ifs->ifs_fr_running = 1;
return 0;
@@ -311,7 +308,7 @@ int mode;
if (error)
break;
if (tmp)
- error = iplattach(ifs, NULL);
+ error = iplattach(ifs);
else
error = ipldetach(ifs);
}
diff --git a/usr/src/cmd/ipf/tools/ipftest.c b/usr/src/cmd/ipf/tools/ipftest.c
index 4463e132de..04e1322acf 100644
--- a/usr/src/cmd/ipf/tools/ipftest.c
+++ b/usr/src/cmd/ipf/tools/ipftest.c
@@ -3,12 +3,10 @@
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "ipf.h"
#include "ipt.h"
#include <sys/ioctl.h>
@@ -40,7 +38,6 @@ void drain_log __P((char *, ipf_stack_t *ifs));
void fixv4sums __P((mb_t *, ip_t *));
ipf_stack_t *get_ifs __P((void));
ipf_stack_t *create_ifs __P((void));
-netstack_t *create_ns __P((void));
#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \
@@ -84,7 +81,6 @@ char *argv[];
mb_t mb, *m;
ip_t *ip;
ipf_stack_t *ifs;
- netstack_t *ns;
m = &mb;
dir = 0;
@@ -99,8 +95,6 @@ char *argv[];
initparse();
ifs = create_ifs();
- ns = create_ns();
- ifs->ifs_netstack = ns;
#if defined(IPFILTER_DEFAULT_BLOCK)
ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH;
@@ -829,13 +823,3 @@ get_ifs()
{
return (gifs);
}
-
-netstack_t *
-create_ns()
-{
- netstack_t *ns;
-
- KMALLOCS(ns, netstack_t *, sizeof (*ns));
- bzero(ns, sizeof (*ns));
- return (ns);
-}
diff --git a/usr/src/cmd/mdb/common/modules/hook/hook.c b/usr/src/cmd/mdb/common/modules/hook/hook.c
index ec9679b2f9..353a592c64 100644
--- a/usr/src/cmd/mdb/common/modules/hook/hook.c
+++ b/usr/src/cmd/mdb/common/modules/hook/hook.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 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>
@@ -47,6 +45,8 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
char hrstr[MAX_LENGTH];
GElf_Sym sym;
char buf[MDB_SYM_NAMLEN + 1];
+ char *hintname;
+ hook_t *h;
if (argc)
return (DCMD_USAGE);
@@ -56,8 +56,9 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
return (DCMD_ERR);
}
- mdb_printf("%<u>%?s %10s %20s %?s%</u>\n",
- "ADDR", "FLAG", "FUNC", "NAME");
+ mdb_printf("%<u>%?s %8s %20s %4s %24s %24s%</u>\n",
+ "ADDR", "FLAG", "FUNC", "HINT", "NAME", "HINTVALUE");
+ h = &hl.hi_hook;
hlp = TAILQ_FIRST(&hr.hei_head);
while (hlp) {
if (mdb_vread((void *)&hl, sizeof (hl),
@@ -66,30 +67,39 @@ hooklist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
hlp);
return (DCMD_ERR);
}
- if (!hl.hi_hook.h_name) {
- mdb_warn("hook list at %p has null role",
- hl.hi_hook);
+ if (!h->h_name) {
+ mdb_warn("hook list at %p has null role", h);
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);
+ (uintptr_t)h->h_name) == -1) {
+ mdb_warn("couldn't read list role at %p", h->h_name);
return (DCMD_ERR);
}
- if (mdb_lookup_by_addr((uintptr_t)hl.hi_hook.h_func,
+ switch (h->h_hint) {
+ case HH_BEFORE :
+ case HH_AFTER :
+ hintname = h->h_hintvalue ?
+ (char *)h->h_hintvalue : "";
+ break;
+ default :
+ hintname = "";
+ break;
+ }
+ if (mdb_lookup_by_addr((uintptr_t)h->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);
+ mdb_printf("%0?p %8x %0?p %4d %24s %24s\n",
+ hlp, h->h_flags, h->h_func,
+ h->h_hint, hrstr, hintname);
else
- mdb_printf("%0?p %10x %20s %10s\n",
- hlp, hl.hi_hook.h_flags, buf, hrstr);
+ mdb_printf("%0?p %8x %20s %4d %24s %24s\n",
+ hlp, h->h_flags, buf,
+ h->h_hint, hrstr, hintname);
hlp = TAILQ_NEXT(&hl, hi_entry);
}
return (DCMD_OK);
}
-
/*
* List pfhooks event information.
* List the hooks information in verbose mode as well.
@@ -217,7 +227,7 @@ hookevent_stack_walk_init(mdb_walk_state_t *wsp)
}
wsp->walk_addr = (uintptr_t)SLIST_FIRST(&hf.hfi_head);
return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
- wsp->walk_cbdata));
+ wsp->walk_cbdata));
}
static int
@@ -234,7 +244,7 @@ hookevent_stack_walk_step(mdb_walk_state_t *wsp)
if (wsp->walk_addr == NULL)
return (WALK_DONE);
return (wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
- wsp->walk_cbdata));
+ wsp->walk_cbdata));
}
static const mdb_dcmd_t dcmds[] = {
diff --git a/usr/src/cmd/mdb/common/modules/neti/neti.c b/usr/src/cmd/mdb/common/modules/neti/neti.c
index e58fa42f0b..e18110997f 100644
--- a/usr/src/cmd/mdb/common/modules/neti/neti.c
+++ b/usr/src/cmd/mdb/common/modules/neti/neti.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 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>
@@ -72,15 +70,15 @@ netinfolist(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_warn("couldn't read netinfo at %p", p);
return (DCMD_ERR);
}
- if (!nd.netd_info.neti_protocol) {
+ if (!nd.netd_info.netp_name) {
mdb_warn("netinfo at %p has null protocol",
- nd.netd_info.neti_protocol);
+ nd.netd_info.netp_name);
return (DCMD_ERR);
}
if (mdb_readstr((char *)str, sizeof (str),
- (uintptr_t)nd.netd_info.neti_protocol) == -1) {
+ (uintptr_t)nd.netd_info.netp_name) == -1) {
mdb_warn("couldn't read protocol at %p",
- nd.netd_info.neti_protocol);
+ nd.netd_info.netp_name);
return (DCMD_ERR);
}
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 89132ff644..b1b98171a9 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -495,7 +495,7 @@ IP6_OBJS += ip6ddi.o
HOOK_OBJS += hook.o
-NETI_OBJS += neti.o
+NETI_OBJS += neti_impl.o neti_mod.o neti_stack.o
KEYSOCK_OBJS += keysockddi.o keysock.o keysock_opt_data.o
diff --git a/usr/src/uts/common/inet/arp/arp.c b/usr/src/uts/common/inet/arp/arp.c
index 7ad9f29d25..314963616d 100644
--- a/usr/src/uts/common/inet/arp/arp.c
+++ b/usr/src/uts/common/inet/arp/arp.c
@@ -229,6 +229,7 @@ static mblk_t *ar_cmd_dequeue(arl_t *arl);
static void *arp_stack_init(netstackid_t stackid, netstack_t *ns);
static void arp_stack_fini(netstackid_t stackid, void *arg);
+static void arp_stack_shutdown(netstackid_t stackid, void *arg);
/*
* All of these are alterable, within the min/max values given,
* at run time. arp_publish_interval and arp_publish_count are
@@ -1042,8 +1043,8 @@ ar_close(queue_t *q)
info.hne_event = NE_UNPLUMB;
info.hne_data = name;
info.hne_datalen = strlen(name);
- (void) hook_run(as->as_arpnicevents, (hook_data_t)&info,
- as->as_netstack);
+ (void) hook_run(as->as_net_data->netd_hooks,
+ as->as_arpnicevents, (hook_data_t)&info);
}
netstack_rele(as->as_netstack);
return (0);
@@ -3730,8 +3731,8 @@ ar_slifname(queue_t *q, mblk_t *mp_orig)
info.hne_event = NE_PLUMB;
info.hne_data = arl->arl_name;
info.hne_datalen = strlen(arl->arl_name);
- (void) hook_run(as->as_arpnicevents, (hook_data_t)&info,
- as->as_netstack);
+ (void) hook_run(as->as_net_data->netd_hooks, as->as_arpnicevents,
+ (hook_data_t)&info);
/* Chain in the new arl. */
rw_enter(&as->as_arl_lock, RW_WRITER);
@@ -4473,7 +4474,8 @@ arp_ddi_init(void)
* destroyed in the kernel, so we can maintain the
* set of arp_stack_t's.
*/
- netstack_register(NS_ARP, arp_stack_init, NULL, arp_stack_fini);
+ netstack_register(NS_ARP, arp_stack_init, arp_stack_shutdown,
+ arp_stack_fini);
}
void
@@ -4506,12 +4508,22 @@ arp_stack_init(netstackid_t stackid, netstack_t *ns)
as->as_arp_counter_wrapped = 0;
rw_init(&as->as_arl_lock, NULL, RW_DRIVER, NULL);
- arp_net_init(as, ns);
+ arp_net_init(as, stackid);
arp_hook_init(as);
return (as);
}
+/* ARGSUSED */
+static void
+arp_stack_shutdown(netstackid_t stackid, void *arg)
+{
+ arp_stack_t *as = (arp_stack_t *)arg;
+
+ arp_hook_destroy(as);
+ arp_net_destroy(as);
+}
+
/*
* Free the ARP stack instance.
*/
@@ -4521,10 +4533,7 @@ arp_stack_fini(netstackid_t stackid, void *arg)
{
arp_stack_t *as = (arp_stack_t *)arg;
- arp_hook_destroy(as);
- arp_net_destroy(as);
rw_destroy(&as->as_arl_lock);
-
nd_free(&as->as_nd);
kmem_free(as->as_param_arr, sizeof (arp_param_arr));
as->as_param_arr = NULL;
diff --git a/usr/src/uts/common/inet/arp/arp_netinfo.c b/usr/src/uts/common/inet/arp/arp_netinfo.c
index e45475f3bf..56ac894408 100644
--- a/usr/src/uts/common/inet/arp/arp_netinfo.c
+++ b/usr/src/uts/common/inet/arp/arp_netinfo.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 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>
@@ -43,20 +41,20 @@
/*
* ARP netinfo entry point declarations.
*/
-static int arp_getifname(phy_if_t, char *, const size_t, netstack_t *);
-static int arp_getmtu(phy_if_t, lif_if_t, netstack_t *);
-static int arp_getpmtuenabled(netstack_t *);
-static int arp_getlifaddr(phy_if_t, lif_if_t, size_t,
- net_ifaddr_t [], void *, netstack_t *);
-static phy_if_t arp_phygetnext(phy_if_t, netstack_t *);
-static phy_if_t arp_phylookup(const char *, netstack_t *);
-static lif_if_t arp_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
-static int arp_inject(inject_t, net_inject_t *, netstack_t *);
-static phy_if_t arp_routeto(struct sockaddr *, netstack_t *);
-static int arp_ispartialchecksum(mblk_t *);
-static int arp_isvalidchecksum(mblk_t *);
-
-static net_info_t arp_netinfo = {
+static int arp_getifname(net_handle_t, phy_if_t, char *, const size_t);
+static int arp_getmtu(net_handle_t, phy_if_t, lif_if_t);
+static int arp_getpmtuenabled(net_handle_t);
+static int arp_getlifaddr(net_handle_t, phy_if_t, lif_if_t, size_t,
+ net_ifaddr_t [], void *);
+static phy_if_t arp_phygetnext(net_handle_t, phy_if_t);
+static phy_if_t arp_phylookup(net_handle_t, const char *);
+static lif_if_t arp_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
+static int arp_inject(net_handle_t, inject_t, net_inject_t *);
+static phy_if_t arp_routeto(net_handle_t, struct sockaddr *, struct sockaddr *);
+static int arp_ispartialchecksum(net_handle_t, mblk_t *);
+static int arp_isvalidchecksum(net_handle_t, mblk_t *);
+
+static net_protocol_t arp_netinfo = {
NETINFO_VERSION,
NHF_ARP,
arp_getifname,
@@ -76,9 +74,14 @@ static net_info_t arp_netinfo = {
* Register ARP netinfo functions.
*/
void
-arp_net_init(arp_stack_t *as, netstack_t *ns)
+arp_net_init(arp_stack_t *as, netstackid_t stackid)
{
- as->as_net_data = net_register_impl(&arp_netinfo, ns);
+ netid_t id;
+
+ id = net_getnetidbynetstackid(stackid);
+ ASSERT(id != -1);
+
+ as->as_net_data = net_protocol_register(id, &arp_netinfo);
ASSERT(as->as_net_data != NULL);
}
@@ -88,7 +91,7 @@ arp_net_init(arp_stack_t *as, netstack_t *ns)
void
arp_net_destroy(arp_stack_t *as)
{
- (void) net_unregister(as->as_net_data);
+ (void) net_protocol_unregister(as->as_net_data);
}
/*
@@ -98,33 +101,33 @@ void
arp_hook_init(arp_stack_t *as)
{
HOOK_FAMILY_INIT(&as->as_arproot, Hn_ARP);
- if (net_register_family(as->as_net_data, &as->as_arproot) != 0) {
+ if (net_family_register(as->as_net_data, &as->as_arproot) != 0) {
cmn_err(CE_NOTE, "arp_hook_init: "
- "net_register_family failed for arp");
+ "net_family_register failed for arp");
}
HOOK_EVENT_INIT(&as->as_arp_physical_in_event, NH_PHYSICAL_IN);
- as->as_arp_physical_in = net_register_event(as->as_net_data,
+ as->as_arp_physical_in = net_event_register(as->as_net_data,
&as->as_arp_physical_in_event);
if (as->as_arp_physical_in == NULL) {
cmn_err(CE_NOTE, "arp_hook_init: "
- "net_register_event failed for arp/physical_in");
+ "net_event_register failed for arp/physical_in");
}
HOOK_EVENT_INIT(&as->as_arp_physical_out_event, NH_PHYSICAL_OUT);
- as->as_arp_physical_out = net_register_event(as->as_net_data,
+ as->as_arp_physical_out = net_event_register(as->as_net_data,
&as->as_arp_physical_out_event);
if (as->as_arp_physical_out == NULL) {
cmn_err(CE_NOTE, "arp_hook_init: "
- "net_register_event failed for arp/physical_out");
+ "net_event_register failed for arp/physical_out");
}
HOOK_EVENT_INIT(&as->as_arp_nic_events, NH_NIC_EVENTS);
- as->as_arpnicevents = net_register_event(as->as_net_data,
+ as->as_arpnicevents = net_event_register(as->as_net_data,
&as->as_arp_nic_events);
if (as->as_arpnicevents == NULL) {
cmn_err(CE_NOTE, "arp_hook_init: "
- "net_register_event failed for arp/nic_events");
+ "net_event_register failed for arp/nic_events");
}
}
@@ -132,35 +135,36 @@ void
arp_hook_destroy(arp_stack_t *as)
{
if (as->as_arpnicevents != NULL) {
- if (net_unregister_event(as->as_net_data,
+ if (net_event_unregister(as->as_net_data,
&as->as_arp_nic_events) == 0)
as->as_arpnicevents = NULL;
}
if (as->as_arp_physical_out != NULL) {
- if (net_unregister_event(as->as_net_data,
+ if (net_event_unregister(as->as_net_data,
&as->as_arp_physical_out_event) == 0)
as->as_arp_physical_out = NULL;
}
if (as->as_arp_physical_in != NULL) {
- if (net_unregister_event(as->as_net_data,
+ if (net_event_unregister(as->as_net_data,
&as->as_arp_physical_in_event) == 0)
as->as_arp_physical_in = NULL;
}
- (void) net_unregister_family(as->as_net_data, &as->as_arproot);
+ (void) net_family_unregister(as->as_net_data, &as->as_arproot);
}
/*
* Determine the name of the lower level interface
*/
static int
-arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
- netstack_t *ns)
+arp_getifname(net_handle_t net, phy_if_t phy_ifdata, char *buffer,
+ const size_t buflen)
{
arl_t *arl;
arp_stack_t *as;
+ netstack_t *ns = net->netd_stack->nts_netstack;
ASSERT(buffer != NULL);
ASSERT(ns != NULL);
@@ -184,7 +188,7 @@ arp_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
*/
/*ARGSUSED*/
static int
-arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
+arp_getmtu(net_handle_t net, phy_if_t phy_ifdata, lif_if_t ifdata)
{
return (-1);
}
@@ -194,7 +198,7 @@ arp_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
*/
/*ARGSUSED*/
static int
-arp_getpmtuenabled(netstack_t *ns)
+arp_getpmtuenabled(net_handle_t net)
{
return (-1);
}
@@ -204,8 +208,8 @@ arp_getpmtuenabled(netstack_t *ns)
*/
/*ARGSUSED*/
static int
-arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
- net_ifaddr_t type[], void *storage, netstack_t *ns)
+arp_getlifaddr(net_handle_t net, phy_if_t phy_ifdata, lif_if_t ifdata,
+ size_t nelem, net_ifaddr_t type[], void *storage)
{
return (-1);
}
@@ -214,11 +218,12 @@ arp_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
* Determine the instance number of the next lower level interface
*/
static phy_if_t
-arp_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
+arp_phygetnext(net_handle_t net, phy_if_t phy_ifdata)
{
arl_t *arl;
int index;
arp_stack_t *as;
+ netstack_t *ns = net->netd_stack->nts_netstack;
ASSERT(ns != NULL);
@@ -247,11 +252,12 @@ arp_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
* Given a network interface name, find its ARP layer instance number.
*/
static phy_if_t
-arp_phylookup(const char *name, netstack_t *ns)
+arp_phylookup(net_handle_t net, const char *name)
{
arl_t *arl;
int index;
arp_stack_t *as;
+ netstack_t *ns = net->netd_stack->nts_netstack;
ASSERT(name != NULL);
ASSERT(ns != NULL);
@@ -276,7 +282,7 @@ arp_phylookup(const char *name, netstack_t *ns)
*/
/*ARGSUSED*/
static lif_if_t
-arp_lifgetnext(phy_if_t ifp, lif_if_t lif, netstack_t *ns)
+arp_lifgetnext(net_handle_t net, phy_if_t ifp, lif_if_t lif)
{
return ((lif_if_t)-1);
}
@@ -286,7 +292,7 @@ arp_lifgetnext(phy_if_t ifp, lif_if_t lif, netstack_t *ns)
*/
/*ARGSUSED*/
static int
-arp_inject(inject_t injection, net_inject_t *neti, netstack_t *ns)
+arp_inject(net_handle_t net, inject_t injection, net_inject_t *neti)
{
return (-1);
}
@@ -296,7 +302,7 @@ arp_inject(inject_t injection, net_inject_t *neti, netstack_t *ns)
*/
/*ARGSUSED*/
static phy_if_t
-arp_routeto(struct sockaddr *addr, netstack_t *ns)
+arp_routeto(net_handle_t net, struct sockaddr *addr, struct sockaddr *next)
{
return ((phy_if_t)-1);
}
@@ -306,7 +312,7 @@ arp_routeto(struct sockaddr *addr, netstack_t *ns)
*/
/*ARGSUSED*/
int
-arp_ispartialchecksum(mblk_t *mb)
+arp_ispartialchecksum(net_handle_t net, mblk_t *mb)
{
return (-1);
}
@@ -316,7 +322,7 @@ arp_ispartialchecksum(mblk_t *mb)
*/
/*ARGSUSED*/
static int
-arp_isvalidchecksum(mblk_t *mb)
+arp_isvalidchecksum(net_handle_t net, mblk_t *mb)
{
return (-1);
}
diff --git a/usr/src/uts/common/inet/arp_impl.h b/usr/src/uts/common/inet/arp_impl.h
index a9be780a42..8f59d7a56f 100644
--- a/usr/src/uts/common/inet/arp_impl.h
+++ b/usr/src/uts/common/inet/arp_impl.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _ARP_IMPL_H
#define _ARP_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -124,13 +122,14 @@ typedef struct ace_s {
if ((_hook).he_interested) { \
hook_pkt_event_t info; \
\
+ info.hpe_protocol = as->as_net_data; \
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, \
- as->as_netstack) != 0) { \
+ if (hook_run(as->as_net_data->netd_hooks, \
+ _event, (hook_data_t)&info) != 0) { \
if (_fm != NULL) { \
freemsg(_fm); \
_fm = NULL; \
@@ -148,13 +147,14 @@ typedef struct ace_s {
if ((_hook).he_interested) { \
hook_pkt_event_t info; \
\
+ info.hpe_protocol = as->as_net_data; \
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, \
- as->as_netstack) != 0) { \
+ if (hook_run(as->as_net_data->netd_hooks, \
+ _event, (hook_data_t)&info) != 0) { \
if (_fm != NULL) { \
freemsg(_fm); \
_fm = NULL; \
@@ -211,7 +211,7 @@ struct arp_stack {
hook_event_token_t as_arp_physical_out;
hook_event_token_t as_arpnicevents;
- net_data_t as_net_data;
+ net_handle_t as_net_data;
};
typedef struct arp_stack arp_stack_t;
@@ -236,7 +236,7 @@ typedef struct ar_s {
extern void arp_hook_init(arp_stack_t *);
extern void arp_hook_destroy(arp_stack_t *);
-extern void arp_net_init(arp_stack_t *, netstack_t *);
+extern void arp_net_init(arp_stack_t *, netstackid_t);
extern void arp_net_destroy(arp_stack_t *);
#endif /* _KERNEL */
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index 21416d0d0b..7dd21ae1b3 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -28,8 +28,6 @@
#ifndef _INET_IP_H
#define _INET_IP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -1894,7 +1892,7 @@ typedef struct ill_s {
/*
* NIC event information attached, to be used by nic event hooks.
*/
- hook_nic_event_t *ill_nic_event_info;
+ hook_nic_event_int_t *ill_nic_event_info;
/* Used for IP frag reassembly throttling on a per ILL basis. */
uint_t ill_ipf_gen; /* Generation of next fragment queue */
@@ -2989,12 +2987,13 @@ extern struct module_info ip_mod_info;
(_olp))->ill_phyint->phyint_hook_ifindex; \
else \
info.hpe_ofp = 0; \
+ info.hpe_protocol = ipst->ips_ipv4_net_data; \
info.hpe_hdr = _iph; \
info.hpe_mp = &(_fm); \
info.hpe_mb = _m; \
info.hpe_flags = _llm; \
- if (hook_run(_event, (hook_data_t)&info, \
- ipst->ips_netstack) != 0) { \
+ if (hook_run(ipst->ips_ipv4_net_data->netd_hooks, \
+ _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) { \
@@ -3032,12 +3031,13 @@ extern struct module_info ip_mod_info;
(_olp))->ill_phyint->phyint_hook_ifindex; \
else \
info.hpe_ofp = 0; \
+ info.hpe_protocol = ipst->ips_ipv6_net_data; \
info.hpe_hdr = _iph; \
info.hpe_mp = &(_fm); \
info.hpe_mb = _m; \
info.hpe_flags = _llm; \
- if (hook_run(_event, (hook_data_t)&info, \
- ipst->ips_netstack) != 0) { \
+ if (hook_run(ipst->ips_ipv6_net_data->netd_hooks, \
+ _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) { \
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index cc890ddbe2..42adc33a54 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -5710,6 +5710,18 @@ ip_stack_shutdown(netstackid_t stackid, void *arg)
/* Get rid of loopback interfaces and their IREs */
ip_loopback_cleanup(ipst);
+
+ /*
+ * The destroy functions here will end up causing notify callbacks
+ * in the hook framework and these need to be run before the shtudown
+ * of the hook framework is begun - that happens from netstack after
+ * IP shutdown has completed. If we leave doing these actions until
+ * ip_stack_fini then the notify callbacks for the net_*_unregister
+ * are happening against a backdrop of shattered terain.
+ */
+ ipv4_hook_destroy(ipst);
+ ipv6_hook_destroy(ipst);
+ ip_net_destroy(ipst);
}
/*
@@ -5724,10 +5736,6 @@ ip_stack_fini(netstackid_t stackid, void *arg)
#ifdef NS_DEBUG
printf("ip_stack_fini(%p, stack %d)\n", (void *)ipst, stackid);
#endif
- ipv4_hook_destroy(ipst);
- ipv6_hook_destroy(ipst);
- ip_net_destroy(ipst);
-
rw_destroy(&ipst->ips_srcid_lock);
ip_kstat_fini(stackid, ipst->ips_ip_mibkp);
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index 8407012da1..1f94033f84 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -4309,7 +4309,7 @@ ill_delete_interface_type(ill_if_t *interface)
static void
ill_glist_delete(ill_t *ill)
{
- hook_nic_event_t *info;
+ hook_nic_event_int_t *info;
ip_stack_t *ipst;
if (ill == NULL)
@@ -4353,7 +4353,7 @@ ill_glist_delete(ill_t *ill)
* order of them in the kernel.
*/
info = ill->ill_nic_event_info;
- if (info != NULL && info->hne_event == NE_DOWN) {
+ if (info != NULL && info->hnei_event.hne_event == NE_DOWN) {
mutex_enter(&ill->ill_lock);
ill_nic_info_dispatch(ill);
mutex_exit(&ill->ill_lock);
@@ -22748,7 +22748,7 @@ ill_nic_info_plumb(ill_t *ill, boolean_t group)
void
ill_nic_info_dispatch(ill_t *ill)
{
- hook_nic_event_t *info;
+ hook_nic_event_int_t *info;
ASSERT(MUTEX_HELD(&ill->ill_lock));
@@ -22757,9 +22757,11 @@ ill_nic_info_dispatch(ill_t *ill)
ip_ne_queue_func, info, DDI_SLEEP) == DDI_FAILURE) {
ip2dbg(("ill_nic_info_dispatch: "
"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));
+ if (info->hnei_event.hne_data != NULL) {
+ kmem_free(info->hnei_event.hne_data,
+ info->hnei_event.hne_datalen);
+ }
+ kmem_free(info, sizeof (*info));
}
ill->ill_nic_event_info = NULL;
}
@@ -24384,12 +24386,14 @@ ill_hook_event2str(nic_event_t event)
static void
ill_hook_event_destroy(ill_t *ill)
{
- hook_nic_event_t *info;
+ hook_nic_event_int_t *info;
if ((info = ill->ill_nic_event_info) != NULL) {
- if (info->hne_data != NULL)
- kmem_free(info->hne_data, info->hne_datalen);
- kmem_free(info, sizeof (hook_nic_event_t));
+ if (info->hnei_event.hne_data != NULL) {
+ kmem_free(info->hnei_event.hne_data,
+ info->hnei_event.hne_datalen);
+ }
+ kmem_free(info, sizeof (*info));
ill->ill_nic_event_info = NULL;
}
@@ -24401,39 +24405,41 @@ ill_hook_event_create(ill_t *ill, lif_if_t lif, nic_event_t event,
nic_event_data_t data, size_t datalen)
{
ip_stack_t *ipst = ill->ill_ipst;
- hook_nic_event_t *info;
+ hook_nic_event_int_t *info;
const char *str = NULL;
/* destroy nic event info if it exists */
if ((info = ill->ill_nic_event_info) != NULL) {
- str = ill_hook_event2str(info->hne_event);
+ str = ill_hook_event2str(info->hnei_event.hne_event);
ip2dbg(("ill_hook_event_create: unexpected nic event %s "
"attached for %s\n", str, ill->ill_name));
ill_hook_event_destroy(ill);
}
/* create a new nic event info */
- if ((info = kmem_alloc(sizeof (hook_nic_event_t), KM_NOSLEEP)) == NULL)
+ info = kmem_alloc(sizeof (*info), KM_NOSLEEP);
+ if (info == NULL)
goto fail;
ill->ill_nic_event_info = info;
if (event == NE_UNPLUMB)
- info->hne_nic = ill->ill_phyint->phyint_ifindex;
+ info->hnei_event.hne_nic = ill->ill_phyint->phyint_ifindex;
else
- info->hne_nic = ill->ill_phyint->phyint_hook_ifindex;
- info->hne_lif = lif;
- info->hne_event = event;
- info->hne_family = ill->ill_isv6 ?
+ info->hnei_event.hne_nic = ill->ill_phyint->phyint_hook_ifindex;
+ info->hnei_event.hne_lif = lif;
+ info->hnei_event.hne_event = event;
+ info->hnei_event.hne_protocol = ill->ill_isv6 ?
ipst->ips_ipv6_net_data : ipst->ips_ipv4_net_data;
- info->hne_data = NULL;
- info->hne_datalen = 0;
+ info->hnei_event.hne_data = NULL;
+ info->hnei_event.hne_datalen = 0;
+ info->hnei_stackid = ipst->ips_netstack->netstack_stackid;
if (data != NULL && datalen != 0) {
- info->hne_data = kmem_alloc(datalen, KM_NOSLEEP);
- if (info->hne_data != NULL) {
- bcopy(data, info->hne_data, datalen);
- info->hne_datalen = datalen;
+ info->hnei_event.hne_data = kmem_alloc(datalen, KM_NOSLEEP);
+ if (info->hnei_event.hne_data != NULL) {
+ bcopy(data, info->hnei_event.hne_data, datalen);
+ info->hnei_event.hne_datalen = datalen;
} else {
ill_hook_event_destroy(ill);
goto fail;
diff --git a/usr/src/uts/common/inet/ip/ip_netinfo.c b/usr/src/uts/common/inet/ip/ip_netinfo.c
index 9c073e795c..aea6870d12 100644
--- a/usr/src/uts/common/inet/ip/ip_netinfo.c
+++ b/usr/src/uts/common/inet/ip/ip_netinfo.c
@@ -23,8 +23,6 @@
* 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>
@@ -37,6 +35,7 @@
#include <sys/socket.h>
#include <sys/neti.h>
#include <sys/sdt.h>
+#include <sys/cmn_err.h>
#include <netinet/in.h>
#include <inet/common.h>
@@ -54,46 +53,49 @@
/*
* IPv4 netinfo entry point declarations.
*/
-static int ip_getifname(phy_if_t, char *, const size_t,
- netstack_t *);
-static int ip_getmtu(phy_if_t, lif_if_t, netstack_t *);
-static int ip_getpmtuenabled(netstack_t *);
-static int ip_getlifaddr(phy_if_t, lif_if_t, size_t,
- net_ifaddr_t [], void *, netstack_t *);
-static phy_if_t ip_phygetnext(phy_if_t, netstack_t *);
-static phy_if_t ip_phylookup(const char *, netstack_t *);
-static lif_if_t ip_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
-static int ip_inject(inject_t, net_inject_t *, netstack_t *);
-static phy_if_t ip_routeto(struct sockaddr *, netstack_t *);
-static int ip_ispartialchecksum(mblk_t *);
-static int ip_isvalidchecksum(mblk_t *);
-
-static int ipv6_getifname(phy_if_t, char *, const size_t,
- netstack_t *);
-static int ipv6_getmtu(phy_if_t, lif_if_t, netstack_t *);
-static int ipv6_getlifaddr(phy_if_t, lif_if_t, size_t,
- net_ifaddr_t [], void *, netstack_t *);
-static phy_if_t ipv6_phygetnext(phy_if_t, netstack_t *);
-static phy_if_t ipv6_phylookup(const char *, netstack_t *);
-static lif_if_t ipv6_lifgetnext(phy_if_t, lif_if_t, netstack_t *);
-static int ipv6_inject(inject_t, net_inject_t *, netstack_t *);
-static phy_if_t ipv6_routeto(struct sockaddr *, netstack_t *);
-static int ipv6_isvalidchecksum(mblk_t *);
+static int ip_getifname(net_handle_t, phy_if_t, char *,
+ const size_t);
+static int ip_getmtu(net_handle_t, phy_if_t, lif_if_t);
+static int ip_getpmtuenabled(net_handle_t);
+static int ip_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
+ size_t, net_ifaddr_t [], void *);
+static phy_if_t ip_phygetnext(net_handle_t, phy_if_t);
+static phy_if_t ip_phylookup(net_handle_t, const char *);
+static lif_if_t ip_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
+static int ip_inject(net_handle_t, inject_t, net_inject_t *);
+static phy_if_t ip_routeto(net_handle_t, struct sockaddr *,
+ struct sockaddr *);
+static int ip_ispartialchecksum(net_handle_t, mblk_t *);
+static int ip_isvalidchecksum(net_handle_t, mblk_t *);
+
+static int ipv6_getifname(net_handle_t, phy_if_t, char *,
+ const size_t);
+static int ipv6_getmtu(net_handle_t, phy_if_t, lif_if_t);
+static int ipv6_getlifaddr(net_handle_t, phy_if_t, lif_if_t,
+ size_t, net_ifaddr_t [], void *);
+static phy_if_t ipv6_phygetnext(net_handle_t, phy_if_t);
+static phy_if_t ipv6_phylookup(net_handle_t, const char *);
+static lif_if_t ipv6_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
+static int ipv6_inject(net_handle_t, inject_t, net_inject_t *);
+static phy_if_t ipv6_routeto(net_handle_t, struct sockaddr *,
+ struct sockaddr *);
+static int ipv6_isvalidchecksum(net_handle_t, mblk_t *);
/* Netinfo private functions */
static int ip_getifname_impl(phy_if_t, char *,
- const size_t, boolean_t, ip_stack_t *);
+ const size_t, boolean_t, ip_stack_t *);
static int ip_getmtu_impl(phy_if_t, lif_if_t, boolean_t,
- ip_stack_t *);
+ ip_stack_t *);
static phy_if_t ip_phylookup_impl(const char *, boolean_t,
- ip_stack_t *ipst);
+ ip_stack_t *);
static lif_if_t ip_lifgetnext_impl(phy_if_t, lif_if_t, boolean_t,
- ip_stack_t *ipst);
+ ip_stack_t *);
static int ip_inject_impl(inject_t, net_inject_t *, boolean_t,
- ip_stack_t *);
+ ip_stack_t *);
static int ip_getifaddr_type(sa_family_t, ipif_t *, lif_if_t,
void *);
-static phy_if_t ip_routeto_impl(struct sockaddr *, ip_stack_t *);
+static phy_if_t ip_routeto_impl(struct sockaddr *, struct sockaddr *,
+ ip_stack_t *);
static int ip_getlifaddr_impl(sa_family_t, phy_if_t, lif_if_t,
size_t, net_ifaddr_t [], struct sockaddr *,
ip_stack_t *);
@@ -102,7 +104,7 @@ static void ip_ni_queue_out_func(void *);
static void ip_ni_queue_func_impl(injection_t *, boolean_t);
-static net_info_t ipv4info = {
+static net_protocol_t ipv4info = {
NETINFO_VERSION,
NHF_INET,
ip_getifname,
@@ -119,7 +121,7 @@ static net_info_t ipv4info = {
};
-static net_info_t ipv6info = {
+static net_protocol_t ipv6info = {
NETINFO_VERSION,
NHF_INET6,
ipv6_getifname,
@@ -206,11 +208,15 @@ ip_net_g_destroy()
void
ip_net_init(ip_stack_t *ipst, netstack_t *ns)
{
+ netid_t id;
+
+ id = net_getnetidbynetstackid(ns->netstack_stackid);
+ ASSERT(id != -1);
- ipst->ips_ipv4_net_data = net_register_impl(&ipv4info, ns);
+ ipst->ips_ipv4_net_data = net_protocol_register(id, &ipv4info);
ASSERT(ipst->ips_ipv4_net_data != NULL);
- ipst->ips_ipv6_net_data = net_register_impl(&ipv6info, ns);
+ ipst->ips_ipv6_net_data = net_protocol_register(id, &ipv6info);
ASSERT(ipst->ips_ipv6_net_data != NULL);
}
@@ -222,12 +228,12 @@ void
ip_net_destroy(ip_stack_t *ipst)
{
if (ipst->ips_ipv4_net_data != NULL) {
- if (net_unregister(ipst->ips_ipv4_net_data) == 0)
+ if (net_protocol_unregister(ipst->ips_ipv4_net_data) == 0)
ipst->ips_ipv4_net_data = NULL;
}
if (ipst->ips_ipv6_net_data != NULL) {
- if (net_unregister(ipst->ips_ipv6_net_data) == 0)
+ if (net_protocol_unregister(ipst->ips_ipv6_net_data) == 0)
ipst->ips_ipv6_net_data = NULL;
}
}
@@ -239,59 +245,59 @@ void
ipv4_hook_init(ip_stack_t *ipst)
{
HOOK_FAMILY_INIT(&ipst->ips_ipv4root, Hn_IPV4);
- if (net_register_family(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root)
+ if (net_family_register(ipst->ips_ipv4_net_data, &ipst->ips_ipv4root)
!= 0) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_family failed for ipv4");
+ "net_family_register failed for ipv4");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_physical_in_event, NH_PHYSICAL_IN);
- ipst->ips_ipv4firewall_physical_in = net_register_event(
+ ipst->ips_ipv4firewall_physical_in = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_in_event);
if (ipst->ips_ipv4firewall_physical_in == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/physical_in");
+ "net_event_register failed for ipv4/physical_in");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_physical_out_event, NH_PHYSICAL_OUT);
- ipst->ips_ipv4firewall_physical_out = net_register_event(
+ ipst->ips_ipv4firewall_physical_out = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_physical_out_event);
if (ipst->ips_ipv4firewall_physical_out == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/physical_out");
+ "net_event_register failed for ipv4/physical_out");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_forwarding_event, NH_FORWARDING);
- ipst->ips_ipv4firewall_forwarding = net_register_event(
+ ipst->ips_ipv4firewall_forwarding = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_forwarding_event);
if (ipst->ips_ipv4firewall_forwarding == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/forwarding");
+ "net_event_register failed for ipv4/forwarding");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_in_event, NH_LOOPBACK_IN);
- ipst->ips_ipv4firewall_loopback_in = net_register_event(
+ ipst->ips_ipv4firewall_loopback_in = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_in_event);
if (ipst->ips_ipv4firewall_loopback_in == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/loopback_in");
+ "net_event_register failed for ipv4/loopback_in");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_loopback_out_event, NH_LOOPBACK_OUT);
- ipst->ips_ipv4firewall_loopback_out = net_register_event(
+ ipst->ips_ipv4firewall_loopback_out = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_loopback_out_event);
if (ipst->ips_ipv4firewall_loopback_out == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/loopback_out");
+ "net_event_register failed for ipv4/loopback_out");
}
HOOK_EVENT_INIT(&ipst->ips_ip4_nic_events, NH_NIC_EVENTS);
ipst->ips_ip4_nic_events.he_flags = HOOK_RDONLY;
- ipst->ips_ipv4nicevents = net_register_event(
+ ipst->ips_ipv4nicevents = net_event_register(
ipst->ips_ipv4_net_data, &ipst->ips_ip4_nic_events);
if (ipst->ips_ipv4nicevents == NULL) {
cmn_err(CE_NOTE, "ipv4_hook_init: "
- "net_register_event failed for ipv4/nic_events");
+ "net_event_register failed for ipv4/nic_events");
}
}
@@ -299,42 +305,42 @@ void
ipv4_hook_destroy(ip_stack_t *ipst)
{
if (ipst->ips_ipv4firewall_forwarding != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_forwarding_event) == 0)
ipst->ips_ipv4firewall_forwarding = NULL;
}
if (ipst->ips_ipv4firewall_physical_in != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_physical_in_event) == 0)
ipst->ips_ipv4firewall_physical_in = NULL;
}
if (ipst->ips_ipv4firewall_physical_out != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_physical_out_event) == 0)
ipst->ips_ipv4firewall_physical_out = NULL;
}
if (ipst->ips_ipv4firewall_loopback_in != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_loopback_in_event) == 0)
ipst->ips_ipv4firewall_loopback_in = NULL;
}
if (ipst->ips_ipv4firewall_loopback_out != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_loopback_out_event) == 0)
ipst->ips_ipv4firewall_loopback_out = NULL;
}
if (ipst->ips_ipv4nicevents != NULL) {
- if (net_unregister_event(ipst->ips_ipv4_net_data,
+ if (net_event_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ip4_nic_events) == 0)
ipst->ips_ipv4nicevents = NULL;
}
- (void) net_unregister_family(ipst->ips_ipv4_net_data,
+ (void) net_family_unregister(ipst->ips_ipv4_net_data,
&ipst->ips_ipv4root);
}
@@ -346,59 +352,59 @@ ipv6_hook_init(ip_stack_t *ipst)
{
HOOK_FAMILY_INIT(&ipst->ips_ipv6root, Hn_IPV6);
- if (net_register_family(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root)
+ if (net_family_register(ipst->ips_ipv6_net_data, &ipst->ips_ipv6root)
!= 0) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_family failed for ipv6");
+ "net_family_register failed for ipv6");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_physical_in_event, NH_PHYSICAL_IN);
- ipst->ips_ipv6firewall_physical_in = net_register_event(
+ ipst->ips_ipv6firewall_physical_in = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_in_event);
if (ipst->ips_ipv6firewall_physical_in == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/physical_in");
+ "net_event_register failed for ipv6/physical_in");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_physical_out_event, NH_PHYSICAL_OUT);
- ipst->ips_ipv6firewall_physical_out = net_register_event(
+ ipst->ips_ipv6firewall_physical_out = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_physical_out_event);
if (ipst->ips_ipv6firewall_physical_out == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/physical_out");
+ "net_event_register failed for ipv6/physical_out");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_forwarding_event, NH_FORWARDING);
- ipst->ips_ipv6firewall_forwarding = net_register_event(
+ ipst->ips_ipv6firewall_forwarding = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_forwarding_event);
if (ipst->ips_ipv6firewall_forwarding == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/forwarding");
+ "net_event_register failed for ipv6/forwarding");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_in_event, NH_LOOPBACK_IN);
- ipst->ips_ipv6firewall_loopback_in = net_register_event(
+ ipst->ips_ipv6firewall_loopback_in = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_in_event);
if (ipst->ips_ipv6firewall_loopback_in == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/loopback_in");
+ "net_event_register failed for ipv6/loopback_in");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_loopback_out_event, NH_LOOPBACK_OUT);
- ipst->ips_ipv6firewall_loopback_out = net_register_event(
+ ipst->ips_ipv6firewall_loopback_out = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_loopback_out_event);
if (ipst->ips_ipv6firewall_loopback_out == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/loopback_out");
+ "net_event_register failed for ipv6/loopback_out");
}
HOOK_EVENT_INIT(&ipst->ips_ip6_nic_events, NH_NIC_EVENTS);
ipst->ips_ip6_nic_events.he_flags = HOOK_RDONLY;
- ipst->ips_ipv6nicevents = net_register_event(
+ ipst->ips_ipv6nicevents = net_event_register(
ipst->ips_ipv6_net_data, &ipst->ips_ip6_nic_events);
if (ipst->ips_ipv6nicevents == NULL) {
cmn_err(CE_NOTE, "ipv6_hook_init: "
- "net_register_event failed for ipv6/nic_events");
+ "net_event_register failed for ipv6/nic_events");
}
}
@@ -406,42 +412,42 @@ void
ipv6_hook_destroy(ip_stack_t *ipst)
{
if (ipst->ips_ipv6firewall_forwarding != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_forwarding_event) == 0)
ipst->ips_ipv6firewall_forwarding = NULL;
}
if (ipst->ips_ipv6firewall_physical_in != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_physical_in_event) == 0)
ipst->ips_ipv6firewall_physical_in = NULL;
}
if (ipst->ips_ipv6firewall_physical_out != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_physical_out_event) == 0)
ipst->ips_ipv6firewall_physical_out = NULL;
}
if (ipst->ips_ipv6firewall_loopback_in != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_loopback_in_event) == 0)
ipst->ips_ipv6firewall_loopback_in = NULL;
}
if (ipst->ips_ipv6firewall_loopback_out != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_loopback_out_event) == 0)
ipst->ips_ipv6firewall_loopback_out = NULL;
}
if (ipst->ips_ipv6nicevents != NULL) {
- if (net_unregister_event(ipst->ips_ipv6_net_data,
+ if (net_event_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ip6_nic_events) == 0)
ipst->ips_ipv6nicevents = NULL;
}
- (void) net_unregister_family(ipst->ips_ipv6_net_data,
+ (void) net_family_unregister(ipst->ips_ipv6_net_data,
&ipst->ips_ipv6root);
}
@@ -449,22 +455,22 @@ ipv6_hook_destroy(ip_stack_t *ipst)
* Determine the name of an IPv4 interface
*/
static int
-ip_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
- netstack_t *ns)
+ip_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
+ const size_t buflen)
{
return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_FALSE,
- ns->netstack_ip));
+ neti->netd_stack->nts_netstack->netstack_ip));
}
/*
* Determine the name of an IPv6 interface
*/
static int
-ipv6_getifname(phy_if_t phy_ifdata, char *buffer, const size_t buflen,
- netstack_t *ns)
+ipv6_getifname(net_handle_t neti, phy_if_t phy_ifdata, char *buffer,
+ const size_t buflen)
{
return (ip_getifname_impl(phy_ifdata, buffer, buflen, B_TRUE,
- ns->netstack_ip));
+ neti->netd_stack->nts_netstack->netstack_ip));
}
/*
@@ -509,8 +515,11 @@ ip_getifname_impl(phy_if_t phy_ifdata,
* Determine the MTU of an IPv4 network interface
*/
static int
-ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
+ip_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_getmtu_impl(phy_ifdata, ifdata, B_FALSE, ns->netstack_ip));
}
@@ -519,8 +528,11 @@ ip_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
* Determine the MTU of an IPv6 network interface
*/
static int
-ipv6_getmtu(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
+ipv6_getmtu(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_getmtu_impl(phy_ifdata, ifdata, B_TRUE, ns->netstack_ip));
}
@@ -577,10 +589,13 @@ ip_getmtu_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
* Determine if path MTU discovery is enabled for IP
*/
static int
-ip_getpmtuenabled(netstack_t *ns)
+ip_getpmtuenabled(net_handle_t neti)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
- return ((ns->netstack_ip)->ips_ip_path_mtu_discovery);
+ return (ns->netstack_ip->ips_ip_path_mtu_discovery);
}
/*
@@ -590,8 +605,11 @@ ip_getpmtuenabled(netstack_t *ns)
* But IP Filter does not use this function.
*/
static phy_if_t
-ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
+ip_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ill_get_next_ifindex(phy_ifdata, B_FALSE, ns->netstack_ip));
}
@@ -600,8 +618,11 @@ ip_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
* Get next interface from the current list of IPv6 physical network interfaces
*/
static phy_if_t
-ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
+ipv6_phygetnext(net_handle_t neti, phy_if_t phy_ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ill_get_next_ifindex(phy_ifdata, B_TRUE, ns->netstack_ip));
}
@@ -610,8 +631,11 @@ ipv6_phygetnext(phy_if_t phy_ifdata, netstack_t *ns)
* Determine if a network interface name exists for IPv4
*/
static phy_if_t
-ip_phylookup(const char *name, netstack_t *ns)
+ip_phylookup(net_handle_t neti, const char *name)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_phylookup_impl(name, B_FALSE, ns->netstack_ip));
}
@@ -620,8 +644,11 @@ ip_phylookup(const char *name, netstack_t *ns)
* Determine if a network interface name exists for IPv6
*/
static phy_if_t
-ipv6_phylookup(const char *name, netstack_t *ns)
+ipv6_phylookup(net_handle_t neti, const char *name)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_phylookup_impl(name, B_TRUE, ns->netstack_ip));
}
@@ -658,8 +685,11 @@ ip_phylookup_impl(const char *name, boolean_t isv6, ip_stack_t *ipst)
* 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, netstack_t *ns)
+ip_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_FALSE,
ns->netstack_ip));
@@ -669,8 +699,11 @@ ip_lifgetnext(phy_if_t phy_ifdata, lif_if_t ifdata, netstack_t *ns)
* 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, netstack_t *ns)
+ipv6_lifgetnext(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_lifgetnext_impl(phy_ifdata, ifdata, B_TRUE,
ns->netstack_ip));
@@ -744,8 +777,11 @@ ip_lifgetnext_impl(phy_if_t phy_ifdata, lif_if_t ifdata, boolean_t isv6,
* Inject an IPv4 packet to or from an interface
*/
static int
-ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns)
+ip_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_inject_impl(style, packet, B_FALSE, ns->netstack_ip));
}
@@ -755,9 +791,11 @@ ip_inject(inject_t style, net_inject_t *packet, netstack_t *ns)
* Inject an IPv6 packet to or from an interface
*/
static int
-ipv6_inject(inject_t style, net_inject_t *packet, netstack_t *ns)
+ipv6_inject(net_handle_t neti, inject_t style, net_inject_t *packet)
{
- ASSERT(ns != NULL);
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
return (ip_inject_impl(style, packet, B_TRUE, ns->netstack_ip));
}
@@ -944,51 +982,68 @@ ip_inject_impl(inject_t style, net_inject_t *packet, boolean_t isv6,
* Find the interface used for traffic to a given IPv4 address
*/
static phy_if_t
-ip_routeto(struct sockaddr *address, netstack_t *ns)
+ip_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
{
+ netstack_t *ns;
+
ASSERT(address != NULL);
- ASSERT(ns != NULL);
if (address->sa_family != AF_INET)
return (0);
- return (ip_routeto_impl(address, ns->netstack_ip));
+
+ ns = neti->netd_stack->nts_netstack;
+ ASSERT(ns != NULL);
+
+ return (ip_routeto_impl(address, next, ns->netstack_ip));
}
/*
* Find the interface used for traffic to a given IPv6 address
*/
static phy_if_t
-ipv6_routeto(struct sockaddr *address, netstack_t *ns)
+ipv6_routeto(net_handle_t neti, struct sockaddr *address, struct sockaddr *next)
{
+ netstack_t *ns;
+
ASSERT(address != NULL);
- ASSERT(ns != NULL);
if (address->sa_family != AF_INET6)
return (0);
- return (ip_routeto_impl(address, ns->netstack_ip));
+
+ ns = neti->netd_stack->nts_netstack;
+ ASSERT(ns != NULL);
+
+ return (ip_routeto_impl(address, next, ns->netstack_ip));
}
/*
- * Find the interface used for traffic to an address
+ * Find the interface used for traffic to an address.
+ * For lint reasons, next/next6/sin/sin6 are all declared and assigned
+ * a value at the top. The alternative would end up with two bunches
+ * of assignments, with each bunch setting half to NULL.
*/
static phy_if_t
-ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst)
+ip_routeto_impl(struct sockaddr *address, struct sockaddr *nexthop,
+ ip_stack_t *ipst)
{
+ struct sockaddr_in6 *next6 = (struct sockaddr_in6 *)nexthop;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address;
+ struct sockaddr_in *next = (struct sockaddr_in *)nexthop;
+ struct sockaddr_in *sin = (struct sockaddr_in *)address;
+ ire_t *sire = NULL;
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,
+ 0, 0, NULL, &sire, ALL_ZONES, NULL,
MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
ipst);
} 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,
+ 0, 0, NULL, &sire, ALL_ZONES, NULL,
MATCH_IRE_DSTONLY|MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE,
ipst);
}
@@ -996,14 +1051,40 @@ ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst)
if (ire == NULL)
return (0);
+ /*
+ * For some destinations, we have routes that are dead ends, so
+ * return to indicate that no physical interface can be used to
+ * reach the destination.
+ */
+ if ((ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE)) != 0) {
+ if (sire != NULL)
+ ire_refrele(sire);
+ ire_refrele(ire);
+ return (0);
+ }
+
ill = ire_to_ill(ire);
if (ill == NULL) {
+ if (sire != NULL)
+ ire_refrele(sire);
ire_refrele(ire);
return (0);
}
+ if (nexthop != NULL) {
+ if (address->sa_family == AF_INET6) {
+ next->sin_addr.s_addr = sire ? sire->ire_gateway_addr :
+ sin->sin_addr.s_addr;
+ } else {
+ next6->sin6_addr = sire ? sire->ire_gateway_addr_v6 :
+ sin6->sin6_addr;
+ }
+ }
+
ASSERT(ill != NULL);
phy_if = (phy_if_t)ill->ill_phyint->phyint_hook_ifindex;
+ if (sire != NULL)
+ ire_refrele(sire);
ire_refrele(ire);
return (phy_if);
@@ -1018,8 +1099,9 @@ ip_routeto_impl(struct sockaddr *address, ip_stack_t *ipst)
* NET_HCK_L4_FULL: full layer 4 checksum
* NET_HCK_L4_PART: partial layer 4 checksum
*/
+/*ARGSUSED*/
static int
-ip_ispartialchecksum(mblk_t *mp)
+ip_ispartialchecksum(net_handle_t neti, mblk_t *mp)
{
int ret = 0;
@@ -1048,8 +1130,9 @@ ip_ispartialchecksum(mblk_t *mp)
* 0: the checksum was incorrect
* 1: the original checksum was correct
*/
+/*ARGSUSED*/
static int
-ip_isvalidchecksum(mblk_t *mp)
+ip_isvalidchecksum(net_handle_t neti, mblk_t *mp)
{
unsigned char *wptr;
ipha_t *ipha = (ipha_t *)mp->b_rptr;
@@ -1097,7 +1180,7 @@ ip_isvalidchecksum(mblk_t *mp)
*/
/*ARGSUSED*/
static int
-ipv6_isvalidchecksum(mblk_t *mp)
+ipv6_isvalidchecksum(net_handle_t neti, mblk_t *mp)
{
return (-1);
}
@@ -1106,9 +1189,12 @@ ipv6_isvalidchecksum(mblk_t *mp)
* 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, netstack_t *ns)
+ip_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
+ size_t nelem, net_ifaddr_t type[], void *storage)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_getlifaddr_impl(AF_INET, phy_ifdata, ifdata,
nelem, type, storage, ns->netstack_ip));
@@ -1118,9 +1204,12 @@ ip_getlifaddr(phy_if_t phy_ifdata, lif_if_t ifdata, size_t nelem,
* 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, netstack_t *ns)
+ipv6_getlifaddr(net_handle_t neti, phy_if_t phy_ifdata, lif_if_t ifdata,
+ size_t nelem, net_ifaddr_t type[], void *storage)
{
+ netstack_t *ns;
+
+ ns = neti->netd_stack->nts_netstack;
ASSERT(ns != NULL);
return (ip_getlifaddr_impl(AF_INET6, phy_ifdata, ifdata,
nelem, type, storage, ns->netstack_ip));
@@ -1338,18 +1427,29 @@ ip_ni_queue_func_impl(injection_t *inject, boolean_t out)
void
ip_ne_queue_func(void *arg)
{
- hook_event_int_t *hr;
- hook_nic_event_t *info = (hook_nic_event_t *)arg;
- netstack_t *ns = info->hne_family->netd_netstack;
- ip_stack_t *ipst = ns->netstack_ip;
+ hook_event_token_t hr;
+ hook_nic_event_int_t *info = (hook_nic_event_int_t *)arg;
+ ip_stack_t *ipst;
+ netstack_t *ns;
- hr = (info->hne_family == ipst->ips_ipv6_net_data) ?
- ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
- (void) hook_run(hr, (hook_data_t)info, ns);
+ ns = netstack_find_by_stackid(info->hnei_stackid);
+ if (ns == NULL)
+ goto done;
+
+ ipst = ns->netstack_ip;
+ if (ipst == NULL)
+ goto done;
- if (info->hne_data != NULL)
- kmem_free(info->hne_data, info->hne_datalen);
- kmem_free(arg, sizeof (hook_nic_event_t));
+ hr = (info->hnei_event.hne_protocol == ipst->ips_ipv6_net_data) ?
+ ipst->ips_ipv6nicevents : ipst->ips_ipv4nicevents;
+ (void) hook_run(info->hnei_event.hne_protocol->netd_hooks, hr,
+ (hook_data_t)&info->hnei_event);
+
+done:
+ if (ns != NULL)
+ netstack_rele(ns);
+ kmem_free(info->hnei_event.hne_data, info->hnei_event.hne_datalen);
+ kmem_free(arg, sizeof (hook_nic_event_int_t));
}
/*
diff --git a/usr/src/uts/common/inet/ip_stack.h b/usr/src/uts/common/inet/ip_stack.h
index 371027e061..48eeea10dd 100644
--- a/usr/src/uts/common/inet/ip_stack.h
+++ b/usr/src/uts/common/inet/ip_stack.h
@@ -27,8 +27,6 @@
#ifndef _INET_IP_STACK_H
#define _INET_IP_STACK_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -412,8 +410,8 @@ struct ip_stack {
hook_event_token_t ips_ipv6firewall_loopback_out;
hook_event_token_t ips_ipv6nicevents;
- net_data_t ips_ipv4_net_data;
- net_data_t ips_ipv6_net_data;
+ net_handle_t ips_ipv4_net_data;
+ net_handle_t ips_ipv6_net_data;
};
typedef struct ip_stack ip_stack_t;
diff --git a/usr/src/uts/common/inet/ipf/fil.c b/usr/src/uts/common/inet/ipf/fil.c
index a97089a7be..253c60df58 100644
--- a/usr/src/uts/common/inet/ipf/fil.c
+++ b/usr/src/uts/common/inet/ipf/fil.c
@@ -5651,7 +5651,7 @@ fr_info_t *fin;
ipf_stack_t *ifs = fin->fin_ifs;
#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
- net_data_t net_data_p;
+ net_handle_t net_data_p;
if (fin->fin_v == 4)
net_data_p = ifs->ifs_ipf_ipv4;
else
diff --git a/usr/src/uts/common/inet/ipf/ip_auth.c b/usr/src/uts/common/inet/ipf/ip_auth.c
index 9c03e9e0c9..2bdd66fee3 100644
--- a/usr/src/uts/common/inet/ipf/ip_auth.c
+++ b/usr/src/uts/common/inet/ipf/ip_auth.c
@@ -368,7 +368,7 @@ ipf_stack_t *ifs;
frauth_t auth, *au = &auth, *fra;
int i, error = 0, len;
char *t;
- net_data_t net_data_p;
+ net_handle_t net_data_p;
net_inject_t inj_data;
int ret;
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 ac71544d9a..24c3755eb0 100644
--- a/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
+++ b/usr/src/uts/common/inet/ipf/ip_fil_solaris.c
@@ -65,30 +65,24 @@ static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21
static int frzerostats __P((caddr_t, ipf_stack_t *));
static int fr_setipfloopback __P((int, ipf_stack_t *));
-static int fr_enableipf __P((ipf_stack_t *, netstack_t *, int));
+static int fr_enableipf __P((ipf_stack_t *, 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,
- netstack_t *));
-static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook4_out __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook4_in __P((hook_event_token_t, hook_data_t,
- netstack_t *));
+static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, void *));
+static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, void *));
+static int ipf_hook __P((hook_data_t, int, int, void *));
+static int ipf_hook4_in __P((hook_event_token_t, hook_data_t, void *));
+static int ipf_hook4_out __P((hook_event_token_t, hook_data_t, void *));
static int ipf_hook4_loop_out __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook4 __P((hook_data_t, int, int, netstack_t *));
-static int ipf_hook6_out __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook6_in __P((hook_event_token_t, hook_data_t,
- netstack_t *));
+ void *));
+static int ipf_hook4_loop_in __P((hook_event_token_t, hook_data_t, void *));
+static int ipf_hook4 __P((hook_data_t, int, int, void *));
+static int ipf_hook6_out __P((hook_event_token_t, hook_data_t, void *));
+static int ipf_hook6_in __P((hook_event_token_t, hook_data_t, void *));
static int ipf_hook6_loop_out __P((hook_event_token_t, hook_data_t,
- netstack_t *));
+ void *));
static int ipf_hook6_loop_in __P((hook_event_token_t, hook_data_t,
- netstack_t *));
-static int ipf_hook6 __P((hook_data_t, int, int, netstack_t *));
+ void *));
+static int ipf_hook6 __P((hook_data_t, int, int, void *));
extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *));
@@ -140,43 +134,47 @@ ipf_stack_t *ifs;
#endif
/*
- * This lock needs to be dropped around the net_unregister_hook calls
+ * This lock needs to be dropped around the net_hook_unregister 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(&ifs->ifs_ipf_global);
+#define UNDO_HOOK(_f, _b, _e, _h) \
+ do { \
+ if (ifs->_f != NULL) { \
+ if (ifs->_b) { \
+ ifs->_b = (net_hook_unregister(ifs->_f, \
+ _e, ifs->_h) != 0); \
+ if (!ifs->_b) { \
+ hook_free(ifs->_h); \
+ ifs->_h = NULL; \
+ } \
+ } else if (ifs->_h != NULL) { \
+ hook_free(ifs->_h); \
+ ifs->_h = NULL; \
+ } \
+ } \
+ _NOTE(CONSTCOND) \
+ } while (0)
+
/*
* Remove IPv6 Hooks
*/
if (ifs->ifs_ipf_ipv6 != NULL) {
- if (ifs->ifs_hook6_physical_in) {
- ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) != 0);
- }
- if (ifs->ifs_hook6_physical_out) {
- ifs->ifs_hook6_physical_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) != 0);
- }
- if (ifs->ifs_hook6_nic_events) {
- ifs->ifs_hook6_nic_events =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0);
- }
- if (ifs->ifs_hook6_loopback_in) {
- ifs->ifs_hook6_loopback_in =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0);
- }
- if (ifs->ifs_hook6_loopback_out) {
- ifs->ifs_hook6_loopback_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0);
- }
-
- if (net_release(ifs->ifs_ipf_ipv6) != 0)
+ UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_in,
+ NH_PHYSICAL_IN, ifs_ipfhook6_in);
+ UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_physical_out,
+ NH_PHYSICAL_OUT, ifs_ipfhook6_out);
+ UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_nic_events,
+ NH_NIC_EVENTS, ifs_ipfhook6_nicevents);
+ UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_in,
+ NH_LOOPBACK_IN, ifs_ipfhook6_loop_in);
+ UNDO_HOOK(ifs_ipf_ipv6, ifs_hook6_loopback_out,
+ NH_LOOPBACK_OUT, ifs_ipfhook6_loop_out);
+
+ if (net_protocol_release(ifs->ifs_ipf_ipv6) != 0)
goto detach_failed;
ifs->ifs_ipf_ipv6 = NULL;
}
@@ -185,37 +183,24 @@ ipf_stack_t *ifs;
* Remove IPv4 Hooks
*/
if (ifs->ifs_ipf_ipv4 != NULL) {
- if (ifs->ifs_hook4_physical_in) {
- ifs->ifs_hook4_physical_in =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) != 0);
- }
- if (ifs->ifs_hook4_physical_out) {
- ifs->ifs_hook4_physical_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) != 0);
- }
- if (ifs->ifs_hook4_nic_events) {
- ifs->ifs_hook4_nic_events =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0);
- }
- if (ifs->ifs_hook4_loopback_in) {
- ifs->ifs_hook4_loopback_in =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0);
- }
- if (ifs->ifs_hook4_loopback_out) {
- ifs->ifs_hook4_loopback_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0);
- }
-
- if (net_release(ifs->ifs_ipf_ipv4) != 0)
+ UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_in,
+ NH_PHYSICAL_IN, ifs_ipfhook4_in);
+ UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_physical_out,
+ NH_PHYSICAL_OUT, ifs_ipfhook4_out);
+ UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_nic_events,
+ NH_NIC_EVENTS, ifs_ipfhook4_nicevents);
+ UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_in,
+ NH_LOOPBACK_IN, ifs_ipfhook4_loop_in);
+ UNDO_HOOK(ifs_ipf_ipv4, ifs_hook4_loopback_out,
+ NH_LOOPBACK_OUT, ifs_ipfhook4_loop_out);
+
+ if (net_protocol_release(ifs->ifs_ipf_ipv4) != 0)
goto detach_failed;
ifs->ifs_ipf_ipv4 = NULL;
}
+#undef UNDO_HOOK
+
#ifdef IPFDEBUG
cmn_err(CE_CONT, "ipldetach()\n");
#endif
@@ -234,10 +219,11 @@ ipf_stack_t *ifs;
ifs->ifs_ipf_locks_done = 0;
}
- if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events ||
- ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
- ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in ||
- ifs->ifs_hook6_loopback_out)
+ if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out ||
+ ifs->ifs_hook4_nic_events || ifs->ifs_hook4_loopback_in ||
+ ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events ||
+ ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out ||
+ ifs->ifs_hook6_loopback_in || ifs->ifs_hook6_loopback_out)
return -1;
return 0;
@@ -247,13 +233,13 @@ detach_failed:
return -1;
}
-int iplattach(ifs, ns)
+int iplattach(ifs)
ipf_stack_t *ifs;
-netstack_t *ns;
{
#if SOLARIS2 < 10
int i;
#endif
+ netid_t id = ifs->ifs_netid;
#ifdef IPFDEBUG
cmn_err(CE_CONT, "iplattach()\n");
@@ -283,17 +269,19 @@ netstack_t *ns;
if (fr_initialise(ifs) < 0)
return -1;
- HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4,
- "ipfilter_hook_nicevents");
- HOOK_INIT(&ifs->ifs_ipfhook4_in, ipf_hook4_in, "ipfilter_hook_in");
- HOOK_INIT(&ifs->ifs_ipfhook4_out, ipf_hook4_out, "ipfilter_hook_out");
- HOOK_INIT(&ifs->ifs_ipfhook4_loop_in, ipf_hook4_in,
- "ipfilter_hook_loop_in");
- HOOK_INIT(&ifs->ifs_ipfhook4_loop_out, ipf_hook4_out,
- "ipfilter_hook_loop_out");
+ HOOK_INIT(ifs->ifs_ipfhook4_nicevents, ipf_nic_event_v4,
+ "ipfilter_hook4_nicevents", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook4_in, ipf_hook4_in,
+ "ipfilter_hook4_in", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook4_out, ipf_hook4_out,
+ "ipfilter_hook4_out", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook4_loop_in, ipf_hook4_in,
+ "ipfilter_hook4_loop_in", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook4_loop_out, ipf_hook4_out,
+ "ipfilter_hook4_loop_out", ifs);
/*
- * If we hold this lock over all of the net_register_hook calls, we
+ * If we hold this lock over all of the net_hook_register 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)
@@ -303,79 +291,81 @@ netstack_t *ns;
/*
* Add IPv4 hooks
*/
- ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns);
+ ifs->ifs_ipf_ipv4 = net_protocol_lookup(id, NHF_INET);
if (ifs->ifs_ipf_ipv4 == NULL)
goto hookup_failed;
- ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0);
+ ifs->ifs_hook4_nic_events = (net_hook_register(ifs->ifs_ipf_ipv4,
+ NH_NIC_EVENTS, ifs->ifs_ipfhook4_nicevents) == 0);
if (!ifs->ifs_hook4_nic_events)
goto hookup_failed;
- ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_PHYSICAL_IN, &ifs->ifs_ipfhook4_in) == 0);
+ ifs->ifs_hook4_physical_in = (net_hook_register(ifs->ifs_ipf_ipv4,
+ NH_PHYSICAL_IN, ifs->ifs_ipfhook4_in) == 0);
if (!ifs->ifs_hook4_physical_in)
goto hookup_failed;
- ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_PHYSICAL_OUT, &ifs->ifs_ipfhook4_out) == 0);
+ ifs->ifs_hook4_physical_out = (net_hook_register(ifs->ifs_ipf_ipv4,
+ NH_PHYSICAL_OUT, ifs->ifs_ipfhook4_out) == 0);
if (!ifs->ifs_hook4_physical_out)
goto hookup_failed;
if (ifs->ifs_ipf_loopback) {
- ifs->ifs_hook4_loopback_in =
- (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0);
+ ifs->ifs_hook4_loopback_in = (net_hook_register(
+ ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
+ ifs->ifs_ipfhook4_loop_in) == 0);
if (!ifs->ifs_hook4_loopback_in)
goto hookup_failed;
- ifs->ifs_hook4_loopback_out =
- (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0);
+ ifs->ifs_hook4_loopback_out = (net_hook_register(
+ ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
+ ifs->ifs_ipfhook4_loop_out) == 0);
if (!ifs->ifs_hook4_loopback_out)
goto hookup_failed;
}
/*
* Add IPv6 hooks
*/
- ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns);
+ ifs->ifs_ipf_ipv6 = net_protocol_lookup(id, NHF_INET6);
if (ifs->ifs_ipf_ipv6 == NULL)
goto hookup_failed;
- HOOK_INIT(&ifs->ifs_ipfhook6_in, ipf_hook6_in, "ipfilter_hook_in");
- HOOK_INIT(&ifs->ifs_ipfhook6_out, ipf_hook6_out, "ipfilter_hook_out");
- HOOK_INIT(&ifs->ifs_ipfhook6_loop_in, ipf_hook6_in,
- "ipfilter_hook_loop_in");
- HOOK_INIT(&ifs->ifs_ipfhook6_loop_out, ipf_hook6_out,
- "ipfilter_hook_loop_out");
-
- HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6,
- "ipfilter_hook_nicevents");
- ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0);
+ HOOK_INIT(ifs->ifs_ipfhook6_nicevents, ipf_nic_event_v6,
+ "ipfilter_hook6_nicevents", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook6_in, ipf_hook6_in,
+ "ipfilter_hook6_in", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook6_out, ipf_hook6_out,
+ "ipfilter_hook6_out", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook6_loop_in, ipf_hook6_in,
+ "ipfilter_hook6_loop_in", ifs);
+ HOOK_INIT(ifs->ifs_ipfhook6_loop_out, ipf_hook6_out,
+ "ipfilter_hook6_loop_out", ifs);
+
+ ifs->ifs_hook6_nic_events = (net_hook_register(ifs->ifs_ipf_ipv6,
+ NH_NIC_EVENTS, ifs->ifs_ipfhook6_nicevents) == 0);
if (!ifs->ifs_hook6_nic_events)
goto hookup_failed;
- ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_PHYSICAL_IN, &ifs->ifs_ipfhook6_in) == 0);
+ ifs->ifs_hook6_physical_in = (net_hook_register(ifs->ifs_ipf_ipv6,
+ NH_PHYSICAL_IN, ifs->ifs_ipfhook6_in) == 0);
if (!ifs->ifs_hook6_physical_in)
goto hookup_failed;
- ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_PHYSICAL_OUT, &ifs->ifs_ipfhook6_out) == 0);
+ ifs->ifs_hook6_physical_out = (net_hook_register(ifs->ifs_ipf_ipv6,
+ NH_PHYSICAL_OUT, ifs->ifs_ipfhook6_out) == 0);
if (!ifs->ifs_hook6_physical_out)
goto hookup_failed;
if (ifs->ifs_ipf_loopback) {
- ifs->ifs_hook6_loopback_in =
- (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0);
+ ifs->ifs_hook6_loopback_in = (net_hook_register(
+ ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
+ ifs->ifs_ipfhook6_loop_in) == 0);
if (!ifs->ifs_hook6_loopback_in)
goto hookup_failed;
- ifs->ifs_hook6_loopback_out =
- (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0);
+ ifs->ifs_hook6_loopback_out = (net_hook_register(
+ ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
+ ifs->ifs_ipfhook6_loop_out) == 0);
if (!ifs->ifs_hook6_loopback_out)
goto hookup_failed;
}
@@ -453,27 +443,27 @@ ipf_stack_t *ifs;
if (set && !ifs->ifs_ipf_loopback) {
ifs->ifs_ipf_loopback = 1;
- ifs->ifs_hook4_loopback_in =
- (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) == 0);
+ ifs->ifs_hook4_loopback_in = (net_hook_register(
+ ifs->ifs_ipf_ipv4, NH_LOOPBACK_IN,
+ ifs->ifs_ipfhook4_loop_in) == 0);
if (!ifs->ifs_hook4_loopback_in)
return EINVAL;
- ifs->ifs_hook4_loopback_out =
- (net_register_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) == 0);
+ ifs->ifs_hook4_loopback_out = (net_hook_register(
+ ifs->ifs_ipf_ipv4, NH_LOOPBACK_OUT,
+ ifs->ifs_ipfhook4_loop_out) == 0);
if (!ifs->ifs_hook4_loopback_out)
return EINVAL;
- ifs->ifs_hook6_loopback_in =
- (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) == 0);
+ ifs->ifs_hook6_loopback_in = (net_hook_register(
+ ifs->ifs_ipf_ipv6, NH_LOOPBACK_IN,
+ ifs->ifs_ipfhook6_loop_in) == 0);
if (!ifs->ifs_hook6_loopback_in)
return EINVAL;
- ifs->ifs_hook6_loopback_out =
- (net_register_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) == 0);
+ ifs->ifs_hook6_loopback_out = (net_hook_register(
+ ifs->ifs_ipf_ipv6, NH_LOOPBACK_OUT,
+ ifs->ifs_ipfhook6_loop_out) == 0);
if (!ifs->ifs_hook6_loopback_out)
return EINVAL;
@@ -481,26 +471,26 @@ ipf_stack_t *ifs;
ifs->ifs_ipf_loopback = 0;
ifs->ifs_hook4_loopback_in =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook4_loop_in) != 0);
+ (net_hook_unregister(ifs->ifs_ipf_ipv4,
+ NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
if (ifs->ifs_hook4_loopback_in)
return EBUSY;
ifs->ifs_hook4_loopback_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv4,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook4_loop_out) != 0);
+ (net_hook_unregister(ifs->ifs_ipf_ipv4,
+ NH_LOOPBACK_OUT, ifs->ifs_ipfhook4_loop_out) != 0);
if (ifs->ifs_hook4_loopback_out)
return EBUSY;
ifs->ifs_hook6_loopback_in =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_IN, &ifs->ifs_ipfhook6_loop_in) != 0);
+ (net_hook_unregister(ifs->ifs_ipf_ipv6,
+ NH_LOOPBACK_IN, ifs->ifs_ipfhook4_loop_in) != 0);
if (ifs->ifs_hook6_loopback_in)
return EBUSY;
ifs->ifs_hook6_loopback_out =
- (net_unregister_hook(ifs->ifs_ipf_ipv6,
- NH_LOOPBACK_OUT, &ifs->ifs_ipfhook6_loop_out) != 0);
+ (net_hook_unregister(ifs->ifs_ipf_ipv6,
+ NH_LOOPBACK_OUT, ifs->ifs_ipfhook6_loop_out) != 0);
if (ifs->ifs_hook6_loopback_out)
return EBUSY;
}
@@ -528,7 +518,6 @@ int *rp;
friostat_t fio;
minor_t unit;
u_int enable;
- netstack_t *ns;
ipf_stack_t *ifs;
#ifdef IPFDEBUG
@@ -539,30 +528,31 @@ int *rp;
if (IPL_LOGMAX < unit)
return ENXIO;
- ns = netstack_find_by_cred(cp);
- ASSERT(ns != NULL);
- ifs = ns->netstack_ipf;
+ /*
+ * As we're calling ipf_find_stack in user space, from a given zone
+ * to find the stack pointer for this zone, there is no need to have
+ * a hold/refence count here.
+ */
+ ifs = ipf_find_stack(crgetzoneid(cp));
ASSERT(ifs != NULL);
if (ifs->ifs_fr_running <= 0) {
if (unit != IPL_LOGIPF) {
- netstack_rele(ifs->ifs_netstack);
return EIO;
}
if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
cmd != SIOCIPFSET && cmd != SIOCFRENB &&
cmd != SIOCGETFS && cmd != SIOCGETFF) {
- netstack_rele(ifs->ifs_netstack);
return EIO;
}
}
READ_ENTER(&ifs->ifs_ipf_global);
- error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs);
+ error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid,
+ curproc, ifs);
if (error != -1) {
RWLOCK_EXIT(&ifs->ifs_ipf_global);
- netstack_rele(ifs->ifs_netstack);
return error;
}
error = 0;
@@ -582,7 +572,7 @@ int *rp;
RWLOCK_EXIT(&ifs->ifs_ipf_global);
WRITE_ENTER(&ifs->ifs_ipf_global);
- error = fr_enableipf(ifs, ns, enable);
+ error = fr_enableipf(ifs, enable);
}
break;
case SIOCIPFSET :
@@ -599,8 +589,9 @@ int *rp;
if (!(mode & FWRITE))
error = EPERM;
else {
- error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags,
- sizeof(ifs->ifs_fr_flags));
+ error = COPYIN((caddr_t)data,
+ (caddr_t)&ifs->ifs_fr_flags,
+ sizeof(ifs->ifs_fr_flags));
if (error != 0)
error = EFAULT;
}
@@ -615,7 +606,7 @@ int *rp;
break;
case SIOCGETFF :
error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data,
- sizeof(ifs->ifs_fr_flags));
+ sizeof(ifs->ifs_fr_flags));
if (error != 0)
error = EFAULT;
break;
@@ -675,7 +666,7 @@ int *rp;
if (!error) {
tmp = frflush(unit, 4, tmp, ifs);
error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
- sizeof(tmp));
+ sizeof(tmp));
if (error != 0)
error = EFAULT;
} else
@@ -692,7 +683,7 @@ int *rp;
if (!error) {
tmp = frflush(unit, 6, tmp, ifs);
error = COPYOUT((caddr_t)&tmp, (caddr_t)data,
- sizeof(tmp));
+ sizeof(tmp));
if (error != 0)
error = EFAULT;
} else
@@ -751,11 +742,13 @@ int *rp;
#endif
break;
case SIOCIPFITER :
- error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs);
+ error = ipf_frruleiter((caddr_t)data, cp->cr_uid,
+ curproc, ifs);
break;
case SIOCGENITER :
- error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs);
+ error = ipf_genericiter((caddr_t)data, cp->cr_uid,
+ curproc, ifs);
break;
case SIOCIPFDELTOK :
@@ -768,19 +761,18 @@ int *rp;
break;
default :
- cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data);
+ cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p",
+ cmd, (void *)data);
error = EINVAL;
break;
}
RWLOCK_EXIT(&ifs->ifs_ipf_global);
- netstack_rele(ifs->ifs_netstack);
return error;
}
-static int fr_enableipf(ifs, ns, enable)
+static int fr_enableipf(ifs, enable)
ipf_stack_t *ifs;
-netstack_t *ns;
int enable;
{
int error;
@@ -789,25 +781,26 @@ int enable;
error = ipldetach(ifs);
if (error == 0)
ifs->ifs_fr_running = -1;
- return (error);
+ return error;
}
if (ifs->ifs_fr_running > 0)
- return (0);
+ return 0;
- error = iplattach(ifs, ns);
+ error = iplattach(ifs);
if (error == 0) {
if (ifs->ifs_fr_timer_id == NULL) {
int hz = drv_usectohz(500000);
ifs->ifs_fr_timer_id = timeout(fr_slowtimer,
- (void *)ifs, hz);
+ (void *)ifs,
+ hz);
}
ifs->ifs_fr_running = 1;
} else {
(void) ipldetach(ifs);
}
- return (error);
+ return error;
}
@@ -816,7 +809,7 @@ char *name;
int v;
ipf_stack_t *ifs;
{
- net_data_t nif;
+ net_handle_t nif;
if (v == 4)
nif = ifs->ifs_ipf_ipv4;
@@ -825,8 +818,6 @@ ipf_stack_t *ifs;
else
return 0;
- nif->netd_netstack = ifs->ifs_netstack;
-
return (net_phylookup(nif, name));
}
@@ -881,13 +872,15 @@ dev_t dev;
register struct uio *uio;
cred_t *cp;
{
- netstack_t *ns;
ipf_stack_t *ifs;
int ret;
- ns = netstack_find_by_cred(cp);
- ASSERT(ns != NULL);
- ifs = ns->netstack_ipf;
+ /*
+ * As we're calling ipf_find_stack in user space, from a given zone
+ * to find the stack pointer for this zone, there is no need to have
+ * a hold/refence count here.
+ */
+ ifs = ipf_find_stack(crgetzoneid(cp));
ASSERT(ifs != NULL);
# ifdef IPFDEBUG
@@ -895,19 +888,16 @@ cred_t *cp;
# endif
if (ifs->ifs_fr_running < 1) {
- netstack_rele(ifs->ifs_netstack);
return EIO;
}
# ifdef IPFILTER_SYNC
if (getminor(dev) == IPL_LOGSYNC) {
- netstack_rele(ifs->ifs_netstack);
return ipfsync_read(uio);
}
# endif
ret = ipflog_read(getminor(dev), uio, ifs);
- netstack_rele(ifs->ifs_netstack);
return ret;
}
#endif /* IPFILTER_LOG */
@@ -924,12 +914,14 @@ dev_t dev;
register struct uio *uio;
cred_t *cp;
{
- netstack_t *ns;
ipf_stack_t *ifs;
- ns = netstack_find_by_cred(cp);
- ASSERT(ns != NULL);
- ifs = ns->netstack_ipf;
+ /*
+ * As we're calling ipf_find_stack in user space, from a given zone
+ * to find the stack pointer for this zone, there is no need to have
+ * a hold/refence count here.
+ */
+ ifs = ipf_find_stack(crgetzoneid(cp));
ASSERT(ifs != NULL);
#ifdef IPFDEBUG
@@ -937,7 +929,6 @@ cred_t *cp;
#endif
if (ifs->ifs_fr_running < 1) {
- netstack_rele(ifs->ifs_netstack);
return EIO;
}
@@ -948,7 +939,6 @@ cred_t *cp;
dev = dev; /* LINT */
uio = uio; /* LINT */
cp = cp; /* LINT */
- netstack_rele(ifs->ifs_netstack);
return ENXIO;
}
@@ -1336,7 +1326,7 @@ ipf_stack_t *ifs;
struct sockaddr_in6 v6addr[2];
struct sockaddr_in v4addr[2];
net_ifaddr_t type[2];
- net_data_t net_data;
+ net_handle_t net_data;
phy_if_t phyif;
void *array;
@@ -1645,7 +1635,7 @@ int len;
int fr_verifysrc(fin)
fr_info_t *fin;
{
- net_data_t net_data_p;
+ net_handle_t net_data_p;
phy_if_t phy_ifdata_routeto;
struct sockaddr sin;
ipf_stack_t *ifs = fin->fin_ifs;
@@ -1661,7 +1651,7 @@ fr_info_t *fin;
/* 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);
+ phy_ifdata_routeto = net_routeto(net_data_p, &sin, NULL);
return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0);
}
@@ -1694,8 +1684,8 @@ mblk_t *mb, **mpp;
fr_info_t *fin;
frdest_t *fdp;
{
- net_data_t net_data_p;
- net_inject_t inj_data;
+ net_handle_t net_data_p;
+ net_inject_t *inj;
mblk_t *mp = NULL;
frentry_t *fr = fin->fin_fr;
qpktinfo_t *qpi;
@@ -1717,6 +1707,10 @@ frdest_t *fdp;
return (-1);
}
+ inj = net_inject_alloc(NETINFO_VERSION);
+ if (inj == NULL)
+ return -1;
+
ip = fin->fin_ip;
qpi = fin->fin_qpi;
@@ -1746,12 +1740,12 @@ frdest_t *fdp;
*mpp = mp;
}
- sinp = (struct sockaddr *)&inj_data.ni_addr;
+ sinp = (struct sockaddr *)&inj->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;
+ bzero((char *)&inj->ni_addr, sizeof (inj->ni_addr));
+ inj->ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6;
+ inj->ni_packet = mb;
/*
* In case we're here due to "to <if>" being used with
@@ -1762,7 +1756,7 @@ frdest_t *fdp;
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;
+ inj->ni_physical = (phy_if_t)fdp->fd_ifp;
if (fin->fin_v == 4) {
sin->sin_addr = fdp->fd_ip;
} else {
@@ -1774,7 +1768,7 @@ frdest_t *fdp;
} else {
sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst;
}
- inj_data.ni_physical = net_routeto(net_data_p, sinp);
+ inj->ni_physical = net_routeto(net_data_p, sinp, NULL);
}
/*
@@ -1795,7 +1789,7 @@ frdest_t *fdp;
u_32_t pass;
saveifp = fin->fin_ifp;
- fin->fin_ifp = (void *)inj_data.ni_physical;
+ fin->fin_ifp = (void *)inj->ni_physical;
fin->fin_flx &= ~FI_STATE;
fin->fin_out = 1;
(void) fr_acctpkt(fin, &pass);
@@ -1821,14 +1815,17 @@ frdest_t *fdp;
#endif
if (net_data_p) {
- if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) {
+ if (net_inject(net_data_p, NI_DIRECT_OUT, inj) < 0) {
+ net_inject_free(inj);
return (-1);
}
}
ifs->ifs_fr_frouteok[0]++;
+ net_inject_free(inj);
return 0;
bad_fastroute:
+ net_inject_free(inj);
freemsg(mb);
ifs->ifs_fr_frouteok[1]++;
return -1;
@@ -1836,7 +1833,7 @@ bad_fastroute:
/* ------------------------------------------------------------------------ */
-/* Function: ipf_hook_out */
+/* Function: ipf_hook4_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 */
@@ -1844,18 +1841,18 @@ bad_fastroute:
/* Calling ipf_hook. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_hook4_out(hook_event_token_t token, hook_data_t info, netstack_t *ns)
+int ipf_hook4_out(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook4(info, 1, 0, ns);
+ return ipf_hook(info, 1, 0, arg);
}
/*ARGSUSED*/
-int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns)
+int ipf_hook6_out(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook6(info, 1, 0, ns);
+ return ipf_hook6(info, 1, 0, arg);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_hook_in */
+/* Function: ipf_hook4_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 */
@@ -1863,19 +1860,19 @@ int ipf_hook6_out(hook_event_token_t token, hook_data_t info, netstack_t *ns)
/* Calling ipf_hook. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_hook4_in(hook_event_token_t token, hook_data_t info, netstack_t *ns)
+int ipf_hook4_in(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook4(info, 0, 0, ns);
+ return ipf_hook(info, 0, 0, arg);
}
/*ARGSUSED*/
-int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns)
+int ipf_hook6_in(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook6(info, 0, 0, ns);
+ return ipf_hook6(info, 0, 0, arg);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_hook_loop_out */
+/* Function: ipf_hook4_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 */
@@ -1883,16 +1880,14 @@ int ipf_hook6_in(hook_event_token_t token, hook_data_t info, netstack_t *ns)
/* Calling ipf_hook. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info,
- netstack_t *ns)
+int ipf_hook4_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook4(info, 1, FI_NOCKSUM, ns);
+ return ipf_hook(info, 1, FI_NOCKSUM, arg);
}
/*ARGSUSED*/
-int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info,
- netstack_t *ns)
+int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook6(info, 1, FI_NOCKSUM, ns);
+ return ipf_hook6(info, 1, FI_NOCKSUM, arg);
}
/* ------------------------------------------------------------------------ */
@@ -1904,16 +1899,14 @@ int ipf_hook6_loop_out(hook_event_token_t token, hook_data_t info,
/* Calling ipf_hook. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_hook4_loop_in(hook_event_token_t token, hook_data_t info,
- netstack_t *ns)
+int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook4(info, 0, FI_NOCKSUM, ns);
+ return ipf_hook(info, 0, FI_NOCKSUM, arg);
}
/*ARGSUSED*/
-int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info,
- netstack_t *ns)
+int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info, void *arg)
{
- return ipf_hook6(info, 0, FI_NOCKSUM, ns);
+ return ipf_hook6(info, 0, FI_NOCKSUM, arg);
}
/* ------------------------------------------------------------------------ */
@@ -1927,15 +1920,17 @@ int ipf_hook6_loop_in(hook_event_token_t token, hook_data_t info,
/* parameters out of the info structure and forms them up to be useful for */
/* calling ipfilter. */
/* ------------------------------------------------------------------------ */
-int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns)
+int ipf_hook(hook_data_t info, int out, int loopback, void *arg)
{
hook_pkt_event_t *fw;
- int rval, hlen;
+ ipf_stack_t *ifs;
qpktinfo_t qpi;
+ int rval, hlen;
u_short swap;
phy_if_t phy;
ip_t *ip;
+ ifs = arg;
fw = (hook_pkt_event_t *)info;
ASSERT(fw != NULL);
@@ -1958,7 +1953,7 @@ int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns)
qpi.qpi_flags |= loopback;
rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
- &qpi, fw->hpe_mp, ns->netstack_ipf);
+ &qpi, fw->hpe_mp, ifs);
/* For fastroute cases, fr_check returns 0 with mp set to NULL */
if (rval == 0 && *(fw->hpe_mp) == NULL)
@@ -1977,7 +1972,7 @@ int ipf_hook4(hook_data_t info, int out, int loopback, netstack_t *ns)
return rval;
}
-int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns)
+int ipf_hook6(hook_data_t info, int out, int loopback, void *arg)
{
hook_pkt_event_t *fw;
int rval, hlen;
@@ -2001,7 +1996,7 @@ int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns)
qpi.qpi_flags |= loopback;
rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out,
- &qpi, fw->hpe_mp, ns->netstack_ipf);
+ &qpi, fw->hpe_mp, arg);
/* For fastroute cases, fr_check returns 0 with mp set to NULL */
if (rval == 0 && *(fw->hpe_mp) == NULL)
@@ -2024,12 +2019,11 @@ int ipf_hook6(hook_data_t info, int out, int loopback, netstack_t *ns)
/* Function to receive asynchronous NIC events from IP */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
- netstack_t *ns)
+int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, void *arg)
{
struct sockaddr_in *sin;
hook_nic_event_t *hn;
- ipf_stack_t *ifs = ns->netstack_ipf;
+ ipf_stack_t *ifs = arg;
hn = (hook_nic_event_t *)info;
@@ -2085,12 +2079,11 @@ int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info,
/* Function to receive asynchronous NIC events from IP */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info,
- netstack_t *ns)
+int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, void *arg)
{
struct sockaddr_in6 *sin6;
hook_nic_event_t *hn;
- ipf_stack_t *ifs = ns->netstack_ipf;
+ ipf_stack_t *ifs = arg;
hn = (hook_nic_event_t *)info;
diff --git a/usr/src/uts/common/inet/ipf/ip_log.c b/usr/src/uts/common/inet/ipf/ip_log.c
index 57251901aa..1fe54f3a07 100644
--- a/usr/src/uts/common/inet/ipf/ip_log.c
+++ b/usr/src/uts/common/inet/ipf/ip_log.c
@@ -5,12 +5,10 @@
*
* $Id: ip_log.c,v 2.75.2.7 2005/06/11 07:47:44 darrenr Exp $
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
@@ -242,7 +240,7 @@ u_int flags;
u_char p;
mb_t *m;
# if SOLARIS && defined(_KERNEL)
- net_data_t nif;
+ net_handle_t nif;
void *ifp;
# else
# if defined(__hpux) && defined(_KERNEL)
diff --git a/usr/src/uts/common/inet/ipf/ip_nat.c b/usr/src/uts/common/inet/ipf/ip_nat.c
index 0296144195..b7165f92b1 100644
--- a/usr/src/uts/common/inet/ipf/ip_nat.c
+++ b/usr/src/uts/common/inet/ipf/ip_nat.c
@@ -4129,7 +4129,7 @@ u_32_t nflags;
}
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p = ifs->ifs_ipf_ipv4;
+ net_handle_t net_data_p = ifs->ifs_ipf_ipv4;
#endif
tcp = NULL;
@@ -4459,7 +4459,7 @@ u_32_t nflags;
}
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p = ifs->ifs_ipf_ipv4;
+ net_handle_t net_data_p = ifs->ifs_ipf_ipv4;
#endif
tcp = NULL;
diff --git a/usr/src/uts/common/inet/ipf/ip_nat6.c b/usr/src/uts/common/inet/ipf/ip_nat6.c
index 71a4dbd556..9fbfd694c4 100644
--- a/usr/src/uts/common/inet/ipf/ip_nat6.c
+++ b/usr/src/uts/common/inet/ipf/ip_nat6.c
@@ -7,8 +7,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"$
-
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
@@ -2220,7 +2218,7 @@ u_32_t nflags;
ipf_stack_t *ifs = fin->fin_ifs;
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p = ifs->ifs_ipf_ipv6;
+ net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
#endif
tcp = NULL;
@@ -2509,7 +2507,7 @@ u_32_t nflags;
ipf_stack_t *ifs = fin->fin_ifs;
#if SOLARIS && defined(_KERNEL)
- net_data_t net_data_p = ifs->ifs_ipf_ipv6;
+ net_handle_t net_data_p = ifs->ifs_ipf_ipv6;
#endif
tcp = NULL;
diff --git a/usr/src/uts/common/inet/ipf/ip_proxy.c b/usr/src/uts/common/inet/ipf/ip_proxy.c
index 9a045ca74f..6f89a77073 100644
--- a/usr/src/uts/common/inet/ipf/ip_proxy.c
+++ b/usr/src/uts/common/inet/ipf/ip_proxy.c
@@ -490,7 +490,7 @@ nat_t *nat;
ipf_stack_t *ifs = fin->fin_ifs;
#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
- net_data_t net_data_p;
+ net_handle_t net_data_p;
if (fin->fin_v == 4)
net_data_p = ifs->ifs_ipf_ipv4;
else
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 2763a68a8e..57f6ab4c25 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
@@ -1316,6 +1316,7 @@ extern void ipfilterattach __P((int));
extern int ipl_enable __P((void));
extern int ipl_disable __P((void));
# ifdef MENTAT
+extern ipf_stack_t *ipf_find_stack(const zoneid_t zone);
extern int fr_check __P((struct ip *, int, void *, int, void *,
mblk_t **, ipf_stack_t *));
# if SOLARIS
@@ -1419,7 +1420,7 @@ extern int count4bits __P((u_32_t));
extern int count6bits __P((u_32_t *));
extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int, ipf_stack_t *));
extern char *getifname __P((struct ifnet *));
-extern int iplattach __P((ipf_stack_t *, netstack_t *));
+extern int iplattach __P((ipf_stack_t *));
extern int ipldetach __P((ipf_stack_t *));
extern u_short ipf_cksum __P((u_short *, int));
extern int copyinptr __P((void *, void *, size_t));
diff --git a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
index 44ef0ace0f..29302bcc2a 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ipf_stack.h
@@ -7,8 +7,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef __IPF_STACK_H__
#define __IPF_STACK_H__
@@ -41,7 +39,10 @@
* IPF stack instances
*/
struct ipf_stack {
- netstack_t *ifs_netstack;
+ struct ipf_stack *ifs_next;
+ struct ipf_stack **ifs_pnext;
+ netid_t ifs_netid;
+ zoneid_t ifs_zone;
/* ipf module */
@@ -108,15 +109,16 @@ struct ipf_stack {
ipftuneable_t *ifs_ipf_tunelist;
/* ip_fil_solaris.c */
- hook_t ifs_ipfhook4_in;
- hook_t ifs_ipfhook4_out;
- hook_t ifs_ipfhook4_loop_in;
- hook_t ifs_ipfhook4_loop_out;
- hook_t ifs_ipfhook6_in;
- hook_t ifs_ipfhook6_out;
- hook_t ifs_ipfhook6_loop_in;
- hook_t ifs_ipfhook6_loop_out;
- hook_t ifs_ipfhook_nicevents;
+ hook_t *ifs_ipfhook4_in;
+ hook_t *ifs_ipfhook4_out;
+ hook_t *ifs_ipfhook4_loop_in;
+ hook_t *ifs_ipfhook4_loop_out;
+ hook_t *ifs_ipfhook4_nicevents;
+ hook_t *ifs_ipfhook6_in;
+ hook_t *ifs_ipfhook6_out;
+ hook_t *ifs_ipfhook6_loop_in;
+ hook_t *ifs_ipfhook6_loop_out;
+ hook_t *ifs_ipfhook6_nicevents;
/* flags to indicate whether hooks are registered. */
boolean_t ifs_hook4_physical_in;
@@ -131,8 +133,8 @@ struct ipf_stack {
boolean_t ifs_hook6_loopback_out;
int ifs_ipf_loopback;
- net_data_t ifs_ipf_ipv4;
- net_data_t ifs_ipf_ipv6;
+ net_handle_t ifs_ipf_ipv4;
+ net_handle_t ifs_ipf_ipv6;
/* ip_auth.c */
int ifs_fr_authsize;
diff --git a/usr/src/uts/common/inet/ipf/solaris.c b/usr/src/uts/common/inet/ipf/solaris.c
index a48a3250cf..aed5a475a4 100644
--- a/usr/src/uts/common/inet/ipf/solaris.c
+++ b/usr/src/uts/common/inet/ipf/solaris.c
@@ -3,14 +3,12 @@
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/
#pragma ident "@(#)$Id: solaris.c,v 2.73.2.6 2005/07/13 21:40:47 darrenr Exp $"
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/systm.h>
#include <sys/types.h>
#include <sys/param.h>
@@ -39,7 +37,6 @@
#if SOLARIS2 >= 6
# include <net/if_types.h>
#endif
-#include <sys/netstack.h>
#include <net/af.h>
#include <net/route.h>
#include <netinet/in.h>
@@ -71,6 +68,8 @@ 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 void *ipf_stack_create __P((const netid_t));
+static void ipf_stack_destroy __P((const netid_t, void *));
static int ipf_property_g_update __P((dev_info_t *));
static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME,
IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME,
@@ -117,6 +116,10 @@ static struct dev_ops ipf_ops = {
(struct bus_ops *)0
};
+
+static net_instance_t *ipfncb = NULL;
+static ipf_stack_t *ipf_stacks = NULL;
+static kmutex_t ipf_stack_lock;
extern struct mod_ops mod_driverops;
static struct modldrv iplmod = {
&mod_driverops, IPL_VERSION, &ipf_ops };
@@ -217,45 +220,51 @@ static const filter_kstats_t ipf_kstat_tmp = {
static int ipf_kstat_update(kstat_t *ksp, int rwflag);
static void
-ipf_kstat_init(ipf_stack_t *ifs, netstackid_t stackid)
+ipf_kstat_init(ipf_stack_t *ifs)
{
- int i;
+ ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid, "ipf", 0,
+ "inbound", "net", KSTAT_TYPE_NAMED,
+ sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
+ if (ifs->ifs_kstatp[0] != NULL) {
+ bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data,
+ sizeof (filter_kstats_t));
+ ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update;
+ ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0];
+ kstat_install(ifs->ifs_kstatp[0]);
+ }
- for (i = 0; i < 2; i++) {
- ifs->ifs_kstatp[i] = kstat_create_netstack("ipf", 0,
- (i==0)?"inbound":"outbound",
- "net",
- KSTAT_TYPE_NAMED,
- sizeof (filter_kstats_t) / sizeof (kstat_named_t),
- 0, stackid);
- if (ifs->ifs_kstatp[i] != NULL) {
- bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[i]->ks_data,
- sizeof (filter_kstats_t));
- ifs->ifs_kstatp[i]->ks_update = ipf_kstat_update;
- ifs->ifs_kstatp[i]->ks_private = &ifs->ifs_frstats[i];
- kstat_install(ifs->ifs_kstatp[i]);
- }
+ ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid, "ipf", 0,
+ "outbound", "net", KSTAT_TYPE_NAMED,
+ sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0);
+ if (ifs->ifs_kstatp[1] != NULL) {
+ bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data,
+ sizeof (filter_kstats_t));
+ ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update;
+ ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1];
+ kstat_install(ifs->ifs_kstatp[1]);
}
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init() installed 0x%x, 0x%x",
- ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
+ cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p",
+ ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]);
#endif
}
+
static void
-ipf_kstat_fini(ipf_stack_t *ifs, netstackid_t stackid)
+ipf_kstat_fini(ipf_stack_t *ifs)
{
int i;
for (i = 0; i < 2; i++) {
if (ifs->ifs_kstatp[i] != NULL) {
- kstat_delete_netstack(ifs->ifs_kstatp[i], stackid);
+ net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]);
ifs->ifs_kstatp[i] = NULL;
}
}
}
+
static int
ipf_kstat_update(kstat_t *ksp, int rwflag)
{
@@ -309,6 +318,7 @@ int _init()
#ifdef IPFDEBUG
cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst);
#endif
+ mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL);
return ipfinst;
}
@@ -332,7 +342,7 @@ struct modinfo *modinfop;
ipfinst = mod_info(&modlink1, modinfop);
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst);
+ cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst);
#endif
return ipfinst;
}
@@ -343,7 +353,7 @@ static int ipf_identify(dip)
dev_info_t *dip;
{
# ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip);
+ cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip);
# endif
if (strcmp(ddi_get_name(dip), "ipf") == 0)
return (DDI_IDENTIFIED);
@@ -355,19 +365,17 @@ dev_info_t *dip;
* Initialize things for IPF for each stack instance
*/
static void *
-ipf_stack_init(netstackid_t stackid, netstack_t *ns)
+ipf_stack_create(const netid_t id)
{
ipf_stack_t *ifs;
-#ifdef NS_DEBUG
- (void) printf("ipf_stack_init(%d)\n", stackid);
+#ifdef IPFDEBUG
+ cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id);
#endif
- KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs));
+ ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP);
bzero(ifs, sizeof (*ifs));
- ifs->ifs_netstack = ns;
-
ifs->ifs_hook4_physical_in = B_FALSE;
ifs->ifs_hook4_physical_out = B_FALSE;
ifs->ifs_hook4_nic_events = B_FALSE;
@@ -384,8 +392,13 @@ ipf_stack_init(netstackid_t stackid, netstack_t *ns)
*/
RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex");
RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock");
-#ifdef KERNEL
- ipf_kstat_init(ifs, stackid);
+
+ ifs->ifs_netid = id;
+ ifs->ifs_zone = net_getzoneidbynetid(id);
+ ipf_kstat_init(ifs);
+
+#ifdef IPFDEBUG
+ cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone);
#endif
/*
@@ -396,12 +409,44 @@ ipf_stack_init(netstackid_t stackid, netstack_t *ns)
RWLOCK_EXIT(&ifs->ifs_ipf_global);
/* Limit to global stack */
- if (stackid == GLOBAL_NETSTACKID)
+ if (ifs->ifs_zone == GLOBAL_ZONEID)
cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version);
+ mutex_enter(&ipf_stack_lock);
+ if (ipf_stacks != NULL)
+ ipf_stacks->ifs_pnext = &ifs->ifs_next;
+ ifs->ifs_next = ipf_stacks;
+ ifs->ifs_pnext = &ipf_stacks;
+ ipf_stacks = ifs;
+ mutex_exit(&ipf_stack_lock);
+
return (ifs);
}
+
+/*
+ * This function should only ever be used to find the pointer to the
+ * ipfilter stack structure for the zone that is currently being
+ * executed... so if you're running in the context of zone 1, you
+ * should not attempt to find the ipf_stack_t for zone 0 or 2 or
+ * anything else but 1. In that way, the returned pointer is safe
+ * as it will only be nuked when the instance is destroyed as part
+ * of the final shutdown of a zone.
+ */
+ipf_stack_t *ipf_find_stack(const zoneid_t zone)
+{
+ ipf_stack_t *ifs;
+
+ mutex_enter(&ipf_stack_lock);
+ for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) {
+ if (ifs->ifs_zone == zone)
+ break;
+ }
+ mutex_exit(&ipf_stack_lock);
+ return ifs;
+}
+
+
static int ipf_detach_check_zone(ipf_stack_t *ifs)
{
/*
@@ -430,38 +475,32 @@ static int ipf_detach_check_zone(ipf_stack_t *ifs)
return (0);
}
+
static int ipf_detach_check_all()
{
- netstack_handle_t nh;
- netstack_t *ns;
- int ret;
-
- netstack_next_init(&nh);
- while ((ns = netstack_next(&nh)) != NULL) {
- ret = ipf_detach_check_zone(ns->netstack_ipf);
- netstack_rele(ns);
- if (ret != 0) {
- netstack_next_fini(&nh);
- return (-1);
- }
- }
+ ipf_stack_t *ifs;
- netstack_next_fini(&nh);
- return (0);
+ mutex_enter(&ipf_stack_lock);
+ for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next)
+ if (ipf_detach_check_zone(ifs) != 0)
+ break;
+ mutex_exit(&ipf_stack_lock);
+ return ((ifs == NULL) ? 0 : -1);
}
+
/*
* Destroy things for ipf for one stack.
*/
/* ARGSUSED */
static void
-ipf_stack_fini(netstackid_t stackid, void *arg)
+ipf_stack_destroy(const netid_t id, void *arg)
{
ipf_stack_t *ifs = (ipf_stack_t *)arg;
+ timeout_id_t tid;
-#ifdef NS_DEBUG
- (void) printf("ipf_stack_destroy(%p, stackid %d)\n",
- (void *)ifs, stackid);
+#ifdef IPFDEBUG
+ (void) printf("ipf_stack_destroy(%p)\n", (void *)ifs);
#endif
/*
@@ -474,19 +513,24 @@ ipf_stack_fini(netstackid_t stackid, void *arg)
return;
}
ifs->ifs_fr_running = -2;
+ tid = ifs->ifs_fr_timer_id;
+ ifs->ifs_fr_timer_id = NULL;
RWLOCK_EXIT(&ifs->ifs_ipf_global);
-#ifdef KERNEL
- ipf_kstat_fini(ifs, stackid);
-#endif
- if (ifs->ifs_fr_timer_id != 0) {
- (void) untimeout(ifs->ifs_fr_timer_id);
- ifs->ifs_fr_timer_id = 0;
- }
+ mutex_enter(&ipf_stack_lock);
+ if (ifs->ifs_next != NULL)
+ ifs->ifs_next->ifs_pnext = ifs->ifs_pnext;
+ *ifs->ifs_pnext = ifs->ifs_next;
+ mutex_exit(&ipf_stack_lock);
+
+ ipf_kstat_fini(ifs);
+
+ if (tid != NULL)
+ (void) untimeout(tid);
WRITE_ENTER(&ifs->ifs_ipf_global);
if (ipldetach(ifs) != 0) {
- printf("ipf_stack_fini: ipldetach failed\n");
+ printf("ipf_stack_destroy: ipldetach failed\n");
}
ipftuneable_free(ifs);
@@ -498,6 +542,7 @@ ipf_stack_fini(netstackid_t stackid, void *arg)
KFREE(ifs);
}
+
static int ipf_attach(dip, cmd)
dev_info_t *dip;
ddi_attach_cmd_t cmd;
@@ -507,7 +552,7 @@ ddi_attach_cmd_t cmd;
int instance;
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd);
+ cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd);
#endif
switch (cmd)
@@ -519,7 +564,7 @@ ddi_attach_cmd_t cmd;
return DDI_FAILURE;
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance);
+ cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance);
#endif
(void) ipf_property_g_update(dip);
@@ -538,8 +583,18 @@ ddi_attach_cmd_t cmd;
}
ipf_dev_info = dip;
- netstack_register(NS_IPF, ipf_stack_init, NULL,
- ipf_stack_fini);
+
+ ipfncb = net_instance_alloc(NETINFO_VERSION);
+ ipfncb->nin_name = "ipf";
+ ipfncb->nin_create = ipf_stack_create;
+ ipfncb->nin_destroy = ipf_stack_destroy;
+ ipfncb->nin_shutdown = NULL;
+ i = net_instance_register(ipfncb);
+
+#ifdef IPFDEBUG
+ cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i);
+#endif
+
return DDI_SUCCESS;
/* NOTREACHED */
default:
@@ -559,7 +614,7 @@ ddi_detach_cmd_t cmd;
int i;
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd);
+ cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd);
#endif
switch (cmd) {
case DDI_DETACH:
@@ -579,7 +634,9 @@ ddi_detach_cmd_t cmd;
return DDI_FAILURE;
}
- netstack_unregister(NS_IPF);
+ (void) net_instance_unregister(ipfncb);
+ net_instance_free(ipfncb);
+
return DDI_SUCCESS;
/* NOTREACHED */
default:
@@ -600,7 +657,7 @@ void *arg, **result;
error = DDI_FAILURE;
#ifdef IPFDEBUG
- cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg);
+ cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg);
#endif
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
diff --git a/usr/src/uts/common/io/hook.c b/usr/src/uts/common/io/hook.c
index 323503498c..8b7129a35b 100644
--- a/usr/src/uts/common/io/hook.c
+++ b/usr/src/uts/common/io/hook.c
@@ -19,11 +19,9 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 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>
@@ -34,6 +32,7 @@
#include <sys/modctl.h>
#include <sys/hook_impl.h>
#include <sys/sdt.h>
+#include <sys/cmn_err.h>
/*
* This file provides kernel hook framework.
@@ -51,6 +50,109 @@ static struct modlinkage modlinkage = {
};
/*
+ * How it works.
+ * =============
+ * Use of the hook framework here is tied up with zones - when a new zone
+ * is created, we create a new hook_stack_t and are open to business for
+ * allowing new hook families and their events.
+ *
+ * A consumer of these hooks is expected to operate in this fashion:
+ * 1) call hook_family_add() to create a new family of hooks. It is a
+ * current requirement that this call must be made with the value
+ * returned from hook_stack_init, by way of infrastructure elsewhere.
+ * 2) add events to the registered family with calls to hook_event_add.
+ *
+ * At this point, the structures in place should be open to others to
+ * add hooks to the event or add notifiers for when the contents of the
+ * hook stack changes.
+ *
+ * The interesting stuff happens on teardown.
+ *
+ * It is a requirement that the provider of hook events work in the reverse
+ * order to the above, so that the first step is:
+ * 1) remove events from each hook family created earlier
+ * 2) remove hook families from the hook stack.
+ *
+ * When doing teardown of both events and families, a check is made to see
+ * if either structure is still "busy". If so then a boolean flag is set to
+ * say that the structure is condemned. The presence of this flag being set
+ * must be checked for in _add()/_register()/ functions and a failure returned
+ * if it is set. It is ignored by the _find() functions because they're
+ * used by _remove()/_unregister(). While setting the condemned flag when
+ * trying to delete a structure would normally be keyed from the presence
+ * of a reference count being greater than 1, in this implementation there
+ * are no reference counts required: instead the presence of objects on
+ * linked lists is taken to mean something is still "busy."
+ *
+ * ONLY the caller that adds the family and the events ever has a direct
+ * reference to the internal structures and thus ONLY it should be doing
+ * the removal of either the event or family. In practise, what this means
+ * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed
+ * by net_event_register() (these interface to hook_family_add() and
+ * hook_event_add(), respectively) that are made when we create an instance
+ * of IP and when the IP instance is shutdown/destroyed, it calls
+ * net_event_unregister() and net_protocol_unregister(), which in turn call
+ * hook_event_remove() and hook_family_remove() respectively. Nobody else
+ * is entitled to call the _unregister() functions. It is imperative that
+ * there be only one _remove() call for every _add() call.
+ *
+ * It is possible that code which is interfacing with this hook framework
+ * won't do all the cleaning up that it needs to at the right time. While
+ * we can't prevent programmers from creating memory leaks, we can synchronise
+ * when we clean up data structures to prevent code accessing free'd memory.
+ *
+ * A simple diagram showing the ownership is as follows:
+ *
+ * Owned +--------------+
+ * by | hook_stack_t |
+ * the +--------------+
+ * Instance |
+ * - - - - - - - -|- - - - - - - - - - - - - - - - - -
+ * V
+ * Owned +-------------------+ +-------------------+
+ * | hook_family_int_t |---->| hook_family_int_t |
+ * by +-------------------+ +-------------------+
+ * | \+---------------+ \+---------------+
+ * network | | hook_family_t | | hook_family_t |
+ * V +---------------+ +---------------+
+ * protocol +------------------+ +------------------+
+ * | hook_event_int_t |---->| hook_event_int_t |
+ * (ipv4,ipv6) +------------------+ +------------------+
+ * | \+--------------+ \+--------------+
+ * | | hook_event_t | | hook_event_t |
+ * | +--------------+ +--------------+
+ * - - - - - - - -|- - - - - - - - - - - - - - - - - -
+ * V
+ * Owned +------------+
+ * | hook_int_t |
+ * by +------------+
+ * \+--------+
+ * the consumer | hook_t |
+ * +--------+
+ *
+ * The consumers, such as IPFilter, do not have any pointers or hold any
+ * references to hook_int_t, hook_event_t or hook_event_int_t. By placing
+ * a hook on an event through net_hook_register(), an implicit reference
+ * to the hook_event_int_t is returned with a successful call. Additionally,
+ * IPFilter does not see the hook_family_int_t or hook_family_t directly.
+ * Rather it is returned a net_handle_t (from net_protocol_lookup()) that
+ * contains a pointer to hook_family_int_t. The structure behind the
+ * net_handle_t (struct net_data) *is* reference counted and managed
+ * appropriately.
+ *
+ * A more detailed picture that describes how the family/event structures
+ * are linked together can be found in <sys/hook_impl.h>
+ */
+
+/*
+ * Locking
+ * =======
+ * The use of CVW_* macros to do locking is driven by the need to allow
+ * recursive locking with read locks when we're processing packets. This
+ * is necessary because various netinfo functions need to hold read locks,
+ * by design, as they can be called in or out of packet context.
+ */
+/*
* Hook internal functions
*/
static hook_int_t *hook_copy(hook_t *src);
@@ -58,16 +160,45 @@ static hook_event_int_t *hook_event_checkdup(hook_event_t *he,
hook_stack_t *hks);
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 void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi);
static hook_family_int_t *hook_family_copy(hook_family_t *src);
static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks);
-static void hook_family_free(hook_family_int_t *hfi);
+static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks);
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_int_free(hook_int_t *hi, netstackid_t);
static void hook_init(void);
static void hook_fini(void);
static void *hook_stack_init(netstackid_t stackid, netstack_t *ns);
static void hook_stack_fini(netstackid_t stackid, void *arg);
+static void hook_stack_shutdown(netstackid_t stackid, void *arg);
+static int hook_insert(hook_int_head_t *head, hook_int_t *new);
+static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new);
+static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new);
+static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name);
+static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *);
+static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *,
+ char *event, char *name, hook_notify_cmd_t cmd);
+static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei,
+ hook_int_t *hi);
+static int hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head,
+ hook_notify_fn_t callback, void *arg);
+static int hook_notify_unregister(cvwaitlock_t *lock,
+ hook_notify_head_t *head, hook_notify_fn_t callback);
+static void hook_notify_run(hook_notify_head_t *head, char *family,
+ char *event, char *name, hook_notify_cmd_t cmd);
+static void hook_stack_notify_run(hook_stack_t *hks, char *name,
+ hook_notify_cmd_t cmd);
+static void hook_stack_remove(hook_stack_t *hks);
+
+/*
+ * A list of the hook stacks is kept here because we need to enable
+ * net_instance_notify_register() to be called during the creation
+ * of a new instance. Previously hook_stack_get() would just use
+ * the netstack functions for this work but they will return NULL
+ * until the zone has been fully initialised.
+ */
+static hook_stack_head_t hook_stacks;
+static kmutex_t hook_stack_lock;
/*
* Module entry points.
@@ -85,7 +216,6 @@ _init(void)
return (error);
}
-
int
_fini(void)
{
@@ -98,14 +228,12 @@ _fini(void)
return (error);
}
-
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
-
/*
* Function: hook_init
* Returns: None
@@ -116,11 +244,14 @@ _info(struct modinfo *modinfop)
static void
hook_init(void)
{
+ mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL);
+ SLIST_INIT(&hook_stacks);
+
/*
* We want to be informed each time a stack is created or
* destroyed in the kernel.
*/
- netstack_register(NS_HOOK, hook_stack_init, NULL,
+ netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown,
hook_stack_fini);
}
@@ -135,6 +266,134 @@ static void
hook_fini(void)
{
netstack_unregister(NS_HOOK);
+
+ mutex_destroy(&hook_stack_lock);
+ ASSERT(SLIST_EMPTY(&hook_stacks));
+}
+
+/*
+ * Function: hook_wait_setflag
+ * Returns: -1 = setting flag is disallowed, 0 = flag set and did
+ * not have to wait (ie no lock droped), 1 = flag set but
+ * it was necessary to drop locks to set it.
+ * Parameters: waiter(I) - control data structure
+ * busyset(I) - set of flags that we don't want set while
+ * we are active.
+ * wanted(I) - flag associated with newflag to indicate
+ * what we want to do.
+ * newflag(I) - the new ACTIVE flag we want to set that
+ * indicates what we are doing.
+ *
+ * The set of functions hook_wait_* implement an API that builds on top of
+ * the kcondvar_t to provide controlled execution through a critical region.
+ * For each flag that indicates work is being done (FWF_*_ACTIVE) there is
+ * also a flag that we set to indicate that we want to do it (FWF_*_WANTED).
+ * The combination of flags is required as when this function exits to do
+ * the task, the structure is then free for another caller to use and
+ * to indicate that it wants to do work. The trump flags here are those
+ * that indicate someone wants to destroy the structure that owns this
+ * flagwait_t. In this case, we don't try to secure the ability to run
+ * and return with an error.
+ *
+ * wanted - the FWF_*_WANTED flag that describes the action being requested
+ * busyset- the set of FWF_* flags we don't want set when we run
+ * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy
+ */
+int
+hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted,
+ fwflag_t newflag)
+{
+ int waited = 0;
+
+ mutex_enter(&waiter->fw_lock);
+ if (waiter->fw_flags & FWF_DESTROY) {
+ mutex_exit(&waiter->fw_lock);
+ return (-1);
+ }
+ while (waiter->fw_flags & busyset) {
+ waiter->fw_flags |= wanted;
+ CVW_EXIT_WRITE(waiter->fw_owner);
+ cv_wait(&waiter->fw_cv, &waiter->fw_lock);
+ waited = 1;
+ CVW_ENTER_WRITE(waiter->fw_owner);
+ if (waiter->fw_flags & FWF_DESTROY) {
+ waiter->fw_flags &= ~wanted;
+ mutex_exit(&waiter->fw_lock);
+ return (-1);
+ }
+ waiter->fw_flags |= wanted;
+ }
+ waiter->fw_flags &= ~wanted;
+ waiter->fw_flags |= newflag;
+ mutex_exit(&waiter->fw_lock);
+ return (waited);
+}
+
+/*
+ * Function: hook_wait_unsetflag
+ * Returns: None
+ * Parameters: waiter(I) - control data structure
+ * oldflag(I) - flag to reset
+ *
+ * Turn off the bit that we had set to run and let others know that
+ * they should now check to see if they can run.
+ */
+void
+hook_wait_unsetflag(flagwait_t *waiter, uint32_t oldflag)
+{
+ mutex_enter(&waiter->fw_lock);
+ waiter->fw_flags &= ~oldflag;
+ cv_signal(&waiter->fw_cv);
+ mutex_exit(&waiter->fw_lock);
+}
+
+/*
+ * Function: hook_wait_destroy
+ * Returns: None
+ * Parameters: waiter(I) - control data structure
+ *
+ * Since outer locking (on fw_owner) should ensure that only one function
+ * at a time gets to call hook_wait_destroy() on a given object, there is
+ * no need to guard against setting FWF_DESTROY_WANTED already being set.
+ * It is, however, necessary to wait for all activity on the owning
+ * structure to cease.
+ */
+void
+hook_wait_destroy(flagwait_t *waiter)
+{
+ ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0);
+ waiter->fw_flags |= FWF_DESTROY_WANTED;
+ while (!FWF_DESTROY_OK(waiter)) {
+ CVW_EXIT_WRITE(waiter->fw_owner);
+ cv_wait(&waiter->fw_cv, &waiter->fw_lock);
+ CVW_ENTER_WRITE(waiter->fw_owner);
+ }
+ /*
+ * There should now be nothing else using "waiter" or its
+ * owner, so we can safely assign here without risk of wiiping
+ * out someone's bit.
+ */
+ waiter->fw_flags = FWF_DESTROY_ACTIVE;
+}
+
+/*
+ * Function: hook_wait_init
+ * Returns: None
+ * Parameters: waiter(I) - control data structure
+ * ownder(I) - pointer to lock that the owner of this
+ * waiter uses
+ *
+ * "owner" gets passed in here so that when we need to call cv_wait,
+ * for example in hook_wait_setflag(), we can drop the lock for the
+ * next layer out, which is likely to be held in an exclusive manner.
+ */
+void
+hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner)
+{
+ cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL);
+ mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL);
+ waiter->fw_flags = FWF_NONE;
+ waiter->fw_owner = owner;
}
/*
@@ -151,14 +410,37 @@ hook_stack_init(netstackid_t stackid, netstack_t *ns)
#endif
hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP);
- hks->hk_netstack = ns;
+ hks->hks_netstack = ns;
+ hks->hks_netstackid = stackid;
- CVW_INIT(&hks->hks_familylock);
+ CVW_INIT(&hks->hks_lock);
+ TAILQ_INIT(&hks->hks_nhead);
SLIST_INIT(&hks->hks_familylist);
+ hook_wait_init(&hks->hks_waiter, &hks->hks_lock);
+
+ mutex_enter(&hook_stack_lock);
+ SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry);
+ mutex_exit(&hook_stack_lock);
+
return (hks);
}
+/*ARGSUSED*/
+static void
+hook_stack_shutdown(netstackid_t stackid, void *arg)
+{
+ hook_stack_t *hks = (hook_stack_t *)arg;
+
+ mutex_enter(&hook_stack_lock);
+ /*
+ * Once this flag gets set to one, no more additions are allowed
+ * to any of the structures that make up this stack.
+ */
+ hks->hks_shutdown = 1;
+ mutex_exit(&hook_stack_lock);
+}
+
/*
* Free the hook stack instance.
*/
@@ -166,14 +448,143 @@ hook_stack_init(netstackid_t stackid, netstack_t *ns)
static void
hook_stack_fini(netstackid_t stackid, void *arg)
{
- hook_stack_t *hks = (hook_stack_t *)arg;
-#ifdef NS_DEBUG
- printf("hook_stack_fini(%p, stack %d)\n", arg, stackid);
-#endif
- CVW_DESTROY(&hks->hks_familylock);
+ hook_stack_t *hks = (hook_stack_t *)arg;
+
+ mutex_enter(&hook_stack_lock);
+ hks->hks_shutdown = 2;
+ hook_stack_remove(hks);
+ mutex_exit(&hook_stack_lock);
+}
+
+/*
+ * This function assumes that it is called with hook_stack_lock held.
+ * It functions differently to hook_family/event_remove in that it does
+ * the checks to see if it can be removed. This difference exists
+ * because this structure has nothing higher up that depends on it.
+ */
+static void
+hook_stack_remove(hook_stack_t *hks)
+{
+
+ ASSERT(mutex_owned(&hook_stack_lock));
+
+ /*
+ * Is the structure still in use?
+ */
+ if (!SLIST_EMPTY(&hks->hks_familylist) ||
+ !TAILQ_EMPTY(&hks->hks_nhead))
+ return;
+
+ SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry);
+
+ hook_wait_destroy(&hks->hks_waiter);
+ CVW_DESTROY(&hks->hks_lock);
kmem_free(hks, sizeof (*hks));
}
+static hook_stack_t *
+hook_stack_get(netstackid_t stackid)
+{
+ hook_stack_t *hks;
+
+ SLIST_FOREACH(hks, &hook_stacks, hks_entry) {
+ if (hks->hks_netstackid == stackid)
+ break;
+ }
+
+ return (hks);
+}
+
+/*
+ * Function: hook_stack_notify_register
+ * Returns: 0 = success, else failure
+ * Parameters: stackid(I) - netstack identifier
+ * callback(I)- function to be called
+ * arg(I) - arg to provide callback when it is called
+ *
+ * If we're not shutting down this instance, append a new function to the
+ * list of those to call when a new family of hooks is added to this stack.
+ */
+int
+hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback,
+ void *arg)
+{
+ hook_stack_t *hks;
+ int error;
+
+ mutex_enter(&hook_stack_lock);
+ hks = hook_stack_get(stackid);
+ if (hks != NULL) {
+ if (hks->hks_shutdown != 0) {
+ error = ESHUTDOWN;
+ } else {
+ error = hook_notify_register(&hks->hks_lock,
+ &hks->hks_nhead, callback, arg);
+ }
+ } else {
+ error = ESRCH;
+ }
+ mutex_exit(&hook_stack_lock);
+
+ return (error);
+}
+
+/*
+ * Function: hook_stack_notify_unregister
+ * Returns: 0 = success, else failure
+ * Parameters: stackid(I) - netstack identifier
+ * callback(I) - function to be called
+ *
+ * Attempt to remove a registered function from a hook stack's list of
+ * callbacks to activiate when protocols are added/deleted.
+ */
+int
+hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
+{
+ hook_stack_t *hks;
+ int error;
+
+ mutex_enter(&hook_stack_lock);
+ hks = hook_stack_get(stackid);
+ if (hks != NULL) {
+ error = hook_notify_unregister(&hks->hks_lock,
+ &hks->hks_nhead, callback);
+ if ((error == 0) && (hks->hks_shutdown == 2))
+ hook_stack_remove(hks);
+ } else {
+ error = ESRCH;
+ }
+ mutex_exit(&hook_stack_lock);
+
+ return (error);
+}
+
+/*
+ * Function: hook_stack_notify_run
+ * Returns: None
+ * Parameters: hks(I) - hook stack pointer to execute callbacks for
+ * name(I) - name of a hook family
+ * cmd(I) - either HN_UNREGISTER or HN_REGISTER
+ *
+ * Run through the list of callbacks on the hook stack to be called when
+ * a new hook family is added
+ *
+ * As hook_notify_run() expects 3 names, one for the family, one for the
+ * event and one for the object being introduced and we really only have
+ * one name (that of the new hook family), fake the hook stack's name by
+ * converting the integer to a string and for the event just pass NULL.
+ */
+static void
+hook_stack_notify_run(hook_stack_t *hks, char *name,
+ hook_notify_cmd_t cmd)
+{
+ char buffer[16];
+
+ (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid);
+
+ hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd);
+}
+
/*
* Function: hook_run
* Returns: int - return value according to callback func
@@ -187,11 +598,10 @@ hook_stack_fini(netstackid_t stackid, void *arg)
* called more than once, simultaneously.
*/
int
-hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns)
+hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info)
{
- hook_int_t *hi;
hook_event_int_t *hei;
- hook_stack_t *hks = ns->netstack_hook;
+ hook_int_t *hi;
int rval = 0;
ASSERT(token != NULL);
@@ -201,11 +611,17 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns)
hook_event_token_t, token,
hook_data_t, info);
- /* Hold global read lock to ensure event will not be deleted */
- CVW_ENTER_READ(&hks->hks_familylock);
-
- /* Hold event read lock to ensure hook will not be changed */
- CVW_ENTER_READ(&hei->hei_lock);
+ /*
+ * Hold global read lock to ensure event will not be deleted.
+ * While it might be expected that we should also hold a read lock
+ * on the event lock (hei_lock) to prevent the hook list from
+ * changing while we're executing this function, both addition
+ * to and removal from the hook list on the event is done with
+ * a write lock held on hfi_lock. This is by design so that we
+ * only need to get one of these locks to process a packet.
+ * - locking is not a cheap thing to do for every packet.
+ */
+ CVW_ENTER_READ(&hfi->hfi_lock);
TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) {
ASSERT(hi->hi_hook.h_func != NULL);
@@ -213,18 +629,20 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns)
hook_event_token_t, token,
hook_data_t, info,
hook_int_t *, hi);
- rval = (*hi->hi_hook.h_func)(token, info, ns);
+ rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg);
DTRACE_PROBE4(hook__func__end,
hook_event_token_t, token,
hook_data_t, info,
hook_int_t *, hi,
int, rval);
+ hi->hi_kstats.hook_hits.value.ui64++;
if (rval != 0)
break;
}
- CVW_EXIT_READ(&hei->hei_lock);
- CVW_EXIT_READ(&hks->hks_familylock);
+ hei->hei_kstats.events.value.ui64++;
+
+ CVW_EXIT_READ(&hfi->hfi_lock);
DTRACE_PROBE3(hook__run__end,
hook_event_token_t, token,
@@ -234,7 +652,6 @@ hook_run(hook_event_token_t token, hook_data_t info, netstack_t *ns)
return (rval);
}
-
/*
* Function: hook_family_add
* Returns: internal family pointer - NULL = Fail
@@ -254,32 +671,62 @@ hook_family_add(hook_family_t *hf, hook_stack_t *hks)
if (new == NULL)
return (NULL);
- CVW_ENTER_WRITE(&hks->hks_familylock);
+ mutex_enter(&hook_stack_lock);
+ CVW_ENTER_WRITE(&hks->hks_lock);
+
+ if (hks->hks_shutdown != 0) {
+ CVW_EXIT_WRITE(&hks->hks_lock);
+ mutex_exit(&hook_stack_lock);
+ hook_family_free(new, NULL);
+ return (NULL);
+ }
/* search family list */
hfi = hook_family_find(hf->hf_name, hks);
if (hfi != NULL) {
- CVW_EXIT_WRITE(&hks->hks_familylock);
- hook_family_free(new);
+ CVW_EXIT_WRITE(&hks->hks_lock);
+ mutex_exit(&hook_stack_lock);
+ hook_family_free(new, NULL);
return (NULL);
}
- new->hfi_ptr = (void *)hks;
+ if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK,
+ FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
+ CVW_EXIT_WRITE(&hks->hks_lock);
+ mutex_exit(&hook_stack_lock);
+ hook_family_free(new, NULL);
+ return (NULL);
+ }
+
+ CVW_INIT(&new->hfi_lock);
+ SLIST_INIT(&new->hfi_head);
+ TAILQ_INIT(&new->hfi_nhead);
+
+ hook_wait_init(&new->hfi_waiter, &new->hfi_lock);
+
+ new->hfi_stack = hks;
/* Add to family list head */
SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry);
- CVW_EXIT_WRITE(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hks->hks_lock);
+ mutex_exit(&hook_stack_lock);
+
+ hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER);
+
+ hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
+
return (new);
}
-
/*
* Function: hook_family_remove
* Returns: int - 0 = Succ, Else = Fail
* Parameters: hfi(I) - internal family pointer
*
- * Remove family from family list
+ * Remove family from family list. This function has been designed to be
+ * called once and once only per hook_family_int_t. Thus when cleaning up
+ * this structure as an orphan, callers should only call hook_family_free.
*/
int
hook_family_remove(hook_family_int_t *hfi)
@@ -287,27 +734,99 @@ hook_family_remove(hook_family_int_t *hfi)
hook_stack_t *hks;
ASSERT(hfi != NULL);
- hks = (hook_stack_t *)hfi->hfi_ptr;
+ hks = hfi->hfi_stack;
- CVW_ENTER_WRITE(&hks->hks_familylock);
+ CVW_ENTER_WRITE(&hks->hks_lock);
+
+ if (hook_wait_setflag(&hks->hks_waiter, FWF_WAIT_MASK,
+ FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
+ /*
+ * If we're trying to destroy the hook_stack_t...
+ */
+ return (ENXIO);
+ }
- /* Check if there are events */
- if (!SLIST_EMPTY(&hfi->hfi_head)) {
- CVW_EXIT_WRITE(&hks->hks_familylock);
- return (EBUSY);
+ /*
+ * Check if the family is in use by the presence of either events
+ * or notify callbacks on the hook family.
+ */
+ if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) {
+ hfi->hfi_condemned = B_TRUE;
+ } else {
+ /*
+ * Although hfi_condemned = B_FALSE is implied from creation,
+ * putting a comment here inside the else upsets lint.
+ */
+ hfi->hfi_condemned = B_FALSE;
}
- /* Remove from family list */
- SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int, hfi_entry);
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+ hook_wait_destroy(&hfi->hfi_waiter);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+
+ CVW_EXIT_WRITE(&hks->hks_lock);
+
+ hook_stack_notify_run(hks, hfi->hfi_family.hf_name, HN_UNREGISTER);
- CVW_EXIT_WRITE(&hks->hks_familylock);
- hook_family_free(hfi);
+ hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
+
+ /*
+ * If we don't have to wait for anything else to disappear from this
+ * structure then we can free it up.
+ */
+ if (!hfi->hfi_condemned)
+ hook_family_free(hfi, hks);
return (0);
}
/*
+ * 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, hook_stack_t *hks)
+{
+
+ /*
+ * This lock gives us possession of the hks pointer after the
+ * SLIST_REMOVE, for which it is not needed, when hks_shutdown
+ * is checked and hook_stack_remove called.
+ */
+ mutex_enter(&hook_stack_lock);
+
+ ASSERT(hfi != NULL);
+
+ if (hks != NULL) {
+ CVW_ENTER_WRITE(&hks->hks_lock);
+ /* Remove from family list */
+ SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int,
+ hfi_entry);
+
+ CVW_EXIT_WRITE(&hks->hks_lock);
+ }
+
+ /* 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));
+
+ if (hks->hks_shutdown == 2)
+ hook_stack_remove(hks);
+
+ mutex_exit(&hook_stack_lock);
+}
+
+
+/*
* Function: hook_family_copy
* Returns: internal family pointer - NULL = Failed
* Parameters: src(I) - family pointer
@@ -327,10 +846,12 @@ hook_family_copy(hook_family_t *src)
new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
/* Copy body */
- SLIST_INIT(&new->hfi_head);
dst = &new->hfi_family;
*dst = *src;
+ SLIST_INIT(&new->hfi_head);
+ TAILQ_INIT(&new->hfi_nhead);
+
/* Copy name */
dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP);
(void) strcpy(dst->hf_name, src->hf_name);
@@ -338,13 +859,13 @@ hook_family_copy(hook_family_t *src)
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.
+ * A lock on hfi_lock must be held when called.
*/
static hook_family_int_t *
hook_family_find(char *family, hook_stack_t *hks)
@@ -360,29 +881,90 @@ hook_family_find(char *family, hook_stack_t *hks)
return (hfi);
}
-
/*
- * Function: hook_family_free
- * Returns: None
- * Parameters: hfi(I) - internal family pointer
+ * Function: hook_family_notify_register
+ * Returns: 0 = success, else failure
+ * Parameters: hfi(I) - hook family
+ * callback(I) - function to be called
+ * arg(I) - arg to provide callback when it is called
*
- * Free alloc memory for family
+ * So long as this hook stack isn't being shut down, register a new
+ * callback to be activated each time a new event is added to this
+ * family.
+ *
+ * To call this function we must have an active handle in use on the family,
+ * so if we take this into account, then neither the hook_family_int_t nor
+ * the hook_stack_t that owns it can disappear. We have to put some trust
+ * in the callers to be properly synchronised...
+ *
+ * Holding hks_lock is required to provide synchronisation for hks_shutdown.
*/
-static void
-hook_family_free(hook_family_int_t *hfi)
+int
+hook_family_notify_register(hook_family_int_t *hfi,
+ hook_notify_fn_t callback, void *arg)
{
- ASSERT(hfi != NULL);
+ hook_stack_t *hks;
+ int error;
- /* Free name space */
- if (hfi->hfi_family.hf_name != NULL) {
- kmem_free(hfi->hfi_family.hf_name,
- strlen(hfi->hfi_family.hf_name) + 1);
+ hks = hfi->hfi_stack;
+
+ CVW_ENTER_READ(&hks->hks_lock);
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+
+ if (hfi->hfi_stack->hks_shutdown != 0) {
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ return (ESHUTDOWN);
}
- /* Free container */
- kmem_free(hfi, sizeof (*hfi));
+ error = hook_notify_register(&hfi->hfi_lock, &hfi->hfi_nhead,
+ callback, arg);
+
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+
+ return (error);
}
+/*
+ * Function: hook_family_notify_unregister
+ * Returns: 0 = success, else failure
+ * Parameters: hfi(I) - hook family
+ * callback(I) - function to be called
+ *
+ * Remove a callback from the list of those executed when a new event is
+ * added to a hook family.
+ */
+int
+hook_family_notify_unregister(hook_family_int_t *hfi,
+ hook_notify_fn_t callback)
+{
+ boolean_t free_family;
+ int error;
+
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+
+ error = hook_notify_unregister(&hfi->hfi_lock, &hfi->hfi_nhead,
+ callback);
+
+ /*
+ * If hook_family_remove has been called but the structure was still
+ * "busy" ... but we might have just made it "unbusy"...
+ */
+ if ((error == 0) && hfi->hfi_condemned &&
+ SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) {
+ free_family = B_TRUE;
+ } else {
+ free_family = B_FALSE;
+ }
+
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+
+ if (free_family)
+ hook_family_free(hfi, hfi->hfi_stack);
+
+ return (error);
+}
/*
* Function: hook_event_add
@@ -398,35 +980,110 @@ hook_family_free(hook_family_int_t *hfi)
hook_event_int_t *
hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
{
- hook_stack_t *hks;
hook_event_int_t *hei, *new;
+ hook_stack_t *hks;
ASSERT(hfi != NULL);
ASSERT(he != NULL);
ASSERT(he->he_name != NULL);
- hks = (hook_stack_t *)hfi->hfi_ptr;
new = hook_event_copy(he);
if (new == NULL)
return (NULL);
- CVW_ENTER_WRITE(&hks->hks_familylock);
+ hks = hfi->hfi_stack;
+ CVW_ENTER_READ(&hks->hks_lock);
+
+ hks = hfi->hfi_stack;
+ if (hks->hks_shutdown != 0) {
+ CVW_EXIT_READ(&hks->hks_lock);
+ hook_event_free(new, NULL);
+ return (NULL);
+ }
/* Check whether this event pointer is already registered */
hei = hook_event_checkdup(he, hks);
if (hei != NULL) {
- CVW_EXIT_WRITE(&hks->hks_familylock);
- hook_event_free(new);
+ CVW_EXIT_READ(&hks->hks_lock);
+ hook_event_free(new, NULL);
return (NULL);
}
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+
+ if (hfi->hfi_condemned) {
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ hook_event_free(new, NULL);
+ return (NULL);
+ }
+
+ if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK,
+ FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ hook_event_free(new, NULL);
+ return (NULL);
+ }
+
+ TAILQ_INIT(&new->hei_nhead);
+
+ hook_event_init_kstats(hfi, new);
+ hook_wait_init(&new->hei_waiter, &new->hei_lock);
+
/* Add to event list head */
SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry);
- CVW_EXIT_WRITE(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+
+ CVW_EXIT_READ(&hks->hks_lock);
+
+ hook_notify_run(&hfi->hfi_nhead,
+ hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER);
+
+ hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
+
return (new);
}
+/*
+ * Function: hook_event_init_kstats
+ * Returns: None
+ * Parameters: hfi(I) - pointer to the family that owns this event.
+ * hei(I) - pointer to the hook event that needs some kstats.
+ *
+ * Create a set of kstats that relate to each event registered with
+ * the hook framework. A counter is kept for each time the event is
+ * activated and for each time a hook is added or removed. As the
+ * kstats just count the events as they happen, the total number of
+ * hooks registered must be obtained by subtractived removed from added.
+ */
+static void
+hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei)
+{
+ hook_event_kstat_t template = {
+ { "hooksAdded", KSTAT_DATA_UINT64 },
+ { "hooksRemoved", KSTAT_DATA_UINT64 },
+ { "events", KSTAT_DATA_UINT64 }
+ };
+ hook_stack_t *hks;
+
+ hks = hfi->hfi_stack;
+ hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0,
+ hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED,
+ sizeof (hei->hei_kstats) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
+
+ bcopy((char *)&template, &hei->hei_kstats, sizeof (template));
+
+ if (hei->hei_kstatp != NULL) {
+ hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats;
+ hei->hei_kstatp->ks_private =
+ (void *)(uintptr_t)hks->hks_netstackid;
+
+ kstat_install(hei->hei_kstatp);
+ }
+}
/*
* Function: hook_event_remove
@@ -435,48 +1092,136 @@ hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
* he(I) - event pointer
*
* Remove event from event list on specific family
+ *
+ * This function assumes that the caller has received a pointer to a the
+ * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'.
+ * This the hook_family_int_t is guaranteed to be around for the life of this
+ * call, unless the caller has decided to call net_protocol_release or
+ * net_protocol_unregister before calling net_event_unregister - an error.
*/
int
hook_event_remove(hook_family_int_t *hfi, hook_event_t *he)
{
- hook_stack_t *hks;
+ boolean_t free_family;
hook_event_int_t *hei;
ASSERT(hfi != NULL);
ASSERT(he != NULL);
- hks = (hook_stack_t *)hfi->hfi_ptr;
- CVW_ENTER_WRITE(&hks->hks_familylock);
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+
+ /*
+ * Set the flag so that we can call hook_event_notify_run without
+ * holding any locks but at the same time prevent other changes to
+ * the event at the same time.
+ */
+ if (hook_wait_setflag(&hfi->hfi_waiter, FWF_WAIT_MASK,
+ FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ return (ENXIO);
+ }
hei = hook_event_find(hfi, he->he_name);
if (hei == NULL) {
- CVW_EXIT_WRITE(&hks->hks_familylock);
- return (ENXIO);
+ hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ return (ESRCH);
}
- /* Check if there are registered hooks for this event */
- if (!TAILQ_EMPTY(&hei->hei_head)) {
- CVW_EXIT_WRITE(&hks->hks_familylock);
- return (EBUSY);
+ free_family = B_FALSE;
+
+ CVW_ENTER_WRITE(&hei->hei_lock);
+ /*
+ * If there are any hooks still registered for this event or
+ * there are any notifiers registered, return an error indicating
+ * that the event is still busy.
+ */
+ if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) {
+ hei->hei_condemned = B_TRUE;
+ CVW_EXIT_WRITE(&hei->hei_lock);
+ } else {
+ /* hei_condemned = B_FALSE is implied from creation */
+ /*
+ * Even though we know the notify list is empty, we call
+ * hook_wait_destroy here to synchronise wait removing a
+ * hook from an event.
+ */
+ hook_wait_destroy(&hei->hei_waiter);
+
+ CVW_EXIT_WRITE(&hei->hei_lock);
+
+ if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
+ TAILQ_EMPTY(&hfi->hfi_nhead))
+ free_family = B_TRUE;
}
- /* Remove from event list */
- SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+
+ hook_notify_run(&hfi->hfi_nhead,
+ hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
- CVW_EXIT_WRITE(&hks->hks_familylock);
- hook_event_free(hei);
+ hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
+
+ if (!hei->hei_condemned) {
+ hook_event_free(hei, hfi);
+ if (free_family)
+ hook_family_free(hfi, hfi->hfi_stack);
+ }
return (0);
}
+/*
+ * 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, hook_family_int_t *hfi)
+{
+ boolean_t free_family;
+
+ ASSERT(hei != NULL);
+
+ if (hfi != NULL) {
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
+ /*
+ * Remove the event from the hook family's list.
+ */
+ SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
+ if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
+ TAILQ_EMPTY(&hfi->hfi_nhead)) {
+ free_family = B_TRUE;
+ } else {
+ free_family = B_FALSE;
+ }
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ }
+
+ if (hei->hei_kstatp != NULL) {
+ ASSERT(hfi != NULL);
+
+ kstat_delete_netstack(hei->hei_kstatp,
+ hfi->hfi_stack->hks_netstackid);
+ hei->hei_kstatp = NULL;
+ }
+
+ /* Free container */
+ kmem_free(hei, sizeof (*hei));
+
+ if (free_family)
+ hook_family_free(hfi, hfi->hfi_stack);
+}
/*
* 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.
+ * Search all of the hook families to see if the event being passed in
+ * has already been associated with one.
*/
static hook_event_int_t *
hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
@@ -486,17 +1231,20 @@ hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
ASSERT(he != NULL);
+ CVW_ENTER_READ(&hks->hks_lock);
SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
- if (hei->hei_event == he)
+ if (hei->hei_event == he) {
+ CVW_EXIT_READ(&hks->hks_lock);
return (hei);
+ }
}
}
+ CVW_EXIT_READ(&hks->hks_lock);
return (NULL);
}
-
/*
* Function: hook_event_copy
* Returns: internal event pointer - NULL = Failed
@@ -522,7 +1270,6 @@ hook_event_copy(hook_event_t *src)
return (new);
}
-
/*
* Function: hook_event_find
* Returns: internal event pointer - NULL = Not match
@@ -530,7 +1277,7 @@ hook_event_copy(hook_event_t *src)
* event(I) - event name string
*
* Search event list with event name
- * A lock on hks->hks_familylock must be held when called.
+ * A lock on hfi->hfi_lock must be held when called.
*/
static hook_event_int_t *
hook_event_find(hook_family_int_t *hfi, char *event)
@@ -541,30 +1288,157 @@ hook_event_find(hook_family_int_t *hfi, char *event)
ASSERT(event != NULL);
SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
- if (strcmp(hei->hei_event->he_name, event) == 0)
+ if ((strcmp(hei->hei_event->he_name, event) == 0) &&
+ ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0))
break;
}
return (hei);
}
+/*
+ * Function: hook_event_notify_register
+ * Returns: 0 = success, else failure
+ * Parameters: hfi(I) - hook family
+ * event(I) - name of the event
+ * callback(I) - function to be called
+ * arg(I) - arg to provide callback when it is called
+ *
+ * Adds a new callback to the event named by "event" (we must find it)
+ * that will be executed each time a new hook is added to the event.
+ * Of course, if the stack is being shut down, this call should fail.
+ */
+int
+hook_event_notify_register(hook_family_int_t *hfi, char *event,
+ hook_notify_fn_t callback, void *arg)
+{
+ hook_event_int_t *hei;
+ hook_stack_t *hks;
+ int error;
+
+ hks = hfi->hfi_stack;
+ CVW_ENTER_READ(&hks->hks_lock);
+ if (hks->hks_shutdown != 0) {
+ CVW_EXIT_READ(&hks->hks_lock);
+ return (ESHUTDOWN);
+ }
+
+ CVW_ENTER_READ(&hfi->hfi_lock);
+
+ if (hfi->hfi_condemned) {
+ CVW_EXIT_READ(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ return (ESHUTDOWN);
+ }
+
+ hei = hook_event_find(hfi, event);
+ if (hei == NULL) {
+ CVW_EXIT_READ(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ return (ESRCH);
+ }
+
+ /*
+ * Grabbing the read lock on hei_lock is only so that we can
+ * synchronise access to hei_condemned.
+ */
+ CVW_ENTER_WRITE(&hei->hei_lock);
+ if (hei->hei_condemned) {
+ CVW_EXIT_WRITE(&hei->hei_lock);
+ CVW_EXIT_READ(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+ return (ESHUTDOWN);
+ }
+
+ error = hook_notify_register(&hei->hei_lock, &hei->hei_nhead,
+ callback, arg);
+
+ CVW_EXIT_WRITE(&hei->hei_lock);
+ CVW_EXIT_READ(&hfi->hfi_lock);
+ CVW_EXIT_READ(&hks->hks_lock);
+
+ return (error);
+}
/*
- * Function: hook_event_free
+ * Function: hook_event_notify_unregister
+ * Returns: 0 = success, else failure
+ * Parameters: hfi(I) - hook family
+ * event(I) - name of the event
+ * callback(I) - function to be called
+ *
+ * Remove the given callback from the named event's list of functions
+ * to call when a hook is added or removed.
+ */
+int
+hook_event_notify_unregister(hook_family_int_t *hfi, char *event,
+ hook_notify_fn_t callback)
+{
+ hook_event_int_t *hei;
+ boolean_t free_event;
+ int error;
+
+ CVW_ENTER_READ(&hfi->hfi_lock);
+
+ hei = hook_event_find(hfi, event);
+ if (hei == NULL) {
+ CVW_EXIT_READ(&hfi->hfi_lock);
+ return (ESRCH);
+ }
+
+ CVW_ENTER_WRITE(&hei->hei_lock);
+
+ error = hook_notify_unregister(&hei->hei_lock, &hei->hei_nhead,
+ callback);
+
+ /*
+ * hei_condemned has been set if someone tried to remove the
+ * event but couldn't because there were still things attached to
+ * it. Now that we've done a successful remove, if it is now empty
+ * then by all rights we should be free'ing it too. Note that the
+ * expectation is that only the caller of hook_event_add will ever
+ * call hook_event_remove.
+ */
+ if ((error == 0) && hei->hei_condemned &&
+ TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) {
+ free_event = B_TRUE;
+ } else {
+ free_event = B_FALSE;
+ }
+
+ CVW_EXIT_WRITE(&hei->hei_lock);
+ CVW_EXIT_READ(&hfi->hfi_lock);
+
+ if (free_event) {
+ /*
+ * It is safe to pass in hfi here, without a lock, because
+ * our structure (hei) is still on one of its lists and thus
+ * it won't be able to disappear yet...
+ */
+ hook_event_free(hei, hfi);
+ }
+
+ return (error);
+}
+
+/*
+ * Function: hook_event_notify_run
* Returns: None
- * Parameters: hei(I) - internal event pointer
+ * Parameters: nrun(I) - pointer to the list of callbacks to execute
+ * hfi(I) - hook stack pointer to execute callbacks for
+ * name(I) - name of a hook family
+ * cmd(I) - either HN_UNREGISTER or HN_REGISTER
*
- * Free alloc memory for event
+ * Execute all of the callbacks registered for this event.
*/
static void
-hook_event_free(hook_event_int_t *hei)
+hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi,
+ char *event, char *name, hook_notify_cmd_t cmd)
{
- ASSERT(hei != NULL);
- /* Free container */
- kmem_free(hei, sizeof (*hei));
+ hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name,
+ event, name, cmd);
}
-
/*
* Function: hook_register
* Returns: int- 0 = Succ, Else = Fail
@@ -572,19 +1446,21 @@ hook_event_free(hook_event_int_t *hei)
* event(I) - event name string
* h(I) - hook pointer
*
- * Add new hook to hook list on spefic family, event
+ * Add new hook to hook list on the specified family and event.
*/
int
hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
{
- hook_stack_t *hks;
hook_event_int_t *hei;
hook_int_t *hi, *new;
+ int error;
ASSERT(hfi != NULL);
ASSERT(event != NULL);
ASSERT(h != NULL);
- hks = (hook_stack_t *)hfi->hfi_ptr;
+
+ if (hfi->hfi_stack->hks_shutdown)
+ return (NULL);
/* Alloc hook_int_t and copy hook */
new = hook_copy(h);
@@ -596,43 +1472,255 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
* 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(&hks->hks_familylock);
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
hei = hook_event_find(hfi, event);
if (hei == NULL) {
- CVW_EXIT_READ(&hks->hks_familylock);
- hook_free(new);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ hook_int_free(new, hfi->hfi_stack->hks_netstackid);
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(&hks->hks_familylock);
- hook_free(new);
- return (EEXIST);
- }
-
hi = hook_find(hei, h);
if (hi != NULL) {
+ error = EEXIST;
+ goto bad_add;
+ }
+
+ if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK,
+ FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
+ error = ENOENT;
+bad_add:
CVW_EXIT_WRITE(&hei->hei_lock);
- CVW_EXIT_READ(&hks->hks_familylock);
- hook_free(new);
- return (EEXIST);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ hook_int_free(new, hfi->hfi_stack->hks_netstackid);
+ return (error);
}
/* Add to hook list head */
- TAILQ_INSERT_HEAD(&hei->hei_head, new, hi_entry);
- hei->hei_event->he_interested = B_TRUE;
+ error = hook_insert(&hei->hei_head, new);
+ if (error == 0) {
+ hei->hei_event->he_interested = B_TRUE;
+ hei->hei_kstats.hooks_added.value.ui64++;
+
+ hook_init_kstats(hfi, hei, new);
+ }
CVW_EXIT_WRITE(&hei->hei_lock);
- CVW_EXIT_READ(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+
+ /*
+ * Note that the name string passed through to the notify callbacks
+ * is from the original hook being registered, not the copy being
+ * inserted.
+ */
+ if (error == 0) {
+ hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER);
+ hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
+ }
+
+ return (error);
+}
+
+/*
+ * Function: hook_insert
+ * Returns: int- 0 = Succ, else = Fail
+ * Parameters: head(I) - pointer to hook list to insert hook onto
+ * new(I) - pointer to hook to be inserted
+ *
+ * Try to insert the hook onto the list of hooks according to the hints
+ * given in the hook to be inserted and those that already exist on the
+ * list. For now, the implementation permits only a single hook to be
+ * either first or last and names provided with before or after are only
+ * loosely coupled with the action.
+ */
+static int
+hook_insert(hook_int_head_t *head, hook_int_t *new)
+{
+ hook_int_t *before;
+ hook_int_t *hi;
+ hook_t *hih;
+ hook_t *h = &new->hi_hook;
+
+ switch (new->hi_hook.h_hint) {
+ case HH_NONE :
+ before = NULL;
+ /*
+ * If there is no hint present (or not one that can be
+ * satisfied now) then try to at least respect the wishes
+ * of those that want to be last. If there are none wanting
+ * to be last then add the new hook to the tail of the
+ * list - this means we keep any wanting to be first
+ * happy without having to search for HH_FIRST.
+ */
+ TAILQ_FOREACH(hi, head, hi_entry) {
+ hih = &hi->hi_hook;
+ if ((hih->h_hint == HH_AFTER) &&
+ (strcmp(h->h_name,
+ (char *)hih->h_hintvalue) == 0)) {
+ TAILQ_INSERT_BEFORE(hi, new, hi_entry);
+ return (0);
+ }
+ if ((hih->h_hint == HH_BEFORE) && (before == NULL) &&
+ (strcmp(h->h_name,
+ (char *)hih->h_hintvalue) == 0)) {
+ before = hi;
+ }
+ }
+ if (before != NULL) {
+ TAILQ_INSERT_AFTER(head, before, new, hi_entry);
+ return (0);
+ }
+ hook_insert_plain(head, new);
+ break;
+
+ case HH_FIRST :
+ hi = TAILQ_FIRST(head);
+ if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST))
+ return (EBUSY);
+ TAILQ_INSERT_HEAD(head, new, hi_entry);
+ break;
+
+ case HH_LAST :
+ hi = TAILQ_LAST(head, hook_int_head);
+ if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST))
+ return (EBUSY);
+ TAILQ_INSERT_TAIL(head, new, hi_entry);
+ break;
+
+ case HH_BEFORE :
+ hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
+ if (hi == NULL)
+ return (hook_insert_afterbefore(head, new));
+
+ if (hi->hi_hook.h_hint == HH_FIRST)
+ return (EBUSY);
+
+ TAILQ_INSERT_BEFORE(hi, new, hi_entry);
+ break;
+
+ case HH_AFTER :
+ hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
+ if (hi == NULL)
+ return (hook_insert_afterbefore(head, new));
+
+ if (hi->hi_hook.h_hint == HH_LAST)
+ return (EBUSY);
+
+ TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
+ break;
+
+ default :
+ return (EINVAL);
+ }
+
return (0);
}
+/*
+ * Function: hook_insert_plain
+ * Returns: int- 0 = success, else = failure
+ * Parameters: head(I) - pointer to hook list to insert hook onto
+ * new(I) - pointer to hook to be inserted
+ *
+ * Insert a hook such that it respects the wishes of those that want to
+ * be last. If there are none wanting to be last then add the new hook
+ * to the tail of the list - this means we keep any wanting to be first
+ * happy without having to search for HH_FIRST.
+ */
+static void
+hook_insert_plain(hook_int_head_t *head, hook_int_t *new)
+{
+ hook_int_t *hi;
+
+ hi = TAILQ_FIRST(head);
+ if (hi != NULL) {
+ if (hi->hi_hook.h_hint == HH_LAST) {
+ TAILQ_INSERT_BEFORE(hi, new, hi_entry);
+ } else {
+ TAILQ_INSERT_TAIL(head, new, hi_entry);
+ }
+ } else {
+ TAILQ_INSERT_TAIL(head, new, hi_entry);
+ }
+}
+
+/*
+ * Function: hook_insert_afterbefore
+ * Returns: int- 0 = success, else = failure
+ * Parameters: head(I) - pointer to hook list to insert hook onto
+ * new(I) - pointer to hook to be inserted
+ *
+ * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not
+ * possible, so now we need to be more careful. The first pass is to go
+ * through the list and look for any other hooks that also specify the
+ * same hint name as the new one. The object of this exercise is to make
+ * sure that hooks with HH_BEFORE always appear on the list before those
+ * with HH_AFTER so that when said hook arrives, it can be placed in the
+ * middle of the BEFOREs and AFTERs. If this condition does not arise,
+ * just use hook_insert_plain() to try and insert the hook somewhere that
+ * is innocuous to existing efforts.
+ */
+static int
+hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new)
+{
+ hook_int_t *hi;
+ hook_t *nh;
+ hook_t *h;
+
+ nh = &new->hi_hook;
+ ASSERT(new->hi_hook.h_hint != HH_NONE);
+ ASSERT(new->hi_hook.h_hint != HH_LAST);
+ ASSERT(new->hi_hook.h_hint != HH_FIRST);
+
+ /*
+ * First, look through the list to see if there are any other
+ * before's or after's that have a matching hint name.
+ */
+ TAILQ_FOREACH(hi, head, hi_entry) {
+ h = &hi->hi_hook;
+ switch (h->h_hint) {
+ case HH_FIRST :
+ case HH_LAST :
+ case HH_NONE :
+ break;
+ case HH_BEFORE :
+ if ((nh->h_hint == HH_BEFORE) &&
+ (strcmp((char *)h->h_hintvalue,
+ (char *)nh->h_hintvalue) == 0)) {
+ TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
+ return (0);
+ }
+ if ((nh->h_hint == HH_AFTER) &&
+ (strcmp((char *)h->h_hintvalue,
+ (char *)nh->h_hintvalue) == 0)) {
+ TAILQ_INSERT_BEFORE(hi, new, hi_entry);
+ return (0);
+ }
+ break;
+ case HH_AFTER :
+ if ((nh->h_hint == HH_AFTER) &&
+ (strcmp((char *)h->h_hintvalue,
+ (char *)nh->h_hintvalue) == 0)) {
+ TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
+ return (0);
+ }
+ if ((nh->h_hint == HH_BEFORE) &&
+ (strcmp((char *)h->h_hintvalue,
+ (char *)nh->h_hintvalue) == 0)) {
+ TAILQ_INSERT_BEFORE(hi, new, hi_entry);
+ return (0);
+ }
+ break;
+ }
+ }
+
+ hook_insert_plain(head, new);
+
+ return (0);
+}
/*
* Function: hook_unregister
@@ -646,19 +1734,18 @@ hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
int
hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
{
- hook_stack_t *hks;
hook_event_int_t *hei;
hook_int_t *hi;
+ boolean_t free_event;
ASSERT(hfi != NULL);
ASSERT(h != NULL);
- hks = (hook_stack_t *)hfi->hfi_ptr;
- CVW_ENTER_READ(&hks->hks_familylock);
+ CVW_ENTER_WRITE(&hfi->hfi_lock);
hei = hook_event_find(hfi, event);
if (hei == NULL) {
- CVW_EXIT_READ(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
return (ENXIO);
}
@@ -668,23 +1755,72 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
hi = hook_find(hei, h);
if (hi == NULL) {
CVW_EXIT_WRITE(&hei->hei_lock);
- CVW_EXIT_READ(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
return (ENXIO);
}
+ if (hook_wait_setflag(&hei->hei_waiter, FWF_WAIT_MASK,
+ FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
+ CVW_EXIT_WRITE(&hei->hei_lock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ return (ENOENT);
+ }
+
/* Remove from hook list */
TAILQ_REMOVE(&hei->hei_head, hi, hi_entry);
+
+ free_event = B_FALSE;
if (TAILQ_EMPTY(&hei->hei_head)) {
hei->hei_event->he_interested = B_FALSE;
+ /*
+ * If the delete pending flag has been set and there are
+ * no notifiers on the event (and we've removed the last
+ * hook) then we need to free this event after we're done.
+ */
+ if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead))
+ free_event = B_TRUE;
}
+ hei->hei_kstats.hooks_removed.value.ui64++;
CVW_EXIT_WRITE(&hei->hei_lock);
- CVW_EXIT_READ(&hks->hks_familylock);
+ CVW_EXIT_WRITE(&hfi->hfi_lock);
+ /*
+ * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t
+ * will not be free'd and thus the hook_family_int_t wil not
+ * be free'd either.
+ */
+ hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER);
+ hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
+
+ hook_int_free(hi, hfi->hfi_stack->hks_netstackid);
+
+ if (free_event)
+ hook_event_free(hei, hfi);
- hook_free(hi);
return (0);
}
+/*
+ * Function: hook_find_byname
+ * Returns: internal hook pointer - NULL = Not match
+ * Parameters: hei(I) - internal event pointer
+ * name(I)- hook name
+ *
+ * Search an event's list of hooks to see if there is a hook present that
+ * has a matching name to the one being looked for.
+ */
+static hook_int_t *
+hook_find_byname(hook_int_head_t *head, char *name)
+{
+ hook_int_t *hi;
+
+ TAILQ_FOREACH(hi, head, hi_entry) {
+ if (strcmp(hi->hi_hook.h_name, name) == 0)
+ return (hi);
+ }
+
+ return (NULL);
+}
/*
* Function: hook_find
@@ -692,25 +1828,20 @@ hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
* Parameters: hei(I) - internal event pointer
* h(I) - hook pointer
*
- * Search hook list
- * A lock on familylock must be held when called.
+ * Search an event's list of hooks to see if there is already one that
+ * matches the hook being passed in. Currently the only criteria for a
+ * successful search here is for the names to be the same.
*/
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);
+ return (hook_find_byname(&hei->hei_head, h->h_name));
}
-
/*
* Function: hook_copy
* Returns: internal hook pointer - NULL = Failed
@@ -718,12 +1849,17 @@ hook_find(hook_event_int_t *hei, hook_t *h)
*
* Allocate internal hook block and duplicate incoming hook.
* No locks should be held across this function as it may sleep.
+ * Because hook_copy() is responsible for the creation of the internal
+ * hook structure that is used here, it takes on population the structure
+ * with the kstat information. Note that while the kstat bits are
+ * seeded here, their installation of the kstats is handled elsewhere.
*/
static hook_int_t *
hook_copy(hook_t *src)
{
hook_int_t *new;
hook_t *dst;
+ int len;
ASSERT(src != NULL);
ASSERT(src->h_name != NULL);
@@ -735,29 +1871,278 @@ hook_copy(hook_t *src)
*dst = *src;
/* Copy name */
- dst->h_name = (char *)kmem_alloc(strlen(src->h_name) + 1, KM_SLEEP);
+ len = strlen(src->h_name);
+ dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP);
(void) strcpy(dst->h_name, src->h_name);
+ /*
+ * This is initialised in this manner to make it safer to use the
+ * same pointer in the kstats field.
+ */
+ dst->h_hintvalue = (uintptr_t)"";
+
+ if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) {
+ len = strlen((char *)src->h_hintvalue);
+ if (len > 0) {
+ dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1,
+ KM_SLEEP);
+ (void) strcpy((char *)dst->h_hintvalue,
+ (char *)src->h_hintvalue);
+ }
+ }
+
return (new);
}
/*
- * Function: hook_free
+ * Function: hook_init_kstats
+ * Returns: None
+ * Parameters: hfi(I) - pointer to the family that owns the event.
+ * hei(I) - pointer to the event that owns this hook
+ * hi(I) - pointer to the hook for which we create kstats for
+ *
+ * Each hook that is registered with this framework has its own kstats
+ * set up so that we can provide an easy way in which to observe the
+ * look of hooks (using the kstat command.) The position is set to 0
+ * here but is recalculated after we know the insertion has been a
+ * success.
+ */
+static void
+hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi)
+{
+ hook_hook_kstat_t template = {
+ { "version", KSTAT_DATA_INT32 },
+ { "flags", KSTAT_DATA_UINT32 },
+ { "hint", KSTAT_DATA_INT32 },
+ { "hint_value", KSTAT_DATA_UINT64 },
+ { "position", KSTAT_DATA_INT32 },
+ { "hook_hits", KSTAT_DATA_UINT64 }
+ };
+ hook_stack_t *hks;
+ size_t kslen;
+ int position;
+ hook_int_t *h;
+
+ kslen = strlen(hfi->hfi_family.hf_name) +
+ strlen(hei->hei_event->he_name) + 2;
+
+ hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP);
+ (void) snprintf(hi->hi_ksname, kslen, "%s/%s",
+ hfi->hfi_family.hf_name, hei->hei_event->he_name);
+
+ hks = hfi->hfi_stack;
+ hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0,
+ hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED,
+ sizeof (hi->hi_kstats) / sizeof (kstat_named_t),
+ KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
+
+ /* Initialise the kstats for the structure */
+ bcopy(&template, &hi->hi_kstats, sizeof (template));
+ hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version;
+ hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags;
+ hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint;
+ hi->hi_kstats.hook_position.value.i32 = 0;
+ hi->hi_kstats.hook_hits.value.ui64 = 0;
+
+ switch (hi->hi_hook.h_hint) {
+ case HH_BEFORE :
+ case HH_AFTER :
+ hi->hi_kstats.hook_hintvalue.data_type = KSTAT_DATA_STRING;
+ hi->hi_kstats.hook_hintvalue.value.ui64 =
+ hi->hi_hook.h_hintvalue;
+ break;
+ default :
+ break;
+ }
+
+ if (hi->hi_kstatp != NULL) {
+ hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats;
+ hi->hi_kstatp->ks_private =
+ (void *)(uintptr_t)hks->hks_netstackid;
+
+ kstat_install(hi->hi_kstatp);
+ }
+
+ position = 1;
+ TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
+ h->hi_kstats.hook_position.value.ui32 = position++;
+ }
+}
+
+/*
+ * Function: hook_int_free
* Returns: None
* Parameters: hi(I) - internal hook pointer
*
* Free alloc memory for hook
*/
static void
-hook_free(hook_int_t *hi)
+hook_int_free(hook_int_t *hi, netstackid_t stackid)
{
+ int len;
+
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);
}
+ if (hi->hi_ksname != NULL) {
+ kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1);
+ }
+
+ /* Free the name used with the before/after hints. */
+ switch (hi->hi_hook.h_hint) {
+ case HH_BEFORE :
+ case HH_AFTER :
+ len = strlen((char *)hi->hi_hook.h_hintvalue);
+ if (len > 0)
+ kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1);
+ break;
+ default :
+ break;
+ }
+
+ if (hi->hi_kstatp != NULL)
+ kstat_delete_netstack(hi->hi_kstatp, stackid);
/* Free container */
kmem_free(hi, sizeof (*hi));
}
+
+/*
+ * Function: hook_alloc
+ * Returns: hook_t * - pointer to new hook structure
+ * Parameters: version(I) - version number of the API when compiled
+ *
+ * This function serves as the interface for consumers to obtain a hook_t
+ * structure. At this point in time, there is only a single "version" of
+ * it, leading to a straight forward function. In a perfect world the
+ * h_vesion would be a protected data structure member, but C isn't that
+ * advanced...
+ */
+hook_t *
+hook_alloc(const int h_version)
+{
+ hook_t *h;
+
+ h = kmem_zalloc(sizeof (hook_t), KM_SLEEP);
+ h->h_version = h_version;
+ return (h);
+}
+
+/*
+ * Function: hook_free
+ * Returns: None
+ * Parameters: h(I) - external hook pointer
+ *
+ * This function only free's memory allocated with hook_alloc(), so that if
+ * (for example) kernel memory was allocated for h_name, this needs to be
+ * free'd before calling hook_free().
+ */
+void
+hook_free(hook_t *h)
+{
+ kmem_free(h, sizeof (*h));
+}
+
+/*
+ * Function: hook_notify_register
+ * Returns: 0 = success, else failure
+ * Parameters: lock(I) - netstack identifier
+ * head(I) - top of the list of callbacks
+ * callback(I) - function to be called
+ * arg(I) - arg to pass back to the function
+ *
+ * This function implements the modification of the list of callbacks
+ * that are registered when someone wants to be advised of a change
+ * that has happened.
+ */
+static int
+hook_notify_register(cvwaitlock_t *lock, hook_notify_head_t *head,
+ hook_notify_fn_t callback, void *arg)
+{
+ hook_notify_t *hn;
+
+ CVW_ENTER_WRITE(lock);
+
+ TAILQ_FOREACH(hn, head, hn_entry) {
+ if (hn->hn_func == callback) {
+ CVW_EXIT_WRITE(lock);
+ return (EEXIST);
+ }
+ }
+
+ hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP);
+ hn->hn_func = callback;
+ hn->hn_arg = arg;
+ TAILQ_INSERT_TAIL(head, hn, hn_entry);
+
+ CVW_EXIT_WRITE(lock);
+
+ return (0);
+}
+
+/*
+ * Function: hook_stack_notify_register
+ * Returns: 0 = success, else failure
+ * Parameters: stackid(I) - netstack identifier
+ * callback(I) - function to be called
+ *
+ */
+static int
+hook_notify_unregister(cvwaitlock_t *lock, hook_notify_head_t *head,
+ hook_notify_fn_t callback)
+{
+ hook_notify_t *hn;
+
+ CVW_ENTER_WRITE(lock);
+
+ TAILQ_FOREACH(hn, head, hn_entry) {
+ if (hn->hn_func == callback)
+ break;
+ }
+ if (hn == NULL) {
+ CVW_EXIT_WRITE(lock);
+ return (ESRCH);
+ }
+
+ TAILQ_REMOVE(head, hn, hn_entry);
+
+ CVW_EXIT_WRITE(lock);
+
+ kmem_free(hn, sizeof (*hn));
+
+ return (0);
+}
+
+/*
+ * Function: hook_notify_run
+ * Returns: None
+ * Parameters: head(I) - top of the list of callbacks
+ * family(I) - name of the hook family that owns the event
+ * event(I) - name of the event being changed
+ * name(I) - name of the object causing change
+ * cmd(I) - either HN_UNREGISTER or HN_REGISTER
+ *
+ * This function walks through the list of registered callbacks and
+ * executes each one, passing back the arg supplied when registered
+ * and the name of the family (that owns the event), event (the thing
+ * to which we're making a change) and finally a name that describes
+ * what is being added or removed, as indicated by cmd.
+ *
+ * This function does not acquire or release any lock as it is required
+ * that code calling it do so before hand. The use of hook_notify_head_t
+ * is protected by the use of flagwait_t in the structures that own this
+ * list and with the use of the FWF_ADD/DEL_ACTIVE flags.
+ */
+static void
+hook_notify_run(hook_notify_head_t *head, char *family, char *event,
+ char *name, hook_notify_cmd_t cmd)
+{
+ hook_notify_t *hn;
+
+ TAILQ_FOREACH(hn, head, hn_entry) {
+ (*hn->hn_func)(cmd, hn->hn_arg, family, event, name);
+ }
+}
diff --git a/usr/src/uts/common/io/neti.c b/usr/src/uts/common/io/neti.c
deleted file mode 100644
index 49a17ee91f..0000000000
--- a/usr/src/uts/common/io/neti.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/*
- * 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 2007 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 void net_init();
-static void net_fini();
-static net_data_t net_find(const char *protocol, neti_stack_t *ns);
-static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
-static void neti_stack_fini(netstackid_t stackid, void *arg);
-
-/*
- * 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)
-{
- int error;
-
- net_init();
- error = mod_install(&modlinkage);
- if (error != 0)
- net_fini();
-
- return (error);
-}
-
-
-int
-_fini(void)
-{
- int error;
-
- error = mod_remove(&modlinkage);
- if (error == 0)
- net_fini();
-
- return (error);
-}
-
-
-int
-_info(struct modinfo *modinfop)
-{
-
- return (mod_info(&modlinkage, modinfop));
-}
-
-
-static void
-net_init()
-{
- /*
- * We want to be informed each time a stack is created or
- * destroyed in the kernel.
- */
- netstack_register(NS_NETI, neti_stack_init, NULL,
- neti_stack_fini);
-}
-
-static void
-net_fini()
-{
- netstack_unregister(NS_NETI);
-}
-
-
-/*
- * Initialize the neti stack instance.
- */
-/*ARGSUSED*/
-static void *
-neti_stack_init(netstackid_t stackid, netstack_t *ns)
-{
- neti_stack_t *nts;
-
-#ifdef NS_DEBUG
- printf("neti_stack_init(stack %d)\n", stackid);
-#endif
-
- nts = (neti_stack_t *)kmem_zalloc(sizeof (*nts), KM_SLEEP);
- nts->nts_netstack = ns;
-
- rw_init(&nts->nts_netlock, NULL, RW_DRIVER, NULL);
- LIST_INIT(&nts->nts_netd_head);
-
- return (nts);
-}
-
-
-/*
- * Free the neti stack instance.
- */
-/*ARGSUSED*/
-static void
-neti_stack_fini(netstackid_t stackid, void *arg)
-{
- neti_stack_t *nts = (neti_stack_t *)arg;
-#ifdef NS_DEBUG
- printf("neti_stack_fini(%p, stack %d)\n", arg, stackid);
-#endif
- rw_destroy(&nts->nts_netlock);
- kmem_free(nts, sizeof (*nts));
-}
-
-
-static net_data_t
-net_find(const char *protocol, neti_stack_t *nts)
-{
- struct net_data *n;
-
- ASSERT(protocol != NULL);
-
- LIST_FOREACH(n, &nts->nts_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, netstackid_t nsid)
-{
- netstack_t *ns;
- net_data_t nd;
-
- ns = netstack_find_by_stackid(nsid);
- nd = net_register_impl(info, ns);
- netstack_rele(ns);
-
- return (nd);
-}
-
-net_data_t
-net_register_impl(const net_info_t *info, netstack_t *ns)
-{
- struct net_data *n, *new;
- struct neti_stack *nts;
-
- ASSERT(info != NULL);
- ASSERT(ns != NULL);
-
- nts = ns->netstack_neti;
-
- new = kmem_alloc(sizeof (*new), KM_SLEEP);
- new->netd_refcnt = 0;
- new->netd_hooks = NULL;
- new->netd_info = *info;
- new->netd_netstack = ns;
-
- rw_enter(&nts->nts_netlock, RW_WRITER);
- n = net_find(info->neti_protocol, nts);
- if (n != NULL) {
- rw_exit(&nts->nts_netlock);
- kmem_free(new, sizeof (*new));
- return (NULL);
- }
-
- if (LIST_EMPTY(&nts->nts_netd_head))
- LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list);
- else
- LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head),
- new, netd_list);
-
- rw_exit(&nts->nts_netlock);
- return (new);
-}
-
-
-int
-net_unregister(net_data_t info)
-{
- struct netstack *ns;
- struct neti_stack *nts;
- ns = info->netd_netstack;
- nts = ns->netstack_neti;
-
- ASSERT(info != NULL);
-
- rw_enter(&nts->nts_netlock, RW_WRITER);
- if (info->netd_refcnt != 0) {
- rw_exit(&nts->nts_netlock);
- return (EBUSY);
- }
-
- LIST_REMOVE(info, netd_list);
-
- rw_exit(&nts->nts_netlock);
-
- kmem_free(info, sizeof (struct net_data));
- return (0);
-}
-
-net_data_t
-net_lookup(const char *protocol, netstackid_t nsid)
-{
- netstack_t *ns;
- net_data_t nd;
-
- ns = netstack_find_by_stackid(nsid);
- nd = net_lookup_impl(protocol, ns);
- netstack_rele(ns);
-
- return (nd);
-}
-
-net_data_t
-net_lookup_impl(const char *protocol, netstack_t *ns)
-{
- struct net_data *n;
- struct neti_stack *nts;
-
- ASSERT(protocol != NULL);
- ASSERT(ns != NULL);
-
- nts = ns->netstack_neti;
-
- rw_enter(&nts->nts_netlock, RW_READER);
- n = net_find(protocol, nts);
- if (n != NULL)
- atomic_add_32((uint_t *)&n->netd_refcnt, 1);
- rw_exit(&nts->nts_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)
-{
- struct netstack *ns;
- struct neti_stack *nts;
-
- ns = info->netd_netstack;
- nts = ns->netstack_neti;
-
- ASSERT(info != NULL);
-
- rw_enter(&nts->nts_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(&nts->nts_netlock);
- return (1);
- }
- rw_exit(&nts->nts_netlock);
-
- return (0);
-}
-
-net_data_t
-net_walk(net_data_t info, netstackid_t nsid)
-{
- netstack_t *ns;
- net_data_t nd;
-
- ns = netstack_find_by_stackid(nsid);
- nd = net_walk_impl(info, ns);
- netstack_rele(ns);
-
- return (nd);
-}
-
-net_data_t
-net_walk_impl(net_data_t info, netstack_t *ns)
-{
- struct net_data *n = NULL;
- boolean_t found = B_FALSE;
- struct neti_stack *nts;
-
- ASSERT(ns != NULL);
-
- nts = ns->netstack_neti;
-
- if (info == NULL)
- found = B_TRUE;
-
- rw_enter(&nts->nts_netlock, RW_READER);
- LIST_FOREACH(n, &nts->nts_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(&nts->nts_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,
- info->netd_netstack));
-}
-
-
-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,
- info->netd_netstack));
-}
-
-
-int
-net_getpmtuenabled(net_data_t info)
-{
-
- ASSERT(info != NULL);
-
- return (info->netd_info.neti_getpmtuenabled(info->netd_netstack));
-}
-
-
-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, info->netd_netstack));
-}
-
-
-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,
- info->netd_netstack));
-}
-
-
-phy_if_t
-net_phylookup(net_data_t info, const char *name)
-{
-
- ASSERT(info != NULL);
-
- return (info->netd_info.neti_phylookup(name, info->netd_netstack));
-}
-
-
-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,
- info->netd_netstack));
-}
-
-
-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,
- info->netd_netstack));
-}
-
-
-phy_if_t
-net_routeto(net_data_t info, struct sockaddr *address)
-{
-
- ASSERT(info != NULL);
-
- return (info->netd_info.neti_routeto(address, info->netd_netstack));
-}
-
-
-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, info->netd_netstack->netstack_hook);
- 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/neti_impl.c b/usr/src/uts/common/io/neti_impl.c
new file mode 100644
index 0000000000..346e49903d
--- /dev/null
+++ b/usr/src/uts/common/io/neti_impl.c
@@ -0,0 +1,621 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#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/neti.h>
+#include <sys/zone.h>
+
+static net_handle_t net_find(const char *protocol, neti_stack_t *ns);
+
+static net_handle_t
+net_find(const char *protocol, neti_stack_t *nts)
+{
+ struct net_data *n;
+
+ ASSERT(protocol != NULL);
+ ASSERT(nts != NULL);
+
+ LIST_FOREACH(n, &nts->nts_netd_head, netd_list) {
+ ASSERT(n->netd_info.netp_name != NULL);
+ /*
+ * If they're trying to find a protocol that is being
+ * shutdown, just ignore it..
+ */
+ if (n->netd_condemned != 0)
+ continue;
+ if (strcmp(n->netd_info.netp_name, protocol) == 0) {
+ break;
+ }
+ }
+
+ return (n);
+}
+
+net_handle_t
+net_protocol_register(netid_t id, const net_protocol_t *info)
+{
+ struct net_data *n, *new;
+ neti_stack_t *nts;
+
+ ASSERT(info != NULL);
+
+ nts = net_getnetistackbyid(id);
+ if (nts == NULL)
+ return (NULL);
+
+ new = kmem_alloc(sizeof (*new), KM_SLEEP);
+ new->netd_refcnt = 1;
+ new->netd_hooks = NULL;
+ new->netd_info = *info;
+ new->netd_stack = nts;
+ new->netd_condemned = 0;
+
+ mutex_enter(&nts->nts_lock);
+ n = net_find(info->netp_name, nts);
+ if (n != NULL) {
+ mutex_exit(&nts->nts_lock);
+ kmem_free(new, sizeof (*new));
+ return (NULL);
+ }
+
+ if (LIST_EMPTY(&nts->nts_netd_head)) {
+ LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list);
+ } else {
+ LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head),
+ new, netd_list);
+ }
+ mutex_exit(&nts->nts_lock);
+
+ return (new);
+}
+
+int
+net_protocol_unregister(net_handle_t info)
+{
+ neti_stack_t *nts;
+
+ ASSERT(info != NULL);
+
+ nts = info->netd_stack;
+ ASSERT(nts != NULL);
+
+ mutex_enter(&nts->nts_lock);
+ LIST_REMOVE(info, netd_list);
+ info->netd_stack = NULL;
+ mutex_exit(&nts->nts_lock);
+
+ (void) net_protocol_release(info);
+
+ return (0);
+}
+
+net_handle_t
+net_protocol_lookup(netid_t netid, const char *protocol)
+{
+ neti_stack_t *nts;
+ net_handle_t nd;
+
+ ASSERT(protocol != NULL);
+
+ nts = net_getnetistackbyid(netid);
+ if (nts == NULL)
+ return (NULL);
+
+ mutex_enter(&nts->nts_lock);
+ nd = net_find(protocol, nts);
+ if (nd != NULL)
+ atomic_add_32((uint_t *)&nd->netd_refcnt, 1);
+ mutex_exit(&nts->nts_lock);
+ return (nd);
+}
+
+/*
+ * 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_handle_t passed in, so -1 is never a
+ * return value.
+ */
+int
+net_protocol_release(net_handle_t info)
+{
+
+ ASSERT(info->netd_refcnt > 0);
+ /*
+ * Is this safe? No hold on nts_lock? Consider that if the caller
+ * of net_protocol_release() is going to free this structure then
+ * it is now the only owner (refcnt==1) and it will have been
+ * removed from the nts_netd_head list on the neti_stack_t from a
+ * call to net_protocol_unregister already, so it is thus an orphan.
+ */
+ if (atomic_add_32_nv((uint_t *)&info->netd_refcnt, -1) == 0) {
+ ASSERT(info->netd_hooks == NULL);
+ ASSERT(info->netd_stack == NULL);
+ kmem_free(info, sizeof (struct net_data));
+ }
+
+ return (0);
+}
+
+net_handle_t
+net_protocol_walk(netid_t netid, net_handle_t info)
+{
+ struct net_data *n = NULL;
+ boolean_t found = B_FALSE;
+ neti_stack_t *nts;
+
+ nts = net_getnetistackbyid(netid);
+ ASSERT(nts != NULL);
+
+ if (info == NULL)
+ found = B_TRUE;
+
+ mutex_enter(&nts->nts_lock);
+ LIST_FOREACH(n, &nts->nts_netd_head, netd_list) {
+ if (found) {
+ /*
+ * We are only interested in finding protocols that
+ * are not in some sort of shutdown state. There is
+ * no need to check for netd_stack==NULL because
+ * that implies it is no longer on this list.
+ */
+ if (n->netd_condemned == 0)
+ continue;
+ break;
+ }
+
+ if (n == info)
+ found = B_TRUE;
+ }
+
+ if (info != NULL)
+ (void) net_protocol_release(info);
+
+ if (n != NULL)
+ atomic_add_32((uint_t *)&n->netd_refcnt, 1);
+
+ mutex_exit(&nts->nts_lock);
+
+ return (n);
+}
+
+/*
+ * Public accessor functions
+ */
+int
+net_getifname(net_handle_t info, phy_if_t nic, char *buffer,
+ const size_t buflen)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_getifname(info, nic, buffer, buflen));
+}
+
+int
+net_getmtu(net_handle_t info, phy_if_t nic, lif_if_t ifdata)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_getmtu(info, nic, ifdata));
+}
+
+int
+net_getpmtuenabled(net_handle_t info)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_getpmtuenabled(info));
+}
+
+int
+net_getlifaddr(net_handle_t info, phy_if_t nic, lif_if_t ifdata,
+ int nelem, net_ifaddr_t type[], void *storage)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_getlifaddr(info, nic, ifdata,
+ nelem, type, storage));
+}
+
+phy_if_t
+net_phygetnext(net_handle_t info, phy_if_t nic)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return ((phy_if_t)-1);
+
+ return (info->netd_info.netp_phygetnext(info, nic));
+}
+
+phy_if_t
+net_phylookup(net_handle_t info, const char *name)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return ((phy_if_t)-1);
+
+ return (info->netd_info.netp_phylookup(info, name));
+}
+
+lif_if_t
+net_lifgetnext(net_handle_t info, phy_if_t ifidx, lif_if_t ifdata)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return ((lif_if_t)-1);
+
+ return (info->netd_info.netp_lifgetnext(info, ifidx, ifdata));
+}
+
+int
+net_inject(net_handle_t info, inject_t style, net_inject_t *packet)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_inject(info, style, packet));
+}
+
+phy_if_t
+net_routeto(net_handle_t info, struct sockaddr *address, struct sockaddr *next)
+{
+
+ ASSERT(info != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return ((phy_if_t)-1);
+
+ return (info->netd_info.netp_routeto(info, address, next));
+}
+
+int
+net_ispartialchecksum(net_handle_t info, mblk_t *mp)
+{
+
+ ASSERT(info != NULL);
+ ASSERT(mp != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_ispartialchecksum(info, mp));
+}
+
+int
+net_isvalidchecksum(net_handle_t info, mblk_t *mp)
+{
+
+ ASSERT(info != NULL);
+ ASSERT(mp != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (-1);
+
+ return (info->netd_info.netp_isvalidchecksum(info, mp));
+}
+
+/*
+ * Hooks related functions
+ */
+
+/*
+ * Function: net_family_register
+ * Returns: int - 0 = Succ, Else = Fail
+ * Parameters: info(I) - protocol
+ * hf(I) - family pointer
+ *
+ * Call hook_family_add to register family
+ *
+ * There is no need to bump netd_refcnt in the two functions
+ * net_family_register and net_family_unregister because the caller of these
+ * two functions is assumed to "own" a reference on 'info' via an earlier
+ * call to net_protocol_register(). Thus the owner is expected to do a
+ * call to net_protocol_unregister() after having done a
+ * net_family_unregister() to make sure things are properly cleaned up.
+ */
+int
+net_family_register(net_handle_t info, hook_family_t *hf)
+{
+ hook_family_int_t *hfi;
+ netstack_t *ns;
+
+ ASSERT(info != NULL);
+ ASSERT(hf != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (ESHUTDOWN);
+
+ if (info->netd_hooks != NULL)
+ return (EEXIST);
+
+ ns = info->netd_stack->nts_netstack;
+ ASSERT(ns != NULL);
+ hfi = hook_family_add(hf, ns->netstack_hook);
+ if (hfi == NULL)
+ return (EEXIST);
+
+ info->netd_hooks = hfi;
+ return (0);
+}
+
+/*
+ * Function: net_family_unregister
+ * Returns: int - transparent value, explained by caller
+ * Parameters: info(I) - protocol
+ * hf(I) - family pointer
+ *
+ * Call hook_family_remove to unregister family
+ */
+int
+net_family_unregister(net_handle_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_event_register
+ * 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_event_register(net_handle_t info, hook_event_t *he)
+{
+ hook_event_int_t *hei;
+
+ ASSERT(info != NULL);
+ ASSERT(he != NULL);
+
+ if (info->netd_hooks == NULL || info->netd_condemned != 0 ||
+ info->netd_stack == NULL)
+ return (NULL);
+
+ hei = hook_event_add(info->netd_hooks, he);
+ return ((hook_event_token_t)hei);
+}
+
+/*
+ * Function: net_event_unregister
+ * 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_event_unregister(net_handle_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_hook_register
+ * 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_hook_register(net_handle_t info, char *event, hook_t *h)
+{
+
+ ASSERT(info != NULL);
+ ASSERT(event != NULL);
+ ASSERT(h != NULL);
+
+ if (info->netd_condemned != 0 || info->netd_stack == NULL)
+ return (ESHUTDOWN);
+
+ if (info->netd_hooks == NULL)
+ return (ENXIO);
+
+ return (hook_register(info->netd_hooks, event, h));
+}
+
+/*
+ * Function: net_hook_unregister
+ * 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_hook_unregister(net_handle_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));
+}
+
+netid_t
+net_getnetid(net_handle_t netd)
+{
+
+ if (netd->netd_stack == NULL)
+ return (-1);
+ return (netd->netd_stack->nts_id);
+}
+
+net_inject_t *
+net_inject_alloc(const int version)
+{
+ net_inject_t *ni;
+
+ ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP);
+ if (ni == NULL)
+ return (NULL);
+
+ ni->ni_version = version;
+ return (ni);
+}
+
+void
+net_inject_free(net_inject_t *ni)
+{
+ kmem_free(ni, sizeof (*ni));
+}
+
+kstat_t *
+net_kstat_create(netid_t netid, char *module, int instance, char *name,
+ char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag)
+{
+ netstackid_t stackid = net_getnetstackidbynetid(netid);
+
+ if (stackid == -1)
+ return (NULL);
+
+ return (kstat_create_netstack(module, instance, name, class, type,
+ ndata, ks_flag, stackid));
+}
+
+void
+net_kstat_delete(netid_t netid, kstat_t *ks)
+{
+ netstackid_t stackid = net_getnetstackidbynetid(netid);
+
+ if (stackid != -1)
+ kstat_delete_netstack(ks, stackid);
+}
+
+int
+net_event_notify_register(net_handle_t family, char *event,
+ hook_notify_fn_t callback, void *arg)
+{
+ int error;
+
+ if (family->netd_condemned != 0 || family->netd_stack == NULL)
+ return (ESHUTDOWN);
+
+ error = hook_event_notify_register(family->netd_hooks, event,
+ callback, arg);
+
+ return (error);
+}
+
+int
+net_event_notify_unregister(net_handle_t family, char *event,
+ hook_notify_fn_t callback)
+{
+ int error;
+
+ error = hook_event_notify_unregister(family->netd_hooks, event,
+ callback);
+
+ return (error);
+}
+
+int
+net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback,
+ void *arg)
+{
+ int error;
+
+ if (family->netd_condemned != 0 || family->netd_stack == NULL)
+ return (ESHUTDOWN);
+
+ error = hook_family_notify_register(family->netd_hooks, callback,
+ arg);
+
+ return (error);
+}
+
+int
+net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback)
+{
+ int error;
+
+ error = hook_family_notify_unregister(family->netd_hooks, callback);
+
+ return (error);
+}
diff --git a/usr/src/uts/common/io/neti_mod.c b/usr/src/uts/common/io/neti_mod.c
new file mode 100644
index 0000000000..ad0bcbc2e4
--- /dev/null
+++ b/usr/src/uts/common/io/neti_mod.c
@@ -0,0 +1,80 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/param.h>
+#include <sys/modctl.h>
+#include <sys/neti.h>
+
+
+/*
+ * Module linkage information for the kernel.
+ */
+static struct modldrv modlmisc = {
+ &mod_miscops, /* drv_modops */
+ "netinfo module", /* drv_linkinfo */
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1, /* ml_rev */
+ &modlmisc, /* ml_linkage */
+ NULL
+};
+
+/*
+ * Module entry points.
+ */
+int
+_init(void)
+{
+ int error;
+
+ neti_init();
+ error = mod_install(&modlinkage);
+ if (error != 0)
+ neti_fini();
+
+ return (error);
+}
+
+
+int
+_fini(void)
+{
+ int error;
+
+ error = mod_remove(&modlinkage);
+ if (error == 0)
+ neti_fini();
+
+ return (error);
+}
+
+
+int
+_info(struct modinfo *modinfop)
+{
+
+ return (mod_info(&modlinkage, modinfop));
+}
diff --git a/usr/src/uts/common/io/neti_stack.c b/usr/src/uts/common/io/neti_stack.c
new file mode 100644
index 0000000000..1428638b7b
--- /dev/null
+++ b/usr/src/uts/common/io/neti_stack.c
@@ -0,0 +1,840 @@
+/*
+ * 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 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#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 <sys/sunddi.h>
+#include <inet/common.h>
+#include <inet/led.h>
+#include <inet/ip.h>
+#include <sys/neti.h>
+#include <sys/zone.h>
+#include <sys/sdt.h>
+
+
+typedef boolean_t napplyfn_t(kmutex_t *, neti_stack_t *, void *);
+
+static void *neti_stack_init(netstackid_t stackid, netstack_t *ns);
+static void neti_stack_fini(netstackid_t stackid, void *arg);
+static net_instance_int_t *net_instance_int_create(net_instance_t *nin,
+ net_instance_int_t *parent);
+static void neti_stack_shutdown(netstackid_t stackid, void *arg);
+static void net_instance_int_free(net_instance_int_t *nini);
+
+static boolean_t neti_stack_apply_create(kmutex_t *, neti_stack_t *, void *);
+static boolean_t neti_stack_apply_destroy(kmutex_t *, neti_stack_t *, void *);
+static boolean_t neti_stack_apply_shutdown(kmutex_t *, neti_stack_t *, void *);
+static void neti_apply_all_instances(neti_stack_t *, napplyfn_t *);
+static void neti_apply_all_stacks(void *, napplyfn_t *);
+static boolean_t wait_for_nini_inprogress(neti_stack_t *, kmutex_t *,
+ net_instance_int_t *, uint32_t);
+
+static nini_head_t neti_instance_list;
+static neti_stack_head_t neti_stack_list;
+static kmutex_t neti_stack_lock;
+
+void
+neti_init()
+{
+ mutex_init(&neti_stack_lock, NULL, MUTEX_DRIVER, NULL);
+
+ LIST_INIT(&neti_instance_list);
+ LIST_INIT(&neti_stack_list);
+ /*
+ * We want to be informed each time a netstack is created or
+ * destroyed in the kernel.
+ */
+ netstack_register(NS_NETI, neti_stack_init, neti_stack_shutdown,
+ neti_stack_fini);
+}
+
+void
+neti_fini()
+{
+ ASSERT(LIST_EMPTY(&neti_instance_list));
+ ASSERT(LIST_EMPTY(&neti_stack_list));
+
+ netstack_unregister(NS_NETI);
+
+ mutex_destroy(&neti_stack_lock);
+}
+
+/*
+ * Initialize the neti stack instance. Because this is called out of the
+ * netstack framework, it is not possible for it to be called twice with
+ * the same values for (stackid,ns). The same also applies to the other
+ * two functions used with netstack_register: neti_stack_shutdown and
+ * neti_stack_fini.
+ */
+static void *
+neti_stack_init(netstackid_t stackid, netstack_t *ns)
+{
+ net_instance_int_t *dup;
+ net_instance_int_t *n;
+ neti_stack_t *nts;
+
+ nts = kmem_zalloc(sizeof (*nts), KM_SLEEP);
+ LIST_INIT(&nts->nts_instances);
+ nts->nts_id = (netid_t)stackid;
+ nts->nts_stackid = stackid;
+ nts->nts_netstack = ns;
+ nts->nts_zoneid = netstackid_to_zoneid(stackid);
+ nts->nts_flags = NSF_ZONE_CREATE;
+ cv_init(&nts->nts_cv, NULL, CV_DRIVER, NULL);
+ mutex_init(&nts->nts_lock, NULL, MUTEX_DRIVER, NULL);
+
+ mutex_enter(&neti_stack_lock);
+ LIST_INSERT_HEAD(&neti_stack_list, nts, nts_next);
+
+ LIST_FOREACH(n, &neti_instance_list, nini_next) {
+ /*
+ * This function returns with the NSS_CREATE_NEEDED flag
+ * set in "dup", so it is adequately prepared for the
+ * upcoming apply.
+ */
+ dup = net_instance_int_create(n->nini_instance, n);
+
+ mutex_enter(&nts->nts_lock);
+ LIST_INSERT_HEAD(&nts->nts_instances, dup, nini_next);
+ mutex_exit(&nts->nts_lock);
+ }
+
+ neti_apply_all_instances(nts, neti_stack_apply_create);
+
+ mutex_enter(&nts->nts_lock);
+ nts->nts_flags &= ~NSF_ZONE_CREATE;
+ cv_signal(&nts->nts_cv);
+ mutex_exit(&nts->nts_lock);
+
+ mutex_exit(&neti_stack_lock);
+
+ return (nts);
+}
+
+/*
+ * Run the shutdown for all of the hooks.
+ */
+/*ARGSUSED*/
+static void
+neti_stack_shutdown(netstackid_t stackid, void *arg)
+{
+ neti_stack_t *nts = arg;
+ net_instance_int_t *n;
+ struct net_data *nd;
+
+ ASSERT(nts != NULL);
+
+ mutex_enter(&neti_stack_lock);
+ mutex_enter(&nts->nts_lock);
+ /*
+ * Walk through all of the protocol stacks and mark them as shutting
+ * down.
+ */
+ LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
+ nd->netd_condemned = 1;
+ }
+
+ /*
+ * Now proceed to see which callbacks are waiting to hear about the
+ * impending shutdown...
+ */
+ LIST_FOREACH(n, &nts->nts_instances, nini_next) {
+ if (n->nini_instance->nin_shutdown == NULL) {
+ /*
+ * If there is no shutdown function registered,
+ * fake that we have completed it.
+ */
+ n->nini_flags |= NSS_SHUTDOWN_COMPLETED;
+ continue;
+ }
+
+ /*
+ * We need to ensure that we don't try and shutdown something
+ * that is already in the process of being shutdown or
+ * destroyed. If it is still being created, that's ok, the
+ * shtudown flag is added to the mix of things to do.
+ */
+ if ((n->nini_flags & (NSS_DESTROY_ALL|NSS_SHUTDOWN_ALL)) == 0)
+ n->nini_flags |= NSS_SHUTDOWN_NEEDED;
+ }
+ nts->nts_flags |= NSF_ZONE_SHUTDOWN;
+ mutex_exit(&nts->nts_lock);
+
+ neti_apply_all_instances(nts, neti_stack_apply_shutdown);
+
+ mutex_enter(&nts->nts_lock);
+
+ nts->nts_netstack = NULL;
+ mutex_exit(&nts->nts_lock);
+
+ mutex_exit(&neti_stack_lock);
+ ASSERT(nts != NULL);
+}
+
+/*
+ * Free the neti stack instance.
+ * This function relies on the netstack framework only calling the _destroy
+ * callback once for each stackid. The netstack framework also provides us
+ * with assurance that nobody else will be doing any work (_create, _shutdown)
+ * on it, so there is no need to set and use flags to guard against
+ * simultaneous execution (ie. no need to set NSF_CLOSING.)
+ * What is required, however, is to make sure that we don't corrupt the
+ * list of neti_stack_t's for other code that walks it.
+ */
+/*ARGSUSED*/
+static void
+neti_stack_fini(netstackid_t stackid, void *arg)
+{
+ neti_stack_t *nts = arg;
+ net_instance_int_t *n;
+ struct net_data *nd;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_REMOVE(nts, nts_next);
+
+ mutex_enter(&nts->nts_lock);
+ nts->nts_flags |= NSF_ZONE_DESTROY;
+ /*
+ * Walk through all of the protocol stacks and mark them as being
+ * destroyed.
+ */
+ LIST_FOREACH(nd, &nts->nts_netd_head, netd_list) {
+ nd->netd_condemned = 2;
+ }
+
+ LIST_FOREACH(n, &nts->nts_instances, nini_next) {
+ ASSERT((n->nini_flags & NSS_SHUTDOWN_ALL) != 0);
+ if (n->nini_instance->nin_shutdown == NULL)
+ continue;
+ if ((n->nini_flags & NSS_DESTROY_ALL) == 0)
+ n->nini_flags |= NSS_DESTROY_NEEDED;
+ }
+ mutex_exit(&nts->nts_lock);
+
+ neti_apply_all_instances(nts, neti_stack_apply_destroy);
+ mutex_exit(&neti_stack_lock);
+
+ while (!LIST_EMPTY(&nts->nts_instances)) {
+ n = LIST_FIRST(&nts->nts_instances);
+ LIST_REMOVE(n, nini_next);
+
+ net_instance_int_free(n);
+ }
+
+ ASSERT(LIST_EMPTY(&nts->nts_netd_head));
+
+ mutex_destroy(&nts->nts_lock);
+ cv_destroy(&nts->nts_cv);
+
+ kmem_free(nts, sizeof (*nts));
+}
+
+static net_instance_int_t *
+net_instance_int_create(net_instance_t *nin, net_instance_int_t *parent)
+{
+ net_instance_int_t *nini;
+
+ nini = kmem_zalloc(sizeof (net_instance_int_t), KM_SLEEP);
+ nini->nini_instance = nin;
+ nini->nini_parent = parent;
+ if (parent != NULL) {
+ /*
+ * If the parent pointer is non-NULL then we take that as
+ * an indication that the net_instance_int_t is being
+ * created for an active instance and there will expect
+ * the create function to be called. In contrast, if
+ * parent is NULL then this code assumes the object is
+ * being prepared for insertion onto the master list of
+ * callbacks to be called when an instance is created, etc.
+ */
+ parent->nini_ref++;
+ nini->nini_flags |= NSS_CREATE_NEEDED;
+ }
+
+ cv_init(&nini->nini_cv, NULL, CV_DRIVER, NULL);
+
+ return (nini);
+}
+
+static void
+net_instance_int_free(net_instance_int_t *nini)
+{
+
+ cv_destroy(&nini->nini_cv);
+
+ if (nini->nini_parent != NULL)
+ nini->nini_parent->nini_ref--;
+
+ ASSERT(nini->nini_ref == 0);
+ kmem_free(nini, sizeof (*nini));
+}
+
+net_instance_t *
+net_instance_alloc(const int version)
+{
+ net_instance_t *nin;
+
+ if (version != NETINFO_VERSION)
+ return (NULL);
+
+ nin = kmem_zalloc(sizeof (net_instance_t), KM_SLEEP);
+ nin->nin_version = version;
+
+ return (nin);
+}
+
+void
+net_instance_free(net_instance_t *nin)
+{
+ kmem_free(nin, sizeof (*nin));
+}
+
+int
+net_instance_register(net_instance_t *nin)
+{
+ net_instance_int_t *parent;
+ net_instance_int_t *tmp;
+ neti_stack_t *nts;
+
+ ASSERT(nin->nin_name != NULL);
+
+ if (nin->nin_create == NULL || nin->nin_destroy == NULL)
+ return (DDI_FAILURE);
+
+ mutex_enter(&neti_stack_lock);
+ /*
+ * Search for duplicate, either on the global list or on any
+ * of the known instances.
+ */
+ LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
+ if (strcmp(nin->nin_name, tmp->nini_instance->nin_name) == 0) {
+ mutex_exit(&neti_stack_lock);
+ return (DDI_FAILURE);
+ }
+ }
+
+ /*
+ * Now insert and activate.
+ */
+ parent = net_instance_int_create(nin, NULL);
+ ASSERT(parent != NULL);
+ LIST_INSERT_HEAD(&neti_instance_list, parent, nini_next);
+
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ mutex_enter(&nts->nts_lock);
+ /*
+ * If shutdown of the zone has begun then do not add a new
+ * instance of the object being registered.
+ */
+ if ((nts->nts_flags & NSF_ZONE_SHUTDOWN) ||
+ (nts->nts_netstack == NULL)) {
+ mutex_exit(&nts->nts_lock);
+ continue;
+ }
+ /*
+ * This function returns with the NSS_CREATE_NEEDED flag
+ * set in "dup", so it is adequately prepared for the
+ * upcoming apply.
+ */
+ tmp = net_instance_int_create(nin, parent);
+ ASSERT(tmp != NULL);
+ LIST_INSERT_HEAD(&nts->nts_instances, tmp, nini_next);
+ mutex_exit(&nts->nts_lock);
+
+ }
+
+ neti_apply_all_stacks(parent, neti_stack_apply_create);
+ mutex_exit(&neti_stack_lock);
+
+ return (DDI_SUCCESS);
+}
+
+/*
+ * While net_instance_register() isn't likely to be racing against itself,
+ * net_instance_unregister() can be entered from various directions that
+ * can compete: shutdown of a zone, unloading of a module (and it calling
+ * _unregister() as part of that) and the module doing an _unregister()
+ * anyway.
+ */
+int
+net_instance_unregister(net_instance_t *nin)
+{
+ net_instance_int_t *parent;
+ net_instance_int_t *tmp;
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+
+ LIST_FOREACH(tmp, &neti_instance_list, nini_next) {
+ if (strcmp(tmp->nini_instance->nin_name, nin->nin_name) == 0) {
+ LIST_REMOVE(tmp, nini_next);
+ break;
+ }
+ }
+
+ if (tmp == NULL) {
+ mutex_exit(&neti_stack_lock);
+ return (DDI_FAILURE);
+ }
+ parent = tmp;
+
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ mutex_enter(&nts->nts_lock);
+ LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
+ if (tmp->nini_parent != parent)
+ continue;
+ /*
+ * Netstack difference:
+ * In netstack.c, there is a check for
+ * NSS_CREATE_COMPLETED before setting the other
+ * _NEEDED flags. If we consider that a list
+ * member must always have at least the _CREATE_NEEDED
+ * flag set and that wait_for_nini_inprogress will
+ * also wait for that flag to be cleared in both of
+ * the shutdown and destroy apply functions.
+ *
+ * It is possible to optimize out the case where
+ * all three _NEEDED flags are set to being able
+ * to pretend everything has been done and just
+ * set all three _COMPLETE flags. This makes a
+ * special case that we then need to consider in
+ * other locations, so for the sake of simplicity,
+ * we leave it as it is.
+ */
+ if ((tmp->nini_flags & NSS_SHUTDOWN_ALL) == 0)
+ tmp->nini_flags |= NSS_SHUTDOWN_NEEDED;
+ if ((tmp->nini_flags & NSS_DESTROY_ALL) == 0)
+ tmp->nini_flags |= NSS_DESTROY_NEEDED;
+ }
+ mutex_exit(&nts->nts_lock);
+ }
+
+ /*
+ * Each of these functions ensures that the requisite _COMPLETED
+ * flag is present before calling the apply function. So we are
+ * guaranteed to have NSS_CREATE_COMPLETED|NSS_SHUTDOWN_COMPLETED
+ * both set after the first call here and when the second completes,
+ * NSS_DESTROY_COMPLETED is also set.
+ */
+ neti_apply_all_stacks(parent, neti_stack_apply_shutdown);
+ neti_apply_all_stacks(parent, neti_stack_apply_destroy);
+
+ /*
+ * Remove the instance callback information from each stack.
+ */
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ mutex_enter(&nts->nts_lock);
+ LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
+ if ((tmp->nini_parent == parent) &&
+ (tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) &&
+ (tmp->nini_flags & NSS_DESTROY_COMPLETED)) {
+ /*
+ * There should only be one entry that has a
+ * matching nini_parent so there is no need to
+ * worry about continuing a loop where we are
+ * free'ing the structure holding the 'next'
+ * pointer.
+ */
+ LIST_REMOVE(tmp, nini_next);
+ net_instance_int_free(tmp);
+ break;
+ }
+ }
+ mutex_exit(&nts->nts_lock);
+ }
+ mutex_exit(&neti_stack_lock);
+
+ net_instance_int_free(parent);
+
+ return (DDI_SUCCESS);
+}
+
+static void
+neti_apply_all_instances(neti_stack_t *nts, napplyfn_t *applyfn)
+{
+ net_instance_int_t *n;
+
+ ASSERT(mutex_owned(&neti_stack_lock));
+
+ n = LIST_FIRST(&nts->nts_instances);
+ while (n != NULL) {
+ if ((applyfn)(&neti_stack_lock, nts, n->nini_parent)) {
+ /* Lock dropped - restart at head */
+ n = LIST_FIRST(&nts->nts_instances);
+ } else {
+ n = LIST_NEXT(n, nini_next);
+ }
+ }
+}
+
+static void
+neti_apply_all_stacks(void *parent, napplyfn_t *applyfn)
+{
+ neti_stack_t *nts;
+
+ ASSERT(mutex_owned(&neti_stack_lock));
+
+ nts = LIST_FIRST(&neti_stack_list);
+ while (nts != NULL) {
+ /*
+ * This function differs, in that it doesn't have a call to
+ * a "wait_creator" call, from the zsd/netstack code. The
+ * waiting is pushed into the apply functions which cause
+ * the waiting to be done in wait_for_nini_progress with
+ * the passing in of cmask.
+ */
+ if ((applyfn)(&neti_stack_lock, nts, parent)) {
+ /* Lock dropped - restart at head */
+ nts = LIST_FIRST(&neti_stack_list);
+ } else {
+ nts = LIST_NEXT(nts, nts_next);
+ }
+ }
+}
+
+static boolean_t
+neti_stack_apply_create(kmutex_t *lockp, neti_stack_t *nts, void *parent)
+{
+ void *result;
+ boolean_t dropped = B_FALSE;
+ net_instance_int_t *tmp;
+ net_instance_t *nin;
+
+ ASSERT(parent != NULL);
+ ASSERT(lockp != NULL);
+ ASSERT(mutex_owned(lockp));
+
+ mutex_enter(&nts->nts_lock);
+
+ LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
+ if (tmp->nini_parent == parent)
+ break;
+ }
+ if (tmp == NULL) {
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+ }
+
+ if (wait_for_nini_inprogress(nts, lockp, tmp, 0))
+ dropped = B_TRUE;
+
+ if (tmp->nini_flags & NSS_CREATE_NEEDED) {
+ nin = tmp->nini_instance;
+ tmp->nini_flags &= ~NSS_CREATE_NEEDED;
+ tmp->nini_flags |= NSS_CREATE_INPROGRESS;
+ DTRACE_PROBE2(neti__stack__create__inprogress,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ mutex_exit(&nts->nts_lock);
+ mutex_exit(lockp);
+ dropped = B_TRUE;
+
+ ASSERT(tmp->nini_created == NULL);
+ ASSERT(nin->nin_create != NULL);
+ DTRACE_PROBE2(neti__stack__create__start,
+ netstackid_t, nts->nts_id,
+ neti_stack_t *, nts);
+ result = (nin->nin_create)(nts->nts_id);
+ DTRACE_PROBE2(neti__stack__create__end,
+ void *, result, neti_stack_t *, nts);
+
+ ASSERT(result != NULL);
+ mutex_enter(lockp);
+ mutex_enter(&nts->nts_lock);
+ tmp->nini_created = result;
+ tmp->nini_flags &= ~NSS_CREATE_INPROGRESS;
+ tmp->nini_flags |= NSS_CREATE_COMPLETED;
+ cv_broadcast(&tmp->nini_cv);
+ DTRACE_PROBE2(neti__stack__create__completed,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ }
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+}
+
+
+static boolean_t
+neti_stack_apply_shutdown(kmutex_t *lockp, neti_stack_t *nts, void *parent)
+{
+ boolean_t dropped = B_FALSE;
+ net_instance_int_t *tmp;
+ net_instance_t *nin;
+
+ ASSERT(parent != NULL);
+ ASSERT(lockp != NULL);
+ ASSERT(mutex_owned(lockp));
+
+ mutex_enter(&nts->nts_lock);
+
+ LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
+ if (tmp->nini_parent == parent)
+ break;
+ }
+ if (tmp == NULL) {
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+ }
+
+ if (wait_for_nini_inprogress(nts, lockp, tmp, NSS_CREATE_NEEDED))
+ dropped = B_TRUE;
+
+ nin = tmp->nini_instance;
+ if (nin->nin_shutdown == NULL) {
+ /*
+ * If there is no shutdown function, fake having completed it.
+ */
+ if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
+ tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
+ tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
+ }
+
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+ }
+
+ if (tmp->nini_flags & NSS_SHUTDOWN_NEEDED) {
+ ASSERT((tmp->nini_flags & NSS_CREATE_COMPLETED) != 0);
+ tmp->nini_flags &= ~NSS_SHUTDOWN_NEEDED;
+ tmp->nini_flags |= NSS_SHUTDOWN_INPROGRESS;
+ DTRACE_PROBE2(neti__stack__shutdown__inprogress,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ mutex_exit(&nts->nts_lock);
+ mutex_exit(lockp);
+ dropped = B_TRUE;
+
+ ASSERT(nin->nin_shutdown != NULL);
+ DTRACE_PROBE2(neti__stack__shutdown__start,
+ netstackid_t, nts->nts_id,
+ neti_stack_t *, nts);
+ (nin->nin_shutdown)(nts->nts_id, tmp->nini_created);
+ DTRACE_PROBE1(neti__stack__shutdown__end,
+ neti_stack_t *, nts);
+
+ mutex_enter(lockp);
+ mutex_enter(&nts->nts_lock);
+ tmp->nini_flags &= ~NSS_SHUTDOWN_INPROGRESS;
+ tmp->nini_flags |= NSS_SHUTDOWN_COMPLETED;
+ cv_broadcast(&tmp->nini_cv);
+ DTRACE_PROBE2(neti__stack__shutdown__completed,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ }
+ ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+}
+
+static boolean_t
+neti_stack_apply_destroy(kmutex_t *lockp, neti_stack_t *nts, void *parent)
+{
+ boolean_t dropped = B_FALSE;
+ net_instance_int_t *tmp;
+ net_instance_t *nin;
+
+ ASSERT(parent != NULL);
+ ASSERT(lockp != NULL);
+ ASSERT(mutex_owned(lockp));
+
+ mutex_enter(&nts->nts_lock);
+
+ LIST_FOREACH(tmp, &nts->nts_instances, nini_next) {
+ if (tmp->nini_parent == parent)
+ break;
+ }
+ if (tmp == NULL) {
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+ }
+
+ /*
+ * We pause here so that when we continue we know that we're the
+ * only one doing anything active with this node.
+ */
+ if (wait_for_nini_inprogress(nts, lockp, tmp,
+ NSS_CREATE_NEEDED|NSS_SHUTDOWN_NEEDED))
+ dropped = B_TRUE;
+
+ if (tmp->nini_flags & NSS_DESTROY_NEEDED) {
+ ASSERT((tmp->nini_flags & NSS_SHUTDOWN_COMPLETED) != 0);
+ nin = tmp->nini_instance;
+ tmp->nini_flags &= ~NSS_DESTROY_NEEDED;
+ tmp->nini_flags |= NSS_DESTROY_INPROGRESS;
+ DTRACE_PROBE2(neti__stack__destroy__inprogress,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ mutex_exit(&nts->nts_lock);
+ mutex_exit(lockp);
+ dropped = B_TRUE;
+
+ ASSERT(nin->nin_destroy != NULL);
+ DTRACE_PROBE2(neti__stack__destroy__start,
+ netstackid_t, nts->nts_id,
+ neti_stack_t *, nts);
+ (nin->nin_destroy)(nts->nts_id, tmp->nini_created);
+ DTRACE_PROBE1(neti__stack__destroy__end,
+ neti_stack_t *, nts);
+
+ mutex_enter(lockp);
+ mutex_enter(&nts->nts_lock);
+ tmp->nini_flags &= ~NSS_DESTROY_INPROGRESS;
+ tmp->nini_flags |= NSS_DESTROY_COMPLETED;
+ cv_broadcast(&tmp->nini_cv);
+ DTRACE_PROBE2(neti__stack__destroy__completed,
+ neti_stack_t *, nts, net_instance_int_t *, tmp);
+ }
+ mutex_exit(&nts->nts_lock);
+ return (dropped);
+}
+
+static boolean_t
+wait_for_nini_inprogress(neti_stack_t *nts, kmutex_t *lockp,
+ net_instance_int_t *nini, uint32_t cmask)
+{
+ boolean_t dropped = B_FALSE;
+
+ ASSERT(lockp != NULL);
+ ASSERT(mutex_owned(lockp));
+
+ while (nini->nini_flags & (NSS_ALL_INPROGRESS|cmask)) {
+ DTRACE_PROBE2(netstack__wait__nms__inprogress,
+ neti_stack_t *, nts, net_instance_int_t *, nini);
+ dropped = B_TRUE;
+ mutex_exit(lockp);
+
+ cv_wait(&nini->nini_cv, &nts->nts_lock);
+
+ /* First drop netstack_lock to preserve order */
+ mutex_exit(&nts->nts_lock);
+ mutex_enter(lockp);
+ mutex_enter(&nts->nts_lock);
+ }
+ return (dropped);
+}
+
+/* ======================================================================= */
+
+netid_t
+net_zoneidtonetid(zoneid_t zoneid)
+{
+
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ if (nts->nts_zoneid == zoneid) {
+ mutex_exit(&neti_stack_lock);
+ return (nts->nts_id);
+ }
+ }
+ mutex_exit(&neti_stack_lock);
+
+ return (-1);
+}
+
+zoneid_t
+net_getzoneidbynetid(netid_t netid)
+{
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ if (nts->nts_id == netid) {
+ mutex_exit(&neti_stack_lock);
+ return (nts->nts_zoneid);
+ }
+ }
+ mutex_exit(&neti_stack_lock);
+
+ return (-1);
+}
+
+netstackid_t
+net_getnetstackidbynetid(netid_t netid)
+{
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ if (nts->nts_id == netid) {
+ mutex_exit(&neti_stack_lock);
+ return (nts->nts_stackid);
+ }
+ }
+ mutex_exit(&neti_stack_lock);
+
+ return (-1);
+}
+
+netid_t
+net_getnetidbynetstackid(netstackid_t netstackid)
+{
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ if (nts->nts_stackid == netstackid) {
+ mutex_exit(&neti_stack_lock);
+ return (nts->nts_id);
+ }
+ }
+ mutex_exit(&neti_stack_lock);
+
+ return (-1);
+}
+
+neti_stack_t *
+net_getnetistackbyid(netid_t netid)
+{
+ neti_stack_t *nts;
+
+ mutex_enter(&neti_stack_lock);
+ LIST_FOREACH(nts, &neti_stack_list, nts_next) {
+ if (nts->nts_id == netid) {
+ mutex_exit(&neti_stack_lock);
+ return (nts);
+ }
+ }
+ mutex_exit(&neti_stack_lock);
+
+ return (NULL);
+}
+
+int
+net_instance_notify_register(netid_t netid, hook_notify_fn_t callback,
+ void *arg)
+{
+
+ return (hook_stack_notify_register(net_getnetstackidbynetid(netid),
+ callback, arg));
+}
+
+int
+net_instance_notify_unregister(netid_t netid, hook_notify_fn_t callback)
+{
+
+ return (hook_stack_notify_unregister(net_getnetstackidbynetid(netid),
+ callback));
+}
diff --git a/usr/src/uts/common/os/netstack.c b/usr/src/uts/common/os/netstack.c
index c1e59fe6c3..37f851df8e 100644
--- a/usr/src/uts/common/os/netstack.c
+++ b/usr/src/uts/common/os/netstack.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/vm.h>
@@ -435,7 +433,7 @@ netstack_zone_shutdown(zoneid_t zoneid, void *arg)
* Call the shutdown function for all registered modules for this
* netstack.
*/
- apply_all_modules(ns, netstack_apply_shutdown);
+ apply_all_modules_reverse(ns, netstack_apply_shutdown);
/* Tell any waiting netstack_register/netstack_unregister to proceed */
mutex_enter(&ns->netstack_lock);
@@ -546,7 +544,7 @@ netstack_stack_inactive(netstack_t *ns)
* leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set.
* That is different than in the netstack_unregister() case.
*/
- apply_all_modules(ns, netstack_apply_shutdown);
+ apply_all_modules_reverse(ns, netstack_apply_shutdown);
apply_all_modules_reverse(ns, netstack_apply_destroy);
/* Tell any waiting netstack_register/netstack_unregister to proceed */
@@ -676,6 +674,7 @@ netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
DTRACE_PROBE2(netstack__create__start,
netstackid_t, stackid,
netstack_t *, ns);
+printf("ns[%d](%d).create\n", moduleid, stackid);
result = (ns_reg[moduleid].nr_create)(stackid, ns);
DTRACE_PROBE2(netstack__create__end,
void *, result, netstack_t *, ns);
@@ -737,6 +736,7 @@ netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
DTRACE_PROBE2(netstack__shutdown__start,
netstackid_t, stackid,
void *, netstack_module);
+printf("ns[%d](%d).shutdown\n", moduleid, stackid);
(ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
DTRACE_PROBE1(netstack__shutdown__end,
netstack_t *, ns);
@@ -796,6 +796,7 @@ netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
DTRACE_PROBE2(netstack__destroy__start,
netstackid_t, stackid,
void *, netstack_module);
+printf("ns[%d](%d).destroy\n", moduleid, stackid);
(ns_reg[moduleid].nr_destroy)(stackid, netstack_module);
DTRACE_PROBE1(netstack__destroy__end,
netstack_t *, ns);
diff --git a/usr/src/uts/common/sys/condvar_impl.h b/usr/src/uts/common/sys/condvar_impl.h
index 75c5867375..429eede4f9 100644
--- a/usr/src/uts/common/sys/condvar_impl.h
+++ b/usr/src/uts/common/sys/condvar_impl.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_CONDVAR_IMPL_H
#define _SYS_CONDVAR_IMPL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Implementation-private definitions for condition variables
*/
@@ -102,6 +100,14 @@ typedef struct cvwaitlock_s {
mutex_exit(&(_c)->cvw_lock); \
}
+#define CVW_WRITE_TO_READ(_c) { \
+ mutex_enter(&(_c)->cvw_lock); \
+ ASSERT((_c)->cvw_refcnt == -1); \
+ (_c)->cvw_refcnt = 1; \
+ cv_broadcast(&(_c)->cvw_waiter); \
+ mutex_exit(&(_c)->cvw_lock); \
+}
+
#define CVW_DESTROY(_c) { \
mutex_destroy(&(_c)->cvw_lock); \
cv_destroy(&(_c)->cvw_waiter); \
diff --git a/usr/src/uts/common/sys/hook.h b/usr/src/uts/common/sys/hook.h
index 00b0048093..464f2b8b50 100644
--- a/usr/src/uts/common/sys/hook.h
+++ b/usr/src/uts/common/sys/hook.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +30,6 @@
#ifndef _SYS_HOOK_H
#define _SYS_HOOK_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/queue.h>
#include <sys/netstack.h>
@@ -49,33 +47,62 @@ typedef uintptr_t hook_data_t;
struct hook_event_int;
typedef struct hook_event_int *hook_event_token_t;
+struct hook_int;
+typedef struct hook_int *hook_token_t;
+
+typedef int (* hook_func_t)(hook_event_token_t, hook_data_t, void *);
+
+/*
+ * A hook_notify_cmd_t is given as an argument to functions called as part of
+ * the notify callbacks that have been registered firing.
+ */
+typedef enum hook_notify_cmd_e {
+ HN_NONE = 0,
+ HN_REGISTER = 1,
+ HN_UNREGISTER = 2
+} hook_notify_cmd_t;
-typedef int (* hook_func_t)(hook_event_token_t, hook_data_t, netstack_t *);
+/*
+ *
+ */
+typedef enum hook_hint_e {
+ HH_NONE = 0,
+ HH_FIRST,
+ HH_LAST,
+ HH_BEFORE,
+ HH_AFTER
+} hook_hint_t;
/*
* Hook
*/
-typedef struct hook {
- int32_t h_version; /* version number */
+typedef struct hook_s {
+ int h_version;
hook_func_t h_func; /* callback func */
char *h_name; /* name of this hook */
- int h_flags; /* extra hook properties */
+ uint_t h_flags; /* extra hook properties */
+ hook_hint_t h_hint; /* What type of hint is hintvalue */
+ uintptr_t h_hintvalue;
+ void *h_arg; /* value to pass back into the hook */
} hook_t;
-#define HOOK_INIT(x, fn, r) \
+#define HOOK_INIT(x, fn, r, a) \
do { \
- (x)->h_version = HOOK_VERSION; \
+ (x) = hook_alloc(HOOK_VERSION); \
(x)->h_func = (fn); \
(x)->h_name = (r); \
(x)->h_flags = 0; \
+ (x)->h_hint = HH_NONE; \
+ (x)->h_hintvalue = 0; \
+ (x)->h_arg = (a); \
_NOTE(CONSTCOND) \
} while (0)
/*
* Family
*/
-typedef struct hook_family {
- int32_t hf_version; /* version number */
+typedef struct hook_family_s {
+ int hf_version; /* version number */
char *hf_name; /* family name */
} hook_family_t;
@@ -89,8 +116,8 @@ typedef struct hook_family {
/*
* Event
*/
-typedef struct hook_event {
- int32_t he_version; /* version number */
+typedef struct hook_event_s {
+ int he_version;
char *he_name; /* name of this hook list */
int he_flags; /* 1 = multiple entries allowed */
boolean_t he_interested; /* true if callback exist */
@@ -108,6 +135,12 @@ typedef struct hook_event {
_NOTE(CONSTCOND) \
} while (0)
+typedef int (* hook_notify_fn_t)(hook_notify_cmd_t, void *, const char *,
+ const char *, const char *);
+
+extern hook_t *hook_alloc(const int version);
+extern void hook_free(hook_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/hook_event.h b/usr/src/uts/common/sys/hook_event.h
index 12dcef0e84..df99a67956 100644
--- a/usr/src/uts/common/sys/hook_event.h
+++ b/usr/src/uts/common/sys/hook_event.h
@@ -32,8 +32,6 @@
#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>
@@ -46,6 +44,8 @@ extern "C" {
* associated network interfaces.
*
* The members of this structure are defined as follows:
+ * hpe_protocol - protocol identifier that indicates which protocol the
+ * header data is associated with.
* 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
@@ -53,12 +53,14 @@ extern "C" {
* hpe_mb - pointer to the mblk that contains hpe_hdr
*/
typedef struct hook_pkt_event {
+ net_handle_t hpe_protocol;
phy_if_t hpe_ifp;
phy_if_t hpe_ofp;
void *hpe_hdr;
mblk_t **hpe_mp;
mblk_t *hpe_mb;
int hpe_flags;
+ void *hpe_reserved[2];
} hook_pkt_event_t;
#define HPE_MULTICAST 0x01
@@ -81,7 +83,7 @@ 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_protocol- network protocol for 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
@@ -89,7 +91,7 @@ typedef void *nic_event_data_t;
* hne_datalen - size of data pointed to by hne_data (can be 0)
*/
typedef struct hook_nic_event {
- net_data_t hne_family;
+ net_handle_t hne_protocol;
phy_if_t hne_nic;
lif_if_t hne_lif;
nic_event_t hne_event;
@@ -97,6 +99,15 @@ typedef struct hook_nic_event {
size_t hne_datalen;
} hook_nic_event_t;
+/*
+ * This structure is used internally by ip to queue events.
+ */
+struct hook_nic_event_int {
+ netstackid_t hnei_stackid;
+ hook_nic_event_t hnei_event;
+};
+typedef struct hook_nic_event_int hook_nic_event_int_t;
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/hook_impl.h b/usr/src/uts/common/sys/hook_impl.h
index 08112e4144..2357a2d287 100644
--- a/usr/src/uts/common/sys/hook_impl.h
+++ b/usr/src/uts/common/sys/hook_impl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,8 +30,6 @@
#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>
#include <sys/netstack.h>
@@ -40,6 +38,31 @@
extern "C" {
#endif
+typedef enum fwflag_e {
+ FWF_NONE = 0x00,
+ FWF_DESTROY_ACTIVE = 0x01,
+ FWF_ADD_ACTIVE = 0x04,
+ FWF_DEL_ACTIVE = 0x08,
+ FWF_DESTROY_WANTED = 0x10,
+ FWF_ADD_WANTED = 0x40,
+ FWF_DEL_WANTED = 0x80,
+ FWF_NOT_READY = 0x100
+} fwflag_t;
+
+#define FWF_WAIT_MASK (FWF_ADD_ACTIVE|FWF_DEL_ACTIVE|\
+ FWF_ADD_WANTED|FWF_DEL_WANTED)
+#define FWF_UNSAFE (FWF_DESTROY_ACTIVE|FWF_NOT_READY)
+#define FWF_DESTROY (FWF_DESTROY_ACTIVE|FWF_DESTROY_WANTED)
+#define FWF_DESTROY_OK(x) ((x)->fw_flags == FWF_DESTROY_WANTED)
+
+typedef struct flagwait_s {
+ kcondvar_t fw_cv;
+ kmutex_t fw_lock;
+ uint32_t fw_flags;
+ cvwaitlock_t *fw_owner;
+} flagwait_t;
+
+
/*
* The following diagram describes the linking together of data structures
* used in this implementation of callback hooks. The start of it all is
@@ -58,32 +81,66 @@ extern "C" {
* | 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 |
+ * | +---------------+ | / | hei_nhead----------\ / | +----------+ |
+ * | | / | | X | |
+ * | hfi_head------------/ | hei_head-----------/ \ | hi_entry--\ |
+ * | hfi_entry--\ | | hei_entry--\ | | +-----------|--+
+ * +------------|------+ +------------|-----+ | |
+ * | | | |
+ * V V | V
+ * +-------------------+ +------------------+ | +--------------+
+ * | hook_family_int_t | | hook_event_int_t | | | hook_int_t |
+ * V
+ * +--------------+
+ * |
* ...
*/
+typedef struct hook_hook_kstat {
+ kstat_named_t hook_version;
+ kstat_named_t hook_flags;
+ kstat_named_t hook_hint;
+ kstat_named_t hook_hintvalue;
+ kstat_named_t hook_position;
+ kstat_named_t hook_hits;
+} hook_hook_kstat_t;
+
/*
* hook_int: internal storage of hook
*/
typedef struct hook_int {
- TAILQ_ENTRY(hook_int) hi_entry;
- hook_t hi_hook;
+ TAILQ_ENTRY(hook_int) hi_entry;
+ hook_t hi_hook;
+ hook_hook_kstat_t hi_kstats;
+ kstat_t *hi_kstatp;
+ char *hi_ksname;
+ cvwaitlock_t hi_notify_lock;
} hook_int_t;
/*
- * Hook_int_head: tail queue of hook_int
+ * hook_int_head: tail queue of hook_int
*/
TAILQ_HEAD(hook_int_head, hook_int);
typedef struct hook_int_head hook_int_head_t;
+
+typedef struct hook_notify {
+ TAILQ_ENTRY(hook_notify) hn_entry;
+ hook_notify_fn_t hn_func;
+ void *hn_arg;
+ uint32_t hn_flags;
+} hook_notify_t;
+
+TAILQ_HEAD(hook_notify_head, hook_notify);
+typedef struct hook_notify_head hook_notify_head_t;
+
+
+typedef struct hook_event_kstat {
+ kstat_named_t hooks_added;
+ kstat_named_t hooks_removed;
+ kstat_named_t events;
+} hook_event_kstat_t;
+
/*
* hook_event_int: internal storage of hook_event
*/
@@ -92,6 +149,11 @@ typedef struct hook_event_int {
SLIST_ENTRY(hook_event_int) hei_entry;
hook_event_t *hei_event;
hook_int_head_t hei_head;
+ kstat_t *hei_kstatp;
+ hook_event_kstat_t hei_kstats;
+ hook_notify_head_t hei_nhead;
+ flagwait_t hei_waiter;
+ boolean_t hei_condemned;
} hook_event_int_t;
/*
@@ -104,10 +166,15 @@ typedef struct hook_event_int_head hook_event_int_head_t;
* hook_family_int: internal storage of hook_family
*/
typedef struct hook_family_int {
+ cvwaitlock_t hfi_lock;
SLIST_ENTRY(hook_family_int) hfi_entry;
hook_event_int_head_t hfi_head;
hook_family_t hfi_family;
- void *hfi_ptr;
+ kstat_t *hfi_kstat;
+ struct hook_stack *hfi_stack;
+ hook_notify_head_t hfi_nhead;
+ flagwait_t hfi_waiter;
+ boolean_t hfi_condemned;
} hook_family_int_t;
/*
@@ -120,11 +187,18 @@ typedef struct hook_family_int_head hook_family_int_head_t;
* hook stack instances
*/
struct hook_stack {
- cvwaitlock_t hks_familylock; /* global lock */
- hook_family_int_head_t hks_familylist; /* family list head */
- netstack_t *hk_netstack;
+ cvwaitlock_t hks_lock;
+ SLIST_ENTRY(hook_stack) hks_entry;
+ hook_family_int_head_t hks_familylist; /* family list head */
+ netstack_t *hks_netstack;
+ netstackid_t hks_netstackid;
+ hook_notify_head_t hks_nhead;
+ int hks_shutdown;
+ flagwait_t hks_waiter;
};
typedef struct hook_stack hook_stack_t;
+SLIST_HEAD(hook_stack_head, hook_stack);
+typedef struct hook_stack_head hook_stack_head_t;
/*
* Names of hooks families currently defined by Solaris
@@ -133,13 +207,26 @@ typedef struct hook_stack hook_stack_t;
#define Hn_IPV4 "inet"
#define Hn_IPV6 "inet6"
-extern hook_family_int_t *hook_family_add(hook_family_t *, hook_stack_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_run(hook_family_int_t *, hook_event_token_t, hook_data_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, netstack_t *);
+extern hook_event_int_t *hook_event_add(hook_family_int_t *, hook_event_t *);
+extern int hook_event_notify_register(hook_family_int_t *, char *,
+ hook_notify_fn_t, void *);
+extern int hook_event_notify_unregister(hook_family_int_t *, char *,
+ hook_notify_fn_t);
+extern int hook_event_remove(hook_family_int_t *, hook_event_t *);
+
+extern hook_family_int_t *hook_family_add(hook_family_t *, hook_stack_t *);
+extern int hook_family_notify_register(hook_family_int_t *, hook_notify_fn_t,
+ void *);
+extern int hook_family_notify_unregister(hook_family_int_t *, hook_notify_fn_t);
+extern int hook_family_remove(hook_family_int_t *);
+
+extern int hook_stack_notify_register(netstackid_t, hook_notify_fn_t, void *);
+extern int hook_stack_notify_unregister(netstackid_t, hook_notify_fn_t);
+
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/neti.h b/usr/src/uts/common/sys/neti.h
index ea6c843158..ad82ae0d87 100644
--- a/usr/src/uts/common/sys/neti.h
+++ b/usr/src/uts/common/sys/neti.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 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>
@@ -81,9 +79,7 @@ extern "C" {
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;
+typedef id_t netid_t;
/*
* Netinfo interface specification
@@ -106,33 +102,41 @@ typedef enum inject {
NI_DIRECT_OUT
} inject_t;
+/*
+ * net_inject - public interface
+ */
typedef struct net_inject {
+ int ni_version;
+ netid_t ni_netid;
mblk_t *ni_packet;
struct sockaddr_storage ni_addr;
phy_if_t ni_physical;
} net_inject_t;
+typedef struct net_data *net_handle_t;
/*
- * net_info_t public interface
+ * net_protocol_t private interface
*/
-typedef struct net_info {
- int neti_version;
- char *neti_protocol;
- int (*neti_getifname)(phy_if_t, char *, const size_t,
- netstack_t *);
- int (*neti_getmtu)(phy_if_t, lif_if_t, netstack_t *);
- int (*neti_getpmtuenabled)(netstack_t *);
- int (*neti_getlifaddr)(phy_if_t, lif_if_t, size_t,
- net_ifaddr_t [], void *, netstack_t *);
- phy_if_t (*neti_phygetnext)(phy_if_t, netstack_t *);
- phy_if_t (*neti_phylookup)(const char *, netstack_t *);
- lif_if_t (*neti_lifgetnext)(phy_if_t, lif_if_t, netstack_t *);
- int (*neti_inject)(inject_t, net_inject_t *, netstack_t *);
- phy_if_t (*neti_routeto)(struct sockaddr *, netstack_t *);
- int (*neti_ispartialchecksum)(mblk_t *);
- int (*neti_isvalidchecksum)(mblk_t *);
-} net_info_t;
+struct net_protocol_s {
+ int netp_version;
+ char *netp_name;
+ int (*netp_getifname)(net_handle_t, phy_if_t, char *,
+ const size_t);
+ int (*netp_getmtu)(net_handle_t, phy_if_t, lif_if_t);
+ int (*netp_getpmtuenabled)(net_handle_t);
+ int (*netp_getlifaddr)(net_handle_t, phy_if_t, lif_if_t,
+ size_t, net_ifaddr_t [], void *);
+ phy_if_t (*netp_phygetnext)(net_handle_t, phy_if_t);
+ phy_if_t (*netp_phylookup)(net_handle_t, const char *);
+ lif_if_t (*netp_lifgetnext)(net_handle_t, phy_if_t, lif_if_t);
+ int (*netp_inject)(net_handle_t, inject_t, net_inject_t *);
+ phy_if_t (*netp_routeto)(net_handle_t, struct sockaddr *,
+ struct sockaddr *);
+ int (*netp_ispartialchecksum)(net_handle_t, mblk_t *);
+ int (*netp_isvalidchecksum)(net_handle_t, mblk_t *);
+};
+typedef struct net_protocol_s net_protocol_t;
/*
@@ -140,10 +144,11 @@ typedef struct net_info {
*/
struct net_data {
LIST_ENTRY(net_data) netd_list;
- net_info_t netd_info;
+ net_protocol_t netd_info;
int netd_refcnt;
hook_family_int_t *netd_hooks;
- netstack_t *netd_netstack;
+ struct neti_stack_s *netd_stack;
+ int netd_condemned;
};
@@ -162,53 +167,117 @@ typedef struct injection_s {
#define MAP_IPIF_ID(x) ((x) + 1)
#define UNMAP_IPIF_ID(x) (((x) > 0) ? (x) - 1 : (x))
+struct net_instance_s {
+ int nin_version;
+ char *nin_name;
+ void *(*nin_create)(const netid_t);
+ void (*nin_destroy)(const netid_t, void *);
+ void (*nin_shutdown)(const netid_t, void *);
+};
+typedef struct net_instance_s net_instance_t;
+
+struct net_instance_int_s {
+ LIST_ENTRY(net_instance_int_s) nini_next;
+ int nini_ref;
+ void *nini_created;
+ struct net_instance_int_s *nini_parent;
+ net_instance_t *nini_instance;
+ hook_notify_t nini_notify;
+ uint32_t nini_flags;
+ kcondvar_t nini_cv;
+};
+typedef struct net_instance_int_s net_instance_int_t;
+LIST_HEAD(nini_head_s, net_instance_int_s);
+typedef struct nini_head_s nini_head_t;
+
+#define nini_version nini_instance->nin_version
+#define nini_name nini_instance->nin_name
+#define nini_create nini_instance->nin_create
+#define nini_destroy nini_instance->nin_destroy
+#define nini_shutdown nini_instance->nin_shutdown
/*
- * neti stack instances
+ * netinfo stack instances
*/
-struct neti_stack {
- krwlock_t nts_netlock;
-
- /* list of net_data_t */
+struct neti_stack_s {
+ kmutex_t nts_lock;
+ LIST_ENTRY(neti_stack_s) nts_next;
+ netid_t nts_id;
+ zoneid_t nts_zoneid;
+ netstackid_t nts_stackid;
+ netstack_t *nts_netstack;
+ nini_head_t nts_instances;
+ uint32_t nts_flags;
+ kcondvar_t nts_cv;
+ /* list of net_handle_t */
LIST_HEAD(netd_listhead, net_data) nts_netd_head;
- netstack_t *nts_netstack;
};
-typedef struct neti_stack neti_stack_t;
-
+typedef struct neti_stack_s neti_stack_t;
+LIST_HEAD(neti_stack_head_s, neti_stack_s);
+typedef struct neti_stack_head_s neti_stack_head_t;
/*
- * Data management functions
+ * Internal functions that need to be exported within the module.
*/
-extern net_data_t net_register(const net_info_t *, netstackid_t);
-extern net_data_t net_register_impl(const net_info_t *, netstack_t *);
-extern int net_unregister(net_data_t);
-extern net_data_t net_lookup(const char *, netstackid_t);
-extern net_data_t net_lookup_impl(const char *, netstack_t *);
-extern int net_release(net_data_t);
-extern net_data_t net_walk(net_data_t, netstackid_t);
-extern net_data_t net_walk_impl(net_data_t, netstack_t *);
+extern void neti_init(void);
+extern void neti_fini(void);
+extern neti_stack_t *net_getnetistackbyid(netid_t);
+extern netstackid_t net_getnetstackidbynetid(netid_t);
+extern netid_t net_getnetidbynetstackid(netstackid_t);
+extern netid_t net_zoneidtonetid(zoneid_t);
+extern zoneid_t net_getzoneidbynetid(netid_t);
/*
- * Accessor functions
+ * Functions available for public use.
*/
-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,
+extern hook_event_token_t net_event_register(net_handle_t, hook_event_t *);
+extern int net_event_unregister(net_handle_t, hook_event_t *);
+extern int net_event_notify_register(net_handle_t, char *,
+ hook_notify_fn_t, void *);
+extern int net_event_notify_unregister(net_handle_t, char *, hook_notify_fn_t);
+
+extern int net_family_register(net_handle_t, hook_family_t *);
+extern int net_family_unregister(net_handle_t, hook_family_t *);
+
+extern int net_hook_register(net_handle_t, char *, hook_t *);
+extern int net_hook_unregister(net_handle_t, char *, hook_t *);
+
+extern int net_inject(net_handle_t, inject_t, net_inject_t *);
+extern net_inject_t *net_inject_alloc(const int);
+extern void net_inject_free(net_inject_t *);
+
+extern net_instance_t *net_instance_alloc(const int version);
+extern void net_instance_free(net_instance_t *);
+extern int net_instance_register(net_instance_t *);
+extern int net_instance_unregister(net_instance_t *);
+extern int net_instance_notify_register(netid_t, hook_notify_fn_t, void *);
+extern int net_instance_notify_unregister(netid_t netid, hook_notify_fn_t);
+
+extern kstat_t *net_kstat_create(netid_t, char *, int, char *, char *,
+ uchar_t, ulong_t, uchar_t);
+extern void net_kstat_delete(netid_t, kstat_t *);
+
+extern net_handle_t net_protocol_lookup(netid_t, const char *);
+extern net_handle_t net_protocol_register(netid_t, const net_protocol_t *);
+extern int net_protocol_release(net_handle_t);
+extern int net_protocol_unregister(net_handle_t);
+extern net_handle_t net_protocol_walk(netid_t, net_handle_t);
+extern int net_protocol_notify_register(net_handle_t, hook_notify_fn_t, void *);
+extern int net_protocol_notify_unregister(net_handle_t, hook_notify_fn_t);
+
+
+extern int net_getifname(net_handle_t, phy_if_t, char *, const size_t);
+extern int net_getmtu(net_handle_t, phy_if_t, lif_if_t);
+extern int net_getpmtuenabled(net_handle_t);
+extern int net_getlifaddr(net_handle_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 *);
+extern phy_if_t net_phygetnext(net_handle_t, phy_if_t);
+extern phy_if_t net_phylookup(net_handle_t, const char *);
+extern lif_if_t net_lifgetnext(net_handle_t, phy_if_t, lif_if_t);
+extern phy_if_t net_routeto(net_handle_t, struct sockaddr *,
+ struct sockaddr *);
+extern int net_ispartialchecksum(net_handle_t, mblk_t *);
+extern int net_isvalidchecksum(net_handle_t, mblk_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/netstack.h b/usr/src/uts/common/sys/netstack.h
index 9bd7701693..55acab834c 100644
--- a/usr/src/uts/common/sys/netstack.h
+++ b/usr/src/uts/common/sys/netstack.h
@@ -26,8 +26,6 @@
#ifndef _SYS_NETSTACK_H
#define _SYS_NETSTACK_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/kstat.h>
#ifdef __cplusplus
@@ -64,24 +62,23 @@ typedef id_t netstackid_t;
* done ine in decending order).
*/
#define NS_ALL -1 /* Match all */
-#define NS_HOOK 0
-#define NS_NETI 1
-#define NS_ARP 2
-#define NS_IP 3
-#define NS_ICMP 4
-#define NS_UDP 5
-#define NS_TCP 6
-#define NS_SCTP 7
-#define NS_RTS 8
-#define NS_IPSEC 9
-#define NS_KEYSOCK 10
-#define NS_SPDSOCK 11
-#define NS_IPSECAH 12
-#define NS_IPSECESP 13
-#define NS_TUN 14
-#define NS_IPF 15
-#define NS_STR 16 /* autopush list etc */
-#define NS_MAX (NS_STR+1)
+#define NS_STR 0 /* autopush list etc */
+#define NS_HOOK 1
+#define NS_NETI 2
+#define NS_ARP 3
+#define NS_IP 4
+#define NS_ICMP 5
+#define NS_UDP 6
+#define NS_TCP 7
+#define NS_SCTP 8
+#define NS_RTS 9
+#define NS_IPSEC 10
+#define NS_KEYSOCK 11
+#define NS_SPDSOCK 12
+#define NS_IPSECAH 13
+#define NS_IPSECESP 14
+#define NS_TUN 15
+#define NS_MAX (NS_TUN+1)
/*
* State maintained for each module which tracks the state of
@@ -138,6 +135,7 @@ struct netstack {
union {
void *nu_modules[NS_MAX];
struct {
+ struct str_stack *nu_str;
struct hook_stack *nu_hook;
struct neti_stack *nu_neti;
struct arp_stack *nu_arp;
@@ -153,11 +151,10 @@ struct netstack {
struct ipsecah_stack *nu_ipsecah;
struct ipsecesp_stack *nu_ipsecesp;
struct tun_stack *nu_tun;
- struct ipf_stack *nu_ipf;
- struct str_stack *nu_str;
} nu_s;
} netstack_u;
#define netstack_modules netstack_u.nu_modules
+#define netstack_str netstack_u.nu_s.nu_str
#define netstack_hook netstack_u.nu_s.nu_hook
#define netstack_neti netstack_u.nu_s.nu_neti
#define netstack_arp netstack_u.nu_s.nu_arp
@@ -173,8 +170,6 @@ struct netstack {
#define netstack_ipsecah netstack_u.nu_s.nu_ipsecah
#define netstack_ipsecesp netstack_u.nu_s.nu_ipsecesp
#define netstack_tun netstack_u.nu_s.nu_tun
-#define netstack_ipf netstack_u.nu_s.nu_ipf
-#define netstack_str netstack_u.nu_s.nu_str
nm_state_t netstack_m_state[NS_MAX]; /* module state */
diff --git a/usr/src/uts/intel/hook/hook.global-objs.debug64 b/usr/src/uts/intel/hook/hook.global-objs.debug64
index c813224003..48d393076f 100644
--- a/usr/src/uts/intel/hook/hook.global-objs.debug64
+++ b/usr/src/uts/intel/hook/hook.global-objs.debug64
@@ -19,10 +19,11 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
modlinkage
modlmisc
+hook_stack_lock
+hook_stacks
diff --git a/usr/src/uts/intel/ipf/Makefile b/usr/src/uts/intel/ipf/Makefile
index 8ae5ba3dff..db27bf34f7 100644
--- a/usr/src/uts/intel/ipf/Makefile
+++ b/usr/src/uts/intel/ipf/Makefile
@@ -22,8 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# uts/intel/ipf/Makefile
#
# This makefile drives the production of the ipf driver
@@ -60,7 +58,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP -DUSE_INET6
CPPFLAGS += -DSUNDDI -DSOLARIS2=$(RELEASE_MINOR) -DIRE_ILL_CN
-LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/kcf
+LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/hook -Nmisc/kcf
INC_PATH += -I$(UTSBASE)/common/inet/ipf
diff --git a/usr/src/uts/intel/ipf/ipf.global-objs.debug64 b/usr/src/uts/intel/ipf/ipf.global-objs.debug64
index de4365bbd0..203dd14416 100644
--- a/usr/src/uts/intel/ipf/ipf.global-objs.debug64
+++ b/usr/src/uts/intel/ipf/ipf.global-objs.debug64
@@ -22,7 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
fr_availfuncs
fr_features
@@ -40,7 +39,10 @@ ipf_devfiles
ipf_kstat_tmp
ipf_ops
ipf_proxy_debug
+ipf_stack_lock
+ipf_stacks
ipfilter_version
+ipfncb
ipl_magic
iplmod
ipopts
diff --git a/usr/src/uts/intel/neti/neti.global-objs.debug64 b/usr/src/uts/intel/neti/neti.global-objs.debug64
index c813224003..f0ebce499b 100644
--- a/usr/src/uts/intel/neti/neti.global-objs.debug64
+++ b/usr/src/uts/intel/neti/neti.global-objs.debug64
@@ -19,10 +19,12 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
modlinkage
modlmisc
+neti_instance_list
+neti_stack_list
+neti_stack_lock
diff --git a/usr/src/uts/sparc/hook/hook.global-objs.debug64 b/usr/src/uts/sparc/hook/hook.global-objs.debug64
index c813224003..48d393076f 100644
--- a/usr/src/uts/sparc/hook/hook.global-objs.debug64
+++ b/usr/src/uts/sparc/hook/hook.global-objs.debug64
@@ -19,10 +19,11 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
modlinkage
modlmisc
+hook_stack_lock
+hook_stacks
diff --git a/usr/src/uts/sparc/ipf/Makefile b/usr/src/uts/sparc/ipf/Makefile
index 9ab95b305b..1270d808af 100644
--- a/usr/src/uts/sparc/ipf/Makefile
+++ b/usr/src/uts/sparc/ipf/Makefile
@@ -22,8 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
# uts/sparc/ipf/Makefile
#
#
@@ -65,7 +63,7 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
CFLAGS += $(CCVERBOSE)
CPPFLAGS += -DIPFILTER_LKM -DIPFILTER_LOG -DIPFILTER_LOOKUP
CPPFLAGS += -DSUNDDI -DSOLARIS2=$(RELEASE_MINOR) -DIRE_ILL_CN -DUSE_INET6
-LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/kcf
+LDFLAGS += -dy -Ndrv/ip -Nmisc/md5 -Nmisc/neti -Nmisc/hook -Nmisc/kcf
INC_PATH += -I$(UTSBASE)/common/inet/ipf
diff --git a/usr/src/uts/sparc/ipf/ipf.global-objs.debug64 b/usr/src/uts/sparc/ipf/ipf.global-objs.debug64
index 21c10a84f4..61566e8b65 100644
--- a/usr/src/uts/sparc/ipf/ipf.global-objs.debug64
+++ b/usr/src/uts/sparc/ipf/ipf.global-objs.debug64
@@ -22,7 +22,6 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
fr_availfuncs
fr_features
@@ -40,7 +39,10 @@ ipf_devfiles
ipf_kstat_tmp
ipf_ops
ipf_proxy_debug
+ipf_stack_lock
+ipf_stacks
ipfilter_version
+ipfncb
ipl_magic
iplmod
ipopts
diff --git a/usr/src/uts/sparc/neti/Makefile b/usr/src/uts/sparc/neti/Makefile
index 3a338bb130..2520b77173 100644
--- a/usr/src/uts/sparc/neti/Makefile
+++ b/usr/src/uts/sparc/neti/Makefile
@@ -21,11 +21,9 @@
#
# uts/sparc/neti/Makefile
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 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.
#
# SPARC implementation architecture dependent
diff --git a/usr/src/uts/sparc/neti/neti.global-objs.debug64 b/usr/src/uts/sparc/neti/neti.global-objs.debug64
index c813224003..f0ebce499b 100644
--- a/usr/src/uts/sparc/neti/neti.global-objs.debug64
+++ b/usr/src/uts/sparc/neti/neti.global-objs.debug64
@@ -19,10 +19,12 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
modlinkage
modlmisc
+neti_instance_list
+neti_stack_list
+neti_stack_lock