Ignore:
Timestamp:
Mar 18, 2020, 11:16:59 PM (4 years ago)
Author:
alain
Message:

Introduce remote_buf.c/.h & socket.c/.h files.
Update dev_nic.c/.h files.

File:
1 edited

Legend:

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

    r647 r657  
    22 * dev_nic.c - NIC (Network Controler) generic device API implementation.
    33 *
    4  * Author  Alain Greiner    (2016,2017,2018,2019)
     4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    2424#include <hal_kernel_types.h>
    2525#include <hal_special.h>
     26#include <hal_uspace.h>
     27#include <remote_buf.h>
    2628#include <printk.h>
    2729#include <chdev.h>
    2830#include <thread.h>
     31#include <socket.h>
    2932#include <hal_drivers.h>
    3033#include <dev_nic.h>
     34#include <vfs.h>
     35#include <shared_socket.h>
    3136
    3237/////////////////////////////////////////////////////////////////////////////////////////
    33 // Extern global variables
     38//                 Extern global variables
    3439/////////////////////////////////////////////////////////////////////////////////////////
    3540
    3641extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
     42
     43////////////////////////////////////////////////////////////////////////////////////////////
     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).
     48////////////////////////////////////////////////////////////////////////////////////////////
     49// @ seq   : [in] value to be checked.
     50// @ min   : [in] first  base.
     51// @ max   : [in] window size.
     52////////////////////////////////////////////////////////////////////////////////////////////
     53static inline bool_t is_in_window( uint32_t seq,
     54                                   uint32_t min,
     55                                   uint32_t max )
     56{
     57    if( max >= min )    // no wrap_around => only one window [min,max]
     58    {
     59        return( (seq >= min) && (seq <= max) );
     60    }
     61    else                // window wrap-around => two windows [min,0xFFFFFFFF] and [0,max]
     62    {
     63        return( (seq <= max) || (seq >= min) );
     64    }
     65
     66
     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////////////////////////////////////////////////////////////////////////////////////////////
     75static 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
     90////////////////////////////////////////////////////////////////////////////////////////
     91// This static function computes the checksum for an IP packet header.
     92// The "checksum" field itself is not taken into account for this computation.
     93////////////////////////////////////////////////////////////////////////////////////////
     94// @ buffer      : [in] pointer on IP packet header (20 bytes)
     95// @ return the checksum value on 16 bits
     96////////////////////////////////////////////////////////////////////////////////////////
     97uint16_t dev_nic_ip_checksum( uint8_t  * buffer )
     98{
     99    uint32_t   i;           
     100    uint32_t   cs;      // 32 bits accumulator
     101    uint16_t * buf;     
     102   
     103    buf = (uint16_t *)buffer;
     104
     105    // compute checksum
     106    for( i = 0 , cs = 0 ; i < 10 ; i++ )
     107    {
     108        if( i != 5 )  cs += buf[i];
     109    }
     110
     111    // one's complement
     112    return ~cs;
     113}
     114
     115////////////////////////////////////////////////////////////////////////////////////////
     116// This static function computes the checksum for an UDP packet defined by
     117// the <buffer> and <size> arguments.
     118////////////////////////////////////////////////////////////////////////////////////////
     119// @ buffer      : [in] pointer on UDP packet base.
     120// @ size        : [in] number of bytes in this packet (including header).
     121// @ return the checksum value on 16 bits
     122////////////////////////////////////////////////////////////////////////////////////////
     123uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
     124                               uint32_t   size )
     125{
     126    uint32_t   i;           
     127    uint32_t   carry;
     128    uint32_t   cs;      // 32 bits accumulator
     129    uint16_t * buf;     
     130    uint32_t   max;     // number of uint16_t in packet
     131   
     132    // compute max & buf
     133    buf = (uint16_t *)buffer;
     134    max = size >> 1;
     135
     136    // extend buffer[] if required
     137    if( size & 1 )
     138    {
     139        max++;
     140        buffer[size] = 0;
     141    }
     142
     143    // compute checksum for UDP packet
     144    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
     145
     146    // handle carry
     147    carry = (cs >> 16);
     148    if( carry )
     149    {
     150        cs += carry;
     151        carry = (cs >> 16);
     152        if( carry ) cs += carry;
     153    }
     154
     155    // one's complement
     156    return ~cs;
     157}
     158
     159////////////////////////////////////////////////////////////////////////////////////////
     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.
     164////////////////////////////////////////////////////////////////////////////////////////
     165// @ buffer      : [in] pointer on TCP segment base.
     166// @ size        : [in] number of bytes in this segment (including header).
     167// @ src_ip_addr : [in] source IP address (pseudo header)
     168// @ dst_ip_addr : [in] destination IP address (pseudo header)
     169// @ return the checksum value on 16 bits
     170////////////////////////////////////////////////////////////////////////////////////////
     171uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
     172                               uint32_t   size,
     173                               uint32_t   src_ip_addr,
     174                               uint32_t   dst_ip_addr )
     175{
     176    uint32_t   i;           
     177    uint32_t   carry;
     178    uint32_t   cs;      // 32 bits accumulator
     179    uint16_t * buf;
     180    uint32_t   max;     // number of uint16_t in segment
     181
     182    // compute max & buf
     183    buf = (uint16_t *)buffer;
     184    max = size >> 1;
     185
     186    // extend buffer[] if required
     187    if( size & 1 )
     188    {
     189        max++;
     190        buffer[size] = 0;
     191    }
     192
     193    // compute checksum for TCP segment
     194    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
     195
     196    // complete checksum for pseudo-header
     197    cs += src_ip_addr;
     198    cs += dst_ip_addr;
     199    cs += PROTOCOL_TCP;
     200    cs += size;
     201
     202    // handle carry
     203    carry = (cs >> 16);
     204    if( carry )
     205    {
     206        cs += carry;
     207        carry = (cs >> 16);
     208        if( carry ) cs += carry;
     209    }
     210
     211    // one's complement
     212    return ~cs;
     213}
    37214
    38215//////////////////////////////////
     
    80257}  // end dev_nic_init()
    81258
     259
     260/////////////////////////////////////////////////////////////////////////////////////////
     261//                 Functions implementing the SOCKET related syscalls
     262/////////////////////////////////////////////////////////////////////////////////////////
     263
     264//////////////////////////////////////
     265int dev_nic_socket( uint32_t   domain,
     266                    uint32_t   type )
     267{
     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////////////////////////////////
     284int 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 )
     302    {
     303        printk("\n[ERROR] in %s : undefined fdid %d",
     304        __FUNCTION__, fdid );
     305        return -1;
     306    }
     307
     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//////////////////////////////////
     331int 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
    82402///////////////////////////////////
    83 error_t dev_nic_read( pkd_t * pkd )
    84 {
    85     error_t  error;
    86 
    87     // get pointers on this NIC-RX kernel thread
    88     thread_t * thread_ptr = CURRENT_THREAD;
    89     xptr_t     thread_xp  = XPTR( local_cxy , thread_ptr );
    90 
    91     // get local pointer on core running this kernel thead
    92     core_t * core = thread_ptr->core;
    93 
    94 // check thread can yield
    95 assert( (thread_ptr->busylocks == 0),
    96 "cannot yield : busylocks = %d\n", thread_ptr->busylocks );
     403int 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////////////////////////////////////
     531int 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////////////////////////////////////////////////////////////////////////////////////////
     679int 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///////////////////////////////////
     937int dev_nic_send( uint32_t    fdid,
     938                  uint8_t   * u_buf,
     939                  uint32_t    length )
     940{
     941#if DEBUG_DEV_NIC_TX
     942thread_t  * this    = CURRENT_THREAD;
     943process_t * process = this->process;
     944trdid_t     trdid   = this->trdid;
     945pid_t       pid     = process->pid;
     946uint32_t cycle = (uint32_t)hal_get_cycle();
     947if (DEBUG_DEV_NIC_TX < cycle )
     948printk("[%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
     958cycle = (uint32_t)hal_get_cycle();
     959if (DEBUG_DEV_NIC_TX < cycle )
     960printk("[%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///////////////////////////////////
     969int dev_nic_recv( uint32_t    fdid,
     970                  uint8_t   * u_buf,
     971                  uint32_t    length )
     972{
     973#if DEBUG_DEV_NIC_RX
     974thread_t  * this    = CURRENT_THREAD;
     975process_t * process = this->process;
     976trdid_t     trdid   = this->trdid;
     977pid_t       pid     = process->pid;
     978uint32_t    cycle   = (uint32_t)hal_get_cycle();
     979if (DEBUG_DEV_NIC_RX < cycle )
     980printk("[%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
     990cycle = (uint32_t)hal_get_cycle();
     991if (DEBUG_DEV_NIC_RX < cycle )
     992printk("[%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/////////////////////////////////////
     1001int 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
     1008thread_t  * this    = CURRENT_THREAD;
     1009process_t * process = this->process;
     1010trdid_t     trdid   = this->trdid;
     1011pid_t       pid     = process->pid;
     1012uint32_t cycle = (uint32_t)hal_get_cycle();
     1013if (DEBUG_DEV_NIC_TX < cycle )
     1014printk("[%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
     1026cycle = (uint32_t)hal_get_cycle();
     1027if (DEBUG_DEV_NIC_TX < cycle )
     1028printk("[%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///////////////////////////////////////
     1037int 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
     1044thread_t  * this    = CURRENT_THREAD;
     1045process_t * process = this->process;
     1046trdid_t     trdid   = this->trdid;
     1047pid_t       pid     = process->pid;
     1048uint32_t    cycle   = (uint32_t)hal_get_cycle();
     1049if (DEBUG_DEV_NIC_RX < cycle )
     1050printk("[%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
     1062cycle = (uint32_t)hal_get_cycle();
     1063if (DEBUG_DEV_NIC_RX < cycle )
     1064printk("[%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
     1076
     1077
     1078
     1079///////////////////////////////////////////////////////////////////////////////////////////
     1080//               Functions called by the NIC_RX server thread
     1081///////////////////////////////////////////////////////////////////////////////////////////
     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/////////////////////////////////////////////////////////////////////////////////////////
     1091static 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///////////////////////////////////////////////////////////////////////////////////////////
     1116error_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///////////////////////////////////////////////////////////////////////////////////////////
     1148error_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;
    971153
    981154#if DEBUG_DEV_NIC_RX
    991155uint32_t cycle = (uint32_t)hal_get_cycles();
    1001156if( DEBUG_DEV_NIC_RX < cycle )
    101 printk("\n[DBG] %s : thread %x enters for packet %x in cluster %x\n",
    102 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     1157printk("\n[%s] thread[%x,%x] enters / cycle %d\n",
     1158__FUNCTION__, this->process->pid, this->trdid, cycle );
    1031159#endif
    1041160
    105     // get pointer on NIC-RX chdev descriptor
    106     uint32_t   channel = thread_ptr->chdev->channel;
    107     xptr_t     dev_xp  = chdev_dir.nic_rx[channel];
    108     cxy_t      dev_cxy = GET_CXY( dev_xp );
    109     chdev_t  * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    110 
    111     assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" );
    112 
    113     assert( (dev_cxy == local_cxy) , " chdev must be local" );
    114 
    115     // initialize command in thread descriptor
    116     thread_ptr->nic_cmd.dev_xp = dev_xp;
    117 
    118     // call driver to test readable
    119     thread_ptr->nic_cmd.cmd = NIC_CMD_READABLE;
    120     dev_ptr->cmd( thread_xp );
     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;
    1211170
    1221171    // check error
    123     error = thread_ptr->nic_cmd.error;
    124     if( error ) return error;
    125 
    126     // block and deschedule if queue non readable
    127     if( thread_ptr->nic_cmd.status == false ) 
    128     {
    129         // enable NIC-RX IRQ
    130         dev_pic_enable_irq( core->lid , dev_xp );
    131 
    132         // block client thread on THREAD_BLOCKED_IO
    133         thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO );
    134 
    135         // deschedule client thread
    136         sched_yield("client blocked on I/O");
    137 
    138         // disable NIC-RX IRQ
    139         dev_pic_disable_irq( core->lid , dev_xp );
    140     }
    141 
    142     // call driver for actual read
    143     thread_ptr->nic_cmd.cmd     = NIC_CMD_READ;
    144     thread_ptr->nic_cmd.buffer  = pkd->buffer;
    145     dev_ptr->cmd( thread_xp );
    146 
    147     // check error
    148     error = thread_ptr->nic_cmd.error;
    149     if( error ) return error;
    150 
    151     // returns packet length   
    152     pkd->length = thread_ptr->nic_cmd.length;
     1172    if( this->nic_cmd.error )
     1173    {
    1531174
    1541175#if DEBUG_DEV_NIC_RX
    1551176cycle = (uint32_t)hal_get_cycles();
    1561177if( DEBUG_DEV_NIC_RX < cycle )
    157 printk("\n[DBG] %s : thread %x exit for packet %x in cluster %x\n",
    158 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     1178printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n",
     1179__FUNCTION__, this->process->pid, this->trdid, cycle );
    1591180#endif
    1601181
     1182        return -1;
     1183    }
     1184    else
     1185    {
     1186
     1187#if DEBUG_DEV_NIC_RX
     1188cycle = (uint32_t)hal_get_cycles();
     1189if( DEBUG_DEV_NIC_RX < cycle )
     1190printk("\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()
     1198
     1199///////////////////////////////////////////////////////////////////////////////////////////
     1200// This static function is called by the dev_nic_rx_server() function.
     1201// It analyses an Ethernet frame contained in the kernel buffer defined
     1202// by the <buffer> argument, and returns in the  <ip_length> argument the length
     1203// of the IP packet contained in the Ethernet packet payload.
     1204///////////////////////////////////////////////////////////////////////////////////////////
     1205// @ buffer     : [in] pointer on a received Ethernet packet
     1206// @ ip_length  : [out] length of IP packet (in bytes).
     1207// @ return 0 if success / return -1 if illegal packet length.
     1208///////////////////////////////////////////////////////////////////////////////////////////
     1209static error_t dev_nic_rx_check_eth( uint8_t  * buffer,
     1210                                     uint32_t * ip_length )
     1211{
     1212    uint32_t length = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13];
     1213
     1214    *ip_length = length;
     1215
    1611216    return 0;
    162 
    163 }   // end dev_nic_read()
    164 
    165 
    166 ////////////////////////////////////
    167 error_t dev_nic_write( pkd_t * pkd )
    168 {
    169     error_t error;
    170 
    171     // get pointers on the NIC-TX kernel tread
    172     thread_t * thread_ptr = CURRENT_THREAD;
    173     xptr_t     thread_xp  = XPTR( local_cxy , thread_ptr );
    174 
    175     // get local pointer on core running this kernel thead
    176     core_t * core = thread_ptr->core;
     1217}
     1218   
     1219///////////////////////////////////////////////////////////////////////////////////////////
     1220// This static function analyses the IP packet contained in the kernel buffer
     1221// defined by the <buffer> argument, and returns in the <ip_src_addr>, <ip_dst_addr>,
     1222// <header_length> and <protocol> arguments the informations contained in the IP header.
     1223// It checks the IP packet length versus the value contained in Ethernet header.
     1224// It checks the IP header checksum.
     1225///////////////////////////////////////////////////////////////////////////////////////////
     1226// @ buffer          : [in] pointer on the IP packet.
     1227// @ expected_length : [in] expected IP packet length (from Ethernet header).
     1228// @ ip_src_addr     : [out] source IP address.
     1229// @ ip_dst_addr     : [out] destination IP address.
     1230// @ protocol        : [out] transport protocol type.
     1231// @ return 0 if success / return -1 if illegal packet.
     1232///////////////////////////////////////////////////////////////////////////////////////////
     1233static error_t dev_nic_rx_check_ip( uint8_t  * buffer,
     1234                                    uint32_t   expected_length,
     1235                                    uint32_t * ip_src_addr,
     1236                                    uint32_t * ip_dst_addr,
     1237                                    uint32_t * trsp_protocol )
     1238{
     1239    uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
     1240
     1241    // discard packet if eth_length != ip_length
     1242    if( length != expected_length )
     1243    {
     1244
     1245#if DEBUG_NIC_DEV
     1246thread_t * this = CURRENT_THREAD;
     1247printk("\n[%s] thread[%x,%x] enters : length (%d) != expected_length (%d)\n",
     1248__FUNCTION__, this->process->pid, this->trdid, length, expected_length );
     1249#endif
     1250
     1251        return -1;
     1252    }
     1253
     1254    // compute IP header checksum
     1255    uint32_t received_cs = (uint32_t)dev_nic_ip_checksum( buffer );
     1256
     1257    // extract IP header checksum
     1258    uint32_t computed_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);
     1259
     1260    // discard packet if bad checksum
     1261    if( received_cs != computed_cs )
     1262    {
     1263
     1264#if DEBUG_NIC_DEV
     1265thread_t * this = CURRENT_THREAD;
     1266printk("\n[%s] thread[%x,%x] computed checksum (%d) != received checksum (%d)\n",
     1267__FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs );
     1268#endif
     1269
     1270        return -1;
     1271    }
     1272
     1273
     1274    *ip_src_addr = ((uint32_t)buffer[12] << 24) |
     1275                   ((uint32_t)buffer[13] << 16) |
     1276                   ((uint32_t)buffer[14] <<  8) |
     1277                   ((uint32_t)buffer[15]      ) ;
     1278
     1279    *ip_dst_addr = ((uint32_t)buffer[16] << 24) |
     1280                   ((uint32_t)buffer[17] << 16) |
     1281                   ((uint32_t)buffer[18] <<  8) |
     1282                   ((uint32_t)buffer[19]      ) ;
     1283
     1284    *trsp_protocol = (uint32_t)buffer[9];
     1285   
     1286    return 0;
     1287}
     1288
     1289///////////////////////////////////////////////////////////////////////////////////////////
     1290// This static function analyses the UDP packet contained in the kernel buffer
     1291// defined by the <k_buf> and <k_length> arguments.
     1292// It checks the UDP checksum, and discard corrupted packets.
     1293// It scans the list of sockets attached to the NIC_RX chdev to find a matching socket,
     1294// and discard the received packet if no UDP socket found.
     1295// Finally, it copies the payload to the socket "rx_buf", as long as the packet payload
     1296// is not larger than the rx_buf.
     1297// It set the "rx_valid" flip-flop, and unblock the client thread when the last expected
     1298// byte has been received.
     1299///////////////////////////////////////////////////////////////////////////////////////////
     1300// @ chdev         : [in] local pointer on local NIC_RX chdev descriptor.
     1301// @ k_buf         : [in] pointer on the UDP packet in local kernel buffer.
     1302// @ k_length      : [in] number of bytes in buffer (including UDP header).
     1303// @ pkt_src_addr  : [in] source IP address (from IP packet header).
     1304// @ pkt_dst_addr  : [in] destination IP address (from IP packet header).
     1305///////////////////////////////////////////////////////////////////////////////////////////
     1306static void dev_nic_rx_handle_udp_packet( chdev_t  * chdev,
     1307                                          uint8_t  * k_buf,
     1308                                          uint32_t   k_length,
     1309                                          uint32_t   pkt_src_addr,
     1310                                          uint32_t   pkt_dst_addr )
     1311{
     1312    xptr_t     root_xp;           // extended pointer on attached sockets list root
     1313    xptr_t     lock_xp;           // extended pointer on chdev lock
     1314    xptr_t     iter_xp;           // iterator on socket list
     1315    xptr_t     socket_xp;         // extended pointer on socket descriptor
     1316    cxy_t      socket_cxy;
     1317    socket_t * socket_ptr;
     1318    uint32_t   socket_type;       // socket type
     1319    uint32_t   socket_state;      // socket state
     1320    uint32_t   local_addr;        // local IP address from socket
     1321    uint32_t   local_port;        // local port from socket
     1322    uint32_t   remote_addr;       // remote IP address from socket
     1323    uint32_t   remote_port;       // remote port from socket
     1324    bool_t     match_socket;      // matching socket found
     1325    uint16_t   checksum;          // computed checksum
     1326    uint16_t   pkt_checksum;      // received checksum
     1327    xptr_t     socket_rbuf_xp;    // extended pointer on socket rx_buf
     1328    xptr_t     socket_lock_xp;    // extended pointer on socket lock
     1329    xptr_t     socket_client_xp;  // extended pointer on socket rx_client field
     1330    xptr_t     client_xp;         // extended pointer on client thread descriptor
     1331    uint32_t   payload;           // number of bytes in payload
     1332    uint32_t   status;            // number of bytes in rx_buf
     1333    uint32_t   space;             // number of free slots in rx_buf
     1334    uint32_t   moved_bytes;       // number of bytes actually moved to rx_buf
     1335
     1336    // build extended pointers on list of sockets attached to NIC_RX chdev
     1337    root_xp = XPTR( local_cxy , &chdev->wait_root );
     1338    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
     1339
     1340    // compute UDP packet checksum
     1341    checksum = dev_nic_udp_checksum( k_buf , k_length );
     1342
     1343    // get checksum from received packet header
     1344    pkt_checksum = ((uint16_t)k_buf[6] << 8) | (uint16_t)k_buf[7];
     1345
     1346    // discard corrupted packet 
     1347    if( pkt_checksum != checksum ) return;
     1348   
     1349    // get src_port and dst_port from UDP header
     1350    uint32_t pkt_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
     1351    uint32_t pkt_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
     1352
     1353    // discard unexpected packet
     1354    if( xlist_is_empty( root_xp ) ) return;
     1355 
     1356    // take the tock protecting the sockets list
     1357    remote_busylock_acquire( lock_xp );
     1358
     1359    match_socket = false;
     1360
     1361    // scan sockets list to find a match
     1362    XLIST_FOREACH( root_xp , iter_xp )
     1363    {
     1364        // get socket cluster and local pointer
     1365        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
     1366        socket_ptr = GET_PTR( socket_xp );
     1367        socket_cxy = GET_CXY( socket_xp );
     1368
     1369        // get socket type
     1370        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
     1371        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
     1372               
     1373        // skip TCP socket
     1374        if( socket_type == SOCK_STREAM ) continue;
     1375
     1376        // get relevant info from socket descriptor
     1377        local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     1378        remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     1379        local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     1380        remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     1381
     1382        // compute matching
     1383        bool_t local_match  = (local_addr  == pkt_dst_addr) &&
     1384                              (local_port  == pkt_dst_port);
     1385
     1386        bool_t remote_match = (remote_addr == pkt_src_addr) &&
     1387                              (remote_port == pkt_src_port);
     1388
     1389        if (socket_state == UDP_STATE_CONNECT ) match_socket = local_match && remote_match;
     1390        else                                    match_socket = local_match;
     1391
     1392        // exit loop when socket found
     1393        if( match_socket ) break;
     1394    }
     1395
     1396    // release the lock protecting the sockets list
     1397    remote_busylock_release( lock_xp );
     1398
     1399    // discard unexpected packet
     1400    if( match_socket == false ) return;
     1401   
     1402    // build extended pointers on various socket fields
     1403    socket_rbuf_xp   = XPTR( socket_cxy , &socket_ptr->rx_buf );
     1404    socket_lock_xp   = XPTR( socket_cxy , &socket_ptr->lock );
     1405    socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client );
     1406
     1407    // take the lock protecting the socket
     1408    remote_rwlock_wr_acquire( socket_lock_xp );
     1409
     1410    // get status & space from rx_buf
     1411    status = remote_buf_status( socket_rbuf_xp );
     1412    space  = NIC_RX_BUF_SIZE - status;
     1413
     1414    // get client thread
     1415    client_xp  = hal_remote_l64( socket_client_xp );
     1416
     1417    // get number of bytes in payload
     1418    payload = k_length - UDP_HEAD_LEN;
     1419
     1420    // compute number of bytes to move : min (space , seg_payload)
     1421    moved_bytes = ( space < payload ) ? space : payload;
     1422
     1423    // move payload from kernel buffer to socket rx_buf
     1424    remote_buf_put_from_kernel( socket_rbuf_xp,
     1425                                 k_buf + UDP_HEAD_LEN,
     1426                                 moved_bytes );
     1427
     1428    // unblock client thread if registered
     1429    if( client_xp != XPTR_NULL )
     1430    {
     1431        thread_unblock( client_xp , THREAD_BLOCKED_IO );
     1432    }
     1433
     1434    // release the lock protecting the socket
     1435    remote_rwlock_wr_release( socket_lock_xp );
     1436
     1437}  // end dev_nic_rx_handle_udp_packet()
     1438
     1439///////////////////////////////////////////////////////////////////////////////////////////
     1440// This static function is called by the dev_nic_rx_server() function to handle one RX
     1441// 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.
     1444///////////////////////////////////////////////////////////////////////////////////////////
     1445// 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).
     1463///////////////////////////////////////////////////////////////////////////////////////////
     1464static void dev_nic_rx_handle_tcp_segment( chdev_t  * chdev,
     1465                                           uint8_t  * k_buf,
     1466                                           uint32_t   k_length,
     1467                                           uint32_t   seg_src_addr,
     1468                                           uint32_t   seg_dst_addr )
     1469{
     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 );
     1496
     1497    // 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];
     1500
     1501    uint32_t seg_seq_num  = ((uint32_t)k_buf[4]  << 24) |
     1502                            ((uint32_t)k_buf[5]  << 16) |
     1503                            ((uint32_t)k_buf[6]  <<  8) |
     1504                            ((uint32_t)k_buf[7]       );
     1505
     1506    uint32_t seg_ack_num  = ((uint32_t)k_buf[8]  << 24) |
     1507                            ((uint32_t)k_buf[9]  << 16) |
     1508                            ((uint32_t)k_buf[10] <<  8) |
     1509                            ((uint32_t)k_buf[11]      );
     1510
     1511    uint8_t  seg_hlen     = k_buf[12] >> 2;       // TCP header length in bytes
     1512 
     1513    uint8_t  seg_flags    = k_buf[13];
     1514
     1515    bool_t   seg_ack_set  = ((seg_flags & TCP_FLAG_ACK) != 0);
     1516    bool_t   seg_syn_set  = ((seg_flags & TCP_FLAG_SYN) != 0);
     1517    bool_t   seg_fin_set  = ((seg_flags & TCP_FLAG_FIN) != 0);
     1518    bool_t   seg_rst_set  = ((seg_flags & TCP_FLAG_RST) != 0);
     1519
     1520    uint16_t seg_window   = ((uint32_t)k_buf[14] << 8) | (uint32_t)k_buf[15];
     1521
     1522    uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17];
     1523
     1524    uint32_t seg_payload  = k_length - seg_hlen;  // number of bytes in payload
     1525
     1526    // 1. compute TCP checksum
     1527    checksum = dev_nic_tcp_checksum( k_buf,
     1528                                     k_length,
     1529                                     seg_src_addr,
     1530                                     seg_dst_addr );
     1531
     1532    // discard segment if corrupted
     1533    if( seg_checksum != checksum ) return;
     1534   
     1535    match_socket = false;
     1536
     1537    // take the lock protecting the list of sockets
     1538    remote_busylock_acquire( lock_xp );
     1539
     1540    // 2. scan list of sockets to find a matching socket
     1541    XLIST_FOREACH( root_xp , iter_xp )
     1542    {
     1543        // get socket cluster and local pointer
     1544        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
     1545        socket_ptr = GET_PTR( socket_xp );
     1546        socket_cxy = GET_CXY( socket_xp );
     1547
     1548        // get socket type and state
     1549        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
     1550        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
     1551               
     1552        // skip UDP socket
     1553        if( socket_type == SOCK_DGRAM ) continue;
     1554
     1555        // 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 ));
     1560               
     1561        // compute matching condition
     1562        // (in LISTEN state, remote_port and remote_addr can be unspecified)
     1563        if( socket_state == TCP_STATE_LISTEN )
     1564        {
     1565            match_socket = (local_addr  == seg_dst_addr) &&
     1566                           (local_port  == seg_dst_port) ;
     1567        }
     1568        else
     1569        {
     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 )
     1619            {
     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
     1628                    break;
     1629                }
     1630
     1631                // [3] handle SYN flag
     1632                if( seg_syn_set )
     1633                {
     1634                    // 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                }               
     1670                break;
     1671            }
     1672            ////////////////////////
     1673            case TCP_STATE_SYN_SENT:
     1674            {
     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
     1696                if( seg_rst_set )
     1697                {
     1698                    // TODO signal "error: connection reset" to user
     1699
     1700                    // 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                    }
     1749                }
     1750                break;
     1751            }
     1752            ////////////////////////
     1753            case TCP_STATE_SYN_RCVD:
     1754            case TCP_STATE_ESTAB:
     1755            case TCP_STATE_FIN_WAIT1:
     1756            case TCP_STATE_FIN_WAIT2:
     1757            case TCP_STATE_CLOSE_WAIT:
     1758            case TCP_STATE_CLOSING:
     1759            case TCP_STATE_LAST_ACK:
     1760            case TCP_STATE_TIME_WAIT:
     1761            {
     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                {
     1776                    // discard segment
     1777                    return;
     1778                }
     1779
     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 ) )
     1830                    {
     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                    {
     1864                        // discard segment
     1865                        break;
     1866                    }
     1867               
     1868                    // specific for FIN_WAIT1
     1869                    if( socket_state == TCP_STATE_FIN_WAIT1 )
     1870                    {
     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                        }
     1877                    }
     1878
     1879                    // specific for CLOSING
     1880                    if( socket_state == TCP_STATE_CLOSING )
     1881                    {
     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                        }
     1893                    }
     1894                }
     1895                else if( socket_state == TCP_STATE_LAST_ACK )
     1896                {
     1897                    if( seg_ack_set )
     1898                    {
     1899                        // update socket.state
     1900                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
     1901                                              TCP_STATE_TIME_WAIT );
     1902                    }
     1903                   
     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 )
     1911                {
     1912                    if( (socket_state == TCP_STATE_ESTAB)     ||
     1913                        (socket_state == TCP_STATE_FIN_WAIT1) ||
     1914                        (socket_state == TCP_STATE_FIN_WAIT2) )
     1915                    {
     1916                        // get number of bytes already stored in rx_buf
     1917                        uint32_t status = remote_buf_status( socket_rx_buf_xp );
     1918
     1919                        // compute empty space in rx_buf
     1920                        uint32_t space = NIC_RX_BUF_SIZE - status;
     1921
     1922                        // compute number of bytes to move : min (space , seg_payload)
     1923                        uint32_t nbytes = ( space < seg_payload ) ? space : seg_payload;
     1924
     1925                        // move payload from k_buf to rx_buf
     1926                        remote_buf_put_from_kernel( socket_rx_buf_xp,
     1927                                                    k_buf + seg_hlen,
     1928                                                    nbytes );
     1929                        // update socket.rx_nxt
     1930                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1931                                              socket_rx_nxt + nbytes );
     1932
     1933                        // update socket.rx_wnd
     1934                        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 )
     1946                        {
     1947                            thread_unblock( client_xp , THREAD_BLOCKED_IO );
     1948                        }
     1949                    }
     1950                }
     1951
     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) )
     1960                    {
     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
     1973                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
     1974                                        socket_rx_nxt + 1 );
     1975
     1976                        if( (socket_state == TCP_STATE_SYN_RCVD) ||
     1977                            (socket_state == TCP_STATE_ESTAB) )
     1978                        {
     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                        }
     2012                    }
     2013                }  // end if FIN
     2014            }  // end case sockets synchronized
     2015        }  // end switch socket state
     2016
     2017        // release the lock protecting socket
     2018        remote_rwlock_wr_acquire( socket_lock_xp );
     2019
     2020    }  // end socket found
     2021
     2022}  // end dev_nic_rx_handle_tcp_segment()
     2023
     2024
     2025/////////////////////////////////////////
     2026void dev_nic_rx_server( chdev_t * chdev )
     2027{
     2028    uint8_t       k_buf[2048];          // kernel buffer for one ETH/IP/UDP packet
     2029                                 
     2030    uint32_t      pkt_src_addr;         // packet source IP address
     2031    uint32_t      pkt_dst_addr;         // packet destination IP address
     2032    uint32_t      trsp_protocol;        // transport protocol (TCP / UDP)
     2033    uint32_t      eth_length;           // size of Ethernet packet (bytes)
     2034    uint32_t      ip_length;            // size of IP packet in bytes
     2035    uint32_t      nic_queue_readable;   // NIC_RX queue non empty when true
     2036    error_t       error;
     2037
     2038    thread_t * this = CURRENT_THREAD;
     2039
     2040// check chdev direction and type
     2041assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == true) ,
     2042"illegal chdev type or direction" );
    1772043
    1782044// check thread can yield
    179 assert( (thread_ptr->busylocks == 0),
    180 "cannot yield : busylocks = %d\n", thread_ptr->busylocks );
     2045assert( (this->busylocks == 0),
     2046"cannot yield : busylocks = %d\n", this->busylocks );
     2047
     2048    while( 1 )
     2049    {
     2050        // check NIC_RX_QUEUE readable
     2051        error = dev_nic_rx_queue_readable( chdev,
     2052                                           &nic_queue_readable );
     2053        if( error )
     2054        {
     2055            printk("\n[PANIC] in %s : cannot access NIC_TX[%d] queue\n",
     2056            __FUNCTION__, chdev->channel );
     2057        }
     2058   
     2059        if( nic_queue_readable ) // NIC_TX_QUEUE non empty
     2060        {
     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            }
     2070
     2071            // analyse the ETH header
     2072            error = dev_nic_rx_check_eth( k_buf,
     2073                                          &ip_length );
     2074
     2075            // discard packet if error reported by Ethernet layer
     2076            if( error ) continue;
     2077
     2078            // analyse the IP header
     2079            error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN,
     2080                                         ip_length,
     2081                                         &pkt_src_addr,
     2082                                         &pkt_dst_addr,
     2083                                         &trsp_protocol );
     2084
     2085            // discard packet if error reported by IP layer
     2086            if( error ) continue;
     2087
     2088            // call relevant transport protocol
     2089            if( trsp_protocol == PROTOCOL_UDP )   
     2090            {
     2091                dev_nic_rx_handle_udp_packet( chdev,
     2092                                              k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
     2093                                              ip_length - IP_HEAD_LEN,
     2094                                              pkt_src_addr,
     2095                                              pkt_dst_addr );
     2096            }
     2097            else if ( trsp_protocol == PROTOCOL_TCP)
     2098            {
     2099                dev_nic_rx_handle_tcp_segment( chdev,
     2100                                               k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
     2101                                               ip_length - IP_HEAD_LEN,
     2102                                               pkt_src_addr,
     2103                                               pkt_dst_addr );
     2104            }
     2105        }
     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
     2112    } // end of while loop
     2113
     2114}  // end dev_nic_rx_server()
     2115
     2116
     2117
     2118
     2119
     2120
     2121
     2122
     2123
     2124
     2125///////////////////////////////////////////////////////////////////////////////////////////
     2126//              Functions used by the NIC_TX server thread
     2127///////////////////////////////////////////////////////////////////////////////////////////
     2128
     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///////////////////////////////////////////////////////////////////////////////////////////
     2141static 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////////////////////////////////////////////////////////////
     2163static 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///////////////////////////////////////////////////////////////////////////////////////////
     2194error_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.
     2218// It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and
     2219// <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.
     2229///////////////////////////////////////////////////////////////////////////////////////////
     2230// @ chdev   : [in] local pointer on NIC_TX chdev.
     2231// @ buffer  : [in] pointer on a local kernel buffer (2K bytes).
     2232// @ length  : [in] actual Ethernet packet length in bytes.
     2233///////////////////////////////////////////////////////////////////////////////////////////
     2234void dev_nic_tx_move_packet( chdev_t  * chdev,
     2235                             uint8_t  * buffer,
     2236                             uint32_t   length )
     2237{
     2238    error_t    error;
     2239    uint32_t   writable;
     2240
     2241    thread_t * this = CURRENT_THREAD;
     2242
     2243    // get extended pointers on server tread and chdev
     2244    xptr_t     thread_xp = XPTR( local_cxy , this );
     2245    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
     2246
     2247    // get local pointer on core running this server thead
     2248    core_t * core = this->core;
     2249
     2250// check thread can yield
     2251assert( (this->busylocks == 0),
     2252"cannot yield : busylocks = %d\n", this->busylocks );
    1812253
    1822254#if DEBUG_DEV_NIC_RX
    1832255uint32_t cycle = (uint32_t)hal_get_cycles();
    1842256if( DEBUG_DEV_NIC_RX < cycle )
    185 printk("\n[DBG] %s : thread %x enters for packet %x in cluster %x\n",
    186 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     2257printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n",
     2258__FUNCTION__, this->process->pid, this->trdid, pkd, cycle );
    1872259#endif
    1882260
    189     // get pointer on NIC-TX chdev descriptor
    190     uint32_t   channel = thread_ptr->chdev->channel;
    191     xptr_t     dev_xp  = chdev_dir.nic_tx[channel];
    192     cxy_t      dev_cxy = GET_CXY( dev_xp );
    193     chdev_t  * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    194 
    195     assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" );
    196 
    197     assert( (dev_cxy == local_cxy) , " chdev must be local" );
    198 
    199     // initialize command in thread descriptor
    200     thread_ptr->nic_cmd.dev_xp = dev_xp;
    201 
    202     // call driver to test writable
    203     thread_ptr->nic_cmd.cmd = NIC_CMD_WRITABLE;
    204     dev_ptr->cmd( thread_xp );
    205 
    206     // check error
    207     error = thread_ptr->nic_cmd.error;
    208     if( error ) return error;
    209 
    210     // block and deschedule if queue non writable
    211     if( thread_ptr->nic_cmd.status == false ) 
    212     {
    213         // enable NIC-TX IRQ
    214         dev_pic_enable_irq( core->lid ,dev_xp );
    215 
    216         // block client thread on THREAD_BLOCKED I/O condition
    217         thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO );
    218 
    219         // deschedule client thread
    220         sched_yield("client blocked on I/O");
    221 
    222         // disable NIC-TX IRQ
    223         dev_pic_disable_irq( core->lid , dev_xp );
    224     }
    225 
    226     // call driver for actual write
    227     thread_ptr->nic_cmd.cmd    = NIC_CMD_WRITE;
    228     thread_ptr->nic_cmd.buffer = pkd->buffer;
    229     thread_ptr->nic_cmd.length = pkd->length;
    230     dev_ptr->cmd( thread_xp );
    231 
    232     // check error
    233     error = thread_ptr->nic_cmd.error;
    234     if( error ) return error;
     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    }
     2292
     2293    // initialize WRITE command in server thread descriptor
     2294    this->nic_cmd.dev_xp = chdev_xp;
     2295    this->nic_cmd.type   = NIC_CMD_WRITE;
     2296    this->nic_cmd.buffer = buffer;
     2297    this->nic_cmd.length = length;
     2298
     2299    // call driver to move packet
     2300    chdev->cmd( thread_xp );
    2352301
    2362302#if DEBUG_DEV_NIC_RX
    2372303cycle = (uint32_t)hal_get_cycles();
    2382304if( DEBUG_DEV_NIC_RX < cycle )
    239 printk("\n[DBG] %s : thread %x exit for packet %x in cluster %x\n",
    240 __FUNCTION__ , thread_ptr , pkd , local_cxy );
     2305printk("\n[%s] thread[%x,%x] exit for packet %x\n",
     2306__FUNCTION__ , this->process->pid, this->trdid , pkd );
    2412307#endif
    2422308
    243     return 0;
    244 }  // end dev_nic_write()
    245 
    246 
    247 
     2309    return;
     2310
     2311}  // end dev_nic_tx_move_packet()
     2312
     2313///////////////////////////////////////////////////////////////////////////////////////////
     2314// This static function is called by the dev_nic_tx_server() function to build an UDP
     2315// header in the kernel buffer defined by the <k_buf> arguement,  as specified by the
     2316// <socket_xp> argument. The <length> argument defines the number of bytes in payload.
     2317// It set the "src_port", "dst_port", "total_length" and "checksum" fields in UDP header.
     2318// The payload must be previouly loaded in the pernel buffer.
     2319///////////////////////////////////////////////////////////////////////////////////////////
     2320// @ k_buf      : [in]  pointer on first byte of UDP header in kernel buffer.
     2321// @ socket_xp  : [in]  extended pointer on socket.
     2322// @ length     : [in]  number of bytes in payload.
     2323///////////////////////////////////////////////////////////////////////////////////////////
     2324void dev_nic_tx_build_udp_header( uint8_t  * k_buf,
     2325                                  xptr_t     socket_xp,
     2326                                  uint32_t   length )
     2327{
     2328    uint16_t   checksum;        // checksum value
     2329    uint32_t   total_length;    // total UDP packet length
     2330    uint32_t   local_addr;      // local IP address
     2331    uint32_t   remote_addr;     // remote IP address
     2332    uint32_t   local_port;      // local port
     2333    uint32_t   remote_port;     // remote port
     2334
     2335    // get socket cluster an local pointer
     2336    socket_t * socket_ptr = GET_PTR( socket_xp );
     2337    cxy_t      socket_cxy = GET_CXY( socket_xp );
     2338
     2339    // get relevant infos from socket
     2340    local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));
     2341    remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));
     2342    local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));
     2343    remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));
     2344
     2345    // compute UDP packet total length
     2346    total_length = length + UDP_HEAD_LEN;
     2347
     2348    // set src_port and dst_port in header
     2349    k_buf[0] = local_port >> 8;
     2350    k_buf[1] = local_port;
     2351    k_buf[2] = remote_port >> 8;
     2352    k_buf[3] = remote_port;
     2353
     2354    // set packet length in header
     2355    k_buf[4] = total_length >> 8;
     2356    k_buf[5] = total_length;
     2357   
     2358    // compute UDP packet checksum
     2359    checksum = dev_nic_udp_checksum( k_buf , total_length );
     2360
     2361    // set checksum
     2362    k_buf[6] = checksum >> 8;
     2363    k_buf[7] = checksum;
     2364
     2365}  // end dev_nic_tx_build_udp_header()
     2366
     2367///////////////////////////////////////////////////////////////////////////////////////////
     2368// This static function is called by the dev_nic_tx_server() function.
     2369// It builds a TCP header in the kernel buffer defined by the <k_buf> argument.
     2370// The payload must have been previouly registered in this buffer.
     2371// The "local_addr", "local_port", "remote_addr", "remote_port", seq_num", "ack_num",
     2372// and "window" fields are obtained from the <socket_xp> argument.
     2373// The <length> argument defines the number of bytes in payload, and the <flags> argument
     2374// defines the flags to be set in TCP header.
     2375///////////////////////////////////////////////////////////////////////////////////////////
     2376// @ k_buf      : [in]  pointer on first byte of TCP header in kernel buffer.
     2377// @ length     : [in]  number of bytes in payload.
     2378// @ socket_xp  : [in]  extended pointer on socket.
     2379// @ flags      : [in]  flags to be set in TCP header.
     2380///////////////////////////////////////////////////////////////////////////////////////////
     2381void dev_nic_tx_build_tcp_header( uint8_t  * k_buf,
     2382                                  uint32_t   length,
     2383                                  xptr_t     socket_xp,
     2384                                  uint8_t    flags )
     2385{
     2386    uint16_t   checksum;        // global segment checksum
     2387    uint32_t   total_length;    // total UDP packet length
     2388    uint32_t   src_addr;        // local IP address
     2389    uint32_t   dst_addr;        // remote IP address
     2390    uint16_t   src_port;        // local port
     2391    uint16_t   dst_port;        // remote port
     2392    uint32_t   seq_num;         // first byte of segment in TX stream
     2393    uint32_t   ack_num;         // next expected byte in RX stream
     2394    uint16_t   window;          // window of accepted segments in RX stream
     2395
     2396    // get socket cluster an local pointer
     2397    socket_t * sock_ptr = GET_PTR( socket_xp );
     2398    cxy_t      sock_cxy = GET_CXY( socket_xp );
     2399
     2400    // get relevant infos from socket
     2401    src_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_addr ));
     2402    dst_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_addr ));
     2403    src_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_port ));
     2404    dst_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_port ));
     2405    seq_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->tx_nxt ));
     2406    ack_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_nxt ));
     2407    window   = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_wnd ));
     2408
     2409    // compute TCP segment total length
     2410    total_length = length + TCP_HEAD_LEN;
     2411
     2412    // set "src_port" and "dst_port"
     2413    k_buf[0]  = src_port >> 8;
     2414    k_buf[1]  = src_port;
     2415    k_buf[2]  = dst_port >> 8;
     2416    k_buf[3]  = dst_port;
     2417
     2418    // set "seq_num" 
     2419    k_buf[4]  = seq_num >> 24;
     2420    k_buf[5]  = seq_num >> 16;
     2421    k_buf[6]  = seq_num >>  8;
     2422    k_buf[7]  = seq_num;
     2423
     2424    // set "ack_num" 
     2425    k_buf[8]  = ack_num >> 24;
     2426    k_buf[9]  = ack_num >> 16;
     2427    k_buf[10] = ack_num >>  8;
     2428    k_buf[11] = ack_num;
     2429
     2430    // set "hlen"
     2431    k_buf[12] = 5;
     2432
     2433    // set "flags"
     2434    k_buf[13] = flags & 0x3F;
     2435
     2436    // set "window"
     2437    k_buf[14] = window >> 8;
     2438    k_buf[15] = window;
     2439
     2440    // reset "checksum"
     2441    k_buf[16] = 0;
     2442    k_buf[17] = 0;
     2443   
     2444    // set "urgent_ptr"
     2445    k_buf[18] = 0;
     2446    k_buf[19] = 0;
     2447 
     2448    // compute TCP segment checksum
     2449    checksum = dev_nic_tcp_checksum( k_buf,
     2450                                     total_length,
     2451                                     src_addr,
     2452                                     dst_addr );
     2453    // set "checksum"
     2454    k_buf[16] = checksum >> 8;
     2455    k_buf[17] = checksum;
     2456
     2457}  // end dev_nic_tx_build_tcp_header()
     2458
     2459
     2460///////////////////////////////////////////////////////////////////////////////////////////
     2461// This static function is called by the dev_nic_tx_server() function.
     2462// It builds the IP header in the 20 first bytes of <buffer>.
     2463///////////////////////////////////////////////////////////////////////////////////////////
     2464// @ buffer     : pointer on first byte of IP header in kernel buffer
     2465// @ src_addr   : source IP address.
     2466// @ dst_addr   : destination IP address.
     2467// @ length     : number of bytes in IP packet payload.
     2468///////////////////////////////////////////////////////////////////////////////////////////
     2469void dev_nic_tx_build_ip_header( uint8_t * buffer,
     2470                                 uint32_t  src_addr,
     2471                                 uint32_t  dst_addr,
     2472                                 uint16_t  length )
     2473{
     2474    uint16_t   hcs;
     2475
     2476    uint16_t   total = length + IP_HEAD_LEN;
     2477
     2478    buffer[0]  = 0x45;         // IPV4 / IHL = 20 bytes 
     2479    buffer[1]  = 0;            // DSCP / ECN
     2480    buffer[2]  = total >> 8; 
     2481    buffer[3]  = total; 
     2482
     2483    buffer[4]  = 0x40;         // Don't Fragment
     2484    buffer[5]  = 0;
     2485    buffer[6]  = 0;
     2486    buffer[7]  = 0;
     2487
     2488    buffer[8]  = 0xFF;         // TTL
     2489    buffer[9]  = 0x11;         // UDP protocol
     2490   
     2491    buffer[12] = src_addr >> 24;
     2492    buffer[13] = src_addr >> 16;
     2493    buffer[14] = src_addr >> 8;
     2494    buffer[15] = src_addr;
     2495
     2496    buffer[16] = dst_addr >> 24;
     2497    buffer[17] = dst_addr >> 16;
     2498    buffer[18] = dst_addr >> 8;
     2499    buffer[19] = dst_addr;
     2500
     2501    // compute IP header checksum
     2502    hcs = dev_nic_ip_checksum( buffer );
     2503
     2504    // set checksum
     2505    buffer[10] = hcs >> 8;
     2506    buffer[11] = hcs;
     2507
     2508}  // end dev_nic_tx_build_ip_header
     2509
     2510///////////////////////////////////////////////////////////////////////////////////////////
     2511// This static function is called by the dev_nic_tx_server() function.
     2512// It builds the Ethernet header in the 14 first bytes of <buffer>.
     2513///////////////////////////////////////////////////////////////////////////////////////////
     2514// @ buffer     : pointer on first byte of Ethernet header in kernel buffer
     2515// @ src_mac_54 : two MSB bytes in source MAC address.
     2516// @ src_mac_32 : two MED bytes in source MAC address.
     2517// @ src_mac_10 : two LSB bytes in source MAC address.
     2518// @ dst_mac_54 : two MSB bytes in destination MAC address.
     2519// @ dst_mac_32 : two MED bytes in destination MAC address.
     2520// @ dst_mac_10 : two LSB bytes in destination MAC address.
     2521// @ length     : number of bytes in Ethernet frame payload.
     2522///////////////////////////////////////////////////////////////////////////////////////////
     2523void 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 )
     2531{
     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;
     2545
     2546    buffer[12] = length >> 8;
     2547    buffer[13] = length;
     2548
     2549}  // end dev_nic_tx_build_eth_header()
     2550
     2551///////////////////////////////////////////////////////////////////////////////////////////
     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:
     2561// 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///////////////////////////////////////////////////////////////////////////////////////////
     2570// @ socket_xp   : [in] extended pointer on client socket. 
     2571// @ k_buf       : [in] local pointer on kernel buffer (2 Kbytes).
     2572// @ chdev       : [in] local pointer on NIC_RX chdev.
     2573///////////////////////////////////////////////////////////////////////////////////////////
     2574static void dev_nic_tx_handle_one_cmd( xptr_t    socket_xp,
     2575                                       uint8_t * k_buf,
     2576                                       chdev_t * chdev )
     2577{
     2578    socket_t  * socket_ptr;
     2579    cxy_t       socket_cxy;
     2580    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
     2586    uint32_t    todo;            // number of bytes not yet sent
     2587    uint32_t    socket_type;     // socket type (UDP/TCP)
     2588    uint32_t    socket_state;    // socket state       
     2589    xptr_t      socket_lock_xp;  // extended pointer on socket lock
     2590    xptr_t      socket_r2tq_xp;  // extended pointer on R2T queue
     2591    uint32_t    src_ip_addr;     // source IP address
     2592    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
     2595    uint32_t    nbytes;          // number of bytes in UDP/TCP packet payload
     2596    uint8_t   * k_base;          // pointer UDP/TCP packet in kernel buffer
     2597    uint32_t    trsp_length;     // length of TCP/UDP packet
     2598    uint8_t     r2t_flags;       // flags defined by one R2T queue request
     2599    bool_t      do_send;         // build & send a packet when true
     2600 
     2601    // get socket cluster and local pointer
     2602    socket_cxy = GET_CXY( socket_xp );
     2603    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 );
     2607    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
     2608
     2609    // 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
     2619    {
     2620        // 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 ));
     2625       
     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
     2630        // 3. UDP : build UDP packet and update UDP socket state
     2631        if( socket_type == SOCK_DGRAM )       
     2632        {
     2633            if( socket_state == UDP_STATE_UNBOUND )
     2634            {
     2635                // report illegal command
     2636                dev_nic_tx_report_error( socket_xp, cmd, socket_state );
     2637
     2638                do_send = false;
     2639            }
     2640            else  // BOUND or CONNECT state
     2641            {
     2642                if( cmd == SOCKET_TX_SEND )
     2643                {
     2644                    // compute payload length
     2645                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
     2646
     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 );
     2654                    // build UDP header
     2655                    dev_nic_tx_build_udp_header( k_base,
     2656                                                 socket_xp,
     2657                                                 nbytes );
     2658
     2659                    // 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 )
     2665                    {
     2666                        dev_nic_tx_report_success( socket_xp );
     2667                    }
     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;
     2677                }
     2678            }
     2679
     2680            // compute transport packet length
     2681            trsp_length = UDP_HEAD_LEN + nbytes;
     2682
     2683        }  // end UDP
     2684
     2685        // 3. TCP : build TCP segment and update TCP socket state
     2686        if( socket_type == SOCK_STREAM )
     2687        {
     2688            // extract one request from TCP socket R2T queue if queue non empty
     2689            if( remote_buf_status( socket_r2tq_xp ) )
     2690            {
     2691                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
     2692            }
     2693            else
     2694            {
     2695                r2t_flags = 0;
     2696            }
     2697
     2698            /////////////////////////////////////
     2699            if( socket_state == TCP_STATE_ESTAB )    // connected TCP socket
     2700            {
     2701                if( cmd == SOCKET_TX_SEND )         
     2702                {
     2703                    // get  "tx_nxt", and "tx_una" from socket descriptor
     2704                    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 ));
     2706
     2707                    // compute actual payload length
     2708                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
     2709
     2710                    // 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 );
     2717
     2718                    // build TCP header
     2719                    dev_nic_tx_build_tcp_header( k_base,
     2720                                                 socket_xp,
     2721                                                 nbytes,                       // payload
     2722                                                 TCP_FLAG_ACK | r2t_flags );   // flags
     2723
     2724                    // update "tx_todo" in socket descriptor
     2725                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_todo ),
     2726                                    todo - nbytes );
     2727
     2728                    // 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) )
     2734                    {
     2735                        dev_nic_tx_report_success( socket_xp );
     2736                    }
     2737
     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;
     2759                }
     2760            }
     2761            //////////////////////////////////////////
     2762            else if( socket_state == TCP_STATE_BOUND )  // unconnected TCP socket
     2763            {
     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                }
     2792            }
     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
     2887    {
     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        }
     2911    }
     2912
     2913    // 4. release the lock protecting the socket
     2914    remote_rwlock_wr_release( socket_lock_xp );
     2915
     2916    // return if no packet to send
     2917    if( do_send == false ) return;
     2918
     2919    // 5. build IP header
     2920    dev_nic_tx_build_ip_header( k_buf + ETH_HEAD_LEN,
     2921                                src_ip_addr,
     2922                                dst_ip_addr,
     2923                                IP_HEAD_LEN + trsp_length );
     2924
     2925    // 6. build ETH header
     2926    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
     2936    dev_nic_tx_move_packet( chdev,
     2937                            k_buf,
     2938                            ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
     2939
     2940}  // end dev_nic_tx_handle_one_cmd()
     2941
     2942/////////////////////////////////////////
     2943void dev_nic_tx_server( chdev_t * chdev )
     2944{
     2945    uint8_t       k_buf[NIC_KERNEL_BUF_SIZE];  // buffer for one packet
     2946
     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
     2950    socket_t    * socket_ptr;
     2951    cxy_t         socket_cxy;
     2952    xptr_t        entry_xp;        // extended pointer on socket tx_list entry
     2953
     2954    thread_t * this = CURRENT_THREAD;
     2955
     2956// check chdev direction and type
     2957assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == false) ,
     2958"illegal chdev type or direction" );
     2959
     2960// check thread can yield
     2961assert( (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 );
     2967
     2968    while( 1 )  // TX server infinite loop
     2969    {
     2970        // 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 )
     2975        {
     2976            // release the lock protecting the TX client sockets queue
     2977            remote_busylock_release( lock_xp );
     2978 
     2979            // block and deschedule
     2980            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT );
     2981            sched_yield( "waiting client" );
     2982        }
     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
     3015}  // end dev_nic_tx_server()
     3016
     3017
Note: See TracChangeset for help on using the changeset viewer.