42#include <sys/endian.h>
43#include <sys/eventhandler.h>
45#include <sys/kernel.h>
46#include <sys/kerneldump.h>
48#include <sys/module.h>
51#include <sys/protosw.h>
52#include <sys/socket.h>
53#include <sys/sysctl.h>
54#include <sys/syslog.h>
59#include <ddb/db_lex.h>
62#include <net/ethernet.h>
64#include <net/if_arp.h>
66#include <net/if_types.h>
67#include <net/if_var.h>
68#include <net/debugnet.h>
80#include <machine/in_cksum.h>
81#include <machine/pcb.h>
83#define NETDDEBUGV(f, ...) do { \
85 printf(("%s: " f), __func__, ## __VA_ARGS__); \
92 vm_offset_t physical __unused, off_t offset,
size_t length);
95static int netdump_ioctl(
struct cdev *dev __unused, u_long cmd,
96 caddr_t addr,
int flags __unused,
struct thread *td);
103static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
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
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)
136static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
137 "netdump parameters");
142 "Debug message verbosity");
144 CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0,
146 "netdump configuration status");
150 "Server path for output files");
157 "Number of times to poll before assuming packet loss (0.5ms per poll)");
159 &debugnet_nretries, 0,
160 "Number of retransmit attempts before giving up");
161SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
162 &debugnet_arp_nretries, 0,
163 "Number of ARP attempts before giving up");
191 error = SYSCTL_OUT(req, &en,
sizeof(en));
192 if (error != 0 || req->newptr == NULL)
211 struct debugnet_proto_aux auxdata = {
212 .dp_offset_start =
nd_conf.nd_tx_off,
240 vm_offset_t physical __unused, off_t offset,
size_t length)
244 NETDDEBUGV(
"netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
245 virtual, (uintmax_t)offset, length);
247 if (
virtual == NULL) {
253 printf(
"failed to dump the kernel core\n");
255 debugnet_sendempty(
nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
256 printf(
"failed to close the transaction\n");
258 printf(
"\nnetdump finished.\n");
262 if (length >
sizeof(
nd_buf)) {
269 nd_conf.nd_buf_len != offset)) {
291 struct debugnet_conn_params dcp;
292 struct debugnet_pcb *pcb;
293 char buf[INET_ADDRSTRLEN];
302 if (!KERNEL_PANICKED()) {
304 "netdump_start: netdump may only be used after a panic\n");
308 memset(&dcp, 0,
sizeof(dcp));
311 printf(
"netdump_start: can't netdump; no server IP given\n");
328 dcp.dc_herald_datalen = (
nd_path[0] == 0) ? 0 : strlen(
nd_path) + 1;
330 error = debugnet_connect(&dcp, &pcb);
332 printf(
"failed to contact netdump server\n");
338 debugnet_get_gw_mac(pcb),
":");
343 if (keysize >
sizeof(
nd_buf)) {
344 printf(
"crypto key is too large (%u)\n", keysize);
348 memcpy(
nd_buf, key, keysize);
352 printf(
"error %d sending crypto key\n", error);
374 memcpy(
nd_buf, kdh,
sizeof(*kdh));
400 .d_version = D_VERSION,
410 struct diocskerneldump_arg kda;
415 bzero(&kda,
sizeof(kda));
416 kda.kda_index = KDA_REMOVE_DEV;
417 (void)dumper_remove(
nd_conf.ndc_iface, &kda);
424 log(LOG_WARNING,
"netdump: Lost configured interface %s\n",
451 if (conf->kda_iface[0] != 0) {
452 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
455 ifp = ifunit_ref(conf->kda_iface);
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)); \
497 int flags __unused,
struct thread *td)
499 struct diocskerneldump_arg kda_copy, *conf;
500 struct dumperinfo dumper;
503#ifdef COMPAT_FREEBSD11
506#ifdef COMPAT_FREEBSD12
507 struct diocskerneldump_arg_freebsd12 *kda12;
516#ifdef COMPAT_FREEBSD11
517 case DIOCSKERNELDUMP_FREEBSD11:
518 gone_in(13,
"11.x ABI compatibility");
528#ifdef COMPAT_FREEBSD12
534 case DIOCSKERNELDUMP_FREEBSD12:
535 gone_in(14,
"12.x ABI compatibility");
537 kda12 = (
void *)addr;
538 if (kda12->kda12_enable) {
547 gone_in(14,
"FreeBSD 12.x ABI compat");
548 conf12 = (
void *)addr;
554 if (
nd_conf.ndc_af != AF_INET) {
570 case DIOCGKERNELDUMP:
583 strlcpy(conf->kda_iface,
nd_ifp->if_xname,
584 sizeof(conf->kda_iface));
592#ifdef COMPAT_FREEBSD12
594 gone_in(14,
"FreeBSD 12.x ABI compat");
598 _Static_assert(offsetof(
struct diocskerneldump_arg, kda_server)
600 "simplifying assumption");
602 memset(&kda_copy, 0,
sizeof(kda_copy));
603 memcpy(&kda_copy, conf12,
604 offsetof(
struct diocskerneldump_arg, kda_server));
607 kda_copy.kda_af = AF_INET;
616 (conf12->
ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL);
619 explicit_bzero(conf12,
sizeof(*conf12));
622 case DIOCSKERNELDUMP:
624 if (cmd == DIOCSKERNELDUMP) {
626 memcpy(&kda_copy, conf,
sizeof(kda_copy));
629 if (conf->kda_af != AF_INET) {
630 error = EPROTONOSUPPORT;
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) {
640 if (conf->kda_index == KDA_REMOVE_ALL)
641 error = dumper_remove(NULL, conf);
649 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
650 if (conf->kda_encryptedkeysize <= 0 ||
651 conf->kda_encryptedkeysize >
652 KERNELDUMP_ENCKEY_MAX_SIZE) {
656 encryptedkey = malloc(conf->kda_encryptedkeysize,
658 error = copyin(conf->kda_encryptedkey, encryptedkey,
659 conf->kda_encryptedkeysize);
661 free(encryptedkey, M_TEMP);
665 conf->kda_encryptedkey = encryptedkey;
668 memset(&dumper, 0,
sizeof(dumper));
674 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
675 dumper.mediaoffset = 0;
676 dumper.mediasize = 0;
678 error = dumper_insert(&dumper, conf->kda_iface, conf);
679 zfree(encryptedkey, M_TEMP);
687 explicit_bzero(&kda_copy,
sizeof(kda_copy));
689 explicit_bzero(conf,
sizeof(*conf));
710 struct diocskerneldump_arg conf;
725 if ((arg = kern_getenv(
"net.dump.iface")) != NULL) {
726 strlcpy(conf.kda_iface, arg,
sizeof(conf.kda_iface));
729 if ((arg = kern_getenv(
"net.dump.server")) != NULL) {
733 if ((arg = kern_getenv(
"net.dump.client")) != NULL) {
737 if ((arg = kern_getenv(
"net.dump.gateway")) != NULL) {
741 conf.kda_af = AF_INET;
752 printf(
"netdump: disabling dump device for unload\n");
757 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
785DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL)
787 static struct diocskerneldump_arg conf;
790 struct dumperinfo di;
792 char di_buf[
sizeof(
struct dumperinfo) + 1];
795 struct debugnet_ddb_config params;
798 error = debugnet_parse_ddb_cmd(
"netdump", ¶ms);
800 db_printf(
"Error configuring netdump: %d\n", error);
805 memset(&conf, 0,
sizeof(conf));
807 if (params.dd_ifp != NULL)
808 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
809 sizeof(conf.kda_iface));
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 };
817 if (params.dd_has_gateway)
818 conf.kda_gateway.in4 = (
struct in_addr) { params.dd_gateway };
825 db_printf(
"Error enabling netdump: %d\n", error);
830 memset(&u.di_buf, 0,
sizeof(u.di_buf));
836 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
837 u.di.mediaoffset = 0;
839 u.di.blockbuf = blockbuf;
841 dumper_ddb_insert(&u.di);
843 error = doadump(
false);
845 dumper_ddb_remove(&u.di);
847 db_printf(
"Cannot dump: %d\n", error);
char * inet_ntoa_r(struct in_addr ina, char *buf)
int inet_aton(const char *, struct in_addr *)
#define NETDUMPSCONF_FREEBSD12
#define NETDUMPGCONF_FREEBSD12
static bool nd_is_enabled
static void netdump_cleanup(void)
static moduledata_t netdump_mod
SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock")
#define NETDDEBUGV(f,...)
SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, nd_path, sizeof(nd_path), "Server path for output files")
struct debugnet_pcb * nd_pcb
static int netdump_flush_buf(void)
static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "netdump parameters")
#define NETDUMP_WUNLOCK()
MODULE_VERSION(netdump, 1)
static int netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
static int netdump_dumper(void *priv __unused, void *virtual, vm_offset_t physical __unused, off_t offset, size_t length)
SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD|CTLTYPE_INT|CTLFLAG_MPSAFE, NULL, 0, netdump_enabled_sysctl, "I", "netdump configuration status")
static void netdump_set_enabled(bool status)
static eventhandler_tag nd_detach_cookie
static struct ifnet * nd_ifp
DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY)
static int netdump_modevent(module_t mod, int type, void *priv)
static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
static struct cdevsw netdump_cdevsw
static void netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, &nd_debug, 0, "Debug message verbosity")
#define NETDUMP_RUNLOCK()
static int netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
static struct @31 nd_conf
static struct cdev * netdump_cdev
#define NETDUMP_ASSERT_WLOCKED()
static unsigned char nd_buf[MAXDUMPPGS *PAGE_SIZE]
static void netdump_unconfigure(void)
static struct sx nd_conf_lk
static bool netdump_enabled(void)
static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, int flags __unused, struct thread *td)
#define NETDUMP_ASSERT_LOCKED()
static int netdump_configure(struct diocskerneldump_arg *, struct thread *)
static char nd_path[MAXPATHLEN]
FEATURE(netdump, "Netdump client support")
struct in_addr ndc12_server
struct diocskerneldump_arg_freebsd12 ndc12_kda
char ndc12_iface[IFNAMSIZ]
struct in_addr ndc12_gateway
struct in_addr ndc12_client