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

Last change on this file since 690 was 683, checked in by alain, 3 years ago

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

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