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"
@@ -165,11 +169,139 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
165169 FAR struct socket * psock ;
166170 FAR struct file * filep ;
167171 ssize_t ret ;
172+ #ifdef CONFIG_BUILD_KERNEL
173+ struct msghdr kmsg ;
174+ struct msghdr umsg ;
175+ FAR struct msghdr * recv_msg = msg ;
176+ FAR struct iovec * user_iov = NULL ;
177+ FAR struct iovec * kiov = NULL ;
178+ FAR uint8_t * kdata = NULL ;
179+ FAR void * kname = NULL ;
180+ FAR void * kcontrol = NULL ;
181+ size_t total_len ;
182+ size_t i ;
183+ FAR uint8_t * ptr ;
184+ ssize_t remaining ;
185+ size_t chunk ;
186+ #endif
168187
169188 /* recvmsg() is a cancellation point */
170189
171190 enter_cancellation_point ();
172191
192+ #ifdef CONFIG_BUILD_KERNEL
193+ /* Receive into kernel buffers, then copy out to the user msghdr (see
194+ * recvfrom()).
195+ */
196+
197+ memcpy (& umsg , msg , sizeof (struct msghdr ));
198+
199+ if (umsg .msg_iov == NULL )
200+ {
201+ ret = - EINVAL ;
202+ goto errout_with_cleanup ;
203+ }
204+
205+ if (umsg .msg_iovlen > 0 )
206+ {
207+ user_iov = kmm_malloc (umsg .msg_iovlen * sizeof (struct iovec ));
208+ if (user_iov == NULL )
209+ {
210+ ret = - ENOMEM ;
211+ goto errout_with_cleanup ;
212+ }
213+
214+ memcpy (user_iov , msg -> msg_iov , umsg .msg_iovlen * sizeof (struct iovec ));
215+
216+ kiov = kmm_malloc (umsg .msg_iovlen * sizeof (struct iovec ));
217+ if (kiov == NULL )
218+ {
219+ ret = - ENOMEM ;
220+ goto errout_with_cleanup ;
221+ }
222+
223+ total_len = 0 ;
224+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
225+ {
226+ total_len += user_iov [i ].iov_len ;
227+ }
228+
229+ if (total_len > 0 )
230+ {
231+ kdata = kmm_malloc (total_len );
232+ if (kdata == NULL )
233+ {
234+ ret = - ENOMEM ;
235+ goto errout_with_cleanup ;
236+ }
237+
238+ ptr = kdata ;
239+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
240+ {
241+ if (user_iov [i ].iov_len > 0 )
242+ {
243+ kiov [i ].iov_base = ptr ;
244+ kiov [i ].iov_len = user_iov [i ].iov_len ;
245+ ptr += user_iov [i ].iov_len ;
246+ }
247+ else
248+ {
249+ kiov [i ].iov_base = NULL ;
250+ kiov [i ].iov_len = 0 ;
251+ }
252+ }
253+ }
254+ else
255+ {
256+ for (i = 0 ; i < umsg .msg_iovlen ; i ++ )
257+ {
258+ kiov [i ].iov_base = NULL ;
259+ kiov [i ].iov_len = 0 ;
260+ }
261+ }
262+ }
263+
264+ memcpy (& kmsg , & umsg , sizeof (kmsg ));
265+ kmsg .msg_iov = kiov ;
266+ kmsg .msg_iovlen = umsg .msg_iovlen ;
267+
268+ if (umsg .msg_name != NULL && umsg .msg_namelen > 0 )
269+ {
270+ kname = kmm_malloc (umsg .msg_namelen );
271+ if (kname == NULL )
272+ {
273+ ret = - ENOMEM ;
274+ goto errout_with_cleanup ;
275+ }
276+
277+ kmsg .msg_name = (FAR struct sockaddr * )kname ;
278+ }
279+ else
280+ {
281+ kmsg .msg_name = NULL ;
282+ kmsg .msg_namelen = 0 ;
283+ }
284+
285+ if (umsg .msg_control != NULL && umsg .msg_controllen > 0 )
286+ {
287+ kcontrol = kmm_malloc (umsg .msg_controllen );
288+ if (kcontrol == NULL )
289+ {
290+ ret = - ENOMEM ;
291+ goto errout_with_cleanup ;
292+ }
293+
294+ kmsg .msg_control = kcontrol ;
295+ }
296+ else
297+ {
298+ kmsg .msg_control = NULL ;
299+ kmsg .msg_controllen = 0 ;
300+ }
301+
302+ recv_msg = & kmsg ;
303+ #endif
304+
173305 /* Get the underlying socket structure */
174306
175307 ret = sockfd_socket (sockfd , & filep , & psock );
@@ -178,10 +310,50 @@ ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags)
178310
179311 if (ret == OK )
180312 {
313+ #ifdef CONFIG_BUILD_KERNEL
314+ ret = psock_recvmsg (psock , recv_msg , flags );
315+ #else
181316 ret = psock_recvmsg (psock , msg , flags );
317+ #endif
182318 file_put (filep );
183319 }
184320
321+ #ifdef CONFIG_BUILD_KERNEL
322+ if (ret >= 0 )
323+ {
324+ remaining = ret ;
325+ for (i = 0 ; i < umsg .msg_iovlen && remaining > 0 ; i ++ )
326+ {
327+ chunk = kiov [i ].iov_len < (size_t )remaining ? kiov [i ].iov_len :
328+ (size_t )remaining ;
329+ memcpy (user_iov [i ].iov_base , kiov [i ].iov_base , chunk );
330+ remaining -= (ssize_t )chunk ;
331+ }
332+
333+ msg -> msg_namelen = kmsg .msg_namelen ;
334+ if (umsg .msg_name != NULL && kmsg .msg_namelen > 0 )
335+ {
336+ memcpy (umsg .msg_name , kname , kmsg .msg_namelen );
337+ }
338+
339+ msg -> msg_flags = kmsg .msg_flags ;
340+
341+ if (umsg .msg_control != NULL && umsg .msg_controllen > 0 )
342+ {
343+ memcpy (umsg .msg_control , kcontrol , kmsg .msg_controllen );
344+ }
345+
346+ msg -> msg_controllen = kmsg .msg_controllen ;
347+ }
348+
349+ errout_with_cleanup :
350+ kmm_free (kcontrol );
351+ kmm_free (kname );
352+ kmm_free (kdata );
353+ kmm_free (kiov );
354+ kmm_free (user_iov );
355+ #endif
356+
185357 if (ret < 0 )
186358 {
187359 set_errno (- ret );
0 commit comments