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); 926b6e2954SConrad Meyer static int netdump_configure(struct diocskerneldump_arg *, 936b6e2954SConrad 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*6144b50fSConrad Meyer static struct { 123*6144b50fSConrad Meyer char ndc_iface[IFNAMSIZ]; 124*6144b50fSConrad Meyer union kd_ip ndc_server; 125*6144b50fSConrad Meyer union kd_ip ndc_client; 126*6144b50fSConrad Meyer union kd_ip ndc_gateway; 127*6144b50fSConrad Meyer uint8_t ndc_af; 128*6144b50fSConrad Meyer } nd_conf; 129*6144b50fSConrad Meyer #define nd_server nd_conf.ndc_server.in4 130*6144b50fSConrad Meyer #define nd_client nd_conf.ndc_client.in4 131*6144b50fSConrad Meyer #define nd_gateway nd_conf.ndc_gateway.in4 132e5054602SMark Johnston 133e5054602SMark Johnston /* General dynamic settings. */ 134e5054602SMark Johnston static struct ether_addr nd_gw_mac; 135e5054602SMark Johnston static struct ifnet *nd_ifp; 136e5054602SMark Johnston static uint16_t nd_server_port = NETDUMP_PORT; 137e5054602SMark Johnston 138e5054602SMark Johnston FEATURE(netdump, "Netdump client support"); 139e5054602SMark Johnston 140e5054602SMark Johnston static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL, 141e5054602SMark Johnston "netdump parameters"); 142e5054602SMark Johnston 143e5054602SMark Johnston static int nd_debug; 144e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN, 145e5054602SMark Johnston &nd_debug, 0, 146e5054602SMark Johnston "Debug message verbosity"); 147e5054602SMark Johnston static int nd_enabled; 148e5054602SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD, 149e5054602SMark Johnston &nd_enabled, 0, 150e5054602SMark Johnston "netdump configuration status"); 151e5054602SMark Johnston static char nd_path[MAXPATHLEN]; 152e5054602SMark Johnston SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW, 153e5054602SMark Johnston nd_path, sizeof(nd_path), 154e5054602SMark Johnston "Server path for output files"); 155da7d7778SMark Johnston static int nd_polls = 2000; 156da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN, 157da7d7778SMark Johnston &nd_polls, 0, 158da7d7778SMark Johnston "Number of times to poll before assuming packet loss (0.5ms per poll)"); 159da7d7778SMark Johnston static int nd_retries = 10; 160da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN, 161da7d7778SMark Johnston &nd_retries, 0, 162da7d7778SMark Johnston "Number of retransmit attempts before giving up"); 163da7d7778SMark Johnston static int nd_arp_retries = 3; 164da7d7778SMark Johnston SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN, 165da7d7778SMark Johnston &nd_arp_retries, 0, 166da7d7778SMark Johnston "Number of ARP attempts before giving up"); 167e5054602SMark Johnston 168e5054602SMark Johnston /* 169e5054602SMark Johnston * Checks for netdump support on a network interface 170e5054602SMark Johnston * 171e5054602SMark Johnston * Parameters: 172e5054602SMark Johnston * ifp The network interface that is being tested for support 173e5054602SMark Johnston * 174e5054602SMark Johnston * Returns: 175e5054602SMark Johnston * int 1 if the interface is supported, 0 if not 176e5054602SMark Johnston */ 177e5054602SMark Johnston static bool 178e5054602SMark Johnston netdump_supported_nic(struct ifnet *ifp) 179e5054602SMark Johnston { 180e5054602SMark Johnston 181e5054602SMark Johnston return (ifp->if_netdump_methods != NULL); 182e5054602SMark Johnston } 183e5054602SMark Johnston 184e5054602SMark Johnston /*- 185e5054602SMark Johnston * Network specific primitives. 186e5054602SMark Johnston * Following down the code they are divided ordered as: 187e5054602SMark Johnston * - Packet buffer primitives 188e5054602SMark Johnston * - Output primitives 189e5054602SMark Johnston * - Input primitives 190e5054602SMark Johnston * - Polling primitives 191e5054602SMark Johnston */ 192e5054602SMark Johnston 193e5054602SMark Johnston /* 194e5054602SMark Johnston * Handles creation of the ethernet header, then places outgoing packets into 195e5054602SMark Johnston * the tx buffer for the NIC 196e5054602SMark Johnston * 197e5054602SMark Johnston * Parameters: 198e5054602SMark Johnston * m The mbuf containing the packet to be sent (will be freed by 199e5054602SMark Johnston * this function or the NIC driver) 200e5054602SMark Johnston * ifp The interface to send on 201e5054602SMark Johnston * dst The destination ethernet address (source address will be looked 202e5054602SMark Johnston * up using ifp) 203e5054602SMark Johnston * etype The ETHERTYPE_* value for the protocol that is being sent 204e5054602SMark Johnston * 205e5054602SMark Johnston * Returns: 206e5054602SMark Johnston * int see errno.h, 0 for success 207e5054602SMark Johnston */ 208e5054602SMark Johnston static int 209e5054602SMark Johnston netdump_ether_output(struct mbuf *m, struct ifnet *ifp, struct ether_addr dst, 210e5054602SMark Johnston u_short etype) 211e5054602SMark Johnston { 212e5054602SMark Johnston struct ether_header *eh; 213e5054602SMark Johnston 214e5054602SMark Johnston if (((ifp->if_flags & (IFF_MONITOR | IFF_UP)) != IFF_UP) || 215e5054602SMark Johnston (ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) { 216e5054602SMark Johnston if_printf(ifp, "netdump_ether_output: interface isn't up\n"); 217e5054602SMark Johnston m_freem(m); 218e5054602SMark Johnston return (ENETDOWN); 219e5054602SMark Johnston } 220e5054602SMark Johnston 221e5054602SMark Johnston /* Fill in the ethernet header. */ 222e5054602SMark Johnston M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT); 223e5054602SMark Johnston if (m == NULL) { 224e5054602SMark Johnston printf("%s: out of mbufs\n", __func__); 225e5054602SMark Johnston return (ENOBUFS); 226e5054602SMark Johnston } 227e5054602SMark Johnston eh = mtod(m, struct ether_header *); 228e5054602SMark Johnston memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN); 229e5054602SMark Johnston memcpy(eh->ether_dhost, dst.octet, ETHER_ADDR_LEN); 230e5054602SMark Johnston eh->ether_type = htons(etype); 231e5054602SMark Johnston return ((ifp->if_netdump_methods->nd_transmit)(ifp, m)); 232e5054602SMark Johnston } 233e5054602SMark Johnston 234e5054602SMark Johnston /* 235e5054602SMark Johnston * Unreliable transmission of an mbuf chain to the netdump server 236e5054602SMark Johnston * Note: can't handle fragmentation; fails if the packet is larger than 237e5054602SMark Johnston * nd_ifp->if_mtu after adding the UDP/IP headers 238e5054602SMark Johnston * 239e5054602SMark Johnston * Parameters: 240e5054602SMark Johnston * m mbuf chain 241e5054602SMark Johnston * 242e5054602SMark Johnston * Returns: 243e5054602SMark Johnston * int see errno.h, 0 for success 244e5054602SMark Johnston */ 245e5054602SMark Johnston static int 246e5054602SMark Johnston netdump_udp_output(struct mbuf *m) 247e5054602SMark Johnston { 248e5054602SMark Johnston struct udpiphdr *ui; 249e5054602SMark Johnston struct ip *ip; 250e5054602SMark Johnston 251e5054602SMark Johnston MPASS(nd_ifp != NULL); 252e5054602SMark Johnston 253e5054602SMark Johnston M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT); 254e5054602SMark Johnston if (m == NULL) { 255e5054602SMark Johnston printf("%s: out of mbufs\n", __func__); 256e5054602SMark Johnston return (ENOBUFS); 257e5054602SMark Johnston } 258e5054602SMark Johnston 259e5054602SMark Johnston if (m->m_pkthdr.len > nd_ifp->if_mtu) { 260e5054602SMark Johnston printf("netdump_udp_output: Packet is too big: %d > MTU %u\n", 261e5054602SMark Johnston m->m_pkthdr.len, nd_ifp->if_mtu); 262e5054602SMark Johnston m_freem(m); 263e5054602SMark Johnston return (ENOBUFS); 264e5054602SMark Johnston } 265e5054602SMark Johnston 266e5054602SMark Johnston ui = mtod(m, struct udpiphdr *); 267e5054602SMark Johnston bzero(ui->ui_x1, sizeof(ui->ui_x1)); 268e5054602SMark Johnston ui->ui_pr = IPPROTO_UDP; 269e5054602SMark Johnston ui->ui_len = htons(m->m_pkthdr.len - sizeof(struct ip)); 270e5054602SMark Johnston ui->ui_ulen = ui->ui_len; 271e5054602SMark Johnston ui->ui_src = nd_client; 272e5054602SMark Johnston ui->ui_dst = nd_server; 273e5054602SMark Johnston /* Use this src port so that the server can connect() the socket */ 274e5054602SMark Johnston ui->ui_sport = htons(NETDUMP_ACKPORT); 275e5054602SMark Johnston ui->ui_dport = htons(nd_server_port); 276e5054602SMark Johnston ui->ui_sum = 0; 277e5054602SMark Johnston if ((ui->ui_sum = in_cksum(m, m->m_pkthdr.len)) == 0) 278e5054602SMark Johnston ui->ui_sum = 0xffff; 279e5054602SMark Johnston 280e5054602SMark Johnston ip = mtod(m, struct ip *); 281e5054602SMark Johnston ip->ip_v = IPVERSION; 282e5054602SMark Johnston ip->ip_hl = sizeof(struct ip) >> 2; 283e5054602SMark Johnston ip->ip_tos = 0; 284e5054602SMark Johnston ip->ip_len = htons(m->m_pkthdr.len); 285e5054602SMark Johnston ip->ip_id = 0; 286e5054602SMark Johnston ip->ip_off = htons(IP_DF); 287e5054602SMark Johnston ip->ip_ttl = 255; 288e5054602SMark Johnston ip->ip_sum = 0; 289e5054602SMark Johnston ip->ip_sum = in_cksum(m, sizeof(struct ip)); 290e5054602SMark Johnston 291e5054602SMark Johnston return (netdump_ether_output(m, nd_ifp, nd_gw_mac, ETHERTYPE_IP)); 292e5054602SMark Johnston } 293e5054602SMark Johnston 294e5054602SMark Johnston /* 295e5054602SMark Johnston * Builds and sends a single ARP request to locate the server 296e5054602SMark Johnston * 297e5054602SMark Johnston * Return value: 298e5054602SMark Johnston * 0 on success 299e5054602SMark Johnston * errno on error 300e5054602SMark Johnston */ 301e5054602SMark Johnston static int 302e5054602SMark Johnston netdump_send_arp(in_addr_t dst) 303e5054602SMark Johnston { 304e5054602SMark Johnston struct ether_addr bcast; 305e5054602SMark Johnston struct mbuf *m; 306e5054602SMark Johnston struct arphdr *ah; 307e5054602SMark Johnston int pktlen; 308e5054602SMark Johnston 309e5054602SMark Johnston MPASS(nd_ifp != NULL); 310e5054602SMark Johnston 311e5054602SMark Johnston /* Fill-up a broadcast address. */ 312e5054602SMark Johnston memset(&bcast, 0xFF, ETHER_ADDR_LEN); 313e5054602SMark Johnston m = m_gethdr(M_NOWAIT, MT_DATA); 314e5054602SMark Johnston if (m == NULL) { 315e5054602SMark Johnston printf("netdump_send_arp: Out of mbufs\n"); 316e5054602SMark Johnston return (ENOBUFS); 317e5054602SMark Johnston } 318e5054602SMark Johnston pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr)); 319e5054602SMark Johnston m->m_len = pktlen; 320e5054602SMark Johnston m->m_pkthdr.len = pktlen; 321e5054602SMark Johnston MH_ALIGN(m, pktlen); 322e5054602SMark Johnston ah = mtod(m, struct arphdr *); 323e5054602SMark Johnston ah->ar_hrd = htons(ARPHRD_ETHER); 324e5054602SMark Johnston ah->ar_pro = htons(ETHERTYPE_IP); 325e5054602SMark Johnston ah->ar_hln = ETHER_ADDR_LEN; 326e5054602SMark Johnston ah->ar_pln = sizeof(struct in_addr); 327e5054602SMark Johnston ah->ar_op = htons(ARPOP_REQUEST); 328e5054602SMark Johnston memcpy(ar_sha(ah), IF_LLADDR(nd_ifp), ETHER_ADDR_LEN); 329e5054602SMark Johnston ((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr; 330e5054602SMark Johnston bzero(ar_tha(ah), ETHER_ADDR_LEN); 331e5054602SMark Johnston ((struct in_addr *)ar_tpa(ah))->s_addr = dst; 332e5054602SMark Johnston return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP)); 333e5054602SMark Johnston } 334e5054602SMark Johnston 335e5054602SMark Johnston /* 336e5054602SMark Johnston * Sends ARP requests to locate the server and waits for a response. 337e5054602SMark Johnston * We first try to ARP the server itself, and fall back to the provided 338e5054602SMark Johnston * gateway if the server appears to be off-link. 339e5054602SMark Johnston * 340e5054602SMark Johnston * Return value: 341e5054602SMark Johnston * 0 on success 342e5054602SMark Johnston * errno on error 343e5054602SMark Johnston */ 344e5054602SMark Johnston static int 345e5054602SMark Johnston netdump_arp_gw(void) 346e5054602SMark Johnston { 347e5054602SMark Johnston in_addr_t dst; 348e5054602SMark Johnston int error, polls, retries; 349e5054602SMark Johnston 350e5054602SMark Johnston dst = nd_server.s_addr; 351e5054602SMark Johnston restart: 352e5054602SMark Johnston for (retries = 0; retries < nd_arp_retries && have_gw_mac == 0; 353e5054602SMark Johnston retries++) { 354e5054602SMark Johnston error = netdump_send_arp(dst); 355e5054602SMark Johnston if (error != 0) 356e5054602SMark Johnston return (error); 357e5054602SMark Johnston for (polls = 0; polls < nd_polls && have_gw_mac == 0; polls++) { 358e5054602SMark Johnston netdump_network_poll(); 359e5054602SMark Johnston DELAY(500); 360e5054602SMark Johnston } 361e5054602SMark Johnston if (have_gw_mac == 0) 362e5054602SMark Johnston printf("(ARP retry)"); 363e5054602SMark Johnston } 364e5054602SMark Johnston if (have_gw_mac != 0) 365e5054602SMark Johnston return (0); 366e5054602SMark Johnston if (dst == nd_server.s_addr && nd_server.s_addr != nd_gateway.s_addr) { 367e5054602SMark Johnston printf("Failed to ARP server, trying to reach gateway...\n"); 368e5054602SMark Johnston dst = nd_gateway.s_addr; 369e5054602SMark Johnston goto restart; 370e5054602SMark Johnston } 371e5054602SMark Johnston 372e5054602SMark Johnston printf("\nARP timed out.\n"); 373e5054602SMark Johnston return (ETIMEDOUT); 374e5054602SMark Johnston } 375e5054602SMark Johnston 376e5054602SMark Johnston /* 377e5054602SMark Johnston * Dummy free function for netdump clusters. 378e5054602SMark Johnston */ 379e5054602SMark Johnston static void 380e5054602SMark Johnston netdump_mbuf_free(struct mbuf *m __unused) 381e5054602SMark Johnston { 382e5054602SMark Johnston } 383e5054602SMark Johnston 384e5054602SMark Johnston /* 385e5054602SMark Johnston * Construct and reliably send a netdump packet. May fail from a resource 386e5054602SMark Johnston * shortage or extreme number of unacknowledged retransmissions. Wait for 387e5054602SMark Johnston * an acknowledgement before returning. Splits packets into chunks small 388e5054602SMark Johnston * enough to be sent without fragmentation (looks up the interface MTU) 389e5054602SMark Johnston * 390e5054602SMark Johnston * Parameters: 391e5054602SMark Johnston * type netdump packet type (HERALD, FINISHED, or VMCORE) 392e5054602SMark Johnston * offset vmcore data offset (bytes) 393e5054602SMark Johnston * data vmcore data 394e5054602SMark Johnston * datalen vmcore data size (bytes) 395e5054602SMark Johnston * 396e5054602SMark Johnston * Returns: 397e5054602SMark Johnston * int see errno.h, 0 for success 398e5054602SMark Johnston */ 399e5054602SMark Johnston static int 400e5054602SMark Johnston netdump_send(uint32_t type, off_t offset, unsigned char *data, uint32_t datalen) 401e5054602SMark Johnston { 402e5054602SMark Johnston struct netdump_msg_hdr *nd_msg_hdr; 403e5054602SMark Johnston struct mbuf *m, *m2; 404e5054602SMark Johnston uint64_t want_acks; 405e5054602SMark Johnston uint32_t i, pktlen, sent_so_far; 406e5054602SMark Johnston int retries, polls, error; 407e5054602SMark Johnston 408e5054602SMark Johnston want_acks = 0; 409e5054602SMark Johnston rcvd_acks = 0; 410e5054602SMark Johnston retries = 0; 411e5054602SMark Johnston 412e5054602SMark Johnston MPASS(nd_ifp != NULL); 413e5054602SMark Johnston 414e5054602SMark Johnston retransmit: 415e5054602SMark Johnston /* Chunks can be too big to fit in packets. */ 416e5054602SMark Johnston for (i = sent_so_far = 0; sent_so_far < datalen || 417e5054602SMark Johnston (i == 0 && datalen == 0); i++) { 418e5054602SMark Johnston pktlen = datalen - sent_so_far; 419e5054602SMark Johnston 420e5054602SMark Johnston /* First bound: the packet structure. */ 421e5054602SMark Johnston pktlen = min(pktlen, NETDUMP_DATASIZE); 422e5054602SMark Johnston 423e5054602SMark Johnston /* Second bound: the interface MTU (assume no IP options). */ 424e5054602SMark Johnston pktlen = min(pktlen, nd_ifp->if_mtu - sizeof(struct udpiphdr) - 425e5054602SMark Johnston sizeof(struct netdump_msg_hdr)); 426e5054602SMark Johnston 427e5054602SMark Johnston /* 428e5054602SMark Johnston * Check if it is retransmitting and this has been ACKed 429e5054602SMark Johnston * already. 430e5054602SMark Johnston */ 431e5054602SMark Johnston if ((rcvd_acks & (1 << i)) != 0) { 432e5054602SMark Johnston sent_so_far += pktlen; 433e5054602SMark Johnston continue; 434e5054602SMark Johnston } 435e5054602SMark Johnston 436e5054602SMark Johnston /* 437e5054602SMark Johnston * Get and fill a header mbuf, then chain data as an extended 438e5054602SMark Johnston * mbuf. 439e5054602SMark Johnston */ 440e5054602SMark Johnston m = m_gethdr(M_NOWAIT, MT_DATA); 441e5054602SMark Johnston if (m == NULL) { 442e5054602SMark Johnston printf("netdump_send: Out of mbufs\n"); 443e5054602SMark Johnston return (ENOBUFS); 444e5054602SMark Johnston } 445e5054602SMark Johnston m->m_len = sizeof(struct netdump_msg_hdr); 446e5054602SMark Johnston m->m_pkthdr.len = sizeof(struct netdump_msg_hdr); 447e5054602SMark Johnston MH_ALIGN(m, sizeof(struct netdump_msg_hdr)); 448e5054602SMark Johnston nd_msg_hdr = mtod(m, struct netdump_msg_hdr *); 449e5054602SMark Johnston nd_msg_hdr->mh_seqno = htonl(nd_seqno + i); 450e5054602SMark Johnston nd_msg_hdr->mh_type = htonl(type); 451e5054602SMark Johnston nd_msg_hdr->mh_offset = htobe64(offset + sent_so_far); 452e5054602SMark Johnston nd_msg_hdr->mh_len = htonl(pktlen); 453e5054602SMark Johnston nd_msg_hdr->mh__pad = 0; 454e5054602SMark Johnston 455e5054602SMark Johnston if (pktlen != 0) { 456e5054602SMark Johnston m2 = m_get(M_NOWAIT, MT_DATA); 457e5054602SMark Johnston if (m2 == NULL) { 458e5054602SMark Johnston m_freem(m); 459e5054602SMark Johnston printf("netdump_send: Out of mbufs\n"); 460e5054602SMark Johnston return (ENOBUFS); 461e5054602SMark Johnston } 462e5054602SMark Johnston MEXTADD(m2, data + sent_so_far, pktlen, 463e5054602SMark Johnston netdump_mbuf_free, NULL, NULL, 0, EXT_DISPOSABLE); 464e5054602SMark Johnston m2->m_len = pktlen; 465e5054602SMark Johnston 466e5054602SMark Johnston m_cat(m, m2); 467e5054602SMark Johnston m->m_pkthdr.len += pktlen; 468e5054602SMark Johnston } 469e5054602SMark Johnston error = netdump_udp_output(m); 470e5054602SMark Johnston if (error != 0) 471e5054602SMark Johnston return (error); 472e5054602SMark Johnston 473e5054602SMark Johnston /* Note that we're waiting for this packet in the bitfield. */ 474e5054602SMark Johnston want_acks |= (1 << i); 475e5054602SMark Johnston sent_so_far += pktlen; 476e5054602SMark Johnston } 477e5054602SMark Johnston if (i >= NETDUMP_MAX_IN_FLIGHT) 478e5054602SMark Johnston printf("Warning: Sent more than %d packets (%d). " 479e5054602SMark Johnston "Acknowledgements will fail unless the size of " 480e5054602SMark Johnston "rcvd_acks/want_acks is increased.\n", 481e5054602SMark Johnston NETDUMP_MAX_IN_FLIGHT, i); 482e5054602SMark Johnston 483e5054602SMark Johnston /* 484e5054602SMark Johnston * Wait for acks. A *real* window would speed things up considerably. 485e5054602SMark Johnston */ 486e5054602SMark Johnston polls = 0; 487e5054602SMark Johnston while (rcvd_acks != want_acks) { 488e5054602SMark Johnston if (polls++ > nd_polls) { 489e5054602SMark Johnston if (retries++ > nd_retries) 490e5054602SMark Johnston return (ETIMEDOUT); 491e5054602SMark Johnston printf(". "); 492e5054602SMark Johnston goto retransmit; 493e5054602SMark Johnston } 494e5054602SMark Johnston netdump_network_poll(); 495e5054602SMark Johnston DELAY(500); 496e5054602SMark Johnston } 497e5054602SMark Johnston nd_seqno += i; 498e5054602SMark Johnston return (0); 499e5054602SMark Johnston } 500e5054602SMark Johnston 501e5054602SMark Johnston /* 502e5054602SMark Johnston * Handler for IP packets: checks their sanity and then processes any netdump 503e5054602SMark Johnston * ACK packets it finds. 504e5054602SMark Johnston * 505e5054602SMark Johnston * It needs to replicate partially the behaviour of ip_input() and 506e5054602SMark Johnston * udp_input(). 507e5054602SMark Johnston * 508e5054602SMark Johnston * Parameters: 509e5054602SMark Johnston * mb a pointer to an mbuf * containing the packet received 510e5054602SMark Johnston * Updates *mb if m_pullup et al change the pointer 511e5054602SMark Johnston * Assumes the calling function will take care of freeing the mbuf 512e5054602SMark Johnston */ 513e5054602SMark Johnston static void 514e5054602SMark Johnston netdump_handle_ip(struct mbuf **mb) 515e5054602SMark Johnston { 516e5054602SMark Johnston struct ip *ip; 517e5054602SMark Johnston struct udpiphdr *udp; 518e5054602SMark Johnston struct netdump_ack *nd_ack; 519e5054602SMark Johnston struct mbuf *m; 520e5054602SMark Johnston int rcv_ackno; 521e5054602SMark Johnston unsigned short hlen; 522e5054602SMark Johnston 523e5054602SMark Johnston /* IP processing. */ 524e5054602SMark Johnston m = *mb; 525e5054602SMark Johnston if (m->m_pkthdr.len < sizeof(struct ip)) { 526e5054602SMark Johnston NETDDEBUG("dropping packet too small for IP header\n"); 527e5054602SMark Johnston return; 528e5054602SMark Johnston } 529e5054602SMark Johnston if (m->m_len < sizeof(struct ip)) { 530e5054602SMark Johnston m = m_pullup(m, sizeof(struct ip)); 531e5054602SMark Johnston *mb = m; 532e5054602SMark Johnston if (m == NULL) { 533e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 534e5054602SMark Johnston return; 535e5054602SMark Johnston } 536e5054602SMark Johnston } 537e5054602SMark Johnston ip = mtod(m, struct ip *); 538e5054602SMark Johnston 539e5054602SMark Johnston /* IP version. */ 540e5054602SMark Johnston if (ip->ip_v != IPVERSION) { 541e5054602SMark Johnston NETDDEBUG("bad IP version %d\n", ip->ip_v); 542e5054602SMark Johnston return; 543e5054602SMark Johnston } 544e5054602SMark Johnston 545e5054602SMark Johnston /* Header length. */ 546e5054602SMark Johnston hlen = ip->ip_hl << 2; 547e5054602SMark Johnston if (hlen < sizeof(struct ip)) { 548e5054602SMark Johnston NETDDEBUG("bad IP header length (%hu)\n", hlen); 549e5054602SMark Johnston return; 550e5054602SMark Johnston } 551e5054602SMark Johnston if (hlen > m->m_len) { 552e5054602SMark Johnston m = m_pullup(m, hlen); 553e5054602SMark Johnston *mb = m; 554e5054602SMark Johnston if (m == NULL) { 555e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 556e5054602SMark Johnston return; 557e5054602SMark Johnston } 558e5054602SMark Johnston ip = mtod(m, struct ip *); 559e5054602SMark Johnston } 560e5054602SMark Johnston /* Ignore packets with IP options. */ 561e5054602SMark Johnston if (hlen > sizeof(struct ip)) { 562e5054602SMark Johnston NETDDEBUG("drop packet with IP options\n"); 563e5054602SMark Johnston return; 564e5054602SMark Johnston } 565e5054602SMark Johnston 566e5054602SMark Johnston #ifdef INVARIANTS 5676c1c6ae5SRodney W. Grimes if ((IN_LOOPBACK(ntohl(ip->ip_dst.s_addr)) || 5686c1c6ae5SRodney W. Grimes IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) && 569e5054602SMark Johnston (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { 570e5054602SMark Johnston NETDDEBUG("Bad IP header (RFC1122)\n"); 571e5054602SMark Johnston return; 572e5054602SMark Johnston } 573e5054602SMark Johnston #endif 574e5054602SMark Johnston 575e5054602SMark Johnston /* Checksum. */ 576e5054602SMark Johnston if ((m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) != 0) { 577e5054602SMark Johnston if ((m->m_pkthdr.csum_flags & CSUM_IP_VALID) == 0) { 578e5054602SMark Johnston NETDDEBUG("bad IP checksum\n"); 579e5054602SMark Johnston return; 580e5054602SMark Johnston } 581e5054602SMark Johnston } else { 582e5054602SMark Johnston /* XXX */ ; 583e5054602SMark Johnston } 584e5054602SMark Johnston 585e5054602SMark Johnston /* Convert fields to host byte order. */ 586e5054602SMark Johnston ip->ip_len = ntohs(ip->ip_len); 587e5054602SMark Johnston if (ip->ip_len < hlen) { 588e5054602SMark Johnston NETDDEBUG("IP packet smaller (%hu) than header (%hu)\n", 589e5054602SMark Johnston ip->ip_len, hlen); 590e5054602SMark Johnston return; 591e5054602SMark Johnston } 592e5054602SMark Johnston if (m->m_pkthdr.len < ip->ip_len) { 593e5054602SMark Johnston NETDDEBUG("IP packet bigger (%hu) than ethernet packet (%d)\n", 594e5054602SMark Johnston ip->ip_len, m->m_pkthdr.len); 595e5054602SMark Johnston return; 596e5054602SMark Johnston } 597e5054602SMark Johnston if (m->m_pkthdr.len > ip->ip_len) { 598e5054602SMark Johnston 599e5054602SMark Johnston /* Truncate the packet to the IP length. */ 600e5054602SMark Johnston if (m->m_len == m->m_pkthdr.len) { 601e5054602SMark Johnston m->m_len = ip->ip_len; 602e5054602SMark Johnston m->m_pkthdr.len = ip->ip_len; 603e5054602SMark Johnston } else 604e5054602SMark Johnston m_adj(m, ip->ip_len - m->m_pkthdr.len); 605e5054602SMark Johnston } 606e5054602SMark Johnston 607e5054602SMark Johnston ip->ip_off = ntohs(ip->ip_off); 608e5054602SMark Johnston 609e5054602SMark Johnston /* Check that the source is the server's IP. */ 610e5054602SMark Johnston if (ip->ip_src.s_addr != nd_server.s_addr) { 611e5054602SMark Johnston NETDDEBUG("drop packet not from server (from 0x%x)\n", 612e5054602SMark Johnston ip->ip_src.s_addr); 613e5054602SMark Johnston return; 614e5054602SMark Johnston } 615e5054602SMark Johnston 616e5054602SMark Johnston /* Check if the destination IP is ours. */ 617e5054602SMark Johnston if (ip->ip_dst.s_addr != nd_client.s_addr) { 618e5054602SMark Johnston NETDDEBUGV("drop packet not to our IP\n"); 619e5054602SMark Johnston return; 620e5054602SMark Johnston } 621e5054602SMark Johnston 622e5054602SMark Johnston if (ip->ip_p != IPPROTO_UDP) { 623e5054602SMark Johnston NETDDEBUG("drop non-UDP packet\n"); 624e5054602SMark Johnston return; 625e5054602SMark Johnston } 626e5054602SMark Johnston 627e5054602SMark Johnston /* Do not deal with fragments. */ 628e5054602SMark Johnston if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) { 629e5054602SMark Johnston NETDDEBUG("drop fragmented packet\n"); 630e5054602SMark Johnston return; 631e5054602SMark Johnston } 632e5054602SMark Johnston 633e5054602SMark Johnston /* UDP custom is to have packet length not include IP header. */ 634e5054602SMark Johnston ip->ip_len -= hlen; 635e5054602SMark Johnston 636e5054602SMark Johnston /* UDP processing. */ 637e5054602SMark Johnston 638e5054602SMark Johnston /* Get IP and UDP headers together, along with the netdump packet. */ 639e5054602SMark Johnston if (m->m_pkthdr.len < 640e5054602SMark Johnston sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) { 641e5054602SMark Johnston NETDDEBUG("ignoring small packet\n"); 642e5054602SMark Johnston return; 643e5054602SMark Johnston } 644e5054602SMark Johnston if (m->m_len < sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) { 645e5054602SMark Johnston m = m_pullup(m, sizeof(struct udpiphdr) + 646e5054602SMark Johnston sizeof(struct netdump_ack)); 647e5054602SMark Johnston *mb = m; 648e5054602SMark Johnston if (m == NULL) { 649e5054602SMark Johnston NETDDEBUG("m_pullup failed\n"); 650e5054602SMark Johnston return; 651e5054602SMark Johnston } 652e5054602SMark Johnston } 653e5054602SMark Johnston udp = mtod(m, struct udpiphdr *); 654e5054602SMark Johnston 655e5054602SMark Johnston if (ntohs(udp->ui_u.uh_dport) != NETDUMP_ACKPORT) { 656e5054602SMark Johnston NETDDEBUG("not on the netdump port.\n"); 657e5054602SMark Johnston return; 658e5054602SMark Johnston } 659e5054602SMark Johnston 660e5054602SMark Johnston /* Netdump processing. */ 661e5054602SMark Johnston 662e5054602SMark Johnston /* 663e5054602SMark Johnston * Packet is meant for us. Extract the ack sequence number and the 664e5054602SMark Johnston * port number if necessary. 665e5054602SMark Johnston */ 666e5054602SMark Johnston nd_ack = (struct netdump_ack *)(mtod(m, caddr_t) + 667e5054602SMark Johnston sizeof(struct udpiphdr)); 668e5054602SMark Johnston rcv_ackno = ntohl(nd_ack->na_seqno); 669e5054602SMark Johnston if (nd_server_port == NETDUMP_PORT) 670e5054602SMark Johnston nd_server_port = ntohs(udp->ui_u.uh_sport); 671e5054602SMark Johnston if (rcv_ackno >= nd_seqno + NETDUMP_MAX_IN_FLIGHT) 672e5054602SMark Johnston printf("%s: ACK %d too far in future!\n", __func__, rcv_ackno); 673e5054602SMark Johnston else if (rcv_ackno >= nd_seqno) { 674e5054602SMark Johnston /* We're interested in this ack. Record it. */ 675e5054602SMark Johnston rcvd_acks |= 1 << (rcv_ackno - nd_seqno); 676e5054602SMark Johnston } 677e5054602SMark Johnston } 678e5054602SMark Johnston 679e5054602SMark Johnston /* 680e5054602SMark Johnston * Handler for ARP packets: checks their sanity and then 681e5054602SMark Johnston * 1. If the ARP is a request for our IP, respond with our MAC address 682e5054602SMark Johnston * 2. If the ARP is a response from our server, record its MAC address 683e5054602SMark Johnston * 684e5054602SMark Johnston * It needs to replicate partially the behaviour of arpintr() and 685e5054602SMark Johnston * in_arpinput(). 686e5054602SMark Johnston * 687e5054602SMark Johnston * Parameters: 688e5054602SMark Johnston * mb a pointer to an mbuf * containing the packet received 689e5054602SMark Johnston * Updates *mb if m_pullup et al change the pointer 690e5054602SMark Johnston * Assumes the calling function will take care of freeing the mbuf 691e5054602SMark Johnston */ 692e5054602SMark Johnston static void 693e5054602SMark Johnston netdump_handle_arp(struct mbuf **mb) 694e5054602SMark Johnston { 695e5054602SMark Johnston char buf[INET_ADDRSTRLEN]; 696e5054602SMark Johnston struct in_addr isaddr, itaddr, myaddr; 697e5054602SMark Johnston struct ether_addr dst; 698e5054602SMark Johnston struct mbuf *m; 699e5054602SMark Johnston struct arphdr *ah; 700e5054602SMark Johnston struct ifnet *ifp; 701e5054602SMark Johnston uint8_t *enaddr; 702e5054602SMark Johnston int req_len, op; 703e5054602SMark Johnston 704e5054602SMark Johnston m = *mb; 705e5054602SMark Johnston ifp = m->m_pkthdr.rcvif; 706e5054602SMark Johnston if (m->m_len < sizeof(struct arphdr)) { 707e5054602SMark Johnston m = m_pullup(m, sizeof(struct arphdr)); 708e5054602SMark Johnston *mb = m; 709e5054602SMark Johnston if (m == NULL) { 710e5054602SMark Johnston NETDDEBUG("runt packet: m_pullup failed\n"); 711e5054602SMark Johnston return; 712e5054602SMark Johnston } 713e5054602SMark Johnston } 714e5054602SMark Johnston 715e5054602SMark Johnston ah = mtod(m, struct arphdr *); 716e5054602SMark Johnston if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) { 717e5054602SMark Johnston NETDDEBUG("unknown hardware address 0x%2D)\n", 718e5054602SMark Johnston (unsigned char *)&ah->ar_hrd, ""); 719e5054602SMark Johnston return; 720e5054602SMark Johnston } 721e5054602SMark Johnston if (ntohs(ah->ar_pro) != ETHERTYPE_IP) { 722e5054602SMark Johnston NETDDEBUG("drop ARP for unknown protocol %d\n", 723e5054602SMark Johnston ntohs(ah->ar_pro)); 724e5054602SMark Johnston return; 725e5054602SMark Johnston } 726e5054602SMark Johnston req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr)); 727e5054602SMark Johnston if (m->m_len < req_len) { 728e5054602SMark Johnston m = m_pullup(m, req_len); 729e5054602SMark Johnston *mb = m; 730e5054602SMark Johnston if (m == NULL) { 731e5054602SMark Johnston NETDDEBUG("runt packet: m_pullup failed\n"); 732e5054602SMark Johnston return; 733e5054602SMark Johnston } 734e5054602SMark Johnston } 735e5054602SMark Johnston ah = mtod(m, struct arphdr *); 736e5054602SMark Johnston 737e5054602SMark Johnston op = ntohs(ah->ar_op); 738e5054602SMark Johnston memcpy(&isaddr, ar_spa(ah), sizeof(isaddr)); 739e5054602SMark Johnston memcpy(&itaddr, ar_tpa(ah), sizeof(itaddr)); 740e5054602SMark Johnston enaddr = (uint8_t *)IF_LLADDR(ifp); 741e5054602SMark Johnston myaddr = nd_client; 742e5054602SMark Johnston 743e5054602SMark Johnston if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) { 744e5054602SMark Johnston NETDDEBUG("ignoring ARP from myself\n"); 745e5054602SMark Johnston return; 746e5054602SMark Johnston } 747e5054602SMark Johnston 748e5054602SMark Johnston if (isaddr.s_addr == nd_client.s_addr) { 749e5054602SMark Johnston printf("%s: %*D is using my IP address %s!\n", __func__, 750e5054602SMark Johnston ifp->if_addrlen, (u_char *)ar_sha(ah), ":", 751e5054602SMark Johnston inet_ntoa_r(isaddr, buf)); 752e5054602SMark Johnston return; 753e5054602SMark Johnston } 754e5054602SMark Johnston 755e5054602SMark Johnston if (memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen) == 0) { 756e5054602SMark Johnston NETDDEBUG("ignoring ARP from broadcast address\n"); 757e5054602SMark Johnston return; 758e5054602SMark Johnston } 759e5054602SMark Johnston 760e5054602SMark Johnston if (op == ARPOP_REPLY) { 761e5054602SMark Johnston if (isaddr.s_addr != nd_gateway.s_addr && 762e5054602SMark Johnston isaddr.s_addr != nd_server.s_addr) { 763e5054602SMark Johnston inet_ntoa_r(isaddr, buf); 764e5054602SMark Johnston NETDDEBUG( 765e5054602SMark Johnston "ignoring ARP reply from %s (not netdump server)\n", 766e5054602SMark Johnston buf); 767e5054602SMark Johnston return; 768e5054602SMark Johnston } 769e5054602SMark Johnston memcpy(nd_gw_mac.octet, ar_sha(ah), 770e5054602SMark Johnston min(ah->ar_hln, ETHER_ADDR_LEN)); 771e5054602SMark Johnston have_gw_mac = 1; 772e5054602SMark Johnston NETDDEBUG("got server MAC address %6D\n", nd_gw_mac.octet, ":"); 773e5054602SMark Johnston return; 774e5054602SMark Johnston } 775e5054602SMark Johnston 776e5054602SMark Johnston if (op != ARPOP_REQUEST) { 777e5054602SMark Johnston NETDDEBUG("ignoring ARP non-request/reply\n"); 778e5054602SMark Johnston return; 779e5054602SMark Johnston } 780e5054602SMark Johnston 781e5054602SMark Johnston if (itaddr.s_addr != nd_client.s_addr) { 782e5054602SMark Johnston NETDDEBUG("ignoring ARP not to our IP\n"); 783e5054602SMark Johnston return; 784e5054602SMark Johnston } 785e5054602SMark Johnston 786e5054602SMark Johnston memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln); 787e5054602SMark Johnston memcpy(ar_sha(ah), enaddr, ah->ar_hln); 788e5054602SMark Johnston memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); 789e5054602SMark Johnston memcpy(ar_spa(ah), &itaddr, ah->ar_pln); 790e5054602SMark Johnston ah->ar_op = htons(ARPOP_REPLY); 791e5054602SMark Johnston ah->ar_pro = htons(ETHERTYPE_IP); 792e5054602SMark Johnston m->m_flags &= ~(M_BCAST|M_MCAST); 793e5054602SMark Johnston m->m_len = arphdr_len(ah); 794e5054602SMark Johnston m->m_pkthdr.len = m->m_len; 795e5054602SMark Johnston 796e5054602SMark Johnston memcpy(dst.octet, ar_tha(ah), ETHER_ADDR_LEN); 797e5054602SMark Johnston netdump_ether_output(m, ifp, dst, ETHERTYPE_ARP); 798e5054602SMark Johnston *mb = NULL; 799e5054602SMark Johnston } 800e5054602SMark Johnston 801e5054602SMark Johnston /* 802e5054602SMark Johnston * Handler for incoming packets directly from the network adapter 803e5054602SMark Johnston * Identifies the packet type (IP or ARP) and passes it along to one of the 804e5054602SMark Johnston * helper functions netdump_handle_ip or netdump_handle_arp. 805e5054602SMark Johnston * 806e5054602SMark Johnston * It needs to replicate partially the behaviour of ether_input() and 807e5054602SMark Johnston * ether_demux(). 808e5054602SMark Johnston * 809e5054602SMark Johnston * Parameters: 810e5054602SMark Johnston * ifp the interface the packet came from (should be nd_ifp) 811e5054602SMark Johnston * m an mbuf containing the packet received 812e5054602SMark Johnston */ 813e5054602SMark Johnston static void 814e5054602SMark Johnston netdump_pkt_in(struct ifnet *ifp, struct mbuf *m) 815e5054602SMark Johnston { 816e5054602SMark Johnston struct ifreq ifr; 817e5054602SMark Johnston struct ether_header *eh; 818e5054602SMark Johnston u_short etype; 819e5054602SMark Johnston 820e5054602SMark Johnston /* Ethernet processing. */ 821e5054602SMark Johnston if ((m->m_flags & M_PKTHDR) == 0) { 822e5054602SMark Johnston NETDDEBUG_IF(ifp, "discard frame without packet header\n"); 823e5054602SMark Johnston goto done; 824e5054602SMark Johnston } 825e5054602SMark Johnston if (m->m_len < ETHER_HDR_LEN) { 826e5054602SMark Johnston NETDDEBUG_IF(ifp, 827e5054602SMark Johnston "discard frame without leading eth header (len %u pktlen %u)\n", 828e5054602SMark Johnston m->m_len, m->m_pkthdr.len); 829e5054602SMark Johnston goto done; 830e5054602SMark Johnston } 831e5054602SMark Johnston if ((m->m_flags & M_HASFCS) != 0) { 832e5054602SMark Johnston m_adj(m, -ETHER_CRC_LEN); 833e5054602SMark Johnston m->m_flags &= ~M_HASFCS; 834e5054602SMark Johnston } 835e5054602SMark Johnston eh = mtod(m, struct ether_header *); 836e5054602SMark Johnston etype = ntohs(eh->ether_type); 837e5054602SMark Johnston if ((m->m_flags & M_VLANTAG) != 0 || etype == ETHERTYPE_VLAN) { 838e5054602SMark Johnston NETDDEBUG_IF(ifp, "ignoring vlan packets\n"); 839e5054602SMark Johnston goto done; 840e5054602SMark Johnston } 841e5054602SMark Johnston if (if_gethwaddr(ifp, &ifr) != 0) { 842e5054602SMark Johnston NETDDEBUG_IF(ifp, "failed to get hw addr for interface\n"); 843e5054602SMark Johnston goto done; 844e5054602SMark Johnston } 845e5054602SMark Johnston if (memcmp(ifr.ifr_addr.sa_data, eh->ether_dhost, 846e5054602SMark Johnston ETHER_ADDR_LEN) != 0) { 847e5054602SMark Johnston NETDDEBUG_IF(ifp, 848e5054602SMark Johnston "discard frame with incorrect destination addr\n"); 849e5054602SMark Johnston goto done; 850e5054602SMark Johnston } 851e5054602SMark Johnston 852e5054602SMark Johnston /* Done ethernet processing. Strip off the ethernet header. */ 853e5054602SMark Johnston m_adj(m, ETHER_HDR_LEN); 854e5054602SMark Johnston switch (etype) { 855e5054602SMark Johnston case ETHERTYPE_ARP: 856e5054602SMark Johnston netdump_handle_arp(&m); 857e5054602SMark Johnston break; 858e5054602SMark Johnston case ETHERTYPE_IP: 859e5054602SMark Johnston netdump_handle_ip(&m); 860e5054602SMark Johnston break; 861e5054602SMark Johnston default: 862e5054602SMark Johnston NETDDEBUG_IF(ifp, "dropping unknown ethertype %hu\n", etype); 863e5054602SMark Johnston break; 864e5054602SMark Johnston } 865e5054602SMark Johnston done: 866e5054602SMark Johnston if (m != NULL) 867e5054602SMark Johnston m_freem(m); 868e5054602SMark Johnston } 869e5054602SMark Johnston 870e5054602SMark Johnston /* 871e5054602SMark Johnston * After trapping, instead of assuming that most of the network stack is sane, 872e5054602SMark Johnston * we just poll the driver directly for packets. 873e5054602SMark Johnston */ 874e5054602SMark Johnston static void 875e5054602SMark Johnston netdump_network_poll(void) 876e5054602SMark Johnston { 877e5054602SMark Johnston 878e5054602SMark Johnston MPASS(nd_ifp != NULL); 879e5054602SMark Johnston 880e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_poll(nd_ifp, 1000); 881e5054602SMark Johnston } 882e5054602SMark Johnston 883e5054602SMark Johnston /*- 884e5054602SMark Johnston * Dumping specific primitives. 885e5054602SMark Johnston */ 886e5054602SMark Johnston 887e5054602SMark Johnston /* 888e5054602SMark Johnston * Callback from dumpsys() to dump a chunk of memory. 889e5054602SMark Johnston * Copies it out to our static buffer then sends it across the network. 890e5054602SMark Johnston * Detects the initial KDH and makes sure it is given a special packet type. 891e5054602SMark Johnston * 892e5054602SMark Johnston * Parameters: 893e5054602SMark Johnston * priv Unused. Optional private pointer. 894e5054602SMark Johnston * virtual Virtual address (where to read the data from) 895e5054602SMark Johnston * physical Unused. Physical memory address. 896e5054602SMark Johnston * offset Offset from start of core file 897e5054602SMark Johnston * length Data length 898e5054602SMark Johnston * 899e5054602SMark Johnston * Return value: 900e5054602SMark Johnston * 0 on success 901e5054602SMark Johnston * errno on error 902e5054602SMark Johnston */ 903e5054602SMark Johnston static int 904e5054602SMark Johnston netdump_dumper(void *priv __unused, void *virtual, 905e5054602SMark Johnston vm_offset_t physical __unused, off_t offset, size_t length) 906e5054602SMark Johnston { 907e5054602SMark Johnston int error; 908e5054602SMark Johnston 909e5054602SMark Johnston NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n", 910e5054602SMark Johnston virtual, (uintmax_t)offset, length); 911e5054602SMark Johnston 912e5054602SMark Johnston if (virtual == NULL) { 913e5054602SMark Johnston if (dump_failed != 0) 914e5054602SMark Johnston printf("failed to dump the kernel core\n"); 915e5054602SMark Johnston else if (netdump_send(NETDUMP_FINISHED, 0, NULL, 0) != 0) 916e5054602SMark Johnston printf("failed to close the transaction\n"); 917e5054602SMark Johnston else 918e5054602SMark Johnston printf("\nnetdump finished.\n"); 919e5054602SMark Johnston netdump_cleanup(); 920e5054602SMark Johnston return (0); 921e5054602SMark Johnston } 922e5054602SMark Johnston if (length > sizeof(nd_buf)) 923e5054602SMark Johnston return (ENOSPC); 924e5054602SMark Johnston 925e5054602SMark Johnston memmove(nd_buf, virtual, length); 926e5054602SMark Johnston error = netdump_send(NETDUMP_VMCORE, offset, nd_buf, length); 927e5054602SMark Johnston if (error != 0) { 928e5054602SMark Johnston dump_failed = 1; 929e5054602SMark Johnston return (error); 930e5054602SMark Johnston } 931e5054602SMark Johnston return (0); 932e5054602SMark Johnston } 933e5054602SMark Johnston 934e5054602SMark Johnston /* 935e5054602SMark Johnston * Perform any initalization needed prior to transmitting the kernel core. 936e5054602SMark Johnston */ 937e5054602SMark Johnston static int 938e5054602SMark Johnston netdump_start(struct dumperinfo *di) 939e5054602SMark Johnston { 940e5054602SMark Johnston char *path; 941e5054602SMark Johnston char buf[INET_ADDRSTRLEN]; 942e5054602SMark Johnston uint32_t len; 943e5054602SMark Johnston int error; 944e5054602SMark Johnston 945e5054602SMark Johnston error = 0; 946e5054602SMark Johnston 947e5054602SMark Johnston /* Check if the dumping is allowed to continue. */ 948e5054602SMark Johnston if (nd_enabled == 0) 949e5054602SMark Johnston return (EINVAL); 950e5054602SMark Johnston 951e5054602SMark Johnston if (panicstr == NULL) { 952e5054602SMark Johnston printf( 953e5054602SMark Johnston "netdump_start: netdump may only be used after a panic\n"); 954e5054602SMark Johnston return (EINVAL); 955e5054602SMark Johnston } 956e5054602SMark Johnston 957e5054602SMark Johnston MPASS(nd_ifp != NULL); 958e5054602SMark Johnston 959e5054602SMark Johnston if (nd_server.s_addr == INADDR_ANY) { 960e5054602SMark Johnston printf("netdump_start: can't netdump; no server IP given\n"); 961e5054602SMark Johnston return (EINVAL); 962e5054602SMark Johnston } 963e5054602SMark Johnston if (nd_client.s_addr == INADDR_ANY) { 964e5054602SMark Johnston printf("netdump_start: can't netdump; no client IP given\n"); 965e5054602SMark Johnston return (EINVAL); 966e5054602SMark Johnston } 967e5054602SMark Johnston 968e5054602SMark Johnston /* We start dumping at offset 0. */ 969e5054602SMark Johnston di->dumpoff = 0; 970e5054602SMark Johnston 971e5054602SMark Johnston nd_seqno = 1; 972e5054602SMark Johnston 973e5054602SMark Johnston /* 974e5054602SMark Johnston * nd_server_port could have switched after the first ack the 975e5054602SMark Johnston * first time it gets called. Adjust it accordingly. 976e5054602SMark Johnston */ 977e5054602SMark Johnston nd_server_port = NETDUMP_PORT; 978e5054602SMark Johnston 979e5054602SMark Johnston /* Switch to the netdump mbuf zones. */ 980e5054602SMark Johnston netdump_mbuf_dump(); 981e5054602SMark Johnston 982e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_START); 983e5054602SMark Johnston 984e5054602SMark Johnston /* Make the card use *our* receive callback. */ 985e5054602SMark Johnston drv_if_input = nd_ifp->if_input; 986e5054602SMark Johnston nd_ifp->if_input = netdump_pkt_in; 987e5054602SMark Johnston 988e5054602SMark Johnston if (nd_gateway.s_addr == INADDR_ANY) { 989e5054602SMark Johnston restore_gw_addr = 1; 990e5054602SMark Johnston nd_gateway.s_addr = nd_server.s_addr; 991e5054602SMark Johnston } 992e5054602SMark Johnston 993e5054602SMark Johnston printf("netdump in progress. searching for server...\n"); 994e5054602SMark Johnston if (netdump_arp_gw()) { 995e5054602SMark Johnston printf("failed to locate server MAC address\n"); 996e5054602SMark Johnston error = EINVAL; 997e5054602SMark Johnston goto trig_abort; 998e5054602SMark Johnston } 999e5054602SMark Johnston 1000e5054602SMark Johnston if (nd_path[0] != '\0') { 1001e5054602SMark Johnston path = nd_path; 1002e5054602SMark Johnston len = strlen(path) + 1; 1003e5054602SMark Johnston } else { 1004e5054602SMark Johnston path = NULL; 1005e5054602SMark Johnston len = 0; 1006e5054602SMark Johnston } 1007e5054602SMark Johnston if (netdump_send(NETDUMP_HERALD, 0, path, len) != 0) { 1008e5054602SMark Johnston printf("failed to contact netdump server\n"); 1009e5054602SMark Johnston error = EINVAL; 1010e5054602SMark Johnston goto trig_abort; 1011e5054602SMark Johnston } 1012e5054602SMark Johnston printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf), 1013e5054602SMark Johnston nd_gw_mac.octet, ":"); 1014e5054602SMark Johnston return (0); 1015e5054602SMark Johnston 1016e5054602SMark Johnston trig_abort: 1017e5054602SMark Johnston netdump_cleanup(); 1018e5054602SMark Johnston return (error); 1019e5054602SMark Johnston } 1020e5054602SMark Johnston 1021e5054602SMark Johnston static int 1022e5054602SMark Johnston netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh, 1023e5054602SMark Johnston void *key, uint32_t keysize) 1024e5054602SMark Johnston { 1025e5054602SMark Johnston int error; 1026e5054602SMark Johnston 1027e5054602SMark Johnston memcpy(nd_buf, kdh, sizeof(*kdh)); 1028e5054602SMark Johnston error = netdump_send(NETDUMP_KDH, 0, nd_buf, sizeof(*kdh)); 1029e5054602SMark Johnston if (error == 0 && keysize > 0) { 1030e5054602SMark Johnston if (keysize > sizeof(nd_buf)) 1031e5054602SMark Johnston return (EINVAL); 1032e5054602SMark Johnston memcpy(nd_buf, key, keysize); 1033e5054602SMark Johnston error = netdump_send(NETDUMP_EKCD_KEY, 0, nd_buf, keysize); 1034e5054602SMark Johnston } 1035e5054602SMark Johnston return (error); 1036e5054602SMark Johnston } 1037e5054602SMark Johnston 1038e5054602SMark Johnston /* 1039e5054602SMark Johnston * Cleanup routine for a possibly failed netdump. 1040e5054602SMark Johnston */ 1041e5054602SMark Johnston static void 1042e5054602SMark Johnston netdump_cleanup(void) 1043e5054602SMark Johnston { 1044e5054602SMark Johnston 1045e5054602SMark Johnston if (restore_gw_addr != 0) { 1046e5054602SMark Johnston nd_gateway.s_addr = INADDR_ANY; 1047e5054602SMark Johnston restore_gw_addr = 0; 1048e5054602SMark Johnston } 1049e5054602SMark Johnston if (drv_if_input != NULL) { 1050e5054602SMark Johnston nd_ifp->if_input = drv_if_input; 1051e5054602SMark Johnston drv_if_input = NULL; 1052e5054602SMark Johnston } 1053e5054602SMark Johnston nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_END); 1054e5054602SMark Johnston } 1055e5054602SMark Johnston 1056e5054602SMark Johnston /*- 1057e5054602SMark Johnston * KLD specific code. 1058e5054602SMark Johnston */ 1059e5054602SMark Johnston 1060e5054602SMark Johnston static struct cdevsw netdump_cdevsw = { 1061e5054602SMark Johnston .d_version = D_VERSION, 1062e5054602SMark Johnston .d_ioctl = netdump_ioctl, 1063e5054602SMark Johnston .d_name = "netdump", 1064e5054602SMark Johnston }; 1065e5054602SMark Johnston 1066e5054602SMark Johnston static struct cdev *netdump_cdev; 1067e5054602SMark Johnston 1068e5054602SMark Johnston static int 10696b6e2954SConrad Meyer netdump_configure(struct diocskerneldump_arg *conf, struct thread *td) 1070e5054602SMark Johnston { 1071a68cc388SGleb Smirnoff struct epoch_tracker et; 1072e5054602SMark Johnston struct ifnet *ifp; 1073e5054602SMark Johnston 1074b35822d9SMark Johnston CURVNET_SET(TD_TO_VNET(td)); 1075b35822d9SMark Johnston if (!IS_DEFAULT_VNET(curvnet)) { 1076b35822d9SMark Johnston CURVNET_RESTORE(); 1077b35822d9SMark Johnston return (EINVAL); 1078b35822d9SMark Johnston } 1079a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 10804f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 10816b6e2954SConrad Meyer if (strcmp(ifp->if_xname, conf->kda_iface) == 0) 1082e5054602SMark Johnston break; 1083e5054602SMark Johnston } 1084e5054602SMark Johnston /* XXX ref */ 1085a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 1086b35822d9SMark Johnston CURVNET_RESTORE(); 1087e5054602SMark Johnston 1088e5054602SMark Johnston if (ifp == NULL) 1089e5054602SMark Johnston return (ENOENT); 1090e5054602SMark Johnston if ((if_getflags(ifp) & IFF_UP) == 0) 1091e5054602SMark Johnston return (ENXIO); 1092e5054602SMark Johnston if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) 10936b6e2954SConrad Meyer return (ENODEV); 1094e5054602SMark Johnston 1095e5054602SMark Johnston nd_ifp = ifp; 1096*6144b50fSConrad Meyer 1097e5054602SMark Johnston netdump_reinit(ifp); 1098*6144b50fSConrad Meyer #define COPY_SIZED(elm) do { \ 1099*6144b50fSConrad Meyer _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \ 1100*6144b50fSConrad Meyer sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \ 1101*6144b50fSConrad Meyer memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \ 1102*6144b50fSConrad Meyer sizeof(nd_conf.ndc_ ## elm)); \ 1103*6144b50fSConrad Meyer } while (0) 1104*6144b50fSConrad Meyer COPY_SIZED(iface); 1105*6144b50fSConrad Meyer COPY_SIZED(server); 1106*6144b50fSConrad Meyer COPY_SIZED(client); 1107*6144b50fSConrad Meyer COPY_SIZED(gateway); 1108*6144b50fSConrad Meyer COPY_SIZED(af); 1109*6144b50fSConrad Meyer #undef COPY_SIZED 1110e5054602SMark Johnston nd_enabled = 1; 1111e5054602SMark Johnston return (0); 1112e5054602SMark Johnston } 1113e5054602SMark Johnston 1114e5054602SMark Johnston /* 1115e5054602SMark Johnston * Reinitialize the mbuf pool used by drivers while dumping. This is called 1116e5054602SMark Johnston * from the generic ioctl handler for SIOCSIFMTU after the driver has 1117e5054602SMark Johnston * reconfigured itself. 1118e5054602SMark Johnston */ 1119e5054602SMark Johnston void 1120e5054602SMark Johnston netdump_reinit(struct ifnet *ifp) 1121e5054602SMark Johnston { 1122e5054602SMark Johnston int clsize, nmbuf, ncl, nrxr; 1123e5054602SMark Johnston 1124e5054602SMark Johnston if (ifp != nd_ifp) 1125e5054602SMark Johnston return; 1126e5054602SMark Johnston 1127e5054602SMark Johnston ifp->if_netdump_methods->nd_init(ifp, &nrxr, &ncl, &clsize); 1128e5054602SMark Johnston KASSERT(nrxr > 0, ("invalid receive ring count %d", nrxr)); 1129e5054602SMark Johnston 1130e5054602SMark Johnston /* 1131e5054602SMark Johnston * We need two headers per message on the transmit side. Multiply by 1132e5054602SMark Johnston * four to give us some breathing room. 1133e5054602SMark Johnston */ 1134e5054602SMark Johnston nmbuf = ncl * (4 + nrxr); 1135e5054602SMark Johnston ncl *= nrxr; 1136e5054602SMark Johnston netdump_mbuf_reinit(nmbuf, ncl, clsize); 1137e5054602SMark Johnston } 1138e5054602SMark Johnston 1139e5054602SMark Johnston /* 1140e5054602SMark Johnston * ioctl(2) handler for the netdump device. This is currently only used to 1141e5054602SMark Johnston * register netdump as a dump device. 1142e5054602SMark Johnston * 1143e5054602SMark Johnston * Parameters: 1144e5054602SMark Johnston * dev, Unused. 1145e5054602SMark Johnston * cmd, The ioctl to be handled. 1146e5054602SMark Johnston * addr, The parameter for the ioctl. 1147e5054602SMark Johnston * flags, Unused. 1148e5054602SMark Johnston * td, The thread invoking this ioctl. 1149e5054602SMark Johnston * 1150e5054602SMark Johnston * Returns: 1151e5054602SMark Johnston * 0 on success, and an errno value on failure. 1152e5054602SMark Johnston */ 1153e5054602SMark Johnston static int 1154e5054602SMark Johnston netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 1155e5054602SMark Johnston int flags __unused, struct thread *td) 1156e5054602SMark Johnston { 11576b6e2954SConrad Meyer struct diocskerneldump_arg kda_copy, *conf; 1158e5054602SMark Johnston struct dumperinfo dumper; 1159e5054602SMark Johnston uint8_t *encryptedkey; 1160e5054602SMark Johnston int error; 1161a9f7f192SConrad Meyer #ifdef COMPAT_FREEBSD11 1162e5054602SMark Johnston u_int u; 1163a9f7f192SConrad Meyer #endif 11646b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 11656b6e2954SConrad Meyer struct diocskerneldump_arg_freebsd12 *kda12; 11666b6e2954SConrad Meyer struct netdump_conf_freebsd12 *conf12; 11676b6e2954SConrad Meyer #endif 1168e5054602SMark Johnston 11696b6e2954SConrad Meyer conf = NULL; 1170e5054602SMark Johnston error = 0; 1171e5054602SMark Johnston switch (cmd) { 117260ade167SConrad Meyer #ifdef COMPAT_FREEBSD11 117360ade167SConrad Meyer case DIOCSKERNELDUMP_FREEBSD11: 11746b6e2954SConrad Meyer gone_in(13, "11.x ABI compatibility"); 1175e5054602SMark Johnston u = *(u_int *)addr; 1176e5054602SMark Johnston if (u != 0) { 1177e5054602SMark Johnston error = ENXIO; 1178e5054602SMark Johnston break; 1179e5054602SMark Johnston } 118060ade167SConrad Meyer if (nd_enabled) { 118160ade167SConrad Meyer nd_enabled = 0; 118260ade167SConrad Meyer netdump_mbuf_drain(); 118360ade167SConrad Meyer } 118460ade167SConrad Meyer break; 118560ade167SConrad Meyer #endif 11866b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 11876b6e2954SConrad Meyer /* 11886b6e2954SConrad Meyer * Used by dumpon(8) in 12.x for clearing previous 11896b6e2954SConrad Meyer * configuration -- then NETDUMPSCONF_FREEBSD12 is used to 11906b6e2954SConrad Meyer * actually configure netdump. 11916b6e2954SConrad Meyer */ 11926b6e2954SConrad Meyer case DIOCSKERNELDUMP_FREEBSD12: 11936b6e2954SConrad Meyer gone_in(14, "12.x ABI compatibility"); 11946b6e2954SConrad Meyer 11956b6e2954SConrad Meyer kda12 = (void *)addr; 11966b6e2954SConrad Meyer if (kda12->kda12_enable) { 119760ade167SConrad Meyer error = ENXIO; 119860ade167SConrad Meyer break; 119960ade167SConrad Meyer } 1200e5054602SMark Johnston if (nd_enabled) { 1201e5054602SMark Johnston nd_enabled = 0; 1202e5054602SMark Johnston netdump_mbuf_drain(); 1203e5054602SMark Johnston } 1204e5054602SMark Johnston break; 12056b6e2954SConrad Meyer 12066b6e2954SConrad Meyer case NETDUMPGCONF_FREEBSD12: 12076b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 12086b6e2954SConrad Meyer conf12 = (void *)addr; 12096b6e2954SConrad Meyer 1210e5054602SMark Johnston if (!nd_enabled) { 1211e5054602SMark Johnston error = ENXIO; 1212e5054602SMark Johnston break; 1213e5054602SMark Johnston } 1214*6144b50fSConrad Meyer if (nd_conf.ndc_af != AF_INET) { 12156b6e2954SConrad Meyer error = EOPNOTSUPP; 1216e5054602SMark Johnston break; 12176b6e2954SConrad Meyer } 1218e5054602SMark Johnston 12196b6e2954SConrad Meyer strlcpy(conf12->ndc12_iface, nd_ifp->if_xname, 12206b6e2954SConrad Meyer sizeof(conf12->ndc12_iface)); 12216b6e2954SConrad Meyer memcpy(&conf12->ndc12_server, &nd_server, 12226b6e2954SConrad Meyer sizeof(conf12->ndc12_server)); 12236b6e2954SConrad Meyer memcpy(&conf12->ndc12_client, &nd_client, 12246b6e2954SConrad Meyer sizeof(conf12->ndc12_client)); 12256b6e2954SConrad Meyer memcpy(&conf12->ndc12_gateway, &nd_gateway, 12266b6e2954SConrad Meyer sizeof(conf12->ndc12_gateway)); 12276b6e2954SConrad Meyer break; 12286b6e2954SConrad Meyer #endif 12296b6e2954SConrad Meyer case DIOCGKERNELDUMP: 12306b6e2954SConrad Meyer conf = (void *)addr; 12316b6e2954SConrad Meyer /* 12326b6e2954SConrad Meyer * For now, index is ignored; netdump doesn't support multiple 12336b6e2954SConrad Meyer * configurations (yet). 12346b6e2954SConrad Meyer */ 12356b6e2954SConrad Meyer if (!nd_enabled) { 12366b6e2954SConrad Meyer error = ENXIO; 12376b6e2954SConrad Meyer conf = NULL; 12386b6e2954SConrad Meyer break; 12396b6e2954SConrad Meyer } 12406b6e2954SConrad Meyer 12416b6e2954SConrad Meyer strlcpy(conf->kda_iface, nd_ifp->if_xname, 12426b6e2954SConrad Meyer sizeof(conf->kda_iface)); 12436b6e2954SConrad Meyer memcpy(&conf->kda_server, &nd_server, sizeof(nd_server)); 12446b6e2954SConrad Meyer memcpy(&conf->kda_client, &nd_client, sizeof(nd_client)); 12456b6e2954SConrad Meyer memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway)); 1246*6144b50fSConrad Meyer conf->kda_af = nd_conf.ndc_af; 12476b6e2954SConrad Meyer conf = NULL; 12486b6e2954SConrad Meyer break; 12496b6e2954SConrad Meyer 12506b6e2954SConrad Meyer #ifdef COMPAT_FREEBSD12 12516b6e2954SConrad Meyer case NETDUMPSCONF_FREEBSD12: 12526b6e2954SConrad Meyer gone_in(14, "FreeBSD 12.x ABI compat"); 12536b6e2954SConrad Meyer 12546b6e2954SConrad Meyer conf12 = (struct netdump_conf_freebsd12 *)addr; 12556b6e2954SConrad Meyer 12566b6e2954SConrad Meyer _Static_assert(offsetof(struct diocskerneldump_arg, kda_server) 12576b6e2954SConrad Meyer == offsetof(struct netdump_conf_freebsd12, ndc12_server), 12586b6e2954SConrad Meyer "simplifying assumption"); 12596b6e2954SConrad Meyer 12606b6e2954SConrad Meyer memset(&kda_copy, 0, sizeof(kda_copy)); 12616b6e2954SConrad Meyer memcpy(&kda_copy, conf12, 12626b6e2954SConrad Meyer offsetof(struct diocskerneldump_arg, kda_server)); 12636b6e2954SConrad Meyer 12646b6e2954SConrad Meyer /* 12.x ABI could only configure IPv4 (INET) netdump. */ 12656b6e2954SConrad Meyer kda_copy.kda_af = AF_INET; 12666b6e2954SConrad Meyer memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server, 12676b6e2954SConrad Meyer sizeof(struct in_addr)); 12686b6e2954SConrad Meyer memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client, 12696b6e2954SConrad Meyer sizeof(struct in_addr)); 12706b6e2954SConrad Meyer memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway, 12716b6e2954SConrad Meyer sizeof(struct in_addr)); 12726b6e2954SConrad Meyer 12736b6e2954SConrad Meyer kda_copy.kda_index = 12746b6e2954SConrad Meyer (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL); 12756b6e2954SConrad Meyer 12766b6e2954SConrad Meyer conf = &kda_copy; 12776b6e2954SConrad Meyer explicit_bzero(conf12, sizeof(*conf12)); 12786b6e2954SConrad Meyer /* FALLTHROUGH */ 12796b6e2954SConrad Meyer #endif 12806b6e2954SConrad Meyer case DIOCSKERNELDUMP: 12816b6e2954SConrad Meyer encryptedkey = NULL; 12826b6e2954SConrad Meyer if (cmd == DIOCSKERNELDUMP) { 12836b6e2954SConrad Meyer conf = (void *)addr; 12846b6e2954SConrad Meyer memcpy(&kda_copy, conf, sizeof(kda_copy)); 12856b6e2954SConrad Meyer } 12866b6e2954SConrad Meyer /* Netdump only supports IP4 at this time. */ 12876b6e2954SConrad Meyer if (conf->kda_af != AF_INET) { 12886b6e2954SConrad Meyer error = EPROTONOSUPPORT; 12896b6e2954SConrad Meyer break; 12906b6e2954SConrad Meyer } 12916b6e2954SConrad Meyer 12926b6e2954SConrad Meyer conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0'; 12936b6e2954SConrad Meyer if (conf->kda_index == KDA_REMOVE || 12946b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_DEV || 12956b6e2954SConrad Meyer conf->kda_index == KDA_REMOVE_ALL) { 12966b6e2954SConrad Meyer if (nd_enabled || conf->kda_index == KDA_REMOVE_ALL) { 12976b6e2954SConrad Meyer error = dumper_remove(conf->kda_iface, conf); 1298b35822d9SMark Johnston if (error == 0) { 1299e5054602SMark Johnston nd_enabled = 0; 1300b35822d9SMark Johnston netdump_mbuf_drain(); 1301b35822d9SMark Johnston } 1302e5054602SMark Johnston } 1303e5054602SMark Johnston break; 1304e5054602SMark Johnston } 1305e5054602SMark Johnston 1306b35822d9SMark Johnston error = netdump_configure(conf, td); 1307e5054602SMark Johnston if (error != 0) 1308e5054602SMark Johnston break; 1309e5054602SMark Johnston 13106b6e2954SConrad Meyer if (conf->kda_encryption != KERNELDUMP_ENC_NONE) { 13116b6e2954SConrad Meyer if (conf->kda_encryptedkeysize <= 0 || 13126b6e2954SConrad Meyer conf->kda_encryptedkeysize > 13136b6e2954SConrad Meyer KERNELDUMP_ENCKEY_MAX_SIZE) { 13146b6e2954SConrad Meyer error = EINVAL; 13156b6e2954SConrad Meyer break; 13166b6e2954SConrad Meyer } 13176b6e2954SConrad Meyer encryptedkey = malloc(conf->kda_encryptedkeysize, 13186b6e2954SConrad Meyer M_TEMP, M_WAITOK); 13196b6e2954SConrad Meyer error = copyin(conf->kda_encryptedkey, encryptedkey, 13206b6e2954SConrad Meyer conf->kda_encryptedkeysize); 1321e5054602SMark Johnston if (error != 0) { 1322e5054602SMark Johnston free(encryptedkey, M_TEMP); 13236b6e2954SConrad Meyer break; 1324e5054602SMark Johnston } 13256b6e2954SConrad Meyer 13266b6e2954SConrad Meyer conf->kda_encryptedkey = encryptedkey; 1327e5054602SMark Johnston } 1328e5054602SMark Johnston 13299f78e2b8SMark Johnston memset(&dumper, 0, sizeof(dumper)); 1330e5054602SMark Johnston dumper.dumper_start = netdump_start; 1331e5054602SMark Johnston dumper.dumper_hdr = netdump_write_headers; 1332e5054602SMark Johnston dumper.dumper = netdump_dumper; 1333e5054602SMark Johnston dumper.priv = NULL; 1334e5054602SMark Johnston dumper.blocksize = NETDUMP_DATASIZE; 1335e5054602SMark Johnston dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; 1336e5054602SMark Johnston dumper.mediaoffset = 0; 1337e5054602SMark Johnston dumper.mediasize = 0; 1338e5054602SMark Johnston 13396b6e2954SConrad Meyer error = dumper_insert(&dumper, conf->kda_iface, conf); 1340e5054602SMark Johnston if (encryptedkey != NULL) { 13416b6e2954SConrad Meyer explicit_bzero(encryptedkey, 13426b6e2954SConrad Meyer conf->kda_encryptedkeysize); 1343e5054602SMark Johnston free(encryptedkey, M_TEMP); 1344e5054602SMark Johnston } 1345b35822d9SMark Johnston if (error != 0) { 1346e5054602SMark Johnston nd_enabled = 0; 1347b35822d9SMark Johnston netdump_mbuf_drain(); 1348b35822d9SMark Johnston } 1349e5054602SMark Johnston break; 1350e5054602SMark Johnston default: 13516b6e2954SConrad Meyer error = ENOTTY; 1352e5054602SMark Johnston break; 1353e5054602SMark Johnston } 13546b6e2954SConrad Meyer explicit_bzero(&kda_copy, sizeof(kda_copy)); 13556b6e2954SConrad Meyer if (conf != NULL) 13566b6e2954SConrad Meyer explicit_bzero(conf, sizeof(*conf)); 1357e5054602SMark Johnston return (error); 1358e5054602SMark Johnston } 1359e5054602SMark Johnston 1360e5054602SMark Johnston /* 1361e5054602SMark Johnston * Called upon system init or kld load. Initializes the netdump parameters to 1362e5054602SMark Johnston * sane defaults (locates the first available NIC and uses the first IPv4 IP on 1363e5054602SMark Johnston * that card as the client IP). Leaves the server IP unconfigured. 1364e5054602SMark Johnston * 1365e5054602SMark Johnston * Parameters: 1366e5054602SMark Johnston * mod, Unused. 1367e5054602SMark Johnston * what, The module event type. 1368e5054602SMark Johnston * priv, Unused. 1369e5054602SMark Johnston * 1370e5054602SMark Johnston * Returns: 1371e5054602SMark Johnston * int, An errno value if an error occured, 0 otherwise. 1372e5054602SMark Johnston */ 1373e5054602SMark Johnston static int 1374e5054602SMark Johnston netdump_modevent(module_t mod __unused, int what, void *priv __unused) 1375e5054602SMark Johnston { 13766b6e2954SConrad Meyer struct diocskerneldump_arg conf; 1377e5054602SMark Johnston char *arg; 1378e5054602SMark Johnston int error; 1379e5054602SMark Johnston 1380e5054602SMark Johnston error = 0; 1381e5054602SMark Johnston switch (what) { 1382e5054602SMark Johnston case MOD_LOAD: 1383e5054602SMark Johnston error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev, 1384e5054602SMark Johnston &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump"); 1385e5054602SMark Johnston if (error != 0) 1386e5054602SMark Johnston return (error); 1387e5054602SMark Johnston 1388e5054602SMark Johnston if ((arg = kern_getenv("net.dump.iface")) != NULL) { 13896b6e2954SConrad Meyer strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface)); 1390e5054602SMark Johnston freeenv(arg); 1391e5054602SMark Johnston 1392e5054602SMark Johnston if ((arg = kern_getenv("net.dump.server")) != NULL) { 13936b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1394e5054602SMark Johnston freeenv(arg); 1395e5054602SMark Johnston } 1396e5054602SMark Johnston if ((arg = kern_getenv("net.dump.client")) != NULL) { 13976b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1398e5054602SMark Johnston freeenv(arg); 1399e5054602SMark Johnston } 1400e5054602SMark Johnston if ((arg = kern_getenv("net.dump.gateway")) != NULL) { 14016b6e2954SConrad Meyer inet_aton(arg, &conf.kda_server.in4); 1402e5054602SMark Johnston freeenv(arg); 1403e5054602SMark Johnston } 14046b6e2954SConrad Meyer conf.kda_af = AF_INET; 1405e5054602SMark Johnston 1406e5054602SMark Johnston /* Ignore errors; we print a message to the console. */ 1407b35822d9SMark Johnston (void)netdump_configure(&conf, curthread); 1408e5054602SMark Johnston } 1409e5054602SMark Johnston break; 1410e5054602SMark Johnston case MOD_UNLOAD: 1411e5054602SMark Johnston if (nd_enabled) { 14126b6e2954SConrad Meyer struct diocskerneldump_arg kda; 14136b6e2954SConrad Meyer 1414e5054602SMark Johnston printf("netdump: disabling dump device for unload\n"); 14156b6e2954SConrad Meyer 14166b6e2954SConrad Meyer bzero(&kda, sizeof(kda)); 14176b6e2954SConrad Meyer kda.kda_index = KDA_REMOVE_DEV; 1418*6144b50fSConrad Meyer (void)dumper_remove(nd_conf.ndc_iface, &kda); 14196b6e2954SConrad Meyer 14206b6e2954SConrad Meyer netdump_mbuf_drain(); 1421e5054602SMark Johnston nd_enabled = 0; 1422e5054602SMark Johnston } 14236b6e2954SConrad Meyer destroy_dev(netdump_cdev); 1424e5054602SMark Johnston break; 1425e5054602SMark Johnston default: 1426e5054602SMark Johnston error = EOPNOTSUPP; 1427e5054602SMark Johnston break; 1428e5054602SMark Johnston } 1429e5054602SMark Johnston return (error); 1430e5054602SMark Johnston } 1431e5054602SMark Johnston 1432e5054602SMark Johnston static moduledata_t netdump_mod = { 1433e5054602SMark Johnston "netdump", 1434e5054602SMark Johnston netdump_modevent, 1435e5054602SMark Johnston NULL, 1436e5054602SMark Johnston }; 1437e5054602SMark Johnston 1438e5054602SMark Johnston MODULE_VERSION(netdump, 1); 1439e5054602SMark Johnston DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 1440