Merge from vendor branch TCPDUMP:
[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, &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, 0, NULL, 0, &uap->sysmsg_result);
132         }
133         return (error);
134 }
135
136 int
137 sys_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 sys_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 sys_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 sys_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 cleanup2;
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         iovec_free(&iov, aiov);
288 cleanup2:
289         if (sa)
290                 FREE(sa, M_SONAME);
291         return (error);
292 }
293
294 int
295 sys_orecv(struct orecv_args *uap)
296 {
297         struct thread *td = curthread;
298         struct uio auio;
299         struct iovec aiov;
300         int error;
301
302         aiov.iov_base = uap->buf;
303         aiov.iov_len = uap->len;
304         auio.uio_iov = &aiov;
305         auio.uio_iovcnt = 1;
306         auio.uio_offset = 0;
307         auio.uio_resid = uap->len;
308         auio.uio_segflg = UIO_USERSPACE;
309         auio.uio_rw = UIO_READ;
310         auio.uio_td = td;
311
312         error = kern_recvmsg(uap->s, NULL, &auio, NULL, &uap->flags,
313            &uap->sysmsg_result);
314
315         return (error);
316 }
317
318 int
319 sys_orecvfrom(struct recvfrom_args *uap)
320 {
321         struct thread *td = curthread;
322         struct uio auio;
323         struct iovec aiov;
324         struct sockaddr *sa = NULL;
325         int error, fromlen;
326
327         if (uap->from && uap->fromlenaddr) {
328                 error = copyin(uap->fromlenaddr, &fromlen, sizeof(fromlen));
329                 if (error)
330                         return (error);
331                 if (fromlen < 0)
332                         return (EINVAL);
333         } else {
334                 fromlen = 0;
335         }
336         aiov.iov_base = uap->buf;
337         aiov.iov_len = uap->len;
338         auio.uio_iov = &aiov;
339         auio.uio_iovcnt = 1;
340         auio.uio_offset = 0;
341         auio.uio_resid = uap->len;
342         auio.uio_segflg = UIO_USERSPACE;
343         auio.uio_rw = UIO_READ;
344         auio.uio_td = td;
345
346         error = kern_recvmsg(uap->s, uap->from ? &sa : NULL, &auio, NULL,
347             &uap->flags, &uap->sysmsg_result);
348
349         if (error == 0 && uap->from) {
350                 if (sa != NULL) {
351                         fromlen = MIN(fromlen, sa->sa_len);
352                         error = compat_43_copyout_sockaddr(sa, uap->from,
353                                                            fromlen);
354                 } else
355                         fromlen = 0;
356                 if (error == 0)
357                         /*
358                          * Old recvfrom didn't signal an error if this
359                          * next copyout failed.
360                          */
361                         copyout(&fromlen, uap->fromlenaddr, sizeof(fromlen));
362         }
363         if (sa)
364                 FREE(sa, M_SONAME);
365
366         return (error);
367 }
368
369 int
370 sys_orecvmsg(struct orecvmsg_args *uap)
371 {
372         struct thread *td = curthread;
373         struct msghdr msg;
374         struct uio auio;
375         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
376         struct mbuf *m, *control = NULL;
377         struct sockaddr *sa = NULL;
378         caddr_t ctlbuf;
379         socklen_t *ufromlenp, *ucontrollenp;
380         int error, fromlen, controllen, len, flags, *uflagsp;
381
382         /*
383          * This copyin handles everything except the iovec.
384          */
385         error = copyin(uap->msg, &msg, sizeof(struct omsghdr));
386         if (error)
387                 return (error);
388
389         if (msg.msg_name && msg.msg_namelen < 0)
390                 return (EINVAL);
391         if (msg.msg_control && msg.msg_controllen < 0)
392                 return (EINVAL);
393
394         ufromlenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
395             msg_namelen));
396         ucontrollenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
397             msg_controllen));
398         uflagsp = (int *)((caddr_t)uap->msg + offsetof(struct msghdr,
399             msg_flags));
400
401         /*
402          * Populate auio.
403          */
404         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
405                              &auio.uio_resid);
406         if (error)
407                 return (error);
408         auio.uio_iov = iov;
409         auio.uio_iovcnt = msg.msg_iovlen;
410         auio.uio_offset = 0;
411         auio.uio_segflg = UIO_USERSPACE;
412         auio.uio_rw = UIO_READ;
413         auio.uio_td = td;
414
415         flags = msg.msg_flags;
416
417         error = kern_recvmsg(uap->s, msg.msg_name ? &sa : NULL, &auio,
418             msg.msg_control ? &control : NULL, &flags, &uap->sysmsg_result);
419
420         /*
421          * Copyout msg.msg_name and msg.msg_namelen.
422          */
423         if (error == 0 && msg.msg_name) {
424                 if (sa != NULL) {
425                         fromlen = MIN(msg.msg_namelen, sa->sa_len);
426                         error = compat_43_copyout_sockaddr(sa, msg.msg_name,
427                                                            fromlen);
428                 } else
429                         fromlen = 0;
430                 if (error == 0)
431                         /*
432                          * Old recvfrom didn't signal an error if this
433                          * next copyout failed.
434                          */
435                         copyout(&fromlen, ufromlenp, sizeof(*ufromlenp));
436         }
437
438         /*
439          * Copyout msg.msg_control and msg.msg_controllen.
440          */
441         if (error == 0 && msg.msg_control) {
442                 /*
443                  * If we receive access rights, trim the cmsghdr; anything
444                  * else is tossed.
445                  */
446                 if (mtod((struct mbuf *)msg.msg_control,
447                     struct cmsghdr *)->cmsg_level != SOL_SOCKET ||
448                     mtod((struct mbuf *)msg.msg_control,
449                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
450                         int temp = 0;
451                         error = copyout(&temp, ucontrollenp,
452                             sizeof(*ucontrollenp));
453                         goto cleanup;
454                 }
455                 ((struct mbuf *)msg.msg_control)->m_len -=
456                     sizeof(struct cmsghdr);
457                 ((struct mbuf *)msg.msg_control)->m_data +=
458                     sizeof(struct cmsghdr);
459
460                 len = msg.msg_controllen;
461                 m = control;
462                 ctlbuf = (caddr_t)msg.msg_control;
463
464                 while(m && len > 0) {
465                         unsigned int tocopy;
466
467                         if (len >= m->m_len) {
468                                 tocopy = m->m_len;
469                         } else {
470                                 msg.msg_flags |= MSG_CTRUNC;
471                                 tocopy = len;
472                         }
473
474                         error = copyout(mtod(m, caddr_t), ctlbuf,
475                             tocopy);
476                         if (error)
477                                 goto cleanup;
478
479                         ctlbuf += tocopy;
480                         len -= tocopy;
481                         m = m->m_next;
482                 }
483                 controllen = ctlbuf - (caddr_t)msg.msg_control;
484                 error = copyout(&controllen, ucontrollenp,
485                     sizeof(*ucontrollenp));
486         }
487
488         if (error == 0)
489                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
490
491 cleanup:
492         if (sa)
493                 FREE(sa, M_SONAME);
494         iovec_free(&iov, aiov);
495         if (control)
496                 m_freem(control);
497         return (error);
498 }
499