netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems
@ 2010-09-24 12:23 Kumar A Sanghvi
  2010-09-24 12:23 ` [PATCH 1/2] " Kumar A Sanghvi
  2010-09-24 12:23 ` [PATCH 2/2] Documentation: Update Phonet doc for Pipe Controller implementation Kumar A Sanghvi
  0 siblings, 2 replies; 5+ messages in thread
From: Kumar A Sanghvi @ 2010-09-24 12:23 UTC (permalink / raw)
  To: remi.denis-courmont, davem, netdev
  Cc: STEricsson_nomadik_linux, sudeep.divakaran, gulshan.karmani,
	Kumar Sanghvi

From: Kumar Sanghvi <kumar.sanghvi@stericsson.com>

This patch implements the Pipe Controller functionality in Phonet stack to
support Nokia Modems like WG2.5 which do not have Pipe Controller in them.

Abbreviation:
APE: Application Processing Engine running Linux Kernel.
Modem is a separate entity attached to the APE.

With the current Phonet stack, to send Pipe data (example TCP/IP data over
GPRS), it is assumed that there is some type of Pipe Controller present either
in Modem or on APE user-space.

Many Nokia Modems implement the Pipe controller inside them.
HOwever, the Nokia Slim Modem WG2.5, the one in ST-Ericsson U8500 platform,
does not implement the Pipe Controller.
So, it is expected that APE running Linux implement the Pipe controller.

Now, PN_DEV_HOST (0x00) is normally the address of modem, so Phonet stack sends
out Pipe data by default on 0x00.
However, the Nokia Slim Modem WG2.5 expects that any data directed to it from
App processing engine should have dst_dev = 0x60 in Phonet header.

On APE side, Pipe controller can be implemented either in user-space or at
Phonet stack level.

1. Pipe controller at User-space level
---------------------------------------
There are 3 cases now:

	Case 1: net_device carrying phonet traffic on APE has device address
	= 0x6c and user-space specifies destination as 0x00.
	---------------------------------------------------------------------

	Nokia Slim modem WG2.5 simply gets reset for MCE related messages which
	has dest_dev as something other than 0x60 in Phonet header.
	Further, the modem does not process Pipe messages which has dest_dev as
	something other than 0x60 in Phonet header, and simply echoes the
	message back.

	Case 2: net_device carrying phonet traffic on APE has device address
	= 0x6c and user-space specifies destination as 0x60.
	---------------------------------------------------------------------

	Things work fine here.
	The GPRS device gets created also and IP address is also obtained from
	modem.
	However, problem comes when its time for sending PIPE_DATA.
	Phonet stack will by default send PIPE_DATA to destination with dst_dev
	= 0x00 and dst_obj = 0x00 in pipe_skb_send. So, modem, as indicated in
	case above, will not process the Pipe data message which has dest_dev
	as something other than 0x60 in Phonet header, and simply echoes the
	message back. So, the GPRS device user never gets a correct response.

	Case 3: net_device carrying phonet traffic on APE has device address
	= 0x00 and user-space specified destination as 0x60.
	---------------------------------------------------------------------

	Things work fine here also.
	The GPRS device gets created also and IP address is also obtained from
	modem.
	However, again problem comes when its time for sending PIPE_DATA.
	Since, Phonet stack will send PIPE_DATA to dest_dev = 0x00 and dest_obj
	= 0x00, and since APE net-device also has address = 0x00, this message
	will get looped-back.
	So, some user-space app OR user-space Pipe handler has to take this
	data, fill in correct dst_dev (0x60) and send it to modem.
	As a result, the traffic essentially traverses two times via the Phonet
	stack:
		1st. via pipe_skb_send which will send data to 0x00 - which will
	 	     get looped back.
		2nd. via user-space pipe handler which again sends this data to
		     modem via phonet stack.

	Again, in the receive path, the return traffic will first go to pipe
	handler in user-space and then it will go to gprs0 device.

2. Pipe Controller at Phonet stack
----------------------------------

Implementing Pipe controller at Phonet stack resolves the problem of GPRS data
traversing two times the Phonet stack in Case 3 above.
Further, the pipe-creation and related Pipe handling will be transparent to
user-space.

This patch implements the Pipe controller logic in Phonet stack.
The implementation is derived from 'Nokia Wireless Modem API -
WirelessModem_API_user_guide.pdf' document depicting the sequence for
establishing data connection.

The patch adds a Kconfig option to Phonet stack allowing users to
enable/disable Pipe controller functionality in Phonet stack.
Users can enable this option for Nokia Slim modems which do not have Pipe
controller in them.

The patch adds 4 setsockopt options at the Phonet stack level to enable
creation, enabling, disabling and destroying a pipe.
The patch also adds getsockopt options to query the state of pipe at any stage
ie. whether it is created or enabled.

The patch also implements negotiating the flow control and selects the best
flow control which is supported by modem and APE.

This patch has been tested on ST-Ericsson U8500 running Linux kernel and
works fine for GPRS data.

Kumar Sanghvi (2):
  Phonet: Implement Pipe Controller to support Nokia Slim Modems
  Documentation: Update Phonet doc for Pipe Controller implementation

 Documentation/networking/phonet.txt |   53 ++++
 include/linux/phonet.h              |    5 +
 include/net/phonet/pep.h            |   21 ++
 net/phonet/Kconfig                  |   11 +
 net/phonet/pep.c                    |  447 ++++++++++++++++++++++++++++++++++-
 5 files changed, 531 insertions(+), 6 deletions(-)

-- 
1.7.2.dirty


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems
  2010-09-24 12:23 [PATCH 0/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems Kumar A Sanghvi
@ 2010-09-24 12:23 ` Kumar A Sanghvi
  2010-09-24 13:52   ` Eric Dumazet
  2010-09-24 12:23 ` [PATCH 2/2] Documentation: Update Phonet doc for Pipe Controller implementation Kumar A Sanghvi
  1 sibling, 1 reply; 5+ messages in thread
From: Kumar A Sanghvi @ 2010-09-24 12:23 UTC (permalink / raw)
  To: remi.denis-courmont, davem, netdev
  Cc: STEricsson_nomadik_linux, sudeep.divakaran, gulshan.karmani,
	Kumar Sanghvi, Linus Walleij

From: Kumar Sanghvi <kumar.sanghvi@stericsson.com>

Phonet stack assumes the presence of Pipe Controller, either in Modem or
on Application Processing Engine user-space for the Pipe data.
Nokia Slim Modems like WG2.5 used in ST-Ericsson U8500 platform do not
implement Pipe controller in them.
This patch adds Pipe Controller implemenation to Phonet stack to support
Pipe data over Phonet stack for Nokia Slim Modems.

Signed-off-by: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 include/linux/phonet.h   |    5 +
 include/net/phonet/pep.h |   21 +++
 net/phonet/Kconfig       |   11 ++
 net/phonet/pep.c         |  447 +++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 478 insertions(+), 6 deletions(-)

diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index 85e14a8..96f5625 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -36,6 +36,11 @@
 /* Socket options for SOL_PNPIPE level */
 #define PNPIPE_ENCAP		1
 #define PNPIPE_IFINDEX		2
+#define PNPIPE_CREATE           3
+#define PNPIPE_ENABLE           4
+#define PNPIPE_DISABLE          5
+#define PNPIPE_DESTROY          6
+#define PNPIPE_INQ              7
 
 #define PNADDR_ANY		0
 #define PNADDR_BROADCAST	0xFC
diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h
index 37f23dc..def6cfa 100644
--- a/include/net/phonet/pep.h
+++ b/include/net/phonet/pep.h
@@ -45,6 +45,10 @@ struct pep_sock {
 	u8			tx_fc;	/* TX flow control */
 	u8			init_enable;	/* auto-enable at creation */
 	u8			aligned;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	u16                     remote_pep;
+	u8                      pipe_state;
+#endif
 };
 
 static inline struct pep_sock *pep_sk(struct sock *sk)
@@ -165,4 +169,21 @@ enum {
 	PEP_IND_READY,
 };
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+#define PNS_PEP_CONNECT_UTID           0x02
+#define PNS_PIPE_CREATED_IND_UTID      0x04
+#define PNS_PIPE_ENABLE_UTID           0x0A
+#define PNS_PIPE_ENABLED_IND_UTID      0x0C
+#define PNS_PIPE_DISABLE_UTID          0x0F
+#define PNS_PIPE_DISABLED_IND_UTID     0x11
+#define PNS_PEP_DISCONNECT_UTID        0x06
+
+/* Used for tracking state of a pipe */
+enum {
+	PIPE_IDLE,
+	PIPE_DISABLED,
+	PIPE_ENABLED,
+};
+#endif /* CONFIG_PHONET_PIPECTRLR */
+
 #endif
diff --git a/net/phonet/Kconfig b/net/phonet/Kconfig
index 6ec7d55..901956a 100644
--- a/net/phonet/Kconfig
+++ b/net/phonet/Kconfig
@@ -14,3 +14,14 @@ config PHONET
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called phonet. If unsure, say N.
+
+config PHONET_PIPECTRLR
+	bool "Phonet Pipe Controller"
+	depends on PHONET
+	default N
+	help
+	  The Pipe Controller implementation in Phonet stack to support Pipe
+	  data with Nokia Slim modems like WG2.5 used on ST-Ericsson U8500
+	  platform.
+
+	  If unsure, say N.
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index d0e7eb2..02f60b0 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -88,6 +88,15 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
 	const struct pnpipehdr *oph = pnp_hdr(oskb);
 	struct pnpipehdr *ph;
 	struct sk_buff *skb;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	const struct phonethdr *hdr = pn_hdr(oskb);
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = hdr->pn_sdev,
+		.spn_obj = hdr->pn_sobj,
+	};
+#endif
 
 	skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
 	if (!skb)
@@ -105,10 +114,270 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
 	ph->pipe_handle = oph->pipe_handle;
 	ph->error_code = code;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	return pn_skb_send(sk, skb, &spn);
+#else
 	return pn_skb_send(sk, skb, &pipe_srv);
+#endif
 }
 
 #define PAD 0x00
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len)
+{
+	int i, j;
+	u8 base_fc, final_fc;
+
+	for (i = 0; i < len; i++) {
+		base_fc = host_fc[i];
+		for (j = 0; j < len; j++) {
+			if (remote_fc[j] == base_fc) {
+				final_fc = base_fc;
+				goto done;
+			}
+		}
+	}
+	return -EINVAL;
+
+done:
+	return final_fc;
+
+}
+
+static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
+		u8 *pref_rx_fc, u8 *req_tx_fc)
+{
+	struct pnpipehdr *hdr = pnp_hdr(skb);
+	u8 n_sb;
+
+	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
+		return -EINVAL;
+
+	n_sb = hdr->data[4];
+
+	__skb_pull(skb, sizeof(*hdr) + 4);
+	while (n_sb > 0) {
+		u8 type, buf[3], len = sizeof(buf);
+		u8 *data = pep_get_sb(skb, &type, &len, buf);
+
+		if (data == NULL)
+			return -EINVAL;
+
+		switch (type) {
+		case PN_PIPE_SB_REQUIRED_FC_TX:
+			if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+				break;
+			req_tx_fc[0] = data[2];
+			req_tx_fc[1] = data[3];
+			req_tx_fc[2] = data[4];
+			break;
+
+		case PN_PIPE_SB_PREFERRED_FC_RX:
+			if (len < 3 || (data[2] | data[3] | data[4]) > 3)
+				break;
+			pref_rx_fc[0] = data[2];
+			pref_rx_fc[1] = data[3];
+			pref_rx_fc[2] = data[4];
+			break;
+
+		}
+		n_sb--;
+	}
+	return 0;
+}
+
+static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid,
+		u8 msg_id, u8 p_handle, gfp_t priority)
+{
+	int len;
+	struct pnpipehdr *ph;
+	struct sk_buff *skb;
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = pn_dev(dobj),
+		.spn_obj = pn_obj(dobj),
+	};
+
+	static const u8 data[4] = {
+		PAD, PAD, PAD, PAD,
+	};
+
+	switch (msg_id) {
+	case PNS_PEP_CONNECT_REQ:
+		len = sizeof(data);
+		break;
+
+	case PNS_PEP_DISCONNECT_REQ:
+	case PNS_PEP_ENABLE_REQ:
+	case PNS_PEP_DISABLE_REQ:
+		len = 0;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PNPIPE_HEADER);
+	if (len) {
+		__skb_put(skb, len);
+		skb_copy_to_linear_data(skb, data, len);
+	}
+	__skb_push(skb, sizeof(*ph));
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = utid;
+	ph->message_id = msg_id;
+	ph->pipe_handle = p_handle;
+	ph->error_code = PN_PIPE_NO_ERROR;
+
+	return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_send_created_ind(struct sock *sk, u16 dobj,
+		u8 utid, u8 p_handle, u8 msg_id, u8 tx_fc, u8 rx_fc)
+{
+	int err_code;
+	struct pnpipehdr *ph;
+	struct sk_buff *skb;
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = pn_dev(dobj),
+		.spn_obj = pn_obj(dobj),
+	};
+
+	static u8 data[4] = {
+		0x03, 0x04,
+	};
+	data[2] = tx_fc;
+	data[3] = rx_fc;
+
+	/*
+	 * actually, below is number of sub-blocks and not error code.
+	 * Pipe_created_ind message format does not have any
+	 * error code field. However, the Phonet stack will always send
+	 * an error code as part of pnpipehdr. So, use that err_code to
+	 * specify the number of sub-blocks.
+	 */
+	err_code = 0x01;
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PNPIPE_HEADER);
+	__skb_put(skb, sizeof(data));
+	skb_copy_to_linear_data(skb, data, sizeof(data));
+	__skb_push(skb, sizeof(*ph));
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = utid;
+	ph->message_id = msg_id;
+	ph->pipe_handle = p_handle;
+	ph->error_code = err_code;
+
+	return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid,
+		u8 p_handle, u8 msg_id)
+{
+	int err_code;
+	struct pnpipehdr *ph;
+	struct sk_buff *skb;
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = pn_dev(dobj),
+		.spn_obj = pn_obj(dobj),
+	};
+
+	/*
+	 * actually, below is a filler.
+	 * Pipe_enabled/disabled_ind message format does not have any
+	 * error code field. However, the Phonet stack will always send
+	 * an error code as part of pnpipehdr. So, use that err_code to
+	 * specify the filler value.
+	 */
+	err_code = 0x0;
+
+	skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+	skb_set_owner_w(skb, sk);
+
+	skb_reserve(skb, MAX_PNPIPE_HEADER);
+	__skb_push(skb, sizeof(*ph));
+	skb_reset_transport_header(skb);
+	ph = pnp_hdr(skb);
+	ph->utid = utid;
+	ph->message_id = msg_id;
+	ph->pipe_handle = p_handle;
+	ph->error_code = err_code;
+
+	return pn_skb_send(sk, skb, &spn);
+}
+
+static int pipe_handler_enable_pipe(struct sock *sk, int cmd)
+{
+	int ret;
+	struct pep_sock *pn = pep_sk(sk);
+
+	switch (cmd) {
+	case PNPIPE_ENABLE:
+		ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
+				PNS_PIPE_ENABLE_UTID, PNS_PEP_ENABLE_REQ,
+				pn->pipe_handle, GFP_ATOMIC);
+		break;
+
+	case PNPIPE_DISABLE:
+		ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
+				PNS_PIPE_DISABLE_UTID, PNS_PEP_DISABLE_REQ,
+				pn->pipe_handle, GFP_ATOMIC);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pipe_handler_create_pipe(struct sock *sk, int pipe_handle, int cmd)
+{
+	int ret;
+	struct pep_sock *pn = pep_sk(sk);
+
+	switch (cmd) {
+	case PNPIPE_CREATE:
+		ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
+				PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ,
+				pipe_handle, GFP_ATOMIC);
+		break;
+
+	case PNPIPE_DESTROY:
+		ret = pipe_handler_send_req(sk, pn->remote_pep,
+				PNS_PEP_DISCONNECT_UTID,
+				PNS_PEP_DISCONNECT_REQ,
+				pn->pipe_handle, GFP_ATOMIC);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+#endif
+
 static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
 {
 	static const u8 data[20] = {
@@ -173,6 +442,14 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
 	struct pep_sock *pn = pep_sk(sk);
 	struct pnpipehdr *ph;
 	struct sk_buff *skb;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = pn_dev(pn->remote_pep),
+		.spn_obj = pn_obj(pn->remote_pep),
+	};
+#endif
 
 	skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
 	if (!skb)
@@ -192,7 +469,11 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
 	ph->data[3] = PAD;
 	ph->data[4] = status;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	return pn_skb_send(sk, skb, &spn);
+#else
 	return pn_skb_send(sk, skb, &pipe_srv);
+#endif
 }
 
 /* Send our RX flow control information to the sender.
@@ -308,6 +589,12 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 	struct pnpipehdr *hdr = pnp_hdr(skb);
 	struct sk_buff_head *queue;
 	int err = 0;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	struct phonethdr *ph = pn_hdr(skb);
+	static u8 host_pref_rx_fc[3], host_req_tx_fc[3];
+	u8 remote_pref_rx_fc[3], remote_req_tx_fc[3];
+	u8 negotiated_rx_fc, negotiated_tx_fc;
+#endif
 
 	BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
 
@@ -316,6 +603,40 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 		pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
 		break;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNS_PEP_CONNECT_RESP:
+		if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+				(ph->pn_sobj == pn_obj(pn->remote_pep))) {
+			pipe_get_flow_info(sk, skb, remote_pref_rx_fc,
+					remote_req_tx_fc);
+
+			 negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc,
+					 host_pref_rx_fc,
+					 sizeof(host_pref_rx_fc));
+			 negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc,
+					 remote_pref_rx_fc,
+					 sizeof(host_pref_rx_fc));
+
+			pn->pipe_state = PIPE_DISABLED;
+			pipe_handler_send_created_ind(sk, pn->remote_pep,
+					PNS_PIPE_CREATED_IND_UTID,
+					pn->pipe_handle, PNS_PIPE_CREATED_IND,
+					negotiated_tx_fc, negotiated_rx_fc);
+			pipe_handler_send_created_ind(sk, pn->pn_sk.sobject,
+					PNS_PIPE_CREATED_IND_UTID,
+					pn->pipe_handle, PNS_PIPE_CREATED_IND,
+					negotiated_tx_fc, negotiated_rx_fc);
+		} else {
+			pipe_handler_send_req(sk, pn->remote_pep,
+					PNS_PEP_CONNECT_UTID,
+					PNS_PEP_CONNECT_REQ, pn->pipe_handle,
+					GFP_ATOMIC);
+			pipe_get_flow_info(sk, skb, host_pref_rx_fc,
+					host_req_tx_fc);
+		}
+		break;
+#endif
+
 	case PNS_PEP_DISCONNECT_REQ:
 		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
 		sk->sk_state = TCP_CLOSE_WAIT;
@@ -323,11 +644,41 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 			sk->sk_state_change(sk);
 		break;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNS_PEP_DISCONNECT_RESP:
+		pn->pipe_state = PIPE_IDLE;
+		pipe_handler_send_req(sk, pn->pn_sk.sobject,
+				PNS_PEP_DISCONNECT_UTID,
+				PNS_PEP_DISCONNECT_REQ, pn->pipe_handle,
+				GFP_KERNEL);
+		break;
+#endif
+
 	case PNS_PEP_ENABLE_REQ:
 		/* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
 		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
 		break;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNS_PEP_ENABLE_RESP:
+		if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+				(ph->pn_sobj == pn_obj(pn->remote_pep))) {
+			pn->pipe_state = PIPE_ENABLED;
+			pipe_handler_send_ind(sk, pn->remote_pep,
+					PNS_PIPE_ENABLED_IND_UTID,
+					pn->pipe_handle, PNS_PIPE_ENABLED_IND);
+			pipe_handler_send_ind(sk, pn->pn_sk.sobject,
+					PNS_PIPE_ENABLED_IND_UTID,
+					pn->pipe_handle, PNS_PIPE_ENABLED_IND);
+		} else
+			pipe_handler_send_req(sk, pn->remote_pep,
+					PNS_PIPE_ENABLE_UTID,
+					PNS_PEP_ENABLE_REQ, pn->pipe_handle,
+					GFP_KERNEL);
+
+		break;
+#endif
+
 	case PNS_PEP_RESET_REQ:
 		switch (hdr->state_after_reset) {
 		case PN_PIPE_DISABLE:
@@ -346,6 +697,27 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
 		pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
 		break;
 
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNS_PEP_DISABLE_RESP:
+		if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
+				(ph->pn_sobj == pn_obj(pn->remote_pep))) {
+			pn->pipe_state = PIPE_DISABLED;
+			pipe_handler_send_ind(sk, pn->remote_pep,
+					PNS_PIPE_DISABLED_IND_UTID,
+					pn->pipe_handle,
+					PNS_PIPE_DISABLED_IND);
+			pipe_handler_send_ind(sk, pn->pn_sk.sobject,
+					PNS_PIPE_DISABLED_IND_UTID,
+					pn->pipe_handle,
+					PNS_PIPE_DISABLED_IND);
+		} else
+			pipe_handler_send_req(sk, pn->remote_pep,
+					PNS_PIPE_DISABLE_UTID,
+					PNS_PEP_DISABLE_REQ, pn->pipe_handle,
+					GFP_KERNEL);
+		break;
+#endif
+
 	case PNS_PEP_CTRL_REQ:
 		if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
 			atomic_inc(&sk->sk_drops);
@@ -519,6 +891,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
 	newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
 	newpn->init_enable = enabled;
 	newpn->aligned = aligned;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	newpn->remote_pep = pn->remote_pep;
+#endif
 
 	BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
 	skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -781,6 +1156,10 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
 {
 	struct pep_sock *pn = pep_sk(sk);
 	int val = 0, err = 0;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	int remote_pep;
+	int pipe_handle;
+#endif
 
 	if (level != SOL_PNPIPE)
 		return -ENOPROTOOPT;
@@ -791,6 +1170,48 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
 
 	lock_sock(sk);
 	switch (optname) {
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNPIPE_CREATE:
+		if (val) {
+			if (pn->pipe_state > PIPE_IDLE) {
+				err = -EFAULT;
+				break;
+			}
+			remote_pep = val & 0xFFFF;
+			pipe_handle =  (val >> 16) & 0xFF;
+			pn->remote_pep = remote_pep;
+			err = pipe_handler_create_pipe(sk, pipe_handle,
+					PNPIPE_CREATE);
+			break;
+		}
+
+	case PNPIPE_ENABLE:
+		if (pn->pipe_state != PIPE_DISABLED) {
+			err = -EFAULT;
+			break;
+		}
+		err = pipe_handler_enable_pipe(sk, PNPIPE_ENABLE);
+		break;
+
+	case PNPIPE_DISABLE:
+		if (pn->pipe_state != PIPE_ENABLED) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = pipe_handler_enable_pipe(sk, PNPIPE_DISABLE);
+		break;
+
+	case PNPIPE_DESTROY:
+		if (pn->pipe_state < PIPE_DISABLED) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY);
+		break;
+#endif
+
 	case PNPIPE_ENCAP:
 		if (val && val != PNPIPE_ENCAP_IP) {
 			err = -EINVAL;
@@ -840,6 +1261,13 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
 	case PNPIPE_ENCAP:
 		val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
 		break;
+
+#ifdef CONFIG_PHONET_PIPECTRLR
+	case PNPIPE_INQ:
+		val = pn->pipe_state;
+		break;
+#endif
+
 	case PNPIPE_IFINDEX:
 		val = pn->ifindex;
 		break;
@@ -859,7 +1287,14 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
 {
 	struct pep_sock *pn = pep_sk(sk);
 	struct pnpipehdr *ph;
-	int err;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	struct sockaddr_pn spn = {
+		.spn_family = AF_PHONET,
+		.spn_resource = 0xD9,
+		.spn_dev = pn_dev(pn->remote_pep),
+		.spn_obj = pn_obj(pn->remote_pep),
+	};
+#endif
 
 	if (pn_flow_safe(pn->tx_fc) &&
 	    !atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -877,11 +1312,11 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
 	} else
 		ph->message_id = PNS_PIPE_DATA;
 	ph->pipe_handle = pn->pipe_handle;
-
-	err = pn_skb_send(sk, skb, &pipe_srv);
-	if (err && pn_flow_safe(pn->tx_fc))
-		atomic_inc(&pn->tx_credits);
-	return err;
+#ifdef CONFIG_PHONET_PIPECTRLR
+	return pn_skb_send(sk, skb, &spn);
+#else
+	return pn_skb_send(sk, skb, &pipe_srv);
+#endif
 }
 
 static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
-- 
1.7.2.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] Documentation: Update Phonet doc for Pipe Controller implementation
  2010-09-24 12:23 [PATCH 0/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems Kumar A Sanghvi
  2010-09-24 12:23 ` [PATCH 1/2] " Kumar A Sanghvi
@ 2010-09-24 12:23 ` Kumar A Sanghvi
  1 sibling, 0 replies; 5+ messages in thread
From: Kumar A Sanghvi @ 2010-09-24 12:23 UTC (permalink / raw)
  To: remi.denis-courmont, davem, netdev
  Cc: STEricsson_nomadik_linux, sudeep.divakaran, gulshan.karmani,
	Kumar Sanghvi, Linus Walleij

From: Kumar Sanghvi <kumar.sanghvi@stericsson.com>

Updates the Phonet document with description related to Pipe controller
implementation

Signed-off-by: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@stericsson.com>
---
 Documentation/networking/phonet.txt |   53 +++++++++++++++++++++++++++++++++++
 1 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt
index cf76608..cccf5ff 100644
--- a/Documentation/networking/phonet.txt
+++ b/Documentation/networking/phonet.txt
@@ -182,6 +182,59 @@ The pipe protocol provides two socket options at the SOL_PNPIPE level:
     or zero if encapsulation is off.
 
 
+Phonet Pipe-controller Implementation
+-------------------------------------
+
+Phonet Pipe-controller is enabled by selecting the CONFIG_PHONET_PIPECTRLR Kconfig
+option. It is useful when communicating with those Nokia Modems which do not
+implement Pipe controller in them e.g. Nokia Slim Modem used in ST-Ericsson
+U8500 platform.
+
+The implementation is based on the Data Connection Establishment Sequence
+depicted in 'Nokia Wireless Modem API - Wireless_modem_user_guide.pdf'
+document.
+
+It allows a phonet sequenced socket (host-pep) to initiate a Pipe connection
+between itself and a remote pipe-end point (e.g. modem).
+
+The implementation adds socket options at SOL_PNPIPE level:
+
+ PNPIPE_CREATE
+	It accepts an integer argument where-in
+		lower order 16 bits: pn_dev and pn_port pair for remote pep.
+		higher order 16 bits: 8 bit pipe-handle
+
+	It sends a PNS_PEP_CONNECT_REQ on sequenced socket itself. On getting
+	PNS_PEP_CONNECT_RESP, it sends PNS_PEP_CONNECT_REQ to remote pep. On
+	getting response from remote pep, it selects the best possible Flow
+	control mechanism supported by remote-pep (modem) and then it sends
+	PNS_PEP_CREATED_IND to the sequenced socket and to the remote pep.
+
+	It then updates the pipe state associated with the sequenced socket to
+	be PIPE_DISABLED.
+
+  PNPIPE_ENABLE
+	It follows the same sequence as above for enabling a pipe by sending
+	PNS_PEP_ENABLE_REQ initially and then sending PNS_PEP_ENABLED_IND after
+	getting responses from sequenced socket and remote-pep.
+	It will also update the pipe state associated with the sequenced socket
+	to PIPE_ENABLED.
+
+   PNPIPE_DESTROY
+	This will send out PNS_PEP_DISCONNECT_REQ on the sequenced socket and
+	the remote pep.
+	It will also update the pipe state associated with the sequenced socket
+	to PIPE_IDLE
+
+   PNPIPE_INQ
+	This getsocktopt allows the user-space running on the sequenced socket
+	to examine the pipe state associated with that socket ie. whether the
+	pipe is created (PIPE_DISABLED) or enabled (PIPE_ENABLED) or disabled
+	(PIPE_DISABLED) or no pipe exists (PIPE_IDLE).
+
+After a pipe has been created and enabled successfully, the Pipe data can be
+exchanged between the host-pep and remote-pep (modem).
+
 Authors
 -------
 
-- 
1.7.2.dirty


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems
  2010-09-24 12:23 ` [PATCH 1/2] " Kumar A Sanghvi
@ 2010-09-24 13:52   ` Eric Dumazet
  2010-09-24 14:20     ` Kumar SANGHVI
  0 siblings, 1 reply; 5+ messages in thread
From: Eric Dumazet @ 2010-09-24 13:52 UTC (permalink / raw)
  To: Kumar A Sanghvi
  Cc: remi.denis-courmont, davem, netdev, STEricsson_nomadik_linux,
	sudeep.divakaran, gulshan.karmani, Linus Walleij

Le vendredi 24 septembre 2010 à 17:53 +0530, Kumar A Sanghvi a écrit :

> +static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
> +		u8 *pref_rx_fc, u8 *req_tx_fc)
> +{
> +	struct pnpipehdr *hdr = pnp_hdr(skb);
> +	u8 n_sb;
> +
> +	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
> +		return -EINVAL;

This is wrong.

pskb_may_pull() might change skb->data, so you should do

{
	struct pnpipehdr *hdr;
	u8 n_sb;

	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
		return -EINVAL;

	hdr = pnp_hdr(skb);

...






^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems
  2010-09-24 13:52   ` Eric Dumazet
@ 2010-09-24 14:20     ` Kumar SANGHVI
  0 siblings, 0 replies; 5+ messages in thread
From: Kumar SANGHVI @ 2010-09-24 14:20 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: remi.denis-courmont@nokia.com, davem@davemloft.net,
	netdev@vger.kernel.org, STEricsson_nomadik_linux,
	Sudeep DIVAKARAN, Gulshan KARMANI, Linus WALLEIJ

Hi Eric,

On Fri, Sep 24, 2010 at 15:52:13 +0200, Eric Dumazet wrote:
> Le vendredi 24 septembre 2010 à 17:53 +0530, Kumar A Sanghvi a écrit :
> 
> > +static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
> > +		u8 *pref_rx_fc, u8 *req_tx_fc)
> > +{
> > +	struct pnpipehdr *hdr = pnp_hdr(skb);
> > +	u8 n_sb;
> > +
> > +	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
> > +		return -EINVAL;
> 
> This is wrong.
> 
> pskb_may_pull() might change skb->data, so you should do
> 
> {
> 	struct pnpipehdr *hdr;
> 	u8 n_sb;
> 
> 	if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
> 		return -EINVAL;
> 
> 	hdr = pnp_hdr(skb);
> 
Thanks for pointing this out.
I will correct this and post a v2 version of patch.

I will also post a fix for similar problem which now I noticed, based on
your above comment, in pipe_rcv_status function in net/phonet/pep.c

Best regards,
Kumar.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2010-09-24 14:21 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-09-24 12:23 [PATCH 0/2] Phonet: Implement Pipe Controller to support Nokia Slim Modems Kumar A Sanghvi
2010-09-24 12:23 ` [PATCH 1/2] " Kumar A Sanghvi
2010-09-24 13:52   ` Eric Dumazet
2010-09-24 14:20     ` Kumar SANGHVI
2010-09-24 12:23 ` [PATCH 2/2] Documentation: Update Phonet doc for Pipe Controller implementation Kumar A Sanghvi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).