1 /* 2 * Copyright (C) 1993-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2006 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/ddi.h> 28 #include <sys/sunddi.h> 29 #include <sys/ksynch.h> 30 #include <sys/kmem.h> 31 #include <sys/mkdev.h> 32 #include <sys/protosw.h> 33 #include <sys/socket.h> 34 #include <sys/dditypes.h> 35 #include <sys/cmn_err.h> 36 #include <net/if.h> 37 #include <net/af.h> 38 #include <net/route.h> 39 #include <netinet/in.h> 40 #include <netinet/in_systm.h> 41 #include <netinet/ip.h> 42 #include <netinet/ip_var.h> 43 #include <netinet/tcp.h> 44 #include <netinet/udp.h> 45 #include <netinet/tcpip.h> 46 #include <netinet/ip_icmp.h> 47 #include "netinet/ip_compat.h" 48 #ifdef USE_INET6 49 # include <netinet/icmp6.h> 50 #endif 51 #include "netinet/ip_fil.h" 52 #include "netinet/ip_nat.h" 53 #include "netinet/ip_frag.h" 54 #include "netinet/ip_state.h" 55 #include "netinet/ip_auth.h" 56 #include "netinet/ip_proxy.h" 57 #ifdef IPFILTER_LOOKUP 58 # include "netinet/ip_lookup.h" 59 #endif 60 #include <inet/ip_ire.h> 61 62 #include <sys/md5.h> 63 64 extern int fr_flags, fr_active; 65 #if SOLARIS2 >= 7 66 timeout_id_t fr_timer_id; 67 #else 68 int fr_timer_id; 69 #endif 70 71 72 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m, mblk_t **mp)); 73 74 ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 75 ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 76 ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache; 77 ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 78 kcondvar_t iplwait, ipfauthwait; 79 #if SOLARIS2 < 10 80 #if SOLARIS2 >= 7 81 timeout_id_t fr_timer_id; 82 u_int *ip_ttl_ptr = NULL; 83 u_int *ip_mtudisc = NULL; 84 # if SOLARIS2 >= 8 85 int *ip_forwarding = NULL; 86 u_int *ip6_forwarding = NULL; 87 # else 88 u_int *ip_forwarding = NULL; 89 # endif 90 #else 91 int fr_timer_id; 92 u_long *ip_ttl_ptr = NULL; 93 u_long *ip_mtudisc = NULL; 94 u_long *ip_forwarding = NULL; 95 #endif 96 #endif 97 int ipf_locks_done = 0; 98 99 100 /* ------------------------------------------------------------------------ */ 101 /* Function: ipldetach */ 102 /* Returns: int - 0 == success, else error. */ 103 /* Parameters: Nil */ 104 /* */ 105 /* This function is responsible for undoing anything that might have been */ 106 /* done in a call to iplattach(). It must be able to clean up from a call */ 107 /* to iplattach() that did not succeed. Why might that happen? Someone */ 108 /* configures a table to be so large that we cannot allocate enough memory */ 109 /* for it. */ 110 /* ------------------------------------------------------------------------ */ 111 int ipldetach() 112 { 113 114 ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 115 116 #if SOLARIS2 < 10 117 118 if (fr_control_forwarding & 2) { 119 if (ip_forwarding != NULL) 120 *ip_forwarding = 0; 121 #if SOLARIS2 >= 8 122 if (ip6_forwarding != NULL) 123 *ip6_forwarding = 0; 124 #endif 125 } 126 #endif 127 128 #ifdef IPFDEBUG 129 cmn_err(CE_CONT, "ipldetach()\n"); 130 #endif 131 132 fr_deinitialise(); 133 134 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 135 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 136 137 if (ipf_locks_done == 1) { 138 MUTEX_DESTROY(&ipf_timeoutlock); 139 MUTEX_DESTROY(&ipf_rw); 140 RW_DESTROY(&ipf_ipidfrag); 141 ipf_locks_done = 0; 142 } 143 return 0; 144 } 145 146 147 int iplattach __P((void)) 148 { 149 #if SOLARIS2 < 10 150 int i; 151 #endif 152 153 #ifdef IPFDEBUG 154 cmn_err(CE_CONT, "iplattach()\n"); 155 #endif 156 157 ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 158 159 bzero((char *)frcache, sizeof(frcache)); 160 MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 161 MUTEX_INIT(&ipf_timeoutlock, "ipf timeout lock mutex"); 162 RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 163 ipf_locks_done = 1; 164 165 if (fr_initialise() < 0) 166 return -1; 167 168 /* Do not use private interface ip_params_arr[] in Solaris 10 */ 169 #if SOLARIS2 < 10 170 171 #if SOLARIS2 >= 8 172 ip_forwarding = &ip_g_forward; 173 #endif 174 /* 175 * XXX - There is no terminator for this array, so it is not possible 176 * to tell if what we are looking for is missing and go off the end 177 * of the array. 178 */ 179 180 #if SOLARIS2 <= 8 181 for (i = 0; ; i++) { 182 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 183 ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 184 } else if (!strcmp(ip_param_arr[i].ip_param_name, 185 "ip_path_mtu_discovery")) { 186 ip_mtudisc = &ip_param_arr[i].ip_param_value; 187 } 188 #if SOLARIS2 < 8 189 else if (!strcmp(ip_param_arr[i].ip_param_name, 190 "ip_forwarding")) { 191 ip_forwarding = &ip_param_arr[i].ip_param_value; 192 } 193 #else 194 else if (!strcmp(ip_param_arr[i].ip_param_name, 195 "ip6_forwarding")) { 196 ip6_forwarding = &ip_param_arr[i].ip_param_value; 197 } 198 #endif 199 200 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 201 #if SOLARIS2 >= 8 202 ip6_forwarding != NULL && 203 #endif 204 ip_forwarding != NULL) 205 break; 206 } 207 #endif 208 209 if (fr_control_forwarding & 1) { 210 if (ip_forwarding != NULL) 211 *ip_forwarding = 1; 212 #if SOLARIS2 >= 8 213 if (ip6_forwarding != NULL) 214 *ip6_forwarding = 1; 215 #endif 216 } 217 218 #endif 219 220 return 0; 221 } 222 223 224 /* 225 * Filter ioctl interface. 226 */ 227 /*ARGSUSED*/ 228 int iplioctl(dev, cmd, data, mode, cp, rp) 229 dev_t dev; 230 int cmd; 231 #if SOLARIS2 >= 7 232 intptr_t data; 233 #else 234 int *data; 235 #endif 236 int mode; 237 cred_t *cp; 238 int *rp; 239 { 240 int error = 0, tmp; 241 friostat_t fio; 242 minor_t unit; 243 u_int enable; 244 245 #ifdef IPFDEBUG 246 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 247 dev, cmd, data, mode, cp, rp); 248 #endif 249 unit = getminor(dev); 250 if (IPL_LOGMAX < unit) 251 return ENXIO; 252 253 if (fr_running <= 0) { 254 if (unit != IPL_LOGIPF) 255 return EIO; 256 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 257 cmd != SIOCIPFSET && cmd != SIOCFRENB && 258 cmd != SIOCGETFS && cmd != SIOCGETFF) 259 return EIO; 260 } 261 262 READ_ENTER(&ipf_global); 263 264 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode); 265 if (error != -1) { 266 RWLOCK_EXIT(&ipf_global); 267 return error; 268 } 269 error = 0; 270 271 switch (cmd) 272 { 273 case SIOCFRENB : 274 if (!(mode & FWRITE)) 275 error = EPERM; 276 else { 277 error = COPYIN((caddr_t)data, (caddr_t)&enable, 278 sizeof(enable)); 279 if (error != 0) { 280 error = EFAULT; 281 break; 282 } 283 284 RWLOCK_EXIT(&ipf_global); 285 WRITE_ENTER(&ipf_global); 286 if (enable) { 287 if (fr_running > 0) 288 error = 0; 289 else 290 error = iplattach(); 291 if (error == 0) 292 fr_running = 1; 293 else 294 (void) ipldetach(); 295 } else { 296 error = ipldetach(); 297 if (error == 0) 298 fr_running = -1; 299 } 300 } 301 break; 302 case SIOCIPFSET : 303 if (!(mode & FWRITE)) { 304 error = EPERM; 305 break; 306 } 307 /* FALLTHRU */ 308 case SIOCIPFGETNEXT : 309 case SIOCIPFGET : 310 error = fr_ipftune(cmd, (void *)data); 311 break; 312 case SIOCSETFF : 313 if (!(mode & FWRITE)) 314 error = EPERM; 315 else { 316 error = COPYIN((caddr_t)data, (caddr_t)&fr_flags, 317 sizeof(fr_flags)); 318 if (error != 0) 319 error = EFAULT; 320 } 321 break; 322 case SIOCGETFF : 323 error = COPYOUT((caddr_t)&fr_flags, (caddr_t)data, 324 sizeof(fr_flags)); 325 if (error != 0) 326 error = EFAULT; 327 break; 328 case SIOCFUNCL : 329 error = fr_resolvefunc((void *)data); 330 break; 331 case SIOCINAFR : 332 case SIOCRMAFR : 333 case SIOCADAFR : 334 case SIOCZRLST : 335 if (!(mode & FWRITE)) 336 error = EPERM; 337 else 338 error = frrequest(unit, cmd, (caddr_t)data, 339 fr_active, 1); 340 break; 341 case SIOCINIFR : 342 case SIOCRMIFR : 343 case SIOCADIFR : 344 if (!(mode & FWRITE)) 345 error = EPERM; 346 else 347 error = frrequest(unit, cmd, (caddr_t)data, 348 1 - fr_active, 1); 349 break; 350 case SIOCSWAPA : 351 if (!(mode & FWRITE)) 352 error = EPERM; 353 else { 354 WRITE_ENTER(&ipf_mutex); 355 bzero((char *)frcache, sizeof(frcache[0]) * 2); 356 error = COPYOUT((caddr_t)&fr_active, (caddr_t)data, 357 sizeof(fr_active)); 358 if (error != 0) 359 error = EFAULT; 360 else 361 fr_active = 1 - fr_active; 362 RWLOCK_EXIT(&ipf_mutex); 363 } 364 break; 365 case SIOCGETFS : 366 fr_getstat(&fio); 367 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 368 break; 369 case SIOCFRZST : 370 if (!(mode & FWRITE)) 371 error = EPERM; 372 else 373 error = fr_zerostats((caddr_t)data); 374 break; 375 case SIOCIPFFL : 376 if (!(mode & FWRITE)) 377 error = EPERM; 378 else { 379 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 380 sizeof(tmp)); 381 if (!error) { 382 tmp = frflush(unit, 4, tmp); 383 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 384 sizeof(tmp)); 385 if (error != 0) 386 error = EFAULT; 387 } else 388 error = EFAULT; 389 } 390 break; 391 #ifdef USE_INET6 392 case SIOCIPFL6 : 393 if (!(mode & FWRITE)) 394 error = EPERM; 395 else { 396 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 397 sizeof(tmp)); 398 if (!error) { 399 tmp = frflush(unit, 6, tmp); 400 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 401 sizeof(tmp)); 402 if (error != 0) 403 error = EFAULT; 404 } else 405 error = EFAULT; 406 } 407 break; 408 #endif 409 case SIOCSTLCK : 410 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 411 if (error == 0) { 412 fr_state_lock = tmp; 413 fr_nat_lock = tmp; 414 fr_frag_lock = tmp; 415 fr_auth_lock = tmp; 416 } else 417 error = EFAULT; 418 break; 419 #ifdef IPFILTER_LOG 420 case SIOCIPFFB : 421 if (!(mode & FWRITE)) 422 error = EPERM; 423 else { 424 tmp = ipflog_clear(unit); 425 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 426 sizeof(tmp)); 427 if (error) 428 error = EFAULT; 429 } 430 break; 431 #endif /* IPFILTER_LOG */ 432 case SIOCFRSYN : 433 if (!(mode & FWRITE)) 434 error = EPERM; 435 else { 436 RWLOCK_EXIT(&ipf_global); 437 WRITE_ENTER(&ipf_global); 438 error = ipfsync(); 439 } 440 break; 441 case SIOCGFRST : 442 error = fr_outobj((void *)data, fr_fragstats(), 443 IPFOBJ_FRAGSTAT); 444 break; 445 case FIONREAD : 446 #ifdef IPFILTER_LOG 447 tmp = (int)iplused[IPL_LOGIPF]; 448 449 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 450 if (error != 0) 451 error = EFAULT; 452 #endif 453 break; 454 default : 455 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", cmd, (void *)data); 456 error = EINVAL; 457 break; 458 } 459 RWLOCK_EXIT(&ipf_global); 460 return error; 461 } 462 463 464 void *get_unit(name, v) 465 char *name; 466 int v; 467 { 468 qif_t *qf; 469 int sap; 470 471 if (v == 4) 472 sap = 0x0800; 473 else if (v == 6) 474 sap = 0x86dd; 475 else 476 return NULL; 477 rw_enter(&pfil_rw, RW_READER); 478 qf = qif_iflookup(name, sap); 479 rw_exit(&pfil_rw); 480 return qf; 481 } 482 483 484 /* 485 * routines below for saving IP headers to buffer 486 */ 487 /*ARGSUSED*/ 488 int iplopen(devp, flags, otype, cred) 489 dev_t *devp; 490 int flags, otype; 491 cred_t *cred; 492 { 493 minor_t min = getminor(*devp); 494 495 #ifdef IPFDEBUG 496 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 497 #endif 498 if (!(otype & OTYP_CHR)) 499 return ENXIO; 500 501 min = (IPL_LOGMAX < min) ? ENXIO : 0; 502 return min; 503 } 504 505 506 /*ARGSUSED*/ 507 int iplclose(dev, flags, otype, cred) 508 dev_t dev; 509 int flags, otype; 510 cred_t *cred; 511 { 512 minor_t min = getminor(dev); 513 514 #ifdef IPFDEBUG 515 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 516 #endif 517 518 min = (IPL_LOGMAX < min) ? ENXIO : 0; 519 return min; 520 } 521 522 #ifdef IPFILTER_LOG 523 /* 524 * iplread/ipllog 525 * both of these must operate with at least splnet() lest they be 526 * called during packet processing and cause an inconsistancy to appear in 527 * the filter lists. 528 */ 529 /*ARGSUSED*/ 530 int iplread(dev, uio, cp) 531 dev_t dev; 532 register struct uio *uio; 533 cred_t *cp; 534 { 535 # ifdef IPFDEBUG 536 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 537 # endif 538 # ifdef IPFILTER_SYNC 539 if (getminor(dev) == IPL_LOGSYNC) 540 return ipfsync_read(uio); 541 # endif 542 543 return ipflog_read(getminor(dev), uio); 544 } 545 #endif /* IPFILTER_LOG */ 546 547 548 /* 549 * iplread/ipllog 550 * both of these must operate with at least splnet() lest they be 551 * called during packet processing and cause an inconsistancy to appear in 552 * the filter lists. 553 */ 554 int iplwrite(dev, uio, cp) 555 dev_t dev; 556 register struct uio *uio; 557 cred_t *cp; 558 { 559 #ifdef IPFDEBUG 560 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 561 #endif 562 #ifdef IPFILTER_SYNC 563 if (getminor(dev) == IPL_LOGSYNC) 564 return ipfsync_write(uio); 565 #endif /* IPFILTER_SYNC */ 566 dev = dev; /* LINT */ 567 uio = uio; /* LINT */ 568 cp = cp; /* LINT */ 569 return ENXIO; 570 } 571 572 573 /* 574 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 575 * requires a large amount of setting up and isn't any more efficient. 576 */ 577 int fr_send_reset(fin) 578 fr_info_t *fin; 579 { 580 tcphdr_t *tcp, *tcp2; 581 int tlen, hlen; 582 mblk_t *m; 583 #ifdef USE_INET6 584 ip6_t *ip6; 585 #endif 586 ip_t *ip; 587 588 tcp = fin->fin_dp; 589 if (tcp->th_flags & TH_RST) 590 return -1; 591 592 #ifndef IPFILTER_CKSUM 593 if (fr_checkl4sum(fin) == -1) 594 return -1; 595 #endif 596 597 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 598 #ifdef USE_INET6 599 if (fin->fin_v == 6) 600 hlen = sizeof(ip6_t); 601 else 602 #endif 603 hlen = sizeof(ip_t); 604 hlen += sizeof(*tcp2); 605 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 606 return -1; 607 608 m->b_rptr += 64; 609 MTYPE(m) = M_DATA; 610 m->b_wptr = m->b_rptr + hlen; 611 ip = (ip_t *)m->b_rptr; 612 bzero((char *)ip, hlen); 613 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 614 tcp2->th_dport = tcp->th_sport; 615 tcp2->th_sport = tcp->th_dport; 616 if (tcp->th_flags & TH_ACK) { 617 tcp2->th_seq = tcp->th_ack; 618 tcp2->th_flags = TH_RST; 619 } else { 620 tcp2->th_ack = ntohl(tcp->th_seq); 621 tcp2->th_ack += tlen; 622 tcp2->th_ack = htonl(tcp2->th_ack); 623 tcp2->th_flags = TH_RST|TH_ACK; 624 } 625 tcp2->th_off = sizeof(struct tcphdr) >> 2; 626 627 ip->ip_v = fin->fin_v; 628 #ifdef USE_INET6 629 if (fin->fin_v == 6) { 630 ip6 = (ip6_t *)m->b_rptr; 631 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 632 ip6->ip6_src = fin->fin_dst6; 633 ip6->ip6_dst = fin->fin_src6; 634 ip6->ip6_plen = htons(sizeof(*tcp)); 635 ip6->ip6_nxt = IPPROTO_TCP; 636 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 637 } else 638 #endif 639 { 640 ip->ip_src.s_addr = fin->fin_daddr; 641 ip->ip_dst.s_addr = fin->fin_saddr; 642 ip->ip_id = fr_nextipid(fin); 643 ip->ip_hl = sizeof(*ip) >> 2; 644 ip->ip_p = IPPROTO_TCP; 645 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 646 ip->ip_tos = fin->fin_ip->ip_tos; 647 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 648 } 649 return fr_send_ip(fin, m, &m); 650 } 651 652 /* 653 * Function: fr_send_ip 654 * Returns: 0: success 655 * -1: failed 656 * Parameters: 657 * fin: packet information 658 * m: the message block where ip head starts 659 * 660 * Send a new packet through the IP stack. 661 * 662 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 663 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 664 * function). 665 * 666 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 667 * in by this function. 668 * 669 * All other portions of the packet must be in on-the-wire format. 670 */ 671 /*ARGSUSED*/ 672 static int fr_send_ip(fin, m, mpp) 673 fr_info_t *fin; 674 mblk_t *m, **mpp; 675 { 676 qpktinfo_t qpi, *qpip; 677 fr_info_t fnew; 678 qif_t *qif; 679 ip_t *ip; 680 int i, hlen; 681 682 ip = (ip_t *)m->b_rptr; 683 bzero((char *)&fnew, sizeof(fnew)); 684 685 #ifdef USE_INET6 686 if (fin->fin_v == 6) { 687 ip6_t *ip6; 688 689 ip6 = (ip6_t *)ip; 690 ip6->ip6_vfc = 0x60; 691 ip6->ip6_hlim = 127; 692 fnew.fin_v = 6; 693 hlen = sizeof(*ip6); 694 fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen; 695 } else 696 #endif 697 { 698 fnew.fin_v = 4; 699 #if SOLARIS2 >= 10 700 ip->ip_ttl = 255; 701 702 ip->ip_off = htons(IP_DF); 703 #else 704 if (ip_ttl_ptr != NULL) 705 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 706 else 707 ip->ip_ttl = 63; 708 if (ip_mtudisc != NULL) 709 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 710 else 711 ip->ip_off = htons(IP_DF); 712 #endif 713 /* 714 * The dance with byte order and ip_len/ip_off is because in 715 * fr_fastroute, it expects them to be in host byte order but 716 * ipf_cksum expects them to be in network byte order. 717 */ 718 ip->ip_len = htons(ip->ip_len); 719 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 720 ip->ip_len = ntohs(ip->ip_len); 721 ip->ip_off = ntohs(ip->ip_off); 722 hlen = sizeof(*ip); 723 fnew.fin_plen = ip->ip_len; 724 } 725 726 qpip = fin->fin_qpi; 727 qpi.qpi_q = qpip->qpi_q; 728 qpi.qpi_off = 0; 729 qpi.qpi_name = qpip->qpi_name; 730 qif = qpip->qpi_real; 731 qpi.qpi_real = qif; 732 qpi.qpi_ill = qif->qf_ill; 733 qpi.qpi_hl = qif->qf_hl; 734 qpi.qpi_ppa = qif->qf_ppa; 735 qpi.qpi_num = qif->qf_num; 736 qpi.qpi_flags = qif->qf_flags; 737 qpi.qpi_max_frag = qif->qf_max_frag; 738 qpi.qpi_m = m; 739 qpi.qpi_data = ip; 740 fnew.fin_qpi = &qpi; 741 fnew.fin_ifp = fin->fin_ifp; 742 fnew.fin_flx = FI_NOCKSUM; 743 fnew.fin_m = m; 744 fnew.fin_ip = ip; 745 fnew.fin_mp = mpp; 746 fnew.fin_hlen = hlen; 747 fnew.fin_dp = (char *)ip + hlen; 748 (void) fr_makefrip(hlen, ip, &fnew); 749 750 i = fr_fastroute(m, mpp, &fnew, NULL); 751 return i; 752 } 753 754 755 int fr_send_icmp_err(type, fin, dst) 756 int type; 757 fr_info_t *fin; 758 int dst; 759 { 760 struct in_addr dst4; 761 struct icmp *icmp; 762 qpktinfo_t *qpi; 763 int hlen, code; 764 u_short sz; 765 #ifdef USE_INET6 766 mblk_t *mb; 767 #endif 768 mblk_t *m; 769 #ifdef USE_INET6 770 ip6_t *ip6; 771 #endif 772 ip_t *ip; 773 774 if ((type < 0) || (type > ICMP_MAXTYPE)) 775 return -1; 776 777 code = fin->fin_icode; 778 #ifdef USE_INET6 779 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 780 return -1; 781 #endif 782 783 #ifndef IPFILTER_CKSUM 784 if (fr_checkl4sum(fin) == -1) 785 return -1; 786 #endif 787 788 qpi = fin->fin_qpi; 789 790 #ifdef USE_INET6 791 mb = fin->fin_qfm; 792 793 if (fin->fin_v == 6) { 794 sz = sizeof(ip6_t); 795 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 796 hlen = sizeof(ip6_t); 797 type = icmptoicmp6types[type]; 798 if (type == ICMP6_DST_UNREACH) 799 code = icmptoicmp6unreach[code]; 800 } else 801 #endif 802 { 803 if ((fin->fin_p == IPPROTO_ICMP) && 804 !(fin->fin_flx & FI_SHORT)) 805 switch (ntohs(fin->fin_data[0]) >> 8) 806 { 807 case ICMP_ECHO : 808 case ICMP_TSTAMP : 809 case ICMP_IREQ : 810 case ICMP_MASKREQ : 811 break; 812 default : 813 return 0; 814 } 815 816 sz = sizeof(ip_t) * 2; 817 sz += 8; /* 64 bits of data */ 818 hlen = sizeof(ip_t); 819 } 820 821 sz += offsetof(struct icmp, icmp_ip); 822 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 823 return -1; 824 MTYPE(m) = M_DATA; 825 m->b_rptr += 64; 826 m->b_wptr = m->b_rptr + sz; 827 bzero((char *)m->b_rptr, (size_t)sz); 828 ip = (ip_t *)m->b_rptr; 829 ip->ip_v = fin->fin_v; 830 icmp = (struct icmp *)(m->b_rptr + hlen); 831 icmp->icmp_type = type & 0xff; 832 icmp->icmp_code = code & 0xff; 833 #ifdef icmp_nextmtu 834 if (type == ICMP_UNREACH && (qpi->qpi_max_frag != 0) && 835 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 836 icmp->icmp_nextmtu = htons(qpi->qpi_max_frag); 837 #endif 838 839 #ifdef USE_INET6 840 if (fin->fin_v == 6) { 841 struct in6_addr dst6; 842 int csz; 843 844 if (dst == 0) { 845 if (fr_ifpaddr(6, FRI_NORMAL, qpi->qpi_real, 846 (struct in_addr *)&dst6, NULL) == -1) { 847 FREE_MB_T(m); 848 return -1; 849 } 850 } else 851 dst6 = fin->fin_dst6; 852 853 csz = sz; 854 sz -= sizeof(ip6_t); 855 ip6 = (ip6_t *)m->b_rptr; 856 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 857 ip6->ip6_plen = htons((u_short)sz); 858 ip6->ip6_nxt = IPPROTO_ICMPV6; 859 ip6->ip6_src = dst6; 860 ip6->ip6_dst = fin->fin_src6; 861 sz -= offsetof(struct icmp, icmp_ip); 862 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 863 icmp->icmp_cksum = csz - sizeof(ip6_t); 864 } else 865 #endif 866 { 867 ip->ip_hl = sizeof(*ip) >> 2; 868 ip->ip_p = IPPROTO_ICMP; 869 ip->ip_id = fin->fin_ip->ip_id; 870 ip->ip_tos = fin->fin_ip->ip_tos; 871 ip->ip_len = (u_short)sz; 872 if (dst == 0) { 873 if (fr_ifpaddr(4, FRI_NORMAL, qpi->qpi_real, 874 &dst4, NULL) == -1) { 875 FREE_MB_T(m); 876 return -1; 877 } 878 } else 879 dst4 = fin->fin_dst; 880 ip->ip_src = dst4; 881 ip->ip_dst = fin->fin_src; 882 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 883 sizeof(*fin->fin_ip)); 884 bcopy((char *)fin->fin_ip + fin->fin_hlen, 885 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 886 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 887 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 888 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 889 sz - sizeof(ip_t)); 890 } 891 892 /* 893 * Need to exit out of these so we don't recursively call rw_enter 894 * from fr_qout. 895 */ 896 return fr_send_ip(fin, m, &m); 897 } 898 899 #ifdef IRE_ILL_CN 900 #include <sys/time.h> 901 #include <sys/varargs.h> 902 903 #ifndef _KERNEL 904 #include <stdio.h> 905 #endif 906 907 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 908 909 910 /* 911 * Print out warning message at rate-limited speed. 912 */ 913 static void rate_limit_message(int rate, const char *message, ...) 914 { 915 static time_t last_time = 0; 916 time_t now; 917 va_list args; 918 char msg_buf[256]; 919 int need_printed = 0; 920 921 now = ddi_get_time(); 922 923 /* make sure, no multiple entries */ 924 ASSERT(MUTEX_NOT_HELD(&(ipf_rw.ipf_lk))); 925 MUTEX_ENTER(&ipf_rw); 926 if (now - last_time >= rate) { 927 need_printed = 1; 928 last_time = now; 929 } 930 MUTEX_EXIT(&ipf_rw); 931 932 if (need_printed) { 933 va_start(args, message); 934 (void)vsnprintf(msg_buf, 255, message, args); 935 va_end(args); 936 #ifdef _KERNEL 937 cmn_err(CE_WARN, msg_buf); 938 #else 939 fprintf(std_err, msg_buf); 940 #endif 941 } 942 } 943 #endif 944 945 /* 946 * return the first IP Address associated with an interface 947 */ 948 /*ARGSUSED*/ 949 int fr_ifpaddr(v, atype, qifptr, inp, inpmask) 950 int v, atype; 951 void *qifptr; 952 struct in_addr *inp, *inpmask; 953 { 954 #ifdef USE_INET6 955 struct sockaddr_in6 sin6, mask6; 956 #endif 957 struct sockaddr_in sin, mask; 958 qif_t *qif; 959 960 #ifdef USE_INET6 961 #ifdef IRE_ILL_CN 962 s_ill_t *ill; 963 #endif 964 #endif 965 if ((qifptr == NULL) || (qifptr == (void *)-1)) 966 return -1; 967 968 qif = qifptr; 969 970 #ifdef USE_INET6 971 #ifdef IRE_ILL_CN 972 ill = qif->qf_ill; 973 #endif 974 #endif 975 976 #ifdef USE_INET6 977 if (v == 6) { 978 #ifndef IRE_ILL_CN 979 in6_addr_t *inp6; 980 ipif_t *ipif; 981 ill_t *ill; 982 983 ill = qif->qf_ill; 984 985 /* 986 * First is always link local. 987 */ 988 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { 989 inp6 = &ipif->ipif_v6lcl_addr; 990 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 991 !IN6_IS_ADDR_LOOPBACK(inp6)) 992 break; 993 } 994 if (ipif == NULL) 995 return -1; 996 997 mask6.sin6_addr = ipif->ipif_v6net_mask; 998 if (atype == FRI_BROADCAST) 999 sin6.sin6_addr = ipif->ipif_v6brd_addr; 1000 else if (atype == FRI_PEERADDR) 1001 sin6.sin6_addr = ipif->ipif_v6pp_dst_addr; 1002 else 1003 sin6.sin6_addr = *inp6; 1004 #else /* IRE_ILL_CN */ 1005 if (IN6_IS_ADDR_UNSPECIFIED(&ill->netmask.in6.sin6_addr) || 1006 IN6_IS_ADDR_UNSPECIFIED(&ill->localaddr.in6.sin6_addr)) { 1007 rate_limit_message(NULLADDR_RATE_LIMIT, 1008 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1009 ill->ill_name); 1010 return -1; 1011 } 1012 mask6 = ill->netmask.in6; 1013 if (atype == FRI_BROADCAST) 1014 sin6 = ill->broadaddr.in6; 1015 else if (atype == FRI_PEERADDR) 1016 sin6 = ill->dstaddr.in6; 1017 else 1018 sin6 = ill->localaddr.in6; 1019 #endif /* IRE_ILL_CN */ 1020 return fr_ifpfillv6addr(atype, &sin6, &mask6, inp, inpmask); 1021 } 1022 #endif 1023 1024 #ifndef IRE_ILL_CN 1025 1026 switch (atype) 1027 { 1028 case FRI_BROADCAST : 1029 sin.sin_addr.s_addr = QF_V4_BROADCAST(qif); 1030 break; 1031 case FRI_PEERADDR : 1032 sin.sin_addr.s_addr = QF_V4_PEERADDR(qif); 1033 break; 1034 default : 1035 sin.sin_addr.s_addr = QF_V4_ADDR(qif); 1036 break; 1037 } 1038 mask.sin_addr.s_addr = QF_V4_NETMASK(qif); 1039 1040 #else 1041 if (ill->netmask.in.sin_addr.s_addr == 0 || 1042 ill->localaddr.in.sin_addr.s_addr == 0) { 1043 rate_limit_message(NULLADDR_RATE_LIMIT, 1044 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1045 ill->ill_name); 1046 return -1; 1047 } 1048 mask = ill->netmask.in; 1049 if (atype == FRI_BROADCAST) 1050 sin = ill->broadaddr.in; 1051 else if (atype == FRI_PEERADDR) 1052 sin = ill->dstaddr.in; 1053 else 1054 sin = ill->localaddr.in; 1055 #endif /* IRE_ILL_CN */ 1056 return fr_ifpfillv4addr(atype, &sin, &mask, inp, inpmask); 1057 } 1058 1059 1060 u_32_t fr_newisn(fin) 1061 fr_info_t *fin; 1062 { 1063 static int iss_seq_off = 0; 1064 u_char hash[16]; 1065 u_32_t newiss; 1066 MD5_CTX ctx; 1067 1068 /* 1069 * Compute the base value of the ISS. It is a hash 1070 * of (saddr, sport, daddr, dport, secret). 1071 */ 1072 MD5Init(&ctx); 1073 1074 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1075 sizeof(fin->fin_fi.fi_src)); 1076 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1077 sizeof(fin->fin_fi.fi_dst)); 1078 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1079 1080 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1081 1082 MD5Final(hash, &ctx); 1083 1084 bcopy(hash, &newiss, sizeof(newiss)); 1085 1086 /* 1087 * Now increment our "timer", and add it in to 1088 * the computed value. 1089 * 1090 * XXX Use `addin'? 1091 * XXX TCP_ISSINCR too large to use? 1092 */ 1093 iss_seq_off += 0x00010000; 1094 newiss += iss_seq_off; 1095 return newiss; 1096 } 1097 1098 1099 /* ------------------------------------------------------------------------ */ 1100 /* Function: fr_nextipid */ 1101 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1102 /* Parameters: fin(I) - pointer to packet information */ 1103 /* */ 1104 /* Returns the next IPv4 ID to use for this packet. */ 1105 /* ------------------------------------------------------------------------ */ 1106 u_short fr_nextipid(fin) 1107 fr_info_t *fin; 1108 { 1109 static u_short ipid = 0; 1110 ipstate_t *is; 1111 nat_t *nat; 1112 u_short id; 1113 1114 MUTEX_ENTER(&ipf_rw); 1115 if (fin->fin_state != NULL) { 1116 is = fin->fin_state; 1117 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1118 } else if (fin->fin_nat != NULL) { 1119 nat = fin->fin_nat; 1120 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1121 } else 1122 id = ipid++; 1123 MUTEX_EXIT(&ipf_rw); 1124 1125 return id; 1126 } 1127 1128 1129 #ifndef IPFILTER_CKSUM 1130 /* ARGSUSED */ 1131 #endif 1132 INLINE void fr_checkv4sum(fin) 1133 fr_info_t *fin; 1134 { 1135 #ifdef IPFILTER_CKSUM 1136 if (fr_checkl4sum(fin) == -1) 1137 fin->fin_flx |= FI_BAD; 1138 #endif 1139 } 1140 1141 1142 #ifdef USE_INET6 1143 # ifndef IPFILTER_CKSUM 1144 /* ARGSUSED */ 1145 # endif 1146 INLINE void fr_checkv6sum(fin) 1147 fr_info_t *fin; 1148 { 1149 # ifdef IPFILTER_CKSUM 1150 if (fr_checkl4sum(fin) == -1) 1151 fin->fin_flx |= FI_BAD; 1152 # endif 1153 } 1154 #endif /* USE_INET6 */ 1155 1156 1157 /* 1158 * Function: fr_verifysrc 1159 * Returns: int (really boolean) 1160 * Parameters: fin - packet information 1161 * 1162 * Check whether the packet has a valid source address for the interface on 1163 * which the packet arrived, implementing the "fr_chksrc" feature. 1164 * Returns true iff the packet's source address is valid. 1165 * Pre-Solaris 10, we call into the routing code to make the determination. 1166 * On Solaris 10 and later, we have a valid address set from pfild to check 1167 * against. 1168 */ 1169 int fr_verifysrc(fin) 1170 fr_info_t *fin; 1171 { 1172 ire_t *dir; 1173 int result; 1174 1175 #if SOLARIS2 >= 6 1176 dir = ire_route_lookup(fin->fin_saddr, 0xffffffff, 0, 0, NULL, 1177 NULL, NULL, NULL, MATCH_IRE_DSTONLY| 1178 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1179 #else 1180 dir = ire_lookup(fin->fin_saddr); 1181 #endif 1182 1183 if (!dir) 1184 return 0; 1185 result = (ire_to_ill(dir) == fin->fin_ifp); 1186 #if SOLARIS2 >= 8 1187 ire_refrele(dir); 1188 #endif 1189 return result; 1190 } 1191 1192 1193 #if (SOLARIS2 < 7) 1194 void fr_slowtimer() 1195 #else 1196 /*ARGSUSED*/ 1197 void fr_slowtimer __P((void *ptr)) 1198 #endif 1199 { 1200 1201 WRITE_ENTER(&ipf_global); 1202 if (fr_running <= 0) { 1203 if (fr_running == -1) 1204 fr_timer_id = timeout(fr_slowtimer, NULL, 1205 drv_usectohz(500000)); 1206 else 1207 fr_timer_id = NULL; 1208 RWLOCK_EXIT(&ipf_global); 1209 return; 1210 } 1211 MUTEX_DOWNGRADE(&ipf_global); 1212 1213 fr_fragexpire(); 1214 fr_timeoutstate(); 1215 fr_natexpire(); 1216 fr_authexpire(); 1217 fr_ticks++; 1218 if (fr_running == -1 || fr_running == 1) 1219 fr_timer_id = timeout(fr_slowtimer, NULL, drv_usectohz(500000)); 1220 else 1221 fr_timer_id = NULL; 1222 RWLOCK_EXIT(&ipf_global); 1223 } 1224 1225 1226 /* 1227 * Function: fr_fastroute 1228 * Returns: 0: success; 1229 * -1: failed 1230 * Parameters: 1231 * mb: the message block where ip head starts 1232 * mpp: the pointer to the pointer of the orignal 1233 * packet message 1234 * fin: packet information 1235 * fdp: destination interface information 1236 * if it is NULL, no interface information provided. 1237 * 1238 * This function is for fastroute/to/dup-to rules. It calls 1239 * pfil_make_lay2_packet to search route, make lay-2 header 1240 * ,and identify output queue for the IP packet. 1241 * The destination address depends on the following conditions: 1242 * 1: for fastroute rule, fdp is passed in as NULL, so the 1243 * destination address is the IP Packet's destination address 1244 * 2: for to/dup-to rule, if an ip address is specified after 1245 * the interface name, this address is the as destination 1246 * address. Otherwise IP Packet's destination address is used 1247 */ 1248 int fr_fastroute(mb, mpp, fin, fdp) 1249 mblk_t *mb, **mpp; 1250 fr_info_t *fin; 1251 frdest_t *fdp; 1252 { 1253 struct in_addr dst; 1254 #ifndef IRE_ILL_CN 1255 size_t hlen = 0; 1256 ill_t *ifp; 1257 ire_t *dir; 1258 u_char *s; 1259 frdest_t fd; 1260 #ifdef USE_INET6 1261 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 1262 #endif 1263 #else 1264 void *target = NULL; 1265 char *ifname = NULL; 1266 #endif 1267 queue_t *q = NULL; 1268 mblk_t *mp = NULL; 1269 qpktinfo_t *qpi; 1270 frentry_t *fr; 1271 qif_t *qif; 1272 ip_t *ip; 1273 #ifndef sparc 1274 u_short __iplen, __ipoff; 1275 #endif 1276 #ifdef USE_INET6 1277 struct in6_addr dst6; 1278 #endif 1279 #ifndef IRE_ILL_CN 1280 dir = NULL; 1281 #endif 1282 fr = fin->fin_fr; 1283 ip = fin->fin_ip; 1284 qpi = fin->fin_qpi; 1285 1286 /* 1287 * If this is a duplicate mblk then we want ip to point at that 1288 * data, not the original, if and only if it is already pointing at 1289 * the current mblk data. 1290 * Otherwise, If it's not a duplicate, and we're not already pointing 1291 * at the current mblk data, then we want to ensure that the data 1292 * points at ip. 1293 */ 1294 if (ip == (ip_t *)qpi->qpi_m->b_rptr && qpi->qpi_m != mb) 1295 ip = (ip_t *)mb->b_rptr; 1296 else if (qpi->qpi_m == mb && ip != (ip_t *)qpi->qpi_m->b_rptr) { 1297 qpi->qpi_m->b_rptr = (u_char *)ip; 1298 qpi->qpi_off = 0; 1299 } 1300 1301 /* 1302 * If there is another M_PROTO, we don't want it 1303 */ 1304 if (*mpp != mb) { 1305 mp = unlinkb(*mpp); 1306 freeb(*mpp); 1307 *mpp = mp; 1308 } 1309 1310 /* 1311 * If the fdp is NULL then there is no set route for this packet. 1312 */ 1313 if (fdp == NULL) { 1314 qif = fin->fin_ifp; 1315 #ifndef IRE_ILL_CN 1316 switch (fin->fin_v) 1317 { 1318 case 4 : 1319 fd.fd_ip = ip->ip_dst; 1320 break; 1321 #ifdef USE_INET6 1322 case 6 : 1323 fd.fd_ip6.in6 = ip6->ip6_dst; 1324 break; 1325 #endif 1326 } 1327 fdp = &fd; 1328 #endif 1329 } else { 1330 qif = fdp->fd_ifp; 1331 1332 if (qif == NULL || qif == (void *)-1) 1333 goto bad_fastroute; 1334 } 1335 1336 /* 1337 * In case we're here due to "to <if>" being used with 1338 * "keep state", check that we're going in the correct 1339 * direction. 1340 */ 1341 if ((fr != NULL) && (fin->fin_rev != 0)) { 1342 if ((qif != NULL) && (fdp == &fr->fr_tif)) 1343 return -1; 1344 dst.s_addr = fin->fin_fi.fi_daddr; 1345 } else { 1346 if (fin->fin_v == 4) { 1347 if (fdp && fdp->fd_ip.s_addr != 0) { 1348 dst = fdp->fd_ip; 1349 #ifdef IRE_ILL_CN 1350 target = &dst; 1351 #endif 1352 } else 1353 dst.s_addr = fin->fin_fi.fi_daddr; 1354 } 1355 #ifdef USE_INET6 1356 else if (fin->fin_v == 6) { 1357 if (fdp && IP6_NOTZERO(&fdp->fd_ip)) { 1358 dst6 = fdp->fd_ip6.in6; 1359 #ifdef IRE_ILL_CN 1360 target = &dst6; 1361 #endif 1362 } else 1363 dst6 = fin->fin_dst6; 1364 } 1365 #endif 1366 else 1367 goto bad_fastroute; 1368 } 1369 1370 #ifndef IRE_ILL_CN 1371 #if SOLARIS2 >= 6 1372 if (fin->fin_v == 4) { 1373 dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, 1374 NULL, NULL, MATCH_IRE_DSTONLY| 1375 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1376 } 1377 # ifdef USE_INET6 1378 else if (fin->fin_v == 6) { 1379 dir = ire_route_lookup_v6(&ip6->ip6_dst, NULL, 0, 0, 1380 NULL, NULL, NULL, MATCH_IRE_DSTONLY| 1381 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1382 } 1383 # endif 1384 #else 1385 dir = ire_lookup(dst.s_addr); 1386 #endif 1387 #if SOLARIS2 < 8 1388 if (dir != NULL) 1389 if (dir->ire_ll_hdr_mp == NULL || dir->ire_ll_hdr_length == 0) 1390 dir = NULL; 1391 1392 #elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) 1393 if (dir != NULL) { 1394 if (dir->ire_fp_mp == NULL || dir->ire_dlureq_mp == NULL) { 1395 ire_refrele(dir); 1396 dir = NULL; 1397 } 1398 } 1399 #else 1400 1401 if (dir != NULL) 1402 if (dir->ire_nce && dir->ire_nce->nce_state != ND_REACHABLE) { 1403 ire_refrele(dir); 1404 dir = NULL; 1405 } 1406 #endif 1407 #else /* IRE_ILL_CN */ 1408 if (fdp && fdp->fd_ifname[0] != 0) 1409 ifname = fdp->fd_ifname; 1410 1411 DB_CKSUMFLAGS(mb) = 0; /* disable hardware checksum */ 1412 mp = pfil_make_dl_packet(mb, ip, target, ifname, &q); 1413 if (mp == NULL) 1414 { 1415 goto bad_fastroute; 1416 } 1417 mb = mp; 1418 #endif /* IRE_ILL_CN */ 1419 1420 #ifdef IRE_ILL_CN 1421 if (mp != NULL) { 1422 #else 1423 if (dir != NULL) { 1424 #if SOLARIS2 < 8 1425 mp = dir->ire_ll_hdr_mp; 1426 hlen = dir->ire_ll_hdr_length; 1427 #elif (SOLARIS2 >= 8) && (SOLARIS2 <= 10) 1428 mp = dir->ire_fp_mp; 1429 hlen = mp ? mp->b_wptr - mp->b_rptr : 0; 1430 if (mp == NULL) 1431 mp = dir->ire_dlureq_mp; 1432 #else 1433 mp = dir->ire_nce->nce_fp_mp; 1434 hlen = mp ? mp->b_wptr - mp->b_rptr : 0; 1435 if (mp == NULL) 1436 mp = dir->ire_nce->nce_res_mp; 1437 #endif 1438 #endif 1439 if (fin->fin_out == 0) { 1440 void *saveqif; 1441 u_32_t pass; 1442 1443 saveqif = fin->fin_ifp; 1444 fin->fin_ifp = qif; 1445 fin->fin_out = 1; 1446 (void)fr_acctpkt(fin, &pass); 1447 fin->fin_fr = NULL; 1448 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1449 (void) fr_checkstate(fin, &pass); 1450 1451 switch (fr_checknatout(fin, NULL)) 1452 { 1453 /* FALLTHROUGH */ 1454 case 0 : 1455 case 1 : 1456 break; 1457 case -1 : 1458 goto bad_fastroute; 1459 } 1460 1461 fin->fin_out = 0; 1462 fin->fin_ifp = saveqif; 1463 } 1464 #ifndef sparc 1465 if (fin->fin_v == 4) { 1466 __iplen = (u_short)ip->ip_len, 1467 __ipoff = (u_short)ip->ip_off; 1468 1469 ip->ip_len = htons(__iplen); 1470 ip->ip_off = htons(__ipoff); 1471 } 1472 #endif 1473 #ifndef IRE_ILL_CN 1474 ifp = qif->qf_ill; 1475 1476 if (mp != NULL) { 1477 s = mb->b_rptr; 1478 if ( 1479 #if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 1480 (dohwcksum && 1481 ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC) || 1482 #endif 1483 (hlen && (s - mb->b_datap->db_base) >= hlen)) { 1484 s -= hlen; 1485 mb->b_rptr = (u_char *)s; 1486 bcopy((char *)mp->b_rptr, (char *)s, hlen); 1487 } else { 1488 mblk_t *mp2; 1489 1490 mp2 = copyb(mp); 1491 if (mp2 == NULL) 1492 goto bad_fastroute; 1493 linkb(mp2, mb); 1494 mb = mp2; 1495 } 1496 } 1497 *mpp = mb; 1498 1499 if (dir->ire_stq != NULL) 1500 q = dir->ire_stq; 1501 else if (dir->ire_rfq != NULL) 1502 q = WR(dir->ire_rfq); 1503 if (q != NULL) 1504 q = q->q_next; 1505 if (q != NULL) { 1506 RWLOCK_EXIT(&ipf_global); 1507 #if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 1508 if ((fin->fin_p == IPPROTO_TCP) && dohwcksum && 1509 (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { 1510 tcphdr_t *tcp; 1511 u_32_t t; 1512 1513 tcp = (tcphdr_t *)((char *)ip + fin->fin_hlen); 1514 t = ip->ip_src.s_addr; 1515 t += ip->ip_dst.s_addr; 1516 t += 30; 1517 t = (t & 0xffff) + (t >> 16); 1518 tcp->th_sum = t & 0xffff; 1519 } 1520 #endif 1521 putnext(q, mb); 1522 ATOMIC_INCL(fr_frouteok[0]); 1523 #if SOLARIS2 >= 8 1524 ire_refrele(dir); 1525 #endif 1526 READ_ENTER(&ipf_global); 1527 return 0; 1528 } 1529 #else /* IRE_ILL_CN */ 1530 mb->b_queue = q; 1531 *mpp = mb; 1532 pfil_send_dl_packet(q, mb); 1533 ATOMIC_INCL(fr_frouteok[0]); 1534 return 0; 1535 #endif /* IRE_ILL_CN */ 1536 } 1537 bad_fastroute: 1538 #ifndef IRE_ILL_CN 1539 #if SOLARIS2 >= 8 1540 if (dir != NULL) 1541 ire_refrele(dir); 1542 #endif 1543 #endif 1544 freemsg(mb); 1545 ATOMIC_INCL(fr_frouteok[1]); 1546 return -1; 1547 } 1548 1549 1550 /* ------------------------------------------------------------------------ */ 1551 /* Function: fr_pullup */ 1552 /* Returns: NULL == pullup failed, else pointer to protocol header */ 1553 /* Parameters: m(I) - pointer to buffer where data packet starts */ 1554 /* fin(I) - pointer to packet information */ 1555 /* len(I) - number of bytes to pullup */ 1556 /* */ 1557 /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1558 /* single buffer for ease of access. Operating system native functions are */ 1559 /* used to manage buffers - if necessary. If the entire packet ends up in */ 1560 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1561 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1562 /* and ONLY if the pullup succeeds. */ 1563 /* */ 1564 /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1565 /* of buffers that starts at *fin->fin_mp. */ 1566 /* ------------------------------------------------------------------------ */ 1567 void *fr_pullup(min, fin, len) 1568 mb_t *min; 1569 fr_info_t *fin; 1570 int len; 1571 { 1572 qpktinfo_t *qpi = fin->fin_qpi; 1573 int out = fin->fin_out, dpoff, ipoff; 1574 mb_t *m = min; 1575 char *ip; 1576 1577 if (m == NULL) 1578 return NULL; 1579 1580 ip = (char *)fin->fin_ip; 1581 if ((fin->fin_flx & FI_COALESCE) != 0) 1582 return ip; 1583 1584 ipoff = fin->fin_ipoff; 1585 if (fin->fin_dp != NULL) 1586 dpoff = (char *)fin->fin_dp - (char *)ip; 1587 else 1588 dpoff = 0; 1589 1590 if (M_LEN(m) < len) { 1591 1592 /* 1593 * pfil_precheck ensures the IP header is on a 32bit 1594 * aligned address so simply fail if that isn't currently 1595 * the case (should never happen). 1596 */ 1597 int inc = 0; 1598 1599 if (ipoff > 0) { 1600 if ((ipoff & 3) != 0) { 1601 inc = 4 - (ipoff & 3); 1602 if (m->b_rptr - inc >= m->b_datap->db_base) 1603 m->b_rptr -= inc; 1604 else 1605 inc = 0; 1606 } 1607 } 1608 if (pullupmsg(m, len + ipoff + inc) == 0) { 1609 ATOMIC_INCL(frstats[out].fr_pull[1]); 1610 FREE_MB_T(*fin->fin_mp); 1611 *fin->fin_mp = NULL; 1612 fin->fin_m = NULL; 1613 fin->fin_ip = NULL; 1614 fin->fin_dp = NULL; 1615 qpi->qpi_data = NULL; 1616 return NULL; 1617 } 1618 m->b_rptr += inc; 1619 fin->fin_m = m; 1620 ip = MTOD(m, char *) + ipoff; 1621 qpi->qpi_data = ip; 1622 } 1623 1624 ATOMIC_INCL(frstats[out].fr_pull[0]); 1625 fin->fin_ip = (ip_t *)ip; 1626 if (fin->fin_dp != NULL) 1627 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1628 1629 if (len == fin->fin_plen) 1630 fin->fin_flx |= FI_COALESCE; 1631 return ip; 1632 } 1633