diff options
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r-- | net/phonet/pep.c | 388 |
1 files changed, 386 insertions, 2 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 15003021f4f0..3e60f2e4e6c2 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -109,6 +109,210 @@ static int pep_reply(struct sock *sk, struct sk_buff *oskb, | |||
109 | } | 109 | } |
110 | 110 | ||
111 | #define PAD 0x00 | 111 | #define PAD 0x00 |
112 | |||
113 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
114 | static u8 pipe_negotiate_fc(u8 *host_fc, u8 *remote_fc, int len) | ||
115 | { | ||
116 | int i, j; | ||
117 | u8 base_fc, final_fc; | ||
118 | |||
119 | for (i = 0; i < len; i++) { | ||
120 | base_fc = host_fc[i]; | ||
121 | for (j = 0; j < len; j++) { | ||
122 | if (remote_fc[j] == base_fc) { | ||
123 | final_fc = base_fc; | ||
124 | goto done; | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | return -EINVAL; | ||
129 | |||
130 | done: | ||
131 | return final_fc; | ||
132 | |||
133 | } | ||
134 | |||
135 | static int pipe_get_flow_info(struct sock *sk, struct sk_buff *skb, | ||
136 | u8 *pref_rx_fc, u8 *req_tx_fc) | ||
137 | { | ||
138 | struct pnpipehdr *hdr; | ||
139 | u8 n_sb; | ||
140 | |||
141 | if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) | ||
142 | return -EINVAL; | ||
143 | |||
144 | hdr = pnp_hdr(skb); | ||
145 | n_sb = hdr->data[4]; | ||
146 | |||
147 | __skb_pull(skb, sizeof(*hdr) + 4); | ||
148 | while (n_sb > 0) { | ||
149 | u8 type, buf[3], len = sizeof(buf); | ||
150 | u8 *data = pep_get_sb(skb, &type, &len, buf); | ||
151 | |||
152 | if (data == NULL) | ||
153 | return -EINVAL; | ||
154 | |||
155 | switch (type) { | ||
156 | case PN_PIPE_SB_REQUIRED_FC_TX: | ||
157 | if (len < 3 || (data[2] | data[3] | data[4]) > 3) | ||
158 | break; | ||
159 | req_tx_fc[0] = data[2]; | ||
160 | req_tx_fc[1] = data[3]; | ||
161 | req_tx_fc[2] = data[4]; | ||
162 | break; | ||
163 | |||
164 | case PN_PIPE_SB_PREFERRED_FC_RX: | ||
165 | if (len < 3 || (data[2] | data[3] | data[4]) > 3) | ||
166 | break; | ||
167 | pref_rx_fc[0] = data[2]; | ||
168 | pref_rx_fc[1] = data[3]; | ||
169 | pref_rx_fc[2] = data[4]; | ||
170 | break; | ||
171 | |||
172 | } | ||
173 | n_sb--; | ||
174 | } | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int pipe_handler_send_req(struct sock *sk, u8 utid, | ||
179 | u8 msg_id, gfp_t priority) | ||
180 | { | ||
181 | int len; | ||
182 | struct pnpipehdr *ph; | ||
183 | struct sk_buff *skb; | ||
184 | struct pep_sock *pn = pep_sk(sk); | ||
185 | |||
186 | static const u8 data[4] = { | ||
187 | PAD, PAD, PAD, PAD, | ||
188 | }; | ||
189 | |||
190 | switch (msg_id) { | ||
191 | case PNS_PEP_CONNECT_REQ: | ||
192 | len = sizeof(data); | ||
193 | break; | ||
194 | |||
195 | case PNS_PEP_DISCONNECT_REQ: | ||
196 | case PNS_PEP_ENABLE_REQ: | ||
197 | case PNS_PEP_DISABLE_REQ: | ||
198 | len = 0; | ||
199 | break; | ||
200 | |||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); | ||
206 | if (!skb) | ||
207 | return -ENOMEM; | ||
208 | skb_set_owner_w(skb, sk); | ||
209 | |||
210 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
211 | if (len) { | ||
212 | __skb_put(skb, len); | ||
213 | skb_copy_to_linear_data(skb, data, len); | ||
214 | } | ||
215 | __skb_push(skb, sizeof(*ph)); | ||
216 | skb_reset_transport_header(skb); | ||
217 | ph = pnp_hdr(skb); | ||
218 | ph->utid = utid; | ||
219 | ph->message_id = msg_id; | ||
220 | ph->pipe_handle = pn->pipe_handle; | ||
221 | ph->error_code = PN_PIPE_NO_ERROR; | ||
222 | |||
223 | return pn_skb_send(sk, skb, &pn->remote_pep); | ||
224 | } | ||
225 | |||
226 | static int pipe_handler_send_created_ind(struct sock *sk, | ||
227 | u8 utid, u8 msg_id) | ||
228 | { | ||
229 | int err_code; | ||
230 | struct pnpipehdr *ph; | ||
231 | struct sk_buff *skb; | ||
232 | |||
233 | struct pep_sock *pn = pep_sk(sk); | ||
234 | static u8 data[4] = { | ||
235 | 0x03, 0x04, | ||
236 | }; | ||
237 | data[2] = pn->tx_fc; | ||
238 | data[3] = pn->rx_fc; | ||
239 | |||
240 | /* | ||
241 | * actually, below is number of sub-blocks and not error code. | ||
242 | * Pipe_created_ind message format does not have any | ||
243 | * error code field. However, the Phonet stack will always send | ||
244 | * an error code as part of pnpipehdr. So, use that err_code to | ||
245 | * specify the number of sub-blocks. | ||
246 | */ | ||
247 | err_code = 0x01; | ||
248 | |||
249 | skb = alloc_skb(MAX_PNPIPE_HEADER + sizeof(data), GFP_ATOMIC); | ||
250 | if (!skb) | ||
251 | return -ENOMEM; | ||
252 | skb_set_owner_w(skb, sk); | ||
253 | |||
254 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
255 | __skb_put(skb, sizeof(data)); | ||
256 | skb_copy_to_linear_data(skb, data, sizeof(data)); | ||
257 | __skb_push(skb, sizeof(*ph)); | ||
258 | skb_reset_transport_header(skb); | ||
259 | ph = pnp_hdr(skb); | ||
260 | ph->utid = utid; | ||
261 | ph->message_id = msg_id; | ||
262 | ph->pipe_handle = pn->pipe_handle; | ||
263 | ph->error_code = err_code; | ||
264 | |||
265 | return pn_skb_send(sk, skb, &pn->remote_pep); | ||
266 | } | ||
267 | |||
268 | static int pipe_handler_send_ind(struct sock *sk, u8 utid, u8 msg_id) | ||
269 | { | ||
270 | int err_code; | ||
271 | struct pnpipehdr *ph; | ||
272 | struct sk_buff *skb; | ||
273 | struct pep_sock *pn = pep_sk(sk); | ||
274 | |||
275 | /* | ||
276 | * actually, below is a filler. | ||
277 | * Pipe_enabled/disabled_ind message format does not have any | ||
278 | * error code field. However, the Phonet stack will always send | ||
279 | * an error code as part of pnpipehdr. So, use that err_code to | ||
280 | * specify the filler value. | ||
281 | */ | ||
282 | err_code = 0x0; | ||
283 | |||
284 | skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC); | ||
285 | if (!skb) | ||
286 | return -ENOMEM; | ||
287 | skb_set_owner_w(skb, sk); | ||
288 | |||
289 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
290 | __skb_push(skb, sizeof(*ph)); | ||
291 | skb_reset_transport_header(skb); | ||
292 | ph = pnp_hdr(skb); | ||
293 | ph->utid = utid; | ||
294 | ph->message_id = msg_id; | ||
295 | ph->pipe_handle = pn->pipe_handle; | ||
296 | ph->error_code = err_code; | ||
297 | |||
298 | return pn_skb_send(sk, skb, &pn->remote_pep); | ||
299 | } | ||
300 | |||
301 | static int pipe_handler_enable_pipe(struct sock *sk, int enable) | ||
302 | { | ||
303 | int utid, req; | ||
304 | |||
305 | if (enable) { | ||
306 | utid = PNS_PIPE_ENABLE_UTID; | ||
307 | req = PNS_PEP_ENABLE_REQ; | ||
308 | } else { | ||
309 | utid = PNS_PIPE_DISABLE_UTID; | ||
310 | req = PNS_PEP_DISABLE_REQ; | ||
311 | } | ||
312 | return pipe_handler_send_req(sk, utid, req, GFP_ATOMIC); | ||
313 | } | ||
314 | #endif | ||
315 | |||
112 | static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) | 316 | static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) |
113 | { | 317 | { |
114 | static const u8 data[20] = { | 318 | static const u8 data[20] = { |
@@ -192,7 +396,11 @@ static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) | |||
192 | ph->data[3] = PAD; | 396 | ph->data[3] = PAD; |
193 | ph->data[4] = status; | 397 | ph->data[4] = status; |
194 | 398 | ||
399 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
400 | return pn_skb_send(sk, skb, &pn->remote_pep); | ||
401 | #else | ||
195 | return pn_skb_send(sk, skb, &pipe_srv); | 402 | return pn_skb_send(sk, skb, &pipe_srv); |
403 | #endif | ||
196 | } | 404 | } |
197 | 405 | ||
198 | /* Send our RX flow control information to the sender. | 406 | /* Send our RX flow control information to the sender. |
@@ -324,11 +532,35 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
324 | sk->sk_state_change(sk); | 532 | sk->sk_state_change(sk); |
325 | break; | 533 | break; |
326 | 534 | ||
535 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
536 | case PNS_PEP_DISCONNECT_RESP: | ||
537 | pn->pipe_state = PIPE_IDLE; | ||
538 | sk->sk_state = TCP_CLOSE; | ||
539 | break; | ||
540 | #endif | ||
541 | |||
327 | case PNS_PEP_ENABLE_REQ: | 542 | case PNS_PEP_ENABLE_REQ: |
328 | /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ | 543 | /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */ |
329 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 544 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
330 | break; | 545 | break; |
331 | 546 | ||
547 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
548 | case PNS_PEP_ENABLE_RESP: | ||
549 | pn->pipe_state = PIPE_ENABLED; | ||
550 | pipe_handler_send_ind(sk, PNS_PIPE_ENABLED_IND_UTID, | ||
551 | PNS_PIPE_ENABLED_IND); | ||
552 | |||
553 | if (!pn_flow_safe(pn->tx_fc)) { | ||
554 | atomic_set(&pn->tx_credits, 1); | ||
555 | sk->sk_write_space(sk); | ||
556 | } | ||
557 | if (sk->sk_state == TCP_ESTABLISHED) | ||
558 | break; /* Nothing to do */ | ||
559 | sk->sk_state = TCP_ESTABLISHED; | ||
560 | pipe_grant_credits(sk); | ||
561 | break; | ||
562 | #endif | ||
563 | |||
332 | case PNS_PEP_RESET_REQ: | 564 | case PNS_PEP_RESET_REQ: |
333 | switch (hdr->state_after_reset) { | 565 | switch (hdr->state_after_reset) { |
334 | case PN_PIPE_DISABLE: | 566 | case PN_PIPE_DISABLE: |
@@ -347,6 +579,17 @@ 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); | 579 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
348 | break; | 580 | break; |
349 | 581 | ||
582 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
583 | case PNS_PEP_DISABLE_RESP: | ||
584 | pn->pipe_state = PIPE_DISABLED; | ||
585 | atomic_set(&pn->tx_credits, 0); | ||
586 | pipe_handler_send_ind(sk, PNS_PIPE_DISABLED_IND_UTID, | ||
587 | PNS_PIPE_DISABLED_IND); | ||
588 | sk->sk_state = TCP_SYN_RECV; | ||
589 | pn->rx_credits = 0; | ||
590 | break; | ||
591 | #endif | ||
592 | |||
350 | case PNS_PEP_CTRL_REQ: | 593 | case PNS_PEP_CTRL_REQ: |
351 | if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { | 594 | if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX) { |
352 | atomic_inc(&sk->sk_drops); | 595 | atomic_inc(&sk->sk_drops); |
@@ -438,6 +681,42 @@ static void pipe_destruct(struct sock *sk) | |||
438 | skb_queue_purge(&pn->ctrlreq_queue); | 681 | skb_queue_purge(&pn->ctrlreq_queue); |
439 | } | 682 | } |
440 | 683 | ||
684 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
685 | static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | ||
686 | { | ||
687 | struct pep_sock *pn = pep_sk(sk); | ||
688 | u8 host_pref_rx_fc[3] = {3, 2, 1}, host_req_tx_fc[3] = {3, 2, 1}; | ||
689 | u8 remote_pref_rx_fc[3], remote_req_tx_fc[3]; | ||
690 | u8 negotiated_rx_fc, negotiated_tx_fc; | ||
691 | int ret; | ||
692 | |||
693 | pipe_get_flow_info(sk, skb, remote_pref_rx_fc, | ||
694 | remote_req_tx_fc); | ||
695 | negotiated_tx_fc = pipe_negotiate_fc(remote_req_tx_fc, | ||
696 | host_pref_rx_fc, | ||
697 | sizeof(host_pref_rx_fc)); | ||
698 | negotiated_rx_fc = pipe_negotiate_fc(host_req_tx_fc, | ||
699 | remote_pref_rx_fc, | ||
700 | sizeof(host_pref_rx_fc)); | ||
701 | |||
702 | pn->pipe_state = PIPE_DISABLED; | ||
703 | sk->sk_state = TCP_SYN_RECV; | ||
704 | sk->sk_backlog_rcv = pipe_do_rcv; | ||
705 | sk->sk_destruct = pipe_destruct; | ||
706 | pn->rx_credits = 0; | ||
707 | pn->rx_fc = negotiated_rx_fc; | ||
708 | pn->tx_fc = negotiated_tx_fc; | ||
709 | sk->sk_state_change(sk); | ||
710 | |||
711 | ret = pipe_handler_send_created_ind(sk, | ||
712 | PNS_PIPE_CREATED_IND_UTID, | ||
713 | PNS_PIPE_CREATED_IND | ||
714 | ); | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | #endif | ||
719 | |||
441 | static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) | 720 | static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) |
442 | { | 721 | { |
443 | struct sock *newsk; | 722 | struct sock *newsk; |
@@ -601,6 +880,12 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
601 | err = pep_connreq_rcv(sk, skb); | 880 | err = pep_connreq_rcv(sk, skb); |
602 | break; | 881 | break; |
603 | 882 | ||
883 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
884 | case PNS_PEP_CONNECT_RESP: | ||
885 | err = pep_connresp_rcv(sk, skb); | ||
886 | break; | ||
887 | #endif | ||
888 | |||
604 | case PNS_PEP_DISCONNECT_REQ: | 889 | case PNS_PEP_DISCONNECT_REQ: |
605 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 890 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
606 | break; | 891 | break; |
@@ -621,6 +906,28 @@ drop: | |||
621 | return err; | 906 | return err; |
622 | } | 907 | } |
623 | 908 | ||
909 | static int pipe_do_remove(struct sock *sk) | ||
910 | { | ||
911 | struct pep_sock *pn = pep_sk(sk); | ||
912 | struct pnpipehdr *ph; | ||
913 | struct sk_buff *skb; | ||
914 | |||
915 | skb = alloc_skb(MAX_PNPIPE_HEADER, GFP_KERNEL); | ||
916 | if (!skb) | ||
917 | return -ENOMEM; | ||
918 | |||
919 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
920 | __skb_push(skb, sizeof(*ph)); | ||
921 | skb_reset_transport_header(skb); | ||
922 | ph = pnp_hdr(skb); | ||
923 | ph->utid = 0; | ||
924 | ph->message_id = PNS_PIPE_REMOVE_REQ; | ||
925 | ph->pipe_handle = pn->pipe_handle; | ||
926 | ph->data[0] = PAD; | ||
927 | |||
928 | return pn_skb_send(sk, skb, &pipe_srv); | ||
929 | } | ||
930 | |||
624 | /* associated socket ceases to exist */ | 931 | /* associated socket ceases to exist */ |
625 | static void pep_sock_close(struct sock *sk, long timeout) | 932 | static void pep_sock_close(struct sock *sk, long timeout) |
626 | { | 933 | { |
@@ -639,7 +946,22 @@ static void pep_sock_close(struct sock *sk, long timeout) | |||
639 | sk_for_each_safe(sknode, p, n, &pn->ackq) | 946 | sk_for_each_safe(sknode, p, n, &pn->ackq) |
640 | sk_del_node_init(sknode); | 947 | sk_del_node_init(sknode); |
641 | sk->sk_state = TCP_CLOSE; | 948 | sk->sk_state = TCP_CLOSE; |
949 | } else if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) | ||
950 | /* Forcefully remove dangling Phonet pipe */ | ||
951 | pipe_do_remove(sk); | ||
952 | |||
953 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
954 | if (pn->pipe_state != PIPE_IDLE) { | ||
955 | /* send pep disconnect request */ | ||
956 | pipe_handler_send_req(sk, | ||
957 | PNS_PEP_DISCONNECT_UTID, PNS_PEP_DISCONNECT_REQ, | ||
958 | GFP_KERNEL); | ||
959 | |||
960 | pn->pipe_state = PIPE_IDLE; | ||
961 | sk->sk_state = TCP_CLOSE; | ||
642 | } | 962 | } |
963 | #endif | ||
964 | |||
643 | ifindex = pn->ifindex; | 965 | ifindex = pn->ifindex; |
644 | pn->ifindex = 0; | 966 | pn->ifindex = 0; |
645 | release_sock(sk); | 967 | release_sock(sk); |
@@ -716,6 +1038,20 @@ out: | |||
716 | return newsk; | 1038 | return newsk; |
717 | } | 1039 | } |
718 | 1040 | ||
1041 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1042 | static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) | ||
1043 | { | ||
1044 | struct pep_sock *pn = pep_sk(sk); | ||
1045 | struct sockaddr_pn *spn = (struct sockaddr_pn *)addr; | ||
1046 | |||
1047 | memcpy(&pn->remote_pep, spn, sizeof(struct sockaddr_pn)); | ||
1048 | |||
1049 | return pipe_handler_send_req(sk, | ||
1050 | PNS_PEP_CONNECT_UTID, PNS_PEP_CONNECT_REQ, | ||
1051 | GFP_ATOMIC); | ||
1052 | } | ||
1053 | #endif | ||
1054 | |||
719 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | 1055 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) |
720 | { | 1056 | { |
721 | struct pep_sock *pn = pep_sk(sk); | 1057 | struct pep_sock *pn = pep_sk(sk); |
@@ -767,6 +1103,18 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, | |||
767 | 1103 | ||
768 | lock_sock(sk); | 1104 | lock_sock(sk); |
769 | switch (optname) { | 1105 | switch (optname) { |
1106 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1107 | case PNPIPE_PIPE_HANDLE: | ||
1108 | if (val) { | ||
1109 | if (pn->pipe_state > PIPE_IDLE) { | ||
1110 | err = -EFAULT; | ||
1111 | break; | ||
1112 | } | ||
1113 | pn->pipe_handle = val; | ||
1114 | break; | ||
1115 | } | ||
1116 | #endif | ||
1117 | |||
770 | case PNPIPE_ENCAP: | 1118 | case PNPIPE_ENCAP: |
771 | if (val && val != PNPIPE_ENCAP_IP) { | 1119 | if (val && val != PNPIPE_ENCAP_IP) { |
772 | err = -EINVAL; | 1120 | err = -EINVAL; |
@@ -792,6 +1140,17 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, | |||
792 | err = 0; | 1140 | err = 0; |
793 | } | 1141 | } |
794 | goto out_norel; | 1142 | goto out_norel; |
1143 | |||
1144 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1145 | case PNPIPE_ENABLE: | ||
1146 | if (pn->pipe_state <= PIPE_IDLE) { | ||
1147 | err = -ENOTCONN; | ||
1148 | break; | ||
1149 | } | ||
1150 | err = pipe_handler_enable_pipe(sk, val); | ||
1151 | break; | ||
1152 | #endif | ||
1153 | |||
795 | default: | 1154 | default: |
796 | err = -ENOPROTOOPT; | 1155 | err = -ENOPROTOOPT; |
797 | } | 1156 | } |
@@ -816,9 +1175,19 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, | |||
816 | case PNPIPE_ENCAP: | 1175 | case PNPIPE_ENCAP: |
817 | val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; | 1176 | val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; |
818 | break; | 1177 | break; |
1178 | |||
819 | case PNPIPE_IFINDEX: | 1179 | case PNPIPE_IFINDEX: |
820 | val = pn->ifindex; | 1180 | val = pn->ifindex; |
821 | break; | 1181 | break; |
1182 | |||
1183 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1184 | case PNPIPE_ENABLE: | ||
1185 | if (pn->pipe_state <= PIPE_IDLE) | ||
1186 | return -ENOTCONN; | ||
1187 | val = pn->pipe_state != PIPE_DISABLED; | ||
1188 | break; | ||
1189 | #endif | ||
1190 | |||
822 | default: | 1191 | default: |
823 | return -ENOPROTOOPT; | 1192 | return -ENOPROTOOPT; |
824 | } | 1193 | } |
@@ -835,6 +1204,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
835 | { | 1204 | { |
836 | struct pep_sock *pn = pep_sk(sk); | 1205 | struct pep_sock *pn = pep_sk(sk); |
837 | struct pnpipehdr *ph; | 1206 | struct pnpipehdr *ph; |
1207 | int err; | ||
838 | 1208 | ||
839 | if (pn_flow_safe(pn->tx_fc) && | 1209 | if (pn_flow_safe(pn->tx_fc) && |
840 | !atomic_add_unless(&pn->tx_credits, -1, 0)) { | 1210 | !atomic_add_unless(&pn->tx_credits, -1, 0)) { |
@@ -852,8 +1222,16 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
852 | } else | 1222 | } else |
853 | ph->message_id = PNS_PIPE_DATA; | 1223 | ph->message_id = PNS_PIPE_DATA; |
854 | ph->pipe_handle = pn->pipe_handle; | 1224 | ph->pipe_handle = pn->pipe_handle; |
1225 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1226 | err = pn_skb_send(sk, skb, &pn->remote_pep); | ||
1227 | #else | ||
1228 | err = pn_skb_send(sk, skb, &pipe_srv); | ||
1229 | #endif | ||
1230 | |||
1231 | if (err && pn_flow_safe(pn->tx_fc)) | ||
1232 | atomic_inc(&pn->tx_credits); | ||
1233 | return err; | ||
855 | 1234 | ||
856 | return pn_skb_send(sk, skb, &pipe_srv); | ||
857 | } | 1235 | } |
858 | 1236 | ||
859 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | 1237 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, |
@@ -873,7 +1251,7 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
873 | skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, | 1251 | skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, |
874 | flags & MSG_DONTWAIT, &err); | 1252 | flags & MSG_DONTWAIT, &err); |
875 | if (!skb) | 1253 | if (!skb) |
876 | return -ENOBUFS; | 1254 | return err; |
877 | 1255 | ||
878 | skb_reserve(skb, MAX_PHONET_HEADER + 3); | 1256 | skb_reserve(skb, MAX_PHONET_HEADER + 3); |
879 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | 1257 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); |
@@ -1045,6 +1423,8 @@ static void pep_sock_unhash(struct sock *sk) | |||
1045 | struct sock *skparent = NULL; | 1423 | struct sock *skparent = NULL; |
1046 | 1424 | ||
1047 | lock_sock(sk); | 1425 | lock_sock(sk); |
1426 | |||
1427 | #ifndef CONFIG_PHONET_PIPECTRLR | ||
1048 | if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { | 1428 | if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { |
1049 | skparent = pn->listener; | 1429 | skparent = pn->listener; |
1050 | release_sock(sk); | 1430 | release_sock(sk); |
@@ -1054,6 +1434,7 @@ static void pep_sock_unhash(struct sock *sk) | |||
1054 | sk_del_node_init(sk); | 1434 | sk_del_node_init(sk); |
1055 | sk = skparent; | 1435 | sk = skparent; |
1056 | } | 1436 | } |
1437 | #endif | ||
1057 | /* Unhash a listening sock only when it is closed | 1438 | /* Unhash a listening sock only when it is closed |
1058 | * and all of its active connected pipes are closed. */ | 1439 | * and all of its active connected pipes are closed. */ |
1059 | if (hlist_empty(&pn->hlist)) | 1440 | if (hlist_empty(&pn->hlist)) |
@@ -1067,6 +1448,9 @@ static void pep_sock_unhash(struct sock *sk) | |||
1067 | static struct proto pep_proto = { | 1448 | static struct proto pep_proto = { |
1068 | .close = pep_sock_close, | 1449 | .close = pep_sock_close, |
1069 | .accept = pep_sock_accept, | 1450 | .accept = pep_sock_accept, |
1451 | #ifdef CONFIG_PHONET_PIPECTRLR | ||
1452 | .connect = pep_sock_connect, | ||
1453 | #endif | ||
1070 | .ioctl = pep_ioctl, | 1454 | .ioctl = pep_ioctl, |
1071 | .init = pep_init, | 1455 | .init = pep_init, |
1072 | .setsockopt = pep_setsockopt, | 1456 | .setsockopt = pep_setsockopt, |