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