kernel: Sync ACPICA with Intel's version 20140424.
[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.6 2006/01/14 13:36:39 swildner 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 (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(int cmd, void *tok, int arg1, int arg2)
185 {
186         struct sscop    *sop = (struct sscop *)tok;
187         void            (**ptab) (struct sscop *, KBuffer *, caddr_t);
188         void            (*func) (struct sscop *, KBuffer *, caddr_t);
189         caddr_t         trlr;
190         int             type;
191
192         ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=%p, state=%d, arg1=0x%x, arg2=0x%x\n",
193                 cmd, sop, sop->so_state, arg1, arg2);
194
195         switch (cmd) {
196
197         case CPCS_UNITDATA_SIG:
198                 /*
199                  * Decode/validate received PDU
200                  */
201                 trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type);
202                 if (trlr == NULL) {
203                         return;
204                 }
205
206                 /*
207                  * Validate sscop state
208                  */
209                 if (sop->so_state > SOS_MAXSTATE) {
210                         log(LOG_ERR, 
211                                 "sscop_upper: invalid state sop=%p, state=%d\n",
212                                 sop, sop->so_state);
213                         KB_FREEALL((KBuffer *)arg1);
214                         return;
215                 }
216
217                 /*
218                  * Call event processing function
219                  */
220                 ptab = sop->so_vers == SSCOP_VERS_QSAAL ?
221                                 sscop_qsaal_pdutab[type]:
222                                 sscop_q2110_pdutab[type];
223                 func = ptab[sop->so_state];
224                 if (func == NULL) {
225                         log(LOG_ERR, 
226                                 "sscop_upper: unsupported pdu=%d, state=%d\n",
227                                 type, sop->so_state);
228                         break;
229                 }
230                 (*func)(sop, (KBuffer *)arg1, trlr);
231                 break;
232
233         default:
234                 log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=%p\n",
235                         cmd, sop);
236         }
237
238         return;
239 }
240
241
242 /*
243  * Decode and Validate Received PDU
244  * 
245  * This function will process all received SSCOP PDUs.  The PDU type will be
246  * determined and PDU format validation will be performed.  If the PDU is
247  * successfully decoded and validated, the buffer chain will have the PDU
248  * trailer removed, but any resultant zero-length buffers will NOT be freed.  
249  * If the PDU fails validation, then the buffer chain will be freed.
250  *
251  * Arguments:
252  *      m       pointer to PDU buffer chain
253  *      sop     pointer to sscop connection block
254  *      typep   address to store PDU type
255  *
256  * Returns:
257  *      addr    pointer to (contiguous) PDU trailer
258  *      0       invalid PDU, buffer chain freed
259  *
260  */
261 static caddr_t
262 sscop_pdu_receive(KBuffer *m, struct sscop *sop, int *typep)
263 {
264         KBuffer         *m0, *ml, *mn;
265         caddr_t         cp, tp;
266         int             len, tlen, type, plen;
267
268         /*
269          * Calculate PDU length and find the last two buffers in the chain
270          */
271         len = 0;
272         for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) {
273                 len += KB_LEN(m0);
274                 mn = ml;
275                 ml = m0;
276         }
277
278         /*
279          * Make sure we've got a minimum sized PDU
280          */
281         if (len < PDU_MIN_LEN)
282                 goto badpdu;
283
284         /*
285          * Get PDU type field
286          */
287         if (KB_LEN(ml) >= PDU_MIN_LEN) {
288                 KB_DATAEND(ml, tp, caddr_t);
289                 tp -= PDU_MIN_LEN;
290         } else {
291                 KB_DATAEND(mn, tp, caddr_t);
292                 tp -= (PDU_MIN_LEN - KB_LEN(ml));
293         }
294         *typep = type = *tp & PT_TYPE_MASK;
295
296         /*
297          * Check up on PDU length
298          */
299         if (sop->so_vers == SSCOP_VERS_QSAAL) {
300                 if ((len < (tlen = qsaal_pdulen[type].min)) ||
301                     (len > qsaal_pdulen[type].max) ||
302                     (len & PDU_LEN_MASK))
303                         goto badpdu;
304         } else {
305                 if ((len < (tlen = q2110_pdulen[type].min)) ||
306                     (len > q2110_pdulen[type].max) ||
307                     (len & PDU_LEN_MASK))
308                         goto badpdu;
309         }
310
311         /*
312          * Get a contiguous, aligned PDU trailer and adjust buffer
313          * controls to remove trailer
314          */
315         if (KB_LEN(ml) >= tlen) {
316                 /*
317                  * Trailer is contained in last buffer
318                  */
319                 KB_TAILADJ(ml, -tlen);
320                 KB_DATAEND(ml, cp, caddr_t);
321                 if ((int)cp & PDU_ADDR_MASK) {
322                         /*
323                          * Trailer not aligned in buffer, use local memory
324                          */
325                         KM_COPY(cp, (caddr_t)&sscop_trailer, tlen);
326                         cp = (caddr_t)&sscop_trailer;
327                 }
328         } else {
329                 /*
330                  * Trailer is split across buffers, use local memory
331                  */
332                 caddr_t cp1;
333                 int     off = tlen - KB_LEN(ml);
334
335                 cp = (caddr_t)&sscop_trailer;
336
337                 /*
338                  * Ensure trailer is within last two buffers
339                  */
340                 if ((mn == NULL) || (KB_LEN(mn) < off))
341                         goto badpdu;
342
343                 KB_DATASTART(ml, cp1, caddr_t);
344                 KM_COPY(cp1, cp + off, KB_LEN(ml));
345                 KB_LEN(ml) = 0;
346                 KB_TAILADJ(mn, -off);
347                 KB_DATAEND(mn, cp1, caddr_t);
348                 KM_COPY(cp1, cp, off);
349         }
350
351         /*
352          * Get possible PDU Pad Length
353          */
354         if (sop->so_vers == SSCOP_VERS_QSAAL) {
355                 if (qsaal_padlen[type])
356                         plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
357                 else
358                         plen = 0;
359         } else {
360                 if (q2110_padlen[type])
361                         plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT;
362                 else
363                         plen = 0;
364         }
365
366         /*
367          * Perform Pad Length adjustments 
368          */
369         if (plen) {
370                 if (KB_LEN(ml) >= plen) {
371                         /*
372                          * All pad bytes in last buffer
373                          */
374                         KB_TAILADJ(ml, -plen);
375                 } else {
376                         /*
377                          * Pad bytes split between buffers
378                          */
379                         plen -= KB_LEN(ml);
380                         if ((mn == NULL) || (KB_LEN(mn) < plen))
381                                 goto badpdu;
382                         KB_LEN(ml) = 0;
383                         KB_TAILADJ(mn, -plen);
384                 }
385         }
386
387         return (cp);
388
389 badpdu:
390         /*
391          * This MAA Error is only supposed to be for a PDU length violation,
392          * but we use it for any PDU format error.
393          */
394         sscop_maa_error(sop, 'U');
395         sscop_pdu_print(sop, m, "badpdu received");
396         KB_FREEALL(m);
397         return (NULL);
398 }
399