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