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