2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
7 * This Host ATM Research Platform ("HARP") file (the "Software") is
8 * made available by Network Computing Services, Inc. ("NetworkCS")
9 * "AS IS". NetworkCS does not provide maintenance, improvements or
10 * support of any kind.
12 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16 * In no event shall NetworkCS be responsible for any damages, including
17 * but not limited to consequential damages, arising from or relating to
18 * any use of the Software or related support.
20 * Copyright 1994-1998 Network Computing Services, Inc.
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
27 * ATM Forum UNI Support
28 * ---------------------
30 * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs)
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
42 #include <netatm/port.h>
43 #include <netatm/queue.h>
44 #include <netatm/atm.h>
45 #include <netatm/atm_sys.h>
46 #include <netatm/atm_sap.h>
47 #include <netatm/atm_cm.h>
48 #include <netatm/atm_if.h>
49 #include <netatm/atm_stack.h>
50 #include <netatm/atm_pcb.h>
51 #include <netatm/atm_var.h>
53 #include <netatm/uni/sscop.h>
54 #include <netatm/uni/sscop_misc.h>
55 #include <netatm/uni/sscop_pdu.h>
56 #include <netatm/uni/sscop_var.h>
61 static void sscop_bgn_outconn(struct sscop *, KBuffer *, caddr_t);
62 static void sscop_bgn_inconn(struct sscop *, KBuffer *, caddr_t);
63 static void sscop_bgn_ready(struct sscop *, KBuffer *, caddr_t);
64 static void sscop_bgrej_outrecov(struct sscop *, KBuffer *, caddr_t);
65 static void sscop_end_outrecov(struct sscop *, KBuffer *, caddr_t);
66 static void sscop_end_ready(struct sscop *, KBuffer *, caddr_t);
67 static void sscop_endak_outrecov(struct sscop *, KBuffer *, caddr_t);
68 static void sscop_rs_outresyn(struct sscop *, KBuffer *, caddr_t);
69 static void sscop_rs_inresyn(struct sscop *, KBuffer *, caddr_t);
70 static void sscop_rs_outrecov(struct sscop *, KBuffer *, caddr_t);
71 static void sscop_rs_ready(struct sscop *, KBuffer *, caddr_t);
72 static void sscop_er_error(struct sscop *, KBuffer *, caddr_t);
73 static void sscop_er_idle(struct sscop *, KBuffer *, caddr_t);
74 static void sscop_er_outrecov(struct sscop *, KBuffer *, caddr_t);
75 static void sscop_er_recovrsp(struct sscop *, KBuffer *, caddr_t);
76 static void sscop_er_inrecov(struct sscop *, KBuffer *, caddr_t);
77 static void sscop_er_ready(struct sscop *, KBuffer *, caddr_t);
78 static void sscop_erak_error(struct sscop *, KBuffer *, caddr_t);
79 static void sscop_erak_idle(struct sscop *, KBuffer *, caddr_t);
80 static void sscop_erak_outrecov(struct sscop *, KBuffer *, caddr_t);
81 static void sscop_sd_ready(struct sscop *, KBuffer *, caddr_t);
82 static void sscop_poll_ready(struct sscop *, KBuffer *, caddr_t);
86 * PDU type state lookup tables
89 static void (*sscop_bgn_tab[SOS_NUMSTATES])
90 (struct sscop *, KBuffer *, caddr_t) = {
92 sscop_bgn_idle, /* SOS_IDLE */
93 sscop_bgn_outconn, /* SOS_OUTCONN */
94 sscop_bgn_inconn, /* SOS_INCONN */
95 sscop_bgn_outdisc, /* SOS_OUTDISC */
96 sscop_bgn_outresyn, /* SOS_OUTRESYN */
97 sscop_bgn_inresyn, /* SOS_INRESYN */
98 sscop_bgn_inresyn, /* SOS_OUTRECOV */
99 sscop_bgn_inresyn, /* SOS_RECOVRSP */
100 sscop_bgn_inresyn, /* SOS_INRECOV */
101 sscop_bgn_ready, /* SOS_READY */
102 sscop_noop /* SOS_TERM */
106 static void (*sscop_bgak_tab[SOS_NUMSTATES])
107 (struct sscop *, KBuffer *, caddr_t) = {
109 sscop_bgak_idle, /* SOS_IDLE */
110 sscop_bgak_outconn, /* SOS_OUTCONN */
111 sscop_bgak_error, /* SOS_INCONN */
112 sscop_noop, /* SOS_OUTDISC */
113 sscop_noop, /* SOS_OUTRESYN */
114 sscop_bgak_error, /* SOS_INRESYN */
115 sscop_bgak_error, /* SOS_OUTRECOV */
116 sscop_bgak_error, /* SOS_RECOVRSP */
117 sscop_bgak_error, /* SOS_INRECOV */
118 sscop_noop, /* SOS_READY */
119 sscop_noop /* SOS_TERM */
123 static void (*sscop_bgrej_tab[SOS_NUMSTATES])
124 (struct sscop *, KBuffer *, caddr_t) = {
126 sscop_bgrej_error, /* SOS_IDLE */
127 sscop_bgrej_outconn, /* SOS_OUTCONN */
128 sscop_bgrej_inconn, /* SOS_INCONN */
129 sscop_endak_outdisc, /* SOS_OUTDISC */
130 sscop_bgrej_outresyn, /* SOS_OUTRESYN */
131 sscop_bgrej_inconn, /* SOS_INRESYN */
132 sscop_bgrej_outrecov, /* SOS_OUTRECOV */
133 sscop_bgrej_inconn, /* SOS_RECOVRSP */
134 sscop_bgrej_inconn, /* SOS_INRECOV */
135 sscop_bgrej_ready, /* SOS_READY */
136 sscop_noop /* SOS_TERM */
140 static void (*sscop_end_tab[SOS_NUMSTATES])
141 (struct sscop *, KBuffer *, caddr_t) = {
143 sscop_end_idle, /* SOS_IDLE */
144 sscop_noop, /* SOS_OUTCONN */
145 sscop_end_inconn, /* SOS_INCONN */
146 sscop_end_outdisc, /* SOS_OUTDISC */
147 sscop_end_inconn, /* SOS_OUTRESYN */
148 sscop_end_inconn, /* SOS_INRESYN */
149 sscop_end_outrecov, /* SOS_OUTRECOV */
150 sscop_end_inconn, /* SOS_RECOVRSP */
151 sscop_end_inconn, /* SOS_INRECOV */
152 sscop_end_ready, /* SOS_READY */
153 sscop_noop /* SOS_TERM */
157 static void (*sscop_endak_tab[SOS_NUMSTATES])
158 (struct sscop *, KBuffer *, caddr_t) = {
160 sscop_noop, /* SOS_IDLE */
161 sscop_noop, /* SOS_OUTCONN */
162 sscop_endak_inconn, /* SOS_INCONN */
163 sscop_endak_outdisc, /* SOS_OUTDISC */
164 sscop_endak_inconn, /* SOS_OUTRESYN */
165 sscop_endak_inconn, /* SOS_INRESYN */
166 sscop_endak_outrecov, /* SOS_OUTRECOV */
167 sscop_endak_inconn, /* SOS_RECOVRSP */
168 sscop_endak_inconn, /* SOS_INRECOV */
169 sscop_endak_ready, /* SOS_READY */
170 sscop_noop /* SOS_TERM */
174 static void (*sscop_rs_tab[SOS_NUMSTATES])
175 (struct sscop *, KBuffer *, caddr_t) = {
177 sscop_rs_idle, /* SOS_IDLE */
178 sscop_noop, /* SOS_OUTCONN */
179 sscop_rs_error, /* SOS_INCONN */
180 sscop_noop, /* SOS_OUTDISC */
181 sscop_rs_outresyn, /* SOS_OUTRESYN */
182 sscop_rs_inresyn, /* SOS_INRESYN */
183 sscop_rs_outrecov, /* SOS_OUTRECOV */
184 sscop_rs_outrecov, /* SOS_RECOVRSP */
185 sscop_rs_outrecov, /* SOS_INRECOV */
186 sscop_rs_ready, /* SOS_READY */
187 sscop_noop /* SOS_TERM */
191 static void (*sscop_rsak_tab[SOS_NUMSTATES])
192 (struct sscop *, KBuffer *, caddr_t) = {
194 sscop_rsak_idle, /* SOS_IDLE */
195 sscop_noop, /* SOS_OUTCONN */
196 sscop_rsak_error, /* SOS_INCONN */
197 sscop_noop, /* SOS_OUTDISC */
198 sscop_rsak_outresyn, /* SOS_OUTRESYN */
199 sscop_rsak_error, /* SOS_INRESYN */
200 sscop_rsak_error, /* SOS_OUTRECOV */
201 sscop_rsak_error, /* SOS_RECOVRSP */
202 sscop_rsak_error, /* SOS_INRECOV */
203 sscop_noop, /* SOS_READY */
204 sscop_noop /* SOS_TERM */
208 static void (*sscop_er_tab[SOS_NUMSTATES])
209 (struct sscop *, KBuffer *, caddr_t) = {
211 sscop_er_idle, /* SOS_IDLE */
212 sscop_noop, /* SOS_OUTCONN */
213 sscop_er_error, /* SOS_INCONN */
214 sscop_noop, /* SOS_OUTDISC */
215 sscop_noop, /* SOS_OUTRESYN */
216 sscop_er_error, /* SOS_INRESYN */
217 sscop_er_outrecov, /* SOS_OUTRECOV */
218 sscop_er_recovrsp, /* SOS_RECOVRSP */
219 sscop_er_inrecov, /* SOS_INRECOV */
220 sscop_er_ready, /* SOS_READY */
221 sscop_noop /* SOS_TERM */
225 static void (*sscop_erak_tab[SOS_NUMSTATES])
226 (struct sscop *, KBuffer *, caddr_t) = {
228 sscop_erak_idle, /* SOS_IDLE */
229 sscop_noop, /* SOS_OUTCONN */
230 sscop_erak_error, /* SOS_INCONN */
231 sscop_noop, /* SOS_OUTDISC */
232 sscop_noop, /* SOS_OUTRESYN */
233 sscop_erak_error, /* SOS_INRESYN */
234 sscop_erak_outrecov, /* SOS_OUTRECOV */
235 sscop_noop, /* SOS_RECOVRSP */
236 sscop_erak_error, /* SOS_INRECOV */
237 sscop_noop, /* SOS_READY */
238 sscop_noop /* SOS_TERM */
242 static void (*sscop_sd_tab[SOS_NUMSTATES])
243 (struct sscop *, KBuffer *, caddr_t) = {
245 sscop_sd_idle, /* SOS_IDLE */
246 sscop_noop, /* SOS_OUTCONN */
247 sscop_sd_inconn, /* SOS_INCONN */
248 sscop_noop, /* SOS_OUTDISC */
249 sscop_noop, /* SOS_OUTRESYN */
250 sscop_sd_inconn, /* SOS_INRESYN */
251 sscop_noop, /* SOS_OUTRECOV */
252 sscop_noop, /* SOS_RECOVRSP */
253 sscop_sd_inconn, /* SOS_INRECOV */
254 sscop_sd_ready, /* SOS_READY */
255 sscop_noop /* SOS_TERM */
259 static void (*sscop_poll_tab[SOS_NUMSTATES])
260 (struct sscop *, KBuffer *, caddr_t) = {
262 sscop_poll_idle, /* SOS_IDLE */
263 sscop_noop, /* SOS_OUTCONN */
264 sscop_poll_inconn, /* SOS_INCONN */
265 sscop_noop, /* SOS_OUTDISC */
266 sscop_noop, /* SOS_OUTRESYN */
267 sscop_poll_inconn, /* SOS_INRESYN */
268 sscop_noop, /* SOS_OUTRECOV */
269 sscop_noop, /* SOS_RECOVRSP */
270 sscop_poll_inconn, /* SOS_INRECOV */
271 sscop_poll_ready, /* SOS_READY */
272 sscop_noop /* SOS_TERM */
276 static void (*sscop_stat_tab[SOS_NUMSTATES])
277 (struct sscop *, KBuffer *, caddr_t) = {
279 sscop_stat_idle, /* SOS_IDLE */
280 sscop_noop, /* SOS_OUTCONN */
281 sscop_stat_inconn, /* SOS_INCONN */
282 sscop_noop, /* SOS_OUTDISC */
283 sscop_noop, /* SOS_OUTRESYN */
284 sscop_stat_inconn, /* SOS_INRESYN */
285 sscop_noop, /* SOS_OUTRECOV */
286 sscop_stat_inconn, /* SOS_RECOVRSP */
287 sscop_stat_inconn, /* SOS_INRECOV */
288 sscop_stat_ready, /* SOS_READY */
289 sscop_noop /* SOS_TERM */
293 static void (*sscop_ustat_tab[SOS_NUMSTATES])
294 (struct sscop *, KBuffer *, caddr_t) = {
296 sscop_ustat_idle, /* SOS_IDLE */
297 sscop_noop, /* SOS_OUTCONN */
298 sscop_ustat_inconn, /* SOS_INCONN */
299 sscop_noop, /* SOS_OUTDISC */
300 sscop_noop, /* SOS_OUTRESYN */
301 sscop_ustat_inconn, /* SOS_INRESYN */
302 sscop_noop, /* SOS_OUTRECOV */
303 sscop_ustat_inconn, /* SOS_RECOVRSP */
304 sscop_ustat_inconn, /* SOS_INRECOV */
305 sscop_ustat_ready, /* SOS_READY */
306 sscop_noop /* SOS_TERM */
310 static void (*sscop_ud_tab[SOS_NUMSTATES])
311 (struct sscop *, KBuffer *, caddr_t) = {
313 sscop_ud_all, /* SOS_IDLE */
314 sscop_ud_all, /* SOS_OUTCONN */
315 sscop_ud_all, /* SOS_INCONN */
316 sscop_ud_all, /* SOS_OUTDISC */
317 sscop_ud_all, /* SOS_OUTRESYN */
318 sscop_ud_all, /* SOS_INRESYN */
319 sscop_ud_all, /* SOS_OUTRECOV */
320 sscop_ud_all, /* SOS_RECOVRSP */
321 sscop_ud_all, /* SOS_INRECOV */
322 sscop_ud_all, /* SOS_READY */
323 sscop_noop /* SOS_TERM */
327 static void (*sscop_md_tab[SOS_NUMSTATES])
328 (struct sscop *, KBuffer *, caddr_t) = {
330 sscop_md_all, /* SOS_IDLE */
331 sscop_md_all, /* SOS_OUTCONN */
332 sscop_md_all, /* SOS_INCONN */
333 sscop_md_all, /* SOS_OUTDISC */
334 sscop_md_all, /* SOS_OUTRESYN */
335 sscop_md_all, /* SOS_INRESYN */
336 sscop_md_all, /* SOS_OUTRECOV */
337 sscop_md_all, /* SOS_RECOVRSP */
338 sscop_md_all, /* SOS_INRECOV */
339 sscop_md_all, /* SOS_READY */
340 sscop_noop /* SOS_TERM */
345 * PDU type lookup table
347 void (*(*sscop_q2110_pdutab[]))
348 (struct sscop *, KBuffer *, caddr_t) = {
369 * BGN PDU / SOS_OUTCONN Processor
372 * sop pointer to sscop connection block
373 * m pointer to PDU buffer (without trailer)
374 * trlr pointer to PDU trailer
381 sscop_bgn_outconn(sop, m, trlr)
386 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
390 * If retransmitted BGN, ignore it
392 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
398 * Stop retransmit timer
400 sop->so_timer[SSCOP_T_CC] = 0;
403 * Initialize state variables
405 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
406 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
407 q2110_init_state(sop);
410 * Return an ACK to peer
412 (void) sscop_send_bgak(sop);
415 * Notify user of connection establishment
417 STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku,
418 sop->so_connvc, (intptr_t)m, 0, err);
421 sscop_abort(sop, "stack memory\n");
426 * Start data transfer timers
428 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
429 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
432 * OK, we're ready for data
434 sop->so_state = SOS_READY;
437 * See if transmit queues need servicing
439 if (sop->so_flags & SOF_XMITSRVC)
440 sscop_service_xmit(sop);
447 * BGN PDU / SOS_INCONN Processor
450 * sop pointer to sscop connection block
451 * m pointer to PDU buffer (without trailer)
452 * trlr pointer to PDU trailer
459 sscop_bgn_inconn(sop, m, trlr)
464 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
468 * If retransmitted BGN, ignore it
470 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
476 * Initialize transmit window
478 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
481 * First, tell user current connection has been released
483 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
484 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
487 sscop_abort(sop, "stack memory\n");
492 * Now, tell user of new connection establishment
494 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
495 sop->so_connvc, (intptr_t)m, 0, err);
498 sscop_abort(sop, "stack memory\n");
507 * BGN PDU / SOS_READY Processor
510 * sop pointer to sscop connection block
511 * m pointer to PDU buffer (without trailer)
512 * trlr pointer to PDU trailer
519 sscop_bgn_ready(sop, m, trlr)
524 struct bgn_pdu *bp = (struct bgn_pdu *)trlr;
528 * If retransmitted BGN, just ACK it again
530 if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
532 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
533 (void) sscop_send_bgak(sop);
538 * Stop data transfer timers
540 sop->so_timer[SSCOP_T_POLL] = 0;
541 sop->so_timer[SSCOP_T_NORESP] = 0;
542 sop->so_timer[SSCOP_T_IDLE] = 0;
543 sop->so_flags &= ~SOF_KEEPALIVE;
546 * Initialize transmit window
548 SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
551 * Clear out appropriate queues
553 q2110_prep_retrieve(sop);
556 * Tell user current connection has been released
558 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
559 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
562 sscop_abort(sop, "stack memory\n");
567 * Tell user of incoming connection
569 STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
570 sop->so_connvc, (intptr_t)m, 0, err);
573 sscop_abort(sop, "stack memory\n");
578 * Wait for user's response
580 sop->so_state = SOS_INCONN;
587 * BGREJ PDU / SOS_OUTRECOV Processor
590 * sop pointer to sscop connection block
591 * m pointer to PDU buffer (without trailer)
592 * trlr pointer to PDU trailer
599 sscop_bgrej_outrecov(sop, m, trlr)
607 * Stop retransmit timer
609 sop->so_timer[SSCOP_T_CC] = 0;
612 * Report protocol error
614 sscop_bgrej_error(sop, m, trlr);
617 * Notify user of connection failure
619 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
620 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
622 sscop_abort(sop, "stack memory\n");
627 * Clear receiver buffer
629 sscop_rcvr_drain(sop);
634 sop->so_state = SOS_IDLE;
641 * END PDU / SOS_OUTRECOV Processor
644 * sop pointer to sscop connection block
645 * m pointer to PDU buffer (without trailer)
646 * trlr pointer to PDU trailer
653 sscop_end_outrecov(sop, m, trlr)
658 struct end_pdu *ep = (struct end_pdu *)trlr;
662 * Stop retransmit timer
664 sop->so_timer[SSCOP_T_CC] = 0;
669 (void) sscop_send_endak(sop);
674 if (ep->end_type & PT_SOURCE_SSCOP)
675 source = SSCOP_SOURCE_SSCOP;
677 source = SSCOP_SOURCE_USER;
680 * Notify user of connection termination
682 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
683 sop->so_connvc, (intptr_t)m, source, err);
686 sscop_abort(sop, "stack memory\n");
691 * Clear receiver buffer
693 sscop_rcvr_drain(sop);
698 sop->so_state = SOS_IDLE;
705 * END PDU / SOS_READY Processor
708 * sop pointer to sscop connection block
709 * m pointer to PDU buffer (without trailer)
710 * trlr pointer to PDU trailer
717 sscop_end_ready(sop, m, trlr)
722 struct end_pdu *ep = (struct end_pdu *)trlr;
726 * Stop data transfer timers
728 sop->so_timer[SSCOP_T_POLL] = 0;
729 sop->so_timer[SSCOP_T_NORESP] = 0;
730 sop->so_timer[SSCOP_T_IDLE] = 0;
731 sop->so_flags &= ~SOF_KEEPALIVE;
736 (void) sscop_send_endak(sop);
741 if (ep->end_type & PT_SOURCE_SSCOP)
742 source = SSCOP_SOURCE_SSCOP;
744 source = SSCOP_SOURCE_USER;
747 * Notify user of connection termination
749 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
750 sop->so_connvc, (intptr_t)m, source, err);
753 sscop_abort(sop, "stack memory\n");
758 * Clear out appropriate queues
760 q2110_prep_retrieve(sop);
765 sop->so_state = SOS_IDLE;
772 * ENDAK PDU / SOS_OUTRECOV Processor
775 * sop pointer to sscop connection block
776 * m pointer to PDU buffer (without trailer)
777 * trlr pointer to PDU trailer
784 sscop_endak_outrecov(sop, m, trlr)
792 * Stop retransmit timer
794 sop->so_timer[SSCOP_T_CC] = 0;
797 * Report protocol error
799 sscop_endak_error(sop, m, trlr);
802 * Notify user of connection failure
804 STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
805 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
807 sscop_abort(sop, "stack memory\n");
812 * Clear receiver buffer
814 sscop_rcvr_drain(sop);
819 sop->so_state = SOS_IDLE;
826 * RS PDU / SOS_OUTRESYN Processor
829 * sop pointer to sscop connection block
830 * m pointer to PDU buffer (without trailer)
831 * trlr pointer to PDU trailer
838 sscop_rs_outresyn(sop, m, trlr)
843 struct rs_pdu *rp = (struct rs_pdu *)trlr;
847 * If retransmitted RS, ignore it
849 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
855 * Stop retransmit timer
857 sop->so_timer[SSCOP_T_CC] = 0;
860 * Initialize state variables
862 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
863 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
864 q2110_init_state(sop);
872 * Return an ACK to peer
874 (void) sscop_send_rsak(sop);
877 * Notify user of connection resynchronization
879 STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku,
880 sop->so_connvc, 0, 0, err);
882 sscop_abort(sop, "stack memory\n");
887 * Start data transfer timers
889 sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
890 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
893 * OK, we're ready for data
895 sop->so_state = SOS_READY;
898 * See if transmit queues need servicing
900 if (sop->so_flags & SOF_XMITSRVC)
901 sscop_service_xmit(sop);
908 * RS PDU / SOS_INRESYN Processor
911 * sop pointer to sscop connection block
912 * m pointer to PDU buffer (without trailer)
913 * trlr pointer to PDU trailer
920 sscop_rs_inresyn(sop, m, trlr)
925 struct rs_pdu *rp = (struct rs_pdu *)trlr;
928 * If retransmitted RS, ignore it
930 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
936 * Report error condition
938 sscop_rs_error(sop, m, trlr);
945 * RS PDU / SOS_OUTRECOV Processor
948 * sop pointer to sscop connection block
949 * m pointer to PDU buffer (without trailer)
950 * trlr pointer to PDU trailer
957 sscop_rs_outrecov(sop, m, trlr)
962 struct rs_pdu *rp = (struct rs_pdu *)trlr;
966 * If retransmitted RS, report an error
968 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
969 sscop_rs_error(sop, m, trlr);
974 * Stop retransmit timer
976 sop->so_timer[SSCOP_T_CC] = 0;
979 * Initialize transmit window
981 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
984 * Notify user of connection resynchronization
986 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
987 sop->so_connvc, (intptr_t)m, 0, err);
990 sscop_abort(sop, "stack memory\n");
995 * Clear receiver buffer
997 sscop_rcvr_drain(sop);
1000 * Wait for user response
1002 sop->so_state = SOS_INRESYN;
1009 * RS PDU / SOS_READY Processor
1012 * sop pointer to sscop connection block
1013 * m pointer to PDU buffer (without trailer)
1014 * trlr pointer to PDU trailer
1021 sscop_rs_ready(sop, m, trlr)
1026 struct rs_pdu *rp = (struct rs_pdu *)trlr;
1030 * If retransmitted RS, just ACK it
1032 if (sscop_is_rexmit(sop, rp->rs_nsq)) {
1034 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1035 sscop_send_rsak(sop);
1040 * Stop data transfer timers
1042 sop->so_timer[SSCOP_T_POLL] = 0;
1043 sop->so_timer[SSCOP_T_NORESP] = 0;
1044 sop->so_timer[SSCOP_T_IDLE] = 0;
1045 sop->so_flags &= ~SOF_KEEPALIVE;
1048 * Initialize transmit window
1050 SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
1053 * Notify user of connection resynchronization
1055 STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku,
1056 sop->so_connvc, (intptr_t)m, 0, err);
1059 sscop_abort(sop, "stack memory\n");
1064 * Clear out appropriate queues
1066 q2110_prep_retrieve(sop);
1069 * Wait for user response
1071 sop->so_state = SOS_INRESYN;
1077 * ER PDU / Protocol Error
1080 * sop pointer to sscop connection block
1081 * m pointer to PDU buffer (without trailer)
1082 * trlr pointer to PDU trailer
1089 sscop_er_error(sop, m, trlr)
1096 * Record error condition
1098 sscop_maa_error(sop, 'L');
1106 * ER PDU / SOS_IDLE Processor
1109 * sop pointer to sscop connection block
1110 * m pointer to PDU buffer (without trailer)
1111 * trlr pointer to PDU trailer
1118 sscop_er_idle(sop, m, trlr)
1125 * Record error condition
1127 sscop_er_error(sop, m, trlr);
1130 * Return an END to peer
1132 (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1139 * ER PDU / SOS_OUTRECOV Processor
1142 * sop pointer to sscop connection block
1143 * m pointer to PDU buffer (without trailer)
1144 * trlr pointer to PDU trailer
1151 sscop_er_outrecov(sop, m, trlr)
1156 struct er_pdu *ep = (struct er_pdu *)trlr;
1160 * If retransmitted ER, report an error
1162 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1163 sscop_er_error(sop, m, trlr);
1168 * Stop retransmit timer
1170 sop->so_timer[SSCOP_T_CC] = 0;
1173 * Initialize transmit window
1175 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1178 * Initialize receiver window
1180 SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
1190 (void) sscop_send_erak(sop);
1193 * Deliver any outstanding data to user
1195 q2110_deliver_data(sop);
1198 * Notify user of connection recovery
1200 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1201 sop->so_connvc, 0, 0, err);
1203 sscop_abort(sop, "stack memory\n");
1208 * Wait for user response
1210 sop->so_state = SOS_RECOVRSP;
1217 * ER PDU / SOS_RECOVRSP Processor
1220 * sop pointer to sscop connection block
1221 * m pointer to PDU buffer (without trailer)
1222 * trlr pointer to PDU trailer
1229 sscop_er_recovrsp(sop, m, trlr)
1234 struct er_pdu *ep = (struct er_pdu *)trlr;
1237 * If retransmitted ER, just ACK it
1239 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1241 (void) sscop_send_erak(sop);
1246 * Report error condition
1248 sscop_er_error(sop, m, trlr);
1255 * ER PDU / SOS_INRECOV Processor
1258 * sop pointer to sscop connection block
1259 * m pointer to PDU buffer (without trailer)
1260 * trlr pointer to PDU trailer
1267 sscop_er_inrecov(sop, m, trlr)
1272 struct er_pdu *ep = (struct er_pdu *)trlr;
1275 * If retransmitted ER, just ignore it
1277 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1283 * Report error condition
1285 sscop_er_error(sop, m, trlr);
1292 * ER PDU / SOS_READY Processor
1295 * sop pointer to sscop connection block
1296 * m pointer to PDU buffer (without trailer)
1297 * trlr pointer to PDU trailer
1304 sscop_er_ready(sop, m, trlr)
1309 struct er_pdu *ep = (struct er_pdu *)trlr;
1313 * If retransmitted ER, just ACK it
1315 if (sscop_is_rexmit(sop, ep->er_nsq)) {
1317 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1318 sscop_send_erak(sop);
1323 * Stop data transfer timers
1325 sop->so_timer[SSCOP_T_POLL] = 0;
1326 sop->so_timer[SSCOP_T_NORESP] = 0;
1327 sop->so_timer[SSCOP_T_IDLE] = 0;
1328 sop->so_flags &= ~SOF_KEEPALIVE;
1331 * Initialize transmit window
1333 SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1341 * Clear out appropriate queues
1343 q2110_prep_recovery(sop);
1346 * Deliver any outstanding data to user
1348 q2110_deliver_data(sop);
1351 * Notify user of connection recovery
1353 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1354 sop->so_connvc, 0, 0, err);
1356 sscop_abort(sop, "stack memory\n");
1361 * Wait for user response
1363 sop->so_state = SOS_INRECOV;
1370 * ERAK PDU / Protocol Error
1373 * sop pointer to sscop connection block
1374 * m pointer to PDU buffer (without trailer)
1375 * trlr pointer to PDU trailer
1382 sscop_erak_error(sop, m, trlr)
1389 * Record error condition
1391 sscop_maa_error(sop, 'M');
1399 * ERAK PDU / SOS_IDLE Processor
1402 * sop pointer to sscop connection block
1403 * m pointer to PDU buffer (without trailer)
1404 * trlr pointer to PDU trailer
1411 sscop_erak_idle(sop, m, trlr)
1418 * Record error condition
1420 sscop_erak_error(sop, m, trlr);
1423 * Return an END to peer
1425 (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1432 * ERAK PDU / SOS_OUTRECOV Processor
1435 * sop pointer to sscop connection block
1436 * m pointer to PDU buffer (without trailer)
1437 * trlr pointer to PDU trailer
1444 sscop_erak_outrecov(sop, m, trlr)
1449 struct erak_pdu *ep = (struct erak_pdu *)trlr;
1453 * Stop retransmit timer
1455 sop->so_timer[SSCOP_T_CC] = 0;
1458 * Initialize transmit window
1460 SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
1468 * Deliver any outstanding data to user
1470 q2110_deliver_data(sop);
1473 * Notify user of connection recovery
1475 STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku,
1476 sop->so_connvc, 0, 0, err);
1478 sscop_abort(sop, "stack memory\n");
1483 * Wait for user response
1485 sop->so_state = SOS_RECOVRSP;
1492 * SD PDU / SOS_READY Processor
1495 * sop pointer to sscop connection block
1496 * m pointer to PDU buffer (without trailer)
1497 * trlr pointer to PDU trailer
1504 sscop_sd_ready(sop, m, trlr)
1509 struct sd_pdu *sp = (struct sd_pdu *)trlr;
1510 struct pdu_hdr *php;
1516 * Get PDU sequence number
1518 SEQ_SET(ns, ntohl(sp->sd_ns));
1521 * Ensure that the sequence number fits within the window
1523 if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
1525 * It doesn't, drop received data
1530 * If next highest PDU hasn't reached window end yet,
1531 * then send a USTAT to inform transmitter of this gap
1533 if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) {
1534 (void) sscop_send_ustat(sop, sop->so_rcvmax);
1535 sop->so_rcvhigh = sop->so_rcvmax;
1541 * If this is the next in-sequence PDU, hand it to user
1543 if (ns == sop->so_rcvnext) {
1544 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1545 sop->so_connvc, (intptr_t)m, ns, err);
1552 * Bump next expected sequence number
1554 SEQ_INCR(sop->so_rcvnext, 1);
1557 * Slide receive window down
1559 SEQ_INCR(sop->so_rcvmax, 1);
1562 * Is this the highest sequence PDU we've received??
1564 if (ns == sop->so_rcvhigh) {
1566 * Yes, bump the limit and exit
1568 sop->so_rcvhigh = sop->so_rcvnext;
1573 * This is a retransmitted PDU, so see if we have
1574 * more in-sequence PDUs already queued up
1576 while ((php = sop->so_recv_hd) &&
1577 (php->ph_ns == sop->so_rcvnext)) {
1580 * Yup we do, so remove next PDU from queue and
1581 * pass it up to the user as well
1583 sop->so_recv_hd = php->ph_recv_lk;
1584 if (sop->so_recv_hd == NULL)
1585 sop->so_recv_tl = NULL;
1586 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1587 sop->so_connvc, (intptr_t)php->ph_buf,
1591 * Should never happen, but...
1593 KB_FREEALL(php->ph_buf);
1594 sscop_abort(sop, "stack memory\n");
1599 * Bump next expected sequence number
1601 SEQ_INCR(sop->so_rcvnext, 1);
1604 * Slide receive window down
1606 SEQ_INCR(sop->so_rcvmax, 1);
1610 * Finished with data delivery...
1616 * We're gonna have to queue this PDU, so find space
1617 * for the PDU header
1619 KB_HEADROOM(m, space);
1622 * If there's not enough room in the received buffer,
1623 * allocate & link a new buffer for the header
1625 if (space < sizeof(struct pdu_hdr)) {
1627 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
1632 KB_HEADSET(n, sizeof(struct pdu_hdr));
1641 * We can at least assume/require that the start of
1642 * the user data is aligned. Also note that we don't
1643 * include this header in the buffer len/offset fields.
1645 KB_DATASTART(m, php, struct pdu_hdr *);
1651 * Insert PDU into the receive queue
1653 if (sscop_recv_insert(sop, php)) {
1655 * Oops, a duplicate sequence number PDU is already on
1656 * the queue, somethings wrong here.
1658 sscop_maa_error(sop, 'Q');
1666 * Go into recovery mode
1668 q2110_error_recovery(sop);
1674 * Are we at the high-water mark??
1676 if (ns == sop->so_rcvhigh) {
1678 * Yes, just bump the mark
1680 SEQ_INCR(sop->so_rcvhigh, 1);
1686 * Are we beyond the high-water mark??
1688 if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1690 * Yes, then there's a missing PDU, so inform the transmitter
1692 (void) sscop_send_ustat(sop, ns);
1695 * Update high-water mark
1697 sop->so_rcvhigh = SEQ_ADD(ns, 1);
1705 * POLL PDU / SOS_READY Processor
1708 * sop pointer to sscop connection block
1709 * m pointer to PDU buffer (without trailer)
1710 * trlr pointer to PDU trailer
1717 sscop_poll_ready(sop, m, trlr)
1722 struct poll_pdu *pp = (struct poll_pdu *)trlr;
1725 pp->poll_ns = ntohl(pp->poll_ns);
1728 * If the poll sequence number is less than highest number
1729 * we've already seen, something's wrong
1731 if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1733 * Record error condition
1735 sscop_maa_error(sop, 'Q');
1743 * Go into recovery mode
1745 q2110_error_recovery(sop);
1751 * Set a new "next highest" sequence number expected
1753 if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
1754 SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
1756 sop->so_rcvhigh = sop->so_rcvmax;
1759 * Return a STAT PDU to peer
1761 SEQ_SET(nps, ntohl(pp->poll_nps));
1763 (void) sscop_send_stat(sop, nps);