diff options
Diffstat (limited to 'net/phonet/pep.c')
-rw-r--r-- | net/phonet/pep.c | 588 |
1 files changed, 386 insertions, 202 deletions
diff --git a/net/phonet/pep.c b/net/phonet/pep.c index 15003021f4f0..f17fd841f948 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c | |||
@@ -42,7 +42,7 @@ | |||
42 | * TCP_ESTABLISHED connected pipe in enabled state | 42 | * TCP_ESTABLISHED connected pipe in enabled state |
43 | * | 43 | * |
44 | * pep_sock locking: | 44 | * pep_sock locking: |
45 | * - sk_state, ackq, hlist: sock lock needed | 45 | * - sk_state, hlist: sock lock needed |
46 | * - listener: read only | 46 | * - listener: read only |
47 | * - pipe_handle: read only | 47 | * - pipe_handle: read only |
48 | */ | 48 | */ |
@@ -50,11 +50,6 @@ | |||
50 | #define CREDITS_MAX 10 | 50 | #define CREDITS_MAX 10 |
51 | #define CREDITS_THR 7 | 51 | #define CREDITS_THR 7 |
52 | 52 | ||
53 | static const struct sockaddr_pn pipe_srv = { | ||
54 | .spn_family = AF_PHONET, | ||
55 | .spn_resource = 0xD9, /* pipe service */ | ||
56 | }; | ||
57 | |||
58 | #define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */ | 53 | #define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */ |
59 | 54 | ||
60 | /* Get the next TLV sub-block. */ | 55 | /* Get the next TLV sub-block. */ |
@@ -82,33 +77,96 @@ static unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen, | |||
82 | return data; | 77 | return data; |
83 | } | 78 | } |
84 | 79 | ||
85 | static int pep_reply(struct sock *sk, struct sk_buff *oskb, | 80 | static struct sk_buff *pep_alloc_skb(struct sock *sk, const void *payload, |
86 | u8 code, const void *data, int len, gfp_t priority) | 81 | int len, gfp_t priority) |
82 | { | ||
83 | struct sk_buff *skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); | ||
84 | if (!skb) | ||
85 | return NULL; | ||
86 | skb_set_owner_w(skb, sk); | ||
87 | |||
88 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
89 | __skb_put(skb, len); | ||
90 | skb_copy_to_linear_data(skb, payload, len); | ||
91 | __skb_push(skb, sizeof(struct pnpipehdr)); | ||
92 | skb_reset_transport_header(skb); | ||
93 | return skb; | ||
94 | } | ||
95 | |||
96 | static int pep_reply(struct sock *sk, struct sk_buff *oskb, u8 code, | ||
97 | const void *data, int len, gfp_t priority) | ||
87 | { | 98 | { |
88 | const struct pnpipehdr *oph = pnp_hdr(oskb); | 99 | const struct pnpipehdr *oph = pnp_hdr(oskb); |
89 | struct pnpipehdr *ph; | 100 | struct pnpipehdr *ph; |
90 | struct sk_buff *skb; | 101 | struct sk_buff *skb; |
102 | struct sockaddr_pn peer; | ||
91 | 103 | ||
92 | skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority); | 104 | skb = pep_alloc_skb(sk, data, len, priority); |
93 | if (!skb) | 105 | if (!skb) |
94 | return -ENOMEM; | 106 | return -ENOMEM; |
95 | skb_set_owner_w(skb, sk); | ||
96 | 107 | ||
97 | skb_reserve(skb, MAX_PNPIPE_HEADER); | ||
98 | __skb_put(skb, len); | ||
99 | skb_copy_to_linear_data(skb, data, len); | ||
100 | __skb_push(skb, sizeof(*ph)); | ||
101 | skb_reset_transport_header(skb); | ||
102 | ph = pnp_hdr(skb); | 108 | ph = pnp_hdr(skb); |
103 | ph->utid = oph->utid; | 109 | ph->utid = oph->utid; |
104 | ph->message_id = oph->message_id + 1; /* REQ -> RESP */ | 110 | ph->message_id = oph->message_id + 1; /* REQ -> RESP */ |
105 | ph->pipe_handle = oph->pipe_handle; | 111 | ph->pipe_handle = oph->pipe_handle; |
106 | ph->error_code = code; | 112 | ph->error_code = code; |
107 | 113 | ||
108 | return pn_skb_send(sk, skb, &pipe_srv); | 114 | pn_skb_get_src_sockaddr(oskb, &peer); |
115 | return pn_skb_send(sk, skb, &peer); | ||
116 | } | ||
117 | |||
118 | static int pep_indicate(struct sock *sk, u8 id, u8 code, | ||
119 | const void *data, int len, gfp_t priority) | ||
120 | { | ||
121 | struct pep_sock *pn = pep_sk(sk); | ||
122 | struct pnpipehdr *ph; | ||
123 | struct sk_buff *skb; | ||
124 | |||
125 | skb = pep_alloc_skb(sk, data, len, priority); | ||
126 | if (!skb) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | ph = pnp_hdr(skb); | ||
130 | ph->utid = 0; | ||
131 | ph->message_id = id; | ||
132 | ph->pipe_handle = pn->pipe_handle; | ||
133 | ph->data[0] = code; | ||
134 | return pn_skb_send(sk, skb, NULL); | ||
109 | } | 135 | } |
110 | 136 | ||
111 | #define PAD 0x00 | 137 | #define PAD 0x00 |
138 | |||
139 | static int pipe_handler_request(struct sock *sk, u8 id, u8 code, | ||
140 | const void *data, int len) | ||
141 | { | ||
142 | struct pep_sock *pn = pep_sk(sk); | ||
143 | struct pnpipehdr *ph; | ||
144 | struct sk_buff *skb; | ||
145 | |||
146 | skb = pep_alloc_skb(sk, data, len, GFP_KERNEL); | ||
147 | if (!skb) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | ph = pnp_hdr(skb); | ||
151 | ph->utid = id; /* whatever */ | ||
152 | ph->message_id = id; | ||
153 | ph->pipe_handle = pn->pipe_handle; | ||
154 | ph->data[0] = code; | ||
155 | return pn_skb_send(sk, skb, NULL); | ||
156 | } | ||
157 | |||
158 | static int pipe_handler_send_created_ind(struct sock *sk) | ||
159 | { | ||
160 | struct pep_sock *pn = pep_sk(sk); | ||
161 | u8 data[4] = { | ||
162 | PN_PIPE_SB_NEGOTIATED_FC, pep_sb_size(2), | ||
163 | pn->tx_fc, pn->rx_fc, | ||
164 | }; | ||
165 | |||
166 | return pep_indicate(sk, PNS_PIPE_CREATED_IND, 1 /* sub-blocks */, | ||
167 | data, 4, GFP_ATOMIC); | ||
168 | } | ||
169 | |||
112 | static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) | 170 | static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) |
113 | { | 171 | { |
114 | static const u8 data[20] = { | 172 | static const u8 data[20] = { |
@@ -130,11 +188,12 @@ static int pep_accept_conn(struct sock *sk, struct sk_buff *skb) | |||
130 | GFP_KERNEL); | 188 | GFP_KERNEL); |
131 | } | 189 | } |
132 | 190 | ||
133 | static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code) | 191 | static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code, |
192 | gfp_t priority) | ||
134 | { | 193 | { |
135 | static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; | 194 | static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ }; |
136 | WARN_ON(code == PN_PIPE_NO_ERROR); | 195 | WARN_ON(code == PN_PIPE_NO_ERROR); |
137 | return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC); | 196 | return pep_reply(sk, skb, code, data, sizeof(data), priority); |
138 | } | 197 | } |
139 | 198 | ||
140 | /* Control requests are not sent by the pipe service and have a specific | 199 | /* Control requests are not sent by the pipe service and have a specific |
@@ -146,23 +205,21 @@ static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, | |||
146 | struct sk_buff *skb; | 205 | struct sk_buff *skb; |
147 | struct pnpipehdr *ph; | 206 | struct pnpipehdr *ph; |
148 | struct sockaddr_pn dst; | 207 | struct sockaddr_pn dst; |
208 | u8 data[4] = { | ||
209 | oph->data[0], /* PEP type */ | ||
210 | code, /* error code, at an unusual offset */ | ||
211 | PAD, PAD, | ||
212 | }; | ||
149 | 213 | ||
150 | skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); | 214 | skb = pep_alloc_skb(sk, data, 4, priority); |
151 | if (!skb) | 215 | if (!skb) |
152 | return -ENOMEM; | 216 | return -ENOMEM; |
153 | skb_set_owner_w(skb, sk); | ||
154 | |||
155 | skb_reserve(skb, MAX_PHONET_HEADER); | ||
156 | ph = (struct pnpipehdr *)skb_put(skb, sizeof(*ph) + 4); | ||
157 | 217 | ||
218 | ph = pnp_hdr(skb); | ||
158 | ph->utid = oph->utid; | 219 | ph->utid = oph->utid; |
159 | ph->message_id = PNS_PEP_CTRL_RESP; | 220 | ph->message_id = PNS_PEP_CTRL_RESP; |
160 | ph->pipe_handle = oph->pipe_handle; | 221 | ph->pipe_handle = oph->pipe_handle; |
161 | ph->data[0] = oph->data[1]; /* CTRL id */ | 222 | ph->data[0] = oph->data[1]; /* CTRL id */ |
162 | ph->data[1] = oph->data[0]; /* PEP type */ | ||
163 | ph->data[2] = code; /* error code, at an usual offset */ | ||
164 | ph->data[3] = PAD; | ||
165 | ph->data[4] = PAD; | ||
166 | 223 | ||
167 | pn_skb_get_src_sockaddr(oskb, &dst); | 224 | pn_skb_get_src_sockaddr(oskb, &dst); |
168 | return pn_skb_send(sk, skb, &dst); | 225 | return pn_skb_send(sk, skb, &dst); |
@@ -170,34 +227,15 @@ static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code, | |||
170 | 227 | ||
171 | static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) | 228 | static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority) |
172 | { | 229 | { |
173 | struct pep_sock *pn = pep_sk(sk); | 230 | u8 data[4] = { type, PAD, PAD, status }; |
174 | struct pnpipehdr *ph; | ||
175 | struct sk_buff *skb; | ||
176 | 231 | ||
177 | skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority); | 232 | return pep_indicate(sk, PNS_PEP_STATUS_IND, PN_PEP_TYPE_COMMON, |
178 | if (!skb) | 233 | data, 4, priority); |
179 | return -ENOMEM; | ||
180 | skb_set_owner_w(skb, sk); | ||
181 | |||
182 | skb_reserve(skb, MAX_PNPIPE_HEADER + 4); | ||
183 | __skb_push(skb, sizeof(*ph) + 4); | ||
184 | skb_reset_transport_header(skb); | ||
185 | ph = pnp_hdr(skb); | ||
186 | ph->utid = 0; | ||
187 | ph->message_id = PNS_PEP_STATUS_IND; | ||
188 | ph->pipe_handle = pn->pipe_handle; | ||
189 | ph->pep_type = PN_PEP_TYPE_COMMON; | ||
190 | ph->data[1] = type; | ||
191 | ph->data[2] = PAD; | ||
192 | ph->data[3] = PAD; | ||
193 | ph->data[4] = status; | ||
194 | |||
195 | return pn_skb_send(sk, skb, &pipe_srv); | ||
196 | } | 234 | } |
197 | 235 | ||
198 | /* Send our RX flow control information to the sender. | 236 | /* Send our RX flow control information to the sender. |
199 | * Socket must be locked. */ | 237 | * Socket must be locked. */ |
200 | static void pipe_grant_credits(struct sock *sk) | 238 | static void pipe_grant_credits(struct sock *sk, gfp_t priority) |
201 | { | 239 | { |
202 | struct pep_sock *pn = pep_sk(sk); | 240 | struct pep_sock *pn = pep_sk(sk); |
203 | 241 | ||
@@ -207,16 +245,16 @@ static void pipe_grant_credits(struct sock *sk) | |||
207 | case PN_LEGACY_FLOW_CONTROL: /* TODO */ | 245 | case PN_LEGACY_FLOW_CONTROL: /* TODO */ |
208 | break; | 246 | break; |
209 | case PN_ONE_CREDIT_FLOW_CONTROL: | 247 | case PN_ONE_CREDIT_FLOW_CONTROL: |
210 | pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL, | 248 | if (pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL, |
211 | PEP_IND_READY, GFP_ATOMIC); | 249 | PEP_IND_READY, priority) == 0) |
212 | pn->rx_credits = 1; | 250 | pn->rx_credits = 1; |
213 | break; | 251 | break; |
214 | case PN_MULTI_CREDIT_FLOW_CONTROL: | 252 | case PN_MULTI_CREDIT_FLOW_CONTROL: |
215 | if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX) | 253 | if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX) |
216 | break; | 254 | break; |
217 | if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS, | 255 | if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS, |
218 | CREDITS_MAX - pn->rx_credits, | 256 | CREDITS_MAX - pn->rx_credits, |
219 | GFP_ATOMIC) == 0) | 257 | priority) == 0) |
220 | pn->rx_credits = CREDITS_MAX; | 258 | pn->rx_credits = CREDITS_MAX; |
221 | break; | 259 | break; |
222 | } | 260 | } |
@@ -314,7 +352,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
314 | 352 | ||
315 | switch (hdr->message_id) { | 353 | switch (hdr->message_id) { |
316 | case PNS_PEP_CONNECT_REQ: | 354 | case PNS_PEP_CONNECT_REQ: |
317 | pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); | 355 | pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_ATOMIC); |
318 | break; | 356 | break; |
319 | 357 | ||
320 | case PNS_PEP_DISCONNECT_REQ: | 358 | case PNS_PEP_DISCONNECT_REQ: |
@@ -364,7 +402,8 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
364 | if (!pn_flow_safe(pn->rx_fc)) { | 402 | if (!pn_flow_safe(pn->rx_fc)) { |
365 | err = sock_queue_rcv_skb(sk, skb); | 403 | err = sock_queue_rcv_skb(sk, skb); |
366 | if (!err) | 404 | if (!err) |
367 | return 0; | 405 | return NET_RX_SUCCESS; |
406 | err = -ENOBUFS; | ||
368 | break; | 407 | break; |
369 | } | 408 | } |
370 | 409 | ||
@@ -402,7 +441,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
402 | if (sk->sk_state == TCP_ESTABLISHED) | 441 | if (sk->sk_state == TCP_ESTABLISHED) |
403 | break; /* Nothing to do */ | 442 | break; /* Nothing to do */ |
404 | sk->sk_state = TCP_ESTABLISHED; | 443 | sk->sk_state = TCP_ESTABLISHED; |
405 | pipe_grant_credits(sk); | 444 | pipe_grant_credits(sk, GFP_ATOMIC); |
406 | break; | 445 | break; |
407 | 446 | ||
408 | case PNS_PIPE_DISABLED_IND: | 447 | case PNS_PIPE_DISABLED_IND: |
@@ -417,7 +456,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
417 | } | 456 | } |
418 | out: | 457 | out: |
419 | kfree_skb(skb); | 458 | kfree_skb(skb); |
420 | return err; | 459 | return (err == -ENOBUFS) ? NET_RX_DROP : NET_RX_SUCCESS; |
421 | 460 | ||
422 | queue: | 461 | queue: |
423 | skb->dev = NULL; | 462 | skb->dev = NULL; |
@@ -426,7 +465,7 @@ queue: | |||
426 | skb_queue_tail(queue, skb); | 465 | skb_queue_tail(queue, skb); |
427 | if (!sock_flag(sk, SOCK_DEAD)) | 466 | if (!sock_flag(sk, SOCK_DEAD)) |
428 | sk->sk_data_ready(sk, err); | 467 | sk->sk_data_ready(sk, err); |
429 | return 0; | 468 | return NET_RX_SUCCESS; |
430 | } | 469 | } |
431 | 470 | ||
432 | /* Destroy connected sock. */ | 471 | /* Destroy connected sock. */ |
@@ -438,97 +477,126 @@ static void pipe_destruct(struct sock *sk) | |||
438 | skb_queue_purge(&pn->ctrlreq_queue); | 477 | skb_queue_purge(&pn->ctrlreq_queue); |
439 | } | 478 | } |
440 | 479 | ||
441 | static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) | 480 | static u8 pipe_negotiate_fc(const u8 *fcs, unsigned n) |
481 | { | ||
482 | unsigned i; | ||
483 | u8 final_fc = PN_NO_FLOW_CONTROL; | ||
484 | |||
485 | for (i = 0; i < n; i++) { | ||
486 | u8 fc = fcs[i]; | ||
487 | |||
488 | if (fc > final_fc && fc < PN_MAX_FLOW_CONTROL) | ||
489 | final_fc = fc; | ||
490 | } | ||
491 | return final_fc; | ||
492 | } | ||
493 | |||
494 | static int pep_connresp_rcv(struct sock *sk, struct sk_buff *skb) | ||
442 | { | 495 | { |
443 | struct sock *newsk; | 496 | struct pep_sock *pn = pep_sk(sk); |
444 | struct pep_sock *newpn, *pn = pep_sk(sk); | ||
445 | struct pnpipehdr *hdr; | 497 | struct pnpipehdr *hdr; |
446 | struct sockaddr_pn dst; | 498 | u8 n_sb; |
447 | u16 peer_type; | ||
448 | u8 pipe_handle, enabled, n_sb; | ||
449 | u8 aligned = 0; | ||
450 | 499 | ||
451 | if (!pskb_pull(skb, sizeof(*hdr) + 4)) | 500 | if (!pskb_pull(skb, sizeof(*hdr) + 4)) |
452 | return -EINVAL; | 501 | return -EINVAL; |
453 | 502 | ||
454 | hdr = pnp_hdr(skb); | 503 | hdr = pnp_hdr(skb); |
455 | pipe_handle = hdr->pipe_handle; | 504 | if (hdr->error_code != PN_PIPE_NO_ERROR) |
456 | switch (hdr->state_after_connect) { | 505 | return -ECONNREFUSED; |
457 | case PN_PIPE_DISABLE: | ||
458 | enabled = 0; | ||
459 | break; | ||
460 | case PN_PIPE_ENABLE: | ||
461 | enabled = 1; | ||
462 | break; | ||
463 | default: | ||
464 | pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | peer_type = hdr->other_pep_type << 8; | ||
468 | 506 | ||
469 | if (unlikely(sk->sk_state != TCP_LISTEN) || sk_acceptq_is_full(sk)) { | 507 | /* Parse sub-blocks */ |
470 | pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE); | ||
471 | return -ENOBUFS; | ||
472 | } | ||
473 | |||
474 | /* Parse sub-blocks (options) */ | ||
475 | n_sb = hdr->data[4]; | 508 | n_sb = hdr->data[4]; |
476 | while (n_sb > 0) { | 509 | while (n_sb > 0) { |
477 | u8 type, buf[1], len = sizeof(buf); | 510 | u8 type, buf[6], len = sizeof(buf); |
478 | const u8 *data = pep_get_sb(skb, &type, &len, buf); | 511 | const u8 *data = pep_get_sb(skb, &type, &len, buf); |
479 | 512 | ||
480 | if (data == NULL) | 513 | if (data == NULL) |
481 | return -EINVAL; | 514 | return -EINVAL; |
515 | |||
482 | switch (type) { | 516 | switch (type) { |
483 | case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: | 517 | case PN_PIPE_SB_REQUIRED_FC_TX: |
484 | if (len < 1) | 518 | if (len < 2 || len < data[0]) |
485 | return -EINVAL; | 519 | break; |
486 | peer_type = (peer_type & 0xff00) | data[0]; | 520 | pn->tx_fc = pipe_negotiate_fc(data + 2, len - 2); |
487 | break; | 521 | break; |
488 | case PN_PIPE_SB_ALIGNED_DATA: | 522 | |
489 | aligned = data[0] != 0; | 523 | case PN_PIPE_SB_PREFERRED_FC_RX: |
524 | if (len < 2 || len < data[0]) | ||
525 | break; | ||
526 | pn->rx_fc = pipe_negotiate_fc(data + 2, len - 2); | ||
490 | break; | 527 | break; |
528 | |||
491 | } | 529 | } |
492 | n_sb--; | 530 | n_sb--; |
493 | } | 531 | } |
494 | 532 | ||
495 | skb = skb_clone(skb, GFP_ATOMIC); | 533 | return pipe_handler_send_created_ind(sk); |
496 | if (!skb) | 534 | } |
497 | return -ENOMEM; | ||
498 | 535 | ||
499 | /* Create a new to-be-accepted sock */ | 536 | /* Queue an skb to an actively connected sock. |
500 | newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot); | 537 | * Socket lock must be held. */ |
501 | if (!newsk) { | 538 | static int pipe_handler_do_rcv(struct sock *sk, struct sk_buff *skb) |
502 | kfree_skb(skb); | 539 | { |
503 | return -ENOMEM; | 540 | struct pep_sock *pn = pep_sk(sk); |
504 | } | 541 | struct pnpipehdr *hdr = pnp_hdr(skb); |
505 | sock_init_data(NULL, newsk); | 542 | int err = NET_RX_SUCCESS; |
506 | newsk->sk_state = TCP_SYN_RECV; | ||
507 | newsk->sk_backlog_rcv = pipe_do_rcv; | ||
508 | newsk->sk_protocol = sk->sk_protocol; | ||
509 | newsk->sk_destruct = pipe_destruct; | ||
510 | 543 | ||
511 | newpn = pep_sk(newsk); | 544 | switch (hdr->message_id) { |
512 | pn_skb_get_dst_sockaddr(skb, &dst); | 545 | case PNS_PIPE_ALIGNED_DATA: |
513 | newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); | 546 | __skb_pull(skb, 1); |
514 | newpn->pn_sk.resource = pn->pn_sk.resource; | 547 | /* fall through */ |
515 | skb_queue_head_init(&newpn->ctrlreq_queue); | 548 | case PNS_PIPE_DATA: |
516 | newpn->pipe_handle = pipe_handle; | 549 | __skb_pull(skb, 3); /* Pipe data header */ |
517 | atomic_set(&newpn->tx_credits, 0); | 550 | if (!pn_flow_safe(pn->rx_fc)) { |
518 | newpn->peer_type = peer_type; | 551 | err = sock_queue_rcv_skb(sk, skb); |
519 | newpn->rx_credits = 0; | 552 | if (!err) |
520 | newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; | 553 | return NET_RX_SUCCESS; |
521 | newpn->init_enable = enabled; | 554 | err = NET_RX_DROP; |
522 | newpn->aligned = aligned; | 555 | break; |
556 | } | ||
523 | 557 | ||
524 | BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue)); | 558 | if (pn->rx_credits == 0) { |
525 | skb_queue_head(&newsk->sk_receive_queue, skb); | 559 | atomic_inc(&sk->sk_drops); |
526 | if (!sock_flag(sk, SOCK_DEAD)) | 560 | err = NET_RX_DROP; |
527 | sk->sk_data_ready(sk, 0); | 561 | break; |
562 | } | ||
563 | pn->rx_credits--; | ||
564 | skb->dev = NULL; | ||
565 | skb_set_owner_r(skb, sk); | ||
566 | err = skb->len; | ||
567 | skb_queue_tail(&sk->sk_receive_queue, skb); | ||
568 | if (!sock_flag(sk, SOCK_DEAD)) | ||
569 | sk->sk_data_ready(sk, err); | ||
570 | return NET_RX_SUCCESS; | ||
528 | 571 | ||
529 | sk_acceptq_added(sk); | 572 | case PNS_PEP_CONNECT_RESP: |
530 | sk_add_node(newsk, &pn->ackq); | 573 | if (sk->sk_state != TCP_SYN_SENT) |
531 | return 0; | 574 | break; |
575 | if (!sock_flag(sk, SOCK_DEAD)) | ||
576 | sk->sk_state_change(sk); | ||
577 | if (pep_connresp_rcv(sk, skb)) { | ||
578 | sk->sk_state = TCP_CLOSE_WAIT; | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | sk->sk_state = TCP_ESTABLISHED; | ||
583 | if (!pn_flow_safe(pn->tx_fc)) { | ||
584 | atomic_set(&pn->tx_credits, 1); | ||
585 | sk->sk_write_space(sk); | ||
586 | } | ||
587 | pipe_grant_credits(sk, GFP_ATOMIC); | ||
588 | break; | ||
589 | |||
590 | case PNS_PEP_DISCONNECT_RESP: | ||
591 | /* sock should already be dead, nothing to do */ | ||
592 | break; | ||
593 | |||
594 | case PNS_PEP_STATUS_IND: | ||
595 | pipe_rcv_status(sk, skb); | ||
596 | break; | ||
597 | } | ||
598 | kfree_skb(skb); | ||
599 | return err; | ||
532 | } | 600 | } |
533 | 601 | ||
534 | /* Listening sock must be locked */ | 602 | /* Listening sock must be locked */ |
@@ -568,7 +636,6 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
568 | struct sock *sknode; | 636 | struct sock *sknode; |
569 | struct pnpipehdr *hdr; | 637 | struct pnpipehdr *hdr; |
570 | struct sockaddr_pn dst; | 638 | struct sockaddr_pn dst; |
571 | int err = NET_RX_SUCCESS; | ||
572 | u8 pipe_handle; | 639 | u8 pipe_handle; |
573 | 640 | ||
574 | if (!pskb_may_pull(skb, sizeof(*hdr))) | 641 | if (!pskb_may_pull(skb, sizeof(*hdr))) |
@@ -586,20 +653,18 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
586 | if (sknode) | 653 | if (sknode) |
587 | return sk_receive_skb(sknode, skb, 1); | 654 | return sk_receive_skb(sknode, skb, 1); |
588 | 655 | ||
589 | /* Look for a pipe handle pending accept */ | ||
590 | sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle); | ||
591 | if (sknode) { | ||
592 | sock_put(sknode); | ||
593 | if (net_ratelimit()) | ||
594 | printk(KERN_WARNING"Phonet unconnected PEP ignored"); | ||
595 | err = NET_RX_DROP; | ||
596 | goto drop; | ||
597 | } | ||
598 | |||
599 | switch (hdr->message_id) { | 656 | switch (hdr->message_id) { |
600 | case PNS_PEP_CONNECT_REQ: | 657 | case PNS_PEP_CONNECT_REQ: |
601 | err = pep_connreq_rcv(sk, skb); | 658 | if (sk->sk_state != TCP_LISTEN || sk_acceptq_is_full(sk)) { |
602 | break; | 659 | pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, |
660 | GFP_ATOMIC); | ||
661 | break; | ||
662 | } | ||
663 | skb_queue_head(&sk->sk_receive_queue, skb); | ||
664 | sk_acceptq_added(sk); | ||
665 | if (!sock_flag(sk, SOCK_DEAD)) | ||
666 | sk->sk_data_ready(sk, 0); | ||
667 | return NET_RX_SUCCESS; | ||
603 | 668 | ||
604 | case PNS_PEP_DISCONNECT_REQ: | 669 | case PNS_PEP_DISCONNECT_REQ: |
605 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); | 670 | pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); |
@@ -613,12 +678,35 @@ static int pep_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
613 | case PNS_PEP_ENABLE_REQ: | 678 | case PNS_PEP_ENABLE_REQ: |
614 | case PNS_PEP_DISABLE_REQ: | 679 | case PNS_PEP_DISABLE_REQ: |
615 | /* invalid handle is not even allowed here! */ | 680 | /* invalid handle is not even allowed here! */ |
681 | break; | ||
682 | |||
616 | default: | 683 | default: |
617 | err = NET_RX_DROP; | 684 | if ((1 << sk->sk_state) |
685 | & ~(TCPF_CLOSE|TCPF_LISTEN|TCPF_CLOSE_WAIT)) | ||
686 | /* actively connected socket */ | ||
687 | return pipe_handler_do_rcv(sk, skb); | ||
618 | } | 688 | } |
619 | drop: | 689 | drop: |
620 | kfree_skb(skb); | 690 | kfree_skb(skb); |
621 | return err; | 691 | return NET_RX_SUCCESS; |
692 | } | ||
693 | |||
694 | static int pipe_do_remove(struct sock *sk) | ||
695 | { | ||
696 | struct pep_sock *pn = pep_sk(sk); | ||
697 | struct pnpipehdr *ph; | ||
698 | struct sk_buff *skb; | ||
699 | |||
700 | skb = pep_alloc_skb(sk, NULL, 0, GFP_KERNEL); | ||
701 | if (!skb) | ||
702 | return -ENOMEM; | ||
703 | |||
704 | ph = pnp_hdr(skb); | ||
705 | ph->utid = 0; | ||
706 | ph->message_id = PNS_PIPE_REMOVE_REQ; | ||
707 | ph->pipe_handle = pn->pipe_handle; | ||
708 | ph->data[0] = PAD; | ||
709 | return pn_skb_send(sk, skb, NULL); | ||
622 | } | 710 | } |
623 | 711 | ||
624 | /* associated socket ceases to exist */ | 712 | /* associated socket ceases to exist */ |
@@ -631,15 +719,16 @@ static void pep_sock_close(struct sock *sk, long timeout) | |||
631 | sk_common_release(sk); | 719 | sk_common_release(sk); |
632 | 720 | ||
633 | lock_sock(sk); | 721 | lock_sock(sk); |
634 | if (sk->sk_state == TCP_LISTEN) { | 722 | if ((1 << sk->sk_state) & (TCPF_SYN_RECV|TCPF_ESTABLISHED)) { |
635 | /* Destroy the listen queue */ | 723 | if (sk->sk_backlog_rcv == pipe_do_rcv) |
636 | struct sock *sknode; | 724 | /* Forcefully remove dangling Phonet pipe */ |
637 | struct hlist_node *p, *n; | 725 | pipe_do_remove(sk); |
638 | 726 | else | |
639 | sk_for_each_safe(sknode, p, n, &pn->ackq) | 727 | pipe_handler_request(sk, PNS_PEP_DISCONNECT_REQ, PAD, |
640 | sk_del_node_init(sknode); | 728 | NULL, 0); |
641 | sk->sk_state = TCP_CLOSE; | ||
642 | } | 729 | } |
730 | sk->sk_state = TCP_CLOSE; | ||
731 | |||
643 | ifindex = pn->ifindex; | 732 | ifindex = pn->ifindex; |
644 | pn->ifindex = 0; | 733 | pn->ifindex = 0; |
645 | release_sock(sk); | 734 | release_sock(sk); |
@@ -649,73 +738,142 @@ static void pep_sock_close(struct sock *sk, long timeout) | |||
649 | sock_put(sk); | 738 | sock_put(sk); |
650 | } | 739 | } |
651 | 740 | ||
652 | static int pep_wait_connreq(struct sock *sk, int noblock) | 741 | static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) |
653 | { | 742 | { |
654 | struct task_struct *tsk = current; | 743 | struct pep_sock *pn = pep_sk(sk), *newpn; |
655 | struct pep_sock *pn = pep_sk(sk); | 744 | struct sock *newsk = NULL; |
656 | long timeo = sock_rcvtimeo(sk, noblock); | 745 | struct sk_buff *skb; |
657 | 746 | struct pnpipehdr *hdr; | |
658 | for (;;) { | 747 | struct sockaddr_pn dst, src; |
659 | DEFINE_WAIT(wait); | 748 | int err; |
749 | u16 peer_type; | ||
750 | u8 pipe_handle, enabled, n_sb; | ||
751 | u8 aligned = 0; | ||
660 | 752 | ||
661 | if (sk->sk_state != TCP_LISTEN) | 753 | skb = skb_recv_datagram(sk, 0, flags & O_NONBLOCK, errp); |
662 | return -EINVAL; | 754 | if (!skb) |
663 | if (!hlist_empty(&pn->ackq)) | 755 | return NULL; |
664 | break; | ||
665 | if (!timeo) | ||
666 | return -EWOULDBLOCK; | ||
667 | if (signal_pending(tsk)) | ||
668 | return sock_intr_errno(timeo); | ||
669 | 756 | ||
670 | prepare_to_wait_exclusive(sk_sleep(sk), &wait, | 757 | lock_sock(sk); |
671 | TASK_INTERRUPTIBLE); | 758 | if (sk->sk_state != TCP_LISTEN) { |
672 | release_sock(sk); | 759 | err = -EINVAL; |
673 | timeo = schedule_timeout(timeo); | 760 | goto drop; |
674 | lock_sock(sk); | ||
675 | finish_wait(sk_sleep(sk), &wait); | ||
676 | } | 761 | } |
762 | sk_acceptq_removed(sk); | ||
677 | 763 | ||
678 | return 0; | 764 | err = -EPROTO; |
679 | } | 765 | if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) |
766 | goto drop; | ||
680 | 767 | ||
681 | static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp) | 768 | hdr = pnp_hdr(skb); |
682 | { | 769 | pipe_handle = hdr->pipe_handle; |
683 | struct pep_sock *pn = pep_sk(sk); | 770 | switch (hdr->state_after_connect) { |
684 | struct sock *newsk = NULL; | 771 | case PN_PIPE_DISABLE: |
685 | struct sk_buff *oskb; | 772 | enabled = 0; |
686 | int err; | 773 | break; |
774 | case PN_PIPE_ENABLE: | ||
775 | enabled = 1; | ||
776 | break; | ||
777 | default: | ||
778 | pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM, | ||
779 | GFP_KERNEL); | ||
780 | goto drop; | ||
781 | } | ||
782 | peer_type = hdr->other_pep_type << 8; | ||
687 | 783 | ||
688 | lock_sock(sk); | 784 | /* Parse sub-blocks (options) */ |
689 | err = pep_wait_connreq(sk, flags & O_NONBLOCK); | 785 | n_sb = hdr->data[4]; |
690 | if (err) | 786 | while (n_sb > 0) { |
691 | goto out; | 787 | u8 type, buf[1], len = sizeof(buf); |
788 | const u8 *data = pep_get_sb(skb, &type, &len, buf); | ||
692 | 789 | ||
693 | newsk = __sk_head(&pn->ackq); | 790 | if (data == NULL) |
791 | goto drop; | ||
792 | switch (type) { | ||
793 | case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE: | ||
794 | if (len < 1) | ||
795 | goto drop; | ||
796 | peer_type = (peer_type & 0xff00) | data[0]; | ||
797 | break; | ||
798 | case PN_PIPE_SB_ALIGNED_DATA: | ||
799 | aligned = data[0] != 0; | ||
800 | break; | ||
801 | } | ||
802 | n_sb--; | ||
803 | } | ||
694 | 804 | ||
695 | oskb = skb_dequeue(&newsk->sk_receive_queue); | 805 | /* Check for duplicate pipe handle */ |
696 | err = pep_accept_conn(newsk, oskb); | 806 | newsk = pep_find_pipe(&pn->hlist, &dst, pipe_handle); |
697 | if (err) { | 807 | if (unlikely(newsk)) { |
698 | skb_queue_head(&newsk->sk_receive_queue, oskb); | 808 | __sock_put(newsk); |
699 | newsk = NULL; | 809 | newsk = NULL; |
700 | goto out; | 810 | pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE, GFP_KERNEL); |
811 | goto drop; | ||
812 | } | ||
813 | |||
814 | /* Create a new to-be-accepted sock */ | ||
815 | newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_KERNEL, sk->sk_prot); | ||
816 | if (!newsk) { | ||
817 | pep_reject_conn(sk, skb, PN_PIPE_ERR_OVERLOAD, GFP_KERNEL); | ||
818 | err = -ENOBUFS; | ||
819 | goto drop; | ||
701 | } | 820 | } |
702 | kfree_skb(oskb); | ||
703 | 821 | ||
822 | sock_init_data(NULL, newsk); | ||
823 | newsk->sk_state = TCP_SYN_RECV; | ||
824 | newsk->sk_backlog_rcv = pipe_do_rcv; | ||
825 | newsk->sk_protocol = sk->sk_protocol; | ||
826 | newsk->sk_destruct = pipe_destruct; | ||
827 | |||
828 | newpn = pep_sk(newsk); | ||
829 | pn_skb_get_dst_sockaddr(skb, &dst); | ||
830 | pn_skb_get_src_sockaddr(skb, &src); | ||
831 | newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst); | ||
832 | newpn->pn_sk.dobject = pn_sockaddr_get_object(&src); | ||
833 | newpn->pn_sk.resource = pn_sockaddr_get_resource(&dst); | ||
704 | sock_hold(sk); | 834 | sock_hold(sk); |
705 | pep_sk(newsk)->listener = sk; | 835 | newpn->listener = sk; |
836 | skb_queue_head_init(&newpn->ctrlreq_queue); | ||
837 | newpn->pipe_handle = pipe_handle; | ||
838 | atomic_set(&newpn->tx_credits, 0); | ||
839 | newpn->ifindex = 0; | ||
840 | newpn->peer_type = peer_type; | ||
841 | newpn->rx_credits = 0; | ||
842 | newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; | ||
843 | newpn->init_enable = enabled; | ||
844 | newpn->aligned = aligned; | ||
706 | 845 | ||
707 | sock_hold(newsk); | 846 | err = pep_accept_conn(newsk, skb); |
708 | sk_del_node_init(newsk); | 847 | if (err) { |
709 | sk_acceptq_removed(sk); | 848 | sock_put(newsk); |
849 | newsk = NULL; | ||
850 | goto drop; | ||
851 | } | ||
710 | sk_add_node(newsk, &pn->hlist); | 852 | sk_add_node(newsk, &pn->hlist); |
711 | __sock_put(newsk); | 853 | drop: |
712 | |||
713 | out: | ||
714 | release_sock(sk); | 854 | release_sock(sk); |
855 | kfree_skb(skb); | ||
715 | *errp = err; | 856 | *errp = err; |
716 | return newsk; | 857 | return newsk; |
717 | } | 858 | } |
718 | 859 | ||
860 | static int pep_sock_connect(struct sock *sk, struct sockaddr *addr, int len) | ||
861 | { | ||
862 | struct pep_sock *pn = pep_sk(sk); | ||
863 | int err; | ||
864 | u8 data[4] = { 0 /* sub-blocks */, PAD, PAD, PAD }; | ||
865 | |||
866 | pn->pipe_handle = 1; /* anything but INVALID_HANDLE */ | ||
867 | err = pipe_handler_request(sk, PNS_PEP_CONNECT_REQ, | ||
868 | PN_PIPE_ENABLE, data, 4); | ||
869 | if (err) { | ||
870 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | ||
871 | return err; | ||
872 | } | ||
873 | sk->sk_state = TCP_SYN_SENT; | ||
874 | return 0; | ||
875 | } | ||
876 | |||
719 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) | 877 | static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg) |
720 | { | 878 | { |
721 | struct pep_sock *pn = pep_sk(sk); | 879 | struct pep_sock *pn = pep_sk(sk); |
@@ -745,10 +903,18 @@ static int pep_init(struct sock *sk) | |||
745 | { | 903 | { |
746 | struct pep_sock *pn = pep_sk(sk); | 904 | struct pep_sock *pn = pep_sk(sk); |
747 | 905 | ||
748 | INIT_HLIST_HEAD(&pn->ackq); | 906 | sk->sk_destruct = pipe_destruct; |
749 | INIT_HLIST_HEAD(&pn->hlist); | 907 | INIT_HLIST_HEAD(&pn->hlist); |
908 | pn->listener = NULL; | ||
750 | skb_queue_head_init(&pn->ctrlreq_queue); | 909 | skb_queue_head_init(&pn->ctrlreq_queue); |
910 | atomic_set(&pn->tx_credits, 0); | ||
911 | pn->ifindex = 0; | ||
912 | pn->peer_type = 0; | ||
751 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; | 913 | pn->pipe_handle = PN_PIPE_INVALID_HANDLE; |
914 | pn->rx_credits = 0; | ||
915 | pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL; | ||
916 | pn->init_enable = 1; | ||
917 | pn->aligned = 0; | ||
752 | return 0; | 918 | return 0; |
753 | } | 919 | } |
754 | 920 | ||
@@ -792,6 +958,7 @@ static int pep_setsockopt(struct sock *sk, int level, int optname, | |||
792 | err = 0; | 958 | err = 0; |
793 | } | 959 | } |
794 | goto out_norel; | 960 | goto out_norel; |
961 | |||
795 | default: | 962 | default: |
796 | err = -ENOPROTOOPT; | 963 | err = -ENOPROTOOPT; |
797 | } | 964 | } |
@@ -816,9 +983,17 @@ static int pep_getsockopt(struct sock *sk, int level, int optname, | |||
816 | case PNPIPE_ENCAP: | 983 | case PNPIPE_ENCAP: |
817 | val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; | 984 | val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE; |
818 | break; | 985 | break; |
986 | |||
819 | case PNPIPE_IFINDEX: | 987 | case PNPIPE_IFINDEX: |
820 | val = pn->ifindex; | 988 | val = pn->ifindex; |
821 | break; | 989 | break; |
990 | |||
991 | case PNPIPE_HANDLE: | ||
992 | val = pn->pipe_handle; | ||
993 | if (val == PN_PIPE_INVALID_HANDLE) | ||
994 | return -EINVAL; | ||
995 | break; | ||
996 | |||
822 | default: | 997 | default: |
823 | return -ENOPROTOOPT; | 998 | return -ENOPROTOOPT; |
824 | } | 999 | } |
@@ -835,6 +1010,7 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
835 | { | 1010 | { |
836 | struct pep_sock *pn = pep_sk(sk); | 1011 | struct pep_sock *pn = pep_sk(sk); |
837 | struct pnpipehdr *ph; | 1012 | struct pnpipehdr *ph; |
1013 | int err; | ||
838 | 1014 | ||
839 | if (pn_flow_safe(pn->tx_fc) && | 1015 | if (pn_flow_safe(pn->tx_fc) && |
840 | !atomic_add_unless(&pn->tx_credits, -1, 0)) { | 1016 | !atomic_add_unless(&pn->tx_credits, -1, 0)) { |
@@ -852,8 +1028,12 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) | |||
852 | } else | 1028 | } else |
853 | ph->message_id = PNS_PIPE_DATA; | 1029 | ph->message_id = PNS_PIPE_DATA; |
854 | ph->pipe_handle = pn->pipe_handle; | 1030 | ph->pipe_handle = pn->pipe_handle; |
1031 | err = pn_skb_send(sk, skb, NULL); | ||
1032 | |||
1033 | if (err && pn_flow_safe(pn->tx_fc)) | ||
1034 | atomic_inc(&pn->tx_credits); | ||
1035 | return err; | ||
855 | 1036 | ||
856 | return pn_skb_send(sk, skb, &pipe_srv); | ||
857 | } | 1037 | } |
858 | 1038 | ||
859 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | 1039 | static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, |
@@ -873,9 +1053,9 @@ static int pep_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
873 | skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, | 1053 | skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len, |
874 | flags & MSG_DONTWAIT, &err); | 1054 | flags & MSG_DONTWAIT, &err); |
875 | if (!skb) | 1055 | if (!skb) |
876 | return -ENOBUFS; | 1056 | return err; |
877 | 1057 | ||
878 | skb_reserve(skb, MAX_PHONET_HEADER + 3); | 1058 | skb_reserve(skb, MAX_PHONET_HEADER + 3 + pn->aligned); |
879 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); | 1059 | err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); |
880 | if (err < 0) | 1060 | if (err < 0) |
881 | goto outfree; | 1061 | goto outfree; |
@@ -977,7 +1157,7 @@ struct sk_buff *pep_read(struct sock *sk) | |||
977 | struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); | 1157 | struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); |
978 | 1158 | ||
979 | if (sk->sk_state == TCP_ESTABLISHED) | 1159 | if (sk->sk_state == TCP_ESTABLISHED) |
980 | pipe_grant_credits(sk); | 1160 | pipe_grant_credits(sk, GFP_ATOMIC); |
981 | return skb; | 1161 | return skb; |
982 | } | 1162 | } |
983 | 1163 | ||
@@ -1022,7 +1202,7 @@ static int pep_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
1022 | } | 1202 | } |
1023 | 1203 | ||
1024 | if (sk->sk_state == TCP_ESTABLISHED) | 1204 | if (sk->sk_state == TCP_ESTABLISHED) |
1025 | pipe_grant_credits(sk); | 1205 | pipe_grant_credits(sk, GFP_KERNEL); |
1026 | release_sock(sk); | 1206 | release_sock(sk); |
1027 | copy: | 1207 | copy: |
1028 | msg->msg_flags |= MSG_EOR; | 1208 | msg->msg_flags |= MSG_EOR; |
@@ -1045,8 +1225,10 @@ static void pep_sock_unhash(struct sock *sk) | |||
1045 | struct sock *skparent = NULL; | 1225 | struct sock *skparent = NULL; |
1046 | 1226 | ||
1047 | lock_sock(sk); | 1227 | lock_sock(sk); |
1048 | if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) { | 1228 | |
1229 | if (pn->listener != NULL) { | ||
1049 | skparent = pn->listener; | 1230 | skparent = pn->listener; |
1231 | pn->listener = NULL; | ||
1050 | release_sock(sk); | 1232 | release_sock(sk); |
1051 | 1233 | ||
1052 | pn = pep_sk(skparent); | 1234 | pn = pep_sk(skparent); |
@@ -1054,6 +1236,7 @@ static void pep_sock_unhash(struct sock *sk) | |||
1054 | sk_del_node_init(sk); | 1236 | sk_del_node_init(sk); |
1055 | sk = skparent; | 1237 | sk = skparent; |
1056 | } | 1238 | } |
1239 | |||
1057 | /* Unhash a listening sock only when it is closed | 1240 | /* Unhash a listening sock only when it is closed |
1058 | * and all of its active connected pipes are closed. */ | 1241 | * and all of its active connected pipes are closed. */ |
1059 | if (hlist_empty(&pn->hlist)) | 1242 | if (hlist_empty(&pn->hlist)) |
@@ -1067,6 +1250,7 @@ static void pep_sock_unhash(struct sock *sk) | |||
1067 | static struct proto pep_proto = { | 1250 | static struct proto pep_proto = { |
1068 | .close = pep_sock_close, | 1251 | .close = pep_sock_close, |
1069 | .accept = pep_sock_accept, | 1252 | .accept = pep_sock_accept, |
1253 | .connect = pep_sock_connect, | ||
1070 | .ioctl = pep_ioctl, | 1254 | .ioctl = pep_ioctl, |
1071 | .init = pep_init, | 1255 | .init = pep_init, |
1072 | .setsockopt = pep_setsockopt, | 1256 | .setsockopt = pep_setsockopt, |