diff options
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r-- | net/phonet/pep.c | 448 |
1 files changed, 442 insertions, 6 deletions
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 | ||
127 | static 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 | |||
143 | done: | ||
144 | return final_fc; | ||
145 | |||
146 | } | ||
147 | |||
148 | static 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 | |||
191 | static 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 | |||
244 | static 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 | |||
291 | static 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 | |||
330 | static 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 | |||
355 | static 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 | |||
112 | static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) | 382 | static 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 | ||
887 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | 1323 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, |