Commit bdb6e697 authored by Dinesh Kumar Sharma's avatar Dinesh Kumar Sharma Committed by David S. Miller

Phonet: set the pipe handle using setsockopt

This provides flexibility to set the pipe handle
using setsockopt. The pipe can be enabled (if disabled) later
using ioctl.
Signed-off-by: default avatarHemant Ramdasi <hemant.ramdasi@stericsson.com>
Signed-off-by: default avatarDinesh Kumar Sharma <dinesh.sharma@stericsson.com>
Acked-by: default avatarRémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 805dc1d6
......@@ -38,6 +38,7 @@
#define PNPIPE_ENCAP 1
#define PNPIPE_IFINDEX 2
#define PNPIPE_HANDLE 3
#define PNPIPE_INITSTATE 4
#define PNADDR_ANY 0
#define PNADDR_BROADCAST 0xFC
......@@ -49,6 +50,7 @@
/* ioctls */
#define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0)
#define SIOCPNENABLEPIPE (SIOCPROTOPRIVATE + 13)
#define SIOCPNADDRESOURCE (SIOCPROTOPRIVATE + 14)
#define SIOCPNDELRESOURCE (SIOCPROTOPRIVATE + 15)
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment