10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*1766Skcpoon * Common Development and Distribution License (the "License").
6*1766Skcpoon * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*1766Skcpoon
220Sstevel@tonic-gate /*
23*1766Skcpoon * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <inet/common.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <netinet/sctp.h>
370Sstevel@tonic-gate #include <arpa/inet.h>
380Sstevel@tonic-gate #include <string.h>
390Sstevel@tonic-gate #include "snoop.h"
400Sstevel@tonic-gate
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate * Snoop interpreter for SCTP (rfc2960).
430Sstevel@tonic-gate *
440Sstevel@tonic-gate * To add support for an upper-layer protocol, modify either
450Sstevel@tonic-gate * the port-dispatcher in snoop_rport.c, or the protocol ID
460Sstevel@tonic-gate * dispatcher at the bottom of this file (or both).
470Sstevel@tonic-gate */
480Sstevel@tonic-gate
490Sstevel@tonic-gate static void interpret_protoid(int, uint32_t, char *, int);
500Sstevel@tonic-gate extern char *prot_prefix;
510Sstevel@tonic-gate
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate * This defines the length of internal, unbounded buffers. We set
540Sstevel@tonic-gate * this to be MAXLINE (the maximum verbose display line length) -
550Sstevel@tonic-gate * 64, which should be enough for all necessary descriptions. 64
560Sstevel@tonic-gate * bytes seems like a reasonably conservative estimate of the
570Sstevel@tonic-gate * maximum prefix length snoop may add to any text buffer it hands out.
580Sstevel@tonic-gate */
590Sstevel@tonic-gate #define BUFLEN MAXLINE - 64
600Sstevel@tonic-gate
610Sstevel@tonic-gate /*
620Sstevel@tonic-gate * Common structure to hold descriptions and parsers for all
630Sstevel@tonic-gate * chunks, parameters, and errors. Each parser should implement
640Sstevel@tonic-gate * this interface:
650Sstevel@tonic-gate *
660Sstevel@tonic-gate * void parse(int flags, uint8_t cflags, void *data, int datalen);
670Sstevel@tonic-gate *
680Sstevel@tonic-gate * Where flags is the snoop flags, cflags are the chunk flags, data
690Sstevel@tonic-gate * is the chunk or parameter data (not including the chunk or
700Sstevel@tonic-gate * parameter header), and datalen is the length of the chunk or
710Sstevel@tonic-gate * parameter data (again not including any headers).
720Sstevel@tonic-gate */
730Sstevel@tonic-gate typedef void parse_func_t(int, uint8_t, const void *, int);
740Sstevel@tonic-gate
750Sstevel@tonic-gate typedef struct {
760Sstevel@tonic-gate uint16_t id;
770Sstevel@tonic-gate const char *sdesc; /* short description */
780Sstevel@tonic-gate const char *vdesc; /* verbose description */
790Sstevel@tonic-gate parse_func_t *parse; /* parser function */
800Sstevel@tonic-gate } dispatch_t;
810Sstevel@tonic-gate
820Sstevel@tonic-gate static void interpret_params(const void *, int, char *, const dispatch_t *,
830Sstevel@tonic-gate int, int);
840Sstevel@tonic-gate
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * Chunk parsers
870Sstevel@tonic-gate */
880Sstevel@tonic-gate static parse_func_t parse_abort_chunk, parse_data_chunk, parse_error_chunk,
890Sstevel@tonic-gate parse_init_chunk, parse_opaque_chunk, parse_sack_chunk,
900Sstevel@tonic-gate parse_shutdone_chunk, parse_shutdown_chunk, parse_asconf_chunk,
910Sstevel@tonic-gate parse_ftsn_chunk;
920Sstevel@tonic-gate
930Sstevel@tonic-gate
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate * Chunk parser dispatch table. There are few enough chunks defined
960Sstevel@tonic-gate * in the core protocol, and they are sequential, so the chunk code
970Sstevel@tonic-gate * can be used as the index into this array for the common case.
980Sstevel@tonic-gate * It is still necessary to check that the code and index match,
990Sstevel@tonic-gate * since optional extensions will not follow sequentially the
1000Sstevel@tonic-gate * core chunks.
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate static const dispatch_t chunk_dispatch_table[] = {
1030Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */
1040Sstevel@tonic-gate { CHUNK_DATA, "Data", "Data Chunk",
1050Sstevel@tonic-gate parse_data_chunk },
1060Sstevel@tonic-gate { CHUNK_INIT, "Init", "Init Chunk",
1070Sstevel@tonic-gate parse_init_chunk },
1080Sstevel@tonic-gate { CHUNK_INIT_ACK, "Init ACK", "Init ACK Chunk",
1090Sstevel@tonic-gate parse_init_chunk },
1100Sstevel@tonic-gate { CHUNK_SACK, "SACK", "SACK Chunk",
1110Sstevel@tonic-gate parse_sack_chunk },
1120Sstevel@tonic-gate { CHUNK_HEARTBEAT, "Heartbeat", "Heartbeat Chunk",
1130Sstevel@tonic-gate parse_opaque_chunk },
1140Sstevel@tonic-gate { CHUNK_HEARTBEAT_ACK, "Heartbeat ACK", "Heartbeat ACK Chunk",
1150Sstevel@tonic-gate parse_opaque_chunk },
1160Sstevel@tonic-gate { CHUNK_ABORT, "Abort", "Abort Chunk",
1170Sstevel@tonic-gate parse_abort_chunk },
1180Sstevel@tonic-gate { CHUNK_SHUTDOWN, "Shutdown", "Shutdown Chunk",
1190Sstevel@tonic-gate parse_shutdown_chunk },
1200Sstevel@tonic-gate { CHUNK_SHUTDOWN_ACK, "Shutdown ACK", "Shutdown ACK Chunk",
1210Sstevel@tonic-gate NULL },
1220Sstevel@tonic-gate { CHUNK_ERROR, "Err", "Error Chunk",
1230Sstevel@tonic-gate parse_error_chunk },
1240Sstevel@tonic-gate { CHUNK_COOKIE, "Cookie", "Cookie Chunk",
1250Sstevel@tonic-gate parse_opaque_chunk },
1260Sstevel@tonic-gate { CHUNK_COOKIE_ACK, "Cookie ACK", "Cookie ACK Chunk",
1270Sstevel@tonic-gate parse_opaque_chunk },
1280Sstevel@tonic-gate { CHUNK_ECNE, "ECN Echo", "ECN Echo Chunk",
1290Sstevel@tonic-gate parse_opaque_chunk },
1300Sstevel@tonic-gate { CHUNK_CWR, "CWR", "CWR Chunk",
1310Sstevel@tonic-gate parse_opaque_chunk },
1320Sstevel@tonic-gate { CHUNK_SHUTDOWN_COMPLETE, "Shutdown Done", "Shutdown Done",
1330Sstevel@tonic-gate parse_shutdone_chunk },
1340Sstevel@tonic-gate { CHUNK_FORWARD_TSN, "FORWARD TSN", "Forward TSN Chunk",
1350Sstevel@tonic-gate parse_ftsn_chunk },
1360Sstevel@tonic-gate { CHUNK_ASCONF_ACK, "ASCONF ACK", "ASCONF ACK Chunk",
1370Sstevel@tonic-gate parse_asconf_chunk },
1380Sstevel@tonic-gate { CHUNK_ASCONF, "ASCONF", "ASCONF Chunk",
1390Sstevel@tonic-gate parse_asconf_chunk }
1400Sstevel@tonic-gate };
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate /*
1430Sstevel@tonic-gate * Parameter Parsers
1440Sstevel@tonic-gate */
1450Sstevel@tonic-gate static parse_func_t parse_encap_param, parse_int32_param, parse_ip4_param,
1460Sstevel@tonic-gate parse_ip6_param, parse_opaque_param, parse_suppaddr_param,
1470Sstevel@tonic-gate parse_unrec_chunk, parse_addip_param, parse_asconferr_param,
1480Sstevel@tonic-gate parse_asconfok_param, parse_addiperr_param;
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * Parameter parser dispatch table. The summary description is not
1520Sstevel@tonic-gate * used here. Strictly speaking, parameter types are defined within
1530Sstevel@tonic-gate * the context of a chunk type. However, thus far the IETF WG has
1540Sstevel@tonic-gate * agreed to follow the convention that parameter types are globally
1550Sstevel@tonic-gate * unique (and why not, with a 16-bit namespace). However, if this
1560Sstevel@tonic-gate * ever changes, there will need to be different parameter dispatch
1570Sstevel@tonic-gate * tables for each chunk type.
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate static const dispatch_t parm_dispatch_table[] = {
1600Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */
1610Sstevel@tonic-gate { PARM_UNKNOWN, "", "Unknown Parameter",
1620Sstevel@tonic-gate parse_opaque_param },
1630Sstevel@tonic-gate { PARM_HBINFO, "", "Heartbeat Info",
1640Sstevel@tonic-gate parse_opaque_param },
1650Sstevel@tonic-gate { PARM_ADDR4, "", "IPv4 Address",
1660Sstevel@tonic-gate parse_ip4_param },
1670Sstevel@tonic-gate { PARM_ADDR6, "", "IPv6 Address",
1680Sstevel@tonic-gate parse_ip6_param },
1690Sstevel@tonic-gate { PARM_COOKIE, "", "Cookie",
1700Sstevel@tonic-gate parse_opaque_param },
1710Sstevel@tonic-gate { PARM_UNRECOGNIZED, "", "Unrecognized Param",
1720Sstevel@tonic-gate parse_encap_param },
1730Sstevel@tonic-gate { PARM_COOKIE_PRESERVE, "", "Cookie Preservative",
1740Sstevel@tonic-gate parse_opaque_param },
1750Sstevel@tonic-gate { 10, "", "Reserved for ECN",
1760Sstevel@tonic-gate parse_opaque_param },
1770Sstevel@tonic-gate { PARM_ADDR_HOST_NAME, "", "Host Name Parameter",
1780Sstevel@tonic-gate parse_opaque_param },
1790Sstevel@tonic-gate { PARM_SUPP_ADDRS, "", "Supported Addresses",
1800Sstevel@tonic-gate parse_suppaddr_param },
1810Sstevel@tonic-gate { PARM_ECN_CAPABLE, "", "ECN Capable",
1820Sstevel@tonic-gate parse_opaque_param },
1830Sstevel@tonic-gate { PARM_ADD_IP, "", "Add IP",
1840Sstevel@tonic-gate parse_addip_param },
1850Sstevel@tonic-gate { PARM_DEL_IP, "", "Del IP",
1860Sstevel@tonic-gate parse_addip_param },
1870Sstevel@tonic-gate { PARM_ASCONF_ERROR, "", "ASCONF Error Ind",
1880Sstevel@tonic-gate parse_asconferr_param },
1890Sstevel@tonic-gate { PARM_PRIMARY_ADDR, "", "Set Primary Address",
1900Sstevel@tonic-gate parse_addip_param },
1910Sstevel@tonic-gate { PARM_FORWARD_TSN, "", "Forward TSN",
1920Sstevel@tonic-gate NULL },
1930Sstevel@tonic-gate { PARM_ASCONF_SUCCESS, "", "ASCONF Success Ind",
1940Sstevel@tonic-gate parse_asconfok_param }
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate * Errors have the same wire format at parameters.
1990Sstevel@tonic-gate */
2000Sstevel@tonic-gate static const dispatch_t err_dispatch_table[] = {
2010Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */
2020Sstevel@tonic-gate { SCTP_ERR_UNKNOWN, "", "Unknown Error",
2030Sstevel@tonic-gate parse_opaque_param },
2040Sstevel@tonic-gate { SCTP_ERR_BAD_SID, "", "Invalid Stream ID",
2050Sstevel@tonic-gate parse_opaque_param },
2060Sstevel@tonic-gate { SCTP_ERR_MISSING_PARM, "", "Missing Parameter",
2070Sstevel@tonic-gate parse_opaque_param },
2080Sstevel@tonic-gate { SCTP_ERR_STALE_COOKIE, "", "Stale Cookie",
2090Sstevel@tonic-gate parse_int32_param },
2100Sstevel@tonic-gate { SCTP_ERR_NO_RESOURCES, "", "Out Of Resources",
2110Sstevel@tonic-gate parse_opaque_param },
2120Sstevel@tonic-gate { SCTP_ERR_BAD_ADDR, "", "Unresolvable Address",
2130Sstevel@tonic-gate parse_opaque_param },
2140Sstevel@tonic-gate { SCTP_ERR_UNREC_CHUNK, "", "Unrecognized Chunk",
2150Sstevel@tonic-gate parse_unrec_chunk },
2160Sstevel@tonic-gate { SCTP_ERR_BAD_MANDPARM, "", "Bad Mandatory Parameter",
2170Sstevel@tonic-gate parse_opaque_param },
2180Sstevel@tonic-gate { SCTP_ERR_UNREC_PARM, "", "Unrecognized Parameter",
2190Sstevel@tonic-gate parse_opaque_param },
2200Sstevel@tonic-gate { SCTP_ERR_NO_USR_DATA, "", "No User Data",
2210Sstevel@tonic-gate parse_int32_param },
2220Sstevel@tonic-gate { SCTP_ERR_COOKIE_SHUT, "", "Cookie During Shutdown",
2230Sstevel@tonic-gate parse_opaque_param },
2240Sstevel@tonic-gate { SCTP_ERR_DELETE_LASTADDR, "", "Delete Last Remaining Address",
2250Sstevel@tonic-gate parse_addiperr_param },
2260Sstevel@tonic-gate { SCTP_ERR_RESOURCE_SHORTAGE, "", "Resource Shortage",
2270Sstevel@tonic-gate parse_addiperr_param },
2280Sstevel@tonic-gate { SCTP_ERR_DELETE_SRCADDR, "", "Delete Source IP Address",
2290Sstevel@tonic-gate parse_addiperr_param },
2300Sstevel@tonic-gate { SCTP_ERR_AUTH_ERR, "", "Not authorized",
2310Sstevel@tonic-gate parse_addiperr_param }
2320Sstevel@tonic-gate };
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate * These are global because the data chunk parser needs them to dispatch
2360Sstevel@tonic-gate * to ULPs. The alternative is to add source and dest port arguments
2370Sstevel@tonic-gate * to every parser, which seems even messier (since *only* the data
2380Sstevel@tonic-gate * chunk parser needs it)...
2390Sstevel@tonic-gate */
2400Sstevel@tonic-gate static in_port_t sport, dport;
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate /* Summary line miscellany */
2430Sstevel@tonic-gate static int sumlen;
2440Sstevel@tonic-gate static char scratch[MAXLINE];
2450Sstevel@tonic-gate static char *sumline;
2460Sstevel@tonic-gate
2470Sstevel@tonic-gate #define SUMAPPEND(fmt) \
2480Sstevel@tonic-gate sumlen -= snprintf fmt; \
2490Sstevel@tonic-gate (void) strlcat(sumline, scratch, sumlen)
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate #define DUMPHEX_MAX 16
2520Sstevel@tonic-gate
2530Sstevel@tonic-gate static const dispatch_t *
lookup_dispatch(int id,const dispatch_t * tbl,int tblsz)2540Sstevel@tonic-gate lookup_dispatch(int id, const dispatch_t *tbl, int tblsz)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate int i;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate * Try fast lookup first. The common chunks defined in RFC2960
2600Sstevel@tonic-gate * will have indices aligned with their IDs, so this works for
2610Sstevel@tonic-gate * the common case.
2620Sstevel@tonic-gate */
2630Sstevel@tonic-gate if (id < (tblsz - 1)) {
2640Sstevel@tonic-gate if (id == tbl[id].id) {
2650Sstevel@tonic-gate return (tbl + id);
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate * Nope - probably an extension. Search the whole table,
2710Sstevel@tonic-gate * starting from the end, since extensions are at the end.
2720Sstevel@tonic-gate */
2730Sstevel@tonic-gate for (i = tblsz - 1; i >= 0; i--) {
2740Sstevel@tonic-gate if (id == tbl[i].id) {
2750Sstevel@tonic-gate return (tbl + i);
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate return (NULL);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate * Dumps no more than the first DUMPHEX_MAX bytes in hex. If
2840Sstevel@tonic-gate * the user wants more, they can use the -x option to snoop.
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate static void
dumphex(const uchar_t * payload,int payload_len,char * msg)2870Sstevel@tonic-gate dumphex(const uchar_t *payload, int payload_len, char *msg)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate int index;
2900Sstevel@tonic-gate int end;
2910Sstevel@tonic-gate char buf[BUFLEN];
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate if (payload_len == 0) {
2940Sstevel@tonic-gate return;
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate end = payload_len > DUMPHEX_MAX ? DUMPHEX_MAX : payload_len;
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate for (index = 0; index < end; index++) {
3000Sstevel@tonic-gate (void) snprintf(&buf[index * 3], 4, " %.2x", payload[index]);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate if (payload_len > DUMPHEX_MAX) {
3040Sstevel@tonic-gate (void) strlcat(buf, " ...", BUFLEN);
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate (void) snprintf(get_line(0, 0), BUFLEN, msg, buf);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate * Present perscribed action for unknowns according to rfc2960. Works
3120Sstevel@tonic-gate * for chunks and parameters as well if the parameter type is
3130Sstevel@tonic-gate * shifted 8 bits right.
3140Sstevel@tonic-gate */
3150Sstevel@tonic-gate static const char *
get_action_desc(uint8_t id)3160Sstevel@tonic-gate get_action_desc(uint8_t id)
3170Sstevel@tonic-gate {
3180Sstevel@tonic-gate if ((id & 0xc0) == 0xc0) {
3190Sstevel@tonic-gate return (": skip on unknown, return error");
3200Sstevel@tonic-gate } else if ((id & 0x80) == 0x80) {
3210Sstevel@tonic-gate return (": skip on unknown, no error");
3220Sstevel@tonic-gate } else if ((id & 0x40) == 0x40) {
3230Sstevel@tonic-gate return (": stop on unknown, return error");
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /* Top two bits are clear */
3270Sstevel@tonic-gate return (": stop on unknown, no error");
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /* ARGSUSED */
3310Sstevel@tonic-gate static void
parse_asconfok_param(int flags,uint8_t notused,const void * data,int dlen)3320Sstevel@tonic-gate parse_asconfok_param(int flags, uint8_t notused, const void *data, int dlen)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate uint32_t *cid;
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate if (dlen < sizeof (*cid)) {
3370Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
3380Sstevel@tonic-gate " ==> Incomplete ASCONF Success Ind parameter");
3390Sstevel@tonic-gate return;
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate cid = (uint32_t *)data;
3420Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u",
3430Sstevel@tonic-gate ntohl(*cid));
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate /* ARGSUSED */
3470Sstevel@tonic-gate static void
parse_asconferr_param(int flags,uint8_t notused,const void * data,int dlen)3480Sstevel@tonic-gate parse_asconferr_param(int flags, uint8_t notused, const void *data, int dlen)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate uint32_t *cid;
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate if (dlen < sizeof (*cid)) {
3530Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
3540Sstevel@tonic-gate " ==> Incomplete ASCONF Error Ind parameter");
3550Sstevel@tonic-gate return;
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate cid = (uint32_t *)data;
3580Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u",
3590Sstevel@tonic-gate ntohl(*cid));
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate interpret_params(cid + 1, dlen - sizeof (*cid), "Error",
3620Sstevel@tonic-gate err_dispatch_table, A_CNT(err_dispatch_table), flags);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate
3650Sstevel@tonic-gate /* ARGSUSED */
3660Sstevel@tonic-gate static void
parse_addiperr_param(int flags,uint8_t notused,const void * data,int dlen)3670Sstevel@tonic-gate parse_addiperr_param(int flags, uint8_t notused, const void *data, int dlen)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate
3700Sstevel@tonic-gate interpret_params(data, dlen, "Parameter",
3710Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate /* ARGSUSED */
3750Sstevel@tonic-gate static void
parse_addip_param(int flags,uint8_t notused,const void * data,int dlen)3760Sstevel@tonic-gate parse_addip_param(int flags, uint8_t notused, const void *data, int dlen)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate uint32_t *cid;
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate if (dlen < sizeof (*cid)) {
3820Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
3830Sstevel@tonic-gate " ==> Incomplete ASCONF Error Ind parameter");
3840Sstevel@tonic-gate return;
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate cid = (uint32_t *)data;
3870Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u",
3880Sstevel@tonic-gate ntohl(*cid));
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate interpret_params(cid + 1, dlen - sizeof (*cid), "Parameter",
3910Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate /* ARGSUSED */
3950Sstevel@tonic-gate static void
parse_ip4_param(int flags,uint8_t notused,const void * data,int datalen)3960Sstevel@tonic-gate parse_ip4_param(int flags, uint8_t notused, const void *data, int datalen)
3970Sstevel@tonic-gate {
3980Sstevel@tonic-gate char abuf[INET_ADDRSTRLEN];
3990Sstevel@tonic-gate char *ap;
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate if (datalen < sizeof (in_addr_t)) {
4020Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4030Sstevel@tonic-gate " ==> Incomplete IPv4 Addr parameter");
4040Sstevel@tonic-gate return;
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate ap = (char *)inet_ntop(AF_INET, data, abuf, INET_ADDRSTRLEN);
4080Sstevel@tonic-gate if (ap == NULL) {
4090Sstevel@tonic-gate ap = "<Bad Address>";
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " Addr = %s", ap);
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate /* ARGSUSED */
4160Sstevel@tonic-gate static void
parse_ip6_param(int flags,uint8_t notused,const void * data,int datalen)4170Sstevel@tonic-gate parse_ip6_param(int flags, uint8_t notused, const void *data, int datalen)
4180Sstevel@tonic-gate {
4190Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
4200Sstevel@tonic-gate char *ap;
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if (datalen < sizeof (in6_addr_t)) {
4230Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4240Sstevel@tonic-gate " ==> Incomplete IPv6 Addr parameter");
4250Sstevel@tonic-gate return;
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate ap = (char *)inet_ntop(AF_INET6, data, abuf, INET6_ADDRSTRLEN);
4290Sstevel@tonic-gate if (ap == NULL) {
4300Sstevel@tonic-gate ap = "<Bad Address>";
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " Addr = %s", ap);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate /* ARGSUSED */
4370Sstevel@tonic-gate static void
parse_int32_param(int flags,uint8_t notused,const void * data,int datalen)4380Sstevel@tonic-gate parse_int32_param(int flags, uint8_t notused, const void *data, int datalen)
4390Sstevel@tonic-gate {
4400Sstevel@tonic-gate if (datalen < 4) {
4410Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4420Sstevel@tonic-gate " ==> Incomplete INT32 parameter");
4430Sstevel@tonic-gate return;
4440Sstevel@tonic-gate }
4450Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " INT32 = %u",
4460Sstevel@tonic-gate ntohl(*(uint32_t *)data));
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /* ARGSUSED */
4500Sstevel@tonic-gate static void
parse_suppaddr_param(int flags,uint8_t notused,const void * data,int dlen)4510Sstevel@tonic-gate parse_suppaddr_param(int flags, uint8_t notused, const void *data, int dlen)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate const uint16_t *type;
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate if (dlen < 2) {
4560Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4570Sstevel@tonic-gate "==> Incomplete Supported Addr parameter");
4580Sstevel@tonic-gate return;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate type = data;
4620Sstevel@tonic-gate while (dlen > 0) {
4630Sstevel@tonic-gate switch (ntohs(*type)) {
4640Sstevel@tonic-gate case PARM_ADDR4:
4650Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4660Sstevel@tonic-gate " IPv4");
4670Sstevel@tonic-gate break;
4680Sstevel@tonic-gate case PARM_ADDR6:
4690Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4700Sstevel@tonic-gate " IPv6");
4710Sstevel@tonic-gate break;
4720Sstevel@tonic-gate case PARM_ADDR_HOST_NAME:
4730Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4740Sstevel@tonic-gate " Host Name");
4750Sstevel@tonic-gate break;
4760Sstevel@tonic-gate default:
4770Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4780Sstevel@tonic-gate "Unknown Type (%hu)", ntohs(*type));
4790Sstevel@tonic-gate break;
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate dlen -= sizeof (*type);
4820Sstevel@tonic-gate type++;
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate
4860Sstevel@tonic-gate /*ARGSUSED*/
4870Sstevel@tonic-gate static void
parse_encap_param(int flags,uint8_t notused,const void * data,int dlen)4880Sstevel@tonic-gate parse_encap_param(int flags, uint8_t notused, const void *data, int dlen)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate if (dlen < sizeof (sctp_parm_hdr_t)) {
4910Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4920Sstevel@tonic-gate "==> Incomplete Parameter");
4930Sstevel@tonic-gate return;
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate interpret_params(data, dlen, "Parameter",
4970Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
4980Sstevel@tonic-gate }
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate /* ARGSUSED */
5010Sstevel@tonic-gate static void
parse_unrec_chunk(int flags,uint8_t cflags,const void * data,int datalen)5020Sstevel@tonic-gate parse_unrec_chunk(int flags, uint8_t cflags, const void *data, int datalen)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate const sctp_chunk_hdr_t *cp = data;
5050Sstevel@tonic-gate const dispatch_t *dp;
5060Sstevel@tonic-gate const char *actstr;
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate if (datalen < sizeof (*cp)) {
5090Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
5100Sstevel@tonic-gate "==> Incomplete Unrecognized Chunk Error");
5110Sstevel@tonic-gate return;
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate /* Maybe snoop knows about this chunk? */
5150Sstevel@tonic-gate dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table,
5160Sstevel@tonic-gate A_CNT(chunk_dispatch_table));
5170Sstevel@tonic-gate if (dp != NULL) {
5180Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
5190Sstevel@tonic-gate " Chunk Type = %u (%s)", cp->sch_id, dp->vdesc);
5200Sstevel@tonic-gate } else {
5210Sstevel@tonic-gate actstr = get_action_desc(cp->sch_id);
5220Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
5230Sstevel@tonic-gate " Chunk Type = %u%s", cp->sch_id, actstr);
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate }
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate /*
5280Sstevel@tonic-gate * Same as parse_opaque_chunk except for the indentation.
5290Sstevel@tonic-gate */
5300Sstevel@tonic-gate /* ARGSUSED */
5310Sstevel@tonic-gate static void
parse_opaque_param(int flags,uint8_t cflags,const void * data,int datalen)5320Sstevel@tonic-gate parse_opaque_param(int flags, uint8_t cflags, const void *data, int datalen)
5330Sstevel@tonic-gate {
5340Sstevel@tonic-gate dumphex(data, datalen, " Data = %s");
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate /*
5380Sstevel@tonic-gate * Loops through all parameters (or errors) until it has read
5390Sstevel@tonic-gate * datalen bytes of information, finding a parser for each.
5400Sstevel@tonic-gate * The tbl argument allows the caller to specify which dispatch
5410Sstevel@tonic-gate * table to use, making this function useful for both parameters
5420Sstevel@tonic-gate * and errors. The type argument is used to denote whether this
5430Sstevel@tonic-gate * is an error or parameter in detailed mode.
5440Sstevel@tonic-gate */
5450Sstevel@tonic-gate static void
interpret_params(const void * data,int datalen,char * type,const dispatch_t * tbl,int tbl_size,int flags)5460Sstevel@tonic-gate interpret_params(const void *data, int datalen, char *type,
5470Sstevel@tonic-gate const dispatch_t *tbl, int tbl_size, int flags)
5480Sstevel@tonic-gate {
5490Sstevel@tonic-gate const sctp_parm_hdr_t *hdr = data;
5500Sstevel@tonic-gate uint16_t plen;
5510Sstevel@tonic-gate uint16_t ptype;
5520Sstevel@tonic-gate const char *desc;
5530Sstevel@tonic-gate parse_func_t *parse;
5540Sstevel@tonic-gate int pad;
5550Sstevel@tonic-gate const dispatch_t *dp;
5560Sstevel@tonic-gate const char *actstr;
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate for (;;) {
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate * Adjust for padding: if the address isn't aligned, there
5610Sstevel@tonic-gate * should be some padding. So skip over the padding and
5620Sstevel@tonic-gate * adjust hdr accordingly. RFC2960 mandates that all
5630Sstevel@tonic-gate * parameters must be 32-bit aligned WRT the enclosing chunk,
5640Sstevel@tonic-gate * which ensures that this parameter header will
5650Sstevel@tonic-gate * be 32-bit aligned in memory. We must, of course, bounds
5660Sstevel@tonic-gate * check fraglen before actually trying to use hdr, in
5670Sstevel@tonic-gate * case the packet has been mangled or is the product
5680Sstevel@tonic-gate * of a buggy implementation.
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate if ((pad = (uintptr_t)hdr % SCTP_ALIGN) != 0) {
5710Sstevel@tonic-gate pad = SCTP_ALIGN - pad;
5720Sstevel@tonic-gate datalen -= pad;
5730Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
5740Sstevel@tonic-gate hdr = (sctp_parm_hdr_t *)((char *)hdr + pad);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /* Need to compare against 0 1st, since sizeof is unsigned */
5780Sstevel@tonic-gate if (datalen < 0 || datalen < sizeof (*hdr)) {
5790Sstevel@tonic-gate if (datalen > 0) {
5800Sstevel@tonic-gate (void) snprintf(get_line(0, 0),
5810Sstevel@tonic-gate get_line_remain(),
5820Sstevel@tonic-gate "==> Extra data after last parameter");
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate return;
5850Sstevel@tonic-gate }
5860Sstevel@tonic-gate plen = ntohs(hdr->sph_len);
5870Sstevel@tonic-gate if (datalen < plen || plen < sizeof (*hdr)) {
5880Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
5890Sstevel@tonic-gate " ==> Incomplete %s", type);
5900Sstevel@tonic-gate return;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate /* Get description and parser */
5940Sstevel@tonic-gate ptype = ntohs(hdr->sph_type);
5950Sstevel@tonic-gate desc = "Unknown Parameter Type";
5960Sstevel@tonic-gate parse = parse_opaque_param;
5970Sstevel@tonic-gate dp = lookup_dispatch(ptype, tbl, tbl_size);
5980Sstevel@tonic-gate if (dp != NULL) {
5990Sstevel@tonic-gate desc = dp->vdesc;
6000Sstevel@tonic-gate parse = dp->parse;
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate show_space();
6040Sstevel@tonic-gate if (dp != NULL) {
6050Sstevel@tonic-gate actstr = "";
6060Sstevel@tonic-gate } else {
6070Sstevel@tonic-gate actstr = get_action_desc((uint8_t)(ptype >> 8));
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6100Sstevel@tonic-gate " ------- SCTP %s Type = %s (%u%s)", type, desc, ptype,
6110Sstevel@tonic-gate actstr);
6120Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6130Sstevel@tonic-gate " Data length = %hu", plen - sizeof (*hdr));
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate if (parse != NULL) {
6160Sstevel@tonic-gate parse(flags, 0, (char *)(hdr + 1),
6170Sstevel@tonic-gate plen - sizeof (*hdr));
6180Sstevel@tonic-gate }
6190Sstevel@tonic-gate datalen -= plen;
6200Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
6210Sstevel@tonic-gate hdr = (sctp_parm_hdr_t *)((char *)hdr + plen);
6220Sstevel@tonic-gate }
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /* ARGSUSED */
6260Sstevel@tonic-gate static void
parse_ftsn_chunk(int flags,uint8_t cflags,const void * data,int datalen)6270Sstevel@tonic-gate parse_ftsn_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate uint32_t *ftsn;
6300Sstevel@tonic-gate ftsn_entry_t *ftsn_entry;
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate if (datalen < (sizeof (*ftsn) + sizeof (*ftsn_entry))) {
6330Sstevel@tonic-gate if (flags & F_DTAIL) {
6340Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6350Sstevel@tonic-gate "==> Incomplete FORWARD-TSN chunk");
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate return;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate ftsn = (uint32_t *)data;
6410Sstevel@tonic-gate if (flags & F_SUM) {
6420Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "CTSN %x ", ntohl(*ftsn)));
6430Sstevel@tonic-gate return;
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Cum TSN= %x",
6460Sstevel@tonic-gate ntohl(*ftsn));
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate datalen -= sizeof (*ftsn);
6490Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(ftsn + 1);
6500Sstevel@tonic-gate while (datalen >= sizeof (*ftsn_entry)) {
6510Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6520Sstevel@tonic-gate "SID = %u : SSN = %u", ntohs(ftsn_entry->ftsn_sid),
6530Sstevel@tonic-gate ntohs(ftsn_entry->ftsn_ssn));
6540Sstevel@tonic-gate datalen -= sizeof (*ftsn_entry);
6550Sstevel@tonic-gate ftsn_entry++;
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate /* ARGSUSED */
6600Sstevel@tonic-gate static void
parse_asconf_chunk(int flags,uint8_t cflags,const void * data,int datalen)6610Sstevel@tonic-gate parse_asconf_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate uint32_t *sn;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate if (datalen < sizeof (*sn)) {
6660Sstevel@tonic-gate if (flags & F_DTAIL) {
6670Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6680Sstevel@tonic-gate "==> Incomplete ASCONF chunk");
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate return;
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate sn = (uint32_t *)data;
6740Sstevel@tonic-gate if (flags & F_SUM) {
6750Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "sn %x ", ntohl(*sn)));
6760Sstevel@tonic-gate return;
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Serial Number= %x",
6790Sstevel@tonic-gate ntohl(*sn));
6800Sstevel@tonic-gate interpret_params(sn + 1, datalen - sizeof (*sn), "Parameter",
6810Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate static void
parse_init_chunk(int flags,uint8_t cflags,const void * data,int datalen)6850Sstevel@tonic-gate parse_init_chunk(int flags, uint8_t cflags, const void *data, int datalen)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate const sctp_init_chunk_t *icp = data;
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate if (datalen < sizeof (*icp)) {
6900Sstevel@tonic-gate if (flags & F_DTAIL) {
6910Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6920Sstevel@tonic-gate "==> Incomplete INIT chunk");
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate return;
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate if (flags & F_SUM) {
6980Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "tsn %x str %hu/%hu win %u ",
6990Sstevel@tonic-gate ntohl(icp->sic_inittsn), ntohs(icp->sic_outstr),
7000Sstevel@tonic-gate ntohs(icp->sic_instr), ntohl(icp->sic_a_rwnd)));
7010Sstevel@tonic-gate return;
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Flags = 0x%.2x",
7050Sstevel@tonic-gate cflags);
7060Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7070Sstevel@tonic-gate "Initiate tag = 0x%.8x", ntohl(icp->sic_inittag));
7080Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7090Sstevel@tonic-gate "Advertised receiver window credit = %u", ntohl(icp->sic_a_rwnd));
7100Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7110Sstevel@tonic-gate "Outbound streams = %hu", ntohs(icp->sic_outstr));
7120Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7130Sstevel@tonic-gate "Inbound streams = %hu", ntohs(icp->sic_instr));
7140Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7150Sstevel@tonic-gate "Initial TSN = 0x%.8x", ntohl(icp->sic_inittsn));
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate if (datalen > sizeof (*icp)) {
7180Sstevel@tonic-gate interpret_params(icp + 1, datalen - sizeof (*icp),
7190Sstevel@tonic-gate "Parameter", parm_dispatch_table,
7200Sstevel@tonic-gate A_CNT(parm_dispatch_table), flags);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate }
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate static void
parse_data_chunk(int flags,uint8_t cflags,const void * data,int datalen)7250Sstevel@tonic-gate parse_data_chunk(int flags, uint8_t cflags, const void *data, int datalen)
7260Sstevel@tonic-gate {
7270Sstevel@tonic-gate const sctp_data_chunk_t *dcp = data;
7280Sstevel@tonic-gate char *payload;
7290Sstevel@tonic-gate uint32_t ppid;
7300Sstevel@tonic-gate
7310Sstevel@tonic-gate if (datalen < sizeof (*dcp)) {
7320Sstevel@tonic-gate if (flags & F_DTAIL) {
7330Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7340Sstevel@tonic-gate "==> Incomplete DATA chunk %d (%d)", datalen,
7350Sstevel@tonic-gate sizeof (*dcp));
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate return;
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate ppid = ntohl(dcp->sdc_payload_id);
741*1766Skcpoon /* This is the actual data len, excluding the data chunk header. */
742*1766Skcpoon datalen -= sizeof (*dcp);
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate if (flags & F_DTAIL) {
7450Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7460Sstevel@tonic-gate "flags = 0x%.2x", cflags);
7470Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
7480Sstevel@tonic-gate getflag(cflags, SCTP_DATA_UBIT, "unordered", "ordered"));
7490Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
7500Sstevel@tonic-gate getflag(cflags, SCTP_DATA_BBIT,
7510Sstevel@tonic-gate "beginning", "(beginning unset)"));
7520Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
7530Sstevel@tonic-gate getflag(cflags, SCTP_DATA_EBIT, "end", "(end unset)"));
7540Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7550Sstevel@tonic-gate "TSN = 0x%.8x", ntohl(dcp->sdc_tsn));
7560Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7570Sstevel@tonic-gate "Stream ID = %hu", ntohs(dcp->sdc_sid));
7580Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7590Sstevel@tonic-gate "Stream Sequence Number = %hu", ntohs(dcp->sdc_ssn));
7600Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7610Sstevel@tonic-gate "Payload Protocol ID = 0x%.8x", ppid);
7620Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
763*1766Skcpoon "Data Length = %d", datalen);
7640Sstevel@tonic-gate show_space();
7650Sstevel@tonic-gate }
7660Sstevel@tonic-gate if (flags & F_SUM) {
767*1766Skcpoon SUMAPPEND((scratch, MAXLINE, "len %d tsn %x str %hu/%hu "
768*1766Skcpoon "ppid %x ", datalen, ntohl(dcp->sdc_tsn),
769*1766Skcpoon ntohs(dcp->sdc_sid), ntohs(dcp->sdc_ssn), ppid));
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate * Go to the next protocol layer, but not if we are in
7740Sstevel@tonic-gate * summary mode only. In summary mode, each ULP parse would
7750Sstevel@tonic-gate * create a new line, and if there were several data chunks
7760Sstevel@tonic-gate * bundled together in the packet, this would confuse snoop's
7770Sstevel@tonic-gate * packet numbering and timestamping.
7780Sstevel@tonic-gate *
7790Sstevel@tonic-gate * SCTP carries two ways to determine an ULP: ports and the
7800Sstevel@tonic-gate * payload protocol identifier (ppid). Since ports are the
7810Sstevel@tonic-gate * better entrenched convention, we first try interpret_reserved().
7820Sstevel@tonic-gate * If that fails to find a parser, we try by the PPID.
7830Sstevel@tonic-gate */
7840Sstevel@tonic-gate if (!(flags & F_ALLSUM) && !(flags & F_DTAIL)) {
7850Sstevel@tonic-gate return;
7860Sstevel@tonic-gate }
7870Sstevel@tonic-gate
7880Sstevel@tonic-gate payload = (char *)(dcp + 1);
7890Sstevel@tonic-gate if (!interpret_reserved(flags, IPPROTO_SCTP, sport, dport, payload,
790*1766Skcpoon datalen) && ppid != 0) {
7910Sstevel@tonic-gate
792*1766Skcpoon interpret_protoid(flags, ppid, payload, datalen);
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate /*
7960Sstevel@tonic-gate * Reset the protocol prefix, since it may have been changed
7970Sstevel@tonic-gate * by a ULP interpreter.
7980Sstevel@tonic-gate */
7990Sstevel@tonic-gate prot_prefix = "SCTP: ";
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate /* ARGSUSED */
8030Sstevel@tonic-gate static void
parse_sack_chunk(int flags,uint8_t cflags,const void * data,int datalen)8040Sstevel@tonic-gate parse_sack_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8050Sstevel@tonic-gate {
8060Sstevel@tonic-gate const sctp_sack_chunk_t *scp = data;
8070Sstevel@tonic-gate uint16_t numfrags, numdups;
8080Sstevel@tonic-gate sctp_sack_frag_t *frag;
8090Sstevel@tonic-gate int i;
8100Sstevel@tonic-gate uint32_t *tsn;
8110Sstevel@tonic-gate
8120Sstevel@tonic-gate if (datalen < sizeof (*scp)) {
8130Sstevel@tonic-gate if (flags & F_DTAIL) {
8140Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8150Sstevel@tonic-gate "==> Incomplete SACK chunk");
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate return;
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate
8200Sstevel@tonic-gate if (flags & F_DTAIL) {
8210Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8220Sstevel@tonic-gate "Cumulative TSN ACK = 0x%.8x", ntohl(scp->ssc_cumtsn));
8230Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8240Sstevel@tonic-gate "Advertised Receiver Window Credit = %u",
8250Sstevel@tonic-gate ntohl(scp->ssc_a_rwnd));
8260Sstevel@tonic-gate numfrags = ntohs(scp->ssc_numfrags);
8270Sstevel@tonic-gate numdups = ntohs(scp->ssc_numdups);
8280Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8290Sstevel@tonic-gate "Number of Fragments = %hu", numfrags);
8300Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8310Sstevel@tonic-gate "Number of Duplicates = %hu", numdups);
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate /* Display any gap reports */
8340Sstevel@tonic-gate datalen -= sizeof (*scp);
8350Sstevel@tonic-gate if (datalen < (numfrags * sizeof (*frag))) {
8360Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8370Sstevel@tonic-gate " ==> Malformed gap report listing");
8380Sstevel@tonic-gate return;
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate frag = (sctp_sack_frag_t *)(scp + 1);
8410Sstevel@tonic-gate for (i = 0; i < numfrags; i++) {
8420Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8430Sstevel@tonic-gate " Fragment #%d: Start = %hu, end = %hu", i,
8440Sstevel@tonic-gate ntohs(frag->ssf_start), ntohs(frag->ssf_end));
8450Sstevel@tonic-gate frag += 1;
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate
8480Sstevel@tonic-gate /* Display any duplicate reports */
8490Sstevel@tonic-gate datalen -= numfrags * sizeof (*frag);
8500Sstevel@tonic-gate if (datalen < (numdups * sizeof (*tsn))) {
8510Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8520Sstevel@tonic-gate " ==> Malformed duplicate report listing");
8530Sstevel@tonic-gate return;
8540Sstevel@tonic-gate }
8550Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
8560Sstevel@tonic-gate tsn = (uint32_t *)frag;
8570Sstevel@tonic-gate for (i = 0; i < numdups; i++) {
8580Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8590Sstevel@tonic-gate " Duplicate #%d: TSN = %x", i, *tsn);
8600Sstevel@tonic-gate tsn++;
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate if (flags & F_SUM) {
8640Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE,
8650Sstevel@tonic-gate "tsn %x win %u gaps/dups %hu/%hu ", ntohl(scp->ssc_cumtsn),
8660Sstevel@tonic-gate ntohl(scp->ssc_a_rwnd), ntohs(scp->ssc_numfrags),
8670Sstevel@tonic-gate ntohs(scp->ssc_numdups)));
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate /* ARGSUSED */
8720Sstevel@tonic-gate static void
parse_shutdown_chunk(int flags,uint8_t cflags,const void * data,int datalen)8730Sstevel@tonic-gate parse_shutdown_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate const uint32_t *cumtsn = data;
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate if (datalen < sizeof (*cumtsn)) {
8780Sstevel@tonic-gate if (flags & F_DTAIL) {
8790Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8800Sstevel@tonic-gate "==> Incomplete Shutdown chunk");
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate return;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate if (flags & F_DTAIL) {
8860Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
8870Sstevel@tonic-gate "Cumulative TSN = 0x%.8x", ntohl(*cumtsn));
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate if (flags & F_SUM) {
8900Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "tsn %x", ntohl(*cumtsn)));
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate /* ARGSUSED */
8950Sstevel@tonic-gate static void
parse_error_chunk(int flags,uint8_t cflags,const void * data,int datalen)8960Sstevel@tonic-gate parse_error_chunk(int flags, uint8_t cflags, const void *data, int datalen)
8970Sstevel@tonic-gate {
8980Sstevel@tonic-gate if (!(flags & F_DTAIL)) {
8990Sstevel@tonic-gate return;
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate
9020Sstevel@tonic-gate interpret_params(data, datalen, "Error", err_dispatch_table,
9030Sstevel@tonic-gate A_CNT(err_dispatch_table), flags);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate static void
parse_abort_chunk(int flags,uint8_t cflags,const void * data,int datalen)9070Sstevel@tonic-gate parse_abort_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate if (!(flags & F_DTAIL)) {
9100Sstevel@tonic-gate return;
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate
9130Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x",
9140Sstevel@tonic-gate cflags);
9150Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
9160Sstevel@tonic-gate getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed"));
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate interpret_params(data, datalen, "Error", err_dispatch_table,
9190Sstevel@tonic-gate A_CNT(err_dispatch_table), flags);
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate /* ARGSUSED2 */
9230Sstevel@tonic-gate static void
parse_shutdone_chunk(int flags,uint8_t cflags,const void * data,int datalen)9240Sstevel@tonic-gate parse_shutdone_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate if (!(flags & F_DTAIL)) {
9270Sstevel@tonic-gate return;
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x",
9310Sstevel@tonic-gate cflags);
9320Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s",
9330Sstevel@tonic-gate getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed"));
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate /* ARGSUSED */
9370Sstevel@tonic-gate static void
parse_opaque_chunk(int flags,uint8_t cflags,const void * data,int datalen)9380Sstevel@tonic-gate parse_opaque_chunk(int flags, uint8_t cflags, const void *data, int datalen)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate if (!(flags & F_DTAIL)) {
9410Sstevel@tonic-gate return;
9420Sstevel@tonic-gate }
9430Sstevel@tonic-gate if (datalen == 0) {
9440Sstevel@tonic-gate return;
9450Sstevel@tonic-gate }
9460Sstevel@tonic-gate
9470Sstevel@tonic-gate dumphex(data, datalen, "Data = %s");
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate
9500Sstevel@tonic-gate /*
9510Sstevel@tonic-gate * Loops through all chunks until it has read fraglen bytes of
9520Sstevel@tonic-gate * information, finding a parser for each. If any parameters are
9530Sstevel@tonic-gate * present, interpret_params() is then called. Returns the remaining
9540Sstevel@tonic-gate * fraglen.
9550Sstevel@tonic-gate */
9560Sstevel@tonic-gate static int
interpret_chunks(int flags,sctp_chunk_hdr_t * cp,int fraglen)9570Sstevel@tonic-gate interpret_chunks(int flags, sctp_chunk_hdr_t *cp, int fraglen)
9580Sstevel@tonic-gate {
9590Sstevel@tonic-gate uint16_t clen;
9600Sstevel@tonic-gate int signed_len;
9610Sstevel@tonic-gate int pad;
9620Sstevel@tonic-gate const char *desc;
9630Sstevel@tonic-gate parse_func_t *parse;
9640Sstevel@tonic-gate const dispatch_t *dp;
9650Sstevel@tonic-gate const char *actstr;
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate for (;;) {
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate * Adjust for padding: if the address isn't aligned, there
9700Sstevel@tonic-gate * should be some padding. So skip over the padding and
9710Sstevel@tonic-gate * adjust hdr accordingly. RFC2960 mandates that all
9720Sstevel@tonic-gate * chunks must be 32-bit aligned WRT the SCTP common hdr,
9730Sstevel@tonic-gate * which ensures that this chunk header will
9740Sstevel@tonic-gate * be 32-bit aligned in memory. We must, of course, bounds
9750Sstevel@tonic-gate * check fraglen before actually trying to use hdr, in
9760Sstevel@tonic-gate * case the packet has been mangled or is the product
9770Sstevel@tonic-gate * of a buggy implementation.
9780Sstevel@tonic-gate */
9790Sstevel@tonic-gate if ((pad = (uintptr_t)cp % SCTP_ALIGN) != 0) {
9800Sstevel@tonic-gate pad = SCTP_ALIGN - pad;
9810Sstevel@tonic-gate fraglen -= pad;
9820Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
9830Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)((char *)cp + pad);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate /* Need to compare against 0 1st, since sizeof is unsigned */
9870Sstevel@tonic-gate if (fraglen < 0 || fraglen < sizeof (*cp)) {
9880Sstevel@tonic-gate if (fraglen > 0 && flags & F_DTAIL) {
9890Sstevel@tonic-gate (void) snprintf(get_line(0, 0),
9900Sstevel@tonic-gate get_line_remain(),
9910Sstevel@tonic-gate "==> Extra data after last chunk");
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate return (fraglen);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate
9960Sstevel@tonic-gate clen = ntohs(cp->sch_len);
9970Sstevel@tonic-gate if (fraglen < clen) {
9980Sstevel@tonic-gate if (flags & F_DTAIL) {
9990Sstevel@tonic-gate (void) snprintf(get_line(0, 0),
10000Sstevel@tonic-gate get_line_remain(), "==> Corrupted chunk");
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate return (fraglen);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate signed_len = clen - sizeof (*cp);
10060Sstevel@tonic-gate if (signed_len < 0) {
10070Sstevel@tonic-gate if (flags & F_DTAIL) {
10080Sstevel@tonic-gate (void) snprintf(get_line(0, 0),
10090Sstevel@tonic-gate get_line_remain(),
10100Sstevel@tonic-gate "==> Incomplete or corrupted chunk");
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate return (0);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate /* Get description and parser */
10160Sstevel@tonic-gate dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table,
10170Sstevel@tonic-gate A_CNT(chunk_dispatch_table));
10180Sstevel@tonic-gate if (dp != NULL) {
10190Sstevel@tonic-gate if (flags & F_SUM) {
10200Sstevel@tonic-gate desc = dp->sdesc;
10210Sstevel@tonic-gate } else if (flags & F_DTAIL) {
10220Sstevel@tonic-gate desc = dp->vdesc;
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate parse = dp->parse;
10250Sstevel@tonic-gate } else {
10260Sstevel@tonic-gate if (flags & F_SUM) {
10270Sstevel@tonic-gate desc = "UNK";
10280Sstevel@tonic-gate } else if (flags & F_DTAIL) {
10290Sstevel@tonic-gate desc = "Unknown Chunk Type";
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate parse = parse_opaque_chunk;
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate if (flags & F_SUM) {
10350Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "%s ", desc));
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate if (flags & F_DTAIL) {
10380Sstevel@tonic-gate show_space();
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate if (dp != NULL) {
10410Sstevel@tonic-gate actstr = "";
10420Sstevel@tonic-gate } else {
10430Sstevel@tonic-gate actstr = get_action_desc(cp->sch_id);
10440Sstevel@tonic-gate }
10450Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
10460Sstevel@tonic-gate "------- SCTP Chunk Type = %s (%u%s)", desc,
10470Sstevel@tonic-gate cp->sch_id, actstr);
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
10500Sstevel@tonic-gate "Chunk length = %hu", clen);
10510Sstevel@tonic-gate }
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate if (parse != NULL) {
10540Sstevel@tonic-gate parse(flags, cp->sch_flags, (char *)(cp + 1),
10550Sstevel@tonic-gate signed_len);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate fraglen -= clen;
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
10610Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)((char *)cp + clen);
10620Sstevel@tonic-gate }
10630Sstevel@tonic-gate }
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate void
interpret_sctp(int flags,sctp_hdr_t * sctp,int iplen,int fraglen)10660Sstevel@tonic-gate interpret_sctp(int flags, sctp_hdr_t *sctp, int iplen, int fraglen)
10670Sstevel@tonic-gate {
10680Sstevel@tonic-gate int len_from_iphdr;
10690Sstevel@tonic-gate sctp_chunk_hdr_t *cp;
10700Sstevel@tonic-gate char *pn;
10710Sstevel@tonic-gate char buff[32];
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * Alignment check. If the header is 32-bit aligned, all other
10750Sstevel@tonic-gate * protocol units will also be aligned, as mandated by rfc2960.
10760Sstevel@tonic-gate * Buggy packets will be caught and flagged by chunk and
10770Sstevel@tonic-gate * parameter bounds checking.
10780Sstevel@tonic-gate * If the header is not aligned, however, we drop the packet.
10790Sstevel@tonic-gate */
10800Sstevel@tonic-gate if (!IS_P2ALIGNED(sctp, SCTP_ALIGN)) {
10810Sstevel@tonic-gate if (flags & F_DTAIL) {
10820Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
10830Sstevel@tonic-gate "==> SCTP header not aligned, dropping");
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate return;
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate fraglen -= sizeof (*sctp);
10890Sstevel@tonic-gate if (fraglen < 0) {
10900Sstevel@tonic-gate if (flags & F_DTAIL) {
10910Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
10920Sstevel@tonic-gate "==> Incomplete sctp header");
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate return;
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate /* If fraglen is somehow longer than the IP payload, adjust it */
10970Sstevel@tonic-gate len_from_iphdr = iplen - sizeof (*sctp);
10980Sstevel@tonic-gate if (fraglen > len_from_iphdr) {
10990Sstevel@tonic-gate fraglen = len_from_iphdr;
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate /* Keep track of the ports */
11030Sstevel@tonic-gate sport = ntohs(sctp->sh_sport);
11040Sstevel@tonic-gate dport = ntohs(sctp->sh_dport);
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate /* Set pointer to first chunk */
11070Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)(sctp + 1);
11080Sstevel@tonic-gate
11090Sstevel@tonic-gate if (flags & F_SUM) {
11100Sstevel@tonic-gate sumline = get_sum_line();
11110Sstevel@tonic-gate *sumline = '\0';
11120Sstevel@tonic-gate sumlen = MAXLINE;
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "SCTP D=%d S=%d ", dport, sport));
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate
11170Sstevel@tonic-gate if (flags & F_DTAIL) {
11180Sstevel@tonic-gate show_header("SCTP: ", "SCTP Header", fraglen);
11190Sstevel@tonic-gate show_space();
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate pn = getportname(IPPROTO_SCTP, (ushort_t)sport);
11220Sstevel@tonic-gate if (pn == NULL) {
11230Sstevel@tonic-gate pn = "";
11240Sstevel@tonic-gate } else {
11250Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "(%s)", pn);
11260Sstevel@tonic-gate pn = buff;
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
11290Sstevel@tonic-gate "Source port = %hu %s", sport, pn);
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate pn = getportname(IPPROTO_SCTP, (ushort_t)dport);
11320Sstevel@tonic-gate if (pn == NULL) {
11330Sstevel@tonic-gate pn = "";
11340Sstevel@tonic-gate } else {
11350Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "(%s)", pn);
11360Sstevel@tonic-gate pn = buff;
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
11390Sstevel@tonic-gate "Destination port = %hu %s", dport, pn);
11400Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
11410Sstevel@tonic-gate "Verification tag = 0x%.8x", ntohl(sctp->sh_verf));
11420Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
11430Sstevel@tonic-gate "CRC-32c = 0x%.8x", ntohl(sctp->sh_chksum));
11440Sstevel@tonic-gate }
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate (void) interpret_chunks(flags, cp, fraglen);
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate if (flags & F_DTAIL) {
11490Sstevel@tonic-gate show_space();
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate }
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate /*
11540Sstevel@tonic-gate * Payload protocol ID table. Add new ULP information and parsers
11550Sstevel@tonic-gate * here.
11560Sstevel@tonic-gate */
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate struct protoid_table {
11590Sstevel@tonic-gate int pid_num;
11600Sstevel@tonic-gate char *pid_short;
11610Sstevel@tonic-gate char *pid_long;
11620Sstevel@tonic-gate };
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate static struct protoid_table pid_sctp[] = {
11650Sstevel@tonic-gate 1, "IUA", "ISDN Q.921 User Adaption Layer",
11660Sstevel@tonic-gate 2, "M2UA", "SS7 MTP2 User Adaption Layer",
11670Sstevel@tonic-gate 3, "M3UA", "SS7 MTP3 User Adaption Layer",
11680Sstevel@tonic-gate 4, "SUA", "SS7 SCCP User Adaption Layer",
11690Sstevel@tonic-gate 5, "M2PA", "SS7 MTP2-User Peer-to-Peer Adaption Layer",
11700Sstevel@tonic-gate 6, "V5UA", "V5UA",
11710Sstevel@tonic-gate 0, NULL, "",
11720Sstevel@tonic-gate };
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate static void
interpret_protoid(int flags,uint32_t ppid,char * data,int dlen)11750Sstevel@tonic-gate interpret_protoid(int flags, uint32_t ppid, char *data, int dlen)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate struct protoid_table *p;
11780Sstevel@tonic-gate char pbuf[16];
11790Sstevel@tonic-gate
11800Sstevel@tonic-gate /*
11810Sstevel@tonic-gate * Branch to a ULP interpreter here, or continue on to
11820Sstevel@tonic-gate * the default parser, which just tries to display
11830Sstevel@tonic-gate * printable characters from the payload.
11840Sstevel@tonic-gate */
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate for (p = pid_sctp; p->pid_num; p++) {
11870Sstevel@tonic-gate if (ppid == p->pid_num) {
11880Sstevel@tonic-gate if (flags & F_SUM) {
11890Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE,
11900Sstevel@tonic-gate "D=%d S=%d %s %s", dport, sport,
11910Sstevel@tonic-gate p->pid_short, show_string(data, dlen, 20));
11920Sstevel@tonic-gate }
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate if (flags & F_DTAIL) {
11950Sstevel@tonic-gate (void) snprintf(pbuf, MAXLINE, "%s: ",
11960Sstevel@tonic-gate p->pid_short);
11970Sstevel@tonic-gate show_header(pbuf, p->pid_long, dlen);
11980Sstevel@tonic-gate show_space();
11990Sstevel@tonic-gate (void) snprintf(get_line(0, 0),
12000Sstevel@tonic-gate get_line_remain(), "\"%s\"",
12010Sstevel@tonic-gate show_string(data, dlen, 60));
12020Sstevel@tonic-gate show_trailer();
12030Sstevel@tonic-gate }
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate return;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate }
1209