Changeset 663


Ignore:
Timestamp:
Oct 10, 2020, 4:56:11 PM (4 years ago)
Author:
alain
Message:

Introduce support for both TCP in the dev_nic.h & dev_nic.c files.

Location:
trunk/kernel/devices
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/devices/dev_ioc.c

    r657 r663  
    7878                                  lid );
    7979
    80     assert( (error == 0) , "cannot create server thread" );
     80assert( (error == 0) , "cannot create server thread" );
    8181
    8282    // set "server" field in chdev descriptor
  • trunk/kernel/devices/dev_mmc.h

    r657 r663  
    9696
    9797/*****************************************************************************************
    98  * This function initializes the driver specific fields in the generic MMC device
    99  * descriptor, and the implementation specific driver.
     98 * This function initializes the driver specific fields in the local MMC chdev,
     99 * and initializes the implementation specific MMC driver.
    100100 * It must be executed once in any cluster containing an L2 cache.
    101101 *****************************************************************************************
     
    105105
    106106/*****************************************************************************************
    107  * This function invalidates all cache lines covering a memory buffer
    108  * in the physical address space.
     107 * This function invalidates all cache lines covering a memory buffer  defined by
     108 * the <buf_xp> and <buf_size> arguments.
    109109 * It can be executed by any thread in any cluster, because it uses remote accesses
    110110 * to access both the MMC device descriptor, and the L2 cache configuration interface.
     
    119119/*****************************************************************************************
    120120 * This function forces the L2 cache to synchronize the L3 cache for all cache lines
    121  * covering a memory buffer in the physical address space.
     121 * covering a memory buffer defined by the <buf_xp> and <buf_size> arguments.
    122122 * It can be executed by any thread in any cluster, because it uses remote accesses
    123123 * to access both the MMC device descriptor, and the L2 cache configuration interface.
  • trunk/kernel/devices/dev_nic.c

    r657 r663  
     1
    12/*
    23 * dev_nic.c - NIC (Network Controler) generic device API implementation.
     
    2627#include <hal_uspace.h>
    2728#include <remote_buf.h>
     29#include <memcpy.h>
    2830#include <printk.h>
    2931#include <chdev.h>
    3032#include <thread.h>
    31 #include <socket.h>
     33#include <ksocket.h>
    3234#include <hal_drivers.h>
    3335#include <dev_nic.h>
     
    4143extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
    4244
     45////////////////////////////////////
     46void dev_nic_init( chdev_t * chdev )
     47{
     48    thread_t * new_thread;
     49    error_t    error;
     50
     51    // get "channel" & "is_rx" fields from chdev descriptor
     52    uint32_t  channel = chdev->channel;
     53    bool_t    is_rx   = chdev->is_rx;
     54
     55    // set chdev name
     56    if( is_rx ) snprintf( chdev->name , 16 , "nic%d_rx" , channel );
     57    else        snprintf( chdev->name , 16 , "nic%d_tx" , channel );
     58
     59    // initialize the root of the listening sockets list
     60    xlist_root_init( XPTR( local_cxy , &chdev->ext.nic.root ) );
     61
     62    // initialize the lock protecting this list
     63    remote_busylock_init( XPTR( local_cxy , &chdev->ext.nic.lock ),
     64                          LOCK_LISTEN_SOCKET );
     65
     66    // call driver init function for this chdev
     67    hal_drivers_nic_init( chdev );
     68
     69    // select a core to execute the NIC server thread
     70    lid_t lid = cluster_select_local_core( local_cxy );
     71
     72    // bind the NIC IRQ to the selected core
     73    dev_pic_bind_irq( lid , chdev );
     74
     75    // build pointer on server function
     76    void * func = is_rx ? &dev_nic_rx_server : &dev_nic_tx_server;
     77
     78    // create server thread
     79    error = thread_kernel_create( &new_thread,
     80                                  THREAD_DEV,
     81                                  func,
     82                                  chdev,
     83                                  lid );
     84    if( error )
     85    {
     86        printk("\n[PANIC] in %s : cannot create server thread\n", __FUNCTION__ );
     87        return;
     88    }
     89
     90    // set "server" field in chdev descriptor
     91    chdev->server = new_thread;
     92   
     93    // set "chdev" field in thread descriptor
     94    new_thread->chdev = chdev;
     95
     96    // unblock server thread
     97    thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
     98
     99#if (DEBUG_DEV_NIC_TX || DEBUG_DEV_NIC_RX)
     100thread_t * this = CURRENT_THREAD;
     101if( is_rx )
     102printk("\n[%s] thread[%x,%x] initialized NIC_RX[%d] / server %x\n",
     103__FUNCTION__, this->process->pid, this->trdid, channel, new_thread->trdid );
     104else
     105printk("\n[%s] thread[%x,%x] initialized NIC_TX[%d] / server %x\n",
     106__FUNCTION__, this->process->pid, this->trdid, channel, new_thread->trdid );
     107#endif
     108   
     109}  // end dev_nic_init()
     110
     111
     112///////////////////////////////////////////////////////////////////////////////////////////
     113//      Functions directly called by the client threads
     114///////////////////////////////////////////////////////////////////////////////////////////
     115
     116////////////////////////////////////////
     117uint32_t dev_nic_get_key( uint32_t addr,
     118                          uint16_t port )
     119{
     120    thread_t * this = CURRENT_THREAD;
     121   
     122    xptr_t dev_xp = chdev_dir.nic_tx[0];
     123    chdev_t * dev_ptr = GET_PTR( dev_xp );
     124
     125    if( dev_xp == XPTR_NULL ) return -1;
     126   
     127    // set command arguments in client thread descriptor
     128    this->nic_cmd.buffer = (uint8_t *)addr;
     129    this->nic_cmd.length = (uint32_t)port;
     130    this->nic_cmd.dev_xp = dev_xp;
     131    this->nic_cmd.type   = NIC_CMD_GET_KEY;
     132
     133    // call driver
     134    dev_ptr->cmd( XPTR( local_cxy , this ) );
     135
     136    // get "status"
     137    return this->nic_cmd.status;
     138}
     139
     140//////////////////////////////////////////
     141error_t dev_nic_set_run( uint32_t channel,
     142                         uint32_t run )
     143{
     144    thread_t * this = CURRENT_THREAD;
     145
     146    if( channel >= LOCAL_CLUSTER->nb_nic_channels ) return -1;
     147
     148    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     149    chdev_t * dev_ptr = GET_PTR( dev_xp );
     150
     151    if( dev_xp == XPTR_NULL ) return -1;
     152   
     153    // set command arguments in client thread descriptor
     154    this->nic_cmd.dev_xp = dev_xp;
     155    this->nic_cmd.type   = NIC_CMD_SET_RUN;
     156    this->nic_cmd.length = channel;
     157    this->nic_cmd.status = run;
     158
     159    // call driver
     160    dev_ptr->cmd( XPTR( local_cxy , this ) );
     161
     162    // return "error"
     163    return this->nic_cmd.error;
     164}
     165
     166//////////////////////////////////
     167error_t dev_nic_get_instru( void )
     168{
     169    thread_t * this = CURRENT_THREAD;
     170
     171    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     172    chdev_t * dev_ptr = GET_PTR( dev_xp );
     173   
     174    if( dev_xp == XPTR_NULL ) return -1;
     175   
     176    // set command arguments in client thread descriptor
     177    this->nic_cmd.dev_xp = dev_xp;
     178    this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
     179
     180    // call driver
     181    dev_ptr->cmd( XPTR( local_cxy , this ) );
     182
     183    // return "error"
     184    return this->nic_cmd.error;
     185}
     186
     187////////////////////////////////////
     188error_t dev_nic_clear_instru( void )
     189{
     190    thread_t * this = CURRENT_THREAD;
     191
     192    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
     193    chdev_t * dev_ptr = GET_PTR( dev_xp );
     194   
     195    if( dev_xp == XPTR_NULL ) return -1;
     196   
     197    // set command arguments in client thread descriptor
     198    this->nic_cmd.dev_xp = dev_xp;
     199    this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
     200
     201    // call driver
     202    dev_ptr->cmd( XPTR( local_cxy , this ) );
     203
     204    // return "error"
     205    return this->nic_cmd.error;
     206}
     207
     208
    43209////////////////////////////////////////////////////////////////////////////////////////////
    44 // This static function is used by the dev_nic_rx_handle_tcp() & dev_nic_tx_handle_tcp()
    45 // functions to check acceptability of a given sequence number. It returns true when
    46 // the <seq> argument is contained in a wrap-around window defined by the <min> and <max>
    47 // arguments. The window wrap-around when (min > max).
     210//      Static functions called by the NIC_RX server & NIC_TX server threads
     211////////////////////////////////////////////////////////////////////////////////////////////
     212
     213////////////////////////////////////////////////////////////////////////////////////////////
     214// This static function is used by the dev_nic_rx_handle_tcp() function
     215// to check acceptability of a given sequence number. It returns true when
     216// the <seq> argument is contained in a wrap-around window defined by the
     217// <min> and <max> arguments. The window wrap-around when (min > max).
    48218////////////////////////////////////////////////////////////////////////////////////////////
    49219// @ seq   : [in] value to be checked.
     
    65235
    66236
    67 ////////////////////////////////////////////////////////////////////////////////////////////
    68 // this static function compute a channel index in range [0,nic_channelx[ from
    69 // a remote IP address and remote port.
    70 // TODO this function should be provided by the NIC driver.
    71 ////////////////////////////////////////////////////////////////////////////////////////////
    72 // @ addr     : [in] IP address.
    73 // @ port     : [in] TCP/UDP port.
    74 ////////////////////////////////////////////////////////////////////////////////////////////
    75 static inline uint32_t dev_nic_channel_index( uint32_t addr,
    76                                               uint16_t port )
    77 {
    78     // get number of NIC channels
    79     uint32_t nic_channels = LOCAL_CLUSTER->nb_nic_channels;
    80  
    81     // compute NIC channel index
    82     return ( ((addr     ) & 0xFF) ^
    83              ((addr > 8 ) & 0xFF) ^
    84              ((addr > 16) & 0xFF) ^
    85              ((addr > 24) & 0xFF) ^
    86              ((port     ) & 0xFF) ^
    87              ((port > 8 ) & 0xFF) ) % nic_channels;
    88 }
    89 
    90237////////////////////////////////////////////////////////////////////////////////////////
    91238// This static function computes the checksum for an IP packet header.
     
    95242// @ return the checksum value on 16 bits
    96243////////////////////////////////////////////////////////////////////////////////////////
    97 uint16_t dev_nic_ip_checksum( uint8_t  * buffer )
     244static uint16_t dev_nic_ip_checksum( uint8_t  * buffer )
    98245{
    99246    uint32_t   i;           
     
    121268// @ return the checksum value on 16 bits
    122269////////////////////////////////////////////////////////////////////////////////////////
    123 uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
    124                                uint32_t   size )
     270static uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
     271                                      uint32_t   size )
    125272{
    126273    uint32_t   i;           
     
    158305
    159306////////////////////////////////////////////////////////////////////////////////////////
    160 // This static function computes the checksum for a TCP segment defined by
    161 // the <buffer> and <size> arguments.
    162 // It includes the pseudo header defined by the <src_ip_addr>, <dst_ip_addr>,
    163 // <size> arguments, and by the TCP_PROTOCOL code.
     307// This static function computes the checksum for a TCP segment defined by the <buffer>
     308// and <size> arguments. It includes the pseudo header defined by the <src_ip_addr>,
     309// <dst_ip_addr>, <size> arguments, and by the TCP_PROTOCOL code.
    164310////////////////////////////////////////////////////////////////////////////////////////
    165311// @ buffer      : [in] pointer on TCP segment base.
    166 // @ size        : [in] number of bytes in this segment (including header).
     312// @ tcp_length  : [in] number of bytes in this TCP segment (including header).
    167313// @ src_ip_addr : [in] source IP address (pseudo header)
    168314// @ dst_ip_addr : [in] destination IP address (pseudo header)
    169315// @ return the checksum value on 16 bits
    170316////////////////////////////////////////////////////////////////////////////////////////
    171 uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
    172                                uint32_t   size,
    173                                uint32_t   src_ip_addr,
    174                                uint32_t   dst_ip_addr )
     317static uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
     318                                      uint32_t   tcp_length,
     319                                      uint32_t   src_ip_addr,
     320                                      uint32_t   dst_ip_addr )
    175321{
    176322    uint32_t   i;           
     
    182328    // compute max & buf
    183329    buf = (uint16_t *)buffer;
    184     max = size >> 1;
     330    max = tcp_length >> 1;
    185331
    186332    // extend buffer[] if required
    187     if( size & 1 )
     333    if( tcp_length & 1 )
    188334    {
    189335        max++;
    190         buffer[size] = 0;
     336        buffer[tcp_length] = 0;
    191337    }
    192338
    193339    // compute checksum for TCP segment
    194     for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
     340    for( i = 0 , cs = 0 ; i < tcp_length ; i++ )  cs += buf[i];
    195341
    196342    // complete checksum for pseudo-header
     
    198344    cs += dst_ip_addr;
    199345    cs += PROTOCOL_TCP;
    200     cs += size;
     346    cs += tcp_length;
    201347
    202348    // handle carry
     
    213359}
    214360
    215 //////////////////////////////////
    216 void dev_nic_init( chdev_t * nic )
     361///////////////////////////////////////////////////////////////////////////////////////////
     362// This static function can be called by the NIC_TX or NIC_RX server threads to unblock
     363// the TX client thread after completion (success or error) of a TX command registered
     364// in a socket identified by the <socket_xp> argument. The <status> argument defines
     365// the command success/failure status: a null value signals a success, a non-null value
     366// signals a failure. For all commands, it copies the status value in the tx_sts field,
     367// and print an error message on TXT0 in case of failure.
     368///////////////////////////////////////////////////////////////////////////////////////////
     369// @ socket_xp  : [in] extended pointer on socket
     370// @ status     : [in] command status (see above)
     371///////////////////////////////////////////////////////////////////////////////////////////
     372static void dev_nic_unblock_tx_client( xptr_t   socket_xp,
     373                                       int32_t  status )
    217374{
    218     // get "channel" & "is_rx" fields from chdev descriptor
    219     uint32_t  channel = nic->channel;
    220     bool_t    is_rx   = nic->is_rx;
    221 
    222     // set chdev name
    223     if( is_rx ) snprintf( nic->name , 16 , "nic%d_rx" , channel );
    224     else        snprintf( nic->name , 16 , "nic%d_tx" , channel );
    225 
    226     // call driver init function
    227     hal_drivers_nic_init( nic );
    228 
    229     // select a core to execute the NIC server thread
    230     lid_t lid = cluster_select_local_core( local_cxy );
    231 
    232     // bind the NIC IRQ to the selected core
    233     // but does NOT enable it
    234     dev_pic_bind_irq( lid , nic );
    235 
    236     // create server thread
    237     thread_t * new_thread;
    238     error_t    error;
    239 
    240     error = thread_kernel_create( &new_thread,
    241                                   THREAD_DEV,
    242                                   &chdev_server_func,
    243                                   nic,
    244                                   lid );
    245 
    246     assert( (error == 0) , "cannot create server thread" );
    247 
    248     // set "server" field in chdev descriptor
    249     nic->server = new_thread;
    250    
    251     // set "chdev" field in thread descriptor
    252     new_thread->chdev = nic;
    253 
    254     // unblock server thread
    255     thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
    256 
    257 }  // end dev_nic_init()
    258 
    259 
    260 /////////////////////////////////////////////////////////////////////////////////////////
    261 //                 Functions implementing the SOCKET related syscalls
    262 /////////////////////////////////////////////////////////////////////////////////////////
    263 
    264 //////////////////////////////////////
    265 int dev_nic_socket( uint32_t   domain,
    266                     uint32_t   type )
     375    // get socket thread cluster and local pointer
     376    socket_t * socket_ptr = GET_PTR( socket_xp );
     377    cxy_t      socket_cxy = GET_CXY( socket_xp );
     378
     379    if( status != CMD_STS_SUCCESS )
     380    {
     381        uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
     382        uint32_t cmd_type   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
     383        pid_t    pid        = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     384        fdid_t   fdid       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
     385
     386        printk("\n[ERROR] reported by %s : socket[%x,%d] / %s / cmd %s / error %s \n",
     387        __FUNCTION__, pid, fdid, socket_state_str(sock_state),
     388        socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) );
     389    }
     390
     391    // set tx_sts field in socket descriptor
     392    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_sts ) , status );
     393
     394    // get extended point on TX client thread
     395    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
     396
     397    // unblock the client thread
     398    thread_unblock( client_xp , THREAD_BLOCKED_IO );
     399
     400}  // end dev_nic_unblock_tx_client()
     401
     402///////////////////////////////////////////////////////////////////////////////////////////
     403// This static function can be called by the NIC_TX or NIC_RX server threads to unblock
     404// the RX client thread after completion (success or error) of an RX command registered
     405// in a socket identified by the <socket_xp> argument. The <status> argument defines
     406// the command success/failure status: a null value signals a success, a non-null value
     407// signals a failure. For all commands, it copies the status value in the rx_sts field,
     408// and print an error message on TXT0 in case of failure.
     409///////////////////////////////////////////////////////////////////////////////////////////
     410// @ socket_xp  : [in] extended pointer on socket
     411// @ status     : [in] command status (see above)
     412///////////////////////////////////////////////////////////////////////////////////////////
     413static void dev_nic_unblock_rx_client( xptr_t   socket_xp,
     414                                       int32_t  status )
    267415{
    268     uint32_t    fdid;
    269     socket_t  * socket;
    270     error_t     error;
    271 
    272     // allocate memory for the file descriptor and for the socket
    273     error = socket_create( local_cxy,
    274                            domain,
    275                            type,
    276                            &socket,    // unused here
    277                            &fdid );
    278 
    279     if( error ) return -1;
    280     return fdid;
    281 }
    282 
    283 ////////////////////////////////
    284 int dev_nic_bind( uint32_t fdid,
    285                   uint32_t addr,
    286                   uint16_t port )
    287 {
    288     vfs_inode_type_t    type;
    289     socket_t          * socket;
    290     uint32_t            state;
    291 
    292     thread_t  * this    = CURRENT_THREAD;
    293     process_t * process = this->process;
    294 
    295     // get pointers on file descriptor
    296     xptr_t       file_xp  = process_fd_get_xptr( process , fdid );
    297     vfs_file_t * file_ptr = GET_PTR( file_xp );
    298     cxy_t        file_cxy = GET_CXY( file_xp );
    299 
    300     // check file_xp
    301     if( file_xp == XPTR_NULL )
     416    // get socket thread cluster and local pointer
     417    socket_t * socket_ptr = GET_PTR( socket_xp );
     418    cxy_t      socket_cxy = GET_CXY( socket_xp );
     419
     420    if( status != CMD_STS_SUCCESS )
    302421    {
    303         printk("\n[ERROR] in %s : undefined fdid %d",
    304         __FUNCTION__, fdid );
    305         return -1;
     422        uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
     423        uint32_t cmd_type   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->rx_cmd ));
     424        pid_t    pid        = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     425        fdid_t   fdid       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
     426
     427        printk("\n[ERROR] reported by %s : socket[%x,%d] / %s / cmd %s / error %s\n",
     428        __FUNCTION__, pid, fdid, socket_state_str(sock_state),
     429        socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) );
    306430    }
    307431
    308     type   = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
    309     socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
    310 
    311     // check file descriptor type
    312     if( type != INODE_TYPE_SOCK )
    313     {
    314         printk("\n[ERROR] in %s : illegal file type %s",
    315         __FUNCTION__, vfs_inode_type_str( type ) );
    316         return -1;
    317     }
    318 
    319     state = (type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND;
    320 
    321     // update the socket descriptor
    322     hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr );
    323     hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port );
    324     hal_remote_s32( XPTR( file_cxy , &socket->state      ) , state );
    325 
    326     return 0;
    327 
    328 }  // end dev_nic_bind()
    329 
    330 //////////////////////////////////
    331 int dev_nic_listen( uint32_t fdid,
    332                     uint32_t max_pending )
    333 {
    334     xptr_t              file_xp;
    335     vfs_file_t        * file_ptr;
    336     cxy_t               file_cxy;
    337     vfs_inode_type_t    file_type;
    338     socket_t          * socket_ptr;
    339     uint32_t            socket_type;
    340     uint32_t            socket_state;
    341 
    342     thread_t  * this    = CURRENT_THREAD;
    343     process_t * process = this->process;
    344 
    345     if( max_pending != 0 )
    346     {
    347         printk("\n[WARNING] in %s : max_pending argument non supported\n",
    348         __FUNCTION__ );
    349     }
    350 
    351     // get pointers on file descriptor
    352     file_xp  = process_fd_get_xptr( process , fdid );
    353     file_ptr = GET_PTR( file_xp );
    354     file_cxy = GET_CXY( file_xp );
    355 
    356     // check file_xp
    357     if( file_xp == XPTR_NULL )
    358     {
    359         printk("\n[ERROR] in %s : undefined fdid %d",
    360         __FUNCTION__, fdid );
    361         return -1;
    362     }
    363 
    364     file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
    365     socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
    366 
    367     // check file descriptor type
    368     if( file_type != INODE_TYPE_SOCK )
    369     {
    370         printk("\n[ERROR] in %s : illegal file type %s",
    371         __FUNCTION__, vfs_inode_type_str(file_type) );
    372         return -1;
    373     }
    374 
    375     // get socket type and state
    376     socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
    377     socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
    378 
    379     // check socket type
    380     if( socket_type != SOCK_STREAM )
    381     {
    382         printk("\n[ERROR] in %s : illegal socket type",
    383         __FUNCTION__ );
    384         return -1;
    385     }
    386    
    387     // check socket state
    388     if( socket_state != TCP_STATE_BOUND )
    389     {
    390         printk("\n[ERROR] in %s : illegal socket state %s",
    391         __FUNCTION__, socket_state_str(socket_state) );
    392         return -1;
    393     }
    394    
    395     // update socket.state
    396     hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , TCP_STATE_LISTEN );
    397 
    398     return 0;
    399 
    400 }  // end dev_nic_listen()
    401 
    402 ///////////////////////////////////
    403 int dev_nic_connect( uint32_t fdid,
    404                      uint32_t remote_addr,
    405                      uint16_t remote_port )
    406 {
    407     vfs_inode_type_t    file_type;
    408     socket_t          * socket;
    409     uint32_t            socket_state;     // socket state
    410     uint32_t            socket_type;      // socket type 
    411     uint32_t            local_addr;       // local IP address
    412     uint32_t            local_port;       // local port
    413     xptr_t              tx_server_xp;     // extended pointer on TX server thread
    414     thread_t          * tx_server_ptr;    // local pointer on TX server thread
    415 
    416     thread_t  * this    = CURRENT_THREAD;
    417     process_t * process = this->process;
    418 
    419     // get pointers on file descriptor
    420     xptr_t       file_xp  = process_fd_get_xptr( process , fdid );
    421     vfs_file_t * file_ptr = GET_PTR( file_xp );
    422     cxy_t        file_cxy = GET_CXY( file_xp );
    423 
    424     // check file_xp
    425     if( file_xp == XPTR_NULL )
    426     {
    427         printk("\n[ERROR] in %s : undefined fdid %d",
    428         __FUNCTION__, fdid );
    429         return -1;
    430     }
    431 
    432     file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
    433     socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
    434 
    435     // check file descriptor type
    436     if( file_type != INODE_TYPE_SOCK )
    437     {
    438         printk("\n[ERROR] in %s : illegal file type %s",
    439         __FUNCTION__, vfs_inode_type_str( file_type ) );
    440         return -1;
    441     }
    442 
    443     // get relevant socket infos
    444     socket_type   = hal_remote_l32( XPTR( file_cxy , &socket->type ) );
    445     socket_state  = hal_remote_l32( XPTR( file_cxy , &socket->state ) );
    446     local_addr    = hal_remote_l32( XPTR( file_cxy , &socket->local_addr ) );
    447     local_port    = hal_remote_l32( XPTR( file_cxy , &socket->local_port ) );
    448 
    449     if( socket_type == SOCK_DGRAM )       // UDP
    450     {
    451         if( socket_state != UDP_STATE_BOUND )
    452         {
    453             printk("\n[ERROR] in %s : illegal socket statea %s for CONNECT",
    454             __FUNCTION__, socket_state_str(socket_state) );
    455             return -1;
    456         }
    457     }
    458     else if( socket_type == SOCK_STREAM )  // TCP
    459     {
    460         if( socket_state != TCP_STATE_BOUND )
    461         {
    462             printk("\n[ERROR] in %s : illegal socket state %s for CONNECT",
    463             __FUNCTION__, socket_state_str(socket_state) );
    464             return -1;
    465         }
    466     }
    467     else
    468     {
    469         printk("\n[ERROR] in %s : illegal socket type %d for CONNECT",
    470         __FUNCTION__, socket_type );
    471         return -1;
    472     }
    473 
    474     // compute nic_channel index from remote_addr and remote_port
    475     uint32_t nic_channel = dev_nic_channel_index( remote_addr , remote_port );
    476 
    477     // link new socket to chdev servers
    478     socket_link_to_servers( XPTR( file_cxy , socket ),
    479                             nic_channel );
    480 
    481     // update the socket descriptor
    482     hal_remote_s32( XPTR( file_cxy , &socket->remote_addr ) , remote_addr  );
    483     hal_remote_s32( XPTR( file_cxy , &socket->remote_port ) , remote_port  );
    484     hal_remote_s32( XPTR( file_cxy , &socket->nic_channel ) , nic_channel  );
    485 
    486     // the actual connection mechanism depends on socket type
    487     // UDP : client thread directly updates the local socket state
    488     // TCP : client thread request TX server thread to start the 3 steps handshake
    489 
    490     if( socket_type == SOCK_DGRAM )  // UDP
    491     {
    492         // directly update the local socket state
    493         hal_remote_s32( XPTR( file_cxy , &socket->state ) , UDP_STATE_CONNECT );
    494     }
    495     else                             // TCP
    496     {
    497         // get pointers on NIC_TX[index] chdev
    498         xptr_t    tx_chdev_xp  = chdev_dir.nic_tx[nic_channel];
    499         chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp );
    500         cxy_t     tx_chdev_cxy = GET_CXY( tx_chdev_xp );
    501 
    502         // get pointers on NIC_TX[channel] server thread
    503         tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server ));
    504         tx_server_xp  = XPTR( tx_chdev_cxy , tx_server_ptr );
    505 
    506         // register command arguments in socket descriptor
    507         hal_remote_s64( XPTR( file_cxy , &socket->tx_cmd ),
    508                         SOCKET_TX_CONNECT );
    509 
    510         // update the "tx_client" field in socket descriptor
    511         hal_remote_s64( XPTR( file_cxy , &socket->tx_client ),
    512                         XPTR( local_cxy , this ) );
    513 
    514         // unblock NIC_TX server thread
    515         thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT );
    516  
    517         // block on THREAD_BLOCKED_IO condition and deschedules
    518         thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
    519         sched_yield( "blocked in connect" );
    520 
    521         // reset the "tx_client" field in socket descriptor
    522         hal_remote_s64( XPTR( file_cxy , &socket->tx_client ),
    523                         XPTR_NULL );
    524     }
    525 
    526     return 0;
    527 
    528 }  // end dev_nic_connect()
    529 
    530 ////////////////////////////////////
    531 int dev_nic_accept( uint32_t   fdid,
    532                     uint32_t * remote_addr,
    533                     uint16_t * remote_port )
    534 {
    535     xptr_t              file_xp;             // extended pointer on remote file
    536     vfs_file_t        * file_ptr;
    537     cxy_t               file_cxy;
    538     vfs_inode_type_t    file_type;           // file descriptor type
    539     socket_t          * socket;              // local pointer on remote waiting socket
    540     uint32_t            socket_type;         // waiting socket type   
    541     uint32_t            socket_state;        // waiting socket state
    542     uint32_t            socket_domain;       // waiting socket domain
    543     uint32_t            socket_local_addr;   // waiting socket local IP address
    544     uint32_t            socket_local_port;   // waiting socket local port
    545     xptr_t              crqq_xp;             // extended pointer on socket.crqq queue
    546     socket_t          * new_socket;          // local pointer on new socket
    547     uint32_t            new_fdid;            // new socket file descriptor index
    548     sockaddr_t          new_sockaddr;        // one request in crqq queue
    549     uint32_t            new_remote_addr;     // new socket remote IP address
    550     uint32_t            new_remote_port;     // new socket remote port
    551     error_t             error;
    552 
    553     thread_t  * this    = CURRENT_THREAD;
    554     process_t * process = this->process;
    555 
    556     // get pointers on file descriptor
    557     file_xp  = process_fd_get_xptr( process , fdid );
    558     file_ptr = GET_PTR( file_xp );
    559     file_cxy = GET_CXY( file_xp );
    560 
    561     // check file_xp
    562     if( file_xp == XPTR_NULL )
    563     {
    564         printk("\n[ERROR] in %s : undefined fdid %d",
    565         __FUNCTION__, fdid );
    566         return -1;
    567     }
    568 
    569     file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
    570     socket    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
    571 
    572     // check file descriptor type
    573     if( file_type != INODE_TYPE_SOCK )
    574     {
    575         printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]\n",
    576         __FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid );
    577         return -1;
    578     }
    579 
    580     // get socket type, domain, state, local_addr and local_port
    581     socket_type       = hal_remote_l32( XPTR( file_cxy , &socket->type ));
    582     socket_state      = hal_remote_l32( XPTR( file_cxy , &socket->state ));
    583     socket_domain     = hal_remote_l32( XPTR( file_cxy , &socket->domain ));
    584     socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket->local_addr ));
    585     socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket->local_port ));
    586 
    587     // check socket type
    588     if( socket_type != SOCK_STREAM )
    589     {
    590         printk("\n[ERROR] in %s : illegal socket type / thread[%x,%x]\n",
    591         __FUNCTION__, process->pid , this->trdid );
    592         return -1;
    593     }
    594    
    595     // check socket state
    596     if( socket_state != TCP_STATE_LISTEN )
    597     {
    598         printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x]\n",
    599         __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
    600         return -1;
    601     }
    602    
    603     // select a cluster for the new socket
    604     cxy_t new_cxy = cluster_random_select();
    605 
    606     // allocate memory for the new socket descriptor
    607     error = socket_create( new_cxy,
    608                            socket_domain,
    609                            socket_type,
    610                            &new_socket,
    611                            &new_fdid );
    612     if( error )
    613     {
    614         printk("\n[ERROR] in %s : cannot allocate new socket / thread[%x,%x]\n",
    615         __FUNCTION__, process->pid, this->trdid );
    616         return -1;
    617     }
    618    
    619     // build extended pointer on socket.crqq
    620     crqq_xp  = XPTR( file_cxy , &socket->crqq );
    621 
    622     // blocks and deschedules if requests queue empty
    623     if( remote_buf_status( crqq_xp ) == 0 )
    624     {
    625         thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
    626         sched_yield( "socket.crqq queue empty");
    627     }
    628        
    629     // extract first request from the socket.crqq queue
    630     remote_buf_get_to_kernel( crqq_xp,
    631                               (uint8_t *)(&new_sockaddr),
    632                               sizeof(sockaddr_t) );
    633 
    634     new_remote_addr = new_sockaddr.s_addr;
    635     new_remote_port = new_sockaddr.s_port;
    636 
    637     // compute NIC channel index from remote_addr and remote_port
    638     uint32_t nic_channel = dev_nic_channel_index( new_remote_addr , new_remote_port );
    639 
    640     // update new socket descriptor
    641     new_socket->local_addr  = hal_remote_l32(XPTR( file_cxy , &socket->local_addr ));
    642     new_socket->local_port  = hal_remote_l32(XPTR( file_cxy , &socket->local_port ));
    643     new_socket->remote_addr = new_remote_addr;
    644     new_socket->remote_port = new_remote_port;
    645     new_socket->nic_channel = nic_channel;
    646 
    647     // link new socket to chdev servers
    648     socket_link_to_servers( XPTR( new_cxy , new_socket ),
    649                             nic_channel );
    650     // return success
    651     *remote_addr = new_remote_addr;
    652     *remote_port = new_remote_port;
    653 
    654     return new_fdid;
    655 
    656 }  // end dev_nic_accept()
    657 
    658 ////////////////////////////////////////////////////////////////////////////////////////
    659 // This static and blocking function is called by the four functions :
    660 // dev_nic_send() / dev_nic_recv() / dev_nic_sendto() / dev_nic_recvfrom().
    661 ////////////////////////////////////////////////////////////////////////////////////////
    662 // Implementation note
    663 // The behavior is very different for SEND & RECV :
    664 // - For a SEND, the client thread checks that there is no TX command registered
    665 //   in the socket. It registers the command arguments in the socket descriptor
    666 //   (tx_client, tx_cmd, tx_buf, tx_len). Then the client thread unblocks the
    667 //   TX server thread from the BLOCKED_CLIENT condition, blocks itself on the
    668 //   BLOCKED_IO condition, and deschedules. It is unblocked by the TX server thread
    669 //   when the last byte has been sent (for UDP) or acknowledged (for TCP).
    670 //   When the client thread resumes, it reset the command in socket, and returns.
    671 // - For a RECV, the client thread checks that there is no RX command registered
    672 //   in the socket. It registers itself in socket (rx_client). It checks the status
    673 //   of the receive buffer. It the rx_buf is empty, it blocks on the BLOCKED_IO
    674 //   condition, and deschedules. It is unblocked by the RX server thread when an UDP
    675 //   packet or TCP segment has been writen in the rx_buf. When it resumes, it moves
    676 //   the available data from the rx_buf to the user buffer, reset its registration
    677 //   in socket (reset the rx_buf for an UDP socket), and returns.
    678 ////////////////////////////////////////////////////////////////////////////////////////
    679 int dev_nic_register_cmd( bool_t     is_send,
    680                           uint32_t   fdid,
    681                           uint8_t  * u_buf,
    682                           uint32_t   length,
    683                           bool_t     explicit,
    684                           uint32_t   explicit_addr,
    685                           uint32_t   explicit_port )
    686 {
    687     vfs_inode_type_t    file_type;       // file descriptor type
    688     socket_t          * socket_ptr;      // local pointer on socket descriptor
    689     uint32_t            socket_state;    // current socket state
    690     uint32_t            socket_type;     // socket type (UDP/TCP)
    691     uint32_t            nic_channel;     // NIC channel for this socket
    692     xptr_t              socket_lock_xp;  // extended pointer on socket lock
    693     xptr_t              file_xp;         // extended pointer on file descriptor
    694     vfs_file_t        * file_ptr;
    695     cxy_t               file_cxy;
    696     xptr_t              chdev_xp;        // extended pointer on NIC_TX[channel] chdev
    697     chdev_t           * chdev_ptr;
    698     cxy_t               chdev_cxy;
    699     uint32_t            remote_addr;
    700     uint32_t            remote_port;
    701     uint32_t            status;          // number of bytes in rx_buf
    702     int32_t             moved_bytes;     // total number of moved bytes (fot return)
    703     xptr_t              server_xp;       // extended pointer on NIC_TX / NIC_RX server thread
    704     thread_t          * server_ptr;      // local pointer on NIC_TX / NIC_RX server thread
    705 
    706     thread_t  * this    = CURRENT_THREAD;
    707     process_t * process = this->process;
    708 
    709     // get pointers on file descriptor identifying the socket
    710     file_xp  = process_fd_get_xptr( process , fdid );
    711     file_ptr = GET_PTR( file_xp );
    712     file_cxy = GET_CXY( file_xp );
    713 
    714     if( file_xp == XPTR_NULL )
    715     {
    716         printk("\n[ERROR] in %s : undefined fdid %d / thread%x,%x]\n",
    717         __FUNCTION__, fdid , process->pid, this->trdid );
    718         return -1;
    719     }
    720  
    721     // get file type and socket pointer
    722     file_type  = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) );
    723 
    724     // get local pointer on socket
    725     socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) );
    726 
    727     // check file descriptor type
    728     if( file_type != INODE_TYPE_SOCK )
    729     {
    730         printk("\n[ERROR] in %s : illegal file type %s / fdid %d / thread%x,%x]\n",
    731         __FUNCTION__, vfs_inode_type_str(file_type), fdid, process->pid, this->trdid );
    732         return -1;
    733     }
    734 
    735     // build extended pointer on file lock protecting socket
    736     socket_lock_xp = XPTR( file_cxy , &file_ptr->lock );
    737 
    738     // take the socket lock
    739     remote_rwlock_wr_acquire( socket_lock_xp );
    740 
    741     // get socket type, state, and channel
    742     socket_type  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type ));
    743     socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state ));
    744     nic_channel  = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel ));
    745 
    746     // check socket state / type
    747     if( socket_type == SOCK_STREAM )     // TCP socket
    748     {
    749         if( socket_state != TCP_STATE_ESTAB )
    750         {
    751             printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
    752             __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
    753             return -1;
    754         }
    755 
    756         if( explicit )
    757         {
    758             // get remote IP address and type from socket descriptor
    759             remote_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_addr ));
    760             remote_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_port ));
    761 
    762             if( (remote_addr != explicit_addr) || (remote_port != explicit_port) )
    763             {
    764                 printk("\n[ERROR] in %s : wrong expliciy access / thread%x,%x]\n",
    765                 __FUNCTION__, process->pid, this->trdid );
    766                 return -1;
    767             }
    768         }
    769     }
    770     else                              // UDP socket
    771     {
    772         if( explicit )
    773         {
    774             if( socket_state == UDP_STATE_UNBOUND )
    775             {
    776                 printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
    777                 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
    778                 return -1;
    779             }
    780 
    781             // update remote IP address and port into socket descriptor
    782             hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ), explicit_addr );
    783             hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ), explicit_port );
    784         }
    785         else
    786         {
    787             if( socket_state != UDP_STATE_CONNECT )
    788             {
    789                 printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n",
    790                 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid );
    791                 return -1;
    792             }
    793         }
    794     }
    795 
    796     ///////////////////////////////////////////////////////
    797     if( is_send )                       // SEND command
    798     {
    799         // build extended pointer on socket "tx_client"
    800         xptr_t client_xp = XPTR( file_cxy , &socket_ptr->tx_client );
    801 
    802         // check no previous SEND command
    803         xptr_t client = hal_remote_l64( client_xp );
    804 
    805         if( client != XPTR_NULL )  // release socket lock and return error
    806         {
    807             // release socket lock
    808             remote_rwlock_wr_release( socket_lock_xp );
    809                    
    810             // get previous thread cluster & local pointer
    811             cxy_t      prev_cxy = GET_CXY( client );
    812             thread_t * prev_ptr = GET_PTR( client );
    813 
    814             // get previous command type and trdid
    815             uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type ));
    816             uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid ));
    817 
    818             printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n",
    819             __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid,
    820             process->pid, this->trdid );
    821 
    822             return -1;
    823         }
    824 
    825         // client thread registers in socket descriptor
    826         hal_remote_s64( client_xp , XPTR( local_cxy , this ) );
    827         hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd  ) , SOCKET_TX_SEND );
    828         hal_remote_spt( XPTR( file_cxy , &socket_ptr->tx_buf  ) , u_buf );
    829         hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_len  ) , length );
    830         hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_todo ) , length );
    831 
    832         // release socket lock
    833         remote_rwlock_wr_release( socket_lock_xp );
    834                    
    835         // get pointers on relevant chdev
    836         chdev_xp  = chdev_dir.nic_tx[nic_channel];
    837         chdev_ptr = GET_PTR( chdev_xp );
    838         chdev_cxy = GET_CXY( chdev_xp );
    839 
    840         // get pointers on NIC_TX[channel] server thread
    841         server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server ));
    842         server_xp  = XPTR( chdev_cxy , server_ptr );
    843 
    844         // unblocks the NIC_TX server thread
    845         thread_unblock( server_xp , THREAD_BLOCKED_CLIENT );
    846 
    847         // client thread blocks itself and deschedules
    848         thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
    849         sched_yield( "blocked in nic_io" );
    850 
    851         // take the socket lock when unblocked
    852         remote_rwlock_wr_acquire( socket_lock_xp );
    853 
    854         // unlink client thread from socket
    855         hal_remote_s64( client_xp , XPTR_NULL );
    856                    
    857         // release socket lock
    858         remote_rwlock_wr_release( socket_lock_xp );
    859                    
    860         // exit waiting loop and return
    861         return length;
    862 
    863     }  // end SEND
    864 
    865     ////////////////////////////////////////////////////////
    866     else                                 // RECV command
    867     {
    868         // build extended pointers on socket "rx_client"
    869         xptr_t client_xp = XPTR( file_cxy , &socket_ptr->rx_client );
    870 
    871         // check no previous RECV command
    872         xptr_t client = hal_remote_l64( client_xp );
    873 
    874         if( client != XPTR_NULL )  // release socket lock and return error
    875         {
    876             // release socket lock
    877             remote_rwlock_wr_release( socket_lock_xp );
    878                    
    879             // get previous thread cluster & local pointer
    880             cxy_t      prev_cxy = GET_CXY( client );
    881             thread_t * prev_ptr = GET_PTR( client );
    882 
    883             // get previous command type and trdid
    884             uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type ));
    885             uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid ));
    886 
    887             printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n",
    888             __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid, process->pid, this->trdid );
    889             return -1;
    890         }
    891 
    892         // build extended pointer on "rx_buf"
    893         xptr_t rx_buf_xp = XPTR( file_cxy , &socket_ptr->rx_buf );
    894 
    895         // get rx_buf status from socket
    896         status = remote_buf_status( rx_buf_xp );
    897 
    898         if( status == 0 )    // rx_buf empty => blocks and deschedules
    899         {
    900             // release socket lock
    901             remote_rwlock_wr_release( socket_lock_xp );
    902                  
    903             // client thread blocks itself and deschedules
    904             thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO );
    905             sched_yield( "blocked in nic_io" );
    906 
    907             // take socket lock
    908             remote_rwlock_wr_release( socket_lock_xp );
    909         }
    910 
    911         // number of moved bytes cannot be larger than u_buf size
    912         moved_bytes = ( length < status ) ? length : status;
    913 
    914         // move data from kernel rx_buf to user u_buf
    915         remote_buf_get_to_user( rx_buf_xp,
    916                                  u_buf,
    917                                  moved_bytes );
    918 
    919         // reset rx_buf for an UDP socket
    920         if( socket_type == SOCK_DGRAM ) remote_buf_reset( rx_buf_xp );
    921 
    922         // unlink client thread from socket
    923         hal_remote_s64( client_xp , XPTR_NULL );
    924                    
    925         // release socket lock
    926         remote_rwlock_wr_release( socket_lock_xp );
    927                    
    928         // exit waiting loop and return
    929         return moved_bytes;
    930 
    931     }  // end SEND 
    932 
    933 } // end dev_nic_register_cmd()
    934 
    935 
    936 ///////////////////////////////////
    937 int dev_nic_send( uint32_t    fdid,
    938                   uint8_t   * u_buf,
    939                   uint32_t    length )
    940 {
    941 #if DEBUG_DEV_NIC_TX
    942 thread_t  * this    = CURRENT_THREAD;
    943 process_t * process = this->process;
    944 trdid_t     trdid   = this->trdid;
    945 pid_t       pid     = process->pid;
    946 uint32_t cycle = (uint32_t)hal_get_cycle();
    947 if (DEBUG_DEV_NIC_TX < cycle )
    948 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
    949 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
    950 #endif
    951 
    952     error_t error = dev_nic_register_cmd( true,           // SEND
    953                                           fdid,
    954                                           u_buf,
    955                                           length,
    956                                           false, 0, 0 );  // no explicit remote socket
    957 #if DEBUG_DEV_NIC_TX
    958 cycle = (uint32_t)hal_get_cycle();
    959 if (DEBUG_DEV_NIC_TX < cycle )
    960 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
    961 __FUNCTION__, pid, trdid, cycle );
    962 #endif
    963 
    964     return error;
    965 
    966 }  // end dev_nic_send()
    967 
    968 ///////////////////////////////////
    969 int dev_nic_recv( uint32_t    fdid,
    970                   uint8_t   * u_buf,
    971                   uint32_t    length )
    972 {
    973 #if DEBUG_DEV_NIC_RX
    974 thread_t  * this    = CURRENT_THREAD;
    975 process_t * process = this->process;
    976 trdid_t     trdid   = this->trdid;
    977 pid_t       pid     = process->pid;
    978 uint32_t    cycle   = (uint32_t)hal_get_cycle();
    979 if (DEBUG_DEV_NIC_RX < cycle )
    980 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
    981 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
    982 #endif
    983 
    984     error_t error = dev_nic_register_cmd( false,          // RECV
    985                                           fdid,
    986                                           u_buf,
    987                                           length,
    988                                           false, 0, 0 );  // no explicit remote socket
    989 #if DEBUG_DEV_NIC_RX
    990 cycle = (uint32_t)hal_get_cycle();
    991 if (DEBUG_DEV_NIC_RX < cycle )
    992 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
    993 __FUNCTION__, pid, trdid, cycle );
    994 #endif
    995 
    996     return error;
    997 
    998 } // end dev_nic_recv()
    999 
    1000 /////////////////////////////////////
    1001 int dev_nic_sendto( uint32_t    fdid,
    1002                     uint8_t   * u_buf,
    1003                     uint32_t    length,
    1004                     uint32_t    remote_addr,
    1005                     uint32_t    remote_port )
    1006 {
    1007 #if DEBUG_DEV_NIC_TX
    1008 thread_t  * this    = CURRENT_THREAD;
    1009 process_t * process = this->process;
    1010 trdid_t     trdid   = this->trdid;
    1011 pid_t       pid     = process->pid;
    1012 uint32_t cycle = (uint32_t)hal_get_cycle();
    1013 if (DEBUG_DEV_NIC_TX < cycle )
    1014 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
    1015 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
    1016 #endif
    1017 
    1018     error_t error = dev_nic_register_cmd( true,          // SEND
    1019                                           fdid,
    1020                                           u_buf,
    1021                                           length,
    1022                                           true,          // explicit remote socket
    1023                                           remote_addr,
    1024                                           remote_port );
    1025 #if DEBUG_DEV_NIC_TX
    1026 cycle = (uint32_t)hal_get_cycle();
    1027 if (DEBUG_DEV_NIC_TX < cycle )
    1028 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
    1029 __FUNCTION__, pid, trdid, cycle );
    1030 #endif
    1031 
    1032     return error;
    1033 
    1034 }  // end dev_nic_sendto()
    1035 
    1036 ///////////////////////////////////////
    1037 int dev_nic_recvfrom( uint32_t    fdid,
    1038                       uint8_t   * u_buf,
    1039                       uint32_t    length,
    1040                       uint32_t    remote_addr,
    1041                       uint32_t    remote_port )
    1042 {
    1043 #if DEBUG_DEV_NIC_RX
    1044 thread_t  * this    = CURRENT_THREAD;
    1045 process_t * process = this->process;
    1046 trdid_t     trdid   = this->trdid;
    1047 pid_t       pid     = process->pid;
    1048 uint32_t    cycle   = (uint32_t)hal_get_cycle();
    1049 if (DEBUG_DEV_NIC_RX < cycle )
    1050 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n",
    1051 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle );
    1052 #endif
    1053 
    1054     error_t error = dev_nic_register_cmd( false,         // RECV
    1055                                           fdid,
    1056                                           u_buf,
    1057                                           length,
    1058                                           true,          // explicit remote socket
    1059                                           remote_addr,
    1060                                           remote_port );
    1061 #if DEBUG_DEV_NIC_RX
    1062 cycle = (uint32_t)hal_get_cycle();
    1063 if (DEBUG_DEV_NIC_RX < cycle )
    1064 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n",
    1065 __FUNCTION__, pid, trdid, cycle );
    1066 #endif
    1067 
    1068     return error;
    1069 
    1070 }  // end dev_nic_recvfrom()
    1071 
    1072 
    1073 
    1074 
    1075 
     432    // set rx_sts field in socket descriptor
     433    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_sts ) , status );
     434
     435    // get extended point on RX client thread
     436    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->rx_client ));
     437
     438    // unblock the client thread
     439    thread_unblock( client_xp , THREAD_BLOCKED_IO );
     440
     441}  // end dev_nic_unblock_rx_client()
    1076442
    1077443
     
    1080446//               Functions called by the NIC_RX server thread
    1081447///////////////////////////////////////////////////////////////////////////////////////////
    1082 
    1083 /////////////////////////////////////////////////////////////////////////////////////////
    1084 // This static function is called by the NIC_RX[channel] server thread to register
    1085 // a send request defined by the <flags> argument in the R2T queue  specified by
    1086 // the <queue_xp> argument.
    1087 /////////////////////////////////////////////////////////////////////////////////////////
    1088 // @ queue_xp   : [in] extended pointer on the R2T qeue descriptor.
    1089 // @ flags      : [in] flags to be set in the TCP segment.
    1090 /////////////////////////////////////////////////////////////////////////////////////////
    1091 static void dev_nic_rx_put_r2t_request( xptr_t    queue_xp,
    1092                                         uint32_t  flags )
    1093 {
    1094     while( 1 )
    1095     {
    1096         error_t error = remote_buf_put_from_kernel( queue_xp,
    1097                                                     (uint8_t *)(&flags),
    1098                                                     1 );
    1099 
    1100         if( error )  sched_yield( "waiting R2T queue" );
    1101         else         break;
    1102     }
    1103 
    1104 }  // end dev_nic_rx_put_r2t_request()
    1105  
    1106 ///////////////////////////////////////////////////////////////////////////////////////////
    1107 // This static function is called by the dev_nic_rx_server() function.
    1108 // It calls directly the NIC driver (with the READABLE command) and returns the status
    1109 // of the NIC_RX queue identified by the <chdev> argument.
    1110 // in the <readable> buffer.
    1111 ///////////////////////////////////////////////////////////////////////////////////////////
    1112 // @ chdev     : [in]  local pointer on NIC_TX chdev.
    1113 // @ readable  : [out] zero if queue empty. 
    1114 // @ returns 0 if success / returns -1 if failure in accessing NIC device.
    1115 ///////////////////////////////////////////////////////////////////////////////////////////
    1116 error_t dev_nic_rx_queue_readable( chdev_t  * chdev,
    1117                                    uint32_t * readable )
    1118 {
    1119     thread_t * this = CURRENT_THREAD;
    1120 
    1121     // initialize NIC_READABLE command in thread descriptor
    1122     this->nic_cmd.dev_xp = XPTR( local_cxy , chdev );
    1123     this->nic_cmd.type   = NIC_CMD_READABLE;
    1124 
    1125     // call driver to test readable
    1126     chdev->cmd( XPTR( local_cxy , this ) );
    1127 
    1128     // return status
    1129     *readable = this->nic_cmd.status;
    1130 
    1131     // return error
    1132     return this->nic_cmd.error;
    1133 }
    1134 
    1135 ///////////////////////////////////////////////////////////////////////////////////////////
    1136 // This static function is called by the dev_nic_rx_server() function.
    1137 // It moves one Ethernet packet from the NIC_RX_QUEUE identified the <chdev> argument,
    1138 // to the 2K bytes kernel buffer identified by the <buffer> argument. The actual
    1139 // Ethernet packet length is returned in the <length> argument.
    1140 // It calls directly the NIC driver with the READ command, without registering in the
    1141 // waiting queue, because only the NIC_RX server thread can access this NIC_RX_QUEUE.
    1142 ///////////////////////////////////////////////////////////////////////////////////////////
    1143 // @ chdev   : [in]  local pointer on NIC_TX chdev.
    1144 // @ buffer  : [in]  local pointer on destination kernel buffer.
    1145 // @ length  : [out] Ethernet packet size in bytes.
    1146 // @ returns 0 if success / returns -1 if failure in accessing NIC device.
    1147 ///////////////////////////////////////////////////////////////////////////////////////////
    1148 error_t dev_nic_rx_move_packet( chdev_t  * chdev,
    1149                                 uint8_t  * k_buf,
    1150                                 uint32_t * length )
    1151 {
    1152     thread_t * this = CURRENT_THREAD;
    1153 
    1154 #if DEBUG_DEV_NIC_RX
    1155 uint32_t cycle = (uint32_t)hal_get_cycles();
    1156 if( DEBUG_DEV_NIC_RX < cycle )
    1157 printk("\n[%s] thread[%x,%x] enters / cycle %d\n",
    1158 __FUNCTION__, this->process->pid, this->trdid, cycle );
    1159 #endif
    1160 
    1161     // initialize NIC_READ command in thread descriptor
    1162     this->nic_cmd.type    = NIC_CMD_READ;
    1163     this->nic_cmd.buffer  = k_buf;
    1164 
    1165     // call NIC driver 
    1166     chdev->cmd( XPTR( local_cxy , this ) );
    1167 
    1168     // returns packet length   
    1169     *length = this->nic_cmd.length;
    1170 
    1171     // check error
    1172     if( this->nic_cmd.error )
    1173     {
    1174 
    1175 #if DEBUG_DEV_NIC_RX
    1176 cycle = (uint32_t)hal_get_cycles();
    1177 if( DEBUG_DEV_NIC_RX < cycle )
    1178 printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n",
    1179 __FUNCTION__, this->process->pid, this->trdid, cycle );
    1180 #endif
    1181 
    1182         return -1;
    1183     }
    1184     else
    1185     {
    1186 
    1187 #if DEBUG_DEV_NIC_RX
    1188 cycle = (uint32_t)hal_get_cycles();
    1189 if( DEBUG_DEV_NIC_RX < cycle )
    1190 printk("\n[%s] thread[%x,%x] exit / SUCCESS / cycle %d\n",
    1191 __FUNCTION__, this->process->pid, this->trdid, cycle );
    1192 #endif
    1193 
    1194         return 0;
    1195     }
    1196 
    1197 }   // end dev_nic_rx_move_packet()
    1198448
    1199449///////////////////////////////////////////////////////////////////////////////////////////
     
    1237487                                    uint32_t * trsp_protocol )
    1238488{
     489
     490#if DEBUG_DEV_NIC_RX
     491thread_t * this  = CURRENT_THREAD;
     492uint32_t   cycle = (uint32_t)hal_get_cycles();
     493#endif
     494
     495    // get packet length
    1239496    uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
    1240497
    1241     // discard packet if eth_length != ip_length
     498    // discard packet if eth_payload_length != ip_length
    1242499    if( length != expected_length )
    1243500    {
    1244501
    1245 #if DEBUG_NIC_DEV
    1246 thread_t * this = CURRENT_THREAD;
    1247 printk("\n[%s] thread[%x,%x] enters : length (%d) != expected_length (%d)\n",
     502#if DEBUG_DEV_NIC_RX
     503if( DEBUG_DEV_NIC_RX < cycle )
     504printk("\n[%s] thread[%x,%x] failure : length (%d) != expected_length (%d)\n",
    1248505__FUNCTION__, this->process->pid, this->trdid, length, expected_length );
    1249506#endif
    1250 
    1251507        return -1;
    1252508    }
    1253509
     510    // get transport protocol type
     511    uint8_t protocol = buffer[9];
     512
     513    // discard packet if unsupported protocol
     514    if( (protocol != PROTOCOL_TCP) && (protocol != PROTOCOL_UDP) )
     515    {
     516
     517#if DEBUG_DEV_NIC_RX
     518if( DEBUG_DEV_NIC_RX < cycle )
     519printk("\n[%s] thread[%x,%x] failure : unsupported transport protocol (%d)\n",
     520__FUNCTION__, this->process->pid, this->trdid, protocol );
     521#endif
     522        return -1;
     523
     524    }
    1254525    // compute IP header checksum
    1255     uint32_t received_cs = (uint32_t)dev_nic_ip_checksum( buffer );
     526    uint32_t computed_cs = (uint32_t)dev_nic_ip_checksum( buffer );
    1256527
    1257528    // extract IP header checksum
    1258     uint32_t computed_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);
     529    uint32_t received_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);
    1259530
    1260531    // discard packet if bad checksum
     
    1262533    {
    1263534
    1264 #if DEBUG_NIC_DEV
    1265 thread_t * this = CURRENT_THREAD;
    1266 printk("\n[%s] thread[%x,%x] computed checksum (%d) != received checksum (%d)\n",
     535#if DEBUG_DEV_NIC_RX
     536if( DEBUG_DEV_NIC_RX < cycle )
     537printk("\n[%s] thread[%x,%x] failure : computed checksum (%d) != received checksum (%d)\n",
    1267538__FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs );
    1268539#endif
    1269 
    1270540        return -1;
    1271541    }
     
    1282552                   ((uint32_t)buffer[19]      ) ;
    1283553
    1284     *trsp_protocol = (uint32_t)buffer[9];
     554    *trsp_protocol = protocol;
    1285555   
    1286556    return 0;
     
    1354624    if( xlist_is_empty( root_xp ) ) return;
    1355625 
    1356     // take the tock protecting the sockets list
     626    // take the lock protecting the sockets list
    1357627    remote_busylock_acquire( lock_xp );
    1358628
     
    1387657                              (remote_port == pkt_src_port);
    1388658
    1389         if (socket_state == UDP_STATE_CONNECT ) match_socket = local_match && remote_match;
    1390         else                                    match_socket = local_match;
     659        if (socket_state == UDP_STATE_ESTAB ) match_socket = local_match && remote_match;
     660        else                                  match_socket = local_match;
    1391661
    1392662        // exit loop when socket found
     
    1406676
    1407677    // take the lock protecting the socket
    1408     remote_rwlock_wr_acquire( socket_lock_xp );
     678    remote_queuelock_acquire( socket_lock_xp );
    1409679
    1410680    // get status & space from rx_buf
     
    1425695                                 k_buf + UDP_HEAD_LEN,
    1426696                                 moved_bytes );
    1427 
    1428     // unblock client thread if registered
     697    // unblock client thread
    1429698    if( client_xp != XPTR_NULL )
    1430699    {
     
    1433702
    1434703    // release the lock protecting the socket
    1435     remote_rwlock_wr_release( socket_lock_xp );
     704    remote_queuelock_release( socket_lock_xp );
    1436705
    1437706}  // end dev_nic_rx_handle_udp_packet()
     
    1440709// This static function is called by the dev_nic_rx_server() function to handle one RX
    1441710// TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments.
    1442 // It the received segment doesn't match an existing local socket, or is corrupted,
    1443 // this faulty segment is discarded.
     711// The <seg_remote_addr> and <seg_local_addr> arguments are obtained from the received
     712// IP packet header. It the received segment doesn't match any connected socket attached
     713// to the selected chdev[k], or any listening socket waiting connection, or if the segment
     714// is corrupted, this segment is discarded.
     715// If required by the TCP flags, it registers an R2T request in the socket R2T queue
     716// to implement the TCP handcheck for close and connect.
    1444717///////////////////////////////////////////////////////////////////////////////////////////
    1445718// Implementation note:
    1446 // 1) It checks the TCP checksum, and discard the corrupted segment.
    1447 // 2) It scans the list of sockets attached to the RX chdev, to find the socket
    1448 //    matching the TCP segment header, and discards the segment if no socket found.
    1449 // 3) When a socket has been found, it takes the lock protecting the socket state,
    1450 //    because the socket is accessed by both the NIC_TX and NIC_RX server threads.
    1451 // 4) Depending on the socket state, it handle the received segment, including the
    1452 //    SYN, FIN, ACK and RST flags. It updates the socket state when required, moves
    1453 //    data to the rx_buf when possible, and registers requests to the TX server
    1454 //    thread in the R2T queue attached to the socket, to insert control flags in the
    1455 //    TX stream, as required.
    1456 // 5) Finally, it releases the lock protecting the socke and returns.
    1457 ///////////////////////////////////////////////////////////////////////////////////////////
    1458 // @ chdev         : [in] local pointer on local NIC_RX chdev descriptor.
    1459 // @ k_buf         : [in] pointer on the TCP packet in local kernel buffer.
    1460 // @ k_length      : [in] number of bytes in buffer (including TCP header).
    1461 // @ seg_src_addr  : [in] source IP address (from IP packet header).
    1462 // @ seg_dst_addr  : [in] destination IP address (from IP packet header).
     719// A "connected" socket is actually a TCP socket already attached to a given NIC_RX[k]
     720// chdev, and can therefore receive a TCP segment on the NIC channel <k>. A "listening"
     721// socket is a TCP socket in the LISTEN state. This function operates in 6 steps:
     722// 1) It checks the TCP checksum, and discard the corrupted segment if corrupted.
     723// 2) It scans the list of sockets attached to the NIC_RX[k] chdev, to find one TCP
     724//    socket matching the TCP segment header.
     725// 3) When a matching connected socket is found, it handles the received segment, including
     726//    the SYN, FIN, ACK and RST flags. It updates the socket state when required, moves
     727//    data to the rx_buf when possible, and return. It takes the lock protecting the socket,
     728//    because an connected socket is accessed by both the NIC_TX and NIC_RX server threads.
     729// 4) If no matching connected socket has been found, it scans the list of listening
     730//    sockets to find a matching listening socket.
     731// 5) When a matching listening socket is found, it simply registers a new connection
     732//    request in the listening socket CRQ queue, when the SYN flag is set, and insert
     733//    a SYN-ACK request in the socket R2T queue.
     734// 6) It discards the packet if no connected or listening socket has been found.
     735///////////////////////////////////////////////////////////////////////////////////////////
     736// @ chdev           : [in] local pointer on local NIC_RX chdev descriptor.
     737// @ k_buf           : [in] pointer on the TCP packet in local kernel buffer.
     738// @ k_length        : [in] number of bytes in buffer (including TCP header).
     739// @ seg_remote_addr : [in] remote IP address (from IP packet header).
     740// @ seg_local_addr  : [in] local IP address (from IP packet header).
    1463741///////////////////////////////////////////////////////////////////////////////////////////
    1464742static void dev_nic_rx_handle_tcp_segment( chdev_t  * chdev,
    1465743                                           uint8_t  * k_buf,
    1466744                                           uint32_t   k_length,
    1467                                            uint32_t   seg_src_addr,
    1468                                            uint32_t   seg_dst_addr )
     745                                           uint32_t   seg_remote_addr,
     746                                           uint32_t   seg_local_addr )
    1469747{
    1470     xptr_t     root_xp;           // extended pointer on attached sockets list root
    1471     xptr_t     lock_xp;           // extended pointer on chdev lock
    1472     xptr_t     iter_xp;           // iterator for these queues
    1473     bool_t     match_socket;      // true if socket found
    1474     xptr_t     socket_xp;         // extended pointer on matching socket descriptor
    1475     cxy_t      socket_cxy;
    1476     socket_t * socket_ptr;
    1477     uint32_t   local_addr;        // local IP address from socket
    1478     uint32_t   local_port;        // local port from socket
    1479     uint32_t   remote_addr;       // remote IP address from socket
    1480     uint32_t   remote_port;       // remote port from socket
    1481     uint32_t   socket_state;      // socket state
    1482     uint32_t   socket_type;       // socket type
    1483     uint32_t   socket_tx_nxt;    // next byte to send in TX stream
    1484     uint32_t   socket_tx_una;    // first unacknowledged byte in TX stream
    1485     uint32_t   socket_rx_nxt;    // next expected byte in RX stream
    1486     uint32_t   socket_rx_wnd;    // current window value in RX stream
    1487     xptr_t     socket_lock_xp;    // extended pointer on lock protecting socket state
    1488     xptr_t     socket_rx_buf_xp;  // extended pointer on socket rx_buf
    1489     xptr_t     socket_r2tq_xp;    // extended pointer on socket r2t queue
    1490     xptr_t     socket_client_xp;  // extended pointer on socket rx_client thread
    1491     uint16_t   checksum;          // computed TCP segment chechsum
    1492 
    1493     // build extended pointer on xlist of all sockets attached to NIC_RX chdev
    1494     root_xp = XPTR( local_cxy , &chdev->wait_root );
    1495     lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     748    xptr_t     root_xp;            // extended pointer on connected sockets list root
     749    xptr_t     lock_xp;            // extended pointer on chdev lock
     750    xptr_t     iter_xp;            // iterator for these queues
     751    bool_t     attached_match;     // true if one attached socket match
     752    bool_t     listening_match;    // true if one listening socket match
     753    xptr_t     socket_xp;          // extended pointer on matching socket
     754    cxy_t      socket_cxy;         // cluster identifier of matching socket
     755    socket_t * socket_ptr;         // local pointer on matching socket
     756    uint32_t   socket_local_addr;  // local IP address from socket
     757    uint32_t   socket_local_port;  // local port from socket
     758    uint32_t   socket_remote_addr; // remote IP address from socket
     759    uint32_t   socket_remote_port; // remote port from socket
     760    uint32_t   socket_state;       // socket state
     761    uint32_t   socket_type;        // socket type
     762    bool_t     socket_tx_valid;    // TX command valid
     763    uint32_t   socket_tx_cmd;      // TX command type
     764    uint32_t   socket_tx_todo;     // number of TX bytes not sent yet
     765    uint32_t   socket_tx_nxt;      // next byte to send in TX stream
     766    uint32_t   socket_tx_una;      // first unacknowledged byte in TX stream
     767    bool_t     socket_rx_valid;    // RX command valid
     768    uint32_t   socket_rx_cmd;      // TX command type
     769    uint32_t   socket_rx_nxt;      // next expected byte in RX stream
     770    uint32_t   socket_rx_wnd;      // current window value in RX stream
     771    uint32_t   socket_rx_irs;      // initial sequence index in RX stream
     772    xptr_t     socket_lock_xp;     // extended pointer on lock protecting socket state
     773    xptr_t     socket_rx_buf_xp;   // extended pointer on socket rx_buf
     774    xptr_t     socket_r2tq_xp;     // extended pointer on socket R2T queue
     775    xptr_t     socket_crqq_xp;     // extended pointer on socket CRQ queue
     776    uint16_t   checksum;           // computed TCP segment chechsum
     777    error_t    error;
    1496778
    1497779    // get relevant infos from TCP segment header
    1498     uint32_t seg_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
    1499     uint32_t seg_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
     780    uint32_t seg_remote_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
     781    uint32_t seg_local_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
    1500782
    1501783    uint32_t seg_seq_num  = ((uint32_t)k_buf[4]  << 24) |
     
    1509791                            ((uint32_t)k_buf[11]      );
    1510792
    1511     uint8_t  seg_hlen     = k_buf[12] >> 2;       // TCP header length in bytes
     793    uint8_t  seg_hlen     = k_buf[12] << 2;       // TCP header length in bytes
    1512794 
    1513795    uint8_t  seg_flags    = k_buf[13];
     
    1522804    uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17];
    1523805
    1524     uint32_t seg_payload  = k_length - seg_hlen;  // number of bytes in payload
    1525 
    1526     // 1. compute TCP checksum
     806    uint32_t seg_data_len = k_length - seg_hlen;  // number of bytes in payload
     807
     808#if DEBUG_DEV_NIC_RX
     809thread_t * this = CURRENT_THREAD;
     810uint32_t   cycle;
     811uint32_t   fdid;
     812pid_t      pid;
     813#endif
     814
     815#if DEBUG_DEV_NIC_RX
     816cycle = (uint32_t)hal_get_cycles();
     817if( cycle > DEBUG_DEV_NIC_RX )
     818printk("\n[%s] thread[%x,%x] enters / tcp_length %d / tcp_flags %x / cycle %d\n",
     819__FUNCTION__, this->process->pid, this->trdid, k_length, seg_flags , cycle );
     820#endif
     821
     822    // compute and check TCP checksum
     823    k_buf[16] = 0;
     824    k_buf[17] = 0;
    1527825    checksum = dev_nic_tcp_checksum( k_buf,
    1528826                                     k_length,
    1529                                      seg_src_addr,
    1530                                      seg_dst_addr );
     827                                     seg_remote_addr,
     828                                     seg_local_addr );
    1531829
    1532830    // discard segment if corrupted
    1533     if( seg_checksum != checksum ) return;
     831    if( seg_checksum != checksum )
     832    {
     833
     834#if DEBUG_DEV_NIC_RX
     835if( cycle > DEBUG_DEV_NIC_RX )
     836printk("\n[%s] thread[%x,%x] tcp checksum failure : received %x / computed %x\n",
     837__FUNCTION__, this->process->pid, this->trdid, seg_checksum, checksum );
     838#endif
     839        return;
     840    }
    1534841   
    1535     match_socket = false;
    1536 
    1537     // take the lock protecting the list of sockets
     842    // scan list of attached sockets to find a matching TCP socket
     843    attached_match = false;
     844
     845    // build extended pointer on xlist of sockets attached to NIC_RX chdev
     846    root_xp = XPTR( local_cxy , &chdev->wait_root );
     847    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     848
     849    // take the lock protecting the list of attached sockets
    1538850    remote_busylock_acquire( lock_xp );
    1539851
    1540     // 2. scan list of sockets to find a matching socket
    1541852    XLIST_FOREACH( root_xp , iter_xp )
    1542853    {
     
    1554865
    1555866        // get relevant socket infos for matching
    1556         local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
    1557         remote_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
    1558         local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
    1559         remote_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     867        socket_local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     868        socket_remote_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     869        socket_local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     870        socket_remote_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
    1560871               
    1561         // compute matching condition
    1562         // (in LISTEN state, remote_port and remote_addr can be unspecified)
    1563         if( socket_state == TCP_STATE_LISTEN )
     872        // compute matching condition for a connected socket
     873        attached_match = (socket_local_addr  == seg_local_addr) &&
     874                         (socket_local_port  == seg_local_port) &&
     875                         (socket_remote_addr == seg_remote_addr) &&
     876                         (socket_remote_port == seg_remote_port) ;
     877
     878        // exit loop if matching
     879        if( attached_match )
    1564880        {
    1565             match_socket = (local_addr  == seg_dst_addr) &&
    1566                            (local_port  == seg_dst_port) ;
     881
     882#if DEBUG_DEV_NIC_RX
     883fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
     884pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
     885if( cycle > DEBUG_DEV_NIC_RX )
     886printk("\n[%s] thread[%x,%x] matching attached socket[%d,%d] / state %s\n",
     887__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
     888#endif
     889            break;
    1567890        }
    1568         else
     891
     892    }  // end loop on attached sockets
     893
     894    // release the lock protecting the list of attached sockets
     895    remote_busylock_release( lock_xp );
     896
     897    // handle TCP segment for an attached socket
     898    if( attached_match )
     899    {
     900        // The actions depend on both the socket state and the received segment flags :
     901        // - update socket state,
     902        // - move data to rx_buf,
     903        // - register a request in R2T queue when required
     904 
     905        // build extended pointers on various socket fields
     906        socket_lock_xp    = XPTR( socket_cxy , &socket_ptr->lock );
     907        socket_rx_buf_xp  = XPTR( socket_cxy , &socket_ptr->rx_buf );
     908        socket_r2tq_xp    = XPTR( socket_cxy , &socket_ptr->r2tq );
     909
     910        // take the lock protecting the matching socket
     911        remote_queuelock_acquire( socket_lock_xp );
     912
     913        // get relevant socket infos from socket descriptor
     914        socket_tx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_valid ));
     915        socket_tx_cmd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_cmd ));
     916        socket_tx_todo  = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_todo ));
     917        socket_tx_nxt   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt ));
     918        socket_tx_una   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una ));
     919
     920        socket_rx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_valid ));
     921        socket_rx_cmd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_cmd ));
     922        socket_rx_nxt   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt ));
     923        socket_rx_wnd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd ));
     924        socket_rx_irs   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_irs ));
     925
     926        // handle the received segment, depending on the matching socket state
     927        switch( socket_state )
    1569928        {
    1570             match_socket = (local_addr  == seg_dst_addr) &&
    1571                            (local_port  == seg_dst_port) &&
    1572                            (remote_addr == seg_src_addr) &&
    1573                            (remote_port == seg_src_port) ;
    1574         }
    1575 
    1576         // exit loop if matching
    1577         if( match_socket ) break;
    1578 
    1579     }  // end loop on sockets
    1580 
    1581     // release the lock protecting the list of sockets
    1582     remote_busylock_release( lock_xp );
    1583 
    1584     // discard segment if no matching socket found
    1585     if( match_socket == false ) return;
    1586 
    1587     // From here the actions depend on both the socket state,
    1588     // and the received segment flags
    1589     // - update socket state,
    1590     // - move data to rx_buf,
    1591     // - make a R2T request when required
    1592 
    1593     // build extended pointers on various socket fields
    1594     socket_lock_xp    = XPTR( socket_cxy , &socket_ptr->lock );
    1595     socket_rx_buf_xp  = XPTR( socket_cxy , &socket_ptr->rx_buf );
    1596     socket_r2tq_xp    = XPTR( socket_cxy , &socket_ptr->r2tq );
    1597     socket_client_xp  = XPTR( socket_cxy , &socket_ptr->rx_client );
    1598 
    1599     // 3. take the lock protecting the matching socket
    1600     remote_rwlock_wr_acquire( socket_lock_xp );
    1601 
    1602     // get relevant socket infos from socket descriptor
    1603     socket_state   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->state ));
    1604     socket_rx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt ));
    1605     socket_rx_wnd = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd ));
    1606     socket_tx_una = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una ));
    1607     socket_tx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt ));
    1608 
    1609     switch( socket_state )
    1610     {
    1611         //////////////////////
    1612         case TCP_STATE_LISTEN:
    1613         {
    1614             // [1] discard segment if RST flag
    1615             if( seg_rst_set )  return;
    1616 
    1617             // [2] send a RST & discard segment if ACK flag
    1618             if( seg_ack_set )
     929            ////////////////////////
     930            case TCP_STATE_SYN_SENT:  // TCP client waiting for SYN-ACK in connect handshake
    1619931            {
    1620                     // set socket.tx_nxt to seg_ack_num
    1621                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    1622                                     seg_ack_num );
    1623 
    1624                     // make RST request to R2T queue
    1625                     dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1626                                                 TCP_FLAG_RST );
    1627                     // discard segment
     932                // [1] check ACK flag
     933                if( seg_ack_set )
     934                {
     935                    if( seg_ack_num != TCP_ISS_CLIENT + 1 )  // bad ACK => report error
     936                    {
     937
     938#if DEBUG_DEV_NIC_RX
     939printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
     940__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     941socket_state_str(socket_state), TCP_ISS_CLIENT + 1, seg_ack_num );
     942#endif
     943                        // make an RST request to R2T queue
     944                        socket_put_r2t_request( socket_r2tq_xp,
     945                                                TCP_FLAG_RST,
     946                                                chdev->channel );
     947
     948                        // report error to local TX client thread
     949                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
     950
     951                        break;
     952                    }
     953                }
     954
     955                // [2] check RST flag                       // receive RST => report error
     956                if( seg_rst_set )
     957                {
     958
     959#if DEBUG_DEV_NIC_RX
     960printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
     961__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
     962#endif
     963                    // update socket state
     964                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     965                                          TCP_STATE_BOUND );
     966
     967                    // signal error to local TX client thread
     968                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
     969
    1628970                    break;
    1629971                }
    1630972
    1631                 // [3] handle SYN flag
    1632                 if( seg_syn_set )
    1633                 {
     973                // [3] handle security & precedence TODO ... someday
     974
     975                // [4] handle SYN-ACK
     976                if( seg_syn_set && seg_ack_set )  // received SYN and ACK => report success
     977                {
     978
     979#if DEBUG_DEV_NIC_RX
     980printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected SYN-ACK\n",
     981__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     982#endif
     983                    // set socket.tx_una 
     984                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
     985
     986                    // set socket.rx_irs
     987                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->rx_irs), seg_seq_num );
     988
     989                    // set socket.rx_nxt
     990                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->rx_nxt), seg_seq_num + 1 );
     991
     992                    // update socket.state
     993                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_ESTAB );
     994
     995                    // make an ACK request to R2T queue
     996                    socket_put_r2t_request( socket_r2tq_xp,
     997                                            TCP_FLAG_ACK,
     998                                            chdev->channel );
     999
     1000                    // report succes to local TX client thread
     1001                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
     1002                }
     1003                else        // received SYN without ACK => client becomes server
     1004                {
     1005
     1006#if DEBUG_DEV_NIC_RX
     1007printk("\n[%s] thread[%x,%x] for socket[%x,%d] %s : received SYN-ACK => become server\n",
     1008__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1009#endif
     1010                    // update socket.state
     1011                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->state), TCP_STATE_SYN_RCVD );
     1012
     1013                    // set socket.tx_nxt
     1014                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
     1015
    16341016                    // set socket.rx_nxt to seg_seq_num + 1
    1635                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
    1636                                     seg_seq_num + 1 );
    1637 
    1638                     // set socket.tx_nxt to ISS
    1639                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    1640                                     TCP_ISS );
    1641 
    1642                     // set socket.rx_irs to seg_seq_num
    1643                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ),
    1644                                     seg_seq_num + 1 );
    1645 
    1646                     // make SYN.ACK request to R2T queue
    1647                     dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1648                                                 TCP_FLAG_SYN | TCP_FLAG_ACK );
    1649                      
    1650                     // set socket.tx_nxt to ISS + 1
    1651                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    1652                                     TCP_ISS + 1 );
    1653 
    1654                     // set socket.tx_una to ISS
    1655                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
    1656                                     TCP_ISS );
    1657            
    1658                     // update socket.state
    1659                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1660                                     TCP_STATE_SYN_RCVD );
    1661 
    1662                     // update socket.remote_addr
    1663                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_addr ),
    1664                                     seg_src_addr );
    1665 
    1666                     // update socket.remote_port
    1667                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_port ),
    1668                                     seg_src_port );
    1669                 }               
     1017                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_nxt), seg_seq_num + 1 );
     1018
     1019                    // make a SYN.ACK request to R2T queue
     1020                    socket_put_r2t_request( socket_r2tq_xp,
     1021                                            TCP_FLAG_SYN | TCP_FLAG_ACK,
     1022                                            chdev->channel );
     1023                }
    16701024                break;
    16711025            }
    16721026            ////////////////////////
    1673             case TCP_STATE_SYN_SENT:
     1027            case TCP_STATE_SYN_RCVD:  // TCP server waiting last ACK in connect handshake
    16741028            {
    1675                 // [1] check ACK flag
    1676                 if( seg_ack_set )
    1677                 {
    1678                     if( seg_ack_num != TCP_ISS + 1 )  // ACK not acceptable
    1679                     {
    1680                         // discard segment if RST
    1681                         if( seg_rst_set ) break;
    1682 
    1683                         // set socket.tx_nxt to seg_ack_num
    1684                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    1685                                         seg_ack_num );
    1686 
    1687                         // make an RST request to R2T queue
    1688                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1689                                                     TCP_FLAG_RST );
    1690                         // discard segment
    1691                         break;
    1692                     }
    1693                 }
    1694 
    1695                 // [2] check RST flag
     1029                // [1] check sequence number
     1030                if( seg_seq_num != socket_rx_nxt )        // unexpected SEQ_NUM => discard
     1031                {
     1032
     1033#if DEBUG_DEV_NIC_RX
     1034printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect seq_num %x / get %x\n",
     1035__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1036socket_state_str(socket_state), socket_rx_nxt, seg_seq_num );
     1037#endif
     1038                    // discard segment without reporting
     1039                    break;
     1040                }
     1041
     1042                // [2] handle RST flag                    // received RST => report error
    16961043                if( seg_rst_set )
    16971044                {
    1698                     // TODO signal "error: connection reset" to user
     1045
     1046#if DEBUG_DEV_NIC_RX
     1047printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
     1048__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1049#endif
     1050                    // update socket state
     1051                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), TCP_STATE_BOUND );
     1052
     1053                    // report error to local TX client thread
     1054                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
     1055
     1056                    break;
     1057                }
     1058
     1059                // [3] handle security & precedence TODO ... someday
     1060
     1061                // [4] handle SYN flag
     1062                if( seg_syn_set )                           // received SYN => discard
     1063                {
     1064
     1065#if DEBUG_DEV_NIC_RX
     1066printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received SYN flag\n",
     1067__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1068#endif
     1069                    // discard segment without reporting
     1070                    break;
     1071                }
     1072
     1073                // [5] handle  ACK flag
     1074                if( seg_ack_set == false )                      // missing ACK => discard
     1075                {
     1076
     1077#if DEBUG_DEV_NIC_RX
     1078printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK in TCP segment\n",
     1079__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1080#endif
     1081                    // discard segment without reporting
     1082                    break;
     1083                }
     1084                else if( seg_ack_num != (TCP_ISS_SERVER + 1) )  // unacceptable ACK
     1085                {
     1086
     1087#if DEBUG_DEV_NIC_RX
     1088printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
     1089__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1090socket_state_str(socket_state), TCP_ISS_SERVER + 1, seg_ack_num );
     1091#endif
     1092
     1093                    // register an RST request to R2TQ for remote TCP client
     1094                    socket_put_r2t_request( socket_r2tq_xp,
     1095                                            TCP_FLAG_RST,
     1096                                            chdev->channel );
     1097
     1098                    // report error to local TX client thread
     1099                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
     1100                }
     1101                else                                           // acceptable ACK
     1102                {
     1103
     1104#if DEBUG_DEV_NIC_RX
     1105printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected ACK\n",
     1106__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1107#endif
     1108                    // set socket.tx_una 
     1109                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
    16991110
    17001111                    // update socket.state
    1701                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1702                                     TCP_STATE_BOUND );
    1703 
    1704                     // discard segment
    1705                     break;
    1706                 }
    1707 
    1708                 // [3] handle SYN flag when (no ACK or acceptable ACK, and no RST)
    1709                 if( seg_syn_set )
    1710                 {
    1711                     // TODO Ne faut-il pas tester seg_seq_num ?
    1712 
    1713                     if( seg_ack_set )  // received both SYN and ACK
    1714                     {
    1715                         // set socket.rx_nxt to seg_seq_num + 1
    1716                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
    1717                                         seg_seq_num + 1 );
    1718 
    1719                         // set socket.tx_una to seg_ack_num
    1720                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
    1721                                         seg_ack_num );
    1722 
    1723                         // set socket.rx_irs to seg_seq_num
    1724                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ),
    1725                                         seg_seq_num );
    1726 
    1727                         // update socket.state
    1728                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1729                                         TCP_STATE_ESTAB );
    1730 
    1731                         // make an ACK request to R2T queue
    1732                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1733                                                     TCP_FLAG_ACK );
    1734                     }
    1735                     else               // received SYN without ACK
    1736                     {
    1737                         // update socket.state
    1738                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1739                                         TCP_STATE_SYN_RCVD );
    1740 
    1741                         // set socket.tx_nxt to ISS
    1742                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    1743                                         TCP_ISS );     
    1744 
    1745                         // make a SYN.ACK request to R2T queue
    1746                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1747                                                     TCP_FLAG_SYN | TCP_FLAG_ACK );
    1748                     }
     1112                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state),
     1113                                    TCP_STATE_ESTAB );
     1114
     1115                    // report success to local TX client thread
     1116                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
    17491117                }
    17501118                break;
    17511119            }
    1752             ////////////////////////
    1753             case TCP_STATE_SYN_RCVD:
     1120            /////////////////////
    17541121            case TCP_STATE_ESTAB:
    17551122            case TCP_STATE_FIN_WAIT1:
     
    17601127            case TCP_STATE_TIME_WAIT:
    17611128            {
    1762                 // [1] check sequence number
    1763 
    1764                 // compute min & max acceptable sequence numbers
    1765                 uint32_t seq_min  = socket_rx_nxt;
    1766                 uint32_t seq_max  = socket_rx_nxt + socket_rx_wnd - 1;
    1767 
    1768                 // compute sequence number for last byte in segment
    1769                 uint32_t seg_seq_last = seg_seq_num + seg_payload - 1;
    1770 
    1771                 if( (seg_seq_num != socket_rx_nxt) ||     // out_of_order
    1772                     (is_in_window( seg_seq_last,
    1773                                    seq_min,
    1774                                    seq_max ) == false) )  // out_of_window
    1775                 {
     1129                // [1] check sequence number : out_of_order segments not accepted
     1130                if( seg_seq_num != socket_rx_nxt )
     1131                {
     1132
     1133#if DEBUG_DEV_NIC_RX
     1134printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : illegal SEQ_NUM %x / expected %x\n",
     1135__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1136socket_state_str(socket_state), seg_seq_num, socket_rx_nxt );
     1137#endif
    17761138                    // discard segment
    1777                     return;
     1139                    break;
    17781140                }
    17791141
    1780                 // [2] handle RST flag
    1781 
    1782                 if( seg_rst_set )
    1783                 {
    1784                      if( socket_state == TCP_STATE_SYN_RCVD )
    1785                      {
    1786                          // TODO unblock all clients threads with "reset" responses
    1787                      }
    1788                      else if( (socket_state == TCP_STATE_ESTAB     ) ||
    1789                               (socket_state == TCP_STATE_FIN_WAIT1 ) ||
    1790                               (socket_state == TCP_STATE_FIN_WAIT2 ) ||
    1791                               (socket_state == TCP_STATE_CLOSE_WAIT) )
    1792                      {
    1793                          // TODO all pending send & received commands
    1794                          // must receive "reset" responses
    1795 
    1796                          // TODO destroy the socket
    1797                      }
    1798                      else  // all other states
    1799                      {
    1800                              
    1801 
    1802                 }
    1803 
    1804                 // [3] handle security & precedence TODO ... someday
    1805 
    1806                 // [4] handle SYN flag
    1807 
    1808                 if( seg_syn_set )        // received SYN
    1809                 {
    1810                     // TODO signal error to user
    1811 
    1812                     // make an RST request to R2T queue
    1813                     dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1814                                                 TCP_FLAG_RST );
    1815                     // update socket state
    1816                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1817                                     TCP_STATE_BOUND );
    1818                 }
    1819 
    1820                 // [5] handle  ACK flag
    1821 
    1822                 if( seg_ack_set == false )
    1823                 {
    1824                     // discard segment when ACK not set
    1825                     break;
    1826                 }
    1827                 else if( socket_state == TCP_STATE_SYN_RCVD )
    1828                 {
    1829                     if( is_in_window( seg_ack_num , socket_tx_una , socket_tx_nxt ) )
     1142                // check all bytes in window when the payload exist
     1143                // TODO : we could accept bytes that are in window,
     1144                // but this implementation reject all bytes in segment
     1145                if( seg_data_len > 0 )
     1146                {
     1147                    // compute min & max acceptable sequence numbers
     1148                    uint32_t seq_min  = socket_rx_nxt;
     1149                    uint32_t seq_max  = socket_rx_nxt + socket_rx_wnd - 1;
     1150
     1151                    // compute sequence number for last byte in segment
     1152                    uint32_t seg_seq_last = seg_seq_num + seg_data_len - 1;
     1153                     
     1154                    if( is_in_window( seg_seq_last, seq_min, seq_max ) == false )
    18301155                    {
    1831                         // update socket.state to ESTAB
    1832                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1833                                               TCP_STATE_ESTAB );
    1834                     }
    1835                     else   // unacceptable ACK
    1836                     {
    1837                         // set socket.tx_nxt to seg_ack_num
    1838                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
    1839                                         seg_ack_num );
    1840 
    1841                         // make an RST request to R2T queue
    1842                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1843                                                     TCP_FLAG_RST );
    1844                     }
    1845                 }
    1846                 else if( (socket_state == TCP_STATE_ESTAB)      ||
    1847                          (socket_state == TCP_STATE_FIN_WAIT1)  ||
    1848                          (socket_state == TCP_STATE_FIN_WAIT1)  ||
    1849                          (socket_state == TCP_STATE_CLOSE_WAIT) ||
    1850                          (socket_state == TCP_STATE_CLOSING)    )
    1851                 {
    1852                     if( is_in_window( seg_ack_num + 1 , socket_tx_una , socket_tx_nxt ) )
    1853                     {
    1854                         // update socket.tx_una
    1855                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
    1856                                         seg_ack_num );
    1857 
    1858                         // update socket.tx_wnd 
    1859                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_wnd ),
    1860                                         seg_window );
    1861                     }
    1862                     else   // unacceptable ACK
    1863                     {
     1156
     1157#if DEBUG_DEV_NIC_RX
     1158printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : last SEQ_NUM %x not in [%x,%x]\n",
     1159__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1160socket_state_str(socket_state), seg_seq_last, seq_min, seq_max );
     1161#endif
    18641162                        // discard segment
    18651163                        break;
    18661164                    }
    1867                
    1868                     // specific for FIN_WAIT1
    1869                     if( socket_state == TCP_STATE_FIN_WAIT1 )
     1165                }
     1166
     1167                // [2] handle RST flag
     1168                if( seg_rst_set )
     1169                {
     1170
     1171#if DEBUG_DEV_NIC_RX
     1172printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
     1173__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
     1174#endif
     1175                    if( (socket_state == TCP_STATE_ESTAB     ) ||
     1176                        (socket_state == TCP_STATE_FIN_WAIT1 ) ||
     1177                        (socket_state == TCP_STATE_FIN_WAIT2 ) ||
     1178                        (socket_state == TCP_STATE_CLOSE_WAIT) )
    18701179                    {
    1871                         if( seg_fin_set )
    1872                         {
    1873                             // update socket.state
    1874                             hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1875                                                   TCP_STATE_FIN_WAIT2 );
    1876                         }
     1180                        // TODO all pending send & received commands
     1181                        // must receive "reset" responses
     1182
     1183                        // TODO destroy the socket
    18771184                    }
    1878 
    1879                     // specific for CLOSING
    1880                     if( socket_state == TCP_STATE_CLOSING )
     1185                    else  // states CLOSING / LAST_ACK / TIME_WAIT
    18811186                    {
    1882                         if( seg_ack_set )
    1883                         {
    1884                             // update socket.state
    1885                             hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1886                                                   TCP_STATE_TIME_WAIT );
    1887                         }
    1888                         else
    1889                         {
    1890                             // discard segment
    1891                             break;
    1892                         }
     1187                        // TODO         
    18931188                    }
    1894                 }
    1895                 else if( socket_state == TCP_STATE_LAST_ACK )
    1896                 {
    1897                     if( seg_ack_set )
     1189                    break;
     1190                }
     1191
     1192                // [3] handle security & precedence TODO ... someday
     1193
     1194                // [4] check SYN flag
     1195                if( seg_syn_set )                                // received SYN => ERROR
     1196                {
     1197
     1198#if DEBUG_DEV_NIC_RX
     1199printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received unexpected SYN\n",
     1200__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
     1201#endif
     1202                    // TODO signal error to user
     1203
     1204                    // make an RST request to R2T queue
     1205                    socket_put_r2t_request( socket_r2tq_xp,
     1206                                            TCP_FLAG_RST,
     1207                                            chdev->channel );
     1208
     1209                    // update socket state
     1210                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_BOUND );
     1211
     1212                    break;
     1213                }
     1214
     1215                // [5] check ACK 
     1216                if( seg_ack_set == false )                           // missing ACK
     1217                {
     1218
     1219#if DEBUG_DEV_NIC_RX
     1220printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK flag\n",
     1221__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
     1222#endif
     1223                    // discard segment
     1224                    break;
     1225                }
     1226                else if( is_in_window( seg_ack_num,
     1227                                       socket_tx_una,
     1228                                       socket_tx_nxt ) == false )    // unacceptable ACK
     1229                {
     1230
     1231#if DEBUG_DEV_NIC_RX
     1232printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : ACK_NUM %x not in [%x,%x]\n",
     1233__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state),
     1234seg_ack_num, socket_tx_una, socket_tx_nxt );
     1235#endif
     1236                    // discard segment
     1237                    break;
     1238                }
     1239                else                                                // acceptable ack
     1240                {
     1241                    // update socket.tx_una
     1242                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
     1243
     1244                    // update socket.tx_wnd 
     1245                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_wnd), seg_window );
     1246
     1247                    // check last data byte acknowledged for a SEND command
     1248                    if( (socket_tx_todo == 0) &&
     1249                        (seg_ack_num == socket_tx_nxt) &&
     1250                        (socket_tx_cmd == CMD_TX_SEND) )
    18981251                    {
    1899                         // update socket.state
    1900                         hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1901                                               TCP_STATE_TIME_WAIT );
     1252                        // signal success to TX client thread
     1253                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
    19021254                    }
     1255                }
    19031256                   
    1904                 }
    1905 
    1906                 // [6] handle URG flag  TODO ... someday
    1907 
    1908                 // [7] Move DATA to rx_buf and unblock client thread
    1909 
    1910                 if( seg_payload )
     1257                // [7] handle URG flag  TODO ... someday
     1258
     1259                // [8] Move DATA to rx_buf / ACK request to R2T queue / unblock rx_client
     1260                if( seg_data_len )
    19111261                {
    19121262                    if( (socket_state == TCP_STATE_ESTAB)     ||
     
    19201270                        uint32_t space = NIC_RX_BUF_SIZE - status;
    19211271
    1922                         // compute number of bytes to move : min (space , seg_payload)
    1923                         uint32_t nbytes = ( space < seg_payload ) ? space : seg_payload;
     1272                        // compute number of bytes to move : min (space , seg_data_len)
     1273                        uint32_t nbytes = ( space < seg_data_len ) ? space : seg_data_len;
    19241274
    19251275                        // move payload from k_buf to rx_buf
     
    19271277                                                    k_buf + seg_hlen,
    19281278                                                    nbytes );
     1279#if DEBUG_DEV_NIC_RX
     1280printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : move %d bytes to rx_buf\n",
     1281__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1282socket_state_str(socket_state), nbytes );
     1283#endif
    19291284                        // update socket.rx_nxt
    19301285                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     
    19331288                        // update socket.rx_wnd
    19341289                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
    1935                                         socket_rx_wnd - nbytes );
    1936 
    1937                         // make an ACK request to R2T queue
    1938                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1939                                                     TCP_FLAG_ACK );
    1940 
    1941                         // get extended pointer on rx_client thread
    1942                         xptr_t client_xp = hal_remote_l64( socket_client_xp );
    1943                        
    1944                         // unblock client thread
    1945                         if( client_xp != XPTR_NULL )
     1290                                              socket_rx_wnd - nbytes );
     1291
     1292                        // make an ACK request to R2T queue
     1293                        socket_put_r2t_request( socket_r2tq_xp,
     1294                                                TCP_FLAG_ACK,
     1295                                                chdev->channel );
     1296
     1297                        // check pending RX_RECV command
     1298                        if( (socket_rx_valid == true) &&
     1299                            (socket_rx_cmd == CMD_RX_RECV) )
    19461300                        {
    1947                             thread_unblock( client_xp , THREAD_BLOCKED_IO );
     1301                            // reset rx_valid
     1302                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
     1303
     1304                            // report success to RX client thread
     1305                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
     1306#if DEBUG_DEV_NIC_RX
     1307printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock waiting RX client thread\n",
     1308__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1309socket_state_str(socket_state) );
     1310#endif
    19481311                        }
    19491312                    }
    19501313                }
    19511314
    1952                 // [8] handle FIN flag
    1953 
    1954                 if( seg_fin_set )
    1955                 {
    1956                     if( (socket_state == TCP_STATE_UNBOUND) ||
    1957                         (socket_state == TCP_STATE_BOUND)   ||
    1958                         (socket_state == TCP_STATE_LISTEN)  ||
    1959                         (socket_state == TCP_STATE_SYN_SENT) )
     1315                // [9] handle FIN flag
     1316                if( socket_state == TCP_STATE_ESTAB )
     1317                {
     1318                    if( seg_fin_set )  // received ACK & FIN   
    19601319                    {
    1961                         // discard segment
    1962                         break;
    1963                     }
    1964                     else // all other states
    1965                     {
    1966                         // TODO signal "connection closing"
    1967 
    1968                         // make an ACK request to R2T queue
    1969                         dev_nic_rx_put_r2t_request( socket_r2tq_xp,
    1970                                                     TCP_FLAG_ACK );
    1971 
    1972                         // increment socket.rx_nxt
     1320
     1321#if DEBUG_DEV_NIC_RX
     1322printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSE_WAIT\n",
     1323__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1324socket_state_str(socket_state) );
     1325#endif
     1326                        // update socket.rx_nxt when FIN received
    19731327                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
    19741328                                        socket_rx_nxt + 1 );
    19751329
    1976                         if( (socket_state == TCP_STATE_SYN_RCVD) ||
    1977                             (socket_state == TCP_STATE_ESTAB) )
     1330                        // update socket state
     1331                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1332                                        TCP_STATE_CLOSE_WAIT );
     1333
     1334                        // make an ACK request to R2T queue
     1335                        socket_put_r2t_request( socket_r2tq_xp,
     1336                                                TCP_FLAG_ACK,
     1337                                                chdev->channel );
     1338
     1339                        // check pending RX_RECV command
     1340                        if( (socket_rx_valid == true) &&
     1341                            (socket_rx_cmd == CMD_RX_RECV) )
    19781342                        {
    1979                             // update socket.state
    1980                             hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1981                                             TCP_STATE_TIME_WAIT );
    1982                         }
    1983                         else if( socket_state == TCP_STATE_FIN_WAIT1 )
    1984                         {
    1985                             if( seg_ack_set )
    1986                             {
    1987                                 // TODO start "time-wait" timer / turn off others timers
    1988 
    1989                                 // update socket.state
    1990                                 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1991                                                 TCP_STATE_TIME_WAIT );
    1992                             }
    1993                             else
    1994                             {
    1995                                 // update socket.state
    1996                                 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    1997                                                 TCP_STATE_CLOSING );
    1998                             }
    1999                         }
    2000                         else if( socket_state == TCP_STATE_FIN_WAIT2 )
    2001                         {
    2002                             // TODO start "time-wait" timer / turn off other timers
    2003 
    2004                             // update socket.state
    2005                             hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2006                                             TCP_STATE_TIME_WAIT );
    2007                         }
    2008                         else if( socket_state == TCP_STATE_TIME_WAIT )
    2009                         {
    2010                             // TODO restart "time_wait" timer
    2011                         }
     1343                            // reset rx_valid
     1344                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
     1345
     1346                            // report error to RX client thread
     1347                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_EOF );
     1348#if DEBUG_DEV_NIC_RX
     1349printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock RX client waiting on RECV\n",
     1350__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1351socket_state_str(socket_state) );
     1352#endif
     1353                        }
    20121354                    }
    2013                 }  // end if FIN
    2014             }  // end case sockets synchronized
     1355                }
     1356                else if( socket_state == TCP_STATE_FIN_WAIT1 )
     1357                {
     1358                    if( seg_fin_set )  // received ACK & FIN
     1359                    {
     1360
     1361#if DEBUG_DEV_NIC_RX
     1362printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSING\n",
     1363__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1364socket_state_str(socket_state) );
     1365#endif
     1366                        // update socket.rx_nxt when FIN received
     1367                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1368                                        socket_rx_nxt + 1 );
     1369
     1370                        // update socket state
     1371                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1372                                        TCP_STATE_CLOSING );
     1373
     1374                        // make an ACK request to R2T queue
     1375                        socket_put_r2t_request( socket_r2tq_xp,
     1376                                                TCP_FLAG_ACK,
     1377                                                chdev->channel );
     1378                    }
     1379                    else              // received ACK only
     1380                    {
     1381
     1382#if DEBUG_DEV_NIC_RX
     1383printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : only ACK => goes FIN_WAIT2\n",
     1384__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1385socket_state_str(socket_state) );
     1386#endif
     1387                        // update socket state
     1388                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1389                                        TCP_STATE_FIN_WAIT2 );
     1390                    }
     1391                }
     1392                else if( socket_state == TCP_STATE_FIN_WAIT2 )
     1393                {
     1394                    if( seg_fin_set )  // received ACK & FIN
     1395                    {
     1396
     1397#if DEBUG_DEV_NIC_RX
     1398printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSED / unblock client\n",
     1399__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     1400socket_state_str(socket_state) );
     1401#endif
     1402                        // update socket.rx_nxt when FIN received
     1403                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1404                                        socket_rx_nxt + 1 );
     1405
     1406                        // update socket.state
     1407                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1408                                        TCP_STATE_CLOSED );  // TODO change to TIME_WAIT
     1409
     1410                        // make an ACK request to R2T queue
     1411                        socket_put_r2t_request( socket_r2tq_xp,
     1412                                                TCP_FLAG_ACK,
     1413                                                chdev->channel );
     1414               
     1415                        // report success to TX client thread
     1416                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
     1417
     1418                        // TODO start the MSL timer / turn off others timers
     1419
     1420                    }
     1421                }
     1422                else if( socket_state == TCP_STATE_CLOSING )   // received ACK
     1423                {
     1424                    // update socket.state
     1425                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1426                                    TCP_STATE_CLOSED );  // todo change to TIME_WAIT
     1427
     1428                    // TODO start the MSL timer / turn off others timers
     1429
     1430                }
     1431                else if( socket_state == TCP_STATE_TIME_WAIT )
     1432                {
     1433                    // TODO wait msl_time_out before unblocking TX thread
     1434
     1435                    // update socket.state when ACK received
     1436                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1437                                    TCP_STATE_CLOSED );
     1438
     1439                    // unblock TX client thead for success
     1440                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
     1441                }
     1442                else if( socket_state == TCP_STATE_CLOSE_WAIT )
     1443                {
     1444                    // do nothing
     1445                }
     1446                else if( socket_state == TCP_STATE_LAST_ACK )
     1447                {
     1448                    // update socket.state when ACK received
     1449                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1450                                    TCP_STATE_CLOSED );
     1451
     1452                    // unblock TX client thead for success
     1453                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
     1454                }
     1455            }  // end case connecteded states
    20151456        }  // end switch socket state
    20161457
    2017         // release the lock protecting socket
    2018         remote_rwlock_wr_acquire( socket_lock_xp );
    2019 
    2020     }  // end socket found
     1458        // release the lock protecting socket state
     1459        remote_queuelock_release( socket_lock_xp );
     1460
     1461        return;
     1462
     1463    }  // end if attached socket
     1464
     1465    // 4. scan the list of listening sockets
     1466    listening_match = false;
     1467 
     1468    // get pointers on NIC_RX[0] chdev
     1469    xptr_t    rx0_chdev_xp  = chdev_dir.nic_rx[0];
     1470    chdev_t * rx0_chdev_ptr = GET_PTR( rx0_chdev_xp );
     1471    cxy_t     rx0_chdev_cxy = GET_CXY( rx0_chdev_xp );
     1472   
     1473    // build extended pointers on list of listening sockets
     1474    xptr_t    rx0_root_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.root );
     1475    xptr_t    rx0_lock_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.lock );
     1476
     1477    // take the lock protecting the list of listening sockets
     1478    remote_busylock_acquire( rx0_lock_xp );
     1479
     1480    // scan the xlist of listening socket
     1481    XLIST_FOREACH( rx0_root_xp , iter_xp )
     1482    {
     1483        // get socket cluster and local pointer
     1484        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
     1485        socket_ptr = GET_PTR( socket_xp );
     1486        socket_cxy = GET_CXY( socket_xp );
     1487
     1488        // get relevant socket type and state
     1489        socket_type     = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
     1490        socket_state    = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
     1491               
     1492// check socket type and state
     1493assert( (socket_type  == SOCK_STREAM ) , "illegal socket type" );
     1494assert( (socket_state == TCP_STATE_LISTEN ) , "illegal socket state" );
     1495
     1496        // get relevant socket infos for matching
     1497        socket_local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     1498        socket_local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     1499               
     1500        // compute matching condition for a listening socket
     1501        listening_match = (socket_local_addr  == seg_local_addr) &&
     1502                          (socket_local_port  == seg_local_port);
     1503
     1504        // exit loop if matching
     1505        if( listening_match )
     1506        {
     1507
     1508#if DEBUG_DEV_NIC_RX
     1509fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
     1510pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
     1511if( cycle > DEBUG_DEV_NIC_RX )
     1512printk("\n[%s] thread[%x,%x] matching listening socket[%d,%d] / state %s\n",
     1513__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
     1514#endif
     1515            break;
     1516        }
     1517    }   // end loop on listening sockets
     1518
     1519    // release the lock protecting the list of listening sockets
     1520    remote_busylock_release( rx0_lock_xp );
     1521
     1522    // 5. handle TCP segment for a matching listening socket
     1523    if( listening_match )
     1524    {
     1525        // The actions depend on the received segment flags
     1526        // - discard segment for RST or ACK
     1527        // - update socket state & remote IP address,
     1528        //   register connect request in socket CRQ queue,
     1529        //   and unblock client thread for SYN
     1530 
     1531        // discard segment if RST flag
     1532        if( seg_rst_set )
     1533        {
     1534
     1535#if DEBUG_DEV_NIC_RX
     1536if( cycle > DEBUG_DEV_NIC_RX )
     1537printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received RST\n",
     1538__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
     1539#endif
     1540            return;
     1541        }
     1542
     1543        // discard segment if ACK flag
     1544        if( seg_ack_set )
     1545        {
     1546
     1547#if DEBUG_DEV_NIC_RX
     1548if( cycle > DEBUG_DEV_NIC_RX )
     1549printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received ACK\n",
     1550__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
     1551#endif
     1552            return;
     1553        }
     1554
     1555        // SYN flag == CONNECT request / seq_num cannot be wrong
     1556        if( seg_syn_set )
     1557        {
     1558            // build extended pointer on listening socket CRQ
     1559            socket_crqq_xp = XPTR( socket_cxy , &socket_ptr->crqq );
     1560
     1561            // try to register request into CRQ queue
     1562            error = socket_put_crq_request( socket_crqq_xp,
     1563                                            seg_remote_addr,
     1564                                            seg_remote_port,
     1565                                            seg_seq_num,
     1566                                            seg_window );
     1567
     1568            if ( error )   // CRQ full
     1569            {
     1570
     1571#if DEBUG_DEV_NIC_RX
     1572if( cycle > DEBUG_DEV_NIC_RX )
     1573printk("\n[%s] thread[%x,%x] listening socket[%x,%d] CRQ full => send RST\n",
     1574__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
     1575#endif
     1576                // make an RST request to R2T queue
     1577                socket_put_r2t_request( socket_r2tq_xp,
     1578                                        TCP_FLAG_RST,
     1579                                        chdev->channel );
     1580            }
     1581            else          // new connection request registered in CRQ
     1582            {
     1583
     1584#if DEBUG_DEV_NIC_RX
     1585if( cycle > DEBUG_DEV_NIC_RX )
     1586printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : register request in CRQ\n",
     1587__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
     1588#endif
     1589                // check pending RX_ACCEPT command
     1590                if( (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_valid)) == true) &&
     1591                    (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_cmd)) == CMD_RX_ACCEPT) )
     1592                {
     1593                    // reset rx_valid
     1594                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_valid ), false );
     1595                     
     1596                    // report success to RX client thread
     1597                    dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
     1598
     1599#if DEBUG_DEV_NIC_RX
     1600if( cycle > DEBUG_DEV_NIC_RX )
     1601printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] unblock RX client thread\n",
     1602__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
     1603#endif
     1604                }
     1605            }   // end register request in CRQ
     1606        }   // end if SYN
     1607       
     1608        return;
     1609
     1610    }  // end if listening_match
     1611
     1612    // 6. no socket found => discard segment
     1613
     1614#if DEBUG_DEV_NIC_RX
     1615if( cycle > DEBUG_DEV_NIC_RX )
     1616printk("\n[%s] thread[%x,%x] exit failure : no socket found => discard segment\n",
     1617__FUNCTION__, this->process->pid, this->trdid );
     1618#endif
    20211619
    20221620}  // end dev_nic_rx_handle_tcp_segment()
     
    20271625{
    20281626    uint8_t       k_buf[2048];          // kernel buffer for one ETH/IP/UDP packet
    2029                                  
    20301627    uint32_t      pkt_src_addr;         // packet source IP address
    20311628    uint32_t      pkt_dst_addr;         // packet destination IP address
     
    20331630    uint32_t      eth_length;           // size of Ethernet packet (bytes)
    20341631    uint32_t      ip_length;            // size of IP packet in bytes
    2035     uint32_t      nic_queue_readable;   // NIC_RX queue non empty when true
    20361632    error_t       error;
    20371633
    2038     thread_t * this = CURRENT_THREAD;
     1634    thread_t    * this = CURRENT_THREAD;
     1635
     1636// check thread can yield
     1637thread_assert_can_yield( this , __FUNCTION__ );
    20391638
    20401639// check chdev direction and type
     
    20421641"illegal chdev type or direction" );
    20431642
    2044 // check thread can yield
    2045 assert( (this->busylocks == 0),
    2046 "cannot yield : busylocks = %d\n", this->busylocks );
     1643#if DEBUG_DEV_NIC_RX
     1644uint32_t   cycle = (uint32_t)hal_get_cycles();
     1645if( cycle > DEBUG_DEV_NIC_RX )
     1646printk("\n[%s] thread[%x,%x] starts / cycle %d\n",
     1647__FUNCTION__, this->process->pid, this->trdid, cycle );
     1648#endif
     1649
     1650    // get extended pointers on server tread and chdev
     1651    xptr_t     thread_xp = XPTR( local_cxy , this );
     1652    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
    20471653
    20481654    while( 1 )
    20491655    {
    2050         // check NIC_RX_QUEUE readable
    2051         error = dev_nic_rx_queue_readable( chdev,
    2052                                            &nic_queue_readable );
    2053         if( error )
     1656        // call NIC driver to move one packet from NIC_RX queue to kernel buffer
     1657        this->nic_cmd.dev_xp  = chdev_xp;
     1658        this->nic_cmd.type    = NIC_CMD_READ;
     1659        this->nic_cmd.buffer  = k_buf;
     1660        chdev->cmd( XPTR( local_cxy , this ) );
     1661
     1662        // get packet length   
     1663        eth_length = this->nic_cmd.status;
     1664
     1665        // check success
     1666        if( eth_length == 0 )  // queue empty => block and deschedule
    20541667        {
    2055             printk("\n[PANIC] in %s : cannot access NIC_TX[%d] queue\n",
    2056             __FUNCTION__, chdev->channel );
     1668
     1669#if DEBUG_DEV_NIC_RX
     1670cycle = (uint32_t)hal_get_cycles();
     1671if( DEBUG_DEV_NIC_RX < cycle )
     1672printk("\n[%s] thread[%x,%x] NIC_RX_QUEUE empty => blocks on <ISR> / cycle %d\n",
     1673__FUNCTION__, this->process->pid, this->trdid, cycle );
     1674#endif
     1675            // enable NIC_RX IRQ
     1676            dev_pic_enable_irq( this->core->lid , chdev_xp );
     1677
     1678            // block and deschedule
     1679            thread_block( thread_xp , THREAD_BLOCKED_ISR );
     1680            sched_yield("client blocked on NIC_TX queue full");
     1681
     1682            // disable NIC-RX IRQ
     1683            dev_pic_disable_irq( this->core->lid , chdev_xp );
     1684
     1685#if DEBUG_DEV_NIC_RX
     1686cycle = (uint32_t)hal_get_cycles();
     1687if( DEBUG_DEV_NIC_RX < cycle )
     1688printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
     1689__FUNCTION__, this->process->pid, this->trdid, cycle );
     1690#endif
     1691
    20571692        }
    2058    
    2059         if( nic_queue_readable ) // NIC_TX_QUEUE non empty
     1693        else                 // success => handle packet
    20601694        {
    2061             // moves one Ethernet packet to kernel buffer
    2062             error = dev_nic_rx_move_packet( chdev,
    2063                                             k_buf,
    2064                                             &eth_length );
    2065             if( error )
    2066             {
    2067                 printk("\n[PANIC] in %s : cannot read the NIC_TX[%d] queue\n",
    2068                 __FUNCTION__, chdev->channel );
    2069             }
     1695
     1696#if DEBUG_DEV_NIC_RX
     1697cycle = (uint32_t)hal_get_cycles();
     1698if( DEBUG_DEV_NIC_RX < cycle )
     1699dev_nic_packet_display( false,               // is_tx
     1700                        this->process->pid,
     1701                        this->trdid,
     1702                        cycle,
     1703                        k_buf );
     1704#endif
    20701705
    20711706            // analyse the ETH header
     
    20741709
    20751710            // discard packet if error reported by Ethernet layer
    2076             if( error ) continue;
    2077 
     1711            if( error )
     1712            {
     1713
     1714#if DEBUG_DEV_NIC_RX
     1715cycle = (uint32_t)hal_get_cycles();
     1716if( DEBUG_DEV_NIC_RX < cycle )
     1717printk("\n[%s] thread[%x,%x] discard ETH packet / cycle %d\n",
     1718__FUNCTION__, this->process->pid, this->trdid, cycle );
     1719#endif
     1720                continue;
     1721            }
     1722
     1723#if (DEBUG_DEV_NIC_RX & 1)
     1724cycle = (uint32_t)hal_get_cycles();
     1725if( DEBUG_DEV_NIC_RX < cycle )
     1726printk("\n[%s] thread[%x,%x] successfully checked ETH packet / cycle %d\n",
     1727__FUNCTION__, this->process->pid, this->trdid, cycle );
     1728#endif
    20781729            // analyse the IP header
    20791730            error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN,
     
    20841735
    20851736            // discard packet if error reported by IP layer
    2086             if( error ) continue;
     1737            if( error )
     1738            {
     1739
     1740#if DEBUG_DEV_NIC_RX
     1741cycle = (uint32_t)hal_get_cycles();
     1742if( DEBUG_DEV_NIC_RX < cycle )
     1743printk("\n[%s] thread[%x,%x] discarded IP packet / cycle %d\n",
     1744__FUNCTION__, this->process->pid, this->trdid, cycle );
     1745#endif
     1746                continue;
     1747            }
     1748
     1749#if (DEBUG_DEV_NIC_RX & 1 )
     1750cycle = (uint32_t)hal_get_cycles();
     1751if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_UDP) )
     1752printk("\n[%s] thread[%x,%x] successfully checked UDP packet / cycle %d\n",
     1753__FUNCTION__, this->process->pid, this->trdid, cycle );
     1754if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_TCP) )
     1755printk("\n[%s] thread[%x,%x] successfully checked TCP segment / cycle %d\n",
     1756__FUNCTION__, this->process->pid, this->trdid, cycle );
     1757#endif
    20871758
    20881759            // call relevant transport protocol
     
    21031774                                               pkt_dst_addr );
    21041775            }
     1776            else // discard packet if unsupported transport protocol
     1777            {
     1778 
     1779#if DEBUG_DEV_NIC_RX
     1780cycle = (uint32_t)hal_get_cycles();
     1781if( DEBUG_DEV_NIC_RX < cycle )
     1782printk("\n[%s] thread[%x,%x] discarded unsupported transport protocol %d\n",
     1783__FUNCTION__, this->process->pid, this->trdid, trsp_protocol, cycle );
     1784#endif
     1785                continue;
     1786            }
    21051787        }
    2106         else     // block and deschedule if NIC_RX_QUEUE empty
    2107         {
    2108             thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_ISR );
    2109             sched_yield( "waiting RX client" );
    2110         }
    2111 
    21121788    } // end of while loop
    2113 
    21141789}  // end dev_nic_rx_server()
    21151790
     
    21171792
    21181793
    2119 
    2120 
    2121 
    2122 
    2123 
    2124 
    21251794///////////////////////////////////////////////////////////////////////////////////////////
    21261795//              Functions used by the NIC_TX server thread
    21271796///////////////////////////////////////////////////////////////////////////////////////////
    21281797
    2129 
    2130 ///////////////////////////////////////////////////////////////////////////////////////////
    2131 // These static functions are called by the NIC_TX server thread to report the
    2132 // completion  (success or error) of a TX command.
    2133 // - it print an error message in case of error.
    2134 // - it updates the "tx_error"  field in socket descriptor.
    2135 // - it unblocks the client thread.
    2136 ///////////////////////////////////////////////////////////////////////////////////////////
    2137 // @ socket_xp    : [in] extended pointer on socket
    2138 // @ cmd_type     : [in] SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE
    2139 // @ socket_state : [in] current socket state
    2140 ///////////////////////////////////////////////////////////////////////////////////////////
    2141 static void dev_nic_tx_report_error( xptr_t    socket_xp,
    2142                                      uint32_t  cmd_type,
    2143                                      uint32_t  socket_state )
    2144 {
    2145     printk("\n[ERROR] in %s : command %s in %s state\n",
    2146     __FUNCTION__, socket_cmd_str(cmd_type), socket_state_str(socket_state) );
    2147 
    2148     // get socket thread cluster and local pointer
    2149     socket_t * socket_ptr = GET_PTR( socket_xp );
    2150     cxy_t      socket_cxy = GET_CXY( socket_xp );
    2151 
    2152     // set tx_error field in socket descriptor
    2153     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 1 );
    2154 
    2155     // get extended point on client thread
    2156     xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
    2157 
    2158     // unblock the client thread
    2159     thread_unblock( client_xp , THREAD_BLOCKED_IO );
    2160 }
    2161 
    2162 ////////////////////////////////////////////////////////////
    2163 static void dev_nic_tx_report_success( xptr_t    socket_xp )
    2164 {
    2165     // get socket thread cluster and local pointer
    2166     socket_t * socket_ptr = GET_PTR( socket_xp );
    2167     cxy_t      socket_cxy = GET_CXY( socket_xp );
    2168 
    2169     // set tx_error field in socket descriptor
    2170     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 0 );
    2171 
    2172     // get extended point on client thread
    2173     xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
    2174 
    2175     // unblock the client thread
    2176     thread_unblock( client_xp , THREAD_BLOCKED_IO );
    2177 }
    2178 
    2179 
    2180 
    2181 
    2182 
    2183 ///////////////////////////////////////////////////////////////////////////////////////////
    2184 // This static function is called by the dev_nic_tx_server() function.
    2185 // It calls directly the NIC driver (WRITABLE command) and returns the status
    2186 // of the NIC_TX queue identified by the <chdev> argument.
    2187 // in the <writable> buffer.
    2188 ///////////////////////////////////////////////////////////////////////////////////////////
    2189 // @ chdev     : [in]  local pointer on NIC_TX chdev.
    2190 // @ length    : [in]  packet length in bytes.
    2191 // @ writable  : [out] zero if queue full. 
    2192 // @ returns 0 if success / returns -1 if failure in accessing NIC device.
    2193 ///////////////////////////////////////////////////////////////////////////////////////////
    2194 error_t dev_nic_tx_queue_writable( chdev_t  * chdev,
    2195                                    uint32_t   length,
    2196                                    uint32_t * writable )
    2197 {
    2198     thread_t * this = CURRENT_THREAD;
    2199 
    2200     // initialize READABLE command in thread descriptor
    2201     this->nic_cmd.dev_xp = XPTR( local_cxy , chdev );
    2202     this->nic_cmd.type   = NIC_CMD_WRITABLE;
    2203     this->nic_cmd.length = length;
    2204 
    2205     // call driver to test writable
    2206     chdev->cmd( XPTR( local_cxy , this ) );
    2207 
    2208     // return status
    2209     *writable = this->nic_cmd.status;
    2210 
    2211     // return error
    2212     return this->nic_cmd.error;
    2213 
    2214 }  // end dev_nic_tx_queue_writable
    2215 
    2216 ///////////////////////////////////////////////////////////////////////////////////////////
    2217 // This static function is called by the dev_nic_tx_server() function.
     1798///////////////////////////////////////////////////////////////////////////////////////////
     1799// This static function is called by the dev_nic_tx_build_packet() function.
    22181800// It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and
    22191801// <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument.
    2220 // It calls directly the NIC driver, without registering in a waiting queue, because
    2221 // only this NIC_TX server thread can access this NIC_TX_QUEUE.
    2222 // 1) It checks NIC_TX_QUEUE status in a while loop, using the NIC_CMD_WRITABLE command.
    2223 //    As long as the queue is not writable, it blocks and deschedules. It is re-activated
    2224 //    by the NIC-TX ISR as soon as the queue changes status.
    2225 // 2) When the queue is writable, it put the ETH/IP/UDP packet into the NIC_TX_QUEUE,
    2226 //   using the driver NIC_CMD_WRITE command.
    2227 // Both commands are successively registered in this NIC-TX server thread descriptor
    2228 // to be passed to the driver.
     1802// It blocks and deschedules on the BLOCKED_ISR condition if the queue is full.
    22291803///////////////////////////////////////////////////////////////////////////////////////////
    22301804// @ chdev   : [in] local pointer on NIC_TX chdev.
    2231 // @ buffer  : [in] pointer on a local kernel buffer (2K bytes).
     1805// @ k_buf   : [in] pointer on a local kernel buffer (2K bytes).
    22321806// @ length  : [in] actual Ethernet packet length in bytes.
    22331807///////////////////////////////////////////////////////////////////////////////////////////
    2234 void dev_nic_tx_move_packet( chdev_t  * chdev,
    2235                              uint8_t  * buffer,
    2236                              uint32_t   length )
     1808static void dev_nic_tx_move_packet( chdev_t  * chdev,
     1809                                    uint8_t  * k_buf,
     1810                                    uint32_t   length )
    22371811{
    2238     error_t    error;
    2239     uint32_t   writable;
    2240 
    22411812    thread_t * this = CURRENT_THREAD;
    22421813
     
    22451816    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
    22461817
    2247     // get local pointer on core running this server thead
    2248     core_t * core = this->core;
    2249 
    22501818// check thread can yield
    2251 assert( (this->busylocks == 0),
    2252 "cannot yield : busylocks = %d\n", this->busylocks );
    2253 
    2254 #if DEBUG_DEV_NIC_RX
     1819thread_assert_can_yield( this , __FUNCTION__ );
     1820
     1821#if (DEBUG_DEV_NIC_TX & 1)
    22551822uint32_t cycle = (uint32_t)hal_get_cycles();
    2256 if( DEBUG_DEV_NIC_RX < cycle )
    2257 printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n",
    2258 __FUNCTION__, this->process->pid, this->trdid, pkd, cycle );
    2259 #endif
    2260 
    2261     // check NIC_TX_QUEUE writable
    2262     while( 1 )
    2263     {
    2264         error = dev_nic_tx_queue_writable( chdev,
    2265                                            length,
    2266                                            &writable );
    2267         if( error )
    2268         {
    2269             printk("\n[PANIC] in %s : cannot access NIC_TX queue\n", __FUNCTION__ );
    2270             return;
    2271         }
    2272            
    2273         if( writable == 0 )  // block & deschedule if non writable
    2274         {
    2275             // enable NIC-TX IRQ
    2276             dev_pic_enable_irq( core->lid , chdev_xp );
    2277 
    2278             // block TX server thread
    2279             thread_block( thread_xp , THREAD_BLOCKED_ISR );
    2280 
    2281             // deschedule TX server thread
    2282             sched_yield("client blocked on NIC_TX queue full");
    2283 
    2284             // disable NIC-TX IRQ
    2285             dev_pic_disable_irq( core->lid , chdev_xp );
    2286         }
    2287         else                // exit loop if writable
    2288         {
    2289             break;
    2290         }
    2291     }
     1823if( DEBUG_DEV_NIC_TX < cycle )
     1824printk("\n[%s] thread[%x,%x] enter / buf %x / length %d / cycle %d\n",
     1825__FUNCTION__, this->process->pid, this->trdid, k_buf, length, cycle );
     1826#endif
    22921827
    22931828    // initialize WRITE command in server thread descriptor
    22941829    this->nic_cmd.dev_xp = chdev_xp;
    22951830    this->nic_cmd.type   = NIC_CMD_WRITE;
    2296     this->nic_cmd.buffer = buffer;
     1831    this->nic_cmd.buffer = k_buf;
    22971832    this->nic_cmd.length = length;
    22981833
    2299     // call driver to move packet
    2300     chdev->cmd( thread_xp );
    2301 
    2302 #if DEBUG_DEV_NIC_RX
     1834    while( 1 )
     1835    {
     1836        // call driver to move TX packet
     1837        chdev->cmd( thread_xp );
     1838
     1839        // exit while if success
     1840        if( this->nic_cmd.status == length )    // exit while & return if success
     1841        {
     1842
     1843#if (DEBUG_DEV_NIC_TX & 1)
    23031844cycle = (uint32_t)hal_get_cycles();
    2304 if( DEBUG_DEV_NIC_RX < cycle )
    2305 printk("\n[%s] thread[%x,%x] exit for packet %x\n",
    2306 __FUNCTION__ , this->process->pid, this->trdid , pkd );
    2307 #endif
    2308 
    2309     return;
    2310 
     1845if( DEBUG_DEV_NIC_TX < cycle )
     1846printk("\n[%s] thread[%x,%x] exit SUCCESS / cycle %d\n",
     1847__FUNCTION__, this->process->pid, this->trdid, cycle );
     1848#endif
     1849           break;
     1850        }
     1851        else                                    // block and deschedule if queue full
     1852        {
     1853
     1854#if (DEBUG_DEV_NIC_TX & 1)
     1855cycle = (uint32_t)hal_get_cycles();
     1856if( DEBUG_DEV_NIC_TX < cycle )
     1857printk("\n[%s] thread[%x,%x] NIC_TX_QUEUE full => blocks on ISR / cycle %d\n",
     1858__FUNCTION__, this->process->pid, this->trdid, cycle );
     1859#endif
     1860            // enable NIC_TX IRQ
     1861            dev_pic_enable_irq( this->core->lid , chdev_xp );
     1862
     1863            // TX server thread blocks and deschedules
     1864            thread_block( thread_xp , THREAD_BLOCKED_ISR );
     1865            sched_yield("client blocked on NIC_TX queue full");
     1866
     1867            // disable NIC-TX IRQ
     1868            dev_pic_disable_irq( this->core->lid , chdev_xp );
     1869
     1870#if (DEBUG_DEV_NIC_TX & 1)
     1871cycle = (uint32_t)hal_get_cycles();
     1872if( DEBUG_DEV_NIC_TX < cycle )
     1873printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
     1874__FUNCTION__, this->process->pid, this->trdid, cycle );
     1875#endif
     1876        }
     1877    }
    23111878}  // end dev_nic_tx_move_packet()
    23121879
     
    23221889// @ length     : [in]  number of bytes in payload.
    23231890///////////////////////////////////////////////////////////////////////////////////////////
    2324 void dev_nic_tx_build_udp_header( uint8_t  * k_buf,
    2325                                   xptr_t     socket_xp,
    2326                                   uint32_t   length )
     1891static void dev_nic_tx_build_udp_header( uint8_t  * k_buf,
     1892                                         xptr_t     socket_xp,
     1893                                         uint32_t   length )
    23271894{
    23281895    uint16_t   checksum;        // checksum value
     
    23751942///////////////////////////////////////////////////////////////////////////////////////////
    23761943// @ k_buf      : [in]  pointer on first byte of TCP header in kernel buffer.
     1944// @ socket_xp  : [in]  extended pointer on socket.
    23771945// @ length     : [in]  number of bytes in payload.
    2378 // @ socket_xp  : [in]  extended pointer on socket.
    23791946// @ flags      : [in]  flags to be set in TCP header.
    23801947///////////////////////////////////////////////////////////////////////////////////////////
    2381 void dev_nic_tx_build_tcp_header( uint8_t  * k_buf,
    2382                                   uint32_t   length,
    2383                                   xptr_t     socket_xp,
    2384                                   uint8_t    flags )
     1948static void dev_nic_tx_build_tcp_header( uint8_t  * k_buf,
     1949                                         xptr_t     socket_xp,
     1950                                         uint32_t   length,
     1951                                         uint8_t    flags )
    23851952{
    23861953    uint16_t   checksum;        // global segment checksum
     
    23921959    uint32_t   seq_num;         // first byte of segment in TX stream
    23931960    uint32_t   ack_num;         // next expected byte in RX stream
    2394     uint16_t   window;          // window of accepted segments in RX stream
     1961    uint32_t   window;          // window of accepted segments in RX stream
    23951962
    23961963    // get socket cluster an local pointer
     
    24672034// @ length     : number of bytes in IP packet payload.
    24682035///////////////////////////////////////////////////////////////////////////////////////////
    2469 void dev_nic_tx_build_ip_header( uint8_t * buffer,
    2470                                  uint32_t  src_addr,
    2471                                  uint32_t  dst_addr,
    2472                                  uint16_t  length )
     2036static void dev_nic_tx_build_ip_header( uint8_t * buffer,
     2037                                        uint32_t  src_addr,
     2038                                        uint32_t  dst_addr,
     2039                                        uint8_t   protocol,
     2040                                        uint16_t  length )
    24732041{
    24742042    uint16_t   hcs;
     
    24872055
    24882056    buffer[8]  = 0xFF;         // TTL
    2489     buffer[9]  = 0x11;         // UDP protocol
     2057    buffer[9]  = protocol;     // transport protocol
    24902058   
    24912059    buffer[12] = src_addr >> 24;
     
    25212089// @ length     : number of bytes in Ethernet frame payload.
    25222090///////////////////////////////////////////////////////////////////////////////////////////
    2523 void dev_nic_tx_build_eth_header( uint8_t * buffer,
    2524                                   uint16_t  src_mac_54,
    2525                                   uint16_t  src_mac_32,
    2526                                   uint16_t  src_mac_10,
    2527                                   uint16_t  dst_mac_54,
    2528                                   uint16_t  dst_mac_32,
    2529                                   uint16_t  dst_mac_10,
    2530                                   uint32_t  length )
     2091static void dev_nic_tx_build_eth_header( uint8_t * buffer,
     2092                                         uint8_t   src_mac_5,
     2093                                         uint8_t   src_mac_4,
     2094                                         uint8_t   src_mac_3,
     2095                                         uint8_t   src_mac_2,
     2096                                         uint8_t   src_mac_1,
     2097                                         uint8_t   src_mac_0,
     2098                                         uint8_t   dst_mac_5,
     2099                                         uint8_t   dst_mac_4,
     2100                                         uint8_t   dst_mac_3,
     2101                                         uint8_t   dst_mac_2,
     2102                                         uint8_t   dst_mac_1,
     2103                                         uint8_t   dst_mac_0,
     2104                                         uint32_t  length )
    25312105{
    2532     buffer[0]  = dst_mac_54 >> 8;
    2533     buffer[1]  = dst_mac_54;
    2534     buffer[2]  = dst_mac_32 >> 8;
    2535     buffer[3]  = dst_mac_32;
    2536     buffer[4]  = dst_mac_10 >> 8;
    2537     buffer[5]  = dst_mac_10;
    2538 
    2539     buffer[6]  = src_mac_54 >> 8;
    2540     buffer[7]  = src_mac_54;
    2541     buffer[8]  = src_mac_32 >> 8;
    2542     buffer[9]  = src_mac_32;
    2543     buffer[10] = src_mac_10 >> 8;
    2544     buffer[11] = src_mac_10;
     2106    buffer[0]  = dst_mac_5;
     2107    buffer[1]  = dst_mac_4;
     2108    buffer[2]  = dst_mac_3;
     2109    buffer[3]  = dst_mac_2;
     2110    buffer[4]  = dst_mac_1;
     2111    buffer[5]  = dst_mac_0;
     2112
     2113    buffer[6]  = src_mac_5;
     2114    buffer[7]  = src_mac_4;
     2115    buffer[8]  = src_mac_3;
     2116    buffer[9]  = src_mac_2;
     2117    buffer[10] = src_mac_1;
     2118    buffer[11] = src_mac_0;
    25452119
    25462120    buffer[12] = length >> 8;
     
    25502124
    25512125///////////////////////////////////////////////////////////////////////////////////////////
    2552 // This static function is called by the dev_nic_tx_server() function to handle one
    2553 // TX command, or one R2T request, registered in the socket identified by the <socket_xp>
    2554 // argument. If there is one valid command, or if the R2T queue is non empty (for a TCP
    2555 // socket), it builds an ETH/IP/UDP packet (or a ETH/IP/TCP segment), in the buffer
    2556 // defined by the  <k_buf> argument, and registers it in the NIC_TX queue defined by the
    2557 // <chdev> argument. The supported commands are SOCKET_SEND/SOCKET_CONNECT/SOCKET_CLOSE.
    2558 // It unblocks the client thread when the command is completed.
    2559 ///////////////////////////////////////////////////////////////////////////////////////////
    2560 // When there is a packet to send, it makes the following actions:
     2126// This static function is called by the dev_nic_tx_server() function to handle one TX
     2127// command, or one R2T request, as defined by the <cmd_valid> and <r2t_valid> arguments,
     2128// for the socket identified by the <socket_xp> argument. It builds an ETH/IP/UDP packet
     2129// or ETH/IP/TCP segment, in the buffer defined by the <k_buf> argument, and registers
     2130// it in the NIC_TX queue defined by the <chdev> argument.
     2131// For a TCP header, the "seq_num", ack_num", and "window" fiels are defined by the
     2132// "socket.tx_next", "socket.rx_next" and "socket.rx_wnd" fields respectively.
     2133// It updates the "socket.state", "socket.tx_nxt", "socket.r2tq", and "socket.crqq"
     2134// The supported TX command types are CONNECT / ACCEPT / SEND / CLOSE.
     2135// fields as required by the command type.
     2136// - For an UDP socket, it reset the "socket.tx_valid" field, and unblock the client
     2137//   thread when the packet has been sent, or when an error must be reported.
     2138// - For a TCP socket, it reset the "socket.tx_valid" field when the segment has been
     2139//   sent, but does not unblocks the client thread, that will be unblocqued by the
     2140//   NIC_RX thread when the TX command is fully completed.
     2141///////////////////////////////////////////////////////////////////////////////////////////
     2142// To build a packet, it makes the following actions:
    25612143// 1) it takes the lock protecting the socket state.
    2562 // 2) it get the command arguments from client thread descriptor.
    2563 // 3) it build an UDP packet or a TCP segment, depending on both the command type, and
    2564 //    the socket state, updates the socket state, and unblocks the client thread.
    2565 // 4) it release the lock protecting the socket.
    2566 // 5) it build the IP header.
    2567 // 6) it build the ETH header.
    2568 // 7) it copies the packet in the NIC_TX queue.
    2569 ///////////////////////////////////////////////////////////////////////////////////////////
     2144// 2) it get the command arguments from socket descriptor.
     2145// 3) it build an UDP packet or a TCP segment, depending on command type and socket state.
     2146// 4) it updates the socket state.
     2147// 5) it releases the lock protecting the socket.
     2148// 6) it build the IP header.
     2149// 7) it build the ETH header.
     2150// 8) it copies the packet in the NIC_TX queue.
     2151///////////////////////////////////////////////////////////////////////////////////////////
     2152// @ cmd_state   : [in] TX command valid in socket descriptor.
     2153// @ r2t_valid   : [in] R2T request valid in command descriptor.
    25702154// @ socket_xp   : [in] extended pointer on client socket. 
    25712155// @ k_buf       : [in] local pointer on kernel buffer (2 Kbytes).
    25722156// @ chdev       : [in] local pointer on NIC_RX chdev.
    25732157///////////////////////////////////////////////////////////////////////////////////////////
    2574 static void dev_nic_tx_handle_one_cmd( xptr_t    socket_xp,
    2575                                        uint8_t * k_buf,
    2576                                        chdev_t * chdev )
     2158static void dev_nic_tx_build_packet( bool_t    cmd_valid,
     2159                                     bool_t    r2t_valid,
     2160                                     xptr_t    socket_xp,
     2161                                     uint8_t * k_buf,
     2162                                     chdev_t * chdev )
    25772163{
    25782164    socket_t  * socket_ptr;
    25792165    cxy_t       socket_cxy;
    25802166    xptr_t      client_xp;       // extended pointer on client thread 
    2581     thread_t  * client_ptr;
    2582     cxy_t       client_cxy;
    2583     sock_cmd_t  cmd;             // NIC command type
    2584     uint8_t   * buf;             // pointer on user buffer
    2585     uint32_t    len;             // user buffer length
     2167    uint32_t    cmd_type;        // NIC command type
     2168    uint8_t   * tx_buf;          // local pointer on kernel buffer for payload
     2169    uint32_t    len;             // tx_buf length (bytes)
    25862170    uint32_t    todo;            // number of bytes not yet sent
    25872171    uint32_t    socket_type;     // socket type (UDP/TCP)
     
    25912175    uint32_t    src_ip_addr;     // source IP address
    25922176    uint32_t    dst_ip_addr;     // destination IP address
    2593     uint32_t    tx_una;          // next byte to be sent
    2594     uint32_t    tx_nxt;          // first unacknowledged byte
     2177    uint32_t    tx_nxt;          // next sequence number in TX stream
    25952178    uint32_t    nbytes;          // number of bytes in UDP/TCP packet payload
    2596     uint8_t   * k_base;          // pointer UDP/TCP packet in kernel buffer
     2179    uint8_t   * k_trsp_base;     // pointer on UDP/TCP packet in kernel buffer
    25972180    uint32_t    trsp_length;     // length of TCP/UDP packet
     2181    uint8_t     trsp_protocol;   // transport protocol type (UDP/TCP)
    25982182    uint8_t     r2t_flags;       // flags defined by one R2T queue request
    25992183    bool_t      do_send;         // build & send a packet when true
     
    26022186    socket_cxy = GET_CXY( socket_xp );
    26032187    socket_ptr = GET_PTR( socket_xp );
    2604    
    2605     // build extended pointer on socket lock and r2t queue
    2606     socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );
     2188
     2189#if DEBUG_DEV_NIC_TX
     2190thread_t * this = CURRENT_THREAD;;
     2191uint32_t   cycle = (uint32_t)hal_get_cycles();
     2192uint32_t   fdid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
     2193uint32_t   pid   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     2194if( cycle > DEBUG_DEV_NIC_TX )
     2195printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] : cmd_valid %d / r2t_valid %d / cycle %d\n",
     2196__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
     2197#endif
     2198
     2199    // build extended pointers on socket lock and r2t queue
     2200    socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );   
    26072201    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
    26082202
    26092203    // 1. take lock protecting this socket
    2610     remote_rwlock_wr_acquire( socket_lock_xp );
    2611 
    2612     // get pointers on TX client thread from socket
    2613     client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
    2614     client_cxy = GET_CXY( client_xp );
    2615     client_ptr = GET_PTR( client_xp );
    2616 
    2617     // check valid command
    2618     if( client_xp != XPTR_NULL )   // valid command found
     2204    remote_queuelock_acquire( socket_lock_xp );
     2205
     2206    // get relevant socket infos
     2207    socket_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->type ));
     2208    socket_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
     2209    src_ip_addr  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->local_addr ));
     2210    dst_ip_addr  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->remote_addr ));
     2211
     2212    // compute UDP/TCP packet base in kernel buffer
     2213    k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
     2214
     2215    // set default values
     2216    do_send     = false;
     2217    trsp_length = 0;
     2218    nbytes      = 0;
     2219
     2220    if( cmd_valid )  // handle TX command
    26192221    {
    26202222        // 2. get command arguments from socket
    2621         cmd  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_cmd ));
    2622         buf  = hal_remote_lpt( XPTR(socket_cxy , &socket_ptr->tx_buf ));
    2623         len  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_len ));
    2624         todo = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_todo ));
     2223        cmd_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
     2224        tx_buf    = hal_remote_lpt( XPTR( socket_cxy , &socket_ptr->tx_buf ));
     2225        len       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_len ));
     2226        todo      = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_todo ));
     2227        client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
    26252228       
    2626         // get socket type and state
    2627         socket_type  = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->type ));
    2628         socket_state = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->state ));
    2629 
     2229#if DEBUG_DEV_NIC_TX
     2230cycle = (uint32_t)hal_get_cycles();
     2231if( cycle > DEBUG_DEV_NIC_TX )
     2232printk("\n[%s] thread[%x,%x] cmd_valid for socket[%x,%d] : %s / %s / cycle %d\n",
     2233__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2234socket_cmd_type_str(cmd_type), socket_state_str(socket_state), cycle );
     2235#endif
     2236
     2237        //////////////////////////////////////////////////////////
    26302238        // 3. UDP : build UDP packet and update UDP socket state
    26312239        if( socket_type == SOCK_DGRAM )       
    26322240        {
    2633             if( socket_state == UDP_STATE_UNBOUND )
     2241            trsp_protocol = PROTOCOL_UDP;
     2242
     2243            if( socket_state != UDP_STATE_ESTAB )
    26342244            {
    2635                 // report illegal command
    2636                 dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2637 
    2638                 do_send = false;
     2245                // reset tx_valid
     2246                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
     2247
     2248                // unblock client thread / report error
     2249                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
    26392250            }
    2640             else  // BOUND or CONNECT state
     2251            else
    26412252            {
    2642                 if( cmd == SOCKET_TX_SEND )
     2253                if( cmd_type == CMD_TX_SEND )
    26432254                {
    26442255                    // compute payload length
    26452256                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
    26462257
    2647                     // compute UDP packet base in kernel buffer
    2648                     k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
    2649 
    2650                     // move payload to kernel buffer
    2651                     hal_copy_from_uspace( XPTR(local_cxy , k_base + UDP_HEAD_LEN ),
    2652                                           buf + (len - todo),
    2653                                           nbytes );
     2258                    // move payload from tx_buf to 2 Kbytes kernel buffer
     2259                    memcpy( k_trsp_base + UDP_HEAD_LEN,
     2260                            tx_buf + (len - todo),
     2261                            nbytes );
     2262
    26542263                    // build UDP header
    2655                     dev_nic_tx_build_udp_header( k_base,
     2264                    dev_nic_tx_build_udp_header( k_trsp_base,
    26562265                                                 socket_xp,
    26572266                                                 nbytes );
    26582267
    26592268                    // update "tx_todo" in socket descriptor
    2660                     hal_remote_s32( XPTR(socket_cxy , socket_ptr->tx_todo),
    2661                                     todo - nbytes );
    2662 
    2663                     // unblock client thread when SEND command completed
    2664                     if( nbytes == todo )
     2269                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
     2270
     2271                    // send UDP packet
     2272                    trsp_length = UDP_HEAD_LEN + nbytes;
     2273                    do_send     = true;
     2274
     2275#if( DEBUG_DEV_NIC_TX & 1)
     2276cycle = (uint32_t)hal_get_cycles();
     2277if( cycle > DEBUG_DEV_NIC_TX )
     2278printk("\n[%s] thread[%x,%x] socket[%x,%d] UDP packet build / length %d / cycle %d\n",
     2279__FUNCTION__, this->process->pid, this->trdid, trsp_length , cycle );
     2280#endif
     2281                    if( nbytes == todo )    // last byte sent
    26652282                    {
    2666                         dev_nic_tx_report_success( socket_xp );
     2283                        // reset tx_valid
     2284                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
     2285
     2286                        // report success to TX client
     2287                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
    26672288                    }
    2668 
    2669                     do_send = true;
    2670                 }
    2671                 else
    2672                 {
    2673                     // report illegal command
    2674                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2675 
    2676                     do_send = false;
     2289                }
     2290                else // CONNECT, ACCEPT, or CLOSE commands are illegal for UDP
     2291                {
     2292                    // reset tx_valid
     2293                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
     2294
     2295                    // report error
     2296                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
    26772297                }
    26782298            }
    2679 
    2680             // compute transport packet length
    2681             trsp_length = UDP_HEAD_LEN + nbytes;
    2682 
    26832299        }  // end UDP
    26842300
     2301        ///////////////////////////////////////////////////////////
    26852302        // 3. TCP : build TCP segment and update TCP socket state
    2686         if( socket_type == SOCK_STREAM )
     2303        else if( socket_type == SOCK_STREAM )
    26872304        {
    2688             // extract one request from TCP socket R2T queue if queue non empty
    2689             if( remote_buf_status( socket_r2tq_xp ) )
     2305            trsp_protocol = PROTOCOL_TCP;
     2306
     2307            // handle R2T request / initialize r2t_flags
     2308            if( r2t_valid )
    26902309            {
     2310                // build extended pointers on r2t queue
     2311                socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
     2312       
     2313                // get one request from R2T queue
    26912314                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
    26922315            }
     
    26962319            }
    26972320
     2321            ////////////////////////////////
     2322            if( cmd_type == CMD_TX_CONNECT )  // always executed by a TCP client
     2323            {
     2324                if( (socket_state == TCP_STATE_BOUND) ||
     2325                    (socket_state == TCP_STATE_LISTEN) )  // send a SYN segment
     2326                {
     2327                    // initialises socket tx_nxt, and rx_wnd
     2328                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_CLIENT );
     2329                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), TCP_MAX_WINDOW );
     2330
     2331                    // build TCP SYN segment
     2332                    dev_nic_tx_build_tcp_header( k_trsp_base,
     2333                                                 socket_xp,
     2334                                                 0,        // length
     2335                                                 TCP_FLAG_SYN );   
     2336                    // send segment
     2337                    trsp_length = TCP_HEAD_LEN;
     2338                    do_send     = true;
     2339
     2340#if DEBUG_DEV_NIC_TX
     2341cycle = (uint32_t)hal_get_cycles();
     2342if( cycle > DEBUG_DEV_NIC_TX )
     2343printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CONNECT / "
     2344"TCP SYN build / cycle %d\n",
     2345__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2346socket_state_str( socket_state ), cycle );
     2347#endif
     2348                    // update socket.state
     2349                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2350                                          TCP_STATE_SYN_SENT );
     2351
     2352                    // update socket.tx_nxt
     2353                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     2354                                          TCP_ISS_CLIENT + 1 );
     2355
     2356                    // reset tx_valid but do not unblock client thread
     2357                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2358                }
     2359                else                      // report error for all other socket states
     2360                {
     2361                    // reset tx_valid
     2362                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
     2363                   
     2364                    // report error
     2365                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
     2366                }
     2367            }
     2368            ////////////////////////////////////
     2369            else if( cmd_type == CMD_TX_ACCEPT )   // always executed by a TCP server
     2370            {
     2371
     2372                if( socket_state == TCP_STATE_SYN_RCVD )  // send a SYN-ACK segment
     2373                {
     2374                    // initialize socket tx_nxt, and rx_wnd
     2375                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
     2376                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), NIC_RX_BUF_SIZE);
     2377               
     2378                    // build TCP ACK-SYN segment
     2379                    dev_nic_tx_build_tcp_header( k_trsp_base,
     2380                                                 socket_xp,
     2381                                                 0,         //  length
     2382                                                 TCP_FLAG_SYN | TCP_FLAG_ACK );
     2383                    // send segment
     2384                    trsp_length = TCP_HEAD_LEN;
     2385                    do_send     = true;
     2386
     2387#if DEBUG_DEV_NIC_TX
     2388cycle = (uint32_t)hal_get_cycles();
     2389if( cycle > DEBUG_DEV_NIC_TX )
     2390printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / ACCEPT / send SYN-ACK / cycle %d\n",
     2391__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2392socket_state_str( socket_state ), cycle );
     2393#endif
     2394                    // update socket.state
     2395                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     2396                                          TCP_STATE_SYN_RCVD );
     2397
     2398                    // update socket.tx_nxt
     2399                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
     2400                                          TCP_ISS_SERVER + 1 );
     2401
     2402                    // reset tx_valid but do not unblock client thread
     2403                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2404                }
     2405                else                     // report error in all other socket states
     2406                {
     2407                    // reset tx_valid
     2408                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2409
     2410                    // report error to TX client thread
     2411                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
     2412                }
     2413            }
     2414            ///////////////////////////////////
     2415            else if( cmd_type == CMD_TX_CLOSE )
     2416            {
     2417                if( (socket_state == TCP_STATE_SYN_RCVD  ) ||
     2418                    (socket_state == TCP_STATE_ESTAB     ) ||
     2419                    (socket_state == TCP_STATE_CLOSE_WAIT) )   // send a FIN-ACK segment
     2420                {
     2421                    // get  "tx_nxt" from socket descriptor
     2422                    tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt ));
     2423
     2424                    // compute next state
     2425                    uint32_t state = (socket_state == TCP_STATE_CLOSE_WAIT) ?
     2426                                     TCP_STATE_LAST_ACK : TCP_STATE_FIN_WAIT1;
     2427
     2428                    // update socket state
     2429                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), state );
     2430
     2431                    // build TCP FIN segment
     2432                    dev_nic_tx_build_tcp_header( k_trsp_base,
     2433                                                 socket_xp,
     2434                                                 0,         // length
     2435                                                 TCP_FLAG_FIN | TCP_FLAG_ACK );   
     2436
     2437                    // update "tx_nxt" in socket descriptor
     2438                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + 1 );
     2439
     2440                    // send segment
     2441                    trsp_length = TCP_HEAD_LEN;
     2442                    do_send     = true;
     2443
     2444#if DEBUG_DEV_NIC_TX
     2445cycle = (uint32_t)hal_get_cycles();
     2446if( cycle > DEBUG_DEV_NIC_TX )
     2447printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / send FIN-ACK / cycle %d\n",
     2448__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2449socket_state_str( socket_state ), cycle );
     2450#endif
     2451                    // reset tx_valid but do not unblock client thread
     2452                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2453                }
     2454                else                                 // all other states => signal error
     2455                {
     2456
     2457#if DEBUG_DEV_NIC_TX
     2458cycle = (uint32_t)hal_get_cycles();
     2459if( cycle > DEBUG_DEV_NIC_TX )
     2460printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / error BADSTATE / cycle %d\n",
     2461__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2462socket_state_str( socket_state ), cycle );
     2463#endif
     2464                    // reset tx_valid
     2465                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2466
     2467                    // report error
     2468                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
     2469                }
     2470            }
    26982471            /////////////////////////////////////
    2699             if( socket_state == TCP_STATE_ESTAB )    // connected TCP socket
     2472            else if( cmd_type == CMD_TX_SEND )
    27002473            {
    2701                 if( cmd == SOCKET_TX_SEND )         
    2702                 {
    2703                     // get  "tx_nxt", and "tx_una" from socket descriptor
     2474                if( (socket_state == TCP_STATE_ESTAB     ) ||
     2475                    (socket_state == TCP_STATE_CLOSE_WAIT) )
     2476                {
     2477                    // get  "tx_nxt" from socket descriptor
    27042478                    tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt ));
    2705                     tx_una = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_una ));
    27062479
    27072480                    // compute actual payload length
     
    27092482
    27102483                    // compute TCP segment base in kernel buffer
    2711                     k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
    2712 
    2713                     // move payload to kernel buffer
    2714                     hal_copy_from_uspace( XPTR( local_cxy , k_base + TCP_HEAD_LEN ),
    2715                                           buf + (len - todo),
    2716                                           nbytes );
     2484                    k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
     2485
     2486                    // move payload to k_buf
     2487                    memcpy( k_trsp_base + TCP_HEAD_LEN,
     2488                            tx_buf + (len - todo),
     2489                            nbytes );
    27172490
    27182491                    // build TCP header
    2719                     dev_nic_tx_build_tcp_header( k_base,
     2492                    dev_nic_tx_build_tcp_header( k_trsp_base,
    27202493                                                 socket_xp,
    27212494                                                 nbytes,                       // payload
     
    27232496
    27242497                    // update "tx_todo" in socket descriptor
    2725                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_todo ),
    2726                                     todo - nbytes );
     2498                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
    27272499
    27282500                    // update "tx_nxt" in socket descriptor
    2729                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    2730                                     tx_nxt + nbytes );
    2731 
    2732                     // unblock client thread when SEND command completed
    2733                     if( (todo == 0) && (tx_nxt == tx_una) )
     2501                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + nbytes );
     2502
     2503                    // send TCP segment
     2504                    trsp_length = TCP_HEAD_LEN + nbytes;
     2505                    do_send     = true;
     2506
     2507                    if( todo == nbytes )   // last byte sent
    27342508                    {
    2735                         dev_nic_tx_report_success( socket_xp );
     2509                        // reset tx_valid when last byte has been sent
     2510                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_valid), false );
    27362511                    }
    27372512
    2738                     do_send = true;
    2739                 }
    2740                 else if( cmd == SOCKET_TX_CLOSE )         
    2741                 {
    2742                     // build TCP FIN segment
    2743                     dev_nic_tx_build_tcp_header( k_base,
    2744                                                  socket_xp,
    2745                                                  0,                            // payload
    2746                                                  TCP_FLAG_FIN | r2t_flags );   // flags
    2747                     // update socket state
    2748                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2749                                     TCP_STATE_FIN_WAIT1 );
    2750 
    2751                     do_send = true;
    2752                 }
    2753                 else  // cmd == CONNECT
    2754                 {
    2755                     // report illegal command
    2756                     dev_nic_tx_report_error( socket_xp , cmd , socket_state );
    2757 
    2758                     do_send = false;
     2513#if DEBUG_DEV_NIC_TX
     2514cycle = (uint32_t)hal_get_cycles();
     2515if( cycle > DEBUG_DEV_NIC_TX )
     2516printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / SEND / "
     2517"TCP DATA build / payload %d / cycle %d\n",
     2518__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
     2519socket_state_str( socket_state ), nbytes, cycle );
     2520#endif
     2521                }
     2522                else  // all other socket states
     2523                {
     2524                    // reset tx_valid
     2525                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2526
     2527                    // report error to TX client thread
     2528                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
    27592529                }
    27602530            }
    2761             //////////////////////////////////////////
    2762             else if( socket_state == TCP_STATE_BOUND )  // unconnected TCP socket
     2531            ///////////////////////////////////
     2532            else  // undefined TX command type
    27632533            {
    2764                 if ( cmd == SOCKET_TX_CONNECT ) 
    2765                 {
    2766                     // set socket.tx_nxt
    2767                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
    2768                                      TCP_ISS  );
    2769                      
    2770                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 0 );
    2771                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
    2772                                     NIC_RX_BUF_SIZE);
    2773                                      
    2774                     // build TCP SYN segment
    2775                     dev_nic_tx_build_tcp_header( k_base,
    2776                                                   socket_xp,
    2777                                                   0,                // payload
    2778                                                   TCP_FLAG_SYN );   // flags
    2779                     // update socket state
    2780                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2781                                      TCP_STATE_SYN_SENT );
    2782 
    2783                     do_send = true;
    2784                 }
    2785                 else   // cmd == SEND / CLOSE
    2786                 {
    2787                     // report illegal command
    2788                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2789 
    2790                     do_send = false;
    2791                 }
     2534                // reset tx_valid
     2535                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
     2536
     2537                // report error to TX client thread
     2538                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
    27922539            }
    2793             ///////////////////////////////////////////
    2794             else if( socket_state == TCP_STATE_LISTEN )  // server wait connect
    2795             {
    2796                 if( cmd == SOCKET_TX_CONNECT )         
    2797                 {
    2798                     // update socket.state
    2799                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2800                                     TCP_STATE_SYN_SENT );
    2801                    
    2802                     // set socket.tx_una 
    2803                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
    2804                                     TCP_ISS );
    2805 
    2806                     // set socket.tx_nxt
    2807                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ),
    2808                                     TCP_ISS + 1 );
    2809 
    2810                     // build TCP SYN segment
    2811                     dev_nic_tx_build_tcp_header( k_base,
    2812                                                  socket_xp,
    2813                                                  0,                // payload
    2814                                                  TCP_FLAG_SYN );   // flags
    2815                     do_send = true;
    2816                 }
    2817                 else  // cmd == CLOSE / SEND
    2818                 {
    2819                     // report illegal command
    2820                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2821 
    2822                     do_send = false;
    2823                 }
    2824             }
    2825             /////////////////////////////////////////////
    2826             else if( socket_state == TCP_STATE_SYN_RCVD )  // socket wait ACK
    2827             {
    2828                 if( cmd == SOCKET_TX_CLOSE )         
    2829                 {
    2830                     // build TCP FIN segment
    2831                     dev_nic_tx_build_tcp_header( k_base,
    2832                                                  socket_xp,
    2833                                                  0,                // payload
    2834                                                  TCP_FLAG_FIN );   // flags
    2835                     // update socket state
    2836                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2837                                     TCP_STATE_FIN_WAIT1 );
    2838 
    2839                     do_send = true;
    2840                 }
    2841                 else  // SEND / CONNECT
    2842                 {
    2843                     // report illegal command
    2844                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2845 
    2846                     do_send = false;
    2847                 }
    2848             }
    2849             ////////////////////////////////////////////////
    2850             else if( socket_state == TCP_STATE_CLOSE_WAIT )  // wait local close()
    2851             {
    2852                 if( cmd == SOCKET_TX_CLOSE )         
    2853                 {
    2854                     // build TCP FIN segment
    2855                     dev_nic_tx_build_tcp_header( k_base,
    2856                                                  socket_xp,
    2857                                                  0,                // payload
    2858                                                  TCP_FLAG_FIN );   // flags
    2859                     // update socket state
    2860                     hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
    2861                                     TCP_STATE_LAST_ACK );
    2862 
    2863                     do_send = true;
    2864                 }
    2865                 else  // SEND / CONNECT
    2866                 {
    2867                     // report illegal command
    2868                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2869 
    2870                     do_send = false;
    2871                 }
    2872             }
    2873             ////
    2874             else
    2875             {
    2876                     // report illegal command
    2877                     dev_nic_tx_report_error( socket_xp, cmd, socket_state );
    2878 
    2879                     do_send = false;
    2880             }
    2881 
    2882             // compute TCP segment length
    2883             trsp_length = TCP_HEAD_LEN + nbytes;
    2884         }
    2885     } 
    2886     else                        // no valid command found
     2540        }  // end TCP
     2541    }
     2542    else         // no valid TX command => handle R2T request only
    28872543    {
    2888         if( socket_type == SOCK_DGRAM )    //  UDP socket
    2889         {
    2890             do_send = false;
    2891         }
    2892         else                               //  TCP socket
    2893         {
    2894             if( remote_buf_status( socket_r2tq_xp ) == 0 )  // R2T queue empty
    2895             {
    2896                 do_send = false;
    2897             }
    2898             else                                // pending request in R2T queue
    2899             {
    2900                 // get one request from R2T queue
    2901                 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
    2902 
    2903                 // build TCP header for an empty segment
    2904                 dev_nic_tx_build_tcp_header( k_base,
    2905                                              socket_xp,
    2906                                              0,             // payload
    2907                                              r2t_flags );   // flags
    2908                 do_send = true;
    2909             }         
    2910         }
     2544        // get one request from R2T queue
     2545        remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
     2546
     2547#if DEBUG_DEV_NIC_TX
     2548cycle = (uint32_t)hal_get_cycles();
     2549if( cycle > DEBUG_DEV_NIC_TX )
     2550printk("\n[%s] thread[%x,%x] only r2t_valid for socket[%x,%d] / flags %x / cycle %d\n",
     2551__FUNCTION__, this->process->pid, this->trdid, pid, fdid, r2t_flags, cycle );
     2552#endif
     2553
     2554        // build TCP header
     2555        dev_nic_tx_build_tcp_header( k_trsp_base,
     2556                                     socket_xp,
     2557                                     0,             // payload length
     2558                                     r2t_flags );   // flags
     2559        // send TCP segment
     2560        trsp_protocol = PROTOCOL_TCP;
     2561        trsp_length   = TCP_HEAD_LEN;
     2562        do_send       = true;
    29112563    }
    29122564
    29132565    // 4. release the lock protecting the socket
    2914     remote_rwlock_wr_release( socket_lock_xp );
     2566    remote_queuelock_release( socket_lock_xp );
    29152567
    29162568    // return if no packet to send
     
    29212573                                src_ip_addr,
    29222574                                dst_ip_addr,
    2923                                 IP_HEAD_LEN + trsp_length );
     2575                                trsp_protocol,
     2576                                trsp_length );
     2577
     2578#if( DEBUG_DEV_NIC_TX & 1)
     2579cycle = (uint32_t)hal_get_cycles();
     2580if( cycle > DEBUG_DEV_NIC_TX )
     2581printk("\n[%s] thread[%x,%x] IP header build / length %d / cycle %d\n",
     2582__FUNCTION__, this->process->pid, this->trdid, IP_HEAD_LEN + trsp_length , cycle );
     2583#endif
    29242584
    29252585    // 6. build ETH header
    29262586    dev_nic_tx_build_eth_header( k_buf,
    2927                                  (uint16_t)SRC_MAC_54,
    2928                                  (uint16_t)SRC_MAC_32,
    2929                                  (uint16_t)SRC_MAC_10,
    2930                                  (uint16_t)DST_MAC_54,
    2931                                  (uint16_t)DST_MAC_32,
    2932                                  (uint16_t)DST_MAC_10,
    2933                                  ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
    2934 
    2935     // 7. move packet to NIC_TX queue
     2587                                 (uint8_t)DST_MAC_5,
     2588                                 (uint8_t)DST_MAC_4,
     2589                                 (uint8_t)DST_MAC_3,
     2590                                 (uint8_t)DST_MAC_2,
     2591                                 (uint8_t)DST_MAC_1,
     2592                                 (uint8_t)DST_MAC_0,
     2593                                 (uint8_t)SRC_MAC_5,
     2594                                 (uint8_t)SRC_MAC_4,
     2595                                 (uint8_t)SRC_MAC_3,
     2596                                 (uint8_t)SRC_MAC_2,
     2597                                 (uint8_t)SRC_MAC_1,
     2598                                 (uint8_t)SRC_MAC_0,
     2599                                 IP_HEAD_LEN + trsp_length );
     2600
     2601#if( DEBUG_DEV_NIC_TX & 1)
     2602cycle = (uint32_t)hal_get_cycles();
     2603if( cycle > DEBUG_DEV_NIC_TX )
     2604printk("\n[%s] thread[%x,%x] ETH header build / cycle %d\n",
     2605__FUNCTION__, this->process->pid, this->trdid, cycle );
     2606#endif
     2607
     2608    // 7. move packet to NIC_TX queue (blocking function)
    29362609    dev_nic_tx_move_packet( chdev,
    29372610                            k_buf,
    29382611                            ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
    29392612
    2940 }  // end dev_nic_tx_handle_one_cmd()
     2613#if DEBUG_DEV_NIC_TX
     2614cycle = (uint32_t)hal_get_cycles();
     2615if( cycle > DEBUG_DEV_NIC_TX )
     2616printk("\n[%s] thread[%x,%x] for socket[%x,%d] moved packet to NIC_TX / cycle %d\n",
     2617__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cycle );
     2618#endif
     2619
     2620}  // end dev_nic_tx_build_packet()
     2621
    29412622
    29422623/////////////////////////////////////////
     
    29452626    uint8_t       k_buf[NIC_KERNEL_BUF_SIZE];  // buffer for one packet
    29462627
    2947     xptr_t        root_xp;         // extended pointer on clients list root
    2948     xptr_t        lock_xp;         // extended pointer on lock protecting this list
    2949     xptr_t        socket_xp;       // extended pointer on on client socket
     2628    xptr_t        queue_root_xp;       // extended pointer on sockets list root
     2629    xptr_t        queue_lock_xp;       // extended pointer on lock protecting this list
     2630    xptr_t        socket_xp;           // extended pointer on on registered socket
    29502631    socket_t    * socket_ptr;
    29512632    cxy_t         socket_cxy;
    2952     xptr_t        entry_xp;        // extended pointer on socket tx_list entry
     2633    xptr_t        iter_xp;             // iterator for loop on registered sockets
     2634    xlist_entry_t temp_root;           // root of temporary list of sockets
     2635    xptr_t        temp_root_xp;        // extended pointer on temporary list of sockets
     2636    uint32_t      temp_nr;             // number of active registered sockets
     2637    bool_t        cmd_valid;           // TX command valid in socket descriptor
     2638    bool_t        r2t_valid;           // valid R2T request in socket descriptor
    29532639
    29542640    thread_t * this = CURRENT_THREAD;
     2641
     2642#if DEBUG_DEV_NIC_TX
     2643uint32_t cycle = (uint32_t)hal_get_cycles();
     2644uint32_t pid;
     2645uint32_t fdid;
     2646if( cycle > DEBUG_DEV_NIC_TX )
     2647printk("\n[%s] thread[%x,%x] starts / cycle %d\n",
     2648__FUNCTION__, this->process->pid, this->trdid, cycle );
     2649#endif
    29552650
    29562651// check chdev direction and type
     
    29592654
    29602655// check thread can yield
    2961 assert( (this->busylocks == 0),
    2962 "cannot yield : busylocks = %d\n", this->busylocks );
    2963 
    2964     // build extended pointer on client sockets lock & root
    2965     lock_xp = XPTR( local_cxy , &chdev->wait_lock );
    2966     root_xp = XPTR( local_cxy , &chdev->wait_root );
     2656thread_assert_can_yield( this , __FUNCTION__ );
     2657
     2658    // build extended pointer on temporary list
     2659    temp_root_xp = XPTR( local_cxy , &temp_root );
     2660                                                         
     2661    // build extended pointer on client sockets queue (lock & root)
     2662    queue_lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     2663    queue_root_xp = XPTR( local_cxy , &chdev->wait_root );
    29672664
    29682665    while( 1 )  // TX server infinite loop
    29692666    {
     2667        // initialize temporary list of registered sockets as empty
     2668        xlist_root_init( temp_root_xp );
     2669        temp_nr = 0;
     2670
    29702671        // take the lock protecting the client sockets queue
    2971         remote_busylock_acquire( lock_xp );
    2972 
    2973         /////////////// block and deschedule if no clients
    2974         if( xlist_is_empty( root_xp ) == false )
     2672        remote_busylock_acquire( queue_lock_xp );
     2673
     2674        // build temporary list of all registered sockets
     2675        if( xlist_is_empty( queue_root_xp ) == false ) 
    29752676        {
    2976             // release the lock protecting the TX client sockets queue
    2977             remote_busylock_release( lock_xp );
     2677            XLIST_FOREACH( queue_root_xp , iter_xp )
     2678            {
     2679                // get client socket cluster and local pointer
     2680                socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_list );
     2681                socket_ptr = GET_PTR( socket_xp );
     2682                socket_cxy = GET_CXY( socket_xp );
     2683
     2684                // register socket in temporary list
     2685                xlist_add_last( temp_root_xp , XPTR( socket_cxy , &socket_ptr->tx_temp ));
     2686                temp_nr++;
     2687            }
     2688        }
     2689
     2690        // release the lock protecting the client sockets queue
     2691        remote_busylock_release( queue_lock_xp );
     2692
     2693        if( temp_nr > 0 )
     2694        {
     2695            // loop on temporary list
     2696            XLIST_FOREACH( temp_root_xp , iter_xp )
     2697            {
     2698                // get client socket cluster and local pointer
     2699                socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_temp );
     2700                socket_ptr = GET_PTR( socket_xp );
     2701                socket_cxy = GET_CXY( socket_xp );
     2702
     2703                // get cmd_valid & t2t_valid from socket descriptor
     2704                cmd_valid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_valid ));
     2705
     2706                // get r2t_valid from socket descriptor
     2707                r2t_valid = (bool_t)remote_buf_status( XPTR( socket_cxy , &socket_ptr->r2tq ));
     2708
     2709                // test if socket is active
     2710                if( cmd_valid || r2t_valid )  // active socket
     2711                {
     2712
     2713#if DEBUG_DEV_NIC_TX
     2714cycle = (uint32_t)hal_get_cycles();
     2715pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
     2716fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
     2717if( cycle > DEBUG_DEV_NIC_TX )
     2718printk("\n[%s] thread[%x,%x] found socket[%x,%d] / cmd_valid %d / r2t_valid %d / cycle %d\n",
     2719__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
     2720#endif
     2721                    // build and send one packet/segment for this socket
     2722                    dev_nic_tx_build_packet( cmd_valid,
     2723                                             r2t_valid,
     2724                                             socket_xp,
     2725                                             k_buf,
     2726                                             chdev );
     2727#if DEBUG_DEV_NIC_TX
     2728cycle = (uint32_t)hal_get_cycles();
     2729if( cycle > DEBUG_DEV_NIC_TX )
     2730dev_nic_packet_display( true,                // is_tx
     2731                        this->process->pid,
     2732                        this->trdid,
     2733                        cycle,
     2734                        k_buf );
     2735#endif
     2736                }
     2737                else                          // inactive socket
     2738                {
     2739                   temp_nr--;
     2740                }
     2741            }  // end loop on temporary list
     2742        }
     2743
     2744        // block & deschedule if no active socket found in current iteration
     2745        if( temp_nr == 0 )
     2746        {
    29782747 
     2748#if DEBUG_DEV_NIC_TX
     2749cycle = (uint32_t)hal_get_cycles();
     2750if( cycle > DEBUG_DEV_NIC_TX )
     2751printk("\n[%s] thread[%x,%x] no active socket => blocks on <CLIENT> / cycle %d\n",
     2752__FUNCTION__, this->process->pid, this->trdid, cycle );
     2753#endif
     2754
    29792755            // block and deschedule
    29802756            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT );
    29812757            sched_yield( "waiting client" );
     2758
     2759#if DEBUG_DEV_NIC_TX
     2760cycle = (uint32_t)hal_get_cycles();
     2761if( cycle > DEBUG_DEV_NIC_TX )
     2762printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
     2763__FUNCTION__, this->process->pid, this->trdid, cycle );
     2764#endif
    29822765        }
    2983         ////////////// 
    2984         else
    2985         {
    2986             // get first client socket
    2987             socket_xp  = XLIST_FIRST( root_xp , socket_t , tx_list );
    2988             socket_cxy = GET_CXY( socket_xp );
    2989             socket_ptr = GET_PTR( socket_xp );
    2990  
    2991             // build extended pointer on socket xlist_entry
    2992             entry_xp = XPTR( socket_cxy , &socket_ptr->tx_list );
    2993 
    2994             // remove this socket from the waiting queue
    2995             xlist_unlink( entry_xp );
    2996 
    2997             // release the lock protecting the client sockets queue
    2998             remote_busylock_release( lock_xp );
    2999 
    3000             // handle this TX client
    3001             dev_nic_tx_handle_one_cmd( socket_xp,
    3002                                        k_buf,
    3003                                        chdev );
    3004 
    3005             // take the lock protecting the client sockets queue
    3006             remote_busylock_acquire( lock_xp );
    3007 
    3008             // add this socket in last position of queue
    3009             xlist_add_last( root_xp , entry_xp );
    3010 
    3011             // release the lock protecting the client sockets queue
    3012             remote_busylock_release( lock_xp );
    3013         }
    3014     }   // end while
     2766    }   // end infinite while loop
    30152767}  // end dev_nic_tx_server()
    30162768
    30172769
     2770/////////////////////////////////////////////
     2771void dev_nic_packet_display( bool_t    is_tx,
     2772                             pid_t     thread_pid,
     2773                             trdid_t   thread_trdid,
     2774                             uint32_t  cycle,
     2775                             uint8_t * buf )
     2776{
     2777    // get ETH header fields
     2778    uint64_t eth_dst_mac = ((uint64_t)buf[5]  << 40) |
     2779                           ((uint64_t)buf[4]  << 32) |
     2780                           ((uint64_t)buf[3]  << 24) |
     2781                           ((uint64_t)buf[2]  << 16) |
     2782                           ((uint64_t)buf[1]  <<  8) |
     2783                           ((uint64_t)buf[0]       ) ;
     2784
     2785    uint64_t eth_src_mac = ((uint64_t)buf[11] << 40) |
     2786                           ((uint64_t)buf[10] << 32) |
     2787                           ((uint64_t)buf[9]  << 24) |
     2788                           ((uint64_t)buf[8]  << 16) |
     2789                           ((uint64_t)buf[7]  <<  8) |
     2790                           ((uint64_t)buf[6]       ) ;
     2791
     2792    uint16_t eth_length  = ((uint16_t)buf[12] <<  8) |
     2793                           ((uint16_t)buf[13]      ) ;
     2794
     2795    // get IP header fields
     2796    uint8_t  ip_version  = buf[14];
     2797    uint8_t  ip_tos      = buf[15];
     2798    uint16_t ip_length   = ((uint16_t)buf[16] << 8) |
     2799                           ((uint16_t)buf[17]     ) ;
     2800
     2801    uint16_t ip_ident    = ((uint16_t)buf[18] << 8) |
     2802                           ((uint16_t)buf[19]     ) ;
     2803    uint16_t ip_offset   = ((uint16_t)buf[20] << 8) |
     2804                           ((uint16_t)buf[21]     ) ;
     2805
     2806    uint8_t  ip_ttl      = buf[22];
     2807    uint8_t  ip_protocol = buf[23];
     2808    uint16_t ip_checksum = ((uint16_t)buf[24] << 8) |
     2809                           ((uint16_t)buf[25]     ) ;
     2810
     2811    uint32_t ip_src_addr = ((uint32_t)buf[26] << 24) |
     2812                           ((uint32_t)buf[27] << 16) |
     2813                           ((uint32_t)buf[28] <<  8) |
     2814                           ((uint32_t)buf[29]      ) ;
     2815
     2816    uint32_t ip_dst_addr = ((uint32_t)buf[30] << 24) |
     2817                           ((uint32_t)buf[31] << 16) |
     2818                           ((uint32_t)buf[32] <<  8) |
     2819                           ((uint32_t)buf[33]      ) ;
     2820   
     2821    // get pointers on TXT0 chdev
     2822    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
     2823    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
     2824    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
     2825
     2826    // get extended pointer on remote TXT0 chdev lock
     2827    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
     2828
     2829    // get TXT0 lock
     2830    remote_busylock_acquire( lock_xp );
     2831
     2832    if( is_tx )
     2833    {
     2834        nolock_printk("\n*** NIC_TX server thread[%x,%x] send packet / cycle %d\n",
     2835        thread_pid, thread_trdid, cycle );
     2836    }
     2837    else
     2838    {
     2839        nolock_printk("\n*** NIC_RX server thread[%x,%x] get packet / cycle %d\n",
     2840        thread_pid, thread_trdid, cycle );
     2841    }
     2842
     2843    nolock_printk("\n***** ETH header *****\n");
     2844    nolock_printk(" - dst_mac  [6] = %l\n" , eth_dst_mac );
     2845    nolock_printk(" - src_mac  [6] = %l\n" , eth_src_mac );
     2846    nolock_printk(" - length   [2] = %d\n" , (uint32_t)eth_length );
     2847    nolock_printk("***** IP  header *****\n");
     2848    nolock_printk(" - version  [1] = %x\n" , (uint32_t)ip_version );
     2849    nolock_printk(" - tos      [1] = %x\n" , (uint32_t)ip_tos );
     2850    nolock_printk(" - length   [2] = %d\n" , (uint32_t)ip_length );
     2851    nolock_printk(" - ident    [2] = %x\n" , (uint32_t)ip_ident  );
     2852    nolock_printk(" - offset   [2] = %x\n" , (uint32_t)ip_offset );
     2853    nolock_printk(" - ttl      [1] = %x\n" , (uint32_t)ip_ttl );
     2854    nolock_printk(" - protocol [1] = %x\n" , (uint32_t)ip_protocol );
     2855    nolock_printk(" - checksum [2] = %x\n" , (uint32_t)ip_checksum );
     2856    nolock_printk(" - src_addr [4] = %x\n" , (uint32_t)ip_src_addr );
     2857    nolock_printk(" - dst_addr [4] = %x\n" , (uint32_t)ip_dst_addr );
     2858
     2859    // get UDP / TCP fields
     2860    if ( ip_protocol == PROTOCOL_UDP )
     2861    {
     2862        uint16_t udp_src_port = ((uint16_t)buf[34] << 8) |
     2863                                ((uint16_t)buf[35]     ) ;
     2864        uint16_t udp_dst_port = ((uint16_t)buf[36] << 8) |
     2865                                ((uint16_t)buf[37]     ) ;
     2866
     2867        nolock_printk("***** UDP header *****\n");
     2868        nolock_printk(" - src_port [2] = %d\n" , (uint32_t)udp_src_port );
     2869        nolock_printk(" - dst_port [2] = %d\n" , (uint32_t)udp_dst_port );
     2870    }
     2871    else if( ip_protocol == PROTOCOL_TCP )
     2872    {
     2873        uint16_t tcp_src_port = ((uint16_t)buf[34] << 8) |
     2874                                ((uint16_t)buf[35]     ) ;
     2875        uint16_t tcp_dst_port = ((uint16_t)buf[36] << 8) |
     2876                                ((uint16_t)buf[37]     ) ;
     2877
     2878        uint32_t tcp_seq_num  = ((uint32_t)buf[38] << 24) |
     2879                                ((uint32_t)buf[39] << 16) |
     2880                                ((uint32_t)buf[40] <<  8) |
     2881                                ((uint32_t)buf[41]      ) ;
     2882
     2883        uint32_t tcp_ack_num  = ((uint32_t)buf[42] << 24) |
     2884                                ((uint32_t)buf[43] << 16) |
     2885                                ((uint32_t)buf[44] <<  8) |
     2886                                ((uint32_t)buf[45]      ) ;
     2887
     2888        uint8_t  tcp_hlen      = buf[46];
     2889        uint8_t  tcp_flags     = buf[47];
     2890        uint16_t tcp_window    = ((uint16_t)buf[48] << 8) |
     2891                                 ((uint16_t)buf[49]     ) ;
     2892
     2893        uint16_t tcp_checksum  = ((uint16_t)buf[50] << 8) |
     2894                                 ((uint16_t)buf[51]     ) ;
     2895        uint16_t tcp_urgent    = ((uint16_t)buf[52] << 8) |
     2896                                 ((uint16_t)buf[53]     ) ;
     2897
     2898        nolock_printk("***** TCP header *****\n");
     2899        nolock_printk(" - src_port [2] = %x\n" , (uint32_t)tcp_src_port );
     2900        nolock_printk(" - dst_port [2] = %x\n" , (uint32_t)tcp_dst_port );
     2901        nolock_printk(" - seq_num  [4] = %x\n" , (uint32_t)tcp_seq_num );
     2902        nolock_printk(" - ack_num  [4] = %x\n" , (uint32_t)tcp_ack_num );
     2903        nolock_printk(" - hlen     [1] = %d\n" , (uint32_t)tcp_hlen );
     2904        nolock_printk(" - flags    [1] = %x\n" , (uint32_t)tcp_flags );
     2905        nolock_printk(" - window   [2] = %x\n" , (uint32_t)tcp_window );
     2906        nolock_printk(" - checksum [2] = %x\n" , (uint32_t)tcp_checksum );
     2907        nolock_printk(" - urgent   [2] = %x\n" , (uint32_t)tcp_urgent );
     2908    }
     2909    else
     2910    {
     2911        nolock_printk("!!!!! undefined transport protocol !!!!!\n");
     2912    }
     2913
     2914    // release TXT0 lock
     2915    remote_busylock_release( lock_xp );
     2916
     2917}  // end dev_nic_packet_display()
     2918
  • trunk/kernel/devices/dev_nic.h

    r657 r663  
    5656 * In this case, the channel index is defined by an hash function computed from the remote
    5757 * IP address and port. This index is computed by the hardware for an RX packet, and is
    58  * computed by the kernel for a TX packet, using a specific driver function. TODO ...
     58 * computed by the kernel for a TX packet, using a specific driver function.
    5959 * The 2*N chdevs, and the associated server threads implementing the protocols stack,
    6060 * are distributed in 2*N different clusters.
     
    6363 *
    6464 * On the user side, ALMOS-MKH implements the POSIX socket API.
    65  * The kernel functions implementing the socket related syscalls are :
    66  * - dev_nic_socket()    : create a local socket registered in process fd_array[].
    67  * - dev_nic_bind()      : attach a local IP address and port to a local socket.
    68  * - dev_nic_listen()    : local server makes a passive open.
    69  * - dev_nic_connect()   : local client makes an active open to a remote server.
    70  * - dev_nic_accept()    : local server accept a new remote client.
    71  * - dev_nic_send()      : send data on a connected socket.
    72  * - dev_nic_recv()      : receive data on a connected socket.
    73  * - dev_nic_sendto()    : send a packet to a remote (IP address/port).
    74  * - dev_nic_recvfrom()  : receive a paket from a remote (IP address/port).
    75  * - dev_nic_close()     : close a socket
    76  *
    77  * 3) TX stream
    78  *
    79  * The internal API between the client threads and the TX server thread defines
    80  * the 3 following commands:
    81  *   . SOCKET_TX_CONNECT : request to execute the 3 steps TCP connection handshake.
    82  *   . SOCKET_TX_SEND    : send data to a remote socket (UDP or TCP).
    83  *   . SOCKET_TX_CLOSE   : request to execute the 3 steps TCP close handshake.
    84  *
    85  * - These 3 commands are blocking for the client thread that registers the command in the
    86  *   socket descriptor, blocks on the BLOCKED_IO condition, and deschedules.
    87  * - The TX server thread is acting as a multiplexer. It scans the list of attached sockets,
    88  *   to handle all valid commands: one UDP packet or TCP segment per iteration.
    89  *   It uses the user buffer defined by the client thread, and attached to socket descriptor,
    90  *   as a retransmission buffer. It blocks and deschedules on the BLOCKED_CLIENT condition,
    91  *   when there is no more active TX command registered in any socket. It is re-activated
    92  *   by the first client thread registering a new TX command in the socket descriptor.
    93  *   It unblocks a client thread only when a command is fully completed. It signals errors
    94  *   to the client thread using the tx_error field in socket descriptor.
    95  *
    96  * 4) RX stream
    97  *
    98  * The communication between the RX server thread and the client threads expecting data
    99  * is done through receive buffers (one private buffer per socket) that are handled
    100  * as single-writer / single reader-FIFOs, called rx_buf.
    101  * - The RX server thread is acting as a demultiplexor: it handle one TCP segment or UDP
    102  *   packet per iteration, and register the data in the rx_buf of the socket matching
    103  *   the packet. It simply discard all packets that does not match a registered socket.
    104  *   When a client thread is registered in the socket descriptor, the RX server thread
    105  *   unblocks this client thread as soon as there is data available in rx_buf.
    106  *   It blocks and deschedules on the BLOCKED_ISR condition when there is no more packets
    107  *   in the NIC_RX queue. It is unblocked by the hardware ISR.
    108  * - The client thread simply access the rx_buf attached to socket descriptor, and consumes
    109  *   the available data when the rx_buf is non empty. It blocks on the BLOCKED_IO condition,
    110  *   and deschedules when the rx_buf is empty.
    111  *
    112  * 5) R2T queue
    113  *
    114  * To implement the TCP "3 steps handshake" protocol, the RX server thread can directly
    115  * request the associated TX server thread to send control packets in  the TX stream,
    116  * using a dedicate R2T (RX to TX) FIFO stored in the socket descriptor.
    117  *
    118  * 6) NIC driver API
    119  *
    120  * The generic NIC device "driver" API defines the following commands to the NIC driver:
    121  * - READABLE : returns true if at least one RX paquet is available in RX queue.
    122  * - WRITABLE : returns true if at least one empty slot is available in TX queue.
    123  * - READ     : consume one packet from the RX queue.
    124  * - WRITE    : produce one packet to the TX queue.
     65 * The following kernel functions implement the socket related syscalls :
     66 * - socket_build()     : create a local socket registered in process fd_array[].
     67 * - socket_bind()      : attach a local IP address and port to a local socket.
     68 * - socket_listen()    : local server makes a passive open.
     69 * - socket_connect()   : local client makes an active open to a remote server.
     70 * - socket_accept()    : local server accept a new remote client.
     71 * - socket_send()      : send data on a connected socket.
     72 * - socket_recv()      : receive data on a connected socket.
     73 * - socket_sendto()    : send a packet to a remote (IP address/port).
     74 * - socket_recvfrom()  : receive a paket from a remote (IP address/port).
     75 *
     76 * 3) NIC TX and NIC_RX server threads
     77 *
     78 * The dev_nic_tx_server() & dev_nic_rx_server() functions defined below execute
     79 * the user commands stored in the sockets to implement the [ETH / IP / TCP or UDP]
     80 * protocols stack, as defined in the <ksocket.c> and <ksocket.h> files.
     81 *
     82 * 4) NIC driver API
     83 *
     84 * The generic NIC device "driver" API defines the following commands, used by the
     85 * NIC_TX and NIC_RX server threads, running in the cluster containing the relevant chdev,
     86 * to access the NIC_TX and NIC_RX packets queues:
     87 *
     88 * - READ     : consume one packet from the NIC_RX queue.
     89 * - WRITE    : produce one packet to the NIC_TX queue.
     90 *
    12591 * All RX or TX paquets are sent or received in standard 2 Kbytes kernel buffers,
    12692 * that are dynamically allocated by the protocols stack.
    127  *
    12893 * The actual TX an RX queues structures depends on the hardware NIC implementation,
    12994 * and are defined in the HAL specific driver code.
     95 *
     96 * Moreover, the generic NIC device "driver" API defines the following commands,
     97 * used directly by a client thread running in any cluster, to access the NIC device
     98 * configuration or status registers:
     99 *
     100 * - GET_KEY      : get channel index from remote IP address and port
     101 * - SET_RUN      : activate/desactivate one channel
     102 * - GET_INSTRU   : get one instrumentation counter value
     103 * - CLEAR_INSTRU : reset all instrumentation counters
    130104 *
    131105 * WARNING: the WTI mailboxes used by the driver ro receive events from the hardware
     
    140114struct chdev_s;
    141115
    142 /******************************************************************************************
    143  *   Various constants used by the Protocols stack
    144  *****************************************************************************************/
    145 
    146 #define SRC_MAC_54             0x54
    147 #define SRC_MAC_32             0x32
    148 #define SRC_MAC_10             0x10
    149 #define DST_MAC_54             0x54
    150 #define DST_MAC_32             0x32
    151 #define DST_MAC_10             0x10
     116/*****************************************************************************************
     117 *   Various constants used by the protocols stack
     118 ****************************************************************************************/
     119
     120#define SRC_MAC_5              0x66         // This is a temporary short-cut for debug
     121#define SRC_MAC_4              0x55
     122#define SRC_MAC_3              0x44
     123#define SRC_MAC_2              0x33
     124#define SRC_MAC_1              0x22
     125#define SRC_MAC_0              0x11
     126
     127#define DST_MAC_5              0x66         // This is a temporary short-cut for debug
     128#define DST_MAC_4              0x55
     129#define DST_MAC_3              0x44
     130#define DST_MAC_2              0x33
     131#define DST_MAC_1              0x22
     132#define DST_MAC_0              0x11
    152133
    153134#define TCP_HEAD_LEN           20
     
    159140#define PROTOCOL_TCP           0x06
    160141
    161 #define TCP_ISS                0x10000
    162 
    163 #define PAYLOAD_MAX_LEN        1500         // max payload for and UDP packet or a TCP segment
     142#define TCP_ISS_CLIENT         0x10000      // initial sequence number for TCP client
     143#define TCP_ISS_SERVER         0x20000      // initial sequence number for TCP server
     144#define TCP_MAX_WINDOW         0xFFFFF      // initial TCP send window
     145
     146#define PAYLOAD_MAX_LEN        1500         // max length for an UDP packet / TCP segment
    164147
    165148#define TCP_FLAG_FIN           0x01
     
    172155#define NIC_RX_BUF_SIZE        0x100000     // 1 Mbytes
    173156#define NIC_R2T_QUEUE_SIZE     0x64         // smallest KCM size
    174 #define NIC_CRQ_QUEUE_SIZE     0x8          // 8 * sizeof(sockaddr_t) = smallest KCM size
    175 #define NIC_PKT_MAX_SIZE       1500         // for Ethernet
    176 #define NIC_KERNEL_BUF_SIZE    2000         // for on ETH/IP/TCP packet
     157#define NIC_CRQ_QUEUE_SIZE     0x8          // actual size is 8 * sizeof(sockaddr_t)
     158#define NIC_KERNEL_BUF_SIZE    0x800        // 2 Kbytes for one ETH/IP/TCP packet
    177159
    178160/*****************************************************************************************
    179  * This defines the extension for the generic NIC device.
    180  * The actual queue descriptor depends on the implementation.
    181  *
    182  * WARNING : for all NIC_TX and NIC_RX chdevs, the xlist rooted in in the chdev
    183  *           ("wait_root" and "wait_lock" fields) is actually a list of sockets.
     161 * This structure defines the specific chdev extension for NIC device:
     162 * - queue : local pointer on the memory mapped queue of TX or RX packets, used
     163 *   by the NIC driver to move packets to/from the NIC hardware. The actual descriptor
     164 *   depends on the NIC implementation.
     165 * - root  : root of an xlist of sockets that are in the LISTEN state, waiting one or
     166 *   several TCP connection requests from remote processes. It is only used by the
     167 *   NIC_RX server thread attached to a NIC_RX chdev.
     168 * - lock  : lock protecting concurrent access to the litening sockets list.
    184169 ****************************************************************************************/
    185170
    186171typedef struct nic_extend_s
    187172{
    188     void         * queue;       /*! local pointer on NIC queue descriptor (RX or TX)    */
     173    void            * queue;    /*! pointer on NIC packets queue descriptor (RX or TX)  */
     174    xlist_entry_t     root;     /*! root of listening sockets list (only used in RX[0]) */
     175    remote_busylock_t lock;     /*! lock protecting this list  (only used in RX[0]      */
    189176}
    190177nic_extend_t;
     
    204191/****************************************************************************************
    205192 * This defines the (implementation independant) commands to access the NIC hardware.
    206  * These commands are registered by the NIC_TX and NIC_RX server threads in the
    207  * server thread descriptor, to be used by the NIC driver.
    208  * The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet.
     193 * There is two types of commands
     194 * - The first 2 commands are used by the NIC_TX and NIC_RX server threads, and stored
     195 *   in the server thread descriptor, to access the NIC_RX & NIC_TX packet queues.
     196 *   The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet.
     197 * - The next 4 synchronous commands are used by the client th, and stored in the
     198 *   client thread descriptor, to directly access the NIC registers.
    209199 ****************************************************************************************/
    210200
    211201typedef enum nic_cmd_e
    212202{
    213     NIC_CMD_WRITABLE  = 10,   /*! test TX queue not full (for a given packet length)    */
    214     NIC_CMD_WRITE     = 11,   /*! put one (given length) packet to TX queue             */
    215     NIC_CMD_READABLE  = 12,   /*! test RX queue not empty (for any packet length)       */
    216     NIC_CMD_READ      = 13,   /*! get one (any length) packet from RX queue             */
     203    NIC_CMD_WRITE        = 10,  /*! put one (given length) packet to TX queue           */
     204    NIC_CMD_READ         = 11,  /*! get one (any length) packet from RX queue           */
     205
     206    NIC_CMD_GET_KEY      = 20,  /*! return channel index from IP address and port       */
     207    NIC_CMD_SET_RUN      = 21,  /*! enable/disable one NIC channel                      */
     208    NIC_CMD_GET_INSTRU   = 22,  /*! return one intrumentation register value            */
     209    NIC_CMD_CLEAR_INSTRU = 23,  /*! reset all instrumentation registers                 */
    217210}
    218211nic_cmd_t;
     
    222215    xptr_t      dev_xp;       /*! extended pointer on NIC chdev descriptor              */
    223216    nic_cmd_t   type;         /*! command type                                          */
    224     uint8_t   * buffer;       /*! local pointer on buffer (kernel or user space)        */ 
     217    uint8_t   * buffer;       /*! local pointer on kernel buffer                        */ 
    225218    uint32_t    length;       /*! number of bytes in buffer                             */
    226219    uint32_t    status;       /*! return value (depends on command type)                */
     
    228221}
    229222nic_command_t;
    230 
    231 /*****************************************************************************************
    232  * This structure defines a socket descriptor. In order to parallelize the transfers,
    233  * the set of all registered sockets is split in several subsets.
    234  * The number of subsets is the number of  NIC channels.
    235  * The distribution key is computed from the (remote_addr/remote_port) couple.
    236  * This computation is done by the NIC hardware for RX packets,
    237  * and by the dev_nic_connect() function for the TX packets.
    238  *
    239  * A socket is attached to the NIC_TX[channel] & NIC_RX[channel] chdevs.
    240  * Each socket descriptor allows the TX and TX server threads to access various buffers:
    241  * - the user "send" buffer contains the data to be send by the TX server thread.
    242  * - the kernel "receive" buffer contains the data received by the RX server thread.
    243  * - the kernel "r2t" buffer allows the RX server thread to make direct requests
    244  *   to the associated TX server (to implement the TCP 3 steps handshake).
    245  *
    246  * The synchronisation mechanism between the clients threads and the servers threads
    247  * is different for TX and RX transfers:
    248  *
    249  * 1) For a TX transfer, it can exist only one client thread for a given socket,
    250  *    the transfer is always initiated by the local process, and all TX commands
    251  *    (CONNECT/SEND/CLOSE) are blocking for the client thread. The user buffer is
    252  *    used by TCP to handle retransmissions when required.in case of re
    253  *    The client thread registers the command in the thread descriptor, registers itself
    254  *    in the socket descriptor, unblocks the TX server thread from the BLOCKED_CLIENT
    255  *    condition, blocks itself on the BLOCKED_IO condition, and deschedules.
    256  *    When the command is completed, the TX server thread unblocks the client thread.
    257  *    The TX server blocks itself on the BLOCKED_CLIENT condition, when there is no
    258  *    pending commands and the R2T queue is empty. It is unblocked when a client
    259  *    register a new command, or when the TX server thread register a mew request
    260  *    in the R2T queue.
    261  *    The tx_valid flip-flop is SET by the client thread to signal a valid command.
    262  *    It is RESET by the server thread when the command is completed: For a SEND,
    263  *    all bytes have been sent (UDP) or acknowledged (TCP).
    264  *
    265  * 2) For an RX transfer, it can exist only one client thread for a given socket,
    266  *    but the transfer is initiated by the remote process, and the  RECV command
    267  *    is not really blocking: the data can arrive before the local RECV command is
    268  *    executed, and the server thread does not wait to receive all requested data
    269  *    to deliver data to client thread. Therefore each socket contains a receive
    270  *    buffer (rx_buf) handled as a single-writer/single-reader fifo.
    271  *    The client thread consumes data from the rx_buf when possible. It blocks on the
    272  *    BLOCKED_IO condition and deschedules when the rx_buf is empty.
    273  *    It is unblocked by the RX server thread when new data is available in the rx_buf.
    274  *    The RX server blocks itself on the BLOCKED_ISR condition When the NIC_RX packets
    275  *    queue is empty. It is unblocked by the hardware when new packets are available.
    276  *
    277  * Note : the socket domains and types are defined in the "shared_socket.h" file.
    278  ****************************************************************************************/
    279 
    280 /******************************************************************************************
    281  * This function returns a printable string for a given NIC command <type>.
    282  ******************************************************************************************
    283  * @ type    : NIC command type
    284  *****************************************************************************************/
    285 char * nic_cmd_str( uint32_t type );
    286    
    287 /******************************************************************************************
    288  * This function returns a printable string for a given socket <state>.
    289  ******************************************************************************************
    290  * @ state    : socket state
    291  *****************************************************************************************/
    292 char * socket_state_str( uint32_t state );
    293223
    294224/******************************************************************************************
     
    299229 * device and the specific data structures when required.
    300230 * It creates the associated server thread and allocates a WTI from local ICU.
    301  * For a TX_NIC chedv, it allocates and initializes the R2T waiting queue used by the
    302  * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server.
     231 * For a TX_NIC chedv, it allocates and initializes the R2T queue used by the
     232 * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server,
     233 * and the CRQ queue used to register connection requests.
    303234 * It must de executed by a local thread.
     235 * For NIC_TX and NIC_RX chdevs, the "wait_root" field is actually a list of sockets.
    304236 ******************************************************************************************
    305237 * @ chdev    : local pointer on NIC chdev descriptor.
     
    307239void dev_nic_init( struct chdev_s * chdev );
    308240
    309 
    310 /* functions implementing the socket API */
    311 
    312 /****************************************************************************************
    313  * This function implements the socket() syscall.
    314  * This function allocates and intializes in the calling thread cluster:
    315  * - a new socket descriptor, defined by the <domain> and <type> arguments,
    316  * - a new file descriptor, associated to this socket,
    317  * It registers the file descriptor in the reference process fd_array[], set
    318  * the socket state to IDLE, and returns the <fdid> value.
    319  ****************************************************************************************
    320  * @ domain  : [in] socket protocol family (AF_UNIX / AF_INET)
    321  * @ type    : [in] socket type (SOCK_DGRAM / SOCK_STREAM).
    322  * @ return a file descriptor <fdid> if success / return -1 if failure.
    323 ***************************************************************************************/
    324 int dev_nic_socket( uint32_t   domain,
    325                     uint32_t   type );
    326 
    327 /****************************************************************************************
    328  * This function implements the bind() syscall.
    329  * It initializes the  "local_addr" and "local_port" fields in the socket
    330  * descriptor identified by the <fdid> argument and set the socket state to BOUND.
    331  * It can be called by a thread running in any cluster.
    332  ****************************************************************************************
    333  * @ fdid      : [in] file descriptor identifying the socket.
    334  * @ addr      : [in] local IP address.
    335  * @ port      : [in] local port.
    336  * @ return 0 if success / return -1 if failure.
    337  ***************************************************************************************/
    338 int dev_nic_bind( uint32_t fdid,
    339                   uint32_t addr,
    340                   uint16_t port );
    341 
    342 /****************************************************************************************
    343  * This function implements the listen() syscall().
    344  * It is called by a (local) server process to specify the max size of the queue
    345  * registering the (remote) client process connections, and set the socket identified
    346  * by the <fdid> argument to LISTEN state. It applies only to sockets of type TCP.
    347  * It can be called by a thread running in any cluster.
    348  * TODO handle the <max_pending> argument...
    349  ****************************************************************************************
    350  * @ fdid        : [in] file descriptor identifying the local server socket.
    351  * @ max_pending : [in] max number of accepted remote client connections.
    352  ***************************************************************************************/
    353 int dev_nic_listen( uint32_t fdid,
    354                     uint32_t max_pending );
    355 
    356 /****************************************************************************************
    357  * This function implements the connect() syscall.
    358  * It is used by a (local) client process to connect a local socket identified by
    359  * the <fdid> argument, to a remote socket identified by the <remote_addr> and
    360  * <remote_port> arguments. It can be used for both  UDP and TCP sockets.
    361  * It computes the nic_channel index from <remote_addr> and <remote_port> values,
    362  * and initializes "remote_addr","remote_port", "nic_channel" in local socket.
    363  * It registers the socket in the two lists of clients rooted in the NIC_RX[channel]
    364  * and NIC_TX[channel] chdevs.  It can be called by a thread running in any cluster.
    365  * WARNING : the clients are the socket descriptors, and NOT the threads descriptors.
    366  ****************************************************************************************
    367  * Implementation Note:
    368  * - For a TCP socket, it updates the "remote_addr", "remote_port", "nic_channel" fields
    369  *   in the socket descriptor defined by the <fdid> argument, and register this socket,
    370  *   in the lists of sockets attached to the NIC_TX and NIC_RX chdevs.
    371  *   Then, it registers a CONNECT command in the "nic_cmd" field ot the client thread
    372  *   descriptor to request the NIC_TX server thread to execute the 3 steps handshake,
    373  *   and updates the "tx_client" field in the socket descriptor. It unblocks the NIC_TX
    374  *   server thread, blocks on the THREAD_BLOCKED_IO condition and deschedules.
    375  * - For an UDP socket, it simply updates "remote_addr", "remote_port", "nic_channel"
    376  *   in the socket descriptor defined by the <fdid> argument, and register this socket,
    377  *   in the lists of sockets attached to the NIC_TX and NIC_RX chdevs.
    378  *   Then, it set the socket state to CONNECT, without unblocking the NIC_TX server
    379  *   thread, and without blocking itself.
    380  * TODO : the nic_channel index computation must be done by a driver specific function.
    381  ****************************************************************************************
    382  * @ fdid          : [in] file descriptor identifying the socket.
    383  * @ remote_addr   : [in] remote IP address.
    384  * @ remote_port   : [in] remote port.
    385  * @ return 0 if success / return -1 if failure.
    386  ***************************************************************************************/
    387 int dev_nic_connect( uint32_t  fdid,
    388                      uint32_t  remote_addr,
    389                      uint16_t  remote_port );
    390 
    391 /****************************************************************************************
    392  * This function implements the accept() syscall().
    393  * It is executed by a server process, waiting for one (or several) client process(es)
    394  * requesting a connection on a socket identified by the <fdid> argument.
    395  * This socket was previouly created with socket(), bound to a local address with bind(),
    396  * and is listening for connections after a listen().
    397  * This function extracts the first connection request on the CRQQ queue of pending
    398  * requests, creates a new socket with the same properties as the existing socket,
    399  * and allocates a new file descriptor for this new socket.
    400  * If no pending connections are present on the queue, it blocks the caller until a
    401  * connection is present.
    402  * The new socket cannot accept more connections, but the original socket remains open.
    403  * It returns the new socket <fdid>, and register in the <address> an <port> arguments
    404  * the remote client IP address & port. It applies only to sockets of type SOCK_STREAM.
    405  ****************************************************************************************
    406  * @ fdid         : [in] file descriptor identifying the listening socket.
    407  * @ address      : [out] server IP address.
    408  * @ port         : [out] server port address length in bytes.
    409  * @ return the new socket <fdid> if success / return -1 if failure
    410  ***************************************************************************************/
    411 int dev_nic_accept( uint32_t   fdid,
    412                     uint32_t * address,
    413                     uint16_t * port );
    414 
    415 /****************************************************************************************
    416  * This blocking function implements the send() syscall.
    417  * It is used to send data stored in the user buffer, identified the <u_buf> and <length>
    418  * arguments, to a connected (TCP or UDP) socket, identified by the <fdid> argument.
    419  * The work is actually done by the NIC_TX server thread, and the synchronisation
    420  * between the client and the server threads uses the "rx_valid" set/reset flip-flop:
    421  * The client thread registers itself in the socket descriptor, registers in the queue
    422  * rooted in the NIC_TX[index] chdev, set "rx_valid", unblocks the server thread, and
    423  * finally blocks on THREAD_BLOCKED_IO, and deschedules.
    424  * When the TX server thread completes the command (all data has been sent for an UDP
    425  * socket, or acknowledeged for a TCP socket), the server thread reset "rx_valid" and
    426  * unblocks the client thread.
    427  * This function can be called by a thread running in any cluster.
    428  * WARNING : This implementation does not support several concurent SEND/SENDTO commands
    429  * on the same socket, as only one TX thread can register in a given socket.
    430  ****************************************************************************************
    431  * @ fdid      : [in] file descriptor identifying the socket.
    432  * @ u_buf     : [in] pointer on buffer containing packet in user space.
    433  * @ length    : [in] packet size in bytes.
    434  * @ return number of sent bytes if success / return -1 if failure.
    435  ***************************************************************************************/
    436 int dev_nic_send( uint32_t    fdid,
    437                   uint8_t   * u_buf,
    438                   uint32_t    length );
    439 
    440 /****************************************************************************************
    441  * This blocking function implements the sendto() syscall.
    442  * It registers the <remote_addr> and <remote_port> arguments in the local socket
    443  * descriptor, and does the same thing as the dev_nic_send() function above,
    444  * but can be called  on an unconnected UDP socket.
    445  ****************************************************************************************
    446  * @ fdid        : [in] file descriptor identifying the socket.
    447  * @ u_buf       : [in] pointer on buffer containing packet in user space.
    448  * @ length      : [in] packet size in bytes.
    449  * @ remote_addr : [in] destination IP address.
    450  * @ remote_port : [in] destination port.
    451  * @ return number of sent bytes if success / return -1 if failure.
    452  ***************************************************************************************/
    453 int dev_nic_sendto( uint32_t    fdid,
    454                     uint8_t   * u_buf,
    455                     uint32_t    length,
    456                     uint32_t    remote_addr,
    457                     uint32_t    remote_port );
    458 
    459 /****************************************************************************************
    460  * This blocking function implements the recv() syscall.
    461  * It is used to receive data that has been stored by the NIC_RX server thread in the
    462  * rx_buf of a connected (TCP or UDP) socket, identified by the <fdid> argument.
    463  * The synchronisation between the client and the server threads uses the "rx_valid"
    464  * set/reset flip-flop: If "rx_valid" is set, the client simply moves the available
    465  * data from the "rx_buf" to the user buffer identified by the <u_buf> and <length>
    466  * arguments, and reset the "rx_valid" flip_flop. If "rx_valid" is not set, the client
    467  * thread register itself in the socket descriptor, registers in the clients queue rooted
    468  * in the NIC_RX[index] chdev, and finally blocks on THREAD_BLOCKED_IO, and deschedules.
    469  * The client thread is re-activated by the RX server, that set the "rx_valid" flip-flop
    470  * as soon as data is available in the "rcv_buf" (can be less than the user buffer size).
    471  * This  function can be called by a thread running in any cluster.
    472  * WARNING : This implementation does not support several concurent RECV/RECVFROM
    473  * commands on the same socket, as only one RX thread can register in a given socket.
    474  ****************************************************************************************
    475  * @ fdid      : [in] file descriptor identifying the socket.
    476  * @ u_buf     : [in] pointer on buffer in user space.
    477  * @ length    : [in] buffer size in bytes.
    478  * @ return number of received bytes if success / return -1 if failure.
    479  ***************************************************************************************/
    480 int dev_nic_recv( uint32_t    fdid,
    481                   uint8_t   * u_buf,
    482                   uint32_t    length );
    483 
    484 /****************************************************************************************
    485  * This blocking function implements the recvfrom() syscall.
    486  * It registers the <remote_addr> and <remote_port> arguments in the local socket
    487  * descriptor, and does the same thing as the dev_nic_recv() function above,
    488  * but can be called  on an unconnected UDP socket.
    489  ****************************************************************************************
    490  * @ fdid        : [in] file descriptor identifying the socket.
    491  * @ u_buf       : [in] pointer on buffer containing packet in user space.
    492  * @ length      : [in] packet size in bytes.
    493  * @ remote_addr : [in] destination IP address.
    494  * @ remote_port : [in] destination port.
    495  * @ return number of received bytes if success / return -1 if failure.
    496  ***************************************************************************************/
    497 int dev_nic_recvfrom( uint32_t    fdid,
    498                       uint8_t   * u_buf,
    499                       uint32_t    length,
    500                       uint32_t    remote_addr,
    501                       uint32_t    remote_port );
    502 
    503 
    504 /*  Instrumentation functions */
    505 
     241/* Functions directly called by a client thread in any cluster */
     242 
     243/******************************************************************************************
     244 * This function compute a channel index in range [0,nic_channels[ from the remote IP
     245 * address <addr> and <port>, by calling the relevant driver command.
     246 ******************************************************************************************
     247 * @ addr     : [in] IP address.
     248 * @ port     : [in] TCP/UDP port.
     249 * @ return the selected channel index
     250 *****************************************************************************************/
     251uint32_t dev_nic_get_key( uint32_t addr,
     252                          uint16_t port );
     253
     254/******************************************************************************************
     255 * This function activate / de-activate a NIC channel DMA engine identified by the
     256 * <channel> argument, as defined by the <run> argument.
     257 ******************************************************************************************
     258 * @ channel  : [in] NIC channel index.
     259 * @ run      : [in] activate if non-zero / desactivate if zero.
     260 * @ return 0 if success / return -1 if error.
     261 *****************************************************************************************/
     262error_t dev_nic_set_run( uint32_t channel,
     263                         uint32_t run );
    506264
    507265/******************************************************************************************
    508266 * This instrumentation function displays on the TXT0 kernel terminal the content
    509267 * of the instrumentation registers contained in the NIC device.
    510  *****************************************************************************************/
    511 void dev_nic_print_stats( void );
     268 ******************************************************************************************
     269 * @ return 0 if success / return -1 if error.
     270 *****************************************************************************************/
     271error_t dev_nic_get_instru( void );
    512272
    513273/******************************************************************************************
    514274 * This instrumentation function reset all instrumentation registers contained
    515275 * in the NIC device.
    516  *****************************************************************************************/
    517 void dev_nic_clear_stats( void );
    518 
     276 ******************************************************************************************
     277 * @ return 0 if success / return -1 if error.
     278 *****************************************************************************************/
     279error_t dev_nic_clear_instru( void );
    519280
    520281/* Functions executed by the TX and RX server threads */
     
    532293 * When the TX client threads queue is empty, it blocks on THREAD_BLOCKED_CLIENT
    533294 * condition and deschedules. It is re-activated by a client thread registering a command.
     295 * When the NIC_TX packet queue is full, it blocks on the THREAD_BLOCKED_ISR condition
     296 * and deschedules. It is reactivated by the NIC_TX DMA engine.
    534297 ******************************************************************************************
    535298 * Implementation note:
     
    556319 * requests to the TX server, using the R2T queue attached to the involved socket.
    557320 * It blocks on the THREAD_BLOCKED_ISR condition and deschedules when the NIC_RX_QUEUE
    558  * is empty. It is re-activated by the NIC_RX_ISR, when the queue becomes non empty.
     321 * is empty, and is re-activated by the NIC_RX_ISR, when the queue becomes non empty.
    559322 ******************************************************************************************
    560323 * Implementation note:
     
    570333void dev_nic_rx_server( struct chdev_s * chdev );
    571334
     335/******************************************************************************************
     336 * This function displays all the fields of an ETH/IP/TCP segment or ETH/IP/UDP packet.
     337 ******************************************************************************************
     338 * @ is_tx   : [in] sent packet if true / received packet if false.
     339 * @ pid     : [in] process identifier.
     340 * @ trdid   : [in] thread identifier.
     341 * @ cycle   : [in] date (number of cycles).
     342 * @ buf     : [in] local pointer on kernel buffer containing the packet.
     343 *****************************************************************************************/
     344void dev_nic_packet_display( bool_t    is_tx,
     345                             pid_t     pid,
     346                             trdid_t   trdid,
     347                             uint32_t  cycle,
     348                             uint8_t * buf );
     349
    572350#endif  /* _DEV_NIC_H */
  • trunk/kernel/devices/dev_txt.c

    r657 r663  
    7474    bool_t    is_rx   = txt->is_rx;
    7575
    76     assert( (pic_xp != XPTR_NULL) || (channel == 0) ,
    77             "PIC not initialised before TXT" );
     76assert( (pic_xp != XPTR_NULL) || (channel == 0) ,
     77"PIC not initialised before TXT" );
    7878
    7979    // set chdev name
Note: See TracChangeset for help on using the changeset viewer.