fetch.9: Minor fixes.
[dragonfly.git] / sys / netproto / atm / uni / q2110_sigcpcs.c
blob53bdebab34aa1dca4871e45da261459bf4ec96c0
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/uni/q2110_sigcpcs.c,v 1.4 2000/01/17 20:49:49 mks Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/uni/q2110_sigcpcs.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
31 * ATM Forum UNI Support
32 * ---------------------
34 * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs)
38 #include <netproto/atm/kern_include.h>
40 #include "sscop.h"
41 #include "sscop_misc.h"
42 #include "sscop_pdu.h"
43 #include "sscop_var.h"
46 * Local functions
48 static void sscop_bgn_outconn (struct sscop *, KBuffer *, caddr_t);
49 static void sscop_bgn_inconn (struct sscop *, KBuffer *, caddr_t);
50 static void sscop_bgn_ready (struct sscop *, KBuffer *, caddr_t);
51 static void sscop_bgrej_outrecov (struct sscop *, KBuffer *, caddr_t);
52 static void sscop_end_outrecov (struct sscop *, KBuffer *, caddr_t);
53 static void sscop_end_ready (struct sscop *, KBuffer *, caddr_t);
54 static void sscop_endak_outrecov (struct sscop *, KBuffer *, caddr_t);
55 static void sscop_rs_outresyn (struct sscop *, KBuffer *, caddr_t);
56 static void sscop_rs_inresyn (struct sscop *, KBuffer *, caddr_t);
57 static void sscop_rs_outrecov (struct sscop *, KBuffer *, caddr_t);
58 static void sscop_rs_ready (struct sscop *, KBuffer *, caddr_t);
59 static void sscop_er_error (struct sscop *, KBuffer *, caddr_t);
60 static void sscop_er_idle (struct sscop *, KBuffer *, caddr_t);
61 static void sscop_er_outrecov (struct sscop *, KBuffer *, caddr_t);
62 static void sscop_er_recovrsp (struct sscop *, KBuffer *, caddr_t);
63 static void sscop_er_inrecov (struct sscop *, KBuffer *, caddr_t);
64 static void sscop_er_ready (struct sscop *, KBuffer *, caddr_t);
65 static void sscop_erak_error (struct sscop *, KBuffer *, caddr_t);
66 static void sscop_erak_idle (struct sscop *, KBuffer *, caddr_t);
67 static void sscop_erak_outrecov (struct sscop *, KBuffer *, caddr_t);
68 static void sscop_sd_ready (struct sscop *, KBuffer *, caddr_t);
69 static void sscop_poll_ready (struct sscop *, KBuffer *, caddr_t);
73 * PDU type state lookup tables
75 /* BGN PDU */
76 static void (*sscop_bgn_tab[SOS_NUMSTATES])
77 (struct sscop *, KBuffer *, caddr_t) = {
78 NULL, /* SOS_INST */
79 sscop_bgn_idle, /* SOS_IDLE */
80 sscop_bgn_outconn, /* SOS_OUTCONN */
81 sscop_bgn_inconn, /* SOS_INCONN */
82 sscop_bgn_outdisc, /* SOS_OUTDISC */
83 sscop_bgn_outresyn, /* SOS_OUTRESYN */
84 sscop_bgn_inresyn, /* SOS_INRESYN */
85 sscop_bgn_inresyn, /* SOS_OUTRECOV */
86 sscop_bgn_inresyn, /* SOS_RECOVRSP */
87 sscop_bgn_inresyn, /* SOS_INRECOV */
88 sscop_bgn_ready, /* SOS_READY */
89 sscop_noop /* SOS_TERM */
92 /* BGAK PDU */
93 static void (*sscop_bgak_tab[SOS_NUMSTATES])
94 (struct sscop *, KBuffer *, caddr_t) = {
95 NULL, /* SOS_INST */
96 sscop_bgak_idle, /* SOS_IDLE */
97 sscop_bgak_outconn, /* SOS_OUTCONN */
98 sscop_bgak_error, /* SOS_INCONN */
99 sscop_noop, /* SOS_OUTDISC */
100 sscop_noop, /* SOS_OUTRESYN */
101 sscop_bgak_error, /* SOS_INRESYN */
102 sscop_bgak_error, /* SOS_OUTRECOV */
103 sscop_bgak_error, /* SOS_RECOVRSP */
104 sscop_bgak_error, /* SOS_INRECOV */
105 sscop_noop, /* SOS_READY */
106 sscop_noop /* SOS_TERM */
109 /* BGREJ PDU */
110 static void (*sscop_bgrej_tab[SOS_NUMSTATES])
111 (struct sscop *, KBuffer *, caddr_t) = {
112 NULL, /* SOS_INST */
113 sscop_bgrej_error, /* SOS_IDLE */
114 sscop_bgrej_outconn, /* SOS_OUTCONN */
115 sscop_bgrej_inconn, /* SOS_INCONN */
116 sscop_endak_outdisc, /* SOS_OUTDISC */
117 sscop_bgrej_outresyn, /* SOS_OUTRESYN */
118 sscop_bgrej_inconn, /* SOS_INRESYN */
119 sscop_bgrej_outrecov, /* SOS_OUTRECOV */
120 sscop_bgrej_inconn, /* SOS_RECOVRSP */
121 sscop_bgrej_inconn, /* SOS_INRECOV */
122 sscop_bgrej_ready, /* SOS_READY */
123 sscop_noop /* SOS_TERM */
126 /* END PDU */
127 static void (*sscop_end_tab[SOS_NUMSTATES])
128 (struct sscop *, KBuffer *, caddr_t) = {
129 NULL, /* SOS_INST */
130 sscop_end_idle, /* SOS_IDLE */
131 sscop_noop, /* SOS_OUTCONN */
132 sscop_end_inconn, /* SOS_INCONN */
133 sscop_end_outdisc, /* SOS_OUTDISC */
134 sscop_end_inconn, /* SOS_OUTRESYN */
135 sscop_end_inconn, /* SOS_INRESYN */
136 sscop_end_outrecov, /* SOS_OUTRECOV */
137 sscop_end_inconn, /* SOS_RECOVRSP */
138 sscop_end_inconn, /* SOS_INRECOV */
139 sscop_end_ready, /* SOS_READY */
140 sscop_noop /* SOS_TERM */
143 /* ENDAK PDU */
144 static void (*sscop_endak_tab[SOS_NUMSTATES])
145 (struct sscop *, KBuffer *, caddr_t) = {
146 NULL, /* SOS_INST */
147 sscop_noop, /* SOS_IDLE */
148 sscop_noop, /* SOS_OUTCONN */
149 sscop_endak_inconn, /* SOS_INCONN */
150 sscop_endak_outdisc, /* SOS_OUTDISC */
151 sscop_endak_inconn, /* SOS_OUTRESYN */
152 sscop_endak_inconn, /* SOS_INRESYN */
153 sscop_endak_outrecov, /* SOS_OUTRECOV */
154 sscop_endak_inconn, /* SOS_RECOVRSP */
155 sscop_endak_inconn, /* SOS_INRECOV */
156 sscop_endak_ready, /* SOS_READY */
157 sscop_noop /* SOS_TERM */
160 /* RS PDU */
161 static void (*sscop_rs_tab[SOS_NUMSTATES])
162 (struct sscop *, KBuffer *, caddr_t) = {
163 NULL, /* SOS_INST */
164 sscop_rs_idle, /* SOS_IDLE */
165 sscop_noop, /* SOS_OUTCONN */
166 sscop_rs_error, /* SOS_INCONN */
167 sscop_noop, /* SOS_OUTDISC */
168 sscop_rs_outresyn, /* SOS_OUTRESYN */
169 sscop_rs_inresyn, /* SOS_INRESYN */
170 sscop_rs_outrecov, /* SOS_OUTRECOV */
171 sscop_rs_outrecov, /* SOS_RECOVRSP */
172 sscop_rs_outrecov, /* SOS_INRECOV */
173 sscop_rs_ready, /* SOS_READY */
174 sscop_noop /* SOS_TERM */
177 /* RSAK PDU */
178 static void (*sscop_rsak_tab[SOS_NUMSTATES])
179 (struct sscop *, KBuffer *, caddr_t) = {
180 NULL, /* SOS_INST */
181 sscop_rsak_idle, /* SOS_IDLE */
182 sscop_noop, /* SOS_OUTCONN */
183 sscop_rsak_error, /* SOS_INCONN */
184 sscop_noop, /* SOS_OUTDISC */
185 sscop_rsak_outresyn, /* SOS_OUTRESYN */
186 sscop_rsak_error, /* SOS_INRESYN */
187 sscop_rsak_error, /* SOS_OUTRECOV */
188 sscop_rsak_error, /* SOS_RECOVRSP */
189 sscop_rsak_error, /* SOS_INRECOV */
190 sscop_noop, /* SOS_READY */
191 sscop_noop /* SOS_TERM */
194 /* ER PDU */
195 static void (*sscop_er_tab[SOS_NUMSTATES])
196 (struct sscop *, KBuffer *, caddr_t) = {
197 NULL, /* SOS_INST */
198 sscop_er_idle, /* SOS_IDLE */
199 sscop_noop, /* SOS_OUTCONN */
200 sscop_er_error, /* SOS_INCONN */
201 sscop_noop, /* SOS_OUTDISC */
202 sscop_noop, /* SOS_OUTRESYN */
203 sscop_er_error, /* SOS_INRESYN */
204 sscop_er_outrecov, /* SOS_OUTRECOV */
205 sscop_er_recovrsp, /* SOS_RECOVRSP */
206 sscop_er_inrecov, /* SOS_INRECOV */
207 sscop_er_ready, /* SOS_READY */
208 sscop_noop /* SOS_TERM */
211 /* ERAK PDU */
212 static void (*sscop_erak_tab[SOS_NUMSTATES])
213 (struct sscop *, KBuffer *, caddr_t) = {
214 NULL, /* SOS_INST */
215 sscop_erak_idle, /* SOS_IDLE */
216 sscop_noop, /* SOS_OUTCONN */
217 sscop_erak_error, /* SOS_INCONN */
218 sscop_noop, /* SOS_OUTDISC */
219 sscop_noop, /* SOS_OUTRESYN */
220 sscop_erak_error, /* SOS_INRESYN */
221 sscop_erak_outrecov, /* SOS_OUTRECOV */
222 sscop_noop, /* SOS_RECOVRSP */
223 sscop_erak_error, /* SOS_INRECOV */
224 sscop_noop, /* SOS_READY */
225 sscop_noop /* SOS_TERM */
228 /* SD PDU */
229 static void (*sscop_sd_tab[SOS_NUMSTATES])
230 (struct sscop *, KBuffer *, caddr_t) = {
231 NULL, /* SOS_INST */
232 sscop_sd_idle, /* SOS_IDLE */
233 sscop_noop, /* SOS_OUTCONN */
234 sscop_sd_inconn, /* SOS_INCONN */
235 sscop_noop, /* SOS_OUTDISC */
236 sscop_noop, /* SOS_OUTRESYN */
237 sscop_sd_inconn, /* SOS_INRESYN */
238 sscop_noop, /* SOS_OUTRECOV */
239 sscop_noop, /* SOS_RECOVRSP */
240 sscop_sd_inconn, /* SOS_INRECOV */
241 sscop_sd_ready, /* SOS_READY */
242 sscop_noop /* SOS_TERM */
245 /* POLL PDU */
246 static void (*sscop_poll_tab[SOS_NUMSTATES])
247 (struct sscop *, KBuffer *, caddr_t) = {
248 NULL, /* SOS_INST */
249 sscop_poll_idle, /* SOS_IDLE */
250 sscop_noop, /* SOS_OUTCONN */
251 sscop_poll_inconn, /* SOS_INCONN */
252 sscop_noop, /* SOS_OUTDISC */
253 sscop_noop, /* SOS_OUTRESYN */
254 sscop_poll_inconn, /* SOS_INRESYN */
255 sscop_noop, /* SOS_OUTRECOV */
256 sscop_noop, /* SOS_RECOVRSP */
257 sscop_poll_inconn, /* SOS_INRECOV */
258 sscop_poll_ready, /* SOS_READY */
259 sscop_noop /* SOS_TERM */
262 /* STAT PDU */
263 static void (*sscop_stat_tab[SOS_NUMSTATES])
264 (struct sscop *, KBuffer *, caddr_t) = {
265 NULL, /* SOS_INST */
266 sscop_stat_idle, /* SOS_IDLE */
267 sscop_noop, /* SOS_OUTCONN */
268 sscop_stat_inconn, /* SOS_INCONN */
269 sscop_noop, /* SOS_OUTDISC */
270 sscop_noop, /* SOS_OUTRESYN */
271 sscop_stat_inconn, /* SOS_INRESYN */
272 sscop_noop, /* SOS_OUTRECOV */
273 sscop_stat_inconn, /* SOS_RECOVRSP */
274 sscop_stat_inconn, /* SOS_INRECOV */
275 sscop_stat_ready, /* SOS_READY */
276 sscop_noop /* SOS_TERM */
279 /* USTAT PDU */
280 static void (*sscop_ustat_tab[SOS_NUMSTATES])
281 (struct sscop *, KBuffer *, caddr_t) = {
282 NULL, /* SOS_INST */
283 sscop_ustat_idle, /* SOS_IDLE */
284 sscop_noop, /* SOS_OUTCONN */
285 sscop_ustat_inconn, /* SOS_INCONN */
286 sscop_noop, /* SOS_OUTDISC */
287 sscop_noop, /* SOS_OUTRESYN */
288 sscop_ustat_inconn, /* SOS_INRESYN */
289 sscop_noop, /* SOS_OUTRECOV */
290 sscop_ustat_inconn, /* SOS_RECOVRSP */
291 sscop_ustat_inconn, /* SOS_INRECOV */
292 sscop_ustat_ready, /* SOS_READY */
293 sscop_noop /* SOS_TERM */
296 /* UD PDU */
297 static void (*sscop_ud_tab[SOS_NUMSTATES])
298 (struct sscop *, KBuffer *, caddr_t) = {
299 NULL, /* SOS_INST */
300 sscop_ud_all, /* SOS_IDLE */
301 sscop_ud_all, /* SOS_OUTCONN */
302 sscop_ud_all, /* SOS_INCONN */
303 sscop_ud_all, /* SOS_OUTDISC */
304 sscop_ud_all, /* SOS_OUTRESYN */
305 sscop_ud_all, /* SOS_INRESYN */
306 sscop_ud_all, /* SOS_OUTRECOV */
307 sscop_ud_all, /* SOS_RECOVRSP */
308 sscop_ud_all, /* SOS_INRECOV */
309 sscop_ud_all, /* SOS_READY */
310 sscop_noop /* SOS_TERM */
313 /* MD PDU */
314 static void (*sscop_md_tab[SOS_NUMSTATES])
315 (struct sscop *, KBuffer *, caddr_t) = {
316 NULL, /* SOS_INST */
317 sscop_md_all, /* SOS_IDLE */
318 sscop_md_all, /* SOS_OUTCONN */
319 sscop_md_all, /* SOS_INCONN */
320 sscop_md_all, /* SOS_OUTDISC */
321 sscop_md_all, /* SOS_OUTRESYN */
322 sscop_md_all, /* SOS_INRESYN */
323 sscop_md_all, /* SOS_OUTRECOV */
324 sscop_md_all, /* SOS_RECOVRSP */
325 sscop_md_all, /* SOS_INRECOV */
326 sscop_md_all, /* SOS_READY */
327 sscop_noop /* SOS_TERM */
332 * PDU type lookup table
334 void (*(*sscop_q2110_pdutab[]))
335 (struct sscop *, KBuffer *, caddr_t) = {
336 NULL,
337 sscop_bgn_tab,
338 sscop_bgak_tab,
339 sscop_end_tab,
340 sscop_endak_tab,
341 sscop_rs_tab,
342 sscop_rsak_tab,
343 sscop_bgrej_tab,
344 sscop_sd_tab,
345 sscop_er_tab,
346 sscop_poll_tab,
347 sscop_stat_tab,
348 sscop_ustat_tab,
349 sscop_ud_tab,
350 sscop_md_tab,
351 sscop_erak_tab
356 * BGN PDU / SOS_OUTCONN Processor
358 * Arguments:
359 * sop pointer to sscop connection block
360 * m pointer to PDU buffer (without trailer)
361 * trlr pointer to PDU trailer
363 * Returns:
364 * none
367 static void
368 sscop_bgn_outconn(struct sscop *sop, KBuffer *m, caddr_t trlr)
370 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
371 int err;
374 * If retransmitted BGN, ignore it
376 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
377 KB_FREEALL(m);
378 return;
382 * Stop retransmit timer
384 sop->so_timer[SSCOP_T_CC] = 0;
387 * Initialize state variables
389 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
390 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
391 q2110_init_state(sop);
394 * Return an ACK to peer
396 sscop_send_bgak(sop);
399 * Notify user of connection establishment
401 STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
402 sop->so_connvc, (int)m, 0, err);
403 if (err) {
404 KB_FREEALL(m);
405 sscop_abort(sop, "stack memory\n");
406 return;
410 * Start data transfer timers
412 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
413 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
416 * OK, we're ready for data
418 sop->so_state = SOS_READY;
421 * See if transmit queues need servicing
423 if (sop->so_flags & SOF_XMITSRVC)
424 sscop_service_xmit(sop);
426 return;
431 * BGN PDU / SOS_INCONN Processor
433 * Arguments:
434 * sop pointer to sscop connection block
435 * m pointer to PDU buffer (without trailer)
436 * trlr pointer to PDU trailer
438 * Returns:
439 * none
442 static void
443 sscop_bgn_inconn(struct sscop *sop, KBuffer *m, caddr_t trlr)
445 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
446 int err;
449 * If retransmitted BGN, ignore it
451 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
452 KB_FREEALL(m);
453 return;
457 * Initialize transmit window
459 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
462 * First, tell user current connection has been released
464 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
465 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
466 if (err) {
467 KB_FREEALL(m);
468 sscop_abort(sop, "stack memory\n");
469 return;
473 * Now, tell user of new connection establishment
475 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
476 sop->so_connvc, (int)m, 0, err);
477 if (err) {
478 KB_FREEALL(m);
479 sscop_abort(sop, "stack memory\n");
480 return;
483 return;
488 * BGN PDU / SOS_READY Processor
490 * Arguments:
491 * sop pointer to sscop connection block
492 * m pointer to PDU buffer (without trailer)
493 * trlr pointer to PDU trailer
495 * Returns:
496 * none
499 static void
500 sscop_bgn_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
502 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
503 int err;
506 * If retransmitted BGN, just ACK it again
508 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
509 KB_FREEALL(m);
510 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
511 sscop_send_bgak(sop);
512 return;
516 * Stop data transfer timers
518 sop->so_timer[SSCOP_T_POLL] = 0;
519 sop->so_timer[SSCOP_T_NORESP] = 0;
520 sop->so_timer[SSCOP_T_IDLE] = 0;
521 sop->so_flags &= ~SOF_KEEPALIVE;
524 * Initialize transmit window
526 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
529 * Clear out appropriate queues
531 q2110_prep_retrieve(sop);
534 * Tell user current connection has been released
536 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
537 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
538 if (err) {
539 KB_FREEALL(m);
540 sscop_abort(sop, "stack memory\n");
541 return;
545 * Tell user of incoming connection
547 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
548 sop->so_connvc, (int)m, 0, err);
549 if (err) {
550 KB_FREEALL(m);
551 sscop_abort(sop, "stack memory\n");
552 return;
556 * Wait for user's response
558 sop->so_state = SOS_INCONN;
560 return;
565 * BGREJ PDU / SOS_OUTRECOV Processor
567 * Arguments:
568 * sop pointer to sscop connection block
569 * m pointer to PDU buffer (without trailer)
570 * trlr pointer to PDU trailer
572 * Returns:
573 * none
576 static void
577 sscop_bgrej_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
579 int err;
582 * Stop retransmit timer
584 sop->so_timer[SSCOP_T_CC] = 0;
587 * Report protocol error
589 sscop_bgrej_error(sop, m, trlr);
592 * Notify user of connection failure
594 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
595 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
596 if (err) {
597 sscop_abort(sop, "stack memory\n");
598 return;
602 * Clear receiver buffer
604 sscop_rcvr_drain(sop);
607 * Back to idle state
609 sop->so_state = SOS_IDLE;
611 return;
616 * END PDU / SOS_OUTRECOV Processor
618 * Arguments:
619 * sop pointer to sscop connection block
620 * m pointer to PDU buffer (without trailer)
621 * trlr pointer to PDU trailer
623 * Returns:
624 * none
627 static void
628 sscop_end_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
630 struct end_pdu *ep = (struct end_pdu *)trlr;
631 int err, source;
634 * Stop retransmit timer
636 sop->so_timer[SSCOP_T_CC] = 0;
639 * Acknowledge END
641 sscop_send_endak(sop);
644 * Get Source value
646 if (ep->end_type & PT_SOURCE_SSCOP)
647 source = SSCOP_SOURCE_SSCOP;
648 else
649 source = SSCOP_SOURCE_USER;
652 * Notify user of connection termination
654 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
655 sop->so_connvc, (int)m, source, err);
656 if (err) {
657 KB_FREEALL(m);
658 sscop_abort(sop, "stack memory\n");
659 return;
663 * Clear receiver buffer
665 sscop_rcvr_drain(sop);
668 * Back to idle state
670 sop->so_state = SOS_IDLE;
672 return;
677 * END PDU / SOS_READY Processor
679 * Arguments:
680 * sop pointer to sscop connection block
681 * m pointer to PDU buffer (without trailer)
682 * trlr pointer to PDU trailer
684 * Returns:
685 * none
688 static void
689 sscop_end_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
691 struct end_pdu *ep = (struct end_pdu *)trlr;
692 int err, source;
695 * Stop data transfer timers
697 sop->so_timer[SSCOP_T_POLL] = 0;
698 sop->so_timer[SSCOP_T_NORESP] = 0;
699 sop->so_timer[SSCOP_T_IDLE] = 0;
700 sop->so_flags &= ~SOF_KEEPALIVE;
703 * Acknowledge END
705 sscop_send_endak(sop);
708 * Get Source value
710 if (ep->end_type & PT_SOURCE_SSCOP)
711 source = SSCOP_SOURCE_SSCOP;
712 else
713 source = SSCOP_SOURCE_USER;
716 * Notify user of connection termination
718 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
719 sop->so_connvc, (int)m, source, err);
720 if (err) {
721 KB_FREEALL(m);
722 sscop_abort(sop, "stack memory\n");
723 return;
727 * Clear out appropriate queues
729 q2110_prep_retrieve(sop);
732 * Back to idle state
734 sop->so_state = SOS_IDLE;
736 return;
741 * ENDAK PDU / SOS_OUTRECOV Processor
743 * Arguments:
744 * sop pointer to sscop connection block
745 * m pointer to PDU buffer (without trailer)
746 * trlr pointer to PDU trailer
748 * Returns:
749 * none
752 static void
753 sscop_endak_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
755 int err;
758 * Stop retransmit timer
760 sop->so_timer[SSCOP_T_CC] = 0;
763 * Report protocol error
765 sscop_endak_error(sop, m, trlr);
768 * Notify user of connection failure
770 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
771 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
772 if (err) {
773 sscop_abort(sop, "stack memory\n");
774 return;
778 * Clear receiver buffer
780 sscop_rcvr_drain(sop);
783 * Back to idle state
785 sop->so_state = SOS_IDLE;
787 return;
792 * RS PDU / SOS_OUTRESYN Processor
794 * Arguments:
795 * sop pointer to sscop connection block
796 * m pointer to PDU buffer (without trailer)
797 * trlr pointer to PDU trailer
799 * Returns:
800 * none
803 static void
804 sscop_rs_outresyn(struct sscop *sop, KBuffer *m, caddr_t trlr)
806 struct rs_pdu *rp = (struct rs_pdu *)trlr;
807 int err;
810 * If retransmitted RS, ignore it
812 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
813 KB_FREEALL(m);
814 return;
818 * Stop retransmit timer
820 sop->so_timer[SSCOP_T_CC] = 0;
823 * Initialize state variables
825 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
826 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
827 q2110_init_state(sop);
830 * Free PDU buffers
832 KB_FREEALL(m);
835 * Return an ACK to peer
837 sscop_send_rsak(sop);
840 * Notify user of connection resynchronization
842 STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
843 sop->so_connvc, 0, 0, err);
844 if (err) {
845 sscop_abort(sop, "stack memory\n");
846 return;
850 * Start data transfer timers
852 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
853 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
856 * OK, we're ready for data
858 sop->so_state = SOS_READY;
861 * See if transmit queues need servicing
863 if (sop->so_flags & SOF_XMITSRVC)
864 sscop_service_xmit(sop);
866 return;
871 * RS PDU / SOS_INRESYN Processor
873 * Arguments:
874 * sop pointer to sscop connection block
875 * m pointer to PDU buffer (without trailer)
876 * trlr pointer to PDU trailer
878 * Returns:
879 * none
882 static void
883 sscop_rs_inresyn(struct sscop *sop, KBuffer *m, caddr_t trlr)
885 struct rs_pdu *rp = (struct rs_pdu *)trlr;
888 * If retransmitted RS, ignore it
890 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
891 KB_FREEALL(m);
892 return;
896 * Report error condition
898 sscop_rs_error(sop, m, trlr);
900 return;
905 * RS PDU / SOS_OUTRECOV Processor
907 * Arguments:
908 * sop pointer to sscop connection block
909 * m pointer to PDU buffer (without trailer)
910 * trlr pointer to PDU trailer
912 * Returns:
913 * none
916 static void
917 sscop_rs_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
919 struct rs_pdu *rp = (struct rs_pdu *)trlr;
920 int err;
923 * If retransmitted RS, report an error
925 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
926 sscop_rs_error(sop, m, trlr);
927 return;
931 * Stop retransmit timer
933 sop->so_timer[SSCOP_T_CC] = 0;
936 * Initialize transmit window
938 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
941 * Notify user of connection resynchronization
943 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
944 sop->so_connvc, (int)m, 0, err);
945 if (err) {
946 KB_FREEALL(m);
947 sscop_abort(sop, "stack memory\n");
948 return;
952 * Clear receiver buffer
954 sscop_rcvr_drain(sop);
957 * Wait for user response
959 sop->so_state = SOS_INRESYN;
961 return;
966 * RS PDU / SOS_READY Processor
968 * Arguments:
969 * sop pointer to sscop connection block
970 * m pointer to PDU buffer (without trailer)
971 * trlr pointer to PDU trailer
973 * Returns:
974 * none
977 static void
978 sscop_rs_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
980 struct rs_pdu *rp = (struct rs_pdu *)trlr;
981 int err;
984 * If retransmitted RS, just ACK it
986 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
987 KB_FREEALL(m);
988 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
989 sscop_send_rsak(sop);
990 return;
994 * Stop data transfer timers
996 sop->so_timer[SSCOP_T_POLL] = 0;
997 sop->so_timer[SSCOP_T_NORESP] = 0;
998 sop->so_timer[SSCOP_T_IDLE] = 0;
999 sop->so_flags &= ~SOF_KEEPALIVE;
1002 * Initialize transmit window
1004 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
1007 * Notify user of connection resynchronization
1009 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
1010 sop->so_connvc, (int)m, 0, err);
1011 if (err) {
1012 KB_FREEALL(m);
1013 sscop_abort(sop, "stack memory\n");
1014 return;
1018 * Clear out appropriate queues
1020 q2110_prep_retrieve(sop);
1023 * Wait for user response
1025 sop->so_state = SOS_INRESYN;
1027 return;
1031 * ER PDU / Protocol Error
1033 * Arguments:
1034 * sop pointer to sscop connection block
1035 * m pointer to PDU buffer (without trailer)
1036 * trlr pointer to PDU trailer
1038 * Returns:
1039 * none
1042 static void
1043 sscop_er_error(struct sscop *sop, KBuffer *m, caddr_t trlr)
1047 * Record error condition
1049 sscop_maa_error(sop, 'L');
1050 KB_FREEALL(m);
1052 return;
1057 * ER PDU / SOS_IDLE Processor
1059 * Arguments:
1060 * sop pointer to sscop connection block
1061 * m pointer to PDU buffer (without trailer)
1062 * trlr pointer to PDU trailer
1064 * Returns:
1065 * none
1068 static void
1069 sscop_er_idle(struct sscop *sop, KBuffer *m, caddr_t trlr)
1073 * Record error condition
1075 sscop_er_error(sop, m, trlr);
1078 * Return an END to peer
1080 sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1082 return;
1087 * ER PDU / SOS_OUTRECOV Processor
1089 * Arguments:
1090 * sop pointer to sscop connection block
1091 * m pointer to PDU buffer (without trailer)
1092 * trlr pointer to PDU trailer
1094 * Returns:
1095 * none
1098 static void
1099 sscop_er_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1101 struct er_pdu *ep = (struct er_pdu *)trlr;
1102 int err;
1105 * If retransmitted ER, report an error
1107 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1108 sscop_er_error(sop, m, trlr);
1109 return;
1113 * Stop retransmit timer
1115 sop->so_timer[SSCOP_T_CC] = 0;
1118 * Initialize transmit window
1120 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1123 * Initialize receiver window
1125 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
1128 * Free PDU buffers
1130 KB_FREEALL(m);
1133 * Acknowledge ER
1135 sscop_send_erak(sop);
1138 * Deliver any outstanding data to user
1140 q2110_deliver_data(sop);
1143 * Notify user of connection recovery
1145 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1146 sop->so_connvc, 0, 0, err);
1147 if (err) {
1148 sscop_abort(sop, "stack memory\n");
1149 return;
1153 * Wait for user response
1155 sop->so_state = SOS_RECOVRSP;
1157 return;
1162 * ER PDU / SOS_RECOVRSP Processor
1164 * Arguments:
1165 * sop pointer to sscop connection block
1166 * m pointer to PDU buffer (without trailer)
1167 * trlr pointer to PDU trailer
1169 * Returns:
1170 * none
1173 static void
1174 sscop_er_recovrsp(struct sscop *sop, KBuffer *m, caddr_t trlr)
1176 struct er_pdu *ep = (struct er_pdu *)trlr;
1179 * If retransmitted ER, just ACK it
1181 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1182 KB_FREEALL(m);
1183 sscop_send_erak(sop);
1184 return;
1188 * Report error condition
1190 sscop_er_error(sop, m, trlr);
1192 return;
1197 * ER PDU / SOS_INRECOV Processor
1199 * Arguments:
1200 * sop pointer to sscop connection block
1201 * m pointer to PDU buffer (without trailer)
1202 * trlr pointer to PDU trailer
1204 * Returns:
1205 * none
1208 static void
1209 sscop_er_inrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1211 struct er_pdu *ep = (struct er_pdu *)trlr;
1214 * If retransmitted ER, just ignore it
1216 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1217 KB_FREEALL(m);
1218 return;
1222 * Report error condition
1224 sscop_er_error(sop, m, trlr);
1226 return;
1231 * ER PDU / SOS_READY Processor
1233 * Arguments:
1234 * sop pointer to sscop connection block
1235 * m pointer to PDU buffer (without trailer)
1236 * trlr pointer to PDU trailer
1238 * Returns:
1239 * none
1242 static void
1243 sscop_er_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1245 struct er_pdu *ep = (struct er_pdu *)trlr;
1246 int err;
1249 * If retransmitted ER, just ACK it
1251 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1252 KB_FREEALL(m);
1253 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1254 sscop_send_erak(sop);
1255 return;
1259 * Stop data transfer timers
1261 sop->so_timer[SSCOP_T_POLL] = 0;
1262 sop->so_timer[SSCOP_T_NORESP] = 0;
1263 sop->so_timer[SSCOP_T_IDLE] = 0;
1264 sop->so_flags &= ~SOF_KEEPALIVE;
1267 * Initialize transmit window
1269 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1272 * Free PDU buffers
1274 KB_FREEALL(m);
1277 * Clear out appropriate queues
1279 q2110_prep_recovery(sop);
1282 * Deliver any outstanding data to user
1284 q2110_deliver_data(sop);
1287 * Notify user of connection recovery
1289 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1290 sop->so_connvc, 0, 0, err);
1291 if (err) {
1292 sscop_abort(sop, "stack memory\n");
1293 return;
1297 * Wait for user response
1299 sop->so_state = SOS_INRECOV;
1301 return;
1306 * ERAK PDU / Protocol Error
1308 * Arguments:
1309 * sop pointer to sscop connection block
1310 * m pointer to PDU buffer (without trailer)
1311 * trlr pointer to PDU trailer
1313 * Returns:
1314 * none
1317 static void
1318 sscop_erak_error(struct sscop *sop, KBuffer *m, caddr_t trlr)
1322 * Record error condition
1324 sscop_maa_error(sop, 'M');
1325 KB_FREEALL(m);
1327 return;
1332 * ERAK PDU / SOS_IDLE Processor
1334 * Arguments:
1335 * sop pointer to sscop connection block
1336 * m pointer to PDU buffer (without trailer)
1337 * trlr pointer to PDU trailer
1339 * Returns:
1340 * none
1343 static void
1344 sscop_erak_idle(struct sscop *sop, KBuffer *m, caddr_t trlr)
1348 * Record error condition
1350 sscop_erak_error(sop, m, trlr);
1353 * Return an END to peer
1355 sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1357 return;
1362 * ERAK PDU / SOS_OUTRECOV Processor
1364 * Arguments:
1365 * sop pointer to sscop connection block
1366 * m pointer to PDU buffer (without trailer)
1367 * trlr pointer to PDU trailer
1369 * Returns:
1370 * none
1373 static void
1374 sscop_erak_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1376 struct erak_pdu *ep = (struct erak_pdu *)trlr;
1377 int err;
1380 * Stop retransmit timer
1382 sop->so_timer[SSCOP_T_CC] = 0;
1385 * Initialize transmit window
1387 SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
1390 * Free PDU buffers
1392 KB_FREEALL(m);
1395 * Deliver any outstanding data to user
1397 q2110_deliver_data(sop);
1400 * Notify user of connection recovery
1402 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1403 sop->so_connvc, 0, 0, err);
1404 if (err) {
1405 sscop_abort(sop, "stack memory\n");
1406 return;
1410 * Wait for user response
1412 sop->so_state = SOS_RECOVRSP;
1414 return;
1419 * SD PDU / SOS_READY Processor
1421 * Arguments:
1422 * sop pointer to sscop connection block
1423 * m pointer to PDU buffer (without trailer)
1424 * trlr pointer to PDU trailer
1426 * Returns:
1427 * none
1430 static void
1431 sscop_sd_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1433 struct sd_pdu *sp = (struct sd_pdu *)trlr;
1434 struct pdu_hdr *php;
1435 KBuffer *n;
1436 sscop_seq ns;
1437 int err, space;
1440 * Get PDU sequence number
1442 SEQ_SET(ns, ntohl(sp->sd_ns));
1445 * Ensure that the sequence number fits within the window
1447 if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
1449 * It doesn't, drop received data
1451 KB_FREEALL(m);
1454 * If next highest PDU hasn't reached window end yet,
1455 * then send a USTAT to inform transmitter of this gap
1457 if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) {
1458 sscop_send_ustat(sop, sop->so_rcvmax);
1459 sop->so_rcvhigh = sop->so_rcvmax;
1461 return;
1465 * If this is the next in-sequence PDU, hand it to user
1467 if (ns == sop->so_rcvnext) {
1468 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1469 sop->so_connvc, (int)m, ns, err);
1470 if (err) {
1471 KB_FREEALL(m);
1472 return;
1476 * Bump next expected sequence number
1478 SEQ_INCR(sop->so_rcvnext, 1);
1481 * Slide receive window down
1483 SEQ_INCR(sop->so_rcvmax, 1);
1486 * Is this the highest sequence PDU we've received??
1488 if (ns == sop->so_rcvhigh) {
1490 * Yes, bump the limit and exit
1492 sop->so_rcvhigh = sop->so_rcvnext;
1493 return;
1497 * This is a retransmitted PDU, so see if we have
1498 * more in-sequence PDUs already queued up
1500 while ((php = sop->so_recv_hd) &&
1501 (php->ph_ns == sop->so_rcvnext)) {
1504 * Yup we do, so remove next PDU from queue and
1505 * pass it up to the user as well
1507 sop->so_recv_hd = php->ph_recv_lk;
1508 if (sop->so_recv_hd == NULL)
1509 sop->so_recv_tl = NULL;
1510 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1511 sop->so_connvc, (int)php->ph_buf, php->ph_ns,
1512 err);
1513 if (err) {
1515 * Should never happen, but...
1517 KB_FREEALL(php->ph_buf);
1518 sscop_abort(sop, "stack memory\n");
1519 return;
1523 * Bump next expected sequence number
1525 SEQ_INCR(sop->so_rcvnext, 1);
1528 * Slide receive window down
1530 SEQ_INCR(sop->so_rcvmax, 1);
1534 * Finished with data delivery...
1536 return;
1540 * We're gonna have to queue this PDU, so find space
1541 * for the PDU header
1543 KB_HEADROOM(m, space);
1546 * If there's not enough room in the received buffer,
1547 * allocate & link a new buffer for the header
1549 if (space < sizeof(struct pdu_hdr)) {
1551 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
1552 if (n == NULL) {
1553 KB_FREEALL(m);
1554 return;
1556 KB_HEADSET(n, sizeof(struct pdu_hdr));
1557 KB_LEN(n) = 0;
1558 KB_LINKHEAD(n, m);
1559 m = n;
1563 * Build PDU header
1565 * We can at least assume/require that the start of
1566 * the user data is aligned. Also note that we don't
1567 * include this header in the buffer len/offset fields.
1569 KB_DATASTART(m, php, struct pdu_hdr *);
1570 php--;
1571 php->ph_ns = ns;
1572 php->ph_buf = m;
1575 * Insert PDU into the receive queue
1577 if (sscop_recv_insert(sop, php)) {
1579 * Oops, a duplicate sequence number PDU is already on
1580 * the queue, somethings wrong here.
1582 sscop_maa_error(sop, 'Q');
1585 * Free buffers
1587 KB_FREEALL(m);
1590 * Go into recovery mode
1592 q2110_error_recovery(sop);
1594 return;
1598 * Are we at the high-water mark??
1600 if (ns == sop->so_rcvhigh) {
1602 * Yes, just bump the mark
1604 SEQ_INCR(sop->so_rcvhigh, 1);
1606 return;
1610 * Are we beyond the high-water mark??
1612 if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1614 * Yes, then there's a missing PDU, so inform the transmitter
1616 sscop_send_ustat(sop, ns);
1619 * Update high-water mark
1621 sop->so_rcvhigh = SEQ_ADD(ns, 1);
1624 return;
1629 * POLL PDU / SOS_READY Processor
1631 * Arguments:
1632 * sop pointer to sscop connection block
1633 * m pointer to PDU buffer (without trailer)
1634 * trlr pointer to PDU trailer
1636 * Returns:
1637 * none
1640 static void
1641 sscop_poll_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1643 struct poll_pdu *pp = (struct poll_pdu *)trlr;
1644 sscop_seq nps;
1646 pp->poll_ns = ntohl(pp->poll_ns);
1649 * If the poll sequence number is less than highest number
1650 * we've already seen, something's wrong
1652 if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1654 * Record error condition
1656 sscop_maa_error(sop, 'Q');
1659 * Free buffers
1661 KB_FREEALL(m);
1664 * Go into recovery mode
1666 q2110_error_recovery(sop);
1668 return;
1672 * Set a new "next highest" sequence number expected
1674 if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
1675 SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
1676 else
1677 sop->so_rcvhigh = sop->so_rcvmax;
1680 * Return a STAT PDU to peer
1682 SEQ_SET(nps, ntohl(pp->poll_nps));
1683 KB_FREEALL(m);
1684 sscop_send_stat(sop, nps);
1686 return;