1/* 2 * Copyright (c) 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/*- 29 * Copyright (c) 1983, 1988, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * Redistribution and use in source and binary forms, with or without 33 * modification, are permitted provided that the following conditions 34 * are met: 35 * 1. Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * 2. Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in the 39 * documentation and/or other materials provided with the distribution. 40 * 3. All advertising materials mentioning features or use of this software 41 * must display the following acknowledgement: 42 * This product includes software developed by the University of 43 * California, Berkeley and its contributors. 44 * 4. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61#include <sys/param.h> 62#include <sys/queue.h> 63#include <sys/socket.h> 64#include <sys/socketvar.h> 65#include <sys/sysctl.h> 66#include <sys/sys_domain.h> 67#include <sys/kern_control.h> 68#include <sys/kern_event.h> 69 70#include <errno.h> 71#include <err.h> 72#include <stddef.h> 73#include <stdio.h> 74#include <stdlib.h> 75#include <strings.h> 76 77#include "netstat.h" 78 79#define ROUNDUP64(a) \ 80((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t)) 81#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n)) 82 83struct xgen_n { 84 u_int32_t xgn_len; /* length of this structure */ 85 u_int32_t xgn_kind; /* number of PCBs at this time */ 86}; 87 88#define ALL_XGN_KIND_KCREG (XSO_KCREG) 89#define ALL_XGN_KIND_EVT (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_EVT) 90#define ALL_XGN_KIND_KCB (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_KCB) 91 92void 93systmpr(uint32_t proto, 94 char *name, int af) 95{ 96 const char *mibvar; 97 size_t len; 98 char *buf, *next; 99 struct xsystmgen *xig, *oxig; 100 struct xgen_n *xgn; 101 int which = 0; 102 struct xsocket_n *so = NULL; 103 struct xsockbuf_n *so_rcv = NULL; 104 struct xsockbuf_n *so_snd = NULL; 105 struct xsockstat_n *so_stat = NULL; 106 struct xkctl_reg *kctl = NULL; 107 struct xkctlpcb *kcb = NULL; 108 struct xkevtpcb *kevb = NULL; 109 int first = 1; 110 111 switch (proto) { 112 case SYSPROTO_EVENT: 113 mibvar = "net.systm.kevt.pcblist"; 114 break; 115 case SYSPROTO_CONTROL: 116 mibvar = "net.systm.kctl.pcblist"; 117 break; 118 case 0: 119 mibvar = "net.systm.kctl.reg_list"; 120 break; 121 default: 122 mibvar = NULL; 123 break; 124 } 125 if (mibvar == NULL) 126 return; 127 len = 0; 128 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { 129 if (errno != ENOENT) 130 warn("sysctl: %s", mibvar); 131 return; 132 } 133 if ((buf = malloc(len)) == 0) { 134 warn("malloc %lu bytes", (u_long)len); 135 return; 136 } 137 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { 138 warn("sysctl: %s", mibvar); 139 free(buf); 140 return; 141 } 142 /* 143 * Bail-out to avoid logic error in the loop below when 144 * there is in fact no more control block to process 145 */ 146 if (len <= sizeof(struct xsystmgen)) { 147 free(buf); 148 return; 149 } 150 oxig = xig = (struct xsystmgen *)buf; 151 for (next = buf + ROUNDUP64(xig->xg_len); next < buf + len; 152 next += ROUNDUP64(xgn->xgn_len)) { 153 xgn = (struct xgen_n*)next; 154 if (xgn->xgn_len <= sizeof(struct xsystmgen)) 155 break; 156 157 if ((which & xgn->xgn_kind) == 0) { 158 which |= xgn->xgn_kind; 159 switch (xgn->xgn_kind) { 160 case XSO_SOCKET: 161 so = (struct xsocket_n *)xgn; 162 break; 163 case XSO_RCVBUF: 164 so_rcv = (struct xsockbuf_n *)xgn; 165 break; 166 case XSO_SNDBUF: 167 so_snd = (struct xsockbuf_n *)xgn; 168 break; 169 case XSO_STATS: 170 so_stat = (struct xsockstat_n *)xgn; 171 break; 172 case XSO_KCREG: 173 kctl = (struct xkctl_reg *)xgn; 174 break; 175 case XSO_KCB: 176 kcb = (struct xkctlpcb *)xgn; 177 break; 178 case XSO_EVT: 179 kevb = (struct xkevtpcb *)xgn; 180 break; 181 default: 182 printf("unexpected kind %d\n", xgn->xgn_kind); 183 break; 184 } 185 } else { 186 if (vflag) 187 printf("got %d twice\n", xgn->xgn_kind); 188 } 189 190 if (which == ALL_XGN_KIND_KCREG) { 191 which = 0; 192 193 if (first) { 194 printf("Registered kernel control modules\n"); 195 if (Aflag) 196 printf("%-16.16s ", "kctlref"); 197 printf("%-8.8s ", "id"); 198 if (Aflag) 199 printf("%-8.8s ", "unit"); 200 printf("%-8.8s ", "flags"); 201 printf("%-8.8s ", "pcbcount"); 202 printf("%-8.8s ", "rcvbuf"); 203 printf("%-8.8s ", "sndbuf"); 204 printf("%s ", "name"); 205 printf("\n"); 206 first = 0; 207 } 208 if (Aflag) 209 printf("%16llx ", kctl->xkr_kctlref); 210 printf("%8x ", kctl->xkr_id); 211 if (Aflag) 212 printf("%8d ", kctl->xkr_reg_unit); 213 printf("%8x ", kctl->xkr_flags); 214 printf("%8d ", kctl->xkr_pcbcount); 215 printf("%8d ", kctl->xkr_recvbufsize); 216 printf("%8d ", kctl->xkr_sendbufsize); 217 printf("%s ", kctl->xkr_name); 218 printf("\n"); 219 } else if (which == ALL_XGN_KIND_KCB) { 220 which = 0; 221 222 if (first) { 223 printf("Active kernel control sockets\n"); 224 if (Aflag) 225 printf("%16.16s ", "pcb"); 226 printf("%-5.5s %-6.6s %-6.6s ", 227 "Proto", "Recv-Q", "Send-Q"); 228 if (bflag > 0) 229 printf("%10.10s %10.10s ", 230 "rxbytes", "txbytes"); 231 if (vflag > 0) 232 printf("%6.6s %6.6s %6.6s %6.6s ", 233 "rhiwat", "shiwat", "pid", "epid"); 234 printf("%6.6s ", "unit"); 235 printf("%6.6s ", "id"); 236 printf("%s", "name"); 237 printf("\n"); 238 first = 0; 239 } 240 if (Aflag) 241 printf("%16llx ", kcb->xkp_kctpcb); 242 printf("%-5.5s %6u %6u ", name, 243 so_rcv->sb_cc, 244 so_snd->sb_cc); 245 if (bflag > 0) { 246 int i; 247 u_int64_t rxbytes = 0; 248 u_int64_t txbytes = 0; 249 250 for (i = 0; i < SO_TC_STATS_MAX; i++) { 251 rxbytes += so_stat->xst_tc_stats[i].rxbytes; 252 txbytes += so_stat->xst_tc_stats[i].txbytes; 253 } 254 printf("%10llu %10llu ", rxbytes, txbytes); 255 } 256 if (vflag > 0) { 257 printf("%6u %6u %6u %6u ", 258 so_rcv->sb_hiwat, 259 so_snd->sb_hiwat, 260 so->so_last_pid, 261 so->so_e_pid); 262 } 263 printf("%6d ", kcb->xkp_unit); 264 printf("%6d ", kcb->xkp_kctlid); 265 printf("%s", kcb->xkp_kctlname); 266 printf("\n"); 267 268 } else if (which == ALL_XGN_KIND_EVT) { 269 which = 0; 270 if (first) { 271 printf("Active kernel event sockets\n"); 272 if (Aflag) 273 printf("%16.16s ", "pcb"); 274 printf("%-5.5s %-6.6s %-6.6s ", 275 "Proto", "Recv-Q", "Send-Q"); 276 printf("%6.6s ", "vendor"); 277 printf("%6.6s ", "class"); 278 printf("%6.6s", "subclass"); 279 if (bflag > 0) 280 printf("%10.10s %10.10s ", 281 "rxbytes", "txbytes"); 282 if (vflag > 0) 283 printf("%6.6s %6.6s %6.6s %6.6s", 284 "rhiwat", "shiwat", "pid", "epid"); 285 printf("\n"); 286 first = 0; 287 } 288 if (Aflag) 289 printf("%16llx ", kevb->kep_evtpcb); 290 printf("%-5.5s %6u %6u ", name, 291 so_rcv->sb_cc, 292 so_snd->sb_cc); 293 printf("%6d ", kevb->kep_vendor_code_filter); 294 printf("%6d ", kevb->kep_class_filter); 295 printf("%6d", kevb->kep_subclass_filter); 296 if (bflag > 0) { 297 int i; 298 u_int64_t rxbytes = 0; 299 u_int64_t txbytes = 0; 300 301 for (i = 0; i < SO_TC_STATS_MAX; i++) { 302 rxbytes += so_stat->xst_tc_stats[i].rxbytes; 303 txbytes += so_stat->xst_tc_stats[i].txbytes; 304 } 305 printf("%10llu %10llu ", rxbytes, txbytes); 306 } 307 if (vflag > 0) { 308 printf("%6u %6u %6u %6u", 309 so_rcv->sb_hiwat, 310 so_snd->sb_hiwat, 311 so->so_last_pid, 312 so->so_e_pid); 313 } 314 printf("\n"); 315 } 316 317 } 318 if (xig != oxig && xig->xg_gen != oxig->xg_gen) { 319 if (oxig->xg_count > xig->xg_count) { 320 printf("Some %s sockets may have been deleted.\n", 321 name); 322 } else if (oxig->xg_count < xig->xg_count) { 323 printf("Some %s sockets may have been created.\n", 324 name); 325 } else { 326 printf("Some %s sockets may have been created or deleted", 327 name); 328 } 329 } 330 free(buf); 331} 332 333void 334kctl_stats(uint32_t off __unused, char *name, int af __unused) 335{ 336 static struct kctlstat pkctlstat; 337 struct kctlstat kctlstat; 338 size_t len = sizeof(struct kctlstat); 339 const char *mibvar = "net.systm.kctl.stats"; 340 341 if (sysctlbyname(mibvar, &kctlstat, &len, 0, 0) < 0) { 342 warn("sysctl: %s", mibvar); 343 return; 344 } 345 if (interval && vflag > 0) 346 print_time(); 347 printf ("%s:\n", name); 348 349#define STATDIFF(f) (kctlstat.f - pkctlstat.f) 350#define p(f, m) if (STATDIFF(f) || sflag <= 1) \ 351 printf(m, STATDIFF(f), plural(STATDIFF(f))) 352#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \ 353 printf(m, STATDIFF(f)) 354 355 p(kcs_reg_total, "\t%llu total kernel control module%s registered\n"); 356 p(kcs_reg_count, "\t%llu current kernel control module%s registered\n"); 357 p(kcs_pcbcount, "\t%llu current kernel control socket%s\n"); 358 p1a(kcs_gencnt, "\t%llu kernel control generation count\n"); 359 p(kcs_connections, "\t%llu connection attempt%s\n"); 360 p(kcs_conn_fail, "\t%llu connection failure%s\n"); 361 p(kcs_send_fail, "\t%llu send failure%s\n"); 362 p(kcs_send_list_fail, "\t%llu send list failure%s\n"); 363 p(kcs_enqueue_fail, "\t%llu enqueus failure%s\n"); 364 p(kcs_enqueue_fullsock, "\t%llu packet%s dropped due to full socket buffers\n"); 365 366#undef STATDIFF 367#undef p 368#undef p1a 369 370 if (interval > 0) 371 bcopy(&kctlstat, &pkctlstat, len); 372} 373 374void 375kevt_stats(uint32_t off __unused, char *name, int af __unused) 376{ 377 static struct kevtstat pkevtstat; 378 struct kevtstat kevtstat; 379 size_t len = sizeof(struct kctlstat); 380 const char *mibvar = "net.systm.kevt.stats"; 381 382 if (sysctlbyname(mibvar, &kevtstat, &len, 0, 0) < 0) { 383 warn("sysctl: %s", mibvar); 384 return; 385 } 386 if (interval && vflag > 0) 387 print_time(); 388 printf ("%s:\n", name); 389 390#define STATDIFF(f) (kevtstat.f - pkevtstat.f) 391#define p(f, m) if (STATDIFF(f) || sflag <= 1) \ 392 printf(m, STATDIFF(f), plural(STATDIFF(f))) 393#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \ 394 printf(m, STATDIFF(f)) 395 396 p(kes_pcbcount, "\t%llu current kernel control socket%s\n"); 397 p1a(kes_gencnt, "\t%llu kernel control generation count\n"); 398 p(kes_badvendor, "\t%llu bad vendor failure%s\n"); 399 p(kes_toobig, "\t%llu message too big failure%s\n"); 400 p(kes_nomem, "\t%llu out of memeory failure%s\n"); 401 p(kes_fullsock, "\t%llu message%s dropped due to full socket buffers\n"); 402 p(kes_posted, "\t%llu message posted%s\n"); 403 404 if (interval > 0) 405 bcopy(&kevtstat, &pkevtstat, len); 406} 407