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"
@@ -439,24 +440,109 @@ nsapi_size_or_error_t LWIP::socket_recv(nsapi_socket_t handle, void *data, nsapi
439440}
440441
441442nsapi_size_or_error_t LWIP::socket_sendto (nsapi_socket_t handle, const SocketAddress &address, const void *data, nsapi_size_t size)
443+ {
444+ return socket_sendmsg (handle, address, data, size, NULL , 0 );
445+ }
446+
447+ nsapi_size_or_error_t LWIP::socket_recvfrom (nsapi_socket_t handle, SocketAddress *address, void *data, nsapi_size_t size)
448+ {
449+ return socket_recvmsg (handle, address, data, size, NULL , 0 );
450+
451+ }
452+
453+ nsapi_size_or_error_t LWIP::socket_recvmsg (nsapi_socket_t handle, SocketAddress *address,
454+ void *data, nsapi_size_t size,
455+ nsapi_msghdr_t *control, nsapi_size_t control_size)
442456{
443457 struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
444- ip_addr_t ip_addr;
458+ struct netbuf *buf;
459+
460+ err_t err = netconn_recv (s->conn , &buf);
461+ if (err != ERR_OK) {
462+ return err_remap (err);
463+ }
464+
465+ if (address) {
466+ nsapi_addr_t addr;
467+ convert_lwip_addr_to_mbed (&addr, netbuf_fromaddr (buf));
468+ address->set_addr (addr);
469+ address->set_port (netbuf_fromport (buf));
470+ }
471+
472+ if ((s->conn ->flags & NETCONN_FLAG_PKTINFO) && control && control_size >= sizeof (nsapi_pktinfo_t )) {
473+ nsapi_pktinfo_t *pkt_info = reinterpret_cast <nsapi_pktinfo *>(control);
474+ // Not optimal but sufficient. It should help the caller in not iterating over
475+ // the control data structure
476+ control->len = control_size;
477+ control->level = NSAPI_SOCKET;
478+ control->type = NSAPI_PKTINFO;
479+ // retrieve the destination
480+ convert_lwip_addr_to_mbed (&pkt_info->ipi_addr , netbuf_destaddr (buf));
481+ // retrieve the interface id
482+ pkt_info->ipi_ifindex = buf->p ->if_idx ;
483+ }
484+
485+ u16_t recv = netbuf_copy (buf, data, (u16_t )size);
486+ netbuf_delete (buf);
487+
488+ return recv;
489+ }
490+
491+ nsapi_size_or_error_t LWIP::socket_sendmsg (nsapi_socket_t handle, const SocketAddress &address,
492+ const void *data, nsapi_size_t size,
493+ nsapi_msghdr_t *control, nsapi_size_t control_size)
494+ {
495+ struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle;
496+ ip_addr_t ip_addr = {};
497+
498+ // Used for backup the bound address if the packet must be sent from a specific address,
499+ ip_addr_t bound_addr = {};
500+ ip_addr_t src_addr = {};
501+
502+ nsapi_pktinfo_t *pkt_info = nullptr ;
445503
446504 nsapi_addr_t addr = address.get_addr ();
447505 if (!convert_mbed_addr_to_lwip (&ip_addr, &addr)) {
448506 return NSAPI_ERROR_PARAMETER;
449507 }
450- struct netif *netif_ = netif_get_by_index (s->conn ->pcb .ip ->netif_idx );
508+
509+ // We try to extract the pktinfo from the header
510+
511+ if (control) {
512+ MsgHeaderIterator it (control, control_size);
513+ while (it.has_next ()) {
514+ auto *hdr = it.next ();
515+ if (hdr->level == NSAPI_SOCKET && hdr->type == NSAPI_PKTINFO) {
516+ pkt_info = reinterpret_cast <nsapi_pktinfo_t *>(hdr);
517+ break ;
518+ }
519+ }
520+ }
521+
522+ if (pkt_info) {
523+ if (!convert_mbed_addr_to_lwip (&src_addr, &pkt_info->ipi_addr )) {
524+ return NSAPI_ERROR_PARAMETER;
525+ }
526+ }
527+
528+ struct netif *netif_ = nullptr ;
529+
530+ if (pkt_info) {
531+ netif_ = netif_get_by_index (pkt_info->ipi_ifindex );
532+ } else {
533+ netif_ = netif_get_by_index (s->conn ->pcb .ip ->netif_idx );
534+ }
451535 if (!netif_) {
452536 netif_ = &default_interface->netif ;
453537 }
538+
454539 if (netif_) {
455540 if ((addr.version == NSAPI_IPv4 && !get_ipv4_addr (netif_)) ||
456541 (addr.version == NSAPI_IPv6 && !get_ipv6_addr (netif_) && !get_ipv6_link_local_addr (netif_))) {
457542 return NSAPI_ERROR_PARAMETER;
458543 }
459544 }
545+
460546 struct netbuf *buf = netbuf_new ();
461547
462548 err_t err = netbuf_ref (buf, data, (u16_t )size);
@@ -465,36 +551,29 @@ nsapi_size_or_error_t LWIP::socket_sendto(nsapi_socket_t handle, const SocketAdd
465551 return err_remap (err);
466552 }
467553
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);
554+ // handle src destination if required
555+ if (pkt_info) {
556+ // Backup the bound address
557+ ip_addr_copy (bound_addr, s->conn ->pcb .udp ->local_ip );
558+ // replace it with the source address
559+ if (!ip_addr_isany (&src_addr)) {
560+ ip_addr_copy (s->conn ->pcb .udp ->local_ip , src_addr);
561+ }
472562 }
473563
474- return size;
475- }
564+ err = netconn_sendto (s->conn , buf, &ip_addr, address.get_port ());
476565
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;
566+ if (pkt_info) {
567+ // restore bound address
568+ ip_addr_copy (s-> conn -> pcb . udp -> local_ip , bound_addr) ;
569+ }
481570
482- err_t err = netconn_recv (s-> conn , & buf);
571+ netbuf_delete ( buf);
483572 if (err != ERR_OK) {
484573 return err_remap (err);
485574 }
486575
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;
576+ return size;
498577}
499578
500579int32_t LWIP::find_multicast_member (const struct mbed_lwip_socket *s, const nsapi_ip_mreq_t *imr)
@@ -687,6 +766,19 @@ nsapi_error_t LWIP::setsockopt(nsapi_socket_t handle, int level, int optname, co
687766 }
688767 s->conn ->pcb .ip ->tos = (u8_t )(*(const int *)optval);
689768 return 0 ;
769+
770+ case NSAPI_PKTINFO:
771+ // FIXME: Turn NETCONN_FLAG_PKTINFO off by default
772+ if (optlen != sizeof (int )) {
773+ return NSAPI_ERROR_UNSUPPORTED;
774+ }
775+ if (*(const int *)optval) {
776+ s->conn ->flags |= NETCONN_FLAG_PKTINFO;
777+ } else {
778+ s->conn ->flags &= ~NETCONN_FLAG_PKTINFO;
779+ }
780+ return 0 ;
781+
690782 default :
691783 return NSAPI_ERROR_UNSUPPORTED;
692784 }
0 commit comments