12393Syz155240 /* 22393Syz155240 * Copyright (C) 1993-2001, 2003 by Darren Reed. 32393Syz155240 * 42393Syz155240 * See the IPFILTER.LICENCE file for details on licencing. 52393Syz155240 * 67513SDarren.Reed@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 72393Syz155240 * Use is subject to license terms. 82393Syz155240 */ 92393Syz155240 102393Syz155240 #include <sys/systm.h> 112393Syz155240 #include <sys/types.h> 122393Syz155240 #include <sys/param.h> 132393Syz155240 #include <sys/errno.h> 142393Syz155240 #include <sys/uio.h> 152393Syz155240 #include <sys/buf.h> 162393Syz155240 #include <sys/modctl.h> 172393Syz155240 #include <sys/open.h> 182393Syz155240 #include <sys/kmem.h> 192393Syz155240 #include <sys/conf.h> 202393Syz155240 #include <sys/cmn_err.h> 212393Syz155240 #include <sys/stat.h> 222393Syz155240 #include <sys/cred.h> 232393Syz155240 #include <sys/dditypes.h> 242393Syz155240 #include <sys/poll.h> 252393Syz155240 #include <sys/autoconf.h> 262393Syz155240 #include <sys/byteorder.h> 272393Syz155240 #include <sys/socket.h> 282393Syz155240 #include <sys/dlpi.h> 292393Syz155240 #include <sys/stropts.h> 302393Syz155240 #include <sys/kstat.h> 312393Syz155240 #include <sys/sockio.h> 322958Sdr146992 #include <sys/neti.h> 332958Sdr146992 #include <sys/hook.h> 342393Syz155240 #include <net/if.h> 352393Syz155240 #if SOLARIS2 >= 6 36*7656SSherry.Moore@Sun.COM #include <net/if_types.h> 372393Syz155240 #endif 382393Syz155240 #include <net/af.h> 392393Syz155240 #include <net/route.h> 402393Syz155240 #include <netinet/in.h> 412393Syz155240 #include <netinet/in_systm.h> 422393Syz155240 #include <netinet/if_ether.h> 432393Syz155240 #include <netinet/ip.h> 442393Syz155240 #include <netinet/ip_var.h> 452393Syz155240 #include <netinet/tcp.h> 462393Syz155240 #include <netinet/udp.h> 472393Syz155240 #include <netinet/tcpip.h> 482393Syz155240 #include <netinet/ip_icmp.h> 492393Syz155240 #include <sys/ddi.h> 502393Syz155240 #include <sys/sunddi.h> 512393Syz155240 #include "netinet/ip_compat.h" 522393Syz155240 #include "netinet/ipl.h" 532393Syz155240 #include "netinet/ip_fil.h" 542393Syz155240 #include "netinet/ip_nat.h" 552393Syz155240 #include "netinet/ip_frag.h" 562393Syz155240 #include "netinet/ip_auth.h" 572393Syz155240 #include "netinet/ip_state.h" 583448Sdh155122 #include "netinet/ipf_stack.h" 592393Syz155240 602393Syz155240 extern int iplwrite __P((dev_t, struct uio *, cred_t *)); 612393Syz155240 622393Syz155240 static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t, 63*7656SSherry.Moore@Sun.COM void *, void **)); 642393Syz155240 #if SOLARIS2 < 10 652393Syz155240 static int ipf_identify __P((dev_info_t *)); 662393Syz155240 #endif 672393Syz155240 static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t)); 682393Syz155240 static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t)); 697513SDarren.Reed@Sun.COM static void *ipf_stack_create __P((const netid_t)); 707513SDarren.Reed@Sun.COM static void ipf_stack_destroy __P((const netid_t, void *)); 713448Sdh155122 static int ipf_property_g_update __P((dev_info_t *)); 722393Syz155240 static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 732393Syz155240 IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 742393Syz155240 IPLOOKUP_NAME, NULL }; 752393Syz155240 762393Syz155240 772393Syz155240 static struct cb_ops ipf_cb_ops = { 782393Syz155240 iplopen, 792393Syz155240 iplclose, 802393Syz155240 nodev, /* strategy */ 812393Syz155240 nodev, /* print */ 822393Syz155240 nodev, /* dump */ 832393Syz155240 iplread, 842393Syz155240 iplwrite, /* write */ 852393Syz155240 iplioctl, /* ioctl */ 862393Syz155240 nodev, /* devmap */ 872393Syz155240 nodev, /* mmap */ 882393Syz155240 nodev, /* segmap */ 892393Syz155240 nochpoll, /* poll */ 902393Syz155240 ddi_prop_op, 912393Syz155240 NULL, 922393Syz155240 D_MTSAFE, 932393Syz155240 #if SOLARIS2 > 4 942393Syz155240 CB_REV, 952393Syz155240 nodev, /* aread */ 962393Syz155240 nodev, /* awrite */ 972393Syz155240 #endif 982393Syz155240 }; 992393Syz155240 1002393Syz155240 static struct dev_ops ipf_ops = { 1012393Syz155240 DEVO_REV, 1022393Syz155240 0, 1032393Syz155240 ipf_getinfo, 1042393Syz155240 #if SOLARIS2 >= 10 1052393Syz155240 nulldev, 1062393Syz155240 #else 1072393Syz155240 ipf_identify, 1082393Syz155240 #endif 1092393Syz155240 nulldev, 1102393Syz155240 ipf_attach, 1112393Syz155240 ipf_detach, 1122393Syz155240 nodev, /* reset */ 1132393Syz155240 &ipf_cb_ops, 114*7656SSherry.Moore@Sun.COM (struct bus_ops *)0, 115*7656SSherry.Moore@Sun.COM NULL, 116*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1172393Syz155240 }; 1182393Syz155240 1197513SDarren.Reed@Sun.COM 1207513SDarren.Reed@Sun.COM static net_instance_t *ipfncb = NULL; 1217513SDarren.Reed@Sun.COM static ipf_stack_t *ipf_stacks = NULL; 1227513SDarren.Reed@Sun.COM static kmutex_t ipf_stack_lock; 1232393Syz155240 extern struct mod_ops mod_driverops; 1242393Syz155240 static struct modldrv iplmod = { 1252393Syz155240 &mod_driverops, IPL_VERSION, &ipf_ops }; 1262393Syz155240 static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL }; 1272393Syz155240 1282393Syz155240 #if SOLARIS2 >= 6 1292393Syz155240 static size_t hdrsizes[57][2] = { 1302393Syz155240 { 0, 0 }, 1312393Syz155240 { IFT_OTHER, 0 }, 1322393Syz155240 { IFT_1822, 0 }, 1332393Syz155240 { IFT_HDH1822, 0 }, 1342393Syz155240 { IFT_X25DDN, 0 }, 1352393Syz155240 { IFT_X25, 0 }, 1362393Syz155240 { IFT_ETHER, 14 }, 1372393Syz155240 { IFT_ISO88023, 0 }, 1382393Syz155240 { IFT_ISO88024, 0 }, 1392393Syz155240 { IFT_ISO88025, 0 }, 1402393Syz155240 { IFT_ISO88026, 0 }, 1412393Syz155240 { IFT_STARLAN, 0 }, 1422393Syz155240 { IFT_P10, 0 }, 1432393Syz155240 { IFT_P80, 0 }, 1442393Syz155240 { IFT_HY, 0 }, 1452393Syz155240 { IFT_FDDI, 24 }, 1462393Syz155240 { IFT_LAPB, 0 }, 1472393Syz155240 { IFT_SDLC, 0 }, 1482393Syz155240 { IFT_T1, 0 }, 1492393Syz155240 { IFT_CEPT, 0 }, 1502393Syz155240 { IFT_ISDNBASIC, 0 }, 1512393Syz155240 { IFT_ISDNPRIMARY, 0 }, 1522393Syz155240 { IFT_PTPSERIAL, 0 }, 1532393Syz155240 { IFT_PPP, 0 }, 1542393Syz155240 { IFT_LOOP, 0 }, 1552393Syz155240 { IFT_EON, 0 }, 1562393Syz155240 { IFT_XETHER, 0 }, 1572393Syz155240 { IFT_NSIP, 0 }, 1582393Syz155240 { IFT_SLIP, 0 }, 1592393Syz155240 { IFT_ULTRA, 0 }, 1602393Syz155240 { IFT_DS3, 0 }, 1612393Syz155240 { IFT_SIP, 0 }, 1622393Syz155240 { IFT_FRELAY, 0 }, 1632393Syz155240 { IFT_RS232, 0 }, 1642393Syz155240 { IFT_PARA, 0 }, 1652393Syz155240 { IFT_ARCNET, 0 }, 1662393Syz155240 { IFT_ARCNETPLUS, 0 }, 1672393Syz155240 { IFT_ATM, 0 }, 1682393Syz155240 { IFT_MIOX25, 0 }, 1692393Syz155240 { IFT_SONET, 0 }, 1702393Syz155240 { IFT_X25PLE, 0 }, 1712393Syz155240 { IFT_ISO88022LLC, 0 }, 1722393Syz155240 { IFT_LOCALTALK, 0 }, 1732393Syz155240 { IFT_SMDSDXI, 0 }, 1742393Syz155240 { IFT_FRELAYDCE, 0 }, 1752393Syz155240 { IFT_V35, 0 }, 1762393Syz155240 { IFT_HSSI, 0 }, 1772393Syz155240 { IFT_HIPPI, 0 }, 1782393Syz155240 { IFT_MODEM, 0 }, 1792393Syz155240 { IFT_AAL5, 0 }, 1802393Syz155240 { IFT_SONETPATH, 0 }, 1812393Syz155240 { IFT_SONETVT, 0 }, 1822393Syz155240 { IFT_SMDSICIP, 0 }, 1832393Syz155240 { IFT_PROPVIRTUAL, 0 }, 1842393Syz155240 { IFT_PROPMUX, 0 }, 1852393Syz155240 }; 1862393Syz155240 #endif /* SOLARIS2 >= 6 */ 1872393Syz155240 1883448Sdh155122 dev_info_t *ipf_dev_info = NULL; 1892393Syz155240 1902393Syz155240 static const filter_kstats_t ipf_kstat_tmp = { 1912393Syz155240 { "pass", KSTAT_DATA_ULONG }, 1922393Syz155240 { "block", KSTAT_DATA_ULONG }, 1932393Syz155240 { "nomatch", KSTAT_DATA_ULONG }, 1942393Syz155240 { "short", KSTAT_DATA_ULONG }, 1952393Syz155240 { "pass, logged", KSTAT_DATA_ULONG }, 1962393Syz155240 { "block, logged", KSTAT_DATA_ULONG }, 1972393Syz155240 { "nomatch, logged", KSTAT_DATA_ULONG }, 1982393Syz155240 { "logged", KSTAT_DATA_ULONG }, 1992393Syz155240 { "skip", KSTAT_DATA_ULONG }, 2002393Syz155240 { "return sent", KSTAT_DATA_ULONG }, 2012393Syz155240 { "acct", KSTAT_DATA_ULONG }, 2022393Syz155240 { "bad frag state alloc", KSTAT_DATA_ULONG }, 2032393Syz155240 { "new frag state kept", KSTAT_DATA_ULONG }, 2042393Syz155240 { "new frag state compl. pkt", KSTAT_DATA_ULONG }, 2052393Syz155240 { "bad pkt state alloc", KSTAT_DATA_ULONG }, 2062393Syz155240 { "new pkt kept state", KSTAT_DATA_ULONG }, 2072393Syz155240 { "cachehit", KSTAT_DATA_ULONG }, 2082393Syz155240 { "tcp cksum bad", KSTAT_DATA_ULONG }, 2092393Syz155240 {{ "pullup ok", KSTAT_DATA_ULONG }, 2102393Syz155240 { "pullup nok", KSTAT_DATA_ULONG }}, 2112393Syz155240 { "src != route", KSTAT_DATA_ULONG }, 2122393Syz155240 { "ttl invalid", KSTAT_DATA_ULONG }, 2132393Syz155240 { "bad ip pkt", KSTAT_DATA_ULONG }, 2142393Syz155240 { "ipv6 pkt", KSTAT_DATA_ULONG }, 2152393Syz155240 { "dropped:pps ceiling", KSTAT_DATA_ULONG }, 2162393Syz155240 { "ip upd. fail", KSTAT_DATA_ULONG } 2172393Syz155240 }; 2182393Syz155240 2192958Sdr146992 2202393Syz155240 static int ipf_kstat_update(kstat_t *ksp, int rwflag); 2212393Syz155240 2222393Syz155240 static void 2237513SDarren.Reed@Sun.COM ipf_kstat_init(ipf_stack_t *ifs) 2242393Syz155240 { 2257513SDarren.Reed@Sun.COM ifs->ifs_kstatp[0] = net_kstat_create(ifs->ifs_netid, "ipf", 0, 2267513SDarren.Reed@Sun.COM "inbound", "net", KSTAT_TYPE_NAMED, 2277513SDarren.Reed@Sun.COM sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); 2287513SDarren.Reed@Sun.COM if (ifs->ifs_kstatp[0] != NULL) { 2297513SDarren.Reed@Sun.COM bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[0]->ks_data, 2307513SDarren.Reed@Sun.COM sizeof (filter_kstats_t)); 2317513SDarren.Reed@Sun.COM ifs->ifs_kstatp[0]->ks_update = ipf_kstat_update; 2327513SDarren.Reed@Sun.COM ifs->ifs_kstatp[0]->ks_private = &ifs->ifs_frstats[0]; 2337513SDarren.Reed@Sun.COM kstat_install(ifs->ifs_kstatp[0]); 2347513SDarren.Reed@Sun.COM } 2352393Syz155240 2367513SDarren.Reed@Sun.COM ifs->ifs_kstatp[1] = net_kstat_create(ifs->ifs_netid, "ipf", 0, 2377513SDarren.Reed@Sun.COM "outbound", "net", KSTAT_TYPE_NAMED, 2387513SDarren.Reed@Sun.COM sizeof (filter_kstats_t) / sizeof (kstat_named_t), 0); 2397513SDarren.Reed@Sun.COM if (ifs->ifs_kstatp[1] != NULL) { 2407513SDarren.Reed@Sun.COM bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[1]->ks_data, 2417513SDarren.Reed@Sun.COM sizeof (filter_kstats_t)); 2427513SDarren.Reed@Sun.COM ifs->ifs_kstatp[1]->ks_update = ipf_kstat_update; 2437513SDarren.Reed@Sun.COM ifs->ifs_kstatp[1]->ks_private = &ifs->ifs_frstats[1]; 2447513SDarren.Reed@Sun.COM kstat_install(ifs->ifs_kstatp[1]); 2452393Syz155240 } 2462393Syz155240 2472393Syz155240 #ifdef IPFDEBUG 2487513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init(%p) installed %p, %p", 249*7656SSherry.Moore@Sun.COM ifs, ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]); 2502393Syz155240 #endif 2512393Syz155240 } 2522393Syz155240 2537513SDarren.Reed@Sun.COM 2542393Syz155240 static void 2557513SDarren.Reed@Sun.COM ipf_kstat_fini(ipf_stack_t *ifs) 2562393Syz155240 { 2572393Syz155240 int i; 2583448Sdh155122 2592393Syz155240 for (i = 0; i < 2; i++) { 2603448Sdh155122 if (ifs->ifs_kstatp[i] != NULL) { 2617513SDarren.Reed@Sun.COM net_kstat_delete(ifs->ifs_netid, ifs->ifs_kstatp[i]); 2623448Sdh155122 ifs->ifs_kstatp[i] = NULL; 2632393Syz155240 } 2642393Syz155240 } 2652393Syz155240 } 2662393Syz155240 2677513SDarren.Reed@Sun.COM 2682393Syz155240 static int 2692393Syz155240 ipf_kstat_update(kstat_t *ksp, int rwflag) 2702393Syz155240 { 2712393Syz155240 filter_kstats_t *fkp; 2722393Syz155240 filterstats_t *fsp; 2732393Syz155240 2743448Sdh155122 if (ksp == NULL || ksp->ks_data == NULL) 2753448Sdh155122 return (EIO); 2763448Sdh155122 2772393Syz155240 if (rwflag == KSTAT_WRITE) 2782393Syz155240 return (EACCES); 2792393Syz155240 2802393Syz155240 fkp = ksp->ks_data; 2812393Syz155240 fsp = ksp->ks_private; 2822393Syz155240 2832393Syz155240 fkp->fks_pass.value.ul = fsp->fr_pass; 2842393Syz155240 fkp->fks_block.value.ul = fsp->fr_block; 2852393Syz155240 fkp->fks_nom.value.ul = fsp->fr_nom; 2862393Syz155240 fkp->fks_short.value.ul = fsp->fr_short; 2872393Syz155240 fkp->fks_ppkl.value.ul = fsp->fr_ppkl; 2882393Syz155240 fkp->fks_bpkl.value.ul = fsp->fr_bpkl; 2892393Syz155240 fkp->fks_npkl.value.ul = fsp->fr_npkl; 2902393Syz155240 fkp->fks_pkl.value.ul = fsp->fr_pkl; 2912393Syz155240 fkp->fks_skip.value.ul = fsp->fr_skip; 2922393Syz155240 fkp->fks_ret.value.ul = fsp->fr_ret; 2932393Syz155240 fkp->fks_acct.value.ul = fsp->fr_acct; 2942393Syz155240 fkp->fks_bnfr.value.ul = fsp->fr_bnfr; 2952393Syz155240 fkp->fks_nfr.value.ul = fsp->fr_nfr; 2962393Syz155240 fkp->fks_cfr.value.ul = fsp->fr_cfr; 2972393Syz155240 fkp->fks_bads.value.ul = fsp->fr_bads; 2982393Syz155240 fkp->fks_ads.value.ul = fsp->fr_ads; 2992393Syz155240 fkp->fks_chit.value.ul = fsp->fr_chit; 3002393Syz155240 fkp->fks_tcpbad.value.ul = fsp->fr_tcpbad; 3012393Syz155240 fkp->fks_pull[0].value.ul = fsp->fr_pull[0]; 3022393Syz155240 fkp->fks_pull[1].value.ul = fsp->fr_pull[1]; 3032393Syz155240 fkp->fks_badsrc.value.ul = fsp->fr_badsrc; 3042393Syz155240 fkp->fks_badttl.value.ul = fsp->fr_badttl; 3052393Syz155240 fkp->fks_bad.value.ul = fsp->fr_bad; 3062393Syz155240 fkp->fks_ipv6.value.ul = fsp->fr_ipv6; 3072393Syz155240 fkp->fks_ppshit.value.ul = fsp->fr_ppshit; 3082393Syz155240 fkp->fks_ipud.value.ul = fsp->fr_ipud; 3092393Syz155240 3102393Syz155240 return (0); 3112393Syz155240 } 3122393Syz155240 313*7656SSherry.Moore@Sun.COM int 314*7656SSherry.Moore@Sun.COM _init() 3152393Syz155240 { 3162393Syz155240 int ipfinst; 3172393Syz155240 3182393Syz155240 ipfinst = mod_install(&modlink1); 3192393Syz155240 #ifdef IPFDEBUG 3202393Syz155240 cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst); 3212393Syz155240 #endif 3227513SDarren.Reed@Sun.COM mutex_init(&ipf_stack_lock, NULL, MUTEX_DRIVER, NULL); 323*7656SSherry.Moore@Sun.COM return (ipfinst); 3242393Syz155240 } 3252393Syz155240 3262393Syz155240 327*7656SSherry.Moore@Sun.COM int 328*7656SSherry.Moore@Sun.COM _fini(void) 3292393Syz155240 { 3302393Syz155240 int ipfinst; 3312393Syz155240 3322393Syz155240 ipfinst = mod_remove(&modlink1); 3332393Syz155240 #ifdef IPFDEBUG 3342393Syz155240 cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst); 3352393Syz155240 #endif 336*7656SSherry.Moore@Sun.COM return (ipfinst); 3372393Syz155240 } 3382393Syz155240 3392393Syz155240 340*7656SSherry.Moore@Sun.COM int 341*7656SSherry.Moore@Sun.COM _info(modinfop) 3422393Syz155240 struct modinfo *modinfop; 3432393Syz155240 { 3442393Syz155240 int ipfinst; 3452393Syz155240 3462393Syz155240 ipfinst = mod_info(&modlink1, modinfop); 3472393Syz155240 #ifdef IPFDEBUG 3487513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: _info(%p) = %d", modinfop, ipfinst); 3492393Syz155240 #endif 350*7656SSherry.Moore@Sun.COM return (ipfinst); 3512393Syz155240 } 3522393Syz155240 3532393Syz155240 3542393Syz155240 #if SOLARIS2 < 10 3552393Syz155240 static int ipf_identify(dip) 3562393Syz155240 dev_info_t *dip; 3572393Syz155240 { 358*7656SSherry.Moore@Sun.COM #ifdef IPFDEBUG 3597513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: ipf_identify(%p)", dip); 360*7656SSherry.Moore@Sun.COM #endif 3612393Syz155240 if (strcmp(ddi_get_name(dip), "ipf") == 0) 3622393Syz155240 return (DDI_IDENTIFIED); 3632393Syz155240 return (DDI_NOT_IDENTIFIED); 3642393Syz155240 } 3652393Syz155240 #endif 3662393Syz155240 3673448Sdh155122 /* 3683448Sdh155122 * Initialize things for IPF for each stack instance 3693448Sdh155122 */ 3703448Sdh155122 static void * 3717513SDarren.Reed@Sun.COM ipf_stack_create(const netid_t id) 3723448Sdh155122 { 3733448Sdh155122 ipf_stack_t *ifs; 3743448Sdh155122 3757513SDarren.Reed@Sun.COM #ifdef IPFDEBUG 3767513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter:stack_create id=%d", id); 3773448Sdh155122 #endif 3783448Sdh155122 3797513SDarren.Reed@Sun.COM ifs = (ipf_stack_t *)kmem_alloc(sizeof (*ifs), KM_SLEEP); 3803448Sdh155122 bzero(ifs, sizeof (*ifs)); 3813448Sdh155122 3823448Sdh155122 ifs->ifs_hook4_physical_in = B_FALSE; 3833448Sdh155122 ifs->ifs_hook4_physical_out = B_FALSE; 3843448Sdh155122 ifs->ifs_hook4_nic_events = B_FALSE; 3853448Sdh155122 ifs->ifs_hook4_loopback_in = B_FALSE; 3863448Sdh155122 ifs->ifs_hook4_loopback_out = B_FALSE; 3873448Sdh155122 ifs->ifs_hook6_physical_in = B_FALSE; 3883448Sdh155122 ifs->ifs_hook6_physical_out = B_FALSE; 3893448Sdh155122 ifs->ifs_hook6_nic_events = B_FALSE; 3903448Sdh155122 ifs->ifs_hook6_loopback_in = B_FALSE; 3913448Sdh155122 ifs->ifs_hook6_loopback_out = B_FALSE; 3923448Sdh155122 3933448Sdh155122 /* 3943448Sdh155122 * Initialize mutex's 3953448Sdh155122 */ 3963448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); 3973448Sdh155122 RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); 3987513SDarren.Reed@Sun.COM 3997513SDarren.Reed@Sun.COM ifs->ifs_netid = id; 4007513SDarren.Reed@Sun.COM ifs->ifs_zone = net_getzoneidbynetid(id); 4017513SDarren.Reed@Sun.COM ipf_kstat_init(ifs); 4027513SDarren.Reed@Sun.COM 4037513SDarren.Reed@Sun.COM #ifdef IPFDEBUG 4047513SDarren.Reed@Sun.COM cmn_err(CE_CONT, "IP Filter:stack_create zone=%d", ifs->ifs_zone); 4053448Sdh155122 #endif 4063448Sdh155122 4073448Sdh155122 /* 4083448Sdh155122 * Lock people out while we set things up. 4093448Sdh155122 */ 4103448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global); 4113448Sdh155122 ipftuneable_alloc(ifs); 4123448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 4133448Sdh155122 4144287Snordmark /* Limit to global stack */ 4157513SDarren.Reed@Sun.COM if (ifs->ifs_zone == GLOBAL_ZONEID) 4164287Snordmark cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version); 4174287Snordmark 4187513SDarren.Reed@Sun.COM mutex_enter(&ipf_stack_lock); 4197513SDarren.Reed@Sun.COM if (ipf_stacks != NULL) 4207513SDarren.Reed@Sun.COM ipf_stacks->ifs_pnext = &ifs->ifs_next; 4217513SDarren.Reed@Sun.COM ifs->ifs_next = ipf_stacks; 4227513SDarren.Reed@Sun.COM ifs->ifs_pnext = &ipf_stacks; 4237513SDarren.Reed@Sun.COM ipf_stacks = ifs; 4247513SDarren.Reed@Sun.COM mutex_exit(&ipf_stack_lock); 4257513SDarren.Reed@Sun.COM 4263448Sdh155122 return (ifs); 4273448Sdh155122 } 4283448Sdh155122 4297513SDarren.Reed@Sun.COM 4307513SDarren.Reed@Sun.COM /* 4317513SDarren.Reed@Sun.COM * This function should only ever be used to find the pointer to the 4327513SDarren.Reed@Sun.COM * ipfilter stack structure for the zone that is currently being 4337513SDarren.Reed@Sun.COM * executed... so if you're running in the context of zone 1, you 4347513SDarren.Reed@Sun.COM * should not attempt to find the ipf_stack_t for zone 0 or 2 or 4357513SDarren.Reed@Sun.COM * anything else but 1. In that way, the returned pointer is safe 4367513SDarren.Reed@Sun.COM * as it will only be nuked when the instance is destroyed as part 4377513SDarren.Reed@Sun.COM * of the final shutdown of a zone. 4387513SDarren.Reed@Sun.COM */ 439*7656SSherry.Moore@Sun.COM ipf_stack_t * 440*7656SSherry.Moore@Sun.COM ipf_find_stack(const zoneid_t zone) 4417513SDarren.Reed@Sun.COM { 4427513SDarren.Reed@Sun.COM ipf_stack_t *ifs; 4437513SDarren.Reed@Sun.COM 4447513SDarren.Reed@Sun.COM mutex_enter(&ipf_stack_lock); 4457513SDarren.Reed@Sun.COM for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) { 4467513SDarren.Reed@Sun.COM if (ifs->ifs_zone == zone) 4477513SDarren.Reed@Sun.COM break; 4487513SDarren.Reed@Sun.COM } 4497513SDarren.Reed@Sun.COM mutex_exit(&ipf_stack_lock); 450*7656SSherry.Moore@Sun.COM return (ifs); 4517513SDarren.Reed@Sun.COM } 4527513SDarren.Reed@Sun.COM 4537513SDarren.Reed@Sun.COM 4543448Sdh155122 static int ipf_detach_check_zone(ipf_stack_t *ifs) 4553448Sdh155122 { 4563448Sdh155122 /* 4573448Sdh155122 * Make sure we're the only one's modifying things. With 4583448Sdh155122 * this lock others should just fall out of the loop. 4593448Sdh155122 */ 4603448Sdh155122 READ_ENTER(&ifs->ifs_ipf_global); 4613448Sdh155122 if (ifs->ifs_fr_running == 1) { 4623448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 4633448Sdh155122 return (-1); 4643448Sdh155122 } 465*7656SSherry.Moore@Sun.COM 4663448Sdh155122 /* 4673448Sdh155122 * Make sure there is no active filter rule. 4683448Sdh155122 */ 4693448Sdh155122 if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] || 4703448Sdh155122 ifs->ifs_ipfilter[1][ifs->ifs_fr_active] || 4713448Sdh155122 ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] || 4723448Sdh155122 ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) { 4733448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 4743448Sdh155122 return (-1); 4753448Sdh155122 } 4763448Sdh155122 4773448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 4783448Sdh155122 4793448Sdh155122 return (0); 4803448Sdh155122 } 4813448Sdh155122 4827513SDarren.Reed@Sun.COM 4833448Sdh155122 static int ipf_detach_check_all() 4843448Sdh155122 { 4857513SDarren.Reed@Sun.COM ipf_stack_t *ifs; 4863448Sdh155122 4877513SDarren.Reed@Sun.COM mutex_enter(&ipf_stack_lock); 4887513SDarren.Reed@Sun.COM for (ifs = ipf_stacks; ifs != NULL; ifs = ifs->ifs_next) 4897513SDarren.Reed@Sun.COM if (ipf_detach_check_zone(ifs) != 0) 4907513SDarren.Reed@Sun.COM break; 4917513SDarren.Reed@Sun.COM mutex_exit(&ipf_stack_lock); 4927513SDarren.Reed@Sun.COM return ((ifs == NULL) ? 0 : -1); 4937513SDarren.Reed@Sun.COM } 4943448Sdh155122 4953448Sdh155122 4963448Sdh155122 /* 4973448Sdh155122 * Destroy things for ipf for one stack. 4983448Sdh155122 */ 4993448Sdh155122 /* ARGSUSED */ 5003448Sdh155122 static void 5017513SDarren.Reed@Sun.COM ipf_stack_destroy(const netid_t id, void *arg) 5023448Sdh155122 { 5033448Sdh155122 ipf_stack_t *ifs = (ipf_stack_t *)arg; 5047513SDarren.Reed@Sun.COM timeout_id_t tid; 5053448Sdh155122 5067513SDarren.Reed@Sun.COM #ifdef IPFDEBUG 5077513SDarren.Reed@Sun.COM (void) printf("ipf_stack_destroy(%p)\n", (void *)ifs); 5083448Sdh155122 #endif 5093448Sdh155122 5103448Sdh155122 /* 5113448Sdh155122 * Make sure we're the only one's modifying things. With 5123448Sdh155122 * this lock others should just fall out of the loop. 5133448Sdh155122 */ 5143448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global); 5153448Sdh155122 if (ifs->ifs_fr_running == -2) { 5163448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 5173448Sdh155122 return; 5183448Sdh155122 } 5193448Sdh155122 ifs->ifs_fr_running = -2; 5207513SDarren.Reed@Sun.COM tid = ifs->ifs_fr_timer_id; 5217513SDarren.Reed@Sun.COM ifs->ifs_fr_timer_id = NULL; 5223448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 5233448Sdh155122 5247513SDarren.Reed@Sun.COM mutex_enter(&ipf_stack_lock); 5257513SDarren.Reed@Sun.COM if (ifs->ifs_next != NULL) 5267513SDarren.Reed@Sun.COM ifs->ifs_next->ifs_pnext = ifs->ifs_pnext; 5277513SDarren.Reed@Sun.COM *ifs->ifs_pnext = ifs->ifs_next; 5287513SDarren.Reed@Sun.COM mutex_exit(&ipf_stack_lock); 5297513SDarren.Reed@Sun.COM 5307513SDarren.Reed@Sun.COM ipf_kstat_fini(ifs); 5317513SDarren.Reed@Sun.COM 5327513SDarren.Reed@Sun.COM if (tid != NULL) 5337513SDarren.Reed@Sun.COM (void) untimeout(tid); 5343448Sdh155122 5353448Sdh155122 WRITE_ENTER(&ifs->ifs_ipf_global); 5363448Sdh155122 if (ipldetach(ifs) != 0) { 5377513SDarren.Reed@Sun.COM printf("ipf_stack_destroy: ipldetach failed\n"); 5383448Sdh155122 } 5393448Sdh155122 5403448Sdh155122 ipftuneable_free(ifs); 5413448Sdh155122 5423448Sdh155122 RWLOCK_EXIT(&ifs->ifs_ipf_global); 5433448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_mutex); 5443448Sdh155122 RW_DESTROY(&ifs->ifs_ipf_global); 5453448Sdh155122 5463448Sdh155122 KFREE(ifs); 5473448Sdh155122 } 5482393Syz155240 5497513SDarren.Reed@Sun.COM 5502393Syz155240 static int ipf_attach(dip, cmd) 5512393Syz155240 dev_info_t *dip; 5522393Syz155240 ddi_attach_cmd_t cmd; 5532393Syz155240 { 5542393Syz155240 char *s; 5552393Syz155240 int i; 5562393Syz155240 int instance; 5572393Syz155240 5582393Syz155240 #ifdef IPFDEBUG 5597513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: ipf_attach(%p,%x)", dip, cmd); 5602393Syz155240 #endif 5612393Syz155240 5622393Syz155240 switch (cmd) 5632393Syz155240 { 5642393Syz155240 case DDI_ATTACH: 5652393Syz155240 instance = ddi_get_instance(dip); 5662393Syz155240 /* Only one instance of ipf (instance 0) can be attached. */ 5672393Syz155240 if (instance > 0) 568*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 5692393Syz155240 5702393Syz155240 #ifdef IPFDEBUG 5717513SDarren.Reed@Sun.COM cmn_err(CE_CONT, "IP Filter: attach ipf instance %d", instance); 5722393Syz155240 #endif 5732393Syz155240 5743448Sdh155122 (void) ipf_property_g_update(dip); 5752393Syz155240 5762393Syz155240 for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) { 5772393Syz155240 s = strrchr(s, '/'); 5782393Syz155240 if (s == NULL) 5792393Syz155240 continue; 5802393Syz155240 s++; 5812393Syz155240 if (ddi_create_minor_node(dip, s, S_IFCHR, i, 582*7656SSherry.Moore@Sun.COM DDI_PSEUDO, 0) == 5832393Syz155240 DDI_FAILURE) { 5842393Syz155240 ddi_remove_minor_node(dip, NULL); 5852393Syz155240 goto attach_failed; 5862393Syz155240 } 5872393Syz155240 } 5882393Syz155240 5892393Syz155240 ipf_dev_info = dip; 5907513SDarren.Reed@Sun.COM 5917513SDarren.Reed@Sun.COM ipfncb = net_instance_alloc(NETINFO_VERSION); 5927513SDarren.Reed@Sun.COM ipfncb->nin_name = "ipf"; 5937513SDarren.Reed@Sun.COM ipfncb->nin_create = ipf_stack_create; 5947513SDarren.Reed@Sun.COM ipfncb->nin_destroy = ipf_stack_destroy; 5957513SDarren.Reed@Sun.COM ipfncb->nin_shutdown = NULL; 5967513SDarren.Reed@Sun.COM i = net_instance_register(ipfncb); 5977513SDarren.Reed@Sun.COM 5987513SDarren.Reed@Sun.COM #ifdef IPFDEBUG 5997513SDarren.Reed@Sun.COM cmn_err(CE_CONT, "IP Filter:stack_create callback_reg=%d", i); 6007513SDarren.Reed@Sun.COM #endif 6017513SDarren.Reed@Sun.COM 602*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 6032393Syz155240 /* NOTREACHED */ 6042393Syz155240 default: 6052393Syz155240 break; 6062393Syz155240 } 6072393Syz155240 6082393Syz155240 attach_failed: 6093448Sdh155122 ddi_prop_remove_all(dip); 610*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 6112393Syz155240 } 6122393Syz155240 6132393Syz155240 6142393Syz155240 static int ipf_detach(dip, cmd) 6152393Syz155240 dev_info_t *dip; 6162393Syz155240 ddi_detach_cmd_t cmd; 6172393Syz155240 { 6182393Syz155240 int i; 6192393Syz155240 6202393Syz155240 #ifdef IPFDEBUG 6217513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: ipf_detach(%p,%x)", dip, cmd); 6222393Syz155240 #endif 6232393Syz155240 switch (cmd) { 6242393Syz155240 case DDI_DETACH: 6253448Sdh155122 if (ipf_detach_check_all() != 0) 626*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 6272393Syz155240 628*7656SSherry.Moore@Sun.COM /* 629*7656SSherry.Moore@Sun.COM * Undo what we did in ipf_attach, freeing resources 6302393Syz155240 * and removing things we installed. The system 6312393Syz155240 * framework guarantees we are not active with this devinfo 6322393Syz155240 * node in any other entry points at this time. 6332393Syz155240 */ 6342393Syz155240 ddi_prop_remove_all(dip); 6352393Syz155240 i = ddi_get_instance(dip); 6362393Syz155240 ddi_remove_minor_node(dip, NULL); 6372393Syz155240 if (i > 0) { 6382393Syz155240 cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i); 639*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 6402393Syz155240 } 6412393Syz155240 6427513SDarren.Reed@Sun.COM (void) net_instance_unregister(ipfncb); 6437513SDarren.Reed@Sun.COM net_instance_free(ipfncb); 6447513SDarren.Reed@Sun.COM 645*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 6463448Sdh155122 /* NOTREACHED */ 6472393Syz155240 default: 6482393Syz155240 break; 6492393Syz155240 } 6502393Syz155240 cmn_err(CE_NOTE, "IP Filter: failed to detach\n"); 651*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 6522393Syz155240 } 6532393Syz155240 6542393Syz155240 6552393Syz155240 /*ARGSUSED*/ 6562393Syz155240 static int ipf_getinfo(dip, infocmd, arg, result) 6572393Syz155240 dev_info_t *dip; 6582393Syz155240 ddi_info_cmd_t infocmd; 6592393Syz155240 void *arg, **result; 6602393Syz155240 { 6612393Syz155240 int error; 6622393Syz155240 6632393Syz155240 error = DDI_FAILURE; 6642393Syz155240 #ifdef IPFDEBUG 6657513SDarren.Reed@Sun.COM cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%p,%x,%p)", dip, infocmd, arg); 6662393Syz155240 #endif 6672393Syz155240 switch (infocmd) { 6682393Syz155240 case DDI_INFO_DEVT2DEVINFO: 6692393Syz155240 *result = ipf_dev_info; 6702393Syz155240 error = DDI_SUCCESS; 6712393Syz155240 break; 6722393Syz155240 case DDI_INFO_DEVT2INSTANCE: 6732393Syz155240 *result = (void *)0; 6742393Syz155240 error = DDI_SUCCESS; 6752393Syz155240 break; 6762393Syz155240 default: 6772393Syz155240 break; 6782393Syz155240 } 6792393Syz155240 return (error); 6802393Syz155240 } 6812393Syz155240 6822393Syz155240 6832393Syz155240 /* 6842393Syz155240 * Fetch configuration file values that have been entered into the ipf.conf 6852393Syz155240 * driver file. 6862393Syz155240 */ 6873448Sdh155122 static int ipf_property_g_update(dip) 6882393Syz155240 dev_info_t *dip; 6892393Syz155240 { 6902393Syz155240 #ifdef DDI_NO_AUTODETACH 6912393Syz155240 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 6922393Syz155240 DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) { 6932393Syz155240 cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed"); 694*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 6952393Syz155240 } 6962393Syz155240 #else 6972393Syz155240 if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 6982393Syz155240 "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) { 6992393Syz155240 cmn_err(CE_WARN, "!updating ddi-no-autodetach failed"); 700*7656SSherry.Moore@Sun.COM return (DDI_FAILURE); 7012393Syz155240 } 7022393Syz155240 #endif 7032393Syz155240 704*7656SSherry.Moore@Sun.COM return (DDI_SUCCESS); 7053448Sdh155122 } 7063448Sdh155122 707*7656SSherry.Moore@Sun.COM int 708*7656SSherry.Moore@Sun.COM ipf_property_update(dip, ifs) 7093448Sdh155122 dev_info_t *dip; 7103448Sdh155122 ipf_stack_t *ifs; 7113448Sdh155122 { 7123448Sdh155122 ipftuneable_t *ipft; 7133448Sdh155122 int64_t *i64p; 7143448Sdh155122 char *name; 715*7656SSherry.Moore@Sun.COM uint_t one; 7163448Sdh155122 int *i32p; 7173448Sdh155122 int err; 7183448Sdh155122 719*7656SSherry.Moore@Sun.COM for (ipft = ifs->ifs_ipf_tuneables; (name = ipft->ipft_name) != NULL; 720*7656SSherry.Moore@Sun.COM ipft++) { 7212393Syz155240 one = 1; 7222393Syz155240 switch (ipft->ipft_sz) 7232393Syz155240 { 7242393Syz155240 case 4 : 7252393Syz155240 i32p = NULL; 7262393Syz155240 err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 7272393Syz155240 0, name, &i32p, &one); 7282393Syz155240 if (err == DDI_PROP_NOT_FOUND) 7292393Syz155240 continue; 7302393Syz155240 #ifdef IPFDEBUG 7312393Syz155240 cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n", 7322393Syz155240 name, err); 7332393Syz155240 #endif 7342393Syz155240 if (err != DDI_PROP_SUCCESS) 735*7656SSherry.Moore@Sun.COM return (err); 7362393Syz155240 if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max) 7372393Syz155240 *ipft->ipft_pint = *i32p; 7382393Syz155240 else 7392393Syz155240 err = DDI_PROP_CANNOT_DECODE; 7402393Syz155240 ddi_prop_free(i32p); 7412393Syz155240 break; 7422393Syz155240 7432393Syz155240 #if SOLARIS2 > 8 7442393Syz155240 case 8 : 7452393Syz155240 i64p = NULL; 7462393Syz155240 err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip, 747*7656SSherry.Moore@Sun.COM 0, name, &i64p, &one); 7482393Syz155240 if (err == DDI_PROP_NOT_FOUND) 7492393Syz155240 continue; 750*7656SSherry.Moore@Sun.COM #ifdef IPFDEBUG 7512393Syz155240 cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n", 752*7656SSherry.Moore@Sun.COM name, err); 753*7656SSherry.Moore@Sun.COM #endif 7542393Syz155240 if (err != DDI_PROP_SUCCESS) 755*7656SSherry.Moore@Sun.COM return (err); 7562393Syz155240 if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max) 7572393Syz155240 *ipft->ipft_pint = *i64p; 7582393Syz155240 else 7592393Syz155240 err = DDI_PROP_CANNOT_DECODE; 7602393Syz155240 ddi_prop_free(i64p); 7612393Syz155240 break; 7622393Syz155240 #endif 7632393Syz155240 default : 7642393Syz155240 break; 7652393Syz155240 } 7662393Syz155240 if (err != DDI_SUCCESS) 7672393Syz155240 break; 7682393Syz155240 } 769*7656SSherry.Moore@Sun.COM return (err); 7702393Syz155240 } 771