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