NetBSD-5.0.2/usr.sbin/isdn/isdntrace/q931.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1997, 2000 Hellmuth Michaelis. 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.
 *
 *---------------------------------------------------------------------------
 *
 *	q931.c - print Q.931 traces
 *	---------------------------
 *
 *	$Id: q931.c,v 1.3 2003/10/06 09:43:28 itojun Exp $ 
 *
 * $FreeBSD$
 *
 *      last edit-date: [Mon Feb 14 14:51:13 2000]
 *
 *---------------------------------------------------------------------------*/

#include "trace.h"

/*---------------------------------------------------------------------------*
 *	decode Q.931 protocol
 *---------------------------------------------------------------------------*/
void
decode_q931(char *pbuf, int n, int off, unsigned char *buf, int raw)
{
	int codeset = 0;
	int codelock = 0;
	int oldcodeset = 0;
	
	int pd;
	int len;
	int j;
	int i;

	if (n <= 0)
		return;

	*pbuf = '\0';
	
	if (raw)
	{
		for (i = 0; i < n; i += 16)
		{
			sprintf((pbuf+strlen(pbuf)),"Dump:%.3d  ", i+off);
			for (j = 0; j < 16; j++)
				if (i + j < n)
					sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
				else
					sprintf((pbuf+strlen(pbuf)),"   ");
			sprintf((pbuf+strlen(pbuf)),"      ");
			for (j = 0; j < 16 && i + j < n; j++)
				if (isprint(buf[i + j]))
					sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
				else
					sprintf((pbuf+strlen(pbuf)),".");
			sprintf((pbuf+strlen(pbuf)),"\n");
		}
	}

	i = 0;
		
	sprintf((pbuf+strlen(pbuf)), "Q931: ");

	/* protocol discriminator */

	pd = buf[i];

	if (pd >= 0x00 && pd <= 0x07)
		sprintf((pbuf+strlen(pbuf)), "pd=User-User (0x%02x)\n",pd);
	else if (pd == 0x08)
		sprintf((pbuf+strlen(pbuf)), "pd=Q.931/I.451, ");
	else if (pd >= 0x10 && pd <= 0x3f)
		sprintf((pbuf+strlen(pbuf)), "pd=Other Layer 3 or X.25 (0x%02x)\n",pd);
	else if (pd >= 0x40 && pd <= 0x4f)
		sprintf((pbuf+strlen(pbuf)), "pd=National Use (0x%02x)\n",pd);
	else if (pd >= 0x50 && pd <= 0xfe)
		sprintf((pbuf+strlen(pbuf)), "pd=Other Layer 3 or X.25 (0x%02x)\n",pd);
	else
		sprintf((pbuf+strlen(pbuf)), "pd=Reserved (0x%02x)\n",pd);

	/* call reference */

	i++;

	len = buf[i] & 0x0f;

	switch (len)
	{
	case 0:
		sprintf((pbuf+strlen(pbuf)), "cr=Dummy, ");
		break;
	case 1:
		sprintf((pbuf+strlen(pbuf)), "cr=0x%02x %s, ", (buf[i+1] & 0x7f), (buf[i+1] & 0x80) ? "(from destination)" : "(from origination)");
		break;
	case 2:
		sprintf((pbuf+strlen(pbuf)), "cr=0x%02x 0x%02x %s, ", (buf[i+1] & 0x7f), (buf[i+2] & 0x7f), (buf[i+1] & 0x80) ? "(org)" : "(dst)");
		break;
	}

	i += (len+1);
	
	/* message type */	

	sprintf((pbuf+strlen(pbuf)), "message=");

	switch (buf[i])
	{
	/* escape to nationally specific message type */

	case 0x00:
		sprintf((pbuf+strlen(pbuf)), "ESCAPE: ");
		break;

	/* call establishment */

	case 0x01:
		sprintf((pbuf+strlen(pbuf)), "ALERTING: ");
		break;
	case 0x02:
		sprintf((pbuf+strlen(pbuf)), "CALL PROCEEDING: ");
		break;
	case 0x03:
		sprintf((pbuf+strlen(pbuf)), "PROGRESS: ");
		break;
	case 0x05:
		sprintf((pbuf+strlen(pbuf)), "SETUP: ");
		break;
	case 0x07:
		sprintf((pbuf+strlen(pbuf)), "CONNECT: ");
		break;
	case 0x0d:
		sprintf((pbuf+strlen(pbuf)), "SETUP ACKNOWLEDGE: ");
		break;
	case 0x0f:
		sprintf((pbuf+strlen(pbuf)), "CONNECT ACKNOWLEDGE: ");
		break;

	/* call information phase */

	case 0x20:
		sprintf((pbuf+strlen(pbuf)), "USER INFORMATION: ");
		break;
	case 0x21:
		sprintf((pbuf+strlen(pbuf)), "SUSPEND REJECT: ");
		break;
	case 0x22:
		sprintf((pbuf+strlen(pbuf)), "RESUME REJECT: ");
		break;
	case 0x24:
		sprintf((pbuf+strlen(pbuf)), "HOLD: ");
		break;
	case 0x25:
		sprintf((pbuf+strlen(pbuf)), "SUSPEND: ");
		break;
	case 0x26:
		sprintf((pbuf+strlen(pbuf)), "RESUME: ");
		break;
	case 0x28:
		sprintf((pbuf+strlen(pbuf)), "HOLD ACKNOWLEDGE: ");
		break;
	case 0x2d:
		sprintf((pbuf+strlen(pbuf)), "SUSPEND ACKNOWLEDGE: ");
		break;
	case 0x2e:
		sprintf((pbuf+strlen(pbuf)), "RESUME ACKNOWLEDGE: ");
		break;
	case 0x30:
		sprintf((pbuf+strlen(pbuf)), "HOLD REJECT (Q.932): ");
		break;
	case 0x31:
		sprintf((pbuf+strlen(pbuf)), "RETRIEVE (Q.932): ");
		break;
	case 0x32:
		sprintf((pbuf+strlen(pbuf)), "RETRIEVE ACKNOWLEDGE (Q.932): ");
		break;
	case 0x37:
		sprintf((pbuf+strlen(pbuf)), "RETRIEVE REJECT (Q.932): ");
		break;

	/* call clearing */
		
	case 0x40:
		sprintf((pbuf+strlen(pbuf)), "DETACH: ");
		break;
	case 0x45:
		sprintf((pbuf+strlen(pbuf)), "DISCONNECT: ");
		break;
	case 0x46:
		sprintf((pbuf+strlen(pbuf)), "RESTART: ");
		break;
	case 0x48:
		sprintf((pbuf+strlen(pbuf)), "DETACH ACKNOWLEDGE: ");
		break;
	case 0x4d:
		sprintf((pbuf+strlen(pbuf)), "RELEASE: ");
		break;
	case 0x4e:
		sprintf((pbuf+strlen(pbuf)), "RESTART ACKNOWLEDGE: ");
		break;
	case 0x5a:
		sprintf((pbuf+strlen(pbuf)), "RELEASE COMPLETE: ");
		break;
		
	/* misc messages */

	case 0x60:
		sprintf((pbuf+strlen(pbuf)), "SEGMENT: ");
		break;
	case 0x62:
		sprintf((pbuf+strlen(pbuf)), "FACILITY (Q.932): ");
		break;
	case 0x64:
		sprintf((pbuf+strlen(pbuf)), "REGISTER (Q.932): ");
		break;
	case 0x68:
		sprintf((pbuf+strlen(pbuf)), "CANCEL ACKNOWLEDGE: ");
		break;
	case 0x6a:
		sprintf((pbuf+strlen(pbuf)), "FACILITY ACKNOWLEDGE: ");
		break;
	case 0x6c:
		sprintf((pbuf+strlen(pbuf)), "REGISTER ACKNOWLEDGE: ");
		break;
	case 0x6e:
		sprintf((pbuf+strlen(pbuf)), "NOTIFY: ");
		break;
	case 0x70:
		sprintf((pbuf+strlen(pbuf)), "CANCEL REJECT: ");
		break;
	case 0x72:
		sprintf((pbuf+strlen(pbuf)), "FACILITY REJECT: ");
		break;
	case 0x74:
		sprintf((pbuf+strlen(pbuf)), "REGISTER REJECT: ");
		break;
	case 0x75:
		sprintf((pbuf+strlen(pbuf)), "STATUS ENQIRY: ");
		break;
	case 0x79:
		sprintf((pbuf+strlen(pbuf)), "CONGESTION CONTROL: ");
		break;
	case 0x7b:
		sprintf((pbuf+strlen(pbuf)), "INFORMATION: ");
		break;
	case 0x7d:
		sprintf((pbuf+strlen(pbuf)), "STATUS: ");
		break;
	default:
		sprintf((pbuf+strlen(pbuf)), "UNDEFINED, TYPE=0x%02x, ", buf[i]);
		break;
	}

	/* other information elements */

	i++;
	
	for (; i < n;)
	{
		sprintf((pbuf+strlen(pbuf)), "\n     ");
		
		if (buf[i] & 0x80)
		{
			/* single octett info element */

			switch (buf[i] & 0x70)
			{
			case 0x00:	/* reserved */
				sprintf((pbuf+strlen(pbuf)), "[reserved single octett info]");
				break;

			case 0x10:	/* shift */
				oldcodeset = codeset;
				codeset = buf[i] & 0x07;
				if (buf[i] & 0x08)
					codelock = 0;
				else
					codelock = 1;
				sprintf((pbuf+strlen(pbuf)), "[shift: codeset=%d lock=%d]", codeset, codelock);
				break;

			case 0x20:	/* more data */
				if (buf[i] & 0x01)
					sprintf((pbuf+strlen(pbuf)), "[sending complete]");
				else
					sprintf((pbuf+strlen(pbuf)), "[more data]");
				break;

			case 0x30:	/* congestion level */
				sprintf((pbuf+strlen(pbuf)), "[congestion level=");
				switch (buf[i] & 0x0f)
				{
				case 0x00:
					sprintf((pbuf+strlen(pbuf)), "rx-ready]");
					break;
				case 0x0f:
					sprintf((pbuf+strlen(pbuf)), "rx-not-ready]");
					break;
				default:
					sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)]", buf[i] & 0x0f);
					break;
				}
				break;
				
			case 0x50:	/* repeat ind */
				sprintf((pbuf+strlen(pbuf)), "[repeat indicator]");
				break;

			default:
				sprintf((pbuf+strlen(pbuf)), "[UNKNOWN SINGLE OCTET ELEMENT 0x%02x]", buf[i]);
				break;
			}

			i++;	/* next */

		}
		else
		{
			/* variable length info element */

			if (codeset == 0)
			{
				switch (buf[i])
				{
				case 0x00:
					sprintf((pbuf+strlen(pbuf)), "[segmented message: ");
					break;
				case 0x04:
					sprintf((pbuf+strlen(pbuf)), "[bearer capability: ");
					i += p_q931bc(pbuf, &buf[i]);
					goto next;
					break;
				case 0x08:
					sprintf((pbuf+strlen(pbuf)), "[cause: ");
					i += p_q931cause(pbuf, &buf[i]);
					goto next;
					break;
				case 0x0c:
					sprintf((pbuf+strlen(pbuf)), "[connected address (old): ");
					break;
				case 0x0d:
					sprintf((pbuf+strlen(pbuf)), "[extended facility (Q.932: )");
					break;
				case 0x10:
					sprintf((pbuf+strlen(pbuf)), "[call identity: ");
					break;
				case 0x14:
					sprintf((pbuf+strlen(pbuf)), "[call state: ");
					i++;
					len = buf[i];
					i++;
					sprintf((pbuf+strlen(pbuf)), "Std=");
					switch ((buf[i] & 0x60) >> 5)
					{
					case 0:
						sprintf((pbuf+strlen(pbuf)), "CCITT");
						break;
					case 1:
						sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "National");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "Special");
						break;
					}
					sprintf((pbuf+strlen(pbuf)), ", State=");

					switch ((buf[i] & 0x3f))
					{
					case 0:
						sprintf((pbuf+strlen(pbuf)), "Null");
						break;
					case 1:
						sprintf((pbuf+strlen(pbuf)), "Call initiated");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "Overlap sending");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "Outgoing call proceeding");
						break;
					case 4:
						sprintf((pbuf+strlen(pbuf)), "Call delivered");
						break;
					case 6:
						sprintf((pbuf+strlen(pbuf)), "Call present");
						break;
					case 7:
						sprintf((pbuf+strlen(pbuf)), "Call received");
						break;
					case 8:
						sprintf((pbuf+strlen(pbuf)), "Connect request");
						break;
					case 9:
						sprintf((pbuf+strlen(pbuf)), "Incoming call proceeding");
						break;
					case 10:
						sprintf((pbuf+strlen(pbuf)), "Active");
						break;
					case 11:
						sprintf((pbuf+strlen(pbuf)), "Disconnect request");
						break;
					case 12:
						sprintf((pbuf+strlen(pbuf)), "Disconnect indication");
						break;
					case 15:
						sprintf((pbuf+strlen(pbuf)), "Suspend request");
						break;
					case 17:
						sprintf((pbuf+strlen(pbuf)), "Resume request");
						break;
					case 19:
						sprintf((pbuf+strlen(pbuf)), "Release request");
						break;
					case 22:
						sprintf((pbuf+strlen(pbuf)), "Call abort");
						break;
					case 25:
						sprintf((pbuf+strlen(pbuf)), "Overlap receiving");
						break;
					case 0x3d:
						sprintf((pbuf+strlen(pbuf)), "Restart request");
						break;
					case 0x3e:
						sprintf((pbuf+strlen(pbuf)), "Restart");
						break;
					default:
						sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
						break;
					}
					sprintf((pbuf+strlen(pbuf)), "]");
					i++;
					goto next;
					break;
				case 0x18:
					sprintf((pbuf+strlen(pbuf)), "[channel id: channel=");
					i++;
					len = buf[i];
					i++;
					switch (buf[i] & 0x03)
					{
					case 0:
						sprintf((pbuf+strlen(pbuf)), "no channel");
						break;
					case 1:
						sprintf((pbuf+strlen(pbuf)), "B-1");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "B-2");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "any channel");
						break;
					}
					if (buf[i] & 0x08)
						sprintf((pbuf+strlen(pbuf)), " (exclusive)]");
					else
						sprintf((pbuf+strlen(pbuf)), " (preferred)]");
					i++;
					goto next;
					break;
				case 0x19:
					sprintf((pbuf+strlen(pbuf)), "[data link connection id (Q.933): ");
					break;
				case 0x1c:
					i += q932_facility(pbuf, &buf[i]);
					goto next;
					break;
				case 0x1e:
					sprintf((pbuf+strlen(pbuf)), "[progress ind: ");
					i++;
					len = buf[i];
					i++;
					sprintf((pbuf+strlen(pbuf)), "Std=");
					switch ((buf[i] & 0x60) >> 5)
					{
					case 0:
						sprintf((pbuf+strlen(pbuf)), "CCITT");
						break;
					case 1:
						sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "National");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "Local");
						break;
					}
					sprintf((pbuf+strlen(pbuf)), ", Loc=");

					switch ((buf[i] & 0x0f))
					{
					case 0:
						sprintf((pbuf+strlen(pbuf)), "User");
						break;
					case 1:
						sprintf((pbuf+strlen(pbuf)), "Private network serving local user");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "Public network serving local user");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "Transit network");
						break;
					case 4:
						sprintf((pbuf+strlen(pbuf)), "Public network serving remote user");
						break;
					case 5:
						sprintf((pbuf+strlen(pbuf)), "Private network serving remote user");
						break;
					case 6:
						sprintf((pbuf+strlen(pbuf)), "Network beyond interworking point");
						break;
					default:
						sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
						break;
					}

					i++;

					sprintf((pbuf+strlen(pbuf)), "\n          Description: ");
					
					switch ((buf[i] & 0x7f))
					{
					case 1:
						sprintf((pbuf+strlen(pbuf)), "Call is not end-to-end ISDN");
						break;
					case 2:
						sprintf((pbuf+strlen(pbuf)), "Destination address is non-ISDN");
						break;
					case 3:
						sprintf((pbuf+strlen(pbuf)), "Origination address is non-ISDN");
						break;
					case 4:
						sprintf((pbuf+strlen(pbuf)), "Call has returned to the ISDN");
						break;
					case 5:
						sprintf((pbuf+strlen(pbuf)), "Interworking occurred, Service change");
						break;
					case 8:
						sprintf((pbuf+strlen(pbuf)), "In-band info or appropriate pattern now available");
						break;
					default:
						sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
						break;
					}
					sprintf((pbuf+strlen(pbuf)), "]");
					i++;
					goto next;
					break;
				case 0x20:
					sprintf((pbuf+strlen(pbuf)), "[network specific facilities: ");
					break;
				case 0x24:
					sprintf((pbuf+strlen(pbuf)), "[terminal capabilities: ");
					break;
				case 0x27:
					sprintf((pbuf+strlen(pbuf)), "[notification indicator: ");
					i += p_q931notification(pbuf, &buf[i]);
					goto next;
					break;
				case 0x28:
					sprintf((pbuf+strlen(pbuf)), "[display: ");
					i++;
					len = buf[i];
					i++;
					for (j = 0; j < len; j++)
					{
						sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
					}
					sprintf((pbuf+strlen(pbuf)),"]");
					i += j;
					goto next;
					break;
				case 0x29:
					sprintf((pbuf+strlen(pbuf)), "[date/time: ");
					i++;
					len = buf[i];
					i++;
					j = 0;
					sprintf((pbuf+strlen(pbuf)),"%.2d.%.2d.%.2d",
						buf[i+2], buf[i+1], buf[i]);
					j+=3;
					if (j < len)
					{
						sprintf((pbuf+strlen(pbuf))," %.2d", buf[i+3]);
						j++;
					}
					if (j < len)
					{
						sprintf((pbuf+strlen(pbuf)),":%.2d", buf[i+4]);
						j++;
					}
					if (j < len)
					{
						sprintf((pbuf+strlen(pbuf)),":%.2d", buf[i+5]);
						j++;
					}
					sprintf((pbuf+strlen(pbuf)),"]");	
					i += len;
					goto next;
					break;
				case 0x2c:
					sprintf((pbuf+strlen(pbuf)), "[keypad: ");
					break;
				case 0x30:
					sprintf((pbuf+strlen(pbuf)), "[keypad echo: ");
					break;
				case 0x32:
					sprintf((pbuf+strlen(pbuf)), "[information req (Q.932): ");
					break;
				case 0x34:
					sprintf((pbuf+strlen(pbuf)), "[signal: ");
					break;
				case 0x36:
					sprintf((pbuf+strlen(pbuf)), "[switchhook: ");
					break;
				case 0x38:
					sprintf((pbuf+strlen(pbuf)), "[feature activation (Q.932): ");
					break;
				case 0x39:
					sprintf((pbuf+strlen(pbuf)), "[feature ind (Q.932): ");
					break;
				case 0x3a:
					sprintf((pbuf+strlen(pbuf)), "[service profile id (Q.932): ");
					break;
				case 0x3b:
					sprintf((pbuf+strlen(pbuf)), "[endpoint id (Q.932): ");
					break;
				case 0x40:
					sprintf((pbuf+strlen(pbuf)), "[information rate: ");
					break;
				case 0x41:
					sprintf((pbuf+strlen(pbuf)), "[precedence level (Q.955): ");
					break;
				case 0x42:
					sprintf((pbuf+strlen(pbuf)), "[end-to-end transit delay: ");
					break;
				case 0x43:
					sprintf((pbuf+strlen(pbuf)), "[transit delay detection and indication: ");
					break;
				case 0x44:
					sprintf((pbuf+strlen(pbuf)), "[packet layer binary parameters: ");
					break;
				case 0x45:
					sprintf((pbuf+strlen(pbuf)), "[packet layer window size: ");
					break;
				case 0x46:
					sprintf((pbuf+strlen(pbuf)), "[packet size: ");
					break;
				case 0x47:
					sprintf((pbuf+strlen(pbuf)), "[closed user group: ");
					break;
				case 0x48:
					sprintf((pbuf+strlen(pbuf)), "[link layer core parameters (Q.933): ");
					break;
				case 0x49:
					sprintf((pbuf+strlen(pbuf)), "[link layer protocol parameters (Q.933): ");
					break;
				case 0x4a:
					sprintf((pbuf+strlen(pbuf)), "[reverse charging information: ");
					break;
				case 0x4c:
					sprintf((pbuf+strlen(pbuf)), "[connected number (Q.951): ");
					i += p_q931address(pbuf, &buf[i]);
					goto next;
					break;

					break;
				case 0x4d:
					sprintf((pbuf+strlen(pbuf)), "[connected subaddress (Q.951): ");
					break;
				case 0x50:
					sprintf((pbuf+strlen(pbuf)), "[X.213 priority (Q.933): ");
					break;
				case 0x51:
					sprintf((pbuf+strlen(pbuf)), "[report type (Q.933): ");
					break;
				case 0x53:
					sprintf((pbuf+strlen(pbuf)), "[link integrity verification (Q.933): ");
					break;
				case 0x57:
					sprintf((pbuf+strlen(pbuf)), "[PVC status (Q.933): ");
					break;
				case 0x6c:
					sprintf((pbuf+strlen(pbuf)), "[calling party number: ");
					i += p_q931address(pbuf, &buf[i]);
					goto next;
					break;
				case 0x6d:
					sprintf((pbuf+strlen(pbuf)), "[calling party subaddress: ");
					break;
				case 0x70:
					sprintf((pbuf+strlen(pbuf)), "[called party number: ");
					i += p_q931address(pbuf, &buf[i]);
					goto next;
					break;
				case 0x71:
					sprintf((pbuf+strlen(pbuf)), "[called party subaddress: ");
					break;
				case 0x74:
					sprintf((pbuf+strlen(pbuf)), "[redirecting number: ");
					i += p_q931redir(pbuf, &buf[i]);
					goto next;
					break;
				case 0x76:
					sprintf((pbuf+strlen(pbuf)), "[redirection number: ");
					i += p_q931redir(pbuf, &buf[i]);
					goto next;
					break;
				case 0x78:
					sprintf((pbuf+strlen(pbuf)), "[transit network selection: ");
					break;
				case 0x79:
					sprintf((pbuf+strlen(pbuf)), "[restart indicator: ");
					break;
				case 0x7c:
					sprintf((pbuf+strlen(pbuf)), "[low layer compatibility: ");
					break;
				case 0x7d:
					sprintf((pbuf+strlen(pbuf)), "[high layer compatibility:");
					i += p_q931high_compat(pbuf, &buf[i]);
					goto next;
					break;
				case 0x7e:
					sprintf((pbuf+strlen(pbuf)), "[user-user: ");
					i += p_q931user_user(pbuf, &buf[i]);
					goto next;
					break;
				case 0x7f:
					sprintf((pbuf+strlen(pbuf)), "[escape for extension: ");
					break;
				default:
					sprintf((pbuf+strlen(pbuf)), "[UNKNOWN INFO-ELEMENT-ID=0x%02x: ", buf[i]);
					break;
				}
			}
			else
			{
				sprintf((pbuf+strlen(pbuf)), "[UNKNOWN CODESET=%d, IE=0x%02x: ", codeset, buf[i]);
			}

			i++;	/* index -> length */

			len = buf[i];

			sprintf((pbuf+strlen(pbuf)), "LEN=0x%02x, DATA=", len);			

			i++;	/* index -> 1st param */

			for (j = 0; j < len; j++)
			{
				sprintf((pbuf+strlen(pbuf)),"0x%02x ", buf[j+i]);
			}
	
			sprintf((pbuf+strlen(pbuf)),"]");

			i += len;

next:

			if (!codelock && (codeset != oldcodeset))
				codeset = oldcodeset;
		}
	}
	sprintf((pbuf+strlen(pbuf)),"\n");
}

/* EOF */