add ssize_t, required by POSIX 1003.1
[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 *
f501b4b9 7 * @(#)tp_inet.c 7.10 (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
a50e2bc0 61#include "param.h"
2f41dd0f
KS
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"
a50e2bc0
KS
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"
2f41dd0f
KS
76#include "../netinet/in_var.h"
77
a50e2bc0
KS
78#ifndef ISO
79#include "iso_chksum.c"
80#endif
2f41dd0f
KS
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 */
a50e2bc0 99in_getsufx(inp, lenp, data_out, which)
2f41dd0f 100 struct inpcb *inp;
a50e2bc0
KS
101 u_short *lenp;
102 caddr_t data_out;
2f41dd0f
KS
103 int which;
104{
a50e2bc0 105 *lenp = sizeof(u_short);
2f41dd0f
KS
106 switch (which) {
107 case TP_LOCAL:
a50e2bc0
KS
108 *(u_short *)data_out = inp->inp_lport;
109 return;
2f41dd0f
KS
110
111 case TP_FOREIGN:
a50e2bc0 112 *(u_short *)data_out = inp->inp_fport;
2f41dd0f 113 }
a50e2bc0 114
2f41dd0f
KS
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 */
a50e2bc0 133/*ARGSUSED*/
2f41dd0f 134void
a50e2bc0 135in_putsufx(inp, sufxloc, sufxlen, which)
2f41dd0f 136 struct inpcb *inp;
a50e2bc0 137 caddr_t sufxloc;
2f41dd0f
KS
138 int which;
139{
a50e2bc0
KS
140 if (which == TP_FOREIGN) {
141 bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
2f41dd0f
KS
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 */
163void
164in_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 */
188void
189in_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
63f88aec
KS
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 */
227in_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
2f41dd0f
KS
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
a50e2bc0 249 * an mbuf (name);
2f41dd0f
KS
250 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
251 *
252 * RETURNS: Nada
253 *
254 * SIDE EFFECTS:
255 *
256 * NOTES:
257 */
258
259void
260in_getnetaddr( inp, name, which)
a50e2bc0 261 register struct mbuf *name;
2f41dd0f 262 struct inpcb *inp;
2f41dd0f
KS
263 int which;
264{
a50e2bc0
KS
265 register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
266 bzero((caddr_t)sin, sizeof(*sin));
2f41dd0f
KS
267 switch (which) {
268 case TP_LOCAL:
a50e2bc0
KS
269 sin->sin_addr = inp->inp_laddr;
270 sin->sin_port = inp->inp_lport;
2f41dd0f 271 break;
2f41dd0f 272 case TP_FOREIGN:
a50e2bc0
KS
273 sin->sin_addr = inp->inp_faddr;
274 sin->sin_port = inp->inp_fport;
2f41dd0f 275 break;
a50e2bc0
KS
276 default:
277 return;
2f41dd0f 278 }
a50e2bc0
KS
279 name->m_len = sin->sin_len = sizeof (*sin);
280 sin->sin_family = AF_INET;
2f41dd0f
KS
281}
282
283/*
284 * NAME: tpip_mtu()
285 *
286 * CALLED FROM:
f501b4b9 287 * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
2f41dd0f
KS
288 *
289 * FUNCTION, ARGUMENTS, and RETURN VALUE:
290 *
f501b4b9
KS
291 * Perform subnetwork dependent part of determining MTU information.
292 * It appears that setting a double pointer to the rtentry associated with
293 * the destination, and returning the header size for the network protocol
294 * suffices.
2f41dd0f
KS
295 *
296 * SIDE EFFECTS:
f501b4b9 297 * Sets tp_routep pointer in pcb.
2f41dd0f
KS
298 *
299 * NOTES:
300 */
301
f501b4b9
KS
302tpip_mtu(tpcb)
303register struct tp_pcb *tpcb;
2f41dd0f 304{
f501b4b9 305 struct inpcb *inp = (struct inpcb *)tpcb->tp_npcb;
2f41dd0f
KS
306
307 IFDEBUG(D_CONN)
f501b4b9
KS
308 printf("tpip_mtu(tpcb)\n", tpcb);
309 printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr);
2f41dd0f 310 ENDDEBUG
f501b4b9
KS
311 tpcb->tp_routep = &(inp->inp_route.ro_rt);
312 return (sizeof (struct ip));
2f41dd0f
KS
313
314}
315
316/*
317 * NAME: tpip_output()
318 *
319 * CALLED FROM: tp_emit()
320 *
321 * FUNCTION and ARGUMENTS:
322 * Take a packet(m0) from tp and package it so that ip will accept it.
323 * This means prepending space for the ip header and filling in a few
324 * of the fields.
325 * inp is the inpcb structure; datalen is the length of the data in the
326 * mbuf string m0.
327 * RETURNS:
328 * whatever (E*) is returned form the net layer output routine.
329 *
330 * SIDE EFFECTS:
331 *
332 * NOTES:
333 */
334
335int
336tpip_output(inp, m0, datalen, nochksum)
337 struct inpcb *inp;
338 struct mbuf *m0;
339 int datalen;
340 int nochksum;
341{
342 return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
343 &inp->inp_route, nochksum);
344}
345
346/*
347 * NAME: tpip_output_dg()
348 *
349 * CALLED FROM: tp_error_emit()
350 *
351 * FUNCTION and ARGUMENTS:
352 * This is a copy of tpip_output that takes the addresses
353 * instead of a pcb. It's used by the tp_error_emit, when we
354 * don't have an in_pcb with which to call the normal output rtn.
355 *
356 * RETURNS: ENOBUFS or whatever (E*) is
357 * returned form the net layer output routine.
358 *
359 * SIDE EFFECTS:
360 *
361 * NOTES:
362 */
363
a50e2bc0 364/*ARGSUSED*/
2f41dd0f
KS
365int
366tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
367 struct in_addr *laddr, *faddr;
368 struct mbuf *m0;
369 int datalen;
370 struct route *ro;
371 int nochksum;
372{
373 register struct mbuf *m;
374 register struct ip *ip;
375 int error;
376
377 IFDEBUG(D_EMIT)
378 printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0);
379 ENDDEBUG
380
381
a50e2bc0 382 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
2f41dd0f
KS
383 if (m == 0) {
384 error = ENOBUFS;
385 goto bad;
386 }
2f41dd0f 387 m->m_next = m0;
a50e2bc0 388 MH_ALIGN(m, sizeof(struct ip));
2f41dd0f 389 m->m_len = sizeof(struct ip);
2f41dd0f
KS
390
391 ip = mtod(m, struct ip *);
a50e2bc0 392 bzero((caddr_t)ip, sizeof *ip);
2f41dd0f
KS
393
394 ip->ip_p = IPPROTO_TP;
a50e2bc0 395 m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
2f41dd0f
KS
396 ip->ip_ttl = MAXTTL;
397 /* don't know why you need to set ttl;
398 * overlay doesn't even make this available
399 */
400
401 ip->ip_src = *laddr;
402 ip->ip_dst = *faddr;
403
404 IncStat(ts_tpdu_sent);
405 IFDEBUG(D_EMIT)
406 dump_mbuf(m, "tpip_output_dg before ip_output\n");
407 ENDDEBUG
408
409 error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
410
411 IFDEBUG(D_EMIT)
412 printf("tpip_output_dg after ip_output\n");
413 ENDDEBUG
414
415 return error;
416
417bad:
418 m_freem(m);
419 IncStat(ts_send_drop);
420 return error;
421}
422
423/*
424 * NAME: tpip_input()
425 *
426 * CALLED FROM:
427 * ip's input routine, indirectly through the protosw.
428 *
429 * FUNCTION and ARGUMENTS:
430 * Take a packet (m) from ip, strip off the ip header and give it to tp
431 *
432 * RETURNS: No return value.
433 *
434 * SIDE EFFECTS:
435 *
436 * NOTES:
437 */
438ProtoHook
a50e2bc0 439tpip_input(m, iplen)
2f41dd0f 440 struct mbuf *m;
a50e2bc0 441 int iplen;
2f41dd0f 442{
2f41dd0f
KS
443 struct sockaddr_in src, dst;
444 register struct ip *ip;
a50e2bc0 445 int s = splnet(), hdrlen;
2f41dd0f
KS
446
447 IncStat(ts_pkt_rcvd);
448
a50e2bc0
KS
449 /*
450 * IP layer has already pulled up the IP header,
451 * but the first byte after the IP header may not be there,
452 * e.g. if you came in via loopback, so you have to do an
453 * m_pullup to before you can even look to see how much you
454 * really need. The good news is that m_pullup will round
455 * up to almost the next mbuf's worth.
456 */
2f41dd0f 457
a50e2bc0
KS
458
459 if((m = m_pullup(m, iplen + 1)) == MNULL)
460 goto discard;
2f41dd0f
KS
461 CHANGE_MTYPE(m, TPMT_DATA);
462
463 /*
a50e2bc0
KS
464 * Now pull up the whole tp header:
465 * Unfortunately, there may be IP options to skip past so we
466 * just fetch it as an unsigned char.
2f41dd0f 467 */
a50e2bc0 468 hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
2f41dd0f 469
a50e2bc0
KS
470 if( m->m_len < hdrlen ) {
471 if((m = m_pullup(m, hdrlen)) == MNULL){
2f41dd0f
KS
472 IFDEBUG(D_TPINPUT)
473 printf("tp_input, pullup 2!\n");
474 ENDDEBUG
475 goto discard;
476 }
477 }
478 /*
479 * cannot use tp_inputprep() here 'cause you don't
480 * have quite the same situation
481 */
482
483 IFDEBUG(D_TPINPUT)
484 dump_mbuf(m, "after tpip_input both pullups");
485 ENDDEBUG
486 /*
487 * m_pullup may have returned a different mbuf
488 */
a50e2bc0 489 ip = mtod(m, struct ip *);
2f41dd0f
KS
490
491 /*
492 * drop the ip header from the front of the mbuf
493 * this is necessary for the tp checksum
494 */
a50e2bc0
KS
495 m->m_len -= iplen;
496 m->m_data += iplen;
2f41dd0f
KS
497
498 src.sin_addr = *(struct in_addr *)&(ip->ip_src);
499 src.sin_family = AF_INET;
a50e2bc0 500 src.sin_len = sizeof(src);
2f41dd0f
KS
501 dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
502 dst.sin_family = AF_INET;
a50e2bc0 503 dst.sin_len = sizeof(dst);
2f41dd0f 504
a50e2bc0 505 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
41fac7bb 506 0, tpip_output_dg, 0);
2f41dd0f
KS
507 return 0;
508
509discard:
510 IFDEBUG(D_TPINPUT)
511 printf("tpip_input DISCARD\n");
512 ENDDEBUG
513 IFTRACE(D_TPINPUT)
514 tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0);
515 ENDTRACE
516 m_freem(m);
517 IncStat(ts_recv_drop);
a50e2bc0 518 splx(s);
2f41dd0f
KS
519 return 0;
520}
521
522
e663c139 523#include "protosw.h"
2f41dd0f
KS
524#include "../netinet/ip_icmp.h"
525
a50e2bc0 526extern void tp_quench();
2f41dd0f
KS
527/*
528 * NAME: tpin_quench()
529 *
530 * CALLED FROM: tpip_ctlinput()
531 *
532 * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench
533 *
534 * RETURNS: Nada
535 *
536 * SIDE EFFECTS:
537 *
538 * NOTES:
539 */
540
541void
542tpin_quench(inp)
543 struct inpcb *inp;
544{
f15f73d2 545 tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
2f41dd0f
KS
546}
547
548/*
549 * NAME: tpip_ctlinput()
550 *
551 * CALLED FROM:
552 * The network layer through the protosw table.
553 *
554 * FUNCTION and ARGUMENTS:
555 * When clnp gets an ICMP msg this gets called.
556 * It either returns an error status to the user or
557 * causes all connections on this address to be aborted
558 * by calling the appropriate xx_notify() routine.
559 * (cmd) is the type of ICMP error.
560 * (sa) the address of the sender
561 *
562 * RETURNS: Nothing
563 *
564 * SIDE EFFECTS:
565 *
566 * NOTES:
567 */
568ProtoHook
569tpip_ctlinput(cmd, sin)
570 int cmd;
571 struct sockaddr_in *sin;
572{
573 extern u_char inetctlerrmap[];
574 extern ProtoHook tpin_abort();
575 extern ProtoHook in_rtchange();
87387e5e 576 extern struct in_addr zeroin_addr;
2f41dd0f
KS
577
578 if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
579 return 0;
580 if (sin->sin_addr.s_addr == INADDR_ANY)
581 return 0;
582 if (cmd < 0 || cmd > PRC_NCMDS)
583 return 0;
584 switch (cmd) {
585
586 case PRC_QUENCH:
87387e5e
KS
587 in_pcbnotify(&tp_inpcb, sin, 0,
588 zeroin_addr, 0, cmd, (int (*)())tp_quench);
2f41dd0f
KS
589 break;
590
591 case PRC_ROUTEDEAD:
592 case PRC_HOSTUNREACH:
593 case PRC_UNREACH_NET:
594 case PRC_IFDOWN:
595 case PRC_HOSTDEAD:
87387e5e
KS
596 in_pcbnotify(&tp_inpcb, sin, 0,
597 zeroin_addr, 0, cmd, in_rtchange);
2f41dd0f
KS
598 break;
599
600 default:
601 /*
602 case PRC_MSGSIZE:
603 case PRC_UNREACH_HOST:
604 case PRC_UNREACH_PROTOCOL:
605 case PRC_UNREACH_PORT:
606 case PRC_UNREACH_NEEDFRAG:
607 case PRC_UNREACH_SRCFAIL:
608 case PRC_REDIRECT_NET:
609 case PRC_REDIRECT_HOST:
610 case PRC_REDIRECT_TOSNET:
611 case PRC_REDIRECT_TOSHOST:
612 case PRC_TIMXCEED_INTRANS:
613 case PRC_TIMXCEED_REASS:
614 case PRC_PARAMPROB:
615 */
87387e5e
KS
616 in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
617 cmd, tpin_abort);
2f41dd0f
KS
618 }
619 return 0;
620}
621
622/*
623 * NAME: tpin_abort()
624 *
625 * CALLED FROM:
626 * xxx_notify() from tp_ctlinput() when
627 * net level gets some ICMP-equiv. type event.
628 *
629 * FUNCTION and ARGUMENTS:
630 * Cause the connection to be aborted with some sort of error
631 * reason indicating that the network layer caused the abort.
632 * Fakes an ER TPDU so we can go through the driver.
633 *
634 * RETURNS: Nothing
635 *
636 * SIDE EFFECTS:
637 *
638 * NOTES:
639 */
640
641ProtoHook
642tpin_abort(inp)
643 struct inpcb *inp;
644{
645 struct tp_event e;
646
647 e.ev_number = ER_TPDU;
648 e.ATTR(ER_TPDU).e_reason = ENETRESET;
a50e2bc0 649 (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
2f41dd0f
KS
650 return 0;
651}
652
653#ifdef ARGO_DEBUG
654dump_inaddr(addr)
655 register struct sockaddr_in *addr;
656{
657 printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
658}
659#endif ARGO_DEBUG
2f41dd0f 660#endif INET