18023SPhil.Kirk@Sun.COM /*
28023SPhil.Kirk@Sun.COM * CDDL HEADER START
38023SPhil.Kirk@Sun.COM *
48023SPhil.Kirk@Sun.COM * The contents of this file are subject to the terms of the
58023SPhil.Kirk@Sun.COM * Common Development and Distribution License (the "License").
68023SPhil.Kirk@Sun.COM * You may not use this file except in compliance with the License.
78023SPhil.Kirk@Sun.COM *
88023SPhil.Kirk@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98023SPhil.Kirk@Sun.COM * or http://www.opensolaris.org/os/licensing.
108023SPhil.Kirk@Sun.COM * See the License for the specific language governing permissions
118023SPhil.Kirk@Sun.COM * and limitations under the License.
128023SPhil.Kirk@Sun.COM *
138023SPhil.Kirk@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
148023SPhil.Kirk@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158023SPhil.Kirk@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
168023SPhil.Kirk@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
178023SPhil.Kirk@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
188023SPhil.Kirk@Sun.COM *
198023SPhil.Kirk@Sun.COM * CDDL HEADER END
208023SPhil.Kirk@Sun.COM */
218023SPhil.Kirk@Sun.COM
228023SPhil.Kirk@Sun.COM /*
238485SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
248023SPhil.Kirk@Sun.COM * Use is subject to license terms.
258023SPhil.Kirk@Sun.COM */
268023SPhil.Kirk@Sun.COM
278023SPhil.Kirk@Sun.COM /*
288023SPhil.Kirk@Sun.COM * The ipnet device defined here provides access to packets at the IP layer. To
298023SPhil.Kirk@Sun.COM * provide access to packets at this layer it registers a callback function in
308023SPhil.Kirk@Sun.COM * the ip module and when there are open instances of the device ip will pass
318023SPhil.Kirk@Sun.COM * packets into the device. Packets from ip are passed on the input, output and
328023SPhil.Kirk@Sun.COM * loopback paths. Internally the module returns to ip as soon as possible by
338023SPhil.Kirk@Sun.COM * deferring processing using a taskq.
348023SPhil.Kirk@Sun.COM *
358023SPhil.Kirk@Sun.COM * Management of the devices in /dev/ipnet/ is handled by the devname
368023SPhil.Kirk@Sun.COM * filesystem and use of the neti interfaces. This module registers for NIC
378023SPhil.Kirk@Sun.COM * events using the neti framework so that when IP interfaces are bought up,
388023SPhil.Kirk@Sun.COM * taken down etc. the ipnet module is notified and its view of the interfaces
398023SPhil.Kirk@Sun.COM * configured on the system adjusted. On attach, the module gets an initial
408023SPhil.Kirk@Sun.COM * view of the system again using the neti framework but as it has already
418023SPhil.Kirk@Sun.COM * registered for IP interface events, it is still up-to-date with any changes.
428023SPhil.Kirk@Sun.COM */
438023SPhil.Kirk@Sun.COM
448023SPhil.Kirk@Sun.COM #include <sys/types.h>
458023SPhil.Kirk@Sun.COM #include <sys/conf.h>
468023SPhil.Kirk@Sun.COM #include <sys/cred.h>
478023SPhil.Kirk@Sun.COM #include <sys/stat.h>
488023SPhil.Kirk@Sun.COM #include <sys/ddi.h>
498023SPhil.Kirk@Sun.COM #include <sys/sunddi.h>
508023SPhil.Kirk@Sun.COM #include <sys/modctl.h>
518023SPhil.Kirk@Sun.COM #include <sys/dlpi.h>
528023SPhil.Kirk@Sun.COM #include <sys/strsun.h>
538023SPhil.Kirk@Sun.COM #include <sys/id_space.h>
548023SPhil.Kirk@Sun.COM #include <sys/kmem.h>
558023SPhil.Kirk@Sun.COM #include <sys/mkdev.h>
568023SPhil.Kirk@Sun.COM #include <sys/neti.h>
578023SPhil.Kirk@Sun.COM #include <net/if.h>
588023SPhil.Kirk@Sun.COM #include <sys/errno.h>
598023SPhil.Kirk@Sun.COM #include <sys/list.h>
608023SPhil.Kirk@Sun.COM #include <sys/ksynch.h>
618023SPhil.Kirk@Sun.COM #include <sys/hook_event.h>
6210639SDarren.Reed@Sun.COM #include <sys/sdt.h>
638023SPhil.Kirk@Sun.COM #include <sys/stropts.h>
648023SPhil.Kirk@Sun.COM #include <sys/sysmacros.h>
658023SPhil.Kirk@Sun.COM #include <inet/ip.h>
6610639SDarren.Reed@Sun.COM #include <inet/ip_if.h>
678023SPhil.Kirk@Sun.COM #include <inet/ip_multi.h>
688023SPhil.Kirk@Sun.COM #include <inet/ip6.h>
698023SPhil.Kirk@Sun.COM #include <inet/ipnet.h>
7010639SDarren.Reed@Sun.COM #include <net/bpf.h>
7110639SDarren.Reed@Sun.COM #include <net/bpfdesc.h>
7210639SDarren.Reed@Sun.COM #include <net/dlt.h>
738023SPhil.Kirk@Sun.COM
748023SPhil.Kirk@Sun.COM static struct module_info ipnet_minfo = {
758023SPhil.Kirk@Sun.COM 1, /* mi_idnum */
768023SPhil.Kirk@Sun.COM "ipnet", /* mi_idname */
778023SPhil.Kirk@Sun.COM 0, /* mi_minpsz */
788023SPhil.Kirk@Sun.COM INFPSZ, /* mi_maxpsz */
798023SPhil.Kirk@Sun.COM 2048, /* mi_hiwat */
808023SPhil.Kirk@Sun.COM 0 /* mi_lowat */
818023SPhil.Kirk@Sun.COM };
828023SPhil.Kirk@Sun.COM
838023SPhil.Kirk@Sun.COM /*
848023SPhil.Kirk@Sun.COM * List to hold static view of ipnetif_t's on the system. This is needed to
858023SPhil.Kirk@Sun.COM * avoid holding the lock protecting the avl tree of ipnetif's over the
868023SPhil.Kirk@Sun.COM * callback into the dev filesystem.
878023SPhil.Kirk@Sun.COM */
888023SPhil.Kirk@Sun.COM typedef struct ipnetif_cbdata {
898023SPhil.Kirk@Sun.COM char ic_ifname[LIFNAMSIZ];
908023SPhil.Kirk@Sun.COM dev_t ic_dev;
918023SPhil.Kirk@Sun.COM list_node_t ic_next;
928023SPhil.Kirk@Sun.COM } ipnetif_cbdata_t;
938023SPhil.Kirk@Sun.COM
948023SPhil.Kirk@Sun.COM /*
958023SPhil.Kirk@Sun.COM * Convenience enumerated type for ipnet_accept(). It describes the
968023SPhil.Kirk@Sun.COM * properties of a given ipnet_addrp_t relative to a single ipnet_t
978023SPhil.Kirk@Sun.COM * client stream. The values represent whether the address is ...
988023SPhil.Kirk@Sun.COM */
998023SPhil.Kirk@Sun.COM typedef enum {
1008023SPhil.Kirk@Sun.COM IPNETADDR_MYADDR, /* an address on my ipnetif_t. */
1018023SPhil.Kirk@Sun.COM IPNETADDR_MBCAST, /* a multicast or broadcast address. */
1028023SPhil.Kirk@Sun.COM IPNETADDR_UNKNOWN /* none of the above. */
1038023SPhil.Kirk@Sun.COM } ipnet_addrtype_t;
1048023SPhil.Kirk@Sun.COM
1058023SPhil.Kirk@Sun.COM /* Argument used for the ipnet_nicevent_taskq callback. */
1068023SPhil.Kirk@Sun.COM typedef struct ipnet_nicevent_s {
1078023SPhil.Kirk@Sun.COM nic_event_t ipne_event;
1088023SPhil.Kirk@Sun.COM net_handle_t ipne_protocol;
1098023SPhil.Kirk@Sun.COM netstackid_t ipne_stackid;
1108023SPhil.Kirk@Sun.COM uint64_t ipne_ifindex;
1118023SPhil.Kirk@Sun.COM uint64_t ipne_lifindex;
1128023SPhil.Kirk@Sun.COM char ipne_ifname[LIFNAMSIZ];
1138023SPhil.Kirk@Sun.COM } ipnet_nicevent_t;
1148023SPhil.Kirk@Sun.COM
1158023SPhil.Kirk@Sun.COM static dev_info_t *ipnet_dip;
1168023SPhil.Kirk@Sun.COM static major_t ipnet_major;
1178023SPhil.Kirk@Sun.COM static ddi_taskq_t *ipnet_taskq; /* taskq for packets */
1188023SPhil.Kirk@Sun.COM static ddi_taskq_t *ipnet_nicevent_taskq; /* taskq for NIC events */
1198023SPhil.Kirk@Sun.COM static id_space_t *ipnet_minor_space;
1208023SPhil.Kirk@Sun.COM static const int IPNET_MINOR_LO = 1; /* minor number for /dev/lo0 */
1218023SPhil.Kirk@Sun.COM static const int IPNET_MINOR_MIN = 2; /* start of dynamic minors */
1228023SPhil.Kirk@Sun.COM static dl_info_ack_t ipnet_infoack = IPNET_INFO_ACK_INIT;
1238023SPhil.Kirk@Sun.COM static ipnet_acceptfn_t ipnet_accept, ipnet_loaccept;
12410639SDarren.Reed@Sun.COM static bpf_itap_fn_t ipnet_itap;
1258023SPhil.Kirk@Sun.COM
1268023SPhil.Kirk@Sun.COM static void ipnet_input(mblk_t *);
1278023SPhil.Kirk@Sun.COM static int ipnet_wput(queue_t *, mblk_t *);
1288023SPhil.Kirk@Sun.COM static int ipnet_rsrv(queue_t *);
1298023SPhil.Kirk@Sun.COM static int ipnet_open(queue_t *, dev_t *, int, int, cred_t *);
1308023SPhil.Kirk@Sun.COM static int ipnet_close(queue_t *);
1318023SPhil.Kirk@Sun.COM static void ipnet_ioctl(queue_t *, mblk_t *);
1328023SPhil.Kirk@Sun.COM static void ipnet_iocdata(queue_t *, mblk_t *);
1338023SPhil.Kirk@Sun.COM static void ipnet_wputnondata(queue_t *, mblk_t *);
1348023SPhil.Kirk@Sun.COM static int ipnet_attach(dev_info_t *, ddi_attach_cmd_t);
1358023SPhil.Kirk@Sun.COM static int ipnet_detach(dev_info_t *, ddi_detach_cmd_t);
1368023SPhil.Kirk@Sun.COM static int ipnet_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1378023SPhil.Kirk@Sun.COM static void ipnet_inforeq(queue_t *q, mblk_t *mp);
1388023SPhil.Kirk@Sun.COM static void ipnet_bindreq(queue_t *q, mblk_t *mp);
1398023SPhil.Kirk@Sun.COM static void ipnet_unbindreq(queue_t *q, mblk_t *mp);
1408023SPhil.Kirk@Sun.COM static void ipnet_dlpromisconreq(queue_t *q, mblk_t *mp);
1418023SPhil.Kirk@Sun.COM static void ipnet_dlpromiscoffreq(queue_t *q, mblk_t *mp);
1428023SPhil.Kirk@Sun.COM static int ipnet_join_allmulti(ipnetif_t *, ipnet_stack_t *);
1438023SPhil.Kirk@Sun.COM static void ipnet_leave_allmulti(ipnetif_t *, ipnet_stack_t *);
1448023SPhil.Kirk@Sun.COM static int ipnet_nicevent_cb(hook_event_token_t, hook_data_t, void *);
1458023SPhil.Kirk@Sun.COM static void ipnet_nicevent_task(void *);
14610639SDarren.Reed@Sun.COM static ipnetif_t *ipnetif_create(const char *, uint64_t, ipnet_stack_t *,
14710639SDarren.Reed@Sun.COM uint64_t);
14810639SDarren.Reed@Sun.COM static void ipnetif_remove(ipnetif_t *, ipnet_stack_t *);
1498023SPhil.Kirk@Sun.COM static ipnetif_addr_t *ipnet_match_lif(ipnetif_t *, lif_if_t, boolean_t);
15010639SDarren.Reed@Sun.COM static ipnetif_t *ipnetif_getby_index(uint64_t, ipnet_stack_t *);
15110639SDarren.Reed@Sun.COM static ipnetif_t *ipnetif_getby_dev(dev_t, ipnet_stack_t *);
15210639SDarren.Reed@Sun.COM static boolean_t ipnetif_in_zone(ipnetif_t *, zoneid_t, ipnet_stack_t *);
15310639SDarren.Reed@Sun.COM static void ipnetif_zonecheck(ipnetif_t *, ipnet_stack_t *);
1548023SPhil.Kirk@Sun.COM static int ipnet_populate_if(net_handle_t, ipnet_stack_t *, boolean_t);
15510639SDarren.Reed@Sun.COM static int ipnetif_compare_name(const void *, const void *);
15610639SDarren.Reed@Sun.COM static int ipnetif_compare_name_zone(const void *, const void *);
15710639SDarren.Reed@Sun.COM static int ipnetif_compare_index(const void *, const void *);
1588023SPhil.Kirk@Sun.COM static void ipnet_add_ifaddr(uint64_t, ipnetif_t *, net_handle_t);
1598023SPhil.Kirk@Sun.COM static void ipnet_delete_ifaddr(ipnetif_addr_t *, ipnetif_t *, boolean_t);
1608023SPhil.Kirk@Sun.COM static void ipnetif_refhold(ipnetif_t *);
1618023SPhil.Kirk@Sun.COM static void ipnetif_refrele(ipnetif_t *);
1628023SPhil.Kirk@Sun.COM static void ipnet_walkers_inc(ipnet_stack_t *);
1638023SPhil.Kirk@Sun.COM static void ipnet_walkers_dec(ipnet_stack_t *);
1648023SPhil.Kirk@Sun.COM static void ipnet_register_netihook(ipnet_stack_t *);
1658023SPhil.Kirk@Sun.COM static void *ipnet_stack_init(netstackid_t, netstack_t *);
1668023SPhil.Kirk@Sun.COM static void ipnet_stack_fini(netstackid_t, void *);
16710639SDarren.Reed@Sun.COM static void ipnet_dispatch(void *);
16810639SDarren.Reed@Sun.COM static int ipobs_bounce_func(hook_event_token_t, hook_data_t, void *);
16910639SDarren.Reed@Sun.COM static int ipnet_bpf_bounce(hook_event_token_t, hook_data_t, void *);
17010639SDarren.Reed@Sun.COM static ipnetif_t *ipnetif_clone_create(ipnetif_t *, zoneid_t);
17110639SDarren.Reed@Sun.COM static void ipnetif_clone_release(ipnetif_t *);
1728023SPhil.Kirk@Sun.COM
1738023SPhil.Kirk@Sun.COM static struct qinit ipnet_rinit = {
1748023SPhil.Kirk@Sun.COM NULL, /* qi_putp */
1758023SPhil.Kirk@Sun.COM ipnet_rsrv, /* qi_srvp */
1768023SPhil.Kirk@Sun.COM ipnet_open, /* qi_qopen */
1778023SPhil.Kirk@Sun.COM ipnet_close, /* qi_qclose */
1788023SPhil.Kirk@Sun.COM NULL, /* qi_qadmin */
1798023SPhil.Kirk@Sun.COM &ipnet_minfo, /* qi_minfo */
1808023SPhil.Kirk@Sun.COM };
1818023SPhil.Kirk@Sun.COM
1828023SPhil.Kirk@Sun.COM static struct qinit ipnet_winit = {
1838023SPhil.Kirk@Sun.COM ipnet_wput, /* qi_putp */
1848023SPhil.Kirk@Sun.COM NULL, /* qi_srvp */
1858023SPhil.Kirk@Sun.COM NULL, /* qi_qopen */
1868023SPhil.Kirk@Sun.COM NULL, /* qi_qclose */
1878023SPhil.Kirk@Sun.COM NULL, /* qi_qadmin */
1888023SPhil.Kirk@Sun.COM &ipnet_minfo, /* qi_minfo */
1898023SPhil.Kirk@Sun.COM };
1908023SPhil.Kirk@Sun.COM
1918023SPhil.Kirk@Sun.COM static struct streamtab ipnet_info = {
1928023SPhil.Kirk@Sun.COM &ipnet_rinit, &ipnet_winit
1938023SPhil.Kirk@Sun.COM };
1948023SPhil.Kirk@Sun.COM
1958023SPhil.Kirk@Sun.COM DDI_DEFINE_STREAM_OPS(ipnet_ops, nulldev, nulldev, ipnet_attach,
1968023SPhil.Kirk@Sun.COM ipnet_detach, nodev, ipnet_devinfo, D_MP | D_MTPERMOD, &ipnet_info,
1978023SPhil.Kirk@Sun.COM ddi_quiesce_not_supported);
1988023SPhil.Kirk@Sun.COM
1998023SPhil.Kirk@Sun.COM static struct modldrv modldrv = {
2008023SPhil.Kirk@Sun.COM &mod_driverops,
2018023SPhil.Kirk@Sun.COM "STREAMS ipnet driver",
2028023SPhil.Kirk@Sun.COM &ipnet_ops
2038023SPhil.Kirk@Sun.COM };
2048023SPhil.Kirk@Sun.COM
2058023SPhil.Kirk@Sun.COM static struct modlinkage modlinkage = {
2068023SPhil.Kirk@Sun.COM MODREV_1, &modldrv, NULL
2078023SPhil.Kirk@Sun.COM };
2088023SPhil.Kirk@Sun.COM
2098023SPhil.Kirk@Sun.COM /*
21010639SDarren.Reed@Sun.COM * This structure contains the template data (names and type) that is
21110639SDarren.Reed@Sun.COM * copied, in bulk, into the new kstats structure created by net_kstat_create.
21210639SDarren.Reed@Sun.COM * No actual statistical information is stored in this instance of the
21310639SDarren.Reed@Sun.COM * ipnet_kstats_t structure.
21410639SDarren.Reed@Sun.COM */
21510639SDarren.Reed@Sun.COM static ipnet_kstats_t stats_template = {
21610639SDarren.Reed@Sun.COM { "duplicationFail", KSTAT_DATA_UINT64 },
21710639SDarren.Reed@Sun.COM { "dispatchOk", KSTAT_DATA_UINT64 },
21810639SDarren.Reed@Sun.COM { "dispatchFail", KSTAT_DATA_UINT64 },
21910639SDarren.Reed@Sun.COM { "dispatchHeaderDrop", KSTAT_DATA_UINT64 },
22010639SDarren.Reed@Sun.COM { "dispatchDupDrop", KSTAT_DATA_UINT64 },
22110639SDarren.Reed@Sun.COM { "dispatchDeliver", KSTAT_DATA_UINT64 },
22210639SDarren.Reed@Sun.COM { "acceptOk", KSTAT_DATA_UINT64 },
22310639SDarren.Reed@Sun.COM { "acceptFail", KSTAT_DATA_UINT64 }
22410639SDarren.Reed@Sun.COM };
22510639SDarren.Reed@Sun.COM
22610639SDarren.Reed@Sun.COM /*
2278023SPhil.Kirk@Sun.COM * Walk the list of physical interfaces on the machine, for each
2288023SPhil.Kirk@Sun.COM * interface create a new ipnetif_t and add any addresses to it. We
2298023SPhil.Kirk@Sun.COM * need to do the walk twice, once for IPv4 and once for IPv6.
2308023SPhil.Kirk@Sun.COM *
2318023SPhil.Kirk@Sun.COM * The interfaces are destroyed as part of ipnet_stack_fini() for each
2328023SPhil.Kirk@Sun.COM * stack. Note that we cannot do this initialization in
2338023SPhil.Kirk@Sun.COM * ipnet_stack_init(), since ipnet_stack_init() cannot fail.
2348023SPhil.Kirk@Sun.COM */
2358023SPhil.Kirk@Sun.COM static int
ipnetif_init(void)23610639SDarren.Reed@Sun.COM ipnetif_init(void)
2378023SPhil.Kirk@Sun.COM {
2388023SPhil.Kirk@Sun.COM netstack_handle_t nh;
2398023SPhil.Kirk@Sun.COM netstack_t *ns;
2408023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
2418023SPhil.Kirk@Sun.COM int ret = 0;
2428023SPhil.Kirk@Sun.COM
2438023SPhil.Kirk@Sun.COM netstack_next_init(&nh);
2448023SPhil.Kirk@Sun.COM while ((ns = netstack_next(&nh)) != NULL) {
2458023SPhil.Kirk@Sun.COM ips = ns->netstack_ipnet;
2468356SSebastien.Roy@Sun.COM if ((ret = ipnet_populate_if(ips->ips_ndv4, ips, B_FALSE)) == 0)
2478356SSebastien.Roy@Sun.COM ret = ipnet_populate_if(ips->ips_ndv6, ips, B_TRUE);
2488356SSebastien.Roy@Sun.COM netstack_rele(ns);
2498356SSebastien.Roy@Sun.COM if (ret != 0)
2508023SPhil.Kirk@Sun.COM break;
2518023SPhil.Kirk@Sun.COM }
2528023SPhil.Kirk@Sun.COM netstack_next_fini(&nh);
2538023SPhil.Kirk@Sun.COM return (ret);
2548023SPhil.Kirk@Sun.COM }
2558023SPhil.Kirk@Sun.COM
2568023SPhil.Kirk@Sun.COM /*
2578023SPhil.Kirk@Sun.COM * Standard module entry points.
2588023SPhil.Kirk@Sun.COM */
2598023SPhil.Kirk@Sun.COM int
_init(void)2608023SPhil.Kirk@Sun.COM _init(void)
2618023SPhil.Kirk@Sun.COM {
26210639SDarren.Reed@Sun.COM int ret;
26310639SDarren.Reed@Sun.COM boolean_t netstack_registered = B_FALSE;
2648023SPhil.Kirk@Sun.COM
2658023SPhil.Kirk@Sun.COM if ((ipnet_major = ddi_name_to_major("ipnet")) == (major_t)-1)
2668023SPhil.Kirk@Sun.COM return (ENODEV);
2678023SPhil.Kirk@Sun.COM ipnet_minor_space = id_space_create("ipnet_minor_space",
2688023SPhil.Kirk@Sun.COM IPNET_MINOR_MIN, MAXMIN32);
2698485SPeter.Memishian@Sun.COM
2708023SPhil.Kirk@Sun.COM /*
2718023SPhil.Kirk@Sun.COM * We call ddi_taskq_create() with nthread == 1 to ensure in-order
2728485SPeter.Memishian@Sun.COM * delivery of packets to clients. Note that we need to create the
2738485SPeter.Memishian@Sun.COM * taskqs before calling netstack_register() since ipnet_stack_init()
2748485SPeter.Memishian@Sun.COM * registers callbacks that use 'em.
2758023SPhil.Kirk@Sun.COM */
2768023SPhil.Kirk@Sun.COM ipnet_taskq = ddi_taskq_create(NULL, "ipnet", 1, TASKQ_DEFAULTPRI, 0);
2778023SPhil.Kirk@Sun.COM ipnet_nicevent_taskq = ddi_taskq_create(NULL, "ipnet_nic_event_queue",
2788023SPhil.Kirk@Sun.COM 1, TASKQ_DEFAULTPRI, 0);
2798023SPhil.Kirk@Sun.COM if (ipnet_taskq == NULL || ipnet_nicevent_taskq == NULL) {
2808023SPhil.Kirk@Sun.COM ret = ENOMEM;
2818023SPhil.Kirk@Sun.COM goto done;
2828023SPhil.Kirk@Sun.COM }
2838485SPeter.Memishian@Sun.COM
2848485SPeter.Memishian@Sun.COM netstack_register(NS_IPNET, ipnet_stack_init, NULL, ipnet_stack_fini);
2858485SPeter.Memishian@Sun.COM netstack_registered = B_TRUE;
2868485SPeter.Memishian@Sun.COM
28710639SDarren.Reed@Sun.COM if ((ret = ipnetif_init()) == 0)
2888023SPhil.Kirk@Sun.COM ret = mod_install(&modlinkage);
2898023SPhil.Kirk@Sun.COM done:
2908023SPhil.Kirk@Sun.COM if (ret != 0) {
2918023SPhil.Kirk@Sun.COM if (ipnet_taskq != NULL)
2928023SPhil.Kirk@Sun.COM ddi_taskq_destroy(ipnet_taskq);
2938023SPhil.Kirk@Sun.COM if (ipnet_nicevent_taskq != NULL)
2948023SPhil.Kirk@Sun.COM ddi_taskq_destroy(ipnet_nicevent_taskq);
2958485SPeter.Memishian@Sun.COM if (netstack_registered)
2968485SPeter.Memishian@Sun.COM netstack_unregister(NS_IPNET);
2978023SPhil.Kirk@Sun.COM id_space_destroy(ipnet_minor_space);
2988023SPhil.Kirk@Sun.COM }
2998023SPhil.Kirk@Sun.COM return (ret);
3008023SPhil.Kirk@Sun.COM }
3018023SPhil.Kirk@Sun.COM
3028023SPhil.Kirk@Sun.COM int
_fini(void)3038023SPhil.Kirk@Sun.COM _fini(void)
3048023SPhil.Kirk@Sun.COM {
30510639SDarren.Reed@Sun.COM int err;
3068023SPhil.Kirk@Sun.COM
3078023SPhil.Kirk@Sun.COM if ((err = mod_remove(&modlinkage)) != 0)
3088023SPhil.Kirk@Sun.COM return (err);
3098485SPeter.Memishian@Sun.COM
3108485SPeter.Memishian@Sun.COM netstack_unregister(NS_IPNET);
3118023SPhil.Kirk@Sun.COM ddi_taskq_destroy(ipnet_nicevent_taskq);
3128023SPhil.Kirk@Sun.COM ddi_taskq_destroy(ipnet_taskq);
3138023SPhil.Kirk@Sun.COM id_space_destroy(ipnet_minor_space);
3148023SPhil.Kirk@Sun.COM return (0);
3158023SPhil.Kirk@Sun.COM }
3168023SPhil.Kirk@Sun.COM
3178023SPhil.Kirk@Sun.COM int
_info(struct modinfo * modinfop)3188023SPhil.Kirk@Sun.COM _info(struct modinfo *modinfop)
3198023SPhil.Kirk@Sun.COM {
3208023SPhil.Kirk@Sun.COM return (mod_info(&modlinkage, modinfop));
3218023SPhil.Kirk@Sun.COM }
3228023SPhil.Kirk@Sun.COM
3238023SPhil.Kirk@Sun.COM static void
ipnet_register_netihook(ipnet_stack_t * ips)3248023SPhil.Kirk@Sun.COM ipnet_register_netihook(ipnet_stack_t *ips)
3258023SPhil.Kirk@Sun.COM {
3268023SPhil.Kirk@Sun.COM int ret;
3278356SSebastien.Roy@Sun.COM zoneid_t zoneid;
3288356SSebastien.Roy@Sun.COM netid_t netid;
3298023SPhil.Kirk@Sun.COM
3308023SPhil.Kirk@Sun.COM HOOK_INIT(ips->ips_nicevents, ipnet_nicevent_cb, "ipnet_nicevents",
3318023SPhil.Kirk@Sun.COM ips);
3328023SPhil.Kirk@Sun.COM
3338023SPhil.Kirk@Sun.COM /*
3348356SSebastien.Roy@Sun.COM * It is possible for an exclusive stack to be in the process of
3358356SSebastien.Roy@Sun.COM * shutting down here, and the netid and protocol lookups could fail
3368356SSebastien.Roy@Sun.COM * in that case.
3378023SPhil.Kirk@Sun.COM */
3388356SSebastien.Roy@Sun.COM zoneid = netstackid_to_zoneid(ips->ips_netstack->netstack_stackid);
3398356SSebastien.Roy@Sun.COM if ((netid = net_zoneidtonetid(zoneid)) == -1)
3408356SSebastien.Roy@Sun.COM return;
3418023SPhil.Kirk@Sun.COM
3428356SSebastien.Roy@Sun.COM if ((ips->ips_ndv4 = net_protocol_lookup(netid, NHF_INET)) != NULL) {
3438356SSebastien.Roy@Sun.COM if ((ret = net_hook_register(ips->ips_ndv4, NH_NIC_EVENTS,
3448356SSebastien.Roy@Sun.COM ips->ips_nicevents)) != 0) {
3458356SSebastien.Roy@Sun.COM VERIFY(net_protocol_release(ips->ips_ndv4) == 0);
3468356SSebastien.Roy@Sun.COM ips->ips_ndv4 = NULL;
3478356SSebastien.Roy@Sun.COM cmn_err(CE_WARN, "unable to register IPv4 netinfo hooks"
3488356SSebastien.Roy@Sun.COM " in zone %d: %d", zoneid, ret);
3498356SSebastien.Roy@Sun.COM }
3508023SPhil.Kirk@Sun.COM }
3518356SSebastien.Roy@Sun.COM if ((ips->ips_ndv6 = net_protocol_lookup(netid, NHF_INET6)) != NULL) {
3528356SSebastien.Roy@Sun.COM if ((ret = net_hook_register(ips->ips_ndv6, NH_NIC_EVENTS,
3538356SSebastien.Roy@Sun.COM ips->ips_nicevents)) != 0) {
3548356SSebastien.Roy@Sun.COM VERIFY(net_protocol_release(ips->ips_ndv6) == 0);
3558356SSebastien.Roy@Sun.COM ips->ips_ndv6 = NULL;
3568356SSebastien.Roy@Sun.COM cmn_err(CE_WARN, "unable to register IPv6 netinfo hooks"
3578356SSebastien.Roy@Sun.COM " in zone %d: %d", zoneid, ret);
3588356SSebastien.Roy@Sun.COM }
3598023SPhil.Kirk@Sun.COM }
36010639SDarren.Reed@Sun.COM
36110639SDarren.Reed@Sun.COM /*
36210639SDarren.Reed@Sun.COM * Create a local set of kstats for each zone.
36310639SDarren.Reed@Sun.COM */
36410639SDarren.Reed@Sun.COM ips->ips_kstatp = net_kstat_create(netid, "ipnet", 0, "ipnet_stats",
36510639SDarren.Reed@Sun.COM "misc", KSTAT_TYPE_NAMED,
36610639SDarren.Reed@Sun.COM sizeof (ipnet_kstats_t) / sizeof (kstat_named_t), 0);
36710639SDarren.Reed@Sun.COM if (ips->ips_kstatp != NULL) {
36810639SDarren.Reed@Sun.COM bcopy(&stats_template, &ips->ips_stats,
36910639SDarren.Reed@Sun.COM sizeof (ips->ips_stats));
37010639SDarren.Reed@Sun.COM ips->ips_kstatp->ks_data = &ips->ips_stats;
37110639SDarren.Reed@Sun.COM ips->ips_kstatp->ks_private =
37210639SDarren.Reed@Sun.COM (void *)(uintptr_t)ips->ips_netstack->netstack_stackid;
37310639SDarren.Reed@Sun.COM kstat_install(ips->ips_kstatp);
37410639SDarren.Reed@Sun.COM } else {
37510639SDarren.Reed@Sun.COM cmn_err(CE_WARN, "net_kstat_create(%s,%s,%s) failed",
37610639SDarren.Reed@Sun.COM "ipnet", "ipnet_stats", "misc");
37710639SDarren.Reed@Sun.COM }
3788023SPhil.Kirk@Sun.COM }
3798023SPhil.Kirk@Sun.COM
3808023SPhil.Kirk@Sun.COM /*
3818023SPhil.Kirk@Sun.COM * This function is called on attach to build an initial view of the
3828023SPhil.Kirk@Sun.COM * interfaces on the system. It will be called once for IPv4 and once
3838023SPhil.Kirk@Sun.COM * for IPv6, although there is only one ipnet interface for both IPv4
3848023SPhil.Kirk@Sun.COM * and IPv6 there are separate address lists.
3858023SPhil.Kirk@Sun.COM */
3868023SPhil.Kirk@Sun.COM static int
ipnet_populate_if(net_handle_t nd,ipnet_stack_t * ips,boolean_t isv6)3878023SPhil.Kirk@Sun.COM ipnet_populate_if(net_handle_t nd, ipnet_stack_t *ips, boolean_t isv6)
3888023SPhil.Kirk@Sun.COM {
38910639SDarren.Reed@Sun.COM phy_if_t phyif;
39010639SDarren.Reed@Sun.COM lif_if_t lif;
39110639SDarren.Reed@Sun.COM ipnetif_t *ipnetif;
39210639SDarren.Reed@Sun.COM char name[LIFNAMSIZ];
39310639SDarren.Reed@Sun.COM boolean_t new_if = B_FALSE;
39410639SDarren.Reed@Sun.COM uint64_t ifflags;
39510639SDarren.Reed@Sun.COM int ret = 0;
3968023SPhil.Kirk@Sun.COM
3978023SPhil.Kirk@Sun.COM /*
3988356SSebastien.Roy@Sun.COM * If ipnet_register_netihook() was unable to initialize this
3998356SSebastien.Roy@Sun.COM * stack's net_handle_t, then we cannot populate any interface
4008356SSebastien.Roy@Sun.COM * information. This usually happens when we attempted to
4018356SSebastien.Roy@Sun.COM * grab a net_handle_t as a stack was shutting down. We don't
4028356SSebastien.Roy@Sun.COM * want to fail the entire _init() operation because of a
4038356SSebastien.Roy@Sun.COM * stack shutdown (other stacks will continue to work just
4048356SSebastien.Roy@Sun.COM * fine), so we silently return success here.
4058356SSebastien.Roy@Sun.COM */
4068356SSebastien.Roy@Sun.COM if (nd == NULL)
4078356SSebastien.Roy@Sun.COM return (0);
4088356SSebastien.Roy@Sun.COM
4098356SSebastien.Roy@Sun.COM /*
4108023SPhil.Kirk@Sun.COM * Make sure we're not processing NIC events during the
4118023SPhil.Kirk@Sun.COM * population of our interfaces and address lists.
4128023SPhil.Kirk@Sun.COM */
4138023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_event_lock);
4148023SPhil.Kirk@Sun.COM
4158023SPhil.Kirk@Sun.COM for (phyif = net_phygetnext(nd, 0); phyif != 0;
4168023SPhil.Kirk@Sun.COM phyif = net_phygetnext(nd, phyif)) {
4178023SPhil.Kirk@Sun.COM if (net_getifname(nd, phyif, name, LIFNAMSIZ) != 0)
4188023SPhil.Kirk@Sun.COM continue;
41910639SDarren.Reed@Sun.COM ifflags = 0;
42010639SDarren.Reed@Sun.COM (void) net_getlifflags(nd, phyif, 0, &ifflags);
42110639SDarren.Reed@Sun.COM if ((ipnetif = ipnetif_getby_index(phyif, ips)) == NULL) {
42210639SDarren.Reed@Sun.COM ipnetif = ipnetif_create(name, phyif, ips, ifflags);
4238023SPhil.Kirk@Sun.COM if (ipnetif == NULL) {
4248023SPhil.Kirk@Sun.COM ret = ENOMEM;
4258023SPhil.Kirk@Sun.COM goto done;
4268023SPhil.Kirk@Sun.COM }
4278023SPhil.Kirk@Sun.COM new_if = B_TRUE;
4288023SPhil.Kirk@Sun.COM }
4298023SPhil.Kirk@Sun.COM ipnetif->if_flags |=
4308023SPhil.Kirk@Sun.COM isv6 ? IPNETIF_IPV6PLUMBED : IPNETIF_IPV4PLUMBED;
4318023SPhil.Kirk@Sun.COM
4328023SPhil.Kirk@Sun.COM for (lif = net_lifgetnext(nd, phyif, 0); lif != 0;
4338023SPhil.Kirk@Sun.COM lif = net_lifgetnext(nd, phyif, lif)) {
4348023SPhil.Kirk@Sun.COM /*
4358023SPhil.Kirk@Sun.COM * Skip addresses that aren't up. We'll add
4368023SPhil.Kirk@Sun.COM * them when we receive an NE_LIF_UP event.
4378023SPhil.Kirk@Sun.COM */
4388023SPhil.Kirk@Sun.COM if (net_getlifflags(nd, phyif, lif, &ifflags) != 0 ||
4398023SPhil.Kirk@Sun.COM !(ifflags & IFF_UP))
4408023SPhil.Kirk@Sun.COM continue;
4418023SPhil.Kirk@Sun.COM /* Don't add it if we already have it. */
4428023SPhil.Kirk@Sun.COM if (ipnet_match_lif(ipnetif, lif, isv6) != NULL)
4438023SPhil.Kirk@Sun.COM continue;
4448023SPhil.Kirk@Sun.COM ipnet_add_ifaddr(lif, ipnetif, nd);
4458023SPhil.Kirk@Sun.COM }
4468023SPhil.Kirk@Sun.COM if (!new_if)
4478023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
4488023SPhil.Kirk@Sun.COM }
4498023SPhil.Kirk@Sun.COM
4508023SPhil.Kirk@Sun.COM done:
4518023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_event_lock);
4528023SPhil.Kirk@Sun.COM return (ret);
4538023SPhil.Kirk@Sun.COM }
4548023SPhil.Kirk@Sun.COM
4558023SPhil.Kirk@Sun.COM static int
ipnet_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)4568023SPhil.Kirk@Sun.COM ipnet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4578023SPhil.Kirk@Sun.COM {
4588023SPhil.Kirk@Sun.COM if (cmd != DDI_ATTACH)
4598023SPhil.Kirk@Sun.COM return (DDI_FAILURE);
4608023SPhil.Kirk@Sun.COM
4618023SPhil.Kirk@Sun.COM if (ddi_create_minor_node(dip, "lo0", S_IFCHR, IPNET_MINOR_LO,
4628023SPhil.Kirk@Sun.COM DDI_PSEUDO, 0) == DDI_FAILURE)
4638023SPhil.Kirk@Sun.COM return (DDI_FAILURE);
4648023SPhil.Kirk@Sun.COM
4658023SPhil.Kirk@Sun.COM ipnet_dip = dip;
4668023SPhil.Kirk@Sun.COM return (DDI_SUCCESS);
4678023SPhil.Kirk@Sun.COM }
4688023SPhil.Kirk@Sun.COM
4698023SPhil.Kirk@Sun.COM static int
ipnet_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4708023SPhil.Kirk@Sun.COM ipnet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4718023SPhil.Kirk@Sun.COM {
4728023SPhil.Kirk@Sun.COM if (cmd != DDI_DETACH)
4738023SPhil.Kirk@Sun.COM return (DDI_FAILURE);
4748023SPhil.Kirk@Sun.COM
4758023SPhil.Kirk@Sun.COM ASSERT(dip == ipnet_dip);
4768023SPhil.Kirk@Sun.COM ddi_remove_minor_node(ipnet_dip, NULL);
4778023SPhil.Kirk@Sun.COM ipnet_dip = NULL;
4788023SPhil.Kirk@Sun.COM return (DDI_SUCCESS);
4798023SPhil.Kirk@Sun.COM }
4808023SPhil.Kirk@Sun.COM
4818023SPhil.Kirk@Sun.COM /* ARGSUSED */
4828023SPhil.Kirk@Sun.COM static int
ipnet_devinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4838023SPhil.Kirk@Sun.COM ipnet_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4848023SPhil.Kirk@Sun.COM {
48510639SDarren.Reed@Sun.COM int error = DDI_FAILURE;
4868023SPhil.Kirk@Sun.COM
4878023SPhil.Kirk@Sun.COM switch (infocmd) {
4888023SPhil.Kirk@Sun.COM case DDI_INFO_DEVT2INSTANCE:
4898023SPhil.Kirk@Sun.COM *result = (void *)0;
4908023SPhil.Kirk@Sun.COM error = DDI_SUCCESS;
4918023SPhil.Kirk@Sun.COM break;
4928023SPhil.Kirk@Sun.COM case DDI_INFO_DEVT2DEVINFO:
4938023SPhil.Kirk@Sun.COM if (ipnet_dip != NULL) {
4948023SPhil.Kirk@Sun.COM *result = ipnet_dip;
4958023SPhil.Kirk@Sun.COM error = DDI_SUCCESS;
4968023SPhil.Kirk@Sun.COM }
4978023SPhil.Kirk@Sun.COM break;
4988023SPhil.Kirk@Sun.COM }
4998023SPhil.Kirk@Sun.COM return (error);
5008023SPhil.Kirk@Sun.COM }
5018023SPhil.Kirk@Sun.COM
5028023SPhil.Kirk@Sun.COM /* ARGSUSED */
5038023SPhil.Kirk@Sun.COM static int
ipnet_open(queue_t * rq,dev_t * dev,int oflag,int sflag,cred_t * crp)5048023SPhil.Kirk@Sun.COM ipnet_open(queue_t *rq, dev_t *dev, int oflag, int sflag, cred_t *crp)
5058023SPhil.Kirk@Sun.COM {
5068023SPhil.Kirk@Sun.COM ipnet_t *ipnet;
5078023SPhil.Kirk@Sun.COM netstack_t *ns = NULL;
5088023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
5098023SPhil.Kirk@Sun.COM int err = 0;
5108023SPhil.Kirk@Sun.COM zoneid_t zoneid = crgetzoneid(crp);
5118023SPhil.Kirk@Sun.COM
5128023SPhil.Kirk@Sun.COM /*
5138023SPhil.Kirk@Sun.COM * If the system is labeled, only the global zone is allowed to open
5148023SPhil.Kirk@Sun.COM * IP observability nodes.
5158023SPhil.Kirk@Sun.COM */
5168023SPhil.Kirk@Sun.COM if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
5178023SPhil.Kirk@Sun.COM return (EACCES);
5188023SPhil.Kirk@Sun.COM
5198023SPhil.Kirk@Sun.COM /* We don't support open as a module */
5208023SPhil.Kirk@Sun.COM if (sflag & MODOPEN)
5218023SPhil.Kirk@Sun.COM return (ENOTSUP);
5228023SPhil.Kirk@Sun.COM
5238023SPhil.Kirk@Sun.COM /* This driver is self-cloning, we don't support re-open. */
5248023SPhil.Kirk@Sun.COM if (rq->q_ptr != NULL)
5258023SPhil.Kirk@Sun.COM return (EBUSY);
5268023SPhil.Kirk@Sun.COM
5278023SPhil.Kirk@Sun.COM if ((ipnet = kmem_zalloc(sizeof (*ipnet), KM_NOSLEEP)) == NULL)
5288023SPhil.Kirk@Sun.COM return (ENOMEM);
5298023SPhil.Kirk@Sun.COM
5308023SPhil.Kirk@Sun.COM VERIFY((ns = netstack_find_by_cred(crp)) != NULL);
5318023SPhil.Kirk@Sun.COM ips = ns->netstack_ipnet;
5328023SPhil.Kirk@Sun.COM
5338023SPhil.Kirk@Sun.COM rq->q_ptr = WR(rq)->q_ptr = ipnet;
5348023SPhil.Kirk@Sun.COM ipnet->ipnet_rq = rq;
5358023SPhil.Kirk@Sun.COM ipnet->ipnet_minor = (minor_t)id_alloc(ipnet_minor_space);
5368023SPhil.Kirk@Sun.COM ipnet->ipnet_zoneid = zoneid;
5378023SPhil.Kirk@Sun.COM ipnet->ipnet_dlstate = DL_UNBOUND;
5388023SPhil.Kirk@Sun.COM ipnet->ipnet_ns = ns;
5398023SPhil.Kirk@Sun.COM
5408023SPhil.Kirk@Sun.COM /*
5418023SPhil.Kirk@Sun.COM * We need to hold ips_event_lock here as any NE_LIF_DOWN events need
5428023SPhil.Kirk@Sun.COM * to be processed after ipnet_if is set and the ipnet_t has been
5438023SPhil.Kirk@Sun.COM * inserted in the ips_str_list.
5448023SPhil.Kirk@Sun.COM */
5458023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_event_lock);
5468023SPhil.Kirk@Sun.COM if (getminor(*dev) == IPNET_MINOR_LO) {
5478023SPhil.Kirk@Sun.COM ipnet->ipnet_flags |= IPNET_LOMODE;
5488023SPhil.Kirk@Sun.COM ipnet->ipnet_acceptfn = ipnet_loaccept;
5498023SPhil.Kirk@Sun.COM } else {
5508023SPhil.Kirk@Sun.COM ipnet->ipnet_acceptfn = ipnet_accept;
55110639SDarren.Reed@Sun.COM ipnet->ipnet_if = ipnetif_getby_dev(*dev, ips);
5528023SPhil.Kirk@Sun.COM if (ipnet->ipnet_if == NULL ||
55310639SDarren.Reed@Sun.COM !ipnetif_in_zone(ipnet->ipnet_if, zoneid, ips)) {
5548023SPhil.Kirk@Sun.COM err = ENODEV;
5558023SPhil.Kirk@Sun.COM goto done;
5568023SPhil.Kirk@Sun.COM }
5578023SPhil.Kirk@Sun.COM }
5588023SPhil.Kirk@Sun.COM
5598023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_walkers_lock);
5608023SPhil.Kirk@Sun.COM while (ips->ips_walkers_cnt != 0)
5618023SPhil.Kirk@Sun.COM cv_wait(&ips->ips_walkers_cv, &ips->ips_walkers_lock);
5628023SPhil.Kirk@Sun.COM list_insert_head(&ips->ips_str_list, ipnet);
5638023SPhil.Kirk@Sun.COM *dev = makedevice(getmajor(*dev), ipnet->ipnet_minor);
5648023SPhil.Kirk@Sun.COM qprocson(rq);
5658023SPhil.Kirk@Sun.COM
5668023SPhil.Kirk@Sun.COM /*
5678023SPhil.Kirk@Sun.COM * Only register our callback if we're the first open client; we call
5688023SPhil.Kirk@Sun.COM * unregister in close() for the last open client.
5698023SPhil.Kirk@Sun.COM */
5708023SPhil.Kirk@Sun.COM if (list_head(&ips->ips_str_list) == list_tail(&ips->ips_str_list))
57110639SDarren.Reed@Sun.COM ips->ips_hook = ipobs_register_hook(ns, ipnet_input);
5728023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_walkers_lock);
5738023SPhil.Kirk@Sun.COM
5748023SPhil.Kirk@Sun.COM done:
5758023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_event_lock);
5768023SPhil.Kirk@Sun.COM if (err != 0) {
5778023SPhil.Kirk@Sun.COM netstack_rele(ns);
5788023SPhil.Kirk@Sun.COM id_free(ipnet_minor_space, ipnet->ipnet_minor);
5798023SPhil.Kirk@Sun.COM if (ipnet->ipnet_if != NULL)
5808023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnet->ipnet_if);
5818023SPhil.Kirk@Sun.COM kmem_free(ipnet, sizeof (*ipnet));
5828023SPhil.Kirk@Sun.COM }
5838023SPhil.Kirk@Sun.COM return (err);
5848023SPhil.Kirk@Sun.COM }
5858023SPhil.Kirk@Sun.COM
5868023SPhil.Kirk@Sun.COM static int
ipnet_close(queue_t * rq)5878023SPhil.Kirk@Sun.COM ipnet_close(queue_t *rq)
5888023SPhil.Kirk@Sun.COM {
5898023SPhil.Kirk@Sun.COM ipnet_t *ipnet = rq->q_ptr;
5908023SPhil.Kirk@Sun.COM ipnet_stack_t *ips = ipnet->ipnet_ns->netstack_ipnet;
5918023SPhil.Kirk@Sun.COM
5928023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_PHYS)
5938023SPhil.Kirk@Sun.COM ipnet_leave_allmulti(ipnet->ipnet_if, ips);
5948023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_MULTI)
5958023SPhil.Kirk@Sun.COM ipnet_leave_allmulti(ipnet->ipnet_if, ips);
5968023SPhil.Kirk@Sun.COM
5978023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_walkers_lock);
5988023SPhil.Kirk@Sun.COM while (ips->ips_walkers_cnt != 0)
5998023SPhil.Kirk@Sun.COM cv_wait(&ips->ips_walkers_cv, &ips->ips_walkers_lock);
6008023SPhil.Kirk@Sun.COM
6018023SPhil.Kirk@Sun.COM qprocsoff(rq);
6028023SPhil.Kirk@Sun.COM
6038023SPhil.Kirk@Sun.COM list_remove(&ips->ips_str_list, ipnet);
6048023SPhil.Kirk@Sun.COM if (ipnet->ipnet_if != NULL)
6058023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnet->ipnet_if);
6068023SPhil.Kirk@Sun.COM id_free(ipnet_minor_space, ipnet->ipnet_minor);
6078023SPhil.Kirk@Sun.COM
60810639SDarren.Reed@Sun.COM if (list_is_empty(&ips->ips_str_list)) {
60910639SDarren.Reed@Sun.COM ipobs_unregister_hook(ips->ips_netstack, ips->ips_hook);
61010639SDarren.Reed@Sun.COM ips->ips_hook = NULL;
61110639SDarren.Reed@Sun.COM }
61210639SDarren.Reed@Sun.COM
61310639SDarren.Reed@Sun.COM kmem_free(ipnet, sizeof (*ipnet));
6148023SPhil.Kirk@Sun.COM
6158023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_walkers_lock);
6168023SPhil.Kirk@Sun.COM netstack_rele(ips->ips_netstack);
6178023SPhil.Kirk@Sun.COM return (0);
6188023SPhil.Kirk@Sun.COM }
6198023SPhil.Kirk@Sun.COM
6208023SPhil.Kirk@Sun.COM static int
ipnet_wput(queue_t * q,mblk_t * mp)6218023SPhil.Kirk@Sun.COM ipnet_wput(queue_t *q, mblk_t *mp)
6228023SPhil.Kirk@Sun.COM {
6238023SPhil.Kirk@Sun.COM switch (mp->b_datap->db_type) {
6248023SPhil.Kirk@Sun.COM case M_FLUSH:
6258023SPhil.Kirk@Sun.COM if (*mp->b_rptr & FLUSHW) {
6268023SPhil.Kirk@Sun.COM flushq(q, FLUSHDATA);
6278023SPhil.Kirk@Sun.COM *mp->b_rptr &= ~FLUSHW;
6288023SPhil.Kirk@Sun.COM }
6298023SPhil.Kirk@Sun.COM if (*mp->b_rptr & FLUSHR)
6308023SPhil.Kirk@Sun.COM qreply(q, mp);
6318023SPhil.Kirk@Sun.COM else
6328023SPhil.Kirk@Sun.COM freemsg(mp);
6338023SPhil.Kirk@Sun.COM break;
6348023SPhil.Kirk@Sun.COM case M_PROTO:
6358023SPhil.Kirk@Sun.COM case M_PCPROTO:
6368023SPhil.Kirk@Sun.COM ipnet_wputnondata(q, mp);
6378023SPhil.Kirk@Sun.COM break;
6388023SPhil.Kirk@Sun.COM case M_IOCTL:
6398023SPhil.Kirk@Sun.COM ipnet_ioctl(q, mp);
6408023SPhil.Kirk@Sun.COM break;
6418023SPhil.Kirk@Sun.COM case M_IOCDATA:
6428023SPhil.Kirk@Sun.COM ipnet_iocdata(q, mp);
6438023SPhil.Kirk@Sun.COM break;
6448023SPhil.Kirk@Sun.COM default:
6458023SPhil.Kirk@Sun.COM freemsg(mp);
6468023SPhil.Kirk@Sun.COM break;
6478023SPhil.Kirk@Sun.COM }
6488023SPhil.Kirk@Sun.COM return (0);
6498023SPhil.Kirk@Sun.COM }
6508023SPhil.Kirk@Sun.COM
6518023SPhil.Kirk@Sun.COM static int
ipnet_rsrv(queue_t * q)6528023SPhil.Kirk@Sun.COM ipnet_rsrv(queue_t *q)
6538023SPhil.Kirk@Sun.COM {
65410639SDarren.Reed@Sun.COM mblk_t *mp;
6558023SPhil.Kirk@Sun.COM
6568023SPhil.Kirk@Sun.COM while ((mp = getq(q)) != NULL) {
6578023SPhil.Kirk@Sun.COM ASSERT(DB_TYPE(mp) == M_DATA);
6588023SPhil.Kirk@Sun.COM if (canputnext(q)) {
6598023SPhil.Kirk@Sun.COM putnext(q, mp);
6608023SPhil.Kirk@Sun.COM } else {
6618023SPhil.Kirk@Sun.COM (void) putbq(q, mp);
6628023SPhil.Kirk@Sun.COM break;
6638023SPhil.Kirk@Sun.COM }
6648023SPhil.Kirk@Sun.COM }
6658023SPhil.Kirk@Sun.COM return (0);
6668023SPhil.Kirk@Sun.COM }
6678023SPhil.Kirk@Sun.COM
6688023SPhil.Kirk@Sun.COM static void
ipnet_ioctl(queue_t * q,mblk_t * mp)6698023SPhil.Kirk@Sun.COM ipnet_ioctl(queue_t *q, mblk_t *mp)
6708023SPhil.Kirk@Sun.COM {
67110639SDarren.Reed@Sun.COM struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
6728023SPhil.Kirk@Sun.COM
6738023SPhil.Kirk@Sun.COM switch (iocp->ioc_cmd) {
6748023SPhil.Kirk@Sun.COM case DLIOCRAW:
6758023SPhil.Kirk@Sun.COM miocack(q, mp, 0, 0);
6768023SPhil.Kirk@Sun.COM break;
6778023SPhil.Kirk@Sun.COM case DLIOCIPNETINFO:
6788023SPhil.Kirk@Sun.COM if (iocp->ioc_count == TRANSPARENT) {
6798023SPhil.Kirk@Sun.COM mcopyin(mp, NULL, sizeof (uint_t), NULL);
6808023SPhil.Kirk@Sun.COM qreply(q, mp);
6818023SPhil.Kirk@Sun.COM break;
6828023SPhil.Kirk@Sun.COM }
6838023SPhil.Kirk@Sun.COM /* Fallthrough, we don't support I_STR with DLIOCIPNETINFO. */
6848023SPhil.Kirk@Sun.COM default:
6858023SPhil.Kirk@Sun.COM miocnak(q, mp, 0, EINVAL);
6868023SPhil.Kirk@Sun.COM break;
6878023SPhil.Kirk@Sun.COM }
6888023SPhil.Kirk@Sun.COM }
6898023SPhil.Kirk@Sun.COM
6908023SPhil.Kirk@Sun.COM static void
ipnet_iocdata(queue_t * q,mblk_t * mp)6918023SPhil.Kirk@Sun.COM ipnet_iocdata(queue_t *q, mblk_t *mp)
6928023SPhil.Kirk@Sun.COM {
6938023SPhil.Kirk@Sun.COM struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
69410639SDarren.Reed@Sun.COM ipnet_t *ipnet = q->q_ptr;
6958023SPhil.Kirk@Sun.COM
6968023SPhil.Kirk@Sun.COM switch (iocp->ioc_cmd) {
6978023SPhil.Kirk@Sun.COM case DLIOCIPNETINFO:
6988023SPhil.Kirk@Sun.COM if (*(int *)mp->b_cont->b_rptr == 1)
6998023SPhil.Kirk@Sun.COM ipnet->ipnet_flags |= IPNET_INFO;
7008023SPhil.Kirk@Sun.COM else if (*(int *)mp->b_cont->b_rptr == 0)
7018023SPhil.Kirk@Sun.COM ipnet->ipnet_flags &= ~IPNET_INFO;
7028023SPhil.Kirk@Sun.COM else
7038023SPhil.Kirk@Sun.COM goto iocnak;
7048023SPhil.Kirk@Sun.COM miocack(q, mp, 0, DL_IPNETINFO_VERSION);
7058023SPhil.Kirk@Sun.COM break;
7068023SPhil.Kirk@Sun.COM default:
70710639SDarren.Reed@Sun.COM iocnak:
7088023SPhil.Kirk@Sun.COM miocnak(q, mp, 0, EINVAL);
7098023SPhil.Kirk@Sun.COM break;
7108023SPhil.Kirk@Sun.COM }
7118023SPhil.Kirk@Sun.COM }
7128023SPhil.Kirk@Sun.COM
7138023SPhil.Kirk@Sun.COM static void
ipnet_wputnondata(queue_t * q,mblk_t * mp)7148023SPhil.Kirk@Sun.COM ipnet_wputnondata(queue_t *q, mblk_t *mp)
7158023SPhil.Kirk@Sun.COM {
7168023SPhil.Kirk@Sun.COM union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
7178023SPhil.Kirk@Sun.COM t_uscalar_t prim = dlp->dl_primitive;
7188023SPhil.Kirk@Sun.COM
7198023SPhil.Kirk@Sun.COM switch (prim) {
7208023SPhil.Kirk@Sun.COM case DL_INFO_REQ:
7218023SPhil.Kirk@Sun.COM ipnet_inforeq(q, mp);
7228023SPhil.Kirk@Sun.COM break;
7238023SPhil.Kirk@Sun.COM case DL_UNBIND_REQ:
7248023SPhil.Kirk@Sun.COM ipnet_unbindreq(q, mp);
7258023SPhil.Kirk@Sun.COM break;
7268023SPhil.Kirk@Sun.COM case DL_BIND_REQ:
7278023SPhil.Kirk@Sun.COM ipnet_bindreq(q, mp);
7288023SPhil.Kirk@Sun.COM break;
7298023SPhil.Kirk@Sun.COM case DL_PROMISCON_REQ:
7308023SPhil.Kirk@Sun.COM ipnet_dlpromisconreq(q, mp);
7318023SPhil.Kirk@Sun.COM break;
7328023SPhil.Kirk@Sun.COM case DL_PROMISCOFF_REQ:
7338023SPhil.Kirk@Sun.COM ipnet_dlpromiscoffreq(q, mp);
7348023SPhil.Kirk@Sun.COM break;
7358023SPhil.Kirk@Sun.COM case DL_UNITDATA_REQ:
7368023SPhil.Kirk@Sun.COM case DL_DETACH_REQ:
7378023SPhil.Kirk@Sun.COM case DL_PHYS_ADDR_REQ:
7388023SPhil.Kirk@Sun.COM case DL_SET_PHYS_ADDR_REQ:
7398023SPhil.Kirk@Sun.COM case DL_ENABMULTI_REQ:
7408023SPhil.Kirk@Sun.COM case DL_DISABMULTI_REQ:
7418023SPhil.Kirk@Sun.COM case DL_ATTACH_REQ:
7428023SPhil.Kirk@Sun.COM dlerrorack(q, mp, prim, DL_UNSUPPORTED, 0);
7438023SPhil.Kirk@Sun.COM break;
7448023SPhil.Kirk@Sun.COM default:
7458023SPhil.Kirk@Sun.COM dlerrorack(q, mp, prim, DL_BADPRIM, 0);
7468023SPhil.Kirk@Sun.COM break;
7478023SPhil.Kirk@Sun.COM }
7488023SPhil.Kirk@Sun.COM }
7498023SPhil.Kirk@Sun.COM
7508023SPhil.Kirk@Sun.COM static void
ipnet_inforeq(queue_t * q,mblk_t * mp)7518023SPhil.Kirk@Sun.COM ipnet_inforeq(queue_t *q, mblk_t *mp)
7528023SPhil.Kirk@Sun.COM {
7538023SPhil.Kirk@Sun.COM dl_info_ack_t *dlip;
7548023SPhil.Kirk@Sun.COM size_t size = sizeof (dl_info_ack_t) + sizeof (ushort_t);
7558023SPhil.Kirk@Sun.COM
7568023SPhil.Kirk@Sun.COM if (MBLKL(mp) < DL_INFO_REQ_SIZE) {
7578023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_INFO_REQ, DL_BADPRIM, 0);
7588023SPhil.Kirk@Sun.COM return;
7598023SPhil.Kirk@Sun.COM }
7608023SPhil.Kirk@Sun.COM
7618023SPhil.Kirk@Sun.COM if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_INFO_ACK)) == NULL)
7628023SPhil.Kirk@Sun.COM return;
7638023SPhil.Kirk@Sun.COM
7648023SPhil.Kirk@Sun.COM dlip = (dl_info_ack_t *)mp->b_rptr;
7658023SPhil.Kirk@Sun.COM *dlip = ipnet_infoack;
7668023SPhil.Kirk@Sun.COM qreply(q, mp);
7678023SPhil.Kirk@Sun.COM }
7688023SPhil.Kirk@Sun.COM
7698023SPhil.Kirk@Sun.COM static void
ipnet_bindreq(queue_t * q,mblk_t * mp)7708023SPhil.Kirk@Sun.COM ipnet_bindreq(queue_t *q, mblk_t *mp)
7718023SPhil.Kirk@Sun.COM {
77210639SDarren.Reed@Sun.COM union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
77310639SDarren.Reed@Sun.COM ipnet_t *ipnet = q->q_ptr;
7748023SPhil.Kirk@Sun.COM
7758023SPhil.Kirk@Sun.COM if (MBLKL(mp) < DL_BIND_REQ_SIZE) {
7768023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_BIND_REQ, DL_BADPRIM, 0);
7778023SPhil.Kirk@Sun.COM return;
7788023SPhil.Kirk@Sun.COM }
7798023SPhil.Kirk@Sun.COM
78010639SDarren.Reed@Sun.COM switch (dlp->bind_req.dl_sap) {
78110639SDarren.Reed@Sun.COM case 0 :
78210639SDarren.Reed@Sun.COM ipnet->ipnet_family = AF_UNSPEC;
78310639SDarren.Reed@Sun.COM break;
78410639SDarren.Reed@Sun.COM case IPV4_VERSION :
78510639SDarren.Reed@Sun.COM ipnet->ipnet_family = AF_INET;
78610639SDarren.Reed@Sun.COM break;
78710639SDarren.Reed@Sun.COM case IPV6_VERSION :
78810639SDarren.Reed@Sun.COM ipnet->ipnet_family = AF_INET6;
78910639SDarren.Reed@Sun.COM break;
79010639SDarren.Reed@Sun.COM default :
7918023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_BIND_REQ, DL_BADSAP, 0);
79210639SDarren.Reed@Sun.COM return;
79310639SDarren.Reed@Sun.COM /*NOTREACHED*/
7948023SPhil.Kirk@Sun.COM }
79510639SDarren.Reed@Sun.COM
79610639SDarren.Reed@Sun.COM ipnet->ipnet_dlstate = DL_IDLE;
79710639SDarren.Reed@Sun.COM dlbindack(q, mp, dlp->bind_req.dl_sap, 0, 0, 0, 0);
7988023SPhil.Kirk@Sun.COM }
7998023SPhil.Kirk@Sun.COM
8008023SPhil.Kirk@Sun.COM static void
ipnet_unbindreq(queue_t * q,mblk_t * mp)8018023SPhil.Kirk@Sun.COM ipnet_unbindreq(queue_t *q, mblk_t *mp)
8028023SPhil.Kirk@Sun.COM {
8038023SPhil.Kirk@Sun.COM ipnet_t *ipnet = q->q_ptr;
8048023SPhil.Kirk@Sun.COM
8058023SPhil.Kirk@Sun.COM if (MBLKL(mp) < DL_UNBIND_REQ_SIZE) {
8068023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_UNBIND_REQ, DL_BADPRIM, 0);
8078023SPhil.Kirk@Sun.COM return;
8088023SPhil.Kirk@Sun.COM }
8098023SPhil.Kirk@Sun.COM
8108023SPhil.Kirk@Sun.COM if (ipnet->ipnet_dlstate != DL_IDLE) {
8118023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
8128023SPhil.Kirk@Sun.COM } else {
8138023SPhil.Kirk@Sun.COM ipnet->ipnet_dlstate = DL_UNBOUND;
81410639SDarren.Reed@Sun.COM ipnet->ipnet_family = AF_UNSPEC;
8158023SPhil.Kirk@Sun.COM dlokack(q, mp, DL_UNBIND_REQ);
8168023SPhil.Kirk@Sun.COM }
8178023SPhil.Kirk@Sun.COM }
8188023SPhil.Kirk@Sun.COM
8198023SPhil.Kirk@Sun.COM static void
ipnet_dlpromisconreq(queue_t * q,mblk_t * mp)8208023SPhil.Kirk@Sun.COM ipnet_dlpromisconreq(queue_t *q, mblk_t *mp)
8218023SPhil.Kirk@Sun.COM {
8228023SPhil.Kirk@Sun.COM ipnet_t *ipnet = q->q_ptr;
8238023SPhil.Kirk@Sun.COM t_uscalar_t level;
8248023SPhil.Kirk@Sun.COM int err;
8258023SPhil.Kirk@Sun.COM
8268023SPhil.Kirk@Sun.COM if (MBLKL(mp) < DL_PROMISCON_REQ_SIZE) {
8278023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
8288023SPhil.Kirk@Sun.COM return;
8298023SPhil.Kirk@Sun.COM }
8308023SPhil.Kirk@Sun.COM
8318023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_LOMODE) {
8328023SPhil.Kirk@Sun.COM dlokack(q, mp, DL_PROMISCON_REQ);
8338023SPhil.Kirk@Sun.COM return;
8348023SPhil.Kirk@Sun.COM }
8358023SPhil.Kirk@Sun.COM
8368023SPhil.Kirk@Sun.COM level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
8378023SPhil.Kirk@Sun.COM if (level == DL_PROMISC_PHYS || level == DL_PROMISC_MULTI) {
8388023SPhil.Kirk@Sun.COM if ((err = ipnet_join_allmulti(ipnet->ipnet_if,
8398023SPhil.Kirk@Sun.COM ipnet->ipnet_ns->netstack_ipnet)) != 0) {
8408023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCON_REQ, DL_SYSERR, err);
8418023SPhil.Kirk@Sun.COM return;
8428023SPhil.Kirk@Sun.COM }
8438023SPhil.Kirk@Sun.COM }
8448023SPhil.Kirk@Sun.COM
8458023SPhil.Kirk@Sun.COM switch (level) {
8468023SPhil.Kirk@Sun.COM case DL_PROMISC_PHYS:
8478023SPhil.Kirk@Sun.COM ipnet->ipnet_flags |= IPNET_PROMISC_PHYS;
8488023SPhil.Kirk@Sun.COM break;
8498023SPhil.Kirk@Sun.COM case DL_PROMISC_SAP:
8508023SPhil.Kirk@Sun.COM ipnet->ipnet_flags |= IPNET_PROMISC_SAP;
8518023SPhil.Kirk@Sun.COM break;
8528023SPhil.Kirk@Sun.COM case DL_PROMISC_MULTI:
8538023SPhil.Kirk@Sun.COM ipnet->ipnet_flags |= IPNET_PROMISC_MULTI;
8548023SPhil.Kirk@Sun.COM break;
8558023SPhil.Kirk@Sun.COM default:
8568023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCON_REQ, DL_BADPRIM, 0);
8578023SPhil.Kirk@Sun.COM return;
8588023SPhil.Kirk@Sun.COM }
8598023SPhil.Kirk@Sun.COM
8608023SPhil.Kirk@Sun.COM dlokack(q, mp, DL_PROMISCON_REQ);
8618023SPhil.Kirk@Sun.COM }
8628023SPhil.Kirk@Sun.COM
8638023SPhil.Kirk@Sun.COM static void
ipnet_dlpromiscoffreq(queue_t * q,mblk_t * mp)8648023SPhil.Kirk@Sun.COM ipnet_dlpromiscoffreq(queue_t *q, mblk_t *mp)
8658023SPhil.Kirk@Sun.COM {
8668023SPhil.Kirk@Sun.COM ipnet_t *ipnet = q->q_ptr;
8678023SPhil.Kirk@Sun.COM t_uscalar_t level;
8688023SPhil.Kirk@Sun.COM uint16_t orig_ipnet_flags = ipnet->ipnet_flags;
8698023SPhil.Kirk@Sun.COM
8708023SPhil.Kirk@Sun.COM if (MBLKL(mp) < DL_PROMISCOFF_REQ_SIZE) {
8718023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
8728023SPhil.Kirk@Sun.COM return;
8738023SPhil.Kirk@Sun.COM }
8748023SPhil.Kirk@Sun.COM
8758023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_LOMODE) {
8768023SPhil.Kirk@Sun.COM dlokack(q, mp, DL_PROMISCOFF_REQ);
8778023SPhil.Kirk@Sun.COM return;
8788023SPhil.Kirk@Sun.COM }
8798023SPhil.Kirk@Sun.COM
8808023SPhil.Kirk@Sun.COM level = ((dl_promiscon_req_t *)mp->b_rptr)->dl_level;
8818023SPhil.Kirk@Sun.COM switch (level) {
8828023SPhil.Kirk@Sun.COM case DL_PROMISC_PHYS:
8838023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_PHYS)
8848023SPhil.Kirk@Sun.COM ipnet->ipnet_flags &= ~IPNET_PROMISC_PHYS;
8858023SPhil.Kirk@Sun.COM break;
8868023SPhil.Kirk@Sun.COM case DL_PROMISC_SAP:
8878023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_SAP)
8888023SPhil.Kirk@Sun.COM ipnet->ipnet_flags &= ~IPNET_PROMISC_SAP;
8898023SPhil.Kirk@Sun.COM break;
8908023SPhil.Kirk@Sun.COM case DL_PROMISC_MULTI:
8918023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_MULTI)
8928023SPhil.Kirk@Sun.COM ipnet->ipnet_flags &= ~IPNET_PROMISC_MULTI;
8938023SPhil.Kirk@Sun.COM break;
8948023SPhil.Kirk@Sun.COM default:
8958023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_BADPRIM, 0);
8968023SPhil.Kirk@Sun.COM return;
8978023SPhil.Kirk@Sun.COM }
8988023SPhil.Kirk@Sun.COM
8998023SPhil.Kirk@Sun.COM if (orig_ipnet_flags == ipnet->ipnet_flags) {
9008023SPhil.Kirk@Sun.COM dlerrorack(q, mp, DL_PROMISCOFF_REQ, DL_NOTENAB, 0);
9018023SPhil.Kirk@Sun.COM return;
9028023SPhil.Kirk@Sun.COM }
9038023SPhil.Kirk@Sun.COM
9048023SPhil.Kirk@Sun.COM if (level == DL_PROMISC_PHYS || level == DL_PROMISC_MULTI) {
9058023SPhil.Kirk@Sun.COM ipnet_leave_allmulti(ipnet->ipnet_if,
9068023SPhil.Kirk@Sun.COM ipnet->ipnet_ns->netstack_ipnet);
9078023SPhil.Kirk@Sun.COM }
9088023SPhil.Kirk@Sun.COM
9098023SPhil.Kirk@Sun.COM dlokack(q, mp, DL_PROMISCOFF_REQ);
9108023SPhil.Kirk@Sun.COM }
9118023SPhil.Kirk@Sun.COM
9128023SPhil.Kirk@Sun.COM static int
ipnet_join_allmulti(ipnetif_t * ipnetif,ipnet_stack_t * ips)9138023SPhil.Kirk@Sun.COM ipnet_join_allmulti(ipnetif_t *ipnetif, ipnet_stack_t *ips)
9148023SPhil.Kirk@Sun.COM {
9158023SPhil.Kirk@Sun.COM int err = 0;
9168023SPhil.Kirk@Sun.COM ip_stack_t *ipst = ips->ips_netstack->netstack_ip;
9178023SPhil.Kirk@Sun.COM uint64_t index = ipnetif->if_index;
9188023SPhil.Kirk@Sun.COM
9198023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_event_lock);
9208023SPhil.Kirk@Sun.COM if (ipnetif->if_multicnt == 0) {
9218023SPhil.Kirk@Sun.COM ASSERT((ipnetif->if_flags &
9228023SPhil.Kirk@Sun.COM (IPNETIF_IPV4ALLMULTI | IPNETIF_IPV6ALLMULTI)) == 0);
9238023SPhil.Kirk@Sun.COM if (ipnetif->if_flags & IPNETIF_IPV4PLUMBED) {
9248023SPhil.Kirk@Sun.COM err = ip_join_allmulti(index, B_FALSE, ipst);
9258023SPhil.Kirk@Sun.COM if (err != 0)
9268023SPhil.Kirk@Sun.COM goto done;
9278023SPhil.Kirk@Sun.COM ipnetif->if_flags |= IPNETIF_IPV4ALLMULTI;
9288023SPhil.Kirk@Sun.COM }
9298023SPhil.Kirk@Sun.COM if (ipnetif->if_flags & IPNETIF_IPV6PLUMBED) {
9308023SPhil.Kirk@Sun.COM err = ip_join_allmulti(index, B_TRUE, ipst);
9318023SPhil.Kirk@Sun.COM if (err != 0 &&
9328023SPhil.Kirk@Sun.COM (ipnetif->if_flags & IPNETIF_IPV4ALLMULTI)) {
9338023SPhil.Kirk@Sun.COM (void) ip_leave_allmulti(index, B_FALSE, ipst);
9348023SPhil.Kirk@Sun.COM ipnetif->if_flags &= ~IPNETIF_IPV4ALLMULTI;
9358023SPhil.Kirk@Sun.COM goto done;
9368023SPhil.Kirk@Sun.COM }
9378023SPhil.Kirk@Sun.COM ipnetif->if_flags |= IPNETIF_IPV6ALLMULTI;
9388023SPhil.Kirk@Sun.COM }
9398023SPhil.Kirk@Sun.COM }
9408023SPhil.Kirk@Sun.COM ipnetif->if_multicnt++;
9418023SPhil.Kirk@Sun.COM
9428023SPhil.Kirk@Sun.COM done:
9438023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_event_lock);
9448023SPhil.Kirk@Sun.COM return (err);
9458023SPhil.Kirk@Sun.COM }
9468023SPhil.Kirk@Sun.COM
9478023SPhil.Kirk@Sun.COM static void
ipnet_leave_allmulti(ipnetif_t * ipnetif,ipnet_stack_t * ips)9488023SPhil.Kirk@Sun.COM ipnet_leave_allmulti(ipnetif_t *ipnetif, ipnet_stack_t *ips)
9498023SPhil.Kirk@Sun.COM {
9508023SPhil.Kirk@Sun.COM int err;
9518023SPhil.Kirk@Sun.COM ip_stack_t *ipst = ips->ips_netstack->netstack_ip;
9528023SPhil.Kirk@Sun.COM uint64_t index = ipnetif->if_index;
9538023SPhil.Kirk@Sun.COM
9548023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_event_lock);
9558023SPhil.Kirk@Sun.COM ASSERT(ipnetif->if_multicnt != 0);
9568023SPhil.Kirk@Sun.COM if (--ipnetif->if_multicnt == 0) {
9578023SPhil.Kirk@Sun.COM if (ipnetif->if_flags & IPNETIF_IPV4ALLMULTI) {
9588023SPhil.Kirk@Sun.COM err = ip_leave_allmulti(index, B_FALSE, ipst);
9598023SPhil.Kirk@Sun.COM ASSERT(err == 0 || err == ENODEV);
9608023SPhil.Kirk@Sun.COM ipnetif->if_flags &= ~IPNETIF_IPV4ALLMULTI;
9618023SPhil.Kirk@Sun.COM }
9628023SPhil.Kirk@Sun.COM if (ipnetif->if_flags & IPNETIF_IPV6ALLMULTI) {
9638023SPhil.Kirk@Sun.COM err = ip_leave_allmulti(index, B_TRUE, ipst);
9648023SPhil.Kirk@Sun.COM ASSERT(err == 0 || err == ENODEV);
9658023SPhil.Kirk@Sun.COM ipnetif->if_flags &= ~IPNETIF_IPV6ALLMULTI;
9668023SPhil.Kirk@Sun.COM }
9678023SPhil.Kirk@Sun.COM }
9688023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_event_lock);
9698023SPhil.Kirk@Sun.COM }
9708023SPhil.Kirk@Sun.COM
97110639SDarren.Reed@Sun.COM /*
97210639SDarren.Reed@Sun.COM * Allocate a new mblk_t and put a dl_ipnetinfo_t in it.
97310639SDarren.Reed@Sun.COM * The structure it copies the header information from,
97410639SDarren.Reed@Sun.COM * hook_pkt_observe_t, is constructed using network byte
97510639SDarren.Reed@Sun.COM * order in ipobs_hook(), so there is no conversion here.
97610639SDarren.Reed@Sun.COM */
9778023SPhil.Kirk@Sun.COM static mblk_t *
ipnet_addheader(hook_pkt_observe_t * hdr,mblk_t * mp)97810639SDarren.Reed@Sun.COM ipnet_addheader(hook_pkt_observe_t *hdr, mblk_t *mp)
9798023SPhil.Kirk@Sun.COM {
9808023SPhil.Kirk@Sun.COM mblk_t *dlhdr;
9818023SPhil.Kirk@Sun.COM dl_ipnetinfo_t *dl;
9828023SPhil.Kirk@Sun.COM
9838023SPhil.Kirk@Sun.COM if ((dlhdr = allocb(sizeof (dl_ipnetinfo_t), BPRI_HI)) == NULL) {
9848023SPhil.Kirk@Sun.COM freemsg(mp);
9858023SPhil.Kirk@Sun.COM return (NULL);
9868023SPhil.Kirk@Sun.COM }
9878023SPhil.Kirk@Sun.COM dl = (dl_ipnetinfo_t *)dlhdr->b_rptr;
9888023SPhil.Kirk@Sun.COM dl->dli_version = DL_IPNETINFO_VERSION;
98910639SDarren.Reed@Sun.COM dl->dli_family = hdr->hpo_family;
99010639SDarren.Reed@Sun.COM dl->dli_htype = hdr->hpo_htype;
99110639SDarren.Reed@Sun.COM dl->dli_pktlen = hdr->hpo_pktlen;
99210639SDarren.Reed@Sun.COM dl->dli_ifindex = hdr->hpo_ifindex;
99310639SDarren.Reed@Sun.COM dl->dli_grifindex = hdr->hpo_grifindex;
99410639SDarren.Reed@Sun.COM dl->dli_zsrc = hdr->hpo_zsrc;
99510639SDarren.Reed@Sun.COM dl->dli_zdst = hdr->hpo_zdst;
9968023SPhil.Kirk@Sun.COM dlhdr->b_wptr += sizeof (*dl);
9978023SPhil.Kirk@Sun.COM dlhdr->b_cont = mp;
9988023SPhil.Kirk@Sun.COM
9998023SPhil.Kirk@Sun.COM return (dlhdr);
10008023SPhil.Kirk@Sun.COM }
10018023SPhil.Kirk@Sun.COM
10028023SPhil.Kirk@Sun.COM static ipnet_addrtype_t
ipnet_get_addrtype(ipnet_t * ipnet,ipnet_addrp_t * addr)10038023SPhil.Kirk@Sun.COM ipnet_get_addrtype(ipnet_t *ipnet, ipnet_addrp_t *addr)
10048023SPhil.Kirk@Sun.COM {
10058023SPhil.Kirk@Sun.COM list_t *list;
10068023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif = ipnet->ipnet_if;
10078023SPhil.Kirk@Sun.COM ipnetif_addr_t *ifaddr;
10088023SPhil.Kirk@Sun.COM ipnet_addrtype_t addrtype = IPNETADDR_UNKNOWN;
10098023SPhil.Kirk@Sun.COM
10108023SPhil.Kirk@Sun.COM /* First check if the address is multicast or limited broadcast. */
10118023SPhil.Kirk@Sun.COM switch (addr->iap_family) {
10128023SPhil.Kirk@Sun.COM case AF_INET:
10138023SPhil.Kirk@Sun.COM if (CLASSD(*(addr->iap_addr4)) ||
10148023SPhil.Kirk@Sun.COM *(addr->iap_addr4) == INADDR_BROADCAST)
10158023SPhil.Kirk@Sun.COM return (IPNETADDR_MBCAST);
10168023SPhil.Kirk@Sun.COM break;
10178023SPhil.Kirk@Sun.COM case AF_INET6:
10188023SPhil.Kirk@Sun.COM if (IN6_IS_ADDR_MULTICAST(addr->iap_addr6))
10198023SPhil.Kirk@Sun.COM return (IPNETADDR_MBCAST);
10208023SPhil.Kirk@Sun.COM break;
10218023SPhil.Kirk@Sun.COM }
10228023SPhil.Kirk@Sun.COM
10238023SPhil.Kirk@Sun.COM /*
10248023SPhil.Kirk@Sun.COM * Walk the address list to see if the address belongs to our
10258023SPhil.Kirk@Sun.COM * interface or is one of our subnet broadcast addresses.
10268023SPhil.Kirk@Sun.COM */
10278023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
10288023SPhil.Kirk@Sun.COM list = (addr->iap_family == AF_INET) ?
10298023SPhil.Kirk@Sun.COM &ipnetif->if_ip4addr_list : &ipnetif->if_ip6addr_list;
10308023SPhil.Kirk@Sun.COM for (ifaddr = list_head(list);
10318023SPhil.Kirk@Sun.COM ifaddr != NULL && addrtype == IPNETADDR_UNKNOWN;
10328023SPhil.Kirk@Sun.COM ifaddr = list_next(list, ifaddr)) {
10338023SPhil.Kirk@Sun.COM /*
10348023SPhil.Kirk@Sun.COM * If we're not in the global zone, then only look at
10358023SPhil.Kirk@Sun.COM * addresses in our zone.
10368023SPhil.Kirk@Sun.COM */
10378023SPhil.Kirk@Sun.COM if (ipnet->ipnet_zoneid != GLOBAL_ZONEID &&
10388023SPhil.Kirk@Sun.COM ipnet->ipnet_zoneid != ifaddr->ifa_zone)
10398023SPhil.Kirk@Sun.COM continue;
10408023SPhil.Kirk@Sun.COM switch (addr->iap_family) {
10418023SPhil.Kirk@Sun.COM case AF_INET:
10428023SPhil.Kirk@Sun.COM if (ifaddr->ifa_ip4addr != INADDR_ANY &&
10438023SPhil.Kirk@Sun.COM *(addr->iap_addr4) == ifaddr->ifa_ip4addr)
10448023SPhil.Kirk@Sun.COM addrtype = IPNETADDR_MYADDR;
10458023SPhil.Kirk@Sun.COM else if (ifaddr->ifa_brdaddr != INADDR_ANY &&
10468023SPhil.Kirk@Sun.COM *(addr->iap_addr4) == ifaddr->ifa_brdaddr)
10478023SPhil.Kirk@Sun.COM addrtype = IPNETADDR_MBCAST;
10488023SPhil.Kirk@Sun.COM break;
10498023SPhil.Kirk@Sun.COM case AF_INET6:
10508023SPhil.Kirk@Sun.COM if (IN6_ARE_ADDR_EQUAL(addr->iap_addr6,
10518023SPhil.Kirk@Sun.COM &ifaddr->ifa_ip6addr))
10528023SPhil.Kirk@Sun.COM addrtype = IPNETADDR_MYADDR;
10538023SPhil.Kirk@Sun.COM break;
10548023SPhil.Kirk@Sun.COM }
10558023SPhil.Kirk@Sun.COM }
10568023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
10578023SPhil.Kirk@Sun.COM
10588023SPhil.Kirk@Sun.COM return (addrtype);
10598023SPhil.Kirk@Sun.COM }
10608023SPhil.Kirk@Sun.COM
10618023SPhil.Kirk@Sun.COM /*
106210639SDarren.Reed@Sun.COM * Verify if the packet contained in hdr should be passed up to the
10638023SPhil.Kirk@Sun.COM * ipnet client stream.
10648023SPhil.Kirk@Sun.COM */
10658023SPhil.Kirk@Sun.COM static boolean_t
ipnet_accept(ipnet_t * ipnet,hook_pkt_observe_t * hdr,ipnet_addrp_t * src,ipnet_addrp_t * dst)106610639SDarren.Reed@Sun.COM ipnet_accept(ipnet_t *ipnet, hook_pkt_observe_t *hdr, ipnet_addrp_t *src,
10678023SPhil.Kirk@Sun.COM ipnet_addrp_t *dst)
10688023SPhil.Kirk@Sun.COM {
10698485SPeter.Memishian@Sun.COM boolean_t obsif;
10708023SPhil.Kirk@Sun.COM uint64_t ifindex = ipnet->ipnet_if->if_index;
107110639SDarren.Reed@Sun.COM ipnet_addrtype_t srctype;
107210639SDarren.Reed@Sun.COM ipnet_addrtype_t dsttype;
10738023SPhil.Kirk@Sun.COM
10748023SPhil.Kirk@Sun.COM srctype = ipnet_get_addrtype(ipnet, src);
10758023SPhil.Kirk@Sun.COM dsttype = ipnet_get_addrtype(ipnet, dst);
10768023SPhil.Kirk@Sun.COM
10778023SPhil.Kirk@Sun.COM /*
10788485SPeter.Memishian@Sun.COM * If the packet's ifindex matches ours, or the packet's group ifindex
10798485SPeter.Memishian@Sun.COM * matches ours, it's on the interface we're observing. (Thus,
10808485SPeter.Memishian@Sun.COM * observing on the group ifindex matches all ifindexes in the group.)
10818485SPeter.Memishian@Sun.COM */
108210639SDarren.Reed@Sun.COM obsif = (ntohl(hdr->hpo_ifindex) == ifindex ||
108310639SDarren.Reed@Sun.COM ntohl(hdr->hpo_grifindex) == ifindex);
108410639SDarren.Reed@Sun.COM
108510639SDarren.Reed@Sun.COM DTRACE_PROBE5(ipnet_accept__addr,
108610639SDarren.Reed@Sun.COM ipnet_addrtype_t, srctype, ipnet_addrp_t *, src,
108710639SDarren.Reed@Sun.COM ipnet_addrtype_t, dsttype, ipnet_addrp_t *, dst,
108810639SDarren.Reed@Sun.COM boolean_t, obsif);
10898485SPeter.Memishian@Sun.COM
10908485SPeter.Memishian@Sun.COM /*
10918023SPhil.Kirk@Sun.COM * Do not allow an ipnet stream to see packets that are not from or to
10928023SPhil.Kirk@Sun.COM * its zone. The exception is when zones are using the shared stack
10938023SPhil.Kirk@Sun.COM * model. In this case, streams in the global zone have visibility
10948023SPhil.Kirk@Sun.COM * into other shared-stack zones, and broadcast and multicast traffic
10958023SPhil.Kirk@Sun.COM * is visible by all zones in the stack.
10968023SPhil.Kirk@Sun.COM */
10978023SPhil.Kirk@Sun.COM if (ipnet->ipnet_zoneid != GLOBAL_ZONEID &&
10988023SPhil.Kirk@Sun.COM dsttype != IPNETADDR_MBCAST) {
109910639SDarren.Reed@Sun.COM if (ipnet->ipnet_zoneid != ntohl(hdr->hpo_zsrc) &&
110010639SDarren.Reed@Sun.COM ipnet->ipnet_zoneid != ntohl(hdr->hpo_zdst))
11018023SPhil.Kirk@Sun.COM return (B_FALSE);
11028023SPhil.Kirk@Sun.COM }
11038023SPhil.Kirk@Sun.COM
11048023SPhil.Kirk@Sun.COM /*
11058023SPhil.Kirk@Sun.COM * If DL_PROMISC_SAP isn't enabled, then the bound SAP must match the
11068023SPhil.Kirk@Sun.COM * packet's IP version.
11078023SPhil.Kirk@Sun.COM */
11088023SPhil.Kirk@Sun.COM if (!(ipnet->ipnet_flags & IPNET_PROMISC_SAP) &&
110910639SDarren.Reed@Sun.COM ipnet->ipnet_family != hdr->hpo_family)
11108023SPhil.Kirk@Sun.COM return (B_FALSE);
11118023SPhil.Kirk@Sun.COM
11128023SPhil.Kirk@Sun.COM /* If the destination address is ours, then accept the packet. */
11138023SPhil.Kirk@Sun.COM if (dsttype == IPNETADDR_MYADDR)
11148023SPhil.Kirk@Sun.COM return (B_TRUE);
11158023SPhil.Kirk@Sun.COM
11168023SPhil.Kirk@Sun.COM /*
11178023SPhil.Kirk@Sun.COM * If DL_PROMISC_PHYS is enabled, then we can see all packets that are
11188023SPhil.Kirk@Sun.COM * sent or received on the interface we're observing, or packets that
11198023SPhil.Kirk@Sun.COM * have our source address (this allows us to see packets we send).
11208023SPhil.Kirk@Sun.COM */
11218023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_PROMISC_PHYS) {
11228485SPeter.Memishian@Sun.COM if (srctype == IPNETADDR_MYADDR || obsif)
11238023SPhil.Kirk@Sun.COM return (B_TRUE);
11248023SPhil.Kirk@Sun.COM }
11258023SPhil.Kirk@Sun.COM
11268023SPhil.Kirk@Sun.COM /*
11278023SPhil.Kirk@Sun.COM * We accept multicast and broadcast packets transmitted or received
11288023SPhil.Kirk@Sun.COM * on the interface we're observing.
11298023SPhil.Kirk@Sun.COM */
11308485SPeter.Memishian@Sun.COM if (dsttype == IPNETADDR_MBCAST && obsif)
11318023SPhil.Kirk@Sun.COM return (B_TRUE);
11328023SPhil.Kirk@Sun.COM
11338023SPhil.Kirk@Sun.COM return (B_FALSE);
11348023SPhil.Kirk@Sun.COM }
11358023SPhil.Kirk@Sun.COM
11368023SPhil.Kirk@Sun.COM /*
113710639SDarren.Reed@Sun.COM * Verify if the packet contained in hdr should be passed up to the ipnet
11388023SPhil.Kirk@Sun.COM * client stream that's in IPNET_LOMODE.
11398023SPhil.Kirk@Sun.COM */
11408023SPhil.Kirk@Sun.COM /* ARGSUSED */
11418023SPhil.Kirk@Sun.COM static boolean_t
ipnet_loaccept(ipnet_t * ipnet,hook_pkt_observe_t * hdr,ipnet_addrp_t * src,ipnet_addrp_t * dst)114210639SDarren.Reed@Sun.COM ipnet_loaccept(ipnet_t *ipnet, hook_pkt_observe_t *hdr, ipnet_addrp_t *src,
11438023SPhil.Kirk@Sun.COM ipnet_addrp_t *dst)
11448023SPhil.Kirk@Sun.COM {
1145*11258SDarren.Reed@Sun.COM if (hdr->hpo_htype != htons(IPOBS_HOOK_LOCAL)) {
114610639SDarren.Reed@Sun.COM /*
114710639SDarren.Reed@Sun.COM * ipnet_if is only NULL for IPNET_MINOR_LO devices.
114810639SDarren.Reed@Sun.COM */
114910639SDarren.Reed@Sun.COM if (ipnet->ipnet_if == NULL)
115010639SDarren.Reed@Sun.COM return (B_FALSE);
115110639SDarren.Reed@Sun.COM }
11528023SPhil.Kirk@Sun.COM
11538023SPhil.Kirk@Sun.COM /*
11548023SPhil.Kirk@Sun.COM * An ipnet stream must not see packets that are not from/to its zone.
11558023SPhil.Kirk@Sun.COM */
11568023SPhil.Kirk@Sun.COM if (ipnet->ipnet_zoneid != GLOBAL_ZONEID) {
115710639SDarren.Reed@Sun.COM if (ipnet->ipnet_zoneid != ntohl(hdr->hpo_zsrc) &&
115810639SDarren.Reed@Sun.COM ipnet->ipnet_zoneid != ntohl(hdr->hpo_zdst))
11598023SPhil.Kirk@Sun.COM return (B_FALSE);
11608023SPhil.Kirk@Sun.COM }
11618023SPhil.Kirk@Sun.COM
116210639SDarren.Reed@Sun.COM return (ipnet->ipnet_family == AF_UNSPEC ||
116310639SDarren.Reed@Sun.COM ipnet->ipnet_family == hdr->hpo_family);
11648023SPhil.Kirk@Sun.COM }
11658023SPhil.Kirk@Sun.COM
11668023SPhil.Kirk@Sun.COM static void
ipnet_dispatch(void * arg)11678023SPhil.Kirk@Sun.COM ipnet_dispatch(void *arg)
11688023SPhil.Kirk@Sun.COM {
11698023SPhil.Kirk@Sun.COM mblk_t *mp = arg;
117010639SDarren.Reed@Sun.COM hook_pkt_observe_t *hdr = (hook_pkt_observe_t *)mp->b_rptr;
11718023SPhil.Kirk@Sun.COM ipnet_t *ipnet;
11728023SPhil.Kirk@Sun.COM mblk_t *netmp;
11738023SPhil.Kirk@Sun.COM list_t *list;
117410639SDarren.Reed@Sun.COM ipnet_stack_t *ips;
117510639SDarren.Reed@Sun.COM ipnet_addrp_t src;
117610639SDarren.Reed@Sun.COM ipnet_addrp_t dst;
117710639SDarren.Reed@Sun.COM
117810639SDarren.Reed@Sun.COM ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
11798023SPhil.Kirk@Sun.COM
118010639SDarren.Reed@Sun.COM netmp = hdr->hpo_pkt->b_cont;
118110639SDarren.Reed@Sun.COM src.iap_family = hdr->hpo_family;
118210639SDarren.Reed@Sun.COM dst.iap_family = hdr->hpo_family;
118310639SDarren.Reed@Sun.COM
118410639SDarren.Reed@Sun.COM if (hdr->hpo_family == AF_INET) {
118510639SDarren.Reed@Sun.COM src.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_src;
118610639SDarren.Reed@Sun.COM dst.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_dst;
11878023SPhil.Kirk@Sun.COM } else {
118810639SDarren.Reed@Sun.COM src.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_src;
118910639SDarren.Reed@Sun.COM dst.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_dst;
11908023SPhil.Kirk@Sun.COM }
11918023SPhil.Kirk@Sun.COM
11928023SPhil.Kirk@Sun.COM ipnet_walkers_inc(ips);
11938023SPhil.Kirk@Sun.COM
11948023SPhil.Kirk@Sun.COM list = &ips->ips_str_list;
11958023SPhil.Kirk@Sun.COM for (ipnet = list_head(list); ipnet != NULL;
11968023SPhil.Kirk@Sun.COM ipnet = list_next(list, ipnet)) {
119710639SDarren.Reed@Sun.COM if (!(*ipnet->ipnet_acceptfn)(ipnet, hdr, &src, &dst)) {
119810639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_acceptFail);
11998023SPhil.Kirk@Sun.COM continue;
120010639SDarren.Reed@Sun.COM }
120110639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_acceptOk);
12028023SPhil.Kirk@Sun.COM
12038023SPhil.Kirk@Sun.COM if (list_next(list, ipnet) == NULL) {
120410639SDarren.Reed@Sun.COM netmp = hdr->hpo_pkt->b_cont;
120510639SDarren.Reed@Sun.COM hdr->hpo_pkt->b_cont = NULL;
12068023SPhil.Kirk@Sun.COM } else {
120710639SDarren.Reed@Sun.COM if ((netmp = dupmsg(hdr->hpo_pkt->b_cont)) == NULL &&
120810639SDarren.Reed@Sun.COM (netmp = copymsg(hdr->hpo_pkt->b_cont)) == NULL) {
120910639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_duplicationFail);
12108023SPhil.Kirk@Sun.COM continue;
12118023SPhil.Kirk@Sun.COM }
12128023SPhil.Kirk@Sun.COM }
12138023SPhil.Kirk@Sun.COM
12148023SPhil.Kirk@Sun.COM if (ipnet->ipnet_flags & IPNET_INFO) {
121510639SDarren.Reed@Sun.COM if ((netmp = ipnet_addheader(hdr, netmp)) == NULL) {
121610639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchHeaderDrop);
12178023SPhil.Kirk@Sun.COM continue;
12188023SPhil.Kirk@Sun.COM }
12198023SPhil.Kirk@Sun.COM }
12208023SPhil.Kirk@Sun.COM
12218023SPhil.Kirk@Sun.COM if (ipnet->ipnet_rq->q_first == NULL &&
12228023SPhil.Kirk@Sun.COM canputnext(ipnet->ipnet_rq)) {
12238023SPhil.Kirk@Sun.COM putnext(ipnet->ipnet_rq, netmp);
122410639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchDeliver);
12258023SPhil.Kirk@Sun.COM } else if (canput(ipnet->ipnet_rq)) {
12268023SPhil.Kirk@Sun.COM (void) putq(ipnet->ipnet_rq, netmp);
122710639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchDeliver);
12288023SPhil.Kirk@Sun.COM } else {
12298023SPhil.Kirk@Sun.COM freemsg(netmp);
123010639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchPutDrop);
12318023SPhil.Kirk@Sun.COM }
12328023SPhil.Kirk@Sun.COM }
12338023SPhil.Kirk@Sun.COM
12348023SPhil.Kirk@Sun.COM ipnet_walkers_dec(ips);
12358023SPhil.Kirk@Sun.COM
12368023SPhil.Kirk@Sun.COM freemsg(mp);
12378023SPhil.Kirk@Sun.COM }
12388023SPhil.Kirk@Sun.COM
12398023SPhil.Kirk@Sun.COM static void
ipnet_input(mblk_t * mp)12408023SPhil.Kirk@Sun.COM ipnet_input(mblk_t *mp)
12418023SPhil.Kirk@Sun.COM {
124210639SDarren.Reed@Sun.COM hook_pkt_observe_t *hdr = (hook_pkt_observe_t *)mp->b_rptr;
124310639SDarren.Reed@Sun.COM ipnet_stack_t *ips;
124410639SDarren.Reed@Sun.COM
124510639SDarren.Reed@Sun.COM ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
12468023SPhil.Kirk@Sun.COM
12478023SPhil.Kirk@Sun.COM if (ddi_taskq_dispatch(ipnet_taskq, ipnet_dispatch, mp, DDI_NOSLEEP) !=
12488023SPhil.Kirk@Sun.COM DDI_SUCCESS) {
124910639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchFail);
12508023SPhil.Kirk@Sun.COM freemsg(mp);
125110639SDarren.Reed@Sun.COM } else {
125210639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_dispatchOk);
12538023SPhil.Kirk@Sun.COM }
12548023SPhil.Kirk@Sun.COM }
12558023SPhil.Kirk@Sun.COM
125610639SDarren.Reed@Sun.COM static ipnetif_t *
ipnet_alloc_if(ipnet_stack_t * ips)125710639SDarren.Reed@Sun.COM ipnet_alloc_if(ipnet_stack_t *ips)
125810639SDarren.Reed@Sun.COM {
125910639SDarren.Reed@Sun.COM ipnetif_t *ipnetif;
126010639SDarren.Reed@Sun.COM
126110639SDarren.Reed@Sun.COM if ((ipnetif = kmem_zalloc(sizeof (*ipnetif), KM_NOSLEEP)) == NULL)
126210639SDarren.Reed@Sun.COM return (NULL);
126310639SDarren.Reed@Sun.COM
126410639SDarren.Reed@Sun.COM mutex_init(&ipnetif->if_addr_lock, NULL, MUTEX_DEFAULT, 0);
126510639SDarren.Reed@Sun.COM list_create(&ipnetif->if_ip4addr_list, sizeof (ipnetif_addr_t),
126610639SDarren.Reed@Sun.COM offsetof(ipnetif_addr_t, ifa_link));
126710639SDarren.Reed@Sun.COM list_create(&ipnetif->if_ip6addr_list, sizeof (ipnetif_addr_t),
126810639SDarren.Reed@Sun.COM offsetof(ipnetif_addr_t, ifa_link));
126910639SDarren.Reed@Sun.COM mutex_init(&ipnetif->if_reflock, NULL, MUTEX_DEFAULT, 0);
127010639SDarren.Reed@Sun.COM
127110639SDarren.Reed@Sun.COM ipnetif->if_stackp = ips;
127210639SDarren.Reed@Sun.COM
127310639SDarren.Reed@Sun.COM return (ipnetif);
127410639SDarren.Reed@Sun.COM }
127510639SDarren.Reed@Sun.COM
12768023SPhil.Kirk@Sun.COM /*
12778023SPhil.Kirk@Sun.COM * Create a new ipnetif_t and new minor node for it. If creation is
12788023SPhil.Kirk@Sun.COM * successful the new ipnetif_t is inserted into an avl_tree
12798023SPhil.Kirk@Sun.COM * containing ipnetif's for this stack instance.
12808023SPhil.Kirk@Sun.COM */
12818023SPhil.Kirk@Sun.COM static ipnetif_t *
ipnetif_create(const char * name,uint64_t index,ipnet_stack_t * ips,uint64_t ifflags)128210639SDarren.Reed@Sun.COM ipnetif_create(const char *name, uint64_t index, ipnet_stack_t *ips,
128310639SDarren.Reed@Sun.COM uint64_t ifflags)
12848023SPhil.Kirk@Sun.COM {
12858023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
12868023SPhil.Kirk@Sun.COM avl_index_t where = 0;
12878023SPhil.Kirk@Sun.COM minor_t ifminor;
12888023SPhil.Kirk@Sun.COM
12898023SPhil.Kirk@Sun.COM /*
129010639SDarren.Reed@Sun.COM * Because ipnetif_create() can be called from a NIC event
12918023SPhil.Kirk@Sun.COM * callback, it should not block.
12928023SPhil.Kirk@Sun.COM */
12938023SPhil.Kirk@Sun.COM ifminor = (minor_t)id_alloc_nosleep(ipnet_minor_space);
12948023SPhil.Kirk@Sun.COM if (ifminor == (minor_t)-1)
12958023SPhil.Kirk@Sun.COM return (NULL);
129610639SDarren.Reed@Sun.COM if ((ipnetif = ipnet_alloc_if(ips)) == NULL) {
12978023SPhil.Kirk@Sun.COM id_free(ipnet_minor_space, ifminor);
12988023SPhil.Kirk@Sun.COM return (NULL);
12998023SPhil.Kirk@Sun.COM }
13008023SPhil.Kirk@Sun.COM
13018023SPhil.Kirk@Sun.COM (void) strlcpy(ipnetif->if_name, name, LIFNAMSIZ);
130210639SDarren.Reed@Sun.COM ipnetif->if_index = (uint_t)index;
130310639SDarren.Reed@Sun.COM ipnetif->if_zoneid = netstack_get_zoneid(ips->ips_netstack);
130410639SDarren.Reed@Sun.COM ipnetif->if_dev = makedevice(ipnet_major, ifminor);
13058023SPhil.Kirk@Sun.COM
13068023SPhil.Kirk@Sun.COM ipnetif->if_refcnt = 1;
130710639SDarren.Reed@Sun.COM if ((ifflags & IFF_LOOPBACK) != 0)
130810639SDarren.Reed@Sun.COM ipnetif->if_flags = IPNETIF_LOOPBACK;
13098023SPhil.Kirk@Sun.COM
13108023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
13118023SPhil.Kirk@Sun.COM VERIFY(avl_find(&ips->ips_avl_by_index, &index, &where) == NULL);
13128023SPhil.Kirk@Sun.COM avl_insert(&ips->ips_avl_by_index, ipnetif, where);
13138023SPhil.Kirk@Sun.COM VERIFY(avl_find(&ips->ips_avl_by_name, (void *)name, &where) == NULL);
13148023SPhil.Kirk@Sun.COM avl_insert(&ips->ips_avl_by_name, ipnetif, where);
13158023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
13168023SPhil.Kirk@Sun.COM
13178023SPhil.Kirk@Sun.COM return (ipnetif);
13188023SPhil.Kirk@Sun.COM }
13198023SPhil.Kirk@Sun.COM
13208023SPhil.Kirk@Sun.COM static void
ipnetif_remove(ipnetif_t * ipnetif,ipnet_stack_t * ips)132110639SDarren.Reed@Sun.COM ipnetif_remove(ipnetif_t *ipnetif, ipnet_stack_t *ips)
13228023SPhil.Kirk@Sun.COM {
13238023SPhil.Kirk@Sun.COM ipnet_t *ipnet;
13248023SPhil.Kirk@Sun.COM
13258023SPhil.Kirk@Sun.COM ipnet_walkers_inc(ips);
13268023SPhil.Kirk@Sun.COM /* Send a SIGHUP to all open streams associated with this ipnetif. */
13278023SPhil.Kirk@Sun.COM for (ipnet = list_head(&ips->ips_str_list); ipnet != NULL;
13288023SPhil.Kirk@Sun.COM ipnet = list_next(&ips->ips_str_list, ipnet)) {
13298023SPhil.Kirk@Sun.COM if (ipnet->ipnet_if == ipnetif)
13308023SPhil.Kirk@Sun.COM (void) putnextctl(ipnet->ipnet_rq, M_HANGUP);
13318023SPhil.Kirk@Sun.COM }
13328023SPhil.Kirk@Sun.COM ipnet_walkers_dec(ips);
13338023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
13348023SPhil.Kirk@Sun.COM avl_remove(&ips->ips_avl_by_index, ipnetif);
13358023SPhil.Kirk@Sun.COM avl_remove(&ips->ips_avl_by_name, ipnetif);
13368023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
133710639SDarren.Reed@Sun.COM /*
133810639SDarren.Reed@Sun.COM * Release the reference we implicitly held in ipnetif_create().
133910639SDarren.Reed@Sun.COM */
13408023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
13418023SPhil.Kirk@Sun.COM }
13428023SPhil.Kirk@Sun.COM
13438023SPhil.Kirk@Sun.COM static void
ipnet_purge_addrlist(list_t * addrlist)13448023SPhil.Kirk@Sun.COM ipnet_purge_addrlist(list_t *addrlist)
13458023SPhil.Kirk@Sun.COM {
134610639SDarren.Reed@Sun.COM ipnetif_addr_t *ifa;
13478023SPhil.Kirk@Sun.COM
13488023SPhil.Kirk@Sun.COM while ((ifa = list_head(addrlist)) != NULL) {
13498023SPhil.Kirk@Sun.COM list_remove(addrlist, ifa);
135010639SDarren.Reed@Sun.COM if (ifa->ifa_shared != NULL)
135110639SDarren.Reed@Sun.COM ipnetif_clone_release(ifa->ifa_shared);
13528023SPhil.Kirk@Sun.COM kmem_free(ifa, sizeof (*ifa));
13538023SPhil.Kirk@Sun.COM }
13548023SPhil.Kirk@Sun.COM }
13558023SPhil.Kirk@Sun.COM
13568023SPhil.Kirk@Sun.COM static void
ipnetif_free(ipnetif_t * ipnetif)135710639SDarren.Reed@Sun.COM ipnetif_free(ipnetif_t *ipnetif)
13588023SPhil.Kirk@Sun.COM {
13598023SPhil.Kirk@Sun.COM ASSERT(ipnetif->if_refcnt == 0);
136010639SDarren.Reed@Sun.COM ASSERT(ipnetif->if_sharecnt == 0);
13618023SPhil.Kirk@Sun.COM
13628023SPhil.Kirk@Sun.COM /* Remove IPv4/v6 address lists from the ipnetif */
13638023SPhil.Kirk@Sun.COM ipnet_purge_addrlist(&ipnetif->if_ip4addr_list);
13648023SPhil.Kirk@Sun.COM list_destroy(&ipnetif->if_ip4addr_list);
13658023SPhil.Kirk@Sun.COM ipnet_purge_addrlist(&ipnetif->if_ip6addr_list);
13668023SPhil.Kirk@Sun.COM list_destroy(&ipnetif->if_ip6addr_list);
13678023SPhil.Kirk@Sun.COM mutex_destroy(&ipnetif->if_addr_lock);
13688023SPhil.Kirk@Sun.COM mutex_destroy(&ipnetif->if_reflock);
136910639SDarren.Reed@Sun.COM if (ipnetif->if_dev != 0)
137010639SDarren.Reed@Sun.COM id_free(ipnet_minor_space, getminor(ipnetif->if_dev));
13718023SPhil.Kirk@Sun.COM kmem_free(ipnetif, sizeof (*ipnetif));
13728023SPhil.Kirk@Sun.COM }
13738023SPhil.Kirk@Sun.COM
13748023SPhil.Kirk@Sun.COM /*
13758023SPhil.Kirk@Sun.COM * Create an ipnetif_addr_t with the given logical interface id (lif)
13768023SPhil.Kirk@Sun.COM * and add it to the supplied ipnetif. The lif is the netinfo
13778023SPhil.Kirk@Sun.COM * representation of logical interface id, and we use this id to match
13788023SPhil.Kirk@Sun.COM * incoming netinfo events against our lists of addresses.
13798023SPhil.Kirk@Sun.COM */
13808023SPhil.Kirk@Sun.COM static void
ipnet_add_ifaddr(uint64_t lif,ipnetif_t * ipnetif,net_handle_t nd)13818023SPhil.Kirk@Sun.COM ipnet_add_ifaddr(uint64_t lif, ipnetif_t *ipnetif, net_handle_t nd)
13828023SPhil.Kirk@Sun.COM {
13838023SPhil.Kirk@Sun.COM ipnetif_addr_t *ifaddr;
13848023SPhil.Kirk@Sun.COM zoneid_t zoneid;
13858023SPhil.Kirk@Sun.COM struct sockaddr_in bcast;
13868023SPhil.Kirk@Sun.COM struct sockaddr_storage addr;
13878023SPhil.Kirk@Sun.COM net_ifaddr_t type = NA_ADDRESS;
13888023SPhil.Kirk@Sun.COM uint64_t phyif = ipnetif->if_index;
13898023SPhil.Kirk@Sun.COM
13908023SPhil.Kirk@Sun.COM if (net_getlifaddr(nd, phyif, lif, 1, &type, &addr) != 0 ||
13918023SPhil.Kirk@Sun.COM net_getlifzone(nd, phyif, lif, &zoneid) != 0)
13928023SPhil.Kirk@Sun.COM return;
139310639SDarren.Reed@Sun.COM
13948023SPhil.Kirk@Sun.COM if ((ifaddr = kmem_alloc(sizeof (*ifaddr), KM_NOSLEEP)) == NULL)
13958023SPhil.Kirk@Sun.COM return;
13968023SPhil.Kirk@Sun.COM ifaddr->ifa_zone = zoneid;
13978023SPhil.Kirk@Sun.COM ifaddr->ifa_id = lif;
139810639SDarren.Reed@Sun.COM ifaddr->ifa_shared = NULL;
13998023SPhil.Kirk@Sun.COM
14008023SPhil.Kirk@Sun.COM switch (addr.ss_family) {
14018023SPhil.Kirk@Sun.COM case AF_INET:
14028023SPhil.Kirk@Sun.COM ifaddr->ifa_ip4addr =
14038023SPhil.Kirk@Sun.COM ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
14048023SPhil.Kirk@Sun.COM /*
14058023SPhil.Kirk@Sun.COM * Try and get the broadcast address. Note that it's okay for
14068023SPhil.Kirk@Sun.COM * an interface to not have a broadcast address, so we don't
14078023SPhil.Kirk@Sun.COM * fail the entire operation if net_getlifaddr() fails here.
14088023SPhil.Kirk@Sun.COM */
14098023SPhil.Kirk@Sun.COM type = NA_BROADCAST;
14108023SPhil.Kirk@Sun.COM if (net_getlifaddr(nd, phyif, lif, 1, &type, &bcast) == 0)
14118023SPhil.Kirk@Sun.COM ifaddr->ifa_brdaddr = bcast.sin_addr.s_addr;
14128023SPhil.Kirk@Sun.COM break;
14138023SPhil.Kirk@Sun.COM case AF_INET6:
14148023SPhil.Kirk@Sun.COM ifaddr->ifa_ip6addr = ((struct sockaddr_in6 *)&addr)->sin6_addr;
14158023SPhil.Kirk@Sun.COM break;
14168023SPhil.Kirk@Sun.COM }
14178023SPhil.Kirk@Sun.COM
141810695SDarren.Reed@Sun.COM /*
141910695SDarren.Reed@Sun.COM * The zoneid stored in ipnetif_t needs to correspond to the actual
142010695SDarren.Reed@Sun.COM * zone the address is being used in. This facilitates finding the
142110695SDarren.Reed@Sun.COM * correct netstack_t pointer, amongst other things, later.
142210695SDarren.Reed@Sun.COM */
142310695SDarren.Reed@Sun.COM if (zoneid == ALL_ZONES)
142410695SDarren.Reed@Sun.COM zoneid = GLOBAL_ZONEID;
142510695SDarren.Reed@Sun.COM
14268023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
142710639SDarren.Reed@Sun.COM if (zoneid != ipnetif->if_zoneid) {
142810639SDarren.Reed@Sun.COM ipnetif_t *ifp2;
142910639SDarren.Reed@Sun.COM
143010639SDarren.Reed@Sun.COM ifp2 = ipnetif_clone_create(ipnetif, zoneid);
143110639SDarren.Reed@Sun.COM ifaddr->ifa_shared = ifp2;
143210639SDarren.Reed@Sun.COM }
14338023SPhil.Kirk@Sun.COM list_insert_tail(addr.ss_family == AF_INET ?
14348023SPhil.Kirk@Sun.COM &ipnetif->if_ip4addr_list : &ipnetif->if_ip6addr_list, ifaddr);
14358023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
14368023SPhil.Kirk@Sun.COM }
14378023SPhil.Kirk@Sun.COM
14388023SPhil.Kirk@Sun.COM static void
ipnet_delete_ifaddr(ipnetif_addr_t * ifaddr,ipnetif_t * ipnetif,boolean_t isv6)14398023SPhil.Kirk@Sun.COM ipnet_delete_ifaddr(ipnetif_addr_t *ifaddr, ipnetif_t *ipnetif, boolean_t isv6)
14408023SPhil.Kirk@Sun.COM {
14418023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
144210639SDarren.Reed@Sun.COM if (ifaddr->ifa_shared != NULL)
144310639SDarren.Reed@Sun.COM ipnetif_clone_release(ifaddr->ifa_shared);
144410639SDarren.Reed@Sun.COM
14458023SPhil.Kirk@Sun.COM list_remove(isv6 ?
14468023SPhil.Kirk@Sun.COM &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list, ifaddr);
14478023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
14488023SPhil.Kirk@Sun.COM kmem_free(ifaddr, sizeof (*ifaddr));
14498023SPhil.Kirk@Sun.COM }
14508023SPhil.Kirk@Sun.COM
14518023SPhil.Kirk@Sun.COM static void
ipnet_plumb_ev(ipnet_nicevent_t * ipne,ipnet_stack_t * ips,boolean_t isv6)145210639SDarren.Reed@Sun.COM ipnet_plumb_ev(ipnet_nicevent_t *ipne, ipnet_stack_t *ips, boolean_t isv6)
14538023SPhil.Kirk@Sun.COM {
14548023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
14558023SPhil.Kirk@Sun.COM boolean_t refrele_needed = B_TRUE;
145610639SDarren.Reed@Sun.COM uint64_t ifflags;
145710639SDarren.Reed@Sun.COM uint64_t ifindex;
145810639SDarren.Reed@Sun.COM char *ifname;
14598023SPhil.Kirk@Sun.COM
146010639SDarren.Reed@Sun.COM ifflags = 0;
146110639SDarren.Reed@Sun.COM ifname = ipne->ipne_ifname;
146210639SDarren.Reed@Sun.COM ifindex = ipne->ipne_ifindex;
146310639SDarren.Reed@Sun.COM
146410639SDarren.Reed@Sun.COM (void) net_getlifflags(ipne->ipne_protocol, ifindex, 0, &ifflags);
146510639SDarren.Reed@Sun.COM
146610639SDarren.Reed@Sun.COM if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL) {
146710639SDarren.Reed@Sun.COM ipnetif = ipnetif_create(ifname, ifindex, ips, ifflags);
14688023SPhil.Kirk@Sun.COM refrele_needed = B_FALSE;
14698023SPhil.Kirk@Sun.COM }
14708023SPhil.Kirk@Sun.COM if (ipnetif != NULL) {
14718023SPhil.Kirk@Sun.COM ipnetif->if_flags |=
14728023SPhil.Kirk@Sun.COM isv6 ? IPNETIF_IPV6PLUMBED : IPNETIF_IPV4PLUMBED;
14738023SPhil.Kirk@Sun.COM }
14748023SPhil.Kirk@Sun.COM
14758023SPhil.Kirk@Sun.COM if (ipnetif->if_multicnt != 0) {
14768023SPhil.Kirk@Sun.COM if (ip_join_allmulti(ifindex, isv6,
14778023SPhil.Kirk@Sun.COM ips->ips_netstack->netstack_ip) == 0) {
14788023SPhil.Kirk@Sun.COM ipnetif->if_flags |=
14798023SPhil.Kirk@Sun.COM isv6 ? IPNETIF_IPV6ALLMULTI : IPNETIF_IPV4ALLMULTI;
14808023SPhil.Kirk@Sun.COM }
14818023SPhil.Kirk@Sun.COM }
14828023SPhil.Kirk@Sun.COM
14838023SPhil.Kirk@Sun.COM if (refrele_needed)
14848023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
14858023SPhil.Kirk@Sun.COM }
14868023SPhil.Kirk@Sun.COM
14878023SPhil.Kirk@Sun.COM static void
ipnet_unplumb_ev(uint64_t ifindex,ipnet_stack_t * ips,boolean_t isv6)14888023SPhil.Kirk@Sun.COM ipnet_unplumb_ev(uint64_t ifindex, ipnet_stack_t *ips, boolean_t isv6)
14898023SPhil.Kirk@Sun.COM {
14908023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
14918023SPhil.Kirk@Sun.COM
149210639SDarren.Reed@Sun.COM if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
14938023SPhil.Kirk@Sun.COM return;
14948023SPhil.Kirk@Sun.COM
14958023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
14968023SPhil.Kirk@Sun.COM ipnet_purge_addrlist(isv6 ?
14978023SPhil.Kirk@Sun.COM &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list);
14988023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
14998023SPhil.Kirk@Sun.COM
15008023SPhil.Kirk@Sun.COM /*
15018023SPhil.Kirk@Sun.COM * Note that we have one ipnetif for both IPv4 and IPv6, but we receive
15028023SPhil.Kirk@Sun.COM * separate NE_UNPLUMB events for IPv4 and IPv6. We remove the ipnetif
15038023SPhil.Kirk@Sun.COM * if both IPv4 and IPv6 interfaces have been unplumbed.
15048023SPhil.Kirk@Sun.COM */
15058023SPhil.Kirk@Sun.COM ipnetif->if_flags &= isv6 ? ~IPNETIF_IPV6PLUMBED : ~IPNETIF_IPV4PLUMBED;
15068023SPhil.Kirk@Sun.COM if (!(ipnetif->if_flags & (IPNETIF_IPV4PLUMBED | IPNETIF_IPV6PLUMBED)))
150710639SDarren.Reed@Sun.COM ipnetif_remove(ipnetif, ips);
15088023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
15098023SPhil.Kirk@Sun.COM }
15108023SPhil.Kirk@Sun.COM
15118023SPhil.Kirk@Sun.COM static void
ipnet_lifup_ev(uint64_t ifindex,uint64_t lifindex,net_handle_t nd,ipnet_stack_t * ips,boolean_t isv6)15128023SPhil.Kirk@Sun.COM ipnet_lifup_ev(uint64_t ifindex, uint64_t lifindex, net_handle_t nd,
15138023SPhil.Kirk@Sun.COM ipnet_stack_t *ips, boolean_t isv6)
15148023SPhil.Kirk@Sun.COM {
15158023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
15168023SPhil.Kirk@Sun.COM ipnetif_addr_t *ifaddr;
15178023SPhil.Kirk@Sun.COM
151810639SDarren.Reed@Sun.COM if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
15198023SPhil.Kirk@Sun.COM return;
15208023SPhil.Kirk@Sun.COM if ((ifaddr = ipnet_match_lif(ipnetif, lifindex, isv6)) != NULL) {
15218023SPhil.Kirk@Sun.COM /*
15228023SPhil.Kirk@Sun.COM * We must have missed a NE_LIF_DOWN event. Delete this
15238023SPhil.Kirk@Sun.COM * ifaddr and re-create it.
15248023SPhil.Kirk@Sun.COM */
15258023SPhil.Kirk@Sun.COM ipnet_delete_ifaddr(ifaddr, ipnetif, isv6);
15268023SPhil.Kirk@Sun.COM }
15278023SPhil.Kirk@Sun.COM
15288023SPhil.Kirk@Sun.COM ipnet_add_ifaddr(lifindex, ipnetif, nd);
15298023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
15308023SPhil.Kirk@Sun.COM }
15318023SPhil.Kirk@Sun.COM
15328023SPhil.Kirk@Sun.COM static void
ipnet_lifdown_ev(uint64_t ifindex,uint64_t lifindex,ipnet_stack_t * ips,boolean_t isv6)15338023SPhil.Kirk@Sun.COM ipnet_lifdown_ev(uint64_t ifindex, uint64_t lifindex, ipnet_stack_t *ips,
15348023SPhil.Kirk@Sun.COM boolean_t isv6)
15358023SPhil.Kirk@Sun.COM {
15368023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
15378023SPhil.Kirk@Sun.COM ipnetif_addr_t *ifaddr;
15388023SPhil.Kirk@Sun.COM
153910639SDarren.Reed@Sun.COM if ((ipnetif = ipnetif_getby_index(ifindex, ips)) == NULL)
15408023SPhil.Kirk@Sun.COM return;
15418023SPhil.Kirk@Sun.COM if ((ifaddr = ipnet_match_lif(ipnetif, lifindex, isv6)) != NULL)
15428023SPhil.Kirk@Sun.COM ipnet_delete_ifaddr(ifaddr, ipnetif, isv6);
15438023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif);
15448023SPhil.Kirk@Sun.COM /*
15458023SPhil.Kirk@Sun.COM * Make sure that open streams on this ipnetif are still allowed to
15468023SPhil.Kirk@Sun.COM * have it open.
15478023SPhil.Kirk@Sun.COM */
154810639SDarren.Reed@Sun.COM ipnetif_zonecheck(ipnetif, ips);
15498023SPhil.Kirk@Sun.COM }
15508023SPhil.Kirk@Sun.COM
15518023SPhil.Kirk@Sun.COM /*
15528023SPhil.Kirk@Sun.COM * This callback from the NIC event framework dispatches a taskq as the event
15538023SPhil.Kirk@Sun.COM * handlers may block.
15548023SPhil.Kirk@Sun.COM */
15558023SPhil.Kirk@Sun.COM /* ARGSUSED */
15568023SPhil.Kirk@Sun.COM static int
ipnet_nicevent_cb(hook_event_token_t token,hook_data_t info,void * arg)15578023SPhil.Kirk@Sun.COM ipnet_nicevent_cb(hook_event_token_t token, hook_data_t info, void *arg)
15588023SPhil.Kirk@Sun.COM {
15598023SPhil.Kirk@Sun.COM ipnet_stack_t *ips = arg;
15608023SPhil.Kirk@Sun.COM hook_nic_event_t *hn = (hook_nic_event_t *)info;
15618023SPhil.Kirk@Sun.COM ipnet_nicevent_t *ipne;
15628023SPhil.Kirk@Sun.COM
15638023SPhil.Kirk@Sun.COM if ((ipne = kmem_alloc(sizeof (ipnet_nicevent_t), KM_NOSLEEP)) == NULL)
15648023SPhil.Kirk@Sun.COM return (0);
15658023SPhil.Kirk@Sun.COM ipne->ipne_event = hn->hne_event;
15668023SPhil.Kirk@Sun.COM ipne->ipne_protocol = hn->hne_protocol;
15678023SPhil.Kirk@Sun.COM ipne->ipne_stackid = ips->ips_netstack->netstack_stackid;
15688023SPhil.Kirk@Sun.COM ipne->ipne_ifindex = hn->hne_nic;
15698023SPhil.Kirk@Sun.COM ipne->ipne_lifindex = hn->hne_lif;
15708023SPhil.Kirk@Sun.COM if (hn->hne_datalen != 0) {
15718023SPhil.Kirk@Sun.COM (void) strlcpy(ipne->ipne_ifname, hn->hne_data,
15728023SPhil.Kirk@Sun.COM sizeof (ipne->ipne_ifname));
15738023SPhil.Kirk@Sun.COM }
15748023SPhil.Kirk@Sun.COM (void) ddi_taskq_dispatch(ipnet_nicevent_taskq, ipnet_nicevent_task,
15758023SPhil.Kirk@Sun.COM ipne, DDI_NOSLEEP);
15768023SPhil.Kirk@Sun.COM return (0);
15778023SPhil.Kirk@Sun.COM }
15788023SPhil.Kirk@Sun.COM
15798023SPhil.Kirk@Sun.COM static void
ipnet_nicevent_task(void * arg)15808023SPhil.Kirk@Sun.COM ipnet_nicevent_task(void *arg)
15818023SPhil.Kirk@Sun.COM {
15828023SPhil.Kirk@Sun.COM ipnet_nicevent_t *ipne = arg;
15838023SPhil.Kirk@Sun.COM netstack_t *ns;
15848023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
15858023SPhil.Kirk@Sun.COM boolean_t isv6;
15868023SPhil.Kirk@Sun.COM
15878023SPhil.Kirk@Sun.COM if ((ns = netstack_find_by_stackid(ipne->ipne_stackid)) == NULL)
15888023SPhil.Kirk@Sun.COM goto done;
15898023SPhil.Kirk@Sun.COM ips = ns->netstack_ipnet;
15908023SPhil.Kirk@Sun.COM isv6 = (ipne->ipne_protocol == ips->ips_ndv6);
15918023SPhil.Kirk@Sun.COM
15928023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_event_lock);
15938023SPhil.Kirk@Sun.COM switch (ipne->ipne_event) {
15948023SPhil.Kirk@Sun.COM case NE_PLUMB:
159510639SDarren.Reed@Sun.COM ipnet_plumb_ev(ipne, ips, isv6);
15968023SPhil.Kirk@Sun.COM break;
15978023SPhil.Kirk@Sun.COM case NE_UNPLUMB:
15988023SPhil.Kirk@Sun.COM ipnet_unplumb_ev(ipne->ipne_ifindex, ips, isv6);
15998023SPhil.Kirk@Sun.COM break;
16008023SPhil.Kirk@Sun.COM case NE_LIF_UP:
16018023SPhil.Kirk@Sun.COM ipnet_lifup_ev(ipne->ipne_ifindex, ipne->ipne_lifindex,
16028023SPhil.Kirk@Sun.COM ipne->ipne_protocol, ips, isv6);
16038023SPhil.Kirk@Sun.COM break;
16048023SPhil.Kirk@Sun.COM case NE_LIF_DOWN:
16058023SPhil.Kirk@Sun.COM ipnet_lifdown_ev(ipne->ipne_ifindex, ipne->ipne_lifindex, ips,
16068023SPhil.Kirk@Sun.COM isv6);
16078023SPhil.Kirk@Sun.COM break;
16088023SPhil.Kirk@Sun.COM default:
16098023SPhil.Kirk@Sun.COM break;
16108023SPhil.Kirk@Sun.COM }
16118023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_event_lock);
16128023SPhil.Kirk@Sun.COM done:
16138023SPhil.Kirk@Sun.COM if (ns != NULL)
16148023SPhil.Kirk@Sun.COM netstack_rele(ns);
16158023SPhil.Kirk@Sun.COM kmem_free(ipne, sizeof (ipnet_nicevent_t));
16168023SPhil.Kirk@Sun.COM }
16178023SPhil.Kirk@Sun.COM
16188023SPhil.Kirk@Sun.COM dev_t
ipnet_if_getdev(char * name,zoneid_t zoneid)16198023SPhil.Kirk@Sun.COM ipnet_if_getdev(char *name, zoneid_t zoneid)
16208023SPhil.Kirk@Sun.COM {
16218023SPhil.Kirk@Sun.COM netstack_t *ns;
16228023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
16238023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
16248023SPhil.Kirk@Sun.COM dev_t dev = (dev_t)-1;
16258023SPhil.Kirk@Sun.COM
16268023SPhil.Kirk@Sun.COM if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
16278023SPhil.Kirk@Sun.COM return (dev);
16288023SPhil.Kirk@Sun.COM if ((ns = netstack_find_by_zoneid(zoneid)) == NULL)
16298023SPhil.Kirk@Sun.COM return (dev);
16308023SPhil.Kirk@Sun.COM
16318023SPhil.Kirk@Sun.COM ips = ns->netstack_ipnet;
16328023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
16338023SPhil.Kirk@Sun.COM if ((ipnetif = avl_find(&ips->ips_avl_by_name, name, NULL)) != NULL) {
163410639SDarren.Reed@Sun.COM if (ipnetif_in_zone(ipnetif, zoneid, ips))
16358023SPhil.Kirk@Sun.COM dev = ipnetif->if_dev;
16368023SPhil.Kirk@Sun.COM }
16378023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
16388023SPhil.Kirk@Sun.COM netstack_rele(ns);
16398023SPhil.Kirk@Sun.COM
16408023SPhil.Kirk@Sun.COM return (dev);
16418023SPhil.Kirk@Sun.COM }
16428023SPhil.Kirk@Sun.COM
16438023SPhil.Kirk@Sun.COM static ipnetif_t *
ipnetif_getby_index(uint64_t id,ipnet_stack_t * ips)164410639SDarren.Reed@Sun.COM ipnetif_getby_index(uint64_t id, ipnet_stack_t *ips)
16458023SPhil.Kirk@Sun.COM {
16468023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
16478023SPhil.Kirk@Sun.COM
16488023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
16498023SPhil.Kirk@Sun.COM if ((ipnetif = avl_find(&ips->ips_avl_by_index, &id, NULL)) != NULL)
16508023SPhil.Kirk@Sun.COM ipnetif_refhold(ipnetif);
16518023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
16528023SPhil.Kirk@Sun.COM return (ipnetif);
16538023SPhil.Kirk@Sun.COM }
16548023SPhil.Kirk@Sun.COM
16558023SPhil.Kirk@Sun.COM static ipnetif_t *
ipnetif_getby_dev(dev_t dev,ipnet_stack_t * ips)165610639SDarren.Reed@Sun.COM ipnetif_getby_dev(dev_t dev, ipnet_stack_t *ips)
16578023SPhil.Kirk@Sun.COM {
16588023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif;
16598023SPhil.Kirk@Sun.COM avl_tree_t *tree;
16608023SPhil.Kirk@Sun.COM
16618023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
16628023SPhil.Kirk@Sun.COM tree = &ips->ips_avl_by_index;
16638023SPhil.Kirk@Sun.COM for (ipnetif = avl_first(tree); ipnetif != NULL;
16648023SPhil.Kirk@Sun.COM ipnetif = avl_walk(tree, ipnetif, AVL_AFTER)) {
16658023SPhil.Kirk@Sun.COM if (ipnetif->if_dev == dev) {
16668023SPhil.Kirk@Sun.COM ipnetif_refhold(ipnetif);
16678023SPhil.Kirk@Sun.COM break;
16688023SPhil.Kirk@Sun.COM }
16698023SPhil.Kirk@Sun.COM }
16708023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
16718023SPhil.Kirk@Sun.COM return (ipnetif);
16728023SPhil.Kirk@Sun.COM }
16738023SPhil.Kirk@Sun.COM
16748023SPhil.Kirk@Sun.COM static ipnetif_addr_t *
ipnet_match_lif(ipnetif_t * ipnetif,lif_if_t lid,boolean_t isv6)16758023SPhil.Kirk@Sun.COM ipnet_match_lif(ipnetif_t *ipnetif, lif_if_t lid, boolean_t isv6)
16768023SPhil.Kirk@Sun.COM {
16778023SPhil.Kirk@Sun.COM ipnetif_addr_t *ifaddr;
167810639SDarren.Reed@Sun.COM list_t *list;
16798023SPhil.Kirk@Sun.COM
16808023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
16818023SPhil.Kirk@Sun.COM list = isv6 ? &ipnetif->if_ip6addr_list : &ipnetif->if_ip4addr_list;
16828023SPhil.Kirk@Sun.COM for (ifaddr = list_head(list); ifaddr != NULL;
16838023SPhil.Kirk@Sun.COM ifaddr = list_next(list, ifaddr)) {
16848023SPhil.Kirk@Sun.COM if (lid == ifaddr->ifa_id)
16858023SPhil.Kirk@Sun.COM break;
16868023SPhil.Kirk@Sun.COM }
16878023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
16888023SPhil.Kirk@Sun.COM return (ifaddr);
16898023SPhil.Kirk@Sun.COM }
16908023SPhil.Kirk@Sun.COM
16918023SPhil.Kirk@Sun.COM /* ARGSUSED */
16928023SPhil.Kirk@Sun.COM static void *
ipnet_stack_init(netstackid_t stackid,netstack_t * ns)16938023SPhil.Kirk@Sun.COM ipnet_stack_init(netstackid_t stackid, netstack_t *ns)
16948023SPhil.Kirk@Sun.COM {
16958023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
16968023SPhil.Kirk@Sun.COM
16978023SPhil.Kirk@Sun.COM ips = kmem_zalloc(sizeof (*ips), KM_SLEEP);
16988023SPhil.Kirk@Sun.COM ips->ips_netstack = ns;
16998023SPhil.Kirk@Sun.COM mutex_init(&ips->ips_avl_lock, NULL, MUTEX_DEFAULT, 0);
170010639SDarren.Reed@Sun.COM avl_create(&ips->ips_avl_by_index, ipnetif_compare_index,
17018023SPhil.Kirk@Sun.COM sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_index));
170210639SDarren.Reed@Sun.COM avl_create(&ips->ips_avl_by_name, ipnetif_compare_name,
17038023SPhil.Kirk@Sun.COM sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_name));
170410639SDarren.Reed@Sun.COM avl_create(&ips->ips_avl_by_shared, ipnetif_compare_name_zone,
170510639SDarren.Reed@Sun.COM sizeof (ipnetif_t), offsetof(ipnetif_t, if_avl_by_shared));
17068023SPhil.Kirk@Sun.COM mutex_init(&ips->ips_walkers_lock, NULL, MUTEX_DEFAULT, NULL);
17078023SPhil.Kirk@Sun.COM cv_init(&ips->ips_walkers_cv, NULL, CV_DRIVER, NULL);
17088023SPhil.Kirk@Sun.COM list_create(&ips->ips_str_list, sizeof (ipnet_t),
17098023SPhil.Kirk@Sun.COM offsetof(ipnet_t, ipnet_next));
17108023SPhil.Kirk@Sun.COM ipnet_register_netihook(ips);
17118023SPhil.Kirk@Sun.COM return (ips);
17128023SPhil.Kirk@Sun.COM }
17138023SPhil.Kirk@Sun.COM
17148023SPhil.Kirk@Sun.COM /* ARGSUSED */
17158023SPhil.Kirk@Sun.COM static void
ipnet_stack_fini(netstackid_t stackid,void * arg)17168023SPhil.Kirk@Sun.COM ipnet_stack_fini(netstackid_t stackid, void *arg)
17178023SPhil.Kirk@Sun.COM {
17188023SPhil.Kirk@Sun.COM ipnet_stack_t *ips = arg;
17198023SPhil.Kirk@Sun.COM ipnetif_t *ipnetif, *nipnetif;
17208023SPhil.Kirk@Sun.COM
172110639SDarren.Reed@Sun.COM if (ips->ips_kstatp != NULL) {
172210639SDarren.Reed@Sun.COM zoneid_t zoneid;
172310639SDarren.Reed@Sun.COM
172410639SDarren.Reed@Sun.COM zoneid = netstackid_to_zoneid(stackid);
172510639SDarren.Reed@Sun.COM net_kstat_delete(net_zoneidtonetid(zoneid), ips->ips_kstatp);
172610639SDarren.Reed@Sun.COM }
17278023SPhil.Kirk@Sun.COM if (ips->ips_ndv4 != NULL) {
17288023SPhil.Kirk@Sun.COM VERIFY(net_hook_unregister(ips->ips_ndv4, NH_NIC_EVENTS,
17298023SPhil.Kirk@Sun.COM ips->ips_nicevents) == 0);
17308023SPhil.Kirk@Sun.COM VERIFY(net_protocol_release(ips->ips_ndv4) == 0);
17318023SPhil.Kirk@Sun.COM }
17328023SPhil.Kirk@Sun.COM if (ips->ips_ndv6 != NULL) {
17338023SPhil.Kirk@Sun.COM VERIFY(net_hook_unregister(ips->ips_ndv6, NH_NIC_EVENTS,
17348023SPhil.Kirk@Sun.COM ips->ips_nicevents) == 0);
17358023SPhil.Kirk@Sun.COM VERIFY(net_protocol_release(ips->ips_ndv6) == 0);
17368023SPhil.Kirk@Sun.COM }
17378023SPhil.Kirk@Sun.COM hook_free(ips->ips_nicevents);
17388023SPhil.Kirk@Sun.COM
17398023SPhil.Kirk@Sun.COM for (ipnetif = avl_first(&ips->ips_avl_by_index); ipnetif != NULL;
17408023SPhil.Kirk@Sun.COM ipnetif = nipnetif) {
17418023SPhil.Kirk@Sun.COM nipnetif = AVL_NEXT(&ips->ips_avl_by_index, ipnetif);
174210639SDarren.Reed@Sun.COM ipnetif_remove(ipnetif, ips);
17438023SPhil.Kirk@Sun.COM }
174410639SDarren.Reed@Sun.COM avl_destroy(&ips->ips_avl_by_shared);
17458023SPhil.Kirk@Sun.COM avl_destroy(&ips->ips_avl_by_index);
17468023SPhil.Kirk@Sun.COM avl_destroy(&ips->ips_avl_by_name);
17478023SPhil.Kirk@Sun.COM mutex_destroy(&ips->ips_avl_lock);
17488023SPhil.Kirk@Sun.COM mutex_destroy(&ips->ips_walkers_lock);
17498023SPhil.Kirk@Sun.COM cv_destroy(&ips->ips_walkers_cv);
17508023SPhil.Kirk@Sun.COM list_destroy(&ips->ips_str_list);
17518023SPhil.Kirk@Sun.COM kmem_free(ips, sizeof (*ips));
17528023SPhil.Kirk@Sun.COM }
17538023SPhil.Kirk@Sun.COM
17548023SPhil.Kirk@Sun.COM /* Do any of the addresses in addrlist belong the supplied zoneid? */
17558023SPhil.Kirk@Sun.COM static boolean_t
ipnet_addrs_in_zone(list_t * addrlist,zoneid_t zoneid)17568023SPhil.Kirk@Sun.COM ipnet_addrs_in_zone(list_t *addrlist, zoneid_t zoneid)
17578023SPhil.Kirk@Sun.COM {
175810639SDarren.Reed@Sun.COM ipnetif_addr_t *ifa;
17598023SPhil.Kirk@Sun.COM
17608023SPhil.Kirk@Sun.COM for (ifa = list_head(addrlist); ifa != NULL;
17618023SPhil.Kirk@Sun.COM ifa = list_next(addrlist, ifa)) {
17628023SPhil.Kirk@Sun.COM if (ifa->ifa_zone == zoneid)
17638023SPhil.Kirk@Sun.COM return (B_TRUE);
17648023SPhil.Kirk@Sun.COM }
17658023SPhil.Kirk@Sun.COM return (B_FALSE);
17668023SPhil.Kirk@Sun.COM }
17678023SPhil.Kirk@Sun.COM
17688023SPhil.Kirk@Sun.COM /* Should the supplied ipnetif be visible from the supplied zoneid? */
17698023SPhil.Kirk@Sun.COM static boolean_t
ipnetif_in_zone(ipnetif_t * ipnetif,zoneid_t zoneid,ipnet_stack_t * ips)177010639SDarren.Reed@Sun.COM ipnetif_in_zone(ipnetif_t *ipnetif, zoneid_t zoneid, ipnet_stack_t *ips)
17718023SPhil.Kirk@Sun.COM {
177210639SDarren.Reed@Sun.COM int ret;
17738023SPhil.Kirk@Sun.COM
17748023SPhil.Kirk@Sun.COM /*
17758023SPhil.Kirk@Sun.COM * The global zone has visibility into all interfaces in the global
17768023SPhil.Kirk@Sun.COM * stack, and exclusive stack zones have visibility into all
17778023SPhil.Kirk@Sun.COM * interfaces in their stack.
17788023SPhil.Kirk@Sun.COM */
17798023SPhil.Kirk@Sun.COM if (zoneid == GLOBAL_ZONEID ||
17808023SPhil.Kirk@Sun.COM ips->ips_netstack->netstack_stackid != GLOBAL_NETSTACKID)
17818023SPhil.Kirk@Sun.COM return (B_TRUE);
17828023SPhil.Kirk@Sun.COM
17838023SPhil.Kirk@Sun.COM /*
17848023SPhil.Kirk@Sun.COM * Shared-stack zones only have visibility for interfaces that have
17858023SPhil.Kirk@Sun.COM * addresses in their zone.
17868023SPhil.Kirk@Sun.COM */
17878023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_addr_lock);
17888023SPhil.Kirk@Sun.COM ret = ipnet_addrs_in_zone(&ipnetif->if_ip4addr_list, zoneid) ||
17898023SPhil.Kirk@Sun.COM ipnet_addrs_in_zone(&ipnetif->if_ip6addr_list, zoneid);
17908023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_addr_lock);
17918023SPhil.Kirk@Sun.COM return (ret);
17928023SPhil.Kirk@Sun.COM }
17938023SPhil.Kirk@Sun.COM
17948023SPhil.Kirk@Sun.COM /*
17958023SPhil.Kirk@Sun.COM * Verify that any ipnet_t that has a reference to the supplied ipnetif should
17968023SPhil.Kirk@Sun.COM * still be allowed to have it open. A given ipnet_t may no longer be allowed
17978023SPhil.Kirk@Sun.COM * to have an ipnetif open if there are no longer any addresses that belong to
17988023SPhil.Kirk@Sun.COM * the ipnetif in the ipnet_t's non-global shared-stack zoneid. If that's the
17998023SPhil.Kirk@Sun.COM * case, send the ipnet_t an M_HANGUP.
18008023SPhil.Kirk@Sun.COM */
18018023SPhil.Kirk@Sun.COM static void
ipnetif_zonecheck(ipnetif_t * ipnetif,ipnet_stack_t * ips)180210639SDarren.Reed@Sun.COM ipnetif_zonecheck(ipnetif_t *ipnetif, ipnet_stack_t *ips)
18038023SPhil.Kirk@Sun.COM {
18048023SPhil.Kirk@Sun.COM list_t *strlist = &ips->ips_str_list;
18058023SPhil.Kirk@Sun.COM ipnet_t *ipnet;
18068023SPhil.Kirk@Sun.COM
18078023SPhil.Kirk@Sun.COM ipnet_walkers_inc(ips);
18088023SPhil.Kirk@Sun.COM for (ipnet = list_head(strlist); ipnet != NULL;
18098023SPhil.Kirk@Sun.COM ipnet = list_next(strlist, ipnet)) {
18108023SPhil.Kirk@Sun.COM if (ipnet->ipnet_if != ipnetif)
18118023SPhil.Kirk@Sun.COM continue;
181210639SDarren.Reed@Sun.COM if (!ipnetif_in_zone(ipnetif, ipnet->ipnet_zoneid, ips))
18138023SPhil.Kirk@Sun.COM (void) putnextctl(ipnet->ipnet_rq, M_HANGUP);
18148023SPhil.Kirk@Sun.COM }
18158023SPhil.Kirk@Sun.COM ipnet_walkers_dec(ips);
18168023SPhil.Kirk@Sun.COM }
18178023SPhil.Kirk@Sun.COM
18188023SPhil.Kirk@Sun.COM void
ipnet_walk_if(ipnet_walkfunc_t * cb,void * arg,zoneid_t zoneid)18198023SPhil.Kirk@Sun.COM ipnet_walk_if(ipnet_walkfunc_t *cb, void *arg, zoneid_t zoneid)
18208023SPhil.Kirk@Sun.COM {
182110639SDarren.Reed@Sun.COM ipnetif_t *ipnetif;
18228023SPhil.Kirk@Sun.COM list_t cbdata;
18238023SPhil.Kirk@Sun.COM ipnetif_cbdata_t *cbnode;
18248023SPhil.Kirk@Sun.COM netstack_t *ns;
18258023SPhil.Kirk@Sun.COM ipnet_stack_t *ips;
18268023SPhil.Kirk@Sun.COM
18278023SPhil.Kirk@Sun.COM /*
18288023SPhil.Kirk@Sun.COM * On labeled systems, non-global zones shouldn't see anything
18298023SPhil.Kirk@Sun.COM * in /dev/ipnet.
18308023SPhil.Kirk@Sun.COM */
18318023SPhil.Kirk@Sun.COM if (is_system_labeled() && zoneid != GLOBAL_ZONEID)
18328023SPhil.Kirk@Sun.COM return;
18338023SPhil.Kirk@Sun.COM
18348023SPhil.Kirk@Sun.COM if ((ns = netstack_find_by_zoneid(zoneid)) == NULL)
18358023SPhil.Kirk@Sun.COM return;
18368023SPhil.Kirk@Sun.COM
18378023SPhil.Kirk@Sun.COM ips = ns->netstack_ipnet;
18388023SPhil.Kirk@Sun.COM list_create(&cbdata, sizeof (ipnetif_cbdata_t),
18398023SPhil.Kirk@Sun.COM offsetof(ipnetif_cbdata_t, ic_next));
18408023SPhil.Kirk@Sun.COM
18418023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_avl_lock);
18428023SPhil.Kirk@Sun.COM for (ipnetif = avl_first(&ips->ips_avl_by_index); ipnetif != NULL;
18438023SPhil.Kirk@Sun.COM ipnetif = avl_walk(&ips->ips_avl_by_index, ipnetif, AVL_AFTER)) {
184410639SDarren.Reed@Sun.COM if (!ipnetif_in_zone(ipnetif, zoneid, ips))
18458023SPhil.Kirk@Sun.COM continue;
18468023SPhil.Kirk@Sun.COM cbnode = kmem_zalloc(sizeof (ipnetif_cbdata_t), KM_SLEEP);
18478023SPhil.Kirk@Sun.COM (void) strlcpy(cbnode->ic_ifname, ipnetif->if_name, LIFNAMSIZ);
18488023SPhil.Kirk@Sun.COM cbnode->ic_dev = ipnetif->if_dev;
18498023SPhil.Kirk@Sun.COM list_insert_head(&cbdata, cbnode);
18508023SPhil.Kirk@Sun.COM }
18518023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_avl_lock);
18528023SPhil.Kirk@Sun.COM
18538023SPhil.Kirk@Sun.COM while ((cbnode = list_head(&cbdata)) != NULL) {
18548023SPhil.Kirk@Sun.COM cb(cbnode->ic_ifname, arg, cbnode->ic_dev);
18558023SPhil.Kirk@Sun.COM list_remove(&cbdata, cbnode);
18568023SPhil.Kirk@Sun.COM kmem_free(cbnode, sizeof (ipnetif_cbdata_t));
18578023SPhil.Kirk@Sun.COM }
18588023SPhil.Kirk@Sun.COM list_destroy(&cbdata);
18598023SPhil.Kirk@Sun.COM netstack_rele(ns);
18608023SPhil.Kirk@Sun.COM }
18618023SPhil.Kirk@Sun.COM
18628023SPhil.Kirk@Sun.COM static int
ipnetif_compare_index(const void * index_ptr,const void * ipnetifp)186310639SDarren.Reed@Sun.COM ipnetif_compare_index(const void *index_ptr, const void *ipnetifp)
18648023SPhil.Kirk@Sun.COM {
186510639SDarren.Reed@Sun.COM int64_t index1 = *((int64_t *)index_ptr);
186610639SDarren.Reed@Sun.COM int64_t index2 = (int64_t)((ipnetif_t *)ipnetifp)->if_index;
18678023SPhil.Kirk@Sun.COM
18688023SPhil.Kirk@Sun.COM return (SIGNOF(index2 - index1));
18698023SPhil.Kirk@Sun.COM }
18708023SPhil.Kirk@Sun.COM
18718023SPhil.Kirk@Sun.COM static int
ipnetif_compare_name(const void * name_ptr,const void * ipnetifp)187210639SDarren.Reed@Sun.COM ipnetif_compare_name(const void *name_ptr, const void *ipnetifp)
18738023SPhil.Kirk@Sun.COM {
187410639SDarren.Reed@Sun.COM int res;
18758023SPhil.Kirk@Sun.COM
18768023SPhil.Kirk@Sun.COM res = strcmp(((ipnetif_t *)ipnetifp)->if_name, name_ptr);
18778023SPhil.Kirk@Sun.COM return (SIGNOF(res));
18788023SPhil.Kirk@Sun.COM }
18798023SPhil.Kirk@Sun.COM
188010639SDarren.Reed@Sun.COM static int
ipnetif_compare_name_zone(const void * key_ptr,const void * ipnetifp)188110639SDarren.Reed@Sun.COM ipnetif_compare_name_zone(const void *key_ptr, const void *ipnetifp)
188210639SDarren.Reed@Sun.COM {
188310639SDarren.Reed@Sun.COM const uintptr_t *ptr = key_ptr;
188410639SDarren.Reed@Sun.COM const ipnetif_t *ifp;
188510639SDarren.Reed@Sun.COM int res;
188610639SDarren.Reed@Sun.COM
188710639SDarren.Reed@Sun.COM ifp = ipnetifp;
188810639SDarren.Reed@Sun.COM res = ifp->if_zoneid - ptr[0];
188910639SDarren.Reed@Sun.COM if (res != 0)
189010639SDarren.Reed@Sun.COM return (SIGNOF(res));
189110639SDarren.Reed@Sun.COM res = strcmp(ifp->if_name, (char *)ptr[1]);
189210639SDarren.Reed@Sun.COM return (SIGNOF(res));
189310639SDarren.Reed@Sun.COM }
189410639SDarren.Reed@Sun.COM
18958023SPhil.Kirk@Sun.COM static void
ipnetif_refhold(ipnetif_t * ipnetif)18968023SPhil.Kirk@Sun.COM ipnetif_refhold(ipnetif_t *ipnetif)
18978023SPhil.Kirk@Sun.COM {
18988023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_reflock);
18998023SPhil.Kirk@Sun.COM ipnetif->if_refcnt++;
19008023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_reflock);
19018023SPhil.Kirk@Sun.COM }
19028023SPhil.Kirk@Sun.COM
19038023SPhil.Kirk@Sun.COM static void
ipnetif_refrele(ipnetif_t * ipnetif)19048023SPhil.Kirk@Sun.COM ipnetif_refrele(ipnetif_t *ipnetif)
19058023SPhil.Kirk@Sun.COM {
19068023SPhil.Kirk@Sun.COM mutex_enter(&ipnetif->if_reflock);
190710639SDarren.Reed@Sun.COM ASSERT(ipnetif->if_refcnt > 0);
19088023SPhil.Kirk@Sun.COM if (--ipnetif->if_refcnt == 0)
190910639SDarren.Reed@Sun.COM ipnetif_free(ipnetif);
19108023SPhil.Kirk@Sun.COM else
19118023SPhil.Kirk@Sun.COM mutex_exit(&ipnetif->if_reflock);
19128023SPhil.Kirk@Sun.COM }
19138023SPhil.Kirk@Sun.COM
19148023SPhil.Kirk@Sun.COM static void
ipnet_walkers_inc(ipnet_stack_t * ips)19158023SPhil.Kirk@Sun.COM ipnet_walkers_inc(ipnet_stack_t *ips)
19168023SPhil.Kirk@Sun.COM {
19178023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_walkers_lock);
19188023SPhil.Kirk@Sun.COM ips->ips_walkers_cnt++;
19198023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_walkers_lock);
19208023SPhil.Kirk@Sun.COM }
19218023SPhil.Kirk@Sun.COM
19228023SPhil.Kirk@Sun.COM static void
ipnet_walkers_dec(ipnet_stack_t * ips)19238023SPhil.Kirk@Sun.COM ipnet_walkers_dec(ipnet_stack_t *ips)
19248023SPhil.Kirk@Sun.COM {
19258023SPhil.Kirk@Sun.COM mutex_enter(&ips->ips_walkers_lock);
19268023SPhil.Kirk@Sun.COM ASSERT(ips->ips_walkers_cnt != 0);
19278023SPhil.Kirk@Sun.COM if (--ips->ips_walkers_cnt == 0)
19288023SPhil.Kirk@Sun.COM cv_broadcast(&ips->ips_walkers_cv);
19298023SPhil.Kirk@Sun.COM mutex_exit(&ips->ips_walkers_lock);
19308023SPhil.Kirk@Sun.COM }
193110639SDarren.Reed@Sun.COM
193210639SDarren.Reed@Sun.COM /*ARGSUSED*/
193310639SDarren.Reed@Sun.COM static int
ipobs_bounce_func(hook_event_token_t token,hook_data_t info,void * arg)193410639SDarren.Reed@Sun.COM ipobs_bounce_func(hook_event_token_t token, hook_data_t info, void *arg)
193510639SDarren.Reed@Sun.COM {
193610639SDarren.Reed@Sun.COM hook_pkt_observe_t *hdr;
193710639SDarren.Reed@Sun.COM pfv_t func = (pfv_t)arg;
193810639SDarren.Reed@Sun.COM mblk_t *mp;
193910639SDarren.Reed@Sun.COM
194010639SDarren.Reed@Sun.COM hdr = (hook_pkt_observe_t *)info;
194110946SSangeeta.Misra@Sun.COM /*
194210946SSangeeta.Misra@Sun.COM * Code in ip_input() expects that it is the only one accessing the
194310946SSangeeta.Misra@Sun.COM * packet.
194410946SSangeeta.Misra@Sun.COM */
194510946SSangeeta.Misra@Sun.COM mp = copymsg(hdr->hpo_pkt);
194610946SSangeeta.Misra@Sun.COM if (mp == NULL) {
194710946SSangeeta.Misra@Sun.COM netstack_t *ns = hdr->hpo_ctx;
194810946SSangeeta.Misra@Sun.COM ipnet_stack_t *ips = ns->netstack_ipnet;
194910639SDarren.Reed@Sun.COM
195010946SSangeeta.Misra@Sun.COM IPSK_BUMP(ips, ik_dispatchDupDrop);
195110946SSangeeta.Misra@Sun.COM return (0);
195210639SDarren.Reed@Sun.COM }
195310639SDarren.Reed@Sun.COM
195410639SDarren.Reed@Sun.COM hdr = (hook_pkt_observe_t *)mp->b_rptr;
195510639SDarren.Reed@Sun.COM hdr->hpo_pkt = mp;
195610639SDarren.Reed@Sun.COM
195710639SDarren.Reed@Sun.COM func(mp);
195810639SDarren.Reed@Sun.COM
195910639SDarren.Reed@Sun.COM return (0);
196010639SDarren.Reed@Sun.COM }
196110639SDarren.Reed@Sun.COM
196210639SDarren.Reed@Sun.COM hook_t *
ipobs_register_hook(netstack_t * ns,pfv_t func)196310639SDarren.Reed@Sun.COM ipobs_register_hook(netstack_t *ns, pfv_t func)
196410639SDarren.Reed@Sun.COM {
196510639SDarren.Reed@Sun.COM ip_stack_t *ipst = ns->netstack_ip;
196610639SDarren.Reed@Sun.COM char name[32];
196710639SDarren.Reed@Sun.COM hook_t *hook;
196810639SDarren.Reed@Sun.COM
196910639SDarren.Reed@Sun.COM HOOK_INIT(hook, ipobs_bounce_func, "", (void *)func);
197010639SDarren.Reed@Sun.COM VERIFY(hook != NULL);
197110639SDarren.Reed@Sun.COM
197210639SDarren.Reed@Sun.COM /*
197310639SDarren.Reed@Sun.COM * To register multiple hooks with he same callback function,
197410639SDarren.Reed@Sun.COM * a unique name is needed.
197510639SDarren.Reed@Sun.COM */
197610746SDarren.Reed@Sun.COM (void) snprintf(name, sizeof (name), "ipobserve_%p", (void *)hook);
197710639SDarren.Reed@Sun.COM hook->h_name = strdup(name);
197810639SDarren.Reed@Sun.COM
197910639SDarren.Reed@Sun.COM (void) net_hook_register(ipst->ips_ip4_observe_pr, NH_OBSERVE, hook);
198010639SDarren.Reed@Sun.COM (void) net_hook_register(ipst->ips_ip6_observe_pr, NH_OBSERVE, hook);
198110639SDarren.Reed@Sun.COM
198210639SDarren.Reed@Sun.COM return (hook);
198310639SDarren.Reed@Sun.COM }
198410639SDarren.Reed@Sun.COM
198510639SDarren.Reed@Sun.COM void
ipobs_unregister_hook(netstack_t * ns,hook_t * hook)198610639SDarren.Reed@Sun.COM ipobs_unregister_hook(netstack_t *ns, hook_t *hook)
198710639SDarren.Reed@Sun.COM {
198810639SDarren.Reed@Sun.COM ip_stack_t *ipst = ns->netstack_ip;
198910639SDarren.Reed@Sun.COM
199010639SDarren.Reed@Sun.COM (void) net_hook_unregister(ipst->ips_ip4_observe_pr, NH_OBSERVE, hook);
199110639SDarren.Reed@Sun.COM
199210639SDarren.Reed@Sun.COM (void) net_hook_unregister(ipst->ips_ip6_observe_pr, NH_OBSERVE, hook);
199310639SDarren.Reed@Sun.COM
199410639SDarren.Reed@Sun.COM strfree(hook->h_name);
199510639SDarren.Reed@Sun.COM
199610639SDarren.Reed@Sun.COM hook_free(hook);
199710639SDarren.Reed@Sun.COM }
199810639SDarren.Reed@Sun.COM
199910639SDarren.Reed@Sun.COM /* ******************************************************************** */
200010639SDarren.Reed@Sun.COM /* BPF Functions below */
200110639SDarren.Reed@Sun.COM /* ******************************************************************** */
200210639SDarren.Reed@Sun.COM
200310639SDarren.Reed@Sun.COM /*
200410639SDarren.Reed@Sun.COM * Convenience function to make mapping a zoneid to an ipnet_stack_t easy.
200510639SDarren.Reed@Sun.COM */
200611179SDarren.Reed@Sun.COM ipnet_stack_t *
ipnet_find_by_zoneid(zoneid_t zoneid)200710639SDarren.Reed@Sun.COM ipnet_find_by_zoneid(zoneid_t zoneid)
200810639SDarren.Reed@Sun.COM {
200910639SDarren.Reed@Sun.COM netstack_t *ns;
201010639SDarren.Reed@Sun.COM
201110639SDarren.Reed@Sun.COM VERIFY((ns = netstack_find_by_zoneid(zoneid)) != NULL);
201210639SDarren.Reed@Sun.COM return (ns->netstack_ipnet);
201310639SDarren.Reed@Sun.COM }
201410639SDarren.Reed@Sun.COM
201510639SDarren.Reed@Sun.COM /*
201611179SDarren.Reed@Sun.COM * Functions, such as the above ipnet_find_by_zoneid(), will return a
201711179SDarren.Reed@Sun.COM * pointer to ipnet_stack_t by calling a netstack lookup function.
201811179SDarren.Reed@Sun.COM * The netstack_find_*() functions return a pointer after doing a "hold"
201911179SDarren.Reed@Sun.COM * on the data structure and thereby require a "release" when the caller
202011179SDarren.Reed@Sun.COM * is finished with it. We need to mirror that API here and thus a caller
202111179SDarren.Reed@Sun.COM * of ipnet_find_by_zoneid() is required to call ipnet_rele().
202210639SDarren.Reed@Sun.COM */
202311179SDarren.Reed@Sun.COM void
ipnet_rele(ipnet_stack_t * ips)202411179SDarren.Reed@Sun.COM ipnet_rele(ipnet_stack_t *ips)
202510639SDarren.Reed@Sun.COM {
202611179SDarren.Reed@Sun.COM netstack_rele(ips->ips_netstack);
202710639SDarren.Reed@Sun.COM }
202810639SDarren.Reed@Sun.COM
202910639SDarren.Reed@Sun.COM /*
203010639SDarren.Reed@Sun.COM */
203110639SDarren.Reed@Sun.COM void
ipnet_set_itap(bpf_itap_fn_t tapfunc)203211179SDarren.Reed@Sun.COM ipnet_set_itap(bpf_itap_fn_t tapfunc)
203310639SDarren.Reed@Sun.COM {
203411179SDarren.Reed@Sun.COM ipnet_itap = tapfunc;
203510639SDarren.Reed@Sun.COM }
203610639SDarren.Reed@Sun.COM
203710639SDarren.Reed@Sun.COM /*
203810639SDarren.Reed@Sun.COM * The list of interfaces available via ipnet is private for each zone,
203910639SDarren.Reed@Sun.COM * so the AVL tree of each zone must be searched for a given name, even
204010639SDarren.Reed@Sun.COM * if all names are unique.
204110639SDarren.Reed@Sun.COM */
204210639SDarren.Reed@Sun.COM int
ipnet_open_byname(const char * name,ipnetif_t ** ptr,zoneid_t zoneid)204310639SDarren.Reed@Sun.COM ipnet_open_byname(const char *name, ipnetif_t **ptr, zoneid_t zoneid)
204410639SDarren.Reed@Sun.COM {
204510639SDarren.Reed@Sun.COM ipnet_stack_t *ips;
204610639SDarren.Reed@Sun.COM ipnetif_t *ipnetif;
204710639SDarren.Reed@Sun.COM
204810639SDarren.Reed@Sun.COM ASSERT(ptr != NULL);
204910639SDarren.Reed@Sun.COM VERIFY((ips = ipnet_find_by_zoneid(zoneid)) != NULL);
205010639SDarren.Reed@Sun.COM
205110639SDarren.Reed@Sun.COM mutex_enter(&ips->ips_avl_lock);
205211179SDarren.Reed@Sun.COM
205311179SDarren.Reed@Sun.COM /*
205411179SDarren.Reed@Sun.COM * Shared instance zone?
205511179SDarren.Reed@Sun.COM */
205611179SDarren.Reed@Sun.COM if (netstackid_to_zoneid(zoneid_to_netstackid(zoneid)) != zoneid) {
205711179SDarren.Reed@Sun.COM uintptr_t key[2] = { zoneid, (uintptr_t)name };
205811179SDarren.Reed@Sun.COM
205911179SDarren.Reed@Sun.COM ipnetif = avl_find(&ips->ips_avl_by_shared, (void *)key, NULL);
206011179SDarren.Reed@Sun.COM } else {
206111179SDarren.Reed@Sun.COM ipnetif = avl_find(&ips->ips_avl_by_name, (void *)name, NULL);
206211179SDarren.Reed@Sun.COM }
206311179SDarren.Reed@Sun.COM if (ipnetif != NULL)
206410639SDarren.Reed@Sun.COM ipnetif_refhold(ipnetif);
206510639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
206610639SDarren.Reed@Sun.COM
206710639SDarren.Reed@Sun.COM *ptr = ipnetif;
206811179SDarren.Reed@Sun.COM ipnet_rele(ips);
206910639SDarren.Reed@Sun.COM
207010639SDarren.Reed@Sun.COM if (ipnetif == NULL)
207110639SDarren.Reed@Sun.COM return (ESRCH);
207210639SDarren.Reed@Sun.COM return (0);
207310639SDarren.Reed@Sun.COM }
207410639SDarren.Reed@Sun.COM
207510639SDarren.Reed@Sun.COM void
ipnet_close_byhandle(ipnetif_t * ifp)207610639SDarren.Reed@Sun.COM ipnet_close_byhandle(ipnetif_t *ifp)
207710639SDarren.Reed@Sun.COM {
207810639SDarren.Reed@Sun.COM ASSERT(ifp != NULL);
207910639SDarren.Reed@Sun.COM ipnetif_refrele(ifp);
208010639SDarren.Reed@Sun.COM }
208110639SDarren.Reed@Sun.COM
208210639SDarren.Reed@Sun.COM const char *
ipnet_name(ipnetif_t * ifp)208310639SDarren.Reed@Sun.COM ipnet_name(ipnetif_t *ifp)
208410639SDarren.Reed@Sun.COM {
208510639SDarren.Reed@Sun.COM ASSERT(ifp != NULL);
208610639SDarren.Reed@Sun.COM return (ifp->if_name);
208710639SDarren.Reed@Sun.COM }
208810639SDarren.Reed@Sun.COM
208910639SDarren.Reed@Sun.COM /*
209010639SDarren.Reed@Sun.COM * To find the linkid for a given name, it is necessary to know which zone
209110639SDarren.Reed@Sun.COM * the interface name belongs to and to search the avl tree for that zone
209210639SDarren.Reed@Sun.COM * as there is no master list of all interfaces and which zone they belong
209310639SDarren.Reed@Sun.COM * to. It is assumed that the caller of this function is somehow already
209410639SDarren.Reed@Sun.COM * working with the ipnet interfaces and hence the ips_event_lock is held.
209510639SDarren.Reed@Sun.COM * When BPF calls into this function, it is doing so because of an event
209610639SDarren.Reed@Sun.COM * in ipnet, and thus ipnet holds the ips_event_lock. Thus the datalink id
209710639SDarren.Reed@Sun.COM * value returned has meaning without the need for grabbing a hold on the
209810639SDarren.Reed@Sun.COM * owning structure.
209910639SDarren.Reed@Sun.COM */
210010639SDarren.Reed@Sun.COM int
ipnet_get_linkid_byname(const char * name,uint_t * idp,zoneid_t zoneid)210110639SDarren.Reed@Sun.COM ipnet_get_linkid_byname(const char *name, uint_t *idp, zoneid_t zoneid)
210210639SDarren.Reed@Sun.COM {
210310639SDarren.Reed@Sun.COM ipnet_stack_t *ips;
210410639SDarren.Reed@Sun.COM ipnetif_t *ifp;
210510639SDarren.Reed@Sun.COM
210610639SDarren.Reed@Sun.COM VERIFY((ips = ipnet_find_by_zoneid(zoneid)) != NULL);
210710639SDarren.Reed@Sun.COM ASSERT(mutex_owned(&ips->ips_event_lock));
210810639SDarren.Reed@Sun.COM
210910639SDarren.Reed@Sun.COM mutex_enter(&ips->ips_avl_lock);
211010639SDarren.Reed@Sun.COM ifp = avl_find(&ips->ips_avl_by_name, (void *)name, NULL);
211110639SDarren.Reed@Sun.COM if (ifp != NULL)
211210639SDarren.Reed@Sun.COM *idp = (uint_t)ifp->if_index;
211310639SDarren.Reed@Sun.COM
211410639SDarren.Reed@Sun.COM /*
211510639SDarren.Reed@Sun.COM * Shared instance zone?
211610639SDarren.Reed@Sun.COM */
211710639SDarren.Reed@Sun.COM if (netstackid_to_zoneid(zoneid_to_netstackid(zoneid)) != zoneid) {
211810639SDarren.Reed@Sun.COM uintptr_t key[2] = { zoneid, (uintptr_t)name };
211910639SDarren.Reed@Sun.COM
212010639SDarren.Reed@Sun.COM ifp = avl_find(&ips->ips_avl_by_shared, (void *)key, NULL);
212110639SDarren.Reed@Sun.COM if (ifp != NULL)
212210639SDarren.Reed@Sun.COM *idp = (uint_t)ifp->if_index;
212310639SDarren.Reed@Sun.COM }
212410639SDarren.Reed@Sun.COM
212510639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
212611179SDarren.Reed@Sun.COM ipnet_rele(ips);
212710639SDarren.Reed@Sun.COM
212810639SDarren.Reed@Sun.COM if (ifp == NULL)
212910639SDarren.Reed@Sun.COM return (ESRCH);
213010639SDarren.Reed@Sun.COM return (0);
213110639SDarren.Reed@Sun.COM }
213210639SDarren.Reed@Sun.COM
213310639SDarren.Reed@Sun.COM /*
213410639SDarren.Reed@Sun.COM * Strictly speaking, there is no such thing as a "client" in ipnet, like
213510639SDarren.Reed@Sun.COM * there is in mac. BPF only needs to have this because it is required as
213610639SDarren.Reed@Sun.COM * part of interfacing correctly with mac. The reuse of the original
213710639SDarren.Reed@Sun.COM * ipnetif_t as a client poses no danger, so long as it is done with its
213810639SDarren.Reed@Sun.COM * own ref-count'd hold that is given up on close.
213910639SDarren.Reed@Sun.COM */
214010639SDarren.Reed@Sun.COM int
ipnet_client_open(ipnetif_t * ptr,ipnetif_t ** result)214110639SDarren.Reed@Sun.COM ipnet_client_open(ipnetif_t *ptr, ipnetif_t **result)
214210639SDarren.Reed@Sun.COM {
214310639SDarren.Reed@Sun.COM ASSERT(ptr != NULL);
214410639SDarren.Reed@Sun.COM ASSERT(result != NULL);
214510639SDarren.Reed@Sun.COM ipnetif_refhold(ptr);
214610639SDarren.Reed@Sun.COM *result = ptr;
214710639SDarren.Reed@Sun.COM
214810639SDarren.Reed@Sun.COM return (0);
214910639SDarren.Reed@Sun.COM }
215010639SDarren.Reed@Sun.COM
215110639SDarren.Reed@Sun.COM void
ipnet_client_close(ipnetif_t * ptr)215210639SDarren.Reed@Sun.COM ipnet_client_close(ipnetif_t *ptr)
215310639SDarren.Reed@Sun.COM {
215410639SDarren.Reed@Sun.COM ASSERT(ptr != NULL);
215510639SDarren.Reed@Sun.COM ipnetif_refrele(ptr);
215610639SDarren.Reed@Sun.COM }
215710639SDarren.Reed@Sun.COM
215810639SDarren.Reed@Sun.COM /*
215910639SDarren.Reed@Sun.COM * This is called from BPF when it needs to start receiving packets
216010639SDarren.Reed@Sun.COM * from ipnet.
216110639SDarren.Reed@Sun.COM *
216210639SDarren.Reed@Sun.COM * The use of the ipnet_t structure here is somewhat lightweight when
216310639SDarren.Reed@Sun.COM * compared to how it is used elsewhere but it already has all of the
216410639SDarren.Reed@Sun.COM * right fields in it, so reuse here doesn't seem out of order. Its
216510639SDarren.Reed@Sun.COM * primary purpose here is to provide the means to store pointers for
216610639SDarren.Reed@Sun.COM * use when ipnet_promisc_remove() needs to be called.
216710639SDarren.Reed@Sun.COM *
216810639SDarren.Reed@Sun.COM * This should never be called for the IPNET_MINOR_LO device as it is
216910639SDarren.Reed@Sun.COM * never created via ipnetif_create.
217010639SDarren.Reed@Sun.COM */
217110639SDarren.Reed@Sun.COM /*ARGSUSED*/
217210639SDarren.Reed@Sun.COM int
ipnet_promisc_add(void * handle,uint_t how,void * data,uintptr_t * mhandle,int flags)217310639SDarren.Reed@Sun.COM ipnet_promisc_add(void *handle, uint_t how, void *data, uintptr_t *mhandle,
217410639SDarren.Reed@Sun.COM int flags)
217510639SDarren.Reed@Sun.COM {
217610639SDarren.Reed@Sun.COM ip_stack_t *ipst;
217710639SDarren.Reed@Sun.COM netstack_t *ns;
217810639SDarren.Reed@Sun.COM ipnetif_t *ifp;
217910639SDarren.Reed@Sun.COM ipnet_t *ipnet;
218010639SDarren.Reed@Sun.COM char name[32];
218110639SDarren.Reed@Sun.COM int error;
218210639SDarren.Reed@Sun.COM
218310639SDarren.Reed@Sun.COM ifp = (ipnetif_t *)handle;
218410639SDarren.Reed@Sun.COM ns = netstack_find_by_zoneid(ifp->if_zoneid);
218510639SDarren.Reed@Sun.COM
218610639SDarren.Reed@Sun.COM if ((how == DL_PROMISC_PHYS) || (how == DL_PROMISC_MULTI)) {
218710639SDarren.Reed@Sun.COM error = ipnet_join_allmulti(ifp, ns->netstack_ipnet);
218810639SDarren.Reed@Sun.COM if (error != 0)
218910639SDarren.Reed@Sun.COM return (error);
219010639SDarren.Reed@Sun.COM } else {
219110639SDarren.Reed@Sun.COM return (EINVAL);
219210639SDarren.Reed@Sun.COM }
219310639SDarren.Reed@Sun.COM
219410639SDarren.Reed@Sun.COM ipnet = kmem_zalloc(sizeof (*ipnet), KM_SLEEP);
219510639SDarren.Reed@Sun.COM ipnet->ipnet_if = ifp;
219610639SDarren.Reed@Sun.COM ipnet->ipnet_ns = ns;
219710639SDarren.Reed@Sun.COM ipnet->ipnet_flags = flags;
219810639SDarren.Reed@Sun.COM
219910639SDarren.Reed@Sun.COM if ((ifp->if_flags & IPNETIF_LOOPBACK) != 0) {
220010639SDarren.Reed@Sun.COM ipnet->ipnet_acceptfn = ipnet_loaccept;
220110639SDarren.Reed@Sun.COM } else {
220210639SDarren.Reed@Sun.COM ipnet->ipnet_acceptfn = ipnet_accept;
220310639SDarren.Reed@Sun.COM }
220410639SDarren.Reed@Sun.COM
220510639SDarren.Reed@Sun.COM /*
220610639SDarren.Reed@Sun.COM * To register multiple hooks with the same callback function,
220710639SDarren.Reed@Sun.COM * a unique name is needed.
220810639SDarren.Reed@Sun.COM */
220910639SDarren.Reed@Sun.COM HOOK_INIT(ipnet->ipnet_hook, ipnet_bpf_bounce, "", ipnet);
221010639SDarren.Reed@Sun.COM (void) snprintf(name, sizeof (name), "ipnet_promisc_%p",
221110746SDarren.Reed@Sun.COM (void *)ipnet->ipnet_hook);
221210639SDarren.Reed@Sun.COM ipnet->ipnet_hook->h_name = strdup(name);
221310639SDarren.Reed@Sun.COM ipnet->ipnet_data = data;
221410639SDarren.Reed@Sun.COM ipnet->ipnet_zoneid = ifp->if_zoneid;
221510639SDarren.Reed@Sun.COM
221610639SDarren.Reed@Sun.COM ipst = ns->netstack_ip;
221710639SDarren.Reed@Sun.COM
221810639SDarren.Reed@Sun.COM error = net_hook_register(ipst->ips_ip4_observe_pr, NH_OBSERVE,
221910639SDarren.Reed@Sun.COM ipnet->ipnet_hook);
222010639SDarren.Reed@Sun.COM if (error != 0)
222110639SDarren.Reed@Sun.COM goto regfail;
222210639SDarren.Reed@Sun.COM
222310639SDarren.Reed@Sun.COM error = net_hook_register(ipst->ips_ip6_observe_pr, NH_OBSERVE,
222410639SDarren.Reed@Sun.COM ipnet->ipnet_hook);
222510639SDarren.Reed@Sun.COM if (error != 0) {
222610639SDarren.Reed@Sun.COM (void) net_hook_unregister(ipst->ips_ip4_observe_pr,
222710639SDarren.Reed@Sun.COM NH_OBSERVE, ipnet->ipnet_hook);
222810639SDarren.Reed@Sun.COM goto regfail;
222910639SDarren.Reed@Sun.COM }
223010639SDarren.Reed@Sun.COM
223110639SDarren.Reed@Sun.COM *mhandle = (uintptr_t)ipnet;
223211179SDarren.Reed@Sun.COM netstack_rele(ns);
223310639SDarren.Reed@Sun.COM
223410639SDarren.Reed@Sun.COM return (0);
223510639SDarren.Reed@Sun.COM
223610639SDarren.Reed@Sun.COM regfail:
223710639SDarren.Reed@Sun.COM cmn_err(CE_WARN, "net_hook_register failed: %d", error);
223810639SDarren.Reed@Sun.COM strfree(ipnet->ipnet_hook->h_name);
223910639SDarren.Reed@Sun.COM hook_free(ipnet->ipnet_hook);
224011179SDarren.Reed@Sun.COM netstack_rele(ns);
224110639SDarren.Reed@Sun.COM return (error);
224210639SDarren.Reed@Sun.COM }
224310639SDarren.Reed@Sun.COM
224410639SDarren.Reed@Sun.COM void
ipnet_promisc_remove(void * data)224510639SDarren.Reed@Sun.COM ipnet_promisc_remove(void *data)
224610639SDarren.Reed@Sun.COM {
224710639SDarren.Reed@Sun.COM ip_stack_t *ipst;
224810639SDarren.Reed@Sun.COM ipnet_t *ipnet;
224910639SDarren.Reed@Sun.COM hook_t *hook;
225010639SDarren.Reed@Sun.COM
225110639SDarren.Reed@Sun.COM ipnet = data;
225210639SDarren.Reed@Sun.COM ipst = ipnet->ipnet_ns->netstack_ip;
225310639SDarren.Reed@Sun.COM hook = ipnet->ipnet_hook;
225410639SDarren.Reed@Sun.COM
225510639SDarren.Reed@Sun.COM VERIFY(net_hook_unregister(ipst->ips_ip4_observe_pr, NH_OBSERVE,
225610639SDarren.Reed@Sun.COM hook) == 0);
225710639SDarren.Reed@Sun.COM
225810639SDarren.Reed@Sun.COM VERIFY(net_hook_unregister(ipst->ips_ip6_observe_pr, NH_OBSERVE,
225910639SDarren.Reed@Sun.COM hook) == 0);
226010639SDarren.Reed@Sun.COM
226110639SDarren.Reed@Sun.COM strfree(hook->h_name);
226210639SDarren.Reed@Sun.COM
226310639SDarren.Reed@Sun.COM hook_free(hook);
226410639SDarren.Reed@Sun.COM
226510639SDarren.Reed@Sun.COM kmem_free(ipnet, sizeof (*ipnet));
226610639SDarren.Reed@Sun.COM }
226710639SDarren.Reed@Sun.COM
226810639SDarren.Reed@Sun.COM /*
226910639SDarren.Reed@Sun.COM * arg here comes from the ipnet_t allocated in ipnet_promisc_add.
227010639SDarren.Reed@Sun.COM * An important field from that structure is "ipnet_data" that
227110639SDarren.Reed@Sun.COM * contains the "data" pointer passed into ipnet_promisc_add: it needs
227210639SDarren.Reed@Sun.COM * to be passed back to bpf when we call into ipnet_itap.
227310639SDarren.Reed@Sun.COM *
227410639SDarren.Reed@Sun.COM * ipnet_itap is set by ipnet_set_bpfattach, which in turn is called
227510639SDarren.Reed@Sun.COM * from BPF.
227610639SDarren.Reed@Sun.COM */
227710639SDarren.Reed@Sun.COM /*ARGSUSED*/
227810639SDarren.Reed@Sun.COM static int
ipnet_bpf_bounce(hook_event_token_t token,hook_data_t info,void * arg)227910639SDarren.Reed@Sun.COM ipnet_bpf_bounce(hook_event_token_t token, hook_data_t info, void *arg)
228010639SDarren.Reed@Sun.COM {
228110639SDarren.Reed@Sun.COM hook_pkt_observe_t *hdr;
228210639SDarren.Reed@Sun.COM ipnet_addrp_t src;
228310639SDarren.Reed@Sun.COM ipnet_addrp_t dst;
228410639SDarren.Reed@Sun.COM ipnet_stack_t *ips;
228510639SDarren.Reed@Sun.COM ipnet_t *ipnet;
228610639SDarren.Reed@Sun.COM mblk_t *netmp;
228710639SDarren.Reed@Sun.COM mblk_t *mp;
228810639SDarren.Reed@Sun.COM
228910639SDarren.Reed@Sun.COM hdr = (hook_pkt_observe_t *)info;
229010639SDarren.Reed@Sun.COM mp = hdr->hpo_pkt;
229110639SDarren.Reed@Sun.COM ipnet = (ipnet_t *)arg;
229210639SDarren.Reed@Sun.COM ips = ((netstack_t *)hdr->hpo_ctx)->netstack_ipnet;
229310639SDarren.Reed@Sun.COM
229410639SDarren.Reed@Sun.COM netmp = hdr->hpo_pkt->b_cont;
229510639SDarren.Reed@Sun.COM src.iap_family = hdr->hpo_family;
229610639SDarren.Reed@Sun.COM dst.iap_family = hdr->hpo_family;
229710639SDarren.Reed@Sun.COM
229810639SDarren.Reed@Sun.COM if (hdr->hpo_family == AF_INET) {
229910639SDarren.Reed@Sun.COM src.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_src;
230010639SDarren.Reed@Sun.COM dst.iap_addr4 = &((ipha_t *)(netmp->b_rptr))->ipha_dst;
230110639SDarren.Reed@Sun.COM } else {
230210639SDarren.Reed@Sun.COM src.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_src;
230310639SDarren.Reed@Sun.COM dst.iap_addr6 = &((ip6_t *)(netmp->b_rptr))->ip6_dst;
230410639SDarren.Reed@Sun.COM }
230510639SDarren.Reed@Sun.COM
230610639SDarren.Reed@Sun.COM if (!(*ipnet->ipnet_acceptfn)(ipnet, hdr, &src, &dst)) {
230710639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_acceptFail);
230810639SDarren.Reed@Sun.COM return (0);
230910639SDarren.Reed@Sun.COM }
231010639SDarren.Reed@Sun.COM IPSK_BUMP(ips, ik_acceptOk);
231110639SDarren.Reed@Sun.COM
231210639SDarren.Reed@Sun.COM ipnet_itap(ipnet->ipnet_data, mp,
2313*11258SDarren.Reed@Sun.COM hdr->hpo_htype == htons(IPOBS_HOOK_OUTBOUND),
231411179SDarren.Reed@Sun.COM ntohl(hdr->hpo_pktlen) + MBLKL(mp));
231510639SDarren.Reed@Sun.COM
231610639SDarren.Reed@Sun.COM return (0);
231710639SDarren.Reed@Sun.COM }
231810639SDarren.Reed@Sun.COM
231910639SDarren.Reed@Sun.COM /*
232010639SDarren.Reed@Sun.COM * clone'd ipnetif_t's are created when a shared IP instance zone comes
232110639SDarren.Reed@Sun.COM * to life and configures an IP address. The model that BPF uses is that
232210639SDarren.Reed@Sun.COM * each interface must have a unique pointer and each interface must be
232310639SDarren.Reed@Sun.COM * representative of what it can capture. They are limited to one DLT
232410639SDarren.Reed@Sun.COM * per interface and one zone per interface. Thus every interface that
232510639SDarren.Reed@Sun.COM * can be seen in a zone must be announced via an attach to bpf. For
232610639SDarren.Reed@Sun.COM * shared instance zones, this means the ipnet driver needs to detect
232710639SDarren.Reed@Sun.COM * when an address is added to an interface in a zone for the first
232810639SDarren.Reed@Sun.COM * time (and also when the last address is removed.)
232910639SDarren.Reed@Sun.COM */
233010639SDarren.Reed@Sun.COM static ipnetif_t *
ipnetif_clone_create(ipnetif_t * ifp,zoneid_t zoneid)233110639SDarren.Reed@Sun.COM ipnetif_clone_create(ipnetif_t *ifp, zoneid_t zoneid)
233210639SDarren.Reed@Sun.COM {
233310639SDarren.Reed@Sun.COM uintptr_t key[2] = { zoneid, (uintptr_t)ifp->if_name };
233410639SDarren.Reed@Sun.COM ipnet_stack_t *ips = ifp->if_stackp;
233510639SDarren.Reed@Sun.COM avl_index_t where = 0;
233610639SDarren.Reed@Sun.COM ipnetif_t *newif;
233710639SDarren.Reed@Sun.COM
233810639SDarren.Reed@Sun.COM mutex_enter(&ips->ips_avl_lock);
233910639SDarren.Reed@Sun.COM newif = avl_find(&ips->ips_avl_by_shared, (void *)key, &where);
234010639SDarren.Reed@Sun.COM if (newif != NULL) {
234110639SDarren.Reed@Sun.COM ipnetif_refhold(newif);
234210639SDarren.Reed@Sun.COM newif->if_sharecnt++;
234310639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
234410639SDarren.Reed@Sun.COM return (newif);
234510639SDarren.Reed@Sun.COM }
234610639SDarren.Reed@Sun.COM
234710639SDarren.Reed@Sun.COM newif = ipnet_alloc_if(ips);
234810639SDarren.Reed@Sun.COM if (newif == NULL) {
234910639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
235010639SDarren.Reed@Sun.COM return (NULL);
235110639SDarren.Reed@Sun.COM }
235210639SDarren.Reed@Sun.COM
235310639SDarren.Reed@Sun.COM newif->if_refcnt = 1;
235410639SDarren.Reed@Sun.COM newif->if_sharecnt = 1;
235510639SDarren.Reed@Sun.COM newif->if_zoneid = zoneid;
235610639SDarren.Reed@Sun.COM (void) strlcpy(newif->if_name, ifp->if_name, LIFNAMSIZ);
235710639SDarren.Reed@Sun.COM newif->if_flags = ifp->if_flags & IPNETIF_LOOPBACK;
235810639SDarren.Reed@Sun.COM newif->if_index = ifp->if_index;
235910639SDarren.Reed@Sun.COM
236010639SDarren.Reed@Sun.COM avl_insert(&ips->ips_avl_by_shared, newif, where);
236110639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
236210639SDarren.Reed@Sun.COM
236310639SDarren.Reed@Sun.COM return (newif);
236410639SDarren.Reed@Sun.COM }
236510639SDarren.Reed@Sun.COM
236610639SDarren.Reed@Sun.COM static void
ipnetif_clone_release(ipnetif_t * ipnetif)236710639SDarren.Reed@Sun.COM ipnetif_clone_release(ipnetif_t *ipnetif)
236810639SDarren.Reed@Sun.COM {
236910639SDarren.Reed@Sun.COM boolean_t dofree = B_FALSE;
237010639SDarren.Reed@Sun.COM boolean_t doremove = B_FALSE;
237110639SDarren.Reed@Sun.COM ipnet_stack_t *ips = ipnetif->if_stackp;
237210639SDarren.Reed@Sun.COM
237310639SDarren.Reed@Sun.COM mutex_enter(&ipnetif->if_reflock);
237410639SDarren.Reed@Sun.COM ASSERT(ipnetif->if_refcnt > 0);
237510639SDarren.Reed@Sun.COM if (--ipnetif->if_refcnt == 0)
237610639SDarren.Reed@Sun.COM dofree = B_TRUE;
237710639SDarren.Reed@Sun.COM ASSERT(ipnetif->if_sharecnt > 0);
237810639SDarren.Reed@Sun.COM if (--ipnetif->if_sharecnt == 0)
237910639SDarren.Reed@Sun.COM doremove = B_TRUE;
238010639SDarren.Reed@Sun.COM mutex_exit(&ipnetif->if_reflock);
238110639SDarren.Reed@Sun.COM if (doremove) {
238210639SDarren.Reed@Sun.COM mutex_enter(&ips->ips_avl_lock);
238310639SDarren.Reed@Sun.COM avl_remove(&ips->ips_avl_by_shared, ipnetif);
238410639SDarren.Reed@Sun.COM mutex_exit(&ips->ips_avl_lock);
238510639SDarren.Reed@Sun.COM }
238610639SDarren.Reed@Sun.COM if (dofree) {
238710639SDarren.Reed@Sun.COM ASSERT(ipnetif->if_sharecnt == 0);
238810639SDarren.Reed@Sun.COM ipnetif_free(ipnetif);
238910639SDarren.Reed@Sun.COM }
239010639SDarren.Reed@Sun.COM }
2391