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