1e5054602SMark Johnston /*- 2e5054602SMark Johnston * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved. 3e5054602SMark Johnston * Copyright (c) 2000 Darrell Anderson 4e5054602SMark Johnston * All rights reserved. 5e5054602SMark Johnston * 6e5054602SMark Johnston * Redistribution and use in source and binary forms, with or without 7e5054602SMark Johnston * modification, are permitted provided that the following conditions 8e5054602SMark Johnston * are met: 9e5054602SMark Johnston * 1. Redistributions of source code must retain the above copyright 10e5054602SMark Johnston * notice, this list of conditions and the following disclaimer. 11e5054602SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 12e5054602SMark Johnston * notice, this list of conditions and the following disclaimer in the 13e5054602SMark Johnston * documentation and/or other materials provided with the distribution. 14e5054602SMark Johnston * 15e5054602SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e5054602SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e5054602SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e5054602SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e5054602SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e5054602SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e5054602SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e5054602SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e5054602SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e5054602SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e5054602SMark Johnston * SUCH DAMAGE. 26e5054602SMark Johnston */ 27e5054602SMark Johnston 28e5054602SMark Johnston /* 29e5054602SMark Johnston * netdump_client.c 30e5054602SMark Johnston * FreeBSD subsystem supporting netdump network dumps. 31e5054602SMark Johnston * A dedicated server must be running to accept client dumps. 32e5054602SMark Johnston */ 33e5054602SMark Johnston 34e5054602SMark Johnston #include <sys/cdefs.h> 35e5054602SMark Johnston __FBSDID("$FreeBSD$"); 36e5054602SMark Johnston 37e5054602SMark Johnston #include <sys/param.h> 38e5054602SMark Johnston #include <sys/conf.h> 39e5054602SMark Johnston #include <sys/disk.h> 40e5054602SMark Johnston #include <sys/endian.h> 41b35822d9SMark Johnston #include <sys/jail.h> 42e5054602SMark Johnston #include <sys/kernel.h> 43e5054602SMark Johnston #include <sys/kerneldump.h> 44e5054602SMark Johnston #include <sys/mbuf.h> 45e5054602SMark Johnston #include <sys/module.h> 46e5054602SMark Johnston #include <sys/priv.h> 47e5054602SMark Johnston #include <sys/proc.h> 48e5054602SMark Johnston #include <sys/protosw.h> 49e5054602SMark Johnston #include <sys/socket.h> 50e5054602SMark Johnston #include <sys/sysctl.h> 51e5054602SMark Johnston #include <sys/systm.h> 52e5054602SMark Johnston 53e5054602SMark Johnston #include <net/ethernet.h> 54e5054602SMark Johnston #include <net/if.h> 55e5054602SMark Johnston #include <net/if_arp.h> 56e5054602SMark Johnston #include <net/if_dl.h> 57e5054602SMark Johnston #include <net/if_types.h> 58e5054602SMark Johnston #include <net/if_var.h> 59e5054602SMark Johnston 60e5054602SMark Johnston #include <netinet/in.h> 61e5054602SMark Johnston #include <netinet/in_systm.h> 62e5054602SMark Johnston #include <netinet/in_var.h> 63e5054602SMark Johnston #include <netinet/ip.h> 64e5054602SMark Johnston #include <netinet/ip_var.h> 65e5054602SMark Johnston #include <netinet/ip_options.h> 66e5054602SMark Johnston #include <netinet/udp.h> 67e5054602SMark Johnston #include <netinet/udp_var.h> 68e5054602SMark Johnston #include <netinet/netdump/netdump.h> 69e5054602SMark Johnston 70e5054602SMark Johnston #include <machine/in_cksum.h> 71e5054602SMark Johnston #include <machine/pcb.h> 72e5054602SMark Johnston 73e5054602SMark Johnston #define NETDDEBUG(f, ...) do { \ 74e5054602SMark Johnston if (nd_debug > 0) \ 75e5054602SMark Johnston printf(("%s: " f), __func__, ## __VA_ARGS__); \ 76e5054602SMark Johnston } while (0) 77e5054602SMark Johnston #define NETDDEBUG_IF(i, f, ...) do { \ 78e5054602SMark Johnston if (nd_debug > 0) \ 79e5054602SMark Johnston if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \ 80e5054602SMark Johnston } while (0) 81e5054602SMark Johnston #define NETDDEBUGV(f, ...) do { \ 82e5054602SMark Johnston if (nd_debug > 1) \ 83e5054602SMark Johnston printf(("%s: " f), __func__, ## __VA_ARGS__); \ 84e5054602SMark Johnston } while (0) 85e5054602SMark Johnston #define NETDDEBUGV_IF(i, f, ...) do { \ 86e5054602SMark Johnston if (nd_debug > 1) \ 87e5054602SMark Johnston if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \ 88e5054602SMark Johnston } while (0) 89e5054602SMark Johnston 90e5054602SMark Johnston static int netdump_arp_gw(void); 91e5054602SMark Johnston static void netdump_cleanup(void); 92*6b6e2954SConrad Meyer static int netdump_configure(struct diocskerneldump_arg *, 93*6b6e2954SConrad Meyer struct thread *); 94e5054602SMark Johnston static int netdump_dumper(void *priv __unused, void *virtual, 95e5054602SMark Johnston vm_offset_t physical __unused, off_t offset, size_t length); 96e5054602SMark Johnston static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp, 97e5054602SMark Johnston struct ether_addr dst, u_short etype); 98e5054602SMark Johnston static void netdump_handle_arp(struct mbuf **mb); 99e5054602SMark Johnston static void netdump_handle_ip(struct mbuf **mb); 100e5054602SMark Johnston static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, 101e5054602SMark Johnston caddr_t addr, int flags __unused, struct thread *td); 102e5054602SMark Johnston static int netdump_modevent(module_t mod, int type, void *priv); 103e5054602SMark Johnston static void netdump_network_poll(void); 104e5054602SMark Johnston static void netdump_pkt_in(struct ifnet *ifp, struct mbuf *m); 105e5054602SMark Johnston static int netdump_send(uint32_t type, off_t offset, unsigned char *data, 106e5054602SMark Johnston uint32_t datalen); 107e5054602SMark Johnston static int netdump_send_arp(in_addr_t dst); 108e5054602SMark Johnston static int netdump_start(struct dumperinfo *di); 109e5054602SMark Johnston static int netdump_udp_output(struct mbuf *m); 110e5054602SMark Johnston 111e5054602SMark Johnston /* Must be at least as big as the chunks dumpsys() gives us. */ 112e5054602SMark Johnston static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE]; 113e5054602SMark Johnston static uint32_t nd_seqno; 114e5054602SMark Johnston static int dump_failed, have_gw_mac; 115e5054602SMark Johnston static void (*drv_if_input)(struct ifnet *, struct mbuf *); 116e5054602SMark Johnston static int restore_gw_addr; 117e5054602SMark Johnston 118e5054602SMark Johnston static uint64_t rcvd_acks; 119e5054602SMark Johnston CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT); 120e5054602SMark Johnston 121e5054602SMark Johnston /* Configuration parameters. */ 122*6b6e2954SConrad Meyer static struct diocskerneldump_arg nd_conf; 123*6b6e2954SConrad Meyer #define nd_server nd_conf.kda_server.in4 124*6b6e2954SConrad Meyer #define nd_client nd_conf.kda_client.in4 125*6b6e2954SConrad Meyer #define nd_gateway nd_conf.kda_gateway.in4 126e5054602SMark Johnston 127e5054602SMark Johnston /* General dynamic settings. */ 128e5054602SMark Johnston static struct ether_addr nd_gw_mac; 129e5054602SMark Johnston static struct ifnet *nd_ifp; 130e5054602SMark Johnston static uint16_t nd_server_port = NETDUMP_PORT; 131e5054602SMark Johnston 132e5054602SMark Johnston FEATURE(netdump, "Netdump client support"); 133e5054602SMark Johnston 134e5054602SMark Johnston static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL, 135e5054602SMark Johnston "netdump parameters"); 136e5054602SMark Johnston 137e5054602SMark Johnston static int nd_debug; 138e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, 139e5054602SMark Johnston &nd_debug, 0, 140e5054602SMark Johnston "Debug message verbosity"); 141e5054602SMark Johnston static int nd_enabled; 142e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD, 143e5054602SMark Johnston &nd_enabled, 0, 144e5054602SMark Johnston "netdump configuration status"); 145e5054602SMark Johnston static char nd_path[MAXPATHLEN]; 146e5054602SMark Johnston SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, 147e5054602SMark Johnston nd_path, sizeof(nd_path), 148e5054602SMark Johnston "Server path for output files"); 149da7d7778SMark Johnston static int nd_polls = 2000; 150da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN, 151da7d7778SMark Johnston &nd_polls, 0, 152da7d7778SMark Johnston "Number of times to poll before assuming packet loss (0.5ms per poll)"); 153da7d7778SMark Johnston static int nd_retries = 10; 154da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN, 155da7d7778SMark Johnston &nd_retries, 0, 156da7d7778SMark Johnston "Number of retransmit attempts before giving up"); 157da7d7778SMark Johnston static int nd_arp_retries = 3; 158da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN, 159da7d7778SMark Johnston &nd_arp_retries, 0, 160da7d7778SMark Johnston "Number of ARP attempts before giving up"); 161e5054602SMark Johnston 162e5054602SMark Johnston /* 163e5054602SMark Johnston * Checks for netdump support on a network interface 164e5054602SMark Johnston * 165e5054602SMark Johnston * Parameters: 166e5054602SMark Johnston * ifp The network interface that is being tested for support 167e5054602SMark Johnston * 168e5054602SMark Johnston * Returns: 169e5054602SMark Johnston * int 1 if the interface is supported, 0 if not 170e5054602SMark Johnston */ 171e5054602SMark Johnston static bool 172e5054602SMark Johnston netdump_supported_nic(struct ifnet *ifp) 173e5054602SMark Johnston { 174e5054602SMark Johnston 175e5054602SMark Johnston return (ifp->if_netdump_methods != NULL); 176e5054602SMark Johnston } 177e5054602SMark Johnston 178e5054602SMark Johnston /*- 179e5054602SMark Johnston * Network specific primitives. 180e5054602SMark Johnston * Following down the code they are divided ordered as: 181e5054602SMark Johnston * - Packet buffer primitives 182e5054602SMark Johnston * - Output primitives 183e5054602SMark Johnston * - Input primitives 184e5054602SMark Johnston * - Polling primitives 185e5054602SMark Johnston */ 186e5054602SMark Johnston 187e5054602SMark Johnston /* 188e5054602SMark Johnston * Handles creation of the ethernet header, then places outgoing packets into 189e5054602SMark Johnston * the tx buffer for the NIC 190e5054602SMark Johnston * 191e5054602SMark Johnston * Parameters: 192e5054602SMark Johnston * m The mbuf containing the packet to be sent (will be freed by 193e5054602SMark Johnston * this function or the NIC driver) 194e5054602SMark Johnston * ifp The interface to send on 195e5054602SMark Johnston * dst The destination ethernet address (source address will be looked 196e5054602SMark Johnston * up using ifp) 197e5054602SMark Johnston * etype The ETHERTYPE_* value for the protocol that is being sent 198e5054602SMark Johnston * 199e5054602SMark Johnston * Returns: 200e5054602SMark Johnston * int see errno.h, 0 for success 201e5054602SMark Johnston */ 202e5054602SMark Johnston static int 203e5054602SMark Johnston netdump_ether_output(struct mbuf *m, struct ifnet *ifp, struct ether_addr dst, 204e5054602SMark Johnston u_short etype) 205e5054602SMark Johnston { 206e5054602SMark Johnston struct ether_header *eh; 207e5054602SMark Johnston 208e5054602SMark Johnston if (((ifp->if_flags & (IFF_MONITOR | IFF_UP)) != IFF_UP) || 209e5054602SMark Johnston (ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) { 210e5054602SMark Johnston if_printf(ifp, "netdump_ether_output: interface isn't up\n"); 211e5054602SMark Johnston m_freem(m); 212e5054602SMark Johnston return (ENETDOWN); 213e5054602SMark Johnston } 214e5054602SMark Johnston 215e5054602SMark Johnston /* Fill in the ethernet header. */ 216e5054602SMark Johnston M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT); 217e5054602SMark Johnston if (m == NULL) { 218e5054602SMark Johnston printf("%s: out of mbufs\n", __func__); 219e5054602SMark Johnston return (ENOBUFS); 220e5054602SMark Johnston } 221e5054602SMark Johnston eh = mtod(m, struct ether_header *); 222e5054602SMark Johnston memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN); 223e5054602SMark Johnston memcpy(eh->ether_dhost, dst.octet, ETHER_ADDR_LEN); 224e5054602SMark Johnston eh->ether_type = htons(etype); 225e5054602SMark Johnston return ((ifp->if_netdump_methods->nd_transmit)(ifp, m)); 226e5054602SMark Johnston } 227e5054602SMark Johnston 228e5054602SMark Johnston /* 229e5054602SMark Johnston * Unreliable transmission of an mbuf chain to the netdump server 230e5054602SMark Johnston * Note: can't handle fragmentation; fails if the packet is larger than 231e5054602SMark Johnston * nd_ifp->if_mtu after adding the UDP/IP headers 232e5054602SMark Johnston * 233e5054602SMark Johnston * Parameters: 234e5054602SMark Johnston * m mbuf chain 235e5054602SMark Johnston * 236e5054602SMark Johnston * Returns: 237e5054602SMark Johnston * int see errno.h, 0 for success 238e5054602SMark Johnston */ 239e5054602SMark Johnston static int 240e5054602SMark Johnston netdump_udp_output(struct mbuf *m) 241e5054602SMark Johnston { 242e5054602SMark Johnston struct udpiphdr *ui; 243e5054602SMark Johnston struct ip *ip; 244e5054602SMark Johnston 245e5054602SMark Johnston MPASS(nd_ifp != NULL); 246e5054602SMark Johnston 247e5054602SMark Johnston M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT); 248e5054602SMark Johnston if (m == NULL) { 249e5054602SMark Johnston printf("%s: out of mbufs\n", __func__); 250e5054602SMark Johnston return (ENOBUFS); 251e5054602SMark Johnston } 252e5054602SMark Johnston 253e5054602SMark Johnston if (m->m_pkthdr.len > nd_ifp->if_mtu) { 254e5054602SMark Johnston printf("netdump_udp_output: Packet is too big: %d > MTU %u\n", 255e5054602SMark Johnston m->m_pkthdr.len, nd_ifp->if_mtu); 256e5054602SMark Johnston m_freem(m); 257e5054602SMark Johnston return (ENOBUFS); 258e5054602SMark Johnston } 259e5054602SMark Johnston 260e5054602SMark Johnston ui = mtod(m, struct udpiphdr *); 261e5054602SMark Johnston bzero(ui->ui_x1, sizeof(ui->ui_x1)); 262e5054602SMark Johnston ui->ui_pr = IPPROTO_UDP; 263e5054602SMark Johnston ui->ui_len = htons(m->m_pkthdr.len - sizeof(struct ip)); 264e5054602SMark Johnston ui->ui_ulen = ui->ui_len; 265e5054602SMark Johnston ui->ui_src = nd_client; 266e5054602SMark Johnston ui->ui_dst = nd_server; 267e5054602SMark Johnston /* Use this src port so that the server can connect() the socket */ 268e5054602SMark Johnston ui->ui_sport = htons(NETDUMP_ACKPORT); 269e5054602SMark Johnston ui->ui_dport = htons(nd_server_port); 270e5054602SMark Johnston ui->ui_sum = 0; 271e5054602SMark Johnston if ((ui->ui_sum = in_cksum(m, m->m_pkthdr.len)) == 0) 272e5054602SMark Johnston ui->ui_sum = 0xffff; 273e5054602SMark Johnston 274e5054602SMark Johnston ip = mtod(m, struct ip *); 275e5054602SMark Johnston ip->ip_v = IPVERSION; 276e5054602SMark Johnston ip->ip_hl = sizeof(struct ip) >> 2; 277e5054602SMark Johnston ip->ip_tos = 0; 278e5054602SMark Johnston ip->ip_len = htons(m->m_pkthdr.len); 279e5054602SMark Johnston ip->ip_id = 0; 280e5054602SMark Johnston ip->ip_off = htons(IP_DF); 281e5054602SMark Johnston ip->ip_ttl = 255; 282e5054602SMark Johnston ip->ip_sum = 0; 283e5054602SMark Johnston ip->ip_sum = in_cksum(m, sizeof(struct ip)); 284e5054602SMark Johnston 285e5054602SMark Johnston return (netdump_ether_output(m, nd_ifp, nd_gw_mac, ETHERTYPE_IP)); 286e5054602SMark Johnston } 287e5054602SMark Johnston 288e5054602SMark Johnston /* 289e5054602SMark Johnston * Builds and sends a single ARP request to locate the server 290e5054602SMark Johnston * 291e5054602SMark Johnston * Return value: 292e5054602SMark Johnston * 0 on success 293e5054602SMark Johnston * errno on error 294e5054602SMark Johnston */ 295e5054602SMark Johnston static int 296e5054602SMark Johnston netdump_send_arp(in_addr_t dst) 297e5054602SMark Johnston { 298e5054602SMark Johnston struct ether_addr bcast; 299e5054602SMark Johnston struct mbuf *m; 300e5054602SMark Johnston struct arphdr *ah; 301e5054602SMark Johnston int pktlen; 302e5054602SMark Johnston 303e5054602SMark Johnston MPASS(nd_ifp != NULL); 304e5054602SMark Johnston 305e5054602SMark Johnston /* Fill-up a broadcast address. */ 306e5054602SMark Johnston memset(&bcast, 0xFF, ETHER_ADDR_LEN); 307e5054602SMark Johnston m = m_gethdr(M_NOWAIT, MT_DATA); 308e5054602SMark Johnston if (m == NULL) { 309e5054602SMark Johnston printf("netdump_send_arp: Out of mbufs\n"); 310e5054602SMark Johnston return (ENOBUFS); 311e5054602SMark Johnston } 312e5054602SMark Johnston pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr)); 313e5054602SMark Johnston m->m_len = pktlen; 314e5054602SMark Johnston m->m_pkthdr.len = pktlen; 315e5054602SMark Johnston MH_ALIGN(m, pktlen); 316e5054602SMark Johnston ah = mtod(m, struct arphdr *); 317e5054602SMark Johnston ah->ar_hrd = htons(ARPHRD_ETHER); 318e5054602SMark Johnston ah->ar_pro = htons(ETHERTYPE_IP); 319e5054602SMark Johnston ah->ar_hln = ETHER_ADDR_LEN; 320e5054602SMark Johnston ah->ar_pln = sizeof(struct in_addr); 321e5054602SMark Johnston ah->ar_op = htons(ARPOP_REQUEST); 322e5054602SMark Johnston memcpy(ar_sha(ah), IF_LLADDR(nd_ifp), ETHER_ADDR_LEN); 323e5054602SMark Johnston ((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr; 324e5054602SMark Johnston bzero(ar_tha(ah), ETHER_ADDR_LEN); 325e5054602SMark Johnston ((struct in_addr *)ar_tpa(ah))->s_addr = dst; 326e5054602SMark Johnston return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP)); 327e5054602SMark Johnston } 328e5054602SMark Johnston 329e5054602SMark Johnston /* 330e5054602SMark Johnston * Sends ARP requests to locate the server and waits for a response. 331e5054602SMark Johnston * We first try to ARP the server itself, and fall back to the provided 332e5054602SMark Johnston * gateway if the server appears to be off-link. 333e5054602SMark Johnston * 334e5054602SMark Johnston * Return value: 335e5054602SMark Johnston * 0 on success 336e5054602SMark Johnston * errno on error 337e5054602SMark Johnston */ 338e5054602SMark Johnston static int 339e5054602SMark Johnston netdump_arp_gw(void) 340e5054602SMark Johnston { 341e5054602SMark Johnston in_addr_t dst; 342e5054602SMark Johnston int error, polls, retries; 343e5054602SMark Johnston 344e5054602SMark Johnston dst = nd_server.s_addr; 345e5054602SMark Johnston restart: 346e5054602SMark Johnston for (retries = 0; retries < nd_arp_retries && have_gw_mac == 0; 347e5054602SMark Johnston retries++) { 348e5054602SMark Johnston error = netdump_send_arp(dst); 349e5054602SMark Johnston if (error != 0) 350e5054602SMark Johnston return (error); 351e5054602SMark Johnston for (polls = 0; polls < nd_polls && have_gw_mac == 0; polls++) { 352e5054602SMark Johnston netdump_network_poll(); 353e5054602SMark Johnston DELAY(500); 354e5054602SMark Johnston } 355e5054602SMark Johnston if (have_gw_mac == 0) 356e5054602SMark Johnston printf("(ARP retry)"); 357e5054602SMark Johnston } 358e5054602SMark Johnston if (have_gw_mac != 0) 359e5054602SMark Johnston return (0); 360e5054602SMark Johnston if (dst == nd_server.s_addr && nd_server.s_addr != nd_gateway.s_addr) { 361e5054602SMark Johnston printf("Failed to ARP server, trying to reach gateway...\n"); 362e5054602SMark Johnston dst = nd_gateway.s_addr; 363e5054602SMark Johnston goto restart; 364e5054602SMark Johnston } 365e5054602SMark Johnston 366e5054602SMark Johnston printf("\nARP timed out.\n"); 367e5054602SMark Johnston return (ETIMEDOUT); 368e5054602SMark Johnston } 369e5054602SMark Johnston 370e5054602SMark Johnston /* 371e5054602SMark Johnston * Dummy free function for netdump clusters. 372e5054602SMark Johnston */ 373e5054602SMark Johnston static void 374e5054602SMark Johnston netdump_mbuf_free(struct mbuf *m __unused) 375e5054602SMark Johnston { 376e5054602SMark Johnston } 377e5054602SMark Johnston 378e5054602SMark Johnston /* 379e5054602SMark Johnston * Construct and reliably send a netdump packet. May fail from a resource 380e5054602SMark Johnston * shortage or extreme number of unacknowledged retransmissions. Wait for 381e5054602SMark Johnston * an acknowledgement before returning. Splits packets into chunks small 382e5054602SMark Johnston * enough to be sent without fragmentation (looks up the interface MTU) 383e5054602SMark Johnston * 384e5054602SMark Johnston * Parameters: 385e5054602SMark Johnston * type netdump packet type (HERALD, FINISHED, or VMCORE) 386e5054602SMark Johnston * offset vmcore data offset (bytes) 387e5054602SMark Johnston * data vmcore data 388e5054602SMark Johnston * datalen vmcore data size (bytes) 389e5054602SMark Johnston * 390e5054602SMark Johnston * Returns: 391e5054602SMark Johnston * int see errno.h, 0 for success 392e5054602SMark Johnston */ 393e5054602SMark Johnston static int 394e5054602SMark Johnston netdump_send(uint32_t type, off_t offset, unsigned char *data, uint32_t datalen) 395e5054602SMark Johnston { 396e5054602SMark Johnston struct netdump_msg_hdr *nd_msg_hdr; 397e5054602SMark Johnston struct mbuf *m, *m2; 398e5054602SMark Johnston uint64_t want_acks; 399e5054602SMark Johnston uint32_t i, pktlen, sent_so_far; 400e5054602SMark Johnston int retries, polls, error; 401e5054602SMark Johnston 402e5054602SMark Johnston want_acks = 0; 403e5054602SMark Johnston rcvd_acks = 0; 404e5054602SMark Johnston retries = 0; 405e5054602SMark Johnston 406e5054602SMark Johnston MPASS(nd_ifp != NULL); 407e5054602SMark Johnston 408e5054602SMark Johnston retransmit: 409e5054602SMark Johnston /* Chunks can be too big to fit in packets. */ 410e5054602SMark Johnston for (i = sent_so_far = 0; sent_so_far < datalen || 411e5054602SMark Johnston (i == 0 && datalen == 0); i++) { 412e5054602SMark Johnston pktlen = datalen - sent_so_far; 413e5054602SMark Johnston 414e5054602SMark Johnston /* First bound: the packet structure. */ 415e5054602SMark Johnston pktlen = min(pktlen, NETDUMP_DATASIZE); 416e5054602SMark Johnston 417e5054602SMark Johnston /* Second bound: the interface MTU (assume no IP options). */ 418e5054602SMark Johnston pktlen = min(pktlen, nd_ifp->if_mtu - sizeof(struct udpiphdr) - 419e5054602SMark Johnston sizeof(struct netdump_msg_hdr)); 420e5054602SMark Johnston 421e5054602SMark Johnston /* 422e5054602SMark Johnston * Check if it is retransmitting and this has been ACKed 423e5054602SMark Johnston * already. 424e5054602SMark Johnston */ 425e5054602SMark Johnston if ((rcvd_acks & (1 << i)) != 0) { 426e5054602SMark Johnston sent_so_far += pktlen; 427e5054602SMark Johnston continue; 428e5054602SMark Johnston } 429e5054602SMark Johnston 430e5054602SMark Johnston /* 431e5054602SMark Johnston * Get and fill a header mbuf, then chain data as an extended 432e5054602SMark Johnston * mbuf. 433e5054602SMark Johnston */ 434e5054602SMark Johnston m = m_gethdr(M_NOWAIT, MT_DATA); 435e5054602SMark Johnston if (m == NULL) { 436e5054602SMark Johnston printf("netdump_send: Out of mbufs\n"); 437e5054602SMark Johnston return (ENOBUFS); 438e5054602SMark Johnston } 439e5054602SMark Johnston m->m_len = sizeof(struct netdump_msg_hdr); 440e5054602SMark Johnston m->m_pkthdr.len = sizeof(struct netdump_msg_hdr); 441e5054602SMark Johnston MH_ALIGN(m, sizeof(struct netdump_msg_hdr)); 442e5054602SMark Johnston nd_msg_hdr = mtod(m, struct netdump_msg_hdr *); 443e5054602SMark Johnston nd_msg_hdr->mh_seqno = htonl(nd_seqno + i); 444e5054602SMark Johnston nd_msg_hdr->mh_type = htonl(type); 445e5054602SMark Johnston nd_msg_hdr->mh_offset = htobe64(offset + sent_so_far); 446e5054602SMark Johnston nd_msg_hdr->mh_len = htonl(pktlen); 447e5054602SMark Johnston nd_msg_hdr->mh__pad = 0; 448e5054602SMark Johnston 449e5054602SMark Johnston if (pktlen != 0) { 450e5054602SMark Johnston m2 = m_get(M_NOWAIT, MT_DATA); 451e5054602SMark Johnston if (m2 == NULL) { 452e5054602SMark Johnston m_freem(m); 453e5054602SMark Johnston printf("netdump_send: Out of mbufs\n"); 454e5054602SMark Johnston return (ENOBUFS); 455e5054602SMark Johnston } 456e5054602SMark Johnston MEXTADD(m2, data + sent_so_far, pktlen, 457e5054602SMark Johnston netdump_mbuf_free, NULL, NULL, 0, EXT_DISPOSABLE); 458e5054602SMark Johnston m2->m_len = pktlen; 459e5054602SMark Johnston 460e5054602SMark Johnston m_cat(m, m2); 461e5054602SMark Johnston m->m_pkthdr.len += pktlen; 462e5054602SMark Johnston } 463e5054602SMark Johnston error = netdump_udp_output(m); 464e5054602SMark Johnston if (error != 0) 465e5054602SMark Johnston return (error); 466e5054602SMark Johnston 467e5054602SMark Johnston /* Note that we're waiting for this packet in the bitfield. */ 468e5054602SMark Johnston want_acks |= (1 << i); 469e5054602SMark Johnston sent_so_far += pktlen; 470e5054602SMark Johnston } 471e5054602SMark Johnston if (i >= NETDUMP_MAX_IN_FLIGHT) 472e5054602SMark Johnston printf("Warning: Sent more than %d packets (%d). " 473e5054602SMark Johnston "Acknowledgements will fail unless the size of " 474e5054602SMark Johnston "rcvd_acks/want_acks is increased.\n", 475e5054602SMark Johnston NETDUMP_MAX_IN_FLIGHT, i); 476e5054602SMark Johnston 477e5054602SMark Johnston /* 478e5054602SMark Johnston * Wait for acks. A *real* window would speed things up considerably. 479e5054602SMark Johnston */ 480e5054602SMark Johnston polls = 0; 481e5054602SMark Johnston while (rcvd_acks != want_acks) { 482e5054602SMark Johnston if (polls++ > nd_polls) { 483e5054602SMark Johnston if (retries++ > nd_retries) 484e5054602SMark Johnston return (ETIMEDOUT); 485e5054602SMark Johnston printf(". "); 486e5054602SMark Johnston goto retransmit; 487e5054602SMark Johnston } 488e5054602SMark Johnston netdump_network_poll(); 489e5054602SMark Johnston DELAY(500); 490e5054602SMark Johnston } 491e5054602SMark Johnston nd_seqno += i; 492e5054602SMark Johnston return (0); 493e5054602SMark Johnston } 494e5054602SMark Johnston 495e5054602SMark Johnston /* 496e5054602SMark Johnston * Handler for IP packets: checks their sanity and then processes any netdump 497e5054602SMark Johnston * ACK packets it finds. 498e5054602SMark Johnston * 499e5054602SMark Johnston * It needs to replicate partially the behaviour of ip_input() and 500e5054602SMark Johnston * udp_input(). 501e5054602SMark Johnston * 502e5054602SMark Johnston * Parameters: 503e5054602SMark Johnston * mb a pointer to an mbuf * containing the packet received 504e5054602SMark Johnston * Updates *mb if m_pullup et al change the pointer 505e5054602SMark Johnston * Assumes the calling function will take care of freeing the mbuf 506e5054602SMark Johnston */ 507e5054602SMark Johnston static void 508e5054602SMark Johnston netdump_handle_ip(struct mbuf **mb) 509e5054602SMark Johnston { 510e5054602SMark Johnston struct ip *ip; 511e5054602SMark Johnston struct udpiphdr *udp; 512e5054602SMark Johnston struct netdump_ack *nd_ack; 513e5054602SMark Johnston struct mbuf *m; 514e5054602SMark Johnston int rcv_ackno; 515e5054602SMark Johnston unsigned short hlen; 516e5054602SMark Johnston 517e5054602SMark Johnston /* IP processing. */ 518e5054602SMark Johnston m = *mb; 519e5054602SMark Johnston if (m->m_pkthdr.len < sizeof(struct ip)) { 520e5054602SMark Johnston NETDDEBUG("dropping packet too small for IP header\n"); 521e5054602SMark Johnston return; 522e5054602SMark Johnston } 523e5054602SMark Johnston if (m->m_len < sizeof(struct ip)) { 524e5054602SMark Johnston m = m_pullup(m, sizeof(struct ip)); 525e5054602SMark Johnston *mb = m; 526e5054602SMark Johnston if (m == NULL) { 527e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 528e5054602SMark Johnston return; 529e5054602SMark Johnston } 530e5054602SMark Johnston } 531e5054602SMark Johnston ip = mtod(m, struct ip *); 532e5054602SMark Johnston 533e5054602SMark Johnston /* IP version. */ 534e5054602SMark Johnston if (ip->ip_v != IPVERSION) { 535e5054602SMark Johnston NETDDEBUG("bad IP version %d\n", ip->ip_v); 536e5054602SMark Johnston return; 537e5054602SMark Johnston } 538e5054602SMark Johnston 539e5054602SMark Johnston /* Header length. */ 540e5054602SMark Johnston hlen = ip->ip_hl << 2; 541e5054602SMark Johnston if (hlen < sizeof(struct ip)) { 542e5054602SMark Johnston NETDDEBUG("bad IP header length (%hu)\n", hlen); 543e5054602SMark Johnston return; 544e5054602SMark Johnston } 545e5054602SMark Johnston if (hlen > m->m_len) { 546e5054602SMark Johnston m = m_pullup(m, hlen); 547e5054602SMark Johnston *mb = m; 548e5054602SMark Johnston if (m == NULL) { 549e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 550e5054602SMark Johnston return; 551e5054602SMark Johnston } 552e5054602SMark Johnston ip = mtod(m, struct ip *); 553e5054602SMark Johnston } 554e5054602SMark Johnston /* Ignore packets with IP options. */ 555e5054602SMark Johnston if (hlen > sizeof(struct ip)) { 556e5054602SMark Johnston NETDDEBUG("drop packet with IP options\n"); 557e5054602SMark Johnston return; 558e5054602SMark Johnston } 559e5054602SMark Johnston 560e5054602SMark Johnston #ifdef INVARIANTS 5616c1c6ae5SRodney W. Grimes if ((IN_LOOPBACK(ntohl(ip->ip_dst.s_addr)) || 5626c1c6ae5SRodney W. Grimes IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) && 563e5054602SMark Johnston (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 564e5054602SMark Johnston NETDDEBUG("Bad IP header (RFC1122)\n"); 565e5054602SMark Johnston return; 566e5054602SMark Johnston } 567e5054602SMark Johnston #endif 568e5054602SMark Johnston 569e5054602SMark Johnston /* Checksum. */ 570e5054602SMark Johnston if ((m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) != 0) { 571e5054602SMark Johnston if ((m->m_pkthdr.csum_flags & CSUM_IP_VALID) == 0) { 572e5054602SMark Johnston NETDDEBUG("bad IP checksum\n"); 573e5054602SMark Johnston return; 574e5054602SMark Johnston } 575e5054602SMark Johnston } else { 576e5054602SMark Johnston /* XXX */ ; 577e5054602SMark Johnston } 578e5054602SMark Johnston 579e5054602SMark Johnston /* Convert fields to host byte order. */ 580e5054602SMark Johnston ip->ip_len = ntohs(ip->ip_len); 581e5054602SMark Johnston if (ip->ip_len < hlen) { 582e5054602SMark Johnston NETDDEBUG("IP packet smaller (%hu) than header (%hu)\n", 583e5054602SMark Johnston ip->ip_len, hlen); 584e5054602SMark Johnston return; 585e5054602SMark Johnston } 586e5054602SMark Johnston if (m->m_pkthdr.len < ip->ip_len) { 587e5054602SMark Johnston NETDDEBUG("IP packet bigger (%hu) than ethernet packet (%d)\n", 588e5054602SMark Johnston ip->ip_len, m->m_pkthdr.len); 589e5054602SMark Johnston return; 590e5054602SMark Johnston } 591e5054602SMark Johnston if (m->m_pkthdr.len > ip->ip_len) { 592e5054602SMark Johnston 593e5054602SMark Johnston /* Truncate the packet to the IP length. */ 594e5054602SMark Johnston if (m->m_len == m->m_pkthdr.len) { 595e5054602SMark Johnston m->m_len = ip->ip_len; 596e5054602SMark Johnston m->m_pkthdr.len = ip->ip_len; 597e5054602SMark Johnston } else 598e5054602SMark Johnston m_adj(m, ip->ip_len - m->m_pkthdr.len); 599e5054602SMark Johnston } 600e5054602SMark Johnston 601e5054602SMark Johnston ip->ip_off = ntohs(ip->ip_off); 602e5054602SMark Johnston 603e5054602SMark Johnston /* Check that the source is the server's IP. */ 604e5054602SMark Johnston if (ip->ip_src.s_addr != nd_server.s_addr) { 605e5054602SMark Johnston NETDDEBUG("drop packet not from server (from 0x%x)\n", 606e5054602SMark Johnston ip->ip_src.s_addr); 607e5054602SMark Johnston return; 608e5054602SMark Johnston } 609e5054602SMark Johnston 610e5054602SMark Johnston /* Check if the destination IP is ours. */ 611e5054602SMark Johnston if (ip->ip_dst.s_addr != nd_client.s_addr) { 612e5054602SMark Johnston NETDDEBUGV("drop packet not to our IP\n"); 613e5054602SMark Johnston return; 614e5054602SMark Johnston } 615e5054602SMark Johnston 616e5054602SMark Johnston if (ip->ip_p != IPPROTO_UDP) { 617e5054602SMark Johnston NETDDEBUG("drop non-UDP packet\n"); 618e5054602SMark Johnston return; 619e5054602SMark Johnston } 620e5054602SMark Johnston 621e5054602SMark Johnston /* Do not deal with fragments. */ 622e5054602SMark Johnston if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) { 623e5054602SMark Johnston NETDDEBUG("drop fragmented packet\n"); 624e5054602SMark Johnston return; 625e5054602SMark Johnston } 626e5054602SMark Johnston 627e5054602SMark Johnston /* UDP custom is to have packet length not include IP header. */ 628e5054602SMark Johnston ip->ip_len -= hlen; 629e5054602SMark Johnston 630e5054602SMark Johnston /* UDP processing. */ 631e5054602SMark Johnston 632e5054602SMark Johnston /* Get IP and UDP headers together, along with the netdump packet. */ 633e5054602SMark Johnston if (m->m_pkthdr.len < 634e5054602SMark Johnston sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) { 635e5054602SMark Johnston NETDDEBUG("ignoring small packet\n"); 636e5054602SMark Johnston return; 637e5054602SMark Johnston } 638e5054602SMark Johnston if (m->m_len < sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) { 639e5054602SMark Johnston m = m_pullup(m, sizeof(struct udpiphdr) + 640e5054602SMark Johnston sizeof(struct netdump_ack)); 641e5054602SMark Johnston *mb = m; 642e5054602SMark Johnston if (m == NULL) { 643e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 644e5054602SMark Johnston return; 645e5054602SMark Johnston } 646e5054602SMark Johnston } 647e5054602SMark Johnston udp = mtod(m, struct udpiphdr *); 648e5054602SMark Johnston 649e5054602SMark Johnston if (ntohs(udp->ui_u.uh_dport) != NETDUMP_ACKPORT) { 650e5054602SMark Johnston NETDDEBUG("not on the netdump port.\n"); 651e5054602SMark Johnston return; 652e5054602SMark Johnston } 653e5054602SMark Johnston 654e5054602SMark Johnston /* Netdump processing. */ 655e5054602SMark Johnston 656e5054602SMark Johnston /* 657e5054602SMark Johnston * Packet is meant for us. Extract the ack sequence number and the 658e5054602SMark Johnston * port number if necessary. 659e5054602SMark Johnston */ 660e5054602SMark Johnston nd_ack = (struct netdump_ack *)(mtod(m, caddr_t) + 661e5054602SMark Johnston sizeof(struct udpiphdr)); 662e5054602SMark Johnston rcv_ackno = ntohl(nd_ack->na_seqno); 663e5054602SMark Johnston if (nd_server_port == NETDUMP_PORT) 664e5054602SMark Johnston nd_server_port = ntohs(udp->ui_u.uh_sport); 665e5054602SMark Johnston if (rcv_ackno >= nd_seqno + NETDUMP_MAX_IN_FLIGHT) 666e5054602SMark Johnston printf("%s: ACK %d too far in future!\n", __func__, rcv_ackno); 667e5054602SMark Johnston else if (rcv_ackno >= nd_seqno) { 668e5054602SMark Johnston /* We're interested in this ack. Record it. */ 669e5054602SMark Johnston rcvd_acks |= 1 << (rcv_ackno - nd_seqno); 670e5054602SMark Johnston } 671e5054602SMark Johnston } 672e5054602SMark Johnston 673e5054602SMark Johnston /* 674e5054602SMark Johnston * Handler for ARP packets: checks their sanity and then 675e5054602SMark Johnston * 1. If the ARP is a request for our IP, respond with our MAC address 676e5054602SMark Johnston * 2. If the ARP is a response from our server, record its MAC address 677e5054602SMark Johnston * 678e5054602SMark Johnston * It needs to replicate partially the behaviour of arpintr() and 679e5054602SMark Johnston * in_arpinput(). 680e5054602SMark Johnston * 681e5054602SMark Johnston * Parameters: 682e5054602SMark Johnston * mb a pointer to an mbuf * containing the packet received 683e5054602SMark Johnston * Updates *mb if m_pullup et al change the pointer 684e5054602SMark Johnston * Assumes the calling function will take care of freeing the mbuf 685e5054602SMark Johnston */ 686e5054602SMark Johnston static void 687e5054602SMark Johnston netdump_handle_arp(struct mbuf **mb) 688e5054602SMark Johnston { 689e5054602SMark Johnston char buf[INET_ADDRSTRLEN]; 690e5054602SMark Johnston struct in_addr isaddr, itaddr, myaddr; 691e5054602SMark Johnston struct ether_addr dst; 692e5054602SMark Johnston struct mbuf *m; 693e5054602SMark Johnston struct arphdr *ah; 694e5054602SMark Johnston struct ifnet *ifp; 695e5054602SMark Johnston uint8_t *enaddr; 696e5054602SMark Johnston int req_len, op; 697e5054602SMark Johnston 698e5054602SMark Johnston m = *mb; 699e5054602SMark Johnston ifp = m->m_pkthdr.rcvif; 700e5054602SMark Johnston if (m->m_len < sizeof(struct arphdr)) { 701e5054602SMark Johnston m = m_pullup(m, sizeof(struct arphdr)); 702e5054602SMark Johnston *mb = m; 703e5054602SMark Johnston if (m == NULL) { 704e5054602SMark Johnston NETDDEBUG("runt packet: m_pullup failed\n"); 705e5054602SMark Johnston return; 706e5054602SMark Johnston } 707e5054602SMark Johnston } 708e5054602SMark Johnston 709e5054602SMark Johnston ah = mtod(m, struct arphdr *); 710e5054602SMark Johnston if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) { 711e5054602SMark Johnston NETDDEBUG("unknown hardware address 0x%2D)\n", 712e5054602SMark Johnston (unsigned char *)&ah->ar_hrd, ""); 713e5054602SMark Johnston return; 714e5054602SMark Johnston } 715e5054602SMark Johnston if (ntohs(ah->ar_pro) != ETHERTYPE_IP) { 716e5054602SMark Johnston NETDDEBUG("drop ARP for unknown protocol %d\n", 717e5054602SMark Johnston ntohs(ah->ar_pro)); 718e5054602SMark Johnston return; 719e5054602SMark Johnston } 720e5054602SMark Johnston req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); 721e5054602SMark Johnston if (m->m_len < req_len) { 722e5054602SMark Johnston m = m_pullup(m, req_len); 723e5054602SMark Johnston *mb = m; 724e5054602SMark Johnston if (m == NULL) { 725e5054602SMark Johnston NETDDEBUG("runt packet: m_pullup failed\n"); 726e5054602SMark Johnston return; 727e5054602SMark Johnston } 728e5054602SMark Johnston } 729e5054602SMark Johnston ah = mtod(m, struct arphdr *); 730e5054602SMark Johnston 731e5054602SMark Johnston op = ntohs(ah->ar_op); 732e5054602SMark Johnston memcpy(&isaddr, ar_spa(ah), sizeof(isaddr)); 733e5054602SMark Johnston memcpy(&itaddr, ar_tpa(ah), sizeof(itaddr)); 734e5054602SMark Johnston enaddr = (uint8_t *)IF_LLADDR(ifp); 735e5054602SMark Johnston myaddr = nd_client; 736e5054602SMark Johnston 737e5054602SMark Johnston if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) { 738e5054602SMark Johnston NETDDEBUG("ignoring ARP from myself\n"); 739e5054602SMark Johnston return; 740e5054602SMark Johnston } 741e5054602SMark Johnston 742e5054602SMark Johnston if (isaddr.s_addr == nd_client.s_addr) { 743e5054602SMark Johnston printf("%s: %*D is using my IP address %s!\n", __func__, 744e5054602SMark Johnston ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 745e5054602SMark Johnston inet_ntoa_r(isaddr, buf)); 746e5054602SMark Johnston return; 747e5054602SMark Johnston } 748e5054602SMark Johnston 749e5054602SMark Johnston if (memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen) == 0) { 750e5054602SMark Johnston NETDDEBUG("ignoring ARP from broadcast address\n"); 751e5054602SMark Johnston return; 752e5054602SMark Johnston } 753e5054602SMark Johnston 754e5054602SMark Johnston if (op == ARPOP_REPLY) { 755e5054602SMark Johnston if (isaddr.s_addr != nd_gateway.s_addr && 756e5054602SMark Johnston isaddr.s_addr != nd_server.s_addr) { 757e5054602SMark Johnston inet_ntoa_r(isaddr, buf); 758e5054602SMark Johnston NETDDEBUG( 759e5054602SMark Johnston "ignoring ARP reply from %s (not netdump server)\n", 760e5054602SMark Johnston buf); 761e5054602SMark Johnston return; 762e5054602SMark Johnston } 763e5054602SMark Johnston memcpy(nd_gw_mac.octet, ar_sha(ah), 764e5054602SMark Johnston min(ah->ar_hln, ETHER_ADDR_LEN)); 765e5054602SMark Johnston have_gw_mac = 1; 766e5054602SMark Johnston NETDDEBUG("got server MAC address %6D\n", nd_gw_mac.octet, ":"); 767e5054602SMark Johnston return; 768e5054602SMark Johnston } 769e5054602SMark Johnston 770e5054602SMark Johnston if (op != ARPOP_REQUEST) { 771e5054602SMark Johnston NETDDEBUG("ignoring ARP non-request/reply\n"); 772e5054602SMark Johnston return; 773e5054602SMark Johnston } 774e5054602SMark Johnston 775e5054602SMark Johnston if (itaddr.s_addr != nd_client.s_addr) { 776e5054602SMark Johnston NETDDEBUG("ignoring ARP not to our IP\n"); 777e5054602SMark Johnston return; 778e5054602SMark Johnston } 779e5054602SMark Johnston 780e5054602SMark Johnston memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 781e5054602SMark Johnston memcpy(ar_sha(ah), enaddr, ah->ar_hln); 782e5054602SMark Johnston memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); 783e5054602SMark Johnston memcpy(ar_spa(ah), &itaddr, ah->ar_pln); 784e5054602SMark Johnston ah->ar_op = htons(ARPOP_REPLY); 785e5054602SMark Johnston ah->ar_pro = htons(ETHERTYPE_IP); 786e5054602SMark Johnston m->m_flags &= ~(M_BCAST|M_MCAST); 787e5054602SMark Johnston m->m_len = arphdr_len(ah); 788e5054602SMark Johnston m->m_pkthdr.len = m->m_len; 789e5054602SMark Johnston 790e5054602SMark Johnston memcpy(dst.octet, ar_tha(ah), ETHER_ADDR_LEN); 791e5054602SMark Johnston netdump_ether_output(m, ifp, dst, ETHERTYPE_ARP); 792e5054602SMark Johnston *mb = NULL; 793e5054602SMark Johnston } 794e5054602SMark Johnston 795e5054602SMark Johnston /* 796e5054602SMark Johnston * Handler for incoming packets directly from the network adapter 797e5054602SMark Johnston * Identifies the packet type (IP or ARP) and passes it along to one of the 798e5054602SMark Johnston * helper functions netdump_handle_ip or netdump_handle_arp. 799e5054602SMark Johnston * 800e5054602SMark Johnston * It needs to replicate partially the behaviour of ether_input() and 801e5054602SMark Johnston * ether_demux(). 802e5054602SMark Johnston * 803e5054602SMark Johnston * Parameters: 804e5054602SMark Johnston * ifp the interface the packet came from (should be nd_ifp) 805e5054602SMark Johnston * m an mbuf containing the packet received 806e5054602SMark Johnston */ 807e5054602SMark Johnston static void 808e5054602SMark Johnston netdump_pkt_in(struct ifnet *ifp, struct mbuf *m) 809e5054602SMark Johnston { 810e5054602SMark Johnston struct ifreq ifr; 811e5054602SMark Johnston struct ether_header *eh; 812e5054602SMark Johnston u_short etype; 813e5054602SMark Johnston 814e5054602SMark Johnston /* Ethernet processing. */ 815e5054602SMark Johnston if ((m->m_flags & M_PKTHDR) == 0) { 816e5054602SMark Johnston NETDDEBUG_IF(ifp, "discard frame without packet header\n"); 817e5054602SMark Johnston goto done; 818e5054602SMark Johnston } 819e5054602SMark Johnston if (m->m_len < ETHER_HDR_LEN) { 820e5054602SMark Johnston NETDDEBUG_IF(ifp, 821e5054602SMark Johnston "discard frame without leading eth header (len %u pktlen %u)\n", 822e5054602SMark Johnston m->m_len, m->m_pkthdr.len); 823e5054602SMark Johnston goto done; 824e5054602SMark Johnston } 825e5054602SMark Johnston if ((m->m_flags & M_HASFCS) != 0) { 826e5054602SMark Johnston m_adj(m, -ETHER_CRC_LEN); 827e5054602SMark Johnston m->m_flags &= ~M_HASFCS; 828e5054602SMark Johnston } 829e5054602SMark Johnston eh = mtod(m, struct ether_header *); 830e5054602SMark Johnston etype = ntohs(eh->ether_type); 831e5054602SMark Johnston if ((m->m_flags & M_VLANTAG) != 0 || etype == ETHERTYPE_VLAN) { 832e5054602SMark Johnston NETDDEBUG_IF(ifp, "ignoring vlan packets\n"); 833e5054602SMark Johnston goto done; 834e5054602SMark Johnston } 835e5054602SMark Johnston if (if_gethwaddr(ifp, &ifr) != 0) { 836e5054602SMark Johnston NETDDEBUG_IF(ifp, "failed to get hw addr for interface\n"); 837e5054602SMark Johnston goto done; 838e5054602SMark Johnston } 839e5054602SMark Johnston if (memcmp(ifr.ifr_addr.sa_data, eh->ether_dhost, 840e5054602SMark Johnston ETHER_ADDR_LEN) != 0) { 841e5054602SMark Johnston NETDDEBUG_IF(ifp, 842e5054602SMark Johnston "discard frame with incorrect destination addr\n"); 843e5054602SMark Johnston goto done; 844e5054602SMark Johnston } 845e5054602SMark Johnston 846e5054602SMark Johnston /* Done ethernet processing. Strip off the ethernet header. */ 847e5054602SMark Johnston m_adj(m, ETHER_HDR_LEN); 848e5054602SMark Johnston switch (etype) { 849e5054602SMark Johnston case ETHERTYPE_ARP: 850e5054602SMark Johnston netdump_handle_arp(&m); 851e5054602SMark Johnston break; 852e5054602SMark Johnston case ETHERTYPE_IP: 853e5054602SMark Johnston netdump_handle_ip(&m); 854e5054602SMark Johnston break; 855e5054602SMark Johnston default: 856e5054602SMark Johnston NETDDEBUG_IF(ifp, "dropping unknown ethertype %hu\n", etype); 857e5054602SMark Johnston break; 858e5054602SMark Johnston } 859e5054602SMark Johnston done: 860e5054602SMark Johnston if (m != NULL) 861e5054602SMark Johnston m_freem(m); 862e5054602SMark Johnston } 863e5054602SMark Johnston 864e5054602SMark Johnston /* 865e5054602SMark Johnston * After trapping, instead of assuming that most of the network stack is sane, 866e5054602SMark Johnston * we just poll the driver directly for packets. 867e5054602SMark Johnston */ 868e5054602SMark Johnston static void 869e5054602SMark Johnston netdump_network_poll(void) 870e5054602SMark Johnston { 871e5054602SMark Johnston 872e5054602SMark Johnston MPASS(nd_ifp != NULL); 873e5054602SMark Johnston 874e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_poll(nd_ifp, 1000); 875e5054602SMark Johnston } 876e5054602SMark Johnston 877e5054602SMark Johnston /*- 878e5054602SMark Johnston * Dumping specific primitives. 879e5054602SMark Johnston */ 880e5054602SMark Johnston 881e5054602SMark Johnston /* 882e5054602SMark Johnston * Callback from dumpsys() to dump a chunk of memory. 883e5054602SMark Johnston * Copies it out to our static buffer then sends it across the network. 884e5054602SMark Johnston * Detects the initial KDH and makes sure it is given a special packet type. 885e5054602SMark Johnston * 886e5054602SMark Johnston * Parameters: 887e5054602SMark Johnston * priv Unused. Optional private pointer. 888e5054602SMark Johnston * virtual Virtual address (where to read the data from) 889e5054602SMark Johnston * physical Unused. Physical memory address. 890e5054602SMark Johnston * offset Offset from start of core file 891e5054602SMark Johnston * length Data length 892e5054602SMark Johnston * 893e5054602SMark Johnston * Return value: 894e5054602SMark Johnston * 0 on success 895e5054602SMark Johnston * errno on error 896e5054602SMark Johnston */ 897e5054602SMark Johnston static int 898e5054602SMark Johnston netdump_dumper(void *priv __unused, void *virtual, 899e5054602SMark Johnston vm_offset_t physical __unused, off_t offset, size_t length) 900e5054602SMark Johnston { 901e5054602SMark Johnston int error; 902e5054602SMark Johnston 903e5054602SMark Johnston NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n", 904e5054602SMark Johnston virtual, (uintmax_t)offset, length); 905e5054602SMark Johnston 906e5054602SMark Johnston if (virtual == NULL) { 907e5054602SMark Johnston if (dump_failed != 0) 908e5054602SMark Johnston printf("failed to dump the kernel core\n"); 909e5054602SMark Johnston else if (netdump_send(NETDUMP_FINISHED, 0, NULL, 0) != 0) 910e5054602SMark Johnston printf("failed to close the transaction\n"); 911e5054602SMark Johnston else 912e5054602SMark Johnston printf("\nnetdump finished.\n"); 913e5054602SMark Johnston netdump_cleanup(); 914e5054602SMark Johnston return (0); 915e5054602SMark Johnston } 916e5054602SMark Johnston if (length > sizeof(nd_buf)) 917e5054602SMark Johnston return (ENOSPC); 918e5054602SMark Johnston 919e5054602SMark Johnston memmove(nd_buf, virtual, length); 920e5054602SMark Johnston error = netdump_send(NETDUMP_VMCORE, offset, nd_buf, length); 921e5054602SMark Johnston if (error != 0) { 922e5054602SMark Johnston dump_failed = 1; 923e5054602SMark Johnston return (error); 924e5054602SMark Johnston } 925e5054602SMark Johnston return (0); 926e5054602SMark Johnston } 927e5054602SMark Johnston 928e5054602SMark Johnston /* 929e5054602SMark Johnston * Perform any initalization needed prior to transmitting the kernel core. 930e5054602SMark Johnston */ 931e5054602SMark Johnston static int 932e5054602SMark Johnston netdump_start(struct dumperinfo *di) 933e5054602SMark Johnston { 934e5054602SMark Johnston char *path; 935e5054602SMark Johnston char buf[INET_ADDRSTRLEN]; 936e5054602SMark Johnston uint32_t len; 937e5054602SMark Johnston int error; 938e5054602SMark Johnston 939e5054602SMark Johnston error = 0; 940e5054602SMark Johnston 941e5054602SMark Johnston /* Check if the dumping is allowed to continue. */ 942e5054602SMark Johnston if (nd_enabled == 0) 943e5054602SMark Johnston return (EINVAL); 944e5054602SMark Johnston 945e5054602SMark Johnston if (panicstr == NULL) { 946e5054602SMark Johnston printf( 947e5054602SMark Johnston "netdump_start: netdump may only be used after a panic\n"); 948e5054602SMark Johnston return (EINVAL); 949e5054602SMark Johnston } 950e5054602SMark Johnston 951e5054602SMark Johnston MPASS(nd_ifp != NULL); 952e5054602SMark Johnston 953e5054602SMark Johnston if (nd_server.s_addr == INADDR_ANY) { 954e5054602SMark Johnston printf("netdump_start: can't netdump; no server IP given\n"); 955e5054602SMark Johnston return (EINVAL); 956e5054602SMark Johnston } 957e5054602SMark Johnston if (nd_client.s_addr == INADDR_ANY) { 958e5054602SMark Johnston printf("netdump_start: can't netdump; no client IP given\n"); 959e5054602SMark Johnston return (EINVAL); 960e5054602SMark Johnston } 961e5054602SMark Johnston 962e5054602SMark Johnston /* We start dumping at offset 0. */ 963e5054602SMark Johnston di->dumpoff = 0; 964e5054602SMark Johnston 965e5054602SMark Johnston nd_seqno = 1; 966e5054602SMark Johnston 967e5054602SMark Johnston /* 968e5054602SMark Johnston * nd_server_port could have switched after the first ack the 969e5054602SMark Johnston * first time it gets called. Adjust it accordingly. 970e5054602SMark Johnston */ 971e5054602SMark Johnston nd_server_port = NETDUMP_PORT; 972e5054602SMark Johnston 973e5054602SMark Johnston /* Switch to the netdump mbuf zones. */ 974e5054602SMark Johnston netdump_mbuf_dump(); 975e5054602SMark Johnston 976e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_START); 977e5054602SMark Johnston 978e5054602SMark Johnston /* Make the card use *our* receive callback. */ 979e5054602SMark Johnston drv_if_input = nd_ifp->if_input; 980e5054602SMark Johnston nd_ifp->if_input = netdump_pkt_in; 981e5054602SMark Johnston 982e5054602SMark Johnston if (nd_gateway.s_addr == INADDR_ANY) { 983e5054602SMark Johnston restore_gw_addr = 1; 984e5054602SMark Johnston nd_gateway.s_addr = nd_server.s_addr; 985e5054602SMark Johnston } 986e5054602SMark Johnston 987e5054602SMark Johnston printf("netdump in progress. searching for server...\n"); 988e5054602SMark Johnston if (netdump_arp_gw()) { 989e5054602SMark Johnston printf("failed to locate server MAC address\n"); 990e5054602SMark Johnston error = EINVAL; 991e5054602SMark Johnston goto trig_abort; 992e5054602SMark Johnston } 993e5054602SMark Johnston 994e5054602SMark Johnston if (nd_path[0] != '\0') { 995e5054602SMark Johnston path = nd_path; 996e5054602SMark Johnston len = strlen(path) + 1; 997e5054602SMark Johnston } else { 998e5054602SMark Johnston path = NULL; 999e5054602SMark Johnston len = 0; 1000e5054602SMark Johnston } 1001e5054602SMark Johnston if (netdump_send(NETDUMP_HERALD, 0, path, len) != 0) { 1002e5054602SMark Johnston printf("failed to contact netdump server\n"); 1003e5054602SMark Johnston error = EINVAL; 1004e5054602SMark Johnston goto trig_abort; 1005e5054602SMark Johnston } 1006e5054602SMark Johnston printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf), 1007e5054602SMark Johnston nd_gw_mac.octet, ":"); 1008e5054602SMark Johnston return (0); 1009e5054602SMark Johnston 1010e5054602SMark Johnston trig_abort: 1011e5054602SMark Johnston netdump_cleanup(); 1012e5054602SMark Johnston return (error); 1013e5054602SMark Johnston } 1014e5054602SMark Johnston 1015e5054602SMark Johnston static int 1016e5054602SMark Johnston netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh, 1017e5054602SMark Johnston void *key, uint32_t keysize) 1018e5054602SMark Johnston { 1019e5054602SMark Johnston int error; 1020e5054602SMark Johnston 1021e5054602SMark Johnston memcpy(nd_buf, kdh, sizeof(*kdh)); 1022e5054602SMark Johnston error = netdump_send(NETDUMP_KDH, 0, nd_buf, sizeof(*kdh)); 1023e5054602SMark Johnston if (error == 0 && keysize > 0) { 1024e5054602SMark Johnston if (keysize > sizeof(nd_buf)) 1025e5054602SMark Johnston return (EINVAL); 1026e5054602SMark Johnston memcpy(nd_buf, key, keysize); 1027e5054602SMark Johnston error = netdump_send(NETDUMP_EKCD_KEY, 0, nd_buf, keysize); 1028e5054602SMark Johnston } 1029e5054602SMark Johnston return (error); 1030e5054602SMark Johnston } 1031e5054602SMark Johnston 1032e5054602SMark Johnston /* 1033e5054602SMark Johnston * Cleanup routine for a possibly failed netdump. 1034e5054602SMark Johnston */ 1035e5054602SMark Johnston static void 1036e5054602SMark Johnston netdump_cleanup(void) 1037e5054602SMark Johnston { 1038e5054602SMark Johnston 1039e5054602SMark Johnston if (restore_gw_addr != 0) { 1040e5054602SMark Johnston nd_gateway.s_addr = INADDR_ANY; 1041e5054602SMark Johnston restore_gw_addr = 0; 1042e5054602SMark Johnston } 1043e5054602SMark Johnston if (drv_if_input != NULL) { 1044e5054602SMark Johnston nd_ifp->if_input = drv_if_input; 1045e5054602SMark Johnston drv_if_input = NULL; 1046e5054602SMark Johnston } 1047e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_END); 1048e5054602SMark Johnston } 1049e5054602SMark Johnston 1050e5054602SMark Johnston /*- 1051e5054602SMark Johnston * KLD specific code. 1052e5054602SMark Johnston */ 1053e5054602SMark Johnston 1054e5054602SMark Johnston static struct cdevsw netdump_cdevsw = { 1055e5054602SMark Johnston .d_version = D_VERSION, 1056e5054602SMark Johnston .d_ioctl = netdump_ioctl, 1057e5054602SMark Johnston .d_name = "netdump", 1058e5054602SMark Johnston }; 1059e5054602SMark Johnston 1060e5054602SMark Johnston static struct cdev *netdump_cdev; 1061e5054602SMark Johnston 1062e5054602SMark Johnston static int 1063*6b6e2954SConrad Meyer netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) 1064e5054602SMark Johnston { 1065a68cc388SGleb Smirnoff struct epoch_tracker et; 1066e5054602SMark Johnston struct ifnet *ifp; 1067e5054602SMark Johnston 1068b35822d9SMark Johnston CURVNET_SET(TD_TO_VNET(td)); 1069b35822d9SMark Johnston if (!IS_DEFAULT_VNET(curvnet)) { 1070b35822d9SMark Johnston CURVNET_RESTORE(); 1071b35822d9SMark Johnston return (EINVAL); 1072b35822d9SMark Johnston } 1073a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10744f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1075*6b6e2954SConrad Meyer if (strcmp(ifp->if_xname, conf->kda_iface) == 0) 1076e5054602SMark Johnston break; 1077e5054602SMark Johnston } 1078e5054602SMark Johnston /* XXX ref */ 1079a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 1080b35822d9SMark Johnston CURVNET_RESTORE(); 1081e5054602SMark Johnston 1082e5054602SMark Johnston if (ifp == NULL) 1083e5054602SMark Johnston return (ENOENT); 1084e5054602SMark Johnston if ((if_getflags(ifp) & IFF_UP) == 0) 1085e5054602SMark Johnston return (ENXIO); 1086e5054602SMark Johnston if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) 1087*6b6e2954SConrad Meyer return (ENODEV); 1088e5054602SMark Johnston 1089e5054602SMark Johnston nd_ifp = ifp; 1090e5054602SMark Johnston netdump_reinit(ifp); 1091e5054602SMark Johnston memcpy(&nd_conf, conf, sizeof(nd_conf)); 1092e5054602SMark Johnston nd_enabled = 1; 1093e5054602SMark Johnston return (0); 1094e5054602SMark Johnston } 1095e5054602SMark Johnston 1096e5054602SMark Johnston /* 1097e5054602SMark Johnston * Reinitialize the mbuf pool used by drivers while dumping. This is called 1098e5054602SMark Johnston * from the generic ioctl handler for SIOCSIFMTU after the driver has 1099e5054602SMark Johnston * reconfigured itself. 1100e5054602SMark Johnston */ 1101e5054602SMark Johnston void 1102e5054602SMark Johnston netdump_reinit(struct ifnet *ifp) 1103e5054602SMark Johnston { 1104e5054602SMark Johnston int clsize, nmbuf, ncl, nrxr; 1105e5054602SMark Johnston 1106e5054602SMark Johnston if (ifp != nd_ifp) 1107e5054602SMark Johnston return; 1108e5054602SMark Johnston 1109e5054602SMark Johnston ifp->if_netdump_methods->nd_init(ifp, &nrxr, &ncl, &clsize); 1110e5054602SMark Johnston KASSERT(nrxr > 0, ("invalid receive ring count %d", nrxr)); 1111e5054602SMark Johnston 1112e5054602SMark Johnston /* 1113e5054602SMark Johnston * We need two headers per message on the transmit side. Multiply by 1114e5054602SMark Johnston * four to give us some breathing room. 1115e5054602SMark Johnston */ 1116e5054602SMark Johnston nmbuf = ncl * (4 + nrxr); 1117e5054602SMark Johnston ncl *= nrxr; 1118e5054602SMark Johnston netdump_mbuf_reinit(nmbuf, ncl, clsize); 1119e5054602SMark Johnston } 1120e5054602SMark Johnston 1121e5054602SMark Johnston /* 1122e5054602SMark Johnston * ioctl(2) handler for the netdump device. This is currently only used to 1123e5054602SMark Johnston * register netdump as a dump device. 1124e5054602SMark Johnston * 1125e5054602SMark Johnston * Parameters: 1126e5054602SMark Johnston * dev, Unused. 1127e5054602SMark Johnston * cmd, The ioctl to be handled. 1128e5054602SMark Johnston * addr, The parameter for the ioctl. 1129e5054602SMark Johnston * flags, Unused. 1130e5054602SMark Johnston * td, The thread invoking this ioctl. 1131e5054602SMark Johnston * 1132e5054602SMark Johnston * Returns: 1133e5054602SMark Johnston * 0 on success, and an errno value on failure. 1134e5054602SMark Johnston */ 1135e5054602SMark Johnston static int 1136e5054602SMark Johnston netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 1137e5054602SMark Johnston int flags __unused, struct thread *td) 1138e5054602SMark Johnston { 1139*6b6e2954SConrad Meyer struct diocskerneldump_arg kda_copy, *conf; 1140e5054602SMark Johnston struct dumperinfo dumper; 1141e5054602SMark Johnston uint8_t *encryptedkey; 1142e5054602SMark Johnston int error; 1143a9f7f192SConrad Meyer #ifdef COMPAT_FREEBSD11 1144e5054602SMark Johnston u_int u; 1145a9f7f192SConrad Meyer #endif 1146*6b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 1147*6b6e2954SConrad Meyer struct diocskerneldump_arg_freebsd12 *kda12; 1148*6b6e2954SConrad Meyer struct netdump_conf_freebsd12 *conf12; 1149*6b6e2954SConrad Meyer #endif 1150e5054602SMark Johnston 1151*6b6e2954SConrad Meyer conf = NULL; 1152e5054602SMark Johnston error = 0; 1153e5054602SMark Johnston switch (cmd) { 115460ade167SConrad Meyer #ifdef COMPAT_FREEBSD11 115560ade167SConrad Meyer case DIOCSKERNELDUMP_FREEBSD11: 1156*6b6e2954SConrad Meyer gone_in(13, "11.x ABI compatibility"); 1157e5054602SMark Johnston u = *(u_int *)addr; 1158e5054602SMark Johnston if (u != 0) { 1159e5054602SMark Johnston error = ENXIO; 1160e5054602SMark Johnston break; 1161e5054602SMark Johnston } 116260ade167SConrad Meyer if (nd_enabled) { 116360ade167SConrad Meyer nd_enabled = 0; 116460ade167SConrad Meyer netdump_mbuf_drain(); 116560ade167SConrad Meyer } 116660ade167SConrad Meyer break; 116760ade167SConrad Meyer #endif 1168*6b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 1169*6b6e2954SConrad Meyer /* 1170*6b6e2954SConrad Meyer * Used by dumpon(8) in 12.x for clearing previous 1171*6b6e2954SConrad Meyer * configuration -- then NETDUMPSCONF_FREEBSD12 is used to 1172*6b6e2954SConrad Meyer * actually configure netdump. 1173*6b6e2954SConrad Meyer */ 1174*6b6e2954SConrad Meyer case DIOCSKERNELDUMP_FREEBSD12: 1175*6b6e2954SConrad Meyer gone_in(14, "12.x ABI compatibility"); 1176*6b6e2954SConrad Meyer 1177*6b6e2954SConrad Meyer kda12 = (void *)addr; 1178*6b6e2954SConrad Meyer if (kda12->kda12_enable) { 117960ade167SConrad Meyer error = ENXIO; 118060ade167SConrad Meyer break; 118160ade167SConrad Meyer } 1182e5054602SMark Johnston if (nd_enabled) { 1183e5054602SMark Johnston nd_enabled = 0; 1184e5054602SMark Johnston netdump_mbuf_drain(); 1185e5054602SMark Johnston } 1186e5054602SMark Johnston break; 1187*6b6e2954SConrad Meyer 1188*6b6e2954SConrad Meyer case NETDUMPGCONF_FREEBSD12: 1189*6b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 1190*6b6e2954SConrad Meyer conf12 = (void *)addr; 1191*6b6e2954SConrad Meyer 1192e5054602SMark Johnston if (!nd_enabled) { 1193e5054602SMark Johnston error = ENXIO; 1194e5054602SMark Johnston break; 1195e5054602SMark Johnston } 1196*6b6e2954SConrad Meyer if (nd_conf.kda_af != AF_INET) { 1197*6b6e2954SConrad Meyer error = EOPNOTSUPP; 1198e5054602SMark Johnston break; 1199*6b6e2954SConrad Meyer } 1200e5054602SMark Johnston 1201*6b6e2954SConrad Meyer strlcpy(conf12->ndc12_iface, nd_ifp->if_xname, 1202*6b6e2954SConrad Meyer sizeof(conf12->ndc12_iface)); 1203*6b6e2954SConrad Meyer memcpy(&conf12->ndc12_server, &nd_server, 1204*6b6e2954SConrad Meyer sizeof(conf12->ndc12_server)); 1205*6b6e2954SConrad Meyer memcpy(&conf12->ndc12_client, &nd_client, 1206*6b6e2954SConrad Meyer sizeof(conf12->ndc12_client)); 1207*6b6e2954SConrad Meyer memcpy(&conf12->ndc12_gateway, &nd_gateway, 1208*6b6e2954SConrad Meyer sizeof(conf12->ndc12_gateway)); 1209*6b6e2954SConrad Meyer break; 1210*6b6e2954SConrad Meyer #endif 1211*6b6e2954SConrad Meyer case DIOCGKERNELDUMP: 1212*6b6e2954SConrad Meyer conf = (void *)addr; 1213*6b6e2954SConrad Meyer /* 1214*6b6e2954SConrad Meyer * For now, index is ignored; netdump doesn't support multiple 1215*6b6e2954SConrad Meyer * configurations (yet). 1216*6b6e2954SConrad Meyer */ 1217*6b6e2954SConrad Meyer if (!nd_enabled) { 1218*6b6e2954SConrad Meyer error = ENXIO; 1219*6b6e2954SConrad Meyer conf = NULL; 1220*6b6e2954SConrad Meyer break; 1221*6b6e2954SConrad Meyer } 1222*6b6e2954SConrad Meyer 1223*6b6e2954SConrad Meyer strlcpy(conf->kda_iface, nd_ifp->if_xname, 1224*6b6e2954SConrad Meyer sizeof(conf->kda_iface)); 1225*6b6e2954SConrad Meyer memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); 1226*6b6e2954SConrad Meyer memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); 1227*6b6e2954SConrad Meyer memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); 1228*6b6e2954SConrad Meyer conf->kda_af = nd_conf.kda_af; 1229*6b6e2954SConrad Meyer conf = NULL; 1230*6b6e2954SConrad Meyer break; 1231*6b6e2954SConrad Meyer 1232*6b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 1233*6b6e2954SConrad Meyer case NETDUMPSCONF_FREEBSD12: 1234*6b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 1235*6b6e2954SConrad Meyer 1236*6b6e2954SConrad Meyer conf12 = (struct netdump_conf_freebsd12 *)addr; 1237*6b6e2954SConrad Meyer 1238*6b6e2954SConrad Meyer _Static_assert(offsetof(struct diocskerneldump_arg, kda_server) 1239*6b6e2954SConrad Meyer == offsetof(struct netdump_conf_freebsd12, ndc12_server), 1240*6b6e2954SConrad Meyer "simplifying assumption"); 1241*6b6e2954SConrad Meyer 1242*6b6e2954SConrad Meyer memset(&kda_copy, 0, sizeof(kda_copy)); 1243*6b6e2954SConrad Meyer memcpy(&kda_copy, conf12, 1244*6b6e2954SConrad Meyer offsetof(struct diocskerneldump_arg, kda_server)); 1245*6b6e2954SConrad Meyer 1246*6b6e2954SConrad Meyer /* 12.x ABI could only configure IPv4 (INET) netdump. */ 1247*6b6e2954SConrad Meyer kda_copy.kda_af = AF_INET; 1248*6b6e2954SConrad Meyer memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server, 1249*6b6e2954SConrad Meyer sizeof(struct in_addr)); 1250*6b6e2954SConrad Meyer memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client, 1251*6b6e2954SConrad Meyer sizeof(struct in_addr)); 1252*6b6e2954SConrad Meyer memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway, 1253*6b6e2954SConrad Meyer sizeof(struct in_addr)); 1254*6b6e2954SConrad Meyer 1255*6b6e2954SConrad Meyer kda_copy.kda_index = 1256*6b6e2954SConrad Meyer (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL); 1257*6b6e2954SConrad Meyer 1258*6b6e2954SConrad Meyer conf = &kda_copy; 1259*6b6e2954SConrad Meyer explicit_bzero(conf12, sizeof(*conf12)); 1260*6b6e2954SConrad Meyer /* FALLTHROUGH */ 1261*6b6e2954SConrad Meyer #endif 1262*6b6e2954SConrad Meyer case DIOCSKERNELDUMP: 1263*6b6e2954SConrad Meyer encryptedkey = NULL; 1264*6b6e2954SConrad Meyer if (cmd == DIOCSKERNELDUMP) { 1265*6b6e2954SConrad Meyer conf = (void *)addr; 1266*6b6e2954SConrad Meyer memcpy(&kda_copy, conf, sizeof(kda_copy)); 1267*6b6e2954SConrad Meyer } 1268*6b6e2954SConrad Meyer /* Netdump only supports IP4 at this time. */ 1269*6b6e2954SConrad Meyer if (conf->kda_af != AF_INET) { 1270*6b6e2954SConrad Meyer error = EPROTONOSUPPORT; 1271*6b6e2954SConrad Meyer break; 1272*6b6e2954SConrad Meyer } 1273*6b6e2954SConrad Meyer 1274*6b6e2954SConrad Meyer conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; 1275*6b6e2954SConrad Meyer if (conf->kda_index == KDA_REMOVE || 1276*6b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_DEV || 1277*6b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_ALL) { 1278*6b6e2954SConrad Meyer if (nd_enabled || conf->kda_index == KDA_REMOVE_ALL) { 1279*6b6e2954SConrad Meyer error = dumper_remove(conf->kda_iface, conf); 1280b35822d9SMark Johnston if (error == 0) { 1281e5054602SMark Johnston nd_enabled = 0; 1282b35822d9SMark Johnston netdump_mbuf_drain(); 1283b35822d9SMark Johnston } 1284e5054602SMark Johnston } 1285e5054602SMark Johnston break; 1286e5054602SMark Johnston } 1287e5054602SMark Johnston 1288b35822d9SMark Johnston error = netdump_configure(conf, td); 1289e5054602SMark Johnston if (error != 0) 1290e5054602SMark Johnston break; 1291e5054602SMark Johnston 1292*6b6e2954SConrad Meyer if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { 1293*6b6e2954SConrad Meyer if (conf->kda_encryptedkeysize <= 0 || 1294*6b6e2954SConrad Meyer conf->kda_encryptedkeysize > 1295*6b6e2954SConrad Meyer KERNELDUMP_ENCKEY_MAX_SIZE) { 1296*6b6e2954SConrad Meyer error = EINVAL; 1297*6b6e2954SConrad Meyer break; 1298*6b6e2954SConrad Meyer } 1299*6b6e2954SConrad Meyer encryptedkey = malloc(conf->kda_encryptedkeysize, 1300*6b6e2954SConrad Meyer M_TEMP, M_WAITOK); 1301*6b6e2954SConrad Meyer error = copyin(conf->kda_encryptedkey, encryptedkey, 1302*6b6e2954SConrad Meyer conf->kda_encryptedkeysize); 1303e5054602SMark Johnston if (error != 0) { 1304e5054602SMark Johnston free(encryptedkey, M_TEMP); 1305*6b6e2954SConrad Meyer break; 1306e5054602SMark Johnston } 1307*6b6e2954SConrad Meyer 1308*6b6e2954SConrad Meyer conf->kda_encryptedkey = encryptedkey; 1309e5054602SMark Johnston } 1310e5054602SMark Johnston 13119f78e2b8SMark Johnston memset(&dumper, 0, sizeof(dumper)); 1312e5054602SMark Johnston dumper.dumper_start = netdump_start; 1313e5054602SMark Johnston dumper.dumper_hdr = netdump_write_headers; 1314e5054602SMark Johnston dumper.dumper = netdump_dumper; 1315e5054602SMark Johnston dumper.priv = NULL; 1316e5054602SMark Johnston dumper.blocksize = NETDUMP_DATASIZE; 1317e5054602SMark Johnston dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; 1318e5054602SMark Johnston dumper.mediaoffset = 0; 1319e5054602SMark Johnston dumper.mediasize = 0; 1320e5054602SMark Johnston 1321*6b6e2954SConrad Meyer error = dumper_insert(&dumper, conf->kda_iface, conf); 1322e5054602SMark Johnston if (encryptedkey != NULL) { 1323*6b6e2954SConrad Meyer explicit_bzero(encryptedkey, 1324*6b6e2954SConrad Meyer conf->kda_encryptedkeysize); 1325e5054602SMark Johnston free(encryptedkey, M_TEMP); 1326e5054602SMark Johnston } 1327b35822d9SMark Johnston if (error != 0) { 1328e5054602SMark Johnston nd_enabled = 0; 1329b35822d9SMark Johnston netdump_mbuf_drain(); 1330b35822d9SMark Johnston } 1331e5054602SMark Johnston break; 1332e5054602SMark Johnston default: 1333*6b6e2954SConrad Meyer error = ENOTTY; 1334e5054602SMark Johnston break; 1335e5054602SMark Johnston } 1336*6b6e2954SConrad Meyer explicit_bzero(&kda_copy, sizeof(kda_copy)); 1337*6b6e2954SConrad Meyer if (conf != NULL) 1338*6b6e2954SConrad Meyer explicit_bzero(conf, sizeof(*conf)); 1339e5054602SMark Johnston return (error); 1340e5054602SMark Johnston } 1341e5054602SMark Johnston 1342e5054602SMark Johnston /* 1343e5054602SMark Johnston * Called upon system init or kld load. Initializes the netdump parameters to 1344e5054602SMark Johnston * sane defaults (locates the first available NIC and uses the first IPv4 IP on 1345e5054602SMark Johnston * that card as the client IP). Leaves the server IP unconfigured. 1346e5054602SMark Johnston * 1347e5054602SMark Johnston * Parameters: 1348e5054602SMark Johnston * mod, Unused. 1349e5054602SMark Johnston * what, The module event type. 1350e5054602SMark Johnston * priv, Unused. 1351e5054602SMark Johnston * 1352e5054602SMark Johnston * Returns: 1353e5054602SMark Johnston * int, An errno value if an error occured, 0 otherwise. 1354e5054602SMark Johnston */ 1355e5054602SMark Johnston static int 1356e5054602SMark Johnston netdump_modevent(module_t mod __unused, int what, void *priv __unused) 1357e5054602SMark Johnston { 1358*6b6e2954SConrad Meyer struct diocskerneldump_arg conf; 1359e5054602SMark Johnston char *arg; 1360e5054602SMark Johnston int error; 1361e5054602SMark Johnston 1362e5054602SMark Johnston error = 0; 1363e5054602SMark Johnston switch (what) { 1364e5054602SMark Johnston case MOD_LOAD: 1365e5054602SMark Johnston error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, 1366e5054602SMark Johnston &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); 1367e5054602SMark Johnston if (error != 0) 1368e5054602SMark Johnston return (error); 1369e5054602SMark Johnston 1370e5054602SMark Johnston if ((arg = kern_getenv("net.dump.iface")) != NULL) { 1371*6b6e2954SConrad Meyer strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); 1372e5054602SMark Johnston freeenv(arg); 1373e5054602SMark Johnston 1374e5054602SMark Johnston if ((arg = kern_getenv("net.dump.server")) != NULL) { 1375*6b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1376e5054602SMark Johnston freeenv(arg); 1377e5054602SMark Johnston } 1378e5054602SMark Johnston if ((arg = kern_getenv("net.dump.client")) != NULL) { 1379*6b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1380e5054602SMark Johnston freeenv(arg); 1381e5054602SMark Johnston } 1382e5054602SMark Johnston if ((arg = kern_getenv("net.dump.gateway")) != NULL) { 1383*6b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1384e5054602SMark Johnston freeenv(arg); 1385e5054602SMark Johnston } 1386*6b6e2954SConrad Meyer conf.kda_af = AF_INET; 1387e5054602SMark Johnston 1388e5054602SMark Johnston /* Ignore errors; we print a message to the console. */ 1389b35822d9SMark Johnston (void)netdump_configure(&conf, curthread); 1390e5054602SMark Johnston } 1391e5054602SMark Johnston break; 1392e5054602SMark Johnston case MOD_UNLOAD: 1393e5054602SMark Johnston if (nd_enabled) { 1394*6b6e2954SConrad Meyer struct diocskerneldump_arg kda; 1395*6b6e2954SConrad Meyer 1396e5054602SMark Johnston printf("netdump: disabling dump device for unload\n"); 1397*6b6e2954SConrad Meyer 1398*6b6e2954SConrad Meyer bzero(&kda, sizeof(kda)); 1399*6b6e2954SConrad Meyer kda.kda_index = KDA_REMOVE_DEV; 1400*6b6e2954SConrad Meyer (void)dumper_remove(nd_conf.kda_iface, &kda); 1401*6b6e2954SConrad Meyer 1402*6b6e2954SConrad Meyer netdump_mbuf_drain(); 1403e5054602SMark Johnston nd_enabled = 0; 1404e5054602SMark Johnston } 1405*6b6e2954SConrad Meyer destroy_dev(netdump_cdev); 1406e5054602SMark Johnston break; 1407e5054602SMark Johnston default: 1408e5054602SMark Johnston error = EOPNOTSUPP; 1409e5054602SMark Johnston break; 1410e5054602SMark Johnston } 1411e5054602SMark Johnston return (error); 1412e5054602SMark Johnston } 1413e5054602SMark Johnston 1414e5054602SMark Johnston static moduledata_t netdump_mod = { 1415e5054602SMark Johnston "netdump", 1416e5054602SMark Johnston netdump_modevent, 1417e5054602SMark Johnston NULL, 1418e5054602SMark Johnston }; 1419e5054602SMark Johnston 1420e5054602SMark Johnston MODULE_VERSION(netdump, 1); 1421e5054602SMark Johnston DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1422