Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/netdump/netdump_client.c
Show First 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
} while (0) | } while (0) | ||||
#define NETDDEBUGV_IF(i, f, ...) do { \ | #define NETDDEBUGV_IF(i, f, ...) do { \ | ||||
if (nd_debug > 1) \ | if (nd_debug > 1) \ | ||||
if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \ | if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \ | ||||
} while (0) | } while (0) | ||||
static int netdump_arp_gw(void); | static int netdump_arp_gw(void); | ||||
static void netdump_cleanup(void); | static void netdump_cleanup(void); | ||||
static int netdump_configure(struct netdump_conf *, struct thread *); | static int netdump_configure(struct diocskerneldump_arg *, | ||||
struct thread *); | |||||
static int netdump_dumper(void *priv __unused, void *virtual, | static int netdump_dumper(void *priv __unused, void *virtual, | ||||
vm_offset_t physical __unused, off_t offset, size_t length); | vm_offset_t physical __unused, off_t offset, size_t length); | ||||
static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp, | static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp, | ||||
struct ether_addr dst, u_short etype); | struct ether_addr dst, u_short etype); | ||||
static void netdump_handle_arp(struct mbuf **mb); | static void netdump_handle_arp(struct mbuf **mb); | ||||
static void netdump_handle_ip(struct mbuf **mb); | static void netdump_handle_ip(struct mbuf **mb); | ||||
static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, | static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, | ||||
caddr_t addr, int flags __unused, struct thread *td); | caddr_t addr, int flags __unused, struct thread *td); | ||||
Show All 12 Lines | |||||
static int dump_failed, have_gw_mac; | static int dump_failed, have_gw_mac; | ||||
static void (*drv_if_input)(struct ifnet *, struct mbuf *); | static void (*drv_if_input)(struct ifnet *, struct mbuf *); | ||||
static int restore_gw_addr; | static int restore_gw_addr; | ||||
static uint64_t rcvd_acks; | static uint64_t rcvd_acks; | ||||
CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT); | CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT); | ||||
/* Configuration parameters. */ | /* Configuration parameters. */ | ||||
static struct netdump_conf nd_conf; | static struct diocskerneldump_arg nd_conf; | ||||
#define nd_server nd_conf.ndc_server | #define nd_server nd_conf.kda_server | ||||
#define nd_client nd_conf.ndc_client | #define nd_client nd_conf.kda_client | ||||
#define nd_gateway nd_conf.ndc_gateway | #define nd_gateway nd_conf.kda_gateway | ||||
/* General dynamic settings. */ | /* General dynamic settings. */ | ||||
static struct ether_addr nd_gw_mac; | static struct ether_addr nd_gw_mac; | ||||
static struct ifnet *nd_ifp; | static struct ifnet *nd_ifp; | ||||
static uint16_t nd_server_port = NETDUMP_PORT; | static uint16_t nd_server_port = NETDUMP_PORT; | ||||
FEATURE(netdump, "Netdump client support"); | FEATURE(netdump, "Netdump client support"); | ||||
▲ Show 20 Lines • Show All 921 Lines • ▼ Show 20 Lines | static struct cdevsw netdump_cdevsw = { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_ioctl = netdump_ioctl, | .d_ioctl = netdump_ioctl, | ||||
.d_name = "netdump", | .d_name = "netdump", | ||||
}; | }; | ||||
static struct cdev *netdump_cdev; | static struct cdev *netdump_cdev; | ||||
static int | static int | ||||
netdump_configure(struct netdump_conf *conf, struct thread *td) | netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) | ||||
{ | { | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
CURVNET_SET(TD_TO_VNET(td)); | CURVNET_SET(TD_TO_VNET(td)); | ||||
if (!IS_DEFAULT_VNET(curvnet)) { | if (!IS_DEFAULT_VNET(curvnet)) { | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | ||||
if (strcmp(ifp->if_xname, conf->ndc_iface) == 0) | if (strcmp(ifp->if_xname, conf->kda_iface) == 0) | ||||
break; | break; | ||||
} | } | ||||
/* XXX ref */ | /* XXX ref */ | ||||
NET_EPOCH_EXIT(et); | NET_EPOCH_EXIT(et); | ||||
CURVNET_RESTORE(); | CURVNET_RESTORE(); | ||||
if (ifp == NULL) | if (ifp == NULL) | ||||
return (ENOENT); | return (ENOENT); | ||||
if ((if_getflags(ifp) & IFF_UP) == 0) | if ((if_getflags(ifp) & IFF_UP) == 0) | ||||
return (ENXIO); | return (ENXIO); | ||||
if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) | if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) | ||||
return (EINVAL); | return (ENODEV); | ||||
nd_ifp = ifp; | nd_ifp = ifp; | ||||
netdump_reinit(ifp); | netdump_reinit(ifp); | ||||
memcpy(&nd_conf, conf, sizeof(nd_conf)); | memcpy(&nd_conf, conf, sizeof(nd_conf)); | ||||
nd_enabled = 1; | nd_enabled = 1; | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 35 Lines | |||||
* | * | ||||
* Returns: | * Returns: | ||||
* 0 on success, and an errno value on failure. | * 0 on success, and an errno value on failure. | ||||
*/ | */ | ||||
static int | static int | ||||
netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, | netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, | ||||
int flags __unused, struct thread *td) | int flags __unused, struct thread *td) | ||||
{ | { | ||||
struct diocskerneldump_arg *kda; | struct diocskerneldump_arg kda_copy, *conf; | ||||
struct dumperinfo dumper; | struct dumperinfo dumper; | ||||
struct netdump_conf *conf; | |||||
uint8_t *encryptedkey; | uint8_t *encryptedkey; | ||||
int error; | int error; | ||||
#ifdef COMPAT_FREEBSD11 | #ifdef COMPAT_FREEBSD11 | ||||
u_int u; | u_int u; | ||||
#endif | #endif | ||||
#ifdef COMPAT_FREEBSD12 | |||||
struct diocskerneldump_arg_freebsd12 *kda12; | |||||
struct netdump_conf_freebsd12 *conf12; | |||||
#endif | |||||
conf = NULL; | |||||
error = 0; | error = 0; | ||||
switch (cmd) { | switch (cmd) { | ||||
#ifdef COMPAT_FREEBSD11 | #ifdef COMPAT_FREEBSD11 | ||||
case DIOCSKERNELDUMP_FREEBSD11: | case DIOCSKERNELDUMP_FREEBSD11: | ||||
gone_in(13, "11.x ABI compatibility"); | |||||
u = *(u_int *)addr; | u = *(u_int *)addr; | ||||
if (u != 0) { | if (u != 0) { | ||||
error = ENXIO; | error = ENXIO; | ||||
break; | break; | ||||
} | } | ||||
if (nd_enabled) { | if (nd_enabled) { | ||||
nd_enabled = 0; | nd_enabled = 0; | ||||
netdump_mbuf_drain(); | netdump_mbuf_drain(); | ||||
} | } | ||||
break; | break; | ||||
#endif | #endif | ||||
case DIOCSKERNELDUMP: | #ifdef COMPAT_FREEBSD12 | ||||
kda = (void *)addr; | /* | ||||
if (kda->kda_enable != 0) { | * Used by dumpon(8) in 12.x for clearing previous | ||||
* configuration -- then NETDUMPSCONF_FREEBSD12 is used to | |||||
* actually configure netdump. | |||||
*/ | |||||
case DIOCSKERNELDUMP_FREEBSD12: | |||||
gone_in(14, "12.x ABI compatibility"); | |||||
kda12 = (void *)addr; | |||||
if (kda12->kda12_enable) { | |||||
error = ENXIO; | error = ENXIO; | ||||
break; | break; | ||||
} | } | ||||
if (nd_enabled) { | if (nd_enabled) { | ||||
nd_enabled = 0; | nd_enabled = 0; | ||||
netdump_mbuf_drain(); | netdump_mbuf_drain(); | ||||
} | } | ||||
break; | break; | ||||
case NETDUMPGCONF: | |||||
conf = (struct netdump_conf *)addr; | case NETDUMPGCONF_FREEBSD12: | ||||
gone_in(14, "FreeBSD 12.x ABI compat"); | |||||
_Static_assert( | |||||
offsetof(struct diocskerneldump_arg, kda_iface) == | |||||
offsetof(struct netdump_conf_freebsd12, ndc12_iface), | |||||
"abi assumption"); | |||||
conf = (void *)addr; | |||||
/* FALLTHROUGH */ | |||||
#endif | |||||
case DIOCGKERNELDUMP: | |||||
if (cmd == DIOCGKERNELDUMP) | |||||
conf = (void *)addr; | |||||
/* | |||||
* For now, index is ignored; netdump doesn't support multiple | |||||
* configurations (yet). | |||||
*/ | |||||
if (!nd_enabled) { | if (!nd_enabled) { | ||||
error = ENXIO; | error = ENXIO; | ||||
conf = NULL; | |||||
break; | break; | ||||
} | } | ||||
strlcpy(conf->ndc_iface, nd_ifp->if_xname, | strlcpy(conf->kda_iface, nd_ifp->if_xname, | ||||
sizeof(conf->ndc_iface)); | sizeof(conf->kda_iface)); | ||||
memcpy(&conf->ndc_server, &nd_server, sizeof(nd_server)); | memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); | ||||
memcpy(&conf->ndc_client, &nd_client, sizeof(nd_client)); | memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); | ||||
memcpy(&conf->ndc_gateway, &nd_gateway, sizeof(nd_gateway)); | memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); | ||||
conf = NULL; | |||||
break; | break; | ||||
case NETDUMPSCONF: | |||||
conf = (struct netdump_conf *)addr; | #ifdef COMPAT_FREEBSD12 | ||||
case NETDUMPSCONF_FREEBSD12: | |||||
gone_in(14, "FreeBSD 12.x ABI compat"); | |||||
conf12 = (struct netdump_conf_freebsd12 *)addr; | |||||
_Static_assert(sizeof(kda_copy) == sizeof(*conf12), | |||||
"simplifying assumption"); | |||||
memcpy(&kda_copy, conf12, sizeof(kda_copy)); | |||||
kda_copy.kda_index = | |||||
(conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL); | |||||
conf = &kda_copy; | |||||
explicit_bzero(conf12, sizeof(*conf12)); | |||||
/* FALLTHROUGH */ | |||||
#endif | |||||
case DIOCSKERNELDUMP: | |||||
encryptedkey = NULL; | encryptedkey = NULL; | ||||
kda = &conf->ndc_kda; | if (cmd == DIOCSKERNELDUMP) { | ||||
conf = (void *)addr; | |||||
memcpy(&kda_copy, conf, sizeof(kda_copy)); | |||||
} | |||||
conf->ndc_iface[sizeof(conf->ndc_iface) - 1] = '\0'; | conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; | ||||
if (kda->kda_enable == 0) { | if (conf->kda_index == KDA_REMOVE || | ||||
if (nd_enabled) { | conf->kda_index == KDA_REMOVE_DEV || | ||||
error = clear_dumper(td); | conf->kda_index == KDA_REMOVE_ALL) { | ||||
if (nd_enabled || conf->kda_index == KDA_REMOVE_ALL) { | |||||
error = dumper_remove(conf->kda_iface, conf); | |||||
if (error == 0) { | if (error == 0) { | ||||
nd_enabled = 0; | nd_enabled = 0; | ||||
netdump_mbuf_drain(); | netdump_mbuf_drain(); | ||||
} | } | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
error = netdump_configure(conf, td); | error = netdump_configure(conf, td); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
if (kda->kda_encryption != KERNELDUMP_ENC_NONE) { | if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { | ||||
if (kda->kda_encryptedkeysize <= 0 || | if (conf->kda_encryptedkeysize <= 0 || | ||||
kda->kda_encryptedkeysize > | conf->kda_encryptedkeysize > | ||||
KERNELDUMP_ENCKEY_MAX_SIZE) | KERNELDUMP_ENCKEY_MAX_SIZE) { | ||||
return (EINVAL); | error = EINVAL; | ||||
encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP, | break; | ||||
M_WAITOK); | } | ||||
error = copyin(kda->kda_encryptedkey, encryptedkey, | encryptedkey = malloc(conf->kda_encryptedkeysize, | ||||
kda->kda_encryptedkeysize); | M_TEMP, M_WAITOK); | ||||
error = copyin(conf->kda_encryptedkey, encryptedkey, | |||||
conf->kda_encryptedkeysize); | |||||
if (error != 0) { | if (error != 0) { | ||||
free(encryptedkey, M_TEMP); | free(encryptedkey, M_TEMP); | ||||
return (error); | break; | ||||
} | } | ||||
conf->kda_encryptedkey = encryptedkey; | |||||
} | } | ||||
memset(&dumper, 0, sizeof(dumper)); | memset(&dumper, 0, sizeof(dumper)); | ||||
dumper.dumper_start = netdump_start; | dumper.dumper_start = netdump_start; | ||||
dumper.dumper_hdr = netdump_write_headers; | dumper.dumper_hdr = netdump_write_headers; | ||||
dumper.dumper = netdump_dumper; | dumper.dumper = netdump_dumper; | ||||
dumper.priv = NULL; | dumper.priv = NULL; | ||||
dumper.blocksize = NETDUMP_DATASIZE; | dumper.blocksize = NETDUMP_DATASIZE; | ||||
dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; | dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; | ||||
dumper.mediaoffset = 0; | dumper.mediaoffset = 0; | ||||
dumper.mediasize = 0; | dumper.mediasize = 0; | ||||
error = set_dumper(&dumper, conf->ndc_iface, td, | error = dumper_insert(&dumper, conf->kda_iface, conf); | ||||
kda->kda_compression, kda->kda_encryption, | |||||
kda->kda_key, kda->kda_encryptedkeysize, | |||||
encryptedkey); | |||||
if (encryptedkey != NULL) { | if (encryptedkey != NULL) { | ||||
explicit_bzero(encryptedkey, kda->kda_encryptedkeysize); | explicit_bzero(encryptedkey, | ||||
conf->kda_encryptedkeysize); | |||||
free(encryptedkey, M_TEMP); | free(encryptedkey, M_TEMP); | ||||
} | } | ||||
if (error != 0) { | if (error != 0) { | ||||
nd_enabled = 0; | nd_enabled = 0; | ||||
netdump_mbuf_drain(); | netdump_mbuf_drain(); | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = ENOTTY; | ||||
break; | break; | ||||
} | } | ||||
explicit_bzero(&kda_copy, sizeof(kda_copy)); | |||||
if (conf != NULL) | |||||
explicit_bzero(conf, sizeof(*conf)); | |||||
cem: I believe this explicit bzeroing came in to geom_dev via the EKCD commit(s); I included it here… | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Called upon system init or kld load. Initializes the netdump parameters to | * Called upon system init or kld load. Initializes the netdump parameters to | ||||
* sane defaults (locates the first available NIC and uses the first IPv4 IP on | * sane defaults (locates the first available NIC and uses the first IPv4 IP on | ||||
* that card as the client IP). Leaves the server IP unconfigured. | * that card as the client IP). Leaves the server IP unconfigured. | ||||
* | * | ||||
* Parameters: | * Parameters: | ||||
* mod, Unused. | * mod, Unused. | ||||
* what, The module event type. | * what, The module event type. | ||||
* priv, Unused. | * priv, Unused. | ||||
* | * | ||||
* Returns: | * Returns: | ||||
* int, An errno value if an error occured, 0 otherwise. | * int, An errno value if an error occured, 0 otherwise. | ||||
*/ | */ | ||||
static int | static int | ||||
netdump_modevent(module_t mod __unused, int what, void *priv __unused) | netdump_modevent(module_t mod __unused, int what, void *priv __unused) | ||||
{ | { | ||||
struct netdump_conf conf; | struct diocskerneldump_arg conf; | ||||
char *arg; | char *arg; | ||||
int error; | int error; | ||||
error = 0; | error = 0; | ||||
switch (what) { | switch (what) { | ||||
case MOD_LOAD: | case MOD_LOAD: | ||||
error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, | error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, | ||||
&netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); | &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); | ||||
if (error != 0) | if (error != 0) | ||||
return (error); | return (error); | ||||
if ((arg = kern_getenv("net.dump.iface")) != NULL) { | if ((arg = kern_getenv("net.dump.iface")) != NULL) { | ||||
strlcpy(conf.ndc_iface, arg, sizeof(conf.ndc_iface)); | strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); | ||||
freeenv(arg); | freeenv(arg); | ||||
if ((arg = kern_getenv("net.dump.server")) != NULL) { | if ((arg = kern_getenv("net.dump.server")) != NULL) { | ||||
inet_aton(arg, &conf.ndc_server); | inet_aton(arg, &conf.kda_server); | ||||
freeenv(arg); | freeenv(arg); | ||||
} | } | ||||
if ((arg = kern_getenv("net.dump.client")) != NULL) { | if ((arg = kern_getenv("net.dump.client")) != NULL) { | ||||
inet_aton(arg, &conf.ndc_server); | inet_aton(arg, &conf.kda_server); | ||||
freeenv(arg); | freeenv(arg); | ||||
} | } | ||||
if ((arg = kern_getenv("net.dump.gateway")) != NULL) { | if ((arg = kern_getenv("net.dump.gateway")) != NULL) { | ||||
inet_aton(arg, &conf.ndc_server); | inet_aton(arg, &conf.kda_server); | ||||
freeenv(arg); | freeenv(arg); | ||||
} | } | ||||
/* Ignore errors; we print a message to the console. */ | /* Ignore errors; we print a message to the console. */ | ||||
(void)netdump_configure(&conf, curthread); | (void)netdump_configure(&conf, curthread); | ||||
} | } | ||||
break; | break; | ||||
case MOD_UNLOAD: | case MOD_UNLOAD: | ||||
destroy_dev(netdump_cdev); | |||||
if (nd_enabled) { | if (nd_enabled) { | ||||
struct diocskerneldump_arg kda; | |||||
printf("netdump: disabling dump device for unload\n"); | printf("netdump: disabling dump device for unload\n"); | ||||
(void)clear_dumper(curthread); | |||||
bzero(&kda, sizeof(kda)); | |||||
kda.kda_index = KDA_REMOVE_DEV; | |||||
(void)dumper_remove(nd_conf.kda_iface, &kda); | |||||
netdump_mbuf_drain(); | |||||
nd_enabled = 0; | nd_enabled = 0; | ||||
} | } | ||||
destroy_dev(netdump_cdev); | |||||
break; | break; | ||||
default: | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 44 Lines • Show Last 20 Lines |
I believe this explicit bzeroing came in to geom_dev via the EKCD commit(s); I included it here for parity with geom_dev configuration.