return hash&(UNIX_HASH_SIZE-1);
}
-#define unix_peer(sk) ((sk)->sk_pair)
+#define unix_peer(sk) (unix_sk(sk)->peer)
static inline int unix_our_peer(struct sock *sk, struct sock *osk)
{
struct msghdr *, size_t, int);
static int unix_dgram_connect(struct socket *, struct sockaddr *,
int, int);
+static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
+ struct msghdr *, size_t);
static struct proto_ops unix_stream_ops = {
.family = PF_UNIX,
.shutdown = unix_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
- .sendmsg = unix_dgram_sendmsg,
+ .sendmsg = unix_seqpacket_sendmsg,
.recvmsg = unix_dgram_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
if (other->sk_shutdown & RCV_SHUTDOWN)
goto out_unlock;
- err = security_unix_may_send(sk->sk_socket, other->sk_socket);
- if (err)
- goto out_unlock;
+ if (sk->sk_type != SOCK_SEQPACKET) {
+ err = security_unix_may_send(sk->sk_socket, other->sk_socket);
+ if (err)
+ goto out_unlock;
+ }
if (unix_peer(other) != sk &&
(skb_queue_len(&other->sk_receive_queue) >
return sent ? : err;
}
+static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock,
+ struct msghdr *msg, size_t len)
+{
+ int err;
+ struct sock *sk = sock->sk;
+
+ err = sock_error(sk);
+ if (err)
+ return err;
+
+ if (sk->sk_state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+
+ if (msg->msg_namelen)
+ msg->msg_namelen = 0;
+
+ return unix_dgram_sendmsg(kiocb, sock, msg, len);
+}
+
static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
{
struct unix_sock *u = unix_sk(sk);
msg->msg_namelen = 0;
+ down(&u->readsem);
+
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb)
- goto out;
+ goto out_unlock;
wake_up_interruptible(&u->peer_wait);
out_free:
skb_free_datagram(sk,skb);
+out_unlock:
+ up(&u->readsem);
out:
return err;
}