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