diff options
author | Sabrina Dubroca <sd@queasysnail.net> | 2014-02-09 00:23:38 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-02-12 19:26:32 -0500 |
commit | 8815cbd9e38a7a02bfb79854aa7d33f1e1e50305 (patch) | |
tree | db9bb3b7d7cd27ccf767d9a0002948a7f72d77cb /net | |
parent | 6028323b52e06377638b3509afffb9d86bf4bdf7 (diff) | |
download | op-kernel-dev-8815cbd9e38a7a02bfb79854aa7d33f1e1e50305.zip op-kernel-dev-8815cbd9e38a7a02bfb79854aa7d33f1e1e50305.tar.gz |
ipx: implement shutdown()
IPX doesn't implement shutdown, which poses a problem to some users:
https://bugzilla.kernel.org/show_bug.cgi?id=67841
This patch is heavily based on the shutdown implementation for unix
sockets.
Reported-by: Bruno Jesus <00cpxxx@gmail.com>
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipx/af_ipx.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index 00b2a6d..41e4e93 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1368,6 +1368,7 @@ static int ipx_release(struct socket *sock) goto out; lock_sock(sk); + sk->sk_shutdown = SHUTDOWN_MASK; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_state_change(sk); @@ -1791,8 +1792,11 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock, skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &rc); - if (!skb) + if (!skb) { + if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN)) + rc = 0; goto out; + } ipx = ipx_hdr(skb); copied = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr); @@ -1922,6 +1926,26 @@ static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long } #endif +static int ipx_shutdown(struct socket *sock, int mode) +{ + struct sock *sk = sock->sk; + + if (mode < SHUT_RD || mode > SHUT_RDWR) + return -EINVAL; + /* This maps: + * SHUT_RD (0) -> RCV_SHUTDOWN (1) + * SHUT_WR (1) -> SEND_SHUTDOWN (2) + * SHUT_RDWR (2) -> SHUTDOWN_MASK (3) + */ + ++mode; + + lock_sock(sk); + sk->sk_shutdown |= mode; + release_sock(sk); + sk->sk_state_change(sk); + + return 0; +} /* * Socket family declarations @@ -1948,7 +1972,7 @@ static const struct proto_ops ipx_dgram_ops = { .compat_ioctl = ipx_compat_ioctl, #endif .listen = sock_no_listen, - .shutdown = sock_no_shutdown, /* FIXME: support shutdown */ + .shutdown = ipx_shutdown, .setsockopt = ipx_setsockopt, .getsockopt = ipx_getsockopt, .sendmsg = ipx_sendmsg, |