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 | |
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')
-rw-r--r-- | net/caif/cfdbgl.c | 4 | ||||
-rw-r--r-- | net/caif/cfdgml.c | 9 | ||||
-rw-r--r-- | net/caif/cfrfml.c | 25 | ||||
-rw-r--r-- | net/caif/cfsrvl.c | 6 | ||||
-rw-r--r-- | net/caif/cfutill.c | 5 | ||||
-rw-r--r-- | net/caif/cfvidl.c | 6 |
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) | |||
41 | struct caif_payload_info *info; | 41 | struct caif_payload_info *info; |
42 | int ret; | 42 | int ret; |
43 | 43 | ||
44 | if (!cfsrvl_ready(service, &ret)) | 44 | if (!cfsrvl_ready(service, &ret)) { |
45 | cfpkt_destroy(pkt); | ||
45 | return ret; | 46 | return ret; |
47 | } | ||
46 | 48 | ||
47 | /* Add info for MUX-layer to route the packet out */ | 49 | /* Add info for MUX-layer to route the packet out */ |
48 | info = cfpkt_info(pkt); | 50 | 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) | |||
86 | struct caif_payload_info *info; | 86 | struct caif_payload_info *info; |
87 | struct cfsrvl *service = container_obj(layr); | 87 | struct cfsrvl *service = container_obj(layr); |
88 | int ret; | 88 | int ret; |
89 | if (!cfsrvl_ready(service, &ret)) | 89 | |
90 | if (!cfsrvl_ready(service, &ret)) { | ||
91 | cfpkt_destroy(pkt); | ||
90 | return ret; | 92 | return ret; |
93 | } | ||
91 | 94 | ||
92 | /* STE Modem cannot handle more than 1500 bytes datagrams */ | 95 | /* STE Modem cannot handle more than 1500 bytes datagrams */ |
93 | if (cfpkt_getlen(pkt) > DGM_MTU) | 96 | if (cfpkt_getlen(pkt) > DGM_MTU) { |
97 | cfpkt_destroy(pkt); | ||
94 | return -EMSGSIZE; | 98 | return -EMSGSIZE; |
99 | } | ||
95 | 100 | ||
96 | cfpkt_add_head(pkt, &zero, 3); | 101 | cfpkt_add_head(pkt, &zero, 3); |
97 | packet_type = 0x08; /* B9 set - UNCLASSIFIED */ | 102 | 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: | |||
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; |
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, | |||
174 | 174 | ||
175 | bool cfsrvl_ready(struct cfsrvl *service, int *err) | 175 | bool cfsrvl_ready(struct cfsrvl *service, int *err) |
176 | { | 176 | { |
177 | if (service->open && service->modem_flow_on && service->phy_flow_on) | ||
178 | return true; | ||
179 | if (!service->open) { | 177 | if (!service->open) { |
180 | *err = -ENOTCONN; | 178 | *err = -ENOTCONN; |
181 | return false; | 179 | return false; |
182 | } | 180 | } |
183 | caif_assert(!(service->modem_flow_on && service->phy_flow_on)); | 181 | return true; |
184 | *err = -EAGAIN; | ||
185 | return false; | ||
186 | } | 182 | } |
187 | 183 | ||
188 | u8 cfsrvl_getphyid(struct cflayer *layer) | 184 | 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) | |||
84 | caif_assert(layr != NULL); | 84 | caif_assert(layr != NULL); |
85 | caif_assert(layr->dn != NULL); | 85 | caif_assert(layr->dn != NULL); |
86 | caif_assert(layr->dn->transmit != NULL); | 86 | caif_assert(layr->dn->transmit != NULL); |
87 | if (!cfsrvl_ready(service, &ret)) | 87 | |
88 | if (!cfsrvl_ready(service, &ret)) { | ||
89 | cfpkt_destroy(pkt); | ||
88 | return ret; | 90 | return ret; |
91 | } | ||
89 | 92 | ||
90 | cfpkt_add_head(pkt, &zero, 1); | 93 | cfpkt_add_head(pkt, &zero, 1); |
91 | /* Add info for MUX-layer to route the packet out. */ | 94 | /* 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) | |||
50 | struct caif_payload_info *info; | 50 | struct caif_payload_info *info; |
51 | u32 videoheader = 0; | 51 | u32 videoheader = 0; |
52 | int ret; | 52 | int ret; |
53 | if (!cfsrvl_ready(service, &ret)) | 53 | |
54 | if (!cfsrvl_ready(service, &ret)) { | ||
55 | cfpkt_destroy(pkt); | ||
54 | return ret; | 56 | return ret; |
57 | } | ||
58 | |||
55 | cfpkt_add_head(pkt, &videoheader, 4); | 59 | cfpkt_add_head(pkt, &videoheader, 4); |
56 | /* Add info for MUX-layer to route the packet out */ | 60 | /* Add info for MUX-layer to route the packet out */ |
57 | info = cfpkt_info(pkt); | 61 | info = cfpkt_info(pkt); |