1ab25eeb5Syz /* 2ab25eeb5Syz * Copyright (C) 1993-2001, 2003 by Darren Reed. 3ab25eeb5Syz * 4ab25eeb5Syz * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz * 67ddc9b1aSDarren Reed * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 7ab25eeb5Syz * Use is subject to license terms. 8ab25eeb5Syz */ 9ab25eeb5Syz 10ab25eeb5Syz #include <sys/systm.h> 11ab25eeb5Syz #include <sys/types.h> 12ab25eeb5Syz #include <sys/param.h> 13ab25eeb5Syz #include <sys/errno.h> 14ab25eeb5Syz #include <sys/uio.h> 15ab25eeb5Syz #include <sys/buf.h> 16ab25eeb5Syz #include <sys/modctl.h> 17ab25eeb5Syz #include <sys/open.h> 18ab25eeb5Syz #include <sys/kmem.h> 19ab25eeb5Syz #include <sys/conf.h> 20ab25eeb5Syz #include <sys/cmn_err.h> 21ab25eeb5Syz #include <sys/stat.h> 22ab25eeb5Syz #include <sys/cred.h> 23ab25eeb5Syz #include <sys/dditypes.h> 24ab25eeb5Syz #include <sys/poll.h> 25ab25eeb5Syz #include <sys/autoconf.h> 26ab25eeb5Syz #include <sys/byteorder.h> 27ab25eeb5Syz #include <sys/socket.h> 28ab25eeb5Syz #include <sys/dlpi.h> 29ab25eeb5Syz #include <sys/stropts.h> 30ab25eeb5Syz #include <sys/kstat.h> 31ab25eeb5Syz #include <sys/sockio.h> 32381a2a9aSdr #include <sys/neti.h> 33381a2a9aSdr #include <sys/hook.h> 34ab25eeb5Syz #include <net/if.h> 35ab25eeb5Syz #if SOLARIS2 >= 6 36*19397407SSherry Moore #include <net/if_types.h> 37ab25eeb5Syz #endif 38ab25eeb5Syz #include <net/af.h> 39ab25eeb5Syz #include <net/route.h> 40ab25eeb5Syz #include <netinet/in.h> 41ab25eeb5Syz #include <netinet/in_systm.h> 42ab25eeb5Syz #include <netinet/if_ether.h> 43ab25eeb5Syz #include <netinet/ip.h> 44ab25eeb5Syz #include <netinet/ip_var.h> 45ab25eeb5Syz #include <netinet/tcp.h> 46ab25eeb5Syz #include <netinet/udp.h> 47ab25eeb5Syz #include <netinet/tcpip.h> 48ab25eeb5Syz #include <netinet/ip_icmp.h> 49ab25eeb5Syz #include <sys/ddi.h> 50ab25eeb5Syz #include <sys/sunddi.h> 51ab25eeb5Syz #include "netinet/ip_compat.h" 52ab25eeb5Syz #include "netinet/ipl.h" 53ab25eeb5Syz #include "netinet/ip_fil.h" 54ab25eeb5Syz #include "netinet/ip_nat.h" 55ab25eeb5Syz #include "netinet/ip_frag.h" 56ab25eeb5Syz #include "netinet/ip_auth.h" 57ab25eeb5Syz #include "netinet/ip_state.h" 58f4b3ec61Sdh #include "netinet/ipf_stack.h" 59ab25eeb5Syz 60ab25eeb5Syz extern int iplwrite __P((dev_t, struct uio *, cred_t *)); 61ab25eeb5Syz 62ab25eeb5Syz static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t, 63*19397407SSherry Moore void *, void **)); 64ab25eeb5Syz #if SOLARIS2 < 10 65ab25eeb5Syz static int ipf_identify __P((dev_info_t *)); 66ab25eeb5Syz #endif 67ab25eeb5Syz static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t)); 68ab25eeb5Syz static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t)); 697ddc9b1aSDarren Reed static void *ipf_stack_create __P((const netid_t)); 707ddc9b1aSDarren Reed static void ipf_stack_destroy __P((const netid_t, void *)); 71f4b3ec61Sdh static int ipf_property_g_update __P((dev_info_t *)); 72ab25eeb5Syz static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 73ab25eeb5Syz IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 74ab25eeb5Syz IPLOOKUP_NAME, NULL }; 75ab25eeb5Syz 76ab25eeb5Syz 77ab25eeb5Syz static struct cb_ops ipf_cb_ops = { 78ab25eeb5Syz iplopen, 79ab25eeb5Syz iplclose, 80ab25eeb5Syz nodev, /* strategy */ 81ab25eeb5Syz nodev, /* print */ 82ab25eeb5Syz nodev, /* dump */ 83ab25eeb5Syz iplread, 84ab25eeb5Syz iplwrite, /* write */ 85ab25eeb5Syz iplioctl, /* ioctl */ 86ab25eeb5Syz nodev, /* devmap */ 87ab25eeb5Syz nodev, /* mmap */ 88ab25eeb5Syz nodev, /* segmap */ 89ab25eeb5Syz nochpoll, /* poll */ 90ab25eeb5Syz ddi_prop_op, 91ab25eeb5Syz NULL, 92ab25eeb5Syz D_MTSAFE, 93ab25eeb5Syz #if SOLARIS2 > 4 94ab25eeb5Syz CB_REV, 95ab25eeb5Syz nodev, /* aread */ 96ab25eeb5Syz nodev, /* awrite */ 97ab25eeb5Syz #endif 98ab25eeb5Syz }; 99ab25eeb5Syz 100ab25eeb5Syz static struct dev_ops ipf_ops = { 101ab25eeb5Syz DEVO_REV, 102ab25eeb5Syz 0, 103ab25eeb5Syz ipf_getinfo, 104ab25eeb5Syz #if SOLARIS2 >= 10 105ab25eeb5Syz nulldev, 106ab25eeb5Syz #else 107ab25eeb5Syz ipf_identify, 108ab25eeb5Syz #endif 109ab25eeb5Syz nulldev, 110ab25eeb5Syz ipf_attach, 111ab25eeb5Syz ipf_detach, 112ab25eeb5Syz nodev, /* reset */ 113ab25eeb5Syz &ipf_cb_ops, 114*19397407SSherry Moore (struct bus_ops *)0, 115*19397407SSherry Moore NULL, 116*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 117ab25eeb5Syz }; 118ab25eeb5Syz 1197ddc9b1aSDarren Reed 1207ddc9b1aSDarren Reed static net_instance_t *ipfncb = NULL; 1217ddc9b1aSDarren Reed static ipf_stack_t *ipf_stacks = NULL; 1227ddc9b1aSDarren Reed static kmutex_t ipf_stack_lock; 123ab25eeb5Syz extern struct mod_ops mod_driverops; 124ab25eeb5Syz static struct modldrv iplmod = { 125ab25eeb5Syz &mod_driverops, IPL_VERSION, &ipf_ops }; 126ab25eeb5Syz static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL }; 127ab25eeb5Syz 128ab25eeb5Syz #if SOLARIS2 >= 6 129ab25eeb5Syz static size_t hdrsizes[57][2] = { 130ab25eeb5Syz { 0, 0 }, 131ab25eeb5Syz { IFT_OTHER, 0 }, 132ab25eeb5Syz { IFT_1822, 0 }, 133ab25eeb5Syz { IFT_HDH1822, 0 }, 134ab25eeb5Syz { IFT_X25DDN, 0 }, 135ab25eeb5Syz { IFT_X25, 0 }, 136ab25eeb5Syz { IFT_ETHER, 14 }, 137ab25eeb5Syz { IFT_ISO88023, 0 }, 138ab25eeb5Syz { IFT_ISO88024, 0 }, 139ab25eeb5Syz { IFT_ISO88025, 0 }, 140ab25eeb5Syz { IFT_ISO88026, 0 }, 141ab25eeb5Syz { IFT_STARLAN, 0 }, 142ab25eeb5Syz { IFT_P10, 0 }, 143ab25eeb5Syz { IFT_P80, 0 }, 144ab25eeb5Syz { IFT_HY, 0 }, 145ab25eeb5Syz { IFT_FDDI, 24 }, 146ab25eeb5Syz { IFT_LAPB, 0 }, 147ab25eeb5Syz { IFT_SDLC, 0 }, 148ab25eeb5Syz { IFT_T1, 0 }, 149ab25eeb5Syz { IFT_CEPT, 0 }, 150ab25eeb5Syz { IFT_ISDNBASIC, 0 }, 151ab25eeb5Syz { IFT_ISDNPRIMARY, 0 }, 152ab25eeb5Syz { IFT_PTPSERIAL, 0 }, 153ab25eeb5Syz { IFT_PPP, 0 }, 154ab25eeb5Syz { IFT_LOOP, 0 }, 155ab25eeb5Syz { IFT_EON, 0 }, 156ab25eeb5Syz { IFT_XETHER, 0 }, 157ab25eeb5Syz { IFT_NSIP, 0 }, 158ab25eeb5Syz { IFT_SLIP, 0 }, 159ab25eeb5Syz { IFT_ULTRA, 0 }, 160ab25eeb5Syz { IFT_DS3, 0 }, 161ab25eeb5Syz { IFT_SIP, 0 }, 162ab25eeb5Syz { IFT_FRELAY, 0 }, 163ab25eeb5Syz { IFT_RS232, 0 }, 164ab25eeb5Syz { IFT_PARA, 0 }, 165ab25eeb5Syz { IFT_ARCNET, 0 }, 166ab25eeb5Syz { IFT_ARCNETPLUS, 0 }, 167ab25eeb5Syz { IFT_ATM, 0 }, 168ab25eeb5Syz { IFT_MIOX25, 0 }, 169ab25eeb5Syz { IFT_SONET, 0 }, 170ab25eeb5Syz { IFT_X25PLE, 0 }, 171ab25eeb5Syz { IFT_ISO88022LLC, 0 }, 172ab25eeb5Syz { IFT_LOCALTALK, 0 }, 173ab25eeb5Syz { IFT_SMDSDXI, 0 }, 174ab25eeb5Syz { IFT_FRELAYDCE, 0 }, 175ab25eeb5Syz { IFT_V35, 0 }, 176ab25eeb5Syz { IFT_HSSI, 0 }, 177ab25eeb5Syz { IFT_HIPPI, 0 }, 178ab25eeb5Syz { IFT_MODEM, 0 }, 179ab25eeb5Syz { IFT_AAL5, 0 }, 180ab25eeb5Syz { IFT_SONETPATH, 0 }, 181ab25eeb5Syz { IFT_SONETVT, 0 }, 182ab25eeb5Syz { IFT_SMDSICIP, 0 }, 183ab25eeb5Syz { IFT_PROPVIRTUAL, 0 }, 184ab25eeb5Syz { IFT_PROPMUX, 0 }, 185ab25eeb5Syz }; 186ab25eeb5Syz #endif /* SOLARIS2 >= 6 */ 187ab25eeb5Syz 188f4b3ec61Sdh dev_info_t *ipf_dev_info = NULL; 189ab25eeb5Syz 190ab25eeb5Syz static const filter_kstats_t ipf_kstat_tmp = { 191ab25eeb5Syz { "pass", KSTAT_DATA_ULONG }, 192ab25eeb5Syz { "block", KSTAT_DATA_ULONG }, 193ab25eeb5Syz { "nomatch", KSTAT_DATA_ULONG }, 194ab25eeb5Syz { "short", KSTAT_DATA_ULONG }, 195ab25eeb5Syz { "pass, logged", KSTAT_DATA_ULONG }, 196ab25eeb5Syz { "block, logged", KSTAT_DATA_ULONG }, 197ab25eeb5Syz { "nomatch, logged", KSTAT_DATA_ULONG }, 198ab25eeb5Syz { "logged", KSTAT_DATA_ULONG }, 199ab25eeb5Syz { "skip", KSTAT_DATA_ULONG }, 200ab25eeb5Syz { "return sent", KSTAT_DATA_ULONG }, 201ab25eeb5Syz { "acct", KSTAT_DATA_ULONG }, 202ab25eeb5Syz { "bad frag state alloc", KSTAT_DATA_ULONG }, 203ab25eeb5Syz { "new frag state kept", KSTAT_DATA_ULONG }, 204ab25eeb5Syz { "new frag state compl. pkt", KSTAT_DATA_ULONG }, 205ab25eeb5Syz { "bad pkt state alloc", KSTAT_DATA_ULONG }, 206ab25eeb5Syz { "new pkt kept state", KSTAT_DATA_ULONG }, 207ab25eeb5Syz { "cachehit", KSTAT_DATA_ULONG }, 208ab25eeb5Syz { "tcp cksum bad", KSTAT_DATA_ULONG }, 209ab25eeb5Syz {{ "pullup ok", KSTAT_DATA_ULONG }, 210ab25eeb5Syz { "pullup nok", KSTAT_DATA_ULONG }}, 211ab25eeb5Syz { "src != route", KSTAT_DATA_ULONG }, 212ab25eeb5Syz { "ttl invalid", KSTAT_DATA_ULONG }, 213ab25eeb5Syz { "bad ip pkt", KSTAT_DATA_ULONG }, 214ab25eeb5Syz { "ipv6 pkt", KSTAT_DATA_ULONG }, 215ab25eeb5Syz { "dropped:pps ceiling", KSTAT_DATA_ULONG }, 216ab25eeb5Syz { "ip upd. fail", KSTAT_DATA_ULONG } 217ab25eeb5Syz }; 218ab25eeb5Syz 219381a2a9aSdr 220ab25eeb5Syz static int ipf_kstat_update(kstat_t *ksp, int rwflag); 221ab25eeb5Syz 222ab25eeb5Syz static void 2237ddc9b1aSDarren Reed ipf_kstat_init(ipf_stack_t *ifs) 224ab25eeb5Syz { 2257ddc9b1aSDarren Reed ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid, "ipf", 0, 2267ddc9b1aSDarren Reed "inbound", "net", KSTAT_TYPE_NAMED, 2277ddc9b1aSDarren Reed sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); 2287ddc9b1aSDarren Reed if (ifs->ifs_kstatp[0] != NULL) { 2297ddc9b1aSDarren Reed bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data, 2307ddc9b1aSDarren Reed sizeof (filter_kstats_t)); 2317ddc9b1aSDarren Reed ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update; 2327ddc9b1aSDarren Reed ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0]; 2337ddc9b1aSDarren Reed kstat_install(ifs->ifs_kstatp[0]); 2347ddc9b1aSDarren Reed } 235ab25eeb5Syz 2367ddc9b1aSDarren Reed ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid, "ipf", 0, 2377ddc9b1aSDarren Reed "outbound", "net", KSTAT_TYPE_NAMED, 2387ddc9b1aSDarren Reed sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); 2397ddc9b1aSDarren Reed if (ifs->ifs_kstatp[1] != NULL) { 2407ddc9b1aSDarren Reed bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data, 2417ddc9b1aSDarren Reed sizeof (filter_kstats_t)); 2427ddc9b1aSDarren Reed ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update; 2437ddc9b1aSDarren Reed ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1]; 2447ddc9b1aSDarren Reed kstat_install(ifs->ifs_kstatp[1]); 245ab25eeb5Syz } 246ab25eeb5Syz 247ab25eeb5Syz #ifdef IPFDEBUG 2487ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p", 249*19397407SSherry Moore ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]); 250ab25eeb5Syz #endif 251ab25eeb5Syz } 252ab25eeb5Syz 2537ddc9b1aSDarren Reed 254ab25eeb5Syz static void 2557ddc9b1aSDarren Reed ipf_kstat_fini(ipf_stack_t *ifs) 256ab25eeb5Syz { 257ab25eeb5Syz int i; 258f4b3ec61Sdh 259ab25eeb5Syz for (i = 0; i < 2; i++) { 260f4b3ec61Sdh if (ifs->ifs_kstatp[i] != NULL) { 2617ddc9b1aSDarren Reed net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]); 262f4b3ec61Sdh ifs->ifs_kstatp[i] = NULL; 263ab25eeb5Syz } 264ab25eeb5Syz } 265ab25eeb5Syz } 266ab25eeb5Syz 2677ddc9b1aSDarren Reed 268ab25eeb5Syz static int 269ab25eeb5Syz ipf_kstat_update(kstat_t *ksp, int rwflag) 270ab25eeb5Syz { 271ab25eeb5Syz filter_kstats_t *fkp; 272ab25eeb5Syz filterstats_t *fsp; 273ab25eeb5Syz 274f4b3ec61Sdh if (ksp == NULL || ksp->ks_data == NULL) 275f4b3ec61Sdh return (EIO); 276f4b3ec61Sdh 277ab25eeb5Syz if (rwflag == KSTAT_WRITE) 278ab25eeb5Syz return (EACCES); 279ab25eeb5Syz 280ab25eeb5Syz fkp = ksp->ks_data; 281ab25eeb5Syz fsp = ksp->ks_private; 282ab25eeb5Syz 283ab25eeb5Syz fkp->fks_pass.value.ul = fsp->fr_pass; 284ab25eeb5Syz fkp->fks_block.value.ul = fsp->fr_block; 285ab25eeb5Syz fkp->fks_nom.value.ul = fsp->fr_nom; 286ab25eeb5Syz fkp->fks_short.value.ul = fsp->fr_short; 287ab25eeb5Syz fkp->fks_ppkl.value.ul = fsp->fr_ppkl; 288ab25eeb5Syz fkp->fks_bpkl.value.ul = fsp->fr_bpkl; 289ab25eeb5Syz fkp->fks_npkl.value.ul = fsp->fr_npkl; 290ab25eeb5Syz fkp->fks_pkl.value.ul = fsp->fr_pkl; 291ab25eeb5Syz fkp->fks_skip.value.ul = fsp->fr_skip; 292ab25eeb5Syz fkp->fks_ret.value.ul = fsp->fr_ret; 293ab25eeb5Syz fkp->fks_acct.value.ul = fsp->fr_acct; 294ab25eeb5Syz fkp->fks_bnfr.value.ul = fsp->fr_bnfr; 295ab25eeb5Syz fkp->fks_nfr.value.ul = fsp->fr_nfr; 296ab25eeb5Syz fkp->fks_cfr.value.ul = fsp->fr_cfr; 297ab25eeb5Syz fkp->fks_bads.value.ul = fsp->fr_bads; 298ab25eeb5Syz fkp->fks_ads.value.ul = fsp->fr_ads; 299ab25eeb5Syz fkp->fks_chit.value.ul = fsp->fr_chit; 300ab25eeb5Syz fkp->fks_tcpbad.value.ul = fsp->fr_tcpbad; 301ab25eeb5Syz fkp->fks_pull[0].value.ul = fsp->fr_pull[0]; 302ab25eeb5Syz fkp->fks_pull[1].value.ul = fsp->fr_pull[1]; 303ab25eeb5Syz fkp->fks_badsrc.value.ul = fsp->fr_badsrc; 304ab25eeb5Syz fkp->fks_badttl.value.ul = fsp->fr_badttl; 305ab25eeb5Syz fkp->fks_bad.value.ul = fsp->fr_bad; 306ab25eeb5Syz fkp->fks_ipv6.value.ul = fsp->fr_ipv6; 307ab25eeb5Syz fkp->fks_ppshit.value.ul = fsp->fr_ppshit; 308ab25eeb5Syz fkp->fks_ipud.value.ul = fsp->fr_ipud; 309ab25eeb5Syz 310ab25eeb5Syz return (0); 311ab25eeb5Syz } 312ab25eeb5Syz 313*19397407SSherry Moore int 314*19397407SSherry Moore _init() 315ab25eeb5Syz { 316ab25eeb5Syz int ipfinst; 317ab25eeb5Syz 318ab25eeb5Syz ipfinst = mod_install(&modlink1); 319ab25eeb5Syz #ifdef IPFDEBUG 320ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst); 321ab25eeb5Syz #endif 3227ddc9b1aSDarren Reed mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL); 323*19397407SSherry Moore return (ipfinst); 324ab25eeb5Syz } 325ab25eeb5Syz 326ab25eeb5Syz 327*19397407SSherry Moore int 328*19397407SSherry Moore _fini(void) 329ab25eeb5Syz { 330ab25eeb5Syz int ipfinst; 331ab25eeb5Syz 332ab25eeb5Syz ipfinst = mod_remove(&modlink1); 333ab25eeb5Syz #ifdef IPFDEBUG 334ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst); 335ab25eeb5Syz #endif 336*19397407SSherry Moore return (ipfinst); 337ab25eeb5Syz } 338ab25eeb5Syz 339ab25eeb5Syz 340*19397407SSherry Moore int 341*19397407SSherry Moore _info(modinfop) 342ab25eeb5Syz struct modinfo *modinfop; 343ab25eeb5Syz { 344ab25eeb5Syz int ipfinst; 345ab25eeb5Syz 346ab25eeb5Syz ipfinst = mod_info(&modlink1, modinfop); 347ab25eeb5Syz #ifdef IPFDEBUG 3487ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst); 349ab25eeb5Syz #endif 350*19397407SSherry Moore return (ipfinst); 351ab25eeb5Syz } 352ab25eeb5Syz 353ab25eeb5Syz 354ab25eeb5Syz #if SOLARIS2 < 10 355ab25eeb5Syz static int ipf_identify(dip) 356ab25eeb5Syz dev_info_t *dip; 357ab25eeb5Syz { 358*19397407SSherry Moore #ifdef IPFDEBUG 3597ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip); 360*19397407SSherry Moore #endif 361ab25eeb5Syz if (strcmp(ddi_get_name(dip), "ipf") == 0) 362ab25eeb5Syz return (DDI_IDENTIFIED); 363ab25eeb5Syz return (DDI_NOT_IDENTIFIED); 364ab25eeb5Syz } 365ab25eeb5Syz #endif 366ab25eeb5Syz 367f4b3ec61Sdh /* 368f4b3ec61Sdh * Initialize things for IPF for each stack instance 369f4b3ec61Sdh */ 370f4b3ec61Sdh static void * 3717ddc9b1aSDarren Reed ipf_stack_create(const netid_t id) 372f4b3ec61Sdh { 373f4b3ec61Sdh ipf_stack_t *ifs; 374f4b3ec61Sdh 3757ddc9b1aSDarren Reed #ifdef IPFDEBUG 3767ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id); 377f4b3ec61Sdh #endif 378f4b3ec61Sdh 3797ddc9b1aSDarren Reed ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP); 380f4b3ec61Sdh bzero(ifs, sizeof (*ifs)); 381f4b3ec61Sdh 382f4b3ec61Sdh ifs->ifs_hook4_physical_in = B_FALSE; 383f4b3ec61Sdh ifs->ifs_hook4_physical_out = B_FALSE; 384f4b3ec61Sdh ifs->ifs_hook4_nic_events = B_FALSE; 385f4b3ec61Sdh ifs->ifs_hook4_loopback_in = B_FALSE; 386f4b3ec61Sdh ifs->ifs_hook4_loopback_out = B_FALSE; 387f4b3ec61Sdh ifs->ifs_hook6_physical_in = B_FALSE; 388f4b3ec61Sdh ifs->ifs_hook6_physical_out = B_FALSE; 389f4b3ec61Sdh ifs->ifs_hook6_nic_events = B_FALSE; 390f4b3ec61Sdh ifs->ifs_hook6_loopback_in = B_FALSE; 391f4b3ec61Sdh ifs->ifs_hook6_loopback_out = B_FALSE; 392f4b3ec61Sdh 393f4b3ec61Sdh /* 394f4b3ec61Sdh * Initialize mutex's 395f4b3ec61Sdh */ 396f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); 397f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); 3987ddc9b1aSDarren Reed 3997ddc9b1aSDarren Reed ifs->ifs_netid = id; 4007ddc9b1aSDarren Reed ifs->ifs_zone = net_getzoneidbynetid(id); 4017ddc9b1aSDarren Reed ipf_kstat_init(ifs); 4027ddc9b1aSDarren Reed 4037ddc9b1aSDarren Reed #ifdef IPFDEBUG 4047ddc9b1aSDarren Reed cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone); 405f4b3ec61Sdh #endif 406f4b3ec61Sdh 407f4b3ec61Sdh /* 408f4b3ec61Sdh * Lock people out while we set things up. 409f4b3ec61Sdh */ 410f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 411f4b3ec61Sdh ipftuneable_alloc(ifs); 412f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 413f4b3ec61Sdh 41423f4867fSnordmark /* Limit to global stack */ 4157ddc9b1aSDarren Reed if (ifs->ifs_zone == GLOBAL_ZONEID) 41623f4867fSnordmark cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version); 41723f4867fSnordmark 4187ddc9b1aSDarren Reed mutex_enter(&ipf_stack_lock); 4197ddc9b1aSDarren Reed if (ipf_stacks != NULL) 4207ddc9b1aSDarren Reed ipf_stacks->ifs_pnext = &ifs->ifs_next; 4217ddc9b1aSDarren Reed ifs->ifs_next = ipf_stacks; 4227ddc9b1aSDarren Reed ifs->ifs_pnext = &ipf_stacks; 4237ddc9b1aSDarren Reed ipf_stacks = ifs; 4247ddc9b1aSDarren Reed mutex_exit(&ipf_stack_lock); 4257ddc9b1aSDarren Reed 426f4b3ec61Sdh return (ifs); 427f4b3ec61Sdh } 428f4b3ec61Sdh 4297ddc9b1aSDarren Reed 4307ddc9b1aSDarren Reed /* 4317ddc9b1aSDarren Reed * This function should only ever be used to find the pointer to the 4327ddc9b1aSDarren Reed * ipfilter stack structure for the zone that is currently being 4337ddc9b1aSDarren Reed * executed... so if you're running in the context of zone 1, you 4347ddc9b1aSDarren Reed * should not attempt to find the ipf_stack_t for zone 0 or 2 or 4357ddc9b1aSDarren Reed * anything else but 1. In that way, the returned pointer is safe 4367ddc9b1aSDarren Reed * as it will only be nuked when the instance is destroyed as part 4377ddc9b1aSDarren Reed * of the final shutdown of a zone. 4387ddc9b1aSDarren Reed */ 439*19397407SSherry Moore ipf_stack_t * 440*19397407SSherry Moore ipf_find_stack(const zoneid_t zone) 4417ddc9b1aSDarren Reed { 4427ddc9b1aSDarren Reed ipf_stack_t *ifs; 4437ddc9b1aSDarren Reed 4447ddc9b1aSDarren Reed mutex_enter(&ipf_stack_lock); 4457ddc9b1aSDarren Reed for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) { 4467ddc9b1aSDarren Reed if (ifs->ifs_zone == zone) 4477ddc9b1aSDarren Reed break; 4487ddc9b1aSDarren Reed } 4497ddc9b1aSDarren Reed mutex_exit(&ipf_stack_lock); 450*19397407SSherry Moore return (ifs); 4517ddc9b1aSDarren Reed } 4527ddc9b1aSDarren Reed 4537ddc9b1aSDarren Reed 454f4b3ec61Sdh static int ipf_detach_check_zone(ipf_stack_t *ifs) 455f4b3ec61Sdh { 456f4b3ec61Sdh /* 457f4b3ec61Sdh * Make sure we're the only one's modifying things. With 458f4b3ec61Sdh * this lock others should just fall out of the loop. 459f4b3ec61Sdh */ 460f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 461f4b3ec61Sdh if (ifs->ifs_fr_running == 1) { 462f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 463f4b3ec61Sdh return (-1); 464f4b3ec61Sdh } 465*19397407SSherry Moore 466f4b3ec61Sdh /* 467f4b3ec61Sdh * Make sure there is no active filter rule. 468f4b3ec61Sdh */ 469f4b3ec61Sdh if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] || 470f4b3ec61Sdh ifs->ifs_ipfilter[1][ifs->ifs_fr_active] || 471f4b3ec61Sdh ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] || 472f4b3ec61Sdh ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) { 473f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 474f4b3ec61Sdh return (-1); 475f4b3ec61Sdh } 476f4b3ec61Sdh 477f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 478f4b3ec61Sdh 479f4b3ec61Sdh return (0); 480f4b3ec61Sdh } 481f4b3ec61Sdh 4827ddc9b1aSDarren Reed 483f4b3ec61Sdh static int ipf_detach_check_all() 484f4b3ec61Sdh { 4857ddc9b1aSDarren Reed ipf_stack_t *ifs; 4867ddc9b1aSDarren Reed 4877ddc9b1aSDarren Reed mutex_enter(&ipf_stack_lock); 4887ddc9b1aSDarren Reed for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) 4897ddc9b1aSDarren Reed if (ipf_detach_check_zone(ifs) != 0) 4907ddc9b1aSDarren Reed break; 4917ddc9b1aSDarren Reed mutex_exit(&ipf_stack_lock); 4927ddc9b1aSDarren Reed return ((ifs == NULL) ? 0 : -1); 493f4b3ec61Sdh } 494f4b3ec61Sdh 4957ddc9b1aSDarren Reed 496f4b3ec61Sdh /* 497f4b3ec61Sdh * Destroy things for ipf for one stack. 498f4b3ec61Sdh */ 499f4b3ec61Sdh /* ARGSUSED */ 500f4b3ec61Sdh static void 5017ddc9b1aSDarren Reed ipf_stack_destroy(const netid_t id, void *arg) 502f4b3ec61Sdh { 503f4b3ec61Sdh ipf_stack_t *ifs = (ipf_stack_t *)arg; 5047ddc9b1aSDarren Reed timeout_id_t tid; 505f4b3ec61Sdh 5067ddc9b1aSDarren Reed #ifdef IPFDEBUG 5077ddc9b1aSDarren Reed (void) printf("ipf_stack_destroy(%p)\n", (void *)ifs); 508f4b3ec61Sdh #endif 509f4b3ec61Sdh 510f4b3ec61Sdh /* 511f4b3ec61Sdh * Make sure we're the only one's modifying things. With 512f4b3ec61Sdh * this lock others should just fall out of the loop. 513f4b3ec61Sdh */ 514f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 515f4b3ec61Sdh if (ifs->ifs_fr_running == -2) { 516f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 517f4b3ec61Sdh return; 518f4b3ec61Sdh } 519f4b3ec61Sdh ifs->ifs_fr_running = -2; 5207ddc9b1aSDarren Reed tid = ifs->ifs_fr_timer_id; 5217ddc9b1aSDarren Reed ifs->ifs_fr_timer_id = NULL; 522f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 523f4b3ec61Sdh 5247ddc9b1aSDarren Reed mutex_enter(&ipf_stack_lock); 5257ddc9b1aSDarren Reed if (ifs->ifs_next != NULL) 5267ddc9b1aSDarren Reed ifs->ifs_next->ifs_pnext = ifs->ifs_pnext; 5277ddc9b1aSDarren Reed *ifs->ifs_pnext = ifs->ifs_next; 5287ddc9b1aSDarren Reed mutex_exit(&ipf_stack_lock); 5297ddc9b1aSDarren Reed 5307ddc9b1aSDarren Reed ipf_kstat_fini(ifs); 5317ddc9b1aSDarren Reed 5327ddc9b1aSDarren Reed if (tid != NULL) 5337ddc9b1aSDarren Reed (void) untimeout(tid); 534f4b3ec61Sdh 535f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 536f4b3ec61Sdh if (ipldetach(ifs) != 0) { 5377ddc9b1aSDarren Reed printf("ipf_stack_destroy: ipldetach failed\n"); 538f4b3ec61Sdh } 539f4b3ec61Sdh 540f4b3ec61Sdh ipftuneable_free(ifs); 541f4b3ec61Sdh 542f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 543f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_mutex); 544f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_global); 545f4b3ec61Sdh 546f4b3ec61Sdh KFREE(ifs); 547f4b3ec61Sdh } 548ab25eeb5Syz 5497ddc9b1aSDarren Reed 550ab25eeb5Syz static int ipf_attach(dip, cmd) 551ab25eeb5Syz dev_info_t *dip; 552ab25eeb5Syz ddi_attach_cmd_t cmd; 553ab25eeb5Syz { 554ab25eeb5Syz char *s; 555ab25eeb5Syz int i; 556ab25eeb5Syz int instance; 557ab25eeb5Syz 558ab25eeb5Syz #ifdef IPFDEBUG 5597ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd); 560ab25eeb5Syz #endif 561ab25eeb5Syz 562ab25eeb5Syz switch (cmd) 563ab25eeb5Syz { 564ab25eeb5Syz case DDI_ATTACH: 565ab25eeb5Syz instance = ddi_get_instance(dip); 566ab25eeb5Syz /* Only one instance of ipf (instance 0) can be attached. */ 567ab25eeb5Syz if (instance > 0) 568*19397407SSherry Moore return (DDI_FAILURE); 569ab25eeb5Syz 570ab25eeb5Syz #ifdef IPFDEBUG 5717ddc9b1aSDarren Reed cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance); 572ab25eeb5Syz #endif 573ab25eeb5Syz 574f4b3ec61Sdh (void) ipf_property_g_update(dip); 575ab25eeb5Syz 576ab25eeb5Syz for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) { 577ab25eeb5Syz s = strrchr(s, '/'); 578ab25eeb5Syz if (s == NULL) 579ab25eeb5Syz continue; 580ab25eeb5Syz s++; 581ab25eeb5Syz if (ddi_create_minor_node(dip, s, S_IFCHR, i, 582*19397407SSherry Moore DDI_PSEUDO, 0) == 583ab25eeb5Syz DDI_FAILURE) { 584ab25eeb5Syz ddi_remove_minor_node(dip, NULL); 585ab25eeb5Syz goto attach_failed; 586ab25eeb5Syz } 587ab25eeb5Syz } 588ab25eeb5Syz 589ab25eeb5Syz ipf_dev_info = dip; 5907ddc9b1aSDarren Reed 5917ddc9b1aSDarren Reed ipfncb = net_instance_alloc(NETINFO_VERSION); 5927ddc9b1aSDarren Reed ipfncb->nin_name = "ipf"; 5937ddc9b1aSDarren Reed ipfncb->nin_create = ipf_stack_create; 5947ddc9b1aSDarren Reed ipfncb->nin_destroy = ipf_stack_destroy; 5957ddc9b1aSDarren Reed ipfncb->nin_shutdown = NULL; 5967ddc9b1aSDarren Reed i = net_instance_register(ipfncb); 5977ddc9b1aSDarren Reed 5987ddc9b1aSDarren Reed #ifdef IPFDEBUG 5997ddc9b1aSDarren Reed cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i); 6007ddc9b1aSDarren Reed #endif 6017ddc9b1aSDarren Reed 602*19397407SSherry Moore return (DDI_SUCCESS); 603ab25eeb5Syz /* NOTREACHED */ 604ab25eeb5Syz default: 605ab25eeb5Syz break; 606ab25eeb5Syz } 607ab25eeb5Syz 608ab25eeb5Syz attach_failed: 609f4b3ec61Sdh ddi_prop_remove_all(dip); 610*19397407SSherry Moore return (DDI_FAILURE); 611ab25eeb5Syz } 612ab25eeb5Syz 613ab25eeb5Syz 614ab25eeb5Syz static int ipf_detach(dip, cmd) 615ab25eeb5Syz dev_info_t *dip; 616ab25eeb5Syz ddi_detach_cmd_t cmd; 617ab25eeb5Syz { 618ab25eeb5Syz int i; 619ab25eeb5Syz 620ab25eeb5Syz #ifdef IPFDEBUG 6217ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd); 622ab25eeb5Syz #endif 623ab25eeb5Syz switch (cmd) { 624ab25eeb5Syz case DDI_DETACH: 625f4b3ec61Sdh if (ipf_detach_check_all() != 0) 626*19397407SSherry Moore return (DDI_FAILURE); 627ab25eeb5Syz 628*19397407SSherry Moore /* 629*19397407SSherry Moore * Undo what we did in ipf_attach, freeing resources 630ab25eeb5Syz * and removing things we installed. The system 631ab25eeb5Syz * framework guarantees we are not active with this devinfo 632ab25eeb5Syz * node in any other entry points at this time. 633ab25eeb5Syz */ 634ab25eeb5Syz ddi_prop_remove_all(dip); 635ab25eeb5Syz i = ddi_get_instance(dip); 636ab25eeb5Syz ddi_remove_minor_node(dip, NULL); 637ab25eeb5Syz if (i > 0) { 638ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i); 639*19397407SSherry Moore return (DDI_FAILURE); 640ab25eeb5Syz } 641ab25eeb5Syz 6427ddc9b1aSDarren Reed (void) net_instance_unregister(ipfncb); 6437ddc9b1aSDarren Reed net_instance_free(ipfncb); 6447ddc9b1aSDarren Reed 645*19397407SSherry Moore return (DDI_SUCCESS); 646f4b3ec61Sdh /* NOTREACHED */ 647ab25eeb5Syz default: 648ab25eeb5Syz break; 649ab25eeb5Syz } 650ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: failed to detach\n"); 651*19397407SSherry Moore return (DDI_FAILURE); 652ab25eeb5Syz } 653ab25eeb5Syz 654ab25eeb5Syz 655ab25eeb5Syz /*ARGSUSED*/ 656ab25eeb5Syz static int ipf_getinfo(dip, infocmd, arg, result) 657ab25eeb5Syz dev_info_t *dip; 658ab25eeb5Syz ddi_info_cmd_t infocmd; 659ab25eeb5Syz void *arg, **result; 660ab25eeb5Syz { 661ab25eeb5Syz int error; 662ab25eeb5Syz 663ab25eeb5Syz error = DDI_FAILURE; 664ab25eeb5Syz #ifdef IPFDEBUG 6657ddc9b1aSDarren Reed cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg); 666ab25eeb5Syz #endif 667ab25eeb5Syz switch (infocmd) { 668ab25eeb5Syz case DDI_INFO_DEVT2DEVINFO: 669ab25eeb5Syz *result = ipf_dev_info; 670ab25eeb5Syz error = DDI_SUCCESS; 671ab25eeb5Syz break; 672ab25eeb5Syz case DDI_INFO_DEVT2INSTANCE: 673ab25eeb5Syz *result = (void *)0; 674ab25eeb5Syz error = DDI_SUCCESS; 675ab25eeb5Syz break; 676ab25eeb5Syz default: 677ab25eeb5Syz break; 678ab25eeb5Syz } 679ab25eeb5Syz return (error); 680ab25eeb5Syz } 681ab25eeb5Syz 682ab25eeb5Syz 683ab25eeb5Syz /* 684ab25eeb5Syz * Fetch configuration file values that have been entered into the ipf.conf 685ab25eeb5Syz * driver file. 686ab25eeb5Syz */ 687f4b3ec61Sdh static int ipf_property_g_update(dip) 688ab25eeb5Syz dev_info_t *dip; 689ab25eeb5Syz { 690ab25eeb5Syz #ifdef DDI_NO_AUTODETACH 691ab25eeb5Syz if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 692ab25eeb5Syz DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) { 693ab25eeb5Syz cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed"); 694*19397407SSherry Moore return (DDI_FAILURE); 695ab25eeb5Syz } 696ab25eeb5Syz #else 697ab25eeb5Syz if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 698ab25eeb5Syz "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) { 699ab25eeb5Syz cmn_err(CE_WARN, "!updating ddi-no-autodetach failed"); 700*19397407SSherry Moore return (DDI_FAILURE); 701ab25eeb5Syz } 702ab25eeb5Syz #endif 703ab25eeb5Syz 704*19397407SSherry Moore return (DDI_SUCCESS); 705f4b3ec61Sdh } 706f4b3ec61Sdh 707*19397407SSherry Moore int 708*19397407SSherry Moore ipf_property_update(dip, ifs) 709f4b3ec61Sdh dev_info_t *dip; 710f4b3ec61Sdh ipf_stack_t *ifs; 711f4b3ec61Sdh { 712f4b3ec61Sdh ipftuneable_t *ipft; 713f4b3ec61Sdh int64_t *i64p; 714f4b3ec61Sdh char *name; 715*19397407SSherry Moore uint_t one; 716f4b3ec61Sdh int *i32p; 717f4b3ec61Sdh int err; 718f4b3ec61Sdh 719*19397407SSherry Moore for (ipft = ifs->ifs_ipf_tuneables; (name = ipft->ipft_name) != NULL; 720*19397407SSherry Moore ipft++) { 721ab25eeb5Syz one = 1; 722ab25eeb5Syz switch (ipft->ipft_sz) 723ab25eeb5Syz { 724ab25eeb5Syz case 4 : 725ab25eeb5Syz i32p = NULL; 726ab25eeb5Syz err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 727ab25eeb5Syz 0, name, &i32p, &one); 728ab25eeb5Syz if (err == DDI_PROP_NOT_FOUND) 729ab25eeb5Syz continue; 730ab25eeb5Syz #ifdef IPFDEBUG 731ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n", 732ab25eeb5Syz name, err); 733ab25eeb5Syz #endif 734ab25eeb5Syz if (err != DDI_PROP_SUCCESS) 735*19397407SSherry Moore return (err); 736ab25eeb5Syz if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max) 737ab25eeb5Syz *ipft->ipft_pint = *i32p; 738ab25eeb5Syz else 739ab25eeb5Syz err = DDI_PROP_CANNOT_DECODE; 740ab25eeb5Syz ddi_prop_free(i32p); 741ab25eeb5Syz break; 742ab25eeb5Syz 743ab25eeb5Syz #if SOLARIS2 > 8 744ab25eeb5Syz case 8 : 745ab25eeb5Syz i64p = NULL; 746ab25eeb5Syz err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip, 747*19397407SSherry Moore 0, name, &i64p, &one); 748ab25eeb5Syz if (err == DDI_PROP_NOT_FOUND) 749ab25eeb5Syz continue; 750*19397407SSherry Moore #ifdef IPFDEBUG 751ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n", 752*19397407SSherry Moore name, err); 753*19397407SSherry Moore #endif 754ab25eeb5Syz if (err != DDI_PROP_SUCCESS) 755*19397407SSherry Moore return (err); 756ab25eeb5Syz if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max) 757ab25eeb5Syz *ipft->ipft_pint = *i64p; 758ab25eeb5Syz else 759ab25eeb5Syz err = DDI_PROP_CANNOT_DECODE; 760ab25eeb5Syz ddi_prop_free(i64p); 761ab25eeb5Syz break; 762ab25eeb5Syz #endif 763ab25eeb5Syz default : 764ab25eeb5Syz break; 765ab25eeb5Syz } 766ab25eeb5Syz if (err != DDI_SUCCESS) 767ab25eeb5Syz break; 768ab25eeb5Syz } 769*19397407SSherry Moore return (err); 770ab25eeb5Syz } 771