diff options
Diffstat (limited to 'sys/contrib/ngatm/netnatm/msg/uni_ie.c')
-rw-r--r-- | sys/contrib/ngatm/netnatm/msg/uni_ie.c | 7162 |
1 files changed, 7162 insertions, 0 deletions
diff --git a/sys/contrib/ngatm/netnatm/msg/uni_ie.c b/sys/contrib/ngatm/netnatm/msg/uni_ie.c new file mode 100644 index 0000000..b6a2b78 --- /dev/null +++ b/sys/contrib/ngatm/netnatm/msg/uni_ie.c @@ -0,0 +1,7162 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Author: Hartmut Brandt <harti@freebsd.org> + * + * $Begemot: libunimsg/atm/msg/uni_ie.c,v 1.12 2003/10/14 15:02:22 hbb Exp $ + * + * Private definitions for the IE code file. + * + * This file includes the table generated automatically. + */ + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef _KERNEL +#include <sys/libkern.h> +#else +#include <string.h> +#endif +#include <netnatm/unimsg.h> +#include <netnatm/msg/unistruct.h> +#include <netnatm/msg/unimsglib.h> +#include <netnatm/msg/uniprint.h> +#include <netnatm/msg/priv.h> + +/* + * Define internal functions. + */ +#define DEF_IE_PRINT(Coding, IE) \ + void uni_ie_print_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_CHECK(Coding, IE) \ + int uni_ie_check_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_ENCODE(Coding, IE) \ + int uni_ie_encode_##Coding##_##IE(struct uni_msg *msg, struct uni_ie_##IE *ie, struct unicx *cx) + +#define DEF_IE_DECODE(Coding, IE) \ + int uni_ie_decode_##Coding##_##IE(struct uni_ie_##IE *ie, struct uni_msg *msg, u_int ielen, struct unicx *cx) + +/* + * This structure is used to define value->string mappings. MKT() is used + * to generate a table entry. EOT() to end the table. + */ +#define MKT(V,N) { #N, V } +#define EOT() { NULL, 0 } + +/* library internal functions */ +static void uni_entry(const char *, struct unicx *); +static int uni_print_iehdr(const char *, struct uni_iehdr *h, struct unicx *); +static void uni_print_ieend(struct unicx *); +static void uni_putc(int, struct unicx *); + + +/* + * Encoding + */ +#define APP_BYTE(M, B) do { \ + *(M)->b_wptr++ = (B); \ + } while (0) +#define APP_16BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_24BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 16; \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_32BIT(M, B) do { \ + u_int _v = (B); \ + *(M)->b_wptr++ = _v >> 24; \ + *(M)->b_wptr++ = _v >> 16; \ + *(M)->b_wptr++ = _v >> 8; \ + *(M)->b_wptr++ = _v; \ + } while (0) +#define APP_BUF(M, B, L) do { \ + (void)memcpy((M)->b_wptr, (B), (L)); \ + (M)->b_wptr += (L); \ + } while (0) + +#define APP_SUB_BYTE(M, T, B) do { APP_BYTE(M, T); APP_BYTE(M, B); } while (0) +#define APP_SUB_16BIT(M, T, B) do { APP_BYTE(M, T); APP_16BIT(M, B); } while (0) +#define APP_SUB_24BIT(M, T, B) do { APP_BYTE(M, T); APP_24BIT(M, B); } while (0) +#define APP_SUB_32BIT(M, T, B) do { APP_BYTE(M, T); APP_32BIT(M, B); } while (0) + +#define APP_OPT(M, F, P, T) do { \ + if ((F) & (P)) \ + APP_BYTE((M), (T)); \ + } while (0) +#define APP_OPT_BYTE(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_BYTE((M), (T), (B)); \ + } while (0) +#define APP_OPT_16BIT(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_16BIT((M), (T), (B)); \ + } while (0) +#define APP_OPT_24BIT(M, F, P, T, B) do { \ + if ((F) & (P)) \ + APP_SUB_24BIT((M), (T), (B)); \ + } while (0) + +#define START_IE(TYPE,CODE,LEN) \ + u_int ielen; \ + \ + if (uni_check_ie(CODE, (union uni_ieall *)ie, cx)) \ + return (-1); \ + if (uni_encode_ie_hdr(msg, CODE, &ie->h, (LEN), cx)) \ + return (0); \ + \ + ielen = msg->b_wptr - msg->b_rptr - 2; + +#define START_IE2(TYPE,CODE,LEN,REALCODE) \ + u_int ielen; \ + \ + if (uni_check_ie(CODE, (union uni_ieall *)ie, cx)) \ + return (-1); \ + if (uni_encode_ie_hdr(msg, REALCODE, &ie->h, (LEN), cx)) \ + return (0); \ + \ + ielen = msg->b_wptr - msg->b_rptr - 2; + +#define SET_IE_LEN(M) do { \ + (M)->b_buf[ielen + 0] = \ + (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 8; \ + (M)->b_buf[ielen + 1] = \ + (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 0; \ + } while (0) + + +/***********************************************************************/ +/* + * Decoding + */ +#define IE_START(ERR) \ + if (IE_ISPRESENT(*ie)) \ + return (0); \ + if (ielen == 0) { \ + IE_SETEMPTY(*ie); \ + return (0); \ + } + +#define IE_END(IE) \ + IE_SETPRESENT(*ie); \ + if (uni_check_ie(UNI_IE_##IE, (union uni_ieall *)ie, cx) == 0) \ + return (0); \ + rej: \ + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; \ + return (1); + +#define DEC_GETF3(ID, F, P) \ + case UNI_##ID##_ID: \ + if (ielen < 3) \ + goto rej; \ + ielen -= 3; \ + if (!(P & UNI_##ID##_P)) { \ + P |= UNI_##ID##_P; \ + ie->F = *msg->b_rptr++ << 16; \ + ie->F |= *msg->b_rptr++ << 8; \ + ie->F |= *msg->b_rptr++; \ + } else \ + msg->b_rptr += 3; \ + break; + +#define DEC_GETF1(ID, F, P) \ + case UNI_##ID##_ID: \ + if (ielen < 1) \ + goto rej; \ + ielen--; \ + if (!(P & UNI_##ID##_P)) { \ + P |= UNI_##ID##_P; \ + ie->F = *msg->b_rptr++; \ + } else \ + msg->b_rptr++; \ + break; + + +#define PRINT_NPREFIX (sizeof(((struct unicx *)0)->prefix) / \ + sizeof(((struct unicx *)0)->prefix[0])) + +/* + * This is rather here than in privmsg.c because we need the APP macros. + */ +int +uni_encode_msg_hdr(struct uni_msg *msg, struct uni_msghdr *h, + enum uni_msgtype type, struct unicx *cx, int *mlen) +{ + u_char byte; + + uni_msg_ensure(msg, 9); + + APP_BYTE(msg, cx->pnni ? PNNI_PROTO : UNI_PROTO); + APP_BYTE(msg, 3); + if(h->cref.cref >= 1<<23) + return -1; + APP_24BIT(msg, h->cref.cref | (h->cref.flag ? 0x800000 : 0)); + APP_BYTE(msg, type); + + byte = 0x80; + if(h->act != UNI_MSGACT_DEFAULT) + byte |= 0x10 | (h->act & 3); + if(cx->pnni && h->pass) + byte |= 0x08; + APP_BYTE(msg, byte); + + *mlen = msg->b_wptr - msg->b_rptr; + APP_16BIT(msg, 0); + + return 0; +} + +/* + * Initialize printing. This must be called by all printing routines + * that are exported to the user. + */ +void +uni_print_init(char *buf, size_t bufsiz, struct unicx *cx) +{ + if (cx->dont_init) + return; + + cx->indent = 0; + cx->nprefix = 0; + cx->doindent = 0; + if (cx->tabsiz == 0) + cx->tabsiz = 4; + cx->buf = buf; + cx->bufsiz = bufsiz; +} + +/* + * Append a character to the buffer if there is still space + */ +static void +uni_putc(int c, struct unicx *cx) +{ + if(cx->bufsiz > 1) { + *cx->buf++ = c; + cx->bufsiz--; + *cx->buf = '\0'; + } +} + +void +uni_printf(struct unicx *cx, const char *fmt, ...) +{ + u_int n; + va_list ap; + + if(cx->bufsiz > 1) { + va_start(ap, fmt); + n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap); + va_end(ap); + if(n > 0) { + if(n < cx->bufsiz) { + cx->bufsiz -= n; + cx->buf += n; + } else { + cx->buf += cx->bufsiz - 1; + cx->bufsiz = 1; + } + } + *cx->buf = '\0'; + } +} + +/* + * Print mode: + * 0 - print all into one line, fully prefixed + * 1 - print on multiple lines, full prefixed, but equal level + * entries on one line + * 2 - like 2, but only partial prefixed + * 3 - like 1, but each entry onto a new line + * 4 - like 2 + 3 + */ + +/* + * If we are in multiline mode, end the current line and set the + * flag, that we need indentation. But prevent double new lines. + */ +void +uni_print_eol(struct unicx *cx) +{ + if (cx->multiline) { + if (!cx->doindent) { + uni_putc('\n', cx); + cx->doindent = 1; + } + } +} + +/* + * New entry. Do the prefixing, indentation and spacing. + */ +static void +doprefix(struct unicx *cx, const char *s) +{ + u_int i; + + if(cx->multiline == 0) { + uni_putc(' ', cx); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 1) { + if(cx->doindent) { + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + cx->doindent = 0; + } else + uni_putc(' ', cx); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 2) { + if(cx->doindent) { + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + cx->doindent = 0; + } else + uni_putc(' ', cx); + } else if(cx->multiline == 3) { + if(cx->doindent) + cx->doindent = 0; + else + uni_putc('\n', cx); + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + for(i = 0; i < cx->nprefix; i++) + if(cx->prefix[i]) + uni_printf(cx, "%s.", cx->prefix[i]); + } else if(cx->multiline == 4) { + if(cx->doindent) + cx->doindent = 0; + else + uni_putc('\n', cx); + uni_printf(cx, "%*s", cx->indent * cx->tabsiz, ""); + } + uni_printf(cx, "%s", s); +} +static void +uni_entry(const char *s, struct unicx *cx) +{ + doprefix(cx, s); + uni_putc('=', cx); +} +void +uni_print_flag(const char *s, struct unicx *cx) +{ + doprefix(cx, s); +} + + +/* + * Start a deeper level of indendation. If multiline is in effect, + * we end the current line. + */ +void +uni_print_push_prefix(const char *prefix, struct unicx *cx) +{ + if (cx->nprefix < PRINT_NPREFIX) + cx->prefix[cx->nprefix++] = prefix; +} +void +uni_print_pop_prefix(struct unicx *cx) +{ + if (cx->nprefix > 0) + cx->nprefix--; +} + +void +uni_print_tbl(const char *entry, u_int val, const struct uni_print_tbl *tbl, + struct unicx *cx) +{ + if (entry) + uni_entry(entry, cx); + while (tbl->name) { + if (tbl->val == val) { + uni_printf(cx, "%s", tbl->name); + return; + } + tbl++; + } + uni_printf(cx, "ERROR(0x%x)", val); +} + +void +uni_print_entry(struct unicx *cx, const char *e, const char *fmt, ...) +{ + u_int n; + va_list ap; + + uni_entry(e, cx); + + if (cx->bufsiz > 1) { + va_start(ap, fmt); + n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap); + va_end(ap); + if (n > 0) { + if (n < cx->bufsiz) { + cx->bufsiz -= n; + cx->buf += n; + } else { + cx->buf += cx->bufsiz - 1; + cx->bufsiz = 1; + } + } + *cx->buf = '\0'; + } +} + +/**********************************************************************/ +/* + * Printing information elements. + */ +static int +uni_print_iehdr(const char *name, struct uni_iehdr *h, struct unicx *cx) +{ + static const struct uni_print_tbl act_tab[] = { + MKT(UNI_IEACT_CLEAR, clear), + MKT(UNI_IEACT_IGNORE, ignore), + MKT(UNI_IEACT_REPORT, report), + MKT(UNI_IEACT_MSG_IGNORE, ignore-msg), + MKT(UNI_IEACT_MSG_REPORT, report-msg), + MKT(UNI_IEACT_DEFAULT, default), + EOT() + }; + static const struct uni_print_tbl cod_tab[] = { + MKT(UNI_CODING_ITU, itut), + MKT(UNI_CODING_NET, atmf), + EOT() + }; + + uni_print_entry(cx, name, "("); + uni_print_tbl(NULL, h->act, act_tab, cx); + uni_putc(',', cx); + uni_print_tbl(NULL, h->coding, cod_tab, cx); + if(cx->pnni && h->pass) + uni_printf(cx, ",pass"); + if(IE_ISEMPTY(*(struct uni_ie_aal *)h)) { + uni_printf(cx, ",empty)"); + uni_print_eol(cx); + return 1; + } + if(IE_ISERROR(*(struct uni_ie_aal *)h)) { + uni_printf(cx, ",error)"); + uni_print_eol(cx); + return 1; + } + + uni_putc(')', cx); + + uni_print_push_prefix(name, cx); + uni_print_eol(cx); + cx->indent++; + + return 0; +} + +static void +uni_print_ieend(struct unicx *cx) +{ + uni_print_pop_prefix(cx); + uni_print_eol(cx); + cx->indent--; +} + +void +uni_print_ie_internal(enum uni_ietype code, const union uni_ieall *ie, + struct unicx *cx) +{ + const struct iedecl *iedecl; + + if((iedecl = GET_IEDECL(code, ie->h.coding)) != NULL) + (*iedecl->print)(ie, cx); +} + +void +uni_print_ie(char *buf, size_t size, enum uni_ietype code, + const union uni_ieall *ie, struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_ie_internal(code, ie, cx); +} + +int +uni_check_ie(enum uni_ietype code, union uni_ieall *ie, struct unicx *cx) +{ + const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding); + + if (iedecl != NULL) + return (iedecl->check(ie, cx)); + else + return (-1); +} + +/* + * Decode a information element header. + * Returns -1 if the message is too short. + * Strip the header from the message. + * The header is stripped, even if it is too short. + */ +int +uni_decode_ie_hdr(enum uni_ietype *ietype, struct uni_iehdr *hdr, + struct uni_msg *msg, struct unicx *cx, u_int *ielen) +{ + u_int len; + + *ietype = (enum uni_ietype)0; + *ielen = 0; + hdr->present = 0; + hdr->coding = UNI_CODING_ITU; + hdr->act = UNI_IEACT_DEFAULT; + + if ((len = uni_msg_len(msg)) == 0) + return (-1); + + *ietype = *msg->b_rptr++; + + if (--len == 0) + return (-1); + + hdr->coding = (*msg->b_rptr >> 5) & 3; + hdr->present = 0; + + switch (*msg->b_rptr & 0x17) { + + case 0x10: case 0x11: case 0x12: + case 0x15: case 0x16: + hdr->act = *msg->b_rptr & 0x7; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + hdr->act = UNI_IEACT_DEFAULT; + break; + + default: + /* Q.2931 5.7.2 last sentence */ + hdr->act = UNI_IEACT_REPORT; + break; + } + if (cx->pnni && (*msg->b_rptr & 0x08)) + hdr->pass = 1; + else + hdr->pass = 0; + msg->b_rptr++; + + if (--len == 0) { + hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if (len < 2) { + msg->b_rptr += len; + hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + *ielen = *msg->b_rptr++ << 8; + *ielen |= *msg->b_rptr++; + + return (0); +} + +/* + * Decode the body of an information element. + */ +int +uni_decode_ie_body(enum uni_ietype ietype, union uni_ieall *ie, + struct uni_msg *msg, u_int ielen, struct unicx *cx) +{ + const struct iedecl *iedecl; + u_char *end; + int ret; + + if (ielen > uni_msg_len(msg)) { + /* + * Information element too long -> content error. + * Q.2931 5.6.8.2 + */ + msg->b_rptr = msg->b_wptr; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if ((iedecl = GET_IEDECL(ietype, ie->h.coding)) == NULL) { + /* + * entirly unknown IE. + * Q.2931 5.6.8.1 + */ + msg->b_rptr += ielen; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + if (ielen > iedecl->maxlen) { + /* + * Information element too long -> content error. + * Q.2931 5.6.8.2 + */ + msg->b_rptr += iedecl->maxlen; + ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT; + return (-1); + } + + end = msg->b_rptr + ielen; + ret = (*iedecl->decode)(ie, msg, ielen, cx); + msg->b_rptr = end; + + return (ret); +} + +int +uni_encode_ie(enum uni_ietype code, struct uni_msg *msg, union uni_ieall *ie, + struct unicx *cx) +{ + const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding); + + if (iedecl == NULL) + return (-1); + return (iedecl->encode(msg, ie, cx)); +} + +int +uni_encode_ie_hdr(struct uni_msg *msg, enum uni_ietype type, + struct uni_iehdr *h, u_int len, struct unicx *cx) +{ + u_char byte; + + uni_msg_ensure(msg, 4 + len); + *msg->b_wptr++ = type; + + byte = 0x80 | (h->coding << 5); + if(h->act != UNI_IEACT_DEFAULT) + byte |= 0x10 | (h->act & 7); + if(cx->pnni) + byte |= h->pass << 3; + *msg->b_wptr++ = byte; + + if(h->present & UNI_IE_EMPTY) { + *msg->b_wptr++ = 0; + *msg->b_wptr++ = 4; + return -1; + } + *msg->b_wptr++ = 0; + *msg->b_wptr++ = 0; + + return 0; +} + +/* + * Printing messages. + */ +static void +uni_print_cref_internal(const struct uni_cref *cref, struct unicx *cx) +{ + uni_print_entry(cx, "cref", "%d.", cref->flag); + if (cref->cref == CREF_GLOBAL) + uni_printf(cx, "GLOBAL"); + else if (cref->cref == CREF_DUMMY) + uni_printf(cx, "DUMMY"); + else + uni_printf(cx, "%d", cref->cref); +} +void +uni_print_cref(char *str, size_t len, const struct uni_cref *cref, + struct unicx *cx) +{ + uni_print_init(str, len, cx); + uni_print_cref_internal(cref, cx); +} + +static void +uni_print_msghdr_internal(const struct uni_msghdr *hdr, struct unicx *cx) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_MSGACT_CLEAR, clear), + MKT(UNI_MSGACT_IGNORE, ignore), + MKT(UNI_MSGACT_REPORT, report), + MKT(UNI_MSGACT_DEFAULT, default), + EOT() + }; + + uni_print_cref_internal(&hdr->cref, cx); + uni_print_tbl("act", hdr->act, tab, cx); + if (cx->pnni) + uni_print_entry(cx, "pass", "%s", hdr->pass ? "yes" : "no"); +} + +void +uni_print_msghdr(char *str, size_t len, const struct uni_msghdr *hdr, + struct unicx *cx) +{ + uni_print_init(str, len, cx); + uni_print_msghdr_internal(hdr, cx); +} + + +static void +uni_print_internal(const struct uni_all *msg, struct unicx *cx) +{ + uni_entry("mtype", cx); + if(msg->mtype >= 256 || uni_msgtable[msg->mtype] == NULL) { + uni_printf(cx, "0x%02x(ERROR)", msg->mtype); + } else { + uni_printf(cx, "%s", uni_msgtable[msg->mtype]->name); + uni_print_msghdr_internal(&msg->u.hdr, cx); + cx->indent++; + uni_print_eol(cx); + (*uni_msgtable[msg->mtype]->print)(&msg->u, cx); + cx->indent--; + } + + if(cx->multiline == 0) + uni_printf(cx, "\n"); +} + +void +uni_print(char *buf, size_t size, const struct uni_all *all, struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_internal(all, cx); +} + +static void +uni_print_msg_internal(u_int mtype, const union uni_msgall *msg, + struct unicx *cx) +{ + + uni_entry("mtype", cx); + if (mtype >= 256 || uni_msgtable[mtype] == NULL) { + uni_printf(cx, "0x%02x(ERROR)", mtype); + } else { + uni_printf(cx, "%s", uni_msgtable[mtype]->name); + uni_print_msghdr_internal(&msg->hdr, cx); + cx->indent++; + uni_print_eol(cx); + (*uni_msgtable[mtype]->print)(msg, cx); + cx->indent--; + } + + if(cx->multiline == 0) + uni_printf(cx, "\n"); +} + +void +uni_print_msg(char *buf, size_t size, u_int mtype, const union uni_msgall *all, + struct unicx *cx) +{ + uni_print_init(buf, size, cx); + uni_print_msg_internal(mtype, all, cx); +} + +void +uni_print_cx(char *buf, size_t size, struct unicx *cx) +{ + static const char *acttab[] = { + "clr", /* 0x00 */ + "ign", /* 0x01 */ + "rep", /* 0x02 */ + "x03", /* 0x03 */ + "x04", /* 0x04 */ + "mig", /* 0x05 */ + "mrp", /* 0x06 */ + "x07", /* 0x07 */ + "def", /* 0x08 */ + }; + + static const char *errtab[] = { + [UNI_IERR_UNK] "unk", /* unknown IE */ + [UNI_IERR_LEN] "len", /* length error */ + [UNI_IERR_BAD] "bad", /* content error */ + [UNI_IERR_ACC] "acc", /* access element discarded */ + [UNI_IERR_MIS] "mis", /* missing IE */ + }; + + u_int i; + + uni_print_init(buf, size, cx); + + uni_printf(cx, "q2932 %d\n", cx->q2932); + uni_printf(cx, "pnni %d\n", cx->pnni); + uni_printf(cx, "git_hard %d\n", cx->git_hard); + uni_printf(cx, "bearer_hard %d\n", cx->bearer_hard); + uni_printf(cx, "cause_hard %d\n", cx->cause_hard); + + uni_printf(cx, "multiline %d\n", cx->multiline); + uni_printf(cx, "tabsiz %d\n", cx->tabsiz); + + uni_printf(cx, "errcnt %d (", cx->errcnt); + for(i = 0; i < cx->errcnt; i++) { + uni_printf(cx, "%02x[%s,%s%s]", cx->err[i].ie, + errtab[cx->err[i].err], acttab[cx->err[i].act], + cx->err[i].man ? ",M" : ""); + if(i != cx->errcnt - 1) + uni_putc(' ', cx); + } + uni_printf(cx, ")\n"); +} + +#include <netnatm/msg/uni_ietab.h> + +/********************************************************************* + * + * Cause + * + * References for this IE are: + * + * Q.2931 pp. 69 (just a pointer to Q.2610) + * Q.2610 (this is a small diff to Q.850) + * Q.850 !! + * UNI4.0 pp. 15 + * PNNI1.0 p. 198 + * + * ITU-T and NET coding for different values. + */ +static const struct causetab { + const char *str; + enum uni_diag diag; +} itu_causes[128] = { + +#define D(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] { STR, UNI_DIAG_##DIAG }, +#define N(NAME,VAL,DIAG,STD,STR) + +UNI_DECLARE_CAUSE_VALUES + +#undef D +#undef N + +}, net_causes[128] = { + +#define D(NAME,VAL,DIAG,STD,STR) +#define N(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] { STR, UNI_DIAG_##DIAG }, + +UNI_DECLARE_CAUSE_VALUES + +#undef D +#undef N + +}; + +enum uni_diag +uni_diag(enum uni_cause cause, enum uni_coding code) +{ + if (cause >= 128) + return (UNI_DIAG_NONE); + + if (code == UNI_CODING_NET) + if (net_causes[cause].str != NULL) + return (net_causes[cause].diag); + if (itu_causes[cause].str != NULL) + return (itu_causes[cause].diag); + return (UNI_DIAG_NONE); +} + +/**********************************************************************/ + +static void +print_cause(struct unicx *cx, struct uni_ie_cause *ie, + const struct causetab *tab1, const struct causetab *tab2) +{ + static const struct uni_print_tbl loc_tbl[] = { + MKT(UNI_CAUSE_LOC_USER, user), + MKT(UNI_CAUSE_LOC_PRIVLOC, priv-net:loc-user), + MKT(UNI_CAUSE_LOC_PUBLOC, pub-net:loc-user), + MKT(UNI_CAUSE_LOC_TRANSIT, transit-net), + MKT(UNI_CAUSE_LOC_PUBREM, pub-net:rem-user), + MKT(UNI_CAUSE_LOC_PRIVREM, priv-net:rem-user), + MKT(UNI_CAUSE_LOC_INTERNAT, int-net), + MKT(UNI_CAUSE_LOC_BEYOND, beyond), + EOT() + }; + static const struct uni_print_tbl pu_tbl[] = { + MKT(UNI_CAUSE_PU_PROVIDER, provider), + MKT(UNI_CAUSE_PU_USER, user), + EOT() + }; + static const struct uni_print_tbl na_tbl[] = { + MKT(UNI_CAUSE_NA_NORMAL, normal), + MKT(UNI_CAUSE_NA_ABNORMAL, abnormal), + EOT() + }; + static const struct uni_print_tbl cond_tbl[] = { + MKT(UNI_CAUSE_COND_UNKNOWN, unknown), + MKT(UNI_CAUSE_COND_PERM, permanent), + MKT(UNI_CAUSE_COND_TRANS, transient), + EOT() + }; + static const struct uni_print_tbl rej_tbl[] = { + MKT(UNI_CAUSE_REASON_USER, user), + MKT(UNI_CAUSE_REASON_IEMISS, ie-missing), + MKT(UNI_CAUSE_REASON_IESUFF, ie-not-suff), + EOT() + }; + char buf[100], *s; + u_int i; + + if (uni_print_iehdr("cause", &ie->h, cx)) + return; + + if (ie->cause < 128 && tab1[ie->cause].str) + strcpy(buf, tab1[ie->cause].str); + else if (ie->cause < 128 && tab2 != NULL && tab2[ie->cause].str != NULL) + strcpy(buf, tab2[ie->cause].str); + else { + sprintf(buf, "UNKNOWN-%u", ie->cause); + } + + for (s = buf; *s != '\0'; s++) + if (*s == ' ') + *s = '_'; + uni_print_entry(cx, "cause", "%s", buf); + + uni_print_tbl("loc", ie->loc, loc_tbl, cx); + + if (ie->h.present & UNI_CAUSE_COND_P) { + uni_print_tbl("pu", ie->u.cond.pu, pu_tbl, cx); + uni_print_tbl("na", ie->u.cond.na, na_tbl, cx); + uni_print_tbl("condition", ie->u.cond.cond, cond_tbl, cx); + } + if (ie->h.present & UNI_CAUSE_REJ_P) { + uni_print_tbl("reject", ie->u.rej.reason, rej_tbl, cx); + } + if (ie->h.present & UNI_CAUSE_REJ_USER_P) { + uni_print_entry(cx, "user", "%u", ie->u.rej.user); + } + if (ie->h.present & UNI_CAUSE_REJ_IE_P) { + uni_print_entry(cx, "ie", "%u", ie->u.rej.ie); + } + if (ie->h.present & UNI_CAUSE_IE_P) { + uni_print_entry(cx, "ie", "("); + for (i = 0; i < ie->u.ie.len; i++) { + if (i) + uni_putc(',', cx); + uni_printf(cx, "0x%02x", ie->u.ie.ie[i]); + } + uni_putc(')', cx); + } + if (ie->h.present & UNI_CAUSE_TRAFFIC_P) { + uni_print_entry(cx, "traffic", "("); + for (i = 0; i < ie->u.traffic.len; i++) { + if (i) + uni_putc(',', cx); + uni_printf(cx, "0x%02x", ie->u.traffic.traffic[i]); + } + uni_putc(')', cx); + } + if (ie->h.present & UNI_CAUSE_VPCI_P) { + uni_print_entry(cx, "vpci", "(%u,%u)", ie->u.vpci.vpci, ie->u.vpci.vci); + } + if (ie->h.present & UNI_CAUSE_MTYPE_P) { + uni_print_entry(cx, "mtype", "%u", ie->u.mtype); + } + if (ie->h.present & UNI_CAUSE_TIMER_P) { + for (i = 0, s = buf; i < 3; i++) { + if (ie->u.timer[i] < ' ') { + *s++ = '^'; + *s++ = ie->u.timer[i] + '@'; + } else if (ie->u.timer[i] <= '~') + *s++ = ie->u.timer[i]; + else { + *s++ = '\\'; + *s++ = ie->u.timer[i] / 0100 + '0'; + *s++ = (ie->u.timer[i] % 0100) / 010 + '0'; + *s++ = ie->u.timer[i] % 010 + '0'; + } + } + *s++ = '\0'; + uni_print_entry(cx, "timer", "\"%s\"", buf); + } + if (ie->h.present & UNI_CAUSE_TNS_P) { + uni_print_eol(cx); + uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx); + } + if (ie->h.present & UNI_CAUSE_NUMBER_P) { + uni_print_eol(cx); + uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx); + } + if (ie->h.present & UNI_CAUSE_ATTR_P) { + uni_print_entry(cx, "attr", "("); + for (i = 0; i < ie->u.attr.nattr; i++) { + uni_printf(cx, "(%u", ie->u.attr.attr[i][0]); + if (!(ie->u.attr.attr[i][0] & 0x80)) { + uni_printf(cx, ",%u", ie->u.attr.attr[i][1]); + if (!(ie->u.attr.attr[i][1] & 0x80)) + uni_printf(cx, ",%u", + ie->u.attr.attr[i][2]); + } + uni_putc(')', cx); + } + } + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(itu, cause) +{ + print_cause(cx, ie, itu_causes, NULL); +} +DEF_IE_PRINT(net, cause) +{ + print_cause(cx, ie, net_causes, itu_causes); +} + +const char * +uni_ie_cause2str(enum uni_coding coding, u_int cause) +{ + if (cause < 128) { + if (coding == UNI_CODING_ITU) + return (itu_causes[cause].str); + if (coding == UNI_CODING_NET) { + if (net_causes[cause].str != NULL) + return (net_causes[cause].str); + return (itu_causes[cause].str); + } + } + return (NULL); +} + +/**********************************************************************/ + +static int +check_cause(struct uni_ie_cause *ie, struct unicx *cx, + const struct causetab *tab1, const struct causetab *tab2) +{ + static const u_int mask = + UNI_CAUSE_COND_P | UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P | + UNI_CAUSE_REJ_IE_P | UNI_CAUSE_IE_P | UNI_CAUSE_TRAFFIC_P | + UNI_CAUSE_VPCI_P | UNI_CAUSE_MTYPE_P | UNI_CAUSE_TIMER_P | + UNI_CAUSE_TNS_P | UNI_CAUSE_NUMBER_P | UNI_CAUSE_ATTR_P | + UNI_CAUSE_PARAM_P; + + const struct causetab *ptr; + + if (ie->cause >= 128) + return (-1); + + switch (ie->loc) { + default: + return (-1); + + case UNI_CAUSE_LOC_USER: + case UNI_CAUSE_LOC_PRIVLOC: + case UNI_CAUSE_LOC_PUBLOC: + case UNI_CAUSE_LOC_TRANSIT: + case UNI_CAUSE_LOC_PUBREM: + case UNI_CAUSE_LOC_PRIVREM: + case UNI_CAUSE_LOC_INTERNAT: + case UNI_CAUSE_LOC_BEYOND: + break; + } + + if (tab1[ie->cause].str != NULL) + ptr = &tab1[ie->cause]; + else if (tab2 != NULL && tab2[ie->cause].str != NULL) + ptr = &tab2[ie->cause]; + else + return (cx->cause_hard ? -1 : 0); + + switch (ptr->diag) { + + case UNI_DIAG_NONE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + break; + } + break; + + case UNI_DIAG_COND: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_COND_P: + break; + } + break; + + case UNI_DIAG_REJ: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P: + break; + } + break; + + case UNI_DIAG_CRATE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TRAFFIC_P: + break; + } + break; + + case UNI_DIAG_IE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_IE_P: + break; + } + break; + + case UNI_DIAG_CHANID: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_VPCI_P: + break; + } + break; + + case UNI_DIAG_MTYPE: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_MTYPE_P: + break; + } + break; + + case UNI_DIAG_TIMER: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TIMER_P: + break; + } + break; + + case UNI_DIAG_TNS: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_TNS_P: + break; + } + break; + + case UNI_DIAG_NUMBER: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_NUMBER_P: + break; + } + break; + + case UNI_DIAG_ATTR: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_ATTR_P: + break; + } + break; + + case UNI_DIAG_PARAM: + switch (ie->h.present & mask) { + default: + if (cx->cause_hard) + return (-1); + break; + + case 0: + case UNI_CAUSE_PARAM_P: + break; + } + break; + } + + if (ie->h.present & UNI_CAUSE_COND_P) { + switch (ie->u.cond.pu) { + default: + return (-1); + + case UNI_CAUSE_PU_PROVIDER: + case UNI_CAUSE_PU_USER: + break; + } + switch (ie->u.cond.na) { + default: + return (-1); + + case UNI_CAUSE_NA_NORMAL: + case UNI_CAUSE_NA_ABNORMAL: + break; + } + switch (ie->u.cond.cond) { + default: + return (-1); + + case UNI_CAUSE_COND_UNKNOWN: + case UNI_CAUSE_COND_PERM: + case UNI_CAUSE_COND_TRANS: + break; + } + } + if (ie->h.present & UNI_CAUSE_REJ_P) { + switch (ie->u.rej.reason) { + default: + return (-1); + + case UNI_CAUSE_REASON_USER: + switch (ie->h.present & mask) { + default: + return (-1); + + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P: + break; + } + break; + + case UNI_CAUSE_REASON_IEMISS: + case UNI_CAUSE_REASON_IESUFF: + switch (ie->h.present & mask) { + default: + return (-1); + + case UNI_CAUSE_REJ_P: + case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P: + break; + } + break; + } + } + if (ie->h.present & UNI_CAUSE_IE_P) { + if (ie->u.ie.len == 0 || ie->u.ie.len > UNI_CAUSE_IE_N) + return (-1); + } + if (ie->h.present & UNI_CAUSE_TRAFFIC_P) { + if (ie->u.traffic.len == 0 || + ie->u.traffic.len > UNI_CAUSE_TRAFFIC_N) + return (-1); + } + + if (ie->h.present & UNI_CAUSE_TNS_P) { + if (uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx)) + return (-1); + } + if (ie->h.present & UNI_CAUSE_NUMBER_P) { + if(uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx)) + return (-1); + } + if (ie->h.present & UNI_CAUSE_ATTR_P) { + if(ie->u.attr.nattr > UNI_CAUSE_ATTR_N || ie->u.attr.nattr == 0) + return (-1); + } + if (ie->h.present & UNI_CAUSE_PARAM_P) { + cx = cx; + } + + return (0); +} + +DEF_IE_CHECK(itu, cause) +{ + return (check_cause(ie, cx, itu_causes, NULL)); +} +DEF_IE_CHECK(net, cause) +{ + return (check_cause(ie, cx, net_causes, itu_causes)); +} +/**********************************************************************/ + +static int +encode_cause(struct uni_msg *msg, struct uni_ie_cause *ie, struct unicx *cx) +{ + u_int i; + + START_IE(cause, UNI_IE_CAUSE, 30); + + if (IE_ISERROR(*ie)) { + APP_BYTE(msg, 0x00 | ie->loc); + } else { + APP_BYTE(msg, 0x80 | ie->loc); + } + APP_BYTE(msg, 0x80 | ie->cause); + + if (ie->h.present & UNI_CAUSE_COND_P) + APP_BYTE(msg, 0x80 | (ie->u.cond.pu << 3) | + (ie->u.cond.na << 2) | ie->u.cond.cond); + + else if (ie->h.present & UNI_CAUSE_REJ_P) { + APP_BYTE(msg, 0x80 | (ie->u.rej.reason << 2) | ie->u.rej.cond); + if (ie->h.present & UNI_CAUSE_REJ_USER_P) + APP_BYTE(msg, ie->u.rej.user); + else if (ie->h.present & UNI_CAUSE_REJ_IE_P) + APP_BYTE(msg, ie->u.rej.ie); + + } else if(ie->h.present & UNI_CAUSE_IE_P) + APP_BUF(msg, ie->u.ie.ie, ie->u.ie.len); + + else if (ie->h.present & UNI_CAUSE_TRAFFIC_P) + APP_BUF(msg, ie->u.traffic.traffic, ie->u.traffic.len); + + else if (ie->h.present & UNI_CAUSE_VPCI_P) { + APP_BYTE(msg, (ie->u.vpci.vpci >> 8)); + APP_BYTE(msg, (ie->u.vpci.vpci >> 0)); + APP_BYTE(msg, (ie->u.vpci.vci >> 8)); + APP_BYTE(msg, (ie->u.vpci.vci >> 0)); + + } else if (ie->h.present & UNI_CAUSE_MTYPE_P) + APP_BYTE(msg, ie->u.mtype); + + else if (ie->h.present & UNI_CAUSE_TIMER_P) { + APP_BYTE(msg, ie->u.timer[0]); + APP_BYTE(msg, ie->u.timer[1]); + APP_BYTE(msg, ie->u.timer[2]); + + } else if (ie->h.present & UNI_CAUSE_TNS_P) + uni_encode_ie(UNI_IE_TNS, msg, + (union uni_ieall *)&ie->u.tns, cx); + + else if (ie->h.present & UNI_CAUSE_NUMBER_P) + uni_encode_ie(UNI_IE_CALLED, msg, + (union uni_ieall *)&ie->u.number, cx); + + else if (ie->h.present & UNI_CAUSE_ATTR_P) { + for (i = 0; i < ie->u.attr.nattr; i++) { + APP_BYTE(msg, ie->u.attr.attr[i][0]); + if (!ie->u.attr.attr[i][0]) { + APP_BYTE(msg, ie->u.attr.attr[i][1]); + if (!ie->u.attr.attr[i][1]) + APP_BYTE(msg, ie->u.attr.attr[i][2]); + } + } + } else if (ie->h.present & UNI_CAUSE_PARAM_P) + APP_BYTE(msg, ie->u.param); + + SET_IE_LEN(msg); + + return (0); +} + +DEF_IE_ENCODE(itu, cause) +{ + return encode_cause(msg, ie, cx); +} +DEF_IE_ENCODE(net, cause) +{ + return encode_cause(msg, ie, cx); +} + +/**********************************************************************/ + +static int +decode_cause(struct uni_ie_cause *ie, struct uni_msg *msg, u_int ielen, + struct unicx *cx, const struct causetab *tab1, const struct causetab *tab2) +{ + u_char c; + const struct causetab *ptr; + enum uni_ietype ietype; + u_int xielen; + + IE_START(;); + + if(ielen < 2 || ielen > 30) + goto rej; + + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->loc = c & 0xf; + + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->cause = c & 0x7f; + + if(tab1[ie->cause].str != NULL) + ptr = &tab1[ie->cause]; + else if(tab2 != NULL && tab2[ie->cause].str != NULL) + ptr = &tab2[ie->cause]; + else { + ptr = NULL; + ielen = 0; /* ignore diags */ + } + + if(ielen) { + switch(ptr->diag) { + + case UNI_DIAG_NONE: + break; + + case UNI_DIAG_COND: + if(ielen < 1) + goto rej; + c = *msg->b_rptr++; + ielen--; + + ie->h.present |= UNI_CAUSE_COND_P; + ie->u.cond.pu = (c >> 3) & 1; + ie->u.cond.na = (c >> 2) & 1; + ie->u.cond.cond = c & 3; + + if(!(c & 0x80)) + goto rej; + break; + + case UNI_DIAG_REJ: + if(ielen < 1) + goto rej; + c = *msg->b_rptr++; + ielen--; + + ie->h.present |= UNI_CAUSE_REJ_P; + ie->u.rej.reason = (c >> 2) & 0x1f; + ie->u.rej.cond = c & 3; + + if(!(c & 0x80)) + goto rej; + + if(ielen > 0) { + c = *msg->b_rptr++; + ielen--; + + switch(ie->u.rej.reason) { + + case UNI_CAUSE_REASON_USER: + ie->h.present |= UNI_CAUSE_REJ_USER_P; + ie->u.rej.user = c; + break; + + case UNI_CAUSE_REASON_IEMISS: + case UNI_CAUSE_REASON_IESUFF: + ie->h.present |= UNI_CAUSE_REJ_IE_P; + ie->u.rej.ie = c; + break; + } + } + break; + + case UNI_DIAG_CRATE: + ie->h.present |= UNI_CAUSE_TRAFFIC_P; + while(ielen && ie->u.traffic.len < UNI_CAUSE_TRAFFIC_N) { + ie->u.traffic.traffic[ie->u.traffic.len++] = + *msg->b_rptr++; + ielen--; + } + break; + + case UNI_DIAG_IE: + ie->h.present |= UNI_CAUSE_IE_P; + while(ielen && ie->u.ie.len < UNI_CAUSE_IE_N) { + ie->u.ie.ie[ie->u.ie.len++] = *msg->b_rptr++; + ielen--; + } + break; + + case UNI_DIAG_CHANID: + if(ielen < 4) + break; + ie->h.present |= UNI_CAUSE_VPCI_P; + ie->u.vpci.vpci = *msg->b_rptr++ << 8; + ie->u.vpci.vpci |= *msg->b_rptr++; + ie->u.vpci.vci = *msg->b_rptr++ << 8; + ie->u.vpci.vci |= *msg->b_rptr++; + ielen -= 4; + break; + + case UNI_DIAG_MTYPE: + ie->h.present |= UNI_CAUSE_MTYPE_P; + ie->u.mtype = *msg->b_rptr++; + ielen--; + break; + + case UNI_DIAG_TIMER: + if(ielen < 3) + break; + ie->h.present |= UNI_CAUSE_TIMER_P; + ie->u.timer[0] = *msg->b_rptr++; + ie->u.timer[1] = *msg->b_rptr++; + ie->u.timer[2] = *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_DIAG_TNS: + if(ielen < 4) + break; + if(uni_decode_ie_hdr(&ietype, &ie->u.tns.h, msg, cx, &xielen)) + break; + if(ietype != UNI_IE_TNS) + break; + if(uni_decode_ie_body(ietype, + (union uni_ieall *)&ie->u.tns, msg, xielen, cx)) + break; + ie->h.present |= UNI_CAUSE_TNS_P; + break; + + case UNI_DIAG_NUMBER: + if(ielen < 4) + break; + if(uni_decode_ie_hdr(&ietype, &ie->u.number.h, msg, cx, &xielen)) + break; + if(ietype != UNI_IE_CALLED) + break; + if(uni_decode_ie_body(ietype, + (union uni_ieall *)&ie->u.number, msg, xielen, cx)) + break; + ie->h.present |= UNI_CAUSE_NUMBER_P; + break; + + case UNI_DIAG_ATTR: + ie->h.present |= UNI_CAUSE_ATTR_P; + while(ielen > 0 && ie->u.attr.nattr < UNI_CAUSE_ATTR_N) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][0] = c; + ielen--; + if(ielen > 0 && !(c & 0x80)) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][1] = c; + ielen--; + if(ielen > 0 && !(c & 0x80)) { + c = *msg->b_rptr++; + ie->u.attr.attr[ie->u.attr.nattr][2] = c; + ielen--; + } + } + } + break; + + case UNI_DIAG_PARAM: + ie->h.present |= UNI_CAUSE_PARAM_P; + ie->u.param = *msg->b_rptr++; + ielen--; + break; + } + } + + IE_END(CAUSE); +} + +DEF_IE_DECODE(itu, cause) +{ + return decode_cause(ie, msg, ielen, cx, itu_causes, NULL); +} +DEF_IE_DECODE(net, cause) +{ + return decode_cause(ie, msg, ielen, cx, net_causes, itu_causes); +} + +/********************************************************************* + * + * Callstate + * + * References for this IE are: + * + * Q.2931 pp. 59...60 + * UNI4.0 pp. 14 + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, callstate) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_CALLSTATE_U0, U0/N0/REST0), + MKT(UNI_CALLSTATE_U1, U1/N1), + MKT(UNI_CALLSTATE_U3, U3/N3), + MKT(UNI_CALLSTATE_U4, U4/N4), + MKT(UNI_CALLSTATE_U6, U6/N6), + MKT(UNI_CALLSTATE_U7, U7/N7), + MKT(UNI_CALLSTATE_U8, U8/N8), + MKT(UNI_CALLSTATE_U9, U9/N9), + MKT(UNI_CALLSTATE_U10, U10/N10), + MKT(UNI_CALLSTATE_U11, U11/N11), + MKT(UNI_CALLSTATE_U12, U12/N12), + MKT(UNI_CALLSTATE_REST1,REST1), + MKT(UNI_CALLSTATE_REST2,REST2), + MKT(UNI_CALLSTATE_U13, U13/N13), + MKT(UNI_CALLSTATE_U14, U14/N14), + EOT() + }; + + if(uni_print_iehdr("callstate", &ie->h, cx)) + return; + uni_print_tbl("state", ie->state, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, callstate) +{ + cx = cx; + + switch(ie->state) { + default: + return -1; + + case UNI_CALLSTATE_U0: + case UNI_CALLSTATE_U1: + case UNI_CALLSTATE_U3: + case UNI_CALLSTATE_U4: + case UNI_CALLSTATE_U6: + case UNI_CALLSTATE_U7: + case UNI_CALLSTATE_U8: + case UNI_CALLSTATE_U9: + case UNI_CALLSTATE_U10: + case UNI_CALLSTATE_U11: + case UNI_CALLSTATE_U12: + case UNI_CALLSTATE_REST1: + case UNI_CALLSTATE_REST2: + case UNI_CALLSTATE_U13: + case UNI_CALLSTATE_U14: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, callstate) +{ + START_IE(callstate, UNI_IE_CALLSTATE, 1); + + APP_BYTE(msg, ie->state); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, callstate) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->state = *msg->b_rptr++ & 0x3f; + ielen--; + + IE_END(CALLSTATE); +} + +/********************************************************************* + * + * Facility Information. + * + * References for this IE are: + * + * Q.2932.1 + * + * The standard allows only ROSE as protocol. We allow everything up to the + * maximum size. + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, facility) +{ + u_int i; + + if(uni_print_iehdr("facility", &ie->h, cx)) + return; + + if(ie->proto == UNI_FACILITY_ROSE) + uni_print_entry(cx, "proto", "rose"); + else + uni_print_entry(cx, "proto", "0x%02x", ie->proto); + + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->apdu[i]); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, facility) +{ + cx = cx; + + if(ie->len > UNI_FACILITY_MAXAPDU) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, facility) +{ + START_IE(facility, UNI_IE_FACILITY, 1 + ie->len); + + APP_BYTE(msg, ie->proto | 0x80); + APP_BUF(msg, ie->apdu, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, facility) +{ + u_char c; + + IE_START(;); + + if(ielen > UNI_FACILITY_MAXAPDU + 1 || ielen < 1) + goto rej; + + ie->proto = (c = *msg->b_rptr++) & 0x1f; + ielen--; + if((c & 0xe0) != 0x80) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->apdu, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(FACILITY); +} + +/********************************************************************* + * + * Notification Indicator + * + * References for this IE are: + * + * Q.2931 p. 76 + * UNI4.0 p. 17 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, notify) +{ + u_int i; + + if(uni_print_iehdr("notify", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->notify[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, notify) +{ + cx = cx; + + if(ie->len > UNI_NOTIFY_MAXLEN) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, notify) +{ + START_IE(notify, UNI_IE_NOTIFY, ie->len); + + APP_BUF(msg, ie->notify, ie->len); + if (IE_ISERROR(*ie)) { + /* make it too long */ + u_int i = ie->len; + + while (i < UNI_NOTIFY_MAXLEN + 1) { + APP_BYTE(msg, 0x00); + i++; + } + } + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, notify) +{ + IE_START(;); + + if (ielen > UNI_NOTIFY_MAXLEN || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->notify, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(NOTIFY); +} + +/********************************************************************* + * + * End-to-end transit delay. + * + * References for this IE are: + * + * Q.2931 pp. 70...71 + * UNI4.0 pp. 69...70 + * PNNI1.0 pp. 198...200 + * + * Not clear, whether the new indicator should be used with NET coding or + * not. + * + * Only ITU-T coding allowed. + */ + +static void +print_eetd(struct uni_ie_eetd *ie, struct unicx *cx) +{ + if (uni_print_iehdr("eetd", &ie->h, cx)) + return; + + if (ie->h.present & UNI_EETD_CUM_P) + uni_print_entry(cx, "cum", "%u", ie->cumulative); + if (ie->h.present & UNI_EETD_MAX_P) { + if (ie->maximum == UNI_EETD_ANYMAX) + uni_print_entry(cx, "max", "any"); + else + uni_print_entry(cx, "max", "%u", ie->maximum); + } + if (ie->h.present & UNI_EETD_PCTD_P) + uni_print_entry(cx, "pnni_cum", "%u", ie->pctd); + if (ie->h.present & UNI_EETD_PMTD_P) + uni_print_entry(cx, "pnni_max", "%u", ie->pmtd); + if (ie->h.present & UNI_EETD_NET_P) + uni_print_flag("netgen", cx); + + uni_print_ieend(cx); +} +DEF_IE_PRINT(itu, eetd) +{ + print_eetd(ie, cx); +} +DEF_IE_PRINT(net, eetd) +{ + print_eetd(ie, cx); +} + +DEF_IE_CHECK(itu, eetd) +{ + + cx = cx; + + if (!(ie->h.present & UNI_EETD_CUM_P)) + return (-1); + if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P)) + return (-1); + return (0); +} + +DEF_IE_CHECK(net, eetd) +{ + + if (!cx->pnni) { + if (!(ie->h.present & UNI_EETD_CUM_P)) + return (-1); + if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P)) + return (-1); + } else { + if (ie->h.present & UNI_EETD_MAX_P) + return (-1); + if ((ie->h.present & UNI_EETD_CUM_P) && + (ie->h.present & UNI_EETD_PCTD_P)) + return (-1); + } + return (0); +} + +DEF_IE_ENCODE(itu, eetd) +{ + START_IE(eetd, UNI_IE_EETD, 9); + + if (ie->h.present & UNI_EETD_CUM_P) { + APP_BYTE(msg, UNI_EETD_CTD_ID); + APP_16BIT(msg, ie->cumulative); + } + if (ie->h.present & UNI_EETD_MAX_P) { + APP_BYTE(msg, UNI_EETD_MTD_ID); + APP_16BIT(msg, ie->maximum); + } + if (ie->h.present & UNI_EETD_PMTD_P) { + APP_BYTE(msg, UNI_EETD_PMTD_ID); + APP_24BIT(msg, ie->pmtd); + } + if (ie->h.present & UNI_EETD_PCTD_P) { + APP_BYTE(msg, UNI_EETD_PCTD_ID); + APP_24BIT(msg, ie->pctd); + } + if (ie->h.present & UNI_EETD_NET_P) { + APP_BYTE(msg, UNI_EETD_NET_ID); + } + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_ENCODE(net, eetd) +{ + return (uni_ie_encode_itu_eetd(msg, ie, cx)); +} + +DEF_IE_DECODE(itu, eetd) +{ + IE_START(;); + + while (ielen > 0) { + switch (ielen--, *msg->b_rptr++) { + + case UNI_EETD_CTD_ID: + if (ielen < 2) + goto rej; + ie->h.present |= UNI_EETD_CUM_P; + ie->cumulative = *msg->b_rptr++ << 8; + ie->cumulative |= *msg->b_rptr++; + ielen -= 2; + break; + + case UNI_EETD_MTD_ID: + if (ielen < 2) + goto rej; + ie->h.present |= UNI_EETD_MAX_P; + ie->maximum = *msg->b_rptr++ << 8; + ie->maximum |= *msg->b_rptr++; + ielen -= 2; + break; + + case UNI_EETD_PCTD_ID: + if (ielen < 3) + goto rej; + ie->h.present |= UNI_EETD_PCTD_P; + ie->pctd = *msg->b_rptr++ << 16; + ie->pctd |= *msg->b_rptr++ << 8; + ie->pctd |= *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_EETD_PMTD_ID: + if (ielen < 3) + goto rej; + ie->h.present |= UNI_EETD_PMTD_P; + ie->pmtd = *msg->b_rptr++ << 16; + ie->pmtd |= *msg->b_rptr++ << 8; + ie->pmtd |= *msg->b_rptr++; + ielen -= 3; + break; + + case UNI_EETD_NET_ID: + ie->h.present |= UNI_EETD_NET_P; + break; + + default: + goto rej; + } + } + + IE_END(EETD); +} +DEF_IE_DECODE(net, eetd) +{ + return (uni_ie_decode_itu_eetd(ie, msg, ielen, cx)); +} + +/********************************************************************* + * + * Called address + * Called subaddress + * Calling address + * Calling subaddress + * Connected address + * Connected subaddress + * + * References for this IE are: + * + * Q.2931 pp. 60...68 + * ...A4 pp. 27...36 + * UNI4.0 pp. 14...15 + * Q.2951 pp. 28...40 + * + * It is assumed, that the coding of the addr arrays is ok. + * + * Only ITU-T coding allowed. + */ + +static const struct uni_print_tbl screen_tbl[] = { + MKT(UNI_ADDR_SCREEN_NOT, no), + MKT(UNI_ADDR_SCREEN_PASSED, passed), + MKT(UNI_ADDR_SCREEN_FAILED, failed), + MKT(UNI_ADDR_SCREEN_NET, network), + EOT() +}; +static const struct uni_print_tbl pres_tbl[] = { + MKT(UNI_ADDR_PRES, allowed), + MKT(UNI_ADDR_RESTRICT, restricted), + MKT(UNI_ADDR_NONUMBER, no-number), + EOT() +}; + + +static void +print_addr(struct unicx *cx, struct uni_addr *addr) +{ + static const struct uni_print_tbl plan_tbl[] = { + MKT(UNI_ADDR_UNKNOWN, unknown), + MKT(UNI_ADDR_E164, E164), + MKT(UNI_ADDR_ATME, ATME), + MKT(UNI_ADDR_DATA, data), + MKT(UNI_ADDR_PRIVATE, private), + EOT() + }; + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_ADDR_UNKNOWN, unknown), + MKT(UNI_ADDR_INTERNATIONAL, international), + MKT(UNI_ADDR_NATIONAL, national), + MKT(UNI_ADDR_NETWORK, network), + MKT(UNI_ADDR_SUBSCR, subscriber), + MKT(UNI_ADDR_ABBR, abbreviated), + EOT() + }; + u_int i; + + uni_print_entry(cx, "addr", "("); + uni_print_tbl(NULL, addr->type, type_tbl, cx); + uni_putc(',', cx); + uni_print_tbl(NULL, addr->plan, plan_tbl, cx); + uni_putc(',', cx); + if(addr->plan == UNI_ADDR_E164) { + uni_putc('"', cx); + for(i = 0; i < addr->len; i++) { + if(addr->addr[i] < ' ') + uni_printf(cx, "^%c", addr->addr[i] + '@'); + else if(addr->addr[i] <= '~') + uni_putc(addr->addr[i], cx); + else + uni_printf(cx, "\\%03o", addr->addr[i]); + } + uni_putc('"', cx); + + } else if(addr->plan == UNI_ADDR_ATME) { + for(i = 0; i < addr->len; i++) + uni_printf(cx, "%02x", addr->addr[i]); + } + uni_putc(')', cx); +} + +static void +print_addrsub(struct unicx *cx, struct uni_subaddr *addr) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_SUBADDR_NSAP, NSAP), + MKT(UNI_SUBADDR_ATME, ATME), + MKT(UNI_SUBADDR_USER, USER), + EOT() + }; + u_int i; + + uni_print_entry(cx, "addr", "("); + uni_print_tbl(NULL, addr->type, type_tbl, cx); + uni_putc(',', cx); + + for(i = 0; i < addr->len; i++) + uni_printf(cx, "%02x", addr->addr[i]); + + uni_putc(')', cx); +} + +static int +check_addr(struct uni_addr *addr) +{ + u_int i; + + switch(addr->plan) { + default: + return -1; + + case UNI_ADDR_E164: + if(addr->type != UNI_ADDR_INTERNATIONAL) + return -1; + if(addr->len > 15 || addr->len == 0) + return -1; + for(i = 0; i < addr->len; i++) + if(addr->addr[i] == 0 || (addr->addr[i] & 0x80)) + return -1; + break; + + case UNI_ADDR_ATME: + if(addr->type != UNI_ADDR_UNKNOWN) + return -1; + if(addr->len != 20) + return -1; + break; + } + + return 0; +} + +static int +check_subaddr(struct uni_subaddr *addr) +{ + switch(addr->type) { + default: + return -1; + + case UNI_SUBADDR_NSAP: + if(addr->len != 20) + return -1; + break; + + case UNI_SUBADDR_ATME: + if(addr->len > 20) + return -1; + break; + } + return 0; +} + +static int +check_screen(enum uni_addr_screen screen, enum uni_addr_pres pres) +{ + switch(pres) { + default: + return -1; + + case UNI_ADDR_PRES: + case UNI_ADDR_RESTRICT: + case UNI_ADDR_NONUMBER: + break; + } + switch(screen) { + default: + return -1; + + case UNI_ADDR_SCREEN_NOT: + case UNI_ADDR_SCREEN_PASSED: + case UNI_ADDR_SCREEN_FAILED: + case UNI_ADDR_SCREEN_NET: + break; + } + + return 0; +} + +static void +encode_addr(struct uni_msg *msg, struct uni_addr *addr, u_int flag, + enum uni_addr_screen screen, enum uni_addr_pres pres, int err) +{ + u_char ext = err ? 0x00 : 0x80; + + if (flag) { + APP_BYTE(msg, (addr->type << 4) | addr->plan); + APP_BYTE(msg, ext | (pres << 5) | (screen)); + } else { + APP_BYTE(msg, ext | (addr->type << 4) | addr->plan); + } + APP_BUF(msg, addr->addr, addr->len); +} + +static void +encode_subaddr(struct uni_msg *msg, struct uni_subaddr *addr) +{ + APP_BYTE(msg, 0x80|(addr->type<<4)); + APP_BUF(msg, addr->addr, addr->len); +} + +static int +decode_addr(struct uni_addr *addr, u_int ielen, struct uni_msg *msg, u_int plan) +{ + addr->plan = plan & 0xf; + addr->type = (plan >> 4) & 0x7; + + switch(addr->plan) { + + case UNI_ADDR_E164: + if(ielen > 15 || ielen == 0) + return -1; + addr->addr[ielen] = 0; + break; + + case UNI_ADDR_ATME: + if(ielen != 20) + return -1; + break; + + default: + return -1; + } + (void)memcpy(addr->addr, msg->b_rptr, ielen); + addr->len = ielen; + msg->b_rptr += ielen; + + return 0; +} + +static int +decode_subaddr(struct uni_subaddr *addr, u_int ielen, struct uni_msg *msg, + u_int type) +{ + switch(addr->type = (type >> 4) & 0x7) { + + case UNI_SUBADDR_NSAP: + if(ielen == 0 || ielen > 20) + return -1; + break; + + case UNI_SUBADDR_ATME: + if(ielen != 20) + return -1; + break; + + default: + return -1; + } + if(!(type & 0x80)) + return -1; + if((type & 0x7) != 0) + return -1; + + addr->len = ielen; + (void)memcpy(addr->addr, msg->b_rptr, ielen); + msg->b_rptr += ielen; + + return 0; +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, called) +{ + if (uni_print_iehdr("called", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, called) +{ + cx = cx; + + if (check_addr(&ie->addr)) + return (-1); + return (0); +} + +DEF_IE_ENCODE(itu, called) +{ + START_IE(called, UNI_IE_CALLED, 21); + encode_addr(msg, &ie->addr, 0, 0, 0, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, called) +{ + u_char c; + IE_START(;); + + if (ielen > 21 || ielen < 1) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if (!(c & 0x80)) + goto rej; + + if (decode_addr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLED); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, calledsub) +{ + if(uni_print_iehdr("calledsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, calledsub) +{ + cx = cx; + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, calledsub) +{ + START_IE(calledsub, UNI_IE_CALLEDSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, calledsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLEDSUB); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, calling) +{ + if(uni_print_iehdr("calling", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + + if(ie->h.present & UNI_CALLING_SCREEN_P) { + uni_print_tbl("screening", ie->screen, screen_tbl, cx); + uni_print_tbl("presentation", ie->pres, pres_tbl, cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, calling) +{ + cx = cx; + + if(check_addr(&ie->addr)) + return -1; + + if(ie->h.present & UNI_CALLING_SCREEN_P) + if(check_screen(ie->screen, ie->pres)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, calling) +{ + START_IE(calling, UNI_IE_CALLING, 22); + encode_addr(msg, &ie->addr, ie->h.present & UNI_CALLING_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, calling) +{ + u_char c, plan; + + IE_START(;); + + if(ielen > 22 || ielen < 1) + goto rej; + + plan = *msg->b_rptr++; + ielen--; + + if(!(plan & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + + ie->h.present |= UNI_CALLING_SCREEN_P; + ie->pres = (c >> 5) & 0x3; + ie->screen = c & 0x3; + + if(!(c & 0x80)) + goto rej; + } + + if(decode_addr(&ie->addr, ielen, msg, plan)) + goto rej; + + IE_END(CALLING); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, callingsub) +{ + if(uni_print_iehdr("callingsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, callingsub) +{ + cx = cx; + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, callingsub) +{ + START_IE(callingsub, UNI_IE_CALLINGSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, callingsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CALLINGSUB); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, conned) +{ + if(uni_print_iehdr("conned", &ie->h, cx)) + return; + print_addr(cx, &ie->addr); + + if(ie->h.present & UNI_CONNED_SCREEN_P) { + uni_print_tbl("screening", ie->screen, screen_tbl, cx); + uni_print_tbl("presentation", ie->pres, pres_tbl, cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, conned) +{ + cx = cx; + + if(check_addr(&ie->addr)) + return -1; + + if(ie->h.present & UNI_CONNED_SCREEN_P) + if(check_screen(ie->screen, ie->pres)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, conned) +{ + START_IE(conned, UNI_IE_CONNED, 22); + encode_addr(msg, &ie->addr, ie->h.present & UNI_CONNED_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie)); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, conned) +{ + u_char c, plan; + + IE_START(;); + + if(ielen > 22 || ielen < 1) + goto rej; + + plan = *msg->b_rptr++; + ielen--; + + if(!(plan & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + + ie->h.present |= UNI_CONNED_SCREEN_P; + ie->pres = (c >> 5) & 0x3; + ie->screen = c & 0x3; + + if(!(c & 0x80)) + goto rej; + } + + if(decode_addr(&ie->addr, ielen, msg, plan)) + goto rej; + + IE_END(CONNED); +} + +/**********************************************************************/ + +DEF_IE_PRINT(itu, connedsub) +{ + if(uni_print_iehdr("connedsub", &ie->h, cx)) + return; + print_addrsub(cx, &ie->addr); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, connedsub) +{ + cx = cx; + + if(check_subaddr(&ie->addr)) + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, connedsub) +{ + START_IE(connedsub, UNI_IE_CONNEDSUB, 21); + encode_subaddr(msg, &ie->addr); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, connedsub) +{ + u_char c; + + IE_START(;); + + if(ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(decode_subaddr(&ie->addr, ielen, msg, c)) + goto rej; + + IE_END(CONNEDSUB); +} + +/********************************************************************* + * + * Endpoint reference. + * + * References for this IE are: + * + * Q.2971 p. 14 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, epref) +{ + if(uni_print_iehdr("epref", &ie->h, cx)) + return; + uni_print_entry(cx, "epref", "(%u,%u)", ie->flag, ie->epref); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, epref) +{ + cx = cx; + + if(ie->epref >= (2<<15)) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, epref) +{ + START_IE(epref, UNI_IE_EPREF, 3); + + if (IE_ISERROR(*ie)) + APP_BYTE(msg, 0xff); + else + APP_BYTE(msg, 0); + APP_BYTE(msg, (ie->flag << 7) | ((ie->epref >> 8) & 0x7f)); + APP_BYTE(msg, (ie->epref & 0xff)); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, epref) +{ + u_char c; + + IE_START(;); + + if(ielen != 3) + goto rej; + if(*msg->b_rptr++ != 0) + goto rej; + + c = *msg->b_rptr++; + ie->flag = (c & 0x80) ? 1 : 0; + ie->epref = (c & 0x7f) << 8; + ie->epref |= *msg->b_rptr++; + + IE_END(EPREF); +} + +/********************************************************************* + * + * Endpoint state. + * + * References for this IE are: + * + * Q.2971 pp. 14...15 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, epstate) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_EPSTATE_NULL, null), + MKT(UNI_EPSTATE_ADD_INIT, add-initiated), + MKT(UNI_EPSTATE_ALERT_DLVD, alerting-delivered), + MKT(UNI_EPSTATE_ADD_RCVD, add-received), + MKT(UNI_EPSTATE_ALERT_RCVD, alerting-received), + MKT(UNI_EPSTATE_ACTIVE, active), + MKT(UNI_EPSTATE_DROP_INIT, drop-initiated), + MKT(UNI_EPSTATE_DROP_RCVD, drop-received), + EOT() + }; + + if(uni_print_iehdr("epstate", &ie->h, cx)) + return; + uni_print_tbl("state", ie->state, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, epstate) +{ + cx = cx; + + switch(ie->state) { + default: + return -1; + + case UNI_EPSTATE_NULL: + case UNI_EPSTATE_ADD_INIT: + case UNI_EPSTATE_ALERT_DLVD: + case UNI_EPSTATE_ADD_RCVD: + case UNI_EPSTATE_ALERT_RCVD: + case UNI_EPSTATE_DROP_INIT: + case UNI_EPSTATE_DROP_RCVD: + case UNI_EPSTATE_ACTIVE: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, epstate) +{ + START_IE(epstate, UNI_IE_EPSTATE, 1); + + APP_BYTE(msg, ie->state); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, epstate) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->state = *msg->b_rptr++ & 0x3f; + + IE_END(EPSTATE); +} + +/********************************************************************* + * + * ATM adaptation layer parameters + * + * References for this IE are: + * + * Q.2931 pp. 43...49 + * Q.2931 Amd 2 + * UNI4.0 p. 9 + * + * UNI4.0 states, that AAL2 is not supported. However we keep it. No + * parameters are associated with AAL2. + * + * Amd2 not checked. XXX + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, aal) +{ + static const struct uni_print_tbl aal_tbl[] = { + MKT(UNI_AAL_0, VOICE), + MKT(UNI_AAL_1, 1), + MKT(UNI_AAL_2, 2), + MKT(UNI_AAL_4, 3/4), + MKT(UNI_AAL_5, 5), + MKT(UNI_AAL_USER, USER), + EOT() + }; + static const struct uni_print_tbl subtype_tbl[] = { + MKT(UNI_AAL1_SUB_NULL, null), + MKT(UNI_AAL1_SUB_VOICE, voice), + MKT(UNI_AAL1_SUB_CIRCUIT, circuit), + MKT(UNI_AAL1_SUB_HQAUDIO, hqaudio), + MKT(UNI_AAL1_SUB_VIDEO, video), + EOT() + }; + static const struct uni_print_tbl cbr_rate_tbl[] = { + MKT(UNI_AAL1_CBR_64, 64), + MKT(UNI_AAL1_CBR_1544, 1544(DS1)), + MKT(UNI_AAL1_CBR_6312, 6312(DS2)), + MKT(UNI_AAL1_CBR_32064, 32064), + MKT(UNI_AAL1_CBR_44736, 44736(DS3)), + MKT(UNI_AAL1_CBR_97728, 97728), + MKT(UNI_AAL1_CBR_2048, 2048(E1)), + MKT(UNI_AAL1_CBR_8448, 8448(E2)), + MKT(UNI_AAL1_CBR_34368, 34368(E3)), + MKT(UNI_AAL1_CBR_139264, 139264), + MKT(UNI_AAL1_CBR_N64, Nx64), + MKT(UNI_AAL1_CBR_N8, Nx8), + EOT() + }; + static const struct uni_print_tbl screc_tbl[] = { + MKT(UNI_AAL1_SCREC_NULL, null), + MKT(UNI_AAL1_SCREC_SRTS, srts), + MKT(UNI_AAL1_SCREC_ACLK, aclk), + EOT() + }; + static const struct uni_print_tbl ecm_tbl[] = { + MKT(UNI_AAL1_ECM_NULL, null), + MKT(UNI_AAL1_ECM_LOSS, loss), + MKT(UNI_AAL1_ECM_DELAY, delay), + EOT() + }; + static const struct uni_print_tbl sscs_tbl[] = { + MKT(UNI_AAL_SSCS_NULL, null), + MKT(UNI_AAL_SSCS_SSCOPA, sscopa), + MKT(UNI_AAL_SSCS_SSCOPU, sscopu), + MKT(UNI_AAL_SSCS_FRAME, frame), + EOT() + }; + + if(uni_print_iehdr("aal", &ie->h, cx)) + return; + uni_print_tbl("type", ie->type, aal_tbl, cx); + + switch(ie->type) { + + case UNI_AAL_0: + uni_print_push_prefix("0", cx); + cx->indent++; + break; + + case UNI_AAL_2: + uni_print_push_prefix("2", cx); + cx->indent++; + break; + + case UNI_AAL_1: + uni_print_push_prefix("1", cx); + cx->indent++; + uni_print_tbl("subtype", ie->u.aal1.subtype, subtype_tbl, cx); + uni_print_tbl("cbr_rate", ie->u.aal1.cbr_rate, cbr_rate_tbl, cx); + if(ie->h.present & UNI_AAL1_MULT_P) + uni_print_entry(cx, "mult", "%u", ie->u.aal1.mult); + if(ie->h.present & UNI_AAL1_SCREC_P) + uni_print_tbl("screc", ie->u.aal1.screc, screc_tbl, cx); + if(ie->h.present & UNI_AAL1_ECM_P) + uni_print_tbl("ecm", ie->u.aal1.ecm, ecm_tbl, cx); + if(ie->h.present & UNI_AAL1_BSIZE_P) + uni_print_entry(cx, "bsize", "%u", ie->u.aal1.bsize); + if(ie->h.present & UNI_AAL1_PART_P) + uni_print_entry(cx, "part", "%u", ie->u.aal1.part); + break; + + case UNI_AAL_4: + uni_print_push_prefix("4", cx); + cx->indent++; + if(ie->h.present & UNI_AAL4_CPCS_P) + uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal4.fwd_cpcs, + ie->u.aal4.bwd_cpcs); + if(ie->h.present & UNI_AAL4_MID_P) + uni_print_entry(cx, "mid", "(%u,%u)", ie->u.aal4.mid_low, + ie->u.aal4.mid_high); + if(ie->h.present & UNI_AAL4_SSCS_P) + uni_print_tbl("sscs", ie->u.aal4.sscs, sscs_tbl, cx); + break; + + case UNI_AAL_5: + uni_print_push_prefix("5", cx); + cx->indent++; + if(ie->h.present & UNI_AAL5_CPCS_P) + uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal5.fwd_cpcs, + ie->u.aal5.bwd_cpcs); + if(ie->h.present & UNI_AAL5_SSCS_P) + uni_print_tbl("sscs", ie->u.aal5.sscs, sscs_tbl, cx); + break; + + case UNI_AAL_USER: + uni_print_push_prefix("user", cx); + cx->indent++; + if(ie->u.aalu.len > 4) { + uni_print_entry(cx, "info", "ERROR(len=%u)", ie->u.aalu.len); + } else { + u_int i; + + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->u.aalu.len; i++) + uni_printf(cx, "%s%u", !i?"":",", ie->u.aalu.user[i]); + uni_printf(cx, ")"); + } + break; + } + cx->indent--; + uni_print_pop_prefix(cx); + uni_print_eol(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, aal) +{ + cx = cx; + + if(ie->type == UNI_AAL_0) { + ; + } else if(ie->type == UNI_AAL_1) { + switch(ie->u.aal1.subtype) { + + default: + return -1; + + case UNI_AAL1_SUB_NULL: + case UNI_AAL1_SUB_VOICE: + case UNI_AAL1_SUB_CIRCUIT: + case UNI_AAL1_SUB_HQAUDIO: + case UNI_AAL1_SUB_VIDEO: + break; + } + switch(ie->u.aal1.cbr_rate) { + + default: + return -1; + + case UNI_AAL1_CBR_64: + case UNI_AAL1_CBR_1544: + case UNI_AAL1_CBR_6312: + case UNI_AAL1_CBR_32064: + case UNI_AAL1_CBR_44736: + case UNI_AAL1_CBR_97728: + case UNI_AAL1_CBR_2048: + case UNI_AAL1_CBR_8448: + case UNI_AAL1_CBR_34368: + case UNI_AAL1_CBR_139264: + if((ie->h.present & UNI_AAL1_MULT_P)) + return -1; + break; + + case UNI_AAL1_CBR_N64: + if(!(ie->h.present & UNI_AAL1_MULT_P)) + return -1; + if(ie->u.aal1.mult < 2) + return -1; + break; + + case UNI_AAL1_CBR_N8: + if(!(ie->h.present & UNI_AAL1_MULT_P)) + return -1; + if(ie->u.aal1.mult == 0 || ie->u.aal1.mult > 7) + return -1; + break; + } + if(ie->h.present & UNI_AAL1_SCREC_P) { + switch(ie->u.aal1.screc) { + + default: + return -1; + + case UNI_AAL1_SCREC_NULL: + case UNI_AAL1_SCREC_SRTS: + case UNI_AAL1_SCREC_ACLK: + break; + } + } + if(ie->h.present & UNI_AAL1_ECM_P) { + switch(ie->u.aal1.ecm) { + + default: + return -1; + + case UNI_AAL1_ECM_NULL: + case UNI_AAL1_ECM_LOSS: + case UNI_AAL1_ECM_DELAY: + break; + } + } + if(ie->h.present & UNI_AAL1_BSIZE_P) { + if(ie->u.aal1.bsize == 0) + return -1; + } + if(ie->h.present & UNI_AAL1_PART_P) { + if(ie->u.aal1.part == 0 || ie->u.aal1.part > 47) + return -1; + } + + } else if(ie->type == UNI_AAL_2) { + ; + + } else if(ie->type == UNI_AAL_4) { + if(ie->h.present & UNI_AAL4_MID_P) { + if(ie->u.aal4.mid_low >= 1024) + return -1; + if(ie->u.aal4.mid_high >= 1024) + return -1; + if(ie->u.aal4.mid_low > ie->u.aal4.mid_high) + return -1; + } + if(ie->h.present & UNI_AAL4_SSCS_P) { + switch(ie->u.aal4.sscs) { + + default: + return -1; + + case UNI_AAL_SSCS_NULL: + case UNI_AAL_SSCS_SSCOPA: + case UNI_AAL_SSCS_SSCOPU: + case UNI_AAL_SSCS_FRAME: + break; + } + } + + } else if(ie->type == UNI_AAL_5) { + if(ie->h.present & UNI_AAL5_SSCS_P) { + switch(ie->u.aal5.sscs) { + + default: + return -1; + + case UNI_AAL_SSCS_NULL: + case UNI_AAL_SSCS_SSCOPA: + case UNI_AAL_SSCS_SSCOPU: + case UNI_AAL_SSCS_FRAME: + break; + } + } + + } else if(ie->type == UNI_AAL_USER) { + if(ie->u.aalu.len > 4) + return -1; + + } else + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, aal) +{ + START_IE(aal, UNI_IE_AAL, 16); + + APP_BYTE(msg, ie->type); + switch(ie->type) { + + case UNI_AAL_0: + break; + + case UNI_AAL_1: + APP_SUB_BYTE(msg, + UNI_AAL_SUB_ID, ie->u.aal1.subtype); + APP_SUB_BYTE(msg, + UNI_AAL_CBR_ID, ie->u.aal1.cbr_rate); + APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_MULT_P, + UNI_AAL_MULT_ID, ie->u.aal1.mult); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_SCREC_P, + UNI_AAL_SCREC_ID, ie->u.aal1.screc); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_ECM_P, + UNI_AAL_ECM_ID, ie->u.aal1.ecm); + APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_BSIZE_P, + UNI_AAL_BSIZE_ID, ie->u.aal1.bsize); + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_PART_P, + UNI_AAL_PART_ID, ie->u.aal1.part); + break; + + case UNI_AAL_2: + break; + + case UNI_AAL_4: + if(ie->h.present & UNI_AAL4_CPCS_P) { + APP_SUB_16BIT(msg, + UNI_AAL_FWDCPCS_ID, ie->u.aal4.fwd_cpcs); + APP_SUB_16BIT(msg, + UNI_AAL_BWDCPCS_ID, ie->u.aal4.bwd_cpcs); + } + if(ie->h.present & UNI_AAL4_MID_P) { + APP_BYTE(msg, UNI_AAL_MID_ID); + APP_16BIT(msg, ie->u.aal4.mid_low); + APP_16BIT(msg, ie->u.aal4.mid_high); + } + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL4_SSCS_P, + UNI_AAL_SSCS_ID, ie->u.aal4.sscs); + break; + + case UNI_AAL_5: + if(ie->h.present & UNI_AAL5_CPCS_P) { + APP_SUB_16BIT(msg, + UNI_AAL_FWDCPCS_ID, ie->u.aal5.fwd_cpcs); + APP_SUB_16BIT(msg, + UNI_AAL_BWDCPCS_ID, ie->u.aal5.bwd_cpcs); + } + APP_OPT_BYTE(msg, ie->h.present, UNI_AAL5_SSCS_P, + UNI_AAL_SSCS_ID, ie->u.aal5.sscs); + break; + + case UNI_AAL_USER: + APP_BUF(msg, ie->u.aalu.user, ie->u.aalu.len); + break; + + default: + return -1; + } + + SET_IE_LEN(msg); + return 0; +} + +/* + * XXX What should we do with multiple subtype occurences? Ignore + * or reject. Currently we reject. + */ +static int +decode_aal_1(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int subtype_p, cbr_p; + + subtype_p = cbr_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_SUB_ID: + if(ielen == 0 || subtype_p) + return -1; + ielen--; + subtype_p = 1; + ie->u.aal1.subtype = *msg->b_rptr++; + break; + + case UNI_AAL_CBR_ID: + if(ielen == 0 || cbr_p) + return -1; + ielen--; + cbr_p = 1; + ie->u.aal1.cbr_rate = *msg->b_rptr++; + break; + + case UNI_AAL_MULT_ID: + if(ielen < 2 || (ie->h.present & UNI_AAL1_MULT_P)) + return -1; + ielen -= 2; + ie->h.present |= UNI_AAL1_MULT_P; + ie->u.aal1.mult = *msg->b_rptr++ << 8; + ie->u.aal1.mult |= *msg->b_rptr++; + break; + + case UNI_AAL_SCREC_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_SCREC_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_SCREC_P; + ie->u.aal1.screc = *msg->b_rptr++; + break; + + case UNI_AAL_ECM_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_ECM_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_ECM_P; + ie->u.aal1.ecm = *msg->b_rptr++; + break; + + case UNI_AAL_BSIZE_ID: + if(ielen < 2 || (ie->h.present & UNI_AAL1_BSIZE_P)) + return -1; + ielen -= 2; + ie->h.present |= UNI_AAL1_BSIZE_P; + ie->u.aal1.bsize = *msg->b_rptr++ << 8; + ie->u.aal1.bsize |= *msg->b_rptr++; + break; + + case UNI_AAL_PART_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL1_PART_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL1_PART_P; + ie->u.aal1.part = *msg->b_rptr++; + break; + + default: + return -1; + } + } + if(!subtype_p || !cbr_p) + return -1; + + return 0; +} + +static int +decode_aal_4(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int fcpcs_p, bcpcs_p; + + fcpcs_p = bcpcs_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_FWDCPCS_ID: + if(ielen < 2 || fcpcs_p) + return -1; + ielen -= 2; + fcpcs_p = 1; + ie->u.aal4.fwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal4.fwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_BWDCPCS_ID: + if(ielen < 2 || bcpcs_p) + return -1; + ielen -= 2; + bcpcs_p = 1; + ie->u.aal4.bwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal4.bwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_MID_ID: + if(ielen < 4 || (ie->h.present & UNI_AAL4_MID_P)) + return -1; + ielen -= 4; + ie->h.present |= UNI_AAL4_MID_P; + ie->u.aal4.mid_low = *msg->b_rptr++ << 8; + ie->u.aal4.mid_low |= *msg->b_rptr++; + ie->u.aal4.mid_high = *msg->b_rptr++ << 8; + ie->u.aal4.mid_high |= *msg->b_rptr++; + break; + + case UNI_AAL_SSCS_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL4_SSCS_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL4_SSCS_P; + ie->u.aal4.sscs = *msg->b_rptr++; + break; + + default: + return -1; + } + } + + if(fcpcs_p ^ bcpcs_p) + return -1; + if(fcpcs_p) + ie->h.present |= UNI_AAL4_CPCS_P; + + return 0; +} + +static int +decode_aal_5(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + int fcpcs_p, bcpcs_p; + + fcpcs_p = bcpcs_p = 0; + + while(ielen-- > 0) { + switch(*msg->b_rptr++) { + + case UNI_AAL_FWDCPCS_ID: + if(ielen < 2 || fcpcs_p) + return -1; + ielen -= 2; + fcpcs_p = 1; + ie->u.aal5.fwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal5.fwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_BWDCPCS_ID: + if(ielen < 2 || bcpcs_p) + return -1; + ielen -= 2; + bcpcs_p = 1; + ie->u.aal5.bwd_cpcs = *msg->b_rptr++ << 8; + ie->u.aal5.bwd_cpcs |= *msg->b_rptr++; + break; + + case UNI_AAL_SSCS_ID: + if(ielen == 0 || (ie->h.present & UNI_AAL5_SSCS_P)) + return -1; + ielen--; + ie->h.present |= UNI_AAL5_SSCS_P; + ie->u.aal5.sscs = *msg->b_rptr++; + break; + + default: + return -1; + } + } + + if(fcpcs_p ^ bcpcs_p) + return -1; + if(fcpcs_p) + ie->h.present |= UNI_AAL5_CPCS_P; + + return 0; +} + +static int +decode_aal_user(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen) +{ + if(ielen > 4) + return -1; + + ie->u.aalu.len = 0; + while(ielen--) + ie->u.aalu.user[ie->u.aalu.len++] = *msg->b_rptr++; + + return 0; +} + +DEF_IE_DECODE(itu, aal) +{ + u_char c; + + IE_START(DISC_ACC_ERR(AAL)); + + if(ielen < 1 || ielen > 21) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + switch(c) { + + case UNI_AAL_0: + ie->type = c; + break; + + case UNI_AAL_1: + ie->type = c; + if(decode_aal_1(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_2: + ie->type = c; + break; + + case UNI_AAL_4: + ie->type = c; + if(decode_aal_4(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_5: + ie->type = c; + if(decode_aal_5(ie, msg, ielen)) + goto rej; + break; + + case UNI_AAL_USER: + ie->type = c; + if(decode_aal_user(ie, msg, ielen)) + goto rej; + break; + + default: + goto rej; + } + + IE_END(AAL); +} + +/********************************************************************* + * + * Traffic descriptor. + * Alternate traffic descriptor. + * Minimum traffic descriptor. + * + * References for this IE are: + * + * Q.2931 pp. 49...51 + * Q.2961 + * Q.2962 + * UNI4.0 pp. 9...10, 106...109 + * + * The Q.s specify the coding. UNI4.0 adds frame discard and best-effort. + * Appendix in UNI4.0 lists the allowed combinations. + * + * PCR0 PCR1 SCR/MBS0 SCR/MBS1 BE TAG FDISC ABR + * 1 CBR.1 - Y - - - N Y/N - + * 2 CBR.2 - Y - - - N Y/N - (*) + * 3 CBR.3 Y Y - - - Y Y/N - (*) + * 4 rt-VBR.1 - Y - Y - N Y/N - + * 5 rt-VBR.2 - Y Y - - N Y/N - + * 6 rt-VBR.3 - Y Y - - Y Y/N - + * 7 rt-VBR.4 Y Y - - - Y/N Y/N - (*) + * 8 rt-VBR.5 - Y - - - N Y/N - (*) + * 9 rt-VBR.6 - Y - Y - N Y/N - (*) + * 10 nrt-VBR.1 - Y - Y - N Y/N - + * 11 nrt-VBR.2 - Y Y - - N Y/N - + * 12 nrt-VBR.3 - Y Y - - Y Y/N - + * 13 nrt-VBR.4 Y Y - - - Y/N Y/N - (*) + * 14 nrt-VBR.5 - Y - - - N Y/N - (*) + * 15 nrt-VBR.6 - Y - Y - N Y/N - (*) + * 16 ABR - Y - - - N Y/N O (*) + * 17 UBR.1 - Y - - Y N Y/N - + * 18 UBR.2 - Y - - Y Y Y/N - + * + * Allow ITU-T and NET coding, because its not clear, whether the + * new fields in UNI4.0 should be used with NET coding or not. + * Does not allow for experimental codings yet. + */ + +static void +print_ie_traffic_common(struct unicx *cx, u_int present, struct uni_xtraffic *ie) +{ + uni_print_entry(cx, "fwd", "("); + if(present & UNI_TRAFFIC_FPCR0_P) + uni_printf(cx, "%u", ie->fpcr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FPCR1_P) + uni_printf(cx, "%u", ie->fpcr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FSCR0_P) + uni_printf(cx, "%u", ie->fscr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FSCR1_P) + uni_printf(cx, "%u", ie->fscr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FMBS0_P) + uni_printf(cx, "%u", ie->fmbs0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FMBS1_P) + uni_printf(cx, "%u", ie->fmbs1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_FABR1_P) + uni_printf(cx, "%u", ie->fabr1); + uni_printf(cx, ")"); + + uni_print_entry(cx, "bwd", "("); + if(present & UNI_TRAFFIC_BPCR0_P) + uni_printf(cx, "%u", ie->bpcr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BPCR1_P) + uni_printf(cx, "%u", ie->bpcr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BSCR0_P) + uni_printf(cx, "%u", ie->bscr0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BSCR1_P) + uni_printf(cx, "%u", ie->bscr1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BMBS0_P) + uni_printf(cx, "%u", ie->bmbs0); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BMBS1_P) + uni_printf(cx, "%u", ie->bmbs1); + uni_putc(',', cx); + if(present & UNI_TRAFFIC_BABR1_P) + uni_printf(cx, "%u", ie->babr1); + uni_printf(cx, ")"); + + if(present & UNI_TRAFFIC_BEST_P) + uni_print_flag("best_effort", cx); + if(present & UNI_TRAFFIC_MOPT_P) { + uni_print_entry(cx, "tag", "("); + if(ie->ftag) + uni_printf(cx, "fwd"); + uni_putc(',', cx); + if(ie->btag) + uni_printf(cx, "bwd"); + uni_putc(')', cx); + + uni_print_entry(cx, "disc", "("); + if(ie->fdisc) + uni_printf(cx, "fwd"); + uni_putc(',', cx); + if(ie->bdisc) + uni_printf(cx, "bwd"); + uni_putc(')', cx); + } +} + +struct tallow { + u_int mask; + int mopt_flag; + u_char mopt_mask, mopt_val; +}; + +static int +check_traffic(u_int mask, u_int mopt, struct tallow *a) +{ + if(mask != a->mask) + return 0; + + if(a->mopt_flag == 0) { + /* not allowed */ + if(mopt == 0xffff) + return 1; + return 0; + } + + if(a->mopt_flag < 0) { + /* optional */ + if(mopt == 0xffff) + return 1; + if((mopt & a->mopt_mask) == a->mopt_val) + return 1; + return 0; + } + + /* required */ + if(mopt == 0xffff) + return 0; + if((mopt & a->mopt_mask) == a->mopt_val) + return 1; + return 0; +} + +static int +check_ie_traffic_common(struct uni_xtraffic *ie, u_int present, + struct unicx *cx __unused) +{ + static u_int fmask = + UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P | + UNI_TRAFFIC_FSCR0_P | UNI_TRAFFIC_FSCR1_P | + UNI_TRAFFIC_FMBS0_P | UNI_TRAFFIC_FMBS1_P | + UNI_TRAFFIC_FABR1_P; + static u_int bmask = + UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P | + UNI_TRAFFIC_BSCR0_P | UNI_TRAFFIC_BSCR1_P | + UNI_TRAFFIC_BMBS0_P | UNI_TRAFFIC_BMBS1_P | + UNI_TRAFFIC_BABR1_P; +#define DTAB(U,X) \ + { U##X##PCR1_P, \ + -1, U##X##TAG, 0 }, /* 1, 2, 8, 14 */ \ + { U##X##PCR0_P | U##X##PCR1_P, \ + +1, U##X##TAG, U##X##TAG }, /* 3 */ \ + { U##X##PCR1_P | U##X##SCR1_P | U##X##MBS1_P, \ + -1, U##X##TAG, 0 }, /* 4, 9, 10, 15 */ \ + { U##X##PCR1_P | U##X##SCR0_P | U##X##MBS0_P, \ + -1, 0, 0 }, /* 5, 6, 11, 12 */ \ + { U##X##PCR0_P | U##X##PCR1_P, \ + -1, 0, 0 }, /* 7, 13 */ \ + { U##X##PCR1_P | U##X##ABR1_P, \ + -1, U##X##TAG, 0 }, /* 16a */ +#define DTABSIZE 6 + + static struct tallow allow[2][DTABSIZE] = { + { DTAB(UNI_TRAFFIC_, F) }, + { DTAB(UNI_TRAFFIC_, B) }, + }; +#undef DTAB + + u_int f, b, p, m; + int i; + + f = present & fmask; + b = present & bmask; + p = present & (fmask | bmask); + m = (present & UNI_TRAFFIC_MOPT_P) + ? ( (ie->ftag ? UNI_TRAFFIC_FTAG : 0) + | (ie->btag ? UNI_TRAFFIC_BTAG : 0) + | (ie->fdisc ? UNI_TRAFFIC_FDISC : 0) + | (ie->bdisc ? UNI_TRAFFIC_BDISC : 0)) + : 0xffff; + + + if(present & UNI_TRAFFIC_BEST_P) { + /* + * Lines 17 and 18 + */ + if(p != (UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_BPCR1_P)) + return -1; + return 0; + } + + /* + * Check forward and backward independent. There must be a higher + * level checking in the CAC + */ + for(i = 0; i < DTABSIZE; i++) + if(check_traffic(f, m, &allow[0][i])) + break; + if(i == DTABSIZE) + return -1; + + for(i = 0; i < DTABSIZE; i++) + if(check_traffic(b, m, &allow[1][i])) + break; + if(i == DTABSIZE) + return -1; + + return 0; +} + +static int +encode_traffic_common(struct uni_msg *msg, struct uni_xtraffic *ie, + u_int present, struct unicx *cx __unused) +{ + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR0_P, + UNI_TRAFFIC_FPCR0_ID, ie->fpcr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR0_P, + UNI_TRAFFIC_BPCR0_ID, ie->bpcr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR1_P, + UNI_TRAFFIC_FPCR1_ID, ie->fpcr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR1_P, + UNI_TRAFFIC_BPCR1_ID, ie->bpcr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR0_P, + UNI_TRAFFIC_FSCR0_ID, ie->fscr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR0_P, + UNI_TRAFFIC_BSCR0_ID, ie->bscr0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR1_P, + UNI_TRAFFIC_FSCR1_ID, ie->fscr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR1_P, + UNI_TRAFFIC_BSCR1_ID, ie->bscr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS0_P, + UNI_TRAFFIC_FMBS0_ID, ie->fmbs0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS0_P, + UNI_TRAFFIC_BMBS0_ID, ie->bmbs0); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS1_P, + UNI_TRAFFIC_FMBS1_ID, ie->fmbs1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS1_P, + UNI_TRAFFIC_BMBS1_ID, ie->bmbs1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FABR1_P, + UNI_TRAFFIC_FABR1_ID, ie->fabr1); + APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BABR1_P, + UNI_TRAFFIC_BABR1_ID, ie->babr1); + + APP_OPT(msg, present, UNI_TRAFFIC_BEST_P, + UNI_TRAFFIC_BEST_ID); + APP_OPT_BYTE(msg, present, UNI_TRAFFIC_MOPT_P, + UNI_TRAFFIC_MOPT_ID, + (ie->ftag ? UNI_TRAFFIC_FTAG : 0) | + (ie->btag ? UNI_TRAFFIC_BTAG : 0) | + (ie->fdisc ? UNI_TRAFFIC_FDISC : 0) | + (ie->fdisc ? UNI_TRAFFIC_BDISC : 0)); + + return 0; +} + +static int +decode_traffic_common(struct uni_xtraffic *ie, struct uni_msg *msg, + u_int ielen, u_int *present) +{ + u_char c; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + rej: + return -1; + + DEC_GETF3(TRAFFIC_FPCR0, fpcr0, *present); + DEC_GETF3(TRAFFIC_BPCR0, bpcr0, *present); + DEC_GETF3(TRAFFIC_FPCR1, fpcr1, *present); + DEC_GETF3(TRAFFIC_BPCR1, bpcr1, *present); + DEC_GETF3(TRAFFIC_FSCR0, fscr0, *present); + DEC_GETF3(TRAFFIC_BSCR0, bscr0, *present); + DEC_GETF3(TRAFFIC_FSCR1, fscr1, *present); + DEC_GETF3(TRAFFIC_BSCR1, bscr1, *present); + DEC_GETF3(TRAFFIC_FMBS0, fmbs0, *present); + DEC_GETF3(TRAFFIC_BMBS0, bmbs0, *present); + DEC_GETF3(TRAFFIC_BMBS1, bmbs1, *present); + DEC_GETF3(TRAFFIC_FABR1, fabr1, *present); + DEC_GETF3(TRAFFIC_BABR1, babr1, *present); + + case UNI_TRAFFIC_BEST_ID: + *present |= UNI_TRAFFIC_BEST_P; + break; + + case UNI_TRAFFIC_MOPT_ID: + if(ielen == 0) + return -1; + ielen--; + if(!(*present & UNI_TRAFFIC_MOPT_P)) { + *present |= UNI_TRAFFIC_MOPT_P; + ie->ftag = (*msg->b_rptr&UNI_TRAFFIC_FTAG)?1:0; + ie->btag = (*msg->b_rptr&UNI_TRAFFIC_BTAG)?1:0; + ie->fdisc = (*msg->b_rptr&UNI_TRAFFIC_FDISC)?1:0; + ie->bdisc = (*msg->b_rptr&UNI_TRAFFIC_BDISC)?1:0; + } + msg->b_rptr++; + break; + } + } + return 0; +} + + +/*****************************************************************/ + +DEF_IE_PRINT(itu, traffic) +{ + if(uni_print_iehdr("traffic", &ie->h, cx)) + return; + print_ie_traffic_common(cx, ie->h.present, &ie->t); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, traffic) +{ + return check_ie_traffic_common(&ie->t, ie->h.present, cx); +} + +DEF_IE_ENCODE(itu, traffic) +{ + START_IE(traffic, UNI_IE_TRAFFIC, 26); + encode_traffic_common(msg, &ie->t, ie->h.present, cx); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, traffic) +{ + IE_START(;); + + if(ielen > 30) + goto rej; + + if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present)) + goto rej; + + IE_END(TRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(itu, atraffic) +{ + if(uni_print_iehdr("atraffic", &ie->h, cx)) + return; + print_ie_traffic_common(cx, ie->h.present, &ie->t); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, atraffic) +{ + return check_ie_traffic_common(&ie->t, ie->h.present, cx); +} + +DEF_IE_ENCODE(itu, atraffic) +{ + START_IE(traffic, UNI_IE_ATRAFFIC, 26); + encode_traffic_common(msg, &ie->t, ie->h.present, cx); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, atraffic) +{ + IE_START(;); + + if(ielen > 30) + goto rej; + + if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present)) + goto rej; + + IE_END(ATRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(itu, mintraffic) +{ + if(uni_print_iehdr("mintraffic", &ie->h, cx)) + return; + + uni_print_entry(cx, "pcr0", "("); + if(ie->h.present & UNI_MINTRAFFIC_FPCR0_P) + uni_printf(cx, "%u", ie->fpcr0); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BPCR0_P) + uni_printf(cx, "%u", ie->bpcr0); + uni_putc(')', cx); + + uni_print_entry(cx, "pcr1", "("); + if(ie->h.present & UNI_MINTRAFFIC_FPCR1_P) + uni_printf(cx, "%u", ie->fpcr1); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BPCR1_P) + uni_printf(cx, "%u", ie->bpcr1); + uni_putc(')', cx); + + uni_print_entry(cx, "abr1", "("); + if(ie->h.present & UNI_MINTRAFFIC_FABR1_P) + uni_printf(cx, "%u", ie->fabr1); + uni_putc(',', cx); + if(ie->h.present & UNI_MINTRAFFIC_BABR1_P) + uni_printf(cx, "%u", ie->babr1); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, mintraffic) +{ + u_int abr; + u_int xbr; + cx = cx; + + abr = ie->h.present & (UNI_MINTRAFFIC_FABR1_P|UNI_MINTRAFFIC_BABR1_P); + xbr = ie->h.present & (UNI_MINTRAFFIC_FPCR0_P|UNI_MINTRAFFIC_BPCR0_P| + UNI_MINTRAFFIC_FPCR1_P|UNI_MINTRAFFIC_BPCR1_P); + + if(abr && xbr) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, mintraffic) +{ + START_IE(mintraffic, UNI_IE_MINTRAFFIC, 16); + + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR0_P, + UNI_TRAFFIC_FPCR0_ID, ie->fpcr0); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR0_P, + UNI_TRAFFIC_BPCR0_ID, ie->bpcr0); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR1_P, + UNI_TRAFFIC_FPCR1_ID, ie->fpcr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR1_P, + UNI_TRAFFIC_BPCR1_ID, ie->bpcr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FABR1_P, + UNI_TRAFFIC_FABR1_ID, ie->fabr1); + APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BABR1_P, + UNI_TRAFFIC_BABR1_ID, ie->babr1); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, mintraffic) +{ + u_char c; + + IE_START(;); + + if(ielen > 20) + goto rej; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(MINTRAFFIC_FPCR0, fpcr0, ie->h.present); + DEC_GETF3(MINTRAFFIC_BPCR0, bpcr0, ie->h.present); + DEC_GETF3(MINTRAFFIC_FPCR1, fpcr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_BPCR1, bpcr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_FABR1, fabr1, ie->h.present); + DEC_GETF3(MINTRAFFIC_BABR1, babr1, ie->h.present); + } + } + + IE_END(MINTRAFFIC); +} + +/*****************************************************************/ + +DEF_IE_PRINT(net, mdcr) +{ + static const struct uni_print_tbl origin_tbl[] = { + MKT(UNI_MDCR_ORIGIN_USER, user), + MKT(UNI_MDCR_ORIGIN_NET, net), + EOT() + }; + + if(uni_print_iehdr("mdcr", &ie->h, cx)) + return; + + uni_print_tbl("origin", ie->origin, origin_tbl, cx); + uni_print_entry(cx, "mdcr", "("); + uni_printf(cx, "%u", ie->fmdcr); + uni_putc(',', cx); + uni_printf(cx, "%u", ie->bmdcr); + uni_putc(')', cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, mdcr) +{ + cx = cx; + + if ((ie->origin != UNI_MDCR_ORIGIN_USER && + ie->origin != UNI_MDCR_ORIGIN_NET) || + ie->fmdcr >= (1 << 24) || ie->bmdcr >= (1 << 24)) + return (-1); + + return (0); +} + +DEF_IE_ENCODE(net, mdcr) +{ + START_IE(mdcr, UNI_IE_MDCR, 9); + + APP_BYTE(msg, ie->origin); + APP_SUB_24BIT(msg, UNI_TRAFFIC_FMDCR_ID, ie->fmdcr); + APP_SUB_24BIT(msg, UNI_TRAFFIC_BMDCR_ID, ie->bmdcr); + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(net, mdcr) +{ + u_char c; +#define UNI_TRAFFIC_FMDCR_P 0x01 +#define UNI_TRAFFIC_BMDCR_P 0x02 + u_int p = 0; + + IE_START(;); + + if(ielen != 9) + goto rej; + + ie->origin = *msg->b_rptr++; + ielen--; + + while(ielen--) { + switch(c = *msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(TRAFFIC_FMDCR, fmdcr, p); + DEC_GETF3(TRAFFIC_BMDCR, bmdcr, p); + } + } + if (p != (UNI_TRAFFIC_FMDCR_P | UNI_TRAFFIC_BMDCR_P)) + goto rej; + + IE_END(MDCR); +} + +/********************************************************************* + * + * Connection identifier + * + * References for this IE are: + * + * Q.2931 pp. 69...70 + * UNI4.0 pp. 15...16 + * PNNI1.0 p. 198 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, connid) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_CONNID_VCI, exclusive), + MKT(UNI_CONNID_ANYVCI, any), + MKT(UNI_CONNID_NOVCI, no), + EOT() + }; + static const struct uni_print_tbl assoc_tbl[] = { + MKT(UNI_CONNID_ASSOC, associated), + MKT(UNI_CONNID_NONASSOC,non-associated), + EOT() + }; + + if(uni_print_iehdr("connid", &ie->h, cx)) + return; + + uni_print_tbl("mode", ie->assoc, assoc_tbl, cx); + uni_print_entry(cx, "connid", "(%u,", ie->vpci); + if(ie->type == UNI_CONNID_VCI) + uni_printf(cx, "%u", ie->vci); + else + uni_print_tbl(NULL, ie->type, tbl, cx); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, connid) +{ + cx = cx; + switch(ie->type) { + default: + return -1; + case UNI_CONNID_VCI: + case UNI_CONNID_ANYVCI: + case UNI_CONNID_NOVCI: + break; + } + +#if 0 + /* + * This field must be checked by the application to fulfil + * Q.2931Amd4 27) 5.2.3 last sentence + */ + switch(ie->assoc) { + + case UNI_CONNID_ASSOC: + if(!cx->cx.pnni) + return -1; + break; + + case UNI_CONNID_NONASSOC: + break; + + default: + return -1; + } +#endif + return 0; +} + +DEF_IE_ENCODE(itu, connid) +{ + START_IE(connid, UNI_IE_CONNID, 5); + + APP_BYTE(msg, 0x80 | (ie->assoc << 3) | ie->type); + APP_BYTE(msg, ie->vpci >> 8); + APP_BYTE(msg, ie->vpci >> 0); + APP_BYTE(msg, ie->vci >> 8); + APP_BYTE(msg, ie->vci >> 0); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, connid) +{ + u_char c; + + IE_START(;); + + if(ielen != 5) + goto rej; + + c = *msg->b_rptr++; + if((c & 0x80) == 0) + goto rej; + ie->assoc = (c >> 3) & 3; + ie->type = c & 7; + ie->vpci = *msg->b_rptr++ << 8; + ie->vpci |= *msg->b_rptr++; + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + + IE_END(CONNID); +} + +/********************************************************************* + * + * Quality of Service + * + * References for this IE are: + * + * Q.2931 pp. 72 + * UNI4.0 pp. 16...17 + */ + +static void +print_qos(struct unicx *cx, struct uni_ie_qos *ie) +{ + static const struct uni_print_tbl class_tbl[] = { + MKT(UNI_QOS_CLASS0, Class0), + MKT(UNI_QOS_CLASS1, Class1), + MKT(UNI_QOS_CLASS2, Class2), + MKT(UNI_QOS_CLASS3, Class3), + MKT(UNI_QOS_CLASS4, Class4), + EOT() + }; + + if(uni_print_iehdr("qos", &ie->h, cx)) + return; + + uni_print_tbl("fwd", ie->fwd, class_tbl, cx); + uni_print_tbl("bwd", ie->bwd, class_tbl, cx); + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(itu, qos) +{ + print_qos(cx, ie); +} +DEF_IE_PRINT(net, qos) +{ + print_qos(cx, ie); +} + +DEF_IE_CHECK(itu, qos) +{ + cx = cx; + + switch(ie->fwd) { + default: + return -1; + + case UNI_QOS_CLASS0: + break; + } + switch(ie->bwd) { + default: + return -1; + + case UNI_QOS_CLASS0: + break; + } + return 0; +} + +DEF_IE_CHECK(net, qos) +{ + cx = cx; + + switch(ie->fwd) { + default: + return -1; + + case UNI_QOS_CLASS1: + case UNI_QOS_CLASS2: + case UNI_QOS_CLASS3: + case UNI_QOS_CLASS4: + break; + } + switch(ie->bwd) { + default: + return -1; + + case UNI_QOS_CLASS1: + case UNI_QOS_CLASS2: + case UNI_QOS_CLASS3: + case UNI_QOS_CLASS4: + break; + } + return 0; +} + +DEF_IE_ENCODE(itu, qos) +{ + START_IE(qos, UNI_IE_QOS, 2); + + APP_BYTE(msg, ie->fwd); + APP_BYTE(msg, ie->bwd); + + SET_IE_LEN(msg); + return 0; +} +DEF_IE_ENCODE(net, qos) +{ + START_IE(qos, UNI_IE_QOS, 2); + + APP_BYTE(msg, ie->fwd); + APP_BYTE(msg, ie->bwd); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, qos) +{ + IE_START(;); + + if(ielen != 2) + goto rej; + + ie->fwd = *msg->b_rptr++; + ie->bwd = *msg->b_rptr++; + + IE_END(QOS); +} + +DEF_IE_DECODE(net, qos) +{ + IE_START(;); + + if(ielen != 2) + goto rej; + + ie->fwd = *msg->b_rptr++; + ie->bwd = *msg->b_rptr++; + + IE_END(QOS); +} + +/********************************************************************* + * + * Broadband Lower Layer Information + * + * References for this IE are: + * + * Q.2931 pp. 53...54 + * UNI4.0 p. 12 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, bhli) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_BHLI_ISO, iso), + MKT(UNI_BHLI_USER, user), + MKT(UNI_BHLI_VENDOR, vendor), + EOT() + }; + u_int i; + + if(uni_print_iehdr("bhli", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + uni_print_entry(cx, "len", "%d", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, ",0x%02x", ie->info[i]); + uni_printf(cx, ")"); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, bhli) +{ + cx = cx; + + switch(ie->type) { + default: + return -1; + + case UNI_BHLI_ISO: + case UNI_BHLI_USER: + case UNI_BHLI_VENDOR: + break; + } + if(ie->len > 8) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, bhli) +{ + START_IE(bhli, UNI_IE_BHLI, 9); + + APP_BYTE(msg, 0x80 | ie->type); + APP_BUF(msg, ie->info, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, bhli) +{ + u_char c; + + IE_START(;); + + if(ielen > 9) + goto rej; + + c = *msg->b_rptr++; + ielen--; + + if(!(c & 0x80)) + goto rej; + ie->type = c & 0x7f; + ie->len = ielen; + (void)memcpy(ie->info, msg->b_rptr, ielen); + msg->b_rptr += ielen; + + IE_END(BHLI); +} + +/********************************************************************* + * + * Broadband bearer capabilities + * + * References for this IE are: + * + * Q.2931 pp. 51...52 + * Q.2931 Amd 1 + * UNI4.0 pp. 10...12, 106...109 + * + * UNI4.0 changed the meaning of byte 5a. Instead of 3 bit traffic type and + * 2 bit timing requirements there are now 7 bits ATM transfer capabilities. + * However the old format is still supported: it should be recognized on + * input, but never be generated on output. Mapping is left to the user of + * UNI. + * + * Amd 1 not checked XXX. + * + * The Appendix in UNI4.0 lists all the supported combinations of various + * traffic IE's. The check function implements part of it. + * + * A C X VP + * 1 CBR.1 7 . 7 7 + * 2 CBR.2 - . 4,5,6 5 (*) + * 3 CBR.3 - . 4,5,6 5 (*) + * 4 rt-VBR.1 . 19 19 19 + * 5 rt-VBR.2 . 9 1,9 9 + * 6 rt-VBR.3 . 9 1,9 9 + * 7 rt-VBR.4 . . 1,9 . (*) + * 8 rt-VBR.5 . . 1,9 . (*) + * 9 rt-VBR.6 . 9 1,9 9 (*) + * 10 nrt-VBR.1 . 11 11 11 + * 11 nrt-VBR.2 . - -,0,2,8,10 -,10 + * 12 nrt-VBR.3 . - -,0,2,8,10 -,10 + * 13 nrt-VBR.4 . - -,0,2,8,10 . (*) + * 14 nrt-VBR.5 . - -,0,2,8,10 . (*) + * 15 nrt-VBR.6 . - -,0,2,8,10 -,10(*) + * 16 ABR . 12 12 12 + * 17 UBR.1 . - -,0,2,8,10 -,10 + * 18 UBR.2 . - -,0,2,8,10 -,10 + * + * (*) compatibility + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, bearer) +{ + static const struct uni_print_tbl bclass_tbl[] = { + MKT(UNI_BEARER_A, bcob-A), + MKT(UNI_BEARER_C, bcob-C), + MKT(UNI_BEARER_X, bcob-X), + MKT(UNI_BEARER_TVP, transparent-VP), + EOT() + }; + static const struct uni_print_tbl atc_tbl[] = { + MKT(UNI_BEARER_ATC_CBR, cbr), + MKT(UNI_BEARER_ATC_CBR1, cbr1), + MKT(UNI_BEARER_ATC_VBR, vbr), + MKT(UNI_BEARER_ATC_VBR1, vbr1), + MKT(UNI_BEARER_ATC_NVBR, nvbr), + MKT(UNI_BEARER_ATC_NVBR1, nvbr1), + MKT(UNI_BEARER_ATC_ABR, abr), + + MKT(UNI_BEARER_ATCX_0, x0), + MKT(UNI_BEARER_ATCX_1, x1), + MKT(UNI_BEARER_ATCX_2, x2), + MKT(UNI_BEARER_ATCX_4, x4), + MKT(UNI_BEARER_ATCX_6, x6), + MKT(UNI_BEARER_ATCX_8, x8), + EOT() + }; + static const struct uni_print_tbl cfg_tbl[] = { + MKT(UNI_BEARER_P2P, p2p), + MKT(UNI_BEARER_MP, mp), + EOT() + }; + static const struct uni_print_tbl clip_tbl[] = { + MKT(UNI_BEARER_NOCLIP, no), + MKT(UNI_BEARER_CLIP, yes), + EOT() + }; + + if(uni_print_iehdr("bearer", &ie->h, cx)) + return; + + uni_print_tbl("class", ie->bclass, bclass_tbl, cx); + + if(ie->h.present & UNI_BEARER_ATC_P) { + uni_print_tbl("atc", ie->atc, atc_tbl, cx); + } + uni_print_tbl("clip", ie->clip, clip_tbl, cx); + uni_print_tbl("cfg", ie->cfg, cfg_tbl, cx); + + uni_print_ieend(cx); +} + +#define QTYPE(C,A) ((UNI_BEARER_##C << 8) | UNI_BEARER_ATC_##A) +#define QTYPEX(C,A) ((UNI_BEARER_##C << 8) | UNI_BEARER_ATCX_##A) +#define QTYPE0(C) ((UNI_BEARER_##C << 8) | (1 << 16)) +DEF_IE_CHECK(itu, bearer) +{ + cx = cx; + + switch((ie->bclass << 8) | + ((ie->h.present & UNI_BEARER_ATC_P) == 0 + ? (1 << 16) + : ie->atc)) { + + default: + return -1; + + case QTYPE (A, CBR1): /* 1 */ + case QTYPE (X, CBR1): /* 1 */ + case QTYPE (TVP, CBR1): /* 1 */ + + case QTYPE0(A): /* 2,3 */ + case QTYPEX(X, 4): /* 2,3 */ + case QTYPE (X, CBR): /* 2,3 */ + case QTYPEX(X, 6): /* 2,3 */ + case QTYPE (TVP, CBR): /* 2,3 */ + + case QTYPE (C, VBR1): /* 4 */ + case QTYPE (X, VBR1): /* 4 */ + case QTYPE (TVP, VBR1): /* 4 */ + + case QTYPE (C, VBR): /* 5,6,9 */ + case QTYPEX(X, 1): /* 5,6,7,8,9 */ + case QTYPE (X, VBR): /* 5,6,7,8,9 */ + case QTYPE (TVP, VBR): /* 5,6,9 */ + + case QTYPE (C, NVBR1): /* 10 */ + case QTYPE (X, NVBR1): /* 10 */ + case QTYPE (TVP, NVBR1): /* 10 */ + + case QTYPE0(C): /* 11,12,13,14,15,17,18 */ + case QTYPE0(X): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 0): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 2): /* 11,12,13,14,15,17,18 */ + case QTYPEX(X, 8): /* 11,12,13,14,15,17,18 */ + case QTYPE (X, NVBR): /* 11,12,13,14,15,17,18 */ + case QTYPE0(TVP): /* 11,12,15,17,18 */ + case QTYPE (TVP, NVBR): /* 11,12,15,17,18 */ + + case QTYPE (C, ABR): /* 16 */ + case QTYPE (X, ABR): /* 16 */ + case QTYPE (TVP, ABR): /* 16 */ + break; + } + + switch(ie->clip) { + default: + return -1; + + case UNI_BEARER_NOCLIP: + case UNI_BEARER_CLIP: + break; + } + switch(ie->cfg) { + default: + return -1; + + case UNI_BEARER_P2P: + case UNI_BEARER_MP: + break; + } + + return 0; +} +#undef QTYPE +#undef QTYPEX +#undef QTYPE0 + +DEF_IE_ENCODE(itu, bearer) +{ + START_IE(bearer, UNI_IE_BEARER, 3); + + APP_BYTE(msg, ie->bclass | + ((ie->h.present & UNI_BEARER_ATC_P) ? 0:0x80)); + APP_OPT(msg, ie->h.present, UNI_BEARER_ATC_P, + 0x80 | ie->atc); + APP_BYTE(msg, 0x80 | (ie->clip << 5) | ie->cfg); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, bearer) +{ + u_char c; + + IE_START(;); + + if(ielen != 2 && ielen != 3) + goto rej; + + c = *msg->b_rptr++; + ielen--; + ie->bclass = c & 0x1f; + if(!(c & 0x80)) { + c = *msg->b_rptr++; + ielen--; + ie->h.present |= UNI_BEARER_ATC_P; + + switch(c & 0x7f) { + /* + * Real legal values + */ + case UNI_BEARER_ATC_CBR: + case UNI_BEARER_ATC_CBR1: + case UNI_BEARER_ATC_VBR: + case UNI_BEARER_ATC_VBR1: + case UNI_BEARER_ATC_NVBR: + case UNI_BEARER_ATC_NVBR1: + case UNI_BEARER_ATC_ABR: + break; + + /* + * Compat values + */ + case UNI_BEARER_ATCX_0: + case UNI_BEARER_ATCX_1: + case UNI_BEARER_ATCX_2: + case UNI_BEARER_ATCX_4: + case UNI_BEARER_ATCX_6: + case UNI_BEARER_ATCX_8: + break; + + default: + goto rej; + } + + if(!(c & 0x80)) + goto rej; + + ie->atc = c & 0x7f; + } + if(ielen == 0) + goto rej; + c = *msg->b_rptr++; + ielen--; + if(!(c & 0x80)) + goto rej; + ie->clip = (c >> 5) & 0x3; + ie->cfg = c & 0x3; + + IE_END(BEARER); +} + +/********************************************************************* + * + * Broadband Lower Layer Information + * + * References for this IE are: + * + * Q.2931 pp. 54...59 + * UNI4.0 pp. 12...14 + * + * UNI4.0 states, that layer 1 info is not supported. + * We allow a layer 1 protocol identifier. + * + * UNI4.0 states, that the layer information subelements are NOT position + * dependent. We allow them in any order on input, but generate always the + * definit order on output. + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, blli) +{ + static const struct uni_print_tbl l2_tbl[] = { + MKT(UNI_BLLI_L2_BASIC, basic), + MKT(UNI_BLLI_L2_Q921, Q921), + MKT(UNI_BLLI_L2_X25LL, X25-LL), + MKT(UNI_BLLI_L2_X25ML, X25-ML), + MKT(UNI_BLLI_L2_LABP, LAPB), + MKT(UNI_BLLI_L2_HDLC_ARM, HDLC-ARM), + MKT(UNI_BLLI_L2_HDLC_NRM, HDLC-NRM), + MKT(UNI_BLLI_L2_HDLC_ABM, HDLC-ABM), + MKT(UNI_BLLI_L2_LAN, LAN), + MKT(UNI_BLLI_L2_X75, X75), + MKT(UNI_BLLI_L2_Q922, Q922), + MKT(UNI_BLLI_L2_USER, user), + MKT(UNI_BLLI_L2_ISO7776, ISO7776), + EOT() + }; + static const struct uni_print_tbl l2mode_tbl[] = { + MKT(UNI_BLLI_L2NORM, normal), + MKT(UNI_BLLI_L2EXT, extended), + EOT() + }; + static const struct uni_print_tbl l3_tbl[] = { + MKT(UNI_BLLI_L3_X25, X25), + MKT(UNI_BLLI_L3_ISO8208, ISO8208), + MKT(UNI_BLLI_L3_X223, X223), + MKT(UNI_BLLI_L3_CLMP, CLMP), + MKT(UNI_BLLI_L3_T70, T70), + MKT(UNI_BLLI_L3_TR9577, TR9577), + MKT(UNI_BLLI_L3_USER, user), + MKT(UNI_BLLI_L3_H310, H310), + MKT(UNI_BLLI_L3_H321, H321), + EOT() + }; + static const struct uni_print_tbl l3mode_tbl[] = { + MKT(UNI_BLLI_L3NSEQ, normal-seq), + MKT(UNI_BLLI_L3ESEQ, extended-seq), + EOT() + }; + static const struct uni_print_tbl l3psiz_tbl[] = { + MKT(UNI_BLLI_L3_16, 16), + MKT(UNI_BLLI_L3_32, 32), + MKT(UNI_BLLI_L3_64, 64), + MKT(UNI_BLLI_L3_128, 128), + MKT(UNI_BLLI_L3_256, 256), + MKT(UNI_BLLI_L3_512, 512), + MKT(UNI_BLLI_L3_1024, 1024), + MKT(UNI_BLLI_L3_2048, 2048), + MKT(UNI_BLLI_L3_4096, 4096), + EOT() + }; + static const struct uni_print_tbl l3ttype_tbl[] = { + MKT(UNI_BLLI_L3_TTYPE_RECV, receive_only), + MKT(UNI_BLLI_L3_TTYPE_SEND, send_only), + MKT(UNI_BLLI_L3_TTYPE_BOTH, both), + EOT() + }; + static const struct uni_print_tbl l3mux_tbl[] = { + MKT(UNI_BLLI_L3_MUX_NOMUX, NOMUX), + MKT(UNI_BLLI_L3_MUX_TS, TS), + MKT(UNI_BLLI_L3_MUX_TSFEC, TSFEC), + MKT(UNI_BLLI_L3_MUX_PS, PS), + MKT(UNI_BLLI_L3_MUX_PSFEC, PSFEC), + MKT(UNI_BLLI_L3_MUX_H221, H221), + EOT() + }; + static const struct uni_print_tbl l3tcap_tbl[] = { + MKT(UNI_BLLI_L3_TCAP_NOIND, noind), + MKT(UNI_BLLI_L3_TCAP_AAL1, aal1), + MKT(UNI_BLLI_L3_TCAP_AAL5, aal5), + MKT(UNI_BLLI_L3_TCAP_AAL15, aal1&5), + EOT() + }; + + if(uni_print_iehdr("blli", &ie->h, cx)) + return; + + if(ie->h.present & UNI_BLLI_L1_P) { + uni_print_entry(cx, "l1", "%u", ie->l1); + uni_print_eol(cx); + } + if(ie->h.present & UNI_BLLI_L2_P) { + uni_print_tbl("l2", ie->l2, l2_tbl, cx); + uni_print_push_prefix("l2", cx); + cx->indent++; + if(ie->h.present & UNI_BLLI_L2_USER_P) + uni_print_entry(cx, "proto", "%u", ie->l2_user); + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + uni_print_entry(cx, "q933", "%u", ie->l2_q933); + uni_print_tbl("mode", ie->l2_mode, l2mode_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) + uni_print_entry(cx, "wsize", "%u", ie->l2_wsiz); + uni_print_pop_prefix(cx); + cx->indent--; + uni_print_eol(cx); + + } + if(ie->h.present & UNI_BLLI_L3_P) { + uni_print_tbl("l3", ie->l3, l3_tbl, cx); + uni_print_push_prefix("l3", cx); + cx->indent++; + if(ie->h.present & UNI_BLLI_L3_USER_P) + uni_print_entry(cx, "proto", "%u", ie->l3_user); + if(ie->h.present & UNI_BLLI_L3_MODE_P) + uni_print_tbl("mode", ie->l3_mode, l3mode_tbl, cx); + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) + uni_print_tbl("packet-size", ie->l3_psiz, l3psiz_tbl, cx); + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) + uni_print_entry(cx, "window-size", "%u", ie->l3_wsiz); + if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + uni_print_tbl("ttype", ie->l3_ttype, l3ttype_tbl, cx); + uni_print_tbl("tcap", ie->l3_tcap, l3tcap_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + uni_print_tbl("fmux", ie->l3_fmux, l3mux_tbl, cx); + uni_print_tbl("bmux", ie->l3_bmux, l3mux_tbl, cx); + } + if(ie->h.present & UNI_BLLI_L3_IPI_P) + uni_print_entry(cx, "ipi", "0x%02x", ie->l3_ipi); + if(ie->h.present & UNI_BLLI_L3_SNAP_P) + uni_print_entry(cx, "snap", "%06x.%04x", ie->oui, ie->pid); + uni_print_pop_prefix(cx); + cx->indent--; + uni_print_eol(cx); + } + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, blli) +{ + cx = cx; +/* + if(ie->h.present & UNI_BLLI_L1_P) + ; +*/ + + if(ie->h.present & UNI_BLLI_L2_P) { + static u_int mask = + UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P | + UNI_BLLI_L2_USER_P; + + switch(ie->l2) { + default: + return -1; + + case UNI_BLLI_L2_BASIC: + case UNI_BLLI_L2_Q921: + case UNI_BLLI_L2_LABP: + case UNI_BLLI_L2_LAN: + case UNI_BLLI_L2_X75: + if(ie->h.present & mask) + return -1; + break; + + case UNI_BLLI_L2_X25LL: + case UNI_BLLI_L2_X25ML: + case UNI_BLLI_L2_HDLC_ARM: + case UNI_BLLI_L2_HDLC_NRM: + case UNI_BLLI_L2_HDLC_ABM: + case UNI_BLLI_L2_Q922: + case UNI_BLLI_L2_ISO7776: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L2_Q933_P: + case UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P: + break; + } + break; + + case UNI_BLLI_L2_USER: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: /* XXX ? */ + case UNI_BLLI_L2_USER_P: + break; + } + break; + } + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + if(ie->l2_q933 != 0) + return -1; + + switch(ie->l2_mode) { + default: + return -1; + + case UNI_BLLI_L2NORM: + case UNI_BLLI_L2EXT: + break; + } + } + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) { + if(ie->l2_wsiz == 0 || ie->l2_wsiz > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L2_USER_P) { + if(ie->l2_user > 127) + return -1; + } + } + if(ie->h.present & UNI_BLLI_L3_P) { + static u_int mask = + UNI_BLLI_L3_MODE_P | UNI_BLLI_L3_PSIZ_P | + UNI_BLLI_L3_WSIZ_P | UNI_BLLI_L3_USER_P | + UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P | + UNI_BLLI_L3_TTYPE_P | UNI_BLLI_L3_MUX_P; + + switch(ie->l3) { + default: + return -1; + + case UNI_BLLI_L3_X25: + case UNI_BLLI_L3_ISO8208: + case UNI_BLLI_L3_X223: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_MODE_P: + case UNI_BLLI_L3_MODE_P | + UNI_BLLI_L3_PSIZ_P: + case UNI_BLLI_L3_MODE_P | + UNI_BLLI_L3_PSIZ_P | + UNI_BLLI_L3_WSIZ_P: + break; + } + break; + + case UNI_BLLI_L3_CLMP: + case UNI_BLLI_L3_T70: + if(ie->h.present & mask) + return -1; + break; + + case UNI_BLLI_L3_TR9577: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_IPI_P: + case UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P: + break; + } + break; + + case UNI_BLLI_L3_H310: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: + case UNI_BLLI_L3_TTYPE_P: + case UNI_BLLI_L3_TTYPE_P|UNI_BLLI_L3_MUX_P: + break; + } + break; + + case UNI_BLLI_L3_USER: + switch(ie->h.present & mask) { + default: + return -1; + + case 0: /* XXX ? */ + case UNI_BLLI_L3_USER_P: + break; + } + break; + } + if(ie->h.present & UNI_BLLI_L3_MODE_P) { + switch(ie->l3_mode) { + default: + return -1; + + case UNI_BLLI_L3NSEQ: + case UNI_BLLI_L3ESEQ: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) { + switch(ie->l3_psiz) { + default: + return -1; + + case UNI_BLLI_L3_16: + case UNI_BLLI_L3_32: + case UNI_BLLI_L3_64: + case UNI_BLLI_L3_128: + case UNI_BLLI_L3_256: + case UNI_BLLI_L3_512: + case UNI_BLLI_L3_1024: + case UNI_BLLI_L3_2048: + case UNI_BLLI_L3_4096: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) { + if(ie->l3_wsiz == 0 || ie->l3_wsiz > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_IPI_P) { + if(ie->l3_ipi == UNI_BLLI_L3_SNAP) { + if(!(ie->h.present & UNI_BLLI_L3_SNAP_P)) + return -1; + } else { + if(ie->h.present & UNI_BLLI_L3_SNAP_P) + return -1; + } + } + if(ie->h.present & UNI_BLLI_L3_USER_P) { + if(ie->l3_user > 127) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_SNAP_P) { + if(ie->oui >= (1<<24)) + return -1; + if(ie->pid >= (1<<16)) + return -1; + } + if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + switch(ie->l3_ttype) { + default: + return -1; + + case UNI_BLLI_L3_TTYPE_RECV: + case UNI_BLLI_L3_TTYPE_SEND: + case UNI_BLLI_L3_TTYPE_BOTH: + break; + } + switch(ie->l3_tcap) { + default: + return -1; + + case UNI_BLLI_L3_TCAP_NOIND: + case UNI_BLLI_L3_TCAP_AAL1: + case UNI_BLLI_L3_TCAP_AAL5: + case UNI_BLLI_L3_TCAP_AAL15: + break; + } + } + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + switch(ie->l3_fmux) { + default: + return -1; + + case UNI_BLLI_L3_MUX_NOMUX: + case UNI_BLLI_L3_MUX_TS: + case UNI_BLLI_L3_MUX_TSFEC: + case UNI_BLLI_L3_MUX_PS: + case UNI_BLLI_L3_MUX_PSFEC: + case UNI_BLLI_L3_MUX_H221: + break; + } + switch(ie->l3_bmux) { + default: + return -1; + + case UNI_BLLI_L3_MUX_NOMUX: + case UNI_BLLI_L3_MUX_TS: + case UNI_BLLI_L3_MUX_TSFEC: + case UNI_BLLI_L3_MUX_PS: + case UNI_BLLI_L3_MUX_PSFEC: + case UNI_BLLI_L3_MUX_H221: + break; + } + } + } + + return 0; +} + +DEF_IE_ENCODE(itu, blli) +{ + START_IE(blli, UNI_IE_BLLI, 13); + + if (IE_ISERROR(*ie)) { + APP_BYTE(msg, 0xff); + APP_BYTE(msg, 0xff); + goto out; + } + + if(ie->h.present & UNI_BLLI_L1_P) + APP_BYTE(msg, (UNI_BLLI_L1_ID<<5)|ie->l1|0x80); + + if(ie->h.present & UNI_BLLI_L2_P) { + if(ie->h.present & UNI_BLLI_L2_Q933_P) { + APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2); + if(ie->h.present & UNI_BLLI_L2_WSIZ_P) { + APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933); + APP_BYTE(msg, ie->l2_wsiz | 0x80); + } else { + APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933|0x80); + } + } else if(ie->h.present & UNI_BLLI_L2_USER_P) { + APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2); + APP_BYTE(msg, ie->l2_user | 0x80); + } else { + APP_BYTE(msg, (UNI_BLLI_L2_ID << 5) | ie->l2 | 0x80); + } + } + + if(ie->h.present & UNI_BLLI_L3_P) { + if(ie->h.present & UNI_BLLI_L3_MODE_P) { + if(ie->h.present & UNI_BLLI_L3_PSIZ_P) { + if(ie->h.present & UNI_BLLI_L3_WSIZ_P) { + APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_mode<<5)); + APP_BYTE(msg,ie->l3_psiz); + APP_BYTE(msg,ie->l3_wsiz|0x80); + } else { + APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_mode<<5)); + APP_BYTE(msg,(ie->l3_psiz|0x80)); + } + } else { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg, (ie->l3_mode<<5)|0x80); + } + } else if(ie->h.present & UNI_BLLI_L3_USER_P) { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,(ie->l3_user|0x80)); + } else if(ie->h.present & UNI_BLLI_L3_IPI_P) { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3); + APP_BYTE(msg,((ie->l3_ipi>>1) & 0x7f)); + APP_BYTE(msg,(((ie->l3_ipi&1)<<6)|0x80)); + if(ie->h.present & UNI_BLLI_L3_SNAP_P) { + APP_BYTE(msg, 0x80); + APP_BYTE(msg, (ie->oui >> 16)); + APP_BYTE(msg, (ie->oui >> 8)); + APP_BYTE(msg, (ie->oui >> 0)); + APP_BYTE(msg, (ie->pid >> 8)); + APP_BYTE(msg, (ie->pid >> 0)); + } + } else if(ie->h.present & UNI_BLLI_L3_TTYPE_P) { + if(ie->h.present & UNI_BLLI_L3_MUX_P) { + APP_BYTE(msg, ie->l3_ttype | (ie->l3_tcap << 4)); + APP_BYTE(msg, 0x80 | (ie->l3_fmux << 3) | ie->l3_bmux); + } else { + APP_BYTE(msg, 0x80 | ie->l3_ttype | (ie->l3_tcap << 4)); + } + } else { + APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3|0x80); + } + } + + out: + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, blli) +{ + u_char c; + + IE_START(;); + + if(ielen > 17) + goto rej; + + while(ielen--) { + switch(((c = *msg->b_rptr++) >> 5) & 0x3) { + default: + goto rej; + + case UNI_BLLI_L1_ID: + ie->h.present |= UNI_BLLI_L1_P; + ie->l1 = c & 0x1f; + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L2_ID: + ie->h.present |= UNI_BLLI_L2_P; + ie->l2 = c & 0x1f; + if(!(c & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + if(ie->l2 == UNI_BLLI_L2_USER) { + ie->h.present |= UNI_BLLI_L2_USER_P; + ie->l2_user = c & 0x7f; + if(!(c & 0x80)) + goto rej; + } else { + ie->h.present |= UNI_BLLI_L2_Q933_P; + ie->l2_q933 = c & 0x3; + ie->l2_mode = (c >> 5) & 0x3; + if(!(c & 0x80)) { + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->h.present |= UNI_BLLI_L2_WSIZ_P; + ie->l2_wsiz = c & 0x7f; + if(!(c & 0x80)) + goto rej; + } + } + } + break; + + case UNI_BLLI_L3_ID: + ie->h.present |= UNI_BLLI_L3_P; + ie->l3 = c & 0x1f; + if(!(c & 0x80)) { + switch(ie->l3) { + default: + case UNI_BLLI_L3_CLMP: + case UNI_BLLI_L3_T70: + goto rej; + + case UNI_BLLI_L3_X25: + case UNI_BLLI_L3_ISO8208: + case UNI_BLLI_L3_X223: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_mode = (c >> 5) & 0x3; + ie->h.present |= UNI_BLLI_L3_MODE_P; + + if(c & 0x80) + break; + + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_psiz = c & 0xf; + ie->h.present |= UNI_BLLI_L3_PSIZ_P; + + if(c & 0x80) + break; + + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_wsiz = c & 0x7f; + ie->h.present |= UNI_BLLI_L3_WSIZ_P; + + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L3_TR9577: + if(ielen < 2) + goto rej; + ielen -= 2; + c = *msg->b_rptr++; + ie->l3_ipi = (c << 1) & 0xfe; + if(c & 0x80) + goto rej; + c = *msg->b_rptr++; + ie->l3_ipi |= c & 1; + if(!(c & 0x80)) + goto rej; + ie->h.present |= UNI_BLLI_L3_IPI_P; + + if(ie->l3_ipi != UNI_BLLI_L3_SNAP) + break; + if(ielen < 6) + goto rej; + ielen -= 6; + if(*msg->b_rptr++ != 0x80) + goto rej; + ie->h.present |= UNI_BLLI_L3_SNAP_P; + ie->oui = *msg->b_rptr++ << 16; + ie->oui |= *msg->b_rptr++ << 8; + ie->oui |= *msg->b_rptr++; + ie->pid = *msg->b_rptr++ << 8; + ie->pid |= *msg->b_rptr++; + break; + + case UNI_BLLI_L3_H310: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_ttype = c & 0xf; + ie->l3_tcap = (c >> 4) & 0x7; + ie->h.present |= UNI_BLLI_L3_TTYPE_P; + if(c & 0x80) + break; + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_fmux = (c >> 3) & 7; + ie->l3_bmux = c & 7; + ie->h.present |= UNI_BLLI_L3_MUX_P; + if(!(c & 0x80)) + goto rej; + break; + + case UNI_BLLI_L3_USER: + if(ielen == 0) + goto rej; + ielen--; + c = *msg->b_rptr++; + ie->l3_user = c & 0x7f; + ie->h.present |= UNI_BLLI_L3_USER_P; + if(!(c & 0x80)) + goto rej; + break; + } + } + break; + } + } + + IE_END(BLLI); +} + +/********************************************************************* + * + * Broadband locking shift + * Broadband non-locking shift. + * + * References for this IE are: + * + * Q.2931 pp. 41...42 + * UNI4.0 pp. 9 + * + * Procedure not supported in UNI4.0, but IE's must be recognized. + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, lshift) +{ + if(uni_print_iehdr("locking_shift", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, lshift) +{ + cx = cx; ie = ie; + return -1; +} + +DEF_IE_ENCODE(itu, lshift) +{ + START_IE(lshift, UNI_IE_LSHIFT, 1); + APP_BYTE(msg, 0x80 | ie->set); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, lshift) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + + if(!(c & 0x80)) + goto rej; + ie->set = c & 7; + + IE_END(LSHIFT); +} + +/***********************************************************************/ + +DEF_IE_PRINT(itu, nlshift) +{ + if(uni_print_iehdr("nonlocking_shift", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, nlshift) +{ + cx = cx; ie = ie; + return -1; +} + +DEF_IE_ENCODE(itu, nlshift) +{ + START_IE(nlshift, UNI_IE_NLSHIFT, 1); + APP_BYTE(msg, 0x80 | ie->set); + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, nlshift) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + + if(!(c & 0x80)) + goto rej; + ie->set = c & 7; + + IE_END(NLSHIFT); +} + +/********************************************************************* + * + * Broadband Sending Complete Indicator + * + * References for this IE are: + * + * Q.2931 pp. 74-75 + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, scompl) +{ + if(uni_print_iehdr("sending_complete", &ie->h, cx)) + return; + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, scompl) +{ + ie = ie; cx = cx; + return 0; +} + +DEF_IE_ENCODE(itu, scompl) +{ + START_IE(scompl, UNI_IE_SCOMPL, 1); + + APP_BYTE(msg, 0x80 | 0x21); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, scompl) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + if(*msg->b_rptr++ != (0x80 | 0x21)) + goto rej; + + IE_END(SCOMPL); +} + +/********************************************************************* + * + * Broadband Repeat Indicator + * + * References for this IE are: + * + * Q.2931 p. 73 + * PNNI1.0 p. 196 + * + * Q.2931 has table 4-19. Only codepoints 0x2 and 0xa (for PNNI) supported. + * + * Only ITU-T coding allowed. + */ +DEF_IE_PRINT(itu, repeat) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_REPEAT_PRIDESC, desc), + MKT(UNI_REPEAT_STACK, stack), + EOT() + }; + + if(uni_print_iehdr("repeat", &ie->h, cx)) + return; + uni_print_tbl("type", ie->type, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, repeat) +{ + switch(ie->type) { + + case UNI_REPEAT_PRIDESC: + break; + + case UNI_REPEAT_STACK: + if(!cx->pnni) + return -1; + break; + + default: + return -1; + } + return 0; +} + +DEF_IE_ENCODE(itu, repeat) +{ + START_IE(repeat, UNI_IE_REPEAT, 1); + + APP_BYTE(msg, 0x80 | ie->type); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, repeat) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + c = *msg->b_rptr++; + if(!(c & 0x80)) + goto rej; + ie->type = c & 0xf; + + IE_END(REPEAT); +} + +/********************************************************************* + * + * Transit Network Selection + * + * References for this IE are: + * + * Q.2931 pp. 75...76 + * UNI4.0 pp. 17 + * + * According to UNI4.0 this is always National Network Id/Carried Id. + * + * ITU-T/Net coding allowed. + */ + +DEF_IE_PRINT(itu, tns) +{ + u_int i; + + if(uni_print_iehdr("tns", &ie->h, cx)) + return; + uni_print_entry(cx, "net", "%u,\"", ie->len); + uni_putc('"', cx); + for(i = 0; i < ie->len; i++) { + if(ie->net[i] < ' ') + uni_printf(cx, "^%c", ie->net[i] + '@'); + else if(ie->net[i] < '~') + uni_putc(ie->net[i], cx); + else + uni_printf(cx, "\\%03o", ie->net[i]); + } + uni_putc('"', cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, tns) +{ + u_int i; + + cx = cx; + + if(ie->len == 0 || ie->len > UNI_TNS_MAXLEN) + return -1; + for(i = 0; i < ie->len; i++) + if(ie->net[i] < ' ' || ie->net[i] > '~') + return -1; + return 0; +} + +DEF_IE_ENCODE(itu, tns) +{ + START_IE(tns, UNI_IE_TNS, ie->len + 1); + + APP_BYTE(msg, 0x80 | (0x2 << 4) | 0x1); + APP_BUF(msg, ie->net, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, tns) +{ + IE_START(;); + + if(ielen < 2 || ielen > 5) + goto rej; + + if(*msg->b_rptr++ != (0x80 | (0x2 << 4) | 0x1)) + goto rej; + ielen--; + + ie->len = 0; + while(ielen--) + ie->net[ie->len++] = *msg->b_rptr++; + + IE_END(TNS); +} + +/********************************************************************* + * + * Restart indicator + * + * References for this IE are: + * + * Q.2931 pp. 73...74 + * UNI4.0 p. 17 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, restart) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_RESTART_CHANNEL, channel), + MKT(UNI_RESTART_PATH, path), + MKT(UNI_RESTART_ALL, all), + EOT() + }; + + if(uni_print_iehdr("restart", &ie->h, cx)) + return; + uni_print_tbl("class", ie->rclass, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, restart) +{ + cx = cx; + + switch(ie->rclass) { + default: + return -1; + + case UNI_RESTART_CHANNEL: + case UNI_RESTART_PATH: + case UNI_RESTART_ALL: + break; + } + + return 0; +} + +DEF_IE_ENCODE(itu, restart) +{ + START_IE(restart, UNI_IE_RESTART, 1); + + APP_BYTE(msg, 0x80 | ie->rclass); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, restart) +{ + u_char c; + + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->rclass = (c = *msg->b_rptr++) & 0x7; + + if(!(c & 0x80)) + goto rej; + + IE_END(RESTART); +} + +/********************************************************************* + * + * User-to-user info. + * + * References for this IE are: + * + * Q.2957 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, uu) +{ + u_int i; + + if(uni_print_iehdr("uu", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "info", "("); + for(i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->uu[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, uu) +{ + cx = cx; + + if(ie->len > UNI_UU_MAXLEN) + return -1; + + return 0; +} + +DEF_IE_ENCODE(itu, uu) +{ + START_IE(uu, UNI_IE_UU, ie->len); + + APP_BUF(msg, ie->uu, ie->len); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, uu) +{ + IE_START(;); + + if(ielen > UNI_UU_MAXLEN || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->uu, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(UU); +} + +/********************************************************************* + * + * Generic Identifier Transport + * + * References for this IE are: + * + * UNI4.0 pp. 26...28 + * + * UNI4.0 prescribes a fixed format for this IE. We have a flag in the + * context structur, which tells us whether the check of this IE should be + * hard or soft. Probably it should be hard for end systems and soft for + * network nodes. + * + * Only Net Coding allowed. (XXX) + */ + +DEF_IE_PRINT(net, git) +{ + static const struct uni_print_tbl std_tbl[] = { + MKT(UNI_GIT_STD_DSMCC, dsmcc), + MKT(UNI_GIT_STD_H245, H.245), + EOT() + }; + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_GIT_TYPE_SESS, sess), + MKT(UNI_GIT_TYPE_RES, res), + EOT() + }; + u_int i, j; + char buf[20]; + + if(uni_print_iehdr("git", &ie->h, cx)) + return; + + uni_print_tbl("std", ie->std, std_tbl, cx); + + uni_print_eol(cx); + uni_print_push_prefix("id", cx); + cx->indent++; + for(i = 0; i < ie->numsub; i++) { + sprintf(buf, "%u", i); + uni_print_entry(cx, buf, "("); + uni_print_tbl(NULL, ie->sub[i].type, type_tbl, cx); + for(j = 0; j < ie->sub[i].len; j++) + uni_printf(cx, ",0x%02x", ie->sub[i].val[j]); + uni_printf(cx, ")"); + uni_print_eol(cx); + } + cx->indent--; + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, git) +{ + u_int i; + + if(cx->git_hard) { + switch(ie->std) { + case UNI_GIT_STD_DSMCC: + case UNI_GIT_STD_H245: + break; + default: + return -1; + } + if(ie->numsub != 2) + return -1; + if(ie->sub[0].type != UNI_GIT_TYPE_SESS) + return -1; + if(ie->sub[0].len > UNI_GIT_MAXSESS) + return -1; + if(ie->sub[1].type != UNI_GIT_TYPE_RES) + return -1; + if(ie->sub[1].len > UNI_GIT_MAXRES) + return -1; + } else { + if(ie->numsub > UNI_GIT_MAXSUB) + return -1; + for(i = 0; i < ie->numsub; i++) + if(ie->sub[i].len > UNI_GIT_MAXVAL) + return -1; + } + return 0; +} + +DEF_IE_ENCODE(net, git) +{ + u_int i; + + START_IE(git, UNI_IE_GIT, 1 + ie->numsub * (1 + UNI_GIT_MAXVAL)); + + APP_BYTE(msg, ie->std); + for(i = 0; i < ie->numsub; i++) { + APP_BYTE(msg, ie->sub[i].type); + APP_BYTE(msg, ie->sub[i].len); + APP_BUF(msg, ie->sub[i].val, ie->sub[i].len); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, git) +{ + IE_START(;); + + if(ielen > 1 + UNI_GIT_MAXSUB * (1 + UNI_GIT_MAXVAL) || ielen < 1) + goto rej; + + ie->std = *msg->b_rptr++; + ielen--; + + ie->numsub = 0; + while(ielen > 0) { + if(ie->numsub >= UNI_GIT_MAXSUB) + goto rej; + + ie->sub[ie->numsub].type = *msg->b_rptr++; + ielen--; + + if(ielen == 0) + goto rej; + ie->sub[ie->numsub].len = *msg->b_rptr++; + ielen--; + + if(ie->sub[ie->numsub].len > UNI_GIT_MAXVAL) + goto rej; + if(ie->sub[ie->numsub].len > (u_int)ielen) + goto rej; + + (void)memcpy(ie->sub[ie->numsub].val, msg->b_rptr, ie->sub[ie->numsub].len); + ielen -= ie->sub[ie->numsub].len; + msg->b_rptr += ie->sub[ie->numsub].len; + + ie->numsub++; + } + + IE_END(GIT); +} + +/********************************************************************* + * + * Additional ABR Parameters + * ABR Setup parameters + * + * References for this IE are: + * + * UNI4.0 pp. 78...82 + * PNNI1.0 p. 195 + * + * Notes: + * Only NET coding. + */ + +static void +print_abr_rec(struct unicx *cx, struct uni_abr_rec *rec) +{ + if(rec->present & UNI_ABR_REC_NRM_P) + uni_print_entry(cx, "nrm", "%d", rec->nrm); + if(rec->present & UNI_ABR_REC_TRM_P) + uni_print_entry(cx, "trm", "%d", rec->trm); + if(rec->present & UNI_ABR_REC_CDF_P) + uni_print_entry(cx, "cdf", "%d", rec->cdf); + if(rec->present & UNI_ABR_REC_ADTF_P) + uni_print_entry(cx, "adtf", "%d", rec->adtf); +} + +DEF_IE_PRINT(net, abradd) +{ + if(uni_print_iehdr("abradd", &ie->h, cx)) + return; + + uni_print_push_prefix("fwd", cx); + print_abr_rec(cx, &ie->fwd); + uni_print_pop_prefix(cx); + + uni_print_push_prefix("bwd", cx); + print_abr_rec(cx, &ie->bwd); + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, abradd) +{ + cx = cx; + ie = ie; + + return 0; +} + +static u_int +encode_abr_rec(struct uni_abr_rec *rec) +{ + u_int ret = rec->present & 0xf000; + + if(ret & UNI_ABR_REC_NRM_P) + ret |= (rec->nrm & 0x7) << 25; + if(ret & UNI_ABR_REC_TRM_P) + ret |= (rec->trm & 0x7) << 22; + if(ret & UNI_ABR_REC_CDF_P) + ret |= (rec->cdf & 0x7) << 19; + if(ret & UNI_ABR_REC_ADTF_P) + ret |= (rec->adtf & 0x3ff) << 9; + + return ret; +} + +DEF_IE_ENCODE(net, abradd) +{ + START_IE(abradd, UNI_IE_ABRADD, 10); + + APP_SUB_32BIT(msg, UNI_ABRADD_FADD_ID, encode_abr_rec(&ie->fwd)); + APP_SUB_32BIT(msg, UNI_ABRADD_BADD_ID, encode_abr_rec(&ie->bwd)); + + SET_IE_LEN(msg); + return 0; +} + +static int +decode_abr_rec(struct uni_msg *msg, struct uni_abr_rec *rec) +{ + u_int val; + + val = *msg->b_rptr++ << 24; + val |= *msg->b_rptr++ << 16; + val |= *msg->b_rptr++ << 8; + val |= *msg->b_rptr++ << 0; + + rec->present = val & 0xf000; + + rec->nrm = (val & UNI_ABR_REC_NRM_P) ? ((val >> 25) & 0x7) : 0; + rec->trm = (val & UNI_ABR_REC_TRM_P) ? ((val >> 22) & 0x7) : 0; + rec->cdf = (val & UNI_ABR_REC_CDF_P) ? ((val >> 19) & 0x7) : 0; + rec->adtf = (val & UNI_ABR_REC_ADTF_P)? ((val >> 9) & 0x3ff) : 0; + + return 0; +} + +DEF_IE_DECODE(net, abradd) +{ + IE_START(;); + + if(ielen != 10) + goto rej; + + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + case UNI_ABRADD_FADD_ID: + if(decode_abr_rec(msg, &ie->fwd)) + goto rej; + ielen -= 4; + break; + + case UNI_ABRADD_BADD_ID: + if(decode_abr_rec(msg, &ie->bwd)) + goto rej; + ielen -= 4; + break; + } + } + IE_END(ABRADD); +} + +/*********************************************************************/ + +DEF_IE_PRINT(net, abrsetup) +{ + if(uni_print_iehdr("abrsetup", &ie->h, cx)) + return; + + uni_print_entry(cx, "rm_frt", "%d", ie->rmfrt); + + uni_print_push_prefix("fwd", cx); + if(ie->h.present & UNI_ABRSETUP_FICR_P) + uni_print_entry(cx, "icr", "%d", ie->ficr); + if(ie->h.present & UNI_ABRSETUP_FTBE_P) + uni_print_entry(cx, "tbe", "%d", ie->ftbe); + if(ie->h.present & UNI_ABRSETUP_FRIF_P) + uni_print_entry(cx, "rif", "%d", ie->frif); + if(ie->h.present & UNI_ABRSETUP_FRDF_P) + uni_print_entry(cx, "rdf", "%d", ie->frdf); + uni_print_pop_prefix(cx); + + uni_print_push_prefix("bwd", cx); + if(ie->h.present & UNI_ABRSETUP_BICR_P) + uni_print_entry(cx, "icr", "%d", ie->bicr); + if(ie->h.present & UNI_ABRSETUP_BTBE_P) + uni_print_entry(cx, "tbe", "%d", ie->btbe); + if(ie->h.present & UNI_ABRSETUP_BRIF_P) + uni_print_entry(cx, "rif", "%d", ie->brif); + if(ie->h.present & UNI_ABRSETUP_BRDF_P) + uni_print_entry(cx, "rdf", "%d", ie->brdf); + uni_print_pop_prefix(cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, abrsetup) +{ + if(cx->pnni) { + if(!(ie->h.present & UNI_ABRSETUP_FICR_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BICR_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FTBE_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BTBE_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FRIF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BRIF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_FRDF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_BRDF_P)) + return -1; + if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P)) + return -1; + } + + if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P)) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FICR_P) + if(ie->ficr >= 1 << 24) + return -1; + if(ie->h.present & UNI_ABRSETUP_BICR_P) + if(ie->bicr >= 1 << 24) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FTBE_P) + if(ie->ftbe >= 1 << 24 || ie->ftbe == 0) + return -1; + if(ie->h.present & UNI_ABRSETUP_BTBE_P) + if(ie->btbe >= 1 << 24 || ie->btbe == 0) + return -1; + + if(ie->rmfrt >= 1 << 24) + return -1; + + if(ie->h.present & UNI_ABRSETUP_FRIF_P) + if(ie->frif > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_FRDF_P) + if(ie->frdf > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_BRIF_P) + if(ie->brif > 15) + return -1; + if(ie->h.present & UNI_ABRSETUP_BRDF_P) + if(ie->brdf > 15) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, abrsetup) +{ + START_IE(abrsetup, UNI_IE_ABRSETUP, 32); + + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FICR_P, + UNI_ABRSETUP_FICR_ID, ie->ficr); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BICR_P, + UNI_ABRSETUP_BICR_ID, ie->bicr); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FTBE_P, + UNI_ABRSETUP_FTBE_ID, ie->ftbe); + APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BTBE_P, + UNI_ABRSETUP_BTBE_ID, ie->btbe); + APP_SUB_24BIT(msg, UNI_ABRSETUP_RMFRT_ID, ie->rmfrt); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRIF_P, + UNI_ABRSETUP_FRIF_ID, ie->frif); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRIF_P, + UNI_ABRSETUP_BRIF_ID, ie->brif); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRDF_P, + UNI_ABRSETUP_FRDF_ID, ie->frdf); + APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRDF_P, + UNI_ABRSETUP_BRDF_ID, ie->brdf); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, abrsetup) +{ + IE_START(;); + + if(ielen < 4 || ielen > 32) + goto rej; + + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + + DEC_GETF3(ABRSETUP_FICR, ficr, ie->h.present); + DEC_GETF3(ABRSETUP_BICR, bicr, ie->h.present); + DEC_GETF3(ABRSETUP_FTBE, ftbe, ie->h.present); + DEC_GETF3(ABRSETUP_BTBE, btbe, ie->h.present); + DEC_GETF1(ABRSETUP_FRIF, frif, ie->h.present); + DEC_GETF1(ABRSETUP_BRIF, brif, ie->h.present); + DEC_GETF1(ABRSETUP_FRDF, frdf, ie->h.present); + DEC_GETF1(ABRSETUP_BRDF, brdf, ie->h.present); + DEC_GETF3(ABRSETUP_RMFRT, frif, ie->h.present); + } + } + IE_END(ABRSETUP); +} + +/********************************************************************* + * + * Broadband report type + * + * References for this IE are: + * + * Q.2963.1 pp. 7...8 + * + * Only ITU-T coding allowed. + */ + +DEF_IE_PRINT(itu, report) +{ + static const struct uni_print_tbl tbl[] = { + MKT(UNI_REPORT_MODCONF, modconf), + MKT(UNI_REPORT_CLOCK, clock), + MKT(UNI_REPORT_EEAVAIL, eeavail), + MKT(UNI_REPORT_EEREQ, eereq), + MKT(UNI_REPORT_EECOMPL, eecompl), + EOT() + }; + + if(uni_print_iehdr("report", &ie->h, cx)) + return; + uni_print_tbl("type", ie->report, tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, report) +{ + cx = cx; + + switch(ie->report) { + + default: + return -1; + + case UNI_REPORT_MODCONF: + case UNI_REPORT_CLOCK: + case UNI_REPORT_EEAVAIL: + case UNI_REPORT_EEREQ: + case UNI_REPORT_EECOMPL: + break; + } + return 0; +} + +DEF_IE_ENCODE(itu, report) +{ + START_IE(report, UNI_IE_REPORT, 1); + + APP_BYTE(msg, ie->report); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(itu, report) +{ + IE_START(;); + if(ielen != 1) + goto rej; + + ie->report = *msg->b_rptr++; + + IE_END(REPORT); +} + +/********************************************************************* + * + * Soft PVPC/PVCC + * + * References for this IE are: + * + * PNNI1.0 pp. 201...203 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, calling_soft) +{ + if(uni_print_iehdr("calling_soft", &ie->h, cx)) + return; + + uni_print_entry(cx, "vpi", "%d", ie->vpi); + if(ie->h.present & UNI_CALLING_SOFT_VCI_P) + uni_print_entry(cx, "vci", "%d", ie->vci); + + uni_print_ieend(cx); +} + +DEF_IE_PRINT(net, called_soft) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_SOFT_SEL_ANY, any), + MKT(UNI_SOFT_SEL_REQ, required), + MKT(UNI_SOFT_SEL_ASS, assigned), + EOT() + }; + + if(uni_print_iehdr("called_soft", &ie->h, cx)) + return; + + uni_print_tbl("selection", ie->sel, tab, cx); + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) + uni_print_entry(cx, "vpi", "%d", ie->vpi); + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) + uni_print_entry(cx, "vci", "%d", ie->vci); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, calling_soft) +{ + cx = cx; + + if(ie->vpi >= 1 << 12) + return -1; + return 0; +} + +DEF_IE_CHECK(net, called_soft) +{ + cx = cx; + + switch(ie->sel) { + + case UNI_SOFT_SEL_ANY: + case UNI_SOFT_SEL_REQ: + case UNI_SOFT_SEL_ASS: + break; + + default: + return -1; + } + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) { + if(ie->vpi >= 1 << 12) + return -1; + } else { + if(ie->sel != UNI_SOFT_SEL_ANY) + return -1; + } + + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) + if(!(ie->h.present & UNI_CALLED_SOFT_VPI_P)) + return -1; + + + return 0; +} + +DEF_IE_ENCODE(net, calling_soft) +{ + START_IE(calling_soft, UNI_IE_CALLING_SOFT, 6); + + APP_BYTE(msg, 0x81); + APP_16BIT(msg, ie->vpi); + + if(ie->h.present & UNI_CALLING_SOFT_VCI_P) { + APP_BYTE(msg, 0x82); + APP_16BIT(msg, ie->vci); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_ENCODE(net, called_soft) +{ + START_IE(called_soft, UNI_IE_CALLED_SOFT, 7); + + APP_BYTE(msg, ie->sel); + + if(ie->h.present & UNI_CALLED_SOFT_VPI_P) { + APP_BYTE(msg, 0x81); + APP_16BIT(msg, ie->vpi); + } + + if(ie->h.present & UNI_CALLED_SOFT_VCI_P) { + APP_BYTE(msg, 0x82); + APP_16BIT(msg, ie->vci); + } + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, calling_soft) +{ + int vci_seen, vpi_seen; + + IE_START(;); + if(ielen < 3) + goto rej; + + vci_seen = 0; + vpi_seen = 0; + + while(ielen) { + switch(*msg->b_rptr++) { + + case 0x81: + if(!vpi_seen) { + ie->vpi = *msg->b_rptr++ << 8; + ie->vpi |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ielen -= 3; + break; + + case 0x82: + if(!vci_seen) { + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ie->h.present |= UNI_CALLING_SOFT_VCI_P; + ielen -= 3; + break; + + default: + goto rej; + } + } + + if(!vpi_seen) + goto rej; + + IE_END(CALLING_SOFT); +} + +DEF_IE_DECODE(net, called_soft) +{ + int vci_seen, vpi_seen; + + IE_START(;); + if(ielen < 3) + goto rej; + + vci_seen = 0; + vpi_seen = 0; + + while(ielen) { + switch(*msg->b_rptr++) { + + case 0x81: + if(!vpi_seen) { + ie->vpi = *msg->b_rptr++ << 8; + ie->vpi |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ielen -= 3; + ie->h.present |= UNI_CALLED_SOFT_VCI_P; + break; + + case 0x82: + if(!vci_seen) { + ie->vci = *msg->b_rptr++ << 8; + ie->vci |= *msg->b_rptr++; + } else { + msg->b_rptr += 2; + } + ie->h.present |= UNI_CALLED_SOFT_VCI_P; + ielen -= 3; + break; + + default: + goto rej; + } + } + + IE_END(CALLED_SOFT); +} + +/********************************************************************* + * + * Crankback + * + * References for this IE are: + * + * PNNI1.0 pp. 203...206 + * + * Only NET coding allowed. + */ + +DEF_IE_PRINT(net, crankback) +{ + u_int j; + + if(uni_print_iehdr("crankback", &ie->h, cx)) + return; + + uni_print_entry(cx, "level", "%d", ie->level); + + switch(ie->type) { + + case UNI_CRANKBACK_IF: + uni_print_entry(cx, "type", "interface"); + break; + + case UNI_CRANKBACK_NODE: + uni_print_entry(cx, "type", "node"); + uni_print_entry(cx, "node", "{%d/", ie->id.node.level); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.node.id[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + break; + + case UNI_CRANKBACK_LINK: + uni_print_entry(cx, "type", "link"); + uni_print_push_prefix("link", cx); + cx->indent++; + + uni_print_entry(cx, "prec", "{%d/", ie->id.link.plevel); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.link.pid[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + + uni_print_entry(cx, "port", "0x%04x", ie->id.link.port); + uni_print_eol(cx); + + uni_print_entry(cx, "succ", "{%d/", ie->id.link.slevel); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->id.link.sid[j]); + uni_printf(cx, "}"); + uni_print_eol(cx); + + cx->indent--; + uni_print_pop_prefix(cx); + break; + + default: + uni_print_entry(cx, "type", "0x%02x", ie->type); + break; + } + + uni_print_entry(cx, "cause", "0x%02x", ie->cause); + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + uni_print_push_prefix("topol", cx); + uni_print_entry(cx, "dir", "%d", ie->diag.top.dir); + uni_print_entry(cx, "port", "0x%04x", ie->diag.top.port); + uni_print_entry(cx, "avcr", "%u", ie->diag.top.avcr); + if(ie->h.present & UNI_CRANKBACK_TOPX_P) { + uni_print_entry(cx, "crm", "%u", ie->diag.top.crm); + uni_print_entry(cx, "vf", "%u", ie->diag.top.vf); + } + uni_print_pop_prefix(cx); + uni_print_eol(cx); + } + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + uni_print_push_prefix("qos", cx); + uni_print_entry(cx, "ctd", "%savail", ie->diag.qos.ctd ? "" : "un"); + uni_print_entry(cx, "cdv", "%savail", ie->diag.qos.cdv ? "" : "un"); + uni_print_entry(cx, "clr", "%savail", ie->diag.qos.clr ? "" : "un"); + uni_print_entry(cx, "other", "%savail", ie->diag.qos.other ? "" : "un"); + uni_print_pop_prefix(cx); + uni_print_eol(cx); + } + + uni_print_eol(cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, crankback) +{ + cx = cx; + + if(ie->level > 104) + return -1; + switch(ie->type) { + case UNI_CRANKBACK_IF: + break; + case UNI_CRANKBACK_NODE: + if(ie->id.node.level > 104) + return -1; + break; + + case UNI_CRANKBACK_LINK: + if(ie->id.link.plevel > 104) + return -1; + if(ie->id.link.slevel > 104) + return -1; + break; + + default: + return -1; + } + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + if(ie->h.present & UNI_CRANKBACK_QOS_P) + return -1; + + if(ie->cause != UNI_CAUSE_CRATE_NAVL) + return -1; + switch(ie->diag.top.dir) { + + case 0x00: + case 0x01: + break; + + default: + return -1; + } + } + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + if(ie->cause != UNI_CAUSE_QOS_NAVL) + return -1; + } + return 0; +} + +DEF_IE_ENCODE(net, crankback) +{ + START_IE(crankback, UNI_IE_CRANKBACK, 72); + + APP_BYTE(msg, ie->level); + APP_BYTE(msg, ie->type); + + switch(ie->type) { + + case UNI_CRANKBACK_IF: + break; + + case UNI_CRANKBACK_NODE: + APP_BYTE(msg, ie->id.node.level); + APP_BUF(msg, ie->id.node.id, 21); + break; + + case UNI_CRANKBACK_LINK: + APP_BYTE(msg, ie->id.link.plevel); + APP_BUF(msg, ie->id.link.pid, 21); + APP_32BIT(msg, ie->id.link.port); + APP_BYTE(msg, ie->id.link.slevel); + APP_BUF(msg, ie->id.link.sid, 21); + break; + } + + APP_BYTE(msg, ie->cause); + + if(ie->h.present & UNI_CRANKBACK_TOP_P) { + APP_BYTE(msg, ie->diag.top.dir); + APP_32BIT(msg, ie->diag.top.port); + APP_32BIT(msg, ie->diag.top.avcr); + if(ie->h.present & UNI_CRANKBACK_TOPX_P) { + APP_32BIT(msg, ie->diag.top.crm); + APP_32BIT(msg, ie->diag.top.vf); + } + } + + if(ie->h.present & UNI_CRANKBACK_QOS_P) { + APP_BYTE(msg, (ie->diag.qos.ctd << 3) + |(ie->diag.qos.cdv << 2) + |(ie->diag.qos.clr << 1) + |(ie->diag.qos.other)); + } + SET_IE_LEN(msg); + return 0; +} + + +DEF_IE_DECODE(net, crankback) +{ + IE_START(;); + + if(ielen < 3) + goto rej; + + ie->level = *msg->b_rptr++; + ielen--; + + ie->type = *msg->b_rptr++; + ielen--; + + switch(ie->type) { + + default: + goto rej; + + case UNI_CRANKBACK_IF: + break; + + case UNI_CRANKBACK_NODE: + if(ielen < 22) + goto rej; + ie->id.node.level = *msg->b_rptr++; + (void)memcpy(ie->id.node.id, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + break; + + case UNI_CRANKBACK_LINK: + if(ielen < 48) + goto rej; + ie->id.link.plevel = *msg->b_rptr++; + (void)memcpy(ie->id.link.pid, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + + ie->id.link.port = *msg->b_rptr++ << 24; + ie->id.link.port |= *msg->b_rptr++ << 16; + ie->id.link.port |= *msg->b_rptr++ << 8; + ie->id.link.port |= *msg->b_rptr++ << 0; + ielen -= 4; + + ie->id.link.slevel = *msg->b_rptr++; + (void)memcpy(ie->id.link.sid, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 22; + + break; + } + + if(ielen < 1) + goto rej; + ie->cause = *msg->b_rptr++; + ielen--; + + if(ie->cause == UNI_CAUSE_CRATE_NAVL) { + if(ielen > 0) { + if(ielen != 9 && ielen != 17) + goto rej; + ie->diag.top.dir = *msg->b_rptr++; + ie->diag.top.port = *msg->b_rptr++ << 24; + ie->diag.top.port |= *msg->b_rptr++ << 16; + ie->diag.top.port |= *msg->b_rptr++ << 8; + ie->diag.top.port |= *msg->b_rptr++ << 0; + ie->diag.top.avcr = *msg->b_rptr++ << 24; + ie->diag.top.avcr |= *msg->b_rptr++ << 16; + ie->diag.top.avcr |= *msg->b_rptr++ << 8; + ie->diag.top.avcr |= *msg->b_rptr++ << 0; + ielen -= 9; + ie->h.present |= UNI_CRANKBACK_TOP_P; + if(ielen > 0) { + ie->diag.top.crm = *msg->b_rptr++ << 24; + ie->diag.top.crm |= *msg->b_rptr++ << 16; + ie->diag.top.crm |= *msg->b_rptr++ << 8; + ie->diag.top.crm |= *msg->b_rptr++ << 0; + ie->diag.top.vf = *msg->b_rptr++ << 24; + ie->diag.top.vf |= *msg->b_rptr++ << 16; + ie->diag.top.vf |= *msg->b_rptr++ << 8; + ie->diag.top.vf |= *msg->b_rptr++ << 0; + ie->h.present |= UNI_CRANKBACK_TOPX_P; + ielen -= 8; + } + } + } else if(ie->cause == UNI_CAUSE_QOS_NAVL) { + if(ielen > 0) { + if(ielen != 1) + goto rej; + ie->diag.qos.ctd = *msg->b_rptr >> 3; + ie->diag.qos.cdv = *msg->b_rptr >> 2; + ie->diag.qos.clr = *msg->b_rptr >> 1; + ie->diag.qos.other = *msg->b_rptr >> 0; + ie->h.present |= UNI_CRANKBACK_QOS_P; + ielen -= 1; + } + } else { + if(ielen > 0) + goto rej; + } + + IE_END(CRANKBACK); +} + +/********************************************************************* + * + * Designated transit list + * + * References for this IE are: + * + * PNNI1.0 pp. 206...208 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, dtl) +{ + u_int i, j; + char buf[10]; + + if(uni_print_iehdr("dtl", &ie->h, cx)) + return; + + uni_print_entry(cx, "ptr", "%d(%d)", ie->ptr, ie->ptr / UNI_DTL_LOGNP_SIZE); + uni_print_push_prefix("dtl", cx); + cx->indent++; + uni_printf(cx, "{"); + for(i = 0; i < ie->num; i++) { + sprintf(buf, "%d", i); + uni_print_entry(cx, buf, "{%d/", ie->dtl[i].node_level); + for(j = 0; j < 21; j++) + uni_printf(cx, "%02x", ie->dtl[i].node_id[j]); + uni_printf(cx, ",%04x}", ie->dtl[i].port_id); + uni_print_eol(cx); + } + cx->indent--; + uni_print_pop_prefix(cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, dtl) +{ + u_int i; + + cx = cx; + + if(ie->ptr % UNI_DTL_LOGNP_SIZE != 0) + return -1; + if(ie->ptr / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM) + return -1; + if(ie->num > UNI_DTL_MAXNUM) + return -1; + for(i = 0; i < ie->num; i++) + if(ie->dtl[i].node_level > 104) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, dtl) +{ + u_int i; + + START_IE(dtl, UNI_IE_DTL, 2 + UNI_DTL_LOGNP_SIZE * ie->num); + + APP_16BIT(msg, ie->ptr); + + for(i = 0; i < ie->num; i++) { + APP_BYTE(msg, UNI_DTL_LOGNP); + APP_BYTE(msg, ie->dtl[i].node_level); + APP_BUF(msg, ie->dtl[i].node_id, 21); + APP_32BIT(msg, ie->dtl[i].port_id); + } + + SET_IE_LEN(msg); + return 0; +} + + +DEF_IE_DECODE(net, dtl) +{ + IE_START(;); + + if(ielen < 2) + goto rej; + + ie->ptr = *msg->b_rptr++ << 8; + ie->ptr |= *msg->b_rptr++; + ielen -= 2; + + if(ielen % UNI_DTL_LOGNP_SIZE != 0) + goto rej; + if(ielen / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM) + goto rej; + + ie->num = 0; + while(ielen) { + if(*msg->b_rptr++ != UNI_DTL_LOGNP) + goto rej; + ielen--; + + ie->dtl[ie->num].node_level = *msg->b_rptr++; + ielen--; + + (void)memcpy(ie->dtl[ie->num].node_id, msg->b_rptr, 21); + msg->b_rptr += 21; + ielen -= 21; + + ie->dtl[ie->num].port_id = *msg->b_rptr++ << 24; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 16; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 8; + ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 0; + ielen -= 4; + + ie->num++; + } + + IE_END(DTL); +} + +/********************************************************************* + * + * Leaf initiated join call identifier. + * Leaf initiated join parameters. + * Leaf initiated join sequence number. + * + * References for this IE are: + * + * UNI4.0 pp. 46...48 + * + * Only NET coding allowed. + */ + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_callid) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_LIJ_IDTYPE_ROOT, root), + EOT() + }; + + if(uni_print_iehdr("lij_callid", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + uni_print_entry(cx, "id", "0x%x", ie->callid); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_callid) +{ + cx = cx; + + switch(ie->type) { + + case UNI_LIJ_IDTYPE_ROOT: + break; + + default: + return -1; + } + + return 0; +} + +DEF_IE_ENCODE(net, lij_callid) +{ + START_IE(lij_callid, UNI_IE_LIJ_CALLID, 5); + + APP_BYTE(msg, 0x80 | ie->type); + APP_32BIT(msg, ie->callid); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_callid) +{ + IE_START(;); + + if(ielen != 5) + goto rej; + + ie->type = *msg->b_rptr++ & 0xf; + ie->callid = *msg->b_rptr++ << 24; + ie->callid |= *msg->b_rptr++ << 16; + ie->callid |= *msg->b_rptr++ << 8; + ie->callid |= *msg->b_rptr++ << 0; + + IE_END(LIJ_CALLID); +} + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_param) +{ + static const struct uni_print_tbl lscreen_tbl[] = { + MKT(UNI_LIJ_SCREEN_NETJOIN, netjoin), + EOT() + }; + + if(uni_print_iehdr("lij_param", &ie->h, cx)) + return; + uni_print_tbl("screen", ie->screen, lscreen_tbl, cx); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_param) +{ + cx = cx; + + switch(ie->screen) { + + case UNI_LIJ_SCREEN_NETJOIN: + break; + + default: + return -1; + } + + return 0; +} + +DEF_IE_ENCODE(net, lij_param) +{ + START_IE(lij_param, UNI_IE_LIJ_PARAM, 1); + + APP_BYTE(msg, 0x80 | ie->screen); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_param) +{ + IE_START(;); + + if(ielen != 1) + goto rej; + + ie->screen = *msg->b_rptr++ & 0xf; + + IE_END(LIJ_PARAM); +} + +/**********************************************************************/ + +DEF_IE_PRINT(net, lij_seqno) +{ + if(uni_print_iehdr("lij_seqno", &ie->h, cx)) + return; + uni_print_entry(cx, "seqno", "0x%x", ie->seqno); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, lij_seqno) +{ + cx = cx; ie = ie; + + return 0; +} + +DEF_IE_ENCODE(net, lij_seqno) +{ + START_IE(lij_seqno, UNI_IE_LIJ_SEQNO, 4); + + APP_32BIT(msg, ie->seqno); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, lij_seqno) +{ + IE_START(;); + + if(ielen != 4) + goto rej; + + ie->seqno = *msg->b_rptr++ << 24; + ie->seqno |= *msg->b_rptr++ << 16; + ie->seqno |= *msg->b_rptr++ << 8; + ie->seqno |= *msg->b_rptr++ << 0; + + IE_END(LIJ_SEQNO); +} + +/********************************************************************* + * + * Connection scope + * + * References for this IE are: + * + * UNI4.0 pp. 57...58 + * + * Only NET coding allowed. + */ +DEF_IE_PRINT(net, cscope) +{ + static const struct uni_print_tbl type_tbl[] = { + MKT(UNI_CSCOPE_ORG, org), + EOT() + }; + static const struct uni_print_tbl scope_tbl[] = { + MKT(UNI_CSCOPE_ORG_LOC, local_network), + MKT(UNI_CSCOPE_ORG_LOC_P1, local_network_plus_one), + MKT(UNI_CSCOPE_ORG_LOC_P2, local_network_plus_two), + MKT(UNI_CSCOPE_ORG_SITE_M1, site_minus_one), + MKT(UNI_CSCOPE_ORG_SITE, intra_site), + MKT(UNI_CSCOPE_ORG_SITE_P1, site_plus_one), + MKT(UNI_CSCOPE_ORG_ORG_M1, organisation_minus_one), + MKT(UNI_CSCOPE_ORG_ORG, intra_organisation), + MKT(UNI_CSCOPE_ORG_ORG_P1, organisation_plus_one), + MKT(UNI_CSCOPE_ORG_COMM_M1, community_minus_one), + MKT(UNI_CSCOPE_ORG_COMM, intra_community), + MKT(UNI_CSCOPE_ORG_COMM_P1, community_plus_one), + MKT(UNI_CSCOPE_ORG_REG, regional), + MKT(UNI_CSCOPE_ORG_INTER, inter_regional), + MKT(UNI_CSCOPE_ORG_GLOBAL, global), + EOT() + }; + + if(uni_print_iehdr("cscope", &ie->h, cx)) + return; + + uni_print_tbl("type", ie->type, type_tbl, cx); + if(ie->type == UNI_CSCOPE_ORG) + uni_print_tbl("scope", (u_int)ie->scope, scope_tbl, cx); + else + uni_print_entry(cx, "scope", "0x%02x", ie->scope); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, cscope) +{ + cx = cx; + + switch(ie->type) { + + default: + return -1; + + case UNI_CSCOPE_ORG: + switch(ie->scope) { + + default: + return -1; + + case UNI_CSCOPE_ORG_LOC: + case UNI_CSCOPE_ORG_LOC_P1: + case UNI_CSCOPE_ORG_LOC_P2: + case UNI_CSCOPE_ORG_SITE_M1: + case UNI_CSCOPE_ORG_SITE: + case UNI_CSCOPE_ORG_SITE_P1: + case UNI_CSCOPE_ORG_ORG_M1: + case UNI_CSCOPE_ORG_ORG: + case UNI_CSCOPE_ORG_ORG_P1: + case UNI_CSCOPE_ORG_COMM_M1: + case UNI_CSCOPE_ORG_COMM: + case UNI_CSCOPE_ORG_COMM_P1: + case UNI_CSCOPE_ORG_REG: + case UNI_CSCOPE_ORG_INTER: + case UNI_CSCOPE_ORG_GLOBAL: + break; + } + break; + } + return 0; +} + +DEF_IE_ENCODE(net, cscope) +{ + START_IE(cscope, UNI_IE_CSCOPE, 2); + + APP_BYTE(msg, ie->type | 0x80); + APP_BYTE(msg, ie->scope); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, cscope) +{ + IE_START(;); + if(ielen != 2) + goto rej; + + if((*msg->b_rptr & 0xf0) != 0x80) + goto rej; + + ie->type = *msg->b_rptr++ & 0xf; + ie->scope = *msg->b_rptr++; + + IE_END(CSCOPE); +} + +/********************************************************************* + * + * Extended Quality of Service + * + * References for this IE are: + * + * UNI4.0 pp. 70...72 + * + * Notes: + * Only NET coding. + */ +DEF_IE_PRINT(net, exqos) +{ + static const struct uni_print_tbl tab[] = { + MKT(UNI_EXQOS_USER, user), + MKT(UNI_EXQOS_NET, net), + EOT() + }; + + if(uni_print_iehdr("exqos", &ie->h, cx)) + return; + + uni_print_tbl("origin", ie->origin, tab, cx); + + uni_print_entry(cx, "acceptable", "("); + if(ie->h.present & UNI_EXQOS_FACC_P) { + if(ie->facc == UNI_EXQOS_ANY_CDV) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->facc); + } + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BACC_P) { + if(ie->bacc == UNI_EXQOS_ANY_CDV) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->bacc); + } + uni_putc(')', cx); + + uni_print_entry(cx, "cumulative", "("); + if(ie->h.present & UNI_EXQOS_FCUM_P) + uni_printf(cx, "%d", ie->fcum); + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BCUM_P) + uni_printf(cx, "%d", ie->bcum); + uni_putc(')', cx); + + uni_print_entry(cx, "clrid", "("); + if(ie->h.present & UNI_EXQOS_FCLR_P) { + if(ie->fclr == UNI_EXQOS_ANY_CLR) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->fclr); + } + uni_putc(',', cx); + if(ie->h.present & UNI_EXQOS_BCLR_P) { + if(ie->bclr == UNI_EXQOS_ANY_CLR) + uni_printf(cx, "ANY"); + else + uni_printf(cx, "%d", ie->bclr); + } + uni_putc(')', cx); + + uni_print_ieend(cx); +} + +DEF_IE_CHECK(net, exqos) +{ + cx = cx; + + switch(ie->origin) { + case UNI_EXQOS_USER: + case UNI_EXQOS_NET: + break; + + default: + return -1; + } + if(ie->h.present & UNI_EXQOS_FACC_P) + if(!(ie->h.present & UNI_EXQOS_FCUM_P)) + return -1; + if(ie->h.present & UNI_EXQOS_BACC_P) + if(!(ie->h.present & UNI_EXQOS_BCUM_P)) + return -1; + + if(ie->h.present & UNI_EXQOS_FACC_P) + if(ie->facc >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_BACC_P) + if(ie->bacc >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_FCUM_P) + if(ie->fcum >= 1 << 24) + return -1; + if(ie->h.present & UNI_EXQOS_BCUM_P) + if(ie->bcum >= 1 << 24) + return -1; + + if(ie->h.present & UNI_EXQOS_FCLR_P) + if(ie->fclr==0 || (ie->fclr>15 && ie->fclr!=UNI_EXQOS_ANY_CLR)) + return -1; + if(ie->h.present & UNI_EXQOS_BCLR_P) + if(ie->bclr==0 || (ie->bclr>15 && ie->bclr!=UNI_EXQOS_ANY_CLR)) + return -1; + return 0; +} + +DEF_IE_ENCODE(net, exqos) +{ + START_IE(exqos, UNI_IE_EXQOS, 21); + + APP_BYTE(msg, ie->origin); + + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FACC_P, + UNI_EXQOS_FACC_ID, ie->facc); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BACC_P, + UNI_EXQOS_BACC_ID, ie->bacc); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FCUM_P, + UNI_EXQOS_FCUM_ID, ie->fcum); + APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BCUM_P, + UNI_EXQOS_BCUM_ID, ie->bcum); + + APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_FCLR_P, + UNI_EXQOS_FCLR_ID, ie->fclr); + APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_BCLR_P, + UNI_EXQOS_BCLR_ID, ie->bclr); + + SET_IE_LEN(msg); + return 0; +} + +DEF_IE_DECODE(net, exqos) +{ + IE_START(;); + + if(ielen < 1 || ielen > 21) + goto rej; + + ie->origin = *msg->b_rptr++; + ielen--; + + while(ielen--) { + switch(*msg->b_rptr++) { + + default: + goto rej; + + DEC_GETF3(EXQOS_FACC, facc, ie->h.present); + DEC_GETF3(EXQOS_BACC, bacc, ie->h.present); + DEC_GETF3(EXQOS_FCUM, fcum, ie->h.present); + DEC_GETF3(EXQOS_BCUM, bcum, ie->h.present); + + DEC_GETF1(EXQOS_FCLR, fclr, ie->h.present); + DEC_GETF1(EXQOS_BCLR, bclr, ie->h.present); + + } + } + IE_END(EXQOS); +} + +/************************************************************** + * + * Free form IE (for testing mainly) + */ +DEF_IE_PRINT(itu, unrec) +{ + u_int i; + + if (uni_print_iehdr("unrec", &ie->h, cx)) + return; + uni_print_entry(cx, "len", "%u", ie->len); + uni_print_entry(cx, "data", "("); + for (i = 0; i < ie->len; i++) + uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->data[i]); + uni_printf(cx, ")"); + uni_print_ieend(cx); +} + +DEF_IE_CHECK(itu, unrec) +{ + cx = cx; + + if (ie->len > sizeof(ie->data)) + return (-1); + + return (0); +} + +DEF_IE_ENCODE(itu, unrec) +{ + START_IE2(unrec, UNI_IE_UNREC, ie->len, ie->id); + + APP_BUF(msg, ie->data, ie->len); + + SET_IE_LEN(msg); + return (0); +} + +DEF_IE_DECODE(itu, unrec) +{ + IE_START(;); + + if (ielen > sizeof(ie->data) / sizeof(ie->data[0]) || ielen < 1) + goto rej; + + ie->len = ielen; + ielen = 0; + (void)memcpy(ie->data, msg->b_rptr, ie->len); + msg->b_rptr += ie->len; + + IE_END(UNREC); +} |