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