1 /*
2 * Copyright (c) 1982, 1986, 1989, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
34 * $FreeBSD: src/sys/kern/uipc_syscalls.c,v 1.20.2.3 1999/09/05 08:15:36 peter Exp $
35 */
36
37 #include "opt_ktrace.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/sysproto.h>
42 #include <sys/filedesc.h>
43 #include <sys/proc.h>
44 #include <sys/file.h>
45 #include <sys/buf.h>
46 #include <sys/malloc.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/stat.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/signalvar.h>
53 #include <sys/un.h>
54 #ifdef KTRACE
55 #include <sys/ktrace.h>
56 #endif
57
58 extern int sendit __P((struct proc *p, int s, struct msghdr *mp, int flags,
59 int *retsize));
60 extern int recvit __P((struct proc *p, int s, struct msghdr *mp,
61 caddr_t namelenp, int *retsize));
62
63 static int accept1 __P((struct proc *p, struct accept_args *uap, int *retval,
64 int compat));
65 static int getsockname1 __P((struct proc *p, struct getsockname_args *uap,
66 int *retval, int compat));
67 static int getpeername1 __P((struct proc *p, struct getpeername_args *uap,
68 int *retval, int compat));
69
70 /*
71 * System call interface to the socket abstraction.
72 */
73 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
74 #define COMPAT_OLDSOCK
75 #endif
76
77 extern struct fileops socketops;
78
79 int
80 socket(p, uap, retval)
81 struct proc *p;
82 register struct socket_args /* {
83 int domain;
84 int type;
85 int protocol;
86 } */ *uap;
87 int *retval;
88 {
89 struct filedesc *fdp = p->p_fd;
90 struct socket *so;
91 struct file *fp;
92 int fd, error;
93
94 error = falloc(p, &fp, &fd);
95 if (error)
96 return (error);
97 fp->f_flag = FREAD|FWRITE;
98 fp->f_type = DTYPE_SOCKET;
99 fp->f_ops = &socketops;
100 error = socreate(uap->domain, &so, uap->type, uap->protocol, p);
101 if (error) {
102 fdp->fd_ofiles[fd] = 0;
103 ffree(fp);
104 } else {
105 fp->f_data = (caddr_t)so;
106 *retval = fd;
107 }
108 return (error);
109 }
110
111 /* ARGSUSED */
112 int
113 bind(p, uap, retval)
114 struct proc *p;
115 register struct bind_args /* {
116 int s;
117 caddr_t name;
118 int namelen;
119 } */ *uap;
120 int *retval;
121 {
122 struct file *fp;
123 struct mbuf *nam;
124 int error;
125
126 error = getsock(p->p_fd, uap->s, &fp);
127 if (error)
128 return (error);
129 error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
130 if (error)
131 return (error);
132 error = sobind((struct socket *)fp->f_data, nam);
133 m_freem(nam);
134 return (error);
135 }
136
137 /* ARGSUSED */
138 int
139 listen(p, uap, retval)
140 struct proc *p;
141 register struct listen_args /* {
142 int s;
143 int backlog;
144 } */ *uap;
145 int *retval;
146 {
147 struct file *fp;
148 int error;
149
150 error = getsock(p->p_fd, uap->s, &fp);
151 if (error)
152 return (error);
153 return (solisten((struct socket *)fp->f_data, uap->backlog));
154 }
155
156 static int
157 accept1(p, uap, retval, compat)
158 struct proc *p;
159 register struct accept_args /* {
160 int s;
161 caddr_t name;
162 int *anamelen;
163 } */ *uap;
164 int *retval;
165 int compat;
166 {
167 struct file *fp;
168 struct mbuf *nam;
169 int namelen, error, s;
170 struct socket *head, *so;
171 short fflag; /* type must match fp->f_flag */
172
173 if (uap->name) {
174 error = copyin((caddr_t)uap->anamelen, (caddr_t)&namelen,
175 sizeof (namelen));
176 if(error)
177 return (error);
178 }
179 error = getsock(p->p_fd, uap->s, &fp);
180 if (error)
181 return (error);
182 s = splnet();
183 head = (struct socket *)fp->f_data;
184 if ((head->so_options & SO_ACCEPTCONN) == 0) {
185 splx(s);
186 return (EINVAL);
187 }
188 if ((head->so_state & SS_NBIO) && head->so_comp.tqh_first == NULL) {
189 splx(s);
190 return (EWOULDBLOCK);
191 }
192 while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
193 if (head->so_state & SS_CANTRCVMORE) {
194 head->so_error = ECONNABORTED;
195 break;
196 }
197 error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH,
198 "accept", 0);
199 if (error) {
200 splx(s);
201 return (error);
202 }
203 }
204 if (head->so_error) {
205 error = head->so_error;
206 head->so_error = 0;
207 splx(s);
208 return (error);
209 }
210
211 /*
212 * At this point we know that there is at least one connection
213 * ready to be accepted. Remove it from the queue prior to
214 * allocating the file descriptor for it since falloc() may
215 * block allowing another process to accept the connection
216 * instead.
217 */
218 so = head->so_comp.tqh_first;
219 TAILQ_REMOVE(&head->so_comp, so, so_list);
220 head->so_qlen--;
221
222 fflag = fp->f_flag;
223 error = falloc(p, &fp, retval);
224 if (error) {
225 /*
226 * Probably ran out of file descriptors. Put the
227 * unaccepted connection back onto the queue and
228 * do another wakeup so some other process might
229 * have a chance at it.
230 */
231 TAILQ_INSERT_HEAD(&head->so_comp, so, so_list);
232 head->so_qlen++;
233 wakeup_one(&head->so_timeo);
234 splx(s);
235 return (error);
236 }
237
238 so->so_state &= ~SS_COMP;
239 so->so_head = NULL;
240
241 fp->f_type = DTYPE_SOCKET;
242 fp->f_flag = fflag;
243 fp->f_ops = &socketops;
244 fp->f_data = (caddr_t)so;
245 nam = m_get(M_WAIT, MT_SONAME);
246 (void) soaccept(so, nam);
247 if (uap->name) {
248 /* check length before it is destroyed */
249 if (namelen > nam->m_len)
250 namelen = nam->m_len;
251 #ifdef COMPAT_OLDSOCK
252 if (compat)
253 mtod(nam, struct osockaddr *)->sa_family =
254 mtod(nam, struct sockaddr *)->sa_family;
255 #endif
256 /* SHOULD COPY OUT A CHAIN HERE */
257 error = copyout(mtod(nam, caddr_t), (caddr_t)uap->name,
258 (u_int)namelen);
259 if (!error)
260 error = copyout((caddr_t)&namelen,
261 (caddr_t)uap->anamelen, sizeof (*uap->anamelen));
262 }
263 m_freem(nam);
264 splx(s);
265 return (error);
266 }
267
268 int
269 accept(p, uap, retval)
270 struct proc *p;
271 struct accept_args *uap;
272 int *retval;
273 {
274
275 return (accept1(p, uap, retval, 0));
276 }
277
278 #ifdef COMPAT_OLDSOCK
279 int
280 oaccept(p, uap, retval)
281 struct proc *p;
282 struct accept_args *uap;
283 int *retval;
284 {
285
286 return (accept1(p, uap, retval, 1));
287 }
288 #endif /* COMPAT_OLDSOCK */
289
290 /* ARGSUSED */
291 int
292 connect(p, uap, retval)
293 struct proc *p;
294 register struct connect_args /* {
295 int s;
296 caddr_t name;
297 int namelen;
298 } */ *uap;
299 int *retval;
300 {
301 struct file *fp;
302 register struct socket *so;
303 struct mbuf *nam;
304 int error, s;
305
306 error = getsock(p->p_fd, uap->s, &fp);
307 if (error)
308 return (error);
309 so = (struct socket *)fp->f_data;
310 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
311 return (EALREADY);
312 error = sockargs(&nam, uap->name, uap->namelen, MT_SONAME);
313 if (error)
314 return (error);
315 error = soconnect(so, nam);
316 if (error)
317 goto bad;
318 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
319 m_freem(nam);
320 return (EINPROGRESS);
321 }
322 s = splnet();
323 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
324 error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
325 "connec", 0);
326 if (error)
327 break;
328 }
329 if (error == 0) {
330 error = so->so_error;
331 so->so_error = 0;
332 }
333 splx(s);
334 bad:
335 so->so_state &= ~SS_ISCONNECTING;
336 m_freem(nam);
337 if (error == ERESTART)
338 error = EINTR;
339 return (error);
340 }
341
342 int
343 socketpair(p, uap, retval)
344 struct proc *p;
345 register struct socketpair_args /* {
346 int domain;
347 int type;
348 int protocol;
349 int *rsv;
350 } */ *uap;
351 int retval[];
352 {
353 register struct filedesc *fdp = p->p_fd;
354 struct file *fp1, *fp2;
355 struct socket *so1, *so2;
356 int fd, error, sv[2];
357
358 error = socreate(uap->domain, &so1, uap->type, uap->protocol, p);
359 if (error)
360 return (error);
361 error = socreate(uap->domain, &so2, uap->type, uap->protocol, p);
362 if (error)
363 goto free1;
364 error = falloc(p, &fp1, &fd);
365 if (error)
366 goto free2;
367 sv[0] = fd;
368 fp1->f_flag = FREAD|FWRITE;
369 fp1->f_type = DTYPE_SOCKET;
370 fp1->f_ops = &socketops;
371 fp1->f_data = (caddr_t)so1;
372 error = falloc(p, &fp2, &fd);
373 if (error)
374 goto free3;
375 fp2->f_flag = FREAD|FWRITE;
376 fp2->f_type = DTYPE_SOCKET;
377 fp2->f_ops = &socketops;
378 fp2->f_data = (caddr_t)so2;
379 sv[1] = fd;
380 error = soconnect2(so1, so2);
381 if (error)
382 goto free4;
383 if (uap->type == SOCK_DGRAM) {
384 /*
385 * Datagram socket connection is asymmetric.
386 */
387 error = soconnect2(so2, so1);
388 if (error)
389 goto free4;
390 }
391 error = copyout((caddr_t)sv, (caddr_t)uap->rsv, 2 * sizeof (int));
392 #if 0 /* old pipe(2) syscall compatability, unused these days */
393 retval[0] = sv[0]; /* XXX ??? */
394 retval[1] = sv[1]; /* XXX ??? */
395 #endif
396 return (error);
397 free4:
398 ffree(fp2);
399 fdp->fd_ofiles[sv[1]] = 0;
400 free3:
401 ffree(fp1);
402 fdp->fd_ofiles[sv[0]] = 0;
403 free2:
404 (void)soclose(so2);
405 free1:
406 (void)soclose(so1);
407 return (error);
408 }
409
410 int
411 sendit(p, s, mp, flags, retsize)
412 register struct proc *p;
413 int s;
414 register struct msghdr *mp;
415 int flags, *retsize;
416 {
417 struct file *fp;
418 struct uio auio;
419 register struct iovec *iov;
420 register int i;
421 struct mbuf *to, *control;
422 int len, error;
423 #ifdef KTRACE
424 struct iovec *ktriov = NULL;
425 #endif
426
427 error = getsock(p->p_fd, s, &fp);
428 if (error)
429 return (error);
430 auio.uio_iov = mp->msg_iov;
431 auio.uio_iovcnt = mp->msg_iovlen;
432 auio.uio_segflg = UIO_USERSPACE;
433 auio.uio_rw = UIO_WRITE;
434 auio.uio_procp = p;
435 auio.uio_offset = 0; /* XXX */
436 auio.uio_resid = 0;
437 iov = mp->msg_iov;
438 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
439 if ((auio.uio_resid += iov->iov_len) < 0)
440 return (EINVAL);
441 }
442 if (mp->msg_name) {
443 error = sockargs(&to, mp->msg_name, mp->msg_namelen, MT_SONAME);
444 if (error)
445 return (error);
446 } else
447 to = 0;
448 if (mp->msg_control) {
449 if (mp->msg_controllen < sizeof(struct cmsghdr)
450 #ifdef COMPAT_OLDSOCK
451 && mp->msg_flags != MSG_COMPAT
452 #endif
453 ) {
454 error = EINVAL;
455 goto bad;
456 }
457 error = sockargs(&control, mp->msg_control,
458 mp->msg_controllen, MT_CONTROL);
459 if (error)
460 goto bad;
461 #ifdef COMPAT_OLDSOCK
462 if (mp->msg_flags == MSG_COMPAT) {
463 register struct cmsghdr *cm;
464
465 M_PREPEND(control, sizeof(*cm), M_WAIT);
466 if (control == 0) {
467 error = ENOBUFS;
468 goto bad;
469 } else {
470 cm = mtod(control, struct cmsghdr *);
471 cm->cmsg_len = control->m_len;
472 cm->cmsg_level = SOL_SOCKET;
473 cm->cmsg_type = SCM_RIGHTS;
474 }
475 }
476 #endif
477 } else
478 control = 0;
479 #ifdef KTRACE
480 if (KTRPOINT(p, KTR_GENIO)) {
481 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
482
483 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
484 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
485 }
486 #endif
487 len = auio.uio_resid;
488 error = sosend((struct socket *)fp->f_data, to, &auio,
489 (struct mbuf *)0, control, flags);
490 if (error) {
491 if (auio.uio_resid != len && (error == ERESTART ||
492 error == EINTR || error == EWOULDBLOCK))
493 error = 0;
494 if (error == EPIPE)
495 psignal(p, SIGPIPE);
496 }
497 if (error == 0)
498 *retsize = len - auio.uio_resid;
499 #ifdef KTRACE
500 if (ktriov != NULL) {
501 if (error == 0)
502 ktrgenio(p->p_tracep, s, UIO_WRITE,
503 ktriov, *retsize, error);
504 FREE(ktriov, M_TEMP);
505 }
506 #endif
507 bad:
508 if (to)
509 m_freem(to);
510 return (error);
511 }
512
513 int
514 sendto(p, uap, retval)
515 struct proc *p;
516 register struct sendto_args /* {
517 int s;
518 caddr_t buf;
519 size_t len;
520 int flags;
521 caddr_t to;
522 int tolen;
523 } */ *uap;
524 int *retval;
525 {
526 struct msghdr msg;
527 struct iovec aiov;
528
529 msg.msg_name = uap->to;
530 msg.msg_namelen = uap->tolen;
531 msg.msg_iov = &aiov;
532 msg.msg_iovlen = 1;
533 msg.msg_control = 0;
534 #ifdef COMPAT_OLDSOCK
535 msg.msg_flags = 0;
536 #endif
537 aiov.iov_base = uap->buf;
538 aiov.iov_len = uap->len;
539 return (sendit(p, uap->s, &msg, uap->flags, retval));
540 }
541
542 #ifdef COMPAT_OLDSOCK
543 int
544 osend(p, uap, retval)
545 struct proc *p;
546 register struct osend_args /* {
547 int s;
548 caddr_t buf;
549 int len;
550 int flags;
551 } */ *uap;
552 int *retval;
553 {
554 struct msghdr msg;
555 struct iovec aiov;
556
557 msg.msg_name = 0;
558 msg.msg_namelen = 0;
559 msg.msg_iov = &aiov;
560 msg.msg_iovlen = 1;
561 aiov.iov_base = uap->buf;
562 aiov.iov_len = uap->len;
563 msg.msg_control = 0;
564 msg.msg_flags = 0;
565 return (sendit(p, uap->s, &msg, uap->flags, retval));
566 }
567
568 int
569 osendmsg(p, uap, retval)
570 struct proc *p;
571 register struct osendmsg_args /* {
572 int s;
573 caddr_t msg;
574 int flags;
575 } */ *uap;
576 int *retval;
577 {
578 struct msghdr msg;
579 struct iovec aiov[UIO_SMALLIOV], *iov;
580 int error;
581
582 error = copyin(uap->msg, (caddr_t)&msg, sizeof (struct omsghdr));
583 if (error)
584 return (error);
585 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
586 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
587 return (EMSGSIZE);
588 MALLOC(iov, struct iovec *,
589 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
590 M_WAITOK);
591 } else
592 iov = aiov;
593 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
594 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
595 if (error)
596 goto done;
597 msg.msg_flags = MSG_COMPAT;
598 msg.msg_iov = iov;
599 error = sendit(p, uap->s, &msg, uap->flags, retval);
600 done:
601 if (iov != aiov)
602 FREE(iov, M_IOV);
603 return (error);
604 }
605 #endif
606
607 int
608 sendmsg(p, uap, retval)
609 struct proc *p;
610 register struct sendmsg_args /* {
611 int s;
612 caddr_t msg;
613 int flags;
614 } */ *uap;
615 int *retval;
616 {
617 struct msghdr msg;
618 struct iovec aiov[UIO_SMALLIOV], *iov;
619 int error;
620
621 error = copyin(uap->msg, (caddr_t)&msg, sizeof (msg));
622 if (error)
623 return (error);
624 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
625 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
626 return (EMSGSIZE);
627 MALLOC(iov, struct iovec *,
628 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
629 M_WAITOK);
630 } else
631 iov = aiov;
632 if (msg.msg_iovlen &&
633 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
634 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
635 goto done;
636 msg.msg_iov = iov;
637 #ifdef COMPAT_OLDSOCK
638 msg.msg_flags = 0;
639 #endif
640 error = sendit(p, uap->s, &msg, uap->flags, retval);
641 done:
642 if (iov != aiov)
643 FREE(iov, M_IOV);
644 return (error);
645 }
646
647 int
648 recvit(p, s, mp, namelenp, retsize)
649 register struct proc *p;
650 int s;
651 register struct msghdr *mp;
652 caddr_t namelenp;
653 int *retsize;
654 {
655 struct file *fp;
656 struct uio auio;
657 register struct iovec *iov;
658 register int i;
659 int len, error;
660 struct mbuf *m, *from = 0, *control = 0;
661 caddr_t ctlbuf;
662 #ifdef KTRACE
663 struct iovec *ktriov = NULL;
664 #endif
665
666 error = getsock(p->p_fd, s, &fp);
667 if (error)
668 return (error);
669 auio.uio_iov = mp->msg_iov;
670 auio.uio_iovcnt = mp->msg_iovlen;
671 auio.uio_segflg = UIO_USERSPACE;
672 auio.uio_rw = UIO_READ;
673 auio.uio_procp = p;
674 auio.uio_offset = 0; /* XXX */
675 auio.uio_resid = 0;
676 iov = mp->msg_iov;
677 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
678 if ((auio.uio_resid += iov->iov_len) < 0)
679 return (EINVAL);
680 }
681 #ifdef KTRACE
682 if (KTRPOINT(p, KTR_GENIO)) {
683 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
684
685 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
686 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
687 }
688 #endif
689 len = auio.uio_resid;
690 error = soreceive((struct socket *)fp->f_data, &from, &auio,
691 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
692 &mp->msg_flags);
693 if (error) {
694 if (auio.uio_resid != len && (error == ERESTART ||
695 error == EINTR || error == EWOULDBLOCK))
696 error = 0;
697 }
698 #ifdef KTRACE
699 if (ktriov != NULL) {
700 if (error == 0)
701 ktrgenio(p->p_tracep, s, UIO_READ,
702 ktriov, len - auio.uio_resid, error);
703 FREE(ktriov, M_TEMP);
704 }
705 #endif
706 if (error)
707 goto out;
708 *retsize = len - auio.uio_resid;
709 if (mp->msg_name) {
710 len = mp->msg_namelen;
711 if (len <= 0 || from == 0)
712 len = 0;
713 else {
714 /* save sa_len before it is destroyed by MSG_COMPAT */
715 if (len > from->m_len)
716 len = from->m_len;
717 /* else if len < from->m_len ??? */
718 #ifdef COMPAT_OLDSOCK
719 if (mp->msg_flags & MSG_COMPAT)
720 mtod(from, struct osockaddr *)->sa_family =
721 mtod(from, struct sockaddr *)->sa_family;
722 #endif
723 error = copyout(mtod(from, caddr_t),
724 (caddr_t)mp->msg_name, (unsigned)len);
725 if (error)
726 goto out;
727 }
728 mp->msg_namelen = len;
729 if (namelenp &&
730 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
731 #ifdef COMPAT_OLDSOCK
732 if (mp->msg_flags & MSG_COMPAT)
733 error = 0; /* old recvfrom didn't check */
734 else
735 #endif
736 goto out;
737 }
738 }
739 if (mp->msg_control) {
740 #ifdef COMPAT_OLDSOCK
741 /*
742 * We assume that old recvmsg calls won't receive access
743 * rights and other control info, esp. as control info
744 * is always optional and those options didn't exist in 4.3.
745 * If we receive rights, trim the cmsghdr; anything else
746 * is tossed.
747 */
748 if (control && mp->msg_flags & MSG_COMPAT) {
749 if (mtod(control, struct cmsghdr *)->cmsg_level !=
750 SOL_SOCKET ||
751 mtod(control, struct cmsghdr *)->cmsg_type !=
752 SCM_RIGHTS) {
753 mp->msg_controllen = 0;
754 goto out;
755 }
756 control->m_len -= sizeof (struct cmsghdr);
757 control->m_data += sizeof (struct cmsghdr);
758 }
759 #endif
760 len = mp->msg_controllen;
761 m = control;
762 mp->msg_controllen = 0;
763 ctlbuf = (caddr_t) mp->msg_control;
764
765 while (m && len > 0) {
766 unsigned int tocopy;
767
768 if (len >= m->m_len)
769 tocopy = m->m_len;
770 else {
771 mp->msg_flags |= MSG_CTRUNC;
772 tocopy = len;
773 }
774
775 if (error = copyout((caddr_t)mtod(m, caddr_t),
776 ctlbuf, tocopy))
777 goto out;
778
779 ctlbuf += tocopy;
780 len -= tocopy;
781 m = m->m_next;
782 }
783 mp->msg_controllen = ctlbuf - mp->msg_control;
784 }
785 out:
786 if (from)
787 m_freem(from);
788 if (control)
789 m_freem(control);
790 return (error);
791 }
792
793 int
794 recvfrom(p, uap, retval)
795 struct proc *p;
796 register struct recvfrom_args /* {
797 int s;
798 caddr_t buf;
799 size_t len;
800 int flags;
801 caddr_t from;
802 int *fromlenaddr;
803 } */ *uap;
804 int *retval;
805 {
806 struct msghdr msg;
807 struct iovec aiov;
808 int error;
809
810 if (uap->fromlenaddr) {
811 error = copyin((caddr_t)uap->fromlenaddr,
812 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen));
813 if (error)
814 return (error);
815 } else
816 msg.msg_namelen = 0;
817 msg.msg_name = uap->from;
818 msg.msg_iov = &aiov;
819 msg.msg_iovlen = 1;
820 aiov.iov_base = uap->buf;
821 aiov.iov_len = uap->len;
822 msg.msg_control = 0;
823 msg.msg_flags = uap->flags;
824 return (recvit(p, uap->s, &msg, (caddr_t)uap->fromlenaddr, retval));
825 }
826
827 #ifdef COMPAT_OLDSOCK
828 int
829 orecvfrom(p, uap, retval)
830 struct proc *p;
831 struct recvfrom_args *uap;
832 int *retval;
833 {
834
835 uap->flags |= MSG_COMPAT;
836 return (recvfrom(p, uap, retval));
837 }
838 #endif
839
840
841 #ifdef COMPAT_OLDSOCK
842 int
843 orecv(p, uap, retval)
844 struct proc *p;
845 register struct orecv_args /* {
846 int s;
847 caddr_t buf;
848 int len;
849 int flags;
850 } */ *uap;
851 int *retval;
852 {
853 struct msghdr msg;
854 struct iovec aiov;
855
856 msg.msg_name = 0;
857 msg.msg_namelen = 0;
858 msg.msg_iov = &aiov;
859 msg.msg_iovlen = 1;
860 aiov.iov_base = uap->buf;
861 aiov.iov_len = uap->len;
862 msg.msg_control = 0;
863 msg.msg_flags = uap->flags;
864 return (recvit(p, uap->s, &msg, (caddr_t)0, retval));
865 }
866
867 /*
868 * Old recvmsg. This code takes advantage of the fact that the old msghdr
869 * overlays the new one, missing only the flags, and with the (old) access
870 * rights where the control fields are now.
871 */
872 int
873 orecvmsg(p, uap, retval)
874 struct proc *p;
875 register struct orecvmsg_args /* {
876 int s;
877 struct omsghdr *msg;
878 int flags;
879 } */ *uap;
880 int *retval;
881 {
882 struct msghdr msg;
883 struct iovec aiov[UIO_SMALLIOV], *iov;
884 int error;
885
886 error = copyin((caddr_t)uap->msg, (caddr_t)&msg,
887 sizeof (struct omsghdr));
888 if (error)
889 return (error);
890 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
891 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
892 return (EMSGSIZE);
893 MALLOC(iov, struct iovec *,
894 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
895 M_WAITOK);
896 } else
897 iov = aiov;
898 msg.msg_flags = uap->flags | MSG_COMPAT;
899 error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
900 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
901 if (error)
902 goto done;
903 msg.msg_iov = iov;
904 error = recvit(p, uap->s, &msg, (caddr_t)&uap->msg->msg_namelen, retval);
905
906 if (msg.msg_controllen && error == 0)
907 error = copyout((caddr_t)&msg.msg_controllen,
908 (caddr_t)&uap->msg->msg_accrightslen, sizeof (int));
909 done:
910 if (iov != aiov)
911 FREE(iov, M_IOV);
912 return (error);
913 }
914 #endif
915
916 int
917 recvmsg(p, uap, retval)
918 struct proc *p;
919 register struct recvmsg_args /* {
920 int s;
921 struct msghdr *msg;
922 int flags;
923 } */ *uap;
924 int *retval;
925 {
926 struct msghdr msg;
927 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
928 register int error;
929
930 error = copyin((caddr_t)uap->msg, (caddr_t)&msg, sizeof (msg));
931 if (error)
932 return (error);
933 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
934 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
935 return (EMSGSIZE);
936 MALLOC(iov, struct iovec *,
937 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
938 M_WAITOK);
939 } else
940 iov = aiov;
941 #ifdef COMPAT_OLDSOCK
942 msg.msg_flags = uap->flags &~ MSG_COMPAT;
943 #else
944 msg.msg_flags = uap->flags;
945 #endif
946 uiov = msg.msg_iov;
947 msg.msg_iov = iov;
948 error = copyin((caddr_t)uiov, (caddr_t)iov,
949 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)));
950 if (error)
951 goto done;
952 error = recvit(p, uap->s, &msg, (caddr_t)0, retval);
953 if (!error) {
954 msg.msg_iov = uiov;
955 error = copyout((caddr_t)&msg, (caddr_t)uap->msg, sizeof(msg));
956 }
957 done:
958 if (iov != aiov)
959 FREE(iov, M_IOV);
960 return (error);
961 }
962
963 /* ARGSUSED */
964 int
965 shutdown(p, uap, retval)
966 struct proc *p;
967 register struct shutdown_args /* {
968 int s;
969 int how;
970 } */ *uap;
971 int *retval;
972 {
973 struct file *fp;
974 int error;
975
976 error = getsock(p->p_fd, uap->s, &fp);
977 if (error)
978 return (error);
979 return (soshutdown((struct socket *)fp->f_data, uap->how));
980 }
981
982 /* ARGSUSED */
983 int
984 setsockopt(p, uap, retval)
985 struct proc *p;
986 register struct setsockopt_args /* {
987 int s;
988 int level;
989 int name;
990 caddr_t val;
991 int valsize;
992 } */ *uap;
993 int *retval;
994 {
995 struct file *fp;
996 struct mbuf *m = NULL;
997 int error;
998
999 error = getsock(p->p_fd, uap->s, &fp);
1000 if (error)
1001 return (error);
1002 if (uap->valsize > MLEN)
1003 return (EINVAL);
1004 if (uap->val) {
1005 m = m_get(M_WAIT, MT_SOOPTS);
1006 if (m == NULL)
1007 return (ENOBUFS);
1008 error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
1009 if (error) {
1010 (void) m_free(m);
1011 return (error);
1012 }
1013 m->m_len = uap->valsize;
1014 }
1015 return (sosetopt((struct socket *)fp->f_data, uap->level,
1016 uap->name, m));
1017 }
1018
1019 /* ARGSUSED */
1020 int
1021 getsockopt(p, uap, retval)
1022 struct proc *p;
1023 register struct getsockopt_args /* {
1024 int s;
1025 int level;
1026 int name;
1027 caddr_t val;
1028 int *avalsize;
1029 } */ *uap;
1030 int *retval;
1031 {
1032 struct file *fp;
1033 struct mbuf *m = NULL, *m0;
1034 int op, i, valsize, error;
1035
1036 error = getsock(p->p_fd, uap->s, &fp);
1037 if (error)
1038 return (error);
1039 if (uap->val) {
1040 error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
1041 sizeof (valsize));
1042 if (error)
1043 return (error);
1044 } else
1045 valsize = 0;
1046 if ((error = sogetopt((struct socket *)fp->f_data, uap->level,
1047 uap->name, &m)) == 0 && uap->val && valsize && m != NULL) {
1048 op = 0;
1049 while (m && !error && op < valsize) {
1050 i = min(m->m_len, (valsize - op));
1051 error = copyout(mtod(m, caddr_t), uap->val, (u_int)i);
1052 op += i;
1053 uap->val += i;
1054 m0 = m;
1055 MFREE(m0,m);
1056 }
1057 valsize = op;
1058 if (error == 0)
1059 error = copyout((caddr_t)&valsize,
1060 (caddr_t)uap->avalsize, sizeof (valsize));
1061 }
1062 if (m != NULL)
1063 (void) m_free(m);
1064 return (error);
1065 }
1066
1067 #ifdef OLD_PIPE
1068 /* ARGSUSED */
1069 int
1070 pipe(p, uap, retval)
1071 struct proc *p;
1072 struct pipe_args /* {
1073 int dummy;
1074 } */ *uap;
1075 int retval[];
1076 {
1077 register struct filedesc *fdp = p->p_fd;
1078 struct file *rf, *wf;
1079 struct socket *rso, *wso;
1080 int fd, error;
1081
1082 error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0, p);
1083 if (error)
1084 return (error);
1085 error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0, p);
1086 if (error)
1087 goto free1;
1088 error = falloc(p, &rf, &fd);
1089 if (error)
1090 goto free2;
1091 retval[0] = fd;
1092 rf->f_flag = FREAD | FWRITE;
1093 rf->f_type = DTYPE_SOCKET;
1094 rf->f_ops = &socketops;
1095 rf->f_data = (caddr_t)rso;
1096 error = falloc(p, &wf, &fd);
1097 if (error)
1098 goto free3;
1099 wf->f_flag = FREAD | FWRITE;
1100 wf->f_type = DTYPE_SOCKET;
1101 wf->f_ops = &socketops;
1102 wf->f_data = (caddr_t)wso;
1103 retval[1] = fd;
1104 error = unp_connect2(wso, rso);
1105 if (error)
1106 goto free4;
1107 return (0);
1108 free4:
1109 ffree(wf);
1110 fdp->fd_ofiles[retval[1]] = 0;
1111 free3:
1112 ffree(rf);
1113 fdp->fd_ofiles[retval[0]] = 0;
1114 free2:
1115 (void)soclose(wso);
1116 free1:
1117 (void)soclose(rso);
1118 return (error);
1119 }
1120 #endif
1121 /*
1122 * Get socket name.
1123 */
1124 /* ARGSUSED */
1125 static int
1126 getsockname1(p, uap, retval, compat)
1127 struct proc *p;
1128 register struct getsockname_args /* {
1129 int fdes;
1130 caddr_t asa;
1131 int *alen;
1132 } */ *uap;
1133 int *retval;
1134 int compat;
1135 {
1136 struct file *fp;
1137 register struct socket *so;
1138 struct mbuf *m;
1139 int len, error;
1140
1141 error = getsock(p->p_fd, uap->fdes, &fp);
1142 if (error)
1143 return (error);
1144 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1145 if (error)
1146 return (error);
1147 so = (struct socket *)fp->f_data;
1148 m = m_getclr(M_WAIT, MT_SONAME);
1149 if (m == NULL)
1150 return (ENOBUFS);
1151 error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, m);
1152 if (error)
1153 goto bad;
1154 if (len > m->m_len)
1155 len = m->m_len;
1156 #ifdef COMPAT_OLDSOCK
1157 if (compat)
1158 mtod(m, struct osockaddr *)->sa_family =
1159 mtod(m, struct sockaddr *)->sa_family;
1160 #endif
1161 error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1162 if (error == 0)
1163 error = copyout((caddr_t)&len, (caddr_t)uap->alen,
1164 sizeof (len));
1165 bad:
1166 m_freem(m);
1167 return (error);
1168 }
1169
1170 int
1171 getsockname(p, uap, retval)
1172 struct proc *p;
1173 struct getsockname_args *uap;
1174 int *retval;
1175 {
1176
1177 return (getsockname1(p, uap, retval, 0));
1178 }
1179
1180 #ifdef COMPAT_OLDSOCK
1181 int
1182 ogetsockname(p, uap, retval)
1183 struct proc *p;
1184 struct getsockname_args *uap;
1185 int *retval;
1186 {
1187
1188 return (getsockname1(p, uap, retval, 1));
1189 }
1190 #endif /* COMPAT_OLDSOCK */
1191
1192 /*
1193 * Get name of peer for connected socket.
1194 */
1195 /* ARGSUSED */
1196 static int
1197 getpeername1(p, uap, retval, compat)
1198 struct proc *p;
1199 register struct getpeername_args /* {
1200 int fdes;
1201 caddr_t asa;
1202 int *alen;
1203 } */ *uap;
1204 int *retval;
1205 int compat;
1206 {
1207 struct file *fp;
1208 register struct socket *so;
1209 struct mbuf *m;
1210 int len, error;
1211
1212 error = getsock(p->p_fd, uap->fdes, &fp);
1213 if (error)
1214 return (error);
1215 so = (struct socket *)fp->f_data;
1216 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
1217 return (ENOTCONN);
1218 error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
1219 if (error)
1220 return (error);
1221 m = m_getclr(M_WAIT, MT_SONAME);
1222 if (m == NULL)
1223 return (ENOBUFS);
1224 error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, m);
1225 if (error)
1226 goto bad;
1227 if (len > m->m_len)
1228 len = m->m_len;
1229 #ifdef COMPAT_OLDSOCK
1230 if (compat)
1231 mtod(m, struct osockaddr *)->sa_family =
1232 mtod(m, struct sockaddr *)->sa_family;
1233 #endif
1234 error = copyout(mtod(m, caddr_t), (caddr_t)uap->asa, (u_int)len);
1235 if (error)
1236 goto bad;
1237 error = copyout((caddr_t)&len, (caddr_t)uap->alen, sizeof (len));
1238 bad:
1239 m_freem(m);
1240 return (error);
1241 }
1242
1243 int
1244 getpeername(p, uap, retval)
1245 struct proc *p;
1246 struct getpeername_args *uap;
1247 int *retval;
1248 {
1249
1250 return (getpeername1(p, uap, retval, 0));
1251 }
1252
1253 #ifdef COMPAT_OLDSOCK
1254 int
1255 ogetpeername(p, uap, retval)
1256 struct proc *p;
1257 struct ogetpeername_args *uap;
1258 int *retval;
1259 {
1260
1261 /* XXX uap should have type `getpeername_args *' to begin with. */
1262 return (getpeername1(p, (struct getpeername_args *)uap, retval, 1));
1263 }
1264 #endif /* COMPAT_OLDSOCK */
1265
1266 int
1267 sockargs(mp, buf, buflen, type)
1268 struct mbuf **mp;
1269 caddr_t buf;
1270 int buflen, type;
1271 {
1272 register struct sockaddr *sa;
1273 register struct mbuf *m;
1274 int error;
1275
1276 if ((u_int)buflen > MLEN) {
1277 #ifdef COMPAT_OLDSOCK
1278 if (type == MT_SONAME && (u_int)buflen <= 112)
1279 buflen = MLEN; /* unix domain compat. hack */
1280 else
1281 #endif
1282 return (EINVAL);
1283 }
1284 m = m_get(M_WAIT, type);
1285 if (m == NULL)
1286 return (ENOBUFS);
1287 m->m_len = buflen;
1288 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
1289 if (error)
1290 (void) m_free(m);
1291 else {
1292 *mp = m;
1293 if (type == MT_SONAME) {
1294 sa = mtod(m, struct sockaddr *);
1295
1296 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
1297 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
1298 sa->sa_family = sa->sa_len;
1299 #endif
1300 sa->sa_len = buflen;
1301 }
1302 }
1303 return (error);
1304 }
1305
1306 int
1307 getsock(fdp, fdes, fpp)
1308 struct filedesc *fdp;
1309 int fdes;
1310 struct file **fpp;
1311 {
1312 register struct file *fp;
1313
1314 if ((unsigned)fdes >= fdp->fd_nfiles ||
1315 (fp = fdp->fd_ofiles[fdes]) == NULL)
1316 return (EBADF);
1317 if (fp->f_type != DTYPE_SOCKET)
1318 return (ENOTSOCK);
1319 *fpp = fp;
1320 return (0);
1321 }
Cache object: 9b5465ea0afae2f08629e1742aab5895
|