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