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

Last change on this file since 669 was 668, checked in by alain, 4 years ago

typos...

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