* %sccs.include.redist.c%
* @(#)uipc_syscalls.c 7.23 (Berkeley) %G%
* System call interface to the socket abstraction.
extern struct fileops socketops
;
struct filedesc
*fdp
= p
->p_fd
;
if (error
= falloc(p
, &fp
, &fd
))
fp
->f_flag
= FREAD
|FWRITE
;
fp
->f_type
= DTYPE_SOCKET
;
if (error
= socreate(uap
->domain
, &so
, uap
->type
, uap
->protocol
)) {
fp
->f_data
= (caddr_t
)so
;
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
if (error
= sockargs(&nam
, uap
->name
, uap
->namelen
, MT_SONAME
))
error
= sobind((struct socket
*)fp
->f_data
, nam
);
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
return (solisten((struct socket
*)fp
->f_data
, uap
->backlog
));
return (accept1(p
, uap
, retval
));
return (accept1(p
, uap
, retval
));
register struct socket
*so
;
if (uap
->name
&& (error
= copyin((caddr_t
)uap
->anamelen
,
(caddr_t
)&namelen
, sizeof (namelen
))))
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
so
= (struct socket
*)fp
->f_data
;
if ((so
->so_options
& SO_ACCEPTCONN
) == 0) {
if ((so
->so_state
& SS_NBIO
) && so
->so_qlen
== 0) {
while (so
->so_qlen
== 0 && so
->so_error
== 0) {
if (so
->so_state
& SS_CANTRCVMORE
) {
so
->so_error
= ECONNABORTED
;
if (error
= tsleep((caddr_t
)&so
->so_timeo
, PSOCK
| PCATCH
,
if (error
= falloc(p
, &fp
, retval
)) {
{ struct socket
*aso
= so
->so_q
;
if (soqremque(aso
, 1) == 0)
fp
->f_type
= DTYPE_SOCKET
;
fp
->f_flag
= FREAD
|FWRITE
;
fp
->f_data
= (caddr_t
)so
;
nam
= m_get(M_WAIT
, MT_SONAME
);
(void) soaccept(so
, nam
);
mtod(nam
, struct osockaddr
*)->sa_family
=
mtod(nam
, struct sockaddr
*)->sa_family
;
if (namelen
> nam
->m_len
)
/* SHOULD COPY OUT A CHAIN HERE */
if ((error
= copyout(mtod(nam
, caddr_t
), (caddr_t
)uap
->name
,
error
= copyout((caddr_t
)&namelen
,
(caddr_t
)uap
->anamelen
, sizeof (*uap
->anamelen
));
register struct socket
*so
;
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
so
= (struct socket
*)fp
->f_data
;
if ((so
->so_state
& SS_NBIO
) && (so
->so_state
& SS_ISCONNECTING
))
if (error
= sockargs(&nam
, uap
->name
, uap
->namelen
, MT_SONAME
))
error
= soconnect(so
, nam
);
if ((so
->so_state
& SS_NBIO
) && (so
->so_state
& SS_ISCONNECTING
)) {
while ((so
->so_state
& SS_ISCONNECTING
) && so
->so_error
== 0)
if (error
= tsleep((caddr_t
)&so
->so_timeo
, PSOCK
| PCATCH
,
so
->so_state
&= ~SS_ISCONNECTING
;
socketpair(p
, uap
, retval
)
register struct filedesc
*fdp
= p
->p_fd
;
struct socket
*so1
, *so2
;
if (error
= socreate(uap
->domain
, &so1
, uap
->type
, uap
->protocol
))
if (error
= socreate(uap
->domain
, &so2
, uap
->type
, uap
->protocol
))
if (error
= falloc(p
, &fp1
, &fd
))
fp1
->f_flag
= FREAD
|FWRITE
;
fp1
->f_type
= DTYPE_SOCKET
;
fp1
->f_data
= (caddr_t
)so1
;
if (error
= falloc(p
, &fp2
, &fd
))
fp2
->f_flag
= FREAD
|FWRITE
;
fp2
->f_type
= DTYPE_SOCKET
;
fp2
->f_data
= (caddr_t
)so2
;
if (error
= soconnect2(so1
, so2
))
if (uap
->type
== SOCK_DGRAM
) {
* Datagram socket connection is asymmetric.
if (error
= soconnect2(so2
, so1
))
error
= copyout((caddr_t
)sv
, (caddr_t
)uap
->rsv
, 2 * sizeof (int));
retval
[0] = sv
[0]; /* XXX ??? */
retval
[1] = sv
[1]; /* XXX ??? */
fdp
->fd_ofiles
[sv
[1]] = 0;
fdp
->fd_ofiles
[sv
[0]] = 0;
msg
.msg_namelen
= uap
->tolen
;
aiov
.iov_base
= uap
->buf
;
return (sendit(p
, uap
->s
, &msg
, uap
->flags
, retval
));
aiov
.iov_base
= uap
->buf
;
return (sendit(p
, uap
->s
, &msg
, uap
->flags
, retval
));
#define MSG_COMPAT 0x8000
struct iovec aiov
[UIO_SMALLIOV
], *iov
;
if (error
= copyin(uap
->msg
, (caddr_t
)&msg
, sizeof (struct omsghdr
)))
if ((u_int
)msg
.msg_iovlen
>= UIO_SMALLIOV
) {
if ((u_int
)msg
.msg_iovlen
>= UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*,
sizeof(struct iovec
) * (u_int
)msg
.msg_iovlen
, M_IOV
,
if (error
= copyin((caddr_t
)msg
.msg_iov
, (caddr_t
)iov
,
(unsigned)(msg
.msg_iovlen
* sizeof (struct iovec
))))
msg
.msg_flags
= MSG_COMPAT
;
error
= sendit(p
, uap
->s
, &msg
, uap
->flags
, retval
);
struct iovec aiov
[UIO_SMALLIOV
], *iov
;
if (error
= copyin(uap
->msg
, (caddr_t
)&msg
, sizeof (msg
)))
if ((u_int
)msg
.msg_iovlen
>= UIO_SMALLIOV
) {
if ((u_int
)msg
.msg_iovlen
>= UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*,
sizeof(struct iovec
) * (u_int
)msg
.msg_iovlen
, M_IOV
,
(error
= copyin((caddr_t
)msg
.msg_iov
, (caddr_t
)iov
,
(unsigned)(msg
.msg_iovlen
* sizeof (struct iovec
)))))
error
= sendit(p
, uap
->s
, &msg
, uap
->flags
, retval
);
sendit(p
, s
, mp
, flags
, retsize
)
register struct msghdr
*mp
;
register struct iovec
*iov
;
struct mbuf
*to
, *control
;
struct iovec
*ktriov
= NULL
;
if (error
= getsock(p
->p_fd
, s
, &fp
))
auio
.uio_iov
= mp
->msg_iov
;
auio
.uio_iovcnt
= mp
->msg_iovlen
;
auio
.uio_segflg
= UIO_USERSPACE
;
auio
.uio_offset
= 0; /* XXX */
for (i
= 0; i
< mp
->msg_iovlen
; i
++, iov
++) {
if ((auio
.uio_resid
+= iov
->iov_len
) < 0)
if (error
= sockargs(&to
, mp
->msg_name
, mp
->msg_namelen
,
if (mp
->msg_controllen
< sizeof(struct cmsghdr
)
&& mp
->msg_flags
!= MSG_COMPAT
if (error
= sockargs(&control
, mp
->msg_control
,
mp
->msg_controllen
, MT_CONTROL
))
if (mp
->msg_flags
== MSG_COMPAT
) {
register struct cmsghdr
*cm
;
M_PREPEND(control
, sizeof(*cm
), M_WAIT
);
cm
= mtod(control
, struct cmsghdr
*);
cm
->cmsg_len
= control
->m_len
;
cm
->cmsg_level
= SOL_SOCKET
;
cm
->cmsg_type
= SCM_RIGHTS
;
if (KTRPOINT(p
, KTR_GENIO
)) {
int iovlen
= auio
.uio_iovcnt
* sizeof (struct iovec
);
MALLOC(ktriov
, struct iovec
*, iovlen
, M_TEMP
, M_WAITOK
);
bcopy((caddr_t
)auio
.uio_iov
, (caddr_t
)ktriov
, iovlen
);
if (error
= sosend((struct socket
*)fp
->f_data
, to
, &auio
,
(struct mbuf
*)0, control
, flags
)) {
if (auio
.uio_resid
!= len
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
*retsize
= len
- auio
.uio_resid
;
ktrgenio(p
->p_tracep
, s
, UIO_WRITE
,
ktriov
, *retsize
, error
);
orecvfrom(p
, uap
, retval
)
uap
->flags
|= MSG_COMPAT
;
return (recvfrom(p
, uap
, retval
));
if (error
= copyin((caddr_t
)uap
->fromlenaddr
,
(caddr_t
)&msg
.msg_namelen
, sizeof (msg
.msg_namelen
)))
msg
.msg_name
= uap
->from
;
aiov
.iov_base
= uap
->buf
;
msg
.msg_flags
= uap
->flags
;
return (recvit(p
, uap
->s
, &msg
, (caddr_t
)uap
->fromlenaddr
, retval
));
aiov
.iov_base
= uap
->buf
;
msg
.msg_flags
= uap
->flags
;
return (recvit(p
, uap
->s
, &msg
, (caddr_t
)0, retval
));
* Old recvmsg. This code takes advantage of the fact that the old msghdr
* overlays the new one, missing only the flags, and with the (old) access
* rights where the control fields are now.
struct iovec aiov
[UIO_SMALLIOV
], *iov
;
if (error
= copyin((caddr_t
)uap
->msg
, (caddr_t
)&msg
,
sizeof (struct omsghdr
)))
if ((u_int
)msg
.msg_iovlen
>= UIO_SMALLIOV
) {
if ((u_int
)msg
.msg_iovlen
>= UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*,
sizeof(struct iovec
) * (u_int
)msg
.msg_iovlen
, M_IOV
,
msg
.msg_flags
= uap
->flags
| MSG_COMPAT
;
if (error
= copyin((caddr_t
)msg
.msg_iov
, (caddr_t
)iov
,
(unsigned)(msg
.msg_iovlen
* sizeof (struct iovec
))))
error
= recvit(p
, uap
->s
, &msg
, (caddr_t
)&uap
->msg
->msg_namelen
, retval
);
if (msg
.msg_controllen
&& error
== 0)
error
= copyout((caddr_t
)&msg
.msg_controllen
,
(caddr_t
)&uap
->msg
->msg_accrightslen
, sizeof (int));
struct iovec aiov
[UIO_SMALLIOV
], *uiov
, *iov
;
if (error
= copyin((caddr_t
)uap
->msg
, (caddr_t
)&msg
, sizeof (msg
)))
if ((u_int
)msg
.msg_iovlen
>= UIO_SMALLIOV
) {
if ((u_int
)msg
.msg_iovlen
>= UIO_MAXIOV
)
MALLOC(iov
, struct iovec
*,
sizeof(struct iovec
) * (u_int
)msg
.msg_iovlen
, M_IOV
,
msg
.msg_flags
= uap
->flags
&~ MSG_COMPAT
;
msg
.msg_flags
= uap
->flags
;
if (error
= copyin((caddr_t
)uiov
, (caddr_t
)iov
,
(unsigned)(msg
.msg_iovlen
* sizeof (struct iovec
))))
if ((error
= recvit(p
, uap
->s
, &msg
, (caddr_t
)0, retval
)) == 0) {
error
= copyout((caddr_t
)&msg
, (caddr_t
)uap
->msg
, sizeof(msg
));
recvit(p
, s
, mp
, namelenp
, retsize
)
register struct msghdr
*mp
;
register struct iovec
*iov
;
struct mbuf
*from
= 0, *control
= 0;
struct iovec
*ktriov
= NULL
;
if (error
= getsock(p
->p_fd
, s
, &fp
))
auio
.uio_iov
= mp
->msg_iov
;
auio
.uio_iovcnt
= mp
->msg_iovlen
;
auio
.uio_segflg
= UIO_USERSPACE
;
auio
.uio_offset
= 0; /* XXX */
for (i
= 0; i
< mp
->msg_iovlen
; i
++, iov
++) {
if ((auio
.uio_resid
+= iov
->iov_len
) < 0)
if (KTRPOINT(p
, KTR_GENIO
)) {
int iovlen
= auio
.uio_iovcnt
* sizeof (struct iovec
);
MALLOC(ktriov
, struct iovec
*, iovlen
, M_TEMP
, M_WAITOK
);
bcopy((caddr_t
)auio
.uio_iov
, (caddr_t
)ktriov
, iovlen
);
if (error
= soreceive((struct socket
*)fp
->f_data
, &from
, &auio
,
(struct mbuf
**)0, &control
, &mp
->msg_flags
)) {
if (auio
.uio_resid
!= len
&& (error
== ERESTART
||
error
== EINTR
|| error
== EWOULDBLOCK
))
ktrgenio(p
->p_tracep
, s
, UIO_READ
,
ktriov
, len
- auio
.uio_resid
, error
);
*retsize
= len
- auio
.uio_resid
;
if (len
<= 0 || from
== 0)
if (mp
->msg_flags
& MSG_COMPAT
)
mtod(from
, struct osockaddr
*)->sa_family
=
mtod(from
, struct sockaddr
*)->sa_family
;
/* else if len < from->m_len ??? */
if (error
= copyout(mtod(from
, caddr_t
),
(caddr_t
)mp
->msg_name
, (unsigned)len
))
(error
= copyout((caddr_t
)&len
, namelenp
, sizeof (int)))) {
if (mp
->msg_flags
& MSG_COMPAT
)
error
= 0; /* old recvfrom didn't check */
* We assume that old recvmsg calls won't receive access
* rights and other control info, esp. as control info
* is always optional and those options didn't exist in 4.3.
* If we receive rights, trim the cmsghdr; anything else
if (control
&& mp
->msg_flags
& MSG_COMPAT
) {
if (mtod(control
, struct cmsghdr
*)->cmsg_level
!=
mtod(control
, struct cmsghdr
*)->cmsg_type
!=
control
->m_len
-= sizeof (struct cmsghdr
);
control
->m_data
+= sizeof (struct cmsghdr
);
len
= mp
->msg_controllen
;
if (len
<= 0 || control
== 0)
if (len
>= control
->m_len
)
mp
->msg_flags
|= MSG_CTRUNC
;
error
= copyout((caddr_t
)mtod(control
, caddr_t
),
(caddr_t
)mp
->msg_control
, (unsigned)len
);
mp
->msg_controllen
= len
;
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
return (soshutdown((struct socket
*)fp
->f_data
, uap
->how
));
setsockopt(p
, uap
, retval
)
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
m
= m_get(M_WAIT
, MT_SOOPTS
);
if (error
= copyin(uap
->val
, mtod(m
, caddr_t
),
return (sosetopt((struct socket
*)fp
->f_data
, uap
->level
,
getsockopt(p
, uap
, retval
)
if (error
= getsock(p
->p_fd
, uap
->s
, &fp
))
if (error
= copyin((caddr_t
)uap
->avalsize
, (caddr_t
)&valsize
,
if ((error
= sogetopt((struct socket
*)fp
->f_data
, uap
->level
,
uap
->name
, &m
)) == 0 && uap
->val
&& valsize
&& m
!= NULL
) {
error
= copyout(mtod(m
, caddr_t
), uap
->val
, (u_int
)valsize
);
error
= copyout((caddr_t
)&valsize
,
(caddr_t
)uap
->avalsize
, sizeof (valsize
));
register struct filedesc
*fdp
= p
->p_fd
;
struct socket
*rso
, *wso
;
if (error
= socreate(AF_UNIX
, &rso
, SOCK_STREAM
, 0))
if (error
= socreate(AF_UNIX
, &wso
, SOCK_STREAM
, 0))
if (error
= falloc(p
, &rf
, &fd
))
rf
->f_type
= DTYPE_SOCKET
;
rf
->f_data
= (caddr_t
)rso
;
if (error
= falloc(p
, &wf
, &fd
))
wf
->f_type
= DTYPE_SOCKET
;
wf
->f_data
= (caddr_t
)wso
;
if (error
= unp_connect2(wso
, rso
))
fdp
->fd_ofiles
[retval
[1]] = 0;
fdp
->fd_ofiles
[retval
[0]] = 0;
getsockname(p
, uap
, retval
)
return (getsockname1(p
, uap
, retval
));
ogetsockname(p
, uap
, retval
)
return (getsockname1(p
, uap
, retval
));
#define getsockname1 getsockname
getsockname1(p
, uap
, retval
)
register struct socket
*so
;
if (error
= getsock(p
->p_fd
, uap
->fdes
, &fp
))
if (error
= copyin((caddr_t
)uap
->alen
, (caddr_t
)&len
, sizeof (len
)))
so
= (struct socket
*)fp
->f_data
;
m
= m_getclr(M_WAIT
, MT_SONAME
);
if (error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_SOCKADDR
, 0, m
, 0))
mtod(m
, struct osockaddr
*)->sa_family
=
mtod(m
, struct sockaddr
*)->sa_family
;
error
= copyout(mtod(m
, caddr_t
), (caddr_t
)uap
->asa
, (u_int
)len
);
error
= copyout((caddr_t
)&len
, (caddr_t
)uap
->alen
,
* Get name of peer for connected socket.
getpeername(p
, uap
, retval
)
return (getpeername1(p
, uap
, retval
));
ogetpeername(p
, uap
, retval
)
return (getpeername1(p
, uap
, retval
));
#define getpeername1 getpeername
getpeername1(p
, uap
, retval
)
register struct socket
*so
;
if (error
= getsock(p
->p_fd
, uap
->fdes
, &fp
))
so
= (struct socket
*)fp
->f_data
;
if ((so
->so_state
& (SS_ISCONNECTED
|SS_ISCONFIRMING
)) == 0)
m
= m_getclr(M_WAIT
, MT_SONAME
);
if (error
= copyin((caddr_t
)uap
->alen
, (caddr_t
)&len
, sizeof (len
)))
if (error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_PEERADDR
, 0, m
, 0))
mtod(m
, struct osockaddr
*)->sa_family
=
mtod(m
, struct sockaddr
*)->sa_family
;
if (error
= copyout(mtod(m
, caddr_t
), (caddr_t
)uap
->asa
, (u_int
)len
))
error
= copyout((caddr_t
)&len
, (caddr_t
)uap
->alen
, sizeof (len
));
sockargs(mp
, buf
, buflen
, type
)
if ((u_int
)buflen
> MLEN
) {
if (type
== MT_SONAME
&& (u_int
)buflen
<= 112)
buflen
= MLEN
; /* unix domain compat. hack */
error
= copyin(buf
, mtod(m
, caddr_t
), (u_int
)buflen
);
register struct sockaddr
*sa
= mtod(m
, struct sockaddr
*);
#if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN
if (sa
->sa_family
== 0 && sa
->sa_len
< AF_MAX
)
sa
->sa_family
= sa
->sa_len
;
register struct file
*fp
;
if ((unsigned)fdes
>= fdp
->fd_nfiles
||
(fp
= fdp
->fd_ofiles
[fdes
]) == NULL
)
if (fp
->f_type
!= DTYPE_SOCKET
)