trailing comment after #else or #endif
[unix-history] / usr / src / sys / netiso / tp_inet.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
4d8170e5 7 * @(#)tp_inet.c 7.12 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
2f41dd0f
KS
10/***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
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:
7bcd1bb8
KB
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
2f41dd0f
KS
57 */
58
2f41dd0f
KS
59#ifdef INET
60
5548a02f
KB
61#include <sys/param.h>
62#include <sys/socket.h>
63#include <sys/socketvar.h>
64#include <sys/mbuf.h>
65#include <sys/errno.h>
66#include <sys/time.h>
67
68#include <net/if.h>
69
70#include <netiso/tp_param.h>
71#include <netiso/argo_debug.h>
72#include <netiso/tp_stat.h>
73#include <netiso/tp_ip.h>
74#include <netiso/tp_pcb.h>
75#include <netiso/tp_trace.h>
76#include <netiso/tp_stat.h>
77#include <netiso/tp_tpdu.h>
78#include <netinet/in_var.h>
2f41dd0f 79
a50e2bc0 80#ifndef ISO
5548a02f 81#include <netiso/iso_chksum.c>
a50e2bc0 82#endif
2f41dd0f
KS
83
84/*
85 * NAME: in_getsufx()
86
87 * CALLED FROM: pr_usrreq() on PRU_BIND,
88 * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
89 *
90 * FUNCTION, ARGUMENTS, and RETURN VALUE:
91 * Get a transport suffix from an inpcb structure (inp).
92 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
93 *
94 * RETURNS: internet port / transport suffix
95 * (CAST TO AN INT)
96 *
97 * SIDE EFFECTS:
98 *
99 * NOTES:
100 */
a50e2bc0 101in_getsufx(inp, lenp, data_out, which)
2f41dd0f 102 struct inpcb *inp;
a50e2bc0
KS
103 u_short *lenp;
104 caddr_t data_out;
2f41dd0f
KS
105 int which;
106{
a50e2bc0 107 *lenp = sizeof(u_short);
2f41dd0f
KS
108 switch (which) {
109 case TP_LOCAL:
a50e2bc0
KS
110 *(u_short *)data_out = inp->inp_lport;
111 return;
2f41dd0f
KS
112
113 case TP_FOREIGN:
a50e2bc0 114 *(u_short *)data_out = inp->inp_fport;
2f41dd0f 115 }
a50e2bc0 116
2f41dd0f
KS
117}
118
119/*
120 * NAME: in_putsufx()
121 *
122 * CALLED FROM: tp_newsocket(); i.e., when a connection
123 * is being established by an incoming CR_TPDU.
124 *
125 * FUNCTION, ARGUMENTS:
126 * Put a transport suffix (found in name) into an inpcb structure (inp).
127 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
128 *
129 * RETURNS: Nada
130 *
131 * SIDE EFFECTS:
132 *
133 * NOTES:
134 */
a50e2bc0 135/*ARGSUSED*/
2f41dd0f 136void
a50e2bc0 137in_putsufx(inp, sufxloc, sufxlen, which)
2f41dd0f 138 struct inpcb *inp;
a50e2bc0 139 caddr_t sufxloc;
2f41dd0f
KS
140 int which;
141{
a50e2bc0
KS
142 if (which == TP_FOREIGN) {
143 bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
2f41dd0f
KS
144 }
145}
146
147/*
148 * NAME: in_recycle_tsuffix()
149 *
150 * CALLED FROM: tp.trans whenever we go into REFWAIT state.
151 *
152 * FUNCTION and ARGUMENT:
153 * Called when a ref is frozen, to allow the suffix to be reused.
154 * (inp) is the net level pcb.
155 *
156 * RETURNS: Nada
157 *
158 * SIDE EFFECTS:
159 *
160 * NOTES: This really shouldn't have to be done in a NET level pcb
161 * but... for the internet world that just the way it is done in BSD...
162 * The alternative is to have the port unusable until the reference
163 * timer goes off.
164 */
165void
166in_recycle_tsuffix(inp)
167 struct inpcb *inp;
168{
169 inp->inp_fport = inp->inp_lport = 0;
170}
171
172/*
173 * NAME: in_putnetaddr()
174 *
175 * CALLED FROM:
176 * tp_newsocket(); i.e., when a connection is being established by an
177 * incoming CR_TPDU.
178 *
179 * FUNCTION and ARGUMENTS:
180 * Copy a whole net addr from a struct sockaddr (name).
181 * into an inpcb (inp).
182 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
183 *
184 * RETURNS: Nada
185 *
186 * SIDE EFFECTS:
187 *
188 * NOTES:
189 */
190void
191in_putnetaddr(inp, name, which)
192 register struct inpcb *inp;
193 struct sockaddr_in *name;
194 int which;
195{
196 switch (which) {
197 case TP_LOCAL:
198 bcopy((caddr_t)&name->sin_addr,
199 (caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
200 /* won't work if the dst address (name) is INADDR_ANY */
201
202 break;
203 case TP_FOREIGN:
204 if( name != (struct sockaddr_in *)0 ) {
205 bcopy((caddr_t)&name->sin_addr,
206 (caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
207 }
208 }
209}
210
63f88aec
KS
211/*
212 * NAME: in_putnetaddr()
213 *
214 * CALLED FROM:
215 * tp_input() when a connection is being established by an
216 * incoming CR_TPDU, and considered for interception.
217 *
218 * FUNCTION and ARGUMENTS:
219 * Compare a whole net addr from a struct sockaddr (name),
220 * with that implicitly stored in an inpcb (inp).
221 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
222 *
223 * RETURNS: Nada
224 *
225 * SIDE EFFECTS:
226 *
227 * NOTES:
228 */
229in_cmpnetaddr(inp, name, which)
230 register struct inpcb *inp;
231 register struct sockaddr_in *name;
232 int which;
233{
234 if (which == TP_LOCAL) {
235 if (name->sin_port && name->sin_port != inp->inp_lport)
236 return 0;
237 return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
238 }
239 if (name->sin_port && name->sin_port != inp->inp_fport)
240 return 0;
241 return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
242}
243
2f41dd0f
KS
244/*
245 * NAME: in_getnetaddr()
246 *
247 * CALLED FROM:
248 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
249 * FUNCTION and ARGUMENTS:
250 * Copy a whole net addr from an inpcb (inp) into
a50e2bc0 251 * an mbuf (name);
2f41dd0f
KS
252 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
253 *
254 * RETURNS: Nada
255 *
256 * SIDE EFFECTS:
257 *
258 * NOTES:
259 */
260
261void
262in_getnetaddr( inp, name, which)
a50e2bc0 263 register struct mbuf *name;
2f41dd0f 264 struct inpcb *inp;
2f41dd0f
KS
265 int which;
266{
a50e2bc0
KS
267 register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
268 bzero((caddr_t)sin, sizeof(*sin));
2f41dd0f
KS
269 switch (which) {
270 case TP_LOCAL:
a50e2bc0
KS
271 sin->sin_addr = inp->inp_laddr;
272 sin->sin_port = inp->inp_lport;
2f41dd0f 273 break;
2f41dd0f 274 case TP_FOREIGN:
a50e2bc0
KS
275 sin->sin_addr = inp->inp_faddr;
276 sin->sin_port = inp->inp_fport;
2f41dd0f 277 break;
a50e2bc0
KS
278 default:
279 return;
2f41dd0f 280 }
a50e2bc0
KS
281 name->m_len = sin->sin_len = sizeof (*sin);
282 sin->sin_family = AF_INET;
2f41dd0f
KS
283}
284
285/*
286 * NAME: tpip_mtu()
287 *
288 * CALLED FROM:
f501b4b9 289 * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
2f41dd0f
KS
290 *
291 * FUNCTION, ARGUMENTS, and RETURN VALUE:
292 *
f501b4b9
KS
293 * Perform subnetwork dependent part of determining MTU information.
294 * It appears that setting a double pointer to the rtentry associated with
295 * the destination, and returning the header size for the network protocol
296 * suffices.
2f41dd0f
KS
297 *
298 * SIDE EFFECTS:
f501b4b9 299 * Sets tp_routep pointer in pcb.
2f41dd0f
KS
300 *
301 * NOTES:
302 */
303
f501b4b9
KS
304tpip_mtu(tpcb)
305register struct tp_pcb *tpcb;
2f41dd0f 306{
f501b4b9 307 struct inpcb *inp = (struct inpcb *)tpcb->tp_npcb;
2f41dd0f
KS
308
309 IFDEBUG(D_CONN)
f501b4b9
KS
310 printf("tpip_mtu(tpcb)\n", tpcb);
311 printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr);
2f41dd0f 312 ENDDEBUG
f501b4b9
KS
313 tpcb->tp_routep = &(inp->inp_route.ro_rt);
314 return (sizeof (struct ip));
2f41dd0f
KS
315
316}
317
318/*
319 * NAME: tpip_output()
320 *
321 * CALLED FROM: tp_emit()
322 *
323 * FUNCTION and ARGUMENTS:
324 * Take a packet(m0) from tp and package it so that ip will accept it.
325 * This means prepending space for the ip header and filling in a few
326 * of the fields.
327 * inp is the inpcb structure; datalen is the length of the data in the
328 * mbuf string m0.
329 * RETURNS:
330 * whatever (E*) is returned form the net layer output routine.
331 *
332 * SIDE EFFECTS:
333 *
334 * NOTES:
335 */
336
337int
338tpip_output(inp, m0, datalen, nochksum)
339 struct inpcb *inp;
340 struct mbuf *m0;
341 int datalen;
342 int nochksum;
343{
344 return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
345 &inp->inp_route, nochksum);
346}
347
348/*
349 * NAME: tpip_output_dg()
350 *
351 * CALLED FROM: tp_error_emit()
352 *
353 * FUNCTION and ARGUMENTS:
354 * This is a copy of tpip_output that takes the addresses
355 * instead of a pcb. It's used by the tp_error_emit, when we
356 * don't have an in_pcb with which to call the normal output rtn.
357 *
358 * RETURNS: ENOBUFS or whatever (E*) is
359 * returned form the net layer output routine.
360 *
361 * SIDE EFFECTS:
362 *
363 * NOTES:
364 */
365
a50e2bc0 366/*ARGSUSED*/
2f41dd0f
KS
367int
368tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
369 struct in_addr *laddr, *faddr;
370 struct mbuf *m0;
371 int datalen;
372 struct route *ro;
373 int nochksum;
374{
375 register struct mbuf *m;
376 register struct ip *ip;
377 int error;
378
379 IFDEBUG(D_EMIT)
380 printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0);
381 ENDDEBUG
382
383
a50e2bc0 384 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
2f41dd0f
KS
385 if (m == 0) {
386 error = ENOBUFS;
387 goto bad;
388 }
2f41dd0f 389 m->m_next = m0;
a50e2bc0 390 MH_ALIGN(m, sizeof(struct ip));
2f41dd0f 391 m->m_len = sizeof(struct ip);
2f41dd0f
KS
392
393 ip = mtod(m, struct ip *);
a50e2bc0 394 bzero((caddr_t)ip, sizeof *ip);
2f41dd0f
KS
395
396 ip->ip_p = IPPROTO_TP;
a50e2bc0 397 m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
2f41dd0f
KS
398 ip->ip_ttl = MAXTTL;
399 /* don't know why you need to set ttl;
400 * overlay doesn't even make this available
401 */
402
403 ip->ip_src = *laddr;
404 ip->ip_dst = *faddr;
405
406 IncStat(ts_tpdu_sent);
407 IFDEBUG(D_EMIT)
408 dump_mbuf(m, "tpip_output_dg before ip_output\n");
409 ENDDEBUG
410
411 error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
412
413 IFDEBUG(D_EMIT)
414 printf("tpip_output_dg after ip_output\n");
415 ENDDEBUG
416
417 return error;
418
419bad:
420 m_freem(m);
421 IncStat(ts_send_drop);
422 return error;
423}
424
425/*
426 * NAME: tpip_input()
427 *
428 * CALLED FROM:
429 * ip's input routine, indirectly through the protosw.
430 *
431 * FUNCTION and ARGUMENTS:
432 * Take a packet (m) from ip, strip off the ip header and give it to tp
433 *
434 * RETURNS: No return value.
435 *
436 * SIDE EFFECTS:
437 *
438 * NOTES:
439 */
440ProtoHook
a50e2bc0 441tpip_input(m, iplen)
2f41dd0f 442 struct mbuf *m;
a50e2bc0 443 int iplen;
2f41dd0f 444{
2f41dd0f
KS
445 struct sockaddr_in src, dst;
446 register struct ip *ip;
a50e2bc0 447 int s = splnet(), hdrlen;
2f41dd0f
KS
448
449 IncStat(ts_pkt_rcvd);
450
a50e2bc0
KS
451 /*
452 * IP layer has already pulled up the IP header,
453 * but the first byte after the IP header may not be there,
454 * e.g. if you came in via loopback, so you have to do an
455 * m_pullup to before you can even look to see how much you
456 * really need. The good news is that m_pullup will round
457 * up to almost the next mbuf's worth.
458 */
2f41dd0f 459
a50e2bc0
KS
460
461 if((m = m_pullup(m, iplen + 1)) == MNULL)
462 goto discard;
2f41dd0f
KS
463 CHANGE_MTYPE(m, TPMT_DATA);
464
465 /*
a50e2bc0
KS
466 * Now pull up the whole tp header:
467 * Unfortunately, there may be IP options to skip past so we
468 * just fetch it as an unsigned char.
2f41dd0f 469 */
a50e2bc0 470 hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
2f41dd0f 471
a50e2bc0
KS
472 if( m->m_len < hdrlen ) {
473 if((m = m_pullup(m, hdrlen)) == MNULL){
2f41dd0f
KS
474 IFDEBUG(D_TPINPUT)
475 printf("tp_input, pullup 2!\n");
476 ENDDEBUG
477 goto discard;
478 }
479 }
480 /*
481 * cannot use tp_inputprep() here 'cause you don't
482 * have quite the same situation
483 */
484
485 IFDEBUG(D_TPINPUT)
486 dump_mbuf(m, "after tpip_input both pullups");
487 ENDDEBUG
488 /*
489 * m_pullup may have returned a different mbuf
490 */
a50e2bc0 491 ip = mtod(m, struct ip *);
2f41dd0f
KS
492
493 /*
494 * drop the ip header from the front of the mbuf
495 * this is necessary for the tp checksum
496 */
a50e2bc0
KS
497 m->m_len -= iplen;
498 m->m_data += iplen;
2f41dd0f
KS
499
500 src.sin_addr = *(struct in_addr *)&(ip->ip_src);
501 src.sin_family = AF_INET;
a50e2bc0 502 src.sin_len = sizeof(src);
2f41dd0f
KS
503 dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
504 dst.sin_family = AF_INET;
a50e2bc0 505 dst.sin_len = sizeof(dst);
2f41dd0f 506
a50e2bc0 507 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
41fac7bb 508 0, tpip_output_dg, 0);
2f41dd0f
KS
509 return 0;
510
511discard:
512 IFDEBUG(D_TPINPUT)
513 printf("tpip_input DISCARD\n");
514 ENDDEBUG
515 IFTRACE(D_TPINPUT)
516 tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0);
517 ENDTRACE
518 m_freem(m);
519 IncStat(ts_recv_drop);
a50e2bc0 520 splx(s);
2f41dd0f
KS
521 return 0;
522}
523
524
5548a02f
KB
525#include <sys/protosw.h>
526#include <netinet/ip_icmp.h>
2f41dd0f 527
a50e2bc0 528extern void tp_quench();
2f41dd0f
KS
529/*
530 * NAME: tpin_quench()
531 *
532 * CALLED FROM: tpip_ctlinput()
533 *
534 * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench
535 *
536 * RETURNS: Nada
537 *
538 * SIDE EFFECTS:
539 *
540 * NOTES:
541 */
542
543void
544tpin_quench(inp)
545 struct inpcb *inp;
546{
f15f73d2 547 tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
2f41dd0f
KS
548}
549
550/*
551 * NAME: tpip_ctlinput()
552 *
553 * CALLED FROM:
554 * The network layer through the protosw table.
555 *
556 * FUNCTION and ARGUMENTS:
557 * When clnp gets an ICMP msg this gets called.
558 * It either returns an error status to the user or
559 * causes all connections on this address to be aborted
560 * by calling the appropriate xx_notify() routine.
561 * (cmd) is the type of ICMP error.
562 * (sa) the address of the sender
563 *
564 * RETURNS: Nothing
565 *
566 * SIDE EFFECTS:
567 *
568 * NOTES:
569 */
570ProtoHook
571tpip_ctlinput(cmd, sin)
572 int cmd;
573 struct sockaddr_in *sin;
574{
575 extern u_char inetctlerrmap[];
576 extern ProtoHook tpin_abort();
577 extern ProtoHook in_rtchange();
87387e5e 578 extern struct in_addr zeroin_addr;
2f41dd0f
KS
579
580 if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
581 return 0;
582 if (sin->sin_addr.s_addr == INADDR_ANY)
583 return 0;
584 if (cmd < 0 || cmd > PRC_NCMDS)
585 return 0;
586 switch (cmd) {
587
588 case PRC_QUENCH:
87387e5e
KS
589 in_pcbnotify(&tp_inpcb, sin, 0,
590 zeroin_addr, 0, cmd, (int (*)())tp_quench);
2f41dd0f
KS
591 break;
592
593 case PRC_ROUTEDEAD:
594 case PRC_HOSTUNREACH:
595 case PRC_UNREACH_NET:
596 case PRC_IFDOWN:
597 case PRC_HOSTDEAD:
87387e5e
KS
598 in_pcbnotify(&tp_inpcb, sin, 0,
599 zeroin_addr, 0, cmd, in_rtchange);
2f41dd0f
KS
600 break;
601
602 default:
603 /*
604 case PRC_MSGSIZE:
605 case PRC_UNREACH_HOST:
606 case PRC_UNREACH_PROTOCOL:
607 case PRC_UNREACH_PORT:
608 case PRC_UNREACH_NEEDFRAG:
609 case PRC_UNREACH_SRCFAIL:
610 case PRC_REDIRECT_NET:
611 case PRC_REDIRECT_HOST:
612 case PRC_REDIRECT_TOSNET:
613 case PRC_REDIRECT_TOSHOST:
614 case PRC_TIMXCEED_INTRANS:
615 case PRC_TIMXCEED_REASS:
616 case PRC_PARAMPROB:
617 */
87387e5e
KS
618 in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
619 cmd, tpin_abort);
2f41dd0f
KS
620 }
621 return 0;
622}
623
624/*
625 * NAME: tpin_abort()
626 *
627 * CALLED FROM:
628 * xxx_notify() from tp_ctlinput() when
629 * net level gets some ICMP-equiv. type event.
630 *
631 * FUNCTION and ARGUMENTS:
632 * Cause the connection to be aborted with some sort of error
633 * reason indicating that the network layer caused the abort.
634 * Fakes an ER TPDU so we can go through the driver.
635 *
636 * RETURNS: Nothing
637 *
638 * SIDE EFFECTS:
639 *
640 * NOTES:
641 */
642
643ProtoHook
644tpin_abort(inp)
645 struct inpcb *inp;
646{
647 struct tp_event e;
648
649 e.ev_number = ER_TPDU;
650 e.ATTR(ER_TPDU).e_reason = ENETRESET;
a50e2bc0 651 (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
2f41dd0f
KS
652 return 0;
653}
654
655#ifdef ARGO_DEBUG
656dump_inaddr(addr)
657 register struct sockaddr_in *addr;
658{
659 printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
660}
4d8170e5
KB
661#endif /* ARGO_DEBUG */
662#endif /* INET */