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