diff options
author | Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> | 2012-03-11 06:28:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-03-11 18:38:16 -0400 |
commit | 374458b3fe4288f820dbf3de0728e314d969f9e4 (patch) | |
tree | 5249fa436617d45cd2c3e5fad60732fc6d1a0e94 /net/caif/cfrfml.c | |
parent | e8abbe0d0236ac1d55d21fec7a8d2ee03e9d3258 (diff) |
caif: Fix for a race in socket transmit with flow control.
Kill faulty checks on flow-off leading to connection drop at race conditions.
caif_socket checks for flow-on before transmitting and goes to sleep or
return -EAGAIN upon flow stop. Remove faulty subsequent checks on flow-off
leading to connection drop. Also fix memory leaks on some of the errors paths.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/caif/cfrfml.c')
-rw-r--r-- | net/caif/cfrfml.c | 25 |
1 files changed, 11 insertions, 14 deletions
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index 6dc75d4f8d94..2b563ad04597 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c | |||
@@ -184,6 +184,11 @@ out: | |||
184 | rfml->serv.dev_info.id); | 184 | rfml->serv.dev_info.id); |
185 | } | 185 | } |
186 | spin_unlock(&rfml->sync); | 186 | spin_unlock(&rfml->sync); |
187 | |||
188 | if (unlikely(err == -EAGAIN)) | ||
189 | /* It is not possible to recover after drop of a fragment */ | ||
190 | err = -EIO; | ||
191 | |||
187 | return err; | 192 | return err; |
188 | } | 193 | } |
189 | 194 | ||
@@ -218,7 +223,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
218 | caif_assert(layr->dn->transmit != NULL); | 223 | caif_assert(layr->dn->transmit != NULL); |
219 | 224 | ||
220 | if (!cfsrvl_ready(&rfml->serv, &err)) | 225 | if (!cfsrvl_ready(&rfml->serv, &err)) |
221 | return err; | 226 | goto out; |
222 | 227 | ||
223 | err = -EPROTO; | 228 | err = -EPROTO; |
224 | if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) | 229 | if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) |
@@ -251,8 +256,11 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
251 | 256 | ||
252 | err = cfrfml_transmit_segment(rfml, frontpkt); | 257 | err = cfrfml_transmit_segment(rfml, frontpkt); |
253 | 258 | ||
254 | if (err != 0) | 259 | if (err != 0) { |
260 | frontpkt = NULL; | ||
255 | goto out; | 261 | goto out; |
262 | } | ||
263 | |||
256 | frontpkt = rearpkt; | 264 | frontpkt = rearpkt; |
257 | rearpkt = NULL; | 265 | rearpkt = NULL; |
258 | 266 | ||
@@ -286,19 +294,8 @@ out: | |||
286 | if (rearpkt) | 294 | if (rearpkt) |
287 | cfpkt_destroy(rearpkt); | 295 | cfpkt_destroy(rearpkt); |
288 | 296 | ||
289 | if (frontpkt && frontpkt != pkt) { | 297 | if (frontpkt) |
290 | |||
291 | cfpkt_destroy(frontpkt); | 298 | cfpkt_destroy(frontpkt); |
292 | /* | ||
293 | * Socket layer will free the original packet, | ||
294 | * but this packet may already be sent and | ||
295 | * freed. So we have to return 0 in this case | ||
296 | * to avoid socket layer to re-free this packet. | ||
297 | * The return of shutdown indication will | ||
298 | * cause connection to be invalidated anyhow. | ||
299 | */ | ||
300 | err = 0; | ||
301 | } | ||
302 | } | 299 | } |
303 | 300 | ||
304 | return err; | 301 | return err; |