1e5054602SMark Johnston /*- 2e5054602SMark Johnston * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved. 3e5054602SMark Johnston * Copyright (c) 2000 Darrell Anderson 4e5054602SMark Johnston * All rights reserved. 5e5054602SMark Johnston * 6e5054602SMark Johnston * Redistribution and use in source and binary forms, with or without 7e5054602SMark Johnston * modification, are permitted provided that the following conditions 8e5054602SMark Johnston * are met: 9e5054602SMark Johnston * 1. Redistributions of source code must retain the above copyright 10e5054602SMark Johnston * notice, this list of conditions and the following disclaimer. 11e5054602SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 12e5054602SMark Johnston * notice, this list of conditions and the following disclaimer in the 13e5054602SMark Johnston * documentation and/or other materials provided with the distribution. 14e5054602SMark Johnston * 15e5054602SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e5054602SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e5054602SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e5054602SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e5054602SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e5054602SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e5054602SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e5054602SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e5054602SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e5054602SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e5054602SMark Johnston * SUCH DAMAGE. 26e5054602SMark Johnston */ 27e5054602SMark Johnston 28e5054602SMark Johnston /* 29e5054602SMark Johnston * netdump_client.c 30e5054602SMark Johnston * FreeBSD subsystem supporting netdump network dumps. 31e5054602SMark Johnston * A dedicated server must be running to accept client dumps. 32e5054602SMark Johnston */ 33e5054602SMark Johnston 34e5054602SMark Johnston #include <sys/cdefs.h> 35e5054602SMark Johnston __FBSDID("$FreeBSD$"); 36e5054602SMark Johnston 378270d35eSConrad Meyer #include "opt_ddb.h" 388270d35eSConrad Meyer 39e5054602SMark Johnston #include <sys/param.h> 40e5054602SMark Johnston #include <sys/conf.h> 41e5054602SMark Johnston #include <sys/disk.h> 42e5054602SMark Johnston #include <sys/endian.h> 4304e0c883SConrad Meyer #include <sys/eventhandler.h> 44b35822d9SMark Johnston #include <sys/jail.h> 45e5054602SMark Johnston #include <sys/kernel.h> 46e5054602SMark Johnston #include <sys/kerneldump.h> 47e5054602SMark Johnston #include <sys/mbuf.h> 48e5054602SMark Johnston #include <sys/module.h> 49e5054602SMark Johnston #include <sys/priv.h> 50e5054602SMark Johnston #include <sys/proc.h> 51e5054602SMark Johnston #include <sys/protosw.h> 52e5054602SMark Johnston #include <sys/socket.h> 53e5054602SMark Johnston #include <sys/sysctl.h> 547790c8c1SConrad Meyer #include <sys/syslog.h> 55e5054602SMark Johnston #include <sys/systm.h> 56e5054602SMark Johnston 578270d35eSConrad Meyer #ifdef DDB 588270d35eSConrad Meyer #include <ddb/ddb.h> 598270d35eSConrad Meyer #include <ddb/db_lex.h> 608270d35eSConrad Meyer #endif 618270d35eSConrad Meyer 62e5054602SMark Johnston #include <net/ethernet.h> 63e5054602SMark Johnston #include <net/if.h> 64e5054602SMark Johnston #include <net/if_arp.h> 65e5054602SMark Johnston #include <net/if_dl.h> 66e5054602SMark Johnston #include <net/if_types.h> 67e5054602SMark Johnston #include <net/if_var.h> 687790c8c1SConrad Meyer #include <net/debugnet.h> 69e5054602SMark Johnston 70e5054602SMark Johnston #include <netinet/in.h> 71e5054602SMark Johnston #include <netinet/in_systm.h> 72e5054602SMark Johnston #include <netinet/in_var.h> 73e5054602SMark Johnston #include <netinet/ip.h> 74e5054602SMark Johnston #include <netinet/ip_var.h> 75e5054602SMark Johnston #include <netinet/ip_options.h> 76e5054602SMark Johnston #include <netinet/udp.h> 77e5054602SMark Johnston #include <netinet/udp_var.h> 78e5054602SMark Johnston #include <netinet/netdump/netdump.h> 79e5054602SMark Johnston 80e5054602SMark Johnston #include <machine/in_cksum.h> 81e5054602SMark Johnston #include <machine/pcb.h> 82e5054602SMark Johnston 83e5054602SMark Johnston #define NETDDEBUGV(f, ...) do { \ 84e5054602SMark Johnston if (nd_debug > 1) \ 85e5054602SMark Johnston printf(("%s: " f), __func__, ## __VA_ARGS__); \ 86e5054602SMark Johnston } while (0) 87e5054602SMark Johnston 88a5732433SBryan Drewery static void netdump_cleanup(void); 896b6e2954SConrad Meyer static int netdump_configure(struct diocskerneldump_arg *, 906b6e2954SConrad Meyer struct thread *); 91e5054602SMark Johnston static int netdump_dumper(void *priv __unused, void *virtual, 92e5054602SMark Johnston vm_offset_t physical __unused, off_t offset, size_t length); 9364e7d18fSConrad Meyer static bool netdump_enabled(void); 9464e7d18fSConrad Meyer static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS); 95e5054602SMark Johnston static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, 96e5054602SMark Johnston caddr_t addr, int flags __unused, struct thread *td); 97e5054602SMark Johnston static int netdump_modevent(module_t mod, int type, void *priv); 98*13a58148SEric van Gyzen static int netdump_start(struct dumperinfo *di, void *key, 99*13a58148SEric van Gyzen uint32_t keysize); 10064e7d18fSConrad Meyer static void netdump_unconfigure(void); 101e5054602SMark Johnston 102e5054602SMark Johnston /* Must be at least as big as the chunks dumpsys() gives us. */ 103e5054602SMark Johnston static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE]; 1047790c8c1SConrad Meyer static int dump_failed; 105e5054602SMark Johnston 106e5054602SMark Johnston /* Configuration parameters. */ 1076144b50fSConrad Meyer static struct { 1086144b50fSConrad Meyer char ndc_iface[IFNAMSIZ]; 1096144b50fSConrad Meyer union kd_ip ndc_server; 1106144b50fSConrad Meyer union kd_ip ndc_client; 1116144b50fSConrad Meyer union kd_ip ndc_gateway; 1126144b50fSConrad Meyer uint8_t ndc_af; 1138726929dSMark Johnston /* Runtime State */ 1147790c8c1SConrad Meyer struct debugnet_pcb *nd_pcb; 1158726929dSMark Johnston off_t nd_tx_off; 1168726929dSMark Johnston size_t nd_buf_len; 1176144b50fSConrad Meyer } nd_conf; 1186144b50fSConrad Meyer #define nd_server nd_conf.ndc_server.in4 1196144b50fSConrad Meyer #define nd_client nd_conf.ndc_client.in4 1206144b50fSConrad Meyer #define nd_gateway nd_conf.ndc_gateway.in4 121e5054602SMark Johnston 122e5054602SMark Johnston /* General dynamic settings. */ 12364e7d18fSConrad Meyer static struct sx nd_conf_lk; 12464e7d18fSConrad Meyer SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock"); 12564e7d18fSConrad Meyer #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk) 12664e7d18fSConrad Meyer #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk) 12764e7d18fSConrad Meyer #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk) 12864e7d18fSConrad Meyer #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk) 12964e7d18fSConrad Meyer #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED) 13064e7d18fSConrad Meyer #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED) 131e5054602SMark Johnston static struct ifnet *nd_ifp; 13264e7d18fSConrad Meyer static eventhandler_tag nd_detach_cookie; 133e5054602SMark Johnston 134e5054602SMark Johnston FEATURE(netdump, "Netdump client support"); 135e5054602SMark Johnston 1367029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 137e5054602SMark Johnston "netdump parameters"); 138e5054602SMark Johnston 139e5054602SMark Johnston static int nd_debug; 140e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, 141e5054602SMark Johnston &nd_debug, 0, 142e5054602SMark Johnston "Debug message verbosity"); 1437029da5cSPawel Biernacki SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, 1447029da5cSPawel Biernacki CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0, 1457029da5cSPawel Biernacki netdump_enabled_sysctl, "I", 1467029da5cSPawel Biernacki "netdump configuration status"); 147e5054602SMark Johnston static char nd_path[MAXPATHLEN]; 148e5054602SMark Johnston SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, 149e5054602SMark Johnston nd_path, sizeof(nd_path), 150e5054602SMark Johnston "Server path for output files"); 1517790c8c1SConrad Meyer /* 1527790c8c1SConrad Meyer * The following three variables were moved to debugnet(4), but these knobs 1537790c8c1SConrad Meyer * were retained as aliases. 1547790c8c1SConrad Meyer */ 155da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN, 1567790c8c1SConrad Meyer &debugnet_npolls, 0, 157da7d7778SMark Johnston "Number of times to poll before assuming packet loss (0.5ms per poll)"); 158da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN, 1597790c8c1SConrad Meyer &debugnet_nretries, 0, 160da7d7778SMark Johnston "Number of retransmit attempts before giving up"); 161da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN, 1627790c8c1SConrad Meyer &debugnet_arp_nretries, 0, 163da7d7778SMark Johnston "Number of ARP attempts before giving up"); 164e5054602SMark Johnston 165fde2cf65SConrad Meyer static bool nd_is_enabled; 16664e7d18fSConrad Meyer static bool 16764e7d18fSConrad Meyer netdump_enabled(void) 16864e7d18fSConrad Meyer { 16964e7d18fSConrad Meyer 17064e7d18fSConrad Meyer NETDUMP_ASSERT_LOCKED(); 171fde2cf65SConrad Meyer return (nd_is_enabled); 172fde2cf65SConrad Meyer } 173fde2cf65SConrad Meyer 174fde2cf65SConrad Meyer static void 175fde2cf65SConrad Meyer netdump_set_enabled(bool status) 176fde2cf65SConrad Meyer { 177fde2cf65SConrad Meyer 178fde2cf65SConrad Meyer NETDUMP_ASSERT_LOCKED(); 179fde2cf65SConrad Meyer nd_is_enabled = status; 18064e7d18fSConrad Meyer } 18164e7d18fSConrad Meyer 18264e7d18fSConrad Meyer static int 18364e7d18fSConrad Meyer netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS) 18464e7d18fSConrad Meyer { 18564e7d18fSConrad Meyer int en, error; 18664e7d18fSConrad Meyer 18764e7d18fSConrad Meyer NETDUMP_RLOCK(); 18864e7d18fSConrad Meyer en = netdump_enabled(); 18964e7d18fSConrad Meyer NETDUMP_RUNLOCK(); 19064e7d18fSConrad Meyer 19164e7d18fSConrad Meyer error = SYSCTL_OUT(req, &en, sizeof(en)); 19264e7d18fSConrad Meyer if (error != 0 || req->newptr == NULL) 19364e7d18fSConrad Meyer return (error); 19464e7d18fSConrad Meyer return (EPERM); 19564e7d18fSConrad Meyer } 19664e7d18fSConrad Meyer 197e5054602SMark Johnston /*- 198e5054602SMark Johnston * Dumping specific primitives. 199e5054602SMark Johnston */ 200e5054602SMark Johnston 201e5054602SMark Johnston /* 202ccdc9866SMark Johnston * Flush any buffered vmcore data. 203ccdc9866SMark Johnston */ 204ccdc9866SMark Johnston static int 205ccdc9866SMark Johnston netdump_flush_buf(void) 206ccdc9866SMark Johnston { 207ccdc9866SMark Johnston int error; 208ccdc9866SMark Johnston 209ccdc9866SMark Johnston error = 0; 210ccdc9866SMark Johnston if (nd_conf.nd_buf_len != 0) { 2117790c8c1SConrad Meyer struct debugnet_proto_aux auxdata = { 2127790c8c1SConrad Meyer .dp_offset_start = nd_conf.nd_tx_off, 2137790c8c1SConrad Meyer }; 2147790c8c1SConrad Meyer error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf, 2157790c8c1SConrad Meyer nd_conf.nd_buf_len, &auxdata); 216ccdc9866SMark Johnston if (error == 0) 217ccdc9866SMark Johnston nd_conf.nd_buf_len = 0; 218ccdc9866SMark Johnston } 219ccdc9866SMark Johnston return (error); 220ccdc9866SMark Johnston } 221ccdc9866SMark Johnston 222ccdc9866SMark Johnston /* 223e5054602SMark Johnston * Callback from dumpsys() to dump a chunk of memory. 224e5054602SMark Johnston * Copies it out to our static buffer then sends it across the network. 225e5054602SMark Johnston * Detects the initial KDH and makes sure it is given a special packet type. 226e5054602SMark Johnston * 227e5054602SMark Johnston * Parameters: 228e5054602SMark Johnston * priv Unused. Optional private pointer. 229e5054602SMark Johnston * virtual Virtual address (where to read the data from) 230e5054602SMark Johnston * physical Unused. Physical memory address. 231e5054602SMark Johnston * offset Offset from start of core file 232e5054602SMark Johnston * length Data length 233e5054602SMark Johnston * 234e5054602SMark Johnston * Return value: 235e5054602SMark Johnston * 0 on success 236e5054602SMark Johnston * errno on error 237e5054602SMark Johnston */ 238e5054602SMark Johnston static int 239e5054602SMark Johnston netdump_dumper(void *priv __unused, void *virtual, 240e5054602SMark Johnston vm_offset_t physical __unused, off_t offset, size_t length) 241e5054602SMark Johnston { 242e5054602SMark Johnston int error; 243e5054602SMark Johnston 244e5054602SMark Johnston NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n", 245e5054602SMark Johnston virtual, (uintmax_t)offset, length); 246e5054602SMark Johnston 247e5054602SMark Johnston if (virtual == NULL) { 248ccdc9866SMark Johnston error = netdump_flush_buf(); 249ccdc9866SMark Johnston if (error != 0) 2508726929dSMark Johnston dump_failed = 1; 2518726929dSMark Johnston 252e5054602SMark Johnston if (dump_failed != 0) 253e5054602SMark Johnston printf("failed to dump the kernel core\n"); 2547790c8c1SConrad Meyer else if ( 2557790c8c1SConrad Meyer debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0) 256e5054602SMark Johnston printf("failed to close the transaction\n"); 257e5054602SMark Johnston else 258e5054602SMark Johnston printf("\nnetdump finished.\n"); 259a5732433SBryan Drewery netdump_cleanup(); 260e5054602SMark Johnston return (0); 261e5054602SMark Johnston } 262a5732433SBryan Drewery if (length > sizeof(nd_buf)) { 263a5732433SBryan Drewery netdump_cleanup(); 264e5054602SMark Johnston return (ENOSPC); 265a5732433SBryan Drewery } 266e5054602SMark Johnston 2678726929dSMark Johnston if (nd_conf.nd_buf_len + length > sizeof(nd_buf) || 2688726929dSMark Johnston (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off + 2698726929dSMark Johnston nd_conf.nd_buf_len != offset)) { 270ccdc9866SMark Johnston error = netdump_flush_buf(); 271e5054602SMark Johnston if (error != 0) { 272e5054602SMark Johnston dump_failed = 1; 273a5732433SBryan Drewery netdump_cleanup(); 274e5054602SMark Johnston return (error); 275e5054602SMark Johnston } 2768726929dSMark Johnston nd_conf.nd_tx_off = offset; 2778726929dSMark Johnston } 2788726929dSMark Johnston 2798726929dSMark Johnston memmove(nd_buf + nd_conf.nd_buf_len, virtual, length); 2808726929dSMark Johnston nd_conf.nd_buf_len += length; 2818726929dSMark Johnston 282e5054602SMark Johnston return (0); 283e5054602SMark Johnston } 284e5054602SMark Johnston 285e5054602SMark Johnston /* 2865aa0576bSEd Maste * Perform any initialization needed prior to transmitting the kernel core. 287e5054602SMark Johnston */ 288e5054602SMark Johnston static int 289*13a58148SEric van Gyzen netdump_start(struct dumperinfo *di, void *key, uint32_t keysize) 290e5054602SMark Johnston { 2917790c8c1SConrad Meyer struct debugnet_conn_params dcp; 2927790c8c1SConrad Meyer struct debugnet_pcb *pcb; 293e5054602SMark Johnston char buf[INET_ADDRSTRLEN]; 294e5054602SMark Johnston int error; 295e5054602SMark Johnston 296e5054602SMark Johnston error = 0; 297e5054602SMark Johnston 298e5054602SMark Johnston /* Check if the dumping is allowed to continue. */ 29964e7d18fSConrad Meyer if (!netdump_enabled()) 300e5054602SMark Johnston return (EINVAL); 301e5054602SMark Johnston 302879e0604SMateusz Guzik if (!KERNEL_PANICKED()) { 303e5054602SMark Johnston printf( 304e5054602SMark Johnston "netdump_start: netdump may only be used after a panic\n"); 305e5054602SMark Johnston return (EINVAL); 306e5054602SMark Johnston } 307e5054602SMark Johnston 3087790c8c1SConrad Meyer memset(&dcp, 0, sizeof(dcp)); 3097790c8c1SConrad Meyer 310e5054602SMark Johnston if (nd_server.s_addr == INADDR_ANY) { 311e5054602SMark Johnston printf("netdump_start: can't netdump; no server IP given\n"); 312e5054602SMark Johnston return (EINVAL); 313e5054602SMark Johnston } 314e5054602SMark Johnston 315e5054602SMark Johnston /* We start dumping at offset 0. */ 316e5054602SMark Johnston di->dumpoff = 0; 317e5054602SMark Johnston 3187790c8c1SConrad Meyer dcp.dc_ifp = nd_ifp; 319e5054602SMark Johnston 3207790c8c1SConrad Meyer dcp.dc_client = nd_client.s_addr; 3217790c8c1SConrad Meyer dcp.dc_server = nd_server.s_addr; 3227790c8c1SConrad Meyer dcp.dc_gateway = nd_gateway.s_addr; 323e5054602SMark Johnston 3247790c8c1SConrad Meyer dcp.dc_herald_port = NETDUMP_PORT; 325e9c69625SConrad Meyer dcp.dc_client_port = NETDUMP_ACKPORT; 326e5054602SMark Johnston 3277790c8c1SConrad Meyer dcp.dc_herald_data = nd_path; 3287790c8c1SConrad Meyer dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1; 329e5054602SMark Johnston 3307790c8c1SConrad Meyer error = debugnet_connect(&dcp, &pcb); 3317790c8c1SConrad Meyer if (error != 0) { 332e5054602SMark Johnston printf("failed to contact netdump server\n"); 3337790c8c1SConrad Meyer /* Squash debugnet to something the dumper code understands. */ 3347790c8c1SConrad Meyer return (EINVAL); 335e5054602SMark Johnston } 336e5054602SMark Johnston 3377790c8c1SConrad Meyer printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf), 3387790c8c1SConrad Meyer debugnet_get_gw_mac(pcb), ":"); 3397790c8c1SConrad Meyer nd_conf.nd_pcb = pcb; 340*13a58148SEric van Gyzen 341*13a58148SEric van Gyzen /* Send the key before the dump so a partial dump is still usable. */ 342*13a58148SEric van Gyzen if (keysize > 0) { 343*13a58148SEric van Gyzen if (keysize > sizeof(nd_buf)) { 344*13a58148SEric van Gyzen printf("crypto key is too large (%u)\n", keysize); 345*13a58148SEric van Gyzen error = EINVAL; 346*13a58148SEric van Gyzen goto out; 347*13a58148SEric van Gyzen } 348*13a58148SEric van Gyzen memcpy(nd_buf, key, keysize); 349*13a58148SEric van Gyzen error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize, 350*13a58148SEric van Gyzen NULL); 351*13a58148SEric van Gyzen if (error != 0) { 352*13a58148SEric van Gyzen printf("error %d sending crypto key\n", error); 353*13a58148SEric van Gyzen goto out; 354*13a58148SEric van Gyzen } 355*13a58148SEric van Gyzen } 356*13a58148SEric van Gyzen 357*13a58148SEric van Gyzen out: 358*13a58148SEric van Gyzen if (error != 0) { 359*13a58148SEric van Gyzen /* As above, squash errors. */ 360*13a58148SEric van Gyzen error = EINVAL; 361*13a58148SEric van Gyzen netdump_cleanup(); 362*13a58148SEric van Gyzen } 363*13a58148SEric van Gyzen return (error); 364e5054602SMark Johnston } 365e5054602SMark Johnston 366e5054602SMark Johnston static int 367*13a58148SEric van Gyzen netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh) 368e5054602SMark Johnston { 369e5054602SMark Johnston int error; 370e5054602SMark Johnston 371ccdc9866SMark Johnston error = netdump_flush_buf(); 372ccdc9866SMark Johnston if (error != 0) 373a5732433SBryan Drewery goto out; 374e5054602SMark Johnston memcpy(nd_buf, kdh, sizeof(*kdh)); 3757790c8c1SConrad Meyer error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf, 3767790c8c1SConrad Meyer sizeof(*kdh), NULL); 377a5732433SBryan Drewery out: 378a5732433SBryan Drewery if (error != 0) 379a5732433SBryan Drewery netdump_cleanup(); 380e5054602SMark Johnston return (error); 381e5054602SMark Johnston } 382e5054602SMark Johnston 383a5732433SBryan Drewery /* 384a5732433SBryan Drewery * Cleanup routine for a possibly failed netdump. 385a5732433SBryan Drewery */ 386a5732433SBryan Drewery static void 387a5732433SBryan Drewery netdump_cleanup(void) 388a5732433SBryan Drewery { 389a5732433SBryan Drewery if (nd_conf.nd_pcb != NULL) { 390a5732433SBryan Drewery debugnet_free(nd_conf.nd_pcb); 391a5732433SBryan Drewery nd_conf.nd_pcb = NULL; 392a5732433SBryan Drewery } 393a5732433SBryan Drewery } 394a5732433SBryan Drewery 395e5054602SMark Johnston /*- 396e5054602SMark Johnston * KLD specific code. 397e5054602SMark Johnston */ 398e5054602SMark Johnston 399e5054602SMark Johnston static struct cdevsw netdump_cdevsw = { 400e5054602SMark Johnston .d_version = D_VERSION, 401e5054602SMark Johnston .d_ioctl = netdump_ioctl, 402e5054602SMark Johnston .d_name = "netdump", 403e5054602SMark Johnston }; 404e5054602SMark Johnston 405e5054602SMark Johnston static struct cdev *netdump_cdev; 406e5054602SMark Johnston 40764e7d18fSConrad Meyer static void 40864e7d18fSConrad Meyer netdump_unconfigure(void) 40964e7d18fSConrad Meyer { 41064e7d18fSConrad Meyer struct diocskerneldump_arg kda; 41164e7d18fSConrad Meyer 41264e7d18fSConrad Meyer NETDUMP_ASSERT_WLOCKED(); 413fde2cf65SConrad Meyer KASSERT(netdump_enabled(), ("%s: not enabled", __func__)); 41464e7d18fSConrad Meyer 41564e7d18fSConrad Meyer bzero(&kda, sizeof(kda)); 41664e7d18fSConrad Meyer kda.kda_index = KDA_REMOVE_DEV; 41764e7d18fSConrad Meyer (void)dumper_remove(nd_conf.ndc_iface, &kda); 41864e7d18fSConrad Meyer 419fde2cf65SConrad Meyer if (nd_ifp != NULL) 42064e7d18fSConrad Meyer if_rele(nd_ifp); 42164e7d18fSConrad Meyer nd_ifp = NULL; 422fde2cf65SConrad Meyer netdump_set_enabled(false); 42364e7d18fSConrad Meyer 4247790c8c1SConrad Meyer log(LOG_WARNING, "netdump: Lost configured interface %s\n", 4257790c8c1SConrad Meyer nd_conf.ndc_iface); 4267790c8c1SConrad Meyer 42764e7d18fSConrad Meyer bzero(&nd_conf, sizeof(nd_conf)); 42864e7d18fSConrad Meyer } 42964e7d18fSConrad Meyer 43064e7d18fSConrad Meyer static void 43164e7d18fSConrad Meyer netdump_ifdetach(void *arg __unused, struct ifnet *ifp) 43264e7d18fSConrad Meyer { 43364e7d18fSConrad Meyer 43464e7d18fSConrad Meyer NETDUMP_WLOCK(); 43564e7d18fSConrad Meyer if (ifp == nd_ifp) 43664e7d18fSConrad Meyer netdump_unconfigure(); 43764e7d18fSConrad Meyer NETDUMP_WUNLOCK(); 43864e7d18fSConrad Meyer } 43964e7d18fSConrad Meyer 4408270d35eSConrad Meyer /* 4418270d35eSConrad Meyer * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or 4428270d35eSConrad Meyer * modload-based tunable parameters). 4438270d35eSConrad Meyer */ 444e5054602SMark Johnston static int 4456b6e2954SConrad Meyer netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) 446e5054602SMark Johnston { 447e5054602SMark Johnston struct ifnet *ifp; 448e5054602SMark Johnston 44964e7d18fSConrad Meyer NETDUMP_ASSERT_WLOCKED(); 45064e7d18fSConrad Meyer 451fde2cf65SConrad Meyer if (conf->kda_iface[0] != 0) { 4524ad8cb68SMichael Tuexen if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td))) 453b35822d9SMark Johnston return (EINVAL); 4544ad8cb68SMichael Tuexen CURVNET_SET(vnet0); 45564e7d18fSConrad Meyer ifp = ifunit_ref(conf->kda_iface); 456b35822d9SMark Johnston CURVNET_RESTORE(); 457fde2cf65SConrad Meyer } else 458fde2cf65SConrad Meyer ifp = NULL; 459e5054602SMark Johnston 460fde2cf65SConrad Meyer if (nd_ifp != NULL) 46164e7d18fSConrad Meyer if_rele(nd_ifp); 462e5054602SMark Johnston nd_ifp = ifp; 463fde2cf65SConrad Meyer netdump_set_enabled(true); 4646144b50fSConrad Meyer 4656144b50fSConrad Meyer #define COPY_SIZED(elm) do { \ 4666144b50fSConrad Meyer _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \ 4676144b50fSConrad Meyer sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \ 4686144b50fSConrad Meyer memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \ 4696144b50fSConrad Meyer sizeof(nd_conf.ndc_ ## elm)); \ 4706144b50fSConrad Meyer } while (0) 4716144b50fSConrad Meyer COPY_SIZED(iface); 4726144b50fSConrad Meyer COPY_SIZED(server); 4736144b50fSConrad Meyer COPY_SIZED(client); 4746144b50fSConrad Meyer COPY_SIZED(gateway); 4756144b50fSConrad Meyer COPY_SIZED(af); 4766144b50fSConrad Meyer #undef COPY_SIZED 47764e7d18fSConrad Meyer 478e5054602SMark Johnston return (0); 479e5054602SMark Johnston } 480e5054602SMark Johnston 481e5054602SMark Johnston /* 482e5054602SMark Johnston * ioctl(2) handler for the netdump device. This is currently only used to 483e5054602SMark Johnston * register netdump as a dump device. 484e5054602SMark Johnston * 485e5054602SMark Johnston * Parameters: 486e5054602SMark Johnston * dev, Unused. 487e5054602SMark Johnston * cmd, The ioctl to be handled. 488e5054602SMark Johnston * addr, The parameter for the ioctl. 489e5054602SMark Johnston * flags, Unused. 490e5054602SMark Johnston * td, The thread invoking this ioctl. 491e5054602SMark Johnston * 492e5054602SMark Johnston * Returns: 493e5054602SMark Johnston * 0 on success, and an errno value on failure. 494e5054602SMark Johnston */ 495e5054602SMark Johnston static int 496e5054602SMark Johnston netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 497e5054602SMark Johnston int flags __unused, struct thread *td) 498e5054602SMark Johnston { 4996b6e2954SConrad Meyer struct diocskerneldump_arg kda_copy, *conf; 500e5054602SMark Johnston struct dumperinfo dumper; 501e5054602SMark Johnston uint8_t *encryptedkey; 502e5054602SMark Johnston int error; 503a9f7f192SConrad Meyer #ifdef COMPAT_FREEBSD11 504e5054602SMark Johnston u_int u; 505a9f7f192SConrad Meyer #endif 5066b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 5076b6e2954SConrad Meyer struct diocskerneldump_arg_freebsd12 *kda12; 5086b6e2954SConrad Meyer struct netdump_conf_freebsd12 *conf12; 5096b6e2954SConrad Meyer #endif 510e5054602SMark Johnston 5116b6e2954SConrad Meyer conf = NULL; 512e5054602SMark Johnston error = 0; 51364e7d18fSConrad Meyer NETDUMP_WLOCK(); 51464e7d18fSConrad Meyer 515e5054602SMark Johnston switch (cmd) { 51660ade167SConrad Meyer #ifdef COMPAT_FREEBSD11 51760ade167SConrad Meyer case DIOCSKERNELDUMP_FREEBSD11: 5186b6e2954SConrad Meyer gone_in(13, "11.x ABI compatibility"); 519e5054602SMark Johnston u = *(u_int *)addr; 520e5054602SMark Johnston if (u != 0) { 521e5054602SMark Johnston error = ENXIO; 522e5054602SMark Johnston break; 523e5054602SMark Johnston } 52464e7d18fSConrad Meyer if (netdump_enabled()) 52564e7d18fSConrad Meyer netdump_unconfigure(); 52660ade167SConrad Meyer break; 52760ade167SConrad Meyer #endif 5286b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 5296b6e2954SConrad Meyer /* 5306b6e2954SConrad Meyer * Used by dumpon(8) in 12.x for clearing previous 5316b6e2954SConrad Meyer * configuration -- then NETDUMPSCONF_FREEBSD12 is used to 5326b6e2954SConrad Meyer * actually configure netdump. 5336b6e2954SConrad Meyer */ 5346b6e2954SConrad Meyer case DIOCSKERNELDUMP_FREEBSD12: 5356b6e2954SConrad Meyer gone_in(14, "12.x ABI compatibility"); 5366b6e2954SConrad Meyer 5376b6e2954SConrad Meyer kda12 = (void *)addr; 5386b6e2954SConrad Meyer if (kda12->kda12_enable) { 53960ade167SConrad Meyer error = ENXIO; 54060ade167SConrad Meyer break; 54160ade167SConrad Meyer } 54264e7d18fSConrad Meyer if (netdump_enabled()) 54364e7d18fSConrad Meyer netdump_unconfigure(); 544e5054602SMark Johnston break; 5456b6e2954SConrad Meyer 5466b6e2954SConrad Meyer case NETDUMPGCONF_FREEBSD12: 5476b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 5486b6e2954SConrad Meyer conf12 = (void *)addr; 5496b6e2954SConrad Meyer 55064e7d18fSConrad Meyer if (!netdump_enabled()) { 551e5054602SMark Johnston error = ENXIO; 552e5054602SMark Johnston break; 553e5054602SMark Johnston } 5546144b50fSConrad Meyer if (nd_conf.ndc_af != AF_INET) { 5556b6e2954SConrad Meyer error = EOPNOTSUPP; 556e5054602SMark Johnston break; 5576b6e2954SConrad Meyer } 558e5054602SMark Johnston 559fde2cf65SConrad Meyer if (nd_ifp != NULL) 5606b6e2954SConrad Meyer strlcpy(conf12->ndc12_iface, nd_ifp->if_xname, 5616b6e2954SConrad Meyer sizeof(conf12->ndc12_iface)); 5626b6e2954SConrad Meyer memcpy(&conf12->ndc12_server, &nd_server, 5636b6e2954SConrad Meyer sizeof(conf12->ndc12_server)); 5646b6e2954SConrad Meyer memcpy(&conf12->ndc12_client, &nd_client, 5656b6e2954SConrad Meyer sizeof(conf12->ndc12_client)); 5666b6e2954SConrad Meyer memcpy(&conf12->ndc12_gateway, &nd_gateway, 5676b6e2954SConrad Meyer sizeof(conf12->ndc12_gateway)); 5686b6e2954SConrad Meyer break; 5696b6e2954SConrad Meyer #endif 5706b6e2954SConrad Meyer case DIOCGKERNELDUMP: 5716b6e2954SConrad Meyer conf = (void *)addr; 5726b6e2954SConrad Meyer /* 5736b6e2954SConrad Meyer * For now, index is ignored; netdump doesn't support multiple 5746b6e2954SConrad Meyer * configurations (yet). 5756b6e2954SConrad Meyer */ 57664e7d18fSConrad Meyer if (!netdump_enabled()) { 5776b6e2954SConrad Meyer error = ENXIO; 5786b6e2954SConrad Meyer conf = NULL; 5796b6e2954SConrad Meyer break; 5806b6e2954SConrad Meyer } 5816b6e2954SConrad Meyer 582fde2cf65SConrad Meyer if (nd_ifp != NULL) 5836b6e2954SConrad Meyer strlcpy(conf->kda_iface, nd_ifp->if_xname, 5846b6e2954SConrad Meyer sizeof(conf->kda_iface)); 5856b6e2954SConrad Meyer memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); 5866b6e2954SConrad Meyer memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); 5876b6e2954SConrad Meyer memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); 5886144b50fSConrad Meyer conf->kda_af = nd_conf.ndc_af; 5896b6e2954SConrad Meyer conf = NULL; 5906b6e2954SConrad Meyer break; 5916b6e2954SConrad Meyer 5926b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 5936b6e2954SConrad Meyer case NETDUMPSCONF_FREEBSD12: 5946b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 5956b6e2954SConrad Meyer 5966b6e2954SConrad Meyer conf12 = (struct netdump_conf_freebsd12 *)addr; 5976b6e2954SConrad Meyer 5986b6e2954SConrad Meyer _Static_assert(offsetof(struct diocskerneldump_arg, kda_server) 5996b6e2954SConrad Meyer == offsetof(struct netdump_conf_freebsd12, ndc12_server), 6006b6e2954SConrad Meyer "simplifying assumption"); 6016b6e2954SConrad Meyer 6026b6e2954SConrad Meyer memset(&kda_copy, 0, sizeof(kda_copy)); 6036b6e2954SConrad Meyer memcpy(&kda_copy, conf12, 6046b6e2954SConrad Meyer offsetof(struct diocskerneldump_arg, kda_server)); 6056b6e2954SConrad Meyer 6066b6e2954SConrad Meyer /* 12.x ABI could only configure IPv4 (INET) netdump. */ 6076b6e2954SConrad Meyer kda_copy.kda_af = AF_INET; 6086b6e2954SConrad Meyer memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server, 6096b6e2954SConrad Meyer sizeof(struct in_addr)); 6106b6e2954SConrad Meyer memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client, 6116b6e2954SConrad Meyer sizeof(struct in_addr)); 6126b6e2954SConrad Meyer memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway, 6136b6e2954SConrad Meyer sizeof(struct in_addr)); 6146b6e2954SConrad Meyer 6156b6e2954SConrad Meyer kda_copy.kda_index = 6166b6e2954SConrad Meyer (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL); 6176b6e2954SConrad Meyer 6186b6e2954SConrad Meyer conf = &kda_copy; 6196b6e2954SConrad Meyer explicit_bzero(conf12, sizeof(*conf12)); 6206b6e2954SConrad Meyer /* FALLTHROUGH */ 6216b6e2954SConrad Meyer #endif 6226b6e2954SConrad Meyer case DIOCSKERNELDUMP: 6236b6e2954SConrad Meyer encryptedkey = NULL; 6246b6e2954SConrad Meyer if (cmd == DIOCSKERNELDUMP) { 6256b6e2954SConrad Meyer conf = (void *)addr; 6266b6e2954SConrad Meyer memcpy(&kda_copy, conf, sizeof(kda_copy)); 6276b6e2954SConrad Meyer } 6286b6e2954SConrad Meyer /* Netdump only supports IP4 at this time. */ 6296b6e2954SConrad Meyer if (conf->kda_af != AF_INET) { 6306b6e2954SConrad Meyer error = EPROTONOSUPPORT; 6316b6e2954SConrad Meyer break; 6326b6e2954SConrad Meyer } 6336b6e2954SConrad Meyer 6346b6e2954SConrad Meyer conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; 6356b6e2954SConrad Meyer if (conf->kda_index == KDA_REMOVE || 6366b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_DEV || 6376b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_ALL) { 63864e7d18fSConrad Meyer if (netdump_enabled()) 63964e7d18fSConrad Meyer netdump_unconfigure(); 64064e7d18fSConrad Meyer if (conf->kda_index == KDA_REMOVE_ALL) 64164e7d18fSConrad Meyer error = dumper_remove(NULL, conf); 642e5054602SMark Johnston break; 643e5054602SMark Johnston } 644e5054602SMark Johnston 645b35822d9SMark Johnston error = netdump_configure(conf, td); 646e5054602SMark Johnston if (error != 0) 647e5054602SMark Johnston break; 648e5054602SMark Johnston 6496b6e2954SConrad Meyer if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { 6506b6e2954SConrad Meyer if (conf->kda_encryptedkeysize <= 0 || 6516b6e2954SConrad Meyer conf->kda_encryptedkeysize > 6526b6e2954SConrad Meyer KERNELDUMP_ENCKEY_MAX_SIZE) { 6536b6e2954SConrad Meyer error = EINVAL; 6546b6e2954SConrad Meyer break; 6556b6e2954SConrad Meyer } 6566b6e2954SConrad Meyer encryptedkey = malloc(conf->kda_encryptedkeysize, 6576b6e2954SConrad Meyer M_TEMP, M_WAITOK); 6586b6e2954SConrad Meyer error = copyin(conf->kda_encryptedkey, encryptedkey, 6596b6e2954SConrad Meyer conf->kda_encryptedkeysize); 660e5054602SMark Johnston if (error != 0) { 661e5054602SMark Johnston free(encryptedkey, M_TEMP); 6626b6e2954SConrad Meyer break; 663e5054602SMark Johnston } 6646b6e2954SConrad Meyer 6656b6e2954SConrad Meyer conf->kda_encryptedkey = encryptedkey; 666e5054602SMark Johnston } 667e5054602SMark Johnston 6689f78e2b8SMark Johnston memset(&dumper, 0, sizeof(dumper)); 669e5054602SMark Johnston dumper.dumper_start = netdump_start; 670e5054602SMark Johnston dumper.dumper_hdr = netdump_write_headers; 671e5054602SMark Johnston dumper.dumper = netdump_dumper; 672e5054602SMark Johnston dumper.priv = NULL; 673e5054602SMark Johnston dumper.blocksize = NETDUMP_DATASIZE; 674e5054602SMark Johnston dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; 675e5054602SMark Johnston dumper.mediaoffset = 0; 676e5054602SMark Johnston dumper.mediasize = 0; 677e5054602SMark Johnston 6786b6e2954SConrad Meyer error = dumper_insert(&dumper, conf->kda_iface, conf); 6794a711b8dSJohn Baldwin zfree(encryptedkey, M_TEMP); 68064e7d18fSConrad Meyer if (error != 0) 68164e7d18fSConrad Meyer netdump_unconfigure(); 682e5054602SMark Johnston break; 683e5054602SMark Johnston default: 6846b6e2954SConrad Meyer error = ENOTTY; 685e5054602SMark Johnston break; 686e5054602SMark Johnston } 6876b6e2954SConrad Meyer explicit_bzero(&kda_copy, sizeof(kda_copy)); 6886b6e2954SConrad Meyer if (conf != NULL) 6896b6e2954SConrad Meyer explicit_bzero(conf, sizeof(*conf)); 69064e7d18fSConrad Meyer NETDUMP_WUNLOCK(); 691e5054602SMark Johnston return (error); 692e5054602SMark Johnston } 693e5054602SMark Johnston 694e5054602SMark Johnston /* 695e5054602SMark Johnston * Called upon system init or kld load. Initializes the netdump parameters to 696e5054602SMark Johnston * sane defaults (locates the first available NIC and uses the first IPv4 IP on 697e5054602SMark Johnston * that card as the client IP). Leaves the server IP unconfigured. 698e5054602SMark Johnston * 699e5054602SMark Johnston * Parameters: 700e5054602SMark Johnston * mod, Unused. 701e5054602SMark Johnston * what, The module event type. 702e5054602SMark Johnston * priv, Unused. 703e5054602SMark Johnston * 704e5054602SMark Johnston * Returns: 705e5054602SMark Johnston * int, An errno value if an error occured, 0 otherwise. 706e5054602SMark Johnston */ 707e5054602SMark Johnston static int 708e5054602SMark Johnston netdump_modevent(module_t mod __unused, int what, void *priv __unused) 709e5054602SMark Johnston { 7106b6e2954SConrad Meyer struct diocskerneldump_arg conf; 711e5054602SMark Johnston char *arg; 712e5054602SMark Johnston int error; 713e5054602SMark Johnston 714e5054602SMark Johnston error = 0; 715e5054602SMark Johnston switch (what) { 716e5054602SMark Johnston case MOD_LOAD: 717e5054602SMark Johnston error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, 718e5054602SMark Johnston &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); 719e5054602SMark Johnston if (error != 0) 720e5054602SMark Johnston return (error); 721e5054602SMark Johnston 72264e7d18fSConrad Meyer nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event, 72364e7d18fSConrad Meyer netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY); 72464e7d18fSConrad Meyer 725e5054602SMark Johnston if ((arg = kern_getenv("net.dump.iface")) != NULL) { 7266b6e2954SConrad Meyer strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); 727e5054602SMark Johnston freeenv(arg); 728e5054602SMark Johnston 729e5054602SMark Johnston if ((arg = kern_getenv("net.dump.server")) != NULL) { 7306b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 731e5054602SMark Johnston freeenv(arg); 732e5054602SMark Johnston } 733e5054602SMark Johnston if ((arg = kern_getenv("net.dump.client")) != NULL) { 734070e7bf9SConrad Meyer inet_aton(arg, &conf.kda_client.in4); 735e5054602SMark Johnston freeenv(arg); 736e5054602SMark Johnston } 737e5054602SMark Johnston if ((arg = kern_getenv("net.dump.gateway")) != NULL) { 738070e7bf9SConrad Meyer inet_aton(arg, &conf.kda_gateway.in4); 739e5054602SMark Johnston freeenv(arg); 740e5054602SMark Johnston } 7416b6e2954SConrad Meyer conf.kda_af = AF_INET; 742e5054602SMark Johnston 743e5054602SMark Johnston /* Ignore errors; we print a message to the console. */ 74464e7d18fSConrad Meyer NETDUMP_WLOCK(); 7458270d35eSConrad Meyer (void)netdump_configure(&conf, NULL); 74664e7d18fSConrad Meyer NETDUMP_WUNLOCK(); 747e5054602SMark Johnston } 748e5054602SMark Johnston break; 749e5054602SMark Johnston case MOD_UNLOAD: 75064e7d18fSConrad Meyer NETDUMP_WLOCK(); 75164e7d18fSConrad Meyer if (netdump_enabled()) { 752e5054602SMark Johnston printf("netdump: disabling dump device for unload\n"); 75364e7d18fSConrad Meyer netdump_unconfigure(); 754e5054602SMark Johnston } 75564e7d18fSConrad Meyer NETDUMP_WUNLOCK(); 7566b6e2954SConrad Meyer destroy_dev(netdump_cdev); 75764e7d18fSConrad Meyer EVENTHANDLER_DEREGISTER(ifnet_departure_event, 75864e7d18fSConrad Meyer nd_detach_cookie); 759e5054602SMark Johnston break; 760e5054602SMark Johnston default: 761e5054602SMark Johnston error = EOPNOTSUPP; 762e5054602SMark Johnston break; 763e5054602SMark Johnston } 764e5054602SMark Johnston return (error); 765e5054602SMark Johnston } 766e5054602SMark Johnston 767e5054602SMark Johnston static moduledata_t netdump_mod = { 768e5054602SMark Johnston "netdump", 769e5054602SMark Johnston netdump_modevent, 770e5054602SMark Johnston NULL, 771e5054602SMark Johnston }; 772e5054602SMark Johnston 773e5054602SMark Johnston MODULE_VERSION(netdump, 1); 774e5054602SMark Johnston DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 7758270d35eSConrad Meyer 7768270d35eSConrad Meyer #ifdef DDB 7778270d35eSConrad Meyer /* 7788270d35eSConrad Meyer * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface> 7798270d35eSConrad Meyer * 7808270d35eSConrad Meyer * Order is not significant. 7818270d35eSConrad Meyer * 7828270d35eSConrad Meyer * Currently, this command does not support configuring encryption or 7838270d35eSConrad Meyer * compression. 7848270d35eSConrad Meyer */ 7858270d35eSConrad Meyer DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL) 7868270d35eSConrad Meyer { 7878270d35eSConrad Meyer static struct diocskerneldump_arg conf; 7888270d35eSConrad Meyer static char blockbuf[NETDUMP_DATASIZE]; 7898270d35eSConrad Meyer static union { 7908270d35eSConrad Meyer struct dumperinfo di; 7918270d35eSConrad Meyer /* For valid di_devname. */ 7928270d35eSConrad Meyer char di_buf[sizeof(struct dumperinfo) + 1]; 7938270d35eSConrad Meyer } u; 7948270d35eSConrad Meyer 7958270d35eSConrad Meyer struct debugnet_ddb_config params; 7968270d35eSConrad Meyer int error; 7978270d35eSConrad Meyer 7988270d35eSConrad Meyer error = debugnet_parse_ddb_cmd("netdump", ¶ms); 7998270d35eSConrad Meyer if (error != 0) { 8008270d35eSConrad Meyer db_printf("Error configuring netdump: %d\n", error); 8018270d35eSConrad Meyer return; 8028270d35eSConrad Meyer } 8038270d35eSConrad Meyer 8048270d35eSConrad Meyer /* Translate to a netdump dumper config. */ 8058270d35eSConrad Meyer memset(&conf, 0, sizeof(conf)); 806fde2cf65SConrad Meyer 807fde2cf65SConrad Meyer if (params.dd_ifp != NULL) 808fde2cf65SConrad Meyer strlcpy(conf.kda_iface, if_name(params.dd_ifp), 809fde2cf65SConrad Meyer sizeof(conf.kda_iface)); 8108270d35eSConrad Meyer 8118270d35eSConrad Meyer conf.kda_af = AF_INET; 8128270d35eSConrad Meyer conf.kda_server.in4 = (struct in_addr) { params.dd_server }; 813fde2cf65SConrad Meyer if (params.dd_has_client) 8148270d35eSConrad Meyer conf.kda_client.in4 = (struct in_addr) { params.dd_client }; 815fde2cf65SConrad Meyer else 816fde2cf65SConrad Meyer conf.kda_client.in4 = (struct in_addr) { INADDR_ANY }; 8178270d35eSConrad Meyer if (params.dd_has_gateway) 8188270d35eSConrad Meyer conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway }; 8198270d35eSConrad Meyer else 8208270d35eSConrad Meyer conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY }; 8218270d35eSConrad Meyer 8228270d35eSConrad Meyer /* Set the global netdump config to these options. */ 8238270d35eSConrad Meyer error = netdump_configure(&conf, NULL); 8248270d35eSConrad Meyer if (error != 0) { 8258270d35eSConrad Meyer db_printf("Error enabling netdump: %d\n", error); 8268270d35eSConrad Meyer return; 8278270d35eSConrad Meyer } 8288270d35eSConrad Meyer 8298270d35eSConrad Meyer /* Fake the generic dump configuration list entry to avoid malloc. */ 8308270d35eSConrad Meyer memset(&u.di_buf, 0, sizeof(u.di_buf)); 8318270d35eSConrad Meyer u.di.dumper_start = netdump_start; 8328270d35eSConrad Meyer u.di.dumper_hdr = netdump_write_headers; 8338270d35eSConrad Meyer u.di.dumper = netdump_dumper; 8348270d35eSConrad Meyer u.di.priv = NULL; 8358270d35eSConrad Meyer u.di.blocksize = NETDUMP_DATASIZE; 8368270d35eSConrad Meyer u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE; 8378270d35eSConrad Meyer u.di.mediaoffset = 0; 8388270d35eSConrad Meyer u.di.mediasize = 0; 8398270d35eSConrad Meyer u.di.blockbuf = blockbuf; 8408270d35eSConrad Meyer 8418270d35eSConrad Meyer dumper_ddb_insert(&u.di); 8428270d35eSConrad Meyer 8438270d35eSConrad Meyer error = doadump(false); 8448270d35eSConrad Meyer 8458270d35eSConrad Meyer dumper_ddb_remove(&u.di); 8468270d35eSConrad Meyer if (error != 0) 8478270d35eSConrad Meyer db_printf("Cannot dump: %d\n", error); 8488270d35eSConrad Meyer } 8498270d35eSConrad Meyer #endif /* DDB */ 850