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