Changeset View
Changeset View
Standalone View
Standalone View
head/sys/net/debugnet.c
Show First 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | debugnet_udp_output(struct debugnet_pcb *pcb, struct mbuf *m) | ||||
if (m == NULL) { | if (m == NULL) { | ||||
printf("%s: out of mbufs\n", __func__); | printf("%s: out of mbufs\n", __func__); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
udp = mtod(m, void *); | udp = mtod(m, void *); | ||||
udp->uh_ulen = htons(m->m_pkthdr.len); | udp->uh_ulen = htons(m->m_pkthdr.len); | ||||
/* Use this src port so that the server can connect() the socket */ | /* Use this src port so that the server can connect() the socket */ | ||||
udp->uh_sport = htons(pcb->dp_client_ack_port); | udp->uh_sport = htons(pcb->dp_client_port); | ||||
udp->uh_dport = htons(pcb->dp_server_port); | udp->uh_dport = htons(pcb->dp_server_port); | ||||
/* Computed later (protocol-dependent). */ | /* Computed later (protocol-dependent). */ | ||||
udp->uh_sum = 0; | udp->uh_sum = 0; | ||||
return (debugnet_ip_output(pcb, m)); | return (debugnet_ip_output(pcb, m)); | ||||
} | } | ||||
static int | |||||
debugnet_ack_output(struct debugnet_pcb *pcb, uint32_t seqno /* net endian */) | |||||
{ | |||||
struct debugnet_ack *dn_ack; | |||||
struct mbuf *m; | |||||
DNETDEBUG("Acking with seqno %u\n", ntohl(seqno)); | |||||
m = m_gethdr(M_NOWAIT, MT_DATA); | |||||
if (m == NULL) { | |||||
printf("%s: Out of mbufs\n", __func__); | |||||
return (ENOBUFS); | |||||
} | |||||
m->m_len = sizeof(*dn_ack); | |||||
m->m_pkthdr.len = sizeof(*dn_ack); | |||||
MH_ALIGN(m, sizeof(*dn_ack)); | |||||
dn_ack = mtod(m, void *); | |||||
dn_ack->da_seqno = seqno; | |||||
return (debugnet_udp_output(pcb, m)); | |||||
} | |||||
/* | /* | ||||
* Dummy free function for debugnet clusters. | * Dummy free function for debugnet clusters. | ||||
*/ | */ | ||||
static void | static void | ||||
debugnet_mbuf_free(struct mbuf *m __unused) | debugnet_mbuf_free(struct mbuf *m __unused) | ||||
{ | { | ||||
} | } | ||||
Show All 17 Lines | debugnet_send(struct debugnet_pcb *pcb, uint32_t type, const void *data, | ||||
uint32_t datalen, const struct debugnet_proto_aux *auxdata) | uint32_t datalen, const struct debugnet_proto_aux *auxdata) | ||||
{ | { | ||||
struct debugnet_msg_hdr *dn_msg_hdr; | struct debugnet_msg_hdr *dn_msg_hdr; | ||||
struct mbuf *m, *m2; | struct mbuf *m, *m2; | ||||
uint64_t want_acks; | uint64_t want_acks; | ||||
uint32_t i, pktlen, sent_so_far; | uint32_t i, pktlen, sent_so_far; | ||||
int retries, polls, error; | int retries, polls, error; | ||||
if (pcb->dp_state == DN_STATE_REMOTE_CLOSED) | |||||
return (ECONNRESET); | |||||
want_acks = 0; | want_acks = 0; | ||||
pcb->dp_rcvd_acks = 0; | pcb->dp_rcvd_acks = 0; | ||||
retries = 0; | retries = 0; | ||||
retransmit: | retransmit: | ||||
/* Chunks can be too big to fit in packets. */ | /* Chunks can be too big to fit in packets. */ | ||||
for (i = sent_so_far = 0; sent_so_far < datalen || | for (i = sent_so_far = 0; sent_so_far < datalen || | ||||
(i == 0 && datalen == 0); i++) { | (i == 0 && datalen == 0); i++) { | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | while (pcb->dp_rcvd_acks != want_acks) { | ||||
if (polls++ > debugnet_npolls) { | if (polls++ > debugnet_npolls) { | ||||
if (retries++ > debugnet_nretries) | if (retries++ > debugnet_nretries) | ||||
return (ETIMEDOUT); | return (ETIMEDOUT); | ||||
printf(". "); | printf(". "); | ||||
goto retransmit; | goto retransmit; | ||||
} | } | ||||
debugnet_network_poll(pcb->dp_ifp); | debugnet_network_poll(pcb->dp_ifp); | ||||
DELAY(500); | DELAY(500); | ||||
if (pcb->dp_state == DN_STATE_REMOTE_CLOSED) | |||||
return (ECONNRESET); | |||||
} | } | ||||
pcb->dp_seqno += i; | pcb->dp_seqno += i; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Network input primitives. | * Network input primitives. | ||||
*/ | */ | ||||
/* | |||||
* Just introspect the header enough to fire off a seqno ack and validate | |||||
* length fits. | |||||
*/ | |||||
static void | static void | ||||
debugnet_handle_rx_msg(struct debugnet_pcb *pcb, struct mbuf **mb) | |||||
{ | |||||
const struct debugnet_msg_hdr *dnh; | |||||
struct mbuf *m; | |||||
int error; | |||||
m = *mb; | |||||
if (m->m_pkthdr.len < sizeof(*dnh)) { | |||||
DNETDEBUG("ignoring small debugnet_msg packet\n"); | |||||
return; | |||||
} | |||||
/* Get ND header. */ | |||||
if (m->m_len < sizeof(*dnh)) { | |||||
m = m_pullup(m, sizeof(*dnh)); | |||||
*mb = m; | |||||
if (m == NULL) { | |||||
DNETDEBUG("m_pullup failed\n"); | |||||
return; | |||||
} | |||||
} | |||||
dnh = mtod(m, const void *); | |||||
if (ntohl(dnh->mh_len) + sizeof(*dnh) > m->m_pkthdr.len) { | |||||
DNETDEBUG("Dropping short packet.\n"); | |||||
return; | |||||
} | |||||
/* | |||||
* If the issue is transient (ENOBUFS), sender should resend. If | |||||
* non-transient (like driver objecting to rx -> tx from the same | |||||
* thread), not much else we can do. | |||||
*/ | |||||
error = debugnet_ack_output(pcb, dnh->mh_seqno); | |||||
if (error != 0) | |||||
return; | |||||
if (ntohl(dnh->mh_type) == DEBUGNET_FINISHED) { | |||||
printf("Remote shut down the connection on us!\n"); | |||||
pcb->dp_state = DN_STATE_REMOTE_CLOSED; | |||||
/* | |||||
* Continue through to the user handler so they are signalled | |||||
* not to wait for further rx. | |||||
*/ | |||||
} | |||||
pcb->dp_rx_handler(pcb, mb); | |||||
} | |||||
static void | |||||
debugnet_handle_ack(struct debugnet_pcb *pcb, struct mbuf **mb, uint16_t sport) | debugnet_handle_ack(struct debugnet_pcb *pcb, struct mbuf **mb, uint16_t sport) | ||||
{ | { | ||||
const struct debugnet_ack *dn_ack; | const struct debugnet_ack *dn_ack; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint32_t rcv_ackno; | uint32_t rcv_ackno; | ||||
m = *mb; | m = *mb; | ||||
if (m->m_pkthdr.len < sizeof(*dn_ack)) { | |||||
DNETDEBUG("ignoring small ACK packet\n"); | |||||
return; | |||||
} | |||||
/* Get Ack. */ | /* Get Ack. */ | ||||
if (m->m_len < sizeof(*dn_ack)) { | if (m->m_len < sizeof(*dn_ack)) { | ||||
m = m_pullup(m, sizeof(*dn_ack)); | m = m_pullup(m, sizeof(*dn_ack)); | ||||
*mb = m; | *mb = m; | ||||
if (m == NULL) { | if (m == NULL) { | ||||
DNETDEBUG("m_pullup failed\n"); | DNETDEBUG("m_pullup failed\n"); | ||||
return; | return; | ||||
} | } | ||||
Show All 18 Lines | debugnet_handle_ack(struct debugnet_pcb *pcb, struct mbuf **mb, uint16_t sport) | ||||
} | } | ||||
} | } | ||||
void | void | ||||
debugnet_handle_udp(struct debugnet_pcb *pcb, struct mbuf **mb) | debugnet_handle_udp(struct debugnet_pcb *pcb, struct mbuf **mb) | ||||
{ | { | ||||
const struct udphdr *udp; | const struct udphdr *udp; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
uint16_t sport; | uint16_t sport, ulen; | ||||
/* UDP processing. */ | /* UDP processing. */ | ||||
m = *mb; | m = *mb; | ||||
if (m->m_pkthdr.len < sizeof(*udp)) { | if (m->m_pkthdr.len < sizeof(*udp)) { | ||||
DNETDEBUG("ignoring small UDP packet\n"); | DNETDEBUG("ignoring small UDP packet\n"); | ||||
return; | return; | ||||
} | } | ||||
/* Get UDP headers. */ | /* Get UDP headers. */ | ||||
if (m->m_len < sizeof(*udp)) { | if (m->m_len < sizeof(*udp)) { | ||||
m = m_pullup(m, sizeof(*udp)); | m = m_pullup(m, sizeof(*udp)); | ||||
*mb = m; | *mb = m; | ||||
if (m == NULL) { | if (m == NULL) { | ||||
DNETDEBUG("m_pullup failed\n"); | DNETDEBUG("m_pullup failed\n"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
udp = mtod(m, const void *); | udp = mtod(m, const void *); | ||||
/* For now, the only UDP packets we expect to receive are acks. */ | /* We expect to receive UDP packets on the configured client port. */ | ||||
if (ntohs(udp->uh_dport) != pcb->dp_client_ack_port) { | if (ntohs(udp->uh_dport) != pcb->dp_client_port) { | ||||
DNETDEBUG("not on the expected ACK port.\n"); | DNETDEBUG("not on the expected port.\n"); | ||||
return; | return; | ||||
} | } | ||||
/* Check that ulen does not exceed actual size of data. */ | |||||
ulen = ntohs(udp->uh_ulen); | |||||
if (m->m_pkthdr.len < ulen) { | |||||
DNETDEBUG("ignoring runt UDP packet\n"); | |||||
return; | |||||
} | |||||
sport = ntohs(udp->uh_sport); | sport = ntohs(udp->uh_sport); | ||||
m_adj(m, sizeof(*udp)); | m_adj(m, sizeof(*udp)); | ||||
ulen -= sizeof(*udp); | |||||
if (ulen == sizeof(struct debugnet_ack)) { | |||||
debugnet_handle_ack(pcb, mb, sport); | debugnet_handle_ack(pcb, mb, sport); | ||||
return; | |||||
} | } | ||||
if (pcb->dp_rx_handler == NULL) { | |||||
if (ulen < sizeof(struct debugnet_ack)) | |||||
DNETDEBUG("ignoring small ACK packet\n"); | |||||
else | |||||
DNETDEBUG("ignoring unexpected non-ACK packet on " | |||||
"half-duplex connection.\n"); | |||||
return; | |||||
} | |||||
debugnet_handle_rx_msg(pcb, mb); | |||||
} | |||||
/* | /* | ||||
* Handler for incoming packets directly from the network adapter | * Handler for incoming packets directly from the network adapter | ||||
* Identifies the packet type (IP or ARP) and passes it along to one of the | * Identifies the packet type (IP or ARP) and passes it along to one of the | ||||
* helper functions debugnet_handle_ip or debugnet_handle_arp. | * helper functions debugnet_handle_ip or debugnet_handle_arp. | ||||
* | * | ||||
* It needs to partially replicate the behaviour of ether_input() and | * It needs to partially replicate the behaviour of ether_input() and | ||||
* ether_demux(). | * ether_demux(). | ||||
* | * | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | debugnet_connect(const struct debugnet_conn_params *dcp, | ||||
pcb = &g_dnet_pcb; | pcb = &g_dnet_pcb; | ||||
*pcb = (struct debugnet_pcb) { | *pcb = (struct debugnet_pcb) { | ||||
.dp_state = DN_STATE_INIT, | .dp_state = DN_STATE_INIT, | ||||
.dp_client = dcp->dc_client, | .dp_client = dcp->dc_client, | ||||
.dp_server = dcp->dc_server, | .dp_server = dcp->dc_server, | ||||
.dp_gateway = dcp->dc_gateway, | .dp_gateway = dcp->dc_gateway, | ||||
.dp_server_port = dcp->dc_herald_port, /* Initially */ | .dp_server_port = dcp->dc_herald_port, /* Initially */ | ||||
.dp_client_ack_port = dcp->dc_client_ack_port, | .dp_client_port = dcp->dc_client_port, | ||||
.dp_seqno = 1, | .dp_seqno = 1, | ||||
.dp_ifp = dcp->dc_ifp, | .dp_ifp = dcp->dc_ifp, | ||||
.dp_rx_handler = dcp->dc_rx_handler, | |||||
}; | }; | ||||
/* Switch to the debugnet mbuf zones. */ | /* Switch to the debugnet mbuf zones. */ | ||||
debugnet_mbuf_start(); | debugnet_mbuf_start(); | ||||
/* At least one needed parameter is missing; infer it. */ | /* At least one needed parameter is missing; infer it. */ | ||||
if (pcb->dp_client == INADDR_ANY || pcb->dp_gateway == INADDR_ANY || | if (pcb->dp_client == INADDR_ANY || pcb->dp_gateway == INADDR_ANY || | ||||
pcb->dp_ifp == NULL) { | pcb->dp_ifp == NULL) { | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (debugnet_debug > 0) { | ||||
inet_ntop(AF_INET, &pcb->dp_server, serbuf, sizeof(serbuf)); | inet_ntop(AF_INET, &pcb->dp_server, serbuf, sizeof(serbuf)); | ||||
inet_ntop(AF_INET, &pcb->dp_client, clibuf, sizeof(clibuf)); | inet_ntop(AF_INET, &pcb->dp_client, clibuf, sizeof(clibuf)); | ||||
if (pcb->dp_gateway != INADDR_ANY) | if (pcb->dp_gateway != INADDR_ANY) | ||||
inet_ntop(AF_INET, &pcb->dp_gateway, gwbuf, sizeof(gwbuf)); | inet_ntop(AF_INET, &pcb->dp_gateway, gwbuf, sizeof(gwbuf)); | ||||
DNETDEBUG("Connecting to %s:%d%s%s from %s:%d on %s\n", | DNETDEBUG("Connecting to %s:%d%s%s from %s:%d on %s\n", | ||||
serbuf, pcb->dp_server_port, | serbuf, pcb->dp_server_port, | ||||
(pcb->dp_gateway == INADDR_ANY) ? "" : " via ", | (pcb->dp_gateway == INADDR_ANY) ? "" : " via ", | ||||
(pcb->dp_gateway == INADDR_ANY) ? "" : gwbuf, | (pcb->dp_gateway == INADDR_ANY) ? "" : gwbuf, | ||||
clibuf, pcb->dp_client_ack_port, if_name(ifp)); | clibuf, pcb->dp_client_port, if_name(ifp)); | ||||
} | } | ||||
/* Validate iface is online and supported. */ | /* Validate iface is online and supported. */ | ||||
if (!DEBUGNET_SUPPORTED_NIC(ifp)) { | if (!DEBUGNET_SUPPORTED_NIC(ifp)) { | ||||
printf("%s: interface '%s' does not support debugnet\n", | printf("%s: interface '%s' does not support debugnet\n", | ||||
__func__, if_name(ifp)); | __func__, if_name(ifp)); | ||||
error = ENODEV; | error = ENODEV; | ||||
goto cleanup; | goto cleanup; | ||||
▲ Show 20 Lines • Show All 345 Lines • Show Last 20 Lines |