source: trunk/kernel/devices/dev_nic.c @ 657

Last change on this file since 657 was 657, checked in by alain, 23 months ago

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

File size: 118.1 KB
Line 
1/*
2 * dev_nic.c - NIC (Network Controler) generic device API implementation.
3 *
4 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_special.h>
26#include <hal_uspace.h>
27#include <remote_buf.h>
28#include <printk.h>
29#include <chdev.h>
30#include <thread.h>
31#include <socket.h>
32#include <hal_drivers.h>
33#include <dev_nic.h>
34#include <vfs.h>
35#include <shared_socket.h>
36
37/////////////////////////////////////////////////////////////////////////////////////////
38//                 Extern global variables
39/////////////////////////////////////////////////////////////////////////////////////////
40
41extern 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}
214
215//////////////////////////////////
216void dev_nic_init( chdev_t * nic )
217{
218    // get "channel" & "is_rx" fields from chdev descriptor
219    uint32_t  channel = nic->channel;
220    bool_t    is_rx   = nic->is_rx;
221
222    // set chdev name
223    if( is_rx ) snprintf( nic->name , 16 , "nic%d_rx" , channel );
224    else        snprintf( nic->name , 16 , "nic%d_tx" , channel );
225
226    // call driver init function
227    hal_drivers_nic_init( nic );
228
229    // select a core to execute the NIC server thread
230    lid_t lid = cluster_select_local_core( local_cxy );
231
232    // bind the NIC IRQ to the selected core
233    // but does NOT enable it
234    dev_pic_bind_irq( lid , nic );
235
236    // create server thread
237    thread_t * new_thread;
238    error_t    error;
239
240    error = thread_kernel_create( &new_thread,
241                                  THREAD_DEV,
242                                  &chdev_server_func,
243                                  nic,
244                                  lid ); 
245
246    assert( (error == 0) , "cannot create server thread" );
247
248    // set "server" field in chdev descriptor
249    nic->server = new_thread;
250   
251    // set "chdev" field in thread descriptor
252    new_thread->chdev = nic;
253
254    // unblock server thread
255    thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
256
257}  // end dev_nic_init()
258
259
260/////////////////////////////////////////////////////////////////////////////////////////
261//                 Functions implementing the SOCKET related syscalls
262/////////////////////////////////////////////////////////////////////////////////////////
263
264//////////////////////////////////////
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
402///////////////////////////////////
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;
1153
1154#if DEBUG_DEV_NIC_RX
1155uint32_t cycle = (uint32_t)hal_get_cycles();
1156if( DEBUG_DEV_NIC_RX < cycle )
1157printk("\n[%s] thread[%x,%x] enters / cycle %d\n", 
1158__FUNCTION__, this->process->pid, this->trdid, cycle );
1159#endif
1160
1161    // initialize NIC_READ command in thread descriptor
1162    this->nic_cmd.type    = NIC_CMD_READ;
1163    this->nic_cmd.buffer  = k_buf;
1164
1165    // call NIC driver 
1166    chdev->cmd( XPTR( local_cxy , this ) );
1167
1168    // returns packet length   
1169    *length = this->nic_cmd.length;
1170
1171    // check error
1172    if( this->nic_cmd.error ) 
1173    {
1174
1175#if DEBUG_DEV_NIC_RX
1176cycle = (uint32_t)hal_get_cycles();
1177if( DEBUG_DEV_NIC_RX < cycle )
1178printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n", 
1179__FUNCTION__, this->process->pid, this->trdid, cycle );
1180#endif
1181
1182        return -1;
1183    }
1184    else
1185    {
1186
1187#if DEBUG_DEV_NIC_RX
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
1216    return 0;
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" );
2043
2044// check thread can yield
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 );
2253
2254#if DEBUG_DEV_NIC_RX
2255uint32_t cycle = (uint32_t)hal_get_cycles();
2256if( DEBUG_DEV_NIC_RX < cycle )
2257printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n", 
2258__FUNCTION__, this->process->pid, this->trdid, pkd, cycle );
2259#endif
2260
2261    // check NIC_TX_QUEUE writable
2262    while( 1 )
2263    {
2264        error = dev_nic_tx_queue_writable( chdev,
2265                                           length,
2266                                           &writable );
2267        if( error )
2268        {
2269            printk("\n[PANIC] in %s : cannot access NIC_TX queue\n", __FUNCTION__ );
2270            return;
2271        }
2272           
2273        if( writable == 0 )  // block & deschedule if non writable
2274        {
2275            // enable NIC-TX IRQ
2276            dev_pic_enable_irq( core->lid , chdev_xp );
2277
2278            // block TX server thread
2279            thread_block( thread_xp , THREAD_BLOCKED_ISR );
2280
2281            // deschedule TX server thread
2282            sched_yield("client blocked on NIC_TX queue full");
2283
2284            // disable NIC-TX IRQ
2285            dev_pic_disable_irq( core->lid , chdev_xp );
2286        }
2287        else                // exit loop if writable
2288        {
2289            break;
2290        }
2291    }
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 );
2301
2302#if DEBUG_DEV_NIC_RX
2303cycle = (uint32_t)hal_get_cycles();
2304if( DEBUG_DEV_NIC_RX < cycle )
2305printk("\n[%s] thread[%x,%x] exit for packet %x\n", 
2306__FUNCTION__ , this->process->pid, this->trdid , pkd );
2307#endif
2308
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 TracBrowser for help on using the repository browser.