HAMMER Utilities: MFC work to date.
[dragonfly.git] / sys / netproto / atm / uni / sscop_upper.c
blob05012df8dd4ce1c283b388a68eeb24205e7b5bb0
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
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 $
31 * ATM Forum UNI Support
32 * ---------------------
34 * SSCOP - CPCS SAP interface processing
38 #include <netproto/atm/kern_include.h>
40 #include "sscop.h"
41 #include "sscop_misc.h"
42 #include "sscop_pdu.h"
43 #include "sscop_var.h"
46 * Local functions
48 static caddr_t sscop_pdu_receive (KBuffer *, struct sscop *, int *);
52 * Local variables
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;
77 * PDU length validation table
79 struct pdulen {
80 int min;
81 int max;
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}
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)}
124 * PDUs with Pad Length Fields
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 /* --- */
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 */
166 * SSCOP Upper Stack Command Handler
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.
173 * Arguments:
174 * cmd stack command code
175 * tok session token
176 * arg1 command specific argument
177 * arg2 command specific argument
179 * Returns:
180 * none
183 void
184 sscop_upper(int cmd, void *tok, int arg1, int arg2)
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;
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);
195 switch (cmd) {
197 case CPCS_UNITDATA_SIG:
199 * Decode/validate received PDU
201 trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type);
202 if (trlr == NULL) {
203 return;
207 * Validate sscop state
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;
218 * Call event processing function
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;
230 (*func)(sop, (KBuffer *)arg1, trlr);
231 break;
233 default:
234 log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=%p\n",
235 cmd, sop);
238 return;
243 * Decode and Validate Received PDU
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.
251 * Arguments:
252 * m pointer to PDU buffer chain
253 * sop pointer to sscop connection block
254 * typep address to store PDU type
256 * Returns:
257 * addr pointer to (contiguous) PDU trailer
258 * 0 invalid PDU, buffer chain freed
261 static caddr_t
262 sscop_pdu_receive(KBuffer *m, struct sscop *sop, int *typep)
264 KBuffer *m0, *ml, *mn;
265 caddr_t cp, tp;
266 int len, tlen, type, plen;
269 * Calculate PDU length and find the last two buffers in the chain
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;
279 * Make sure we've got a minimum sized PDU
281 if (len < PDU_MIN_LEN)
282 goto badpdu;
285 * Get PDU type field
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));
294 *typep = type = *tp & PT_TYPE_MASK;
297 * Check up on PDU length
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;
312 * Get a contiguous, aligned PDU trailer and adjust buffer
313 * controls to remove trailer
315 if (KB_LEN(ml) >= tlen) {
317 * Trailer is contained in last buffer
319 KB_TAILADJ(ml, -tlen);
320 KB_DATAEND(ml, cp, caddr_t);
321 if ((int)cp & PDU_ADDR_MASK) {
323 * Trailer not aligned in buffer, use local memory
325 KM_COPY(cp, (caddr_t)&sscop_trailer, tlen);
326 cp = (caddr_t)&sscop_trailer;
328 } else {
330 * Trailer is split across buffers, use local memory
332 caddr_t cp1;
333 int off = tlen - KB_LEN(ml);
335 cp = (caddr_t)&sscop_trailer;
338 * Ensure trailer is within last two buffers
340 if ((mn == NULL) || (KB_LEN(mn) < off))
341 goto badpdu;
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);
352 * Get possible PDU Pad Length
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;
367 * Perform Pad Length adjustments
369 if (plen) {
370 if (KB_LEN(ml) >= plen) {
372 * All pad bytes in last buffer
374 KB_TAILADJ(ml, -plen);
375 } else {
377 * Pad bytes split between buffers
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);
387 return (cp);
389 badpdu:
391 * This MAA Error is only supposed to be for a PDU length violation,
392 * but we use it for any PDU format error.
394 sscop_maa_error(sop, 'U');
395 sscop_pdu_print(sop, m, "badpdu received");
396 KB_FREEALL(m);
397 return (NULL);