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