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