NetBSD-5.0.2/usr.sbin/isdn/isdntrace/q931_util.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_util.c - utility functions to print Q.931 traces
 *	-----------------------------------------------------
 *
 *	$Id: q931_util.c,v 1.3 2003/10/06 09:43:28 itojun Exp $ 
 *
 * $FreeBSD$
 *
 *      last edit-date: [Tue Feb 15 13:52:09 2000]
 *
 *---------------------------------------------------------------------------*/

#include "trace.h"

/*---------------------------------------------------------------------------*
 *	decode and print the cause
 *---------------------------------------------------------------------------*/
int
p_q931cause(char *pbuf, unsigned char *buf)
{
	int j;
	int len;
	int i = 0;
	int ls;
	int r = 0;
	int rflag = 0;
	
	i++;	/* index -> length */

	len = buf[i];

	i++;	/* coding/location */
	len--;

	ls = buf[i];
	
	i++;
	len--;
	
	if (!(buf[i-1] & 0x80))
	{
		r = buf[i];		
		rflag = 1;
		i++;
		len--;
	}

	sprintf((pbuf+strlen(pbuf)), "%s ", print_cause_q850(buf[i] & 0x7f));

	sprintf((pbuf+strlen(pbuf)), "\n          (location=");
	
	switch (ls & 0x0f)
	{
	case 0x00:
		sprintf((pbuf+strlen(pbuf)), "user");
		break;
	case 0x01:
		sprintf((pbuf+strlen(pbuf)), "private network serving local user");
		break;
	case 0x02:
		sprintf((pbuf+strlen(pbuf)), "public network serving local user");
		break;
	case 0x03:
		sprintf((pbuf+strlen(pbuf)), "transit network");
		break;
	case 0x04:
		sprintf((pbuf+strlen(pbuf)), "public network serving remote user");
		break;
	case 0x05:
		sprintf((pbuf+strlen(pbuf)), "private network serving remote user");
		break;
	case 0x07:
		sprintf((pbuf+strlen(pbuf)), "international network");
		break;
	case 0x0a:
		sprintf((pbuf+strlen(pbuf)), "network beyond interworking point");
		break;
	default:
		sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", ls & 0x0f);
		break;
	}

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

	switch ((ls & 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;
	}

	if (rflag)
	{
		sprintf((pbuf+strlen(pbuf)), ", rec=");

		switch (r & 0x7f)
		{
			case 0:
				sprintf((pbuf+strlen(pbuf)), "Q.931");
				break;
			case 3:
				sprintf((pbuf+strlen(pbuf)), "X.21");
				break;
			case 4:
				sprintf((pbuf+strlen(pbuf)), "X.25");
				break;
			case 5:
				sprintf((pbuf+strlen(pbuf)), "Q.1031/Q.1051");
				break;
			default:
				sprintf((pbuf+strlen(pbuf)), "Reserved");
				break;
		}
	}

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

	i += (len+1);
	
	return(i);
}

/*---------------------------------------------------------------------------*
 *	decode and print the bearer capability
 *---------------------------------------------------------------------------*/
int
p_q931bc(char *pbuf, unsigned char *buf)
{
	int len;
	int i = 0;
	int mr = 0;
	
	i++;	/* index -> length */

	len = buf[i];

	i++;

	sprintf((pbuf+strlen(pbuf)), "\n          cap=");
	
	switch (buf[i] & 0x1f)
	{
		case 0x00:
			sprintf((pbuf+strlen(pbuf)), "speech");
			break;
		case 0x08:
			sprintf((pbuf+strlen(pbuf)), "unrestricted digital information");
			break;
		case 0x09:
			sprintf((pbuf+strlen(pbuf)), "restricted digital information");
			break;
		case 0x10:
			sprintf((pbuf+strlen(pbuf)), "3.1 kHz audio");
			break;
		case 0x11:
			sprintf((pbuf+strlen(pbuf)), "unrestricted digital information with tones");
			break;
		case 0x18:
			sprintf((pbuf+strlen(pbuf)), "video");
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
			break;
	}

	sprintf((pbuf+strlen(pbuf)), "\n          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)), "NSI Std");
			break;
	}

	i++;
	len--;
	
	sprintf((pbuf+strlen(pbuf)), "\n          rate=");
	
	switch (buf[i] & 0x1f)
	{
		case 0x00:
			sprintf((pbuf+strlen(pbuf)), "packet mode");
			break;
		case 0x10:
			sprintf((pbuf+strlen(pbuf)), "64 kbit/s");
			break;
		case 0x11:
			sprintf((pbuf+strlen(pbuf)), "2 x 64 kbit/s");
			break;
		case 0x13:
			sprintf((pbuf+strlen(pbuf)), "384 kbit/s");
			break;
		case 0x15:
			sprintf((pbuf+strlen(pbuf)), "1536 kbit/s");
			break;
		case 0x17:
			sprintf((pbuf+strlen(pbuf)), "1920 kbit/s");
			break;
		case 0x18:
			sprintf((pbuf+strlen(pbuf)), "Multirate");
			mr = 1;
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
			break;
	}

	sprintf((pbuf+strlen(pbuf)), "\n          mode=");

	switch ((buf[i] & 0x60) >> 5)
	{
		case 0:
			sprintf((pbuf+strlen(pbuf)), "circuit");
			break;
		case 2:
			sprintf((pbuf+strlen(pbuf)), "packet");
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", ((buf[i] & 0x60) >> 5));
			break;
	}

	i++;
	len--;

	if (!len)
		goto exit;
	
	if (mr)
	{
		sprintf((pbuf+strlen(pbuf)), "\n          rate multiplier=%d", buf[i] & 0x7f);
		i++;
		len--;
	}

	if (!len)
		goto exit;
	
			sprintf((pbuf+strlen(pbuf)), "\n          layer1=");
	
			switch (buf[i] & 0x1f)
			{
				case 0x01:
					sprintf((pbuf+strlen(pbuf)), "V.110");
					break;
				case 0x02:
					sprintf((pbuf+strlen(pbuf)), "G.711 mu-law");
					break;
				case 0x03:
					sprintf((pbuf+strlen(pbuf)), "G.711 A-law");
					break;
				case 0x04:
					sprintf((pbuf+strlen(pbuf)), "G.721");
					break;
				case 0x05:
					sprintf((pbuf+strlen(pbuf)), "H.221/H.242");
					break;
				case 0x07:
					sprintf((pbuf+strlen(pbuf)), "Non-Std");
					break;
				case 0x08:
					sprintf((pbuf+strlen(pbuf)), "V.120");
					break;
				case 0x09:
					sprintf((pbuf+strlen(pbuf)), "X.31");
					break;
				default:
					sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
					break;
			}
			i++;
			len--;
	
		if (!len)
			goto exit;

	if (!(buf[i-1] & 0x80))
		{
			sprintf((pbuf+strlen(pbuf)), "\n          user rate=0x%02x ", buf[i] & 0x1f);
	
			if (buf[i] & 0x40)
				sprintf((pbuf+strlen(pbuf)), "(async,");
			else
				sprintf((pbuf+strlen(pbuf)), "(sync,");		
	
			if (buf[i] & 0x20)
				sprintf((pbuf+strlen(pbuf)), "in-band neg. possible)");
			else
				sprintf((pbuf+strlen(pbuf)), "in-band neg not possible)");
			
			i++;
			len--;
		}
	
		if (!len)
			goto exit;

	if (!(buf[i-1] & 0x80))
		{
			sprintf((pbuf+strlen(pbuf)), "\n          clk/flow=0x%02x", buf[i] & 0x1f);
	
			sprintf((pbuf+strlen(pbuf)), "\n          intermediate rate=");
			
			switch ((buf[i] & 0x60) >> 5)
			{
				case 0:
					sprintf((pbuf+strlen(pbuf)), "not used");
					break;
				case 1:
					sprintf((pbuf+strlen(pbuf)), "8 kbit/s");
					break;
				case 2:
					sprintf((pbuf+strlen(pbuf)), "16 kbit/s");
					break;
				case 3:
					sprintf((pbuf+strlen(pbuf)), "32 kbit/s");
					break;
			}
			i++;
			len--;
		}
	
		if (!len)
			goto exit;

	if (!(buf[i-1] & 0x80))
		{
			sprintf((pbuf+strlen(pbuf)), "\n          hdr/mfrm/etc.=0x%02x", buf[i]);
			i++;
			len--;
		}
	
		if (!len)
			goto exit;

	if (!(buf[i-1] & 0x80))
		{
			sprintf((pbuf+strlen(pbuf)), "\n          stop/data/parity=0x%02x", buf[i]);
			i++;
			len--;
		}
	
		if (!len)
			goto exit;

	if (!(buf[i-1] & 0x80))
		{
			sprintf((pbuf+strlen(pbuf)), "\n          modemtype=0x%02x", buf[i]);
			i++;
			len--;
		}

	if (!len)
		goto exit;

		switch (buf[i] & 0x7f)
		{
			case 0x42:
				sprintf((pbuf+strlen(pbuf)), "\n          layer2=Q.921/I.441");
				break;
			case 0x46:
				sprintf((pbuf+strlen(pbuf)), "\n          layer2=X.25 link");
				break;
			default:
				sprintf((pbuf+strlen(pbuf)), "\n          layer2=0x%02x",(buf[i] & 0x7f));
				break;
		}
		i++;
		len--;

	if (!len)
		goto exit;
	
		switch (buf[i] & 0x7f)
		{
			case 0x62:
				sprintf((pbuf+strlen(pbuf)), "\n          layer3=Q.921/I.441");
				break;
			case 0x66:
				sprintf((pbuf+strlen(pbuf)), "\n          layer3=X.25 packet");
				break;
			default:
				sprintf((pbuf+strlen(pbuf)), "\n          layer3=0x%02x",(buf[i] & 0x7f));
				break;
		}
		i++;
		len--;

exit:	
	sprintf((pbuf+strlen(pbuf)), "]");	
	return(i);
}

/*---------------------------------------------------------------------------*
 *	decode and print the ISDN (telephone) number
 *---------------------------------------------------------------------------*/
int
p_q931address(char *pbuf, unsigned char *buf)
{
	int j;
	int len;
	int i = 0;
	int tp;
	int ind = 0;
	int indflag = 0;
	
	i++;	/* index -> length */
	len = buf[i];

	i++;	/* index -> type/plan */
	tp = buf[i];
	
	i++;
	len--;
	
	if (!(tp & 0x80))
	{
		ind = buf[i];		
		indflag = 1;
		i++;
		len--;
	}

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

	switch ((tp & 0x70) >> 4)
	{
		case 0:
			sprintf((pbuf+strlen(pbuf)), " (type=unknown, ");
			break;
		case 1:
			sprintf((pbuf+strlen(pbuf)), " (type=international, ");
			break;
		case 2:
			sprintf((pbuf+strlen(pbuf)), " (type=national, ");
			break;
		case 3:
			sprintf((pbuf+strlen(pbuf)), " (type=network specific, ");
			break;
		case 4:
			sprintf((pbuf+strlen(pbuf)), " (type=subscriber, ");
			break;
		case 6:
			sprintf((pbuf+strlen(pbuf)), " (type=abbreviated, ");
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), " (type=reserved (%d), ", ((tp & 0x70) >> 4));
			break;
	}

	switch (tp & 0x0f)
	{
		case 0:
			sprintf((pbuf+strlen(pbuf)), "plan=unknown");
			break;
		case 1:
			sprintf((pbuf+strlen(pbuf)), "plan=ISDN");
			break;
		case 3:
			sprintf((pbuf+strlen(pbuf)), "plan=Data");
			break;
		case 4:
			sprintf((pbuf+strlen(pbuf)), "plan=Telex");
			break;
		case 8:
			sprintf((pbuf+strlen(pbuf)), "plan=National");
			break;
		case 9:
			sprintf((pbuf+strlen(pbuf)), "plan=private");
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "plan=reserved (%d)", (tp & 0x0f));
			break;
	}

	if (indflag)
	{
		sprintf((pbuf+strlen(pbuf)), ",\n          ");
		switch ((ind & 0x60) >> 5)
		{
			case 0:
				sprintf((pbuf+strlen(pbuf)), "presentation allowed, ");
				break;
			case 1:
				sprintf((pbuf+strlen(pbuf)), "presentation restricted, ");
				break;
			case 2:
				sprintf((pbuf+strlen(pbuf)), "number not available, ");
				break;
			case 3:
				sprintf((pbuf+strlen(pbuf)), "reserved, ");
				break;
		}

		switch (ind & 0x03)
		{
			case 0:
				sprintf((pbuf+strlen(pbuf)), "screening user provided: not screened");
				break;
			case 1:
				sprintf((pbuf+strlen(pbuf)), "screening user provided: verified & passed");
				break;
			case 2:
				sprintf((pbuf+strlen(pbuf)), "screening user provided: verified & failed");
				break;
			case 3:
				sprintf((pbuf+strlen(pbuf)), "screening network provided");
				break;
		}
	}		

	sprintf((pbuf+strlen(pbuf)),")]");

	i += j;

	return(i);
}

/*---------------------------------------------------------------------------*
 *	decode and print HL comatibility
 *---------------------------------------------------------------------------*/
int
p_q931high_compat(char *pbuf, unsigned char *buf)
{
	int len = buf[1];

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

	switch ((buf[2] >> 5) & 0x03)
	{
		case 0: sprintf(pbuf+strlen(pbuf), "CCITT");
			break;
		case 1: sprintf(pbuf+strlen(pbuf), "unknown international standard");
			break;
		case 2: sprintf(pbuf+strlen(pbuf), "unknown national standard");
			break;
		case 3: sprintf(pbuf+strlen(pbuf), "local network standard");
	}

	len--;

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

	switch (buf[3] & 0x7f)
	{
		case 0x01:
			sprintf(pbuf+strlen(pbuf), "Telephony");
			break;
		case 0x04:
			sprintf(pbuf+strlen(pbuf), "Fax Group 2/3");
			break;
		case 0x21:
			sprintf(pbuf+strlen(pbuf), "Fax Group 4 Class I (F.184)");
			break;
		case 0x24:
			sprintf(pbuf+strlen(pbuf), "Teletex basic/mixed (F.230) or Fax Group 4 Class II/III (F.184)");
			break;
		case 0x28:
			sprintf(pbuf+strlen(pbuf), "Teletex basic/processable (F.220)");
			break;
		case 0x31:
			sprintf(pbuf+strlen(pbuf), "Teletex basic mode (F.200)");
			break;
		case 0x32:
			sprintf(pbuf+strlen(pbuf), "Videotex (F.300 and T.101)");
			break;
		case 0x35:
			sprintf(pbuf+strlen(pbuf), "Telex (F.60)");
			break;
		case 0x38:
			sprintf(pbuf+strlen(pbuf), "MHS (X.400 series)");
			break;
		case 0x41:
			sprintf(pbuf+strlen(pbuf), "OSI application (X.200 series)");
			break;
		case 0x5e:
			sprintf(pbuf+strlen(pbuf), "Maintenance");
			break;
		case 0x5f:
			sprintf(pbuf+strlen(pbuf), "Management");
			break;
		case 0x7f:
			sprintf(pbuf+strlen(pbuf), "reserved");
			break;
		default:
			sprintf(pbuf+strlen(pbuf), "UNKNOWN (0x%02x)", buf[3]);
			break;
	}

	len--;

	if (!len)
	{
		sprintf(pbuf+strlen(pbuf), "]");
		return 4;
	}
	
	sprintf(pbuf+strlen(pbuf), " of ");

	switch (buf[4] & 0x7f)
	{
		case 0x01:
			sprintf(pbuf+strlen(pbuf), "Telephony");
			break;
		case 0x04:
			sprintf(pbuf+strlen(pbuf), "Fax Group 2/3");
			break;
		case 0x21:
			sprintf(pbuf+strlen(pbuf), "Fax Group 4 Class I (F.184)");
			break;
		case 0x24:
			sprintf(pbuf+strlen(pbuf), "Teletex basic/mixed (F.230) or Fax Group 4 Class II/III (F.184)");
			break;
		case 0x28:
			sprintf(pbuf+strlen(pbuf), "Teletex basic/processable (F.220)");
			break;
		case 0x31:
			sprintf(pbuf+strlen(pbuf), "Teletex basic mode (F.200)");
			break;
		case 0x32:
			sprintf(pbuf+strlen(pbuf), "Videotex (F.300 and T.101)");
			break;
		case 0x35:
			sprintf(pbuf+strlen(pbuf), "Telex (F.60)");
			break;
		case 0x38:
			sprintf(pbuf+strlen(pbuf), "MHS (X.400 series)");
			break;
		case 0x41:
			sprintf(pbuf+strlen(pbuf), "OSI application (X.200 series)");
			break;
		case 0x7f:
			sprintf(pbuf+strlen(pbuf), "reserved");
			break;
		default:
			sprintf(pbuf+strlen(pbuf), "UNKNOWN (0x%02x)", buf[3]);
			break;
	}
	sprintf(pbuf+strlen(pbuf), "]");
	return 5;
}

/*---------------------------------------------------------------------------*
 *	decode and print user-user IE
 *---------------------------------------------------------------------------*/
int
p_q931user_user(char *pbuf, unsigned char *buf)
{
	int j;
	int len;
	int i = 0;
	int pd;
	
	i++;	/* index -> length */
	len = buf[i];

	i++;	/* index -> protocoldiscriminator */
	pd = buf[i];
	
	switch (pd)
	{
		case 0:
			sprintf((pbuf+strlen(pbuf)), "(pd=user-specific");
			break;
		case 1:
			sprintf((pbuf+strlen(pbuf)), "(pd=OSI high-layer protocols");
			break;
		case 2:
			sprintf((pbuf+strlen(pbuf)), "(pd=X.244");
			break;
		case 3:
			sprintf((pbuf+strlen(pbuf)), "(pd=reserved for system management");
			break;
		case 4:
			sprintf((pbuf+strlen(pbuf)), "(pd=IA5 characters");
			break;
		case 6:
			sprintf((pbuf+strlen(pbuf)), "(pd=X.208/X.209 coded user info");
			break;
		case 7:
			sprintf((pbuf+strlen(pbuf)), "(pd=V.120 rate adaption");
			break;
		case 8:
			sprintf((pbuf+strlen(pbuf)), "(pd=Q.931/I.451 user network call control messages");
			break;
		default:
			if (pd >= 0x10 && pd <= 0x3f)
				sprintf((pbuf+strlen(pbuf)), "(pd=0x%x=reserved for other L3 protocols incl. X.25", pd);
			else if (pd >= 0x40 && pd <= 0x47)
				sprintf((pbuf+strlen(pbuf)), "(pd=0x%x=national use", pd);
			else if (pd >= 0x48 && pd <= 0x4f)
				sprintf((pbuf+strlen(pbuf)), "(pd=0x%x=reserved for ETSI", pd);
			else if (pd >= 0x50 && pd <= 0xfe)
				sprintf((pbuf+strlen(pbuf)), "(pd=0x%x=reserved for other L3 protocols incl. X.25", pd);
			else
				sprintf((pbuf+strlen(pbuf)), "(pd=0x%x=reserved", pd);
			break;
	}

	i++;
	len--;

	sprintf((pbuf+strlen(pbuf)),": (");
	
	for (j = 0; j < len; j++)
	{
		if (pd == 4)
			sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
		else
			sprintf((pbuf+strlen(pbuf)),"0x%2x", buf[j+i]);
	}

	sprintf((pbuf+strlen(pbuf)),"))]");

	i += j;

	return(i);
}

/*---------------------------------------------------------------------------*
 *	decode and notification indicator IE (Q.932, p44)
 *---------------------------------------------------------------------------*/
int
p_q931notification(char *pbuf, unsigned char *buf)
{
	int j = 0;
	int len;
	int i = 0;
	int nd;
	
	i++;	/* index -> length */
	len = buf[i];

	i++;	/* index -> notification description */
	nd = buf[i];
	
	switch (nd)
	{
		case 0x80:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, user suspended", nd);
			break;
		case 0x81:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, user resumed", nd);
			break;
		case 0x82:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, bearer service changed", nd);
			break;

		case 0x83:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, BER coded information", nd);
			break;

		case 0xc2:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, conference established", nd);
			break;
		case 0xc3:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, conference disconnected", nd);
			break;
		case 0xc4:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, other party added", nd);
			break;
		case 0xc5:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, isolated", nd);
			break;
		case 0xc6:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, reattached", nd);
			break;
		case 0xc7:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, other party isolated", nd);
			break;
		case 0xc8:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, other party reattached", nd);
			break;
		case 0xc9:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, other party split", nd);
			break;
		case 0xca:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, other party disconnected", nd);
			break;
		case 0xcb:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, conference floating", nd);
			break;
		case 0xcc:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, conference disconnected, preemption", nd);
			break;
		case 0xcf:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, conference floating, server user preempted", nd);
			break;

		case 0xe0:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, call is a waiting call", nd);
			break;			
		case 0xe8:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, diversion activated", nd);
			break;			
		case 0xe9:	/* ECT, EN 300 369-1 V1.2.4 p12) */
			sprintf((pbuf+strlen(pbuf)), "0x%2x, call transferred, alerting", nd);
			break;
		case 0xea:	/* ECT, EN 300 369-1 V1.2.4 p12) */
			sprintf((pbuf+strlen(pbuf)), "0x%2x, call transferred, active", nd);
			break;
		case 0xee:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, reverse charging", nd);
			break;

		case 0xf9:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, remote hold", nd);
			break;
		case 0xfa:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, remote retrieval", nd);
			break;
		case 0xfb:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, call is diverting", nd);
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "0x%2x, undefined", nd);
			break;
	}

	i++;
	len--;

	if (len)
	{
		sprintf((pbuf+strlen(pbuf)),": (");
		
		for (; j < len; j++)
		{
			if (nd == 4)
				sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
			else
				sprintf((pbuf+strlen(pbuf)),"0x%2x", buf[j+i]);
		}
	
		sprintf((pbuf+strlen(pbuf)),")");
	}
	sprintf((pbuf+strlen(pbuf)),"]");
	i += j;

	return(i);
}

/*---------------------------------------------------------------------------*
 *	decode and print redirecting/redirection number
 *---------------------------------------------------------------------------*/
int
p_q931redir(char *pbuf, unsigned char *buf)
{
	int j;
	int len;
	int i = 0;
	int tp;
	int ind = 0;
	int indflag = 0;
	int reas = 0;
	int reasflag = 0;
	
	i++;	/* index -> length */
	len = buf[i];

	i++;	/* index -> type/plan */
	tp = buf[i];
	
	i++;
	len--;
	
	if (!(tp & 0x80))
	{
		ind = buf[i];		
		indflag = 1;
		i++;
		len--;

		if (!(ind & 0x80))
		{
			reas = buf[i];		
			reasflag = 1;
			i++;
			len--;
		}
	}

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

	switch ((tp & 0x70) >> 4)
	{
	case 0:
		sprintf((pbuf+strlen(pbuf)), " (type=unknown, ");
		break;
	case 1:
		sprintf((pbuf+strlen(pbuf)), " (type=international, ");
		break;
	case 2:
		sprintf((pbuf+strlen(pbuf)), " (type=national, ");
		break;
	case 3:
		sprintf((pbuf+strlen(pbuf)), " (type=network specific, ");
		break;
	case 4:
		sprintf((pbuf+strlen(pbuf)), " (type=subscriber, ");
		break;
	case 6:
		sprintf((pbuf+strlen(pbuf)), " (type=abbreviated, ");
		break;
	default:
		sprintf((pbuf+strlen(pbuf)), " (type=reserved (%d), ", ((tp & 0x70) >> 4));
		break;
	}

	switch (tp & 0x0f)
	{
	case 0:
		sprintf((pbuf+strlen(pbuf)), "plan=unknown");
		break;
	case 1:
		sprintf((pbuf+strlen(pbuf)), "plan=ISDN");
		break;
	case 3:
		sprintf((pbuf+strlen(pbuf)), "plan=Data");
		break;
	case 4:
		sprintf((pbuf+strlen(pbuf)), "plan=Telex");
		break;
	case 8:
		sprintf((pbuf+strlen(pbuf)), "plan=National");
		break;
	case 9:
		sprintf((pbuf+strlen(pbuf)), "plan=private");
		break;
	default:
		sprintf((pbuf+strlen(pbuf)), "plan=reserved (%d)", (tp & 0x0f));
		break;
	}

	if (indflag)
	{
		sprintf((pbuf+strlen(pbuf)), ",\n          ");
		switch ((ind & 0x60) >> 5)
		{
		case 0:
			sprintf((pbuf+strlen(pbuf)), "presentation allowed");
			break;
		case 1:
			sprintf((pbuf+strlen(pbuf)), "presentation restricted");
			break;
		case 2:
			sprintf((pbuf+strlen(pbuf)), "number not available");
			break;
		case 3:
			sprintf((pbuf+strlen(pbuf)), "reserved");
			break;
		}
	}		

	if (reasflag)
	{
		sprintf((pbuf+strlen(pbuf)), ",\n          ");
		switch (reas & 0x0f)
		{
		case 0:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: unknown");
			break;
		case 1:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: call forwarding busy");
			break;
		case 2:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: call forwarding unconditional");
			break;
		case 0xa:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: called DTE");
			break;
		case 0xf:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: call forwarding unconditional");
			break;
		default:
			sprintf((pbuf+strlen(pbuf)), "reason for diversion: reserved (0x%2x)",reas & 0x0f);
			break;
		}
	}		

	sprintf((pbuf+strlen(pbuf)),")]");

	i += j;

	return(i);
}

/* EOF */