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