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