drivers: wireless: Fix tcp/udp connect with heavy bulk data traffic in gs2200m.c

Summary:
- During network stress testing, ASSERT happened in gs2200m_ioctl_connect()
- The test was nxplayer (http audio streaming) and repeating wget every 0.5sec
- gs2200m_ioctl_connect() calls gs2200m_send_cmd() to send an AT command
- Then it waits for a synchronous command response.
- However, if heavy tcp traffic happens on another socket, it can receive a bulk packet
- With this commit, if it receives such a packet then the packet is duplicated.
- After that, the duplicated packet is added to the packet queue and notify the userland.

Impact:
- Affect almost all use cases with gs2200m

Testing:
- Tested with both spresense:wifi and spresense:wifi_smp
- Tested with nxplayer (http audio streaming) and repeat wget

Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
This commit is contained in:
Masayuki Ishikawa 2020-10-27 10:35:43 +09:00 committed by Xiang Xiao
parent 162da1169e
commit 1e321ca032

View File

@ -1390,6 +1390,55 @@ static enum pkt_type_e _parse_pkt(FAR uint8_t *p, uint16_t len,
return pkt_ctx.type;
}
/****************************************************************************
* Name: _dup_pkt_dat_and_notify
****************************************************************************/
static void _dup_pkt_dat_and_notify(FAR struct gs2200m_dev_s *dev,
FAR struct pkt_dat_s *pkt_dat0)
{
struct pkt_dat_s *pkt_dat;
uint8_t c;
/* Only bulk data */
ASSERT(pkt_dat0->data && (0 == pkt_dat0->n));
/* Allocate a new pkt_dat */
pkt_dat = (FAR struct pkt_dat_s *)kmm_malloc(sizeof(struct pkt_dat_s));
ASSERT(pkt_dat);
/* Copy pkt_dat0 to pkt_dat */
memcpy(pkt_dat, pkt_dat0, sizeof(struct pkt_dat_s));
/* Allocate bulk data and copy */
pkt_dat->data = (FAR uint8_t *)kmm_malloc(pkt_dat0->len);
ASSERT(pkt_dat->data);
memcpy(pkt_dat->data, pkt_dat0->data, pkt_dat0->len);
/* Convert cid to c */
c = _cid_to_uint8(pkt_dat->cid);
/* Add the pkt_dat to the pkt_q */
dq_addlast((FAR dq_entry_t *)pkt_dat, &dev->pkt_q[c]);
dev->pkt_q_cnt[c]++;
/* NOTE: total_bulk must be updated
* Usually, total_bulk is updated in gs2200m_recv_pkt()
* However, the pkt_dat was duplicated from pkt_dat0
* So it needs to be updated, otherwise it will cause ASSERT
*/
dev->total_bulk += pkt_dat->len;
_notif_q_push(dev, pkt_dat->cid);
}
/****************************************************************************
* Name: gs2200m_recv_pkt
****************************************************************************/
@ -1452,6 +1501,7 @@ static enum pkt_type_e gs2200m_send_cmd(FAR struct gs2200m_dev_s *dev,
{
enum spi_status_e s;
enum pkt_type_e r = TYPE_SPI_ERROR;
bool bulk = false;
int n = 1;
/* Disable gs2200m irq to poll dready */
@ -1470,8 +1520,29 @@ retry:
goto errout;
}
retry_recv:
r = gs2200m_recv_pkt(dev, pkt_dat);
if ((TYPE_BULK_DATA_TCP == r || TYPE_BULK_DATA_UDP == r) && pkt_dat)
{
wlwarn("*** Found bulk data \n");
/* Bulk data found in the response,
* duplicate the packet and notify
*/
_dup_pkt_dat_and_notify(dev, pkt_dat);
/* release & initialize pkt_dat before retry */
_release_pkt_dat(dev, pkt_dat);
memset(pkt_dat, 0, sizeof(pkt_dat));
bulk = true;
goto retry_recv;
}
/* NOTE: retry in case of errors */
if ((TYPE_OK != r) && (0 <= --n))
@ -1490,6 +1561,11 @@ retry:
errout:
if (bulk)
{
wlwarn("*** Normal response r=%d \n", r);
}
/* Enable gs2200m irq again */
dev->lower->enable();
@ -1870,13 +1946,6 @@ static enum pkt_type_e gs2200m_start_server(FAR struct gs2200m_dev_s *dev,
memset(&pkt_dat, 0, sizeof(pkt_dat));
r = gs2200m_send_cmd(dev, cmd, &pkt_dat);
/* REVISIT:
* TYPE_BULK for other sockets might be received here,
* if the sockets have heavy bulk traffic.
* In this case, the packet should be queued and
* wait for a response to the NSTCP command.
*/
if (r != TYPE_OK || pkt_dat.n == 0)
{
goto errout;
@ -2259,13 +2328,6 @@ static int gs2200m_ioctl_connect(FAR struct gs2200m_dev_s *dev,
break;
default:
/* REVISIT:
* TYPE_BULK for other sockets might be received here,
* if the sockets have heavy bulk traffic.
* In this case, the packet should be queued and
* wait for a response to the NCTCP command.
*/
wlerr("+++ error: type=%d \n", type);
ASSERT(false);
ret = -EINVAL;