FreeBSD kernel IPv4 code
netdump_client.c
Go to the documentation of this file.
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>
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
88static void netdump_cleanup(void);
89static int netdump_configure(struct diocskerneldump_arg *,
90 struct thread *);
91static int netdump_dumper(void *priv __unused, void *virtual,
92 vm_offset_t physical __unused, off_t offset, size_t length);
93static bool netdump_enabled(void);
94static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
95static int netdump_ioctl(struct cdev *dev __unused, u_long cmd,
96 caddr_t addr, int flags __unused, struct thread *td);
97static int netdump_modevent(module_t mod, int type, void *priv);
98static int netdump_start(struct dumperinfo *di, void *key,
99 uint32_t keysize);
100static void netdump_unconfigure(void);
101
102/* Must be at least as big as the chunks dumpsys() gives us. */
103static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
104static int dump_failed;
105
106/* Configuration parameters. */
107static struct {
108 char ndc_iface[IFNAMSIZ];
109 union kd_ip ndc_server;
110 union kd_ip ndc_client;
111 union kd_ip ndc_gateway;
113 /* Runtime State */
114 struct debugnet_pcb *nd_pcb;
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. */
123static struct sx nd_conf_lk;
124SX_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)
131static struct ifnet *nd_ifp;
132static eventhandler_tag nd_detach_cookie;
133
134FEATURE(netdump, "Netdump client support");
135
136static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
137 "netdump parameters");
138
139static int nd_debug;
140SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
141 &nd_debug, 0,
142 "Debug message verbosity");
143SYSCTL_PROC(_net_netdump, OID_AUTO, enabled,
144 CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0,
146 "netdump configuration status");
147static char nd_path[MAXPATHLEN];
148SYSCTL_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 */
155SYSCTL_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)");
158SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
159 &debugnet_nretries, 0,
160 "Number of retransmit attempts before giving up");
161SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
162 &debugnet_arp_nretries, 0,
163 "Number of ARP attempts before giving up");
164
165static bool nd_is_enabled;
166static bool
168{
169
171 return (nd_is_enabled);
172}
173
174static void
176{
177
179 nd_is_enabled = status;
180}
181
182static int
183netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
184{
185 int en, error;
186
188 en = netdump_enabled();
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 */
204static int
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 */
238static int
239netdump_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");
260 return (0);
261 }
262 if (length > sizeof(nd_buf)) {
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;
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 */
288static int
289netdump_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
357out:
358 if (error != 0) {
359 /* As above, squash errors. */
360 error = EINVAL;
362 }
363 return (error);
364}
365
366static int
367netdump_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);
377out:
378 if (error != 0)
380 return (error);
381}
382
383/*
384 * Cleanup routine for a possibly failed netdump.
385 */
386static 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
399static struct cdevsw netdump_cdevsw = {
400 .d_version = D_VERSION,
401 .d_ioctl = netdump_ioctl,
402 .d_name = "netdump",
403};
404
405static struct cdev *netdump_cdev;
406
407static void
409{
410 struct diocskerneldump_arg kda;
411
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
430static void
431netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
432{
433
435 if (ifp == nd_ifp)
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 */
444static int
445netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
446{
447 struct ifnet *ifp;
448
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;
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);
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 */
495static int
496netdump_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;
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())
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())
544 break;
545
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
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())
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)
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));
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 */
707static int
708netdump_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. */
745 (void)netdump_configure(&conf, NULL);
747 }
748 break;
749 case MOD_UNLOAD:
751 if (netdump_enabled()) {
752 printf("netdump: disabling dump device for unload\n");
754 }
756 destroy_dev(netdump_cdev);
757 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
759 break;
760 default:
761 error = EOPNOTSUPP;
762 break;
763 }
764 return (error);
765}
766
767static moduledata_t netdump_mod = {
768 "netdump",
770 NULL,
771};
772
773MODULE_VERSION(netdump, 1);
774DECLARE_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 */
785DB_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 */
__uint32_t uint32_t
Definition: in.h:62
__uint8_t uint8_t
Definition: in.h:52
char * inet_ntoa_r(struct in_addr ina, char *buf)
#define INADDR_ANY
Definition: in.h:48
int inet_aton(const char *, struct in_addr *)
#define NETDUMP_ACKPORT
Definition: netdump.h:42
#define NETDUMP_KDH
Definition: netdump.h:47
#define NETDUMP_EKCD_KEY
Definition: netdump.h:48
#define NETDUMPSCONF_FREEBSD12
Definition: netdump.h:69
#define NETDUMP_PORT
Definition: netdump.h:41
#define NETDUMPGCONF_FREEBSD12
Definition: netdump.h:68
#define NETDUMP_DATASIZE
Definition: netdump.h:50
static bool nd_is_enabled
size_t nd_buf_len
static void netdump_cleanup(void)
static moduledata_t netdump_mod
#define NETDUMP_WLOCK()
SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock")
#define NETDDEBUGV(f,...)
SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, nd_path, sizeof(nd_path), "Server path for output files")
struct debugnet_pcb * nd_pcb
#define nd_gateway
static int netdump_flush_buf(void)
static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "netdump parameters")
#define NETDUMP_WUNLOCK()
MODULE_VERSION(netdump, 1)
static int dump_failed
#define nd_client
static int netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
static int netdump_dumper(void *priv __unused, void *virtual, vm_offset_t physical __unused, off_t offset, size_t length)
static int nd_debug
SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD|CTLTYPE_INT|CTLFLAG_MPSAFE, NULL, 0, netdump_enabled_sysctl, "I", "netdump configuration status")
static void netdump_set_enabled(bool status)
static eventhandler_tag nd_detach_cookie
static struct ifnet * nd_ifp
union kd_ip ndc_gateway
DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY)
static int netdump_modevent(module_t mod, int type, void *priv)
static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
static struct cdevsw netdump_cdevsw
static void netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
__FBSDID("$FreeBSD$")
SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, &nd_debug, 0, "Debug message verbosity")
#define COPY_SIZED(elm)
#define NETDUMP_RUNLOCK()
static int netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
off_t nd_tx_off
static struct @31 nd_conf
static struct cdev * netdump_cdev
#define NETDUMP_ASSERT_WLOCKED()
static unsigned char nd_buf[MAXDUMPPGS *PAGE_SIZE]
#define nd_server
static void netdump_unconfigure(void)
static struct sx nd_conf_lk
static bool netdump_enabled(void)
static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, int flags __unused, struct thread *td)
union kd_ip ndc_client
char ndc_iface[IFNAMSIZ]
union kd_ip ndc_server
#define NETDUMP_ASSERT_LOCKED()
static int netdump_configure(struct diocskerneldump_arg *, struct thread *)
static char nd_path[MAXPATHLEN]
#define NETDUMP_RLOCK()
FEATURE(netdump, "Netdump client support")
uint8_t ndc_af
Definition: in.h:83
struct in_addr ndc12_server
Definition: netdump.h:63
struct diocskerneldump_arg_freebsd12 ndc12_kda
Definition: netdump.h:61
char ndc12_iface[IFNAMSIZ]
Definition: netdump.h:62
struct in_addr ndc12_gateway
Definition: netdump.h:65
struct in_addr ndc12_client
Definition: netdump.h:64