diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-02-23 02:07:38 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-02-23 02:07:38 +0000 |
commit | 0362fd4c2229ac1cf9b2743d28e4389a6b8e1722 (patch) | |
tree | 2a6defc7f12a61c60e3e337e9ba8e8fd7e21f342 /nuttx | |
parent | a16ee47f0e0c64da88b21ad1baadd08f79193af6 (diff) | |
download | px4-firmware-0362fd4c2229ac1cf9b2743d28e4389a6b8e1722.tar.gz px4-firmware-0362fd4c2229ac1cf9b2743d28e4389a6b8e1722.tar.bz2 px4-firmware-0362fd4c2229ac1cf9b2743d28e4389a6b8e1722.zip |
(1) Fix a critical memory leak in the TCP read-ahead buffering logic; Add an option to suppress SDIO multi-block transfers in order to work around a buggy SDIO driver
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4415 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/ChangeLog | 2 | ||||
-rw-r--r-- | nuttx/Documentation/NuttxPortingGuide.html | 7 | ||||
-rw-r--r-- | nuttx/configs/README.txt | 3 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/dhcpd/defconfig | 4 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/nettest/defconfig | 4 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/nsh/defconfig | 6 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/nsh2/defconfig | 6 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/ostest/defconfig | 4 | ||||
-rw-r--r-- | nuttx/configs/stm3240g-eval/telnetd/defconfig | 4 | ||||
-rwxr-xr-x | nuttx/configs/stm32f4discovery/nsh/defconfig | 4 | ||||
-rwxr-xr-x | nuttx/configs/stm32f4discovery/ostest/defconfig | 4 | ||||
-rw-r--r-- | nuttx/drivers/mmcsd/mmcsd_sdio.c | 126 | ||||
-rw-r--r-- | nuttx/net/recvfrom.c | 112 | ||||
-rw-r--r-- | nuttx/net/uip/uip_internal.h | 12 | ||||
-rw-r--r-- | nuttx/net/uip/uip_tcpcallback.c | 152 |
15 files changed, 379 insertions, 71 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 4dd369ef4..27bd1cb7f 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -2482,3 +2482,5 @@ of TCP connection must be set up (just as with connect()). The new file net_monitor.c holds the common TCP connection monitoring logic used by both the accecpt() and connect() logic. Contributed by Max Nekludov. + * net/recvfrom.c and net/uip/uip_tcpcallback.c: Fix a leak in the TCP + read-ahead logic. This is a *critical* bug fix! diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index c9656a6c5..04f4611d0 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -12,7 +12,7 @@ <h1><big><font color="#3c34ec"> <i>NuttX RTOS Porting Guide</i> </font></big></h1> - <p>Last Updated: February 5, 2011</p> + <p>Last Updated: February 22, 2011</p> </td> </tr> </table> @@ -4474,6 +4474,11 @@ build <code>CONFIG_SDIO_WIDTH_D1_ONLY</code>: Select 1-bit transfer mode. Default: 4-bit transfer mode. </li> + <li> + <code>CONFIG_MMCSD_MULTIBLOCK_DISABLE</code>: Use only the single block transfer method. + This setting is used to work around buggy SDIO drivers that cannot handle + multiple block transfers. + </li> </ul> <h3>SDIO-based MMC/SD driver</h3> diff --git a/nuttx/configs/README.txt b/nuttx/configs/README.txt index fc8373df9..77d8a556b 100644 --- a/nuttx/configs/README.txt +++ b/nuttx/configs/README.txt @@ -710,6 +710,9 @@ defconfig -- This is a configuration file similar to the Linux or hardware resources are shared with other drivers. CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: 4-bit transfer mode. + CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. + This setting is used to work around buggy SDIO drivers that cannot handle + multiple block transfers. SDIO-based MMC/SD driver diff --git a/nuttx/configs/stm3240g-eval/dhcpd/defconfig b/nuttx/configs/stm3240g-eval/dhcpd/defconfig index 30ff4d545..b11a2d90a 100644 --- a/nuttx/configs/stm3240g-eval/dhcpd/defconfig +++ b/nuttx/configs/stm3240g-eval/dhcpd/defconfig @@ -699,6 +699,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -708,6 +711,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/configs/stm3240g-eval/nettest/defconfig b/nuttx/configs/stm3240g-eval/nettest/defconfig index 6fb7f862d..2f7d19956 100644 --- a/nuttx/configs/stm3240g-eval/nettest/defconfig +++ b/nuttx/configs/stm3240g-eval/nettest/defconfig @@ -699,6 +699,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -708,6 +711,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/configs/stm3240g-eval/nsh/defconfig b/nuttx/configs/stm3240g-eval/nsh/defconfig index bb4b25222..d3f9ecfa3 100644 --- a/nuttx/configs/stm3240g-eval/nsh/defconfig +++ b/nuttx/configs/stm3240g-eval/nsh/defconfig @@ -776,6 +776,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -785,6 +788,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n @@ -876,7 +880,7 @@ CONFIG_NET_RESOLV_ENTRIES=4 # CONFIG_DISABLE_PTHREAD - pthread support is required # CONFIG_DISABLE_POLL - poll() support is required # -CONFIG_FTPD_CMDBUFFERSIZE=512 +CONFIG_FTPD_CMDBUFFERSIZE=2048 # # RTC Configuration diff --git a/nuttx/configs/stm3240g-eval/nsh2/defconfig b/nuttx/configs/stm3240g-eval/nsh2/defconfig index 1160cc96d..05f41123c 100644 --- a/nuttx/configs/stm3240g-eval/nsh2/defconfig +++ b/nuttx/configs/stm3240g-eval/nsh2/defconfig @@ -777,6 +777,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -786,6 +789,7 @@ CONFIG_SDIO_DMA=y #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n @@ -877,7 +881,7 @@ CONFIG_NET_RESOLV_ENTRIES=4 # CONFIG_DISABLE_PTHREAD - pthread support is required # CONFIG_DISABLE_POLL - poll() support is required # -CONFIG_FTPD_CMDBUFFERSIZE=512 +CONFIG_FTPD_CMDBUFFERSIZE=2048 # # RTC Configuration diff --git a/nuttx/configs/stm3240g-eval/ostest/defconfig b/nuttx/configs/stm3240g-eval/ostest/defconfig index d95fc96e7..78a23b09a 100644 --- a/nuttx/configs/stm3240g-eval/ostest/defconfig +++ b/nuttx/configs/stm3240g-eval/ostest/defconfig @@ -687,6 +687,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -696,6 +699,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/configs/stm3240g-eval/telnetd/defconfig b/nuttx/configs/stm3240g-eval/telnetd/defconfig index 7a1394e9f..0726e0e12 100644 --- a/nuttx/configs/stm3240g-eval/telnetd/defconfig +++ b/nuttx/configs/stm3240g-eval/telnetd/defconfig @@ -699,6 +699,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -708,6 +711,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/configs/stm32f4discovery/nsh/defconfig b/nuttx/configs/stm32f4discovery/nsh/defconfig index e4e8789c3..ea5400882 100755 --- a/nuttx/configs/stm32f4discovery/nsh/defconfig +++ b/nuttx/configs/stm32f4discovery/nsh/defconfig @@ -706,6 +706,9 @@ CONFIG_FS_WRITEBUFFER=n # Default: Medium # CONFIG_SDIO_WIDTH_D1_ONLY - Select 1-bit transfer mode. Default: # 4-bit transfer mode. +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT @@ -715,6 +718,7 @@ CONFIG_SDIO_DMA=n #CONFIG_SDIO_PRI=128 #CONFIG_SDIO_DMAPRIO #CONFIG_SDIO_WIDTH_D1_ONLY +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/configs/stm32f4discovery/ostest/defconfig b/nuttx/configs/stm32f4discovery/ostest/defconfig index 27cbb770d..60169385e 100755 --- a/nuttx/configs/stm32f4discovery/ostest/defconfig +++ b/nuttx/configs/stm32f4discovery/ostest/defconfig @@ -672,12 +672,16 @@ CONFIG_FS_WRITEBUFFER=n # # CONFIG_SDIO_DMA # SDIO driver supports DMA +# CONFIG_MMCSD_MULTIBLOCK_DISABLE - Use only the single block transfer method. +# This setting is used to work around buggy drivers that cannot handle +# multiple block transfers. # CONFIG_MMCSD_MMCSUPPORT # Enable support for MMC cards # CONFIG_MMCSD_HAVECARDDETECT # SDIO driver card detection is 100% accurate # CONFIG_SDIO_DMA=n +CONFIG_MMCSD_MULTIBLOCK_DISABLE=y CONFIG_MMCSD_MMCSUPPORT=n CONFIG_MMCSD_HAVECARDDETECT=n diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c index 09c4efedf..20ef3ebe6 100644 --- a/nuttx/drivers/mmcsd/mmcsd_sdio.c +++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c @@ -188,13 +188,17 @@ static bool mmcsd_wrprotected(FAR struct mmcsd_state_s *priv); static int mmcsd_eventwait(FAR struct mmcsd_state_s *priv, sdio_eventset_t failevents, uint32_t timeout); static int mmcsd_transferready(FAR struct mmcsd_state_s *priv); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv); +#endif static int mmcsd_setblocklen(FAR struct mmcsd_state_s *priv, uint32_t blocklen); static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock, size_t nblocks); +#endif #ifdef CONFIG_FS_READAHEAD static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, size_t nblocks); @@ -202,8 +206,10 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, #ifdef CONFIG_FS_WRITABLE static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock); +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks); +#endif #ifdef CONFIG_FS_WRITEBUFFER static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, size_t nblocks); @@ -1190,6 +1196,7 @@ static int mmcsd_transferready(FAR struct mmcsd_state_s *priv) * ****************************************************************************/ +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv) { int ret; @@ -1204,6 +1211,7 @@ static int mmcsd_stoptransmission(FAR struct mmcsd_state_s *priv) } return ret; } +#endif /**************************************************************************** * Name: mmcsd_setblocklen @@ -1355,6 +1363,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv, * ****************************************************************************/ +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, FAR uint8_t *buffer, off_t startblock, size_t nblocks) @@ -1461,6 +1470,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv, return nblocks; } +#endif /**************************************************************************** * Name: mmcsd_reload @@ -1476,10 +1486,35 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, off_t startblock, size_t nblocks) { FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + size_t block; + size_t endblock; +#endif ssize_t ret; DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + /* Read each block using only the single block transfer method */ + + endblock = startblock + nblocks - 1; + for (block = startblock; block <= endblock; block++) + { + /* Read this block into the user buffer */ + + ret = mmcsd_readsingle(priv, buffer, block); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } +#else + /* Use either the single- or muliple-block transfer method */ + if (nblocks == 1) { ret = mmcsd_readsingle(priv, buffer, startblock); @@ -1488,6 +1523,7 @@ static ssize_t mmcsd_reload(FAR void *dev, FAR uint8_t *buffer, { ret = mmcsd_readmultiple(priv, buffer, startblock, nblocks); } +#endif /* On success, return the number of blocks read */ @@ -1614,7 +1650,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv, * ****************************************************************************/ -#ifdef CONFIG_FS_WRITABLE +#if defined(CONFIG_FS_WRITABLE) && !defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, FAR const uint8_t *buffer, off_t startblock, size_t nblocks) @@ -1773,10 +1809,33 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, off_t startblock, size_t nblocks) { FAR struct mmcsd_state_s *priv = (FAR struct mmcsd_state_s *)dev; +#ifndef CONFIG_MMCSD_MULTIBLOCK_DISABLE + size_t block; + size_t endblock; +#endif ssize_t ret; DEBUGASSERT(priv != NULL && buffer != NULL && nblocks > 0) +#ifdef CONFIG_MMCSD_MULTIBLOCK_DISABLE + /* Write each block using only the single block transfer method */ + + endblock = startblock + nblocks - 1; + for (block = startblock; block <= endblock; block++) + { + /* Write this block from the user buffer */ + + ret = mmcsd_writesingle(priv, buffer, block); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } +#else if (nblocks == 1) { ret = mmcsd_writesingle(priv, buffer, startblock); @@ -1785,6 +1844,7 @@ static ssize_t mmcsd_flush(FAR void *dev, FAR const uint8_t *buffer, { ret = mmcsd_writemultiple(priv, buffer, startblock, nblocks); } +#endif /* On success, return the number of blocks written */ @@ -1856,6 +1916,10 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, size_t startsector, unsigned int nsectors) { FAR struct mmcsd_state_s *priv; +#if !defined(CONFIG_FS_READAHEAD) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + size_t sector; + size_t endsector; +#endif ssize_t ret = 0; DEBUGASSERT(inode && inode->i_private); @@ -1866,9 +1930,33 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, if (nsectors > 0) { mmcsd_takesem(priv); -#ifdef CONFIG_FS_READAHEAD + +#if defined(CONFIG_FS_READAHEAD) + /* Get the data from the read-ahead buffer */ + ret = rwb_read(&priv->rwbuffer, startsector, nsectors, buffer); + +#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + /* Read each block using only the single block transfer method */ + + endsector = startsector + nsectors - 1; + for (sector = startsector; sector <= endsector; sector++) + { + /* Read this sector into the user buffer */ + + ret = mmcsd_readsingle(priv, buffer, sector); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the sector size */ + + buffer += priv->blocksize; + } #else + /* Use either the single- or muliple-block transfer method */ + if (nsectors == 1) { ret = mmcsd_readsingle(priv, buffer, startsector); @@ -1896,20 +1984,48 @@ static ssize_t mmcsd_read(FAR struct inode *inode, unsigned char *buffer, ****************************************************************************/ #ifdef CONFIG_FS_WRITABLE -static ssize_t mmcsd_write(FAR struct inode *inode, const unsigned char *buffer, +static ssize_t mmcsd_write(FAR struct inode *inode, FAR const unsigned char *buffer, size_t startsector, unsigned int nsectors) { FAR struct mmcsd_state_s *priv; - int ret; +#if !defined(CONFIG_FS_WRITEBUFFER) && defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + size_t sector; + size_t endsector; +#endif + ssize_t ret = 0; fvdbg("sector: %d nsectors: %d sectorsize: %d\n"); DEBUGASSERT(inode && inode->i_private); priv = (FAR struct mmcsd_state_s *)inode->i_private; mmcsd_takesem(priv); -#ifdef CONFIG_FS_WRITEBUFFER + +#if defined(CONFIG_FS_WRITEBUFFER) + /* Write the data to the write buffer */ + ret = rwb_write(&priv->rwbuffer, startsector, nsectors, buffer); + +#elif defined(CONFIG_MMCSD_MULTIBLOCK_DISABLE) + /* Write each block using only the single block transfer method */ + + endsector = startsector + nsectors - 1; + for (sector = startsector; sector <= endsector; sector++) + { + /* Write this block from the user buffer */ + + ret = mmcsd_writesingle(priv, buffer, sector); + if (ret < 0) + { + break; + } + + /* Increment the buffer pointer by the block size */ + + buffer += priv->blocksize; + } #else + /* Use either the single- or multiple-block transfer method */ + if (nsectors == 1) { ret = mmcsd_writesingle(priv, buffer, startsector); diff --git a/nuttx/net/recvfrom.c b/nuttx/net/recvfrom.c index aabfcedfd..ee8f100bf 100644 --- a/nuttx/net/recvfrom.c +++ b/nuttx/net/recvfrom.c @@ -38,6 +38,7 @@ ****************************************************************************/ #include <nuttx/config.h> + #ifdef CONFIG_NET #include <sys/types.h> @@ -103,7 +104,7 @@ struct recvfrom_s * pstate recvfrom state structure * * Returned Value: - * None + * The number of bytes taken from the packet. * * Assumptions: * Running at the interrupt level @@ -111,7 +112,8 @@ struct recvfrom_s ****************************************************************************/ #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) -static void recvfrom_newdata(struct uip_driver_s *dev, struct recvfrom_s *pstate) +static size_t recvfrom_newdata(FAR struct uip_driver_s *dev, + FAR struct recvfrom_s *pstate) { size_t recvlen; @@ -137,11 +139,105 @@ static void recvfrom_newdata(struct uip_driver_s *dev, struct recvfrom_s *pstate pstate->rf_buffer += recvlen; pstate->rf_buflen -= recvlen; + return recvlen; +} +#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ + +/**************************************************************************** + * Function: recvfrom_newtcpdata + * + * Description: + * Copy the read data from the packet + * + * Parameters: + * dev The sructure of the network driver that caused the interrupt + * pstate recvfrom state structure + * + * Returned Value: + * None. + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static inline void recvfrom_newtcpdata(FAR struct uip_driver_s *dev, + FAR struct recvfrom_s *pstate) +{ + /* Take as much data from the packet as we can */ + + size_t recvlen = recvfrom_newdata(dev, pstate); + + /* If there is more data left in the packet that we could not buffer, than + * add it to the read-ahead buffers. + */ + + if (recvlen < dev->d_len) + { +#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 + FAR struct uip_conn *conn = (FAR struct uip_conn *)pstate->rf_sock->s_conn; + FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen; + uint16_t buflen = dev->d_len - recvlen; + uint16_t nsaved; + + nsaved = uip_datahandler(conn, buffer, buflen); + + /* There are complicated buffering issues that are not addressed + * properly here. For example, what if up_datahandler() cannot buffer + * the remainder of the packet? In that case, the data will be dropped + * but still ACKed. Therefore it will not be resent. Fixing this could be + * tricky. + */ + +#ifdef CONFIG_DEBUG_NET + if (nsaved < buflen) + { + ndbg("ERROR: packet data not saved (%d bytes)\n", buflen - nsaved); + } +#endif +#else + ndbg("ERROR: packet data lost (%d bytes)\n", dev->d_len - recvlen); +#endif + } + /* Indicate no data in the buffer */ dev->d_len = 0; } -#endif /* CONFIG_NET_UDP || CONFIG_NET_TCP */ +#endif /* CONFIG_NET_TCP */ + +/**************************************************************************** + * Function: recvfrom_newudpdata + * + * Description: + * Copy the read data from the packet + * + * Parameters: + * dev The sructure of the network driver that caused the interrupt + * pstate recvfrom state structure + * + * Returned Value: + * None. + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#ifdef CONFIG_NET_TCP +static inline void recvfrom_newudpdata(FAR struct uip_driver_s *dev, + FAR struct recvfrom_s *pstate) +{ + /* Take as much data from the packet as we can */ + + (void)recvfrom_newdata(dev, pstate); + + /* Indicate no data in the buffer */ + + dev->d_len = 0; +} +#endif /* CONFIG_NET_TCP */ /**************************************************************************** * Function: recvfrom_readahead @@ -164,9 +260,9 @@ static void recvfrom_newdata(struct uip_driver_s *dev, struct recvfrom_s *pstate #if defined(CONFIG_NET_TCP) && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 static inline void recvfrom_readahead(struct recvfrom_s *pstate) { - struct uip_conn *conn = (struct uip_conn *)pstate->rf_sock->s_conn; - struct uip_readahead_s *readahead; - size_t recvlen; + FAR struct uip_conn *conn = (FAR struct uip_conn *)pstate->rf_sock->s_conn; + FAR struct uip_readahead_s *readahead; + size_t recvlen; /* Check there is any TCP data already buffered in a read-ahead * buffer. @@ -375,7 +471,7 @@ static uint16_t recvfrom_tcpinterrupt(struct uip_driver_s *dev, void *conn, { /* Copy the data from the packet */ - recvfrom_newdata(dev, pstate); + recvfrom_newtcpdata(dev, pstate); /* Save the sender's address in the caller's 'from' location */ @@ -572,7 +668,7 @@ static uint16_t recvfrom_udpinterrupt(struct uip_driver_s *dev, void *pvconn, { /* Copy the data from the packet */ - recvfrom_newdata(dev, pstate); + recvfrom_newudpdata(dev, pstate); /* We are finished. */ diff --git a/nuttx/net/uip/uip_internal.h b/nuttx/net/uip/uip_internal.h index aab7408da..01c018c51 100644 --- a/nuttx/net/uip/uip_internal.h +++ b/nuttx/net/uip/uip_internal.h @@ -1,8 +1,8 @@ /**************************************************************************** * net/uip/uip_internal.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * Copyright (C) 2007-2009, 2012 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> * * This logic was leveraged from uIP which also has a BSD-style license: * @@ -154,8 +154,12 @@ EXTERN void uip_tcpinput(struct uip_driver_s *dev); /* Defined in uip_tcpcallback.c *********************************************/ -EXTERN uint16_t uip_tcpcallback(struct uip_driver_s *dev, - struct uip_conn *conn, uint16_t flags); +EXTERN uint16_t uip_tcpcallback(FAR struct uip_driver_s *dev, + FAR struct uip_conn *conn, uint16_t flags); +#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 +EXTERN uint16_t uip_datahandler(FAR struct uip_conn *conn, + FAR uint8_t *buffer, uint16_t nbytes); +#endif /* Defined in uip_tcpreadahead.c ********************************************/ diff --git a/nuttx/net/uip/uip_tcpcallback.c b/nuttx/net/uip/uip_tcpcallback.c index 3f6d04c06..099c29bf3 100644 --- a/nuttx/net/uip/uip_tcpcallback.c +++ b/nuttx/net/uip/uip_tcpcallback.c @@ -38,6 +38,7 @@ ****************************************************************************/ #include <nuttx/config.h> + #if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) #include <stdint.h> @@ -102,18 +103,19 @@ static int uip_readahead(struct uip_readahead_s *readahead, uint8_t *buf, * Function: uip_dataevent * * Description: - * This is the default data event handler that is called when there is no - * user data handler in place + * Handle data that is not accepted by the application because there is no + * listener in place ready to receive the data. * * Assumptions: - * - The called has checked that UIP_NEWDATA is set in flags and that is no + * - The caller has checked that UIP_NEWDATA is set in flags and that is no * other handler available to process the incoming data. * - This function is called at the interrupt level with interrupts disabled. * ****************************************************************************/ static inline uint16_t -uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint16_t flags) +uip_dataevent(FAR struct uip_driver_s *dev, FAR struct uip_conn *conn, + uint16_t flags) { uint16_t ret; @@ -130,61 +132,25 @@ uip_dataevent(struct uip_driver_s *dev, struct uip_conn *conn, uint16_t flags) if (dev->d_len > 0) { #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 - struct uip_readahead_s *readahead1; - struct uip_readahead_s *readahead2 = NULL; - uint16_t recvlen = 0; - uint8_t *buf = dev->d_appdata; - int buflen = dev->d_len; + uint8_t *buffer = dev->d_appdata; + int buflen = dev->d_len; + uint16_t recvlen; #endif nllvdbg("No listener on connection\n"); #if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 - /* First, we need to determine if we have space to buffer the data. This - * needs to be verified before we actually begin buffering the data. We - * will use any remaining space in the last allocated readahead buffer - * plus as much one additional buffer. It is expected that the size of - * readahead buffers are tuned so that one full packet will always fit - * into one readahead buffer (for example if the buffer size is 420, then - * a readahead buffer of 366 will hold a full packet of TCP data). - */ + /* Save as much data as possible in the read-ahead buffers */ - readahead1 = (struct uip_readahead_s*)conn->readahead.tail; - if ((readahead1 && - (CONFIG_NET_TCP_READAHEAD_BUFSIZE - readahead1->rh_nbytes) > buflen) || - (readahead2 = uip_tcpreadaheadalloc()) != NULL) - { - /* We have buffer space. Now try to append add as much data as possible - * to the last readahead buffer attached to this connection. - */ - - if (readahead1) - { - recvlen = uip_readahead(readahead1, buf, buflen); - if (recvlen > 0) - { - buf += recvlen; - buflen -= recvlen; - } - } + recvlen = uip_datahandler(conn, buffer, buflen); - /* Do we need to buffer into the newly allocated buffer as well? */ - - if (readahead2) - { - readahead2->rh_nbytes = 0; - (void)uip_readahead(readahead2, buf, buflen); - - /* Save the readahead buffer in the connection structure where - * it can be found with recv() is called. - */ - - sq_addlast(&readahead2->rh_node, &conn->readahead); - } + /* There are several complicated buffering issues that are not addressed + * properly here. For example, what if we cannot buffer the entire + * packet? In that case, some data will be accepted but not ACKed. + * Therefore it will be resent and duplicated. Fixing this could be tricky. + */ - nllvdbg("Buffered %d bytes\n", dev->d_len); - } - else + if (recvlen < buflen) #endif { /* There is no handler to receive new data and there are no free @@ -286,4 +252,88 @@ uint16_t uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, return ret; } +/**************************************************************************** + * Function: uip_datahandler + * + * Description: + * Handle data that is not accepted by the application. This may be called + * either (1) from the data receive logic if it cannot buffer the data, or + * (2) from the TCP event logic is there is no listener in place ready to + * receive the data. + * + * Input Parmeters: + * conn - A pointer to the TCP connection structure + * buffer - A pointer to the buffer to be copied to the read-ahead + * buffers + * buflen - The number of bytes to copy to the read-ahead buffer. + * + * Returned value: + * The number of bytes actually buffered. This could be less than 'nbytes' + * if there is insufficient buffering available. + * + * Assumptions: + * - The caller has checked that UIP_NEWDATA is set in flags and that is no + * other handler available to process the incoming data. + * - This function is called at the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 +uint16_t uip_datahandler(FAR struct uip_conn *conn, FAR uint8_t *buffer, + uint16_t buflen) +{ + FAR struct uip_readahead_s *readahead1; + FAR struct uip_readahead_s *readahead2 = NULL; + uint16_t remaining; + uint16_t recvlen = 0; + + /* First, we need to determine if we have space to buffer the data. This + * needs to be verified before we actually begin buffering the data. We + * will use any remaining space in the last allocated readahead buffer + * plus as much one additional buffer. It is expected that the size of + * readahead buffers are tuned so that one full packet will always fit + * into one readahead buffer (for example if the buffer size is 420, then + * a readahead buffer of 366 will hold a full packet of TCP data). + */ + + readahead1 = (FAR struct uip_readahead_s*)conn->readahead.tail; + if ((readahead1 && + (CONFIG_NET_TCP_READAHEAD_BUFSIZE - readahead1->rh_nbytes) > buflen) || + (readahead2 = uip_tcpreadaheadalloc()) != NULL) + { + /* We have buffer space. Now try to append add as much data as possible + * to the last readahead buffer attached to this connection. + */ + + remaining = buflen; + if (readahead1) + { + recvlen = uip_readahead(readahead1, buffer, remaining); + if (recvlen > 0) + { + buffer += recvlen; + remaining -= recvlen; + } + } + + /* Do we need to buffer into the newly allocated buffer as well? */ + + if (readahead2) + { + readahead2->rh_nbytes = 0; + recvlen += uip_readahead(readahead2, buffer, remaining); + + /* Save the readahead buffer in the connection structure where + * it can be found with recv() is called. + */ + + sq_addlast(&readahead2->rh_node, &conn->readahead); + } + } + + nllvdbg("Buffered %d bytes (of %d)\n", recvlen, buflen); + return recvlen; +} +#endif /* CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0 */ + #endif /* CONFIG_NET && CONFIG_NET_TCP */ |