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