Add support for DSCP

This commit is contained in:
Sergio R. Caprile committed 2026-07-30 17:36:46 -03:00
1 parent b0f5e9cec4
commit 765bb237b7
6 files changed
+234 -140

No files matched your search

+102 -69
View File
@@ -7817,6 +7817,28 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
return len;
}
bool mg_dscp(struct mg_connection *c, uint8_t dscp) {
#if MG_ENABLE_SOCKET
#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_THREADX || \
MG_ARCH == MG_ARCH_TIRTOS || MG_ARCH == MG_ARCH_WIN32
(void) c;
(void) dscp;
#else
int tos = dscp << 2, level = IPPROTO_IP, optname = IP_TOS;
c->dscp = (unsigned) (dscp & 63);
#if MG_ENABLE_IPV6 && !MG_ENABLE_LWIP
if (c->loc.is_ip6)
level = IPPROTO_IPV6, optname = IPV6_TCLASS;
#endif
return setsockopt((MG_SOCKET_TYPE) (size_t) c->fd, level, optname, (char *) &tos, sizeof(tos)) == 0;
#endif
#elif MG_ENABLE_TCPIP
c->dscp = (unsigned) (dscp & 63);
return true;
#endif
return false;
}
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
@@ -8176,7 +8198,7 @@ struct connstate {
struct ip {
uint8_t ver; // Version
uint8_t tos; // Unused
uint8_t tos; // DS field
uint16_t len; // Datagram length
uint16_t id; // Unused
uint16_t frag; // Fragmentation
@@ -8542,13 +8564,15 @@ static void onstatechange(struct mg_tcpip_if *ifp) {
}
static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t proto,
uint32_t ip_src, uint32_t ip_dst, size_t plen) {
uint8_t dscp, uint32_t ip_src, uint32_t ip_dst,
size_t plen) {
// ifp->tx.buf is 8-bit aligned, keep other headers as pointers, see pkt
uint8_t *l2p = (uint8_t *) ifp->tx.buf;
struct ip *ip = (struct ip *) mg_l2_header(ifp, MG_TCPIP_L2PROTO_IPV4,
ifp->mac, l2_dst, l2p);
memset(ip, 0, sizeof(*ip));
ip->ver = 0x45; // Version 4, header length 5 words
ip->ver = 0x45; // Version 4, header length 5 words
ip->tos = (uint8_t) (dscp << 2);
ip->frag = mg_htons(0x4000); // Don't fragment
ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen));
ip->ttl = 64;
@@ -8561,12 +8585,12 @@ static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t proto,
#if MG_ENABLE_IPV6
static struct ip6 *tx_ip6(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
uint8_t next, uint64_t *ip_src, uint64_t *ip_dst,
size_t plen);
uint8_t next, uint8_t dscp, uint64_t *ip_src,
uint64_t *ip_dst, size_t plen);
#endif
static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst, uint8_t dscp,
const void *buf, size_t len) {
uint8_t *l3p;
size_t l2_len;
@@ -8575,7 +8599,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
#if MG_ENABLE_IPV6
struct ip6 *ip6 = NULL;
if (ip_dst->is_ip6) {
ip6 = tx_ip6(ifp, l2_dst, 17, ip_src->addr.ip6, ip_dst->addr.ip6,
ip6 = tx_ip6(ifp, l2_dst, 17, dscp, ip_src->addr.ip6, ip_dst->addr.ip6,
len + sizeof(struct udp));
udp = (struct udp *) (ip6 + 1);
l2_len = sizeof(*ip6) + sizeof(*udp) + len;
@@ -8583,7 +8607,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
} else
#endif
{
ip = tx_ip(ifp, l2_dst, 17, ip_src->addr.ip4, ip_dst->addr.ip4,
ip = tx_ip(ifp, l2_dst, 17, dscp, ip_src->addr.ip4, ip_dst->addr.ip4,
len + sizeof(struct udp));
udp = (struct udp *) (ip + 1);
l2_len = sizeof(*ip) + sizeof(*udp) + len;
@@ -8616,7 +8640,7 @@ static bool tx_udp4(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint32_t ip_src,
memset(&ipd, 0, sizeof(ipd));
ipd.addr.ip4 = ip_dst;
ipd.port = dport;
return tx_udp(ifp, l2_dst, &ips, &ipd, buf, len);
return tx_udp(ifp, l2_dst, &ips, &ipd, 0, buf, len);
}
static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint32_t ip_src,
@@ -8772,7 +8796,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if ((l2addr = get_return_l2addr(ifp, &ips, false, pkt)) == NULL)
return; // safety net for lousy networks
if (plen > room) plen = room;
ip = tx_ip(ifp, l2addr, 1, ifp->ip, pkt->ip->src, sizeof(*icmp) + plen);
ip = tx_ip(ifp, l2addr, 1, 0, ifp->ip, pkt->ip->src, sizeof(*icmp) + plen);
icmp = (struct icmp *) (ip + 1);
memset(icmp, 0, sizeof(*icmp)); // Set csum, type, code to 0
memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX
@@ -8913,14 +8937,15 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
#if MG_ENABLE_IPV6
static struct ip6 *tx_ip6(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
uint8_t next, uint64_t *ip_src, uint64_t *ip_dst,
size_t plen) {
uint8_t next, uint8_t dscp, uint64_t *ip_src,
uint64_t *ip_dst, size_t plen) {
// ifp->tx.buf is 8-bit aligned, keep other headers as pointers, see pkt
uint8_t *l2p = (uint8_t *) ifp->tx.buf;
struct ip6 *ip6 = (struct ip6 *) mg_l2_header(ifp, MG_TCPIP_L2PROTO_IPV6,
ifp->mac, l2_dst, l2p);
memset(ip6, 0, sizeof(*ip6));
ip6->ver = 0x60; // Version 6, traffic class 0
ip6->ver = (uint8_t) (0x60 | (dscp >> 2)); // Version 6, traffic class
ip6->label[0] = (uint8_t) (dscp << 6);
ip6->plen = mg_htons((uint16_t) plen);
ip6->next = next;
ip6->hops = 255; // NDP requires max
@@ -8936,7 +8961,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
const void *buf, size_t len) {
struct ip6 *ip6;
struct icmp6 *icmp6;
ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len);
ip6 = tx_ip6(ifp, l2_dst, 58, 0, ip_src, ip_dst, sizeof(*icmp6) + len);
icmp6 = (struct icmp6 *) (ip6 + 1);
memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0
icmp6->type = type;
@@ -8968,15 +8993,16 @@ static void onstate6change(struct mg_tcpip_if *ifp);
static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct ndp_na *na = (struct ndp_na *) pkt->pay.buf;
uint8_t *opts = (uint8_t *) (na + 1), *endp = opts + pkt->pay.len - sizeof(*na);
if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts
if ((na->res[0] & 0x40) == 0) return; // not "solicited"
if (*opts++ != 2) return; // no target hwaddr, must have
uint8_t *opts = (uint8_t *) (na + 1),
*endp = opts + pkt->pay.len - sizeof(*na);
if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts
if ((na->res[0] & 0x40) == 0) return; // not "solicited"
if (*opts++ != 2) return; // no target hwaddr, must have
MG_VERBOSE(("NDP NA resp from %M", mg_print_ip6, (char *) &na->addr));
if (MG_IP6MATCH(na->addr, ifp->gw6)) {
// Got response for the GW NS request. Set ifp->gw6mac and IP6 -> READY
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, ifp->gw6mac, opts, len)) return;
ifp->gw6_ready = true;
if (ifp->state6 == MG_TCPIP_STATE_IP) {
@@ -8987,8 +9013,8 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
if (c != NULL && c->is_arplooking) {
struct connstate *s = (struct connstate *) (c + 1);
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, s->mac, opts, len)) return;
MG_DEBUG(("%lu NDP resolved %M -> %M", c->id, mg_print_ip6,
&c->rem.addr.ip6, mg_print_l2addr, ifp->l2type, s->mac));
@@ -9000,17 +9026,18 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
// Neighbor Solicitation, 4.3
static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na
struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na
uint64_t target[2];
if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts
if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts
memcpy(target, ns->addr, sizeof(target));
if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) {
uint64_t req[2]; // requester address
uint8_t l2[sizeof(struct mg_l2addr)];
uint8_t len, *opts = (uint8_t *) (ns + 1), *endp = opts + pkt->pay.len - sizeof(*ns);
if (*opts++ != 1) return; // no requester hwaddr (source)
len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len, *opts = (uint8_t *) (ns + 1),
*endp = opts + pkt->pay.len - sizeof(*ns);
if (*opts++ != 1) return; // no requester hwaddr (source)
len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return;
req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit
tx_ndp_na(ifp, l2, target, req, true, ifp->mac);
@@ -9129,7 +9156,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
} else if (type == 5 && length >= 8) {
// process MTU if available, ignore if it smells
mtu = MG_LOAD_BE32(opts + 4);
if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU
if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU
} else if (type == 3 && length >= 32) {
// process prefix, 4.6.2, ignore if it smells
uint8_t pfx_flags = opts[3]; // L=0x80, A=0x40
@@ -9145,7 +9172,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
(void) pref_lifetime;
gotprefix = true;
if (prefix_len != ifp->prefix_len || !match_prefix(prefix, ifp->prefix, ifp->prefix_len))
if (prefix_len != ifp->prefix_len ||
!match_prefix(prefix, ifp->prefix, ifp->prefix_len))
changed = true;
}
opts += length;
@@ -9157,7 +9185,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (changed) ifp->is_ip6_changed = true;
ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1];
if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac));
if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) {
if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP ||
ifp->l2type == MG_TCPIP_L2_PPPoE) {
ifp->state6 = MG_TCPIP_STATE_READY;
ifp->gw6_ready = true;
}
@@ -9242,7 +9271,8 @@ static void onstate6change(struct mg_tcpip_if *ifp) {
ifp->is_ip6_changed = false;
}
} else if (ifp->state6 == MG_TCPIP_STATE_IP) {
if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE))
if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) &&
(ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE))
tx_ndp_ns(ifp, ifp->gw6, NULL); // unsolicited GW hwaddr resolution
} else if (ifp->state6 == MG_TCPIP_STATE_UP) {
MG_INFO(("IP: %M", mg_print_ip6, &ifp->ip6ll));
@@ -9332,8 +9362,8 @@ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst,
uint8_t flags, uint32_t seq, uint32_t ack, const void *buf,
size_t len) {
uint8_t dscp, uint8_t flags, uint32_t seq, uint32_t ack,
const void *buf, size_t len) {
uint8_t *l3p;
struct ip *ip = NULL;
struct tcp *tcp;
@@ -9358,14 +9388,15 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
ip6 =
tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, hlen + len);
ip6 = tx_ip6(ifp, l2_dst, 6, dscp, ip_src->addr.ip6, ip_dst->addr.ip6,
hlen + len);
tcp = (struct tcp *) (ip6 + 1);
l3p = (uint8_t *) ip6;
} else
#endif
{
ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, hlen + len);
ip = tx_ip(ifp, l2_dst, 6, dscp, ip_src->addr.ip4, ip_dst->addr.ip4,
hlen + len);
tcp = (struct tcp *) (ip + 1);
l3p = (uint8_t *) ip;
}
@@ -9415,11 +9446,12 @@ static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
ipd.port = pkt->tcp->sport;
if ((l2addr = get_return_l2addr(ifp, &ipd, false, pkt)) == NULL)
return 0; // safety net for lousy networks
return tx_tcp(ifp, l2addr, &ips, &ipd, flags, seqno, ackno, NULL, 0);
return tx_tcp(ifp, l2addr, &ips, &ipd, 0, flags, seqno, ackno, NULL, 0);
}
static size_t tx_tcp_rst(struct mg_tcpip_if *ifp, struct pkt *pkt, bool toack) {
return tx_tcp_ctrlresp(ifp, pkt, (uint8_t)(toack ? TH_RST : (TH_RST | TH_ACK)),
return tx_tcp_ctrlresp(ifp, pkt,
(uint8_t) (toack ? TH_RST : (TH_RST | TH_ACK)),
toack ? pkt->tcp->ack : 0);
}
@@ -9435,7 +9467,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
s = (struct connstate *) (c + 1);
s->dmss = mss; // from options in client SYN
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t)(s->seq + s->win);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t) (s->seq + s->win);
#if MG_ENABLE_IPV6
if (lsn->loc.is_ip6) {
c->rem.addr.ip6[0] = pkt->ip6->src[0],
@@ -9520,7 +9552,7 @@ static bool udp_send(struct mg_connection *c, const void *buf, size_t len) {
ips.addr.ip4 = ifp->ip;
}
ips.port = c->loc.port;
return tx_udp(ifp, s->mac, &ips, &c->rem, buf, len);
return tx_udp(ifp, s->mac, &ips, &c->rem, c->dscp, buf, len);
}
long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
@@ -9535,7 +9567,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
if (room == 0) return MG_IO_WAIT;
if (len > s->dmss) len = s->dmss; // RFC-6691: reduce if sending opts
if ((uint32_t) len > room) len = room;
sent = tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_PUSH | TH_ACK,
sent = tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_PUSH | TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), buf, len);
if (sent == 0) {
return MG_IO_WAIT;
@@ -9550,16 +9582,16 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
}
static void handle_tls_recv(struct mg_connection *c) {
size_t avail = mg_tls_pending(c); // will change after mg_tls_recv()
size_t avail = mg_tls_pending(c); // will change after mg_tls_recv()
size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail;
struct mg_iobuf *io = &c->recv; // allocated on first avail > 0
struct mg_iobuf *io = &c->recv; // allocated on first avail > 0
if (io->size - io->len < min && !mg_iobuf_resize(io, io->len + min)) {
mg_error(c, "oom");
} else {
// Decrypt data directly into c->recv. If io->buf = NULL or
// io->len = io->size (no room), there can be outstanding data that can't be
// moved (mg_tls_pending() > 0 after mg_tls_recv() returns). So mg_tls_recv()
// takes care of returning 0 in this case (commented as "MIP")
// moved (mg_tls_pending() > 0 after mg_tls_recv() returns). So
// mg_tls_recv() takes care of returning 0 in this case (commented as "MIP")
long n = mg_tls_recv(c, io->buf != NULL ? &io->buf[io->len] : io->buf,
io->size - io->len);
if (n == MG_IO_ERR) {
@@ -9574,7 +9606,7 @@ static void handle_tls_recv(struct mg_connection *c) {
static void handle_ack(struct connstate *s, uint32_t ackno, uint16_t win) {
if (ackno < (s->seq - s->win) || ackno > s->seq) return;
s->maxseq = (uint32_t)(ackno + win);
s->maxseq = (uint32_t) (ackno + win);
s->win = win;
}
@@ -9586,8 +9618,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
uint8_t flags = TH_ACK;
if (mg_ntohl(pkt->tcp->seq) != s->ack) {
MG_VERBOSE(("ignoring FIN, %x != %x", mg_ntohl(pkt->tcp->seq), s->ack));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
return;
}
// If we initiated the closure, we reply with ACK upon receiving FIN
@@ -9608,14 +9640,14 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
// is flushed, then send our FIN.
c->is_draining = 1;
}
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, flags, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, flags,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
if (pkt->pay.len == 0) return; // if no data, we're done
} else if (pkt->pay.len <= 1 && mg_ntohl(pkt->tcp->seq) == s->ack - 1) {
// Keep-Alive (RFC-9293 3.8.4, allow erroneous implementations)
MG_VERBOSE(("%lu keepalive ACK", c->id));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
return; // no data to process
} else if (pkt->pay.len == 0) { // this is an ACK
if (pkt->tcp->flags & TH_ACK)
@@ -9628,8 +9660,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
MG_VERBOSE(("ignoring duplicate pkt"));
} else {
MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
}
return; // drop it
} else if (io->size - io->len < pkt->pay.len &&
@@ -9637,8 +9669,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
mg_error(c, "oom");
return; // drop it
}
if (pkt->tcp->flags & TH_ACK)
handle_ack(s, mg_ntohl(pkt->tcp->ack), mg_ntohs(pkt->tcp->win));
if (pkt->tcp->flags & TH_ACK)
handle_ack(s, mg_ntohl(pkt->tcp->ack), mg_ntohs(pkt->tcp->win));
// Copy TCP payload into the IO buffer. If the connection is plain text,
// we copy to c->recv. If the connection is TLS, this data is encrypted,
// therefore we copy that encrypted data to the c->rtls iobuffer instead,
@@ -9654,8 +9686,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
if (s->unacked > MG_TCPIP_WIN / 2 && s->acked != s->ack) {
// Send ACK immediately
MG_VERBOSE(("%lu imm ACK %lu", c->id, s->acked));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
s->unacked = 0;
s->acked = s->ack;
if (s->ttype != MIP_TTYPE_KEEPALIVE) settmout(c, MIP_TTYPE_KEEPALIVE);
@@ -9757,7 +9789,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (!handle_opt(s, pkt->tcp, pkt->ip6 != NULL))
return; // process options (MSS)
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t)(s->seq + s->win);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t) (s->seq + s->win);
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
c->is_connecting = 0; // Client connected
settmout(c, MIP_TTYPE_KEEPALIVE);
@@ -10143,8 +10175,8 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
drv_up = ifp->driver->poll ? ifp->driver->poll(ifp, expired_1000ms) : true;
l2_up = mg_l2_poll(ifp, expired_1000ms); // Handle L2 up/down link status;
if (expired_1000ms) { // ifp->state rules over state6
mg_ip_link(ifp, drv_up, l2_up); // Handle IPv4
mg_ip6_link(ifp, drv_up, l2_up); // Handle IPv6
mg_ip_link(ifp, drv_up, l2_up); // Handle IPv4
mg_ip6_link(ifp, drv_up, l2_up); // Handle IPv6
if (ifp->state < MG_TCPIP_STATE_UP) MG_ERROR(("Network is down"));
mg_tcpip_call(ifp, MG_TCPIP_EV_TIMER_1S, NULL);
}
@@ -10183,7 +10215,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
continue;
} else if (s->ttype == MIP_TTYPE_ACK && s->acked != s->ack) {
MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack));
tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
s->acked = s->ack;
} else if (s->ttype == MIP_TTYPE_SYN) {
@@ -10196,8 +10228,8 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
mg_error(c, "keepalive");
} else {
MG_VERBOSE(("%lu keepalive", c->id));
tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq - 1),
mg_htonl(s->ack), NULL, 0);
tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq - 1), mg_htonl(s->ack), NULL, 0);
}
}
@@ -10260,7 +10292,8 @@ void mg_tcpip_free(struct mg_tcpip_if *ifp) {
static void send_syn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_SYN, isn, 0, NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_SYN, isn, 0, NULL,
0);
}
static void l2addr_resolved(struct mg_connection *c) {
@@ -10281,9 +10314,9 @@ void mg_connect_resolved(struct mg_connection *c) {
c->loc.port = mg_htons(ifp->eport++);
#if MG_ENABLE_IPV6
if (c->rem.is_ip6) {
if(c->rem.addr.ip6[0] == ifp->ip6ll[0]) { // same local LAN, use ll
if (c->rem.addr.ip6[0] == ifp->ip6ll[0]) { // same local LAN, use ll
c->loc.addr.ip6[0] = ifp->ip6ll[0], c->loc.addr.ip6[1] = ifp->ip6ll[1];
} else { // use global address
} else { // use global address
c->loc.addr.ip6[0] = ifp->ip6[0], c->loc.addr.ip6[1] = ifp->ip6[1];
}
c->loc.is_ip6 = true;
@@ -10363,7 +10396,7 @@ static void init_closure(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
if (c->is_udp == false && c->is_listening == false &&
c->is_connecting == false) { // For TCP conns,
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_FIN | TH_ACK,
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_FIN | TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
settmout(c, MIP_TTYPE_FIN);
}
+9
View File
@@ -2382,6 +2382,10 @@ struct mg_connection {
void *pfn_data; // Protocol-level handler argument
char data[MG_DATA_SIZE]; // Scratch space for protocol state; freely readable
void *tls; // TLS state (internal)
unsigned dscp : 6; // Differentiated Services Code Point
#define MG_DSCP_CS(class_) ((class_) << 3)
#define MG_DSCP_AF(class_, drop_) (((class_) << 3) | ((drop_) << 1))
#define MG_DSCP_EF 46
unsigned is_listening : 1; // Listening connection; accepts inbound connections
unsigned is_client : 1; // Outbound connection created by mg_connect()
unsigned is_accepted : 1; // Inbound connection accepted from a listener
@@ -2462,6 +2466,11 @@ struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
mg_event_handler_t fn, void *fn_data);
// Sets the 6-bit Differentiated Services Code Point for outgoing datagrams.
// Call on MG_EV_OPEN for UDP listeners, MG_EV_CONNECT for clients, or
// MG_EV_ACCEPT for TCP servers, before sending application data.
bool mg_dscp(struct mg_connection *, uint8_t dscp);
// Called internally after DNS resolution completes to create the OS socket
// and initiate the TCP/IP connect. Normally not called by user code.
void mg_connect_resolved(struct mg_connection *);
+22
View File
@@ -29,6 +29,28 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
return len;
}
bool mg_dscp(struct mg_connection *c, uint8_t dscp) {
#if MG_ENABLE_SOCKET
#if MG_ENABLE_FREERTOS_TCP || MG_ARCH == MG_ARCH_THREADX || \
MG_ARCH == MG_ARCH_TIRTOS || MG_ARCH == MG_ARCH_WIN32
(void) c;
(void) dscp;
#else
int tos = dscp << 2, level = IPPROTO_IP, optname = IP_TOS;
c->dscp = (unsigned) (dscp & 63);
#if MG_ENABLE_IPV6 && !MG_ENABLE_LWIP
if (c->loc.is_ip6)
level = IPPROTO_IPV6, optname = IPV6_TCLASS;
#endif
return setsockopt((MG_SOCKET_TYPE) (size_t) c->fd, level, optname, (char *) &tos, sizeof(tos)) == 0;
#endif
#elif MG_ENABLE_TCPIP
c->dscp = (unsigned) (dscp & 63);
return true;
#endif
return false;
}
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_strcasecmp(str, mg_str("localhost")) != 0) return false;
+9
View File
@@ -74,6 +74,10 @@ struct mg_connection {
void *pfn_data; // Protocol-level handler argument
char data[MG_DATA_SIZE]; // Scratch space for protocol state; freely readable
void *tls; // TLS state (internal)
unsigned dscp : 6; // Differentiated Services Code Point
#define MG_DSCP_CS(class_) ((class_) << 3)
#define MG_DSCP_AF(class_, drop_) (((class_) << 3) | ((drop_) << 1))
#define MG_DSCP_EF 46
unsigned is_listening : 1; // Listening connection; accepts inbound connections
unsigned is_client : 1; // Outbound connection created by mg_connect()
unsigned is_accepted : 1; // Inbound connection accepted from a listener
@@ -154,6 +158,11 @@ struct mg_connection *mg_connect(struct mg_mgr *, const char *url,
struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
mg_event_handler_t fn, void *fn_data);
// Sets the 6-bit Differentiated Services Code Point for outgoing datagrams.
// Call on MG_EV_OPEN for UDP listeners, MG_EV_CONNECT for clients, or
// MG_EV_ACCEPT for TCP servers, before sending application data.
bool mg_dscp(struct mg_connection *, uint8_t dscp);
// Called internally after DNS resolution completes to create the OS socket
// and initiate the TCP/IP connect. Normally not called by user code.
void mg_connect_resolved(struct mg_connection *);
+80 -69
View File
@@ -46,7 +46,7 @@ struct connstate {
struct ip {
uint8_t ver; // Version
uint8_t tos; // Unused
uint8_t tos; // DS field
uint16_t len; // Datagram length
uint16_t id; // Unused
uint16_t frag; // Fragmentation
@@ -412,13 +412,15 @@ static void onstatechange(struct mg_tcpip_if *ifp) {
}
static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t proto,
uint32_t ip_src, uint32_t ip_dst, size_t plen) {
uint8_t dscp, uint32_t ip_src, uint32_t ip_dst,
size_t plen) {
// ifp->tx.buf is 8-bit aligned, keep other headers as pointers, see pkt
uint8_t *l2p = (uint8_t *) ifp->tx.buf;
struct ip *ip = (struct ip *) mg_l2_header(ifp, MG_TCPIP_L2PROTO_IPV4,
ifp->mac, l2_dst, l2p);
memset(ip, 0, sizeof(*ip));
ip->ver = 0x45; // Version 4, header length 5 words
ip->ver = 0x45; // Version 4, header length 5 words
ip->tos = (uint8_t) (dscp << 2);
ip->frag = mg_htons(0x4000); // Don't fragment
ip->len = mg_htons((uint16_t) (sizeof(*ip) + plen));
ip->ttl = 64;
@@ -431,12 +433,12 @@ static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t proto,
#if MG_ENABLE_IPV6
static struct ip6 *tx_ip6(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
uint8_t next, uint64_t *ip_src, uint64_t *ip_dst,
size_t plen);
uint8_t next, uint8_t dscp, uint64_t *ip_src,
uint64_t *ip_dst, size_t plen);
#endif
static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst, uint8_t dscp,
const void *buf, size_t len) {
uint8_t *l3p;
size_t l2_len;
@@ -445,7 +447,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
#if MG_ENABLE_IPV6
struct ip6 *ip6 = NULL;
if (ip_dst->is_ip6) {
ip6 = tx_ip6(ifp, l2_dst, 17, ip_src->addr.ip6, ip_dst->addr.ip6,
ip6 = tx_ip6(ifp, l2_dst, 17, dscp, ip_src->addr.ip6, ip_dst->addr.ip6,
len + sizeof(struct udp));
udp = (struct udp *) (ip6 + 1);
l2_len = sizeof(*ip6) + sizeof(*udp) + len;
@@ -453,7 +455,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
} else
#endif
{
ip = tx_ip(ifp, l2_dst, 17, ip_src->addr.ip4, ip_dst->addr.ip4,
ip = tx_ip(ifp, l2_dst, 17, dscp, ip_src->addr.ip4, ip_dst->addr.ip4,
len + sizeof(struct udp));
udp = (struct udp *) (ip + 1);
l2_len = sizeof(*ip) + sizeof(*udp) + len;
@@ -486,7 +488,7 @@ static bool tx_udp4(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint32_t ip_src,
memset(&ipd, 0, sizeof(ipd));
ipd.addr.ip4 = ip_dst;
ipd.port = dport;
return tx_udp(ifp, l2_dst, &ips, &ipd, buf, len);
return tx_udp(ifp, l2_dst, &ips, &ipd, 0, buf, len);
}
static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint32_t ip_src,
@@ -642,7 +644,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if ((l2addr = get_return_l2addr(ifp, &ips, false, pkt)) == NULL)
return; // safety net for lousy networks
if (plen > room) plen = room;
ip = tx_ip(ifp, l2addr, 1, ifp->ip, pkt->ip->src, sizeof(*icmp) + plen);
ip = tx_ip(ifp, l2addr, 1, 0, ifp->ip, pkt->ip->src, sizeof(*icmp) + plen);
icmp = (struct icmp *) (ip + 1);
memset(icmp, 0, sizeof(*icmp)); // Set csum, type, code to 0
memcpy(icmp + 1, pkt->pay.buf, plen); // Copy RX payload to TX
@@ -783,14 +785,15 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
#if MG_ENABLE_IPV6
static struct ip6 *tx_ip6(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
uint8_t next, uint64_t *ip_src, uint64_t *ip_dst,
size_t plen) {
uint8_t next, uint8_t dscp, uint64_t *ip_src,
uint64_t *ip_dst, size_t plen) {
// ifp->tx.buf is 8-bit aligned, keep other headers as pointers, see pkt
uint8_t *l2p = (uint8_t *) ifp->tx.buf;
struct ip6 *ip6 = (struct ip6 *) mg_l2_header(ifp, MG_TCPIP_L2PROTO_IPV6,
ifp->mac, l2_dst, l2p);
memset(ip6, 0, sizeof(*ip6));
ip6->ver = 0x60; // Version 6, traffic class 0
ip6->ver = (uint8_t) (0x60 | (dscp >> 2)); // Version 6, traffic class
ip6->label[0] = (uint8_t) (dscp << 6);
ip6->plen = mg_htons((uint16_t) plen);
ip6->next = next;
ip6->hops = 255; // NDP requires max
@@ -806,7 +809,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
const void *buf, size_t len) {
struct ip6 *ip6;
struct icmp6 *icmp6;
ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len);
ip6 = tx_ip6(ifp, l2_dst, 58, 0, ip_src, ip_dst, sizeof(*icmp6) + len);
icmp6 = (struct icmp6 *) (ip6 + 1);
memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0
icmp6->type = type;
@@ -838,15 +841,16 @@ static void onstate6change(struct mg_tcpip_if *ifp);
static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct ndp_na *na = (struct ndp_na *) pkt->pay.buf;
uint8_t *opts = (uint8_t *) (na + 1), *endp = opts + pkt->pay.len - sizeof(*na);
if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts
if ((na->res[0] & 0x40) == 0) return; // not "solicited"
if (*opts++ != 2) return; // no target hwaddr, must have
uint8_t *opts = (uint8_t *) (na + 1),
*endp = opts + pkt->pay.len - sizeof(*na);
if (pkt->pay.len < (sizeof(*na) + 2)) return; // first 2 bytes in opts
if ((na->res[0] & 0x40) == 0) return; // not "solicited"
if (*opts++ != 2) return; // no target hwaddr, must have
MG_VERBOSE(("NDP NA resp from %M", mg_print_ip6, (char *) &na->addr));
if (MG_IP6MATCH(na->addr, ifp->gw6)) {
// Got response for the GW NS request. Set ifp->gw6mac and IP6 -> READY
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, ifp->gw6mac, opts, len)) return;
ifp->gw6_ready = true;
if (ifp->state6 == MG_TCPIP_STATE_IP) {
@@ -857,8 +861,8 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
if (c != NULL && c->is_arplooking) {
struct connstate *s = (struct connstate *) (c + 1);
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, s->mac, opts, len)) return;
MG_DEBUG(("%lu NDP resolved %M -> %M", c->id, mg_print_ip6,
&c->rem.addr.ip6, mg_print_l2addr, ifp->l2type, s->mac));
@@ -870,17 +874,18 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
// Neighbor Solicitation, 4.3
static void rx_ndp_ns(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na
struct ndp_na *ns = (struct ndp_na *) pkt->pay.buf; // struct ndp_ns = ndp_na
uint64_t target[2];
if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts
if (pkt->pay.len < (sizeof(*ns) + 2)) return; // first 2 bytes in opts
memcpy(target, ns->addr, sizeof(target));
if (MG_IP6MATCH(target, ifp->ip6ll) || MG_IP6MATCH(target, ifp->ip6)) {
uint64_t req[2]; // requester address
uint8_t l2[sizeof(struct mg_l2addr)];
uint8_t len, *opts = (uint8_t *) (ns + 1), *endp = opts + pkt->pay.len - sizeof(*ns);
if (*opts++ != 1) return; // no requester hwaddr (source)
len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
uint8_t len, *opts = (uint8_t *) (ns + 1),
*endp = opts + pkt->pay.len - sizeof(*ns);
if (*opts++ != 1) return; // no requester hwaddr (source)
len = *opts++; // check valid hwaddr and get it
if ((opts + 8 * len - 2) > endp) return; // truncated
if (!mg_l2_ip6get(ifp->l2type, l2, opts, len)) return;
req[0] = pkt->ip6->src[0], req[1] = pkt->ip6->src[1]; // align to 64-bit
tx_ndp_na(ifp, l2, target, req, true, ifp->mac);
@@ -999,7 +1004,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
} else if (type == 5 && length >= 8) {
// process MTU if available, ignore if it smells
mtu = MG_LOAD_BE32(opts + 4);
if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU
if (mtu < 1280 || mtu > ifp->l2mtu) mtu = 0; // RFC-8200, minimum MTU
} else if (type == 3 && length >= 32) {
// process prefix, 4.6.2, ignore if it smells
uint8_t pfx_flags = opts[3]; // L=0x80, A=0x40
@@ -1015,7 +1020,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
(void) pref_lifetime;
gotprefix = true;
if (prefix_len != ifp->prefix_len || !match_prefix(prefix, ifp->prefix, ifp->prefix_len))
if (prefix_len != ifp->prefix_len ||
!match_prefix(prefix, ifp->prefix, ifp->prefix_len))
changed = true;
}
opts += length;
@@ -1027,7 +1033,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (changed) ifp->is_ip6_changed = true;
ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1];
if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac));
if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) {
if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP ||
ifp->l2type == MG_TCPIP_L2_PPPoE) {
ifp->state6 = MG_TCPIP_STATE_READY;
ifp->gw6_ready = true;
}
@@ -1112,7 +1119,8 @@ static void onstate6change(struct mg_tcpip_if *ifp) {
ifp->is_ip6_changed = false;
}
} else if (ifp->state6 == MG_TCPIP_STATE_IP) {
if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE))
if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) &&
(ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE))
tx_ndp_ns(ifp, ifp->gw6, NULL); // unsolicited GW hwaddr resolution
} else if (ifp->state6 == MG_TCPIP_STATE_UP) {
MG_INFO(("IP: %M", mg_print_ip6, &ifp->ip6ll));
@@ -1202,8 +1210,8 @@ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
struct mg_addr *ip_src, struct mg_addr *ip_dst,
uint8_t flags, uint32_t seq, uint32_t ack, const void *buf,
size_t len) {
uint8_t dscp, uint8_t flags, uint32_t seq, uint32_t ack,
const void *buf, size_t len) {
uint8_t *l3p;
struct ip *ip = NULL;
struct tcp *tcp;
@@ -1228,14 +1236,15 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
ip6 =
tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, hlen + len);
ip6 = tx_ip6(ifp, l2_dst, 6, dscp, ip_src->addr.ip6, ip_dst->addr.ip6,
hlen + len);
tcp = (struct tcp *) (ip6 + 1);
l3p = (uint8_t *) ip6;
} else
#endif
{
ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, hlen + len);
ip = tx_ip(ifp, l2_dst, 6, dscp, ip_src->addr.ip4, ip_dst->addr.ip4,
hlen + len);
tcp = (struct tcp *) (ip + 1);
l3p = (uint8_t *) ip;
}
@@ -1285,11 +1294,12 @@ static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
ipd.port = pkt->tcp->sport;
if ((l2addr = get_return_l2addr(ifp, &ipd, false, pkt)) == NULL)
return 0; // safety net for lousy networks
return tx_tcp(ifp, l2addr, &ips, &ipd, flags, seqno, ackno, NULL, 0);
return tx_tcp(ifp, l2addr, &ips, &ipd, 0, flags, seqno, ackno, NULL, 0);
}
static size_t tx_tcp_rst(struct mg_tcpip_if *ifp, struct pkt *pkt, bool toack) {
return tx_tcp_ctrlresp(ifp, pkt, (uint8_t)(toack ? TH_RST : (TH_RST | TH_ACK)),
return tx_tcp_ctrlresp(ifp, pkt,
(uint8_t) (toack ? TH_RST : (TH_RST | TH_ACK)),
toack ? pkt->tcp->ack : 0);
}
@@ -1305,7 +1315,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
s = (struct connstate *) (c + 1);
s->dmss = mss; // from options in client SYN
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t)(s->seq + s->win);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t) (s->seq + s->win);
#if MG_ENABLE_IPV6
if (lsn->loc.is_ip6) {
c->rem.addr.ip6[0] = pkt->ip6->src[0],
@@ -1390,7 +1400,7 @@ static bool udp_send(struct mg_connection *c, const void *buf, size_t len) {
ips.addr.ip4 = ifp->ip;
}
ips.port = c->loc.port;
return tx_udp(ifp, s->mac, &ips, &c->rem, buf, len);
return tx_udp(ifp, s->mac, &ips, &c->rem, c->dscp, buf, len);
}
long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
@@ -1405,7 +1415,7 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
if (room == 0) return MG_IO_WAIT;
if (len > s->dmss) len = s->dmss; // RFC-6691: reduce if sending opts
if ((uint32_t) len > room) len = room;
sent = tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_PUSH | TH_ACK,
sent = tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_PUSH | TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), buf, len);
if (sent == 0) {
return MG_IO_WAIT;
@@ -1420,16 +1430,16 @@ long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
}
static void handle_tls_recv(struct mg_connection *c) {
size_t avail = mg_tls_pending(c); // will change after mg_tls_recv()
size_t avail = mg_tls_pending(c); // will change after mg_tls_recv()
size_t min = avail > MG_MAX_RECV_SIZE ? MG_MAX_RECV_SIZE : avail;
struct mg_iobuf *io = &c->recv; // allocated on first avail > 0
struct mg_iobuf *io = &c->recv; // allocated on first avail > 0
if (io->size - io->len < min && !mg_iobuf_resize(io, io->len + min)) {
mg_error(c, "oom");
} else {
// Decrypt data directly into c->recv. If io->buf = NULL or
// io->len = io->size (no room), there can be outstanding data that can't be
// moved (mg_tls_pending() > 0 after mg_tls_recv() returns). So mg_tls_recv()
// takes care of returning 0 in this case (commented as "MIP")
// moved (mg_tls_pending() > 0 after mg_tls_recv() returns). So
// mg_tls_recv() takes care of returning 0 in this case (commented as "MIP")
long n = mg_tls_recv(c, io->buf != NULL ? &io->buf[io->len] : io->buf,
io->size - io->len);
if (n == MG_IO_ERR) {
@@ -1444,7 +1454,7 @@ static void handle_tls_recv(struct mg_connection *c) {
static void handle_ack(struct connstate *s, uint32_t ackno, uint16_t win) {
if (ackno < (s->seq - s->win) || ackno > s->seq) return;
s->maxseq = (uint32_t)(ackno + win);
s->maxseq = (uint32_t) (ackno + win);
s->win = win;
}
@@ -1456,8 +1466,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
uint8_t flags = TH_ACK;
if (mg_ntohl(pkt->tcp->seq) != s->ack) {
MG_VERBOSE(("ignoring FIN, %x != %x", mg_ntohl(pkt->tcp->seq), s->ack));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
return;
}
// If we initiated the closure, we reply with ACK upon receiving FIN
@@ -1478,14 +1488,14 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
// is flushed, then send our FIN.
c->is_draining = 1;
}
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, flags, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, flags,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
if (pkt->pay.len == 0) return; // if no data, we're done
} else if (pkt->pay.len <= 1 && mg_ntohl(pkt->tcp->seq) == s->ack - 1) {
// Keep-Alive (RFC-9293 3.8.4, allow erroneous implementations)
MG_VERBOSE(("%lu keepalive ACK", c->id));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
return; // no data to process
} else if (pkt->pay.len == 0) { // this is an ACK
if (pkt->tcp->flags & TH_ACK)
@@ -1498,8 +1508,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
MG_VERBOSE(("ignoring duplicate pkt"));
} else {
MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, ack));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), "", 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
}
return; // drop it
} else if (io->size - io->len < pkt->pay.len &&
@@ -1507,8 +1517,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
mg_error(c, "oom");
return; // drop it
}
if (pkt->tcp->flags & TH_ACK)
handle_ack(s, mg_ntohl(pkt->tcp->ack), mg_ntohs(pkt->tcp->win));
if (pkt->tcp->flags & TH_ACK)
handle_ack(s, mg_ntohl(pkt->tcp->ack), mg_ntohs(pkt->tcp->win));
// Copy TCP payload into the IO buffer. If the connection is plain text,
// we copy to c->recv. If the connection is TLS, this data is encrypted,
// therefore we copy that encrypted data to the c->rtls iobuffer instead,
@@ -1524,8 +1534,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
if (s->unacked > MG_TCPIP_WIN / 2 && s->acked != s->ack) {
// Send ACK immediately
MG_VERBOSE(("%lu imm ACK %lu", c->id, s->acked));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
s->unacked = 0;
s->acked = s->ack;
if (s->ttype != MIP_TTYPE_KEEPALIVE) settmout(c, MIP_TTYPE_KEEPALIVE);
@@ -1627,7 +1637,7 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (!handle_opt(s, pkt->tcp, pkt->ip6 != NULL))
return; // process options (MSS)
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t)(s->seq + s->win);
s->win = mg_ntohs(pkt->tcp->win), s->maxseq = (uint32_t) (s->seq + s->win);
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
c->is_connecting = 0; // Client connected
settmout(c, MIP_TTYPE_KEEPALIVE);
@@ -2013,8 +2023,8 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
drv_up = ifp->driver->poll ? ifp->driver->poll(ifp, expired_1000ms) : true;
l2_up = mg_l2_poll(ifp, expired_1000ms); // Handle L2 up/down link status;
if (expired_1000ms) { // ifp->state rules over state6
mg_ip_link(ifp, drv_up, l2_up); // Handle IPv4
mg_ip6_link(ifp, drv_up, l2_up); // Handle IPv6
mg_ip_link(ifp, drv_up, l2_up); // Handle IPv4
mg_ip6_link(ifp, drv_up, l2_up); // Handle IPv6
if (ifp->state < MG_TCPIP_STATE_UP) MG_ERROR(("Network is down"));
mg_tcpip_call(ifp, MG_TCPIP_EV_TIMER_1S, NULL);
}
@@ -2053,7 +2063,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
continue;
} else if (s->ttype == MIP_TTYPE_ACK && s->acked != s->ack) {
MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack));
tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq),
tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK, mg_htonl(s->seq),
mg_htonl(s->ack), NULL, 0);
s->acked = s->ack;
} else if (s->ttype == MIP_TTYPE_SYN) {
@@ -2066,8 +2076,8 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
mg_error(c, "keepalive");
} else {
MG_VERBOSE(("%lu keepalive", c->id));
tx_tcp(ifp, s->mac, &c->loc, &c->rem, TH_ACK, mg_htonl(s->seq - 1),
mg_htonl(s->ack), NULL, 0);
tx_tcp(ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_ACK,
mg_htonl(s->seq - 1), mg_htonl(s->ack), NULL, 0);
}
}
@@ -2130,7 +2140,8 @@ void mg_tcpip_free(struct mg_tcpip_if *ifp) {
static void send_syn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_SYN, isn, 0, NULL, 0);
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_SYN, isn, 0, NULL,
0);
}
static void l2addr_resolved(struct mg_connection *c) {
@@ -2151,9 +2162,9 @@ void mg_connect_resolved(struct mg_connection *c) {
c->loc.port = mg_htons(ifp->eport++);
#if MG_ENABLE_IPV6
if (c->rem.is_ip6) {
if(c->rem.addr.ip6[0] == ifp->ip6ll[0]) { // same local LAN, use ll
if (c->rem.addr.ip6[0] == ifp->ip6ll[0]) { // same local LAN, use ll
c->loc.addr.ip6[0] = ifp->ip6ll[0], c->loc.addr.ip6[1] = ifp->ip6ll[1];
} else { // use global address
} else { // use global address
c->loc.addr.ip6[0] = ifp->ip6[0], c->loc.addr.ip6[1] = ifp->ip6[1];
}
c->loc.is_ip6 = true;
@@ -2233,7 +2244,7 @@ static void init_closure(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1);
if (c->is_udp == false && c->is_listening == false &&
c->is_connecting == false) { // For TCP conns,
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, TH_FIN | TH_ACK,
tx_tcp(c->mgr->ifp, s->mac, &c->loc, &c->rem, c->dscp, TH_FIN | TH_ACK,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
settmout(c, MIP_TTYPE_FIN);
}
+12 -2
View File
@@ -110,7 +110,8 @@ static void ph(struct mg_connection *c, int ev, void *ev_data) {
}
static void fn(struct mg_connection *c, int ev, void *ev_data) {
(void) c, (void) ev, (void) ev_data;
if (ev == MG_EV_ACCEPT) ASSERT(mg_dscp(c, MG_DSCP_AF(4, 1)));
(void) ev_data;
}
static void tcpclosure_fn(struct mg_connection *c, int ev, void *ev_data) {
@@ -499,8 +500,11 @@ static void test_tcp_basics(bool ipv6) {
if (ipv6) {
ASSERT(i6->src[0] == mg_htonll(0x100000000000000) && i6->src[1] == 0 &&
i6->dst[0] == mg_htonll(0x200000000000000) && i6->dst[1] == 0);
ASSERT((uint8_t) (((i6->ver & 15) << 2) | (i6->label[0] >> 6)) ==
MG_DSCP_AF(4, 1));
} else {
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
ASSERT(i->tos == (MG_DSCP_AF(4, 1) << 2));
}
// segment with seq_no way out of window
@@ -1125,8 +1129,11 @@ static void test_tcp(bool ipv6) {
}
static void udp_fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ && c->recv.len == 2 && c->recv.buf[0] == 'p')
if (ev == MG_EV_OPEN) {
ASSERT(mg_dscp(c, MG_DSCP_AF(4, 1)));
} else if (ev == MG_EV_READ && c->recv.len == 2 && c->recv.buf[0] == 'p') {
mg_send(c, "P90", 3);
}
(void) ev_data;
}
@@ -1221,9 +1228,12 @@ static void test_udp(bool ipv6) {
if (ipv6) {
ASSERT(i6->src[0] == mg_htonll(0x100000000000000) && i6->src[1] == 0 &&
i6->dst[0] == mg_htonll(0x200000000000000) && i6->dst[1] == 0);
ASSERT((uint8_t) (((i6->ver & 15) << 2) | (i6->label[0] >> 6)) ==
MG_DSCP_AF(4, 1));
ASSERT(udp6csum_ok(i6, u));
} else {
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
ASSERT(i->tos == (MG_DSCP_AF(4, 1) << 2));
ASSERT(udpcsum_ok(i, u));
}