]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/netdump/netdump_client.c
libucl: import snapshot 2024-02-06
[FreeBSD/FreeBSD.git] / sys / netinet / netdump / netdump_client.c
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 (ifp == NULL)
455                         return (ENODEV);
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 */