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 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 * offset Offset from start of core file
231 * length Data length
232 *
233 * Return value:
234 * 0 on success
235 * errno on error
236 */
237 static int
238 netdump_dumper(void *priv __unused, void *virtual, off_t offset, size_t length)
239 {
240 int error;
241
242 NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
243 virtual, (uintmax_t)offset, length);
244
245 if (virtual == NULL) {
246 error = netdump_flush_buf();
247 if (error != 0)
248 dump_failed = 1;
249
250 if (dump_failed != 0)
251 printf("failed to dump the kernel core\n");
252 else if (
253 debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
254 printf("failed to close the transaction\n");
255 else
256 printf("\nnetdump finished.\n");
257 netdump_cleanup();
258 return (0);
259 }
260 if (length > sizeof(nd_buf)) {
261 netdump_cleanup();
262 return (ENOSPC);
263 }
264
265 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
266 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
267 nd_conf.nd_buf_len != offset)) {
268 error = netdump_flush_buf();
269 if (error != 0) {
270 dump_failed = 1;
271 netdump_cleanup();
272 return (error);
273 }
274 nd_conf.nd_tx_off = offset;
275 }
276
277 memmove(nd_buf + nd_conf.nd_buf_len, virtual, length);
278 nd_conf.nd_buf_len += length;
279
280 return (0);
281 }
282
283 /*
284 * Perform any initialization needed prior to transmitting the kernel core.
285 */
286 static int
287 netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
288 {
289 struct debugnet_conn_params dcp;
290 struct debugnet_pcb *pcb;
291 char buf[INET_ADDRSTRLEN];
292 int error;
293
294 error = 0;
295
296 /* Check if the dumping is allowed to continue. */
297 if (!netdump_enabled())
298 return (EINVAL);
299
300 if (!KERNEL_PANICKED()) {
301 printf(
302 "netdump_start: netdump may only be used after a panic\n");
303 return (EINVAL);
304 }
305
306 memset(&dcp, 0, sizeof(dcp));
307
308 if (nd_server.s_addr == INADDR_ANY) {
309 printf("netdump_start: can't netdump; no server IP given\n");
310 return (EINVAL);
311 }
312
313 /* We start dumping at offset 0. */
314 di->dumpoff = 0;
315
316 dcp.dc_ifp = nd_ifp;
317
318 dcp.dc_client = nd_client.s_addr;
319 dcp.dc_server = nd_server.s_addr;
320 dcp.dc_gateway = nd_gateway.s_addr;
321
322 dcp.dc_herald_port = NETDUMP_PORT;
323 dcp.dc_client_port = NETDUMP_ACKPORT;
324
325 dcp.dc_herald_data = nd_path;
326 dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
327
328 error = debugnet_connect(&dcp, &pcb);
329 if (error != 0) {
330 printf("failed to contact netdump server\n");
331 /* Squash debugnet to something the dumper code understands. */
332 return (EINVAL);
333 }
334
335 printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
336 debugnet_get_gw_mac(pcb), ":");
337 nd_conf.nd_pcb = pcb;
338
339 /* Send the key before the dump so a partial dump is still usable. */
340 if (keysize > 0) {
341 if (keysize > sizeof(nd_buf)) {
342 printf("crypto key is too large (%u)\n", keysize);
343 error = EINVAL;
344 goto out;
345 }
346 memcpy(nd_buf, key, keysize);
347 error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize,
348 NULL);
349 if (error != 0) {
350 printf("error %d sending crypto key\n", error);
351 goto out;
352 }
353 }
354
355 out:
356 if (error != 0) {
357 /* As above, squash errors. */
358 error = EINVAL;
359 netdump_cleanup();
360 }
361 return (error);
362 }
363
364 static int
365 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
366 {
367 int error;
368
369 error = netdump_flush_buf();
370 if (error != 0)
371 goto out;
372 memcpy(nd_buf, kdh, sizeof(*kdh));
373 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
374 sizeof(*kdh), NULL);
375 out:
376 if (error != 0)
377 netdump_cleanup();
378 return (error);
379 }
380
381 /*
382 * Cleanup routine for a possibly failed netdump.
383 */
384 static void
385 netdump_cleanup(void)
386 {
387 if (nd_conf.nd_pcb != NULL) {
388 debugnet_free(nd_conf.nd_pcb);
389 nd_conf.nd_pcb = NULL;
390 }
391 }
392
393 /*-
394 * KLD specific code.
395 */
396
397 static struct cdevsw netdump_cdevsw = {
398 .d_version = D_VERSION,
399 .d_ioctl = netdump_ioctl,
400 .d_name = "netdump",
401 };
402
403 static struct cdev *netdump_cdev;
404
405 static void
406 netdump_unconfigure(void)
407 {
408 struct diocskerneldump_arg kda;
409
410 NETDUMP_ASSERT_WLOCKED();
411 KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
412
413 bzero(&kda, sizeof(kda));
414 kda.kda_index = KDA_REMOVE_DEV;
415 (void)dumper_remove(nd_conf.ndc_iface, &kda);
416
417 if (nd_ifp != NULL)
418 if_rele(nd_ifp);
419 nd_ifp = NULL;
420 netdump_set_enabled(false);
421
422 log(LOG_WARNING, "netdump: Lost configured interface %s\n",
423 nd_conf.ndc_iface);
424
425 bzero(&nd_conf, sizeof(nd_conf));
426 }
427
428 static void
429 netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
430 {
431
432 NETDUMP_WLOCK();
433 if (ifp == nd_ifp)
434 netdump_unconfigure();
435 NETDUMP_WUNLOCK();
436 }
437
438 /*
439 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
440 * modload-based tunable parameters).
441 */
442 static int
443 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
444 {
445 struct ifnet *ifp;
446
447 NETDUMP_ASSERT_WLOCKED();
448
449 if (conf->kda_iface[0] != 0) {
450 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
451 return (EINVAL);
452 CURVNET_SET(vnet0);
453 ifp = ifunit_ref(conf->kda_iface);
454 CURVNET_RESTORE();
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
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 *conf;
502 struct dumperinfo dumper;
503 uint8_t *encryptedkey;
504 int error;
505
506 conf = NULL;
507 error = 0;
508 NETDUMP_WLOCK();
509
510 switch (cmd) {
511 case DIOCGKERNELDUMP:
512 conf = (void *)addr;
513 /*
514 * For now, index is ignored; netdump doesn't support multiple
515 * configurations (yet).
516 */
517 if (!netdump_enabled()) {
518 error = ENXIO;
519 conf = NULL;
520 break;
521 }
522
523 if (nd_ifp != NULL)
524 strlcpy(conf->kda_iface, nd_ifp->if_xname,
525 sizeof(conf->kda_iface));
526 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
527 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
528 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
529 conf->kda_af = nd_conf.ndc_af;
530 conf = NULL;
531 break;
532 case DIOCSKERNELDUMP:
533 encryptedkey = NULL;
534 conf = (void *)addr;
535
536 /* Netdump only supports IP4 at this time. */
537 if (conf->kda_af != AF_INET) {
538 error = EPROTONOSUPPORT;
539 break;
540 }
541
542 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
543 if (conf->kda_index == KDA_REMOVE ||
544 conf->kda_index == KDA_REMOVE_DEV ||
545 conf->kda_index == KDA_REMOVE_ALL) {
546 if (netdump_enabled())
547 netdump_unconfigure();
548 if (conf->kda_index == KDA_REMOVE_ALL)
549 error = dumper_remove(NULL, conf);
550 break;
551 }
552
553 error = netdump_configure(conf, td);
554 if (error != 0)
555 break;
556
557 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
558 if (conf->kda_encryptedkeysize <= 0 ||
559 conf->kda_encryptedkeysize >
560 KERNELDUMP_ENCKEY_MAX_SIZE) {
561 error = EINVAL;
562 break;
563 }
564 encryptedkey = malloc(conf->kda_encryptedkeysize,
565 M_TEMP, M_WAITOK);
566 error = copyin(conf->kda_encryptedkey, encryptedkey,
567 conf->kda_encryptedkeysize);
568 if (error != 0) {
569 free(encryptedkey, M_TEMP);
570 break;
571 }
572
573 conf->kda_encryptedkey = encryptedkey;
574 }
575
576 memset(&dumper, 0, sizeof(dumper));
577 dumper.dumper_start = netdump_start;
578 dumper.dumper_hdr = netdump_write_headers;
579 dumper.dumper = netdump_dumper;
580 dumper.priv = NULL;
581 dumper.blocksize = NETDUMP_DATASIZE;
582 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
583 dumper.mediaoffset = 0;
584 dumper.mediasize = 0;
585
586 error = dumper_insert(&dumper, conf->kda_iface, conf);
587 zfree(encryptedkey, M_TEMP);
588 if (error != 0)
589 netdump_unconfigure();
590 break;
591 default:
592 error = ENOTTY;
593 break;
594 }
595 if (conf != NULL)
596 explicit_bzero(conf, sizeof(*conf));
597 NETDUMP_WUNLOCK();
598 return (error);
599 }
600
601 /*
602 * Called upon system init or kld load. Initializes the netdump parameters to
603 * sane defaults (locates the first available NIC and uses the first IPv4 IP on
604 * that card as the client IP). Leaves the server IP unconfigured.
605 *
606 * Parameters:
607 * mod, Unused.
608 * what, The module event type.
609 * priv, Unused.
610 *
611 * Returns:
612 * int, An errno value if an error occurred, 0 otherwise.
613 */
614 static int
615 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
616 {
617 struct diocskerneldump_arg conf;
618 char *arg;
619 int error;
620
621 error = 0;
622 switch (what) {
623 case MOD_LOAD:
624 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
625 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
626 if (error != 0)
627 return (error);
628
629 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
630 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
631
632 if ((arg = kern_getenv("net.dump.iface")) != NULL) {
633 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
634 freeenv(arg);
635
636 if ((arg = kern_getenv("net.dump.server")) != NULL) {
637 inet_aton(arg, &conf.kda_server.in4);
638 freeenv(arg);
639 }
640 if ((arg = kern_getenv("net.dump.client")) != NULL) {
641 inet_aton(arg, &conf.kda_client.in4);
642 freeenv(arg);
643 }
644 if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
645 inet_aton(arg, &conf.kda_gateway.in4);
646 freeenv(arg);
647 }
648 conf.kda_af = AF_INET;
649
650 /* Ignore errors; we print a message to the console. */
651 NETDUMP_WLOCK();
652 (void)netdump_configure(&conf, NULL);
653 NETDUMP_WUNLOCK();
654 }
655 break;
656 case MOD_UNLOAD:
657 NETDUMP_WLOCK();
658 if (netdump_enabled()) {
659 printf("netdump: disabling dump device for unload\n");
660 netdump_unconfigure();
661 }
662 NETDUMP_WUNLOCK();
663 destroy_dev(netdump_cdev);
664 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
665 nd_detach_cookie);
666 break;
667 default:
668 error = EOPNOTSUPP;
669 break;
670 }
671 return (error);
672 }
673
674 static moduledata_t netdump_mod = {
675 "netdump",
676 netdump_modevent,
677 NULL,
678 };
679
680 MODULE_VERSION(netdump, 1);
681 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
682
683 #ifdef DDB
684 /*
685 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
686 *
687 * Order is not significant.
688 *
689 * Currently, this command does not support configuring encryption or
690 * compression.
691 */
692 DB_COMMAND_FLAGS(netdump, db_netdump_cmd, CS_OWN)
693 {
694 static struct diocskerneldump_arg conf;
695 static char blockbuf[NETDUMP_DATASIZE];
696 static union {
697 struct dumperinfo di;
698 /* For valid di_devname. */
699 char di_buf[sizeof(struct dumperinfo) + 1];
700 } u;
701
702 struct debugnet_ddb_config params;
703 int error;
704
705 error = debugnet_parse_ddb_cmd("netdump", ¶ms);
706 if (error != 0) {
707 db_printf("Error configuring netdump: %d\n", error);
708 return;
709 }
710
711 /* Translate to a netdump dumper config. */
712 memset(&conf, 0, sizeof(conf));
713
714 if (params.dd_ifp != NULL)
715 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
716 sizeof(conf.kda_iface));
717
718 conf.kda_af = AF_INET;
719 conf.kda_server.in4 = (struct in_addr) { params.dd_server };
720 if (params.dd_has_client)
721 conf.kda_client.in4 = (struct in_addr) { params.dd_client };
722 else
723 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
724 if (params.dd_has_gateway)
725 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
726 else
727 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
728
729 /* Set the global netdump config to these options. */
730 error = netdump_configure(&conf, NULL);
731 if (error != 0) {
732 db_printf("Error enabling netdump: %d\n", error);
733 return;
734 }
735
736 /* Fake the generic dump configuration list entry to avoid malloc. */
737 memset(&u.di_buf, 0, sizeof(u.di_buf));
738 u.di.dumper_start = netdump_start;
739 u.di.dumper_hdr = netdump_write_headers;
740 u.di.dumper = netdump_dumper;
741 u.di.priv = NULL;
742 u.di.blocksize = NETDUMP_DATASIZE;
743 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
744 u.di.mediaoffset = 0;
745 u.di.mediasize = 0;
746 u.di.blockbuf = blockbuf;
747
748 dumper_ddb_insert(&u.di);
749
750 error = doadump(false);
751
752 dumper_ddb_remove(&u.di);
753 if (error != 0)
754 db_printf("Cannot dump: %d\n", error);
755 }
756 #endif /* DDB */
Cache object: fe0c0356b21090ac64fcfda9969b7d76
|