Commit 374458b3 authored by Dmitry Tarnyagin's avatar Dmitry Tarnyagin Committed by David S. Miller

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: default avatarSjur Brændeland <sjur.brandeland@stericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e8abbe0d
...@@ -41,8 +41,10 @@ static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -41,8 +41,10 @@ static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
struct caif_payload_info *info; struct caif_payload_info *info;
int ret; int ret;
if (!cfsrvl_ready(service, &ret)) if (!cfsrvl_ready(service, &ret)) {
cfpkt_destroy(pkt);
return ret; return ret;
}
/* Add info for MUX-layer to route the packet out */ /* Add info for MUX-layer to route the packet out */
info = cfpkt_info(pkt); info = cfpkt_info(pkt);
......
...@@ -86,12 +86,17 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -86,12 +86,17 @@ static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
struct caif_payload_info *info; struct caif_payload_info *info;
struct cfsrvl *service = container_obj(layr); struct cfsrvl *service = container_obj(layr);
int ret; int ret;
if (!cfsrvl_ready(service, &ret))
if (!cfsrvl_ready(service, &ret)) {
cfpkt_destroy(pkt);
return ret; return ret;
}
/* STE Modem cannot handle more than 1500 bytes datagrams */ /* 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; return -EMSGSIZE;
}
cfpkt_add_head(pkt, &zero, 3); cfpkt_add_head(pkt, &zero, 3);
packet_type = 0x08; /* B9 set - UNCLASSIFIED */ packet_type = 0x08; /* B9 set - UNCLASSIFIED */
......
...@@ -184,6 +184,11 @@ static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt) ...@@ -184,6 +184,11 @@ static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
rfml->serv.dev_info.id); rfml->serv.dev_info.id);
} }
spin_unlock(&rfml->sync); spin_unlock(&rfml->sync);
if (unlikely(err == -EAGAIN))
/* It is not possible to recover after drop of a fragment */
err = -EIO;
return err; return err;
} }
...@@ -218,7 +223,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -218,7 +223,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr->dn->transmit != NULL); caif_assert(layr->dn->transmit != NULL);
if (!cfsrvl_ready(&rfml->serv, &err)) if (!cfsrvl_ready(&rfml->serv, &err))
return err; goto out;
err = -EPROTO; err = -EPROTO;
if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1) if (cfpkt_getlen(pkt) <= RFM_HEAD_SIZE-1)
...@@ -251,8 +256,11 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -251,8 +256,11 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
err = cfrfml_transmit_segment(rfml, frontpkt); err = cfrfml_transmit_segment(rfml, frontpkt);
if (err != 0) if (err != 0) {
frontpkt = NULL;
goto out; goto out;
}
frontpkt = rearpkt; frontpkt = rearpkt;
rearpkt = NULL; rearpkt = NULL;
...@@ -286,19 +294,8 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -286,19 +294,8 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
if (rearpkt) if (rearpkt)
cfpkt_destroy(rearpkt); cfpkt_destroy(rearpkt);
if (frontpkt && frontpkt != pkt) { if (frontpkt)
cfpkt_destroy(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; return err;
......
...@@ -174,15 +174,11 @@ void cfsrvl_init(struct cfsrvl *service, ...@@ -174,15 +174,11 @@ void cfsrvl_init(struct cfsrvl *service,
bool cfsrvl_ready(struct cfsrvl *service, int *err) bool cfsrvl_ready(struct cfsrvl *service, int *err)
{ {
if (service->open && service->modem_flow_on && service->phy_flow_on)
return true;
if (!service->open) { if (!service->open) {
*err = -ENOTCONN; *err = -ENOTCONN;
return false; return false;
} }
caif_assert(!(service->modem_flow_on && service->phy_flow_on)); return true;
*err = -EAGAIN;
return false;
} }
u8 cfsrvl_getphyid(struct cflayer *layer) u8 cfsrvl_getphyid(struct cflayer *layer)
......
...@@ -84,8 +84,11 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -84,8 +84,11 @@ static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
caif_assert(layr != NULL); caif_assert(layr != NULL);
caif_assert(layr->dn != NULL); caif_assert(layr->dn != NULL);
caif_assert(layr->dn->transmit != NULL); caif_assert(layr->dn->transmit != NULL);
if (!cfsrvl_ready(service, &ret))
if (!cfsrvl_ready(service, &ret)) {
cfpkt_destroy(pkt);
return ret; return ret;
}
cfpkt_add_head(pkt, &zero, 1); cfpkt_add_head(pkt, &zero, 1);
/* Add info for MUX-layer to route the packet out. */ /* Add info for MUX-layer to route the packet out. */
......
...@@ -50,8 +50,12 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt) ...@@ -50,8 +50,12 @@ static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt)
struct caif_payload_info *info; struct caif_payload_info *info;
u32 videoheader = 0; u32 videoheader = 0;
int ret; int ret;
if (!cfsrvl_ready(service, &ret))
if (!cfsrvl_ready(service, &ret)) {
cfpkt_destroy(pkt);
return ret; return ret;
}
cfpkt_add_head(pkt, &videoheader, 4); cfpkt_add_head(pkt, &videoheader, 4);
/* Add info for MUX-layer to route the packet out */ /* Add info for MUX-layer to route the packet out */
info = cfpkt_info(pkt); info = cfpkt_info(pkt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment