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