No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netiso / tp_input.c
blob5a58665303431bd2dc10eef9909fcf13b1280257
1 /* $NetBSD: tp_input.c,v 1.33 2009/03/18 22:08:57 he Exp $ */
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 * @(#)tp_input.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * tp_input() gets an mbuf chain from ip. Actually, not directly from ip,
62 * because ip calls a net-level routine that strips off the net header and
63 * then calls tp_input(), passing the proper type of addresses for the
64 * address family in use (how it figures out which AF is not yet determined.)
66 * Decomposing the tpdu is some of the most laughable code. The variable-length
67 * parameters and the problem of non-aligned memory references necessitates
68 * such abominations as the macros WHILE_OPTIONS (q.v. below) to loop through
69 * the header and decompose it.
71 * The routine tp_newsocket() is called when a CR comes in for a listening
72 * socket. tp_input calls sonewconn() and tp_newsocket() to set up the
73 * "child" socket. Most tpcb values are copied from the parent tpcb into the
74 * child.
76 * Also in here is tp_headersize() (grot) which tells the expected size of a tp
77 * header, to be used by other layers. It's in here because it uses the
78 * static structure tpdu_info.
81 #include <sys/cdefs.h>
82 __KERNEL_RCSID(0, "$NetBSD: tp_input.c,v 1.33 2009/03/18 22:08:57 he Exp $");
84 #include "opt_iso.h"
86 #include <sys/param.h>
87 #include <sys/systm.h>
88 #include <sys/mbuf.h>
89 #include <sys/socket.h>
90 #include <sys/socketvar.h>
91 #include <sys/domain.h>
92 #include <sys/protosw.h>
93 #include <sys/errno.h>
94 #include <sys/time.h>
95 #include <sys/kernel.h>
97 #include <net/if.h>
99 #include <netiso/iso.h>
100 #include <netiso/iso_errno.h>
101 #include <netiso/iso_pcb.h>
102 #include <netiso/tp_param.h>
103 #include <netiso/tp_var.h>
104 #include <netiso/tp_timer.h>
105 #include <netiso/tp_stat.h>
106 #include <netiso/tp_pcb.h>
107 #include <netiso/argo_debug.h>
108 #include <netiso/tp_trace.h>
109 #include <netiso/tp_tpdu.h>
110 #include <netiso/iso_var.h>
112 #include <machine/stdarg.h>
114 static struct socket *
115 tp_newsocket(struct socket *, struct sockaddr *, void *, u_int, u_int);
117 struct mbuf *
118 tp_inputprep(struct mbuf *m)
120 int hdrlen;
122 #ifdef ARGO_DEBUG
123 if (argo_debug[D_TPINPUT]) {
124 printf("tp_inputprep: m %p\n", m);
126 #endif
128 while (m->m_len < 1) {
130 * The "m_free" logic if( (m = m_free(m)) == NULL ) return
131 * (struct mbuf *)0; would cause a system crash if ever
132 * executed. This logic will be executed if the first mbuf in
133 * the chain only contains a CLNP header. The m_free routine
134 * will release the mbuf containing the CLNP header from the
135 * chain and the new head of the chain will not have the
136 * M_PKTHDR bit set. This routine, tp_inputprep, will
137 * eventually call the "sbappendaddr" routine. "sbappendaddr"
138 * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap
139 * way of keeping the head of the chain from being freed.
141 if ((m = m_pullup(m, 1)) == NULL)
142 return (NULL);
144 if (((long) m->m_data) & 0x3) {
146 * If we are not 4-byte aligned, we have to be above the
147 * beginning of the mbuf, and it is ok just to slide it back.
149 void * ocp = m->m_data;
151 m->m_data = (void *) (((long) m->m_data) & ~0x3);
152 memcpy(m->m_data, ocp, (unsigned) m->m_len);
154 CHANGE_MTYPE(m, TPMT_DATA);
157 * we KNOW that there is at least 1 byte in this mbuf and that it is
158 * hdr->tpdu_li XXXXXXX!
161 hdrlen = 1 + *mtod(m, u_char *);
164 * now pull up the whole tp header
166 if (m->m_len < hdrlen) {
167 if ((m = m_pullup(m, hdrlen)) == NULL) {
168 IncStat(ts_recv_drop);
169 return (struct mbuf *) 0;
172 #ifdef ARGO_DEBUG
173 if (argo_debug[D_INPUT]) {
174 printf(
175 " at end: m %p hdr->tpdu_li 0x%x m_len 0x%x\n", m,
176 hdrlen, m->m_len);
178 #endif
179 return m;
183 * begin groan -- this array and the following macros allow you to step
184 * through the parameters of the variable part of a header note that if for
185 * any reason the values of the **_TPDU macros (in tp_events.h) should
186 * change, this array has to be rearranged
189 #define TP_LEN_CLASS_0_INDEX 2
190 #define TP_MAX_DATA_INDEX 3
192 static const u_char tpdu_info[][4] =
194 /* length max data len */
195 /* reg fmt xtd fmt class 0 */
196 /* UNUSED 0x0 */ { 0x0, 0x0, 0x0, 0x0 },
197 /* XPD_TPDU_type 0x1 */ { 0x5, 0x8, 0x0, TP_MAX_XPD_DATA },
198 /* XAK_TPDU_type 0x2 */ { 0x5, 0x8, 0x0, 0x0 },
199 /* GR_TPDU_type 0x3 */ { 0x0, 0x0, 0x0, 0x0 },
200 /* UNUSED 0x4 */ { 0x0, 0x0, 0x0, 0x0 },
201 /* UNUSED 0x5 */ { 0x0, 0x0, 0x0, 0x0 },
202 /* AK_TPDU_type 0x6 */ { 0x5, 0xa, 0x0, 0x0 },
203 /* ER_TPDU_type 0x7 */ { 0x5, 0x5, 0x0, 0x0 },
204 /* DR_TPDU_type 0x8 */ { 0x7, 0x7, 0x7, TP_MAX_DR_DATA },
205 /* UNUSED 0x9 */ { 0x0, 0x0, 0x0, 0x0 },
206 /* UNUSED 0xa */ { 0x0, 0x0, 0x0, 0x0 },
207 /* UNUSED 0xb */ { 0x0, 0x0, 0x0, 0x0 },
208 /* DC_TPDU_type 0xc */ { 0x6, 0x6, 0x0, 0x0 },
209 /* CC_TPDU_type 0xd */ { 0x7, 0x7, 0x7, TP_MAX_CC_DATA },
210 /* CR_TPDU_type 0xe */ { 0x7, 0x7, 0x7, TP_MAX_CR_DATA },
211 /* DT_TPDU_type 0xf */ { 0x5, 0x8, 0x3, 0x0 },
214 #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
215 if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\
216 goto Whattodo; }
219 * WHENEVER YOU USE THE FOLLOWING MACRO, BE SURE THE TPDUTYPE IS A LEGIT
220 * VALUE FIRST!
223 #define WHILE_OPTIONS(P, hdr, format)\
224 { char *P = tpdu_info[(hdr)->tpdu_type][(format)] + (char *)hdr;\
225 char *PLIM = 1 + hdr->tpdu_li + (char *)hdr;\
226 for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
227 CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
228 respond, P - (char *)hdr);\
229 if (P == PLIM) break;
231 #define END_WHILE_OPTIONS(P) } }
233 /* end groan */
236 * NAME: tp_newsocket()
238 * CALLED FROM:
239 * tp_input() on incoming CR, when a socket w/ the called suffix
240 * is awaiting a connection request
242 * FUNCTION and ARGUMENTS:
243 * Create a new socket structure, attach to it a new transport pcb,
244 * using a copy of the net level pcb for the parent socket.
245 * (so) is the parent socket.
246 * (fname) is the foreign address (all that's used is the nsap portion)
248 * RETURN VALUE:
249 * a new socket structure, being this end of the newly formed connection.
251 * SIDE EFFECTS:
252 * Sets a few things in the tpcb and net level pcb
254 * NOTES:
256 static struct socket *
257 tp_newsocket(
258 struct socket *so,
259 struct sockaddr *fname,
260 void * cons_channel,
261 u_int class_to_use,
262 u_int netservice)
264 struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed
265 * below */
266 struct tp_pcb *newtpcb;
269 * sonewconn() gets a new socket structure, a new lower layer pcb and
270 * a new tpcb, but the pcbs are unnamed (not bound)
272 #ifdef TPPT
273 if (tp_traceflags[D_NEWSOCK]) {
274 tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
275 so, tpcb, so->so_head, 0);
277 #endif
279 if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *) 0)
280 return so;
281 #ifdef TPPT
282 if (tp_traceflags[D_NEWSOCK]) {
283 tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
284 so, so->so_head, 0, 0);
286 #endif
288 #ifdef ARGO_DEBUG
289 if (argo_debug[D_NEWSOCK]) {
290 printf("tp_newsocket(channel %p) after sonewconn so %p \n",
291 cons_channel, so);
292 dump_addr(fname);
294 struct socket *t, *head;
296 head = so->so_head;
297 t = so;
298 printf("so %p so_head %p so_q0 %p, q0len %d\n",
299 t, t->so_head, t->so_q0.tqh_first, t->so_q0len);
300 while ((t = t->so_q0.tqh_first) && t != so && t != head)
301 printf("so %p so_head %p so_q0 %p, q0len %d\n",
302 t, t->so_head, t->so_q0.tqh_first,
303 t->so_q0len);
306 #endif
309 * before we clobber the old tpcb ptr, get these items from the
310 * parent pcb
312 newtpcb = sototpcb(so);
313 newtpcb->_tp_param = tpcb->_tp_param;
314 newtpcb->tp_flags = tpcb->tp_flags;
315 newtpcb->tp_lcredit = tpcb->tp_lcredit;
316 newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
317 newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
318 memcpy(newtpcb->tp_lsuffix, tpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
320 if ( /* old */ tpcb->tp_ucddata) {
322 * These data are the connect- , confirm- or disconnect-
323 * data.
325 struct mbuf *conndata;
327 conndata = m_copy(tpcb->tp_ucddata, 0, (int) M_COPYALL);
328 #ifdef ARGO_DEBUG
329 if (argo_debug[D_CONN]) {
330 dump_mbuf(conndata, "conndata after mcopy");
332 #endif
333 newtpcb->tp_ucddata = conndata;
335 tpcb = newtpcb;
336 tpcb->tp_state = TP_LISTENING;
337 tpcb->tp_class = class_to_use;
338 tpcb->tp_netservice = netservice;
341 ASSERT(fname != 0); /* just checking */
342 if (fname) {
344 * tp_route_to takes its address argument in the form of an mbuf.
346 struct mbuf *m;
347 int err;
349 MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is
350 * confusing */
351 if (m) {
353 * this seems a bit grotesque, but tp_route_to expects
354 * an mbuf * instead of simply a sockaddr; it calls the ll
355 * pcb_connect, which expects the name/addr in an mbuf as well.
356 * sigh.
358 memcpy(mtod(m, void *), (void *) fname, fname->sa_len);
359 m->m_len = fname->sa_len;
362 * grot : have to say the kernel can override params
363 * in the passive open case
365 tpcb->tp_dont_change_params = 0;
366 err = tp_route_to(m, tpcb, cons_channel);
367 m_free(m);
369 if (!err)
370 goto ok;
372 #ifdef ARGO_DEBUG
373 if (argo_debug[D_CONN]) {
374 printf("tp_route_to FAILED! detaching tpcb %p, so %p\n",
375 tpcb, so);
377 #endif
378 (void) tp_detach(tpcb);
379 return 0;
382 #ifdef ARGO_DEBUG
383 if (argo_debug[D_TPINPUT]) {
384 printf("tp_newsocket returning so %p, sototpcb(so) %p\n",
385 so, sototpcb(so));
387 #endif
388 return so;
392 * NAME: tp_input()
394 * CALLED FROM: net layer input routine
396 * FUNCTION and ARGUMENTS: Process an incoming TPDU (m), finding the associated
397 * tpcb if there is one. Create the appropriate type of event and call the
398 * driver. (faddr) and (laddr) are the foreign and local addresses.
400 * When tp_input() is called we KNOW that the ENTIRE TP HEADER has been
401 * m_pullup-ed.
403 * RETURN VALUE: Nada
405 * SIDE EFFECTS: When using COSNS it may affect the state of the net-level pcb
407 * NOTE: The initial value of acktime is 2 so that we will never have a 0 value
408 * for tp_peer_acktime. It gets used in the computation of the
409 * retransmission timer value, and so it mustn't be zero. 2 seems like a
410 * reasonable minimum.
412 void
413 tp_input(struct mbuf *m, ...)
415 struct sockaddr *faddr, *laddr; /* NSAP addresses */
416 void * cons_channel;
417 int (*dgout_routine) (struct mbuf *, ...);
418 int ce_bit;
419 struct tp_pcb *tpcb;
420 struct tpdu *hdr;
421 struct socket *so;
422 struct tp_event e;
423 int error;
424 unsigned dutype;
425 u_short dref, sref, acktime, subseq;
426 u_char preferred_class, class_to_use, pdusize;
427 u_char opt, dusize, addlopt, myversion = 0;
428 #ifdef TP_PERF_MEAS
429 u_char perf_meas;
430 #endif /* TP_PERF_MEAS */
431 u_char fsufxlen, lsufxlen;
432 void *fsufxloc, *lsufxloc;
433 int tpdu_len;
434 u_int takes_data;
435 u_int fcc_present;
436 int errlen;
437 struct tp_conn_param tpp;
438 va_list ap;
440 va_start(ap, m);
441 faddr = va_arg(ap, struct sockaddr *);
442 laddr = va_arg(ap, struct sockaddr *);
443 cons_channel = va_arg(ap, void *);
444 /* XXX: Does va_arg does not work for function ptrs */
445 dgout_routine = (int (*)(struct mbuf *, ...)) va_arg(ap, void *);
446 ce_bit = va_arg(ap, int);
447 va_end(ap);
449 again:
450 hdr = mtod(m, struct tpdu *);
451 tpcb = 0;
452 error = errlen = tpdu_len = 0;
453 takes_data = fcc_present = false;
454 acktime = 2;
455 sref = subseq = 0;
456 fsufxloc = lsufxloc = NULL;
457 fsufxlen = lsufxlen =
458 preferred_class = class_to_use = pdusize = addlopt = 0;
459 dusize = TP_DFL_TPDUSIZE;
460 #ifdef TP_PERF_MEAS
461 GET_CUR_TIME(&e.e_time);
462 perf_meas = 0;
463 #endif /* TP_PERF_MEAS */
465 #ifdef ARGO_DEBUG
466 if (argo_debug[D_TPINPUT]) {
467 printf("tp_input(%p, ... %p)\n", m, cons_channel);
469 #endif
473 * get the actual tpdu length - necessary for monitoring and for
474 * checksumming
476 * Also, maybe measure the mbuf chain lengths and sizes.
480 struct mbuf *n = m;
481 #ifdef ARGO_DEBUG
482 int chain_length = 0;
483 #endif /* ARGO_DEBUG */
485 for (;;) {
486 tpdu_len += n->m_len;
487 #ifdef ARGO_DEBUG
488 if (argo_debug[D_MBUF_MEAS]) {
489 if (n->m_flags & M_EXT) {
490 IncStat(ts_mb_cluster);
491 } else {
492 IncStat(ts_mb_small);
494 chain_length++;
496 #endif
497 if (n->m_next == NULL) {
498 break;
500 n = n->m_next;
502 #ifdef ARGO_DEBUG
503 if (argo_debug[D_MBUF_MEAS]) {
504 if (chain_length > 16)
505 chain_length = 0; /* zero used for
506 * anything > 16 */
507 tp_stat.ts_mb_len_distr[chain_length]++;
509 #endif
511 #ifdef TPPT
512 if (tp_traceflags[D_TPINPUT]) {
513 tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li + 1,
514 tpdu_len, 0);
516 #endif
518 dref = ntohs((short) hdr->tpdu_dref);
519 sref = ntohs((short) hdr->tpdu_sref);
520 dutype = (int) hdr->tpdu_type;
522 #ifdef ARGO_DEBUG
523 if (argo_debug[D_TPINPUT]) {
524 printf("input: dutype 0x%x cons_channel %p dref 0x%x\n",
525 dutype, cons_channel, dref);
526 printf("input: dref 0x%x sref 0x%x\n", dref, sref);
528 #endif
529 #ifdef TPPT
530 if (tp_traceflags[D_TPINPUT]) {
531 tptrace(TPPTmisc, "channel dutype dref ",
532 cons_channel, dutype, dref, 0);
534 #endif
537 #ifdef ARGO_DEBUG
538 if ((dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
539 printf("BAD dutype! 0x%x, channel %p dref 0x%x\n",
540 dutype, cons_channel, dref);
541 dump_buf(m, sizeof(struct mbuf));
543 IncStat(ts_inv_dutype);
544 goto discard;
546 #endif /* ARGO_DEBUG */
548 CHECK((dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
549 E_TP_INV_TPDU, ts_inv_dutype, respond,
552 * unfortunately we can't take the address of the tpdu_type field,
553 * since it's a bit field - so we just use the constant offset 2
557 * Now this isn't very neat but since you locate a pcb one way at the
558 * beginning of connection establishment, and by the dref for each
559 * tpdu after that, we have to treat CRs differently
561 if (dutype == CR_TPDU_type) {
562 u_char alt_classes = 0;
564 preferred_class = 1 << hdr->tpdu_CRclass;
565 opt = hdr->tpdu_CRoptions;
567 WHILE_OPTIONS(P, hdr, 1) /* { */
568 switch (vbptr(P)->tpv_code) {
570 case TPP_tpdu_size:
571 vb_getval(P, u_char, dusize);
572 #ifdef ARGO_DEBUG
573 if (argo_debug[D_TPINPUT]) {
574 printf("CR dusize 0x%x\n", dusize);
576 #endif
577 /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
578 if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
579 dusize = TP_DFL_TPDUSIZE;
580 break;
581 case TPP_ptpdu_size:
582 switch (vbptr(P)->tpv_len) {
583 case 1:
584 pdusize = vbval(P, u_char);
585 break;
586 case 2:
587 pdusize = ntohs(vbval(P, u_short));
588 break;
589 default:;
590 #ifdef ARGO_DEBUG
591 if (argo_debug[D_TPINPUT]) {
592 printf("malformed prefered TPDU option\n");
594 #endif
596 break;
597 case TPP_addl_opt:
598 vb_getval(P, u_char, addlopt);
599 break;
600 case TPP_calling_sufx:
602 * could use vb_getval, but we want to save the loc &
603 * len for later use
605 fsufxloc = (void *) & vbptr(P)->tpv_val;
606 fsufxlen = vbptr(P)->tpv_len;
607 #ifdef ARGO_DEBUG
608 if (argo_debug[D_TPINPUT]) {
609 printf("CR fsufx:");
611 int j;
612 for (j = 0; j < fsufxlen; j++) {
613 printf(" 0x%x. ", *((char *) fsufxloc + j));
615 printf("\n");
618 #endif
619 break;
620 case TPP_called_sufx:
622 * could use vb_getval, but we want to save the loc &
623 * len for later use
625 lsufxloc = &vbptr(P)->tpv_val;
626 lsufxlen = vbptr(P)->tpv_len;
627 #ifdef ARGO_DEBUG
628 if (argo_debug[D_TPINPUT]) {
629 printf("CR lsufx:");
631 int j;
632 for (j = 0; j < lsufxlen; j++) {
633 printf(" 0x%x. ", *((u_char *)lsufxloc + j));
635 printf("\n");
638 #endif
639 break;
641 #ifdef TP_PERF_MEAS
642 case TPP_perf_meas:
643 vb_getval(P, u_char, perf_meas);
644 break;
645 #endif /* TP_PERF_MEAS */
647 case TPP_vers:
648 /* not in class 0; 1 octet; in CR_TPDU only */
650 * COS tests says if version wrong, use default
651 * version!?XXX
653 CHECK((vbval(P, u_char) != TP_VERSION),
654 E_TP_INV_PVAL, ts_inv_pval, setversion,
655 (1 + (char *)&vbptr(P)->tpv_val - (char *)hdr));
656 setversion:
657 myversion = vbval(P, u_char);
658 break;
659 case TPP_acktime:
660 vb_getval(P, u_short, acktime);
661 acktime = ntohs(acktime);
662 acktime = acktime / 500; /* convert to slowtimo
663 * ticks */
664 if ((short) acktime <= 0)
665 acktime = 2; /* don't allow a bad peer to
666 * screw us up */
667 #ifdef ARGO_DEBUG
668 if (argo_debug[D_TPINPUT]) {
669 printf("CR acktime 0x%x\n", acktime);
671 #endif
672 break;
674 case TPP_alt_class:
676 u_char *aclass = 0;
677 int i;
678 static u_char bad_alt_classes[5] =
679 {~0, ~3, ~5, ~0xf, ~0x1f};
681 aclass =
682 (u_char *) & (((struct tp_vbp *) P)->tpv_val);
683 for (i = ((struct tp_vbp *) P)->tpv_len; i > 0; i--) {
684 alt_classes |= (1 << ((*aclass++) >> 4));
686 CHECK((bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
687 E_TP_INV_PVAL, ts_inv_aclass, respond,
688 ((char *) aclass) - (char *) hdr);
689 #ifdef ARGO_DEBUG
690 if (argo_debug[D_TPINPUT]) {
691 printf("alt_classes 0x%x\n", alt_classes);
693 #endif
695 break;
697 case TPP_security:
698 case TPP_residER:
699 case TPP_priority:
700 case TPP_transdelay:
701 case TPP_throughput:
702 case TPP_addl_info:
703 case TPP_subseq:
704 default:
705 #ifdef ARGO_DEBUG
706 if (argo_debug[D_TPINPUT]) {
707 printf("param ignored CR_TPDU code= 0x%x\n",
708 vbptr(P)->tpv_code);
710 #endif
711 IncStat(ts_param_ignored);
712 break;
714 case TPP_checksum:
715 #ifdef ARGO_DEBUG
716 if (argo_debug[D_TPINPUT]) {
717 printf("CR before cksum\n");
719 #endif
721 CHECK(iso_check_csum(m, tpdu_len),
722 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
723 #ifdef ARGO_DEBUG
724 if (argo_debug[D_TPINPUT]) {
725 printf("CR before cksum\n");
727 #endif
728 break;
731 /* } */ END_WHILE_OPTIONS(P)
732 if (lsufxlen == 0) {
733 /* can't look for a tpcb w/o any called sufx */
734 error = E_TP_LENGTH_INVAL;
735 IncStat(ts_inv_sufx);
736 goto respond;
737 } else {
738 struct tp_pcb *t;
740 * The intention here is to trap all CR requests
741 * to a given nsap, for constructing transport
742 * service bridges at user level; so these
743 * intercepts should precede the normal listens.
744 * Phrasing the logic in this way also allows for
745 * mop-up listeners, which we don't currently implement.
746 * We also wish to have a single socket be able to
747 * listen over any network service provider,
748 * (cons or clns or ip).
750 for (t = tp_listeners; t; t = t->tp_nextlisten)
751 if ((t->tp_lsuffixlen == 0 ||
752 (lsufxlen == t->tp_lsuffixlen &&
753 memcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) &&
754 ((t->tp_flags & TPF_GENERAL_ADDR) ||
755 (laddr->sa_family == t->tp_domain &&
756 (*t->tp_nlproto->nlp_cmpnetaddr)
757 (t->tp_npcb, laddr, TP_LOCAL))))
758 break;
760 CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
761 (1 + 2 + (char *)&hdr->_tpduf - (char *)hdr))
763 * _tpduf is the fixed part; add 2 to get the dref
764 * bits of the fixed part (can't take the address of
765 * a bit field)
767 #ifdef ARGO_DEBUG
768 if (argo_debug[D_TPINPUT]) {
769 printf("checking if dup CR\n");
771 #endif
772 tpcb = t;
773 for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
774 if (sref != t->tp_fref)
775 continue;
776 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr) (
777 t->tp_npcb, faddr, TP_FOREIGN)) {
778 #ifdef ARGO_DEBUG
779 if (argo_debug[D_TPINPUT]) {
780 printf("duplicate CR discarded\n");
782 #endif
783 goto discard;
786 #ifdef TPPT
787 if (tp_traceflags[D_TPINPUT]) {
788 tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
789 tpcb, *lsufxloc, tpcb->tp_state, 0);
791 #endif
795 * WE HAVE A TPCB already know that the classes in the CR
796 * match at least one class implemented, but we don't know
797 * yet if they include any classes permitted by this server.
800 #ifdef ARGO_DEBUG
801 if (argo_debug[D_TPINPUT]) {
802 printf("HAVE A TPCB 1: %p\n", tpcb);
804 #endif
805 #ifdef ARGO_DEBUG
806 if (argo_debug[D_CONN]) {
807 printf(
808 "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
809 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
811 #endif
812 /* tpcb->tp_class doesn't include any classes not implemented */
813 class_to_use = (preferred_class & tpcb->tp_class);
814 if ((class_to_use = preferred_class & tpcb->tp_class) == 0)
815 class_to_use = alt_classes & tpcb->tp_class;
817 class_to_use = 1 << tp_mask_to_num(class_to_use);
820 tpp = tpcb->_tp_param;
821 tpp.p_class = class_to_use;
822 tpp.p_tpdusize = dusize;
823 tpp.p_ptpdusize = pdusize;
824 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
825 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
826 tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0) ? 0 :
827 (addlopt & TPAO_NO_CSUM) == 0;
828 tpp.p_version = myversion;
829 #ifdef notdef
830 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
831 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
832 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
833 #endif /* notdef */
835 CHECK(
836 tp_consistency(tpcb, 0 /* not force or strict */ , &tpp) != 0,
837 E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
838 (1 + 2 + (char *)&hdr->_tpdufr.CRCC - (char *)hdr)
839 /* ^ more or less the location of class */
842 #ifdef TPPT
843 if (tp_traceflags[D_CONN]) {
844 tptrace(TPPTmisc,
845 "after 1 consist class_to_use class, out, tpconsout",
846 class_to_use,
847 tpcb->tp_class, dgout_routine, tpcons_output
850 #endif
851 CHECK(((class_to_use == TP_CLASS_0) &&
852 (dgout_routine != tpcons_output)),
853 E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
854 (1 + 2 + (char *)&hdr->_tpdufr.CRCC - (char *)hdr)
855 /* ^ more or less the location of class */
857 #ifdef ARGO_DEBUG
858 if (argo_debug[D_CONN]) {
859 printf("CR: after CRCCCHECKS: tpcb %p, flags 0x%x\n",
860 tpcb, tpcb->tp_flags);
862 #endif
863 takes_data = true;
864 e.TPDU_ATTR(CR).e_cdt = hdr->tpdu_CRcdt;
865 e.ev_number = CR_TPDU;
867 so = tpcb->tp_sock;
868 if (so->so_options & SO_ACCEPTCONN) {
869 struct tp_pcb *parent_tpcb = tpcb;
871 * Create a socket, tpcb, ll pcb, etc. for this
872 * newborn connection, and fill in all the values.
874 #ifdef ARGO_DEBUG
875 if (argo_debug[D_CONN]) {
876 printf("abt to call tp_newsocket(%p, %p, %p, %p)\n",
877 so, laddr, faddr, cons_channel);
879 #endif
880 if ((so =
881 tp_newsocket(so, faddr, cons_channel,
882 class_to_use,
883 ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
884 (dgout_routine == tpcons_output) ? ISO_CONS : ISO_CLNS))
885 ) == (struct socket *) 0) {
887 * note - even if netservice is IN_CLNS, as
888 * far as the tp entity is concerned, the
889 * only differences are CO vs CL
891 #ifdef ARGO_DEBUG
892 if (argo_debug[D_CONN]) {
893 printf("tp_newsocket returns 0\n");
895 #endif
896 goto discard;
897 clear_parent_tcb:
898 tpcb = 0;
899 goto respond;
901 tpcb = sototpcb(so);
902 iso_insque(tpcb, parent_tpcb);
905 * Stash the addresses in the net level pcb
906 * kind of like a pcbconnect() but don't need
907 * or want all those checks.
909 (tpcb->tp_nlproto->nlp_putnetaddr) (tpcb->tp_npcb, faddr, TP_FOREIGN);
910 (tpcb->tp_nlproto->nlp_putnetaddr) (tpcb->tp_npcb, laddr, TP_LOCAL);
912 /* stash the f suffix in the new tpcb */
913 if ((tpcb->tp_fsuffixlen = fsufxlen) != 0) {
914 memcpy(tpcb->tp_fsuffix, fsufxloc, fsufxlen);
915 (tpcb->tp_nlproto->nlp_putsufx)
916 (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN);
918 /* stash the l suffix in the new tpcb */
919 tpcb->tp_lsuffixlen = lsufxlen;
920 memcpy(tpcb->tp_lsuffix, lsufxloc, lsufxlen);
921 (tpcb->tp_nlproto->nlp_putsufx)
922 (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL);
923 #ifdef TP_PERF_MEAS
924 if (tpcb->tp_perf_on = perf_meas) { /* assignment */
926 * ok, let's create an mbuf for stashing the
927 * statistics if one doesn't already exist
929 (void) tp_setup_perf(tpcb);
931 #endif /* TP_PERF_MEAS */
932 tpcb->tp_fref = sref;
935 * We've already checked for consistency with the
936 * options set in tpp, but we couldn't set them
937 * earlier because we didn't want to change options
938 * in the LISTENING tpcb. Now we set the options in
939 * the new socket's tpcb.
941 (void) tp_consistency(tpcb, TP_FORCE, &tpp);
943 if (!tpcb->tp_use_checksum)
944 IncStat(ts_csum_off);
945 if (tpcb->tp_xpd_service)
946 IncStat(ts_use_txpd);
947 if (tpcb->tp_xtd_format)
948 IncStat(ts_xtd_fmt);
950 tpcb->tp_peer_acktime = acktime;
953 * The following kludge is used to test
954 * retransmissions and timeout during connection
955 * establishment.
957 #ifdef ARGO_DEBUG
958 if (argo_debug[D_ZDREF]) {
959 IncStat(ts_zdebug);
960 /* tpcb->tp_fref = 0; */
962 #endif
964 LOCAL_CREDIT(tpcb);
965 IncStat(ts_CR_rcvd);
966 if (!tpcb->tp_cebit_off) {
967 tpcb->tp_win_recv = tp_start_win << 8;
968 tpcb->tp_cong_sample.cs_size = 0;
969 CONG_INIT_SAMPLE(tpcb);
970 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
972 } else if (dutype == ER_TPDU_type) {
974 * ER TPDUs have to be recognized separately because they
975 * don't necessarily have a tpcb with them and we don't want
976 * err out looking for such a beast. We could put a bunch of
977 * little kludges in the next section of code so it would
978 * avoid references to tpcb if dutype == ER_TPDU_type but we
979 * don't want code for ERs to mess up code for data transfer.
981 IncStat(ts_ER_rcvd);
982 e.ev_number = ER_TPDU;
983 e.TPDU_ATTR(ER).e_reason = (u_char) hdr->tpdu_ERreason;
984 CHECK(((int) dref <= 0 || dref >= tp_refinfo.tpr_size ||
985 (tpcb = tp_ref[dref].tpr_pcb) == (struct tp_pcb *) 0 ||
986 tpcb->tp_refstate == REF_FREE ||
987 tpcb->tp_refstate == REF_FROZEN),
988 E_TP_MISM_REFS, ts_inv_dref, discard, 0)
989 } else {
990 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
993 * In the next 4 checks, _tpduf is the fixed part; add 2 to
994 * get the dref bits of the fixed part (can't take the
995 * address of a bit field)
999 CHECK(((int) dref <= 0 || dref >= tp_refinfo.tpr_size),
1000 E_TP_MISM_REFS, ts_inv_dref, nonx_dref,
1001 (1 + 2 + (char *)&hdr->_tpduf - (char *)hdr))
1002 CHECK(((tpcb = tp_ref[dref].tpr_pcb) == (struct tp_pcb *) 0),
1003 E_TP_MISM_REFS, ts_inv_dref, nonx_dref,
1004 (1 + 2 + (char *)&hdr->_tpduf - (char *)hdr))
1005 CHECK((tpcb->tp_refstate == REF_FREE),
1006 E_TP_MISM_REFS, ts_inv_dref, nonx_dref,
1007 (1 + 2 + (char *)&hdr->_tpduf - (char *)hdr))
1010 #ifdef ARGO_DEBUG
1011 if (argo_debug[D_TPINPUT]) {
1012 printf("HAVE A TPCB 2: %p\n", tpcb);
1014 #endif
1016 /* causes a DR to be sent for CC; ER for all else */
1017 CHECK((tpcb->tp_refstate == REF_FROZEN),
1018 (dutype == CC_TPDU_type ? E_TP_NO_SESSION : E_TP_MISM_REFS),
1019 ts_inv_dref, respond,
1020 (1 + 2 + (char *)&hdr->_tpduf - (char *)hdr))
1021 #ifdef ARGO_DEBUG
1022 if (argo_debug[D_TPINPUT]) {
1023 printf("state of dref %d ok, tpcb %p\n", dref, tpcb);
1025 #endif
1027 * At this point the state of the dref could be FROZEN:
1028 * tpr_pcb == NULL, has ( reference only) timers for
1029 * example, DC may arrive after the close() has detached the
1030 * tpcb (e.g., if user turned off SO_LISTEN option) OPENING :
1031 * a tpcb exists but no timers yet OPEN : tpcb exists &
1032 * timers are outstanding
1035 if (!tpcb->tp_cebit_off)
1036 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
1038 dusize = tpcb->tp_tpdusize;
1039 pdusize = tpcb->tp_ptpdusize;
1041 dutype = hdr->tpdu_type << 8; /* for the switch below */
1043 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
1044 #define caseof(x,y) case (((x)<<8)+(y))
1045 switch (dutype | vbptr(P)->tpv_code) {
1047 caseof(CC_TPDU_type, TPP_addl_opt):
1048 /* not in class 0; 1 octet */
1049 vb_getval(P, u_char, addlopt);
1050 break;
1051 caseof(CC_TPDU_type, TPP_tpdu_size):
1053 u_char odusize = dusize;
1054 vb_getval(P, u_char, dusize);
1055 CHECK((dusize < TP_MIN_TPDUSIZE ||
1056 dusize > TP_MAX_TPDUSIZE || dusize > odusize),
1057 E_TP_INV_PVAL, ts_inv_pval, respond,
1058 (1 + (char *)&vbptr(P)->tpv_val - (char *) hdr))
1059 #ifdef ARGO_DEBUG
1060 if (argo_debug[D_TPINPUT]) {
1061 printf("CC dusize 0x%x\n", dusize);
1063 #endif
1065 break;
1066 caseof(CC_TPDU_type, TPP_ptpdu_size):
1068 u_short opdusize = pdusize;
1069 switch (vbptr(P)->tpv_len) {
1070 case 1:
1071 pdusize = vbval(P, u_char);
1072 break;
1073 case 2:
1074 pdusize = ntohs(vbval(P, u_short));
1075 break;
1076 default:;
1077 #ifdef ARGO_DEBUG
1078 if (argo_debug[D_TPINPUT]) {
1079 printf("malformed prefered TPDU option\n");
1081 #endif
1083 CHECK((pdusize == 0 ||
1084 (opdusize && (pdusize > opdusize))),
1085 E_TP_INV_PVAL, ts_inv_pval, respond,
1086 (1 + (char *)&vbptr(P)->tpv_val - (char *)hdr))
1088 break;
1089 caseof(CC_TPDU_type, TPP_calling_sufx):
1090 #ifdef ARGO_DEBUG
1091 if (argo_debug[D_TPINPUT]) {
1092 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
1094 #endif
1095 lsufxloc = &vbptr(P)->tpv_val;
1096 lsufxlen = vbptr(P)->tpv_len;
1097 break;
1098 caseof(CC_TPDU_type, TPP_acktime):
1099 /* class 4 only, 2 octets */
1100 vb_getval(P, u_short, acktime);
1101 acktime = ntohs(acktime);
1102 acktime = acktime / 500; /* convert to slowtimo
1103 * ticks */
1104 if ((short) acktime <= 0)
1105 acktime = 2;
1106 break;
1107 caseof(CC_TPDU_type, TPP_called_sufx):
1108 fsufxloc = (void *) & vbptr(P)->tpv_val;
1109 fsufxlen = vbptr(P)->tpv_len;
1110 #ifdef ARGO_DEBUG
1111 if (argo_debug[D_TPINPUT]) {
1112 printf("CC called (foreign) sufx len %d\n", fsufxlen);
1114 #endif
1115 break;
1117 caseof(CC_TPDU_type, TPP_checksum):
1118 caseof(DR_TPDU_type, TPP_checksum):
1119 caseof(DT_TPDU_type, TPP_checksum):
1120 caseof(XPD_TPDU_type, TPP_checksum):
1121 if (tpcb->tp_use_checksum) {
1122 CHECK(iso_check_csum(m, tpdu_len),
1123 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
1125 break;
1128 * this is different from the above because in the
1129 * context of concat/ sep tpdu_len might not be the
1130 * same as hdr len
1132 caseof(AK_TPDU_type, TPP_checksum):
1133 caseof(XAK_TPDU_type, TPP_checksum):
1134 caseof(DC_TPDU_type, TPP_checksum):
1135 if (tpcb->tp_use_checksum) {
1136 CHECK(iso_check_csum(m, (int) hdr->tpdu_li + 1),
1137 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
1139 break;
1140 #ifdef notdef
1141 caseof(DR_TPDU_type, TPP_addl_info):
1143 * ignore - its length and meaning are user defined
1144 * and there's no way to pass this info to the user
1145 * anyway
1147 break;
1148 #endif /* notdef */
1150 caseof(AK_TPDU_type, TPP_subseq):
1151 /* used after reduction of window */
1152 vb_getval(P, u_short, subseq);
1153 subseq = ntohs(subseq);
1154 #ifdef ARGO_DEBUG
1155 if (argo_debug[D_ACKRECV]) {
1156 printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq);
1158 #endif
1159 break;
1161 caseof(AK_TPDU_type, TPP_flow_cntl_conf):
1163 u_int ylwe;
1164 u_short ysubseq, ycredit;
1166 fcc_present = true;
1167 vb_getval(P, u_int, ylwe);
1168 vb_getval(P, u_short, ysubseq);
1169 vb_getval(P, u_short, ycredit);
1170 ylwe = ntohl(ylwe);
1171 ysubseq = ntohs(ysubseq);
1172 ycredit = ntohs(ycredit);
1173 #ifdef ARGO_DEBUG
1174 if (argo_debug[D_ACKRECV]) {
1175 printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n",
1176 "AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref);
1178 #endif
1180 break;
1182 default:
1183 #ifdef ARGO_DEBUG
1184 if (argo_debug[D_TPINPUT]) {
1185 printf("param ignored dutype 0x%x, code 0x%x\n",
1186 dutype, vbptr(P)->tpv_code);
1188 #endif
1189 #ifdef TPPT
1190 if (tp_traceflags[D_TPINPUT]) {
1191 tptrace(TPPTmisc, "param ignored dutype code ",
1192 dutype, vbptr(P)->tpv_code, 0, 0);
1194 #endif
1195 IncStat(ts_param_ignored);
1196 break;
1197 #undef caseof
1199 /* } */ END_WHILE_OPTIONS(P)
1200 /* NOTE: the variable dutype has been shifted left! */
1202 switch (hdr->tpdu_type) {
1203 case CC_TPDU_type:
1205 * If CC comes back with an unacceptable class
1206 * respond with a DR or ER
1209 opt = hdr->tpdu_CCoptions; /* 1 byte */
1212 tpp = tpcb->_tp_param;
1213 tpp.p_class = (1 << hdr->tpdu_CCclass);
1214 tpp.p_tpdusize = dusize;
1215 tpp.p_ptpdusize = pdusize;
1216 tpp.p_dont_change_params = 0;
1217 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1218 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1219 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1220 #ifdef notdef
1221 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1222 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1223 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
1224 #endif /* notdef */
1226 CHECK(
1227 tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1228 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1229 (1 + 2 + (char *)&hdr->_tpdufr.CRCC - (char *)hdr)
1230 /* ^ more or less the location of class */
1232 #ifdef TPPT
1233 if (tp_traceflags[D_CONN]) {
1234 tptrace(TPPTmisc,
1235 "after 1 consist class, out, tpconsout",
1236 tpcb->tp_class, dgout_routine, tpcons_output, 0
1239 #endif
1240 CHECK(
1241 ((class_to_use == TP_CLASS_0) &&
1242 (dgout_routine != tpcons_output)),
1243 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1244 (1 + 2 + (char *)&hdr->_tpdufr.CRCC - (char *)hdr)
1245 /* ^ more or less the location of class */
1248 if (!tpcb->tp_use_checksum)
1249 IncStat(ts_csum_off);
1250 if (tpcb->tp_xpd_service)
1251 IncStat(ts_use_txpd);
1252 if (tpcb->tp_xtd_format)
1253 IncStat(ts_xtd_fmt);
1255 #ifdef TPPT
1256 if (tp_traceflags[D_CONN]) {
1257 tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1258 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1259 hdr->tpdu_CCclass);
1261 #endif
1264 * if called or calling suffixes appeared on the CC,
1265 * they'd better jive with what's in the pcb
1267 if (fsufxlen) {
1268 CHECK(((tpcb->tp_fsuffixlen != fsufxlen) ||
1269 memcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1270 E_TP_INV_PVAL, ts_inv_sufx, respond,
1271 (1 + (char *)fsufxloc - (char *)hdr))
1273 if (lsufxlen) {
1274 CHECK(((tpcb->tp_lsuffixlen != lsufxlen) ||
1275 memcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1276 E_TP_INV_PVAL, ts_inv_sufx, respond,
1277 (1 + (char *)lsufxloc - (char *)hdr))
1279 e.TPDU_ATTR(CC).e_sref = sref;
1280 e.TPDU_ATTR(CC).e_cdt = hdr->tpdu_CCcdt;
1281 takes_data = true;
1282 e.ev_number = CC_TPDU;
1283 IncStat(ts_CC_rcvd);
1284 break;
1286 case DC_TPDU_type:
1287 if (sref != tpcb->tp_fref)
1288 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1289 sref, tpcb->tp_fref);
1291 CHECK((sref != tpcb->tp_fref),
1292 E_TP_MISM_REFS, ts_inv_sufx, discard,
1293 (1 + (char *)&hdr->tpdu_DCsref - (char *)hdr))
1294 e.ev_number = DC_TPDU;
1295 IncStat(ts_DC_rcvd);
1296 break;
1298 case DR_TPDU_type:
1299 #ifdef TPPT
1300 if (tp_traceflags[D_TPINPUT]) {
1301 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1303 #endif
1304 if (sref != tpcb->tp_fref) {
1305 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1306 sref, tpcb->tp_fref);
1308 CHECK((sref != 0 && sref != tpcb->tp_fref &&
1309 tpcb->tp_state != TP_CRSENT),
1310 (TP_ERROR_SNDC | E_TP_MISM_REFS), ts_inv_sufx, respond,
1311 (1 + (char *)&hdr->tpdu_DRsref - (char *)hdr))
1312 e.TPDU_ATTR(DR).e_reason = hdr->tpdu_DRreason;
1313 e.TPDU_ATTR(DR).e_sref = (u_short) sref;
1314 takes_data = true;
1315 e.ev_number = DR_TPDU;
1316 IncStat(ts_DR_rcvd);
1317 break;
1319 case ER_TPDU_type:
1320 #ifdef TPPT
1321 if (tp_traceflags[D_TPINPUT]) {
1322 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason, 0, 0, 0);
1324 #endif
1325 e.ev_number = ER_TPDU;
1326 e.TPDU_ATTR(ER).e_reason = hdr->tpdu_ERreason;
1327 IncStat(ts_ER_rcvd);
1328 break;
1330 case AK_TPDU_type:
1332 e.TPDU_ATTR(AK).e_subseq = subseq;
1333 e.TPDU_ATTR(AK).e_fcc_present = fcc_present;
1335 if (tpcb->tp_xtd_format) {
1336 #ifdef BYTE_ORDER
1337 union seq_type seqeotX;
1339 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1340 e.TPDU_ATTR(AK).e_seq = seqeotX.s_seq;
1341 e.TPDU_ATTR(AK).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1342 #else
1343 e.TPDU_ATTR(AK).e_cdt = hdr->tpdu_AKcdtX;
1344 e.TPDU_ATTR(AK).e_seq = hdr->tpdu_AKseqX;
1345 #endif /* BYTE_ORDER */
1346 } else {
1347 e.TPDU_ATTR(AK).e_cdt = hdr->tpdu_AKcdt;
1348 e.TPDU_ATTR(AK).e_seq = hdr->tpdu_AKseq;
1350 #ifdef TPPT
1351 if (tp_traceflags[D_TPINPUT]) {
1352 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1353 e.TPDU_ATTR(AK).e_seq, e.TPDU_ATTR(AK).e_cdt,
1354 subseq, fcc_present);
1356 #endif
1358 e.ev_number = AK_TPDU;
1359 IncStat(ts_AK_rcvd);
1360 IncPStat(tpcb, tps_AK_rcvd);
1361 break;
1363 case XAK_TPDU_type:
1364 if (tpcb->tp_xtd_format) {
1365 #ifdef BYTE_ORDER
1366 union seq_type seqeotX;
1368 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1369 e.TPDU_ATTR(XAK).e_seq = seqeotX.s_seq;
1370 #else
1371 e.TPDU_ATTR(XAK).e_seq = hdr->tpdu_XAKseqX;
1372 #endif /* BYTE_ORDER */
1373 } else {
1374 e.TPDU_ATTR(XAK).e_seq = hdr->tpdu_XAKseq;
1376 e.ev_number = XAK_TPDU;
1377 IncStat(ts_XAK_rcvd);
1378 IncPStat(tpcb, tps_XAK_rcvd);
1379 break;
1381 case XPD_TPDU_type:
1382 if (tpcb->tp_xtd_format) {
1383 #ifdef BYTE_ORDER
1384 union seq_type seqeotX;
1386 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1387 e.TPDU_ATTR(XPD).e_seq = seqeotX.s_seq;
1388 #else
1389 e.TPDU_ATTR(XPD).e_seq = hdr->tpdu_XPDseqX;
1390 #endif /* BYTE_ORDER */
1391 } else {
1392 e.TPDU_ATTR(XPD).e_seq = hdr->tpdu_XPDseq;
1394 takes_data = true;
1395 e.ev_number = XPD_TPDU;
1396 IncStat(ts_XPD_rcvd);
1397 IncPStat(tpcb, tps_XPD_rcvd);
1398 break;
1400 case DT_TPDU_type:
1402 * the y option will cause occasional packets
1403 * to be dropped. A little crude but it
1404 * works.
1407 #ifdef ARGO_DEBUG
1408 if (argo_debug[D_DROP]) {
1409 if (time_second & 0x4 &&
1410 hdr->tpdu_DTseq & 0x1) {
1411 IncStat(ts_ydebug);
1412 goto discard;
1415 #endif
1416 if (tpcb->tp_class == TP_CLASS_0) {
1417 e.TPDU_ATTR(DT).e_seq = 0; /* actually don't care */
1418 e.TPDU_ATTR(DT).e_eot = (((struct tp0du *) hdr)->tp0du_eot);
1419 } else if (tpcb->tp_xtd_format) {
1420 #ifdef BYTE_ORDER
1421 union seq_type seqeotX;
1423 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1424 e.TPDU_ATTR(DT).e_seq = seqeotX.s_seq;
1425 e.TPDU_ATTR(DT).e_eot = seqeotX.s_eot;
1426 #else
1427 e.TPDU_ATTR(DT).e_seq = hdr->tpdu_DTseqX;
1428 e.TPDU_ATTR(DT).e_eot = hdr->tpdu_DTeotX;
1429 #endif /* BYTE_ORDER */
1430 } else {
1431 e.TPDU_ATTR(DT).e_seq = hdr->tpdu_DTseq;
1432 e.TPDU_ATTR(DT).e_eot = hdr->tpdu_DTeot;
1434 if (e.TPDU_ATTR(DT).e_eot)
1435 IncStat(ts_eot_input);
1436 takes_data = true;
1437 e.ev_number = DT_TPDU;
1438 IncStat(ts_DT_rcvd);
1439 IncPStat(tpcb, tps_DT_rcvd);
1440 break;
1442 case GR_TPDU_type:
1443 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1444 /* drop through */
1445 default:
1447 * this should NEVER happen because there is a check
1448 * for dutype well above here
1450 error = E_TP_INV_TPDU; /* causes an ER */
1451 #ifdef ARGO_DEBUG
1452 if (argo_debug[D_TPINPUT]) {
1453 printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1455 #endif
1456 IncStat(ts_inv_dutype);
1457 goto respond;
1461 * peel off the tp header; remember that the du_li doesn't count
1462 * itself. This may leave us w/ an empty mbuf at the front of a
1463 * chain. We can't just throw away the empty mbuf because hdr still
1464 * points into the mbuf's data area and we're still using hdr (the
1465 * tpdu header)
1467 m->m_len -= ((int) hdr->tpdu_li + 1);
1468 m->m_data += ((int) hdr->tpdu_li + 1);
1470 if (takes_data) {
1471 int xmax = tpdu_info[hdr->tpdu_type][TP_MAX_DATA_INDEX];
1472 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
1473 struct {
1474 struct tp_disc_reason dr;
1475 struct cmsghdr x_hdr;
1476 } x;
1477 #define c_hdr x.x_hdr
1478 struct mbuf *n;
1480 CHECK((xmax && datalen > xmax), E_TP_LENGTH_INVAL,
1481 ts_inv_length, respond, (xmax + hdr->tpdu_li + 1));
1482 switch (hdr->tpdu_type) {
1484 case CR_TPDU_type:
1485 c_hdr.cmsg_type = TPOPT_CONN_DATA;
1486 goto make_control_msg;
1488 case CC_TPDU_type:
1489 c_hdr.cmsg_type = TPOPT_CFRM_DATA;
1490 goto make_control_msg;
1492 case DR_TPDU_type:
1493 x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
1494 x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
1495 x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
1496 x.dr.dr_reason = hdr->tpdu_DRreason;
1497 c_hdr.cmsg_type = TPOPT_DISC_DATA;
1498 make_control_msg:
1499 datalen += sizeof(c_hdr);
1500 c_hdr.cmsg_len = datalen;
1501 c_hdr.cmsg_level = SOL_TRANSPORT;
1502 mbtype = MT_CONTROL;
1503 MGET(n, M_DONTWAIT, MT_DATA);
1504 if (n == 0) {
1505 m_freem(m);
1506 m = 0;
1507 datalen = 0;
1508 goto invoke;
1510 if (hdr->tpdu_type == DR_TPDU_type) {
1511 datalen += sizeof(x) - sizeof(c_hdr);
1512 memcpy(mtod(n, void *), (void *) &x, n->m_len = sizeof(x));
1513 } else
1514 memcpy(mtod(n, void *), (void *) &c_hdr,
1515 n->m_len = sizeof(c_hdr));
1516 n->m_next = m;
1517 m = n;
1518 /* FALLTHROUGH */
1520 case XPD_TPDU_type:
1521 if (mbtype != MT_CONTROL)
1522 mbtype = MT_OOBDATA;
1523 m->m_flags |= M_EOR;
1524 /* FALLTHROUGH */
1526 case DT_TPDU_type:
1527 for (n = m; n; n = n->m_next) {
1528 MCHTYPE(n, mbtype);
1530 invoke:
1531 e.TPDU_ATTR(DT).e_datalen = datalen;
1532 e.TPDU_ATTR(DT).e_data = m;
1533 break;
1535 default:
1536 printf(
1537 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m %p\n",
1538 hdr->tpdu_type, takes_data, m);
1539 break;
1542 * prevent m_freem() after tp_driver() from throwing it all
1543 * away
1545 m = NULL;
1547 IncStat(ts_tpdu_rcvd);
1549 #ifdef ARGO_DEBUG
1550 if (argo_debug[D_TPINPUT]) {
1551 printf("tp_input: before driver, state 0x%x event 0x%x m %p",
1552 tpcb->tp_state, e.ev_number, m);
1553 printf(" e.e_data %p\n", e.TPDU_ATTR(DT).e_data);
1554 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1555 takes_data, (m == NULL) ? 0 : m->m_len, tpdu_len);
1557 #endif
1559 error = tp_driver(tpcb, &e);
1561 ASSERT(tpcb != (struct tp_pcb *) 0);
1562 ASSERT(tpcb->tp_sock != (struct socket *) 0);
1563 if (tpcb->tp_sock->so_error == 0)
1564 tpcb->tp_sock->so_error = error;
1567 * Kludge to keep the state tables under control (adding data on
1568 * connect & disconnect & freeing the mbuf containing the data would
1569 * have exploded the tables and made a big mess ).
1571 switch (e.ev_number) {
1572 case CC_TPDU:
1573 case DR_TPDU:
1574 case CR_TPDU:
1575 m = e.TPDU_ATTR(CC).e_data; /* same field for all three
1576 * dutypes */
1577 #ifdef ARGO_DEBUG
1578 if (argo_debug[D_TPINPUT]) {
1579 printf("after driver, restoring m to %p, takes_data 0x%x\n",
1580 m, takes_data);
1582 #endif
1583 break;
1584 default:
1585 break;
1588 * Concatenated sequences are terminated by any tpdu that carries
1589 * data: CR, CC, DT, XPD, DR. All other tpdu types may be
1590 * concatenated: AK, XAK, DC, ER.
1593 if (takes_data == 0) {
1594 ASSERT(m != NULL);
1596 * we already peeled off the prev. tp header so we can just
1597 * pull up some more and repeat
1600 if ((m = tp_inputprep(m)) != NULL) {
1601 #ifdef ARGO_DEBUG
1602 if (argo_debug[D_TPINPUT]) {
1603 hdr = mtod(m, struct tpdu *);
1604 printf("tp_input @ separate: hdr %p size %d m %p\n",
1605 hdr, (int) hdr->tpdu_li + 1, m);
1606 dump_mbuf(m, "tp_input after driver, at separate");
1608 #endif
1610 IncStat(ts_concat_rcvd);
1611 goto again;
1614 if (m != NULL) {
1615 #ifdef ARGO_DEBUG
1616 if (argo_debug[D_TPINPUT]) {
1617 printf("tp_input : m_freem(%p)\n", m);
1619 #endif
1620 m_freem(m);
1621 #ifdef ARGO_DEBUG
1622 if (argo_debug[D_TPINPUT]) {
1623 printf("tp_input : after m_freem %p\n", m);
1625 #endif
1627 return;
1629 discard:
1630 /* class 4: drop the tpdu */
1632 * class 2,0: Should drop the net connection, if you can figure out
1633 * to which connection it applies
1635 #ifdef ARGO_DEBUG
1636 if (argo_debug[D_TPINPUT]) {
1637 printf("tp_input DISCARD\n");
1639 #endif
1640 #ifdef TPPT
1641 if (tp_traceflags[D_TPINPUT]) {
1642 tptrace(TPPTmisc, "tp_input DISCARD m", m, 0, 0, 0);
1644 #endif
1645 m_freem(m);
1646 IncStat(ts_recv_drop);
1647 return;
1649 nonx_dref:
1650 switch (dutype) {
1651 default:
1652 goto discard;
1653 case CC_TPDU_type:
1654 /* error = E_TP_MISM_REFS; */
1655 break;
1656 case DR_TPDU_type:
1657 error |= TP_ERROR_SNDC;
1659 respond:
1660 #ifdef ARGO_DEBUG
1661 if (argo_debug[D_TPINPUT]) {
1662 printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
1664 #endif
1665 #ifdef TPPT
1666 if (tp_traceflags[D_TPINPUT]) {
1667 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
1669 #endif
1670 if (sref == 0)
1671 goto discard;
1672 (void) tp_error_emit(error, (u_long) sref, satosiso(faddr),
1673 satosiso(laddr), m, errlen, tpcb,
1674 cons_channel, dgout_routine);
1675 #ifdef ARGO_DEBUG
1676 if (argo_debug[D_ERROR_EMIT]) {
1677 printf("tp_input after error_emit\n");
1679 #endif
1681 #ifdef lint
1682 printf("", sref, opt);
1683 #endif /* lint */
1684 IncStat(ts_recv_drop);
1689 * NAME: tp_headersize()
1691 * CALLED FROM:
1692 * tp_emit() and tp_sbsend()
1693 * TP needs to know the header size so it can figure out how
1694 * much data to put in each tpdu.
1696 * FUNCTION, ARGUMENTS, and RETURN VALUE:
1697 * For a given connection, represented by (tpcb), and
1698 * tpdu type (dutype), return the size of a tp header.
1700 * RETURNS: the expected size of the heade in bytesr
1702 * SIDE EFFECTS:
1704 * NOTES: It would be nice if it got the network header size as well.
1707 tp_headersize(int dutype, struct tp_pcb *tpcb)
1709 int size = 0;
1711 #ifdef TPPT
1712 if (tp_traceflags[D_CONN]) {
1713 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1714 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1716 #endif
1717 if (!((tpcb->tp_class == TP_CLASS_0) ||
1718 (tpcb->tp_class == TP_CLASS_4) ||
1719 (dutype == DR_TPDU_type) ||
1720 (dutype == CR_TPDU_type))) {
1721 printf("tp_headersize:dutype 0x%x, class 0x%x",
1722 dutype, tpcb->tp_class);
1723 /* TODO: identify this and GET RID OF IT */
1725 ASSERT((tpcb->tp_class == TP_CLASS_0) ||
1726 (tpcb->tp_class == TP_CLASS_4) ||
1727 (dutype == DR_TPDU_type) ||
1728 (dutype == CR_TPDU_type));
1730 if (tpcb->tp_class == TP_CLASS_0) {
1731 size = tpdu_info[dutype][TP_LEN_CLASS_0_INDEX];
1732 } else {
1733 size = tpdu_info[dutype][tpcb->tp_xtd_format];
1735 return size;
1736 /* caller must get network level header size separately */