17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1a754c38Skcpoon  * Common Development and Distribution License (the "License").
6*1a754c38Skcpoon  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*1a754c38Skcpoon 
227c478bd9Sstevel@tonic-gate /*
23*1a754c38Skcpoon  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/socket.h>
317c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
327c478bd9Sstevel@tonic-gate #include <inet/common.h>
337c478bd9Sstevel@tonic-gate #include <netinet/in.h>
347c478bd9Sstevel@tonic-gate #include <netinet/sctp.h>
357c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include "snoop.h"
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Snoop interpreter for SCTP (rfc2960).
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * To add support for an upper-layer protocol, modify either
437c478bd9Sstevel@tonic-gate  * the port-dispatcher in snoop_rport.c, or the protocol ID
447c478bd9Sstevel@tonic-gate  * dispatcher at the bottom of this file (or both).
457c478bd9Sstevel@tonic-gate  */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static void interpret_protoid(int, uint32_t, char *, int);
487c478bd9Sstevel@tonic-gate extern char *prot_prefix;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * This defines the length of internal, unbounded buffers. We set
527c478bd9Sstevel@tonic-gate  * this to be MAXLINE (the maximum verbose display line length) -
537c478bd9Sstevel@tonic-gate  * 64, which should be enough for all necessary descriptions. 64
547c478bd9Sstevel@tonic-gate  * bytes seems like a reasonably conservative estimate of the
557c478bd9Sstevel@tonic-gate  * maximum prefix length snoop may add to any text buffer it hands out.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate #define	BUFLEN	MAXLINE - 64
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * Common structure to hold descriptions and parsers for all
617c478bd9Sstevel@tonic-gate  * chunks, parameters, and errors. Each parser should implement
627c478bd9Sstevel@tonic-gate  * this interface:
637c478bd9Sstevel@tonic-gate  *
647c478bd9Sstevel@tonic-gate  * void parse(int flags, uint8_t cflags, void *data, int datalen);
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * Where flags is the snoop flags, cflags are the chunk flags, data
677c478bd9Sstevel@tonic-gate  * is the chunk or parameter data (not including the chunk or
687c478bd9Sstevel@tonic-gate  * parameter header), and datalen is the length of the chunk or
697c478bd9Sstevel@tonic-gate  * parameter data (again not including any headers).
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate typedef void parse_func_t(int, uint8_t, const void *, int);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate typedef struct {
747c478bd9Sstevel@tonic-gate 	uint16_t id;
757c478bd9Sstevel@tonic-gate 	const char *sdesc;	/* short description */
767c478bd9Sstevel@tonic-gate 	const char *vdesc;	/* verbose description */
777c478bd9Sstevel@tonic-gate 	parse_func_t *parse;	/* parser function */
787c478bd9Sstevel@tonic-gate } dispatch_t;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static void interpret_params(const void *, int, char *, const dispatch_t *,
817c478bd9Sstevel@tonic-gate     int, int);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * Chunk parsers
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate static parse_func_t parse_abort_chunk, parse_data_chunk, parse_error_chunk,
877c478bd9Sstevel@tonic-gate     parse_init_chunk, parse_opaque_chunk, parse_sack_chunk,
887c478bd9Sstevel@tonic-gate     parse_shutdone_chunk, parse_shutdown_chunk, parse_asconf_chunk,
897c478bd9Sstevel@tonic-gate     parse_ftsn_chunk;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Chunk parser dispatch table. There are few enough chunks defined
947c478bd9Sstevel@tonic-gate  * in the core protocol, and they are sequential, so the chunk code
957c478bd9Sstevel@tonic-gate  * can be used as the index into this array for the common case.
967c478bd9Sstevel@tonic-gate  * It is still necessary to check that the code and index match,
977c478bd9Sstevel@tonic-gate  * since optional extensions will not follow sequentially the
987c478bd9Sstevel@tonic-gate  * core chunks.
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate static const dispatch_t chunk_dispatch_table[] = {
1017c478bd9Sstevel@tonic-gate /*	code	F_SUM desc	F_DTAIL desc		parser function */
1027c478bd9Sstevel@tonic-gate 	{ CHUNK_DATA,			"Data",		"Data Chunk",
1037c478bd9Sstevel@tonic-gate 	    parse_data_chunk },
1047c478bd9Sstevel@tonic-gate 	{ CHUNK_INIT,			"Init",		"Init Chunk",
1057c478bd9Sstevel@tonic-gate 	    parse_init_chunk },
1067c478bd9Sstevel@tonic-gate 	{ CHUNK_INIT_ACK,		"Init ACK",	"Init ACK Chunk",
1077c478bd9Sstevel@tonic-gate 	    parse_init_chunk },
1087c478bd9Sstevel@tonic-gate 	{ CHUNK_SACK,			"SACK",		"SACK Chunk",
1097c478bd9Sstevel@tonic-gate 	    parse_sack_chunk },
1107c478bd9Sstevel@tonic-gate 	{ CHUNK_HEARTBEAT,		"Heartbeat",	"Heartbeat Chunk",
1117c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1127c478bd9Sstevel@tonic-gate 	{ CHUNK_HEARTBEAT_ACK,		"Heartbeat ACK", "Heartbeat ACK Chunk",
1137c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1147c478bd9Sstevel@tonic-gate 	{ CHUNK_ABORT,			"Abort",	"Abort Chunk",
1157c478bd9Sstevel@tonic-gate 	    parse_abort_chunk },
1167c478bd9Sstevel@tonic-gate 	{ CHUNK_SHUTDOWN,		"Shutdown",	"Shutdown Chunk",
1177c478bd9Sstevel@tonic-gate 	    parse_shutdown_chunk },
1187c478bd9Sstevel@tonic-gate 	{ CHUNK_SHUTDOWN_ACK,		"Shutdown ACK",	"Shutdown ACK Chunk",
1197c478bd9Sstevel@tonic-gate 	    NULL },
1207c478bd9Sstevel@tonic-gate 	{ CHUNK_ERROR,			"Err",		"Error Chunk",
1217c478bd9Sstevel@tonic-gate 	    parse_error_chunk },
1227c478bd9Sstevel@tonic-gate 	{ CHUNK_COOKIE,			"Cookie",	"Cookie Chunk",
1237c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1247c478bd9Sstevel@tonic-gate 	{ CHUNK_COOKIE_ACK,		"Cookie ACK",	"Cookie ACK Chunk",
1257c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1267c478bd9Sstevel@tonic-gate 	{ CHUNK_ECNE,			"ECN Echo",	"ECN Echo Chunk",
1277c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1287c478bd9Sstevel@tonic-gate 	{ CHUNK_CWR,			"CWR",		"CWR Chunk",
1297c478bd9Sstevel@tonic-gate 	    parse_opaque_chunk },
1307c478bd9Sstevel@tonic-gate 	{ CHUNK_SHUTDOWN_COMPLETE,	"Shutdown Done", "Shutdown Done",
1317c478bd9Sstevel@tonic-gate 	    parse_shutdone_chunk },
1327c478bd9Sstevel@tonic-gate 	{ CHUNK_FORWARD_TSN,		"FORWARD TSN", 	"Forward TSN Chunk",
1337c478bd9Sstevel@tonic-gate 	    parse_ftsn_chunk },
1347c478bd9Sstevel@tonic-gate 	{ CHUNK_ASCONF_ACK,		"ASCONF ACK", 	"ASCONF ACK Chunk",
1357c478bd9Sstevel@tonic-gate 	    parse_asconf_chunk },
1367c478bd9Sstevel@tonic-gate 	{ CHUNK_ASCONF,			"ASCONF", 	"ASCONF Chunk",
1377c478bd9Sstevel@tonic-gate 	    parse_asconf_chunk }
1387c478bd9Sstevel@tonic-gate };
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * Parameter Parsers
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate static parse_func_t parse_encap_param, parse_int32_param, parse_ip4_param,
1447c478bd9Sstevel@tonic-gate     parse_ip6_param, parse_opaque_param, parse_suppaddr_param,
1457c478bd9Sstevel@tonic-gate     parse_unrec_chunk, parse_addip_param, parse_asconferr_param,
1467c478bd9Sstevel@tonic-gate     parse_asconfok_param, parse_addiperr_param;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * Parameter parser dispatch table. The summary description is not
1507c478bd9Sstevel@tonic-gate  * used here. Strictly speaking, parameter types are defined within
1517c478bd9Sstevel@tonic-gate  * the context of a chunk type. However, thus far the IETF WG has
1527c478bd9Sstevel@tonic-gate  * agreed to follow the convention that parameter types are globally
1537c478bd9Sstevel@tonic-gate  * unique (and why not, with a 16-bit namespace). However, if this
1547c478bd9Sstevel@tonic-gate  * ever changes, there will need to be different parameter dispatch
1557c478bd9Sstevel@tonic-gate  * tables for each chunk type.
1567c478bd9Sstevel@tonic-gate  */
1577c478bd9Sstevel@tonic-gate static const dispatch_t parm_dispatch_table[] = {
1587c478bd9Sstevel@tonic-gate /*	code	F_SUM desc	F_DTAIL desc		parser function */
1597c478bd9Sstevel@tonic-gate 	{ PARM_UNKNOWN,	"",		"Unknown Parameter",
1607c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1617c478bd9Sstevel@tonic-gate 	{ PARM_HBINFO,	"",		"Heartbeat Info",
1627c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1637c478bd9Sstevel@tonic-gate 	{ PARM_ADDR4,	"",		"IPv4 Address",
1647c478bd9Sstevel@tonic-gate 	    parse_ip4_param },
1657c478bd9Sstevel@tonic-gate 	{ PARM_ADDR6,	"",		"IPv6 Address",
1667c478bd9Sstevel@tonic-gate 	    parse_ip6_param },
1677c478bd9Sstevel@tonic-gate 	{ PARM_COOKIE,	"",		"Cookie",
1687c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1697c478bd9Sstevel@tonic-gate 	{ PARM_UNRECOGNIZED,	"",	"Unrecognized Param",
1707c478bd9Sstevel@tonic-gate 	    parse_encap_param },
1717c478bd9Sstevel@tonic-gate 	{ PARM_COOKIE_PRESERVE,	"",	"Cookie Preservative",
1727c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1737c478bd9Sstevel@tonic-gate 	{ 10,	"",			"Reserved for ECN",
1747c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1757c478bd9Sstevel@tonic-gate 	{ PARM_ADDR_HOST_NAME,	"",	"Host Name Parameter",
1767c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1777c478bd9Sstevel@tonic-gate 	{ PARM_SUPP_ADDRS,	"",	"Supported Addresses",
1787c478bd9Sstevel@tonic-gate 	    parse_suppaddr_param },
1797c478bd9Sstevel@tonic-gate 	{ PARM_ECN_CAPABLE,	"",	"ECN Capable",
1807c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
1817c478bd9Sstevel@tonic-gate 	{ PARM_ADD_IP,	"",		"Add IP",
1827c478bd9Sstevel@tonic-gate 	    parse_addip_param },
1837c478bd9Sstevel@tonic-gate 	{ PARM_DEL_IP,	"",		"Del IP",
1847c478bd9Sstevel@tonic-gate 	    parse_addip_param },
1857c478bd9Sstevel@tonic-gate 	{ PARM_ASCONF_ERROR,	"",	"ASCONF Error Ind",
1867c478bd9Sstevel@tonic-gate 	    parse_asconferr_param },
1877c478bd9Sstevel@tonic-gate 	{ PARM_PRIMARY_ADDR,	"",	"Set Primary Address",
1887c478bd9Sstevel@tonic-gate 	    parse_addip_param },
1897c478bd9Sstevel@tonic-gate 	{ PARM_FORWARD_TSN,	"",	"Forward TSN",
1907c478bd9Sstevel@tonic-gate 	    NULL },
1917c478bd9Sstevel@tonic-gate 	{ PARM_ASCONF_SUCCESS,	"",	"ASCONF Success Ind",
1927c478bd9Sstevel@tonic-gate 	    parse_asconfok_param }
1937c478bd9Sstevel@tonic-gate };
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * Errors have the same wire format at parameters.
1977c478bd9Sstevel@tonic-gate  */
1987c478bd9Sstevel@tonic-gate static const dispatch_t err_dispatch_table[] = {
1997c478bd9Sstevel@tonic-gate /*	code	F_SUM desc	F_DTAIL desc		parser function */
2007c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_UNKNOWN,	"",		"Unknown Error",
2017c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2027c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_BAD_SID,	"",		"Invalid Stream ID",
2037c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2047c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_MISSING_PARM,	"",	"Missing Parameter",
2057c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2067c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_STALE_COOKIE,	"",	"Stale Cookie",
2077c478bd9Sstevel@tonic-gate 	    parse_int32_param },
2087c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_NO_RESOURCES,	"",	"Out Of Resources",
2097c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2107c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_BAD_ADDR,	"",		"Unresolvable Address",
2117c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2127c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_UNREC_CHUNK,	"",		"Unrecognized Chunk",
2137c478bd9Sstevel@tonic-gate 	    parse_unrec_chunk },
2147c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_BAD_MANDPARM,	"",	"Bad Mandatory Parameter",
2157c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2167c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_UNREC_PARM,	"",		"Unrecognized Parameter",
2177c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2187c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_NO_USR_DATA,	"",		"No User Data",
2197c478bd9Sstevel@tonic-gate 	    parse_int32_param },
2207c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_COOKIE_SHUT,	"",		"Cookie During Shutdown",
2217c478bd9Sstevel@tonic-gate 	    parse_opaque_param },
2227c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_DELETE_LASTADDR,	"",	"Delete Last Remaining Address",
2237c478bd9Sstevel@tonic-gate 	    parse_addiperr_param },
2247c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_RESOURCE_SHORTAGE,	"",	"Resource Shortage",
2257c478bd9Sstevel@tonic-gate 	    parse_addiperr_param },
2267c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_DELETE_SRCADDR,	"",	"Delete Source IP Address",
2277c478bd9Sstevel@tonic-gate 	    parse_addiperr_param },
2287c478bd9Sstevel@tonic-gate 	{ SCTP_ERR_AUTH_ERR,	"",		"Not authorized",
2297c478bd9Sstevel@tonic-gate 	    parse_addiperr_param }
2307c478bd9Sstevel@tonic-gate };
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate  * These are global because the data chunk parser needs them to dispatch
2347c478bd9Sstevel@tonic-gate  * to ULPs. The alternative is to add source and dest port arguments
2357c478bd9Sstevel@tonic-gate  * to every parser, which seems even messier (since *only* the data
2367c478bd9Sstevel@tonic-gate  * chunk parser needs it)...
2377c478bd9Sstevel@tonic-gate  */
2387c478bd9Sstevel@tonic-gate static in_port_t sport, dport;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /* Summary line miscellany */
2417c478bd9Sstevel@tonic-gate static int sumlen;
2427c478bd9Sstevel@tonic-gate static char scratch[MAXLINE];
2437c478bd9Sstevel@tonic-gate static char *sumline;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate #define	SUMAPPEND(fmt) \
2467c478bd9Sstevel@tonic-gate 	sumlen -= snprintf fmt; \
2477c478bd9Sstevel@tonic-gate 	(void) strlcat(sumline, scratch, sumlen)
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate #define	DUMPHEX_MAX	16
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate static const dispatch_t *
lookup_dispatch(int id,const dispatch_t * tbl,int tblsz)2527c478bd9Sstevel@tonic-gate lookup_dispatch(int id, const dispatch_t *tbl, int tblsz)
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate 	int i;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * Try fast lookup first. The common chunks defined in RFC2960
2587c478bd9Sstevel@tonic-gate 	 * will have indices aligned with their IDs, so this works for
2597c478bd9Sstevel@tonic-gate 	 * the common case.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (id < (tblsz - 1)) {
2627c478bd9Sstevel@tonic-gate 		if (id == tbl[id].id) {
2637c478bd9Sstevel@tonic-gate 			return (tbl + id);
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/*
2687c478bd9Sstevel@tonic-gate 	 * Nope - probably an extension. Search the whole table,
2697c478bd9Sstevel@tonic-gate 	 * starting from the end, since extensions are at the end.
2707c478bd9Sstevel@tonic-gate 	 */
2717c478bd9Sstevel@tonic-gate 	for (i = tblsz - 1; i >= 0; i--) {
2727c478bd9Sstevel@tonic-gate 		if (id == tbl[i].id) {
2737c478bd9Sstevel@tonic-gate 			return (tbl + i);
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	return (NULL);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate  * Dumps no more than the first DUMPHEX_MAX bytes in hex. If
2827c478bd9Sstevel@tonic-gate  * the user wants more, they can use the -x option to snoop.
2837c478bd9Sstevel@tonic-gate  */
2847c478bd9Sstevel@tonic-gate static void
dumphex(const uchar_t * payload,int payload_len,char * msg)2857c478bd9Sstevel@tonic-gate dumphex(const uchar_t *payload, int payload_len, char *msg)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	int index;
2887c478bd9Sstevel@tonic-gate 	int end;
2897c478bd9Sstevel@tonic-gate 	char buf[BUFLEN];
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (payload_len == 0) {
2927c478bd9Sstevel@tonic-gate 		return;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	end = payload_len > DUMPHEX_MAX ? DUMPHEX_MAX : payload_len;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	for (index = 0; index < end; index++) {
2987c478bd9Sstevel@tonic-gate 		(void) snprintf(&buf[index * 3], 4, " %.2x", payload[index]);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	if (payload_len > DUMPHEX_MAX) {
3027c478bd9Sstevel@tonic-gate 		(void) strlcat(buf, " ...", BUFLEN);
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), BUFLEN, msg, buf);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  * Present perscribed action for unknowns according to rfc2960. Works
3107c478bd9Sstevel@tonic-gate  * for chunks and parameters as well if the parameter type is
3117c478bd9Sstevel@tonic-gate  * shifted 8 bits right.
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate static const char *
get_action_desc(uint8_t id)3147c478bd9Sstevel@tonic-gate get_action_desc(uint8_t id)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	if ((id & 0xc0) == 0xc0) {
3177c478bd9Sstevel@tonic-gate 		return (": skip on unknown, return error");
3187c478bd9Sstevel@tonic-gate 	} else if ((id & 0x80) == 0x80) {
3197c478bd9Sstevel@tonic-gate 		return (": skip on unknown, no error");
3207c478bd9Sstevel@tonic-gate 	} else if ((id & 0x40) == 0x40) {
3217c478bd9Sstevel@tonic-gate 		return (": stop on unknown, return error");
3227c478bd9Sstevel@tonic-gate 	}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/* Top two bits are clear */
3257c478bd9Sstevel@tonic-gate 	return (": stop on unknown, no error");
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate /* ARGSUSED */
3297c478bd9Sstevel@tonic-gate static void
parse_asconfok_param(int flags,uint8_t notused,const void * data,int dlen)3307c478bd9Sstevel@tonic-gate parse_asconfok_param(int flags, uint8_t notused, const void *data, int dlen)
3317c478bd9Sstevel@tonic-gate {
3327c478bd9Sstevel@tonic-gate 	uint32_t	*cid;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (dlen < sizeof (*cid)) {
3357c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
3367c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete ASCONF Success Ind parameter");
3377c478bd9Sstevel@tonic-gate 		return;
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 	cid = (uint32_t *)data;
3407c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  ASCONF CID = %u",
3417c478bd9Sstevel@tonic-gate 	    ntohl(*cid));
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate /* ARGSUSED */
3457c478bd9Sstevel@tonic-gate static void
parse_asconferr_param(int flags,uint8_t notused,const void * data,int dlen)3467c478bd9Sstevel@tonic-gate parse_asconferr_param(int flags, uint8_t notused, const void *data, int dlen)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	uint32_t	*cid;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (dlen < sizeof (*cid)) {
3517c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
3527c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete ASCONF Error Ind parameter");
3537c478bd9Sstevel@tonic-gate 		return;
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 	cid = (uint32_t *)data;
3567c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  ASCONF CID = %u",
3577c478bd9Sstevel@tonic-gate 	    ntohl(*cid));
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	interpret_params(cid + 1, dlen - sizeof (*cid), "Error",
3607c478bd9Sstevel@tonic-gate 	    err_dispatch_table, A_CNT(err_dispatch_table), flags);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /* ARGSUSED */
3647c478bd9Sstevel@tonic-gate static void
parse_addiperr_param(int flags,uint8_t notused,const void * data,int dlen)3657c478bd9Sstevel@tonic-gate parse_addiperr_param(int flags, uint8_t notused, const void *data, int dlen)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	interpret_params(data, dlen, "Parameter",
3697c478bd9Sstevel@tonic-gate 	    parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate /* ARGSUSED */
3737c478bd9Sstevel@tonic-gate static void
parse_addip_param(int flags,uint8_t notused,const void * data,int dlen)3747c478bd9Sstevel@tonic-gate parse_addip_param(int flags, uint8_t notused, const void *data, int dlen)
3757c478bd9Sstevel@tonic-gate {
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	uint32_t	*cid;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	if (dlen < sizeof (*cid)) {
3807c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
3817c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete ASCONF Error Ind parameter");
3827c478bd9Sstevel@tonic-gate 		return;
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	cid = (uint32_t *)data;
3857c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  ASCONF CID = %u",
3867c478bd9Sstevel@tonic-gate 	    ntohl(*cid));
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	interpret_params(cid + 1, dlen - sizeof (*cid), "Parameter",
3897c478bd9Sstevel@tonic-gate 	    parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /* ARGSUSED */
3937c478bd9Sstevel@tonic-gate static void
parse_ip4_param(int flags,uint8_t notused,const void * data,int datalen)3947c478bd9Sstevel@tonic-gate parse_ip4_param(int flags, uint8_t notused, const void *data, int datalen)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	char abuf[INET_ADDRSTRLEN];
3977c478bd9Sstevel@tonic-gate 	char *ap;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (in_addr_t)) {
4007c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
4017c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete IPv4 Addr parameter");
4027c478bd9Sstevel@tonic-gate 		return;
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	ap = (char *)inet_ntop(AF_INET, data, abuf, INET_ADDRSTRLEN);
4067c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
4077c478bd9Sstevel@tonic-gate 		ap = "<Bad Address>";
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  Addr = %s", ap);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /* ARGSUSED */
4147c478bd9Sstevel@tonic-gate static void
parse_ip6_param(int flags,uint8_t notused,const void * data,int datalen)4157c478bd9Sstevel@tonic-gate parse_ip6_param(int flags, uint8_t notused, const void *data, int datalen)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	char abuf[INET6_ADDRSTRLEN];
4187c478bd9Sstevel@tonic-gate 	char *ap;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (in6_addr_t)) {
4217c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
4227c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete IPv6 Addr parameter");
4237c478bd9Sstevel@tonic-gate 		return;
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	ap = (char *)inet_ntop(AF_INET6, data, abuf, INET6_ADDRSTRLEN);
4277c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
4287c478bd9Sstevel@tonic-gate 		ap = "<Bad Address>";
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  Addr = %s", ap);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /* ARGSUSED */
4357c478bd9Sstevel@tonic-gate static void
parse_int32_param(int flags,uint8_t notused,const void * data,int datalen)4367c478bd9Sstevel@tonic-gate parse_int32_param(int flags, uint8_t notused, const void *data, int datalen)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	if (datalen < 4) {
4397c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
4407c478bd9Sstevel@tonic-gate 		    "  ==> Incomplete INT32 parameter");
4417c478bd9Sstevel@tonic-gate 		return;
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "  INT32 = %u",
4447c478bd9Sstevel@tonic-gate 	    ntohl(*(uint32_t *)data));
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /* ARGSUSED */
4487c478bd9Sstevel@tonic-gate static void
parse_suppaddr_param(int flags,uint8_t notused,const void * data,int dlen)4497c478bd9Sstevel@tonic-gate parse_suppaddr_param(int flags, uint8_t notused, const void *data, int dlen)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	const uint16_t *type;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	if (dlen < 2) {
4547c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
4557c478bd9Sstevel@tonic-gate 		    "==> Incomplete Supported Addr parameter");
4567c478bd9Sstevel@tonic-gate 		return;
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	type = data;
4607c478bd9Sstevel@tonic-gate 	while (dlen > 0) {
4617c478bd9Sstevel@tonic-gate 		switch (ntohs(*type)) {
4627c478bd9Sstevel@tonic-gate 		case PARM_ADDR4:
4637c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
4647c478bd9Sstevel@tonic-gate 			    "  IPv4");
4657c478bd9Sstevel@tonic-gate 			break;
4667c478bd9Sstevel@tonic-gate 		case PARM_ADDR6:
4677c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
4687c478bd9Sstevel@tonic-gate 			    "  IPv6");
4697c478bd9Sstevel@tonic-gate 			break;
4707c478bd9Sstevel@tonic-gate 		case PARM_ADDR_HOST_NAME:
4717c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
4727c478bd9Sstevel@tonic-gate 			    "  Host Name");
4737c478bd9Sstevel@tonic-gate 			break;
4747c478bd9Sstevel@tonic-gate 		default:
4757c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
4767c478bd9Sstevel@tonic-gate 			    "Unknown Type (%hu)", ntohs(*type));
4777c478bd9Sstevel@tonic-gate 			break;
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 		dlen -= sizeof (*type);
4807c478bd9Sstevel@tonic-gate 		type++;
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4857c478bd9Sstevel@tonic-gate static void
parse_encap_param(int flags,uint8_t notused,const void * data,int dlen)4867c478bd9Sstevel@tonic-gate parse_encap_param(int flags, uint8_t notused, const void *data, int dlen)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	if (dlen < sizeof (sctp_parm_hdr_t)) {
4897c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
4907c478bd9Sstevel@tonic-gate 		    "==> Incomplete Parameter");
4917c478bd9Sstevel@tonic-gate 		return;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	interpret_params(data, dlen, "Parameter",
4957c478bd9Sstevel@tonic-gate 	    parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate /* ARGSUSED */
4997c478bd9Sstevel@tonic-gate static void
parse_unrec_chunk(int flags,uint8_t cflags,const void * data,int datalen)5007c478bd9Sstevel@tonic-gate parse_unrec_chunk(int flags, uint8_t cflags, const void *data, int datalen)
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	const sctp_chunk_hdr_t *cp = data;
5037c478bd9Sstevel@tonic-gate 	const dispatch_t *dp;
5047c478bd9Sstevel@tonic-gate 	const char *actstr;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*cp)) {
5077c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
5087c478bd9Sstevel@tonic-gate 		    "==> Incomplete Unrecognized Chunk Error");
5097c478bd9Sstevel@tonic-gate 		return;
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* Maybe snoop knows about this chunk? */
5137c478bd9Sstevel@tonic-gate 	dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table,
5147c478bd9Sstevel@tonic-gate 	    A_CNT(chunk_dispatch_table));
5157c478bd9Sstevel@tonic-gate 	if (dp != NULL) {
5167c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
5177c478bd9Sstevel@tonic-gate 		    "  Chunk Type = %u (%s)", cp->sch_id, dp->vdesc);
5187c478bd9Sstevel@tonic-gate 	} else {
5197c478bd9Sstevel@tonic-gate 		actstr = get_action_desc(cp->sch_id);
5207c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
5217c478bd9Sstevel@tonic-gate 		    "  Chunk Type = %u%s", cp->sch_id, actstr);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate  * Same as parse_opaque_chunk except for the indentation.
5277c478bd9Sstevel@tonic-gate  */
5287c478bd9Sstevel@tonic-gate /* ARGSUSED */
5297c478bd9Sstevel@tonic-gate static void
parse_opaque_param(int flags,uint8_t cflags,const void * data,int datalen)5307c478bd9Sstevel@tonic-gate parse_opaque_param(int flags, uint8_t cflags, const void *data, int datalen)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	dumphex(data, datalen, " Data = %s");
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate  * Loops through all parameters (or errors) until it has read
5377c478bd9Sstevel@tonic-gate  * datalen bytes of information, finding a parser for each.
5387c478bd9Sstevel@tonic-gate  * The tbl argument allows the caller to specify which dispatch
5397c478bd9Sstevel@tonic-gate  * table to use, making this function useful for both parameters
5407c478bd9Sstevel@tonic-gate  * and errors. The type argument is used to denote whether this
5417c478bd9Sstevel@tonic-gate  * is an error or parameter in detailed mode.
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate static void
interpret_params(const void * data,int datalen,char * type,const dispatch_t * tbl,int tbl_size,int flags)5447c478bd9Sstevel@tonic-gate interpret_params(const void *data, int datalen, char *type,
5457c478bd9Sstevel@tonic-gate     const dispatch_t *tbl, int tbl_size, int flags)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	const sctp_parm_hdr_t *hdr = data;
5487c478bd9Sstevel@tonic-gate 	uint16_t plen;
5497c478bd9Sstevel@tonic-gate 	uint16_t ptype;
5507c478bd9Sstevel@tonic-gate 	const char *desc;
5517c478bd9Sstevel@tonic-gate 	parse_func_t *parse;
5527c478bd9Sstevel@tonic-gate 	int pad;
5537c478bd9Sstevel@tonic-gate 	const dispatch_t *dp;
5547c478bd9Sstevel@tonic-gate 	const char *actstr;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	for (;;) {
5577c478bd9Sstevel@tonic-gate 		/*
5587c478bd9Sstevel@tonic-gate 		 * Adjust for padding: if the address isn't aligned, there
5597c478bd9Sstevel@tonic-gate 		 * should be some padding. So skip over the padding and
5607c478bd9Sstevel@tonic-gate 		 * adjust hdr accordingly. RFC2960 mandates that all
5617c478bd9Sstevel@tonic-gate 		 * parameters must be 32-bit aligned WRT the enclosing chunk,
5627c478bd9Sstevel@tonic-gate 		 * which ensures that this parameter header will
5637c478bd9Sstevel@tonic-gate 		 * be 32-bit aligned in memory. We must, of course, bounds
5647c478bd9Sstevel@tonic-gate 		 * check fraglen before actually trying to use hdr, in
5657c478bd9Sstevel@tonic-gate 		 * case the packet has been mangled or is the product
5667c478bd9Sstevel@tonic-gate 		 * of a buggy implementation.
5677c478bd9Sstevel@tonic-gate 		 */
5687c478bd9Sstevel@tonic-gate 		if ((pad = (uintptr_t)hdr % SCTP_ALIGN) != 0) {
5697c478bd9Sstevel@tonic-gate 			pad = SCTP_ALIGN - pad;
5707c478bd9Sstevel@tonic-gate 			datalen -= pad;
5717c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
5727c478bd9Sstevel@tonic-gate 			hdr = (sctp_parm_hdr_t *)((char *)hdr + pad);
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/* Need to compare against 0 1st, since sizeof is unsigned */
5767c478bd9Sstevel@tonic-gate 		if (datalen < 0 || datalen < sizeof (*hdr)) {
5777c478bd9Sstevel@tonic-gate 			if (datalen > 0) {
5787c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
5797c478bd9Sstevel@tonic-gate 				    get_line_remain(),
5807c478bd9Sstevel@tonic-gate 				    "==> Extra data after last parameter");
5817c478bd9Sstevel@tonic-gate 			}
5827c478bd9Sstevel@tonic-gate 			return;
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 		plen = ntohs(hdr->sph_len);
5857c478bd9Sstevel@tonic-gate 		if (datalen < plen || plen < sizeof (*hdr)) {
5867c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
5877c478bd9Sstevel@tonic-gate 			    "  ==> Incomplete %s", type);
5887c478bd9Sstevel@tonic-gate 			return;
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 		/* Get description and parser */
5927c478bd9Sstevel@tonic-gate 		ptype = ntohs(hdr->sph_type);
5937c478bd9Sstevel@tonic-gate 		desc = "Unknown Parameter Type";
5947c478bd9Sstevel@tonic-gate 		parse = parse_opaque_param;
5957c478bd9Sstevel@tonic-gate 		dp = lookup_dispatch(ptype, tbl, tbl_size);
5967c478bd9Sstevel@tonic-gate 		if (dp != NULL) {
5977c478bd9Sstevel@tonic-gate 			desc = dp->vdesc;
5987c478bd9Sstevel@tonic-gate 			parse = dp->parse;
5997c478bd9Sstevel@tonic-gate 		}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 		show_space();
6027c478bd9Sstevel@tonic-gate 		if (dp != NULL) {
6037c478bd9Sstevel@tonic-gate 			actstr = "";
6047c478bd9Sstevel@tonic-gate 		} else {
6057c478bd9Sstevel@tonic-gate 			actstr = get_action_desc((uint8_t)(ptype >> 8));
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
6087c478bd9Sstevel@tonic-gate 		    "  ------- SCTP %s Type = %s (%u%s)", type, desc, ptype,
6097c478bd9Sstevel@tonic-gate 		    actstr);
6107c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
6117c478bd9Sstevel@tonic-gate 		    "  Data length = %hu", plen - sizeof (*hdr));
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 		if (parse != NULL) {
6147c478bd9Sstevel@tonic-gate 			parse(flags, 0, (char *)(hdr + 1),
6157c478bd9Sstevel@tonic-gate 			    plen - sizeof (*hdr));
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 		datalen -= plen;
6187c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
6197c478bd9Sstevel@tonic-gate 		hdr = (sctp_parm_hdr_t *)((char *)hdr + plen);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate /* ARGSUSED */
6247c478bd9Sstevel@tonic-gate static void
parse_ftsn_chunk(int flags,uint8_t cflags,const void * data,int datalen)6257c478bd9Sstevel@tonic-gate parse_ftsn_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	uint32_t	*ftsn;
6287c478bd9Sstevel@tonic-gate 	ftsn_entry_t	*ftsn_entry;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (datalen < (sizeof (*ftsn) + sizeof (*ftsn_entry))) {
6317c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
6327c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
6337c478bd9Sstevel@tonic-gate 			    "==> Incomplete FORWARD-TSN chunk");
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		return;
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	ftsn = (uint32_t *)data;
6397c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
6407c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE, "CTSN %x ", ntohl(*ftsn)));
6417c478bd9Sstevel@tonic-gate 		return;
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "Cum TSN=  %x",
6447c478bd9Sstevel@tonic-gate 	    ntohl(*ftsn));
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	datalen -= sizeof (*ftsn);
6477c478bd9Sstevel@tonic-gate 	ftsn_entry = (ftsn_entry_t *)(ftsn + 1);
6487c478bd9Sstevel@tonic-gate 	while (datalen >= sizeof (*ftsn_entry)) {
6497c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
6507c478bd9Sstevel@tonic-gate 		    "SID =  %u : SSN = %u", ntohs(ftsn_entry->ftsn_sid),
6517c478bd9Sstevel@tonic-gate 		    ntohs(ftsn_entry->ftsn_ssn));
6527c478bd9Sstevel@tonic-gate 		datalen -= sizeof (*ftsn_entry);
6537c478bd9Sstevel@tonic-gate 		ftsn_entry++;
6547c478bd9Sstevel@tonic-gate 	}
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /* ARGSUSED */
6587c478bd9Sstevel@tonic-gate static void
parse_asconf_chunk(int flags,uint8_t cflags,const void * data,int datalen)6597c478bd9Sstevel@tonic-gate parse_asconf_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	uint32_t	*sn;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*sn)) {
6647c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
6657c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
6667c478bd9Sstevel@tonic-gate 			    "==> Incomplete ASCONF chunk");
6677c478bd9Sstevel@tonic-gate 		}
6687c478bd9Sstevel@tonic-gate 		return;
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	sn = (uint32_t *)data;
6727c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
6737c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE, "sn %x ", ntohl(*sn)));
6747c478bd9Sstevel@tonic-gate 		return;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "Serial Number=  %x",
6777c478bd9Sstevel@tonic-gate 	    ntohl(*sn));
6787c478bd9Sstevel@tonic-gate 	interpret_params(sn + 1, datalen - sizeof (*sn), "Parameter",
6797c478bd9Sstevel@tonic-gate 	    parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate static void
parse_init_chunk(int flags,uint8_t cflags,const void * data,int datalen)6837c478bd9Sstevel@tonic-gate parse_init_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate 	const sctp_init_chunk_t *icp = data;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*icp)) {
6887c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
6897c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
6907c478bd9Sstevel@tonic-gate 			    "==> Incomplete INIT chunk");
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 		return;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
6967c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE, "tsn %x str %hu/%hu win %u ",
6977c478bd9Sstevel@tonic-gate 		    ntohl(icp->sic_inittsn), ntohs(icp->sic_outstr),
6987c478bd9Sstevel@tonic-gate 		    ntohs(icp->sic_instr), ntohl(icp->sic_a_rwnd)));
6997c478bd9Sstevel@tonic-gate 		return;
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "Flags = 0x%.2x",
7037c478bd9Sstevel@tonic-gate 	    cflags);
7047c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
7057c478bd9Sstevel@tonic-gate 	    "Initiate tag = 0x%.8x", ntohl(icp->sic_inittag));
7067c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
7077c478bd9Sstevel@tonic-gate 	    "Advertised receiver window credit = %u", ntohl(icp->sic_a_rwnd));
7087c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
7097c478bd9Sstevel@tonic-gate 	    "Outbound streams = %hu", ntohs(icp->sic_outstr));
7107c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
7117c478bd9Sstevel@tonic-gate 	    "Inbound streams = %hu", ntohs(icp->sic_instr));
7127c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(),
7137c478bd9Sstevel@tonic-gate 	    "Initial TSN = 0x%.8x", ntohl(icp->sic_inittsn));
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (datalen > sizeof (*icp)) {
7167c478bd9Sstevel@tonic-gate 		interpret_params(icp + 1, datalen - sizeof (*icp),
7177c478bd9Sstevel@tonic-gate 		    "Parameter", parm_dispatch_table,
7187c478bd9Sstevel@tonic-gate 		    A_CNT(parm_dispatch_table), flags);
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate static void
parse_data_chunk(int flags,uint8_t cflags,const void * data,int datalen)7237c478bd9Sstevel@tonic-gate parse_data_chunk(int flags, uint8_t cflags, const void *data, int datalen)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	const sctp_data_chunk_t	*dcp = data;
7267c478bd9Sstevel@tonic-gate 	char			*payload;
7277c478bd9Sstevel@tonic-gate 	uint32_t		ppid;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*dcp)) {
7307c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
7317c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
7327c478bd9Sstevel@tonic-gate 			    "==> Incomplete DATA chunk %d (%d)", datalen,
7337c478bd9Sstevel@tonic-gate 			    sizeof (*dcp));
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 		return;
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	ppid = ntohl(dcp->sdc_payload_id);
739*1a754c38Skcpoon 	/* This is the actual data len, excluding the data chunk header. */
740*1a754c38Skcpoon 	datalen -= sizeof (*dcp);
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
7437c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
7447c478bd9Sstevel@tonic-gate 		    "flags = 0x%.2x", cflags);
7457c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
7467c478bd9Sstevel@tonic-gate 		    getflag(cflags, SCTP_DATA_UBIT, "unordered", "ordered"));
7477c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
7487c478bd9Sstevel@tonic-gate 		    getflag(cflags, SCTP_DATA_BBIT,
7497c478bd9Sstevel@tonic-gate 		    "beginning", "(beginning unset)"));
7507c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
7517c478bd9Sstevel@tonic-gate 		    getflag(cflags, SCTP_DATA_EBIT, "end", "(end unset)"));
7527c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
7537c478bd9Sstevel@tonic-gate 		    "TSN = 0x%.8x", ntohl(dcp->sdc_tsn));
7547c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
7557c478bd9Sstevel@tonic-gate 		    "Stream ID = %hu", ntohs(dcp->sdc_sid));
7567c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
7577c478bd9Sstevel@tonic-gate 		    "Stream Sequence Number = %hu", ntohs(dcp->sdc_ssn));
7587c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
7597c478bd9Sstevel@tonic-gate 		    "Payload Protocol ID = 0x%.8x", ppid);
7607c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
761*1a754c38Skcpoon 		    "Data Length = %d", datalen);
7627c478bd9Sstevel@tonic-gate 		show_space();
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
765*1a754c38Skcpoon 		SUMAPPEND((scratch, MAXLINE, "len %d tsn %x str %hu/%hu "
766*1a754c38Skcpoon 		    "ppid %x ", datalen, ntohl(dcp->sdc_tsn),
767*1a754c38Skcpoon 		    ntohs(dcp->sdc_sid), ntohs(dcp->sdc_ssn), ppid));
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/*
7717c478bd9Sstevel@tonic-gate 	 * Go to the next protocol layer, but not if we are in
7727c478bd9Sstevel@tonic-gate 	 * summary mode only. In summary mode, each ULP parse would
7737c478bd9Sstevel@tonic-gate 	 * create a new line, and if there were several data chunks
7747c478bd9Sstevel@tonic-gate 	 * bundled together in the packet, this would confuse snoop's
7757c478bd9Sstevel@tonic-gate 	 * packet numbering and timestamping.
7767c478bd9Sstevel@tonic-gate 	 *
7777c478bd9Sstevel@tonic-gate 	 * SCTP carries two ways to determine an ULP: ports and the
7787c478bd9Sstevel@tonic-gate 	 * payload protocol identifier (ppid). Since ports are the
7797c478bd9Sstevel@tonic-gate 	 * better entrenched convention, we first try interpret_reserved().
7807c478bd9Sstevel@tonic-gate 	 * If that fails to find a parser, we try by the PPID.
7817c478bd9Sstevel@tonic-gate 	 */
7827c478bd9Sstevel@tonic-gate 	if (!(flags & F_ALLSUM) && !(flags & F_DTAIL)) {
7837c478bd9Sstevel@tonic-gate 		return;
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	payload = (char *)(dcp + 1);
7877c478bd9Sstevel@tonic-gate 	if (!interpret_reserved(flags, IPPROTO_SCTP, sport, dport, payload,
788*1a754c38Skcpoon 	    datalen) && ppid != 0) {
7897c478bd9Sstevel@tonic-gate 
790*1a754c38Skcpoon 		interpret_protoid(flags, ppid, payload, datalen);
7917c478bd9Sstevel@tonic-gate 	}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	/*
7947c478bd9Sstevel@tonic-gate 	 * Reset the protocol prefix, since it may have been changed
7957c478bd9Sstevel@tonic-gate 	 * by a ULP interpreter.
7967c478bd9Sstevel@tonic-gate 	 */
7977c478bd9Sstevel@tonic-gate 	prot_prefix = "SCTP:  ";
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate /* ARGSUSED */
8017c478bd9Sstevel@tonic-gate static void
parse_sack_chunk(int flags,uint8_t cflags,const void * data,int datalen)8027c478bd9Sstevel@tonic-gate parse_sack_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8037c478bd9Sstevel@tonic-gate {
8047c478bd9Sstevel@tonic-gate 	const sctp_sack_chunk_t *scp = data;
8057c478bd9Sstevel@tonic-gate 	uint16_t numfrags, numdups;
8067c478bd9Sstevel@tonic-gate 	sctp_sack_frag_t *frag;
8077c478bd9Sstevel@tonic-gate 	int i;
8087c478bd9Sstevel@tonic-gate 	uint32_t *tsn;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*scp)) {
8117c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
8127c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8137c478bd9Sstevel@tonic-gate 			    "==> Incomplete SACK chunk");
8147c478bd9Sstevel@tonic-gate 		}
8157c478bd9Sstevel@tonic-gate 		return;
8167c478bd9Sstevel@tonic-gate 	}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
8197c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
8207c478bd9Sstevel@tonic-gate 		    "Cumulative TSN ACK = 0x%.8x", ntohl(scp->ssc_cumtsn));
8217c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
8227c478bd9Sstevel@tonic-gate 		    "Advertised Receiver Window Credit = %u",
8237c478bd9Sstevel@tonic-gate 		    ntohl(scp->ssc_a_rwnd));
8247c478bd9Sstevel@tonic-gate 		numfrags = ntohs(scp->ssc_numfrags);
8257c478bd9Sstevel@tonic-gate 		numdups = ntohs(scp->ssc_numdups);
8267c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
8277c478bd9Sstevel@tonic-gate 		    "Number of Fragments = %hu", numfrags);
8287c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
8297c478bd9Sstevel@tonic-gate 		    "Number of Duplicates = %hu", numdups);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		/* Display any gap reports */
8327c478bd9Sstevel@tonic-gate 		datalen -= sizeof (*scp);
8337c478bd9Sstevel@tonic-gate 		if (datalen < (numfrags * sizeof (*frag))) {
8347c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8357c478bd9Sstevel@tonic-gate 			    "  ==> Malformed gap report listing");
8367c478bd9Sstevel@tonic-gate 			return;
8377c478bd9Sstevel@tonic-gate 		}
8387c478bd9Sstevel@tonic-gate 		frag = (sctp_sack_frag_t *)(scp + 1);
8397c478bd9Sstevel@tonic-gate 		for (i = 0; i < numfrags; i++) {
8407c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8417c478bd9Sstevel@tonic-gate 			    "  Fragment #%d: Start = %hu, end = %hu", i,
8427c478bd9Sstevel@tonic-gate 			    ntohs(frag->ssf_start), ntohs(frag->ssf_end));
8437c478bd9Sstevel@tonic-gate 			frag += 1;
8447c478bd9Sstevel@tonic-gate 		}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 		/* Display any duplicate reports */
8477c478bd9Sstevel@tonic-gate 		datalen -= numfrags * sizeof (*frag);
8487c478bd9Sstevel@tonic-gate 		if (datalen < (numdups * sizeof (*tsn))) {
8497c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8507c478bd9Sstevel@tonic-gate 			    "  ==> Malformed duplicate report listing");
8517c478bd9Sstevel@tonic-gate 			return;
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
8547c478bd9Sstevel@tonic-gate 		tsn = (uint32_t *)frag;
8557c478bd9Sstevel@tonic-gate 		for (i = 0; i < numdups; i++) {
8567c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8577c478bd9Sstevel@tonic-gate 			    "  Duplicate #%d: TSN = %x", i, *tsn);
8587c478bd9Sstevel@tonic-gate 			tsn++;
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
8627c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE,
8637c478bd9Sstevel@tonic-gate 		    "tsn %x win %u gaps/dups %hu/%hu ", ntohl(scp->ssc_cumtsn),
8647c478bd9Sstevel@tonic-gate 		    ntohl(scp->ssc_a_rwnd), ntohs(scp->ssc_numfrags),
8657c478bd9Sstevel@tonic-gate 		    ntohs(scp->ssc_numdups)));
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate /* ARGSUSED */
8707c478bd9Sstevel@tonic-gate static void
parse_shutdown_chunk(int flags,uint8_t cflags,const void * data,int datalen)8717c478bd9Sstevel@tonic-gate parse_shutdown_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate 	const uint32_t *cumtsn = data;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	if (datalen < sizeof (*cumtsn)) {
8767c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
8777c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
8787c478bd9Sstevel@tonic-gate 			    "==> Incomplete Shutdown chunk");
8797c478bd9Sstevel@tonic-gate 		}
8807c478bd9Sstevel@tonic-gate 		return;
8817c478bd9Sstevel@tonic-gate 	}
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
8847c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
8857c478bd9Sstevel@tonic-gate 		    "Cumulative TSN = 0x%.8x", ntohl(*cumtsn));
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
8887c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE, "tsn %x", ntohl(*cumtsn)));
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate /* ARGSUSED */
8937c478bd9Sstevel@tonic-gate static void
parse_error_chunk(int flags,uint8_t cflags,const void * data,int datalen)8947c478bd9Sstevel@tonic-gate parse_error_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8957c478bd9Sstevel@tonic-gate {
8967c478bd9Sstevel@tonic-gate 	if (!(flags & F_DTAIL)) {
8977c478bd9Sstevel@tonic-gate 		return;
8987c478bd9Sstevel@tonic-gate 	}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	interpret_params(data, datalen, "Error", err_dispatch_table,
9017c478bd9Sstevel@tonic-gate 	    A_CNT(err_dispatch_table), flags);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate static void
parse_abort_chunk(int flags,uint8_t cflags,const void * data,int datalen)9057c478bd9Sstevel@tonic-gate parse_abort_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate 	if (!(flags & F_DTAIL)) {
9087c478bd9Sstevel@tonic-gate 		return;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x",
9127c478bd9Sstevel@tonic-gate 	    cflags);
9137c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
9147c478bd9Sstevel@tonic-gate 	    getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed"));
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	interpret_params(data, datalen, "Error", err_dispatch_table,
9177c478bd9Sstevel@tonic-gate 	    A_CNT(err_dispatch_table), flags);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
9217c478bd9Sstevel@tonic-gate static void
parse_shutdone_chunk(int flags,uint8_t cflags,const void * data,int datalen)9227c478bd9Sstevel@tonic-gate parse_shutdone_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	if (!(flags & F_DTAIL)) {
9257c478bd9Sstevel@tonic-gate 		return;
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x",
9297c478bd9Sstevel@tonic-gate 	    cflags);
9307c478bd9Sstevel@tonic-gate 	(void) snprintf(get_line(0, 0), get_line_remain(), "      %s",
9317c478bd9Sstevel@tonic-gate 	    getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed"));
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate /* ARGSUSED */
9357c478bd9Sstevel@tonic-gate static void
parse_opaque_chunk(int flags,uint8_t cflags,const void * data,int datalen)9367c478bd9Sstevel@tonic-gate parse_opaque_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	if (!(flags & F_DTAIL)) {
9397c478bd9Sstevel@tonic-gate 		return;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 	if (datalen == 0) {
9427c478bd9Sstevel@tonic-gate 		return;
9437c478bd9Sstevel@tonic-gate 	}
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	dumphex(data, datalen, "Data = %s");
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate  * Loops through all chunks until it has read fraglen bytes of
9507c478bd9Sstevel@tonic-gate  * information, finding a parser for each. If any parameters are
9517c478bd9Sstevel@tonic-gate  * present, interpret_params() is then called. Returns the remaining
9527c478bd9Sstevel@tonic-gate  * fraglen.
9537c478bd9Sstevel@tonic-gate  */
9547c478bd9Sstevel@tonic-gate static int
interpret_chunks(int flags,sctp_chunk_hdr_t * cp,int fraglen)9557c478bd9Sstevel@tonic-gate interpret_chunks(int flags, sctp_chunk_hdr_t *cp, int fraglen)
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate 	uint16_t clen;
9587c478bd9Sstevel@tonic-gate 	int signed_len;
9597c478bd9Sstevel@tonic-gate 	int pad;
9607c478bd9Sstevel@tonic-gate 	const char *desc;
9617c478bd9Sstevel@tonic-gate 	parse_func_t *parse;
9627c478bd9Sstevel@tonic-gate 	const dispatch_t *dp;
9637c478bd9Sstevel@tonic-gate 	const char *actstr;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 	for (;;) {
9667c478bd9Sstevel@tonic-gate 		/*
9677c478bd9Sstevel@tonic-gate 		 * Adjust for padding: if the address isn't aligned, there
9687c478bd9Sstevel@tonic-gate 		 * should be some padding. So skip over the padding and
9697c478bd9Sstevel@tonic-gate 		 * adjust hdr accordingly. RFC2960 mandates that all
9707c478bd9Sstevel@tonic-gate 		 * chunks must be 32-bit aligned WRT the SCTP common hdr,
9717c478bd9Sstevel@tonic-gate 		 * which ensures that this chunk header will
9727c478bd9Sstevel@tonic-gate 		 * be 32-bit aligned in memory. We must, of course, bounds
9737c478bd9Sstevel@tonic-gate 		 * check fraglen before actually trying to use hdr, in
9747c478bd9Sstevel@tonic-gate 		 * case the packet has been mangled or is the product
9757c478bd9Sstevel@tonic-gate 		 * of a buggy implementation.
9767c478bd9Sstevel@tonic-gate 		 */
9777c478bd9Sstevel@tonic-gate 		if ((pad = (uintptr_t)cp % SCTP_ALIGN) != 0) {
9787c478bd9Sstevel@tonic-gate 			pad = SCTP_ALIGN - pad;
9797c478bd9Sstevel@tonic-gate 			fraglen -= pad;
9807c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
9817c478bd9Sstevel@tonic-gate 			cp = (sctp_chunk_hdr_t *)((char *)cp + pad);
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		/* Need to compare against 0 1st, since sizeof is unsigned */
9857c478bd9Sstevel@tonic-gate 		if (fraglen < 0 || fraglen < sizeof (*cp)) {
9867c478bd9Sstevel@tonic-gate 			if (fraglen > 0 && flags & F_DTAIL) {
9877c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
9887c478bd9Sstevel@tonic-gate 				    get_line_remain(),
9897c478bd9Sstevel@tonic-gate 				    "==> Extra data after last chunk");
9907c478bd9Sstevel@tonic-gate 			}
9917c478bd9Sstevel@tonic-gate 			return (fraglen);
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 		clen = ntohs(cp->sch_len);
9957c478bd9Sstevel@tonic-gate 		if (fraglen < clen) {
9967c478bd9Sstevel@tonic-gate 			if (flags & F_DTAIL) {
9977c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
9987c478bd9Sstevel@tonic-gate 				    get_line_remain(), "==> Corrupted chunk");
9997c478bd9Sstevel@tonic-gate 			}
10007c478bd9Sstevel@tonic-gate 			return (fraglen);
10017c478bd9Sstevel@tonic-gate 		}
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 		signed_len = clen - sizeof (*cp);
10047c478bd9Sstevel@tonic-gate 		if (signed_len < 0) {
10057c478bd9Sstevel@tonic-gate 			if (flags & F_DTAIL) {
10067c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
10077c478bd9Sstevel@tonic-gate 				    get_line_remain(),
10087c478bd9Sstevel@tonic-gate 				    "==> Incomplete or corrupted chunk");
10097c478bd9Sstevel@tonic-gate 			}
10107c478bd9Sstevel@tonic-gate 			return (0);
10117c478bd9Sstevel@tonic-gate 		}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 		/* Get description and parser */
10147c478bd9Sstevel@tonic-gate 		dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table,
10157c478bd9Sstevel@tonic-gate 		    A_CNT(chunk_dispatch_table));
10167c478bd9Sstevel@tonic-gate 		if (dp != NULL) {
10177c478bd9Sstevel@tonic-gate 			if (flags & F_SUM) {
10187c478bd9Sstevel@tonic-gate 				desc = dp->sdesc;
10197c478bd9Sstevel@tonic-gate 			} else if (flags & F_DTAIL) {
10207c478bd9Sstevel@tonic-gate 				desc = dp->vdesc;
10217c478bd9Sstevel@tonic-gate 			}
10227c478bd9Sstevel@tonic-gate 			parse = dp->parse;
10237c478bd9Sstevel@tonic-gate 		} else {
10247c478bd9Sstevel@tonic-gate 			if (flags & F_SUM) {
10257c478bd9Sstevel@tonic-gate 				desc = "UNK";
10267c478bd9Sstevel@tonic-gate 			} else if (flags & F_DTAIL) {
10277c478bd9Sstevel@tonic-gate 				desc = "Unknown Chunk Type";
10287c478bd9Sstevel@tonic-gate 			}
10297c478bd9Sstevel@tonic-gate 			parse = parse_opaque_chunk;
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 		if (flags & F_SUM) {
10337c478bd9Sstevel@tonic-gate 			SUMAPPEND((scratch, MAXLINE, "%s ", desc));
10347c478bd9Sstevel@tonic-gate 		}
10357c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
10367c478bd9Sstevel@tonic-gate 			show_space();
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 			if (dp != NULL) {
10397c478bd9Sstevel@tonic-gate 				actstr = "";
10407c478bd9Sstevel@tonic-gate 			} else {
10417c478bd9Sstevel@tonic-gate 				actstr = get_action_desc(cp->sch_id);
10427c478bd9Sstevel@tonic-gate 			}
10437c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
10447c478bd9Sstevel@tonic-gate 			    "------- SCTP Chunk Type = %s (%u%s)", desc,
10457c478bd9Sstevel@tonic-gate 			    cp->sch_id, actstr);
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
10487c478bd9Sstevel@tonic-gate 			    "Chunk length = %hu", clen);
10497c478bd9Sstevel@tonic-gate 		}
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 		if (parse != NULL) {
10527c478bd9Sstevel@tonic-gate 			parse(flags, cp->sch_flags, (char *)(cp + 1),
10537c478bd9Sstevel@tonic-gate 			    signed_len);
10547c478bd9Sstevel@tonic-gate 		}
10557c478bd9Sstevel@tonic-gate 
10567c478bd9Sstevel@tonic-gate 		fraglen -= clen;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
10597c478bd9Sstevel@tonic-gate 		cp = (sctp_chunk_hdr_t *)((char *)cp + clen);
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate void
interpret_sctp(int flags,sctp_hdr_t * sctp,int iplen,int fraglen)10647c478bd9Sstevel@tonic-gate interpret_sctp(int flags, sctp_hdr_t *sctp, int iplen, int fraglen)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate 	int len_from_iphdr;
10677c478bd9Sstevel@tonic-gate 	sctp_chunk_hdr_t *cp;
10687c478bd9Sstevel@tonic-gate 	char *pn;
10697c478bd9Sstevel@tonic-gate 	char buff[32];
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	/*
10727c478bd9Sstevel@tonic-gate 	 * Alignment check. If the header is 32-bit aligned, all other
10737c478bd9Sstevel@tonic-gate 	 * protocol units will also be aligned, as mandated by rfc2960.
10747c478bd9Sstevel@tonic-gate 	 * Buggy packets will be caught and flagged by chunk and
10757c478bd9Sstevel@tonic-gate 	 * parameter bounds checking.
10767c478bd9Sstevel@tonic-gate 	 * If the header is not aligned, however, we drop the packet.
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	if (!IS_P2ALIGNED(sctp, SCTP_ALIGN)) {
10797c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
10807c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
10817c478bd9Sstevel@tonic-gate 			    "==> SCTP header not aligned, dropping");
10827c478bd9Sstevel@tonic-gate 		}
10837c478bd9Sstevel@tonic-gate 		return;
10847c478bd9Sstevel@tonic-gate 	}
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	fraglen -= sizeof (*sctp);
10877c478bd9Sstevel@tonic-gate 	if (fraglen < 0) {
10887c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL) {
10897c478bd9Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
10907c478bd9Sstevel@tonic-gate 			    "==> Incomplete sctp header");
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 		return;
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 	/* If fraglen is somehow longer than the IP payload, adjust it */
10957c478bd9Sstevel@tonic-gate 	len_from_iphdr = iplen - sizeof (*sctp);
10967c478bd9Sstevel@tonic-gate 	if (fraglen > len_from_iphdr) {
10977c478bd9Sstevel@tonic-gate 		fraglen = len_from_iphdr;
10987c478bd9Sstevel@tonic-gate 	}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/* Keep track of the ports */
11017c478bd9Sstevel@tonic-gate 	sport = ntohs(sctp->sh_sport);
11027c478bd9Sstevel@tonic-gate 	dport = ntohs(sctp->sh_dport);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	/* Set pointer to first chunk */
11057c478bd9Sstevel@tonic-gate 	cp = (sctp_chunk_hdr_t *)(sctp + 1);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
11087c478bd9Sstevel@tonic-gate 		sumline = get_sum_line();
11097c478bd9Sstevel@tonic-gate 		*sumline = '\0';
11107c478bd9Sstevel@tonic-gate 		sumlen = MAXLINE;
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 		SUMAPPEND((scratch, MAXLINE, "SCTP D=%d S=%d ", dport, sport));
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
11167c478bd9Sstevel@tonic-gate 		show_header("SCTP:  ", "SCTP Header", fraglen);
11177c478bd9Sstevel@tonic-gate 		show_space();
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		pn = getportname(IPPROTO_SCTP, (ushort_t)sport);
11207c478bd9Sstevel@tonic-gate 		if (pn == NULL) {
11217c478bd9Sstevel@tonic-gate 			pn = "";
11227c478bd9Sstevel@tonic-gate 		} else {
11237c478bd9Sstevel@tonic-gate 			(void) snprintf(buff, sizeof (buff), "(%s)", pn);
11247c478bd9Sstevel@tonic-gate 			pn = buff;
11257c478bd9Sstevel@tonic-gate 		}
11267c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
11277c478bd9Sstevel@tonic-gate 		    "Source port = %hu %s", sport, pn);
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 		pn = getportname(IPPROTO_SCTP, (ushort_t)dport);
11307c478bd9Sstevel@tonic-gate 		if (pn == NULL) {
11317c478bd9Sstevel@tonic-gate 			pn = "";
11327c478bd9Sstevel@tonic-gate 		} else {
11337c478bd9Sstevel@tonic-gate 			(void) snprintf(buff, sizeof (buff), "(%s)", pn);
11347c478bd9Sstevel@tonic-gate 			pn = buff;
11357c478bd9Sstevel@tonic-gate 		}
11367c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
11377c478bd9Sstevel@tonic-gate 		    "Destination port = %hu %s", dport, pn);
11387c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
11397c478bd9Sstevel@tonic-gate 		    "Verification tag = 0x%.8x", ntohl(sctp->sh_verf));
11407c478bd9Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
11417c478bd9Sstevel@tonic-gate 		    "CRC-32c = 0x%.8x", ntohl(sctp->sh_chksum));
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	(void) interpret_chunks(flags, cp, fraglen);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
11477c478bd9Sstevel@tonic-gate 		show_space();
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate /*
11527c478bd9Sstevel@tonic-gate  * Payload protocol ID table. Add new ULP information and parsers
11537c478bd9Sstevel@tonic-gate  * here.
11547c478bd9Sstevel@tonic-gate  */
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate struct protoid_table {
11577c478bd9Sstevel@tonic-gate 	int	pid_num;
11587c478bd9Sstevel@tonic-gate 	char	*pid_short;
11597c478bd9Sstevel@tonic-gate 	char	*pid_long;
11607c478bd9Sstevel@tonic-gate };
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate static struct protoid_table pid_sctp[] = {
11637c478bd9Sstevel@tonic-gate 	1,	"IUA",		"ISDN Q.921 User Adaption Layer",
11647c478bd9Sstevel@tonic-gate 	2,	"M2UA",		"SS7 MTP2 User Adaption Layer",
11657c478bd9Sstevel@tonic-gate 	3,	"M3UA",		"SS7 MTP3 User Adaption Layer",
11667c478bd9Sstevel@tonic-gate 	4,	"SUA",		"SS7 SCCP User Adaption Layer",
11677c478bd9Sstevel@tonic-gate 	5,	"M2PA",		"SS7 MTP2-User Peer-to-Peer Adaption Layer",
11687c478bd9Sstevel@tonic-gate 	6,	"V5UA",		"V5UA",
11697c478bd9Sstevel@tonic-gate 	0,	NULL,		"",
11707c478bd9Sstevel@tonic-gate };
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate static void
interpret_protoid(int flags,uint32_t ppid,char * data,int dlen)11737c478bd9Sstevel@tonic-gate interpret_protoid(int flags, uint32_t ppid, char *data, int dlen)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	struct protoid_table *p;
11767c478bd9Sstevel@tonic-gate 	char pbuf[16];
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	/*
11797c478bd9Sstevel@tonic-gate 	 * Branch to a ULP interpreter here, or continue on to
11807c478bd9Sstevel@tonic-gate 	 * the default parser, which just tries to display
11817c478bd9Sstevel@tonic-gate 	 * printable characters from the payload.
11827c478bd9Sstevel@tonic-gate 	 */
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	for (p = pid_sctp; p->pid_num; p++) {
11857c478bd9Sstevel@tonic-gate 		if (ppid == p->pid_num) {
11867c478bd9Sstevel@tonic-gate 			if (flags & F_SUM) {
11877c478bd9Sstevel@tonic-gate 				(void) snprintf(get_sum_line(), MAXLINE,
11887c478bd9Sstevel@tonic-gate 				    "D=%d S=%d %s %s", dport, sport,
11897c478bd9Sstevel@tonic-gate 				    p->pid_short, show_string(data, dlen, 20));
11907c478bd9Sstevel@tonic-gate 			}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 			if (flags & F_DTAIL) {
11937c478bd9Sstevel@tonic-gate 				(void) snprintf(pbuf, MAXLINE, "%s:  ",
11947c478bd9Sstevel@tonic-gate 				    p->pid_short);
11957c478bd9Sstevel@tonic-gate 				show_header(pbuf, p->pid_long, dlen);
11967c478bd9Sstevel@tonic-gate 				show_space();
11977c478bd9Sstevel@tonic-gate 				(void) snprintf(get_line(0, 0),
11987c478bd9Sstevel@tonic-gate 				    get_line_remain(), "\"%s\"",
11997c478bd9Sstevel@tonic-gate 				    show_string(data, dlen, 60));
12007c478bd9Sstevel@tonic-gate 				show_trailer();
12017c478bd9Sstevel@tonic-gate 			}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 			return;
12047c478bd9Sstevel@tonic-gate 		}
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate }
1207