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