2828
2929#include <assert.h>
3030#include <errno.h>
31+ #include <string.h>
32+
33+ #include <sys/socket.h>
3134
3235#include <nuttx/cancelpt.h>
3336#include <nuttx/fs/fs.h>
37+ #include <nuttx/kmalloc.h>
3438#include <nuttx/net/net.h>
3539
3640#include "socket/socket.h"
@@ -145,11 +149,129 @@ ssize_t sendmsg(int sockfd, FAR const struct msghdr *msg, int flags)
145149 FAR struct socket * psock ;
146150 FAR struct file * filep ;
147151 ssize_t ret ;
152+ #ifdef CONFIG_BUILD_KERNEL
153+ struct msghdr kmsg ;
154+ struct msghdr umsg ;
155+ FAR struct iovec * uiov = NULL ;
156+ FAR uint8_t * kdata = NULL ;
157+ FAR void * kname = NULL ;
158+ FAR void * kcontrol = NULL ;
159+ FAR const struct msghdr * send_msg = msg ;
160+ size_t total_len ;
161+ size_t i ;
162+ FAR uint8_t * ptr ;
163+ #endif
148164
149165 /* sendmsg() is a cancellation point */
150166
151167 enter_cancellation_point ();
152168
169+ #ifdef CONFIG_BUILD_KERNEL
170+ /* Copy user msghdr, iovec array, and payload into kernel memory so the
171+ * network stack can safely memcpy from iov bases (see sendto()).
172+ */
173+
174+ memcpy (& umsg , msg , sizeof (struct msghdr ));
175+
176+ if (umsg .msg_iov == NULL )
177+ {
178+ ret = - EINVAL ;
179+ goto errout_with_cleanup ;
180+ }
181+
182+ if (umsg .msg_iovlen > 0 )
183+ {
184+ uiov = kmm_malloc (umsg .msg_iovlen * sizeof (struct iovec ));
185+ if (uiov == NULL )
186+ {
187+ ret = - ENOMEM ;
188+ goto errout_with_cleanup ;
189+ }
190+
191+ memcpy (uiov , msg -> msg_iov , umsg .msg_iovlen * sizeof (struct iovec ));
192+
193+ total_len = 0 ;
194+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
195+ {
196+ total_len += uiov [i ].iov_len ;
197+ }
198+
199+ if (total_len > 0 )
200+ {
201+ kdata = kmm_malloc (total_len );
202+ if (kdata == NULL )
203+ {
204+ ret = - ENOMEM ;
205+ goto errout_with_cleanup ;
206+ }
207+
208+ ptr = kdata ;
209+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
210+ {
211+ if (uiov [i ].iov_len > 0 )
212+ {
213+ memcpy (ptr , uiov [i ].iov_base , uiov [i ].iov_len );
214+ uiov [i ].iov_base = ptr ;
215+ ptr += uiov [i ].iov_len ;
216+ }
217+ else
218+ {
219+ uiov [i ].iov_base = NULL ;
220+ }
221+ }
222+ }
223+ else
224+ {
225+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
226+ {
227+ uiov [i ].iov_base = NULL ;
228+ }
229+ }
230+ }
231+
232+ memcpy (& kmsg , & umsg , sizeof (kmsg ));
233+ kmsg .msg_iov = uiov ;
234+ kmsg .msg_iovlen = umsg .msg_iovlen ;
235+
236+ if (umsg .msg_name != NULL && umsg .msg_namelen > 0 )
237+ {
238+ kname = kmm_malloc (umsg .msg_namelen );
239+ if (kname == NULL )
240+ {
241+ ret = - ENOMEM ;
242+ goto errout_with_cleanup ;
243+ }
244+
245+ memcpy (kname , umsg .msg_name , umsg .msg_namelen );
246+ kmsg .msg_name = (FAR struct sockaddr * )kname ;
247+ }
248+ else
249+ {
250+ kmsg .msg_name = NULL ;
251+ kmsg .msg_namelen = 0 ;
252+ }
253+
254+ if (umsg .msg_control != NULL && umsg .msg_controllen > 0 )
255+ {
256+ kcontrol = kmm_malloc (umsg .msg_controllen );
257+ if (kcontrol == NULL )
258+ {
259+ ret = - ENOMEM ;
260+ goto errout_with_cleanup ;
261+ }
262+
263+ memcpy (kcontrol , umsg .msg_control , umsg .msg_controllen );
264+ kmsg .msg_control = kcontrol ;
265+ }
266+ else
267+ {
268+ kmsg .msg_control = NULL ;
269+ kmsg .msg_controllen = 0 ;
270+ }
271+
272+ send_msg = & kmsg ;
273+ #endif
274+
153275 /* Get the underlying socket structure */
154276
155277 ret = sockfd_socket (sockfd , & filep , & psock );
@@ -158,10 +280,22 @@ ssize_t sendmsg(int sockfd, FAR const struct msghdr *msg, int flags)
158280
159281 if (ret == OK )
160282 {
283+ #ifdef CONFIG_BUILD_KERNEL
284+ ret = psock_sendmsg (psock , send_msg , flags );
285+ #else
161286 ret = psock_sendmsg (psock , msg , flags );
287+ #endif
162288 file_put (filep );
163289 }
164290
291+ #ifdef CONFIG_BUILD_KERNEL
292+ errout_with_cleanup :
293+ kmm_free (kcontrol );
294+ kmm_free (kname );
295+ kmm_free (kdata );
296+ kmm_free (uiov );
297+ #endif
298+
165299 if (ret < 0 )
166300 {
167301 set_errno (- ret );
0 commit comments