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

Last change on this file since 679 was 674, checked in by alain, 4 years ago

1) Introduce up to 4 command lines arguments in the KSH "load" command.
These arguments are transfered to the user process through the
argc/argv mechanism, using the user space "args" vseg.

2) Introduce the named and anonymous "pipes", for inter-process communication
through the pipe() and mkfifo() syscalls.

3) Introduce the "chat" application to validate the two above mechanisms.

4) Improve printk() and assert() fonctions in printk.c.

File size: 117.6 KB
RevLine 
[663]1
[1]2/*
3 * dev_nic.c - NIC (Network Controler) generic device API implementation.
4 *
[657]5 * Author  Alain Greiner    (2016,2017,2018,2019,2020)
[1]6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
[457]25#include <hal_kernel_types.h>
[1]26#include <hal_special.h>
[657]27#include <hal_uspace.h>
28#include <remote_buf.h>
[663]29#include <memcpy.h>
[1]30#include <printk.h>
[3]31#include <chdev.h>
[1]32#include <thread.h>
[663]33#include <ksocket.h>
[259]34#include <hal_drivers.h>
[1]35#include <dev_nic.h>
[657]36#include <vfs.h>
37#include <shared_socket.h>
[1]38
39/////////////////////////////////////////////////////////////////////////////////////////
[657]40//                 Extern global variables
[1]41/////////////////////////////////////////////////////////////////////////////////////////
42
[3]43extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
[1]44
[663]45////////////////////////////////////
46void dev_nic_init( chdev_t * chdev )
47{
48    thread_t * new_thread;
49    error_t    error;
50
51    // get "channel" & "is_rx" fields from chdev descriptor
52    uint32_t  channel = chdev->channel;
53    bool_t    is_rx   = chdev->is_rx;
54
55    // set chdev name
[674]56    if( is_rx ) snprintk( chdev->name , 16 , "nic%d_rx" , channel );
57    else        snprintk( chdev->name , 16 , "nic%d_tx" , channel );
[663]58
59    // initialize the root of the listening sockets list
60    xlist_root_init( XPTR( local_cxy , &chdev->ext.nic.root ) );
61
62    // initialize the lock protecting this list
63    remote_busylock_init( XPTR( local_cxy , &chdev->ext.nic.lock ),
64                          LOCK_LISTEN_SOCKET );
65
66    // call driver init function for this chdev
67    hal_drivers_nic_init( chdev );
68
69    // select a core to execute the NIC server thread
70    lid_t lid = cluster_select_local_core( local_cxy );
71
72    // bind the NIC IRQ to the selected core
73    dev_pic_bind_irq( lid , chdev );
74
75    // build pointer on server function
76    void * func = is_rx ? &dev_nic_rx_server : &dev_nic_tx_server;
77
78    // create server thread
79    error = thread_kernel_create( &new_thread,
80                                  THREAD_DEV,
81                                  func,
82                                  chdev,
83                                  lid ); 
84    if( error )
85    {
86        printk("\n[PANIC] in %s : cannot create server thread\n", __FUNCTION__ );
87        return;
88    }
89
90    // set "server" field in chdev descriptor
91    chdev->server = new_thread;
92   
93    // set "chdev" field in thread descriptor
94    new_thread->chdev = chdev;
95
96    // unblock server thread
97    thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
98
99#if (DEBUG_DEV_NIC_TX || DEBUG_DEV_NIC_RX)
100thread_t * this = CURRENT_THREAD;
101if( is_rx )
102printk("\n[%s] thread[%x,%x] initialized NIC_RX[%d] / server %x\n",
103__FUNCTION__, this->process->pid, this->trdid, channel, new_thread->trdid );
104else
105printk("\n[%s] thread[%x,%x] initialized NIC_TX[%d] / server %x\n",
106__FUNCTION__, this->process->pid, this->trdid, channel, new_thread->trdid );
107#endif
108   
109}  // end dev_nic_init()
110
111
112///////////////////////////////////////////////////////////////////////////////////////////
113//      Functions directly called by the client threads
114///////////////////////////////////////////////////////////////////////////////////////////
115
116////////////////////////////////////////
117uint32_t dev_nic_get_key( uint32_t addr,
118                          uint16_t port )
119{
120    thread_t * this = CURRENT_THREAD;
121   
122    xptr_t dev_xp = chdev_dir.nic_tx[0];
123    chdev_t * dev_ptr = GET_PTR( dev_xp );
124
125    if( dev_xp == XPTR_NULL ) return -1;
126   
127    // set command arguments in client thread descriptor
128    this->nic_cmd.buffer = (uint8_t *)addr;
129    this->nic_cmd.length = (uint32_t)port;
130    this->nic_cmd.dev_xp = dev_xp;
131    this->nic_cmd.type   = NIC_CMD_GET_KEY;
132
133    // call driver
134    dev_ptr->cmd( XPTR( local_cxy , this ) );
135
136    // get "status"
137    return this->nic_cmd.status;
138}
139
140//////////////////////////////////////////
141error_t dev_nic_set_run( uint32_t channel,
142                         uint32_t run )
143{
144    thread_t * this = CURRENT_THREAD;
145
146    if( channel >= LOCAL_CLUSTER->nb_nic_channels ) return -1;
147
148    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
149    chdev_t * dev_ptr = GET_PTR( dev_xp );
150
151    if( dev_xp == XPTR_NULL ) return -1;
152   
153    // set command arguments in client thread descriptor
154    this->nic_cmd.dev_xp = dev_xp;
155    this->nic_cmd.type   = NIC_CMD_SET_RUN;
156    this->nic_cmd.length = channel;
157    this->nic_cmd.status = run;
158
159    // call driver
160    dev_ptr->cmd( XPTR( local_cxy , this ) );
161
162    // return "error"
163    return this->nic_cmd.error;
164}
165
166//////////////////////////////////
167error_t dev_nic_get_instru( void )
168{
169    thread_t * this = CURRENT_THREAD;
170
171    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
172    chdev_t * dev_ptr = GET_PTR( dev_xp );
173   
174    if( dev_xp == XPTR_NULL ) return -1;
175   
176    // set command arguments in client thread descriptor
177    this->nic_cmd.dev_xp = dev_xp;
178    this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
179
180    // call driver
181    dev_ptr->cmd( XPTR( local_cxy , this ) );
182
183    // return "error"
184    return this->nic_cmd.error;
185}
186
187////////////////////////////////////
188error_t dev_nic_clear_instru( void )
189{
190    thread_t * this = CURRENT_THREAD;
191
192    xptr_t    dev_xp  = chdev_dir.nic_tx[0];
193    chdev_t * dev_ptr = GET_PTR( dev_xp );
194   
195    if( dev_xp == XPTR_NULL ) return -1;
196   
197    // set command arguments in client thread descriptor
198    this->nic_cmd.dev_xp = dev_xp;
199    this->nic_cmd.type   = NIC_CMD_GET_INSTRU;
200
201    // call driver
202    dev_ptr->cmd( XPTR( local_cxy , this ) );
203
204    // return "error"
205    return this->nic_cmd.error;
206}
207
208
[657]209////////////////////////////////////////////////////////////////////////////////////////////
[663]210//      Static functions called by the NIC_RX server & NIC_TX server threads
[657]211////////////////////////////////////////////////////////////////////////////////////////////
[663]212
213////////////////////////////////////////////////////////////////////////////////////////////
214// This static function is used by the dev_nic_rx_handle_tcp() function
215// to check acceptability of a given sequence number. It returns true when
216// the <seq> argument is contained in a wrap-around window defined by the
217// <min> and <max> arguments. The window wrap-around when (min > max).
218////////////////////////////////////////////////////////////////////////////////////////////
[657]219// @ seq   : [in] value to be checked.
220// @ min   : [in] first  base.
221// @ max   : [in] window size.
222////////////////////////////////////////////////////////////////////////////////////////////
223static inline bool_t is_in_window( uint32_t seq,
224                                   uint32_t min,
225                                   uint32_t max )
226{
227    if( max >= min )    // no wrap_around => only one window [min,max]
228    {
229        return( (seq >= min) && (seq <= max) ); 
230    }
231    else                // window wrap-around => two windows [min,0xFFFFFFFF] and [0,max]
232    {
233        return( (seq <= max) || (seq >= min) );
234    }
235} 
236
237////////////////////////////////////////////////////////////////////////////////////////
238// This static function computes the checksum for an IP packet header.
239// The "checksum" field itself is not taken into account for this computation.
240////////////////////////////////////////////////////////////////////////////////////////
241// @ buffer      : [in] pointer on IP packet header (20 bytes)
242// @ return the checksum value on 16 bits
243////////////////////////////////////////////////////////////////////////////////////////
[663]244static uint16_t dev_nic_ip_checksum( uint8_t  * buffer )
[657]245{
246    uint32_t   i;           
247    uint32_t   cs;      // 32 bits accumulator
248    uint16_t * buf;     
249   
250    buf = (uint16_t *)buffer;
251
252    // compute checksum
253    for( i = 0 , cs = 0 ; i < 10 ; i++ )
254    {
255        if( i != 5 )  cs += buf[i];
256    }
257
258    // one's complement
259    return ~cs;
260}
261
262////////////////////////////////////////////////////////////////////////////////////////
263// This static function computes the checksum for an UDP packet defined by
264// the <buffer> and <size> arguments.
265////////////////////////////////////////////////////////////////////////////////////////
266// @ buffer      : [in] pointer on UDP packet base.
267// @ size        : [in] number of bytes in this packet (including header).
268// @ return the checksum value on 16 bits
269////////////////////////////////////////////////////////////////////////////////////////
[663]270static uint16_t dev_nic_udp_checksum( uint8_t  * buffer,
271                                      uint32_t   size )
[657]272{
273    uint32_t   i;           
274    uint32_t   carry;
275    uint32_t   cs;      // 32 bits accumulator
276    uint16_t * buf;     
277    uint32_t   max;     // number of uint16_t in packet
278   
279    // compute max & buf
280    buf = (uint16_t *)buffer;
281    max = size >> 1;
282
283    // extend buffer[] if required
284    if( size & 1 )
285    {
286        max++;
287        buffer[size] = 0;
288    }
289
290    // compute checksum for UDP packet
291    for( i = 0 , cs = 0 ; i < size ; i++ )  cs += buf[i];
292
293    // handle carry
294    carry = (cs >> 16);
295    if( carry ) 
296    {
297        cs += carry; 
298        carry = (cs >> 16);
299        if( carry ) cs += carry;
300    } 
301
302    // one's complement
303    return ~cs;
304}
305
306////////////////////////////////////////////////////////////////////////////////////////
[663]307// This static function computes the checksum for a TCP segment defined by the <buffer>
308// and <size> arguments. It includes the pseudo header defined by the <src_ip_addr>,
309// <dst_ip_addr>, <size> arguments, and by the TCP_PROTOCOL code.
[657]310////////////////////////////////////////////////////////////////////////////////////////
311// @ buffer      : [in] pointer on TCP segment base.
[663]312// @ tcp_length  : [in] number of bytes in this TCP segment (including header).
[657]313// @ src_ip_addr : [in] source IP address (pseudo header)
314// @ dst_ip_addr : [in] destination IP address (pseudo header)
315// @ return the checksum value on 16 bits
316////////////////////////////////////////////////////////////////////////////////////////
[663]317static uint16_t dev_nic_tcp_checksum( uint8_t  * buffer,
318                                      uint32_t   tcp_length,
319                                      uint32_t   src_ip_addr,
320                                      uint32_t   dst_ip_addr )
[657]321{
322    uint32_t   i;           
323    uint32_t   carry;
324    uint32_t   cs;      // 32 bits accumulator
325    uint16_t * buf;
326    uint32_t   max;     // number of uint16_t in segment
327
328    // compute max & buf
329    buf = (uint16_t *)buffer;
[663]330    max = tcp_length >> 1;
[657]331
332    // extend buffer[] if required
[663]333    if( tcp_length & 1 )
[657]334    {
335        max++;
[663]336        buffer[tcp_length] = 0;
[657]337    }
338
339    // compute checksum for TCP segment
[663]340    for( i = 0 , cs = 0 ; i < tcp_length ; i++ )  cs += buf[i];
[657]341
342    // complete checksum for pseudo-header
343    cs += src_ip_addr;
344    cs += dst_ip_addr;
345    cs += PROTOCOL_TCP;
[663]346    cs += tcp_length;
[657]347
348    // handle carry
349    carry = (cs >> 16);
350    if( carry ) 
351    {
352        cs += carry; 
353        carry = (cs >> 16);
354        if( carry ) cs += carry;
355    } 
356
357    // one's complement
358    return ~cs;
359}
360
[663]361///////////////////////////////////////////////////////////////////////////////////////////
[674]362// This static function is called by the NIC_TX or NIC_RX server threads to unblock
[663]363// the TX client thread after completion (success or error) of a TX command registered
364// in a socket identified by the <socket_xp> argument. The <status> argument defines
365// the command success/failure status: a null value signals a success, a non-null value
366// signals a failure. For all commands, it copies the status value in the tx_sts field,
367// and print an error message on TXT0 in case of failure.
368///////////////////////////////////////////////////////////////////////////////////////////
369// @ socket_xp  : [in] extended pointer on socket
370// @ status     : [in] command status (see above)
371///////////////////////////////////////////////////////////////////////////////////////////
372static void dev_nic_unblock_tx_client( xptr_t   socket_xp,
373                                       int32_t  status )
[1]374{
[663]375    // get socket thread cluster and local pointer
376    socket_t * socket_ptr = GET_PTR( socket_xp );
377    cxy_t      socket_cxy = GET_CXY( socket_xp );
[1]378
[663]379    if( status != CMD_STS_SUCCESS )
[657]380    {
[663]381        uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
382        uint32_t cmd_type   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
383        pid_t    pid        = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
384        fdid_t   fdid       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
[657]385
[668]386        printk("\n[WARNING] reported by %s : socket[%x,%d] / %s / cmd %s / status %s \n",
[663]387        __FUNCTION__, pid, fdid, socket_state_str(sock_state),
388        socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) );
[657]389    }
390
[663]391    // set tx_sts field in socket descriptor
392    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_sts ) , status );
[657]393
[663]394    // get extended point on TX client thread
395    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
[657]396
[663]397    // unblock the client thread
398    thread_unblock( client_xp , THREAD_BLOCKED_IO );
[657]399
[663]400}  // end dev_nic_unblock_tx_client()
[657]401
[663]402///////////////////////////////////////////////////////////////////////////////////////////
[674]403// This static function is called by the NIC_TX or NIC_RX server threads to unblock
[663]404// the RX client thread after completion (success or error) of an RX command registered
405// in a socket identified by the <socket_xp> argument. The <status> argument defines
406// the command success/failure status: a null value signals a success, a non-null value
407// signals a failure. For all commands, it copies the status value in the rx_sts field,
408// and print an error message on TXT0 in case of failure.
409///////////////////////////////////////////////////////////////////////////////////////////
410// @ socket_xp  : [in] extended pointer on socket
411// @ status     : [in] command status (see above)
412///////////////////////////////////////////////////////////////////////////////////////////
413static void dev_nic_unblock_rx_client( xptr_t   socket_xp,
414                                       int32_t  status )
[657]415{
[663]416    // get socket thread cluster and local pointer
417    socket_t * socket_ptr = GET_PTR( socket_xp );
418    cxy_t      socket_cxy = GET_CXY( socket_xp );
[657]419
[663]420    if( status != CMD_STS_SUCCESS )
[657]421    {
[663]422        uint32_t sock_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
423        uint32_t cmd_type   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->rx_cmd ));
424        pid_t    pid        = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
425        fdid_t   fdid       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
[657]426
[668]427        printk("\n[WARNING] reported by %s : socket[%x,%d] / %s / cmd %s / status %s\n",
[663]428        __FUNCTION__, pid, fdid, socket_state_str(sock_state),
429        socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) );
[657]430    }
431
[663]432    // set rx_sts field in socket descriptor
433    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_sts ) , status );
[657]434
[663]435    // get extended point on RX client thread
436    xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->rx_client ));
[657]437
[663]438    // unblock the client thread
439    thread_unblock( client_xp , THREAD_BLOCKED_IO );
[657]440
[663]441}  // end dev_nic_unblock_rx_client()
[657]442
443///////////////////////////////////////////////////////////////////////////////////////////
444//               Functions called by the NIC_RX server thread
445///////////////////////////////////////////////////////////////////////////////////////////
446
447///////////////////////////////////////////////////////////////////////////////////////////
448// This static function is called by the dev_nic_rx_server() function.
449// It analyses an Ethernet frame contained in the kernel buffer defined
450// by the <buffer> argument, and returns in the  <ip_length> argument the length
451// of the IP packet contained in the Ethernet packet payload.
452///////////////////////////////////////////////////////////////////////////////////////////
453// @ buffer     : [in] pointer on a received Ethernet packet
454// @ ip_length  : [out] length of IP packet (in bytes).
455// @ return 0 if success / return -1 if illegal packet length.
456///////////////////////////////////////////////////////////////////////////////////////////
457static error_t dev_nic_rx_check_eth( uint8_t  * buffer,
458                                     uint32_t * ip_length )
459{
460    uint32_t length = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13];
461
462    *ip_length = length;
463
[1]464    return 0;
[657]465}
466   
467///////////////////////////////////////////////////////////////////////////////////////////
468// This static function analyses the IP packet contained in the kernel buffer
469// defined by the <buffer> argument, and returns in the <ip_src_addr>, <ip_dst_addr>,
470// <header_length> and <protocol> arguments the informations contained in the IP header.
471// It checks the IP packet length versus the value contained in Ethernet header.
472// It checks the IP header checksum.
473///////////////////////////////////////////////////////////////////////////////////////////
474// @ buffer          : [in] pointer on the IP packet.
475// @ expected_length : [in] expected IP packet length (from Ethernet header).
476// @ ip_src_addr     : [out] source IP address.
477// @ ip_dst_addr     : [out] destination IP address.
478// @ protocol        : [out] transport protocol type.
479// @ return 0 if success / return -1 if illegal packet.
480///////////////////////////////////////////////////////////////////////////////////////////
481static error_t dev_nic_rx_check_ip( uint8_t  * buffer,
482                                    uint32_t   expected_length, 
483                                    uint32_t * ip_src_addr, 
484                                    uint32_t * ip_dst_addr,
485                                    uint32_t * trsp_protocol )
486{
[663]487
488#if DEBUG_DEV_NIC_RX
489thread_t * this  = CURRENT_THREAD;
490uint32_t   cycle = (uint32_t)hal_get_cycles();
491#endif
492
493    // get packet length
[657]494    uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
[1]495
[663]496    // discard packet if eth_payload_length != ip_length
[657]497    if( length != expected_length )
498    {
[1]499
[663]500#if DEBUG_DEV_NIC_RX
501if( DEBUG_DEV_NIC_RX < cycle )
502printk("\n[%s] thread[%x,%x] failure : length (%d) != expected_length (%d)\n",
[657]503__FUNCTION__, this->process->pid, this->trdid, length, expected_length );
504#endif
[663]505        return -1;
506    }
[1]507
[663]508    // get transport protocol type
509    uint8_t protocol = buffer[9];
510
511    // discard packet if unsupported protocol
512    if( (protocol != PROTOCOL_TCP) && (protocol != PROTOCOL_UDP) )
513    {
514
515#if DEBUG_DEV_NIC_RX
516if( DEBUG_DEV_NIC_RX < cycle )
517printk("\n[%s] thread[%x,%x] failure : unsupported transport protocol (%d)\n",
518__FUNCTION__, this->process->pid, this->trdid, protocol );
519#endif
[657]520        return -1;
[663]521
[657]522    }
523    // compute IP header checksum
[663]524    uint32_t computed_cs = (uint32_t)dev_nic_ip_checksum( buffer );
[657]525
526    // extract IP header checksum
[663]527    uint32_t received_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);
[657]528
529    // discard packet if bad checksum
530    if( received_cs != computed_cs )
531    {
532
[663]533#if DEBUG_DEV_NIC_RX
534if( DEBUG_DEV_NIC_RX < cycle )
535printk("\n[%s] thread[%x,%x] failure : computed checksum (%d) != received checksum (%d)\n",
[657]536__FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs );
537#endif
538        return -1;
539    }
540
541
542    *ip_src_addr = ((uint32_t)buffer[12] << 24) |
543                   ((uint32_t)buffer[13] << 16) |
544                   ((uint32_t)buffer[14] <<  8) |
545                   ((uint32_t)buffer[15]      ) ;
546
547    *ip_dst_addr = ((uint32_t)buffer[16] << 24) |
548                   ((uint32_t)buffer[17] << 16) |
549                   ((uint32_t)buffer[18] <<  8) |
550                   ((uint32_t)buffer[19]      ) ;
551
[663]552    *trsp_protocol = protocol;
[657]553   
554    return 0;
555}
556
557///////////////////////////////////////////////////////////////////////////////////////////
558// This static function analyses the UDP packet contained in the kernel buffer
559// defined by the <k_buf> and <k_length> arguments.
560// It checks the UDP checksum, and discard corrupted packets.
561// It scans the list of sockets attached to the NIC_RX chdev to find a matching socket,
562// and discard the received packet if no UDP socket found.
563// Finally, it copies the payload to the socket "rx_buf", as long as the packet payload
564// is not larger than the rx_buf.
565// It set the "rx_valid" flip-flop, and unblock the client thread when the last expected
566// byte has been received.
567///////////////////////////////////////////////////////////////////////////////////////////
568// @ chdev         : [in] local pointer on local NIC_RX chdev descriptor.
569// @ k_buf         : [in] pointer on the UDP packet in local kernel buffer.
570// @ k_length      : [in] number of bytes in buffer (including UDP header).
571// @ pkt_src_addr  : [in] source IP address (from IP packet header).
572// @ pkt_dst_addr  : [in] destination IP address (from IP packet header).
573///////////////////////////////////////////////////////////////////////////////////////////
574static void dev_nic_rx_handle_udp_packet( chdev_t  * chdev,
575                                          uint8_t  * k_buf,
576                                          uint32_t   k_length,
577                                          uint32_t   pkt_src_addr,
578                                          uint32_t   pkt_dst_addr )
[1]579{
[657]580    xptr_t     root_xp;           // extended pointer on attached sockets list root
581    xptr_t     lock_xp;           // extended pointer on chdev lock
582    xptr_t     iter_xp;           // iterator on socket list
583    xptr_t     socket_xp;         // extended pointer on socket descriptor
584    cxy_t      socket_cxy;
585    socket_t * socket_ptr;
586    uint32_t   socket_type;       // socket type
587    uint32_t   socket_state;      // socket state
588    uint32_t   local_addr;        // local IP address from socket
589    uint32_t   local_port;        // local port from socket
590    uint32_t   remote_addr;       // remote IP address from socket
591    uint32_t   remote_port;       // remote port from socket
592    bool_t     match_socket;      // matching socket found
593    uint16_t   checksum;          // computed checksum
594    uint16_t   pkt_checksum;      // received checksum
595    xptr_t     socket_rbuf_xp;    // extended pointer on socket rx_buf
596    xptr_t     socket_lock_xp;    // extended pointer on socket lock
597    xptr_t     socket_client_xp;  // extended pointer on socket rx_client field
598    xptr_t     client_xp;         // extended pointer on client thread descriptor
599    uint32_t   payload;           // number of bytes in payload
600    uint32_t   status;            // number of bytes in rx_buf
601    uint32_t   space;             // number of free slots in rx_buf
602    uint32_t   moved_bytes;       // number of bytes actually moved to rx_buf
[1]603
[657]604    // build extended pointers on list of sockets attached to NIC_RX chdev
605    root_xp = XPTR( local_cxy , &chdev->wait_root );
606    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
[1]607
[657]608    // compute UDP packet checksum
609    checksum = dev_nic_udp_checksum( k_buf , k_length );
[1]610
[657]611    // get checksum from received packet header
612    pkt_checksum = ((uint16_t)k_buf[6] << 8) | (uint16_t)k_buf[7];
613
614    // discard corrupted packet 
615    if( pkt_checksum != checksum ) return;
616   
617    // get src_port and dst_port from UDP header
618    uint32_t pkt_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
619    uint32_t pkt_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
620
621    // discard unexpected packet
622    if( xlist_is_empty( root_xp ) ) return;
623 
[663]624    // take the lock protecting the sockets list
[657]625    remote_busylock_acquire( lock_xp );
626
627    match_socket = false;
628
629    // scan sockets list to find a match
630    XLIST_FOREACH( root_xp , iter_xp )
631    {
632        // get socket cluster and local pointer
633        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
634        socket_ptr = GET_PTR( socket_xp );
635        socket_cxy = GET_CXY( socket_xp );
636
637        // get socket type
638        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
639        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
640               
641        // skip TCP socket
642        if( socket_type == SOCK_STREAM ) continue;
643
644        // get relevant info from socket descriptor
645        local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 
646        remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 
647        local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 
648        remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 
649
650        // compute matching
651        bool_t local_match  = (local_addr  == pkt_dst_addr) && 
652                              (local_port  == pkt_dst_port);
653
654        bool_t remote_match = (remote_addr == pkt_src_addr) &&
655                              (remote_port == pkt_src_port);
656
[663]657        if (socket_state == UDP_STATE_ESTAB ) match_socket = local_match && remote_match;
658        else                                  match_socket = local_match;
[657]659
660        // exit loop when socket found
661        if( match_socket ) break;
662    }
663
664    // release the lock protecting the sockets list
665    remote_busylock_release( lock_xp );
666
667    // discard unexpected packet
668    if( match_socket == false ) return;
669   
670    // build extended pointers on various socket fields
671    socket_rbuf_xp   = XPTR( socket_cxy , &socket_ptr->rx_buf );
672    socket_lock_xp   = XPTR( socket_cxy , &socket_ptr->lock ); 
673    socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client );
674
675    // take the lock protecting the socket
[663]676    remote_queuelock_acquire( socket_lock_xp );
[657]677
678    // get status & space from rx_buf
679    status = remote_buf_status( socket_rbuf_xp );
[674]680    space  = CONFIG_SOCK_RX_BUF_SIZE - status;
[657]681
682    // get client thread
683    client_xp  = hal_remote_l64( socket_client_xp );
684
685    // get number of bytes in payload
686    payload = k_length - UDP_HEAD_LEN;
687
688    // compute number of bytes to move : min (space , seg_payload)
689    moved_bytes = ( space < payload ) ? space : payload;
690
691    // move payload from kernel buffer to socket rx_buf
692    remote_buf_put_from_kernel( socket_rbuf_xp,
693                                 k_buf + UDP_HEAD_LEN,
694                                 moved_bytes );
[663]695    // unblock client thread
[657]696    if( client_xp != XPTR_NULL )
697    {
698        thread_unblock( client_xp , THREAD_BLOCKED_IO );
699    }
700
701    // release the lock protecting the socket
[663]702    remote_queuelock_release( socket_lock_xp );
[657]703
704}  // end dev_nic_rx_handle_udp_packet()
705
706///////////////////////////////////////////////////////////////////////////////////////////
707// This static function is called by the dev_nic_rx_server() function to handle one RX
708// TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments.
[663]709// The <seg_remote_addr> and <seg_local_addr> arguments are obtained from the received
710// IP packet header. It the received segment doesn't match any connected socket attached
711// to the selected chdev[k], or any listening socket waiting connection, or if the segment
712// is corrupted, this segment is discarded.
713// If required by the TCP flags, it registers an R2T request in the socket R2T queue
714// to implement the TCP handcheck for close and connect.
[657]715///////////////////////////////////////////////////////////////////////////////////////////
716// Implementation note:
[663]717// A "connected" socket is actually a TCP socket already attached to a given NIC_RX[k]
718// chdev, and can therefore receive a TCP segment on the NIC channel <k>. A "listening"
719// socket is a TCP socket in the LISTEN state. This function operates in 6 steps:
720// 1) It checks the TCP checksum, and discard the corrupted segment if corrupted.
721// 2) It scans the list of sockets attached to the NIC_RX[k] chdev, to find one TCP
722//    socket matching the TCP segment header.
723// 3) When a matching connected socket is found, it handles the received segment, including
724//    the SYN, FIN, ACK and RST flags. It updates the socket state when required, moves
725//    data to the rx_buf when possible, and return. It takes the lock protecting the socket,
726//    because an connected socket is accessed by both the NIC_TX and NIC_RX server threads.
727// 4) If no matching connected socket has been found, it scans the list of listening
728//    sockets to find a matching listening socket.
729// 5) When a matching listening socket is found, it simply registers a new connection
730//    request in the listening socket CRQ queue, when the SYN flag is set, and insert
731//    a SYN-ACK request in the socket R2T queue.
732// 6) It discards the packet if no connected or listening socket has been found.
[657]733///////////////////////////////////////////////////////////////////////////////////////////
[663]734// @ chdev           : [in] local pointer on local NIC_RX chdev descriptor.
735// @ k_buf           : [in] pointer on the TCP packet in local kernel buffer.
736// @ k_length        : [in] number of bytes in buffer (including TCP header).
737// @ seg_remote_addr : [in] remote IP address (from IP packet header).
738// @ seg_local_addr  : [in] local IP address (from IP packet header).
[657]739///////////////////////////////////////////////////////////////////////////////////////////
740static void dev_nic_rx_handle_tcp_segment( chdev_t  * chdev,
741                                           uint8_t  * k_buf,
742                                           uint32_t   k_length,
[663]743                                           uint32_t   seg_remote_addr,
744                                           uint32_t   seg_local_addr )
[657]745{
[663]746    xptr_t     root_xp;            // extended pointer on connected sockets list root
747    xptr_t     lock_xp;            // extended pointer on chdev lock
748    xptr_t     iter_xp;            // iterator for these queues
749    bool_t     attached_match;     // true if one attached socket match
750    bool_t     listening_match;    // true if one listening socket match
751    xptr_t     socket_xp;          // extended pointer on matching socket
752    cxy_t      socket_cxy;         // cluster identifier of matching socket
753    socket_t * socket_ptr;         // local pointer on matching socket
754    uint32_t   socket_local_addr;  // local IP address from socket
755    uint32_t   socket_local_port;  // local port from socket
756    uint32_t   socket_remote_addr; // remote IP address from socket
757    uint32_t   socket_remote_port; // remote port from socket
758    uint32_t   socket_state;       // socket state
759    uint32_t   socket_type;        // socket type
760    bool_t     socket_tx_valid;    // TX command valid
761    uint32_t   socket_tx_cmd;      // TX command type
762    uint32_t   socket_tx_todo;     // number of TX bytes not sent yet
763    uint32_t   socket_tx_nxt;      // next byte to send in TX stream
764    uint32_t   socket_tx_una;      // first unacknowledged byte in TX stream
765    bool_t     socket_rx_valid;    // RX command valid
766    uint32_t   socket_rx_cmd;      // TX command type
767    uint32_t   socket_rx_nxt;      // next expected byte in RX stream
768    uint32_t   socket_rx_wnd;      // current window value in RX stream
769    uint32_t   socket_rx_irs;      // initial sequence index in RX stream
770    xptr_t     socket_lock_xp;     // extended pointer on lock protecting socket state
771    xptr_t     socket_rx_buf_xp;   // extended pointer on socket rx_buf
772    xptr_t     socket_r2tq_xp;     // extended pointer on socket R2T queue
773    xptr_t     socket_crqq_xp;     // extended pointer on socket CRQ queue
774    uint16_t   checksum;           // computed TCP segment chechsum
775    error_t    error;
[657]776
777    // get relevant infos from TCP segment header
[663]778    uint32_t seg_remote_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];
779    uint32_t seg_local_port  = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];
[657]780
781    uint32_t seg_seq_num  = ((uint32_t)k_buf[4]  << 24) | 
782                            ((uint32_t)k_buf[5]  << 16) |
783                            ((uint32_t)k_buf[6]  <<  8) |
784                            ((uint32_t)k_buf[7]       );
785
786    uint32_t seg_ack_num  = ((uint32_t)k_buf[8]  << 24) | 
787                            ((uint32_t)k_buf[9]  << 16) |
788                            ((uint32_t)k_buf[10] <<  8) |
789                            ((uint32_t)k_buf[11]      );
790
[663]791    uint8_t  seg_hlen     = k_buf[12] << 2;       // TCP header length in bytes
[657]792 
793    uint8_t  seg_flags    = k_buf[13];
794
795    bool_t   seg_ack_set  = ((seg_flags & TCP_FLAG_ACK) != 0);
796    bool_t   seg_syn_set  = ((seg_flags & TCP_FLAG_SYN) != 0);
797    bool_t   seg_fin_set  = ((seg_flags & TCP_FLAG_FIN) != 0);
798    bool_t   seg_rst_set  = ((seg_flags & TCP_FLAG_RST) != 0);
799
800    uint16_t seg_window   = ((uint32_t)k_buf[14] << 8) | (uint32_t)k_buf[15];
801
802    uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17];
803
[663]804    uint32_t seg_data_len = k_length - seg_hlen;  // number of bytes in payload
[657]805
[663]806#if DEBUG_DEV_NIC_RX
807thread_t * this = CURRENT_THREAD;
808uint32_t   cycle;
809uint32_t   fdid;
810pid_t      pid;
811#endif
812
813#if DEBUG_DEV_NIC_RX
814cycle = (uint32_t)hal_get_cycles();
815if( cycle > DEBUG_DEV_NIC_RX )
816printk("\n[%s] thread[%x,%x] enters / tcp_length %d / tcp_flags %x / cycle %d\n",
817__FUNCTION__, this->process->pid, this->trdid, k_length, seg_flags , cycle );
818#endif
819
820    // compute and check TCP checksum
821    k_buf[16] = 0;
822    k_buf[17] = 0;
[657]823    checksum = dev_nic_tcp_checksum( k_buf,
824                                     k_length,
[663]825                                     seg_remote_addr,
826                                     seg_local_addr );
[657]827
828    // discard segment if corrupted
[663]829    if( seg_checksum != checksum )
830    {
831
832#if DEBUG_DEV_NIC_RX
833if( cycle > DEBUG_DEV_NIC_RX )
834printk("\n[%s] thread[%x,%x] tcp checksum failure : received %x / computed %x\n",
835__FUNCTION__, this->process->pid, this->trdid, seg_checksum, checksum );
836#endif
837        return;
838    }
[657]839   
[663]840    // scan list of attached sockets to find a matching TCP socket
841    attached_match = false;
[657]842
[663]843    // build extended pointer on xlist of sockets attached to NIC_RX chdev
844    root_xp = XPTR( local_cxy , &chdev->wait_root );
845    lock_xp = XPTR( local_cxy , &chdev->wait_lock );
846
847    // take the lock protecting the list of attached sockets
[657]848    remote_busylock_acquire( lock_xp );
849
850    XLIST_FOREACH( root_xp , iter_xp )
851    {
852        // get socket cluster and local pointer
853        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
854        socket_ptr = GET_PTR( socket_xp );
855        socket_cxy = GET_CXY( socket_xp );
856
857        // get socket type and state
858        socket_type  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
859        socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
860               
861        // skip UDP socket
862        if( socket_type == SOCK_DGRAM ) continue;
863
864        // get relevant socket infos for matching
[663]865        socket_local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 
866        socket_remote_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 
867        socket_local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 
868        socket_remote_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 
[657]869               
[663]870        // compute matching condition for a connected socket
871        attached_match = (socket_local_addr  == seg_local_addr) && 
872                         (socket_local_port  == seg_local_port) &&
873                         (socket_remote_addr == seg_remote_addr) &&
874                         (socket_remote_port == seg_remote_port) ;
875
876        // exit loop if matching
877        if( attached_match ) 
[657]878        {
[663]879
880#if DEBUG_DEV_NIC_RX
881fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
882pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
883if( cycle > DEBUG_DEV_NIC_RX )
884printk("\n[%s] thread[%x,%x] matching attached socket[%d,%d] / state %s\n",
885__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
886#endif
887            break;
[657]888        }
889
[663]890    }  // end loop on attached sockets
[657]891
[663]892    // release the lock protecting the list of attached sockets
[657]893    remote_busylock_release( lock_xp );
894
[663]895    // handle TCP segment for an attached socket
896    if( attached_match )
897    {
898        // The actions depend on both the socket state and the received segment flags :
899        // - update socket state,
900        // - move data to rx_buf,
901        // - register a request in R2T queue when required
902 
903        // build extended pointers on various socket fields
904        socket_lock_xp    = XPTR( socket_cxy , &socket_ptr->lock );
905        socket_rx_buf_xp  = XPTR( socket_cxy , &socket_ptr->rx_buf );
906        socket_r2tq_xp    = XPTR( socket_cxy , &socket_ptr->r2tq );
[657]907
[663]908        // take the lock protecting the matching socket
909        remote_queuelock_acquire( socket_lock_xp );
[657]910
[663]911        // get relevant socket infos from socket descriptor
912        socket_tx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_valid ));
913        socket_tx_cmd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_cmd ));
914        socket_tx_todo  = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_todo ));
915        socket_tx_nxt   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt )); 
916        socket_tx_una   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una ));
[657]917
[663]918        socket_rx_valid = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_valid ));
919        socket_rx_cmd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_cmd ));
920        socket_rx_nxt   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt )); 
921        socket_rx_wnd   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd )); 
922        socket_rx_irs   = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_irs ));
[657]923
[663]924        // handle the received segment, depending on the matching socket state
925        switch( socket_state )
[657]926        {
[663]927            ////////////////////////
928            case TCP_STATE_SYN_SENT:  // TCP client waiting for SYN-ACK in connect handshake
[657]929            {
[663]930                // [1] check ACK flag
931                if( seg_ack_set )
932                {
933                    if( seg_ack_num != TCP_ISS_CLIENT + 1 )  // bad ACK => report error
934                    {
[657]935
[663]936#if DEBUG_DEV_NIC_RX
937printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
938__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
939socket_state_str(socket_state), TCP_ISS_CLIENT + 1, seg_ack_num );
940#endif
941                        // make an RST request to R2T queue
942                        socket_put_r2t_request( socket_r2tq_xp,
943                                                TCP_FLAG_RST,
944                                                chdev->channel );
945
946                        // report error to local TX client thread
947                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
948
949                        break;
950                    }
[657]951                }
952
[663]953                // [2] check RST flag                       // receive RST => report error
954                if( seg_rst_set )
[657]955                {
956
[663]957#if DEBUG_DEV_NIC_RX
958printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
959__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
960#endif
961                    // update socket state
962                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
963                                          TCP_STATE_BOUND );
[657]964
[663]965                    // signal error to local TX client thread
966                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
[657]967
[663]968                    break;
969                }
[657]970
[663]971                // [3] handle security & precedence TODO ... someday
972
973                // [4] handle SYN-ACK
974                if( seg_syn_set && seg_ack_set )  // received SYN and ACK => report success
975                { 
976
977#if DEBUG_DEV_NIC_RX
978printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected SYN-ACK\n",
979__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
980#endif
981                    // set socket.tx_una 
982                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
983
984                    // set socket.rx_irs
985                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->rx_irs), seg_seq_num );
986
987                    // set socket.rx_nxt
988                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->rx_nxt), seg_seq_num + 1 );
989
[657]990                    // update socket.state
[663]991                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_ESTAB );
[657]992
[663]993                    // make an ACK request to R2T queue
994                    socket_put_r2t_request( socket_r2tq_xp,
995                                            TCP_FLAG_ACK,
996                                            chdev->channel );
[657]997
[663]998                    // report succes to local TX client thread
999                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
1000                }
1001                else        // received SYN without ACK => client becomes server
1002                {
1003
1004#if DEBUG_DEV_NIC_RX
1005printk("\n[%s] thread[%x,%x] for socket[%x,%d] %s : received SYN-ACK => become server\n",
1006__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1007#endif
1008                    // update socket.state
1009                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->state), TCP_STATE_SYN_RCVD );
1010
1011                    // set socket.tx_nxt
1012                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
1013
1014                    // set socket.rx_nxt to seg_seq_num + 1
1015                    hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_nxt), seg_seq_num + 1 );
1016
1017                    // make a SYN.ACK request to R2T queue
1018                    socket_put_r2t_request( socket_r2tq_xp,
1019                                            TCP_FLAG_SYN | TCP_FLAG_ACK,
1020                                            chdev->channel );
1021                }
[657]1022                break;
1023            }
1024            ////////////////////////
[663]1025            case TCP_STATE_SYN_RCVD:  // TCP server waiting last ACK in connect handshake
[657]1026            {
[663]1027                // [1] check sequence number
1028                if( seg_seq_num != socket_rx_nxt )        // unexpected SEQ_NUM => discard
[657]1029                {
1030
[663]1031#if DEBUG_DEV_NIC_RX
1032printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect seq_num %x / get %x\n",
1033__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1034socket_state_str(socket_state), socket_rx_nxt, seg_seq_num );
1035#endif
1036                    // discard segment without reporting
1037                    break;
1038                } 
[657]1039
[663]1040                // [2] handle RST flag                    // received RST => report error
[657]1041                if( seg_rst_set )
1042                {
1043
[663]1044#if DEBUG_DEV_NIC_RX
1045printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
1046__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1047#endif
1048                    // update socket state
1049                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), TCP_STATE_BOUND );
[657]1050
[663]1051                    // report error to local TX client thread
1052                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST );
1053
[657]1054                    break;
1055                }
1056
[663]1057                // [3] handle security & precedence TODO ... someday
1058
1059                // [4] handle SYN flag
1060                if( seg_syn_set )                           // received SYN => discard
[657]1061                {
1062
[663]1063#if DEBUG_DEV_NIC_RX
1064printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received SYN flag\n",
1065__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1066#endif
1067                    // discard segment without reporting
1068                    break;
1069                } 
[657]1070
[663]1071                // [5] handle  ACK flag
1072                if( seg_ack_set == false )                      // missing ACK => discard
1073                {
[657]1074
[663]1075#if DEBUG_DEV_NIC_RX
1076printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK in TCP segment\n",
1077__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1078#endif
1079                    // discard segment without reporting
1080                    break;
1081                }
1082                else if( seg_ack_num != (TCP_ISS_SERVER + 1) )  // unacceptable ACK
1083                {
[657]1084
[663]1085#if DEBUG_DEV_NIC_RX
1086printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : expect ack_num %x / get %x\n",
1087__FUNCTION__, this->process->pid, this->trdid, pid, fdid, 
1088socket_state_str(socket_state), TCP_ISS_SERVER + 1, seg_ack_num );
1089#endif
[657]1090
[663]1091                    // register an RST request to R2TQ for remote TCP client
1092                    socket_put_r2t_request( socket_r2tq_xp,
1093                                            TCP_FLAG_RST,
1094                                            chdev->channel );
[657]1095
[663]1096                    // report error to local TX client thread
1097                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADACK );
1098                }
1099                else                                           // acceptable ACK
1100                {
[657]1101
[663]1102#if DEBUG_DEV_NIC_RX
1103printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received expected ACK\n",
1104__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1105#endif
1106                    // set socket.tx_una 
1107                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
1108
1109                    // update socket.state
1110                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), 
1111                                    TCP_STATE_ESTAB );
1112
1113                    // report success to local TX client thread
1114                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
[657]1115                }
1116                break;
1117            }
[663]1118            /////////////////////
[657]1119            case TCP_STATE_ESTAB:
1120            case TCP_STATE_FIN_WAIT1:
1121            case TCP_STATE_FIN_WAIT2:
1122            case TCP_STATE_CLOSE_WAIT:
1123            case TCP_STATE_CLOSING:
1124            case TCP_STATE_LAST_ACK:
1125            case TCP_STATE_TIME_WAIT:
1126            {
[663]1127                // [1] check sequence number : out_of_order segments not accepted
1128                if( seg_seq_num != socket_rx_nxt )
1129                {
[657]1130
[663]1131#if DEBUG_DEV_NIC_RX
1132printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : illegal SEQ_NUM %x / expected %x\n",
1133__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1134socket_state_str(socket_state), seg_seq_num, socket_rx_nxt );
1135#endif
1136                    // discard segment
1137                    break;
1138                } 
[657]1139
[663]1140                // check all bytes in window when the payload exist
1141                // TODO : we could accept bytes that are in window,
1142                // but this implementation reject all bytes in segment
1143                if( seg_data_len > 0 )
1144                {
1145                    // compute min & max acceptable sequence numbers
1146                    uint32_t seq_min  = socket_rx_nxt;
1147                    uint32_t seq_max  = socket_rx_nxt + socket_rx_wnd - 1;
[657]1148
[663]1149                    // compute sequence number for last byte in segment
1150                    uint32_t seg_seq_last = seg_seq_num + seg_data_len - 1;
1151                     
1152                    if( is_in_window( seg_seq_last, seq_min, seq_max ) == false ) 
1153                    {
1154
1155#if DEBUG_DEV_NIC_RX
1156printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : last SEQ_NUM %x not in [%x,%x]\n",
1157__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1158socket_state_str(socket_state), seg_seq_last, seq_min, seq_max );
1159#endif
1160                        // discard segment
1161                        break;
1162                    }
[657]1163                } 
1164
1165                // [2] handle RST flag
1166                if( seg_rst_set )
1167                {
1168
[663]1169#if DEBUG_DEV_NIC_RX
1170printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received RST flag\n",
1171__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
1172#endif
1173                    if( (socket_state == TCP_STATE_ESTAB     ) ||
1174                        (socket_state == TCP_STATE_FIN_WAIT1 ) ||
1175                        (socket_state == TCP_STATE_FIN_WAIT2 ) ||
1176                        (socket_state == TCP_STATE_CLOSE_WAIT) )
1177                    {
1178                        // TODO all pending send & received commands
1179                        // must receive "reset" responses
[657]1180
[663]1181                        // TODO destroy the socket
1182                    }
1183                    else  // states CLOSING / LAST_ACK / TIME_WAIT
1184                    {
1185                        // TODO         
1186                    }
1187                    break;
[657]1188                }
1189
1190                // [3] handle security & precedence TODO ... someday
1191
[663]1192                // [4] check SYN flag
1193                if( seg_syn_set )                                // received SYN => ERROR
1194                {
[657]1195
[663]1196#if DEBUG_DEV_NIC_RX
1197printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : received unexpected SYN\n",
1198__FUNCTION__, this->process->pid, this->trdid, pid, fdid , socket_state_str(socket_state) );
1199#endif
[657]1200                    // TODO signal error to user
1201
1202                    // make an RST request to R2T queue
[663]1203                    socket_put_r2t_request( socket_r2tq_xp, 
1204                                            TCP_FLAG_RST,
1205                                            chdev->channel );
1206
[657]1207                    // update socket state
[663]1208                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_BOUND );
1209
1210                    break;
[657]1211                }
1212
[663]1213                // [5] check ACK 
1214                if( seg_ack_set == false )                           // missing ACK
1215                {
[657]1216
[663]1217#if DEBUG_DEV_NIC_RX
1218printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : no ACK flag\n",
1219__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
1220#endif
1221                    // discard segment
[657]1222                    break;
1223                }
[663]1224                else if( is_in_window( seg_ack_num,
1225                                       socket_tx_una,
1226                                       socket_tx_nxt ) == false )    // unacceptable ACK
[657]1227                {
1228
[663]1229#if DEBUG_DEV_NIC_RX
1230printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : ACK_NUM %x not in [%x,%x]\n",
1231__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state),
1232seg_ack_num, socket_tx_una, socket_tx_nxt );
1233#endif
1234                    // discard segment
1235                    break;
[657]1236                }
[663]1237                else                                                // acceptable ack
[657]1238                {
[663]1239                    // update socket.tx_una
1240                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num );
[657]1241
[663]1242                    // update socket.tx_wnd 
1243                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_wnd), seg_window );
[657]1244
[663]1245                    // check last data byte acknowledged for a SEND command
1246                    if( (socket_tx_todo == 0) && 
1247                        (seg_ack_num == socket_tx_nxt) &&
1248                        (socket_tx_cmd == CMD_TX_SEND) )
[657]1249                    {
[663]1250                        // signal success to TX client thread
1251                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
[657]1252                    }
1253                }
1254                   
[663]1255                // [7] handle URG flag  TODO ... someday
[657]1256
[663]1257                // [8] Move DATA to rx_buf / ACK request to R2T queue / unblock rx_client
1258                if( seg_data_len )
[657]1259                {
1260                    if( (socket_state == TCP_STATE_ESTAB)     ||
1261                        (socket_state == TCP_STATE_FIN_WAIT1) ||
1262                        (socket_state == TCP_STATE_FIN_WAIT2) )
1263                    {
1264                        // get number of bytes already stored in rx_buf
1265                        uint32_t status = remote_buf_status( socket_rx_buf_xp );
1266
1267                        // compute empty space in rx_buf
[674]1268                        uint32_t space = CONFIG_SOCK_RX_BUF_SIZE - status;
[657]1269
[663]1270                        // compute number of bytes to move : min (space , seg_data_len)
1271                        uint32_t nbytes = ( space < seg_data_len ) ? space : seg_data_len;
[657]1272
1273                        // move payload from k_buf to rx_buf
1274                        remote_buf_put_from_kernel( socket_rx_buf_xp, 
1275                                                    k_buf + seg_hlen,
1276                                                    nbytes );
[663]1277#if DEBUG_DEV_NIC_RX
1278printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : move %d bytes to rx_buf\n",
1279__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1280socket_state_str(socket_state), nbytes );
1281#endif
[657]1282                        // update socket.rx_nxt
1283                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
1284                                              socket_rx_nxt + nbytes );
1285
1286                        // update socket.rx_wnd
1287                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ),
[663]1288                                              socket_rx_wnd - nbytes ); 
[657]1289
[663]1290                        // make an ACK request to R2T queue
1291                        socket_put_r2t_request( socket_r2tq_xp,
1292                                                TCP_FLAG_ACK,
1293                                                chdev->channel );
[657]1294
[663]1295                        // check pending RX_RECV command
1296                        if( (socket_rx_valid == true) &&
1297                            (socket_rx_cmd == CMD_RX_RECV) )
[657]1298                        {
[663]1299                            // reset rx_valid
1300                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
1301
1302                            // report success to RX client thread
1303                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
1304#if DEBUG_DEV_NIC_RX
1305printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock waiting RX client thread\n",
1306__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1307socket_state_str(socket_state) );
1308#endif
[657]1309                        }
1310                    }
1311                }
1312
[663]1313                // [9] handle FIN flag
1314                if( socket_state == TCP_STATE_ESTAB )
[657]1315                {
[663]1316                    if( seg_fin_set )  // received ACK & FIN   
[657]1317                    {
[663]1318
1319#if DEBUG_DEV_NIC_RX
1320printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSE_WAIT\n",
1321__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1322socket_state_str(socket_state) );
1323#endif
1324                        // update socket.rx_nxt when FIN received
1325                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
1326                                        socket_rx_nxt + 1 ); 
1327
1328                        // update socket state
1329                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
1330                                        TCP_STATE_CLOSE_WAIT );
1331
1332                        // make an ACK request to R2T queue
1333                        socket_put_r2t_request( socket_r2tq_xp,
1334                                                TCP_FLAG_ACK,
1335                                                chdev->channel );
1336
1337                        // check pending RX_RECV command
1338                        if( (socket_rx_valid == true) &&
1339                            (socket_rx_cmd == CMD_RX_RECV) )
1340                        {
1341                            // reset rx_valid
1342                            hal_remote_s32( XPTR(socket_cxy,&socket_ptr->rx_valid), false );
1343
1344                            // report error to RX client thread
1345                            dev_nic_unblock_rx_client( socket_xp , CMD_STS_EOF );
1346#if DEBUG_DEV_NIC_RX
1347printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock RX client waiting on RECV\n",
1348__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1349socket_state_str(socket_state) );
1350#endif
1351                        } 
[657]1352                    }
[663]1353                }
1354                else if( socket_state == TCP_STATE_FIN_WAIT1 )
1355                {
1356                    if( seg_fin_set )  // received ACK & FIN
1357                    { 
[657]1358
[663]1359#if DEBUG_DEV_NIC_RX
1360printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSING\n",
1361__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1362socket_state_str(socket_state) );
1363#endif
1364                        // update socket.rx_nxt when FIN received
1365                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
1366                                        socket_rx_nxt + 1 ); 
1367
1368                        // update socket state
1369                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
1370                                        TCP_STATE_CLOSING );
1371
[657]1372                        // make an ACK request to R2T queue
[663]1373                        socket_put_r2t_request( socket_r2tq_xp,
1374                                                TCP_FLAG_ACK,
1375                                                chdev->channel );
1376                    }
1377                    else              // received ACK only
1378                    {
[657]1379
[663]1380#if DEBUG_DEV_NIC_RX
1381printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : only ACK => goes FIN_WAIT2\n",
1382__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1383socket_state_str(socket_state) );
1384#endif
1385                        // update socket state
1386                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
1387                                        TCP_STATE_FIN_WAIT2 );
1388                    }
1389                }
1390                else if( socket_state == TCP_STATE_FIN_WAIT2 )
1391                {
1392                    if( seg_fin_set )  // received ACK & FIN
1393                    { 
1394
1395#if DEBUG_DEV_NIC_RX
1396printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSED / unblock client\n",
1397__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
1398socket_state_str(socket_state) );
1399#endif
1400                        // update socket.rx_nxt when FIN received
[657]1401                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ),
1402                                        socket_rx_nxt + 1 ); 
1403
[663]1404                        // update socket.state
1405                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
[674]1406                                        TCP_STATE_CLOSED ); 
[657]1407
[663]1408                        // make an ACK request to R2T queue
1409                        socket_put_r2t_request( socket_r2tq_xp,
1410                                                TCP_FLAG_ACK,
1411                                                chdev->channel );
1412               
1413                        // report success to TX client thread
1414                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
[657]1415                    }
[663]1416                }
1417                else if( socket_state == TCP_STATE_CLOSING )   // received ACK
1418                {
1419                    // update socket.state
1420                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
[674]1421                                    TCP_STATE_CLOSED ); 
[663]1422
[674]1423                    // report success to TX client thread
1424                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
[663]1425
1426                }
1427                else if( socket_state == TCP_STATE_CLOSE_WAIT )
1428                {
1429                    // do nothing
1430                }
1431                else if( socket_state == TCP_STATE_LAST_ACK )
1432                {
1433                    // update socket.state when ACK received
1434                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
1435                                    TCP_STATE_CLOSED );
1436
1437                    // unblock TX client thead for success
1438                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
1439                }
1440            }  // end case connecteded states
[657]1441        }  // end switch socket state
1442
[663]1443        // release the lock protecting socket state
1444        remote_queuelock_release( socket_lock_xp );
[657]1445
[663]1446        return;
[657]1447
[663]1448    }  // end if attached socket
1449
1450    // 4. scan the list of listening sockets
1451    listening_match = false;
1452 
1453    // get pointers on NIC_RX[0] chdev
1454    xptr_t    rx0_chdev_xp  = chdev_dir.nic_rx[0];
1455    chdev_t * rx0_chdev_ptr = GET_PTR( rx0_chdev_xp );
1456    cxy_t     rx0_chdev_cxy = GET_CXY( rx0_chdev_xp );
1457   
1458    // build extended pointers on list of listening sockets
1459    xptr_t    rx0_root_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.root );
1460    xptr_t    rx0_lock_xp = XPTR( rx0_chdev_cxy , &rx0_chdev_ptr->ext.nic.lock );
1461
1462    // take the lock protecting the list of listening sockets
1463    remote_busylock_acquire( rx0_lock_xp );
1464
1465    // scan the xlist of listening socket
1466    XLIST_FOREACH( rx0_root_xp , iter_xp )
1467    {
1468        // get socket cluster and local pointer
1469        socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , rx_list );
1470        socket_ptr = GET_PTR( socket_xp );
1471        socket_cxy = GET_CXY( socket_xp );
1472
1473        // get relevant socket type and state
1474        socket_type     = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type ));
1475        socket_state    = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state ));
1476               
1477// check socket type and state
[674]1478assert( __FUNCTION__, (socket_type  == SOCK_STREAM ) , "illegal socket type" );
1479assert( __FUNCTION__, (socket_state == TCP_STATE_LISTEN ) , "illegal socket state" );
[663]1480
1481        // get relevant socket infos for matching
1482        socket_local_addr   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 
1483        socket_local_port   = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 
1484               
1485        // compute matching condition for a listening socket
1486        listening_match = (socket_local_addr  == seg_local_addr) && 
1487                          (socket_local_port  == seg_local_port);
1488
1489        // exit loop if matching
1490        if( listening_match ) 
1491        {
1492
1493#if DEBUG_DEV_NIC_RX
1494fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) );
1495pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) );
1496if( cycle > DEBUG_DEV_NIC_RX )
1497printk("\n[%s] thread[%x,%x] matching listening socket[%d,%d] / state %s\n",
1498__FUNCTION__, this->process->pid, this->trdid, pid, fdid, socket_state_str(socket_state) );
1499#endif
1500            break;
1501        }
1502    }   // end loop on listening sockets
1503
1504    // release the lock protecting the list of listening sockets
1505    remote_busylock_release( rx0_lock_xp );
1506
1507    // 5. handle TCP segment for a matching listening socket
1508    if( listening_match )
1509    {
1510        // The actions depend on the received segment flags
1511        // - discard segment for RST or ACK
1512        // - update socket state & remote IP address,
1513        //   register connect request in socket CRQ queue,
1514        //   and unblock client thread for SYN
1515 
1516        // discard segment if RST flag
1517        if( seg_rst_set )
1518        {
1519
1520#if DEBUG_DEV_NIC_RX
1521if( cycle > DEBUG_DEV_NIC_RX )
1522printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received RST\n",
1523__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
1524#endif
1525            return;
1526        }
1527
1528        // discard segment if ACK flag
1529        if( seg_ack_set ) 
1530        {
1531
1532#if DEBUG_DEV_NIC_RX
1533if( cycle > DEBUG_DEV_NIC_RX )
1534printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : received ACK\n",
1535__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
1536#endif
1537            return;
1538        }
1539
1540        // SYN flag == CONNECT request / seq_num cannot be wrong
1541        if( seg_syn_set )
1542        {
1543            // build extended pointer on listening socket CRQ
1544            socket_crqq_xp = XPTR( socket_cxy , &socket_ptr->crqq );
1545
1546            // try to register request into CRQ queue
1547            error = socket_put_crq_request( socket_crqq_xp,
1548                                            seg_remote_addr, 
1549                                            seg_remote_port,
1550                                            seg_seq_num,
1551                                            seg_window );
1552
1553            if ( error )   // CRQ full
1554            {
1555
1556#if DEBUG_DEV_NIC_RX
1557if( cycle > DEBUG_DEV_NIC_RX )
1558printk("\n[%s] thread[%x,%x] listening socket[%x,%d] CRQ full => send RST\n",
1559__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
1560#endif
1561                // make an RST request to R2T queue
1562                socket_put_r2t_request( socket_r2tq_xp,
1563                                        TCP_FLAG_RST,
1564                                        chdev->channel );
1565            }
1566            else          // new connection request registered in CRQ
1567            {
1568
1569#if DEBUG_DEV_NIC_RX
1570if( cycle > DEBUG_DEV_NIC_RX )
1571printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] : register request in CRQ\n",
1572__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
1573#endif
1574                // check pending RX_ACCEPT command
1575                if( (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_valid)) == true) &&
1576                    (hal_remote_l32(XPTR(socket_cxy,&socket_ptr->rx_cmd)) == CMD_RX_ACCEPT) )
1577                {
1578                    // reset rx_valid
1579                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_valid ), false );
1580                     
1581                    // report success to RX client thread
1582                    dev_nic_unblock_rx_client( socket_xp , CMD_STS_SUCCESS );
1583
1584#if DEBUG_DEV_NIC_RX
1585if( cycle > DEBUG_DEV_NIC_RX )
1586printk("\n[%s] thread[%x,%x] for listening socket[%x,%d] unblock RX client thread\n", 
1587__FUNCTION__, this->process->pid, this->trdid, pid, fdid );
1588#endif
1589                }
1590            }   // end register request in CRQ
1591        }   // end if SYN
1592       
1593        return;
1594
1595    }  // end if listening_match
1596
1597    // 6. no socket found => discard segment
1598
1599#if DEBUG_DEV_NIC_RX
1600if( cycle > DEBUG_DEV_NIC_RX )
1601printk("\n[%s] thread[%x,%x] exit failure : no socket found => discard segment\n",
1602__FUNCTION__, this->process->pid, this->trdid );
1603#endif
1604
[657]1605}  // end dev_nic_rx_handle_tcp_segment()
1606
1607
1608/////////////////////////////////////////
1609void dev_nic_rx_server( chdev_t * chdev )
1610{
1611    uint8_t       k_buf[2048];          // kernel buffer for one ETH/IP/UDP packet
1612    uint32_t      pkt_src_addr;         // packet source IP address
1613    uint32_t      pkt_dst_addr;         // packet destination IP address
1614    uint32_t      trsp_protocol;        // transport protocol (TCP / UDP)
1615    uint32_t      eth_length;           // size of Ethernet packet (bytes)
1616    uint32_t      ip_length;            // size of IP packet in bytes
1617    error_t       error;
1618
[663]1619    thread_t    * this = CURRENT_THREAD;
[657]1620
[663]1621// check thread can yield
1622thread_assert_can_yield( this , __FUNCTION__ );
1623
[657]1624// check chdev direction and type
[674]1625assert( __FUNCTION__, (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == true) ,
[657]1626"illegal chdev type or direction" );
1627
[663]1628#if DEBUG_DEV_NIC_RX
1629uint32_t   cycle = (uint32_t)hal_get_cycles();
1630if( cycle > DEBUG_DEV_NIC_RX )
1631printk("\n[%s] thread[%x,%x] starts / cycle %d\n",
1632__FUNCTION__, this->process->pid, this->trdid, cycle );
1633#endif
[565]1634
[663]1635    // get extended pointers on server tread and chdev
1636    xptr_t     thread_xp = XPTR( local_cxy , this );
1637    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
1638
[657]1639    while( 1 )
1640    {
[663]1641        // call NIC driver to move one packet from NIC_RX queue to kernel buffer
1642        this->nic_cmd.dev_xp  = chdev_xp;
1643        this->nic_cmd.type    = NIC_CMD_READ;
1644        this->nic_cmd.buffer  = k_buf;
1645        chdev->cmd( XPTR( local_cxy , this ) );
1646
1647        // get packet length   
1648        eth_length = this->nic_cmd.status;
1649
1650        // check success
1651        if( eth_length == 0 )  // queue empty => block and deschedule
[657]1652        {
[663]1653
1654#if DEBUG_DEV_NIC_RX
1655cycle = (uint32_t)hal_get_cycles();
1656if( DEBUG_DEV_NIC_RX < cycle )
1657printk("\n[%s] thread[%x,%x] NIC_RX_QUEUE empty => blocks on <ISR> / cycle %d\n",
1658__FUNCTION__, this->process->pid, this->trdid, cycle );
1659#endif
1660            // enable NIC_RX IRQ
1661            dev_pic_enable_irq( this->core->lid , chdev_xp );
1662
1663            // block and deschedule
1664            thread_block( thread_xp , THREAD_BLOCKED_ISR );
1665            sched_yield("client blocked on NIC_TX queue full");
1666
1667            // disable NIC-RX IRQ
1668            dev_pic_disable_irq( this->core->lid , chdev_xp );
1669
1670#if DEBUG_DEV_NIC_RX
1671cycle = (uint32_t)hal_get_cycles();
1672if( DEBUG_DEV_NIC_RX < cycle )
1673printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
1674__FUNCTION__, this->process->pid, this->trdid, cycle );
1675#endif
1676
[657]1677        }
[663]1678        else                 // success => handle packet
[657]1679        {
[1]1680
[663]1681#if DEBUG_DEV_NIC_RX
1682cycle = (uint32_t)hal_get_cycles();
1683if( DEBUG_DEV_NIC_RX < cycle )
1684dev_nic_packet_display( false,               // is_tx
1685                        this->process->pid,
1686                        this->trdid,
1687                        cycle,
1688                        k_buf );
1689#endif
1690
[657]1691            // analyse the ETH header
1692            error = dev_nic_rx_check_eth( k_buf,
1693                                          &ip_length );
[1]1694
[657]1695            // discard packet if error reported by Ethernet layer
[663]1696            if( error )
1697            {
[1]1698
[663]1699#if DEBUG_DEV_NIC_RX
1700cycle = (uint32_t)hal_get_cycles();
1701if( DEBUG_DEV_NIC_RX < cycle )
1702printk("\n[%s] thread[%x,%x] discard ETH packet / cycle %d\n", 
1703__FUNCTION__, this->process->pid, this->trdid, cycle );
1704#endif
1705                continue; 
1706            }
1707
1708#if (DEBUG_DEV_NIC_RX & 1)
1709cycle = (uint32_t)hal_get_cycles();
1710if( DEBUG_DEV_NIC_RX < cycle )
1711printk("\n[%s] thread[%x,%x] successfully checked ETH packet / cycle %d\n", 
1712__FUNCTION__, this->process->pid, this->trdid, cycle );
1713#endif
[657]1714            // analyse the IP header
1715            error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN,
1716                                         ip_length, 
1717                                         &pkt_src_addr, 
1718                                         &pkt_dst_addr,
1719                                         &trsp_protocol );
[1]1720
[657]1721            // discard packet if error reported by IP layer
[663]1722            if( error ) 
1723            {
[1]1724
[663]1725#if DEBUG_DEV_NIC_RX
1726cycle = (uint32_t)hal_get_cycles();
1727if( DEBUG_DEV_NIC_RX < cycle )
1728printk("\n[%s] thread[%x,%x] discarded IP packet / cycle %d\n", 
1729__FUNCTION__, this->process->pid, this->trdid, cycle );
1730#endif
1731                continue; 
1732            }
1733
1734#if (DEBUG_DEV_NIC_RX & 1 )
1735cycle = (uint32_t)hal_get_cycles();
1736if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_UDP) )
1737printk("\n[%s] thread[%x,%x] successfully checked UDP packet / cycle %d\n", 
1738__FUNCTION__, this->process->pid, this->trdid, cycle );
1739if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_TCP) )
1740printk("\n[%s] thread[%x,%x] successfully checked TCP segment / cycle %d\n", 
1741__FUNCTION__, this->process->pid, this->trdid, cycle );
1742#endif
1743
[657]1744            // call relevant transport protocol
1745            if( trsp_protocol == PROTOCOL_UDP )   
1746            { 
1747                dev_nic_rx_handle_udp_packet( chdev,
1748                                              k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
1749                                              ip_length - IP_HEAD_LEN,
1750                                              pkt_src_addr,
1751                                              pkt_dst_addr );
1752            }
1753            else if ( trsp_protocol == PROTOCOL_TCP)
1754            {
1755                dev_nic_rx_handle_tcp_segment( chdev,
1756                                               k_buf + ETH_HEAD_LEN + IP_HEAD_LEN,
1757                                               ip_length - IP_HEAD_LEN,
1758                                               pkt_src_addr,
1759                                               pkt_dst_addr );
1760            }
[663]1761            else // discard packet if unsupported transport protocol
1762            {
1763 
1764#if DEBUG_DEV_NIC_RX
1765cycle = (uint32_t)hal_get_cycles();
1766if( DEBUG_DEV_NIC_RX < cycle )
1767printk("\n[%s] thread[%x,%x] discarded unsupported transport protocol %d\n", 
1768__FUNCTION__, this->process->pid, this->trdid, trsp_protocol, cycle );
1769#endif
1770                continue;
1771            }
[657]1772        }
1773    } // end of while loop
1774}  // end dev_nic_rx_server()
1775
1776
1777
1778
1779///////////////////////////////////////////////////////////////////////////////////////////
1780//              Functions used by the NIC_TX server thread
1781///////////////////////////////////////////////////////////////////////////////////////////
1782
1783///////////////////////////////////////////////////////////////////////////////////////////
[663]1784// This static function is called by the dev_nic_tx_build_packet() function.
[657]1785// It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and
1786// <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument.
[663]1787// It blocks and deschedules on the BLOCKED_ISR condition if the queue is full.
[657]1788///////////////////////////////////////////////////////////////////////////////////////////
1789// @ chdev   : [in] local pointer on NIC_TX chdev.
[663]1790// @ k_buf   : [in] pointer on a local kernel buffer (2K bytes).
[657]1791// @ length  : [in] actual Ethernet packet length in bytes.
1792///////////////////////////////////////////////////////////////////////////////////////////
[663]1793static void dev_nic_tx_move_packet( chdev_t  * chdev,
1794                                    uint8_t  * k_buf,
1795                                    uint32_t   length )
[657]1796{
1797    thread_t * this = CURRENT_THREAD;
1798
1799    // get extended pointers on server tread and chdev
1800    xptr_t     thread_xp = XPTR( local_cxy , this );
1801    xptr_t     chdev_xp  = XPTR( local_cxy , chdev );
1802
1803// check thread can yield
[663]1804thread_assert_can_yield( this , __FUNCTION__ );
[657]1805
[663]1806#if (DEBUG_DEV_NIC_TX & 1)
[657]1807uint32_t cycle = (uint32_t)hal_get_cycles();
[663]1808if( DEBUG_DEV_NIC_TX < cycle )
1809printk("\n[%s] thread[%x,%x] enter / buf %x / length %d / cycle %d\n", 
1810__FUNCTION__, this->process->pid, this->trdid, k_buf, length, cycle );
[657]1811#endif
1812
[663]1813    // initialize WRITE command in server thread descriptor
1814    this->nic_cmd.dev_xp = chdev_xp;
1815    this->nic_cmd.type   = NIC_CMD_WRITE;
1816    this->nic_cmd.buffer = k_buf;
1817    this->nic_cmd.length = length;
1818
[657]1819    while( 1 )
[1]1820    {
[663]1821        // call driver to move TX packet
1822        chdev->cmd( thread_xp );
1823
1824        // exit while if success
1825        if( this->nic_cmd.status == length )    // exit while & return if success
[657]1826        {
[663]1827
1828#if (DEBUG_DEV_NIC_TX & 1)
1829cycle = (uint32_t)hal_get_cycles();
1830if( DEBUG_DEV_NIC_TX < cycle )
1831printk("\n[%s] thread[%x,%x] exit SUCCESS / cycle %d\n",
1832__FUNCTION__, this->process->pid, this->trdid, cycle );
1833#endif
1834           break; 
[657]1835        }
[663]1836        else                                    // block and deschedule if queue full
[657]1837        {
[1]1838
[663]1839#if (DEBUG_DEV_NIC_TX & 1)
1840cycle = (uint32_t)hal_get_cycles();
1841if( DEBUG_DEV_NIC_TX < cycle )
1842printk("\n[%s] thread[%x,%x] NIC_TX_QUEUE full => blocks on ISR / cycle %d\n",
1843__FUNCTION__, this->process->pid, this->trdid, cycle );
1844#endif
1845            // enable NIC_TX IRQ
1846            dev_pic_enable_irq( this->core->lid , chdev_xp );
1847
1848            // TX server thread blocks and deschedules
[657]1849            thread_block( thread_xp , THREAD_BLOCKED_ISR );
1850            sched_yield("client blocked on NIC_TX queue full");
[1]1851
[657]1852            // disable NIC-TX IRQ
[663]1853            dev_pic_disable_irq( this->core->lid , chdev_xp );
[1]1854
[663]1855#if (DEBUG_DEV_NIC_TX & 1)
[437]1856cycle = (uint32_t)hal_get_cycles();
[663]1857if( DEBUG_DEV_NIC_TX < cycle )
1858printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
1859__FUNCTION__, this->process->pid, this->trdid, cycle );
[437]1860#endif
[663]1861        }
1862    }
[657]1863}  // end dev_nic_tx_move_packet()
[1]1864
[657]1865///////////////////////////////////////////////////////////////////////////////////////////
1866// This static function is called by the dev_nic_tx_server() function to build an UDP
1867// header in the kernel buffer defined by the <k_buf> arguement,  as specified by the
1868// <socket_xp> argument. The <length> argument defines the number of bytes in payload.
1869// It set the "src_port", "dst_port", "total_length" and "checksum" fields in UDP header.
1870// The payload must be previouly loaded in the pernel buffer.
1871///////////////////////////////////////////////////////////////////////////////////////////
1872// @ k_buf      : [in]  pointer on first byte of UDP header in kernel buffer.
1873// @ socket_xp  : [in]  extended pointer on socket.
1874// @ length     : [in]  number of bytes in payload.
1875///////////////////////////////////////////////////////////////////////////////////////////
[663]1876static void dev_nic_tx_build_udp_header( uint8_t  * k_buf,
1877                                         xptr_t     socket_xp,
1878                                         uint32_t   length )
[657]1879{
1880    uint16_t   checksum;        // checksum value
1881    uint32_t   total_length;    // total UDP packet length
1882    uint32_t   local_addr;      // local IP address
1883    uint32_t   remote_addr;     // remote IP address
1884    uint32_t   local_port;      // local port
1885    uint32_t   remote_port;     // remote port
[1]1886
[657]1887    // get socket cluster an local pointer
1888    socket_t * socket_ptr = GET_PTR( socket_xp );
1889    cxy_t      socket_cxy = GET_CXY( socket_xp );
1890
1891    // get relevant infos from socket
1892    local_addr  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 
1893    remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 
1894    local_port  = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 
1895    remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 
1896
1897    // compute UDP packet total length
1898    total_length = length + UDP_HEAD_LEN;
1899
1900    // set src_port and dst_port in header
1901    k_buf[0] = local_port >> 8; 
1902    k_buf[1] = local_port; 
1903    k_buf[2] = remote_port >> 8; 
1904    k_buf[3] = remote_port; 
1905
1906    // set packet length in header
1907    k_buf[4] = total_length >> 8;
1908    k_buf[5] = total_length;
1909   
1910    // compute UDP packet checksum
1911    checksum = dev_nic_udp_checksum( k_buf , total_length );
1912
1913    // set checksum
1914    k_buf[6] = checksum >> 8;
1915    k_buf[7] = checksum;
1916
1917}  // end dev_nic_tx_build_udp_header()
1918
1919///////////////////////////////////////////////////////////////////////////////////////////
1920// This static function is called by the dev_nic_tx_server() function.
1921// It builds a TCP header in the kernel buffer defined by the <k_buf> argument.
1922// The payload must have been previouly registered in this buffer.
1923// The "local_addr", "local_port", "remote_addr", "remote_port", seq_num", "ack_num",
1924// and "window" fields are obtained from the <socket_xp> argument.
1925// The <length> argument defines the number of bytes in payload, and the <flags> argument
1926// defines the flags to be set in TCP header.
1927///////////////////////////////////////////////////////////////////////////////////////////
1928// @ k_buf      : [in]  pointer on first byte of TCP header in kernel buffer.
[663]1929// @ socket_xp  : [in]  extended pointer on socket.
[657]1930// @ length     : [in]  number of bytes in payload.
1931// @ flags      : [in]  flags to be set in TCP header.
1932///////////////////////////////////////////////////////////////////////////////////////////
[663]1933static void dev_nic_tx_build_tcp_header( uint8_t  * k_buf,
1934                                         xptr_t     socket_xp,
1935                                         uint32_t   length,
1936                                         uint8_t    flags )
[657]1937{
1938    uint16_t   checksum;        // global segment checksum
1939    uint32_t   total_length;    // total UDP packet length
1940    uint32_t   src_addr;        // local IP address
1941    uint32_t   dst_addr;        // remote IP address
1942    uint16_t   src_port;        // local port
1943    uint16_t   dst_port;        // remote port
1944    uint32_t   seq_num;         // first byte of segment in TX stream
1945    uint32_t   ack_num;         // next expected byte in RX stream
[663]1946    uint32_t   window;          // window of accepted segments in RX stream
[657]1947
1948    // get socket cluster an local pointer
1949    socket_t * sock_ptr = GET_PTR( socket_xp );
1950    cxy_t      sock_cxy = GET_CXY( socket_xp );
1951
1952    // get relevant infos from socket
1953    src_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_addr )); 
1954    dst_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_addr )); 
1955    src_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_port )); 
1956    dst_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_port )); 
1957    seq_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->tx_nxt ));
1958    ack_num  = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_nxt ));
1959    window   = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_wnd ));
1960
1961    // compute TCP segment total length
1962    total_length = length + TCP_HEAD_LEN;
1963
1964    // set "src_port" and "dst_port"
1965    k_buf[0]  = src_port >> 8; 
1966    k_buf[1]  = src_port; 
1967    k_buf[2]  = dst_port >> 8; 
1968    k_buf[3]  = dst_port; 
1969
1970    // set "seq_num" 
1971    k_buf[4]  = seq_num >> 24;
1972    k_buf[5]  = seq_num >> 16;
1973    k_buf[6]  = seq_num >>  8;
1974    k_buf[7]  = seq_num;
1975
1976    // set "ack_num" 
1977    k_buf[8]  = ack_num >> 24;
1978    k_buf[9]  = ack_num >> 16;
1979    k_buf[10] = ack_num >>  8;
1980    k_buf[11] = ack_num;
1981
1982    // set "hlen"
1983    k_buf[12] = 5;
1984
1985    // set "flags"
1986    k_buf[13] = flags & 0x3F;
1987
1988    // set "window"
1989    k_buf[14] = window >> 8;
1990    k_buf[15] = window;
1991
1992    // reset "checksum"
1993    k_buf[16] = 0;
1994    k_buf[17] = 0;
1995   
1996    // set "urgent_ptr"
1997    k_buf[18] = 0;
1998    k_buf[19] = 0;
1999 
2000    // compute TCP segment checksum
2001    checksum = dev_nic_tcp_checksum( k_buf,
2002                                     total_length,
2003                                     src_addr,
2004                                     dst_addr );
2005    // set "checksum"
2006    k_buf[16] = checksum >> 8;
2007    k_buf[17] = checksum;
2008
2009}  // end dev_nic_tx_build_tcp_header()
2010
2011
2012///////////////////////////////////////////////////////////////////////////////////////////
2013// This static function is called by the dev_nic_tx_server() function.
2014// It builds the IP header in the 20 first bytes of <buffer>.
2015///////////////////////////////////////////////////////////////////////////////////////////
2016// @ buffer     : pointer on first byte of IP header in kernel buffer
2017// @ src_addr   : source IP address.
2018// @ dst_addr   : destination IP address.
2019// @ length     : number of bytes in IP packet payload.
2020///////////////////////////////////////////////////////////////////////////////////////////
[663]2021static void dev_nic_tx_build_ip_header( uint8_t * buffer,
2022                                        uint32_t  src_addr,
2023                                        uint32_t  dst_addr,
2024                                        uint8_t   protocol,
2025                                        uint16_t  length )
[657]2026{
2027    uint16_t   hcs;
2028
2029    uint16_t   total = length + IP_HEAD_LEN;
2030
2031    buffer[0]  = 0x45;         // IPV4 / IHL = 20 bytes 
2032    buffer[1]  = 0;            // DSCP / ECN
2033    buffer[2]  = total >> 8; 
2034    buffer[3]  = total; 
2035
2036    buffer[4]  = 0x40;         // Don't Fragment
2037    buffer[5]  = 0; 
2038    buffer[6]  = 0;
2039    buffer[7]  = 0; 
2040
2041    buffer[8]  = 0xFF;         // TTL
[663]2042    buffer[9]  = protocol;     // transport protocol
[657]2043   
2044    buffer[12] = src_addr >> 24; 
2045    buffer[13] = src_addr >> 16; 
2046    buffer[14] = src_addr >> 8; 
2047    buffer[15] = src_addr; 
2048
2049    buffer[16] = dst_addr >> 24; 
2050    buffer[17] = dst_addr >> 16; 
2051    buffer[18] = dst_addr >> 8;
2052    buffer[19] = dst_addr; 
2053
2054    // compute IP header checksum
2055    hcs = dev_nic_ip_checksum( buffer ); 
2056
2057    // set checksum
2058    buffer[10] = hcs >> 8;
2059    buffer[11] = hcs; 
2060
2061}  // end dev_nic_tx_build_ip_header
2062
2063///////////////////////////////////////////////////////////////////////////////////////////
2064// This static function is called by the dev_nic_tx_server() function.
2065// It builds the Ethernet header in the 14 first bytes of <buffer>.
2066///////////////////////////////////////////////////////////////////////////////////////////
2067// @ buffer     : pointer on first byte of Ethernet header in kernel buffer
2068// @ src_mac_54 : two MSB bytes in source MAC address.
2069// @ src_mac_32 : two MED bytes in source MAC address.
2070// @ src_mac_10 : two LSB bytes in source MAC address.
2071// @ dst_mac_54 : two MSB bytes in destination MAC address.
2072// @ dst_mac_32 : two MED bytes in destination MAC address.
2073// @ dst_mac_10 : two LSB bytes in destination MAC address.
2074// @ length     : number of bytes in Ethernet frame payload.
2075///////////////////////////////////////////////////////////////////////////////////////////
[663]2076static void dev_nic_tx_build_eth_header( uint8_t * buffer,
2077                                         uint8_t   src_mac_5,
2078                                         uint8_t   src_mac_4,
2079                                         uint8_t   src_mac_3,
2080                                         uint8_t   src_mac_2,
2081                                         uint8_t   src_mac_1,
2082                                         uint8_t   src_mac_0,
2083                                         uint8_t   dst_mac_5,
2084                                         uint8_t   dst_mac_4,
2085                                         uint8_t   dst_mac_3,
2086                                         uint8_t   dst_mac_2,
2087                                         uint8_t   dst_mac_1,
2088                                         uint8_t   dst_mac_0,
2089                                         uint32_t  length )
[657]2090{
[663]2091    buffer[0]  = dst_mac_5;
2092    buffer[1]  = dst_mac_4;
2093    buffer[2]  = dst_mac_3;
2094    buffer[3]  = dst_mac_2;
2095    buffer[4]  = dst_mac_1;
2096    buffer[5]  = dst_mac_0;
[657]2097
[663]2098    buffer[6]  = src_mac_5;
2099    buffer[7]  = src_mac_4;
2100    buffer[8]  = src_mac_3;
2101    buffer[9]  = src_mac_2;
2102    buffer[10] = src_mac_1;
2103    buffer[11] = src_mac_0;
[657]2104
2105    buffer[12] = length >> 8;
2106    buffer[13] = length;
2107
2108}  // end dev_nic_tx_build_eth_header()
2109
2110///////////////////////////////////////////////////////////////////////////////////////////
[663]2111// This static function is called by the dev_nic_tx_server() function to handle one TX
2112// command, or one R2T request, as defined by the <cmd_valid> and <r2t_valid> arguments,
2113// for the socket identified by the <socket_xp> argument. It builds an ETH/IP/UDP packet
2114// or ETH/IP/TCP segment, in the buffer defined by the <k_buf> argument, and registers
2115// it in the NIC_TX queue defined by the <chdev> argument.
2116// For a TCP header, the "seq_num", ack_num", and "window" fiels are defined by the
2117// "socket.tx_next", "socket.rx_next" and "socket.rx_wnd" fields respectively.
2118// It updates the "socket.state", "socket.tx_nxt", "socket.r2tq", and "socket.crqq"
2119// The supported TX command types are CONNECT / ACCEPT / SEND / CLOSE.
2120// fields as required by the command type.
2121// - For an UDP socket, it reset the "socket.tx_valid" field, and unblock the client
2122//   thread when the packet has been sent, or when an error must be reported.
2123// - For a TCP socket, it reset the "socket.tx_valid" field when the segment has been
2124//   sent, but does not unblocks the client thread, that will be unblocqued by the
2125//   NIC_RX thread when the TX command is fully completed.
[657]2126///////////////////////////////////////////////////////////////////////////////////////////
[663]2127// To build a packet, it makes the following actions:
[657]2128// 1) it takes the lock protecting the socket state.
[663]2129// 2) it get the command arguments from socket descriptor.
2130// 3) it build an UDP packet or a TCP segment, depending on command type and socket state.
2131// 4) it updates the socket state.
2132// 5) it releases the lock protecting the socket.
2133// 6) it build the IP header.
2134// 7) it build the ETH header.
2135// 8) it copies the packet in the NIC_TX queue.
[657]2136///////////////////////////////////////////////////////////////////////////////////////////
[663]2137// @ cmd_state   : [in] TX command valid in socket descriptor.
2138// @ r2t_valid   : [in] R2T request valid in command descriptor.
[657]2139// @ socket_xp   : [in] extended pointer on client socket. 
2140// @ k_buf       : [in] local pointer on kernel buffer (2 Kbytes).
2141// @ chdev       : [in] local pointer on NIC_RX chdev.
2142///////////////////////////////////////////////////////////////////////////////////////////
[663]2143static void dev_nic_tx_build_packet( bool_t    cmd_valid,
2144                                     bool_t    r2t_valid,
2145                                     xptr_t    socket_xp,
2146                                     uint8_t * k_buf,
2147                                     chdev_t * chdev )
[657]2148{
2149    socket_t  * socket_ptr;
2150    cxy_t       socket_cxy;
2151    xptr_t      client_xp;       // extended pointer on client thread 
[663]2152    uint32_t    cmd_type;        // NIC command type
2153    uint8_t   * tx_buf;          // local pointer on kernel buffer for payload
2154    uint32_t    len;             // tx_buf length (bytes)
[657]2155    uint32_t    todo;            // number of bytes not yet sent
2156    uint32_t    socket_type;     // socket type (UDP/TCP)
2157    uint32_t    socket_state;    // socket state       
2158    xptr_t      socket_lock_xp;  // extended pointer on socket lock
2159    xptr_t      socket_r2tq_xp;  // extended pointer on R2T queue
2160    uint32_t    src_ip_addr;     // source IP address
2161    uint32_t    dst_ip_addr;     // destination IP address
[663]2162    uint32_t    tx_nxt;          // next sequence number in TX stream
[657]2163    uint32_t    nbytes;          // number of bytes in UDP/TCP packet payload
[663]2164    uint8_t   * k_trsp_base;     // pointer on UDP/TCP packet in kernel buffer
[657]2165    uint32_t    trsp_length;     // length of TCP/UDP packet
[663]2166    uint8_t     trsp_protocol;   // transport protocol type (UDP/TCP)
[657]2167    uint8_t     r2t_flags;       // flags defined by one R2T queue request
2168    bool_t      do_send;         // build & send a packet when true
2169 
2170    // get socket cluster and local pointer
2171    socket_cxy = GET_CXY( socket_xp );
2172    socket_ptr = GET_PTR( socket_xp );
[663]2173
2174#if DEBUG_DEV_NIC_TX
2175thread_t * this = CURRENT_THREAD;;
2176uint32_t   cycle = (uint32_t)hal_get_cycles();
2177uint32_t   fdid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
2178uint32_t   pid   = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
2179if( cycle > DEBUG_DEV_NIC_TX )
2180printk("\n[%s] thread[%x,%x] enter for socket[%x,%d] : cmd_valid %d / r2t_valid %d / cycle %d\n",
2181__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
2182#endif
2183
2184    // build extended pointers on socket lock and r2t queue
2185    socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock );   
[657]2186    socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
2187
2188    // 1. take lock protecting this socket
[663]2189    remote_queuelock_acquire( socket_lock_xp );
[657]2190
[663]2191    // get relevant socket infos
2192    socket_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->type ));
2193    socket_state = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->state ));
2194    src_ip_addr  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->local_addr ));
2195    dst_ip_addr  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->remote_addr ));
[657]2196
[663]2197    // compute UDP/TCP packet base in kernel buffer
2198    k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
2199
2200    // set default values
2201    do_send     = false;
2202    trsp_length = 0;
2203    nbytes      = 0;
2204
2205    if( cmd_valid )  // handle TX command
[657]2206    {
2207        // 2. get command arguments from socket
[663]2208        cmd_type  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_cmd ));
2209        tx_buf    = hal_remote_lpt( XPTR( socket_cxy , &socket_ptr->tx_buf ));
2210        len       = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_len ));
2211        todo      = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_todo ));
2212        client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client ));
[657]2213       
[663]2214#if DEBUG_DEV_NIC_TX
2215cycle = (uint32_t)hal_get_cycles();
2216if( cycle > DEBUG_DEV_NIC_TX )
2217printk("\n[%s] thread[%x,%x] cmd_valid for socket[%x,%d] : %s / %s / cycle %d\n",
2218__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2219socket_cmd_type_str(cmd_type), socket_state_str(socket_state), cycle );
2220#endif
[657]2221
[663]2222        //////////////////////////////////////////////////////////
[657]2223        // 3. UDP : build UDP packet and update UDP socket state
2224        if( socket_type == SOCK_DGRAM )       
2225        {
[663]2226            trsp_protocol = PROTOCOL_UDP;
2227
2228            if( socket_state != UDP_STATE_ESTAB )
[657]2229            {
[663]2230                // reset tx_valid
2231                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
[657]2232
[663]2233                // unblock client thread / report error
2234                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
[657]2235            }
[663]2236            else
[657]2237            {
[663]2238                if( cmd_type == CMD_TX_SEND ) 
[657]2239                {
2240                    // compute payload length
2241                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
2242
[663]2243                    // move payload from tx_buf to 2 Kbytes kernel buffer
2244                    memcpy( k_trsp_base + UDP_HEAD_LEN,
2245                            tx_buf + (len - todo),
2246                            nbytes );
[657]2247
2248                    // build UDP header
[663]2249                    dev_nic_tx_build_udp_header( k_trsp_base,
[657]2250                                                 socket_xp,
2251                                                 nbytes );
2252
2253                    // update "tx_todo" in socket descriptor
[663]2254                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
[657]2255
[663]2256                    // send UDP packet
2257                    trsp_length = UDP_HEAD_LEN + nbytes;
2258                    do_send     = true;
2259
2260#if( DEBUG_DEV_NIC_TX & 1)
2261cycle = (uint32_t)hal_get_cycles();
2262if( cycle > DEBUG_DEV_NIC_TX )
2263printk("\n[%s] thread[%x,%x] socket[%x,%d] UDP packet build / length %d / cycle %d\n",
2264__FUNCTION__, this->process->pid, this->trdid, trsp_length , cycle );
2265#endif
2266                    if( nbytes == todo )    // last byte sent
[657]2267                    {
[663]2268                        // reset tx_valid
2269                        hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
2270
2271                        // report success to TX client
2272                        dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS );
[657]2273                    }
2274                }
[663]2275                else // CONNECT, ACCEPT, or CLOSE commands are illegal for UDP
[657]2276                {
[663]2277                    // reset tx_valid
2278                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
[657]2279
[663]2280                    // report error
2281                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
[657]2282                }
2283            }
2284        }  // end UDP
2285
[663]2286        ///////////////////////////////////////////////////////////
[657]2287        // 3. TCP : build TCP segment and update TCP socket state
[663]2288        else if( socket_type == SOCK_STREAM ) 
[657]2289        {
[663]2290            trsp_protocol = PROTOCOL_TCP;
2291
2292            // handle R2T request / initialize r2t_flags
2293            if( r2t_valid )
[657]2294            {
[663]2295                // build extended pointers on r2t queue
2296                socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq );
2297       
2298                // get one request from R2T queue
[657]2299                remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
2300            }
2301            else
2302            {
2303                r2t_flags = 0;
2304            }
2305
[663]2306            ////////////////////////////////
2307            if( cmd_type == CMD_TX_CONNECT )  // always executed by a TCP client
[657]2308            {
[663]2309                if( (socket_state == TCP_STATE_BOUND) ||
2310                    (socket_state == TCP_STATE_LISTEN) )  // send a SYN segment
[657]2311                {
[663]2312                    // initialises socket tx_nxt, and rx_wnd
2313                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_CLIENT );
2314                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), TCP_MAX_WINDOW );
[657]2315
[663]2316                    // build TCP SYN segment
2317                    dev_nic_tx_build_tcp_header( k_trsp_base,
[657]2318                                                 socket_xp,
[663]2319                                                 0,        // length
2320                                                 TCP_FLAG_SYN );   
2321                    // send segment
2322                    trsp_length = TCP_HEAD_LEN;
2323                    do_send     = true;
[657]2324
[663]2325#if DEBUG_DEV_NIC_TX
2326cycle = (uint32_t)hal_get_cycles();
2327if( cycle > DEBUG_DEV_NIC_TX )
2328printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CONNECT / "
2329"TCP SYN build / cycle %d\n",
2330__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2331socket_state_str( socket_state ), cycle );
2332#endif
2333                    // update socket.state
2334                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
2335                                          TCP_STATE_SYN_SENT );
[657]2336
[663]2337                    // update socket.tx_nxt
[657]2338                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
[663]2339                                          TCP_ISS_CLIENT + 1 );
[657]2340
[663]2341                    // reset tx_valid but do not unblock client thread
2342                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
2343                } 
2344                else                      // report error for all other socket states
[657]2345                {
[663]2346                    // reset tx_valid
2347                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false );
2348                   
2349                    // report error
2350                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE ); 
[657]2351                }
2352            }
[663]2353            ////////////////////////////////////
2354            else if( cmd_type == CMD_TX_ACCEPT )   // always executed by a TCP server
[657]2355            {
[663]2356
2357                if( socket_state == TCP_STATE_SYN_RCVD )  // send a SYN-ACK segment
[657]2358                {
[663]2359                    // initialize socket tx_nxt, and rx_wnd
2360                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->tx_nxt), TCP_ISS_SERVER );
[674]2361                    hal_remote_s32(XPTR(socket_cxy , &socket_ptr->rx_wnd), CONFIG_SOCK_RX_BUF_SIZE);
[663]2362               
2363                    // build TCP ACK-SYN segment
2364                    dev_nic_tx_build_tcp_header( k_trsp_base,
2365                                                 socket_xp,
2366                                                 0,         //  length
2367                                                 TCP_FLAG_SYN | TCP_FLAG_ACK );
2368                    // send segment
2369                    trsp_length = TCP_HEAD_LEN;
2370                    do_send     = true;
2371
2372#if DEBUG_DEV_NIC_TX
2373cycle = (uint32_t)hal_get_cycles();
2374if( cycle > DEBUG_DEV_NIC_TX )
2375printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / ACCEPT / send SYN-ACK / cycle %d\n",
2376__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2377socket_state_str( socket_state ), cycle );
2378#endif
2379                    // update socket.state
[657]2380                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ),
[663]2381                                          TCP_STATE_SYN_RCVD );
[657]2382
[663]2383                    // update socket.tx_nxt
2384                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ),
2385                                          TCP_ISS_SERVER + 1 );
2386
2387                    // reset tx_valid but do not unblock client thread
2388                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
[657]2389                }
[663]2390                else                     // report error in all other socket states
[657]2391                {
[663]2392                    // reset tx_valid
2393                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
[657]2394
[663]2395                    // report error to TX client thread
2396                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
[657]2397                }
2398            }
[663]2399            ///////////////////////////////////
2400            else if( cmd_type == CMD_TX_CLOSE )
[657]2401            {
[663]2402                if( (socket_state == TCP_STATE_SYN_RCVD  ) ||
2403                    (socket_state == TCP_STATE_ESTAB     ) ||
2404                    (socket_state == TCP_STATE_CLOSE_WAIT) )   // send a FIN-ACK segment
[657]2405                {
[663]2406                    // get  "tx_nxt" from socket descriptor
2407                    tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt ));
[657]2408
[663]2409                    // compute next state
2410                    uint32_t state = (socket_state == TCP_STATE_CLOSE_WAIT) ?
2411                                     TCP_STATE_LAST_ACK : TCP_STATE_FIN_WAIT1;
[657]2412
[663]2413                    // update socket state
2414                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), state );
[657]2415
2416                    // build TCP FIN segment
[663]2417                    dev_nic_tx_build_tcp_header( k_trsp_base,
[657]2418                                                 socket_xp,
[663]2419                                                 0,         // length
2420                                                 TCP_FLAG_FIN | TCP_FLAG_ACK );   
[657]2421
[663]2422                    // update "tx_nxt" in socket descriptor
2423                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + 1 );
2424
2425                    // send segment
2426                    trsp_length = TCP_HEAD_LEN;
2427                    do_send     = true;
2428
2429#if DEBUG_DEV_NIC_TX
2430cycle = (uint32_t)hal_get_cycles();
2431if( cycle > DEBUG_DEV_NIC_TX )
2432printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / send FIN-ACK / cycle %d\n",
2433__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2434socket_state_str( socket_state ), cycle );
2435#endif
2436                    // reset tx_valid but do not unblock client thread
2437                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
[657]2438                }
[663]2439                else                                 // all other states => signal error
[657]2440                {
2441
[663]2442#if DEBUG_DEV_NIC_TX
2443cycle = (uint32_t)hal_get_cycles();
2444if( cycle > DEBUG_DEV_NIC_TX )
2445printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / error BADSTATE / cycle %d\n",
2446__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2447socket_state_str( socket_state ), cycle );
2448#endif
2449                    // reset tx_valid
2450                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
2451
2452                    // report error
2453                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
[657]2454                }
2455            }
[663]2456            /////////////////////////////////////
2457            else if( cmd_type == CMD_TX_SEND )
[657]2458            {
[663]2459                if( (socket_state == TCP_STATE_ESTAB     ) ||
2460                    (socket_state == TCP_STATE_CLOSE_WAIT) )
[657]2461                {
[663]2462                    // get  "tx_nxt" from socket descriptor
2463                    tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt ));
2464
2465                    // compute actual payload length
2466                    nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo;
2467
2468                    // compute TCP segment base in kernel buffer
2469                    k_trsp_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;
2470
2471                    // move payload to k_buf
2472                    memcpy( k_trsp_base + TCP_HEAD_LEN,
2473                            tx_buf + (len - todo),
2474                            nbytes );
2475
2476                    // build TCP header
2477                    dev_nic_tx_build_tcp_header( k_trsp_base,
[657]2478                                                 socket_xp,
[663]2479                                                 nbytes,                       // payload
2480                                                 TCP_FLAG_ACK | r2t_flags );   // flags
[657]2481
[663]2482                    // update "tx_todo" in socket descriptor
2483                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes );
2484
2485                    // update "tx_nxt" in socket descriptor
2486                    hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_nxt), tx_nxt + nbytes );
2487
2488                    // send TCP segment
2489                    trsp_length = TCP_HEAD_LEN + nbytes;
2490                    do_send     = true;
2491
2492                    if( todo == nbytes )   // last byte sent
2493                    {
2494                        // reset tx_valid when last byte has been sent
2495                        hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_valid), false );
2496                    }
2497
2498#if DEBUG_DEV_NIC_TX
2499cycle = (uint32_t)hal_get_cycles();
2500if( cycle > DEBUG_DEV_NIC_TX )
2501printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / SEND / "
2502"TCP DATA build / payload %d / cycle %d\n",
2503__FUNCTION__, this->process->pid, this->trdid, pid, fdid,
2504socket_state_str( socket_state ), nbytes, cycle );
2505#endif
[657]2506                }
[663]2507                else  // all other socket states
[657]2508                {
[663]2509                    // reset tx_valid
2510                    hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
[657]2511
[663]2512                    // report error to TX client thread
2513                    dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE );
[657]2514                }
2515            }
[663]2516            ///////////////////////////////////
2517            else  // undefined TX command type
[657]2518            {
[663]2519                // reset tx_valid
2520                hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false );
[657]2521
[663]2522                // report error to TX client thread
2523                dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD );
[657]2524            }
[663]2525        }  // end TCP
2526    }
2527    else         // no valid TX command => handle R2T request only
[657]2528    {
[663]2529        // get one request from R2T queue
2530        remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 );
[657]2531
[663]2532#if DEBUG_DEV_NIC_TX
2533cycle = (uint32_t)hal_get_cycles();
2534if( cycle > DEBUG_DEV_NIC_TX )
2535printk("\n[%s] thread[%x,%x] only r2t_valid for socket[%x,%d] / flags %x / cycle %d\n",
2536__FUNCTION__, this->process->pid, this->trdid, pid, fdid, r2t_flags, cycle );
2537#endif
2538
2539        // build TCP header
2540        dev_nic_tx_build_tcp_header( k_trsp_base,
2541                                     socket_xp,
2542                                     0,             // payload length
2543                                     r2t_flags );   // flags
2544        // send TCP segment
2545        trsp_protocol = PROTOCOL_TCP;
2546        trsp_length   = TCP_HEAD_LEN;
2547        do_send       = true;
[657]2548    }
2549
2550    // 4. release the lock protecting the socket
[663]2551    remote_queuelock_release( socket_lock_xp );
[657]2552
2553    // return if no packet to send
2554    if( do_send == false ) return;
2555
2556    // 5. build IP header
2557    dev_nic_tx_build_ip_header( k_buf + ETH_HEAD_LEN,
2558                                src_ip_addr,
2559                                dst_ip_addr,
[663]2560                                trsp_protocol,
2561                                trsp_length );
[657]2562
[663]2563#if( DEBUG_DEV_NIC_TX & 1)
2564cycle = (uint32_t)hal_get_cycles();
2565if( cycle > DEBUG_DEV_NIC_TX )
2566printk("\n[%s] thread[%x,%x] IP header build / length %d / cycle %d\n",
2567__FUNCTION__, this->process->pid, this->trdid, IP_HEAD_LEN + trsp_length , cycle );
2568#endif
2569
[657]2570    // 6. build ETH header
2571    dev_nic_tx_build_eth_header( k_buf,
[663]2572                                 (uint8_t)DST_MAC_5,
2573                                 (uint8_t)DST_MAC_4,
2574                                 (uint8_t)DST_MAC_3,
2575                                 (uint8_t)DST_MAC_2,
2576                                 (uint8_t)DST_MAC_1,
2577                                 (uint8_t)DST_MAC_0,
2578                                 (uint8_t)SRC_MAC_5,
2579                                 (uint8_t)SRC_MAC_4,
2580                                 (uint8_t)SRC_MAC_3,
2581                                 (uint8_t)SRC_MAC_2,
2582                                 (uint8_t)SRC_MAC_1,
2583                                 (uint8_t)SRC_MAC_0,
2584                                 IP_HEAD_LEN + trsp_length );
[657]2585
[663]2586#if( DEBUG_DEV_NIC_TX & 1)
2587cycle = (uint32_t)hal_get_cycles();
2588if( cycle > DEBUG_DEV_NIC_TX )
2589printk("\n[%s] thread[%x,%x] ETH header build / cycle %d\n",
2590__FUNCTION__, this->process->pid, this->trdid, cycle );
2591#endif
2592
2593    // 7. move packet to NIC_TX queue (blocking function)
[657]2594    dev_nic_tx_move_packet( chdev,
2595                            k_buf,
2596                            ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length );
2597
[663]2598#if DEBUG_DEV_NIC_TX
2599cycle = (uint32_t)hal_get_cycles();
2600if( cycle > DEBUG_DEV_NIC_TX )
2601printk("\n[%s] thread[%x,%x] for socket[%x,%d] moved packet to NIC_TX / cycle %d\n",
2602__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cycle );
2603#endif
[657]2604
[663]2605}  // end dev_nic_tx_build_packet()
2606
2607
[657]2608/////////////////////////////////////////
2609void dev_nic_tx_server( chdev_t * chdev )
2610{
[674]2611    uint8_t       k_buf[CONFIG_SOCK_PKT_BUF_SIZE];  // buffer for one packet
[657]2612
[663]2613    xptr_t        queue_root_xp;       // extended pointer on sockets list root
2614    xptr_t        queue_lock_xp;       // extended pointer on lock protecting this list
2615    xptr_t        socket_xp;           // extended pointer on on registered socket
[657]2616    socket_t    * socket_ptr;
2617    cxy_t         socket_cxy;
[663]2618    xptr_t        iter_xp;             // iterator for loop on registered sockets
2619    xlist_entry_t temp_root;           // root of temporary list of sockets
2620    xptr_t        temp_root_xp;        // extended pointer on temporary list of sockets
2621    uint32_t      temp_nr;             // number of active registered sockets
2622    bool_t        cmd_valid;           // TX command valid in socket descriptor
2623    bool_t        r2t_valid;           // valid R2T request in socket descriptor
[657]2624
2625    thread_t * this = CURRENT_THREAD;
2626
[663]2627#if DEBUG_DEV_NIC_TX
2628uint32_t cycle = (uint32_t)hal_get_cycles();
2629uint32_t pid;
2630uint32_t fdid;
2631if( cycle > DEBUG_DEV_NIC_TX )
2632printk("\n[%s] thread[%x,%x] starts / cycle %d\n",
2633__FUNCTION__, this->process->pid, this->trdid, cycle );
2634#endif
2635
[657]2636// check chdev direction and type
[674]2637assert( __FUNCTION__, (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == false) ,
[657]2638"illegal chdev type or direction" );
2639
2640// check thread can yield
[663]2641thread_assert_can_yield( this , __FUNCTION__ );
[657]2642
[663]2643    // build extended pointer on temporary list
2644    temp_root_xp = XPTR( local_cxy , &temp_root );
2645                                                         
2646    // build extended pointer on client sockets queue (lock & root)
2647    queue_lock_xp = XPTR( local_cxy , &chdev->wait_lock );
2648    queue_root_xp = XPTR( local_cxy , &chdev->wait_root );
[657]2649
2650    while( 1 )  // TX server infinite loop
2651    {
[663]2652        // initialize temporary list of registered sockets as empty
2653        xlist_root_init( temp_root_xp );
2654        temp_nr = 0;
2655
[657]2656        // take the lock protecting the client sockets queue
[663]2657        remote_busylock_acquire( queue_lock_xp );
[657]2658
[663]2659        // build temporary list of all registered sockets
2660        if( xlist_is_empty( queue_root_xp ) == false ) 
[657]2661        {
[663]2662            XLIST_FOREACH( queue_root_xp , iter_xp )
2663            {
2664                // get client socket cluster and local pointer
2665                socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_list );
2666                socket_ptr = GET_PTR( socket_xp );
2667                socket_cxy = GET_CXY( socket_xp );
2668
2669                // register socket in temporary list
2670                xlist_add_last( temp_root_xp , XPTR( socket_cxy , &socket_ptr->tx_temp ));
2671                temp_nr++;
2672            }
2673        }
2674
2675        // release the lock protecting the client sockets queue
2676        remote_busylock_release( queue_lock_xp );
2677
2678        if( temp_nr > 0 )
2679        {
2680            // loop on temporary list
2681            XLIST_FOREACH( temp_root_xp , iter_xp )
2682            {
2683                // get client socket cluster and local pointer
2684                socket_xp  = XLIST_ELEMENT( iter_xp , socket_t , tx_temp );
2685                socket_ptr = GET_PTR( socket_xp );
2686                socket_cxy = GET_CXY( socket_xp );
2687
2688                // get cmd_valid & t2t_valid from socket descriptor
2689                cmd_valid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->tx_valid ));
2690
2691                // get r2t_valid from socket descriptor
2692                r2t_valid = (bool_t)remote_buf_status( XPTR( socket_cxy , &socket_ptr->r2tq ));
2693
2694                // test if socket is active
2695                if( cmd_valid || r2t_valid )  // active socket
2696                {
2697
2698#if DEBUG_DEV_NIC_TX
2699cycle = (uint32_t)hal_get_cycles();
2700pid  = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ));
2701fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ));
2702if( cycle > DEBUG_DEV_NIC_TX )
2703printk("\n[%s] thread[%x,%x] found socket[%x,%d] / cmd_valid %d / r2t_valid %d / cycle %d\n",
2704__FUNCTION__, this->process->pid, this->trdid, pid, fdid, cmd_valid, r2t_valid, cycle );
2705#endif
2706                    // build and send one packet/segment for this socket
2707                    dev_nic_tx_build_packet( cmd_valid,
2708                                             r2t_valid,
2709                                             socket_xp,
2710                                             k_buf,
2711                                             chdev );
2712#if DEBUG_DEV_NIC_TX
2713cycle = (uint32_t)hal_get_cycles();
2714if( cycle > DEBUG_DEV_NIC_TX )
2715dev_nic_packet_display( true,                // is_tx
2716                        this->process->pid,
2717                        this->trdid,
2718                        cycle,
2719                        k_buf );
2720#endif
2721                }
2722                else                          // inactive socket
2723                {
2724                   temp_nr--;
2725                }
2726            }  // end loop on temporary list
2727        }
2728
2729        // block & deschedule if no active socket found in current iteration
2730        if( temp_nr == 0 )
2731        {
[657]2732 
[663]2733#if DEBUG_DEV_NIC_TX
2734cycle = (uint32_t)hal_get_cycles();
2735if( cycle > DEBUG_DEV_NIC_TX )
2736printk("\n[%s] thread[%x,%x] no active socket => blocks on <CLIENT> / cycle %d\n",
2737__FUNCTION__, this->process->pid, this->trdid, cycle );
2738#endif
2739
[657]2740            // block and deschedule
2741            thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT );
2742            sched_yield( "waiting client" );
[663]2743
2744#if DEBUG_DEV_NIC_TX
2745cycle = (uint32_t)hal_get_cycles();
2746if( cycle > DEBUG_DEV_NIC_TX )
2747printk("\n[%s] thread[%x,%x] resumes / cycle %d\n",
2748__FUNCTION__, this->process->pid, this->trdid, cycle );
2749#endif
[657]2750        }
[663]2751    }   // end infinite while loop
2752}  // end dev_nic_tx_server()
[657]2753
2754
[663]2755/////////////////////////////////////////////
2756void dev_nic_packet_display( bool_t    is_tx,
2757                             pid_t     thread_pid,
2758                             trdid_t   thread_trdid,
2759                             uint32_t  cycle,
2760                             uint8_t * buf )
2761{
2762    // get ETH header fields
2763    uint64_t eth_dst_mac = ((uint64_t)buf[5]  << 40) |
2764                           ((uint64_t)buf[4]  << 32) |
2765                           ((uint64_t)buf[3]  << 24) |
2766                           ((uint64_t)buf[2]  << 16) |
2767                           ((uint64_t)buf[1]  <<  8) |
2768                           ((uint64_t)buf[0]       ) ;
[657]2769
[663]2770    uint64_t eth_src_mac = ((uint64_t)buf[11] << 40) |
2771                           ((uint64_t)buf[10] << 32) |
2772                           ((uint64_t)buf[9]  << 24) |
2773                           ((uint64_t)buf[8]  << 16) |
2774                           ((uint64_t)buf[7]  <<  8) |
2775                           ((uint64_t)buf[6]       ) ;
[657]2776
[663]2777    uint16_t eth_length  = ((uint16_t)buf[12] <<  8) |
2778                           ((uint16_t)buf[13]      ) ;
[657]2779
[663]2780    // get IP header fields
2781    uint8_t  ip_version  = buf[14];
2782    uint8_t  ip_tos      = buf[15];
2783    uint16_t ip_length   = ((uint16_t)buf[16] << 8) |
2784                           ((uint16_t)buf[17]     ) ;
[657]2785
[663]2786    uint16_t ip_ident    = ((uint16_t)buf[18] << 8) |
2787                           ((uint16_t)buf[19]     ) ;
2788    uint16_t ip_offset   = ((uint16_t)buf[20] << 8) |
2789                           ((uint16_t)buf[21]     ) ;
[657]2790
[663]2791    uint8_t  ip_ttl      = buf[22];
2792    uint8_t  ip_protocol = buf[23];
2793    uint16_t ip_checksum = ((uint16_t)buf[24] << 8) |
2794                           ((uint16_t)buf[25]     ) ;
[657]2795
[663]2796    uint32_t ip_src_addr = ((uint32_t)buf[26] << 24) |
2797                           ((uint32_t)buf[27] << 16) |
2798                           ((uint32_t)buf[28] <<  8) |
2799                           ((uint32_t)buf[29]      ) ;
2800
2801    uint32_t ip_dst_addr = ((uint32_t)buf[30] << 24) |
2802                           ((uint32_t)buf[31] << 16) |
2803                           ((uint32_t)buf[32] <<  8) |
2804                           ((uint32_t)buf[33]      ) ;
2805   
2806    // get pointers on TXT0 chdev
2807    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
2808    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
2809    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
2810
2811    // get extended pointer on remote TXT0 chdev lock
2812    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
2813
2814    // get TXT0 lock
2815    remote_busylock_acquire( lock_xp );
2816
2817    if( is_tx )
2818    {
2819        nolock_printk("\n*** NIC_TX server thread[%x,%x] send packet / cycle %d\n",
2820        thread_pid, thread_trdid, cycle );
2821    }
2822    else
2823    {
2824        nolock_printk("\n*** NIC_RX server thread[%x,%x] get packet / cycle %d\n",
2825        thread_pid, thread_trdid, cycle );
2826    }
2827
2828    nolock_printk("\n***** ETH header *****\n");
2829    nolock_printk(" - dst_mac  [6] = %l\n" , eth_dst_mac );
2830    nolock_printk(" - src_mac  [6] = %l\n" , eth_src_mac );
2831    nolock_printk(" - length   [2] = %d\n" , (uint32_t)eth_length );
2832    nolock_printk("***** IP  header *****\n");
2833    nolock_printk(" - version  [1] = %x\n" , (uint32_t)ip_version );
2834    nolock_printk(" - tos      [1] = %x\n" , (uint32_t)ip_tos );
2835    nolock_printk(" - length   [2] = %d\n" , (uint32_t)ip_length );
2836    nolock_printk(" - ident    [2] = %x\n" , (uint32_t)ip_ident  );
2837    nolock_printk(" - offset   [2] = %x\n" , (uint32_t)ip_offset );
2838    nolock_printk(" - ttl      [1] = %x\n" , (uint32_t)ip_ttl );
2839    nolock_printk(" - protocol [1] = %x\n" , (uint32_t)ip_protocol );
2840    nolock_printk(" - checksum [2] = %x\n" , (uint32_t)ip_checksum );
2841    nolock_printk(" - src_addr [4] = %x\n" , (uint32_t)ip_src_addr );
2842    nolock_printk(" - dst_addr [4] = %x\n" , (uint32_t)ip_dst_addr );
2843
2844    // get UDP / TCP fields
2845    if ( ip_protocol == PROTOCOL_UDP )
2846    {
2847        uint16_t udp_src_port = ((uint16_t)buf[34] << 8) |
2848                                ((uint16_t)buf[35]     ) ;
2849        uint16_t udp_dst_port = ((uint16_t)buf[36] << 8) |
2850                                ((uint16_t)buf[37]     ) ;
2851
2852        nolock_printk("***** UDP header *****\n");
2853        nolock_printk(" - src_port [2] = %d\n" , (uint32_t)udp_src_port );
2854        nolock_printk(" - dst_port [2] = %d\n" , (uint32_t)udp_dst_port );
2855    }
2856    else if( ip_protocol == PROTOCOL_TCP )
2857    {
2858        uint16_t tcp_src_port = ((uint16_t)buf[34] << 8) |
2859                                ((uint16_t)buf[35]     ) ;
2860        uint16_t tcp_dst_port = ((uint16_t)buf[36] << 8) |
2861                                ((uint16_t)buf[37]     ) ;
2862
2863        uint32_t tcp_seq_num  = ((uint32_t)buf[38] << 24) |
2864                                ((uint32_t)buf[39] << 16) |
2865                                ((uint32_t)buf[40] <<  8) |
2866                                ((uint32_t)buf[41]      ) ;
2867
2868        uint32_t tcp_ack_num  = ((uint32_t)buf[42] << 24) |
2869                                ((uint32_t)buf[43] << 16) |
2870                                ((uint32_t)buf[44] <<  8) |
2871                                ((uint32_t)buf[45]      ) ;
2872
2873        uint8_t  tcp_hlen      = buf[46];
2874        uint8_t  tcp_flags     = buf[47];
2875        uint16_t tcp_window    = ((uint16_t)buf[48] << 8) |
2876                                 ((uint16_t)buf[49]     ) ;
2877
2878        uint16_t tcp_checksum  = ((uint16_t)buf[50] << 8) |
2879                                 ((uint16_t)buf[51]     ) ;
2880        uint16_t tcp_urgent    = ((uint16_t)buf[52] << 8) |
2881                                 ((uint16_t)buf[53]     ) ;
2882
2883        nolock_printk("***** TCP header *****\n");
2884        nolock_printk(" - src_port [2] = %x\n" , (uint32_t)tcp_src_port );
2885        nolock_printk(" - dst_port [2] = %x\n" , (uint32_t)tcp_dst_port );
2886        nolock_printk(" - seq_num  [4] = %x\n" , (uint32_t)tcp_seq_num );
2887        nolock_printk(" - ack_num  [4] = %x\n" , (uint32_t)tcp_ack_num );
2888        nolock_printk(" - hlen     [1] = %d\n" , (uint32_t)tcp_hlen );
2889        nolock_printk(" - flags    [1] = %x\n" , (uint32_t)tcp_flags );
2890        nolock_printk(" - window   [2] = %x\n" , (uint32_t)tcp_window );
2891        nolock_printk(" - checksum [2] = %x\n" , (uint32_t)tcp_checksum );
2892        nolock_printk(" - urgent   [2] = %x\n" , (uint32_t)tcp_urgent );
2893    }
2894    else
2895    {
2896        nolock_printk("!!!!! undefined transport protocol !!!!!\n");
2897    }
2898
2899    // release TXT0 lock
2900    remote_busylock_release( lock_xp );
2901
2902}  // end dev_nic_packet_display()
2903
Note: See TracBrowser for help on using the repository browser.