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