summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2012-03-11 10:28:31 +0000
committerDavid S. Miller <davem@davemloft.net>2012-03-11 15:38:16 -0700
commit374458b3fe4288f820dbf3de0728e314d969f9e4 (patch)
tree5249fa436617d45cd2c3e5fad60732fc6d1a0e94
parente8abbe0d0236ac1d55d21fec7a8d2ee03e9d3258 (diff)
downloadlinux-374458b3fe4288f820dbf3de0728e314d969f9e4.tar.bz2
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>
-rw-r--r--net/caif/cfdbgl.c4
-rw-r--r--net/caif/cfdgml.c9
-rw-r--r--net/caif/cfrfml.c25
-rw-r--r--net/caif/cfsrvl.c6
-rw-r--r--net/caif/cfutill.c5
-rw-r--r--net/caif/cfvidl.c6
6 files changed, 31 insertions, 24 deletions
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
index 65d6ef3cf9aa..2914659eb9b2 100644
--- a/net/caif/cfdbgl.c
+++ b/net/caif/cfdbgl.c
@@ -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);
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
index 0f5ff27aa41c..a63f4a5f5aff 100644
--- a/net/caif/cfdgml.c
+++ b/net/caif/cfdgml.c
@@ -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 */
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:
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;
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
index b99f5b22689d..4aa33d4496b6 100644
--- a/net/caif/cfsrvl.c
+++ b/net/caif/cfsrvl.c
@@ -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)
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
index 53e49f3e3af3..86d2dadb4b73 100644
--- a/net/caif/cfutill.c
+++ b/net/caif/cfutill.c
@@ -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. */
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
index e3f37db40ac3..a8e2a2d758a5 100644
--- a/net/caif/cfvidl.c
+++ b/net/caif/cfvidl.c
@@ -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);