]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/netatm/uni/q2110_sigcpcs.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / netatm / uni / q2110_sigcpcs.c
1 /*-
2  * ===================================
3  * HARP  |  Host ATM Research Platform
4  * ===================================
5  *
6  *
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.
11  *
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.
19  *
20  * Copyright 1994-1998 Network Computing Services, Inc.
21  *
22  * Copies of this Software may be made, however, the above copyright
23  * notice must be reproduced on all copies.
24  */
25
26 /*
27  * ATM Forum UNI Support
28  * ---------------------
29  *
30  * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs)
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <net/if.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>
52
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>
57
58 /*
59  * Local functions
60  */
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);
83
84
85 /*
86  * PDU type state lookup tables
87  */
88 /* BGN PDU */
89 static void     (*sscop_bgn_tab[SOS_NUMSTATES])
90                                 (struct sscop *, KBuffer *, caddr_t) = {
91                         NULL,                   /* SOS_INST */
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 */
103 };
104
105 /* BGAK PDU */
106 static void     (*sscop_bgak_tab[SOS_NUMSTATES])
107                                 (struct sscop *, KBuffer *, caddr_t) = {
108                         NULL,                   /* SOS_INST */
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 */
120 };
121
122 /* BGREJ PDU */
123 static void     (*sscop_bgrej_tab[SOS_NUMSTATES])
124                                 (struct sscop *, KBuffer *, caddr_t) = {
125                         NULL,                   /* SOS_INST */
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 */
137 };
138
139 /* END PDU */
140 static void     (*sscop_end_tab[SOS_NUMSTATES])
141                                 (struct sscop *, KBuffer *, caddr_t) = {
142                         NULL,                   /* SOS_INST */
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 */
154 };
155
156 /* ENDAK PDU */
157 static void     (*sscop_endak_tab[SOS_NUMSTATES])
158                                 (struct sscop *, KBuffer *, caddr_t) = {
159                         NULL,                   /* SOS_INST */
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 */
171 };
172
173 /* RS PDU */
174 static void     (*sscop_rs_tab[SOS_NUMSTATES])
175                                 (struct sscop *, KBuffer *, caddr_t) = {
176                         NULL,                   /* SOS_INST */
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 */
188 };
189
190 /* RSAK PDU */
191 static void     (*sscop_rsak_tab[SOS_NUMSTATES])
192                                 (struct sscop *, KBuffer *, caddr_t) = {
193                         NULL,                   /* SOS_INST */
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 */
205 };
206
207 /* ER PDU */
208 static void     (*sscop_er_tab[SOS_NUMSTATES])
209                                 (struct sscop *, KBuffer *, caddr_t) = {
210                         NULL,                   /* SOS_INST */
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 */
222 };
223
224 /* ERAK PDU */
225 static void     (*sscop_erak_tab[SOS_NUMSTATES])
226                                 (struct sscop *, KBuffer *, caddr_t) = {
227                         NULL,                   /* SOS_INST */
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 */
239 };
240
241 /* SD PDU */
242 static void     (*sscop_sd_tab[SOS_NUMSTATES])
243                                 (struct sscop *, KBuffer *, caddr_t) = {
244                         NULL,                   /* SOS_INST */
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 */
256 };
257
258 /* POLL PDU */
259 static void     (*sscop_poll_tab[SOS_NUMSTATES])
260                                 (struct sscop *, KBuffer *, caddr_t) = {
261                         NULL,                   /* SOS_INST */
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 */
273 };
274
275 /* STAT PDU */
276 static void     (*sscop_stat_tab[SOS_NUMSTATES])
277                                 (struct sscop *, KBuffer *, caddr_t) = {
278                         NULL,                   /* SOS_INST */
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 */
290 };
291
292 /* USTAT PDU */
293 static void     (*sscop_ustat_tab[SOS_NUMSTATES])
294                                 (struct sscop *, KBuffer *, caddr_t) = {
295                         NULL,                   /* SOS_INST */
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 */
307 };
308
309 /* UD PDU */
310 static void     (*sscop_ud_tab[SOS_NUMSTATES])
311                                 (struct sscop *, KBuffer *, caddr_t) = {
312                         NULL,                   /* SOS_INST */
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 */
324 };
325
326 /* MD PDU */
327 static void     (*sscop_md_tab[SOS_NUMSTATES])
328                                 (struct sscop *, KBuffer *, caddr_t) = {
329                         NULL,                   /* SOS_INST */
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 */
341 };
342
343
344 /*
345  * PDU type lookup table
346  */
347 void    (*(*sscop_q2110_pdutab[]))
348                                 (struct sscop *, KBuffer *, caddr_t) = {
349                 NULL,
350                 sscop_bgn_tab,
351                 sscop_bgak_tab,
352                 sscop_end_tab,
353                 sscop_endak_tab,
354                 sscop_rs_tab,
355                 sscop_rsak_tab,
356                 sscop_bgrej_tab,
357                 sscop_sd_tab,
358                 sscop_er_tab,
359                 sscop_poll_tab,
360                 sscop_stat_tab,
361                 sscop_ustat_tab,
362                 sscop_ud_tab,
363                 sscop_md_tab,
364                 sscop_erak_tab
365 };
366
367
368 /*
369  * BGN PDU / SOS_OUTCONN Processor
370  * 
371  * Arguments:
372  *      sop     pointer to sscop connection block
373  *      m       pointer to PDU buffer (without trailer)
374  *      trlr    pointer to PDU trailer
375  *
376  * Returns:
377  *      none
378  *
379  */
380 static void
381 sscop_bgn_outconn(sop, m, trlr)
382         struct sscop    *sop;
383         KBuffer         *m;
384         caddr_t         trlr;
385 {
386         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
387         int             err;
388
389         /*
390          * If retransmitted BGN, ignore it
391          */
392         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
393                 KB_FREEALL(m);
394                 return;
395         }
396
397         /*
398          * Stop retransmit timer
399          */
400         sop->so_timer[SSCOP_T_CC] = 0;
401
402         /*
403          * Initialize state variables
404          */
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);
408
409         /*
410          * Return an ACK to peer
411          */
412         (void) sscop_send_bgak(sop);
413
414         /*
415          * Notify user of connection establishment
416          */
417         STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, 
418                 sop->so_connvc, (intptr_t)m, 0, err);
419         if (err) {
420                 KB_FREEALL(m);
421                 sscop_abort(sop, "stack memory\n");
422                 return;
423         }
424
425         /*
426          * Start data transfer timers
427          */
428         sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
429         sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
430
431         /*
432          * OK, we're ready for data
433          */
434         sop->so_state = SOS_READY;
435
436         /*
437          * See if transmit queues need servicing
438          */
439         if (sop->so_flags & SOF_XMITSRVC)
440                 sscop_service_xmit(sop);
441
442         return;
443 }
444
445
446 /*
447  * BGN PDU / SOS_INCONN Processor
448  * 
449  * Arguments:
450  *      sop     pointer to sscop connection block
451  *      m       pointer to PDU buffer (without trailer)
452  *      trlr    pointer to PDU trailer
453  *
454  * Returns:
455  *      none
456  *
457  */
458 static void
459 sscop_bgn_inconn(sop, m, trlr)
460         struct sscop    *sop;
461         KBuffer         *m;
462         caddr_t         trlr;
463 {
464         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
465         int             err;
466
467         /*
468          * If retransmitted BGN, ignore it
469          */
470         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
471                 KB_FREEALL(m);
472                 return;
473         }
474
475         /*
476          * Initialize transmit window
477          */
478         SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
479
480         /*
481          * First, tell user current connection has been released
482          */
483         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, 
484                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
485         if (err) {
486                 KB_FREEALL(m);
487                 sscop_abort(sop, "stack memory\n");
488                 return;
489         }
490
491         /*
492          * Now, tell user of new connection establishment
493          */
494         STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, 
495                 sop->so_connvc, (intptr_t)m, 0, err);
496         if (err) {
497                 KB_FREEALL(m);
498                 sscop_abort(sop, "stack memory\n");
499                 return;
500         }
501
502         return;
503 }
504
505
506 /*
507  * BGN PDU / SOS_READY Processor
508  *
509  * Arguments:
510  *      sop     pointer to sscop connection block
511  *      m       pointer to PDU buffer (without trailer)
512  *      trlr    pointer to PDU trailer
513  *
514  * Returns:
515  *      none
516  *
517  */
518 static void
519 sscop_bgn_ready(sop, m, trlr)
520         struct sscop    *sop;
521         KBuffer         *m;
522         caddr_t         trlr;
523 {
524         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
525         int             err;
526
527         /*
528          * If retransmitted BGN, just ACK it again
529          */
530         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
531                 KB_FREEALL(m);
532                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
533                 (void) sscop_send_bgak(sop);
534                 return;
535         }
536
537         /*
538          * Stop data transfer timers
539          */
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;
544
545         /*
546          * Initialize transmit window
547          */
548         SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
549
550         /*
551          * Clear out appropriate queues
552          */
553         q2110_prep_retrieve(sop);
554
555         /*
556          * Tell user current connection has been released
557          */
558         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
559                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
560         if (err) {
561                 KB_FREEALL(m);
562                 sscop_abort(sop, "stack memory\n");
563                 return;
564         }
565
566         /*
567          * Tell user of incoming connection
568          */
569         STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
570                 sop->so_connvc, (intptr_t)m, 0, err);
571         if (err) {
572                 KB_FREEALL(m);
573                 sscop_abort(sop, "stack memory\n");
574                 return;
575         }
576
577         /*
578          * Wait for user's response
579          */
580         sop->so_state = SOS_INCONN;
581
582         return;
583 }
584
585
586 /*
587  * BGREJ PDU / SOS_OUTRECOV Processor
588  *
589  * Arguments:
590  *      sop     pointer to sscop connection block
591  *      m       pointer to PDU buffer (without trailer)
592  *      trlr    pointer to PDU trailer
593  *
594  * Returns:
595  *      none
596  *
597  */
598 static void
599 sscop_bgrej_outrecov(sop, m, trlr)
600         struct sscop    *sop;
601         KBuffer         *m;
602         caddr_t         trlr;
603 {
604         int             err;
605
606         /*
607          * Stop retransmit timer
608          */
609         sop->so_timer[SSCOP_T_CC] = 0;
610
611         /*
612          * Report protocol error
613          */
614         sscop_bgrej_error(sop, m, trlr);
615
616         /*
617          * Notify user of connection failure
618          */
619         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
620                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
621         if (err) {
622                 sscop_abort(sop, "stack memory\n");
623                 return;
624         }
625
626         /*
627          * Clear receiver buffer
628          */
629         sscop_rcvr_drain(sop);
630
631         /*
632          * Back to idle state
633          */
634         sop->so_state = SOS_IDLE;
635
636         return;
637 }
638
639
640 /*
641  * END PDU / SOS_OUTRECOV Processor
642  *
643  * Arguments:
644  *      sop     pointer to sscop connection block
645  *      m       pointer to PDU buffer (without trailer)
646  *      trlr    pointer to PDU trailer
647  *
648  * Returns:
649  *      none
650  *
651  */
652 static void
653 sscop_end_outrecov(sop, m, trlr)
654         struct sscop    *sop;
655         KBuffer         *m;
656         caddr_t         trlr;
657 {
658         struct end_pdu  *ep = (struct end_pdu *)trlr;
659         int             err, source;
660
661         /*
662          * Stop retransmit timer
663          */
664         sop->so_timer[SSCOP_T_CC] = 0;
665
666         /*
667          * Acknowledge END
668          */
669         (void) sscop_send_endak(sop);
670
671         /*
672          * Get Source value
673          */
674         if (ep->end_type & PT_SOURCE_SSCOP)
675                 source = SSCOP_SOURCE_SSCOP;
676         else
677                 source = SSCOP_SOURCE_USER;
678
679         /*
680          * Notify user of connection termination
681          */
682         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
683                 sop->so_connvc, (intptr_t)m, source, err);
684         if (err) {
685                 KB_FREEALL(m);
686                 sscop_abort(sop, "stack memory\n");
687                 return;
688         }
689
690         /*
691          * Clear receiver buffer
692          */
693         sscop_rcvr_drain(sop);
694
695         /*
696          * Back to idle state
697          */
698         sop->so_state = SOS_IDLE;
699
700         return;
701 }
702
703
704 /*
705  * END PDU / SOS_READY Processor
706  *
707  * Arguments:
708  *      sop     pointer to sscop connection block
709  *      m       pointer to PDU buffer (without trailer)
710  *      trlr    pointer to PDU trailer
711  *
712  * Returns:
713  *      none
714  *
715  */
716 static void
717 sscop_end_ready(sop, m, trlr)
718         struct sscop    *sop;
719         KBuffer         *m;
720         caddr_t         trlr;
721 {
722         struct end_pdu  *ep = (struct end_pdu *)trlr;
723         int             err, source;
724
725         /*
726          * Stop data transfer timers
727          */
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;
732
733         /*
734          * Acknowledge END
735          */
736         (void) sscop_send_endak(sop);
737
738         /*
739          * Get Source value
740          */
741         if (ep->end_type & PT_SOURCE_SSCOP)
742                 source = SSCOP_SOURCE_SSCOP;
743         else
744                 source = SSCOP_SOURCE_USER;
745
746         /*
747          * Notify user of connection termination
748          */
749         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
750                 sop->so_connvc, (intptr_t)m, source, err);
751         if (err) {
752                 KB_FREEALL(m);
753                 sscop_abort(sop, "stack memory\n");
754                 return;
755         }
756
757         /*
758          * Clear out appropriate queues
759          */
760         q2110_prep_retrieve(sop);
761
762         /*
763          * Back to idle state
764          */
765         sop->so_state = SOS_IDLE;
766
767         return;
768 }
769
770
771 /*
772  * ENDAK PDU / SOS_OUTRECOV Processor
773  *
774  * Arguments:
775  *      sop     pointer to sscop connection block
776  *      m       pointer to PDU buffer (without trailer)
777  *      trlr    pointer to PDU trailer
778  *
779  * Returns:
780  *      none
781  *
782  */
783 static void
784 sscop_endak_outrecov(sop, m, trlr)
785         struct sscop    *sop;
786         KBuffer         *m;
787         caddr_t         trlr;
788 {
789         int             err;
790
791         /*
792          * Stop retransmit timer
793          */
794         sop->so_timer[SSCOP_T_CC] = 0;
795
796         /*
797          * Report protocol error
798          */
799         sscop_endak_error(sop, m, trlr);
800
801         /*
802          * Notify user of connection failure
803          */
804         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
805                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
806         if (err) {
807                 sscop_abort(sop, "stack memory\n");
808                 return;
809         }
810
811         /*
812          * Clear receiver buffer
813          */
814         sscop_rcvr_drain(sop);
815
816         /*
817          * Back to idle state
818          */
819         sop->so_state = SOS_IDLE;
820
821         return;
822 }
823
824
825 /*
826  * RS PDU / SOS_OUTRESYN Processor
827  * 
828  * Arguments:
829  *      sop     pointer to sscop connection block
830  *      m       pointer to PDU buffer (without trailer)
831  *      trlr    pointer to PDU trailer
832  *
833  * Returns:
834  *      none
835  *
836  */
837 static void
838 sscop_rs_outresyn(sop, m, trlr)
839         struct sscop    *sop;
840         KBuffer         *m;
841         caddr_t         trlr;
842 {
843         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
844         int             err;
845
846         /*
847          * If retransmitted RS, ignore it
848          */
849         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
850                 KB_FREEALL(m);
851                 return;
852         }
853
854         /*
855          * Stop retransmit timer
856          */
857         sop->so_timer[SSCOP_T_CC] = 0;
858
859         /*
860          * Initialize state variables
861          */
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);
865
866         /*
867          * Free PDU buffers
868          */
869         KB_FREEALL(m);
870
871         /*
872          * Return an ACK to peer
873          */
874         (void) sscop_send_rsak(sop);
875
876         /*
877          * Notify user of connection resynchronization
878          */
879         STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, 
880                 sop->so_connvc, 0, 0, err);
881         if (err) {
882                 sscop_abort(sop, "stack memory\n");
883                 return;
884         }
885
886         /*
887          * Start data transfer timers
888          */
889         sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
890         sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
891
892         /*
893          * OK, we're ready for data
894          */
895         sop->so_state = SOS_READY;
896
897         /*
898          * See if transmit queues need servicing
899          */
900         if (sop->so_flags & SOF_XMITSRVC)
901                 sscop_service_xmit(sop);
902
903         return;
904 }
905
906
907 /*
908  * RS PDU / SOS_INRESYN Processor
909  * 
910  * Arguments:
911  *      sop     pointer to sscop connection block
912  *      m       pointer to PDU buffer (without trailer)
913  *      trlr    pointer to PDU trailer
914  *
915  * Returns:
916  *      none
917  *
918  */
919 static void
920 sscop_rs_inresyn(sop, m, trlr)
921         struct sscop    *sop;
922         KBuffer         *m;
923         caddr_t         trlr;
924 {
925         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
926
927         /*
928          * If retransmitted RS, ignore it
929          */
930         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
931                 KB_FREEALL(m);
932                 return;
933         }
934
935         /*
936          * Report error condition
937          */
938         sscop_rs_error(sop, m, trlr);
939
940         return;
941 }
942
943
944 /*
945  * RS PDU / SOS_OUTRECOV Processor
946  * 
947  * Arguments:
948  *      sop     pointer to sscop connection block
949  *      m       pointer to PDU buffer (without trailer)
950  *      trlr    pointer to PDU trailer
951  *
952  * Returns:
953  *      none
954  *
955  */
956 static void
957 sscop_rs_outrecov(sop, m, trlr)
958         struct sscop    *sop;
959         KBuffer         *m;
960         caddr_t         trlr;
961 {
962         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
963         int             err;
964
965         /*
966          * If retransmitted RS, report an error
967          */
968         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
969                 sscop_rs_error(sop, m, trlr);
970                 return;
971         }
972
973         /*
974          * Stop retransmit timer
975          */
976         sop->so_timer[SSCOP_T_CC] = 0;
977
978         /*
979          * Initialize transmit window
980          */
981         SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
982
983         /*
984          * Notify user of connection resynchronization
985          */
986         STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, 
987                 sop->so_connvc, (intptr_t)m, 0, err);
988         if (err) {
989                 KB_FREEALL(m);
990                 sscop_abort(sop, "stack memory\n");
991                 return;
992         }
993
994         /*
995          * Clear receiver buffer
996          */
997         sscop_rcvr_drain(sop);
998
999         /*
1000          * Wait for user response
1001          */
1002         sop->so_state = SOS_INRESYN;
1003
1004         return;
1005 }
1006
1007
1008 /*
1009  * RS PDU / SOS_READY Processor
1010  * 
1011  * Arguments:
1012  *      sop     pointer to sscop connection block
1013  *      m       pointer to PDU buffer (without trailer)
1014  *      trlr    pointer to PDU trailer
1015  *
1016  * Returns:
1017  *      none
1018  *
1019  */
1020 static void
1021 sscop_rs_ready(sop, m, trlr)
1022         struct sscop    *sop;
1023         KBuffer         *m;
1024         caddr_t         trlr;
1025 {
1026         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
1027         int             err;
1028
1029         /*
1030          * If retransmitted RS, just ACK it
1031          */
1032         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
1033                 KB_FREEALL(m);
1034                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1035                 sscop_send_rsak(sop);
1036                 return;
1037         }
1038
1039         /*
1040          * Stop data transfer timers
1041          */
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;
1046
1047         /*
1048          * Initialize transmit window
1049          */
1050         SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
1051
1052         /*
1053          * Notify user of connection resynchronization
1054          */
1055         STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, 
1056                 sop->so_connvc, (intptr_t)m, 0, err);
1057         if (err) {
1058                 KB_FREEALL(m);
1059                 sscop_abort(sop, "stack memory\n");
1060                 return;
1061         }
1062
1063         /*
1064          * Clear out appropriate queues
1065          */
1066         q2110_prep_retrieve(sop);
1067
1068         /*
1069          * Wait for user response
1070          */
1071         sop->so_state = SOS_INRESYN;
1072
1073         return;
1074 }
1075
1076 /*
1077  * ER PDU / Protocol Error
1078  *
1079  * Arguments:
1080  *      sop     pointer to sscop connection block
1081  *      m       pointer to PDU buffer (without trailer)
1082  *      trlr    pointer to PDU trailer
1083  *
1084  * Returns:
1085  *      none
1086  *
1087  */
1088 static void
1089 sscop_er_error(sop, m, trlr)
1090         struct sscop    *sop;
1091         KBuffer         *m;
1092         caddr_t         trlr;
1093 {
1094
1095         /*
1096          * Record error condition
1097          */
1098         sscop_maa_error(sop, 'L');
1099         KB_FREEALL(m);
1100
1101         return;
1102 }
1103
1104
1105 /*
1106  * ER PDU / SOS_IDLE Processor
1107  *
1108  * Arguments:
1109  *      sop     pointer to sscop connection block
1110  *      m       pointer to PDU buffer (without trailer)
1111  *      trlr    pointer to PDU trailer
1112  *
1113  * Returns:
1114  *      none
1115  *
1116  */
1117 static void
1118 sscop_er_idle(sop, m, trlr)
1119         struct sscop    *sop;
1120         KBuffer         *m;
1121         caddr_t         trlr;
1122 {
1123
1124         /*
1125          * Record error condition
1126          */
1127         sscop_er_error(sop, m, trlr);
1128
1129         /*
1130          * Return an END to peer
1131          */
1132         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1133
1134         return;
1135 }
1136
1137
1138 /*
1139  * ER PDU / SOS_OUTRECOV Processor
1140  * 
1141  * Arguments:
1142  *      sop     pointer to sscop connection block
1143  *      m       pointer to PDU buffer (without trailer)
1144  *      trlr    pointer to PDU trailer
1145  *
1146  * Returns:
1147  *      none
1148  *
1149  */
1150 static void
1151 sscop_er_outrecov(sop, m, trlr)
1152         struct sscop    *sop;
1153         KBuffer         *m;
1154         caddr_t         trlr;
1155 {
1156         struct er_pdu   *ep = (struct er_pdu *)trlr;
1157         int             err;
1158
1159         /*
1160          * If retransmitted ER, report an error
1161          */
1162         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1163                 sscop_er_error(sop, m, trlr);
1164                 return;
1165         }
1166
1167         /*
1168          * Stop retransmit timer
1169          */
1170         sop->so_timer[SSCOP_T_CC] = 0;
1171
1172         /*
1173          * Initialize transmit window
1174          */
1175         SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1176
1177         /*
1178          * Initialize receiver window
1179          */
1180         SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
1181
1182         /*
1183          * Free PDU buffers
1184          */
1185         KB_FREEALL(m);
1186
1187         /*
1188          * Acknowledge ER
1189          */
1190         (void) sscop_send_erak(sop);
1191
1192         /*
1193          * Deliver any outstanding data to user
1194          */
1195         q2110_deliver_data(sop);
1196
1197         /*
1198          * Notify user of connection recovery
1199          */
1200         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1201                 sop->so_connvc, 0, 0, err);
1202         if (err) {
1203                 sscop_abort(sop, "stack memory\n");
1204                 return;
1205         }
1206
1207         /*
1208          * Wait for user response
1209          */
1210         sop->so_state = SOS_RECOVRSP;
1211
1212         return;
1213 }
1214
1215
1216 /*
1217  * ER PDU / SOS_RECOVRSP Processor
1218  * 
1219  * Arguments:
1220  *      sop     pointer to sscop connection block
1221  *      m       pointer to PDU buffer (without trailer)
1222  *      trlr    pointer to PDU trailer
1223  *
1224  * Returns:
1225  *      none
1226  *
1227  */
1228 static void
1229 sscop_er_recovrsp(sop, m, trlr)
1230         struct sscop    *sop;
1231         KBuffer         *m;
1232         caddr_t         trlr;
1233 {
1234         struct er_pdu   *ep = (struct er_pdu *)trlr;
1235
1236         /*
1237          * If retransmitted ER, just ACK it
1238          */
1239         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1240                 KB_FREEALL(m);
1241                 (void) sscop_send_erak(sop);
1242                 return;
1243         }
1244
1245         /*
1246          * Report error condition
1247          */
1248         sscop_er_error(sop, m, trlr);
1249
1250         return;
1251 }
1252
1253
1254 /*
1255  * ER PDU / SOS_INRECOV Processor
1256  * 
1257  * Arguments:
1258  *      sop     pointer to sscop connection block
1259  *      m       pointer to PDU buffer (without trailer)
1260  *      trlr    pointer to PDU trailer
1261  *
1262  * Returns:
1263  *      none
1264  *
1265  */
1266 static void
1267 sscop_er_inrecov(sop, m, trlr)
1268         struct sscop    *sop;
1269         KBuffer         *m;
1270         caddr_t         trlr;
1271 {
1272         struct er_pdu   *ep = (struct er_pdu *)trlr;
1273
1274         /*
1275          * If retransmitted ER, just ignore it
1276          */
1277         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1278                 KB_FREEALL(m);
1279                 return;
1280         }
1281
1282         /*
1283          * Report error condition
1284          */
1285         sscop_er_error(sop, m, trlr);
1286
1287         return;
1288 }
1289
1290
1291 /*
1292  * ER PDU / SOS_READY Processor
1293  * 
1294  * Arguments:
1295  *      sop     pointer to sscop connection block
1296  *      m       pointer to PDU buffer (without trailer)
1297  *      trlr    pointer to PDU trailer
1298  *
1299  * Returns:
1300  *      none
1301  *
1302  */
1303 static void
1304 sscop_er_ready(sop, m, trlr)
1305         struct sscop    *sop;
1306         KBuffer         *m;
1307         caddr_t         trlr;
1308 {
1309         struct er_pdu   *ep = (struct er_pdu *)trlr;
1310         int             err;
1311
1312         /*
1313          * If retransmitted ER, just ACK it
1314          */
1315         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1316                 KB_FREEALL(m);
1317                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1318                 sscop_send_erak(sop);
1319                 return;
1320         }
1321
1322         /*
1323          * Stop data transfer timers
1324          */
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;
1329
1330         /*
1331          * Initialize transmit window
1332          */
1333         SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1334
1335         /*
1336          * Free PDU buffers
1337          */
1338         KB_FREEALL(m);
1339
1340         /*
1341          * Clear out appropriate queues
1342          */
1343         q2110_prep_recovery(sop);
1344
1345         /*
1346          * Deliver any outstanding data to user
1347          */
1348         q2110_deliver_data(sop);
1349
1350         /*
1351          * Notify user of connection recovery
1352          */
1353         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1354                 sop->so_connvc, 0, 0, err);
1355         if (err) {
1356                 sscop_abort(sop, "stack memory\n");
1357                 return;
1358         }
1359
1360         /*
1361          * Wait for user response
1362          */
1363         sop->so_state = SOS_INRECOV;
1364
1365         return;
1366 }
1367
1368
1369 /*
1370  * ERAK PDU / Protocol Error
1371  *
1372  * Arguments:
1373  *      sop     pointer to sscop connection block
1374  *      m       pointer to PDU buffer (without trailer)
1375  *      trlr    pointer to PDU trailer
1376  *
1377  * Returns:
1378  *      none
1379  *
1380  */
1381 static void
1382 sscop_erak_error(sop, m, trlr)
1383         struct sscop    *sop;
1384         KBuffer         *m;
1385         caddr_t         trlr;
1386 {
1387
1388         /*
1389          * Record error condition
1390          */
1391         sscop_maa_error(sop, 'M');
1392         KB_FREEALL(m);
1393
1394         return;
1395 }
1396
1397
1398 /*
1399  * ERAK PDU / SOS_IDLE Processor
1400  *
1401  * Arguments:
1402  *      sop     pointer to sscop connection block
1403  *      m       pointer to PDU buffer (without trailer)
1404  *      trlr    pointer to PDU trailer
1405  *
1406  * Returns:
1407  *      none
1408  *
1409  */
1410 static void
1411 sscop_erak_idle(sop, m, trlr)
1412         struct sscop    *sop;
1413         KBuffer         *m;
1414         caddr_t         trlr;
1415 {
1416
1417         /*
1418          * Record error condition
1419          */
1420         sscop_erak_error(sop, m, trlr);
1421
1422         /*
1423          * Return an END to peer
1424          */
1425         (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1426
1427         return;
1428 }
1429
1430
1431 /*
1432  * ERAK PDU / SOS_OUTRECOV Processor
1433  * 
1434  * Arguments:
1435  *      sop     pointer to sscop connection block
1436  *      m       pointer to PDU buffer (without trailer)
1437  *      trlr    pointer to PDU trailer
1438  *
1439  * Returns:
1440  *      none
1441  *
1442  */
1443 static void
1444 sscop_erak_outrecov(sop, m, trlr)
1445         struct sscop    *sop;
1446         KBuffer         *m;
1447         caddr_t         trlr;
1448 {
1449         struct erak_pdu *ep = (struct erak_pdu *)trlr;
1450         int             err;
1451
1452         /*
1453          * Stop retransmit timer
1454          */
1455         sop->so_timer[SSCOP_T_CC] = 0;
1456
1457         /*
1458          * Initialize transmit window
1459          */
1460         SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
1461
1462         /*
1463          * Free PDU buffers
1464          */
1465         KB_FREEALL(m);
1466
1467         /*
1468          * Deliver any outstanding data to user
1469          */
1470         q2110_deliver_data(sop);
1471
1472         /*
1473          * Notify user of connection recovery
1474          */
1475         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1476                 sop->so_connvc, 0, 0, err);
1477         if (err) {
1478                 sscop_abort(sop, "stack memory\n");
1479                 return;
1480         }
1481
1482         /*
1483          * Wait for user response
1484          */
1485         sop->so_state = SOS_RECOVRSP;
1486
1487         return;
1488 }
1489
1490
1491 /*
1492  * SD PDU / SOS_READY Processor
1493  *
1494  * Arguments:
1495  *      sop     pointer to sscop connection block
1496  *      m       pointer to PDU buffer (without trailer)
1497  *      trlr    pointer to PDU trailer
1498  *
1499  * Returns:
1500  *      none
1501  *
1502  */
1503 static void
1504 sscop_sd_ready(sop, m, trlr)
1505         struct sscop    *sop;
1506         KBuffer         *m;
1507         caddr_t         trlr;
1508 {
1509         struct sd_pdu   *sp = (struct sd_pdu *)trlr;
1510         struct pdu_hdr  *php;
1511         KBuffer         *n;
1512         sscop_seq       ns;
1513         int             err, space;
1514
1515         /*
1516          * Get PDU sequence number
1517          */
1518         SEQ_SET(ns, ntohl(sp->sd_ns));
1519
1520         /*
1521          * Ensure that the sequence number fits within the window
1522          */
1523         if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
1524                 /*
1525                  * It doesn't, drop received data
1526                  */
1527                 KB_FREEALL(m);
1528
1529                 /*
1530                  * If next highest PDU hasn't reached window end yet,
1531                  * then send a USTAT to inform transmitter of this gap
1532                  */
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;
1536                 }
1537                 return;
1538         }
1539
1540         /*
1541          * If this is the next in-sequence PDU, hand it to user
1542          */
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);
1546                 if (err) {
1547                         KB_FREEALL(m);
1548                         return;
1549                 }
1550
1551                 /*
1552                  * Bump next expected sequence number
1553                  */
1554                 SEQ_INCR(sop->so_rcvnext, 1);
1555
1556                 /*
1557                  * Slide receive window down
1558                  */
1559                 SEQ_INCR(sop->so_rcvmax, 1);
1560
1561                 /*
1562                  * Is this the highest sequence PDU we've received??
1563                  */
1564                 if (ns == sop->so_rcvhigh) {
1565                         /*
1566                          * Yes, bump the limit and exit
1567                          */
1568                         sop->so_rcvhigh = sop->so_rcvnext;
1569                         return;
1570                 }
1571
1572                 /*
1573                  * This is a retransmitted PDU, so see if we have
1574                  * more in-sequence PDUs already queued up
1575                  */
1576                 while ((php = sop->so_recv_hd) &&
1577                        (php->ph_ns == sop->so_rcvnext)) {
1578
1579                         /*
1580                          * Yup we do, so remove next PDU from queue and
1581                          * pass it up to the user as well
1582                          */
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,
1588                                 php->ph_ns, err);
1589                         if (err) {
1590                                 /*
1591                                  * Should never happen, but...
1592                                  */
1593                                 KB_FREEALL(php->ph_buf);
1594                                 sscop_abort(sop, "stack memory\n");
1595                                 return;
1596                         }
1597
1598                         /*
1599                          * Bump next expected sequence number
1600                          */
1601                         SEQ_INCR(sop->so_rcvnext, 1);
1602
1603                         /*
1604                          * Slide receive window down
1605                          */
1606                         SEQ_INCR(sop->so_rcvmax, 1);
1607                 }
1608
1609                 /*
1610                  * Finished with data delivery...
1611                  */
1612                 return;
1613         }
1614
1615         /*
1616          * We're gonna have to queue this PDU, so find space
1617          * for the PDU header
1618          */
1619         KB_HEADROOM(m, space);
1620
1621         /*
1622          * If there's not enough room in the received buffer,
1623          * allocate & link a new buffer for the header
1624          */
1625         if (space < sizeof(struct pdu_hdr)) {
1626
1627                 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
1628                 if (n == NULL) {
1629                         KB_FREEALL(m);
1630                         return;
1631                 }
1632                 KB_HEADSET(n, sizeof(struct pdu_hdr));
1633                 KB_LEN(n) = 0;
1634                 KB_LINKHEAD(n, m);
1635                 m = n;
1636         }
1637
1638         /*
1639          * Build PDU header
1640          *
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.
1644          */
1645         KB_DATASTART(m, php, struct pdu_hdr *);
1646         php--;
1647         php->ph_ns = ns;
1648         php->ph_buf = m;
1649
1650         /*
1651          * Insert PDU into the receive queue
1652          */
1653         if (sscop_recv_insert(sop, php)) {
1654                 /*
1655                  * Oops, a duplicate sequence number PDU is already on
1656                  * the queue, somethings wrong here.
1657                  */
1658                 sscop_maa_error(sop, 'Q');
1659
1660                 /*
1661                  * Free buffers
1662                  */
1663                 KB_FREEALL(m);
1664
1665                 /*
1666                  * Go into recovery mode
1667                  */
1668                 q2110_error_recovery(sop);
1669
1670                 return;
1671         }
1672
1673         /*
1674          * Are we at the high-water mark??
1675          */
1676         if (ns == sop->so_rcvhigh) {
1677                 /*
1678                  * Yes, just bump the mark
1679                  */
1680                 SEQ_INCR(sop->so_rcvhigh, 1);
1681
1682                 return;
1683         }
1684
1685         /*
1686          * Are we beyond the high-water mark??
1687          */
1688         if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1689                 /*
1690                  * Yes, then there's a missing PDU, so inform the transmitter
1691                  */
1692                 (void) sscop_send_ustat(sop, ns);
1693
1694                 /*
1695                  * Update high-water mark
1696                  */
1697                 sop->so_rcvhigh = SEQ_ADD(ns, 1);
1698         }
1699
1700         return;
1701 }
1702
1703
1704 /*
1705  * POLL PDU / SOS_READY Processor
1706  *
1707  * Arguments:
1708  *      sop     pointer to sscop connection block
1709  *      m       pointer to PDU buffer (without trailer)
1710  *      trlr    pointer to PDU trailer
1711  *
1712  * Returns:
1713  *      none
1714  *
1715  */
1716 static void
1717 sscop_poll_ready(sop, m, trlr)
1718         struct sscop    *sop;
1719         KBuffer         *m;
1720         caddr_t         trlr;
1721 {
1722         struct poll_pdu *pp = (struct poll_pdu *)trlr;
1723         sscop_seq       nps;
1724
1725         pp->poll_ns = ntohl(pp->poll_ns);
1726
1727         /*
1728          * If the poll sequence number is less than highest number
1729          * we've already seen, something's wrong
1730          */
1731         if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1732                 /*
1733                  * Record error condition
1734                  */
1735                 sscop_maa_error(sop, 'Q');
1736
1737                 /*
1738                  * Free buffers
1739                  */
1740                 KB_FREEALL(m);
1741
1742                 /*
1743                  * Go into recovery mode
1744                  */
1745                 q2110_error_recovery(sop);
1746
1747                 return;
1748         }
1749
1750         /*
1751          * Set a new "next highest" sequence number expected
1752          */
1753         if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
1754                 SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
1755         else
1756                 sop->so_rcvhigh = sop->so_rcvmax;
1757
1758         /*
1759          * Return a STAT PDU to peer
1760          */
1761         SEQ_SET(nps, ntohl(pp->poll_nps));
1762         KB_FREEALL(m);
1763         (void) sscop_send_stat(sop, nps);
1764
1765         return;
1766 }
1767