xref: /freebsd/sys/netinet/netdump/netdump_client.c (revision 13a58148de1730f851d37513913fae547e53a512)
1e5054602SMark Johnston /*-
2e5054602SMark Johnston  * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
3e5054602SMark Johnston  * Copyright (c) 2000 Darrell Anderson
4e5054602SMark Johnston  * All rights reserved.
5e5054602SMark Johnston  *
6e5054602SMark Johnston  * Redistribution and use in source and binary forms, with or without
7e5054602SMark Johnston  * modification, are permitted provided that the following conditions
8e5054602SMark Johnston  * are met:
9e5054602SMark Johnston  * 1. Redistributions of source code must retain the above copyright
10e5054602SMark Johnston  *    notice, this list of conditions and the following disclaimer.
11e5054602SMark Johnston  * 2. Redistributions in binary form must reproduce the above copyright
12e5054602SMark Johnston  *    notice, this list of conditions and the following disclaimer in the
13e5054602SMark Johnston  *    documentation and/or other materials provided with the distribution.
14e5054602SMark Johnston  *
15e5054602SMark Johnston  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16e5054602SMark Johnston  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17e5054602SMark Johnston  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18e5054602SMark Johnston  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19e5054602SMark Johnston  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20e5054602SMark Johnston  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21e5054602SMark Johnston  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22e5054602SMark Johnston  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23e5054602SMark Johnston  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24e5054602SMark Johnston  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25e5054602SMark Johnston  * SUCH DAMAGE.
26e5054602SMark Johnston  */
27e5054602SMark Johnston 
28e5054602SMark Johnston /*
29e5054602SMark Johnston  * netdump_client.c
30e5054602SMark Johnston  * FreeBSD subsystem supporting netdump network dumps.
31e5054602SMark Johnston  * A dedicated server must be running to accept client dumps.
32e5054602SMark Johnston  */
33e5054602SMark Johnston 
34e5054602SMark Johnston #include <sys/cdefs.h>
35e5054602SMark Johnston __FBSDID("$FreeBSD$");
36e5054602SMark Johnston 
378270d35eSConrad Meyer #include "opt_ddb.h"
388270d35eSConrad Meyer 
39e5054602SMark Johnston #include <sys/param.h>
40e5054602SMark Johnston #include <sys/conf.h>
41e5054602SMark Johnston #include <sys/disk.h>
42e5054602SMark Johnston #include <sys/endian.h>
4304e0c883SConrad Meyer #include <sys/eventhandler.h>
44b35822d9SMark Johnston #include <sys/jail.h>
45e5054602SMark Johnston #include <sys/kernel.h>
46e5054602SMark Johnston #include <sys/kerneldump.h>
47e5054602SMark Johnston #include <sys/mbuf.h>
48e5054602SMark Johnston #include <sys/module.h>
49e5054602SMark Johnston #include <sys/priv.h>
50e5054602SMark Johnston #include <sys/proc.h>
51e5054602SMark Johnston #include <sys/protosw.h>
52e5054602SMark Johnston #include <sys/socket.h>
53e5054602SMark Johnston #include <sys/sysctl.h>
547790c8c1SConrad Meyer #include <sys/syslog.h>
55e5054602SMark Johnston #include <sys/systm.h>
56e5054602SMark Johnston 
578270d35eSConrad Meyer #ifdef DDB
588270d35eSConrad Meyer #include <ddb/ddb.h>
598270d35eSConrad Meyer #include <ddb/db_lex.h>
608270d35eSConrad Meyer #endif
618270d35eSConrad Meyer 
62e5054602SMark Johnston #include <net/ethernet.h>
63e5054602SMark Johnston #include <net/if.h>
64e5054602SMark Johnston #include <net/if_arp.h>
65e5054602SMark Johnston #include <net/if_dl.h>
66e5054602SMark Johnston #include <net/if_types.h>
67e5054602SMark Johnston #include <net/if_var.h>
687790c8c1SConrad Meyer #include <net/debugnet.h>
69e5054602SMark Johnston 
70e5054602SMark Johnston #include <netinet/in.h>
71e5054602SMark Johnston #include <netinet/in_systm.h>
72e5054602SMark Johnston #include <netinet/in_var.h>
73e5054602SMark Johnston #include <netinet/ip.h>
74e5054602SMark Johnston #include <netinet/ip_var.h>
75e5054602SMark Johnston #include <netinet/ip_options.h>
76e5054602SMark Johnston #include <netinet/udp.h>
77e5054602SMark Johnston #include <netinet/udp_var.h>
78e5054602SMark Johnston #include <netinet/netdump/netdump.h>
79e5054602SMark Johnston 
80e5054602SMark Johnston #include <machine/in_cksum.h>
81e5054602SMark Johnston #include <machine/pcb.h>
82e5054602SMark Johnston 
83e5054602SMark Johnston #define	NETDDEBUGV(f, ...) do {						\
84e5054602SMark Johnston 	if (nd_debug > 1)						\
85e5054602SMark Johnston 		printf(("%s: " f), __func__, ## __VA_ARGS__);		\
86e5054602SMark Johnston } while (0)
87e5054602SMark Johnston 
88a5732433SBryan Drewery static void	 netdump_cleanup(void);
896b6e2954SConrad Meyer static int	 netdump_configure(struct diocskerneldump_arg *,
906b6e2954SConrad Meyer 		    struct thread *);
91e5054602SMark Johnston static int	 netdump_dumper(void *priv __unused, void *virtual,
92e5054602SMark Johnston 		    vm_offset_t physical __unused, off_t offset, size_t length);
9364e7d18fSConrad Meyer static bool	 netdump_enabled(void);
9464e7d18fSConrad Meyer static int	 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
95e5054602SMark Johnston static int	 netdump_ioctl(struct cdev *dev __unused, u_long cmd,
96e5054602SMark Johnston 		    caddr_t addr, int flags __unused, struct thread *td);
97e5054602SMark Johnston static int	 netdump_modevent(module_t mod, int type, void *priv);
98*13a58148SEric van Gyzen static int	 netdump_start(struct dumperinfo *di, void *key,
99*13a58148SEric van Gyzen 		    uint32_t keysize);
10064e7d18fSConrad Meyer static void	 netdump_unconfigure(void);
101e5054602SMark Johnston 
102e5054602SMark Johnston /* Must be at least as big as the chunks dumpsys() gives us. */
103e5054602SMark Johnston static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
1047790c8c1SConrad Meyer static int dump_failed;
105e5054602SMark Johnston 
106e5054602SMark Johnston /* Configuration parameters. */
1076144b50fSConrad Meyer static struct {
1086144b50fSConrad Meyer 	char		 ndc_iface[IFNAMSIZ];
1096144b50fSConrad Meyer 	union kd_ip	 ndc_server;
1106144b50fSConrad Meyer 	union kd_ip	 ndc_client;
1116144b50fSConrad Meyer 	union kd_ip	 ndc_gateway;
1126144b50fSConrad Meyer 	uint8_t		 ndc_af;
1138726929dSMark Johnston 	/* Runtime State */
1147790c8c1SConrad Meyer 	struct debugnet_pcb *nd_pcb;
1158726929dSMark Johnston 	off_t		 nd_tx_off;
1168726929dSMark Johnston 	size_t		 nd_buf_len;
1176144b50fSConrad Meyer } nd_conf;
1186144b50fSConrad Meyer #define	nd_server	nd_conf.ndc_server.in4
1196144b50fSConrad Meyer #define	nd_client	nd_conf.ndc_client.in4
1206144b50fSConrad Meyer #define	nd_gateway	nd_conf.ndc_gateway.in4
121e5054602SMark Johnston 
122e5054602SMark Johnston /* General dynamic settings. */
12364e7d18fSConrad Meyer static struct sx nd_conf_lk;
12464e7d18fSConrad Meyer SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock");
12564e7d18fSConrad Meyer #define NETDUMP_WLOCK()			sx_xlock(&nd_conf_lk)
12664e7d18fSConrad Meyer #define NETDUMP_WUNLOCK()		sx_xunlock(&nd_conf_lk)
12764e7d18fSConrad Meyer #define NETDUMP_RLOCK()			sx_slock(&nd_conf_lk)
12864e7d18fSConrad Meyer #define NETDUMP_RUNLOCK()		sx_sunlock(&nd_conf_lk)
12964e7d18fSConrad Meyer #define NETDUMP_ASSERT_WLOCKED()	sx_assert(&nd_conf_lk, SA_XLOCKED)
13064e7d18fSConrad Meyer #define NETDUMP_ASSERT_LOCKED()		sx_assert(&nd_conf_lk, SA_LOCKED)
131e5054602SMark Johnston static struct ifnet *nd_ifp;
13264e7d18fSConrad Meyer static eventhandler_tag nd_detach_cookie;
133e5054602SMark Johnston 
134e5054602SMark Johnston FEATURE(netdump, "Netdump client support");
135e5054602SMark Johnston 
1367029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
137e5054602SMark Johnston     "netdump parameters");
138e5054602SMark Johnston 
139e5054602SMark Johnston static int nd_debug;
140e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
141e5054602SMark Johnston     &nd_debug, 0,
142e5054602SMark Johnston     "Debug message verbosity");
1437029da5cSPawel Biernacki SYSCTL_PROC(_net_netdump, OID_AUTO, enabled,
1447029da5cSPawel Biernacki     CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0,
1457029da5cSPawel Biernacki     netdump_enabled_sysctl, "I",
1467029da5cSPawel Biernacki     "netdump configuration status");
147e5054602SMark Johnston static char nd_path[MAXPATHLEN];
148e5054602SMark Johnston SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
149e5054602SMark Johnston     nd_path, sizeof(nd_path),
150e5054602SMark Johnston     "Server path for output files");
1517790c8c1SConrad Meyer /*
1527790c8c1SConrad Meyer  * The following three variables were moved to debugnet(4), but these knobs
1537790c8c1SConrad Meyer  * were retained as aliases.
1547790c8c1SConrad Meyer  */
155da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN,
1567790c8c1SConrad Meyer     &debugnet_npolls, 0,
157da7d7778SMark Johnston     "Number of times to poll before assuming packet loss (0.5ms per poll)");
158da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
1597790c8c1SConrad Meyer     &debugnet_nretries, 0,
160da7d7778SMark Johnston     "Number of retransmit attempts before giving up");
161da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
1627790c8c1SConrad Meyer     &debugnet_arp_nretries, 0,
163da7d7778SMark Johnston     "Number of ARP attempts before giving up");
164e5054602SMark Johnston 
165fde2cf65SConrad Meyer static bool nd_is_enabled;
16664e7d18fSConrad Meyer static bool
16764e7d18fSConrad Meyer netdump_enabled(void)
16864e7d18fSConrad Meyer {
16964e7d18fSConrad Meyer 
17064e7d18fSConrad Meyer 	NETDUMP_ASSERT_LOCKED();
171fde2cf65SConrad Meyer 	return (nd_is_enabled);
172fde2cf65SConrad Meyer }
173fde2cf65SConrad Meyer 
174fde2cf65SConrad Meyer static void
175fde2cf65SConrad Meyer netdump_set_enabled(bool status)
176fde2cf65SConrad Meyer {
177fde2cf65SConrad Meyer 
178fde2cf65SConrad Meyer 	NETDUMP_ASSERT_LOCKED();
179fde2cf65SConrad Meyer 	nd_is_enabled = status;
18064e7d18fSConrad Meyer }
18164e7d18fSConrad Meyer 
18264e7d18fSConrad Meyer static int
18364e7d18fSConrad Meyer netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
18464e7d18fSConrad Meyer {
18564e7d18fSConrad Meyer 	int en, error;
18664e7d18fSConrad Meyer 
18764e7d18fSConrad Meyer 	NETDUMP_RLOCK();
18864e7d18fSConrad Meyer 	en = netdump_enabled();
18964e7d18fSConrad Meyer 	NETDUMP_RUNLOCK();
19064e7d18fSConrad Meyer 
19164e7d18fSConrad Meyer 	error = SYSCTL_OUT(req, &en, sizeof(en));
19264e7d18fSConrad Meyer 	if (error != 0 || req->newptr == NULL)
19364e7d18fSConrad Meyer 		return (error);
19464e7d18fSConrad Meyer 	return (EPERM);
19564e7d18fSConrad Meyer }
19664e7d18fSConrad Meyer 
197e5054602SMark Johnston /*-
198e5054602SMark Johnston  * Dumping specific primitives.
199e5054602SMark Johnston  */
200e5054602SMark Johnston 
201e5054602SMark Johnston /*
202ccdc9866SMark Johnston  * Flush any buffered vmcore data.
203ccdc9866SMark Johnston  */
204ccdc9866SMark Johnston static int
205ccdc9866SMark Johnston netdump_flush_buf(void)
206ccdc9866SMark Johnston {
207ccdc9866SMark Johnston 	int error;
208ccdc9866SMark Johnston 
209ccdc9866SMark Johnston 	error = 0;
210ccdc9866SMark Johnston 	if (nd_conf.nd_buf_len != 0) {
2117790c8c1SConrad Meyer 		struct debugnet_proto_aux auxdata = {
2127790c8c1SConrad Meyer 			.dp_offset_start = nd_conf.nd_tx_off,
2137790c8c1SConrad Meyer 		};
2147790c8c1SConrad Meyer 		error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf,
2157790c8c1SConrad Meyer 		    nd_conf.nd_buf_len, &auxdata);
216ccdc9866SMark Johnston 		if (error == 0)
217ccdc9866SMark Johnston 			nd_conf.nd_buf_len = 0;
218ccdc9866SMark Johnston 	}
219ccdc9866SMark Johnston 	return (error);
220ccdc9866SMark Johnston }
221ccdc9866SMark Johnston 
222ccdc9866SMark Johnston /*
223e5054602SMark Johnston  * Callback from dumpsys() to dump a chunk of memory.
224e5054602SMark Johnston  * Copies it out to our static buffer then sends it across the network.
225e5054602SMark Johnston  * Detects the initial KDH and makes sure it is given a special packet type.
226e5054602SMark Johnston  *
227e5054602SMark Johnston  * Parameters:
228e5054602SMark Johnston  *	priv	 Unused. Optional private pointer.
229e5054602SMark Johnston  *	virtual  Virtual address (where to read the data from)
230e5054602SMark Johnston  *	physical Unused. Physical memory address.
231e5054602SMark Johnston  *	offset	 Offset from start of core file
232e5054602SMark Johnston  *	length	 Data length
233e5054602SMark Johnston  *
234e5054602SMark Johnston  * Return value:
235e5054602SMark Johnston  *	0 on success
236e5054602SMark Johnston  *	errno on error
237e5054602SMark Johnston  */
238e5054602SMark Johnston static int
239e5054602SMark Johnston netdump_dumper(void *priv __unused, void *virtual,
240e5054602SMark Johnston     vm_offset_t physical __unused, off_t offset, size_t length)
241e5054602SMark Johnston {
242e5054602SMark Johnston 	int error;
243e5054602SMark Johnston 
244e5054602SMark Johnston 	NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
245e5054602SMark Johnston 	    virtual, (uintmax_t)offset, length);
246e5054602SMark Johnston 
247e5054602SMark Johnston 	if (virtual == NULL) {
248ccdc9866SMark Johnston 		error = netdump_flush_buf();
249ccdc9866SMark Johnston 		if (error != 0)
2508726929dSMark Johnston 			dump_failed = 1;
2518726929dSMark Johnston 
252e5054602SMark Johnston 		if (dump_failed != 0)
253e5054602SMark Johnston 			printf("failed to dump the kernel core\n");
2547790c8c1SConrad Meyer 		else if (
2557790c8c1SConrad Meyer 		    debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
256e5054602SMark Johnston 			printf("failed to close the transaction\n");
257e5054602SMark Johnston 		else
258e5054602SMark Johnston 			printf("\nnetdump finished.\n");
259a5732433SBryan Drewery 		netdump_cleanup();
260e5054602SMark Johnston 		return (0);
261e5054602SMark Johnston 	}
262a5732433SBryan Drewery 	if (length > sizeof(nd_buf)) {
263a5732433SBryan Drewery 		netdump_cleanup();
264e5054602SMark Johnston 		return (ENOSPC);
265a5732433SBryan Drewery 	}
266e5054602SMark Johnston 
2678726929dSMark Johnston 	if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
2688726929dSMark Johnston 	    (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
2698726929dSMark Johnston 	    nd_conf.nd_buf_len != offset)) {
270ccdc9866SMark Johnston 		error = netdump_flush_buf();
271e5054602SMark Johnston 		if (error != 0) {
272e5054602SMark Johnston 			dump_failed = 1;
273a5732433SBryan Drewery 			netdump_cleanup();
274e5054602SMark Johnston 			return (error);
275e5054602SMark Johnston 		}
2768726929dSMark Johnston 		nd_conf.nd_tx_off = offset;
2778726929dSMark Johnston 	}
2788726929dSMark Johnston 
2798726929dSMark Johnston 	memmove(nd_buf + nd_conf.nd_buf_len, virtual, length);
2808726929dSMark Johnston 	nd_conf.nd_buf_len += length;
2818726929dSMark Johnston 
282e5054602SMark Johnston 	return (0);
283e5054602SMark Johnston }
284e5054602SMark Johnston 
285e5054602SMark Johnston /*
2865aa0576bSEd Maste  * Perform any initialization needed prior to transmitting the kernel core.
287e5054602SMark Johnston  */
288e5054602SMark Johnston static int
289*13a58148SEric van Gyzen netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
290e5054602SMark Johnston {
2917790c8c1SConrad Meyer 	struct debugnet_conn_params dcp;
2927790c8c1SConrad Meyer 	struct debugnet_pcb *pcb;
293e5054602SMark Johnston 	char buf[INET_ADDRSTRLEN];
294e5054602SMark Johnston 	int error;
295e5054602SMark Johnston 
296e5054602SMark Johnston 	error = 0;
297e5054602SMark Johnston 
298e5054602SMark Johnston 	/* Check if the dumping is allowed to continue. */
29964e7d18fSConrad Meyer 	if (!netdump_enabled())
300e5054602SMark Johnston 		return (EINVAL);
301e5054602SMark Johnston 
302879e0604SMateusz Guzik 	if (!KERNEL_PANICKED()) {
303e5054602SMark Johnston 		printf(
304e5054602SMark Johnston 		    "netdump_start: netdump may only be used after a panic\n");
305e5054602SMark Johnston 		return (EINVAL);
306e5054602SMark Johnston 	}
307e5054602SMark Johnston 
3087790c8c1SConrad Meyer 	memset(&dcp, 0, sizeof(dcp));
3097790c8c1SConrad Meyer 
310e5054602SMark Johnston 	if (nd_server.s_addr == INADDR_ANY) {
311e5054602SMark Johnston 		printf("netdump_start: can't netdump; no server IP given\n");
312e5054602SMark Johnston 		return (EINVAL);
313e5054602SMark Johnston 	}
314e5054602SMark Johnston 
315e5054602SMark Johnston 	/* We start dumping at offset 0. */
316e5054602SMark Johnston 	di->dumpoff = 0;
317e5054602SMark Johnston 
3187790c8c1SConrad Meyer 	dcp.dc_ifp = nd_ifp;
319e5054602SMark Johnston 
3207790c8c1SConrad Meyer 	dcp.dc_client = nd_client.s_addr;
3217790c8c1SConrad Meyer 	dcp.dc_server = nd_server.s_addr;
3227790c8c1SConrad Meyer 	dcp.dc_gateway = nd_gateway.s_addr;
323e5054602SMark Johnston 
3247790c8c1SConrad Meyer 	dcp.dc_herald_port = NETDUMP_PORT;
325e9c69625SConrad Meyer 	dcp.dc_client_port = NETDUMP_ACKPORT;
326e5054602SMark Johnston 
3277790c8c1SConrad Meyer 	dcp.dc_herald_data = nd_path;
3287790c8c1SConrad Meyer 	dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
329e5054602SMark Johnston 
3307790c8c1SConrad Meyer 	error = debugnet_connect(&dcp, &pcb);
3317790c8c1SConrad Meyer 	if (error != 0) {
332e5054602SMark Johnston 		printf("failed to contact netdump server\n");
3337790c8c1SConrad Meyer 		/* Squash debugnet to something the dumper code understands. */
3347790c8c1SConrad Meyer 		return (EINVAL);
335e5054602SMark Johnston 	}
336e5054602SMark Johnston 
3377790c8c1SConrad Meyer 	printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
3387790c8c1SConrad Meyer 	    debugnet_get_gw_mac(pcb), ":");
3397790c8c1SConrad Meyer 	nd_conf.nd_pcb = pcb;
340*13a58148SEric van Gyzen 
341*13a58148SEric van Gyzen 	/* Send the key before the dump so a partial dump is still usable. */
342*13a58148SEric van Gyzen 	if (keysize > 0) {
343*13a58148SEric van Gyzen 		if (keysize > sizeof(nd_buf)) {
344*13a58148SEric van Gyzen 			printf("crypto key is too large (%u)\n", keysize);
345*13a58148SEric van Gyzen 			error = EINVAL;
346*13a58148SEric van Gyzen 			goto out;
347*13a58148SEric van Gyzen 		}
348*13a58148SEric van Gyzen 		memcpy(nd_buf, key, keysize);
349*13a58148SEric van Gyzen 		error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize,
350*13a58148SEric van Gyzen 		    NULL);
351*13a58148SEric van Gyzen 		if (error != 0) {
352*13a58148SEric van Gyzen 			printf("error %d sending crypto key\n", error);
353*13a58148SEric van Gyzen 			goto out;
354*13a58148SEric van Gyzen 		}
355*13a58148SEric van Gyzen 	}
356*13a58148SEric van Gyzen 
357*13a58148SEric van Gyzen out:
358*13a58148SEric van Gyzen 	if (error != 0) {
359*13a58148SEric van Gyzen 		/* As above, squash errors. */
360*13a58148SEric van Gyzen 		error = EINVAL;
361*13a58148SEric van Gyzen 		netdump_cleanup();
362*13a58148SEric van Gyzen 	}
363*13a58148SEric van Gyzen 	return (error);
364e5054602SMark Johnston }
365e5054602SMark Johnston 
366e5054602SMark Johnston static int
367*13a58148SEric van Gyzen netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
368e5054602SMark Johnston {
369e5054602SMark Johnston 	int error;
370e5054602SMark Johnston 
371ccdc9866SMark Johnston 	error = netdump_flush_buf();
372ccdc9866SMark Johnston 	if (error != 0)
373a5732433SBryan Drewery 		goto out;
374e5054602SMark Johnston 	memcpy(nd_buf, kdh, sizeof(*kdh));
3757790c8c1SConrad Meyer 	error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
3767790c8c1SConrad Meyer 	    sizeof(*kdh), NULL);
377a5732433SBryan Drewery out:
378a5732433SBryan Drewery 	if (error != 0)
379a5732433SBryan Drewery 		netdump_cleanup();
380e5054602SMark Johnston 	return (error);
381e5054602SMark Johnston }
382e5054602SMark Johnston 
383a5732433SBryan Drewery /*
384a5732433SBryan Drewery  * Cleanup routine for a possibly failed netdump.
385a5732433SBryan Drewery  */
386a5732433SBryan Drewery static void
387a5732433SBryan Drewery netdump_cleanup(void)
388a5732433SBryan Drewery {
389a5732433SBryan Drewery 	if (nd_conf.nd_pcb != NULL) {
390a5732433SBryan Drewery 		debugnet_free(nd_conf.nd_pcb);
391a5732433SBryan Drewery 		nd_conf.nd_pcb = NULL;
392a5732433SBryan Drewery 	}
393a5732433SBryan Drewery }
394a5732433SBryan Drewery 
395e5054602SMark Johnston /*-
396e5054602SMark Johnston  * KLD specific code.
397e5054602SMark Johnston  */
398e5054602SMark Johnston 
399e5054602SMark Johnston static struct cdevsw netdump_cdevsw = {
400e5054602SMark Johnston 	.d_version =	D_VERSION,
401e5054602SMark Johnston 	.d_ioctl =	netdump_ioctl,
402e5054602SMark Johnston 	.d_name =	"netdump",
403e5054602SMark Johnston };
404e5054602SMark Johnston 
405e5054602SMark Johnston static struct cdev *netdump_cdev;
406e5054602SMark Johnston 
40764e7d18fSConrad Meyer static void
40864e7d18fSConrad Meyer netdump_unconfigure(void)
40964e7d18fSConrad Meyer {
41064e7d18fSConrad Meyer 	struct diocskerneldump_arg kda;
41164e7d18fSConrad Meyer 
41264e7d18fSConrad Meyer 	NETDUMP_ASSERT_WLOCKED();
413fde2cf65SConrad Meyer 	KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
41464e7d18fSConrad Meyer 
41564e7d18fSConrad Meyer 	bzero(&kda, sizeof(kda));
41664e7d18fSConrad Meyer 	kda.kda_index = KDA_REMOVE_DEV;
41764e7d18fSConrad Meyer 	(void)dumper_remove(nd_conf.ndc_iface, &kda);
41864e7d18fSConrad Meyer 
419fde2cf65SConrad Meyer 	if (nd_ifp != NULL)
42064e7d18fSConrad Meyer 		if_rele(nd_ifp);
42164e7d18fSConrad Meyer 	nd_ifp = NULL;
422fde2cf65SConrad Meyer 	netdump_set_enabled(false);
42364e7d18fSConrad Meyer 
4247790c8c1SConrad Meyer 	log(LOG_WARNING, "netdump: Lost configured interface %s\n",
4257790c8c1SConrad Meyer 	    nd_conf.ndc_iface);
4267790c8c1SConrad Meyer 
42764e7d18fSConrad Meyer 	bzero(&nd_conf, sizeof(nd_conf));
42864e7d18fSConrad Meyer }
42964e7d18fSConrad Meyer 
43064e7d18fSConrad Meyer static void
43164e7d18fSConrad Meyer netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
43264e7d18fSConrad Meyer {
43364e7d18fSConrad Meyer 
43464e7d18fSConrad Meyer 	NETDUMP_WLOCK();
43564e7d18fSConrad Meyer 	if (ifp == nd_ifp)
43664e7d18fSConrad Meyer 		netdump_unconfigure();
43764e7d18fSConrad Meyer 	NETDUMP_WUNLOCK();
43864e7d18fSConrad Meyer }
43964e7d18fSConrad Meyer 
4408270d35eSConrad Meyer /*
4418270d35eSConrad Meyer  * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
4428270d35eSConrad Meyer  * modload-based tunable parameters).
4438270d35eSConrad Meyer  */
444e5054602SMark Johnston static int
4456b6e2954SConrad Meyer netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
446e5054602SMark Johnston {
447e5054602SMark Johnston 	struct ifnet *ifp;
448e5054602SMark Johnston 
44964e7d18fSConrad Meyer 	NETDUMP_ASSERT_WLOCKED();
45064e7d18fSConrad Meyer 
451fde2cf65SConrad Meyer 	if (conf->kda_iface[0] != 0) {
4524ad8cb68SMichael Tuexen 		if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
453b35822d9SMark Johnston 			return (EINVAL);
4544ad8cb68SMichael Tuexen 		CURVNET_SET(vnet0);
45564e7d18fSConrad Meyer 		ifp = ifunit_ref(conf->kda_iface);
456b35822d9SMark Johnston 		CURVNET_RESTORE();
457fde2cf65SConrad Meyer 	} else
458fde2cf65SConrad Meyer 		ifp = NULL;
459e5054602SMark Johnston 
460fde2cf65SConrad Meyer 	if (nd_ifp != NULL)
46164e7d18fSConrad Meyer 		if_rele(nd_ifp);
462e5054602SMark Johnston 	nd_ifp = ifp;
463fde2cf65SConrad Meyer 	netdump_set_enabled(true);
4646144b50fSConrad Meyer 
4656144b50fSConrad Meyer #define COPY_SIZED(elm) do {	\
4666144b50fSConrad Meyer 	_Static_assert(sizeof(nd_conf.ndc_ ## elm) ==			\
4676144b50fSConrad Meyer 	    sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
4686144b50fSConrad Meyer 	memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm,		\
4696144b50fSConrad Meyer 	    sizeof(nd_conf.ndc_ ## elm));				\
4706144b50fSConrad Meyer } while (0)
4716144b50fSConrad Meyer 	COPY_SIZED(iface);
4726144b50fSConrad Meyer 	COPY_SIZED(server);
4736144b50fSConrad Meyer 	COPY_SIZED(client);
4746144b50fSConrad Meyer 	COPY_SIZED(gateway);
4756144b50fSConrad Meyer 	COPY_SIZED(af);
4766144b50fSConrad Meyer #undef COPY_SIZED
47764e7d18fSConrad Meyer 
478e5054602SMark Johnston 	return (0);
479e5054602SMark Johnston }
480e5054602SMark Johnston 
481e5054602SMark Johnston /*
482e5054602SMark Johnston  * ioctl(2) handler for the netdump device. This is currently only used to
483e5054602SMark Johnston  * register netdump as a dump device.
484e5054602SMark Johnston  *
485e5054602SMark Johnston  * Parameters:
486e5054602SMark Johnston  *     dev, Unused.
487e5054602SMark Johnston  *     cmd, The ioctl to be handled.
488e5054602SMark Johnston  *     addr, The parameter for the ioctl.
489e5054602SMark Johnston  *     flags, Unused.
490e5054602SMark Johnston  *     td, The thread invoking this ioctl.
491e5054602SMark Johnston  *
492e5054602SMark Johnston  * Returns:
493e5054602SMark Johnston  *     0 on success, and an errno value on failure.
494e5054602SMark Johnston  */
495e5054602SMark Johnston static int
496e5054602SMark Johnston netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
497e5054602SMark Johnston     int flags __unused, struct thread *td)
498e5054602SMark Johnston {
4996b6e2954SConrad Meyer 	struct diocskerneldump_arg kda_copy, *conf;
500e5054602SMark Johnston 	struct dumperinfo dumper;
501e5054602SMark Johnston 	uint8_t *encryptedkey;
502e5054602SMark Johnston 	int error;
503a9f7f192SConrad Meyer #ifdef COMPAT_FREEBSD11
504e5054602SMark Johnston 	u_int u;
505a9f7f192SConrad Meyer #endif
5066b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12
5076b6e2954SConrad Meyer 	struct diocskerneldump_arg_freebsd12 *kda12;
5086b6e2954SConrad Meyer 	struct netdump_conf_freebsd12 *conf12;
5096b6e2954SConrad Meyer #endif
510e5054602SMark Johnston 
5116b6e2954SConrad Meyer 	conf = NULL;
512e5054602SMark Johnston 	error = 0;
51364e7d18fSConrad Meyer 	NETDUMP_WLOCK();
51464e7d18fSConrad Meyer 
515e5054602SMark Johnston 	switch (cmd) {
51660ade167SConrad Meyer #ifdef COMPAT_FREEBSD11
51760ade167SConrad Meyer 	case DIOCSKERNELDUMP_FREEBSD11:
5186b6e2954SConrad Meyer 		gone_in(13, "11.x ABI compatibility");
519e5054602SMark Johnston 		u = *(u_int *)addr;
520e5054602SMark Johnston 		if (u != 0) {
521e5054602SMark Johnston 			error = ENXIO;
522e5054602SMark Johnston 			break;
523e5054602SMark Johnston 		}
52464e7d18fSConrad Meyer 		if (netdump_enabled())
52564e7d18fSConrad Meyer 			netdump_unconfigure();
52660ade167SConrad Meyer 		break;
52760ade167SConrad Meyer #endif
5286b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12
5296b6e2954SConrad Meyer 		/*
5306b6e2954SConrad Meyer 		 * Used by dumpon(8) in 12.x for clearing previous
5316b6e2954SConrad Meyer 		 * configuration -- then NETDUMPSCONF_FREEBSD12 is used to
5326b6e2954SConrad Meyer 		 * actually configure netdump.
5336b6e2954SConrad Meyer 		 */
5346b6e2954SConrad Meyer 	case DIOCSKERNELDUMP_FREEBSD12:
5356b6e2954SConrad Meyer 		gone_in(14, "12.x ABI compatibility");
5366b6e2954SConrad Meyer 
5376b6e2954SConrad Meyer 		kda12 = (void *)addr;
5386b6e2954SConrad Meyer 		if (kda12->kda12_enable) {
53960ade167SConrad Meyer 			error = ENXIO;
54060ade167SConrad Meyer 			break;
54160ade167SConrad Meyer 		}
54264e7d18fSConrad Meyer 		if (netdump_enabled())
54364e7d18fSConrad Meyer 			netdump_unconfigure();
544e5054602SMark Johnston 		break;
5456b6e2954SConrad Meyer 
5466b6e2954SConrad Meyer 	case NETDUMPGCONF_FREEBSD12:
5476b6e2954SConrad Meyer 		gone_in(14, "FreeBSD 12.x ABI compat");
5486b6e2954SConrad Meyer 		conf12 = (void *)addr;
5496b6e2954SConrad Meyer 
55064e7d18fSConrad Meyer 		if (!netdump_enabled()) {
551e5054602SMark Johnston 			error = ENXIO;
552e5054602SMark Johnston 			break;
553e5054602SMark Johnston 		}
5546144b50fSConrad Meyer 		if (nd_conf.ndc_af != AF_INET) {
5556b6e2954SConrad Meyer 			error = EOPNOTSUPP;
556e5054602SMark Johnston 			break;
5576b6e2954SConrad Meyer 		}
558e5054602SMark Johnston 
559fde2cf65SConrad Meyer 		if (nd_ifp != NULL)
5606b6e2954SConrad Meyer 			strlcpy(conf12->ndc12_iface, nd_ifp->if_xname,
5616b6e2954SConrad Meyer 			    sizeof(conf12->ndc12_iface));
5626b6e2954SConrad Meyer 		memcpy(&conf12->ndc12_server, &nd_server,
5636b6e2954SConrad Meyer 		    sizeof(conf12->ndc12_server));
5646b6e2954SConrad Meyer 		memcpy(&conf12->ndc12_client, &nd_client,
5656b6e2954SConrad Meyer 		    sizeof(conf12->ndc12_client));
5666b6e2954SConrad Meyer 		memcpy(&conf12->ndc12_gateway, &nd_gateway,
5676b6e2954SConrad Meyer 		    sizeof(conf12->ndc12_gateway));
5686b6e2954SConrad Meyer 		break;
5696b6e2954SConrad Meyer #endif
5706b6e2954SConrad Meyer 	case DIOCGKERNELDUMP:
5716b6e2954SConrad Meyer 		conf = (void *)addr;
5726b6e2954SConrad Meyer 		/*
5736b6e2954SConrad Meyer 		 * For now, index is ignored; netdump doesn't support multiple
5746b6e2954SConrad Meyer 		 * configurations (yet).
5756b6e2954SConrad Meyer 		 */
57664e7d18fSConrad Meyer 		if (!netdump_enabled()) {
5776b6e2954SConrad Meyer 			error = ENXIO;
5786b6e2954SConrad Meyer 			conf = NULL;
5796b6e2954SConrad Meyer 			break;
5806b6e2954SConrad Meyer 		}
5816b6e2954SConrad Meyer 
582fde2cf65SConrad Meyer 		if (nd_ifp != NULL)
5836b6e2954SConrad Meyer 			strlcpy(conf->kda_iface, nd_ifp->if_xname,
5846b6e2954SConrad Meyer 			    sizeof(conf->kda_iface));
5856b6e2954SConrad Meyer 		memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
5866b6e2954SConrad Meyer 		memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
5876b6e2954SConrad Meyer 		memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
5886144b50fSConrad Meyer 		conf->kda_af = nd_conf.ndc_af;
5896b6e2954SConrad Meyer 		conf = NULL;
5906b6e2954SConrad Meyer 		break;
5916b6e2954SConrad Meyer 
5926b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12
5936b6e2954SConrad Meyer 	case NETDUMPSCONF_FREEBSD12:
5946b6e2954SConrad Meyer 		gone_in(14, "FreeBSD 12.x ABI compat");
5956b6e2954SConrad Meyer 
5966b6e2954SConrad Meyer 		conf12 = (struct netdump_conf_freebsd12 *)addr;
5976b6e2954SConrad Meyer 
5986b6e2954SConrad Meyer 		_Static_assert(offsetof(struct diocskerneldump_arg, kda_server)
5996b6e2954SConrad Meyer 		    == offsetof(struct netdump_conf_freebsd12, ndc12_server),
6006b6e2954SConrad Meyer 		    "simplifying assumption");
6016b6e2954SConrad Meyer 
6026b6e2954SConrad Meyer 		memset(&kda_copy, 0, sizeof(kda_copy));
6036b6e2954SConrad Meyer 		memcpy(&kda_copy, conf12,
6046b6e2954SConrad Meyer 		    offsetof(struct diocskerneldump_arg, kda_server));
6056b6e2954SConrad Meyer 
6066b6e2954SConrad Meyer 		/* 12.x ABI could only configure IPv4 (INET) netdump. */
6076b6e2954SConrad Meyer 		kda_copy.kda_af = AF_INET;
6086b6e2954SConrad Meyer 		memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server,
6096b6e2954SConrad Meyer 		    sizeof(struct in_addr));
6106b6e2954SConrad Meyer 		memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client,
6116b6e2954SConrad Meyer 		    sizeof(struct in_addr));
6126b6e2954SConrad Meyer 		memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway,
6136b6e2954SConrad Meyer 		    sizeof(struct in_addr));
6146b6e2954SConrad Meyer 
6156b6e2954SConrad Meyer 		kda_copy.kda_index =
6166b6e2954SConrad Meyer 		    (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL);
6176b6e2954SConrad Meyer 
6186b6e2954SConrad Meyer 		conf = &kda_copy;
6196b6e2954SConrad Meyer 		explicit_bzero(conf12, sizeof(*conf12));
6206b6e2954SConrad Meyer 		/* FALLTHROUGH */
6216b6e2954SConrad Meyer #endif
6226b6e2954SConrad Meyer 	case DIOCSKERNELDUMP:
6236b6e2954SConrad Meyer 		encryptedkey = NULL;
6246b6e2954SConrad Meyer 		if (cmd == DIOCSKERNELDUMP) {
6256b6e2954SConrad Meyer 			conf = (void *)addr;
6266b6e2954SConrad Meyer 			memcpy(&kda_copy, conf, sizeof(kda_copy));
6276b6e2954SConrad Meyer 		}
6286b6e2954SConrad Meyer 		/* Netdump only supports IP4 at this time. */
6296b6e2954SConrad Meyer 		if (conf->kda_af != AF_INET) {
6306b6e2954SConrad Meyer 			error = EPROTONOSUPPORT;
6316b6e2954SConrad Meyer 			break;
6326b6e2954SConrad Meyer 		}
6336b6e2954SConrad Meyer 
6346b6e2954SConrad Meyer 		conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
6356b6e2954SConrad Meyer 		if (conf->kda_index == KDA_REMOVE ||
6366b6e2954SConrad Meyer 		    conf->kda_index == KDA_REMOVE_DEV ||
6376b6e2954SConrad Meyer 		    conf->kda_index == KDA_REMOVE_ALL) {
63864e7d18fSConrad Meyer 			if (netdump_enabled())
63964e7d18fSConrad Meyer 				netdump_unconfigure();
64064e7d18fSConrad Meyer 			if (conf->kda_index == KDA_REMOVE_ALL)
64164e7d18fSConrad Meyer 				error = dumper_remove(NULL, conf);
642e5054602SMark Johnston 			break;
643e5054602SMark Johnston 		}
644e5054602SMark Johnston 
645b35822d9SMark Johnston 		error = netdump_configure(conf, td);
646e5054602SMark Johnston 		if (error != 0)
647e5054602SMark Johnston 			break;
648e5054602SMark Johnston 
6496b6e2954SConrad Meyer 		if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
6506b6e2954SConrad Meyer 			if (conf->kda_encryptedkeysize <= 0 ||
6516b6e2954SConrad Meyer 			    conf->kda_encryptedkeysize >
6526b6e2954SConrad Meyer 			    KERNELDUMP_ENCKEY_MAX_SIZE) {
6536b6e2954SConrad Meyer 				error = EINVAL;
6546b6e2954SConrad Meyer 				break;
6556b6e2954SConrad Meyer 			}
6566b6e2954SConrad Meyer 			encryptedkey = malloc(conf->kda_encryptedkeysize,
6576b6e2954SConrad Meyer 			    M_TEMP, M_WAITOK);
6586b6e2954SConrad Meyer 			error = copyin(conf->kda_encryptedkey, encryptedkey,
6596b6e2954SConrad Meyer 			    conf->kda_encryptedkeysize);
660e5054602SMark Johnston 			if (error != 0) {
661e5054602SMark Johnston 				free(encryptedkey, M_TEMP);
6626b6e2954SConrad Meyer 				break;
663e5054602SMark Johnston 			}
6646b6e2954SConrad Meyer 
6656b6e2954SConrad Meyer 			conf->kda_encryptedkey = encryptedkey;
666e5054602SMark Johnston 		}
667e5054602SMark Johnston 
6689f78e2b8SMark Johnston 		memset(&dumper, 0, sizeof(dumper));
669e5054602SMark Johnston 		dumper.dumper_start = netdump_start;
670e5054602SMark Johnston 		dumper.dumper_hdr = netdump_write_headers;
671e5054602SMark Johnston 		dumper.dumper = netdump_dumper;
672e5054602SMark Johnston 		dumper.priv = NULL;
673e5054602SMark Johnston 		dumper.blocksize = NETDUMP_DATASIZE;
674e5054602SMark Johnston 		dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
675e5054602SMark Johnston 		dumper.mediaoffset = 0;
676e5054602SMark Johnston 		dumper.mediasize = 0;
677e5054602SMark Johnston 
6786b6e2954SConrad Meyer 		error = dumper_insert(&dumper, conf->kda_iface, conf);
6794a711b8dSJohn Baldwin 		zfree(encryptedkey, M_TEMP);
68064e7d18fSConrad Meyer 		if (error != 0)
68164e7d18fSConrad Meyer 			netdump_unconfigure();
682e5054602SMark Johnston 		break;
683e5054602SMark Johnston 	default:
6846b6e2954SConrad Meyer 		error = ENOTTY;
685e5054602SMark Johnston 		break;
686e5054602SMark Johnston 	}
6876b6e2954SConrad Meyer 	explicit_bzero(&kda_copy, sizeof(kda_copy));
6886b6e2954SConrad Meyer 	if (conf != NULL)
6896b6e2954SConrad Meyer 		explicit_bzero(conf, sizeof(*conf));
69064e7d18fSConrad Meyer 	NETDUMP_WUNLOCK();
691e5054602SMark Johnston 	return (error);
692e5054602SMark Johnston }
693e5054602SMark Johnston 
694e5054602SMark Johnston /*
695e5054602SMark Johnston  * Called upon system init or kld load.  Initializes the netdump parameters to
696e5054602SMark Johnston  * sane defaults (locates the first available NIC and uses the first IPv4 IP on
697e5054602SMark Johnston  * that card as the client IP).  Leaves the server IP unconfigured.
698e5054602SMark Johnston  *
699e5054602SMark Johnston  * Parameters:
700e5054602SMark Johnston  *	mod, Unused.
701e5054602SMark Johnston  *	what, The module event type.
702e5054602SMark Johnston  *	priv, Unused.
703e5054602SMark Johnston  *
704e5054602SMark Johnston  * Returns:
705e5054602SMark Johnston  *	int, An errno value if an error occured, 0 otherwise.
706e5054602SMark Johnston  */
707e5054602SMark Johnston static int
708e5054602SMark Johnston netdump_modevent(module_t mod __unused, int what, void *priv __unused)
709e5054602SMark Johnston {
7106b6e2954SConrad Meyer 	struct diocskerneldump_arg conf;
711e5054602SMark Johnston 	char *arg;
712e5054602SMark Johnston 	int error;
713e5054602SMark Johnston 
714e5054602SMark Johnston 	error = 0;
715e5054602SMark Johnston 	switch (what) {
716e5054602SMark Johnston 	case MOD_LOAD:
717e5054602SMark Johnston 		error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
718e5054602SMark Johnston 		    &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
719e5054602SMark Johnston 		if (error != 0)
720e5054602SMark Johnston 			return (error);
721e5054602SMark Johnston 
72264e7d18fSConrad Meyer 		nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
72364e7d18fSConrad Meyer 		    netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
72464e7d18fSConrad Meyer 
725e5054602SMark Johnston 		if ((arg = kern_getenv("net.dump.iface")) != NULL) {
7266b6e2954SConrad Meyer 			strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
727e5054602SMark Johnston 			freeenv(arg);
728e5054602SMark Johnston 
729e5054602SMark Johnston 			if ((arg = kern_getenv("net.dump.server")) != NULL) {
7306b6e2954SConrad Meyer 				inet_aton(arg, &conf.kda_server.in4);
731e5054602SMark Johnston 				freeenv(arg);
732e5054602SMark Johnston 			}
733e5054602SMark Johnston 			if ((arg = kern_getenv("net.dump.client")) != NULL) {
734070e7bf9SConrad Meyer 				inet_aton(arg, &conf.kda_client.in4);
735e5054602SMark Johnston 				freeenv(arg);
736e5054602SMark Johnston 			}
737e5054602SMark Johnston 			if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
738070e7bf9SConrad Meyer 				inet_aton(arg, &conf.kda_gateway.in4);
739e5054602SMark Johnston 				freeenv(arg);
740e5054602SMark Johnston 			}
7416b6e2954SConrad Meyer 			conf.kda_af = AF_INET;
742e5054602SMark Johnston 
743e5054602SMark Johnston 			/* Ignore errors; we print a message to the console. */
74464e7d18fSConrad Meyer 			NETDUMP_WLOCK();
7458270d35eSConrad Meyer 			(void)netdump_configure(&conf, NULL);
74664e7d18fSConrad Meyer 			NETDUMP_WUNLOCK();
747e5054602SMark Johnston 		}
748e5054602SMark Johnston 		break;
749e5054602SMark Johnston 	case MOD_UNLOAD:
75064e7d18fSConrad Meyer 		NETDUMP_WLOCK();
75164e7d18fSConrad Meyer 		if (netdump_enabled()) {
752e5054602SMark Johnston 			printf("netdump: disabling dump device for unload\n");
75364e7d18fSConrad Meyer 			netdump_unconfigure();
754e5054602SMark Johnston 		}
75564e7d18fSConrad Meyer 		NETDUMP_WUNLOCK();
7566b6e2954SConrad Meyer 		destroy_dev(netdump_cdev);
75764e7d18fSConrad Meyer 		EVENTHANDLER_DEREGISTER(ifnet_departure_event,
75864e7d18fSConrad Meyer 		    nd_detach_cookie);
759e5054602SMark Johnston 		break;
760e5054602SMark Johnston 	default:
761e5054602SMark Johnston 		error = EOPNOTSUPP;
762e5054602SMark Johnston 		break;
763e5054602SMark Johnston 	}
764e5054602SMark Johnston 	return (error);
765e5054602SMark Johnston }
766e5054602SMark Johnston 
767e5054602SMark Johnston static moduledata_t netdump_mod = {
768e5054602SMark Johnston 	"netdump",
769e5054602SMark Johnston 	netdump_modevent,
770e5054602SMark Johnston 	NULL,
771e5054602SMark Johnston };
772e5054602SMark Johnston 
773e5054602SMark Johnston MODULE_VERSION(netdump, 1);
774e5054602SMark Johnston DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
7758270d35eSConrad Meyer 
7768270d35eSConrad Meyer #ifdef DDB
7778270d35eSConrad Meyer /*
7788270d35eSConrad Meyer  * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
7798270d35eSConrad Meyer  *
7808270d35eSConrad Meyer  * Order is not significant.
7818270d35eSConrad Meyer  *
7828270d35eSConrad Meyer  * Currently, this command does not support configuring encryption or
7838270d35eSConrad Meyer  * compression.
7848270d35eSConrad Meyer  */
7858270d35eSConrad Meyer DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL)
7868270d35eSConrad Meyer {
7878270d35eSConrad Meyer 	static struct diocskerneldump_arg conf;
7888270d35eSConrad Meyer 	static char blockbuf[NETDUMP_DATASIZE];
7898270d35eSConrad Meyer 	static union {
7908270d35eSConrad Meyer 		struct dumperinfo di;
7918270d35eSConrad Meyer 		/* For valid di_devname. */
7928270d35eSConrad Meyer 		char di_buf[sizeof(struct dumperinfo) + 1];
7938270d35eSConrad Meyer 	} u;
7948270d35eSConrad Meyer 
7958270d35eSConrad Meyer 	struct debugnet_ddb_config params;
7968270d35eSConrad Meyer 	int error;
7978270d35eSConrad Meyer 
7988270d35eSConrad Meyer 	error = debugnet_parse_ddb_cmd("netdump", &params);
7998270d35eSConrad Meyer 	if (error != 0) {
8008270d35eSConrad Meyer 		db_printf("Error configuring netdump: %d\n", error);
8018270d35eSConrad Meyer 		return;
8028270d35eSConrad Meyer 	}
8038270d35eSConrad Meyer 
8048270d35eSConrad Meyer 	/* Translate to a netdump dumper config. */
8058270d35eSConrad Meyer 	memset(&conf, 0, sizeof(conf));
806fde2cf65SConrad Meyer 
807fde2cf65SConrad Meyer 	if (params.dd_ifp != NULL)
808fde2cf65SConrad Meyer 		strlcpy(conf.kda_iface, if_name(params.dd_ifp),
809fde2cf65SConrad Meyer 		    sizeof(conf.kda_iface));
8108270d35eSConrad Meyer 
8118270d35eSConrad Meyer 	conf.kda_af = AF_INET;
8128270d35eSConrad Meyer 	conf.kda_server.in4 = (struct in_addr) { params.dd_server };
813fde2cf65SConrad Meyer 	if (params.dd_has_client)
8148270d35eSConrad Meyer 		conf.kda_client.in4 = (struct in_addr) { params.dd_client };
815fde2cf65SConrad Meyer 	else
816fde2cf65SConrad Meyer 		conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
8178270d35eSConrad Meyer 	if (params.dd_has_gateway)
8188270d35eSConrad Meyer 		conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
8198270d35eSConrad Meyer 	else
8208270d35eSConrad Meyer 		conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
8218270d35eSConrad Meyer 
8228270d35eSConrad Meyer 	/* Set the global netdump config to these options. */
8238270d35eSConrad Meyer 	error = netdump_configure(&conf, NULL);
8248270d35eSConrad Meyer 	if (error != 0) {
8258270d35eSConrad Meyer 		db_printf("Error enabling netdump: %d\n", error);
8268270d35eSConrad Meyer 		return;
8278270d35eSConrad Meyer 	}
8288270d35eSConrad Meyer 
8298270d35eSConrad Meyer 	/* Fake the generic dump configuration list entry to avoid malloc. */
8308270d35eSConrad Meyer 	memset(&u.di_buf, 0, sizeof(u.di_buf));
8318270d35eSConrad Meyer 	u.di.dumper_start = netdump_start;
8328270d35eSConrad Meyer 	u.di.dumper_hdr = netdump_write_headers;
8338270d35eSConrad Meyer 	u.di.dumper = netdump_dumper;
8348270d35eSConrad Meyer 	u.di.priv = NULL;
8358270d35eSConrad Meyer 	u.di.blocksize = NETDUMP_DATASIZE;
8368270d35eSConrad Meyer 	u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
8378270d35eSConrad Meyer 	u.di.mediaoffset = 0;
8388270d35eSConrad Meyer 	u.di.mediasize = 0;
8398270d35eSConrad Meyer 	u.di.blockbuf = blockbuf;
8408270d35eSConrad Meyer 
8418270d35eSConrad Meyer 	dumper_ddb_insert(&u.di);
8428270d35eSConrad Meyer 
8438270d35eSConrad Meyer 	error = doadump(false);
8448270d35eSConrad Meyer 
8458270d35eSConrad Meyer 	dumper_ddb_remove(&u.di);
8468270d35eSConrad Meyer 	if (error != 0)
8478270d35eSConrad Meyer 		db_printf("Cannot dump: %d\n", error);
8488270d35eSConrad Meyer }
8498270d35eSConrad Meyer #endif /* DDB */
850