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