@@ -1265,6 +1265,24 @@ void sk_prot_clear_portaddr_nulls(struct sock *sk, int size);
#define RCV_SHUTDOWN 1
#define SEND_SHUTDOWN 2
+static inline int shutdown_u2mask(int uhow)
+{
+ /*
+ * map
+ * SHUT_RD -> RCV_SHUTDOWN
+ * SHUT_WR -> SEND_SHUTDOWN
+ * SHUT_RDWR -> SHUTDOWN_MASK
+ *
+ * or report 0 on error
+ */
+
+ uhow++;
+ if (uhow & ~SHUTDOWN_MASK)
+ uhow = 0;
+
+ return uhow;
+}
+
#define SOCK_SNDBUF_LOCK 1
#define SOCK_RCVBUF_LOCK 2
#define SOCK_BINDADDR_LOCK 4
@@ -825,10 +825,9 @@ int inet_shutdown(struct socket *sock, int how)
/* This should really check to make sure
* the socket is a TCP socket. (WHY AC...)
*/
- how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
- 1->2 bit 2 snds.
- 2->3 */
- if ((how & ~SHUTDOWN_MASK) || !how) /* MAXINT->0 */
+
+ how = shutdown_u2mask(how);
+ if (!how)
return -EINVAL;
lock_sock(sk);
@@ -1497,9 +1497,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
struct iucv_message txmsg;
int err = 0;
- how++;
-
- if ((how & ~SHUTDOWN_MASK) || !how)
+ how = shutdown_u2mask(how);
+ if (!how)
return -EINVAL;
lock_sock(sk);
@@ -2057,14 +2057,9 @@ static int unix_shutdown(struct socket *sock, int mode)
struct sock *sk = sock->sk;
struct sock *other;
- if (mode < SHUT_RD || mode > SHUT_RDWR)
+ mode = shutdown_u2mask(mode);
+ if (!mode)
return -EINVAL;
- /* This maps:
- * SHUT_RD (0) -> RCV_SHUTDOWN (1)
- * SHUT_WR (1) -> SEND_SHUTDOWN (2)
- * SHUT_RDWR (2) -> SHUTDOWN_MASK (3)
- */
- ++mode;
unix_state_lock(sk);
sk->sk_shutdown |= mode;
The sys_shutdown "how" argument is converted into kernel-side mask with a trick -- the "how++" does proper bits conversion. And since this is a trick, it's commented in the respective places. When there will be sk_shutdown reporting mechanism it will be natural to report not the kernel-side mask, but the values known by userspace (this "how" thing), i.e. we'll have to do the reciprocal trick. I propose to encapsulate both tricks in helpers, here's the user to kernel one. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> --- include/net/sock.h | 18 ++++++++++++++++++ net/ipv4/af_inet.c | 7 +++---- net/iucv/af_iucv.c | 5 ++--- net/unix/af_unix.c | 9 ++------- 4 files changed, 25 insertions(+), 14 deletions(-)