Commit Graph

25 Commits (9c6dd060dc4efbb71a725fff66975819c7ff6782)

Author SHA1 Message Date
Martin Kojtal a681b14416 Change "error.h" to "mbed_error.h" to avoid conflicts with 3rd party code 2014-08-15 16:19:18 +01:00
Martin Kojtal 09251dd3ba Revert "error.h -> mbed_error.h" 2014-07-08 14:04:50 +02:00
0xc0170 1dcc9246bd [LWIP] error.h -> mbed_error.h 2014-07-07 06:26:54 +02:00
Bogdan Marinescu 94fd2228fb Added K64F TCP/IP support
Currently NET_7 (HttpClient test) and NET_8 (NTP test) fail for
unknown reasons.
2014-04-23 16:16:38 +01:00
mazgch bdd80ab5f3 add errors in case some target defines were not set properly 2014-03-20 16:06:24 +01:00
Andreas Rebert f5511ff82a [LPC4088]: elif should have been else 2013-12-07 12:29:06 +01:00
Andreas Rebert 4109fb7d07 [LPC4088]: Networking was broking when splitting peripheral RAM into two sections 2013-12-06 15:36:37 +01:00
Adam Green 692cbd11f6 lwip: Fix invalid checksum bug
tcp_write() would incorrectly byte swap the checksum 1 too many times
when concatenating a pbuf to an existing TCP segment if the number of
bytes in the concatenated data was odd.  I hit this issue when I tried
to reproduce a lost segment issue reported by a mbed user in this forum
thread: http://mbed.org/forum/mbed/topic/4354/?page=2#comment-22657
2013-10-29 23:41:21 -07:00
Adam Green 7dddd9e578 Asm versions of netstack memcpy() and lwip_standard_chksum()
For tests such as TCPEchoServer
(http://mbed.org/users/emilmont/notebook/networking-libraries-benchmark/)
this change showed a 28% improvement (14Mbps to 18Mbps) when the echo
test was modified to instead use 1K data buffers.

I targetted these two functions based on manual profiling samples which
showed that a great deal of time was being spent in these two functions
when the network stack was being slammed with UDP packets.
2013-08-30 06:09:16 -07:00
Adam Green f5ec5d3ab2 net: Enable SYS_LIGHTWEIGHT_PROT
This option actually enables the use of the lwip_sys_mutex for
protecting concurrent access to such important lwIP resources as:
  select_cb_list (this is the one which orig flagged problem)
  sockets array
  mem stats (if enabled)
  heap (if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT was non-zero)
  memp pool allocs/frees
  netif->loop_last pbuf linked list
  pbuf reference counts
  ...

I first noticed this issue when I hit a crash while slamming the net
stack with a large number of TCP packets (I was actually sending 1k
data buffers from the TCPEchoServer mbed sample.)  It crashed in the
last line of this code snippet from event_callback:
  for (scb = select_cb_list; scb != NULL; scb = scb->next) {
    if (scb->sem_signalled == 0) {

It was crashing because scb had an invalid address so it generated a
bus fault.  I figured that memory was either corrupted or there was
some kind of concurrency issue.  In trying to determine which, I wanted
to walk through the select_cb_list linked list and see where it was
corrupted:
    (gdb) p scb
    $1 = (struct lwip_select_cb *) 0x85100080
    (gdb) p select_cb_list
    $2 = (struct lwip_select_cb *) 0x0

That was interesting, the head of the linked list was now NULL but it
must have had a non-NULL value when this loop started running or we
would have never gotten to the point where we hit this crash.

This was starting to look like a concurrency issue since the linked
list was modified out from underneath this thread.  Looking through the
source code for this function, I saw use of macros like
SYS_ARCH_PROTECT and SYS_ARCH_UNPROTECT which looked like they should
be providing the thead synchronization.  I disassembled the
event_callback() function in the debugger and saw no signs of the
usage of synchronizition APIs that I expected.  A search
through the code for the definition of these SYS_ARCH_UN/PROTECT
macros led me to discovering that they were actually ignored unless an
implementation defined them itself (the mbed version doesn't do so) or
the SYS_LIGHTWEIGHT_PROT macro is set to non-zero (the mbed version
didn't do this either).  Flipping the SYS_LIGHTWEIGHT_PROT macro on in
lwipopts.h fixed the crash I kept hitting, increased the size of the
code a bit, and unfortunately slows things down a bit since it now
actually serializes access to these data structures by making calls
to the RTOS sync APIs.
2013-08-27 22:24:03 -07:00
Adam Green fa392423c8 Silence GCC unused variable warning.
After making my previous commit to completely disable LWIP_ASSERT
macro invocations, I ended up with a warning in pbuf.c where an
err variable was set but only checked for success in an assert.  I
added a "(void)err;" reference to silence this warning.
2013-08-27 22:24:03 -07:00
Adam Green 4603d729f9 net: Fully disable LWIP_ASSERTs
I was doing some debugging that had me looking at the disassembly of
lpc_rx_queue() from within the debugger.  I was looking for the call to
pbuf_alloc() that we see in the following code snippet:
		p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
		if (p == NULL) {
			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
				("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\n",
				lpc_enetif->rx_free_descs));
			return queued;
		}

		/* pbufs allocated from the RAM pool should be non-chained. */
		LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)",
			pbuf_clen(p) <= 1);

When I was looking through the disassembly for this code I noticed a
call to pbuf_clen() in the actual machine code.
=> 0x0000bab0 <+24>:	bl	0x44c0 <pbuf_clen>
   0x0000bab4 <+28>:	ldr	r3, [r4, #112]	; 0x70
   0x0000bab6 <+30>:	ldrh.w	r12, [r5, #10]
   0x0000baba <+34>:	add.w	r2, r3, #9
   0x0000babe <+38>:	add.w	r0, r12, #4294967295	; 0xffffffff

The only call to pbuf_clean made from this function is made from
within the LWIP_ASSERT.  When I looked more closely at how this macro
was defined, I saw that the mbed version of the stack had disabled the
LWIP_PLATFORM_ASSERT macro when LWIP_DEBUG was false which means that
no action will be taken if the assert is false but it still allows the
LWIP_ASSERT macro to potentially evaluate the assert expression.
Defining the LWIP_NOASSERT macro will fully disable the LWIP_ASSERT
macro.

I saw one of my TCP/IP samples shrink about 0.5K when I made this
change.
2013-08-27 22:24:03 -07:00
Adam Green e0fb0a8f9b Don't dereference NULL ipaddr in netif_set_ipaddr()
The code in netif_set_ipaddr would read the memory pointed to by its
ipaddr parameter, even if it was NULL on this line:
  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) {
On the Cortex-M3, it is typically OK to read from address 0 so this
code will actually compare the reset stack pointer value to the
current value in netif->ip_addr.

Later in the code, this same pointer will be used for a second read:
  ip_addr_set(&(netif->ip_addr), ipaddr);

The ip_addr_set call will first check to see if the ipaddr is NULL and
if so, treats it like IP_ADDR_ANY (4 bytes of 0).
    /** Safely copy one IP address to another (src may be NULL) */
    #define ip_addr_set(dest, src) ((dest)->addr = \
                                        ((src) == NULL ? 0 : \
                                        (src)->addr))

The issue here is that when GCC optimizes this code, it assumes that
the first dereference of ipaddr would have thrown an invalid memory
access exception and execution would never make it to this second
dereference.  Therefore it optimizes out the NULL check in ip_addr_set.

The -fno-delete-null-pointer-checks will disable this optimization and
is a good thing to use with GCC in general on Cortex-M parts.  I will
let the mbed guys make that change to their build system.

I have however corrected the code so that the intent of how to handle a
NULL ipaddr is more obvious and gets rid of the potential NULL
dereference.

By the way, this bug caused connect() to fail in obtaining an
address from DHCP.  If I recall correctly from when I first debugged
this issue (late last year), I actually saw the initial value of the
stack pointer being used in the DHCP request as an IP address which
caused it to be rejected.
2013-08-15 19:02:51 -07:00
Bogdan Marinescu 44c43e6e38 Restore C++98 compilation mode
Also, remove the line that required C++11 from UDPSocket.h
2013-08-15 14:09:20 +03:00
Adam Green 657e6df203 Updates to network code to improve performance/robustness
I started out looking at some UDP receive code that was only able to
handle 3 inbound 550 byte datagrams out of 16 when sent in quick
succession.  I stepped through the ethernet driver code and it
seemed to work as expected but it just couldn't queue up more than
3 PBUFs for each burst.  It was almost like it was being starved of
CPU cycles.  Based on that observation, I looked up the thread
priorities for the receive ethernet thread and found the following
close to the top of the lpc17_emac.c source file:
    #define RX_PRIORITY   (osPriorityNormal)
This got me to thinking, what is the priority of the tcp thead?  It
turns out that it gets its priority from the following line in
lwipopts.h:
    #define TCPIP_THREAD_PRIO           1
Interesting!  What priority is 1?  It turns out that it corresponds
to osPriorityAboveNormal.  This means that while the tcp thread is
handling one packet that has been posted to its mailbox from the
ethernet receive thread, the receive thread is starved from processing
any more inbound ethernet packets.

What happens if we set TCP_IP_THREAD_PRIO to osPriorityNormal?  Crash!
The ethernet driver ends up crashing in lpc_low_level_input() when
it tries to set p->len on a NULL p pointer.  The p pointer ended up
being NULL because an earlier call to pbuf_alloc() in lpc_rx_queue()
failed its allocation (I will have more to say about this failed
allocation later since that is caused by yet another bug).  I pulled a
fix from http://lpcware.com/content/bugtrackerissue/lpc17xx-mac-bugs to
remedy this issue.  When the pbuf allocation fails, it discards the
inbound packet in the pbuf and just puts it back into the rx queue.
This means we never end up with a NULL pointer in that queue to
dereference and crash on.

With that bug fixed, the application would just appear to hang after
receiving and processing a few datagrams.  I could place breakpoints in
the packet_rx() thread function and found that it was being signalled
by the ethernet ISR but it was always failing to allocate new PBUFs,
which is what led to our previous crash.  This means that the new
crash prevention code was just discarding every packet that arrived.

Why are these allocations failing?  In my opinion, this was the most
interesting bug to track down.  Is there a memory leak somewhere in
the code which maybe only triggers in low memory situations?  I
figured the easiest way to determine that would be to learn a bit
about the format of the lwIP heap from which the PBUF was failing to
be allocated.  I started by just stepping into the failing lwIP memory
allocator, mem_malloc().  The loop which search the free list starts
with this code:
    for (ptr = (mem_size_t)((u8_t *)lfree - ram);
This loop didn't even go through one iteration and when I looked at the
initial ptr value it contained a really large value.  It turns out that
lfree was actually lower than ram.  At this point I figured that lfree
had probably been corrupted during a free operation after one of the
heap allocations had been underflowed/overflowed to cause the metadata
for an allocation to be corrupted.  As I started thinking about how to
track that kind of bug down, I noticed that the ram variable might be
too large (0x20080a68).  I restarted the debugger and looked at the
initial value.  It was at a nice even address (0x2007c000) and
certainly nothing like what I saw when the allocations were failing.
This global variable shouldn't change at all during the execution of
the program.  I placed a memory access watchpoint on this ram variable
and it fired very quickly inside of the rt_mbx_send() function.  The
ram variable was being changed by this line in rt_mbx_send():
    p_MCB->msg[p_MCB->first] = p_msg;

What the what?  Why does writing to the mailbox queue overwrite the
ram global variable?  Let's start by looking at the data structure used
in the lwIP port to target RTX (defined in sys_arch.h):
// === MAIL BOX ===

typedef struct {
    osMessageQId    id;
    osMessageQDef_t def;
    uint32_t        queue[MB_SIZE];
} sys_mbox_t;

Compare that to the utility macro that RTX defines to help setup one of
these mailboxes with queue:
    #define osMessageQDef(name, queue_sz, type)   \
    uint32_t os_messageQ_q_##name[4+(queue_sz)]; \
    osMessageQDef_t os_messageQ_def_##name = \
    { (queue_sz), (os_messageQ_q_##name) }
Note the 4+(queue_sz) used in the definition of the message queue
array.  What a hack!  The RTX OS requires an extra 16 bytes to contain
its OS_MCB header and this is how it adds it in.  Obviously the
sys_mbox_t structure used in the lwIP OS targetting code doesn't have
this.  Without it, the RTX mailbox routines end up scribbling on
memory following the structure in memory.  Adding 4 in that structure
fixes the memory allocation failure that I was seeing and now the network
stack can handle between 7 and 10 datagrams within a burst.
2013-08-15 03:08:47 -07:00
Adam Green 962dd8bd8f Silence GCC warnings in dhcp.c
The first was a potential out of range index read in dhcp_handle_ack().
The (n < DNS_MAX_SERVERS) check should occur first.  There is also a
documented lwIP bug for this issue here:
    http://savannah.nongnu.org/bugs/?36170

In dhcp_bind() there is no need to perform the NULL check in
ip_addr_isany() for &gw_addr.  Just check (gw_addr.addr == IPADDR_ANY)
instead.

I refactored the chaddr[] copy in dhcp_create_msg() to first copy all
of the valid bytes in hwaddr and then pad the rest of the bytes with 0.
Before it used to check on every destination byte if it should copy or
pad.  GCC originally complained about an index out of range read from
the hwaddr[] array even though it was protected by a conditional
operator.  The refactor makes the intent a bit clearer and saves the
extra comparison per loop iteration.  It also stops GCC from
complaining :)
2013-08-14 20:17:54 -07:00
Adam Green 1cf5243206 Don't call ip_addr_isany() on objects which can't be NULL.
GCC will issue a warning when the ip_addr_isany() macro is used on
a pointer which can never be NULL since the macros NULL check will
always be false:
    #define ip_addr_isany(addr1) ((addr1) == NULL || \
                                  (addr1)->addr == IPADDR_ANY)

In these cases, it is probably clearer to just perform the
x.addr == IPADDR_ANY check inline.
2013-08-14 20:17:54 -07:00
Adam Green 6e95a5ecde Removed extra ALIGNED macro define 2013-08-14 20:17:53 -07:00
Adam Green e014b41377 Silence signed/unsigned comparison warnings in GCC
The dn variable in lpc_low_level_output() was originally defined as a
u32_t but it is later compared to the s32_t return value from
lpc_tx_ready().  Since it is intialized to pbuf_clean() which returns
a u8_t, a s32_t type can safely hold the initial value and remains
consistent with the signed lpc_tx_ready() comparison.

I also modifed writtenLen in TCPSocketConnection::send_all() and
readLen in TCPSocketConnection::recieve_all() to be of type int instead
of size_t.  This is more consistent with their usage within these
methods (they accumulate int ret values and are compared to the int
length value) and their use as a signed integer return values.
2013-08-14 20:17:53 -07:00
Emilio Monti 2c882199b4 Add lwIP copyright information 2013-08-06 14:55:22 +01:00
Andreas Rebert 2662e105c4 Add support for NXP LPC4088 2013-05-16 08:53:02 +02:00
Emilio Monti be73e26366 [mbed::net] Not shutting down the socket, before closing it, is not robust in lwIP 2013-05-14 10:41:47 +01:00
Emilio Monti 80518c489c Add LPC812 target. Update tests. Remove obsolete documentation. Move shared code among targets to target independent layer. 2013-03-14 11:52:38 +00:00
Emilio Monti a80058dc5f Add multicast and broadcast support 2013-03-01 17:02:35 +00:00
Emilio Monti 5c20760685 Initial commit of the mbed libraries and tools 2013-02-18 15:32:11 +00:00