1ab25eeb5Syz /* 2ab25eeb5Syz * Copyright (C) 1993-2001, 2003 by Darren Reed. 3ab25eeb5Syz * 4ab25eeb5Syz * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz * 6*f4b3ec61Sdh * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 7ab25eeb5Syz * Use is subject to license terms. 8ab25eeb5Syz */ 9ab25eeb5Syz /* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/ 10ab25eeb5Syz #pragma ident "@(#)$Id: solaris.c,v 2.73.2.6 2005/07/13 21:40:47 darrenr Exp $" 11ab25eeb5Syz 12ab25eeb5Syz #pragma ident "%Z%%M% %I% %E% SMI" 13ab25eeb5Syz 14ab25eeb5Syz #include <sys/systm.h> 15ab25eeb5Syz #include <sys/types.h> 16ab25eeb5Syz #include <sys/param.h> 17ab25eeb5Syz #include <sys/errno.h> 18ab25eeb5Syz #include <sys/uio.h> 19ab25eeb5Syz #include <sys/buf.h> 20ab25eeb5Syz #include <sys/modctl.h> 21ab25eeb5Syz #include <sys/open.h> 22ab25eeb5Syz #include <sys/kmem.h> 23ab25eeb5Syz #include <sys/conf.h> 24ab25eeb5Syz #include <sys/cmn_err.h> 25ab25eeb5Syz #include <sys/stat.h> 26ab25eeb5Syz #include <sys/cred.h> 27ab25eeb5Syz #include <sys/dditypes.h> 28ab25eeb5Syz #include <sys/poll.h> 29ab25eeb5Syz #include <sys/autoconf.h> 30ab25eeb5Syz #include <sys/byteorder.h> 31ab25eeb5Syz #include <sys/socket.h> 32ab25eeb5Syz #include <sys/dlpi.h> 33ab25eeb5Syz #include <sys/stropts.h> 34ab25eeb5Syz #include <sys/kstat.h> 35ab25eeb5Syz #include <sys/sockio.h> 36381a2a9aSdr #include <sys/neti.h> 37381a2a9aSdr #include <sys/hook.h> 38ab25eeb5Syz #include <net/if.h> 39ab25eeb5Syz #if SOLARIS2 >= 6 40ab25eeb5Syz # include <net/if_types.h> 41ab25eeb5Syz #endif 42*f4b3ec61Sdh #include <sys/netstack.h> 43ab25eeb5Syz #include <net/af.h> 44ab25eeb5Syz #include <net/route.h> 45ab25eeb5Syz #include <netinet/in.h> 46ab25eeb5Syz #include <netinet/in_systm.h> 47ab25eeb5Syz #include <netinet/if_ether.h> 48ab25eeb5Syz #include <netinet/ip.h> 49ab25eeb5Syz #include <netinet/ip_var.h> 50ab25eeb5Syz #include <netinet/tcp.h> 51ab25eeb5Syz #include <netinet/udp.h> 52ab25eeb5Syz #include <netinet/tcpip.h> 53ab25eeb5Syz #include <netinet/ip_icmp.h> 54ab25eeb5Syz #include <sys/ddi.h> 55ab25eeb5Syz #include <sys/sunddi.h> 56ab25eeb5Syz #include "netinet/ip_compat.h" 57ab25eeb5Syz #include "netinet/ipl.h" 58ab25eeb5Syz #include "netinet/ip_fil.h" 59ab25eeb5Syz #include "netinet/ip_nat.h" 60ab25eeb5Syz #include "netinet/ip_frag.h" 61ab25eeb5Syz #include "netinet/ip_auth.h" 62ab25eeb5Syz #include "netinet/ip_state.h" 63*f4b3ec61Sdh #include "netinet/ipf_stack.h" 64ab25eeb5Syz 65ab25eeb5Syz extern int iplwrite __P((dev_t, struct uio *, cred_t *)); 66ab25eeb5Syz 67ab25eeb5Syz static int ipf_getinfo __P((dev_info_t *, ddi_info_cmd_t, 68ab25eeb5Syz void *, void **)); 69ab25eeb5Syz #if SOLARIS2 < 10 70ab25eeb5Syz static int ipf_identify __P((dev_info_t *)); 71ab25eeb5Syz #endif 72ab25eeb5Syz static int ipf_attach __P((dev_info_t *, ddi_attach_cmd_t)); 73ab25eeb5Syz static int ipf_detach __P((dev_info_t *, ddi_detach_cmd_t)); 74*f4b3ec61Sdh static int ipf_property_g_update __P((dev_info_t *)); 75ab25eeb5Syz static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, 76ab25eeb5Syz IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, 77ab25eeb5Syz IPLOOKUP_NAME, NULL }; 78ab25eeb5Syz 79ab25eeb5Syz 80ab25eeb5Syz static struct cb_ops ipf_cb_ops = { 81ab25eeb5Syz iplopen, 82ab25eeb5Syz iplclose, 83ab25eeb5Syz nodev, /* strategy */ 84ab25eeb5Syz nodev, /* print */ 85ab25eeb5Syz nodev, /* dump */ 86ab25eeb5Syz iplread, 87ab25eeb5Syz iplwrite, /* write */ 88ab25eeb5Syz iplioctl, /* ioctl */ 89ab25eeb5Syz nodev, /* devmap */ 90ab25eeb5Syz nodev, /* mmap */ 91ab25eeb5Syz nodev, /* segmap */ 92ab25eeb5Syz nochpoll, /* poll */ 93ab25eeb5Syz ddi_prop_op, 94ab25eeb5Syz NULL, 95ab25eeb5Syz D_MTSAFE, 96ab25eeb5Syz #if SOLARIS2 > 4 97ab25eeb5Syz CB_REV, 98ab25eeb5Syz nodev, /* aread */ 99ab25eeb5Syz nodev, /* awrite */ 100ab25eeb5Syz #endif 101ab25eeb5Syz }; 102ab25eeb5Syz 103ab25eeb5Syz static struct dev_ops ipf_ops = { 104ab25eeb5Syz DEVO_REV, 105ab25eeb5Syz 0, 106ab25eeb5Syz ipf_getinfo, 107ab25eeb5Syz #if SOLARIS2 >= 10 108ab25eeb5Syz nulldev, 109ab25eeb5Syz #else 110ab25eeb5Syz ipf_identify, 111ab25eeb5Syz #endif 112ab25eeb5Syz nulldev, 113ab25eeb5Syz ipf_attach, 114ab25eeb5Syz ipf_detach, 115ab25eeb5Syz nodev, /* reset */ 116ab25eeb5Syz &ipf_cb_ops, 117ab25eeb5Syz (struct bus_ops *)0 118ab25eeb5Syz }; 119ab25eeb5Syz 120ab25eeb5Syz extern struct mod_ops mod_driverops; 121ab25eeb5Syz static struct modldrv iplmod = { 122ab25eeb5Syz &mod_driverops, IPL_VERSION, &ipf_ops }; 123ab25eeb5Syz static struct modlinkage modlink1 = { MODREV_1, &iplmod, NULL }; 124ab25eeb5Syz 125ab25eeb5Syz #if SOLARIS2 >= 6 126ab25eeb5Syz static size_t hdrsizes[57][2] = { 127ab25eeb5Syz { 0, 0 }, 128ab25eeb5Syz { IFT_OTHER, 0 }, 129ab25eeb5Syz { IFT_1822, 0 }, 130ab25eeb5Syz { IFT_HDH1822, 0 }, 131ab25eeb5Syz { IFT_X25DDN, 0 }, 132ab25eeb5Syz { IFT_X25, 0 }, 133ab25eeb5Syz { IFT_ETHER, 14 }, 134ab25eeb5Syz { IFT_ISO88023, 0 }, 135ab25eeb5Syz { IFT_ISO88024, 0 }, 136ab25eeb5Syz { IFT_ISO88025, 0 }, 137ab25eeb5Syz { IFT_ISO88026, 0 }, 138ab25eeb5Syz { IFT_STARLAN, 0 }, 139ab25eeb5Syz { IFT_P10, 0 }, 140ab25eeb5Syz { IFT_P80, 0 }, 141ab25eeb5Syz { IFT_HY, 0 }, 142ab25eeb5Syz { IFT_FDDI, 24 }, 143ab25eeb5Syz { IFT_LAPB, 0 }, 144ab25eeb5Syz { IFT_SDLC, 0 }, 145ab25eeb5Syz { IFT_T1, 0 }, 146ab25eeb5Syz { IFT_CEPT, 0 }, 147ab25eeb5Syz { IFT_ISDNBASIC, 0 }, 148ab25eeb5Syz { IFT_ISDNPRIMARY, 0 }, 149ab25eeb5Syz { IFT_PTPSERIAL, 0 }, 150ab25eeb5Syz { IFT_PPP, 0 }, 151ab25eeb5Syz { IFT_LOOP, 0 }, 152ab25eeb5Syz { IFT_EON, 0 }, 153ab25eeb5Syz { IFT_XETHER, 0 }, 154ab25eeb5Syz { IFT_NSIP, 0 }, 155ab25eeb5Syz { IFT_SLIP, 0 }, 156ab25eeb5Syz { IFT_ULTRA, 0 }, 157ab25eeb5Syz { IFT_DS3, 0 }, 158ab25eeb5Syz { IFT_SIP, 0 }, 159ab25eeb5Syz { IFT_FRELAY, 0 }, 160ab25eeb5Syz { IFT_RS232, 0 }, 161ab25eeb5Syz { IFT_PARA, 0 }, 162ab25eeb5Syz { IFT_ARCNET, 0 }, 163ab25eeb5Syz { IFT_ARCNETPLUS, 0 }, 164ab25eeb5Syz { IFT_ATM, 0 }, 165ab25eeb5Syz { IFT_MIOX25, 0 }, 166ab25eeb5Syz { IFT_SONET, 0 }, 167ab25eeb5Syz { IFT_X25PLE, 0 }, 168ab25eeb5Syz { IFT_ISO88022LLC, 0 }, 169ab25eeb5Syz { IFT_LOCALTALK, 0 }, 170ab25eeb5Syz { IFT_SMDSDXI, 0 }, 171ab25eeb5Syz { IFT_FRELAYDCE, 0 }, 172ab25eeb5Syz { IFT_V35, 0 }, 173ab25eeb5Syz { IFT_HSSI, 0 }, 174ab25eeb5Syz { IFT_HIPPI, 0 }, 175ab25eeb5Syz { IFT_MODEM, 0 }, 176ab25eeb5Syz { IFT_AAL5, 0 }, 177ab25eeb5Syz { IFT_SONETPATH, 0 }, 178ab25eeb5Syz { IFT_SONETVT, 0 }, 179ab25eeb5Syz { IFT_SMDSICIP, 0 }, 180ab25eeb5Syz { IFT_PROPVIRTUAL, 0 }, 181ab25eeb5Syz { IFT_PROPMUX, 0 }, 182ab25eeb5Syz }; 183ab25eeb5Syz #endif /* SOLARIS2 >= 6 */ 184ab25eeb5Syz 185*f4b3ec61Sdh dev_info_t *ipf_dev_info = NULL; 186ab25eeb5Syz 187ab25eeb5Syz static const filter_kstats_t ipf_kstat_tmp = { 188ab25eeb5Syz { "pass", KSTAT_DATA_ULONG }, 189ab25eeb5Syz { "block", KSTAT_DATA_ULONG }, 190ab25eeb5Syz { "nomatch", KSTAT_DATA_ULONG }, 191ab25eeb5Syz { "short", KSTAT_DATA_ULONG }, 192ab25eeb5Syz { "pass, logged", KSTAT_DATA_ULONG }, 193ab25eeb5Syz { "block, logged", KSTAT_DATA_ULONG }, 194ab25eeb5Syz { "nomatch, logged", KSTAT_DATA_ULONG }, 195ab25eeb5Syz { "logged", KSTAT_DATA_ULONG }, 196ab25eeb5Syz { "skip", KSTAT_DATA_ULONG }, 197ab25eeb5Syz { "return sent", KSTAT_DATA_ULONG }, 198ab25eeb5Syz { "acct", KSTAT_DATA_ULONG }, 199ab25eeb5Syz { "bad frag state alloc", KSTAT_DATA_ULONG }, 200ab25eeb5Syz { "new frag state kept", KSTAT_DATA_ULONG }, 201ab25eeb5Syz { "new frag state compl. pkt", KSTAT_DATA_ULONG }, 202ab25eeb5Syz { "bad pkt state alloc", KSTAT_DATA_ULONG }, 203ab25eeb5Syz { "new pkt kept state", KSTAT_DATA_ULONG }, 204ab25eeb5Syz { "cachehit", KSTAT_DATA_ULONG }, 205ab25eeb5Syz { "tcp cksum bad", KSTAT_DATA_ULONG }, 206ab25eeb5Syz {{ "pullup ok", KSTAT_DATA_ULONG }, 207ab25eeb5Syz { "pullup nok", KSTAT_DATA_ULONG }}, 208ab25eeb5Syz { "src != route", KSTAT_DATA_ULONG }, 209ab25eeb5Syz { "ttl invalid", KSTAT_DATA_ULONG }, 210ab25eeb5Syz { "bad ip pkt", KSTAT_DATA_ULONG }, 211ab25eeb5Syz { "ipv6 pkt", KSTAT_DATA_ULONG }, 212ab25eeb5Syz { "dropped:pps ceiling", KSTAT_DATA_ULONG }, 213ab25eeb5Syz { "ip upd. fail", KSTAT_DATA_ULONG } 214ab25eeb5Syz }; 215ab25eeb5Syz 216381a2a9aSdr 217ab25eeb5Syz static int ipf_kstat_update(kstat_t *ksp, int rwflag); 218ab25eeb5Syz 219ab25eeb5Syz static void 220*f4b3ec61Sdh ipf_kstat_init(ipf_stack_t *ifs, netstackid_t stackid) 221ab25eeb5Syz { 222ab25eeb5Syz int i; 223ab25eeb5Syz 224ab25eeb5Syz for (i = 0; i < 2; i++) { 225*f4b3ec61Sdh ifs->ifs_kstatp[i] = kstat_create_netstack("ipf", 0, 226ab25eeb5Syz (i==0)?"inbound":"outbound", 227ab25eeb5Syz "net", 228ab25eeb5Syz KSTAT_TYPE_NAMED, 229ab25eeb5Syz sizeof (filter_kstats_t) / sizeof (kstat_named_t), 230*f4b3ec61Sdh 0, stackid); 231*f4b3ec61Sdh if (ifs->ifs_kstatp[i] != NULL) { 232*f4b3ec61Sdh bcopy(&ipf_kstat_tmp, ifs->ifs_kstatp[i]->ks_data, 233ab25eeb5Syz sizeof (filter_kstats_t)); 234*f4b3ec61Sdh ifs->ifs_kstatp[i]->ks_update = ipf_kstat_update; 235*f4b3ec61Sdh ifs->ifs_kstatp[i]->ks_private = &ifs->ifs_frstats[i]; 236*f4b3ec61Sdh kstat_install(ifs->ifs_kstatp[i]); 237ab25eeb5Syz } 238ab25eeb5Syz } 239ab25eeb5Syz 240ab25eeb5Syz #ifdef IPFDEBUG 241ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: ipf_kstat_init() installed 0x%x, 0x%x", 242*f4b3ec61Sdh ifs->ifs_kstatp[0], ifs->ifs_kstatp[1]); 243ab25eeb5Syz #endif 244ab25eeb5Syz } 245ab25eeb5Syz 246ab25eeb5Syz static void 247*f4b3ec61Sdh ipf_kstat_fini(ipf_stack_t *ifs, netstackid_t stackid) 248ab25eeb5Syz { 249ab25eeb5Syz int i; 250*f4b3ec61Sdh 251ab25eeb5Syz for (i = 0; i < 2; i++) { 252*f4b3ec61Sdh if (ifs->ifs_kstatp[i] != NULL) { 253*f4b3ec61Sdh kstat_delete_netstack(ifs->ifs_kstatp[i], stackid); 254*f4b3ec61Sdh ifs->ifs_kstatp[i] = NULL; 255ab25eeb5Syz } 256ab25eeb5Syz } 257ab25eeb5Syz } 258ab25eeb5Syz 259ab25eeb5Syz static int 260ab25eeb5Syz ipf_kstat_update(kstat_t *ksp, int rwflag) 261ab25eeb5Syz { 262ab25eeb5Syz filter_kstats_t *fkp; 263ab25eeb5Syz filterstats_t *fsp; 264ab25eeb5Syz 265*f4b3ec61Sdh if (ksp == NULL || ksp->ks_data == NULL) 266*f4b3ec61Sdh return (EIO); 267*f4b3ec61Sdh 268ab25eeb5Syz if (rwflag == KSTAT_WRITE) 269ab25eeb5Syz return (EACCES); 270ab25eeb5Syz 271ab25eeb5Syz fkp = ksp->ks_data; 272ab25eeb5Syz fsp = ksp->ks_private; 273ab25eeb5Syz 274ab25eeb5Syz fkp->fks_pass.value.ul = fsp->fr_pass; 275ab25eeb5Syz fkp->fks_block.value.ul = fsp->fr_block; 276ab25eeb5Syz fkp->fks_nom.value.ul = fsp->fr_nom; 277ab25eeb5Syz fkp->fks_short.value.ul = fsp->fr_short; 278ab25eeb5Syz fkp->fks_ppkl.value.ul = fsp->fr_ppkl; 279ab25eeb5Syz fkp->fks_bpkl.value.ul = fsp->fr_bpkl; 280ab25eeb5Syz fkp->fks_npkl.value.ul = fsp->fr_npkl; 281ab25eeb5Syz fkp->fks_pkl.value.ul = fsp->fr_pkl; 282ab25eeb5Syz fkp->fks_skip.value.ul = fsp->fr_skip; 283ab25eeb5Syz fkp->fks_ret.value.ul = fsp->fr_ret; 284ab25eeb5Syz fkp->fks_acct.value.ul = fsp->fr_acct; 285ab25eeb5Syz fkp->fks_bnfr.value.ul = fsp->fr_bnfr; 286ab25eeb5Syz fkp->fks_nfr.value.ul = fsp->fr_nfr; 287ab25eeb5Syz fkp->fks_cfr.value.ul = fsp->fr_cfr; 288ab25eeb5Syz fkp->fks_bads.value.ul = fsp->fr_bads; 289ab25eeb5Syz fkp->fks_ads.value.ul = fsp->fr_ads; 290ab25eeb5Syz fkp->fks_chit.value.ul = fsp->fr_chit; 291ab25eeb5Syz fkp->fks_tcpbad.value.ul = fsp->fr_tcpbad; 292ab25eeb5Syz fkp->fks_pull[0].value.ul = fsp->fr_pull[0]; 293ab25eeb5Syz fkp->fks_pull[1].value.ul = fsp->fr_pull[1]; 294ab25eeb5Syz fkp->fks_badsrc.value.ul = fsp->fr_badsrc; 295ab25eeb5Syz fkp->fks_badttl.value.ul = fsp->fr_badttl; 296ab25eeb5Syz fkp->fks_bad.value.ul = fsp->fr_bad; 297ab25eeb5Syz fkp->fks_ipv6.value.ul = fsp->fr_ipv6; 298ab25eeb5Syz fkp->fks_ppshit.value.ul = fsp->fr_ppshit; 299ab25eeb5Syz fkp->fks_ipud.value.ul = fsp->fr_ipud; 300ab25eeb5Syz 301ab25eeb5Syz return (0); 302ab25eeb5Syz } 303ab25eeb5Syz 304ab25eeb5Syz int _init() 305ab25eeb5Syz { 306ab25eeb5Syz int ipfinst; 307ab25eeb5Syz 308ab25eeb5Syz ipfinst = mod_install(&modlink1); 309ab25eeb5Syz #ifdef IPFDEBUG 310ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: _init() = %d", ipfinst); 311ab25eeb5Syz #endif 312ab25eeb5Syz return ipfinst; 313ab25eeb5Syz } 314ab25eeb5Syz 315ab25eeb5Syz 316ab25eeb5Syz int _fini(void) 317ab25eeb5Syz { 318ab25eeb5Syz int ipfinst; 319ab25eeb5Syz 320ab25eeb5Syz ipfinst = mod_remove(&modlink1); 321ab25eeb5Syz #ifdef IPFDEBUG 322ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: _fini() = %d", ipfinst); 323ab25eeb5Syz #endif 324ab25eeb5Syz return ipfinst; 325ab25eeb5Syz } 326ab25eeb5Syz 327ab25eeb5Syz 328ab25eeb5Syz int _info(modinfop) 329ab25eeb5Syz struct modinfo *modinfop; 330ab25eeb5Syz { 331ab25eeb5Syz int ipfinst; 332ab25eeb5Syz 333ab25eeb5Syz ipfinst = mod_info(&modlink1, modinfop); 334ab25eeb5Syz #ifdef IPFDEBUG 335ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: _info(%x) = %x", modinfop, ipfinst); 336ab25eeb5Syz #endif 337ab25eeb5Syz return ipfinst; 338ab25eeb5Syz } 339ab25eeb5Syz 340ab25eeb5Syz 341ab25eeb5Syz #if SOLARIS2 < 10 342ab25eeb5Syz static int ipf_identify(dip) 343ab25eeb5Syz dev_info_t *dip; 344ab25eeb5Syz { 345ab25eeb5Syz # ifdef IPFDEBUG 346ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: ipf_identify(%x)", dip); 347ab25eeb5Syz # endif 348ab25eeb5Syz if (strcmp(ddi_get_name(dip), "ipf") == 0) 349ab25eeb5Syz return (DDI_IDENTIFIED); 350ab25eeb5Syz return (DDI_NOT_IDENTIFIED); 351ab25eeb5Syz } 352ab25eeb5Syz #endif 353ab25eeb5Syz 354*f4b3ec61Sdh /* 355*f4b3ec61Sdh * Initialize things for IPF for each stack instance 356*f4b3ec61Sdh */ 357*f4b3ec61Sdh static void * 358*f4b3ec61Sdh ipf_stack_init(netstackid_t stackid, netstack_t *ns) 359*f4b3ec61Sdh { 360*f4b3ec61Sdh ipf_stack_t *ifs; 361*f4b3ec61Sdh 362*f4b3ec61Sdh #ifdef NS_DEBUG 363*f4b3ec61Sdh (void) printf("ipf_stack_init(%d)\n", stackid); 364*f4b3ec61Sdh #endif 365*f4b3ec61Sdh 366*f4b3ec61Sdh KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs)); 367*f4b3ec61Sdh bzero(ifs, sizeof (*ifs)); 368*f4b3ec61Sdh 369*f4b3ec61Sdh ifs->ifs_netstack = ns; 370*f4b3ec61Sdh 371*f4b3ec61Sdh ifs->ifs_hook4_physical_in = B_FALSE; 372*f4b3ec61Sdh ifs->ifs_hook4_physical_out = B_FALSE; 373*f4b3ec61Sdh ifs->ifs_hook4_nic_events = B_FALSE; 374*f4b3ec61Sdh ifs->ifs_hook4_loopback_in = B_FALSE; 375*f4b3ec61Sdh ifs->ifs_hook4_loopback_out = B_FALSE; 376*f4b3ec61Sdh ifs->ifs_hook6_physical_in = B_FALSE; 377*f4b3ec61Sdh ifs->ifs_hook6_physical_out = B_FALSE; 378*f4b3ec61Sdh ifs->ifs_hook6_nic_events = B_FALSE; 379*f4b3ec61Sdh ifs->ifs_hook6_loopback_in = B_FALSE; 380*f4b3ec61Sdh ifs->ifs_hook6_loopback_out = B_FALSE; 381*f4b3ec61Sdh 382*f4b3ec61Sdh /* 383*f4b3ec61Sdh * Initialize mutex's 384*f4b3ec61Sdh */ 385*f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); 386*f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); 387*f4b3ec61Sdh RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf cache rwlock"); 388*f4b3ec61Sdh #ifdef KERNEL 389*f4b3ec61Sdh ipf_kstat_init(ifs, stackid); 390*f4b3ec61Sdh #endif 391*f4b3ec61Sdh 392*f4b3ec61Sdh /* 393*f4b3ec61Sdh * Lock people out while we set things up. 394*f4b3ec61Sdh */ 395*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 396*f4b3ec61Sdh ipftuneable_alloc(ifs); 397*f4b3ec61Sdh ifs->ifs_fr_timer_id = timeout(fr_slowtimer, (void *)ifs, 398*f4b3ec61Sdh drv_usectohz(500000)); 399*f4b3ec61Sdh 400*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 401*f4b3ec61Sdh 402*f4b3ec61Sdh cmn_err(CE_CONT, "!%s, running.\n", ipfilter_version); 403*f4b3ec61Sdh return (ifs); 404*f4b3ec61Sdh } 405*f4b3ec61Sdh 406*f4b3ec61Sdh static int ipf_detach_check_zone(ipf_stack_t *ifs) 407*f4b3ec61Sdh { 408*f4b3ec61Sdh /* 409*f4b3ec61Sdh * Make sure we're the only one's modifying things. With 410*f4b3ec61Sdh * this lock others should just fall out of the loop. 411*f4b3ec61Sdh */ 412*f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_global); 413*f4b3ec61Sdh if (ifs->ifs_fr_running == 1) { 414*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 415*f4b3ec61Sdh return (-1); 416*f4b3ec61Sdh } 417*f4b3ec61Sdh 418*f4b3ec61Sdh /* 419*f4b3ec61Sdh * Make sure there is no active filter rule. 420*f4b3ec61Sdh */ 421*f4b3ec61Sdh if (ifs->ifs_ipfilter[0][ifs->ifs_fr_active] || 422*f4b3ec61Sdh ifs->ifs_ipfilter[1][ifs->ifs_fr_active] || 423*f4b3ec61Sdh ifs->ifs_ipfilter6[0][ifs->ifs_fr_active] || 424*f4b3ec61Sdh ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]) { 425*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 426*f4b3ec61Sdh return (-1); 427*f4b3ec61Sdh } 428*f4b3ec61Sdh 429*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 430*f4b3ec61Sdh 431*f4b3ec61Sdh return (0); 432*f4b3ec61Sdh } 433*f4b3ec61Sdh 434*f4b3ec61Sdh static int ipf_detach_check_all() 435*f4b3ec61Sdh { 436*f4b3ec61Sdh netstack_handle_t nh; 437*f4b3ec61Sdh netstack_t *ns; 438*f4b3ec61Sdh int ret; 439*f4b3ec61Sdh 440*f4b3ec61Sdh netstack_next_init(&nh); 441*f4b3ec61Sdh while ((ns = netstack_next(&nh)) != NULL) { 442*f4b3ec61Sdh ret = ipf_detach_check_zone(ns->netstack_ipf); 443*f4b3ec61Sdh netstack_rele(ns); 444*f4b3ec61Sdh if (ret != 0) { 445*f4b3ec61Sdh netstack_next_fini(&nh); 446*f4b3ec61Sdh return (-1); 447*f4b3ec61Sdh } 448*f4b3ec61Sdh } 449*f4b3ec61Sdh 450*f4b3ec61Sdh netstack_next_fini(&nh); 451*f4b3ec61Sdh return (0); 452*f4b3ec61Sdh } 453*f4b3ec61Sdh 454*f4b3ec61Sdh /* 455*f4b3ec61Sdh * Destroy things for ipf for one stack. 456*f4b3ec61Sdh */ 457*f4b3ec61Sdh /* ARGSUSED */ 458*f4b3ec61Sdh static void 459*f4b3ec61Sdh ipf_stack_fini(netstackid_t stackid, void *arg) 460*f4b3ec61Sdh { 461*f4b3ec61Sdh ipf_stack_t *ifs = (ipf_stack_t *)arg; 462*f4b3ec61Sdh 463*f4b3ec61Sdh #ifdef NS_DEBUG 464*f4b3ec61Sdh (void) printf("ipf_stack_destroy(%p, stackid %d)\n", 465*f4b3ec61Sdh (void *)ifs, stackid); 466*f4b3ec61Sdh #endif 467*f4b3ec61Sdh 468*f4b3ec61Sdh /* 469*f4b3ec61Sdh * Make sure we're the only one's modifying things. With 470*f4b3ec61Sdh * this lock others should just fall out of the loop. 471*f4b3ec61Sdh */ 472*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 473*f4b3ec61Sdh if (ifs->ifs_fr_running == -2) { 474*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 475*f4b3ec61Sdh return; 476*f4b3ec61Sdh } 477*f4b3ec61Sdh ifs->ifs_fr_running = -2; 478*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 479*f4b3ec61Sdh 480*f4b3ec61Sdh #ifdef KERNEL 481*f4b3ec61Sdh ipf_kstat_fini(ifs, stackid); 482*f4b3ec61Sdh #endif 483*f4b3ec61Sdh if (ifs->ifs_fr_timer_id != 0) { 484*f4b3ec61Sdh (void) untimeout(ifs->ifs_fr_timer_id); 485*f4b3ec61Sdh ifs->ifs_fr_timer_id = 0; 486*f4b3ec61Sdh } 487*f4b3ec61Sdh 488*f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_global); 489*f4b3ec61Sdh if (ipldetach(ifs) != 0) { 490*f4b3ec61Sdh printf("ipf_stack_fini: ipldetach failed\n"); 491*f4b3ec61Sdh } 492*f4b3ec61Sdh 493*f4b3ec61Sdh ipftuneable_free(ifs); 494*f4b3ec61Sdh 495*f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_global); 496*f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_mutex); 497*f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_frcache); 498*f4b3ec61Sdh RW_DESTROY(&ifs->ifs_ipf_global); 499*f4b3ec61Sdh 500*f4b3ec61Sdh KFREE(ifs); 501*f4b3ec61Sdh } 502ab25eeb5Syz 503ab25eeb5Syz static int ipf_attach(dip, cmd) 504ab25eeb5Syz dev_info_t *dip; 505ab25eeb5Syz ddi_attach_cmd_t cmd; 506ab25eeb5Syz { 507ab25eeb5Syz char *s; 508ab25eeb5Syz int i; 509ab25eeb5Syz int instance; 510ab25eeb5Syz 511ab25eeb5Syz #ifdef IPFDEBUG 512ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: ipf_attach(%x,%x)", dip, cmd); 513ab25eeb5Syz #endif 514ab25eeb5Syz 515ab25eeb5Syz switch (cmd) 516ab25eeb5Syz { 517ab25eeb5Syz case DDI_ATTACH: 518ab25eeb5Syz instance = ddi_get_instance(dip); 519ab25eeb5Syz /* Only one instance of ipf (instance 0) can be attached. */ 520ab25eeb5Syz if (instance > 0) 521ab25eeb5Syz return DDI_FAILURE; 522ab25eeb5Syz 523ab25eeb5Syz #ifdef IPFDEBUG 524ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: attach ipf instance %d", instance); 525ab25eeb5Syz #endif 526ab25eeb5Syz 527*f4b3ec61Sdh (void) ipf_property_g_update(dip); 528ab25eeb5Syz 529ab25eeb5Syz for (i = 0; ((s = ipf_devfiles[i]) != NULL); i++) { 530ab25eeb5Syz s = strrchr(s, '/'); 531ab25eeb5Syz if (s == NULL) 532ab25eeb5Syz continue; 533ab25eeb5Syz s++; 534ab25eeb5Syz if (ddi_create_minor_node(dip, s, S_IFCHR, i, 535ab25eeb5Syz DDI_PSEUDO, 0) == 536ab25eeb5Syz DDI_FAILURE) { 537ab25eeb5Syz ddi_remove_minor_node(dip, NULL); 538ab25eeb5Syz goto attach_failed; 539ab25eeb5Syz } 540ab25eeb5Syz } 541ab25eeb5Syz 542ab25eeb5Syz ipf_dev_info = dip; 543*f4b3ec61Sdh netstack_register(NS_IPF, ipf_stack_init, NULL, 544*f4b3ec61Sdh ipf_stack_fini); 545ab25eeb5Syz return DDI_SUCCESS; 546ab25eeb5Syz /* NOTREACHED */ 547ab25eeb5Syz default: 548ab25eeb5Syz break; 549ab25eeb5Syz } 550ab25eeb5Syz 551ab25eeb5Syz attach_failed: 552*f4b3ec61Sdh ddi_prop_remove_all(dip); 553ab25eeb5Syz return DDI_FAILURE; 554ab25eeb5Syz } 555ab25eeb5Syz 556ab25eeb5Syz 557ab25eeb5Syz static int ipf_detach(dip, cmd) 558ab25eeb5Syz dev_info_t *dip; 559ab25eeb5Syz ddi_detach_cmd_t cmd; 560ab25eeb5Syz { 561ab25eeb5Syz int i; 562ab25eeb5Syz 563ab25eeb5Syz #ifdef IPFDEBUG 564ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: ipf_detach(%x,%x)", dip, cmd); 565ab25eeb5Syz #endif 566ab25eeb5Syz switch (cmd) { 567ab25eeb5Syz case DDI_DETACH: 568*f4b3ec61Sdh if (ipf_detach_check_all() != 0) 569ab25eeb5Syz return DDI_FAILURE; 570ab25eeb5Syz 571*f4b3ec61Sdh /* Undo what we did in ipf_attach, freeing resources 572ab25eeb5Syz * and removing things we installed. The system 573ab25eeb5Syz * framework guarantees we are not active with this devinfo 574ab25eeb5Syz * node in any other entry points at this time. 575ab25eeb5Syz */ 576ab25eeb5Syz ddi_prop_remove_all(dip); 577ab25eeb5Syz i = ddi_get_instance(dip); 578ab25eeb5Syz ddi_remove_minor_node(dip, NULL); 579ab25eeb5Syz if (i > 0) { 580ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: still attached (%d)\n", i); 581ab25eeb5Syz return DDI_FAILURE; 582ab25eeb5Syz } 583ab25eeb5Syz 584*f4b3ec61Sdh netstack_unregister(NS_IPF); 585*f4b3ec61Sdh return DDI_SUCCESS; 586*f4b3ec61Sdh /* NOTREACHED */ 587ab25eeb5Syz default: 588ab25eeb5Syz break; 589ab25eeb5Syz } 590ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: failed to detach\n"); 591ab25eeb5Syz return DDI_FAILURE; 592ab25eeb5Syz } 593ab25eeb5Syz 594ab25eeb5Syz 595ab25eeb5Syz /*ARGSUSED*/ 596ab25eeb5Syz static int ipf_getinfo(dip, infocmd, arg, result) 597ab25eeb5Syz dev_info_t *dip; 598ab25eeb5Syz ddi_info_cmd_t infocmd; 599ab25eeb5Syz void *arg, **result; 600ab25eeb5Syz { 601ab25eeb5Syz int error; 602ab25eeb5Syz 603ab25eeb5Syz error = DDI_FAILURE; 604ab25eeb5Syz #ifdef IPFDEBUG 605ab25eeb5Syz cmn_err(CE_NOTE, "IP Filter: ipf_getinfo(%x,%x,%x)", dip, infocmd, arg); 606ab25eeb5Syz #endif 607ab25eeb5Syz switch (infocmd) { 608ab25eeb5Syz case DDI_INFO_DEVT2DEVINFO: 609ab25eeb5Syz *result = ipf_dev_info; 610ab25eeb5Syz error = DDI_SUCCESS; 611ab25eeb5Syz break; 612ab25eeb5Syz case DDI_INFO_DEVT2INSTANCE: 613ab25eeb5Syz *result = (void *)0; 614ab25eeb5Syz error = DDI_SUCCESS; 615ab25eeb5Syz break; 616ab25eeb5Syz default: 617ab25eeb5Syz break; 618ab25eeb5Syz } 619ab25eeb5Syz return (error); 620ab25eeb5Syz } 621ab25eeb5Syz 622ab25eeb5Syz 623ab25eeb5Syz /* 624ab25eeb5Syz * Fetch configuration file values that have been entered into the ipf.conf 625ab25eeb5Syz * driver file. 626ab25eeb5Syz */ 627*f4b3ec61Sdh static int ipf_property_g_update(dip) 628ab25eeb5Syz dev_info_t *dip; 629ab25eeb5Syz { 630ab25eeb5Syz #ifdef DDI_NO_AUTODETACH 631ab25eeb5Syz if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 632ab25eeb5Syz DDI_NO_AUTODETACH, 1) != DDI_PROP_SUCCESS) { 633ab25eeb5Syz cmn_err(CE_WARN, "!updating DDI_NO_AUTODETACH failed"); 634ab25eeb5Syz return DDI_FAILURE; 635ab25eeb5Syz } 636ab25eeb5Syz #else 637ab25eeb5Syz if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 638ab25eeb5Syz "ddi-no-autodetach", 1) != DDI_PROP_SUCCESS) { 639ab25eeb5Syz cmn_err(CE_WARN, "!updating ddi-no-autodetach failed"); 640ab25eeb5Syz return DDI_FAILURE; 641ab25eeb5Syz } 642ab25eeb5Syz #endif 643ab25eeb5Syz 644*f4b3ec61Sdh return DDI_SUCCESS; 645*f4b3ec61Sdh } 646*f4b3ec61Sdh 647*f4b3ec61Sdh int ipf_property_update(dip, ifs) 648*f4b3ec61Sdh dev_info_t *dip; 649*f4b3ec61Sdh ipf_stack_t *ifs; 650*f4b3ec61Sdh { 651*f4b3ec61Sdh ipftuneable_t *ipft; 652*f4b3ec61Sdh int64_t *i64p; 653*f4b3ec61Sdh char *name; 654*f4b3ec61Sdh u_int one; 655*f4b3ec61Sdh int *i32p; 656*f4b3ec61Sdh int err; 657*f4b3ec61Sdh 658*f4b3ec61Sdh for (ipft = ifs->ifs_ipf_tuneables; (name = ipft->ipft_name) != NULL; ipft++) { 659ab25eeb5Syz one = 1; 660ab25eeb5Syz switch (ipft->ipft_sz) 661ab25eeb5Syz { 662ab25eeb5Syz case 4 : 663ab25eeb5Syz i32p = NULL; 664ab25eeb5Syz err = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 665ab25eeb5Syz 0, name, &i32p, &one); 666ab25eeb5Syz if (err == DDI_PROP_NOT_FOUND) 667ab25eeb5Syz continue; 668ab25eeb5Syz #ifdef IPFDEBUG 669ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: lookup_int(%s) = %d\n", 670ab25eeb5Syz name, err); 671ab25eeb5Syz #endif 672ab25eeb5Syz if (err != DDI_PROP_SUCCESS) 673ab25eeb5Syz return err; 674ab25eeb5Syz if (*i32p >= ipft->ipft_min && *i32p <= ipft->ipft_max) 675ab25eeb5Syz *ipft->ipft_pint = *i32p; 676ab25eeb5Syz else 677ab25eeb5Syz err = DDI_PROP_CANNOT_DECODE; 678ab25eeb5Syz ddi_prop_free(i32p); 679ab25eeb5Syz break; 680ab25eeb5Syz 681ab25eeb5Syz #if SOLARIS2 > 8 682ab25eeb5Syz case 8 : 683ab25eeb5Syz i64p = NULL; 684ab25eeb5Syz err = ddi_prop_lookup_int64_array(DDI_DEV_T_ANY, dip, 685ab25eeb5Syz 0, name, &i64p, &one); 686ab25eeb5Syz if (err == DDI_PROP_NOT_FOUND) 687ab25eeb5Syz continue; 688ab25eeb5Syz # ifdef IPFDEBUG 689ab25eeb5Syz cmn_err(CE_CONT, "IP Filter: lookup_int64(%s) = %d\n", 690ab25eeb5Syz name, err); 691ab25eeb5Syz # endif 692ab25eeb5Syz if (err != DDI_PROP_SUCCESS) 693ab25eeb5Syz return err; 694ab25eeb5Syz if (*i64p >= ipft->ipft_min && *i64p <= ipft->ipft_max) 695ab25eeb5Syz *ipft->ipft_pint = *i64p; 696ab25eeb5Syz else 697ab25eeb5Syz err = DDI_PROP_CANNOT_DECODE; 698ab25eeb5Syz ddi_prop_free(i64p); 699ab25eeb5Syz break; 700ab25eeb5Syz #endif 701ab25eeb5Syz default : 702ab25eeb5Syz break; 703ab25eeb5Syz } 704ab25eeb5Syz if (err != DDI_SUCCESS) 705ab25eeb5Syz break; 706ab25eeb5Syz } 707ab25eeb5Syz return err; 708ab25eeb5Syz } 709