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