1170461Srrs/*- 2170461Srrs * Copyright (c) 2001-2007, by Weongyo Jeong. All rights reserved. 3224271Stuexen * Copyright (c) 2011, by Michael Tuexen. All rights reserved. 4170461Srrs * 5170461Srrs * Redistribution and use in source and binary forms, with or without 6170461Srrs * modification, are permitted provided that the following conditions are met: 7170461Srrs * 8170461Srrs * a) Redistributions of source code must retain the above copyright notice, 9170461Srrs * this list of conditions and the following disclaimer. 10170461Srrs * 11170461Srrs * b) Redistributions in binary form must reproduce the above copyright 12170461Srrs * notice, this list of conditions and the following disclaimer in 13170461Srrs * the documentation and/or other materials provided with the distribution. 14170461Srrs * 15170461Srrs * c) Neither the name of Cisco Systems, Inc. nor the names of its 16170461Srrs * contributors may be used to endorse or promote products derived 17170461Srrs * from this software without specific prior written permission. 18170461Srrs * 19170461Srrs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20170461Srrs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21170461Srrs * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22170461Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23170461Srrs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24170461Srrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25170461Srrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26170461Srrs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27170461Srrs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28170461Srrs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29170461Srrs * THE POSSIBILITY OF SUCH DAMAGE. 30170461Srrs */ 31170461Srrs 32170461Srrs#if 0 33170461Srrs#ifndef lint 34170461Srrsstatic char sccsid[] = "@(#)sctp.c 0.1 (Berkeley) 4/18/2007"; 35170461Srrs#endif /* not lint */ 36170461Srrs#endif 37170461Srrs 38170461Srrs#include <sys/cdefs.h> 39170461Srrs__FBSDID("$FreeBSD$"); 40170461Srrs 41170461Srrs#include <sys/param.h> 42170461Srrs#include <sys/queue.h> 43170461Srrs#include <sys/types.h> 44170461Srrs#include <sys/socket.h> 45170461Srrs#include <sys/socketvar.h> 46170461Srrs#include <sys/sysctl.h> 47170461Srrs#include <sys/protosw.h> 48170461Srrs 49170461Srrs#include <netinet/in.h> 50170461Srrs#include <netinet/sctp.h> 51170461Srrs#include <netinet/sctp_constants.h> 52170461Srrs#include <arpa/inet.h> 53170461Srrs 54170461Srrs#include <err.h> 55170461Srrs#include <errno.h> 56200462Sdelphij#include <libutil.h> 57200462Sdelphij#include <netdb.h> 58170461Srrs#include <stdint.h> 59170461Srrs#include <stdio.h> 60170461Srrs#include <stdlib.h> 61170461Srrs#include <string.h> 62200462Sdelphij#include <unistd.h> 63170461Srrs#include "netstat.h" 64170461Srrs 65170461Srrs#ifdef SCTP 66170461Srrs 67170461Srrsstatic void sctp_statesprint(uint32_t state); 68170461Srrs 69175061Sobrien#define NETSTAT_SCTP_STATES_CLOSED 0x0 70175061Sobrien#define NETSTAT_SCTP_STATES_BOUND 0x1 71175061Sobrien#define NETSTAT_SCTP_STATES_LISTEN 0x2 72175061Sobrien#define NETSTAT_SCTP_STATES_COOKIE_WAIT 0x3 73175061Sobrien#define NETSTAT_SCTP_STATES_COOKIE_ECHOED 0x4 74175061Sobrien#define NETSTAT_SCTP_STATES_ESTABLISHED 0x5 75175061Sobrien#define NETSTAT_SCTP_STATES_SHUTDOWN_SENT 0x6 76175061Sobrien#define NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED 0x7 77175061Sobrien#define NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT 0x8 78175061Sobrien#define NETSTAT_SCTP_STATES_SHUTDOWN_PENDING 0x9 79170461Srrs 80246988Scharnierconst char *sctpstates[] = { 81170461Srrs "CLOSED", 82170461Srrs "BOUND", 83175061Sobrien "LISTEN", 84175061Sobrien "COOKIE_WAIT", 85175061Sobrien "COOKIE_ECHOED", 86175061Sobrien "ESTABLISHED", 87170461Srrs "SHUTDOWN_SENT", 88170461Srrs "SHUTDOWN_RECEIVED", 89170461Srrs "SHUTDOWN_ACK_SENT", 90170461Srrs "SHUTDOWN_PENDING" 91170461Srrs}; 92170461Srrs 93170461SrrsLIST_HEAD(xladdr_list, xladdr_entry) xladdr_head; 94170461Srrsstruct xladdr_entry { 95170461Srrs struct xsctp_laddr *xladdr; 96170461Srrs LIST_ENTRY(xladdr_entry) xladdr_entries; 97170461Srrs}; 98170461Srrs 99170461SrrsLIST_HEAD(xraddr_list, xraddr_entry) xraddr_head; 100170461Srrsstruct xraddr_entry { 101170461Srrs struct xsctp_raddr *xraddr; 102170461Srrs LIST_ENTRY(xraddr_entry) xraddr_entries; 103170461Srrs}; 104170461Srrs 105224271Stuexen/* 106224271Stuexen * Construct an Internet address representation. 107224271Stuexen * If numeric_addr has been supplied, give 108224271Stuexen * numeric value, otherwise try for symbolic name. 109224271Stuexen */ 110238514Stuexen#ifdef INET 111224271Stuexenstatic char * 112224271Stuexeninetname(struct in_addr *inp) 113224271Stuexen{ 114224271Stuexen char *cp; 115224271Stuexen static char line[MAXHOSTNAMELEN]; 116224271Stuexen struct hostent *hp; 117224271Stuexen struct netent *np; 118224271Stuexen 119224271Stuexen cp = 0; 120224271Stuexen if (!numeric_addr && inp->s_addr != INADDR_ANY) { 121224271Stuexen int net = inet_netof(*inp); 122224271Stuexen int lna = inet_lnaof(*inp); 123224271Stuexen 124224271Stuexen if (lna == INADDR_ANY) { 125224271Stuexen np = getnetbyaddr(net, AF_INET); 126224271Stuexen if (np) 127224271Stuexen cp = np->n_name; 128224271Stuexen } 129224271Stuexen if (cp == 0) { 130224271Stuexen hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); 131224271Stuexen if (hp) { 132224271Stuexen cp = hp->h_name; 133224271Stuexen trimdomain(cp, strlen(cp)); 134224271Stuexen } 135224271Stuexen } 136224271Stuexen } 137224271Stuexen if (inp->s_addr == INADDR_ANY) 138224271Stuexen strcpy(line, "*"); 139224271Stuexen else if (cp) { 140224271Stuexen strlcpy(line, cp, sizeof(line)); 141224271Stuexen } else { 142224271Stuexen inp->s_addr = ntohl(inp->s_addr); 143224271Stuexen#define C(x) ((u_int)((x) & 0xff)) 144224271Stuexen sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24), 145224271Stuexen C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr)); 146224271Stuexen inp->s_addr = htonl(inp->s_addr); 147224271Stuexen } 148224271Stuexen return (line); 149224271Stuexen} 150238514Stuexen#endif 151224271Stuexen 152224271Stuexen#ifdef INET6 153224271Stuexenstatic char ntop_buf[INET6_ADDRSTRLEN]; 154224271Stuexen 155224271Stuexenstatic char * 156224271Stuexeninet6name(struct in6_addr *in6p) 157224271Stuexen{ 158224271Stuexen char *cp; 159224271Stuexen static char line[50]; 160224271Stuexen struct hostent *hp; 161224271Stuexen static char domain[MAXHOSTNAMELEN]; 162224271Stuexen static int first = 1; 163224271Stuexen 164224271Stuexen if (first && !numeric_addr) { 165224271Stuexen first = 0; 166224271Stuexen if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 167229403Sed (cp = strchr(domain, '.'))) 168224271Stuexen (void) strcpy(domain, cp + 1); 169224271Stuexen else 170224271Stuexen domain[0] = 0; 171224271Stuexen } 172224271Stuexen cp = 0; 173224271Stuexen if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) { 174224271Stuexen hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6); 175224271Stuexen if (hp) { 176229403Sed if ((cp = strchr(hp->h_name, '.')) && 177224271Stuexen !strcmp(cp + 1, domain)) 178224271Stuexen *cp = 0; 179224271Stuexen cp = hp->h_name; 180224271Stuexen } 181224271Stuexen } 182224271Stuexen if (IN6_IS_ADDR_UNSPECIFIED(in6p)) 183224271Stuexen strcpy(line, "*"); 184224271Stuexen else if (cp) 185224271Stuexen strcpy(line, cp); 186224271Stuexen else 187224271Stuexen sprintf(line, "%s", 188224271Stuexen inet_ntop(AF_INET6, (void *)in6p, ntop_buf, 189224271Stuexen sizeof(ntop_buf))); 190224271Stuexen return (line); 191224271Stuexen} 192224271Stuexen#endif 193224271Stuexen 194224271Stuexenstatic void 195224271Stuexensctp_print_address(union sctp_sockstore *address, int port, int num_port) 196224271Stuexen{ 197224271Stuexen struct servent *sp = 0; 198224271Stuexen char line[80], *cp; 199224271Stuexen int width; 200224271Stuexen 201224271Stuexen switch (address->sa.sa_family) { 202238514Stuexen#ifdef INET 203224271Stuexen case AF_INET: 204224271Stuexen sprintf(line, "%.*s.", Wflag ? 39 : 16, inetname(&address->sin.sin_addr)); 205224271Stuexen break; 206238514Stuexen#endif 207224271Stuexen#ifdef INET6 208224271Stuexen case AF_INET6: 209224271Stuexen sprintf(line, "%.*s.", Wflag ? 39 : 16, inet6name(&address->sin6.sin6_addr)); 210224271Stuexen break; 211224271Stuexen#endif 212224271Stuexen default: 213224271Stuexen sprintf(line, "%.*s.", Wflag ? 39 : 16, ""); 214224271Stuexen break; 215224271Stuexen } 216229403Sed cp = strchr(line, '\0'); 217224271Stuexen if (!num_port && port) 218224271Stuexen sp = getservbyport((int)port, "sctp"); 219224271Stuexen if (sp || port == 0) 220224271Stuexen sprintf(cp, "%.15s ", sp ? sp->s_name : "*"); 221224271Stuexen else 222224271Stuexen sprintf(cp, "%d ", ntohs((u_short)port)); 223224271Stuexen width = Wflag ? 45 : 22; 224224271Stuexen printf("%-*.*s ", width, width, line); 225224271Stuexen} 226224271Stuexen 227170461Srrsstatic int 228170461Srrssctp_skip_xinpcb_ifneed(char *buf, const size_t buflen, size_t *offset) 229170461Srrs{ 230170461Srrs int exist_tcb = 0; 231170461Srrs struct xsctp_tcb *xstcb; 232170461Srrs struct xsctp_raddr *xraddr; 233170461Srrs struct xsctp_laddr *xladdr; 234170461Srrs 235170461Srrs while (*offset < buflen) { 236170461Srrs xladdr = (struct xsctp_laddr *)(buf + *offset); 237170461Srrs *offset += sizeof(struct xsctp_laddr); 238170461Srrs if (xladdr->last == 1) 239170461Srrs break; 240170461Srrs } 241175061Sobrien 242170461Srrs while (*offset < buflen) { 243170461Srrs xstcb = (struct xsctp_tcb *)(buf + *offset); 244170461Srrs *offset += sizeof(struct xsctp_tcb); 245170461Srrs if (xstcb->last == 1) 246170461Srrs break; 247170461Srrs 248170461Srrs exist_tcb = 1; 249170461Srrs 250170461Srrs while (*offset < buflen) { 251170461Srrs xladdr = (struct xsctp_laddr *)(buf + *offset); 252170461Srrs *offset += sizeof(struct xsctp_laddr); 253170461Srrs if (xladdr->last == 1) 254170461Srrs break; 255170461Srrs } 256170461Srrs 257170461Srrs while (*offset < buflen) { 258170461Srrs xraddr = (struct xsctp_raddr *)(buf + *offset); 259170461Srrs *offset += sizeof(struct xsctp_raddr); 260170461Srrs if (xraddr->last == 1) 261170461Srrs break; 262170461Srrs } 263170461Srrs } 264170461Srrs 265170461Srrs /* 266170461Srrs * If Lflag is set, we don't care about the return value. 267170461Srrs */ 268170461Srrs if (Lflag) 269170461Srrs return 0; 270170461Srrs 271170461Srrs return exist_tcb; 272170461Srrs} 273170461Srrs 274170461Srrsstatic void 275224271Stuexensctp_process_tcb(struct xsctp_tcb *xstcb, 276170461Srrs char *buf, const size_t buflen, size_t *offset, int *indent) 277170461Srrs{ 278170461Srrs int i, xl_total = 0, xr_total = 0, x_max; 279170461Srrs struct xsctp_raddr *xraddr; 280170461Srrs struct xsctp_laddr *xladdr; 281170461Srrs struct xladdr_entry *prev_xl = NULL, *xl = NULL, *xl_tmp; 282170461Srrs struct xraddr_entry *prev_xr = NULL, *xr = NULL, *xr_tmp; 283170461Srrs 284170461Srrs LIST_INIT(&xladdr_head); 285170461Srrs LIST_INIT(&xraddr_head); 286170461Srrs 287170461Srrs /* 288170461Srrs * Make `struct xladdr_list' list and `struct xraddr_list' list 289170461Srrs * to handle the address flexibly. 290170461Srrs */ 291170461Srrs while (*offset < buflen) { 292170461Srrs xladdr = (struct xsctp_laddr *)(buf + *offset); 293170461Srrs *offset += sizeof(struct xsctp_laddr); 294170461Srrs if (xladdr->last == 1) 295170461Srrs break; 296175061Sobrien 297170461Srrs prev_xl = xl; 298170461Srrs xl = malloc(sizeof(struct xladdr_entry)); 299170461Srrs if (xl == NULL) { 300175061Sobrien warnx("malloc %lu bytes", 301170461Srrs (u_long)sizeof(struct xladdr_entry)); 302170461Srrs goto out; 303170461Srrs } 304170461Srrs xl->xladdr = xladdr; 305170461Srrs if (prev_xl == NULL) 306170461Srrs LIST_INSERT_HEAD(&xladdr_head, xl, xladdr_entries); 307170461Srrs else 308170461Srrs LIST_INSERT_AFTER(prev_xl, xl, xladdr_entries); 309170461Srrs xl_total++; 310170461Srrs } 311175061Sobrien 312170461Srrs while (*offset < buflen) { 313170461Srrs xraddr = (struct xsctp_raddr *)(buf + *offset); 314170461Srrs *offset += sizeof(struct xsctp_raddr); 315170461Srrs if (xraddr->last == 1) 316170461Srrs break; 317175061Sobrien 318170461Srrs prev_xr = xr; 319170461Srrs xr = malloc(sizeof(struct xraddr_entry)); 320170461Srrs if (xr == NULL) { 321175061Sobrien warnx("malloc %lu bytes", 322170461Srrs (u_long)sizeof(struct xraddr_entry)); 323170461Srrs goto out; 324170461Srrs } 325170461Srrs xr->xraddr = xraddr; 326170461Srrs if (prev_xr == NULL) 327170461Srrs LIST_INSERT_HEAD(&xraddr_head, xr, xraddr_entries); 328170461Srrs else 329170461Srrs LIST_INSERT_AFTER(prev_xr, xr, xraddr_entries); 330170461Srrs xr_total++; 331170461Srrs } 332175061Sobrien 333170461Srrs /* 334170461Srrs * Let's print the address infos. 335170461Srrs */ 336170461Srrs xl = LIST_FIRST(&xladdr_head); 337170461Srrs xr = LIST_FIRST(&xraddr_head); 338170461Srrs x_max = (xl_total > xr_total) ? xl_total : xr_total; 339170461Srrs for (i = 0; i < x_max; i++) { 340170461Srrs if (((*indent == 0) && i > 0) || *indent > 0) 341224271Stuexen printf("%-12s ", " "); 342175061Sobrien 343170461Srrs if (xl != NULL) { 344224271Stuexen sctp_print_address(&(xl->xladdr->address), 345224271Stuexen htons(xstcb->local_port), numeric_port); 346224271Stuexen } else { 347224271Stuexen if (Wflag) { 348224271Stuexen printf("%-45s ", " "); 349224271Stuexen } else { 350224271Stuexen printf("%-22s ", " "); 351170461Srrs } 352170461Srrs } 353175061Sobrien 354170461Srrs if (xr != NULL && !Lflag) { 355224271Stuexen sctp_print_address(&(xr->xraddr->address), 356224271Stuexen htons(xstcb->remote_port), numeric_port); 357170461Srrs } 358175061Sobrien 359170461Srrs if (xl != NULL) 360170461Srrs xl = LIST_NEXT(xl, xladdr_entries); 361170461Srrs if (xr != NULL) 362170461Srrs xr = LIST_NEXT(xr, xraddr_entries); 363175061Sobrien 364170461Srrs if (i == 0 && !Lflag) 365170461Srrs sctp_statesprint(xstcb->state); 366175061Sobrien 367170461Srrs if (i < x_max) 368170461Srrs putchar('\n'); 369170461Srrs } 370175061Sobrien 371170461Srrsout: 372170461Srrs /* 373170461Srrs * Free the list which be used to handle the address. 374170461Srrs */ 375170461Srrs xl = LIST_FIRST(&xladdr_head); 376170461Srrs while (xl != NULL) { 377170461Srrs xl_tmp = LIST_NEXT(xl, xladdr_entries); 378170461Srrs free(xl); 379170461Srrs xl = xl_tmp; 380170461Srrs } 381175061Sobrien 382170461Srrs xr = LIST_FIRST(&xraddr_head); 383170461Srrs while (xr != NULL) { 384170461Srrs xr_tmp = LIST_NEXT(xr, xraddr_entries); 385170461Srrs free(xr); 386170461Srrs xr = xr_tmp; 387170461Srrs } 388170461Srrs} 389170461Srrs 390170461Srrsstatic void 391224271Stuexensctp_process_inpcb(struct xsctp_inpcb *xinpcb, 392170461Srrs char *buf, const size_t buflen, size_t *offset) 393170461Srrs{ 394224271Stuexen int indent = 0, xladdr_total = 0, is_listening = 0; 395170461Srrs static int first = 1; 396246988Scharnier const char *tname, *pname; 397170461Srrs struct xsctp_tcb *xstcb; 398170461Srrs struct xsctp_laddr *xladdr; 399224271Stuexen size_t offset_laddr; 400224271Stuexen int process_closed; 401170461Srrs 402224271Stuexen if (xinpcb->maxqlen > 0) 403170461Srrs is_listening = 1; 404170461Srrs 405170461Srrs if (first) { 406170461Srrs if (!Lflag) { 407170461Srrs printf("Active SCTP associations"); 408170461Srrs if (aflag) 409170461Srrs printf(" (including servers)"); 410170461Srrs } else 411170461Srrs printf("Current listen queue sizes (qlen/maxqlen)"); 412170461Srrs putchar('\n'); 413170461Srrs if (Lflag) 414224271Stuexen printf("%-6.6s %-5.5s %-8.8s %-22.22s\n", 415170461Srrs "Proto", "Type", "Listen", "Local Address"); 416170461Srrs else 417224271Stuexen if (Wflag) 418224271Stuexen printf("%-6.6s %-5.5s %-45.45s %-45.45s %s\n", 419224271Stuexen "Proto", "Type", 420224271Stuexen "Local Address", "Foreign Address", 421224271Stuexen "(state)"); 422224271Stuexen else 423224271Stuexen printf("%-6.6s %-5.5s %-22.22s %-22.22s %s\n", 424224271Stuexen "Proto", "Type", 425224271Stuexen "Local Address", "Foreign Address", 426224271Stuexen "(state)"); 427170461Srrs first = 0; 428170461Srrs } 429224271Stuexen xladdr = (struct xsctp_laddr *)(buf + *offset); 430224271Stuexen if (Lflag && !is_listening) { 431213620Sdim sctp_skip_xinpcb_ifneed(buf, buflen, offset); 432170461Srrs return; 433170461Srrs } 434170461Srrs 435224271Stuexen if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { 436224271Stuexen /* Can't distinguish between sctp46 and sctp6 */ 437224271Stuexen pname = "sctp46"; 438224271Stuexen } else { 439224271Stuexen pname = "sctp4"; 440224271Stuexen } 441175061Sobrien 442170461Srrs if (xinpcb->flags & SCTP_PCB_FLAGS_TCPTYPE) 443170461Srrs tname = "1to1"; 444170461Srrs else if (xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) 445170461Srrs tname = "1toN"; 446170461Srrs else 447224271Stuexen tname = "????"; 448175061Sobrien 449170461Srrs if (Lflag) { 450170461Srrs char buf1[9]; 451175061Sobrien 452170461Srrs snprintf(buf1, 9, "%hu/%hu", xinpcb->qlen, xinpcb->maxqlen); 453224271Stuexen printf("%-6.6s %-5.5s ", pname, tname); 454170461Srrs printf("%-8.8s ", buf1); 455170461Srrs } 456224271Stuexen 457224271Stuexen offset_laddr = *offset; 458224271Stuexen process_closed = 0; 459224271Stuexenretry: 460170461Srrs while (*offset < buflen) { 461170461Srrs xladdr = (struct xsctp_laddr *)(buf + *offset); 462170461Srrs *offset += sizeof(struct xsctp_laddr); 463224271Stuexen if (xladdr->last) { 464224271Stuexen if (aflag && !Lflag && (xladdr_total == 0) && process_closed) { 465224271Stuexen printf("%-6.6s %-5.5s ", pname, tname); 466224271Stuexen if (Wflag) { 467224271Stuexen printf("%-91.91s CLOSED", " "); 468224271Stuexen } else { 469224271Stuexen printf("%-45.45s CLOSED", " "); 470224271Stuexen } 471224271Stuexen } 472224271Stuexen if (process_closed || is_listening) { 473224271Stuexen putchar('\n'); 474224271Stuexen } 475170461Srrs break; 476224271Stuexen } 477170461Srrs 478224271Stuexen if (!Lflag && !is_listening && !process_closed) 479170461Srrs continue; 480170461Srrs 481224271Stuexen if (xladdr_total == 0) { 482224271Stuexen printf("%-6.6s %-5.5s ", pname, tname); 483224271Stuexen } else { 484170461Srrs putchar('\n'); 485170461Srrs printf((Lflag) ? 486224271Stuexen "%-21.21s " : "%-12.12s ", " "); 487170461Srrs } 488224271Stuexen sctp_print_address(&(xladdr->address), 489224271Stuexen htons(xinpcb->local_port), numeric_port); 490224271Stuexen if (aflag && !Lflag && xladdr_total == 0) { 491224271Stuexen if (Wflag) { 492224271Stuexen if (process_closed) { 493224271Stuexen printf("%-45.45s CLOSED", " "); 494224271Stuexen } else { 495224271Stuexen printf("%-45.45s LISTEN", " "); 496224271Stuexen } 497224271Stuexen } else { 498224271Stuexen if (process_closed) { 499224271Stuexen printf("%-22.22s CLOSED", " "); 500224271Stuexen } else { 501224271Stuexen printf("%-22.22s LISTEN", " "); 502224271Stuexen } 503224271Stuexen } 504224271Stuexen } 505170461Srrs xladdr_total++; 506170461Srrs } 507170461Srrs 508170461Srrs xstcb = (struct xsctp_tcb *)(buf + *offset); 509170461Srrs *offset += sizeof(struct xsctp_tcb); 510224271Stuexen if (aflag && (xladdr_total == 0) && xstcb->last && !process_closed) { 511224271Stuexen process_closed = 1; 512224271Stuexen *offset = offset_laddr; 513224271Stuexen goto retry; 514224271Stuexen } 515170461Srrs while (xstcb->last == 0 && *offset < buflen) { 516224271Stuexen printf("%-6.6s %-5.5s ", pname, tname); 517224271Stuexen sctp_process_tcb(xstcb, buf, buflen, offset, &indent); 518170461Srrs indent++; 519170461Srrs xstcb = (struct xsctp_tcb *)(buf + *offset); 520170461Srrs *offset += sizeof(struct xsctp_tcb); 521170461Srrs } 522170461Srrs} 523170461Srrs 524170461Srrs/* 525170461Srrs * Print a summary of SCTP connections related to an Internet 526170461Srrs * protocol. 527170461Srrs */ 528170461Srrsvoid 529171465Sjhbsctp_protopr(u_long off __unused, 530246988Scharnier const char *name __unused, int af1 __unused, int proto) 531170461Srrs{ 532170461Srrs char *buf; 533170461Srrs const char *mibvar = "net.inet.sctp.assoclist"; 534170646Sdelphij size_t offset = 0; 535170461Srrs size_t len = 0; 536170461Srrs struct xsctp_inpcb *xinpcb; 537175061Sobrien 538170461Srrs if (proto != IPPROTO_SCTP) 539170461Srrs return; 540170461Srrs 541170461Srrs if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { 542170461Srrs if (errno != ENOENT) 543170461Srrs warn("sysctl: %s", mibvar); 544170461Srrs return; 545170461Srrs } 546170461Srrs if ((buf = malloc(len)) == 0) { 547170461Srrs warnx("malloc %lu bytes", (u_long)len); 548170461Srrs return; 549170461Srrs } 550170461Srrs if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { 551170461Srrs warn("sysctl: %s", mibvar); 552170461Srrs free(buf); 553170461Srrs return; 554170461Srrs } 555170461Srrs 556170461Srrs xinpcb = (struct xsctp_inpcb *)(buf + offset); 557170461Srrs offset += sizeof(struct xsctp_inpcb); 558170461Srrs while (xinpcb->last == 0 && offset < len) { 559224271Stuexen sctp_process_inpcb(xinpcb, buf, (const size_t)len, 560170461Srrs &offset); 561170461Srrs 562170461Srrs xinpcb = (struct xsctp_inpcb *)(buf + offset); 563170461Srrs offset += sizeof(struct xsctp_inpcb); 564170461Srrs } 565170461Srrs 566170461Srrs free(buf); 567170461Srrs} 568170461Srrs 569170461Srrsstatic void 570170461Srrssctp_statesprint(uint32_t state) 571170461Srrs{ 572170461Srrs int idx; 573170461Srrs 574170461Srrs switch (state) { 575170461Srrs case SCTP_STATE_COOKIE_WAIT: 576170461Srrs idx = NETSTAT_SCTP_STATES_COOKIE_WAIT; 577170461Srrs break; 578170461Srrs case SCTP_STATE_COOKIE_ECHOED: 579170461Srrs idx = NETSTAT_SCTP_STATES_COOKIE_ECHOED; 580170461Srrs break; 581170461Srrs case SCTP_STATE_OPEN: 582170461Srrs idx = NETSTAT_SCTP_STATES_ESTABLISHED; 583170461Srrs break; 584170461Srrs case SCTP_STATE_SHUTDOWN_SENT: 585170461Srrs idx = NETSTAT_SCTP_STATES_SHUTDOWN_SENT; 586170461Srrs break; 587170461Srrs case SCTP_STATE_SHUTDOWN_RECEIVED: 588170461Srrs idx = NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED; 589170461Srrs break; 590170461Srrs case SCTP_STATE_SHUTDOWN_ACK_SENT: 591170461Srrs idx = NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT; 592170461Srrs break; 593170461Srrs case SCTP_STATE_SHUTDOWN_PENDING: 594170461Srrs idx = NETSTAT_SCTP_STATES_SHUTDOWN_PENDING; 595170461Srrs break; 596170461Srrs default: 597170461Srrs printf("UNKNOWN 0x%08x", state); 598170461Srrs return; 599170461Srrs } 600170461Srrs 601170461Srrs printf("%s", sctpstates[idx]); 602170461Srrs} 603170461Srrs 604170461Srrs/* 605170461Srrs * Dump SCTP statistics structure. 606170461Srrs */ 607170461Srrsvoid 608171465Sjhbsctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) 609170461Srrs{ 610170461Srrs struct sctpstat sctpstat, zerostat; 611170461Srrs size_t len = sizeof(sctpstat); 612170461Srrs 613171465Sjhb if (live) { 614171465Sjhb if (zflag) 615171465Sjhb memset(&zerostat, 0, len); 616171465Sjhb if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len, 617171465Sjhb zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { 618230555Stuexen if (errno != ENOENT) 619230555Stuexen warn("sysctl: net.inet.sctp.stats"); 620171465Sjhb return; 621171465Sjhb } 622171465Sjhb } else 623171465Sjhb kread(off, &sctpstat, len); 624170461Srrs 625170461Srrs printf ("%s:\n", name); 626170461Srrs 627170461Srrs#define p(f, m) if (sctpstat.f || sflag <= 1) \ 628172103Srrs printf(m, (uintmax_t)sctpstat.f, plural(sctpstat.f)) 629170461Srrs#define p1a(f, m) if (sctpstat.f || sflag <= 1) \ 630172103Srrs printf(m, (uintmax_t)sctpstat.f) 631170461Srrs 632170461Srrs /* 633170461Srrs * input statistics 634170461Srrs */ 635172103Srrs p(sctps_recvpackets, "\t%ju input packet%s\n"); 636172103Srrs p(sctps_recvdatagrams, "\t\t%ju datagram%s\n"); 637172103Srrs p(sctps_recvpktwithdata, "\t\t%ju packet%s that had data\n"); 638172103Srrs p(sctps_recvsacks, "\t\t%ju input SACK chunk%s\n"); 639172103Srrs p(sctps_recvdata, "\t\t%ju input DATA chunk%s\n"); 640172103Srrs p(sctps_recvdupdata, "\t\t%ju duplicate DATA chunk%s\n"); 641172103Srrs p(sctps_recvheartbeat, "\t\t%ju input HB chunk%s\n"); 642172103Srrs p(sctps_recvheartbeatack, "\t\t%ju HB-ACK chunk%s\n"); 643172103Srrs p(sctps_recvecne, "\t\t%ju input ECNE chunk%s\n"); 644172103Srrs p(sctps_recvauth, "\t\t%ju input AUTH chunk%s\n"); 645172103Srrs p(sctps_recvauthmissing, "\t\t%ju chunk%s missing AUTH\n"); 646172103Srrs p(sctps_recvivalhmacid, "\t\t%ju invalid HMAC id%s received\n"); 647172720Srrs p(sctps_recvivalkeyid, "\t\t%ju invalid secret id%s received\n"); 648172103Srrs p1a(sctps_recvauthfailed, "\t\t%ju auth failed\n"); 649172720Srrs p1a(sctps_recvexpress, "\t\t%ju fast path receives all one chunk\n"); 650172720Srrs p1a(sctps_recvexpressm, "\t\t%ju fast path multi-part data\n"); 651170461Srrs 652170461Srrs /* 653170461Srrs * output statistics 654170461Srrs */ 655172103Srrs p(sctps_sendpackets, "\t%ju output packet%s\n"); 656172103Srrs p(sctps_sendsacks, "\t\t%ju output SACK%s\n"); 657172103Srrs p(sctps_senddata, "\t\t%ju output DATA chunk%s\n"); 658172720Srrs p(sctps_sendretransdata, "\t\t%ju retransmitted DATA chunk%s\n"); 659172720Srrs p(sctps_sendfastretrans, "\t\t%ju fast retransmitted DATA chunk%s\n"); 660172103Srrs p(sctps_sendmultfastretrans, "\t\t%ju FR'%s that happened more " 661178252Srrs "than once to same chunk\n"); 662219613Sbrucec p(sctps_sendheartbeat, "\t\t%ju output HB chunk%s\n"); 663172103Srrs p(sctps_sendecne, "\t\t%ju output ECNE chunk%s\n"); 664172103Srrs p(sctps_sendauth, "\t\t%ju output AUTH chunk%s\n"); 665172103Srrs p1a(sctps_senderrors, "\t\t%ju ip_output error counter\n"); 666170461Srrs 667170461Srrs /* 668170461Srrs * PCKDROPREP statistics 669170461Srrs */ 670170882Srrs printf("\tPacket drop statistics:\n"); 671172103Srrs p1a(sctps_pdrpfmbox, "\t\t%ju from middle box\n"); 672172720Srrs p1a(sctps_pdrpfehos, "\t\t%ju from end host\n"); 673172103Srrs p1a(sctps_pdrpmbda, "\t\t%ju with data\n"); 674172103Srrs p1a(sctps_pdrpmbct, "\t\t%ju non-data, non-endhost\n"); 675172720Srrs p1a(sctps_pdrpbwrpt, "\t\t%ju non-endhost, bandwidth rep only\n"); 676172103Srrs p1a(sctps_pdrpcrupt, "\t\t%ju not enough for chunk header\n"); 677172103Srrs p1a(sctps_pdrpnedat, "\t\t%ju not enough data to confirm\n"); 678172720Srrs p1a(sctps_pdrppdbrk, "\t\t%ju where process_chunk_drop said break\n"); 679172103Srrs p1a(sctps_pdrptsnnf, "\t\t%ju failed to find TSN\n"); 680172720Srrs p1a(sctps_pdrpdnfnd, "\t\t%ju attempt reverse TSN lookup\n"); 681172720Srrs p1a(sctps_pdrpdiwnp, "\t\t%ju e-host confirms zero-rwnd\n"); 682172720Srrs p1a(sctps_pdrpdizrw, "\t\t%ju midbox confirms no space\n"); 683172103Srrs p1a(sctps_pdrpbadd, "\t\t%ju data did not match TSN\n"); 684172103Srrs p(sctps_pdrpmark, "\t\t%ju TSN'%s marked for Fast Retran\n"); 685170461Srrs 686170461Srrs /* 687170461Srrs * Timeouts 688170461Srrs */ 689170882Srrs printf("\tTimeouts:\n"); 690172103Srrs p(sctps_timoiterator, "\t\t%ju iterator timer%s fired\n"); 691172103Srrs p(sctps_timodata, "\t\t%ju T3 data time out%s\n"); 692172103Srrs p(sctps_timowindowprobe, "\t\t%ju window probe (T3) timer%s fired\n"); 693172103Srrs p(sctps_timoinit, "\t\t%ju INIT timer%s fired\n"); 694172720Srrs p(sctps_timosack, "\t\t%ju sack timer%s fired\n"); 695172720Srrs p(sctps_timoshutdown, "\t\t%ju shutdown timer%s fired\n"); 696172103Srrs p(sctps_timoheartbeat, "\t\t%ju heartbeat timer%s fired\n"); 697172103Srrs p1a(sctps_timocookie, "\t\t%ju a cookie timeout fired\n"); 698172103Srrs p1a(sctps_timosecret, "\t\t%ju an endpoint changed its cookie" 699170882Srrs "secret\n"); 700172103Srrs p(sctps_timopathmtu, "\t\t%ju PMTU timer%s fired\n"); 701172720Srrs p(sctps_timoshutdownack, "\t\t%ju shutdown ack timer%s fired\n"); 702172720Srrs p(sctps_timoshutdownguard, "\t\t%ju shutdown guard timer%s fired\n"); 703172720Srrs p(sctps_timostrmrst, "\t\t%ju stream reset timer%s fired\n"); 704172103Srrs p(sctps_timoearlyfr, "\t\t%ju early FR timer%s fired\n"); 705172103Srrs p1a(sctps_timoasconf, "\t\t%ju an asconf timer fired\n"); 706172103Srrs p1a(sctps_timoautoclose, "\t\t%ju auto close timer fired\n"); 707172720Srrs p(sctps_timoassockill, "\t\t%ju asoc free timer%s expired\n"); 708172103Srrs p(sctps_timoinpkill, "\t\t%ju inp free timer%s expired\n"); 709170461Srrs 710170461Srrs#if 0 711170461Srrs /* 712170461Srrs * Early fast retransmission counters 713170461Srrs */ 714172720Srrs p(sctps_earlyfrstart, "\t%ju TODO:sctps_earlyfrstart\n"); 715172720Srrs p(sctps_earlyfrstop, "\t%ju TODO:sctps_earlyfrstop\n"); 716172720Srrs p(sctps_earlyfrmrkretrans, "\t%ju TODO:sctps_earlyfrmrkretrans\n"); 717172720Srrs p(sctps_earlyfrstpout, "\t%ju TODO:sctps_earlyfrstpout\n"); 718172720Srrs p(sctps_earlyfrstpidsck1, "\t%ju TODO:sctps_earlyfrstpidsck1\n"); 719172720Srrs p(sctps_earlyfrstpidsck2, "\t%ju TODO:sctps_earlyfrstpidsck2\n"); 720172720Srrs p(sctps_earlyfrstpidsck3, "\t%ju TODO:sctps_earlyfrstpidsck3\n"); 721172720Srrs p(sctps_earlyfrstpidsck4, "\t%ju TODO:sctps_earlyfrstpidsck4\n"); 722172720Srrs p(sctps_earlyfrstrid, "\t%ju TODO:sctps_earlyfrstrid\n"); 723172720Srrs p(sctps_earlyfrstrout, "\t%ju TODO:sctps_earlyfrstrout\n"); 724172720Srrs p(sctps_earlyfrstrtmr, "\t%ju TODO:sctps_earlyfrstrtmr\n"); 725170461Srrs#endif 726170461Srrs 727170461Srrs /* 728170461Srrs * Others 729170461Srrs */ 730172720Srrs p1a(sctps_hdrops, "\t%ju packet shorter than header\n"); 731172720Srrs p1a(sctps_badsum, "\t%ju checksum error\n"); 732172103Srrs p1a(sctps_noport, "\t%ju no endpoint for port\n"); 733172103Srrs p1a(sctps_badvtag, "\t%ju bad v-tag\n"); 734172103Srrs p1a(sctps_badsid, "\t%ju bad SID\n"); 735172103Srrs p1a(sctps_nomem, "\t%ju no memory\n"); 736172103Srrs p1a(sctps_fastretransinrtt, "\t%ju number of multiple FR in a RTT " 737170461Srrs "window\n"); 738170461Srrs#if 0 739172720Srrs p(sctps_markedretrans, "\t%ju TODO:sctps_markedretrans\n"); 740170461Srrs#endif 741172720Srrs p1a(sctps_naglesent, "\t%ju RFC813 allowed sending\n"); 742172720Srrs p1a(sctps_naglequeued, "\t%ju RFC813 does not allow sending\n"); 743178252Srrs p1a(sctps_maxburstqueued, "\t%ju times max burst prohibited sending\n"); 744172720Srrs p1a(sctps_ifnomemqueued, "\t%ju look ahead tells us no memory in " 745170882Srrs "interface\n"); 746172720Srrs p(sctps_windowprobed, "\t%ju number%s of window probes sent\n"); 747172103Srrs p(sctps_lowlevelerr, "\t%ju time%s an output error to clamp " 748178252Srrs "down on next user send\n"); 749172103Srrs p(sctps_lowlevelerrusr, "\t%ju time%s sctp_senderrors were " 750170882Srrs "caused from a user\n"); 751172103Srrs p(sctps_datadropchklmt, "\t%ju number of in data drop%s due to " 752170461Srrs "chunk limit reached\n"); 753172103Srrs p(sctps_datadroprwnd, "\t%ju number of in data drop%s due to rwnd " 754170461Srrs "limit reached\n"); 755172103Srrs p(sctps_ecnereducedcwnd, "\t%ju time%s a ECN reduced " 756170461Srrs "the cwnd\n"); 757172720Srrs p1a(sctps_vtagexpress, "\t%ju used express lookup via vtag\n"); 758178252Srrs p1a(sctps_vtagbogus, "\t%ju collision in express lookup\n"); 759172103Srrs p(sctps_primary_randry, "\t%ju time%s the sender ran dry " 760170461Srrs "of user data on primary\n"); 761172103Srrs p1a(sctps_cmt_randry, "\t%ju same for above\n"); 762172103Srrs p(sctps_slowpath_sack, "\t%ju sack%s the slow way\n"); 763172720Srrs p(sctps_wu_sacks_sent, "\t%ju window update only sack%s sent\n"); 764172720Srrs p(sctps_sends_with_flags, "\t%ju send%s with sinfo_flags !=0\n"); 765172720Srrs p(sctps_sends_with_unord, "\t%ju unordered send%s\n"); 766172720Srrs p(sctps_sends_with_eof, "\t%ju send%s with EOF flag set\n"); 767172720Srrs p(sctps_sends_with_abort, "\t%ju send%s with ABORT flag set\n"); 768172103Srrs p(sctps_protocol_drain_calls, "\t%ju time%s protocol drain called\n"); 769172103Srrs p(sctps_protocol_drains_done, "\t%ju time%s we did a protocol " 770170882Srrs "drain\n"); 771172103Srrs p(sctps_read_peeks, "\t%ju time%s recv was called with peek\n"); 772172103Srrs p(sctps_cached_chk, "\t%ju cached chunk%s used\n"); 773172720Srrs p1a(sctps_cached_strmoq, "\t%ju cached stream oq's used\n"); 774172720Srrs p(sctps_left_abandon, "\t%ju unread message%s abandonded by close\n"); 775172720Srrs p1a(sctps_send_burst_avoid, "\t%ju send burst avoidance, already " 776170461Srrs "max burst inflight to net\n"); 777172720Srrs p1a(sctps_send_cwnd_avoid, "\t%ju send cwnd full avoidance, already " 778172720Srrs "max burst inflight to net\n"); 779172103Srrs p(sctps_fwdtsn_map_over, "\t%ju number of map array over-run%s via " 780170461Srrs "fwd-tsn's\n"); 781170882Srrs 782170882Srrs#undef p 783170882Srrs#undef p1a 784170461Srrs} 785170461Srrs 786170461Srrs#endif /* SCTP */ 787