trailing comment after #else or #endif
[unix-history] / usr / src / sys / netiso / tp_input.c
CommitLineData
7bcd1bb8
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 *
4d8170e5 7 * @(#)tp_input.c 7.32 (Berkeley) %G%
7bcd1bb8
KB
8 */
9
b7fb0758
KS
10/***********************************************************
11 Copyright IBM Corporation 1987
12
13 All Rights Reserved
14
15Permission to use, copy, modify, and distribute this software and its
16documentation for any purpose and without fee is hereby granted,
17provided that the above copyright notice appear in all copies and that
18both that copyright notice and this permission notice appear in
19supporting documentation, and that the name of IBM not be
20used in advertising or publicity pertaining to distribution of the
21software without specific, written prior permission.
22
23IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29SOFTWARE.
30
31******************************************************************/
32
33/*
34 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35 */
36/*
37 * ARGO TP
38 *
39 * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $
40 * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $
41 *
42 * tp_input() gets an mbuf chain from ip. Actually, not directly
43 * from ip, because ip calls a net-level routine that strips off
44 * the net header and then calls tp_input(), passing the proper type
45 * of addresses for the address family in use (how it figures out
01acbfa1 46 * which AF is not yet determined.)
b7fb0758
KS
47 *
48 * Decomposing the tpdu is some of the most laughable code. The variable-length
49 * parameters and the problem of non-aligned memory references
50 * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below)
51 * to loop through the header and decompose it.
52 *
53 * The routine tp_newsocket() is called when a CR comes in for a listening
54 * socket. tp_input calls sonewconn() and tp_newsocket() to set up the
55 * "child" socket. Most tpcb values are copied from the parent tpcb into
56 * the child.
57 *
58 * Also in here is tp_headersize() (grot) which tells the expected size
59 * of a tp header, to be used by other layers. It's in here because it
60 * uses the static structure tpdu_info.
61 */
62
5548a02f
KB
63#include <sys/param.h>
64#include <sys/systm.h>
65#include <sys/mbuf.h>
66#include <sys/socket.h>
67#include <sys/socketvar.h>
68#include <sys/domain.h>
69#include <sys/protosw.h>
70#include <sys/errno.h>
71#include <sys/time.h>
72#include <sys/kernel.h>
194a383a 73
5548a02f
KB
74#include <netiso/iso.h>
75#include <netiso/iso_errno.h>
76#include <netiso/iso_pcb.h>
77#include <netiso/tp_param.h>
78#include <netiso/tp_timer.h>
79#include <netiso/tp_stat.h>
80#include <netiso/tp_pcb.h>
81#include <netiso/argo_debug.h>
82#include <netiso/tp_trace.h>
83#include <netiso/tp_tpdu.h>
84
85#include <net/if.h>
194a383a
KS
86#ifdef TRUE
87#undef FALSE
88#undef TRUE
89#endif
5548a02f
KB
90#include <netccitt/x25.h>
91#include <netccitt/pk.h>
92#include <netccitt/pk_var.h>
b7fb0758
KS
93
94int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit();
95
a50e2bc0
KS
96/*
97 #ifdef lint
98 #undef ATTR
99 #define ATTR(X)ev_number
100 #endif lint
101*/
b7fb0758
KS
102
103struct mbuf *
104tp_inputprep(m)
a50e2bc0 105 register struct mbuf *m;
b7fb0758 106{
a50e2bc0 107 int hdrlen;
b7fb0758
KS
108
109 IFDEBUG(D_TPINPUT)
a50e2bc0 110 printf("tp_inputprep: m 0x%x\n", m) ;
b7fb0758
KS
111 ENDDEBUG
112
113 while( m->m_len < 1 ) {
de9e4e14
KS
114 /* The "m_free" logic
115 * if( (m = m_free(m)) == MNULL )
116 * return (struct mbuf *)0;
117 * would cause a system crash if ever executed.
118 * This logic will be executed if the first mbuf
119 * in the chain only contains a CLNP header. The m_free routine
120 * will release the mbuf containing the CLNP header from the
121 * chain and the new head of the chain will not have the
122 * M_PKTHDR bit set. This routine, tp_inputprep, will
123 * eventually call the "sbappendaddr" routine. "sbappendaddr"
124 * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap
125 * way of keeping the head of the chain from being freed.
126 */
70338c83 127 if((m = m_pullup(m, 1)) == MNULL)
de9e4e14 128 return (MNULL);
b7fb0758 129 }
a50e2bc0
KS
130 if(((int)m->m_data) & 0x3) {
131 /* If we are not 4-byte aligned, we have to be
132 * above the beginning of the mbuf, and it is ok just
133 * to slide it back.
134 */
135 caddr_t ocp = m->m_data;
b7fb0758 136
a50e2bc0 137 m->m_data = (caddr_t)(((int)m->m_data) & ~0x3);
a7d903c5 138 bcopy(ocp, m->m_data, (unsigned)m->m_len);
b7fb0758
KS
139 }
140 CHANGE_MTYPE(m, TPMT_DATA);
141
a50e2bc0
KS
142 /* we KNOW that there is at least 1 byte in this mbuf
143 and that it is hdr->tpdu_li XXXXXXX! */
b7fb0758 144
a50e2bc0 145 hdrlen = 1 + *mtod( m, u_char *);
b7fb0758
KS
146
147 /*
148 * now pull up the whole tp header
149 */
a50e2bc0
KS
150 if ( m->m_len < hdrlen) {
151 if ((m = m_pullup(m, hdrlen)) == MNULL ) {
b7fb0758
KS
152 IncStat(ts_recv_drop);
153 return (struct mbuf *)0;
154 }
155 }
156 IFDEBUG(D_INPUT)
157 printf(
158 " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m,
a50e2bc0 159 hdrlen, m->m_len);
b7fb0758
KS
160 ENDDEBUG
161 return m;
162}
163
164/* begin groan
165 * -- this array and the following macros allow you to step through the
166 * parameters of the variable part of a header
167 * note that if for any reason the values of the **_TPDU macros (in tp_events.h)
168 * should change, this array has to be rearranged
169 */
170
171#define TP_LEN_CLASS_0_INDEX 2
172#define TP_MAX_DATA_INDEX 3
173
174static u_char tpdu_info[][4] =
175{
176/* length max data len */
177/* reg fmt xtd fmt class 0 */
178 /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0,
179 /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA,
180 /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0,
181 /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0,
182 /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0,
183 /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0,
184 /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0,
185 /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0,
186 /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA,
187 /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0,
188 /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0,
189 /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0,
190 /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0,
191 /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA,
192 /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA,
193 /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0,
194};
195
facaece3 196#define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
de9e4e14 197 if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\
facaece3
KS
198 goto Whattodo; }
199
b7fb0758
KS
200/*
201 * WHENEVER YOU USE THE FOLLOWING MACRO,
202 * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
203 */
204
facaece3
KS
205#define WHILE_OPTIONS(P, hdr, format)\
206{ register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\
207 caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\
208 for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\
209 CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\
210 respond, P - (caddr_t)hdr);\
211 if (P == PLIM) break;
b7fb0758 212
facaece3 213#define END_WHILE_OPTIONS(P) } }
b7fb0758
KS
214
215/* end groan */
216
217/*
218 * NAME: tp_newsocket()
219 *
220 * CALLED FROM:
221 * tp_input() on incoming CR, when a socket w/ the called suffix
222 * is awaiting a connection request
223 *
224 * FUNCTION and ARGUMENTS:
225 * Create a new socket structure, attach to it a new transport pcb,
226 * using a copy of the net level pcb for the parent socket.
227 * (so) is the parent socket.
228 * (fname) is the foreign address (all that's used is the nsap portion)
229 *
230 * RETURN VALUE:
231 * a new socket structure, being this end of the newly formed connection.
232 *
233 * SIDE EFFECTS:
234 * Sets a few things in the tpcb and net level pcb
235 *
236 * NOTES:
237 */
238static struct socket *
239tp_newsocket(so, fname, cons_channel, class_to_use, netservice)
240 struct socket *so;
241 struct sockaddr *fname;
01acbfa1 242 caddr_t cons_channel;
b7fb0758
KS
243 u_char class_to_use;
244 u_int netservice;
245{
246 register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */
194a383a 247 register struct tp_pcb *newtpcb;
b7fb0758
KS
248
249 /*
250 * sonewconn() gets a new socket structure,
251 * a new lower layer pcb and a new tpcb,
252 * but the pcbs are unnamed (not bound)
253 */
254 IFTRACE(D_NEWSOCK)
44f52ea5 255 tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
7b25382f 256 so, tpcb, so->so_head, 0);
b7fb0758
KS
257 ENDTRACE
258
bb2bb663 259 if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0)
b7fb0758
KS
260 return so;
261 IFTRACE(D_NEWSOCK)
44f52ea5
KS
262 tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
263 so, so->so_head, 0, 0);
b7fb0758
KS
264 ENDTRACE
265
b7fb0758 266 IFDEBUG(D_NEWSOCK)
a50e2bc0
KS
267 printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n",
268 cons_channel, so);
269 dump_addr(fname);
b7fb0758
KS
270 {
271 struct socket *t, *head ;
272
273 head = so->so_head;
274 t = so;
275 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
276 t, t->so_head, t->so_q0, t->so_q0len);
277 while( (t=t->so_q0) && t!= so && t!= head)
278 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
279 t, t->so_head, t->so_q0, t->so_q0len);
280 }
281 ENDDEBUG
282
283 /*
284 * before we clobber the old tpcb ptr, get these items from the parent pcb
285 */
286 newtpcb = sototpcb(so);
287 newtpcb->_tp_param = tpcb->_tp_param;
288 newtpcb->tp_flags = tpcb->tp_flags;
289 newtpcb->tp_lcredit = tpcb->tp_lcredit;
290 newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
291 newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
292 bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
b7fb0758 293
a50e2bc0 294 if( /* old */ tpcb->tp_ucddata) {
b7fb0758 295 /*
a50e2bc0 296 * These data are the connect- , confirm- or disconnect- data.
b7fb0758
KS
297 */
298 struct mbuf *conndata;
299
a50e2bc0 300 conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
b7fb0758
KS
301 IFDEBUG(D_CONN)
302 dump_mbuf(conndata, "conndata after mcopy");
b7fb0758 303 ENDDEBUG
a50e2bc0 304 newtpcb->tp_ucddata = conndata;
b7fb0758
KS
305 }
306
307 tpcb = newtpcb;
308 tpcb->tp_state = TP_LISTENING;
309 tpcb->tp_class = class_to_use;
310 tpcb->tp_netservice = netservice;
311
312
313 ASSERT( fname != 0 ) ; /* just checking */
314 if ( fname ) {
315 /*
316 * tp_route_to takes its address argument in the form of an mbuf.
317 */
318 struct mbuf *m;
319 int err;
320
321 MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */
322 if (m) {
323 /*
324 * this seems a bit grotesque, but tp_route_to expects
325 * an mbuf * instead of simply a sockaddr; it calls the ll
326 * pcb_connect, which expects the name/addr in an mbuf as well.
327 * sigh.
328 */
a50e2bc0
KS
329 bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
330 m->m_len = fname->sa_len;
b7fb0758
KS
331
332 /* grot : have to say the kernel can override params in
333 * the passive open case
334 */
335 tpcb->tp_dont_change_params = 0;
336 err = tp_route_to( m, tpcb, cons_channel);
337 m_free(m);
338
339 if (!err)
340 goto ok;
341 }
342 IFDEBUG(D_CONN)
343 printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
344 tpcb, so);
345 ENDDEBUG
346 (void) tp_detach(tpcb);
347 return 0;
348 }
349ok:
350 IFDEBUG(D_TPINPUT)
351 printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
352 so, sototpcb(so));
353 ENDDEBUG
354 return so;
355}
356
194a383a 357#ifndef TPCONS
b7fb0758
KS
358tpcons_output()
359{
360 return(0);
361}
4d8170e5 362#endif /* !CONS */
b7fb0758
KS
363
364/*
365 * NAME: tp_input()
366 *
367 * CALLED FROM:
368 * net layer input routine
369 *
370 * FUNCTION and ARGUMENTS:
371 * Process an incoming TPDU (m), finding the associated tpcb if there
372 * is one. Create the appropriate type of event and call the driver.
373 * (faddr) and (laddr) are the foreign and local addresses.
374 *
375 * When tp_input() is called we KNOW that the ENTIRE TP HEADER
376 * has been m_pullup-ed.
377 *
378 * RETURN VALUE: Nada
379 *
380 * SIDE EFFECTS:
381 * When using COSNS it may affect the state of the net-level pcb
382 *
383 * NOTE:
384 * The initial value of acktime is 2 so that we will never
385 * have a 0 value for tp_peer_acktime. It gets used in the
386 * computation of the retransmission timer value, and so it
387 * mustn't be zero.
388 * 2 seems like a reasonable minimum.
389 */
390ProtoHook
20650f15 391tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit)
b7fb0758
KS
392 register struct mbuf *m;
393 struct sockaddr *faddr, *laddr; /* NSAP addresses */
01acbfa1 394 caddr_t cons_channel;
b7fb0758 395 int (*dgout_routine)();
20650f15 396 int ce_bit;
b7fb0758
KS
397
398{
de9e4e14 399 register struct tp_pcb *tpcb;
d9a01c3e 400 register struct tpdu *hdr;
b7fb0758
KS
401 struct socket *so;
402 struct tp_event e;
de9e4e14 403 int error;
b7fb0758 404 unsigned dutype;
de9e4e14
KS
405 u_short dref, sref, acktime, subseq;
406 u_char preferred_class, class_to_use, pdusize;
407 u_char opt, dusize, addlopt, version;
b7fb0758 408#ifdef TP_PERF_MEAS
44f52ea5 409 u_char perf_meas;
4d8170e5 410#endif /* TP_PERF_MEAS */
de9e4e14
KS
411 u_char fsufxlen, lsufxlen;
412 caddr_t fsufxloc, lsufxloc;
413 int tpdu_len;
414 u_int takes_data;
415 u_int fcc_present;
416 int errlen;
b7fb0758
KS
417 struct tp_conn_param tpp;
418 int tpcons_output();
419
44f52ea5 420again:
d9a01c3e 421 hdr = mtod(m, struct tpdu *);
de9e4e14 422 tpcb = 0;
70338c83 423 error = errlen = tpdu_len = 0;
de9e4e14
KS
424 takes_data = fcc_present = FALSE;
425 acktime = 2; sref = subseq = 0;
70338c83 426 fsufxloc = lsufxloc = NULL;
de9e4e14
KS
427 fsufxlen = lsufxlen =
428 preferred_class = class_to_use = pdusize = addlopt = 0;
429 dusize = TP_DFL_TPDUSIZE;
b7fb0758 430#ifdef TP_PERF_MEAS
44f52ea5 431 GET_CUR_TIME( &e.e_time ); perf_meas = 0;
4d8170e5 432#endif /* TP_PERF_MEAS */
b7fb0758
KS
433
434 IFDEBUG(D_TPINPUT)
435 printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel);
436 ENDDEBUG
437
b7fb0758 438
b7fb0758
KS
439 /*
440 * get the actual tpdu length - necessary for monitoring
441 * and for checksumming
442 *
443 * Also, maybe measure the mbuf chain lengths and sizes.
444 */
445
446 { register struct mbuf *n=m;
447# ifdef ARGO_DEBUG
448 int chain_length = 0;
449# endif ARGO_DEBUG
450
451 for(;;) {
452 tpdu_len += n->m_len;
453 IFDEBUG(D_MBUF_MEAS)
a50e2bc0 454 if( n->m_flags & M_EXT) {
b7fb0758
KS
455 IncStat(ts_mb_cluster);
456 } else {
457 IncStat(ts_mb_small);
458 }
459 chain_length ++;
460 ENDDEBUG
461 if (n->m_next == MNULL ) {
462 break;
463 }
464 n = n->m_next;
465 }
466 IFDEBUG(D_MBUF_MEAS)
467 if(chain_length > 16)
468 chain_length = 0; /* zero used for anything > 16 */
469 tp_stat.ts_mb_len_distr[chain_length] ++;
470 ENDDEBUG
471 }
472 IFTRACE(D_TPINPUT)
473 tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
474 0);
475 ENDTRACE
476
477 dref = ntohs((short)hdr->tpdu_dref);
478 sref = ntohs((short)hdr->tpdu_sref);
479 dutype = (int)hdr->tpdu_type;
480
481 IFDEBUG(D_TPINPUT)
482 printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
483 cons_channel, dref);
484 printf("input: dref 0x%x sref 0x%x\n", dref, sref);
485 ENDDEBUG
486 IFTRACE(D_TPINPUT)
487 tptrace(TPPTmisc, "channel dutype dref ",
488 cons_channel, dutype, dref, 0);
489 ENDTRACE
490
491
492#ifdef ARGO_DEBUG
493 if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
494 printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
495 dutype, cons_channel, dref);
496 dump_buf (m, sizeof( struct mbuf ));
497
498 IncStat(ts_inv_dutype);
499 goto discard;
500 }
4d8170e5 501#endif /* ARGO_DEBUG */
b7fb0758
KS
502
503 CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
504 E_TP_INV_TPDU, ts_inv_dutype, respond,
505 2 );
506 /* unfortunately we can't take the address of the tpdu_type field,
507 * since it's a bit field - so we just use the constant offset 2
508 */
509
510 /* Now this isn't very neat but since you locate a pcb one way
511 * at the beginning of connection establishment, and by
512 * the dref for each tpdu after that, we have to treat CRs differently
513 */
514 if ( dutype == CR_TPDU_type ) {
515 u_char alt_classes = 0;
516
a50e2bc0 517 preferred_class = 1 << hdr->tpdu_CRclass;
b7fb0758
KS
518 opt = hdr->tpdu_CRoptions;
519
520 WHILE_OPTIONS(P, hdr, 1 ) /* { */
521
522 switch( vbptr(P)->tpv_code ) {
523
524 case TPP_tpdu_size:
525 vb_getval(P, u_char, dusize);
526 IFDEBUG(D_TPINPUT)
527 printf("CR dusize 0x%x\n", dusize);
528 ENDDEBUG
facaece3
KS
529 /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */
530 if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE)
531 dusize = TP_DFL_TPDUSIZE;
b7fb0758 532 break;
d119092b
KS
533 case TPP_ptpdu_size:
534 switch (vbptr(P)->tpv_len) {
535 case 1: pdusize = vbval(P, u_char); break;
536 case 2: pdusize = ntohs(vbval(P, u_short)); break;
537 default: ;
538 IFDEBUG(D_TPINPUT)
539 printf("malformed prefered TPDU option\n");
540 ENDDEBUG
541 }
542 break;
b7fb0758
KS
543 case TPP_addl_opt:
544 vb_getval(P, u_char, addlopt);
545 break;
546 case TPP_calling_sufx:
547 /* could use vb_getval, but we want to save the loc & len
548 * for later use
549 */
550 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
551 fsufxlen = vbptr(P)->tpv_len;
552 IFDEBUG(D_TPINPUT)
553 printf("CR fsufx:");
554 { register int j;
555 for(j=0; j<fsufxlen; j++ ) {
556 printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
557 }
558 printf("\n");
559 }
560 ENDDEBUG
561 break;
562 case TPP_called_sufx:
563 /* could use vb_getval, but we want to save the loc & len
564 * for later use
565 */
566 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
567 lsufxlen = vbptr(P)->tpv_len;
568 IFDEBUG(D_TPINPUT)
569 printf("CR lsufx:");
570 { register int j;
571 for(j=0; j<lsufxlen; j++ ) {
a50e2bc0 572 printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
b7fb0758
KS
573 }
574 printf("\n");
575 }
576 ENDDEBUG
577 break;
578
579#ifdef TP_PERF_MEAS
580 case TPP_perf_meas:
581 vb_getval(P, u_char, perf_meas);
582 break;
4d8170e5 583#endif /* TP_PERF_MEAS */
b7fb0758
KS
584
585 case TPP_vers:
586 /* not in class 0; 1 octet; in CR_TPDU only */
facaece3 587 /* COS tests says if version wrong, use default version!?XXX */
b7fb0758 588 CHECK( (vbval(P, u_char) != TP_VERSION ),
10c42688 589 E_TP_INV_PVAL, ts_inv_pval, setversion,
facaece3 590 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) );
10c42688
KS
591 setversion:
592 version = vbval(P, u_char);
b7fb0758
KS
593 break;
594 case TPP_acktime:
595 vb_getval(P, u_short, acktime);
596 acktime = ntohs(acktime);
597 acktime = acktime/500; /* convert to slowtimo ticks */
598 if((short)acktime <=0 )
599 acktime = 2; /* don't allow a bad peer to screw us up */
600 IFDEBUG(D_TPINPUT)
601 printf("CR acktime 0x%x\n", acktime);
602 ENDDEBUG
603 break;
604
605 case TPP_alt_class:
606 {
607 u_char *aclass = 0;
608 register int i;
facaece3
KS
609 static u_char bad_alt_classes[5] =
610 { ~0, ~3, ~5, ~0xf, ~0x1f};
b7fb0758 611
facaece3
KS
612 aclass =
613 (u_char *) &(((struct tp_vbp *)P)->tpv_val);
b7fb0758 614 for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
facaece3 615 alt_classes |= (1<<((*aclass++)>>4));
b7fb0758 616 }
facaece3
KS
617 CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes),
618 E_TP_INV_PVAL, ts_inv_aclass, respond,
619 ((caddr_t)aclass) - (caddr_t)hdr);
b7fb0758
KS
620 IFDEBUG(D_TPINPUT)
621 printf("alt_classes 0x%x\n", alt_classes);
622 ENDDEBUG
623 }
624 break;
625
626 case TPP_security:
627 case TPP_residER:
628 case TPP_priority:
629 case TPP_transdelay:
630 case TPP_throughput:
631 case TPP_addl_info:
632 case TPP_subseq:
d9a01c3e 633 default:
b7fb0758
KS
634 IFDEBUG(D_TPINPUT)
635 printf("param ignored CR_TPDU code= 0x%x\n",
636 vbptr(P)->tpv_code);
637 ENDDEBUG
638 IncStat(ts_param_ignored);
639 break;
640
641 case TPP_checksum:
642 IFDEBUG(D_TPINPUT)
643 printf("CR before cksum\n");
644 ENDDEBUG
645
646 CHECK( iso_check_csum(m, tpdu_len),
647 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
648
649 IFDEBUG(D_TPINPUT)
650 printf("CR before cksum\n");
651 ENDDEBUG
652 break;
b7fb0758
KS
653 }
654
655 /* } */ END_WHILE_OPTIONS(P)
656
63f88aec 657 if (lsufxlen == 0) {
b7fb0758
KS
658 /* can't look for a tpcb w/o any called sufx */
659 error = E_TP_LENGTH_INVAL;
660 IncStat(ts_inv_sufx);
661 goto respond;
662 } else {
63f88aec 663 register struct tp_pcb *t;
01acbfa1
KS
664 /*
665 * The intention here is to trap all CR requests
666 * to a given nsap, for constructing transport
667 * service bridges at user level; so these
668 * intercepts should precede the normal listens.
669 * Phrasing the logic in this way also allows for
670 * mop-up listeners, which we don't currently implement.
671 * We also wish to have a single socket be able to
672 * listen over any network service provider,
673 * (cons or clns or ip).
674 */
823532e9 675 for (t = tp_listeners; t ; t = t->tp_nextlisten)
01acbfa1
KS
676 if ((t->tp_lsuffixlen == 0 ||
677 (lsufxlen == t->tp_lsuffixlen &&
678 bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) &&
679 ((t->tp_flags & TPF_GENERAL_ADDR) ||
680 (laddr->sa_family == t->tp_domain &&
681 (*t->tp_nlproto->nlp_cmpnetaddr)
682 (t->tp_npcb, laddr, TP_LOCAL))))
683 break;
684
63f88aec 685 CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond,
b7fb0758
KS
686 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
687 /* _tpduf is the fixed part; add 2 to get the dref bits of
688 * the fixed part (can't take the address of a bit field)
689 */
823532e9
KS
690 IFDEBUG(D_TPINPUT)
691 printf("checking if dup CR\n");
692 ENDDEBUG
63f88aec
KS
693 tpcb = t;
694 for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) {
695 if (sref != t->tp_fref)
696 continue;
697 if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)(
698 t->tp_npcb, faddr, TP_FOREIGN)) {
699 IFDEBUG(D_TPINPUT)
700 printf("duplicate CR discarded\n");
701 ENDDEBUG
702 goto discard;
703 }
704 }
705 IFTRACE(D_TPINPUT)
706 tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate",
707 tpcb, *lsufxloc, tpcb->tp_state, 0);
708 ENDTRACE
b7fb0758
KS
709 }
710
711 /*
712 * WE HAVE A TPCB
713 * already know that the classes in the CR match at least
714 * one class implemented, but we don't know yet if they
715 * include any classes permitted by this server.
716 */
717
718 IFDEBUG(D_TPINPUT)
719 printf("HAVE A TPCB 1: 0x%x\n", tpcb);
720 ENDDEBUG
721 IFDEBUG(D_CONN)
722 printf(
723"CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
724 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
725 ENDDEBUG
726 /* tpcb->tp_class doesn't include any classes not implemented */
727 class_to_use = (preferred_class & tpcb->tp_class);
728 if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
729 class_to_use = alt_classes & tpcb->tp_class;
730
731 class_to_use = 1 << tp_mask_to_num(class_to_use);
732
733 {
734 tpp = tpcb->_tp_param;
735 tpp.p_class = class_to_use;
736 tpp.p_tpdusize = dusize;
d119092b 737 tpp.p_ptpdusize = pdusize;
b7fb0758
KS
738 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
739 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
740 tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
741 (addlopt & TPAO_NO_CSUM) == 0;
10c42688 742 tpp.p_version = version;
b7fb0758
KS
743#ifdef notdef
744 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
745 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
746 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
4d8170e5 747#endif /* notdef */
b7fb0758
KS
748
749 CHECK(
750 tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
01acbfa1 751 E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
b7fb0758
KS
752 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
753 /* ^ more or less the location of class */
754 )
755 }
756 IFTRACE(D_CONN)
757 tptrace(TPPTmisc,
758 "after 1 consist class_to_use class, out, tpconsout",
759 class_to_use,
760 tpcb->tp_class, dgout_routine, tpcons_output
761 );
762 ENDTRACE
763 CHECK(
764 ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
01acbfa1 765 E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb,
b7fb0758
KS
766 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
767 /* ^ more or less the location of class */
768 )
769 IFDEBUG(D_CONN)
770 printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
771 tpcb, tpcb->tp_flags);
772 ENDDEBUG
773 takes_data = TRUE;
774 e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt;
775 e.ev_number = CR_TPDU;
776
777 so = tpcb->tp_sock;
778 if (so->so_options & SO_ACCEPTCONN) {
63f88aec 779 struct tp_pcb *parent_tpcb = tpcb;
b7fb0758
KS
780 /*
781 * Create a socket, tpcb, ll pcb, etc.
782 * for this newborn connection, and fill in all the values.
783 */
784 IFDEBUG(D_CONN)
785 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
786 so, laddr, faddr, cons_channel);
787 ENDDEBUG
788 if( (so =
789 tp_newsocket(so, faddr, cons_channel,
790 class_to_use,
a50e2bc0
KS
791 ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
792 (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
b7fb0758
KS
793 ) == (struct socket *)0 ) {
794 /* note - even if netservice is IN_CLNS, as far as
795 * the tp entity is concerned, the only differences
a50e2bc0 796 * are CO vs CL
b7fb0758
KS
797 */
798 IFDEBUG(D_CONN)
799 printf("tp_newsocket returns 0\n");
800 ENDDEBUG
801 goto discard;
01acbfa1
KS
802 clear_parent_tcb:
803 tpcb = 0;
804 goto respond;
b7fb0758
KS
805 }
806 tpcb = sototpcb(so);
823532e9 807 insque(tpcb, parent_tpcb);
b7fb0758 808
b7fb0758 809 /*
a50e2bc0 810 * Stash the addresses in the net level pcb
b7fb0758
KS
811 * kind of like a pcbconnect() but don't need
812 * or want all those checks.
813 */
f15f73d2
KS
814 (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN);
815 (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL);
b7fb0758 816
a50e2bc0 817 /* stash the f suffix in the new tpcb */
01acbfa1
KS
818 if (tpcb->tp_fsuffixlen = fsufxlen) {
819 bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
820 (tpcb->tp_nlproto->nlp_putsufx)
821 (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN);
822 }
823 /* stash the l suffix in the new tpcb */
824 tpcb->tp_lsuffixlen = lsufxlen;
825 bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen);
44f52ea5 826 (tpcb->tp_nlproto->nlp_putsufx)
f15f73d2 827 (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL);
b7fb0758
KS
828#ifdef TP_PERF_MEAS
829 if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
830 /* ok, let's create an mbuf for stashing the
831 * statistics if one doesn't already exist
832 */
833 (void) tp_setup_perf(tpcb);
834 }
4d8170e5 835#endif /* TP_PERF_MEAS */
b7fb0758
KS
836 tpcb->tp_fref = sref;
837
838 /* We've already checked for consistency with the options
839 * set in tpp, but we couldn't set them earlier because
840 * we didn't want to change options in the LISTENING tpcb.
841 * Now we set the options in the new socket's tpcb.
842 */
843 (void) tp_consistency( tpcb, TP_FORCE, &tpp);
844
845 if(!tpcb->tp_use_checksum)
846 IncStat(ts_csum_off);
847 if(tpcb->tp_xpd_service)
848 IncStat(ts_use_txpd);
849 if(tpcb->tp_xtd_format)
850 IncStat(ts_xtd_fmt);
851
b7fb0758
KS
852 tpcb->tp_peer_acktime = acktime;
853
854 /*
855 * The following kludge is used to test retransmissions and
856 * timeout during connection establishment.
857 */
858 IFDEBUG(D_ZDREF)
859 IncStat(ts_zdebug);
a50e2bc0 860 /*tpcb->tp_fref = 0;*/
b7fb0758
KS
861 ENDDEBUG
862 }
8c123bbf 863 LOCAL_CREDIT(tpcb);
b7fb0758 864 IncStat(ts_CR_rcvd);
20650f15
KS
865 if (!tpcb->tp_cebit_off) {
866 tpcb->tp_win_recv = tp_start_win << 8;
867 tpcb->tp_cong_sample.cs_size = 0;
20650f15
KS
868 CONG_INIT_SAMPLE(tpcb);
869 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
870 }
b7fb0758
KS
871 } else if ( dutype == ER_TPDU_type ) {
872 /*
873 * ER TPDUs have to be recognized separately
874 * because they don't necessarily have a tpcb
875 * with them and we don't want err out looking for such
876 * a beast.
877 * We could put a bunch of little kludges in the
878 * next section of code so it would avoid references to tpcb
879 * if dutype == ER_TPDU_type but we don't want code for ERs to
880 * mess up code for data transfer.
881 */
882 IncStat(ts_ER_rcvd);
883 e.ev_number = ER_TPDU;
884 e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason;
3a2fbed9 885 CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size ||
0b673a61 886 (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ||
bdf41b09
KS
887 tpcb->tp_refstate == REF_FREE ||
888 tpcb->tp_refstate == REF_FROZEN),
0b673a61
KS
889 E_TP_MISM_REFS, ts_inv_dref, discard, 0)
890
b7fb0758
KS
891 } else {
892 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
893
894 /* In the next 4 checks,
895 * _tpduf is the fixed part; add 2 to get the dref bits of
896 * the fixed part (can't take the address of a bit field)
897 */
01acbfa1
KS
898#ifdef TPCONS
899 if (cons_channel && dutype == DT_TPDU_type) {
900 struct isopcb *isop = ((struct isopcb *)
901 ((struct pklcd *)cons_channel)->lcd_upnext);
902 if (isop && isop->isop_refcnt == 1 && isop->isop_socket &&
903 (tpcb = sototpcb(isop->isop_socket)) &&
904 (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) {
905 IFDEBUG(D_TPINPUT)
906 printf("tpinput_dt: class 0 short circuit\n");
907 ENDDEBUG
908 dref = tpcb->tp_lref;
909 sref = tpcb->tp_fref;
bdf41b09 910 CHECK( (tpcb->tp_refstate == REF_FREE),
01acbfa1
KS
911 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
912 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
913 goto tp0_data;
914 }
b7fb0758 915
01acbfa1 916 }
194a383a 917#endif
194a383a 918 {
b7fb0758 919
3a2fbed9 920 CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) ,
facaece3 921 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
b7fb0758
KS
922 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
923 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
facaece3 924 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
b7fb0758 925 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
bdf41b09 926 CHECK( (tpcb->tp_refstate == REF_FREE),
facaece3 927 E_TP_MISM_REFS,ts_inv_dref, nonx_dref,
b7fb0758
KS
928 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
929 }
930
931 IFDEBUG(D_TPINPUT)
932 printf("HAVE A TPCB 2: 0x%x\n", tpcb);
933 ENDDEBUG
934
935 /* causes a DR to be sent for CC; ER for all else */
bdf41b09 936 CHECK( (tpcb->tp_refstate == REF_FROZEN),
b7fb0758
KS
937 (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
938 ts_inv_dref, respond,
939 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
940
941 IFDEBUG(D_TPINPUT)
942 printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
943 ENDDEBUG
944 /*
945 * At this point the state of the dref could be
946 * FROZEN: tpr_pcb == NULL, has ( reference only) timers
947 * for example, DC may arrive after the close() has detached
948 * the tpcb (e.g., if user turned off SO_LISTEN option)
949 * OPENING : a tpcb exists but no timers yet
950 * OPEN : tpcb exists & timers are outstanding
951 */
952
20650f15
KS
953 if (!tpcb->tp_cebit_off)
954 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
955
b7fb0758 956 dusize = tpcb->tp_tpdusize;
d119092b 957 pdusize = tpcb->tp_ptpdusize;
b7fb0758
KS
958
959 dutype = hdr->tpdu_type << 8; /* for the switch below */
960
961 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
962
a50e2bc0 963#define caseof(x,y) case (((x)<<8)+(y))
b7fb0758
KS
964 switch( dutype | vbptr(P)->tpv_code ) {
965
966 caseof( CC_TPDU_type, TPP_addl_opt ):
967 /* not in class 0; 1 octet */
968 vb_getval(P, u_char, addlopt);
969 break;
970 caseof( CC_TPDU_type, TPP_tpdu_size ):
facaece3
KS
971 {
972 u_char odusize = dusize;
b7fb0758 973 vb_getval(P, u_char, dusize);
facaece3
KS
974 CHECK( (dusize < TP_MIN_TPDUSIZE ||
975 dusize > TP_MAX_TPDUSIZE || dusize > odusize),
976 E_TP_INV_PVAL, ts_inv_pval, respond,
977 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
b7fb0758
KS
978 IFDEBUG(D_TPINPUT)
979 printf("CC dusize 0x%x\n", dusize);
980 ENDDEBUG
facaece3 981 }
b7fb0758 982 break;
d119092b
KS
983 caseof( CC_TPDU_type, TPP_ptpdu_size ):
984 {
985 u_short opdusize = pdusize;
986 switch (vbptr(P)->tpv_len) {
987 case 1: pdusize = vbval(P, u_char); break;
988 case 2: pdusize = ntohs(vbval(P, u_short)); break;
989 default: ;
990 IFDEBUG(D_TPINPUT)
991 printf("malformed prefered TPDU option\n");
992 ENDDEBUG
993 }
994 CHECK( (pdusize == 0 ||
995 (opdusize && (pdusize > opdusize))),
996 E_TP_INV_PVAL, ts_inv_pval, respond,
997 (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) )
998 }
999 break;
b7fb0758
KS
1000 caseof( CC_TPDU_type, TPP_calling_sufx):
1001 IFDEBUG(D_TPINPUT)
1002 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
1003 ENDDEBUG
1004 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
1005 lsufxlen = vbptr(P)->tpv_len;
1006 break;
1007 caseof( CC_TPDU_type, TPP_acktime ):
1008 /* class 4 only, 2 octets */
1009 vb_getval(P, u_short, acktime);
d9a01c3e 1010 acktime = ntohs(acktime);
b7fb0758
KS
1011 acktime = acktime/500; /* convert to slowtimo ticks */
1012 if( (short)acktime <=0 )
1013 acktime = 2;
1014 break;
1015 caseof( CC_TPDU_type, TPP_called_sufx):
1016 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
1017 fsufxlen = vbptr(P)->tpv_len;
1018 IFDEBUG(D_TPINPUT)
1019 printf("CC called (foreign) sufx len %d\n", fsufxlen);
1020 ENDDEBUG
1021 break;
1022
1023 caseof( CC_TPDU_type, TPP_checksum):
1024 caseof( DR_TPDU_type, TPP_checksum):
1025 caseof( DT_TPDU_type, TPP_checksum):
1026 caseof( XPD_TPDU_type, TPP_checksum):
1027 if( tpcb->tp_use_checksum ) {
1028 CHECK( iso_check_csum(m, tpdu_len),
1029 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
1030 }
1031 break;
1032
1033 /* this is different from the above because in the context
1034 * of concat/ sep tpdu_len might not be the same as hdr len
1035 */
1036 caseof( AK_TPDU_type, TPP_checksum):
1037 caseof( XAK_TPDU_type, TPP_checksum):
1038 caseof( DC_TPDU_type, TPP_checksum):
1039 if( tpcb->tp_use_checksum ) {
a50e2bc0 1040 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
b7fb0758
KS
1041 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
1042 }
1043 break;
1044#ifdef notdef
1045 caseof( DR_TPDU_type, TPP_addl_info ):
1046 /* ignore - its length and meaning are
1047 * user defined and there's no way
1048 * to pass this info to the user anyway
1049 */
1050 break;
4d8170e5 1051#endif /* notdef */
b7fb0758
KS
1052
1053 caseof( AK_TPDU_type, TPP_subseq ):
1054 /* used after reduction of window */
1055 vb_getval(P, u_short, subseq);
1056 subseq = ntohs(subseq);
1057 IFDEBUG(D_ACKRECV)
bdf41b09 1058 printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq);
b7fb0758
KS
1059 ENDDEBUG
1060 break;
1061
1062 caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
1063 {
1064 u_int ylwe;
1065 u_short ysubseq, ycredit;
1066
1067 fcc_present = TRUE;
1068 vb_getval(P, u_int, ylwe);
1069 vb_getval(P, u_short, ysubseq);
1070 vb_getval(P, u_short, ycredit);
1071 ylwe = ntohl(ylwe);
1072 ysubseq = ntohs(ysubseq);
1073 ycredit = ntohs(ycredit);
1074 IFDEBUG(D_ACKRECV)
bdf41b09
KS
1075 printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n",
1076 "AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref);
b7fb0758
KS
1077 ENDDEBUG
1078 }
1079 break;
1080
1081 default:
1082 IFDEBUG(D_TPINPUT)
1083 printf("param ignored dutype 0x%x, code 0x%x\n",
1084 dutype, vbptr(P)->tpv_code);
1085 ENDDEBUG
1086 IFTRACE(D_TPINPUT)
1087 tptrace(TPPTmisc, "param ignored dutype code ",
1088 dutype, vbptr(P)->tpv_code ,0,0);
1089 ENDTRACE
1090 IncStat(ts_param_ignored);
1091 break;
1092#undef caseof
1093 }
1094 /* } */ END_WHILE_OPTIONS(P)
1095
1096 /* NOTE: the variable dutype has been shifted left! */
1097
1098 switch( hdr->tpdu_type ) {
1099 case CC_TPDU_type:
1100 /* If CC comes back with an unacceptable class
1101 * respond with a DR or ER
1102 */
1103
1104 opt = hdr->tpdu_CCoptions; /* 1 byte */
1105
1106 {
1107 tpp = tpcb->_tp_param;
1108 tpp.p_class = (1<<hdr->tpdu_CCclass);
1109 tpp.p_tpdusize = dusize;
d119092b 1110 tpp.p_ptpdusize = pdusize;
b7fb0758
KS
1111 tpp.p_dont_change_params = 0;
1112 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1113 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1114 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1115#ifdef notdef
1116 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1117 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1118 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
4d8170e5 1119#endif /* notdef */
b7fb0758
KS
1120
1121 CHECK(
1122 tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1123 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1124 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1125 /* ^ more or less the location of class */
1126 )
1127 IFTRACE(D_CONN)
1128 tptrace(TPPTmisc,
1129 "after 1 consist class, out, tpconsout",
1130 tpcb->tp_class, dgout_routine, tpcons_output, 0
1131 );
1132 ENDTRACE
1133 CHECK(
1134 ((class_to_use == TP_CLASS_0)&&
1135 (dgout_routine != tpcons_output)),
1136 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1137 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1138 /* ^ more or less the location of class */
1139 )
194a383a
KS
1140#ifdef TPCONS
1141 if (tpcb->tp_netservice == ISO_CONS &&
1142 class_to_use == TP_CLASS_0) {
1143 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
1144 struct pklcd *lcp = (struct pklcd *)isop->isop_chan;
1145 lcp->lcd_flags &= ~X25_DG_CIRCUIT;
1146 }
1147#endif
b7fb0758
KS
1148 }
1149 if( ! tpcb->tp_use_checksum)
1150 IncStat(ts_csum_off);
1151 if(tpcb->tp_xpd_service)
1152 IncStat(ts_use_txpd);
1153 if(tpcb->tp_xtd_format)
1154 IncStat(ts_xtd_fmt);
1155
1156 IFTRACE(D_CONN)
1157 tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1158 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1159 hdr->tpdu_CCclass);
1160 ENDTRACE
1161
b7fb0758
KS
1162 /* if called or calling suffices appeared on the CC,
1163 * they'd better jive with what's in the pcb
1164 */
1165 if( fsufxlen ) {
1166 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
1167 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1168 E_TP_INV_PVAL,ts_inv_sufx, respond,
1169 (1+fsufxloc - (caddr_t)hdr))
1170 }
1171 if( lsufxlen ) {
1172 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
1173 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1174 E_TP_INV_PVAL,ts_inv_sufx, respond,
1175 (1+lsufxloc - (caddr_t)hdr))
1176 }
1177
b7fb0758 1178 e.ATTR(CC_TPDU).e_sref = sref;
b7fb0758
KS
1179 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt;
1180 takes_data = TRUE;
1181 e.ev_number = CC_TPDU;
1182 IncStat(ts_CC_rcvd);
1183 break;
1184
1185 case DC_TPDU_type:
b7fb0758
KS
1186 if (sref != tpcb->tp_fref)
1187 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1188 sref, tpcb->tp_fref);
b7fb0758 1189
b7fb0758 1190 CHECK( (sref != tpcb->tp_fref),
facaece3 1191 E_TP_MISM_REFS, ts_inv_sufx, discard,
b7fb0758 1192 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
facaece3 1193
b7fb0758
KS
1194 e.ev_number = DC_TPDU;
1195 IncStat(ts_DC_rcvd);
1196 break;
1197
1198 case DR_TPDU_type:
1199 IFTRACE(D_TPINPUT)
1200 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1201 ENDTRACE
facaece3 1202 if (sref != tpcb->tp_fref) {
b7fb0758
KS
1203 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1204 sref, tpcb->tp_fref);
facaece3 1205 }
b7fb0758 1206
facaece3
KS
1207 CHECK( (sref != 0 && sref != tpcb->tp_fref &&
1208 tpcb->tp_state != TP_CRSENT),
1209 (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond,
b7fb0758
KS
1210 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1211
1212 e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
1213 e.ATTR(DR_TPDU).e_sref = (u_short)sref;
b7fb0758
KS
1214 takes_data = TRUE;
1215 e.ev_number = DR_TPDU;
1216 IncStat(ts_DR_rcvd);
1217 break;
1218
1219 case ER_TPDU_type:
1220 IFTRACE(D_TPINPUT)
1221 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
1222 ENDTRACE
1223 e.ev_number = ER_TPDU;
1224 e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
1225 IncStat(ts_ER_rcvd);
1226 break;
1227
1228 case AK_TPDU_type:
1229
1230 e.ATTR(AK_TPDU).e_subseq = subseq;
1231 e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
1232
1233 if (tpcb->tp_xtd_format) {
1234#ifdef BYTE_ORDER
1235 union seq_type seqeotX;
1236
1237 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1238 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
1239 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1240#else
1241 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
1242 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
4d8170e5 1243#endif /* BYTE_ORDER */
b7fb0758
KS
1244 } else {
1245 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
1246 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
1247 }
1248 IFTRACE(D_TPINPUT)
1249 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1250 e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
1251 subseq, fcc_present);
1252 ENDTRACE
1253
1254 e.ev_number = AK_TPDU;
1255 IncStat(ts_AK_rcvd);
1256 IncPStat(tpcb, tps_AK_rcvd);
1257 break;
1258
1259 case XAK_TPDU_type:
1260 if (tpcb->tp_xtd_format) {
1261#ifdef BYTE_ORDER
1262 union seq_type seqeotX;
1263
1264 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1265 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
1266#else
1267 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
4d8170e5 1268#endif /* BYTE_ORDER */
b7fb0758
KS
1269 } else {
1270 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
1271 }
1272 e.ev_number = XAK_TPDU;
1273 IncStat(ts_XAK_rcvd);
1274 IncPStat(tpcb, tps_XAK_rcvd);
1275 break;
1276
1277 case XPD_TPDU_type:
1278 if (tpcb->tp_xtd_format) {
1279#ifdef BYTE_ORDER
1280 union seq_type seqeotX;
1281
1282 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1283 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
1284#else
1285 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
4d8170e5 1286#endif /* BYTE_ORDER */
b7fb0758
KS
1287 } else {
1288 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
1289 }
1290 takes_data = TRUE;
1291 e.ev_number = XPD_TPDU;
1292 IncStat(ts_XPD_rcvd);
1293 IncPStat(tpcb, tps_XPD_rcvd);
1294 break;
1295
1296 case DT_TPDU_type:
1297 { /* the y option will cause occasional packets to be dropped.
1298 * A little crude but it works.
1299 */
1300
1301 IFDEBUG(D_DROP)
1302 if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
1303 IncStat(ts_ydebug);
1304 goto discard;
1305 }
1306 ENDDEBUG
1307 }
1308 if (tpcb->tp_class == TP_CLASS_0) {
01acbfa1 1309 tp0_data:
b7fb0758
KS
1310 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
1311 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
1312 } else if (tpcb->tp_xtd_format) {
1313#ifdef BYTE_ORDER
1314 union seq_type seqeotX;
1315
1316 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1317 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
1318 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
1319#else
1320 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
1321 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
4d8170e5 1322#endif /* BYTE_ORDER */
b7fb0758
KS
1323 } else {
1324 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
1325 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
1326 }
1327 if(e.ATTR(DT_TPDU).e_eot)
1328 IncStat(ts_eot_input);
1329 takes_data = TRUE;
1330 e.ev_number = DT_TPDU;
1331 IncStat(ts_DT_rcvd);
1332 IncPStat(tpcb, tps_DT_rcvd);
1333 break;
1334
1335 case GR_TPDU_type:
1336 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1337 /* drop through */
1338 default:
1339 /* this should NEVER happen because there is a
1340 * check for dutype well above here
1341 */
1342 error = E_TP_INV_TPDU; /* causes an ER */
1343 IFDEBUG(D_TPINPUT)
1344 printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1345 ENDDEBUG
1346 IncStat(ts_inv_dutype);
1347 goto respond;
1348 }
1349 }
b7fb0758
KS
1350 /* peel off the tp header;
1351 * remember that the du_li doesn't count itself.
1352 * This may leave us w/ an empty mbuf at the front of a chain.
1353 * We can't just throw away the empty mbuf because hdr still points
1354 * into the mbuf's data area and we're still using hdr (the tpdu header)
1355 */
1356 m->m_len -= ((int)hdr->tpdu_li + 1);
a50e2bc0 1357 m->m_data += ((int)hdr->tpdu_li + 1);
b7fb0758 1358
a50e2bc0
KS
1359 if (takes_data) {
1360 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
1361 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
c71927bd
KS
1362 struct {
1363 struct tp_disc_reason dr;
1364 struct cmsghdr x_hdr;
1365 } x;
1366#define c_hdr x.x_hdr
1367 register struct mbuf *n;
b7fb0758 1368
a50e2bc0
KS
1369 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
1370 ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
b7fb0758 1371 switch( hdr->tpdu_type ) {
a50e2bc0 1372
b7fb0758 1373 case CR_TPDU_type:
a50e2bc0
KS
1374 c_hdr.cmsg_type = TPOPT_CONN_DATA;
1375 goto make_control_msg;
1376
b7fb0758 1377 case CC_TPDU_type:
a50e2bc0
KS
1378 c_hdr.cmsg_type = TPOPT_CFRM_DATA;
1379 goto make_control_msg;
1380
b7fb0758 1381 case DR_TPDU_type:
c71927bd
KS
1382 x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr);
1383 x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON;
1384 x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT;
1385 x.dr.dr_reason = hdr->tpdu_DRreason;
a50e2bc0
KS
1386 c_hdr.cmsg_type = TPOPT_DISC_DATA;
1387 make_control_msg:
c71927bd
KS
1388 datalen += sizeof(c_hdr);
1389 c_hdr.cmsg_len = datalen;
a50e2bc0
KS
1390 c_hdr.cmsg_level = SOL_TRANSPORT;
1391 mbtype = MT_CONTROL;
c2bb180a 1392 MGET(n, M_DONTWAIT, MT_DATA);
c71927bd
KS
1393 if (n == 0)
1394 {m_freem(m); m = 0; datalen = 0; goto invoke; }
1395 if (hdr->tpdu_type == DR_TPDU_type) {
1396 datalen += sizeof(x) - sizeof(c_hdr);
1397 bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x));
1398 } else
1399 bcopy((caddr_t)&c_hdr, mtod(n, caddr_t),
1400 n->m_len = sizeof(c_hdr));
1401 n->m_next = m;
1402 m = n;
a50e2bc0
KS
1403 /* FALLTHROUGH */
1404
b7fb0758 1405 case XPD_TPDU_type:
a50e2bc0
KS
1406 if (mbtype != MT_CONTROL)
1407 mbtype = MT_OOBDATA;
1408 m->m_flags |= M_EOR;
1409 /* FALLTHROUGH */
b7fb0758 1410
a50e2bc0
KS
1411 case DT_TPDU_type:
1412 for (n = m; n; n = n->m_next) {
1413 MCHTYPE(n, mbtype);
1414 }
c2bb180a 1415 invoke:
a50e2bc0 1416 e.ATTR(DT_TPDU).e_datalen = datalen;
b7fb0758
KS
1417 e.ATTR(DT_TPDU).e_data = m;
1418 break;
1419
1420 default:
1421 printf(
1422 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1423 hdr->tpdu_type, takes_data, m);
1424 break;
1425 }
1426 /* prevent m_freem() after tp_driver() from throwing it all away */
1427 m = MNULL;
1428 }
1429
1430 IncStat(ts_tpdu_rcvd);
1431
1432 IFDEBUG(D_TPINPUT)
1433 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1434 tpcb->tp_state, e.ev_number, m );
1435 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
1436 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1437 takes_data, (m==MNULL)?0:m->m_len, tpdu_len);
1438 ENDDEBUG
1439
b7fb0758
KS
1440 error = tp_driver(tpcb, &e);
1441
1442 ASSERT(tpcb != (struct tp_pcb *)0);
1443 ASSERT(tpcb->tp_sock != (struct socket *)0);
1444 if( tpcb->tp_sock->so_error == 0 )
1445 tpcb->tp_sock->so_error = error;
1446
1447 /* Kludge to keep the state tables under control (adding
1448 * data on connect & disconnect & freeing the mbuf containing
1449 * the data would have exploded the tables and made a big mess ).
1450 */
1451 switch(e.ev_number) {
1452 case CC_TPDU:
1453 case DR_TPDU:
1454 case CR_TPDU:
1455 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
1456 IFDEBUG(D_TPINPUT)
1457 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1458 m, takes_data);
1459 ENDDEBUG
1460 break;
1461 default:
1462 break;
1463 }
1464 /* Concatenated sequences are terminated by any tpdu that
1465 * carries data: CR, CC, DT, XPD, DR.
1466 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1467 */
1468
1469separate:
1470 if ( takes_data == 0 ) {
1471 ASSERT( m != MNULL );
1472 /*
1473 * we already peeled off the prev. tp header so
1474 * we can just pull up some more and repeat
1475 */
1476
a50e2bc0 1477 if( m = tp_inputprep(m) ) {
b7fb0758
KS
1478 IFDEBUG(D_TPINPUT)
1479 hdr = mtod(m, struct tpdu *);
1480 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1481 hdr, (int) hdr->tpdu_li + 1, m);
1482 dump_mbuf(m, "tp_input after driver, at separate");
1483 ENDDEBUG
1484
b7fb0758
KS
1485 IncStat(ts_concat_rcvd);
1486 goto again;
1487 }
1488 }
1489 if ( m != MNULL ) {
1490 IFDEBUG(D_TPINPUT)
1491 printf("tp_input : m_freem(0x%x)\n", m);
1492 ENDDEBUG
1493 m_freem(m);
1494 IFDEBUG(D_TPINPUT)
1495 printf("tp_input : after m_freem 0x%x\n", m);
1496 ENDDEBUG
1497 }
1498 return (ProtoHook) tpcb;
1499
1500discard:
1501 /* class 4: drop the tpdu */
1502 /* class 2,0: Should drop the net connection, if you can figure out
1503 * to which connection it applies
1504 */
1505 IFDEBUG(D_TPINPUT)
1506 printf("tp_input DISCARD\n");
1507 ENDDEBUG
1508 IFTRACE(D_TPINPUT)
1509 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0);
1510 ENDTRACE
1511 m_freem(m);
1512 IncStat(ts_recv_drop);
1513 return (ProtoHook)0;
1514
facaece3
KS
1515nonx_dref:
1516 switch (dutype) {
1517 default:
1518 goto discard;
1519 case CC_TPDU_type:
1520 /* error = E_TP_MISM_REFS; */
1521 break;
1522 case DR_TPDU_type:
1523 error |= TP_ERROR_SNDC;
1524 }
b7fb0758 1525respond:
c2bb180a 1526 IFDEBUG(D_TPINPUT)
facaece3 1527 printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen);
b7fb0758
KS
1528 ENDDEBUG
1529 IFTRACE(D_TPINPUT)
facaece3 1530 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0);
b7fb0758 1531 ENDTRACE
facaece3 1532 if (sref == 0)
b7fb0758 1533 goto discard;
a50e2bc0 1534 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
facaece3 1535 (struct sockaddr_iso *)laddr, m, errlen, tpcb,
01acbfa1 1536 cons_channel, dgout_routine);
b7fb0758
KS
1537 IFDEBUG(D_ERROR_EMIT)
1538 printf("tp_input after error_emit\n");
1539 ENDDEBUG
1540
1541#ifdef lint
1542 printf("",sref,opt);
4d8170e5 1543#endif /* lint */
b7fb0758
KS
1544 IncStat(ts_recv_drop);
1545 return (ProtoHook)0;
1546}
1547
1548
1549/*
1550 * NAME: tp_headersize()
1551 *
1552 * CALLED FROM:
1553 * tp_emit() and tp_sbsend()
1554 * TP needs to know the header size so it can figure out how
1555 * much data to put in each tpdu.
1556 *
1557 * FUNCTION, ARGUMENTS, and RETURN VALUE:
1558 * For a given connection, represented by (tpcb), and
1559 * tpdu type (dutype), return the size of a tp header.
1560 *
1561 * RETURNS: the expected size of the heade in bytesr
1562 *
1563 * SIDE EFFECTS:
1564 *
1565 * NOTES: It would be nice if it got the network header size as well.
1566 */
1567int
1568tp_headersize(dutype, tpcb)
1569 int dutype;
1570 struct tp_pcb *tpcb;
1571{
1572 register int size = 0;
1573
1574 IFTRACE(D_CONN)
1575 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1576 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1577 ENDTRACE
1578 if( !( (tpcb->tp_class == TP_CLASS_0) ||
1579 (tpcb->tp_class == TP_CLASS_4) ||
1580 (dutype == DR_TPDU_type) ||
1581 (dutype == CR_TPDU_type) )) {
1582 printf("tp_headersize:dutype 0x%x, class 0x%x",
1583 dutype, tpcb->tp_class);
1584 /* TODO: identify this and GET RID OF IT */
1585 }
1586 ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
1587 (tpcb->tp_class == TP_CLASS_4) ||
1588 (dutype == DR_TPDU_type) ||
1589 (dutype == CR_TPDU_type) );
1590
1591 if( tpcb->tp_class == TP_CLASS_0 ) {
1592 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
1593 } else {
1594 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
1595 }
1596 return size;
1597 /* caller must get network level header size separately */
1598}