From 7417fa83c1a8b75a03bd9b9b358999f38e771eab Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Wed, 15 Sep 2010 12:30:12 +0000 Subject: Phonet: hook resource routing to userspace via ioctl()'s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I wish we could use something cleaner, such as bind(). But that would not work since resource subscription is orthogonal/in addition to the normal object ID allocated via bind(). This is similar to multicasting which also uses ioctl()'s. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/linux/phonet.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux/phonet.h') diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 76edadf046d3..85e14a83283b 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -47,6 +47,8 @@ /* ioctls */ #define SIOCPNGETOBJECT (SIOCPROTOPRIVATE + 0) +#define SIOCPNADDRESOURCE (SIOCPROTOPRIVATE + 14) +#define SIOCPNDELRESOURCE (SIOCPROTOPRIVATE + 15) /* Phonet protocol header */ struct phonethdr { -- cgit v1.2.3 From 8d98efa84b790bdd62248eb0dfff17e9baf5c844 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Sun, 26 Sep 2010 19:07:59 +0000 Subject: Phonet: Implement Pipe Controller to support Nokia Slim Modems 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 Acked-by: Linus Walleij Signed-off-by: David S. Miller --- include/linux/phonet.h | 5 + include/net/phonet/pep.h | 21 +++ net/phonet/Kconfig | 11 ++ net/phonet/pep.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 479 insertions(+), 6 deletions(-) (limited to 'include/linux/phonet.h') diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 85e14a83283b..96f5625d62fa 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 37f23dc05de8..def6cfa3f451 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 6ec7d55b1769..901956ada9c8 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 d0e7eb24c8b9..7bf23cf36b02 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,271 @@ 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; + u8 n_sb; + + if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) + return -EINVAL; + + hdr = pnp_hdr(skb); + 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 +443,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 +470,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 +590,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 +604,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 +645,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 +698,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 +892,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 +1157,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 +1171,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 +1262,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 +1288,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 +1313,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, -- cgit v1.2.3 From 03789f26722a15ccfe6f191e9fb3d356f2f18a1e Mon Sep 17 00:00:00 2001 From: Rémi Denis-Courmont Date: Fri, 8 Oct 2010 04:02:02 +0000 Subject: Phonet: cleanup pipe enable socket option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code works like this: int garbage, status; socklen_t len = sizeof(status); /* enable pipe */ setsockopt(fd, SOL_PNPIPE, PNPIPE_ENABLE, &garbage, sizeof(garbage)); /* disable pipe */ setsockopt(fd, SOL_PNPIPE, PNPIPE_DISABLE, &garbage, sizeof(garbage)); /* get status */ getsockopt(fd, SOL_PNPIPE, PNPIPE_INQ, &status, &len); ...which does not follow the usual socket option pattern. This patch merges all three "options" into a single gettable&settable option, before Linux 2.6.37 gets out: int status; socklen_t len = sizeof(status); /* enable pipe */ status = 1; setsockopt(fd, SOL_PNPIPE, PNPIPE_ENABLE, &status, sizeof(status)); /* disable pipe */ status = 0; setsockopt(fd, SOL_PNPIPE, PNPIPE_ENABLE, &status, sizeof(status)); /* get status */ getsockopt(fd, SOL_PNPIPE, PNPIPE_ENABLE, &status, &len); This also fixes the error code from EFAULT to ENOTCONN. Signed-off-by: Rémi Denis-Courmont Cc: Kumar Sanghvi Signed-off-by: David S. Miller --- Documentation/networking/phonet.txt | 15 ++------ include/linux/phonet.h | 3 +- net/phonet/pep.c | 72 ++++++++++++++++--------------------- 3 files changed, 34 insertions(+), 56 deletions(-) (limited to 'include/linux/phonet.h') diff --git a/Documentation/networking/phonet.txt b/Documentation/networking/phonet.txt index cccf5ff07ec2..2d9bc2b711fc 100644 --- a/Documentation/networking/phonet.txt +++ b/Documentation/networking/phonet.txt @@ -213,12 +213,9 @@ The implementation adds socket options at SOL_PNPIPE level: 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_ENABLE accepts one integer value (int). If set to zero, the pipe + is disabled. If the value is non-zero, the pipe is enabled. If the pipe + is not (yet) connected, ENOTCONN is error is returned. PNPIPE_DESTROY This will send out PNS_PEP_DISCONNECT_REQ on the sequenced socket and @@ -226,12 +223,6 @@ The implementation adds socket options at SOL_PNPIPE level: 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). diff --git a/include/linux/phonet.h b/include/linux/phonet.h index 96f5625d62fa..e27cbf931740 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -38,9 +38,8 @@ #define PNPIPE_IFINDEX 2 #define PNPIPE_CREATE 3 #define PNPIPE_ENABLE 4 -#define PNPIPE_DISABLE 5 +/* unused slot */ #define PNPIPE_DESTROY 6 -#define PNPIPE_INQ 7 #define PNADDR_ANY 0 #define PNADDR_BROADCAST 0xFC diff --git a/net/phonet/pep.c b/net/phonet/pep.c index aa3d8700d213..f818f76d297d 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -327,29 +327,20 @@ static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid, return pn_skb_send(sk, skb, &spn); } -static int pipe_handler_enable_pipe(struct sock *sk, int cmd) +static int pipe_handler_enable_pipe(struct sock *sk, int enable) { - 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; + int utid, req; + + if (enable) { + utid = PNS_PIPE_ENABLE_UTID; + req = PNS_PEP_ENABLE_REQ; + } else { + utid = PNS_PIPE_DISABLE_UTID; + req = PNS_PEP_DISABLE_REQ; } - - return ret; + return pipe_handler_send_req(sk, pn->pn_sk.sobject, utid, req, + pn->pipe_handle, GFP_ATOMIC); } static int pipe_handler_create_pipe(struct sock *sk, int pipe_handle, int cmd) @@ -1187,23 +1178,6 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, 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; @@ -1239,6 +1213,17 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, err = 0; } goto out_norel; + +#ifdef CONFIG_PHONET_PIPECTRLR + case PNPIPE_ENABLE: + if (pn->pipe_state <= PIPE_IDLE) { + err = -ENOTCONN; + break; + } + err = pipe_handler_enable_pipe(sk, val); + break; +#endif + default: err = -ENOPROTOOPT; } @@ -1264,15 +1249,18 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; break; + case PNPIPE_IFINDEX: + val = pn->ifindex; + break; + #ifdef CONFIG_PHONET_PIPECTRLR - case PNPIPE_INQ: - val = pn->pipe_state; + case PNPIPE_ENABLE: + if (pn->pipe_state <= PIPE_IDLE) + return -ENOTCONN; + val = pn->pipe_state != PIPE_DISABLED; break; #endif - case PNPIPE_IFINDEX: - val = pn->ifindex; - break; default: return -ENOPROTOOPT; } -- cgit v1.2.3 From b3d6255388de0680a14f0907deb7b7f4fa0d25d5 Mon Sep 17 00:00:00 2001 From: Kumar Sanghvi Date: Tue, 12 Oct 2010 20:14:43 +0000 Subject: Phonet: 'connect' socket implementation for Pipe controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on suggestion by Rémi Denis-Courmont to implement 'connect' for Pipe controller logic, this patch implements 'connect' socket call for the Pipe controller logic. The patch does following:- - Removes setsockopts for PNPIPE_CREATE and PNPIPE_DESTROY - Adds setsockopt for setting the Pipe handle value - Implements connect socket call - Updates the Pipe controller logic User-space should now follow below sequence with Pipe controller:- -socket -bind -setsockopt for PNPIPE_PIPE_HANDLE -connect -setsockopt for PNPIPE_ENCAP_IP -setsockopt for PNPIPE_ENABLE GPRS/3G data has been tested working fine with this. Signed-off-by: Kumar Sanghvi Acked-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- include/linux/phonet.h | 3 +- include/net/phonet/pep.h | 4 +- net/phonet/pep.c | 300 ++++++++++++++++++----------------------------- net/phonet/socket.c | 99 ++++++++++++++++ 4 files changed, 215 insertions(+), 191 deletions(-) (limited to 'include/linux/phonet.h') diff --git a/include/linux/phonet.h b/include/linux/phonet.h index e27cbf931740..26c8df786918 100644 --- a/include/linux/phonet.h +++ b/include/linux/phonet.h @@ -36,10 +36,9 @@ /* Socket options for SOL_PNPIPE level */ #define PNPIPE_ENCAP 1 #define PNPIPE_IFINDEX 2 -#define PNPIPE_CREATE 3 +#define PNPIPE_PIPE_HANDLE 3 #define PNPIPE_ENABLE 4 /* unused slot */ -#define PNPIPE_DESTROY 6 #define PNADDR_ANY 0 #define PNADDR_BROADCAST 0xFC diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index def6cfa3f451..b60b28c99e87 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h @@ -46,8 +46,8 @@ struct pep_sock { u8 init_enable; /* auto-enable at creation */ u8 aligned; #ifdef CONFIG_PHONET_PIPECTRLR - u16 remote_pep; - u8 pipe_state; + u8 pipe_state; + struct sockaddr_pn remote_pep; #endif }; diff --git a/net/phonet/pep.c b/net/phonet/pep.c index f818f76d297d..9c903f9e5079 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -88,15 +88,6 @@ 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) @@ -114,11 +105,7 @@ 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 @@ -188,18 +175,13 @@ static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb, return 0; } -static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid, - u8 msg_id, u8 p_handle, gfp_t priority) +static int pipe_handler_send_req(struct sock *sk, u8 utid, + u8 msg_id, 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), - }; + struct pep_sock *pn = pep_sk(sk); static const u8 data[4] = { PAD, PAD, PAD, PAD, @@ -235,30 +217,25 @@ static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid, ph = pnp_hdr(skb); ph->utid = utid; ph->message_id = msg_id; - ph->pipe_handle = p_handle; + ph->pipe_handle = pn->pipe_handle; ph->error_code = PN_PIPE_NO_ERROR; - return pn_skb_send(sk, skb, &spn); + return pn_skb_send(sk, skb, &pn->remote_pep); } -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) +static int pipe_handler_send_created_ind(struct sock *sk, + u8 utid, 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), - }; + struct pep_sock *pn = pep_sk(sk); static u8 data[4] = { 0x03, 0x04, }; - data[2] = tx_fc; - data[3] = rx_fc; + data[2] = pn->tx_fc; + data[3] = pn->rx_fc; /* * actually, below is number of sub-blocks and not error code. @@ -282,24 +259,18 @@ static int pipe_handler_send_created_ind(struct sock *sk, u16 dobj, ph = pnp_hdr(skb); ph->utid = utid; ph->message_id = msg_id; - ph->pipe_handle = p_handle; + ph->pipe_handle = pn->pipe_handle; ph->error_code = err_code; - return pn_skb_send(sk, skb, &spn); + return pn_skb_send(sk, skb, &pn->remote_pep); } -static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid, - u8 p_handle, u8 msg_id) +static int pipe_handler_send_ind(struct sock *sk, u8 utid, 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), - }; + struct pep_sock *pn = pep_sk(sk); /* * actually, below is a filler. @@ -321,10 +292,10 @@ static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid, ph = pnp_hdr(skb); ph->utid = utid; ph->message_id = msg_id; - ph->pipe_handle = p_handle; + ph->pipe_handle = pn->pipe_handle; ph->error_code = err_code; - return pn_skb_send(sk, skb, &spn); + return pn_skb_send(sk, skb, &pn->remote_pep); } static int pipe_handler_enable_pipe(struct sock *sk, int enable) @@ -339,34 +310,7 @@ static int pipe_handler_enable_pipe(struct sock *sk, int enable) utid = PNS_PIPE_DISABLE_UTID; req = PNS_PEP_DISABLE_REQ; } - return pipe_handler_send_req(sk, pn->pn_sk.sobject, utid, req, - pn->pipe_handle, GFP_ATOMIC); -} - -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; + return pipe_handler_send_req(sk, utid, req, GFP_ATOMIC); } #endif @@ -434,14 +378,6 @@ 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) @@ -462,7 +398,7 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) ph->data[4] = status; #ifdef CONFIG_PHONET_PIPECTRLR - return pn_skb_send(sk, skb, &spn); + return pn_skb_send(sk, skb, &pn->remote_pep); #else return pn_skb_send(sk, skb, &pipe_srv); #endif @@ -582,12 +518,6 @@ 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); @@ -596,40 +526,6 @@ 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; @@ -640,10 +536,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) #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); + sk->sk_state = TCP_CLOSE; break; #endif @@ -654,21 +547,18 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) #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); + pn->pipe_state = PIPE_ENABLED; + pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND_UTID, + PNS_PIPE_ENABLED_IND); + if (!pn_flow_safe(pn->tx_fc)) { + atomic_set(&pn->tx_credits, 1); + sk->sk_write_space(sk); + } + if (sk->sk_state == TCP_ESTABLISHED) + break; /* Nothing to do */ + sk->sk_state = TCP_ESTABLISHED; + pipe_grant_credits(sk); break; #endif @@ -692,22 +582,12 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) #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); + pn->pipe_state = PIPE_DISABLED; + atomic_set(&pn->tx_credits, 0); + pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND_UTID, + PNS_PIPE_DISABLED_IND); + sk->sk_state = TCP_SYN_RECV; + pn->rx_credits = 0; break; #endif @@ -802,6 +682,42 @@ static void pipe_destruct(struct sock *sk) skb_queue_purge(&pn->ctrlreq_queue); } +#ifdef CONFIG_PHONET_PIPECTRLR +static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) +{ + struct pep_sock *pn = pep_sk(sk); + u8 host_pref_rx_fc[3] = {3, 2, 1}, host_req_tx_fc[3] = {3, 2, 1}; + u8 remote_pref_rx_fc[3], remote_req_tx_fc[3]; + u8 negotiated_rx_fc, negotiated_tx_fc; + int ret; + + 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; + sk->sk_state = TCP_SYN_RECV; + sk->sk_backlog_rcv = pipe_do_rcv; + sk->sk_destruct = pipe_destruct; + pn->rx_credits = 0; + pn->rx_fc = negotiated_rx_fc; + pn->tx_fc = negotiated_tx_fc; + sk->sk_state_change(sk); + + ret = pipe_handler_send_created_ind(sk, + PNS_PIPE_CREATED_IND_UTID, + PNS_PIPE_CREATED_IND + ); + + return ret; +} +#endif + static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) { struct sock *newsk; @@ -884,9 +800,6 @@ 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); @@ -968,6 +881,12 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) err = pep_connreq_rcv(sk, skb); break; +#ifdef CONFIG_PHONET_PIPECTRLR + case PNS_PEP_CONNECT_RESP: + err = pep_connresp_rcv(sk, skb); + break; +#endif + case PNS_PEP_DISCONNECT_REQ: pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); break; @@ -1032,6 +951,18 @@ static void pep_sock_close(struct sock *sk, long timeout) /* Forcefully remove dangling Phonet pipe */ pipe_do_remove(sk); +#ifdef CONFIG_PHONET_PIPECTRLR + if (pn->pipe_state != PIPE_IDLE) { + /* send pep disconnect request */ + pipe_handler_send_req(sk, + PNS_PEP_DISCONNECT_UTID, PNS_PEP_DISCONNECT_REQ, + GFP_KERNEL); + + pn->pipe_state = PIPE_IDLE; + sk->sk_state = TCP_CLOSE; + } +#endif + ifindex = pn->ifindex; pn->ifindex = 0; release_sock(sk); @@ -1108,6 +1039,20 @@ out: return newsk; } +#ifdef CONFIG_PHONET_PIPECTRLR +static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) +{ + struct pep_sock *pn = pep_sk(sk); + struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; + + memcpy(&pn->remote_pep, spn, sizeof(struct sockaddr_pn)); + + return pipe_handler_send_req(sk, + PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ, + GFP_ATOMIC); +} +#endif + static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) { struct pep_sock *pn = pep_sk(sk); @@ -1149,10 +1094,6 @@ 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; @@ -1164,28 +1105,15 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, lock_sock(sk); switch (optname) { #ifdef CONFIG_PHONET_PIPECTRLR - case PNPIPE_CREATE: + case PNPIPE_PIPE_HANDLE: 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_DESTROY: - if (pn->pipe_state < PIPE_DISABLED) { - err = -EFAULT; + pn->pipe_handle = val; break; } - - err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY); - break; #endif case PNPIPE_ENCAP: @@ -1278,14 +1206,6 @@ 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)) { @@ -1304,7 +1224,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) ph->message_id = PNS_PIPE_DATA; ph->pipe_handle = pn->pipe_handle; #ifdef CONFIG_PHONET_PIPECTRLR - err = pn_skb_send(sk, skb, &spn); + err = pn_skb_send(sk, skb, &pn->remote_pep); #else err = pn_skb_send(sk, skb, &pipe_srv); #endif @@ -1504,6 +1424,8 @@ static void pep_sock_unhash(struct sock *sk) struct sock *skparent = NULL; lock_sock(sk); + +#ifndef CONFIG_PHONET_PIPECTRLR if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { skparent = pn->listener; release_sock(sk); @@ -1513,6 +1435,7 @@ static void pep_sock_unhash(struct sock *sk) sk_del_node_init(sk); sk = skparent; } +#endif /* Unhash a listening sock only when it is closed * and all of its active connected pipes are closed. */ if (hlist_empty(&pn->hlist)) @@ -1526,6 +1449,9 @@ static void pep_sock_unhash(struct sock *sk) static struct proto pep_proto = { .close = pep_sock_close, .accept = pep_sock_accept, +#ifdef CONFIG_PHONET_PIPECTRLR + .connect = pep_sock_connect, +#endif .ioctl = pep_ioctl, .init = pep_init, .setsockopt = pep_setsockopt, diff --git a/net/phonet/socket.c b/net/phonet/socket.c index aca8fba099e9..25f746d20c1f 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -225,6 +225,101 @@ static int pn_socket_autobind(struct socket *sock) return 0; /* socket was already bound */ } +#ifdef CONFIG_PHONET_PIPECTRLR +static int pn_socket_connect(struct socket *sock, struct sockaddr *addr, + int len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; + long timeo; + int err; + + if (len < sizeof(struct sockaddr_pn)) + return -EINVAL; + if (spn->spn_family != AF_PHONET) + return -EAFNOSUPPORT; + + lock_sock(sk); + + switch (sock->state) { + case SS_UNCONNECTED: + sk->sk_state = TCP_CLOSE; + break; + case SS_CONNECTING: + switch (sk->sk_state) { + case TCP_SYN_RECV: + sock->state = SS_CONNECTED; + err = -EISCONN; + goto out; + case TCP_CLOSE: + err = -EALREADY; + if (flags & O_NONBLOCK) + goto out; + goto wait_connect; + } + break; + case SS_CONNECTED: + switch (sk->sk_state) { + case TCP_SYN_RECV: + err = -EISCONN; + goto out; + case TCP_CLOSE: + sock->state = SS_UNCONNECTED; + break; + } + break; + case SS_DISCONNECTING: + case SS_FREE: + break; + } + sk->sk_state = TCP_CLOSE; + sk_stream_kill_queues(sk); + + sock->state = SS_CONNECTING; + err = sk->sk_prot->connect(sk, addr, len); + if (err < 0) { + sock->state = SS_UNCONNECTED; + sk->sk_state = TCP_CLOSE; + goto out; + } + + err = -EINPROGRESS; +wait_connect: + if (sk->sk_state != TCP_SYN_RECV && (flags & O_NONBLOCK)) + goto out; + + timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); + release_sock(sk); + + err = -ERESTARTSYS; + timeo = wait_event_interruptible_timeout(*sk_sleep(sk), + sk->sk_state != TCP_CLOSE, + timeo); + + lock_sock(sk); + if (timeo < 0) + goto out; /* -ERESTARTSYS */ + + err = -ETIMEDOUT; + if (timeo == 0 && sk->sk_state != TCP_SYN_RECV) + goto out; + + if (sk->sk_state != TCP_SYN_RECV) { + sock->state = SS_UNCONNECTED; + err = sock_error(sk); + if (!err) + err = -ECONNREFUSED; + goto out; + } + sock->state = SS_CONNECTED; + err = 0; + +out: + release_sock(sk); + return err; +} +#endif + static int pn_socket_accept(struct socket *sock, struct socket *newsock, int flags) { @@ -393,7 +488,11 @@ const struct proto_ops phonet_stream_ops = { .owner = THIS_MODULE, .release = pn_socket_release, .bind = pn_socket_bind, +#ifdef CONFIG_PHONET_PIPECTRLR + .connect = pn_socket_connect, +#else .connect = sock_no_connect, +#endif .socketpair = sock_no_socketpair, .accept = pn_socket_accept, .getname = pn_socket_getname, -- cgit v1.2.3