You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/02 14:09:43 UTC

[incubator-nuttx] 25/31: Socket: Control message addded initial stubs for sendmsg()

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch SocketCAN
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit b37b61614d4a843568bbac4dc4a0f92f5738224b
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Fri Mar 13 18:12:29 2020 +0100

    Socket: Control message addded initial stubs for sendmsg()
---
 arch/arm/src/s32k1xx/Kconfig           |   1 +
 arch/arm/src/s32k1xx/s32k1xx_flexcan.c |   9 +-
 include/netpacket/can.h                |   2 +
 include/nuttx/net/net.h                |   8 +-
 libs/libc/net/lib_recvmsg.c            |   4 +-
 libs/libc/net/lib_sendmsg.c            |   4 +-
 net/bluetooth/bluetooth_sockif.c       |   3 +-
 net/can/Kconfig                        |  20 ++++
 net/can/can.h                          |  16 +--
 net/can/can_getsockopt.c               |  21 ++++
 net/can/can_recvfrom.c                 | 191 +++++++++++++++------------------
 net/can/can_send.c                     |   4 +
 net/can/can_setsockopt.c               |  10 ++
 net/can/can_sockif.c                   |  51 ++++++++-
 net/icmp/icmp_sockif.c                 |   3 +-
 net/icmpv6/icmpv6_sockif.c             |   3 +-
 net/ieee802154/ieee802154_sockif.c     |   3 +-
 net/inet/inet_sockif.c                 |   3 +-
 net/local/local_sockif.c               |   3 +-
 net/netlink/netlink_sockif.c           |   3 +-
 net/pkt/pkt_sockif.c                   |   3 +-
 net/socket/Kconfig                     |  14 +--
 net/socket/Make.defs                   |   5 +-
 net/socket/recvmsg.c                   |   4 +-
 net/socket/{recvmsg.c => sendmsg.c}    |  68 ++++++------
 25 files changed, 280 insertions(+), 176 deletions(-)

diff --git a/arch/arm/src/s32k1xx/Kconfig b/arch/arm/src/s32k1xx/Kconfig
index 68f9bb6..41638d0 100644
--- a/arch/arm/src/s32k1xx/Kconfig
+++ b/arch/arm/src/s32k1xx/Kconfig
@@ -152,6 +152,7 @@ config S32K1XX_ENET
 
 config S32K1XX_FLEXCAN
 	bool "FLEXCAN"
+	select NET_CAN_HAVE_TX_DEADLINE
 	default n
 
 menuconfig S32K1XX_LPI2C0
diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
index 15e5b62..5c02aa0 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
@@ -433,10 +433,7 @@ static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
           mb->id.std = frame->can_id & MASKSTDID;
         }
 
-  #if 0
-      /* cs.rtr = frame.isRemoteTransmissionRequest(); */
-  #endif
-
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
       cs.dlc = frame->can_dlc;
 
       mb->data[0].w00 = __builtin_bswap32(*(uint32_t *)&frame->data[0]);
@@ -458,9 +455,7 @@ static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
           mb->id.std = frame->can_id & MASKSTDID;
         }
 
-#if 0
-      /* cs.rtr = frame.isRemoteTransmissionRequest(); */
-#endif
+      cs.rtr = frame->can_id & FLAGRTR ? 1 : 0;
 
       if (frame->len < 9)
         {
diff --git a/include/netpacket/can.h b/include/netpacket/can.h
index 4ea2104..bd0442d 100644
--- a/include/netpacket/can.h
+++ b/include/netpacket/can.h
@@ -75,6 +75,8 @@
                                  /* allow CAN FD frames (default:off) */
 #define CAN_RAW_JOIN_FILTERS   (__SO_PROTOCOL + 5)     
                                  /* all filters must match to trigger */
+#define CAN_RAW_TX_DEADLINE    (__SO_PROTOCOL + 6)
+                                 /* Abort frame when deadline has been passed */
 
 /****************************************************************************
  * Public Types
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 27c5fe9..055c865 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -217,7 +217,7 @@ struct sock_intf_s
                     FAR socklen_t *fromlen);
 #ifdef CONFIG_NET_RECVMSG_CMSG
   CODE ssize_t    (*si_recvmsg)(FAR struct socket *psock,
-                FAR struct msghdr *msg, int flags);
+		            FAR struct msghdr *msg, int flags);
 #endif
   CODE int        (*si_close)(FAR struct socket *psock);
 #ifdef CONFIG_NET_USRSOCK
@@ -507,9 +507,9 @@ FAR struct iob_s *net_ioballoc(bool throttled, enum iob_user_e consumerid);
  * Description:
  *   Check if the socket descriptor is valid for the provided TCB and if it
  *   supports the requested access.  This trivial operation is part of the
- *   fdopen() operation when the fdopen() is performed on a socket
- *   descriptor.  It simply performs some sanity checking before permitting
- *   the socket descriptor to be wrapped as a C FILE stream.
+ *   fdopen() operation when the fdopen() is performed on a socket descriptor.
+ *   It simply performs some sanity checking before permitting the socket
+ *   descriptor to be wrapped as a C FILE stream.
  *
  ****************************************************************************/
 
diff --git a/libs/libc/net/lib_recvmsg.c b/libs/libc/net/lib_recvmsg.c
index 5200acd..071c189 100644
--- a/libs/libc/net/lib_recvmsg.c
+++ b/libs/libc/net/lib_recvmsg.c
@@ -39,7 +39,7 @@
 
 #include <nuttx/config.h>
 
-#if defined(CONFIG_NET) && !defined(CONFIG_NET_RECVMSG_CMSG)
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -87,4 +87,4 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
     }
 }
 
-#endif /* CONFIG_NET && !CONFIG_NET_RECVMSG_CMSG */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/libs/libc/net/lib_sendmsg.c b/libs/libc/net/lib_sendmsg.c
index 0d09faa..9f98e51 100644
--- a/libs/libc/net/lib_sendmsg.c
+++ b/libs/libc/net/lib_sendmsg.c
@@ -39,7 +39,7 @@
 
 #include <nuttx/config.h>
 
-#ifdef CONFIG_NET
+#if defined(CONFIG_NET) && !defined(CONFIG_NET_CMSG)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -86,4 +86,4 @@ ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
     }
 }
 
-#endif /* CONFIG_NET */
+#endif /* CONFIG_NET && !CONFIG_NET_CMSG */
diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c
index fd6d95f..4057d93 100644
--- a/net/bluetooth/bluetooth_sockif.c
+++ b/net/bluetooth/bluetooth_sockif.c
@@ -109,8 +109,9 @@ const struct sock_intf_s g_bluetooth_sockif =
   NULL,                  /* si_sendfile */
 #endif
   bluetooth_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,                  /* si_recvmsg */
+  NULL,                  /* si_sendmsg */
 #endif
   bluetooth_close        /* si_close */
 };
diff --git a/net/can/Kconfig b/net/can/Kconfig
index 3b2e450..ac94021 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -18,6 +18,10 @@ config NET_CAN
 
 if NET_CAN
 
+config NET_CAN_HAVE_TX_DEADLINE
+	bool
+	default n
+
 config CAN_CONNS
 	int "Number of CAN connections"
 	default 4
@@ -27,9 +31,25 @@ config CAN_CONNS
 config NET_CAN_SOCK_OPTS
 	bool "sockopt support"
 	default n
+	select NET_SOCKOPTS
 	select NET_CANPROTO_OPTIONS
 	---help---
 		Enable support for the CAN socket options
+				
+config NET_CAN_RAW_TX_DEADLINE
+	bool "TX deadline sockopt"
+	default n
+	depends on NET_CAN_SOCK_OPTS && NET_CAN_HAVE_TX_DEADLINE
+	select NET_CMSG
+	---help---
+	    Note: Non-standard SocketCAN sockopt, but this options helps us in
+	    real-time use cases.
+	    
+		When the CAN_RAW_TX_DEADLINE sockopt is enabled. The user can send 
+		CAN frames using sendmsg() function and add a deadline timespec 
+		value in the CMSG data. When the deadline has been passed and the
+		CAN frame is still in the HW TX mailbox then the CAN driver will 
+		discard the CAN frame automatically.
 		
 config NET_CAN_RAW_FILTER_MAX
 	int "CAN_RAW_FILTER max filter count"
diff --git a/net/can/can.h b/net/can/can.h
index 7c6b614..00c297d 100644
--- a/net/can/can.h
+++ b/net/can/can.h
@@ -104,20 +104,23 @@ struct can_conn_s
    */
 
   struct can_poll_s pollinfo[4]; /* FIXME make dynamic */
-
+  
 #ifdef CONFIG_NET_CANPROTO_OPTIONS
   int32_t loopback;
   int32_t recv_own_msgs;
   int32_t fd_frames;
   struct can_filter filters[CONFIG_NET_CAN_RAW_FILTER_MAX];
   int32_t filter_count;
-
-  /* TODO add filter support */
+# ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+  int32_t tx_deadline;
+# endif
 #endif
-
+  
 #ifdef CONFIG_NET_TIMESTAMP
   FAR struct socket *psock; /* Needed to get SO_TIMESTAMP value */
 #endif
+
+  
 };
 
 /****************************************************************************
@@ -166,8 +169,8 @@ FAR struct can_conn_s *can_alloc(void);
  * Name: can_free()
  *
  * Description:
- *   Free a NetLink connection structure that is no longer in use. This
- *   should be done by the implementation of close().
+ *   Free a NetLink connection structure that is no longer in use. This should
+ *   be done by the implementation of close().
  *
  ****************************************************************************/
 
@@ -256,6 +259,7 @@ uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
  *
  ****************************************************************************/
 
+
 ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                      int flags, FAR struct sockaddr *from,
                      FAR socklen_t *fromlen);
diff --git a/net/can/can_getsockopt.c b/net/can/can_getsockopt.c
index 238695c..17184e2 100644
--- a/net/can/can_getsockopt.c
+++ b/net/can/can_getsockopt.c
@@ -188,6 +188,27 @@ int can_getsockopt(FAR struct socket *psock, int option,
       case CAN_RAW_JOIN_FILTERS:
         break;
 
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+      case CAN_RAW_TX_DEADLINE:
+        if (*value_len < sizeof(conn->tx_deadline))
+          {
+            /* REVISIT: POSIX says that we should truncate the value if it
+             * is larger than value_len.   That just doesn't make sense
+             * to me in this case.
+             */
+
+            ret              = -EINVAL;
+          }
+        else
+          {
+            FAR int *tx_deadline = (FAR int32_t *)value;
+            *tx_deadline         = conn->tx_deadline;
+            *value_len         = sizeof(conn->tx_deadline);
+            ret                = OK;
+          }
+        break;
+#endif
+
       default:
         nerr("ERROR: Unrecognized RAW CAN socket option: %d\n", option);
         ret = -ENOPROTOOPT;
diff --git a/net/can/can_recvfrom.c b/net/can/can_recvfrom.c
index 2211ed0..d9ed8cb 100644
--- a/net/can/can_recvfrom.c
+++ b/net/can/can_recvfrom.c
@@ -50,19 +50,20 @@
 #include <sys/time.h>
 #endif
 
+
 /****************************************************************************
  * Private Types
  ****************************************************************************/
 
 struct can_recvfrom_s
 {
-  FAR struct socket *pr_sock;          /* The parent socket structure */
+  FAR struct socket       *pr_sock;      /* The parent socket structure */
   FAR struct devif_callback_s *pr_cb;  /* Reference to callback instance */
   sem_t        pr_sem;                 /* Semaphore signals recv completion */
   size_t       pr_buflen;              /* Length of receive buffer */
   FAR uint8_t *pr_buffer;              /* Pointer to receive buffer */
   ssize_t      pr_recvlen;             /* The received length */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   size_t       pr_msglen;              /* Length of msg buffer */
   FAR uint8_t *pr_msgbuf;              /* Pointer to msg buffer */
 #endif
@@ -232,15 +233,14 @@ static inline void can_newdata(FAR struct net_driver_s *dev,
 
 static inline int can_readahead(struct can_recvfrom_s *pstate)
 {
-  FAR struct can_conn_s *conn =
-    (FAR struct can_conn_s *) pstate->pr_sock->s_conn;
+  FAR struct can_conn_s *conn = (FAR struct can_conn_s *)pstate->pr_sock->s_conn;
   FAR struct iob_s *iob;
   int recvlen;
 
   /* Check there is any CAN data already buffered in a read-ahead
    * buffer.
    */
-
+  
   pstate->pr_recvlen = -1;
 
   if ((iob = iob_peek_queue(&conn->readahead)) != NULL &&
@@ -287,16 +287,15 @@ static inline int can_readahead(struct can_recvfrom_s *pstate)
                              IOBUSER_NET_CAN_READAHEAD);
         }
 
-      /* do not pass frames with DLC > 8 to a legacy socket */
-
-      if (!conn->fd_frames)
-        {
-          struct canfd_frame *cfd = (struct canfd_frame *)pstate->pr_buffer;
-          if (cfd->len > CAN_MAX_DLEN)
-            {
-              return 0;
-            }
-        }
+	  /* do not pass frames with DLC > 8 to a legacy socket */
+	  if (!conn->fd_frames)
+	    {
+		  struct canfd_frame *cfd = (struct canfd_frame *)pstate->pr_buffer;
+		  if (cfd->len > CAN_MAX_DLEN)
+		    {
+	  			return 0;
+		    }
+	    }
 
       return recvlen;
     }
@@ -320,14 +319,13 @@ static inline int can_readahead(struct can_recvfrom_s *pstate)
  *   The network is locked.
  *
  ****************************************************************************/
-
 #ifdef CONFIG_NET_TIMESTAMP
-static inline int can_readahead_timestamp(struct can_conn_s *conn,
-                                          FAR uint8_t *buffer)
+static inline int can_readahead_timestamp(struct can_conn_s *conn, FAR uint8_t *buffer)
 {
   FAR struct iob_s *iob;
   int recvlen;
 
+
   if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
     {
       DEBUGASSERT(iob->io_pktlen > 0);
@@ -381,27 +379,26 @@ static inline int can_readahead_timestamp(struct can_conn_s *conn,
 #ifdef CONFIG_NET_CANPROTO_OPTIONS
 static int can_recv_filter(struct can_conn_s *conn, canid_t id)
 {
-  for (int i = 0; i < conn->filter_count; i++)
+  for(int i = 0; i < conn->filter_count; i++)
     {
-      if (conn->filters[i].can_id & CAN_INV_FILTER)
-        {
-          if ((id & conn->filters[i].can_mask) !=
-                ((conn->filters[i].can_id & ~CAN_INV_FILTER) &
-                conn->filters[i].can_mask))
-            {
-              return 1;
-            }
-        }
-      else
-        {
-          if ((id & conn->filters[i].can_mask) ==
-                (conn->filters[i].can_id & conn->filters[i].can_mask))
-            {
-              return 1;
-            }
-        }
+	  if (conn->filters[i].can_id & CAN_INV_FILTER)
+	    {
+		  if((id & conn->filters[i].can_mask) !=
+				  ((conn->filters[i].can_id & ~CAN_INV_FILTER)
+						  & conn->filters[i].can_mask))
+		    {
+			  return 1;
+		    }
+	    }
+	  else
+	    {
+		  if((id & conn->filters[i].can_mask) ==
+				  (conn->filters[i].can_id & conn->filters[i].can_mask))
+		    {
+			  return 1;
+		    }
+	    }
     }
-
   return 0;
 }
 #endif
@@ -419,50 +416,46 @@ static uint16_t can_recvfrom_eventhandler(FAR struct net_driver_s *dev,
     {
       if ((flags & CAN_NEWDATA) != 0)
         {
-          /* If a new packet is available, check receive filters
-           * when is valid then complete the read action.
-           */
+    	  /* If a new packet is available, check receive filters
+    	   * when is valid then complete the read action. */
 #ifdef CONFIG_NET_CANPROTO_OPTIONS
-          if (can_recv_filter(conn, (canid_t) *dev->d_appdata) == 0)
-            {
-              flags &= ~CAN_NEWDATA;
-              return flags;
-            }
+    	  if(can_recv_filter(conn,(canid_t)*dev->d_appdata) == 0)
+    	    {
+    		  flags &= ~CAN_NEWDATA;
+    	  	  return flags;
+    		}
 #endif
 
-          /* do not pass frames with DLC > 8 to a legacy socket */
-
-          if (!conn->fd_frames)
-            {
-              struct canfd_frame *cfd = (struct canfd_frame *)dev->d_appdata;
-              if (cfd->len > CAN_MAX_DLEN)
-                {
-                  /* DO WE NEED TO CLEAR FLAGS?? */
-
-                  flags &= ~CAN_NEWDATA;
-                  return flags;
-                }
-            }
+    	  /* do not pass frames with DLC > 8 to a legacy socket */
+    	  if (!conn->fd_frames)
+    	    {
+    		  struct canfd_frame *cfd = (struct canfd_frame*)dev->d_appdata;
+    	      if (cfd->len > CAN_MAX_DLEN)
+    	      {
+    	    	/* DO WE NEED TO CLEAR FLAGS?? */
+    	        flags &= ~CAN_NEWDATA;
+  	  			return flags;
+    	      }
+    	    }
 
           /* Copy the packet */
 
           can_newdata(dev, pstate);
 
 #ifdef CONFIG_NET_TIMESTAMP
-          if (pstate->pr_sock->s_timestamp)
-            {
-              if (pstate->pr_msglen == sizeof(struct timeval))
-                {
-                  can_readahead_timestamp(conn, pstate->pr_msgbuf);
-                }
-              else
-                {
-                  /* We still have to consume the data otherwise IOB gets full */
-
-                  uint8_t dummy_buf[sizeof(struct timeval)];
-                  can_readahead_timestamp(conn, &dummy_buf);
-                }
-            }
+		  if(pstate->pr_sock->s_timestamp)
+			{
+			  if(pstate->pr_msglen == sizeof(struct timeval))
+			    {
+				  can_readahead_timestamp(conn, pstate->pr_msgbuf);
+			    }
+			  else
+			    {
+				/* We still have to consume the data otherwise IOB gets full */
+				  uint8_t dummy_buf[sizeof(struct timeval)];
+				  can_readahead_timestamp(conn, &dummy_buf);
+			    }
+			}
 #endif
 
           /* We are finished. */
@@ -515,7 +508,6 @@ static ssize_t can_recvfrom_result(int result,
   if (pstate->pr_result < 0)
     {
       /* This might return EAGAIN on a timeout */
-
       return pstate->pr_result;
     }
 
@@ -600,10 +592,10 @@ ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
 
   ret = can_readahead(&state);
   if (ret > 0)
-    {
+    {      
       goto errout_with_state;
     }
-
+    
   ret = state.pr_recvlen;
 
   /* Handle non-blocking CAN sockets */
@@ -618,7 +610,7 @@ ssize_t can_recvfrom(FAR struct socket *psock, FAR void *buf,
         {
           /* Nothing was received */
 
-          ret = -EAGAIN;
+          ret = -EAGAIN;          
           goto errout_with_state;
         }
     }
@@ -683,7 +675,6 @@ errout_with_state:
  *   flags    Receive flags (ignored)
  *
  ****************************************************************************/
-
 #ifdef CONFIG_NET_RECVMSG_CMSG
 ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
                     size_t len, int flags)
@@ -716,22 +707,20 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
   nxsem_init(&state.pr_sem, 0, 0); /* Doesn't really fail */
   nxsem_setprotocol(&state.pr_sem, SEM_PRIO_NONE);
 
+
   state.pr_buflen = msg->msg_iov->iov_len;
   state.pr_buffer = msg->msg_iov->iov_base;
-
 #ifdef CONFIG_NET_TIMESTAMP
-  if (psock->s_timestamp && msg->msg_controllen ==
-        (sizeof(struct cmsghdr) + sizeof(struct timeval)))
+  if(psock->s_timestamp && msg->msg_controllen == (sizeof(struct cmsghdr) + sizeof(struct timeval)))
     {
-      struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
-      state.pr_msglen = sizeof(struct timeval);
-      state.pr_msgbuf = CMSG_DATA(cmsg);
-      cmsg->cmsg_level = SOL_SOCKET;
-      cmsg->cmsg_type = SO_TIMESTAMP;
-      cmsg->cmsg_len = state.pr_msglen;
+	  struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg);
+	  state.pr_msglen = sizeof(struct timeval);
+	  state.pr_msgbuf = CMSG_DATA(cmsg);
+	  cmsg->cmsg_level = SOL_SOCKET;
+	  cmsg->cmsg_type = SO_TIMESTAMP;
+	  cmsg->cmsg_len = state.pr_msglen;
     }
 #endif
-
   state.pr_sock   = psock;
 
   /* Handle any any CAN data already buffered in a read-ahead buffer.  NOTE
@@ -743,22 +732,20 @@ ssize_t can_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
   if (ret > 0)
     {
 #ifdef CONFIG_NET_TIMESTAMP
-      if (psock->s_timestamp)
-        {
-          if (state.pr_msglen == sizeof(struct timeval))
-            {
-              can_readahead_timestamp(conn, state.pr_msgbuf);
-            }
-          else
-            {
-              /* We still have to consume the data otherwise IOB gets full */
-
-              uint8_t dummy_buf[sizeof(struct timeval)];
-              can_readahead_timestamp(conn, &dummy_buf);
-            }
-        }
+	  if(psock->s_timestamp)
+	    {
+		  if(state.pr_msglen == sizeof(struct timeval))
+		    {
+			  can_readahead_timestamp(conn, state.pr_msgbuf);
+		    }
+		  else
+		    {
+			/* We still have to consume the data otherwise IOB gets full */
+		    uint8_t dummy_buf[sizeof(struct timeval)];
+			can_readahead_timestamp(conn, &dummy_buf);
+		    }
+	    }
 #endif
-
       goto errout_with_state;
     }
 
diff --git a/net/can/can_send.c b/net/can/can_send.c
index 644adc3..dfb03d0 100644
--- a/net/can/can_send.c
+++ b/net/can/can_send.c
@@ -76,6 +76,10 @@ struct send_s
   sem_t                   snd_sem;     /* Used to wake up the waiting thread */
   FAR const uint8_t      *snd_buffer;  /* Points to the buffer of data to send */
   size_t                  snd_buflen;  /* Number of bytes in the buffer to send */
+#ifdef CONFIG_NET_CMSG
+  size_t                  pr_msglen;   /* Length of msg buffer */
+  FAR uint8_t            *pr_msgbuf;   /* Pointer to msg buffer */
+#endif
   ssize_t                 snd_sent;    /* The number of bytes sent */
 };
 
diff --git a/net/can/can_setsockopt.c b/net/can/can_setsockopt.c
index 6858c1a..ac9f912 100644
--- a/net/can/can_setsockopt.c
+++ b/net/can/can_setsockopt.c
@@ -147,6 +147,16 @@ int can_setsockopt(FAR struct socket *psock, int option,
       case CAN_RAW_JOIN_FILTERS:
         break;
 
+#ifdef CONFIG_NET_CAN_RAW_TX_DEADLINE
+      case CAN_RAW_TX_DEADLINE:
+  		if (value_len != sizeof(conn->tx_deadline))
+  			return -EINVAL;
+
+  		conn->tx_deadline = *(FAR int32_t *)value;
+
+  		break;
+#endif
+
       default:
         nerr("ERROR: Unrecognized CAN option: %d\n", option);
         ret = -ENOPROTOOPT;
diff --git a/net/can/can_sockif.c b/net/can/can_sockif.c
index 737788e..09a61d0 100644
--- a/net/can/can_sockif.c
+++ b/net/can/can_sockif.c
@@ -69,6 +69,10 @@ static ssize_t can_send(FAR struct socket *psock,
 static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
               size_t len, int flags, FAR const struct sockaddr *to,
               socklen_t tolen);
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    size_t len, int flags);
+#endif
 static int can_close(FAR struct socket *psock);
 
 /****************************************************************************
@@ -93,8 +97,9 @@ const struct sock_intf_s g_can_sockif =
   NULL,             /* si_sendfile */
 #endif
   can_recvfrom,     /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   can_recvmsg,      /* si_recvmsg */
+  can_sendmsg,      /* si_sendmsg */
 #endif
   can_close         /* si_close */
 };
@@ -774,6 +779,50 @@ static ssize_t can_sendto(FAR struct socket *psock, FAR const void *buf,
 }
 
 /****************************************************************************
+ * Name: can_sendmsg
+ *
+ * Description:
+ *   The can_sendmsg() send a CAN frame to psock
+ *
+ * Input Parameters:
+ *   psock - An instance of the internal socket structure.
+ *   msg   - CAN frame and optional CMSG
+ *   flags - Send flags (ignored)
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error, a negated
+ *   errno value is returned (see send() for the list of appropriate error
+ *   values.
+ *
+ ****************************************************************************/
+#ifdef CONFIG_NET_CMSG
+static ssize_t can_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+                    size_t len, int flags);
+{
+  ssize_t ret;
+
+  /* Only SOCK_RAW is supported */
+
+  if (psock->s_type == SOCK_RAW)
+    {
+      /* Raw packet send */
+
+      ret = psock_can_send(psock, buf, len);
+    }
+  else
+    {
+      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
+       * no peer address is set.
+       */
+
+      ret = -EDESTADDRREQ;
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
  * Name: can_close
  *
  * Description:
diff --git a/net/icmp/icmp_sockif.c b/net/icmp/icmp_sockif.c
index c81592e..ebe2bab 100644
--- a/net/icmp/icmp_sockif.c
+++ b/net/icmp/icmp_sockif.c
@@ -102,8 +102,9 @@ const struct sock_intf_s g_icmp_sockif =
   NULL,             /* si_sendfile */
 #endif
   icmp_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,             /* si_recvmsg */
+  NULL,             /* si_sendmsg */
 #endif
   icmp_close        /* si_close */
 };
diff --git a/net/icmpv6/icmpv6_sockif.c b/net/icmpv6/icmpv6_sockif.c
index 29e5e47..5adae60 100644
--- a/net/icmpv6/icmpv6_sockif.c
+++ b/net/icmpv6/icmpv6_sockif.c
@@ -102,8 +102,9 @@ const struct sock_intf_s g_icmpv6_sockif =
   NULL,               /* si_sendfile */
 #endif
   icmpv6_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,               /* si_recvmsg */
+  NULL,               /* si_sendmsg */
 #endif
   icmpv6_close        /* si_close */
 };
diff --git a/net/ieee802154/ieee802154_sockif.c b/net/ieee802154/ieee802154_sockif.c
index d1ac29b..6c0f88a 100644
--- a/net/ieee802154/ieee802154_sockif.c
+++ b/net/ieee802154/ieee802154_sockif.c
@@ -107,8 +107,9 @@ const struct sock_intf_s g_ieee802154_sockif =
   NULL,                   /* si_sendfile */
 #endif
   ieee802154_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,                   /* si_recvmsg */
+  NULL,                   /* si_sendmsg */
 #endif
   ieee802154_close        /* si_close */
 };
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index 2a09c45..488f2d1 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -117,8 +117,9 @@ static const struct sock_intf_s g_inet_sockif =
   inet_sendfile,    /* si_sendfile */
 #endif
   inet_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,             /* si_recvmsg */
+  NULL,             /* si_sendmsg */
 #endif
   inet_close        /* si_close */
 };
diff --git a/net/local/local_sockif.c b/net/local/local_sockif.c
index 62d56b5..cd9bd66 100644
--- a/net/local/local_sockif.c
+++ b/net/local/local_sockif.c
@@ -110,8 +110,9 @@ const struct sock_intf_s g_local_sockif =
   NULL,              /* si_sendfile */
 #endif
   local_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,              /* si_recvmsg */
+  NULL,              /* si_sendmsg */
 #endif
   local_close        /* si_close */
 };
diff --git a/net/netlink/netlink_sockif.c b/net/netlink/netlink_sockif.c
index 970aed4..34b011a 100644
--- a/net/netlink/netlink_sockif.c
+++ b/net/netlink/netlink_sockif.c
@@ -111,8 +111,9 @@ const struct sock_intf_s g_netlink_sockif =
   NULL,                 /* si_sendfile */
 #endif
   netlink_recvfrom,     /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,                 /* si_recvmsg */
+  NULL,                 /* si_sendmsg */
 #endif
   netlink_close         /* si_close */
 };
diff --git a/net/pkt/pkt_sockif.c b/net/pkt/pkt_sockif.c
index bbabf42..dbf3e3c 100644
--- a/net/pkt/pkt_sockif.c
+++ b/net/pkt/pkt_sockif.c
@@ -108,8 +108,9 @@ const struct sock_intf_s g_pkt_sockif =
   NULL,            /* si_sendfile */
 #endif
   pkt_recvfrom,    /* si_recvfrom */
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
   NULL,            /* si_recvmsg */
+  NULL,            /* si_sendmsg */
 #endif
   pkt_close        /* si_close */
 };
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index f4c9408..f13e22d 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -58,18 +58,20 @@ config NET_SOLINGER
 config NET_TIMESTAMP
 	bool "SO_TIMESTAMP socket option"
 	default n
-	depends on NET_CAN && NET_RECVMSG_CMSG
+	depends on NET_CAN
+	select NET_CMSG
 	---help---
 		Enable or disable support for the SO_TIMESTAMP socket option. Currently only tested & implemented in SocketCAN but should work on all sockets
 
 endif # NET_SOCKOPTS
 
-config NET_RECVMSG_CMSG
-	bool "recvmsg() control messages (CMSG) support"
+config NET_CMSG
+	bool "Control messages (CMSG) support"
 	default n
 	---help---
-		Enable or disable support for control messages in the recvmsg function.
-		Control messages (also defined in POSIX 1003.1g as ancillary data object information).
-		Includes additional information on the packet received.
+		Enable or disable support for control messages in the recvmsg() and
+		sendmsg() function. Control messages (also defined in POSIX 1003.1g 
+		as ancillary data object information). Includes additional 
+		information on the packet received or to be transmitted.
 
 endmenu # Socket Support
diff --git a/net/socket/Make.defs b/net/socket/Make.defs
index 2be9dbf..6bf79ed 100644
--- a/net/socket/Make.defs
+++ b/net/socket/Make.defs
@@ -75,7 +75,8 @@ endif
 DEPPATH += --dep-path socket
 VPATH += :socket
 
-# Support for recvmsg() with control messages (CMSG)
-ifeq ($(CONFIG_NET_RECVMSG_CMSG),y)
+# Support for control messages (CMSG)
+ifeq ($(CONFIG_NET_CMSG),y)
 SOCK_CSRCS += recvmsg.c
+SOCK_CSRCS += sendmsg.c
 endif
diff --git a/net/socket/recvmsg.c b/net/socket/recvmsg.c
index 17d4dfe..800eeb1 100644
--- a/net/socket/recvmsg.c
+++ b/net/socket/recvmsg.c
@@ -47,7 +47,7 @@
 
 #include "socket/socket.h"
 
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
 
 /****************************************************************************
  * Public Functions
@@ -235,4 +235,4 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
   return ret;
 }
 
-#endif /* CONFIG_NET_RECVMSG_CMSG */
+#endif /* CONFIG_NET_CMSG */
diff --git a/net/socket/recvmsg.c b/net/socket/sendmsg.c
similarity index 78%
copy from net/socket/recvmsg.c
copy to net/socket/sendmsg.c
index 17d4dfe..3bc32e8 100644
--- a/net/socket/recvmsg.c
+++ b/net/socket/sendmsg.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * net/socket/recvmsg.c
+ * net/socket/sendmsg.c
  *
  *   Copyright (C) 2007-2009, 2011-2017, 2019 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org>
@@ -47,20 +47,20 @@
 
 #include "socket/socket.h"
 
-#ifdef CONFIG_NET_RECVMSG_CMSG
+#ifdef CONFIG_NET_CMSG
 
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: psock_recvmsg
+ * Name: psock_sendmsg
  *
  * Description:
- *   psock_recvfrom() receives messages from a socket, and may be used to
- *   receive data on a socket whether or not it is connection-oriented.
+ *   psock_sendfrom() sends messages to a socket, and may be used to
+ *   send data on a socket whether or not it is connection-oriented.
  *   This is an internal OS interface.  It is functionally equivalent to
- *   recvfrom() except that:
+ *   sendfrom() except that:
  *
  *   - It is not a cancellation point,
  *   - It does not modify the errno variable, and
@@ -69,20 +69,20 @@
  *
  * Input Parameters:
  *   psock   - A pointer to a NuttX-specific, internal socket structure
- *   msg      Buffer to receive msg
+ *   msg     - Buffer to of the msg
  *   len     - Length of buffer
  *   flags   - Receive flags
  *
  * Returned Value:
  *   On success, returns the number of characters sent.  If no data is
  *   available to be received and the peer has performed an orderly shutdown,
- *   recv() will return 0.  Otherwise, on any failure, a negated errno value
+ *   send() will return 0.  Otherwise, on any failure, a negated errno value
  *   is returned (see comments with send() for a list of appropriate errno
  *   values).
  *
  ****************************************************************************/
 
-ssize_t psock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
+ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
                        int flags)
 {
   /* Verify that non-NULL pointers were passed */
@@ -103,38 +103,38 @@ ssize_t psock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
       return -EBADF;
     }
 
-  /* Let logic specific to this address family handle the recvfrom()
+  /* Let logic specific to this address family handle the sendfrom()
    * operation.
    */
 
   DEBUGASSERT(psock->s_sockif != NULL &&
-              (psock->s_sockif->si_recvmsg != NULL ||
-               psock->s_sockif->si_recvfrom != NULL));
+              (psock->s_sockif->si_sendmsg != NULL ||
+               psock->s_sockif->si_sendto != NULL));
 
-  if(psock->s_sockif->si_recvmsg != NULL)
+  if(psock->s_sockif->si_sendmsg != NULL)
     {
-	  return psock->s_sockif->si_recvmsg(psock, msg, flags);
+	  return psock->s_sockif->si_sendmsg(psock, msg, flags);
     }
   else
     {
-	  /* Socket doesn't implement si_recvmsg fallback to si_recvfrom */
-	  FAR void *buf             = msg->msg_iov->iov_base;
-	  FAR struct sockaddr *from = msg->msg_name;
-	  FAR socklen_t *fromlen    = (FAR socklen_t *)&msg->msg_namelen;
-	  size_t len                = msg->msg_iov->iov_len;
-	  return psock->s_sockif->si_recvfrom(psock, buf, len, flags, from, fromlen);
+	  /* Socket doesn't implement si_sendmsg fallback to si_sendto */
+	  FAR void *buf           = msg->msg_iov->iov_base;
+	  FAR struct sockaddr *to = msg->msg_name;
+	  socklen_t tolen         = msg->msg_namelen;
+	  size_t len              = msg->msg_iov->iov_len;
+	  return psock->s_sockif->si_sendto(psock, buf, len, flags, to, tolen);
     }
 
 }
 
 /****************************************************************************
- * Name: nx_recvfrom
+ * Name: nx_sendfrom
  *
  * Description:
- *   nx_recvfrom() receives messages from a socket, and may be used to
+ *   nx_sendfrom() receives messages from a socket, and may be used to
  *   receive data on a socket whether or not it is connection-oriented.
  *   This is an internal OS interface.  It is functionally equivalent to
- *   recvfrom() except that:
+ *   sendfrom() except that:
  *
  *   - It is not a cancellation point, and
  *   - It does not modify the errno variable.
@@ -148,13 +148,13 @@ ssize_t psock_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
  * Returned Value:
  *   On success, returns the number of characters sent.  If no data is
  *   available to be received and the peer has performed an orderly shutdown,
- *   recv() will return 0.  Otherwise, on any failure, a negated errno value
+ *   send() will return 0.  Otherwise, on any failure, a negated errno value
  *   is returned (see comments with send() for a list of appropriate errno
  *   values).
  *
  ****************************************************************************/
 
-ssize_t nx_recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+ssize_t nx_sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
 {
   FAR struct socket *psock;
 
@@ -162,16 +162,16 @@ ssize_t nx_recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
 
   psock = sockfd_socket(sockfd);
 
-  /* Then let psock_recvmsg() do all of the work */
+  /* Then let psock_sendmsg() do all of the work */
 
-  return psock_recvmsg(psock, msg, flags);
+  return psock_sendmsg(psock, msg, flags);
 }
 
 /****************************************************************************
- * Function: recvmsg
+ * Function: sendmsg
  *
  * Description:
- *   The recvmsg() call is identical to recvfrom() with a NULL from parameter.
+ *   The sendmsg() call is identical to sendfrom() with a NULL from parameter.
  *
  * Parameters:
  *   sockfd   Socket descriptor of socket
@@ -209,12 +209,12 @@ ssize_t nx_recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
  *
  ****************************************************************************/
 
-ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
+ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags)
 {
   FAR struct socket *psock;
   ssize_t ret;
 
-  /* recvfrom() is a cancellation point */
+  /* sendfrom() is a cancellation point */
 
   enter_cancellation_point();
 
@@ -222,9 +222,9 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
 
   psock = sockfd_socket(sockfd);
 
-  /* Let psock_recvfrom() do all of the work */
+  /* Let psock_sendfrom() do all of the work */
 
-  ret = psock_recvmsg(psock, msg, flags);
+  ret = psock_sendmsg(psock, msg, flags);
   if (ret < 0)
     {
       _SO_SETERRNO(psock, -ret);
@@ -235,4 +235,4 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
   return ret;
 }
 
-#endif /* CONFIG_NET_RECVMSG_CMSG */
+#endif /* CONFIG_NET_CMSG */