aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,