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

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
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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);
+7 −2
Original line number Diff line number Diff line
@@ -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 */
+11 −14
Original line number Diff line number Diff line
@@ -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;
+1 −5
Original line number Diff line number Diff line
@@ -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)
+4 −1
Original line number Diff line number Diff line
@@ -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. */
Loading