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