aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet')
-rw-r--r--net/phonet/Kconfig11
-rw-r--r--net/phonet/af_phonet.c17
-rw-r--r--net/phonet/datagram.c13
-rw-r--r--net/phonet/pep.c477
-rw-r--r--net/phonet/pn_dev.c5
-rw-r--r--net/phonet/socket.c190
6 files changed, 707 insertions, 6 deletions
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/af_phonet.c b/net/phonet/af_phonet.c
index 73aee7f2fcdc..fd95beb72f5d 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -251,6 +251,16 @@ int pn_skb_send(struct sock *sk, struct sk_buff *skb,
251 else if (phonet_address_lookup(net, daddr) == 0) { 251 else if (phonet_address_lookup(net, daddr) == 0) {
252 dev = phonet_device_get(net); 252 dev = phonet_device_get(net);
253 skb->pkt_type = PACKET_LOOPBACK; 253 skb->pkt_type = PACKET_LOOPBACK;
254 } else if (pn_sockaddr_get_object(target) == 0) {
255 /* Resource routing (small race until phonet_rcv()) */
256 struct sock *sk = pn_find_sock_by_res(net,
257 target->spn_resource);
258 if (sk) {
259 sock_put(sk);
260 dev = phonet_device_get(net);
261 skb->pkt_type = PACKET_LOOPBACK;
262 } else
263 dev = phonet_route_output(net, daddr);
254 } else 264 } else
255 dev = phonet_route_output(net, daddr); 265 dev = phonet_route_output(net, daddr);
256 266
@@ -383,6 +393,13 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
383 goto out; 393 goto out;
384 } 394 }
385 395
396 /* resource routing */
397 if (pn_sockaddr_get_object(&sa) == 0) {
398 struct sock *sk = pn_find_sock_by_res(net, sa.spn_resource);
399 if (sk)
400 return sk_receive_skb(sk, skb, 0);
401 }
402
386 /* check if we are the destination */ 403 /* check if we are the destination */
387 if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) { 404 if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
388 /* Phonet packet input */ 405 /* Phonet packet input */
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
index 1bd38db4fe1e..2f032381bd45 100644
--- a/net/phonet/datagram.c
+++ b/net/phonet/datagram.c
@@ -52,6 +52,19 @@ static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
52 answ = skb ? skb->len : 0; 52 answ = skb ? skb->len : 0;
53 release_sock(sk); 53 release_sock(sk);
54 return put_user(answ, (int __user *)arg); 54 return put_user(answ, (int __user *)arg);
55
56 case SIOCPNADDRESOURCE:
57 case SIOCPNDELRESOURCE: {
58 u32 res;
59 if (get_user(res, (u32 __user *)arg))
60 return -EFAULT;
61 if (res >= 256)
62 return -EINVAL;
63 if (cmd == SIOCPNADDRESOURCE)
64 return pn_sock_bind_res(sk, res);
65 else
66 return pn_sock_unbind_res(sk, res);
67 }
55 } 68 }
56 69
57 return -ENOIOCTLCMD; 70 return -ENOIOCTLCMD;
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 15003021f4f0..aa3d8700d213 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.
@@ -309,6 +591,12 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
309 struct pnpipehdr *hdr = pnp_hdr(skb); 591 struct pnpipehdr *hdr = pnp_hdr(skb);
310 struct sk_buff_head *queue; 592 struct sk_buff_head *queue;
311 int err = 0; 593 int err = 0;
594#ifdef CONFIG_PHONET_PIPECTRLR
595 struct phonethdr *ph = pn_hdr(skb);
596 static u8 host_pref_rx_fc[3], host_req_tx_fc[3];
597 u8 remote_pref_rx_fc[3], remote_req_tx_fc[3];
598 u8 negotiated_rx_fc, negotiated_tx_fc;
599#endif
312 600
313 BUG_ON(sk->sk_state == TCP_CLOSE_WAIT); 601 BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
314 602
@@ -317,6 +605,40 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
317 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); 605 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
318 break; 606 break;
319 607
608#ifdef CONFIG_PHONET_PIPECTRLR
609 case PNS_PEP_CONNECT_RESP:
610 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
611 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
612 pipe_get_flow_info(sk, skb, remote_pref_rx_fc,
613 remote_req_tx_fc);
614
615 negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc,
616 host_pref_rx_fc,
617 sizeof(host_pref_rx_fc));
618 negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc,
619 remote_pref_rx_fc,
620 sizeof(host_pref_rx_fc));
621
622 pn->pipe_state = PIPE_DISABLED;
623 pipe_handler_send_created_ind(sk, pn->remote_pep,
624 PNS_PIPE_CREATED_IND_UTID,
625 pn->pipe_handle, PNS_PIPE_CREATED_IND,
626 negotiated_tx_fc, negotiated_rx_fc);
627 pipe_handler_send_created_ind(sk, pn->pn_sk.sobject,
628 PNS_PIPE_CREATED_IND_UTID,
629 pn->pipe_handle, PNS_PIPE_CREATED_IND,
630 negotiated_tx_fc, negotiated_rx_fc);
631 } else {
632 pipe_handler_send_req(sk, pn->remote_pep,
633 PNS_PEP_CONNECT_UTID,
634 PNS_PEP_CONNECT_REQ, pn->pipe_handle,
635 GFP_ATOMIC);
636 pipe_get_flow_info(sk, skb, host_pref_rx_fc,
637 host_req_tx_fc);
638 }
639 break;
640#endif
641
320 case PNS_PEP_DISCONNECT_REQ: 642 case PNS_PEP_DISCONNECT_REQ:
321 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 643 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
322 sk->sk_state = TCP_CLOSE_WAIT; 644 sk->sk_state = TCP_CLOSE_WAIT;
@@ -324,11 +646,41 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
324 sk->sk_state_change(sk); 646 sk->sk_state_change(sk);
325 break; 647 break;
326 648
649#ifdef CONFIG_PHONET_PIPECTRLR
650 case PNS_PEP_DISCONNECT_RESP:
651 pn->pipe_state = PIPE_IDLE;
652 pipe_handler_send_req(sk, pn->pn_sk.sobject,
653 PNS_PEP_DISCONNECT_UTID,
654 PNS_PEP_DISCONNECT_REQ, pn->pipe_handle,
655 GFP_KERNEL);
656 break;
657#endif
658
327 case PNS_PEP_ENABLE_REQ: 659 case PNS_PEP_ENABLE_REQ:
328 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ 660 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
329 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 661 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
330 break; 662 break;
331 663
664#ifdef CONFIG_PHONET_PIPECTRLR
665 case PNS_PEP_ENABLE_RESP:
666 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
667 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
668 pn->pipe_state = PIPE_ENABLED;
669 pipe_handler_send_ind(sk, pn->remote_pep,
670 PNS_PIPE_ENABLED_IND_UTID,
671 pn->pipe_handle, PNS_PIPE_ENABLED_IND);
672 pipe_handler_send_ind(sk, pn->pn_sk.sobject,
673 PNS_PIPE_ENABLED_IND_UTID,
674 pn->pipe_handle, PNS_PIPE_ENABLED_IND);
675 } else
676 pipe_handler_send_req(sk, pn->remote_pep,
677 PNS_PIPE_ENABLE_UTID,
678 PNS_PEP_ENABLE_REQ, pn->pipe_handle,
679 GFP_KERNEL);
680
681 break;
682#endif
683
332 case PNS_PEP_RESET_REQ: 684 case PNS_PEP_RESET_REQ:
333 switch (hdr->state_after_reset) { 685 switch (hdr->state_after_reset) {
334 case PN_PIPE_DISABLE: 686 case PN_PIPE_DISABLE:
@@ -347,6 +699,27 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
347 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); 699 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
348 break; 700 break;
349 701
702#ifdef CONFIG_PHONET_PIPECTRLR
703 case PNS_PEP_DISABLE_RESP:
704 if ((ph->pn_sdev == pn_dev(pn->remote_pep)) &&
705 (ph->pn_sobj == pn_obj(pn->remote_pep))) {
706 pn->pipe_state = PIPE_DISABLED;
707 pipe_handler_send_ind(sk, pn->remote_pep,
708 PNS_PIPE_DISABLED_IND_UTID,
709 pn->pipe_handle,
710 PNS_PIPE_DISABLED_IND);
711 pipe_handler_send_ind(sk, pn->pn_sk.sobject,
712 PNS_PIPE_DISABLED_IND_UTID,
713 pn->pipe_handle,
714 PNS_PIPE_DISABLED_IND);
715 } else
716 pipe_handler_send_req(sk, pn->remote_pep,
717 PNS_PIPE_DISABLE_UTID,
718 PNS_PEP_DISABLE_REQ, pn->pipe_handle,
719 GFP_KERNEL);
720 break;
721#endif
722
350 case PNS_PEP_CTRL_REQ: 723 case PNS_PEP_CTRL_REQ:
351 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { 724 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) {
352 atomic_inc(&sk->sk_drops); 725 atomic_inc(&sk->sk_drops);
@@ -520,6 +893,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
520 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; 893 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
521 newpn->init_enable = enabled; 894 newpn->init_enable = enabled;
522 newpn->aligned = aligned; 895 newpn->aligned = aligned;
896#ifdef CONFIG_PHONET_PIPECTRLR
897 newpn->remote_pep = pn->remote_pep;
898#endif
523 899
524 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); 900 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
525 skb_queue_head(&newsk->sk_receive_queue, skb); 901 skb_queue_head(&newsk->sk_receive_queue, skb);
@@ -621,6 +997,28 @@ drop:
621 return err; 997 return err;
622} 998}
623 999
1000static int pipe_do_remove(struct sock *sk)
1001{
1002 struct pep_sock *pn = pep_sk(sk);
1003 struct pnpipehdr *ph;
1004 struct sk_buff *skb;
1005
1006 skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_KERNEL);
1007 if (!skb)
1008 return -ENOMEM;
1009
1010 skb_reserve(skb, MAX_PNPIPE_HEADER);
1011 __skb_push(skb, sizeof(*ph));
1012 skb_reset_transport_header(skb);
1013 ph = pnp_hdr(skb);
1014 ph->utid = 0;
1015 ph->message_id = PNS_PIPE_REMOVE_REQ;
1016 ph->pipe_handle = pn->pipe_handle;
1017 ph->data[0] = PAD;
1018
1019 return pn_skb_send(sk, skb, &pipe_srv);
1020}
1021
624/* associated socket ceases to exist */ 1022/* associated socket ceases to exist */
625static void pep_sock_close(struct sock *sk, long timeout) 1023static void pep_sock_close(struct sock *sk, long timeout)
626{ 1024{
@@ -639,7 +1037,10 @@ static void pep_sock_close(struct sock *sk, long timeout)
639 sk_for_each_safe(sknode, p, n, &pn->ackq) 1037 sk_for_each_safe(sknode, p, n, &pn->ackq)
640 sk_del_node_init(sknode); 1038 sk_del_node_init(sknode);
641 sk->sk_state = TCP_CLOSE; 1039 sk->sk_state = TCP_CLOSE;
642 } 1040 } else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED))
1041 /* Forcefully remove dangling Phonet pipe */
1042 pipe_do_remove(sk);
1043
643 ifindex = pn->ifindex; 1044 ifindex = pn->ifindex;
644 pn->ifindex = 0; 1045 pn->ifindex = 0;
645 release_sock(sk); 1046 release_sock(sk);
@@ -757,6 +1158,10 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
757{ 1158{
758 struct pep_sock *pn = pep_sk(sk); 1159 struct pep_sock *pn = pep_sk(sk);
759 int val = 0, err = 0; 1160 int val = 0, err = 0;
1161#ifdef CONFIG_PHONET_PIPECTRLR
1162 int remote_pep;
1163 int pipe_handle;
1164#endif
760 1165
761 if (level != SOL_PNPIPE) 1166 if (level != SOL_PNPIPE)
762 return -ENOPROTOOPT; 1167 return -ENOPROTOOPT;
@@ -767,6 +1172,48 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
767 1172
768 lock_sock(sk); 1173 lock_sock(sk);
769 switch (optname) { 1174 switch (optname) {
1175#ifdef CONFIG_PHONET_PIPECTRLR
1176 case PNPIPE_CREATE:
1177 if (val) {
1178 if (pn->pipe_state > PIPE_IDLE) {
1179 err = -EFAULT;
1180 break;
1181 }
1182 remote_pep = val & 0xFFFF;
1183 pipe_handle = (val >> 16) & 0xFF;
1184 pn->remote_pep = remote_pep;
1185 err = pipe_handler_create_pipe(sk, pipe_handle,
1186 PNPIPE_CREATE);
1187 break;
1188 }
1189
1190 case PNPIPE_ENABLE:
1191 if (pn->pipe_state != PIPE_DISABLED) {
1192 err = -EFAULT;
1193 break;
1194 }
1195 err = pipe_handler_enable_pipe(sk, PNPIPE_ENABLE);
1196 break;
1197
1198 case PNPIPE_DISABLE:
1199 if (pn->pipe_state != PIPE_ENABLED) {
1200 err = -EFAULT;
1201 break;
1202 }
1203
1204 err = pipe_handler_enable_pipe(sk, PNPIPE_DISABLE);
1205 break;
1206
1207 case PNPIPE_DESTROY:
1208 if (pn->pipe_state < PIPE_DISABLED) {
1209 err = -EFAULT;
1210 break;
1211 }
1212
1213 err = pipe_handler_create_pipe(sk, 0x0, PNPIPE_DESTROY);
1214 break;
1215#endif
1216
770 case PNPIPE_ENCAP: 1217 case PNPIPE_ENCAP:
771 if (val && val != PNPIPE_ENCAP_IP) { 1218 if (val && val != PNPIPE_ENCAP_IP) {
772 err = -EINVAL; 1219 err = -EINVAL;
@@ -816,6 +1263,13 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
816 case PNPIPE_ENCAP: 1263 case PNPIPE_ENCAP:
817 val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; 1264 val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
818 break; 1265 break;
1266
1267#ifdef CONFIG_PHONET_PIPECTRLR
1268 case PNPIPE_INQ:
1269 val = pn->pipe_state;
1270 break;
1271#endif
1272
819 case PNPIPE_IFINDEX: 1273 case PNPIPE_IFINDEX:
820 val = pn->ifindex; 1274 val = pn->ifindex;
821 break; 1275 break;
@@ -835,6 +1289,15 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
835{ 1289{
836 struct pep_sock *pn = pep_sk(sk); 1290 struct pep_sock *pn = pep_sk(sk);
837 struct pnpipehdr *ph; 1291 struct pnpipehdr *ph;
1292 int err;
1293#ifdef CONFIG_PHONET_PIPECTRLR
1294 struct sockaddr_pn spn = {
1295 .spn_family = AF_PHONET,
1296 .spn_resource = 0xD9,
1297 .spn_dev = pn_dev(pn->remote_pep),
1298 .spn_obj = pn_obj(pn->remote_pep),
1299 };
1300#endif
838 1301
839 if (pn_flow_safe(pn->tx_fc) && 1302 if (pn_flow_safe(pn->tx_fc) &&
840 !atomic_add_unless(&pn->tx_credits, -1, 0)) { 1303 !atomic_add_unless(&pn->tx_credits, -1, 0)) {
@@ -852,8 +1315,16 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
852 } else 1315 } else
853 ph->message_id = PNS_PIPE_DATA; 1316 ph->message_id = PNS_PIPE_DATA;
854 ph->pipe_handle = pn->pipe_handle; 1317 ph->pipe_handle = pn->pipe_handle;
1318#ifdef CONFIG_PHONET_PIPECTRLR
1319 err = pn_skb_send(sk, skb, &spn);
1320#else
1321 err = pn_skb_send(sk, skb, &pipe_srv);
1322#endif
1323
1324 if (err && pn_flow_safe(pn->tx_fc))
1325 atomic_inc(&pn->tx_credits);
1326 return err;
855 1327
856 return pn_skb_send(sk, skb, &pipe_srv);
857} 1328}
858 1329
859static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, 1330static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -873,7 +1344,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
873 skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, 1344 skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
874 flags & MSG_DONTWAIT, &err); 1345 flags & MSG_DONTWAIT, &err);
875 if (!skb) 1346 if (!skb)
876 return -ENOBUFS; 1347 return err;
877 1348
878 skb_reserve(skb, MAX_PHONET_HEADER + 3); 1349 skb_reserve(skb, MAX_PHONET_HEADER + 3);
879 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); 1350 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
index b18e48fae975..947038ddd04c 100644
--- a/net/phonet/pn_dev.c
+++ b/net/phonet/pn_dev.c
@@ -292,8 +292,7 @@ static void phonet_route_autodel(struct net_device *dev)
292 if (bitmap_empty(deleted, 64)) 292 if (bitmap_empty(deleted, 64))
293 return; /* short-circuit RCU */ 293 return; /* short-circuit RCU */
294 synchronize_rcu(); 294 synchronize_rcu();
295 for (i = find_first_bit(deleted, 64); i < 64; 295 for_each_set_bit(i, deleted, 64) {
296 i = find_next_bit(deleted, 64, i + 1)) {
297 rtm_phonet_notify(RTM_DELROUTE, dev, i); 296 rtm_phonet_notify(RTM_DELROUTE, dev, i);
298 dev_put(dev); 297 dev_put(dev);
299 } 298 }
@@ -374,6 +373,7 @@ int __init phonet_device_init(void)
374 if (err) 373 if (err)
375 return err; 374 return err;
376 375
376 proc_net_fops_create(&init_net, "pnresource", 0, &pn_res_seq_fops);
377 register_netdevice_notifier(&phonet_device_notifier); 377 register_netdevice_notifier(&phonet_device_notifier);
378 err = phonet_netlink_register(); 378 err = phonet_netlink_register();
379 if (err) 379 if (err)
@@ -386,6 +386,7 @@ void phonet_device_exit(void)
386 rtnl_unregister_all(PF_PHONET); 386 rtnl_unregister_all(PF_PHONET);
387 unregister_netdevice_notifier(&phonet_device_notifier); 387 unregister_netdevice_notifier(&phonet_device_notifier);
388 unregister_pernet_device(&phonet_net_ops); 388 unregister_pernet_device(&phonet_net_ops);
389 proc_net_remove(&init_net, "pnresource");
389} 390}
390 391
391int phonet_route_add(struct net_device *dev, u8 daddr) 392int phonet_route_add(struct net_device *dev, u8 daddr)
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 6e9848bf0370..aca8fba099e9 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -158,6 +158,7 @@ void pn_sock_unhash(struct sock *sk)
158 spin_lock_bh(&pnsocks.lock); 158 spin_lock_bh(&pnsocks.lock);
159 sk_del_node_init(sk); 159 sk_del_node_init(sk);
160 spin_unlock_bh(&pnsocks.lock); 160 spin_unlock_bh(&pnsocks.lock);
161 pn_sock_unbind_all_res(sk);
161} 162}
162EXPORT_SYMBOL(pn_sock_unhash); 163EXPORT_SYMBOL(pn_sock_unhash);
163 164
@@ -281,7 +282,9 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
281 if (!mask && sk->sk_state == TCP_CLOSE_WAIT) 282 if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
282 return POLLHUP; 283 return POLLHUP;
283 284
284 if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits)) 285 if (sk->sk_state == TCP_ESTABLISHED &&
286 atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
287 atomic_read(&pn->tx_credits))
285 mask |= POLLOUT | POLLWRNORM | POLLWRBAND; 288 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
286 289
287 return mask; 290 return mask;
@@ -563,3 +566,188 @@ const struct file_operations pn_sock_seq_fops = {
563 .release = seq_release_net, 566 .release = seq_release_net,
564}; 567};
565#endif 568#endif
569
570static struct {
571 struct sock *sk[256];
572} pnres;
573
574/*
575 * Find and hold socket based on resource.
576 */
577struct sock *pn_find_sock_by_res(struct net *net, u8 res)
578{
579 struct sock *sk;
580
581 if (!net_eq(net, &init_net))
582 return NULL;
583
584 rcu_read_lock();
585 sk = rcu_dereference(pnres.sk[res]);
586 if (sk)
587 sock_hold(sk);
588 rcu_read_unlock();
589 return sk;
590}
591
592static DEFINE_MUTEX(resource_mutex);
593
594int pn_sock_bind_res(struct sock *sk, u8 res)
595{
596 int ret = -EADDRINUSE;
597
598 if (!net_eq(sock_net(sk), &init_net))
599 return -ENOIOCTLCMD;
600 if (!capable(CAP_SYS_ADMIN))
601 return -EPERM;
602 if (pn_socket_autobind(sk->sk_socket))
603 return -EAGAIN;
604
605 mutex_lock(&resource_mutex);
606 if (pnres.sk[res] == NULL) {
607 sock_hold(sk);
608 rcu_assign_pointer(pnres.sk[res], sk);
609 ret = 0;
610 }
611 mutex_unlock(&resource_mutex);
612 return ret;
613}
614
615int pn_sock_unbind_res(struct sock *sk, u8 res)
616{
617 int ret = -ENOENT;
618
619 if (!capable(CAP_SYS_ADMIN))
620 return -EPERM;
621
622 mutex_lock(&resource_mutex);
623 if (pnres.sk[res] == sk) {
624 rcu_assign_pointer(pnres.sk[res], NULL);
625 ret = 0;
626 }
627 mutex_unlock(&resource_mutex);
628
629 if (ret == 0) {
630 synchronize_rcu();
631 sock_put(sk);
632 }
633 return ret;
634}
635
636void pn_sock_unbind_all_res(struct sock *sk)
637{
638 unsigned res, match = 0;
639
640 mutex_lock(&resource_mutex);
641 for (res = 0; res < 256; res++) {
642 if (pnres.sk[res] == sk) {
643 rcu_assign_pointer(pnres.sk[res], NULL);
644 match++;
645 }
646 }
647 mutex_unlock(&resource_mutex);
648
649 if (match == 0)
650 return;
651 synchronize_rcu();
652 while (match > 0) {
653 sock_put(sk);
654 match--;
655 }
656}
657
658#ifdef CONFIG_PROC_FS
659static struct sock **pn_res_get_idx(struct seq_file *seq, loff_t pos)
660{
661 struct net *net = seq_file_net(seq);
662 unsigned i;
663
664 if (!net_eq(net, &init_net))
665 return NULL;
666
667 for (i = 0; i < 256; i++) {
668 if (pnres.sk[i] == NULL)
669 continue;
670 if (!pos)
671 return pnres.sk + i;
672 pos--;
673 }
674 return NULL;
675}
676
677static struct sock **pn_res_get_next(struct seq_file *seq, struct sock **sk)
678{
679 struct net *net = seq_file_net(seq);
680 unsigned i;
681
682 BUG_ON(!net_eq(net, &init_net));
683
684 for (i = (sk - pnres.sk) + 1; i < 256; i++)
685 if (pnres.sk[i])
686 return pnres.sk + i;
687 return NULL;
688}
689
690static void *pn_res_seq_start(struct seq_file *seq, loff_t *pos)
691 __acquires(resource_mutex)
692{
693 mutex_lock(&resource_mutex);
694 return *pos ? pn_res_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
695}
696
697static void *pn_res_seq_next(struct seq_file *seq, void *v, loff_t *pos)
698{
699 struct sock **sk;
700
701 if (v == SEQ_START_TOKEN)
702 sk = pn_res_get_idx(seq, 0);
703 else
704 sk = pn_res_get_next(seq, v);
705 (*pos)++;
706 return sk;
707}
708
709static void pn_res_seq_stop(struct seq_file *seq, void *v)
710 __releases(resource_mutex)
711{
712 mutex_unlock(&resource_mutex);
713}
714
715static int pn_res_seq_show(struct seq_file *seq, void *v)
716{
717 int len;
718
719 if (v == SEQ_START_TOKEN)
720 seq_printf(seq, "%s%n", "rs uid inode", &len);
721 else {
722 struct sock **psk = v;
723 struct sock *sk = *psk;
724
725 seq_printf(seq, "%02X %5d %lu%n",
726 (int) (psk - pnres.sk), sock_i_uid(sk),
727 sock_i_ino(sk), &len);
728 }
729 seq_printf(seq, "%*s\n", 63 - len, "");
730 return 0;
731}
732
733static const struct seq_operations pn_res_seq_ops = {
734 .start = pn_res_seq_start,
735 .next = pn_res_seq_next,
736 .stop = pn_res_seq_stop,
737 .show = pn_res_seq_show,
738};
739
740static int pn_res_open(struct inode *inode, struct file *file)
741{
742 return seq_open_net(inode, file, &pn_res_seq_ops,
743 sizeof(struct seq_net_private));
744}
745
746const struct file_operations pn_res_seq_fops = {
747 .owner = THIS_MODULE,
748 .open = pn_res_open,
749 .read = seq_read,
750 .llseek = seq_lseek,
751 .release = seq_release_net,
752};
753#endif