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