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