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