1 /*- 2 * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved. 3 * Copyright (c) 2000 Darrell Anderson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * netdump_client.c 30 * FreeBSD subsystem supporting netdump network dumps. 31 * A dedicated server must be running to accept client dumps. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include "opt_ddb.h" 38 39 #include <sys/param.h> 40 #include <sys/conf.h> 41 #include <sys/disk.h> 42 #include <sys/endian.h> 43 #include <sys/eventhandler.h> 44 #include <sys/jail.h> 45 #include <sys/kernel.h> 46 #include <sys/kerneldump.h> 47 #include <sys/mbuf.h> 48 #include <sys/module.h> 49 #include <sys/priv.h> 50 #include <sys/proc.h> 51 #include <sys/protosw.h> 52 #include <sys/socket.h> 53 #include <sys/sysctl.h> 54 #include <sys/syslog.h> 55 #include <sys/systm.h> 56 57 #ifdef DDB 58 #include <ddb/ddb.h> 59 #include <ddb/db_lex.h> 60 #endif 61 62 #include <net/ethernet.h> 63 #include <net/if.h> 64 #include <net/if_arp.h> 65 #include <net/if_dl.h> 66 #include <net/if_types.h> 67 #include <net/if_var.h> 68 #include <net/debugnet.h> 69 70 #include <netinet/in.h> 71 #include <netinet/in_systm.h> 72 #include <netinet/in_var.h> 73 #include <netinet/ip.h> 74 #include <netinet/ip_var.h> 75 #include <netinet/ip_options.h> 76 #include <netinet/udp.h> 77 #include <netinet/udp_var.h> 78 #include <netinet/netdump/netdump.h> 79 80 #include <machine/in_cksum.h> 81 #include <machine/pcb.h> 82 83 #define NETDDEBUGV(f, ...) do { \ 84 if (nd_debug > 1) \ 85 printf(("%s: " f), __func__, ## __VA_ARGS__); \ 86 } while (0) 87 88 static int netdump_configure(struct diocskerneldump_arg *, 89 struct thread *); 90 static int netdump_dumper(void *priv __unused, void *virtual, 91 vm_offset_t physical __unused, off_t offset, size_t length); 92 static bool netdump_enabled(void); 93 static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS); 94 static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, 95 caddr_t addr, int flags __unused, struct thread *td); 96 static int netdump_modevent(module_t mod, int type, void *priv); 97 static int netdump_start(struct dumperinfo *di); 98 static void netdump_unconfigure(void); 99 100 /* Must be at least as big as the chunks dumpsys() gives us. */ 101 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE]; 102 static int dump_failed; 103 104 /* Configuration parameters. */ 105 static struct { 106 char ndc_iface[IFNAMSIZ]; 107 union kd_ip ndc_server; 108 union kd_ip ndc_client; 109 union kd_ip ndc_gateway; 110 uint8_t ndc_af; 111 /* Runtime State */ 112 struct debugnet_pcb *nd_pcb; 113 off_t nd_tx_off; 114 size_t nd_buf_len; 115 } nd_conf; 116 #define nd_server nd_conf.ndc_server.in4 117 #define nd_client nd_conf.ndc_client.in4 118 #define nd_gateway nd_conf.ndc_gateway.in4 119 120 /* General dynamic settings. */ 121 static struct sx nd_conf_lk; 122 SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock"); 123 #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk) 124 #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk) 125 #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk) 126 #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk) 127 #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED) 128 #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED) 129 static struct ifnet *nd_ifp; 130 static eventhandler_tag nd_detach_cookie; 131 132 FEATURE(netdump, "Netdump client support"); 133 134 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL, 135 "netdump parameters"); 136 137 static int nd_debug; 138 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, 139 &nd_debug, 0, 140 "Debug message verbosity"); 141 SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD | CTLTYPE_INT, NULL, 0, 142 netdump_enabled_sysctl, "I", "netdump configuration status"); 143 static char nd_path[MAXPATHLEN]; 144 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, 145 nd_path, sizeof(nd_path), 146 "Server path for output files"); 147 /* 148 * The following three variables were moved to debugnet(4), but these knobs 149 * were retained as aliases. 150 */ 151 SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN, 152 &debugnet_npolls, 0, 153 "Number of times to poll before assuming packet loss (0.5ms per poll)"); 154 SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN, 155 &debugnet_nretries, 0, 156 "Number of retransmit attempts before giving up"); 157 SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN, 158 &debugnet_arp_nretries, 0, 159 "Number of ARP attempts before giving up"); 160 161 static bool nd_is_enabled; 162 static bool 163 netdump_enabled(void) 164 { 165 166 NETDUMP_ASSERT_LOCKED(); 167 return (nd_is_enabled); 168 } 169 170 static void 171 netdump_set_enabled(bool status) 172 { 173 174 NETDUMP_ASSERT_LOCKED(); 175 nd_is_enabled = status; 176 } 177 178 static int 179 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS) 180 { 181 int en, error; 182 183 NETDUMP_RLOCK(); 184 en = netdump_enabled(); 185 NETDUMP_RUNLOCK(); 186 187 error = SYSCTL_OUT(req, &en, sizeof(en)); 188 if (error != 0 || req->newptr == NULL) 189 return (error); 190 return (EPERM); 191 } 192 193 /*- 194 * Dumping specific primitives. 195 */ 196 197 /* 198 * Flush any buffered vmcore data. 199 */ 200 static int 201 netdump_flush_buf(void) 202 { 203 int error; 204 205 error = 0; 206 if (nd_conf.nd_buf_len != 0) { 207 struct debugnet_proto_aux auxdata = { 208 .dp_offset_start = nd_conf.nd_tx_off, 209 }; 210 error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf, 211 nd_conf.nd_buf_len, &auxdata); 212 if (error == 0) 213 nd_conf.nd_buf_len = 0; 214 } 215 return (error); 216 } 217 218 /* 219 * Callback from dumpsys() to dump a chunk of memory. 220 * Copies it out to our static buffer then sends it across the network. 221 * Detects the initial KDH and makes sure it is given a special packet type. 222 * 223 * Parameters: 224 * priv Unused. Optional private pointer. 225 * virtual Virtual address (where to read the data from) 226 * physical Unused. Physical memory address. 227 * offset Offset from start of core file 228 * length Data length 229 * 230 * Return value: 231 * 0 on success 232 * errno on error 233 */ 234 static int 235 netdump_dumper(void *priv __unused, void *virtual, 236 vm_offset_t physical __unused, off_t offset, size_t length) 237 { 238 int error; 239 240 NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n", 241 virtual, (uintmax_t)offset, length); 242 243 if (virtual == NULL) { 244 error = netdump_flush_buf(); 245 if (error != 0) 246 dump_failed = 1; 247 248 if (dump_failed != 0) 249 printf("failed to dump the kernel core\n"); 250 else if ( 251 debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0) 252 printf("failed to close the transaction\n"); 253 else 254 printf("\nnetdump finished.\n"); 255 debugnet_free(nd_conf.nd_pcb); 256 nd_conf.nd_pcb = NULL; 257 return (0); 258 } 259 if (length > sizeof(nd_buf)) 260 return (ENOSPC); 261 262 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) || 263 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off + 264 nd_conf.nd_buf_len != offset)) { 265 error = netdump_flush_buf(); 266 if (error != 0) { 267 dump_failed = 1; 268 return (error); 269 } 270 nd_conf.nd_tx_off = offset; 271 } 272 273 memmove(nd_buf + nd_conf.nd_buf_len, virtual, length); 274 nd_conf.nd_buf_len += length; 275 276 return (0); 277 } 278 279 /* 280 * Perform any initalization needed prior to transmitting the kernel core. 281 */ 282 static int 283 netdump_start(struct dumperinfo *di) 284 { 285 struct debugnet_conn_params dcp; 286 struct debugnet_pcb *pcb; 287 char buf[INET_ADDRSTRLEN]; 288 int error; 289 290 error = 0; 291 292 /* Check if the dumping is allowed to continue. */ 293 if (!netdump_enabled()) 294 return (EINVAL); 295 296 if (!KERNEL_PANICKED()) { 297 printf( 298 "netdump_start: netdump may only be used after a panic\n"); 299 return (EINVAL); 300 } 301 302 memset(&dcp, 0, sizeof(dcp)); 303 304 if (nd_server.s_addr == INADDR_ANY) { 305 printf("netdump_start: can't netdump; no server IP given\n"); 306 return (EINVAL); 307 } 308 309 /* We start dumping at offset 0. */ 310 di->dumpoff = 0; 311 312 dcp.dc_ifp = nd_ifp; 313 314 dcp.dc_client = nd_client.s_addr; 315 dcp.dc_server = nd_server.s_addr; 316 dcp.dc_gateway = nd_gateway.s_addr; 317 318 dcp.dc_herald_port = NETDUMP_PORT; 319 dcp.dc_client_port = NETDUMP_ACKPORT; 320 321 dcp.dc_herald_data = nd_path; 322 dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1; 323 324 error = debugnet_connect(&dcp, &pcb); 325 if (error != 0) { 326 printf("failed to contact netdump server\n"); 327 /* Squash debugnet to something the dumper code understands. */ 328 return (EINVAL); 329 } 330 331 printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf), 332 debugnet_get_gw_mac(pcb), ":"); 333 nd_conf.nd_pcb = pcb; 334 return (0); 335 } 336 337 static int 338 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh, 339 void *key, uint32_t keysize) 340 { 341 int error; 342 343 error = netdump_flush_buf(); 344 if (error != 0) 345 return (error); 346 memcpy(nd_buf, kdh, sizeof(*kdh)); 347 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf, 348 sizeof(*kdh), NULL); 349 if (error == 0 && keysize > 0) { 350 if (keysize > sizeof(nd_buf)) 351 return (EINVAL); 352 memcpy(nd_buf, key, keysize); 353 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_EKCD_KEY, nd_buf, 354 keysize, NULL); 355 } 356 return (error); 357 } 358 359 /*- 360 * KLD specific code. 361 */ 362 363 static struct cdevsw netdump_cdevsw = { 364 .d_version = D_VERSION, 365 .d_ioctl = netdump_ioctl, 366 .d_name = "netdump", 367 }; 368 369 static struct cdev *netdump_cdev; 370 371 static void 372 netdump_unconfigure(void) 373 { 374 struct diocskerneldump_arg kda; 375 376 NETDUMP_ASSERT_WLOCKED(); 377 KASSERT(netdump_enabled(), ("%s: not enabled", __func__)); 378 379 bzero(&kda, sizeof(kda)); 380 kda.kda_index = KDA_REMOVE_DEV; 381 (void)dumper_remove(nd_conf.ndc_iface, &kda); 382 383 if (nd_ifp != NULL) 384 if_rele(nd_ifp); 385 nd_ifp = NULL; 386 netdump_set_enabled(false); 387 388 log(LOG_WARNING, "netdump: Lost configured interface %s\n", 389 nd_conf.ndc_iface); 390 391 bzero(&nd_conf, sizeof(nd_conf)); 392 } 393 394 static void 395 netdump_ifdetach(void *arg __unused, struct ifnet *ifp) 396 { 397 398 NETDUMP_WLOCK(); 399 if (ifp == nd_ifp) 400 netdump_unconfigure(); 401 NETDUMP_WUNLOCK(); 402 } 403 404 /* 405 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or 406 * modload-based tunable parameters). 407 */ 408 static int 409 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) 410 { 411 struct ifnet *ifp; 412 413 NETDUMP_ASSERT_WLOCKED(); 414 415 if (conf->kda_iface[0] != 0) { 416 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td))) 417 return (EINVAL); 418 CURVNET_SET(vnet0); 419 ifp = ifunit_ref(conf->kda_iface); 420 CURVNET_RESTORE(); 421 } else 422 ifp = NULL; 423 424 if (nd_ifp != NULL) 425 if_rele(nd_ifp); 426 nd_ifp = ifp; 427 netdump_set_enabled(true); 428 429 #define COPY_SIZED(elm) do { \ 430 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \ 431 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \ 432 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \ 433 sizeof(nd_conf.ndc_ ## elm)); \ 434 } while (0) 435 COPY_SIZED(iface); 436 COPY_SIZED(server); 437 COPY_SIZED(client); 438 COPY_SIZED(gateway); 439 COPY_SIZED(af); 440 #undef COPY_SIZED 441 442 return (0); 443 } 444 445 /* 446 * ioctl(2) handler for the netdump device. This is currently only used to 447 * register netdump as a dump device. 448 * 449 * Parameters: 450 * dev, Unused. 451 * cmd, The ioctl to be handled. 452 * addr, The parameter for the ioctl. 453 * flags, Unused. 454 * td, The thread invoking this ioctl. 455 * 456 * Returns: 457 * 0 on success, and an errno value on failure. 458 */ 459 static int 460 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 461 int flags __unused, struct thread *td) 462 { 463 struct diocskerneldump_arg kda_copy, *conf; 464 struct dumperinfo dumper; 465 uint8_t *encryptedkey; 466 int error; 467 #ifdef COMPAT_FREEBSD11 468 u_int u; 469 #endif 470 #ifdef COMPAT_FREEBSD12 471 struct diocskerneldump_arg_freebsd12 *kda12; 472 struct netdump_conf_freebsd12 *conf12; 473 #endif 474 475 conf = NULL; 476 error = 0; 477 NETDUMP_WLOCK(); 478 479 switch (cmd) { 480 #ifdef COMPAT_FREEBSD11 481 case DIOCSKERNELDUMP_FREEBSD11: 482 gone_in(13, "11.x ABI compatibility"); 483 u = *(u_int *)addr; 484 if (u != 0) { 485 error = ENXIO; 486 break; 487 } 488 if (netdump_enabled()) 489 netdump_unconfigure(); 490 break; 491 #endif 492 #ifdef COMPAT_FREEBSD12 493 /* 494 * Used by dumpon(8) in 12.x for clearing previous 495 * configuration -- then NETDUMPSCONF_FREEBSD12 is used to 496 * actually configure netdump. 497 */ 498 case DIOCSKERNELDUMP_FREEBSD12: 499 gone_in(14, "12.x ABI compatibility"); 500 501 kda12 = (void *)addr; 502 if (kda12->kda12_enable) { 503 error = ENXIO; 504 break; 505 } 506 if (netdump_enabled()) 507 netdump_unconfigure(); 508 break; 509 510 case NETDUMPGCONF_FREEBSD12: 511 gone_in(14, "FreeBSD 12.x ABI compat"); 512 conf12 = (void *)addr; 513 514 if (!netdump_enabled()) { 515 error = ENXIO; 516 break; 517 } 518 if (nd_conf.ndc_af != AF_INET) { 519 error = EOPNOTSUPP; 520 break; 521 } 522 523 if (nd_ifp != NULL) 524 strlcpy(conf12->ndc12_iface, nd_ifp->if_xname, 525 sizeof(conf12->ndc12_iface)); 526 memcpy(&conf12->ndc12_server, &nd_server, 527 sizeof(conf12->ndc12_server)); 528 memcpy(&conf12->ndc12_client, &nd_client, 529 sizeof(conf12->ndc12_client)); 530 memcpy(&conf12->ndc12_gateway, &nd_gateway, 531 sizeof(conf12->ndc12_gateway)); 532 break; 533 #endif 534 case DIOCGKERNELDUMP: 535 conf = (void *)addr; 536 /* 537 * For now, index is ignored; netdump doesn't support multiple 538 * configurations (yet). 539 */ 540 if (!netdump_enabled()) { 541 error = ENXIO; 542 conf = NULL; 543 break; 544 } 545 546 if (nd_ifp != NULL) 547 strlcpy(conf->kda_iface, nd_ifp->if_xname, 548 sizeof(conf->kda_iface)); 549 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); 550 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); 551 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); 552 conf->kda_af = nd_conf.ndc_af; 553 conf = NULL; 554 break; 555 556 #ifdef COMPAT_FREEBSD12 557 case NETDUMPSCONF_FREEBSD12: 558 gone_in(14, "FreeBSD 12.x ABI compat"); 559 560 conf12 = (struct netdump_conf_freebsd12 *)addr; 561 562 _Static_assert(offsetof(struct diocskerneldump_arg, kda_server) 563 == offsetof(struct netdump_conf_freebsd12, ndc12_server), 564 "simplifying assumption"); 565 566 memset(&kda_copy, 0, sizeof(kda_copy)); 567 memcpy(&kda_copy, conf12, 568 offsetof(struct diocskerneldump_arg, kda_server)); 569 570 /* 12.x ABI could only configure IPv4 (INET) netdump. */ 571 kda_copy.kda_af = AF_INET; 572 memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server, 573 sizeof(struct in_addr)); 574 memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client, 575 sizeof(struct in_addr)); 576 memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway, 577 sizeof(struct in_addr)); 578 579 kda_copy.kda_index = 580 (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL); 581 582 conf = &kda_copy; 583 explicit_bzero(conf12, sizeof(*conf12)); 584 /* FALLTHROUGH */ 585 #endif 586 case DIOCSKERNELDUMP: 587 encryptedkey = NULL; 588 if (cmd == DIOCSKERNELDUMP) { 589 conf = (void *)addr; 590 memcpy(&kda_copy, conf, sizeof(kda_copy)); 591 } 592 /* Netdump only supports IP4 at this time. */ 593 if (conf->kda_af != AF_INET) { 594 error = EPROTONOSUPPORT; 595 break; 596 } 597 598 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; 599 if (conf->kda_index == KDA_REMOVE || 600 conf->kda_index == KDA_REMOVE_DEV || 601 conf->kda_index == KDA_REMOVE_ALL) { 602 if (netdump_enabled()) 603 netdump_unconfigure(); 604 if (conf->kda_index == KDA_REMOVE_ALL) 605 error = dumper_remove(NULL, conf); 606 break; 607 } 608 609 error = netdump_configure(conf, td); 610 if (error != 0) 611 break; 612 613 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { 614 if (conf->kda_encryptedkeysize <= 0 || 615 conf->kda_encryptedkeysize > 616 KERNELDUMP_ENCKEY_MAX_SIZE) { 617 error = EINVAL; 618 break; 619 } 620 encryptedkey = malloc(conf->kda_encryptedkeysize, 621 M_TEMP, M_WAITOK); 622 error = copyin(conf->kda_encryptedkey, encryptedkey, 623 conf->kda_encryptedkeysize); 624 if (error != 0) { 625 free(encryptedkey, M_TEMP); 626 break; 627 } 628 629 conf->kda_encryptedkey = encryptedkey; 630 } 631 632 memset(&dumper, 0, sizeof(dumper)); 633 dumper.dumper_start = netdump_start; 634 dumper.dumper_hdr = netdump_write_headers; 635 dumper.dumper = netdump_dumper; 636 dumper.priv = NULL; 637 dumper.blocksize = NETDUMP_DATASIZE; 638 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; 639 dumper.mediaoffset = 0; 640 dumper.mediasize = 0; 641 642 error = dumper_insert(&dumper, conf->kda_iface, conf); 643 if (encryptedkey != NULL) { 644 explicit_bzero(encryptedkey, 645 conf->kda_encryptedkeysize); 646 free(encryptedkey, M_TEMP); 647 } 648 if (error != 0) 649 netdump_unconfigure(); 650 break; 651 default: 652 error = ENOTTY; 653 break; 654 } 655 explicit_bzero(&kda_copy, sizeof(kda_copy)); 656 if (conf != NULL) 657 explicit_bzero(conf, sizeof(*conf)); 658 NETDUMP_WUNLOCK(); 659 return (error); 660 } 661 662 /* 663 * Called upon system init or kld load. Initializes the netdump parameters to 664 * sane defaults (locates the first available NIC and uses the first IPv4 IP on 665 * that card as the client IP). Leaves the server IP unconfigured. 666 * 667 * Parameters: 668 * mod, Unused. 669 * what, The module event type. 670 * priv, Unused. 671 * 672 * Returns: 673 * int, An errno value if an error occured, 0 otherwise. 674 */ 675 static int 676 netdump_modevent(module_t mod __unused, int what, void *priv __unused) 677 { 678 struct diocskerneldump_arg conf; 679 char *arg; 680 int error; 681 682 error = 0; 683 switch (what) { 684 case MOD_LOAD: 685 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, 686 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); 687 if (error != 0) 688 return (error); 689 690 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 691 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY); 692 693 if ((arg = kern_getenv("net.dump.iface")) != NULL) { 694 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); 695 freeenv(arg); 696 697 if ((arg = kern_getenv("net.dump.server")) != NULL) { 698 inet_aton(arg, &conf.kda_server.in4); 699 freeenv(arg); 700 } 701 if ((arg = kern_getenv("net.dump.client")) != NULL) { 702 inet_aton(arg, &conf.kda_client.in4); 703 freeenv(arg); 704 } 705 if ((arg = kern_getenv("net.dump.gateway")) != NULL) { 706 inet_aton(arg, &conf.kda_gateway.in4); 707 freeenv(arg); 708 } 709 conf.kda_af = AF_INET; 710 711 /* Ignore errors; we print a message to the console. */ 712 NETDUMP_WLOCK(); 713 (void)netdump_configure(&conf, NULL); 714 NETDUMP_WUNLOCK(); 715 } 716 break; 717 case MOD_UNLOAD: 718 NETDUMP_WLOCK(); 719 if (netdump_enabled()) { 720 printf("netdump: disabling dump device for unload\n"); 721 netdump_unconfigure(); 722 } 723 NETDUMP_WUNLOCK(); 724 destroy_dev(netdump_cdev); 725 EVENTHANDLER_DEREGISTER(ifnet_departure_event, 726 nd_detach_cookie); 727 break; 728 default: 729 error = EOPNOTSUPP; 730 break; 731 } 732 return (error); 733 } 734 735 static moduledata_t netdump_mod = { 736 "netdump", 737 netdump_modevent, 738 NULL, 739 }; 740 741 MODULE_VERSION(netdump, 1); 742 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 743 744 #ifdef DDB 745 /* 746 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface> 747 * 748 * Order is not significant. 749 * 750 * Currently, this command does not support configuring encryption or 751 * compression. 752 */ 753 DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL) 754 { 755 static struct diocskerneldump_arg conf; 756 static char blockbuf[NETDUMP_DATASIZE]; 757 static union { 758 struct dumperinfo di; 759 /* For valid di_devname. */ 760 char di_buf[sizeof(struct dumperinfo) + 1]; 761 } u; 762 763 struct debugnet_ddb_config params; 764 int error; 765 766 error = debugnet_parse_ddb_cmd("netdump", ¶ms); 767 if (error != 0) { 768 db_printf("Error configuring netdump: %d\n", error); 769 return; 770 } 771 772 /* Translate to a netdump dumper config. */ 773 memset(&conf, 0, sizeof(conf)); 774 775 if (params.dd_ifp != NULL) 776 strlcpy(conf.kda_iface, if_name(params.dd_ifp), 777 sizeof(conf.kda_iface)); 778 779 conf.kda_af = AF_INET; 780 conf.kda_server.in4 = (struct in_addr) { params.dd_server }; 781 if (params.dd_has_client) 782 conf.kda_client.in4 = (struct in_addr) { params.dd_client }; 783 else 784 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY }; 785 if (params.dd_has_gateway) 786 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway }; 787 else 788 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY }; 789 790 /* Set the global netdump config to these options. */ 791 error = netdump_configure(&conf, NULL); 792 if (error != 0) { 793 db_printf("Error enabling netdump: %d\n", error); 794 return; 795 } 796 797 /* Fake the generic dump configuration list entry to avoid malloc. */ 798 memset(&u.di_buf, 0, sizeof(u.di_buf)); 799 u.di.dumper_start = netdump_start; 800 u.di.dumper_hdr = netdump_write_headers; 801 u.di.dumper = netdump_dumper; 802 u.di.priv = NULL; 803 u.di.blocksize = NETDUMP_DATASIZE; 804 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE; 805 u.di.mediaoffset = 0; 806 u.di.mediasize = 0; 807 u.di.blockbuf = blockbuf; 808 809 dumper_ddb_insert(&u.di); 810 811 error = doadump(false); 812 813 dumper_ddb_remove(&u.di); 814 if (error != 0) 815 db_printf("Cannot dump: %d\n", error); 816 } 817 #endif /* DDB */ 818