276 lines
6.6 KiB
C
276 lines
6.6 KiB
C
/*
|
|
* Copyright (c) 2001-2003
|
|
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* Author: Hartmut Brandt <harti@freebsd.org>
|
|
*
|
|
* $Begemot: libunimsg/netnatm/msg/privmsg.c,v 1.8 2003/10/10 14:50:05 hbb Exp $
|
|
*
|
|
* Private definitions for the MSG code file.
|
|
*
|
|
* This file is included at the begin of the automatically generated
|
|
* uni_msg.c.
|
|
*/
|
|
|
|
/*
|
|
* Decode a UNI message header.
|
|
* Return values:
|
|
* 0 - ok
|
|
* -1 - ignore message (proto, length, CR error)
|
|
*/
|
|
int
|
|
uni_decode_head(struct uni_msg *msg, struct uni_all *out,
|
|
struct unicx *cx __unused)
|
|
{
|
|
u_int mlen;
|
|
|
|
cx->errcnt = 0;
|
|
(void)memset(out, 0, sizeof(struct uni_all));
|
|
|
|
if(uni_msg_len(msg) < 9)
|
|
return -1; /* Q.2931 5.6.2 */
|
|
if(cx->pnni) {
|
|
if(*msg->b_rptr++ != PNNI_PROTO)
|
|
return -1; /* Q.2931 5.6.1 */
|
|
} else {
|
|
if(*msg->b_rptr++ != UNI_PROTO)
|
|
return -1; /* Q.2931 5.6.1 */
|
|
}
|
|
if(*msg->b_rptr++ != 3)
|
|
return -1; /* Q.2931 5.6.3.1 */
|
|
|
|
out->u.hdr.cref.flag = (*msg->b_rptr & 0x80) ? 1 : 0;
|
|
out->u.hdr.cref.cref = (*msg->b_rptr++ & 0x7f) << 16;
|
|
out->u.hdr.cref.cref |= *msg->b_rptr++ << 8;
|
|
out->u.hdr.cref.cref |= *msg->b_rptr++;
|
|
|
|
out->mtype = *msg->b_rptr++;
|
|
|
|
/*
|
|
* Be not too piggy about this byte
|
|
*/
|
|
switch(*msg->b_rptr & 0x13) {
|
|
|
|
case 0x00: case 0x01: case 0x02: case 0x03:
|
|
out->u.hdr.act = UNI_MSGACT_DEFAULT;
|
|
break;
|
|
|
|
case 0x10: case 0x11: case 0x12:
|
|
out->u.hdr.act = *msg->b_rptr & 0x3;
|
|
break;
|
|
|
|
case 0x13: /* Q.2931 5.7.1 */
|
|
out->u.hdr.act = UNI_MSGACT_REPORT;
|
|
break;
|
|
}
|
|
if(cx->pnni && (*msg->b_rptr & 0x08))
|
|
out->u.hdr.pass = 1;
|
|
else
|
|
out->u.hdr.pass = 0;
|
|
|
|
msg->b_rptr++;
|
|
|
|
mlen = *msg->b_rptr++ << 8;
|
|
mlen |= *msg->b_rptr++;
|
|
|
|
/*
|
|
* If the message is longer than the indicated length
|
|
* shorten it. If it is shorter, probably one of the IE
|
|
* decoders will break, but we should proceed. 5.5.6.5
|
|
*/
|
|
#if 0
|
|
if(uni_msg_len(msg) > mlen)
|
|
msg->b_wptr = msg->b_rptr + mlen;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
uni_decode_body_internal(enum uni_msgtype mtype, struct uni_msg *msg,
|
|
union uni_msgall *out, struct unicx *cx)
|
|
{
|
|
enum uni_ietype ietype;
|
|
struct uni_iehdr hdr;
|
|
u_int ielen;
|
|
const struct iedecl *iedecl;
|
|
int err = 0, ret;
|
|
u_char *end;
|
|
|
|
cx->ielast = (enum uni_ietype)0;
|
|
cx->repeat.h.present = 0;
|
|
|
|
while (uni_msg_len(msg) != 0) {
|
|
if (uni_decode_ie_hdr(&ietype, &hdr, msg, cx, &ielen)) {
|
|
/*
|
|
* Short header. Set the ielen to an impossible size.
|
|
* Then we should bump out in the error handling below.
|
|
* We should have at least an IE type here.
|
|
*/
|
|
ielen = 0xffffffff;
|
|
}
|
|
#ifdef DTRACE
|
|
printf("IE %x\n", ietype);
|
|
#endif
|
|
|
|
if ((iedecl = GET_IEDECL(ietype, hdr.coding)) == NULL ||
|
|
ietype == UNI_IE_UNREC) {
|
|
/*
|
|
* entirly unknown IE. Check the length and skip it.
|
|
* Q.2931 5.6.8.1
|
|
*/
|
|
if (ielen > uni_msg_len(msg))
|
|
msg->b_rptr = msg->b_wptr;
|
|
else
|
|
msg->b_rptr += ielen;
|
|
UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK);
|
|
err = -1;
|
|
continue;
|
|
}
|
|
#ifdef DTRACE
|
|
printf("IE %x known\n", ietype);
|
|
#endif
|
|
if (ielen > iedecl->maxlen - 4 || ielen > uni_msg_len(msg)) {
|
|
/*
|
|
* Information element too long -> content error.
|
|
* Let the decoding routine set the error flag and
|
|
* return DEC_ERR.
|
|
* Q.2931 5.6.8.2
|
|
*/
|
|
#if 0
|
|
/*
|
|
* It is not clear how to best handle this error.
|
|
*/
|
|
if (ielen > iedecl->maxlen - 4)
|
|
ielen = iedecl->maxlen - 4;
|
|
#endif
|
|
|
|
if (ielen > uni_msg_len(msg))
|
|
ielen = uni_msg_len(msg);
|
|
|
|
hdr.present |= UNI_IE_ERROR;
|
|
|
|
#ifdef DTRACE
|
|
printf("IE %x length too large\n", ietype);
|
|
#endif
|
|
}
|
|
|
|
#ifdef DTRACE
|
|
else
|
|
printf("IE %x length ok\n", ietype);
|
|
#endif
|
|
end = msg->b_rptr + ielen;
|
|
ret = uni_msgtable[mtype]->decode(out, msg, ietype,
|
|
&hdr, ielen, cx);
|
|
msg->b_rptr = end;
|
|
|
|
#ifdef DTRACE
|
|
printf("IE %x ret %d\n", ietype, ret);
|
|
#endif
|
|
|
|
switch (ret) {
|
|
|
|
case DEC_OK: /* ok */
|
|
break;
|
|
|
|
case DEC_ILL: /* illegal IE */
|
|
/*
|
|
* Unexpected but recognized.
|
|
* Q.2931 5.6.8.3
|
|
*/
|
|
UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_UNK);
|
|
err = -1;
|
|
break;
|
|
|
|
case DEC_ERR: /* bad IE */
|
|
if (iedecl->flags & UNIFL_ACCESS)
|
|
/* this may be wrong: 5.6.8.2 */
|
|
UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_ACC);
|
|
else
|
|
UNI_SAVE_IERR(cx, ietype, hdr.act, UNI_IERR_BAD);
|
|
err = -1;
|
|
break;
|
|
|
|
default:
|
|
PANIC(("bad decode return"));
|
|
}
|
|
cx->ielast = ietype;
|
|
if (ietype != UNI_IE_REPEAT)
|
|
cx->repeat.h.present = 0;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* Decode the body of a message. The header is assumed to be decoded
|
|
* already and out->hdr is filled in. Only information elements remain.
|
|
*/
|
|
int
|
|
uni_decode_body(struct uni_msg *msg, struct uni_all *out, struct unicx *cx)
|
|
{
|
|
cx->errcnt = 0;
|
|
if (out->mtype >= 256)
|
|
return (-1);
|
|
if (uni_msgtable[out->mtype] == NULL)
|
|
return (-1);
|
|
return (uni_decode_body_internal(out->mtype, msg, &out->u, cx));
|
|
}
|
|
|
|
|
|
/*
|
|
* Decode a uni message
|
|
*/
|
|
int
|
|
uni_decode(struct uni_msg *msg, struct uni_all *out, struct unicx *cx)
|
|
{
|
|
cx->errcnt = 0;
|
|
if (uni_decode_head(msg, out, cx))
|
|
return (-1);
|
|
if (uni_decode_body(msg, out, cx))
|
|
return (-2);
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
uni_encode(struct uni_msg *msg, struct uni_all *in, struct unicx *cx)
|
|
{
|
|
if (in->mtype >= 256)
|
|
return (-1);
|
|
if (uni_msgtable[in->mtype] == NULL)
|
|
return (-3);
|
|
|
|
return ((uni_msgtable[in->mtype]->encode)(msg, &in->u, cx));
|
|
}
|
|
|
|
/*
|
|
* Doesn't belong here
|
|
*/
|
|
void
|
|
uni_initcx(struct unicx *cx)
|
|
{
|
|
memset(cx, 0, sizeof(struct unicx));
|
|
cx->tabsiz = 4;
|
|
}
|