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>
This commit is contained in:
Dmitry Tarnyagin
2012-03-11 10:28:31 +00:00
committed by David S. Miller
parent e8abbe0d02
commit 374458b3fe
6 changed files with 31 additions and 24 deletions

View File

@@ -184,6 +184,11 @@ out:
rfml->serv.dev_info.id);
}
spin_unlock(&rfml->sync);
if (unlikely(err == -EAGAIN))
/* It is not possible to recover after drop of a fragment */
err = -EIO;
return err;
}
@@ -218,7 +223,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->dn->transmit != NULL);
if (!cfsrvl_ready(&rfml->serv, &err))
return err;
goto out;
err = -EPROTO;
if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1)
@@ -251,8 +256,11 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
err = cfrfml_transmit_segment(rfml, frontpkt);
if (err != 0)
if (err != 0) {
frontpkt = NULL;
goto out;
}
frontpkt = rearpkt;
rearpkt = NULL;
@@ -286,19 +294,8 @@ out:
if (rearpkt)
cfpkt_destroy(rearpkt);
if (frontpkt && frontpkt != pkt) {
if (frontpkt)
cfpkt_destroy(frontpkt);
/*
* Socket layer will free the original packet,
* but this packet may already be sent and
* freed. So we have to return 0 in this case
* to avoid socket layer to re-free this packet.
* The return of shutdown indication will
* cause connection to be invalidated anyhow.
*/
err = 0;
}
}
return err;