Initial import of binutils 2.22 on the new vendor branch
[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 <sys/mplock2.h>
58
59 #include "43bsd_socket.h"
60
61 /*
62  * System call interface to the socket abstraction.
63  */
64
65 static int
66 compat_43_getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
67 {
68         struct sockaddr *sa;
69         int error;
70
71         *namp = NULL;
72         if (len > SOCK_MAXADDRLEN)
73                 return ENAMETOOLONG;
74         if (len < offsetof(struct sockaddr, sa_data[0]))
75                 return EDOM;
76         MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK);
77         error = copyin(uaddr, sa, len);
78         if (error) {
79                 FREE(sa, M_SONAME);
80         } else {
81                 /*
82                  * Convert to the 4.4BSD sockaddr structure.
83                  */
84                 sa->sa_family = sa->sa_len;
85                 sa->sa_len = len;
86                 *namp = sa;
87         }
88         return error;
89 }
90
91 static int
92 compat_43_copyout_sockaddr(struct sockaddr *sa, caddr_t uaddr, int sa_len)
93 {
94         int error;
95
96         ((struct osockaddr *)sa)->sa_family = sa->sa_family;
97         error = copyout(sa, uaddr, sa_len);
98
99         return (error);
100 }
101
102 /*
103  * MPALMOSTSAFE
104  */
105 int
106 sys_oaccept(struct accept_args *uap)
107 {
108         struct sockaddr *sa = NULL;
109         int sa_len;
110         int error;
111
112         if (uap->name) {
113                 error = copyin(uap->anamelen, &sa_len, sizeof(sa_len));
114                 if (error)
115                         return (error);
116
117                 get_mplock();
118                 error = kern_accept(uap->s, 0, &sa, &sa_len,
119                                     &uap->sysmsg_iresult);
120                 rel_mplock();
121
122                 if (error) {
123                         /*
124                          * return a namelen of zero for older code which
125                          * might ignore the return value from accept.
126                          */
127                         sa_len = 0;
128                         copyout(&sa_len, uap->anamelen, sizeof(*uap->anamelen));
129                 } else {
130                         compat_43_copyout_sockaddr(sa, uap->name, sa_len);
131                         if (error == 0) {
132                                 error = copyout(&sa_len, uap->anamelen,
133                                     sizeof(*uap->anamelen));
134                         }
135                 }
136                 if (sa)
137                         FREE(sa, M_SONAME);
138         } else {
139                 get_mplock();
140                 error = kern_accept(uap->s, 0, NULL, 0, &uap->sysmsg_iresult);
141                 rel_mplock();
142         }
143         return (error);
144 }
145
146 /*
147  * MPALMOSTSAFE
148  */
149 int
150 sys_ogetsockname(struct getsockname_args *uap)
151 {
152         struct sockaddr *sa = NULL;
153         int error, sa_len;
154
155         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
156         if (error)
157                 return (error);
158
159         get_mplock();
160         error = kern_getsockname(uap->fdes, &sa, &sa_len);
161         rel_mplock();
162
163         if (error == 0)
164                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
165         if (error == 0) {
166                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
167         }
168         if (sa)
169                 FREE(sa, M_SONAME);
170         return (error);
171 }
172
173 /*
174  * MPALMOSTSAFE
175  */
176 int
177 sys_ogetpeername(struct ogetpeername_args *uap)
178 {
179         struct sockaddr *sa = NULL;
180         int error, sa_len;
181
182         error = copyin(uap->alen, &sa_len, sizeof(sa_len));
183         if (error)
184                 return (error);
185
186         get_mplock();
187         error = kern_getpeername(uap->fdes, &sa, &sa_len);
188         rel_mplock();
189
190         if (error == 0) {
191                 error = compat_43_copyout_sockaddr(sa, uap->asa, sa_len);
192         }
193         if (error == 0)
194                 error = copyout(&sa_len, uap->alen, sizeof(*uap->alen));
195         if (sa)
196                 FREE(sa, M_SONAME);
197         return (error);
198 }
199
200 /*
201  * MPALMOSTSAFE
202  */
203 int
204 sys_osend(struct osend_args *uap)
205 {
206         struct thread *td = curthread;
207         struct uio auio;
208         struct iovec aiov;
209         int error;
210
211         aiov.iov_base = uap->buf;
212         aiov.iov_len = uap->len;
213         auio.uio_iov = &aiov;
214         auio.uio_iovcnt = 1;
215         auio.uio_offset = 0;
216         auio.uio_resid = uap->len;
217         auio.uio_segflg = UIO_USERSPACE;
218         auio.uio_rw = UIO_WRITE;
219         auio.uio_td = td;
220
221         get_mplock();
222         error = kern_sendmsg(uap->s, NULL, &auio, NULL, uap->flags,
223                              &uap->sysmsg_szresult);
224         rel_mplock();
225
226         return (error);
227 }
228
229 /*
230  * MPALMOSTSAFE
231  */
232 int
233 sys_osendmsg(struct osendmsg_args *uap)
234 {
235         struct thread *td = curthread;
236         struct msghdr msg;
237         struct uio auio;
238         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
239         struct sockaddr *sa = NULL;
240         struct mbuf *control = NULL;
241         struct cmsghdr *cm;
242         int error;
243
244         error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
245         if (error)
246                 return (error);
247
248         /*
249          * Conditionally copyin msg.msg_name.
250          */
251         if (msg.msg_name) {
252                 error = compat_43_getsockaddr(&sa, msg.msg_name,
253                     msg.msg_namelen);
254                 if (error)
255                         return (error);
256         }
257
258         /*
259          * Populate auio.
260          */
261         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
262                              &auio.uio_resid);
263         if (error)
264                 goto cleanup2;
265         auio.uio_iov = iov;
266         auio.uio_iovcnt = msg.msg_iovlen;
267         auio.uio_offset = 0;
268         auio.uio_segflg = UIO_USERSPACE;
269         auio.uio_rw = UIO_WRITE;
270         auio.uio_td = td;
271
272         /*
273          * Conditionally copyin msg.msg_control.
274          */
275         if (msg.msg_control) {
276                 if (msg.msg_controllen < 0 || msg.msg_controllen > MLEN) {
277                         error = EINVAL;
278                         goto cleanup;
279                 }
280                 control = m_get(MB_WAIT, MT_CONTROL);
281                 if (control == NULL) {
282                         error = ENOBUFS;
283                         goto cleanup;
284                 }
285                 control->m_len = msg.msg_controllen;
286                 error = copyin(msg.msg_control, mtod(control, caddr_t),
287                     msg.msg_controllen);
288                 if (error) {
289                         m_free(control);
290                         goto cleanup;
291                 }
292                 /*
293                  * In 4.3BSD, the only type of ancillary data was
294                  * access rights and this data did not use a header
295                  * to identify it's type.  Thus, we must prepend the
296                  * control data with the proper cmsghdr structure
297                  * so that the kernel recognizes it as access rights.
298                  */
299                 M_PREPEND(control, sizeof(*cm), MB_WAIT);
300                 if (control == NULL) {
301                         error = ENOBUFS;
302                         goto cleanup;
303                 } else {
304                         cm = mtod(control, struct cmsghdr *);
305                         cm->cmsg_len = control->m_len;
306                         cm->cmsg_level = SOL_SOCKET;
307                         cm->cmsg_type = SCM_RIGHTS;
308                 }
309         }
310
311         get_mplock();
312         error = kern_sendmsg(uap->s, sa, &auio, control, uap->flags,
313                              &uap->sysmsg_szresult);
314         rel_mplock();
315
316 cleanup:
317         iovec_free(&iov, aiov);
318 cleanup2:
319         if (sa)
320                 FREE(sa, M_SONAME);
321         return (error);
322 }
323
324 /*
325  * MPALMOSTSAFE
326  */
327 int
328 sys_orecv(struct orecv_args *uap)
329 {
330         struct thread *td = curthread;
331         struct uio auio;
332         struct iovec aiov;
333         int error;
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         get_mplock();
346         error = kern_recvmsg(uap->s, NULL, &auio, NULL, &uap->flags,
347                              &uap->sysmsg_szresult);
348         rel_mplock();
349
350         return (error);
351 }
352
353 /*
354  * MPALMOSTSAFE
355  */
356 int
357 sys_orecvfrom(struct recvfrom_args *uap)
358 {
359         struct thread *td = curthread;
360         struct uio auio;
361         struct iovec aiov;
362         struct sockaddr *sa = NULL;
363         int error, fromlen;
364
365         if (uap->from && uap->fromlenaddr) {
366                 error = copyin(uap->fromlenaddr, &fromlen, sizeof(fromlen));
367                 if (error)
368                         return (error);
369                 if (fromlen < 0)
370                         return (EINVAL);
371         } else {
372                 fromlen = 0;
373         }
374         aiov.iov_base = uap->buf;
375         aiov.iov_len = uap->len;
376         auio.uio_iov = &aiov;
377         auio.uio_iovcnt = 1;
378         auio.uio_offset = 0;
379         auio.uio_resid = uap->len;
380         auio.uio_segflg = UIO_USERSPACE;
381         auio.uio_rw = UIO_READ;
382         auio.uio_td = td;
383
384         get_mplock();
385         error = kern_recvmsg(uap->s, uap->from ? &sa : NULL, &auio, NULL,
386                              &uap->flags, &uap->sysmsg_szresult);
387         rel_mplock();
388
389         if (error == 0 && uap->from) {
390                 if (sa != NULL) {
391                         fromlen = MIN(fromlen, sa->sa_len);
392                         error = compat_43_copyout_sockaddr(sa, uap->from,
393                                                            fromlen);
394                 } else
395                         fromlen = 0;
396                 if (error == 0)
397                         /*
398                          * Old recvfrom didn't signal an error if this
399                          * next copyout failed.
400                          */
401                         copyout(&fromlen, uap->fromlenaddr, sizeof(fromlen));
402         }
403         if (sa)
404                 FREE(sa, M_SONAME);
405
406         return (error);
407 }
408
409 /*
410  * MPALMOSTSAFE
411  */
412 int
413 sys_orecvmsg(struct orecvmsg_args *uap)
414 {
415         struct thread *td = curthread;
416         struct msghdr msg;
417         struct uio auio;
418         struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
419         struct mbuf *m, *control = NULL;
420         struct sockaddr *sa = NULL;
421         caddr_t ctlbuf;
422         socklen_t *ufromlenp, *ucontrollenp;
423         int error, fromlen, controllen, len, flags, *uflagsp;
424
425         /*
426          * This copyin handles everything except the iovec.
427          */
428         error = copyin(uap->msg, &msg, sizeof(struct omsghdr));
429         if (error)
430                 return (error);
431
432         if (msg.msg_name && msg.msg_namelen < 0)
433                 return (EINVAL);
434         if (msg.msg_control && msg.msg_controllen < 0)
435                 return (EINVAL);
436
437         ufromlenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
438             msg_namelen));
439         ucontrollenp = (socklen_t *)((caddr_t)uap->msg + offsetof(struct msghdr,
440             msg_controllen));
441         uflagsp = (int *)((caddr_t)uap->msg + offsetof(struct msghdr,
442             msg_flags));
443
444         /*
445          * Populate auio.
446          */
447         error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
448                              &auio.uio_resid);
449         if (error)
450                 return (error);
451         auio.uio_iov = iov;
452         auio.uio_iovcnt = msg.msg_iovlen;
453         auio.uio_offset = 0;
454         auio.uio_segflg = UIO_USERSPACE;
455         auio.uio_rw = UIO_READ;
456         auio.uio_td = td;
457
458         flags = msg.msg_flags;
459
460         get_mplock();
461         error = kern_recvmsg(uap->s, (msg.msg_name ? &sa : NULL), &auio,
462                              (msg.msg_control ? &control : NULL), &flags,
463                              &uap->sysmsg_szresult);
464         rel_mplock();
465
466         /*
467          * Copyout msg.msg_name and msg.msg_namelen.
468          */
469         if (error == 0 && msg.msg_name) {
470                 if (sa != NULL) {
471                         fromlen = MIN(msg.msg_namelen, sa->sa_len);
472                         error = compat_43_copyout_sockaddr(sa, msg.msg_name,
473                                                            fromlen);
474                 } else
475                         fromlen = 0;
476                 if (error == 0)
477                         /*
478                          * Old recvfrom didn't signal an error if this
479                          * next copyout failed.
480                          */
481                         copyout(&fromlen, ufromlenp, sizeof(*ufromlenp));
482         }
483
484         /*
485          * Copyout msg.msg_control and msg.msg_controllen.
486          */
487         if (error == 0 && msg.msg_control) {
488                 /*
489                  * If we receive access rights, trim the cmsghdr; anything
490                  * else is tossed.
491                  */
492                 if (mtod((struct mbuf *)msg.msg_control,
493                     struct cmsghdr *)->cmsg_level != SOL_SOCKET ||
494                     mtod((struct mbuf *)msg.msg_control,
495                     struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
496                         int temp = 0;
497                         error = copyout(&temp, ucontrollenp,
498                             sizeof(*ucontrollenp));
499                         goto cleanup;
500                 }
501                 ((struct mbuf *)msg.msg_control)->m_len -=
502                     sizeof(struct cmsghdr);
503                 ((struct mbuf *)msg.msg_control)->m_data +=
504                     sizeof(struct cmsghdr);
505
506                 len = msg.msg_controllen;
507                 m = control;
508                 ctlbuf = (caddr_t)msg.msg_control;
509
510                 while(m && len > 0) {
511                         unsigned int tocopy;
512
513                         if (len >= m->m_len) {
514                                 tocopy = m->m_len;
515                         } else {
516                                 msg.msg_flags |= MSG_CTRUNC;
517                                 tocopy = len;
518                         }
519
520                         error = copyout(mtod(m, caddr_t), ctlbuf,
521                             tocopy);
522                         if (error)
523                                 goto cleanup;
524
525                         ctlbuf += tocopy;
526                         len -= tocopy;
527                         m = m->m_next;
528                 }
529                 controllen = ctlbuf - (caddr_t)msg.msg_control;
530                 error = copyout(&controllen, ucontrollenp,
531                     sizeof(*ucontrollenp));
532         }
533
534         if (error == 0)
535                 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
536
537 cleanup:
538         if (sa)
539                 FREE(sa, M_SONAME);
540         iovec_free(&iov, aiov);
541         if (control)
542                 m_freem(control);
543         return (error);
544 }
545