AMD64 - Refactor uio_resid and size_t assumptions.
[dragonfly.git] / sys / emulation / 43bsd / 43bsd_socket.c
1 /*
2  * 43BSD_SOCKET.C       - 4.3BSD compatibility socket syscalls
3  *
4  * Copyright (c) 1982, 1986, 1989, 1990, 1993
5  *      The Regents of the University of California.  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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $DragonFly: src/sys/emulation/43bsd/43bsd_socket.c,v 1.10 2007/01/28 06:31:00 y0netan1 Exp $
36  *      from: DragonFly kern/uipc_syscalls.c,v 1.13
37  *
38  * The original versions of these syscalls used to live in
39  * kern/uipc_syscalls.c.  These are heavily modified to use the
40  * new split syscalls.
41  */
42
43 #include "opt_compat.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/sysproto.h>
49 #include <sys/kern_syscall.h>
50 #include <sys/malloc.h>
51 #include <sys/mbuf.h>
52 #include <sys/proc.h>
53 #include <sys/socket.h>
54 #include <sys/socketvar.h>
55 #include <sys/uio.h>
56
57 #include "43bsd_socket.h"
58
59 /*
60  * System call interface to the socket abstraction.
61  */
62
63 static int
64 compat_43_getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
65 {
66         struct sockaddr *sa;
67         int error;
68
69         *namp = NULL;
70         if (len > SOCK_MAXADDRLEN)
71                 return ENAMETOOLONG;
72         if (len < offsetof(struct sockaddr, sa_data[0]))
73                 return EDOM;
74         MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK);
75         error = copyin(uaddr, sa, len);
76         if (error) {
77                 FREE(sa, M_SONAME);
78         } else {
79                 /*
80                  * Convert to the 4.4BSD sockaddr structure.
81                  */
82                 sa->sa_family = sa->sa_len;
83                 sa->sa_len = len;
84                 *namp = sa;
85         }
86         return error;
87 }
88
89 static int
90 compat_43_copyout_sockaddr(struct sockaddr *sa, caddr_t uaddr, int sa_len)
91 {
92         int error;
93
94         ((struct osockaddr *)sa)->sa_family = sa->sa_family;
95         error = copyout(sa, uaddr, sa_len);
96
97         return (error);
98 }
99
100 int
101 sys_oaccept(struct accept_args *uap)
102 {
103         struct sockaddr *sa = NULL;
104         int sa_len;
105         int error;
106
107         if (uap->name) {
108                 error = copyin(uap->anamelen, &sa_len, sizeof(sa_len));
109                 if (error)
110                         return (error);
111
112                 error = kern_accept(uap->s, 0, &sa, &sa_len,
113                                     &uap->sysmsg_iresult);
114
115                 if (error) {
116                         /*
117                          * return a namelen of zero for older code which
118                          * might ignore the return value from accept.
119                          */
120                         sa_len = 0;
121                         copyout(&sa_len, uap->anamelen, sizeof(*uap->anamelen));
122                 } else {
123                         compat_43_copyout_sockaddr(sa, uap->name, sa_len);
124                         if (error == 0) {
125                                 error = copyout(&sa_len, uap->anamelen,
126                                     sizeof(*uap->anamelen));
127                         }
128                 }
129                 if (sa)
130                         FREE(sa, M_SONAME);
131         } else {
132                 error = kern_accept(uap->s, 0, NULL, 0, &uap->sysmsg_iresult);
133         }
134         return (error);
135 }
136
137 int
138 sys_ogetsockname(struct getsockname_args *uap)
139 {
140         struct sockaddr *sa = NULL;
141         int error, sa_len;
142
143         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
144         if (error)
145                 return (error);
146
147         error = kern_getsockname(uap->fdes, &sa, &sa_len);
148
149         if (error == 0)
150                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
151         if (error == 0) {
152                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
153         }
154         if (sa)
155                 FREE(sa, M_SONAME);
156         return (error);
157 }
158
159 int
160 sys_ogetpeername(struct ogetpeername_args *uap)
161 {
162         struct sockaddr *sa = NULL;
163         int error, sa_len;
164
165         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
166         if (error)
167                 return (error);
168
169         error = kern_getpeername(uap->fdes, &sa, &sa_len);
170
171         if (error == 0) {
172                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
173         }
174         if (error == 0)
175                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
176         if (sa)
177                 FREE(sa, M_SONAME);
178         return (error);
179 }
180
181 int
182 sys_osend(struct osend_args *uap)
183 {
184         struct thread *td = curthread;
185         struct uio auio;
186         struct iovec aiov;
187         int error;
188
189         aiov.iov_base = uap->buf;
190         aiov.iov_len = uap->len;
191         auio.uio_iov = &aiov;
192         auio.uio_iovcnt = 1;
193         auio.uio_offset = 0;
194         auio.uio_resid = uap->len;
195         auio.uio_segflg = UIO_USERSPACE;
196         auio.uio_rw = UIO_WRITE;
197         auio.uio_td = td;
198
199         error = kern_sendmsg(uap->s, NULL, &auio, NULL, uap->flags,
200                              &uap->sysmsg_szresult);
201
202         return (error);
203 }
204
205 int
206 sys_osendmsg(struct osendmsg_args *uap)
207 {
208         struct thread *td = curthread;
209         struct msghdr msg;
210         struct uio auio;
211         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
212         struct sockaddr *sa = NULL;
213         struct mbuf *control = NULL;
214         struct cmsghdr *cm;
215         int error;
216
217         error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
218         if (error)
219                 return (error);
220
221         /*
222          * Conditionally copyin msg.msg_name.
223          */
224         if (msg.msg_name) {
225                 error = compat_43_getsockaddr(&sa, msg.msg_name,
226                     msg.msg_namelen);
227                 if (error)
228                         return (error);
229         }
230
231         /*
232          * Populate auio.
233          */
234         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
235                              &auio.uio_resid);
236         if (error)
237                 goto cleanup2;
238         auio.uio_iov = iov;
239         auio.uio_iovcnt = msg.msg_iovlen;
240         auio.uio_offset = 0;
241         auio.uio_segflg = UIO_USERSPACE;
242         auio.uio_rw = UIO_WRITE;
243         auio.uio_td = td;
244
245         /*
246          * Conditionally copyin msg.msg_control.
247          */
248         if (msg.msg_control) {
249                 if (msg.msg_controllen < 0 || msg.msg_controllen > MLEN) {
250                         error = EINVAL;
251                         goto cleanup;
252                 }
253                 control = m_get(MB_WAIT, MT_CONTROL);
254                 if (control == NULL) {
255                         error = ENOBUFS;
256                         goto cleanup;
257                 }
258                 control->m_len = msg.msg_controllen;
259                 error = copyin(msg.msg_control, mtod(control, caddr_t),
260                     msg.msg_controllen);
261                 if (error) {
262                         m_free(control);
263                         goto cleanup;
264                 }
265                 /*
266                  * In 4.3BSD, the only type of ancillary data was
267                  * access rights and this data did not use a header
268                  * to identify it's type.  Thus, we must prepend the
269                  * control data with the proper cmsghdr structure
270                  * so that the kernel recognizes it as access rights.
271                  */
272                 M_PREPEND(control, sizeof(*cm), MB_WAIT);
273                 if (control == NULL) {
274                         error = ENOBUFS;
275                         goto cleanup;
276                 } else {
277                         cm = mtod(control, struct cmsghdr *);
278                         cm->cmsg_len = control->m_len;
279                         cm->cmsg_level = SOL_SOCKET;
280                         cm->cmsg_type = SCM_RIGHTS;
281                 }
282         }
283
284         error = kern_sendmsg(uap->s, sa, &auio, control, uap->flags,
285                              &uap->sysmsg_szresult);
286
287 cleanup:
288         iovec_free(&iov, aiov);
289 cleanup2:
290         if (sa)
291                 FREE(sa, M_SONAME);
292         return (error);
293 }
294
295 int
296 sys_orecv(struct orecv_args *uap)
297 {
298         struct thread *td = curthread;
299         struct uio auio;
300         struct iovec aiov;
301         int error;
302
303         aiov.iov_base = uap->buf;
304         aiov.iov_len = uap->len;
305         auio.uio_iov = &aiov;
306         auio.uio_iovcnt = 1;
307         auio.uio_offset = 0;
308         auio.uio_resid = uap->len;
309         auio.uio_segflg = UIO_USERSPACE;
310         auio.uio_rw = UIO_READ;
311         auio.uio_td = td;
312
313         error = kern_recvmsg(uap->s, NULL, &auio, NULL, &uap->flags,
314                              &uap->sysmsg_szresult);
315
316         return (error);
317 }
318
319 int
320 sys_orecvfrom(struct recvfrom_args *uap)
321 {
322         struct thread *td = curthread;
323         struct uio auio;
324         struct iovec aiov;
325         struct sockaddr *sa = NULL;
326         int error, fromlen;
327
328         if (uap->from && uap->fromlenaddr) {
329                 error = copyin(uap->fromlenaddr, &fromlen, sizeof(fromlen));
330                 if (error)
331                         return (error);
332                 if (fromlen < 0)
333                         return (EINVAL);
334         } else {
335                 fromlen = 0;
336         }
337         aiov.iov_base = uap->buf;
338         aiov.iov_len = uap->len;
339         auio.uio_iov = &aiov;
340         auio.uio_iovcnt = 1;
341         auio.uio_offset = 0;
342         auio.uio_resid = uap->len;
343         auio.uio_segflg = UIO_USERSPACE;
344         auio.uio_rw = UIO_READ;
345         auio.uio_td = td;
346
347         error = kern_recvmsg(uap->s, uap->from ? &sa : NULL, &auio, NULL,
348                              &uap->flags, &uap->sysmsg_szresult);
349
350         if (error == 0 && uap->from) {
351                 if (sa != NULL) {
352                         fromlen = MIN(fromlen, sa->sa_len);
353                         error = compat_43_copyout_sockaddr(sa, uap->from,
354                                                            fromlen);
355                 } else
356                         fromlen = 0;
357                 if (error == 0)
358                         /*
359                          * Old recvfrom didn't signal an error if this
360                          * next copyout failed.
361                          */
362                         copyout(&fromlen, uap->fromlenaddr, sizeof(fromlen));
363         }
364         if (sa)
365                 FREE(sa, M_SONAME);
366
367         return (error);
368 }
369
370 int
371 sys_orecvmsg(struct orecvmsg_args *uap)
372 {
373         struct thread *td = curthread;
374         struct msghdr msg;
375         struct uio auio;
376         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
377         struct mbuf *m, *control = NULL;
378         struct sockaddr *sa = NULL;
379         caddr_t ctlbuf;
380         socklen_t *ufromlenp, *ucontrollenp;
381         int error, fromlen, controllen, len, flags, *uflagsp;
382
383         /*
384          * This copyin handles everything except the iovec.
385          */
386         error = copyin(uap->msg, &msg, sizeof(struct omsghdr));
387         if (error)
388                 return (error);
389
390         if (msg.msg_name && msg.msg_namelen < 0)
391                 return (EINVAL);
392         if (msg.msg_control && msg.msg_controllen < 0)
393                 return (EINVAL);
394
395         ufromlenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
396             msg_namelen));
397         ucontrollenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
398             msg_controllen));
399         uflagsp = (int *)((caddr_t)uap->msg + offsetof(struct msghdr,
400             msg_flags));
401
402         /*
403          * Populate auio.
404          */
405         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
406                              &auio.uio_resid);
407         if (error)
408                 return (error);
409         auio.uio_iov = iov;
410         auio.uio_iovcnt = msg.msg_iovlen;
411         auio.uio_offset = 0;
412         auio.uio_segflg = UIO_USERSPACE;
413         auio.uio_rw = UIO_READ;
414         auio.uio_td = td;
415
416         flags = msg.msg_flags;
417
418         error = kern_recvmsg(uap->s, (msg.msg_name ? &sa : NULL), &auio,
419                              (msg.msg_control ? &control : NULL), &flags,
420                              &uap->sysmsg_szresult);
421
422         /*
423          * Copyout msg.msg_name and msg.msg_namelen.
424          */
425         if (error == 0 && msg.msg_name) {
426                 if (sa != NULL) {
427                         fromlen = MIN(msg.msg_namelen, sa->sa_len);
428                         error = compat_43_copyout_sockaddr(sa, msg.msg_name,
429                                                            fromlen);
430                 } else
431                         fromlen = 0;
432                 if (error == 0)
433                         /*
434                          * Old recvfrom didn't signal an error if this
435                          * next copyout failed.
436                          */
437                         copyout(&fromlen, ufromlenp, sizeof(*ufromlenp));
438         }
439
440         /*
441          * Copyout msg.msg_control and msg.msg_controllen.
442          */
443         if (error == 0 && msg.msg_control) {
444                 /*
445                  * If we receive access rights, trim the cmsghdr; anything
446                  * else is tossed.
447                  */
448                 if (mtod((struct mbuf *)msg.msg_control,
449                     struct cmsghdr *)->cmsg_level != SOL_SOCKET ||
450                     mtod((struct mbuf *)msg.msg_control,
451                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
452                         int temp = 0;
453                         error = copyout(&temp, ucontrollenp,
454                             sizeof(*ucontrollenp));
455                         goto cleanup;
456                 }
457                 ((struct mbuf *)msg.msg_control)->m_len -=
458                     sizeof(struct cmsghdr);
459                 ((struct mbuf *)msg.msg_control)->m_data +=
460                     sizeof(struct cmsghdr);
461
462                 len = msg.msg_controllen;
463                 m = control;
464                 ctlbuf = (caddr_t)msg.msg_control;
465
466                 while(m && len > 0) {
467                         unsigned int tocopy;
468
469                         if (len >= m->m_len) {
470                                 tocopy = m->m_len;
471                         } else {
472                                 msg.msg_flags |= MSG_CTRUNC;
473                                 tocopy = len;
474                         }
475
476                         error = copyout(mtod(m, caddr_t), ctlbuf,
477                             tocopy);
478                         if (error)
479                                 goto cleanup;
480
481                         ctlbuf += tocopy;
482                         len -= tocopy;
483                         m = m->m_next;
484                 }
485                 controllen = ctlbuf - (caddr_t)msg.msg_control;
486                 error = copyout(&controllen, ucontrollenp,
487                     sizeof(*ucontrollenp));
488         }
489
490         if (error == 0)
491                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
492
493 cleanup:
494         if (sa)
495                 FREE(sa, M_SONAME);
496         iovec_free(&iov, aiov);
497         if (control)
498                 m_freem(control);
499         return (error);
500 }
501