|
|
1.1 root 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
23: static char *rcsid = "$Header/**/$";
24: #endif lint
25: #define _XEBEC_PG static
26:
27: #include "tp_states.h"
28:
29: static 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:
61: static trick_hc = 1;
62:
63: int tp_emit(),
64: tp_goodack(), tp_goodXack(),
65: tp_stash()
66: ;
67: void 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:
80: typedef struct tp_pcb tpcb_struct;
81:
82:
83:
84: typedef tpcb_struct tp_PCB_;
85:
86: #include "tp_events.h"
87:
88: _XEBEC_PG int _Xebec_action(a,e,p)
89: int a;
90: struct tp_event *e;
91: tp_PCB_ *p;
92: {
93: switch(a) {
94: case -1: return tp_protocol_error(e,p);
95: case 0x1:
96: {
97: (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL);
98: }
99: break;
100: case 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;
108: case 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;
118: case 0x4:
119: {
120: tp_detach(p);
121: }
122: break;
123: case 0x5:
124: {
125: p->tp_refstate = REF_OPEN; /* has timers ??? */
126: }
127: break;
128: case 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;
147: case 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;
161: case 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;
178: case 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;
189: case 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;
217: case 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;
249: case 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;
258: case 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;
265: case 0xe:
266: {
267: tp_cuntimeout(p, TM_retrans);
268: tp_soisdisconnected(p);
269: }
270: break;
271: case 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;
278: case 0x10:
279: {
280: tp_cuntimeout(p, TM_retrans);
281: tp_soisdisconnected(p);
282: }
283: break;
284: case 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;
290: case 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;
298: case 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;
312: case 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;
320: case 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;
352: case 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;
376: case 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;
384: case 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;
396: case 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;
431: case 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;
441: case 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;
463: case 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;
475: case 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;
499: case 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;
530: case 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;
538: case 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;
558: case 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;
573: case 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;
593: case 0x23:
594: {
595: tp_soisdisconnecting(p->tp_sock);
596: tp_netcmd( p, CONN_CLOSE);
597: tp_soisdisconnected(p);
598: }
599: break;
600: case 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;
625: case 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;
639: case 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;
650: case 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;
665: case 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;
689: case 0x29:
690: {
691: p->tp_rxtshift++;
692: (void) tp_data_retrans(p);
693: }
694: break;
695: case 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;
703: case 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;
711: case 0x2c:
712: {
713: tp_freeref(p->tp_lref);
714: tp_detach(p);
715: }
716: break;
717: case 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;
727: case 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;
737: case 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;
768: case 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;
784: case 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;
801: case 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;
812: case 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;
822: case 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;
840: case 0x35:
841: {
842: if (sbspace(&p->tp_sock->so_rcv) > 0)
843: tp0_openflow(p);
844: }
845: break;
846: case 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;
868: case 0x37:
869: {
870: if(trick_hc)
871: return ECONNABORTED;
872: }
873: break;
874: case 0x38:
875: {
876: ASSERT( p->tp_state != TP_LISTENING );
877: tp_indicate(T_DISCONNECT, p, ECONNRESET);
878: tp_soisdisconnected(p);
879: }
880: break;
881: }
882: return 0;
883: }
884:
885: _XEBEC_PG int
886: _Xebec_index( e,p )
887: struct tp_event *e;
888: tp_PCB_ *p;
889: {
890: switch( (e->ev_number<<4)+(p->tp_state) ) {
891: case 0x12:
892: if ( p->tp_retrans > 0 ) return 0x1e;
893: else return 0x1f;
894: case 0x13:
895: if ( p->tp_retrans > 0 ) return 0x2f;
896: else return 0x30;
897: case 0x14:
898: if ( p->tp_retrans > 0 ) return 0x32;
899: else return 0x31;
900: case 0x15:
901: if ( p->tp_retrans > 0 ) return 0x34;
902: else return 0x35;
903: case 0x54:
904: if (p->tp_rxtshift < TP_NRETRANS) return 0x33;
905: else return 0x31;
906: case 0x64:
907: if (p->tp_class == TP_CLASS_0) return 0x1a;
908: else return 0x1b;
909: case 0x77:
910: if ( p->tp_class == TP_CLASS_0) return 0xd;
911: else return 0xe;
912: case 0x86:
913: if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2;
914: else return 0x3;
915: case 0xa2:
916: if (p->tp_class == TP_CLASS_0) return 0x1c;
917: else return 0x1d;
918: case 0xb2:
919: if (p->tp_class == TP_CLASS_0) return 0x5;
920: else return 0x0;
921: case 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;
924: case 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;
928: case 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;
933: case 0xd3:
934: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
935: else return 0x2a;
936: case 0xd4:
937: if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27;
938: else return 0x29;
939: case 0xe4:
940: if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c;
941: else return 0x3d;
942: case 0x102:
943: if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
944: else return 0x2e;
945: case 0x104:
946: if ( p->tp_class == TP_CLASS_0 ) return 0x2d;
947: else return 0x2e;
948: case 0x144:
949: if (p->tp_class == TP_CLASS_0) return 0x3f;
950: else return 0x40;
951: case 0x162:
952: if (p->tp_class == TP_CLASS_0) return 0x2b;
953: else return 0x2c;
954: case 0x172:
955: if ( p->tp_class != TP_CLASS_4 ) return 0x42;
956: else return 0x46;
957: case 0x174:
958: if ( p->tp_class != TP_CLASS_4 ) return 0x42;
959: else return 0x47;
960: case 0x177:
961: if ( p->tp_class != TP_CLASS_4 ) return 0x42;
962: else return 0x43;
963: case 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;
967: default: return 0;
968: } /* end switch */
969: } /* _Xebec_index() */
970: static 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: };
997: tp_driver(p, e)
998: register tp_PCB_ *p;
999: register 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.