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