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