Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LwIP: Support client sending multicast / broadcast (IPv4) packets #1548

Merged
merged 1 commit into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions examples/lwip/config/lwipopts.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@
* (Needs MEMP_STATS set) when coap_free_context() is called.
*/
#define LWIP_STATS_DISPLAY 1

/*
* Set to 1 for debugging UDP traffic
*/
#if 0
#define LWIP_DEBUG 1
#define UDP_DEBUG LWIP_DBG_ON
#endif
8 changes: 3 additions & 5 deletions include/coap3/coap_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ coap_address_set_port(coap_address_t *addr, uint16_t port) {

#define _coap_address_isany_impl(A) ip_addr_isany(&(A)->addr)

#define _coap_is_mcast_impl(Address) ip_addr_ismulticast(&(Address)->addr)

#elif defined(WITH_CONTIKI)

#include "uip.h"
Expand Down Expand Up @@ -298,7 +296,7 @@ coap_address_isany(const coap_address_t *a) {
return _coap_address_isany_impl(a);
}

#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)
#if !defined(WITH_CONTIKI) && !defined(RIOT_VERSION)

/**
* Checks if given address @p a denotes a multicast address. This function
Expand All @@ -318,7 +316,7 @@ int coap_is_bcast(const coap_address_t *a);
*/
int coap_is_af_unix(const coap_address_t *a);

#else /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */
#else /* WITH_CONTIKI || RIOT_VERSION */

/**
* Checks if given address @p a denotes a multicast address. This function
Expand All @@ -339,6 +337,6 @@ coap_is_af_unix(const coap_address_t *a) {
return 0;
}

#endif /* WITH_LWIP || WITH_CONTIKI || RIOT_VERSION */
#endif /* WITH_CONTIKI || RIOT_VERSION */

#endif /* COAP_ADDRESS_H_ */
132 changes: 123 additions & 9 deletions src/coap_io_lwip.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ coap_recvc(void *arg, struct udp_pcb *upcb, struct pbuf *p,
coap_session_t *session = (coap_session_t *)arg;
int result = -1;
(void)upcb;
(void)addr;
(void)port;

assert(session);
LWIP_ASSERT("Proto not supported for LWIP", COAP_PROTO_NOT_RELIABLE(session->proto));
Expand All @@ -184,6 +182,8 @@ coap_recvc(void *arg, struct udp_pcb *upcb, struct pbuf *p,
/* Minimum size of CoAP header - ignore runt */
return;
}
memcpy(&session->addr_info.remote.addr, addr, sizeof(session->addr_info.remote.addr));
coap_address_set_port(&session->addr_info.remote, port);

coap_log_debug("* %s: lwip: recv %4d bytes\n",
coap_session_str(session), p->len);
Expand Down Expand Up @@ -429,11 +429,12 @@ coap_socket_connect_udp(coap_socket_t *sock,
coap_address_t *remote_addr) {
err_t err;
struct udp_pcb *pcb;
int is_mcast = coap_is_mcast(server);
coap_address_t connect_addr;

(void)local_if;
(void)default_port;
(void)local_addr;
(void)remote_addr;
coap_address_copy(&connect_addr, server);
if (connect_addr.port == 0)
connect_addr.port = default_port;

coap_lock_invert(sock->session->context,
LOCK_TCPIP_CORE(),
Expand All @@ -445,18 +446,35 @@ coap_socket_connect_udp(coap_socket_t *sock,
goto err_unlock;
}

if (local_if) {
pcb->local_ip = local_if->addr;
pcb->local_port = local_if->port;
}
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("coap_socket_connect_udp: port bind failed\n"));
goto err_udp_remove;
}

if (local_addr) {
local_addr->addr = pcb->local_ip;
local_addr->port = pcb->local_port;
}
sock->session->addr_info.local.port = pcb->local_port;

err = udp_connect(pcb, &server->addr, server->port);
if (err) {
goto err_udp_unbind;
if (remote_addr) {
coap_address_copy(remote_addr, &connect_addr);
}

if (is_mcast) {
coap_address_copy(&sock->mcast_addr, &connect_addr);
sock->flags |= COAP_SOCKET_MULTICAST;
} else {
err = udp_connect(pcb, &connect_addr.addr, connect_addr.port);
if (err) {
goto err_udp_unbind;
}
}

#if LWIP_IPV6 && LWIP_IPV4
Expand Down Expand Up @@ -794,3 +812,99 @@ coap_socket_close(coap_socket_t *sock) {
#endif /* !COAP_DISABLE_TCP */
return;
}

int
coap_is_mcast(const coap_address_t *a) {
if (!a)
return 0;

/* Treat broadcast in same way as multicast */
if (coap_is_bcast(a))
return 1;

return ip_addr_ismulticast(&(a)->addr);
}

#ifndef COAP_BCST_CNT
#define COAP_BCST_CNT 15
#endif /* COAP_BCST_CNT */

/* How frequently to refresh the list of valid IPv4 broadcast addresses */
#ifndef COAP_BCST_REFRESH_SECS
#define COAP_BCST_REFRESH_SECS 30
#endif /* COAP_BCST_REFRESH_SECS */

#if COAP_IPV4_SUPPORT
static int bcst_cnt = -1;
static coap_tick_t last_refresh;
static uint32_t b_ipv4[COAP_BCST_CNT];
#endif /* COAP_IPV4_SUPPORT */

int
coap_is_bcast(const coap_address_t *a) {
int i;
coap_tick_t now;
#if COAP_IPV4_SUPPORT
const ip4_addr_t *ipv4;
#endif /* COAP_IPV4_SUPPORT */

if (!a)
return 0;

if (IP_IS_V6(&(a)->addr))
return 0;

#if COAP_IPV4_SUPPORT
#ifndef INADDR_BROADCAST
#define INADDR_BROADCAST ((uint32_t)0xffffffffUL)
#endif /* !INADDR_BROADCAST */
ipv4 = ip_2_ip4(&(a)->addr);
if (ipv4->addr == INADDR_BROADCAST)
return 1;

coap_ticks(&now);
if (bcst_cnt == -1 ||
(now - last_refresh) > (COAP_BCST_REFRESH_SECS * COAP_TICKS_PER_SECOND)) {
/* Determine the list of broadcast interfaces */
struct netif *netif;

bcst_cnt = 0;
last_refresh = now;

LWIP_ASSERT_CORE_LOCKED();

NETIF_FOREACH(netif) {
if (bcst_cnt < COAP_BCST_CNT) {
const ip4_addr_t *ip_addr;
const ip4_addr_t *netmask;

ip_addr = ip_2_ip4(&netif->ip_addr);
netmask = ip_2_ip4(&netif->netmask);
if (netmask->addr != 0xffffffff) {
b_ipv4[bcst_cnt] = ip_addr->addr | ~(netmask->addr);
bcst_cnt++;
}
}
}

if (bcst_cnt == COAP_BCST_CNT) {
coap_log_warn("coap_is_bcst: Insufficient space for broadcast addresses\n");
}
}
for (i = 0; i < bcst_cnt; i++) {
if (ipv4->addr == b_ipv4[i])
return 1;
}
#endif /* COAP_IPV4_SUPPORT */
return 0;
}

/**
* Checks if given address @p a denotes a AF_UNIX address. This function
* returns @c 1 if @p a is of type AF_UNIX, @c 0 otherwise.
*/
int
coap_is_af_unix(const coap_address_t *a) {
(void)a;
return 0;
}
Loading