af_iucv: add shutdown for HS transport
AF_IUCV sockets offer a shutdown function. This patch makes sure shutdown works for HS transport as well. Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
9fbd87d413
commit
82492a355f
|
@ -62,6 +62,7 @@ struct sock_msg_q {
|
||||||
#define AF_IUCV_FLAG_SYN 0x2
|
#define AF_IUCV_FLAG_SYN 0x2
|
||||||
#define AF_IUCV_FLAG_FIN 0x4
|
#define AF_IUCV_FLAG_FIN 0x4
|
||||||
#define AF_IUCV_FLAG_WIN 0x8
|
#define AF_IUCV_FLAG_WIN 0x8
|
||||||
|
#define AF_IUCV_FLAG_SHT 0x10
|
||||||
|
|
||||||
struct af_iucv_trans_hdr {
|
struct af_iucv_trans_hdr {
|
||||||
u16 magic;
|
u16 magic;
|
||||||
|
|
|
@ -165,8 +165,6 @@ static int afiucv_pm_freeze(struct device *dev)
|
||||||
read_lock(&iucv_sk_list.lock);
|
read_lock(&iucv_sk_list.lock);
|
||||||
sk_for_each(sk, node, &iucv_sk_list.head) {
|
sk_for_each(sk, node, &iucv_sk_list.head) {
|
||||||
iucv = iucv_sk(sk);
|
iucv = iucv_sk(sk);
|
||||||
skb_queue_purge(&iucv->send_skb_q);
|
|
||||||
skb_queue_purge(&iucv->backlog_skb_q);
|
|
||||||
switch (sk->sk_state) {
|
switch (sk->sk_state) {
|
||||||
case IUCV_DISCONN:
|
case IUCV_DISCONN:
|
||||||
case IUCV_CLOSING:
|
case IUCV_CLOSING:
|
||||||
|
@ -405,7 +403,19 @@ static struct sock *__iucv_get_sock_by_name(char *nm)
|
||||||
static void iucv_sock_destruct(struct sock *sk)
|
static void iucv_sock_destruct(struct sock *sk)
|
||||||
{
|
{
|
||||||
skb_queue_purge(&sk->sk_receive_queue);
|
skb_queue_purge(&sk->sk_receive_queue);
|
||||||
skb_queue_purge(&sk->sk_write_queue);
|
skb_queue_purge(&sk->sk_error_queue);
|
||||||
|
|
||||||
|
sk_mem_reclaim(sk);
|
||||||
|
|
||||||
|
if (!sock_flag(sk, SOCK_DEAD)) {
|
||||||
|
pr_err("Attempt to release alive iucv socket %p\n", sk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
|
||||||
|
WARN_ON(atomic_read(&sk->sk_wmem_alloc));
|
||||||
|
WARN_ON(sk->sk_wmem_queued);
|
||||||
|
WARN_ON(sk->sk_forward_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cleanup Listen */
|
/* Cleanup Listen */
|
||||||
|
@ -1342,6 +1352,8 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
|
|
||||||
rlen = skb->len; /* real length of skb */
|
rlen = skb->len; /* real length of skb */
|
||||||
copied = min_t(unsigned int, rlen, len);
|
copied = min_t(unsigned int, rlen, len);
|
||||||
|
if (!rlen)
|
||||||
|
sk->sk_shutdown = sk->sk_shutdown | RCV_SHUTDOWN;
|
||||||
|
|
||||||
cskb = skb;
|
cskb = skb;
|
||||||
if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
|
if (skb_copy_datagram_iovec(cskb, 0, msg->msg_iov, copied)) {
|
||||||
|
@ -1493,42 +1505,47 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
switch (sk->sk_state) {
|
switch (sk->sk_state) {
|
||||||
|
case IUCV_LISTEN:
|
||||||
case IUCV_DISCONN:
|
case IUCV_DISCONN:
|
||||||
case IUCV_CLOSING:
|
case IUCV_CLOSING:
|
||||||
case IUCV_CLOSED:
|
case IUCV_CLOSED:
|
||||||
err = -ENOTCONN;
|
err = -ENOTCONN;
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sk->sk_shutdown |= how;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
|
if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
|
||||||
txmsg.class = 0;
|
if (iucv->transport == AF_IUCV_TRANS_IUCV) {
|
||||||
txmsg.tag = 0;
|
txmsg.class = 0;
|
||||||
err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
|
txmsg.tag = 0;
|
||||||
0, (void *) iprm_shutdown, 8);
|
err = pr_iucv->message_send(iucv->path, &txmsg,
|
||||||
if (err) {
|
IUCV_IPRMDATA, 0, (void *) iprm_shutdown, 8);
|
||||||
switch (err) {
|
if (err) {
|
||||||
case 1:
|
switch (err) {
|
||||||
err = -ENOTCONN;
|
case 1:
|
||||||
break;
|
err = -ENOTCONN;
|
||||||
case 2:
|
break;
|
||||||
err = -ECONNRESET;
|
case 2:
|
||||||
break;
|
err = -ECONNRESET;
|
||||||
default:
|
break;
|
||||||
err = -ENOTCONN;
|
default:
|
||||||
break;
|
err = -ENOTCONN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
|
iucv_send_ctrl(sk, AF_IUCV_FLAG_SHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk->sk_shutdown |= how;
|
||||||
if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
|
if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
|
||||||
err = pr_iucv->path_quiesce(iucv->path, NULL);
|
if (iucv->transport == AF_IUCV_TRANS_IUCV) {
|
||||||
if (err)
|
err = pr_iucv->path_quiesce(iucv->path, NULL);
|
||||||
err = -ENOTCONN;
|
if (err)
|
||||||
|
err = -ENOTCONN;
|
||||||
|
/* skb_queue_purge(&sk->sk_receive_queue); */
|
||||||
|
}
|
||||||
skb_queue_purge(&sk->sk_receive_queue);
|
skb_queue_purge(&sk->sk_receive_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,8 +2083,13 @@ static int afiucv_hs_callback_rx(struct sock *sk, struct sk_buff *skb)
|
||||||
return NET_RX_SUCCESS;
|
return NET_RX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sk->sk_shutdown & RCV_SHUTDOWN) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
return NET_RX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* write stuff from iucv_msg to skb cb */
|
/* write stuff from iucv_msg to skb cb */
|
||||||
if (skb->len <= sizeof(struct af_iucv_trans_hdr)) {
|
if (skb->len < sizeof(struct af_iucv_trans_hdr)) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NET_RX_SUCCESS;
|
return NET_RX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -2173,7 +2195,10 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through and receive non-zero length data */
|
||||||
|
case (AF_IUCV_FLAG_SHT):
|
||||||
|
/* shutdown request */
|
||||||
|
/* fall through and receive zero length data */
|
||||||
case 0:
|
case 0:
|
||||||
/* plain data frame */
|
/* plain data frame */
|
||||||
memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
|
memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
|
||||||
|
|
Loading…
Reference in a new issue