1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <stdio.h> 30*0Sstevel@tonic-gate #include <stdlib.h> 31*0Sstevel@tonic-gate #include <sys/types.h> 32*0Sstevel@tonic-gate #include <sys/socket.h> 33*0Sstevel@tonic-gate #include <sys/sysmacros.h> 34*0Sstevel@tonic-gate #include <inet/common.h> 35*0Sstevel@tonic-gate #include <netinet/in.h> 36*0Sstevel@tonic-gate #include <netinet/sctp.h> 37*0Sstevel@tonic-gate #include <arpa/inet.h> 38*0Sstevel@tonic-gate #include <string.h> 39*0Sstevel@tonic-gate #include "snoop.h" 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate /* 42*0Sstevel@tonic-gate * Snoop interpreter for SCTP (rfc2960). 43*0Sstevel@tonic-gate * 44*0Sstevel@tonic-gate * To add support for an upper-layer protocol, modify either 45*0Sstevel@tonic-gate * the port-dispatcher in snoop_rport.c, or the protocol ID 46*0Sstevel@tonic-gate * dispatcher at the bottom of this file (or both). 47*0Sstevel@tonic-gate */ 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate static void interpret_protoid(int, uint32_t, char *, int); 50*0Sstevel@tonic-gate extern char *prot_prefix; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * This defines the length of internal, unbounded buffers. We set 54*0Sstevel@tonic-gate * this to be MAXLINE (the maximum verbose display line length) - 55*0Sstevel@tonic-gate * 64, which should be enough for all necessary descriptions. 64 56*0Sstevel@tonic-gate * bytes seems like a reasonably conservative estimate of the 57*0Sstevel@tonic-gate * maximum prefix length snoop may add to any text buffer it hands out. 58*0Sstevel@tonic-gate */ 59*0Sstevel@tonic-gate #define BUFLEN MAXLINE - 64 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate /* 62*0Sstevel@tonic-gate * Common structure to hold descriptions and parsers for all 63*0Sstevel@tonic-gate * chunks, parameters, and errors. Each parser should implement 64*0Sstevel@tonic-gate * this interface: 65*0Sstevel@tonic-gate * 66*0Sstevel@tonic-gate * void parse(int flags, uint8_t cflags, void *data, int datalen); 67*0Sstevel@tonic-gate * 68*0Sstevel@tonic-gate * Where flags is the snoop flags, cflags are the chunk flags, data 69*0Sstevel@tonic-gate * is the chunk or parameter data (not including the chunk or 70*0Sstevel@tonic-gate * parameter header), and datalen is the length of the chunk or 71*0Sstevel@tonic-gate * parameter data (again not including any headers). 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate typedef void parse_func_t(int, uint8_t, const void *, int); 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate typedef struct { 76*0Sstevel@tonic-gate uint16_t id; 77*0Sstevel@tonic-gate const char *sdesc; /* short description */ 78*0Sstevel@tonic-gate const char *vdesc; /* verbose description */ 79*0Sstevel@tonic-gate parse_func_t *parse; /* parser function */ 80*0Sstevel@tonic-gate } dispatch_t; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate static void interpret_params(const void *, int, char *, const dispatch_t *, 83*0Sstevel@tonic-gate int, int); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate /* 86*0Sstevel@tonic-gate * Chunk parsers 87*0Sstevel@tonic-gate */ 88*0Sstevel@tonic-gate static parse_func_t parse_abort_chunk, parse_data_chunk, parse_error_chunk, 89*0Sstevel@tonic-gate parse_init_chunk, parse_opaque_chunk, parse_sack_chunk, 90*0Sstevel@tonic-gate parse_shutdone_chunk, parse_shutdown_chunk, parse_asconf_chunk, 91*0Sstevel@tonic-gate parse_ftsn_chunk; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate /* 95*0Sstevel@tonic-gate * Chunk parser dispatch table. There are few enough chunks defined 96*0Sstevel@tonic-gate * in the core protocol, and they are sequential, so the chunk code 97*0Sstevel@tonic-gate * can be used as the index into this array for the common case. 98*0Sstevel@tonic-gate * It is still necessary to check that the code and index match, 99*0Sstevel@tonic-gate * since optional extensions will not follow sequentially the 100*0Sstevel@tonic-gate * core chunks. 101*0Sstevel@tonic-gate */ 102*0Sstevel@tonic-gate static const dispatch_t chunk_dispatch_table[] = { 103*0Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */ 104*0Sstevel@tonic-gate { CHUNK_DATA, "Data", "Data Chunk", 105*0Sstevel@tonic-gate parse_data_chunk }, 106*0Sstevel@tonic-gate { CHUNK_INIT, "Init", "Init Chunk", 107*0Sstevel@tonic-gate parse_init_chunk }, 108*0Sstevel@tonic-gate { CHUNK_INIT_ACK, "Init ACK", "Init ACK Chunk", 109*0Sstevel@tonic-gate parse_init_chunk }, 110*0Sstevel@tonic-gate { CHUNK_SACK, "SACK", "SACK Chunk", 111*0Sstevel@tonic-gate parse_sack_chunk }, 112*0Sstevel@tonic-gate { CHUNK_HEARTBEAT, "Heartbeat", "Heartbeat Chunk", 113*0Sstevel@tonic-gate parse_opaque_chunk }, 114*0Sstevel@tonic-gate { CHUNK_HEARTBEAT_ACK, "Heartbeat ACK", "Heartbeat ACK Chunk", 115*0Sstevel@tonic-gate parse_opaque_chunk }, 116*0Sstevel@tonic-gate { CHUNK_ABORT, "Abort", "Abort Chunk", 117*0Sstevel@tonic-gate parse_abort_chunk }, 118*0Sstevel@tonic-gate { CHUNK_SHUTDOWN, "Shutdown", "Shutdown Chunk", 119*0Sstevel@tonic-gate parse_shutdown_chunk }, 120*0Sstevel@tonic-gate { CHUNK_SHUTDOWN_ACK, "Shutdown ACK", "Shutdown ACK Chunk", 121*0Sstevel@tonic-gate NULL }, 122*0Sstevel@tonic-gate { CHUNK_ERROR, "Err", "Error Chunk", 123*0Sstevel@tonic-gate parse_error_chunk }, 124*0Sstevel@tonic-gate { CHUNK_COOKIE, "Cookie", "Cookie Chunk", 125*0Sstevel@tonic-gate parse_opaque_chunk }, 126*0Sstevel@tonic-gate { CHUNK_COOKIE_ACK, "Cookie ACK", "Cookie ACK Chunk", 127*0Sstevel@tonic-gate parse_opaque_chunk }, 128*0Sstevel@tonic-gate { CHUNK_ECNE, "ECN Echo", "ECN Echo Chunk", 129*0Sstevel@tonic-gate parse_opaque_chunk }, 130*0Sstevel@tonic-gate { CHUNK_CWR, "CWR", "CWR Chunk", 131*0Sstevel@tonic-gate parse_opaque_chunk }, 132*0Sstevel@tonic-gate { CHUNK_SHUTDOWN_COMPLETE, "Shutdown Done", "Shutdown Done", 133*0Sstevel@tonic-gate parse_shutdone_chunk }, 134*0Sstevel@tonic-gate { CHUNK_FORWARD_TSN, "FORWARD TSN", "Forward TSN Chunk", 135*0Sstevel@tonic-gate parse_ftsn_chunk }, 136*0Sstevel@tonic-gate { CHUNK_ASCONF_ACK, "ASCONF ACK", "ASCONF ACK Chunk", 137*0Sstevel@tonic-gate parse_asconf_chunk }, 138*0Sstevel@tonic-gate { CHUNK_ASCONF, "ASCONF", "ASCONF Chunk", 139*0Sstevel@tonic-gate parse_asconf_chunk } 140*0Sstevel@tonic-gate }; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate * Parameter Parsers 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate static parse_func_t parse_encap_param, parse_int32_param, parse_ip4_param, 146*0Sstevel@tonic-gate parse_ip6_param, parse_opaque_param, parse_suppaddr_param, 147*0Sstevel@tonic-gate parse_unrec_chunk, parse_addip_param, parse_asconferr_param, 148*0Sstevel@tonic-gate parse_asconfok_param, parse_addiperr_param; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate /* 151*0Sstevel@tonic-gate * Parameter parser dispatch table. The summary description is not 152*0Sstevel@tonic-gate * used here. Strictly speaking, parameter types are defined within 153*0Sstevel@tonic-gate * the context of a chunk type. However, thus far the IETF WG has 154*0Sstevel@tonic-gate * agreed to follow the convention that parameter types are globally 155*0Sstevel@tonic-gate * unique (and why not, with a 16-bit namespace). However, if this 156*0Sstevel@tonic-gate * ever changes, there will need to be different parameter dispatch 157*0Sstevel@tonic-gate * tables for each chunk type. 158*0Sstevel@tonic-gate */ 159*0Sstevel@tonic-gate static const dispatch_t parm_dispatch_table[] = { 160*0Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */ 161*0Sstevel@tonic-gate { PARM_UNKNOWN, "", "Unknown Parameter", 162*0Sstevel@tonic-gate parse_opaque_param }, 163*0Sstevel@tonic-gate { PARM_HBINFO, "", "Heartbeat Info", 164*0Sstevel@tonic-gate parse_opaque_param }, 165*0Sstevel@tonic-gate { PARM_ADDR4, "", "IPv4 Address", 166*0Sstevel@tonic-gate parse_ip4_param }, 167*0Sstevel@tonic-gate { PARM_ADDR6, "", "IPv6 Address", 168*0Sstevel@tonic-gate parse_ip6_param }, 169*0Sstevel@tonic-gate { PARM_COOKIE, "", "Cookie", 170*0Sstevel@tonic-gate parse_opaque_param }, 171*0Sstevel@tonic-gate { PARM_UNRECOGNIZED, "", "Unrecognized Param", 172*0Sstevel@tonic-gate parse_encap_param }, 173*0Sstevel@tonic-gate { PARM_COOKIE_PRESERVE, "", "Cookie Preservative", 174*0Sstevel@tonic-gate parse_opaque_param }, 175*0Sstevel@tonic-gate { 10, "", "Reserved for ECN", 176*0Sstevel@tonic-gate parse_opaque_param }, 177*0Sstevel@tonic-gate { PARM_ADDR_HOST_NAME, "", "Host Name Parameter", 178*0Sstevel@tonic-gate parse_opaque_param }, 179*0Sstevel@tonic-gate { PARM_SUPP_ADDRS, "", "Supported Addresses", 180*0Sstevel@tonic-gate parse_suppaddr_param }, 181*0Sstevel@tonic-gate { PARM_ECN_CAPABLE, "", "ECN Capable", 182*0Sstevel@tonic-gate parse_opaque_param }, 183*0Sstevel@tonic-gate { PARM_ADD_IP, "", "Add IP", 184*0Sstevel@tonic-gate parse_addip_param }, 185*0Sstevel@tonic-gate { PARM_DEL_IP, "", "Del IP", 186*0Sstevel@tonic-gate parse_addip_param }, 187*0Sstevel@tonic-gate { PARM_ASCONF_ERROR, "", "ASCONF Error Ind", 188*0Sstevel@tonic-gate parse_asconferr_param }, 189*0Sstevel@tonic-gate { PARM_PRIMARY_ADDR, "", "Set Primary Address", 190*0Sstevel@tonic-gate parse_addip_param }, 191*0Sstevel@tonic-gate { PARM_FORWARD_TSN, "", "Forward TSN", 192*0Sstevel@tonic-gate NULL }, 193*0Sstevel@tonic-gate { PARM_ASCONF_SUCCESS, "", "ASCONF Success Ind", 194*0Sstevel@tonic-gate parse_asconfok_param } 195*0Sstevel@tonic-gate }; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate /* 198*0Sstevel@tonic-gate * Errors have the same wire format at parameters. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate static const dispatch_t err_dispatch_table[] = { 201*0Sstevel@tonic-gate /* code F_SUM desc F_DTAIL desc parser function */ 202*0Sstevel@tonic-gate { SCTP_ERR_UNKNOWN, "", "Unknown Error", 203*0Sstevel@tonic-gate parse_opaque_param }, 204*0Sstevel@tonic-gate { SCTP_ERR_BAD_SID, "", "Invalid Stream ID", 205*0Sstevel@tonic-gate parse_opaque_param }, 206*0Sstevel@tonic-gate { SCTP_ERR_MISSING_PARM, "", "Missing Parameter", 207*0Sstevel@tonic-gate parse_opaque_param }, 208*0Sstevel@tonic-gate { SCTP_ERR_STALE_COOKIE, "", "Stale Cookie", 209*0Sstevel@tonic-gate parse_int32_param }, 210*0Sstevel@tonic-gate { SCTP_ERR_NO_RESOURCES, "", "Out Of Resources", 211*0Sstevel@tonic-gate parse_opaque_param }, 212*0Sstevel@tonic-gate { SCTP_ERR_BAD_ADDR, "", "Unresolvable Address", 213*0Sstevel@tonic-gate parse_opaque_param }, 214*0Sstevel@tonic-gate { SCTP_ERR_UNREC_CHUNK, "", "Unrecognized Chunk", 215*0Sstevel@tonic-gate parse_unrec_chunk }, 216*0Sstevel@tonic-gate { SCTP_ERR_BAD_MANDPARM, "", "Bad Mandatory Parameter", 217*0Sstevel@tonic-gate parse_opaque_param }, 218*0Sstevel@tonic-gate { SCTP_ERR_UNREC_PARM, "", "Unrecognized Parameter", 219*0Sstevel@tonic-gate parse_opaque_param }, 220*0Sstevel@tonic-gate { SCTP_ERR_NO_USR_DATA, "", "No User Data", 221*0Sstevel@tonic-gate parse_int32_param }, 222*0Sstevel@tonic-gate { SCTP_ERR_COOKIE_SHUT, "", "Cookie During Shutdown", 223*0Sstevel@tonic-gate parse_opaque_param }, 224*0Sstevel@tonic-gate { SCTP_ERR_DELETE_LASTADDR, "", "Delete Last Remaining Address", 225*0Sstevel@tonic-gate parse_addiperr_param }, 226*0Sstevel@tonic-gate { SCTP_ERR_RESOURCE_SHORTAGE, "", "Resource Shortage", 227*0Sstevel@tonic-gate parse_addiperr_param }, 228*0Sstevel@tonic-gate { SCTP_ERR_DELETE_SRCADDR, "", "Delete Source IP Address", 229*0Sstevel@tonic-gate parse_addiperr_param }, 230*0Sstevel@tonic-gate { SCTP_ERR_AUTH_ERR, "", "Not authorized", 231*0Sstevel@tonic-gate parse_addiperr_param } 232*0Sstevel@tonic-gate }; 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * These are global because the data chunk parser needs them to dispatch 236*0Sstevel@tonic-gate * to ULPs. The alternative is to add source and dest port arguments 237*0Sstevel@tonic-gate * to every parser, which seems even messier (since *only* the data 238*0Sstevel@tonic-gate * chunk parser needs it)... 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate static in_port_t sport, dport; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* Summary line miscellany */ 243*0Sstevel@tonic-gate static int sumlen; 244*0Sstevel@tonic-gate static char scratch[MAXLINE]; 245*0Sstevel@tonic-gate static char *sumline; 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate #define SUMAPPEND(fmt) \ 248*0Sstevel@tonic-gate sumlen -= snprintf fmt; \ 249*0Sstevel@tonic-gate (void) strlcat(sumline, scratch, sumlen) 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate #define DUMPHEX_MAX 16 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate static const dispatch_t * 254*0Sstevel@tonic-gate lookup_dispatch(int id, const dispatch_t *tbl, int tblsz) 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate int i; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * Try fast lookup first. The common chunks defined in RFC2960 260*0Sstevel@tonic-gate * will have indices aligned with their IDs, so this works for 261*0Sstevel@tonic-gate * the common case. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate if (id < (tblsz - 1)) { 264*0Sstevel@tonic-gate if (id == tbl[id].id) { 265*0Sstevel@tonic-gate return (tbl + id); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate /* 270*0Sstevel@tonic-gate * Nope - probably an extension. Search the whole table, 271*0Sstevel@tonic-gate * starting from the end, since extensions are at the end. 272*0Sstevel@tonic-gate */ 273*0Sstevel@tonic-gate for (i = tblsz - 1; i >= 0; i--) { 274*0Sstevel@tonic-gate if (id == tbl[i].id) { 275*0Sstevel@tonic-gate return (tbl + i); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate return (NULL); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * Dumps no more than the first DUMPHEX_MAX bytes in hex. If 284*0Sstevel@tonic-gate * the user wants more, they can use the -x option to snoop. 285*0Sstevel@tonic-gate */ 286*0Sstevel@tonic-gate static void 287*0Sstevel@tonic-gate dumphex(const uchar_t *payload, int payload_len, char *msg) 288*0Sstevel@tonic-gate { 289*0Sstevel@tonic-gate int index; 290*0Sstevel@tonic-gate int end; 291*0Sstevel@tonic-gate char buf[BUFLEN]; 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate if (payload_len == 0) { 294*0Sstevel@tonic-gate return; 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate end = payload_len > DUMPHEX_MAX ? DUMPHEX_MAX : payload_len; 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate for (index = 0; index < end; index++) { 300*0Sstevel@tonic-gate (void) snprintf(&buf[index * 3], 4, " %.2x", payload[index]); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate if (payload_len > DUMPHEX_MAX) { 304*0Sstevel@tonic-gate (void) strlcat(buf, " ...", BUFLEN); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), BUFLEN, msg, buf); 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * Present perscribed action for unknowns according to rfc2960. Works 312*0Sstevel@tonic-gate * for chunks and parameters as well if the parameter type is 313*0Sstevel@tonic-gate * shifted 8 bits right. 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate static const char * 316*0Sstevel@tonic-gate get_action_desc(uint8_t id) 317*0Sstevel@tonic-gate { 318*0Sstevel@tonic-gate if ((id & 0xc0) == 0xc0) { 319*0Sstevel@tonic-gate return (": skip on unknown, return error"); 320*0Sstevel@tonic-gate } else if ((id & 0x80) == 0x80) { 321*0Sstevel@tonic-gate return (": skip on unknown, no error"); 322*0Sstevel@tonic-gate } else if ((id & 0x40) == 0x40) { 323*0Sstevel@tonic-gate return (": stop on unknown, return error"); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* Top two bits are clear */ 327*0Sstevel@tonic-gate return (": stop on unknown, no error"); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* ARGSUSED */ 331*0Sstevel@tonic-gate static void 332*0Sstevel@tonic-gate parse_asconfok_param(int flags, uint8_t notused, const void *data, int dlen) 333*0Sstevel@tonic-gate { 334*0Sstevel@tonic-gate uint32_t *cid; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if (dlen < sizeof (*cid)) { 337*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 338*0Sstevel@tonic-gate " ==> Incomplete ASCONF Success Ind parameter"); 339*0Sstevel@tonic-gate return; 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate cid = (uint32_t *)data; 342*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u", 343*0Sstevel@tonic-gate ntohl(*cid)); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* ARGSUSED */ 347*0Sstevel@tonic-gate static void 348*0Sstevel@tonic-gate parse_asconferr_param(int flags, uint8_t notused, const void *data, int dlen) 349*0Sstevel@tonic-gate { 350*0Sstevel@tonic-gate uint32_t *cid; 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate if (dlen < sizeof (*cid)) { 353*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 354*0Sstevel@tonic-gate " ==> Incomplete ASCONF Error Ind parameter"); 355*0Sstevel@tonic-gate return; 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate cid = (uint32_t *)data; 358*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u", 359*0Sstevel@tonic-gate ntohl(*cid)); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate interpret_params(cid + 1, dlen - sizeof (*cid), "Error", 362*0Sstevel@tonic-gate err_dispatch_table, A_CNT(err_dispatch_table), flags); 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate /* ARGSUSED */ 366*0Sstevel@tonic-gate static void 367*0Sstevel@tonic-gate parse_addiperr_param(int flags, uint8_t notused, const void *data, int dlen) 368*0Sstevel@tonic-gate { 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate interpret_params(data, dlen, "Parameter", 371*0Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags); 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* ARGSUSED */ 375*0Sstevel@tonic-gate static void 376*0Sstevel@tonic-gate parse_addip_param(int flags, uint8_t notused, const void *data, int dlen) 377*0Sstevel@tonic-gate { 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate uint32_t *cid; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if (dlen < sizeof (*cid)) { 382*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 383*0Sstevel@tonic-gate " ==> Incomplete ASCONF Error Ind parameter"); 384*0Sstevel@tonic-gate return; 385*0Sstevel@tonic-gate } 386*0Sstevel@tonic-gate cid = (uint32_t *)data; 387*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " ASCONF CID = %u", 388*0Sstevel@tonic-gate ntohl(*cid)); 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate interpret_params(cid + 1, dlen - sizeof (*cid), "Parameter", 391*0Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags); 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate /* ARGSUSED */ 395*0Sstevel@tonic-gate static void 396*0Sstevel@tonic-gate parse_ip4_param(int flags, uint8_t notused, const void *data, int datalen) 397*0Sstevel@tonic-gate { 398*0Sstevel@tonic-gate char abuf[INET_ADDRSTRLEN]; 399*0Sstevel@tonic-gate char *ap; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate if (datalen < sizeof (in_addr_t)) { 402*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 403*0Sstevel@tonic-gate " ==> Incomplete IPv4 Addr parameter"); 404*0Sstevel@tonic-gate return; 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate ap = (char *)inet_ntop(AF_INET, data, abuf, INET_ADDRSTRLEN); 408*0Sstevel@tonic-gate if (ap == NULL) { 409*0Sstevel@tonic-gate ap = "<Bad Address>"; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " Addr = %s", ap); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* ARGSUSED */ 416*0Sstevel@tonic-gate static void 417*0Sstevel@tonic-gate parse_ip6_param(int flags, uint8_t notused, const void *data, int datalen) 418*0Sstevel@tonic-gate { 419*0Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 420*0Sstevel@tonic-gate char *ap; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (datalen < sizeof (in6_addr_t)) { 423*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 424*0Sstevel@tonic-gate " ==> Incomplete IPv6 Addr parameter"); 425*0Sstevel@tonic-gate return; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate ap = (char *)inet_ntop(AF_INET6, data, abuf, INET6_ADDRSTRLEN); 429*0Sstevel@tonic-gate if (ap == NULL) { 430*0Sstevel@tonic-gate ap = "<Bad Address>"; 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " Addr = %s", ap); 434*0Sstevel@tonic-gate } 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate /* ARGSUSED */ 437*0Sstevel@tonic-gate static void 438*0Sstevel@tonic-gate parse_int32_param(int flags, uint8_t notused, const void *data, int datalen) 439*0Sstevel@tonic-gate { 440*0Sstevel@tonic-gate if (datalen < 4) { 441*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 442*0Sstevel@tonic-gate " ==> Incomplete INT32 parameter"); 443*0Sstevel@tonic-gate return; 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " INT32 = %u", 446*0Sstevel@tonic-gate ntohl(*(uint32_t *)data)); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* ARGSUSED */ 450*0Sstevel@tonic-gate static void 451*0Sstevel@tonic-gate parse_suppaddr_param(int flags, uint8_t notused, const void *data, int dlen) 452*0Sstevel@tonic-gate { 453*0Sstevel@tonic-gate const uint16_t *type; 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate if (dlen < 2) { 456*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 457*0Sstevel@tonic-gate "==> Incomplete Supported Addr parameter"); 458*0Sstevel@tonic-gate return; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate type = data; 462*0Sstevel@tonic-gate while (dlen > 0) { 463*0Sstevel@tonic-gate switch (ntohs(*type)) { 464*0Sstevel@tonic-gate case PARM_ADDR4: 465*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 466*0Sstevel@tonic-gate " IPv4"); 467*0Sstevel@tonic-gate break; 468*0Sstevel@tonic-gate case PARM_ADDR6: 469*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 470*0Sstevel@tonic-gate " IPv6"); 471*0Sstevel@tonic-gate break; 472*0Sstevel@tonic-gate case PARM_ADDR_HOST_NAME: 473*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 474*0Sstevel@tonic-gate " Host Name"); 475*0Sstevel@tonic-gate break; 476*0Sstevel@tonic-gate default: 477*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 478*0Sstevel@tonic-gate "Unknown Type (%hu)", ntohs(*type)); 479*0Sstevel@tonic-gate break; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate dlen -= sizeof (*type); 482*0Sstevel@tonic-gate type++; 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate /*ARGSUSED*/ 487*0Sstevel@tonic-gate static void 488*0Sstevel@tonic-gate parse_encap_param(int flags, uint8_t notused, const void *data, int dlen) 489*0Sstevel@tonic-gate { 490*0Sstevel@tonic-gate if (dlen < sizeof (sctp_parm_hdr_t)) { 491*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 492*0Sstevel@tonic-gate "==> Incomplete Parameter"); 493*0Sstevel@tonic-gate return; 494*0Sstevel@tonic-gate } 495*0Sstevel@tonic-gate 496*0Sstevel@tonic-gate interpret_params(data, dlen, "Parameter", 497*0Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags); 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate /* ARGSUSED */ 501*0Sstevel@tonic-gate static void 502*0Sstevel@tonic-gate parse_unrec_chunk(int flags, uint8_t cflags, const void *data, int datalen) 503*0Sstevel@tonic-gate { 504*0Sstevel@tonic-gate const sctp_chunk_hdr_t *cp = data; 505*0Sstevel@tonic-gate const dispatch_t *dp; 506*0Sstevel@tonic-gate const char *actstr; 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate if (datalen < sizeof (*cp)) { 509*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 510*0Sstevel@tonic-gate "==> Incomplete Unrecognized Chunk Error"); 511*0Sstevel@tonic-gate return; 512*0Sstevel@tonic-gate } 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate /* Maybe snoop knows about this chunk? */ 515*0Sstevel@tonic-gate dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table, 516*0Sstevel@tonic-gate A_CNT(chunk_dispatch_table)); 517*0Sstevel@tonic-gate if (dp != NULL) { 518*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 519*0Sstevel@tonic-gate " Chunk Type = %u (%s)", cp->sch_id, dp->vdesc); 520*0Sstevel@tonic-gate } else { 521*0Sstevel@tonic-gate actstr = get_action_desc(cp->sch_id); 522*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 523*0Sstevel@tonic-gate " Chunk Type = %u%s", cp->sch_id, actstr); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate /* 528*0Sstevel@tonic-gate * Same as parse_opaque_chunk except for the indentation. 529*0Sstevel@tonic-gate */ 530*0Sstevel@tonic-gate /* ARGSUSED */ 531*0Sstevel@tonic-gate static void 532*0Sstevel@tonic-gate parse_opaque_param(int flags, uint8_t cflags, const void *data, int datalen) 533*0Sstevel@tonic-gate { 534*0Sstevel@tonic-gate dumphex(data, datalen, " Data = %s"); 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * Loops through all parameters (or errors) until it has read 539*0Sstevel@tonic-gate * datalen bytes of information, finding a parser for each. 540*0Sstevel@tonic-gate * The tbl argument allows the caller to specify which dispatch 541*0Sstevel@tonic-gate * table to use, making this function useful for both parameters 542*0Sstevel@tonic-gate * and errors. The type argument is used to denote whether this 543*0Sstevel@tonic-gate * is an error or parameter in detailed mode. 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate static void 546*0Sstevel@tonic-gate interpret_params(const void *data, int datalen, char *type, 547*0Sstevel@tonic-gate const dispatch_t *tbl, int tbl_size, int flags) 548*0Sstevel@tonic-gate { 549*0Sstevel@tonic-gate const sctp_parm_hdr_t *hdr = data; 550*0Sstevel@tonic-gate uint16_t plen; 551*0Sstevel@tonic-gate uint16_t ptype; 552*0Sstevel@tonic-gate const char *desc; 553*0Sstevel@tonic-gate parse_func_t *parse; 554*0Sstevel@tonic-gate int pad; 555*0Sstevel@tonic-gate const dispatch_t *dp; 556*0Sstevel@tonic-gate const char *actstr; 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate for (;;) { 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * Adjust for padding: if the address isn't aligned, there 561*0Sstevel@tonic-gate * should be some padding. So skip over the padding and 562*0Sstevel@tonic-gate * adjust hdr accordingly. RFC2960 mandates that all 563*0Sstevel@tonic-gate * parameters must be 32-bit aligned WRT the enclosing chunk, 564*0Sstevel@tonic-gate * which ensures that this parameter header will 565*0Sstevel@tonic-gate * be 32-bit aligned in memory. We must, of course, bounds 566*0Sstevel@tonic-gate * check fraglen before actually trying to use hdr, in 567*0Sstevel@tonic-gate * case the packet has been mangled or is the product 568*0Sstevel@tonic-gate * of a buggy implementation. 569*0Sstevel@tonic-gate */ 570*0Sstevel@tonic-gate if ((pad = (uintptr_t)hdr % SCTP_ALIGN) != 0) { 571*0Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 572*0Sstevel@tonic-gate datalen -= pad; 573*0Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 574*0Sstevel@tonic-gate hdr = (sctp_parm_hdr_t *)((char *)hdr + pad); 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate /* Need to compare against 0 1st, since sizeof is unsigned */ 578*0Sstevel@tonic-gate if (datalen < 0 || datalen < sizeof (*hdr)) { 579*0Sstevel@tonic-gate if (datalen > 0) { 580*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 581*0Sstevel@tonic-gate get_line_remain(), 582*0Sstevel@tonic-gate "==> Extra data after last parameter"); 583*0Sstevel@tonic-gate } 584*0Sstevel@tonic-gate return; 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate plen = ntohs(hdr->sph_len); 587*0Sstevel@tonic-gate if (datalen < plen || plen < sizeof (*hdr)) { 588*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 589*0Sstevel@tonic-gate " ==> Incomplete %s", type); 590*0Sstevel@tonic-gate return; 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate /* Get description and parser */ 594*0Sstevel@tonic-gate ptype = ntohs(hdr->sph_type); 595*0Sstevel@tonic-gate desc = "Unknown Parameter Type"; 596*0Sstevel@tonic-gate parse = parse_opaque_param; 597*0Sstevel@tonic-gate dp = lookup_dispatch(ptype, tbl, tbl_size); 598*0Sstevel@tonic-gate if (dp != NULL) { 599*0Sstevel@tonic-gate desc = dp->vdesc; 600*0Sstevel@tonic-gate parse = dp->parse; 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate show_space(); 604*0Sstevel@tonic-gate if (dp != NULL) { 605*0Sstevel@tonic-gate actstr = ""; 606*0Sstevel@tonic-gate } else { 607*0Sstevel@tonic-gate actstr = get_action_desc((uint8_t)(ptype >> 8)); 608*0Sstevel@tonic-gate } 609*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 610*0Sstevel@tonic-gate " ------- SCTP %s Type = %s (%u%s)", type, desc, ptype, 611*0Sstevel@tonic-gate actstr); 612*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 613*0Sstevel@tonic-gate " Data length = %hu", plen - sizeof (*hdr)); 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate if (parse != NULL) { 616*0Sstevel@tonic-gate parse(flags, 0, (char *)(hdr + 1), 617*0Sstevel@tonic-gate plen - sizeof (*hdr)); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate datalen -= plen; 620*0Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 621*0Sstevel@tonic-gate hdr = (sctp_parm_hdr_t *)((char *)hdr + plen); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* ARGSUSED */ 626*0Sstevel@tonic-gate static void 627*0Sstevel@tonic-gate parse_ftsn_chunk(int flags, uint8_t cflags, const void *data, int datalen) 628*0Sstevel@tonic-gate { 629*0Sstevel@tonic-gate uint32_t *ftsn; 630*0Sstevel@tonic-gate ftsn_entry_t *ftsn_entry; 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate if (datalen < (sizeof (*ftsn) + sizeof (*ftsn_entry))) { 633*0Sstevel@tonic-gate if (flags & F_DTAIL) { 634*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 635*0Sstevel@tonic-gate "==> Incomplete FORWARD-TSN chunk"); 636*0Sstevel@tonic-gate } 637*0Sstevel@tonic-gate return; 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate ftsn = (uint32_t *)data; 641*0Sstevel@tonic-gate if (flags & F_SUM) { 642*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "CTSN %x ", ntohl(*ftsn))); 643*0Sstevel@tonic-gate return; 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Cum TSN= %x", 646*0Sstevel@tonic-gate ntohl(*ftsn)); 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate datalen -= sizeof (*ftsn); 649*0Sstevel@tonic-gate ftsn_entry = (ftsn_entry_t *)(ftsn + 1); 650*0Sstevel@tonic-gate while (datalen >= sizeof (*ftsn_entry)) { 651*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 652*0Sstevel@tonic-gate "SID = %u : SSN = %u", ntohs(ftsn_entry->ftsn_sid), 653*0Sstevel@tonic-gate ntohs(ftsn_entry->ftsn_ssn)); 654*0Sstevel@tonic-gate datalen -= sizeof (*ftsn_entry); 655*0Sstevel@tonic-gate ftsn_entry++; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate /* ARGSUSED */ 660*0Sstevel@tonic-gate static void 661*0Sstevel@tonic-gate parse_asconf_chunk(int flags, uint8_t cflags, const void *data, int datalen) 662*0Sstevel@tonic-gate { 663*0Sstevel@tonic-gate uint32_t *sn; 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate if (datalen < sizeof (*sn)) { 666*0Sstevel@tonic-gate if (flags & F_DTAIL) { 667*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 668*0Sstevel@tonic-gate "==> Incomplete ASCONF chunk"); 669*0Sstevel@tonic-gate } 670*0Sstevel@tonic-gate return; 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate sn = (uint32_t *)data; 674*0Sstevel@tonic-gate if (flags & F_SUM) { 675*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "sn %x ", ntohl(*sn))); 676*0Sstevel@tonic-gate return; 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Serial Number= %x", 679*0Sstevel@tonic-gate ntohl(*sn)); 680*0Sstevel@tonic-gate interpret_params(sn + 1, datalen - sizeof (*sn), "Parameter", 681*0Sstevel@tonic-gate parm_dispatch_table, A_CNT(parm_dispatch_table), flags); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate static void 685*0Sstevel@tonic-gate parse_init_chunk(int flags, uint8_t cflags, const void *data, int datalen) 686*0Sstevel@tonic-gate { 687*0Sstevel@tonic-gate const sctp_init_chunk_t *icp = data; 688*0Sstevel@tonic-gate 689*0Sstevel@tonic-gate if (datalen < sizeof (*icp)) { 690*0Sstevel@tonic-gate if (flags & F_DTAIL) { 691*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 692*0Sstevel@tonic-gate "==> Incomplete INIT chunk"); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate return; 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if (flags & F_SUM) { 698*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "tsn %x str %hu/%hu win %u ", 699*0Sstevel@tonic-gate ntohl(icp->sic_inittsn), ntohs(icp->sic_outstr), 700*0Sstevel@tonic-gate ntohs(icp->sic_instr), ntohl(icp->sic_a_rwnd))); 701*0Sstevel@tonic-gate return; 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "Flags = 0x%.2x", 705*0Sstevel@tonic-gate cflags); 706*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 707*0Sstevel@tonic-gate "Initiate tag = 0x%.8x", ntohl(icp->sic_inittag)); 708*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 709*0Sstevel@tonic-gate "Advertised receiver window credit = %u", ntohl(icp->sic_a_rwnd)); 710*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 711*0Sstevel@tonic-gate "Outbound streams = %hu", ntohs(icp->sic_outstr)); 712*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 713*0Sstevel@tonic-gate "Inbound streams = %hu", ntohs(icp->sic_instr)); 714*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 715*0Sstevel@tonic-gate "Initial TSN = 0x%.8x", ntohl(icp->sic_inittsn)); 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate if (datalen > sizeof (*icp)) { 718*0Sstevel@tonic-gate interpret_params(icp + 1, datalen - sizeof (*icp), 719*0Sstevel@tonic-gate "Parameter", parm_dispatch_table, 720*0Sstevel@tonic-gate A_CNT(parm_dispatch_table), flags); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate } 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate static void 725*0Sstevel@tonic-gate parse_data_chunk(int flags, uint8_t cflags, const void *data, int datalen) 726*0Sstevel@tonic-gate { 727*0Sstevel@tonic-gate const sctp_data_chunk_t *dcp = data; 728*0Sstevel@tonic-gate char *payload; 729*0Sstevel@tonic-gate uint32_t ppid; 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if (datalen < sizeof (*dcp)) { 732*0Sstevel@tonic-gate if (flags & F_DTAIL) { 733*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 734*0Sstevel@tonic-gate "==> Incomplete DATA chunk %d (%d)", datalen, 735*0Sstevel@tonic-gate sizeof (*dcp)); 736*0Sstevel@tonic-gate } 737*0Sstevel@tonic-gate return; 738*0Sstevel@tonic-gate } 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate ppid = ntohl(dcp->sdc_payload_id); 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if (flags & F_DTAIL) { 743*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 744*0Sstevel@tonic-gate "flags = 0x%.2x", cflags); 745*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 746*0Sstevel@tonic-gate getflag(cflags, SCTP_DATA_UBIT, "unordered", "ordered")); 747*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 748*0Sstevel@tonic-gate getflag(cflags, SCTP_DATA_BBIT, 749*0Sstevel@tonic-gate "beginning", "(beginning unset)")); 750*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 751*0Sstevel@tonic-gate getflag(cflags, SCTP_DATA_EBIT, "end", "(end unset)")); 752*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 753*0Sstevel@tonic-gate "TSN = 0x%.8x", ntohl(dcp->sdc_tsn)); 754*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 755*0Sstevel@tonic-gate "Stream ID = %hu", ntohs(dcp->sdc_sid)); 756*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 757*0Sstevel@tonic-gate "Stream Sequence Number = %hu", ntohs(dcp->sdc_ssn)); 758*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 759*0Sstevel@tonic-gate "Payload Protocol ID = 0x%.8x", ppid); 760*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 761*0Sstevel@tonic-gate "Data Length = %d", datalen - sizeof (*dcp)); 762*0Sstevel@tonic-gate show_space(); 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate if (flags & F_SUM) { 765*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "tsn %x str %hu/%hu ppid %x ", 766*0Sstevel@tonic-gate ntohl(dcp->sdc_tsn), ntohs(dcp->sdc_sid), 767*0Sstevel@tonic-gate ntohs(dcp->sdc_ssn), ppid)); 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate /* 771*0Sstevel@tonic-gate * Go to the next protocol layer, but not if we are in 772*0Sstevel@tonic-gate * summary mode only. In summary mode, each ULP parse would 773*0Sstevel@tonic-gate * create a new line, and if there were several data chunks 774*0Sstevel@tonic-gate * bundled together in the packet, this would confuse snoop's 775*0Sstevel@tonic-gate * packet numbering and timestamping. 776*0Sstevel@tonic-gate * 777*0Sstevel@tonic-gate * SCTP carries two ways to determine an ULP: ports and the 778*0Sstevel@tonic-gate * payload protocol identifier (ppid). Since ports are the 779*0Sstevel@tonic-gate * better entrenched convention, we first try interpret_reserved(). 780*0Sstevel@tonic-gate * If that fails to find a parser, we try by the PPID. 781*0Sstevel@tonic-gate */ 782*0Sstevel@tonic-gate if (!(flags & F_ALLSUM) && !(flags & F_DTAIL)) { 783*0Sstevel@tonic-gate return; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate payload = (char *)(dcp + 1); 787*0Sstevel@tonic-gate if (!interpret_reserved(flags, IPPROTO_SCTP, sport, dport, payload, 788*0Sstevel@tonic-gate datalen - sizeof (*dcp)) && ppid != 0) { 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate interpret_protoid(flags, ppid, payload, 791*0Sstevel@tonic-gate datalen - sizeof (*dcp)); 792*0Sstevel@tonic-gate } 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate /* 795*0Sstevel@tonic-gate * Reset the protocol prefix, since it may have been changed 796*0Sstevel@tonic-gate * by a ULP interpreter. 797*0Sstevel@tonic-gate */ 798*0Sstevel@tonic-gate prot_prefix = "SCTP: "; 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate 801*0Sstevel@tonic-gate /* ARGSUSED */ 802*0Sstevel@tonic-gate static void 803*0Sstevel@tonic-gate parse_sack_chunk(int flags, uint8_t cflags, const void *data, int datalen) 804*0Sstevel@tonic-gate { 805*0Sstevel@tonic-gate const sctp_sack_chunk_t *scp = data; 806*0Sstevel@tonic-gate uint16_t numfrags, numdups; 807*0Sstevel@tonic-gate sctp_sack_frag_t *frag; 808*0Sstevel@tonic-gate int i; 809*0Sstevel@tonic-gate uint32_t *tsn; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate if (datalen < sizeof (*scp)) { 812*0Sstevel@tonic-gate if (flags & F_DTAIL) { 813*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 814*0Sstevel@tonic-gate "==> Incomplete SACK chunk"); 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate return; 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate if (flags & F_DTAIL) { 820*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 821*0Sstevel@tonic-gate "Cumulative TSN ACK = 0x%.8x", ntohl(scp->ssc_cumtsn)); 822*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 823*0Sstevel@tonic-gate "Advertised Receiver Window Credit = %u", 824*0Sstevel@tonic-gate ntohl(scp->ssc_a_rwnd)); 825*0Sstevel@tonic-gate numfrags = ntohs(scp->ssc_numfrags); 826*0Sstevel@tonic-gate numdups = ntohs(scp->ssc_numdups); 827*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 828*0Sstevel@tonic-gate "Number of Fragments = %hu", numfrags); 829*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 830*0Sstevel@tonic-gate "Number of Duplicates = %hu", numdups); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate /* Display any gap reports */ 833*0Sstevel@tonic-gate datalen -= sizeof (*scp); 834*0Sstevel@tonic-gate if (datalen < (numfrags * sizeof (*frag))) { 835*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 836*0Sstevel@tonic-gate " ==> Malformed gap report listing"); 837*0Sstevel@tonic-gate return; 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate frag = (sctp_sack_frag_t *)(scp + 1); 840*0Sstevel@tonic-gate for (i = 0; i < numfrags; i++) { 841*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 842*0Sstevel@tonic-gate " Fragment #%d: Start = %hu, end = %hu", i, 843*0Sstevel@tonic-gate ntohs(frag->ssf_start), ntohs(frag->ssf_end)); 844*0Sstevel@tonic-gate frag += 1; 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate /* Display any duplicate reports */ 848*0Sstevel@tonic-gate datalen -= numfrags * sizeof (*frag); 849*0Sstevel@tonic-gate if (datalen < (numdups * sizeof (*tsn))) { 850*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 851*0Sstevel@tonic-gate " ==> Malformed duplicate report listing"); 852*0Sstevel@tonic-gate return; 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 855*0Sstevel@tonic-gate tsn = (uint32_t *)frag; 856*0Sstevel@tonic-gate for (i = 0; i < numdups; i++) { 857*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 858*0Sstevel@tonic-gate " Duplicate #%d: TSN = %x", i, *tsn); 859*0Sstevel@tonic-gate tsn++; 860*0Sstevel@tonic-gate } 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate if (flags & F_SUM) { 863*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, 864*0Sstevel@tonic-gate "tsn %x win %u gaps/dups %hu/%hu ", ntohl(scp->ssc_cumtsn), 865*0Sstevel@tonic-gate ntohl(scp->ssc_a_rwnd), ntohs(scp->ssc_numfrags), 866*0Sstevel@tonic-gate ntohs(scp->ssc_numdups))); 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate } 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate /* ARGSUSED */ 871*0Sstevel@tonic-gate static void 872*0Sstevel@tonic-gate parse_shutdown_chunk(int flags, uint8_t cflags, const void *data, int datalen) 873*0Sstevel@tonic-gate { 874*0Sstevel@tonic-gate const uint32_t *cumtsn = data; 875*0Sstevel@tonic-gate 876*0Sstevel@tonic-gate if (datalen < sizeof (*cumtsn)) { 877*0Sstevel@tonic-gate if (flags & F_DTAIL) { 878*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 879*0Sstevel@tonic-gate "==> Incomplete Shutdown chunk"); 880*0Sstevel@tonic-gate } 881*0Sstevel@tonic-gate return; 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate if (flags & F_DTAIL) { 885*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 886*0Sstevel@tonic-gate "Cumulative TSN = 0x%.8x", ntohl(*cumtsn)); 887*0Sstevel@tonic-gate } 888*0Sstevel@tonic-gate if (flags & F_SUM) { 889*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "tsn %x", ntohl(*cumtsn))); 890*0Sstevel@tonic-gate } 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate /* ARGSUSED */ 894*0Sstevel@tonic-gate static void 895*0Sstevel@tonic-gate parse_error_chunk(int flags, uint8_t cflags, const void *data, int datalen) 896*0Sstevel@tonic-gate { 897*0Sstevel@tonic-gate if (!(flags & F_DTAIL)) { 898*0Sstevel@tonic-gate return; 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate interpret_params(data, datalen, "Error", err_dispatch_table, 902*0Sstevel@tonic-gate A_CNT(err_dispatch_table), flags); 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate static void 906*0Sstevel@tonic-gate parse_abort_chunk(int flags, uint8_t cflags, const void *data, int datalen) 907*0Sstevel@tonic-gate { 908*0Sstevel@tonic-gate if (!(flags & F_DTAIL)) { 909*0Sstevel@tonic-gate return; 910*0Sstevel@tonic-gate } 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x", 913*0Sstevel@tonic-gate cflags); 914*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 915*0Sstevel@tonic-gate getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed")); 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate interpret_params(data, datalen, "Error", err_dispatch_table, 918*0Sstevel@tonic-gate A_CNT(err_dispatch_table), flags); 919*0Sstevel@tonic-gate } 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate /* ARGSUSED2 */ 922*0Sstevel@tonic-gate static void 923*0Sstevel@tonic-gate parse_shutdone_chunk(int flags, uint8_t cflags, const void *data, int datalen) 924*0Sstevel@tonic-gate { 925*0Sstevel@tonic-gate if (!(flags & F_DTAIL)) { 926*0Sstevel@tonic-gate return; 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), "flags = 0x%.2x", 930*0Sstevel@tonic-gate cflags); 931*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), " %s", 932*0Sstevel@tonic-gate getflag(cflags, SCTP_TBIT, "TCB not destroyed", "TCB destroyed")); 933*0Sstevel@tonic-gate } 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate /* ARGSUSED */ 936*0Sstevel@tonic-gate static void 937*0Sstevel@tonic-gate parse_opaque_chunk(int flags, uint8_t cflags, const void *data, int datalen) 938*0Sstevel@tonic-gate { 939*0Sstevel@tonic-gate if (!(flags & F_DTAIL)) { 940*0Sstevel@tonic-gate return; 941*0Sstevel@tonic-gate } 942*0Sstevel@tonic-gate if (datalen == 0) { 943*0Sstevel@tonic-gate return; 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate dumphex(data, datalen, "Data = %s"); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate /* 950*0Sstevel@tonic-gate * Loops through all chunks until it has read fraglen bytes of 951*0Sstevel@tonic-gate * information, finding a parser for each. If any parameters are 952*0Sstevel@tonic-gate * present, interpret_params() is then called. Returns the remaining 953*0Sstevel@tonic-gate * fraglen. 954*0Sstevel@tonic-gate */ 955*0Sstevel@tonic-gate static int 956*0Sstevel@tonic-gate interpret_chunks(int flags, sctp_chunk_hdr_t *cp, int fraglen) 957*0Sstevel@tonic-gate { 958*0Sstevel@tonic-gate uint16_t clen; 959*0Sstevel@tonic-gate int signed_len; 960*0Sstevel@tonic-gate int pad; 961*0Sstevel@tonic-gate const char *desc; 962*0Sstevel@tonic-gate parse_func_t *parse; 963*0Sstevel@tonic-gate const dispatch_t *dp; 964*0Sstevel@tonic-gate const char *actstr; 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate for (;;) { 967*0Sstevel@tonic-gate /* 968*0Sstevel@tonic-gate * Adjust for padding: if the address isn't aligned, there 969*0Sstevel@tonic-gate * should be some padding. So skip over the padding and 970*0Sstevel@tonic-gate * adjust hdr accordingly. RFC2960 mandates that all 971*0Sstevel@tonic-gate * chunks must be 32-bit aligned WRT the SCTP common hdr, 972*0Sstevel@tonic-gate * which ensures that this chunk header will 973*0Sstevel@tonic-gate * be 32-bit aligned in memory. We must, of course, bounds 974*0Sstevel@tonic-gate * check fraglen before actually trying to use hdr, in 975*0Sstevel@tonic-gate * case the packet has been mangled or is the product 976*0Sstevel@tonic-gate * of a buggy implementation. 977*0Sstevel@tonic-gate */ 978*0Sstevel@tonic-gate if ((pad = (uintptr_t)cp % SCTP_ALIGN) != 0) { 979*0Sstevel@tonic-gate pad = SCTP_ALIGN - pad; 980*0Sstevel@tonic-gate fraglen -= pad; 981*0Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 982*0Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)((char *)cp + pad); 983*0Sstevel@tonic-gate } 984*0Sstevel@tonic-gate 985*0Sstevel@tonic-gate /* Need to compare against 0 1st, since sizeof is unsigned */ 986*0Sstevel@tonic-gate if (fraglen < 0 || fraglen < sizeof (*cp)) { 987*0Sstevel@tonic-gate if (fraglen > 0 && flags & F_DTAIL) { 988*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 989*0Sstevel@tonic-gate get_line_remain(), 990*0Sstevel@tonic-gate "==> Extra data after last chunk"); 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate return (fraglen); 993*0Sstevel@tonic-gate } 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate clen = ntohs(cp->sch_len); 996*0Sstevel@tonic-gate if (fraglen < clen) { 997*0Sstevel@tonic-gate if (flags & F_DTAIL) { 998*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 999*0Sstevel@tonic-gate get_line_remain(), "==> Corrupted chunk"); 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate return (fraglen); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate signed_len = clen - sizeof (*cp); 1005*0Sstevel@tonic-gate if (signed_len < 0) { 1006*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1007*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 1008*0Sstevel@tonic-gate get_line_remain(), 1009*0Sstevel@tonic-gate "==> Incomplete or corrupted chunk"); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate return (0); 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate /* Get description and parser */ 1015*0Sstevel@tonic-gate dp = lookup_dispatch(cp->sch_id, chunk_dispatch_table, 1016*0Sstevel@tonic-gate A_CNT(chunk_dispatch_table)); 1017*0Sstevel@tonic-gate if (dp != NULL) { 1018*0Sstevel@tonic-gate if (flags & F_SUM) { 1019*0Sstevel@tonic-gate desc = dp->sdesc; 1020*0Sstevel@tonic-gate } else if (flags & F_DTAIL) { 1021*0Sstevel@tonic-gate desc = dp->vdesc; 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate parse = dp->parse; 1024*0Sstevel@tonic-gate } else { 1025*0Sstevel@tonic-gate if (flags & F_SUM) { 1026*0Sstevel@tonic-gate desc = "UNK"; 1027*0Sstevel@tonic-gate } else if (flags & F_DTAIL) { 1028*0Sstevel@tonic-gate desc = "Unknown Chunk Type"; 1029*0Sstevel@tonic-gate } 1030*0Sstevel@tonic-gate parse = parse_opaque_chunk; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate if (flags & F_SUM) { 1034*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "%s ", desc)); 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1037*0Sstevel@tonic-gate show_space(); 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate if (dp != NULL) { 1040*0Sstevel@tonic-gate actstr = ""; 1041*0Sstevel@tonic-gate } else { 1042*0Sstevel@tonic-gate actstr = get_action_desc(cp->sch_id); 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1045*0Sstevel@tonic-gate "------- SCTP Chunk Type = %s (%u%s)", desc, 1046*0Sstevel@tonic-gate cp->sch_id, actstr); 1047*0Sstevel@tonic-gate 1048*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1049*0Sstevel@tonic-gate "Chunk length = %hu", clen); 1050*0Sstevel@tonic-gate } 1051*0Sstevel@tonic-gate 1052*0Sstevel@tonic-gate if (parse != NULL) { 1053*0Sstevel@tonic-gate parse(flags, cp->sch_flags, (char *)(cp + 1), 1054*0Sstevel@tonic-gate signed_len); 1055*0Sstevel@tonic-gate } 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate fraglen -= clen; 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */ 1060*0Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)((char *)cp + clen); 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate void 1065*0Sstevel@tonic-gate interpret_sctp(int flags, sctp_hdr_t *sctp, int iplen, int fraglen) 1066*0Sstevel@tonic-gate { 1067*0Sstevel@tonic-gate int len_from_iphdr; 1068*0Sstevel@tonic-gate sctp_chunk_hdr_t *cp; 1069*0Sstevel@tonic-gate char *pn; 1070*0Sstevel@tonic-gate char buff[32]; 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gate /* 1073*0Sstevel@tonic-gate * Alignment check. If the header is 32-bit aligned, all other 1074*0Sstevel@tonic-gate * protocol units will also be aligned, as mandated by rfc2960. 1075*0Sstevel@tonic-gate * Buggy packets will be caught and flagged by chunk and 1076*0Sstevel@tonic-gate * parameter bounds checking. 1077*0Sstevel@tonic-gate * If the header is not aligned, however, we drop the packet. 1078*0Sstevel@tonic-gate */ 1079*0Sstevel@tonic-gate if (!IS_P2ALIGNED(sctp, SCTP_ALIGN)) { 1080*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1081*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1082*0Sstevel@tonic-gate "==> SCTP header not aligned, dropping"); 1083*0Sstevel@tonic-gate } 1084*0Sstevel@tonic-gate return; 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate fraglen -= sizeof (*sctp); 1088*0Sstevel@tonic-gate if (fraglen < 0) { 1089*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1090*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1091*0Sstevel@tonic-gate "==> Incomplete sctp header"); 1092*0Sstevel@tonic-gate } 1093*0Sstevel@tonic-gate return; 1094*0Sstevel@tonic-gate } 1095*0Sstevel@tonic-gate /* If fraglen is somehow longer than the IP payload, adjust it */ 1096*0Sstevel@tonic-gate len_from_iphdr = iplen - sizeof (*sctp); 1097*0Sstevel@tonic-gate if (fraglen > len_from_iphdr) { 1098*0Sstevel@tonic-gate fraglen = len_from_iphdr; 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate /* Keep track of the ports */ 1102*0Sstevel@tonic-gate sport = ntohs(sctp->sh_sport); 1103*0Sstevel@tonic-gate dport = ntohs(sctp->sh_dport); 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate /* Set pointer to first chunk */ 1106*0Sstevel@tonic-gate cp = (sctp_chunk_hdr_t *)(sctp + 1); 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate if (flags & F_SUM) { 1109*0Sstevel@tonic-gate sumline = get_sum_line(); 1110*0Sstevel@tonic-gate *sumline = '\0'; 1111*0Sstevel@tonic-gate sumlen = MAXLINE; 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gate SUMAPPEND((scratch, MAXLINE, "SCTP D=%d S=%d ", dport, sport)); 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1117*0Sstevel@tonic-gate show_header("SCTP: ", "SCTP Header", fraglen); 1118*0Sstevel@tonic-gate show_space(); 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate pn = getportname(IPPROTO_SCTP, (ushort_t)sport); 1121*0Sstevel@tonic-gate if (pn == NULL) { 1122*0Sstevel@tonic-gate pn = ""; 1123*0Sstevel@tonic-gate } else { 1124*0Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "(%s)", pn); 1125*0Sstevel@tonic-gate pn = buff; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1128*0Sstevel@tonic-gate "Source port = %hu %s", sport, pn); 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate pn = getportname(IPPROTO_SCTP, (ushort_t)dport); 1131*0Sstevel@tonic-gate if (pn == NULL) { 1132*0Sstevel@tonic-gate pn = ""; 1133*0Sstevel@tonic-gate } else { 1134*0Sstevel@tonic-gate (void) snprintf(buff, sizeof (buff), "(%s)", pn); 1135*0Sstevel@tonic-gate pn = buff; 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1138*0Sstevel@tonic-gate "Destination port = %hu %s", dport, pn); 1139*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1140*0Sstevel@tonic-gate "Verification tag = 0x%.8x", ntohl(sctp->sh_verf)); 1141*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(), 1142*0Sstevel@tonic-gate "CRC-32c = 0x%.8x", ntohl(sctp->sh_chksum)); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate (void) interpret_chunks(flags, cp, fraglen); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1148*0Sstevel@tonic-gate show_space(); 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate /* 1153*0Sstevel@tonic-gate * Payload protocol ID table. Add new ULP information and parsers 1154*0Sstevel@tonic-gate * here. 1155*0Sstevel@tonic-gate */ 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate struct protoid_table { 1158*0Sstevel@tonic-gate int pid_num; 1159*0Sstevel@tonic-gate char *pid_short; 1160*0Sstevel@tonic-gate char *pid_long; 1161*0Sstevel@tonic-gate }; 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate static struct protoid_table pid_sctp[] = { 1164*0Sstevel@tonic-gate 1, "IUA", "ISDN Q.921 User Adaption Layer", 1165*0Sstevel@tonic-gate 2, "M2UA", "SS7 MTP2 User Adaption Layer", 1166*0Sstevel@tonic-gate 3, "M3UA", "SS7 MTP3 User Adaption Layer", 1167*0Sstevel@tonic-gate 4, "SUA", "SS7 SCCP User Adaption Layer", 1168*0Sstevel@tonic-gate 5, "M2PA", "SS7 MTP2-User Peer-to-Peer Adaption Layer", 1169*0Sstevel@tonic-gate 6, "V5UA", "V5UA", 1170*0Sstevel@tonic-gate 0, NULL, "", 1171*0Sstevel@tonic-gate }; 1172*0Sstevel@tonic-gate 1173*0Sstevel@tonic-gate static void 1174*0Sstevel@tonic-gate interpret_protoid(int flags, uint32_t ppid, char *data, int dlen) 1175*0Sstevel@tonic-gate { 1176*0Sstevel@tonic-gate struct protoid_table *p; 1177*0Sstevel@tonic-gate char pbuf[16]; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate /* 1180*0Sstevel@tonic-gate * Branch to a ULP interpreter here, or continue on to 1181*0Sstevel@tonic-gate * the default parser, which just tries to display 1182*0Sstevel@tonic-gate * printable characters from the payload. 1183*0Sstevel@tonic-gate */ 1184*0Sstevel@tonic-gate 1185*0Sstevel@tonic-gate for (p = pid_sctp; p->pid_num; p++) { 1186*0Sstevel@tonic-gate if (ppid == p->pid_num) { 1187*0Sstevel@tonic-gate if (flags & F_SUM) { 1188*0Sstevel@tonic-gate (void) snprintf(get_sum_line(), MAXLINE, 1189*0Sstevel@tonic-gate "D=%d S=%d %s %s", dport, sport, 1190*0Sstevel@tonic-gate p->pid_short, show_string(data, dlen, 20)); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate if (flags & F_DTAIL) { 1194*0Sstevel@tonic-gate (void) snprintf(pbuf, MAXLINE, "%s: ", 1195*0Sstevel@tonic-gate p->pid_short); 1196*0Sstevel@tonic-gate show_header(pbuf, p->pid_long, dlen); 1197*0Sstevel@tonic-gate show_space(); 1198*0Sstevel@tonic-gate (void) snprintf(get_line(0, 0), 1199*0Sstevel@tonic-gate get_line_remain(), "\"%s\"", 1200*0Sstevel@tonic-gate show_string(data, dlen, 60)); 1201*0Sstevel@tonic-gate show_trailer(); 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate return; 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate } 1208