Merge from vendor branch NTPD:
[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.5 2004/06/02 14:42:56 eirikn 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 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, &sa, &sa_len, &uap->sysmsg_result);
113
114                 if (error) {
115                         /*
116                          * return a namelen of zero for older code which
117                          * might ignore the return value from accept.
118                          */
119                         sa_len = 0;
120                         copyout(&sa_len, uap->anamelen, sizeof(*uap->anamelen));
121                 } else {
122                         compat_43_copyout_sockaddr(sa, uap->name, sa_len);
123                         if (error == 0) {
124                                 error = copyout(&sa_len, uap->anamelen,
125                                     sizeof(*uap->anamelen));
126                         }
127                 }
128                 if (sa)
129                         FREE(sa, M_SONAME);
130         } else {
131                 error = kern_accept(uap->s, NULL, 0, &uap->sysmsg_result);
132         }
133         return (error);
134 }
135
136 int
137 ogetsockname(struct getsockname_args *uap)
138 {
139         struct sockaddr *sa = NULL;
140         int error, sa_len;
141
142         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
143         if (error)
144                 return (error);
145
146         error = kern_getsockname(uap->fdes, &sa, &sa_len);
147
148         if (error == 0)
149                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
150         if (error == 0) {
151                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
152         }
153         if (sa)
154                 FREE(sa, M_SONAME);
155         return (error);
156 }
157
158 int
159 ogetpeername(struct ogetpeername_args *uap)
160 {
161         struct sockaddr *sa = NULL;
162         int error, sa_len;
163
164         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
165         if (error)
166                 return (error);
167
168         error = kern_getpeername(uap->fdes, &sa, &sa_len);
169
170         if (error == 0) {
171                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
172         }
173         if (error == 0)
174                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
175         if (sa)
176                 FREE(sa, M_SONAME);
177         return (error);
178 }
179
180 int
181 osend(struct osend_args *uap)
182 {
183         struct thread *td = curthread;
184         struct uio auio;
185         struct iovec aiov;
186         int error;
187
188         aiov.iov_base = uap->buf;
189         aiov.iov_len = uap->len;
190         auio.uio_iov = &aiov;
191         auio.uio_iovcnt = 1;
192         auio.uio_offset = 0;
193         auio.uio_resid = uap->len;
194         auio.uio_segflg = UIO_USERSPACE;
195         auio.uio_rw = UIO_WRITE;
196         auio.uio_td = td;
197
198         error = kern_sendmsg(uap->s, NULL, &auio, NULL, uap->flags,
199             &uap->sysmsg_result);
200
201         return (error);
202 }
203
204 int
205 osendmsg(struct osendmsg_args *uap)
206 {
207         struct thread *td = curthread;
208         struct msghdr msg;
209         struct uio auio;
210         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
211         struct sockaddr *sa = NULL;
212         struct mbuf *control = NULL;
213         struct cmsghdr *cm;
214         int error;
215
216         error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
217         if (error)
218                 return (error);
219
220         /*
221          * Conditionally copyin msg.msg_name.
222          */
223         if (msg.msg_name) {
224                 error = compat_43_getsockaddr(&sa, msg.msg_name,
225                     msg.msg_namelen);
226                 if (error)
227                         return (error);
228         }
229
230         /*
231          * Populate auio.
232          */
233         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
234             &auio.uio_resid);
235         if (error)
236                 goto cleanup;
237         auio.uio_iov = iov;
238         auio.uio_iovcnt = msg.msg_iovlen;
239         auio.uio_offset = 0;
240         auio.uio_segflg = UIO_USERSPACE;
241         auio.uio_rw = UIO_WRITE;
242         auio.uio_td = td;
243
244         /*
245          * Conditionally copyin msg.msg_control.
246          */
247         if (msg.msg_control) {
248                 if (msg.msg_controllen < 0 || msg.msg_controllen > MLEN) {
249                         error = EINVAL;
250                         goto cleanup;
251                 }
252                 control = m_get(MB_WAIT, MT_CONTROL);
253                 if (control == NULL) {
254                         error = ENOBUFS;
255                         goto cleanup;
256                 }
257                 control->m_len = msg.msg_controllen;
258                 error = copyin(msg.msg_control, mtod(control, caddr_t),
259                     msg.msg_controllen);
260                 if (error) {
261                         m_free(control);
262                         goto cleanup;
263                 }
264                 /*
265                  * In 4.3BSD, the only type of ancillary data was
266                  * access rights and this data did not use a header
267                  * to identify it's type.  Thus, we must prepend the
268                  * control data with the proper cmsghdr structure
269                  * so that the kernel recognizes it as access rights.
270                  */
271                 M_PREPEND(control, sizeof(*cm), MB_WAIT);
272                 if (control == NULL) {
273                         error = ENOBUFS;
274                         goto cleanup;
275                 } else {
276                         cm = mtod(control, struct cmsghdr *);
277                         cm->cmsg_len = control->m_len;
278                         cm->cmsg_level = SOL_SOCKET;
279                         cm->cmsg_type = SCM_RIGHTS;
280                 }
281         }
282
283         error = kern_sendmsg(uap->s, sa, &auio, control, uap->flags,
284             &uap->sysmsg_result);
285
286 cleanup:
287         if (sa)
288                 FREE(sa, M_SONAME);
289         iovec_free(&iov, aiov);
290         return (error);
291 }
292
293 int
294 orecv(struct orecv_args *uap)
295 {
296         struct thread *td = curthread;
297         struct uio auio;
298         struct iovec aiov;
299         int error;
300
301         aiov.iov_base = uap->buf;
302         aiov.iov_len = uap->len;
303         auio.uio_iov = &aiov;
304         auio.uio_iovcnt = 1;
305         auio.uio_offset = 0;
306         auio.uio_resid = uap->len;
307         auio.uio_segflg = UIO_USERSPACE;
308         auio.uio_rw = UIO_READ;
309         auio.uio_td = td;
310
311         error = kern_recvmsg(uap->s, NULL, &auio, NULL, &uap->flags,
312            &uap->sysmsg_result);
313
314         return (error);
315 }
316
317 int
318 orecvfrom(struct recvfrom_args *uap)
319 {
320         struct thread *td = curthread;
321         struct uio auio;
322         struct iovec aiov;
323         struct sockaddr *sa = NULL;
324         int error, fromlen;
325
326         if (uap->from && uap->fromlenaddr) {
327                 error = copyin(uap->fromlenaddr, &fromlen, sizeof(fromlen));
328                 if (error)
329                         return (error);
330                 if (fromlen < 0)
331                         return (EINVAL);
332         } else {
333                 fromlen = 0;
334         }
335         aiov.iov_base = uap->buf;
336         aiov.iov_len = uap->len;
337         auio.uio_iov = &aiov;
338         auio.uio_iovcnt = 1;
339         auio.uio_offset = 0;
340         auio.uio_resid = uap->len;
341         auio.uio_segflg = UIO_USERSPACE;
342         auio.uio_rw = UIO_READ;
343         auio.uio_td = td;
344
345         error = kern_recvmsg(uap->s, uap->from ? &sa : NULL, &auio, NULL,
346             &uap->flags, &uap->sysmsg_result);
347
348         if (error == 0 && uap->from) {
349                 fromlen = MIN(fromlen, sa->sa_len);
350                 error = compat_43_copyout_sockaddr(sa, uap->from, fromlen);
351                 if (error == 0)
352                         /*
353                          * Old recvfrom didn't signal an error if this
354                          * next copyout failed.
355                          */
356                         copyout(&fromlen, uap->fromlenaddr, sizeof(fromlen));
357         }
358         if (sa)
359                 FREE(sa, M_SONAME);
360
361         return (error);
362 }
363
364 int
365 orecvmsg(struct orecvmsg_args *uap)
366 {
367         struct thread *td = curthread;
368         struct msghdr msg;
369         struct uio auio;
370         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
371         struct mbuf *m, *control = NULL;
372         struct sockaddr *sa = NULL;
373         caddr_t ctlbuf;
374         socklen_t *ufromlenp, *ucontrollenp;
375         int error, fromlen, controllen, len, flags, *uflagsp;
376
377         /*
378          * This copyin handles everything except the iovec.
379          */
380         error = copyin(uap->msg, &msg, sizeof(struct omsghdr));
381         if (error)
382                 return (error);
383
384         if (msg.msg_name && msg.msg_namelen < 0)
385                 return (EINVAL);
386         if (msg.msg_control && msg.msg_controllen < 0)
387                 return (EINVAL);
388
389         ufromlenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
390             msg_namelen));
391         ucontrollenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
392             msg_controllen));
393         uflagsp = (int *)((caddr_t)uap->msg + offsetof(struct msghdr,
394             msg_flags));
395
396         /*
397          * Populate auio.
398          */
399         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
400             &auio.uio_resid);
401         if (error)
402                 return (error);
403         auio.uio_iov = iov;
404         auio.uio_iovcnt = msg.msg_iovlen;
405         auio.uio_offset = 0;
406         auio.uio_segflg = UIO_USERSPACE;
407         auio.uio_rw = UIO_READ;
408         auio.uio_td = td;
409
410         flags = msg.msg_flags;
411
412         error = kern_recvmsg(uap->s, msg.msg_name ? &sa : NULL, &auio,
413             msg.msg_control ? &control : NULL, &flags, &uap->sysmsg_result);
414
415         /*
416          * Copyout msg.msg_name and msg.msg_namelen.
417          */
418         if (error == 0 && msg.msg_name) {
419                 fromlen = MIN(msg.msg_namelen, sa->sa_len);
420                 error = compat_43_copyout_sockaddr(sa, msg.msg_name, fromlen);
421                 if (error == 0)
422                         /*
423                          * Old recvfrom didn't signal an error if this
424                          * next copyout failed.
425                          */
426                         copyout(&fromlen, ufromlenp, sizeof(*ufromlenp));
427         }
428
429         /*
430          * Copyout msg.msg_control and msg.msg_controllen.
431          */
432         if (error == 0 && msg.msg_control) {
433                 /*
434                  * If we receive access rights, trim the cmsghdr; anything
435                  * else is tossed.
436                  */
437                 if (mtod((struct mbuf *)msg.msg_control,
438                     struct cmsghdr *)->cmsg_level != SOL_SOCKET ||
439                     mtod((struct mbuf *)msg.msg_control,
440                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
441                         int temp = 0;
442                         error = copyout(&temp, ucontrollenp,
443                             sizeof(*ucontrollenp));
444                         goto cleanup;
445                 }
446                 ((struct mbuf *)msg.msg_control)->m_len -=
447                     sizeof(struct cmsghdr);
448                 ((struct mbuf *)msg.msg_control)->m_data +=
449                     sizeof(struct cmsghdr);
450
451                 len = msg.msg_controllen;
452                 m = control;
453                 ctlbuf = (caddr_t)msg.msg_control;
454
455                 while(m && len > 0) {
456                         unsigned int tocopy;
457
458                         if (len >= m->m_len) {
459                                 tocopy = m->m_len;
460                         } else {
461                                 msg.msg_flags |= MSG_CTRUNC;
462                                 tocopy = len;
463                         }
464
465                         error = copyout(mtod(m, caddr_t), ctlbuf,
466                             tocopy);
467                         if (error)
468                                 goto cleanup;
469
470                         ctlbuf += tocopy;
471                         len -= tocopy;
472                         m = m->m_next;
473                 }
474                 controllen = ctlbuf - (caddr_t)msg.msg_control;
475                 error = copyout(&controllen, ucontrollenp,
476                     sizeof(*ucontrollenp));
477         }
478
479         if (error == 0)
480                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
481
482 cleanup:
483         if (sa)
484                 FREE(sa, M_SONAME);
485         iovec_free(&iov, aiov);
486         if (control)
487                 m_freem(control);
488         return (error);
489 }
490