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/privmsg.c,v 1.8 2003/10/10 14:50:05 hbb Exp $
30 *
31 * Private definitions for the MSG code file.
32 *
33 * This file is included at the begin of the automatically generated
34 * uni_msg.c.
35 */
36
37/*
38 * Decode a UNI message header.
39 * Return values:
40 *   0 - ok
41 *  -1 - ignore message (proto, length, CR error)
42 */
43int
44uni_decode_head(struct uni_msg *msg, struct uni_all *out,
45    struct unicx *cx __unused)
46{
47	u_int mlen;
48
49	cx->errcnt = 0;
50	(void)memset(out, 0, sizeof(struct uni_all));
51
52	if(uni_msg_len(msg) < 9)
53		return -1;			/* Q.2931 5.6.2 */
54	if(cx->pnni) {
55		if(*msg->b_rptr++ != PNNI_PROTO)
56			return -1;			/* Q.2931 5.6.1 */
57	} else {
58		if(*msg->b_rptr++ != UNI_PROTO)
59			return -1;			/* Q.2931 5.6.1 */
60	}
61	if(*msg->b_rptr++ != 3)
62		return -1;			/* Q.2931 5.6.3.1 */
63
64	out->u.hdr.cref.flag = (*msg->b_rptr & 0x80) ? 1 : 0;
65	out->u.hdr.cref.cref = (*msg->b_rptr++ & 0x7f) << 16;
66	out->u.hdr.cref.cref |= *msg->b_rptr++ << 8;
67	out->u.hdr.cref.cref |= *msg->b_rptr++;
68
69	out->mtype = *msg->b_rptr++;
70
71	/*
72	 * Be not too piggy about this byte
73	 */
74	switch(*msg->b_rptr & 0x13) {
75
76	  case 0x00: case 0x01: case 0x02: case 0x03:
77		out->u.hdr.act = UNI_MSGACT_DEFAULT;
78		break;
79
80	  case 0x10: case 0x11: case 0x12:
81		out->u.hdr.act = *msg->b_rptr & 0x3;
82		break;
83
84	  case 0x13:			/* Q.2931 5.7.1 */
85		out->u.hdr.act = UNI_MSGACT_REPORT;
86		break;
87	}
88	if(cx->pnni && (*msg->b_rptr & 0x08))
89		out->u.hdr.pass = 1;
90	else
91		out->u.hdr.pass = 0;
92
93	msg->b_rptr++;
94
95	mlen = *msg->b_rptr++ << 8;
96	mlen |= *msg->b_rptr++;
97
98	/*
99	 * If the message is longer than the indicated length
100	 * shorten it. If it is shorter, probably one of the IE
101	 * decoders will break, but we should proceed. 5.5.6.5
102	 */
103#if 0
104	if(uni_msg_len(msg) > mlen)
105		msg->b_wptr = msg->b_rptr + mlen;
106#endif
107
108	return 0;
109}
110
111static int
112uni_decode_body_internal(enum uni_msgtype mtype, struct uni_msg *msg,
113    union uni_msgall *out, struct unicx *cx)
114{
115	enum uni_ietype ietype;
116	struct uni_iehdr hdr;
117	u_int ielen;
118	const struct iedecl *iedecl;
119	int err = 0, ret;
120	u_char *end;
121
122	cx->ielast = (enum uni_ietype)0;
123	cx->repeat.h.present = 0;
124
125	while (uni_msg_len(msg) != 0) {
126		if (uni_decode_ie_hdr(&ietype, &hdr, msg, cx, &ielen)) {
127			/*
128			 * Short header. Set the ielen to an impossible size.
129			 * Then we should bump out in the error handling below.
130			 * We should have at least an IE type here.
131			 */
132			ielen = 0xffffffff;
133		}
134#ifdef DTRACE
135		printf("IE %x\n", ietype);
136#endif
137
138		if ((iedecl = GET_IEDECL(ietype, hdr.coding)) == NULL ||
139		    ietype == UNI_IE_UNREC) {
140			/*
141			 * entirly unknown IE. Check the length and skip it.
142			 * Q.2931 5.6.8.1
143			 */
144			if (ielen > uni_msg_len(msg))
145				msg->b_rptr = msg->b_wptr;
146			else
147				msg->b_rptr += ielen;
148			(void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK);
149			err = -1;
150			continue;
151		}
152#ifdef DTRACE
153		printf("IE %x known\n", ietype);
154#endif
155		if (ielen > iedecl->maxlen - 4 || ielen > uni_msg_len(msg)) {
156			/*
157			 * Information element too long -> content error.
158			 * Let the decoding routine set the error flag and
159			 * return DEC_ERR.
160			 * Q.2931 5.6.8.2
161			 */
162#if 0
163			/*
164			 * It is not clear how to best handle this error.
165			 */
166			if (ielen > iedecl->maxlen - 4)
167				ielen = iedecl->maxlen - 4;
168#endif
169
170			if (ielen > uni_msg_len(msg))
171				ielen = uni_msg_len(msg);
172
173			hdr.present |= UNI_IE_ERROR;
174
175#ifdef DTRACE
176			printf("IE %x length too large\n", ietype);
177#endif
178		}
179
180#ifdef DTRACE
181		else
182			printf("IE %x length ok\n", ietype);
183#endif
184		end = msg->b_rptr + ielen;
185		ret = uni_msgtable[mtype]->decode(out, msg, ietype,
186		    &hdr, ielen, cx);
187		msg->b_rptr = end;
188
189#ifdef DTRACE
190		printf("IE %x ret %d\n", ietype, ret);
191#endif
192
193		switch (ret) {
194
195		  case DEC_OK:	/* ok */
196			break;
197
198		  case DEC_ILL:	/* illegal IE */
199			/*
200			 * Unexpected but recognized.
201			 * Q.2931 5.6.8.3
202			 */
203			(void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK);
204			err = -1;
205			break;
206
207		  case DEC_ERR:	/* bad IE */
208			if (iedecl->flags & UNIFL_ACCESS)
209				/* this may be wrong: 5.6.8.2 */
210				(void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_ACC);
211			else
212				(void)UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_BAD);
213			err = -1;
214			break;
215
216		  default:
217			PANIC(("bad decode return"));
218		}
219	    	cx->ielast = ietype;
220	    	if (ietype != UNI_IE_REPEAT)
221			cx->repeat.h.present = 0;
222	}
223	return err;
224}
225
226/*
227 * Decode the body of a message. The header is assumed to be decoded
228 * already and out->hdr is filled in. Only information elements remain.
229 */
230int
231uni_decode_body(struct uni_msg *msg, struct uni_all *out, struct unicx *cx)
232{
233	cx->errcnt = 0;
234	if (out->mtype >= 256)
235		return (-1);
236	if (uni_msgtable[out->mtype] == NULL)
237		return (-1);
238	return (uni_decode_body_internal(out->mtype, msg, &out->u, cx));
239}
240
241
242/*
243 * Decode a uni message
244 */
245int
246uni_decode(struct uni_msg *msg, struct uni_all *out, struct unicx *cx)
247{
248	cx->errcnt = 0;
249	if (uni_decode_head(msg, out, cx))
250		return (-1);
251	if (uni_decode_body(msg, out, cx))
252		return (-2);
253	return (0);
254}
255
256int
257uni_encode(struct uni_msg *msg, struct uni_all *in, struct unicx *cx)
258{
259	if (in->mtype >= 256)
260		return (-1);
261	if (uni_msgtable[in->mtype] == NULL)
262		return (-3);
263
264	return ((uni_msgtable[in->mtype]->encode)(msg, &in->u, cx));
265}
266
267/*
268 * Doesn't belong here
269 */
270void
271uni_initcx(struct unicx *cx)
272{
273	memset(cx, 0, sizeof(struct unicx));
274	cx->tabsiz = 4;
275}
276