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>
41 #include "sscop_misc.h"
42 #include "sscop_pdu.h"
43 #include "sscop_var.h"
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
76 static void (*sscop_bgn_tab
[SOS_NUMSTATES
])
77 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
93 static void (*sscop_bgak_tab
[SOS_NUMSTATES
])
94 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
110 static void (*sscop_bgrej_tab
[SOS_NUMSTATES
])
111 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
127 static void (*sscop_end_tab
[SOS_NUMSTATES
])
128 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
144 static void (*sscop_endak_tab
[SOS_NUMSTATES
])
145 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
161 static void (*sscop_rs_tab
[SOS_NUMSTATES
])
162 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
178 static void (*sscop_rsak_tab
[SOS_NUMSTATES
])
179 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
195 static void (*sscop_er_tab
[SOS_NUMSTATES
])
196 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
212 static void (*sscop_erak_tab
[SOS_NUMSTATES
])
213 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
229 static void (*sscop_sd_tab
[SOS_NUMSTATES
])
230 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
246 static void (*sscop_poll_tab
[SOS_NUMSTATES
])
247 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
263 static void (*sscop_stat_tab
[SOS_NUMSTATES
])
264 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
280 static void (*sscop_ustat_tab
[SOS_NUMSTATES
])
281 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
297 static void (*sscop_ud_tab
[SOS_NUMSTATES
])
298 (struct sscop
*, KBuffer
*, caddr_t
) = {
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 */
314 static void (*sscop_md_tab
[SOS_NUMSTATES
])
315 (struct sscop
*, KBuffer
*, caddr_t
) = {
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
) = {
356 * BGN PDU / SOS_OUTCONN Processor
359 * sop pointer to sscop connection block
360 * m pointer to PDU buffer (without trailer)
361 * trlr pointer to PDU trailer
368 sscop_bgn_outconn(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
370 struct bgn_pdu
*bp
= (struct bgn_pdu
*)trlr
;
374 * If retransmitted BGN, ignore it
376 if (sscop_is_rexmit(sop
, bp
->bgn_nsq
)) {
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
);
405 sscop_abort(sop
, "stack memory\n");
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
);
431 * BGN PDU / SOS_INCONN Processor
434 * sop pointer to sscop connection block
435 * m pointer to PDU buffer (without trailer)
436 * trlr pointer to PDU trailer
443 sscop_bgn_inconn(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
445 struct bgn_pdu
*bp
= (struct bgn_pdu
*)trlr
;
449 * If retransmitted BGN, ignore it
451 if (sscop_is_rexmit(sop
, bp
->bgn_nsq
)) {
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
);
468 sscop_abort(sop
, "stack memory\n");
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
);
479 sscop_abort(sop
, "stack memory\n");
488 * BGN PDU / SOS_READY Processor
491 * sop pointer to sscop connection block
492 * m pointer to PDU buffer (without trailer)
493 * trlr pointer to PDU trailer
500 sscop_bgn_ready(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
502 struct bgn_pdu
*bp
= (struct bgn_pdu
*)trlr
;
506 * If retransmitted BGN, just ACK it again
508 if (sscop_is_rexmit(sop
, bp
->bgn_nsq
)) {
510 sop
->so_timer
[SSCOP_T_NORESP
] = sop
->so_parm
.sp_timeresp
;
511 sscop_send_bgak(sop
);
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
);
540 sscop_abort(sop
, "stack memory\n");
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
);
551 sscop_abort(sop
, "stack memory\n");
556 * Wait for user's response
558 sop
->so_state
= SOS_INCONN
;
565 * BGREJ PDU / SOS_OUTRECOV Processor
568 * sop pointer to sscop connection block
569 * m pointer to PDU buffer (without trailer)
570 * trlr pointer to PDU trailer
577 sscop_bgrej_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
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
);
597 sscop_abort(sop
, "stack memory\n");
602 * Clear receiver buffer
604 sscop_rcvr_drain(sop
);
609 sop
->so_state
= SOS_IDLE
;
616 * END PDU / SOS_OUTRECOV Processor
619 * sop pointer to sscop connection block
620 * m pointer to PDU buffer (without trailer)
621 * trlr pointer to PDU trailer
628 sscop_end_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
630 struct end_pdu
*ep
= (struct end_pdu
*)trlr
;
634 * Stop retransmit timer
636 sop
->so_timer
[SSCOP_T_CC
] = 0;
641 sscop_send_endak(sop
);
646 if (ep
->end_type
& PT_SOURCE_SSCOP
)
647 source
= SSCOP_SOURCE_SSCOP
;
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
);
658 sscop_abort(sop
, "stack memory\n");
663 * Clear receiver buffer
665 sscop_rcvr_drain(sop
);
670 sop
->so_state
= SOS_IDLE
;
677 * END PDU / SOS_READY Processor
680 * sop pointer to sscop connection block
681 * m pointer to PDU buffer (without trailer)
682 * trlr pointer to PDU trailer
689 sscop_end_ready(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
691 struct end_pdu
*ep
= (struct end_pdu
*)trlr
;
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
;
705 sscop_send_endak(sop
);
710 if (ep
->end_type
& PT_SOURCE_SSCOP
)
711 source
= SSCOP_SOURCE_SSCOP
;
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
);
722 sscop_abort(sop
, "stack memory\n");
727 * Clear out appropriate queues
729 q2110_prep_retrieve(sop
);
734 sop
->so_state
= SOS_IDLE
;
741 * ENDAK PDU / SOS_OUTRECOV Processor
744 * sop pointer to sscop connection block
745 * m pointer to PDU buffer (without trailer)
746 * trlr pointer to PDU trailer
753 sscop_endak_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
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
);
773 sscop_abort(sop
, "stack memory\n");
778 * Clear receiver buffer
780 sscop_rcvr_drain(sop
);
785 sop
->so_state
= SOS_IDLE
;
792 * RS PDU / SOS_OUTRESYN Processor
795 * sop pointer to sscop connection block
796 * m pointer to PDU buffer (without trailer)
797 * trlr pointer to PDU trailer
804 sscop_rs_outresyn(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
806 struct rs_pdu
*rp
= (struct rs_pdu
*)trlr
;
810 * If retransmitted RS, ignore it
812 if (sscop_is_rexmit(sop
, rp
->rs_nsq
)) {
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
);
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
);
845 sscop_abort(sop
, "stack memory\n");
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
);
871 * RS PDU / SOS_INRESYN Processor
874 * sop pointer to sscop connection block
875 * m pointer to PDU buffer (without trailer)
876 * trlr pointer to PDU trailer
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
)) {
896 * Report error condition
898 sscop_rs_error(sop
, m
, trlr
);
905 * RS PDU / SOS_OUTRECOV Processor
908 * sop pointer to sscop connection block
909 * m pointer to PDU buffer (without trailer)
910 * trlr pointer to PDU trailer
917 sscop_rs_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
919 struct rs_pdu
*rp
= (struct rs_pdu
*)trlr
;
923 * If retransmitted RS, report an error
925 if (sscop_is_rexmit(sop
, rp
->rs_nsq
)) {
926 sscop_rs_error(sop
, m
, trlr
);
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
);
947 sscop_abort(sop
, "stack memory\n");
952 * Clear receiver buffer
954 sscop_rcvr_drain(sop
);
957 * Wait for user response
959 sop
->so_state
= SOS_INRESYN
;
966 * RS PDU / SOS_READY Processor
969 * sop pointer to sscop connection block
970 * m pointer to PDU buffer (without trailer)
971 * trlr pointer to PDU trailer
978 sscop_rs_ready(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
980 struct rs_pdu
*rp
= (struct rs_pdu
*)trlr
;
984 * If retransmitted RS, just ACK it
986 if (sscop_is_rexmit(sop
, rp
->rs_nsq
)) {
988 sop
->so_timer
[SSCOP_T_NORESP
] = sop
->so_parm
.sp_timeresp
;
989 sscop_send_rsak(sop
);
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
);
1013 sscop_abort(sop
, "stack memory\n");
1018 * Clear out appropriate queues
1020 q2110_prep_retrieve(sop
);
1023 * Wait for user response
1025 sop
->so_state
= SOS_INRESYN
;
1031 * ER PDU / Protocol Error
1034 * sop pointer to sscop connection block
1035 * m pointer to PDU buffer (without trailer)
1036 * trlr pointer to PDU trailer
1043 sscop_er_error(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1047 * Record error condition
1049 sscop_maa_error(sop
, 'L');
1057 * ER PDU / SOS_IDLE Processor
1060 * sop pointer to sscop connection block
1061 * m pointer to PDU buffer (without trailer)
1062 * trlr pointer to PDU trailer
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
);
1087 * ER PDU / SOS_OUTRECOV Processor
1090 * sop pointer to sscop connection block
1091 * m pointer to PDU buffer (without trailer)
1092 * trlr pointer to PDU trailer
1099 sscop_er_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1101 struct er_pdu
*ep
= (struct er_pdu
*)trlr
;
1105 * If retransmitted ER, report an error
1107 if (sscop_is_rexmit(sop
, ep
->er_nsq
)) {
1108 sscop_er_error(sop
, m
, trlr
);
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
);
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
);
1148 sscop_abort(sop
, "stack memory\n");
1153 * Wait for user response
1155 sop
->so_state
= SOS_RECOVRSP
;
1162 * ER PDU / SOS_RECOVRSP Processor
1165 * sop pointer to sscop connection block
1166 * m pointer to PDU buffer (without trailer)
1167 * trlr pointer to PDU trailer
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
)) {
1183 sscop_send_erak(sop
);
1188 * Report error condition
1190 sscop_er_error(sop
, m
, trlr
);
1197 * ER PDU / SOS_INRECOV Processor
1200 * sop pointer to sscop connection block
1201 * m pointer to PDU buffer (without trailer)
1202 * trlr pointer to PDU trailer
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
)) {
1222 * Report error condition
1224 sscop_er_error(sop
, m
, trlr
);
1231 * ER PDU / SOS_READY Processor
1234 * sop pointer to sscop connection block
1235 * m pointer to PDU buffer (without trailer)
1236 * trlr pointer to PDU trailer
1243 sscop_er_ready(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1245 struct er_pdu
*ep
= (struct er_pdu
*)trlr
;
1249 * If retransmitted ER, just ACK it
1251 if (sscop_is_rexmit(sop
, ep
->er_nsq
)) {
1253 sop
->so_timer
[SSCOP_T_NORESP
] = sop
->so_parm
.sp_timeresp
;
1254 sscop_send_erak(sop
);
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
));
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
);
1292 sscop_abort(sop
, "stack memory\n");
1297 * Wait for user response
1299 sop
->so_state
= SOS_INRECOV
;
1306 * ERAK PDU / Protocol Error
1309 * sop pointer to sscop connection block
1310 * m pointer to PDU buffer (without trailer)
1311 * trlr pointer to PDU trailer
1318 sscop_erak_error(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1322 * Record error condition
1324 sscop_maa_error(sop
, 'M');
1332 * ERAK PDU / SOS_IDLE Processor
1335 * sop pointer to sscop connection block
1336 * m pointer to PDU buffer (without trailer)
1337 * trlr pointer to PDU trailer
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
);
1362 * ERAK PDU / SOS_OUTRECOV Processor
1365 * sop pointer to sscop connection block
1366 * m pointer to PDU buffer (without trailer)
1367 * trlr pointer to PDU trailer
1374 sscop_erak_outrecov(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1376 struct erak_pdu
*ep
= (struct erak_pdu
*)trlr
;
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
));
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
);
1405 sscop_abort(sop
, "stack memory\n");
1410 * Wait for user response
1412 sop
->so_state
= SOS_RECOVRSP
;
1419 * SD PDU / SOS_READY Processor
1422 * sop pointer to sscop connection block
1423 * m pointer to PDU buffer (without trailer)
1424 * trlr pointer to PDU trailer
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
;
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
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
;
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
);
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
;
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
,
1515 * Should never happen, but...
1517 KB_FREEALL(php
->ph_buf
);
1518 sscop_abort(sop
, "stack memory\n");
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...
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
);
1556 KB_HEADSET(n
, sizeof(struct pdu_hdr
));
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
*);
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');
1590 * Go into recovery mode
1592 q2110_error_recovery(sop
);
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);
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);
1629 * POLL PDU / SOS_READY Processor
1632 * sop pointer to sscop connection block
1633 * m pointer to PDU buffer (without trailer)
1634 * trlr pointer to PDU trailer
1641 sscop_poll_ready(struct sscop
*sop
, KBuffer
*m
, caddr_t trlr
)
1643 struct poll_pdu
*pp
= (struct poll_pdu
*)trlr
;
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');
1664 * Go into recovery mode
1666 q2110_error_recovery(sop
);
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
);
1677 sop
->so_rcvhigh
= sop
->so_rcvmax
;
1680 * Return a STAT PDU to peer
1682 SEQ_SET(nps
, ntohl(pp
->poll_nps
));
1684 sscop_send_stat(sop
, nps
);