uipc_syscalls.c revision 1.13 1 /* $NetBSD: uipc_syscalls.c,v 1.13 1995/06/24 20:34:27 christos Exp $ */
2
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 * @(#)uipc_syscalls.c 8.4 (Berkeley) 2/21/94
36 */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/filedesc.h>
41 #include <sys/proc.h>
42 #include <sys/file.h>
43 #include <sys/buf.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #ifdef KTRACE
50 #include <sys/ktrace.h>
51 #endif
52
53 #include <sys/mount.h>
54 #include <sys/syscallargs.h>
55
56 /*
57 * System call interface to the socket abstraction.
58 */
59 #if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_LINUX) || \
60 defined(COMPAT_HPUX)
61 #define COMPAT_OLDSOCK
62 #define MSG_COMPAT 0x8000
63 #endif
64
65 extern struct fileops socketops;
66
67 int
68 socket(p, uap, retval)
69 struct proc *p;
70 register struct socket_args /* {
71 syscallarg(int) domain;
72 syscallarg(int) type;
73 syscallarg(int) protocol;
74 } */ *uap;
75 register_t *retval;
76 {
77 struct filedesc *fdp = p->p_fd;
78 struct socket *so;
79 struct file *fp;
80 int fd, error;
81
82 if (error = falloc(p, &fp, &fd))
83 return (error);
84 fp->f_flag = FREAD|FWRITE;
85 fp->f_type = DTYPE_SOCKET;
86 fp->f_ops = &socketops;
87 if (error = socreate(SCARG(uap, domain), &so, SCARG(uap, type),
88 SCARG(uap, protocol))) {
89 fdp->fd_ofiles[fd] = 0;
90 ffree(fp);
91 } else {
92 fp->f_data = (caddr_t)so;
93 *retval = fd;
94 }
95 return (error);
96 }
97
98 /* ARGSUSED */
99 int
100 bind(p, uap, retval)
101 struct proc *p;
102 register struct bind_args /* {
103 syscallarg(int) s;
104 syscallarg(caddr_t) name;
105 syscallarg(int) namelen;
106 } */ *uap;
107 register_t *retval;
108 {
109 struct file *fp;
110 struct mbuf *nam;
111 int error;
112
113 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
114 return (error);
115 if (error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
116 MT_SONAME))
117 return (error);
118 error = sobind((struct socket *)fp->f_data, nam);
119 m_freem(nam);
120 return (error);
121 }
122
123 /* ARGSUSED */
124 int
125 listen(p, uap, retval)
126 struct proc *p;
127 register struct listen_args /* {
128 syscallarg(int) s;
129 syscallarg(int) backlog;
130 } */ *uap;
131 register_t *retval;
132 {
133 struct file *fp;
134 int error;
135
136 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
137 return (error);
138 return (solisten((struct socket *)fp->f_data, SCARG(uap, backlog)));
139 }
140
141 int
142 accept(p, uap, retval)
143 struct proc *p;
144 register struct accept_args /* {
145 syscallarg(int) s;
146 syscallarg(caddr_t) name;
147 syscallarg(int *) anamelen;
148 } */ *uap;
149 register_t *retval;
150 {
151 struct file *fp;
152 struct mbuf *nam;
153 int namelen, error, s, tmpfd;
154 register struct socket *so;
155
156 if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, anamelen),
157 (caddr_t)&namelen, sizeof (namelen))))
158 return (error);
159 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
160 return (error);
161 s = splnet();
162 so = (struct socket *)fp->f_data;
163 if ((so->so_options & SO_ACCEPTCONN) == 0) {
164 splx(s);
165 return (EINVAL);
166 }
167 if ((so->so_state & SS_NBIO) && so->so_qlen == 0) {
168 splx(s);
169 return (EWOULDBLOCK);
170 }
171 while (so->so_qlen == 0 && so->so_error == 0) {
172 if (so->so_state & SS_CANTRCVMORE) {
173 so->so_error = ECONNABORTED;
174 break;
175 }
176 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
177 netcon, 0)) {
178 splx(s);
179 return (error);
180 }
181 }
182 if (so->so_error) {
183 error = so->so_error;
184 so->so_error = 0;
185 splx(s);
186 return (error);
187 }
188 if (error = falloc(p, &fp, &tmpfd)) {
189 splx(s);
190 return (error);
191 }
192 *retval = tmpfd;
193 { struct socket *aso = so->so_q;
194 if (soqremque(aso, 1) == 0)
195 panic("accept");
196 so = aso;
197 }
198 fp->f_type = DTYPE_SOCKET;
199 fp->f_flag = FREAD|FWRITE;
200 fp->f_ops = &socketops;
201 fp->f_data = (caddr_t)so;
202 nam = m_get(M_WAIT, MT_SONAME);
203 (void) soaccept(so, nam);
204 if (SCARG(uap, name)) {
205 if (namelen > nam->m_len)
206 namelen = nam->m_len;
207 /* SHOULD COPY OUT A CHAIN HERE */
208 if ((error = copyout(mtod(nam, caddr_t),
209 (caddr_t)SCARG(uap, name), (u_int)namelen)) == 0)
210 error = copyout((caddr_t)&namelen,
211 (caddr_t)SCARG(uap, anamelen),
212 sizeof (*SCARG(uap, anamelen)));
213 }
214 m_freem(nam);
215 splx(s);
216 return (error);
217 }
218
219 /* ARGSUSED */
220 int
221 connect(p, uap, retval)
222 struct proc *p;
223 register struct connect_args /* {
224 syscallarg(int) s;
225 syscallarg(caddr_t) name;
226 syscallarg(int) namelen;
227 } */ *uap;
228 register_t *retval;
229 {
230 struct file *fp;
231 register struct socket *so;
232 struct mbuf *nam;
233 int error, s;
234
235 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
236 return (error);
237 so = (struct socket *)fp->f_data;
238 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
239 return (EALREADY);
240 if (error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
241 MT_SONAME))
242 return (error);
243 error = soconnect(so, nam);
244 if (error)
245 goto bad;
246 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
247 m_freem(nam);
248 return (EINPROGRESS);
249 }
250 s = splnet();
251 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0)
252 if (error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
253 netcon, 0))
254 break;
255 if (error == 0) {
256 error = so->so_error;
257 so->so_error = 0;
258 }
259 splx(s);
260 bad:
261 so->so_state &= ~SS_ISCONNECTING;
262 m_freem(nam);
263 if (error == ERESTART)
264 error = EINTR;
265 return (error);
266 }
267
268 int
269 socketpair(p, uap, retval)
270 struct proc *p;
271 register struct socketpair_args /* {
272 syscallarg(int) domain;
273 syscallarg(int) type;
274 syscallarg(int) protocol;
275 syscallarg(int *) rsv;
276 } */ *uap;
277 register_t *retval;
278 {
279 register struct filedesc *fdp = p->p_fd;
280 struct file *fp1, *fp2;
281 struct socket *so1, *so2;
282 int fd, error, sv[2];
283
284 if (error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type),
285 SCARG(uap, protocol)))
286 return (error);
287 if (error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type),
288 SCARG(uap, protocol)))
289 goto free1;
290 if (error = falloc(p, &fp1, &fd))
291 goto free2;
292 sv[0] = fd;
293 fp1->f_flag = FREAD|FWRITE;
294 fp1->f_type = DTYPE_SOCKET;
295 fp1->f_ops = &socketops;
296 fp1->f_data = (caddr_t)so1;
297 if (error = falloc(p, &fp2, &fd))
298 goto free3;
299 fp2->f_flag = FREAD|FWRITE;
300 fp2->f_type = DTYPE_SOCKET;
301 fp2->f_ops = &socketops;
302 fp2->f_data = (caddr_t)so2;
303 sv[1] = fd;
304 if (error = soconnect2(so1, so2))
305 goto free4;
306 if (SCARG(uap, type) == SOCK_DGRAM) {
307 /*
308 * Datagram socket connection is asymmetric.
309 */
310 if (error = soconnect2(so2, so1))
311 goto free4;
312 }
313 error = copyout((caddr_t)sv, (caddr_t)SCARG(uap, rsv),
314 2 * sizeof (int));
315 retval[0] = sv[0]; /* XXX ??? */
316 retval[1] = sv[1]; /* XXX ??? */
317 return (error);
318 free4:
319 ffree(fp2);
320 fdp->fd_ofiles[sv[1]] = 0;
321 free3:
322 ffree(fp1);
323 fdp->fd_ofiles[sv[0]] = 0;
324 free2:
325 (void)soclose(so2);
326 free1:
327 (void)soclose(so1);
328 return (error);
329 }
330
331 int
332 sendto(p, uap, retval)
333 struct proc *p;
334 register struct sendto_args /* {
335 syscallarg(int) s;
336 syscallarg(caddr_t) buf;
337 syscallarg(size_t) len;
338 syscallarg(int) flags;
339 syscallarg(caddr_t) to;
340 syscallarg(int) tolen;
341 } */ *uap;
342 register_t *retval;
343 {
344 struct msghdr msg;
345 struct iovec aiov;
346
347 msg.msg_name = SCARG(uap, to);
348 msg.msg_namelen = SCARG(uap, tolen);
349 msg.msg_iov = &aiov;
350 msg.msg_iovlen = 1;
351 msg.msg_control = 0;
352 #ifdef COMPAT_OLDSOCK
353 msg.msg_flags = 0;
354 #endif
355 aiov.iov_base = SCARG(uap, buf);
356 aiov.iov_len = SCARG(uap, len);
357 return (sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval));
358 }
359
360 int
361 sendmsg(p, uap, retval)
362 struct proc *p;
363 register struct sendmsg_args /* {
364 syscallarg(int) s;
365 syscallarg(caddr_t) msg;
366 syscallarg(int) flags;
367 } */ *uap;
368 register_t *retval;
369 {
370 struct msghdr msg;
371 struct iovec aiov[UIO_SMALLIOV], *iov;
372 int error;
373
374 if (error = copyin(SCARG(uap, msg), (caddr_t)&msg, sizeof (msg)))
375 return (error);
376 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
377 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
378 return (EMSGSIZE);
379 MALLOC(iov, struct iovec *,
380 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
381 M_WAITOK);
382 } else
383 iov = aiov;
384 if (msg.msg_iovlen &&
385 (error = copyin((caddr_t)msg.msg_iov, (caddr_t)iov,
386 (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
387 goto done;
388 msg.msg_iov = iov;
389 #ifdef COMPAT_OLDSOCK
390 msg.msg_flags = 0;
391 #endif
392 error = sendit(p, SCARG(uap, s), &msg, SCARG(uap, flags), retval);
393 done:
394 if (iov != aiov)
395 FREE(iov, M_IOV);
396 return (error);
397 }
398
399 int
400 sendit(p, s, mp, flags, retsize)
401 register struct proc *p;
402 int s;
403 register struct msghdr *mp;
404 int flags;
405 register_t *retsize;
406 {
407 struct file *fp;
408 struct uio auio;
409 register struct iovec *iov;
410 register int i;
411 struct mbuf *to, *control;
412 int len, error;
413 #ifdef KTRACE
414 struct iovec *ktriov = NULL;
415 #endif
416
417 if (error = getsock(p->p_fd, s, &fp))
418 return (error);
419 auio.uio_iov = mp->msg_iov;
420 auio.uio_iovcnt = mp->msg_iovlen;
421 auio.uio_segflg = UIO_USERSPACE;
422 auio.uio_rw = UIO_WRITE;
423 auio.uio_procp = p;
424 auio.uio_offset = 0; /* XXX */
425 auio.uio_resid = 0;
426 iov = mp->msg_iov;
427 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
428 if (iov->iov_len < 0)
429 return (EINVAL);
430 if ((auio.uio_resid += iov->iov_len) < 0)
431 return (EINVAL);
432 }
433 if (mp->msg_name) {
434 if (error = sockargs(&to, mp->msg_name, mp->msg_namelen,
435 MT_SONAME))
436 return (error);
437 } else
438 to = 0;
439 if (mp->msg_control) {
440 if (mp->msg_controllen < sizeof(struct cmsghdr)
441 #ifdef COMPAT_OLDSOCK
442 && mp->msg_flags != MSG_COMPAT
443 #endif
444 ) {
445 error = EINVAL;
446 goto bad;
447 }
448 if (error = sockargs(&control, mp->msg_control,
449 mp->msg_controllen, MT_CONTROL))
450 goto bad;
451 #ifdef COMPAT_OLDSOCK
452 if (mp->msg_flags == MSG_COMPAT) {
453 register struct cmsghdr *cm;
454
455 M_PREPEND(control, sizeof(*cm), M_WAIT);
456 if (control == 0) {
457 error = ENOBUFS;
458 goto bad;
459 } else {
460 cm = mtod(control, struct cmsghdr *);
461 cm->cmsg_len = control->m_len;
462 cm->cmsg_level = SOL_SOCKET;
463 cm->cmsg_type = SCM_RIGHTS;
464 }
465 }
466 #endif
467 } else
468 control = 0;
469 #ifdef KTRACE
470 if (KTRPOINT(p, KTR_GENIO)) {
471 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
472
473 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
474 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
475 }
476 #endif
477 len = auio.uio_resid;
478 if (error = sosend((struct socket *)fp->f_data, to, &auio,
479 (struct mbuf *)0, control, flags)) {
480 if (auio.uio_resid != len && (error == ERESTART ||
481 error == EINTR || error == EWOULDBLOCK))
482 error = 0;
483 if (error == EPIPE)
484 psignal(p, SIGPIPE);
485 }
486 if (error == 0)
487 *retsize = len - auio.uio_resid;
488 #ifdef KTRACE
489 if (ktriov != NULL) {
490 if (error == 0)
491 ktrgenio(p->p_tracep, s, UIO_WRITE,
492 ktriov, *retsize, error);
493 FREE(ktriov, M_TEMP);
494 }
495 #endif
496 bad:
497 if (to)
498 m_freem(to);
499 return (error);
500 }
501
502 int
503 recvfrom(p, uap, retval)
504 struct proc *p;
505 register struct recvfrom_args /* {
506 syscallarg(int) s;
507 syscallarg(caddr_t) buf;
508 syscallarg(size_t) len;
509 syscallarg(int) flags;
510 syscallarg(caddr_t) from;
511 syscallarg(int *) fromlenaddr;
512 } */ *uap;
513 register_t *retval;
514 {
515 struct msghdr msg;
516 struct iovec aiov;
517 int error;
518
519 if (SCARG(uap, fromlenaddr)) {
520 if (error = copyin((caddr_t)SCARG(uap, fromlenaddr),
521 (caddr_t)&msg.msg_namelen, sizeof (msg.msg_namelen)))
522 return (error);
523 } else
524 msg.msg_namelen = 0;
525 msg.msg_name = SCARG(uap, from);
526 msg.msg_iov = &aiov;
527 msg.msg_iovlen = 1;
528 aiov.iov_base = SCARG(uap, buf);
529 aiov.iov_len = SCARG(uap, len);
530 msg.msg_control = 0;
531 msg.msg_flags = SCARG(uap, flags);
532 return (recvit(p, SCARG(uap, s), &msg,
533 (caddr_t)SCARG(uap, fromlenaddr), retval));
534 }
535
536 int
537 recvmsg(p, uap, retval)
538 struct proc *p;
539 register struct recvmsg_args /* {
540 syscallarg(int) s;
541 syscallarg(struct msghdr *) msg;
542 syscallarg(int) flags;
543 } */ *uap;
544 register_t *retval;
545 {
546 struct msghdr msg;
547 struct iovec aiov[UIO_SMALLIOV], *uiov, *iov;
548 register int error;
549
550 if (error = copyin((caddr_t)SCARG(uap, msg), (caddr_t)&msg,
551 sizeof (msg)))
552 return (error);
553 if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
554 if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
555 return (EMSGSIZE);
556 MALLOC(iov, struct iovec *,
557 sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
558 M_WAITOK);
559 } else
560 iov = aiov;
561 #ifdef COMPAT_OLDSOCK
562 msg.msg_flags = SCARG(uap, flags) &~ MSG_COMPAT;
563 #else
564 msg.msg_flags = SCARG(uap, flags);
565 #endif
566 uiov = msg.msg_iov;
567 msg.msg_iov = iov;
568 if (error = copyin((caddr_t)uiov, (caddr_t)iov,
569 (unsigned)(msg.msg_iovlen * sizeof (struct iovec))))
570 goto done;
571 if ((error = recvit(p, SCARG(uap, s), &msg, (caddr_t)0, retval)) == 0) {
572 msg.msg_iov = uiov;
573 error = copyout((caddr_t)&msg, (caddr_t)SCARG(uap, msg),
574 sizeof(msg));
575 }
576 done:
577 if (iov != aiov)
578 FREE(iov, M_IOV);
579 return (error);
580 }
581
582 int
583 recvit(p, s, mp, namelenp, retsize)
584 register struct proc *p;
585 int s;
586 register struct msghdr *mp;
587 caddr_t namelenp;
588 register_t *retsize;
589 {
590 struct file *fp;
591 struct uio auio;
592 register struct iovec *iov;
593 register int i;
594 int len, error;
595 struct mbuf *from = 0, *control = 0;
596 #ifdef KTRACE
597 struct iovec *ktriov = NULL;
598 #endif
599
600 if (error = getsock(p->p_fd, s, &fp))
601 return (error);
602 auio.uio_iov = mp->msg_iov;
603 auio.uio_iovcnt = mp->msg_iovlen;
604 auio.uio_segflg = UIO_USERSPACE;
605 auio.uio_rw = UIO_READ;
606 auio.uio_procp = p;
607 auio.uio_offset = 0; /* XXX */
608 auio.uio_resid = 0;
609 iov = mp->msg_iov;
610 for (i = 0; i < mp->msg_iovlen; i++, iov++) {
611 if (iov->iov_len < 0)
612 return (EINVAL);
613 if ((auio.uio_resid += iov->iov_len) < 0)
614 return (EINVAL);
615 }
616 #ifdef KTRACE
617 if (KTRPOINT(p, KTR_GENIO)) {
618 int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
619
620 MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
621 bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
622 }
623 #endif
624 len = auio.uio_resid;
625 if (error = soreceive((struct socket *)fp->f_data, &from, &auio,
626 (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
627 &mp->msg_flags)) {
628 if (auio.uio_resid != len && (error == ERESTART ||
629 error == EINTR || error == EWOULDBLOCK))
630 error = 0;
631 }
632 #ifdef KTRACE
633 if (ktriov != NULL) {
634 if (error == 0)
635 ktrgenio(p->p_tracep, s, UIO_READ,
636 ktriov, len - auio.uio_resid, error);
637 FREE(ktriov, M_TEMP);
638 }
639 #endif
640 if (error)
641 goto out;
642 *retsize = len - auio.uio_resid;
643 if (mp->msg_name) {
644 len = mp->msg_namelen;
645 if (len <= 0 || from == 0)
646 len = 0;
647 else {
648 #ifdef COMPAT_OLDSOCK
649 if (mp->msg_flags & MSG_COMPAT)
650 mtod(from, struct osockaddr *)->sa_family =
651 mtod(from, struct sockaddr *)->sa_family;
652 #endif
653 if (len > from->m_len)
654 len = from->m_len;
655 /* else if len < from->m_len ??? */
656 if (error = copyout(mtod(from, caddr_t),
657 (caddr_t)mp->msg_name, (unsigned)len))
658 goto out;
659 }
660 mp->msg_namelen = len;
661 if (namelenp &&
662 (error = copyout((caddr_t)&len, namelenp, sizeof (int)))) {
663 #ifdef COMPAT_OLDSOCK
664 if (mp->msg_flags & MSG_COMPAT)
665 error = 0; /* old recvfrom didn't check */
666 else
667 #endif
668 goto out;
669 }
670 }
671 if (mp->msg_control) {
672 #ifdef COMPAT_OLDSOCK
673 /*
674 * We assume that old recvmsg calls won't receive access
675 * rights and other control info, esp. as control info
676 * is always optional and those options didn't exist in 4.3.
677 * If we receive rights, trim the cmsghdr; anything else
678 * is tossed.
679 */
680 if (control && mp->msg_flags & MSG_COMPAT) {
681 if (mtod(control, struct cmsghdr *)->cmsg_level !=
682 SOL_SOCKET ||
683 mtod(control, struct cmsghdr *)->cmsg_type !=
684 SCM_RIGHTS) {
685 mp->msg_controllen = 0;
686 goto out;
687 }
688 control->m_len -= sizeof (struct cmsghdr);
689 control->m_data += sizeof (struct cmsghdr);
690 }
691 #endif
692 len = mp->msg_controllen;
693 if (len <= 0 || control == 0)
694 len = 0;
695 else {
696 if (len >= control->m_len)
697 len = control->m_len;
698 else
699 mp->msg_flags |= MSG_CTRUNC;
700 error = copyout((caddr_t)mtod(control, caddr_t),
701 (caddr_t)mp->msg_control, (unsigned)len);
702 }
703 mp->msg_controllen = len;
704 }
705 out:
706 if (from)
707 m_freem(from);
708 if (control)
709 m_freem(control);
710 return (error);
711 }
712
713 /* ARGSUSED */
714 int
715 shutdown(p, uap, retval)
716 struct proc *p;
717 register struct shutdown_args /* {
718 syscallarg(int) s;
719 syscallarg(int) how;
720 } */ *uap;
721 register_t *retval;
722 {
723 struct file *fp;
724 int error;
725
726 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
727 return (error);
728 return (soshutdown((struct socket *)fp->f_data, SCARG(uap, how)));
729 }
730
731 /* ARGSUSED */
732 int
733 setsockopt(p, uap, retval)
734 struct proc *p;
735 register struct setsockopt_args /* {
736 syscallarg(int) s;
737 syscallarg(int) level;
738 syscallarg(int) name;
739 syscallarg(caddr_t) val;
740 syscallarg(int) valsize;
741 } */ *uap;
742 register_t *retval;
743 {
744 struct file *fp;
745 struct mbuf *m = NULL;
746 int error;
747
748 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
749 return (error);
750 if (SCARG(uap, valsize) > MLEN)
751 return (EINVAL);
752 if (SCARG(uap, val)) {
753 m = m_get(M_WAIT, MT_SOOPTS);
754 if (m == NULL)
755 return (ENOBUFS);
756 if (error = copyin(SCARG(uap, val), mtod(m, caddr_t),
757 (u_int)SCARG(uap, valsize))) {
758 (void) m_free(m);
759 return (error);
760 }
761 m->m_len = SCARG(uap, valsize);
762 }
763 return (sosetopt((struct socket *)fp->f_data, SCARG(uap, level),
764 SCARG(uap, name), m));
765 }
766
767 /* ARGSUSED */
768 int
769 getsockopt(p, uap, retval)
770 struct proc *p;
771 register struct getsockopt_args /* {
772 syscallarg(int) s;
773 syscallarg(int) level;
774 syscallarg(int) name;
775 syscallarg(caddr_t) val;
776 syscallarg(int *) avalsize;
777 } */ *uap;
778 register_t *retval;
779 {
780 struct file *fp;
781 struct mbuf *m = NULL;
782 int valsize, error;
783
784 if (error = getsock(p->p_fd, SCARG(uap, s), &fp))
785 return (error);
786 if (SCARG(uap, val)) {
787 if (error = copyin((caddr_t)SCARG(uap, avalsize),
788 (caddr_t)&valsize, sizeof (valsize)))
789 return (error);
790 } else
791 valsize = 0;
792 if ((error = sogetopt((struct socket *)fp->f_data, SCARG(uap, level),
793 SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
794 m != NULL) {
795 if (valsize > m->m_len)
796 valsize = m->m_len;
797 error = copyout(mtod(m, caddr_t), SCARG(uap, val),
798 (u_int)valsize);
799 if (error == 0)
800 error = copyout((caddr_t)&valsize,
801 (caddr_t)SCARG(uap, avalsize), sizeof (valsize));
802 }
803 if (m != NULL)
804 (void) m_free(m);
805 return (error);
806 }
807
808 /* ARGSUSED */
809 int
810 pipe(p, uap, retval)
811 struct proc *p;
812 void *uap;
813 register_t *retval;
814 {
815 register struct filedesc *fdp = p->p_fd;
816 struct file *rf, *wf;
817 struct socket *rso, *wso;
818 int fd, error;
819
820 if (error = socreate(AF_UNIX, &rso, SOCK_STREAM, 0))
821 return (error);
822 if (error = socreate(AF_UNIX, &wso, SOCK_STREAM, 0))
823 goto free1;
824 if (error = falloc(p, &rf, &fd))
825 goto free2;
826 retval[0] = fd;
827 rf->f_flag = FREAD;
828 rf->f_type = DTYPE_SOCKET;
829 rf->f_ops = &socketops;
830 rf->f_data = (caddr_t)rso;
831 if (error = falloc(p, &wf, &fd))
832 goto free3;
833 wf->f_flag = FWRITE;
834 wf->f_type = DTYPE_SOCKET;
835 wf->f_ops = &socketops;
836 wf->f_data = (caddr_t)wso;
837 retval[1] = fd;
838 if (error = unp_connect2(wso, rso))
839 goto free4;
840 return (0);
841 free4:
842 ffree(wf);
843 fdp->fd_ofiles[retval[1]] = 0;
844 free3:
845 ffree(rf);
846 fdp->fd_ofiles[retval[0]] = 0;
847 free2:
848 (void)soclose(wso);
849 free1:
850 (void)soclose(rso);
851 return (error);
852 }
853
854 /*
855 * Get socket name.
856 */
857 /* ARGSUSED */
858 int
859 getsockname(p, uap, retval)
860 struct proc *p;
861 register struct getsockname_args /* {
862 syscallarg(int) fdes;
863 syscallarg(caddr_t) asa;
864 syscallarg(int *) alen;
865 } */ *uap;
866 register_t *retval;
867 {
868 struct file *fp;
869 register struct socket *so;
870 struct mbuf *m;
871 int len, error;
872
873 if (error = getsock(p->p_fd, SCARG(uap, fdes), &fp))
874 return (error);
875 if (error = copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len,
876 sizeof (len)))
877 return (error);
878 so = (struct socket *)fp->f_data;
879 m = m_getclr(M_WAIT, MT_SONAME);
880 if (m == NULL)
881 return (ENOBUFS);
882 if (error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0))
883 goto bad;
884 if (len > m->m_len)
885 len = m->m_len;
886 error = copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), (u_int)len);
887 if (error == 0)
888 error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen),
889 sizeof (len));
890 bad:
891 m_freem(m);
892 return (error);
893 }
894
895 /*
896 * Get name of peer for connected socket.
897 */
898 /* ARGSUSED */
899 int
900 getpeername(p, uap, retval)
901 struct proc *p;
902 register struct getpeername_args /* {
903 syscallarg(int) fdes;
904 syscallarg(caddr_t) asa;
905 syscallarg(int *) alen;
906 } */ *uap;
907 register_t *retval;
908 {
909 struct file *fp;
910 register struct socket *so;
911 struct mbuf *m;
912 int len, error;
913
914 if (error = getsock(p->p_fd, SCARG(uap, fdes), &fp))
915 return (error);
916 so = (struct socket *)fp->f_data;
917 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
918 return (ENOTCONN);
919 if (error =
920 copyin((caddr_t)SCARG(uap, alen), (caddr_t)&len, sizeof (len)))
921 return (error);
922 m = m_getclr(M_WAIT, MT_SONAME);
923 if (m == NULL)
924 return (ENOBUFS);
925 if (error = (*so->so_proto->pr_usrreq)(so, PRU_PEERADDR, 0, m, 0))
926 goto bad;
927 if (len > m->m_len)
928 len = m->m_len;
929 if (error =
930 copyout(mtod(m, caddr_t), (caddr_t)SCARG(uap, asa), (u_int)len))
931 goto bad;
932 error = copyout((caddr_t)&len, (caddr_t)SCARG(uap, alen), sizeof (len));
933 bad:
934 m_freem(m);
935 return (error);
936 }
937
938 int
939 sockargs(mp, buf, buflen, type)
940 struct mbuf **mp;
941 caddr_t buf;
942 int buflen, type;
943 {
944 register struct sockaddr *sa;
945 register struct mbuf *m;
946 int error;
947
948 if ((u_int)buflen > MLEN) {
949 #ifdef COMPAT_OLDSOCK
950 if (type == MT_SONAME && (u_int)buflen <= 112)
951 buflen = MLEN; /* unix domain compat. hack */
952 else
953 #endif
954 return (EINVAL);
955 }
956 m = m_get(M_WAIT, type);
957 if (m == NULL)
958 return (ENOBUFS);
959 m->m_len = buflen;
960 error = copyin(buf, mtod(m, caddr_t), (u_int)buflen);
961 if (error) {
962 (void) m_free(m);
963 return (error);
964 }
965 *mp = m;
966 if (type == MT_SONAME) {
967 sa = mtod(m, struct sockaddr *);
968
969 #if defined(COMPAT_OLDSOCK) && BYTE_ORDER != BIG_ENDIAN
970 if (sa->sa_family == 0 && sa->sa_len < AF_MAX)
971 sa->sa_family = sa->sa_len;
972 #endif
973 sa->sa_len = buflen;
974 }
975 return (0);
976 }
977
978 int
979 getsock(fdp, fdes, fpp)
980 struct filedesc *fdp;
981 int fdes;
982 struct file **fpp;
983 {
984 register struct file *fp;
985
986 if ((unsigned)fdes >= fdp->fd_nfiles ||
987 (fp = fdp->fd_ofiles[fdes]) == NULL)
988 return (EBADF);
989 if (fp->f_type != DTYPE_SOCKET)
990 return (ENOTSOCK);
991 *fpp = fp;
992 return (0);
993 }
994