mirror of
https://github.com/apache/nuttx.git
synced 2026-06-06 16:50:55 +08:00
NET: Improvied I/O buffer logic
This commit is contained in:
+26
-5
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user