aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKumar Sanghvi <kumar.sanghvi@stericsson.com>2010-09-26 15:07:59 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-28 00:30:41 -0400
commit8d98efa84b790bdd62248eb0dfff17e9baf5c844 (patch)
tree1bf9c2f58502a930963579d50f3bcd49e5a8ed70
parente40051d134f7ee95c8c1f7a3471e84eafc9ab326 (diff)
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 <kumar.sanghvi@stericsson.com> Acked-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/phonet.h5
-rw-r--r--include/net/phonet/pep.h21
-rw-r--r--net/phonet/Kconfig11
-rw-r--r--net/phonet/pep.c448
4 files changed, 479 insertions, 6 deletions
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 @@
36/* Socket options for SOL_PNPIPE level */ 36/* Socket options for SOL_PNPIPE level */
37#define PNPIPE_ENCAP 1 37#define PNPIPE_ENCAP 1
38#define PNPIPE_IFINDEX 2 38#define PNPIPE_IFINDEX 2
39#define PNPIPE_CREATE 3
40#define PNPIPE_ENABLE 4
41#define PNPIPE_DISABLE 5
42#define PNPIPE_DESTROY 6
43#define PNPIPE_INQ 7
39 44
40#define PNADDR_ANY 0 45#define PNADDR_ANY 0
41#define PNADDR_BROADCAST 0xFC 46#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 {
45 u8 tx_fc; /* TX flow control */ 45 u8 tx_fc; /* TX flow control */
46 u8 init_enable; /* auto-enable at creation */ 46 u8 init_enable; /* auto-enable at creation */
47 u8 aligned; 47 u8 aligned;
48#ifdef CONFIG_PHONET_PIPECTRLR
49 u16 remote_pep;
50 u8 pipe_state;
51#endif
48}; 52};
49 53
50static inline struct pep_sock *pep_sk(struct sock *sk) 54static inline struct pep_sock *pep_sk(struct sock *sk)
@@ -165,4 +169,21 @@ enum {
165 PEP_IND_READY, 169 PEP_IND_READY,
166}; 170};
167 171
172#ifdef CONFIG_PHONET_PIPECTRLR
173#define PNS_PEP_CONNECT_UTID 0x02
174#define PNS_PIPE_CREATED_IND_UTID 0x04
175#define PNS_PIPE_ENABLE_UTID 0x0A
176#define PNS_PIPE_ENABLED_IND_UTID 0x0C
177#define PNS_PIPE_DISABLE_UTID 0x0F
178#define PNS_PIPE_DISABLED_IND_UTID 0x11
179#define PNS_PEP_DISCONNECT_UTID 0x06
180
181/* Used for tracking state of a pipe */
182enum {
183 PIPE_IDLE,
184 PIPE_DISABLED,
185 PIPE_ENABLED,
186};
187#endif /* CONFIG_PHONET_PIPECTRLR */
188
168#endif 189#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
14 14
15 To compile this driver as a module, choose M here: the module 15 To compile this driver as a module, choose M here: the module
16 will be called phonet. If unsure, say N. 16 will be called phonet. If unsure, say N.
17
18config PHONET_PIPECTRLR
19 bool "Phonet Pipe Controller"
20 depends on PHONET
21 default N
22 help
23 The Pipe Controller implementation in Phonet stack to support Pipe
24 data with Nokia Slim modems like WG2.5 used on ST-Ericsson U8500
25 platform.
26
27 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,
88 const struct pnpipehdr *oph = pnp_hdr(oskb); 88 const struct pnpipehdr *oph = pnp_hdr(oskb);
89 struct pnpipehdr *ph; 89 struct pnpipehdr *ph;
90 struct sk_buff *skb; 90 struct sk_buff *skb;
91#ifdef CONFIG_PHONET_PIPECTRLR
92 const struct phonethdr *hdr = pn_hdr(oskb);
93 struct sockaddr_pn spn = {
94 .spn_family = AF_PHONET,
95 .spn_resource = 0xD9,
96 .spn_dev = hdr->pn_sdev,
97 .spn_obj = hdr->pn_sobj,
98 };
99#endif
91 100
92 skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); 101 skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
93 if (!skb) 102 if (!skb)
@@ -105,10 +114,271 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb,
105 ph->pipe_handle = oph->pipe_handle; 114 ph->pipe_handle = oph->pipe_handle;
106 ph->error_code = code; 115 ph->error_code = code;
107 116
117#ifdef CONFIG_PHONET_PIPECTRLR
118 return pn_skb_send(sk, skb, &spn);
119#else
108 return pn_skb_send(sk, skb, &pipe_srv); 120 return pn_skb_send(sk, skb, &pipe_srv);
121#endif
109} 122}
110 123
111#define PAD 0x00 124#define PAD 0x00
125
126#ifdef CONFIG_PHONET_PIPECTRLR
127static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len)
128{
129 int i, j;
130 u8 base_fc, final_fc;
131
132 for (i = 0; i < len; i++) {
133 base_fc = host_fc[i];
134 for (j = 0; j < len; j++) {
135 if (remote_fc[j] == base_fc) {
136 final_fc = base_fc;
137 goto done;
138 }
139 }
140 }
141 return -EINVAL;
142
143done:
144 return final_fc;
145
146}
147
148static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb,
149 u8 *pref_rx_fc, u8 *req_tx_fc)
150{
151 struct pnpipehdr *hdr;
152 u8 n_sb;
153
154 if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
155 return -EINVAL;
156
157 hdr = pnp_hdr(skb);
158 n_sb = hdr->data[4];
159
160 __skb_pull(skb, sizeof(*hdr) + 4);
161 while (n_sb > 0) {
162 u8 type, buf[3], len = sizeof(buf);
163 u8 *data = pep_get_sb(skb, &type, &len, buf);
164
165 if (data == NULL)
166 return -EINVAL;
167
168 switch (type) {
169 case PN_PIPE_SB_REQUIRED_FC_TX:
170 if (len < 3 || (data[2] | data[3] | data[4]) > 3)
171 break;
172 req_tx_fc[0] = data[2];
173 req_tx_fc[1] = data[3];
174 req_tx_fc[2] = data[4];
175 break;
176
177 case PN_PIPE_SB_PREFERRED_FC_RX:
178 if (len < 3 || (data[2] | data[3] | data[4]) > 3)
179 break;
180 pref_rx_fc[0] = data[2];
181 pref_rx_fc[1] = data[3];
182 pref_rx_fc[2] = data[4];
183 break;
184
185 }
186 n_sb--;
187 }
188 return 0;
189}
190
191static int pipe_handler_send_req(struct sock *sk, u16 dobj, u8 utid,
192 u8 msg_id, u8 p_handle, gfp_t priority)
193{
194 int len;
195 struct pnpipehdr *ph;
196 struct sk_buff *skb;
197 struct sockaddr_pn spn = {
198 .spn_family = AF_PHONET,
199 .spn_resource = 0xD9,
200 .spn_dev = pn_dev(dobj),
201 .spn_obj = pn_obj(dobj),
202 };
203
204 static const u8 data[4] = {
205 PAD, PAD, PAD, PAD,
206 };
207
208 switch (msg_id) {
209 case PNS_PEP_CONNECT_REQ:
210 len = sizeof(data);
211 break;
212
213 case PNS_PEP_DISCONNECT_REQ:
214 case PNS_PEP_ENABLE_REQ:
215 case PNS_PEP_DISABLE_REQ:
216 len = 0;
217 break;
218
219 default:
220 return -EINVAL;
221 }
222
223 skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
224 if (!skb)
225 return -ENOMEM;
226 skb_set_owner_w(skb, sk);
227
228 skb_reserve(skb, MAX_PNPIPE_HEADER);
229 if (len) {
230 __skb_put(skb, len);
231 skb_copy_to_linear_data(skb, data, len);
232 }
233 __skb_push(skb, sizeof(*ph));
234 skb_reset_transport_header(skb);
235 ph = pnp_hdr(skb);
236 ph->utid = utid;
237 ph->message_id = msg_id;
238 ph->pipe_handle = p_handle;
239 ph->error_code = PN_PIPE_NO_ERROR;
240
241 return pn_skb_send(sk, skb, &spn);
242}
243
244static int pipe_handler_send_created_ind(struct sock *sk, u16 dobj,
245 u8 utid, u8 p_handle, u8 msg_id, u8 tx_fc, u8 rx_fc)
246{
247 int err_code;
248 struct pnpipehdr *ph;
249 struct sk_buff *skb;
250 struct sockaddr_pn spn = {
251 .spn_family = AF_PHONET,
252 .spn_resource = 0xD9,
253 .spn_dev = pn_dev(dobj),
254 .spn_obj = pn_obj(dobj),
255 };
256
257 static u8 data[4] = {
258 0x03, 0x04,
259 };
260 data[2] = tx_fc;
261 data[3] = rx_fc;
262
263 /*
264 * actually, below is number of sub-blocks and not error code.
265 * Pipe_created_ind message format does not have any
266 * error code field. However, the Phonet stack will always send
267 * an error code as part of pnpipehdr. So, use that err_code to
268 * specify the number of sub-blocks.
269 */
270 err_code = 0x01;
271
272 skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC);
273 if (!skb)
274 return -ENOMEM;
275 skb_set_owner_w(skb, sk);
276
277 skb_reserve(skb, MAX_PNPIPE_HEADER);
278 __skb_put(skb, sizeof(data));
279 skb_copy_to_linear_data(skb, data, sizeof(data));
280 __skb_push(skb, sizeof(*ph));
281 skb_reset_transport_header(skb);
282 ph = pnp_hdr(skb);
283 ph->utid = utid;
284 ph->message_id = msg_id;
285 ph->pipe_handle = p_handle;
286 ph->error_code = err_code;
287
288 return pn_skb_send(sk, skb, &spn);
289}
290
291static int pipe_handler_send_ind(struct sock *sk, u16 dobj, u8 utid,
292 u8 p_handle, u8 msg_id)
293{
294 int err_code;
295 struct pnpipehdr *ph;
296 struct sk_buff *skb;
297 struct sockaddr_pn spn = {
298 .spn_family = AF_PHONET,
299 .spn_resource = 0xD9,
300 .spn_dev = pn_dev(dobj),
301 .spn_obj = pn_obj(dobj),
302 };
303
304 /*
305 * actually, below is a filler.
306 * Pipe_enabled/disabled_ind message format does not have any
307 * error code field. However, the Phonet stack will always send
308 * an error code as part of pnpipehdr. So, use that err_code to
309 * specify the filler value.
310 */
311 err_code = 0x0;
312
313 skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
314 if (!skb)
315 return -ENOMEM;
316 skb_set_owner_w(skb, sk);
317
318 skb_reserve(skb, MAX_PNPIPE_HEADER);
319 __skb_push(skb, sizeof(*ph));
320 skb_reset_transport_header(skb);
321 ph = pnp_hdr(skb);
322 ph->utid = utid;
323 ph->message_id = msg_id;
324 ph->pipe_handle = p_handle;
325 ph->error_code = err_code;
326
327 return pn_skb_send(sk, skb, &spn);
328}
329
330static int pipe_handler_enable_pipe(struct sock *sk, int cmd)
331{
332 int ret;
333 struct pep_sock *pn = pep_sk(sk);
334
335 switch (cmd) {
336 case PNPIPE_ENABLE:
337 ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
338 PNS_PIPE_ENABLE_UTID, PNS_PEP_ENABLE_REQ,
339 pn->pipe_handle, GFP_ATOMIC);
340 break;
341
342 case PNPIPE_DISABLE:
343 ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
344 PNS_PIPE_DISABLE_UTID, PNS_PEP_DISABLE_REQ,
345 pn->pipe_handle, GFP_ATOMIC);
346 break;
347
348 default:
349 ret = -EINVAL;
350 }
351
352 return ret;
353}
354
355static int pipe_handler_create_pipe(struct sock *sk, int pipe_handle, int cmd)
356{
357 int ret;
358 struct pep_sock *pn = pep_sk(sk);
359
360 switch (cmd) {
361 case PNPIPE_CREATE:
362 ret = pipe_handler_send_req(sk, pn->pn_sk.sobject,
363 PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ,
364 pipe_handle, GFP_ATOMIC);
365 break;
366
367 case PNPIPE_DESTROY:
368 ret = pipe_handler_send_req(sk, pn->remote_pep,
369 PNS_PEP_DISCONNECT_UTID,
370 PNS_PEP_DISCONNECT_REQ,
371 pn->pipe_handle, GFP_ATOMIC);
372 break;
373
374 default:
375 ret = -EINVAL;
376 }
377
378 return ret;
379}
380#endif
381
112static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) 382static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
113{ 383{
114 static const u8 data[20] = { 384 static const u8 data[20] = {
@@ -173,6 +443,14 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
173 struct pep_sock *pn = pep_sk(sk); 443 struct pep_sock *pn = pep_sk(sk);
174 struct pnpipehdr *ph; 444 struct pnpipehdr *ph;
175 struct sk_buff *skb; 445 struct sk_buff *skb;
446#ifdef CONFIG_PHONET_PIPECTRLR
447 struct sockaddr_pn spn = {
448 .spn_family = AF_PHONET,
449 .spn_resource = 0xD9,
450 .spn_dev = pn_dev(pn->remote_pep),
451 .spn_obj = pn_obj(pn->remote_pep),
452 };
453#endif
176 454
177 skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); 455 skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
178 if (!skb) 456 if (!skb)
@@ -192,7 +470,11 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
192 ph->data[3] = PAD; 470 ph->data[3] = PAD;
193 ph->data[4] = status; 471 ph->data[4] = status;
194 472
473#ifdef CONFIG_PHONET_PIPECTRLR
474 return pn_skb_send(sk, skb, &spn);
475#else
195 return pn_skb_send(sk, skb, &pipe_srv); 476 return pn_skb_send(sk, skb, &pipe_srv);
477#endif
196} 478}
197 479
198/* Send our RX flow control information to the sender. 480/* 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)
308 struct pnpipehdr *hdr = pnp_hdr(skb); 590 struct pnpipehdr *hdr = pnp_hdr(skb);
309 struct sk_buff_head *queue; 591 struct sk_buff_head *queue;
310 int err = 0; 592 int err = 0;
593#ifdef CONFIG_PHONET_PIPECTRLR
594 struct phonethdr *ph = pn_hdr(skb);
595 static u8 host_pref_rx_fc[3], host_req_tx_fc[3];
596 u8 remote_pref_rx_fc[3], remote_req_tx_fc[3];
597 u8 negotiated_rx_fc, negotiated_tx_fc;
598#endif
311 599
312 BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); 600 BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
313 601
@@ -316,6 +604,40 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
316 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 604 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
317 break; 605 break;
318 606
607#ifdef CONFIG_PHONET_PIPECTRLR
608 case PNS_PEP_CONNECT_RESP:
609 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
610 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
611 pipe_get_flow_info(sk, skb, remote_pref_rx_fc,
612 remote_req_tx_fc);
613
614 negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc,
615 host_pref_rx_fc,
616 sizeof(host_pref_rx_fc));
617 negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc,
618 remote_pref_rx_fc,
619 sizeof(host_pref_rx_fc));
620
621 pn->pipe_state = PIPE_DISABLED;
622 pipe_handler_send_created_ind(sk, pn->remote_pep,
623 PNS_PIPE_CREATED_IND_UTID,
624 pn->pipe_handle, PNS_PIPE_CREATED_IND,
625 negotiated_tx_fc, negotiated_rx_fc);
626 pipe_handler_send_created_ind(sk, pn->pn_sk.sobject,
627 PNS_PIPE_CREATED_IND_UTID,
628 pn->pipe_handle, PNS_PIPE_CREATED_IND,
629 negotiated_tx_fc, negotiated_rx_fc);
630 } else {
631 pipe_handler_send_req(sk, pn->remote_pep,
632 PNS_PEP_CONNECT_UTID,
633 PNS_PEP_CONNECT_REQ, pn->pipe_handle,
634 GFP_ATOMIC);
635 pipe_get_flow_info(sk, skb, host_pref_rx_fc,
636 host_req_tx_fc);
637 }
638 break;
639#endif
640
319 case PNS_PEP_DISCONNECT_REQ: 641 case PNS_PEP_DISCONNECT_REQ:
320 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 642 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
321 sk->sk_state = TCP_CLOSE_WAIT; 643 sk->sk_state = TCP_CLOSE_WAIT;
@@ -323,11 +645,41 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
323 sk->sk_state_change(sk); 645 sk->sk_state_change(sk);
324 break; 646 break;
325 647
648#ifdef CONFIG_PHONET_PIPECTRLR
649 case PNS_PEP_DISCONNECT_RESP:
650 pn->pipe_state = PIPE_IDLE;
651 pipe_handler_send_req(sk, pn->pn_sk.sobject,
652 PNS_PEP_DISCONNECT_UTID,
653 PNS_PEP_DISCONNECT_REQ, pn->pipe_handle,
654 GFP_KERNEL);
655 break;
656#endif
657
326 case PNS_PEP_ENABLE_REQ: 658 case PNS_PEP_ENABLE_REQ:
327 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 659 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
328 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 660 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
329 break; 661 break;
330 662
663#ifdef CONFIG_PHONET_PIPECTRLR
664 case PNS_PEP_ENABLE_RESP:
665 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
666 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
667 pn->pipe_state = PIPE_ENABLED;
668 pipe_handler_send_ind(sk, pn->remote_pep,
669 PNS_PIPE_ENABLED_IND_UTID,
670 pn->pipe_handle, PNS_PIPE_ENABLED_IND);
671 pipe_handler_send_ind(sk, pn->pn_sk.sobject,
672 PNS_PIPE_ENABLED_IND_UTID,
673 pn->pipe_handle, PNS_PIPE_ENABLED_IND);
674 } else
675 pipe_handler_send_req(sk, pn->remote_pep,
676 PNS_PIPE_ENABLE_UTID,
677 PNS_PEP_ENABLE_REQ, pn->pipe_handle,
678 GFP_KERNEL);
679
680 break;
681#endif
682
331 case PNS_PEP_RESET_REQ: 683 case PNS_PEP_RESET_REQ:
332 switch (hdr->state_after_reset) { 684 switch (hdr->state_after_reset) {
333 case PN_PIPE_DISABLE: 685 case PN_PIPE_DISABLE:
@@ -346,6 +698,27 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
346 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 698 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
347 break; 699 break;
348 700
701#ifdef CONFIG_PHONET_PIPECTRLR
702 case PNS_PEP_DISABLE_RESP:
703 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
704 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
705 pn->pipe_state = PIPE_DISABLED;
706 pipe_handler_send_ind(sk, pn->remote_pep,
707 PNS_PIPE_DISABLED_IND_UTID,
708 pn->pipe_handle,
709 PNS_PIPE_DISABLED_IND);
710 pipe_handler_send_ind(sk, pn->pn_sk.sobject,
711 PNS_PIPE_DISABLED_IND_UTID,
712 pn->pipe_handle,
713 PNS_PIPE_DISABLED_IND);
714 } else
715 pipe_handler_send_req(sk, pn->remote_pep,
716 PNS_PIPE_DISABLE_UTID,
717 PNS_PEP_DISABLE_REQ, pn->pipe_handle,
718 GFP_KERNEL);
719 break;
720#endif
721
349 case PNS_PEP_CTRL_REQ: 722 case PNS_PEP_CTRL_REQ:
350 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { 723 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
351 atomic_inc(&sk->sk_drops); 724 atomic_inc(&sk->sk_drops);
@@ -519,6 +892,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
519 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 892 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
520 newpn->init_enable = enabled; 893 newpn->init_enable = enabled;
521 newpn->aligned = aligned; 894 newpn->aligned = aligned;
895#ifdef CONFIG_PHONET_PIPECTRLR
896 newpn->remote_pep = pn->remote_pep;
897#endif
522 898
523 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); 899 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
524 skb_queue_head(&newsk->sk_receive_queue, skb); 900 skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -781,6 +1157,10 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
781{ 1157{
782 struct pep_sock *pn = pep_sk(sk); 1158 struct pep_sock *pn = pep_sk(sk);
783 int val = 0, err = 0; 1159 int val = 0, err = 0;
1160#ifdef CONFIG_PHONET_PIPECTRLR
1161 int remote_pep;
1162 int pipe_handle;
1163#endif
784 1164
785 if (level != SOL_PNPIPE) 1165 if (level != SOL_PNPIPE)
786 return -ENOPROTOOPT; 1166 return -ENOPROTOOPT;
@@ -791,6 +1171,48 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
791 1171
792 lock_sock(sk); 1172 lock_sock(sk);
793 switch (optname) { 1173 switch (optname) {
1174#ifdef CONFIG_PHONET_PIPECTRLR
1175 case PNPIPE_CREATE:
1176 if (val) {
1177 if (pn->pipe_state > PIPE_IDLE) {
1178 err = -EFAULT;
1179 break;
1180 }
1181 remote_pep = val & 0xFFFF;
1182 pipe_handle = (val >> 16) & 0xFF;
1183 pn->remote_pep = remote_pep;
1184 err = pipe_handler_create_pipe(sk, pipe_handle,
1185 PNPIPE_CREATE);
1186 break;
1187 }
1188
1189 case PNPIPE_ENABLE:
1190 if (pn->pipe_state != PIPE_DISABLED) {
1191 err = -EFAULT;
1192 break;
1193 }
1194 err = pipe_handler_enable_pipe(sk, PNPIPE_ENABLE);
1195 break;
1196
1197 case PNPIPE_DISABLE:
1198 if (pn->pipe_state != PIPE_ENABLED) {
1199 err = -EFAULT;
1200 break;
1201 }
1202
1203 err = pipe_handler_enable_pipe(sk, PNPIPE_DISABLE);
1204 break;
1205
1206 case PNPIPE_DESTROY:
1207 if (pn->pipe_state < PIPE_DISABLED) {
1208 err = -EFAULT;
1209 break;
1210 }
1211
1212 err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY);
1213 break;
1214#endif
1215
794 case PNPIPE_ENCAP: 1216 case PNPIPE_ENCAP:
795 if (val && val != PNPIPE_ENCAP_IP) { 1217 if (val && val != PNPIPE_ENCAP_IP) {
796 err = -EINVAL; 1218 err = -EINVAL;
@@ -840,6 +1262,13 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
840 case PNPIPE_ENCAP: 1262 case PNPIPE_ENCAP:
841 val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 1263 val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
842 break; 1264 break;
1265
1266#ifdef CONFIG_PHONET_PIPECTRLR
1267 case PNPIPE_INQ:
1268 val = pn->pipe_state;
1269 break;
1270#endif
1271
843 case PNPIPE_IFINDEX: 1272 case PNPIPE_IFINDEX:
844 val = pn->ifindex; 1273 val = pn->ifindex;
845 break; 1274 break;
@@ -859,7 +1288,14 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
859{ 1288{
860 struct pep_sock *pn = pep_sk(sk); 1289 struct pep_sock *pn = pep_sk(sk);
861 struct pnpipehdr *ph; 1290 struct pnpipehdr *ph;
862 int err; 1291#ifdef CONFIG_PHONET_PIPECTRLR
1292 struct sockaddr_pn spn = {
1293 .spn_family = AF_PHONET,
1294 .spn_resource = 0xD9,
1295 .spn_dev = pn_dev(pn->remote_pep),
1296 .spn_obj = pn_obj(pn->remote_pep),
1297 };
1298#endif
863 1299
864 if (pn_flow_safe(pn->tx_fc) && 1300 if (pn_flow_safe(pn->tx_fc) &&
865 !atomic_add_unless(&pn->tx_credits, -1, 0)) { 1301 !atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -877,11 +1313,11 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
877 } else 1313 } else
878 ph->message_id = PNS_PIPE_DATA; 1314 ph->message_id = PNS_PIPE_DATA;
879 ph->pipe_handle = pn->pipe_handle; 1315 ph->pipe_handle = pn->pipe_handle;
880 1316#ifdef CONFIG_PHONET_PIPECTRLR
881 err = pn_skb_send(sk, skb, &pipe_srv); 1317 return pn_skb_send(sk, skb, &spn);
882 if (err && pn_flow_safe(pn->tx_fc)) 1318#else
883 atomic_inc(&pn->tx_credits); 1319 return pn_skb_send(sk, skb, &pipe_srv);
884 return err; 1320#endif
885} 1321}
886 1322
887static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 1323static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,