netbsd32_socket.c revision 1.51 1 /* $NetBSD: netbsd32_socket.c,v 1.51 2019/09/27 08:12:01 mlelstv 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.51 2019/09/27 08:12:01 mlelstv 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, u_int *len,
78 struct mbuf *m, char **q, bool *truncated)
79 {
80 struct cmsghdr *cmsg, cmsg32;
81 size_t i, j;
82 int error;
83
84 *truncated = false;
85 cmsg = mtod(m, struct cmsghdr *);
86 do {
87 if ((char *)cmsg == mtod(m, char *) + m->m_len)
88 break;
89 if ((char *)cmsg > mtod(m, char *) + m->m_len - sizeof(*cmsg))
90 return EINVAL;
91 cmsg32 = *cmsg;
92 j = cmsg->cmsg_len - CMSG_LEN(0);
93 i = cmsg32.cmsg_len = CMSG32_LEN(j);
94 if (i > *len) {
95 mp->msg_flags |= MSG_CTRUNC;
96 if (cmsg->cmsg_level == SOL_SOCKET
97 && cmsg->cmsg_type == SCM_RIGHTS) {
98 *truncated = true;
99 return 0;
100 }
101 j -= i - *len;
102 i = *len;
103 }
104
105 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
106 error = copyout(&cmsg32, *q, MIN(i, sizeof(cmsg32)));
107 if (error)
108 return (error);
109 if (i > CMSG32_LEN(0)) {
110 error = copyout(CMSG_DATA(cmsg), *q + CMSG32_LEN(0),
111 i - CMSG32_LEN(0));
112 if (error)
113 return (error);
114 }
115 j = CMSG32_SPACE(cmsg->cmsg_len - CMSG_LEN(0));
116 if (*len >= j) {
117 *len -= j;
118 *q += j;
119 } else {
120 *q += i;
121 *len = 0;
122 }
123 cmsg = (void *)((char *)cmsg + CMSG_ALIGN(cmsg->cmsg_len));
124 } while (*len > 0);
125
126 return 0;
127 }
128
129 static int
130 copyout32_msg_control(struct lwp *l, struct msghdr *mp, struct mbuf *control)
131 {
132 int len, error = 0;
133 struct mbuf *m;
134 char *q;
135 bool truncated;
136
137 len = mp->msg_controllen;
138 if (len <= 0 || control == 0) {
139 mp->msg_controllen = 0;
140 free_control_mbuf(l, control, control);
141 return 0;
142 }
143
144 q = (char *)mp->msg_control;
145
146 for (m = control; len > 0 && m != NULL; m = m->m_next) {
147 error = copyout32_msg_control_mbuf(l, mp, &len, m, &q,
148 &truncated);
149 if (truncated) {
150 m = control;
151 break;
152 }
153 if (error)
154 break;
155 }
156
157 free_control_mbuf(l, control, m);
158
159 mp->msg_controllen = q - (char *)mp->msg_control;
160 return error;
161 }
162
163 static int
164 msg_recv_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
165 struct msghdr *msg, struct iovec *aiov)
166 {
167 int error;
168 size_t iovsz;
169 struct iovec *iov = aiov;
170
171 iovsz = msg32->msg_iovlen * sizeof(struct iovec);
172 if (msg32->msg_iovlen > UIO_SMALLIOV) {
173 if (msg32->msg_iovlen > IOV_MAX)
174 return EMSGSIZE;
175 iov = kmem_alloc(iovsz, KM_SLEEP);
176 }
177
178 error = netbsd32_to_iovecin(NETBSD32PTR64(msg32->msg_iov), iov,
179 msg32->msg_iovlen);
180 if (error)
181 goto out;
182
183 netbsd32_to_msghdr(msg32, msg);
184 msg->msg_iov = iov;
185 out:
186 if (iov != aiov)
187 kmem_free(iov, iovsz);
188 return error;
189 }
190
191 static int
192 msg_recv_copyout(struct lwp *l, struct netbsd32_msghdr *msg32,
193 struct msghdr *msg, struct netbsd32_msghdr *arg,
194 struct mbuf *from, struct mbuf *control)
195 {
196 int error = 0;
197
198 if (msg->msg_control != NULL)
199 error = copyout32_msg_control(l, msg, control);
200
201 if (error == 0)
202 error = copyout_sockname(msg->msg_name, &msg->msg_namelen, 0,
203 from);
204
205 if (from != NULL)
206 m_free(from);
207 if (error)
208 return error;
209
210 msg32->msg_namelen = msg->msg_namelen;
211 msg32->msg_controllen = msg->msg_controllen;
212 msg32->msg_flags = msg->msg_flags;
213 ktrkuser("msghdr", msg, sizeof(*msg));
214 if (arg == NULL)
215 return 0;
216 return copyout(msg32, arg, sizeof(*arg));
217 }
218
219 int
220 netbsd32_recvmsg(struct lwp *l, const struct netbsd32_recvmsg_args *uap,
221 register_t *retval)
222 {
223 /* {
224 syscallarg(int) s;
225 syscallarg(netbsd32_msghdrp_t) msg;
226 syscallarg(int) flags;
227 } */
228 struct netbsd32_msghdr msg32;
229 struct iovec aiov[UIO_SMALLIOV];
230 struct msghdr msg;
231 int error;
232 struct mbuf *from, *control;
233
234 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
235 if (error)
236 return (error);
237
238 if ((error = msg_recv_copyin(l, &msg32, &msg, aiov)) != 0)
239 return error;
240
241 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
242 error = do_sys_recvmsg(l, SCARG(uap, s), &msg,
243 &from, msg.msg_control != NULL ? &control : NULL, retval);
244 if (error != 0)
245 goto out;
246
247 error = msg_recv_copyout(l, &msg32, &msg, SCARG_P32(uap, msg),
248 from, control);
249 out:
250 if (msg.msg_iov != aiov)
251 kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
252 return error;
253 }
254
255 int
256 netbsd32_recvmmsg(struct lwp *l, const struct netbsd32_recvmmsg_args *uap,
257 register_t *retval)
258 {
259 /* {
260 syscallarg(int) s;
261 syscallarg(netbsd32_mmsghdr_t) mmsg;
262 syscallarg(unsigned int) vlen;
263 syscallarg(unsigned int) flags;
264 syscallarg(netbsd32_timespecp_t) timeout;
265 } */
266 struct mmsghdr mmsg;
267 struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
268 struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
269 struct socket *so;
270 struct msghdr *msg = &mmsg.msg_hdr;
271 int error, s;
272 struct mbuf *from, *control;
273 struct timespec ts, now;
274 struct netbsd32_timespec ts32;
275 unsigned int vlen, flags, dg;
276 struct iovec aiov[UIO_SMALLIOV];
277
278 ts.tv_sec = 0; // XXX: gcc
279 ts.tv_nsec = 0;
280 if (SCARG_P32(uap, timeout)) {
281 if ((error = copyin(SCARG_P32(uap, timeout), &ts32,
282 sizeof(ts32))) != 0)
283 return error;
284 getnanotime(&now);
285 netbsd32_to_timespec(&ts32, &ts);
286 timespecadd(&now, &ts, &ts);
287 }
288
289 s = SCARG(uap, s);
290 if ((error = fd_getsock(s, &so)) != 0)
291 return error;
292
293 /*
294 * If so->so_rerror holds a deferred error return it now.
295 */
296 if (so->so_rerror) {
297 error = so->so_rerror;
298 so->so_rerror = 0;
299 fd_putfile(s);
300 return error;
301 }
302
303 vlen = SCARG(uap, vlen);
304 if (vlen > 1024)
305 vlen = 1024;
306
307 from = NULL;
308 flags = SCARG(uap, flags) & MSG_USERFLAGS;
309
310 for (dg = 0; dg < vlen;) {
311 error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
312 if (error)
313 break;
314
315 if ((error = msg_recv_copyin(l, msg32, msg, aiov)) != 0)
316 return error;
317
318 msg->msg_flags = flags & ~MSG_WAITFORONE;
319
320 if (from != NULL) {
321 m_free(from);
322 from = NULL;
323 }
324
325 error = do_sys_recvmsg_so(l, s, so, msg, &from,
326 msg->msg_control != NULL ? &control : NULL, retval);
327 if (error) {
328 if (error == EAGAIN && dg > 0)
329 error = 0;
330 break;
331 }
332 error = msg_recv_copyout(l, msg32, msg, NULL,
333 from, control);
334 from = NULL;
335 if (error)
336 break;
337
338 mmsg32.msg_len = *retval;
339
340 error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
341 if (error)
342 break;
343
344 dg++;
345 if (msg->msg_flags & MSG_OOB)
346 break;
347
348 if (SCARG_P32(uap, timeout)) {
349 getnanotime(&now);
350 timespecsub(&now, &ts, &now);
351 if (now.tv_sec > 0)
352 break;
353 }
354
355 if (flags & MSG_WAITFORONE)
356 flags |= MSG_DONTWAIT;
357
358 }
359
360 if (from != NULL)
361 m_free(from);
362
363 *retval = dg;
364
365 /*
366 * If we succeeded at least once, return 0, hopefully so->so_rerror
367 * will catch it next time.
368 */
369 if (error && dg > 0) {
370 so->so_rerror = error;
371 error = 0;
372 }
373
374 fd_putfile(s);
375
376 return error;
377 }
378
379 static int
380 copyin32_msg_control(struct lwp *l, struct msghdr *mp)
381 {
382 /*
383 * Handle cmsg if there is any.
384 */
385 struct cmsghdr *cmsg, cmsg32, *cc;
386 struct mbuf *ctl_mbuf;
387 ssize_t resid = mp->msg_controllen;
388 size_t clen, cidx = 0, cspace;
389 u_int8_t *control;
390 int error;
391
392 ctl_mbuf = m_get(M_WAIT, MT_CONTROL);
393 clen = MLEN;
394 control = mtod(ctl_mbuf, void *);
395 memset(control, 0, clen);
396
397 for (cc = CMSG32_FIRSTHDR(mp); cc; cc = CMSG32_NXTHDR(mp, &cmsg32, cc))
398 {
399 error = copyin(cc, &cmsg32, sizeof(cmsg32));
400 if (error)
401 goto failure;
402
403 /*
404 * Sanity check the control message length.
405 */
406 if (cmsg32.cmsg_len > (size_t)resid ||
407 cmsg32.cmsg_len < sizeof(cmsg32)) {
408 error = EINVAL;
409 goto failure;
410 }
411
412 cspace = CMSG_SPACE(cmsg32.cmsg_len - CMSG32_LEN(0));
413
414 /* Check the buffer is big enough */
415 if (__predict_false(cidx + cspace > clen)) {
416 u_int8_t *nc;
417 size_t nclen;
418
419 nclen = cidx + cspace;
420 if (nclen >= PAGE_SIZE) {
421 error = EINVAL;
422 goto failure;
423 }
424 nc = realloc(clen <= MLEN ? NULL : control,
425 nclen, M_TEMP, M_WAITOK);
426 if (!nc) {
427 error = ENOMEM;
428 goto failure;
429 }
430 if (cidx <= MLEN) {
431 /* Old buffer was in mbuf... */
432 memcpy(nc, control, cidx);
433 memset(nc + cidx, 0, nclen - cidx);
434 } else {
435 memset(nc + nclen, 0, nclen - clen);
436 }
437 control = nc;
438 clen = nclen;
439 }
440
441 /* Copy header */
442 cmsg = (void *)&control[cidx];
443 cmsg->cmsg_len = CMSG_LEN(cmsg32.cmsg_len - CMSG32_LEN(0));
444 cmsg->cmsg_level = cmsg32.cmsg_level;
445 cmsg->cmsg_type = cmsg32.cmsg_type;
446
447 /* Copyin the data */
448 error = copyin(CMSG32_DATA(cc), CMSG_DATA(cmsg),
449 cmsg32.cmsg_len - CMSG32_LEN(0));
450 if (error)
451 goto failure;
452 ktrkuser(mbuftypes[MT_CONTROL], cmsg, cmsg->cmsg_len);
453
454 resid -= CMSG32_ALIGN(cmsg32.cmsg_len);
455 cidx += CMSG_ALIGN(cmsg->cmsg_len);
456 }
457
458 /* If we allocated a buffer, attach to mbuf */
459 if (cidx > MLEN) {
460 MEXTADD(ctl_mbuf, control, clen, M_MBUF, NULL, NULL);
461 ctl_mbuf->m_flags |= M_EXT_RW;
462 }
463 control = NULL;
464 mp->msg_controllen = ctl_mbuf->m_len = CMSG_ALIGN(cidx);
465
466 mp->msg_control = ctl_mbuf;
467 mp->msg_flags |= MSG_CONTROLMBUF;
468
469
470 return 0;
471
472 failure:
473 if (control != mtod(ctl_mbuf, void *))
474 free(control, M_MBUF);
475 m_free(ctl_mbuf);
476 return error;
477 }
478
479 static int
480 msg_send_copyin(struct lwp *l, const struct netbsd32_msghdr *msg32,
481 struct msghdr *msg, struct iovec *aiov)
482 {
483 int error;
484 struct iovec *iov = aiov;
485 struct netbsd32_iovec *iov32;
486 size_t iovsz;
487
488 netbsd32_to_msghdr(msg32, msg);
489 msg->msg_flags = 0;
490
491 if (CMSG32_FIRSTHDR(msg)) {
492 error = copyin32_msg_control(l, msg);
493 if (error)
494 return error;
495 /* From here on, msg->msg_control is allocated */
496 } else {
497 msg->msg_control = NULL;
498 msg->msg_controllen = 0;
499 }
500
501 iovsz = msg->msg_iovlen * sizeof(struct iovec);
502 if ((u_int)msg->msg_iovlen > UIO_SMALLIOV) {
503 if ((u_int)msg->msg_iovlen > IOV_MAX) {
504 error = EMSGSIZE;
505 goto out;
506 }
507 iov = kmem_alloc(iovsz, KM_SLEEP);
508 }
509
510 iov32 = NETBSD32PTR64(msg32->msg_iov);
511 error = netbsd32_to_iovecin(iov32, iov, msg->msg_iovlen);
512 if (error)
513 goto out;
514 msg->msg_iov = iov;
515 return 0;
516 out:
517 if (msg->msg_control)
518 m_free(msg->msg_control);
519 if (iov != aiov)
520 kmem_free(iov, iovsz);
521 return error;
522 }
523
524 int
525 netbsd32_sendmsg(struct lwp *l, const struct netbsd32_sendmsg_args *uap,
526 register_t *retval)
527 {
528 /* {
529 syscallarg(int) s;
530 syscallarg(const netbsd32_msghdrp_t) msg;
531 syscallarg(int) flags;
532 } */
533 struct msghdr msg;
534 struct netbsd32_msghdr msg32;
535 struct iovec aiov[UIO_SMALLIOV];
536 int error;
537
538 error = copyin(SCARG_P32(uap, msg), &msg32, sizeof(msg32));
539 if (error)
540 return error;
541
542 if ((error = msg_send_copyin(l, &msg32, &msg, aiov)) != 0)
543 return error;
544
545 error = do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
546 retval);
547 /* msg.msg_control freed by do_sys_sendmsg() */
548
549 if (msg.msg_iov != aiov)
550 kmem_free(msg.msg_iov, msg.msg_iovlen * sizeof(struct iovec));
551 return error;
552 }
553
554 int
555 netbsd32_sendmmsg(struct lwp *l, const struct netbsd32_sendmmsg_args *uap,
556 register_t *retval)
557 {
558 /* {
559 syscallarg(int) s;
560 syscallarg(const netbsd32_mmsghdr_t) mmsg;
561 syscallarg(unsigned int) vlen;
562 syscallarg(unsigned int) flags;
563 } */
564 struct mmsghdr mmsg;
565 struct netbsd32_mmsghdr mmsg32, *mmsg32p = SCARG_P32(uap, mmsg);
566 struct netbsd32_msghdr *msg32 = &mmsg32.msg_hdr;
567 struct socket *so;
568 file_t *fp;
569 struct msghdr *msg = &mmsg.msg_hdr;
570 int error, s;
571 unsigned int vlen, flags, dg;
572 struct iovec aiov[UIO_SMALLIOV];
573
574 s = SCARG(uap, s);
575 if ((error = fd_getsock1(s, &so, &fp)) != 0)
576 return error;
577
578 vlen = SCARG(uap, vlen);
579 if (vlen > 1024)
580 vlen = 1024;
581
582 flags = SCARG(uap, flags) & MSG_USERFLAGS;
583
584 for (dg = 0; dg < vlen;) {
585 error = copyin(mmsg32p + dg, &mmsg32, sizeof(mmsg32));
586 if (error)
587 break;
588 if ((error = msg_send_copyin(l, msg32, msg, aiov)) != 0)
589 break;
590
591 msg->msg_flags = flags;
592
593 error = do_sys_sendmsg_so(l, s, so, fp, msg, flags, retval);
594 if (msg->msg_iov != aiov) {
595 kmem_free(msg->msg_iov,
596 msg->msg_iovlen * sizeof(struct iovec));
597 }
598 if (error)
599 break;
600
601 ktrkuser("msghdr", msg, sizeof(*msg));
602 mmsg.msg_len = *retval;
603 netbsd32_from_mmsghdr(&mmsg32, &mmsg);
604 error = copyout(&mmsg32, mmsg32p + dg, sizeof(mmsg32));
605 if (error)
606 break;
607 dg++;
608 }
609
610 *retval = dg;
611
612 fd_putfile(s);
613
614 /*
615 * If we succeeded at least once, return 0.
616 */
617 if (dg)
618 return 0;
619 return error;
620 }
621
622 int
623 netbsd32_recvfrom(struct lwp *l, const struct netbsd32_recvfrom_args *uap,
624 register_t *retval)
625 {
626 /* {
627 syscallarg(int) s;
628 syscallarg(netbsd32_voidp) buf;
629 syscallarg(netbsd32_size_t) len;
630 syscallarg(int) flags;
631 syscallarg(netbsd32_sockaddrp_t) from;
632 syscallarg(netbsd32_intp) fromlenaddr;
633 } */
634 struct msghdr msg;
635 struct iovec aiov;
636 int error;
637 struct mbuf *from;
638
639 msg.msg_name = NULL;
640 msg.msg_iov = &aiov;
641 msg.msg_iovlen = 1;
642 aiov.iov_base = SCARG_P32(uap, buf);
643 aiov.iov_len = SCARG(uap, len);
644 msg.msg_control = NULL;
645 msg.msg_flags = SCARG(uap, flags) & MSG_USERFLAGS;
646
647 error = do_sys_recvmsg(l, SCARG(uap, s), &msg, &from, NULL, retval);
648 if (error != 0)
649 return error;
650
651 error = copyout_sockname(SCARG_P32(uap, from),
652 SCARG_P32(uap, fromlenaddr), MSG_LENUSRSPACE, from);
653 if (from != NULL)
654 m_free(from);
655 return error;
656 }
657
658 int
659 netbsd32_sendto(struct lwp *l, const struct netbsd32_sendto_args *uap,
660 register_t *retval)
661 {
662 /* {
663 syscallarg(int) s;
664 syscallarg(const netbsd32_voidp) buf;
665 syscallarg(netbsd32_size_t) len;
666 syscallarg(int) flags;
667 syscallarg(const netbsd32_sockaddrp_t) to;
668 syscallarg(int) tolen;
669 } */
670 struct msghdr msg;
671 struct iovec aiov;
672
673 msg.msg_name = SCARG_P32(uap, to); /* XXX kills const */
674 msg.msg_namelen = SCARG(uap, tolen);
675 msg.msg_iov = &aiov;
676 msg.msg_iovlen = 1;
677 msg.msg_control = 0;
678 aiov.iov_base = SCARG_P32(uap, buf); /* XXX kills const */
679 aiov.iov_len = SCARG(uap, len);
680 msg.msg_flags = 0;
681 return do_sys_sendmsg(l, SCARG(uap, s), &msg, SCARG(uap, flags),
682 retval);
683 }
684