include file for per-architecture Makefiles
[unix-history] / usr / src / sys / netiso / tp_inet.c
... / ...
CommitLineData
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.10 (Berkeley) %G%
8 */
9
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:
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 */
99in_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*/
134void
135in_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 */
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
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
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
259void
260in_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_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
288 *
289 * FUNCTION, ARGUMENTS, and RETURN VALUE:
290 *
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.
295 *
296 * SIDE EFFECTS:
297 * Sets tp_routep pointer in pcb.
298 *
299 * NOTES:
300 */
301
302tpip_mtu(tpcb)
303register struct tp_pcb *tpcb;
304{
305 struct inpcb *inp = (struct inpcb *)tpcb->tp_npcb;
306
307 IFDEBUG(D_CONN)
308 printf("tpip_mtu(tpcb)\n", tpcb);
309 printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr);
310 ENDDEBUG
311 tpcb->tp_routep = &(inp->inp_route.ro_rt);
312 return (sizeof (struct ip));
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
364/*ARGSUSED*/
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
382 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
383 if (m == 0) {
384 error = ENOBUFS;
385 goto bad;
386 }
387 m->m_next = m0;
388 MH_ALIGN(m, sizeof(struct ip));
389 m->m_len = sizeof(struct ip);
390
391 ip = mtod(m, struct ip *);
392 bzero((caddr_t)ip, sizeof *ip);
393
394 ip->ip_p = IPPROTO_TP;
395 m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
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
439tpip_input(m, iplen)
440 struct mbuf *m;
441 int iplen;
442{
443 struct sockaddr_in src, dst;
444 register struct ip *ip;
445 int s = splnet(), hdrlen;
446
447 IncStat(ts_pkt_rcvd);
448
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 */
457
458
459 if((m = m_pullup(m, iplen + 1)) == MNULL)
460 goto discard;
461 CHANGE_MTYPE(m, TPMT_DATA);
462
463 /*
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.
467 */
468 hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
469
470 if( m->m_len < hdrlen ) {
471 if((m = m_pullup(m, hdrlen)) == MNULL){
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 */
489 ip = mtod(m, struct ip *);
490
491 /*
492 * drop the ip header from the front of the mbuf
493 * this is necessary for the tp checksum
494 */
495 m->m_len -= iplen;
496 m->m_data += iplen;
497
498 src.sin_addr = *(struct in_addr *)&(ip->ip_src);
499 src.sin_family = AF_INET;
500 src.sin_len = sizeof(src);
501 dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
502 dst.sin_family = AF_INET;
503 dst.sin_len = sizeof(dst);
504
505 (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
506 0, tpip_output_dg, 0);
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);
518 splx(s);
519 return 0;
520}
521
522
523#include "protosw.h"
524#include "../netinet/ip_icmp.h"
525
526extern void tp_quench();
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{
545 tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH);
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();
576 extern struct in_addr zeroin_addr;
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:
587 in_pcbnotify(&tp_inpcb, sin, 0,
588 zeroin_addr, 0, cmd, (int (*)())tp_quench);
589 break;
590
591 case PRC_ROUTEDEAD:
592 case PRC_HOSTUNREACH:
593 case PRC_UNREACH_NET:
594 case PRC_IFDOWN:
595 case PRC_HOSTDEAD:
596 in_pcbnotify(&tp_inpcb, sin, 0,
597 zeroin_addr, 0, cmd, in_rtchange);
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 */
616 in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
617 cmd, tpin_abort);
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;
649 (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
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
660#endif INET