Phonet: set the pipe handle using setsockopt
authorDinesh Kumar Sharma <dinesh.sharma@stericsson.com>
Fri, 18 Nov 2011 01:22:05 +0000 (01:22 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 18 Nov 2011 19:37:40 +0000 (14:37 -0500)
This provides flexibility to set the pipe handle
using setsockopt. The pipe can be enabled (if disabled) later
using ioctl.

Signed-off-by: Hemant Ramdasi <hemant.ramdasi@stericsson.com>
Signed-off-by: Dinesh Kumar Sharma <dinesh.sharma@stericsson.com>
Acked-by: RĂ©mi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/linux/phonet.h
net/phonet/pep.c

index f53a416..f48bfc8 100644 (file)
@@ -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)
 
index 2ba6e9f..9f60008 100644 (file)
@@ -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;
        }