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