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