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[] = "%W% %G% (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 } else 695 #endif 696 { 697 fnew.fin_v = 4; 698 #if SOLARIS2 >= 10 699 ip->ip_ttl = 255; 700 701 ip->ip_off = htons(IP_DF); 702 #else 703 if (ip_ttl_ptr != NULL) 704 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 705 else 706 ip->ip_ttl = 63; 707 if (ip_mtudisc != NULL) 708 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 709 else 710 ip->ip_off = htons(IP_DF); 711 #endif 712 /* 713 * The dance with byte order and ip_len/ip_off is because in 714 * fr_fastroute, it expects them to be in host byte order but 715 * ipf_cksum expects them to be in network byte order. 716 */ 717 ip->ip_len = htons(ip->ip_len); 718 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 719 ip->ip_len = ntohs(ip->ip_len); 720 ip->ip_off = ntohs(ip->ip_off); 721 hlen = sizeof(*ip); 722 } 723 724 qpip = fin->fin_qpi; 725 qpi.qpi_q = qpip->qpi_q; 726 qpi.qpi_off = 0; 727 qpi.qpi_name = qpip->qpi_name; 728 qif = qpip->qpi_real; 729 qpi.qpi_real = qif; 730 qpi.qpi_ill = qif->qf_ill; 731 qpi.qpi_hl = qif->qf_hl; 732 qpi.qpi_ppa = qif->qf_ppa; 733 qpi.qpi_num = qif->qf_num; 734 qpi.qpi_flags = qif->qf_flags; 735 qpi.qpi_max_frag = qif->qf_max_frag; 736 qpi.qpi_m = m; 737 qpi.qpi_data = ip; 738 fnew.fin_qpi = &qpi; 739 fnew.fin_ifp = fin->fin_ifp; 740 fnew.fin_flx = FI_NOCKSUM; 741 fnew.fin_m = m; 742 fnew.fin_ip = ip; 743 fnew.fin_mp = mpp; 744 fnew.fin_hlen = hlen; 745 fnew.fin_dp = (char *)ip + hlen; 746 (void) fr_makefrip(hlen, ip, &fnew); 747 748 i = fr_fastroute(m, mpp, &fnew, NULL); 749 return i; 750 } 751 752 753 int fr_send_icmp_err(type, fin, dst) 754 int type; 755 fr_info_t *fin; 756 int dst; 757 { 758 struct in_addr dst4; 759 struct icmp *icmp; 760 qpktinfo_t *qpi; 761 int hlen, code; 762 u_short sz; 763 #ifdef USE_INET6 764 mblk_t *mb; 765 #endif 766 mblk_t *m; 767 #ifdef USE_INET6 768 ip6_t *ip6; 769 #endif 770 ip_t *ip; 771 772 if ((type < 0) || (type > ICMP_MAXTYPE)) 773 return -1; 774 775 code = fin->fin_icode; 776 #ifdef USE_INET6 777 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 778 return -1; 779 #endif 780 781 #ifndef IPFILTER_CKSUM 782 if (fr_checkl4sum(fin) == -1) 783 return -1; 784 #endif 785 786 qpi = fin->fin_qpi; 787 788 #ifdef USE_INET6 789 mb = fin->fin_qfm; 790 791 if (fin->fin_v == 6) { 792 sz = sizeof(ip6_t); 793 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 794 hlen = sizeof(ip6_t); 795 type = icmptoicmp6types[type]; 796 if (type == ICMP6_DST_UNREACH) 797 code = icmptoicmp6unreach[code]; 798 } else 799 #endif 800 { 801 if ((fin->fin_p == IPPROTO_ICMP) && 802 !(fin->fin_flx & FI_SHORT)) 803 switch (ntohs(fin->fin_data[0]) >> 8) 804 { 805 case ICMP_ECHO : 806 case ICMP_TSTAMP : 807 case ICMP_IREQ : 808 case ICMP_MASKREQ : 809 break; 810 default : 811 return 0; 812 } 813 814 sz = sizeof(ip_t) * 2; 815 sz += 8; /* 64 bits of data */ 816 hlen = sizeof(ip_t); 817 } 818 819 sz += offsetof(struct icmp, icmp_ip); 820 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 821 return -1; 822 MTYPE(m) = M_DATA; 823 m->b_rptr += 64; 824 m->b_wptr = m->b_rptr + sz; 825 bzero((char *)m->b_rptr, (size_t)sz); 826 ip = (ip_t *)m->b_rptr; 827 ip->ip_v = fin->fin_v; 828 icmp = (struct icmp *)(m->b_rptr + hlen); 829 icmp->icmp_type = type & 0xff; 830 icmp->icmp_code = code & 0xff; 831 #ifdef icmp_nextmtu 832 if (type == ICMP_UNREACH && (qpi->qpi_max_frag != 0) && 833 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 834 icmp->icmp_nextmtu = htons(qpi->qpi_max_frag); 835 #endif 836 837 #ifdef USE_INET6 838 if (fin->fin_v == 6) { 839 struct in6_addr dst6; 840 int csz; 841 842 if (dst == 0) { 843 if (fr_ifpaddr(6, FRI_NORMAL, qpi->qpi_real, 844 (struct in_addr *)&dst6, NULL) == -1) { 845 FREE_MB_T(m); 846 return -1; 847 } 848 } else 849 dst6 = fin->fin_dst6; 850 851 csz = sz; 852 sz -= sizeof(ip6_t); 853 ip6 = (ip6_t *)m->b_rptr; 854 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 855 ip6->ip6_plen = htons((u_short)sz); 856 ip6->ip6_nxt = IPPROTO_ICMPV6; 857 ip6->ip6_src = dst6; 858 ip6->ip6_dst = fin->fin_src6; 859 sz -= offsetof(struct icmp, icmp_ip); 860 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 861 icmp->icmp_cksum = csz - sizeof(ip6_t); 862 } else 863 #endif 864 { 865 ip->ip_hl = sizeof(*ip) >> 2; 866 ip->ip_p = IPPROTO_ICMP; 867 ip->ip_id = fin->fin_ip->ip_id; 868 ip->ip_tos = fin->fin_ip->ip_tos; 869 ip->ip_len = (u_short)sz; 870 if (dst == 0) { 871 if (fr_ifpaddr(4, FRI_NORMAL, qpi->qpi_real, 872 &dst4, NULL) == -1) { 873 FREE_MB_T(m); 874 return -1; 875 } 876 } else 877 dst4 = fin->fin_dst; 878 ip->ip_src = dst4; 879 ip->ip_dst = fin->fin_src; 880 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 881 sizeof(*fin->fin_ip)); 882 bcopy((char *)fin->fin_ip + fin->fin_hlen, 883 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 884 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 885 icmp->icmp_ip.ip_off = htons(icmp->icmp_ip.ip_off); 886 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 887 sz - sizeof(ip_t)); 888 } 889 890 /* 891 * Need to exit out of these so we don't recursively call rw_enter 892 * from fr_qout. 893 */ 894 return fr_send_ip(fin, m, &m); 895 } 896 897 #ifdef IRE_ILL_CN 898 #include <sys/time.h> 899 #include <sys/varargs.h> 900 901 #ifndef _KERNEL 902 #include <stdio.h> 903 #endif 904 905 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 906 907 908 /* 909 * Print out warning message at rate-limited speed. 910 */ 911 static void rate_limit_message(int rate, const char *message, ...) 912 { 913 static time_t last_time = 0; 914 time_t now; 915 va_list args; 916 char msg_buf[256]; 917 int need_printed = 0; 918 919 now = ddi_get_time(); 920 921 /* make sure, no multiple entries */ 922 ASSERT(MUTEX_NOT_HELD(&(ipf_rw.ipf_lk))); 923 MUTEX_ENTER(&ipf_rw); 924 if (now - last_time >= rate) { 925 need_printed = 1; 926 last_time = now; 927 } 928 MUTEX_EXIT(&ipf_rw); 929 930 if (need_printed) { 931 va_start(args, message); 932 (void)vsnprintf(msg_buf, 255, message, args); 933 va_end(args); 934 #ifdef _KERNEL 935 cmn_err(CE_WARN, msg_buf); 936 #else 937 fprintf(std_err, msg_buf); 938 #endif 939 } 940 } 941 #endif 942 943 /* 944 * return the first IP Address associated with an interface 945 */ 946 /*ARGSUSED*/ 947 int fr_ifpaddr(v, atype, qifptr, inp, inpmask) 948 int v, atype; 949 void *qifptr; 950 struct in_addr *inp, *inpmask; 951 { 952 #ifdef USE_INET6 953 struct sockaddr_in6 sin6, mask6; 954 #endif 955 struct sockaddr_in sin, mask; 956 qif_t *qif; 957 958 #ifdef USE_INET6 959 #ifdef IRE_ILL_CN 960 s_ill_t *ill; 961 #endif 962 #endif 963 if ((qifptr == NULL) || (qifptr == (void *)-1)) 964 return -1; 965 966 qif = qifptr; 967 968 #ifdef USE_INET6 969 #ifdef IRE_ILL_CN 970 ill = qif->qf_ill; 971 #endif 972 #endif 973 974 #ifdef USE_INET6 975 if (v == 6) { 976 #ifndef IRE_ILL_CN 977 in6_addr_t *inp6; 978 ipif_t *ipif; 979 ill_t *ill; 980 981 ill = qif->qf_ill; 982 983 /* 984 * First is always link local. 985 */ 986 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { 987 inp6 = &ipif->ipif_v6lcl_addr; 988 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 989 !IN6_IS_ADDR_LOOPBACK(inp6)) 990 break; 991 } 992 if (ipif == NULL) 993 return -1; 994 995 mask6.sin6_addr = ipif->ipif_v6net_mask; 996 if (atype == FRI_BROADCAST) 997 sin6.sin6_addr = ipif->ipif_v6brd_addr; 998 else if (atype == FRI_PEERADDR) 999 sin6.sin6_addr = ipif->ipif_v6pp_dst_addr; 1000 else 1001 sin6.sin6_addr = *inp6; 1002 #else /* IRE_ILL_CN */ 1003 if (IN6_IS_ADDR_UNSPECIFIED(&ill->netmask.in6.sin6_addr) || 1004 IN6_IS_ADDR_UNSPECIFIED(&ill->localaddr.in6.sin6_addr)) { 1005 rate_limit_message(NULLADDR_RATE_LIMIT, 1006 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1007 ill->ill_name); 1008 return -1; 1009 } 1010 mask6 = ill->netmask.in6; 1011 if (atype == FRI_BROADCAST) 1012 sin6 = ill->broadaddr.in6; 1013 else if (atype == FRI_PEERADDR) 1014 sin6 = ill->dstaddr.in6; 1015 else 1016 sin6 = ill->localaddr.in6; 1017 #endif /* IRE_ILL_CN */ 1018 return fr_ifpfillv6addr(atype, &sin6, &mask6, inp, inpmask); 1019 } 1020 #endif 1021 1022 #ifndef IRE_ILL_CN 1023 1024 switch (atype) 1025 { 1026 case FRI_BROADCAST : 1027 sin.sin_addr.s_addr = QF_V4_BROADCAST(qif); 1028 break; 1029 case FRI_PEERADDR : 1030 sin.sin_addr.s_addr = QF_V4_PEERADDR(qif); 1031 break; 1032 default : 1033 sin.sin_addr.s_addr = QF_V4_ADDR(qif); 1034 break; 1035 } 1036 mask.sin_addr.s_addr = QF_V4_NETMASK(qif); 1037 1038 #else 1039 if (ill->netmask.in.sin_addr.s_addr == 0 || 1040 ill->localaddr.in.sin_addr.s_addr == 0) { 1041 rate_limit_message(NULLADDR_RATE_LIMIT, 1042 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1043 ill->ill_name); 1044 return -1; 1045 } 1046 mask = ill->netmask.in; 1047 if (atype == FRI_BROADCAST) 1048 sin = ill->broadaddr.in; 1049 else if (atype == FRI_PEERADDR) 1050 sin = ill->dstaddr.in; 1051 else 1052 sin = ill->localaddr.in; 1053 #endif /* IRE_ILL_CN */ 1054 return fr_ifpfillv4addr(atype, &sin, &mask, inp, inpmask); 1055 } 1056 1057 1058 u_32_t fr_newisn(fin) 1059 fr_info_t *fin; 1060 { 1061 static int iss_seq_off = 0; 1062 u_char hash[16]; 1063 u_32_t newiss; 1064 MD5_CTX ctx; 1065 1066 /* 1067 * Compute the base value of the ISS. It is a hash 1068 * of (saddr, sport, daddr, dport, secret). 1069 */ 1070 MD5Init(&ctx); 1071 1072 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1073 sizeof(fin->fin_fi.fi_src)); 1074 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1075 sizeof(fin->fin_fi.fi_dst)); 1076 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1077 1078 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1079 1080 MD5Final(hash, &ctx); 1081 1082 bcopy(hash, &newiss, sizeof(newiss)); 1083 1084 /* 1085 * Now increment our "timer", and add it in to 1086 * the computed value. 1087 * 1088 * XXX Use `addin'? 1089 * XXX TCP_ISSINCR too large to use? 1090 */ 1091 iss_seq_off += 0x00010000; 1092 newiss += iss_seq_off; 1093 return newiss; 1094 } 1095 1096 1097 /* ------------------------------------------------------------------------ */ 1098 /* Function: fr_nextipid */ 1099 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1100 /* Parameters: fin(I) - pointer to packet information */ 1101 /* */ 1102 /* Returns the next IPv4 ID to use for this packet. */ 1103 /* ------------------------------------------------------------------------ */ 1104 u_short fr_nextipid(fin) 1105 fr_info_t *fin; 1106 { 1107 static u_short ipid = 0; 1108 ipstate_t *is; 1109 nat_t *nat; 1110 u_short id; 1111 1112 MUTEX_ENTER(&ipf_rw); 1113 if (fin->fin_state != NULL) { 1114 is = fin->fin_state; 1115 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1116 } else if (fin->fin_nat != NULL) { 1117 nat = fin->fin_nat; 1118 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1119 } else 1120 id = ipid++; 1121 MUTEX_EXIT(&ipf_rw); 1122 1123 return id; 1124 } 1125 1126 1127 #ifndef IPFILTER_CKSUM 1128 /* ARGSUSED */ 1129 #endif 1130 INLINE void fr_checkv4sum(fin) 1131 fr_info_t *fin; 1132 { 1133 #ifdef IPFILTER_CKSUM 1134 if (fr_checkl4sum(fin) == -1) 1135 fin->fin_flx |= FI_BAD; 1136 #endif 1137 } 1138 1139 1140 #ifdef USE_INET6 1141 # ifndef IPFILTER_CKSUM 1142 /* ARGSUSED */ 1143 # endif 1144 INLINE void fr_checkv6sum(fin) 1145 fr_info_t *fin; 1146 { 1147 # ifdef IPFILTER_CKSUM 1148 if (fr_checkl4sum(fin) == -1) 1149 fin->fin_flx |= FI_BAD; 1150 # endif 1151 } 1152 #endif /* USE_INET6 */ 1153 1154 1155 /* 1156 * Function: fr_verifysrc 1157 * Returns: int (really boolean) 1158 * Parameters: fin - packet information 1159 * 1160 * Check whether the packet has a valid source address for the interface on 1161 * which the packet arrived, implementing the "fr_chksrc" feature. 1162 * Returns true iff the packet's source address is valid. 1163 * Pre-Solaris 10, we call into the routing code to make the determination. 1164 * On Solaris 10 and later, we have a valid address set from pfild to check 1165 * against. 1166 */ 1167 int fr_verifysrc(fin) 1168 fr_info_t *fin; 1169 { 1170 ire_t *dir; 1171 int result; 1172 1173 #if SOLARIS2 >= 6 1174 dir = ire_route_lookup(fin->fin_saddr, 0xffffffff, 0, 0, NULL, 1175 NULL, NULL, NULL, MATCH_IRE_DSTONLY| 1176 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1177 #else 1178 dir = ire_lookup(fin->fin_saddr); 1179 #endif 1180 1181 if (!dir) 1182 return 0; 1183 result = (ire_to_ill(dir) == fin->fin_ifp); 1184 #if SOLARIS2 >= 8 1185 ire_refrele(dir); 1186 #endif 1187 return result; 1188 } 1189 1190 1191 #if (SOLARIS2 < 7) 1192 void fr_slowtimer() 1193 #else 1194 /*ARGSUSED*/ 1195 void fr_slowtimer __P((void *ptr)) 1196 #endif 1197 { 1198 1199 WRITE_ENTER(&ipf_global); 1200 if (fr_running <= 0) { 1201 if (fr_running == -1) 1202 fr_timer_id = timeout(fr_slowtimer, NULL, 1203 drv_usectohz(500000)); 1204 else 1205 fr_timer_id = NULL; 1206 RWLOCK_EXIT(&ipf_global); 1207 return; 1208 } 1209 MUTEX_DOWNGRADE(&ipf_global); 1210 1211 fr_fragexpire(); 1212 fr_timeoutstate(); 1213 fr_natexpire(); 1214 fr_authexpire(); 1215 fr_ticks++; 1216 if (fr_running == -1 || fr_running == 1) 1217 fr_timer_id = timeout(fr_slowtimer, NULL, drv_usectohz(500000)); 1218 else 1219 fr_timer_id = NULL; 1220 RWLOCK_EXIT(&ipf_global); 1221 } 1222 1223 1224 /* 1225 * Function: fr_fastroute 1226 * Returns: 0: success; 1227 * -1: failed 1228 * Parameters: 1229 * mb: the message block where ip head starts 1230 * mpp: the pointer to the pointer of the orignal 1231 * packet message 1232 * fin: packet information 1233 * fdp: destination interface information 1234 * if it is NULL, no interface information provided. 1235 * 1236 * This function is for fastroute/to/dup-to rules. It calls 1237 * pfil_make_lay2_packet to search route, make lay-2 header 1238 * ,and identify output queue for the IP packet. 1239 * The destination address depends on the following conditions: 1240 * 1: for fastroute rule, fdp is passed in as NULL, so the 1241 * destination address is the IP Packet's destination address 1242 * 2: for to/dup-to rule, if an ip address is specified after 1243 * the interface name, this address is the as destination 1244 * address. Otherwise IP Packet's destination address is used 1245 */ 1246 int fr_fastroute(mb, mpp, fin, fdp) 1247 mblk_t *mb, **mpp; 1248 fr_info_t *fin; 1249 frdest_t *fdp; 1250 { 1251 struct in_addr dst; 1252 #ifndef IRE_ILL_CN 1253 size_t hlen = 0; 1254 ill_t *ifp; 1255 ire_t *dir; 1256 u_char *s; 1257 frdest_t fd; 1258 #ifdef USE_INET6 1259 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 1260 #endif 1261 #else 1262 void *target = NULL; 1263 char *ifname = NULL; 1264 #endif 1265 queue_t *q = NULL; 1266 mblk_t *mp = NULL; 1267 qpktinfo_t *qpi; 1268 frentry_t *fr; 1269 qif_t *qif; 1270 ip_t *ip; 1271 #ifndef sparc 1272 u_short __iplen, __ipoff; 1273 #endif 1274 #ifdef USE_INET6 1275 struct in6_addr dst6; 1276 #endif 1277 #ifndef IRE_ILL_CN 1278 dir = NULL; 1279 #endif 1280 fr = fin->fin_fr; 1281 ip = fin->fin_ip; 1282 qpi = fin->fin_qpi; 1283 1284 /* 1285 * If this is a duplicate mblk then we want ip to point at that 1286 * data, not the original, if and only if it is already pointing at 1287 * the current mblk data. 1288 */ 1289 if (ip == (ip_t *)qpi->qpi_m->b_rptr && qpi->qpi_m != mb) 1290 ip = (ip_t *)mb->b_rptr; 1291 1292 /* 1293 * If there is another M_PROTO, we don't want it 1294 */ 1295 if (*mpp != mb) { 1296 mp = unlinkb(*mpp); 1297 freeb(*mpp); 1298 *mpp = mp; 1299 } 1300 1301 #ifdef IRE_ILL_CN 1302 if (fdp != NULL) { 1303 #else 1304 /* 1305 * If the fdp is NULL then there is no set route for this packet. 1306 */ 1307 if (fdp == NULL) { 1308 qif = fin->fin_ifp; 1309 1310 switch (fin->fin_v) 1311 { 1312 case 4 : 1313 fd.fd_ip = ip->ip_dst; 1314 break; 1315 #ifdef USE_INET6 1316 case 6 : 1317 fd.fd_ip6.in6 = ip6->ip6_dst; 1318 break; 1319 #endif 1320 } 1321 fdp = &fd; 1322 } else { 1323 #endif 1324 qif = fdp->fd_ifp; 1325 1326 if (qif == NULL || qif == (void *)-1) 1327 goto bad_fastroute; 1328 } 1329 1330 /* 1331 * In case we're here due to "to <if>" being used with 1332 * "keep state", check that we're going in the correct 1333 * direction. 1334 */ 1335 if ((fr != NULL) && (fin->fin_rev != 0)) { 1336 if ((qif != NULL) && (fdp == &fr->fr_tif)) 1337 return -1; 1338 dst.s_addr = fin->fin_fi.fi_daddr; 1339 } else { 1340 if (fin->fin_v == 4) { 1341 if (fdp && fdp->fd_ip.s_addr != 0) { 1342 dst = fdp->fd_ip; 1343 #ifdef IRE_ILL_CN 1344 target = &dst; 1345 #endif 1346 } else 1347 dst.s_addr = fin->fin_fi.fi_daddr; 1348 } 1349 #ifdef USE_INET6 1350 else if (fin->fin_v == 6) { 1351 if (fdp && IP6_NOTZERO(&fdp->fd_ip)) { 1352 dst6 = fdp->fd_ip6.in6; 1353 #ifdef IRE_ILL_CN 1354 target = &dst6; 1355 #endif 1356 } else 1357 dst6 = fin->fin_dst6; 1358 } 1359 #endif 1360 else 1361 goto bad_fastroute; 1362 } 1363 1364 #ifndef IRE_ILL_CN 1365 #if SOLARIS2 >= 6 1366 if (fin->fin_v == 4) { 1367 dir = ire_route_lookup(dst.s_addr, 0xffffffff, 0, 0, NULL, 1368 NULL, NULL, MATCH_IRE_DSTONLY| 1369 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1370 } 1371 # ifdef USE_INET6 1372 else if (fin->fin_v == 6) { 1373 dir = ire_route_lookup_v6(&ip6->ip6_dst, NULL, 0, 0, 1374 NULL, NULL, NULL, MATCH_IRE_DSTONLY| 1375 MATCH_IRE_DEFAULT|MATCH_IRE_RECURSIVE); 1376 } 1377 # endif 1378 #else 1379 dir = ire_lookup(dst.s_addr); 1380 #endif 1381 #if SOLARIS2 < 8 1382 if (dir != NULL) 1383 if (dir->ire_ll_hdr_mp == NULL || dir->ire_ll_hdr_length == 0) 1384 dir = NULL; 1385 #else 1386 if (dir != NULL) 1387 if (dir->ire_fp_mp == NULL || dir->ire_dlureq_mp == NULL) { 1388 ire_refrele(dir); 1389 dir = NULL; 1390 } 1391 #endif 1392 #else /* IRE_ILL_CN */ 1393 if (fdp && fdp->fd_ifname[0] != 0) 1394 ifname = fdp->fd_ifname; 1395 1396 DB_CKSUMFLAGS(mb) = 0; /* disable hardware checksum */ 1397 mp = pfil_make_dl_packet(mb, ip, target, ifname, &q); 1398 if (mp == NULL) 1399 { 1400 goto bad_fastroute; 1401 } 1402 mb = mp; 1403 #endif /* IRE_ILL_CN */ 1404 1405 #ifdef IRE_ILL_CN 1406 if (mp != NULL) { 1407 #else 1408 if (dir != NULL) { 1409 #if SOLARIS2 < 8 1410 mp = dir->ire_ll_hdr_mp; 1411 hlen = dir->ire_ll_hdr_length; 1412 #else 1413 mp = dir->ire_fp_mp; 1414 hlen = mp ? mp->b_wptr - mp->b_rptr : 0; 1415 if (mp == NULL) 1416 mp = dir->ire_dlureq_mp; 1417 #endif 1418 #endif 1419 if (fin->fin_out == 0) { 1420 void *saveqif; 1421 u_32_t pass; 1422 1423 saveqif = fin->fin_ifp; 1424 fin->fin_ifp = qif; 1425 fin->fin_out = 1; 1426 (void)fr_acctpkt(fin, &pass); 1427 fin->fin_fr = NULL; 1428 if (!fr || !(fr->fr_flags & FR_RETMASK)) 1429 (void) fr_checkstate(fin, &pass); 1430 1431 switch (fr_checknatout(fin, NULL)) 1432 { 1433 /* FALLTHROUGH */ 1434 case 0 : 1435 case 1 : 1436 break; 1437 case -1 : 1438 goto bad_fastroute; 1439 } 1440 1441 fin->fin_out = 0; 1442 fin->fin_ifp = saveqif; 1443 } 1444 #ifndef sparc 1445 if (fin->fin_v == 4) { 1446 __iplen = (u_short)ip->ip_len, 1447 __ipoff = (u_short)ip->ip_off; 1448 1449 ip->ip_len = htons(__iplen); 1450 ip->ip_off = htons(__ipoff); 1451 } 1452 #endif 1453 #ifndef IRE_ILL_CN 1454 ifp = qif->qf_ill; 1455 1456 if (mp != NULL) { 1457 s = mb->b_rptr; 1458 if ( 1459 #if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 1460 (dohwcksum && 1461 ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC) || 1462 #endif 1463 (hlen && (s - mb->b_datap->db_base) >= hlen)) { 1464 s -= hlen; 1465 mb->b_rptr = (u_char *)s; 1466 bcopy((char *)mp->b_rptr, (char *)s, hlen); 1467 } else { 1468 mblk_t *mp2; 1469 1470 mp2 = copyb(mp); 1471 if (mp2 == NULL) 1472 goto bad_fastroute; 1473 linkb(mp2, mb); 1474 mb = mp2; 1475 } 1476 } 1477 *mpp = mb; 1478 1479 if (dir->ire_stq != NULL) 1480 q = dir->ire_stq; 1481 else if (dir->ire_rfq != NULL) 1482 q = WR(dir->ire_rfq); 1483 if (q != NULL) 1484 q = q->q_next; 1485 if (q != NULL) { 1486 RWLOCK_EXIT(&ipf_global); 1487 #if (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC) 1488 if ((fin->fin_p == IPPROTO_TCP) && dohwcksum && 1489 (ifp->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { 1490 tcphdr_t *tcp; 1491 u_32_t t; 1492 1493 tcp = (tcphdr_t *)((char *)ip + fin->fin_hlen); 1494 t = ip->ip_src.s_addr; 1495 t += ip->ip_dst.s_addr; 1496 t += 30; 1497 t = (t & 0xffff) + (t >> 16); 1498 tcp->th_sum = t & 0xffff; 1499 } 1500 #endif 1501 putnext(q, mb); 1502 ATOMIC_INCL(fr_frouteok[0]); 1503 #if SOLARIS2 >= 8 1504 ire_refrele(dir); 1505 #endif 1506 READ_ENTER(&ipf_global); 1507 return 0; 1508 } 1509 #else /* IRE_ILL_CN */ 1510 mb->b_queue = q; 1511 *mpp = mb; 1512 pfil_send_dl_packet(q, mb); 1513 ATOMIC_INCL(fr_frouteok[0]); 1514 return 0; 1515 #endif /* IRE_ILL_CN */ 1516 } 1517 bad_fastroute: 1518 #ifndef IRE_ILL_CN 1519 #if SOLARIS2 >= 8 1520 if (dir != NULL) 1521 ire_refrele(dir); 1522 #endif 1523 #endif 1524 freemsg(mb); 1525 ATOMIC_INCL(fr_frouteok[1]); 1526 return -1; 1527 } 1528 1529 1530 /* ------------------------------------------------------------------------ */ 1531 /* Function: fr_pullup */ 1532 /* Returns: NULL == pullup failed, else pointer to protocol header */ 1533 /* Parameters: m(I) - pointer to buffer where data packet starts */ 1534 /* fin(I) - pointer to packet information */ 1535 /* len(I) - number of bytes to pullup */ 1536 /* */ 1537 /* Attempt to move at least len bytes (from the start of the buffer) into a */ 1538 /* single buffer for ease of access. Operating system native functions are */ 1539 /* used to manage buffers - if necessary. If the entire packet ends up in */ 1540 /* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */ 1541 /* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */ 1542 /* and ONLY if the pullup succeeds. */ 1543 /* */ 1544 /* We assume that 'min' is a pointer to a buffer that is part of the chain */ 1545 /* of buffers that starts at *fin->fin_mp. */ 1546 /* ------------------------------------------------------------------------ */ 1547 void *fr_pullup(min, fin, len) 1548 mb_t *min; 1549 fr_info_t *fin; 1550 int len; 1551 { 1552 qpktinfo_t *qpi = fin->fin_qpi; 1553 int out = fin->fin_out, dpoff, ipoff; 1554 mb_t *m = min; 1555 char *ip; 1556 1557 if (m == NULL) 1558 return NULL; 1559 1560 ip = (char *)fin->fin_ip; 1561 if ((fin->fin_flx & FI_COALESCE) != 0) 1562 return ip; 1563 1564 ipoff = fin->fin_ipoff; 1565 if (fin->fin_dp != NULL) 1566 dpoff = (char *)fin->fin_dp - (char *)ip; 1567 else 1568 dpoff = 0; 1569 1570 if (M_LEN(m) < len) { 1571 1572 /* 1573 * pfil_precheck ensures the IP header is on a 32bit 1574 * aligned address so simply fail if that isn't currently 1575 * the case (should never happen). 1576 */ 1577 int inc = 0; 1578 1579 if (ipoff > 0) { 1580 if ((ipoff & 3) != 0) { 1581 inc = 4 - (ipoff & 3); 1582 if (m->b_rptr - inc >= m->b_datap->db_base) 1583 m->b_rptr -= inc; 1584 else 1585 inc = 0; 1586 } 1587 } 1588 if (pullupmsg(m, len + ipoff + inc) == 0) { 1589 ATOMIC_INCL(frstats[out].fr_pull[1]); 1590 FREE_MB_T(*fin->fin_mp); 1591 *fin->fin_mp = NULL; 1592 fin->fin_m = NULL; 1593 fin->fin_ip = NULL; 1594 fin->fin_dp = NULL; 1595 qpi->qpi_data = NULL; 1596 return NULL; 1597 } 1598 m->b_rptr += inc; 1599 fin->fin_m = m; 1600 ip = MTOD(m, char *) + ipoff; 1601 qpi->qpi_data = ip; 1602 } 1603 1604 ATOMIC_INCL(frstats[out].fr_pull[0]); 1605 fin->fin_ip = (ip_t *)ip; 1606 if (fin->fin_dp != NULL) 1607 fin->fin_dp = (char *)fin->fin_ip + dpoff; 1608 1609 if (len == fin->fin_plen) 1610 fin->fin_flx |= FI_COALESCE; 1611 return ip; 1612 } 1613