* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)uipc_usrreq.c 6.17 (Berkeley) %G%
* Unix communications domain.
* rethink name space problems
* need a proper out-of-band
struct sockaddr sun_noname
= { AF_UNIX
};
ino_t unp_ino
; /* fake inode numbers */
uipc_usrreq(so
, req
, m
, nam
, rights
)
struct mbuf
*m
, *nam
, *rights
;
struct unpcb
*unp
= sotounpcb(so
);
register struct socket
*so2
;
if (req
!= PRU_SEND
&& rights
&& rights
->m_len
) {
if (unp
== 0 && req
!= PRU_ATTACH
) {
error
= unp_bind(unp
, nam
);
error
= unp_connect(so
, nam
);
error
= unp_connect2(so
, (struct mbuf
*)0,
nam
->m_len
= unp
->unp_remaddr
->m_len
;
bcopy(mtod(unp
->unp_remaddr
, caddr_t
),
mtod(nam
, caddr_t
), (unsigned)nam
->m_len
);
#define rcv (&so->so_rcv)
#define snd (&so2->so_snd)
so2
= unp
->unp_conn
->unp_socket
;
* Transfer resources back to send port
* and wakeup any waiting to write.
snd
->sb_mbmax
+= rcv
->sb_mbmax
- rcv
->sb_mbcnt
;
rcv
->sb_mbmax
= rcv
->sb_mbcnt
;
snd
->sb_hiwat
+= rcv
->sb_hiwat
- rcv
->sb_cc
;
rcv
->sb_hiwat
= rcv
->sb_cc
;
error
= unp_connect(so
, nam
);
if (unp
->unp_conn
== 0) {
so2
= unp
->unp_conn
->unp_socket
;
error
= unp_internalize(rights
);
if (sbspace(&so2
->so_rcv
) > 0) {
* There's no record of source socket's
* name, so send null name for the moment.
if (sbappendaddr(&so2
->so_rcv
,
&sun_noname
, m
, rights
)) {
#define rcv (&so2->so_rcv)
#define snd (&so->so_snd)
if (rights
&& rights
->m_len
) {
if (so
->so_state
& SS_CANTSENDMORE
) {
so2
= unp
->unp_conn
->unp_socket
;
* Send to paired receive port, and then
* give it enough resources to hold what it already has.
snd
->sb_mbmax
-= rcv
->sb_mbcnt
- rcv
->sb_mbmax
;
rcv
->sb_mbmax
= rcv
->sb_mbcnt
;
snd
->sb_hiwat
-= rcv
->sb_cc
- rcv
->sb_hiwat
;
rcv
->sb_hiwat
= rcv
->sb_cc
;
unp_drop(unp
, ECONNABORTED
);
((struct stat
*) m
)->st_blksize
= so
->so_snd
.sb_hiwat
;
if (so
->so_type
== SOCK_STREAM
&& unp
->unp_conn
!= 0) {
so2
= unp
->unp_conn
->unp_socket
;
((struct stat
*) m
)->st_blksize
+= so2
->so_rcv
.sb_cc
;
((struct stat
*) m
)->st_dev
= NODEV
;
((struct stat
*) m
)->st_ino
= unp_ino
++;
* We assign all buffering for stream sockets to the source,
* as that is where the flow control is implemented.
* Datagram sockets really use the sendspace as the maximum datagram size,
* and don't really want to reserve the sendspace. Their recvspace should
* be large enough for at least one max-size datagram plus address.
int unpst_sendspace
= PIPSIZ
;
int unpdg_sendspace
= 2*1024; /* really max datagram size */
int unpdg_recvspace
= 4*1024;
register struct unpcb
*unp
;
error
= soreserve(so
, unpst_sendspace
, unpst_recvspace
);
error
= soreserve(so
, unpdg_sendspace
, unpdg_recvspace
);
m
= m_getclr(M_DONTWAIT
, MT_PCB
);
unp
= mtod(m
, struct unpcb
*);
so
->so_pcb
= (caddr_t
)unp
;
register struct unpcb
*unp
;
unp
->unp_inode
->i_socket
= 0;
unp_drop(unp
->unp_refs
, ECONNRESET
);
soisdisconnected(unp
->unp_socket
);
unp
->unp_socket
->so_pcb
= 0;
m_freem(unp
->unp_remaddr
);
(void) m_free(dtom(unp
));
struct sockaddr_un
*soun
= mtod(nam
, struct sockaddr_un
*);
register struct inode
*ip
;
register struct nameidata
*ndp
= &u
.u_nd
;
ndp
->ni_dirp
= soun
->sun_path
;
if (unp
->unp_inode
!= NULL
|| nam
->m_len
== MLEN
)
*(mtod(nam
, caddr_t
) + nam
->m_len
) = 0;
/* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
ndp
->ni_nameiop
= CREATE
| FOLLOW
;
ndp
->ni_segflg
= UIO_SYSSPACE
;
ip
= maknode(IFSOCK
| 0777, ndp
);
error
= u
.u_error
; /* XXX */
ip
->i_socket
= unp
->unp_socket
;
iunlock(ip
); /* but keep reference */
register struct sockaddr_un
*soun
= mtod(nam
, struct sockaddr_un
*);
register struct inode
*ip
;
register struct socket
*so2
;
register struct nameidata
*ndp
= &u
.u_nd
;
ndp
->ni_dirp
= soun
->sun_path
;
if (nam
->m_len
+ (nam
->m_off
- MMINOFF
) == MLEN
)
*(mtod(nam
, caddr_t
) + nam
->m_len
) = 0;
ndp
->ni_nameiop
= LOOKUP
| FOLLOW
;
ndp
->ni_segflg
= UIO_SYSSPACE
;
return (error
); /* XXX */
if (access(ip
, IWRITE
)) {
if ((ip
->i_mode
&IFMT
) != IFSOCK
) {
if (so
->so_type
!= so2
->so_type
) {
if (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
&&
((so2
->so_options
&SO_ACCEPTCONN
) == 0 ||
(so2
= sonewconn(so2
)) == 0)) {
error
= unp_connect2(so
, nam
, so2
);
unp_connect2(so
, sonam
, so2
)
register struct socket
*so
;
register struct socket
*so2
;
register struct unpcb
*unp
= sotounpcb(so
);
register struct unpcb
*unp2
;
if (so2
->so_type
!= so
->so_type
)
unp
->unp_nextref
= unp2
->unp_refs
;
unp2
->unp_remaddr
= m_copy(sonam
, 0, (int)M_COPYALL
);
register struct unpcb
*unp2
= unp
->unp_conn
;
switch (unp
->unp_socket
->so_type
) {
if (unp2
->unp_refs
== unp
)
unp2
->unp_refs
= unp
->unp_nextref
;
if (unp2
->unp_nextref
== unp
)
unp2
= unp2
->unp_nextref
;
unp2
->unp_nextref
= unp
->unp_nextref
;
unp
->unp_socket
->so_state
&= ~SS_ISCONNECTED
;
soisdisconnected(unp
->unp_socket
);
soisdisconnected(unp2
->unp_socket
);
struct socket
*so
= unp
->unp_socket
;
so
->so_pcb
= (caddr_t
) 0;
m_freem(unp
->unp_remaddr
);
(void) m_free(dtom(unp
));
int newfds
= rights
->m_len
/ sizeof (int);
register struct file
**rp
= mtod(rights
, struct file
**);
register struct file
*fp
;
if (newfds
> ufavail()) {
for (i
= 0; i
< newfds
; i
++) {
for (i
= 0; i
< newfds
; i
++) {
panic("unp_externalize");
register struct file
**rp
;
int oldfds
= rights
->m_len
/ sizeof (int);
register struct file
*fp
;
rp
= mtod(rights
, struct file
**);
for (i
= 0; i
< oldfds
; i
++)
if (getf(*(int *)rp
++) == 0)
rp
= mtod(rights
, struct file
**);
for (i
= 0; i
< oldfds
; i
++) {
int unp_defer
, unp_gcing
;
extern struct domain unixdomain
;
register struct file
*fp
;
register struct socket
*so
;
for (fp
= file
; fp
< fileNFILE
; fp
++)
fp
->f_flag
&= ~(FMARK
|FDEFER
);
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_flag
& FDEFER
) {
if (fp
->f_count
== fp
->f_msgcount
)
if (fp
->f_type
!= DTYPE_SOCKET
)
so
= (struct socket
*)fp
->f_data
;
if (so
->so_proto
->pr_domain
!= &unixdomain
||
(so
->so_proto
->pr_flags
&PR_RIGHTS
) == 0)
if (so
->so_rcv
.sb_flags
& SB_LOCK
) {
unp_scan(so
->so_rcv
.sb_mb
, unp_mark
);
for (fp
= file
; fp
< fileNFILE
; fp
++) {
if (fp
->f_count
== fp
->f_msgcount
&& (fp
->f_flag
&FMARK
)==0) {
if (fp
->f_type
!= DTYPE_SOCKET
)
(void) soshutdown((struct socket
*)fp
->f_data
, 0);
unp_scan(m
, unp_discard
);
register struct mbuf
*m0
;
register struct file
**rp
;
for (m
= m0
; m
; m
= m
->m_next
)
if (m
->m_type
== MT_RIGHTS
&& m
->m_len
) {
qfds
= m
->m_len
/ sizeof (struct file
*);
rp
= mtod(m
, struct file
**);
for (i
= 0; i
< qfds
; i
++)
break; /* XXX, but saves time */
fp
->f_flag
|= (FMARK
|FDEFER
);