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 $
31 * ATM Forum UNI Support
32 * ---------------------
34 * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs)
38 #include <netatm/kern_include.h>
40 #include <netatm/uni/sscop.h>
41 #include <netatm/uni/sscop_misc.h>
42 #include <netatm/uni/sscop_pdu.h>
43 #include <netatm/uni/sscop_var.h>
46 __RCSID("@(#) $FreeBSD: src/sys/netatm/uni/q2110_sigcpcs.c,v 1.4 2000/01/17 20:49:49 mks Exp $");
53 static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t));
54 static void sscop_bgn_inconn __P((struct sscop *, KBuffer *, caddr_t));
55 static void sscop_bgn_ready __P((struct sscop *, KBuffer *, caddr_t));
56 static void sscop_bgrej_outrecov __P((struct sscop *, KBuffer *, caddr_t));
57 static void sscop_end_outrecov __P((struct sscop *, KBuffer *, caddr_t));
58 static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t));
59 static void sscop_endak_outrecov __P((struct sscop *, KBuffer *, caddr_t));
60 static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t));
61 static void sscop_rs_inresyn __P((struct sscop *, KBuffer *, caddr_t));
62 static void sscop_rs_outrecov __P((struct sscop *, KBuffer *, caddr_t));
63 static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t));
64 static void sscop_er_error __P((struct sscop *, KBuffer *, caddr_t));
65 static void sscop_er_idle __P((struct sscop *, KBuffer *, caddr_t));
66 static void sscop_er_outrecov __P((struct sscop *, KBuffer *, caddr_t));
67 static void sscop_er_recovrsp __P((struct sscop *, KBuffer *, caddr_t));
68 static void sscop_er_inrecov __P((struct sscop *, KBuffer *, caddr_t));
69 static void sscop_er_ready __P((struct sscop *, KBuffer *, caddr_t));
70 static void sscop_erak_error __P((struct sscop *, KBuffer *, caddr_t));
71 static void sscop_erak_idle __P((struct sscop *, KBuffer *, caddr_t));
72 static void sscop_erak_outrecov __P((struct sscop *, KBuffer *, caddr_t));
73 static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t));
74 static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t));
78 * PDU type state lookup tables
81 static void (*sscop_bgn_tab[SOS_NUMSTATES])
82 __P((struct sscop *, KBuffer *, caddr_t)) = {
84 sscop_bgn_idle, /* SOS_IDLE */
85 sscop_bgn_outconn, /* SOS_OUTCONN */
86 sscop_bgn_inconn, /* SOS_INCONN */
87 sscop_bgn_outdisc, /* SOS_OUTDISC */
88 sscop_bgn_outresyn, /* SOS_OUTRESYN */
89 sscop_bgn_inresyn, /* SOS_INRESYN */
90 sscop_bgn_inresyn, /* SOS_OUTRECOV */
91 sscop_bgn_inresyn, /* SOS_RECOVRSP */
92 sscop_bgn_inresyn, /* SOS_INRECOV */
93 sscop_bgn_ready, /* SOS_READY */
94 sscop_noop /* SOS_TERM */
98 static void (*sscop_bgak_tab[SOS_NUMSTATES])
99 __P((struct sscop *, KBuffer *, caddr_t)) = {
101 sscop_bgak_idle, /* SOS_IDLE */
102 sscop_bgak_outconn, /* SOS_OUTCONN */
103 sscop_bgak_error, /* SOS_INCONN */
104 sscop_noop, /* SOS_OUTDISC */
105 sscop_noop, /* SOS_OUTRESYN */
106 sscop_bgak_error, /* SOS_INRESYN */
107 sscop_bgak_error, /* SOS_OUTRECOV */
108 sscop_bgak_error, /* SOS_RECOVRSP */
109 sscop_bgak_error, /* SOS_INRECOV */
110 sscop_noop, /* SOS_READY */
111 sscop_noop /* SOS_TERM */
115 static void (*sscop_bgrej_tab[SOS_NUMSTATES])
116 __P((struct sscop *, KBuffer *, caddr_t)) = {
118 sscop_bgrej_error, /* SOS_IDLE */
119 sscop_bgrej_outconn, /* SOS_OUTCONN */
120 sscop_bgrej_inconn, /* SOS_INCONN */
121 sscop_endak_outdisc, /* SOS_OUTDISC */
122 sscop_bgrej_outresyn, /* SOS_OUTRESYN */
123 sscop_bgrej_inconn, /* SOS_INRESYN */
124 sscop_bgrej_outrecov, /* SOS_OUTRECOV */
125 sscop_bgrej_inconn, /* SOS_RECOVRSP */
126 sscop_bgrej_inconn, /* SOS_INRECOV */
127 sscop_bgrej_ready, /* SOS_READY */
128 sscop_noop /* SOS_TERM */
132 static void (*sscop_end_tab[SOS_NUMSTATES])
133 __P((struct sscop *, KBuffer *, caddr_t)) = {
135 sscop_end_idle, /* SOS_IDLE */
136 sscop_noop, /* SOS_OUTCONN */
137 sscop_end_inconn, /* SOS_INCONN */
138 sscop_end_outdisc, /* SOS_OUTDISC */
139 sscop_end_inconn, /* SOS_OUTRESYN */
140 sscop_end_inconn, /* SOS_INRESYN */
141 sscop_end_outrecov, /* SOS_OUTRECOV */
142 sscop_end_inconn, /* SOS_RECOVRSP */
143 sscop_end_inconn, /* SOS_INRECOV */
144 sscop_end_ready, /* SOS_READY */
145 sscop_noop /* SOS_TERM */
149 static void (*sscop_endak_tab[SOS_NUMSTATES])
150 __P((struct sscop *, KBuffer *, caddr_t)) = {
152 sscop_noop, /* SOS_IDLE */
153 sscop_noop, /* SOS_OUTCONN */
154 sscop_endak_inconn, /* SOS_INCONN */
155 sscop_endak_outdisc, /* SOS_OUTDISC */
156 sscop_endak_inconn, /* SOS_OUTRESYN */
157 sscop_endak_inconn, /* SOS_INRESYN */
158 sscop_endak_outrecov, /* SOS_OUTRECOV */
159 sscop_endak_inconn, /* SOS_RECOVRSP */
160 sscop_endak_inconn, /* SOS_INRECOV */
161 sscop_endak_ready, /* SOS_READY */
162 sscop_noop /* SOS_TERM */
166 static void (*sscop_rs_tab[SOS_NUMSTATES])
167 __P((struct sscop *, KBuffer *, caddr_t)) = {
169 sscop_rs_idle, /* SOS_IDLE */
170 sscop_noop, /* SOS_OUTCONN */
171 sscop_rs_error, /* SOS_INCONN */
172 sscop_noop, /* SOS_OUTDISC */
173 sscop_rs_outresyn, /* SOS_OUTRESYN */
174 sscop_rs_inresyn, /* SOS_INRESYN */
175 sscop_rs_outrecov, /* SOS_OUTRECOV */
176 sscop_rs_outrecov, /* SOS_RECOVRSP */
177 sscop_rs_outrecov, /* SOS_INRECOV */
178 sscop_rs_ready, /* SOS_READY */
179 sscop_noop /* SOS_TERM */
183 static void (*sscop_rsak_tab[SOS_NUMSTATES])
184 __P((struct sscop *, KBuffer *, caddr_t)) = {
186 sscop_rsak_idle, /* SOS_IDLE */
187 sscop_noop, /* SOS_OUTCONN */
188 sscop_rsak_error, /* SOS_INCONN */
189 sscop_noop, /* SOS_OUTDISC */
190 sscop_rsak_outresyn, /* SOS_OUTRESYN */
191 sscop_rsak_error, /* SOS_INRESYN */
192 sscop_rsak_error, /* SOS_OUTRECOV */
193 sscop_rsak_error, /* SOS_RECOVRSP */
194 sscop_rsak_error, /* SOS_INRECOV */
195 sscop_noop, /* SOS_READY */
196 sscop_noop /* SOS_TERM */
200 static void (*sscop_er_tab[SOS_NUMSTATES])
201 __P((struct sscop *, KBuffer *, caddr_t)) = {
203 sscop_er_idle, /* SOS_IDLE */
204 sscop_noop, /* SOS_OUTCONN */
205 sscop_er_error, /* SOS_INCONN */
206 sscop_noop, /* SOS_OUTDISC */
207 sscop_noop, /* SOS_OUTRESYN */
208 sscop_er_error, /* SOS_INRESYN */
209 sscop_er_outrecov, /* SOS_OUTRECOV */
210 sscop_er_recovrsp, /* SOS_RECOVRSP */
211 sscop_er_inrecov, /* SOS_INRECOV */
212 sscop_er_ready, /* SOS_READY */
213 sscop_noop /* SOS_TERM */
217 static void (*sscop_erak_tab[SOS_NUMSTATES])
218 __P((struct sscop *, KBuffer *, caddr_t)) = {
220 sscop_erak_idle, /* SOS_IDLE */
221 sscop_noop, /* SOS_OUTCONN */
222 sscop_erak_error, /* SOS_INCONN */
223 sscop_noop, /* SOS_OUTDISC */
224 sscop_noop, /* SOS_OUTRESYN */
225 sscop_erak_error, /* SOS_INRESYN */
226 sscop_erak_outrecov, /* SOS_OUTRECOV */
227 sscop_noop, /* SOS_RECOVRSP */
228 sscop_erak_error, /* SOS_INRECOV */
229 sscop_noop, /* SOS_READY */
230 sscop_noop /* SOS_TERM */
234 static void (*sscop_sd_tab[SOS_NUMSTATES])
235 __P((struct sscop *, KBuffer *, caddr_t)) = {
237 sscop_sd_idle, /* SOS_IDLE */
238 sscop_noop, /* SOS_OUTCONN */
239 sscop_sd_inconn, /* SOS_INCONN */
240 sscop_noop, /* SOS_OUTDISC */
241 sscop_noop, /* SOS_OUTRESYN */
242 sscop_sd_inconn, /* SOS_INRESYN */
243 sscop_noop, /* SOS_OUTRECOV */
244 sscop_noop, /* SOS_RECOVRSP */
245 sscop_sd_inconn, /* SOS_INRECOV */
246 sscop_sd_ready, /* SOS_READY */
247 sscop_noop /* SOS_TERM */
251 static void (*sscop_poll_tab[SOS_NUMSTATES])
252 __P((struct sscop *, KBuffer *, caddr_t)) = {
254 sscop_poll_idle, /* SOS_IDLE */
255 sscop_noop, /* SOS_OUTCONN */
256 sscop_poll_inconn, /* SOS_INCONN */
257 sscop_noop, /* SOS_OUTDISC */
258 sscop_noop, /* SOS_OUTRESYN */
259 sscop_poll_inconn, /* SOS_INRESYN */
260 sscop_noop, /* SOS_OUTRECOV */
261 sscop_noop, /* SOS_RECOVRSP */
262 sscop_poll_inconn, /* SOS_INRECOV */
263 sscop_poll_ready, /* SOS_READY */
264 sscop_noop /* SOS_TERM */
268 static void (*sscop_stat_tab[SOS_NUMSTATES])
269 __P((struct sscop *, KBuffer *, caddr_t)) = {
271 sscop_stat_idle, /* SOS_IDLE */
272 sscop_noop, /* SOS_OUTCONN */
273 sscop_stat_inconn, /* SOS_INCONN */
274 sscop_noop, /* SOS_OUTDISC */
275 sscop_noop, /* SOS_OUTRESYN */
276 sscop_stat_inconn, /* SOS_INRESYN */
277 sscop_noop, /* SOS_OUTRECOV */
278 sscop_stat_inconn, /* SOS_RECOVRSP */
279 sscop_stat_inconn, /* SOS_INRECOV */
280 sscop_stat_ready, /* SOS_READY */
281 sscop_noop /* SOS_TERM */
285 static void (*sscop_ustat_tab[SOS_NUMSTATES])
286 __P((struct sscop *, KBuffer *, caddr_t)) = {
288 sscop_ustat_idle, /* SOS_IDLE */
289 sscop_noop, /* SOS_OUTCONN */
290 sscop_ustat_inconn, /* SOS_INCONN */
291 sscop_noop, /* SOS_OUTDISC */
292 sscop_noop, /* SOS_OUTRESYN */
293 sscop_ustat_inconn, /* SOS_INRESYN */
294 sscop_noop, /* SOS_OUTRECOV */
295 sscop_ustat_inconn, /* SOS_RECOVRSP */
296 sscop_ustat_inconn, /* SOS_INRECOV */
297 sscop_ustat_ready, /* SOS_READY */
298 sscop_noop /* SOS_TERM */
302 static void (*sscop_ud_tab[SOS_NUMSTATES])
303 __P((struct sscop *, KBuffer *, caddr_t)) = {
305 sscop_ud_all, /* SOS_IDLE */
306 sscop_ud_all, /* SOS_OUTCONN */
307 sscop_ud_all, /* SOS_INCONN */
308 sscop_ud_all, /* SOS_OUTDISC */
309 sscop_ud_all, /* SOS_OUTRESYN */
310 sscop_ud_all, /* SOS_INRESYN */
311 sscop_ud_all, /* SOS_OUTRECOV */
312 sscop_ud_all, /* SOS_RECOVRSP */
313 sscop_ud_all, /* SOS_INRECOV */
314 sscop_ud_all, /* SOS_READY */
315 sscop_noop /* SOS_TERM */
319 static void (*sscop_md_tab[SOS_NUMSTATES])
320 __P((struct sscop *, KBuffer *, caddr_t)) = {
322 sscop_md_all, /* SOS_IDLE */
323 sscop_md_all, /* SOS_OUTCONN */
324 sscop_md_all, /* SOS_INCONN */
325 sscop_md_all, /* SOS_OUTDISC */
326 sscop_md_all, /* SOS_OUTRESYN */
327 sscop_md_all, /* SOS_INRESYN */
328 sscop_md_all, /* SOS_OUTRECOV */
329 sscop_md_all, /* SOS_RECOVRSP */
330 sscop_md_all, /* SOS_INRECOV */
331 sscop_md_all, /* SOS_READY */
332 sscop_noop /* SOS_TERM */
337 * PDU type lookup table
339 void (*(*sscop_q2110_pdutab[]))
340 __P((struct sscop *, KBuffer *, caddr_t)) = {
361 * BGN PDU / SOS_OUTCONN Processor
364 * sop pointer to sscop connection block
365 * m pointer to PDU buffer (without trailer)
366 * trlr pointer to PDU trailer
373 sscop_bgn_outconn(sop, m, trlr)
378 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
382 * If retransmitted BGN, ignore it
384 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
390 * Stop retransmit timer
392 sop->so_timer[SSCOP_T_CC] = 0;
395 * Initialize state variables
397 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
398 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
399 q2110_init_state(sop);
402 * Return an ACK to peer
404 (void) sscop_send_bgak(sop);
407 * Notify user of connection establishment
409 STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
410 sop->so_connvc, (int)m, 0, err);
413 sscop_abort(sop, "stack memory\n");
418 * Start data transfer timers
420 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
421 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
424 * OK, we're ready for data
426 sop->so_state = SOS_READY;
429 * See if transmit queues need servicing
431 if (sop->so_flags & SOF_XMITSRVC)
432 sscop_service_xmit(sop);
439 * BGN PDU / SOS_INCONN Processor
442 * sop pointer to sscop connection block
443 * m pointer to PDU buffer (without trailer)
444 * trlr pointer to PDU trailer
451 sscop_bgn_inconn(sop, m, trlr)
456 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
460 * If retransmitted BGN, ignore it
462 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
468 * Initialize transmit window
470 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
473 * First, tell user current connection has been released
475 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
476 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
479 sscop_abort(sop, "stack memory\n");
484 * Now, tell user of new connection establishment
486 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
487 sop->so_connvc, (int)m, 0, err);
490 sscop_abort(sop, "stack memory\n");
499 * BGN PDU / SOS_READY Processor
502 * sop pointer to sscop connection block
503 * m pointer to PDU buffer (without trailer)
504 * trlr pointer to PDU trailer
511 sscop_bgn_ready(sop, m, trlr)
516 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
520 * If retransmitted BGN, just ACK it again
522 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
524 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
525 (void) sscop_send_bgak(sop);
530 * Stop data transfer timers
532 sop->so_timer[SSCOP_T_POLL] = 0;
533 sop->so_timer[SSCOP_T_NORESP] = 0;
534 sop->so_timer[SSCOP_T_IDLE] = 0;
535 sop->so_flags &= ~SOF_KEEPALIVE;
538 * Initialize transmit window
540 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
543 * Clear out appropriate queues
545 q2110_prep_retrieve(sop);
548 * Tell user current connection has been released
550 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
551 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
554 sscop_abort(sop, "stack memory\n");
559 * Tell user of incoming connection
561 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
562 sop->so_connvc, (int)m, 0, err);
565 sscop_abort(sop, "stack memory\n");
570 * Wait for user's response
572 sop->so_state = SOS_INCONN;
579 * BGREJ PDU / SOS_OUTRECOV Processor
582 * sop pointer to sscop connection block
583 * m pointer to PDU buffer (without trailer)
584 * trlr pointer to PDU trailer
591 sscop_bgrej_outrecov(sop, m, trlr)
599 * Stop retransmit timer
601 sop->so_timer[SSCOP_T_CC] = 0;
604 * Report protocol error
606 sscop_bgrej_error(sop, m, trlr);
609 * Notify user of connection failure
611 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
612 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
614 sscop_abort(sop, "stack memory\n");
619 * Clear receiver buffer
621 sscop_rcvr_drain(sop);
626 sop->so_state = SOS_IDLE;
633 * END PDU / SOS_OUTRECOV Processor
636 * sop pointer to sscop connection block
637 * m pointer to PDU buffer (without trailer)
638 * trlr pointer to PDU trailer
645 sscop_end_outrecov(sop, m, trlr)
650 struct end_pdu *ep = (struct end_pdu *)trlr;
654 * Stop retransmit timer
656 sop->so_timer[SSCOP_T_CC] = 0;
661 (void) sscop_send_endak(sop);
666 if (ep->end_type & PT_SOURCE_SSCOP)
667 source = SSCOP_SOURCE_SSCOP;
669 source = SSCOP_SOURCE_USER;
672 * Notify user of connection termination
674 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
675 sop->so_connvc, (int)m, source, err);
678 sscop_abort(sop, "stack memory\n");
683 * Clear receiver buffer
685 sscop_rcvr_drain(sop);
690 sop->so_state = SOS_IDLE;
697 * END PDU / SOS_READY Processor
700 * sop pointer to sscop connection block
701 * m pointer to PDU buffer (without trailer)
702 * trlr pointer to PDU trailer
709 sscop_end_ready(sop, m, trlr)
714 struct end_pdu *ep = (struct end_pdu *)trlr;
718 * Stop data transfer timers
720 sop->so_timer[SSCOP_T_POLL] = 0;
721 sop->so_timer[SSCOP_T_NORESP] = 0;
722 sop->so_timer[SSCOP_T_IDLE] = 0;
723 sop->so_flags &= ~SOF_KEEPALIVE;
728 (void) sscop_send_endak(sop);
733 if (ep->end_type & PT_SOURCE_SSCOP)
734 source = SSCOP_SOURCE_SSCOP;
736 source = SSCOP_SOURCE_USER;
739 * Notify user of connection termination
741 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
742 sop->so_connvc, (int)m, source, err);
745 sscop_abort(sop, "stack memory\n");
750 * Clear out appropriate queues
752 q2110_prep_retrieve(sop);
757 sop->so_state = SOS_IDLE;
764 * ENDAK PDU / SOS_OUTRECOV Processor
767 * sop pointer to sscop connection block
768 * m pointer to PDU buffer (without trailer)
769 * trlr pointer to PDU trailer
776 sscop_endak_outrecov(sop, m, trlr)
784 * Stop retransmit timer
786 sop->so_timer[SSCOP_T_CC] = 0;
789 * Report protocol error
791 sscop_endak_error(sop, m, trlr);
794 * Notify user of connection failure
796 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
797 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
799 sscop_abort(sop, "stack memory\n");
804 * Clear receiver buffer
806 sscop_rcvr_drain(sop);
811 sop->so_state = SOS_IDLE;
818 * RS PDU / SOS_OUTRESYN Processor
821 * sop pointer to sscop connection block
822 * m pointer to PDU buffer (without trailer)
823 * trlr pointer to PDU trailer
830 sscop_rs_outresyn(sop, m, trlr)
835 struct rs_pdu *rp = (struct rs_pdu *)trlr;
839 * If retransmitted RS, ignore it
841 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
847 * Stop retransmit timer
849 sop->so_timer[SSCOP_T_CC] = 0;
852 * Initialize state variables
854 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
855 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
856 q2110_init_state(sop);
864 * Return an ACK to peer
866 (void) sscop_send_rsak(sop);
869 * Notify user of connection resynchronization
871 STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
872 sop->so_connvc, 0, 0, err);
874 sscop_abort(sop, "stack memory\n");
879 * Start data transfer timers
881 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
882 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
885 * OK, we're ready for data
887 sop->so_state = SOS_READY;
890 * See if transmit queues need servicing
892 if (sop->so_flags & SOF_XMITSRVC)
893 sscop_service_xmit(sop);
900 * RS PDU / SOS_INRESYN Processor
903 * sop pointer to sscop connection block
904 * m pointer to PDU buffer (without trailer)
905 * trlr pointer to PDU trailer
912 sscop_rs_inresyn(sop, m, trlr)
917 struct rs_pdu *rp = (struct rs_pdu *)trlr;
920 * If retransmitted RS, ignore it
922 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
928 * Report error condition
930 sscop_rs_error(sop, m, trlr);
937 * RS PDU / SOS_OUTRECOV Processor
940 * sop pointer to sscop connection block
941 * m pointer to PDU buffer (without trailer)
942 * trlr pointer to PDU trailer
949 sscop_rs_outrecov(sop, m, trlr)
954 struct rs_pdu *rp = (struct rs_pdu *)trlr;
958 * If retransmitted RS, report an error
960 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
961 sscop_rs_error(sop, m, trlr);
966 * Stop retransmit timer
968 sop->so_timer[SSCOP_T_CC] = 0;
971 * Initialize transmit window
973 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
976 * Notify user of connection resynchronization
978 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
979 sop->so_connvc, (int)m, 0, err);
982 sscop_abort(sop, "stack memory\n");
987 * Clear receiver buffer
989 sscop_rcvr_drain(sop);
992 * Wait for user response
994 sop->so_state = SOS_INRESYN;
1001 * RS PDU / SOS_READY Processor
1004 * sop pointer to sscop connection block
1005 * m pointer to PDU buffer (without trailer)
1006 * trlr pointer to PDU trailer
1013 sscop_rs_ready(sop, m, trlr)
1018 struct rs_pdu *rp = (struct rs_pdu *)trlr;
1022 * If retransmitted RS, just ACK it
1024 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
1026 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1027 sscop_send_rsak(sop);
1032 * Stop data transfer timers
1034 sop->so_timer[SSCOP_T_POLL] = 0;
1035 sop->so_timer[SSCOP_T_NORESP] = 0;
1036 sop->so_timer[SSCOP_T_IDLE] = 0;
1037 sop->so_flags &= ~SOF_KEEPALIVE;
1040 * Initialize transmit window
1042 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
1045 * Notify user of connection resynchronization
1047 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
1048 sop->so_connvc, (int)m, 0, err);
1051 sscop_abort(sop, "stack memory\n");
1056 * Clear out appropriate queues
1058 q2110_prep_retrieve(sop);
1061 * Wait for user response
1063 sop->so_state = SOS_INRESYN;
1069 * ER PDU / Protocol Error
1072 * sop pointer to sscop connection block
1073 * m pointer to PDU buffer (without trailer)
1074 * trlr pointer to PDU trailer
1081 sscop_er_error(sop, m, trlr)
1088 * Record error condition
1090 sscop_maa_error(sop, 'L');
1098 * ER PDU / SOS_IDLE Processor
1101 * sop pointer to sscop connection block
1102 * m pointer to PDU buffer (without trailer)
1103 * trlr pointer to PDU trailer
1110 sscop_er_idle(sop, m, trlr)
1117 * Record error condition
1119 sscop_er_error(sop, m, trlr);
1122 * Return an END to peer
1124 (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1131 * ER PDU / SOS_OUTRECOV Processor
1134 * sop pointer to sscop connection block
1135 * m pointer to PDU buffer (without trailer)
1136 * trlr pointer to PDU trailer
1143 sscop_er_outrecov(sop, m, trlr)
1148 struct er_pdu *ep = (struct er_pdu *)trlr;
1152 * If retransmitted ER, report an error
1154 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1155 sscop_er_error(sop, m, trlr);
1160 * Stop retransmit timer
1162 sop->so_timer[SSCOP_T_CC] = 0;
1165 * Initialize transmit window
1167 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1170 * Initialize receiver window
1172 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
1182 (void) sscop_send_erak(sop);
1185 * Deliver any outstanding data to user
1187 q2110_deliver_data(sop);
1190 * Notify user of connection recovery
1192 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1193 sop->so_connvc, 0, 0, err);
1195 sscop_abort(sop, "stack memory\n");
1200 * Wait for user response
1202 sop->so_state = SOS_RECOVRSP;
1209 * ER PDU / SOS_RECOVRSP Processor
1212 * sop pointer to sscop connection block
1213 * m pointer to PDU buffer (without trailer)
1214 * trlr pointer to PDU trailer
1221 sscop_er_recovrsp(sop, m, trlr)
1226 struct er_pdu *ep = (struct er_pdu *)trlr;
1229 * If retransmitted ER, just ACK it
1231 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1233 (void) sscop_send_erak(sop);
1238 * Report error condition
1240 sscop_er_error(sop, m, trlr);
1247 * ER PDU / SOS_INRECOV Processor
1250 * sop pointer to sscop connection block
1251 * m pointer to PDU buffer (without trailer)
1252 * trlr pointer to PDU trailer
1259 sscop_er_inrecov(sop, m, trlr)
1264 struct er_pdu *ep = (struct er_pdu *)trlr;
1267 * If retransmitted ER, just ignore it
1269 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1275 * Report error condition
1277 sscop_er_error(sop, m, trlr);
1284 * ER PDU / SOS_READY Processor
1287 * sop pointer to sscop connection block
1288 * m pointer to PDU buffer (without trailer)
1289 * trlr pointer to PDU trailer
1296 sscop_er_ready(sop, m, trlr)
1301 struct er_pdu *ep = (struct er_pdu *)trlr;
1305 * If retransmitted ER, just ACK it
1307 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1309 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1310 sscop_send_erak(sop);
1315 * Stop data transfer timers
1317 sop->so_timer[SSCOP_T_POLL] = 0;
1318 sop->so_timer[SSCOP_T_NORESP] = 0;
1319 sop->so_timer[SSCOP_T_IDLE] = 0;
1320 sop->so_flags &= ~SOF_KEEPALIVE;
1323 * Initialize transmit window
1325 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1333 * Clear out appropriate queues
1335 q2110_prep_recovery(sop);
1338 * Deliver any outstanding data to user
1340 q2110_deliver_data(sop);
1343 * Notify user of connection recovery
1345 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1346 sop->so_connvc, 0, 0, err);
1348 sscop_abort(sop, "stack memory\n");
1353 * Wait for user response
1355 sop->so_state = SOS_INRECOV;
1362 * ERAK PDU / Protocol Error
1365 * sop pointer to sscop connection block
1366 * m pointer to PDU buffer (without trailer)
1367 * trlr pointer to PDU trailer
1374 sscop_erak_error(sop, m, trlr)
1381 * Record error condition
1383 sscop_maa_error(sop, 'M');
1391 * ERAK PDU / SOS_IDLE Processor
1394 * sop pointer to sscop connection block
1395 * m pointer to PDU buffer (without trailer)
1396 * trlr pointer to PDU trailer
1403 sscop_erak_idle(sop, m, trlr)
1410 * Record error condition
1412 sscop_erak_error(sop, m, trlr);
1415 * Return an END to peer
1417 (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1424 * ERAK PDU / SOS_OUTRECOV Processor
1427 * sop pointer to sscop connection block
1428 * m pointer to PDU buffer (without trailer)
1429 * trlr pointer to PDU trailer
1436 sscop_erak_outrecov(sop, m, trlr)
1441 struct erak_pdu *ep = (struct erak_pdu *)trlr;
1445 * Stop retransmit timer
1447 sop->so_timer[SSCOP_T_CC] = 0;
1450 * Initialize transmit window
1452 SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
1460 * Deliver any outstanding data to user
1462 q2110_deliver_data(sop);
1465 * Notify user of connection recovery
1467 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1468 sop->so_connvc, 0, 0, err);
1470 sscop_abort(sop, "stack memory\n");
1475 * Wait for user response
1477 sop->so_state = SOS_RECOVRSP;
1484 * SD PDU / SOS_READY Processor
1487 * sop pointer to sscop connection block
1488 * m pointer to PDU buffer (without trailer)
1489 * trlr pointer to PDU trailer
1496 sscop_sd_ready(sop, m, trlr)
1501 struct sd_pdu *sp = (struct sd_pdu *)trlr;
1502 struct pdu_hdr *php;
1508 * Get PDU sequence number
1510 SEQ_SET(ns, ntohl(sp->sd_ns));
1513 * Ensure that the sequence number fits within the window
1515 if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
1517 * It doesn't, drop received data
1522 * If next highest PDU hasn't reached window end yet,
1523 * then send a USTAT to inform transmitter of this gap
1525 if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) {
1526 (void) sscop_send_ustat(sop, sop->so_rcvmax);
1527 sop->so_rcvhigh = sop->so_rcvmax;
1533 * If this is the next in-sequence PDU, hand it to user
1535 if (ns == sop->so_rcvnext) {
1536 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1537 sop->so_connvc, (int)m, ns, err);
1544 * Bump next expected sequence number
1546 SEQ_INCR(sop->so_rcvnext, 1);
1549 * Slide receive window down
1551 SEQ_INCR(sop->so_rcvmax, 1);
1554 * Is this the highest sequence PDU we've received??
1556 if (ns == sop->so_rcvhigh) {
1558 * Yes, bump the limit and exit
1560 sop->so_rcvhigh = sop->so_rcvnext;
1565 * This is a retransmitted PDU, so see if we have
1566 * more in-sequence PDUs already queued up
1568 while ((php = sop->so_recv_hd) &&
1569 (php->ph_ns == sop->so_rcvnext)) {
1572 * Yup we do, so remove next PDU from queue and
1573 * pass it up to the user as well
1575 sop->so_recv_hd = php->ph_recv_lk;
1576 if (sop->so_recv_hd == NULL)
1577 sop->so_recv_tl = NULL;
1578 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1579 sop->so_connvc, (int)php->ph_buf, php->ph_ns,
1583 * Should never happen, but...
1585 KB_FREEALL(php->ph_buf);
1586 sscop_abort(sop, "stack memory\n");
1591 * Bump next expected sequence number
1593 SEQ_INCR(sop->so_rcvnext, 1);
1596 * Slide receive window down
1598 SEQ_INCR(sop->so_rcvmax, 1);
1602 * Finished with data delivery...
1608 * We're gonna have to queue this PDU, so find space
1609 * for the PDU header
1611 KB_HEADROOM(m, space);
1614 * If there's not enough room in the received buffer,
1615 * allocate & link a new buffer for the header
1617 if (space < sizeof(struct pdu_hdr)) {
1619 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
1624 KB_HEADSET(n, sizeof(struct pdu_hdr));
1633 * We can at least assume/require that the start of
1634 * the user data is aligned. Also note that we don't
1635 * include this header in the buffer len/offset fields.
1637 KB_DATASTART(m, php, struct pdu_hdr *);
1643 * Insert PDU into the receive queue
1645 if (sscop_recv_insert(sop, php)) {
1647 * Oops, a duplicate sequence number PDU is already on
1648 * the queue, somethings wrong here.
1650 sscop_maa_error(sop, 'Q');
1658 * Go into recovery mode
1660 q2110_error_recovery(sop);
1666 * Are we at the high-water mark??
1668 if (ns == sop->so_rcvhigh) {
1670 * Yes, just bump the mark
1672 SEQ_INCR(sop->so_rcvhigh, 1);
1678 * Are we beyond the high-water mark??
1680 if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1682 * Yes, then there's a missing PDU, so inform the transmitter
1684 (void) sscop_send_ustat(sop, ns);
1687 * Update high-water mark
1689 sop->so_rcvhigh = SEQ_ADD(ns, 1);
1697 * POLL PDU / SOS_READY Processor
1700 * sop pointer to sscop connection block
1701 * m pointer to PDU buffer (without trailer)
1702 * trlr pointer to PDU trailer
1709 sscop_poll_ready(sop, m, trlr)
1714 struct poll_pdu *pp = (struct poll_pdu *)trlr;
1720 * If the poll sequence number is less than highest number
1721 * we've already seen, something's wrong
1723 if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1725 * Record error condition
1727 sscop_maa_error(sop, 'Q');
1735 * Go into recovery mode
1737 q2110_error_recovery(sop);
1743 * Set a new "next highest" sequence number expected
1745 if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
1746 SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
1748 sop->so_rcvhigh = sop->so_rcvmax;
1751 * Return a STAT PDU to peer
1753 SEQ_SET(nps, ntohl(pp->poll_nps));
1755 (void) sscop_send_stat(sop, nps);