1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Isilon Systems, LLC. 5 * Copyright (c) 2005-2014 Sandvine Incorporated 6 * Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 /* 34 * Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram 35 * transport while a machine is in a debug state. (N-1 CPUs stopped, 36 * interrupts disabled, may or may not be in a panic(9) state.) Only one 37 * stream may be active at a time. A dedicated server must be running to 38 * accept connections. 39 */ 40 41 #pragma once 42 43 #include <sys/types.h> 44 #include <netinet/in.h> 45 46 /* 47 * Debugnet protocol details. 48 */ 49 #define DEBUGNET_HERALD 1 /* Connection handshake. */ 50 #define DEBUGNET_FINISHED 2 /* Close the connection. */ 51 #define DEBUGNET_DATA 3 /* Contains data. */ 52 53 struct debugnet_msg_hdr { 54 uint32_t mh_type; /* Debugnet message type. */ 55 uint32_t mh_seqno; /* Match acks with msgs. */ 56 uint64_t mh_offset; /* Offset in fragment. */ 57 uint32_t mh_len; /* Attached data (bytes). */ 58 uint32_t mh_aux2; /* Consumer-specific. */ 59 } __packed; 60 61 struct debugnet_ack { 62 uint32_t da_seqno; /* Match acks with msgs. */ 63 } __packed; 64 65 #define DEBUGNET_MAX_IN_FLIGHT 64 66 67 #ifdef _KERNEL 68 /* 69 * Hook API for network drivers. 70 */ 71 enum debugnet_ev { 72 DEBUGNET_START, 73 DEBUGNET_END, 74 }; 75 76 struct ifnet; 77 struct mbuf; 78 typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize); 79 typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev); 80 typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *); 81 typedef int debugnet_poll_t(struct ifnet *, int); 82 83 struct debugnet_methods { 84 debugnet_init_t *dn_init; 85 debugnet_event_t *dn_event; 86 debugnet_transmit_t *dn_transmit; 87 debugnet_poll_t *dn_poll; 88 }; 89 90 #define DEBUGNET_SUPPORTED_NIC(ifp) \ 91 ((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER) 92 93 struct debugnet_pcb; /* opaque */ 94 95 /* 96 * Debugnet consumer API. 97 */ 98 struct debugnet_conn_params { 99 struct ifnet *dc_ifp; 100 in_addr_t dc_client; 101 in_addr_t dc_server; 102 in_addr_t dc_gateway; 103 104 uint16_t dc_herald_port; 105 uint16_t dc_client_port; 106 107 const void *dc_herald_data; 108 uint32_t dc_herald_datalen; 109 110 /* 111 * Consistent with debugnet_send(), aux parameters to debugnet 112 * functions are provided host-endian (but converted to 113 * network endian on the wire). 114 */ 115 uint32_t dc_herald_aux2; 116 uint64_t dc_herald_offset; 117 118 /* 119 * If NULL, debugnet is a unidirectional channel from panic machine to 120 * remote server (like netdump). 121 * 122 * If handler is non-NULL, packets received on the client port that are 123 * not just tx acks are forwarded to the provided handler. 124 * 125 * The mbuf chain will have all non-debugnet framing headers removed 126 * (ethernet, inet, udp). It will start with a debugnet_msg_hdr, of 127 * which the header is guaranteed to be contiguous. If m_pullup is 128 * used, the supplied in-out mbuf pointer should be updated 129 * appropriately. 130 * 131 * If the handler frees the mbuf chain, it should set the mbuf pointer 132 * to NULL. Otherwise, the debugnet input framework will free the 133 * chain. 134 * 135 * The handler should ACK receieved packets with debugnet_ack_output. 136 */ 137 int (*dc_rx_handler)(struct mbuf *); 138 139 /* Cleanup signal for bidirectional protocols. */ 140 void (*dc_finish_handler)(void); 141 }; 142 143 /* 144 * Open a stream to the specified server's herald port. 145 * 146 * If all goes well, the server will send ACK from a different port to our ack 147 * port. This allows servers to somewhat gracefully handle multiple debugnet 148 * clients. (Clients are limited to single connections.) 149 * 150 * Returns zero on success, or errno. 151 */ 152 int debugnet_connect(const struct debugnet_conn_params *, 153 struct debugnet_pcb **pcb_out); 154 155 /* 156 * Free a debugnet stream that was previously successfully opened. 157 * 158 * No attempt is made to cleanly terminate communication with the remote 159 * server. Consumers should first send an empty DEBUGNET_FINISHED message, or 160 * otherwise let the remote know they are signing off. 161 */ 162 void debugnet_free(struct debugnet_pcb *); 163 164 /* 165 * Send a message, with common debugnet_msg_hdr header, to the connected remote 166 * server. 167 * 168 * - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other 169 * protocol-specific type). 170 * - Data and datalen describe the attached data; datalen may be zero. 171 * - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero. 172 * Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and 173 * mh_aux2 will have the value of auxdata->dp_aux2. 174 * 175 * Returns zero on success, or an errno on failure. 176 */ 177 struct debugnet_proto_aux { 178 uint64_t dp_offset_start; 179 uint32_t dp_aux2; 180 }; 181 int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data, 182 uint32_t datalen, const struct debugnet_proto_aux *auxdata); 183 184 /* 185 * A simple wrapper around the above when no data or auxdata is needed. 186 */ 187 static inline int 188 debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype) 189 { 190 return (debugnet_send(pcb, mhtype, NULL, 0, NULL)); 191 } 192 193 /* 194 * Full-duplex RX should ACK received messages. 195 */ 196 int debugnet_ack_output(struct debugnet_pcb *, uint32_t seqno /*net endian*/); 197 198 /* 199 * Check and/or wait for further packets. 200 */ 201 void debugnet_network_poll(struct debugnet_pcb *); 202 203 /* 204 * PCB accessors. 205 */ 206 207 /* 208 * Get the 48-bit MAC address of the discovered next hop (gateway, or 209 * destination server if it is on the same segment. 210 */ 211 const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *); 212 213 /* 214 * Get the connected server address. 215 */ 216 const in_addr_t *debugnet_get_server_addr(const struct debugnet_pcb *); 217 218 /* 219 * Get the connected server port. 220 */ 221 const uint16_t debugnet_get_server_port(const struct debugnet_pcb *); 222 223 /* 224 * Callbacks from core mbuf code. 225 */ 226 void debugnet_any_ifnet_update(struct ifnet *); 227 228 /* 229 * DDB parsing helper for common debugnet options. 230 * 231 * -s <server> [-g <gateway -c <localip> -i <interface>] 232 * 233 * Order is not significant. Interface is an online interface that supports 234 * debugnet and can route to the debugnet server. The other parameters are all 235 * IP addresses. Only the server parameter is required. The others are 236 * inferred automatically from the routing table, if not explicitly provided. 237 * 238 * Provides basic '-h' using provided 'cmd' string. 239 * 240 * Returns zero on success, or errno. 241 */ 242 struct debugnet_ddb_config { 243 struct ifnet *dd_ifp; /* not ref'd */ 244 in_addr_t dd_client; 245 in_addr_t dd_server; 246 in_addr_t dd_gateway; 247 bool dd_has_client : 1; 248 bool dd_has_gateway : 1; 249 }; 250 int debugnet_parse_ddb_cmd(const char *cmd, 251 struct debugnet_ddb_config *result); 252 253 /* Expose sysctl variables for netdump(4) to alias. */ 254 extern int debugnet_npolls; 255 extern int debugnet_nretries; 256 extern int debugnet_arp_nretries; 257 258 /* 259 * Conditionally-defined macros for device drivers so we can avoid ifdef 260 * wrappers in every single implementation. 261 */ 262 #ifdef DEBUGNET 263 #define DEBUGNET_DEFINE(driver) \ 264 static debugnet_init_t driver##_debugnet_init; \ 265 static debugnet_event_t driver##_debugnet_event; \ 266 static debugnet_transmit_t driver##_debugnet_transmit; \ 267 static debugnet_poll_t driver##_debugnet_poll; \ 268 \ 269 static struct debugnet_methods driver##_debugnet_methods = { \ 270 .dn_init = driver##_debugnet_init, \ 271 .dn_event = driver##_debugnet_event, \ 272 .dn_transmit = driver##_debugnet_transmit, \ 273 .dn_poll = driver##_debugnet_poll, \ 274 } 275 276 #define DEBUGNET_NOTIFY_MTU(ifp) debugnet_any_ifnet_update(ifp) 277 278 #define DEBUGNET_SET(ifp, driver) \ 279 if_setdebugnet_methods((ifp), &driver##_debugnet_methods) 280 281 #else /* !DEBUGNET || !INET */ 282 283 #define DEBUGNET_DEFINE(driver) 284 #define DEBUGNET_NOTIFY_MTU(ifp) 285 #define DEBUGNET_SET(ifp, driver) 286 287 #endif /* DEBUGNET && INET */ 288 #endif /* _KERNEL */ 289