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