diff --git a/include/nuttx/net/iob.h b/include/nuttx/net/iob.h index 29457aa3e6..eda65047db 100644 --- a/include/nuttx/net/iob.h +++ b/include/nuttx/net/iob.h @@ -54,7 +54,7 @@ /* IOB flags */ #define IOBFLAGS_MCAST (1 << 0) /* Multicast packet */ -#define IOBFLAGS_VLANTAG (1 << 0) /* VLAN tag is value */ +#define IOBFLAGS_VLANTAG (1 << 1) /* VLAN tag is value (not supported) */ /**************************************************************************** * Public Types @@ -69,10 +69,17 @@ 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 */ +#if CONFIG_IOB_BUFSIZE < 256 + uint8_t io_len; /* Length of the data in the entry */ + uint8_t io_offset; /* Data begins at this offset */ +#else uint16_t io_len; /* Length of the data in the entry */ uint16_t io_offset; /* Data begins at this offset */ +#endif uint16_t io_pktlen; /* Total length of the packet */ - uint16_t io_vtag; /* VLAN tag */ +#ifdef __NO_VLAN__ + uint16_t io_vtag; /* VLAN tag (not supported) */ +#endif void *io_priv; /* User private data attached to the I/O buffer */ uint8_t io_data[CONFIG_IOB_BUFSIZE]; }; @@ -126,17 +133,29 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob); void iob_freeq(FAR sq_queue_t *q); +/**************************************************************************** + * Name: iob_copyin + * + * Description: + * Copy data 'len' bytes from a user buffer into the I/O buffer chain, + * starting at 'offset', extending the chain as necessary. + * + ****************************************************************************/ + +int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, + unsigned int len, unsigned int offset); + /**************************************************************************** * Name: iob_copyout * * Description: * Copy data 'len' bytes of data into the user buffer starting at 'offset' - * in the I/O buffer. + * in the I/O buffer, returning that actual number of bytes copied out. * ****************************************************************************/ -void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, - unsigned int len, unsigned int offset); +int iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, + unsigned int len, unsigned int offset); /**************************************************************************** * Name: iob_concat diff --git a/net/iob/iob_alloc.c b/net/iob/iob_alloc.c index 91106d4d53..a3c1bc64a9 100644 --- a/net/iob/iob_alloc.c +++ b/net/iob/iob_alloc.c @@ -85,7 +85,6 @@ FAR struct iob_s *iob_alloc(void) 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 */ } diff --git a/net/iob/iob_concat.c b/net/iob/iob_concat.c index a18d0e35e7..1e2620615c 100644 --- a/net/iob/iob_concat.c +++ b/net/iob/iob_concat.c @@ -93,6 +93,5 @@ void iob_concat(FAR struct iob_s *iob1, FAR struct iob_s *iob2) iob1->io_pktlen += iob2->io_pktlen; iob2->io_flags = 0; - iob2->io_vtag = 0; iob2->io_priv = NULL; } diff --git a/net/iob/iob_copyin.c b/net/iob/iob_copyin.c index 34c76bc69f..48129af0cb 100644 --- a/net/iob/iob_copyin.c +++ b/net/iob/iob_copyin.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -78,7 +79,7 @@ * * Description: * Copy data 'len' bytes from a user buffer into the I/O buffer chain, - * starting at 'offset'. + * starting at 'offset', extending the chain as necessary. * ****************************************************************************/ @@ -86,13 +87,25 @@ 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 struct iob_s *next; FAR uint8_t *dest; unsigned int ncopy; unsigned int avail; + DEBUGASSERT(iob && src); + + /* The offset must applied to data that is already in the I/O buffer chain */ + + if (offset > iob->io_pktlen) + { + ndbg("ERROR: offset is past the end of data: %d > %d\n", + offset, iob->io_pktlen); + return -ESPIPE; + } + /* Skip to the I/O buffer containing the data offset */ - while (offset >= iob->io_len) + while (offset > iob->io_len) { offset -= iob->io_len; iob = (FAR struct iob_s *)iob->io_link.flink; @@ -102,18 +115,69 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, while (len > 0) { + next = (FAR struct iob_s *)iob->io_link.flink; + /* 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. + * available from that address. */ dest = &iob->io_data[iob->io_offset + offset]; avail = iob->io_len - offset; - /* Copy from the user buffer to the I/O buffer + /* Will the rest of the copy fit into this buffer, overwriting + * existing data. */ - ncopy = MIN(len, avail); + if (len > avail) + { + /* No.. Is this the last buffer in the chain? */ + + if (next) + { + /* No.. clip to size that will overwrite. We cannot + * extend the length of an I/O block in mid-chain. + */ + + ncopy = avail; + } + else + { + unsigned int maxlen; + unsigned int newlen; + + /* Yes.. We can extend this buffer to the up to the very end. */ + + maxlen = CONFIG_IOB_BUFSIZE - iob->io_offset; + + /* This is the new buffer length that we need. Of course, + * clipped to the maximum possible size in this buffer. + */ + + newlen = len + offset; + if (newlen > maxlen) + { + newlen = maxlen; + } + + /* Set the new length and increment the packet length */ + + head->io_pktlen += (newlen - iob->io_len); + iob->io_len = newlen; + + /* Set the new number of bytes to copy */ + + ncopy = newlen - offset; + } + } + else + { + /* Yes.. Copy all of the remaining bytes */ + + ncopy = len; + } + + /* Copy from the user buffer to the I/O buffer. */ + memcpy(dest, src, ncopy); /* Adjust the total length of the copy and the destination address in @@ -127,38 +191,23 @@ int iob_copyin(FAR struct iob_s *iob, FAR const uint8_t *src, * are at the end of the buffer chain. */ - if (iob->io_link.flink == NULL) + if (len > 0 && !next) { - struct iob_s *newiob; - unsigned int newlen; - /* Yes.. allocate a new buffer */ - newiob = iob_alloc(); - if (newiob == NULL) + next = iob_alloc(); + if (next == NULL) { ndbg("ERROR: Failed to allocate I/O buffer\n"); return -ENOMEM; } - /* Add the new I/O buffer to the end of the buffer chain. */ + /* Add the new, empty I/O buffer to the end of the buffer chain. */ - iob->io_link.flink = &newiob->io_link; - 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 - { - /* Otherwise, just move to the next buffer in the list */ - - iob = (FAR struct iob_s *)iob->io_link.flink; + iob->io_link.flink = &next->io_link; } + iob = next; offset = 0; } diff --git a/net/iob/iob_copyout.c b/net/iob/iob_copyout.c index d103561502..4afab26166 100644 --- a/net/iob/iob_copyout.c +++ b/net/iob/iob_copyout.c @@ -77,16 +77,17 @@ * * Description: * Copy data 'len' bytes of data into the user buffer starting at 'offset' - * in the I/O buffer. + * in the I/O buffer, returning that actual number of bytes copied out. * ****************************************************************************/ -void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, - unsigned int len, unsigned int offset) +int iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, + unsigned int len, unsigned int offset) { FAR const uint8_t *src; unsigned int ncopy; unsigned int avail; + unsigned int remaining; /* Skip to the I/O buffer containing the offset */ @@ -98,10 +99,9 @@ void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, /* Then loop until all of the I/O data is copied to the user buffer */ - while (len > 0) + remaining = len; + while (iob && remaining > 0) { - ASSERT(iob); - /* Get the source I/O buffer offset address and the amount of data * available from that address. */ @@ -111,14 +111,14 @@ void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, /* Copy the from the I/O buffer in to the user buffer */ - ncopy = MIN(avail, len); + ncopy = MIN(avail, remaining); memcpy(dest, src, ncopy); /* Adjust the total length of the copy and the destination address in * the user buffer. */ - len -= ncopy; + remaining -= ncopy; dest += ncopy; /* Skip to the next I/O buffer in the chain */ @@ -126,4 +126,6 @@ void iob_copyout(FAR uint8_t *dest, FAR const struct iob_s *iob, iob = (FAR struct iob_s *)iob->io_link.flink; offset = 0; } + + return len - remaining; } diff --git a/net/iob/iob_pack.c b/net/iob/iob_pack.c index 43bdd6b558..ce60f96c5e 100644 --- a/net/iob/iob_pack.c +++ b/net/iob/iob_pack.c @@ -95,7 +95,6 @@ FAR struct iob_s *iob_pack(FAR struct iob_s *iob) uint8_t flags = iob->io_flags; uint16_t pktlen = iob->io_pktlen; - uint16_t vtag = iob->io_vtag; void *priv = iob->io_priv; iob = iob_free(iob); @@ -104,7 +103,6 @@ FAR struct iob_s *iob_pack(FAR struct iob_s *iob) iob->io_flags = flags; iob->io_pktlen = pktlen; - iob->io_vtag = vtag; iob->io_priv = priv; } diff --git a/net/iob/iob_test.c b/net/iob/iob_test.c new file mode 100644 index 0000000000..828022fc58 --- /dev/null +++ b/net/iob/iob_test.c @@ -0,0 +1,235 @@ +/**************************************************************************** + * net/iob/iob_test.c + * Unit test driver. This is of historical interest only since it requires + * and custom build setup and modifications to the iob source and header + * files. + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "iob.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +uint8_t buffer1[16384]; +uint8_t buffer2[16384]; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void dump_chain(struct iob_s *iob) +{ + int n; + + printf("=========================================================\n"); + printf("pktlen: %d flags: %02x\n", iob->io_pktlen, iob->io_flags); + + n = 0; + while (iob) + { + printf("%d. len=%d, offset=%d, priv=%p\n", + n, iob->io_len, iob->io_offset, iob->io_priv); + + iob = (struct iob_s *)iob->io_link.flink; + n++; + } + + printf("=========================================================\n"); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + * + * Description: + * A simple unit test for the I/O buffer logic + * + ****************************************************************************/ + +int main(int argc, char **argv) +{ + struct iob_s *iob; + int nbytes; + int i; + + iob_initialize(); + iob = iob_alloc(); + + for (i = 0; i < 4096; i++) + { + buffer1[i] = (uint8_t)(i & 0xff); + } + memset(buffer2, 0xff, 4096); + + iob_copyin(iob, buffer2, 47, 0); + printf("Copy IN: 47, offset 0\n"); + dump_chain(iob); + + iob_copyin(iob, buffer1, 4096, 47); + printf("Copy IN: 4096, offset 47\n"); + dump_chain(iob); + + nbytes = iob_copyout(buffer2, iob, 4096, 47); + printf("Copy OUT: %d, offset 47\n", nbytes); + + if (memcmp(buffer1, buffer2, nbytes) != 0) + { + fprintf(stderr, "Buffer1 does not match buffer2\n"); + } + + iob = iob_trimhead(iob, 47); + printf("Trim: 47 from the beginning of the list\n"); + dump_chain(iob); + + iob = iob_trimtail(iob, 493); + printf("Trim: 493 from the end of the list\n"); + dump_chain(iob); + + nbytes = iob_copyout(buffer2, iob, 4096, 0); + printf("Copy OUT: %d, offset 0\n", nbytes); + + if (memcmp(buffer1, buffer2, nbytes) != 0) + { + fprintf(stderr, "Buffer1 does not match buffer2\n"); + } + + iob = iob_trimhead(iob, 1362); + printf("Trim: 1362 from the beginning of the list\n"); + dump_chain(iob); + + nbytes = iob_copyout(buffer2, iob, 4096, 0); + printf("Copy OUT: %d, offset 0\n", nbytes); + + if (memcmp(&buffer1[1362], buffer2, nbytes) != 0) + { + fprintf(stderr, "Buffer1 does not match buffer2\n"); + } + + iob = iob_pack(iob); + printf("Packed\n", nbytes); + dump_chain(iob); + + nbytes = iob_copyout(buffer2, iob, 4096, 0); + printf("Copy OUT: %d, offset 0\n", nbytes); + + if (memcmp(&buffer1[1362], buffer2, nbytes) != 0) + { + fprintf(stderr, "Buffer1 does not match buffer2\n"); + } + + while (iob) iob = iob_free(iob); + return EXIT_SUCCESS; +} + +/**************************************************************************** + * Name: my_assert + * + * Description: + * A stand-in for the NuttX assertion routine. + * + ****************************************************************************/ + +void my_assert(bool value) +{ + if (!value) + { + fprintf(stderr, "Assertion failed\n"); + + abort(); + } +} + +/**************************************************************************** + * Non-standard queue functions cloned from libc/queue + ****************************************************************************/ + +sq_entry_t *sq_remfirst(sq_queue_t *queue) +{ + sq_entry_t *ret = queue->head; + + if (ret) + { + queue->head = ret->flink; + if (!queue->head) + { + queue->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +void sq_addlast(sq_entry_t *node, sq_queue_t *queue) +{ + node->flink = NULL; + if (!queue->head) + { + queue->head = node; + queue->tail = node; + } + else + { + queue->tail->flink = node; + queue->tail = node; + } +} diff --git a/net/iob/iob_trimhead.c b/net/iob/iob_trimhead.c index a4e47ac2e0..40fb270d20 100644 --- a/net/iob/iob_trimhead.c +++ b/net/iob/iob_trimhead.c @@ -77,7 +77,6 @@ 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; @@ -89,7 +88,6 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) 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 */ @@ -97,7 +95,7 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) entry = iob; len = trimlen; - while (entry != NULL) + while (len > 0 && entry != NULL) { /* Do we trim this entire I/O buffer away? */ @@ -140,7 +138,6 @@ FAR struct iob_s *iob_trimhead(FAR struct iob_s *iob, unsigned int trimlen) iob->io_flags = flags; iob->io_pktlen = pktlen; - iob->io_vtag = vtag; iob->io_priv = priv; }