17790c8c1SConrad Meyer /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
37790c8c1SConrad Meyer *
47790c8c1SConrad Meyer * Copyright (c) 2019 Isilon Systems, LLC.
57790c8c1SConrad Meyer * Copyright (c) 2005-2014 Sandvine Incorporated
67790c8c1SConrad Meyer * Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu>
77790c8c1SConrad Meyer * All rights reserved.
87790c8c1SConrad Meyer *
97790c8c1SConrad Meyer * Redistribution and use in source and binary forms, with or without
107790c8c1SConrad Meyer * modification, are permitted provided that the following conditions
117790c8c1SConrad Meyer * are met:
127790c8c1SConrad Meyer * 1. Redistributions of source code must retain the above copyright
137790c8c1SConrad Meyer * notice, this list of conditions and the following disclaimer.
147790c8c1SConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright
157790c8c1SConrad Meyer * notice, this list of conditions and the following disclaimer in the
167790c8c1SConrad Meyer * documentation and/or other materials provided with the distribution.
177790c8c1SConrad Meyer *
187790c8c1SConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
197790c8c1SConrad Meyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
207790c8c1SConrad Meyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217790c8c1SConrad Meyer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
227790c8c1SConrad Meyer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237790c8c1SConrad Meyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247790c8c1SConrad Meyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257790c8c1SConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267790c8c1SConrad Meyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277790c8c1SConrad Meyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287790c8c1SConrad Meyer * SUCH DAMAGE.
297790c8c1SConrad Meyer */
307790c8c1SConrad Meyer
317790c8c1SConrad Meyer /*
327790c8c1SConrad Meyer * Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram
337790c8c1SConrad Meyer * transport while a machine is in a debug state. (N-1 CPUs stopped,
347790c8c1SConrad Meyer * interrupts disabled, may or may not be in a panic(9) state.) Only one
357790c8c1SConrad Meyer * stream may be active at a time. A dedicated server must be running to
367790c8c1SConrad Meyer * accept connections.
377790c8c1SConrad Meyer */
387790c8c1SConrad Meyer
397790c8c1SConrad Meyer #pragma once
407790c8c1SConrad Meyer
417790c8c1SConrad Meyer #include <sys/types.h>
427790c8c1SConrad Meyer #include <netinet/in.h>
437790c8c1SConrad Meyer
447790c8c1SConrad Meyer /*
457790c8c1SConrad Meyer * Debugnet protocol details.
467790c8c1SConrad Meyer */
477790c8c1SConrad Meyer #define DEBUGNET_HERALD 1 /* Connection handshake. */
487790c8c1SConrad Meyer #define DEBUGNET_FINISHED 2 /* Close the connection. */
497790c8c1SConrad Meyer #define DEBUGNET_DATA 3 /* Contains data. */
507790c8c1SConrad Meyer
517790c8c1SConrad Meyer struct debugnet_msg_hdr {
527790c8c1SConrad Meyer uint32_t mh_type; /* Debugnet message type. */
537790c8c1SConrad Meyer uint32_t mh_seqno; /* Match acks with msgs. */
547790c8c1SConrad Meyer uint64_t mh_offset; /* Offset in fragment. */
557790c8c1SConrad Meyer uint32_t mh_len; /* Attached data (bytes). */
567790c8c1SConrad Meyer uint32_t mh_aux2; /* Consumer-specific. */
577790c8c1SConrad Meyer } __packed;
587790c8c1SConrad Meyer
597790c8c1SConrad Meyer struct debugnet_ack {
607790c8c1SConrad Meyer uint32_t da_seqno; /* Match acks with msgs. */
617790c8c1SConrad Meyer } __packed;
627790c8c1SConrad Meyer
637790c8c1SConrad Meyer #define DEBUGNET_MAX_IN_FLIGHT 64
647790c8c1SConrad Meyer
657790c8c1SConrad Meyer #ifdef _KERNEL
667790c8c1SConrad Meyer /*
677790c8c1SConrad Meyer * Hook API for network drivers.
687790c8c1SConrad Meyer */
697790c8c1SConrad Meyer enum debugnet_ev {
707790c8c1SConrad Meyer DEBUGNET_START,
717790c8c1SConrad Meyer DEBUGNET_END,
727790c8c1SConrad Meyer };
737790c8c1SConrad Meyer
747790c8c1SConrad Meyer struct ifnet;
757790c8c1SConrad Meyer struct mbuf;
767790c8c1SConrad Meyer typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize);
777790c8c1SConrad Meyer typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev);
787790c8c1SConrad Meyer typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *);
797790c8c1SConrad Meyer typedef int debugnet_poll_t(struct ifnet *, int);
807790c8c1SConrad Meyer
817790c8c1SConrad Meyer struct debugnet_methods {
827790c8c1SConrad Meyer debugnet_init_t *dn_init;
837790c8c1SConrad Meyer debugnet_event_t *dn_event;
847790c8c1SConrad Meyer debugnet_transmit_t *dn_transmit;
857790c8c1SConrad Meyer debugnet_poll_t *dn_poll;
867790c8c1SConrad Meyer };
877790c8c1SConrad Meyer
887790c8c1SConrad Meyer #define DEBUGNET_SUPPORTED_NIC(ifp) \
897790c8c1SConrad Meyer ((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER)
907790c8c1SConrad Meyer
91e9c69625SConrad Meyer struct debugnet_pcb; /* opaque */
92e9c69625SConrad Meyer
937790c8c1SConrad Meyer /*
947790c8c1SConrad Meyer * Debugnet consumer API.
957790c8c1SConrad Meyer */
967790c8c1SConrad Meyer struct debugnet_conn_params {
977790c8c1SConrad Meyer struct ifnet *dc_ifp;
987790c8c1SConrad Meyer in_addr_t dc_client;
997790c8c1SConrad Meyer in_addr_t dc_server;
1007790c8c1SConrad Meyer in_addr_t dc_gateway;
1017790c8c1SConrad Meyer
1027790c8c1SConrad Meyer uint16_t dc_herald_port;
103e9c69625SConrad Meyer uint16_t dc_client_port;
1047790c8c1SConrad Meyer
1057790c8c1SConrad Meyer const void *dc_herald_data;
1067790c8c1SConrad Meyer uint32_t dc_herald_datalen;
1077790c8c1SConrad Meyer
108e9c69625SConrad Meyer /*
109b2b1bb04SGordon Bergling * Consistent with debugnet_send(), aux parameters to debugnet
110dda17b36SConrad Meyer * functions are provided host-endian (but converted to
111dda17b36SConrad Meyer * network endian on the wire).
112dda17b36SConrad Meyer */
113dda17b36SConrad Meyer uint32_t dc_herald_aux2;
114dda17b36SConrad Meyer uint64_t dc_herald_offset;
115dda17b36SConrad Meyer
116dda17b36SConrad Meyer /*
117e9c69625SConrad Meyer * If NULL, debugnet is a unidirectional channel from panic machine to
118e9c69625SConrad Meyer * remote server (like netdump).
119e9c69625SConrad Meyer *
120e9c69625SConrad Meyer * If handler is non-NULL, packets received on the client port that are
121e9c69625SConrad Meyer * not just tx acks are forwarded to the provided handler.
122e9c69625SConrad Meyer *
123e9c69625SConrad Meyer * The mbuf chain will have all non-debugnet framing headers removed
124e9c69625SConrad Meyer * (ethernet, inet, udp). It will start with a debugnet_msg_hdr, of
125e9c69625SConrad Meyer * which the header is guaranteed to be contiguous. If m_pullup is
126e9c69625SConrad Meyer * used, the supplied in-out mbuf pointer should be updated
127e9c69625SConrad Meyer * appropriately.
128e9c69625SConrad Meyer *
129e9c69625SConrad Meyer * If the handler frees the mbuf chain, it should set the mbuf pointer
130e9c69625SConrad Meyer * to NULL. Otherwise, the debugnet input framework will free the
131e9c69625SConrad Meyer * chain.
132dda17b36SConrad Meyer *
133dda17b36SConrad Meyer * The handler should ACK receieved packets with debugnet_ack_output.
134e9c69625SConrad Meyer */
135*b498331bSJohn Reimer int (*dc_rx_handler)(struct mbuf *);
136*b498331bSJohn Reimer
137*b498331bSJohn Reimer /* Cleanup signal for bidirectional protocols. */
138*b498331bSJohn Reimer void (*dc_finish_handler)(void);
139e9c69625SConrad Meyer };
1407790c8c1SConrad Meyer
1417790c8c1SConrad Meyer /*
142dda17b36SConrad Meyer * Open a stream to the specified server's herald port.
1437790c8c1SConrad Meyer *
1447790c8c1SConrad Meyer * If all goes well, the server will send ACK from a different port to our ack
1457790c8c1SConrad Meyer * port. This allows servers to somewhat gracefully handle multiple debugnet
1467790c8c1SConrad Meyer * clients. (Clients are limited to single connections.)
1477790c8c1SConrad Meyer *
1487790c8c1SConrad Meyer * Returns zero on success, or errno.
1497790c8c1SConrad Meyer */
1507790c8c1SConrad Meyer int debugnet_connect(const struct debugnet_conn_params *,
1517790c8c1SConrad Meyer struct debugnet_pcb **pcb_out);
1527790c8c1SConrad Meyer
1537790c8c1SConrad Meyer /*
1547790c8c1SConrad Meyer * Free a debugnet stream that was previously successfully opened.
1557790c8c1SConrad Meyer *
1567790c8c1SConrad Meyer * No attempt is made to cleanly terminate communication with the remote
1577790c8c1SConrad Meyer * server. Consumers should first send an empty DEBUGNET_FINISHED message, or
1587790c8c1SConrad Meyer * otherwise let the remote know they are signing off.
1597790c8c1SConrad Meyer */
1607790c8c1SConrad Meyer void debugnet_free(struct debugnet_pcb *);
1617790c8c1SConrad Meyer
1627790c8c1SConrad Meyer /*
1637790c8c1SConrad Meyer * Send a message, with common debugnet_msg_hdr header, to the connected remote
1647790c8c1SConrad Meyer * server.
1657790c8c1SConrad Meyer *
1667790c8c1SConrad Meyer * - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other
1677790c8c1SConrad Meyer * protocol-specific type).
1687790c8c1SConrad Meyer * - Data and datalen describe the attached data; datalen may be zero.
1697790c8c1SConrad Meyer * - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero.
1707790c8c1SConrad Meyer * Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and
1717790c8c1SConrad Meyer * mh_aux2 will have the value of auxdata->dp_aux2.
1727790c8c1SConrad Meyer *
1737790c8c1SConrad Meyer * Returns zero on success, or an errno on failure.
1747790c8c1SConrad Meyer */
1757790c8c1SConrad Meyer struct debugnet_proto_aux {
1767790c8c1SConrad Meyer uint64_t dp_offset_start;
1777790c8c1SConrad Meyer uint32_t dp_aux2;
1787790c8c1SConrad Meyer };
1797790c8c1SConrad Meyer int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data,
1807790c8c1SConrad Meyer uint32_t datalen, const struct debugnet_proto_aux *auxdata);
1817790c8c1SConrad Meyer
1827790c8c1SConrad Meyer /*
1837790c8c1SConrad Meyer * A simple wrapper around the above when no data or auxdata is needed.
1847790c8c1SConrad Meyer */
1857790c8c1SConrad Meyer static inline int
debugnet_sendempty(struct debugnet_pcb * pcb,uint32_t mhtype)1867790c8c1SConrad Meyer debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype)
1877790c8c1SConrad Meyer {
1887790c8c1SConrad Meyer return (debugnet_send(pcb, mhtype, NULL, 0, NULL));
1897790c8c1SConrad Meyer }
1907790c8c1SConrad Meyer
1917790c8c1SConrad Meyer /*
192dda17b36SConrad Meyer * Full-duplex RX should ACK received messages.
193dda17b36SConrad Meyer */
194dda17b36SConrad Meyer int debugnet_ack_output(struct debugnet_pcb *, uint32_t seqno /*net endian*/);
195dda17b36SConrad Meyer
196dda17b36SConrad Meyer /*
197dda17b36SConrad Meyer * Check and/or wait for further packets.
198dda17b36SConrad Meyer */
199dda17b36SConrad Meyer void debugnet_network_poll(struct debugnet_pcb *);
200dda17b36SConrad Meyer
201dda17b36SConrad Meyer /*
2027790c8c1SConrad Meyer * PCB accessors.
2037790c8c1SConrad Meyer */
2047790c8c1SConrad Meyer
2057790c8c1SConrad Meyer /*
2067790c8c1SConrad Meyer * Get the 48-bit MAC address of the discovered next hop (gateway, or
2077790c8c1SConrad Meyer * destination server if it is on the same segment.
2087790c8c1SConrad Meyer */
2097790c8c1SConrad Meyer const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *);
2107790c8c1SConrad Meyer
2117790c8c1SConrad Meyer /*
212*b498331bSJohn Reimer * Get the connected server address.
213*b498331bSJohn Reimer */
214*b498331bSJohn Reimer const in_addr_t *debugnet_get_server_addr(const struct debugnet_pcb *);
215*b498331bSJohn Reimer
216*b498331bSJohn Reimer /*
217*b498331bSJohn Reimer * Get the connected server port.
218*b498331bSJohn Reimer */
219*b498331bSJohn Reimer const uint16_t debugnet_get_server_port(const struct debugnet_pcb *);
220*b498331bSJohn Reimer
221*b498331bSJohn Reimer /*
2227790c8c1SConrad Meyer * Callbacks from core mbuf code.
2237790c8c1SConrad Meyer */
2247790c8c1SConrad Meyer void debugnet_any_ifnet_update(struct ifnet *);
2257790c8c1SConrad Meyer
2268270d35eSConrad Meyer /*
2278270d35eSConrad Meyer * DDB parsing helper for common debugnet options.
2288270d35eSConrad Meyer *
229fde2cf65SConrad Meyer * -s <server> [-g <gateway -c <localip> -i <interface>]
2308270d35eSConrad Meyer *
2318270d35eSConrad Meyer * Order is not significant. Interface is an online interface that supports
2328270d35eSConrad Meyer * debugnet and can route to the debugnet server. The other parameters are all
233fde2cf65SConrad Meyer * IP addresses. Only the server parameter is required. The others are
234fde2cf65SConrad Meyer * inferred automatically from the routing table, if not explicitly provided.
2358270d35eSConrad Meyer *
2368270d35eSConrad Meyer * Provides basic '-h' using provided 'cmd' string.
2378270d35eSConrad Meyer *
2388270d35eSConrad Meyer * Returns zero on success, or errno.
2398270d35eSConrad Meyer */
2408270d35eSConrad Meyer struct debugnet_ddb_config {
2418270d35eSConrad Meyer struct ifnet *dd_ifp; /* not ref'd */
2428270d35eSConrad Meyer in_addr_t dd_client;
2438270d35eSConrad Meyer in_addr_t dd_server;
2448270d35eSConrad Meyer in_addr_t dd_gateway;
245fde2cf65SConrad Meyer bool dd_has_client : 1;
2468270d35eSConrad Meyer bool dd_has_gateway : 1;
2478270d35eSConrad Meyer };
2488270d35eSConrad Meyer int debugnet_parse_ddb_cmd(const char *cmd,
2498270d35eSConrad Meyer struct debugnet_ddb_config *result);
2508270d35eSConrad Meyer
2517790c8c1SConrad Meyer /* Expose sysctl variables for netdump(4) to alias. */
2527790c8c1SConrad Meyer extern int debugnet_npolls;
2537790c8c1SConrad Meyer extern int debugnet_nretries;
2547790c8c1SConrad Meyer extern int debugnet_arp_nretries;
2557790c8c1SConrad Meyer
2567790c8c1SConrad Meyer /*
2577790c8c1SConrad Meyer * Conditionally-defined macros for device drivers so we can avoid ifdef
2587790c8c1SConrad Meyer * wrappers in every single implementation.
2597790c8c1SConrad Meyer */
2607790c8c1SConrad Meyer #ifdef DEBUGNET
2617790c8c1SConrad Meyer #define DEBUGNET_DEFINE(driver) \
2627790c8c1SConrad Meyer static debugnet_init_t driver##_debugnet_init; \
2637790c8c1SConrad Meyer static debugnet_event_t driver##_debugnet_event; \
2647790c8c1SConrad Meyer static debugnet_transmit_t driver##_debugnet_transmit; \
2657790c8c1SConrad Meyer static debugnet_poll_t driver##_debugnet_poll; \
2667790c8c1SConrad Meyer \
2677790c8c1SConrad Meyer static struct debugnet_methods driver##_debugnet_methods = { \
2687790c8c1SConrad Meyer .dn_init = driver##_debugnet_init, \
2697790c8c1SConrad Meyer .dn_event = driver##_debugnet_event, \
2707790c8c1SConrad Meyer .dn_transmit = driver##_debugnet_transmit, \
2717790c8c1SConrad Meyer .dn_poll = driver##_debugnet_poll, \
2727790c8c1SConrad Meyer }
2737790c8c1SConrad Meyer
2747790c8c1SConrad Meyer #define DEBUGNET_NOTIFY_MTU(ifp) debugnet_any_ifnet_update(ifp)
2757790c8c1SConrad Meyer
2767790c8c1SConrad Meyer #define DEBUGNET_SET(ifp, driver) \
277053a24d1SJustin Hibbits if_setdebugnet_methods((ifp), &driver##_debugnet_methods)
2787790c8c1SConrad Meyer
2797790c8c1SConrad Meyer #else /* !DEBUGNET || !INET */
2807790c8c1SConrad Meyer
2817790c8c1SConrad Meyer #define DEBUGNET_DEFINE(driver)
2827790c8c1SConrad Meyer #define DEBUGNET_NOTIFY_MTU(ifp)
2837790c8c1SConrad Meyer #define DEBUGNET_SET(ifp, driver)
2847790c8c1SConrad Meyer
2857790c8c1SConrad Meyer #endif /* DEBUGNET && INET */
2867790c8c1SConrad Meyer #endif /* _KERNEL */
287