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