1 /* $NetBSD: tp_input.c,v 1.33 2009/03/18 22:08:57 he Exp $ */
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
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
31 * @(#)tp_input.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
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
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
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 $");
86 #include <sys/param.h>
87 #include <sys/systm.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>
95 #include <sys/kernel.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
);
118 tp_inputprep(struct mbuf
*m
)
123 if (argo_debug
[D_TPINPUT
]) {
124 printf("tp_inputprep: m %p\n", m
);
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
)
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;
173 if (argo_debug
[D_INPUT
]) {
175 " at end: m %p hdr->tpdu_li 0x%x m_len 0x%x\n", 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);\
219 * WHENEVER YOU USE THE FOLLOWING MACRO, BE SURE THE TPDUTYPE IS A LEGIT
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) } }
236 * NAME: tp_newsocket()
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)
249 * a new socket structure, being this end of the newly formed connection.
252 * Sets a few things in the tpcb and net level pcb
256 static struct socket
*
259 struct sockaddr
*fname
,
264 struct tp_pcb
*tpcb
= sototpcb(so
); /* old tpcb, needed
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)
273 if (tp_traceflags
[D_NEWSOCK
]) {
274 tptraceTPCB(TPPTmisc
, "newsock: listg_so, _tpcb, so_head",
275 so
, tpcb
, so
->so_head
, 0);
279 if ((so
= sonewconn(so
, SS_ISCONFIRMING
)) == (struct socket
*) 0)
282 if (tp_traceflags
[D_NEWSOCK
]) {
283 tptraceTPCB(TPPTmisc
, "newsock: after newconn so, so_head",
284 so
, so
->so_head
, 0, 0);
289 if (argo_debug
[D_NEWSOCK
]) {
290 printf("tp_newsocket(channel %p) after sonewconn so %p \n",
294 struct socket
*t
, *head
;
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
,
309 * before we clobber the old tpcb ptr, get these items from the
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-
325 struct mbuf
*conndata
;
327 conndata
= m_copy(tpcb
->tp_ucddata
, 0, (int) M_COPYALL
);
329 if (argo_debug
[D_CONN
]) {
330 dump_mbuf(conndata
, "conndata after mcopy");
333 newtpcb
->tp_ucddata
= conndata
;
336 tpcb
->tp_state
= TP_LISTENING
;
337 tpcb
->tp_class
= class_to_use
;
338 tpcb
->tp_netservice
= netservice
;
341 ASSERT(fname
!= 0); /* just checking */
344 * tp_route_to takes its address argument in the form of an mbuf.
349 MGET(m
, M_DONTWAIT
, MT_SONAME
); /* mbuf type used is
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.
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
);
373 if (argo_debug
[D_CONN
]) {
374 printf("tp_route_to FAILED! detaching tpcb %p, so %p\n",
378 (void) tp_detach(tpcb
);
383 if (argo_debug
[D_TPINPUT
]) {
384 printf("tp_newsocket returning so %p, sototpcb(so) %p\n",
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
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.
413 tp_input(struct mbuf
*m
, ...)
415 struct sockaddr
*faddr
, *laddr
; /* NSAP addresses */
417 int (*dgout_routine
) (struct mbuf
*, ...);
425 u_short dref
, sref
, acktime
, subseq
;
426 u_char preferred_class
, class_to_use
, pdusize
;
427 u_char opt
, dusize
, addlopt
, myversion
= 0;
430 #endif /* TP_PERF_MEAS */
431 u_char fsufxlen
, lsufxlen
;
432 void *fsufxloc
, *lsufxloc
;
437 struct tp_conn_param tpp
;
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);
450 hdr
= mtod(m
, struct tpdu
*);
452 error
= errlen
= tpdu_len
= 0;
453 takes_data
= fcc_present
= false;
456 fsufxloc
= lsufxloc
= NULL
;
457 fsufxlen
= lsufxlen
=
458 preferred_class
= class_to_use
= pdusize
= addlopt
= 0;
459 dusize
= TP_DFL_TPDUSIZE
;
461 GET_CUR_TIME(&e
.e_time
);
463 #endif /* TP_PERF_MEAS */
466 if (argo_debug
[D_TPINPUT
]) {
467 printf("tp_input(%p, ... %p)\n", m
, cons_channel
);
473 * get the actual tpdu length - necessary for monitoring and for
476 * Also, maybe measure the mbuf chain lengths and sizes.
482 int chain_length
= 0;
483 #endif /* ARGO_DEBUG */
486 tpdu_len
+= n
->m_len
;
488 if (argo_debug
[D_MBUF_MEAS
]) {
489 if (n
->m_flags
& M_EXT
) {
490 IncStat(ts_mb_cluster
);
492 IncStat(ts_mb_small
);
497 if (n
->m_next
== NULL
) {
503 if (argo_debug
[D_MBUF_MEAS
]) {
504 if (chain_length
> 16)
505 chain_length
= 0; /* zero used for
507 tp_stat
.ts_mb_len_distr
[chain_length
]++;
512 if (tp_traceflags
[D_TPINPUT
]) {
513 tptraceTPCB(TPPTtpduin
, hdr
->tpdu_type
, hdr
, hdr
->tpdu_li
+ 1,
518 dref
= ntohs((short) hdr
->tpdu_dref
);
519 sref
= ntohs((short) hdr
->tpdu_sref
);
520 dutype
= (int) hdr
->tpdu_type
;
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
);
530 if (tp_traceflags
[D_TPINPUT
]) {
531 tptrace(TPPTmisc
, "channel dutype dref ",
532 cons_channel
, dutype
, dref
, 0);
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
);
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
) {
571 vb_getval(P
, u_char
, dusize
);
573 if (argo_debug
[D_TPINPUT
]) {
574 printf("CR dusize 0x%x\n", dusize
);
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
;
582 switch (vbptr(P
)->tpv_len
) {
584 pdusize
= vbval(P
, u_char
);
587 pdusize
= ntohs(vbval(P
, u_short
));
591 if (argo_debug
[D_TPINPUT
]) {
592 printf("malformed prefered TPDU option\n");
598 vb_getval(P
, u_char
, addlopt
);
600 case TPP_calling_sufx
:
602 * could use vb_getval, but we want to save the loc &
605 fsufxloc
= (void *) & vbptr(P
)->tpv_val
;
606 fsufxlen
= vbptr(P
)->tpv_len
;
608 if (argo_debug
[D_TPINPUT
]) {
612 for (j
= 0; j
< fsufxlen
; j
++) {
613 printf(" 0x%x. ", *((char *) fsufxloc
+ j
));
620 case TPP_called_sufx
:
622 * could use vb_getval, but we want to save the loc &
625 lsufxloc
= &vbptr(P
)->tpv_val
;
626 lsufxlen
= vbptr(P
)->tpv_len
;
628 if (argo_debug
[D_TPINPUT
]) {
632 for (j
= 0; j
< lsufxlen
; j
++) {
633 printf(" 0x%x. ", *((u_char
*)lsufxloc
+ j
));
643 vb_getval(P
, u_char
, perf_meas
);
645 #endif /* TP_PERF_MEAS */
648 /* not in class 0; 1 octet; in CR_TPDU only */
650 * COS tests says if version wrong, use default
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
));
657 myversion
= vbval(P
, u_char
);
660 vb_getval(P
, u_short
, acktime
);
661 acktime
= ntohs(acktime
);
662 acktime
= acktime
/ 500; /* convert to slowtimo
664 if ((short) acktime
<= 0)
665 acktime
= 2; /* don't allow a bad peer to
668 if (argo_debug
[D_TPINPUT
]) {
669 printf("CR acktime 0x%x\n", acktime
);
678 static u_char bad_alt_classes
[5] =
679 {~0, ~3, ~5, ~0xf, ~0x1f};
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
);
690 if (argo_debug
[D_TPINPUT
]) {
691 printf("alt_classes 0x%x\n", alt_classes
);
706 if (argo_debug
[D_TPINPUT
]) {
707 printf("param ignored CR_TPDU code= 0x%x\n",
711 IncStat(ts_param_ignored
);
716 if (argo_debug
[D_TPINPUT
]) {
717 printf("CR before cksum\n");
721 CHECK(iso_check_csum(m
, tpdu_len
),
722 E_TP_INV_PVAL
, ts_bad_csum
, discard
, 0)
724 if (argo_debug
[D_TPINPUT
]) {
725 printf("CR before cksum\n");
731 /* } */ END_WHILE_OPTIONS(P
)
733 /* can't look for a tpcb w/o any called sufx */
734 error
= E_TP_LENGTH_INVAL
;
735 IncStat(ts_inv_sufx
);
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
))))
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
768 if (argo_debug
[D_TPINPUT
]) {
769 printf("checking if dup CR\n");
773 for (t
= tpcb
->tp_next
; t
!= tpcb
; t
= t
->tp_next
) {
774 if (sref
!= t
->tp_fref
)
776 if ((*tpcb
->tp_nlproto
->nlp_cmpnetaddr
) (
777 t
->tp_npcb
, faddr
, TP_FOREIGN
)) {
779 if (argo_debug
[D_TPINPUT
]) {
780 printf("duplicate CR discarded\n");
787 if (tp_traceflags
[D_TPINPUT
]) {
788 tptrace(TPPTmisc
, "tp_input: tpcb *lsufxloc tpstate",
789 tpcb
, *lsufxloc
, tpcb
->tp_state
, 0);
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.
801 if (argo_debug
[D_TPINPUT
]) {
802 printf("HAVE A TPCB 1: %p\n", tpcb
);
806 if (argo_debug
[D_CONN
]) {
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
);
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
;
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
;
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 */
843 if (tp_traceflags
[D_CONN
]) {
845 "after 1 consist class_to_use class, out, tpconsout",
847 tpcb
->tp_class
, dgout_routine
, tpcons_output
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 */
858 if (argo_debug
[D_CONN
]) {
859 printf("CR: after CRCCCHECKS: tpcb %p, flags 0x%x\n",
860 tpcb
, tpcb
->tp_flags
);
864 e
.TPDU_ATTR(CR
).e_cdt
= hdr
->tpdu_CRcdt
;
865 e
.ev_number
= CR_TPDU
;
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.
875 if (argo_debug
[D_CONN
]) {
876 printf("abt to call tp_newsocket(%p, %p, %p, %p)\n",
877 so
, laddr
, faddr
, cons_channel
);
881 tp_newsocket(so
, faddr
, cons_channel
,
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
892 if (argo_debug
[D_CONN
]) {
893 printf("tp_newsocket returns 0\n");
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
);
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
)
950 tpcb
->tp_peer_acktime
= acktime
;
953 * The following kludge is used to test
954 * retransmissions and timeout during connection
958 if (argo_debug
[D_ZDREF
]) {
960 /* tpcb->tp_fref = 0; */
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.
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)
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
))
1011 if (argo_debug
[D_TPINPUT
]) {
1012 printf("HAVE A TPCB 2: %p\n", tpcb
);
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
))
1022 if (argo_debug
[D_TPINPUT
]) {
1023 printf("state of dref %d ok, tpcb %p\n", dref
, tpcb
);
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
);
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
))
1060 if (argo_debug
[D_TPINPUT
]) {
1061 printf("CC dusize 0x%x\n", dusize
);
1066 caseof(CC_TPDU_type
, TPP_ptpdu_size
):
1068 u_short opdusize
= pdusize
;
1069 switch (vbptr(P
)->tpv_len
) {
1071 pdusize
= vbval(P
, u_char
);
1074 pdusize
= ntohs(vbval(P
, u_short
));
1078 if (argo_debug
[D_TPINPUT
]) {
1079 printf("malformed prefered TPDU option\n");
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
))
1089 caseof(CC_TPDU_type
, TPP_calling_sufx
):
1091 if (argo_debug
[D_TPINPUT
]) {
1092 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen
);
1095 lsufxloc
= &vbptr(P
)->tpv_val
;
1096 lsufxlen
= vbptr(P
)->tpv_len
;
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
1104 if ((short) acktime
<= 0)
1107 caseof(CC_TPDU_type
, TPP_called_sufx
):
1108 fsufxloc
= (void *) & vbptr(P
)->tpv_val
;
1109 fsufxlen
= vbptr(P
)->tpv_len
;
1111 if (argo_debug
[D_TPINPUT
]) {
1112 printf("CC called (foreign) sufx len %d\n", fsufxlen
);
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)
1128 * this is different from the above because in the
1129 * context of concat/ sep tpdu_len might not be the
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)
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
1150 caseof(AK_TPDU_type
, TPP_subseq
):
1151 /* used after reduction of window */
1152 vb_getval(P
, u_short
, subseq
);
1153 subseq
= ntohs(subseq
);
1155 if (argo_debug
[D_ACKRECV
]) {
1156 printf("AK dref 0x%x Subseq 0x%x\n", dref
, subseq
);
1161 caseof(AK_TPDU_type
, TPP_flow_cntl_conf
):
1164 u_short ysubseq
, ycredit
;
1167 vb_getval(P
, u_int
, ylwe
);
1168 vb_getval(P
, u_short
, ysubseq
);
1169 vb_getval(P
, u_short
, ycredit
);
1171 ysubseq
= ntohs(ysubseq
);
1172 ycredit
= ntohs(ycredit
);
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
);
1184 if (argo_debug
[D_TPINPUT
]) {
1185 printf("param ignored dutype 0x%x, code 0x%x\n",
1186 dutype
, vbptr(P
)->tpv_code
);
1190 if (tp_traceflags
[D_TPINPUT
]) {
1191 tptrace(TPPTmisc
, "param ignored dutype code ",
1192 dutype
, vbptr(P
)->tpv_code
, 0, 0);
1195 IncStat(ts_param_ignored
);
1199 /* } */ END_WHILE_OPTIONS(P
)
1200 /* NOTE: the variable dutype has been shifted left! */
1202 switch (hdr
->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;
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
;
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 */
1233 if (tp_traceflags
[D_CONN
]) {
1235 "after 1 consist class, out, tpconsout",
1236 tpcb
->tp_class
, dgout_routine
, tpcons_output
, 0
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
);
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
,
1264 * if called or calling suffixes appeared on the CC,
1265 * they'd better jive with what's in the pcb
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
))
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
;
1282 e
.ev_number
= CC_TPDU
;
1283 IncStat(ts_CC_rcvd
);
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
);
1300 if (tp_traceflags
[D_TPINPUT
]) {
1301 tptrace(TPPTmisc
, "DR recvd", hdr
->tpdu_DRreason
, 0, 0, 0);
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
;
1315 e
.ev_number
= DR_TPDU
;
1316 IncStat(ts_DR_rcvd
);
1321 if (tp_traceflags
[D_TPINPUT
]) {
1322 tptrace(TPPTmisc
, "ER recvd", hdr
->tpdu_ERreason
, 0, 0, 0);
1325 e
.ev_number
= ER_TPDU
;
1326 e
.TPDU_ATTR(ER
).e_reason
= hdr
->tpdu_ERreason
;
1327 IncStat(ts_ER_rcvd
);
1332 e
.TPDU_ATTR(AK
).e_subseq
= subseq
;
1333 e
.TPDU_ATTR(AK
).e_fcc_present
= fcc_present
;
1335 if (tpcb
->tp_xtd_format
) {
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
);
1343 e
.TPDU_ATTR(AK
).e_cdt
= hdr
->tpdu_AKcdtX
;
1344 e
.TPDU_ATTR(AK
).e_seq
= hdr
->tpdu_AKseqX
;
1345 #endif /* BYTE_ORDER */
1347 e
.TPDU_ATTR(AK
).e_cdt
= hdr
->tpdu_AKcdt
;
1348 e
.TPDU_ATTR(AK
).e_seq
= hdr
->tpdu_AKseq
;
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
);
1358 e
.ev_number
= AK_TPDU
;
1359 IncStat(ts_AK_rcvd
);
1360 IncPStat(tpcb
, tps_AK_rcvd
);
1364 if (tpcb
->tp_xtd_format
) {
1366 union seq_type seqeotX
;
1368 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1369 e
.TPDU_ATTR(XAK
).e_seq
= seqeotX
.s_seq
;
1371 e
.TPDU_ATTR(XAK
).e_seq
= hdr
->tpdu_XAKseqX
;
1372 #endif /* BYTE_ORDER */
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
);
1382 if (tpcb
->tp_xtd_format
) {
1384 union seq_type seqeotX
;
1386 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1387 e
.TPDU_ATTR(XPD
).e_seq
= seqeotX
.s_seq
;
1389 e
.TPDU_ATTR(XPD
).e_seq
= hdr
->tpdu_XPDseqX
;
1390 #endif /* BYTE_ORDER */
1392 e
.TPDU_ATTR(XPD
).e_seq
= hdr
->tpdu_XPDseq
;
1395 e
.ev_number
= XPD_TPDU
;
1396 IncStat(ts_XPD_rcvd
);
1397 IncPStat(tpcb
, tps_XPD_rcvd
);
1402 * the y option will cause occasional packets
1403 * to be dropped. A little crude but it
1408 if (argo_debug
[D_DROP
]) {
1409 if (time_second
& 0x4 &&
1410 hdr
->tpdu_DTseq
& 0x1) {
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
) {
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
;
1427 e
.TPDU_ATTR(DT
).e_seq
= hdr
->tpdu_DTseqX
;
1428 e
.TPDU_ATTR(DT
).e_eot
= hdr
->tpdu_DTeotX
;
1429 #endif /* BYTE_ORDER */
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
);
1437 e
.ev_number
= DT_TPDU
;
1438 IncStat(ts_DT_rcvd
);
1439 IncPStat(tpcb
, tps_DT_rcvd
);
1443 tp_indicate(T_DISCONNECT
, tpcb
, ECONNABORTED
);
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 */
1452 if (argo_debug
[D_TPINPUT
]) {
1453 printf("INVALID dutype 0x%x\n", hdr
->tpdu_type
);
1456 IncStat(ts_inv_dutype
);
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
1467 m
->m_len
-= ((int) hdr
->tpdu_li
+ 1);
1468 m
->m_data
+= ((int) hdr
->tpdu_li
+ 1);
1471 int xmax
= tpdu_info
[hdr
->tpdu_type
][TP_MAX_DATA_INDEX
];
1472 int datalen
= tpdu_len
- hdr
->tpdu_li
- 1, mbtype
= MT_DATA
;
1474 struct tp_disc_reason dr
;
1475 struct cmsghdr x_hdr
;
1477 #define c_hdr x.x_hdr
1480 CHECK((xmax
&& datalen
> xmax
), E_TP_LENGTH_INVAL
,
1481 ts_inv_length
, respond
, (xmax
+ hdr
->tpdu_li
+ 1));
1482 switch (hdr
->tpdu_type
) {
1485 c_hdr
.cmsg_type
= TPOPT_CONN_DATA
;
1486 goto make_control_msg
;
1489 c_hdr
.cmsg_type
= TPOPT_CFRM_DATA
;
1490 goto make_control_msg
;
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
;
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
);
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
));
1514 memcpy(mtod(n
, void *), (void *) &c_hdr
,
1515 n
->m_len
= sizeof(c_hdr
));
1521 if (mbtype
!= MT_CONTROL
)
1522 mbtype
= MT_OOBDATA
;
1523 m
->m_flags
|= M_EOR
;
1527 for (n
= m
; n
; n
= n
->m_next
) {
1531 e
.TPDU_ATTR(DT
).e_datalen
= datalen
;
1532 e
.TPDU_ATTR(DT
).e_data
= m
;
1537 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m %p\n",
1538 hdr
->tpdu_type
, takes_data
, m
);
1542 * prevent m_freem() after tp_driver() from throwing it all
1547 IncStat(ts_tpdu_rcvd
);
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
);
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
) {
1575 m
= e
.TPDU_ATTR(CC
).e_data
; /* same field for all three
1578 if (argo_debug
[D_TPINPUT
]) {
1579 printf("after driver, restoring m to %p, takes_data 0x%x\n",
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) {
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
) {
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");
1610 IncStat(ts_concat_rcvd
);
1616 if (argo_debug
[D_TPINPUT
]) {
1617 printf("tp_input : m_freem(%p)\n", m
);
1622 if (argo_debug
[D_TPINPUT
]) {
1623 printf("tp_input : after m_freem %p\n", m
);
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
1636 if (argo_debug
[D_TPINPUT
]) {
1637 printf("tp_input DISCARD\n");
1641 if (tp_traceflags
[D_TPINPUT
]) {
1642 tptrace(TPPTmisc
, "tp_input DISCARD m", m
, 0, 0, 0);
1646 IncStat(ts_recv_drop
);
1654 /* error = E_TP_MISM_REFS; */
1657 error
|= TP_ERROR_SNDC
;
1661 if (argo_debug
[D_TPINPUT
]) {
1662 printf("RESPOND: error 0x%x, errlen 0x%x\n", error
, errlen
);
1666 if (tp_traceflags
[D_TPINPUT
]) {
1667 tptrace(TPPTmisc
, "tp_input RESPOND m error sref", m
, error
, sref
, 0);
1672 (void) tp_error_emit(error
, (u_long
) sref
, satosiso(faddr
),
1673 satosiso(laddr
), m
, errlen
, tpcb
,
1674 cons_channel
, dgout_routine
);
1676 if (argo_debug
[D_ERROR_EMIT
]) {
1677 printf("tp_input after error_emit\n");
1682 printf("", sref
, opt
);
1684 IncStat(ts_recv_drop
);
1689 * NAME: tp_headersize()
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
1704 * NOTES: It would be nice if it got the network header size as well.
1707 tp_headersize(int dutype
, struct tp_pcb
*tpcb
)
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);
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
];
1733 size
= tpdu_info
[dutype
][tpcb
->tp_xtd_format
];
1736 /* caller must get network level header size separately */