EDK9.1 LWIP network stack crashing?

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Greetings all,

I'm encountering a problem with the lwip network stack.  Perhaps someone
can spot what I'm missing.

My hardware is an ML405 board.  I'm using essentially the reference PPC
design with the Ethernet replaced with the hard TEMAC core.  My software
stack is derived from the TEMAC example design, echo.c (from
ml403_ppc_lwip_temac_fifo_91i.zip on the Xilnx website).

I kept the echo port from the example design, and added a second port
for a command interpreter (behind which the real functions are
implemented; they aren't important for purposes of this question).

===================================

/* Standard */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "lwip/sys.h"    // threads &c
#include "lwip/sockets.h"
#include "lwip/inet.h"

/*
  * Thread for each ECHO connection
  */
void *net_echo_processor(void *arg)
{
   int len;
   char buf[400];
   int s;

   // Copy the file descriptor then release it
   s = *((int*) arg);
////  sys_sem_signal(echo_launch_sem);

   LOG(printf("net_echo_processor: Processing data for connection %d\n",
s));
   while((len = read(s,buf,400)) > 0) {
     write(s,buf,len);
   }

   LOG(printf("net_echo_processor: Closing socket\n"));
   close(s);
}


/*
  * Thread for each Command connection
  */
void *net_command_processor(void *arg)
{
   int len;
   cmd_t cmd;

   char buf[400];

   // Copy the file descriptor then release it
   cmd.sock = *((int*) arg);
////  sys_sem_signal(command_launch_sem);

   // Allocate buffers for command/response data. Allow 1 extra char
   //  for terminating null.
   cmd.state = IDLE;
   cmd.c_buf = malloc((CMD_BUFFER_SIZE+1) * sizeof(char));
   cmd.c_ptr = cmd.c_buf;
   cmd.c_fill = 0;
   cmd.r_buf = malloc((CMD_BUFFER_SIZE+1) * sizeof(char));
   cmd.tx_buf_idx = TX_BUFFER_NO; // default transmit buffer

   // Banner
   LOG(printf("net_command_processor: Processing data for connection %d\n",
       cmd.sock));
   len = sprintf(buf, "# foo Adapter\r\n"
                 "# Ethernet Interface\r\n"
                 "# Version %d.%d.%d\r\n",
                 VER_MAJOR, VER_MINOR, VER_BUILD);
   write(cmd.sock, buf, len);
   if ((cmd.c_buf == NULL) || (cmd.r_buf == NULL)) {
     len = sprintf(buf, "er 5 ER_NOMEM # No Memory for command struct!\r\n"
                        "## Aborting...\r\n\r\n\r\n");
     write(cmd.sock, buf, len);
     close(cmd.sock);
     free(cmd.c_buf);
     free(cmd.r_buf);
     return;
   } else {
     len = sprintf(buf, "st TBD TBD TBD # Status not yet implemented\r\n");
     write(cmd.sock, buf, len);
   }

   // Initialization complete

   // Loop repeatedly, get buffers of data and call the command parser
   // Note c_buf is the start of the command buffer, and c_ptr is the
   // start of where the read is allowed to put data (there may be a
   // partially processed command in the buffer).
   while((len = read(cmd.sock,cmd.c_ptr,
                     (CMD_BUFFER_SIZE-(cmd.c_ptr-cmd.c_buf)))) > 0) {
     //write(s,buf,len);
     cmd.c_fill += len;
     cmd.c_ptr = &cmd.c_buf[cmd.c_fill];
     *(cmd.c_ptr) = '';
     parse_command(&cmd);
     // Check for exit
     if (cmd.state == LNK_CLOSE)
       break;
   }

   // Connection closed, exit
   LOG(printf("net_command_processor: Closing socket\r\n"));
   free(cmd.c_buf);
   free(cmd.r_buf);
   close(cmd.sock);
}


/*
  * Socket listeners
  *
  */

void *net_echo_listener(void *arg)
{
   int sock, s;
   int len;
   struct sockaddr_in addr, rem;

   // Initialize the protection of 's' to "locked"
////  echo_launch_sem = sys_sem_new(0);

   LOG(printf("net_echo_listener: Creating socket\n"));
   sock = socket(AF_INET, SOCK_STREAM, 0);

   LOG(printf("net_echo_listener: Doing bind\n"));
   addr.sin_family = AF_INET;
   addr.sin_port = htons(ECHO_PORT);
   addr.sin_addr.s_addr = INADDR_ANY;
   bind(sock, (struct sockaddr *)&addr, sizeof(addr));

   LOG(printf("net_echo_listener: Listening\n"));
   listen(sock, 5);

   while(1) {
     len = sizeof(rem);
     s = accept(sock, NULL, NULL);
//    s = accept(sock, (struct sockaddr *)&rem, &len);
     LOG(printf("net_echo_listener: Accepting new connection\n"));
     // Thread is expected to release protection for 's' once it's copied
////    sys_thread_new(net_echo_processor, &s, 7);
     net_echo_processor(&s);
     // Wait until thread is done initializing and re-protect 's'
////    sys_sem_wait(echo_launch_sem);
   }

}

void *net_command_listener(void *arg)
{
   int sock, s;
   int len;
   struct sockaddr_in addr, rem;

   // Initialize the protection of 's' to "locked"
////  command_launch_sem = sys_sem_new(0);

   LOG(printf("net_command_listener: Creating socket\n"));
   sock = socket(AF_INET, SOCK_STREAM, 0);

   LOG(printf("net_command_listener: Doing bind\n"));
   addr.sin_family = AF_INET;
   addr.sin_port = htons(COMMAND_PORT);
   addr.sin_addr.s_addr = INADDR_ANY;
   bind(sock, (struct sockaddr *)&addr, sizeof(addr));

   LOG(printf("net_command_listener: Listening\n"));
   listen(sock, 5);

   while(1) {
     len = sizeof(rem);
     s = accept(sock, NULL, NULL);
//    s = accept(sock, (struct sockaddr *)&rem, &len);
     LOG(printf("net_command_listener: Accepting new connection\n"));
     // Thread is expected to release protection for 's' once it's copied
////    sys_thread_new(net_command_processor, &s, 7);
     net_command_processor(&s);
     // Wait until thread is done initializing and re-protect 's'
////    sys_sem_wait(command_launch_sem);
//     LOG(printf("net_command_listener: Launched new command processor\n"));
   }


}


/*
  * Network subsystem main entry point
  *
  *  - Initialize LwIP and the TEMAC.
  *  - Register IP address
  *  - Launch service listener threads
  *
  * Initialization assumes only one network interface implemented.
  *
  */
void *network_main(void *arg)
{

   /*
    * Initialize network hardware and TCP stack
    *
    */
   if (network_init()) {
     LOG(printf("network_main: Initialization failed!\n"));
     exit(-1);
   } else {
     LOG(printf("network_main: Network Initialized.\n"));
   }


   /*
    * Launch service threads
    */
   sys_thread_new(net_echo_listener, 0, 7);  // lowish priority
   sys_thread_new(net_command_listener, 0, 7); // lowish priority

    /*
    * Exit, nothing left to do
    */
}

====================================

The module entry point, network_main() is a thread started after
xilkernel and lwip are initialized.  The network_init() function
initializes the TEMAC hardware, and is lifted from the example echo.c.
LOG() is a wrapper around printf() to assert a semaphore while printing
in order for messages to not step on each other.  parse_command() is
where the actual work happens.

I use a stock linux telnet to access the echo and operation ports.  The
echo port works as expected.  So does the "command" port.  If I
disconnect by using the Telnet escape sequence (i.e. initiate the
disconnect from the telnet client end) I can reconnect with no trouble.
However one of the operations behind parse_command() is supposed to
result in a disconnect - in the loop in net_command_processor()
parse_comand() sets cmd.state to LNK_CLOSE, resulting in the loop
exiting and closing the socket handle.  When that happens, neither the
command port nor the echo port can be accessed any longer.  It's as
though lwip is well and truly crashed.

A secondary, and possibly related problem is I thought the parameter 5
in listen() allows up to 5 connections.  Only one connection is possible.

 From my approach to the problem you can easily tell my experience doing
sockets programming is limited.  I'd appreciate any clues as to what
might be going wrong, or at least where I could try looking.

Thanks in advance!

    ken

Site Timeline