Merge branch 'vendor/OPENSSH'
[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.7 2006/01/14 13:36:39 swildner 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(struct sscop *sop, KBuffer *m, caddr_t trlr)
369 {
370         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
371         int             err;
372
373         /*
374          * If retransmitted BGN, ignore it
375          */
376         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
377                 KB_FREEALL(m);
378                 return;
379         }
380
381         /*
382          * Stop retransmit timer
383          */
384         sop->so_timer[SSCOP_T_CC] = 0;
385
386         /*
387          * Initialize state variables
388          */
389         SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
390         SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
391         q2110_init_state(sop);
392
393         /*
394          * Return an ACK to peer
395          */
396         sscop_send_bgak(sop);
397
398         /*
399          * Notify user of connection establishment
400          */
401         STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, 
402                 sop->so_connvc, (int)m, 0, err);
403         if (err) {
404                 KB_FREEALL(m);
405                 sscop_abort(sop, "stack memory\n");
406                 return;
407         }
408
409         /*
410          * Start data transfer timers
411          */
412         sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
413         sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
414
415         /*
416          * OK, we're ready for data
417          */
418         sop->so_state = SOS_READY;
419
420         /*
421          * See if transmit queues need servicing
422          */
423         if (sop->so_flags & SOF_XMITSRVC)
424                 sscop_service_xmit(sop);
425
426         return;
427 }
428
429
430 /*
431  * BGN PDU / SOS_INCONN Processor
432  * 
433  * Arguments:
434  *      sop     pointer to sscop connection block
435  *      m       pointer to PDU buffer (without trailer)
436  *      trlr    pointer to PDU trailer
437  *
438  * Returns:
439  *      none
440  *
441  */
442 static void
443 sscop_bgn_inconn(struct sscop *sop, KBuffer *m, caddr_t trlr)
444 {
445         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
446         int             err;
447
448         /*
449          * If retransmitted BGN, ignore it
450          */
451         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
452                 KB_FREEALL(m);
453                 return;
454         }
455
456         /*
457          * Initialize transmit window
458          */
459         SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
460
461         /*
462          * First, tell user current connection has been released
463          */
464         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, 
465                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
466         if (err) {
467                 KB_FREEALL(m);
468                 sscop_abort(sop, "stack memory\n");
469                 return;
470         }
471
472         /*
473          * Now, tell user of new connection establishment
474          */
475         STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, 
476                 sop->so_connvc, (int)m, 0, err);
477         if (err) {
478                 KB_FREEALL(m);
479                 sscop_abort(sop, "stack memory\n");
480                 return;
481         }
482
483         return;
484 }
485
486
487 /*
488  * BGN PDU / SOS_READY Processor
489  *
490  * Arguments:
491  *      sop     pointer to sscop connection block
492  *      m       pointer to PDU buffer (without trailer)
493  *      trlr    pointer to PDU trailer
494  *
495  * Returns:
496  *      none
497  *
498  */
499 static void
500 sscop_bgn_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
501 {
502         struct bgn_pdu  *bp = (struct bgn_pdu *)trlr;
503         int             err;
504
505         /*
506          * If retransmitted BGN, just ACK it again
507          */
508         if (sscop_is_rexmit(sop, bp->bgn_nsq)) {
509                 KB_FREEALL(m);
510                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
511                 sscop_send_bgak(sop);
512                 return;
513         }
514
515         /*
516          * Stop data transfer timers
517          */
518         sop->so_timer[SSCOP_T_POLL] = 0;
519         sop->so_timer[SSCOP_T_NORESP] = 0;
520         sop->so_timer[SSCOP_T_IDLE] = 0;
521         sop->so_flags &= ~SOF_KEEPALIVE;
522
523         /*
524          * Initialize transmit window
525          */
526         SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr));
527
528         /*
529          * Clear out appropriate queues
530          */
531         q2110_prep_retrieve(sop);
532
533         /*
534          * Tell user current connection has been released
535          */
536         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
537                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err);
538         if (err) {
539                 KB_FREEALL(m);
540                 sscop_abort(sop, "stack memory\n");
541                 return;
542         }
543
544         /*
545          * Tell user of incoming connection
546          */
547         STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku,
548                 sop->so_connvc, (int)m, 0, err);
549         if (err) {
550                 KB_FREEALL(m);
551                 sscop_abort(sop, "stack memory\n");
552                 return;
553         }
554
555         /*
556          * Wait for user's response
557          */
558         sop->so_state = SOS_INCONN;
559
560         return;
561 }
562
563
564 /*
565  * BGREJ PDU / SOS_OUTRECOV Processor
566  *
567  * Arguments:
568  *      sop     pointer to sscop connection block
569  *      m       pointer to PDU buffer (without trailer)
570  *      trlr    pointer to PDU trailer
571  *
572  * Returns:
573  *      none
574  *
575  */
576 static void
577 sscop_bgrej_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
578 {
579         int             err;
580
581         /*
582          * Stop retransmit timer
583          */
584         sop->so_timer[SSCOP_T_CC] = 0;
585
586         /*
587          * Report protocol error
588          */
589         sscop_bgrej_error(sop, m, trlr);
590
591         /*
592          * Notify user of connection failure
593          */
594         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
595                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
596         if (err) {
597                 sscop_abort(sop, "stack memory\n");
598                 return;
599         }
600
601         /*
602          * Clear receiver buffer
603          */
604         sscop_rcvr_drain(sop);
605
606         /*
607          * Back to idle state
608          */
609         sop->so_state = SOS_IDLE;
610
611         return;
612 }
613
614
615 /*
616  * END PDU / SOS_OUTRECOV Processor
617  *
618  * Arguments:
619  *      sop     pointer to sscop connection block
620  *      m       pointer to PDU buffer (without trailer)
621  *      trlr    pointer to PDU trailer
622  *
623  * Returns:
624  *      none
625  *
626  */
627 static void
628 sscop_end_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
629 {
630         struct end_pdu  *ep = (struct end_pdu *)trlr;
631         int             err, source;
632
633         /*
634          * Stop retransmit timer
635          */
636         sop->so_timer[SSCOP_T_CC] = 0;
637
638         /*
639          * Acknowledge END
640          */
641         sscop_send_endak(sop);
642
643         /*
644          * Get Source value
645          */
646         if (ep->end_type & PT_SOURCE_SSCOP)
647                 source = SSCOP_SOURCE_SSCOP;
648         else
649                 source = SSCOP_SOURCE_USER;
650
651         /*
652          * Notify user of connection termination
653          */
654         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
655                 sop->so_connvc, (int)m, source, err);
656         if (err) {
657                 KB_FREEALL(m);
658                 sscop_abort(sop, "stack memory\n");
659                 return;
660         }
661
662         /*
663          * Clear receiver buffer
664          */
665         sscop_rcvr_drain(sop);
666
667         /*
668          * Back to idle state
669          */
670         sop->so_state = SOS_IDLE;
671
672         return;
673 }
674
675
676 /*
677  * END PDU / SOS_READY Processor
678  *
679  * Arguments:
680  *      sop     pointer to sscop connection block
681  *      m       pointer to PDU buffer (without trailer)
682  *      trlr    pointer to PDU trailer
683  *
684  * Returns:
685  *      none
686  *
687  */
688 static void
689 sscop_end_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
690 {
691         struct end_pdu  *ep = (struct end_pdu *)trlr;
692         int             err, source;
693
694         /*
695          * Stop data transfer timers
696          */
697         sop->so_timer[SSCOP_T_POLL] = 0;
698         sop->so_timer[SSCOP_T_NORESP] = 0;
699         sop->so_timer[SSCOP_T_IDLE] = 0;
700         sop->so_flags &= ~SOF_KEEPALIVE;
701
702         /*
703          * Acknowledge END
704          */
705         sscop_send_endak(sop);
706
707         /*
708          * Get Source value
709          */
710         if (ep->end_type & PT_SOURCE_SSCOP)
711                 source = SSCOP_SOURCE_SSCOP;
712         else
713                 source = SSCOP_SOURCE_USER;
714
715         /*
716          * Notify user of connection termination
717          */
718         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
719                 sop->so_connvc, (int)m, source, err);
720         if (err) {
721                 KB_FREEALL(m);
722                 sscop_abort(sop, "stack memory\n");
723                 return;
724         }
725
726         /*
727          * Clear out appropriate queues
728          */
729         q2110_prep_retrieve(sop);
730
731         /*
732          * Back to idle state
733          */
734         sop->so_state = SOS_IDLE;
735
736         return;
737 }
738
739
740 /*
741  * ENDAK PDU / SOS_OUTRECOV Processor
742  *
743  * Arguments:
744  *      sop     pointer to sscop connection block
745  *      m       pointer to PDU buffer (without trailer)
746  *      trlr    pointer to PDU trailer
747  *
748  * Returns:
749  *      none
750  *
751  */
752 static void
753 sscop_endak_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
754 {
755         int             err;
756
757         /*
758          * Stop retransmit timer
759          */
760         sop->so_timer[SSCOP_T_CC] = 0;
761
762         /*
763          * Report protocol error
764          */
765         sscop_endak_error(sop, m, trlr);
766
767         /*
768          * Notify user of connection failure
769          */
770         STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku,
771                 sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err);
772         if (err) {
773                 sscop_abort(sop, "stack memory\n");
774                 return;
775         }
776
777         /*
778          * Clear receiver buffer
779          */
780         sscop_rcvr_drain(sop);
781
782         /*
783          * Back to idle state
784          */
785         sop->so_state = SOS_IDLE;
786
787         return;
788 }
789
790
791 /*
792  * RS PDU / SOS_OUTRESYN Processor
793  * 
794  * Arguments:
795  *      sop     pointer to sscop connection block
796  *      m       pointer to PDU buffer (without trailer)
797  *      trlr    pointer to PDU trailer
798  *
799  * Returns:
800  *      none
801  *
802  */
803 static void
804 sscop_rs_outresyn(struct sscop *sop, KBuffer *m, caddr_t trlr)
805 {
806         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
807         int             err;
808
809         /*
810          * If retransmitted RS, ignore it
811          */
812         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
813                 KB_FREEALL(m);
814                 return;
815         }
816
817         /*
818          * Stop retransmit timer
819          */
820         sop->so_timer[SSCOP_T_CC] = 0;
821
822         /*
823          * Initialize state variables
824          */
825         SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
826         SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
827         q2110_init_state(sop);
828
829         /*
830          * Free PDU buffers
831          */
832         KB_FREEALL(m);
833
834         /*
835          * Return an ACK to peer
836          */
837         sscop_send_rsak(sop);
838
839         /*
840          * Notify user of connection resynchronization
841          */
842         STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, 
843                 sop->so_connvc, 0, 0, err);
844         if (err) {
845                 sscop_abort(sop, "stack memory\n");
846                 return;
847         }
848
849         /*
850          * Start data transfer timers
851          */
852         sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll;
853         sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
854
855         /*
856          * OK, we're ready for data
857          */
858         sop->so_state = SOS_READY;
859
860         /*
861          * See if transmit queues need servicing
862          */
863         if (sop->so_flags & SOF_XMITSRVC)
864                 sscop_service_xmit(sop);
865
866         return;
867 }
868
869
870 /*
871  * RS PDU / SOS_INRESYN Processor
872  * 
873  * Arguments:
874  *      sop     pointer to sscop connection block
875  *      m       pointer to PDU buffer (without trailer)
876  *      trlr    pointer to PDU trailer
877  *
878  * Returns:
879  *      none
880  *
881  */
882 static void
883 sscop_rs_inresyn(struct sscop *sop, KBuffer *m, caddr_t trlr)
884 {
885         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
886
887         /*
888          * If retransmitted RS, ignore it
889          */
890         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
891                 KB_FREEALL(m);
892                 return;
893         }
894
895         /*
896          * Report error condition
897          */
898         sscop_rs_error(sop, m, trlr);
899
900         return;
901 }
902
903
904 /*
905  * RS PDU / SOS_OUTRECOV Processor
906  * 
907  * Arguments:
908  *      sop     pointer to sscop connection block
909  *      m       pointer to PDU buffer (without trailer)
910  *      trlr    pointer to PDU trailer
911  *
912  * Returns:
913  *      none
914  *
915  */
916 static void
917 sscop_rs_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
918 {
919         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
920         int             err;
921
922         /*
923          * If retransmitted RS, report an error
924          */
925         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
926                 sscop_rs_error(sop, m, trlr);
927                 return;
928         }
929
930         /*
931          * Stop retransmit timer
932          */
933         sop->so_timer[SSCOP_T_CC] = 0;
934
935         /*
936          * Initialize transmit window
937          */
938         SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
939
940         /*
941          * Notify user of connection resynchronization
942          */
943         STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, 
944                 sop->so_connvc, (int)m, 0, err);
945         if (err) {
946                 KB_FREEALL(m);
947                 sscop_abort(sop, "stack memory\n");
948                 return;
949         }
950
951         /*
952          * Clear receiver buffer
953          */
954         sscop_rcvr_drain(sop);
955
956         /*
957          * Wait for user response
958          */
959         sop->so_state = SOS_INRESYN;
960
961         return;
962 }
963
964
965 /*
966  * RS PDU / SOS_READY Processor
967  * 
968  * Arguments:
969  *      sop     pointer to sscop connection block
970  *      m       pointer to PDU buffer (without trailer)
971  *      trlr    pointer to PDU trailer
972  *
973  * Returns:
974  *      none
975  *
976  */
977 static void
978 sscop_rs_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
979 {
980         struct rs_pdu   *rp = (struct rs_pdu *)trlr;
981         int             err;
982
983         /*
984          * If retransmitted RS, just ACK it
985          */
986         if (sscop_is_rexmit(sop, rp->rs_nsq)) {
987                 KB_FREEALL(m);
988                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
989                 sscop_send_rsak(sop);
990                 return;
991         }
992
993         /*
994          * Stop data transfer timers
995          */
996         sop->so_timer[SSCOP_T_POLL] = 0;
997         sop->so_timer[SSCOP_T_NORESP] = 0;
998         sop->so_timer[SSCOP_T_IDLE] = 0;
999         sop->so_flags &= ~SOF_KEEPALIVE;
1000
1001         /*
1002          * Initialize transmit window
1003          */
1004         SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr));
1005
1006         /*
1007          * Notify user of connection resynchronization
1008          */
1009         STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, 
1010                 sop->so_connvc, (int)m, 0, err);
1011         if (err) {
1012                 KB_FREEALL(m);
1013                 sscop_abort(sop, "stack memory\n");
1014                 return;
1015         }
1016
1017         /*
1018          * Clear out appropriate queues
1019          */
1020         q2110_prep_retrieve(sop);
1021
1022         /*
1023          * Wait for user response
1024          */
1025         sop->so_state = SOS_INRESYN;
1026
1027         return;
1028 }
1029
1030 /*
1031  * ER PDU / Protocol Error
1032  *
1033  * Arguments:
1034  *      sop     pointer to sscop connection block
1035  *      m       pointer to PDU buffer (without trailer)
1036  *      trlr    pointer to PDU trailer
1037  *
1038  * Returns:
1039  *      none
1040  *
1041  */
1042 static void
1043 sscop_er_error(struct sscop *sop, KBuffer *m, caddr_t trlr)
1044 {
1045
1046         /*
1047          * Record error condition
1048          */
1049         sscop_maa_error(sop, 'L');
1050         KB_FREEALL(m);
1051
1052         return;
1053 }
1054
1055
1056 /*
1057  * ER PDU / SOS_IDLE Processor
1058  *
1059  * Arguments:
1060  *      sop     pointer to sscop connection block
1061  *      m       pointer to PDU buffer (without trailer)
1062  *      trlr    pointer to PDU trailer
1063  *
1064  * Returns:
1065  *      none
1066  *
1067  */
1068 static void
1069 sscop_er_idle(struct sscop *sop, KBuffer *m, caddr_t trlr)
1070 {
1071
1072         /*
1073          * Record error condition
1074          */
1075         sscop_er_error(sop, m, trlr);
1076
1077         /*
1078          * Return an END to peer
1079          */
1080         sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1081
1082         return;
1083 }
1084
1085
1086 /*
1087  * ER PDU / SOS_OUTRECOV Processor
1088  * 
1089  * Arguments:
1090  *      sop     pointer to sscop connection block
1091  *      m       pointer to PDU buffer (without trailer)
1092  *      trlr    pointer to PDU trailer
1093  *
1094  * Returns:
1095  *      none
1096  *
1097  */
1098 static void
1099 sscop_er_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1100 {
1101         struct er_pdu   *ep = (struct er_pdu *)trlr;
1102         int             err;
1103
1104         /*
1105          * If retransmitted ER, report an error
1106          */
1107         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1108                 sscop_er_error(sop, m, trlr);
1109                 return;
1110         }
1111
1112         /*
1113          * Stop retransmit timer
1114          */
1115         sop->so_timer[SSCOP_T_CC] = 0;
1116
1117         /*
1118          * Initialize transmit window
1119          */
1120         SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1121
1122         /*
1123          * Initialize receiver window
1124          */
1125         SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin);
1126
1127         /*
1128          * Free PDU buffers
1129          */
1130         KB_FREEALL(m);
1131
1132         /*
1133          * Acknowledge ER
1134          */
1135         sscop_send_erak(sop);
1136
1137         /*
1138          * Deliver any outstanding data to user
1139          */
1140         q2110_deliver_data(sop);
1141
1142         /*
1143          * Notify user of connection recovery
1144          */
1145         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1146                 sop->so_connvc, 0, 0, err);
1147         if (err) {
1148                 sscop_abort(sop, "stack memory\n");
1149                 return;
1150         }
1151
1152         /*
1153          * Wait for user response
1154          */
1155         sop->so_state = SOS_RECOVRSP;
1156
1157         return;
1158 }
1159
1160
1161 /*
1162  * ER PDU / SOS_RECOVRSP Processor
1163  * 
1164  * Arguments:
1165  *      sop     pointer to sscop connection block
1166  *      m       pointer to PDU buffer (without trailer)
1167  *      trlr    pointer to PDU trailer
1168  *
1169  * Returns:
1170  *      none
1171  *
1172  */
1173 static void
1174 sscop_er_recovrsp(struct sscop *sop, KBuffer *m, caddr_t trlr)
1175 {
1176         struct er_pdu   *ep = (struct er_pdu *)trlr;
1177
1178         /*
1179          * If retransmitted ER, just ACK it
1180          */
1181         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1182                 KB_FREEALL(m);
1183                 sscop_send_erak(sop);
1184                 return;
1185         }
1186
1187         /*
1188          * Report error condition
1189          */
1190         sscop_er_error(sop, m, trlr);
1191
1192         return;
1193 }
1194
1195
1196 /*
1197  * ER PDU / SOS_INRECOV Processor
1198  * 
1199  * Arguments:
1200  *      sop     pointer to sscop connection block
1201  *      m       pointer to PDU buffer (without trailer)
1202  *      trlr    pointer to PDU trailer
1203  *
1204  * Returns:
1205  *      none
1206  *
1207  */
1208 static void
1209 sscop_er_inrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1210 {
1211         struct er_pdu   *ep = (struct er_pdu *)trlr;
1212
1213         /*
1214          * If retransmitted ER, just ignore it
1215          */
1216         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1217                 KB_FREEALL(m);
1218                 return;
1219         }
1220
1221         /*
1222          * Report error condition
1223          */
1224         sscop_er_error(sop, m, trlr);
1225
1226         return;
1227 }
1228
1229
1230 /*
1231  * ER PDU / SOS_READY Processor
1232  * 
1233  * Arguments:
1234  *      sop     pointer to sscop connection block
1235  *      m       pointer to PDU buffer (without trailer)
1236  *      trlr    pointer to PDU trailer
1237  *
1238  * Returns:
1239  *      none
1240  *
1241  */
1242 static void
1243 sscop_er_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1244 {
1245         struct er_pdu   *ep = (struct er_pdu *)trlr;
1246         int             err;
1247
1248         /*
1249          * If retransmitted ER, just ACK it
1250          */
1251         if (sscop_is_rexmit(sop, ep->er_nsq)) {
1252                 KB_FREEALL(m);
1253                 sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp;
1254                 sscop_send_erak(sop);
1255                 return;
1256         }
1257
1258         /*
1259          * Stop data transfer timers
1260          */
1261         sop->so_timer[SSCOP_T_POLL] = 0;
1262         sop->so_timer[SSCOP_T_NORESP] = 0;
1263         sop->so_timer[SSCOP_T_IDLE] = 0;
1264         sop->so_flags &= ~SOF_KEEPALIVE;
1265
1266         /*
1267          * Initialize transmit window
1268          */
1269         SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr));
1270
1271         /*
1272          * Free PDU buffers
1273          */
1274         KB_FREEALL(m);
1275
1276         /*
1277          * Clear out appropriate queues
1278          */
1279         q2110_prep_recovery(sop);
1280
1281         /*
1282          * Deliver any outstanding data to user
1283          */
1284         q2110_deliver_data(sop);
1285
1286         /*
1287          * Notify user of connection recovery
1288          */
1289         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1290                 sop->so_connvc, 0, 0, err);
1291         if (err) {
1292                 sscop_abort(sop, "stack memory\n");
1293                 return;
1294         }
1295
1296         /*
1297          * Wait for user response
1298          */
1299         sop->so_state = SOS_INRECOV;
1300
1301         return;
1302 }
1303
1304
1305 /*
1306  * ERAK PDU / Protocol Error
1307  *
1308  * Arguments:
1309  *      sop     pointer to sscop connection block
1310  *      m       pointer to PDU buffer (without trailer)
1311  *      trlr    pointer to PDU trailer
1312  *
1313  * Returns:
1314  *      none
1315  *
1316  */
1317 static void
1318 sscop_erak_error(struct sscop *sop, KBuffer *m, caddr_t trlr)
1319 {
1320
1321         /*
1322          * Record error condition
1323          */
1324         sscop_maa_error(sop, 'M');
1325         KB_FREEALL(m);
1326
1327         return;
1328 }
1329
1330
1331 /*
1332  * ERAK PDU / SOS_IDLE Processor
1333  *
1334  * Arguments:
1335  *      sop     pointer to sscop connection block
1336  *      m       pointer to PDU buffer (without trailer)
1337  *      trlr    pointer to PDU trailer
1338  *
1339  * Returns:
1340  *      none
1341  *
1342  */
1343 static void
1344 sscop_erak_idle(struct sscop *sop, KBuffer *m, caddr_t trlr)
1345 {
1346
1347         /*
1348          * Record error condition
1349          */
1350         sscop_erak_error(sop, m, trlr);
1351
1352         /*
1353          * Return an END to peer
1354          */
1355         sscop_send_end(sop, SSCOP_SOURCE_SSCOP);
1356
1357         return;
1358 }
1359
1360
1361 /*
1362  * ERAK PDU / SOS_OUTRECOV Processor
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_outrecov(struct sscop *sop, KBuffer *m, caddr_t trlr)
1375 {
1376         struct erak_pdu *ep = (struct erak_pdu *)trlr;
1377         int             err;
1378
1379         /*
1380          * Stop retransmit timer
1381          */
1382         sop->so_timer[SSCOP_T_CC] = 0;
1383
1384         /*
1385          * Initialize transmit window
1386          */
1387         SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr));
1388
1389         /*
1390          * Free PDU buffers
1391          */
1392         KB_FREEALL(m);
1393
1394         /*
1395          * Deliver any outstanding data to user
1396          */
1397         q2110_deliver_data(sop);
1398
1399         /*
1400          * Notify user of connection recovery
1401          */
1402         STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, 
1403                 sop->so_connvc, 0, 0, err);
1404         if (err) {
1405                 sscop_abort(sop, "stack memory\n");
1406                 return;
1407         }
1408
1409         /*
1410          * Wait for user response
1411          */
1412         sop->so_state = SOS_RECOVRSP;
1413
1414         return;
1415 }
1416
1417
1418 /*
1419  * SD PDU / SOS_READY 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_sd_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1432 {
1433         struct sd_pdu   *sp = (struct sd_pdu *)trlr;
1434         struct pdu_hdr  *php;
1435         KBuffer         *n;
1436         sscop_seq       ns;
1437         int             err, space;
1438
1439         /*
1440          * Get PDU sequence number
1441          */
1442         SEQ_SET(ns, ntohl(sp->sd_ns));
1443
1444         /*
1445          * Ensure that the sequence number fits within the window
1446          */
1447         if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) {
1448                 /*
1449                  * It doesn't, drop received data
1450                  */
1451                 KB_FREEALL(m);
1452
1453                 /*
1454                  * If next highest PDU hasn't reached window end yet,
1455                  * then send a USTAT to inform transmitter of this gap
1456                  */
1457                 if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) { 
1458                         sscop_send_ustat(sop, sop->so_rcvmax);
1459                         sop->so_rcvhigh = sop->so_rcvmax;
1460                 }
1461                 return;
1462         }
1463
1464         /*
1465          * If this is the next in-sequence PDU, hand it to user
1466          */
1467         if (ns == sop->so_rcvnext) {
1468                 STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1469                         sop->so_connvc, (int)m, ns, err);
1470                 if (err) {
1471                         KB_FREEALL(m);
1472                         return;
1473                 }
1474
1475                 /*
1476                  * Bump next expected sequence number
1477                  */
1478                 SEQ_INCR(sop->so_rcvnext, 1);
1479
1480                 /*
1481                  * Slide receive window down
1482                  */
1483                 SEQ_INCR(sop->so_rcvmax, 1);
1484
1485                 /*
1486                  * Is this the highest sequence PDU we've received??
1487                  */
1488                 if (ns == sop->so_rcvhigh) {
1489                         /*
1490                          * Yes, bump the limit and exit
1491                          */
1492                         sop->so_rcvhigh = sop->so_rcvnext;
1493                         return;
1494                 }
1495
1496                 /*
1497                  * This is a retransmitted PDU, so see if we have
1498                  * more in-sequence PDUs already queued up
1499                  */
1500                 while ((php = sop->so_recv_hd) &&
1501                        (php->ph_ns == sop->so_rcvnext)) {
1502
1503                         /*
1504                          * Yup we do, so remove next PDU from queue and
1505                          * pass it up to the user as well
1506                          */
1507                         sop->so_recv_hd = php->ph_recv_lk;
1508                         if (sop->so_recv_hd == NULL)
1509                                 sop->so_recv_tl = NULL;
1510                         STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku,
1511                                 sop->so_connvc, (int)php->ph_buf, php->ph_ns,
1512                                 err);
1513                         if (err) {
1514                                 /*
1515                                  * Should never happen, but...
1516                                  */
1517                                 KB_FREEALL(php->ph_buf);
1518                                 sscop_abort(sop, "stack memory\n");
1519                                 return;
1520                         }
1521
1522                         /*
1523                          * Bump next expected sequence number
1524                          */
1525                         SEQ_INCR(sop->so_rcvnext, 1);
1526
1527                         /*
1528                          * Slide receive window down
1529                          */
1530                         SEQ_INCR(sop->so_rcvmax, 1);
1531                 }
1532
1533                 /*
1534                  * Finished with data delivery...
1535                  */
1536                 return;
1537         }
1538
1539         /*
1540          * We're gonna have to queue this PDU, so find space
1541          * for the PDU header
1542          */
1543         KB_HEADROOM(m, space);
1544
1545         /*
1546          * If there's not enough room in the received buffer,
1547          * allocate & link a new buffer for the header
1548          */
1549         if (space < sizeof(struct pdu_hdr)) {
1550
1551                 KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER);
1552                 if (n == NULL) {
1553                         KB_FREEALL(m);
1554                         return;
1555                 }
1556                 KB_HEADSET(n, sizeof(struct pdu_hdr));
1557                 KB_LEN(n) = 0;
1558                 KB_LINKHEAD(n, m);
1559                 m = n;
1560         }
1561
1562         /*
1563          * Build PDU header
1564          *
1565          * We can at least assume/require that the start of
1566          * the user data is aligned.  Also note that we don't
1567          * include this header in the buffer len/offset fields.
1568          */
1569         KB_DATASTART(m, php, struct pdu_hdr *);
1570         php--;
1571         php->ph_ns = ns;
1572         php->ph_buf = m;
1573
1574         /*
1575          * Insert PDU into the receive queue
1576          */
1577         if (sscop_recv_insert(sop, php)) {
1578                 /*
1579                  * Oops, a duplicate sequence number PDU is already on
1580                  * the queue, somethings wrong here.
1581                  */
1582                 sscop_maa_error(sop, 'Q');
1583
1584                 /*
1585                  * Free buffers
1586                  */
1587                 KB_FREEALL(m);
1588
1589                 /*
1590                  * Go into recovery mode
1591                  */
1592                 q2110_error_recovery(sop);
1593
1594                 return;
1595         }
1596
1597         /*
1598          * Are we at the high-water mark??
1599          */
1600         if (ns == sop->so_rcvhigh) {
1601                 /*
1602                  * Yes, just bump the mark
1603                  */
1604                 SEQ_INCR(sop->so_rcvhigh, 1);
1605
1606                 return;
1607         }
1608
1609         /*
1610          * Are we beyond the high-water mark??
1611          */
1612         if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1613                 /*
1614                  * Yes, then there's a missing PDU, so inform the transmitter
1615                  */
1616                 sscop_send_ustat(sop, ns);
1617
1618                 /*
1619                  * Update high-water mark
1620                  */
1621                 sop->so_rcvhigh = SEQ_ADD(ns, 1);
1622         }
1623
1624         return;
1625 }
1626
1627
1628 /*
1629  * POLL PDU / SOS_READY Processor
1630  *
1631  * Arguments:
1632  *      sop     pointer to sscop connection block
1633  *      m       pointer to PDU buffer (without trailer)
1634  *      trlr    pointer to PDU trailer
1635  *
1636  * Returns:
1637  *      none
1638  *
1639  */
1640 static void
1641 sscop_poll_ready(struct sscop *sop, KBuffer *m, caddr_t trlr)
1642 {
1643         struct poll_pdu *pp = (struct poll_pdu *)trlr;
1644         sscop_seq       nps;
1645
1646         pp->poll_ns = ntohl(pp->poll_ns);
1647
1648         /*
1649          * If the poll sequence number is less than highest number
1650          * we've already seen, something's wrong
1651          */
1652         if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) {
1653                 /*
1654                  * Record error condition
1655                  */
1656                 sscop_maa_error(sop, 'Q');
1657
1658                 /*
1659                  * Free buffers
1660                  */
1661                 KB_FREEALL(m);
1662
1663                 /*
1664                  * Go into recovery mode
1665                  */
1666                 q2110_error_recovery(sop);
1667
1668                 return;
1669         }
1670
1671         /*
1672          * Set a new "next highest" sequence number expected
1673          */
1674         if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext))
1675                 SEQ_SET(sop->so_rcvhigh, pp->poll_ns);
1676         else
1677                 sop->so_rcvhigh = sop->so_rcvmax;
1678
1679         /*
1680          * Return a STAT PDU to peer
1681          */
1682         SEQ_SET(nps, ntohl(pp->poll_nps));
1683         KB_FREEALL(m);
1684         sscop_send_stat(sop, nps);
1685
1686         return;
1687 }
1688