/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2019 Isilon Systems, LLC. * Copyright (c) 2005-2014 Sandvine Incorporated * Copyright (c) 2000 Darrell Anderson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram * transport while a machine is in a debug state. (N-1 CPUs stopped, * interrupts disabled, may or may not be in a panic(9) state.) Only one * stream may be active at a time. A dedicated server must be running to * accept connections. */ #pragma once #include #include /* * Debugnet protocol details. */ #define DEBUGNET_HERALD 1 /* Connection handshake. */ #define DEBUGNET_FINISHED 2 /* Close the connection. */ #define DEBUGNET_DATA 3 /* Contains data. */ struct debugnet_msg_hdr { uint32_t mh_type; /* Debugnet message type. */ uint32_t mh_seqno; /* Match acks with msgs. */ uint64_t mh_offset; /* Offset in fragment. */ uint32_t mh_len; /* Attached data (bytes). */ uint32_t mh_aux2; /* Consumer-specific. */ } __packed; struct debugnet_ack { uint32_t da_seqno; /* Match acks with msgs. */ } __packed; #define DEBUGNET_MAX_IN_FLIGHT 64 #ifdef _KERNEL /* * Hook API for network drivers. */ enum debugnet_ev { DEBUGNET_START, DEBUGNET_END, }; struct ifnet; struct mbuf; typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize); typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev); typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *); typedef int debugnet_poll_t(struct ifnet *, int); struct debugnet_methods { debugnet_init_t *dn_init; debugnet_event_t *dn_event; debugnet_transmit_t *dn_transmit; debugnet_poll_t *dn_poll; }; #define DEBUGNET_SUPPORTED_NIC(ifp) \ ((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER) struct debugnet_pcb; /* opaque */ /* * Debugnet consumer API. */ struct debugnet_conn_params { struct ifnet *dc_ifp; in_addr_t dc_client; in_addr_t dc_server; in_addr_t dc_gateway; uint16_t dc_herald_port; uint16_t dc_client_port; const void *dc_herald_data; uint32_t dc_herald_datalen; /* * Consistent with debugnet_send(), aux paramaters to debugnet * functions are provided host-endian (but converted to * network endian on the wire). */ uint32_t dc_herald_aux2; uint64_t dc_herald_offset; /* * If NULL, debugnet is a unidirectional channel from panic machine to * remote server (like netdump). * * If handler is non-NULL, packets received on the client port that are * not just tx acks are forwarded to the provided handler. * * The mbuf chain will have all non-debugnet framing headers removed * (ethernet, inet, udp). It will start with a debugnet_msg_hdr, of * which the header is guaranteed to be contiguous. If m_pullup is * used, the supplied in-out mbuf pointer should be updated * appropriately. * * If the handler frees the mbuf chain, it should set the mbuf pointer * to NULL. Otherwise, the debugnet input framework will free the * chain. * * The handler should ACK receieved packets with debugnet_ack_output. */ void (*dc_rx_handler)(struct debugnet_pcb *, struct mbuf **); }; /* * Open a stream to the specified server's herald port. * * If all goes well, the server will send ACK from a different port to our ack * port. This allows servers to somewhat gracefully handle multiple debugnet * clients. (Clients are limited to single connections.) * * Returns zero on success, or errno. */ int debugnet_connect(const struct debugnet_conn_params *, struct debugnet_pcb **pcb_out); /* * Free a debugnet stream that was previously successfully opened. * * No attempt is made to cleanly terminate communication with the remote * server. Consumers should first send an empty DEBUGNET_FINISHED message, or * otherwise let the remote know they are signing off. */ void debugnet_free(struct debugnet_pcb *); /* * Send a message, with common debugnet_msg_hdr header, to the connected remote * server. * * - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other * protocol-specific type). * - Data and datalen describe the attached data; datalen may be zero. * - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero. * Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and * mh_aux2 will have the value of auxdata->dp_aux2. * * Returns zero on success, or an errno on failure. */ struct debugnet_proto_aux { uint64_t dp_offset_start; uint32_t dp_aux2; }; int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data, uint32_t datalen, const struct debugnet_proto_aux *auxdata); /* * A simple wrapper around the above when no data or auxdata is needed. */ static inline int debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype) { return (debugnet_send(pcb, mhtype, NULL, 0, NULL)); } /* * Full-duplex RX should ACK received messages. */ int debugnet_ack_output(struct debugnet_pcb *, uint32_t seqno /*net endian*/); /* * Check and/or wait for further packets. */ void debugnet_network_poll(struct debugnet_pcb *); /* * PCB accessors. */ /* * Get the 48-bit MAC address of the discovered next hop (gateway, or * destination server if it is on the same segment. */ const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *); /* * Callbacks from core mbuf code. */ void debugnet_any_ifnet_update(struct ifnet *); /* * DDB parsing helper for common debugnet options. * * -s [-g -i ] * * Order is not significant. Interface is an online interface that supports * debugnet and can route to the debugnet server. The other parameters are all * IP addresses. Only the server parameter is required. The others are * inferred automatically from the routing table, if not explicitly provided. * * Provides basic '-h' using provided 'cmd' string. * * Returns zero on success, or errno. */ struct debugnet_ddb_config { struct ifnet *dd_ifp; /* not ref'd */ in_addr_t dd_client; in_addr_t dd_server; in_addr_t dd_gateway; bool dd_has_client : 1; bool dd_has_gateway : 1; }; int debugnet_parse_ddb_cmd(const char *cmd, struct debugnet_ddb_config *result); /* Expose sysctl variables for netdump(4) to alias. */ extern int debugnet_npolls; extern int debugnet_nretries; extern int debugnet_arp_nretries; /* * Conditionally-defined macros for device drivers so we can avoid ifdef * wrappers in every single implementation. */ #ifdef DEBUGNET #define DEBUGNET_DEFINE(driver) \ static debugnet_init_t driver##_debugnet_init; \ static debugnet_event_t driver##_debugnet_event; \ static debugnet_transmit_t driver##_debugnet_transmit; \ static debugnet_poll_t driver##_debugnet_poll; \ \ static struct debugnet_methods driver##_debugnet_methods = { \ .dn_init = driver##_debugnet_init, \ .dn_event = driver##_debugnet_event, \ .dn_transmit = driver##_debugnet_transmit, \ .dn_poll = driver##_debugnet_poll, \ } #define DEBUGNET_NOTIFY_MTU(ifp) debugnet_any_ifnet_update(ifp) #define DEBUGNET_SET(ifp, driver) \ (ifp)->if_debugnet_methods = &driver##_debugnet_methods #else /* !DEBUGNET || !INET */ #define DEBUGNET_DEFINE(driver) #define DEBUGNET_NOTIFY_MTU(ifp) #define DEBUGNET_SET(ifp, driver) #endif /* DEBUGNET && INET */ #endif /* _KERNEL */