EDK9.1 LWIP network stack crashing?

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 #include #include #include

#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) = '\0'; 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

Reply to
Ken Ryan
Loading thread data ...

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.