]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_input.c
ceeecf5f1f8a59c7519da97587dc1f8eadb2789d
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)tp_input.c 8.1 (Berkeley) 6/10/93
57 /***********************************************************
58 Copyright IBM Corporation 1987
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of IBM not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
70 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
78 ******************************************************************/
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
86 * tp_input() gets an mbuf chain from ip. Actually, not directly
87 * from ip, because ip calls a net-level routine that strips off
88 * the net header and then calls tp_input(), passing the proper type
89 * of addresses for the address family in use (how it figures out
90 * which AF is not yet determined.)
92 * Decomposing the tpdu is some of the most laughable code. The variable-length
93 * parameters and the problem of non-aligned memory references
94 * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
95 * to loop through the header and decompose it.
97 * The routine tp_newsocket() is called when a CR comes in for a listening
98 * socket. tp_input calls sonewconn() and tp_newsocket() to set up the
99 * "child" socket. Most tpcb values are copied from the parent tpcb into
102 * Also in here is tp_headersize() (grot) which tells the expected size
103 * of a tp header, to be used by other layers. It's in here because it
104 * uses the static structure tpdu_info.
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/mbuf.h>
110 #include <sys/socket.h>
111 #include <sys/socketvar.h>
112 #include <sys/domain.h>
113 #include <sys/protosw.h>
114 #include <sys/errno.h>
115 #include <sys/time.h>
116 #include <sys/kernel.h>
118 #include <netiso/iso.h>
119 #include <netiso/iso_errno.h>
120 #include <netiso/iso_pcb.h>
121 #include <netiso/tp_param.h>
122 #include <netiso/tp_timer.h>
123 #include <netiso/tp_stat.h>
124 #include <netiso/tp_pcb.h>
125 #include <netiso/argo_debug.h>
126 #include <netiso/tp_trace.h>
127 #include <netiso/tp_tpdu.h>
134 #include <netccitt/x25.h>
135 #include <netccitt/pk.h>
136 #include <netccitt/pk_var.h>
138 int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
143 #define ATTR(X)ev_number
149 register struct mbuf
*m
;
154 printf("tp_inputprep: m 0x%x\n", m
) ;
157 while( m
->m_len
< 1 ) {
158 /* The "m_free" logic
159 * if( (m = m_free(m)) == MNULL )
160 * return (struct mbuf *)0;
161 * would cause a system crash if ever executed.
162 * This logic will be executed if the first mbuf
163 * in the chain only contains a CLNP header. The m_free routine
164 * will release the mbuf containing the CLNP header from the
165 * chain and the new head of the chain will not have the
166 * M_PKTHDR bit set. This routine, tp_inputprep, will
167 * eventually call the "sbappendaddr" routine. "sbappendaddr"
168 * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap
169 * way of keeping the head of the chain from being freed.
171 if((m
= m_pullup(m
, 1)) == MNULL
)
174 if(((int)m
->m_data
) & 0x3) {
175 /* If we are not 4-byte aligned, we have to be
176 * above the beginning of the mbuf, and it is ok just
179 caddr_t ocp
= m
->m_data
;
181 m
->m_data
= (caddr_t
)(((int)m
->m_data
) & ~0x3);
182 bcopy(ocp
, m
->m_data
, (unsigned)m
->m_len
);
184 CHANGE_MTYPE(m
, TPMT_DATA
);
186 /* we KNOW that there is at least 1 byte in this mbuf
187 and that it is hdr->tpdu_li XXXXXXX! */
189 hdrlen
= 1 + *mtod( m
, u_char
*);
192 * now pull up the whole tp header
194 if ( m
->m_len
< hdrlen
) {
195 if ((m
= m_pullup(m
, hdrlen
)) == MNULL
) {
196 IncStat(ts_recv_drop
);
197 return (struct mbuf
*)0;
202 " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m
,
209 * -- this array and the following macros allow you to step through the
210 * parameters of the variable part of a header
211 * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
212 * should change, this array has to be rearranged
215 #define TP_LEN_CLASS_0_INDEX 2
216 #define TP_MAX_DATA_INDEX 3
218 static u_char tpdu_info
[][4] =
220 /* length max data len */
221 /* reg fmt xtd fmt class 0 */
222 /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0,
223 /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA
,
224 /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0,
225 /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0,
226 /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0,
227 /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0,
228 /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0,
229 /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0,
230 /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA
,
231 /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0,
232 /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0,
233 /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0,
234 /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0,
235 /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA
,
236 /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA
,
237 /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0,
240 #define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
241 if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\
245 * WHENEVER YOU USE THE FOLLOWING MACRO,
246 * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
249 #define WHILE_OPTIONS(P, hdr, format)\
250 { register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
251 caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
252 for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
253 CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
254 respond, P - (caddr_t)hdr);\
255 if (P == PLIM) break;
257 #define END_WHILE_OPTIONS(P) } }
262 * NAME: tp_newsocket()
265 * tp_input() on incoming CR, when a socket w/ the called suffix
266 * is awaiting a connection request
268 * FUNCTION and ARGUMENTS:
269 * Create a new socket structure, attach to it a new transport pcb,
270 * using a copy of the net level pcb for the parent socket.
271 * (so) is the parent socket.
272 * (fname) is the foreign address (all that's used is the nsap portion)
275 * a new socket structure, being this end of the newly formed connection.
278 * Sets a few things in the tpcb and net level pcb
282 static struct socket
*
283 tp_newsocket(so
, fname
, cons_channel
, class_to_use
, netservice
)
285 struct sockaddr
*fname
;
286 caddr_t cons_channel
;
290 register struct tp_pcb
*tpcb
= sototpcb(so
); /* old tpcb, needed below */
291 register struct tp_pcb
*newtpcb
;
294 * sonewconn() gets a new socket structure,
295 * a new lower layer pcb and a new tpcb,
296 * but the pcbs are unnamed (not bound)
299 tptraceTPCB(TPPTmisc
, "newsock: listg_so, _tpcb, so_head",
300 so
, tpcb
, so
->so_head
, 0);
303 if ((so
= sonewconn(so
, SS_ISCONFIRMING
)) == (struct socket
*)0)
306 tptraceTPCB(TPPTmisc
, "newsock: after newconn so, so_head",
307 so
, so
->so_head
, 0, 0);
311 printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n",
315 struct socket
*t
, *head
;
319 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
320 t
, t
->so_head
, t
->so_q0
, t
->so_q0len
);
321 while( (t
=t
->so_q0
) && t
!= so
&& t
!= head
)
322 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
323 t
, t
->so_head
, t
->so_q0
, t
->so_q0len
);
328 * before we clobber the old tpcb ptr, get these items from the parent pcb
330 newtpcb
= sototpcb(so
);
331 newtpcb
->_tp_param
= tpcb
->_tp_param
;
332 newtpcb
->tp_flags
= tpcb
->tp_flags
;
333 newtpcb
->tp_lcredit
= tpcb
->tp_lcredit
;
334 newtpcb
->tp_l_tpdusize
= tpcb
->tp_l_tpdusize
;
335 newtpcb
->tp_lsuffixlen
= tpcb
->tp_lsuffixlen
;
336 bcopy( tpcb
->tp_lsuffix
, newtpcb
->tp_lsuffix
, newtpcb
->tp_lsuffixlen
);
338 if( /* old */ tpcb
->tp_ucddata
) {
340 * These data are the connect- , confirm- or disconnect- data.
342 struct mbuf
*conndata
;
344 conndata
= m_copy(tpcb
->tp_ucddata
, 0, (int)M_COPYALL
);
346 dump_mbuf(conndata
, "conndata after mcopy");
348 newtpcb
->tp_ucddata
= conndata
;
352 tpcb
->tp_state
= TP_LISTENING
;
353 tpcb
->tp_class
= class_to_use
;
354 tpcb
->tp_netservice
= netservice
;
357 ASSERT( fname
!= 0 ) ; /* just checking */
360 * tp_route_to takes its address argument in the form of an mbuf.
365 MGET(m
, M_DONTWAIT
, MT_SONAME
); /* mbuf type used is confusing */
368 * this seems a bit grotesque, but tp_route_to expects
369 * an mbuf * instead of simply a sockaddr; it calls the ll
370 * pcb_connect, which expects the name/addr in an mbuf as well.
373 bcopy((caddr_t
)fname
, mtod(m
, caddr_t
), fname
->sa_len
);
374 m
->m_len
= fname
->sa_len
;
376 /* grot : have to say the kernel can override params in
377 * the passive open case
379 tpcb
->tp_dont_change_params
= 0;
380 err
= tp_route_to( m
, tpcb
, cons_channel
);
387 printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
390 (void) tp_detach(tpcb
);
395 printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
412 * net layer input routine
414 * FUNCTION and ARGUMENTS:
415 * Process an incoming TPDU (m), finding the associated tpcb if there
416 * is one. Create the appropriate type of event and call the driver.
417 * (faddr) and (laddr) are the foreign and local addresses.
419 * When tp_input() is called we KNOW that the ENTIRE TP HEADER
420 * has been m_pullup-ed.
425 * When using COSNS it may affect the state of the net-level pcb
428 * The initial value of acktime is 2 so that we will never
429 * have a 0 value for tp_peer_acktime. It gets used in the
430 * computation of the retransmission timer value, and so it
432 * 2 seems like a reasonable minimum.
435 tp_input(m
, faddr
, laddr
, cons_channel
, dgout_routine
, ce_bit
)
436 register struct mbuf
*m
;
437 struct sockaddr
*faddr
, *laddr
; /* NSAP addresses */
438 caddr_t cons_channel
;
439 int (*dgout_routine
)();
443 register struct tp_pcb
*tpcb
;
444 register struct tpdu
*hdr
;
449 u_short dref
, sref
, acktime
, subseq
;
450 u_char preferred_class
, class_to_use
, pdusize
;
451 u_char opt
, dusize
, addlopt
, version
;
454 #endif /* TP_PERF_MEAS */
455 u_char fsufxlen
, lsufxlen
;
456 caddr_t fsufxloc
, lsufxloc
;
461 struct tp_conn_param tpp
;
465 hdr
= mtod(m
, struct tpdu
*);
467 error
= errlen
= tpdu_len
= 0;
468 takes_data
= fcc_present
= FALSE
;
469 acktime
= 2; sref
= subseq
= 0;
470 fsufxloc
= lsufxloc
= NULL
;
471 fsufxlen
= lsufxlen
=
472 preferred_class
= class_to_use
= pdusize
= addlopt
= 0;
473 dusize
= TP_DFL_TPDUSIZE
;
475 GET_CUR_TIME( &e
.e_time
); perf_meas
= 0;
476 #endif /* TP_PERF_MEAS */
479 printf("tp_input(0x%x, ... 0x%x)\n", m
, cons_channel
);
484 * get the actual tpdu length - necessary for monitoring
485 * and for checksumming
487 * Also, maybe measure the mbuf chain lengths and sizes.
490 { register struct mbuf
*n
=m
;
492 int chain_length
= 0;
496 tpdu_len
+= n
->m_len
;
498 if( n
->m_flags
& M_EXT
) {
499 IncStat(ts_mb_cluster
);
501 IncStat(ts_mb_small
);
505 if (n
->m_next
== MNULL
) {
511 if(chain_length
> 16)
512 chain_length
= 0; /* zero used for anything > 16 */
513 tp_stat
.ts_mb_len_distr
[chain_length
] ++;
517 tptraceTPCB(TPPTtpduin
, hdr
->tpdu_type
, hdr
, hdr
->tpdu_li
+1, tpdu_len
,
521 dref
= ntohs((short)hdr
->tpdu_dref
);
522 sref
= ntohs((short)hdr
->tpdu_sref
);
523 dutype
= (int)hdr
->tpdu_type
;
526 printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype
,
528 printf("input: dref 0x%x sref 0x%x\n", dref
, sref
);
531 tptrace(TPPTmisc
, "channel dutype dref ",
532 cons_channel
, dutype
, dref
, 0);
537 if( (dutype
< TP_MIN_TPDUTYPE
) || (dutype
> TP_MAX_TPDUTYPE
)) {
538 printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
539 dutype
, cons_channel
, dref
);
540 dump_buf (m
, sizeof( struct mbuf
));
542 IncStat(ts_inv_dutype
);
545 #endif /* ARGO_DEBUG */
547 CHECK( (dutype
< TP_MIN_TPDUTYPE
|| dutype
> TP_MAX_TPDUTYPE
),
548 E_TP_INV_TPDU
, ts_inv_dutype
, respond
,
550 /* unfortunately we can't take the address of the tpdu_type field,
551 * since it's a bit field - so we just use the constant offset 2
554 /* Now this isn't very neat but since you locate a pcb one way
555 * at the beginning of connection establishment, and by
556 * the dref for each tpdu after that, we have to treat CRs differently
558 if ( dutype
== CR_TPDU_type
) {
559 u_char alt_classes
= 0;
561 preferred_class
= 1 << hdr
->tpdu_CRclass
;
562 opt
= hdr
->tpdu_CRoptions
;
564 WHILE_OPTIONS(P
, hdr
, 1 ) /* { */
566 switch( vbptr(P
)->tpv_code
) {
569 vb_getval(P
, u_char
, dusize
);
571 printf("CR dusize 0x%x\n", dusize
);
573 /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
574 if (dusize
< TP_MIN_TPDUSIZE
|| dusize
> TP_MAX_TPDUSIZE
)
575 dusize
= TP_DFL_TPDUSIZE
;
578 switch (vbptr(P
)->tpv_len
) {
579 case 1: pdusize
= vbval(P
, u_char
); break;
580 case 2: pdusize
= ntohs(vbval(P
, u_short
)); break;
583 printf("malformed prefered TPDU option\n");
588 vb_getval(P
, u_char
, addlopt
);
590 case TPP_calling_sufx
:
591 /* could use vb_getval, but we want to save the loc & len
594 fsufxloc
= (caddr_t
) &vbptr(P
)->tpv_val
;
595 fsufxlen
= vbptr(P
)->tpv_len
;
599 for(j
=0; j
<fsufxlen
; j
++ ) {
600 printf(" 0x%x. ", *((caddr_t
)(fsufxloc
+j
)) );
606 case TPP_called_sufx
:
607 /* could use vb_getval, but we want to save the loc & len
610 lsufxloc
= (caddr_t
) &vbptr(P
)->tpv_val
;
611 lsufxlen
= vbptr(P
)->tpv_len
;
615 for(j
=0; j
<lsufxlen
; j
++ ) {
616 printf(" 0x%x. ", *((u_char
*)(lsufxloc
+j
)) );
625 vb_getval(P
, u_char
, perf_meas
);
627 #endif /* TP_PERF_MEAS */
630 /* not in class 0; 1 octet; in CR_TPDU only */
631 /* COS tests says if version wrong, use default version!?XXX */
632 CHECK( (vbval(P
, u_char
) != TP_VERSION
),
633 E_TP_INV_PVAL
, ts_inv_pval
, setversion
,
634 (1 + (caddr_t
)&vbptr(P
)->tpv_val
- (caddr_t
)hdr
) );
636 version
= vbval(P
, u_char
);
639 vb_getval(P
, u_short
, acktime
);
640 acktime
= ntohs(acktime
);
641 acktime
= acktime
/500; /* convert to slowtimo ticks */
642 if((short)acktime
<=0 )
643 acktime
= 2; /* don't allow a bad peer to foul us up */
645 printf("CR acktime 0x%x\n", acktime
);
653 static u_char bad_alt_classes
[5] =
654 { ~0, ~3, ~5, ~0xf, ~0x1f};
657 (u_char
*) &(((struct tp_vbp
*)P
)->tpv_val
);
658 for (i
= ((struct tp_vbp
*)P
)->tpv_len
; i
>0; i
--) {
659 alt_classes
|= (1<<((*aclass
++)>>4));
661 CHECK( (bad_alt_classes
[hdr
->tpdu_CRclass
] & alt_classes
),
662 E_TP_INV_PVAL
, ts_inv_aclass
, respond
,
663 ((caddr_t
)aclass
) - (caddr_t
)hdr
);
665 printf("alt_classes 0x%x\n", alt_classes
);
679 printf("param ignored CR_TPDU code= 0x%x\n",
682 IncStat(ts_param_ignored
);
687 printf("CR before cksum\n");
690 CHECK( iso_check_csum(m
, tpdu_len
),
691 E_TP_INV_PVAL
, ts_bad_csum
, discard
, 0)
694 printf("CR before cksum\n");
699 /* } */ END_WHILE_OPTIONS(P
)
702 /* can't look for a tpcb w/o any called sufx */
703 error
= E_TP_LENGTH_INVAL
;
704 IncStat(ts_inv_sufx
);
707 register struct tp_pcb
*t
;
709 * The intention here is to trap all CR requests
710 * to a given nsap, for constructing transport
711 * service bridges at user level; so these
712 * intercepts should precede the normal listens.
713 * Phrasing the logic in this way also allows for
714 * mop-up listeners, which we don't currently implement.
715 * We also wish to have a single socket be able to
716 * listen over any network service provider,
717 * (cons or clns or ip).
719 for (t
= tp_listeners
; t
; t
= t
->tp_nextlisten
)
720 if ((t
->tp_lsuffixlen
== 0 ||
721 (lsufxlen
== t
->tp_lsuffixlen
&&
722 bcmp(lsufxloc
, t
->tp_lsuffix
, lsufxlen
) == 0)) &&
723 ((t
->tp_flags
& TPF_GENERAL_ADDR
) ||
724 (laddr
->sa_family
== t
->tp_domain
&&
725 (*t
->tp_nlproto
->nlp_cmpnetaddr
)
726 (t
->tp_npcb
, laddr
, TP_LOCAL
))))
729 CHECK(t
== 0, E_TP_NO_SESSION
, ts_inv_sufx
, respond
,
730 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
731 /* _tpduf is the fixed part; add 2 to get the dref bits of
732 * the fixed part (can't take the address of a bit field)
735 printf("checking if dup CR\n");
738 for (t
= tpcb
->tp_next
; t
!= tpcb
; t
= t
->tp_next
) {
739 if (sref
!= t
->tp_fref
)
741 if ((*tpcb
->tp_nlproto
->nlp_cmpnetaddr
)(
742 t
->tp_npcb
, faddr
, TP_FOREIGN
)) {
744 printf("duplicate CR discarded\n");
750 tptrace(TPPTmisc
, "tp_input: tpcb *lsufxloc tpstate",
751 tpcb
, *lsufxloc
, tpcb
->tp_state
, 0);
757 * already know that the classes in the CR match at least
758 * one class implemented, but we don't know yet if they
759 * include any classes permitted by this server.
763 printf("HAVE A TPCB 1: 0x%x\n", tpcb
);
767 "CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
768 tpcb
->tp_flags
, class_to_use
, alt_classes
, opt
, tpcb
->tp_class
);
770 /* tpcb->tp_class doesn't include any classes not implemented */
771 class_to_use
= (preferred_class
& tpcb
->tp_class
);
772 if( (class_to_use
= preferred_class
& tpcb
->tp_class
) == 0 )
773 class_to_use
= alt_classes
& tpcb
->tp_class
;
775 class_to_use
= 1 << tp_mask_to_num(class_to_use
);
778 tpp
= tpcb
->_tp_param
;
779 tpp
.p_class
= class_to_use
;
780 tpp
.p_tpdusize
= dusize
;
781 tpp
.p_ptpdusize
= pdusize
;
782 tpp
.p_xtd_format
= (opt
& TPO_XTD_FMT
) == TPO_XTD_FMT
;
783 tpp
.p_xpd_service
= (addlopt
& TPAO_USE_TXPD
) == TPAO_USE_TXPD
;
784 tpp
.p_use_checksum
= (tpp
.p_class
== TP_CLASS_0
)?0:
785 (addlopt
& TPAO_NO_CSUM
) == 0;
786 tpp
.p_version
= version
;
788 tpp
.p_use_efc
= (opt
& TPO_USE_EFC
) == TPO_USE_EFC
;
789 tpp
.p_use_nxpd
= (addlopt
& TPAO_USE_NXPD
) == TPAO_USE_NXPD
;
790 tpp
.p_use_rcc
= (addlopt
& TPAO_USE_RCC
) == TPAO_USE_RCC
;
794 tp_consistency(tpcb
, 0 /* not force or strict */, &tpp
) != 0,
795 E_TP_NEGOT_FAILED
, ts_negotfailed
, clear_parent_tcb
,
796 (1 + 2 + (caddr_t
)&hdr
->_tpdufr
.CRCC
- (caddr_t
)hdr
)
797 /* ^ more or less the location of class */
802 "after 1 consist class_to_use class, out, tpconsout",
804 tpcb
->tp_class
, dgout_routine
, tpcons_output
808 ((class_to_use
== TP_CLASS_0
)&&(dgout_routine
!= tpcons_output
)),
809 E_TP_NEGOT_FAILED
, ts_negotfailed
, clear_parent_tcb
,
810 (1 + 2 + (caddr_t
)&hdr
->_tpdufr
.CRCC
- (caddr_t
)hdr
)
811 /* ^ more or less the location of class */
814 printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
815 tpcb
, tpcb
->tp_flags
);
818 e
.ATTR(CR_TPDU
).e_cdt
= hdr
->tpdu_CRcdt
;
819 e
.ev_number
= CR_TPDU
;
822 if (so
->so_options
& SO_ACCEPTCONN
) {
823 struct tp_pcb
*parent_tpcb
= tpcb
;
825 * Create a socket, tpcb, ll pcb, etc.
826 * for this newborn connection, and fill in all the values.
829 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
830 so
, laddr
, faddr
, cons_channel
);
833 tp_newsocket(so
, faddr
, cons_channel
,
835 ((tpcb
->tp_netservice
== IN_CLNS
) ? IN_CLNS
:
836 (dgout_routine
== tpcons_output
)?ISO_CONS
:ISO_CLNS
))
837 ) == (struct socket
*)0 ) {
838 /* note - even if netservice is IN_CLNS, as far as
839 * the tp entity is concerned, the only differences
843 printf("tp_newsocket returns 0\n");
851 insque(tpcb
, parent_tpcb
);
854 * Stash the addresses in the net level pcb
855 * kind of like a pcbconnect() but don't need
856 * or want all those checks.
858 (tpcb
->tp_nlproto
->nlp_putnetaddr
)(tpcb
->tp_npcb
, faddr
, TP_FOREIGN
);
859 (tpcb
->tp_nlproto
->nlp_putnetaddr
)(tpcb
->tp_npcb
, laddr
, TP_LOCAL
);
861 /* stash the f suffix in the new tpcb */
862 if (tpcb
->tp_fsuffixlen
= fsufxlen
) {
863 bcopy(fsufxloc
, tpcb
->tp_fsuffix
, fsufxlen
);
864 (tpcb
->tp_nlproto
->nlp_putsufx
)
865 (tpcb
->tp_npcb
, fsufxloc
, fsufxlen
, TP_FOREIGN
);
867 /* stash the l suffix in the new tpcb */
868 tpcb
->tp_lsuffixlen
= lsufxlen
;
869 bcopy(lsufxloc
, tpcb
->tp_lsuffix
, lsufxlen
);
870 (tpcb
->tp_nlproto
->nlp_putsufx
)
871 (tpcb
->tp_npcb
, lsufxloc
, lsufxlen
, TP_LOCAL
);
873 if( tpcb
->tp_perf_on
= perf_meas
) { /* assignment */
874 /* ok, let's create an mbuf for stashing the
875 * statistics if one doesn't already exist
877 (void) tp_setup_perf(tpcb
);
879 #endif /* TP_PERF_MEAS */
880 tpcb
->tp_fref
= sref
;
882 /* We've already checked for consistency with the options
883 * set in tpp, but we couldn't set them earlier because
884 * we didn't want to change options in the LISTENING tpcb.
885 * Now we set the options in the new socket's tpcb.
887 (void) tp_consistency( tpcb
, TP_FORCE
, &tpp
);
889 if(!tpcb
->tp_use_checksum
)
890 IncStat(ts_csum_off
);
891 if(tpcb
->tp_xpd_service
)
892 IncStat(ts_use_txpd
);
893 if(tpcb
->tp_xtd_format
)
896 tpcb
->tp_peer_acktime
= acktime
;
899 * The following kludge is used to test retransmissions and
900 * timeout during connection establishment.
904 /*tpcb->tp_fref = 0;*/
909 if (!tpcb
->tp_cebit_off
) {
910 tpcb
->tp_win_recv
= tp_start_win
<< 8;
911 tpcb
->tp_cong_sample
.cs_size
= 0;
912 CONG_INIT_SAMPLE(tpcb
);
913 CONG_UPDATE_SAMPLE(tpcb
, ce_bit
);
915 } else if ( dutype
== ER_TPDU_type
) {
917 * ER TPDUs have to be recognized separately
918 * because they don't necessarily have a tpcb
919 * with them and we don't want err out looking for such
921 * We could put a bunch of little kludges in the
922 * next section of code so it would avoid references to tpcb
923 * if dutype == ER_TPDU_type but we don't want code for ERs to
924 * mess up code for data transfer.
927 e
.ev_number
= ER_TPDU
;
928 e
.ATTR(ER_TPDU
).e_reason
= (u_char
)hdr
->tpdu_ERreason
;
929 CHECK (((int)dref
<= 0 || dref
>= tp_refinfo
.tpr_size
||
930 (tpcb
= tp_ref
[dref
].tpr_pcb
) == (struct tp_pcb
*) 0 ||
931 tpcb
->tp_refstate
== REF_FREE
||
932 tpcb
->tp_refstate
== REF_FROZEN
),
933 E_TP_MISM_REFS
, ts_inv_dref
, discard
, 0)
936 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
938 /* In the next 4 checks,
939 * _tpduf is the fixed part; add 2 to get the dref bits of
940 * the fixed part (can't take the address of a bit field)
943 if (cons_channel
&& dutype
== DT_TPDU_type
) {
944 struct isopcb
*isop
= ((struct isopcb
*)
945 ((struct pklcd
*)cons_channel
)->lcd_upnext
);
946 if (isop
&& isop
->isop_refcnt
== 1 && isop
->isop_socket
&&
947 (tpcb
= sototpcb(isop
->isop_socket
)) &&
948 (tpcb
->tp_class
== TP_CLASS_0
/* || == CLASS_1 */)) {
950 printf("tpinput_dt: class 0 short circuit\n");
952 dref
= tpcb
->tp_lref
;
953 sref
= tpcb
->tp_fref
;
954 CHECK( (tpcb
->tp_refstate
== REF_FREE
),
955 E_TP_MISM_REFS
,ts_inv_dref
, nonx_dref
,
956 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
964 CHECK( ((int)dref
<= 0 || dref
>= tp_refinfo
.tpr_size
) ,
965 E_TP_MISM_REFS
,ts_inv_dref
, nonx_dref
,
966 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
967 CHECK( ((tpcb
= tp_ref
[dref
].tpr_pcb
) == (struct tp_pcb
*) 0 ),
968 E_TP_MISM_REFS
,ts_inv_dref
, nonx_dref
,
969 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
970 CHECK( (tpcb
->tp_refstate
== REF_FREE
),
971 E_TP_MISM_REFS
,ts_inv_dref
, nonx_dref
,
972 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
976 printf("HAVE A TPCB 2: 0x%x\n", tpcb
);
979 /* causes a DR to be sent for CC; ER for all else */
980 CHECK( (tpcb
->tp_refstate
== REF_FROZEN
),
981 (dutype
== CC_TPDU_type
?E_TP_NO_SESSION
:E_TP_MISM_REFS
),
982 ts_inv_dref
, respond
,
983 (1 + 2 + (caddr_t
)&hdr
->_tpduf
- (caddr_t
)hdr
))
986 printf("state of dref %d ok, tpcb 0x%x\n", dref
,tpcb
);
989 * At this point the state of the dref could be
990 * FROZEN: tpr_pcb == NULL, has ( reference only) timers
991 * for example, DC may arrive after the close() has detached
992 * the tpcb (e.g., if user turned off SO_LISTEN option)
993 * OPENING : a tpcb exists but no timers yet
994 * OPEN : tpcb exists & timers are outstanding
997 if (!tpcb
->tp_cebit_off
)
998 CONG_UPDATE_SAMPLE(tpcb
, ce_bit
);
1000 dusize
= tpcb
->tp_tpdusize
;
1001 pdusize
= tpcb
->tp_ptpdusize
;
1003 dutype
= hdr
->tpdu_type
<< 8; /* for the switch below */
1005 WHILE_OPTIONS(P
, hdr
, tpcb
->tp_xtd_format
) /* { */
1007 #define caseof(x,y) case (((x)<<8)+(y))
1008 switch( dutype
| vbptr(P
)->tpv_code
) {
1010 caseof( CC_TPDU_type
, TPP_addl_opt
):
1011 /* not in class 0; 1 octet */
1012 vb_getval(P
, u_char
, addlopt
);
1014 caseof( CC_TPDU_type
, TPP_tpdu_size
):
1016 u_char odusize
= dusize
;
1017 vb_getval(P
, u_char
, dusize
);
1018 CHECK( (dusize
< TP_MIN_TPDUSIZE
||
1019 dusize
> TP_MAX_TPDUSIZE
|| dusize
> odusize
),
1020 E_TP_INV_PVAL
, ts_inv_pval
, respond
,
1021 (1 + (caddr_t
)&vbptr(P
)->tpv_val
- (caddr_t
)hdr
) )
1023 printf("CC dusize 0x%x\n", dusize
);
1027 caseof( CC_TPDU_type
, TPP_ptpdu_size
):
1029 u_short opdusize
= pdusize
;
1030 switch (vbptr(P
)->tpv_len
) {
1031 case 1: pdusize
= vbval(P
, u_char
); break;
1032 case 2: pdusize
= ntohs(vbval(P
, u_short
)); break;
1035 printf("malformed prefered TPDU option\n");
1038 CHECK( (pdusize
== 0 ||
1039 (opdusize
&& (pdusize
> opdusize
))),
1040 E_TP_INV_PVAL
, ts_inv_pval
, respond
,
1041 (1 + (caddr_t
)&vbptr(P
)->tpv_val
- (caddr_t
)hdr
) )
1044 caseof( CC_TPDU_type
, TPP_calling_sufx
):
1046 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen
);
1048 lsufxloc
= (caddr_t
) &vbptr(P
)->tpv_val
;
1049 lsufxlen
= vbptr(P
)->tpv_len
;
1051 caseof( CC_TPDU_type
, TPP_acktime
):
1052 /* class 4 only, 2 octets */
1053 vb_getval(P
, u_short
, acktime
);
1054 acktime
= ntohs(acktime
);
1055 acktime
= acktime
/500; /* convert to slowtimo ticks */
1056 if( (short)acktime
<=0 )
1059 caseof( CC_TPDU_type
, TPP_called_sufx
):
1060 fsufxloc
= (caddr_t
) &vbptr(P
)->tpv_val
;
1061 fsufxlen
= vbptr(P
)->tpv_len
;
1063 printf("CC called (foreign) sufx len %d\n", fsufxlen
);
1067 caseof( CC_TPDU_type
, TPP_checksum
):
1068 caseof( DR_TPDU_type
, TPP_checksum
):
1069 caseof( DT_TPDU_type
, TPP_checksum
):
1070 caseof( XPD_TPDU_type
, TPP_checksum
):
1071 if( tpcb
->tp_use_checksum
) {
1072 CHECK( iso_check_csum(m
, tpdu_len
),
1073 E_TP_INV_PVAL
, ts_bad_csum
, discard
, 0)
1077 /* this is different from the above because in the context
1078 * of concat/ sep tpdu_len might not be the same as hdr len
1080 caseof( AK_TPDU_type
, TPP_checksum
):
1081 caseof( XAK_TPDU_type
, TPP_checksum
):
1082 caseof( DC_TPDU_type
, TPP_checksum
):
1083 if( tpcb
->tp_use_checksum
) {
1084 CHECK( iso_check_csum(m
, (int)hdr
->tpdu_li
+ 1),
1085 E_TP_INV_PVAL
, ts_bad_csum
, discard
, 0)
1089 caseof( DR_TPDU_type
, TPP_addl_info
):
1090 /* ignore - its length and meaning are
1091 * user defined and there's no way
1092 * to pass this info to the user anyway
1097 caseof( AK_TPDU_type
, TPP_subseq
):
1098 /* used after reduction of window */
1099 vb_getval(P
, u_short
, subseq
);
1100 subseq
= ntohs(subseq
);
1102 printf("AK dref 0x%x Subseq 0x%x\n", dref
, subseq
);
1106 caseof( AK_TPDU_type
, TPP_flow_cntl_conf
):
1109 u_short ysubseq
, ycredit
;
1112 vb_getval(P
, u_int
, ylwe
);
1113 vb_getval(P
, u_short
, ysubseq
);
1114 vb_getval(P
, u_short
, ycredit
);
1116 ysubseq
= ntohs(ysubseq
);
1117 ycredit
= ntohs(ycredit
);
1119 printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n",
1120 "AK FCC lwe 0x", ylwe
, ysubseq
, ycredit
, dref
);
1127 printf("param ignored dutype 0x%x, code 0x%x\n",
1128 dutype
, vbptr(P
)->tpv_code
);
1131 tptrace(TPPTmisc
, "param ignored dutype code ",
1132 dutype
, vbptr(P
)->tpv_code
,0,0);
1134 IncStat(ts_param_ignored
);
1138 /* } */ END_WHILE_OPTIONS(P
)
1140 /* NOTE: the variable dutype has been shifted left! */
1142 switch( hdr
->tpdu_type
) {
1144 /* If CC comes back with an unacceptable class
1145 * respond with a DR or ER
1148 opt
= hdr
->tpdu_CCoptions
; /* 1 byte */
1151 tpp
= tpcb
->_tp_param
;
1152 tpp
.p_class
= (1<<hdr
->tpdu_CCclass
);
1153 tpp
.p_tpdusize
= dusize
;
1154 tpp
.p_ptpdusize
= pdusize
;
1155 tpp
.p_dont_change_params
= 0;
1156 tpp
.p_xtd_format
= (opt
& TPO_XTD_FMT
) == TPO_XTD_FMT
;
1157 tpp
.p_xpd_service
= (addlopt
& TPAO_USE_TXPD
) == TPAO_USE_TXPD
;
1158 tpp
.p_use_checksum
= (addlopt
& TPAO_NO_CSUM
) == 0;
1160 tpp
.p_use_efc
= (opt
& TPO_USE_EFC
) == TPO_USE_EFC
;
1161 tpp
.p_use_nxpd
= (addlopt
& TPAO_USE_NXPD
) == TPAO_USE_NXPD
;
1162 tpp
.p_use_rcc
= (addlopt
& TPAO_USE_RCC
) == TPAO_USE_RCC
;
1166 tp_consistency(tpcb
, TP_FORCE
, &tpp
) != 0,
1167 E_TP_NEGOT_FAILED
, ts_negotfailed
, respond
,
1168 (1 + 2 + (caddr_t
)&hdr
->_tpdufr
.CRCC
- (caddr_t
)hdr
)
1169 /* ^ more or less the location of class */
1173 "after 1 consist class, out, tpconsout",
1174 tpcb
->tp_class
, dgout_routine
, tpcons_output
, 0
1178 ((class_to_use
== TP_CLASS_0
)&&
1179 (dgout_routine
!= tpcons_output
)),
1180 E_TP_NEGOT_FAILED
, ts_negotfailed
, respond
,
1181 (1 + 2 + (caddr_t
)&hdr
->_tpdufr
.CRCC
- (caddr_t
)hdr
)
1182 /* ^ more or less the location of class */
1185 if (tpcb
->tp_netservice
== ISO_CONS
&&
1186 class_to_use
== TP_CLASS_0
) {
1187 struct isopcb
*isop
= (struct isopcb
*)tpcb
->tp_npcb
;
1188 struct pklcd
*lcp
= (struct pklcd
*)isop
->isop_chan
;
1189 lcp
->lcd_flags
&= ~X25_DG_CIRCUIT
;
1193 if( ! tpcb
->tp_use_checksum
)
1194 IncStat(ts_csum_off
);
1195 if(tpcb
->tp_xpd_service
)
1196 IncStat(ts_use_txpd
);
1197 if(tpcb
->tp_xtd_format
)
1198 IncStat(ts_xtd_fmt
);
1201 tptrace(TPPTmisc
, "after CC class flags dusize CCclass",
1202 tpcb
->tp_class
, tpcb
->tp_flags
, tpcb
->tp_tpdusize
,
1206 /* if called or calling suffices appeared on the CC,
1207 * they'd better jive with what's in the pcb
1210 CHECK( ((tpcb
->tp_fsuffixlen
!= fsufxlen
) ||
1211 bcmp(fsufxloc
, tpcb
->tp_fsuffix
, fsufxlen
)),
1212 E_TP_INV_PVAL
,ts_inv_sufx
, respond
,
1213 (1+fsufxloc
- (caddr_t
)hdr
))
1216 CHECK( ((tpcb
->tp_lsuffixlen
!= lsufxlen
) ||
1217 bcmp(lsufxloc
, tpcb
->tp_lsuffix
, lsufxlen
)),
1218 E_TP_INV_PVAL
,ts_inv_sufx
, respond
,
1219 (1+lsufxloc
- (caddr_t
)hdr
))
1222 e
.ATTR(CC_TPDU
).e_sref
= sref
;
1223 e
.ATTR(CC_TPDU
).e_cdt
= hdr
->tpdu_CCcdt
;
1225 e
.ev_number
= CC_TPDU
;
1226 IncStat(ts_CC_rcvd
);
1230 if (sref
!= tpcb
->tp_fref
)
1231 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1232 sref
, tpcb
->tp_fref
);
1234 CHECK( (sref
!= tpcb
->tp_fref
),
1235 E_TP_MISM_REFS
, ts_inv_sufx
, discard
,
1236 (1 + (caddr_t
)&hdr
->tpdu_DCsref
- (caddr_t
)hdr
))
1238 e
.ev_number
= DC_TPDU
;
1239 IncStat(ts_DC_rcvd
);
1244 tptrace(TPPTmisc
, "DR recvd", hdr
->tpdu_DRreason
, 0, 0, 0);
1246 if (sref
!= tpcb
->tp_fref
) {
1247 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1248 sref
, tpcb
->tp_fref
);
1251 CHECK( (sref
!= 0 && sref
!= tpcb
->tp_fref
&&
1252 tpcb
->tp_state
!= TP_CRSENT
),
1253 (TP_ERROR_SNDC
| E_TP_MISM_REFS
),ts_inv_sufx
, respond
,
1254 (1 + (caddr_t
)&hdr
->tpdu_DRsref
- (caddr_t
)hdr
))
1256 e
.ATTR(DR_TPDU
).e_reason
= hdr
->tpdu_DRreason
;
1257 e
.ATTR(DR_TPDU
).e_sref
= (u_short
)sref
;
1259 e
.ev_number
= DR_TPDU
;
1260 IncStat(ts_DR_rcvd
);
1265 tptrace(TPPTmisc
, "ER recvd", hdr
->tpdu_ERreason
,0,0,0);
1267 e
.ev_number
= ER_TPDU
;
1268 e
.ATTR(ER_TPDU
).e_reason
= hdr
->tpdu_ERreason
;
1269 IncStat(ts_ER_rcvd
);
1274 e
.ATTR(AK_TPDU
).e_subseq
= subseq
;
1275 e
.ATTR(AK_TPDU
).e_fcc_present
= fcc_present
;
1277 if (tpcb
->tp_xtd_format
) {
1279 union seq_type seqeotX
;
1281 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1282 e
.ATTR(AK_TPDU
).e_seq
= seqeotX
.s_seq
;
1283 e
.ATTR(AK_TPDU
).e_cdt
= ntohs(hdr
->tpdu_AKcdtX
);
1285 e
.ATTR(AK_TPDU
).e_cdt
= hdr
->tpdu_AKcdtX
;
1286 e
.ATTR(AK_TPDU
).e_seq
= hdr
->tpdu_AKseqX
;
1287 #endif /* BYTE_ORDER */
1289 e
.ATTR(AK_TPDU
).e_cdt
= hdr
->tpdu_AKcdt
;
1290 e
.ATTR(AK_TPDU
).e_seq
= hdr
->tpdu_AKseq
;
1293 tptrace(TPPTmisc
, "AK recvd seq cdt subseq fcc_pres",
1294 e
.ATTR(AK_TPDU
).e_seq
, e
.ATTR(AK_TPDU
).e_cdt
,
1295 subseq
, fcc_present
);
1298 e
.ev_number
= AK_TPDU
;
1299 IncStat(ts_AK_rcvd
);
1300 IncPStat(tpcb
, tps_AK_rcvd
);
1304 if (tpcb
->tp_xtd_format
) {
1306 union seq_type seqeotX
;
1308 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1309 e
.ATTR(XAK_TPDU
).e_seq
= seqeotX
.s_seq
;
1311 e
.ATTR(XAK_TPDU
).e_seq
= hdr
->tpdu_XAKseqX
;
1312 #endif /* BYTE_ORDER */
1314 e
.ATTR(XAK_TPDU
).e_seq
= hdr
->tpdu_XAKseq
;
1316 e
.ev_number
= XAK_TPDU
;
1317 IncStat(ts_XAK_rcvd
);
1318 IncPStat(tpcb
, tps_XAK_rcvd
);
1322 if (tpcb
->tp_xtd_format
) {
1324 union seq_type seqeotX
;
1326 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1327 e
.ATTR(XPD_TPDU
).e_seq
= seqeotX
.s_seq
;
1329 e
.ATTR(XPD_TPDU
).e_seq
= hdr
->tpdu_XPDseqX
;
1330 #endif /* BYTE_ORDER */
1332 e
.ATTR(XPD_TPDU
).e_seq
= hdr
->tpdu_XPDseq
;
1335 e
.ev_number
= XPD_TPDU
;
1336 IncStat(ts_XPD_rcvd
);
1337 IncPStat(tpcb
, tps_XPD_rcvd
);
1341 { /* the y option will cause occasional packets to be dropped.
1342 * A little crude but it works.
1346 if(time
.tv_usec
& 0x4 && hdr
->tpdu_DTseq
& 0x1) {
1352 if (tpcb
->tp_class
== TP_CLASS_0
) {
1354 e
.ATTR(DT_TPDU
).e_seq
= 0; /* actually don't care */
1355 e
.ATTR(DT_TPDU
).e_eot
= (((struct tp0du
*)hdr
)->tp0du_eot
);
1356 } else if (tpcb
->tp_xtd_format
) {
1358 union seq_type seqeotX
;
1360 seqeotX
.s_seqeot
= ntohl(hdr
->tpdu_seqeotX
);
1361 e
.ATTR(DT_TPDU
).e_seq
= seqeotX
.s_seq
;
1362 e
.ATTR(DT_TPDU
).e_eot
= seqeotX
.s_eot
;
1364 e
.ATTR(DT_TPDU
).e_seq
= hdr
->tpdu_DTseqX
;
1365 e
.ATTR(DT_TPDU
).e_eot
= hdr
->tpdu_DTeotX
;
1366 #endif /* BYTE_ORDER */
1368 e
.ATTR(DT_TPDU
).e_seq
= hdr
->tpdu_DTseq
;
1369 e
.ATTR(DT_TPDU
).e_eot
= hdr
->tpdu_DTeot
;
1371 if(e
.ATTR(DT_TPDU
).e_eot
)
1372 IncStat(ts_eot_input
);
1374 e
.ev_number
= DT_TPDU
;
1375 IncStat(ts_DT_rcvd
);
1376 IncPStat(tpcb
, tps_DT_rcvd
);
1380 tp_indicate(T_DISCONNECT
, tpcb
, ECONNABORTED
);
1383 /* this should NEVER happen because there is a
1384 * check for dutype well above here
1386 error
= E_TP_INV_TPDU
; /* causes an ER */
1388 printf("INVALID dutype 0x%x\n", hdr
->tpdu_type
);
1390 IncStat(ts_inv_dutype
);
1394 /* peel off the tp header;
1395 * remember that the du_li doesn't count itself.
1396 * This may leave us w/ an empty mbuf at the front of a chain.
1397 * We can't just throw away the empty mbuf because hdr still points
1398 * into the mbuf's data area and we're still using hdr (the tpdu header)
1400 m
->m_len
-= ((int)hdr
->tpdu_li
+ 1);
1401 m
->m_data
+= ((int)hdr
->tpdu_li
+ 1);
1404 int max
= tpdu_info
[ hdr
->tpdu_type
] [TP_MAX_DATA_INDEX
];
1405 int datalen
= tpdu_len
- hdr
->tpdu_li
- 1, mbtype
= MT_DATA
;
1407 struct tp_disc_reason dr
;
1408 struct cmsghdr x_hdr
;
1410 #define c_hdr x.x_hdr
1411 register struct mbuf
*n
;
1413 CHECK( (max
&& datalen
> max
), E_TP_LENGTH_INVAL
,
1414 ts_inv_length
, respond
, (max
+ hdr
->tpdu_li
+ 1) );
1415 switch( hdr
->tpdu_type
) {
1418 c_hdr
.cmsg_type
= TPOPT_CONN_DATA
;
1419 goto make_control_msg
;
1422 c_hdr
.cmsg_type
= TPOPT_CFRM_DATA
;
1423 goto make_control_msg
;
1426 x
.dr
.dr_hdr
.cmsg_len
= sizeof(x
) - sizeof(c_hdr
);
1427 x
.dr
.dr_hdr
.cmsg_type
= TPOPT_DISC_REASON
;
1428 x
.dr
.dr_hdr
.cmsg_level
= SOL_TRANSPORT
;
1429 x
.dr
.dr_reason
= hdr
->tpdu_DRreason
;
1430 c_hdr
.cmsg_type
= TPOPT_DISC_DATA
;
1432 datalen
+= sizeof(c_hdr
);
1433 c_hdr
.cmsg_len
= datalen
;
1434 c_hdr
.cmsg_level
= SOL_TRANSPORT
;
1435 mbtype
= MT_CONTROL
;
1436 MGET(n
, M_DONTWAIT
, MT_DATA
);
1438 {m_freem(m
); m
= 0; datalen
= 0; goto invoke
; }
1439 if (hdr
->tpdu_type
== DR_TPDU_type
) {
1440 datalen
+= sizeof(x
) - sizeof(c_hdr
);
1441 bcopy((caddr_t
)&x
, mtod(n
, caddr_t
), n
->m_len
= sizeof(x
));
1443 bcopy((caddr_t
)&c_hdr
, mtod(n
, caddr_t
),
1444 n
->m_len
= sizeof(c_hdr
));
1450 if (mbtype
!= MT_CONTROL
)
1451 mbtype
= MT_OOBDATA
;
1452 m
->m_flags
|= M_EOR
;
1456 for (n
= m
; n
; n
= n
->m_next
) {
1460 e
.ATTR(DT_TPDU
).e_datalen
= datalen
;
1461 e
.ATTR(DT_TPDU
).e_data
= m
;
1466 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1467 hdr
->tpdu_type
, takes_data
, m
);
1470 /* prevent m_freem() after tp_driver() from throwing it all away */
1474 IncStat(ts_tpdu_rcvd
);
1477 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1478 tpcb
->tp_state
, e
.ev_number
, m
);
1479 printf(" e.e_data 0x%x\n", e
.ATTR(DT_TPDU
).e_data
);
1480 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1481 takes_data
, (m
==MNULL
)?0:m
->m_len
, tpdu_len
);
1484 error
= tp_driver(tpcb
, &e
);
1486 ASSERT(tpcb
!= (struct tp_pcb
*)0);
1487 ASSERT(tpcb
->tp_sock
!= (struct socket
*)0);
1488 if( tpcb
->tp_sock
->so_error
== 0 )
1489 tpcb
->tp_sock
->so_error
= error
;
1491 /* Kludge to keep the state tables under control (adding
1492 * data on connect & disconnect & freeing the mbuf containing
1493 * the data would have exploded the tables and made a big mess ).
1495 switch(e
.ev_number
) {
1499 m
= e
.ATTR(CC_TPDU
).e_data
; /* same field for all three dutypes */
1501 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1508 /* Concatenated sequences are terminated by any tpdu that
1509 * carries data: CR, CC, DT, XPD, DR.
1510 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1514 if ( takes_data
== 0 ) {
1515 ASSERT( m
!= MNULL
);
1517 * we already peeled off the prev. tp header so
1518 * we can just pull up some more and repeat
1521 if( m
= tp_inputprep(m
) ) {
1523 hdr
= mtod(m
, struct tpdu
*);
1524 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1525 hdr
, (int) hdr
->tpdu_li
+ 1, m
);
1526 dump_mbuf(m
, "tp_input after driver, at separate");
1529 IncStat(ts_concat_rcvd
);
1535 printf("tp_input : m_freem(0x%x)\n", m
);
1539 printf("tp_input : after m_freem 0x%x\n", m
);
1542 return (ProtoHook
) tpcb
;
1545 /* class 4: drop the tpdu */
1546 /* class 2,0: Should drop the net connection, if you can figure out
1547 * to which connection it applies
1550 printf("tp_input DISCARD\n");
1553 tptrace(TPPTmisc
, "tp_input DISCARD m", m
,0,0,0);
1556 IncStat(ts_recv_drop
);
1557 return (ProtoHook
)0;
1564 /* error = E_TP_MISM_REFS; */
1567 error
|= TP_ERROR_SNDC
;
1571 printf("RESPOND: error 0x%x, errlen 0x%x\n", error
, errlen
);
1574 tptrace(TPPTmisc
, "tp_input RESPOND m error sref", m
, error
, sref
, 0);
1578 (void) tp_error_emit(error
, (u_long
)sref
, (struct sockaddr_iso
*)faddr
,
1579 (struct sockaddr_iso
*)laddr
, m
, errlen
, tpcb
,
1580 cons_channel
, dgout_routine
);
1581 IFDEBUG(D_ERROR_EMIT
)
1582 printf("tp_input after error_emit\n");
1586 printf("",sref
,opt
);
1588 IncStat(ts_recv_drop
);
1589 return (ProtoHook
)0;
1594 * NAME: tp_headersize()
1597 * tp_emit() and tp_sbsend()
1598 * TP needs to know the header size so it can figure out how
1599 * much data to put in each tpdu.
1601 * FUNCTION, ARGUMENTS, and RETURN VALUE:
1602 * For a given connection, represented by (tpcb), and
1603 * tpdu type (dutype), return the size of a tp header.
1605 * RETURNS: the expected size of the heade in bytesr
1609 * NOTES: It would be nice if it got the network header size as well.
1612 tp_headersize(dutype
, tpcb
)
1614 struct tp_pcb
*tpcb
;
1616 register int size
= 0;
1619 tptrace(TPPTmisc
, "tp_headersize dutype class xtd_format",
1620 dutype
, tpcb
->tp_class
, tpcb
->tp_xtd_format
, 0);
1622 if( !( (tpcb
->tp_class
== TP_CLASS_0
) ||
1623 (tpcb
->tp_class
== TP_CLASS_4
) ||
1624 (dutype
== DR_TPDU_type
) ||
1625 (dutype
== CR_TPDU_type
) )) {
1626 printf("tp_headersize:dutype 0x%x, class 0x%x",
1627 dutype
, tpcb
->tp_class
);
1628 /* TODO: identify this and GET RID OF IT */
1630 ASSERT( (tpcb
->tp_class
== TP_CLASS_0
) ||
1631 (tpcb
->tp_class
== TP_CLASS_4
) ||
1632 (dutype
== DR_TPDU_type
) ||
1633 (dutype
== CR_TPDU_type
) );
1635 if( tpcb
->tp_class
== TP_CLASS_0
) {
1636 size
= tpdu_info
[ dutype
] [TP_LEN_CLASS_0_INDEX
];
1638 size
= tpdu_info
[ dutype
] [tpcb
->tp_xtd_format
];
1641 /* caller must get network level header size separately */