ipx: implement shutdown()
authorSabrina Dubroca <sd@queasysnail.net>
Sat, 8 Feb 2014 23:23:38 +0000 (00:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 13 Feb 2014 00:26:32 +0000 (19:26 -0500)
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>
net/ipx/af_ipx.c

index 00b2a6d..41e4e93 100644 (file)
@@ -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,