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