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:
parent
e8abbe0d02
commit
374458b3fe
6 changed files with 31 additions and 24 deletions
|
@ -41,8 +41,10 @@ static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
|
|||
struct caif_payload_info *info;
|
||||
int ret;
|
||||
|
||||
if (!cfsrvl_ready(service, &ret))
|
||||
if (!cfsrvl_ready(service, &ret)) {
|
||||
cfpkt_destroy(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Add info for MUX-layer to route the packet out */
|
||||
info = cfpkt_info(pkt);
|
||||
|
|
|
@ -86,12 +86,17 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
|
|||
struct caif_payload_info *info;
|
||||
struct cfsrvl *service = container_obj(layr);
|
||||
int ret;
|
||||
if (!cfsrvl_ready(service, &ret))
|
||||
|
||||
if (!cfsrvl_ready(service, &ret)) {
|
||||
cfpkt_destroy(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* STE Modem cannot handle more than 1500 bytes datagrams */
|
||||
if (cfpkt_getlen(pkt) > DGM_MTU)
|
||||
if (cfpkt_getlen(pkt) > DGM_MTU) {
|
||||
cfpkt_destroy(pkt);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
cfpkt_add_head(pkt, &zero, 3);
|
||||
packet_type = 0x08; /* B9 set - UNCLASSIFIED */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -174,15 +174,11 @@ void cfsrvl_init(struct cfsrvl *service,
|
|||
|
||||
bool cfsrvl_ready(struct cfsrvl *service, int *err)
|
||||
{
|
||||
if (service->open && service->modem_flow_on && service->phy_flow_on)
|
||||
return true;
|
||||
if (!service->open) {
|
||||
*err = -ENOTCONN;
|
||||
return false;
|
||||
}
|
||||
caif_assert(!(service->modem_flow_on && service->phy_flow_on));
|
||||
*err = -EAGAIN;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 cfsrvl_getphyid(struct cflayer *layer)
|
||||
|
|
|
@ -84,8 +84,11 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
|
|||
caif_assert(layr != NULL);
|
||||
caif_assert(layr->dn != NULL);
|
||||
caif_assert(layr->dn->transmit != NULL);
|
||||
if (!cfsrvl_ready(service, &ret))
|
||||
|
||||
if (!cfsrvl_ready(service, &ret)) {
|
||||
cfpkt_destroy(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cfpkt_add_head(pkt, &zero, 1);
|
||||
/* Add info for MUX-layer to route the packet out. */
|
||||
|
|
|
@ -50,8 +50,12 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt)
|
|||
struct caif_payload_info *info;
|
||||
u32 videoheader = 0;
|
||||
int ret;
|
||||
if (!cfsrvl_ready(service, &ret))
|
||||
|
||||
if (!cfsrvl_ready(service, &ret)) {
|
||||
cfpkt_destroy(pkt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cfpkt_add_head(pkt, &videoheader, 4);
|
||||
/* Add info for MUX-layer to route the packet out */
|
||||
info = cfpkt_info(pkt);
|
||||
|
|
Loading…
Reference in a new issue