]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/contrib/ngatm/netnatm/msg/uni_ie.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / contrib / ngatm / netnatm / msg / uni_ie.c
1 /*
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  *
29  * $Begemot: libunimsg/netnatm/msg/uni_ie.c,v 1.16 2005/05/23 12:06:30 brandt_h Exp $
30  *
31  * Private definitions for the IE code file.
32  *
33  * This file includes the table generated automatically.
34  */
35
36 #include <sys/types.h>
37 #include <sys/param.h>
38
39 #ifdef _KERNEL
40 #include <sys/libkern.h>
41 #else
42 #include <string.h>
43 #endif
44 #include <netnatm/unimsg.h>
45 #include <netnatm/msg/unistruct.h>
46 #include <netnatm/msg/unimsglib.h>
47 #include <netnatm/msg/uniprint.h>
48 #include <netnatm/msg/priv.h>
49
50 /*
51  * Define internal functions.
52  */
53 #define DEF_IE_PRINT(Coding, IE) \
54         void uni_ie_print_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx)
55
56 #define DEF_IE_CHECK(Coding, IE) \
57         int uni_ie_check_##Coding##_##IE(struct uni_ie_##IE *ie, struct unicx *cx)
58
59 #define DEF_IE_ENCODE(Coding, IE) \
60         int uni_ie_encode_##Coding##_##IE(struct uni_msg *msg, struct uni_ie_##IE *ie, struct unicx *cx)
61
62 #define DEF_IE_DECODE(Coding, IE) \
63         int uni_ie_decode_##Coding##_##IE(struct uni_ie_##IE *ie, struct uni_msg *msg, u_int ielen, struct unicx *cx)
64
65 /*
66  * This structure is used to define value->string mappings. MKT() is used
67  * to generate a table entry. EOT() to end the table.
68  */
69 #define MKT(V,N)        { #N, V }
70 #define EOT()           { NULL, 0 }
71
72 /* library internal functions */
73 static void uni_entry(const char *, struct unicx *);
74 static int  uni_print_iehdr(const char *, struct uni_iehdr *h, struct unicx *);
75 static void uni_print_ieend(struct unicx *);
76 static void uni_putc(int, struct unicx *);
77
78
79 /*
80  * Encoding
81  */
82 #define APP_BYTE(M, B) do {                                     \
83         *(M)->b_wptr++ = (B);                                   \
84     } while (0)
85 #define APP_16BIT(M, B) do {                                    \
86         u_int _v = (B);                                         \
87         *(M)->b_wptr++ = _v >> 8;                               \
88         *(M)->b_wptr++ = _v;                                    \
89     } while (0)
90 #define APP_24BIT(M, B) do {                                    \
91         u_int _v = (B);                                         \
92         *(M)->b_wptr++ = _v >> 16;                              \
93         *(M)->b_wptr++ = _v >> 8;                               \
94         *(M)->b_wptr++ = _v;                                    \
95     } while (0)
96 #define APP_32BIT(M, B) do {                                    \
97         u_int _v = (B);                                         \
98         *(M)->b_wptr++ = _v >> 24;                              \
99         *(M)->b_wptr++ = _v >> 16;                              \
100         *(M)->b_wptr++ = _v >> 8;                               \
101         *(M)->b_wptr++ = _v;                                    \
102     } while (0)
103 #define APP_BUF(M, B, L) do {                                   \
104         (void)memcpy((M)->b_wptr, (B), (L));                    \
105         (M)->b_wptr += (L);                                     \
106     } while (0)
107
108 #define APP_SUB_BYTE(M, T, B)  do { APP_BYTE(M, T); APP_BYTE(M, B); } while (0)
109 #define APP_SUB_16BIT(M, T, B) do { APP_BYTE(M, T); APP_16BIT(M, B); } while (0)
110 #define APP_SUB_24BIT(M, T, B) do { APP_BYTE(M, T); APP_24BIT(M, B); } while (0)
111 #define APP_SUB_32BIT(M, T, B) do { APP_BYTE(M, T); APP_32BIT(M, B); } while (0)
112
113 #define APP_OPT(M, F, P, T) do {                                \
114         if ((F) & (P))                                          \
115                 APP_BYTE((M), (T));                             \
116     } while (0)
117 #define APP_OPT_BYTE(M, F, P, T, B) do {                        \
118         if ((F) & (P))                                          \
119                 APP_SUB_BYTE((M), (T), (B));                    \
120     } while (0)
121 #define APP_OPT_16BIT(M, F, P, T, B) do {                       \
122         if ((F) & (P))                                          \
123                 APP_SUB_16BIT((M), (T), (B));                   \
124     } while (0)
125 #define APP_OPT_24BIT(M, F, P, T, B) do {                       \
126         if ((F) & (P))                                          \
127                 APP_SUB_24BIT((M), (T), (B));                   \
128     } while (0)
129
130 #define START_IE(TYPE,CODE,LEN)                                 \
131         u_int ielen;                                            \
132                                                                 \
133         if (uni_check_ie(CODE, (union uni_ieall *)ie, cx))      \
134                 return (-1);                                    \
135         if (uni_encode_ie_hdr(msg, CODE, &ie->h, (LEN), cx))    \
136                 return (0);                                     \
137                                                                 \
138         ielen = msg->b_wptr - msg->b_rptr - 2;
139
140 #define START_IE2(TYPE,CODE,LEN,REALCODE)                       \
141         u_int ielen;                                            \
142                                                                 \
143         if (uni_check_ie(CODE, (union uni_ieall *)ie, cx))      \
144                 return (-1);                                    \
145         if (uni_encode_ie_hdr(msg, REALCODE, &ie->h, (LEN), cx)) \
146                 return (0);                                     \
147                                                                 \
148         ielen = msg->b_wptr - msg->b_rptr - 2;
149
150 #define SET_IE_LEN(M) do {                                      \
151         (M)->b_buf[ielen + 0] =                                 \
152             (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 8;     \
153         (M)->b_buf[ielen + 1] =                                 \
154             (((M)->b_wptr - (M)->b_rptr) - ielen - 2) >> 0;     \
155     } while (0)
156
157
158 /***********************************************************************/
159 /*
160  * Decoding
161  */
162 #define IE_START(ERR)                                                   \
163         if (IE_ISPRESENT(*ie))                                          \
164                 return (0);                                             \
165         if (ielen == 0) {                                               \
166                 IE_SETEMPTY(*ie);                                       \
167                 return (0);                                             \
168         }
169
170 #define IE_END(IE)                                                      \
171         IE_SETPRESENT(*ie);                                             \
172         if (uni_check_ie(UNI_IE_##IE, (union uni_ieall *)ie, cx) == 0)  \
173                 return (0);                                             \
174   rej:                                                                  \
175         ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT;                  \
176         return (1);
177
178 #define DEC_GETF3(ID, F, P)                                             \
179                   case UNI_##ID##_ID:                                   \
180                         if (ielen < 3)                                  \
181                                 goto rej;                               \
182                         ielen -= 3;                                     \
183                         if (!(P & UNI_##ID##_P)) {                      \
184                                 P |= UNI_##ID##_P;                      \
185                                 ie->F  = *msg->b_rptr++ << 16;          \
186                                 ie->F |= *msg->b_rptr++ << 8;           \
187                                 ie->F |= *msg->b_rptr++;                \
188                         } else                                          \
189                                 msg->b_rptr += 3;                       \
190                         break;
191
192 #define DEC_GETF1(ID, F, P)                                             \
193                   case UNI_##ID##_ID:                                   \
194                         if (ielen < 1)                                  \
195                                 goto rej;                               \
196                         ielen--;                                        \
197                         if (!(P & UNI_##ID##_P)) {                      \
198                                 P |= UNI_##ID##_P;                      \
199                                 ie->F = *msg->b_rptr++;                 \
200                         } else                                          \
201                                 msg->b_rptr++;                          \
202                         break;
203
204
205 #define PRINT_NPREFIX (sizeof(((struct unicx *)0)->prefix) /            \
206             sizeof(((struct unicx *)0)->prefix[0]))
207
208 /*
209  * This is rather here than in privmsg.c because we need the APP macros.
210  */
211 int
212 uni_encode_msg_hdr(struct uni_msg *msg, struct uni_msghdr *h,
213     enum uni_msgtype type, struct unicx *cx, int *mlen)
214 {
215         u_char byte;
216
217         uni_msg_ensure(msg, 9);
218
219         APP_BYTE(msg, cx->pnni ? PNNI_PROTO : UNI_PROTO); 
220         APP_BYTE(msg, 3); 
221         if(h->cref.cref >= 1<<23) 
222                 return -1; 
223         APP_24BIT(msg, h->cref.cref | (h->cref.flag ? 0x800000 : 0));
224         APP_BYTE(msg, type); 
225
226         byte = 0x80;
227         if(h->act != UNI_MSGACT_DEFAULT)
228                 byte |= 0x10 | (h->act & 3);
229         if(cx->pnni && h->pass)
230                 byte |= 0x08;
231         APP_BYTE(msg, byte); 
232
233         *mlen = msg->b_wptr - msg->b_rptr; 
234         APP_16BIT(msg, 0);
235
236         return 0;
237 }
238
239 /*
240  * Initialize printing. This must be called by all printing routines
241  * that are exported to the user.
242  */
243 void
244 uni_print_init(char *buf, size_t bufsiz, struct unicx *cx)
245 {
246         if (cx->dont_init)
247                 return;
248
249         cx->indent = 0;
250         cx->nprefix = 0;
251         cx->doindent = 0;
252         if (cx->tabsiz == 0)
253                 cx->tabsiz = 4;
254         cx->buf = buf;
255         cx->bufsiz = bufsiz;
256 }
257
258 /*
259  * Append a character to the buffer if there is still space
260  */
261 static void
262 uni_putc(int c, struct unicx *cx)
263 {
264         if(cx->bufsiz > 1) {
265                 *cx->buf++ = c;
266                 cx->bufsiz--;
267                 *cx->buf = '\0';
268         }
269 }
270
271 void
272 uni_printf(struct unicx *cx, const char *fmt, ...)
273 {
274         u_int n;
275         va_list ap;
276
277         if(cx->bufsiz > 1) {
278                 va_start(ap, fmt);
279                 n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap);
280                 va_end(ap);
281                 if(n > 0) {
282                         if(n < cx->bufsiz) {
283                                 cx->bufsiz -= n;
284                                 cx->buf += n;
285                         } else {
286                                 cx->buf += cx->bufsiz - 1;
287                                 cx->bufsiz = 1;
288                         }
289                 }
290                 *cx->buf = '\0';
291         }
292 }
293
294 /*
295  * Print mode:
296  *      0 - print all into one line, fully prefixed
297  *      1 - print on multiple lines, full prefixed, but equal level
298  *          entries on one line
299  *      2 - like 2, but only partial prefixed
300  *      3 - like 1, but each entry onto a new line
301  *      4 - like 2 + 3
302  */
303
304 /*
305  * If we are in multiline mode, end the current line and set the
306  * flag, that we need indentation. But prevent double new lines.
307  */
308 void
309 uni_print_eol(struct unicx *cx)
310 {
311         if (cx->multiline) {
312                 if (!cx->doindent) {
313                         uni_putc('\n', cx);
314                         cx->doindent = 1;
315                 }
316         } 
317 }
318
319 /*
320  * New entry. Do the prefixing, indentation and spacing.
321  */
322 static void
323 doprefix(struct unicx *cx, const char *s)
324 {
325         u_int i;
326
327         if(cx->multiline == 0) {
328                 uni_putc(' ', cx);
329                 for(i = 0; i < cx->nprefix; i++)
330                         if(cx->prefix[i])
331                                 uni_printf(cx, "%s.", cx->prefix[i]);
332         } else if(cx->multiline == 1) {
333                 if(cx->doindent) {
334                         uni_printf(cx, "%*s", cx->indent * cx->tabsiz, "");
335                         cx->doindent = 0;
336                 } else
337                         uni_putc(' ', cx);
338                 for(i = 0; i < cx->nprefix; i++)
339                         if(cx->prefix[i])
340                                 uni_printf(cx, "%s.", cx->prefix[i]);
341         } else if(cx->multiline == 2) {
342                 if(cx->doindent) {
343                         uni_printf(cx, "%*s", cx->indent * cx->tabsiz, "");
344                         cx->doindent = 0;
345                 } else
346                         uni_putc(' ', cx);
347         } else if(cx->multiline == 3) {
348                 if(cx->doindent)
349                         cx->doindent = 0;
350                 else
351                         uni_putc('\n', cx);
352                 uni_printf(cx, "%*s", cx->indent * cx->tabsiz, "");
353                 for(i = 0; i < cx->nprefix; i++)
354                         if(cx->prefix[i])
355                                 uni_printf(cx, "%s.", cx->prefix[i]);
356         } else if(cx->multiline == 4) {
357                 if(cx->doindent)
358                         cx->doindent = 0;
359                 else
360                         uni_putc('\n', cx);
361                 uni_printf(cx, "%*s", cx->indent * cx->tabsiz, "");
362         }
363         uni_printf(cx, "%s", s);
364 }
365 static void
366 uni_entry(const char *s, struct unicx *cx)
367 {
368         doprefix(cx, s);
369         uni_putc('=', cx);
370 }
371 void
372 uni_print_flag(const char *s, struct unicx *cx)
373 {
374         doprefix(cx, s);
375 }
376
377
378 /*
379  * Start a deeper level of indendation. If multiline is in effect,
380  * we end the current line.
381  */
382 void
383 uni_print_push_prefix(const char *prefix, struct unicx *cx)
384 {
385         if (cx->nprefix < PRINT_NPREFIX)
386                 cx->prefix[cx->nprefix++] = prefix;
387 }
388 void
389 uni_print_pop_prefix(struct unicx *cx)
390 {
391         if (cx->nprefix > 0)
392                 cx->nprefix--;
393 }
394
395 void
396 uni_print_tbl(const char *entry, u_int val, const struct uni_print_tbl *tbl,
397     struct unicx *cx)
398 {
399         if (entry)
400                 uni_entry(entry, cx);
401         while (tbl->name) {
402                 if (tbl->val == val) {
403                         uni_printf(cx, "%s", tbl->name);
404                         return;
405                 }
406                 tbl++;
407         }
408         uni_printf(cx, "ERROR(0x%x)", val);
409 }
410
411 void
412 uni_print_entry(struct unicx *cx, const char *e, const char *fmt, ...)
413 {
414         u_int n;
415         va_list ap;
416
417         uni_entry(e, cx);
418
419         if (cx->bufsiz > 1) {
420                 va_start(ap, fmt);
421                 n = vsnprintf(cx->buf, cx->bufsiz, fmt, ap);
422                 va_end(ap);
423                 if (n > 0) {
424                         if (n < cx->bufsiz) {
425                                 cx->bufsiz -= n;
426                                 cx->buf += n;
427                         } else {
428                                 cx->buf += cx->bufsiz - 1;
429                                 cx->bufsiz = 1;
430                         }
431                 }
432                 *cx->buf = '\0';
433         }
434 }
435
436 /**********************************************************************/
437 /*
438  * Printing information elements.
439  */
440 static int
441 uni_print_iehdr(const char *name, struct uni_iehdr *h, struct unicx *cx)
442 {
443         static const struct uni_print_tbl act_tab[] = {
444                 MKT(UNI_IEACT_CLEAR,    clear),
445                 MKT(UNI_IEACT_IGNORE,   ignore),
446                 MKT(UNI_IEACT_REPORT,   report),
447                 MKT(UNI_IEACT_MSG_IGNORE, ignore-msg),
448                 MKT(UNI_IEACT_MSG_REPORT, report-msg),
449                 MKT(UNI_IEACT_DEFAULT,  default),
450                 EOT()
451         };
452         static const struct uni_print_tbl cod_tab[] = {
453                 MKT(UNI_CODING_ITU, itut),
454                 MKT(UNI_CODING_NET, atmf),
455                 EOT()
456         };
457
458         uni_print_entry(cx, name, "(");
459         uni_print_tbl(NULL, h->act, act_tab, cx);
460         uni_putc(',', cx);
461         uni_print_tbl(NULL, h->coding, cod_tab, cx);
462         if(cx->pnni && h->pass)
463                 uni_printf(cx, ",pass");
464         if(IE_ISEMPTY(*(struct uni_ie_aal *)h)) {
465                 uni_printf(cx, ",empty)");
466                 uni_print_eol(cx);
467                 return 1;
468         }
469         if(IE_ISERROR(*(struct uni_ie_aal *)h)) {
470                 uni_printf(cx, ",error)");
471                 uni_print_eol(cx);
472                 return 1;
473         }
474
475         uni_putc(')', cx);
476
477         uni_print_push_prefix(name, cx);
478         uni_print_eol(cx);
479         cx->indent++;
480
481         return 0;
482 }
483
484 static void
485 uni_print_ieend(struct unicx *cx)
486 {
487         uni_print_pop_prefix(cx);
488         uni_print_eol(cx);
489         cx->indent--;
490 }
491
492 void
493 uni_print_ie_internal(enum uni_ietype code, const union uni_ieall *ie,
494     struct unicx *cx)
495 {
496         const struct iedecl *iedecl;
497
498         if((iedecl = GET_IEDECL(code, ie->h.coding)) != NULL)
499                 (*iedecl->print)(ie, cx);
500 }
501
502 void
503 uni_print_ie(char *buf, size_t size, enum uni_ietype code,
504     const union uni_ieall *ie, struct unicx *cx)
505 {
506         uni_print_init(buf, size, cx);
507         uni_print_ie_internal(code, ie, cx);
508 }
509
510 int
511 uni_check_ie(enum uni_ietype code, union uni_ieall *ie, struct unicx *cx)
512 {
513         const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding);
514
515         if (iedecl != NULL)
516                 return (iedecl->check(ie, cx));
517         else
518                 return (-1);
519 }
520
521 /*
522  * Decode a information element header.
523  * Returns -1 if the message is too short.
524  * Strip the header from the message.
525  * The header is stripped, even if it is too short.
526  */
527 int
528 uni_decode_ie_hdr(enum uni_ietype *ietype, struct uni_iehdr *hdr,
529     struct uni_msg *msg, struct unicx *cx, u_int *ielen)
530 {
531         u_int len;
532
533         *ietype = (enum uni_ietype)0;
534         *ielen = 0;
535         hdr->present = 0;
536         hdr->coding = UNI_CODING_ITU;
537         hdr->act = UNI_IEACT_DEFAULT;
538
539         if ((len = uni_msg_len(msg)) == 0)
540                 return (-1);
541
542         *ietype = *msg->b_rptr++;
543
544         if (--len == 0)
545                 return (-1);
546
547         hdr->coding = (*msg->b_rptr >> 5) & 3;
548         hdr->present = 0;
549
550         switch (*msg->b_rptr & 0x17) {
551
552           case 0x10: case 0x11: case 0x12:
553           case 0x15: case 0x16:
554                 hdr->act = *msg->b_rptr & 0x7;
555                 break;
556
557           case 0x00: case 0x01: case 0x02: case 0x03:
558           case 0x04: case 0x05: case 0x06: case 0x07:
559                 hdr->act = UNI_IEACT_DEFAULT;
560                 break;
561
562           default:
563                 /* Q.2931 5.7.2 last sentence */
564                 hdr->act = UNI_IEACT_REPORT;
565                 break;
566         }
567         if (cx->pnni && (*msg->b_rptr & 0x08))
568                 hdr->pass = 1;
569         else
570                 hdr->pass = 0;
571         msg->b_rptr++;
572
573         if (--len == 0) {
574                 hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT;
575                 return (-1);
576         }
577
578         if (len < 2) {
579                 msg->b_rptr += len;
580                 hdr->present = UNI_IE_ERROR | UNI_IE_PRESENT;
581                 return (-1);
582         }
583
584         *ielen = *msg->b_rptr++ << 8;
585         *ielen |= *msg->b_rptr++;
586
587         return (0);
588 }
589
590 /*
591  * Decode the body of an information element.
592  */
593 int
594 uni_decode_ie_body(enum uni_ietype ietype, union uni_ieall *ie,
595     struct uni_msg *msg, u_int ielen, struct unicx *cx)
596 {
597         const struct iedecl *iedecl;
598         u_char *end;
599         int ret;
600
601         if (ielen > uni_msg_len(msg)) {
602                 /*
603                  * Information element too long -> content error.
604                  * Q.2931 5.6.8.2
605                  */
606                 msg->b_rptr = msg->b_wptr;
607                 ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT;
608                 return (-1);
609         }
610
611         if ((iedecl = GET_IEDECL(ietype, ie->h.coding)) == NULL) {
612                 /*
613                  * entirly unknown IE.
614                  * Q.2931 5.6.8.1
615                  */
616                 msg->b_rptr += ielen;
617                 ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT;
618                 return (-1);
619         }
620
621         if (ielen > iedecl->maxlen) {
622                 /*
623                  * Information element too long -> content error.
624                  * Q.2931 5.6.8.2
625                  */
626                 msg->b_rptr += iedecl->maxlen;
627                 ie->h.present = UNI_IE_ERROR | UNI_IE_PRESENT;
628                 return (-1);
629         }
630
631         end = msg->b_rptr + ielen;
632         ret = (*iedecl->decode)(ie, msg, ielen, cx);
633         msg->b_rptr = end;
634
635         return (ret);
636 }
637
638 int
639 uni_encode_ie(enum uni_ietype code, struct uni_msg *msg, union uni_ieall *ie,
640     struct unicx *cx)
641 {
642         const struct iedecl *iedecl = GET_IEDECL(code, ie->h.coding);
643
644         if (iedecl == NULL)
645                 return (-1);
646         return (iedecl->encode(msg, ie, cx));
647 }
648
649 int
650 uni_encode_ie_hdr(struct uni_msg *msg, enum uni_ietype type,
651     struct uni_iehdr *h, u_int len, struct unicx *cx)
652 {
653         u_char byte;
654
655         uni_msg_ensure(msg, 4 + len);
656         *msg->b_wptr++ = type;
657
658         byte = 0x80 | (h->coding << 5);
659         if(h->act != UNI_IEACT_DEFAULT)
660                 byte |= 0x10 | (h->act & 7);
661         if(cx->pnni)
662                 byte |= h->pass << 3;
663         *msg->b_wptr++ = byte;
664
665         if(h->present & UNI_IE_EMPTY) {
666                 *msg->b_wptr++ = 0;
667                 *msg->b_wptr++ = 4;
668                 return -1;
669         }
670         *msg->b_wptr++ = 0;
671         *msg->b_wptr++ = 0;
672
673         return 0;
674 }
675
676 /*
677  * Printing messages.
678  */
679 static void
680 uni_print_cref_internal(const struct uni_cref *cref, struct unicx *cx)
681 {
682         uni_print_entry(cx, "cref", "%d.", cref->flag);
683         if (cref->cref == CREF_GLOBAL)
684                 uni_printf(cx, "GLOBAL");
685         else if (cref->cref == CREF_DUMMY)
686                 uni_printf(cx, "DUMMY");
687         else
688                 uni_printf(cx, "%d", cref->cref);
689 }
690 void
691 uni_print_cref(char *str, size_t len, const struct uni_cref *cref,
692     struct unicx *cx)
693 {
694         uni_print_init(str, len, cx);
695         uni_print_cref_internal(cref, cx);
696 }
697
698 static void
699 uni_print_msghdr_internal(const struct uni_msghdr *hdr, struct unicx *cx)
700 {
701         static const struct uni_print_tbl tab[] = {
702                 MKT(UNI_MSGACT_CLEAR,   clear),
703                 MKT(UNI_MSGACT_IGNORE,  ignore),
704                 MKT(UNI_MSGACT_REPORT,  report),
705                 MKT(UNI_MSGACT_DEFAULT, default),
706                 EOT()
707         };
708
709         uni_print_cref_internal(&hdr->cref, cx);
710         uni_print_tbl("act", hdr->act, tab, cx);
711         if (cx->pnni)
712                 uni_print_entry(cx, "pass", "%s", hdr->pass ? "yes" : "no");
713 }
714
715 void
716 uni_print_msghdr(char *str, size_t len, const struct uni_msghdr *hdr,
717     struct unicx *cx)
718 {
719         uni_print_init(str, len, cx);
720         uni_print_msghdr_internal(hdr, cx);
721 }
722
723
724 static void
725 uni_print_internal(const struct uni_all *msg, struct unicx *cx)
726 {
727         uni_entry("mtype", cx);
728         if(msg->mtype >= 256 || uni_msgtable[msg->mtype] == NULL) {
729                 uni_printf(cx, "0x%02x(ERROR)", msg->mtype);
730         } else {
731                 uni_printf(cx, "%s", uni_msgtable[msg->mtype]->name);
732                 uni_print_msghdr_internal(&msg->u.hdr, cx);
733                 cx->indent++;
734                 uni_print_eol(cx);
735                 (*uni_msgtable[msg->mtype]->print)(&msg->u, cx);
736                 cx->indent--;
737         }
738
739         if(cx->multiline == 0)
740                 uni_printf(cx, "\n");
741 }
742
743 void
744 uni_print(char *buf, size_t size, const struct uni_all *all, struct unicx *cx)
745 {
746         uni_print_init(buf, size, cx);
747         uni_print_internal(all, cx);
748 }
749
750 static void
751 uni_print_msg_internal(u_int mtype, const union uni_msgall *msg,
752     struct unicx *cx)
753 {
754
755         uni_entry("mtype", cx);
756         if (mtype >= 256 || uni_msgtable[mtype] == NULL) {
757                 uni_printf(cx, "0x%02x(ERROR)", mtype);
758         } else {
759                 uni_printf(cx, "%s", uni_msgtable[mtype]->name);
760                 uni_print_msghdr_internal(&msg->hdr, cx);
761                 cx->indent++;
762                 uni_print_eol(cx);
763                 (*uni_msgtable[mtype]->print)(msg, cx);
764                 cx->indent--;
765         }
766
767         if(cx->multiline == 0)
768                 uni_printf(cx, "\n");
769 }
770
771 void
772 uni_print_msg(char *buf, size_t size, u_int mtype, const union uni_msgall *all,
773     struct unicx *cx)
774 {
775         uni_print_init(buf, size, cx);
776         uni_print_msg_internal(mtype, all, cx);
777 }
778
779 void
780 uni_print_cx(char *buf, size_t size, struct unicx *cx)
781 {
782         static const char *acttab[] = {
783                 "clr",  /* 0x00 */
784                 "ign",  /* 0x01 */
785                 "rep",  /* 0x02 */
786                 "x03",  /* 0x03 */
787                 "x04",  /* 0x04 */
788                 "mig",  /* 0x05 */
789                 "mrp",  /* 0x06 */
790                 "x07",  /* 0x07 */
791                 "def",  /* 0x08 */
792         };
793
794         static const char *errtab[] = {
795                 [UNI_IERR_UNK] = "unk", /* unknown IE */
796                 [UNI_IERR_LEN] = "len", /* length error */
797                 [UNI_IERR_BAD] = "bad", /* content error */
798                 [UNI_IERR_ACC] = "acc", /* access element discarded */
799                 [UNI_IERR_MIS] = "mis", /* missing IE */
800         };
801
802         u_int i;
803
804         uni_print_init(buf, size, cx);
805
806         uni_printf(cx, "q2932           %d\n", cx->q2932);
807         uni_printf(cx, "pnni            %d\n", cx->pnni);
808         uni_printf(cx, "git_hard        %d\n", cx->git_hard);
809         uni_printf(cx, "bearer_hard     %d\n", cx->bearer_hard);
810         uni_printf(cx, "cause_hard      %d\n", cx->cause_hard);
811
812         uni_printf(cx, "multiline       %d\n", cx->multiline);
813         uni_printf(cx, "tabsiz          %d\n", cx->tabsiz);
814
815         uni_printf(cx, "errcnt          %d (", cx->errcnt);
816         for(i = 0; i < cx->errcnt; i++) {
817                 uni_printf(cx, "%02x[%s,%s%s]", cx->err[i].ie,
818                     errtab[cx->err[i].err], acttab[cx->err[i].act],
819                     cx->err[i].man ? ",M" : "");
820                 if(i != cx->errcnt - 1)
821                         uni_putc(' ', cx);
822         }
823         uni_printf(cx, ")\n");
824 }
825
826 #include <netnatm/msg/uni_ietab.h>
827
828 /*********************************************************************
829  *
830  * Cause
831  *
832  * References for this IE are:
833  *
834  *  Q.2931 pp. 69 (just a pointer to Q.2610)
835  *  Q.2610        (this is a small diff to Q.850)
836  *  Q.850         !!
837  *  UNI4.0 pp. 15
838  *  PNNI1.0 p. 198
839  *
840  * ITU-T and NET coding for different values.
841  */
842 static const struct causetab {
843         const char      *str;
844         enum uni_diag   diag;
845 } itu_causes[128] = {
846
847 #define D(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] = { STR, UNI_DIAG_##DIAG },
848 #define N(NAME,VAL,DIAG,STD,STR)
849
850 UNI_DECLARE_CAUSE_VALUES
851
852 #undef D
853 #undef N
854
855 }, net_causes[128] = {
856
857 #define D(NAME,VAL,DIAG,STD,STR)
858 #define N(NAME,VAL,DIAG,STD,STR) [UNI_CAUSE_##NAME] = { STR, UNI_DIAG_##DIAG },
859
860 UNI_DECLARE_CAUSE_VALUES
861
862 #undef D
863 #undef N
864
865 };
866
867 enum uni_diag
868 uni_diag(enum uni_cause cause, enum uni_coding code)
869 {
870         if (cause >= 128)
871                 return (UNI_DIAG_NONE);
872
873         if (code == UNI_CODING_NET)
874                 if (net_causes[cause].str != NULL)
875                         return (net_causes[cause].diag);
876         if (itu_causes[cause].str != NULL)
877                 return (itu_causes[cause].diag);
878         return (UNI_DIAG_NONE);
879 }
880
881 /**********************************************************************/
882
883 static void
884 print_cause(struct unicx *cx, struct uni_ie_cause *ie,
885     const struct causetab *tab1, const struct causetab *tab2)
886 {
887         static const struct uni_print_tbl loc_tbl[] = {
888                 MKT(UNI_CAUSE_LOC_USER,         user),
889                 MKT(UNI_CAUSE_LOC_PRIVLOC,      priv-net:loc-user),
890                 MKT(UNI_CAUSE_LOC_PUBLOC,       pub-net:loc-user),
891                 MKT(UNI_CAUSE_LOC_TRANSIT,      transit-net),
892                 MKT(UNI_CAUSE_LOC_PUBREM,       pub-net:rem-user),
893                 MKT(UNI_CAUSE_LOC_PRIVREM,      priv-net:rem-user),
894                 MKT(UNI_CAUSE_LOC_INTERNAT,     int-net),
895                 MKT(UNI_CAUSE_LOC_BEYOND,       beyond),
896                 EOT()
897         };
898         static const struct uni_print_tbl pu_tbl[] = {
899                 MKT(UNI_CAUSE_PU_PROVIDER,      provider),
900                 MKT(UNI_CAUSE_PU_USER,          user),
901                 EOT()
902         };
903         static const struct uni_print_tbl na_tbl[] = {
904                 MKT(UNI_CAUSE_NA_NORMAL,        normal),
905                 MKT(UNI_CAUSE_NA_ABNORMAL,      abnormal),
906                 EOT()
907         };
908         static const struct uni_print_tbl cond_tbl[] = {
909                 MKT(UNI_CAUSE_COND_UNKNOWN,     unknown),
910                 MKT(UNI_CAUSE_COND_PERM,        permanent),
911                 MKT(UNI_CAUSE_COND_TRANS,       transient),
912                 EOT()
913         };
914         static const struct uni_print_tbl rej_tbl[] = {
915                 MKT(UNI_CAUSE_REASON_USER,      user),
916                 MKT(UNI_CAUSE_REASON_IEMISS,    ie-missing),
917                 MKT(UNI_CAUSE_REASON_IESUFF,    ie-not-suff),
918                 EOT()
919         };
920         char buf[100], *s;
921         u_int i;
922
923         if (uni_print_iehdr("cause", &ie->h, cx))
924                 return;
925
926         if (ie->cause < 128 && tab1[ie->cause].str)
927                 strcpy(buf, tab1[ie->cause].str);
928         else if (ie->cause < 128 && tab2 != NULL && tab2[ie->cause].str != NULL)
929                 strcpy(buf, tab2[ie->cause].str);
930         else {
931                 sprintf(buf, "UNKNOWN-%u", ie->cause);
932         }
933
934         for (s = buf; *s != '\0'; s++)
935                 if (*s == ' ')
936                         *s = '_';
937         uni_print_entry(cx, "cause", "%s", buf);
938
939         uni_print_tbl("loc", ie->loc, loc_tbl, cx);
940
941         if (ie->h.present & UNI_CAUSE_COND_P) {
942                 uni_print_tbl("pu", ie->u.cond.pu, pu_tbl, cx);
943                 uni_print_tbl("na", ie->u.cond.na, na_tbl, cx);
944                 uni_print_tbl("condition", ie->u.cond.cond, cond_tbl, cx);
945         }
946         if (ie->h.present & UNI_CAUSE_REJ_P) {
947                 uni_print_tbl("reject", ie->u.rej.reason, rej_tbl, cx);
948         }
949         if (ie->h.present & UNI_CAUSE_REJ_USER_P) {
950                 uni_print_entry(cx, "user", "%u", ie->u.rej.user);
951         }
952         if (ie->h.present & UNI_CAUSE_REJ_IE_P) {
953                 uni_print_entry(cx, "ie", "%u", ie->u.rej.ie);
954         }
955         if (ie->h.present & UNI_CAUSE_IE_P) {
956                 uni_print_entry(cx, "ie", "(");
957                 for (i = 0; i < ie->u.ie.len; i++) {
958                         if (i)
959                                 uni_putc(',', cx);
960                         uni_printf(cx, "0x%02x", ie->u.ie.ie[i]);
961                 }
962                 uni_putc(')', cx);
963         }
964         if (ie->h.present & UNI_CAUSE_TRAFFIC_P) {
965                 uni_print_entry(cx, "traffic", "(");
966                 for (i = 0; i < ie->u.traffic.len; i++) {
967                         if (i)
968                                 uni_putc(',', cx);
969                         uni_printf(cx, "0x%02x", ie->u.traffic.traffic[i]);
970                 }
971                 uni_putc(')', cx);
972         }
973         if (ie->h.present & UNI_CAUSE_VPCI_P) {
974                 uni_print_entry(cx, "vpci", "(%u,%u)", ie->u.vpci.vpci, ie->u.vpci.vci);
975         }
976         if (ie->h.present & UNI_CAUSE_MTYPE_P) {
977                 uni_print_entry(cx, "mtype", "%u", ie->u.mtype);
978         }
979         if (ie->h.present & UNI_CAUSE_TIMER_P) {
980                 for (i = 0, s = buf; i < 3; i++) {
981                         if (ie->u.timer[i] < ' ') {
982                                 *s++ = '^';
983                                 *s++ = ie->u.timer[i] + '@';
984                         } else if (ie->u.timer[i] <= '~')
985                                 *s++ = ie->u.timer[i];
986                         else {
987                                 *s++ = '\\';
988                                 *s++ = ie->u.timer[i] / 0100 + '0';
989                                 *s++ = (ie->u.timer[i] % 0100) / 010 + '0';
990                                 *s++ = ie->u.timer[i] % 010 + '0';
991                         }
992                 }
993                 *s++ = '\0';
994                 uni_print_entry(cx, "timer", "\"%s\"", buf);
995         }
996         if (ie->h.present & UNI_CAUSE_TNS_P) {
997                 uni_print_eol(cx);
998                 uni_print_ie_internal(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx);
999         }
1000         if (ie->h.present & UNI_CAUSE_NUMBER_P) {
1001                 uni_print_eol(cx);
1002                 uni_print_ie_internal(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx);
1003         }
1004         if (ie->h.present & UNI_CAUSE_ATTR_P) {
1005                 uni_print_entry(cx, "attr", "(");
1006                 for (i = 0; i < ie->u.attr.nattr; i++) {
1007                         uni_printf(cx, "(%u", ie->u.attr.attr[i][0]);
1008                         if (!(ie->u.attr.attr[i][0] & 0x80)) {
1009                                 uni_printf(cx, ",%u", ie->u.attr.attr[i][1]);
1010                                 if (!(ie->u.attr.attr[i][1] & 0x80))
1011                                         uni_printf(cx, ",%u",
1012                                             ie->u.attr.attr[i][2]);
1013                         }
1014                         uni_putc(')', cx);
1015                 }
1016         }
1017
1018         uni_print_ieend(cx);
1019 }
1020
1021 DEF_IE_PRINT(itu, cause)
1022 {
1023         print_cause(cx, ie, itu_causes, NULL);
1024 }
1025 DEF_IE_PRINT(net, cause)
1026 {
1027         print_cause(cx, ie, net_causes, itu_causes);
1028 }
1029
1030 const char *
1031 uni_ie_cause2str(enum uni_coding coding, u_int cause)
1032 {
1033         if (cause < 128) {
1034                 if (coding == UNI_CODING_ITU)
1035                         return (itu_causes[cause].str);
1036                 if (coding == UNI_CODING_NET) {
1037                         if (net_causes[cause].str != NULL)
1038                                 return (net_causes[cause].str);
1039                         return (itu_causes[cause].str);
1040                 }
1041         }
1042         return (NULL);
1043 }
1044
1045 /**********************************************************************/
1046
1047 static int
1048 check_cause(struct uni_ie_cause *ie, struct unicx *cx,
1049     const struct causetab *tab1, const struct causetab *tab2)
1050 {
1051         static const u_int mask =
1052                 UNI_CAUSE_COND_P | UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P |
1053                 UNI_CAUSE_REJ_IE_P | UNI_CAUSE_IE_P | UNI_CAUSE_TRAFFIC_P |
1054                 UNI_CAUSE_VPCI_P | UNI_CAUSE_MTYPE_P | UNI_CAUSE_TIMER_P |
1055                 UNI_CAUSE_TNS_P | UNI_CAUSE_NUMBER_P | UNI_CAUSE_ATTR_P |
1056                 UNI_CAUSE_PARAM_P;
1057
1058         const struct causetab *ptr;
1059
1060         if (ie->cause >= 128)
1061                 return (-1);
1062
1063         switch (ie->loc) {
1064           default:
1065                 return (-1);
1066
1067           case UNI_CAUSE_LOC_USER:
1068           case UNI_CAUSE_LOC_PRIVLOC:
1069           case UNI_CAUSE_LOC_PUBLOC:
1070           case UNI_CAUSE_LOC_TRANSIT:
1071           case UNI_CAUSE_LOC_PUBREM:
1072           case UNI_CAUSE_LOC_PRIVREM:
1073           case UNI_CAUSE_LOC_INTERNAT:
1074           case UNI_CAUSE_LOC_BEYOND:
1075                 break;
1076         }
1077
1078         if (tab1[ie->cause].str != NULL)
1079                 ptr = &tab1[ie->cause];
1080         else if (tab2 != NULL && tab2[ie->cause].str != NULL)
1081                 ptr = &tab2[ie->cause];
1082         else
1083                 return (cx->cause_hard ? -1 : 0);
1084
1085         switch (ptr->diag) {
1086
1087           case UNI_DIAG_NONE:
1088                 switch (ie->h.present & mask) {
1089                   default:
1090                         if (cx->cause_hard)
1091                                 return (-1);
1092                         break;
1093
1094                   case 0:
1095                         break;
1096                 }
1097                 break;
1098
1099           case UNI_DIAG_COND:
1100                 switch (ie->h.present & mask) {
1101                   default:
1102                         if (cx->cause_hard)
1103                                 return (-1);
1104                         break;
1105
1106                   case 0:
1107                   case UNI_CAUSE_COND_P:
1108                         break;
1109                 }
1110                 break;
1111
1112           case UNI_DIAG_REJ:
1113                 switch (ie->h.present & mask) {
1114                   default:
1115                         if (cx->cause_hard)
1116                                 return (-1);
1117                         break;
1118
1119                   case 0:
1120                   case UNI_CAUSE_REJ_P:
1121                   case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P:
1122                   case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P:
1123                         break;
1124                 }
1125                 break;
1126
1127           case UNI_DIAG_CRATE:
1128                 switch (ie->h.present & mask) {
1129                   default:
1130                         if (cx->cause_hard)
1131                                 return (-1);
1132                         break;
1133
1134                   case 0:
1135                   case UNI_CAUSE_TRAFFIC_P:
1136                         break;
1137                 }
1138                 break;
1139
1140           case UNI_DIAG_IE:
1141                 switch (ie->h.present & mask) {
1142                   default:
1143                         if (cx->cause_hard)
1144                                 return (-1);
1145                         break;
1146
1147                   case 0:
1148                   case UNI_CAUSE_IE_P:
1149                         break;
1150                 }
1151                 break;
1152
1153           case UNI_DIAG_CHANID:
1154                 switch (ie->h.present & mask) {
1155                   default:
1156                         if (cx->cause_hard)
1157                                 return (-1);
1158                         break;
1159
1160                   case 0:
1161                   case UNI_CAUSE_VPCI_P:
1162                         break;
1163                 }
1164                 break;
1165
1166           case UNI_DIAG_MTYPE:
1167                 switch (ie->h.present & mask) {
1168                   default:
1169                         if (cx->cause_hard)
1170                                 return (-1);
1171                         break;
1172
1173                   case 0:
1174                   case UNI_CAUSE_MTYPE_P:
1175                         break;
1176                 }
1177                 break;
1178
1179           case UNI_DIAG_TIMER:
1180                 switch (ie->h.present & mask) {
1181                   default:
1182                         if (cx->cause_hard)
1183                                 return (-1);
1184                         break;
1185
1186                   case 0:
1187                   case UNI_CAUSE_TIMER_P:
1188                         break;
1189                 }
1190                 break;
1191
1192           case UNI_DIAG_TNS:
1193                 switch (ie->h.present & mask) {
1194                   default:
1195                         if (cx->cause_hard)
1196                                 return (-1);
1197                         break;
1198
1199                   case 0:
1200                   case UNI_CAUSE_TNS_P:
1201                         break;
1202                 }
1203                 break;
1204
1205           case UNI_DIAG_NUMBER:
1206                 switch (ie->h.present & mask) {
1207                   default:
1208                         if (cx->cause_hard)
1209                                 return (-1);
1210                         break;
1211
1212                   case 0:
1213                   case UNI_CAUSE_NUMBER_P:
1214                         break;
1215                 }
1216                 break;
1217
1218           case UNI_DIAG_ATTR:
1219                 switch (ie->h.present & mask) {
1220                   default:
1221                         if (cx->cause_hard)
1222                                 return (-1);
1223                         break;
1224
1225                   case 0:
1226                   case UNI_CAUSE_ATTR_P:
1227                         break;
1228                 }
1229                 break;
1230
1231           case UNI_DIAG_PARAM:
1232                 switch (ie->h.present & mask) {
1233                   default:
1234                         if (cx->cause_hard)
1235                                 return (-1);
1236                         break;
1237
1238                   case 0:
1239                   case UNI_CAUSE_PARAM_P:
1240                         break;
1241                 }
1242                 break;
1243         }
1244
1245         if (ie->h.present & UNI_CAUSE_COND_P) {
1246                 switch (ie->u.cond.pu) {
1247                   default:
1248                         return (-1);
1249
1250                   case UNI_CAUSE_PU_PROVIDER:
1251                   case UNI_CAUSE_PU_USER:
1252                         break;
1253                 }
1254                 switch (ie->u.cond.na) {
1255                   default:
1256                         return (-1);
1257
1258                   case UNI_CAUSE_NA_NORMAL:
1259                   case UNI_CAUSE_NA_ABNORMAL:
1260                         break;
1261                 }
1262                 switch (ie->u.cond.cond) {
1263                   default:
1264                         return (-1);
1265
1266                   case UNI_CAUSE_COND_UNKNOWN:
1267                   case UNI_CAUSE_COND_PERM:
1268                   case UNI_CAUSE_COND_TRANS:
1269                         break;
1270                 }
1271         }
1272         if (ie->h.present & UNI_CAUSE_REJ_P) {
1273                 switch (ie->u.rej.reason) {
1274                   default:
1275                         return (-1);
1276
1277                   case UNI_CAUSE_REASON_USER:
1278                         switch (ie->h.present & mask) {
1279                           default:
1280                                 return (-1);
1281
1282                           case UNI_CAUSE_REJ_P:
1283                           case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_USER_P:
1284                                 break;
1285                         }
1286                         break;
1287
1288                   case UNI_CAUSE_REASON_IEMISS:
1289                   case UNI_CAUSE_REASON_IESUFF:
1290                         switch (ie->h.present & mask) {
1291                           default:
1292                                 return (-1);
1293
1294                           case UNI_CAUSE_REJ_P:
1295                           case UNI_CAUSE_REJ_P | UNI_CAUSE_REJ_IE_P:
1296                                 break;
1297                         }
1298                         break;
1299                 }
1300         }
1301         if (ie->h.present & UNI_CAUSE_IE_P) {
1302                 if (ie->u.ie.len == 0 || ie->u.ie.len > UNI_CAUSE_IE_N)
1303                         return (-1);
1304         }
1305         if (ie->h.present & UNI_CAUSE_TRAFFIC_P) {
1306                 if (ie->u.traffic.len == 0 ||
1307                     ie->u.traffic.len > UNI_CAUSE_TRAFFIC_N)
1308                         return (-1);
1309         }
1310
1311         if (ie->h.present & UNI_CAUSE_TNS_P) {
1312                 if (uni_check_ie(UNI_IE_TNS, (union uni_ieall *)&ie->u.tns, cx))
1313                         return (-1);
1314         }
1315         if (ie->h.present & UNI_CAUSE_NUMBER_P) {
1316                 if(uni_check_ie(UNI_IE_CALLED, (union uni_ieall *)&ie->u.number, cx))
1317                         return (-1);
1318         }
1319         if (ie->h.present & UNI_CAUSE_ATTR_P) {
1320                 if(ie->u.attr.nattr > UNI_CAUSE_ATTR_N || ie->u.attr.nattr == 0)
1321                         return (-1);
1322         }
1323         if (ie->h.present & UNI_CAUSE_PARAM_P) {
1324                 cx = cx;
1325         }
1326
1327         return (0);
1328 }
1329
1330 DEF_IE_CHECK(itu, cause)
1331 {
1332         return (check_cause(ie, cx, itu_causes, NULL));
1333 }
1334 DEF_IE_CHECK(net, cause)
1335 {
1336         return (check_cause(ie, cx, net_causes, itu_causes));
1337 }
1338 /**********************************************************************/
1339
1340 static int
1341 encode_cause(struct uni_msg *msg, struct uni_ie_cause *ie, struct unicx *cx)
1342 {
1343         u_int i;
1344
1345         START_IE(cause, UNI_IE_CAUSE, 30);
1346
1347         if (IE_ISERROR(*ie)) {
1348                 APP_BYTE(msg, 0x00 | ie->loc);
1349         } else {
1350                 APP_BYTE(msg, 0x80 | ie->loc);
1351         }
1352         APP_BYTE(msg, 0x80 | ie->cause);
1353
1354         if (ie->h.present & UNI_CAUSE_COND_P)
1355                 APP_BYTE(msg, 0x80 | (ie->u.cond.pu << 3) |
1356                     (ie->u.cond.na << 2) | ie->u.cond.cond);
1357
1358         else if (ie->h.present & UNI_CAUSE_REJ_P) {
1359                 APP_BYTE(msg, 0x80 | (ie->u.rej.reason << 2) | ie->u.rej.cond);
1360                 if (ie->h.present & UNI_CAUSE_REJ_USER_P)
1361                         APP_BYTE(msg, ie->u.rej.user);
1362                 else if (ie->h.present & UNI_CAUSE_REJ_IE_P)
1363                         APP_BYTE(msg, ie->u.rej.ie);
1364
1365         } else if(ie->h.present & UNI_CAUSE_IE_P)
1366                 APP_BUF(msg, ie->u.ie.ie, ie->u.ie.len);
1367
1368         else if (ie->h.present & UNI_CAUSE_TRAFFIC_P)
1369                 APP_BUF(msg, ie->u.traffic.traffic, ie->u.traffic.len);
1370
1371         else if (ie->h.present & UNI_CAUSE_VPCI_P) {
1372                 APP_BYTE(msg, (ie->u.vpci.vpci >> 8));
1373                 APP_BYTE(msg, (ie->u.vpci.vpci >> 0));
1374                 APP_BYTE(msg, (ie->u.vpci.vci >> 8));
1375                 APP_BYTE(msg, (ie->u.vpci.vci >> 0));
1376
1377         } else if (ie->h.present & UNI_CAUSE_MTYPE_P)
1378                 APP_BYTE(msg, ie->u.mtype);
1379
1380         else if (ie->h.present & UNI_CAUSE_TIMER_P) {
1381                 APP_BYTE(msg, ie->u.timer[0]);
1382                 APP_BYTE(msg, ie->u.timer[1]);
1383                 APP_BYTE(msg, ie->u.timer[2]);
1384
1385         } else if (ie->h.present & UNI_CAUSE_TNS_P)
1386                 uni_encode_ie(UNI_IE_TNS, msg,
1387                     (union uni_ieall *)&ie->u.tns, cx);
1388
1389         else if (ie->h.present & UNI_CAUSE_NUMBER_P)
1390                 uni_encode_ie(UNI_IE_CALLED, msg,
1391                     (union uni_ieall *)&ie->u.number, cx);
1392
1393         else if (ie->h.present & UNI_CAUSE_ATTR_P) {
1394                 for (i = 0; i < ie->u.attr.nattr; i++) {
1395                         APP_BYTE(msg, ie->u.attr.attr[i][0]);
1396                         if (!ie->u.attr.attr[i][0]) {
1397                                 APP_BYTE(msg, ie->u.attr.attr[i][1]);
1398                                 if (!ie->u.attr.attr[i][1])
1399                                         APP_BYTE(msg, ie->u.attr.attr[i][2]);
1400                         }
1401                 }
1402         } else if (ie->h.present & UNI_CAUSE_PARAM_P)
1403                 APP_BYTE(msg, ie->u.param);
1404
1405         SET_IE_LEN(msg);
1406
1407         return (0);
1408 }
1409
1410 DEF_IE_ENCODE(itu, cause)
1411 {
1412         return encode_cause(msg, ie, cx);
1413 }
1414 DEF_IE_ENCODE(net, cause)
1415 {
1416         return encode_cause(msg, ie, cx);
1417 }
1418
1419 /**********************************************************************/
1420
1421 static int
1422 decode_cause(struct uni_ie_cause *ie, struct uni_msg *msg, u_int ielen,
1423     struct unicx *cx, const struct causetab *tab1, const struct causetab *tab2)
1424 {
1425         u_char c;
1426         const struct causetab *ptr;
1427         enum uni_ietype ietype;
1428         u_int xielen;
1429
1430         IE_START(;);
1431
1432         if(ielen < 2 || ielen > 30)
1433                 goto rej;
1434
1435         c = *msg->b_rptr++;
1436         ielen--;
1437         if(!(c & 0x80))
1438                 goto rej;
1439         ie->loc = c & 0xf;
1440
1441         c = *msg->b_rptr++;
1442         ielen--;
1443         if(!(c & 0x80))
1444                 goto rej;
1445         ie->cause = c & 0x7f;
1446
1447         if(tab1[ie->cause].str != NULL)
1448                 ptr = &tab1[ie->cause];
1449         else if(tab2 != NULL && tab2[ie->cause].str != NULL)
1450                 ptr = &tab2[ie->cause];
1451         else {
1452                 ptr = NULL;
1453                 ielen = 0;      /* ignore diags */
1454         }
1455
1456         if(ielen) {
1457                 switch(ptr->diag) {
1458
1459                   case UNI_DIAG_NONE:
1460                         break;
1461
1462                   case UNI_DIAG_COND:
1463                         if(ielen < 1)
1464                                 goto rej;
1465                         c = *msg->b_rptr++;
1466                         ielen--;
1467
1468                         ie->h.present |= UNI_CAUSE_COND_P;
1469                         ie->u.cond.pu = (c >> 3) & 1;
1470                         ie->u.cond.na = (c >> 2) & 1;
1471                         ie->u.cond.cond = c & 3;
1472
1473                         if(!(c & 0x80))
1474                                 goto rej;
1475                         break;
1476
1477                   case UNI_DIAG_REJ:
1478                         if(ielen < 1)
1479                                 goto rej;
1480                         c = *msg->b_rptr++;
1481                         ielen--;
1482
1483                         ie->h.present |= UNI_CAUSE_REJ_P;
1484                         ie->u.rej.reason = (c >> 2) & 0x1f;
1485                         ie->u.rej.cond = c & 3;
1486
1487                         if(!(c & 0x80))
1488                                 goto rej;
1489
1490                         if(ielen > 0) {
1491                                 c = *msg->b_rptr++;
1492                                 ielen--;
1493
1494                                 switch(ie->u.rej.reason) {
1495
1496                                   case UNI_CAUSE_REASON_USER:
1497                                         ie->h.present |= UNI_CAUSE_REJ_USER_P;
1498                                         ie->u.rej.user = c;
1499                                         break;
1500
1501                                   case UNI_CAUSE_REASON_IEMISS:
1502                                   case UNI_CAUSE_REASON_IESUFF:
1503                                         ie->h.present |= UNI_CAUSE_REJ_IE_P;
1504                                         ie->u.rej.ie = c;
1505                                         break;
1506                                 }
1507                         }
1508                         break;
1509
1510                   case UNI_DIAG_CRATE:
1511                         ie->h.present |= UNI_CAUSE_TRAFFIC_P;
1512                         while(ielen && ie->u.traffic.len < UNI_CAUSE_TRAFFIC_N) {
1513                                 ie->u.traffic.traffic[ie->u.traffic.len++] =
1514                                         *msg->b_rptr++;
1515                                 ielen--;
1516                         }
1517                         break;
1518
1519                   case UNI_DIAG_IE:
1520                         ie->h.present |= UNI_CAUSE_IE_P;
1521                         while(ielen && ie->u.ie.len < UNI_CAUSE_IE_N) {
1522                                 ie->u.ie.ie[ie->u.ie.len++] = *msg->b_rptr++;
1523                                 ielen--;
1524                         }
1525                         break;
1526
1527                   case UNI_DIAG_CHANID:
1528                         if(ielen < 4)
1529                                 break;
1530                         ie->h.present |= UNI_CAUSE_VPCI_P;
1531                         ie->u.vpci.vpci  = *msg->b_rptr++ << 8;
1532                         ie->u.vpci.vpci |= *msg->b_rptr++;
1533                         ie->u.vpci.vci  = *msg->b_rptr++ << 8;
1534                         ie->u.vpci.vci |= *msg->b_rptr++;
1535                         ielen -= 4;
1536                         break;
1537
1538                   case UNI_DIAG_MTYPE:
1539                         ie->h.present |= UNI_CAUSE_MTYPE_P;
1540                         ie->u.mtype = *msg->b_rptr++;
1541                         ielen--;
1542                         break;
1543
1544                   case UNI_DIAG_TIMER:
1545                         if(ielen < 3)
1546                                 break;
1547                         ie->h.present |= UNI_CAUSE_TIMER_P;
1548                         ie->u.timer[0] = *msg->b_rptr++;
1549                         ie->u.timer[1] = *msg->b_rptr++;
1550                         ie->u.timer[2] = *msg->b_rptr++;
1551                         ielen -= 3;
1552                         break;
1553
1554                   case UNI_DIAG_TNS:
1555                         if(ielen < 4)
1556                                 break;
1557                         if(uni_decode_ie_hdr(&ietype, &ie->u.tns.h, msg, cx, &xielen))
1558                                 break;
1559                         if(ietype != UNI_IE_TNS)
1560                                 break;
1561                         if(uni_decode_ie_body(ietype,
1562                             (union uni_ieall *)&ie->u.tns, msg, xielen, cx))
1563                                 break;
1564                         ie->h.present |= UNI_CAUSE_TNS_P;
1565                         break;
1566
1567                   case UNI_DIAG_NUMBER:
1568                         if(ielen < 4)
1569                                 break;
1570                         if(uni_decode_ie_hdr(&ietype, &ie->u.number.h, msg, cx, &xielen))
1571                                 break;
1572                         if(ietype != UNI_IE_CALLED)
1573                                 break;
1574                         if(uni_decode_ie_body(ietype,
1575                             (union uni_ieall *)&ie->u.number, msg, xielen, cx))
1576                                 break;
1577                         ie->h.present |= UNI_CAUSE_NUMBER_P;
1578                         break;
1579
1580                   case UNI_DIAG_ATTR:
1581                         ie->h.present |= UNI_CAUSE_ATTR_P;
1582                         while(ielen > 0 && ie->u.attr.nattr < UNI_CAUSE_ATTR_N) {
1583                                 c = *msg->b_rptr++;
1584                                 ie->u.attr.attr[ie->u.attr.nattr][0] = c;
1585                                 ielen--;
1586                                 if(ielen > 0 && !(c & 0x80)) {
1587                                         c = *msg->b_rptr++;
1588                                         ie->u.attr.attr[ie->u.attr.nattr][1] = c;
1589                                         ielen--;
1590                                         if(ielen > 0 && !(c & 0x80)) {
1591                                                 c = *msg->b_rptr++;
1592                                                 ie->u.attr.attr[ie->u.attr.nattr][2] = c;
1593                                                 ielen--;
1594                                         }
1595                                 }
1596                         }
1597                         break;
1598
1599                   case UNI_DIAG_PARAM:
1600                         ie->h.present |= UNI_CAUSE_PARAM_P;
1601                         ie->u.param = *msg->b_rptr++;
1602                         ielen--;
1603                         break;
1604                 }
1605         }
1606
1607         IE_END(CAUSE);
1608 }
1609
1610 DEF_IE_DECODE(itu, cause)
1611 {
1612         return decode_cause(ie, msg, ielen, cx, itu_causes, NULL);
1613 }
1614 DEF_IE_DECODE(net, cause)
1615 {
1616         return decode_cause(ie, msg, ielen, cx, net_causes, itu_causes);
1617 }
1618
1619 /*********************************************************************
1620  *
1621  * Callstate
1622  *
1623  * References for this IE are:
1624  *
1625  *  Q.2931 pp. 59...60
1626  *  UNI4.0 pp. 14
1627  *
1628  * Only ITU-T coding allowed.
1629  */
1630 DEF_IE_PRINT(itu, callstate)
1631 {
1632         static const struct uni_print_tbl tbl[] = {
1633                 MKT(UNI_CALLSTATE_U0,   U0/N0/REST0),
1634                 MKT(UNI_CALLSTATE_U1,   U1/N1),
1635                 MKT(UNI_CALLSTATE_U3,   U3/N3),
1636                 MKT(UNI_CALLSTATE_U4,   U4/N4),
1637                 MKT(UNI_CALLSTATE_U6,   U6/N6),
1638                 MKT(UNI_CALLSTATE_U7,   U7/N7),
1639                 MKT(UNI_CALLSTATE_U8,   U8/N8),
1640                 MKT(UNI_CALLSTATE_U9,   U9/N9),
1641                 MKT(UNI_CALLSTATE_U10,  U10/N10),
1642                 MKT(UNI_CALLSTATE_U11,  U11/N11),
1643                 MKT(UNI_CALLSTATE_U12,  U12/N12),
1644                 MKT(UNI_CALLSTATE_REST1,REST1),
1645                 MKT(UNI_CALLSTATE_REST2,REST2),
1646                 MKT(UNI_CALLSTATE_U13,  U13/N13),
1647                 MKT(UNI_CALLSTATE_U14,  U14/N14),
1648                 EOT()
1649         };
1650
1651         if(uni_print_iehdr("callstate", &ie->h, cx))
1652                 return;
1653         uni_print_tbl("state", ie->state, tbl, cx);
1654         uni_print_ieend(cx);
1655 }
1656
1657 DEF_IE_CHECK(itu, callstate)
1658 {
1659         cx = cx;
1660
1661         switch(ie->state) {
1662           default:
1663                 return -1;
1664
1665           case UNI_CALLSTATE_U0:
1666           case UNI_CALLSTATE_U1:
1667           case UNI_CALLSTATE_U3:
1668           case UNI_CALLSTATE_U4:
1669           case UNI_CALLSTATE_U6:
1670           case UNI_CALLSTATE_U7:
1671           case UNI_CALLSTATE_U8:
1672           case UNI_CALLSTATE_U9:
1673           case UNI_CALLSTATE_U10:
1674           case UNI_CALLSTATE_U11:
1675           case UNI_CALLSTATE_U12:
1676           case UNI_CALLSTATE_REST1:
1677           case UNI_CALLSTATE_REST2:
1678           case UNI_CALLSTATE_U13:
1679           case UNI_CALLSTATE_U14:
1680                 break;
1681         }
1682
1683         return 0;
1684 }
1685
1686 DEF_IE_ENCODE(itu, callstate)
1687 {
1688         START_IE(callstate, UNI_IE_CALLSTATE, 1);
1689
1690         APP_BYTE(msg, ie->state);
1691
1692         SET_IE_LEN(msg);
1693         return 0;
1694 }
1695
1696 DEF_IE_DECODE(itu, callstate)
1697 {
1698         IE_START(;);
1699
1700         if(ielen != 1)
1701                 goto rej;
1702
1703         ie->state = *msg->b_rptr++ & 0x3f;
1704         ielen--;
1705
1706         IE_END(CALLSTATE);
1707 }
1708
1709 /*********************************************************************
1710  *
1711  * Facility Information.
1712  *
1713  * References for this IE are:
1714  *
1715  *  Q.2932.1
1716  *
1717  * The standard allows only ROSE as protocol. We allow everything up to the
1718  * maximum size.
1719  *
1720  * Only ITU-T coding allowed.
1721  */
1722 DEF_IE_PRINT(itu, facility)
1723 {
1724         u_int i;
1725
1726         if(uni_print_iehdr("facility", &ie->h, cx))
1727                 return;
1728
1729         if(ie->proto == UNI_FACILITY_ROSE)
1730                 uni_print_entry(cx, "proto", "rose");
1731         else
1732                 uni_print_entry(cx, "proto", "0x%02x", ie->proto);
1733
1734         uni_print_entry(cx, "len", "%u", ie->len);
1735         uni_print_entry(cx, "info", "(");
1736         for(i = 0; i < ie->len; i++)
1737                 uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->apdu[i]);
1738         uni_printf(cx, ")");
1739
1740         uni_print_ieend(cx);
1741 }
1742
1743 DEF_IE_CHECK(itu, facility)
1744 {
1745         cx = cx;
1746
1747         if(ie->len > UNI_FACILITY_MAXAPDU)
1748                 return -1;
1749
1750         return 0;
1751 }
1752
1753 DEF_IE_ENCODE(itu, facility)
1754 {
1755         START_IE(facility, UNI_IE_FACILITY, 1 + ie->len);
1756
1757         APP_BYTE(msg, ie->proto | 0x80);
1758         APP_BUF(msg, ie->apdu, ie->len);
1759
1760         SET_IE_LEN(msg);
1761         return 0;
1762 }
1763
1764 DEF_IE_DECODE(itu, facility)
1765 {
1766         u_char c;
1767
1768         IE_START(;);
1769
1770         if(ielen > UNI_FACILITY_MAXAPDU + 1 || ielen < 1)
1771                 goto rej;
1772
1773         ie->proto = (c = *msg->b_rptr++) & 0x1f;
1774         ielen--;
1775         if((c & 0xe0) != 0x80)
1776                 goto rej;
1777
1778         ie->len = ielen;
1779         ielen = 0;
1780         (void)memcpy(ie->apdu, msg->b_rptr, ie->len);
1781         msg->b_rptr += ie->len;
1782
1783         IE_END(FACILITY);
1784 }
1785
1786 /*********************************************************************
1787  *
1788  * Notification Indicator
1789  *
1790  * References for this IE are:
1791  *
1792  *  Q.2931 p.  76
1793  *  UNI4.0 p.  17
1794  *
1795  * Only ITU-T coding allowed.
1796  */
1797
1798 DEF_IE_PRINT(itu, notify)
1799 {
1800         u_int i;
1801
1802         if(uni_print_iehdr("notify", &ie->h, cx))
1803                 return;
1804         uni_print_entry(cx, "len", "%u", ie->len);
1805         uni_print_entry(cx, "info", "(");
1806         for(i = 0; i < ie->len; i++)
1807                 uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->notify[i]);
1808         uni_printf(cx, ")");
1809         uni_print_ieend(cx);
1810 }
1811
1812 DEF_IE_CHECK(itu, notify)
1813 {
1814         cx = cx;
1815
1816         if(ie->len > UNI_NOTIFY_MAXLEN)
1817                 return -1;
1818
1819         return 0;
1820 }
1821
1822 DEF_IE_ENCODE(itu, notify)
1823 {
1824         START_IE(notify, UNI_IE_NOTIFY, ie->len);
1825
1826         APP_BUF(msg, ie->notify, ie->len);
1827         if (IE_ISERROR(*ie)) {
1828                 /* make it too long */
1829                 u_int i = ie->len;
1830
1831                 while (i < UNI_NOTIFY_MAXLEN + 1) {
1832                         APP_BYTE(msg, 0x00);
1833                         i++;
1834                 }
1835         }
1836
1837         SET_IE_LEN(msg);
1838         return (0);
1839 }
1840
1841 DEF_IE_DECODE(itu, notify)
1842 {
1843         IE_START(;);
1844
1845         if (ielen > UNI_NOTIFY_MAXLEN || ielen < 1)
1846                 goto rej;
1847
1848         ie->len = ielen;
1849         ielen = 0;
1850         (void)memcpy(ie->notify, msg->b_rptr, ie->len);
1851         msg->b_rptr += ie->len;
1852
1853         IE_END(NOTIFY);
1854 }
1855
1856 /*********************************************************************
1857  *
1858  * End-to-end transit delay.
1859  *
1860  * References for this IE are:
1861  *
1862  *  Q.2931 pp. 70...71
1863  *  UNI4.0 pp. 69...70
1864  *  PNNI1.0 pp. 198...200
1865  *
1866  * Not clear, whether the new indicator should be used with NET coding or
1867  * not.
1868  *
1869  * Only ITU-T coding allowed.
1870  */
1871
1872 static void
1873 print_eetd(struct uni_ie_eetd *ie, struct unicx *cx)
1874 {
1875         if (uni_print_iehdr("eetd", &ie->h, cx))
1876                 return;
1877
1878         if (ie->h.present & UNI_EETD_CUM_P)
1879                 uni_print_entry(cx, "cum", "%u", ie->cumulative);
1880         if (ie->h.present & UNI_EETD_MAX_P) {
1881                 if (ie->maximum == UNI_EETD_ANYMAX)
1882                         uni_print_entry(cx, "max", "any");
1883                 else
1884                         uni_print_entry(cx, "max", "%u", ie->maximum);
1885         }
1886         if (ie->h.present & UNI_EETD_PCTD_P)
1887                 uni_print_entry(cx, "pnni_cum", "%u", ie->pctd);
1888         if (ie->h.present & UNI_EETD_PMTD_P)
1889                 uni_print_entry(cx, "pnni_max", "%u", ie->pmtd);
1890         if (ie->h.present & UNI_EETD_NET_P)
1891                 uni_print_flag("netgen", cx);
1892
1893         uni_print_ieend(cx);
1894 }
1895 DEF_IE_PRINT(itu, eetd)
1896 {
1897         print_eetd(ie, cx);
1898 }
1899 DEF_IE_PRINT(net, eetd)
1900 {
1901         print_eetd(ie, cx);
1902 }
1903
1904 DEF_IE_CHECK(itu, eetd)
1905 {
1906
1907         cx = cx;
1908
1909         if (!(ie->h.present & UNI_EETD_CUM_P))
1910                 return (-1);
1911         if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P))
1912                 return (-1);
1913         return (0);
1914 }
1915
1916 DEF_IE_CHECK(net, eetd)
1917 {
1918
1919         if (!cx->pnni) {
1920                 if (!(ie->h.present & UNI_EETD_CUM_P))
1921                         return (-1);
1922                 if (ie->h.present & (UNI_EETD_PMTD_P | UNI_EETD_PCTD_P))
1923                         return (-1);
1924         } else {
1925                 if (ie->h.present & UNI_EETD_MAX_P)
1926                         return (-1);
1927                 if ((ie->h.present & UNI_EETD_CUM_P) &&
1928                     (ie->h.present & UNI_EETD_PCTD_P))
1929                         return (-1);
1930         }
1931         return (0);
1932 }
1933
1934 DEF_IE_ENCODE(itu, eetd)
1935 {
1936         START_IE(eetd, UNI_IE_EETD, 9);
1937
1938         if (ie->h.present & UNI_EETD_CUM_P) {
1939                 APP_BYTE(msg, UNI_EETD_CTD_ID);
1940                 APP_16BIT(msg, ie->cumulative);
1941         }
1942         if (ie->h.present & UNI_EETD_MAX_P) {
1943                 APP_BYTE(msg, UNI_EETD_MTD_ID);
1944                 APP_16BIT(msg, ie->maximum);
1945         }
1946         if (ie->h.present & UNI_EETD_PMTD_P) {
1947                 APP_BYTE(msg, UNI_EETD_PMTD_ID);
1948                 APP_24BIT(msg, ie->pmtd);
1949         }
1950         if (ie->h.present & UNI_EETD_PCTD_P) {
1951                 APP_BYTE(msg, UNI_EETD_PCTD_ID);
1952                 APP_24BIT(msg, ie->pctd);
1953         }
1954         if (ie->h.present & UNI_EETD_NET_P) {
1955                 APP_BYTE(msg, UNI_EETD_NET_ID);
1956         }
1957
1958         SET_IE_LEN(msg);
1959         return (0);
1960 }
1961
1962 DEF_IE_ENCODE(net, eetd)
1963 {
1964         return (uni_ie_encode_itu_eetd(msg, ie, cx));
1965 }
1966
1967 DEF_IE_DECODE(itu, eetd)
1968 {
1969         IE_START(;);
1970
1971         while (ielen > 0) {
1972                 switch (ielen--, *msg->b_rptr++) {
1973
1974                   case UNI_EETD_CTD_ID:
1975                         if (ielen < 2)
1976                                 goto rej;
1977                         ie->h.present |= UNI_EETD_CUM_P;
1978                         ie->cumulative = *msg->b_rptr++ << 8;
1979                         ie->cumulative |= *msg->b_rptr++;
1980                         ielen -= 2;
1981                         break;
1982
1983                   case UNI_EETD_MTD_ID:
1984                         if (ielen < 2)
1985                                 goto rej;
1986                         ie->h.present |= UNI_EETD_MAX_P;
1987                         ie->maximum = *msg->b_rptr++ << 8;
1988                         ie->maximum |= *msg->b_rptr++;
1989                         ielen -= 2;
1990                         break;
1991
1992                   case UNI_EETD_PCTD_ID:
1993                         if (ielen < 3)
1994                                 goto rej;
1995                         ie->h.present |= UNI_EETD_PCTD_P;
1996                         ie->pctd = *msg->b_rptr++ << 16;
1997                         ie->pctd |= *msg->b_rptr++ << 8;
1998                         ie->pctd |= *msg->b_rptr++;
1999                         ielen -= 3;
2000                         break;
2001
2002                   case UNI_EETD_PMTD_ID:
2003                         if (ielen < 3)
2004                                 goto rej;
2005                         ie->h.present |= UNI_EETD_PMTD_P;
2006                         ie->pmtd = *msg->b_rptr++ << 16;
2007                         ie->pmtd |= *msg->b_rptr++ << 8;
2008                         ie->pmtd |= *msg->b_rptr++;
2009                         ielen -= 3;
2010                         break;
2011
2012                   case UNI_EETD_NET_ID:
2013                         ie->h.present |= UNI_EETD_NET_P;
2014                         break;
2015
2016                   default:
2017                         goto rej;
2018                 }
2019         }
2020
2021         IE_END(EETD);
2022 }
2023 DEF_IE_DECODE(net, eetd)
2024 {
2025         return (uni_ie_decode_itu_eetd(ie, msg, ielen, cx));
2026 }
2027
2028 /*********************************************************************
2029  *
2030  * Called address
2031  * Called subaddress
2032  * Calling address
2033  * Calling subaddress
2034  * Connected address
2035  * Connected subaddress
2036  *
2037  * References for this IE are:
2038  *
2039  *  Q.2931 pp. 60...68
2040  *  ...A4  pp. 27...36
2041  *  UNI4.0 pp. 14...15
2042  *  Q.2951 pp. 28...40
2043  *
2044  * It is assumed, that the coding of the addr arrays is ok.
2045  *
2046  * Only ITU-T coding allowed.
2047  */
2048
2049 static const struct uni_print_tbl screen_tbl[] = {
2050         MKT(UNI_ADDR_SCREEN_NOT,        no),
2051         MKT(UNI_ADDR_SCREEN_PASSED,     passed),
2052         MKT(UNI_ADDR_SCREEN_FAILED,     failed),
2053         MKT(UNI_ADDR_SCREEN_NET,        network),
2054         EOT()
2055 };
2056 static const struct uni_print_tbl pres_tbl[] = {
2057         MKT(UNI_ADDR_PRES,              allowed),
2058         MKT(UNI_ADDR_RESTRICT,          restricted),
2059         MKT(UNI_ADDR_NONUMBER,          no-number),
2060         EOT()
2061 };
2062
2063
2064 static void
2065 print_addr(struct unicx *cx, struct uni_addr *addr)
2066 {
2067         static const struct uni_print_tbl plan_tbl[] = {
2068                 MKT(UNI_ADDR_UNKNOWN,   unknown),
2069                 MKT(UNI_ADDR_E164,      E164),
2070                 MKT(UNI_ADDR_ATME,      ATME),
2071                 MKT(UNI_ADDR_DATA,      data),
2072                 MKT(UNI_ADDR_PRIVATE,   private),
2073                 EOT()
2074         };
2075         static const struct uni_print_tbl type_tbl[] = {
2076                 MKT(UNI_ADDR_UNKNOWN,           unknown),
2077                 MKT(UNI_ADDR_INTERNATIONAL,     international),
2078                 MKT(UNI_ADDR_NATIONAL,          national),
2079                 MKT(UNI_ADDR_NETWORK,           network),
2080                 MKT(UNI_ADDR_SUBSCR,            subscriber),
2081                 MKT(UNI_ADDR_ABBR,              abbreviated),
2082                 EOT()
2083         };
2084         u_int i;
2085
2086         uni_print_entry(cx, "addr", "(");
2087         uni_print_tbl(NULL, addr->type, type_tbl, cx);
2088         uni_putc(',', cx);
2089         uni_print_tbl(NULL, addr->plan, plan_tbl, cx);
2090         uni_putc(',', cx);
2091         if(addr->plan == UNI_ADDR_E164) {
2092                 uni_putc('"', cx);
2093                 for(i = 0; i < addr->len; i++) {
2094                         if(addr->addr[i] < ' ')
2095                                 uni_printf(cx, "^%c", addr->addr[i] + '@');
2096                         else if(addr->addr[i] <= '~')
2097                                 uni_putc(addr->addr[i], cx);
2098                         else
2099                                 uni_printf(cx, "\\%03o", addr->addr[i]);
2100                 }
2101                 uni_putc('"', cx);
2102
2103         } else if(addr->plan == UNI_ADDR_ATME) {
2104                 for(i = 0; i < addr->len; i++)
2105                         uni_printf(cx, "%02x", addr->addr[i]);
2106         }
2107         uni_putc(')', cx);
2108 }
2109
2110 static void
2111 print_addrsub(struct unicx *cx, struct uni_subaddr *addr)
2112 {
2113         static const struct uni_print_tbl type_tbl[] = {
2114                 MKT(UNI_SUBADDR_NSAP,   NSAP),
2115                 MKT(UNI_SUBADDR_ATME,   ATME),
2116                 MKT(UNI_SUBADDR_USER,   USER),
2117                 EOT()
2118         };
2119         u_int i;
2120
2121         uni_print_entry(cx, "addr", "(");
2122         uni_print_tbl(NULL, addr->type, type_tbl, cx);
2123         uni_putc(',', cx);
2124
2125         for(i = 0; i < addr->len; i++)
2126                 uni_printf(cx, "%02x", addr->addr[i]);
2127
2128         uni_putc(')', cx);
2129 }
2130
2131 static int
2132 check_addr(struct uni_addr *addr)
2133 {
2134         u_int i;
2135
2136         switch(addr->plan) {
2137           default:
2138                 return -1;
2139
2140           case UNI_ADDR_E164:
2141                 if(addr->type != UNI_ADDR_INTERNATIONAL)
2142                         return -1;
2143                 if(addr->len > 15 || addr->len == 0)
2144                         return -1;
2145                 for(i = 0; i < addr->len; i++)
2146                         if(addr->addr[i] == 0 || (addr->addr[i] & 0x80))
2147                                 return -1;
2148                 break;
2149
2150           case UNI_ADDR_ATME:
2151                 if(addr->type != UNI_ADDR_UNKNOWN)
2152                         return -1;
2153                 if(addr->len != 20)
2154                         return -1;
2155                 break;
2156         }
2157
2158         return 0;
2159 }
2160
2161 static int
2162 check_subaddr(struct uni_subaddr *addr)
2163 {
2164         switch(addr->type) {
2165           default:
2166                 return -1;
2167
2168           case UNI_SUBADDR_NSAP:
2169                 if(addr->len != 20)
2170                         return -1;
2171                 break;
2172
2173           case UNI_SUBADDR_ATME:
2174                 if(addr->len > 20)
2175                         return -1;
2176                 break;
2177         }
2178         return 0;
2179 }
2180
2181 static int
2182 check_screen(enum uni_addr_screen screen, enum uni_addr_pres pres)
2183 {
2184         switch(pres) {
2185           default:
2186                 return -1;
2187
2188           case UNI_ADDR_PRES:
2189           case UNI_ADDR_RESTRICT:
2190           case UNI_ADDR_NONUMBER:
2191                 break;
2192         }
2193         switch(screen) {
2194           default:
2195                 return -1;
2196
2197           case UNI_ADDR_SCREEN_NOT:
2198           case UNI_ADDR_SCREEN_PASSED:
2199           case UNI_ADDR_SCREEN_FAILED:
2200           case UNI_ADDR_SCREEN_NET:
2201                 break;
2202         }
2203
2204         return 0;
2205 }
2206
2207 static void
2208 encode_addr(struct uni_msg *msg, struct uni_addr *addr, u_int flag,
2209     enum uni_addr_screen screen, enum uni_addr_pres pres, int err)
2210 {
2211         u_char ext = err ? 0x00 : 0x80;
2212
2213         if (flag) {
2214                 APP_BYTE(msg, (addr->type << 4) | addr->plan);
2215                 APP_BYTE(msg, ext | (pres << 5) | (screen));
2216         } else {
2217                 APP_BYTE(msg, ext | (addr->type << 4) | addr->plan);
2218         }
2219         APP_BUF(msg, addr->addr, addr->len);
2220 }
2221
2222 static void
2223 encode_subaddr(struct uni_msg *msg, struct uni_subaddr *addr)
2224 {
2225         APP_BYTE(msg, 0x80|(addr->type<<4));
2226         APP_BUF(msg, addr->addr, addr->len);
2227 }
2228
2229 static int
2230 decode_addr(struct uni_addr *addr, u_int ielen, struct uni_msg *msg, u_int plan)
2231 {
2232         addr->plan = plan & 0xf;
2233         addr->type = (plan >> 4) & 0x7;
2234
2235         switch(addr->plan) {
2236
2237           case UNI_ADDR_E164:
2238                 if(ielen > 15 || ielen == 0)
2239                         return -1;
2240                 addr->addr[ielen] = 0;
2241                 break;
2242
2243           case UNI_ADDR_ATME:
2244                 if(ielen != 20)
2245                         return -1;
2246                 break;
2247
2248           default:
2249                 return -1;
2250         }
2251         (void)memcpy(addr->addr, msg->b_rptr, ielen);
2252         addr->len = ielen;
2253         msg->b_rptr += ielen;
2254
2255         return 0;
2256 }
2257
2258 static int
2259 decode_subaddr(struct uni_subaddr *addr, u_int ielen, struct uni_msg *msg,
2260     u_int type)
2261 {
2262         switch(addr->type = (type >> 4) & 0x7) {
2263
2264           case UNI_SUBADDR_NSAP:
2265                 if(ielen == 0 || ielen > 20)
2266                         return -1;
2267                 break;
2268
2269           case UNI_SUBADDR_ATME:
2270                 if(ielen != 20)
2271                         return -1;
2272                 break;
2273
2274           default:
2275                 return -1;
2276         }
2277         if(!(type & 0x80))
2278                 return -1;
2279         if((type & 0x7) != 0)
2280                 return -1;
2281
2282         addr->len = ielen;
2283         (void)memcpy(addr->addr, msg->b_rptr, ielen);
2284         msg->b_rptr += ielen;
2285
2286         return 0;
2287 }
2288
2289 /**********************************************************************/
2290
2291 DEF_IE_PRINT(itu, called)
2292 {
2293         if (uni_print_iehdr("called", &ie->h, cx))
2294                 return;
2295         print_addr(cx, &ie->addr);
2296         uni_print_ieend(cx);
2297 }
2298
2299 DEF_IE_CHECK(itu, called)
2300 {
2301         cx = cx;
2302
2303         if (check_addr(&ie->addr))
2304                 return (-1);
2305         return (0);
2306 }
2307
2308 DEF_IE_ENCODE(itu, called)
2309 {
2310         START_IE(called, UNI_IE_CALLED, 21);
2311         encode_addr(msg, &ie->addr, 0, 0, 0, IE_ISERROR(*ie));
2312         SET_IE_LEN(msg);
2313         return (0);
2314 }
2315
2316 DEF_IE_DECODE(itu, called)
2317 {
2318         u_char c;
2319         IE_START(;);
2320
2321         if (ielen > 21 || ielen < 1)
2322                 goto rej;
2323
2324         c = *msg->b_rptr++;
2325         ielen--;
2326
2327         if (!(c & 0x80))
2328                 goto rej;
2329
2330         if (decode_addr(&ie->addr, ielen, msg, c))
2331                 goto rej;
2332
2333         IE_END(CALLED);
2334 }
2335
2336 /**********************************************************************/
2337
2338 DEF_IE_PRINT(itu, calledsub)
2339 {
2340         if(uni_print_iehdr("calledsub", &ie->h, cx))
2341                 return;
2342         print_addrsub(cx, &ie->addr);
2343         uni_print_ieend(cx);
2344 }
2345
2346 DEF_IE_CHECK(itu, calledsub)
2347 {
2348         cx = cx;
2349
2350         if(check_subaddr(&ie->addr))
2351                 return -1;
2352         return 0;
2353 }
2354
2355 DEF_IE_ENCODE(itu, calledsub)
2356 {
2357         START_IE(calledsub, UNI_IE_CALLEDSUB, 21);
2358         encode_subaddr(msg, &ie->addr);
2359         SET_IE_LEN(msg);
2360         return 0;
2361 }
2362
2363 DEF_IE_DECODE(itu, calledsub)
2364 {
2365         u_char c;
2366
2367         IE_START(;);
2368
2369         if(ielen > 21)
2370                 goto rej;
2371
2372         c = *msg->b_rptr++;
2373         ielen--;
2374
2375         if(decode_subaddr(&ie->addr, ielen, msg, c))
2376                 goto rej;
2377
2378         IE_END(CALLEDSUB);
2379 }
2380
2381 /**********************************************************************/
2382
2383 DEF_IE_PRINT(itu, calling)
2384 {
2385         if(uni_print_iehdr("calling", &ie->h, cx))
2386                 return;
2387         print_addr(cx, &ie->addr);
2388
2389         if(ie->h.present & UNI_CALLING_SCREEN_P) {
2390                 uni_print_tbl("screening", ie->screen, screen_tbl, cx);
2391                 uni_print_tbl("presentation", ie->pres, pres_tbl, cx);
2392         }
2393
2394         uni_print_ieend(cx);
2395 }
2396
2397 DEF_IE_CHECK(itu, calling)
2398 {
2399         cx = cx;
2400
2401         if(check_addr(&ie->addr))
2402                 return -1;
2403
2404         if(ie->h.present & UNI_CALLING_SCREEN_P)
2405                 if(check_screen(ie->screen, ie->pres))
2406                         return -1;
2407         return 0;
2408 }
2409
2410 DEF_IE_ENCODE(itu, calling)
2411 {
2412         START_IE(calling, UNI_IE_CALLING, 22);
2413         encode_addr(msg, &ie->addr, ie->h.present & UNI_CALLING_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie));
2414         SET_IE_LEN(msg);
2415         return 0;
2416 }
2417
2418 DEF_IE_DECODE(itu, calling)
2419 {
2420         u_char c, plan;
2421
2422         IE_START(;);
2423
2424         if(ielen > 22 || ielen < 1)
2425                 goto rej;
2426
2427         plan = *msg->b_rptr++;
2428         ielen--;
2429
2430         if(!(plan & 0x80)) {
2431                 if(ielen == 0)
2432                         goto rej;
2433                 ielen--;
2434                 c = *msg->b_rptr++;
2435
2436                 ie->h.present |= UNI_CALLING_SCREEN_P;
2437                 ie->pres = (c >> 5) & 0x3;
2438                 ie->screen = c & 0x3;
2439
2440                 if(!(c & 0x80))
2441                         goto rej;
2442         }
2443
2444         if(decode_addr(&ie->addr, ielen, msg, plan))
2445                 goto rej;
2446
2447         IE_END(CALLING);
2448 }
2449
2450 /**********************************************************************/
2451
2452 DEF_IE_PRINT(itu, callingsub)
2453 {
2454         if(uni_print_iehdr("callingsub", &ie->h, cx))
2455                 return;
2456         print_addrsub(cx, &ie->addr);
2457         uni_print_ieend(cx);
2458 }
2459
2460 DEF_IE_CHECK(itu, callingsub)
2461 {
2462         cx = cx;
2463
2464         if(check_subaddr(&ie->addr))
2465                 return -1;
2466         return 0;
2467 }
2468
2469 DEF_IE_ENCODE(itu, callingsub)
2470 {
2471         START_IE(callingsub, UNI_IE_CALLINGSUB, 21);
2472         encode_subaddr(msg, &ie->addr);
2473         SET_IE_LEN(msg);
2474         return 0;
2475 }
2476
2477 DEF_IE_DECODE(itu, callingsub)
2478 {
2479         u_char c;
2480
2481         IE_START(;);
2482
2483         if(ielen > 21)
2484                 goto rej;
2485
2486         c = *msg->b_rptr++;
2487         ielen--;
2488
2489         if(decode_subaddr(&ie->addr, ielen, msg, c))
2490                 goto rej;
2491
2492         IE_END(CALLINGSUB);
2493 }
2494
2495 /**********************************************************************/
2496
2497 DEF_IE_PRINT(itu, conned)
2498 {
2499         if(uni_print_iehdr("conned", &ie->h, cx))
2500                 return;
2501         print_addr(cx, &ie->addr);
2502
2503         if(ie->h.present & UNI_CONNED_SCREEN_P) {
2504                 uni_print_tbl("screening", ie->screen, screen_tbl, cx);
2505                 uni_print_tbl("presentation", ie->pres, pres_tbl, cx);
2506         }
2507
2508         uni_print_ieend(cx);
2509 }
2510
2511 DEF_IE_CHECK(itu, conned)
2512 {
2513         cx = cx;
2514
2515         if(check_addr(&ie->addr))
2516                 return -1;
2517
2518         if(ie->h.present & UNI_CONNED_SCREEN_P)
2519                 if(check_screen(ie->screen, ie->pres))
2520                         return -1;
2521         return 0;
2522 }
2523
2524 DEF_IE_ENCODE(itu, conned)
2525 {
2526         START_IE(conned, UNI_IE_CONNED, 22);
2527         encode_addr(msg, &ie->addr, ie->h.present & UNI_CONNED_SCREEN_P, ie->screen, ie->pres, IE_ISERROR(*ie));
2528         SET_IE_LEN(msg);
2529         return 0;
2530 }
2531
2532 DEF_IE_DECODE(itu, conned)
2533 {
2534         u_char c, plan;
2535
2536         IE_START(;);
2537
2538         if(ielen > 22 || ielen < 1)
2539                 goto rej;
2540
2541         plan = *msg->b_rptr++;
2542         ielen--;
2543
2544         if(!(plan & 0x80)) {
2545                 if(ielen == 0)
2546                         goto rej;
2547                 ielen--;
2548                 c = *msg->b_rptr++;
2549
2550                 ie->h.present |= UNI_CONNED_SCREEN_P;
2551                 ie->pres = (c >> 5) & 0x3;
2552                 ie->screen = c & 0x3;
2553
2554                 if(!(c & 0x80))
2555                         goto rej;
2556         }
2557
2558         if(decode_addr(&ie->addr, ielen, msg, plan))
2559                 goto rej;
2560
2561         IE_END(CONNED);
2562 }
2563
2564 /**********************************************************************/
2565
2566 DEF_IE_PRINT(itu, connedsub)
2567 {
2568         if(uni_print_iehdr("connedsub", &ie->h, cx))
2569                 return;
2570         print_addrsub(cx, &ie->addr);
2571         uni_print_ieend(cx);
2572 }
2573
2574 DEF_IE_CHECK(itu, connedsub)
2575 {
2576         cx = cx;
2577
2578         if(check_subaddr(&ie->addr))
2579                 return -1;
2580         return 0;
2581 }
2582
2583 DEF_IE_ENCODE(itu, connedsub)
2584 {
2585         START_IE(connedsub, UNI_IE_CONNEDSUB, 21);
2586         encode_subaddr(msg, &ie->addr);
2587         SET_IE_LEN(msg);
2588         return 0;
2589 }
2590
2591 DEF_IE_DECODE(itu, connedsub)
2592 {
2593         u_char c;
2594
2595         IE_START(;);
2596
2597         if(ielen > 21)
2598                 goto rej;
2599
2600         c = *msg->b_rptr++;
2601         ielen--;
2602
2603         if(decode_subaddr(&ie->addr, ielen, msg, c))
2604                 goto rej;
2605
2606         IE_END(CONNEDSUB);
2607 }
2608
2609 /*********************************************************************
2610  *
2611  * Endpoint reference.
2612  *
2613  * References for this IE are:
2614  *
2615  *  Q.2971 p.  14
2616  *
2617  * Only ITU-T coding allowed.
2618  */
2619
2620 DEF_IE_PRINT(itu, epref)
2621 {
2622         if(uni_print_iehdr("epref", &ie->h, cx))
2623                 return;
2624         uni_print_entry(cx, "epref", "(%u,%u)", ie->flag, ie->epref);
2625         uni_print_ieend(cx);
2626 }
2627
2628 DEF_IE_CHECK(itu, epref)
2629 {
2630         cx = cx;
2631
2632         if(ie->epref >= (2<<15))
2633                 return -1;
2634
2635         return 0;
2636 }
2637
2638 DEF_IE_ENCODE(itu, epref)
2639 {
2640         START_IE(epref, UNI_IE_EPREF, 3);
2641
2642         if (IE_ISERROR(*ie))
2643                 APP_BYTE(msg, 0xff);
2644         else
2645                 APP_BYTE(msg, 0);
2646         APP_BYTE(msg, (ie->flag << 7) | ((ie->epref >> 8) & 0x7f));
2647         APP_BYTE(msg, (ie->epref & 0xff));
2648
2649         SET_IE_LEN(msg);
2650         return 0;
2651 }
2652
2653 DEF_IE_DECODE(itu, epref)
2654 {
2655         u_char c;
2656
2657         IE_START(;);
2658
2659         if(ielen != 3)
2660                 goto rej;
2661         if(*msg->b_rptr++ != 0)
2662                 goto rej;
2663
2664         c = *msg->b_rptr++;
2665         ie->flag = (c & 0x80) ? 1 : 0;
2666         ie->epref = (c & 0x7f) << 8;
2667         ie->epref |= *msg->b_rptr++;
2668
2669         IE_END(EPREF);
2670 }
2671
2672 /*********************************************************************
2673  *
2674  * Endpoint state.
2675  *
2676  * References for this IE are:
2677  *
2678  *  Q.2971 pp. 14...15
2679  *
2680  * Only ITU-T coding allowed.
2681  */
2682
2683 DEF_IE_PRINT(itu, epstate)
2684 {
2685         static const struct uni_print_tbl tbl[] = {
2686                 MKT(UNI_EPSTATE_NULL,           null),
2687                 MKT(UNI_EPSTATE_ADD_INIT,       add-initiated),
2688                 MKT(UNI_EPSTATE_ALERT_DLVD,     alerting-delivered),
2689                 MKT(UNI_EPSTATE_ADD_RCVD,       add-received),
2690                 MKT(UNI_EPSTATE_ALERT_RCVD,     alerting-received),
2691                 MKT(UNI_EPSTATE_ACTIVE,         active),
2692                 MKT(UNI_EPSTATE_DROP_INIT,      drop-initiated),
2693                 MKT(UNI_EPSTATE_DROP_RCVD,      drop-received),
2694                 EOT()
2695         };
2696
2697         if(uni_print_iehdr("epstate", &ie->h, cx))
2698                 return;
2699         uni_print_tbl("state", ie->state, tbl, cx);
2700         uni_print_ieend(cx);
2701 }
2702
2703 DEF_IE_CHECK(itu, epstate)
2704 {
2705         cx = cx;
2706
2707         switch(ie->state) {
2708           default:
2709                 return -1;
2710
2711           case UNI_EPSTATE_NULL:
2712           case UNI_EPSTATE_ADD_INIT:
2713           case UNI_EPSTATE_ALERT_DLVD:
2714           case UNI_EPSTATE_ADD_RCVD:
2715           case UNI_EPSTATE_ALERT_RCVD:
2716           case UNI_EPSTATE_DROP_INIT:
2717           case UNI_EPSTATE_DROP_RCVD:
2718           case UNI_EPSTATE_ACTIVE:
2719                 break;
2720         }
2721
2722         return 0;
2723 }
2724
2725 DEF_IE_ENCODE(itu, epstate)
2726 {
2727         START_IE(epstate, UNI_IE_EPSTATE, 1);
2728
2729         APP_BYTE(msg, ie->state);
2730
2731         SET_IE_LEN(msg);
2732         return 0;
2733 }
2734
2735 DEF_IE_DECODE(itu, epstate)
2736 {
2737         IE_START(;);
2738
2739         if(ielen != 1)
2740                 goto rej;
2741
2742         ie->state = *msg->b_rptr++ & 0x3f;
2743
2744         IE_END(EPSTATE);
2745 }
2746
2747 /*********************************************************************
2748  *
2749  * ATM adaptation layer parameters
2750  *
2751  * References for this IE are:
2752  *
2753  *  Q.2931 pp. 43...49
2754  *  Q.2931 Amd 2
2755  *  UNI4.0 p.  9
2756  *
2757  * UNI4.0 states, that AAL2 is not supported. However we keep it. No
2758  * parameters are associated with AAL2.
2759  *
2760  * Amd2 not checked. XXX
2761  *
2762  * Only ITU-T coding allowed.
2763  */
2764 DEF_IE_PRINT(itu, aal)
2765 {
2766         static const struct uni_print_tbl aal_tbl[] = {
2767                 MKT(UNI_AAL_0,                  VOICE),
2768                 MKT(UNI_AAL_1,                  1),
2769                 MKT(UNI_AAL_2,                  2),
2770                 MKT(UNI_AAL_4,                  3/4),
2771                 MKT(UNI_AAL_5,                  5),
2772                 MKT(UNI_AAL_USER,               USER),
2773                 EOT()
2774         };
2775         static const struct uni_print_tbl subtype_tbl[] = {
2776                 MKT(UNI_AAL1_SUB_NULL,          null),
2777                 MKT(UNI_AAL1_SUB_VOICE,         voice),
2778                 MKT(UNI_AAL1_SUB_CIRCUIT,       circuit),
2779                 MKT(UNI_AAL1_SUB_HQAUDIO,       hqaudio),
2780                 MKT(UNI_AAL1_SUB_VIDEO,         video),
2781                 EOT()
2782         };
2783         static const struct uni_print_tbl cbr_rate_tbl[] = {
2784                 MKT(UNI_AAL1_CBR_64,            64),
2785                 MKT(UNI_AAL1_CBR_1544,          1544(DS1)),
2786                 MKT(UNI_AAL1_CBR_6312,          6312(DS2)),
2787                 MKT(UNI_AAL1_CBR_32064,         32064),
2788                 MKT(UNI_AAL1_CBR_44736,         44736(DS3)),
2789                 MKT(UNI_AAL1_CBR_97728,         97728),
2790                 MKT(UNI_AAL1_CBR_2048,          2048(E1)),
2791                 MKT(UNI_AAL1_CBR_8448,          8448(E2)),
2792                 MKT(UNI_AAL1_CBR_34368,         34368(E3)),
2793                 MKT(UNI_AAL1_CBR_139264,        139264),
2794                 MKT(UNI_AAL1_CBR_N64,           Nx64),
2795                 MKT(UNI_AAL1_CBR_N8,            Nx8),
2796                 EOT()
2797         };
2798         static const struct uni_print_tbl screc_tbl[] = {
2799                 MKT(UNI_AAL1_SCREC_NULL,        null),
2800                 MKT(UNI_AAL1_SCREC_SRTS,        srts),
2801                 MKT(UNI_AAL1_SCREC_ACLK,        aclk),
2802                 EOT()
2803         };
2804         static const struct uni_print_tbl ecm_tbl[] = {
2805                 MKT(UNI_AAL1_ECM_NULL,          null),
2806                 MKT(UNI_AAL1_ECM_LOSS,          loss),
2807                 MKT(UNI_AAL1_ECM_DELAY,         delay),
2808                 EOT()
2809         };
2810         static const struct uni_print_tbl sscs_tbl[] = {
2811                 MKT(UNI_AAL_SSCS_NULL,          null),
2812                 MKT(UNI_AAL_SSCS_SSCOPA,        sscopa),
2813                 MKT(UNI_AAL_SSCS_SSCOPU,        sscopu),
2814                 MKT(UNI_AAL_SSCS_FRAME,         frame),
2815                 EOT()
2816         };
2817
2818         if(uni_print_iehdr("aal", &ie->h, cx))
2819                 return;
2820         uni_print_tbl("type", ie->type, aal_tbl, cx);
2821
2822         switch(ie->type) {
2823
2824           case UNI_AAL_0:
2825                 uni_print_push_prefix("0", cx);
2826                 cx->indent++;
2827                 break;
2828
2829           case UNI_AAL_2:
2830                 uni_print_push_prefix("2", cx);
2831                 cx->indent++;
2832                 break;
2833
2834           case UNI_AAL_1:
2835                 uni_print_push_prefix("1", cx);
2836                 cx->indent++;
2837                 uni_print_tbl("subtype", ie->u.aal1.subtype, subtype_tbl, cx);
2838                 uni_print_tbl("cbr_rate", ie->u.aal1.cbr_rate, cbr_rate_tbl, cx);
2839                 if(ie->h.present & UNI_AAL1_MULT_P)
2840                         uni_print_entry(cx, "mult", "%u", ie->u.aal1.mult);
2841                 if(ie->h.present & UNI_AAL1_SCREC_P)
2842                         uni_print_tbl("screc", ie->u.aal1.screc, screc_tbl, cx);
2843                 if(ie->h.present & UNI_AAL1_ECM_P)
2844                         uni_print_tbl("ecm", ie->u.aal1.ecm, ecm_tbl, cx);
2845                 if(ie->h.present & UNI_AAL1_BSIZE_P)
2846                         uni_print_entry(cx, "bsize", "%u", ie->u.aal1.bsize);
2847                 if(ie->h.present & UNI_AAL1_PART_P)
2848                         uni_print_entry(cx, "part", "%u", ie->u.aal1.part);
2849                 break;
2850
2851           case UNI_AAL_4:
2852                 uni_print_push_prefix("4", cx);
2853                 cx->indent++;
2854                 if(ie->h.present & UNI_AAL4_CPCS_P)
2855                         uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal4.fwd_cpcs,
2856                                 ie->u.aal4.bwd_cpcs);
2857                 if(ie->h.present & UNI_AAL4_MID_P)
2858                         uni_print_entry(cx, "mid", "(%u,%u)", ie->u.aal4.mid_low,
2859                                 ie->u.aal4.mid_high);
2860                 if(ie->h.present & UNI_AAL4_SSCS_P)
2861                         uni_print_tbl("sscs", ie->u.aal4.sscs, sscs_tbl, cx);
2862                 break;
2863
2864           case UNI_AAL_5:
2865                 uni_print_push_prefix("5", cx);
2866                 cx->indent++;
2867                 if(ie->h.present & UNI_AAL5_CPCS_P)
2868                         uni_print_entry(cx, "cpcs", "(%u,%u)", ie->u.aal5.fwd_cpcs,
2869                                 ie->u.aal5.bwd_cpcs);
2870                 if(ie->h.present & UNI_AAL5_SSCS_P)
2871                         uni_print_tbl("sscs", ie->u.aal5.sscs, sscs_tbl, cx);
2872                 break;
2873
2874           case UNI_AAL_USER:
2875                 uni_print_push_prefix("user", cx);
2876                 cx->indent++;
2877                 if(ie->u.aalu.len > 4) {
2878                         uni_print_entry(cx, "info", "ERROR(len=%u)", ie->u.aalu.len);
2879                 } else {
2880                         u_int i;
2881
2882                         uni_print_entry(cx, "info", "(");
2883                         for(i = 0; i < ie->u.aalu.len; i++)
2884                                 uni_printf(cx, "%s%u", !i?"":",", ie->u.aalu.user[i]);
2885                         uni_printf(cx, ")");
2886                 }
2887                 break;
2888         }
2889         cx->indent--;
2890         uni_print_pop_prefix(cx);
2891         uni_print_eol(cx);
2892
2893         uni_print_ieend(cx);
2894 }
2895
2896 DEF_IE_CHECK(itu, aal)
2897 {
2898         cx = cx;
2899
2900         if(ie->type == UNI_AAL_0) {
2901                 ;
2902         } else if(ie->type == UNI_AAL_1) {
2903                 switch(ie->u.aal1.subtype) {
2904
2905                   default:
2906                         return -1;
2907
2908                   case UNI_AAL1_SUB_NULL:
2909                   case UNI_AAL1_SUB_VOICE:
2910                   case UNI_AAL1_SUB_CIRCUIT:
2911                   case UNI_AAL1_SUB_HQAUDIO:
2912                   case UNI_AAL1_SUB_VIDEO:
2913                         break;
2914                 }
2915                 switch(ie->u.aal1.cbr_rate) {
2916
2917                   default:
2918                         return -1;
2919
2920                   case UNI_AAL1_CBR_64:
2921                   case UNI_AAL1_CBR_1544:
2922                   case UNI_AAL1_CBR_6312:
2923                   case UNI_AAL1_CBR_32064:
2924                   case UNI_AAL1_CBR_44736:
2925                   case UNI_AAL1_CBR_97728:
2926                   case UNI_AAL1_CBR_2048:
2927                   case UNI_AAL1_CBR_8448:
2928                   case UNI_AAL1_CBR_34368:
2929                   case UNI_AAL1_CBR_139264:
2930                         if((ie->h.present & UNI_AAL1_MULT_P))
2931                                 return -1;
2932                         break;
2933
2934                   case UNI_AAL1_CBR_N64:
2935                         if(!(ie->h.present & UNI_AAL1_MULT_P))
2936                                 return -1;
2937                         if(ie->u.aal1.mult < 2)
2938                                 return -1;
2939                         break;
2940
2941                   case UNI_AAL1_CBR_N8:
2942                         if(!(ie->h.present & UNI_AAL1_MULT_P))
2943                                 return -1;
2944                         if(ie->u.aal1.mult == 0 || ie->u.aal1.mult > 7)
2945                                 return -1;
2946                         break;
2947                 }
2948                 if(ie->h.present & UNI_AAL1_SCREC_P) {
2949                         switch(ie->u.aal1.screc) {
2950
2951                           default:
2952                                 return -1;
2953
2954                           case UNI_AAL1_SCREC_NULL:
2955                           case UNI_AAL1_SCREC_SRTS:
2956                           case UNI_AAL1_SCREC_ACLK:
2957                                 break;
2958                         }
2959                 }
2960                 if(ie->h.present & UNI_AAL1_ECM_P) {
2961                         switch(ie->u.aal1.ecm) {
2962
2963                           default:
2964                                 return -1;
2965
2966                           case UNI_AAL1_ECM_NULL:
2967                           case UNI_AAL1_ECM_LOSS:
2968                           case UNI_AAL1_ECM_DELAY:
2969                                 break;
2970                         }
2971                 }
2972                 if(ie->h.present & UNI_AAL1_BSIZE_P) {
2973                         if(ie->u.aal1.bsize == 0)
2974                                 return -1;
2975                 }
2976                 if(ie->h.present & UNI_AAL1_PART_P) {
2977                         if(ie->u.aal1.part == 0 || ie->u.aal1.part > 47)
2978                                 return -1;
2979                 }
2980
2981         } else if(ie->type == UNI_AAL_2) {
2982                 ;
2983
2984         } else if(ie->type == UNI_AAL_4) {
2985                 if(ie->h.present & UNI_AAL4_MID_P) {
2986                         if(ie->u.aal4.mid_low >= 1024)
2987                                 return -1;
2988                         if(ie->u.aal4.mid_high >= 1024)
2989                                 return -1;
2990                         if(ie->u.aal4.mid_low > ie->u.aal4.mid_high)
2991                                 return -1;
2992                 }
2993                 if(ie->h.present & UNI_AAL4_SSCS_P) {
2994                         switch(ie->u.aal4.sscs) {
2995
2996                           default:
2997                                 return -1;
2998
2999                           case UNI_AAL_SSCS_NULL:
3000                           case UNI_AAL_SSCS_SSCOPA:
3001                           case UNI_AAL_SSCS_SSCOPU:
3002                           case UNI_AAL_SSCS_FRAME:
3003                                 break;
3004                         }
3005                 }
3006
3007         } else if(ie->type == UNI_AAL_5) {
3008                 if(ie->h.present & UNI_AAL5_SSCS_P) {
3009                         switch(ie->u.aal5.sscs) {
3010
3011                           default:
3012                                 return -1;
3013
3014                           case UNI_AAL_SSCS_NULL:
3015                           case UNI_AAL_SSCS_SSCOPA:
3016                           case UNI_AAL_SSCS_SSCOPU:
3017                           case UNI_AAL_SSCS_FRAME:
3018                                 break;
3019                         }
3020                 }
3021
3022         } else if(ie->type == UNI_AAL_USER) {
3023                 if(ie->u.aalu.len > 4)
3024                         return -1;
3025
3026         } else
3027                 return -1;
3028
3029         return 0;
3030 }
3031
3032 DEF_IE_ENCODE(itu, aal)
3033 {
3034         START_IE(aal, UNI_IE_AAL, 16);
3035
3036         APP_BYTE(msg, ie->type);
3037         switch(ie->type) {
3038
3039           case UNI_AAL_0:
3040                 break;
3041
3042           case UNI_AAL_1:
3043                 APP_SUB_BYTE(msg,
3044                         UNI_AAL_SUB_ID, ie->u.aal1.subtype);
3045                 APP_SUB_BYTE(msg,
3046                         UNI_AAL_CBR_ID, ie->u.aal1.cbr_rate);
3047                 APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_MULT_P,
3048                         UNI_AAL_MULT_ID, ie->u.aal1.mult);
3049                 APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_SCREC_P,
3050                         UNI_AAL_SCREC_ID, ie->u.aal1.screc);
3051                 APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_ECM_P,
3052                         UNI_AAL_ECM_ID, ie->u.aal1.ecm);
3053                 APP_OPT_16BIT(msg, ie->h.present, UNI_AAL1_BSIZE_P,
3054                         UNI_AAL_BSIZE_ID, ie->u.aal1.bsize);
3055                 APP_OPT_BYTE(msg, ie->h.present, UNI_AAL1_PART_P,
3056                         UNI_AAL_PART_ID, ie->u.aal1.part);
3057                 break;
3058
3059           case UNI_AAL_2:
3060                 break;
3061
3062           case UNI_AAL_4:
3063                 if(ie->h.present & UNI_AAL4_CPCS_P) {
3064                         APP_SUB_16BIT(msg,
3065                                 UNI_AAL_FWDCPCS_ID, ie->u.aal4.fwd_cpcs);
3066                         APP_SUB_16BIT(msg,
3067                                 UNI_AAL_BWDCPCS_ID, ie->u.aal4.bwd_cpcs);
3068                 }
3069                 if(ie->h.present & UNI_AAL4_MID_P) {
3070                         APP_BYTE(msg, UNI_AAL_MID_ID);
3071                         APP_16BIT(msg, ie->u.aal4.mid_low);
3072                         APP_16BIT(msg, ie->u.aal4.mid_high);
3073                 }
3074                 APP_OPT_BYTE(msg, ie->h.present, UNI_AAL4_SSCS_P,
3075                         UNI_AAL_SSCS_ID, ie->u.aal4.sscs);
3076                 break;
3077
3078           case UNI_AAL_5:
3079                 if(ie->h.present & UNI_AAL5_CPCS_P) {
3080                         APP_SUB_16BIT(msg,
3081                                 UNI_AAL_FWDCPCS_ID, ie->u.aal5.fwd_cpcs);
3082                         APP_SUB_16BIT(msg,
3083                                 UNI_AAL_BWDCPCS_ID, ie->u.aal5.bwd_cpcs);
3084                 }
3085                 APP_OPT_BYTE(msg, ie->h.present, UNI_AAL5_SSCS_P,
3086                         UNI_AAL_SSCS_ID, ie->u.aal5.sscs);
3087                 break;
3088
3089           case UNI_AAL_USER:
3090                 APP_BUF(msg, ie->u.aalu.user, ie->u.aalu.len);
3091                 break;
3092
3093           default:
3094                 return -1;
3095         }
3096
3097         SET_IE_LEN(msg);
3098         return 0;
3099 }
3100
3101 /*
3102  * XXX What should we do with multiple subtype occurences? Ignore
3103  * or reject. Currently we reject.
3104  */
3105 static int
3106 decode_aal_1(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen)
3107 {
3108         int subtype_p, cbr_p;
3109
3110         subtype_p = cbr_p = 0;
3111
3112         while(ielen-- > 0) {
3113                 switch(*msg->b_rptr++) {
3114
3115                   case UNI_AAL_SUB_ID:
3116                         if(ielen == 0 || subtype_p)
3117                                 return -1;
3118                         ielen--;
3119                         subtype_p = 1;
3120                         ie->u.aal1.subtype = *msg->b_rptr++;
3121                         break;
3122
3123                   case UNI_AAL_CBR_ID:
3124                         if(ielen == 0 || cbr_p)
3125                                 return -1;
3126                         ielen--;
3127                         cbr_p = 1;
3128                         ie->u.aal1.cbr_rate = *msg->b_rptr++;
3129                         break;
3130
3131                   case UNI_AAL_MULT_ID:
3132                         if(ielen < 2 || (ie->h.present & UNI_AAL1_MULT_P))
3133                                 return -1;
3134                         ielen -= 2;
3135                         ie->h.present |= UNI_AAL1_MULT_P;
3136                         ie->u.aal1.mult  = *msg->b_rptr++ << 8;
3137                         ie->u.aal1.mult |= *msg->b_rptr++;
3138                         break;
3139                         
3140                   case UNI_AAL_SCREC_ID:
3141                         if(ielen == 0 || (ie->h.present & UNI_AAL1_SCREC_P))
3142                                 return -1;
3143                         ielen--;
3144                         ie->h.present |= UNI_AAL1_SCREC_P;
3145                         ie->u.aal1.screc = *msg->b_rptr++;
3146                         break;
3147
3148                   case UNI_AAL_ECM_ID:
3149                         if(ielen == 0 || (ie->h.present & UNI_AAL1_ECM_P))
3150                                 return -1;
3151                         ielen--;
3152                         ie->h.present |= UNI_AAL1_ECM_P;
3153                         ie->u.aal1.ecm = *msg->b_rptr++;
3154                         break;
3155
3156                   case UNI_AAL_BSIZE_ID:
3157                         if(ielen < 2 || (ie->h.present & UNI_AAL1_BSIZE_P))
3158                                 return -1;
3159                         ielen -= 2;
3160                         ie->h.present |= UNI_AAL1_BSIZE_P;
3161                         ie->u.aal1.bsize  = *msg->b_rptr++ << 8;
3162                         ie->u.aal1.bsize |= *msg->b_rptr++;
3163                         break;
3164
3165                   case UNI_AAL_PART_ID:
3166                         if(ielen == 0 || (ie->h.present & UNI_AAL1_PART_P))
3167                                 return -1;
3168                         ielen--;
3169                         ie->h.present |= UNI_AAL1_PART_P;
3170                         ie->u.aal1.part = *msg->b_rptr++;
3171                         break;
3172
3173                   default:
3174                         return -1;
3175                 }
3176         }
3177         if(!subtype_p || !cbr_p)
3178                 return -1;
3179
3180         return 0;
3181 }
3182
3183 static int
3184 decode_aal_4(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen)
3185 {
3186         int fcpcs_p, bcpcs_p;
3187
3188         fcpcs_p = bcpcs_p = 0;
3189
3190         while(ielen-- > 0) {
3191                 switch(*msg->b_rptr++) {
3192
3193                   case UNI_AAL_FWDCPCS_ID:
3194                         if(ielen < 2 || fcpcs_p)
3195                                 return -1;
3196                         ielen -= 2;
3197                         fcpcs_p = 1;
3198                         ie->u.aal4.fwd_cpcs  = *msg->b_rptr++ << 8;
3199                         ie->u.aal4.fwd_cpcs |= *msg->b_rptr++;
3200                         break;
3201
3202                   case UNI_AAL_BWDCPCS_ID:
3203                         if(ielen < 2 || bcpcs_p)
3204                                 return -1;
3205                         ielen -= 2;
3206                         bcpcs_p = 1;
3207                         ie->u.aal4.bwd_cpcs  = *msg->b_rptr++ << 8;
3208                         ie->u.aal4.bwd_cpcs |= *msg->b_rptr++;
3209                         break;
3210
3211                   case UNI_AAL_MID_ID:
3212                         if(ielen < 4 || (ie->h.present & UNI_AAL4_MID_P))
3213                                 return -1;
3214                         ielen -= 4;
3215                         ie->h.present |= UNI_AAL4_MID_P;
3216                         ie->u.aal4.mid_low  = *msg->b_rptr++ << 8;
3217                         ie->u.aal4.mid_low |= *msg->b_rptr++;
3218                         ie->u.aal4.mid_high  = *msg->b_rptr++ << 8;
3219                         ie->u.aal4.mid_high |= *msg->b_rptr++;
3220                         break;
3221
3222                   case UNI_AAL_SSCS_ID:
3223                         if(ielen == 0 || (ie->h.present & UNI_AAL4_SSCS_P))
3224                                 return -1;
3225                         ielen--;
3226                         ie->h.present |= UNI_AAL4_SSCS_P;
3227                         ie->u.aal4.sscs = *msg->b_rptr++;
3228                         break;
3229
3230                   default:
3231                         return -1;
3232                 }
3233         }
3234
3235         if(fcpcs_p ^ bcpcs_p)
3236                 return -1;
3237         if(fcpcs_p)
3238                 ie->h.present |= UNI_AAL4_CPCS_P;
3239
3240         return 0;
3241 }
3242
3243 static int
3244 decode_aal_5(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen)
3245 {
3246         int fcpcs_p, bcpcs_p;
3247
3248         fcpcs_p = bcpcs_p = 0;
3249
3250         while(ielen-- > 0) {
3251                 switch(*msg->b_rptr++) {
3252
3253                   case UNI_AAL_FWDCPCS_ID:
3254                         if(ielen < 2 || fcpcs_p)
3255                                 return -1;
3256                         ielen -= 2;
3257                         fcpcs_p = 1;
3258                         ie->u.aal5.fwd_cpcs  = *msg->b_rptr++ << 8;
3259                         ie->u.aal5.fwd_cpcs |= *msg->b_rptr++;
3260                         break;
3261
3262                   case UNI_AAL_BWDCPCS_ID:
3263                         if(ielen < 2 || bcpcs_p)
3264                                 return -1;
3265                         ielen -= 2;
3266                         bcpcs_p = 1;
3267                         ie->u.aal5.bwd_cpcs  = *msg->b_rptr++ << 8;
3268                         ie->u.aal5.bwd_cpcs |= *msg->b_rptr++;
3269                         break;
3270
3271                   case UNI_AAL_SSCS_ID:
3272                         if(ielen == 0 || (ie->h.present & UNI_AAL5_SSCS_P))
3273                                 return -1;
3274                         ielen--;
3275                         ie->h.present |= UNI_AAL5_SSCS_P;
3276                         ie->u.aal5.sscs = *msg->b_rptr++;
3277                         break;
3278
3279                   default:
3280                         return -1;
3281                 }
3282         }
3283
3284         if(fcpcs_p ^ bcpcs_p)
3285                 return -1;
3286         if(fcpcs_p)
3287                 ie->h.present |= UNI_AAL5_CPCS_P;
3288
3289         return 0;
3290 }
3291
3292 static int
3293 decode_aal_user(struct uni_ie_aal *ie, struct uni_msg *msg, u_int ielen)
3294 {
3295         if(ielen > 4)
3296                 return -1;
3297
3298         ie->u.aalu.len = 0;
3299         while(ielen--)
3300                 ie->u.aalu.user[ie->u.aalu.len++] = *msg->b_rptr++;
3301
3302         return 0;
3303 }
3304
3305 DEF_IE_DECODE(itu, aal)
3306 {
3307         u_char c;
3308
3309         IE_START(DISC_ACC_ERR(AAL));
3310
3311         if(ielen < 1 || ielen > 21)
3312                 goto rej;
3313
3314         c = *msg->b_rptr++;
3315         ielen--;
3316
3317         switch(c) {
3318
3319           case UNI_AAL_0:
3320                 ie->type = c;
3321                 break;
3322
3323           case UNI_AAL_1:
3324                 ie->type = c;
3325                 if(decode_aal_1(ie, msg, ielen))
3326                         goto rej;
3327                 break;
3328
3329           case UNI_AAL_2:
3330                 ie->type = c;
3331                 break;
3332
3333           case UNI_AAL_4:
3334                 ie->type = c;
3335                 if(decode_aal_4(ie, msg, ielen))
3336                         goto rej;
3337                 break;
3338
3339           case UNI_AAL_5:
3340                 ie->type = c;
3341                 if(decode_aal_5(ie, msg, ielen))
3342                         goto rej;
3343                 break;
3344
3345           case UNI_AAL_USER:
3346                 ie->type = c;
3347                 if(decode_aal_user(ie, msg, ielen))
3348                         goto rej;
3349                 break;
3350
3351           default:
3352                 goto rej;
3353         }
3354
3355         IE_END(AAL);
3356 }
3357
3358 /*********************************************************************
3359  *
3360  * Traffic descriptor.
3361  * Alternate traffic descriptor.
3362  * Minimum traffic descriptor.
3363  *
3364  * References for this IE are:
3365  *
3366  *  Q.2931 pp. 49...51
3367  *  Q.2961
3368  *  Q.2962
3369  *  UNI4.0 pp. 9...10, 106...109
3370  *
3371  * The Q.s specify the coding. UNI4.0 adds frame discard and best-effort.
3372  * Appendix in UNI4.0 lists the allowed combinations.
3373  *
3374  *                PCR0 PCR1 SCR/MBS0 SCR/MBS1 BE TAG FDISC ABR
3375  *  1   CBR.1     -    Y    -        -        -  N   Y/N   -
3376  *  2   CBR.2     -    Y    -        -        -  N   Y/N   -    (*)
3377  *  3   CBR.3     Y    Y    -        -        -  Y   Y/N   -    (*)
3378  *  4   rt-VBR.1  -    Y    -        Y        -  N   Y/N   -
3379  *  5   rt-VBR.2  -    Y    Y        -        -  N   Y/N   -
3380  *  6   rt-VBR.3  -    Y    Y        -        -  Y   Y/N   -
3381  *  7   rt-VBR.4  Y    Y    -        -        -  Y/N Y/N   -    (*)
3382  *  8   rt-VBR.5  -    Y    -        -        -  N   Y/N   -    (*)
3383  *  9   rt-VBR.6  -    Y    -        Y        -  N   Y/N   -    (*)
3384  * 10   nrt-VBR.1 -    Y    -        Y        -  N   Y/N   -
3385  * 11   nrt-VBR.2 -    Y    Y        -        -  N   Y/N   -
3386  * 12   nrt-VBR.3 -    Y    Y        -        -  Y   Y/N   -
3387  * 13   nrt-VBR.4 Y    Y    -        -        -  Y/N Y/N   -    (*)
3388  * 14   nrt-VBR.5 -    Y    -        -        -  N   Y/N   -    (*)
3389  * 15   nrt-VBR.6 -    Y    -        Y        -  N   Y/N   -    (*)
3390  * 16   ABR       -    Y    -        -        -  N   Y/N   O    (*)
3391  * 17   UBR.1     -    Y    -        -        Y  N   Y/N   -
3392  * 18   UBR.2     -    Y    -        -        Y  Y   Y/N   -
3393  *
3394  * Allow ITU-T and NET coding, because its not clear, whether the
3395  * new fields in UNI4.0 should be used with NET coding or not.
3396  * Does not allow for experimental codings yet.
3397  */
3398
3399 static void
3400 print_ie_traffic_common(struct unicx *cx, u_int present, struct uni_xtraffic *ie)
3401 {
3402         uni_print_entry(cx, "fwd", "(");
3403         if(present & UNI_TRAFFIC_FPCR0_P)
3404                 uni_printf(cx, "%u", ie->fpcr0);
3405         uni_putc(',', cx);
3406         if(present & UNI_TRAFFIC_FPCR1_P)
3407                 uni_printf(cx, "%u", ie->fpcr1);
3408         uni_putc(',', cx);
3409         if(present & UNI_TRAFFIC_FSCR0_P)
3410                 uni_printf(cx, "%u", ie->fscr0);
3411         uni_putc(',', cx);
3412         if(present & UNI_TRAFFIC_FSCR1_P)
3413                 uni_printf(cx, "%u", ie->fscr1);
3414         uni_putc(',', cx);
3415         if(present & UNI_TRAFFIC_FMBS0_P)
3416                 uni_printf(cx, "%u", ie->fmbs0);
3417         uni_putc(',', cx);
3418         if(present & UNI_TRAFFIC_FMBS1_P)
3419                 uni_printf(cx, "%u", ie->fmbs1);
3420         uni_putc(',', cx);
3421         if(present & UNI_TRAFFIC_FABR1_P)
3422                 uni_printf(cx, "%u", ie->fabr1);
3423         uni_printf(cx, ")");
3424
3425         uni_print_entry(cx, "bwd", "(");
3426         if(present & UNI_TRAFFIC_BPCR0_P)
3427                 uni_printf(cx, "%u", ie->bpcr0);
3428         uni_putc(',', cx);
3429         if(present & UNI_TRAFFIC_BPCR1_P)
3430                 uni_printf(cx, "%u", ie->bpcr1);
3431         uni_putc(',', cx);
3432         if(present & UNI_TRAFFIC_BSCR0_P)
3433                 uni_printf(cx, "%u", ie->bscr0);
3434         uni_putc(',', cx);
3435         if(present & UNI_TRAFFIC_BSCR1_P)
3436                 uni_printf(cx, "%u", ie->bscr1);
3437         uni_putc(',', cx);
3438         if(present & UNI_TRAFFIC_BMBS0_P)
3439                 uni_printf(cx, "%u", ie->bmbs0);
3440         uni_putc(',', cx);
3441         if(present & UNI_TRAFFIC_BMBS1_P)
3442                 uni_printf(cx, "%u", ie->bmbs1);
3443         uni_putc(',', cx);
3444         if(present & UNI_TRAFFIC_BABR1_P)
3445                 uni_printf(cx, "%u", ie->babr1);
3446         uni_printf(cx, ")");
3447
3448         if(present & UNI_TRAFFIC_BEST_P)
3449                 uni_print_flag("best_effort", cx);
3450         if(present & UNI_TRAFFIC_MOPT_P) {
3451                 uni_print_entry(cx, "tag", "(");
3452                 if(ie->ftag)
3453                         uni_printf(cx, "fwd");
3454                 uni_putc(',', cx);
3455                 if(ie->btag)
3456                         uni_printf(cx, "bwd");
3457                 uni_putc(')', cx);
3458
3459                 uni_print_entry(cx, "disc", "(");
3460                 if(ie->fdisc)
3461                         uni_printf(cx, "fwd");
3462                 uni_putc(',', cx);
3463                 if(ie->bdisc)
3464                         uni_printf(cx, "bwd");
3465                 uni_putc(')', cx);
3466         }
3467 }
3468
3469 struct tallow {
3470         u_int   mask;
3471         int     mopt_flag;
3472         u_char  mopt_mask, mopt_val;
3473 };
3474
3475 static int
3476 check_traffic(u_int mask, u_int mopt, struct tallow *a)
3477 {
3478         if(mask != a->mask)
3479                 return 0;
3480
3481         if(a->mopt_flag == 0) {
3482                 /* not allowed */
3483                 if(mopt == 0xffff)
3484                         return 1;
3485                 return 0;
3486         }
3487
3488         if(a->mopt_flag < 0) {
3489                 /* optional */
3490                 if(mopt == 0xffff)
3491                         return 1;
3492                 if((mopt & a->mopt_mask) == a->mopt_val)
3493                         return 1;
3494                 return 0;
3495         }
3496         
3497         /* required */
3498         if(mopt == 0xffff)
3499                 return 0;
3500         if((mopt & a->mopt_mask) == a->mopt_val)
3501                 return 1;
3502         return 0;
3503 }
3504
3505 static int
3506 check_ie_traffic_common(struct uni_xtraffic *ie, u_int present,
3507     struct unicx *cx __unused)
3508 {
3509         static u_int fmask =
3510                 UNI_TRAFFIC_FPCR0_P | UNI_TRAFFIC_FPCR1_P |
3511                 UNI_TRAFFIC_FSCR0_P | UNI_TRAFFIC_FSCR1_P |
3512                 UNI_TRAFFIC_FMBS0_P | UNI_TRAFFIC_FMBS1_P |
3513                 UNI_TRAFFIC_FABR1_P;
3514         static u_int bmask =
3515                 UNI_TRAFFIC_BPCR0_P | UNI_TRAFFIC_BPCR1_P |
3516                 UNI_TRAFFIC_BSCR0_P | UNI_TRAFFIC_BSCR1_P |
3517                 UNI_TRAFFIC_BMBS0_P | UNI_TRAFFIC_BMBS1_P |
3518                 UNI_TRAFFIC_BABR1_P;
3519 #define DTAB(U,X)                                                       \
3520         { U##X##PCR1_P,                                                 \
3521           -1, U##X##TAG,        0 },            /* 1, 2, 8, 14 */       \
3522         { U##X##PCR0_P | U##X##PCR1_P,                                  \
3523           +1, U##X##TAG,        U##X##TAG },    /* 3 */                 \
3524         { U##X##PCR1_P | U##X##SCR1_P | U##X##MBS1_P,                   \
3525           -1, U##X##TAG,        0 },            /* 4, 9, 10, 15 */      \
3526         { U##X##PCR1_P | U##X##SCR0_P | U##X##MBS0_P,                   \
3527           -1, 0,                0 },            /* 5, 6, 11, 12 */      \
3528         { U##X##PCR0_P | U##X##PCR1_P,                                  \
3529           -1, 0,                0 },            /* 7, 13 */             \
3530         { U##X##PCR1_P | U##X##ABR1_P,                                  \
3531           -1, U##X##TAG,        0 },            /* 16a */
3532 #define DTABSIZE 6
3533
3534         static struct tallow allow[2][DTABSIZE] = {
3535                 { DTAB(UNI_TRAFFIC_, F) },
3536                 { DTAB(UNI_TRAFFIC_, B) },
3537         };
3538 #undef DTAB
3539
3540         u_int f, b, p, m;
3541         int i;
3542
3543         f = present & fmask;
3544         b = present & bmask;
3545         p = present & (fmask | bmask);
3546         m = (present & UNI_TRAFFIC_MOPT_P)
3547                 ? (  (ie->ftag ? UNI_TRAFFIC_FTAG : 0)
3548                    | (ie->btag ? UNI_TRAFFIC_BTAG : 0)
3549                    | (ie->fdisc ? UNI_TRAFFIC_FDISC : 0)
3550                    | (ie->bdisc ? UNI_TRAFFIC_BDISC : 0))
3551                 : 0xffff;
3552         
3553
3554         if(present & UNI_TRAFFIC_BEST_P) {
3555                 /*
3556                  * Lines 17 and 18
3557                  */
3558                 if(p != (UNI_TRAFFIC_FPCR1_P | UNI_TRAFFIC_BPCR1_P))
3559                         return -1;
3560                 return 0;
3561         }
3562
3563         /*
3564          * Check forward and backward independent. There must be a higher
3565          * level checking in the CAC
3566          */
3567         for(i = 0; i < DTABSIZE; i++)
3568                 if(check_traffic(f, m, &allow[0][i]))
3569                         break;
3570         if(i == DTABSIZE)
3571                 return -1;
3572
3573         for(i = 0; i < DTABSIZE; i++)
3574                 if(check_traffic(b, m, &allow[1][i]))
3575                         break;
3576         if(i == DTABSIZE)
3577                 return -1;
3578
3579         return 0;
3580 }
3581
3582 static int
3583 encode_traffic_common(struct uni_msg *msg, struct uni_xtraffic *ie,
3584     u_int present, struct unicx *cx __unused)
3585 {
3586         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR0_P,
3587                 UNI_TRAFFIC_FPCR0_ID, ie->fpcr0);
3588         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR0_P,
3589                 UNI_TRAFFIC_BPCR0_ID, ie->bpcr0);
3590         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FPCR1_P,
3591                 UNI_TRAFFIC_FPCR1_ID, ie->fpcr1);
3592         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BPCR1_P,
3593                 UNI_TRAFFIC_BPCR1_ID, ie->bpcr1);
3594         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR0_P,
3595                 UNI_TRAFFIC_FSCR0_ID, ie->fscr0);
3596         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR0_P,
3597                 UNI_TRAFFIC_BSCR0_ID, ie->bscr0);
3598         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FSCR1_P,
3599                 UNI_TRAFFIC_FSCR1_ID, ie->fscr1);
3600         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BSCR1_P,
3601                 UNI_TRAFFIC_BSCR1_ID, ie->bscr1);
3602         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS0_P,
3603                 UNI_TRAFFIC_FMBS0_ID, ie->fmbs0);
3604         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS0_P,
3605                 UNI_TRAFFIC_BMBS0_ID, ie->bmbs0);
3606         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FMBS1_P,
3607                 UNI_TRAFFIC_FMBS1_ID, ie->fmbs1);
3608         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BMBS1_P,
3609                 UNI_TRAFFIC_BMBS1_ID, ie->bmbs1);
3610         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_FABR1_P,
3611                 UNI_TRAFFIC_FABR1_ID, ie->fabr1);
3612         APP_OPT_24BIT(msg, present, UNI_TRAFFIC_BABR1_P,
3613                 UNI_TRAFFIC_BABR1_ID, ie->babr1);
3614
3615         APP_OPT(msg, present, UNI_TRAFFIC_BEST_P,
3616                 UNI_TRAFFIC_BEST_ID);
3617         APP_OPT_BYTE(msg, present, UNI_TRAFFIC_MOPT_P,
3618                 UNI_TRAFFIC_MOPT_ID,
3619                 (ie->ftag ? UNI_TRAFFIC_FTAG : 0) |
3620                 (ie->btag ? UNI_TRAFFIC_BTAG : 0) |
3621                 (ie->fdisc ? UNI_TRAFFIC_FDISC : 0) |
3622                 (ie->fdisc ? UNI_TRAFFIC_BDISC : 0));
3623
3624         return 0;
3625 }
3626
3627 static int
3628 decode_traffic_common(struct uni_xtraffic *ie, struct uni_msg *msg,
3629     u_int ielen, u_int *present)
3630 {
3631         u_char c;
3632
3633         while(ielen--) {
3634                 switch(c = *msg->b_rptr++) {
3635
3636                   default:
3637                   rej:
3638                         return -1;
3639
3640                   DEC_GETF3(TRAFFIC_FPCR0, fpcr0, *present);
3641                   DEC_GETF3(TRAFFIC_BPCR0, bpcr0, *present);
3642                   DEC_GETF3(TRAFFIC_FPCR1, fpcr1, *present);
3643                   DEC_GETF3(TRAFFIC_BPCR1, bpcr1, *present);
3644                   DEC_GETF3(TRAFFIC_FSCR0, fscr0, *present);
3645                   DEC_GETF3(TRAFFIC_BSCR0, bscr0, *present);
3646                   DEC_GETF3(TRAFFIC_FSCR1, fscr1, *present);
3647                   DEC_GETF3(TRAFFIC_BSCR1, bscr1, *present);
3648                   DEC_GETF3(TRAFFIC_FMBS0, fmbs0, *present);
3649                   DEC_GETF3(TRAFFIC_BMBS0, bmbs0, *present);
3650                   DEC_GETF3(TRAFFIC_BMBS1, bmbs1, *present);
3651                   DEC_GETF3(TRAFFIC_FABR1, fabr1, *present);
3652                   DEC_GETF3(TRAFFIC_BABR1, babr1, *present);
3653
3654                   case UNI_TRAFFIC_BEST_ID:
3655                         *present |= UNI_TRAFFIC_BEST_P;
3656                         break;
3657
3658                   case UNI_TRAFFIC_MOPT_ID:
3659                         if(ielen == 0)
3660                                 return -1;
3661                         ielen--;
3662                         if(!(*present & UNI_TRAFFIC_MOPT_P)) {
3663                                 *present |= UNI_TRAFFIC_MOPT_P;
3664                                 ie->ftag = (*msg->b_rptr&UNI_TRAFFIC_FTAG)?1:0;
3665                                 ie->btag = (*msg->b_rptr&UNI_TRAFFIC_BTAG)?1:0;
3666                                 ie->fdisc = (*msg->b_rptr&UNI_TRAFFIC_FDISC)?1:0;
3667                                 ie->bdisc = (*msg->b_rptr&UNI_TRAFFIC_BDISC)?1:0;
3668                         } 
3669                         msg->b_rptr++;
3670                         break;
3671                 }
3672         }
3673         return 0;
3674 }
3675
3676
3677 /*****************************************************************/
3678
3679 DEF_IE_PRINT(itu, traffic)
3680 {
3681         if(uni_print_iehdr("traffic", &ie->h, cx))
3682                 return;
3683         print_ie_traffic_common(cx, ie->h.present, &ie->t);
3684         uni_print_ieend(cx);
3685 }
3686
3687 DEF_IE_CHECK(itu, traffic)
3688 {
3689         return check_ie_traffic_common(&ie->t, ie->h.present, cx);
3690 }
3691
3692 DEF_IE_ENCODE(itu, traffic)
3693 {
3694         START_IE(traffic, UNI_IE_TRAFFIC, 26);
3695         encode_traffic_common(msg, &ie->t, ie->h.present, cx);
3696         SET_IE_LEN(msg);
3697         return 0;
3698 }
3699
3700 DEF_IE_DECODE(itu, traffic)
3701 {
3702         IE_START(;);
3703
3704         if(ielen > 30)
3705                 goto rej;
3706
3707         if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present))
3708                 goto rej;
3709
3710         IE_END(TRAFFIC);
3711 }
3712
3713 /*****************************************************************/
3714
3715 DEF_IE_PRINT(itu, atraffic)
3716 {
3717         if(uni_print_iehdr("atraffic", &ie->h, cx))
3718                 return;
3719         print_ie_traffic_common(cx, ie->h.present, &ie->t);
3720         uni_print_ieend(cx);
3721 }
3722
3723 DEF_IE_CHECK(itu, atraffic)
3724 {
3725         return check_ie_traffic_common(&ie->t, ie->h.present, cx);
3726 }
3727
3728 DEF_IE_ENCODE(itu, atraffic)
3729 {
3730         START_IE(traffic, UNI_IE_ATRAFFIC, 26);
3731         encode_traffic_common(msg, &ie->t, ie->h.present, cx);
3732         SET_IE_LEN(msg);
3733         return 0;
3734 }
3735
3736 DEF_IE_DECODE(itu, atraffic)
3737 {
3738         IE_START(;);
3739
3740         if(ielen > 30)
3741                 goto rej;
3742
3743         if(decode_traffic_common(&ie->t, msg, ielen, &ie->h.present))
3744                 goto rej;
3745
3746         IE_END(ATRAFFIC);
3747 }
3748
3749 /*****************************************************************/
3750
3751 DEF_IE_PRINT(itu, mintraffic)
3752 {
3753         if(uni_print_iehdr("mintraffic", &ie->h, cx))
3754                 return;
3755
3756         uni_print_entry(cx, "pcr0", "(");
3757         if(ie->h.present & UNI_MINTRAFFIC_FPCR0_P)
3758                 uni_printf(cx, "%u", ie->fpcr0);
3759         uni_putc(',', cx);
3760         if(ie->h.present & UNI_MINTRAFFIC_BPCR0_P)
3761                 uni_printf(cx, "%u", ie->bpcr0);
3762         uni_putc(')', cx);
3763
3764         uni_print_entry(cx, "pcr1", "(");
3765         if(ie->h.present & UNI_MINTRAFFIC_FPCR1_P)
3766                 uni_printf(cx, "%u", ie->fpcr1);
3767         uni_putc(',', cx);
3768         if(ie->h.present & UNI_MINTRAFFIC_BPCR1_P)
3769                 uni_printf(cx, "%u", ie->bpcr1);
3770         uni_putc(')', cx);
3771
3772         uni_print_entry(cx, "abr1", "(");
3773         if(ie->h.present & UNI_MINTRAFFIC_FABR1_P)
3774                 uni_printf(cx, "%u", ie->fabr1);
3775         uni_putc(',', cx);
3776         if(ie->h.present & UNI_MINTRAFFIC_BABR1_P)
3777                 uni_printf(cx, "%u", ie->babr1);
3778         uni_printf(cx, ")");
3779
3780         uni_print_ieend(cx);
3781 }
3782
3783 DEF_IE_CHECK(itu, mintraffic)
3784 {
3785         u_int abr;
3786         u_int xbr;
3787         cx = cx;
3788
3789         abr = ie->h.present & (UNI_MINTRAFFIC_FABR1_P|UNI_MINTRAFFIC_BABR1_P);
3790         xbr = ie->h.present & (UNI_MINTRAFFIC_FPCR0_P|UNI_MINTRAFFIC_BPCR0_P|
3791                                UNI_MINTRAFFIC_FPCR1_P|UNI_MINTRAFFIC_BPCR1_P);
3792
3793         if(abr && xbr)
3794                 return -1;
3795
3796         return 0;
3797 }
3798
3799 DEF_IE_ENCODE(itu, mintraffic)
3800 {
3801         START_IE(mintraffic, UNI_IE_MINTRAFFIC, 16);
3802
3803         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR0_P,
3804                 UNI_TRAFFIC_FPCR0_ID, ie->fpcr0);
3805         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR0_P,
3806                 UNI_TRAFFIC_BPCR0_ID, ie->bpcr0);
3807         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FPCR1_P,
3808                 UNI_TRAFFIC_FPCR1_ID, ie->fpcr1);
3809         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BPCR1_P,
3810                 UNI_TRAFFIC_BPCR1_ID, ie->bpcr1);
3811         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_FABR1_P,
3812                 UNI_TRAFFIC_FABR1_ID, ie->fabr1);
3813         APP_OPT_24BIT(msg, ie->h.present, UNI_MINTRAFFIC_BABR1_P,
3814                 UNI_TRAFFIC_BABR1_ID, ie->babr1);
3815
3816         SET_IE_LEN(msg);
3817         return 0;
3818 }
3819
3820 DEF_IE_DECODE(itu, mintraffic)
3821 {
3822         u_char c;
3823
3824         IE_START(;);
3825
3826         if(ielen > 20)
3827                 goto rej;
3828
3829         while(ielen--) {
3830                 switch(c = *msg->b_rptr++) {
3831
3832                   default:
3833                         goto rej;
3834
3835                   DEC_GETF3(MINTRAFFIC_FPCR0, fpcr0, ie->h.present);
3836                   DEC_GETF3(MINTRAFFIC_BPCR0, bpcr0, ie->h.present);
3837                   DEC_GETF3(MINTRAFFIC_FPCR1, fpcr1, ie->h.present);
3838                   DEC_GETF3(MINTRAFFIC_BPCR1, bpcr1, ie->h.present);
3839                   DEC_GETF3(MINTRAFFIC_FABR1, fabr1, ie->h.present);
3840                   DEC_GETF3(MINTRAFFIC_BABR1, babr1, ie->h.present);
3841                 }
3842         }
3843
3844         IE_END(MINTRAFFIC);
3845 }
3846
3847 /*****************************************************************/
3848
3849 DEF_IE_PRINT(net, mdcr)
3850 {
3851         static const struct uni_print_tbl origin_tbl[] = {
3852                 MKT(UNI_MDCR_ORIGIN_USER,       user),
3853                 MKT(UNI_MDCR_ORIGIN_NET,        net),
3854                 EOT()
3855         };
3856
3857         if(uni_print_iehdr("mdcr", &ie->h, cx))
3858                 return;
3859
3860         uni_print_tbl("origin", ie->origin, origin_tbl, cx);
3861         uni_print_entry(cx, "mdcr", "(");
3862         uni_printf(cx, "%u", ie->fmdcr);
3863         uni_putc(',', cx);
3864         uni_printf(cx, "%u", ie->bmdcr);
3865         uni_putc(')', cx);
3866
3867         uni_print_ieend(cx);
3868 }
3869
3870 DEF_IE_CHECK(net, mdcr)
3871 {
3872         cx = cx;
3873
3874         if ((ie->origin != UNI_MDCR_ORIGIN_USER &&
3875             ie->origin != UNI_MDCR_ORIGIN_NET) ||
3876             ie->fmdcr >= (1 << 24) || ie->bmdcr >= (1 << 24))
3877                 return (-1);
3878
3879         return (0);
3880 }
3881
3882 DEF_IE_ENCODE(net, mdcr)
3883 {
3884         START_IE(mdcr, UNI_IE_MDCR, 9);
3885
3886         APP_BYTE(msg, ie->origin);
3887         APP_SUB_24BIT(msg, UNI_TRAFFIC_FMDCR_ID, ie->fmdcr);
3888         APP_SUB_24BIT(msg, UNI_TRAFFIC_BMDCR_ID, ie->bmdcr);
3889
3890         SET_IE_LEN(msg);
3891         return (0);
3892 }
3893
3894 DEF_IE_DECODE(net, mdcr)
3895 {
3896         u_char c;
3897 #define UNI_TRAFFIC_FMDCR_P 0x01
3898 #define UNI_TRAFFIC_BMDCR_P 0x02
3899         u_int p = 0;
3900
3901         IE_START(;);
3902
3903         if(ielen != 9)
3904                 goto rej;
3905
3906         ie->origin = *msg->b_rptr++;
3907         ielen--;
3908
3909         while(ielen--) {
3910                 switch(c = *msg->b_rptr++) {
3911
3912                   default:
3913                         goto rej;
3914
3915                   DEC_GETF3(TRAFFIC_FMDCR, fmdcr, p);
3916                   DEC_GETF3(TRAFFIC_BMDCR, bmdcr, p);
3917                 }
3918         }
3919         if (p != (UNI_TRAFFIC_FMDCR_P | UNI_TRAFFIC_BMDCR_P))
3920                 goto rej;
3921
3922         IE_END(MDCR);
3923 }
3924
3925 /*********************************************************************
3926  *
3927  * Connection identifier
3928  *
3929  * References for this IE are:
3930  *
3931  *  Q.2931 pp. 69...70
3932  *  UNI4.0 pp. 15...16
3933  *  PNNI1.0 p. 198
3934  *
3935  * Only ITU-T coding allowed.
3936  */
3937
3938 DEF_IE_PRINT(itu, connid)
3939 {
3940         static const struct uni_print_tbl tbl[] = {
3941                 MKT(UNI_CONNID_VCI,     exclusive),
3942                 MKT(UNI_CONNID_ANYVCI,  any),
3943                 MKT(UNI_CONNID_NOVCI,   no),
3944                 EOT()
3945         };
3946         static const struct uni_print_tbl assoc_tbl[] = {
3947                 MKT(UNI_CONNID_ASSOC,   associated),
3948                 MKT(UNI_CONNID_NONASSOC,non-associated),
3949                 EOT()
3950         };
3951
3952         if(uni_print_iehdr("connid", &ie->h, cx))
3953                 return;
3954
3955         uni_print_tbl("mode", ie->assoc, assoc_tbl, cx);
3956         uni_print_entry(cx, "connid", "(%u,", ie->vpci);
3957         if(ie->type == UNI_CONNID_VCI)
3958                 uni_printf(cx, "%u", ie->vci);
3959         else
3960                 uni_print_tbl(NULL, ie->type, tbl, cx);
3961         uni_printf(cx, ")");
3962
3963         uni_print_ieend(cx);
3964 }
3965
3966 DEF_IE_CHECK(itu, connid)
3967 {
3968         cx = cx;
3969         switch(ie->type) {
3970           default:
3971                 return -1;
3972           case UNI_CONNID_VCI:
3973           case UNI_CONNID_ANYVCI:
3974           case UNI_CONNID_NOVCI:
3975                 break;
3976         }
3977
3978 #if 0
3979         /*
3980          * This field must be checked by the application to fulfil
3981          * Q.2931Amd4 27) 5.2.3 last sentence
3982          */
3983         switch(ie->assoc) {
3984
3985           case UNI_CONNID_ASSOC:
3986                 if(!cx->cx.pnni)
3987                         return -1;
3988                 break;
3989
3990           case UNI_CONNID_NONASSOC:
3991                 break;
3992
3993           default:
3994                 return -1;
3995         }
3996 #endif
3997         return 0;
3998 }
3999
4000 DEF_IE_ENCODE(itu, connid)
4001 {
4002         START_IE(connid, UNI_IE_CONNID, 5);
4003
4004         APP_BYTE(msg, 0x80 | (ie->assoc << 3) | ie->type);
4005         APP_BYTE(msg, ie->vpci >> 8);
4006         APP_BYTE(msg, ie->vpci >> 0);
4007         APP_BYTE(msg, ie->vci >> 8);
4008         APP_BYTE(msg, ie->vci >> 0);
4009
4010         SET_IE_LEN(msg);
4011         return 0;
4012 }
4013
4014 DEF_IE_DECODE(itu, connid)
4015 {
4016         u_char c;
4017
4018         IE_START(;);
4019
4020         if(ielen != 5)
4021                 goto rej;
4022
4023         c = *msg->b_rptr++;
4024         if((c & 0x80) == 0)
4025                 goto rej;
4026         ie->assoc = (c >> 3) & 3;
4027         ie->type = c & 7;
4028         ie->vpci  = *msg->b_rptr++ << 8;
4029         ie->vpci |= *msg->b_rptr++;
4030         ie->vci  = *msg->b_rptr++ << 8;
4031         ie->vci |= *msg->b_rptr++;
4032
4033         IE_END(CONNID);
4034 }
4035
4036 /*********************************************************************
4037  *
4038  * Quality of Service
4039  *
4040  * References for this IE are:
4041  *
4042  *  Q.2931 pp. 72
4043  *  UNI4.0 pp. 16...17
4044  */
4045
4046 static void
4047 print_qos(struct unicx *cx, struct uni_ie_qos *ie)
4048 {
4049         static const struct uni_print_tbl class_tbl[] = {
4050                 MKT(UNI_QOS_CLASS0,     Class0),
4051                 MKT(UNI_QOS_CLASS1,     Class1),
4052                 MKT(UNI_QOS_CLASS2,     Class2),
4053                 MKT(UNI_QOS_CLASS3,     Class3),
4054                 MKT(UNI_QOS_CLASS4,     Class4),
4055                 EOT()
4056         };
4057
4058         if(uni_print_iehdr("qos", &ie->h, cx))
4059                 return;
4060
4061         uni_print_tbl("fwd", ie->fwd, class_tbl, cx);
4062         uni_print_tbl("bwd", ie->bwd, class_tbl, cx);
4063
4064         uni_print_ieend(cx);
4065 }
4066
4067 DEF_IE_PRINT(itu, qos)
4068 {
4069         print_qos(cx, ie);
4070 }
4071 DEF_IE_PRINT(net, qos)
4072 {
4073         print_qos(cx, ie);
4074 }
4075
4076 DEF_IE_CHECK(itu, qos)
4077 {
4078         cx = cx;
4079
4080         switch(ie->fwd) {
4081           default:
4082                 return -1;
4083
4084           case UNI_QOS_CLASS0:
4085                 break;
4086         }
4087         switch(ie->bwd) {
4088           default:
4089                 return -1;
4090
4091           case UNI_QOS_CLASS0:
4092                 break;
4093         }
4094         return 0;
4095 }
4096
4097 DEF_IE_CHECK(net, qos)
4098 {
4099         cx = cx;
4100
4101         switch(ie->fwd) {
4102           default:
4103                 return -1;
4104
4105           case UNI_QOS_CLASS1:
4106           case UNI_QOS_CLASS2:
4107           case UNI_QOS_CLASS3:
4108           case UNI_QOS_CLASS4:
4109                 break;
4110         }
4111         switch(ie->bwd) {
4112           default:
4113                 return -1;
4114
4115           case UNI_QOS_CLASS1:
4116           case UNI_QOS_CLASS2:
4117           case UNI_QOS_CLASS3:
4118           case UNI_QOS_CLASS4:
4119                 break;
4120         }
4121         return 0;
4122 }
4123
4124 DEF_IE_ENCODE(itu, qos)
4125 {
4126         START_IE(qos, UNI_IE_QOS, 2);
4127
4128         APP_BYTE(msg, ie->fwd);
4129         APP_BYTE(msg, ie->bwd);
4130
4131         SET_IE_LEN(msg);
4132         return 0;
4133 }
4134 DEF_IE_ENCODE(net, qos)
4135 {
4136         START_IE(qos, UNI_IE_QOS, 2);
4137
4138         APP_BYTE(msg, ie->fwd);
4139         APP_BYTE(msg, ie->bwd);
4140
4141         SET_IE_LEN(msg);
4142         return 0;
4143 }
4144
4145 DEF_IE_DECODE(itu, qos)
4146 {
4147         IE_START(;);
4148
4149         if(ielen != 2)
4150                 goto rej;
4151
4152         ie->fwd = *msg->b_rptr++;
4153         ie->bwd = *msg->b_rptr++;
4154
4155         IE_END(QOS);
4156 }
4157
4158 DEF_IE_DECODE(net, qos)
4159 {
4160         IE_START(;);
4161
4162         if(ielen != 2)
4163                 goto rej;
4164
4165         ie->fwd = *msg->b_rptr++;
4166         ie->bwd = *msg->b_rptr++;
4167
4168         IE_END(QOS);
4169 }
4170
4171 /*********************************************************************
4172  *
4173  * Broadband Lower Layer Information
4174  *
4175  * References for this IE are:
4176  *
4177  *  Q.2931 pp. 53...54
4178  *  UNI4.0 p.  12
4179  *
4180  * Only ITU-T coding allowed.
4181  */
4182
4183 DEF_IE_PRINT(itu, bhli)
4184 {
4185         static const struct uni_print_tbl type_tbl[] = {
4186                 MKT(UNI_BHLI_ISO,       iso),
4187                 MKT(UNI_BHLI_USER,      user),
4188                 MKT(UNI_BHLI_VENDOR,    vendor),
4189                 EOT()
4190         };
4191         u_int i;
4192
4193         if(uni_print_iehdr("bhli", &ie->h, cx))
4194                 return;
4195
4196         uni_print_tbl("type", ie->type, type_tbl, cx);
4197         uni_print_entry(cx, "len", "%d", ie->len);
4198         uni_print_entry(cx, "info", "(");
4199         for(i = 0; i < ie->len; i++)
4200                 uni_printf(cx, ",0x%02x", ie->info[i]);
4201         uni_printf(cx, ")");
4202
4203         uni_print_ieend(cx);
4204 }
4205
4206 DEF_IE_CHECK(itu, bhli)
4207 {
4208         cx = cx;
4209
4210         switch(ie->type) {
4211           default:
4212                 return -1;
4213
4214           case UNI_BHLI_ISO:
4215           case UNI_BHLI_USER:
4216           case UNI_BHLI_VENDOR:
4217                 break;
4218         }
4219         if(ie->len > 8)
4220                 return -1;
4221
4222         return 0;
4223 }
4224
4225 DEF_IE_ENCODE(itu, bhli)
4226 {
4227         START_IE(bhli, UNI_IE_BHLI, 9);
4228
4229         APP_BYTE(msg, 0x80 | ie->type);
4230         APP_BUF(msg, ie->info, ie->len);
4231
4232         SET_IE_LEN(msg);
4233         return 0;
4234 }
4235
4236 DEF_IE_DECODE(itu, bhli)
4237 {
4238         u_char c;
4239
4240         IE_START(;);
4241
4242         if(ielen > 9)
4243                 goto rej;
4244
4245         c = *msg->b_rptr++;
4246         ielen--;
4247
4248         if(!(c & 0x80))
4249                 goto rej;
4250         ie->type = c & 0x7f;
4251         ie->len = ielen;
4252         (void)memcpy(ie->info, msg->b_rptr, ielen);
4253         msg->b_rptr += ielen;
4254
4255         IE_END(BHLI);
4256 }
4257
4258 /*********************************************************************
4259  *
4260  * Broadband bearer capabilities
4261  *
4262  * References for this IE are:
4263  *
4264  *  Q.2931 pp. 51...52
4265  *  Q.2931 Amd 1
4266  *  UNI4.0 pp. 10...12, 106...109
4267  *
4268  * UNI4.0 changed the meaning of byte 5a. Instead of 3 bit traffic type and
4269  * 2 bit timing requirements there are now 7 bits ATM transfer capabilities.
4270  * However the old format is still supported: it should be recognized on
4271  * input, but never be generated on output. Mapping is left to the user of
4272  * UNI.
4273  *
4274  * Amd 1 not checked XXX.
4275  *
4276  * The Appendix in UNI4.0 lists all the supported combinations of various
4277  * traffic IE's. The check function implements part of it.
4278  *
4279  *                      A               C               X               VP
4280  * 1    CBR.1           7               .               7               7
4281  * 2    CBR.2           -               .               4,5,6           5   (*)
4282  * 3    CBR.3           -               .               4,5,6           5   (*)
4283  * 4    rt-VBR.1        .               19              19              19
4284  * 5    rt-VBR.2        .               9               1,9             9
4285  * 6    rt-VBR.3        .               9               1,9             9
4286  * 7    rt-VBR.4        .               .               1,9             .   (*)
4287  * 8    rt-VBR.5        .               .               1,9             .   (*)
4288  * 9    rt-VBR.6        .               9               1,9             9   (*)
4289  * 10   nrt-VBR.1       .               11              11              11
4290  * 11   nrt-VBR.2       .               -               -,0,2,8,10      -,10
4291  * 12   nrt-VBR.3       .               -               -,0,2,8,10      -,10
4292  * 13   nrt-VBR.4       .               -               -,0,2,8,10      .   (*)
4293  * 14   nrt-VBR.5       .               -               -,0,2,8,10      .   (*)
4294  * 15   nrt-VBR.6       .               -               -,0,2,8,10      -,10(*)
4295  * 16   ABR             .               12              12              12
4296  * 17   UBR.1           .               -               -,0,2,8,10      -,10
4297  * 18   UBR.2           .               -               -,0,2,8,10      -,10
4298  *
4299  * (*) compatibility
4300  *
4301  * Only ITU-T coding allowed.
4302  */
4303
4304 DEF_IE_PRINT(itu, bearer)
4305 {
4306         static const struct uni_print_tbl bclass_tbl[] = {
4307                 MKT(UNI_BEARER_A,       bcob-A),
4308                 MKT(UNI_BEARER_C,       bcob-C),
4309                 MKT(UNI_BEARER_X,       bcob-X),
4310                 MKT(UNI_BEARER_TVP,     transparent-VP),
4311                 EOT()
4312         };
4313         static const struct uni_print_tbl atc_tbl[] = {
4314                 MKT(UNI_BEARER_ATC_CBR,         cbr),
4315                 MKT(UNI_BEARER_ATC_CBR1,        cbr1),
4316                 MKT(UNI_BEARER_ATC_VBR,         vbr),
4317                 MKT(UNI_BEARER_ATC_VBR1,        vbr1),
4318                 MKT(UNI_BEARER_ATC_NVBR,        nvbr),
4319                 MKT(UNI_BEARER_ATC_NVBR1,       nvbr1),
4320                 MKT(UNI_BEARER_ATC_ABR,         abr),
4321
4322                 MKT(UNI_BEARER_ATCX_0,          x0),
4323                 MKT(UNI_BEARER_ATCX_1,          x1),
4324                 MKT(UNI_BEARER_ATCX_2,          x2),
4325                 MKT(UNI_BEARER_ATCX_4,          x4),
4326                 MKT(UNI_BEARER_ATCX_6,          x6),
4327                 MKT(UNI_BEARER_ATCX_8,          x8),
4328                 EOT()
4329         };
4330         static const struct uni_print_tbl cfg_tbl[] = {
4331                 MKT(UNI_BEARER_P2P,     p2p),
4332                 MKT(UNI_BEARER_MP,      mp),
4333                 EOT()
4334         };
4335         static const struct uni_print_tbl clip_tbl[] = {
4336                 MKT(UNI_BEARER_NOCLIP,  no),
4337                 MKT(UNI_BEARER_CLIP,    yes),
4338                 EOT()
4339         };
4340
4341         if(uni_print_iehdr("bearer", &ie->h, cx))
4342                 return;
4343
4344         uni_print_tbl("class", ie->bclass, bclass_tbl, cx);
4345
4346         if(ie->h.present & UNI_BEARER_ATC_P) {
4347                 uni_print_tbl("atc", ie->atc, atc_tbl, cx);
4348         }
4349         uni_print_tbl("clip", ie->clip, clip_tbl, cx);
4350         uni_print_tbl("cfg", ie->cfg, cfg_tbl, cx);
4351
4352         uni_print_ieend(cx);
4353 }
4354
4355 #define QTYPE(C,A)      ((UNI_BEARER_##C << 8) | UNI_BEARER_ATC_##A)
4356 #define QTYPEX(C,A)     ((UNI_BEARER_##C << 8) | UNI_BEARER_ATCX_##A)
4357 #define QTYPE0(C)       ((UNI_BEARER_##C << 8) | (1 << 16))
4358 DEF_IE_CHECK(itu, bearer)
4359 {
4360         cx = cx;
4361
4362         switch((ie->bclass << 8) |
4363                ((ie->h.present & UNI_BEARER_ATC_P) == 0
4364                         ? (1 << 16)
4365                         : ie->atc)) {
4366
4367           default:
4368                 return -1;
4369
4370           case QTYPE (A,   CBR1):       /* 1 */
4371           case QTYPE (X,   CBR1):       /* 1 */
4372           case QTYPE (TVP, CBR1):       /* 1 */
4373
4374           case QTYPE0(A):               /* 2,3 */
4375           case QTYPEX(X,   4):          /* 2,3 */
4376           case QTYPE (X,   CBR):        /* 2,3 */
4377           case QTYPEX(X,   6):          /* 2,3 */
4378           case QTYPE (TVP, CBR):        /* 2,3 */
4379
4380           case QTYPE (C,   VBR1):       /* 4 */
4381           case QTYPE (X,   VBR1):       /* 4 */
4382           case QTYPE (TVP, VBR1):       /* 4 */
4383
4384           case QTYPE (C,   VBR):        /* 5,6,9 */
4385           case QTYPEX(X,   1):          /* 5,6,7,8,9 */
4386           case QTYPE (X,   VBR):        /* 5,6,7,8,9 */
4387           case QTYPE (TVP, VBR):        /* 5,6,9 */
4388
4389           case QTYPE (C,   NVBR1):      /* 10 */
4390           case QTYPE (X,   NVBR1):      /* 10 */
4391           case QTYPE (TVP, NVBR1):      /* 10 */
4392
4393           case QTYPE0(C):               /* 11,12,13,14,15,17,18 */
4394           case QTYPE0(X):               /* 11,12,13,14,15,17,18 */
4395           case QTYPEX(X,   0):          /* 11,12,13,14,15,17,18 */
4396           case QTYPEX(X,   2):          /* 11,12,13,14,15,17,18 */
4397           case QTYPEX(X,   8):          /* 11,12,13,14,15,17,18 */
4398           case QTYPE (X,   NVBR):       /* 11,12,13,14,15,17,18 */
4399           case QTYPE0(TVP):             /* 11,12,15,17,18 */
4400           case QTYPE (TVP, NVBR):       /* 11,12,15,17,18 */
4401
4402           case QTYPE (C,   ABR):        /* 16 */
4403           case QTYPE (X,   ABR):        /* 16 */
4404           case QTYPE (TVP, ABR):        /* 16 */
4405                 break;
4406         }
4407
4408         switch(ie->clip) {
4409           default:
4410                 return -1;
4411
4412           case UNI_BEARER_NOCLIP:
4413           case UNI_BEARER_CLIP:
4414                 break;
4415         }
4416         switch(ie->cfg) {
4417           default:
4418                 return -1;
4419
4420           case UNI_BEARER_P2P:
4421           case UNI_BEARER_MP:
4422                 break;
4423         }
4424
4425         return 0;
4426 }
4427 #undef QTYPE
4428 #undef QTYPEX
4429 #undef QTYPE0
4430
4431 DEF_IE_ENCODE(itu, bearer)
4432 {
4433         START_IE(bearer, UNI_IE_BEARER, 3);
4434
4435         APP_BYTE(msg, ie->bclass |
4436                 ((ie->h.present & UNI_BEARER_ATC_P) ? 0:0x80));
4437         APP_OPT(msg, ie->h.present, UNI_BEARER_ATC_P,
4438                 0x80 | ie->atc);
4439         APP_BYTE(msg, 0x80 | (ie->clip << 5) | ie->cfg);
4440
4441         SET_IE_LEN(msg);
4442         return 0;
4443 }
4444
4445 DEF_IE_DECODE(itu, bearer)
4446 {
4447         u_char c;
4448
4449         IE_START(;);
4450
4451         if(ielen != 2 && ielen != 3)
4452                 goto rej;
4453
4454         c = *msg->b_rptr++;
4455         ielen--;
4456         ie->bclass = c & 0x1f;
4457         if(!(c & 0x80)) {
4458                 c = *msg->b_rptr++;
4459                 ielen--;
4460                 ie->h.present |= UNI_BEARER_ATC_P;
4461
4462                 switch(c & 0x7f) {
4463                   /*
4464                    * Real legal values
4465                    */
4466                   case UNI_BEARER_ATC_CBR:
4467                   case UNI_BEARER_ATC_CBR1:
4468                   case UNI_BEARER_ATC_VBR:
4469                   case UNI_BEARER_ATC_VBR1:
4470                   case UNI_BEARER_ATC_NVBR:
4471                   case UNI_BEARER_ATC_NVBR1:
4472                   case UNI_BEARER_ATC_ABR:
4473                         break;
4474
4475                   /*
4476                    * Compat values
4477                    */
4478                   case UNI_BEARER_ATCX_0:
4479                   case UNI_BEARER_ATCX_1:
4480                   case UNI_BEARER_ATCX_2:
4481                   case UNI_BEARER_ATCX_4:
4482                   case UNI_BEARER_ATCX_6:
4483                   case UNI_BEARER_ATCX_8:
4484                         break;
4485
4486                   default:
4487                         goto rej;
4488                 }
4489
4490                 if(!(c & 0x80))
4491                         goto rej;
4492
4493                 ie->atc = c & 0x7f;
4494         }
4495         if(ielen == 0)
4496                 goto rej;
4497         c = *msg->b_rptr++;
4498         ielen--;
4499         if(!(c & 0x80))
4500                 goto rej;
4501         ie->clip = (c >> 5) & 0x3;
4502         ie->cfg = c & 0x3;
4503
4504         IE_END(BEARER);
4505 }
4506
4507 /*********************************************************************
4508  *
4509  * Broadband Lower Layer Information
4510  *
4511  * References for this IE are:
4512  *
4513  *  Q.2931 pp. 54...59
4514  *  UNI4.0 pp. 12...14
4515  *
4516  * UNI4.0 states, that layer 1 info is not supported.
4517  * We allow a layer 1 protocol identifier.
4518  *
4519  * UNI4.0 states, that the layer information subelements are NOT position
4520  * dependent. We allow them in any order on input, but generate always the
4521  * definit order on output.
4522  *
4523  * Only ITU-T coding allowed.
4524  */
4525
4526 DEF_IE_PRINT(itu, blli)
4527 {
4528         static const struct uni_print_tbl l2_tbl[] = {
4529                 MKT(UNI_BLLI_L2_BASIC,          basic),
4530                 MKT(UNI_BLLI_L2_Q921,           Q921),
4531                 MKT(UNI_BLLI_L2_X25LL,          X25-LL),
4532                 MKT(UNI_BLLI_L2_X25ML,          X25-ML),
4533                 MKT(UNI_BLLI_L2_LABP,           LAPB),
4534                 MKT(UNI_BLLI_L2_HDLC_ARM,       HDLC-ARM),
4535                 MKT(UNI_BLLI_L2_HDLC_NRM,       HDLC-NRM),
4536                 MKT(UNI_BLLI_L2_HDLC_ABM,       HDLC-ABM),
4537                 MKT(UNI_BLLI_L2_LAN,            LAN),
4538                 MKT(UNI_BLLI_L2_X75,            X75),
4539                 MKT(UNI_BLLI_L2_Q922,           Q922),
4540                 MKT(UNI_BLLI_L2_USER,           user),
4541                 MKT(UNI_BLLI_L2_ISO7776,        ISO7776),
4542                 EOT()
4543         };
4544         static const struct uni_print_tbl l2mode_tbl[] = {
4545                 MKT(UNI_BLLI_L2NORM,            normal),
4546                 MKT(UNI_BLLI_L2EXT,             extended),
4547                 EOT()
4548         };
4549         static const struct uni_print_tbl l3_tbl[] = {
4550                 MKT(UNI_BLLI_L3_X25,            X25),
4551                 MKT(UNI_BLLI_L3_ISO8208,        ISO8208),
4552                 MKT(UNI_BLLI_L3_X223,           X223),
4553                 MKT(UNI_BLLI_L3_CLMP,           CLMP),
4554                 MKT(UNI_BLLI_L3_T70,            T70),
4555                 MKT(UNI_BLLI_L3_TR9577,         TR9577),
4556                 MKT(UNI_BLLI_L3_USER,           user),
4557                 MKT(UNI_BLLI_L3_H310,           H310),
4558                 MKT(UNI_BLLI_L3_H321,           H321),
4559                 EOT()
4560         };
4561         static const struct uni_print_tbl l3mode_tbl[] = {
4562                 MKT(UNI_BLLI_L3NSEQ,            normal-seq),
4563                 MKT(UNI_BLLI_L3ESEQ,            extended-seq),
4564                 EOT()
4565         };
4566         static const struct uni_print_tbl l3psiz_tbl[] = {
4567                 MKT(UNI_BLLI_L3_16,     16),
4568                 MKT(UNI_BLLI_L3_32,     32),
4569                 MKT(UNI_BLLI_L3_64,     64),
4570                 MKT(UNI_BLLI_L3_128,    128),
4571                 MKT(UNI_BLLI_L3_256,    256),
4572                 MKT(UNI_BLLI_L3_512,    512),
4573                 MKT(UNI_BLLI_L3_1024,   1024),
4574                 MKT(UNI_BLLI_L3_2048,   2048),
4575                 MKT(UNI_BLLI_L3_4096,   4096),
4576                 EOT()
4577         };
4578         static const struct uni_print_tbl l3ttype_tbl[] = {
4579                 MKT(UNI_BLLI_L3_TTYPE_RECV,     receive_only),
4580                 MKT(UNI_BLLI_L3_TTYPE_SEND,     send_only),
4581                 MKT(UNI_BLLI_L3_TTYPE_BOTH,     both),
4582                 EOT()
4583         };
4584         static const struct uni_print_tbl l3mux_tbl[] = {
4585                 MKT(UNI_BLLI_L3_MUX_NOMUX,      NOMUX),
4586                 MKT(UNI_BLLI_L3_MUX_TS,         TS),
4587                 MKT(UNI_BLLI_L3_MUX_TSFEC,      TSFEC),
4588                 MKT(UNI_BLLI_L3_MUX_PS,         PS),
4589                 MKT(UNI_BLLI_L3_MUX_PSFEC,      PSFEC),
4590                 MKT(UNI_BLLI_L3_MUX_H221,       H221),
4591                 EOT()
4592         };
4593         static const struct uni_print_tbl l3tcap_tbl[] = {
4594                 MKT(UNI_BLLI_L3_TCAP_NOIND,     noind),
4595                 MKT(UNI_BLLI_L3_TCAP_AAL1,      aal1),
4596                 MKT(UNI_BLLI_L3_TCAP_AAL5,      aal5),
4597                 MKT(UNI_BLLI_L3_TCAP_AAL15,     aal1&5),
4598                 EOT()
4599         };
4600
4601         if(uni_print_iehdr("blli", &ie->h, cx))
4602                 return;
4603
4604         if(ie->h.present & UNI_BLLI_L1_P) {
4605                 uni_print_entry(cx, "l1", "%u", ie->l1);
4606                 uni_print_eol(cx);
4607         }
4608         if(ie->h.present & UNI_BLLI_L2_P) {
4609                 uni_print_tbl("l2", ie->l2, l2_tbl, cx);
4610                 uni_print_push_prefix("l2", cx);
4611                 cx->indent++;
4612                 if(ie->h.present & UNI_BLLI_L2_USER_P)
4613                         uni_print_entry(cx, "proto", "%u", ie->l2_user);
4614                 if(ie->h.present & UNI_BLLI_L2_Q933_P) {
4615                         uni_print_entry(cx, "q933", "%u", ie->l2_q933);
4616                         uni_print_tbl("mode", ie->l2_mode, l2mode_tbl, cx);
4617                 }
4618                 if(ie->h.present & UNI_BLLI_L2_WSIZ_P)
4619                         uni_print_entry(cx, "wsize", "%u", ie->l2_wsiz);
4620                 uni_print_pop_prefix(cx);
4621                 cx->indent--;
4622                 uni_print_eol(cx);
4623
4624         }
4625         if(ie->h.present & UNI_BLLI_L3_P) {
4626                 uni_print_tbl("l3", ie->l3, l3_tbl, cx);
4627                 uni_print_push_prefix("l3", cx);
4628                 cx->indent++;
4629                 if(ie->h.present & UNI_BLLI_L3_USER_P)
4630                         uni_print_entry(cx, "proto", "%u", ie->l3_user);
4631                 if(ie->h.present & UNI_BLLI_L3_MODE_P)
4632                         uni_print_tbl("mode", ie->l3_mode, l3mode_tbl, cx);
4633                 if(ie->h.present & UNI_BLLI_L3_PSIZ_P)
4634                         uni_print_tbl("packet-size", ie->l3_psiz, l3psiz_tbl, cx);
4635                 if(ie->h.present & UNI_BLLI_L3_WSIZ_P)
4636                         uni_print_entry(cx, "window-size", "%u", ie->l3_wsiz);
4637                 if(ie->h.present & UNI_BLLI_L3_TTYPE_P) {
4638                         uni_print_tbl("ttype", ie->l3_ttype, l3ttype_tbl, cx);
4639                         uni_print_tbl("tcap", ie->l3_tcap, l3tcap_tbl, cx);
4640                 }
4641                 if(ie->h.present & UNI_BLLI_L3_MUX_P) {
4642                         uni_print_tbl("fmux", ie->l3_fmux, l3mux_tbl, cx);
4643                         uni_print_tbl("bmux", ie->l3_bmux, l3mux_tbl, cx);
4644                 }
4645                 if(ie->h.present & UNI_BLLI_L3_IPI_P)
4646                         uni_print_entry(cx, "ipi", "0x%02x", ie->l3_ipi);
4647                 if(ie->h.present & UNI_BLLI_L3_SNAP_P)
4648                         uni_print_entry(cx, "snap", "%06x.%04x", ie->oui, ie->pid);
4649                 uni_print_pop_prefix(cx);
4650                 cx->indent--;
4651                 uni_print_eol(cx);
4652         }
4653
4654         uni_print_ieend(cx);
4655 }
4656
4657 DEF_IE_CHECK(itu, blli)
4658 {
4659         cx = cx;
4660 /*
4661         if(ie->h.present & UNI_BLLI_L1_P)
4662                 ;
4663 */
4664
4665         if(ie->h.present & UNI_BLLI_L2_P) {
4666                 static u_int mask =
4667                         UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P |
4668                         UNI_BLLI_L2_USER_P;
4669
4670                 switch(ie->l2) {
4671                   default:
4672                         return -1;
4673
4674                   case UNI_BLLI_L2_BASIC:
4675                   case UNI_BLLI_L2_Q921:
4676                   case UNI_BLLI_L2_LABP:
4677                   case UNI_BLLI_L2_LAN:
4678                   case UNI_BLLI_L2_X75:
4679                         if(ie->h.present & mask)
4680                                 return -1;
4681                         break;
4682
4683                   case UNI_BLLI_L2_X25LL:
4684                   case UNI_BLLI_L2_X25ML:
4685                   case UNI_BLLI_L2_HDLC_ARM:
4686                   case UNI_BLLI_L2_HDLC_NRM:
4687                   case UNI_BLLI_L2_HDLC_ABM:
4688                   case UNI_BLLI_L2_Q922:
4689                   case UNI_BLLI_L2_ISO7776:
4690                         switch(ie->h.present & mask) {
4691                           default:
4692                                 return -1;
4693
4694                           case 0:
4695                           case UNI_BLLI_L2_Q933_P:
4696                           case UNI_BLLI_L2_Q933_P | UNI_BLLI_L2_WSIZ_P:
4697                                 break;
4698                         }
4699                         break;
4700
4701                   case UNI_BLLI_L2_USER:
4702                         switch(ie->h.present & mask) {
4703                           default:
4704                                 return -1;
4705
4706                           case 0:       /* XXX ? */
4707                           case UNI_BLLI_L2_USER_P:
4708                                 break;
4709                         }
4710                         break;
4711                 }
4712                 if(ie->h.present & UNI_BLLI_L2_Q933_P) {
4713                         if(ie->l2_q933 != 0)
4714                                 return -1;
4715
4716                         switch(ie->l2_mode) {
4717                           default:
4718                                 return -1;
4719
4720                           case UNI_BLLI_L2NORM:
4721                           case UNI_BLLI_L2EXT:
4722                                 break;
4723                         }
4724                 }
4725                 if(ie->h.present & UNI_BLLI_L2_WSIZ_P) {
4726                         if(ie->l2_wsiz == 0 || ie->l2_wsiz > 127)
4727                                 return -1;
4728                 }
4729                 if(ie->h.present & UNI_BLLI_L2_USER_P) {
4730                         if(ie->l2_user > 127)
4731                                 return -1;
4732                 }
4733         }
4734         if(ie->h.present & UNI_BLLI_L3_P) {
4735                 static u_int mask =
4736                         UNI_BLLI_L3_MODE_P | UNI_BLLI_L3_PSIZ_P |
4737                         UNI_BLLI_L3_WSIZ_P | UNI_BLLI_L3_USER_P |
4738                         UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P |
4739                         UNI_BLLI_L3_TTYPE_P | UNI_BLLI_L3_MUX_P;
4740
4741                 switch(ie->l3) {
4742                   default:
4743                         return -1;
4744
4745                   case UNI_BLLI_L3_X25:
4746                   case UNI_BLLI_L3_ISO8208:
4747                   case UNI_BLLI_L3_X223:
4748                         switch(ie->h.present & mask) {
4749                           default:
4750                                 return -1;
4751
4752                           case 0:
4753                           case UNI_BLLI_L3_MODE_P:
4754                           case UNI_BLLI_L3_MODE_P |
4755                                UNI_BLLI_L3_PSIZ_P:
4756                           case UNI_BLLI_L3_MODE_P |
4757                                UNI_BLLI_L3_PSIZ_P |
4758                                UNI_BLLI_L3_WSIZ_P:
4759                                 break;
4760                         }
4761                         break;
4762
4763                   case UNI_BLLI_L3_CLMP:
4764                   case UNI_BLLI_L3_T70:
4765                         if(ie->h.present & mask)
4766                                 return -1;
4767                         break;
4768
4769                   case UNI_BLLI_L3_TR9577:
4770                         switch(ie->h.present & mask) {
4771                           default:
4772                                 return -1;
4773
4774                           case 0:
4775                           case UNI_BLLI_L3_IPI_P:
4776                           case UNI_BLLI_L3_IPI_P | UNI_BLLI_L3_SNAP_P:
4777                                 break;
4778                         }
4779                         break;
4780
4781                   case UNI_BLLI_L3_H310:
4782                         switch(ie->h.present & mask) {
4783                           default:
4784                                 return -1;
4785
4786                           case 0:
4787                           case UNI_BLLI_L3_TTYPE_P:
4788                           case UNI_BLLI_L3_TTYPE_P|UNI_BLLI_L3_MUX_P:
4789                                 break;
4790                         }
4791                         break;
4792
4793                   case UNI_BLLI_L3_USER:
4794                         switch(ie->h.present & mask) {
4795                           default:
4796                                 return -1;
4797
4798                           case 0:       /* XXX ? */
4799                           case UNI_BLLI_L3_USER_P:
4800                                 break;
4801                         }
4802                         break;
4803                 }
4804                 if(ie->h.present & UNI_BLLI_L3_MODE_P) {
4805                         switch(ie->l3_mode) {
4806                           default:
4807                                 return -1;
4808
4809                           case UNI_BLLI_L3NSEQ:
4810                           case UNI_BLLI_L3ESEQ:
4811                                 break;
4812                         }
4813                 }
4814                 if(ie->h.present & UNI_BLLI_L3_PSIZ_P) {
4815                         switch(ie->l3_psiz) {
4816                           default:
4817                                 return -1;
4818
4819                           case UNI_BLLI_L3_16:
4820                           case UNI_BLLI_L3_32:
4821                           case UNI_BLLI_L3_64:
4822                           case UNI_BLLI_L3_128:
4823                           case UNI_BLLI_L3_256:
4824                           case UNI_BLLI_L3_512:
4825                           case UNI_BLLI_L3_1024:
4826                           case UNI_BLLI_L3_2048:
4827                           case UNI_BLLI_L3_4096:
4828                                 break;
4829                         }
4830                 }
4831                 if(ie->h.present & UNI_BLLI_L3_WSIZ_P) {
4832                         if(ie->l3_wsiz == 0 || ie->l3_wsiz > 127)
4833                                 return -1;
4834                 }
4835                 if(ie->h.present & UNI_BLLI_L3_IPI_P) {
4836                         if(ie->l3_ipi == UNI_BLLI_L3_SNAP) {
4837                                 if(!(ie->h.present & UNI_BLLI_L3_SNAP_P))
4838                                         return -1;
4839                         } else {
4840                                 if(ie->h.present & UNI_BLLI_L3_SNAP_P)
4841                                         return -1;
4842                         }
4843                 }
4844                 if(ie->h.present & UNI_BLLI_L3_USER_P) {
4845                         if(ie->l3_user > 127)
4846                                 return -1;
4847                 }
4848                 if(ie->h.present & UNI_BLLI_L3_SNAP_P) {
4849                         if(ie->oui >= (1<<24))
4850                                 return -1;
4851                         if(ie->pid >= (1<<16))
4852                                 return -1;
4853                 }
4854                 if(ie->h.present & UNI_BLLI_L3_TTYPE_P) {
4855                         switch(ie->l3_ttype) {
4856                           default:
4857                                 return -1;
4858
4859                           case UNI_BLLI_L3_TTYPE_RECV:
4860                           case UNI_BLLI_L3_TTYPE_SEND:
4861                           case UNI_BLLI_L3_TTYPE_BOTH:
4862                                 break;
4863                         }
4864                         switch(ie->l3_tcap) {
4865                           default:
4866                                 return -1;
4867
4868                           case UNI_BLLI_L3_TCAP_NOIND:
4869                           case UNI_BLLI_L3_TCAP_AAL1:
4870                           case UNI_BLLI_L3_TCAP_AAL5:
4871                           case UNI_BLLI_L3_TCAP_AAL15:
4872                                 break;
4873                         }
4874                 }
4875                 if(ie->h.present & UNI_BLLI_L3_MUX_P) {
4876                         switch(ie->l3_fmux) {
4877                           default:
4878                                 return -1;
4879
4880                           case UNI_BLLI_L3_MUX_NOMUX:
4881                           case UNI_BLLI_L3_MUX_TS:
4882                           case UNI_BLLI_L3_MUX_TSFEC:
4883                           case UNI_BLLI_L3_MUX_PS:
4884                           case UNI_BLLI_L3_MUX_PSFEC:
4885                           case UNI_BLLI_L3_MUX_H221:
4886                                 break;
4887                         }
4888                         switch(ie->l3_bmux) {
4889                           default:
4890                                 return -1;
4891
4892                           case UNI_BLLI_L3_MUX_NOMUX:
4893                           case UNI_BLLI_L3_MUX_TS:
4894                           case UNI_BLLI_L3_MUX_TSFEC:
4895                           case UNI_BLLI_L3_MUX_PS:
4896                           case UNI_BLLI_L3_MUX_PSFEC:
4897                           case UNI_BLLI_L3_MUX_H221:
4898                                 break;
4899                         }
4900                 }
4901         }
4902
4903         return 0;
4904 }
4905
4906 DEF_IE_ENCODE(itu, blli)
4907 {
4908         START_IE(blli, UNI_IE_BLLI, 13);
4909
4910         if (IE_ISERROR(*ie)) {
4911                 APP_BYTE(msg, 0xff);
4912                 APP_BYTE(msg, 0xff);
4913                 goto out;
4914         }
4915
4916         if(ie->h.present & UNI_BLLI_L1_P)
4917                 APP_BYTE(msg, (UNI_BLLI_L1_ID<<5)|ie->l1|0x80);
4918
4919         if(ie->h.present & UNI_BLLI_L2_P) {
4920                 if(ie->h.present & UNI_BLLI_L2_Q933_P) {
4921                         APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2);
4922                         if(ie->h.present & UNI_BLLI_L2_WSIZ_P) {
4923                                 APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933);
4924                                 APP_BYTE(msg, ie->l2_wsiz | 0x80);
4925                         } else {
4926                                 APP_BYTE(msg, (ie->l2_mode<<5)|ie->l2_q933|0x80);
4927                         }
4928                 } else if(ie->h.present & UNI_BLLI_L2_USER_P) {
4929                         APP_BYTE(msg, (UNI_BLLI_L2_ID<<5)|ie->l2);
4930                         APP_BYTE(msg, ie->l2_user | 0x80);
4931                 } else {
4932                         APP_BYTE(msg, (UNI_BLLI_L2_ID << 5) | ie->l2 | 0x80);
4933                 }
4934         }
4935
4936         if(ie->h.present & UNI_BLLI_L3_P) {
4937                 if(ie->h.present & UNI_BLLI_L3_MODE_P) {
4938                         if(ie->h.present & UNI_BLLI_L3_PSIZ_P) {
4939                                 if(ie->h.present & UNI_BLLI_L3_WSIZ_P) {
4940                                         APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3);
4941                                         APP_BYTE(msg,(ie->l3_mode<<5));
4942                                         APP_BYTE(msg,ie->l3_psiz);
4943                                         APP_BYTE(msg,ie->l3_wsiz|0x80);
4944                                 } else {
4945                                         APP_BYTE(msg,(UNI_BLLI_L3_ID<<5)|ie->l3);
4946                                         APP_BYTE(msg,(ie->l3_mode<<5));
4947                                         APP_BYTE(msg,(ie->l3_psiz|0x80));
4948                                 }
4949                         } else {
4950                                 APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3);
4951                                 APP_BYTE(msg, (ie->l3_mode<<5)|0x80);
4952                         }
4953                 } else if(ie->h.present & UNI_BLLI_L3_USER_P) {
4954                         APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3);
4955                         APP_BYTE(msg,(ie->l3_user|0x80));
4956                 } else if(ie->h.present & UNI_BLLI_L3_IPI_P) {
4957                         APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3);
4958                         APP_BYTE(msg,((ie->l3_ipi>>1) & 0x7f));
4959                         APP_BYTE(msg,(((ie->l3_ipi&1)<<6)|0x80));
4960                         if(ie->h.present & UNI_BLLI_L3_SNAP_P) {
4961                                 APP_BYTE(msg, 0x80);
4962                                 APP_BYTE(msg, (ie->oui >> 16));
4963                                 APP_BYTE(msg, (ie->oui >>  8));
4964                                 APP_BYTE(msg, (ie->oui >>  0));
4965                                 APP_BYTE(msg, (ie->pid >>  8));
4966                                 APP_BYTE(msg, (ie->pid >>  0));
4967                         }
4968                 } else if(ie->h.present & UNI_BLLI_L3_TTYPE_P) {
4969                         if(ie->h.present & UNI_BLLI_L3_MUX_P) {
4970                                 APP_BYTE(msg, ie->l3_ttype | (ie->l3_tcap << 4));
4971                                 APP_BYTE(msg, 0x80 | (ie->l3_fmux << 3) | ie->l3_bmux);
4972                         } else {
4973                                 APP_BYTE(msg, 0x80 | ie->l3_ttype | (ie->l3_tcap << 4));
4974                         }
4975                 } else {
4976                         APP_BYTE(msg, (UNI_BLLI_L3_ID<<5)|ie->l3|0x80);
4977                 }
4978         }
4979
4980   out:
4981         SET_IE_LEN(msg);
4982         return 0;
4983 }
4984
4985 DEF_IE_DECODE(itu, blli)
4986 {
4987         u_char c;
4988
4989         IE_START(;);
4990
4991         if(ielen > 17)
4992                 goto rej;
4993
4994         while(ielen--) {
4995                 switch(((c = *msg->b_rptr++) >> 5) & 0x3) {
4996                   default:
4997                         goto rej;
4998
4999                   case UNI_BLLI_L1_ID:
5000                         ie->h.present |= UNI_BLLI_L1_P;
5001                         ie->l1 = c & 0x1f;
5002                         if(!(c & 0x80))
5003                                 goto rej;
5004                         break;
5005
5006                   case UNI_BLLI_L2_ID:
5007                         ie->h.present |= UNI_BLLI_L2_P;
5008                         ie->l2 = c & 0x1f;
5009                         if(!(c & 0x80)) {
5010                                 if(ielen == 0)
5011                                         goto rej;
5012                                 ielen--;
5013                                 c = *msg->b_rptr++;
5014                                 if(ie->l2 == UNI_BLLI_L2_USER) {
5015                                         ie->h.present |= UNI_BLLI_L2_USER_P;
5016                                         ie->l2_user = c & 0x7f;
5017                                         if(!(c & 0x80))
5018                                                 goto rej;
5019                                 } else {
5020                                         ie->h.present |= UNI_BLLI_L2_Q933_P;
5021                                         ie->l2_q933 = c & 0x3;
5022                                         ie->l2_mode = (c >> 5) & 0x3;
5023                                         if(!(c & 0x80)) {
5024                                                 if(ielen == 0)
5025                                                         goto rej;
5026                                                 ielen--;
5027                                                 c = *msg->b_rptr++;
5028                                                 ie->h.present |= UNI_BLLI_L2_WSIZ_P;
5029                                                 ie->l2_wsiz = c & 0x7f;
5030                                                 if(!(c & 0x80))
5031                                                         goto rej;
5032                                         }
5033                                 }
5034                         }
5035                         break;
5036
5037                   case UNI_BLLI_L3_ID:
5038                         ie->h.present |= UNI_BLLI_L3_P;
5039                         ie->l3 = c & 0x1f;
5040                         if(!(c & 0x80)) {
5041                                 switch(ie->l3) {
5042                                   default:
5043                                   case UNI_BLLI_L3_CLMP:
5044                                   case UNI_BLLI_L3_T70:
5045                                         goto rej;
5046
5047                                   case UNI_BLLI_L3_X25:
5048                                   case UNI_BLLI_L3_ISO8208:
5049                                   case UNI_BLLI_L3_X223:
5050                                         if(ielen == 0)
5051                                                 goto rej;
5052                                         ielen--;
5053                                         c = *msg->b_rptr++;
5054                                         ie->l3_mode = (c >> 5) & 0x3;
5055                                         ie->h.present |= UNI_BLLI_L3_MODE_P;
5056
5057                                         if(c & 0x80)
5058                                                 break;
5059
5060                                         if(ielen == 0)
5061                                                 goto rej;
5062                                         ielen--;
5063                                         c = *msg->b_rptr++;
5064                                         ie->l3_psiz = c & 0xf;
5065                                         ie->h.present |= UNI_BLLI_L3_PSIZ_P;
5066
5067                                         if(c & 0x80)
5068                                                 break;
5069
5070                                         if(ielen == 0)
5071                                                 goto rej;
5072                                         ielen--;
5073                                         c = *msg->b_rptr++;
5074                                         ie->l3_wsiz = c & 0x7f;
5075                                         ie->h.present |= UNI_BLLI_L3_WSIZ_P;
5076
5077                                         if(!(c & 0x80))
5078                                                 goto rej;
5079                                         break;
5080
5081                                   case UNI_BLLI_L3_TR9577:
5082                                         if(ielen < 2)
5083                                                 goto rej;
5084                                         ielen -= 2;
5085                                         c = *msg->b_rptr++;
5086                                         ie->l3_ipi = (c << 1) & 0xfe;
5087                                         if(c & 0x80)
5088                                                 goto rej;
5089                                         c = *msg->b_rptr++;
5090                                         ie->l3_ipi |= c & 1;
5091                                         if(!(c & 0x80))
5092                                                 goto rej;
5093                                         ie->h.present |= UNI_BLLI_L3_IPI_P;
5094
5095                                         if(ie->l3_ipi != UNI_BLLI_L3_SNAP)
5096                                                 break;
5097                                         if(ielen < 6)
5098                                                 goto rej;
5099                                         ielen -= 6;
5100                                         if(*msg->b_rptr++ != 0x80)
5101                                                 goto rej;
5102                                         ie->h.present |= UNI_BLLI_L3_SNAP_P;
5103                                         ie->oui  = *msg->b_rptr++ << 16;
5104                                         ie->oui |= *msg->b_rptr++ << 8;
5105                                         ie->oui |= *msg->b_rptr++;
5106                                         ie->pid  = *msg->b_rptr++ << 8;
5107                                         ie->pid |= *msg->b_rptr++;
5108                                         break;
5109
5110                                   case UNI_BLLI_L3_H310:
5111                                         if(ielen == 0)
5112                                                 goto rej;
5113                                         ielen--;
5114                                         c = *msg->b_rptr++;
5115                                         ie->l3_ttype = c & 0xf;
5116                                         ie->l3_tcap = (c >> 4) & 0x7;
5117                                         ie->h.present |= UNI_BLLI_L3_TTYPE_P;
5118                                         if(c & 0x80)
5119                                                 break;
5120                                         if(ielen == 0)
5121                                                 goto rej;
5122                                         ielen--;
5123                                         c = *msg->b_rptr++;
5124                                         ie->l3_fmux = (c >> 3) & 7;
5125                                         ie->l3_bmux = c & 7;
5126                                         ie->h.present |= UNI_BLLI_L3_MUX_P;
5127                                         if(!(c & 0x80))
5128                                                 goto rej;
5129                                         break;
5130
5131                                   case UNI_BLLI_L3_USER:
5132                                         if(ielen == 0)
5133                                                 goto rej;
5134                                         ielen--;
5135                                         c = *msg->b_rptr++;
5136                                         ie->l3_user = c & 0x7f;
5137                                         ie->h.present |= UNI_BLLI_L3_USER_P;
5138                                         if(!(c & 0x80))
5139                                                 goto rej;
5140                                         break;
5141                                 }
5142                         }
5143                         break;
5144                 }
5145         }
5146
5147         IE_END(BLLI);
5148 }
5149
5150 /*********************************************************************
5151  *
5152  * Broadband locking shift
5153  * Broadband non-locking shift.
5154  *
5155  * References for this IE are:
5156  *
5157  *  Q.2931 pp. 41...42
5158  *  UNI4.0 pp. 9
5159  *
5160  * Procedure not supported in UNI4.0, but IE's must be recognized.
5161  *
5162  * Only ITU-T coding allowed.
5163  */
5164
5165 DEF_IE_PRINT(itu, lshift)
5166 {
5167         if(uni_print_iehdr("locking_shift", &ie->h, cx))
5168                 return;
5169         uni_print_ieend(cx);
5170 }
5171
5172 DEF_IE_CHECK(itu, lshift)
5173 {
5174         cx = cx; ie = ie;
5175         return -1;
5176 }
5177
5178 DEF_IE_ENCODE(itu, lshift)
5179 {
5180         START_IE(lshift, UNI_IE_LSHIFT, 1);
5181         APP_BYTE(msg, 0x80 | ie->set);
5182         SET_IE_LEN(msg);
5183         return 0;
5184 }
5185
5186 DEF_IE_DECODE(itu, lshift)
5187 {
5188         u_char c;
5189
5190         IE_START(;);
5191
5192         if(ielen != 1)
5193                 goto rej;
5194
5195         c = *msg->b_rptr++;
5196
5197         if(!(c & 0x80))
5198                 goto rej;
5199         ie->set = c & 7;
5200
5201         IE_END(LSHIFT);
5202 }
5203
5204 /***********************************************************************/
5205
5206 DEF_IE_PRINT(itu, nlshift)
5207 {
5208         if(uni_print_iehdr("nonlocking_shift", &ie->h, cx))
5209                 return;
5210         uni_print_ieend(cx);
5211 }
5212
5213 DEF_IE_CHECK(itu, nlshift)
5214 {
5215         cx = cx; ie = ie;
5216         return -1;
5217 }
5218
5219 DEF_IE_ENCODE(itu, nlshift)
5220 {
5221         START_IE(nlshift, UNI_IE_NLSHIFT, 1);
5222         APP_BYTE(msg, 0x80 | ie->set);
5223         SET_IE_LEN(msg);
5224         return 0;
5225 }
5226
5227 DEF_IE_DECODE(itu, nlshift)
5228 {
5229         u_char c;
5230
5231         IE_START(;);
5232
5233         if(ielen != 1)
5234                 goto rej;
5235
5236         c = *msg->b_rptr++;
5237
5238         if(!(c & 0x80))
5239                 goto rej;
5240         ie->set = c & 7;
5241
5242         IE_END(NLSHIFT);
5243 }
5244
5245 /*********************************************************************
5246  *
5247  * Broadband Sending Complete Indicator
5248  *
5249  * References for this IE are:
5250  *
5251  *  Q.2931 pp. 74-75
5252  *
5253  * Only ITU-T coding allowed.
5254  */
5255 DEF_IE_PRINT(itu, scompl)
5256 {
5257         if(uni_print_iehdr("sending_complete", &ie->h, cx))
5258                 return;
5259         uni_print_ieend(cx);
5260 }
5261
5262 DEF_IE_CHECK(itu, scompl)
5263 {
5264         ie = ie; cx = cx;
5265         return 0;
5266 }
5267
5268 DEF_IE_ENCODE(itu, scompl)
5269 {
5270         START_IE(scompl, UNI_IE_SCOMPL, 1);
5271
5272         APP_BYTE(msg, 0x80 | 0x21);
5273
5274         SET_IE_LEN(msg);
5275         return 0;
5276 }
5277
5278 DEF_IE_DECODE(itu, scompl)
5279 {
5280         IE_START(;);
5281
5282         if(ielen != 1)
5283                 goto rej;
5284
5285         if(*msg->b_rptr++ != (0x80 | 0x21))
5286                 goto rej;
5287
5288         IE_END(SCOMPL);
5289 }
5290
5291 /*********************************************************************
5292  *
5293  * Broadband Repeat Indicator
5294  *
5295  * References for this IE are:
5296  *
5297  *  Q.2931 p.  73
5298  *  PNNI1.0 p. 196
5299  *
5300  * Q.2931 has table 4-19. Only codepoints 0x2 and 0xa (for PNNI) supported.
5301  *
5302  * Only ITU-T coding allowed.
5303  */
5304 DEF_IE_PRINT(itu, repeat)
5305 {
5306         static const struct uni_print_tbl tbl[] = {
5307                 MKT(UNI_REPEAT_PRIDESC, desc),
5308                 MKT(UNI_REPEAT_STACK,   stack),
5309                 EOT()
5310         };
5311
5312         if(uni_print_iehdr("repeat", &ie->h, cx))
5313                 return;
5314         uni_print_tbl("type", ie->type, tbl, cx);
5315         uni_print_ieend(cx);
5316 }
5317
5318 DEF_IE_CHECK(itu, repeat)
5319 {
5320         switch(ie->type) {
5321
5322           case UNI_REPEAT_PRIDESC:
5323                 break;
5324
5325           case UNI_REPEAT_STACK:
5326                 if(!cx->pnni)
5327                         return -1;
5328                 break;
5329
5330           default:
5331                 return -1;
5332         }
5333         return 0;
5334 }
5335
5336 DEF_IE_ENCODE(itu, repeat)
5337 {
5338         START_IE(repeat, UNI_IE_REPEAT, 1);
5339
5340         APP_BYTE(msg, 0x80 | ie->type);
5341
5342         SET_IE_LEN(msg);
5343         return 0;
5344 }
5345
5346 DEF_IE_DECODE(itu, repeat)
5347 {
5348         u_char c;
5349
5350         IE_START(;);
5351
5352         if(ielen != 1)
5353                 goto rej;
5354
5355         c = *msg->b_rptr++;
5356         if(!(c & 0x80))
5357                 goto rej;
5358         ie->type = c & 0xf;
5359
5360         IE_END(REPEAT);
5361 }
5362
5363 /*********************************************************************
5364  *
5365  * Transit Network Selection
5366  *
5367  * References for this IE are:
5368  *
5369  *  Q.2931 pp. 75...76
5370  *  UNI4.0 pp. 17
5371  *
5372  * According to UNI4.0 this is always National Network Id/Carried Id.
5373  *
5374  * ITU-T/Net coding allowed.
5375  */
5376
5377 DEF_IE_PRINT(itu, tns)
5378 {
5379         u_int i;
5380
5381         if(uni_print_iehdr("tns", &ie->h, cx))
5382                 return;
5383         uni_print_entry(cx, "net", "%u,\"", ie->len);
5384         uni_putc('"', cx);
5385         for(i = 0; i < ie->len; i++) {
5386                 if(ie->net[i] < ' ')
5387                         uni_printf(cx, "^%c", ie->net[i] + '@');
5388                 else if(ie->net[i] < '~')
5389                         uni_putc(ie->net[i], cx);
5390                 else
5391                         uni_printf(cx, "\\%03o", ie->net[i]);
5392         }
5393         uni_putc('"', cx);
5394         uni_print_ieend(cx);
5395 }
5396
5397 DEF_IE_CHECK(itu, tns)
5398 {
5399         u_int i;
5400
5401         cx = cx;
5402
5403         if(ie->len == 0 || ie->len > UNI_TNS_MAXLEN)
5404                 return -1;
5405         for(i = 0; i < ie->len; i++)
5406                 if(ie->net[i] < ' ' || ie->net[i] > '~')
5407                         return -1;
5408         return 0;
5409 }
5410
5411 DEF_IE_ENCODE(itu, tns)
5412 {
5413         START_IE(tns, UNI_IE_TNS, ie->len + 1);
5414
5415         APP_BYTE(msg, 0x80 | (0x2 << 4) | 0x1);
5416         APP_BUF(msg, ie->net, ie->len);
5417
5418         SET_IE_LEN(msg);
5419         return 0;
5420 }
5421
5422 DEF_IE_DECODE(itu, tns)
5423 {
5424         IE_START(;);
5425
5426         if(ielen < 2 || ielen > 5)
5427                 goto rej;
5428
5429         if(*msg->b_rptr++ != (0x80 | (0x2 << 4) | 0x1))
5430                 goto rej;
5431         ielen--;
5432
5433         ie->len = 0;
5434         while(ielen--)
5435                 ie->net[ie->len++] = *msg->b_rptr++;
5436
5437         IE_END(TNS);
5438 }
5439
5440 /*********************************************************************
5441  *
5442  * Restart indicator
5443  *
5444  * References for this IE are:
5445  *
5446  *  Q.2931 pp. 73...74
5447  *  UNI4.0 p.  17
5448  *
5449  * Only ITU-T coding allowed.
5450  */
5451
5452 DEF_IE_PRINT(itu, restart)
5453 {
5454         static const struct uni_print_tbl tbl[] = {
5455                 MKT(UNI_RESTART_CHANNEL,        channel),
5456                 MKT(UNI_RESTART_PATH,           path),
5457                 MKT(UNI_RESTART_ALL,            all),
5458                 EOT()
5459         };
5460
5461         if(uni_print_iehdr("restart", &ie->h, cx))
5462                 return;
5463         uni_print_tbl("class", ie->rclass, tbl, cx);
5464         uni_print_ieend(cx);
5465 }
5466
5467 DEF_IE_CHECK(itu, restart)
5468 {
5469         cx = cx;
5470
5471         switch(ie->rclass) {
5472           default:
5473                 return -1;
5474
5475           case UNI_RESTART_CHANNEL:
5476           case UNI_RESTART_PATH:
5477           case UNI_RESTART_ALL:
5478                 break;
5479         }
5480
5481         return 0;
5482 }
5483
5484 DEF_IE_ENCODE(itu, restart)
5485 {
5486         START_IE(restart, UNI_IE_RESTART, 1);
5487
5488         APP_BYTE(msg, 0x80 | ie->rclass);
5489
5490         SET_IE_LEN(msg);
5491         return 0;
5492 }
5493
5494 DEF_IE_DECODE(itu, restart)
5495 {
5496         u_char c;
5497
5498         IE_START(;);
5499
5500         if(ielen != 1)
5501                 goto rej;
5502
5503         ie->rclass = (c = *msg->b_rptr++) & 0x7;
5504
5505         if(!(c & 0x80))
5506                 goto rej;
5507
5508         IE_END(RESTART);
5509 }
5510
5511 /*********************************************************************
5512  *
5513  * User-to-user info.
5514  *
5515  * References for this IE are:
5516  *
5517  *  Q.2957
5518  *
5519  * Only ITU-T coding allowed.
5520  */
5521
5522 DEF_IE_PRINT(itu, uu)
5523 {
5524         u_int i;
5525
5526         if(uni_print_iehdr("uu", &ie->h, cx))
5527                 return;
5528         uni_print_entry(cx, "len", "%u", ie->len);
5529         uni_print_entry(cx, "info", "(");
5530         for(i = 0; i < ie->len; i++)
5531                 uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->uu[i]);
5532         uni_printf(cx, ")");
5533         uni_print_ieend(cx);
5534 }
5535
5536 DEF_IE_CHECK(itu, uu)
5537 {
5538         cx = cx;
5539
5540         if(ie->len > UNI_UU_MAXLEN)
5541                 return -1;
5542
5543         return 0;
5544 }
5545
5546 DEF_IE_ENCODE(itu, uu)
5547 {
5548         START_IE(uu, UNI_IE_UU, ie->len);
5549
5550         APP_BUF(msg, ie->uu, ie->len);
5551
5552         SET_IE_LEN(msg);
5553         return 0;
5554 }
5555
5556 DEF_IE_DECODE(itu, uu)
5557 {
5558         IE_START(;);
5559
5560         if(ielen > UNI_UU_MAXLEN || ielen < 1)
5561                 goto rej;
5562
5563         ie->len = ielen;
5564         ielen = 0;
5565         (void)memcpy(ie->uu, msg->b_rptr, ie->len);
5566         msg->b_rptr += ie->len;
5567
5568         IE_END(UU);
5569 }
5570
5571 /*********************************************************************
5572  *
5573  * Generic Identifier Transport
5574  *
5575  * References for this IE are:
5576  *
5577  *  UNI4.0 pp. 26...28
5578  *
5579  * UNI4.0 prescribes a fixed format for this IE. We have a flag in the
5580  * context structur, which tells us whether the check of this IE should be
5581  * hard or soft. Probably it should be hard for end systems and soft for
5582  * network nodes.
5583  *
5584  * Only Net Coding allowed. (XXX)
5585  */
5586
5587 DEF_IE_PRINT(net, git)
5588 {
5589         static const struct uni_print_tbl std_tbl[] = {
5590                 MKT(UNI_GIT_STD_DSMCC,  dsmcc),
5591                 MKT(UNI_GIT_STD_H245,   H.245),
5592                 EOT()
5593         };
5594         static const struct uni_print_tbl type_tbl[] = {
5595                 MKT(UNI_GIT_TYPE_SESS,  sess),
5596                 MKT(UNI_GIT_TYPE_RES,   res),
5597                 EOT()
5598         };
5599         u_int i, j;
5600         char buf[20];
5601
5602         if(uni_print_iehdr("git", &ie->h, cx))
5603                 return;
5604
5605         uni_print_tbl("std", ie->std, std_tbl, cx);
5606
5607         uni_print_eol(cx);
5608         uni_print_push_prefix("id", cx);
5609         cx->indent++;
5610         for(i = 0; i < ie->numsub; i++) {
5611                 sprintf(buf, "%u", i);
5612                 uni_print_entry(cx, buf, "(");
5613                 uni_print_tbl(NULL, ie->sub[i].type, type_tbl, cx);
5614                 for(j = 0; j < ie->sub[i].len; j++)
5615                         uni_printf(cx, ",0x%02x", ie->sub[i].val[j]);
5616                 uni_printf(cx, ")");
5617                 uni_print_eol(cx);
5618         }
5619         cx->indent--;
5620         uni_print_pop_prefix(cx);
5621
5622         uni_print_ieend(cx);
5623 }
5624
5625 DEF_IE_CHECK(net, git)
5626 {
5627         u_int i;
5628
5629         if(cx->git_hard) {
5630                 switch(ie->std) {
5631                   case UNI_GIT_STD_DSMCC:
5632                   case UNI_GIT_STD_H245:
5633                         break;
5634                   default:
5635                         return -1;
5636                 }
5637                 if(ie->numsub != 2)
5638                         return -1;
5639                 if(ie->sub[0].type != UNI_GIT_TYPE_SESS)
5640                         return -1;
5641                 if(ie->sub[0].len > UNI_GIT_MAXSESS)
5642                         return -1;
5643                 if(ie->sub[1].type != UNI_GIT_TYPE_RES)
5644                         return -1;
5645                 if(ie->sub[1].len > UNI_GIT_MAXRES)
5646                         return -1;
5647         } else {
5648                 if(ie->numsub > UNI_GIT_MAXSUB)
5649                         return -1;
5650                 for(i = 0; i < ie->numsub; i++)
5651                         if(ie->sub[i].len > UNI_GIT_MAXVAL)
5652                                 return -1;
5653         }
5654         return 0;
5655 }
5656
5657 DEF_IE_ENCODE(net, git)
5658 {
5659         u_int i;
5660
5661         START_IE(git, UNI_IE_GIT, 1 + ie->numsub * (1 + UNI_GIT_MAXVAL));
5662
5663         APP_BYTE(msg, ie->std);
5664         for(i = 0; i < ie->numsub; i++) {
5665                 APP_BYTE(msg, ie->sub[i].type);
5666                 APP_BYTE(msg, ie->sub[i].len);
5667                 APP_BUF(msg, ie->sub[i].val, ie->sub[i].len);
5668         }
5669
5670         SET_IE_LEN(msg);
5671         return 0;
5672 }
5673
5674 DEF_IE_DECODE(net, git)
5675 {
5676         IE_START(;);
5677
5678         if(ielen > 1 + UNI_GIT_MAXSUB * (1 + UNI_GIT_MAXVAL) || ielen < 1)
5679                 goto rej;
5680
5681         ie->std = *msg->b_rptr++;
5682         ielen--;
5683
5684         ie->numsub = 0;
5685         while(ielen > 0) {
5686                 if(ie->numsub >= UNI_GIT_MAXSUB)
5687                         goto rej;
5688
5689                 ie->sub[ie->numsub].type = *msg->b_rptr++;
5690                 ielen--;
5691
5692                 if(ielen == 0)
5693                         goto rej;
5694                 ie->sub[ie->numsub].len = *msg->b_rptr++;
5695                 ielen--;
5696
5697                 if(ie->sub[ie->numsub].len > UNI_GIT_MAXVAL)
5698                         goto rej;
5699                 if(ie->sub[ie->numsub].len > (u_int)ielen)
5700                         goto rej;
5701
5702                 (void)memcpy(ie->sub[ie->numsub].val, msg->b_rptr, ie->sub[ie->numsub].len);
5703                 ielen -= ie->sub[ie->numsub].len;
5704                 msg->b_rptr += ie->sub[ie->numsub].len;
5705
5706                 ie->numsub++;
5707         }
5708
5709         IE_END(GIT);
5710 }
5711
5712 /*********************************************************************
5713  *
5714  * Additional ABR Parameters
5715  * ABR Setup parameters
5716  *
5717  * References for this IE are:
5718  *
5719  *      UNI4.0 pp. 78...82
5720  *      PNNI1.0 p. 195
5721  *
5722  * Notes:
5723  *      Only NET coding.
5724  */
5725
5726 static void
5727 print_abr_rec(struct unicx *cx, struct uni_abr_rec *rec)
5728 {
5729         if(rec->present & UNI_ABR_REC_NRM_P)
5730                 uni_print_entry(cx, "nrm", "%d", rec->nrm);
5731         if(rec->present & UNI_ABR_REC_TRM_P)
5732                 uni_print_entry(cx, "trm", "%d", rec->trm);
5733         if(rec->present & UNI_ABR_REC_CDF_P)
5734                 uni_print_entry(cx, "cdf", "%d", rec->cdf);
5735         if(rec->present & UNI_ABR_REC_ADTF_P)
5736                 uni_print_entry(cx, "adtf", "%d", rec->adtf);
5737 }
5738
5739 DEF_IE_PRINT(net, abradd)
5740 {
5741         if(uni_print_iehdr("abradd", &ie->h, cx))
5742                 return;
5743
5744         uni_print_push_prefix("fwd", cx);
5745         print_abr_rec(cx, &ie->fwd);
5746         uni_print_pop_prefix(cx);
5747
5748         uni_print_push_prefix("bwd", cx);
5749         print_abr_rec(cx, &ie->bwd);
5750         uni_print_pop_prefix(cx);
5751
5752         uni_print_ieend(cx);
5753 }
5754
5755 DEF_IE_CHECK(net, abradd)
5756 {
5757         cx = cx;
5758         ie = ie;
5759
5760         return 0;
5761 }
5762
5763 static u_int
5764 encode_abr_rec(struct uni_abr_rec *rec)
5765 {
5766         u_int ret = rec->present & 0xf000;
5767
5768         if(ret & UNI_ABR_REC_NRM_P)
5769                 ret |= (rec->nrm & 0x7) << 25;
5770         if(ret & UNI_ABR_REC_TRM_P)
5771                 ret |= (rec->trm & 0x7) << 22;
5772         if(ret & UNI_ABR_REC_CDF_P)
5773                 ret |= (rec->cdf & 0x7) << 19;
5774         if(ret & UNI_ABR_REC_ADTF_P)
5775                 ret |= (rec->adtf & 0x3ff) << 9;
5776
5777         return ret;
5778 }
5779
5780 DEF_IE_ENCODE(net, abradd)
5781 {
5782         START_IE(abradd, UNI_IE_ABRADD, 10);
5783
5784         APP_SUB_32BIT(msg, UNI_ABRADD_FADD_ID, encode_abr_rec(&ie->fwd));
5785         APP_SUB_32BIT(msg, UNI_ABRADD_BADD_ID, encode_abr_rec(&ie->bwd));
5786
5787         SET_IE_LEN(msg);
5788         return 0;
5789 }
5790
5791 static int
5792 decode_abr_rec(struct uni_msg *msg, struct uni_abr_rec *rec)
5793 {
5794         u_int val;
5795
5796         val  = *msg->b_rptr++ << 24;
5797         val |= *msg->b_rptr++ << 16;
5798         val |= *msg->b_rptr++ <<  8;
5799         val |= *msg->b_rptr++ <<  0;
5800
5801         rec->present = val & 0xf000;
5802
5803         rec->nrm  = (val & UNI_ABR_REC_NRM_P) ? ((val >> 25) & 0x7) : 0;
5804         rec->trm  = (val & UNI_ABR_REC_TRM_P) ? ((val >> 22) & 0x7) : 0;
5805         rec->cdf  = (val & UNI_ABR_REC_CDF_P) ? ((val >> 19) & 0x7) : 0;
5806         rec->adtf = (val & UNI_ABR_REC_ADTF_P)? ((val >>  9) & 0x3ff) : 0;
5807
5808         return 0;
5809 }
5810
5811 DEF_IE_DECODE(net, abradd)
5812 {
5813         IE_START(;);
5814
5815         if(ielen != 10)
5816                 goto rej;
5817
5818
5819         while(ielen--) {
5820                 switch(*msg->b_rptr++) {
5821
5822                   default:
5823                         goto rej;
5824
5825                   case UNI_ABRADD_FADD_ID:
5826                         if(decode_abr_rec(msg, &ie->fwd))
5827                                 goto rej;
5828                         ielen -= 4;
5829                         break;
5830
5831                   case UNI_ABRADD_BADD_ID:
5832                         if(decode_abr_rec(msg, &ie->bwd))
5833                                 goto rej;
5834                         ielen -= 4;
5835                         break;
5836                 }
5837         }
5838         IE_END(ABRADD);
5839 }
5840
5841 /*********************************************************************/
5842
5843 DEF_IE_PRINT(net, abrsetup)
5844 {
5845         if(uni_print_iehdr("abrsetup", &ie->h, cx))
5846                 return;
5847
5848         uni_print_entry(cx, "rm_frt", "%d", ie->rmfrt);
5849
5850         uni_print_push_prefix("fwd", cx);
5851         if(ie->h.present & UNI_ABRSETUP_FICR_P)
5852                 uni_print_entry(cx, "icr", "%d", ie->ficr);
5853         if(ie->h.present & UNI_ABRSETUP_FTBE_P)
5854                 uni_print_entry(cx, "tbe", "%d", ie->ftbe);
5855         if(ie->h.present & UNI_ABRSETUP_FRIF_P)
5856                 uni_print_entry(cx, "rif", "%d", ie->frif);
5857         if(ie->h.present & UNI_ABRSETUP_FRDF_P)
5858                 uni_print_entry(cx, "rdf", "%d", ie->frdf);
5859         uni_print_pop_prefix(cx);
5860
5861         uni_print_push_prefix("bwd", cx);
5862         if(ie->h.present & UNI_ABRSETUP_BICR_P)
5863                 uni_print_entry(cx, "icr", "%d", ie->bicr);
5864         if(ie->h.present & UNI_ABRSETUP_BTBE_P)
5865                 uni_print_entry(cx, "tbe", "%d", ie->btbe);
5866         if(ie->h.present & UNI_ABRSETUP_BRIF_P)
5867                 uni_print_entry(cx, "rif", "%d", ie->brif);
5868         if(ie->h.present & UNI_ABRSETUP_BRDF_P)
5869                 uni_print_entry(cx, "rdf", "%d", ie->brdf);
5870         uni_print_pop_prefix(cx);
5871
5872         uni_print_ieend(cx);
5873 }
5874
5875 DEF_IE_CHECK(net, abrsetup)
5876 {
5877         if(cx->pnni) {
5878                 if(!(ie->h.present & UNI_ABRSETUP_FICR_P))
5879                         return -1;
5880                 if(!(ie->h.present & UNI_ABRSETUP_BICR_P))
5881                         return -1;
5882                 if(!(ie->h.present & UNI_ABRSETUP_FTBE_P))
5883                         return -1;
5884                 if(!(ie->h.present & UNI_ABRSETUP_BTBE_P))
5885                         return -1;
5886                 if(!(ie->h.present & UNI_ABRSETUP_FRIF_P))
5887                         return -1;
5888                 if(!(ie->h.present & UNI_ABRSETUP_BRIF_P))
5889                         return -1;
5890                 if(!(ie->h.present & UNI_ABRSETUP_FRDF_P))
5891                         return -1;
5892                 if(!(ie->h.present & UNI_ABRSETUP_BRDF_P))
5893                         return -1;
5894                 if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P))
5895                         return -1;
5896         }
5897
5898         if(!(ie->h.present & UNI_ABRSETUP_RMFRT_P))
5899                 return -1;
5900
5901         if(ie->h.present & UNI_ABRSETUP_FICR_P)
5902                 if(ie->ficr >= 1 << 24)
5903                         return -1;
5904         if(ie->h.present & UNI_ABRSETUP_BICR_P)
5905                 if(ie->bicr >= 1 << 24)
5906                         return -1;
5907
5908         if(ie->h.present & UNI_ABRSETUP_FTBE_P)
5909                 if(ie->ftbe >= 1 << 24 || ie->ftbe == 0)
5910                         return -1;
5911         if(ie->h.present & UNI_ABRSETUP_BTBE_P)
5912                 if(ie->btbe >= 1 << 24 || ie->btbe == 0)
5913                         return -1;
5914
5915         if(ie->rmfrt >= 1 << 24)
5916                 return -1;
5917
5918         if(ie->h.present & UNI_ABRSETUP_FRIF_P)
5919                 if(ie->frif > 15)
5920                         return -1;
5921         if(ie->h.present & UNI_ABRSETUP_FRDF_P)
5922                 if(ie->frdf > 15)
5923                         return -1;
5924         if(ie->h.present & UNI_ABRSETUP_BRIF_P)
5925                 if(ie->brif > 15)
5926                         return -1;
5927         if(ie->h.present & UNI_ABRSETUP_BRDF_P)
5928                 if(ie->brdf > 15)
5929                         return -1;
5930         return 0;
5931 }
5932
5933 DEF_IE_ENCODE(net, abrsetup)
5934 {
5935         START_IE(abrsetup, UNI_IE_ABRSETUP, 32);
5936
5937         APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FICR_P,
5938                 UNI_ABRSETUP_FICR_ID, ie->ficr);
5939         APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BICR_P,
5940                 UNI_ABRSETUP_BICR_ID, ie->bicr);
5941         APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_FTBE_P,
5942                 UNI_ABRSETUP_FTBE_ID, ie->ftbe);
5943         APP_OPT_24BIT(msg, ie->h.present, UNI_ABRSETUP_BTBE_P,
5944                 UNI_ABRSETUP_BTBE_ID, ie->btbe);
5945         APP_SUB_24BIT(msg, UNI_ABRSETUP_RMFRT_ID, ie->rmfrt);
5946         APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRIF_P,
5947                 UNI_ABRSETUP_FRIF_ID, ie->frif);
5948         APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRIF_P,
5949                 UNI_ABRSETUP_BRIF_ID, ie->brif);
5950         APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_FRDF_P,
5951                 UNI_ABRSETUP_FRDF_ID, ie->frdf);
5952         APP_OPT_BYTE(msg, ie->h.present, UNI_ABRSETUP_BRDF_P,
5953                 UNI_ABRSETUP_BRDF_ID, ie->brdf);
5954
5955         SET_IE_LEN(msg);
5956         return 0;
5957 }
5958
5959 DEF_IE_DECODE(net, abrsetup)
5960 {
5961         IE_START(;);
5962
5963         if(ielen < 4 || ielen > 32)
5964                 goto rej;
5965
5966
5967         while(ielen--) {
5968                 switch(*msg->b_rptr++) {
5969
5970                   default:
5971                         goto rej;
5972
5973
5974                   DEC_GETF3(ABRSETUP_FICR, ficr, ie->h.present);
5975                   DEC_GETF3(ABRSETUP_BICR, bicr, ie->h.present);
5976                   DEC_GETF3(ABRSETUP_FTBE, ftbe, ie->h.present);
5977                   DEC_GETF3(ABRSETUP_BTBE, btbe, ie->h.present);
5978                   DEC_GETF1(ABRSETUP_FRIF, frif, ie->h.present);
5979                   DEC_GETF1(ABRSETUP_BRIF, brif, ie->h.present);
5980                   DEC_GETF1(ABRSETUP_FRDF, frdf, ie->h.present);
5981                   DEC_GETF1(ABRSETUP_BRDF, brdf, ie->h.present);
5982                   DEC_GETF3(ABRSETUP_RMFRT, frif, ie->h.present);
5983                 }
5984         }
5985         IE_END(ABRSETUP);
5986 }
5987
5988 /*********************************************************************
5989  *
5990  * Broadband report type
5991  *
5992  * References for this IE are:
5993  *
5994  *  Q.2963.1  pp. 7...8
5995  *
5996  * Only ITU-T coding allowed.
5997  */
5998
5999 DEF_IE_PRINT(itu, report)
6000 {
6001         static const struct uni_print_tbl tbl[] = {
6002                 MKT(UNI_REPORT_MODCONF, modconf),
6003                 MKT(UNI_REPORT_CLOCK,   clock),
6004                 MKT(UNI_REPORT_EEAVAIL, eeavail),
6005                 MKT(UNI_REPORT_EEREQ,   eereq),
6006                 MKT(UNI_REPORT_EECOMPL, eecompl),
6007                 EOT()
6008         };
6009
6010         if(uni_print_iehdr("report", &ie->h, cx))
6011                 return;
6012         uni_print_tbl("type", ie->report, tbl, cx);
6013         uni_print_ieend(cx);
6014 }
6015
6016 DEF_IE_CHECK(itu, report)
6017 {
6018         cx = cx;
6019
6020         switch(ie->report) {
6021
6022           default:
6023                 return -1;
6024
6025           case UNI_REPORT_MODCONF:
6026           case UNI_REPORT_CLOCK:
6027           case UNI_REPORT_EEAVAIL:
6028           case UNI_REPORT_EEREQ:
6029           case UNI_REPORT_EECOMPL:
6030                 break;
6031         }
6032         return 0;
6033 }
6034
6035 DEF_IE_ENCODE(itu, report)
6036 {
6037         START_IE(report, UNI_IE_REPORT, 1);
6038
6039         APP_BYTE(msg, ie->report);
6040
6041         SET_IE_LEN(msg);
6042         return 0;
6043 }
6044
6045 DEF_IE_DECODE(itu, report)
6046 {
6047         IE_START(;);
6048         if(ielen != 1)
6049                 goto rej;
6050
6051         ie->report = *msg->b_rptr++;
6052
6053         IE_END(REPORT);
6054 }
6055
6056 /*********************************************************************
6057  *
6058  * Soft PVPC/PVCC
6059  *
6060  * References for this IE are:
6061  *
6062  *  PNNI1.0 pp. 201...203
6063  *
6064  * Only NET coding allowed.
6065  */
6066 DEF_IE_PRINT(net, calling_soft)
6067 {
6068         if(uni_print_iehdr("calling_soft", &ie->h, cx))
6069                 return;
6070
6071         uni_print_entry(cx, "vpi", "%d", ie->vpi);
6072         if(ie->h.present & UNI_CALLING_SOFT_VCI_P)
6073                 uni_print_entry(cx, "vci", "%d", ie->vci);
6074
6075         uni_print_ieend(cx);
6076 }
6077
6078 DEF_IE_PRINT(net, called_soft)
6079 {
6080         static const struct uni_print_tbl tab[] = {
6081                 MKT(UNI_SOFT_SEL_ANY,   any),
6082                 MKT(UNI_SOFT_SEL_REQ,   required),
6083                 MKT(UNI_SOFT_SEL_ASS,   assigned),
6084                 EOT()
6085         };
6086
6087         if(uni_print_iehdr("called_soft", &ie->h, cx))
6088                 return;
6089
6090         uni_print_tbl("selection", ie->sel, tab, cx);
6091         if(ie->h.present & UNI_CALLED_SOFT_VPI_P)
6092                 uni_print_entry(cx, "vpi", "%d", ie->vpi);
6093         if(ie->h.present & UNI_CALLED_SOFT_VCI_P)
6094                 uni_print_entry(cx, "vci", "%d", ie->vci);
6095
6096         uni_print_ieend(cx);
6097 }
6098
6099 DEF_IE_CHECK(net, calling_soft)
6100 {
6101         cx = cx;
6102
6103         if(ie->vpi >= 1 << 12)
6104                 return -1;
6105         return 0;
6106 }
6107
6108 DEF_IE_CHECK(net, called_soft)
6109 {
6110         cx = cx;
6111
6112         switch(ie->sel) {
6113
6114           case UNI_SOFT_SEL_ANY:
6115           case UNI_SOFT_SEL_REQ:
6116           case UNI_SOFT_SEL_ASS:
6117                 break;
6118
6119           default:
6120                 return -1;
6121         }
6122         if(ie->h.present & UNI_CALLED_SOFT_VPI_P) {
6123                 if(ie->vpi >= 1 << 12)
6124                         return -1;
6125         } else {
6126                 if(ie->sel != UNI_SOFT_SEL_ANY)
6127                         return -1;
6128         }
6129
6130         if(ie->h.present & UNI_CALLED_SOFT_VCI_P)
6131                 if(!(ie->h.present & UNI_CALLED_SOFT_VPI_P))
6132                         return -1;
6133
6134
6135         return 0;
6136 }
6137
6138 DEF_IE_ENCODE(net, calling_soft)
6139 {
6140         START_IE(calling_soft, UNI_IE_CALLING_SOFT, 6);
6141
6142         APP_BYTE(msg, 0x81);
6143         APP_16BIT(msg, ie->vpi);
6144
6145         if(ie->h.present & UNI_CALLING_SOFT_VCI_P) {
6146                 APP_BYTE(msg, 0x82);
6147                 APP_16BIT(msg, ie->vci);
6148         }
6149
6150         SET_IE_LEN(msg);
6151         return 0;
6152 }
6153
6154 DEF_IE_ENCODE(net, called_soft)
6155 {
6156         START_IE(called_soft, UNI_IE_CALLED_SOFT, 7);
6157
6158         APP_BYTE(msg, ie->sel);
6159
6160         if(ie->h.present & UNI_CALLED_SOFT_VPI_P) {
6161                 APP_BYTE(msg, 0x81);
6162                 APP_16BIT(msg, ie->vpi);
6163         }
6164
6165         if(ie->h.present & UNI_CALLED_SOFT_VCI_P) {
6166                 APP_BYTE(msg, 0x82);
6167                 APP_16BIT(msg, ie->vci);
6168         }
6169
6170         SET_IE_LEN(msg);
6171         return 0;
6172 }
6173
6174 DEF_IE_DECODE(net, calling_soft)
6175 {
6176         int vci_seen, vpi_seen;
6177
6178         IE_START(;);
6179         if(ielen < 3)
6180                 goto rej;
6181
6182         vci_seen = 0;
6183         vpi_seen = 0;
6184
6185         while(ielen) {
6186                 switch(*msg->b_rptr++) {
6187
6188                   case 0x81:
6189                         if(!vpi_seen) {
6190                                 ie->vpi = *msg->b_rptr++ << 8;
6191                                 ie->vpi |= *msg->b_rptr++;
6192                         } else {
6193                                 msg->b_rptr += 2;
6194                         }
6195                         ielen -= 3;
6196                         break;
6197
6198                   case 0x82:
6199                         if(!vci_seen) {
6200                                 ie->vci = *msg->b_rptr++ << 8;
6201                                 ie->vci |= *msg->b_rptr++;
6202                         } else {
6203                                 msg->b_rptr += 2;
6204                         }
6205                         ie->h.present |= UNI_CALLING_SOFT_VCI_P;
6206                         ielen -= 3;
6207                         break;
6208
6209                   default:
6210                         goto rej;
6211                 }
6212         }
6213
6214         if(!vpi_seen)
6215                 goto rej;
6216
6217         IE_END(CALLING_SOFT);
6218 }
6219
6220 DEF_IE_DECODE(net, called_soft)
6221 {
6222         int vci_seen, vpi_seen;
6223
6224         IE_START(;);
6225         if(ielen < 3)
6226                 goto rej;
6227
6228         vci_seen = 0;
6229         vpi_seen = 0;
6230
6231         while(ielen) {
6232                 switch(*msg->b_rptr++) {
6233
6234                   case 0x81:
6235                         if(!vpi_seen) {
6236                                 ie->vpi = *msg->b_rptr++ << 8;
6237                                 ie->vpi |= *msg->b_rptr++;
6238                                 vpi_seen = 1;
6239                         } else {
6240                                 msg->b_rptr += 2;
6241                         }
6242                         ielen -= 3;
6243                         ie->h.present |= UNI_CALLED_SOFT_VCI_P;
6244                         break;
6245
6246                   case 0x82:
6247                         if(!vci_seen) {
6248                                 ie->vci = *msg->b_rptr++ << 8;
6249                                 ie->vci |= *msg->b_rptr++;
6250                                 vci_seen = 1;
6251                         } else {
6252                                 msg->b_rptr += 2;
6253                         }
6254                         ie->h.present |= UNI_CALLED_SOFT_VCI_P;
6255                         ielen -= 3;
6256                         break;
6257
6258                   default:
6259                         goto rej;
6260                 }
6261         }
6262
6263         IE_END(CALLED_SOFT);
6264 }
6265
6266 /*********************************************************************
6267  *
6268  * Crankback
6269  *
6270  * References for this IE are:
6271  *
6272  *  PNNI1.0 pp. 203...206
6273  *
6274  * Only NET coding allowed.
6275  */
6276
6277 DEF_IE_PRINT(net, crankback)
6278 {
6279         u_int j;
6280
6281         if(uni_print_iehdr("crankback", &ie->h, cx))
6282                 return;
6283
6284         uni_print_entry(cx, "level", "%d", ie->level);
6285
6286         switch(ie->type) {
6287
6288           case UNI_CRANKBACK_IF:
6289                 uni_print_entry(cx, "type", "interface");
6290                 break;
6291
6292           case UNI_CRANKBACK_NODE:
6293                 uni_print_entry(cx, "type", "node");
6294                 uni_print_entry(cx, "node", "{%d/", ie->id.node.level);
6295                 for(j = 0; j < 21; j++)
6296                         uni_printf(cx, "%02x", ie->id.node.id[j]);
6297                 uni_printf(cx, "}");
6298                 uni_print_eol(cx);
6299                 break;
6300
6301           case UNI_CRANKBACK_LINK:
6302                 uni_print_entry(cx, "type", "link");
6303                 uni_print_push_prefix("link", cx);
6304                 cx->indent++;
6305
6306                 uni_print_entry(cx, "prec", "{%d/", ie->id.link.plevel);
6307                 for(j = 0; j < 21; j++)
6308                         uni_printf(cx, "%02x", ie->id.link.pid[j]);
6309                 uni_printf(cx, "}");
6310                 uni_print_eol(cx);
6311
6312                 uni_print_entry(cx, "port", "0x%04x", ie->id.link.port);
6313                 uni_print_eol(cx);
6314
6315                 uni_print_entry(cx, "succ", "{%d/", ie->id.link.slevel);
6316                 for(j = 0; j < 21; j++)
6317                         uni_printf(cx, "%02x", ie->id.link.sid[j]);
6318                 uni_printf(cx, "}");
6319                 uni_print_eol(cx);
6320
6321                 cx->indent--;
6322                 uni_print_pop_prefix(cx);
6323                 break;
6324
6325           default:
6326                 uni_print_entry(cx, "type", "0x%02x", ie->type);
6327                 break;
6328         }
6329
6330         uni_print_entry(cx, "cause", "0x%02x", ie->cause);
6331
6332         if(ie->h.present & UNI_CRANKBACK_TOP_P) {
6333                 uni_print_push_prefix("topol", cx);
6334                 uni_print_entry(cx, "dir", "%d", ie->diag.top.dir);
6335                 uni_print_entry(cx, "port", "0x%04x", ie->diag.top.port);
6336                 uni_print_entry(cx, "avcr", "%u", ie->diag.top.avcr);
6337                 if(ie->h.present & UNI_CRANKBACK_TOPX_P) {
6338                         uni_print_entry(cx, "crm", "%u", ie->diag.top.crm);
6339                         uni_print_entry(cx, "vf", "%u", ie->diag.top.vf);
6340                 }
6341                 uni_print_pop_prefix(cx);
6342                 uni_print_eol(cx);
6343         }
6344         if(ie->h.present & UNI_CRANKBACK_QOS_P) {
6345                 uni_print_push_prefix("qos", cx);
6346                 uni_print_entry(cx, "ctd", "%savail", ie->diag.qos.ctd ? "" : "un");
6347                 uni_print_entry(cx, "cdv", "%savail", ie->diag.qos.cdv ? "" : "un");
6348                 uni_print_entry(cx, "clr", "%savail", ie->diag.qos.clr ? "" : "un");
6349                 uni_print_entry(cx, "other", "%savail", ie->diag.qos.other ? "" : "un");
6350                 uni_print_pop_prefix(cx);
6351                 uni_print_eol(cx);
6352         }
6353
6354         uni_print_eol(cx);
6355         uni_print_ieend(cx);
6356 }
6357
6358 DEF_IE_CHECK(net, crankback)
6359 {
6360         cx = cx;
6361
6362         if(ie->level > 104)
6363                 return -1;
6364         switch(ie->type) {
6365           case UNI_CRANKBACK_IF:
6366                 break;
6367           case UNI_CRANKBACK_NODE:
6368                 if(ie->id.node.level > 104)
6369                         return -1;
6370                 break;
6371
6372           case UNI_CRANKBACK_LINK:
6373                 if(ie->id.link.plevel > 104)
6374                         return -1;
6375                 if(ie->id.link.slevel > 104)
6376                         return -1;
6377                 break;
6378
6379           default:
6380                 return -1;
6381         }
6382
6383         if(ie->h.present & UNI_CRANKBACK_TOP_P) {
6384                 if(ie->h.present & UNI_CRANKBACK_QOS_P)
6385                         return -1;
6386
6387                 if(ie->cause != UNI_CAUSE_CRATE_NAVL)
6388                         return -1;
6389                 switch(ie->diag.top.dir) {
6390
6391                   case 0x00:
6392                   case 0x01:
6393                         break;
6394
6395                   default:
6396                         return -1;
6397                 }
6398         }
6399         if(ie->h.present & UNI_CRANKBACK_QOS_P) {
6400                 if(ie->cause != UNI_CAUSE_QOS_NAVL)
6401                         return -1;
6402         }
6403         return 0;
6404 }
6405
6406 DEF_IE_ENCODE(net, crankback)
6407 {
6408         START_IE(crankback, UNI_IE_CRANKBACK, 72);
6409
6410         APP_BYTE(msg, ie->level);
6411         APP_BYTE(msg, ie->type);
6412
6413         switch(ie->type) {
6414
6415           case UNI_CRANKBACK_IF:
6416                 break;
6417
6418           case UNI_CRANKBACK_NODE:
6419                 APP_BYTE(msg, ie->id.node.level);
6420                 APP_BUF(msg, ie->id.node.id, 21);
6421                 break;
6422
6423           case UNI_CRANKBACK_LINK:
6424                 APP_BYTE(msg, ie->id.link.plevel);
6425                 APP_BUF(msg, ie->id.link.pid, 21);
6426                 APP_32BIT(msg, ie->id.link.port);
6427                 APP_BYTE(msg, ie->id.link.slevel);
6428                 APP_BUF(msg, ie->id.link.sid, 21);
6429                 break;
6430         }
6431
6432         APP_BYTE(msg, ie->cause);
6433
6434         if(ie->h.present & UNI_CRANKBACK_TOP_P) {
6435                 APP_BYTE(msg, ie->diag.top.dir);
6436                 APP_32BIT(msg, ie->diag.top.port);
6437                 APP_32BIT(msg, ie->diag.top.avcr);
6438                 if(ie->h.present & UNI_CRANKBACK_TOPX_P) {
6439                         APP_32BIT(msg, ie->diag.top.crm);
6440                         APP_32BIT(msg, ie->diag.top.vf);
6441                 }
6442         }
6443
6444         if(ie->h.present & UNI_CRANKBACK_QOS_P) {
6445                 APP_BYTE(msg, (ie->diag.qos.ctd << 3)
6446                              |(ie->diag.qos.cdv << 2)
6447                              |(ie->diag.qos.clr << 1)
6448                              |(ie->diag.qos.other));
6449         }
6450         SET_IE_LEN(msg);
6451         return 0;
6452 }
6453
6454
6455 DEF_IE_DECODE(net, crankback)
6456 {
6457         IE_START(;);
6458
6459         if(ielen < 3)
6460                 goto rej;
6461
6462         ie->level = *msg->b_rptr++;
6463         ielen--;
6464
6465         ie->type = *msg->b_rptr++;
6466         ielen--;
6467
6468         switch(ie->type) {
6469
6470           default:
6471                 goto rej;
6472
6473           case UNI_CRANKBACK_IF:
6474                 break;
6475
6476           case UNI_CRANKBACK_NODE:
6477                 if(ielen < 22)
6478                         goto rej;
6479                 ie->id.node.level = *msg->b_rptr++;
6480                 (void)memcpy(ie->id.node.id, msg->b_rptr, 21);
6481                 msg->b_rptr += 21;
6482                 ielen -= 22;
6483                 break;
6484
6485           case UNI_CRANKBACK_LINK:
6486                 if(ielen < 48)
6487                         goto rej;
6488                 ie->id.link.plevel = *msg->b_rptr++;
6489                 (void)memcpy(ie->id.link.pid, msg->b_rptr, 21);
6490                 msg->b_rptr += 21;
6491                 ielen -= 22;
6492
6493                 ie->id.link.port  = *msg->b_rptr++ << 24;
6494                 ie->id.link.port |= *msg->b_rptr++ << 16;
6495                 ie->id.link.port |= *msg->b_rptr++ <<  8;
6496                 ie->id.link.port |= *msg->b_rptr++ <<  0;
6497                 ielen -= 4;
6498
6499                 ie->id.link.slevel = *msg->b_rptr++;
6500                 (void)memcpy(ie->id.link.sid, msg->b_rptr, 21);
6501                 msg->b_rptr += 21;
6502                 ielen -= 22;
6503
6504                 break;
6505         }
6506
6507         if(ielen < 1)
6508                 goto rej;
6509         ie->cause = *msg->b_rptr++;
6510         ielen--;
6511
6512         if(ie->cause == UNI_CAUSE_CRATE_NAVL) {
6513                 if(ielen > 0) {
6514                         if(ielen != 9 && ielen != 17)
6515                                 goto rej;
6516                         ie->diag.top.dir = *msg->b_rptr++;
6517                         ie->diag.top.port  = *msg->b_rptr++ << 24;
6518                         ie->diag.top.port |= *msg->b_rptr++ << 16;
6519                         ie->diag.top.port |= *msg->b_rptr++ <<  8;
6520                         ie->diag.top.port |= *msg->b_rptr++ <<  0;
6521                         ie->diag.top.avcr  = *msg->b_rptr++ << 24;
6522                         ie->diag.top.avcr |= *msg->b_rptr++ << 16;
6523                         ie->diag.top.avcr |= *msg->b_rptr++ <<  8;
6524                         ie->diag.top.avcr |= *msg->b_rptr++ <<  0;
6525                         ielen -= 9;
6526                         ie->h.present |= UNI_CRANKBACK_TOP_P;
6527                         if(ielen > 0) {
6528                                 ie->diag.top.crm  = *msg->b_rptr++ << 24;
6529                                 ie->diag.top.crm |= *msg->b_rptr++ << 16;
6530                                 ie->diag.top.crm |= *msg->b_rptr++ <<  8;
6531                                 ie->diag.top.crm |= *msg->b_rptr++ <<  0;
6532                                 ie->diag.top.vf  = *msg->b_rptr++ << 24;
6533                                 ie->diag.top.vf |= *msg->b_rptr++ << 16;
6534                                 ie->diag.top.vf |= *msg->b_rptr++ <<  8;
6535                                 ie->diag.top.vf |= *msg->b_rptr++ <<  0;
6536                                 ie->h.present |= UNI_CRANKBACK_TOPX_P;
6537                                 ielen -= 8;
6538                         }
6539                 }
6540         } else if(ie->cause == UNI_CAUSE_QOS_NAVL) {
6541                 if(ielen > 0) {
6542                         if(ielen != 1)
6543                                 goto rej;
6544                         ie->diag.qos.ctd = *msg->b_rptr >> 3;
6545                         ie->diag.qos.cdv = *msg->b_rptr >> 2;
6546                         ie->diag.qos.clr = *msg->b_rptr >> 1;
6547                         ie->diag.qos.other = *msg->b_rptr >> 0;
6548                         ie->h.present |= UNI_CRANKBACK_QOS_P;
6549                         ielen -= 1;
6550                 }
6551         } else {
6552                 if(ielen > 0)
6553                         goto rej;
6554         }
6555
6556         IE_END(CRANKBACK);
6557 }
6558
6559 /*********************************************************************
6560  *
6561  * Designated transit list
6562  *
6563  * References for this IE are:
6564  *
6565  *  PNNI1.0 pp. 206...208
6566  *
6567  * Only NET coding allowed.
6568  */
6569 DEF_IE_PRINT(net, dtl)
6570 {
6571         u_int i, j;
6572         char buf[10];
6573
6574         if(uni_print_iehdr("dtl", &ie->h, cx))
6575                 return;
6576
6577         uni_print_entry(cx, "ptr", "%d(%d)", ie->ptr, ie->ptr / UNI_DTL_LOGNP_SIZE);
6578         uni_print_push_prefix("dtl", cx);
6579         cx->indent++;
6580         uni_printf(cx, "{");
6581         for(i = 0; i < ie->num; i++) {
6582                 sprintf(buf, "%d", i);
6583                 uni_print_entry(cx, buf, "{%d/", ie->dtl[i].node_level);
6584                 for(j = 0; j < 21; j++)
6585                         uni_printf(cx, "%02x", ie->dtl[i].node_id[j]);
6586                 uni_printf(cx, ",%04x}", ie->dtl[i].port_id);
6587                 uni_print_eol(cx);
6588         }
6589         cx->indent--;
6590         uni_print_pop_prefix(cx);
6591         uni_print_ieend(cx);
6592 }
6593
6594 DEF_IE_CHECK(net, dtl)
6595 {
6596         u_int i;
6597
6598         cx = cx;
6599
6600         if(ie->ptr % UNI_DTL_LOGNP_SIZE != 0)
6601                 return -1;
6602         if(ie->ptr / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM)
6603                 return -1;
6604         if(ie->num > UNI_DTL_MAXNUM)
6605                 return -1;
6606         for(i = 0; i < ie->num; i++)
6607                 if(ie->dtl[i].node_level > 104)
6608                         return -1;
6609         return 0;
6610 }
6611
6612 DEF_IE_ENCODE(net, dtl)
6613 {
6614         u_int i;
6615
6616         START_IE(dtl, UNI_IE_DTL, 2 + UNI_DTL_LOGNP_SIZE * ie->num);
6617
6618         APP_16BIT(msg, ie->ptr);
6619
6620         for(i = 0; i < ie->num; i++) {
6621                 APP_BYTE(msg, UNI_DTL_LOGNP);
6622                 APP_BYTE(msg, ie->dtl[i].node_level);
6623                 APP_BUF(msg, ie->dtl[i].node_id, 21);
6624                 APP_32BIT(msg, ie->dtl[i].port_id);
6625         }
6626
6627         SET_IE_LEN(msg);
6628         return 0;
6629 }
6630
6631
6632 DEF_IE_DECODE(net, dtl)
6633 {
6634         IE_START(;);
6635
6636         if(ielen < 2)
6637                 goto rej;
6638
6639         ie->ptr = *msg->b_rptr++ << 8;
6640         ie->ptr |= *msg->b_rptr++;
6641         ielen -= 2;
6642
6643         if(ielen % UNI_DTL_LOGNP_SIZE != 0)
6644                 goto rej;
6645         if(ielen / UNI_DTL_LOGNP_SIZE > UNI_DTL_MAXNUM)
6646                 goto rej;
6647
6648         ie->num = 0;
6649         while(ielen) {
6650                 if(*msg->b_rptr++ != UNI_DTL_LOGNP)
6651                         goto rej;
6652                 ielen--;
6653
6654                 ie->dtl[ie->num].node_level = *msg->b_rptr++;
6655                 ielen--;
6656
6657                 (void)memcpy(ie->dtl[ie->num].node_id, msg->b_rptr, 21);
6658                 msg->b_rptr += 21;
6659                 ielen -= 21;
6660
6661                 ie->dtl[ie->num].port_id  = *msg->b_rptr++ << 24;
6662                 ie->dtl[ie->num].port_id |= *msg->b_rptr++ << 16;
6663                 ie->dtl[ie->num].port_id |= *msg->b_rptr++ <<  8;
6664                 ie->dtl[ie->num].port_id |= *msg->b_rptr++ <<  0;
6665                 ielen -= 4;
6666
6667                 ie->num++;
6668         }
6669
6670         IE_END(DTL);
6671 }
6672
6673 /*********************************************************************
6674  *
6675  * Leaf initiated join call identifier.
6676  * Leaf initiated join parameters.
6677  * Leaf initiated join sequence number.
6678  *
6679  * References for this IE are:
6680  *
6681  *  UNI4.0 pp. 46...48
6682  *
6683  * Only NET coding allowed.
6684  */
6685
6686 /**********************************************************************/
6687
6688 DEF_IE_PRINT(net, lij_callid)
6689 {
6690         static const struct uni_print_tbl type_tbl[] = {
6691                 MKT(UNI_LIJ_IDTYPE_ROOT, root),
6692                 EOT()
6693         };
6694
6695         if(uni_print_iehdr("lij_callid", &ie->h, cx))
6696                 return;
6697
6698         uni_print_tbl("type", ie->type, type_tbl, cx);
6699         uni_print_entry(cx, "id", "0x%x", ie->callid);
6700
6701         uni_print_ieend(cx);
6702 }
6703
6704 DEF_IE_CHECK(net, lij_callid)
6705 {
6706         cx = cx;
6707
6708         switch(ie->type) {
6709
6710           case UNI_LIJ_IDTYPE_ROOT:
6711                 break;
6712
6713           default:
6714                 return -1;
6715         }
6716
6717         return 0;
6718 }
6719
6720 DEF_IE_ENCODE(net, lij_callid)
6721 {
6722         START_IE(lij_callid, UNI_IE_LIJ_CALLID, 5);
6723
6724         APP_BYTE(msg, 0x80 | ie->type);
6725         APP_32BIT(msg, ie->callid);
6726
6727         SET_IE_LEN(msg);
6728         return 0;
6729 }
6730
6731 DEF_IE_DECODE(net, lij_callid)
6732 {
6733         IE_START(;);
6734
6735         if(ielen != 5)
6736                 goto rej;
6737
6738         ie->type = *msg->b_rptr++ & 0xf;
6739         ie->callid  = *msg->b_rptr++ << 24;
6740         ie->callid |= *msg->b_rptr++ << 16;
6741         ie->callid |= *msg->b_rptr++ <<  8;
6742         ie->callid |= *msg->b_rptr++ <<  0;
6743
6744         IE_END(LIJ_CALLID);
6745 }
6746
6747 /**********************************************************************/
6748
6749 DEF_IE_PRINT(net, lij_param)
6750 {
6751         static const struct uni_print_tbl lscreen_tbl[] = {
6752                 MKT(UNI_LIJ_SCREEN_NETJOIN, netjoin),
6753                 EOT()
6754         };
6755
6756         if(uni_print_iehdr("lij_param", &ie->h, cx))
6757                 return;
6758         uni_print_tbl("screen", ie->screen, lscreen_tbl, cx);
6759         uni_print_ieend(cx);
6760 }
6761
6762 DEF_IE_CHECK(net, lij_param)
6763 {
6764         cx = cx;
6765
6766         switch(ie->screen) {
6767
6768           case UNI_LIJ_SCREEN_NETJOIN:
6769                 break;
6770
6771           default:
6772                 return -1;
6773         }
6774
6775         return 0;
6776 }
6777
6778 DEF_IE_ENCODE(net, lij_param)
6779 {
6780         START_IE(lij_param, UNI_IE_LIJ_PARAM, 1);
6781
6782         APP_BYTE(msg, 0x80 | ie->screen);
6783
6784         SET_IE_LEN(msg);
6785         return 0;
6786 }
6787
6788 DEF_IE_DECODE(net, lij_param)
6789 {
6790         IE_START(;);
6791
6792         if(ielen != 1)
6793                 goto rej;
6794
6795         ie->screen = *msg->b_rptr++ & 0xf;
6796
6797         IE_END(LIJ_PARAM);
6798 }
6799
6800 /**********************************************************************/
6801
6802 DEF_IE_PRINT(net, lij_seqno)
6803 {
6804         if(uni_print_iehdr("lij_seqno", &ie->h, cx))
6805                 return;
6806         uni_print_entry(cx, "seqno", "0x%x", ie->seqno);
6807         uni_print_ieend(cx);
6808 }
6809
6810 DEF_IE_CHECK(net, lij_seqno)
6811 {
6812         cx = cx; ie = ie;
6813
6814         return 0;
6815 }
6816
6817 DEF_IE_ENCODE(net, lij_seqno)
6818 {
6819         START_IE(lij_seqno, UNI_IE_LIJ_SEQNO, 4);
6820
6821         APP_32BIT(msg, ie->seqno);
6822
6823         SET_IE_LEN(msg);
6824         return 0;
6825 }
6826
6827 DEF_IE_DECODE(net, lij_seqno)
6828 {
6829         IE_START(;);
6830
6831         if(ielen != 4)
6832                 goto rej;
6833
6834         ie->seqno  = *msg->b_rptr++ << 24;
6835         ie->seqno |= *msg->b_rptr++ << 16;
6836         ie->seqno |= *msg->b_rptr++ <<  8;
6837         ie->seqno |= *msg->b_rptr++ <<  0;
6838
6839         IE_END(LIJ_SEQNO);
6840 }
6841
6842 /*********************************************************************
6843  *
6844  * Connection scope
6845  *
6846  * References for this IE are:
6847  *
6848  *  UNI4.0 pp. 57...58
6849  *
6850  * Only NET coding allowed.
6851  */
6852 DEF_IE_PRINT(net, cscope)
6853 {
6854         static const struct uni_print_tbl type_tbl[] = {
6855                 MKT(UNI_CSCOPE_ORG,     org),
6856                 EOT()
6857         };
6858         static const struct uni_print_tbl scope_tbl[] = {
6859                 MKT(UNI_CSCOPE_ORG_LOC,         local_network),
6860                 MKT(UNI_CSCOPE_ORG_LOC_P1,      local_network_plus_one),
6861                 MKT(UNI_CSCOPE_ORG_LOC_P2,      local_network_plus_two),
6862                 MKT(UNI_CSCOPE_ORG_SITE_M1,     site_minus_one),
6863                 MKT(UNI_CSCOPE_ORG_SITE,        intra_site),
6864                 MKT(UNI_CSCOPE_ORG_SITE_P1,     site_plus_one),
6865                 MKT(UNI_CSCOPE_ORG_ORG_M1,      organisation_minus_one),
6866                 MKT(UNI_CSCOPE_ORG_ORG,         intra_organisation),
6867                 MKT(UNI_CSCOPE_ORG_ORG_P1,      organisation_plus_one),
6868                 MKT(UNI_CSCOPE_ORG_COMM_M1,     community_minus_one),
6869                 MKT(UNI_CSCOPE_ORG_COMM,        intra_community),
6870                 MKT(UNI_CSCOPE_ORG_COMM_P1,     community_plus_one),
6871                 MKT(UNI_CSCOPE_ORG_REG,         regional),
6872                 MKT(UNI_CSCOPE_ORG_INTER,       inter_regional),
6873                 MKT(UNI_CSCOPE_ORG_GLOBAL,      global),
6874                 EOT()
6875         };
6876
6877         if(uni_print_iehdr("cscope", &ie->h, cx))
6878                 return;
6879
6880         uni_print_tbl("type", ie->type, type_tbl, cx);
6881         if(ie->type == UNI_CSCOPE_ORG)
6882                 uni_print_tbl("scope", (u_int)ie->scope, scope_tbl, cx);
6883         else
6884                 uni_print_entry(cx, "scope", "0x%02x", ie->scope);
6885
6886         uni_print_ieend(cx);
6887 }
6888
6889 DEF_IE_CHECK(net, cscope)
6890 {
6891         cx = cx;
6892
6893         switch(ie->type) {
6894
6895           default:
6896                 return -1;
6897
6898           case UNI_CSCOPE_ORG:
6899                 switch(ie->scope) {
6900
6901                   default:
6902                         return -1;
6903
6904                   case UNI_CSCOPE_ORG_LOC:
6905                   case UNI_CSCOPE_ORG_LOC_P1:
6906                   case UNI_CSCOPE_ORG_LOC_P2:
6907                   case UNI_CSCOPE_ORG_SITE_M1:
6908                   case UNI_CSCOPE_ORG_SITE:
6909                   case UNI_CSCOPE_ORG_SITE_P1:
6910                   case UNI_CSCOPE_ORG_ORG_M1:
6911                   case UNI_CSCOPE_ORG_ORG:
6912                   case UNI_CSCOPE_ORG_ORG_P1:
6913                   case UNI_CSCOPE_ORG_COMM_M1:
6914                   case UNI_CSCOPE_ORG_COMM:
6915                   case UNI_CSCOPE_ORG_COMM_P1:
6916                   case UNI_CSCOPE_ORG_REG:
6917                   case UNI_CSCOPE_ORG_INTER:
6918                   case UNI_CSCOPE_ORG_GLOBAL:
6919                         break;
6920                 }
6921                 break;
6922         }
6923         return 0;
6924 }
6925
6926 DEF_IE_ENCODE(net, cscope)
6927 {
6928         START_IE(cscope, UNI_IE_CSCOPE, 2);
6929
6930         APP_BYTE(msg, ie->type | 0x80);
6931         APP_BYTE(msg, ie->scope);
6932
6933         SET_IE_LEN(msg);
6934         return 0;
6935 }
6936
6937 DEF_IE_DECODE(net, cscope)
6938 {
6939         IE_START(;);
6940         if(ielen != 2)
6941                 goto rej;
6942
6943         if((*msg->b_rptr & 0xf0) != 0x80)
6944                 goto rej;
6945
6946         ie->type = *msg->b_rptr++ & 0xf;
6947         ie->scope = *msg->b_rptr++;
6948
6949         IE_END(CSCOPE);
6950 }
6951
6952 /*********************************************************************
6953  *
6954  * Extended Quality of Service
6955  *
6956  * References for this IE are:
6957  *
6958  *      UNI4.0 pp. 70...72
6959  *
6960  * Notes:
6961  *      Only NET coding.
6962  */
6963 DEF_IE_PRINT(net, exqos)
6964 {
6965         static const struct uni_print_tbl tab[] = {
6966                 MKT(UNI_EXQOS_USER,     user),
6967                 MKT(UNI_EXQOS_NET,      net),
6968                 EOT()
6969         };
6970
6971         if(uni_print_iehdr("exqos", &ie->h, cx))
6972                 return;
6973
6974         uni_print_tbl("origin", ie->origin, tab, cx);
6975
6976         uni_print_entry(cx, "acceptable", "(");
6977         if(ie->h.present & UNI_EXQOS_FACC_P) {
6978                 if(ie->facc == UNI_EXQOS_ANY_CDV)
6979                         uni_printf(cx, "ANY");
6980                 else
6981                         uni_printf(cx, "%d", ie->facc);
6982         }
6983         uni_putc(',', cx);
6984         if(ie->h.present & UNI_EXQOS_BACC_P) {
6985                 if(ie->bacc == UNI_EXQOS_ANY_CDV)
6986                         uni_printf(cx, "ANY");
6987                 else
6988                         uni_printf(cx, "%d", ie->bacc);
6989         }
6990         uni_putc(')', cx);
6991
6992         uni_print_entry(cx, "cumulative", "(");
6993         if(ie->h.present & UNI_EXQOS_FCUM_P)
6994                 uni_printf(cx, "%d", ie->fcum);
6995         uni_putc(',', cx);
6996         if(ie->h.present & UNI_EXQOS_BCUM_P)
6997                 uni_printf(cx, "%d", ie->bcum);
6998         uni_putc(')', cx);
6999
7000         uni_print_entry(cx, "clrid", "(");
7001         if(ie->h.present & UNI_EXQOS_FCLR_P) {
7002                 if(ie->fclr == UNI_EXQOS_ANY_CLR)
7003                         uni_printf(cx, "ANY");
7004                 else
7005                         uni_printf(cx, "%d", ie->fclr);
7006         }
7007         uni_putc(',', cx);
7008         if(ie->h.present & UNI_EXQOS_BCLR_P) {
7009                 if(ie->bclr == UNI_EXQOS_ANY_CLR)
7010                         uni_printf(cx, "ANY");
7011                 else
7012                         uni_printf(cx, "%d", ie->bclr);
7013         }
7014         uni_putc(')', cx);
7015
7016         uni_print_ieend(cx);
7017 }
7018
7019 DEF_IE_CHECK(net, exqos)
7020 {
7021         cx = cx;
7022
7023         switch(ie->origin) {
7024           case UNI_EXQOS_USER:
7025           case UNI_EXQOS_NET:
7026                 break;
7027
7028           default:
7029                 return -1;
7030         }
7031         if(ie->h.present & UNI_EXQOS_FACC_P)
7032                 if(!(ie->h.present & UNI_EXQOS_FCUM_P))
7033                         return -1;
7034         if(ie->h.present & UNI_EXQOS_BACC_P)
7035                 if(!(ie->h.present & UNI_EXQOS_BCUM_P))
7036                         return -1;
7037
7038         if(ie->h.present & UNI_EXQOS_FACC_P)
7039                 if(ie->facc >= 1 << 24)
7040                         return -1;
7041         if(ie->h.present & UNI_EXQOS_BACC_P)
7042                 if(ie->bacc >= 1 << 24)
7043                         return -1;
7044         if(ie->h.present & UNI_EXQOS_FCUM_P)
7045                 if(ie->fcum >= 1 << 24)
7046                         return -1;
7047         if(ie->h.present & UNI_EXQOS_BCUM_P)
7048                 if(ie->bcum >= 1 << 24)
7049                         return -1;
7050
7051         if(ie->h.present & UNI_EXQOS_FCLR_P)
7052                 if(ie->fclr==0 || (ie->fclr>15 && ie->fclr!=UNI_EXQOS_ANY_CLR))
7053                         return -1;
7054         if(ie->h.present & UNI_EXQOS_BCLR_P)
7055                 if(ie->bclr==0 || (ie->bclr>15 && ie->bclr!=UNI_EXQOS_ANY_CLR))
7056                         return -1;
7057         return 0;
7058 }
7059
7060 DEF_IE_ENCODE(net, exqos)
7061 {
7062         START_IE(exqos, UNI_IE_EXQOS, 21);
7063
7064         APP_BYTE(msg, ie->origin);
7065
7066         APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FACC_P,
7067                 UNI_EXQOS_FACC_ID, ie->facc);
7068         APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BACC_P,
7069                 UNI_EXQOS_BACC_ID, ie->bacc);
7070         APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_FCUM_P,
7071                 UNI_EXQOS_FCUM_ID, ie->fcum);
7072         APP_OPT_24BIT(msg, ie->h.present, UNI_EXQOS_BCUM_P,
7073                 UNI_EXQOS_BCUM_ID, ie->bcum);
7074
7075         APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_FCLR_P,
7076                 UNI_EXQOS_FCLR_ID, ie->fclr);
7077         APP_OPT_BYTE(msg, ie->h.present, UNI_EXQOS_BCLR_P,
7078                 UNI_EXQOS_BCLR_ID, ie->bclr);
7079
7080         SET_IE_LEN(msg);
7081         return 0;
7082 }
7083
7084 DEF_IE_DECODE(net, exqos)
7085 {
7086         IE_START(;);
7087
7088         if(ielen < 1 || ielen > 21)
7089                 goto rej;
7090
7091         ie->origin = *msg->b_rptr++;
7092         ielen--;
7093
7094         while(ielen--) {
7095                 switch(*msg->b_rptr++) {
7096
7097                   default:
7098                         goto rej;
7099
7100                   DEC_GETF3(EXQOS_FACC, facc, ie->h.present);
7101                   DEC_GETF3(EXQOS_BACC, bacc, ie->h.present);
7102                   DEC_GETF3(EXQOS_FCUM, fcum, ie->h.present);
7103                   DEC_GETF3(EXQOS_BCUM, bcum, ie->h.present);
7104
7105                   DEC_GETF1(EXQOS_FCLR, fclr, ie->h.present);
7106                   DEC_GETF1(EXQOS_BCLR, bclr, ie->h.present);
7107
7108                 }
7109         }
7110         IE_END(EXQOS);
7111 }
7112
7113 /**************************************************************
7114  *
7115  * Free form IE (for testing mainly)
7116  */
7117 DEF_IE_PRINT(itu, unrec)
7118 {
7119         u_int i;
7120
7121         if (uni_print_iehdr("unrec", &ie->h, cx))
7122                 return;
7123         uni_print_entry(cx, "len", "%u", ie->len);
7124         uni_print_entry(cx, "data", "(");
7125         for (i = 0; i < ie->len; i++)
7126                 uni_printf(cx, "%s0x%02x", i == 0 ? "" : " ", ie->data[i]);
7127         uni_printf(cx, ")");
7128         uni_print_ieend(cx);
7129 }
7130
7131 DEF_IE_CHECK(itu, unrec)
7132 {
7133         cx = cx;
7134
7135         if (ie->len > sizeof(ie->data))
7136                 return (-1);
7137
7138         return (0);
7139 }
7140
7141 DEF_IE_ENCODE(itu, unrec)
7142 {
7143         START_IE2(unrec, UNI_IE_UNREC, ie->len, ie->id);
7144
7145         APP_BUF(msg, ie->data, ie->len);
7146
7147         SET_IE_LEN(msg);
7148         return (0);
7149 }
7150
7151 DEF_IE_DECODE(itu, unrec)
7152 {
7153         IE_START(;);
7154
7155         if (ielen > sizeof(ie->data) / sizeof(ie->data[0]) || ielen < 1)
7156                 goto rej;
7157
7158         ie->len = ielen;
7159         ielen = 0;
7160         (void)memcpy(ie->data, msg->b_rptr, ie->len);
7161         msg->b_rptr += ie->len;
7162
7163         IE_END(UNREC);
7164 }