1 /*********************************************************** 2 Copyright IBM Corporation 1987 3 4 All Rights Reserved 5 6 Permission to use, copy, modify, and distribute this software and its 7 documentation for any purpose and without fee is hereby granted, 8 provided that the above copyright notice appear in all copies and that 9 both that copyright notice and this permission notice appear in 10 supporting documentation, and that the name of IBM not be 11 used in advertising or publicity pertaining to distribution of the 12 software without specific, written prior permission. 13 14 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 SOFTWARE. 21 22 ******************************************************************/ 23 24 /* 25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26 */ 27 /* 28 * ARGO TP 29 * $Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $ 30 * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $ 31 * 32 * Here is where you find the inet-dependent code. We've tried 33 * keep all net-level and (primarily) address-family-dependent stuff 34 * out of the tp source, and everthing here is reached indirectly 35 * through a switch table (struct nl_protosw *) tpcb->tp_nlproto 36 * (see tp_pcb.c). 37 * The routines here are: 38 * in_getsufx: gets transport suffix out of an inpcb structure. 39 * in_putsufx: put transport suffix into an inpcb structure. 40 * in_putnetaddr: put a whole net addr into an inpcb. 41 * in_getnetaddr: get a whole net addr from an inpcb. 42 * in_recycle_suffix: clear suffix for reuse in inpcb 43 * tpip_mtu: figure out what size tpdu to use 44 * tpip_input: take a pkt from ip, strip off its ip header, give to tp 45 * tpip_output_dg: package a pkt for ip given 2 addresses & some data 46 * tpip_output: package a pkt for ip given an inpcb & some data 47 */ 48 49 #ifndef lint 50 static char *rcsid = "$Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $"; 51 #endif lint 52 53 #ifdef INET 54 55 #include "param.h" 56 #include "socket.h" 57 #include "socketvar.h" 58 #include "mbuf.h" 59 #include "errno.h" 60 #include "time.h" 61 #include "../net/if.h" 62 #include "tp_param.h" 63 #include "argo_debug.h" 64 #include "tp_stat.h" 65 #include "tp_ip.h" 66 #include "tp_pcb.h" 67 #include "tp_trace.h" 68 #include "tp_stat.h" 69 #include "tp_tpdu.h" 70 #include "../netinet/in_var.h" 71 72 #ifndef ISO 73 #include "iso_chksum.c" 74 #endif 75 76 /* 77 * NAME: in_getsufx() 78 79 * CALLED FROM: pr_usrreq() on PRU_BIND, 80 * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR 81 * 82 * FUNCTION, ARGUMENTS, and RETURN VALUE: 83 * Get a transport suffix from an inpcb structure (inp). 84 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 85 * 86 * RETURNS: internet port / transport suffix 87 * (CAST TO AN INT) 88 * 89 * SIDE EFFECTS: 90 * 91 * NOTES: 92 */ 93 in_getsufx(inp, lenp, data_out, which) 94 struct inpcb *inp; 95 u_short *lenp; 96 caddr_t data_out; 97 int which; 98 { 99 *lenp = sizeof(u_short); 100 switch (which) { 101 case TP_LOCAL: 102 *(u_short *)data_out = inp->inp_lport; 103 return; 104 105 case TP_FOREIGN: 106 *(u_short *)data_out = inp->inp_fport; 107 } 108 109 } 110 111 /* 112 * NAME: in_putsufx() 113 * 114 * CALLED FROM: tp_newsocket(); i.e., when a connection 115 * is being established by an incoming CR_TPDU. 116 * 117 * FUNCTION, ARGUMENTS: 118 * Put a transport suffix (found in name) into an inpcb structure (inp). 119 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. 120 * 121 * RETURNS: Nada 122 * 123 * SIDE EFFECTS: 124 * 125 * NOTES: 126 */ 127 /*ARGSUSED*/ 128 void 129 in_putsufx(inp, sufxloc, sufxlen, which) 130 struct inpcb *inp; 131 caddr_t sufxloc; 132 int which; 133 { 134 if (which == TP_FOREIGN) { 135 bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport)); 136 } 137 } 138 139 /* 140 * NAME: in_recycle_tsuffix() 141 * 142 * CALLED FROM: tp.trans whenever we go into REFWAIT state. 143 * 144 * FUNCTION and ARGUMENT: 145 * Called when a ref is frozen, to allow the suffix to be reused. 146 * (inp) is the net level pcb. 147 * 148 * RETURNS: Nada 149 * 150 * SIDE EFFECTS: 151 * 152 * NOTES: This really shouldn't have to be done in a NET level pcb 153 * but... for the internet world that just the way it is done in BSD... 154 * The alternative is to have the port unusable until the reference 155 * timer goes off. 156 */ 157 void 158 in_recycle_tsuffix(inp) 159 struct inpcb *inp; 160 { 161 inp->inp_fport = inp->inp_lport = 0; 162 } 163 164 /* 165 * NAME: in_putnetaddr() 166 * 167 * CALLED FROM: 168 * tp_newsocket(); i.e., when a connection is being established by an 169 * incoming CR_TPDU. 170 * 171 * FUNCTION and ARGUMENTS: 172 * Copy a whole net addr from a struct sockaddr (name). 173 * into an inpcb (inp). 174 * The argument (which) takes values TP_LOCAL or TP_FOREIGN 175 * 176 * RETURNS: Nada 177 * 178 * SIDE EFFECTS: 179 * 180 * NOTES: 181 */ 182 void 183 in_putnetaddr(inp, name, which) 184 register struct inpcb *inp; 185 struct sockaddr_in *name; 186 int which; 187 { 188 switch (which) { 189 case TP_LOCAL: 190 bcopy((caddr_t)&name->sin_addr, 191 (caddr_t)&inp->inp_laddr, sizeof(struct in_addr)); 192 /* won't work if the dst address (name) is INADDR_ANY */ 193 194 break; 195 case TP_FOREIGN: 196 if( name != (struct sockaddr_in *)0 ) { 197 bcopy((caddr_t)&name->sin_addr, 198 (caddr_t)&inp->inp_faddr, sizeof(struct in_addr)); 199 } 200 } 201 } 202 203 /* 204 * NAME: in_getnetaddr() 205 * 206 * CALLED FROM: 207 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR 208 * FUNCTION and ARGUMENTS: 209 * Copy a whole net addr from an inpcb (inp) into 210 * an mbuf (name); 211 * The argument (which) takes values TP_LOCAL or TP_FOREIGN. 212 * 213 * RETURNS: Nada 214 * 215 * SIDE EFFECTS: 216 * 217 * NOTES: 218 */ 219 220 void 221 in_getnetaddr( inp, name, which) 222 register struct mbuf *name; 223 struct inpcb *inp; 224 int which; 225 { 226 register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *); 227 bzero((caddr_t)sin, sizeof(*sin)); 228 switch (which) { 229 case TP_LOCAL: 230 sin->sin_addr = inp->inp_laddr; 231 sin->sin_port = inp->inp_lport; 232 break; 233 case TP_FOREIGN: 234 sin->sin_addr = inp->inp_faddr; 235 sin->sin_port = inp->inp_fport; 236 break; 237 default: 238 return; 239 } 240 name->m_len = sin->sin_len = sizeof (*sin); 241 sin->sin_family = AF_INET; 242 } 243 244 /* 245 * NAME: tpip_mtu() 246 * 247 * CALLED FROM: 248 * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT 249 * 250 * FUNCTION, ARGUMENTS, and RETURN VALUE: 251 * 252 * Determine the proper maximum transmission unit, i.e., MTU, to use, given 253 * a) the header size for the network protocol and the max transmission 254 * unit on the subnet interface, determined from the information in (inp), 255 * b) the max size negotiated so far (negot) 256 * c) the window size used by the tp connection (found in so), 257 * 258 * The result is put in the integer *size in its integer form and in 259 * *negot in its logarithmic form. 260 * 261 * The rules are: 262 * a) can only negotiate down from the value found in *negot. 263 * b) the MTU must be < the windowsize, 264 * c) If src and dest are on the same net, 265 * we will negotiate the closest size larger than MTU but really USE 266 * the actual device mtu - ll hdr sizes. 267 * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. 268 * 269 * SIDE EFFECTS: 270 * changes the values addressed by the arguments (size) and (negot) 271 * and 272 * when the peer is not on one of our directly connected subnets, it 273 * looks up a route, leaving the route in the inpcb addressed by (inp) 274 * 275 * NOTES: 276 */ 277 278 void 279 tpip_mtu(so, inp, size, negot) 280 struct socket *so; 281 struct inpcb *inp; 282 int *size; 283 u_char *negot; 284 { 285 register struct ifnet *ifp; 286 struct ifnet *tpip_route(); 287 struct in_ifaddr *ia; 288 register int i; 289 int windowsize = so->so_rcv.sb_hiwat; 290 291 IFDEBUG(D_CONN) 292 printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n", 293 so, inp, size, negot); 294 printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr); 295 ENDDEBUG 296 IFTRACE(D_CONN) 297 tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); 298 ENDTRACE 299 300 *size = 1 << *negot; 301 302 if( *size > windowsize ) { 303 *size = windowsize; 304 } 305 306 ia = in_iaonnetof(in_netof(inp->inp_faddr)); 307 if ( ia == (struct in_ifaddr *)0 ) { 308 ifp = tpip_route(&inp->inp_faddr); 309 if( ifp == (struct ifnet *)0 ) 310 return ; 311 } else 312 ifp = ia->ia_ifp; 313 314 315 /**************************************************************** 316 * TODO - make this indirect off the socket structure to the 317 * network layer to get headersize 318 * After all, who knows what lies below the IP layer? 319 * Who knows how big the NL header will be? 320 ***************************************************************/ 321 322 if( *size > ifp->if_mtu - sizeof(struct ip)) { 323 *size = ifp->if_mtu - sizeof(struct ip); 324 } 325 for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++) 326 ; 327 i--; 328 329 if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) { 330 i++; 331 } else { 332 *size = 1<<i; 333 } 334 *negot = i; 335 336 IFDEBUG(D_CONN) 337 printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", 338 ifp->if_name, *size, *negot); 339 ENDDEBUG 340 IFTRACE(D_CONN) 341 tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", 342 *size, *negot, 0, 0); 343 ENDTRACE 344 345 } 346 347 /* 348 * NAME: tpip_output() 349 * 350 * CALLED FROM: tp_emit() 351 * 352 * FUNCTION and ARGUMENTS: 353 * Take a packet(m0) from tp and package it so that ip will accept it. 354 * This means prepending space for the ip header and filling in a few 355 * of the fields. 356 * inp is the inpcb structure; datalen is the length of the data in the 357 * mbuf string m0. 358 * RETURNS: 359 * whatever (E*) is returned form the net layer output routine. 360 * 361 * SIDE EFFECTS: 362 * 363 * NOTES: 364 */ 365 366 int 367 tpip_output(inp, m0, datalen, nochksum) 368 struct inpcb *inp; 369 struct mbuf *m0; 370 int datalen; 371 int nochksum; 372 { 373 return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen, 374 &inp->inp_route, nochksum); 375 } 376 377 /* 378 * NAME: tpip_output_dg() 379 * 380 * CALLED FROM: tp_error_emit() 381 * 382 * FUNCTION and ARGUMENTS: 383 * This is a copy of tpip_output that takes the addresses 384 * instead of a pcb. It's used by the tp_error_emit, when we 385 * don't have an in_pcb with which to call the normal output rtn. 386 * 387 * RETURNS: ENOBUFS or whatever (E*) is 388 * returned form the net layer output routine. 389 * 390 * SIDE EFFECTS: 391 * 392 * NOTES: 393 */ 394 395 /*ARGSUSED*/ 396 int 397 tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum) 398 struct in_addr *laddr, *faddr; 399 struct mbuf *m0; 400 int datalen; 401 struct route *ro; 402 int nochksum; 403 { 404 register struct mbuf *m; 405 register struct ip *ip; 406 int error; 407 408 IFDEBUG(D_EMIT) 409 printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); 410 ENDDEBUG 411 412 413 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR); 414 if (m == 0) { 415 error = ENOBUFS; 416 goto bad; 417 } 418 m->m_next = m0; 419 MH_ALIGN(m, sizeof(struct ip)); 420 m->m_len = sizeof(struct ip); 421 422 ip = mtod(m, struct ip *); 423 bzero((caddr_t)ip, sizeof *ip); 424 425 ip->ip_p = IPPROTO_TP; 426 m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen; 427 ip->ip_ttl = MAXTTL; 428 /* don't know why you need to set ttl; 429 * overlay doesn't even make this available 430 */ 431 432 ip->ip_src = *laddr; 433 ip->ip_dst = *faddr; 434 435 IncStat(ts_tpdu_sent); 436 IFDEBUG(D_EMIT) 437 dump_mbuf(m, "tpip_output_dg before ip_output\n"); 438 ENDDEBUG 439 440 error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST); 441 442 IFDEBUG(D_EMIT) 443 printf("tpip_output_dg after ip_output\n"); 444 ENDDEBUG 445 446 return error; 447 448 bad: 449 m_freem(m); 450 IncStat(ts_send_drop); 451 return error; 452 } 453 454 /* 455 * NAME: tpip_input() 456 * 457 * CALLED FROM: 458 * ip's input routine, indirectly through the protosw. 459 * 460 * FUNCTION and ARGUMENTS: 461 * Take a packet (m) from ip, strip off the ip header and give it to tp 462 * 463 * RETURNS: No return value. 464 * 465 * SIDE EFFECTS: 466 * 467 * NOTES: 468 */ 469 ProtoHook 470 tpip_input(m, iplen) 471 struct mbuf *m; 472 int iplen; 473 { 474 struct sockaddr_in src, dst; 475 register struct ip *ip; 476 int s = splnet(), hdrlen; 477 478 IncStat(ts_pkt_rcvd); 479 480 /* 481 * IP layer has already pulled up the IP header, 482 * but the first byte after the IP header may not be there, 483 * e.g. if you came in via loopback, so you have to do an 484 * m_pullup to before you can even look to see how much you 485 * really need. The good news is that m_pullup will round 486 * up to almost the next mbuf's worth. 487 */ 488 489 490 if((m = m_pullup(m, iplen + 1)) == MNULL) 491 goto discard; 492 CHANGE_MTYPE(m, TPMT_DATA); 493 494 /* 495 * Now pull up the whole tp header: 496 * Unfortunately, there may be IP options to skip past so we 497 * just fetch it as an unsigned char. 498 */ 499 hdrlen = iplen + 1 + mtod(m, u_char *)[iplen]; 500 501 if( m->m_len < hdrlen ) { 502 if((m = m_pullup(m, hdrlen)) == MNULL){ 503 IFDEBUG(D_TPINPUT) 504 printf("tp_input, pullup 2!\n"); 505 ENDDEBUG 506 goto discard; 507 } 508 } 509 /* 510 * cannot use tp_inputprep() here 'cause you don't 511 * have quite the same situation 512 */ 513 514 IFDEBUG(D_TPINPUT) 515 dump_mbuf(m, "after tpip_input both pullups"); 516 ENDDEBUG 517 /* 518 * m_pullup may have returned a different mbuf 519 */ 520 ip = mtod(m, struct ip *); 521 522 /* 523 * drop the ip header from the front of the mbuf 524 * this is necessary for the tp checksum 525 */ 526 m->m_len -= iplen; 527 m->m_data += iplen; 528 529 src.sin_addr = *(struct in_addr *)&(ip->ip_src); 530 src.sin_family = AF_INET; 531 src.sin_len = sizeof(src); 532 dst.sin_addr = *(struct in_addr *)&(ip->ip_dst); 533 dst.sin_family = AF_INET; 534 dst.sin_len = sizeof(dst); 535 536 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, 537 0, tpip_output_dg); 538 splx(s); 539 return 0; 540 541 discard: 542 IFDEBUG(D_TPINPUT) 543 printf("tpip_input DISCARD\n"); 544 ENDDEBUG 545 IFTRACE(D_TPINPUT) 546 tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0); 547 ENDTRACE 548 m_freem(m); 549 IncStat(ts_recv_drop); 550 splx(s); 551 return 0; 552 } 553 554 555 #include "../h/protosw.h" 556 #include "../netinet/ip_icmp.h" 557 558 extern void tp_quench(); 559 /* 560 * NAME: tpin_quench() 561 * 562 * CALLED FROM: tpip_ctlinput() 563 * 564 * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench 565 * 566 * RETURNS: Nada 567 * 568 * SIDE EFFECTS: 569 * 570 * NOTES: 571 */ 572 573 void 574 tpin_quench(inp) 575 struct inpcb *inp; 576 { 577 tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH); 578 } 579 580 /* 581 * NAME: tpip_ctlinput() 582 * 583 * CALLED FROM: 584 * The network layer through the protosw table. 585 * 586 * FUNCTION and ARGUMENTS: 587 * When clnp gets an ICMP msg this gets called. 588 * It either returns an error status to the user or 589 * causes all connections on this address to be aborted 590 * by calling the appropriate xx_notify() routine. 591 * (cmd) is the type of ICMP error. 592 * (sa) the address of the sender 593 * 594 * RETURNS: Nothing 595 * 596 * SIDE EFFECTS: 597 * 598 * NOTES: 599 */ 600 ProtoHook 601 tpip_ctlinput(cmd, sin) 602 int cmd; 603 struct sockaddr_in *sin; 604 { 605 extern u_char inetctlerrmap[]; 606 extern ProtoHook tpin_abort(); 607 extern ProtoHook in_rtchange(); 608 609 if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK) 610 return 0; 611 if (sin->sin_addr.s_addr == INADDR_ANY) 612 return 0; 613 if (cmd < 0 || cmd > PRC_NCMDS) 614 return 0; 615 switch (cmd) { 616 617 case PRC_QUENCH: 618 in_pcbnotify(&tp_inpcb, &sin->sin_addr, 619 0, (int (*)())tp_quench); 620 break; 621 622 case PRC_ROUTEDEAD: 623 case PRC_HOSTUNREACH: 624 case PRC_UNREACH_NET: 625 case PRC_IFDOWN: 626 case PRC_HOSTDEAD: 627 in_pcbnotify(&tp_inpcb, &sin->sin_addr, 628 (int)inetctlerrmap[cmd], in_rtchange); 629 break; 630 631 default: 632 /* 633 case PRC_MSGSIZE: 634 case PRC_UNREACH_HOST: 635 case PRC_UNREACH_PROTOCOL: 636 case PRC_UNREACH_PORT: 637 case PRC_UNREACH_NEEDFRAG: 638 case PRC_UNREACH_SRCFAIL: 639 case PRC_REDIRECT_NET: 640 case PRC_REDIRECT_HOST: 641 case PRC_REDIRECT_TOSNET: 642 case PRC_REDIRECT_TOSHOST: 643 case PRC_TIMXCEED_INTRANS: 644 case PRC_TIMXCEED_REASS: 645 case PRC_PARAMPROB: 646 */ 647 in_pcbnotify(&tp_inpcb, &sin->sin_addr, 648 (int)inetctlerrmap[cmd], tpin_abort); 649 } 650 return 0; 651 } 652 653 /* 654 * NAME: tpin_abort() 655 * 656 * CALLED FROM: 657 * xxx_notify() from tp_ctlinput() when 658 * net level gets some ICMP-equiv. type event. 659 * 660 * FUNCTION and ARGUMENTS: 661 * Cause the connection to be aborted with some sort of error 662 * reason indicating that the network layer caused the abort. 663 * Fakes an ER TPDU so we can go through the driver. 664 * 665 * RETURNS: Nothing 666 * 667 * SIDE EFFECTS: 668 * 669 * NOTES: 670 */ 671 672 ProtoHook 673 tpin_abort(inp) 674 struct inpcb *inp; 675 { 676 struct tp_event e; 677 678 e.ev_number = ER_TPDU; 679 e.ATTR(ER_TPDU).e_reason = ENETRESET; 680 (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e); 681 return 0; 682 } 683 684 #ifdef ARGO_DEBUG 685 dump_inaddr(addr) 686 register struct sockaddr_in *addr; 687 { 688 printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr); 689 } 690 #endif ARGO_DEBUG 691 692 /* 693 * NAME: tpip_route() 694 * 695 * CALLED FROM: tpip_mtu() 696 * 697 * FUNCTION and ARGUMENTS: given a destination addresss, 698 * find the interface that would be used to send something to this address. 699 * 700 * RETURNS: pointer to an ifnet structure 701 * 702 * SIDE EFFECTS: 703 * 704 * NOTES: 705 */ 706 struct ifnet * 707 tpip_route(dst) 708 struct in_addr *dst; 709 { 710 struct ifnet *ifp = (struct ifnet *)0; 711 struct sockaddr_in insock; 712 struct sockaddr_in *sin = &insock; 713 struct rtentry *rt; 714 struct ifaddr *ia; 715 716 IFDEBUG(D_CONN) 717 printf("tpip_route: dst is x%x\n", *dst); 718 ENDDEBUG 719 720 bzero((caddr_t)sin, sizeof (*sin)); 721 sin->sin_family = AF_INET; 722 sin->sin_len = sizeof(*sin); 723 sin->sin_addr = *dst; 724 725 ia = ifa_ifwithdstaddr((struct sockaddr *)sin); 726 if (ia == 0) 727 ia = ifa_ifwithnet((struct sockaddr *)sin); 728 if (ia != 0) { 729 ifp = ia->ifa_ifp; 730 IFDEBUG(D_CONN) 731 printf("tpip_route: ifp from ia:0x%x\n", ia); 732 ENDDEBUG 733 } else { 734 rt = rtalloc1((struct sockaddr *)sin, 0); 735 if (rt != 0) { 736 ifp = rt->rt_ifp; 737 IFDEBUG(D_CONN) 738 printf("tpip_route: ifp from rentry: 0x%x\n", rt); 739 ENDDEBUG 740 rtfree(rt); 741 } 742 } 743 IFDEBUG(D_CONN) 744 printf("tpip_route: returning 0x%x\n", ifp); 745 if (ifp) 746 printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n", 747 ifp->if_name, ifp->if_unit, ifp->if_mtu); 748 ENDDEBUG 749 return ifp; 750 } 751 752 #endif INET 753