diff options
| author | Dinesh Kumar Sharma <dinesh.sharma@stericsson.com> | 2011-11-18 01:22:05 +0000 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-11-18 14:37:40 -0500 | 
| commit | bdb6e697b2a76c541960b86ab8fda88f3de1adf2 (patch) | |
| tree | 0bd09da4195a4059ab8e353278c2a58757126eff /net/phonet | |
| parent | 805dc1d60fb0d4a8b7730748a11dc2688b8f6cf6 (diff) | |
| download | linux-bdb6e697b2a76c541960b86ab8fda88f3de1adf2.tar.bz2 | |
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: 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>
Diffstat (limited to 'net/phonet')
| -rw-r--r-- | net/phonet/pep.c | 106 | 
1 files changed, 95 insertions, 11 deletions
| diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 2ba6e9fb4cbc..9f60008740e3 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -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;  	} |