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