Skip to content

Commit f89655f

Browse files
authored
Merge pull request ARMmbed#15040 from mat-kalinowski/sendrecv_message
New feature: send/recv message implementation added to network stack
2 parents 3305dc1 + ad0eb0e commit f89655f

31 files changed

+927
-53
lines changed

connectivity/cellular/include/cellular/framework/AT/AT_CellularStack.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ class AT_CellularStack : public NetworkStack {
8888

8989
virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data);
9090

91+
92+
nsapi_size_or_error_t socket_sendto_control(nsapi_socket_t handle, const SocketAddress &address,
93+
const void *data, nsapi_size_t size,
94+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
95+
{
96+
return NSAPI_ERROR_UNSUPPORTED;
97+
}
98+
99+
nsapi_size_or_error_t socket_recvfrom_control(nsapi_socket_t handle, SocketAddress *address,
100+
void *data, nsapi_size_t size,
101+
nsapi_msghdr_t *control, nsapi_size_t control_size) override
102+
{
103+
return NSAPI_ERROR_UNSUPPORTED;
104+
}
105+
91106
protected:
92107
class CellularSocket {
93108
public:

connectivity/lwipstack/include/lwipstack/LWIPStack.h

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
163163
static void netif_status_irq(struct netif *netif);
164164
static Interface *our_if_from_netif(struct netif *netif);
165165
static void delete_interface(OnboardNetworkStack::Interface **interface_out);
166+
NetworkInterface *network_if_from_netif_id(int id);
167+
int netif_id_from_network_if(NetworkInterface *userInterface);
168+
166169

167170
#if LWIP_ETHERNET
168171
static err_t emac_low_level_output(struct netif *netif, struct pbuf *p);
@@ -222,6 +225,8 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
222225
void *hw; /**< alternative implementation pointer - used for PPP */
223226
};
224227

228+
NetworkInterface *user_network_interface;
229+
225230
mbed_rtos_storage_semaphore_t remove_interface_sem;
226231
osSemaphoreId_t remove_interface;
227232
mbed_rtos_storage_semaphore_t linked_sem;
@@ -265,7 +270,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
265270
* @param[out] interface_out pointer to stack interface object controlling the EMAC
266271
* @return NSAPI_ERROR_OK on success, or error code
267272
*/
268-
nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out) override;
273+
nsapi_error_t add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface = NULL) override;
269274

270275
/** Register a network interface with the IP stack
271276
*
@@ -450,6 +455,27 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
450455
nsapi_size_or_error_t socket_send(nsapi_socket_t handle,
451456
const void *data, nsapi_size_t size) override;
452457

458+
/** Send a packet with ancillary data over a UDP socket
459+
*
460+
* Sends data to the specified address. Returns the number of bytes
461+
* sent from the buffer.
462+
*
463+
* This call is non-blocking. If sendto would block,
464+
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
465+
*
466+
* @param handle Socket handle
467+
* @param address The SocketAddress of the remote host
468+
* @param data Buffer of data to send to the host
469+
* @param size Size of the buffer in bytes
470+
* @param control Ancillary data storage
471+
* @param control_size Size of the Ancillary data in bytes
472+
* @return Number of sent bytes on success, negative error
473+
* code on failure
474+
*/
475+
nsapi_size_or_error_t socket_sendto_control(nsapi_socket_t handle, const SocketAddress &address,
476+
const void *data, nsapi_size_t size,
477+
nsapi_msghdr_t *control, nsapi_size_t control_size) override;
478+
453479
/** Receive data over a TCP socket
454480
*
455481
* The socket must be connected to a remote host. Returns the number of
@@ -493,6 +519,7 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
493519
* This call is non-blocking. If recvfrom would block,
494520
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
495521
*
522+
* It uses socket_recvfrom_control with zero ancillary data.
496523
* @param handle Socket handle
497524
* @param address Destination for the source address or NULL
498525
* @param buffer Destination buffer for data received from the host
@@ -503,6 +530,27 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable<LWIP> {
503530
nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address,
504531
void *buffer, nsapi_size_t size) override;
505532

533+
/** Receive a packet with ancillary data over a UDP socket
534+
*
535+
* Receives data and stores the source address in address if address
536+
* is not NULL. Returns the number of bytes received into the buffer.
537+
*
538+
* This call is non-blocking. If recvfrom would block,
539+
* NSAPI_ERROR_WOULD_BLOCK is returned immediately.
540+
*
541+
* @param handle Socket handle
542+
* @param address Destination for the source address or NULL
543+
* @param buffer Destination buffer for data received from the host
544+
* @param size Size of the buffer in bytes
545+
* @param control Ancillary data storage
546+
* @param control_size Size of the Ancillary data in bytes
547+
* @return Number of received bytes on success, negative error
548+
* code on failure
549+
*/
550+
nsapi_size_or_error_t socket_recvfrom_control(nsapi_socket_t handle, SocketAddress *address,
551+
void *data, nsapi_size_t size,
552+
nsapi_msghdr_t *control, nsapi_size_t control_size) override;
553+
506554
/** Register a callback on state change of the socket
507555
*
508556
* The specified callback will be called on state changes such as when

connectivity/lwipstack/include/lwipstack/lwipopts.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@
311311

312312
#endif
313313

314+
#define LWIP_NETBUF_RECVINFO MBED_CONF_LWIP_NETBUF_RECVINFO_ENABLED
315+
314316
// Make sure we default these to off, so
315317
// LWIP doesn't default to on
316318
#ifndef LWIP_ARP

connectivity/lwipstack/lwip/test/unit/lwipopts.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
#define LWIP_NETCONN !NO_SYS
4747
#define LWIP_SOCKET !NO_SYS
4848
#define LWIP_NETCONN_FULLDUPLEX LWIP_SOCKET
49-
#define LWIP_NETBUF_RECVINFO 1
49+
#define LWIP_NETBUF_RECVINFO MBED_CONF_NETBUF_RECVINFO_ENABLED
5050
#define LWIP_HAVE_LOOPIF 1
5151
#define TCPIP_THREAD_TEST
5252

connectivity/lwipstack/source/LWIPInterface.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,28 @@
4242

4343
LWIP::Interface *LWIP::Interface::list;
4444

45+
NetworkInterface *LWIP::Interface::network_if_from_netif_id(int id)
46+
{
47+
for (Interface *interface = list; interface; interface = interface->next) {
48+
if (id == netif_get_index(&interface->netif)) {
49+
return interface->user_network_interface;
50+
}
51+
}
52+
return NULL;
53+
}
54+
55+
int LWIP::Interface::netif_id_from_network_if(NetworkInterface *userInterface)
56+
{
57+
if (userInterface != NULL) {
58+
for (Interface *interface = list; interface; interface = interface->next) {
59+
if (userInterface == interface->user_network_interface) {
60+
return netif_get_index(&interface->netif);
61+
}
62+
}
63+
}
64+
return 0;
65+
}
66+
4567
LWIP::Interface *LWIP::Interface::our_if_from_netif(struct netif *netif)
4668
{
4769
for (Interface *interface = list; interface; interface = interface->next) {
@@ -408,7 +430,7 @@ LWIP::Interface::Interface() :
408430
list = this;
409431
}
410432

411-
nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out)
433+
nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardNetworkStack::Interface **interface_out, NetworkInterface *user_network_interface)
412434
{
413435
#if LWIP_ETHERNET
414436
Interface *interface = new (std::nothrow) Interface();
@@ -431,7 +453,7 @@ nsapi_error_t LWIP::add_ethernet_interface(EMAC &emac, bool default_if, OnboardN
431453
#endif
432454

433455
interface->netif.hwaddr_len = 6;
434-
456+
interface->user_network_interface = user_network_interface;
435457
if (!netif_add(&interface->netif,
436458
#if LWIP_IPV4
437459
0, 0, 0,

connectivity/lwipstack/source/LWIPStack.cpp

Lines changed: 122 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
* limitations under the License.
1616
*/
1717
#include "nsapi.h"
18+
#include "netsocket/MsgHeader.h"
1819
#include "mbed_interface.h"
1920
#include "mbed_assert.h"
2021
#include "Semaphore.h"
21-
#include <stdio.h>
2222
#include <stdbool.h>
2323
#include <string.h>
2424

@@ -37,6 +37,7 @@
3737
#include "lwip/raw.h"
3838
#include "lwip/netif.h"
3939
#include "lwip/lwip_errno.h"
40+
#include "lwip/ip_addr.h"
4041
#include "lwip-sys/arch/sys_arch.h"
4142

4243
#include "LWIPStack.h"
@@ -271,7 +272,9 @@ nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto)
271272
arena_dealloc(s);
272273
return NSAPI_ERROR_NO_SOCKET;
273274
}
274-
275+
#if LWIP_NETBUF_RECVINFO
276+
s->conn->flags &= ~NETCONN_FLAG_PKTINFO;
277+
#endif
275278
netconn_set_nonblocking(s->conn, true);
276279
*(struct mbed_lwip_socket **)handle = s;
277280
return 0;
@@ -439,24 +442,111 @@ nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi
439442
}
440443

441444
nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAddress &address, const void *data, nsapi_size_t size)
445+
{
446+
return socket_sendto_control(handle, address, data, size, NULL, 0);
447+
}
448+
449+
nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
450+
{
451+
return socket_recvfrom_control(handle, address, data, size, NULL, 0);
452+
453+
}
454+
455+
nsapi_size_or_error_t LWIP::socket_recvfrom_control(nsapi_socket_t handle, SocketAddress *address, void *data,
456+
nsapi_size_t size, nsapi_msghdr_t *control,
457+
nsapi_size_t control_size)
442458
{
443459
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
444-
ip_addr_t ip_addr;
460+
struct netbuf *buf;
461+
462+
err_t err = netconn_recv(s->conn, &buf);
463+
if (err != ERR_OK) {
464+
return err_remap(err);
465+
}
466+
467+
if (address) {
468+
nsapi_addr_t addr;
469+
convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf));
470+
address->set_addr(addr);
471+
address->set_port(netbuf_fromport(buf));
472+
}
473+
#if LWIP_NETBUF_RECVINFO
474+
if ((s->conn->flags & NETCONN_FLAG_PKTINFO) && control && control_size >= sizeof(nsapi_pktinfo_t)) {
475+
nsapi_pktinfo_t *pkt_info = reinterpret_cast<nsapi_pktinfo *>(control);
476+
memset(control, 0, control_size);
477+
// Not optimal but sufficient. It should help the caller in not iterating over
478+
// the control data structure
479+
control->len = control_size;
480+
control->level = NSAPI_SOCKET;
481+
control->type = NSAPI_PKTINFO;
482+
// retrieve the destination
483+
convert_lwip_addr_to_mbed(&pkt_info->ipi_addr, netbuf_destaddr(buf));
484+
// retrieve the interface id
485+
pkt_info->network_interface = default_interface->network_if_from_netif_id(buf->p->if_idx);
486+
}
487+
#endif
488+
u16_t recv = netbuf_copy(buf, data, (u16_t)size);
489+
netbuf_delete(buf);
490+
491+
return recv;
492+
}
493+
494+
nsapi_size_or_error_t LWIP::socket_sendto_control(nsapi_socket_t handle, const SocketAddress &address,
495+
const void *data, nsapi_size_t size, nsapi_msghdr_t *control,
496+
nsapi_size_t control_size)
497+
{
498+
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
499+
ip_addr_t ip_addr = {};
500+
501+
// Used for backup the bound address if the packet must be sent from a specific address,
502+
ip_addr_t bound_addr = {};
503+
ip_addr_t src_addr = {};
504+
505+
nsapi_pktinfo_t *pkt_info = nullptr;
445506

446507
nsapi_addr_t addr = address.get_addr();
447508
if (!convert_mbed_addr_to_lwip(&ip_addr, &addr)) {
448509
return NSAPI_ERROR_PARAMETER;
449510
}
450-
struct netif *netif_ = netif_get_by_index(s->conn->pcb.ip->netif_idx);
511+
512+
// We try to extract the pktinfo from the header
513+
514+
if (control) {
515+
MsgHeaderIterator it(control, control_size);
516+
while (it.has_next()) {
517+
auto *hdr = it.next();
518+
if (hdr->level == NSAPI_SOCKET && hdr->type == NSAPI_PKTINFO) {
519+
pkt_info = reinterpret_cast<nsapi_pktinfo_t *>(hdr);
520+
break;
521+
}
522+
}
523+
}
524+
525+
if (pkt_info) {
526+
if (!convert_mbed_addr_to_lwip(&src_addr, &pkt_info->ipi_addr)) {
527+
return NSAPI_ERROR_PARAMETER;
528+
}
529+
}
530+
531+
struct netif *netif_ = nullptr;
532+
533+
if (pkt_info) {
534+
int index = default_interface->netif_id_from_network_if((NetworkInterface *)pkt_info->network_interface);
535+
netif_ = netif_get_by_index(index);
536+
} else {
537+
netif_ = netif_get_by_index(s->conn->pcb.ip->netif_idx);
538+
}
451539
if (!netif_) {
452540
netif_ = &default_interface->netif;
453541
}
542+
454543
if (netif_) {
455544
if ((addr.version == NSAPI_IPv4 && !get_ipv4_addr(netif_)) ||
456545
(addr.version == NSAPI_IPv6 && !get_ipv6_addr(netif_) && !get_ipv6_link_local_addr(netif_))) {
457546
return NSAPI_ERROR_PARAMETER;
458547
}
459548
}
549+
460550
struct netbuf *buf = netbuf_new();
461551

462552
err_t err = netbuf_ref(buf, data, (u16_t)size);
@@ -465,36 +555,29 @@ nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAdd
465555
return err_remap(err);
466556
}
467557

468-
err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port());
469-
netbuf_delete(buf);
470-
if (err != ERR_OK) {
471-
return err_remap(err);
558+
// handle src destination if required
559+
if (pkt_info) {
560+
// Backup the bound address
561+
ip_addr_copy(bound_addr, s->conn->pcb.udp->local_ip);
562+
// replace it with the source address
563+
if (!ip_addr_isany(&src_addr)) {
564+
ip_addr_copy(s->conn->pcb.udp->local_ip, src_addr);
565+
}
472566
}
473567

474-
return size;
475-
}
568+
err = netconn_sendto(s->conn, buf, &ip_addr, address.get_port());
476569

477-
nsapi_size_or_error_t LWIP::socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
478-
{
479-
struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
480-
struct netbuf *buf;
570+
if (pkt_info) {
571+
// restore bound address
572+
ip_addr_copy(s->conn->pcb.udp->local_ip, bound_addr);
573+
}
481574

482-
err_t err = netconn_recv(s->conn, &buf);
575+
netbuf_delete(buf);
483576
if (err != ERR_OK) {
484577
return err_remap(err);
485578
}
486579

487-
if (address) {
488-
nsapi_addr_t addr;
489-
convert_lwip_addr_to_mbed(&addr, netbuf_fromaddr(buf));
490-
address->set_addr(addr);
491-
address->set_port(netbuf_fromport(buf));
492-
}
493-
494-
u16_t recv = netbuf_copy(buf, data, (u16_t)size);
495-
netbuf_delete(buf);
496-
497-
return recv;
580+
return size;
498581
}
499582

500583
int32_t LWIP::find_multicast_member(const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr)
@@ -687,6 +770,19 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
687770
}
688771
s->conn->pcb.ip->tos = (u8_t)(*(const int *)optval);
689772
return 0;
773+
774+
case NSAPI_PKTINFO:
775+
#if LWIP_NETBUF_RECVINFO
776+
if (optlen != sizeof(int)) {
777+
return NSAPI_ERROR_UNSUPPORTED;
778+
}
779+
if (*(const int *)optval) {
780+
s->conn->flags |= NETCONN_FLAG_PKTINFO;
781+
} else {
782+
s->conn->flags &= ~NETCONN_FLAG_PKTINFO;
783+
}
784+
return 0;
785+
#endif
690786
default:
691787
return NSAPI_ERROR_UNSUPPORTED;
692788
}

0 commit comments

Comments
 (0)