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