NET: Improvied I/O buffer logic

This commit is contained in:
Gregory Nutt
2014-06-04 09:03:11 -06:00
parent 35eb466620
commit 67d5e8d154
7 changed files with 124 additions and 108 deletions
+26 -5
View File
@@ -41,6 +41,10 @@
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <queue.h>
#include <nuttx/net/iob.h>
/****************************************************************************
@@ -57,7 +61,8 @@
****************************************************************************/
/* Represents one I/O buffer. A packet is contained by one or more I/O
* buffers in a chain.
* buffers in a chain. The io_flags, io_pktlen, io_vtag and io_priv
* fields are only valid for the I/O buffer at the head of the chain.
*/
struct iob_s
@@ -65,6 +70,7 @@ struct iob_s
sq_entry_t io_link; /* Link to the next I/O buffer in the chain */
uint8_t io_flags; /* Flags associated with the I/O buffer */
uint16_t io_len; /* Length of the data in the entry */
uint16_t io_offset; /* Data begins at this offset */
uint16_t io_pktlen; /* Total length of the packet */
uint16_t io_vtag; /* VLAN tag */
void *io_priv; /* User private data attached to the I/O buffer */
@@ -146,20 +152,35 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2);
* Name: iob_trimhead
*
* Description:
* Remove bytes from the beginning of an I/O chain
* Remove bytes from the beginning of an I/O chain. Emptied I/O buffers
* are freed and, hence, the beginning of the chain may change.
*
****************************************************************************/
void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen);
FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen);
/****************************************************************************
* Name: iob_trimtail
*
* Description:
* Remove bytes from the end of an I/O chain
* Remove bytes from the end of an I/O chain. Emptied I/O buffers are
* freed NULL will be returned in the special case where the entry I/O
* buffer chain is freed.
*
****************************************************************************/
void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen);
FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen);
/****************************************************************************
* Name: iob_pack
*
* Description:
* Pack all data in the I/O buffer chain so that the data offset is zero
* and all but the final buffer in the chain are filled. Any emptied
* buffers at the end of the chain are freed.
*
****************************************************************************/
FAR struct iob_s *iob_pack(FAR struct iob_s *iob);
#endif /* _INCLUDE_NUTTX_NET_IOB_H */
+2 -1
View File
@@ -80,9 +80,10 @@ FAR struct iob_s *iob_alloc(void)
iob = (FAR struct iob_s *)sq_remfirst(&g_iob_freelist);
if (iob)
{
iob->io_link.flink = NULL; /* Not in a list */
iob->io_link.flink = NULL; /* Not in a chain */
iob->io_flags = 0; /* Flags associated with the I/O buffer */
iob->io_len = 0; /* Length of the data in the entry */
iob->io_offset = 0; /* Offset to the beginning of data */
iob->io_pktlen = 0; /* Total length of the packet */
iob->io_vtag = 0; /* VLAN tag */
iob->io_priv = NULL; /* User private data attached to the I/O buffer */
+9 -69
View File
@@ -76,10 +76,6 @@
void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2)
{
unsigned int offset2;
unsigned int ncopy;
unsigned int navail;
/* Find the last buffer in the iob1 buffer chain */
while (iob1->io_link.flink)
@@ -87,72 +83,16 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2)
iob1 = (FAR struct iob_s *)iob1->io_link.flink;
}
/* Then add data to the end of iob1 */
/* Then connect iob2 buffer chain to the end of the iob1 chain */
offset2 = 0;
while (iob2)
{
/* Is the iob1 tail buffer full? */
iob1->io_link.flink = iob2->io_link.flink;
if (iob1->io_len >= CONFIG_IOB_BUFSIZE)
{
/* Yes.. Just connect the chains */
/* Combine the total packet size. flags, VLAN, tags, and private
* data from iob2 are lost.
*/
iob1->io_link.flink = iob2->io_link.flink;
/* Has the data offset in iob2? */
if (offset2 > 0)
{
/* Yes, move the data down and adjust the size */
iob2->io_len -= offset2;
memcpy(iob2->io_data, &iob2->io_data[offset2], iob2->io_len);
/* Set up to continue packing, but now into iob2 */
iob1 = iob2;
iob2 = (FAR struct iob_s *)iob2->io_link.flink;
iob1->io_link.flink = NULL;
offset2 = 0;
}
else
{
/* Otherwise, we are done */
return;
}
}
/* How many bytes can we copy from the source (iob2) */
ncopy = iob2->io_len - offset2;
/* Limit the size of the copy to the amount of free space in iob1 */
navail = CONFIG_IOB_BUFSIZE - iob1->io_len;
if (ncopy > navail)
{
ncopy = navail;
}
/* Copy the data from iob2 into iob1 */
memcpy(iob1->io_data + iob1->io_len, iob2->io_data, ncopy);
iob1->io_len += ncopy;
offset2 += ncopy;
/* Have we consumed all of the data in the iob2 entry? */
if (offset2 >= iob2->io_len)
{
/* Yes.. free the iob2 entry and start processing the next I/O
* buffer in the iob2 chain.
*/
iob2 = iob_free(iob2);
offset2 = 0;
}
}
iob1->io_pktlen += iob2->io_pktlen;
iob2->io_flags = 0;
iob2->io_vtag = 0;
iob2->io_priv = NULL;
}
+18 -8
View File
@@ -85,11 +85,12 @@
int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
unsigned int len, unsigned int offset)
{
FAR struct iob_s *head = iob;
FAR uint8_t *dest;
unsigned int ncopy;
unsigned int avail;
/* Skip to the I/O buffer containing the offset */
/* Skip to the I/O buffer containing the data offset */
while (offset >= iob->io_len)
{
@@ -101,16 +102,18 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
while (len > 0)
{
/* Get the source I/O buffer offset address and the amount of data
* available from that address.
/* Get the destination I/O buffer address and the amount of data
* available from that address. We don't want to extend the length
* an I/O buffer here.
*/
dest = &iob->io_data[offset];
avail = CONFIG_IOB_BUFSIZE - offset;
dest = &iob->io_data[iob->io_offset + offset];
avail = iob->io_len - offset;
/* Copy from the user buffer to the I/O buffer */
/* Copy from the user buffer to the I/O buffer
*/
ncopy = MIN(avail, len);
ncopy = MIN(len, avail);
memcpy(dest, src, ncopy);
/* Adjust the total length of the copy and the destination address in
@@ -127,6 +130,7 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
if (iob->io_link.flink == NULL)
{
struct iob_s *newiob;
unsigned int newlen;
/* Yes.. allocate a new buffer */
@@ -140,7 +144,13 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src,
/* Add the new I/O buffer to the end of the buffer chain. */
iob->io_link.flink = &newiob->io_link;
iob = newiob;
iob = newiob;
/* The additional bytes extend the length of the packet */
newlen = MIN(len, CONFIG_IOB_BUFSIZE);
iob->io_len = newlen;
head->io_pktlen += newlen;
}
else
{
+1 -1
View File
@@ -106,7 +106,7 @@ void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob,
* available from that address.
*/
src = &iob->io_data[offset];
src = &iob->io_data[iob->io_offset + offset];
avail = iob->io_len - offset;
/* Copy the from the I/O buffer in to the user buffer */
+49 -14
View File
@@ -39,9 +39,6 @@
#include <nuttx/config.h>
#include <string.h>
#include <queue.h>
#include <nuttx/net/iob.h>
#include "iob.h"
@@ -70,33 +67,55 @@
* Name: iob_trimhead
*
* Description:
* Remove bytes from the beginning of an I/O chain
* Remove bytes from the beginning of an I/O chain. Emptied I/O buffers
* are freed and, hence, the beginning of the chain may change.
*
****************************************************************************/
void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
{
FAR struct iob_s *entry;
uint8_t flags;
uint16_t pktlen;
uint16_t vtag;
void *priv;
unsigned int len;
if (iob && trimlen > 0)
{
entry = iob;
len = trimlen;
/* Save information from the head of the chain (in case the
* head is removed).
*/
flags = iob->io_flags;
pktlen = iob->io_pktlen;
vtag = iob->io_vtag;
priv = iob->io_priv;
/* Trim from the head of the I/IO buffer chain */
while (entry != NULL && len > 0)
entry = iob;
len = trimlen;
while (entry != NULL)
{
/* Do we trim this entire I/O buffer away? */
if (entry->io_len <= len)
{
/* Yes.. just set is length to zero and skip to the next */
/* Decrement the trim length by the full data size */
len -= entry->io_len;
entry->io_len = 0;
entry = (FAR struct iob_s *)entry->io_link.flink;
pktlen -= entry->io_len;
len -= entry->io_len;
/* Free this one and set the next I/O buffer as the head */
iob = (FAR struct iob_s *)entry->io_link.flink;
iob_free(entry);
/* Continue with the new buffer head */
entry = iob;
}
else
{
@@ -104,10 +123,26 @@ void iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen)
* stop the trim.
*/
entry->io_len -= len;
memcpy(entry->io_data, &entry->io_data[len], entry->io_len);
pktlen -= len;
entry->io_len -= len;
entry->io_offset += len;
len = 0;
}
}
/* Restore the state to the head of the chain (which may not be
* the same I/O buffer chain head that we started with).
*
* Adjust the pktlen by the number of bytes removed from the head
* of the I/O buffer chain. A special case is where we delete the
* entire chain: len > 0 and iob == NULL.
*/
iob->io_flags = flags;
iob->io_pktlen = pktlen;
iob->io_vtag = vtag;
iob->io_priv = priv;
}
return iob;
}
+19 -10
View File
@@ -74,8 +74,9 @@
*
****************************************************************************/
void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
{
FAR struct iob_s *head = iob;
FAR struct iob_s *entry;
FAR struct iob_s *penultimate;
FAR struct iob_s *last;
@@ -118,21 +119,27 @@ void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
if (last->io_len <= len)
{
/* Yes.. just set is length to zero and skip to the next */
/* Yes.. Consume the entire buffer */
len -= last->io_len;
last->io_len = 0;
head->io_pktlen -= last->io_len;
len -= last->io_len;
last->io_len = 0;
/* Free the last, empty buffer in the list */
iob_free(last);
/* There should be a buffer before this one */
if (!penultimate)
{
return;
/* No.. we just freed the head of the chain */
return NULL;
}
/* Free the last, empty buffer in the list */
/* Unlink the penultimate from the freed buffer */
iob_free(last);
penultimate->io_link.flink = NULL;
}
@@ -142,10 +149,12 @@ void iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen)
* stop the trim.
*/
last->io_len -= len;
memcpy(last->io_data, &last->io_data[len], last->io_len);
len = 0;
head->io_pktlen -= last->io_len;
last->io_len -= len;
len = 0;
}
}
}
return iob;
}