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,111 @@ 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_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
500583int32_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