]> git.saurik.com Git - apple/xnu.git/blame - bsd/netiso/tp_driver.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netiso / tp_driver.c
CommitLineData
1c79356b
A
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#ifndef lint
23static char *rcsid = "$Header/**/$";
24#endif lint
25#define _XEBEC_PG static
26
27#include "tp_states.h"
28
29static struct act_ent {
30 int a_newstate;
31 int a_action;
32} statetable[] = { {0,0},
33#include "tp_states.init"
34};
35
36/* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/socket.h>
40#include <sys/socketvar.h>
41#include <sys/protosw.h>
42#include <sys/mbuf.h>
43#include <sys/time.h>
44#include <sys/errno.h>
45#include <sys/ev.h>
46
47#include <netiso/tp_param.h>
48#include <netiso/tp_stat.h>
49#include <netiso/tp_pcb.h>
50#include <netiso/tp_tpdu.h>
51#include <netiso/argo_debug.h>
52#include <netiso/tp_trace.h>
53#include <netiso/iso_errno.h>
54#include <netiso/tp_seq.h>
55#include <netiso/cons.h>
56
57#define DRIVERTRACE TPPTdriver
58#define sbwakeup(sb) sowakeup(p->tp_sock, sb);
59#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0)
60
61static trick_hc = 1;
62
63int tp_emit(),
64 tp_goodack(), tp_goodXack(),
65 tp_stash()
66;
67void tp_indicate(), tp_getoptions(),
68 tp_soisdisconnecting(), tp_soisdisconnected(),
69 tp_recycle_tsuffix(),
70#ifdef TP_DEBUG_TIMERS
71 tp_etimeout(), tp_euntimeout(),
72 tp_ctimeout(), tp_cuntimeout(),
73 tp_ctimeout_MIN(),
74#endif
75 tp_freeref(), tp_detach(),
76 tp0_stash(), tp0_send(),
77 tp_netcmd(), tp_send()
78;
79
80typedef struct tp_pcb tpcb_struct;
81
82
83
84typedef tpcb_struct tp_PCB_;
85
86#include "tp_events.h"
87
88_XEBEC_PG int _Xebec_action(a,e,p)
89int a;
90struct tp_event *e;
91tp_PCB_ *p;
92{
93switch(a) {
94case -1: return tp_protocol_error(e,p);
95case 0x1:
96 {
97 (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
98 }
99 break;
100case 0x2:
101 {
102# ifdef TP_DEBUG
103 if( e->ev_number != AK_TPDU )
104 printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number);
105# endif TP_DEBUG
106 }
107 break;
108case 0x3:
109 {
110 /* oh, man is this grotesque or what? */
111 (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq);
112 /* but it's necessary because this pseudo-ack may happen
113 * before the CC arrives, but we HAVE to adjust the
114 * snduna as a result of the ack, WHENEVER it arrives
115 */
116 }
117 break;
118case 0x4:
119 {
120 tp_detach(p);
121 }
122 break;
123case 0x5:
124 {
125 p->tp_refstate = REF_OPEN; /* has timers ??? */
126 }
127 break;
128case 0x6:
129 {
130 IFTRACE(D_CONN)
131 tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0);
132 ENDTRACE
133 IFDEBUG(D_CONN)
134 printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data);
135 ENDDEBUG
136 p->tp_refstate = REF_OPEN; /* has timers */
137 p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt;
138
139 if (e->ev_union.EV_CR_TPDU.e_datalen > 0) {
140 /* n/a for class 0 */
141 ASSERT(p->tp_Xrcv.sb_cc == 0);
142 sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data);
143 e->ev_union.EV_CR_TPDU.e_data = MNULL;
144 }
145 }
146 break;
147case 0x7:
148 {
149 IncStat(ts_tp0_conn);
150 IFTRACE(D_CONN)
151 tptrace(TPPTmisc, "Confiming", p, 0,0,0);
152 ENDTRACE
153 IFDEBUG(D_CONN)
154 printf("Confirming connection: p" );
155 ENDDEBUG
156 soisconnected(p->tp_sock);
157 (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ;
158 p->tp_fcredit = 1;
159 }
160 break;
161case 0x8:
162 {
163 IncStat(ts_tp4_conn); /* even though not quite open */
164 IFTRACE(D_CONN)
165 tptrace(TPPTmisc, "Confiming", p, 0,0,0);
166 ENDTRACE
167 IFDEBUG(D_CONN)
168 printf("Confirming connection: p" );
169 ENDDEBUG
170 tp_getoptions(p);
171 soisconnecting(p->tp_sock);
172 if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0))
173 p->tp_cong_win = p->tp_fcredit * p->tp_l_tpdusize;
174 p->tp_retrans = p->tp_Nretrans;
175 tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks);
176 }
177 break;
178case 0x9:
179 {
180 IFDEBUG(D_CONN)
181 printf("event: CR_TPDU emit CC failed done " );
182 ENDDEBUG
183 soisdisconnected(p->tp_sock);
184 tp_recycle_tsuffix(p);
185 tp_freeref(p->tp_lref);
186 tp_detach(p);
187 }
188 break;
189case 0xa:
190 {
191 int error;
192 struct mbuf *data = MNULL;
193
194 IFTRACE(D_CONN)
195 tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags,
196 p->tp_ucddata, 0, 0);
197 ENDTRACE
198 data = MCPY(p->tp_ucddata, M_WAIT);
199 if (data) {
200 IFDEBUG(D_CONN)
201 printf("T_CONN_req.trans m_copy cc 0x%x\n",
202 p->tp_ucddata);
203 dump_mbuf(data, "sosnd @ T_CONN_req");
204 ENDDEBUG
205 }
206
207 if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) )
208 return error; /* driver WON'T change state; will return error */
209
210 p->tp_refstate = REF_OPEN; /* has timers */
211 if(p->tp_class != TP_CLASS_0) {
212 p->tp_retrans = p->tp_Nretrans;
213 tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks);
214 }
215 }
216 break;
217case 0xb:
218 {
219 sbflush(&p->tp_Xrcv); /* purge non-delivered data data */
220 if (e->ev_union.EV_DR_TPDU.e_datalen > 0) {
221 sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data);
222 e->ev_union.EV_DR_TPDU.e_data = MNULL;
223 }
224 if (p->tp_state == TP_OPEN)
225 tp_indicate(T_DISCONNECT, p, 0);
226 else {
227 int so_error = ECONNREFUSED;
228 if (e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) &&
229 e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) &&
230 e->ev_union.EV_DR_TPDU.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK))
231 so_error = ECONNABORTED;
232 tp_indicate(T_DISCONNECT, p, so_error);
233 }
234 tp_soisdisconnected(p);
235 if (p->tp_class != TP_CLASS_0) {
236 if (p->tp_state == TP_OPEN ) {
237 tp_euntimeout(p, TM_data_retrans); /* all */
238 tp_cuntimeout(p, TM_retrans);
239 tp_cuntimeout(p, TM_inact);
240 tp_cuntimeout(p, TM_sendack);
241 p->tp_flags &= ~TPF_DELACK;
242 }
243 tp_cuntimeout(p, TM_retrans);
244 if( e->ev_union.EV_DR_TPDU.e_sref != 0 )
245 (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
246 }
247 }
248 break;
249case 0xc:
250 {
251 if( e->ev_union.EV_DR_TPDU.e_sref != 0 )
252 (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
253 /* reference timer already set - reset it to be safe (???) */
254 tp_euntimeout(p, TM_reference); /* all */
255 tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks);
256 }
257 break;
258case 0xd:
259 {
260 tp_cuntimeout(p, TM_retrans);
261 tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
262 tp_soisdisconnected(p);
263 }
264 break;
265case 0xe:
266 {
267 tp_cuntimeout(p, TM_retrans);
268 tp_soisdisconnected(p);
269 }
270 break;
271case 0xf:
272 {
273 tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
274 tp_cuntimeout(p, TM_retrans);
275 tp_soisdisconnected(p);
276 }
277 break;
278case 0x10:
279 {
280 tp_cuntimeout(p, TM_retrans);
281 tp_soisdisconnected(p);
282 }
283 break;
284case 0x11:
285 { /* don't ask me why we have to do this - spec says so */
286 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL);
287 /* don't bother with retransmissions of the DR */
288 }
289 break;
290case 0x12:
291 {
292 tp_soisdisconnecting(p->tp_sock);
293 tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
294 tp_soisdisconnected(p);
295 tp_netcmd( p, CONN_CLOSE );
296 }
297 break;
298case 0x13:
299 {
300 if (p->tp_state == TP_OPEN) {
301 tp_euntimeout(p, TM_data_retrans); /* all */
302 tp_cuntimeout(p, TM_inact);
303 tp_cuntimeout(p, TM_sendack);
304 }
305 tp_soisdisconnecting(p->tp_sock);
306 tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason);
307 p->tp_retrans = p->tp_Nretrans;
308 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
309 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL);
310 }
311 break;
312case 0x14:
313 {
314 tp_cuntimeout(p, TM_retrans);
315 IncStat(ts_tp0_conn);
316 p->tp_fcredit = 1;
317 soisconnected(p->tp_sock);
318 }
319 break;
320case 0x15:
321 {
322 IFDEBUG(D_CONN)
323 printf("trans: CC_TPDU in CRSENT state flags 0x%x\n",
324 (int)p->tp_flags);
325 ENDDEBUG
326 IncStat(ts_tp4_conn);
327 p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref;
328 p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt;
329 if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0))
330 p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt * p->tp_l_tpdusize;
331 tp_getoptions(p);
332 tp_cuntimeout(p, TM_retrans);
333 if (p->tp_ucddata) {
334 IFDEBUG(D_CONN)
335 printf("dropping user connect data cc 0x%x\n",
336 p->tp_ucddata->m_len);
337 ENDDEBUG
338 m_freem(p->tp_ucddata);
339 p->tp_ucddata = 0;
340 }
341 soisconnected(p->tp_sock);
342 if (e->ev_union.EV_CC_TPDU.e_datalen > 0) {
343 ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */
344 sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data);
345 e->ev_union.EV_CC_TPDU.e_data = MNULL;
346 }
347
348 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
349 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
350 }
351 break;
352case 0x16:
353 {
354 struct mbuf *data = MNULL;
355 int error;
356
357 IncStat(ts_retrans_cr);
358 p->tp_cong_win = 1 * p->tp_l_tpdusize;
359 data = MCPY(p->tp_ucddata, M_NOWAIT);
360 if(p->tp_ucddata) {
361 IFDEBUG(D_CONN)
362 printf("TM_retrans.trans m_copy cc 0x%x\n", data);
363 dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans");
364 ENDDEBUG
365 if( data == MNULL )
366 return ENOBUFS;
367 }
368
369 p->tp_retrans --;
370 if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) {
371 p->tp_sock->so_error = error;
372 }
373 tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks);
374 }
375 break;
376case 0x17:
377 {
378 IncStat(ts_conn_gaveup);
379 p->tp_sock->so_error = ETIMEDOUT;
380 tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
381 tp_soisdisconnected(p);
382 }
383 break;
384case 0x18:
385 {
386 int error;
387 struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
388
389 if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) {
390 p->tp_sock->so_error = error;
391 }
392 p->tp_retrans = p->tp_Nretrans;
393 tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks);
394 }
395 break;
396case 0x19:
397 {
398 int doack;
399
400 /*
401 * Get rid of any confirm or connect data, so that if we
402 * crash or close, it isn't thought of as disconnect data.
403 */
404 if (p->tp_ucddata) {
405 m_freem(p->tp_ucddata);
406 p->tp_ucddata = 0;
407 }
408 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
409 tp_cuntimeout(p, TM_retrans);
410 soisconnected(p->tp_sock);
411 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
412
413 /* see also next 2 transitions, if you make any changes */
414
415 doack = tp_stash(p, e);
416 IFDEBUG(D_DATA)
417 printf("tp_stash returns %d\n",doack);
418 ENDDEBUG
419
420 if (doack) {
421 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL );
422 tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks);
423 } else
424 tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks);
425
426 IFDEBUG(D_DATA)
427 printf("after stash calling sbwakeup\n");
428 ENDDEBUG
429 }
430 break;
431case 0x1a:
432 {
433 tp0_stash(p, e);
434 sbwakeup( &p->tp_sock->so_rcv );
435
436 IFDEBUG(D_DATA)
437 printf("after stash calling sbwakeup\n");
438 ENDDEBUG
439 }
440 break;
441case 0x1b:
442 {
443 int doack; /* tells if we must ack immediately */
444
445 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
446 sbwakeup( &p->tp_sock->so_rcv );
447
448 doack = tp_stash(p, e);
449 IFDEBUG(D_DATA)
450 printf("tp_stash returns %d\n",doack);
451 ENDDEBUG
452
453 if(doack)
454 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL );
455 else
456 tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks);
457
458 IFDEBUG(D_DATA)
459 printf("after stash calling sbwakeup\n");
460 ENDDEBUG
461 }
462 break;
463case 0x1c:
464 {
465 IFTRACE(D_DATA)
466 tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ",
467 e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0);
468 ENDTRACE
469 IncStat(ts_dt_niw);
470 m_freem(e->ev_union.EV_DT_TPDU.e_data);
471 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
472 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL );
473 }
474 break;
475case 0x1d:
476 {
477 if (p->tp_ucddata) {
478 m_freem(p->tp_ucddata);
479 p->tp_ucddata = 0;
480 }
481 (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq);
482 tp_cuntimeout(p, TM_retrans);
483
484 soisconnected(p->tp_sock);
485 IFTRACE(D_CONN)
486 struct socket *so = p->tp_sock;
487 tptrace(TPPTmisc,
488 "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags",
489 so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags);
490 tptrace(TPPTmisc,
491 "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head",
492 so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head);
493 ENDTRACE
494
495 tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks);
496 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
497 }
498 break;
499case 0x1e:
500 {
501 if( p->tp_state == TP_AKWAIT ) {
502 if (p->tp_ucddata) {
503 m_freem(p->tp_ucddata);
504 p->tp_ucddata = 0;
505 }
506 tp_cuntimeout(p, TM_retrans);
507 soisconnected(p->tp_sock);
508 tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks);
509 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
510 }
511 IFTRACE(D_XPD)
512 tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n",
513 p->tp_Xrcvnxt,e->ev_union.EV_XPD_TPDU.e_seq, e->ev_union.EV_XPD_TPDU.e_datalen, e->ev_union.EV_XPD_TPDU.e_data->m_len);
514 ENDTRACE
515
516 p->tp_sock->so_state |= SS_RCVATMARK;
517 postevent(p->tp_sock, 0, EV_OOB);
518 e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR;
519 sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data);
520 IFDEBUG(D_XPD)
521 dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv");
522 ENDDEBUG
523 tp_indicate(T_XDATA, p, 0);
524 sbwakeup( &p->tp_Xrcv );
525
526 (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL);
527 SEQ_INC(p, p->tp_Xrcvnxt);
528 }
529 break;
530case 0x1f:
531 {
532 if( p->tp_Xrcv.sb_cc == 0 ) {
533 /* kludge for select(): */
534 /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */
535 }
536 }
537 break;
538case 0x20:
539 {
540 IFTRACE(D_XPD)
541 tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n",
542 p->tp_Xrcvnxt, e->ev_union.EV_XPD_TPDU.e_seq, p->tp_Xrcv.sb_cc , 0);
543 ENDTRACE
544 if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq )
545 IncStat(ts_xpd_niw);
546 if( p->tp_Xrcv.sb_cc ) {
547 /* might as well kick 'em again */
548 tp_indicate(T_XDATA, p, 0);
549 IncStat(ts_xpd_dup);
550 }
551 m_freem(e->ev_union.EV_XPD_TPDU.e_data);
552 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
553 /* don't send an xack because the xak gives "last one received", not
554 * "next one i expect" (dumb)
555 */
556 }
557 break;
558case 0x21:
559 {
560 struct socket *so = p->tp_sock;
561
562 /* detach from parent socket so it can finish closing */
563 if (so->so_head) {
564 if (!soqremque(so, 0) && !soqremque(so, 1))
565 panic("tp: T_DETACH");
566 so->so_head = 0;
567 }
568 tp_soisdisconnecting(p->tp_sock);
569 tp_netcmd( p, CONN_CLOSE);
570 tp_soisdisconnected(p);
571 }
572 break;
573case 0x22:
574 {
575 struct socket *so = p->tp_sock;
576 struct mbuf *data = MNULL;
577
578 /* detach from parent socket so it can finish closing */
579 if (so->so_head) {
580 if (!soqremque(so, 0) && !soqremque(so, 1))
581 panic("tp: T_DETACH");
582 so->so_head = 0;
583 }
584 if (p->tp_state != TP_CLOSING) {
585 tp_soisdisconnecting(p->tp_sock);
586 data = MCPY(p->tp_ucddata, M_NOWAIT);
587 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NORMAL_DISC, data);
588 p->tp_retrans = p->tp_Nretrans;
589 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
590 }
591 }
592 break;
593case 0x23:
594 {
595 tp_soisdisconnecting(p->tp_sock);
596 tp_netcmd( p, CONN_CLOSE);
597 tp_soisdisconnected(p);
598 }
599 break;
600case 0x24:
601 {
602 struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
603
604 if(p->tp_state == TP_OPEN) {
605 tp_euntimeout(p, TM_data_retrans); /* all */
606 tp_cuntimeout(p, TM_inact);
607 tp_cuntimeout(p, TM_sendack);
608 p->tp_flags &= ~TPF_DELACK;
609 }
610 if (data) {
611 IFDEBUG(D_CONN)
612 printf("T_DISC_req.trans tp_ucddata 0x%x\n",
613 p->tp_ucddata);
614 dump_mbuf(data, "ucddata @ T_DISC_req");
615 ENDDEBUG
616 }
617 tp_soisdisconnecting(p->tp_sock);
618 p->tp_retrans = p->tp_Nretrans;
619 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
620
621 if( trick_hc )
622 return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data);
623 }
624 break;
625case 0x25:
626 {
627 int error;
628 struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT);
629
630 IncStat(ts_retrans_cc);
631 p->tp_retrans --;
632 p->tp_cong_win = 1 * p->tp_l_tpdusize;
633
634 if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) )
635 p->tp_sock->so_error = error;
636 tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks);
637 }
638 break;
639case 0x26:
640 {
641 IncStat(ts_conn_gaveup);
642 tp_soisdisconnecting(p->tp_sock);
643 p->tp_sock->so_error = ETIMEDOUT;
644 tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
645 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST, MNULL);
646 p->tp_retrans = p->tp_Nretrans;
647 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
648 }
649 break;
650case 0x27:
651 {
652 tp_euntimeout(p, TM_data_retrans); /* all */
653 tp_cuntimeout(p, TM_inact);
654 tp_cuntimeout(p, TM_sendack);
655
656 IncStat(ts_conn_gaveup);
657 tp_soisdisconnecting(p->tp_sock);
658 p->tp_sock->so_error = ETIMEDOUT;
659 tp_indicate(T_DISCONNECT, p, ETIMEDOUT);
660 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST_2, MNULL);
661 p->tp_retrans = p->tp_Nretrans;
662 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
663 }
664 break;
665case 0x28:
666 {
667 p->tp_cong_win = 1 * p->tp_l_tpdusize;
668 /* resume XPD */
669 if ( p->tp_Xsnd.sb_mb ) {
670 struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc);
671 int shift;
672
673 IFTRACE(D_XPD)
674 tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna",
675 p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt,
676 p->tp_snduna);
677 ENDTRACE
678 IFDEBUG(D_XPD)
679 dump_mbuf(m, "XPD retrans emitting M");
680 ENDDEBUG
681 IncStat(ts_retrans_xpd);
682 p->tp_retrans --;
683 shift = max(p->tp_Nretrans - p->tp_retrans, 6);
684 (void) tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m);
685 tp_ctimeout(p, TM_retrans, ((int)p->tp_dt_ticks) << shift);
686 }
687 }
688 break;
689case 0x29:
690 {
691 p->tp_rxtshift++;
692 (void) tp_data_retrans(p);
693 }
694 break;
695case 0x2a:
696 {
697 p->tp_retrans --;
698 (void) tp_emit(DR_TPDU_type, p, 0, E_TP_DR_NO_REAS, MNULL);
699 IncStat(ts_retrans_dr);
700 tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks);
701 }
702 break;
703case 0x2b:
704 {
705 p->tp_sock->so_error = ETIMEDOUT;
706 p->tp_refstate = REF_FROZEN;
707 tp_recycle_tsuffix( p );
708 tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks);
709 }
710 break;
711case 0x2c:
712 {
713 tp_freeref(p->tp_lref);
714 tp_detach(p);
715 }
716 break;
717case 0x2d:
718 {
719 if( p->tp_class != TP_CLASS_0) {
720 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
721 if ( e->ev_number == CC_TPDU )
722 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
723 }
724 /* ignore it if class 0 - state tables are blank for this */
725 }
726 break;
727case 0x2e:
728 {
729 IFTRACE(D_DATA)
730 tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb",
731 p->tp_sndnxt, p->tp_snduna, p->tp_fcredit, p);
732 ENDTRACE
733
734 tp_send(p);
735 }
736 break;
737case 0x2f:
738 {
739 int error = 0;
740
741 /* resume XPD */
742 if ( p->tp_Xsnd.sb_mb ) {
743 struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc);
744 /* m_copy doesn't preserve the m_xlink field, but at this pt.
745 * that doesn't matter
746 */
747
748 IFTRACE(D_XPD)
749 tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna",
750 p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt,
751 p->tp_snduna);
752 ENDTRACE
753 IFDEBUG(D_XPD)
754 printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc);
755 dump_mbuf(m, "XPD req emitting M");
756 ENDDEBUG
757 error =
758 tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m);
759 p->tp_retrans = p->tp_Nretrans;
760
761 tp_ctimeout(p, TM_retrans, (int)p->tp_rxtcur);
762 SEQ_INC(p, p->tp_Xsndnxt);
763 }
764 if(trick_hc)
765 return error;
766 }
767 break;
768case 0x30:
769 {
770 struct sockbuf *sb = &p->tp_sock->so_snd;
771
772 IFDEBUG(D_ACKRECV)
773 printf("GOOD ACK seq 0x%x cdt 0x%x\n", e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_cdt);
774 ENDDEBUG
775 if( p->tp_class != TP_CLASS_0) {
776 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
777 }
778 sbwakeup(sb);
779 IFDEBUG(D_ACKRECV)
780 printf("GOOD ACK new sndnxt 0x%x\n", p->tp_sndnxt);
781 ENDDEBUG
782 }
783 break;
784case 0x31:
785 {
786 IFTRACE(D_ACKRECV)
787 tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq",
788 e->ev_union.EV_AK_TPDU.e_fcc_present, p->tp_r_subseq, e->ev_union.EV_AK_TPDU.e_subseq, 0);
789 ENDTRACE
790 if( p->tp_class != TP_CLASS_0 ) {
791
792 if ( !e->ev_union.EV_AK_TPDU.e_fcc_present ) {
793 /* send ACK with FCC */
794 IncStat( ts_ackreason[_ACK_FCC_] );
795 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 1, MNULL);
796 }
797 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
798 }
799 }
800 break;
801case 0x32:
802 {
803 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
804 tp_cuntimeout(p, TM_retrans);
805
806 sbwakeup( &p->tp_sock->so_snd );
807
808 /* resume normal data */
809 tp_send(p);
810 }
811 break;
812case 0x33:
813 {
814 IFTRACE(D_ACKRECV)
815 tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0);
816 ENDTRACE
817 if( p->tp_class != TP_CLASS_0 ) {
818 tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks);
819 }
820 }
821 break;
822case 0x34:
823 {
824 int timo;
825 IFTRACE(D_TIMER)
826 tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe,
827 p->tp_sent_lcdt, 0);
828 ENDTRACE
829 IncPStat(p, tps_n_TMsendack);
830 (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
831 if (p->tp_fcredit == 0) {
832 if (p->tp_rxtshift < TP_MAXRXTSHIFT)
833 p->tp_rxtshift++;
834 timo = (p->tp_dt_ticks) << p->tp_rxtshift;
835 } else
836 timo = p->tp_sendack_ticks;
837 tp_ctimeout(p, TM_sendack, timo);
838 }
839 break;
840case 0x35:
841 {
842 if (sbspace(&p->tp_sock->so_rcv) > 0)
843 tp0_openflow(p);
844 }
845 break;
846case 0x36:
847 {
848 if( trick_hc ) {
849 SeqNum ack_thresh;
850 /*
851 * If the upper window edge has advanced a reasonable
852 * amount beyond what was known, send an ACK.
853 * A reasonable amount is 2 packets, unless the max window
854 * is only 1 or 2 packets, in which case we
855 * should send an ack for any advance in the upper window edge.
856 */
857 LOCAL_CREDIT(p);
858 ack_thresh = SEQ_SUB(p, p->tp_lcredit + p->tp_rcvnxt,
859 (p->tp_maxlcredit > 2 ? 2 : 1));
860 if (SEQ_GT(p, ack_thresh, p->tp_sent_uwe)) {
861 IncStat(ts_ackreason[_ACK_USRRCV_]);
862 p->tp_flags &= ~TPF_DELACK;
863 return tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL);
864 }
865 }
866 }
867 break;
868case 0x37:
869 {
870 if(trick_hc)
871 return ECONNABORTED;
872 }
873 break;
874case 0x38:
875 {
876 ASSERT( p->tp_state != TP_LISTENING );
877 tp_indicate(T_DISCONNECT, p, ECONNRESET);
878 tp_soisdisconnected(p);
879 }
880 break;
881 }
882return 0;
883}
884
885_XEBEC_PG int
886_Xebec_index( e,p )
887 struct tp_event *e;
888 tp_PCB_ *p;
889{
890switch( (e->ev_number<<4)+(p->tp_state) ) {
891case 0x12:
892 if ( p->tp_retrans > 0 ) return 0x1e;
893 else return 0x1f;
894case 0x13:
895 if ( p->tp_retrans > 0 ) return 0x2f;
896 else return 0x30;
897case 0x14:
898 if ( p->tp_retrans > 0 ) return 0x32;
899 else return 0x31;
900case 0x15:
901 if ( p->tp_retrans > 0 ) return 0x34;
902 else return 0x35;
903case 0x54:
904 if (p->tp_rxtshift < TP_NRETRANS) return 0x33;
905 else return 0x31;
906case 0x64:
907 if (p->tp_class == TP_CLASS_0) return 0x1a;
908 else return 0x1b;
909case 0x77:
910 if ( p->tp_class == TP_CLASS_0) return 0xd;
911 else return 0xe;
912case 0x86:
913 if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2;
914 else return 0x3;
915case 0xa2:
916 if (p->tp_class == TP_CLASS_0) return 0x1c;
917 else return 0x1d;
918case 0xb2:
919 if (p->tp_class == TP_CLASS_0) return 0x5;
920 else return 0x0;
921case 0xb4:
922 if ( tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq) ) return 0x3a;
923 else return 0x3b;
924case 0xc3:
925 if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq,
926 p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x21;
927 else return 0x24;
928case 0xc4:
929 if ( p->tp_class == TP_CLASS_0 ) return 0x22;
930 else if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq,
931 p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x23;
932 else return 0x25;
933case 0xd3:
934 if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
935 else return 0x2a;
936case 0xd4:
937 if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
938 else return 0x29;
939case 0xe4:
940 if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c;
941 else return 0x3d;
942case 0x102:
943 if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
944 else return 0x2e;
945case 0x104:
946 if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
947 else return 0x2e;
948case 0x144:
949 if (p->tp_class == TP_CLASS_0) return 0x3f;
950 else return 0x40;
951case 0x162:
952 if (p->tp_class == TP_CLASS_0) return 0x2b;
953 else return 0x2c;
954case 0x172:
955 if ( p->tp_class != TP_CLASS_4 ) return 0x42;
956 else return 0x46;
957case 0x174:
958 if ( p->tp_class != TP_CLASS_4 ) return 0x42;
959 else return 0x47;
960case 0x177:
961 if ( p->tp_class != TP_CLASS_4 ) return 0x42;
962 else return 0x43;
963case 0x188:
964 if ( p->tp_class == TP_CLASS_0 ) return 0xf;
965 else if (tp_emit(CC_TPDU_type, p, 0,0, MCPY(p->tp_ucddata, M_NOWAIT)) == 0) return 0x10;
966 else return 0x11;
967default: return 0;
968} /* end switch */
969} /* _Xebec_index() */
970static int inx[26][9] = { {0,0,0,0,0,0,0,0,0,},
971 {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, },
972 {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, },
973 {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, },
974 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
975 {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, },
976 {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, },
977 {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, },
978 {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, },
979 {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, },
980 {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, },
981 {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, },
982 {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, },
983 {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
984 {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, },
985 {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, },
986 {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
987 {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, },
988 {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, },
989 {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, },
990 {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, },
991 {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, },
992 {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, },
993 {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, },
994 {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, },
995 {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, },
996};
997tp_driver(p, e)
998register tp_PCB_ *p;
999register struct tp_event *e;
1000{
1001 register int index, error=0;
1002 struct act_ent *a;
1003 static struct act_ent erroraction = {0,-1};
1004
1005 index = inx[1 + e->ev_number][p->tp_state];
1006 if(index<0) index=_Xebec_index(e, p);
1007 if (index==0) {
1008 a = &erroraction;
1009 } else
1010 a = &statetable[index];
1011
1012 if(a->a_action)
1013 error = _Xebec_action( a->a_action, e, p );
1014 IFTRACE(D_DRIVER)
1015 tptrace(DRIVERTRACE, a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0);
1016 ENDTRACE
1017 if(error==0)
1018 p->tp_state = a->a_newstate;
1019 return error;
1020}