add POSIX-style byte-level record locking
[unix-history] / usr / src / sys / netiso / tp_inet.c
CommitLineData
2f41dd0f
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
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 $
87387e5e 31 * @(#)tp_inet.c 7.7 (Berkeley) %G% *
2f41dd0f
KS
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.
63f88aec 43 * in_cmpnetaddr: compare a whole net addr from an isopcb.
2f41dd0f
KS
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
52static 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
a50e2bc0 57#include "param.h"
2f41dd0f
KS
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"
a50e2bc0
KS
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"
2f41dd0f
KS
72#include "../netinet/in_var.h"
73
a50e2bc0
KS
74#ifndef ISO
75#include "iso_chksum.c"
76#endif
2f41dd0f
KS
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 */
a50e2bc0 95in_getsufx(inp, lenp, data_out, which)
2f41dd0f 96 struct inpcb *inp;
a50e2bc0
KS
97 u_short *lenp;
98 caddr_t data_out;
2f41dd0f
KS
99 int which;
100{
a50e2bc0 101 *lenp = sizeof(u_short);
2f41dd0f
KS
102 switch (which) {
103 case TP_LOCAL:
a50e2bc0
KS
104 *(u_short *)data_out = inp->inp_lport;
105 return;
2f41dd0f
KS
106
107 case TP_FOREIGN:
a50e2bc0 108 *(u_short *)data_out = inp->inp_fport;
2f41dd0f 109 }
a50e2bc0 110
2f41dd0f
KS
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 */
a50e2bc0 129/*ARGSUSED*/
2f41dd0f 130void
a50e2bc0 131in_putsufx(inp, sufxloc, sufxlen, which)
2f41dd0f 132 struct inpcb *inp;
a50e2bc0 133 caddr_t sufxloc;
2f41dd0f
KS
134 int which;
135{
a50e2bc0
KS
136 if (which == TP_FOREIGN) {
137 bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
2f41dd0f
KS
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 */
159void
160in_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 */
184void
185in_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
63f88aec
KS
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 */
223in_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
2f41dd0f
KS
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
a50e2bc0 245 * an mbuf (name);
2f41dd0f
KS
246 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
247 *
248 * RETURNS: Nada
249 *
250 * SIDE EFFECTS:
251 *
252 * NOTES:
253 */
254
255void
256in_getnetaddr( inp, name, which)
a50e2bc0 257 register struct mbuf *name;
2f41dd0f 258 struct inpcb *inp;
2f41dd0f
KS
259 int which;
260{
a50e2bc0
KS
261 register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
262 bzero((caddr_t)sin, sizeof(*sin));
2f41dd0f
KS
263 switch (which) {
264 case TP_LOCAL:
a50e2bc0
KS
265 sin->sin_addr = inp->inp_laddr;
266 sin->sin_port = inp->inp_lport;
2f41dd0f 267 break;
2f41dd0f 268 case TP_FOREIGN:
a50e2bc0
KS
269 sin->sin_addr = inp->inp_faddr;
270 sin->sin_port = inp->inp_fport;
2f41dd0f 271 break;
a50e2bc0
KS
272 default:
273 return;
2f41dd0f 274 }
a50e2bc0
KS
275 name->m_len = sin->sin_len = sizeof (*sin);
276 sin->sin_family = AF_INET;
2f41dd0f
KS
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
313void
314tpip_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
401int
402tpip_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
a50e2bc0 430/*ARGSUSED*/
2f41dd0f
KS
431int
432tpip_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
a50e2bc0 448 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
2f41dd0f
KS
449 if (m == 0) {
450 error = ENOBUFS;
451 goto bad;
452 }
2f41dd0f 453 m->m_next = m0;
a50e2bc0 454 MH_ALIGN(m, sizeof(struct ip));
2f41dd0f 455 m->m_len = sizeof(struct ip);
2f41dd0f
KS
456
457 ip = mtod(m, struct ip *);
a50e2bc0 458 bzero((caddr_t)ip, sizeof *ip);
2f41dd0f
KS
459
460 ip->ip_p = IPPROTO_TP;
a50e2bc0 461 m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
2f41dd0f
KS
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
483bad:
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 */
504ProtoHook
a50e2bc0 505tpip_input(m, iplen)
2f41dd0f 506 struct mbuf *m;
a50e2bc0 507 int iplen;
2f41dd0f 508{
2f41dd0f
KS
509 struct sockaddr_in src, dst;
510 register struct ip *ip;
a50e2bc0 511 int s = splnet(), hdrlen;
2f41dd0f
KS
512
513 IncStat(ts_pkt_rcvd);
514
a50e2bc0
KS
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 */
2f41dd0f 523
a50e2bc0
KS
524
525 if((m = m_pullup(m, iplen + 1)) == MNULL)
526 goto discard;
2f41dd0f
KS
527 CHANGE_MTYPE(m, TPMT_DATA);
528
529 /*
a50e2bc0
KS
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.
2f41dd0f 533 */
a50e2bc0 534 hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
2f41dd0f 535
a50e2bc0
KS
536 if( m->m_len < hdrlen ) {
537 if((m = m_pullup(m, hdrlen)) == MNULL){
2f41dd0f
KS
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 */
a50e2bc0 555 ip = mtod(m, struct ip *);
2f41dd0f
KS
556
557 /*
558 * drop the ip header from the front of the mbuf
559 * this is necessary for the tp checksum
560 */
a50e2bc0
KS
561 m->m_len -= iplen;
562 m->m_data += iplen;
2f41dd0f
KS
563
564 src.sin_addr = *(struct in_addr *)&(ip->ip_src);
565 src.sin_family = AF_INET;
a50e2bc0 566 src.sin_len = sizeof(src);
2f41dd0f
KS
567 dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
568 dst.sin_family = AF_INET;
a50e2bc0 569 dst.sin_len = sizeof(dst);
2f41dd0f 570
a50e2bc0 571 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
41fac7bb 572 0, tpip_output_dg, 0);
2f41dd0f
KS
573 return 0;
574
575discard:
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);
a50e2bc0 584 splx(s);
2f41dd0f
KS
585 return 0;
586}
587
588
e663c139 589#include "protosw.h"
2f41dd0f
KS
590#include "../netinet/ip_icmp.h"
591
a50e2bc0 592extern void tp_quench();
2f41dd0f
KS
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
607void
608tpin_quench(inp)
609 struct inpcb *inp;
610{
a50e2bc0 611 tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH);
2f41dd0f
KS
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 */
634ProtoHook
635tpip_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();
87387e5e 642 extern struct in_addr zeroin_addr;
2f41dd0f
KS
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:
87387e5e
KS
653 in_pcbnotify(&tp_inpcb, sin, 0,
654 zeroin_addr, 0, cmd, (int (*)())tp_quench);
2f41dd0f
KS
655 break;
656
657 case PRC_ROUTEDEAD:
658 case PRC_HOSTUNREACH:
659 case PRC_UNREACH_NET:
660 case PRC_IFDOWN:
661 case PRC_HOSTDEAD:
87387e5e
KS
662 in_pcbnotify(&tp_inpcb, sin, 0,
663 zeroin_addr, 0, cmd, in_rtchange);
2f41dd0f
KS
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 */
87387e5e
KS
682 in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
683 cmd, tpin_abort);
2f41dd0f
KS
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
707ProtoHook
708tpin_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;
a50e2bc0 715 (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
2f41dd0f
KS
716 return 0;
717}
718
719#ifdef ARGO_DEBUG
720dump_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 */
741struct ifnet *
742tpip_route(dst)
743 struct in_addr *dst;
744{
a50e2bc0
KS
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;
2f41dd0f
KS
750
751 IFDEBUG(D_CONN)
752 printf("tpip_route: dst is x%x\n", *dst);
753 ENDDEBUG
754
a50e2bc0
KS
755 bzero((caddr_t)sin, sizeof (*sin));
756 sin->sin_family = AF_INET;
757 sin->sin_len = sizeof(*sin);
758 sin->sin_addr = *dst;
2f41dd0f 759
a50e2bc0 760 ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
2f41dd0f 761 if (ia == 0)
a50e2bc0 762 ia = ifa_ifwithnet((struct sockaddr *)sin);
2f41dd0f 763 if (ia != 0) {
a50e2bc0 764 ifp = ia->ifa_ifp;
2f41dd0f
KS
765 IFDEBUG(D_CONN)
766 printf("tpip_route: ifp from ia:0x%x\n", ia);
767 ENDDEBUG
768 } else {
a50e2bc0
KS
769 rt = rtalloc1((struct sockaddr *)sin, 0);
770 if (rt != 0) {
771 ifp = rt->rt_ifp;
2f41dd0f 772 IFDEBUG(D_CONN)
a50e2bc0 773 printf("tpip_route: ifp from rentry: 0x%x\n", rt);
2f41dd0f 774 ENDDEBUG
a50e2bc0 775 rtfree(rt);
2f41dd0f
KS
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