checkpoint for ``alpha tape''; tp is still a little broken.
[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 $
44f52ea5 32 * @(#)tp_input.c 7.3 (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
171/*
172 * WHENEVER YOU USE THE FOLLOWING MACRO,
173 * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST!
174 */
175
176#define WHILE_OPTIONS(P, hdr,format)\
177{ register caddr_t P;\
178 P = (caddr_t)(hdr) +\
179 tpdu_info[(hdr)->tpdu_type][(format)];\
180 while( P < (caddr_t)(hdr) + (int)((hdr)->tpdu_li) ) {
181
182#define END_WHILE_OPTIONS(P)\
183 P = P + 2 + (int)((struct tp_vbp *)P)->tpv_len ;\
184} }
185
186#define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\
187 if(Phrase) { error = (Erval); errloc = (caddr_t)(Loc); IncStat(Stat); \
188 goto Whattodo; }
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;
44f52ea5 223 extern struct socket *sonewsock();
b7fb0758
KS
224
225 /*
226 * sonewconn() gets a new socket structure,
227 * a new lower layer pcb and a new tpcb,
228 * but the pcbs are unnamed (not bound)
229 */
230 IFTRACE(D_NEWSOCK)
44f52ea5
KS
231 tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head",
232 so, tpcb, so->so_head);
b7fb0758
KS
233 ENDTRACE
234
44f52ea5 235 if ((so = sonewsock(so, SS_ISCONFIRMING)) == (struct socket *)0)
b7fb0758
KS
236 return so;
237 IFTRACE(D_NEWSOCK)
44f52ea5
KS
238 tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head",
239 so, so->so_head, 0, 0);
b7fb0758
KS
240 ENDTRACE
241
b7fb0758 242 IFDEBUG(D_NEWSOCK)
a50e2bc0
KS
243 printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n",
244 cons_channel, so);
245 dump_addr(fname);
b7fb0758
KS
246 {
247 struct socket *t, *head ;
248
249 head = so->so_head;
250 t = so;
251 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
252 t, t->so_head, t->so_q0, t->so_q0len);
253 while( (t=t->so_q0) && t!= so && t!= head)
254 printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n",
255 t, t->so_head, t->so_q0, t->so_q0len);
256 }
257 ENDDEBUG
258
259 /*
260 * before we clobber the old tpcb ptr, get these items from the parent pcb
261 */
262 newtpcb = sototpcb(so);
263 newtpcb->_tp_param = tpcb->_tp_param;
264 newtpcb->tp_flags = tpcb->tp_flags;
265 newtpcb->tp_lcredit = tpcb->tp_lcredit;
266 newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize;
267 newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen;
268 bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen);
a50e2bc0 269 soreserve(so, (u_long)tpcb->tp_winsize, (u_long)tpcb->tp_winsize);
b7fb0758 270
a50e2bc0 271 if( /* old */ tpcb->tp_ucddata) {
b7fb0758 272 /*
a50e2bc0 273 * These data are the connect- , confirm- or disconnect- data.
b7fb0758
KS
274 */
275 struct mbuf *conndata;
276
a50e2bc0 277 conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL);
b7fb0758
KS
278 IFDEBUG(D_CONN)
279 dump_mbuf(conndata, "conndata after mcopy");
b7fb0758 280 ENDDEBUG
a50e2bc0 281 newtpcb->tp_ucddata = conndata;
b7fb0758
KS
282 }
283
284 tpcb = newtpcb;
285 tpcb->tp_state = TP_LISTENING;
286 tpcb->tp_class = class_to_use;
287 tpcb->tp_netservice = netservice;
288
289
290 ASSERT( fname != 0 ) ; /* just checking */
291 if ( fname ) {
292 /*
293 * tp_route_to takes its address argument in the form of an mbuf.
294 */
295 struct mbuf *m;
296 int err;
297
298 MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */
299 if (m) {
300 /*
301 * this seems a bit grotesque, but tp_route_to expects
302 * an mbuf * instead of simply a sockaddr; it calls the ll
303 * pcb_connect, which expects the name/addr in an mbuf as well.
304 * sigh.
305 */
a50e2bc0
KS
306 bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len);
307 m->m_len = fname->sa_len;
b7fb0758
KS
308
309 /* grot : have to say the kernel can override params in
310 * the passive open case
311 */
312 tpcb->tp_dont_change_params = 0;
313 err = tp_route_to( m, tpcb, cons_channel);
314 m_free(m);
315
316 if (!err)
317 goto ok;
318 }
319 IFDEBUG(D_CONN)
320 printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n",
321 tpcb, so);
322 ENDDEBUG
323 (void) tp_detach(tpcb);
324 return 0;
325 }
326ok:
327 IFDEBUG(D_TPINPUT)
328 printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n",
329 so, sototpcb(so));
330 ENDDEBUG
331 return so;
332}
333
334#ifndef CONS
335tpcons_output()
336{
337 return(0);
338}
339#endif !CONS
340
341/*
342 * NAME: tp_input()
343 *
344 * CALLED FROM:
345 * net layer input routine
346 *
347 * FUNCTION and ARGUMENTS:
348 * Process an incoming TPDU (m), finding the associated tpcb if there
349 * is one. Create the appropriate type of event and call the driver.
350 * (faddr) and (laddr) are the foreign and local addresses.
351 *
352 * When tp_input() is called we KNOW that the ENTIRE TP HEADER
353 * has been m_pullup-ed.
354 *
355 * RETURN VALUE: Nada
356 *
357 * SIDE EFFECTS:
358 * When using COSNS it may affect the state of the net-level pcb
359 *
360 * NOTE:
361 * The initial value of acktime is 2 so that we will never
362 * have a 0 value for tp_peer_acktime. It gets used in the
363 * computation of the retransmission timer value, and so it
364 * mustn't be zero.
365 * 2 seems like a reasonable minimum.
366 */
367ProtoHook
368tp_input(m, faddr, laddr, cons_channel, dgout_routine)
369 register struct mbuf *m;
370 struct sockaddr *faddr, *laddr; /* NSAP addresses */
371 u_int cons_channel;
372 int (*dgout_routine)();
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;
44f52ea5 379 int error;
b7fb0758
KS
380 unsigned dutype;
381 u_short dref, sref, acktime, subseq; /*VAX*/
44f52ea5 382 u_char preferred_class, class_to_use;
b7fb0758
KS
383 u_char opt, dusize, addlopt;
384#ifdef TP_PERF_MEAS
44f52ea5 385 u_char perf_meas;
b7fb0758
KS
386#endif TP_PERF_MEAS
387 u_char fsufxlen;
388 u_char lsufxlen;
44f52ea5 389 caddr_t fsufxloc, lsufxloc;
b7fb0758
KS
390 int tpdu_len;
391 u_int takes_data;
392 u_int fcc_present;
44f52ea5 393 caddr_t errloc;
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
KS
406
407 tpdu_len = 0;
408 tpcb = (struct tp_pcb *)0;
44f52ea5
KS
409 fsufxlen = 0; fsufxloc = 0;
410 lsufxlen = 0; lsufxloc = 0;
411 errloc = 0; error = 0;
b7fb0758
KS
412 addlopt = 0;
413 acktime = 2;
414 dusize = TP_DFL_TPDUSIZE;
415 sref = 0;
416 subseq = 0;
417 takes_data = FALSE;
418 fcc_present = FALSE;
44f52ea5 419 preferred_class = 0; class_to_use = 0;
b7fb0758
KS
420
421 /*
422 * get the actual tpdu length - necessary for monitoring
423 * and for checksumming
424 *
425 * Also, maybe measure the mbuf chain lengths and sizes.
426 */
427
428 { register struct mbuf *n=m;
429# ifdef ARGO_DEBUG
430 int chain_length = 0;
431# endif ARGO_DEBUG
432
433 for(;;) {
434 tpdu_len += n->m_len;
435 IFDEBUG(D_MBUF_MEAS)
a50e2bc0 436 if( n->m_flags & M_EXT) {
b7fb0758
KS
437 IncStat(ts_mb_cluster);
438 } else {
439 IncStat(ts_mb_small);
440 }
441 chain_length ++;
442 ENDDEBUG
443 if (n->m_next == MNULL ) {
444 break;
445 }
446 n = n->m_next;
447 }
448 IFDEBUG(D_MBUF_MEAS)
449 if(chain_length > 16)
450 chain_length = 0; /* zero used for anything > 16 */
451 tp_stat.ts_mb_len_distr[chain_length] ++;
452 ENDDEBUG
453 }
454 IFTRACE(D_TPINPUT)
455 tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len,
456 0);
457 ENDTRACE
458
459 dref = ntohs((short)hdr->tpdu_dref);
460 sref = ntohs((short)hdr->tpdu_sref);
461 dutype = (int)hdr->tpdu_type;
462
463 IFDEBUG(D_TPINPUT)
464 printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype,
465 cons_channel, dref);
466 printf("input: dref 0x%x sref 0x%x\n", dref, sref);
467 ENDDEBUG
468 IFTRACE(D_TPINPUT)
469 tptrace(TPPTmisc, "channel dutype dref ",
470 cons_channel, dutype, dref, 0);
471 ENDTRACE
472
473
474#ifdef ARGO_DEBUG
475 if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) {
476 printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n",
477 dutype, cons_channel, dref);
478 dump_buf (m, sizeof( struct mbuf ));
479
480 IncStat(ts_inv_dutype);
481 goto discard;
482 }
483#endif ARGO_DEBUG
484
485 CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE),
486 E_TP_INV_TPDU, ts_inv_dutype, respond,
487 2 );
488 /* unfortunately we can't take the address of the tpdu_type field,
489 * since it's a bit field - so we just use the constant offset 2
490 */
491
492 /* Now this isn't very neat but since you locate a pcb one way
493 * at the beginning of connection establishment, and by
494 * the dref for each tpdu after that, we have to treat CRs differently
495 */
496 if ( dutype == CR_TPDU_type ) {
497 u_char alt_classes = 0;
498
499#ifdef notdef /* This is done up above */
500 sref = hdr->tpdu_CRsref;
501#endif notdef
a50e2bc0 502 preferred_class = 1 << hdr->tpdu_CRclass;
b7fb0758
KS
503 opt = hdr->tpdu_CRoptions;
504
505 WHILE_OPTIONS(P, hdr, 1 ) /* { */
506
507 switch( vbptr(P)->tpv_code ) {
508
509 case TPP_tpdu_size:
510 vb_getval(P, u_char, dusize);
511 IFDEBUG(D_TPINPUT)
512 printf("CR dusize 0x%x\n", dusize);
513 ENDDEBUG
514 CHECK( (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE),
515 E_TP_INV_PVAL, ts_inv_pval, respond,
516 (1 + (caddr_t)&vbptr(P)->tpv_val - P) )
517 break;
518 case TPP_addl_opt:
519 vb_getval(P, u_char, addlopt);
520 break;
521 case TPP_calling_sufx:
522 /* could use vb_getval, but we want to save the loc & len
523 * for later use
524 */
525 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
526 fsufxlen = vbptr(P)->tpv_len;
527 IFDEBUG(D_TPINPUT)
528 printf("CR fsufx:");
529 { register int j;
530 for(j=0; j<fsufxlen; j++ ) {
531 printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) );
532 }
533 printf("\n");
534 }
535 ENDDEBUG
536 break;
537 case TPP_called_sufx:
538 /* could use vb_getval, but we want to save the loc & len
539 * for later use
540 */
541 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
542 lsufxlen = vbptr(P)->tpv_len;
543 IFDEBUG(D_TPINPUT)
544 printf("CR lsufx:");
545 { register int j;
546 for(j=0; j<lsufxlen; j++ ) {
a50e2bc0 547 printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) );
b7fb0758
KS
548 }
549 printf("\n");
550 }
551 ENDDEBUG
552 break;
553
554#ifdef TP_PERF_MEAS
555 case TPP_perf_meas:
556 vb_getval(P, u_char, perf_meas);
557 break;
558#endif TP_PERF_MEAS
559
560 case TPP_vers:
561 /* not in class 0; 1 octet; in CR_TPDU only */
562 CHECK( (vbval(P, u_char) != TP_VERSION ),
563 E_TP_INV_PVAL, ts_inv_pval, respond,
564 (1 + (caddr_t)&vbptr(P)->tpv_val - P) )
565 break;
566 case TPP_acktime:
567 vb_getval(P, u_short, acktime);
568 acktime = ntohs(acktime);
569 acktime = acktime/500; /* convert to slowtimo ticks */
570 if((short)acktime <=0 )
571 acktime = 2; /* don't allow a bad peer to screw us up */
572 IFDEBUG(D_TPINPUT)
573 printf("CR acktime 0x%x\n", acktime);
574 ENDDEBUG
575 break;
576
577 case TPP_alt_class:
578 {
579 u_char *aclass = 0;
580 register int i;
581
582 for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) {
583 aclass =
584 (u_char *) &(((struct tp_vbp *)P)->tpv_val);
a50e2bc0 585 alt_classes |= (1<<((*aclass)>>4));
b7fb0758
KS
586 }
587 IFDEBUG(D_TPINPUT)
588 printf("alt_classes 0x%x\n", alt_classes);
589 ENDDEBUG
590 }
591 break;
592
593 case TPP_security:
594 case TPP_residER:
595 case TPP_priority:
596 case TPP_transdelay:
597 case TPP_throughput:
598 case TPP_addl_info:
599 case TPP_subseq:
600 IFDEBUG(D_TPINPUT)
601 printf("param ignored CR_TPDU code= 0x%x\n",
602 vbptr(P)->tpv_code);
603 ENDDEBUG
604 IncStat(ts_param_ignored);
605 break;
606
607 case TPP_checksum:
608 IFDEBUG(D_TPINPUT)
609 printf("CR before cksum\n");
610 ENDDEBUG
611
612 CHECK( iso_check_csum(m, tpdu_len),
613 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
614
615 IFDEBUG(D_TPINPUT)
616 printf("CR before cksum\n");
617 ENDDEBUG
618 break;
619
620 default:
621 IncStat(ts_inv_pcode);
622 error = E_TP_INV_PCODE;
623 goto discard;
624
625 }
626
627 /* } */ END_WHILE_OPTIONS(P)
628
629 if( lsufxlen == 0) {
630 /* can't look for a tpcb w/o any called sufx */
631 error = E_TP_LENGTH_INVAL;
632 IncStat(ts_inv_sufx);
633 goto respond;
634 } else {
635 register struct tp_ref *rp;
636 register int r;
637 extern int tp_maxrefopen;
638
639 rp = &tp_ref[1]; /* zero-th one is never open */
640 for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
641 if (rp->tpr_state!=REF_OPENING)
642 continue;
643 if ( bcmp(lsufxloc, rp->tpr_pcb->tp_lsuffix, lsufxlen)==0 ) {
644 tpcb = rp->tpr_pcb;
645 if( laddr->sa_family !=
646 tpcb->tp_sock->so_proto->pr_domain->dom_family ) {
647 IFDEBUG(D_CONN)
648 printf(
649 "MISMATCHED AF on CR! laddr.family 0x%x expected 0x%x\n",
650 laddr->sa_family,
651 tpcb->tp_sock->so_proto->pr_domain->dom_family );
652 ENDDEBUG
653 continue;
654 }
655 IFTRACE(D_TPINPUT)
656 tptrace(TPPTmisc, "tp_input: ref *lsufxloc refstate",
657 r, *lsufxloc, rp->tpr_state, 0);
658 ENDTRACE
659 /* found it */
660 break;
661 }
662 }
663
664 CHECK( (r > tp_maxrefopen), E_TP_NO_SESSION, ts_inv_sufx, respond,
665 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
666 /* _tpduf is the fixed part; add 2 to get the dref bits of
667 * the fixed part (can't take the address of a bit field)
668 */
669 }
670
671 /*
672 * WE HAVE A TPCB
673 * already know that the classes in the CR match at least
674 * one class implemented, but we don't know yet if they
675 * include any classes permitted by this server.
676 */
677
678 IFDEBUG(D_TPINPUT)
679 printf("HAVE A TPCB 1: 0x%x\n", tpcb);
680 ENDDEBUG
681 IFDEBUG(D_CONN)
682 printf(
683"CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n",
684 tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class);
685 ENDDEBUG
686 /* tpcb->tp_class doesn't include any classes not implemented */
687 class_to_use = (preferred_class & tpcb->tp_class);
688 if( (class_to_use = preferred_class & tpcb->tp_class) == 0 )
689 class_to_use = alt_classes & tpcb->tp_class;
690
691 class_to_use = 1 << tp_mask_to_num(class_to_use);
692
693 {
694 tpp = tpcb->_tp_param;
695 tpp.p_class = class_to_use;
696 tpp.p_tpdusize = dusize;
697 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
698 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
699 tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0:
700 (addlopt & TPAO_NO_CSUM) == 0;
701#ifdef notdef
702 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
703 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
704 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
705#endif notdef
706
707 CHECK(
708 tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0,
709 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
710 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
711 /* ^ more or less the location of class */
712 )
713 }
714 IFTRACE(D_CONN)
715 tptrace(TPPTmisc,
716 "after 1 consist class_to_use class, out, tpconsout",
717 class_to_use,
718 tpcb->tp_class, dgout_routine, tpcons_output
719 );
720 ENDTRACE
721 CHECK(
722 ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)),
723 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
724 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
725 /* ^ more or less the location of class */
726 )
727 IFDEBUG(D_CONN)
728 printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n",
729 tpcb, tpcb->tp_flags);
730 ENDDEBUG
731 takes_data = TRUE;
732 e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt;
733 e.ev_number = CR_TPDU;
734
735 so = tpcb->tp_sock;
736 if (so->so_options & SO_ACCEPTCONN) {
737 /*
738 * Create a socket, tpcb, ll pcb, etc.
739 * for this newborn connection, and fill in all the values.
740 */
741 IFDEBUG(D_CONN)
742 printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n",
743 so, laddr, faddr, cons_channel);
744 ENDDEBUG
745 if( (so =
746 tp_newsocket(so, faddr, cons_channel,
747 class_to_use,
a50e2bc0
KS
748 ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS :
749 (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS))
b7fb0758
KS
750 ) == (struct socket *)0 ) {
751 /* note - even if netservice is IN_CLNS, as far as
752 * the tp entity is concerned, the only differences
a50e2bc0 753 * are CO vs CL
b7fb0758
KS
754 */
755 IFDEBUG(D_CONN)
756 printf("tp_newsocket returns 0\n");
757 ENDDEBUG
758 goto discard;
759 }
760 tpcb = sototpcb(so);
761
b7fb0758 762 /*
a50e2bc0 763 * Stash the addresses in the net level pcb
b7fb0758
KS
764 * kind of like a pcbconnect() but don't need
765 * or want all those checks.
766 */
767 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, faddr, TP_FOREIGN);
768 (tpcb->tp_nlproto->nlp_putnetaddr)(so->so_pcb, laddr, TP_LOCAL);
769
a50e2bc0
KS
770 /* stash the f suffix in the new tpcb */
771 /* l suffix is already there */
a50e2bc0 772 bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen);
44f52ea5 773
a50e2bc0
KS
774 (tpcb->tp_nlproto->nlp_putsufx)
775 (so->so_pcb, fsufxloc, fsufxlen, TP_FOREIGN);
44f52ea5
KS
776 (tpcb->tp_nlproto->nlp_putsufx)
777 (so->so_pcb, lsufxloc, lsufxlen, TP_LOCAL);
b7fb0758
KS
778
779#ifdef TP_PERF_MEAS
780 if( tpcb->tp_perf_on = perf_meas ) { /* assignment */
781 /* ok, let's create an mbuf for stashing the
782 * statistics if one doesn't already exist
783 */
784 (void) tp_setup_perf(tpcb);
785 }
786#endif TP_PERF_MEAS
787 tpcb->tp_fref = sref;
788
789 /* We've already checked for consistency with the options
790 * set in tpp, but we couldn't set them earlier because
791 * we didn't want to change options in the LISTENING tpcb.
792 * Now we set the options in the new socket's tpcb.
793 */
794 (void) tp_consistency( tpcb, TP_FORCE, &tpp);
795
796 if(!tpcb->tp_use_checksum)
797 IncStat(ts_csum_off);
798 if(tpcb->tp_xpd_service)
799 IncStat(ts_use_txpd);
800 if(tpcb->tp_xtd_format)
801 IncStat(ts_xtd_fmt);
802
803 /*
804 * Get the maximum transmission unit from the lower layer(s)
805 * so we can negotiate a reasonable max TPDU size.
806 */
807 (tpcb->tp_nlproto->nlp_mtu)(so, so->so_pcb,
808 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
809 tpcb->tp_peer_acktime = acktime;
810
811 /*
812 * The following kludge is used to test retransmissions and
813 * timeout during connection establishment.
814 */
815 IFDEBUG(D_ZDREF)
816 IncStat(ts_zdebug);
a50e2bc0 817 /*tpcb->tp_fref = 0;*/
b7fb0758
KS
818 ENDDEBUG
819 }
820 IncStat(ts_CR_rcvd);
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) ,
870 E_TP_MISM_REFS,ts_inv_dref, respond,
871 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
872 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
873 E_TP_MISM_REFS,ts_inv_dref, respond,
874 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
875 CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
876 E_TP_MISM_REFS,ts_inv_dref, respond,
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
902 dusize = tpcb->tp_tpdusize;
903
904 dutype = hdr->tpdu_type << 8; /* for the switch below */
905
906 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
907
a50e2bc0 908#define caseof(x,y) case (((x)<<8)+(y))
b7fb0758
KS
909 switch( dutype | vbptr(P)->tpv_code ) {
910
911 caseof( CC_TPDU_type, TPP_addl_opt ):
912 /* not in class 0; 1 octet */
913 vb_getval(P, u_char, addlopt);
914 break;
915 caseof( CC_TPDU_type, TPP_tpdu_size ):
916 vb_getval(P, u_char, dusize);
917 CHECK( (dusize < TP_MIN_TPDUSIZE || dusize >
918 TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond,
919 (1 + (caddr_t)&vbptr(P)->tpv_val - P) )
920 IFDEBUG(D_TPINPUT)
921 printf("CC dusize 0x%x\n", dusize);
922 ENDDEBUG
923 break;
924 caseof( CC_TPDU_type, TPP_calling_sufx):
925 IFDEBUG(D_TPINPUT)
926 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
927 ENDDEBUG
928 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
929 lsufxlen = vbptr(P)->tpv_len;
930 break;
931 caseof( CC_TPDU_type, TPP_acktime ):
932 /* class 4 only, 2 octets */
933 vb_getval(P, u_short, acktime);
934 acktime = acktime/500; /* convert to slowtimo ticks */
935 if( (short)acktime <=0 )
936 acktime = 2;
937 break;
938 caseof( CC_TPDU_type, TPP_called_sufx):
939 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
940 fsufxlen = vbptr(P)->tpv_len;
941 IFDEBUG(D_TPINPUT)
942 printf("CC called (foreign) sufx len %d\n", fsufxlen);
943 ENDDEBUG
944 break;
945
946 caseof( CC_TPDU_type, TPP_checksum):
947 caseof( DR_TPDU_type, TPP_checksum):
948 caseof( DT_TPDU_type, TPP_checksum):
949 caseof( XPD_TPDU_type, TPP_checksum):
950 if( tpcb->tp_use_checksum ) {
951 CHECK( iso_check_csum(m, tpdu_len),
952 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
953 }
954 break;
955
956 /* this is different from the above because in the context
957 * of concat/ sep tpdu_len might not be the same as hdr len
958 */
959 caseof( AK_TPDU_type, TPP_checksum):
960 caseof( XAK_TPDU_type, TPP_checksum):
961 caseof( DC_TPDU_type, TPP_checksum):
962 if( tpcb->tp_use_checksum ) {
a50e2bc0 963 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
b7fb0758
KS
964 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
965 }
966 break;
967#ifdef notdef
968 caseof( DR_TPDU_type, TPP_addl_info ):
969 /* ignore - its length and meaning are
970 * user defined and there's no way
971 * to pass this info to the user anyway
972 */
973 break;
974#endif notdef
975
976 caseof( AK_TPDU_type, TPP_subseq ):
977 /* used after reduction of window */
978 vb_getval(P, u_short, subseq);
979 subseq = ntohs(subseq);
980 IFDEBUG(D_ACKRECV)
981 printf("AK Subsequence # 0x%x\n", subseq);
982 ENDDEBUG
983 break;
984
985 caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
986 {
987 u_int ylwe;
988 u_short ysubseq, ycredit;
989
990 fcc_present = TRUE;
991 vb_getval(P, u_int, ylwe);
992 vb_getval(P, u_short, ysubseq);
993 vb_getval(P, u_short, ycredit);
994 ylwe = ntohl(ylwe);
995 ysubseq = ntohs(ysubseq);
996 ycredit = ntohs(ycredit);
997 IFDEBUG(D_ACKRECV)
998 printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
999 ylwe, ysubseq, ycredit);
1000 ENDDEBUG
1001 }
1002 break;
1003
1004 default:
1005 IFDEBUG(D_TPINPUT)
1006 printf("param ignored dutype 0x%x, code 0x%x\n",
1007 dutype, vbptr(P)->tpv_code);
1008 ENDDEBUG
1009 IFTRACE(D_TPINPUT)
1010 tptrace(TPPTmisc, "param ignored dutype code ",
1011 dutype, vbptr(P)->tpv_code ,0,0);
1012 ENDTRACE
1013 IncStat(ts_param_ignored);
1014 break;
1015#undef caseof
1016 }
1017 /* } */ END_WHILE_OPTIONS(P)
1018
1019 /* NOTE: the variable dutype has been shifted left! */
1020
1021 switch( hdr->tpdu_type ) {
1022 case CC_TPDU_type:
1023 /* If CC comes back with an unacceptable class
1024 * respond with a DR or ER
1025 */
1026
1027 opt = hdr->tpdu_CCoptions; /* 1 byte */
1028
1029 {
1030 tpp = tpcb->_tp_param;
1031 tpp.p_class = (1<<hdr->tpdu_CCclass);
1032 tpp.p_tpdusize = dusize;
1033 tpp.p_dont_change_params = 0;
1034 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1035 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1036 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1037#ifdef notdef
1038 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1039 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1040 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
1041#endif notdef
1042
1043 CHECK(
1044 tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1045 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1046 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1047 /* ^ more or less the location of class */
1048 )
1049 IFTRACE(D_CONN)
1050 tptrace(TPPTmisc,
1051 "after 1 consist class, out, tpconsout",
1052 tpcb->tp_class, dgout_routine, tpcons_output, 0
1053 );
1054 ENDTRACE
1055 CHECK(
1056 ((class_to_use == TP_CLASS_0)&&
1057 (dgout_routine != tpcons_output)),
1058 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1059 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1060 /* ^ more or less the location of class */
1061 )
1062 }
1063 if( ! tpcb->tp_use_checksum)
1064 IncStat(ts_csum_off);
1065 if(tpcb->tp_xpd_service)
1066 IncStat(ts_use_txpd);
1067 if(tpcb->tp_xtd_format)
1068 IncStat(ts_xtd_fmt);
1069
1070 IFTRACE(D_CONN)
1071 tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1072 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1073 hdr->tpdu_CCclass);
1074 ENDTRACE
1075
1076 /*
1077 * Get the maximum transmission unit from the lower layer(s)
1078 * so we can decide how large a TPDU size to negotiate.
1079 * It would be nice if the arguments to this
1080 * were more reasonable.
1081 */
1082 (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
1083 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
1084
1085#ifdef CONS
1086 /* Could be that this CC came in on a NEW vc, in which case
1087 * we have to confirm it.
1088 */
1089 if( cons_channel )
1090 cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
1091 tpcb->tp_class == TP_CLASS_4);
1092#endif CONS
1093
1094 tpcb->tp_peer_acktime = acktime;
1095
1096 /* if called or calling suffices appeared on the CC,
1097 * they'd better jive with what's in the pcb
1098 */
1099 if( fsufxlen ) {
1100 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
1101 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1102 E_TP_INV_PVAL,ts_inv_sufx, respond,
1103 (1+fsufxloc - (caddr_t)hdr))
1104 }
1105 if( lsufxlen ) {
1106 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
1107 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1108 E_TP_INV_PVAL,ts_inv_sufx, respond,
1109 (1+lsufxloc - (caddr_t)hdr))
1110 }
1111
1112#ifdef notdef
1113 e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref;
1114#else
1115 e.ATTR(CC_TPDU).e_sref = sref;
1116#endif notdef
1117 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt;
1118 takes_data = TRUE;
1119 e.ev_number = CC_TPDU;
1120 IncStat(ts_CC_rcvd);
1121 break;
1122
1123 case DC_TPDU_type:
1124#ifdef notdef
1125 if (hdr->tpdu_DCsref != tpcb->tp_fref)
1126 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1127 hdr->tpdu_DCsref, tpcb->tp_fref);
1128#else
1129 if (sref != tpcb->tp_fref)
1130 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1131 sref, tpcb->tp_fref);
1132#endif notdef
1133
1134#ifdef notdef
1135 CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref),
1136 E_TP_MISM_REFS, ts_inv_sufx, respond,
1137 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1138#else
1139 CHECK( (sref != tpcb->tp_fref),
1140 E_TP_MISM_REFS, ts_inv_sufx, respond,
1141 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1142#endif notdef
1143 e.ev_number = DC_TPDU;
1144 IncStat(ts_DC_rcvd);
1145 break;
1146
1147 case DR_TPDU_type:
1148 IFTRACE(D_TPINPUT)
1149 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1150 ENDTRACE
1151#ifdef vax
1152 if(sref != tpcb->tp_fref)
1153 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1154 sref, tpcb->tp_fref);
1155
1156 CHECK( (sref != tpcb->tp_fref),
1157 E_TP_MISM_REFS,ts_inv_sufx, respond,
1158 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1159
1160 e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason;
1161 e.ATTR(DR_TPDU).e_sref = (u_short)sref;
1162#else
1163 if(hdr->tpdu_DRsref != tpcb->tp_fref)
1164 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1165 hdr->tpdu_DRsref, tpcb->tp_fref);
1166
1167 CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref),
1168 E_TP_MISM_REFS,ts_inv_sufx, respond,
1169 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1170
1171 e.ATTR(DR_TPDU).e_reason =
1172 hdr->tpdu_DRreason;
1173 e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref;
1174#endif vax
1175 takes_data = TRUE;
1176 e.ev_number = DR_TPDU;
1177 IncStat(ts_DR_rcvd);
1178 break;
1179
1180 case ER_TPDU_type:
1181 IFTRACE(D_TPINPUT)
1182 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
1183 ENDTRACE
1184 e.ev_number = ER_TPDU;
1185 e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
1186 IncStat(ts_ER_rcvd);
1187 break;
1188
1189 case AK_TPDU_type:
1190
1191 e.ATTR(AK_TPDU).e_subseq = subseq;
1192 e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
1193
1194 if (tpcb->tp_xtd_format) {
1195#ifdef BYTE_ORDER
1196 union seq_type seqeotX;
1197
1198 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1199 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
1200 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1201#else
1202 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
1203 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
1204#endif BYTE_ORDER
1205 } else {
1206 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
1207 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
1208 }
1209 IFTRACE(D_TPINPUT)
1210 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1211 e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
1212 subseq, fcc_present);
1213 ENDTRACE
1214
1215 e.ev_number = AK_TPDU;
1216 IncStat(ts_AK_rcvd);
1217 IncPStat(tpcb, tps_AK_rcvd);
1218 break;
1219
1220 case XAK_TPDU_type:
1221 if (tpcb->tp_xtd_format) {
1222#ifdef BYTE_ORDER
1223 union seq_type seqeotX;
1224
1225 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1226 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
1227#else
1228 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
1229#endif BYTE_ORDER
1230 } else {
1231 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
1232 }
1233 e.ev_number = XAK_TPDU;
1234 IncStat(ts_XAK_rcvd);
1235 IncPStat(tpcb, tps_XAK_rcvd);
1236 break;
1237
1238 case XPD_TPDU_type:
1239 if (tpcb->tp_xtd_format) {
1240#ifdef BYTE_ORDER
1241 union seq_type seqeotX;
1242
1243 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1244 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
1245#else
1246 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
1247#endif BYTE_ORDER
1248 } else {
1249 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
1250 }
1251 takes_data = TRUE;
1252 e.ev_number = XPD_TPDU;
1253 IncStat(ts_XPD_rcvd);
1254 IncPStat(tpcb, tps_XPD_rcvd);
1255 break;
1256
1257 case DT_TPDU_type:
1258 { /* the y option will cause occasional packets to be dropped.
1259 * A little crude but it works.
1260 */
1261
1262 IFDEBUG(D_DROP)
1263 if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
1264 IncStat(ts_ydebug);
1265 goto discard;
1266 }
1267 ENDDEBUG
1268 }
1269 if (tpcb->tp_class == TP_CLASS_0) {
1270 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
1271 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
1272 } else if (tpcb->tp_xtd_format) {
1273#ifdef BYTE_ORDER
1274 union seq_type seqeotX;
1275
1276 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1277 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
1278 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
1279#else
1280 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
1281 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
1282#endif BYTE_ORDER
1283 } else {
1284 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
1285 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
1286 }
1287 if(e.ATTR(DT_TPDU).e_eot)
1288 IncStat(ts_eot_input);
1289 takes_data = TRUE;
1290 e.ev_number = DT_TPDU;
1291 IncStat(ts_DT_rcvd);
1292 IncPStat(tpcb, tps_DT_rcvd);
1293 break;
1294
1295 case GR_TPDU_type:
1296 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1297 /* drop through */
1298 default:
1299 /* this should NEVER happen because there is a
1300 * check for dutype well above here
1301 */
1302 error = E_TP_INV_TPDU; /* causes an ER */
1303 IFDEBUG(D_TPINPUT)
1304 printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1305 ENDDEBUG
1306 IncStat(ts_inv_dutype);
1307 goto respond;
1308 }
1309 }
1310
1311 /* peel off the tp header;
1312 * remember that the du_li doesn't count itself.
1313 * This may leave us w/ an empty mbuf at the front of a chain.
1314 * We can't just throw away the empty mbuf because hdr still points
1315 * into the mbuf's data area and we're still using hdr (the tpdu header)
1316 */
1317 m->m_len -= ((int)hdr->tpdu_li + 1);
a50e2bc0 1318 m->m_data += ((int)hdr->tpdu_li + 1);
b7fb0758 1319
a50e2bc0
KS
1320 if (takes_data) {
1321 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
1322 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
1323 struct tp_control_hdr c_hdr;
1324 struct mbuf *n;
b7fb0758 1325
a50e2bc0
KS
1326 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
1327 ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
b7fb0758 1328 switch( hdr->tpdu_type ) {
a50e2bc0 1329
b7fb0758 1330 case CR_TPDU_type:
a50e2bc0
KS
1331 c_hdr.cmsg_type = TPOPT_CONN_DATA;
1332 goto make_control_msg;
1333
b7fb0758 1334 case CC_TPDU_type:
a50e2bc0
KS
1335 c_hdr.cmsg_type = TPOPT_CFRM_DATA;
1336 goto make_control_msg;
1337
b7fb0758 1338 case DR_TPDU_type:
a50e2bc0
KS
1339 c_hdr.cmsg_type = TPOPT_DISC_DATA;
1340 make_control_msg:
1341 c_hdr.cmsg_level = SOL_TRANSPORT;
1342 mbtype = MT_CONTROL;
1343 if (datalen > 0) {
1344 datalen += sizeof(c_hdr);
1345 m->m_len += sizeof(c_hdr);
1346 m->m_data -= sizeof(c_hdr);
1347 c_hdr.cmsg_len = datalen;
1348 bcopy((caddr_t)&c_hdr, mtod(m, caddr_t),
1349 sizeof(c_hdr));
1350 }
1351 /* FALLTHROUGH */
1352
b7fb0758 1353 case XPD_TPDU_type:
a50e2bc0
KS
1354 if (mbtype != MT_CONTROL)
1355 mbtype = MT_OOBDATA;
1356 m->m_flags |= M_EOR;
1357 /* FALLTHROUGH */
b7fb0758 1358
a50e2bc0
KS
1359 case DT_TPDU_type:
1360 for (n = m; n; n = n->m_next) {
1361 MCHTYPE(n, mbtype);
1362 }
1363 e.ATTR(DT_TPDU).e_datalen = datalen;
b7fb0758
KS
1364 e.ATTR(DT_TPDU).e_data = m;
1365 break;
1366
1367 default:
1368 printf(
1369 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1370 hdr->tpdu_type, takes_data, m);
1371 break;
1372 }
1373 /* prevent m_freem() after tp_driver() from throwing it all away */
1374 m = MNULL;
1375 }
1376
1377 IncStat(ts_tpdu_rcvd);
1378
1379 IFDEBUG(D_TPINPUT)
1380 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1381 tpcb->tp_state, e.ev_number, m );
1382 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
1383 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1384 takes_data, (m==MNULL)?0:m->m_len, tpdu_len);
1385 ENDDEBUG
1386
1387 if( tpcb->tp_decbit != 0 ) /* unsigned 4 bits */
1388 tpcb->tp_decbit --;
1389
1390 error = tp_driver(tpcb, &e);
1391
1392 ASSERT(tpcb != (struct tp_pcb *)0);
1393 ASSERT(tpcb->tp_sock != (struct socket *)0);
1394 if( tpcb->tp_sock->so_error == 0 )
1395 tpcb->tp_sock->so_error = error;
1396
1397 /* Kludge to keep the state tables under control (adding
1398 * data on connect & disconnect & freeing the mbuf containing
1399 * the data would have exploded the tables and made a big mess ).
1400 */
1401 switch(e.ev_number) {
1402 case CC_TPDU:
1403 case DR_TPDU:
1404 case CR_TPDU:
1405 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
1406 IFDEBUG(D_TPINPUT)
1407 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1408 m, takes_data);
1409 ENDDEBUG
1410 break;
1411 default:
1412 break;
1413 }
1414 /* Concatenated sequences are terminated by any tpdu that
1415 * carries data: CR, CC, DT, XPD, DR.
1416 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1417 */
1418
1419separate:
1420 if ( takes_data == 0 ) {
1421 ASSERT( m != MNULL );
1422 /*
1423 * we already peeled off the prev. tp header so
1424 * we can just pull up some more and repeat
1425 */
1426
a50e2bc0 1427 if( m = tp_inputprep(m) ) {
b7fb0758
KS
1428 IFDEBUG(D_TPINPUT)
1429 hdr = mtod(m, struct tpdu *);
1430 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1431 hdr, (int) hdr->tpdu_li + 1, m);
1432 dump_mbuf(m, "tp_input after driver, at separate");
1433 ENDDEBUG
1434
b7fb0758
KS
1435 IncStat(ts_concat_rcvd);
1436 goto again;
1437 }
1438 }
1439 if ( m != MNULL ) {
1440 IFDEBUG(D_TPINPUT)
1441 printf("tp_input : m_freem(0x%x)\n", m);
1442 ENDDEBUG
1443 m_freem(m);
1444 IFDEBUG(D_TPINPUT)
1445 printf("tp_input : after m_freem 0x%x\n", m);
1446 ENDDEBUG
1447 }
1448 return (ProtoHook) tpcb;
1449
1450discard:
1451 /* class 4: drop the tpdu */
1452 /* class 2,0: Should drop the net connection, if you can figure out
1453 * to which connection it applies
1454 */
1455 IFDEBUG(D_TPINPUT)
1456 printf("tp_input DISCARD\n");
1457 ENDDEBUG
1458 IFTRACE(D_TPINPUT)
1459 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0);
1460 ENDTRACE
1461 m_freem(m);
1462 IncStat(ts_recv_drop);
1463 return (ProtoHook)0;
1464
1465respond:
1466 IFDEBUG(D_ERROR_EMIT)
1467 printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc);
1468 ENDDEBUG
1469 IFTRACE(D_TPINPUT)
1470 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0);
1471 ENDTRACE
1472 if( sref == 0 )
1473 goto discard;
a50e2bc0
KS
1474 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
1475 (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb,
1476 (int)cons_channel, dgout_routine);
b7fb0758
KS
1477 IFDEBUG(D_ERROR_EMIT)
1478 printf("tp_input after error_emit\n");
1479 ENDDEBUG
1480
1481#ifdef lint
1482 printf("",sref,opt);
1483#endif lint
1484 IncStat(ts_recv_drop);
1485 return (ProtoHook)0;
1486}
1487
1488
1489/*
1490 * NAME: tp_headersize()
1491 *
1492 * CALLED FROM:
1493 * tp_emit() and tp_sbsend()
1494 * TP needs to know the header size so it can figure out how
1495 * much data to put in each tpdu.
1496 *
1497 * FUNCTION, ARGUMENTS, and RETURN VALUE:
1498 * For a given connection, represented by (tpcb), and
1499 * tpdu type (dutype), return the size of a tp header.
1500 *
1501 * RETURNS: the expected size of the heade in bytesr
1502 *
1503 * SIDE EFFECTS:
1504 *
1505 * NOTES: It would be nice if it got the network header size as well.
1506 */
1507int
1508tp_headersize(dutype, tpcb)
1509 int dutype;
1510 struct tp_pcb *tpcb;
1511{
1512 register int size = 0;
1513
1514 IFTRACE(D_CONN)
1515 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1516 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1517 ENDTRACE
1518 if( !( (tpcb->tp_class == TP_CLASS_0) ||
1519 (tpcb->tp_class == TP_CLASS_4) ||
1520 (dutype == DR_TPDU_type) ||
1521 (dutype == CR_TPDU_type) )) {
1522 printf("tp_headersize:dutype 0x%x, class 0x%x",
1523 dutype, tpcb->tp_class);
1524 /* TODO: identify this and GET RID OF IT */
1525 }
1526 ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
1527 (tpcb->tp_class == TP_CLASS_4) ||
1528 (dutype == DR_TPDU_type) ||
1529 (dutype == CR_TPDU_type) );
1530
1531 if( tpcb->tp_class == TP_CLASS_0 ) {
1532 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
1533 } else {
1534 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
1535 }
1536 return size;
1537 /* caller must get network level header size separately */
1538}