First cut at conversion of write-buffering to use I/O buffer chaings (IOBs)
This commit is contained in:
parent
7e83501ce5
commit
356d25b503
@ -55,10 +55,12 @@
|
||||
#define IOB_DATA(p) (&(p)->io_data[(p)->io_offset])
|
||||
#define IOB_FREESPACE(p) (CONFIG_IOB_BUFSIZE - (p)->io_len - (p)->io_offset)
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
/* Queue helpers */
|
||||
|
||||
#define IOB_QINIT(q) do { (q)->qh_head = 0; (q)->qh_tail = 0; } while (0)
|
||||
#define IOB_QEMPTY(q) ((q)->head == NULL)
|
||||
# define IOB_QINIT(q) do { (q)->qh_head = 0; (q)->qh_tail = 0; } while (0)
|
||||
# define IOB_QEMPTY(q) ((q)->head == NULL)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
@ -89,6 +91,7 @@ struct iob_s
|
||||
uint8_t io_data[CONFIG_IOB_BUFSIZE];
|
||||
};
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
/* This container structure supports queuing of I/O buffer chains. This
|
||||
* structure is intended only for internal use by the IOB module.
|
||||
*/
|
||||
@ -113,6 +116,7 @@ struct iob_queue_s
|
||||
FAR struct iob_qentry_s *qh_head;
|
||||
FAR struct iob_qentry_s *qh_tail;
|
||||
};
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
||||
/****************************************************************************
|
||||
* Global Data
|
||||
@ -173,7 +177,9 @@ void iob_free_chain(FAR struct iob_s *iob);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq);
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_add_queue
|
||||
@ -183,7 +189,9 @@ int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq);
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_free_queue
|
||||
@ -193,7 +201,9 @@ FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
void iob_free_queue(FAR struct iob_queue_s *qhead);
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_copyin
|
||||
@ -278,11 +288,25 @@ FAR struct iob_s *iob_pack(FAR struct iob_s *iob);
|
||||
* Name: iob_contig
|
||||
*
|
||||
* Description:
|
||||
* Ensure that there is'len' bytes of contiguous space at the beginning
|
||||
* Ensure that there is 'len' bytes of contiguous space at the beginning
|
||||
* of the I/O buffer chain starting at 'iob'.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iob_contig(FAR struct iob_s *iob, unsigned int len);
|
||||
|
||||
/****************************************************************************
|
||||
* Function: iob_dump
|
||||
*
|
||||
* Description:
|
||||
* Dump the contents of a I/O buffer chain
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
void iob_dump(FAR const char *msg, FAR struct iob_s *iob);
|
||||
#else
|
||||
# define tcp_writebuffer_dump(wrb)
|
||||
#endif
|
||||
|
||||
#endif /* _INCLUDE_NUTTX_NET_IOB_H */
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <nuttx/net/uip/uipopt.h>
|
||||
#include <nuttx/net/uip/uip.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -123,6 +124,25 @@
|
||||
# define UIP_TCP_INITIAL_MSS UIP_TCP_MSS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* TCP write buffer access macros */
|
||||
|
||||
# define WRB_SEQNO(wrb) ((wrb)->wb_seqno)
|
||||
# define WRB_PKTLEN(wrb) ((wrb)->wb_iob->io_pktlen)
|
||||
# define WRB_SENT(wrb) ((wrb)->wb_sent)
|
||||
# define WRB_NRTX(wrb) ((wrb)->wb_nrtx)
|
||||
# define WRB_IOB(wrb) ((wrb)->wb_iob)
|
||||
# define WRB_COPYOUT(wrb,dest,n) (iob_copyout(dest,(wrb)->wb_iob,(n),0))
|
||||
# define WRB_COPYIN(wrb,src,n) (iob_copyin((wrb)->wb_iob,src,(n),0))
|
||||
# define WRB_TRIM(wrb,n) (iob_trimhead((wrb)->wb_iob,(n)))
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
# define WRB_DUMP(msg,wrb) tcp_writebuffer_dump(msg,wrb)
|
||||
#else
|
||||
# define WRB_DUMP(mgs,wrb)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
@ -170,22 +190,28 @@ struct uip_conn
|
||||
|
||||
/* Read-ahead buffering.
|
||||
*
|
||||
* readahead - A singly linked list of type struct uip_readahead_s
|
||||
* where the TCP/IP read-ahead data is retained.
|
||||
* readahead - A singly linked list of type struct uip_readahead_s
|
||||
* where the TCP/IP read-ahead data is retained.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_READAHEAD
|
||||
sq_queue_t readahead; /* Read-ahead buffering */
|
||||
#endif
|
||||
|
||||
/* Write buffering */
|
||||
/* Write buffering
|
||||
*
|
||||
* write_q - The queue of unsent I/O buffers. The head of this
|
||||
* list may be partially sent. FIFO ordering.
|
||||
* unacked_q - A queue of completely sent, but unacked I/O buffer
|
||||
* chains. Sequence number ordering.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
sq_queue_t write_q; /* Write buffering for segments */
|
||||
sq_queue_t unacked_q; /* Write buffering for un-ACKed segments */
|
||||
size_t expired; /* Number segments retransmitted but not yet ACKed,
|
||||
uint16_t expired; /* Number segments retransmitted but not yet ACKed,
|
||||
* it can only be updated at UIP_ESTABLISHED state */
|
||||
size_t sent; /* The number of bytes sent */
|
||||
uint16_t sent; /* The number of bytes sent */
|
||||
uint32_t isn; /* Initial sequence number */
|
||||
#endif
|
||||
|
||||
@ -261,14 +287,15 @@ struct uip_readahead_s
|
||||
/* This structure supports TCP write buffering */
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
struct iob_s; /* Forward reference */
|
||||
struct tcp_wrbuffer_s
|
||||
{
|
||||
sq_entry_t wb_node; /* Supports a singly linked list */
|
||||
uint32_t wb_seqno; /* Sequence number of the write segment */
|
||||
uint16_t wb_nbytes; /* Number of bytes available in this buffer */
|
||||
uint16_t wb_sent; /* Number of bytes sent from the I/O buffer chain */
|
||||
uint8_t wb_nrtx; /* The number of retransmissions for the last
|
||||
* segment sent */
|
||||
uint8_t wb_buffer[CONFIG_NET_TCP_WRITE_BUFSIZE];
|
||||
struct iob_s *wb_iob; /* Head of the I/O buffer chain */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -391,7 +391,14 @@ extern int uip_lockedwait(sem_t *sem);
|
||||
* len The maximum amount of data bytes to be sent.
|
||||
*/
|
||||
|
||||
extern void uip_send(struct uip_driver_s *dev, const void *buf, int len);
|
||||
extern void uip_send(FAR struct uip_driver_s *dev, FAR const void *buf,
|
||||
int len);
|
||||
|
||||
#ifdef CONFIG_NET_IOB
|
||||
struct iob_s;
|
||||
extern void uip_iobsend(FAR struct uip_driver_s *dev, FAR struct iob_s *buf,
|
||||
unsigned int len, unsigned int offset);
|
||||
#endif
|
||||
|
||||
/* uIP convenience and converting functions.
|
||||
*
|
||||
|
@ -305,30 +305,6 @@
|
||||
# undef CONFIG_NET_NTCP_READAHEAD_BUFFERS
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
/* Number of TCP write buffers */
|
||||
|
||||
# ifndef CONFIG_NET_NTCP_WRITE_BUFFERS
|
||||
# define CONFIG_NET_NTCP_WRITE_BUFFERS 1
|
||||
# endif
|
||||
|
||||
/* The size of one TCP write buffer */
|
||||
|
||||
# ifndef CONFIG_NET_TCP_WRITE_BUFSIZE
|
||||
# define CONFIG_NET_TCP_WRITE_BUFSIZE UIP_TCP_MSS
|
||||
# endif
|
||||
|
||||
/* The size of the write buffer should not exceed the maximum TCP MSS */
|
||||
|
||||
# if CONFIG_NET_TCP_WRITE_BUFSIZE > UIP_TCP_MSS
|
||||
# error CONFIG_NET_TCP_WRITE_BUFSIZE must not exceed UIP_TCP_MSS
|
||||
# endif
|
||||
|
||||
#else
|
||||
# undef CONFIG_NET_TCP_WRITE_BUFSIZE
|
||||
# undef CONFIG_NET_NTCP_WRITE_BUFFERS
|
||||
#endif
|
||||
|
||||
/* Delay after receive to catch a following packet. No delay should be
|
||||
* required if TCP/IP read-ahead buffering is enabled.
|
||||
*/
|
||||
|
@ -30,10 +30,16 @@ config IOB_BUFSIZE
|
||||
|
||||
config IOB_NCHAINS
|
||||
int "Number of pre-allocated I/O buffer chain heads"
|
||||
default 8
|
||||
default 0
|
||||
---help---
|
||||
These tiny nodes are used as "containers" to suppor queueing of
|
||||
These tiny nodes are used as "containers" to support queueing of
|
||||
I/O buffer chains. This will limit the number of I/O transactions
|
||||
that can be "in-flight" at any give time.
|
||||
that can be "in-flight" at any give time. The default value of
|
||||
zero disables this features.
|
||||
|
||||
These generic I/O buffer chain containers are not currently used
|
||||
by any logic in NuttX. That is because their other other specialized
|
||||
I/O buffer chain containers that also carry a payload of usage
|
||||
specific information.
|
||||
|
||||
endif # NET_IOB
|
||||
|
@ -43,6 +43,10 @@ NET_CSRCS += iob_free_chain.c iob_free_qentry.c iob_free_queue.c
|
||||
NET_CSRCS += iob_initialize.c iob_pack.c iob_remove_queue.c iob_trimhead.c
|
||||
NET_CSRCS += iob_trimtail.c
|
||||
|
||||
ifeq ($(CONFIG_DEBUG),y)
|
||||
NET_CSRCS += iob_dump.c
|
||||
endif
|
||||
|
||||
# Include iob build support
|
||||
|
||||
DEPPATH += --dep-path iob
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <nuttx/net/iob.h>
|
||||
|
||||
/****************************************************************************
|
||||
@ -64,6 +66,11 @@ extern FAR struct iob_s *g_iob_freelist;
|
||||
|
||||
extern FAR struct iob_qentry_s *g_iob_freeqlist;
|
||||
|
||||
/* Counting semaphores that tracks the number of free IOBs/qentries */
|
||||
|
||||
extern sem_t g_iob_sem;
|
||||
extern sem_t g_qentry_sem;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
@ -47,6 +47,8 @@
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -102,3 +104,5 @@ int iob_add_queue(FAR struct iob_s *iob, FAR struct iob_queue_s *iobq)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
@ -39,6 +39,9 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/net/iob.h>
|
||||
|
||||
@ -61,18 +64,19 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_alloc
|
||||
* Name: iob_tryalloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer by taking the buffer at the head of the free list.
|
||||
* Try to allocate an I/O buffer by taking the buffer at the head of the
|
||||
* free list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct iob_s *iob_alloc(void)
|
||||
static FAR struct iob_s *iob_tryalloc(void)
|
||||
{
|
||||
FAR struct iob_s *iob;
|
||||
irqstate_t flags;
|
||||
@ -85,9 +89,12 @@ FAR struct iob_s *iob_alloc(void)
|
||||
iob = g_iob_freelist;
|
||||
if (iob)
|
||||
{
|
||||
/* Remove the I/O buffer from the free list */
|
||||
/* Remove the I/O buffer from the free list and decrement the counting
|
||||
* semaphore that tracks the number of free IOBs.
|
||||
*/
|
||||
|
||||
g_iob_freelist = iob->io_flink;
|
||||
DEBUGVERIFY(sem_trywait(&g_iob_sem));
|
||||
irqrestore(flags);
|
||||
|
||||
/* Put the I/O buffer in a known state */
|
||||
@ -102,3 +109,86 @@ FAR struct iob_s *iob_alloc(void)
|
||||
irqrestore(flags);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_allocwait
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer, waiting if necessary. This function cannot be
|
||||
* called from any interrupt level logic.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct iob_s *iob_allocwait(void)
|
||||
{
|
||||
FAR struct iob_s *iob;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
/* The following must be atomic; interrupt must be disabled so that there
|
||||
* is no conflict with interrupt level I/O buffer allocations. This is
|
||||
* not as bad as it sounds because interrupts will be re-enabled while
|
||||
* we are waiting for I/O buffers to become free.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
do
|
||||
{
|
||||
/* Try to get an I/O buffer. If successful, the semaphore count
|
||||
* will be decremented atomically.
|
||||
*/
|
||||
|
||||
iob = iob_tryalloc();
|
||||
if (!iob)
|
||||
{
|
||||
/* If not successful, then the semaphore count was less than or
|
||||
* equal to zero (meaning that there are no free buffers). We
|
||||
* need to wait for an I/O buffer to be released when the semaphore
|
||||
* count will be incremented.
|
||||
*/
|
||||
|
||||
ret = sem_wait(&g_iob_sem);
|
||||
|
||||
/* When we wake up from wait, an I/O buffer was returned to
|
||||
* the free list. However, if there are concurrent allocations
|
||||
* from interrupt handling, then I suspect that there is a
|
||||
* race condition. But no harm, we will just wait again in
|
||||
* that case.
|
||||
*/
|
||||
}
|
||||
}
|
||||
while (ret == OK && !iob);
|
||||
|
||||
irqrestore(flags);
|
||||
return iob;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_alloc
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer by taking the buffer at the head of the free list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct iob_s *iob_alloc(void)
|
||||
{
|
||||
/* Were we called from the interrupt level? */
|
||||
|
||||
if (up_interrupt_context())
|
||||
{
|
||||
/* Yes, then try to allocate an I/O buffer without waiting */
|
||||
|
||||
return iob_tryalloc();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Then allocate an I/O buffer, waiting as necessary */
|
||||
|
||||
return iob_allocwait();
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,16 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/net/iob.h>
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -60,6 +65,104 @@
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_tryalloc_qentry
|
||||
*
|
||||
* Description:
|
||||
* Try to allocate an I/O buffer chain container by taking the buffer at
|
||||
* the head of the free list. This function is intended only for internal
|
||||
* use by the IOB module.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct iob_qentry_s *iob_tryalloc_qentry(void)
|
||||
{
|
||||
FAR struct iob_qentry_s *iobq;
|
||||
irqstate_t flags;
|
||||
|
||||
/* We don't know what context we are called from so we use extreme measures
|
||||
* to protect the free list: We disable interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
iobq = g_iob_freeqlist;
|
||||
if (iobq)
|
||||
{
|
||||
/* Remove the I/O buffer chain container from the free list and
|
||||
* decrement the counting semaphore that tracks the number of free
|
||||
* containers.
|
||||
*/
|
||||
|
||||
g_iob_freeqlist = iobq->qe_flink;
|
||||
DEBVERIFY(sem_trywait(&g_qentry_sem));
|
||||
|
||||
/* Put the I/O buffer in a known state */
|
||||
|
||||
iobq->qe_head = NULL; /* Nothing is contained */
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return iobq;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_allocwait_qentry
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer chain container by taking the buffer at the head
|
||||
* of the free list. This function is intended only for internal use by
|
||||
* the IOB module.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct iob_qentry_s *iob_allocwait_qentry(void)
|
||||
{
|
||||
FAR struct iob_qentry_s *qentry;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
/* The following must be atomic; interrupt must be disabled so that there
|
||||
* is no conflict with interrupt level I/O buffer chain container
|
||||
* allocations. This is not as bad as it sounds because interrupts will be
|
||||
* re-enabled while we are waiting for I/O buffers to become free.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
do
|
||||
{
|
||||
/* Try to get an I/O buffer chain container. If successful, the
|
||||
* semaphore count will be decremented atomically.
|
||||
*/
|
||||
|
||||
qentry = iob_tryalloc_qentry();
|
||||
if (!qentry)
|
||||
{
|
||||
/* If not successful, then the semaphore count was less than or
|
||||
* equal to zero (meaning that there are no free buffers). We
|
||||
* need to wait for an I/O buffer chain container to be released
|
||||
* when the semaphore count will be incremented.
|
||||
*/
|
||||
|
||||
ret = sem_wait(&g_qentry_sem);
|
||||
|
||||
/* When we wake up from wait, an I/O buffer chain container was
|
||||
* returned to the free list. However, if there are concurrent
|
||||
* allocations from interrupt handling, then I suspect that there
|
||||
* is a race condition. But no harm, we will just wait again in
|
||||
* that case.
|
||||
*/
|
||||
}
|
||||
}
|
||||
while (ret == OK && !qentry);
|
||||
|
||||
irqrestore(flags);
|
||||
return qentry;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -87,9 +190,13 @@ FAR struct iob_qentry_s *iob_alloc_qentry(void)
|
||||
iobq = g_iob_freeqlist;
|
||||
if (iobq)
|
||||
{
|
||||
/* Remove the I/O buffer chain container from the free list */
|
||||
/* Remove the I/O buffer chain container from the free list and
|
||||
* decrement the counting semaphore that tracks the number of free
|
||||
* containers.
|
||||
*/
|
||||
|
||||
g_iob_freeqlist = iobq->qe_flink;
|
||||
DEBVERIFY(sem_trywait(&g_qentry_sem));
|
||||
|
||||
/* Put the I/O buffer in a known state */
|
||||
|
||||
@ -99,3 +206,5 @@ FAR struct iob_qentry_s *iob_alloc_qentry(void)
|
||||
irqrestore(flags);
|
||||
return iobq;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
177
net/iob/iob_dump.c
Normal file
177
net/iob/iob_dump.c
Normal file
@ -0,0 +1,177 @@
|
||||
/****************************************************************************
|
||||
* net/iob/iob_dump.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/iob.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Select the lowest level debug interface available */
|
||||
|
||||
#ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# ifdef CONFIG_ARCH_LOWPUTC
|
||||
# define message(format, ...) lowsyslog(format, ##__VA_ARGS__)
|
||||
# else
|
||||
# define message(format, ...) syslog(format, ##__VA_ARGS__)
|
||||
# endif
|
||||
#else
|
||||
# ifdef CONFIG_ARCH_LOWPUTC
|
||||
# define message lowsyslog
|
||||
# else
|
||||
# define message syslog
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Function: iob_dump
|
||||
*
|
||||
* Description:
|
||||
* Dump the contents of a I/O buffer chain
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void iob_dump(FAR const char *msg, FAR struct iob_s *iob)
|
||||
{
|
||||
FAR struct iob_s *head = iob;
|
||||
FAR const uint8_t *buffer;
|
||||
uint8_t data[32];
|
||||
unsigned int nbytes;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
int len;
|
||||
|
||||
message("%s: IOB=%p pktlen=%d\n", msg, head, head->io_pktlen);
|
||||
|
||||
buffer = &iob->io_data[iob->io_offset];
|
||||
len = iob->io_len;
|
||||
|
||||
for (i = 0; i < head->io_pktlen && iob; i += 32)
|
||||
{
|
||||
/* Copy 32-bytes into our local buffer */
|
||||
|
||||
for (nbytes = 0; nbytes < 32; nbytes++)
|
||||
{
|
||||
data[nbytes] = *buffer++;
|
||||
|
||||
/* If we have exhausted the data in this I/O buffer,
|
||||
* then skip to the next I/O buffer in the chain.
|
||||
*/
|
||||
|
||||
if (--len <= 0)
|
||||
{
|
||||
iob = iob->io_flink;
|
||||
if (!iob)
|
||||
{
|
||||
/* Ooops... we are at the end of the chain.
|
||||
* break out with iob = NULL, len == 0, and
|
||||
* nbytes <= 32.
|
||||
*/
|
||||
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the data from the next I/O buffer in the chain */
|
||||
|
||||
buffer = &iob->io_data[iob->io_offset];
|
||||
len = iob->io_len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that we have something to print */
|
||||
|
||||
if (nbytes > 0)
|
||||
{
|
||||
message("%04x: ", i);
|
||||
for (j = 0; j < 32; j++)
|
||||
{
|
||||
if (j == 16)
|
||||
{
|
||||
message(" ");
|
||||
}
|
||||
|
||||
if (i + j < head->io_pktlen)
|
||||
{
|
||||
message("%02x", buffer[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
message(" ");
|
||||
}
|
||||
}
|
||||
|
||||
message(" ");
|
||||
for (j = 0; j < 32; j++)
|
||||
{
|
||||
if (j == 16)
|
||||
{
|
||||
message(" ");
|
||||
}
|
||||
|
||||
if (i + j < head->io_pktlen)
|
||||
{
|
||||
if (buffer[j] >= 0x20 && buffer[j] < 0x7f)
|
||||
{
|
||||
message("%c", buffer[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
message(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG */
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
@ -86,7 +87,6 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
|
||||
|
||||
if (next)
|
||||
{
|
||||
|
||||
/* Copy and decrement the total packet length, being careful to
|
||||
* do nothing too crazy.
|
||||
*/
|
||||
@ -115,8 +115,12 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
iob->io_flink = g_iob_freelist;
|
||||
iob->io_flink = g_iob_freelist;
|
||||
g_iob_freelist = iob;
|
||||
|
||||
/* Signal that an IOB is available */
|
||||
|
||||
sem_post(&g_iob_sem);
|
||||
irqrestore(flags);
|
||||
|
||||
/* And return the I/O buffer after the one that was freed */
|
||||
|
@ -75,20 +75,12 @@
|
||||
|
||||
void iob_free_chain(FAR struct iob_s *iob)
|
||||
{
|
||||
FAR struct iob_s *last;
|
||||
irqstate_t flags;
|
||||
FAR struct iob_s *next;
|
||||
|
||||
/* Find the last entry in the I/O buffer list */
|
||||
/* Free each IOB in the chain -- one at a time to keep the count straight */
|
||||
|
||||
for (last = iob; last->io_flink; last = last->io_flink);
|
||||
|
||||
/* Free the I/O buffer chain by adding it to the head of the free list. We
|
||||
* don't know what context we are called from so we use extreme measures to
|
||||
* protect the free list: We disable interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
last->io_flink = g_iob_freelist;
|
||||
g_iob_freelist = iob;
|
||||
irqrestore(flags);
|
||||
for (; iob; iob = next)
|
||||
{
|
||||
next = iob_free(iob);
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
@ -46,6 +47,8 @@
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -70,7 +73,7 @@
|
||||
* Name: iob_free_qentry
|
||||
*
|
||||
* Description:
|
||||
* Free the I/O buffer chain container by returning it to the free list.
|
||||
* Free the I/O buffer chain container by returning it to the free list.
|
||||
* The link to the next I/O buffer in the chain is return.
|
||||
*
|
||||
****************************************************************************/
|
||||
@ -86,11 +89,17 @@ FAR struct iob_qentry_s *iob_free_qentry(FAR struct iob_qentry_s *iobq)
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
iobq->qe_flink = g_iob_freeqlist;
|
||||
iobq->qe_flink = g_iob_freeqlist;
|
||||
g_iob_freeqlist = iobq;
|
||||
|
||||
/* Signal that an I/O buffer chain container is available */
|
||||
|
||||
sem_post(&g_qentry_sem);
|
||||
irqrestore(flags);
|
||||
|
||||
/* And return the I/O buffer chain container after the one that was freed */
|
||||
|
||||
return nextq;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -112,3 +114,5 @@ void iob_free_queue(FAR struct iob_queue_s *qhead)
|
||||
iob_free_chain(iob);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include <nuttx/net/iob.h>
|
||||
|
||||
@ -60,7 +61,9 @@
|
||||
/* This is a pool of pre-allocated I/O buffers */
|
||||
|
||||
static struct iob_s g_iob_pool[CONFIG_IOB_NBUFFERS];
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
static struct iob_qentry_s g_iob_qpool[CONFIG_IOB_NCHAINS];
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
@ -72,7 +75,16 @@ FAR struct iob_s *g_iob_freelist;
|
||||
|
||||
/* A list of all free, unallocated I/O buffer queue containers */
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
FAR struct iob_qentry_s *g_iob_freeqlist;
|
||||
#endif
|
||||
|
||||
/* Counting semaphores that tracks the number of free IOBs/qentries */
|
||||
|
||||
sem_t g_iob_sem;
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
sem_t g_qentry_sem;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
@ -107,6 +119,9 @@ void iob_initialize(void)
|
||||
g_iob_freelist = iob;
|
||||
}
|
||||
|
||||
sem_init(&g_iob_sem, 0, CONFIG_IOB_NBUFFERS);
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
/* Add each I/O buffer chain queue container to the free list */
|
||||
|
||||
for (i = 0; i < CONFIG_IOB_NCHAINS; i++)
|
||||
@ -119,6 +134,8 @@ void iob_initialize(void)
|
||||
g_iob_freeqlist = iobq;
|
||||
}
|
||||
|
||||
sem_init(&g_qentry_sem, 0, CONFIG_IOB_NCHAINS);
|
||||
#endif
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -92,3 +94,4 @@ FAR struct iob_s *iob_remove_queue(FAR struct iob_queue_s *iobq)
|
||||
return iob;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IOB_NCHAINS > 0 */
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include <arch/irq.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
#include <nuttx/net/iob.h>
|
||||
#include <nuttx/net/uip/uip-arch.h>
|
||||
|
||||
#include "net_internal.h"
|
||||
@ -92,8 +93,8 @@
|
||||
* ascending order of sequence number.
|
||||
*
|
||||
* Parameters:
|
||||
* segment The segment to be inserted
|
||||
* q The write buffer queue in which to insert the segment
|
||||
* wrb The segment to be inserted
|
||||
* q The write buffer queue in which to insert the segment
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
@ -103,17 +104,17 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void send_insert_seqment(FAR struct tcp_wrbuffer_s *segment,
|
||||
static void send_insert_seqment(FAR struct tcp_wrbuffer_s *wrb,
|
||||
FAR sq_queue_t *q)
|
||||
{
|
||||
sq_entry_t *entry = (sq_entry_t*)segment;
|
||||
sq_entry_t *entry = (sq_entry_t*)wrb;
|
||||
sq_entry_t *insert = NULL;
|
||||
|
||||
sq_entry_t *itr;
|
||||
for (itr = sq_peek(q); itr; itr = sq_next(itr))
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *segment0 = (FAR struct tcp_wrbuffer_s*)itr;
|
||||
if (segment0->wb_seqno < segment->wb_seqno)
|
||||
FAR struct tcp_wrbuffer_s *wrb0 = (FAR struct tcp_wrbuffer_s*)itr;
|
||||
if (WRB_SEQNO(wrb0) < WRB_SEQNO(wrb))
|
||||
{
|
||||
insert = itr;
|
||||
}
|
||||
@ -133,6 +134,54 @@ static void send_insert_seqment(FAR struct tcp_wrbuffer_s *segment,
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: lost_connection
|
||||
*
|
||||
* Description:
|
||||
* The TCP connection has been lost. Free all write buffers.
|
||||
*
|
||||
* Parameters:
|
||||
* psock The socket structure
|
||||
* conn The connection structure associated with the socket
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void lost_connection(FAR struct socket *psock,
|
||||
FAR struct uip_conn *conn)
|
||||
{
|
||||
FAR sq_entry_t *entry;
|
||||
FAR sq_entry_t *next;
|
||||
|
||||
/* Do not allow any further callbacks */
|
||||
|
||||
psock->s_sndcb->flags = 0;
|
||||
psock->s_sndcb->event = NULL;
|
||||
|
||||
/* Free all queued write buffers */
|
||||
|
||||
for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
|
||||
{
|
||||
next = sq_next(entry);
|
||||
tcp_wrbuffer_release((FAR struct tcp_wrbuffer_s *)entry);
|
||||
}
|
||||
|
||||
for (entry = sq_peek(&conn->write_q); entry; entry = next)
|
||||
{
|
||||
next = sq_next(entry);
|
||||
tcp_wrbuffer_release((FAR struct tcp_wrbuffer_s *)entry);
|
||||
}
|
||||
|
||||
/* Reset write buffering variables */
|
||||
|
||||
sq_init(&conn->unacked_q);
|
||||
sq_init(&conn->write_q);
|
||||
conn->expired = 0;
|
||||
conn->sent = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Function: send_interrupt
|
||||
*
|
||||
@ -156,10 +205,10 @@ static void send_insert_seqment(FAR struct tcp_wrbuffer_s *segment,
|
||||
static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
FAR void *pvpriv, uint16_t flags)
|
||||
{
|
||||
FAR struct uip_conn *conn = (FAR struct uip_conn*)pvconn;
|
||||
FAR struct uip_conn *conn = (FAR struct uip_conn *)pvconn;
|
||||
FAR struct socket *psock = (FAR struct socket *)pvpriv;
|
||||
|
||||
nllvdbg("flags: %04x\n", flags);
|
||||
//nllvdbg("flags: %04x\n", flags);
|
||||
|
||||
/* If this packet contains an acknowledgement, then update the count of
|
||||
* acknowledged bytes.
|
||||
@ -167,66 +216,155 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
|
||||
if ((flags & UIP_ACKDATA) != 0)
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
FAR sq_entry_t *entry;
|
||||
FAR sq_entry_t *next;
|
||||
FAR struct tcp_wrbuffer_s *segment;
|
||||
uint32_t ackno;
|
||||
|
||||
ackno = uip_tcpgetsequence(TCPBUF->ackno);
|
||||
nllvdbg("ACK: ackno=%d flags=%04x\n", ackno, flags);
|
||||
|
||||
/* Look at every write buffer int he unacked_q. The unacked_q
|
||||
* holds write buffers that have been entirely sent, but which
|
||||
* have not yet been acked.
|
||||
*/
|
||||
|
||||
for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
|
||||
{
|
||||
next = sq_next(entry);
|
||||
segment = (FAR struct tcp_wrbuffer_s*)entry;
|
||||
uint32_t lastseq;
|
||||
|
||||
if (segment->wb_seqno < ackno)
|
||||
/* Check of some or all of this write buffer has been ACKed. */
|
||||
|
||||
next = sq_next(entry);
|
||||
wrb = (FAR struct tcp_wrbuffer_s*)entry;
|
||||
|
||||
/* If the ACKed sequence number is greater than the start
|
||||
* sequence number of the write buffer, then some or all of
|
||||
* the write buffer has been ACKed.
|
||||
*/
|
||||
|
||||
if (ackno > WRB_SEQNO(wrb))
|
||||
{
|
||||
nllvdbg("ACK: acked=%d buflen=%d ackno=%d\n",
|
||||
segment->wb_seqno, segment->wb_nbytes, ackno);
|
||||
/* Get the sequence number at the end of the data */
|
||||
|
||||
/* Segment was ACKed. Remove from ACK waiting queue */
|
||||
lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb);
|
||||
nllvdbg("ACK: seqno=%d lastseq=%d pktlen=%d ackno=%d\n",
|
||||
WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno);
|
||||
|
||||
sq_rem(entry, &conn->unacked_q);
|
||||
/* Has the entire buffer been ACKed? */
|
||||
|
||||
/* Return the write buffer to the pool of free buffers */
|
||||
if (ackno >= lastseq)
|
||||
{
|
||||
/* Yes... Remove the write buffer from ACK waiting queue */
|
||||
|
||||
tcp_wrbuffer_release(segment);
|
||||
sq_rem(entry, &conn->unacked_q);
|
||||
|
||||
/* And return the write buffer to the pool of free buffers */
|
||||
|
||||
tcp_wrbuffer_release(wrb);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No, then just trim the ACKed bytes from the beginning
|
||||
* of the write buffer. This will free up some I/O buffers
|
||||
* that can be reused while are still sending the last
|
||||
* buffers in the chain.
|
||||
*/
|
||||
|
||||
WRB_TRIM(wrb, ackno - WRB_SEQNO(wrb));
|
||||
WRB_SEQNO(wrb) = ackno;
|
||||
|
||||
nllvdbg("ACK: seqno=%d pktlen=%d\n",
|
||||
WRB_SEQNO(wrb), WRB_PKTLEN(wrb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A special case is the head of the write_q which may be partially
|
||||
* sent and so can still have un-ACKed bytes that could get ACKed
|
||||
* before the entire write buffer has even been sent.
|
||||
*/
|
||||
|
||||
wrb = (FAR struct tcp_wrbuffer_s*)sq_peek(&conn->write_q);
|
||||
if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb))
|
||||
{
|
||||
uint32_t nacked;
|
||||
|
||||
/* Get the sequence number at the end of the data */
|
||||
|
||||
nacked = ackno - WRB_SEQNO(wrb);
|
||||
if (nacked > WRB_SENT(wrb))
|
||||
{
|
||||
/* More data has been ACKed then we have sent? */
|
||||
|
||||
nacked = WRB_SENT(wrb);
|
||||
}
|
||||
|
||||
nllvdbg("ACK: seqno=%d nacked=%d sent=%d ackno=%d\n",
|
||||
WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno);
|
||||
|
||||
/* Trim the ACKed bytes from the beginning of the write buffer. */
|
||||
|
||||
WRB_TRIM(wrb, nacked);
|
||||
WRB_SEQNO(wrb) = ackno;
|
||||
WRB_SENT(wrb) -= nacked;
|
||||
|
||||
nllvdbg("ACK: seqno=%d pktlen=%d sent=%d\n",
|
||||
WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for a loss of connection */
|
||||
|
||||
else if ((flags & (UIP_CLOSE | UIP_ABORT | UIP_TIMEDOUT)) != 0)
|
||||
{
|
||||
nllvdbg("Lost connection: %04x\n", flags);
|
||||
|
||||
/* Report not connected */
|
||||
|
||||
nllvdbg("Lost connection\n");
|
||||
net_lostconnection(psock, flags);
|
||||
goto end_wait;
|
||||
}
|
||||
net_lostconnection(psock, flags);
|
||||
|
||||
/* Free write buffers and terminate polling */
|
||||
|
||||
lost_connection(psock, conn);
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Check if we are being asked to retransmit data */
|
||||
|
||||
else if ((flags & UIP_REXMIT) != 0)
|
||||
{
|
||||
sq_entry_t *entry;
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
FAR sq_entry_t *entry;
|
||||
|
||||
/* Put all segments that have been sent but not ACKed to write queue
|
||||
* again note, the un-ACKed segment is put at the first of the write_q,
|
||||
* so it can be sent as soon as possible.
|
||||
nllvdbg("REXMIT: %04x\n", flags);
|
||||
|
||||
/* If there is a partially sent write buffer at the head of the
|
||||
* write_q, reset the number of bytes sent.
|
||||
*/
|
||||
|
||||
while ((entry = sq_remlast(&conn->unacked_q)))
|
||||
wrb = (FAR struct tcp_wrbuffer_s*)sq_peek(&conn->write_q);
|
||||
if (wrb)
|
||||
{
|
||||
struct tcp_wrbuffer_s *segment = (struct tcp_wrbuffer_s*)entry;
|
||||
WRB_SENT(wrb) = 0;
|
||||
}
|
||||
|
||||
/* Move all segments that have been sent but not ACKed to the write
|
||||
* queue again note, the un-ACKed segments are put at the head of the
|
||||
* write_q so they can be resent as soon as possible.
|
||||
*/
|
||||
|
||||
if (segment->wb_nrtx >= UIP_MAXRTX)
|
||||
while ((entry = sq_remlast(&conn->unacked_q)) != NULL)
|
||||
{
|
||||
wrb = (FAR struct tcp_wrbuffer_s*)entry;
|
||||
|
||||
/* Free any write buffers that have exceed the retry count */
|
||||
|
||||
if (WRB_NRTX(wrb) >= UIP_MAXRTX)
|
||||
{
|
||||
//conn->unacked -= segment->wb_nbytes;
|
||||
/* Return the write buffer to the free list */
|
||||
|
||||
/* Return the write buffer */
|
||||
|
||||
tcp_wrbuffer_release(segment);
|
||||
tcp_wrbuffer_release(wrb);
|
||||
|
||||
/* NOTE expired is different from un-ACKed, it is designed to
|
||||
* represent the number of segments that have been sent,
|
||||
@ -239,8 +377,16 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
conn->expired++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Insert the write buffer into the write_q (in sequence
|
||||
* number order). The retransmission will occur below
|
||||
* when the write buffer with the lowest sequenc number
|
||||
* is pulled from the write_q again.
|
||||
*/
|
||||
|
||||
send_insert_seqment(segment, &conn->write_q);
|
||||
send_insert_seqment(wrb, &conn->write_q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +405,7 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
* asked to retransmit data, (3) the connection is still healthy, and (4)
|
||||
* the outgoing packet is available for our use. In this case, we are
|
||||
* now free to send more data to receiver -- UNLESS the buffer contains
|
||||
* unprocesed incoming data. In that event, we will have to wait for the
|
||||
* unprocessed incoming data. In that event, we will have to wait for the
|
||||
* next polling cycle.
|
||||
*/
|
||||
|
||||
@ -283,44 +429,64 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
if (arp_find(conn->ripaddr) != NULL)
|
||||
#endif
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *segment;
|
||||
FAR void *sndbuf;
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
size_t sndlen;
|
||||
|
||||
/* Get the amount of data that we can send in the next packet */
|
||||
/* Peek at the head of the write queue (but don't remove anything
|
||||
* from the write queue yet.
|
||||
*/
|
||||
|
||||
segment = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||
if (segment)
|
||||
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
if (wrb)
|
||||
{
|
||||
sndbuf = segment->wb_buffer;
|
||||
sndlen = segment->wb_nbytes;
|
||||
|
||||
DEBUGASSERT(sndlen <= uip_mss(conn));
|
||||
|
||||
/* REVISIT: There should be a check here to assure that we do
|
||||
* not excced the window (conn->winsize).
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
* window size.
|
||||
*/
|
||||
|
||||
/* Set the sequence number for this segment. NOTE: uIP
|
||||
* updates sndseq on receipt of ACK *before* this function
|
||||
* is called. In that case sndseq will point to the next
|
||||
* unacknowledged byte (which might have already been
|
||||
* sent). We will overwrite the value of sndseq here
|
||||
* before the packet is sent.
|
||||
*/
|
||||
|
||||
if (segment->wb_nrtx == 0 && segment->wb_seqno == (unsigned)-1)
|
||||
sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb);
|
||||
if (sndlen > uip_mss(conn))
|
||||
{
|
||||
segment->wb_seqno = conn->isn + conn->sent;
|
||||
sndlen = uip_mss(conn);
|
||||
}
|
||||
|
||||
uip_tcpsetsequence(conn->sndseq, segment->wb_seqno);
|
||||
if (sndlen > conn->winsize)
|
||||
{
|
||||
sndlen = conn->winsize;
|
||||
}
|
||||
|
||||
/* Then set-up to send that amount of data. (this won't
|
||||
* actually happen until the polling cycle completes).
|
||||
nllvdbg("pktlen=%d sent=%d sndlen=%d\n",
|
||||
WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen);
|
||||
|
||||
/* Is this the first we have tried to send from this
|
||||
* write buffer?
|
||||
*/
|
||||
|
||||
uip_send(dev, sndbuf, sndlen);
|
||||
if (WRB_SENT(wrb) == 0)
|
||||
{
|
||||
/* Yes..Set the sequence number for this segment.
|
||||
* NOTE: the TCP stack updates sndseq on receipt of ACK
|
||||
* *before* this function is called. In that case sndseq
|
||||
* will point to the next unacknowledged byte (which might
|
||||
* have already been sent). We will overwrite the value of
|
||||
* sndseq here before the packet is sent.
|
||||
*/
|
||||
|
||||
if (WRB_NRTX(wrb) == 0 && WRB_SEQNO(wrb) == (unsigned)-1)
|
||||
{
|
||||
WRB_SEQNO(wrb) = conn->isn + conn->sent;
|
||||
}
|
||||
|
||||
uip_tcpsetsequence(conn->sndseq, WRB_SEQNO(wrb));
|
||||
}
|
||||
|
||||
/* Then set-up to send that amount of data with the offset
|
||||
* corresponding to the amount of data already sent. (this
|
||||
* won't* actually happen until the polling cycle completes).
|
||||
*/
|
||||
|
||||
uip_iobsend(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb));
|
||||
|
||||
/* Remember how much data we send out now so that we know
|
||||
* when everything has been acknowledged. Just increment
|
||||
@ -330,7 +496,7 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
* this path.
|
||||
*/
|
||||
|
||||
if (segment->wb_nrtx == 0)
|
||||
if (WRB_NRTX(wrb) == 0)
|
||||
{
|
||||
conn->unacked += sndlen;
|
||||
conn->sent += sndlen;
|
||||
@ -343,11 +509,31 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
* second interval before expiration.
|
||||
*/
|
||||
|
||||
segment->wb_nrtx++;
|
||||
WRB_NRTX(wrb)++;
|
||||
nllvdbg("nrtx=%d unacked=%d sent=%d\n",
|
||||
WRB_NRTX(wrb), conn->unacked, conn->sent);
|
||||
|
||||
/* The segment is waiting for ACK again */
|
||||
/* Remove the write buffer from the write queue if the
|
||||
* last of the data has been sent from the buffer.
|
||||
*/
|
||||
|
||||
send_insert_seqment(segment, &conn->unacked_q);
|
||||
WRB_SENT(wrb) += sndlen;
|
||||
DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb));
|
||||
|
||||
if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb))
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *tmp;
|
||||
|
||||
tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||
DEBUGASSERT(tmp == wrb);
|
||||
UNUSED(tmp);
|
||||
|
||||
/* Put the I/O buffer chin in the unacked queue; the
|
||||
* segment is waiting for ACK again
|
||||
*/
|
||||
|
||||
send_insert_seqment(wrb, &conn->unacked_q);
|
||||
}
|
||||
|
||||
/* Only one data can be sent by low level driver at once,
|
||||
* tell the caller stop polling the other connection.
|
||||
@ -360,15 +546,6 @@ static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn,
|
||||
|
||||
/* Continue waiting */
|
||||
|
||||
return flags;
|
||||
|
||||
end_wait:
|
||||
|
||||
/* Do not allow any further callbacks */
|
||||
|
||||
psock->s_sndcb->flags = 0;
|
||||
psock->s_sndcb->event = NULL;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@ -444,7 +621,7 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
int flags)
|
||||
{
|
||||
uip_lock_t save;
|
||||
ssize_t completed = 0;
|
||||
ssize_t result = 0;
|
||||
int err;
|
||||
int ret = OK;
|
||||
|
||||
@ -477,16 +654,19 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
psock->s_sndcb = uip_tcpcallbackalloc(conn);
|
||||
}
|
||||
|
||||
/* Test if the callback has been allocated*/
|
||||
/* Test if the callback has been allocated */
|
||||
|
||||
if (!psock->s_sndcb)
|
||||
{
|
||||
/* A buffer allocation error occurred */
|
||||
|
||||
completed = -ENOMEM;
|
||||
ndbg("ERROR: Failed to allocate callback\n");
|
||||
result = -ENOMEM;
|
||||
}
|
||||
else
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *wrb = tcp_wrbuffer_alloc();
|
||||
|
||||
/* Set up the callback in the connection */
|
||||
|
||||
psock->s_sndcb->flags = (UIP_ACKDATA | UIP_REXMIT |UIP_POLL | \
|
||||
@ -494,47 +674,35 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
psock->s_sndcb->priv = (void*)psock;
|
||||
psock->s_sndcb->event = send_interrupt;
|
||||
|
||||
while (completed < len)
|
||||
/* Allocate an write buffer */
|
||||
|
||||
wrb = tcp_wrbuffer_alloc();
|
||||
if (wrb)
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *segment = tcp_wrbuffer_alloc(NULL);
|
||||
if (segment)
|
||||
{
|
||||
size_t cnt;
|
||||
/* Initialize the write buffer */
|
||||
|
||||
segment->wb_seqno = (unsigned)-1;
|
||||
segment->wb_nrtx = 0;
|
||||
WRB_SEQNO(wrb) = (unsigned)-1;
|
||||
WRB_NRTX(wrb) = 0;
|
||||
WRB_COPYIN(wrb, (FAR uint8_t *)buf, len);
|
||||
|
||||
if (len - completed > CONFIG_NET_TCP_WRITE_BUFSIZE)
|
||||
{
|
||||
cnt = CONFIG_NET_TCP_WRITE_BUFSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
cnt = len - completed;
|
||||
}
|
||||
/* send_interrupt() will send data in FIFO order from the
|
||||
* conn->write_q
|
||||
*/
|
||||
|
||||
segment->wb_nbytes = cnt;
|
||||
memcpy(segment->wb_buffer, (char*)buf + completed, cnt);
|
||||
completed += cnt;
|
||||
sq_addlast(&wrb->wb_node, &conn->write_q);
|
||||
|
||||
/* send_interrupt() will refer to all the write buffer by
|
||||
* conn->writebuff
|
||||
*/
|
||||
/* Notify the device driver of the availability of TX data */
|
||||
|
||||
sq_addlast(&segment->wb_node, &conn->write_q);
|
||||
netdev_txnotify(conn->ripaddr);
|
||||
result = len;
|
||||
}
|
||||
|
||||
/* Notify the device driver of the availability of TX data */
|
||||
/* A buffer allocation error occurred */
|
||||
|
||||
netdev_txnotify(conn->ripaddr);
|
||||
}
|
||||
|
||||
/* A buffer allocation error occurred */
|
||||
|
||||
else
|
||||
{
|
||||
completed = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ndbg("ERROR: Failed to allocate write buffer\n");
|
||||
result = -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -549,9 +717,9 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
* for the send length
|
||||
*/
|
||||
|
||||
if (completed < 0)
|
||||
if (result < 0)
|
||||
{
|
||||
err = completed;
|
||||
err = result;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@ -567,7 +735,7 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len,
|
||||
|
||||
/* Return the number of bytes actually sent */
|
||||
|
||||
return completed;
|
||||
return result;
|
||||
|
||||
errout:
|
||||
set_errno(err);
|
||||
|
@ -467,7 +467,6 @@ static uint16_t tcpsend_interrupt(FAR struct uip_driver_s *dev,
|
||||
|
||||
uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent;
|
||||
|
||||
|
||||
#if defined(CONFIG_NET_TCP_SPLIT)
|
||||
|
||||
/* RFC 1122 states that a host may delay ACKing for up to 500ms but
|
||||
|
@ -82,6 +82,7 @@ endif # NET_TCP_READAHEAD
|
||||
config NET_TCP_WRITE_BUFFERS
|
||||
bool "Enable TCP/IP write buffering"
|
||||
default n
|
||||
select NET_IOB
|
||||
---help---
|
||||
Write buffers allows buffering of ongoing TCP/IP packets, providing
|
||||
for higher performance, streamed output.
|
||||
@ -91,34 +92,15 @@ config NET_TCP_WRITE_BUFFERS
|
||||
|
||||
if NET_TCP_WRITE_BUFFERS
|
||||
|
||||
config NET_TCP_WRITE_BUFSIZE
|
||||
int "TCP/IP write buffer size"
|
||||
default 1220 if !NET_SLIP && NET_IPv6
|
||||
default 536 if !NET_SLIP && !NET_IPv6
|
||||
default 256 if NET_SLIP && !NET_IPv6
|
||||
---help---
|
||||
Write buffers allows buffering of ongoing TCP/IP packets, providing
|
||||
for higher performance, streamed output.
|
||||
|
||||
The size of the write buffer will determine the maximum size of an
|
||||
outgoing TCP packet payload (MSS). This value should NOT exceed the
|
||||
maximum MSS which is determined by NET_BUFSIZE minus the size of
|
||||
TCP, IP, and Ethernet headers (assuming you are using the Ethernet
|
||||
transport). IPv4 hosts are required to be able to handle an MSS
|
||||
of 536 octets and IPv6 hosts are required to be able to handle an
|
||||
MSS of 1220 octets.
|
||||
|
||||
This setting specifies the size of one TCP/IP write buffer. This
|
||||
should best be a equal to the maximum packet size (NET_BUFSIZE).
|
||||
|
||||
config NET_NTCP_WRITE_BUFFERS
|
||||
int "Number of TCP/IP write buffers"
|
||||
config NET_TCP_NWRBCHAINS
|
||||
int "Number of pre-allocated I/O buffer chain heads"
|
||||
default 8
|
||||
---help---
|
||||
Write buffers allows buffering of ongoing TCP/IP packets, providing
|
||||
for higher performance, streamed output.
|
||||
|
||||
This setting specifies the number of TCP/IP write buffers.
|
||||
These tiny nodes are used as "containers" to support queueing of
|
||||
TCP write buffers. This setting will limit the number of TCP write
|
||||
operations that can be "in-flight" at any give time. So a good
|
||||
choice for this value would be the same as the maximum number of
|
||||
TCP connections.
|
||||
|
||||
config NET_TCP_WRBUFFER_DEBUG
|
||||
bool "Force write buffer debug"
|
||||
|
@ -51,6 +51,9 @@ endif
|
||||
|
||||
ifeq ($(CONFIG_NET_TCP_WRITE_BUFFERS),y)
|
||||
NET_CSRCS += tcp_wrbuffer.c
|
||||
ifeq ($(CONFIG_DEBUG),y)
|
||||
NET_CSRCS += tcp_wrbuffer_dump.c
|
||||
endif
|
||||
endif
|
||||
|
||||
# Include TCP build support
|
||||
|
@ -98,10 +98,8 @@ void tcp_wrbuffer_initialize(void);
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
struct tcp_wrbuffer_s;
|
||||
struct timespec;
|
||||
|
||||
FAR struct tcp_wrbuffer_s *
|
||||
tcp_wrbuffer_alloc(FAR const struct timespec *abstime);
|
||||
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void);
|
||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||
|
||||
/****************************************************************************
|
||||
@ -118,7 +116,23 @@ tcp_wrbuffer_alloc(FAR const struct timespec *abstime);
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrbuffer);
|
||||
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb);
|
||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||
|
||||
/****************************************************************************
|
||||
* Function: tcp_writebuffer_dump
|
||||
*
|
||||
* Description:
|
||||
* Dump the contents of a write buffer.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_TCP_WRITE_BUFFERS
|
||||
#ifdef CONFIG_DEBUG
|
||||
void tcp_writebuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb);
|
||||
#else
|
||||
# define tcp_writebuffer_dump(msg,wrb)
|
||||
#endif
|
||||
#endif /* CONFIG_NET_TCP_WRITE_BUFFERS */
|
||||
|
||||
#undef EXTERN
|
||||
|
@ -50,9 +50,13 @@
|
||||
|
||||
#include <queue.h>
|
||||
#include <semaphore.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "uip/uip_internal.h"
|
||||
#include "tcp/tcp.h"
|
||||
#include "nuttx/net/iob.h"
|
||||
#include "nuttx/net/uip/uip-tcp.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
@ -72,7 +76,7 @@ struct wrbuffer_s
|
||||
|
||||
/* These are the pre-allocated write buffers */
|
||||
|
||||
struct tcp_wrbuffer_s buffers[CONFIG_NET_NTCP_WRITE_BUFFERS];
|
||||
struct tcp_wrbuffer_s buffers[CONFIG_NET_TCP_NWRBCHAINS];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -108,12 +112,12 @@ void tcp_wrbuffer_initialize(void)
|
||||
|
||||
sq_init(&g_wrbuffer.freebuffers);
|
||||
|
||||
for (i = 0; i < CONFIG_NET_NTCP_WRITE_BUFFERS; i++)
|
||||
for (i = 0; i < CONFIG_NET_TCP_NWRBCHAINS; i++)
|
||||
{
|
||||
sq_addfirst(&g_wrbuffer.buffers[i].wb_node, &g_wrbuffer.freebuffers);
|
||||
}
|
||||
|
||||
sem_init(&g_wrbuffer.sem, 0, CONFIG_NET_NTCP_WRITE_BUFFERS);
|
||||
sem_init(&g_wrbuffer.sem, 0, CONFIG_NET_TCP_NWRBCHAINS);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -129,26 +133,39 @@ void tcp_wrbuffer_initialize(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct tcp_wrbuffer_s *
|
||||
tcp_wrbuffer_alloc(FAR const struct timespec *abstime)
|
||||
FAR struct tcp_wrbuffer_s *tcp_wrbuffer_alloc(void)
|
||||
{
|
||||
int ret;
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
|
||||
if (abstime)
|
||||
{
|
||||
ret = sem_timedwait(&g_wrbuffer.sem, abstime);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sem_wait(&g_wrbuffer.sem);
|
||||
}
|
||||
/* We need to allocate two things: (1) A write buffer structure and (2)
|
||||
* at least one I/O buffer to start the chain.
|
||||
*
|
||||
* Allocate the write buffer structure first then the IOBG. In order to
|
||||
* avoid deadlocks, we will need to free the IOB first, then the write
|
||||
* buffer
|
||||
*/
|
||||
|
||||
if (ret != 0)
|
||||
DEBUGVERIFY(sem_wait(&g_wrbuffer.sem));
|
||||
|
||||
/* Now, we are guaranteed to have a write buffer structure reserved
|
||||
* for us in the free list.
|
||||
*/
|
||||
|
||||
wrb = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&g_wrbuffer.freebuffers);
|
||||
DEBUGASSERT(wrb);
|
||||
memset(wrb, 0, sizeof(struct tcp_wrbuffer_s));
|
||||
|
||||
/* Now get the first I/O buffer for the write buffer structure */
|
||||
|
||||
wrb->wb_iob = iob_alloc();
|
||||
if (!wrb->wb_iob)
|
||||
{
|
||||
ndbg("ERROR: Failed to allocate I/O buffer\n");
|
||||
tcp_wrbuffer_release(wrb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (FAR struct tcp_wrbuffer_s*)sq_remfirst(&g_wrbuffer.freebuffers);
|
||||
return wrb;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -164,9 +181,19 @@ tcp_wrbuffer_alloc(FAR const struct timespec *abstime)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrbuffer)
|
||||
void tcp_wrbuffer_release(FAR struct tcp_wrbuffer_s *wrb)
|
||||
{
|
||||
sq_addlast(&wrbuffer->wb_node, &g_wrbuffer.freebuffers);
|
||||
DEBUGASSERT(wrb && wrb->wb_iob);
|
||||
|
||||
/* To avoid deadlocks, we must following this ordering: Release the I/O
|
||||
* buffer chain first, then the write buffer structure.
|
||||
*/
|
||||
|
||||
iob_free_chain(wrb->wb_iob);
|
||||
|
||||
/* Then free the write buffer structure */
|
||||
|
||||
sq_addlast(&wrb->wb_node, &g_wrbuffer.freebuffers);
|
||||
sem_post(&g_wrbuffer.sem);
|
||||
}
|
||||
|
||||
|
89
net/tcp/tcp_wrbuffer_dump.c
Normal file
89
net/tcp/tcp_wrbuffer_dump.c
Normal file
@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
* net/tcp/tcp_wrbuffer_dump.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/iob.h>
|
||||
#include <nuttx/net/uip/uip-tcp.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Select the lowest level debug interface available */
|
||||
|
||||
#ifdef CONFIG_CPP_HAVE_VARARGS
|
||||
# ifdef CONFIG_ARCH_LOWPUTC
|
||||
# define message(format, ...) lowsyslog(format, ##__VA_ARGS__)
|
||||
# else
|
||||
# define message(format, ...) syslog(format, ##__VA_ARGS__)
|
||||
# endif
|
||||
#else
|
||||
# ifdef CONFIG_ARCH_LOWPUTC
|
||||
# define message lowsyslog
|
||||
# else
|
||||
# define message syslog
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcp_wrbuffer_dump
|
||||
*
|
||||
* Description:
|
||||
* Dump the contents of a write buffer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void tcp_wrbuffer_dump(FAR const char *msg, FAR struct tcp_wrbuffer_s *wrb)
|
||||
{
|
||||
message("%s: WRB=%p segno=%d sent=%d nrtx=%d\n",
|
||||
msg, wrb, WRB_SEQNO(wrb), WRB_SENT(wrb), WRB_NRTX(wrb));
|
||||
iob_dump("I/O Buffer Chain", WRB_IOB(wrb));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG */
|
@ -40,6 +40,12 @@ ifeq ($(CONFIG_NET),y)
|
||||
NET_CSRCS += uip_initialize.c uip_setipid.c uip_input.c uip_send.c
|
||||
NET_CSRCS += uip_poll.c uip_chksum.c uip_callback.c
|
||||
|
||||
# I/O buffer chain support required?
|
||||
|
||||
ifeq ($(CONFIG_NET_IOB),y)
|
||||
NET_CSRCS += uip_iobsend.c
|
||||
endif
|
||||
|
||||
# Non-interrupt level support required?
|
||||
|
||||
ifeq ($(CONFIG_NET_NOINTS),y)
|
||||
|
105
net/uip/uip_iobsend.c
Normal file
105
net/uip/uip_iobsend.c
Normal file
@ -0,0 +1,105 @@
|
||||
/****************************************************************************
|
||||
* net/uip/uip_iobsend.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* 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 <string.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/iob.h>
|
||||
#include <nuttx/net/uip/uip.h>
|
||||
#include <nuttx/net/uip/uip-arch.h>
|
||||
|
||||
#ifdef CONFIG_NET_IOB
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Type Declarations
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Global Constant Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Global Variables
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Constant Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Variables
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Global Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: uip_iobsend
|
||||
*
|
||||
* Description:
|
||||
* Called from socket logic in response to a xmit or poll request from the
|
||||
* the network interface driver.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called from the interrupt level or, at a minimum, with interrupts
|
||||
* disabled.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void uip_iobsend(FAR struct uip_driver_s *dev, FAR struct iob_s *iob,
|
||||
unsigned int len, unsigned int offset)
|
||||
{
|
||||
DEBUGASSERT(dev && len > 0 && len < CONFIG_NET_BUFSIZE);
|
||||
|
||||
iob_copyout(dev->d_snddata, iob, len, offset);
|
||||
dev->d_sndlen = len;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NET_IOB */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* net/uip/uip_send.c
|
||||
*
|
||||
* Copyright (C) 2007i, 2008 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2007, 2008 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Based in part on uIP which also has a BSD stylie license:
|
||||
@ -42,6 +42,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/net/uip/uip.h>
|
||||
@ -94,13 +95,8 @@
|
||||
|
||||
void uip_send(struct uip_driver_s *dev, const void *buf, int len)
|
||||
{
|
||||
/* Some sanity checks -- note that the actually available length in the
|
||||
* buffer is considerably less than CONFIG_NET_BUFSIZE.
|
||||
*/
|
||||
DEBUGASSERT(dev && len > 0 && len < CONFIG_NET_BUFSIZE);
|
||||
|
||||
if (dev && len > 0 && len < CONFIG_NET_BUFSIZE)
|
||||
{
|
||||
memcpy(dev->d_snddata, buf, len);
|
||||
dev->d_sndlen = len;
|
||||
}
|
||||
memcpy(dev->d_snddata, buf, len);
|
||||
dev->d_sndlen = len;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user