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