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