Index: trunk/kernel/devices/dev_nic.c
===================================================================
--- trunk/kernel/devices/dev_nic.c	(revision 674)
+++ trunk/kernel/devices/dev_nic.c	(revision 683)
@@ -1,3 +1,2 @@
-
 /*
  * dev_nic.c - NIC (Network Controler) generic device API implementation.
@@ -46,4 +45,8 @@
 void dev_nic_init( chdev_t * chdev )
 {
+
+assert( __FUNCTION__ , (chdev->func == DEV_FUNC_NIC) , 
+"bad func value");
+
     thread_t * new_thread;
     error_t    error;
@@ -74,10 +77,10 @@
 
     // build pointer on server function
-    void * func = is_rx ? &dev_nic_rx_server : &dev_nic_tx_server;
+    void * server_func = is_rx ? &dev_nic_rx_server : &dev_nic_tx_server;
 
     // create server thread
     error = thread_kernel_create( &new_thread,
                                   THREAD_DEV,
-                                  func,
+                                  server_func,
                                   chdev,
                                   lid ); 
@@ -120,8 +123,18 @@
     thread_t * this = CURRENT_THREAD;
     
-    xptr_t dev_xp = chdev_dir.nic_tx[0];
+    // get cluster and local pointer fo the nic_tx[0] chdev
+    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     chdev_t * dev_ptr = GET_PTR( dev_xp );
-
-    if( dev_xp == XPTR_NULL ) return -1;
+    cxy_t     dev_cxy = GET_CXY( dev_xp );
+
+    if( dev_xp == XPTR_NULL )
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : nic_tx[0] chdev undefined in chdev_dir of cluster %x\n",
+__FUNCTION__, local_cxy );
+#endif
+        return -1;
+    }
     
     // set command arguments in client thread descriptor
@@ -131,10 +144,14 @@
     this->nic_cmd.type   = NIC_CMD_GET_KEY;
 
+    // get cmd function pointer from nic_tx[0] chdev descriptor
+    dev_cmd_t * cmd = hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ));
+    
     // call driver 
-    dev_ptr->cmd( XPTR( local_cxy , this ) );
-
-    // get "status" 
+    cmd( XPTR( local_cxy , this ) );
+
+    // return command status 
     return this->nic_cmd.status;
-}
+
+}  // end dev_nic_get_key()
 
 //////////////////////////////////////////
@@ -146,8 +163,18 @@
     if( channel >= LOCAL_CLUSTER->nb_nic_channels ) return -1;
 
-    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
+    // get cluster and local pointer fo the nic_tx[channel] chdev
+    xptr_t    dev_xp  = chdev_dir.nic_tx[channel];
     chdev_t * dev_ptr = GET_PTR( dev_xp );
-
-    if( dev_xp == XPTR_NULL ) return -1;
+    cxy_t     dev_cxy = GET_CXY( dev_xp );
+
+    if( dev_xp == XPTR_NULL ) 
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : nic_tx[%d] chdev undefined in chdev_dir of cluster %x\n",
+__FUNCTION__, channel, local_cxy );
+#endif
+        return -1;
+    }
     
     // set command arguments in client thread descriptor
@@ -157,10 +184,14 @@
     this->nic_cmd.status = run;
 
+    // get cmd function pointer from nic_tx[channel] chdev descriptor
+    dev_cmd_t * cmd = hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ));
+    
     // call driver 
-    dev_ptr->cmd( XPTR( local_cxy , this ) );
+    cmd( XPTR( local_cxy , this ) );
 
     // return "error" 
     return this->nic_cmd.error;
-}
+
+}  // end dev_nic_set_run()
 
 //////////////////////////////////
@@ -169,8 +200,18 @@
     thread_t * this = CURRENT_THREAD;
 
+    // get cluster and local pointer fo the nic_tx[0] chdev
     xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     chdev_t * dev_ptr = GET_PTR( dev_xp );
+    cxy_t     dev_cxy = GET_CXY( dev_xp );
     
-    if( dev_xp == XPTR_NULL ) return -1;
+    if( dev_xp == XPTR_NULL ) 
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : nic_tx[0] chdev undefined in chdev_dir of cluster %x\n",
+__FUNCTION__, local_cxy );
+#endif
+        return -1;
+    }
     
     // set command arguments in client thread descriptor
@@ -178,10 +219,15 @@
     this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
 
+    // get cmd function pointer from nic_tx[0] chdev descriptor
+    dev_cmd_t * cmd = hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ));
+    
     // call driver 
-    dev_ptr->cmd( XPTR( local_cxy , this ) );
+    cmd( XPTR( local_cxy , this ) );
 
     // return "error" 
     return this->nic_cmd.error;
-}
+
+}  // end dev_nic_get_instru()
+
 
 ////////////////////////////////////
@@ -190,8 +236,18 @@
     thread_t * this = CURRENT_THREAD;
 
+    // get cluster and local pointer fo the nic_tx[0] chdev
     xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     chdev_t * dev_ptr = GET_PTR( dev_xp );
+    cxy_t     dev_cxy = GET_CXY( dev_xp );
     
-    if( dev_xp == XPTR_NULL ) return -1;
+    if( dev_xp == XPTR_NULL ) 
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : nic_tx[0] chdev undefined in chdev_dir of cluster %x\n",
+__FUNCTION__, local_cxy );
+#endif
+        return -1;
+    }
     
     // set command arguments in client thread descriptor
@@ -199,10 +255,14 @@
     this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
 
+    // get cmd function pointer from nic_tx[0] chdev descriptor
+    dev_cmd_t * cmd = hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ));
+    
     // call driver 
-    dev_ptr->cmd( XPTR( local_cxy , this ) );
+    cmd( XPTR( local_cxy , this ) );
 
     // return "error" 
     return this->nic_cmd.error;
-}
+
+}  // end dev_nic_clear_instru()
 
 
@@ -261,62 +321,21 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////
-// This static function computes the checksum for an UDP packet defined by 
-// the <buffer> and <size> arguments.
+// This static function computes the checksum for a TCP segment or an UDP packet,
+// defined by the <buffer> and <length> arguments. 
+// It includes the "pseudo header "defined by the <src_ip_addr>, <dst_ip_addr>, and
+// <tcp_length> arguments, and by the UDP/TCP protocol code.
 ////////////////////////////////////////////////////////////////////////////////////////
-// @ buffer      : [in] pointer on UDP packet base.
-// @ size        : [in] number of bytes in this packet (including header).
+// @ buffer      : [in] pointer on buffer containing the TCP segment or UDP packet.
+// @ length      : [in] number of bytes in this packet/segment (including header).
+// @ src_ip_addr : [in] source IP address (pseudo header).
+// @ dst_ip_addr : [in] destination IP address (pseudo header).
+// @ is_tcp      : [in] TCP if true / UDP if false (pseudo header).
 // @ return the checksum value on 16 bits
 ////////////////////////////////////////////////////////////////////////////////////////
-static uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
-                                      uint32_t   size )
-{
-    uint32_t   i;           
-    uint32_t   carry;
-    uint32_t   cs;      // 32 bits accumulator
-    uint16_t * buf;     
-    uint32_t   max;     // number of uint16_t in packet
-    
-    // compute max & buf
-    buf = (uint16_t *)buffer;
-    max = size >> 1;
-
-    // extend buffer[] if required
-    if( size & 1 )
-    {
-        max++;
-        buffer[size] = 0;
-    }
-
-    // compute checksum for UDP packet
-    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
-
-    // handle carry
-    carry = (cs >> 16);
-    if( carry ) 
-    {
-        cs += carry; 
-        carry = (cs >> 16);
-        if( carry ) cs += carry;
-    } 
-
-    // one's complement
-    return ~cs;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
-// This static function computes the checksum for a TCP segment defined by the <buffer> 
-// and <size> arguments. It includes the pseudo header defined by the <src_ip_addr>,
-// <dst_ip_addr>, <size> arguments, and by the TCP_PROTOCOL code.
-////////////////////////////////////////////////////////////////////////////////////////
-// @ buffer      : [in] pointer on TCP segment base.
-// @ tcp_length  : [in] number of bytes in this TCP segment (including header).
-// @ src_ip_addr : [in] source IP address (pseudo header)
-// @ dst_ip_addr : [in] destination IP address (pseudo header)
-// @ return the checksum value on 16 bits
-////////////////////////////////////////////////////////////////////////////////////////
-static uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
-                                      uint32_t   tcp_length,
-                                      uint32_t   src_ip_addr,
-                                      uint32_t   dst_ip_addr )
+static uint16_t dev_nic_tcp_udp_checksum( uint8_t  * buffer,
+                                          uint32_t   length,
+                                          uint32_t   src_ip_addr,
+                                          uint32_t   dst_ip_addr,
+                                          bool_t     is_tcp )
 {
     uint32_t   i;           
@@ -324,25 +343,27 @@
     uint32_t   cs;      // 32 bits accumulator
     uint16_t * buf;
-    uint32_t   max;     // number of uint16_t in segment
+    uint32_t   max;     // number of uint16_t in segment/paket
 
     // compute max & buf
     buf = (uint16_t *)buffer;
-    max = tcp_length >> 1;
+    max = length >> 1;
 
     // extend buffer[] if required
-    if( tcp_length & 1 )
+    if( length & 1 )
     {
         max++;
-        buffer[tcp_length] = 0;
+        buffer[length] = 0;
     }
 
     // compute checksum for TCP segment
-    for( i = 0 , cs = 0 ; i < tcp_length ; i++ )  cs += buf[i];
+    for( i = 0 , cs = 0 ; i < max ; i++ )  cs += buf[i];
 
     // complete checksum for pseudo-header
-    cs += src_ip_addr;
-    cs += dst_ip_addr;
-    cs += PROTOCOL_TCP;
-    cs += tcp_length;
+    cs += (src_ip_addr & 0xFFFF);
+    cs += (src_ip_addr >> 16 );
+    cs += (dst_ip_addr & 0xFFFF);
+    cs += (dst_ip_addr >> 16 );
+    cs += length;
+    cs += (is_tcp ? PROTOCOL_TCP : PROTOCOL_UDP);
 
     // handle carry
@@ -360,10 +381,10 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the NIC_TX or NIC_RX server threads to unblock
+// This static function is called by the NIC_TX and NIC_RX server threads to unblock
 // the TX client thread after completion (success or error) of a TX command registered
-// in a socket identified by the <socket_xp> argument. The <status> argument defines
-// the command success/failure status: a null value signals a success, a non-null value
-// signals a failure. For all commands, it copies the status value in the tx_sts field,
-// and print an error message on TXT0 in case of failure.
+// in a socket identified by the <socket_xp> argument. 
+// The <status> argument defines the command success/failure status.
+// For all commands, it copies the status value in the tx_sts field, and print an error 
+// message on TXT0 in case of failure.
 ///////////////////////////////////////////////////////////////////////////////////////////
 // @ socket_xp  : [in] extended pointer on socket
@@ -377,5 +398,5 @@
     cxy_t      socket_cxy = GET_CXY( socket_xp );
 
-    if( status != CMD_STS_SUCCESS )
+    if( (status != CMD_STS_SUCCESS) && (status != CMD_STS_EOF) )
     {
         uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
@@ -400,11 +421,16 @@
 }  // end dev_nic_unblock_tx_client()
 
-///////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the NIC_TX or NIC_RX server threads to unblock
+
+///////////////////////////////////////////////////////////////////////////////////////////
+//               Functions called by the NIC_RX server thread
+///////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// This static function is called by the NIC_RX server threads to unblock
 // the RX client thread after completion (success or error) of an RX command registered
-// in a socket identified by the <socket_xp> argument. The <status> argument defines
-// the command success/failure status: a null value signals a success, a non-null value
-// signals a failure. For all commands, it copies the status value in the rx_sts field,
-// and print an error message on TXT0 in case of failure.
+// in a socket identified by the <socket_xp> argument.
+// The <status> argument defines the command success/failure status. 
+// For all commands, it copies the status value in the rx_sts field, and print an error 
+// message on TXT0 in case of failure.
 ///////////////////////////////////////////////////////////////////////////////////////////
 // @ socket_xp  : [in] extended pointer on socket
@@ -418,5 +444,5 @@
     cxy_t      socket_cxy = GET_CXY( socket_xp );
 
-    if( status != CMD_STS_SUCCESS )
+    if( (status != CMD_STS_SUCCESS) && (status != CMD_STS_EOF) )
     {
         uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
@@ -440,8 +466,4 @@
 
 }  // end dev_nic_unblock_rx_client()
-
-///////////////////////////////////////////////////////////////////////////////////////////
-//               Functions called by the NIC_RX server thread
-///////////////////////////////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////////////////////
@@ -553,5 +575,6 @@
    
     return 0;
-}
+
+}   // end dev_nic_rx_check_ip()
 
 ///////////////////////////////////////////////////////////////////////////////////////////
@@ -595,6 +618,7 @@
     xptr_t     socket_rbuf_xp;    // extended pointer on socket rx_buf
     xptr_t     socket_lock_xp;    // extended pointer on socket lock
-    xptr_t     socket_client_xp;  // extended pointer on socket rx_client field
-    xptr_t     client_xp;         // extended pointer on client thread descriptor
+    xptr_t     socket_rx_client;  // socket rx_client thread
+    bool_t     socket_rx_valid;   // socket rx_command valid
+    uint32_t   socket_rx_cmd;     // socket rx_command type
     uint32_t   payload;           // number of bytes in payload
     uint32_t   status;            // number of bytes in rx_buf
@@ -602,16 +626,48 @@
     uint32_t   moved_bytes;       // number of bytes actually moved to rx_buf
 
+#if DEBUG_DEV_NIC_RX || DEBUG_DEV_NIC_ERROR
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_DEV_NIC_RX
+uint32_t   fdid;
+uint32_t   pid;
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] thread[%x,%x] enter / channel %d / plen %d / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, chdev->channel, k_length, cycle );
+if( (DEBUG_DEV_NIC_RX < cycle) && (DEBUG_DEV_NIC_RX & 1))
+putb("64 first bytes in k_buf" , k_buf , 64 );
+#endif
+
     // build extended pointers on list of sockets attached to NIC_RX chdev
     root_xp = XPTR( local_cxy , &chdev->wait_root );
     lock_xp = XPTR( local_cxy , &chdev->wait_lock );
 
-    // compute UDP packet checksum 
-    checksum = dev_nic_udp_checksum( k_buf , k_length );
-
-    // get checksum from received packet header 
+    // extract checksum from received UDP packet header 
     pkt_checksum = ((uint16_t)k_buf[6] << 8) | (uint16_t)k_buf[7];
 
+    // reset checksum field
+    k_buf[6] = 0;
+    k_buf[7] = 0; 
+
+    // compute checksum from received UDP packet
+    checksum = dev_nic_tcp_udp_checksum( k_buf,
+                                         k_length,
+                                         pkt_src_addr,
+                                         pkt_dst_addr,
+                                         false );        // is_not_tcp
     // discard corrupted packet  
-    if( pkt_checksum != checksum ) return;
+    if( pkt_checksum != checksum )
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[WARNING] in %s : thread[%x,%x] discard corrupted packet on channel %d / cycle %d\n"
+"   expected checksum %x / received checksum %x\n",
+__FUNCTION__, this->process->pid, this->trdid, chdev->channel, cycle,
+(uint32_t)checksum, (uint32_t)pkt_checksum ); 
+#endif
+        return;
+    }
     
     // get src_port and dst_port from UDP header
@@ -619,7 +675,4 @@
     uint32_t pkt_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
 
-    // discard unexpected packet
-    if( xlist_is_empty( root_xp ) ) return;
- 
     // take the lock protecting the sockets list
     remote_busylock_acquire( lock_xp );
@@ -658,6 +711,17 @@
         else                                  match_socket = local_match;
 
-        // exit loop when socket found
-        if( match_socket ) break;
+        // exit loop if matching
+        if( match_socket ) 
+        {
+
+#if DEBUG_DEV_NIC_RX
+fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
+pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] thread[%x,%x] found matching UDP socket[%d,%d] / state %s\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
+#endif
+            break;
+        }
     }
 
@@ -666,10 +730,17 @@
 
     // discard unexpected packet
-    if( match_socket == false ) return;
-   
-    // build extended pointers on various socket fields
+    if( match_socket == false )
+    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[WARNING] in %s : thread[%x,%s] discard unexpected packet on channel %d / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, chdev->channel, cycle ); 
+#endif
+        return;
+    }
+ 
+    // build extended pointers on socket.rx_buf and socket.lock
     socket_rbuf_xp   = XPTR( socket_cxy , &socket_ptr->rx_buf );
     socket_lock_xp   = XPTR( socket_cxy , &socket_ptr->lock ); 
-    socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client );
 
     // take the lock protecting the socket 
@@ -678,8 +749,10 @@
     // get status & space from rx_buf
     status = remote_buf_status( socket_rbuf_xp );
-    space  = CONFIG_SOCK_RX_BUF_SIZE - status;
-
-    // get client thread 
-    client_xp  = hal_remote_l64( socket_client_xp );
+    space  = (1 << CONFIG_SOCK_RX_BUF_ORDER) - status;
+
+    // get socket rx_client, rx_valid and rx_cmd values
+    socket_rx_client = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->rx_client ) );
+    socket_rx_valid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->rx_valid ) );
+    socket_rx_cmd    = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->rx_cmd ) );
 
     // get number of bytes in payload
@@ -691,10 +764,40 @@
     // move payload from kernel buffer to socket rx_buf
     remote_buf_put_from_kernel( socket_rbuf_xp,
-                                 k_buf + UDP_HEAD_LEN,
-                                 moved_bytes );
-    // unblock client thread 
-    if( client_xp != XPTR_NULL )
-    {
-        thread_unblock( client_xp , THREAD_BLOCKED_IO );
+                                k_buf + UDP_HEAD_LEN,
+                                moved_bytes );
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] thread[%x,%x] for socket[%d,%d] move %d bytes to rx_buf / buf_sts %d\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid, 
+moved_bytes, remote_buf_status(socket_rbuf_xp), moved_bytes );
+#endif
+
+    // signal client thread if pending RECV command
+    if( (socket_rx_valid == true) && (socket_rx_cmd == CMD_RX_RECV) )
+    {
+        // reset rx_valid
+        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->rx_valid), false );
+
+        // report success to RX client thread
+        dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] thread[%x,%x] for UDP socket[%x,%d] / unblock client thread\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
+#endif
+
+    }
+    else
+    {
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] thread[%x,%x] for socket[%x,%d] / no client thread\n"
+"    rx_valid %d / rx_cmd %s\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
+socket_rx_valid , socket_cmd_type_str(socket_rx_cmd) );
+#endif
+
     }
 
@@ -707,10 +810,14 @@
 // This static function is called by the dev_nic_rx_server() function to handle one RX
 // TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments.
-// The <seg_remote_addr> and <seg_local_addr> arguments are obtained from the received
-// IP packet header. It the received segment doesn't match any connected socket attached
-// to the selected chdev[k], or any listening socket waiting connection, or if the segment
-// is corrupted, this segment is discarded. 
-// If required by the TCP flags, it registers an R2T request in the socket R2T queue 
-// to implement the TCP handcheck for close and connect.
+// The <seg_remote_addr> and <seg_local_addr> arguments have been extracted from the IP
+// IP header. The local and remote ports are obtained from the TCP header.
+// It the received segment doesn't match any connected socket attached to the selected 
+// <chdev>, or any listening socket waiting connection, or if the segment is corrupted,
+// the segment is discarded. This function implement the TCP error recovery protocol,
+// as specified by the RFC. Depending on both the socket state, and the segment header:
+//  - it register data in the RX buffer,
+//  - it update the socket state and TCB,
+//  - it register acknolegce requests in the R2T queue,
+//  - it register connection requests in the CRQ queue,
 ///////////////////////////////////////////////////////////////////////////////////////////
 // Implementation note:
@@ -724,5 +831,5 @@
 //    the SYN, FIN, ACK and RST flags. It updates the socket state when required, moves 
 //    data to the rx_buf when possible, and return. It takes the lock protecting the socket,
-//    because an connected socket is accessed by both the NIC_TX and NIC_RX server threads.
+//    because a connected socket is accessed by both the NIC_TX and NIC_RX server threads.
 // 4) If no matching connected socket has been found, it scans the list of listening 
 //    sockets to find a matching listening socket. 
@@ -760,7 +867,8 @@
     bool_t     socket_tx_valid;    // TX command valid
     uint32_t   socket_tx_cmd;      // TX command type
-    uint32_t   socket_tx_todo;     // number of TX bytes not sent yet 
     uint32_t   socket_tx_nxt;      // next byte to send in TX stream
     uint32_t   socket_tx_una;      // first unacknowledged byte in TX stream
+    uint32_t   socket_tx_len;      // number of bytes in tx_buf
+    uint32_t   socket_tx_ack;      // number of acknowledged bytes in tx_buf
     bool_t     socket_rx_valid;    // RX command valid
     uint32_t   socket_rx_cmd;      // TX command type
@@ -804,48 +912,51 @@
     uint32_t seg_data_len = k_length - seg_hlen;  // number of bytes in payload
 
-#if DEBUG_DEV_NIC_RX
-thread_t * this = CURRENT_THREAD;
-uint32_t   cycle;
+    uint32_t seg_data_dup;     // number of duplicated bytes in payload
+    uint32_t seg_data_new;     // number of new bytes in payload
+
+#if DEBUG_DEV_NIC_RX || DEBUG_DEV_NIC_ERROR
 uint32_t   fdid;
 pid_t      pid;
-#endif
-
-#if DEBUG_DEV_NIC_RX
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_RX )
+thread_t * this  = CURRENT_THREAD;
+uint32_t   cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
 printk("\n[%s] thread[%x,%x] enters / tcp_length %d / tcp_flags %x / cycle %d\n",
 __FUNCTION__, this->process->pid, this->trdid, k_length, seg_flags , cycle );
 #endif
 
-    // compute and check TCP checksum
+    // reset checksum field
     k_buf[16] = 0;
     k_buf[17] = 0;
-    checksum = dev_nic_tcp_checksum( k_buf,
-                                     k_length,
-                                     seg_remote_addr,
-                                     seg_local_addr );
-
+
+    // compute TCP checksum
+    checksum = dev_nic_tcp_udp_checksum( k_buf,
+                                         k_length,
+                                         seg_remote_addr,
+                                         seg_local_addr,
+                                         true );            // is_tcp
     // discard segment if corrupted 
     if( seg_checksum != checksum )
     {
 
-#if DEBUG_DEV_NIC_RX
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] tcp checksum failure : received %x / computed %x\n",
-__FUNCTION__, this->process->pid, this->trdid, seg_checksum, checksum );
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[WARNING] in %s : thread[%x,%x] / checksum failure on channel %d / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, chdev->channel, cycle );
 #endif
         return;
     }
     
-    // scan list of attached sockets to find a matching TCP socket
-    attached_match = false;
-
     // build extended pointer on xlist of sockets attached to NIC_RX chdev
     root_xp = XPTR( local_cxy , &chdev->wait_root );
     lock_xp = XPTR( local_cxy , &chdev->wait_lock );
 
+    attached_match = false;
+
     // take the lock protecting the list of attached sockets
     remote_busylock_acquire( lock_xp );
 
+    // scan list of attached sockets to find a matching TCP socket
     XLIST_FOREACH( root_xp , iter_xp )
     {
@@ -878,10 +989,13 @@
         {
 
-#if DEBUG_DEV_NIC_RX
-fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
-pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] matching attached socket[%d,%d] / state %s\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
+#if DEBUG_DEV_NIC_RX || DEBUG_DEV_NIC_ERROR
+fdid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
+pid   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
+#endif
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] matching attached TCP socket[%d,%d] / state %s\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
             break;
@@ -912,7 +1026,8 @@
         socket_tx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_valid ));
         socket_tx_cmd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_cmd ));
-        socket_tx_todo  = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_todo ));
         socket_tx_nxt   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt )); 
         socket_tx_una   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una ));
+        socket_tx_ack   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_ack ));
+        socket_tx_len   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_len ));
 
         socket_rx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_valid ));
@@ -926,47 +1041,55 @@
         {
             ////////////////////////
-            case TCP_STATE_SYN_SENT:  // TCP client waiting for SYN-ACK in connect handshake
+            case TCP_STATE_SYN_SENT:  // TCP client waiting for SYN-ACK 
             {
-                // [1] check ACK flag 
+                // [1] & [2] check ACK and RST
                 if( seg_ack_set )
                 {
-                    if( seg_ack_num != TCP_ISS_CLIENT + 1 )  // bad ACK => report error
+                    bool_t ack_ok = (seg_ack_num == (CONFIG_SOCK_ISS_CLIENT + 1) );
+
+                    if( seg_rst_set && ack_ok )
                     {
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state), TCP_ISS_CLIENT + 1, seg_ack_num );
-#endif
-                        // make an RST request to R2T queue
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s]  socket[%x,%d] %s RST received from remote TCP => close\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        // report RST to local TCP client thread
+                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
+
+                        // update socket state
+                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
+                                          TCP_STATE_BOUND );
+                        break;
+                    }
+
+                    if( seg_rst_set && (ack_ok == false) )
+                    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s RST but expect ack_num %x != rcvd %x => discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state),
+CONFIG_SOCK_ISS_CLIENT + 1, seg_ack_num );
+#endif
+                        break;
+                    }
+
+                    if( (seg_rst_set == false) && (ack_ok == false) )
+                    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s expected ack_num %x != rcvd %x => send RST\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state), 
+CONFIG_SOCK_ISS_CLIENT + 1, seg_ack_num );
+#endif
+                        // send RST to remote TCP
                         socket_put_r2t_request( socket_r2tq_xp,
                                                 TCP_FLAG_RST,
                                                 chdev->channel );
-
-                        // report error to local TX client thread
-                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
-
                         break;
                     }
                 }
 
-                // [2] check RST flag                       // receive RST => report error
-                if( seg_rst_set )
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
-#endif
-                    // update socket state
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
-                                          TCP_STATE_BOUND );
-
-                    // signal error to local TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
-
-                    break;
-                }
-
                 // [3] handle security & precedence TODO ... someday
 
@@ -976,6 +1099,7 @@
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected SYN-ACK\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : received expected SYN-ACK\n",
+__FUNCTION__, pid, fdid , socket_state_str(socket_state) );
 #endif
                     // set socket.tx_una  
@@ -999,21 +1123,24 @@
                     dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
                 }
-                else        // received SYN without ACK => client becomes server
+                else        // SYN without ACK => TCP client becomes a TCP server
                 {
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] for socket[%x,%d] %s : received SYN-ACK => become server\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : received SYN without ACK => send a SYN_ACK\n",
+__FUNCTION__, pid, fdid , socket_state_str(socket_state) );
 #endif
                     // update socket.state
-                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->state), TCP_STATE_SYN_RCVD );
+                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->state),
+                                    TCP_STATE_SYN_RCVD );
 
                     // set socket.tx_nxt 
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
+                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt),
+                                    CONFIG_SOCK_ISS_SERVER );
 
                     // set socket.rx_nxt to seg_seq_num + 1
                     hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_nxt), seg_seq_num + 1 );
 
-                    // make a SYN.ACK request to R2T queue
+                    // send SYN.ACK to remote TCP
                     socket_put_r2t_request( socket_r2tq_xp,
                                             TCP_FLAG_SYN | TCP_FLAG_ACK,
@@ -1021,100 +1148,8 @@
                 }
                 break;
-            }
-            ////////////////////////
-            case TCP_STATE_SYN_RCVD:  // TCP server waiting last ACK in connect handshake 
-            {
-                // [1] check sequence number
-                if( seg_seq_num != socket_rx_nxt )        // unexpected SEQ_NUM => discard
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect seq_num %x / get %x\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state), socket_rx_nxt, seg_seq_num );
-#endif
-                    // discard segment without reporting
-                    break;
-                } 
-
-                // [2] handle RST flag                    // received RST => report error
-                if( seg_rst_set )
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
-#endif
-                    // update socket state
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), TCP_STATE_BOUND );
-
-                    // report error to local TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
-
-                    break;
-                }
-
-                // [3] handle security & precedence TODO ... someday
-
-                // [4] handle SYN flag 
-                if( seg_syn_set )                           // received SYN => discard
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received SYN flag\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
-#endif
-                    // discard segment without reporting
-                    break;
-                } 
-
-                // [5] handle  ACK flag 
-                if( seg_ack_set == false )                      // missing ACK => discard
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK in TCP segment\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
-#endif
-                    // discard segment without reporting
-                    break;
-                }
-                else if( seg_ack_num != (TCP_ISS_SERVER + 1) )  // unacceptable ACK
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, 
-socket_state_str(socket_state), TCP_ISS_SERVER + 1, seg_ack_num );
-#endif
-
-                    // register an RST request to R2TQ for remote TCP client 
-                    socket_put_r2t_request( socket_r2tq_xp,
-                                            TCP_FLAG_RST,
-                                            chdev->channel );
-
-                    // report error to local TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
-                }
-                else                                           // acceptable ACK
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected ACK\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
-#endif
-                    // set socket.tx_una  
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
-
-                    // update socket.state
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), 
-                                    TCP_STATE_ESTAB );
-
-                    // report success to local TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
-                }
-                break;
-            }
-            /////////////////////
+            }  // end state SYN_SENT
+
+            ////////////////////////    all "connected" states
+            case TCP_STATE_SYN_RCVD:
             case TCP_STATE_ESTAB:
             case TCP_STATE_FIN_WAIT1:
@@ -1125,168 +1160,353 @@
             case TCP_STATE_TIME_WAIT:
             {
-                // [1] check sequence number : out_of_order segments not accepted
-                if( seg_seq_num != socket_rx_nxt )
+                // [1] check SEQ_NUM 
+                // - we accept duplicate segments (i.e. seq_num < rx_next)
+                // - we don't accept out of order segment (i.e. seq_num_num > rx_next)
+                //   => seq_num must be in window [rx_nxt - rx_win , rx_nxt]
+
+                bool_t seq_ok =  is_in_window( seg_seq_num,
+                                               (socket_rx_nxt - socket_rx_wnd),
+                                               socket_rx_nxt );
+
+                if( seq_ok == false ) // SEQ_NUM not acceptable
                 {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : illegal SEQ_NUM %x / expected %x\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state), seg_seq_num, socket_rx_nxt );
-#endif
-                    // discard segment
-                    break;
-                } 
-
-                // check all bytes in window when the payload exist
-                // TODO : we could accept bytes that are in window, 
-                // but this implementation reject all bytes in segment 
-                if( seg_data_len > 0 )
-                {
-                    // compute min & max acceptable sequence numbers
-                    uint32_t seq_min  = socket_rx_nxt;
-                    uint32_t seq_max  = socket_rx_nxt + socket_rx_wnd - 1;
-
-                    // compute sequence number for last byte in segment 
-                    uint32_t seg_seq_last = seg_seq_num + seg_data_len - 1;
-                      
-                    if( is_in_window( seg_seq_last, seq_min, seq_max ) == false ) 
+                    if( seg_rst_set )
                     {
 
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : last SEQ_NUM %x not in [%x,%x]\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state), seg_seq_last, seq_min, seq_max );
-#endif
-                        // discard segment
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s expect seq_num %x != rcvd %x and RST => discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state),
+CONFIG_SOCK_ISS_CLIENT + 1, seg_seq_num );
+#endif
                         break;
                     }
-                } 
-
-                // [2] handle RST flag
-                if( seg_rst_set )
+                    else  // no RST
+                    {
+                        // send ACK to remote TCP
+                        socket_put_r2t_request( socket_r2tq_xp,
+                                                TCP_FLAG_ACK,
+                                                chdev->channel );
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s expect seq_num %x != rcvd %x => ACK and discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state),
+CONFIG_SOCK_ISS_CLIENT + 1, seg_seq_num );
+#endif
+                        break;
+                    }
+                }
+                else                   // SEQ_NUM acceptable
                 {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
-#endif
-                    if( (socket_state == TCP_STATE_ESTAB     ) ||
-                        (socket_state == TCP_STATE_FIN_WAIT1 ) ||
-                        (socket_state == TCP_STATE_FIN_WAIT2 ) ||
-                        (socket_state == TCP_STATE_CLOSE_WAIT) )
+                    // compute number of new bytes & number of duplicated bytes
+                    if( seg_seq_num != socket_rx_nxt )  // duplicate segment
                     {
-                        // TODO all pending send & received commands 
-                        // must receive "reset" responses
-
-                        // TODO destroy the socket
+                        seg_data_dup = socket_rx_nxt - seg_seq_num; 
+                        seg_data_new = (seg_data_len > seg_data_dup) ?
+                                       (seg_data_len - seg_data_dup) : 0;
+                    }
+                    else                                // expected segment
+                    {
+                        seg_data_dup = 0;
+                        seg_data_new = seg_data_len;
+                    }
+                    
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s seq_num %x / rx_nxt %x / len %d / new %d / dup %d\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state), 
+seg_seq_num, socket_rx_nxt, seg_data_len, seg_data_new, seg_data_dup );
+#endif
+                }
+
+                // [2] handle RST flag (depending on socket state)
+                if( seg_rst_set  ) 
+                {
+                    if( socket_state == TCP_STATE_SYN_RCVD )
+                    {
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s RST received from remote TCP => report to user\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        // report RST to local TX client thread
+                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
+
+                        // update socket state
+                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
+                                        TCP_STATE_BOUND );
+                        break;
+                    }
+
+                    else if( (socket_state == TCP_STATE_ESTAB     ) ||
+                             (socket_state == TCP_STATE_FIN_WAIT1 ) ||
+                             (socket_state == TCP_STATE_FIN_WAIT2 ) ||
+                             (socket_state == TCP_STATE_CLOSE_WAIT) )
+                    {
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s / received RST flag\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        // report RST to local TX client thread
+                        if( socket_tx_valid ) dev_nic_unblock_tx_client( socket_xp, 
+                                                                         CMD_STS_RST );
+                        // report RST to local RX client thread
+                        if( socket_rx_valid ) dev_nic_unblock_rx_client( socket_xp, 
+                                                                         CMD_STS_RST );
+                        // update socket state
+                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
+                                        TCP_STATE_BOUND );
+                        break;
                     }
                     else  // states CLOSING / LAST_ACK / TIME_WAIT
                     {
-                        // TODO          
+                        // update socket state
+                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
+                                        TCP_STATE_BOUND );
+                        break;
                     }
+                }
+ 
+                // [3] handle security & precedence TODO ... someday
+
+                // [4] check SYN  
+                if( seg_syn_set )           // received SYN => send RST to remote
+                {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s socket[%x,%d] %s : received SYN flag => send RST-ACK\n",
+__FUNCTION__, pid, fdid , socket_state_str(socket_state) );
+#endif
+                    // send RST & ACK to remote TCP 
+                    socket_put_r2t_request( socket_r2tq_xp,
+                                            TCP_FLAG_RST | TCP_FLAG_ACK,
+                                            chdev->channel );
+
+                    // report RST to local TX client thread
+                    if( socket_tx_valid ) dev_nic_unblock_tx_client( socket_xp, 
+                                                                     CMD_STS_RST );
+                    // report RST to local RX client thread
+                    if( socket_rx_valid ) dev_nic_unblock_rx_client( socket_xp, 
+                                                                     CMD_STS_RST );
+                    // update socket state
+                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), 
+                                    TCP_STATE_BOUND );
                     break;
                 }
 
-                // [3] handle security & precedence TODO ... someday
-
-                // [4] check SYN flag 
-                if( seg_syn_set )                                // received SYN => ERROR
+                // [5] handle ACK (depending on socket state)
+                if( seg_ack_set == false )           // missing ACK => discard segment
                 {
 
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received unexpected SYN\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
-#endif
-                    // TODO signal error to user
-
-                    // make an RST request to R2T queue 
-                    socket_put_r2t_request( socket_r2tq_xp, 
-                                            TCP_FLAG_RST,
-                                            chdev->channel );
-
-                    // update socket state
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_BOUND );
-
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s / no ACK in segment => discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
                     break;
                 }
 
-                // [5] check ACK  
-                if( seg_ack_set == false )                           // missing ACK
+                // compute acceptable ACK
+                bool_t ack_ok = is_in_window( seg_ack_num,
+                                              socket_tx_una,
+                                              socket_tx_nxt );
+
+                if( socket_state == TCP_STATE_SYN_RCVD )
                 {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK flag\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
-#endif
-                    // discard segment
-                    break;
-                }
-                else if( is_in_window( seg_ack_num,
-                                       socket_tx_una,
-                                       socket_tx_nxt ) == false )    // unacceptable ACK
-                {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : ACK_NUM %x not in [%x,%x]\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state),
-seg_ack_num, socket_tx_una, socket_tx_nxt );
-#endif
-                    // discard segment
-                    break;
-                }
-                else                                                // acceptable ack
-                {
-                    // update socket.tx_una
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
-
-                    // update socket.tx_wnd  
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_wnd), seg_window );
-
-                    // check last data byte acknowledged for a SEND command
-                    if( (socket_tx_todo == 0) && 
-                        (seg_ack_num == socket_tx_nxt) &&
-                        (socket_tx_cmd == CMD_TX_SEND) )
+                    if( ack_ok )                      //  acceptable ACK
                     {
-                        // signal success to TX client thread
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : received expected ACK => update socket\n",
+__FUNCTION__, pid, fdid , socket_state_str(socket_state) );
+#endif
+                        // set socket.tx_una  
+                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
+
+                        // update socket.state
+                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), 
+                                        TCP_STATE_ESTAB );
+
+                        // report success to local TX client thread
                         dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
                     }
+                    else                               // send RST to remote
+                    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s / ACK %x not in [%x,%x] => discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state),
+seg_ack_num, socket_tx_una, socket_tx_nxt );
+#endif
+                        // send RST & ACK to remote TCP 
+                        socket_put_r2t_request( socket_r2tq_xp,
+                                                TCP_FLAG_RST | TCP_FLAG_ACK,
+                                                chdev->channel );
+                        break;
+                    }
                 }
-                    
-                // [7] handle URG flag  TODO ... someday
-
-                // [8] Move DATA to rx_buf / ACK request to R2T queue / unblock rx_client
-                if( seg_data_len )
+
+                else if( (socket_state == TCP_STATE_ESTAB)      ||
+                         (socket_state == TCP_STATE_FIN_WAIT1)  ||
+                         (socket_state == TCP_STATE_FIN_WAIT2)  ||
+                         (socket_state == TCP_STATE_FIN_WAIT2)  ||
+                         (socket_state == TCP_STATE_CLOSE_WAIT) ||
+                         (socket_state == TCP_STATE_CLOSING)    )
                 {
-                    if( (socket_state == TCP_STATE_ESTAB)     ||
-                        (socket_state == TCP_STATE_FIN_WAIT1) ||
-                        (socket_state == TCP_STATE_FIN_WAIT2) )
+                    if( ack_ok )                      // acceptable ack
+                    {
+                        // compute number of acknowledged bytes 
+                        uint32_t ack_bytes =  seg_ack_num - socket_tx_una;
+
+                        if( ack_bytes )  // handle acknowledged bytes
+                        { 
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %d bytes acknowledged => update socket\n",
+__FUNCTION__, pid, fdid, ack_bytes );
+#endif
+                            // update socket.tx_una, socket.tx_ack, and socket.tx_wnd fields
+                            hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una),
+                                            seg_ack_num );
+                            hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_ack),
+                                            socket_tx_ack + ack_bytes );
+                            hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_wnd),
+                                            seg_window );
+
+                            //  unblock the TX client thread if last byte acknowledged
+                            if( (socket_tx_ack + ack_bytes) == socket_tx_len )
+                            {
+                                // report success to TX client thread
+                                dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : last ack => unblock TX client thread\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                            }
+                        }
+
+                        if( socket_state == TCP_STATE_FIN_WAIT1 )
+                        {
+                            // update socket state
+                            hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
+                                            TCP_STATE_FIN_WAIT2 );
+                        }
+                        if( socket_state == TCP_STATE_FIN_WAIT2 )
+                        {
+                            // TODO
+                        }
+                        else if( socket_state == TCP_STATE_CLOSING )
+                        {
+                            // update socket state
+                            hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
+                                            TCP_STATE_TIME_WAIT );
+                        }
+                        else if( socket_state == TCP_STATE_CLOSING )
+                        {
+                            // TODO
+                        }
+                    }
+                    else                    // unacceptable ACK => discard segment
+                    {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s / ACK %x not in [%x,%x] => discard\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state),
+seg_ack_num, socket_tx_una, socket_tx_nxt );
+#endif
+                        break;
+                    }
+                }
+    
+                else if( socket_state == TCP_STATE_LAST_ACK )
+                {
+                    // TODO
+                }
+
+                else if( socket_state == TCP_STATE_TIME_WAIT )
+                {
+                    // TODO
+                }
+
+                // [6] handle URG flag  TODO ... someday
+
+                // [7] handle received data : update socket state,
+                // move data to rx_buf, register ACK request to R2T queue,
+                // unblock the RX client thread in case of pending RX_RECV command
+                if((socket_state == TCP_STATE_ESTAB)     ||
+                   (socket_state == TCP_STATE_FIN_WAIT1) ||
+                   (socket_state == TCP_STATE_FIN_WAIT2) )
+                {
+                    // register new bytes if requested 
+                    if( seg_data_new )
                     {
                         // get number of bytes already stored in rx_buf
                         uint32_t status = remote_buf_status( socket_rx_buf_xp );
 
-                        // compute empty space in rx_buf
-                        uint32_t space = CONFIG_SOCK_RX_BUF_SIZE - status;
-
-                        // compute number of bytes to move : min (space , seg_data_len)
-                        uint32_t nbytes = ( space < seg_data_len ) ? space : seg_data_len;
-
-                        // move payload from k_buf to rx_buf
+                        // compute space in rx_buf and actual number of acceptable bytes
+                        // when (space < seg_data_new) the last new bytes are discarded
+                        uint32_t space = (1 << CONFIG_SOCK_RX_BUF_ORDER) - status;
+                        uint32_t rcv_bytes = (space < seg_data_new) ? space : seg_data_new;
+
+                        // move new bytes from k_buf to rx_buf
                         remote_buf_put_from_kernel( socket_rx_buf_xp, 
-                                                    k_buf + seg_hlen,
-                                                    nbytes );
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : move %d bytes to rx_buf\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state), nbytes );
-#endif
-                        // update socket.rx_nxt 
+                                                    k_buf + seg_hlen + seg_data_dup,
+                                                    rcv_bytes );
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : move %d bytes to rx_buf\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state), rcv_bytes );
+ #endif
+                        // update socket.rx_nxt and socket_rx_wnd fields
                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
-                                              socket_rx_nxt + nbytes );
-
-                        // update socket.rx_wnd 
+                                        socket_rx_nxt + rcv_bytes );
                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
-                                              socket_rx_wnd - nbytes ); 
-
-                        // make an ACK request to R2T queue 
+                                        socket_rx_wnd - rcv_bytes ); 
+
+                        // unblock RX client if required
+                        if( (socket_rx_valid == true) && (socket_rx_cmd == CMD_RX_RECV) )
+                        {
+                            // reset rx_valid
+                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
+
+                            // report success to RX client thread
+                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : last data => unblock RX client thread\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        }
+                    }
+
+                    // make an ACK request to remote 
+                    socket_put_r2t_request( socket_r2tq_xp,
+                                            TCP_FLAG_ACK,
+                                            chdev->channel );
+                }  // end payload handling
+
+                // [8] handle FIN flag depending on socket state
+                if( (socket_state == TCP_STATE_SYN_RCVD) ||
+                    (socket_state == TCP_STATE_ESTAB )   )
+                {
+                    if( seg_fin_set )      
+                    {
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : FIN-ACK => goes CLOSE_WAIT\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        // update socket.rx_nxt when FIN received
+                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
+                                        socket_rx_nxt + 1 ); 
+
+                        // update socket state
+                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
+                                        TCP_STATE_CLOSE_WAIT );
+
+                        // send ACK to remote TCP
                         socket_put_r2t_request( socket_r2tq_xp,
                                                 TCP_FLAG_ACK,
@@ -1294,58 +1514,15 @@
 
                         // check pending RX_RECV command
-                        if( (socket_rx_valid == true) &&
-                            (socket_rx_cmd == CMD_RX_RECV) )
+                        if( (socket_rx_valid == true) && (socket_rx_cmd == CMD_RX_RECV) )
                         {
                             // reset rx_valid
                             hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
 
-                            // report success to RX client thread
-                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock waiting RX client thread\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
-#endif
-                        }
-                    }
-                }
-
-                // [9] handle FIN flag 
-                if( socket_state == TCP_STATE_ESTAB )
-                {
-                    if( seg_fin_set )  // received ACK & FIN    
-                    {
-
-#if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSE_WAIT\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
-#endif
-                        // update socket.rx_nxt when FIN received
-                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
-                                        socket_rx_nxt + 1 ); 
-
-                        // update socket state
-                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
-                                        TCP_STATE_CLOSE_WAIT );
-
-                        // make an ACK request to R2T queue
-                        socket_put_r2t_request( socket_r2tq_xp,
-                                                TCP_FLAG_ACK,
-                                                chdev->channel );
-
-                        // check pending RX_RECV command
-                        if( (socket_rx_valid == true) &&
-                            (socket_rx_cmd == CMD_RX_RECV) )
-                        {
-                            // reset rx_valid
-                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
-
-                            // report error to RX client thread
+                            // report FIN to RX client thread
                             dev_nic_unblock_rx_client( socket_xp , CMD_STS_EOF );
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock RX client waiting on RECV\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : unblock RX client waiting on RECV\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
                         } 
@@ -1354,13 +1531,13 @@
                 else if( socket_state == TCP_STATE_FIN_WAIT1 )
                 {
-                    if( seg_fin_set )  // received ACK & FIN
+                    if( seg_fin_set ) 
                     { 
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSING\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
-#endif
-                        // update socket.rx_nxt when FIN received
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : FIN-ACK => goes CLOSING\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+                        // update socket.rx_nxt 
                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
                                         socket_rx_nxt + 1 ); 
@@ -1370,5 +1547,5 @@
                                         TCP_STATE_CLOSING );
 
-                        // make an ACK request to R2T queue
+                        // send ACK request to remote
                         socket_put_r2t_request( socket_r2tq_xp,
                                                 TCP_FLAG_ACK,
@@ -1379,7 +1556,7 @@
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : only ACK => goes FIN_WAIT2\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : only ACK => goes FIN_WAIT2\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
                         // update socket state
@@ -1394,7 +1571,7 @@
 
 #if DEBUG_DEV_NIC_RX
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSED / unblock client\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str(socket_state) );
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] socket[%x,%d] %s : FIN-ACK => goes CLOSED / unblock client\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
                         // update socket.rx_nxt when FIN received
@@ -1438,5 +1615,5 @@
                     dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
                 }
-            }  // end case connecteded states
+            }  // end case connected states
         }  // end switch socket state
 
@@ -1491,10 +1668,13 @@
         {
 
-#if DEBUG_DEV_NIC_RX
-fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
-pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] matching listening socket[%d,%d] / state %s\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
+#if DEBUG_DEV_NIC_RX || DEBUG_DEV_NIC_ERROR
+fdid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
+pid   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
+#endif
+
+#if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
+printk("\n[%s] matching listening socket[%d,%d] / state %s\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
             break;
@@ -1509,38 +1689,46 @@
     {
         // The actions depend on the received segment flags
-        // - discard segment for RST or ACK
-        // - update socket state & remote IP address, 
-        //   register connect request in socket CRQ queue,
-        //   and unblock client thread for SYN 
+        // - discard segment for RST or ACK, 
+        // - for SYN, register the connect request in listening socket CRQ queue,
+        //   and  unblock the client thread in case of pending RX_ACCEPT command. 
  
-        // discard segment if RST flag
-        if( seg_rst_set )
+        // [1] check RST
+        if( seg_rst_set )       // discard segment
         {
 
-#if DEBUG_DEV_NIC_RX
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received RST\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s / received RST => discard segment\n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
 #endif
             return;
         }
 
-        // discard segment if ACK flag
-        if( seg_ack_set ) 
+        // [2] check ACK
+        if( seg_ack_set )    // send RST to remote
         {
 
-#if DEBUG_DEV_NIC_RX
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received ACK\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
-#endif
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : socket[%x,%d] %s received ACK => send RST & discard \n",
+__FUNCTION__, pid, fdid, socket_state_str(socket_state) );
+#endif
+            // make an RST request to R2T queue
+            socket_put_r2t_request( socket_r2tq_xp,
+                                    TCP_FLAG_RST,
+                                    chdev->channel );
             return;
         }
 
-        // SYN flag == CONNECT request / seq_num cannot be wrong
+        // [3] handle security & precedence TODO ... someday
+
+        // handle SYN == CONNECT request
         if( seg_syn_set )
         {
-            // build extended pointer on listening socket CRQ
+            // build extended pointers on various listening socket fields
+            socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );
             socket_crqq_xp = XPTR( socket_cxy , &socket_ptr->crqq );
+            socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
+
+            // take the lock protecting the matching socket
+            remote_queuelock_acquire( socket_lock_xp );
 
             // try to register request into CRQ queue
@@ -1550,12 +1738,10 @@
                                             seg_seq_num,
                                             seg_window );
-
             if ( error )   // CRQ full
             {
 
-#if DEBUG_DEV_NIC_RX
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] listening socket[%x,%d] CRQ full => send RST\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : listening socket[%x,%d] %s receive SYN but CRQ full => send RST\n",
+__FUNCTION__, pid, fdid );
 #endif
                 // make an RST request to R2T queue 
@@ -1564,41 +1750,49 @@
                                         chdev->channel );
             }
-            else          // new connection request registered in CRQ
+            else          // register request in listening socket CRQ
             {
 
 #if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
 if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : register request in CRQ\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
-#endif
-                // check pending RX_ACCEPT command
-                if( (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_valid)) == true) &&
-                    (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_cmd)) == CMD_RX_ACCEPT) )
+printk("\n[%s] listening socket[%x,%d] register request in CRQ\n",
+__FUNCTION__, pid, fdid );
+#endif
+                bool_t   rx_valid = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->rx_valid));
+                uint32_t rx_cmd   = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->rx_cmd));
+                
+                // check pending ACCEPT command
+                if( rx_valid && (rx_cmd == CMD_RX_ACCEPT) )
                 {
                     // reset rx_valid
                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_valid ), false );
                      
-                    // report success to RX client thread
+                    // report success to RX client thread, that will
+                    // create a new socket and request a SYN-ACK to TX server thread
                     dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
 
 #if DEBUG_DEV_NIC_RX
+if( DEBUG_DEV_NIC_RX < cycle )
 if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] unblock RX client thread\n", 
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
+printk("\n[%s] listening socket[%x,%d] unblock RX client thread\n", 
+__FUNCTION__, fdid );
 #endif
                 }
             }   // end register request in CRQ
+
+            // release the lock protecting the matching socket
+            remote_queuelock_release( socket_lock_xp );
+
         }   // end if SYN
-        
+
         return;
 
     }  // end if listening_match
 
-    // 6. no socket found => discard segment
-
-#if DEBUG_DEV_NIC_RX
-if( cycle > DEBUG_DEV_NIC_RX )
-printk("\n[%s] thread[%x,%x] exit failure : no socket found => discard segment\n",
-__FUNCTION__, this->process->pid, this->trdid );
+    // 6. no attached socket found and no listening socket found => discard segment
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : thread[%x,%d] / unexpected TCP segment => discard / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, chdev->channel, cycle ); 
 #endif
 
@@ -1618,5 +1812,5 @@
 
     thread_t    * this = CURRENT_THREAD;
-
+    
 // check thread can yield
 thread_assert_can_yield( this , __FUNCTION__ );
@@ -1626,10 +1820,17 @@
 "illegal chdev type or direction" );
 
-#if DEBUG_DEV_NIC_RX
-uint32_t   cycle = (uint32_t)hal_get_cycles();
+#if DEBUG_DEV_NIC_RX || DEBUG_DEV_NIC_ERROR
+uint32_t cycle = (uint32_t)hal_get_cycles();
+#endif
+
+#if DEBUG_DEV_NIC_RX
 if( cycle > DEBUG_DEV_NIC_RX )
 printk("\n[%s] thread[%x,%x] starts / cycle %d\n",
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
+
+    // avoid warning
+    ip_length = 0;
+    error     = 0;
 
     // get extended pointers on server tread and chdev 
@@ -1674,5 +1875,10 @@
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
-
+            // check possible error reported by NIC ISR
+            if( this->nic_cmd.error )  
+            {
+                printk("\n[PANIC] in %s : %s DMA engine cannot access RX_QUEUE / cycle %d\n",
+                __FUNCTION__, chdev->name , (uint32_t)hal_get_cycles() );
+            }
         }
         else                 // success => handle packet
@@ -1682,9 +1888,4 @@
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_DEV_NIC_RX < cycle )
-dev_nic_packet_display( false,               // is_tx
-                        this->process->pid,
-                        this->trdid,
-                        cycle,
-                        k_buf );
 #endif
 
@@ -1697,8 +1898,6 @@
             {
 
-#if DEBUG_DEV_NIC_RX
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_DEV_NIC_RX < cycle )
-printk("\n[%s] thread[%x,%x] discard ETH packet / cycle %d\n", 
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[WARNING] in %s : thread[%x,%x] discard ETH packet / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
@@ -1723,8 +1922,6 @@
             {
 
-#if DEBUG_DEV_NIC_RX
-cycle = (uint32_t)hal_get_cycles();
-if( DEBUG_DEV_NIC_RX < cycle )
-printk("\n[%s] thread[%x,%x] discarded IP packet / cycle %d\n", 
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[WARNING] in %s : thread[%x,%x] discard IP packet / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
@@ -1762,15 +1959,15 @@
             {
  
-#if DEBUG_DEV_NIC_RX
+#if DEBUG_DEV_NIC_ERROR
 cycle = (uint32_t)hal_get_cycles();
 if( DEBUG_DEV_NIC_RX < cycle )
-printk("\n[%s] thread[%x,%x] discarded unsupported transport protocol %d\n", 
+printk("\n[WARNING] in %s : thread[%x,%x] unsupported transport protocol %d / cycle %d\n", 
 __FUNCTION__, this->process->pid, this->trdid, trsp_protocol, cycle );
 #endif
                 continue;
             }
-        }
-    } // end of while loop
-}  // end dev_nic_rx_server()
+        }   // end else success
+    }   // end of while loop
+}   // end dev_nic_rx_server()
 
 
@@ -1782,5 +1979,5 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the dev_nic_tx_build_packet() function.
+// This static function is called by the dev_nic_tx_send_packet() function.
 // It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and 
 // <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument.
@@ -1816,4 +2013,5 @@
     this->nic_cmd.buffer = k_buf;
     this->nic_cmd.length = length;
+    this->nic_cmd.error  = 0;
 
     while( 1 )
@@ -1868,5 +2066,5 @@
 // <socket_xp> argument. The <length> argument defines the number of bytes in payload.
 // It set the "src_port", "dst_port", "total_length" and "checksum" fields in UDP header.
-// The payload must be previouly loaded in the pernel buffer.
+// The payload must be previouly loaded in the kernel buffer.
 ///////////////////////////////////////////////////////////////////////////////////////////
 // @ k_buf      : [in]  pointer on first byte of UDP header in kernel buffer.
@@ -1904,4 +2102,8 @@
     k_buf[3] = remote_port; 
 
+    // reset checksum
+    k_buf[6] = 0;
+    k_buf[7] = 0;
+
     // set packet length in header
     k_buf[4] = total_length >> 8;
@@ -1909,6 +2111,9 @@
     
     // compute UDP packet checksum
-    checksum = dev_nic_udp_checksum( k_buf , total_length );
-
+    checksum = dev_nic_tcp_udp_checksum( k_buf,
+                                         total_length,
+                                         local_addr,
+                                         remote_addr,
+                                         false );       // is_not_tcp
     // set checksum
     k_buf[6] = checksum >> 8;
@@ -1920,5 +2125,5 @@
 // This static function is called by the dev_nic_tx_server() function. 
 // It builds a TCP header in the kernel buffer defined by the <k_buf> argument.
-// The payload must have been previouly registered in this buffer.
+// The payload must have been previouly registered in this buffer (for checksum).
 // The "local_addr", "local_port", "remote_addr", "remote_port", seq_num", "ack_num",
 // and "window" fields are obtained from the <socket_xp> argument.
@@ -1999,8 +2204,9 @@
   
     // compute TCP segment checksum
-    checksum = dev_nic_tcp_checksum( k_buf,
-                                     total_length,
-                                     src_addr,
-                                     dst_addr );
+    checksum = dev_nic_tcp_udp_checksum( k_buf,
+                                         total_length,
+                                         src_addr,
+                                         dst_addr,
+                                         true );       // is_tcp
     // set "checksum"
     k_buf[16] = checksum >> 8;
@@ -2108,53 +2314,44 @@
 }  // end dev_nic_tx_build_eth_header()
 
-///////////////////////////////////////////////////////////////////////////////////////////
-// This static function is called by the dev_nic_tx_server() function to handle one TX 
-// command, or one R2T request, as defined by the <cmd_valid> and <r2t_valid> arguments,
-// for the socket identified by the <socket_xp> argument. It builds an ETH/IP/UDP packet 
-// or ETH/IP/TCP segment, in the buffer defined by the <k_buf> argument, and registers
-// it in the NIC_TX queue defined by the <chdev> argument. 
-// For a TCP header, the "seq_num", ack_num", and "window" fiels are defined by the
-// "socket.tx_next", "socket.rx_next" and "socket.rx_wnd" fields respectively. 
-// It updates the "socket.state", "socket.tx_nxt", "socket.r2tq", and "socket.crqq" 
-// The supported TX command types are CONNECT / ACCEPT / SEND / CLOSE.
-// fields as required by the command type.
-// - For an UDP socket, it reset the "socket.tx_valid" field, and unblock the client
-//   thread when the packet has been sent, or when an error must be reported.
-// - For a TCP socket, it reset the "socket.tx_valid" field when the segment has been
-//   sent, but does not unblocks the client thread, that will be unblocqued by the 
-//   NIC_RX thread when the TX command is fully completed.
+
+///////////////////////////////////////////////////////////////////////////////////////////
+// This static function implement the TCP protocol as specified by the RFC.
+// It is called by the dev_nic_tx_server() function to handle one TX command, 
+// or one R2T request, for the socket identified by the <socket_xp> argument. 
+// It builds an ETH/IP/UDP packet or ETH/IP/TCP segment, in the 2 Kbytes kernel buffer,
+// defined by the <k_buf> argument from informations found in socket descriptor.
+// It returns a command status code (defined in the ksocket.h file), and returns in the
+// <total_length> argument the actual packet length.
+// It updates the "socket.state", "socket.tx_nxt", "socket.r2tq", "socket.crqq",
+// "socket.todo" fields as required by the command type, but it does NOT reset 
+// the "socket.tx_valid" field and does NOT unblock the client thread.
+// It does NOt take the socket lock, that is taken by the dev_nic_server().
 ///////////////////////////////////////////////////////////////////////////////////////////
 // To build a packet, it makes the following actions:
-// 1) it takes the lock protecting the socket state.
-// 2) it get the command arguments from socket descriptor.
-// 3) it build an UDP packet or a TCP segment, depending on command type and socket state. 
-// 4) it updates the socket state.
-// 5) it releases the lock protecting the socket.
-// 6) it build the IP header.
-// 7) it build the ETH header.
-// 8) it copies the packet in the NIC_TX queue.
-///////////////////////////////////////////////////////////////////////////////////////////
-// @ cmd_state   : [in] TX command valid in socket descriptor.
-// @ r2t_valid   : [in] R2T request valid in command descriptor. 
-// @ socket_xp   : [in] extended pointer on client socket.  
-// @ k_buf       : [in] local pointer on kernel buffer (2 Kbytes).
-// @ chdev       : [in] local pointer on NIC_RX chdev.
-///////////////////////////////////////////////////////////////////////////////////////////
-static void dev_nic_tx_build_packet( bool_t    cmd_valid,
-                                     bool_t    r2t_valid,
-                                     xptr_t    socket_xp,
-                                     uint8_t * k_buf,
-                                     chdev_t * chdev )
+// 1) it get the command arguments from socket descriptor.
+// 2) it build an UDP packet or a TCP segment, and update socket state. 
+// 3) it build the IP header.
+// 4) it build the ETH header.
+///////////////////////////////////////////////////////////////////////////////////////////
+// @ socket_xp    : [in]  extended pointer on client socket.  
+// @ k_buf        : [in]  local pointer on kernel buffer (2 Kbytes).
+// @ total_length : [out] total number of bytes written in k_buf.
+// @ return command status.
+///////////////////////////////////////////////////////////////////////////////////////////
+static socket_cmd_sts_t dev_nic_tx_build_packet( xptr_t     socket_xp,
+                                                 uint8_t  * k_buf,
+                                                 uint32_t * total_length )
 {
     socket_t  * socket_ptr;
     cxy_t       socket_cxy;
     xptr_t      client_xp;       // extended pointer on client thread  
+    bool_t      cmd_valid;       // valid user command
+    bool_t      r2t_valid;       // valid R2T queue request
     uint32_t    cmd_type;        // NIC command type
-    uint8_t   * tx_buf;          // local pointer on kernel buffer for payload
+    uint8_t   * tx_buf;          // local pointer on socket buffer for payload
     uint32_t    len;             // tx_buf length (bytes)
     uint32_t    todo;            // number of bytes not yet sent
     uint32_t    socket_type;     // socket type (UDP/TCP)
     uint32_t    socket_state;    // socket state        
-    xptr_t      socket_lock_xp;  // extended pointer on socket lock
     xptr_t      socket_r2tq_xp;  // extended pointer on R2T queue
     uint32_t    src_ip_addr;     // source IP address
@@ -2166,28 +2363,29 @@
     uint8_t     trsp_protocol;   // transport protocol type (UDP/TCP)
     uint8_t     r2t_flags;       // flags defined by one R2T queue request
-    bool_t      do_send;         // build & send a packet when true
-  
+ 
     // get socket cluster and local pointer
     socket_cxy = GET_CXY( socket_xp );
     socket_ptr = GET_PTR( socket_xp );
 
+#if DEBUG_DEV_NIC_TX  || DEBUG_DEV_NIC_ERROR
+uint32_t   cycle       = (uint32_t)hal_get_cycles();
+uint32_t   socket_fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
+uint32_t   socket_pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
+#endif
+
+    // build extended pointer on socket r2t queue 
+    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
+
+    // get cmd_valid & t2t_valid from socket descriptor
+    cmd_valid = (bool_t)hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_valid ));
+    r2t_valid = (bool_t)remote_buf_status( XPTR( socket_cxy , &socket_ptr->r2tq ));
+
 #if DEBUG_DEV_NIC_TX 
-thread_t * this = CURRENT_THREAD;;
-uint32_t   cycle = (uint32_t)hal_get_cycles();
-uint32_t   fdid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
-uint32_t   pid   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] : cmd_valid %d / r2t_valid %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
-#endif
-
-    // build extended pointers on socket lock and r2t queue
-    socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );    
-    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
-
-    // 1. take lock protecting this socket
-    remote_queuelock_acquire( socket_lock_xp );
-
-    // get relevant socket infos
+printk("\n[%s] enter for socket[%x,%d] : cmd_val %d / r2t_val %d / cycle %d\n",
+__FUNCTION__, socket_pid, socket_fdid, cmd_valid, r2t_valid, cycle );
+#endif
+
+    // 1. get relevant socket infos
     socket_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->type ));
     socket_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
@@ -2195,15 +2393,13 @@
     dst_ip_addr  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->remote_addr ));
 
-    // compute UDP/TCP packet base in kernel buffer
+    // compute UDP/TCP packet base in local kernel buffer
     k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
 
-    // set default values
-    do_send     = false;
+    // default value
     trsp_length = 0;
-    nbytes      = 0;
-
-    if( cmd_valid )  // handle TX command 
-    {
-        // 2. get command arguments from socket
+
+    if( cmd_valid )  // handle TX command depending on type 
+    {
+        // get command arguments from socket
         cmd_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
         tx_buf    = hal_remote_lpt( XPTR( socket_cxy , &socket_ptr->tx_buf ));
@@ -2213,13 +2409,12 @@
         
 #if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] cmd_valid for socket[%x,%d] : %s / %s / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_cmd_type_str(cmd_type), socket_state_str(socket_state), cycle );
+printk("\n[%s] socket[%x,%d] / %s / command %s \n",
+__FUNCTION__, socket_pid, socket_fdid, 
+socket_cmd_type_str(cmd_type),socket_state_str(socket_state) );
 #endif
 
         //////////////////////////////////////////////////////////
-        // 3. UDP : build UDP packet and update UDP socket state
+        // 2. UDP : build UDP packet and update UDP socket state
         if( socket_type == SOCK_DGRAM )        
         {
@@ -2228,62 +2423,46 @@
             if( socket_state != UDP_STATE_ESTAB )
             {
-                // reset tx_valid
-                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
-
-                // unblock client thread / report error
-                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
+                return  CMD_STS_BADSTATE;
             }
-            else
+            else if( cmd_type == CMD_TX_SEND ) 
             {
-                if( cmd_type == CMD_TX_SEND ) 
-                {
-                    // compute payload length
-                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
-
-                    // move payload from tx_buf to 2 Kbytes kernel buffer
-                    memcpy( k_trsp_base + UDP_HEAD_LEN,
-                            tx_buf + (len - todo),
-                            nbytes );
-
-                    // build UDP header 
-                    dev_nic_tx_build_udp_header( k_trsp_base,
-                                                 socket_xp,
-                                                 nbytes );
-
-                    // update "tx_todo" in socket descriptor 
-                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
-
-                    // send UDP packet 
-                    trsp_length = UDP_HEAD_LEN + nbytes;
-                    do_send     = true;
-
-#if( DEBUG_DEV_NIC_TX & 1)
-cycle = (uint32_t)hal_get_cycles();
+                // compute payload length
+                nbytes = ( CONFIG_SOCK_PAYLOAD_MAX < todo ) ? CONFIG_SOCK_PAYLOAD_MAX : todo;
+
+                // move payload from remote socket tx_buf to local kernel buffer
+                hal_remote_memcpy( XPTR( local_cxy  , k_trsp_base + UDP_HEAD_LEN ),
+                                   XPTR( socket_cxy , tx_buf + (len - todo) ),
+                                   nbytes );
+
+                // build UDP header 
+                dev_nic_tx_build_udp_header( k_trsp_base,
+                                             socket_xp,
+                                             nbytes );
+
+                // update "tx_todo" in socket descriptor 
+                hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
+
+                // set UDP packet length
+                trsp_length = UDP_HEAD_LEN + nbytes;
+
+#if DEBUG_DEV_NIC_TX 
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] UDP packet build / length %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, trsp_length , cycle );
-#endif
-                    if( nbytes == todo )    // last byte sent
-                    {
-                        // reset tx_valid
-                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
-
-                        // report success to TX client
-                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
-                    }
-                }
-                else // CONNECT, ACCEPT, or CLOSE commands are illegal for UDP
-                {
-                    // reset tx_valid
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
-
-                    // report error
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
-                }
+printk("\n[%s] socket[%x,%d] UDP packet build / %d bytes\n",
+__FUNCTION__, socket_pid, socket_fdid, nbytes );
+#endif
+            }
+            else // CONNECT, ACCEPT, or CLOSE commands are illegal for UDP
+            {
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : bad state %s for socket[%x,%x] / cycle %d\n",
+__FUNCTION__, socket_state_str(socket_state), socket_pid, socket_fdid, cycle );
+#endif
+                return  CMD_STS_BADCMD;
             }
         }  // end UDP
 
         ///////////////////////////////////////////////////////////
-        // 3. TCP : build TCP segment and update TCP socket state
+        // 2. TCP : build TCP segment and update TCP socket state
         else if( socket_type == SOCK_STREAM ) 
         {
@@ -2296,6 +2475,6 @@
                 socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
         
-                // get one request from R2T queue 
-                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
+                // get one request from R2T queue, and update R2T queue
+                socket_get_r2t_request( socket_r2tq_xp , &r2t_flags );
             }
             else
@@ -2311,6 +2490,8 @@
                 {
                     // initialises socket tx_nxt, and rx_wnd
-                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_CLIENT );
-                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), TCP_MAX_WINDOW );
+                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), 
+                                   CONFIG_SOCK_ISS_CLIENT );
+                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd),
+                                   CONFIG_SOCK_MAX_WINDOW );
 
                     // build TCP SYN segment
@@ -2319,16 +2500,7 @@
                                                  0,        // length
                                                  TCP_FLAG_SYN );   
-                    // send segment
+                    // set TCP packet length
                     trsp_length = TCP_HEAD_LEN;
-                    do_send     = true;
-
-#if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CONNECT / "
-"TCP SYN build / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str( socket_state ), cycle );
-#endif
+
                     // update socket.state 
                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
@@ -2337,16 +2509,19 @@
                     // update socket.tx_nxt
                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
-                                          TCP_ISS_CLIENT + 1 );
-
-                    // reset tx_valid but do not unblock client thread
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
+                                          CONFIG_SOCK_ISS_CLIENT + 1 );
+#if DEBUG_DEV_NIC_TX 
+if( cycle > DEBUG_DEV_NIC_TX )
+printk("\n[%s] socket[%x,%d] %s / CONNECT / TCP SYN build\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state) );
+#endif
                 } 
                 else                      // report error for all other socket states
                 {
-                    // reset tx_valid
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
-                   
-                    // report error
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE ); 
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : bad state %s socket[%x,%x] / cycle %d\n",
+__FUNCTION__, socket_state_str(socket_state), socket_pid, socket_fdid, cycle );
+#endif
+                    return CMD_STS_BADSTATE; 
                 }
             }
@@ -2358,6 +2533,8 @@
                 {
                     // initialize socket tx_nxt, and rx_wnd
-                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
-                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), CONFIG_SOCK_RX_BUF_SIZE);
+                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt),
+                                        CONFIG_SOCK_ISS_SERVER );
+                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd),
+                                        (1 << CONFIG_SOCK_RX_BUF_ORDER) );
                 
                     // build TCP ACK-SYN segment
@@ -2366,15 +2543,7 @@
                                                  0,         //  length
                                                  TCP_FLAG_SYN | TCP_FLAG_ACK );
-                    // send segment
+                    // set TCP packet length
                     trsp_length = TCP_HEAD_LEN;
-                    do_send     = true;
-
-#if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / ACCEPT / send SYN-ACK / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str( socket_state ), cycle );
-#endif
+
                     // update socket.state 
                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
@@ -2383,16 +2552,19 @@
                     // update socket.tx_nxt
                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
-                                          TCP_ISS_SERVER + 1 );
-
-                    // reset tx_valid but do not unblock client thread
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
+                                          CONFIG_SOCK_ISS_SERVER + 1 );
+#if DEBUG_DEV_NIC_TX 
+if( cycle > DEBUG_DEV_NIC_TX )
+printk("\n[%s] socket[%x,%d] %s / ACCEPT / SYN-ACK build\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state) );
+#endif
                 }
                 else                     // report error in all other socket states
                 {
-                    // reset tx_valid
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
-
-                    // report error to TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : bad state %s for socket[%x,%x] / cycle %d\n",
+__FUNCTION__, socket_state_str(socket_state), socket_pid, socket_fdid, cycle );
+#endif
+                    return CMD_STS_BADSTATE; 
                 }
             }
@@ -2423,36 +2595,24 @@
                     hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + 1 );
 
-                    // send segment
+                    // set TCP packet length
                     trsp_length = TCP_HEAD_LEN;
-                    do_send     = true;
 
 #if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / send FIN-ACK / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str( socket_state ), cycle );
-#endif
-                    // reset tx_valid but do not unblock client thread
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
+printk("\n[%s] socket[%x,%d] %s / CLOSE / FIN-ACK build\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state) );
+#endif
                 }
                 else                                 // all other states => signal error
                 {
 
-#if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / error BADSTATE / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str( socket_state ), cycle );
-#endif
-                    // reset tx_valid
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
-
-                    // report error 
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : bad state %s for socket[%x,%x] / cycle %d\n",
+__FUNCTION__, socket_state_str(socket_state),  socket_pid, socket_fdid, cycle );
+#endif
+                    return CMD_STS_BADSTATE; 
                 }
             }
-            /////////////////////////////////////
+            //////////////////////////////////
             else if( cmd_type == CMD_TX_SEND )
             {
@@ -2464,13 +2624,11 @@
 
                     // compute actual payload length
-                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
-
-                    // compute TCP segment base in kernel buffer
-                    k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
-
-                    // move payload to k_buf
-                    memcpy( k_trsp_base + TCP_HEAD_LEN,
-                            tx_buf + (len - todo),
-                            nbytes );
+                    nbytes = ( CONFIG_SOCK_PAYLOAD_MAX < todo ) ? 
+                             CONFIG_SOCK_PAYLOAD_MAX : todo;
+
+                    // move payload from remote tx_buf to local kernel buffer
+                    hal_remote_memcpy( XPTR( local_cxy  , k_trsp_base + TCP_HEAD_LEN ),
+                                       XPTR( socket_cxy , tx_buf + (len - todo) ),
+                                       nbytes );
 
                     // build TCP header 
@@ -2486,30 +2644,21 @@
                     hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + nbytes );
 
-                    // send TCP segment
+                    // set TCP packet length
                     trsp_length = TCP_HEAD_LEN + nbytes;
-                    do_send     = true;
-
-                    if( todo == nbytes )   // last byte sent 
-                    {
-                        // reset tx_valid when last byte has been sent
-                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_valid), false );
-                    }
 
 #if DEBUG_DEV_NIC_TX 
-cycle = (uint32_t)hal_get_cycles();
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / SEND / "
-"TCP DATA build / payload %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
-socket_state_str( socket_state ), nbytes, cycle );
+printk("\n[%s] socket[%x,%d] %s / SEND / %d bytes\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state), nbytes );
 #endif
                 }
                 else  // all other socket states
                 {
-                    // reset tx_valid
-                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
-
-                    // report error to TX client thread
-                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : bad state %s for socket[%x,%x] / cycle %d\n",
+__FUNCTION__, socket_state_str(socket_state), socket_pid, socket_fdid, cycle );
+#endif
+                    return CMD_STS_BADSTATE; 
                 }
             }
@@ -2517,9 +2666,10 @@
             else  // undefined TX command type
             {
-                // reset tx_valid
-                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
-
-                // report error to TX client thread
-                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
+
+#if DEBUG_DEV_NIC_ERROR
+printk("\n[ERROR] in %s : undefined command type for socket[%x,%x] %s / cycle %d\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state), cycle );
+#endif
+                return CMD_STS_BADCMD; 
             }
         }  // end TCP 
@@ -2527,32 +2677,29 @@
     else         // no valid TX command => handle R2T request only
     {
+
+assert( __FUNCTION__ , (socket_type == SOCK_STREAM) , "don't use R2T queue for UDP" );
+ 
         // get one request from R2T queue 
-        remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
+        socket_get_r2t_request( socket_r2tq_xp , &r2t_flags );
 
 #if DEBUG_DEV_NIC_TX 
 cycle = (uint32_t)hal_get_cycles();
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] only r2t_valid for socket[%x,%d] / flags %x / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, r2t_flags, cycle );
-#endif
-
+printk("\n[%s] socket[%x,%d] %s / send only flags %x / no data\n",
+__FUNCTION__, socket_pid, socket_fdid, socket_state_str(socket_state), r2t_flags );
+#endif
         // build TCP header 
         dev_nic_tx_build_tcp_header( k_trsp_base,
                                      socket_xp,
-                                     0,             // payload length
+                                     0,             // no payload
                                      r2t_flags );   // flags
-        // send TCP segment
+        // set protocol
         trsp_protocol = PROTOCOL_TCP;
+
+        // set TCP packet length
         trsp_length   = TCP_HEAD_LEN;
-        do_send       = true;
     }
 
-    // 4. release the lock protecting the socket
-    remote_queuelock_release( socket_lock_xp );
-
-    // return if no packet to send
-    if( do_send == false ) return;
-
-    // 5. build IP header
+    // 3. build IP header
     dev_nic_tx_build_ip_header( k_buf + ETH_HEAD_LEN,
                                 src_ip_addr,
@@ -2561,12 +2708,5 @@
                                 trsp_length );
 
-#if( DEBUG_DEV_NIC_TX & 1)
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] IP header build / length %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, IP_HEAD_LEN + trsp_length , cycle );
-#endif
-
-    // 6. build ETH header
+    // 4. build ETH header
     dev_nic_tx_build_eth_header( k_buf,
                                  (uint8_t)DST_MAC_5,
@@ -2584,43 +2724,39 @@
                                  IP_HEAD_LEN + trsp_length );
 
-#if( DEBUG_DEV_NIC_TX & 1)
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] ETH header build / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, cycle );
-#endif
-
-    // 7. move packet to NIC_TX queue (blocking function)
-    dev_nic_tx_move_packet( chdev,
-                            k_buf,
-                            ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
-
 #if DEBUG_DEV_NIC_TX
 cycle = (uint32_t)hal_get_cycles();
 if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] for socket[%x,%d] moved packet to NIC_TX / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cycle );
-#endif
+printk("\n[%s] exit for socket[%x,%d] / packet build / cycle %d\n",
+__FUNCTION__, socket_pid, socket_fdid, cycle );
+#endif
+
+    // return success and total packet length
+    *total_length = ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length;
+    return CMD_STS_SUCCESS;
 
 }  // end dev_nic_tx_build_packet()
-
 
 /////////////////////////////////////////
 void dev_nic_tx_server( chdev_t * chdev )
 {
-    uint8_t       k_buf[CONFIG_SOCK_PKT_BUF_SIZE];  // buffer for one packet
-
-    xptr_t        queue_root_xp;       // extended pointer on sockets list root
-    xptr_t        queue_lock_xp;       // extended pointer on lock protecting this list
-    xptr_t        socket_xp;           // extended pointer on on registered socket 
-    socket_t    * socket_ptr;
-    cxy_t         socket_cxy;
-    xptr_t        iter_xp;             // iterator for loop on registered sockets
-    xlist_entry_t temp_root;           // root of temporary list of sockets
-    xptr_t        temp_root_xp;        // extended pointer on temporary list of sockets
-    uint32_t      temp_nr;             // number of active registered sockets
-    bool_t        cmd_valid;           // TX command valid in socket descriptor
-    bool_t        r2t_valid;           // valid R2T request in socket descriptor
-
+    uint8_t           k_buf[CONFIG_SOCK_PKT_BUF_SIZE];  // buffer for one packet
+
+    xptr_t            queue_lock_xp;       // extended pointer on lock for sockets list
+    xptr_t            root_xp;             // extended pointer on sockets list root
+    xptr_t            iter_xp;             // iterator for loop on sockets list
+    xptr_t            list_xp;             // extended pointer on socket tx_list field
+    xptr_t            socket_xp;           // extended pointer on found socket 
+    socket_t        * socket_ptr;          // local pointer on found socket
+    cxy_t             socket_cxy;          // found socket cluster identifier
+    xptr_t            socket_lock_xp;      // extented pointer on found socket lock
+    bool_t            cmd_valid;           // TX command valid in socket descriptor
+    bool_t            r2t_valid;           // valid R2T request in socket descriptor
+    uint32_t          sock_type;           // socket type
+    socket_cmd_sts_t  cmd_sts;             // value returned by dev_nic_tx_build_packet()
+    socket_cmd_type_t tx_cmd;              // socket TX command type
+    uint32_t          tx_todo;             // socket number of bytes not sent yet
+    uint32_t          total_length;        // length of the ETH/IP/TCP packet (bytes)
+    bool_t            found;               // one active socket found
+    
     thread_t * this = CURRENT_THREAD;
 
@@ -2638,95 +2774,54 @@
 "illegal chdev type or direction" );
 
-// check thread can yield
-thread_assert_can_yield( this , __FUNCTION__ );
-
-    // build extended pointer on temporary list
-    temp_root_xp = XPTR( local_cxy , &temp_root );
-                                                         
-    // build extended pointer on client sockets queue (lock & root) 
+    // build extended pointers on client sockets queue lock 
     queue_lock_xp = XPTR( local_cxy , &chdev->wait_lock );
-    queue_root_xp = XPTR( local_cxy , &chdev->wait_root );
+
+    // build extended pointers on client sockets queue root and first item 
+    root_xp  = XPTR( local_cxy , &chdev->wait_root );
 
     while( 1 )  // TX server infinite loop
     {
-        // initialize temporary list of registered sockets as empty
-        xlist_root_init( temp_root_xp );
-        temp_nr = 0;
-
         // take the lock protecting the client sockets queue
         remote_busylock_acquire( queue_lock_xp );
 
-        // build temporary list of all registered sockets
-        if( xlist_is_empty( queue_root_xp ) == false )  
+        found = false;
+
+        // scan registered sockets to find one active socket
+        // with a round robin priority between the registered sockets
+        if( xlist_is_empty( root_xp ) == false )  
         {
-            XLIST_FOREACH( queue_root_xp , iter_xp )
+            XLIST_FOREACH( root_xp , iter_xp )
             {
-                // get client socket cluster and local pointer
+                // get client socket cluster and pointers
                 socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_list );
                 socket_ptr = GET_PTR( socket_xp );
                 socket_cxy = GET_CXY( socket_xp );
 
-                // register socket in temporary list
-                xlist_add_last( temp_root_xp , XPTR( socket_cxy , &socket_ptr->tx_temp ));
-                temp_nr++;
-            }
+                // build extended pointer on socket tx_list field
+                list_xp = XPTR( socket_cxy , &socket_ptr->tx_list );
+
+                // get cmd_valid & r2t_valid from socket descriptor
+                cmd_valid = (bool_t)hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_valid ));
+
+                // get r2t_valid from socket descriptor
+                r2t_valid = (bool_t)remote_buf_status( XPTR( socket_cxy , &socket_ptr->r2tq ));
+
+                if( cmd_valid || r2t_valid )    // active => move socket, and exit loop
+                {
+                    // move selected socket to last position for round-robin
+                    xlist_unlink( list_xp );
+                    xlist_add_last( root_xp , list_xp );
+
+                    // exit loop
+                    found = true;
+                    break;
+                }
+            }   // end loop on sockets
         }
-
+        
         // release the lock protecting the client sockets queue
         remote_busylock_release( queue_lock_xp );
 
-        if( temp_nr > 0 )
-        {
-            // loop on temporary list
-            XLIST_FOREACH( temp_root_xp , iter_xp )
-            {
-                // get client socket cluster and local pointer
-                socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_temp );
-                socket_ptr = GET_PTR( socket_xp );
-                socket_cxy = GET_CXY( socket_xp );
-
-                // get cmd_valid & t2t_valid from socket descriptor
-                cmd_valid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_valid ));
-
-                // get r2t_valid from socket descriptor
-                r2t_valid = (bool_t)remote_buf_status( XPTR( socket_cxy , &socket_ptr->r2tq ));
-
-                // test if socket is active
-                if( cmd_valid || r2t_valid )  // active socket 
-                {
-
-#if DEBUG_DEV_NIC_TX
-cycle = (uint32_t)hal_get_cycles();
-pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
-fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
-if( cycle > DEBUG_DEV_NIC_TX )
-printk("\n[%s] thread[%x,%x] found socket[%x,%d] / cmd_valid %d / r2t_valid %d / cycle %d\n",
-__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
-#endif
-                    // build and send one packet/segment for this socket
-                    dev_nic_tx_build_packet( cmd_valid,
-                                             r2t_valid,
-                                             socket_xp,
-                                             k_buf,
-                                             chdev );
-#if DEBUG_DEV_NIC_TX
-cycle = (uint32_t)hal_get_cycles();
-if( cycle > DEBUG_DEV_NIC_TX )
-dev_nic_packet_display( true,                // is_tx
-                        this->process->pid,
-                        this->trdid,
-                        cycle,
-                        k_buf );
-#endif
-                }
-                else                          // inactive socket
-                {
-                   temp_nr--;
-                }
-            }  // end loop on temporary list
-        }
-
-        // block & deschedule if no active socket found in current iteration
-        if( temp_nr == 0 )
+        if( found == false ) // block & deschedule if no active socket 
         {
  
@@ -2737,5 +2832,4 @@
 __FUNCTION__, this->process->pid, this->trdid, cycle );
 #endif
-
             // block and deschedule
             thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT );
@@ -2749,12 +2843,90 @@
 #endif
         }
+        else              // handle active socket request
+        {
+            // avoid warning
+            total_length = 0;
+ 
+            // build extended pointer on socket lock
+            socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );
+
+            // take socket lock
+            remote_queuelock_acquire( socket_lock_xp );
+
+#if DEBUG_DEV_NIC_TX
+cycle = (uint32_t)hal_get_cycles();
+pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
+fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
+#endif
+
+#if DEBUG_DEV_NIC_TX
+if( cycle > DEBUG_DEV_NIC_TX )
+printk("\n[%s] thread[%x,%x] select socket[%x,%d] / cmd_val %d / r2t_val %d / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
+#endif
+            // build one UDP packet / TCP segment 
+            cmd_sts = dev_nic_tx_build_packet( socket_xp,
+                                               k_buf,
+                                               &total_length );
+#if DEBUG_DEV_NIC_TX
+cycle = (uint32_t)hal_get_cycles();
+if( cycle > DEBUG_DEV_NIC_TX )
+printk("\n[%s] thread[%x,%x] for socket[%x,%x] build packet / %d bytes / sts %d / cycle %d\n",
+__FUNCTION__, this->process->pid, this->trdid, pid, fdid, total_length, cmd_sts, cycle );
+#endif
+            // release socket lock
+            remote_queuelock_release( socket_lock_xp );
+
+            if( cmd_sts == CMD_STS_SUCCESS )    // move packet to TX queue
+            {
+                // move packet to NIC_TX queue 
+                dev_nic_tx_move_packet( chdev,
+                                        k_buf,
+                                        total_length );
+#if DEBUG_DEV_NIC_TX
+cycle = (uint32_t)hal_get_cycles();
+if( cycle > DEBUG_DEV_NIC_TX )
+dev_nic_packet_display( pid, fdid, cycle, k_buf );
+#endif
+                // get socket.type, socket.tx_cmd and socket.tx_todo values 
+                tx_cmd    = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
+                tx_todo   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_todo ));
+                sock_type = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->type ));
+
+                // client signaling depends on command type and socket type
+                if( (tx_cmd == CMD_TX_SEND) &&  (tx_todo == 0) )
+                {
+                    // reset tx_valid for both UDP and TCP
+                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid), false );
+
+                    // unblock client thread for UDP only
+                    if(sock_type == SOCK_DGRAM)
+                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
+                }
+                else  // type is CONNECT / ACCEPT / CLOSE 
+                {
+                    // reset tx_valid
+                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid), false );
+                }
+            }
+            else                          // signal error to client thread
+            {
+                // reset tx_valid
+                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid), false );
+
+                // unblock tx_client thread
+                dev_nic_unblock_tx_client( socket_xp , cmd_sts );
+            }
+        }   // end active socket handling
     }   // end infinite while loop
 }  // end dev_nic_tx_server()
 
 
-/////////////////////////////////////////////
-void dev_nic_packet_display( bool_t    is_tx,
-                             pid_t     thread_pid,
-                             trdid_t   thread_trdid,
+
+
+
+//////////////////////////////////////////////////
+void dev_nic_packet_display( pid_t     socket_pid,
+                             uint32_t  socket_fdid,
                              uint32_t  cycle,
                              uint8_t * buf )
@@ -2815,20 +2987,12 @@
     remote_busylock_acquire( lock_xp );
 
-    if( is_tx )
-    {
-        nolock_printk("\n*** NIC_TX server thread[%x,%x] send packet / cycle %d\n",
-        thread_pid, thread_trdid, cycle );
-    }
-    else
-    {
-        nolock_printk("\n*** NIC_RX server thread[%x,%x] get packet / cycle %d\n",
-        thread_pid, thread_trdid, cycle );
-    }
-
-    nolock_printk("\n***** ETH header *****\n");
+    nolock_printk("\n***** packet sent by NIC_TX server for socket[%x,%d] / cycle %d\n",
+    socket_pid, socket_fdid, cycle );
+
+    nolock_printk(" ETH header\n");
     nolock_printk(" - dst_mac  [6] = %l\n" , eth_dst_mac );
     nolock_printk(" - src_mac  [6] = %l\n" , eth_src_mac );
     nolock_printk(" - length   [2] = %d\n" , (uint32_t)eth_length );
-    nolock_printk("***** IP  header *****\n");
+    nolock_printk(" IP  header\n");
     nolock_printk(" - version  [1] = %x\n" , (uint32_t)ip_version );
     nolock_printk(" - tos      [1] = %x\n" , (uint32_t)ip_tos );
@@ -2850,5 +3014,5 @@
                                 ((uint16_t)buf[37]     ) ;
 
-        nolock_printk("***** UDP header *****\n");
+        nolock_printk(" UDP header\n");
         nolock_printk(" - src_port [2] = %d\n" , (uint32_t)udp_src_port );
         nolock_printk(" - dst_port [2] = %d\n" , (uint32_t)udp_dst_port );
@@ -2881,5 +3045,5 @@
                                  ((uint16_t)buf[53]     ) ;
 
-        nolock_printk("***** TCP header *****\n");
+        nolock_printk(" TCP header\n");
         nolock_printk(" - src_port [2] = %x\n" , (uint32_t)tcp_src_port );
         nolock_printk(" - dst_port [2] = %x\n" , (uint32_t)tcp_dst_port );
