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 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if !defined(lint) 13 static const char sccsid[] = "@(#)ip_fil_solaris.c 1.7 07/22/06 (C) 1993-2000 Darren Reed"; 14 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.62.2.19 2005/07/13 21:40:46 darrenr Exp $"; 15 #endif 16 17 #include <sys/types.h> 18 #include <sys/errno.h> 19 #include <sys/param.h> 20 #include <sys/cpuvar.h> 21 #include <sys/open.h> 22 #include <sys/ioctl.h> 23 #include <sys/filio.h> 24 #include <sys/systm.h> 25 #include <sys/strsubr.h> 26 #include <sys/cred.h> 27 #include <sys/cred_impl.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/ksynch.h> 31 #include <sys/kmem.h> 32 #include <sys/mkdev.h> 33 #include <sys/protosw.h> 34 #include <sys/socket.h> 35 #include <sys/dditypes.h> 36 #include <sys/cmn_err.h> 37 #include <sys/zone.h> 38 #include <net/if.h> 39 #include <net/af.h> 40 #include <net/route.h> 41 #include <netinet/in.h> 42 #include <netinet/in_systm.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 "netinet/ip_compat.h" 50 #ifdef USE_INET6 51 # include <netinet/icmp6.h> 52 #endif 53 #include "netinet/ip_fil.h" 54 #include "netinet/ip_nat.h" 55 #include "netinet/ip_frag.h" 56 #include "netinet/ip_state.h" 57 #include "netinet/ip_auth.h" 58 #include "netinet/ip_proxy.h" 59 #include "netinet/ipf_stack.h" 60 #ifdef IPFILTER_LOOKUP 61 # include "netinet/ip_lookup.h" 62 #endif 63 #include <inet/ip_ire.h> 64 65 #include <sys/md5.h> 66 #include <sys/neti.h> 67 68 static int frzerostats __P((caddr_t, ipf_stack_t *)); 69 static int fr_setipfloopback __P((int, ipf_stack_t *)); 70 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 71 static int ipf_nic_event_v4 __P((hook_event_token_t, hook_data_t, 72 netstack_t *)); 73 static int ipf_nic_event_v6 __P((hook_event_token_t, hook_data_t, 74 netstack_t *)); 75 static int ipf_hook_out __P((hook_event_token_t, hook_data_t, 76 netstack_t *)); 77 static int ipf_hook_in __P((hook_event_token_t, hook_data_t, 78 netstack_t *)); 79 static int ipf_hook_loop_out __P((hook_event_token_t, hook_data_t, 80 netstack_t *)); 81 static int ipf_hook_loop_in __P((hook_event_token_t, hook_data_t, 82 netstack_t *)); 83 static int ipf_hook __P((hook_data_t, int, int, netstack_t *)); 84 extern int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *)); 85 extern int ipf_frruleiter __P((void *, int, void *, ipf_stack_t *)); 86 87 #if SOLARIS2 < 10 88 #if SOLARIS2 >= 7 89 u_int *ip_ttl_ptr = NULL; 90 u_int *ip_mtudisc = NULL; 91 # if SOLARIS2 >= 8 92 int *ip_forwarding = NULL; 93 u_int *ip6_forwarding = NULL; 94 # else 95 u_int *ip_forwarding = NULL; 96 # endif 97 #else 98 u_long *ip_ttl_ptr = NULL; 99 u_long *ip_mtudisc = NULL; 100 u_long *ip_forwarding = NULL; 101 #endif 102 #endif 103 104 105 /* ------------------------------------------------------------------------ */ 106 /* Function: ipldetach */ 107 /* Returns: int - 0 == success, else error. */ 108 /* Parameters: Nil */ 109 /* */ 110 /* This function is responsible for undoing anything that might have been */ 111 /* done in a call to iplattach(). It must be able to clean up from a call */ 112 /* to iplattach() that did not succeed. Why might that happen? Someone */ 113 /* configures a table to be so large that we cannot allocate enough memory */ 114 /* for it. */ 115 /* ------------------------------------------------------------------------ */ 116 int ipldetach(ifs) 117 ipf_stack_t *ifs; 118 { 119 120 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 121 122 #if SOLARIS2 < 10 123 124 if (ifs->ifs_fr_control_forwarding & 2) { 125 if (ip_forwarding != NULL) 126 *ip_forwarding = 0; 127 #if SOLARIS2 >= 8 128 if (ip6_forwarding != NULL) 129 *ip6_forwarding = 0; 130 #endif 131 } 132 #endif 133 134 /* 135 * This lock needs to be dropped around the net_unregister_hook calls 136 * because we can deadlock here with: 137 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 138 * R(hook_family)->R(hei_lock)->R(ipf_global) (active hook running) 139 */ 140 RWLOCK_EXIT(&ifs->ifs_ipf_global); 141 142 /* 143 * Remove IPv6 Hooks 144 */ 145 if (ifs->ifs_ipf_ipv6 != NULL) { 146 if (ifs->ifs_hook6_physical_in) { 147 ifs->ifs_hook6_physical_in = (net_unregister_hook(ifs->ifs_ipf_ipv6, 148 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) != 0); 149 } 150 if (ifs->ifs_hook6_physical_out) { 151 ifs->ifs_hook6_physical_out = 152 (net_unregister_hook(ifs->ifs_ipf_ipv6, 153 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) != 0); 154 } 155 if (ifs->ifs_hook6_nic_events) { 156 ifs->ifs_hook6_nic_events = 157 (net_unregister_hook(ifs->ifs_ipf_ipv6, 158 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 159 } 160 if (ifs->ifs_hook6_loopback_in) { 161 ifs->ifs_hook6_loopback_in = 162 (net_unregister_hook(ifs->ifs_ipf_ipv6, 163 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 164 } 165 if (ifs->ifs_hook6_loopback_out) { 166 ifs->ifs_hook6_loopback_out = 167 (net_unregister_hook(ifs->ifs_ipf_ipv6, 168 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 169 } 170 171 if (net_release(ifs->ifs_ipf_ipv6) != 0) 172 goto detach_failed; 173 ifs->ifs_ipf_ipv6 = NULL; 174 } 175 176 /* 177 * Remove IPv4 Hooks 178 */ 179 if (ifs->ifs_ipf_ipv4 != NULL) { 180 if (ifs->ifs_hook4_physical_in) { 181 ifs->ifs_hook4_physical_in = 182 (net_unregister_hook(ifs->ifs_ipf_ipv4, 183 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) != 0); 184 } 185 if (ifs->ifs_hook4_physical_out) { 186 ifs->ifs_hook4_physical_out = 187 (net_unregister_hook(ifs->ifs_ipf_ipv4, 188 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) != 0); 189 } 190 if (ifs->ifs_hook4_nic_events) { 191 ifs->ifs_hook4_nic_events = 192 (net_unregister_hook(ifs->ifs_ipf_ipv4, 193 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) != 0); 194 } 195 if (ifs->ifs_hook4_loopback_in) { 196 ifs->ifs_hook4_loopback_in = 197 (net_unregister_hook(ifs->ifs_ipf_ipv4, 198 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 199 } 200 if (ifs->ifs_hook4_loopback_out) { 201 ifs->ifs_hook4_loopback_out = 202 (net_unregister_hook(ifs->ifs_ipf_ipv4, 203 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 204 } 205 206 if (net_release(ifs->ifs_ipf_ipv4) != 0) 207 goto detach_failed; 208 ifs->ifs_ipf_ipv4 = NULL; 209 } 210 211 #ifdef IPFDEBUG 212 cmn_err(CE_CONT, "ipldetach()\n"); 213 #endif 214 215 WRITE_ENTER(&ifs->ifs_ipf_global); 216 fr_deinitialise(ifs); 217 218 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 219 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 220 221 if (ifs->ifs_ipf_locks_done == 1) { 222 MUTEX_DESTROY(&ifs->ifs_ipf_timeoutlock); 223 MUTEX_DESTROY(&ifs->ifs_ipf_rw); 224 RW_DESTROY(&ifs->ifs_ipf_tokens); 225 RW_DESTROY(&ifs->ifs_ipf_ipidfrag); 226 ifs->ifs_ipf_locks_done = 0; 227 } 228 229 if (ifs->ifs_hook4_physical_in || ifs->ifs_hook4_physical_out || ifs->ifs_hook4_nic_events || 230 ifs->ifs_hook4_loopback_in || ifs->ifs_hook4_loopback_out || ifs->ifs_hook6_nic_events || 231 ifs->ifs_hook6_physical_in || ifs->ifs_hook6_physical_out || ifs->ifs_hook6_loopback_in || 232 ifs->ifs_hook6_loopback_out) 233 return -1; 234 235 return 0; 236 237 detach_failed: 238 WRITE_ENTER(&ifs->ifs_ipf_global); 239 return -1; 240 } 241 242 int iplattach(ifs, ns) 243 ipf_stack_t *ifs; 244 netstack_t *ns; 245 { 246 #if SOLARIS2 < 10 247 int i; 248 #endif 249 250 #ifdef IPFDEBUG 251 cmn_err(CE_CONT, "iplattach()\n"); 252 #endif 253 254 ASSERT(rw_read_locked(&ifs->ifs_ipf_global.ipf_lk) == 0); 255 ifs->ifs_fr_flags = IPF_LOGGING; 256 #ifdef _KERNEL 257 ifs->ifs_fr_update_ipid = 0; 258 #else 259 ifs->ifs_fr_update_ipid = 1; 260 #endif 261 ifs->ifs_fr_minttl = 4; 262 ifs->ifs_fr_icmpminfragmtu = 68; 263 #if defined(IPFILTER_DEFAULT_BLOCK) 264 ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; 265 #else 266 ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 267 #endif 268 ifs->ifs_ipf_loopback = 0; 269 270 bzero((char *)ifs->ifs_frcache, sizeof(ifs->ifs_frcache)); 271 MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); 272 MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock mutex"); 273 RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 274 RWLOCK_INIT(&ifs->ifs_ipf_tokens, "ipf token rwlock"); 275 ifs->ifs_ipf_locks_done = 1; 276 277 if (fr_initialise(ifs) < 0) 278 return -1; 279 280 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v4, 281 "ipfilter_hook_nicevents"); 282 HOOK_INIT(&ifs->ifs_ipfhook_in, ipf_hook_in, "ipfilter_hook_in"); 283 HOOK_INIT(&ifs->ifs_ipfhook_out, ipf_hook_out, "ipfilter_hook_out"); 284 HOOK_INIT(&ifs->ifs_ipfhook_loop_in, ipf_hook_in, 285 "ipfilter_hook_loop_in"); 286 HOOK_INIT(&ifs->ifs_ipfhook_loop_out, ipf_hook_out, 287 "ipfilter_hook_loop_out"); 288 289 /* 290 * If we hold this lock over all of the net_register_hook calls, we 291 * can cause a deadlock to occur with the following lock ordering: 292 * W(ipf_global)->R(hook_family)->W(hei_lock) (this code path) vs 293 * R(hook_family)->R(hei_lock)->R(ipf_global) (packet path) 294 */ 295 RWLOCK_EXIT(&ifs->ifs_ipf_global); 296 297 /* 298 * Add IPv4 hooks 299 */ 300 ifs->ifs_ipf_ipv4 = net_lookup_impl(NHF_INET, ns); 301 if (ifs->ifs_ipf_ipv4 == NULL) 302 goto hookup_failed; 303 304 ifs->ifs_hook4_nic_events = (net_register_hook(ifs->ifs_ipf_ipv4, 305 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 306 if (!ifs->ifs_hook4_nic_events) 307 goto hookup_failed; 308 309 ifs->ifs_hook4_physical_in = (net_register_hook(ifs->ifs_ipf_ipv4, 310 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 311 if (!ifs->ifs_hook4_physical_in) 312 goto hookup_failed; 313 314 ifs->ifs_hook4_physical_out = (net_register_hook(ifs->ifs_ipf_ipv4, 315 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 316 if (!ifs->ifs_hook4_physical_out) 317 goto hookup_failed; 318 319 if (ifs->ifs_ipf_loopback) { 320 ifs->ifs_hook4_loopback_in = 321 (net_register_hook(ifs->ifs_ipf_ipv4, 322 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 323 if (!ifs->ifs_hook4_loopback_in) 324 goto hookup_failed; 325 326 ifs->ifs_hook4_loopback_out = 327 (net_register_hook(ifs->ifs_ipf_ipv4, 328 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 329 if (!ifs->ifs_hook4_loopback_out) 330 goto hookup_failed; 331 } 332 /* 333 * Add IPv6 hooks 334 */ 335 ifs->ifs_ipf_ipv6 = net_lookup_impl(NHF_INET6, ns); 336 if (ifs->ifs_ipf_ipv6 == NULL) 337 goto hookup_failed; 338 339 HOOK_INIT(&ifs->ifs_ipfhook_nicevents, ipf_nic_event_v6, 340 "ipfilter_hook_nicevents"); 341 ifs->ifs_hook6_nic_events = (net_register_hook(ifs->ifs_ipf_ipv6, 342 NH_NIC_EVENTS, &ifs->ifs_ipfhook_nicevents) == 0); 343 if (!ifs->ifs_hook6_nic_events) 344 goto hookup_failed; 345 346 ifs->ifs_hook6_physical_in = (net_register_hook(ifs->ifs_ipf_ipv6, 347 NH_PHYSICAL_IN, &ifs->ifs_ipfhook_in) == 0); 348 if (!ifs->ifs_hook6_physical_in) 349 goto hookup_failed; 350 351 ifs->ifs_hook6_physical_out = (net_register_hook(ifs->ifs_ipf_ipv6, 352 NH_PHYSICAL_OUT, &ifs->ifs_ipfhook_out) == 0); 353 if (!ifs->ifs_hook6_physical_out) 354 goto hookup_failed; 355 356 if (ifs->ifs_ipf_loopback) { 357 ifs->ifs_hook6_loopback_in = 358 (net_register_hook(ifs->ifs_ipf_ipv6, 359 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 360 if (!ifs->ifs_hook6_loopback_in) 361 goto hookup_failed; 362 363 ifs->ifs_hook6_loopback_out = 364 (net_register_hook(ifs->ifs_ipf_ipv6, 365 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 366 if (!ifs->ifs_hook6_loopback_out) 367 goto hookup_failed; 368 } 369 370 /* 371 * Reacquire ipf_global, now it is safe. 372 */ 373 WRITE_ENTER(&ifs->ifs_ipf_global); 374 375 /* Do not use private interface ip_params_arr[] in Solaris 10 */ 376 #if SOLARIS2 < 10 377 378 #if SOLARIS2 >= 8 379 ip_forwarding = &ip_g_forward; 380 #endif 381 /* 382 * XXX - There is no terminator for this array, so it is not possible 383 * to tell if what we are looking for is missing and go off the end 384 * of the array. 385 */ 386 387 #if SOLARIS2 <= 8 388 for (i = 0; ; i++) { 389 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 390 ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 391 } else if (!strcmp(ip_param_arr[i].ip_param_name, 392 "ip_path_mtu_discovery")) { 393 ip_mtudisc = &ip_param_arr[i].ip_param_value; 394 } 395 #if SOLARIS2 < 8 396 else if (!strcmp(ip_param_arr[i].ip_param_name, 397 "ip_forwarding")) { 398 ip_forwarding = &ip_param_arr[i].ip_param_value; 399 } 400 #else 401 else if (!strcmp(ip_param_arr[i].ip_param_name, 402 "ip6_forwarding")) { 403 ip6_forwarding = &ip_param_arr[i].ip_param_value; 404 } 405 #endif 406 407 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 408 #if SOLARIS2 >= 8 409 ip6_forwarding != NULL && 410 #endif 411 ip_forwarding != NULL) 412 break; 413 } 414 #endif 415 416 if (ifs->ifs_fr_control_forwarding & 1) { 417 if (ip_forwarding != NULL) 418 *ip_forwarding = 1; 419 #if SOLARIS2 >= 8 420 if (ip6_forwarding != NULL) 421 *ip6_forwarding = 1; 422 #endif 423 } 424 425 #endif 426 427 return 0; 428 hookup_failed: 429 WRITE_ENTER(&ifs->ifs_ipf_global); 430 return -1; 431 } 432 433 static int fr_setipfloopback(set, ifs) 434 int set; 435 ipf_stack_t *ifs; 436 { 437 if (ifs->ifs_ipf_ipv4 == NULL || ifs->ifs_ipf_ipv6 == NULL) 438 return EFAULT; 439 440 if (set && !ifs->ifs_ipf_loopback) { 441 ifs->ifs_ipf_loopback = 1; 442 443 ifs->ifs_hook4_loopback_in = 444 (net_register_hook(ifs->ifs_ipf_ipv4, 445 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 446 if (!ifs->ifs_hook4_loopback_in) 447 return EINVAL; 448 449 ifs->ifs_hook4_loopback_out = 450 (net_register_hook(ifs->ifs_ipf_ipv4, 451 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 452 if (!ifs->ifs_hook4_loopback_out) 453 return EINVAL; 454 455 ifs->ifs_hook6_loopback_in = 456 (net_register_hook(ifs->ifs_ipf_ipv6, 457 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) == 0); 458 if (!ifs->ifs_hook6_loopback_in) 459 return EINVAL; 460 461 ifs->ifs_hook6_loopback_out = 462 (net_register_hook(ifs->ifs_ipf_ipv6, 463 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) == 0); 464 if (!ifs->ifs_hook6_loopback_out) 465 return EINVAL; 466 467 } else if (!set && ifs->ifs_ipf_loopback) { 468 ifs->ifs_ipf_loopback = 0; 469 470 ifs->ifs_hook4_loopback_in = 471 (net_unregister_hook(ifs->ifs_ipf_ipv4, 472 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 473 if (ifs->ifs_hook4_loopback_in) 474 return EBUSY; 475 476 ifs->ifs_hook4_loopback_out = 477 (net_unregister_hook(ifs->ifs_ipf_ipv4, 478 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 479 if (ifs->ifs_hook4_loopback_out) 480 return EBUSY; 481 482 ifs->ifs_hook6_loopback_in = 483 (net_unregister_hook(ifs->ifs_ipf_ipv6, 484 NH_LOOPBACK_IN, &ifs->ifs_ipfhook_loop_in) != 0); 485 if (ifs->ifs_hook6_loopback_in) 486 return EBUSY; 487 488 ifs->ifs_hook6_loopback_out = 489 (net_unregister_hook(ifs->ifs_ipf_ipv6, 490 NH_LOOPBACK_OUT, &ifs->ifs_ipfhook_loop_out) != 0); 491 if (ifs->ifs_hook6_loopback_out) 492 return EBUSY; 493 } 494 return 0; 495 } 496 497 498 /* 499 * Filter ioctl interface. 500 */ 501 /*ARGSUSED*/ 502 int iplioctl(dev, cmd, data, mode, cp, rp) 503 dev_t dev; 504 int cmd; 505 #if SOLARIS2 >= 7 506 intptr_t data; 507 #else 508 int *data; 509 #endif 510 int mode; 511 cred_t *cp; 512 int *rp; 513 { 514 int error = 0, tmp; 515 friostat_t fio; 516 minor_t unit; 517 u_int enable; 518 netstack_t *ns; 519 ipf_stack_t *ifs; 520 521 #ifdef IPFDEBUG 522 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 523 dev, cmd, data, mode, cp, rp); 524 #endif 525 unit = getminor(dev); 526 if (IPL_LOGMAX < unit) 527 return ENXIO; 528 529 ns = netstack_find_by_cred(cp); 530 ASSERT(ns != NULL); 531 ifs = ns->netstack_ipf; 532 ASSERT(ifs != NULL); 533 534 if (ifs->ifs_fr_running <= 0) { 535 if (unit != IPL_LOGIPF) { 536 netstack_rele(ifs->ifs_netstack); 537 return EIO; 538 } 539 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 540 cmd != SIOCIPFSET && cmd != SIOCFRENB && 541 cmd != SIOCGETFS && cmd != SIOCGETFF) { 542 netstack_rele(ifs->ifs_netstack); 543 return EIO; 544 } 545 } 546 547 READ_ENTER(&ifs->ifs_ipf_global); 548 549 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode, cp->cr_uid, curproc, ifs); 550 if (error != -1) { 551 RWLOCK_EXIT(&ifs->ifs_ipf_global); 552 netstack_rele(ifs->ifs_netstack); 553 return error; 554 } 555 error = 0; 556 557 switch (cmd) 558 { 559 case SIOCFRENB : 560 if (!(mode & FWRITE)) 561 error = EPERM; 562 else { 563 error = COPYIN((caddr_t)data, (caddr_t)&enable, 564 sizeof(enable)); 565 if (error != 0) { 566 error = EFAULT; 567 break; 568 } 569 570 RWLOCK_EXIT(&ifs->ifs_ipf_global); 571 WRITE_ENTER(&ifs->ifs_ipf_global); 572 if (enable) { 573 if (ifs->ifs_fr_running > 0) 574 error = 0; 575 else 576 error = iplattach(ifs, ns); 577 if (error == 0) 578 ifs->ifs_fr_running = 1; 579 else 580 (void) ipldetach(ifs); 581 } else { 582 error = ipldetach(ifs); 583 if (error == 0) 584 ifs->ifs_fr_running = -1; 585 } 586 } 587 break; 588 case SIOCIPFSET : 589 if (!(mode & FWRITE)) { 590 error = EPERM; 591 break; 592 } 593 /* FALLTHRU */ 594 case SIOCIPFGETNEXT : 595 case SIOCIPFGET : 596 error = fr_ipftune(cmd, (void *)data, ifs); 597 break; 598 case SIOCSETFF : 599 if (!(mode & FWRITE)) 600 error = EPERM; 601 else { 602 error = COPYIN((caddr_t)data, (caddr_t)&ifs->ifs_fr_flags, 603 sizeof(ifs->ifs_fr_flags)); 604 if (error != 0) 605 error = EFAULT; 606 } 607 break; 608 case SIOCIPFLP : 609 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 610 sizeof(tmp)); 611 if (error != 0) 612 error = EFAULT; 613 else 614 error = fr_setipfloopback(tmp, ifs); 615 break; 616 case SIOCGETFF : 617 error = COPYOUT((caddr_t)&ifs->ifs_fr_flags, (caddr_t)data, 618 sizeof(ifs->ifs_fr_flags)); 619 if (error != 0) 620 error = EFAULT; 621 break; 622 case SIOCFUNCL : 623 error = fr_resolvefunc((void *)data); 624 break; 625 case SIOCINAFR : 626 case SIOCRMAFR : 627 case SIOCADAFR : 628 case SIOCZRLST : 629 if (!(mode & FWRITE)) 630 error = EPERM; 631 else 632 error = frrequest(unit, cmd, (caddr_t)data, 633 ifs->ifs_fr_active, 1, ifs); 634 break; 635 case SIOCINIFR : 636 case SIOCRMIFR : 637 case SIOCADIFR : 638 if (!(mode & FWRITE)) 639 error = EPERM; 640 else 641 error = frrequest(unit, cmd, (caddr_t)data, 642 1 - ifs->ifs_fr_active, 1, ifs); 643 break; 644 case SIOCSWAPA : 645 if (!(mode & FWRITE)) 646 error = EPERM; 647 else { 648 WRITE_ENTER(&ifs->ifs_ipf_mutex); 649 /* Clear one fourth of the table */ 650 bzero((char *)&ifs->ifs_frcache, 651 sizeof (ifs->ifs_frcache[0]) * 2); 652 error = COPYOUT((caddr_t)&ifs->ifs_fr_active, 653 (caddr_t)data, 654 sizeof(ifs->ifs_fr_active)); 655 if (error != 0) 656 error = EFAULT; 657 else 658 ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; 659 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 660 } 661 break; 662 case SIOCGETFS : 663 fr_getstat(&fio, ifs); 664 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 665 break; 666 case SIOCFRZST : 667 if (!(mode & FWRITE)) 668 error = EPERM; 669 else 670 error = fr_zerostats((caddr_t)data, ifs); 671 break; 672 case SIOCIPFFL : 673 if (!(mode & FWRITE)) 674 error = EPERM; 675 else { 676 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 677 sizeof(tmp)); 678 if (!error) { 679 tmp = frflush(unit, 4, tmp, ifs); 680 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 681 sizeof(tmp)); 682 if (error != 0) 683 error = EFAULT; 684 } else 685 error = EFAULT; 686 } 687 break; 688 #ifdef USE_INET6 689 case SIOCIPFL6 : 690 if (!(mode & FWRITE)) 691 error = EPERM; 692 else { 693 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 694 sizeof(tmp)); 695 if (!error) { 696 tmp = frflush(unit, 6, tmp, ifs); 697 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 698 sizeof(tmp)); 699 if (error != 0) 700 error = EFAULT; 701 } else 702 error = EFAULT; 703 } 704 break; 705 #endif 706 case SIOCSTLCK : 707 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 708 if (error == 0) { 709 ifs->ifs_fr_state_lock = tmp; 710 ifs->ifs_fr_nat_lock = tmp; 711 ifs->ifs_fr_frag_lock = tmp; 712 ifs->ifs_fr_auth_lock = tmp; 713 } else 714 error = EFAULT; 715 break; 716 #ifdef IPFILTER_LOG 717 case SIOCIPFFB : 718 if (!(mode & FWRITE)) 719 error = EPERM; 720 else { 721 tmp = ipflog_clear(unit, ifs); 722 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 723 sizeof(tmp)); 724 if (error) 725 error = EFAULT; 726 } 727 break; 728 #endif /* IPFILTER_LOG */ 729 case SIOCFRSYN : 730 if (!(mode & FWRITE)) 731 error = EPERM; 732 else { 733 RWLOCK_EXIT(&ifs->ifs_ipf_global); 734 WRITE_ENTER(&ifs->ifs_ipf_global); 735 736 frsync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 737 fr_natifpsync(IPFSYNC_RESYNC, NULL, NULL, ifs); 738 fr_nataddrsync(NULL, NULL, ifs); 739 fr_statesync(IPFSYNC_RESYNC, 0, NULL, NULL, ifs); 740 error = 0; 741 } 742 break; 743 case SIOCGFRST : 744 error = fr_outobj((void *)data, fr_fragstats(ifs), 745 IPFOBJ_FRAGSTAT); 746 break; 747 case FIONREAD : 748 #ifdef IPFILTER_LOG 749 tmp = (int)ifs->ifs_iplused[IPL_LOGIPF]; 750 751 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 752 if (error != 0) 753 error = EFAULT; 754 #endif 755 break; 756 case SIOCIPFITER : 757 error = ipf_frruleiter((caddr_t)data, cp->cr_uid, curproc, ifs); 758 break; 759 760 case SIOCGENITER : 761 error = ipf_genericiter((caddr_t)data, cp->cr_uid, curproc, ifs); 762 break; 763 764 case SIOCIPFDELTOK : 765 (void)BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 766 error = ipf_deltoken(tmp, cp->cr_uid, curproc, ifs); 767 break; 768 769 default : 770 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 771 error = EINVAL; 772 break; 773 } 774 RWLOCK_EXIT(&ifs->ifs_ipf_global); 775 netstack_rele(ifs->ifs_netstack); 776 return error; 777 } 778 779 780 phy_if_t get_unit(name, v, ifs) 781 char *name; 782 int v; 783 ipf_stack_t *ifs; 784 { 785 net_data_t nif; 786 787 if (v == 4) 788 nif = ifs->ifs_ipf_ipv4; 789 else if (v == 6) 790 nif = ifs->ifs_ipf_ipv6; 791 else 792 return 0; 793 794 nif->netd_netstack = ifs->ifs_netstack; 795 796 return (net_phylookup(nif, name)); 797 } 798 799 /* 800 * routines below for saving IP headers to buffer 801 */ 802 /*ARGSUSED*/ 803 int iplopen(devp, flags, otype, cred) 804 dev_t *devp; 805 int flags, otype; 806 cred_t *cred; 807 { 808 minor_t min = getminor(*devp); 809 810 #ifdef IPFDEBUG 811 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 812 #endif 813 if (!(otype & OTYP_CHR)) 814 return ENXIO; 815 816 min = (IPL_LOGMAX < min) ? ENXIO : 0; 817 return min; 818 } 819 820 821 /*ARGSUSED*/ 822 int iplclose(dev, flags, otype, cred) 823 dev_t dev; 824 int flags, otype; 825 cred_t *cred; 826 { 827 minor_t min = getminor(dev); 828 829 #ifdef IPFDEBUG 830 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 831 #endif 832 833 min = (IPL_LOGMAX < min) ? ENXIO : 0; 834 return min; 835 } 836 837 #ifdef IPFILTER_LOG 838 /* 839 * iplread/ipllog 840 * both of these must operate with at least splnet() lest they be 841 * called during packet processing and cause an inconsistancy to appear in 842 * the filter lists. 843 */ 844 /*ARGSUSED*/ 845 int iplread(dev, uio, cp) 846 dev_t dev; 847 register struct uio *uio; 848 cred_t *cp; 849 { 850 netstack_t *ns; 851 ipf_stack_t *ifs; 852 int ret; 853 854 ns = netstack_find_by_cred(cp); 855 ASSERT(ns != NULL); 856 ifs = ns->netstack_ipf; 857 ASSERT(ifs != NULL); 858 859 # ifdef IPFDEBUG 860 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 861 # endif 862 863 if (ifs->ifs_fr_running < 1) { 864 netstack_rele(ifs->ifs_netstack); 865 return EIO; 866 } 867 868 # ifdef IPFILTER_SYNC 869 if (getminor(dev) == IPL_LOGSYNC) { 870 netstack_rele(ifs->ifs_netstack); 871 return ipfsync_read(uio); 872 } 873 # endif 874 875 ret = ipflog_read(getminor(dev), uio, ifs); 876 netstack_rele(ifs->ifs_netstack); 877 return ret; 878 } 879 #endif /* IPFILTER_LOG */ 880 881 882 /* 883 * iplread/ipllog 884 * both of these must operate with at least splnet() lest they be 885 * called during packet processing and cause an inconsistancy to appear in 886 * the filter lists. 887 */ 888 int iplwrite(dev, uio, cp) 889 dev_t dev; 890 register struct uio *uio; 891 cred_t *cp; 892 { 893 netstack_t *ns; 894 ipf_stack_t *ifs; 895 896 ns = netstack_find_by_cred(cp); 897 ASSERT(ns != NULL); 898 ifs = ns->netstack_ipf; 899 ASSERT(ifs != NULL); 900 901 #ifdef IPFDEBUG 902 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 903 #endif 904 905 if (ifs->ifs_fr_running < 1) { 906 netstack_rele(ifs->ifs_netstack); 907 return EIO; 908 } 909 910 #ifdef IPFILTER_SYNC 911 if (getminor(dev) == IPL_LOGSYNC) 912 return ipfsync_write(uio); 913 #endif /* IPFILTER_SYNC */ 914 dev = dev; /* LINT */ 915 uio = uio; /* LINT */ 916 cp = cp; /* LINT */ 917 netstack_rele(ifs->ifs_netstack); 918 return ENXIO; 919 } 920 921 922 /* 923 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 924 * requires a large amount of setting up and isn't any more efficient. 925 */ 926 int fr_send_reset(fin) 927 fr_info_t *fin; 928 { 929 tcphdr_t *tcp, *tcp2; 930 int tlen, hlen; 931 mblk_t *m; 932 #ifdef USE_INET6 933 ip6_t *ip6; 934 #endif 935 ip_t *ip; 936 937 tcp = fin->fin_dp; 938 if (tcp->th_flags & TH_RST) 939 return -1; 940 941 #ifndef IPFILTER_CKSUM 942 if (fr_checkl4sum(fin) == -1) 943 return -1; 944 #endif 945 946 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 947 #ifdef USE_INET6 948 if (fin->fin_v == 6) 949 hlen = sizeof(ip6_t); 950 else 951 #endif 952 hlen = sizeof(ip_t); 953 hlen += sizeof(*tcp2); 954 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 955 return -1; 956 957 m->b_rptr += 64; 958 MTYPE(m) = M_DATA; 959 m->b_wptr = m->b_rptr + hlen; 960 ip = (ip_t *)m->b_rptr; 961 bzero((char *)ip, hlen); 962 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 963 tcp2->th_dport = tcp->th_sport; 964 tcp2->th_sport = tcp->th_dport; 965 if (tcp->th_flags & TH_ACK) { 966 tcp2->th_seq = tcp->th_ack; 967 tcp2->th_flags = TH_RST; 968 } else { 969 tcp2->th_ack = ntohl(tcp->th_seq); 970 tcp2->th_ack += tlen; 971 tcp2->th_ack = htonl(tcp2->th_ack); 972 tcp2->th_flags = TH_RST|TH_ACK; 973 } 974 tcp2->th_off = sizeof(struct tcphdr) >> 2; 975 976 ip->ip_v = fin->fin_v; 977 #ifdef USE_INET6 978 if (fin->fin_v == 6) { 979 ip6 = (ip6_t *)m->b_rptr; 980 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 981 ip6->ip6_src = fin->fin_dst6; 982 ip6->ip6_dst = fin->fin_src6; 983 ip6->ip6_plen = htons(sizeof(*tcp)); 984 ip6->ip6_nxt = IPPROTO_TCP; 985 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 986 } else 987 #endif 988 { 989 ip->ip_src.s_addr = fin->fin_daddr; 990 ip->ip_dst.s_addr = fin->fin_saddr; 991 ip->ip_id = fr_nextipid(fin); 992 ip->ip_hl = sizeof(*ip) >> 2; 993 ip->ip_p = IPPROTO_TCP; 994 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 995 ip->ip_tos = fin->fin_ip->ip_tos; 996 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 997 } 998 return fr_send_ip(fin, m, &m); 999 } 1000 1001 /* 1002 * Function: fr_send_ip 1003 * Returns: 0: success 1004 * -1: failed 1005 * Parameters: 1006 * fin: packet information 1007 * m: the message block where ip head starts 1008 * 1009 * Send a new packet through the IP stack. 1010 * 1011 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 1012 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 1013 * function). 1014 * 1015 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 1016 * in by this function. 1017 * 1018 * All other portions of the packet must be in on-the-wire format. 1019 */ 1020 /*ARGSUSED*/ 1021 static int fr_send_ip(fin, m, mpp) 1022 fr_info_t *fin; 1023 mblk_t *m, **mpp; 1024 { 1025 qpktinfo_t qpi, *qpip; 1026 fr_info_t fnew; 1027 ip_t *ip; 1028 int i, hlen; 1029 ipf_stack_t *ifs = fin->fin_ifs; 1030 1031 ip = (ip_t *)m->b_rptr; 1032 bzero((char *)&fnew, sizeof(fnew)); 1033 1034 #ifdef USE_INET6 1035 if (fin->fin_v == 6) { 1036 ip6_t *ip6; 1037 1038 ip6 = (ip6_t *)ip; 1039 ip6->ip6_vfc = 0x60; 1040 ip6->ip6_hlim = 127; 1041 fnew.fin_v = 6; 1042 hlen = sizeof(*ip6); 1043 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 1044 } else 1045 #endif 1046 { 1047 fnew.fin_v = 4; 1048 #if SOLARIS2 >= 10 1049 ip->ip_ttl = 255; 1050 if (net_getpmtuenabled(ifs->ifs_ipf_ipv4) == 1) 1051 ip->ip_off = htons(IP_DF); 1052 #else 1053 if (ip_ttl_ptr != NULL) 1054 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 1055 else 1056 ip->ip_ttl = 63; 1057 if (ip_mtudisc != NULL) 1058 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 1059 else 1060 ip->ip_off = htons(IP_DF); 1061 #endif 1062 /* 1063 * The dance with byte order and ip_len/ip_off is because in 1064 * fr_fastroute, it expects them to be in host byte order but 1065 * ipf_cksum expects them to be in network byte order. 1066 */ 1067 ip->ip_len = htons(ip->ip_len); 1068 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 1069 ip->ip_len = ntohs(ip->ip_len); 1070 ip->ip_off = ntohs(ip->ip_off); 1071 hlen = sizeof(*ip); 1072 fnew.fin_plen = ip->ip_len; 1073 } 1074 1075 qpip = fin->fin_qpi; 1076 qpi.qpi_off = 0; 1077 qpi.qpi_ill = qpip->qpi_ill; 1078 qpi.qpi_m = m; 1079 qpi.qpi_data = ip; 1080 fnew.fin_qpi = &qpi; 1081 fnew.fin_ifp = fin->fin_ifp; 1082 fnew.fin_flx = FI_NOCKSUM; 1083 fnew.fin_m = m; 1084 fnew.fin_ip = ip; 1085 fnew.fin_mp = mpp; 1086 fnew.fin_hlen = hlen; 1087 fnew.fin_dp = (char *)ip + hlen; 1088 fnew.fin_ifs = fin->fin_ifs; 1089 (void) fr_makefrip(hlen, ip, &fnew); 1090 1091 i = fr_fastroute(m, mpp, &fnew, NULL); 1092 return i; 1093 } 1094 1095 1096 int fr_send_icmp_err(type, fin, dst) 1097 int type; 1098 fr_info_t *fin; 1099 int dst; 1100 { 1101 struct in_addr dst4; 1102 struct icmp *icmp; 1103 qpktinfo_t *qpi; 1104 int hlen, code; 1105 phy_if_t phy; 1106 u_short sz; 1107 #ifdef USE_INET6 1108 mblk_t *mb; 1109 #endif 1110 mblk_t *m; 1111 #ifdef USE_INET6 1112 ip6_t *ip6; 1113 #endif 1114 ip_t *ip; 1115 ipf_stack_t *ifs = fin->fin_ifs; 1116 1117 if ((type < 0) || (type > ICMP_MAXTYPE)) 1118 return -1; 1119 1120 code = fin->fin_icode; 1121 #ifdef USE_INET6 1122 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 1123 return -1; 1124 #endif 1125 1126 #ifndef IPFILTER_CKSUM 1127 if (fr_checkl4sum(fin) == -1) 1128 return -1; 1129 #endif 1130 1131 qpi = fin->fin_qpi; 1132 1133 #ifdef USE_INET6 1134 mb = fin->fin_qfm; 1135 1136 if (fin->fin_v == 6) { 1137 sz = sizeof(ip6_t); 1138 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 1139 hlen = sizeof(ip6_t); 1140 type = icmptoicmp6types[type]; 1141 if (type == ICMP6_DST_UNREACH) 1142 code = icmptoicmp6unreach[code]; 1143 } else 1144 #endif 1145 { 1146 if ((fin->fin_p == IPPROTO_ICMP) && 1147 !(fin->fin_flx & FI_SHORT)) 1148 switch (ntohs(fin->fin_data[0]) >> 8) 1149 { 1150 case ICMP_ECHO : 1151 case ICMP_TSTAMP : 1152 case ICMP_IREQ : 1153 case ICMP_MASKREQ : 1154 break; 1155 default : 1156 return 0; 1157 } 1158 1159 sz = sizeof(ip_t) * 2; 1160 sz += 8; /* 64 bits of data */ 1161 hlen = sizeof(ip_t); 1162 } 1163 1164 sz += offsetof(struct icmp, icmp_ip); 1165 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 1166 return -1; 1167 MTYPE(m) = M_DATA; 1168 m->b_rptr += 64; 1169 m->b_wptr = m->b_rptr + sz; 1170 bzero((char *)m->b_rptr, (size_t)sz); 1171 ip = (ip_t *)m->b_rptr; 1172 ip->ip_v = fin->fin_v; 1173 icmp = (struct icmp *)(m->b_rptr + hlen); 1174 icmp->icmp_type = type & 0xff; 1175 icmp->icmp_code = code & 0xff; 1176 phy = (phy_if_t)qpi->qpi_ill; 1177 if (type == ICMP_UNREACH && (phy != 0) && 1178 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 1179 icmp->icmp_nextmtu = net_getmtu(ifs->ifs_ipf_ipv4, phy,0 ); 1180 1181 #ifdef USE_INET6 1182 if (fin->fin_v == 6) { 1183 struct in6_addr dst6; 1184 int csz; 1185 1186 if (dst == 0) { 1187 ipf_stack_t *ifs = fin->fin_ifs; 1188 1189 if (fr_ifpaddr(6, FRI_NORMAL, (void *)phy, 1190 (void *)&dst6, NULL, ifs) == -1) { 1191 FREE_MB_T(m); 1192 return -1; 1193 } 1194 } else 1195 dst6 = fin->fin_dst6; 1196 1197 csz = sz; 1198 sz -= sizeof(ip6_t); 1199 ip6 = (ip6_t *)m->b_rptr; 1200 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 1201 ip6->ip6_plen = htons((u_short)sz); 1202 ip6->ip6_nxt = IPPROTO_ICMPV6; 1203 ip6->ip6_src = dst6; 1204 ip6->ip6_dst = fin->fin_src6; 1205 sz -= offsetof(struct icmp, icmp_ip); 1206 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 1207 icmp->icmp_cksum = csz - sizeof(ip6_t); 1208 } else 1209 #endif 1210 { 1211 ip->ip_hl = sizeof(*ip) >> 2; 1212 ip->ip_p = IPPROTO_ICMP; 1213 ip->ip_id = fin->fin_ip->ip_id; 1214 ip->ip_tos = fin->fin_ip->ip_tos; 1215 ip->ip_len = (u_short)sz; 1216 if (dst == 0) { 1217 ipf_stack_t *ifs = fin->fin_ifs; 1218 1219 if (fr_ifpaddr(4, FRI_NORMAL, (void *)phy, 1220 (void *)&dst4, NULL, ifs) == -1) { 1221 FREE_MB_T(m); 1222 return -1; 1223 } 1224 } else { 1225 dst4 = fin->fin_dst; 1226 } 1227 ip->ip_src = dst4; 1228 ip->ip_dst = fin->fin_src; 1229 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 1230 sizeof(*fin->fin_ip)); 1231 bcopy((char *)fin->fin_ip + fin->fin_hlen, 1232 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 1233 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 1234 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 1235 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 1236 sz - sizeof(ip_t)); 1237 } 1238 1239 /* 1240 * Need to exit out of these so we don't recursively call rw_enter 1241 * from fr_qout. 1242 */ 1243 return fr_send_ip(fin, m, &m); 1244 } 1245 1246 #include <sys/time.h> 1247 #include <sys/varargs.h> 1248 1249 #ifndef _KERNEL 1250 #include <stdio.h> 1251 #endif 1252 1253 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 1254 1255 1256 /* 1257 * Print out warning message at rate-limited speed. 1258 */ 1259 static void rate_limit_message(ipf_stack_t *ifs, 1260 int rate, const char *message, ...) 1261 { 1262 static time_t last_time = 0; 1263 time_t now; 1264 va_list args; 1265 char msg_buf[256]; 1266 int need_printed = 0; 1267 1268 now = ddi_get_time(); 1269 1270 /* make sure, no multiple entries */ 1271 ASSERT(MUTEX_NOT_HELD(&(ifs->ifs_ipf_rw.ipf_lk))); 1272 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1273 if (now - last_time >= rate) { 1274 need_printed = 1; 1275 last_time = now; 1276 } 1277 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1278 1279 if (need_printed) { 1280 va_start(args, message); 1281 (void)vsnprintf(msg_buf, 255, message, args); 1282 va_end(args); 1283 #ifdef _KERNEL 1284 cmn_err(CE_WARN, msg_buf); 1285 #else 1286 fprintf(std_err, msg_buf); 1287 #endif 1288 } 1289 } 1290 1291 /* 1292 * return the first IP Address associated with an interface 1293 */ 1294 /*ARGSUSED*/ 1295 int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) 1296 int v, atype; 1297 void *ifptr; 1298 struct in_addr *inp, *inpmask; 1299 ipf_stack_t *ifs; 1300 { 1301 struct sockaddr_in6 v6addr[2]; 1302 struct sockaddr_in v4addr[2]; 1303 net_ifaddr_t type[2]; 1304 net_data_t net_data; 1305 phy_if_t phyif; 1306 void *array; 1307 1308 switch (v) 1309 { 1310 case 4: 1311 net_data = ifs->ifs_ipf_ipv4; 1312 array = v4addr; 1313 break; 1314 case 6: 1315 net_data = ifs->ifs_ipf_ipv6; 1316 array = v6addr; 1317 break; 1318 default: 1319 net_data = NULL; 1320 break; 1321 } 1322 1323 if (net_data == NULL) 1324 return -1; 1325 1326 phyif = (phy_if_t)ifptr; 1327 1328 switch (atype) 1329 { 1330 case FRI_PEERADDR : 1331 type[0] = NA_PEER; 1332 break; 1333 1334 case FRI_BROADCAST : 1335 type[0] = NA_BROADCAST; 1336 break; 1337 1338 default : 1339 type[0] = NA_ADDRESS; 1340 break; 1341 } 1342 1343 type[1] = NA_NETMASK; 1344 1345 if (net_getlifaddr(net_data, phyif, 0, 2, type, array) < 0) 1346 return -1; 1347 1348 if (v == 6) { 1349 return fr_ifpfillv6addr(atype, &v6addr[0], &v6addr[1], 1350 inp, inpmask); 1351 } 1352 return fr_ifpfillv4addr(atype, &v4addr[0], &v4addr[1], inp, inpmask); 1353 } 1354 1355 1356 u_32_t fr_newisn(fin) 1357 fr_info_t *fin; 1358 { 1359 static int iss_seq_off = 0; 1360 u_char hash[16]; 1361 u_32_t newiss; 1362 MD5_CTX ctx; 1363 ipf_stack_t *ifs = fin->fin_ifs; 1364 1365 /* 1366 * Compute the base value of the ISS. It is a hash 1367 * of (saddr, sport, daddr, dport, secret). 1368 */ 1369 MD5Init(&ctx); 1370 1371 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1372 sizeof(fin->fin_fi.fi_src)); 1373 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1374 sizeof(fin->fin_fi.fi_dst)); 1375 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1376 1377 MD5Update(&ctx, ifs->ifs_ipf_iss_secret, sizeof(ifs->ifs_ipf_iss_secret)); 1378 1379 MD5Final(hash, &ctx); 1380 1381 bcopy(hash, &newiss, sizeof(newiss)); 1382 1383 /* 1384 * Now increment our "timer", and add it in to 1385 * the computed value. 1386 * 1387 * XXX Use `addin'? 1388 * XXX TCP_ISSINCR too large to use? 1389 */ 1390 iss_seq_off += 0x00010000; 1391 newiss += iss_seq_off; 1392 return newiss; 1393 } 1394 1395 1396 /* ------------------------------------------------------------------------ */ 1397 /* Function: fr_nextipid */ 1398 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1399 /* Parameters: fin(I) - pointer to packet information */ 1400 /* */ 1401 /* Returns the next IPv4 ID to use for this packet. */ 1402 /* ------------------------------------------------------------------------ */ 1403 u_short fr_nextipid(fin) 1404 fr_info_t *fin; 1405 { 1406 static u_short ipid = 0; 1407 ipstate_t *is; 1408 nat_t *nat; 1409 u_short id; 1410 ipf_stack_t *ifs = fin->fin_ifs; 1411 1412 MUTEX_ENTER(&ifs->ifs_ipf_rw); 1413 if (fin->fin_state != NULL) { 1414 is = fin->fin_state; 1415 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1416 } else if (fin->fin_nat != NULL) { 1417 nat = fin->fin_nat; 1418 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1419 } else 1420 id = ipid++; 1421 MUTEX_EXIT(&ifs->ifs_ipf_rw); 1422 1423 return id; 1424 } 1425 1426 1427 #ifndef IPFILTER_CKSUM 1428 /* ARGSUSED */ 1429 #endif 1430 INLINE void fr_checkv4sum(fin) 1431 fr_info_t *fin; 1432 { 1433 #ifdef IPFILTER_CKSUM 1434 if (fr_checkl4sum(fin) == -1) 1435 fin->fin_flx |= FI_BAD; 1436 #endif 1437 } 1438 1439 1440 #ifdef USE_INET6 1441 # ifndef IPFILTER_CKSUM 1442 /* ARGSUSED */ 1443 # endif 1444 INLINE void fr_checkv6sum(fin) 1445 fr_info_t *fin; 1446 { 1447 # ifdef IPFILTER_CKSUM 1448 if (fr_checkl4sum(fin) == -1) 1449 fin->fin_flx |= FI_BAD; 1450 # endif 1451 } 1452 #endif /* USE_INET6 */ 1453 1454 1455 #if (SOLARIS2 < 7) 1456 void fr_slowtimer() 1457 #else 1458 /*ARGSUSED*/ 1459 void fr_slowtimer __P((void *arg)) 1460 #endif 1461 { 1462 ipf_stack_t *ifs = arg; 1463 1464 WRITE_ENTER(&ifs->ifs_ipf_global); 1465 if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 0) { 1466 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, drv_usectohz(500000)); 1467 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1468 return; 1469 } 1470 MUTEX_DOWNGRADE(&ifs->ifs_ipf_global); 1471 1472 fr_fragexpire(ifs); 1473 fr_timeoutstate(ifs); 1474 fr_natexpire(ifs); 1475 fr_authexpire(ifs); 1476 ifs->ifs_fr_ticks++; 1477 if (ifs->ifs_fr_running == -1 || ifs->ifs_fr_running == 1) 1478 ifs->ifs_fr_timer_id = timeout(fr_slowtimer, arg, 1479 drv_usectohz(500000)); 1480 else 1481 ifs->ifs_fr_timer_id = NULL; 1482 RWLOCK_EXIT(&ifs->ifs_ipf_global); 1483 } 1484 1485 1486 /* ------------------------------------------------------------------------ */ 1487 /* Function: fr_pullup */ 1488 /* Returns: NULL == pullup failed, else pointer to protocol header */ 1489 /* Parameters: m(I) - pointer to buffer where data packet starts */ 1490 /* fin(I) - pointer to packet information */ 1491 /* len(I) - number of bytes to pullup */ 1492 /* */ 1493 /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1494 /* single buffer for ease of access. Operating system native functions are */ 1495 /* used to manage buffers - if necessary. If the entire packet ends up in */ 1496 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1497 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1498 /* and ONLY if the pullup succeeds. */ 1499 /* */ 1500 /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1501 /* of buffers that starts at *fin->fin_mp. */ 1502 /* ------------------------------------------------------------------------ */ 1503 void *fr_pullup(min, fin, len) 1504 mb_t *min; 1505 fr_info_t *fin; 1506 int len; 1507 { 1508 qpktinfo_t *qpi = fin->fin_qpi; 1509 int out = fin->fin_out, dpoff, ipoff; 1510 mb_t *m = min, *m1, *m2; 1511 char *ip; 1512 uint32_t start, stuff, end, value, flags; 1513 ipf_stack_t *ifs = fin->fin_ifs; 1514 1515 if (m == NULL) 1516 return NULL; 1517 1518 ip = (char *)fin->fin_ip; 1519 if ((fin->fin_flx & FI_COALESCE) != 0) 1520 return ip; 1521 1522 ipoff = fin->fin_ipoff; 1523 if (fin->fin_dp != NULL) 1524 dpoff = (char *)fin->fin_dp - (char *)ip; 1525 else 1526 dpoff = 0; 1527 1528 if (M_LEN(m) < len) { 1529 1530 /* 1531 * pfil_precheck ensures the IP header is on a 32bit 1532 * aligned address so simply fail if that isn't currently 1533 * the case (should never happen). 1534 */ 1535 int inc = 0; 1536 1537 if (ipoff > 0) { 1538 if ((ipoff & 3) != 0) { 1539 inc = 4 - (ipoff & 3); 1540 if (m->b_rptr - inc >= m->b_datap->db_base) 1541 m->b_rptr -= inc; 1542 else 1543 inc = 0; 1544 } 1545 } 1546 1547 /* 1548 * XXX This is here as a work around for a bug with DEBUG 1549 * XXX Solaris kernels. The problem is b_prev is used by IP 1550 * XXX code as a way to stash the phyint_index for a packet, 1551 * XXX this doesn't get reset by IP but freeb does an ASSERT() 1552 * XXX for both of these to be NULL. See 6442390. 1553 */ 1554 m1 = m; 1555 m2 = m->b_prev; 1556 1557 do { 1558 m1->b_next = NULL; 1559 m1->b_prev = NULL; 1560 m1 = m1->b_cont; 1561 } while (m1); 1562 1563 /* 1564 * Need to preserve checksum information by copying them 1565 * to newmp which heads the pulluped message. 1566 */ 1567 hcksum_retrieve(m, NULL, NULL, &start, &stuff, &end, 1568 &value, &flags); 1569 1570 if (pullupmsg(m, len + ipoff + inc) == 0) { 1571 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[1]); 1572 FREE_MB_T(*fin->fin_mp); 1573 *fin->fin_mp = NULL; 1574 fin->fin_m = NULL; 1575 fin->fin_ip = NULL; 1576 fin->fin_dp = NULL; 1577 qpi->qpi_data = NULL; 1578 return NULL; 1579 } 1580 1581 (void) hcksum_assoc(m, NULL, NULL, start, stuff, end, 1582 value, flags, 0); 1583 1584 m->b_prev = m2; 1585 m->b_rptr += inc; 1586 fin->fin_m = m; 1587 ip = MTOD(m, char *) + ipoff; 1588 qpi->qpi_data = ip; 1589 } 1590 1591 ATOMIC_INCL(ifs->ifs_frstats[out].fr_pull[0]); 1592 fin->fin_ip = (ip_t *)ip; 1593 if (fin->fin_dp != NULL) 1594 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1595 1596 if (len == fin->fin_plen) 1597 fin->fin_flx |= FI_COALESCE; 1598 return ip; 1599 } 1600 1601 1602 /* 1603 * Function: fr_verifysrc 1604 * Returns: int (really boolean) 1605 * Parameters: fin - packet information 1606 * 1607 * Check whether the packet has a valid source address for the interface on 1608 * which the packet arrived, implementing the "fr_chksrc" feature. 1609 * Returns true iff the packet's source address is valid. 1610 */ 1611 int fr_verifysrc(fin) 1612 fr_info_t *fin; 1613 { 1614 net_data_t net_data_p; 1615 phy_if_t phy_ifdata_routeto; 1616 struct sockaddr sin; 1617 ipf_stack_t *ifs = fin->fin_ifs; 1618 1619 if (fin->fin_v == 4) { 1620 net_data_p = ifs->ifs_ipf_ipv4; 1621 } else if (fin->fin_v == 6) { 1622 net_data_p = ifs->ifs_ipf_ipv6; 1623 } else { 1624 return (0); 1625 } 1626 1627 /* Get the index corresponding to the if name */ 1628 sin.sa_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1629 bcopy(&fin->fin_saddr, &sin.sa_data, sizeof (struct in_addr)); 1630 phy_ifdata_routeto = net_routeto(net_data_p, &sin); 1631 1632 return (((phy_if_t)fin->fin_ifp == phy_ifdata_routeto) ? 1 : 0); 1633 } 1634 1635 1636 /* 1637 * Function: fr_fastroute 1638 * Returns: 0: success; 1639 * -1: failed 1640 * Parameters: 1641 * mb: the message block where ip head starts 1642 * mpp: the pointer to the pointer of the orignal 1643 * packet message 1644 * fin: packet information 1645 * fdp: destination interface information 1646 * if it is NULL, no interface information provided. 1647 * 1648 * This function is for fastroute/to/dup-to rules. It calls 1649 * pfil_make_lay2_packet to search route, make lay-2 header 1650 * ,and identify output queue for the IP packet. 1651 * The destination address depends on the following conditions: 1652 * 1: for fastroute rule, fdp is passed in as NULL, so the 1653 * destination address is the IP Packet's destination address 1654 * 2: for to/dup-to rule, if an ip address is specified after 1655 * the interface name, this address is the as destination 1656 * address. Otherwise IP Packet's destination address is used 1657 */ 1658 int fr_fastroute(mb, mpp, fin, fdp) 1659 mblk_t *mb, **mpp; 1660 fr_info_t *fin; 1661 frdest_t *fdp; 1662 { 1663 net_data_t net_data_p; 1664 net_inject_t inj_data; 1665 mblk_t *mp = NULL; 1666 frentry_t *fr = fin->fin_fr; 1667 qpktinfo_t *qpi; 1668 ip_t *ip; 1669 1670 struct sockaddr_in *sin; 1671 struct sockaddr_in6 *sin6; 1672 struct sockaddr *sinp; 1673 ipf_stack_t *ifs = fin->fin_ifs; 1674 #ifndef sparc 1675 u_short __iplen, __ipoff; 1676 #endif 1677 1678 if (fin->fin_v == 4) { 1679 net_data_p = ifs->ifs_ipf_ipv4; 1680 } else if (fin->fin_v == 6) { 1681 net_data_p = ifs->ifs_ipf_ipv6; 1682 } else { 1683 return (-1); 1684 } 1685 1686 ip = fin->fin_ip; 1687 qpi = fin->fin_qpi; 1688 1689 /* 1690 * If this is a duplicate mblk then we want ip to point at that 1691 * data, not the original, if and only if it is already pointing at 1692 * the current mblk data. 1693 * 1694 * Otherwise, if it's not a duplicate, and we're not already pointing 1695 * at the current mblk data, then we want to ensure that the data 1696 * points at ip. 1697 */ 1698 1699 if ((ip == (ip_t *)qpi->qpi_m->b_rptr) && (qpi->qpi_m != mb)) { 1700 ip = (ip_t *)mb->b_rptr; 1701 } else if ((qpi->qpi_m == mb) && (ip != (ip_t *)qpi->qpi_m->b_rptr)) { 1702 qpi->qpi_m->b_rptr = (uchar_t *)ip; 1703 qpi->qpi_off = 0; 1704 } 1705 1706 /* 1707 * If there is another M_PROTO, we don't want it 1708 */ 1709 if (*mpp != mb) { 1710 mp = unlinkb(*mpp); 1711 freeb(*mpp); 1712 *mpp = mp; 1713 } 1714 1715 sinp = (struct sockaddr *)&inj_data.ni_addr; 1716 sin = (struct sockaddr_in *)sinp; 1717 sin6 = (struct sockaddr_in6 *)sinp; 1718 bzero((char *)&inj_data.ni_addr, sizeof (inj_data.ni_addr)); 1719 inj_data.ni_addr.ss_family = (fin->fin_v == 4) ? AF_INET : AF_INET6; 1720 inj_data.ni_packet = mb; 1721 1722 /* 1723 * In case we're here due to "to <if>" being used with 1724 * "keep state", check that we're going in the correct 1725 * direction. 1726 */ 1727 if (fdp != NULL) { 1728 if ((fr != NULL) && (fdp->fd_ifp != NULL) && 1729 (fin->fin_rev != 0) && (fdp == &fr->fr_tif)) 1730 goto bad_fastroute; 1731 inj_data.ni_physical = (phy_if_t)fdp->fd_ifp; 1732 if (fin->fin_v == 4) { 1733 sin->sin_addr = fdp->fd_ip; 1734 } else { 1735 sin6->sin6_addr = fdp->fd_ip6.in6; 1736 } 1737 } else { 1738 if (fin->fin_v == 4) { 1739 sin->sin_addr = ip->ip_dst; 1740 } else { 1741 sin6->sin6_addr = ((ip6_t *)ip)->ip6_dst; 1742 } 1743 inj_data.ni_physical = net_routeto(net_data_p, sinp); 1744 } 1745 1746 /* disable hardware checksum */ 1747 DB_CKSUMFLAGS(mb) = 0; 1748 1749 *mpp = mb; 1750 1751 if (fin->fin_out == 0) { 1752 void *saveifp; 1753 u_32_t pass; 1754 1755 saveifp = fin->fin_ifp; 1756 fin->fin_ifp = (void *)inj_data.ni_physical; 1757 fin->fin_out = 1; 1758 (void) fr_acctpkt(fin, &pass); 1759 fin->fin_fr = NULL; 1760 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1761 (void) fr_checkstate(fin, &pass); 1762 switch (fr_checknatout(fin, NULL)) 1763 { 1764 /* FALLTHROUGH */ 1765 case 0 : 1766 case 1 : 1767 break; 1768 case -1 : 1769 goto bad_fastroute; 1770 } 1771 fin->fin_out = 0; 1772 fin->fin_ifp = saveifp; 1773 1774 if (fin->fin_nat != NULL) 1775 fr_natderef((nat_t **)&fin->fin_nat, ifs); 1776 } 1777 #ifndef sparc 1778 if (fin->fin_v == 4) { 1779 __iplen = (u_short)ip->ip_len, 1780 __ipoff = (u_short)ip->ip_off; 1781 1782 ip->ip_len = htons(__iplen); 1783 ip->ip_off = htons(__ipoff); 1784 } 1785 #endif 1786 1787 if (net_data_p) { 1788 if (net_inject(net_data_p, NI_DIRECT_OUT, &inj_data) < 0) { 1789 return (-1); 1790 } 1791 } 1792 1793 ifs->ifs_fr_frouteok[0]++; 1794 return 0; 1795 bad_fastroute: 1796 freemsg(mb); 1797 ifs->ifs_fr_frouteok[1]++; 1798 return -1; 1799 } 1800 1801 1802 /* ------------------------------------------------------------------------ */ 1803 /* Function: ipf_hook_out */ 1804 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1805 /* Parameters: event(I) - pointer to event */ 1806 /* info(I) - pointer to hook information for firewalling */ 1807 /* */ 1808 /* Calling ipf_hook. */ 1809 /* ------------------------------------------------------------------------ */ 1810 /*ARGSUSED*/ 1811 int ipf_hook_out(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1812 { 1813 return ipf_hook(info, 1, 0, ns); 1814 } 1815 1816 /* ------------------------------------------------------------------------ */ 1817 /* Function: ipf_hook_in */ 1818 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1819 /* Parameters: event(I) - pointer to event */ 1820 /* info(I) - pointer to hook information for firewalling */ 1821 /* */ 1822 /* Calling ipf_hook. */ 1823 /* ------------------------------------------------------------------------ */ 1824 /*ARGSUSED*/ 1825 int ipf_hook_in(hook_event_token_t token, hook_data_t info, netstack_t *ns) 1826 { 1827 return ipf_hook(info, 0, 0, ns); 1828 } 1829 1830 1831 /* ------------------------------------------------------------------------ */ 1832 /* Function: ipf_hook_loop_out */ 1833 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1834 /* Parameters: event(I) - pointer to event */ 1835 /* info(I) - pointer to hook information for firewalling */ 1836 /* */ 1837 /* Calling ipf_hook. */ 1838 /* ------------------------------------------------------------------------ */ 1839 /*ARGSUSED*/ 1840 int ipf_hook_loop_out(hook_event_token_t token, hook_data_t info, 1841 netstack_t *ns) 1842 { 1843 return ipf_hook(info, 1, 1, ns); 1844 } 1845 1846 /* ------------------------------------------------------------------------ */ 1847 /* Function: ipf_hook_loop_in */ 1848 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1849 /* Parameters: event(I) - pointer to event */ 1850 /* info(I) - pointer to hook information for firewalling */ 1851 /* */ 1852 /* Calling ipf_hook. */ 1853 /* ------------------------------------------------------------------------ */ 1854 /*ARGSUSED*/ 1855 int ipf_hook_loop_in(hook_event_token_t token, hook_data_t info, 1856 netstack_t *ns) 1857 { 1858 return ipf_hook(info, 0, 1, ns); 1859 } 1860 1861 /* ------------------------------------------------------------------------ */ 1862 /* Function: ipf_hook */ 1863 /* Returns: int - 0 == packet ok, else problem, free packet if not done */ 1864 /* Parameters: info(I) - pointer to hook information for firewalling */ 1865 /* out(I) - whether packet is going in or out */ 1866 /* loopback(I) - whether packet is a loopback packet or not */ 1867 /* */ 1868 /* Stepping stone function between the IP mainline and IPFilter. Extracts */ 1869 /* parameters out of the info structure and forms them up to be useful for */ 1870 /* calling ipfilter. */ 1871 /* ------------------------------------------------------------------------ */ 1872 int ipf_hook(hook_data_t info, int out, int loopback, netstack_t *ns) 1873 { 1874 hook_pkt_event_t *fw; 1875 int rval, v, hlen; 1876 qpktinfo_t qpi; 1877 u_short swap; 1878 phy_if_t phy; 1879 ip_t *ip; 1880 1881 fw = (hook_pkt_event_t *)info; 1882 1883 ASSERT(fw != NULL); 1884 phy = (out == 0) ? fw->hpe_ifp : fw->hpe_ofp; 1885 1886 ip = fw->hpe_hdr; 1887 v = ip->ip_v; 1888 if (v == IPV4_VERSION) { 1889 swap = ntohs(ip->ip_len); 1890 ip->ip_len = swap; 1891 swap = ntohs(ip->ip_off); 1892 ip->ip_off = swap; 1893 1894 hlen = IPH_HDR_LENGTH(ip); 1895 } else 1896 hlen = sizeof (ip6_t); 1897 1898 bzero(&qpi, sizeof (qpktinfo_t)); 1899 1900 qpi.qpi_m = fw->hpe_mb; 1901 qpi.qpi_data = fw->hpe_hdr; 1902 qpi.qpi_off = (char *)qpi.qpi_data - (char *)fw->hpe_mb->b_rptr; 1903 qpi.qpi_ill = (void *)phy; 1904 if (loopback) 1905 qpi.qpi_flags = QPI_NOCKSUM; 1906 else 1907 qpi.qpi_flags = 0; 1908 1909 rval = fr_check(fw->hpe_hdr, hlen, qpi.qpi_ill, out, 1910 &qpi, fw->hpe_mp, ns->netstack_ipf); 1911 1912 /* For fastroute cases, fr_check returns 0 with mp set to NULL */ 1913 if (rval == 0 && *(fw->hpe_mp) == NULL) 1914 rval = 1; 1915 1916 /* Notify IP the packet mblk_t and IP header pointers. */ 1917 fw->hpe_mb = qpi.qpi_m; 1918 fw->hpe_hdr = qpi.qpi_data; 1919 if ((rval == 0) && (v == IPV4_VERSION)) { 1920 ip = qpi.qpi_data; 1921 swap = ntohs(ip->ip_len); 1922 ip->ip_len = swap; 1923 swap = ntohs(ip->ip_off); 1924 ip->ip_off = swap; 1925 } 1926 return rval; 1927 1928 } 1929 1930 1931 /* ------------------------------------------------------------------------ */ 1932 /* Function: ipf_nic_event_v4 */ 1933 /* Returns: int - 0 == no problems encountered */ 1934 /* Parameters: event(I) - pointer to event */ 1935 /* info(I) - pointer to information about a NIC event */ 1936 /* */ 1937 /* Function to receive asynchronous NIC events from IP */ 1938 /* ------------------------------------------------------------------------ */ 1939 /*ARGSUSED*/ 1940 int ipf_nic_event_v4(hook_event_token_t event, hook_data_t info, 1941 netstack_t *ns) 1942 { 1943 struct sockaddr_in *sin; 1944 hook_nic_event_t *hn; 1945 ipf_stack_t *ifs = ns->netstack_ipf; 1946 1947 hn = (hook_nic_event_t *)info; 1948 1949 switch (hn->hne_event) 1950 { 1951 case NE_PLUMB : 1952 frsync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, hn->hne_data, ifs); 1953 fr_natifpsync(IPFSYNC_NEWIFP, (void *)hn->hne_nic, 1954 hn->hne_data, ifs); 1955 fr_statesync(IPFSYNC_NEWIFP, 4, (void *)hn->hne_nic, 1956 hn->hne_data, ifs); 1957 break; 1958 1959 case NE_UNPLUMB : 1960 frsync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1961 fr_natifpsync(IPFSYNC_OLDIFP, (void *)hn->hne_nic, NULL, ifs); 1962 fr_statesync(IPFSYNC_OLDIFP, 4, (void *)hn->hne_nic, NULL, ifs); 1963 break; 1964 1965 case NE_ADDRESS_CHANGE : 1966 sin = hn->hne_data; 1967 fr_nataddrsync((void *)hn->hne_nic, &sin->sin_addr, ifs); 1968 break; 1969 1970 default : 1971 break; 1972 } 1973 1974 return 0; 1975 } 1976 1977 1978 /* ------------------------------------------------------------------------ */ 1979 /* Function: ipf_nic_event_v6 */ 1980 /* Returns: int - 0 == no problems encountered */ 1981 /* Parameters: event(I) - pointer to event */ 1982 /* info(I) - pointer to information about a NIC event */ 1983 /* */ 1984 /* Function to receive asynchronous NIC events from IP */ 1985 /* ------------------------------------------------------------------------ */ 1986 /*ARGSUSED*/ 1987 int ipf_nic_event_v6(hook_event_token_t event, hook_data_t info, 1988 netstack_t *ns) 1989 { 1990 hook_nic_event_t *hn; 1991 ipf_stack_t *ifs = ns->netstack_ipf; 1992 1993 hn = (hook_nic_event_t *)info; 1994 1995 switch (hn->hne_event) 1996 { 1997 case NE_PLUMB : 1998 frsync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, hn->hne_data, ifs); 1999 fr_statesync(IPFSYNC_NEWIFP, 6, (void *)hn->hne_nic, 2000 hn->hne_data, ifs); 2001 break; 2002 2003 case NE_UNPLUMB : 2004 frsync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2005 fr_statesync(IPFSYNC_OLDIFP, 6, (void *)hn->hne_nic, NULL, ifs); 2006 break; 2007 2008 case NE_ADDRESS_CHANGE : 2009 break; 2010 default : 2011 break; 2012 } 2013 2014 return 0; 2015 } 2016