|
@@ -534,6 +534,29 @@ static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb)
|
|
|
return pipe_handler_send_created_ind(sk);
|
|
|
}
|
|
|
|
|
|
+static int pep_enableresp_rcv(struct sock *sk, struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct pnpipehdr *hdr = pnp_hdr(skb);
|
|
|
+
|
|
|
+ if (hdr->error_code != PN_PIPE_NO_ERROR)
|
|
|
+ return -ECONNREFUSED;
|
|
|
+
|
|
|
+ return pep_indicate(sk, PNS_PIPE_ENABLED_IND, 0 /* sub-blocks */,
|
|
|
+ NULL, 0, GFP_ATOMIC);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static void pipe_start_flow_control(struct sock *sk)
|
|
|
+{
|
|
|
+ struct pep_sock *pn = pep_sk(sk);
|
|
|
+
|
|
|
+ if (!pn_flow_safe(pn->tx_fc)) {
|
|
|
+ atomic_set(&pn->tx_credits, 1);
|
|
|
+ sk->sk_write_space(sk);
|
|
|
+ }
|
|
|
+ pipe_grant_credits(sk, GFP_ATOMIC);
|
|
|
+}
|
|
|
+
|
|
|
/* Queue an skb to an actively connected sock.
|
|
|
* Socket lock must be held. */
|
|
|
static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
|
|
@@ -579,13 +602,25 @@ static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb)
|
|
|
sk->sk_state = TCP_CLOSE_WAIT;
|
|
|
break;
|
|
|
}
|
|
|
+ if (pn->init_enable == PN_PIPE_DISABLE)
|
|
|
+ sk->sk_state = TCP_SYN_RECV;
|
|
|
+ else {
|
|
|
+ sk->sk_state = TCP_ESTABLISHED;
|
|
|
+ pipe_start_flow_control(sk);
|
|
|
+ }
|
|
|
+ break;
|
|
|
|
|
|
- sk->sk_state = TCP_ESTABLISHED;
|
|
|
- if (!pn_flow_safe(pn->tx_fc)) {
|
|
|
- atomic_set(&pn->tx_credits, 1);
|
|
|
- sk->sk_write_space(sk);
|
|
|
+ case PNS_PEP_ENABLE_RESP:
|
|
|
+ if (sk->sk_state != TCP_SYN_SENT)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (pep_enableresp_rcv(sk, skb)) {
|
|
|
+ sk->sk_state = TCP_CLOSE_WAIT;
|
|
|
+ break;
|
|
|
}
|
|
|
- pipe_grant_credits(sk, GFP_ATOMIC);
|
|
|
+
|
|
|
+ sk->sk_state = TCP_ESTABLISHED;
|
|
|
+ pipe_start_flow_control(sk);
|
|
|
break;
|
|
|
|
|
|
case PNS_PEP_DISCONNECT_RESP:
|
|
@@ -864,14 +899,32 @@ static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len)
|
|
|
int err;
|
|
|
u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD };
|
|
|
|
|
|
- pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
|
|
|
+ if (pn->pipe_handle == PN_PIPE_INVALID_HANDLE)
|
|
|
+ pn->pipe_handle = 1; /* anything but INVALID_HANDLE */
|
|
|
+
|
|
|
err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ,
|
|
|
- PN_PIPE_ENABLE, data, 4);
|
|
|
+ pn->init_enable, data, 4);
|
|
|
if (err) {
|
|
|
pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
|
|
|
return err;
|
|
|
}
|
|
|
+
|
|
|
sk->sk_state = TCP_SYN_SENT;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int pep_sock_enable(struct sock *sk, struct sockaddr *addr, int len)
|
|
|
+{
|
|
|
+ int err;
|
|
|
+
|
|
|
+ err = pipe_handler_request(sk, PNS_PEP_ENABLE_REQ, PAD,
|
|
|
+ NULL, 0);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ sk->sk_state = TCP_SYN_SENT;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -879,11 +932,14 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
|
|
{
|
|
|
struct pep_sock *pn = pep_sk(sk);
|
|
|
int answ;
|
|
|
+ int ret = -ENOIOCTLCMD;
|
|
|
|
|
|
switch (cmd) {
|
|
|
case SIOCINQ:
|
|
|
- if (sk->sk_state == TCP_LISTEN)
|
|
|
- return -EINVAL;
|
|
|
+ if (sk->sk_state == TCP_LISTEN) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
lock_sock(sk);
|
|
|
if (sock_flag(sk, SOCK_URGINLINE) &&
|
|
@@ -894,10 +950,22 @@ static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
|
|
|
else
|
|
|
answ = 0;
|
|
|
release_sock(sk);
|
|
|
- return put_user(answ, (int __user *)arg);
|
|
|
+ ret = put_user(answ, (int __user *)arg);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SIOCPNENABLEPIPE:
|
|
|
+ lock_sock(sk);
|
|
|
+ if (sk->sk_state == TCP_SYN_SENT)
|
|
|
+ ret = -EBUSY;
|
|
|
+ else if (sk->sk_state == TCP_ESTABLISHED)
|
|
|
+ ret = -EISCONN;
|
|
|
+ else
|
|
|
+ ret = pep_sock_enable(sk, NULL, 0);
|
|
|
+ release_sock(sk);
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- return -ENOIOCTLCMD;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int pep_init(struct sock *sk)
|
|
@@ -960,6 +1028,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
|
|
|
}
|
|
|
goto out_norel;
|
|
|
|
|
|
+ case PNPIPE_HANDLE:
|
|
|
+ if ((sk->sk_state == TCP_CLOSE) &&
|
|
|
+ (val >= 0) && (val < PN_PIPE_INVALID_HANDLE))
|
|
|
+ pn->pipe_handle = val;
|
|
|
+ else
|
|
|
+ err = -EINVAL;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case PNPIPE_INITSTATE:
|
|
|
+ pn->init_enable = !!val;
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
err = -ENOPROTOOPT;
|
|
|
}
|
|
@@ -995,6 +1075,10 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
|
|
|
return -EINVAL;
|
|
|
break;
|
|
|
|
|
|
+ case PNPIPE_INITSTATE:
|
|
|
+ val = pn->init_enable;
|
|
|
+ break;
|
|
|
+
|
|
|
default:
|
|
|
return -ENOPROTOOPT;
|
|
|
}
|