The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/netdump/netdump_client.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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", &params);
  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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.