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