netbsd32_socket.c revision 1.49 1 /* $NetBSD: netbsd32_socket.c,v 1.49 2018/11/14 17:51:37 hannken Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2001 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_socket.c,v 1.49 2018/11/14 17:51:37 hannken Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #define msg __msg /* Don't ask me! */
35 #include <sys/mount.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/socketvar.h>
39 #include <sys/mbuf.h>
40 #include <sys/ktrace.h>
41 #include <sys/file.h>
42 #include <sys/filedesc.h>
43 #include <sys/syscallargs.h>
44 #include <sys/proc.h>
45 #include <sys/dirent.h>
46
47 #include <compat/netbsd32/netbsd32.h>
48 #include <compat/netbsd32/netbsd32_syscallargs.h>
49 #include <compat/netbsd32/netbsd32_conv.h>
50
51 /*
52 * XXX Assumes that struct sockaddr is compatible.
53 */
54
55 #define CMSG32_ALIGN(n) (((n) + ALIGNBYTES32) & ~ALIGNBYTES32)
56 #define CMSG32_ASIZE CMSG32_ALIGN(sizeof(struct cmsghdr))
57 #define CMSG32_DATA(cmsg) (__CASTV(u_char *, cmsg) + CMSG32_ASIZE)
58 #define CMSG32_MSGNEXT(ucmsg, kcmsg) \
59 (__CASTV(char *, kcmsg) + CMSG32_ALIGN((ucmsg)->cmsg_len))
60 #define CMSG32_MSGEND(mhdr) \
61 (__CASTV(char *, (mhdr)->msg_control) + (mhdr)->msg_controllen)
62
63 #define CMSG32_NXTHDR(mhdr, ucmsg, kcmsg) \
64 __CASTV(struct cmsghdr *, \
65 CMSG32_MSGNEXT(ucmsg, kcmsg) + \
66 CMSG32_ASIZE > CMSG32_MSGEND(mhdr) ? 0 : \
67 CMSG32_MSGNEXT(ucmsg, kcmsg))
68 #define CMSG32_FIRSTHDR(mhdr) \
69 __CASTV(struct cmsghdr *, \
70 (mhdr)->msg_controllen < sizeof(struct cmsghdr) ? 0 : \
71 (mhdr)->msg_control)
72
73 #define CMSG32_SPACE(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + CMSG32_ALIGN(l))
74 #define CMSG32_LEN(l) (CMSG32_ALIGN(sizeof(struct cmsghdr)) + (l))
75
76 static int
77 copyout32_msg_control_mbuf(struct lwp *l, struct msghdr *mp, int *len,
78 struct mbuf *m, char **q, bool *truncated)
79 {
80 struct cmsghdr *cmsg, cmsg32;
81 int i, j, error;
82
83 *truncated = false;
84 cmsg = mtod(m, struct cmsghdr *);
85 do {
86 if ((char *)cmsg == mtod(m, char *) + m->m_len)
87 break;
88 if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
89 return EINVAL;
90 cmsg32 = *cmsg;
91 j = cmsg->cmsg_len - CMSG_LEN(0);
92 i = cmsg32.cmsg_len = CMSG32_LEN(j);
93 if (i > *len) {
94 mp->msg_flags |= MSG_CTRUNC;
95 if (cmsg->cmsg_level == SOL_SOCKET
96 && cmsg->cmsg_type == SCM_RIGHTS) {
97 *truncated = true;
98 return 0;
99 }
100 j -= i - *len;
101 i = *len;
102 }
103
104 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
105 error = copyout(&cmsg32, *q, MIN(i, sizeof(cmsg32)));
106 if (error)
107 return (error);
108 if (i > CMSG32_LEN(0)) {
109 error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0),
110 i - CMSG32_LEN(0));
111 if (error)
112 return (error);
113 }
114 j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
115 if (*len >= j) {
116 *len -= j;
117 *q += j;
118 } else {
119 *q += i;
120 *len = 0;
121 }
122 cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
123 } while (*len > 0);
124
125 return 0;
126 }
127
128 static int
129 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
130 {
131 int len, error = 0;
132 struct mbuf *m;
133 char *q;
134 bool truncated;
135
136 len = mp->msg_controllen;
137 if (len <= 0 || control == 0) {
138 mp->msg_controllen = 0;
139 free_control_mbuf(l, control, control);
140 return 0;
141 }
142
143 q = (char *)mp->msg_control;
144
145 for (m = control; len > 0 && m != NULL; m = m->m_next) {
146 error = copyout32_msg_control_mbuf(l, mp, &len, m, &q,
147 &truncated);
148 if (truncated) {
149 m = control;
150 break;
151 }
152 if (error)
153 break;
154 }
155
156 free_control_mbuf(l, control, m);
157
158 mp->msg_controllen = q - (char *)mp->msg_control;
159 return error;
160 }
161
162 static int
163 msg_recv_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
164 struct msghdr *msg, struct iovec *aiov)
165 {
166 int error;
167 size_t iovsz;
168 struct iovec *iov = aiov;
169
170 iovsz = msg32->msg_iovlen * sizeof(struct iovec);
171 if (msg32->msg_iovlen > UIO_SMALLIOV) {
172 if (msg32->msg_iovlen > IOV_MAX)
173 return EMSGSIZE;
174 iov = kmem_alloc(iovsz, KM_SLEEP);
175 }
176
177 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32->msg_iov), iov,
178 msg32->msg_iovlen);
179 if (error)
180 goto out;
181
182 netbsd32_to_msghdr(msg32, msg);
183 msg->msg_iov = iov;
184 out:
185 if (iov != aiov)
186 kmem_free(iov, iovsz);
187 return error;
188 }
189
190 static int
191 msg_recv_copyout(struct lwp *l, struct netbsd32_msghdr *msg32,
192 struct msghdr *msg, struct netbsd32_msghdr *arg,
193 struct mbuf *from, struct mbuf *control)
194 {
195 int error = 0;
196
197 if (msg->msg_control != NULL)
198 error = copyout32_msg_control(l, msg, control);
199
200 if (error == 0)
201 error = copyout_sockname(msg->msg_name, &msg->msg_namelen, 0,
202 from);
203
204 if (from != NULL)
205 m_free(from);
206 if (error)
207 return error;
208
209 msg32->msg_namelen = msg->msg_namelen;
210 msg32->msg_controllen = msg->msg_controllen;
211 msg32->msg_flags = msg->msg_flags;
212 ktrkuser("msghdr", msg, sizeof(*msg));
213 if (arg == NULL)
214 return 0;
215 return copyout(msg32, arg, sizeof(*arg));
216 }
217
218 int
219 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap,
220 register_t *retval)
221 {
222 /* {
223 syscallarg(int) s;
224 syscallarg(netbsd32_msghdrp_t) msg;
225 syscallarg(int) flags;
226 } */
227 struct netbsd32_msghdr msg32;
228 struct iovec aiov[UIO_SMALLIOV];
229 struct msghdr msg;
230 int error;
231 struct mbuf *from, *control;
232
233 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
234 if (error)
235 return (error);
236
237 if ((error = msg_recv_copyin(l, &msg32, &msg, aiov)) != 0)
238 return error;
239
240 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
241 error = do_sys_recvmsg(l, SCARG(uap, s), &msg,
242 &from, msg.msg_control != NULL ? &control : NULL, retval);
243 if (error != 0)
244 goto out;
245
246 error = msg_recv_copyout(l, &msg32, &msg, SCARG_P32(uap, msg),
247 from, control);
248 out:
249 if (msg.msg_iov != aiov)
250 kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
251 return error;
252 }
253
254 int
255 netbsd32_recvmmsg(struct lwp *l, const struct netbsd32_recvmmsg_args *uap,
256 register_t *retval)
257 {
258 /* {
259 syscallarg(int) s;
260 syscallarg(netbsd32_mmsghdr_t) mmsg;
261 syscallarg(unsigned int) vlen;
262 syscallarg(unsigned int) flags;
263 syscallarg(netbsd32_timespecp_t) timeout;
264 } */
265 struct mmsghdr mmsg;
266 struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
267 struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
268 struct socket *so;
269 struct msghdr *msg = &mmsg.msg_hdr;
270 int error, s;
271 struct mbuf *from, *control;
272 struct timespec ts, now;
273 struct netbsd32_timespec ts32;
274 unsigned int vlen, flags, dg;
275 struct iovec aiov[UIO_SMALLIOV];
276
277 ts.tv_sec = 0; // XXX: gcc
278 ts.tv_nsec = 0;
279 if (SCARG_P32(uap, timeout)) {
280 if ((error = copyin(SCARG_P32(uap, timeout), &ts32,
281 sizeof(ts32))) != 0)
282 return error;
283 getnanotime(&now);
284 netbsd32_to_timespec(&ts32, &ts);
285 timespecadd(&now, &ts, &ts);
286 }
287
288 s = SCARG(uap, s);
289 if ((error = fd_getsock(s, &so)) != 0)
290 return error;
291
292 /*
293 * If so->so_rerror holds a deferred error return it now.
294 */
295 if (so->so_rerror) {
296 error = so->so_rerror;
297 so->so_rerror = 0;
298 fd_putfile(s);
299 return error;
300 }
301
302 vlen = SCARG(uap, vlen);
303 if (vlen > 1024)
304 vlen = 1024;
305
306 from = NULL;
307 flags = SCARG(uap, flags) & MSG_USERFLAGS;
308
309 for (dg = 0; dg < vlen;) {
310 error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
311 if (error)
312 break;
313
314 if ((error = msg_recv_copyin(l, msg32, msg, aiov)) != 0)
315 return error;
316
317 msg->msg_flags = flags & ~MSG_WAITFORONE;
318
319 if (from != NULL) {
320 m_free(from);
321 from = NULL;
322 }
323
324 error = do_sys_recvmsg_so(l, s, so, msg, &from,
325 msg->msg_control != NULL ? &control : NULL, retval);
326 if (error) {
327 if (error == EAGAIN && dg > 0)
328 error = 0;
329 break;
330 }
331 error = msg_recv_copyout(l, msg32, msg, NULL,
332 from, control);
333 from = NULL;
334 if (error)
335 break;
336
337 mmsg32.msg_len = *retval;
338
339 error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
340 if (error)
341 break;
342
343 dg++;
344 if (msg->msg_flags & MSG_OOB)
345 break;
346
347 if (SCARG_P32(uap, timeout)) {
348 getnanotime(&now);
349 timespecsub(&now, &ts, &now);
350 if (now.tv_sec > 0)
351 break;
352 }
353
354 if (flags & MSG_WAITFORONE)
355 flags |= MSG_DONTWAIT;
356
357 }
358
359 if (from != NULL)
360 m_free(from);
361
362 *retval = dg;
363
364 /*
365 * If we succeeded at least once, return 0, hopefully so->so_rerror
366 * will catch it next time.
367 */
368 if (error && dg > 0) {
369 so->so_rerror = error;
370 error = 0;
371 }
372
373 fd_putfile(s);
374
375 return error;
376 }
377
378 static int
379 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
380 {
381 /*
382 * Handle cmsg if there is any.
383 */
384 struct cmsghdr *cmsg, cmsg32, *cc;
385 struct mbuf *ctl_mbuf;
386 ssize_t resid = mp->msg_controllen;
387 size_t clen, cidx = 0, cspace;
388 u_int8_t *control;
389 int error;
390
391 ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
392 clen = MLEN;
393 control = mtod(ctl_mbuf, void *);
394 memset(control, 0, clen);
395
396 for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
397 {
398 error = copyin(cc, &cmsg32, sizeof(cmsg32));
399 if (error)
400 goto failure;
401
402 /*
403 * Sanity check the control message length.
404 */
405 if (cmsg32.cmsg_len > resid ||
406 cmsg32.cmsg_len < sizeof(cmsg32)) {
407 error = EINVAL;
408 goto failure;
409 }
410
411 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
412
413 /* Check the buffer is big enough */
414 if (__predict_false(cidx + cspace > clen)) {
415 u_int8_t *nc;
416 size_t nclen;
417
418 nclen = cidx + cspace;
419 if (nclen >= PAGE_SIZE) {
420 error = EINVAL;
421 goto failure;
422 }
423 nc = realloc(clen <= MLEN ? NULL : control,
424 nclen, M_TEMP, M_WAITOK);
425 if (!nc) {
426 error = ENOMEM;
427 goto failure;
428 }
429 if (cidx <= MLEN) {
430 /* Old buffer was in mbuf... */
431 memcpy(nc, control, cidx);
432 memset(nc + cidx, 0, nclen - cidx);
433 } else {
434 memset(nc + nclen, 0, nclen - clen);
435 }
436 control = nc;
437 clen = nclen;
438 }
439
440 /* Copy header */
441 cmsg = (void *)&control[cidx];
442 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
443 cmsg->cmsg_level = cmsg32.cmsg_level;
444 cmsg->cmsg_type = cmsg32.cmsg_type;
445
446 /* Copyin the data */
447 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
448 cmsg32.cmsg_len - CMSG32_LEN(0));
449 if (error)
450 goto failure;
451 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
452
453 resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
454 cidx += CMSG_ALIGN(cmsg->cmsg_len);
455 }
456
457 /* If we allocated a buffer, attach to mbuf */
458 if (cidx > MLEN) {
459 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
460 ctl_mbuf->m_flags |= M_EXT_RW;
461 }
462 control = NULL;
463 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
464
465 mp->msg_control = ctl_mbuf;
466 mp->msg_flags |= MSG_CONTROLMBUF;
467
468
469 return 0;
470
471 failure:
472 if (control != mtod(ctl_mbuf, void *))
473 free(control, M_MBUF);
474 m_free(ctl_mbuf);
475 return error;
476 }
477
478 static int
479 msg_send_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
480 struct msghdr *msg, struct iovec *aiov)
481 {
482 int error;
483 struct iovec *iov = aiov;
484 struct netbsd32_iovec *iov32;
485 size_t iovsz;
486
487 netbsd32_to_msghdr(msg32, msg);
488 msg->msg_flags = 0;
489
490 if (CMSG32_FIRSTHDR(msg)) {
491 error = copyin32_msg_control(l, msg);
492 if (error)
493 return error;
494 /* From here on, msg->msg_control is allocated */
495 } else {
496 msg->msg_control = NULL;
497 msg->msg_controllen = 0;
498 }
499
500 iovsz = msg->msg_iovlen * sizeof(struct iovec);
501 if ((u_int)msg->msg_iovlen > UIO_SMALLIOV) {
502 if ((u_int)msg->msg_iovlen > IOV_MAX) {
503 error = EMSGSIZE;
504 goto out;
505 }
506 iov = kmem_alloc(iovsz, KM_SLEEP);
507 }
508
509 iov32 = NETBSD32PTR64(msg32->msg_iov);
510 error = netbsd32_to_iovecin(iov32, iov, msg->msg_iovlen);
511 if (error)
512 goto out;
513 msg->msg_iov = iov;
514 return 0;
515 out:
516 if (msg->msg_control)
517 m_free(msg->msg_control);
518 if (iov != aiov)
519 kmem_free(iov, iovsz);
520 return error;
521 }
522
523 int
524 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
525 register_t *retval)
526 {
527 /* {
528 syscallarg(int) s;
529 syscallarg(const netbsd32_msghdrp_t) msg;
530 syscallarg(int) flags;
531 } */
532 struct msghdr msg;
533 struct netbsd32_msghdr msg32;
534 struct iovec aiov[UIO_SMALLIOV];
535 int error;
536
537 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
538 if (error)
539 return error;
540
541 if ((error = msg_send_copyin(l, &msg32, &msg, aiov)) != 0)
542 return error;
543
544 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
545 retval);
546 /* msg.msg_control freed by do_sys_sendmsg() */
547
548 if (msg.msg_iov != aiov)
549 kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
550 return error;
551 }
552
553 int
554 netbsd32_sendmmsg(struct lwp *l, const struct netbsd32_sendmmsg_args *uap,
555 register_t *retval)
556 {
557 /* {
558 syscallarg(int) s;
559 syscallarg(const netbsd32_mmsghdr_t) mmsg;
560 syscallarg(unsigned int) vlen;
561 syscallarg(unsigned int) flags;
562 } */
563 struct mmsghdr mmsg;
564 struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
565 struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
566 struct socket *so;
567 file_t *fp;
568 struct msghdr *msg = &mmsg.msg_hdr;
569 int error, s;
570 unsigned int vlen, flags, dg;
571 struct iovec aiov[UIO_SMALLIOV];
572
573 s = SCARG(uap, s);
574 if ((error = fd_getsock1(s, &so, &fp)) != 0)
575 return error;
576
577 vlen = SCARG(uap, vlen);
578 if (vlen > 1024)
579 vlen = 1024;
580
581 flags = SCARG(uap, flags) & MSG_USERFLAGS;
582
583 for (dg = 0; dg < vlen;) {
584 error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
585 if (error)
586 break;
587 if ((error = msg_send_copyin(l, msg32, msg, aiov)) != 0)
588 break;
589
590 msg->msg_flags = flags;
591
592 error = do_sys_sendmsg_so(l, s, so, fp, msg, flags, retval);
593 if (msg->msg_iov != aiov) {
594 kmem_free(msg->msg_iov,
595 msg->msg_iovlen * sizeof(struct iovec));
596 }
597 if (error)
598 break;
599
600 ktrkuser("msghdr", msg, sizeof(*msg));
601 mmsg.msg_len = *retval;
602 netbsd32_from_mmsghdr(&mmsg32, &mmsg);
603 error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
604 if (error)
605 break;
606 dg++;
607 }
608
609 *retval = dg;
610
611 fd_putfile(s);
612
613 /*
614 * If we succeeded at least once, return 0.
615 */
616 if (dg)
617 return 0;
618 return error;
619 }
620
621 int
622 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
623 register_t *retval)
624 {
625 /* {
626 syscallarg(int) s;
627 syscallarg(netbsd32_voidp) buf;
628 syscallarg(netbsd32_size_t) len;
629 syscallarg(int) flags;
630 syscallarg(netbsd32_sockaddrp_t) from;
631 syscallarg(netbsd32_intp) fromlenaddr;
632 } */
633 struct msghdr msg;
634 struct iovec aiov;
635 int error;
636 struct mbuf *from;
637
638 msg.msg_name = NULL;
639 msg.msg_iov = &aiov;
640 msg.msg_iovlen = 1;
641 aiov.iov_base = SCARG_P32(uap, buf);
642 aiov.iov_len = SCARG(uap, len);
643 msg.msg_control = NULL;
644 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
645
646 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
647 if (error != 0)
648 return error;
649
650 error = copyout_sockname(SCARG_P32(uap, from),
651 SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
652 if (from != NULL)
653 m_free(from);
654 return error;
655 }
656
657 int
658 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
659 register_t *retval)
660 {
661 /* {
662 syscallarg(int) s;
663 syscallarg(const netbsd32_voidp) buf;
664 syscallarg(netbsd32_size_t) len;
665 syscallarg(int) flags;
666 syscallarg(const netbsd32_sockaddrp_t) to;
667 syscallarg(int) tolen;
668 } */
669 struct msghdr msg;
670 struct iovec aiov;
671
672 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
673 msg.msg_namelen = SCARG(uap, tolen);
674 msg.msg_iov = &aiov;
675 msg.msg_iovlen = 1;
676 msg.msg_control = 0;
677 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */
678 aiov.iov_len = SCARG(uap, len);
679 msg.msg_flags = 0;
680 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
681 retval);
682 }
683