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