LWIP: (Ab)use mg_conection.priv_2 to pass input interface address

This is required to distinguish input interface for multicast traffic
and select correct output interface for outgoing traffic (advertisements).

http://savannah.nongnu.org/bugs/?49662 removed ability to receive
multicast traffic on on interface-bound sockets (making the previous
change useless, hence the revert), so for LWIP 2.0.1 and newer
multicast packets can only be received on INADDR_ANY listeners.
User is then required to distinguish input interface in the receive path.
This information is only available in the udp_recv callback, so we must
pass this down to dns-sd library somehow, and priv_2 is the how.
It is normally used for DNS resolver state, and is never used on
listening sockets. We thus avoid growing the mg_connection structure.
This commit is contained in:
Deomid "rojer" Ryabkov 2021-05-01 05:23:07 +01:00 committed by Deomid Ryabkov
parent e3a140c9a7
commit da1e5438bd
3 changed files with 78 additions and 14 deletions

View File

@ -2907,10 +2907,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
}
}
/* Copy input interface address. */
if (nc != NULL) nc->priv_2 = lc->priv_2;
}
if (nc != NULL) {
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
DBG(("%p <- %d bytes from %s:%d ia %#x", nc, n,
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port),
(int) (intptr_t) nc->priv_2));
if (nc == lc) {
nc->recv_mbuf.len += n;
} else {
@ -15171,6 +15174,11 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc,
mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
}
struct udp_info {
union socket_address remote_addr;
uint32_t local_ip4;
};
/*
* Lwip included in the SDKs for nRF5x chips has different type for the
* callback of `udp_recv()`
@ -15187,18 +15195,22 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
/* Put address in a separate pbuf and tack it onto the packet. */
struct pbuf *sap =
pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
pbuf_alloc(PBUF_RAW, sizeof(struct udp_info), PBUF_RAM);
if (sap == NULL) {
pbuf_free(p);
return;
}
union socket_address *sa = (union socket_address *) sap->payload;
struct udp_info *ui = (struct udp_info *) sap->payload;
struct netif *nif = ip_current_netif();
#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
ui->remote_addr.sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
ui->local_ip4 = ip_2_ip4(&nif->ip_addr)->addr;
#else
sa->sin.sin_addr.s_addr = addr->addr;
ui->remote_addr.sin.sin_addr.s_addr = addr->addr;
ui->local_ip4 = nif->ip_addr.addr;
#endif
sa->sin.sin_port = htons(port);
ui->remote_addr.sin.sin_port = htons(port);
/* Logic in the recv handler requires that there be exactly one data pbuf. */
p = pbuf_coalesce(p, PBUF_RAW);
pbuf_chain(sap, p);
@ -15238,6 +15250,13 @@ static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
res = MIN(dp->len, len);
pbuf_copy_partial(dp, buf, res, 0);
pbuf_free(dp);
const struct udp_info *ui = (struct udp_info *) ap->payload;
*sa = ui->remote_addr;
/* Store local interface address for incoming packets.
* Only for listener because outgoing connections may use priv_2 for DNS. */
if (nc->listener == NULL) {
nc->priv_2 = (void *) (uintptr_t) ui->local_ip4;
}
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
pbuf_free(ap);
}
@ -15451,11 +15470,19 @@ struct udp_sendto_ctx {
struct pbuf *p;
ip_addr_t *ip;
uint16_t port;
uint32_t mcast_ip4;
int ret;
};
static void udp_sendto_tcpip(void *arg) {
struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
if (ctx->mcast_ip4 != 0) {
#if LWIP_VERSION_MAJOR > 1 && LWIP_MULTICAST_TX_OPTIONS
ctx->upcb->mcast_ip4.addr = ctx->mcast_ip4;
#elif LWIP_VERSION_MAJOR == 1 && LWIP_IGMP
ctx->upcb->multicast_ip.addr = ctx->mcast_ip4;
#endif
}
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
}
@ -15474,8 +15501,13 @@ static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
if (p == NULL) return 0;
memcpy(p->payload, data, len);
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
if (ip_addr_ismulticast(&ip)) {
ctx.mcast_ip4 = (uint32_t) (uintptr_t) nc->priv_2;
}
mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
cs->err = ctx.ret;
DBG(("%p udp_sendto %x mc4 %x res %d", nc, (int) ip_2_ip4(ctx.ip)->addr,
(int) ctx.mcast_ip4, (int) cs->err));
pbuf_free(p);
return (cs->err == ERR_OK ? (int) len : -2);
}

View File

@ -250,6 +250,11 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc,
mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
}
struct udp_info {
union socket_address remote_addr;
uint32_t local_ip4;
};
/*
* Lwip included in the SDKs for nRF5x chips has different type for the
* callback of `udp_recv()`
@ -266,18 +271,22 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
/* Put address in a separate pbuf and tack it onto the packet. */
struct pbuf *sap =
pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
pbuf_alloc(PBUF_RAW, sizeof(struct udp_info), PBUF_RAM);
if (sap == NULL) {
pbuf_free(p);
return;
}
union socket_address *sa = (union socket_address *) sap->payload;
struct udp_info *ui = (struct udp_info *) sap->payload;
struct netif *nif = ip_current_netif();
#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
ui->remote_addr.sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
ui->local_ip4 = ip_2_ip4(&nif->ip_addr)->addr;
#else
sa->sin.sin_addr.s_addr = addr->addr;
ui->remote_addr.sin.sin_addr.s_addr = addr->addr;
ui->local_ip4 = nif->ip_addr.addr;
#endif
sa->sin.sin_port = htons(port);
ui->remote_addr.sin.sin_port = htons(port);
/* Logic in the recv handler requires that there be exactly one data pbuf. */
p = pbuf_coalesce(p, PBUF_RAW);
pbuf_chain(sap, p);
@ -317,6 +326,13 @@ static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
res = MIN(dp->len, len);
pbuf_copy_partial(dp, buf, res, 0);
pbuf_free(dp);
const struct udp_info *ui = (struct udp_info *) ap->payload;
*sa = ui->remote_addr;
/* Store local interface address for incoming packets.
* Only for listener because outgoing connections may use priv_2 for DNS. */
if (nc->listener == NULL) {
nc->priv_2 = (void *) (uintptr_t) ui->local_ip4;
}
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
pbuf_free(ap);
}
@ -530,11 +546,19 @@ struct udp_sendto_ctx {
struct pbuf *p;
ip_addr_t *ip;
uint16_t port;
uint32_t mcast_ip4;
int ret;
};
static void udp_sendto_tcpip(void *arg) {
struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
if (ctx->mcast_ip4 != 0) {
#if LWIP_VERSION_MAJOR > 1 && LWIP_MULTICAST_TX_OPTIONS
ctx->upcb->mcast_ip4.addr = ctx->mcast_ip4;
#elif LWIP_VERSION_MAJOR == 1 && LWIP_IGMP
ctx->upcb->multicast_ip.addr = ctx->mcast_ip4;
#endif
}
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
}
@ -553,8 +577,13 @@ static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
if (p == NULL) return 0;
memcpy(p->payload, data, len);
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
if (ip_addr_ismulticast(&ip)) {
ctx.mcast_ip4 = (uint32_t) (uintptr_t) nc->priv_2;
}
mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
cs->err = ctx.ret;
DBG(("%p udp_sendto %x mc4 %x res %d", nc, (int) ip_2_ip4(ctx.ip)->addr,
(int) ctx.mcast_ip4, (int) cs->err));
pbuf_free(p);
return (cs->err == ERR_OK ? (int) len : -2);
}

View File

@ -680,10 +680,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
}
}
/* Copy input interface address. */
if (nc != NULL) nc->priv_2 = lc->priv_2;
}
if (nc != NULL) {
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
ntohs(nc->sa.sin.sin_port)));
DBG(("%p <- %d bytes from %s:%d ia %#x", nc, n,
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port),
(int) (intptr_t) nc->priv_2));
if (nc == lc) {
nc->recv_mbuf.len += n;
} else {