kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / netproto / atm / uni / sscop_upper.c
... / ...
CommitLineData
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 */
48static caddr_t sscop_pdu_receive __P((KBuffer *, struct sscop *, int *));
49
50
51/*
52 * Local variables
53 */
54static 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 */
79struct pdulen {
80 int min;
81 int max;
82};
83
84static 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
103static 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 */
126static 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
145static 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 */
183void
184sscop_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 */
265static caddr_t
266sscop_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
396badpdu:
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