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