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/if_private.h> 69 #include <net/debugnet.h> 70 71 #include <netinet/in.h> 72 #include <netinet/in_systm.h> 73 #include <netinet/in_var.h> 74 #include <netinet/ip.h> 75 #include <netinet/ip_var.h> 76 #include <netinet/ip_options.h> 77 #include <netinet/udp.h> 78 #include <netinet/udp_var.h> 79 #include <netinet/netdump/netdump.h> 80 81 #include <machine/in_cksum.h> 82 #include <machine/pcb.h> 83 84 #define NETDDEBUGV(f, ...) do { \ 85 if (nd_debug > 1) \ 86 printf(("%s: " f), __func__, ## __VA_ARGS__); \ 87 } while (0) 88 89 static void netdump_cleanup(void); 90 static int netdump_configure(struct diocskerneldump_arg *, 91 struct thread *); 92 static int netdump_dumper(void *priv __unused, void *virtual, 93 off_t offset, size_t length); 94 static bool netdump_enabled(void); 95 static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS); 96 static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, 97 caddr_t addr, int flags __unused, struct thread *td); 98 static int netdump_modevent(module_t mod, int type, void *priv); 99 static int netdump_start(struct dumperinfo *di, void *key, 100 uint32_t keysize); 101 static void netdump_unconfigure(void); 102 103 /* Must be at least as big as the chunks dumpsys() gives us. */ 104 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE]; 105 static int dump_failed; 106 107 /* Configuration parameters. */ 108 static struct { 109 char ndc_iface[IFNAMSIZ]; 110 union kd_ip ndc_server; 111 union kd_ip ndc_client; 112 union kd_ip ndc_gateway; 113 uint8_t ndc_af; 114 /* Runtime State */ 115 struct debugnet_pcb *nd_pcb; 116 off_t nd_tx_off; 117 size_t nd_buf_len; 118 } nd_conf; 119 #define nd_server nd_conf.ndc_server.in4 120 #define nd_client nd_conf.ndc_client.in4 121 #define nd_gateway nd_conf.ndc_gateway.in4 122 123 /* General dynamic settings. */ 124 static struct sx nd_conf_lk; 125 SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock"); 126 #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk) 127 #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk) 128 #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk) 129 #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk) 130 #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED) 131 #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED) 132 static struct ifnet *nd_ifp; 133 static eventhandler_tag nd_detach_cookie; 134 135 FEATURE(netdump, "Netdump client support"); 136 137 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 138 "netdump parameters"); 139 140 static int nd_debug; 141 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, 142 &nd_debug, 0, 143 "Debug message verbosity"); 144 SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, 145 CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0, 146 netdump_enabled_sysctl, "I", 147 "netdump configuration status"); 148 static char nd_path[MAXPATHLEN]; 149 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, 150 nd_path, sizeof(nd_path), 151 "Server path for output files"); 152 /* 153 * The following three variables were moved to debugnet(4), but these knobs 154 * were retained as aliases. 155 */ 156 SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN, 157 &debugnet_npolls, 0, 158 "Number of times to poll before assuming packet loss (0.5ms per poll)"); 159 SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN, 160 &debugnet_nretries, 0, 161 "Number of retransmit attempts before giving up"); 162 SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN, 163 &debugnet_arp_nretries, 0, 164 "Number of ARP attempts before giving up"); 165 166 static bool nd_is_enabled; 167 static bool 168 netdump_enabled(void) 169 { 170 171 NETDUMP_ASSERT_LOCKED(); 172 return (nd_is_enabled); 173 } 174 175 static void 176 netdump_set_enabled(bool status) 177 { 178 179 NETDUMP_ASSERT_LOCKED(); 180 nd_is_enabled = status; 181 } 182 183 static int 184 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS) 185 { 186 int en, error; 187 188 NETDUMP_RLOCK(); 189 en = netdump_enabled(); 190 NETDUMP_RUNLOCK(); 191 192 error = SYSCTL_OUT(req, &en, sizeof(en)); 193 if (error != 0 || req->newptr == NULL) 194 return (error); 195 return (EPERM); 196 } 197 198 /*- 199 * Dumping specific primitives. 200 */ 201 202 /* 203 * Flush any buffered vmcore data. 204 */ 205 static int 206 netdump_flush_buf(void) 207 { 208 int error; 209 210 error = 0; 211 if (nd_conf.nd_buf_len != 0) { 212 struct debugnet_proto_aux auxdata = { 213 .dp_offset_start = nd_conf.nd_tx_off, 214 }; 215 error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf, 216 nd_conf.nd_buf_len, &auxdata); 217 if (error == 0) 218 nd_conf.nd_buf_len = 0; 219 } 220 return (error); 221 } 222 223 /* 224 * Callback from dumpsys() to dump a chunk of memory. 225 * Copies it out to our static buffer then sends it across the network. 226 * Detects the initial KDH and makes sure it is given a special packet type. 227 * 228 * Parameters: 229 * priv Unused. Optional private pointer. 230 * virtual Virtual address (where to read the data from) 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, 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, void *key, uint32_t keysize) 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 340 /* Send the key before the dump so a partial dump is still usable. */ 341 if (keysize > 0) { 342 if (keysize > sizeof(nd_buf)) { 343 printf("crypto key is too large (%u)\n", keysize); 344 error = EINVAL; 345 goto out; 346 } 347 memcpy(nd_buf, key, keysize); 348 error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize, 349 NULL); 350 if (error != 0) { 351 printf("error %d sending crypto key\n", error); 352 goto out; 353 } 354 } 355 356 out: 357 if (error != 0) { 358 /* As above, squash errors. */ 359 error = EINVAL; 360 netdump_cleanup(); 361 } 362 return (error); 363 } 364 365 static int 366 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh) 367 { 368 int error; 369 370 error = netdump_flush_buf(); 371 if (error != 0) 372 goto out; 373 memcpy(nd_buf, kdh, sizeof(*kdh)); 374 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf, 375 sizeof(*kdh), NULL); 376 out: 377 if (error != 0) 378 netdump_cleanup(); 379 return (error); 380 } 381 382 /* 383 * Cleanup routine for a possibly failed netdump. 384 */ 385 static void 386 netdump_cleanup(void) 387 { 388 if (nd_conf.nd_pcb != NULL) { 389 debugnet_free(nd_conf.nd_pcb); 390 nd_conf.nd_pcb = NULL; 391 } 392 } 393 394 /*- 395 * KLD specific code. 396 */ 397 398 static struct cdevsw netdump_cdevsw = { 399 .d_version = D_VERSION, 400 .d_ioctl = netdump_ioctl, 401 .d_name = "netdump", 402 }; 403 404 static struct cdev *netdump_cdev; 405 406 static void 407 netdump_unconfigure(void) 408 { 409 struct diocskerneldump_arg kda; 410 411 NETDUMP_ASSERT_WLOCKED(); 412 KASSERT(netdump_enabled(), ("%s: not enabled", __func__)); 413 414 bzero(&kda, sizeof(kda)); 415 kda.kda_index = KDA_REMOVE_DEV; 416 (void)dumper_remove(nd_conf.ndc_iface, &kda); 417 418 if (nd_ifp != NULL) 419 if_rele(nd_ifp); 420 nd_ifp = NULL; 421 netdump_set_enabled(false); 422 423 log(LOG_WARNING, "netdump: Lost configured interface %s\n", 424 nd_conf.ndc_iface); 425 426 bzero(&nd_conf, sizeof(nd_conf)); 427 } 428 429 static void 430 netdump_ifdetach(void *arg __unused, struct ifnet *ifp) 431 { 432 433 NETDUMP_WLOCK(); 434 if (ifp == nd_ifp) 435 netdump_unconfigure(); 436 NETDUMP_WUNLOCK(); 437 } 438 439 /* 440 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or 441 * modload-based tunable parameters). 442 */ 443 static int 444 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) 445 { 446 struct ifnet *ifp; 447 448 NETDUMP_ASSERT_WLOCKED(); 449 450 if (conf->kda_iface[0] != 0) { 451 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td))) 452 return (EINVAL); 453 CURVNET_SET(vnet0); 454 ifp = ifunit_ref(conf->kda_iface); 455 CURVNET_RESTORE(); 456 if (!DEBUGNET_SUPPORTED_NIC(ifp)) { 457 if_rele(ifp); 458 return (ENODEV); 459 } 460 } else 461 ifp = NULL; 462 463 if (nd_ifp != NULL) 464 if_rele(nd_ifp); 465 nd_ifp = ifp; 466 netdump_set_enabled(true); 467 468 #define COPY_SIZED(elm) do { \ 469 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \ 470 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \ 471 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \ 472 sizeof(nd_conf.ndc_ ## elm)); \ 473 } while (0) 474 COPY_SIZED(iface); 475 COPY_SIZED(server); 476 COPY_SIZED(client); 477 COPY_SIZED(gateway); 478 COPY_SIZED(af); 479 #undef COPY_SIZED 480 481 return (0); 482 } 483 484 /* 485 * ioctl(2) handler for the netdump device. This is currently only used to 486 * register netdump as a dump device. 487 * 488 * Parameters: 489 * dev, Unused. 490 * cmd, The ioctl to be handled. 491 * addr, The parameter for the ioctl. 492 * flags, Unused. 493 * td, The thread invoking this ioctl. 494 * 495 * Returns: 496 * 0 on success, and an errno value on failure. 497 */ 498 static int 499 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 500 int flags __unused, struct thread *td) 501 { 502 struct diocskerneldump_arg *conf; 503 struct dumperinfo dumper; 504 uint8_t *encryptedkey; 505 int error; 506 507 conf = NULL; 508 error = 0; 509 NETDUMP_WLOCK(); 510 511 switch (cmd) { 512 case DIOCGKERNELDUMP: 513 conf = (void *)addr; 514 /* 515 * For now, index is ignored; netdump doesn't support multiple 516 * configurations (yet). 517 */ 518 if (!netdump_enabled()) { 519 error = ENXIO; 520 conf = NULL; 521 break; 522 } 523 524 if (nd_ifp != NULL) 525 strlcpy(conf->kda_iface, nd_ifp->if_xname, 526 sizeof(conf->kda_iface)); 527 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); 528 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); 529 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); 530 conf->kda_af = nd_conf.ndc_af; 531 conf = NULL; 532 break; 533 case DIOCSKERNELDUMP: 534 encryptedkey = NULL; 535 conf = (void *)addr; 536 537 /* Netdump only supports IP4 at this time. */ 538 if (conf->kda_af != AF_INET) { 539 error = EPROTONOSUPPORT; 540 break; 541 } 542 543 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; 544 if (conf->kda_index == KDA_REMOVE || 545 conf->kda_index == KDA_REMOVE_DEV || 546 conf->kda_index == KDA_REMOVE_ALL) { 547 if (netdump_enabled()) 548 netdump_unconfigure(); 549 if (conf->kda_index == KDA_REMOVE_ALL) 550 error = dumper_remove(NULL, conf); 551 break; 552 } 553 554 error = netdump_configure(conf, td); 555 if (error != 0) 556 break; 557 558 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { 559 if (conf->kda_encryptedkeysize <= 0 || 560 conf->kda_encryptedkeysize > 561 KERNELDUMP_ENCKEY_MAX_SIZE) { 562 error = EINVAL; 563 break; 564 } 565 encryptedkey = malloc(conf->kda_encryptedkeysize, 566 M_TEMP, M_WAITOK); 567 error = copyin(conf->kda_encryptedkey, encryptedkey, 568 conf->kda_encryptedkeysize); 569 if (error != 0) { 570 free(encryptedkey, M_TEMP); 571 break; 572 } 573 574 conf->kda_encryptedkey = encryptedkey; 575 } 576 577 memset(&dumper, 0, sizeof(dumper)); 578 dumper.dumper_start = netdump_start; 579 dumper.dumper_hdr = netdump_write_headers; 580 dumper.dumper = netdump_dumper; 581 dumper.priv = NULL; 582 dumper.blocksize = NETDUMP_DATASIZE; 583 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; 584 dumper.mediaoffset = 0; 585 dumper.mediasize = 0; 586 587 error = dumper_insert(&dumper, conf->kda_iface, conf); 588 zfree(encryptedkey, M_TEMP); 589 if (error != 0) 590 netdump_unconfigure(); 591 break; 592 default: 593 error = ENOTTY; 594 break; 595 } 596 if (conf != NULL) 597 explicit_bzero(conf, sizeof(*conf)); 598 NETDUMP_WUNLOCK(); 599 return (error); 600 } 601 602 /* 603 * Called upon system init or kld load. Initializes the netdump parameters to 604 * sane defaults (locates the first available NIC and uses the first IPv4 IP on 605 * that card as the client IP). Leaves the server IP unconfigured. 606 * 607 * Parameters: 608 * mod, Unused. 609 * what, The module event type. 610 * priv, Unused. 611 * 612 * Returns: 613 * int, An errno value if an error occurred, 0 otherwise. 614 */ 615 static int 616 netdump_modevent(module_t mod __unused, int what, void *priv __unused) 617 { 618 struct diocskerneldump_arg conf; 619 char *arg; 620 int error; 621 622 error = 0; 623 switch (what) { 624 case MOD_LOAD: 625 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, 626 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); 627 if (error != 0) 628 return (error); 629 630 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 631 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY); 632 633 if ((arg = kern_getenv("net.dump.iface")) != NULL) { 634 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); 635 freeenv(arg); 636 637 if ((arg = kern_getenv("net.dump.server")) != NULL) { 638 inet_aton(arg, &conf.kda_server.in4); 639 freeenv(arg); 640 } 641 if ((arg = kern_getenv("net.dump.client")) != NULL) { 642 inet_aton(arg, &conf.kda_client.in4); 643 freeenv(arg); 644 } 645 if ((arg = kern_getenv("net.dump.gateway")) != NULL) { 646 inet_aton(arg, &conf.kda_gateway.in4); 647 freeenv(arg); 648 } 649 conf.kda_af = AF_INET; 650 651 /* Ignore errors; we print a message to the console. */ 652 NETDUMP_WLOCK(); 653 (void)netdump_configure(&conf, NULL); 654 NETDUMP_WUNLOCK(); 655 } 656 break; 657 case MOD_UNLOAD: 658 NETDUMP_WLOCK(); 659 if (netdump_enabled()) { 660 printf("netdump: disabling dump device for unload\n"); 661 netdump_unconfigure(); 662 } 663 NETDUMP_WUNLOCK(); 664 destroy_dev(netdump_cdev); 665 EVENTHANDLER_DEREGISTER(ifnet_departure_event, 666 nd_detach_cookie); 667 break; 668 default: 669 error = EOPNOTSUPP; 670 break; 671 } 672 return (error); 673 } 674 675 static moduledata_t netdump_mod = { 676 "netdump", 677 netdump_modevent, 678 NULL, 679 }; 680 681 MODULE_VERSION(netdump, 1); 682 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 683 684 #ifdef DDB 685 /* 686 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface> 687 * 688 * Order is not significant. 689 * 690 * Currently, this command does not support configuring encryption or 691 * compression. 692 */ 693 DB_COMMAND_FLAGS(netdump, db_netdump_cmd, CS_OWN) 694 { 695 static struct diocskerneldump_arg conf; 696 static char blockbuf[NETDUMP_DATASIZE]; 697 static union { 698 struct dumperinfo di; 699 /* For valid di_devname. */ 700 char di_buf[sizeof(struct dumperinfo) + 1]; 701 } u; 702 703 struct debugnet_ddb_config params; 704 int error; 705 706 error = debugnet_parse_ddb_cmd("netdump", ¶ms); 707 if (error != 0) { 708 db_printf("Error configuring netdump: %d\n", error); 709 return; 710 } 711 712 /* Translate to a netdump dumper config. */ 713 memset(&conf, 0, sizeof(conf)); 714 715 if (params.dd_ifp != NULL) 716 strlcpy(conf.kda_iface, if_name(params.dd_ifp), 717 sizeof(conf.kda_iface)); 718 719 conf.kda_af = AF_INET; 720 conf.kda_server.in4 = (struct in_addr) { params.dd_server }; 721 if (params.dd_has_client) 722 conf.kda_client.in4 = (struct in_addr) { params.dd_client }; 723 else 724 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY }; 725 if (params.dd_has_gateway) 726 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway }; 727 else 728 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY }; 729 730 /* Set the global netdump config to these options. */ 731 error = netdump_configure(&conf, NULL); 732 if (error != 0) { 733 db_printf("Error enabling netdump: %d\n", error); 734 return; 735 } 736 737 /* Fake the generic dump configuration list entry to avoid malloc. */ 738 memset(&u.di_buf, 0, sizeof(u.di_buf)); 739 u.di.dumper_start = netdump_start; 740 u.di.dumper_hdr = netdump_write_headers; 741 u.di.dumper = netdump_dumper; 742 u.di.priv = NULL; 743 u.di.blocksize = NETDUMP_DATASIZE; 744 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE; 745 u.di.mediaoffset = 0; 746 u.di.mediasize = 0; 747 u.di.blockbuf = blockbuf; 748 749 dumper_ddb_insert(&u.di); 750 751 error = doadump(false); 752 753 dumper_ddb_remove(&u.di); 754 if (error != 0) 755 db_printf("Cannot dump: %d\n", error); 756 } 757 #endif /* DDB */ 758