| 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 | |