Phonet: 'connect' socket implementation for Pipe controller

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 <kumar.sanghvi@stericsson.com>
Acked-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Kumar Sanghvi 2010-10-12 20:14:43 +00:00 committed by David S. Miller
parent 7368ddf144
commit b3d6255388
4 changed files with 215 additions and 191 deletions

View file

@ -36,10 +36,9 @@
/* Socket options for SOL_PNPIPE level */ /* Socket options for SOL_PNPIPE level */
#define PNPIPE_ENCAP 1 #define PNPIPE_ENCAP 1
#define PNPIPE_IFINDEX 2 #define PNPIPE_IFINDEX 2
#define PNPIPE_CREATE 3 #define PNPIPE_PIPE_HANDLE 3
#define PNPIPE_ENABLE 4 #define PNPIPE_ENABLE 4
/* unused slot */ /* unused slot */
#define PNPIPE_DESTROY 6
#define PNADDR_ANY 0 #define PNADDR_ANY 0
#define PNADDR_BROADCAST 0xFC #define PNADDR_BROADCAST 0xFC

View file

@ -46,8 +46,8 @@ struct pep_sock {
u8 init_enable; /* auto-enable at creation */ u8 init_enable; /* auto-enable at creation */
u8 aligned; u8 aligned;
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
u16 remote_pep; u8 pipe_state;
u8 pipe_state; struct sockaddr_pn remote_pep;
#endif #endif
}; };

View file

@ -88,15 +88,6 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
const struct pnpipehdr *oph = pnp_hdr(oskb); const struct pnpipehdr *oph = pnp_hdr(oskb);
struct pnpipehdr *ph; struct pnpipehdr *ph;
struct sk_buff *skb; 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); skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
if (!skb) if (!skb)
@ -114,11 +105,7 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
ph->pipe_handle = oph->pipe_handle; ph->pipe_handle = oph->pipe_handle;
ph->error_code = code; ph->error_code = code;
#ifdef CONFIG_PHONET_PIPECTRLR
return pn_skb_send(sk, skb, &spn);
#else
return pn_skb_send(sk, skb, &pipe_srv); return pn_skb_send(sk, skb, &pipe_srv);
#endif
} }
#define PAD 0x00 #define PAD 0x00
@ -188,18 +175,13 @@ static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
return 0; return 0;
} }
static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid, static int pipe_handler_send_req(struct sock *sk, u8 utid,
u8 msg_id, u8 p_handle, gfp_t priority) u8 msg_id, gfp_t priority)
{ {
int len; int len;
struct pnpipehdr *ph; struct pnpipehdr *ph;
struct sk_buff *skb; struct sk_buff *skb;
struct sockaddr_pn spn = { struct pep_sock *pn = pep_sk(sk);
.spn_family = AF_PHONET,
.spn_resource = 0xD9,
.spn_dev = pn_dev(dobj),
.spn_obj = pn_obj(dobj),
};
static const u8 data[4] = { static const u8 data[4] = {
PAD, PAD, PAD, PAD, 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 = pnp_hdr(skb);
ph->utid = utid; ph->utid = utid;
ph->message_id = msg_id; ph->message_id = msg_id;
ph->pipe_handle = p_handle; ph->pipe_handle = pn->pipe_handle;
ph->error_code = PN_PIPE_NO_ERROR; 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, static int pipe_handler_send_created_ind(struct sock *sk,
u8 utid, u8 p_handle, u8 msg_id, u8 tx_fc, u8 rx_fc) u8 utid, u8 msg_id)
{ {
int err_code; int err_code;
struct pnpipehdr *ph; struct pnpipehdr *ph;
struct sk_buff *skb; 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] = { static u8 data[4] = {
0x03, 0x04, 0x03, 0x04,
}; };
data[2] = tx_fc; data[2] = pn->tx_fc;
data[3] = rx_fc; data[3] = pn->rx_fc;
/* /*
* actually, below is number of sub-blocks and not error code. * 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 = pnp_hdr(skb);
ph->utid = utid; ph->utid = utid;
ph->message_id = msg_id; ph->message_id = msg_id;
ph->pipe_handle = p_handle; ph->pipe_handle = pn->pipe_handle;
ph->error_code = err_code; 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, static int pipe_handler_send_ind(struct sock *sk, u8 utid, u8 msg_id)
u8 p_handle, u8 msg_id)
{ {
int err_code; int err_code;
struct pnpipehdr *ph; struct pnpipehdr *ph;
struct sk_buff *skb; struct sk_buff *skb;
struct sockaddr_pn spn = { struct pep_sock *pn = pep_sk(sk);
.spn_family = AF_PHONET,
.spn_resource = 0xD9,
.spn_dev = pn_dev(dobj),
.spn_obj = pn_obj(dobj),
};
/* /*
* actually, below is a filler. * 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 = pnp_hdr(skb);
ph->utid = utid; ph->utid = utid;
ph->message_id = msg_id; ph->message_id = msg_id;
ph->pipe_handle = p_handle; ph->pipe_handle = pn->pipe_handle;
ph->error_code = err_code; 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) 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; utid = PNS_PIPE_DISABLE_UTID;
req = PNS_PEP_DISABLE_REQ; req = PNS_PEP_DISABLE_REQ;
} }
return pipe_handler_send_req(sk, pn->pn_sk.sobject, utid, req, return pipe_handler_send_req(sk, utid, req, GFP_ATOMIC);
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;
} }
#endif #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 pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph; struct pnpipehdr *ph;
struct sk_buff *skb; 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); skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
if (!skb) 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; ph->data[4] = status;
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
return pn_skb_send(sk, skb, &spn); return pn_skb_send(sk, skb, &pn->remote_pep);
#else #else
return pn_skb_send(sk, skb, &pipe_srv); return pn_skb_send(sk, skb, &pipe_srv);
#endif #endif
@ -582,12 +518,6 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
struct pnpipehdr *hdr = pnp_hdr(skb); struct pnpipehdr *hdr = pnp_hdr(skb);
struct sk_buff_head *queue; struct sk_buff_head *queue;
int err = 0; 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); 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); pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
break; 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: case PNS_PEP_DISCONNECT_REQ:
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
sk->sk_state = TCP_CLOSE_WAIT; 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 #ifdef CONFIG_PHONET_PIPECTRLR
case PNS_PEP_DISCONNECT_RESP: case PNS_PEP_DISCONNECT_RESP:
pn->pipe_state = PIPE_IDLE; pn->pipe_state = PIPE_IDLE;
pipe_handler_send_req(sk, pn->pn_sk.sobject, sk->sk_state = TCP_CLOSE;
PNS_PEP_DISCONNECT_UTID,
PNS_PEP_DISCONNECT_REQ, pn->pipe_handle,
GFP_KERNEL);
break; break;
#endif #endif
@ -654,21 +547,18 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
case PNS_PEP_ENABLE_RESP: case PNS_PEP_ENABLE_RESP:
if ((ph->pn_sdev == pn_dev(pn->remote_pep)) && pn->pipe_state = PIPE_ENABLED;
(ph->pn_sobj == pn_obj(pn->remote_pep))) { pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND_UTID,
pn->pipe_state = PIPE_ENABLED; PNS_PIPE_ENABLED_IND);
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);
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; break;
#endif #endif
@ -692,22 +582,12 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
case PNS_PEP_DISABLE_RESP: case PNS_PEP_DISABLE_RESP:
if ((ph->pn_sdev == pn_dev(pn->remote_pep)) && pn->pipe_state = PIPE_DISABLED;
(ph->pn_sobj == pn_obj(pn->remote_pep))) { atomic_set(&pn->tx_credits, 0);
pn->pipe_state = PIPE_DISABLED; pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND_UTID,
pipe_handler_send_ind(sk, pn->remote_pep, PNS_PIPE_DISABLED_IND);
PNS_PIPE_DISABLED_IND_UTID, sk->sk_state = TCP_SYN_RECV;
pn->pipe_handle, pn->rx_credits = 0;
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; break;
#endif #endif
@ -802,6 +682,42 @@ static void pipe_destruct(struct sock *sk)
skb_queue_purge(&pn->ctrlreq_queue); 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) static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
{ {
struct sock *newsk; 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->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
newpn->init_enable = enabled; newpn->init_enable = enabled;
newpn->aligned = aligned; newpn->aligned = aligned;
#ifdef CONFIG_PHONET_PIPECTRLR
newpn->remote_pep = pn->remote_pep;
#endif
BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
skb_queue_head(&newsk->sk_receive_queue, skb); 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); err = pep_connreq_rcv(sk, skb);
break; break;
#ifdef CONFIG_PHONET_PIPECTRLR
case PNS_PEP_CONNECT_RESP:
err = pep_connresp_rcv(sk, skb);
break;
#endif
case PNS_PEP_DISCONNECT_REQ: case PNS_PEP_DISCONNECT_REQ:
pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
break; break;
@ -1032,6 +951,18 @@ static void pep_sock_close(struct sock *sk, long timeout)
/* Forcefully remove dangling Phonet pipe */ /* Forcefully remove dangling Phonet pipe */
pipe_do_remove(sk); 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; ifindex = pn->ifindex;
pn->ifindex = 0; pn->ifindex = 0;
release_sock(sk); release_sock(sk);
@ -1108,6 +1039,20 @@ static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
return newsk; 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) static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
{ {
struct pep_sock *pn = pep_sk(sk); 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); struct pep_sock *pn = pep_sk(sk);
int val = 0, err = 0; int val = 0, err = 0;
#ifdef CONFIG_PHONET_PIPECTRLR
int remote_pep;
int pipe_handle;
#endif
if (level != SOL_PNPIPE) if (level != SOL_PNPIPE)
return -ENOPROTOOPT; return -ENOPROTOOPT;
@ -1164,28 +1105,15 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
lock_sock(sk); lock_sock(sk);
switch (optname) { switch (optname) {
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
case PNPIPE_CREATE: case PNPIPE_PIPE_HANDLE:
if (val) { if (val) {
if (pn->pipe_state > PIPE_IDLE) { if (pn->pipe_state > PIPE_IDLE) {
err = -EFAULT; err = -EFAULT;
break; break;
} }
remote_pep = val & 0xFFFF; pn->pipe_handle = val;
pipe_handle = (val >> 16) & 0xFF;
pn->remote_pep = remote_pep;
err = pipe_handler_create_pipe(sk, pipe_handle,
PNPIPE_CREATE);
break; break;
} }
case PNPIPE_DESTROY:
if (pn->pipe_state < PIPE_DISABLED) {
err = -EFAULT;
break;
}
err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY);
break;
#endif #endif
case PNPIPE_ENCAP: 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 pep_sock *pn = pep_sk(sk);
struct pnpipehdr *ph; struct pnpipehdr *ph;
int err; 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) && if (pn_flow_safe(pn->tx_fc) &&
!atomic_add_unless(&pn->tx_credits, -1, 0)) { !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->message_id = PNS_PIPE_DATA;
ph->pipe_handle = pn->pipe_handle; ph->pipe_handle = pn->pipe_handle;
#ifdef CONFIG_PHONET_PIPECTRLR #ifdef CONFIG_PHONET_PIPECTRLR
err = pn_skb_send(sk, skb, &spn); err = pn_skb_send(sk, skb, &pn->remote_pep);
#else #else
err = pn_skb_send(sk, skb, &pipe_srv); err = pn_skb_send(sk, skb, &pipe_srv);
#endif #endif
@ -1504,6 +1424,8 @@ static void pep_sock_unhash(struct sock *sk)
struct sock *skparent = NULL; struct sock *skparent = NULL;
lock_sock(sk); lock_sock(sk);
#ifndef CONFIG_PHONET_PIPECTRLR
if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
skparent = pn->listener; skparent = pn->listener;
release_sock(sk); release_sock(sk);
@ -1513,6 +1435,7 @@ static void pep_sock_unhash(struct sock *sk)
sk_del_node_init(sk); sk_del_node_init(sk);
sk = skparent; sk = skparent;
} }
#endif
/* Unhash a listening sock only when it is closed /* Unhash a listening sock only when it is closed
* and all of its active connected pipes are closed. */ * and all of its active connected pipes are closed. */
if (hlist_empty(&pn->hlist)) if (hlist_empty(&pn->hlist))
@ -1526,6 +1449,9 @@ static void pep_sock_unhash(struct sock *sk)
static struct proto pep_proto = { static struct proto pep_proto = {
.close = pep_sock_close, .close = pep_sock_close,
.accept = pep_sock_accept, .accept = pep_sock_accept,
#ifdef CONFIG_PHONET_PIPECTRLR
.connect = pep_sock_connect,
#endif
.ioctl = pep_ioctl, .ioctl = pep_ioctl,
.init = pep_init, .init = pep_init,
.setsockopt = pep_setsockopt, .setsockopt = pep_setsockopt,

View file

@ -225,6 +225,101 @@ static int pn_socket_autobind(struct socket *sock)
return 0; /* socket was already bound */ 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, static int pn_socket_accept(struct socket *sock, struct socket *newsock,
int flags) int flags)
{ {
@ -393,7 +488,11 @@ const struct proto_ops phonet_stream_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.release = pn_socket_release, .release = pn_socket_release,
.bind = pn_socket_bind, .bind = pn_socket_bind,
#ifdef CONFIG_PHONET_PIPECTRLR
.connect = pn_socket_connect,
#else
.connect = sock_no_connect, .connect = sock_no_connect,
#endif
.socketpair = sock_no_socketpair, .socketpair = sock_no_socketpair,
.accept = pn_socket_accept, .accept = pn_socket_accept,
.getname = pn_socket_getname, .getname = pn_socket_getname,