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
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,114 @@ nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi
439442}
440443
441444nsapi_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_sendmsg (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_recvmsg (handle, address, data, size, NULL , 0 );
452+
453+ }
454+
455+ nsapi_size_or_error_t LWIP::socket_recvmsg (nsapi_socket_t handle, SocketAddress *address,
456+ void *data, nsapi_size_t size,
457+ nsapi_msghdr_t *control, 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+ // to do store Network interface
486+ pkt_info->ipi_ifindex = buf->p ->if_idx ;
487+ default_interface->network_if_from_netif_id (buf->p ->if_idx );
488+ }
489+ #endif
490+ u16_t recv = netbuf_copy (buf, data, (u16_t )size);
491+ netbuf_delete (buf);
492+
493+ return recv;
494+ }
495+
496+ nsapi_size_or_error_t LWIP::socket_sendmsg (nsapi_socket_t handle, const SocketAddress &address,
497+ const void *data, nsapi_size_t size,
498+ nsapi_msghdr_t *control, nsapi_size_t control_size)
499+ {
500+ struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
501+ ip_addr_t ip_addr = {};
502+
503+ // Used for backup the bound address if the packet must be sent from a specific address,
504+ ip_addr_t bound_addr = {};
505+ ip_addr_t src_addr = {};
506+
507+ nsapi_pktinfo_t *pkt_info = nullptr ;
445508
446509 nsapi_addr_t addr = address.get_addr ();
447510 if (!convert_mbed_addr_to_lwip (&ip_addr, &addr)) {
448511 return NSAPI_ERROR_PARAMETER;
449512 }
450- struct netif *netif_ = netif_get_by_index (s->conn ->pcb .ip ->netif_idx );
513+
514+ // We try to extract the pktinfo from the header
515+
516+ if (control) {
517+ MsgHeaderIterator it (control, control_size);
518+ while (it.has_next ()) {
519+ auto *hdr = it.next ();
520+ if (hdr->level == NSAPI_SOCKET && hdr->type == NSAPI_PKTINFO) {
521+ pkt_info = reinterpret_cast <nsapi_pktinfo_t *>(hdr);
522+ break ;
523+ }
524+ }
525+ }
526+
527+ if (pkt_info) {
528+ if (!convert_mbed_addr_to_lwip (&src_addr, &pkt_info->ipi_addr )) {
529+ return NSAPI_ERROR_PARAMETER;
530+ }
531+ }
532+
533+ struct netif *netif_ = nullptr ;
534+
535+ if (pkt_info) {
536+ // to do replace NULL with NetworkInterface
537+ int index = default_interface->netif_id_from_network_if (NULL );
538+ netif_ = netif_get_by_index (index);
539+ } else {
540+ netif_ = netif_get_by_index (s->conn ->pcb .ip ->netif_idx );
541+ }
451542 if (!netif_) {
452543 netif_ = &default_interface->netif ;
453544 }
545+
454546 if (netif_) {
455547 if ((addr.version == NSAPI_IPv4 && !get_ipv4_addr (netif_)) ||
456548 (addr.version == NSAPI_IPv6 && !get_ipv6_addr (netif_) && !get_ipv6_link_local_addr (netif_))) {
457549 return NSAPI_ERROR_PARAMETER;
458550 }
459551 }
552+
460553 struct netbuf *buf = netbuf_new ();
461554
462555 err_t err = netbuf_ref (buf, data, (u16_t )size);
@@ -465,36 +558,29 @@ nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAdd
465558 return err_remap (err);
466559 }
467560
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);
561+ // handle src destination if required
562+ if (pkt_info) {
563+ // Backup the bound address
564+ ip_addr_copy (bound_addr, s->conn ->pcb .udp ->local_ip );
565+ // replace it with the source address
566+ if (!ip_addr_isany (&src_addr)) {
567+ ip_addr_copy (s->conn ->pcb .udp ->local_ip , src_addr);
568+ }
472569 }
473570
474- return size;
475- }
571+ err = netconn_sendto (s->conn , buf, &ip_addr, address.get_port ());
476572
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;
573+ if (pkt_info) {
574+ // restore bound address
575+ ip_addr_copy (s-> conn -> pcb . udp -> local_ip , bound_addr) ;
576+ }
481577
482- err_t err = netconn_recv (s-> conn , & buf);
578+ netbuf_delete ( buf);
483579 if (err != ERR_OK) {
484580 return err_remap (err);
485581 }
486582
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;
583+ return size;
498584}
499585
500586int32_t LWIP::find_multicast_member (const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr)
@@ -687,6 +773,19 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
687773 }
688774 s->conn ->pcb .ip ->tos = (u8_t )(*(const int *)optval);
689775 return 0 ;
776+
777+ case NSAPI_PKTINFO:
778+ #if LWIP_NETBUF_RECVINFO
779+ if (optlen != sizeof (int )) {
780+ return NSAPI_ERROR_UNSUPPORTED;
781+ }
782+ if (*(const int *)optval) {
783+ s->conn ->flags |= NETCONN_FLAG_PKTINFO;
784+ } else {
785+ s->conn ->flags &= ~NETCONN_FLAG_PKTINFO;
786+ }
787+ return 0 ;
788+ #endif
690789 default :
691790 return NSAPI_ERROR_UNSUPPORTED;
692791 }
0 commit comments