kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / uni / sscop_upper.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/sscop_upper.c,v 1.5 2000/01/17 20:49:54 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/sscop_upper.c,v 1.4 2003/08/07 21:54:34 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI Support
32  * ---------------------
33  *
34  * SSCOP - CPCS SAP interface processing
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 caddr_t  sscop_pdu_receive __P((KBuffer *, struct sscop *, int *));
49
50
51 /*
52  * Local variables
53  */
54 static union {
55         struct bgn_pdu          t_bgn;
56         struct bgak_pdu         t_bgak;
57         struct end_pdu          t_end;
58         struct endak_q2110_pdu  t_endak_q2110;
59         struct endak_qsaal_pdu  t_endak_qsaal;
60         struct rs_pdu           t_rs;
61         struct rsak_q2110_pdu   t_rsak_q2110;
62         struct rsak_qsaal_pdu   t_rsak_qsaal;
63         struct bgrej_pdu        t_bgrej;
64         struct sd_pdu           t_sd;
65         struct sdp_pdu          t_sdp;
66         struct er_pdu           t_er;
67         struct poll_pdu         t_poll;
68         struct stat_pdu         t_stat;
69         struct ustat_pdu        t_ustat;
70         struct ud_pdu           t_ud;
71         struct md_pdu           t_md;
72         struct erak_pdu         t_erak;
73 } sscop_trailer;
74
75
76 /*
77  * PDU length validation table
78  */
79 struct pdulen {
80         int     min;
81         int     max;
82 };
83
84 static struct pdulen qsaal_pdulen[] = {
85         {0,                             0},
86         {sizeof(struct bgn_pdu),        sizeof(struct bgn_pdu)},
87         {sizeof(struct bgak_pdu),       sizeof(struct bgak_pdu)},
88         {sizeof(struct end_pdu),        sizeof(struct end_pdu)},
89         {sizeof(struct endak_qsaal_pdu),sizeof(struct endak_qsaal_pdu)},
90         {sizeof(struct rs_pdu),         sizeof(struct rs_pdu)},
91         {sizeof(struct rsak_qsaal_pdu), sizeof(struct rsak_qsaal_pdu)},
92         {sizeof(struct bgrej_pdu),      sizeof(struct bgrej_pdu)},
93         {sizeof(struct sd_pdu),         sizeof(struct sd_pdu) + PDU_MAX_INFO},
94         {sizeof(struct sdp_pdu),        sizeof(struct sdp_pdu) + PDU_MAX_INFO},
95         {sizeof(struct poll_pdu),       sizeof(struct poll_pdu)},
96         {sizeof(struct stat_pdu),       sizeof(struct stat_pdu) + PDU_MAX_STAT},
97         {sizeof(struct ustat_pdu),      sizeof(struct ustat_pdu)},
98         {sizeof(struct ud_pdu),         sizeof(struct ud_pdu) + PDU_MAX_INFO},
99         {sizeof(struct md_pdu),         sizeof(struct md_pdu) + PDU_MAX_INFO},
100         {0,                             0}
101 };
102
103 static struct pdulen q2110_pdulen[] = {
104         {0,                             0},
105         {sizeof(struct bgn_pdu),        sizeof(struct bgn_pdu) + PDU_MAX_UU},
106         {sizeof(struct bgak_pdu),       sizeof(struct bgak_pdu) + PDU_MAX_UU},
107         {sizeof(struct end_pdu),        sizeof(struct end_pdu) + PDU_MAX_UU},
108         {sizeof(struct endak_q2110_pdu),sizeof(struct endak_q2110_pdu)},
109         {sizeof(struct rs_pdu),         sizeof(struct rs_pdu) + PDU_MAX_UU},
110         {sizeof(struct rsak_q2110_pdu), sizeof(struct rsak_q2110_pdu)},
111         {sizeof(struct bgrej_pdu),      sizeof(struct bgrej_pdu) + PDU_MAX_UU},
112         {sizeof(struct sd_pdu),         sizeof(struct sd_pdu) + PDU_MAX_INFO},
113         {sizeof(struct er_pdu),         sizeof(struct er_pdu)},
114         {sizeof(struct poll_pdu),       sizeof(struct poll_pdu)},
115         {sizeof(struct stat_pdu),       sizeof(struct stat_pdu) + PDU_MAX_STAT},
116         {sizeof(struct ustat_pdu),      sizeof(struct ustat_pdu)},
117         {sizeof(struct ud_pdu),         sizeof(struct ud_pdu) + PDU_MAX_INFO},
118         {sizeof(struct md_pdu),         sizeof(struct md_pdu) + PDU_MAX_INFO},
119         {sizeof(struct erak_pdu),       sizeof(struct erak_pdu)}
120 };
121
122
123 /*
124  * PDUs with Pad Length Fields
125  */
126 static u_char qsaal_padlen[] = {
127         0,                      /* --- */
128         0,                      /* BGN */
129         0,                      /* BGAK */
130         0,                      /* END */
131         0,                      /* ENDAK */
132         0,                      /* RS */
133         0,                      /* RSAK */
134         0,                      /* BGREJ */
135         1,                      /* SD */
136         1,                      /* SDP */
137         0,                      /* POLL */
138         0,                      /* STAT */
139         0,                      /* USTAT */
140         1,                      /* UD */
141         1,                      /* MD */
142         0                       /* --- */
143 };
144
145 static u_char q2110_padlen[] = {
146         0,                      /* --- */
147         1,                      /* BGN */
148         1,                      /* BGAK */
149         1,                      /* END */
150         0,                      /* ENDAK */
151         1,                      /* RS */
152         0,                      /* RSAK */
153         1,                      /* BGREJ */
154         1,                      /* SD */
155         0,                      /* ER */
156         0,                      /* POLL */
157         0,                      /* STAT */
158         0,                      /* USTAT */
159         1,                      /* UD */
160         1,                      /* MD */
161         0                       /* ERAK */
162 };
163
164
165 /*
166  * SSCOP Upper Stack Command Handler
167  * 
168  * This function will receive all of the stack commands issued from the 
169  * layer below SSCOP (ie. CPCS).  Currently, only incoming PDUs will be
170  * received here.  The appropriate processing function will be determined 
171  * based on the received PDU type and the current sscop control block state.
172  *
173  * Arguments:
174  *      cmd     stack command code
175  *      tok     session token
176  *      arg1    command specific argument
177  *      arg2    command specific argument
178  *
179  * Returns:
180  *      none
181  *
182  */
183 void
184 sscop_upper(cmd, tok, arg1, arg2)
185         int     cmd;
186         void    *tok;
187         int     arg1;
188         int     arg2;
189 {
190         struct sscop    *sop = (struct sscop *)tok;
191         void            (**ptab) __P((struct sscop *, KBuffer *, caddr_t));
192         void            (*func) __P((struct sscop *, KBuffer *, caddr_t));
193         caddr_t         trlr;
194         int             type;
195
196         ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=%p, state=%d, arg1=0x%x, arg2=0x%x\n",
197                 cmd, sop, sop->so_state, arg1, arg2);
198
199         switch (cmd) {
200
201         case CPCS_UNITDATA_SIG:
202                 /*
203                  * Decode/validate received PDU
204                  */
205                 trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type);
206                 if (trlr == NULL) {
207                         return;
208                 }
209
210                 /*
211                  * Validate sscop state
212                  */
213                 if (sop->so_state > SOS_MAXSTATE) {
214                         log(LOG_ERR, 
215                                 "sscop_upper: invalid state sop=%p, state=%d\n",
216                                 sop, sop->so_state);
217                         KB_FREEALL((KBuffer *)arg1);
218                         return;
219                 }
220
221                 /*
222                  * Call event processing function
223                  */
224                 ptab = sop->so_vers == SSCOP_VERS_QSAAL ?
225                                 sscop_qsaal_pdutab[type]:
226                                 sscop_q2110_pdutab[type];
227                 func = ptab[sop->so_state];
228                 if (func == NULL) {
229                         log(LOG_ERR, 
230                                 "sscop_upper: unsupported pdu=%d, state=%d\n",
231                                 type, sop->so_state);
232                         break;
233                 }
234                 (*func)(sop, (KBuffer *)arg1, trlr);
235                 break;
236
237         default:
238                 log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=%p\n",
239                         cmd, sop);
240         }
241
242         return;
243 }
244
245
246 /*
247  * Decode and Validate Received PDU
248  * 
249  * This function will process all received SSCOP PDUs.  The PDU type will be
250  * determined and PDU format validation will be performed.  If the PDU is
251  * successfully decoded and validated, the buffer chain will have the PDU
252  * trailer removed, but any resultant zero-length buffers will NOT be freed.  
253  * If the PDU fails validation, then the buffer chain will be freed.
254  *
255  * Arguments:
256  *      m       pointer to PDU buffer chain
257  *      sop     pointer to sscop connection block
258  *      typep   address to store PDU type
259  *
260  * Returns:
261  *      addr    pointer to (contiguous) PDU trailer
262  *      0       invalid PDU, buffer chain freed
263  *
264  */
265 static caddr_t
266 sscop_pdu_receive(m, sop, typep)
267         KBuffer         *m;
268         struct sscop    *sop;
269         int             *typep;
270 {
271         KBuffer         *m0, *ml, *mn;
272         caddr_t         cp, tp;
273         int             len, tlen, type, plen;
274
275         /*
276          * Calculate PDU length and find the last two buffers in the chain
277          */
278         len = 0;
279         for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) {
280                 len += KB_LEN(m0);
281                 mn = ml;
282                 ml = m0;
283         }
284
285         /*
286          * Make sure we've got a minimum sized PDU
287          */
288         if (len < PDU_MIN_LEN)
289                 goto badpdu;
290
291         /*
292          * Get PDU type field
293          */
294         if (KB_LEN(ml) >= PDU_MIN_LEN) {
295                 KB_DATAEND(ml, tp, caddr_t);
296                 tp -= PDU_MIN_LEN;
297         } else {
298                 KB_DATAEND(mn, tp, caddr_t);
299                 tp -= (PDU_MIN_LEN - KB_LEN(ml));
300         }
301         *typep = type = *tp & PT_TYPE_MASK;
302
303         /*
304          * Check up on PDU length
305          */
306         if (sop->so_vers == SSCOP_VERS_QSAAL) {
307                 if ((len < (tlen = qsaal_pdulen[type].min)) ||
308                     (len > qsaal_pdulen[type].max) ||
309                     (len & PDU_LEN_MASK))
310                         goto badpdu;
311         } else {
312                 if ((len < (tlen = q2110_pdulen[type].min)) ||
313                     (len > q2110_pdulen[type].max) ||
314                     (len & PDU_LEN_MASK))
315                         goto badpdu;
316         }
317
318         /*
319          * Get a contiguous, aligned PDU trailer and adjust buffer
320          * controls to remove trailer
321          */
322         if (KB_LEN(ml) >= tlen) {
323                 /*
324                  * Trailer is contained in last buffer
325                  */
326                 KB_TAILADJ(ml, -tlen);
327                 KB_DATAEND(ml, cp, caddr_t);
328                 if ((int)cp & PDU_ADDR_MASK) {
329                         /*
330                          * Trailer not aligned in buffer, use local memory
331                          */
332                         KM_COPY(cp, (caddr_t)&sscop_trailer, tlen);
333                         cp = (caddr_t)&sscop_trailer;
334                 }
335         } else {
336                 /*
337                  * Trailer is split across buffers, use local memory
338                  */
339                 caddr_t cp1;
340                 int     off = tlen - KB_LEN(ml);
341
342                 cp = (caddr_t)&sscop_trailer;
343
344                 /*
345                  * Ensure trailer is within last two buffers
346                  */
347                 if ((mn == NULL) || (KB_LEN(mn) < off))
348                         goto badpdu;
349
350                 KB_DATASTART(ml, cp1, caddr_t);
351                 KM_COPY(cp1, cp + off, KB_LEN(ml));
352                 KB_LEN(ml) = 0;
353                 KB_TAILADJ(mn, -off);
354                 KB_DATAEND(mn, cp1, caddr_t);
355                 KM_COPY(cp1, cp, off);
356         }
357
358         /*
359          * Get possible PDU Pad Length
360          */
361         if (sop->so_vers == SSCOP_VERS_QSAAL) {
362                 if (qsaal_padlen[type])
363                         plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
364                 else
365                         plen = 0;
366         } else {
367                 if (q2110_padlen[type])
368                         plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
369                 else
370                         plen = 0;
371         }
372
373         /*
374          * Perform Pad Length adjustments 
375          */
376         if (plen) {
377                 if (KB_LEN(ml) >= plen) {
378                         /*
379                          * All pad bytes in last buffer
380                          */
381                         KB_TAILADJ(ml, -plen);
382                 } else {
383                         /*
384                          * Pad bytes split between buffers
385                          */
386                         plen -= KB_LEN(ml);
387                         if ((mn == NULL) || (KB_LEN(mn) < plen))
388                                 goto badpdu;
389                         KB_LEN(ml) = 0;
390                         KB_TAILADJ(mn, -plen);
391                 }
392         }
393
394         return (cp);
395
396 badpdu:
397         /*
398          * This MAA Error is only supposed to be for a PDU length violation,
399          * but we use it for any PDU format error.
400          */
401         sscop_maa_error(sop, 'U');
402         sscop_pdu_print(sop, m, "badpdu received");
403         KB_FREEALL(m);
404         return (NULL);
405 }
406