note version mismatches
[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 $
a0df93bc 32 * @(#)tp_input.c 7.8 (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;
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;
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);
20650f15
KS
821 if (!tpcb->tp_cebit_off) {
822 tpcb->tp_win_recv = tp_start_win << 8;
823 tpcb->tp_cong_sample.cs_size = 0;
824 LOCAL_CREDIT(tpcb);
825 CONG_INIT_SAMPLE(tpcb);
826 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
827 }
828 tpcb->tp_ackrcvd = 0;
b7fb0758
KS
829 } else if ( dutype == ER_TPDU_type ) {
830 /*
831 * ER TPDUs have to be recognized separately
832 * because they don't necessarily have a tpcb
833 * with them and we don't want err out looking for such
834 * a beast.
835 * We could put a bunch of little kludges in the
836 * next section of code so it would avoid references to tpcb
837 * if dutype == ER_TPDU_type but we don't want code for ERs to
838 * mess up code for data transfer.
839 */
840 IncStat(ts_ER_rcvd);
841 e.ev_number = ER_TPDU;
842 e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason;
843 takes_data = 1;
844 } else {
845 /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */
846
847 /* In the next 4 checks,
848 * _tpduf is the fixed part; add 2 to get the dref bits of
849 * the fixed part (can't take the address of a bit field)
850 */
851 if(cons_channel) {
852#if NARGOXTWENTYFIVE > 0
853 extern struct tp_pcb *cons_chan_to_tpcb();
854
855 tpcb = cons_chan_to_tpcb( cons_channel );
856 /* Problem: We may have a legit
857 * error situation yet we may or may not have
858 * a correspondence between the tpcb and the vc,
859 * e.g., TP4cr--> <no dice, respond w/ DR on vc>
860 * <--- DR
861 * Now it's up to TP to look at the tpdu and do one of:
862 * confirm(dgm)(cr), confirm(circuit)(cr), reject(cr), or
863 * nothing, if the circuit is already open (any other tpdu).
864 * Sigh.
865 */
866
867 /* I don't know about this error value */
868 CHECK( (tpcb == (struct tp_pcb *)0) ,
869 E_TP_NO_CR_ON_NC, ts_inv_dref, respond,
870 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
871#else
872 printf("tp_input(): X25 NOT CONFIGURED!!\n");
873#endif NARGOXTWENTYFIVE > 0
874
875 } else {
876
877 CHECK( ((int)dref <= 0 || dref >= N_TPREF) ,
878 E_TP_MISM_REFS,ts_inv_dref, respond,
879 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
880 CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ),
881 E_TP_MISM_REFS,ts_inv_dref, respond,
882 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
883 CHECK( (tpcb->tp_refp->tpr_state == REF_FREE),
884 E_TP_MISM_REFS,ts_inv_dref, respond,
885 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
886 }
887
888 IFDEBUG(D_TPINPUT)
889 printf("HAVE A TPCB 2: 0x%x\n", tpcb);
890 ENDDEBUG
891
892 /* causes a DR to be sent for CC; ER for all else */
893 CHECK( (tpcb->tp_refp->tpr_state == REF_FROZEN),
894 (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS),
895 ts_inv_dref, respond,
896 (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr))
897
898 IFDEBUG(D_TPINPUT)
899 printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb);
900 ENDDEBUG
901 /*
902 * At this point the state of the dref could be
903 * FROZEN: tpr_pcb == NULL, has ( reference only) timers
904 * for example, DC may arrive after the close() has detached
905 * the tpcb (e.g., if user turned off SO_LISTEN option)
906 * OPENING : a tpcb exists but no timers yet
907 * OPEN : tpcb exists & timers are outstanding
908 */
909
20650f15
KS
910 if (!tpcb->tp_cebit_off)
911 CONG_UPDATE_SAMPLE(tpcb, ce_bit);
912
b7fb0758
KS
913 dusize = tpcb->tp_tpdusize;
914
915 dutype = hdr->tpdu_type << 8; /* for the switch below */
916
917 WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */
918
a50e2bc0 919#define caseof(x,y) case (((x)<<8)+(y))
b7fb0758
KS
920 switch( dutype | vbptr(P)->tpv_code ) {
921
922 caseof( CC_TPDU_type, TPP_addl_opt ):
923 /* not in class 0; 1 octet */
924 vb_getval(P, u_char, addlopt);
925 break;
926 caseof( CC_TPDU_type, TPP_tpdu_size ):
927 vb_getval(P, u_char, dusize);
928 CHECK( (dusize < TP_MIN_TPDUSIZE || dusize >
929 TP_MAX_TPDUSIZE), E_TP_INV_PVAL, ts_inv_pval, respond,
930 (1 + (caddr_t)&vbptr(P)->tpv_val - P) )
931 IFDEBUG(D_TPINPUT)
932 printf("CC dusize 0x%x\n", dusize);
933 ENDDEBUG
934 break;
935 caseof( CC_TPDU_type, TPP_calling_sufx):
936 IFDEBUG(D_TPINPUT)
937 printf("CC calling (local) sufxlen 0x%x\n", lsufxlen);
938 ENDDEBUG
939 lsufxloc = (caddr_t) &vbptr(P)->tpv_val;
940 lsufxlen = vbptr(P)->tpv_len;
941 break;
942 caseof( CC_TPDU_type, TPP_acktime ):
943 /* class 4 only, 2 octets */
944 vb_getval(P, u_short, acktime);
945 acktime = acktime/500; /* convert to slowtimo ticks */
946 if( (short)acktime <=0 )
947 acktime = 2;
948 break;
949 caseof( CC_TPDU_type, TPP_called_sufx):
950 fsufxloc = (caddr_t) &vbptr(P)->tpv_val;
951 fsufxlen = vbptr(P)->tpv_len;
952 IFDEBUG(D_TPINPUT)
953 printf("CC called (foreign) sufx len %d\n", fsufxlen);
954 ENDDEBUG
955 break;
956
957 caseof( CC_TPDU_type, TPP_checksum):
958 caseof( DR_TPDU_type, TPP_checksum):
959 caseof( DT_TPDU_type, TPP_checksum):
960 caseof( XPD_TPDU_type, TPP_checksum):
961 if( tpcb->tp_use_checksum ) {
962 CHECK( iso_check_csum(m, tpdu_len),
963 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
964 }
965 break;
966
967 /* this is different from the above because in the context
968 * of concat/ sep tpdu_len might not be the same as hdr len
969 */
970 caseof( AK_TPDU_type, TPP_checksum):
971 caseof( XAK_TPDU_type, TPP_checksum):
972 caseof( DC_TPDU_type, TPP_checksum):
973 if( tpcb->tp_use_checksum ) {
a50e2bc0 974 CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1),
b7fb0758
KS
975 E_TP_INV_PVAL, ts_bad_csum, discard, 0)
976 }
977 break;
978#ifdef notdef
979 caseof( DR_TPDU_type, TPP_addl_info ):
980 /* ignore - its length and meaning are
981 * user defined and there's no way
982 * to pass this info to the user anyway
983 */
984 break;
985#endif notdef
986
987 caseof( AK_TPDU_type, TPP_subseq ):
988 /* used after reduction of window */
989 vb_getval(P, u_short, subseq);
990 subseq = ntohs(subseq);
991 IFDEBUG(D_ACKRECV)
992 printf("AK Subsequence # 0x%x\n", subseq);
993 ENDDEBUG
994 break;
995
996 caseof( AK_TPDU_type, TPP_flow_cntl_conf ):
997 {
998 u_int ylwe;
999 u_short ysubseq, ycredit;
1000
1001 fcc_present = TRUE;
1002 vb_getval(P, u_int, ylwe);
1003 vb_getval(P, u_short, ysubseq);
1004 vb_getval(P, u_short, ycredit);
1005 ylwe = ntohl(ylwe);
1006 ysubseq = ntohs(ysubseq);
1007 ycredit = ntohs(ycredit);
1008 IFDEBUG(D_ACKRECV)
1009 printf("AK FCC lwe 0x%x, subseq 0x%x, cdt 0x%x\n",
1010 ylwe, ysubseq, ycredit);
1011 ENDDEBUG
1012 }
1013 break;
1014
1015 default:
1016 IFDEBUG(D_TPINPUT)
1017 printf("param ignored dutype 0x%x, code 0x%x\n",
1018 dutype, vbptr(P)->tpv_code);
1019 ENDDEBUG
1020 IFTRACE(D_TPINPUT)
1021 tptrace(TPPTmisc, "param ignored dutype code ",
1022 dutype, vbptr(P)->tpv_code ,0,0);
1023 ENDTRACE
1024 IncStat(ts_param_ignored);
1025 break;
1026#undef caseof
1027 }
1028 /* } */ END_WHILE_OPTIONS(P)
1029
1030 /* NOTE: the variable dutype has been shifted left! */
1031
1032 switch( hdr->tpdu_type ) {
1033 case CC_TPDU_type:
1034 /* If CC comes back with an unacceptable class
1035 * respond with a DR or ER
1036 */
1037
1038 opt = hdr->tpdu_CCoptions; /* 1 byte */
1039
1040 {
1041 tpp = tpcb->_tp_param;
1042 tpp.p_class = (1<<hdr->tpdu_CCclass);
1043 tpp.p_tpdusize = dusize;
1044 tpp.p_dont_change_params = 0;
1045 tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT;
1046 tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD;
1047 tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0;
1048#ifdef notdef
1049 tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC;
1050 tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD;
1051 tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC;
1052#endif notdef
1053
1054 CHECK(
1055 tp_consistency(tpcb, TP_FORCE, &tpp) != 0,
1056 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1057 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1058 /* ^ more or less the location of class */
1059 )
1060 IFTRACE(D_CONN)
1061 tptrace(TPPTmisc,
1062 "after 1 consist class, out, tpconsout",
1063 tpcb->tp_class, dgout_routine, tpcons_output, 0
1064 );
1065 ENDTRACE
1066 CHECK(
1067 ((class_to_use == TP_CLASS_0)&&
1068 (dgout_routine != tpcons_output)),
1069 E_TP_NEGOT_FAILED, ts_negotfailed, respond,
1070 (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr)
1071 /* ^ more or less the location of class */
1072 )
1073 }
1074 if( ! tpcb->tp_use_checksum)
1075 IncStat(ts_csum_off);
1076 if(tpcb->tp_xpd_service)
1077 IncStat(ts_use_txpd);
1078 if(tpcb->tp_xtd_format)
1079 IncStat(ts_xtd_fmt);
1080
1081 IFTRACE(D_CONN)
1082 tptrace(TPPTmisc, "after CC class flags dusize CCclass",
1083 tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize,
1084 hdr->tpdu_CCclass);
1085 ENDTRACE
1086
1087 /*
1088 * Get the maximum transmission unit from the lower layer(s)
1089 * so we can decide how large a TPDU size to negotiate.
1090 * It would be nice if the arguments to this
1091 * were more reasonable.
1092 */
1093 (tpcb->tp_nlproto->nlp_mtu)(tpcb->tp_sock, tpcb->tp_sock->so_pcb,
1094 &tpcb->tp_l_tpdusize, &tpcb->tp_tpdusize, 0);
1095
1096#ifdef CONS
1097 /* Could be that this CC came in on a NEW vc, in which case
1098 * we have to confirm it.
1099 */
1100 if( cons_channel )
1101 cons_netcmd( CONN_CONFIRM, tpcb->tp_npcb, cons_channel,
1102 tpcb->tp_class == TP_CLASS_4);
1103#endif CONS
1104
1105 tpcb->tp_peer_acktime = acktime;
1106
1107 /* if called or calling suffices appeared on the CC,
1108 * they'd better jive with what's in the pcb
1109 */
1110 if( fsufxlen ) {
1111 CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) ||
1112 bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)),
1113 E_TP_INV_PVAL,ts_inv_sufx, respond,
1114 (1+fsufxloc - (caddr_t)hdr))
1115 }
1116 if( lsufxlen ) {
1117 CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) ||
1118 bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)),
1119 E_TP_INV_PVAL,ts_inv_sufx, respond,
1120 (1+lsufxloc - (caddr_t)hdr))
1121 }
1122
1123#ifdef notdef
1124 e.ATTR(CC_TPDU).e_sref = (u_short)hdr->tpdu_CCsref;
1125#else
1126 e.ATTR(CC_TPDU).e_sref = sref;
1127#endif notdef
1128 e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt;
1129 takes_data = TRUE;
1130 e.ev_number = CC_TPDU;
1131 IncStat(ts_CC_rcvd);
1132 break;
1133
1134 case DC_TPDU_type:
1135#ifdef notdef
1136 if (hdr->tpdu_DCsref != tpcb->tp_fref)
1137 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1138 hdr->tpdu_DCsref, tpcb->tp_fref);
1139#else
1140 if (sref != tpcb->tp_fref)
1141 printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n",
1142 sref, tpcb->tp_fref);
1143#endif notdef
1144
1145#ifdef notdef
1146 CHECK( (hdr->tpdu_DCsref != tpcb->tp_fref),
1147 E_TP_MISM_REFS, ts_inv_sufx, respond,
1148 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1149#else
1150 CHECK( (sref != tpcb->tp_fref),
1151 E_TP_MISM_REFS, ts_inv_sufx, respond,
1152 (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr))
1153#endif notdef
1154 e.ev_number = DC_TPDU;
1155 IncStat(ts_DC_rcvd);
1156 break;
1157
1158 case DR_TPDU_type:
1159 IFTRACE(D_TPINPUT)
1160 tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0);
1161 ENDTRACE
1162#ifdef vax
1163 if(sref != tpcb->tp_fref)
1164 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1165 sref, tpcb->tp_fref);
1166
1167 CHECK( (sref != 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 = hdr->tpdu_DRreason;
1172 e.ATTR(DR_TPDU).e_sref = (u_short)sref;
1173#else
1174 if(hdr->tpdu_DRsref != tpcb->tp_fref)
1175 printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n",
1176 hdr->tpdu_DRsref, tpcb->tp_fref);
1177
1178 CHECK( (hdr->tpdu_DRsref != tpcb->tp_fref),
1179 E_TP_MISM_REFS,ts_inv_sufx, respond,
1180 (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr))
1181
1182 e.ATTR(DR_TPDU).e_reason =
1183 hdr->tpdu_DRreason;
1184 e.ATTR(DR_TPDU).e_sref = (u_short)hdr->tpdu_DRsref;
1185#endif vax
1186 takes_data = TRUE;
1187 e.ev_number = DR_TPDU;
1188 IncStat(ts_DR_rcvd);
1189 break;
1190
1191 case ER_TPDU_type:
1192 IFTRACE(D_TPINPUT)
1193 tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0);
1194 ENDTRACE
1195 e.ev_number = ER_TPDU;
1196 e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason;
1197 IncStat(ts_ER_rcvd);
1198 break;
1199
1200 case AK_TPDU_type:
1201
1202 e.ATTR(AK_TPDU).e_subseq = subseq;
1203 e.ATTR(AK_TPDU).e_fcc_present = fcc_present;
1204
1205 if (tpcb->tp_xtd_format) {
1206#ifdef BYTE_ORDER
1207 union seq_type seqeotX;
1208
1209 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1210 e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq;
1211 e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX);
1212#else
1213 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX;
1214 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX;
1215#endif BYTE_ORDER
1216 } else {
1217 e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt;
1218 e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq;
1219 }
1220 IFTRACE(D_TPINPUT)
1221 tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres",
1222 e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt,
1223 subseq, fcc_present);
1224 ENDTRACE
1225
1226 e.ev_number = AK_TPDU;
1227 IncStat(ts_AK_rcvd);
1228 IncPStat(tpcb, tps_AK_rcvd);
1229 break;
1230
1231 case XAK_TPDU_type:
1232 if (tpcb->tp_xtd_format) {
1233#ifdef BYTE_ORDER
1234 union seq_type seqeotX;
1235
1236 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1237 e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq;
1238#else
1239 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX;
1240#endif BYTE_ORDER
1241 } else {
1242 e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq;
1243 }
1244 e.ev_number = XAK_TPDU;
1245 IncStat(ts_XAK_rcvd);
1246 IncPStat(tpcb, tps_XAK_rcvd);
1247 break;
1248
1249 case XPD_TPDU_type:
1250 if (tpcb->tp_xtd_format) {
1251#ifdef BYTE_ORDER
1252 union seq_type seqeotX;
1253
1254 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1255 e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq;
1256#else
1257 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX;
1258#endif BYTE_ORDER
1259 } else {
1260 e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq;
1261 }
1262 takes_data = TRUE;
1263 e.ev_number = XPD_TPDU;
1264 IncStat(ts_XPD_rcvd);
1265 IncPStat(tpcb, tps_XPD_rcvd);
1266 break;
1267
1268 case DT_TPDU_type:
1269 { /* the y option will cause occasional packets to be dropped.
1270 * A little crude but it works.
1271 */
1272
1273 IFDEBUG(D_DROP)
1274 if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) {
1275 IncStat(ts_ydebug);
1276 goto discard;
1277 }
1278 ENDDEBUG
1279 }
1280 if (tpcb->tp_class == TP_CLASS_0) {
1281 e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */
1282 e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot);
1283 } else if (tpcb->tp_xtd_format) {
1284#ifdef BYTE_ORDER
1285 union seq_type seqeotX;
1286
1287 seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX);
1288 e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq;
1289 e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot;
1290#else
1291 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX;
1292 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX;
1293#endif BYTE_ORDER
1294 } else {
1295 e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq;
1296 e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot;
1297 }
1298 if(e.ATTR(DT_TPDU).e_eot)
1299 IncStat(ts_eot_input);
1300 takes_data = TRUE;
1301 e.ev_number = DT_TPDU;
1302 IncStat(ts_DT_rcvd);
1303 IncPStat(tpcb, tps_DT_rcvd);
1304 break;
1305
1306 case GR_TPDU_type:
1307 tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED);
1308 /* drop through */
1309 default:
1310 /* this should NEVER happen because there is a
1311 * check for dutype well above here
1312 */
1313 error = E_TP_INV_TPDU; /* causes an ER */
1314 IFDEBUG(D_TPINPUT)
1315 printf("INVALID dutype 0x%x\n", hdr->tpdu_type);
1316 ENDDEBUG
1317 IncStat(ts_inv_dutype);
1318 goto respond;
1319 }
1320 }
1321
1322 /* peel off the tp header;
1323 * remember that the du_li doesn't count itself.
1324 * This may leave us w/ an empty mbuf at the front of a chain.
1325 * We can't just throw away the empty mbuf because hdr still points
1326 * into the mbuf's data area and we're still using hdr (the tpdu header)
1327 */
1328 m->m_len -= ((int)hdr->tpdu_li + 1);
a50e2bc0 1329 m->m_data += ((int)hdr->tpdu_li + 1);
b7fb0758 1330
a50e2bc0
KS
1331 if (takes_data) {
1332 int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX];
1333 int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA;
a0df93bc 1334 struct cmsghdr c_hdr;
a50e2bc0 1335 struct mbuf *n;
b7fb0758 1336
a50e2bc0
KS
1337 CHECK( (max && datalen > max), E_TP_LENGTH_INVAL,
1338 ts_inv_length, respond, (max + hdr->tpdu_li + 1) );
b7fb0758 1339 switch( hdr->tpdu_type ) {
a50e2bc0 1340
b7fb0758 1341 case CR_TPDU_type:
a50e2bc0
KS
1342 c_hdr.cmsg_type = TPOPT_CONN_DATA;
1343 goto make_control_msg;
1344
b7fb0758 1345 case CC_TPDU_type:
a50e2bc0
KS
1346 c_hdr.cmsg_type = TPOPT_CFRM_DATA;
1347 goto make_control_msg;
1348
b7fb0758 1349 case DR_TPDU_type:
a50e2bc0
KS
1350 c_hdr.cmsg_type = TPOPT_DISC_DATA;
1351 make_control_msg:
1352 c_hdr.cmsg_level = SOL_TRANSPORT;
1353 mbtype = MT_CONTROL;
76d6a813
KS
1354 datalen += sizeof(c_hdr);
1355 m->m_len += sizeof(c_hdr);
1356 m->m_data -= sizeof(c_hdr);
1357 c_hdr.cmsg_len = datalen;
1358 bcopy((caddr_t)&c_hdr, mtod(m, caddr_t), sizeof(c_hdr));
a50e2bc0
KS
1359 /* FALLTHROUGH */
1360
b7fb0758 1361 case XPD_TPDU_type:
a50e2bc0
KS
1362 if (mbtype != MT_CONTROL)
1363 mbtype = MT_OOBDATA;
1364 m->m_flags |= M_EOR;
1365 /* FALLTHROUGH */
b7fb0758 1366
a50e2bc0
KS
1367 case DT_TPDU_type:
1368 for (n = m; n; n = n->m_next) {
1369 MCHTYPE(n, mbtype);
1370 }
1371 e.ATTR(DT_TPDU).e_datalen = datalen;
b7fb0758
KS
1372 e.ATTR(DT_TPDU).e_data = m;
1373 break;
1374
1375 default:
1376 printf(
1377 "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n",
1378 hdr->tpdu_type, takes_data, m);
1379 break;
1380 }
1381 /* prevent m_freem() after tp_driver() from throwing it all away */
1382 m = MNULL;
1383 }
1384
1385 IncStat(ts_tpdu_rcvd);
1386
1387 IFDEBUG(D_TPINPUT)
1388 printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x",
1389 tpcb->tp_state, e.ev_number, m );
1390 printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data);
1391 printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n",
1392 takes_data, (m==MNULL)?0:m->m_len, tpdu_len);
1393 ENDDEBUG
1394
b7fb0758
KS
1395 error = tp_driver(tpcb, &e);
1396
1397 ASSERT(tpcb != (struct tp_pcb *)0);
1398 ASSERT(tpcb->tp_sock != (struct socket *)0);
1399 if( tpcb->tp_sock->so_error == 0 )
1400 tpcb->tp_sock->so_error = error;
1401
1402 /* Kludge to keep the state tables under control (adding
1403 * data on connect & disconnect & freeing the mbuf containing
1404 * the data would have exploded the tables and made a big mess ).
1405 */
1406 switch(e.ev_number) {
1407 case CC_TPDU:
1408 case DR_TPDU:
1409 case CR_TPDU:
1410 m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */
1411 IFDEBUG(D_TPINPUT)
1412 printf("after driver, restoring m to 0x%x, takes_data 0x%x\n",
1413 m, takes_data);
1414 ENDDEBUG
1415 break;
1416 default:
1417 break;
1418 }
1419 /* Concatenated sequences are terminated by any tpdu that
1420 * carries data: CR, CC, DT, XPD, DR.
1421 * All other tpdu types may be concatenated: AK, XAK, DC, ER.
1422 */
1423
1424separate:
1425 if ( takes_data == 0 ) {
1426 ASSERT( m != MNULL );
1427 /*
1428 * we already peeled off the prev. tp header so
1429 * we can just pull up some more and repeat
1430 */
1431
a50e2bc0 1432 if( m = tp_inputprep(m) ) {
b7fb0758
KS
1433 IFDEBUG(D_TPINPUT)
1434 hdr = mtod(m, struct tpdu *);
1435 printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n",
1436 hdr, (int) hdr->tpdu_li + 1, m);
1437 dump_mbuf(m, "tp_input after driver, at separate");
1438 ENDDEBUG
1439
b7fb0758
KS
1440 IncStat(ts_concat_rcvd);
1441 goto again;
1442 }
1443 }
1444 if ( m != MNULL ) {
1445 IFDEBUG(D_TPINPUT)
1446 printf("tp_input : m_freem(0x%x)\n", m);
1447 ENDDEBUG
1448 m_freem(m);
1449 IFDEBUG(D_TPINPUT)
1450 printf("tp_input : after m_freem 0x%x\n", m);
1451 ENDDEBUG
1452 }
1453 return (ProtoHook) tpcb;
1454
1455discard:
1456 /* class 4: drop the tpdu */
1457 /* class 2,0: Should drop the net connection, if you can figure out
1458 * to which connection it applies
1459 */
1460 IFDEBUG(D_TPINPUT)
1461 printf("tp_input DISCARD\n");
1462 ENDDEBUG
1463 IFTRACE(D_TPINPUT)
1464 tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0);
1465 ENDTRACE
1466 m_freem(m);
1467 IncStat(ts_recv_drop);
1468 return (ProtoHook)0;
1469
1470respond:
1471 IFDEBUG(D_ERROR_EMIT)
1472 printf("RESPOND: error 0x%x, errloc 0x%x\n", error, errloc);
1473 ENDDEBUG
1474 IFTRACE(D_TPINPUT)
1475 tptrace(TPPTmisc, "tp_input RESPOND m error sref", m,error,sref,0);
1476 ENDTRACE
1477 if( sref == 0 )
1478 goto discard;
a50e2bc0
KS
1479 (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr,
1480 (struct sockaddr_iso *)laddr, m, (int)errloc, tpcb,
1481 (int)cons_channel, dgout_routine);
b7fb0758
KS
1482 IFDEBUG(D_ERROR_EMIT)
1483 printf("tp_input after error_emit\n");
1484 ENDDEBUG
1485
1486#ifdef lint
1487 printf("",sref,opt);
1488#endif lint
1489 IncStat(ts_recv_drop);
1490 return (ProtoHook)0;
1491}
1492
1493
1494/*
1495 * NAME: tp_headersize()
1496 *
1497 * CALLED FROM:
1498 * tp_emit() and tp_sbsend()
1499 * TP needs to know the header size so it can figure out how
1500 * much data to put in each tpdu.
1501 *
1502 * FUNCTION, ARGUMENTS, and RETURN VALUE:
1503 * For a given connection, represented by (tpcb), and
1504 * tpdu type (dutype), return the size of a tp header.
1505 *
1506 * RETURNS: the expected size of the heade in bytesr
1507 *
1508 * SIDE EFFECTS:
1509 *
1510 * NOTES: It would be nice if it got the network header size as well.
1511 */
1512int
1513tp_headersize(dutype, tpcb)
1514 int dutype;
1515 struct tp_pcb *tpcb;
1516{
1517 register int size = 0;
1518
1519 IFTRACE(D_CONN)
1520 tptrace(TPPTmisc, "tp_headersize dutype class xtd_format",
1521 dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0);
1522 ENDTRACE
1523 if( !( (tpcb->tp_class == TP_CLASS_0) ||
1524 (tpcb->tp_class == TP_CLASS_4) ||
1525 (dutype == DR_TPDU_type) ||
1526 (dutype == CR_TPDU_type) )) {
1527 printf("tp_headersize:dutype 0x%x, class 0x%x",
1528 dutype, tpcb->tp_class);
1529 /* TODO: identify this and GET RID OF IT */
1530 }
1531 ASSERT( (tpcb->tp_class == TP_CLASS_0) ||
1532 (tpcb->tp_class == TP_CLASS_4) ||
1533 (dutype == DR_TPDU_type) ||
1534 (dutype == CR_TPDU_type) );
1535
1536 if( tpcb->tp_class == TP_CLASS_0 ) {
1537 size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX];
1538 } else {
1539 size = tpdu_info[ dutype ] [tpcb->tp_xtd_format];
1540 }
1541 return size;
1542 /* caller must get network level header size separately */
1543}