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