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 | 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 * physical Unused. Physical memory address.
229 * offset Offset from start of core file
230 * length Data length
231 *
232 * Return value:
233 * 0 on success
234 * errno on error
235 */
236 static int
netdump_dumper(void * priv __unused,void * virtual,vm_offset_t physical __unused,off_t offset,size_t length)237 netdump_dumper(void *priv __unused, void *virtual,
238 vm_offset_t physical __unused, 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 debugnet_free(nd_conf.nd_pcb);
258 nd_conf.nd_pcb = NULL;
259 return (0);
260 }
261 if (length > sizeof(nd_buf))
262 return (ENOSPC);
263
264 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
265 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
266 nd_conf.nd_buf_len != offset)) {
267 error = netdump_flush_buf();
268 if (error != 0) {
269 dump_failed = 1;
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)285 netdump_start(struct dumperinfo *di)
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 return (0);
337 }
338
339 static int
netdump_write_headers(struct dumperinfo * di,struct kerneldumpheader * kdh,void * key,uint32_t keysize)340 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh,
341 void *key, uint32_t keysize)
342 {
343 int error;
344
345 error = netdump_flush_buf();
346 if (error != 0)
347 return (error);
348 memcpy(nd_buf, kdh, sizeof(*kdh));
349 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
350 sizeof(*kdh), NULL);
351 if (error == 0 && keysize > 0) {
352 if (keysize > sizeof(nd_buf))
353 return (EINVAL);
354 memcpy(nd_buf, key, keysize);
355 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_EKCD_KEY, nd_buf,
356 keysize, NULL);
357 }
358 return (error);
359 }
360
361 /*-
362 * KLD specific code.
363 */
364
365 static struct cdevsw netdump_cdevsw = {
366 .d_version = D_VERSION,
367 .d_ioctl = netdump_ioctl,
368 .d_name = "netdump",
369 };
370
371 static struct cdev *netdump_cdev;
372
373 static void
netdump_unconfigure(void)374 netdump_unconfigure(void)
375 {
376 struct diocskerneldump_arg kda;
377
378 NETDUMP_ASSERT_WLOCKED();
379 KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
380
381 bzero(&kda, sizeof(kda));
382 kda.kda_index = KDA_REMOVE_DEV;
383 (void)dumper_remove(nd_conf.ndc_iface, &kda);
384
385 if (nd_ifp != NULL)
386 if_rele(nd_ifp);
387 nd_ifp = NULL;
388 netdump_set_enabled(false);
389
390 log(LOG_WARNING, "netdump: Lost configured interface %s\n",
391 nd_conf.ndc_iface);
392
393 bzero(&nd_conf, sizeof(nd_conf));
394 }
395
396 static void
netdump_ifdetach(void * arg __unused,struct ifnet * ifp)397 netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
398 {
399
400 NETDUMP_WLOCK();
401 if (ifp == nd_ifp)
402 netdump_unconfigure();
403 NETDUMP_WUNLOCK();
404 }
405
406 /*
407 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
408 * modload-based tunable parameters).
409 */
410 static int
netdump_configure(struct diocskerneldump_arg * conf,struct thread * td)411 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
412 {
413 struct ifnet *ifp;
414
415 NETDUMP_ASSERT_WLOCKED();
416
417 if (conf->kda_iface[0] != 0) {
418 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
419 return (EINVAL);
420 CURVNET_SET(vnet0);
421 ifp = ifunit_ref(conf->kda_iface);
422 CURVNET_RESTORE();
423 } else
424 ifp = NULL;
425
426 if (nd_ifp != NULL)
427 if_rele(nd_ifp);
428 nd_ifp = ifp;
429 netdump_set_enabled(true);
430
431 #define COPY_SIZED(elm) do { \
432 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
433 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
434 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \
435 sizeof(nd_conf.ndc_ ## elm)); \
436 } while (0)
437 COPY_SIZED(iface);
438 COPY_SIZED(server);
439 COPY_SIZED(client);
440 COPY_SIZED(gateway);
441 COPY_SIZED(af);
442 #undef COPY_SIZED
443
444 return (0);
445 }
446
447 /*
448 * ioctl(2) handler for the netdump device. This is currently only used to
449 * register netdump as a dump device.
450 *
451 * Parameters:
452 * dev, Unused.
453 * cmd, The ioctl to be handled.
454 * addr, The parameter for the ioctl.
455 * flags, Unused.
456 * td, The thread invoking this ioctl.
457 *
458 * Returns:
459 * 0 on success, and an errno value on failure.
460 */
461 static int
netdump_ioctl(struct cdev * dev __unused,u_long cmd,caddr_t addr,int flags __unused,struct thread * td)462 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
463 int flags __unused, struct thread *td)
464 {
465 struct diocskerneldump_arg kda_copy, *conf;
466 struct dumperinfo dumper;
467 uint8_t *encryptedkey;
468 int error;
469 #ifdef COMPAT_FREEBSD11
470 u_int u;
471 #endif
472 #ifdef COMPAT_FREEBSD12
473 struct diocskerneldump_arg_freebsd12 *kda12;
474 struct netdump_conf_freebsd12 *conf12;
475 #endif
476
477 conf = NULL;
478 error = 0;
479 NETDUMP_WLOCK();
480
481 switch (cmd) {
482 #ifdef COMPAT_FREEBSD11
483 case DIOCSKERNELDUMP_FREEBSD11:
484 gone_in(13, "11.x ABI compatibility");
485 u = *(u_int *)addr;
486 if (u != 0) {
487 error = ENXIO;
488 break;
489 }
490 if (netdump_enabled())
491 netdump_unconfigure();
492 break;
493 #endif
494 #ifdef COMPAT_FREEBSD12
495 /*
496 * Used by dumpon(8) in 12.x for clearing previous
497 * configuration -- then NETDUMPSCONF_FREEBSD12 is used to
498 * actually configure netdump.
499 */
500 case DIOCSKERNELDUMP_FREEBSD12:
501 gone_in(14, "12.x ABI compatibility");
502
503 kda12 = (void *)addr;
504 if (kda12->kda12_enable) {
505 error = ENXIO;
506 break;
507 }
508 if (netdump_enabled())
509 netdump_unconfigure();
510 break;
511
512 case NETDUMPGCONF_FREEBSD12:
513 gone_in(14, "FreeBSD 12.x ABI compat");
514 conf12 = (void *)addr;
515
516 if (!netdump_enabled()) {
517 error = ENXIO;
518 break;
519 }
520 if (nd_conf.ndc_af != AF_INET) {
521 error = EOPNOTSUPP;
522 break;
523 }
524
525 if (nd_ifp != NULL)
526 strlcpy(conf12->ndc12_iface, nd_ifp->if_xname,
527 sizeof(conf12->ndc12_iface));
528 memcpy(&conf12->ndc12_server, &nd_server,
529 sizeof(conf12->ndc12_server));
530 memcpy(&conf12->ndc12_client, &nd_client,
531 sizeof(conf12->ndc12_client));
532 memcpy(&conf12->ndc12_gateway, &nd_gateway,
533 sizeof(conf12->ndc12_gateway));
534 break;
535 #endif
536 case DIOCGKERNELDUMP:
537 conf = (void *)addr;
538 /*
539 * For now, index is ignored; netdump doesn't support multiple
540 * configurations (yet).
541 */
542 if (!netdump_enabled()) {
543 error = ENXIO;
544 conf = NULL;
545 break;
546 }
547
548 if (nd_ifp != NULL)
549 strlcpy(conf->kda_iface, nd_ifp->if_xname,
550 sizeof(conf->kda_iface));
551 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
552 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
553 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
554 conf->kda_af = nd_conf.ndc_af;
555 conf = NULL;
556 break;
557
558 #ifdef COMPAT_FREEBSD12
559 case NETDUMPSCONF_FREEBSD12:
560 gone_in(14, "FreeBSD 12.x ABI compat");
561
562 conf12 = (struct netdump_conf_freebsd12 *)addr;
563
564 _Static_assert(offsetof(struct diocskerneldump_arg, kda_server)
565 == offsetof(struct netdump_conf_freebsd12, ndc12_server),
566 "simplifying assumption");
567
568 memset(&kda_copy, 0, sizeof(kda_copy));
569 memcpy(&kda_copy, conf12,
570 offsetof(struct diocskerneldump_arg, kda_server));
571
572 /* 12.x ABI could only configure IPv4 (INET) netdump. */
573 kda_copy.kda_af = AF_INET;
574 memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server,
575 sizeof(struct in_addr));
576 memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client,
577 sizeof(struct in_addr));
578 memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway,
579 sizeof(struct in_addr));
580
581 kda_copy.kda_index =
582 (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL);
583
584 conf = &kda_copy;
585 explicit_bzero(conf12, sizeof(*conf12));
586 /* FALLTHROUGH */
587 #endif
588 case DIOCSKERNELDUMP:
589 encryptedkey = NULL;
590 if (cmd == DIOCSKERNELDUMP) {
591 conf = (void *)addr;
592 memcpy(&kda_copy, conf, sizeof(kda_copy));
593 }
594 /* Netdump only supports IP4 at this time. */
595 if (conf->kda_af != AF_INET) {
596 error = EPROTONOSUPPORT;
597 break;
598 }
599
600 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
601 if (conf->kda_index == KDA_REMOVE ||
602 conf->kda_index == KDA_REMOVE_DEV ||
603 conf->kda_index == KDA_REMOVE_ALL) {
604 if (netdump_enabled())
605 netdump_unconfigure();
606 if (conf->kda_index == KDA_REMOVE_ALL)
607 error = dumper_remove(NULL, conf);
608 break;
609 }
610
611 error = netdump_configure(conf, td);
612 if (error != 0)
613 break;
614
615 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
616 if (conf->kda_encryptedkeysize <= 0 ||
617 conf->kda_encryptedkeysize >
618 KERNELDUMP_ENCKEY_MAX_SIZE) {
619 error = EINVAL;
620 break;
621 }
622 encryptedkey = malloc(conf->kda_encryptedkeysize,
623 M_TEMP, M_WAITOK);
624 error = copyin(conf->kda_encryptedkey, encryptedkey,
625 conf->kda_encryptedkeysize);
626 if (error != 0) {
627 free(encryptedkey, M_TEMP);
628 break;
629 }
630
631 conf->kda_encryptedkey = encryptedkey;
632 }
633
634 memset(&dumper, 0, sizeof(dumper));
635 dumper.dumper_start = netdump_start;
636 dumper.dumper_hdr = netdump_write_headers;
637 dumper.dumper = netdump_dumper;
638 dumper.priv = NULL;
639 dumper.blocksize = NETDUMP_DATASIZE;
640 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
641 dumper.mediaoffset = 0;
642 dumper.mediasize = 0;
643
644 error = dumper_insert(&dumper, conf->kda_iface, conf);
645 zfree(encryptedkey, M_TEMP);
646 if (error != 0)
647 netdump_unconfigure();
648 break;
649 default:
650 error = ENOTTY;
651 break;
652 }
653 explicit_bzero(&kda_copy, sizeof(kda_copy));
654 if (conf != NULL)
655 explicit_bzero(conf, sizeof(*conf));
656 NETDUMP_WUNLOCK();
657 return (error);
658 }
659
660 /*
661 * Called upon system init or kld load. Initializes the netdump parameters to
662 * sane defaults (locates the first available NIC and uses the first IPv4 IP on
663 * that card as the client IP). Leaves the server IP unconfigured.
664 *
665 * Parameters:
666 * mod, Unused.
667 * what, The module event type.
668 * priv, Unused.
669 *
670 * Returns:
671 * int, An errno value if an error occured, 0 otherwise.
672 */
673 static int
netdump_modevent(module_t mod __unused,int what,void * priv __unused)674 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
675 {
676 struct diocskerneldump_arg conf;
677 char *arg;
678 int error;
679
680 error = 0;
681 switch (what) {
682 case MOD_LOAD:
683 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
684 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
685 if (error != 0)
686 return (error);
687
688 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
689 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
690
691 if ((arg = kern_getenv("net.dump.iface")) != NULL) {
692 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
693 freeenv(arg);
694
695 if ((arg = kern_getenv("net.dump.server")) != NULL) {
696 inet_aton(arg, &conf.kda_server.in4);
697 freeenv(arg);
698 }
699 if ((arg = kern_getenv("net.dump.client")) != NULL) {
700 inet_aton(arg, &conf.kda_client.in4);
701 freeenv(arg);
702 }
703 if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
704 inet_aton(arg, &conf.kda_gateway.in4);
705 freeenv(arg);
706 }
707 conf.kda_af = AF_INET;
708
709 /* Ignore errors; we print a message to the console. */
710 NETDUMP_WLOCK();
711 (void)netdump_configure(&conf, NULL);
712 NETDUMP_WUNLOCK();
713 }
714 break;
715 case MOD_UNLOAD:
716 NETDUMP_WLOCK();
717 if (netdump_enabled()) {
718 printf("netdump: disabling dump device for unload\n");
719 netdump_unconfigure();
720 }
721 NETDUMP_WUNLOCK();
722 destroy_dev(netdump_cdev);
723 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
724 nd_detach_cookie);
725 break;
726 default:
727 error = EOPNOTSUPP;
728 break;
729 }
730 return (error);
731 }
732
733 static moduledata_t netdump_mod = {
734 "netdump",
735 netdump_modevent,
736 NULL,
737 };
738
739 MODULE_VERSION(netdump, 1);
740 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
741
742 #ifdef DDB
743 /*
744 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
745 *
746 * Order is not significant.
747 *
748 * Currently, this command does not support configuring encryption or
749 * compression.
750 */
DB_FUNC(netdump,db_netdump_cmd,db_cmd_table,CS_OWN,NULL)751 DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL)
752 {
753 static struct diocskerneldump_arg conf;
754 static char blockbuf[NETDUMP_DATASIZE];
755 static union {
756 struct dumperinfo di;
757 /* For valid di_devname. */
758 char di_buf[sizeof(struct dumperinfo) + 1];
759 } u;
760
761 struct debugnet_ddb_config params;
762 int error;
763
764 error = debugnet_parse_ddb_cmd("netdump", ¶ms);
765 if (error != 0) {
766 db_printf("Error configuring netdump: %d\n", error);
767 return;
768 }
769
770 /* Translate to a netdump dumper config. */
771 memset(&conf, 0, sizeof(conf));
772
773 if (params.dd_ifp != NULL)
774 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
775 sizeof(conf.kda_iface));
776
777 conf.kda_af = AF_INET;
778 conf.kda_server.in4 = (struct in_addr) { params.dd_server };
779 if (params.dd_has_client)
780 conf.kda_client.in4 = (struct in_addr) { params.dd_client };
781 else
782 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
783 if (params.dd_has_gateway)
784 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
785 else
786 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
787
788 /* Set the global netdump config to these options. */
789 error = netdump_configure(&conf, NULL);
790 if (error != 0) {
791 db_printf("Error enabling netdump: %d\n", error);
792 return;
793 }
794
795 /* Fake the generic dump configuration list entry to avoid malloc. */
796 memset(&u.di_buf, 0, sizeof(u.di_buf));
797 u.di.dumper_start = netdump_start;
798 u.di.dumper_hdr = netdump_write_headers;
799 u.di.dumper = netdump_dumper;
800 u.di.priv = NULL;
801 u.di.blocksize = NETDUMP_DATASIZE;
802 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
803 u.di.mediaoffset = 0;
804 u.di.mediasize = 0;
805 u.di.blockbuf = blockbuf;
806
807 dumper_ddb_insert(&u.di);
808
809 error = doadump(false);
810
811 dumper_ddb_remove(&u.di);
812 if (error != 0)
813 db_printf("Cannot dump: %d\n", error);
814 }
815 #endif /* DDB */
816