- Timestamp:
- Oct 10, 2020, 4:56:11 PM (4 years ago)
- Location:
- trunk/kernel/devices
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/devices/dev_ioc.c
r657 r663 78 78 lid ); 79 79 80 80 assert( (error == 0) , "cannot create server thread" ); 81 81 82 82 // set "server" field in chdev descriptor -
trunk/kernel/devices/dev_mmc.h
r657 r663 96 96 97 97 /***************************************************************************************** 98 * This function initializes the driver specific fields in the generic MMC device99 * descriptor, and the implementation specificdriver.98 * This function initializes the driver specific fields in the local MMC chdev, 99 * and initializes the implementation specific MMC driver. 100 100 * It must be executed once in any cluster containing an L2 cache. 101 101 ***************************************************************************************** … … 105 105 106 106 /***************************************************************************************** 107 * This function invalidates all cache lines covering a memory buffer 108 * in the physical address space.107 * This function invalidates all cache lines covering a memory buffer defined by 108 * the <buf_xp> and <buf_size> arguments. 109 109 * It can be executed by any thread in any cluster, because it uses remote accesses 110 110 * to access both the MMC device descriptor, and the L2 cache configuration interface. … … 119 119 /***************************************************************************************** 120 120 * This function forces the L2 cache to synchronize the L3 cache for all cache lines 121 * covering a memory buffer in the physical address space.121 * covering a memory buffer defined by the <buf_xp> and <buf_size> arguments. 122 122 * It can be executed by any thread in any cluster, because it uses remote accesses 123 123 * to access both the MMC device descriptor, and the L2 cache configuration interface. -
trunk/kernel/devices/dev_nic.c
r657 r663 1 1 2 /* 2 3 * dev_nic.c - NIC (Network Controler) generic device API implementation. … … 26 27 #include <hal_uspace.h> 27 28 #include <remote_buf.h> 29 #include <memcpy.h> 28 30 #include <printk.h> 29 31 #include <chdev.h> 30 32 #include <thread.h> 31 #include < socket.h>33 #include <ksocket.h> 32 34 #include <hal_drivers.h> 33 35 #include <dev_nic.h> … … 41 43 extern chdev_directory_t chdev_dir; // allocated in kernel_init.c 42 44 45 //////////////////////////////////// 46 void 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) 100 thread_t * this = CURRENT_THREAD; 101 if( is_rx ) 102 printk("\n[%s] thread[%x,%x] initialized NIC_RX[%d] / server %x\n", 103 __FUNCTION__, this->process->pid, this->trdid, channel, new_thread->trdid ); 104 else 105 printk("\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 //////////////////////////////////////// 117 uint32_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 ////////////////////////////////////////// 141 error_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 ////////////////////////////////// 167 error_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 //////////////////////////////////// 188 error_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 43 209 //////////////////////////////////////////////////////////////////////////////////////////// 44 // This static function is used by the dev_nic_rx_handle_tcp() & dev_nic_tx_handle_tcp() 45 // functions to check acceptability of a given sequence number. It returns true when 46 // the <seq> argument is contained in a wrap-around window defined by the <min> and <max> 47 // arguments. The window wrap-around when (min > max). 210 // Static functions called by the NIC_RX server & NIC_TX server threads 211 //////////////////////////////////////////////////////////////////////////////////////////// 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). 48 218 //////////////////////////////////////////////////////////////////////////////////////////// 49 219 // @ seq : [in] value to be checked. … … 65 235 } 66 236 67 ////////////////////////////////////////////////////////////////////////////////////////////68 // this static function compute a channel index in range [0,nic_channelx[ from69 // a remote IP address and remote port.70 // TODO this function should be provided by the NIC driver.71 ////////////////////////////////////////////////////////////////////////////////////////////72 // @ addr : [in] IP address.73 // @ port : [in] TCP/UDP port.74 ////////////////////////////////////////////////////////////////////////////////////////////75 static inline uint32_t dev_nic_channel_index( uint32_t addr,76 uint16_t port )77 {78 // get number of NIC channels79 uint32_t nic_channels = LOCAL_CLUSTER->nb_nic_channels;80 81 // compute NIC channel index82 return ( ((addr ) & 0xFF) ^83 ((addr > 8 ) & 0xFF) ^84 ((addr > 16) & 0xFF) ^85 ((addr > 24) & 0xFF) ^86 ((port ) & 0xFF) ^87 ((port > 8 ) & 0xFF) ) % nic_channels;88 }89 90 237 //////////////////////////////////////////////////////////////////////////////////////// 91 238 // This static function computes the checksum for an IP packet header. … … 95 242 // @ return the checksum value on 16 bits 96 243 //////////////////////////////////////////////////////////////////////////////////////// 97 uint16_t dev_nic_ip_checksum( uint8_t * buffer )244 static uint16_t dev_nic_ip_checksum( uint8_t * buffer ) 98 245 { 99 246 uint32_t i; … … 121 268 // @ return the checksum value on 16 bits 122 269 //////////////////////////////////////////////////////////////////////////////////////// 123 uint16_t dev_nic_udp_checksum( uint8_t * buffer,124 uint32_t size )270 static uint16_t dev_nic_udp_checksum( uint8_t * buffer, 271 uint32_t size ) 125 272 { 126 273 uint32_t i; … … 158 305 159 306 //////////////////////////////////////////////////////////////////////////////////////// 160 // This static function computes the checksum for a TCP segment defined by 161 // the <buffer> and <size> arguments. 162 // It includes the pseudo header defined by the <src_ip_addr>, <dst_ip_addr>, 163 // <size> arguments, and by the TCP_PROTOCOL code. 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. 164 310 //////////////////////////////////////////////////////////////////////////////////////// 165 311 // @ buffer : [in] pointer on TCP segment base. 166 // @ size : [in] number of bytes in thissegment (including header).312 // @ tcp_length : [in] number of bytes in this TCP segment (including header). 167 313 // @ src_ip_addr : [in] source IP address (pseudo header) 168 314 // @ dst_ip_addr : [in] destination IP address (pseudo header) 169 315 // @ return the checksum value on 16 bits 170 316 //////////////////////////////////////////////////////////////////////////////////////// 171 uint16_t dev_nic_tcp_checksum( uint8_t * buffer,172 uint32_t size,173 uint32_t src_ip_addr,174 uint32_t dst_ip_addr )317 static 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 ) 175 321 { 176 322 uint32_t i; … … 182 328 // compute max & buf 183 329 buf = (uint16_t *)buffer; 184 max = size>> 1;330 max = tcp_length >> 1; 185 331 186 332 // extend buffer[] if required 187 if( size& 1 )333 if( tcp_length & 1 ) 188 334 { 189 335 max++; 190 buffer[ size] = 0;336 buffer[tcp_length] = 0; 191 337 } 192 338 193 339 // compute checksum for TCP segment 194 for( i = 0 , cs = 0 ; i < size; i++ ) cs += buf[i];340 for( i = 0 , cs = 0 ; i < tcp_length ; i++ ) cs += buf[i]; 195 341 196 342 // complete checksum for pseudo-header … … 198 344 cs += dst_ip_addr; 199 345 cs += PROTOCOL_TCP; 200 cs += size;346 cs += tcp_length; 201 347 202 348 // handle carry … … 213 359 } 214 360 215 ////////////////////////////////// 216 void dev_nic_init( chdev_t * nic ) 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 /////////////////////////////////////////////////////////////////////////////////////////// 372 static void dev_nic_unblock_tx_client( xptr_t socket_xp, 373 int32_t status ) 217 374 { 218 // get "channel" & "is_rx" fields from chdev descriptor 219 uint32_t channel = nic->channel; 220 bool_t is_rx = nic->is_rx; 221 222 // set chdev name 223 if( is_rx ) snprintf( nic->name , 16 , "nic%d_rx" , channel ); 224 else snprintf( nic->name , 16 , "nic%d_tx" , channel ); 225 226 // call driver init function 227 hal_drivers_nic_init( nic ); 228 229 // select a core to execute the NIC server thread 230 lid_t lid = cluster_select_local_core( local_cxy ); 231 232 // bind the NIC IRQ to the selected core 233 // but does NOT enable it 234 dev_pic_bind_irq( lid , nic ); 235 236 // create server thread 237 thread_t * new_thread; 238 error_t error; 239 240 error = thread_kernel_create( &new_thread, 241 THREAD_DEV, 242 &chdev_server_func, 243 nic, 244 lid ); 245 246 assert( (error == 0) , "cannot create server thread" ); 247 248 // set "server" field in chdev descriptor 249 nic->server = new_thread; 250 251 // set "chdev" field in thread descriptor 252 new_thread->chdev = nic; 253 254 // unblock server thread 255 thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL ); 256 257 } // end dev_nic_init() 258 259 260 ///////////////////////////////////////////////////////////////////////////////////////// 261 // Functions implementing the SOCKET related syscalls 262 ///////////////////////////////////////////////////////////////////////////////////////// 263 264 ////////////////////////////////////// 265 int dev_nic_socket( uint32_t domain, 266 uint32_t type ) 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 ); 378 379 if( status != CMD_STS_SUCCESS ) 380 { 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 )); 385 386 printk("\n[ERROR] reported by %s : socket[%x,%d] / %s / cmd %s / error %s \n", 387 __FUNCTION__, pid, fdid, socket_state_str(sock_state), 388 socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) ); 389 } 390 391 // set tx_sts field in socket descriptor 392 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_sts ) , status ); 393 394 // get extended point on TX client thread 395 xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client )); 396 397 // unblock the client thread 398 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 399 400 } // end dev_nic_unblock_tx_client() 401 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 /////////////////////////////////////////////////////////////////////////////////////////// 413 static void dev_nic_unblock_rx_client( xptr_t socket_xp, 414 int32_t status ) 267 415 { 268 uint32_t fdid; 269 socket_t * socket; 270 error_t error; 271 272 // allocate memory for the file descriptor and for the socket 273 error = socket_create( local_cxy, 274 domain, 275 type, 276 &socket, // unused here 277 &fdid ); 278 279 if( error ) return -1; 280 return fdid; 281 } 282 283 //////////////////////////////// 284 int dev_nic_bind( uint32_t fdid, 285 uint32_t addr, 286 uint16_t port ) 287 { 288 vfs_inode_type_t type; 289 socket_t * socket; 290 uint32_t state; 291 292 thread_t * this = CURRENT_THREAD; 293 process_t * process = this->process; 294 295 // get pointers on file descriptor 296 xptr_t file_xp = process_fd_get_xptr( process , fdid ); 297 vfs_file_t * file_ptr = GET_PTR( file_xp ); 298 cxy_t file_cxy = GET_CXY( file_xp ); 299 300 // check file_xp 301 if( file_xp == XPTR_NULL ) 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 ); 419 420 if( status != CMD_STS_SUCCESS ) 302 421 { 303 printk("\n[ERROR] in %s : undefined fdid %d", 304 __FUNCTION__, fdid ); 305 return -1; 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 )); 426 427 printk("\n[ERROR] reported by %s : socket[%x,%d] / %s / cmd %s / error %s\n", 428 __FUNCTION__, pid, fdid, socket_state_str(sock_state), 429 socket_cmd_type_str(cmd_type), socket_cmd_sts_str(status) ); 306 430 } 307 431 308 type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 309 socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 310 311 // check file descriptor type 312 if( type != INODE_TYPE_SOCK ) 313 { 314 printk("\n[ERROR] in %s : illegal file type %s", 315 __FUNCTION__, vfs_inode_type_str( type ) ); 316 return -1; 317 } 318 319 state = (type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND; 320 321 // update the socket descriptor 322 hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr ); 323 hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port ); 324 hal_remote_s32( XPTR( file_cxy , &socket->state ) , state ); 325 326 return 0; 327 328 } // end dev_nic_bind() 329 330 ////////////////////////////////// 331 int dev_nic_listen( uint32_t fdid, 332 uint32_t max_pending ) 333 { 334 xptr_t file_xp; 335 vfs_file_t * file_ptr; 336 cxy_t file_cxy; 337 vfs_inode_type_t file_type; 338 socket_t * socket_ptr; 339 uint32_t socket_type; 340 uint32_t socket_state; 341 342 thread_t * this = CURRENT_THREAD; 343 process_t * process = this->process; 344 345 if( max_pending != 0 ) 346 { 347 printk("\n[WARNING] in %s : max_pending argument non supported\n", 348 __FUNCTION__ ); 349 } 350 351 // get pointers on file descriptor 352 file_xp = process_fd_get_xptr( process , fdid ); 353 file_ptr = GET_PTR( file_xp ); 354 file_cxy = GET_CXY( file_xp ); 355 356 // check file_xp 357 if( file_xp == XPTR_NULL ) 358 { 359 printk("\n[ERROR] in %s : undefined fdid %d", 360 __FUNCTION__, fdid ); 361 return -1; 362 } 363 364 file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 365 socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 366 367 // check file descriptor type 368 if( file_type != INODE_TYPE_SOCK ) 369 { 370 printk("\n[ERROR] in %s : illegal file type %s", 371 __FUNCTION__, vfs_inode_type_str(file_type) ); 372 return -1; 373 } 374 375 // get socket type and state 376 socket_type = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type )); 377 socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state )); 378 379 // check socket type 380 if( socket_type != SOCK_STREAM ) 381 { 382 printk("\n[ERROR] in %s : illegal socket type", 383 __FUNCTION__ ); 384 return -1; 385 } 386 387 // check socket state 388 if( socket_state != TCP_STATE_BOUND ) 389 { 390 printk("\n[ERROR] in %s : illegal socket state %s", 391 __FUNCTION__, socket_state_str(socket_state) ); 392 return -1; 393 } 394 395 // update socket.state 396 hal_remote_s32( XPTR( file_cxy , &socket_ptr->state ) , TCP_STATE_LISTEN ); 397 398 return 0; 399 400 } // end dev_nic_listen() 401 402 /////////////////////////////////// 403 int dev_nic_connect( uint32_t fdid, 404 uint32_t remote_addr, 405 uint16_t remote_port ) 406 { 407 vfs_inode_type_t file_type; 408 socket_t * socket; 409 uint32_t socket_state; // socket state 410 uint32_t socket_type; // socket type 411 uint32_t local_addr; // local IP address 412 uint32_t local_port; // local port 413 xptr_t tx_server_xp; // extended pointer on TX server thread 414 thread_t * tx_server_ptr; // local pointer on TX server thread 415 416 thread_t * this = CURRENT_THREAD; 417 process_t * process = this->process; 418 419 // get pointers on file descriptor 420 xptr_t file_xp = process_fd_get_xptr( process , fdid ); 421 vfs_file_t * file_ptr = GET_PTR( file_xp ); 422 cxy_t file_cxy = GET_CXY( file_xp ); 423 424 // check file_xp 425 if( file_xp == XPTR_NULL ) 426 { 427 printk("\n[ERROR] in %s : undefined fdid %d", 428 __FUNCTION__, fdid ); 429 return -1; 430 } 431 432 file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 433 socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 434 435 // check file descriptor type 436 if( file_type != INODE_TYPE_SOCK ) 437 { 438 printk("\n[ERROR] in %s : illegal file type %s", 439 __FUNCTION__, vfs_inode_type_str( file_type ) ); 440 return -1; 441 } 442 443 // get relevant socket infos 444 socket_type = hal_remote_l32( XPTR( file_cxy , &socket->type ) ); 445 socket_state = hal_remote_l32( XPTR( file_cxy , &socket->state ) ); 446 local_addr = hal_remote_l32( XPTR( file_cxy , &socket->local_addr ) ); 447 local_port = hal_remote_l32( XPTR( file_cxy , &socket->local_port ) ); 448 449 if( socket_type == SOCK_DGRAM ) // UDP 450 { 451 if( socket_state != UDP_STATE_BOUND ) 452 { 453 printk("\n[ERROR] in %s : illegal socket statea %s for CONNECT", 454 __FUNCTION__, socket_state_str(socket_state) ); 455 return -1; 456 } 457 } 458 else if( socket_type == SOCK_STREAM ) // TCP 459 { 460 if( socket_state != TCP_STATE_BOUND ) 461 { 462 printk("\n[ERROR] in %s : illegal socket state %s for CONNECT", 463 __FUNCTION__, socket_state_str(socket_state) ); 464 return -1; 465 } 466 } 467 else 468 { 469 printk("\n[ERROR] in %s : illegal socket type %d for CONNECT", 470 __FUNCTION__, socket_type ); 471 return -1; 472 } 473 474 // compute nic_channel index from remote_addr and remote_port 475 uint32_t nic_channel = dev_nic_channel_index( remote_addr , remote_port ); 476 477 // link new socket to chdev servers 478 socket_link_to_servers( XPTR( file_cxy , socket ), 479 nic_channel ); 480 481 // update the socket descriptor 482 hal_remote_s32( XPTR( file_cxy , &socket->remote_addr ) , remote_addr ); 483 hal_remote_s32( XPTR( file_cxy , &socket->remote_port ) , remote_port ); 484 hal_remote_s32( XPTR( file_cxy , &socket->nic_channel ) , nic_channel ); 485 486 // the actual connection mechanism depends on socket type 487 // UDP : client thread directly updates the local socket state 488 // TCP : client thread request TX server thread to start the 3 steps handshake 489 490 if( socket_type == SOCK_DGRAM ) // UDP 491 { 492 // directly update the local socket state 493 hal_remote_s32( XPTR( file_cxy , &socket->state ) , UDP_STATE_CONNECT ); 494 } 495 else // TCP 496 { 497 // get pointers on NIC_TX[index] chdev 498 xptr_t tx_chdev_xp = chdev_dir.nic_tx[nic_channel]; 499 chdev_t * tx_chdev_ptr = GET_PTR( tx_chdev_xp ); 500 cxy_t tx_chdev_cxy = GET_CXY( tx_chdev_xp ); 501 502 // get pointers on NIC_TX[channel] server thread 503 tx_server_ptr = hal_remote_lpt( XPTR( tx_chdev_cxy , &tx_chdev_ptr->server )); 504 tx_server_xp = XPTR( tx_chdev_cxy , tx_server_ptr ); 505 506 // register command arguments in socket descriptor 507 hal_remote_s64( XPTR( file_cxy , &socket->tx_cmd ), 508 SOCKET_TX_CONNECT ); 509 510 // update the "tx_client" field in socket descriptor 511 hal_remote_s64( XPTR( file_cxy , &socket->tx_client ), 512 XPTR( local_cxy , this ) ); 513 514 // unblock NIC_TX server thread 515 thread_unblock( tx_server_xp , THREAD_BLOCKED_CLIENT ); 516 517 // block on THREAD_BLOCKED_IO condition and deschedules 518 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO ); 519 sched_yield( "blocked in connect" ); 520 521 // reset the "tx_client" field in socket descriptor 522 hal_remote_s64( XPTR( file_cxy , &socket->tx_client ), 523 XPTR_NULL ); 524 } 525 526 return 0; 527 528 } // end dev_nic_connect() 529 530 //////////////////////////////////// 531 int dev_nic_accept( uint32_t fdid, 532 uint32_t * remote_addr, 533 uint16_t * remote_port ) 534 { 535 xptr_t file_xp; // extended pointer on remote file 536 vfs_file_t * file_ptr; 537 cxy_t file_cxy; 538 vfs_inode_type_t file_type; // file descriptor type 539 socket_t * socket; // local pointer on remote waiting socket 540 uint32_t socket_type; // waiting socket type 541 uint32_t socket_state; // waiting socket state 542 uint32_t socket_domain; // waiting socket domain 543 uint32_t socket_local_addr; // waiting socket local IP address 544 uint32_t socket_local_port; // waiting socket local port 545 xptr_t crqq_xp; // extended pointer on socket.crqq queue 546 socket_t * new_socket; // local pointer on new socket 547 uint32_t new_fdid; // new socket file descriptor index 548 sockaddr_t new_sockaddr; // one request in crqq queue 549 uint32_t new_remote_addr; // new socket remote IP address 550 uint32_t new_remote_port; // new socket remote port 551 error_t error; 552 553 thread_t * this = CURRENT_THREAD; 554 process_t * process = this->process; 555 556 // get pointers on file descriptor 557 file_xp = process_fd_get_xptr( process , fdid ); 558 file_ptr = GET_PTR( file_xp ); 559 file_cxy = GET_CXY( file_xp ); 560 561 // check file_xp 562 if( file_xp == XPTR_NULL ) 563 { 564 printk("\n[ERROR] in %s : undefined fdid %d", 565 __FUNCTION__, fdid ); 566 return -1; 567 } 568 569 file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 570 socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 571 572 // check file descriptor type 573 if( file_type != INODE_TYPE_SOCK ) 574 { 575 printk("\n[ERROR] in %s : illegal file type %s / thread[%x,%x]\n", 576 __FUNCTION__, vfs_inode_type_str(file_type), process->pid, this->trdid ); 577 return -1; 578 } 579 580 // get socket type, domain, state, local_addr and local_port 581 socket_type = hal_remote_l32( XPTR( file_cxy , &socket->type )); 582 socket_state = hal_remote_l32( XPTR( file_cxy , &socket->state )); 583 socket_domain = hal_remote_l32( XPTR( file_cxy , &socket->domain )); 584 socket_local_addr = hal_remote_l32( XPTR( file_cxy , &socket->local_addr )); 585 socket_local_port = hal_remote_l32( XPTR( file_cxy , &socket->local_port )); 586 587 // check socket type 588 if( socket_type != SOCK_STREAM ) 589 { 590 printk("\n[ERROR] in %s : illegal socket type / thread[%x,%x]\n", 591 __FUNCTION__, process->pid , this->trdid ); 592 return -1; 593 } 594 595 // check socket state 596 if( socket_state != TCP_STATE_LISTEN ) 597 { 598 printk("\n[ERROR] in %s : illegal socket state %s / thread[%x,%x]\n", 599 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid ); 600 return -1; 601 } 602 603 // select a cluster for the new socket 604 cxy_t new_cxy = cluster_random_select(); 605 606 // allocate memory for the new socket descriptor 607 error = socket_create( new_cxy, 608 socket_domain, 609 socket_type, 610 &new_socket, 611 &new_fdid ); 612 if( error ) 613 { 614 printk("\n[ERROR] in %s : cannot allocate new socket / thread[%x,%x]\n", 615 __FUNCTION__, process->pid, this->trdid ); 616 return -1; 617 } 618 619 // build extended pointer on socket.crqq 620 crqq_xp = XPTR( file_cxy , &socket->crqq ); 621 622 // blocks and deschedules if requests queue empty 623 if( remote_buf_status( crqq_xp ) == 0 ) 624 { 625 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO ); 626 sched_yield( "socket.crqq queue empty"); 627 } 628 629 // extract first request from the socket.crqq queue 630 remote_buf_get_to_kernel( crqq_xp, 631 (uint8_t *)(&new_sockaddr), 632 sizeof(sockaddr_t) ); 633 634 new_remote_addr = new_sockaddr.s_addr; 635 new_remote_port = new_sockaddr.s_port; 636 637 // compute NIC channel index from remote_addr and remote_port 638 uint32_t nic_channel = dev_nic_channel_index( new_remote_addr , new_remote_port ); 639 640 // update new socket descriptor 641 new_socket->local_addr = hal_remote_l32(XPTR( file_cxy , &socket->local_addr )); 642 new_socket->local_port = hal_remote_l32(XPTR( file_cxy , &socket->local_port )); 643 new_socket->remote_addr = new_remote_addr; 644 new_socket->remote_port = new_remote_port; 645 new_socket->nic_channel = nic_channel; 646 647 // link new socket to chdev servers 648 socket_link_to_servers( XPTR( new_cxy , new_socket ), 649 nic_channel ); 650 // return success 651 *remote_addr = new_remote_addr; 652 *remote_port = new_remote_port; 653 654 return new_fdid; 655 656 } // end dev_nic_accept() 657 658 //////////////////////////////////////////////////////////////////////////////////////// 659 // This static and blocking function is called by the four functions : 660 // dev_nic_send() / dev_nic_recv() / dev_nic_sendto() / dev_nic_recvfrom(). 661 //////////////////////////////////////////////////////////////////////////////////////// 662 // Implementation note 663 // The behavior is very different for SEND & RECV : 664 // - For a SEND, the client thread checks that there is no TX command registered 665 // in the socket. It registers the command arguments in the socket descriptor 666 // (tx_client, tx_cmd, tx_buf, tx_len). Then the client thread unblocks the 667 // TX server thread from the BLOCKED_CLIENT condition, blocks itself on the 668 // BLOCKED_IO condition, and deschedules. It is unblocked by the TX server thread 669 // when the last byte has been sent (for UDP) or acknowledged (for TCP). 670 // When the client thread resumes, it reset the command in socket, and returns. 671 // - For a RECV, the client thread checks that there is no RX command registered 672 // in the socket. It registers itself in socket (rx_client). It checks the status 673 // of the receive buffer. It the rx_buf is empty, it blocks on the BLOCKED_IO 674 // condition, and deschedules. It is unblocked by the RX server thread when an UDP 675 // packet or TCP segment has been writen in the rx_buf. When it resumes, it moves 676 // the available data from the rx_buf to the user buffer, reset its registration 677 // in socket (reset the rx_buf for an UDP socket), and returns. 678 //////////////////////////////////////////////////////////////////////////////////////// 679 int dev_nic_register_cmd( bool_t is_send, 680 uint32_t fdid, 681 uint8_t * u_buf, 682 uint32_t length, 683 bool_t explicit, 684 uint32_t explicit_addr, 685 uint32_t explicit_port ) 686 { 687 vfs_inode_type_t file_type; // file descriptor type 688 socket_t * socket_ptr; // local pointer on socket descriptor 689 uint32_t socket_state; // current socket state 690 uint32_t socket_type; // socket type (UDP/TCP) 691 uint32_t nic_channel; // NIC channel for this socket 692 xptr_t socket_lock_xp; // extended pointer on socket lock 693 xptr_t file_xp; // extended pointer on file descriptor 694 vfs_file_t * file_ptr; 695 cxy_t file_cxy; 696 xptr_t chdev_xp; // extended pointer on NIC_TX[channel] chdev 697 chdev_t * chdev_ptr; 698 cxy_t chdev_cxy; 699 uint32_t remote_addr; 700 uint32_t remote_port; 701 uint32_t status; // number of bytes in rx_buf 702 int32_t moved_bytes; // total number of moved bytes (fot return) 703 xptr_t server_xp; // extended pointer on NIC_TX / NIC_RX server thread 704 thread_t * server_ptr; // local pointer on NIC_TX / NIC_RX server thread 705 706 thread_t * this = CURRENT_THREAD; 707 process_t * process = this->process; 708 709 // get pointers on file descriptor identifying the socket 710 file_xp = process_fd_get_xptr( process , fdid ); 711 file_ptr = GET_PTR( file_xp ); 712 file_cxy = GET_CXY( file_xp ); 713 714 if( file_xp == XPTR_NULL ) 715 { 716 printk("\n[ERROR] in %s : undefined fdid %d / thread%x,%x]\n", 717 __FUNCTION__, fdid , process->pid, this->trdid ); 718 return -1; 719 } 720 721 // get file type and socket pointer 722 file_type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 723 724 // get local pointer on socket 725 socket_ptr = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 726 727 // check file descriptor type 728 if( file_type != INODE_TYPE_SOCK ) 729 { 730 printk("\n[ERROR] in %s : illegal file type %s / fdid %d / thread%x,%x]\n", 731 __FUNCTION__, vfs_inode_type_str(file_type), fdid, process->pid, this->trdid ); 732 return -1; 733 } 734 735 // build extended pointer on file lock protecting socket 736 socket_lock_xp = XPTR( file_cxy , &file_ptr->lock ); 737 738 // take the socket lock 739 remote_rwlock_wr_acquire( socket_lock_xp ); 740 741 // get socket type, state, and channel 742 socket_type = hal_remote_l32( XPTR( file_cxy , &socket_ptr->type )); 743 socket_state = hal_remote_l32( XPTR( file_cxy , &socket_ptr->state )); 744 nic_channel = hal_remote_l32( XPTR( file_cxy , &socket_ptr->nic_channel )); 745 746 // check socket state / type 747 if( socket_type == SOCK_STREAM ) // TCP socket 748 { 749 if( socket_state != TCP_STATE_ESTAB ) 750 { 751 printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n", 752 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid ); 753 return -1; 754 } 755 756 if( explicit ) 757 { 758 // get remote IP address and type from socket descriptor 759 remote_addr = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_addr )); 760 remote_port = hal_remote_l32( XPTR( file_cxy , &socket_ptr->remote_port )); 761 762 if( (remote_addr != explicit_addr) || (remote_port != explicit_port) ) 763 { 764 printk("\n[ERROR] in %s : wrong expliciy access / thread%x,%x]\n", 765 __FUNCTION__, process->pid, this->trdid ); 766 return -1; 767 } 768 } 769 } 770 else // UDP socket 771 { 772 if( explicit ) 773 { 774 if( socket_state == UDP_STATE_UNBOUND ) 775 { 776 printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n", 777 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid ); 778 return -1; 779 } 780 781 // update remote IP address and port into socket descriptor 782 hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_addr ), explicit_addr ); 783 hal_remote_s32( XPTR( file_cxy , &socket_ptr->remote_port ), explicit_port ); 784 } 785 else 786 { 787 if( socket_state != UDP_STATE_CONNECT ) 788 { 789 printk("\n[ERROR] in %s : illegal SEND/RECV for state %s / thread%x,%x]\n", 790 __FUNCTION__, socket_state_str(socket_state), process->pid, this->trdid ); 791 return -1; 792 } 793 } 794 } 795 796 /////////////////////////////////////////////////////// 797 if( is_send ) // SEND command 798 { 799 // build extended pointer on socket "tx_client" 800 xptr_t client_xp = XPTR( file_cxy , &socket_ptr->tx_client ); 801 802 // check no previous SEND command 803 xptr_t client = hal_remote_l64( client_xp ); 804 805 if( client != XPTR_NULL ) // release socket lock and return error 806 { 807 // release socket lock 808 remote_rwlock_wr_release( socket_lock_xp ); 809 810 // get previous thread cluster & local pointer 811 cxy_t prev_cxy = GET_CXY( client ); 812 thread_t * prev_ptr = GET_PTR( client ); 813 814 // get previous command type and trdid 815 uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type )); 816 uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid )); 817 818 printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n", 819 __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid, 820 process->pid, this->trdid ); 821 822 return -1; 823 } 824 825 // client thread registers in socket descriptor 826 hal_remote_s64( client_xp , XPTR( local_cxy , this ) ); 827 hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_cmd ) , SOCKET_TX_SEND ); 828 hal_remote_spt( XPTR( file_cxy , &socket_ptr->tx_buf ) , u_buf ); 829 hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_len ) , length ); 830 hal_remote_s32( XPTR( file_cxy , &socket_ptr->tx_todo ) , length ); 831 832 // release socket lock 833 remote_rwlock_wr_release( socket_lock_xp ); 834 835 // get pointers on relevant chdev 836 chdev_xp = chdev_dir.nic_tx[nic_channel]; 837 chdev_ptr = GET_PTR( chdev_xp ); 838 chdev_cxy = GET_CXY( chdev_xp ); 839 840 // get pointers on NIC_TX[channel] server thread 841 server_ptr = hal_remote_lpt( XPTR( chdev_cxy , &chdev_ptr->server )); 842 server_xp = XPTR( chdev_cxy , server_ptr ); 843 844 // unblocks the NIC_TX server thread 845 thread_unblock( server_xp , THREAD_BLOCKED_CLIENT ); 846 847 // client thread blocks itself and deschedules 848 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO ); 849 sched_yield( "blocked in nic_io" ); 850 851 // take the socket lock when unblocked 852 remote_rwlock_wr_acquire( socket_lock_xp ); 853 854 // unlink client thread from socket 855 hal_remote_s64( client_xp , XPTR_NULL ); 856 857 // release socket lock 858 remote_rwlock_wr_release( socket_lock_xp ); 859 860 // exit waiting loop and return 861 return length; 862 863 } // end SEND 864 865 //////////////////////////////////////////////////////// 866 else // RECV command 867 { 868 // build extended pointers on socket "rx_client" 869 xptr_t client_xp = XPTR( file_cxy , &socket_ptr->rx_client ); 870 871 // check no previous RECV command 872 xptr_t client = hal_remote_l64( client_xp ); 873 874 if( client != XPTR_NULL ) // release socket lock and return error 875 { 876 // release socket lock 877 remote_rwlock_wr_release( socket_lock_xp ); 878 879 // get previous thread cluster & local pointer 880 cxy_t prev_cxy = GET_CXY( client ); 881 thread_t * prev_ptr = GET_PTR( client ); 882 883 // get previous command type and trdid 884 uint32_t prev_cmd = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->nic_cmd.type )); 885 uint32_t prev_tid = hal_remote_l32( XPTR( prev_cxy , &prev_ptr->trdid )); 886 887 printk("\n[ERROR] in %s : previous command %s for thread %x / thread%x,%x]\n", 888 __FUNCTION__, socket_cmd_str(prev_cmd), prev_tid, process->pid, this->trdid ); 889 return -1; 890 } 891 892 // build extended pointer on "rx_buf" 893 xptr_t rx_buf_xp = XPTR( file_cxy , &socket_ptr->rx_buf ); 894 895 // get rx_buf status from socket 896 status = remote_buf_status( rx_buf_xp ); 897 898 if( status == 0 ) // rx_buf empty => blocks and deschedules 899 { 900 // release socket lock 901 remote_rwlock_wr_release( socket_lock_xp ); 902 903 // client thread blocks itself and deschedules 904 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_IO ); 905 sched_yield( "blocked in nic_io" ); 906 907 // take socket lock 908 remote_rwlock_wr_release( socket_lock_xp ); 909 } 910 911 // number of moved bytes cannot be larger than u_buf size 912 moved_bytes = ( length < status ) ? length : status; 913 914 // move data from kernel rx_buf to user u_buf 915 remote_buf_get_to_user( rx_buf_xp, 916 u_buf, 917 moved_bytes ); 918 919 // reset rx_buf for an UDP socket 920 if( socket_type == SOCK_DGRAM ) remote_buf_reset( rx_buf_xp ); 921 922 // unlink client thread from socket 923 hal_remote_s64( client_xp , XPTR_NULL ); 924 925 // release socket lock 926 remote_rwlock_wr_release( socket_lock_xp ); 927 928 // exit waiting loop and return 929 return moved_bytes; 930 931 } // end SEND 932 933 } // end dev_nic_register_cmd() 934 935 936 /////////////////////////////////// 937 int dev_nic_send( uint32_t fdid, 938 uint8_t * u_buf, 939 uint32_t length ) 940 { 941 #if DEBUG_DEV_NIC_TX 942 thread_t * this = CURRENT_THREAD; 943 process_t * process = this->process; 944 trdid_t trdid = this->trdid; 945 pid_t pid = process->pid; 946 uint32_t cycle = (uint32_t)hal_get_cycle(); 947 if (DEBUG_DEV_NIC_TX < cycle ) 948 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n", 949 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle ); 950 #endif 951 952 error_t error = dev_nic_register_cmd( true, // SEND 953 fdid, 954 u_buf, 955 length, 956 false, 0, 0 ); // no explicit remote socket 957 #if DEBUG_DEV_NIC_TX 958 cycle = (uint32_t)hal_get_cycle(); 959 if (DEBUG_DEV_NIC_TX < cycle ) 960 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n", 961 __FUNCTION__, pid, trdid, cycle ); 962 #endif 963 964 return error; 965 966 } // end dev_nic_send() 967 968 /////////////////////////////////// 969 int dev_nic_recv( uint32_t fdid, 970 uint8_t * u_buf, 971 uint32_t length ) 972 { 973 #if DEBUG_DEV_NIC_RX 974 thread_t * this = CURRENT_THREAD; 975 process_t * process = this->process; 976 trdid_t trdid = this->trdid; 977 pid_t pid = process->pid; 978 uint32_t cycle = (uint32_t)hal_get_cycle(); 979 if (DEBUG_DEV_NIC_RX < cycle ) 980 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n", 981 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle ); 982 #endif 983 984 error_t error = dev_nic_register_cmd( false, // RECV 985 fdid, 986 u_buf, 987 length, 988 false, 0, 0 ); // no explicit remote socket 989 #if DEBUG_DEV_NIC_RX 990 cycle = (uint32_t)hal_get_cycle(); 991 if (DEBUG_DEV_NIC_RX < cycle ) 992 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n", 993 __FUNCTION__, pid, trdid, cycle ); 994 #endif 995 996 return error; 997 998 } // end dev_nic_recv() 999 1000 ///////////////////////////////////// 1001 int dev_nic_sendto( uint32_t fdid, 1002 uint8_t * u_buf, 1003 uint32_t length, 1004 uint32_t remote_addr, 1005 uint32_t remote_port ) 1006 { 1007 #if DEBUG_DEV_NIC_TX 1008 thread_t * this = CURRENT_THREAD; 1009 process_t * process = this->process; 1010 trdid_t trdid = this->trdid; 1011 pid_t pid = process->pid; 1012 uint32_t cycle = (uint32_t)hal_get_cycle(); 1013 if (DEBUG_DEV_NIC_TX < cycle ) 1014 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n", 1015 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle ); 1016 #endif 1017 1018 error_t error = dev_nic_register_cmd( true, // SEND 1019 fdid, 1020 u_buf, 1021 length, 1022 true, // explicit remote socket 1023 remote_addr, 1024 remote_port ); 1025 #if DEBUG_DEV_NIC_TX 1026 cycle = (uint32_t)hal_get_cycle(); 1027 if (DEBUG_DEV_NIC_TX < cycle ) 1028 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n", 1029 __FUNCTION__, pid, trdid, cycle ); 1030 #endif 1031 1032 return error; 1033 1034 } // end dev_nic_sendto() 1035 1036 /////////////////////////////////////// 1037 int dev_nic_recvfrom( uint32_t fdid, 1038 uint8_t * u_buf, 1039 uint32_t length, 1040 uint32_t remote_addr, 1041 uint32_t remote_port ) 1042 { 1043 #if DEBUG_DEV_NIC_RX 1044 thread_t * this = CURRENT_THREAD; 1045 process_t * process = this->process; 1046 trdid_t trdid = this->trdid; 1047 pid_t pid = process->pid; 1048 uint32_t cycle = (uint32_t)hal_get_cycle(); 1049 if (DEBUG_DEV_NIC_RX < cycle ) 1050 printk("[%s] thread[%x,%x] enters : fdid %d / buf %x / length %d / cycle %d\n", 1051 __FUNCTION__, pid, trdid, fdid, u_buf, length, cycle ); 1052 #endif 1053 1054 error_t error = dev_nic_register_cmd( false, // RECV 1055 fdid, 1056 u_buf, 1057 length, 1058 true, // explicit remote socket 1059 remote_addr, 1060 remote_port ); 1061 #if DEBUG_DEV_NIC_RX 1062 cycle = (uint32_t)hal_get_cycle(); 1063 if (DEBUG_DEV_NIC_RX < cycle ) 1064 printk("[%s] thread[%x,%x] exit : fdid %d / cycle %d\n", 1065 __FUNCTION__, pid, trdid, cycle ); 1066 #endif 1067 1068 return error; 1069 1070 } // end dev_nic_recvfrom() 1071 1072 1073 1074 1075 432 // set rx_sts field in socket descriptor 433 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_sts ) , status ); 434 435 // get extended point on RX client thread 436 xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->rx_client )); 437 438 // unblock the client thread 439 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 440 441 } // end dev_nic_unblock_rx_client() 1076 442 1077 443 … … 1080 446 // Functions called by the NIC_RX server thread 1081 447 /////////////////////////////////////////////////////////////////////////////////////////// 1082 1083 /////////////////////////////////////////////////////////////////////////////////////////1084 // This static function is called by the NIC_RX[channel] server thread to register1085 // a send request defined by the <flags> argument in the R2T queue specified by1086 // the <queue_xp> argument.1087 /////////////////////////////////////////////////////////////////////////////////////////1088 // @ queue_xp : [in] extended pointer on the R2T qeue descriptor.1089 // @ flags : [in] flags to be set in the TCP segment.1090 /////////////////////////////////////////////////////////////////////////////////////////1091 static void dev_nic_rx_put_r2t_request( xptr_t queue_xp,1092 uint32_t flags )1093 {1094 while( 1 )1095 {1096 error_t error = remote_buf_put_from_kernel( queue_xp,1097 (uint8_t *)(&flags),1098 1 );1099 1100 if( error ) sched_yield( "waiting R2T queue" );1101 else break;1102 }1103 1104 } // end dev_nic_rx_put_r2t_request()1105 1106 ///////////////////////////////////////////////////////////////////////////////////////////1107 // This static function is called by the dev_nic_rx_server() function.1108 // It calls directly the NIC driver (with the READABLE command) and returns the status1109 // of the NIC_RX queue identified by the <chdev> argument.1110 // in the <readable> buffer.1111 ///////////////////////////////////////////////////////////////////////////////////////////1112 // @ chdev : [in] local pointer on NIC_TX chdev.1113 // @ readable : [out] zero if queue empty.1114 // @ returns 0 if success / returns -1 if failure in accessing NIC device.1115 ///////////////////////////////////////////////////////////////////////////////////////////1116 error_t dev_nic_rx_queue_readable( chdev_t * chdev,1117 uint32_t * readable )1118 {1119 thread_t * this = CURRENT_THREAD;1120 1121 // initialize NIC_READABLE command in thread descriptor1122 this->nic_cmd.dev_xp = XPTR( local_cxy , chdev );1123 this->nic_cmd.type = NIC_CMD_READABLE;1124 1125 // call driver to test readable1126 chdev->cmd( XPTR( local_cxy , this ) );1127 1128 // return status1129 *readable = this->nic_cmd.status;1130 1131 // return error1132 return this->nic_cmd.error;1133 }1134 1135 ///////////////////////////////////////////////////////////////////////////////////////////1136 // This static function is called by the dev_nic_rx_server() function.1137 // It moves one Ethernet packet from the NIC_RX_QUEUE identified the <chdev> argument,1138 // to the 2K bytes kernel buffer identified by the <buffer> argument. The actual1139 // Ethernet packet length is returned in the <length> argument.1140 // It calls directly the NIC driver with the READ command, without registering in the1141 // waiting queue, because only the NIC_RX server thread can access this NIC_RX_QUEUE.1142 ///////////////////////////////////////////////////////////////////////////////////////////1143 // @ chdev : [in] local pointer on NIC_TX chdev.1144 // @ buffer : [in] local pointer on destination kernel buffer.1145 // @ length : [out] Ethernet packet size in bytes.1146 // @ returns 0 if success / returns -1 if failure in accessing NIC device.1147 ///////////////////////////////////////////////////////////////////////////////////////////1148 error_t dev_nic_rx_move_packet( chdev_t * chdev,1149 uint8_t * k_buf,1150 uint32_t * length )1151 {1152 thread_t * this = CURRENT_THREAD;1153 1154 #if DEBUG_DEV_NIC_RX1155 uint32_t cycle = (uint32_t)hal_get_cycles();1156 if( DEBUG_DEV_NIC_RX < cycle )1157 printk("\n[%s] thread[%x,%x] enters / cycle %d\n",1158 __FUNCTION__, this->process->pid, this->trdid, cycle );1159 #endif1160 1161 // initialize NIC_READ command in thread descriptor1162 this->nic_cmd.type = NIC_CMD_READ;1163 this->nic_cmd.buffer = k_buf;1164 1165 // call NIC driver1166 chdev->cmd( XPTR( local_cxy , this ) );1167 1168 // returns packet length1169 *length = this->nic_cmd.length;1170 1171 // check error1172 if( this->nic_cmd.error )1173 {1174 1175 #if DEBUG_DEV_NIC_RX1176 cycle = (uint32_t)hal_get_cycles();1177 if( DEBUG_DEV_NIC_RX < cycle )1178 printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n",1179 __FUNCTION__, this->process->pid, this->trdid, cycle );1180 #endif1181 1182 return -1;1183 }1184 else1185 {1186 1187 #if DEBUG_DEV_NIC_RX1188 cycle = (uint32_t)hal_get_cycles();1189 if( DEBUG_DEV_NIC_RX < cycle )1190 printk("\n[%s] thread[%x,%x] exit / SUCCESS / cycle %d\n",1191 __FUNCTION__, this->process->pid, this->trdid, cycle );1192 #endif1193 1194 return 0;1195 }1196 1197 } // end dev_nic_rx_move_packet()1198 448 1199 449 /////////////////////////////////////////////////////////////////////////////////////////// … … 1237 487 uint32_t * trsp_protocol ) 1238 488 { 489 490 #if DEBUG_DEV_NIC_RX 491 thread_t * this = CURRENT_THREAD; 492 uint32_t cycle = (uint32_t)hal_get_cycles(); 493 #endif 494 495 // get packet length 1239 496 uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3]; 1240 497 1241 // discard packet if eth_ length != ip_length498 // discard packet if eth_payload_length != ip_length 1242 499 if( length != expected_length ) 1243 500 { 1244 501 1245 #if DEBUG_ NIC_DEV1246 thread_t * this = CURRENT_THREAD; 1247 printk("\n[%s] thread[%x,%x] enters: length (%d) != expected_length (%d)\n",502 #if DEBUG_DEV_NIC_RX 503 if( DEBUG_DEV_NIC_RX < cycle ) 504 printk("\n[%s] thread[%x,%x] failure : length (%d) != expected_length (%d)\n", 1248 505 __FUNCTION__, this->process->pid, this->trdid, length, expected_length ); 1249 506 #endif 1250 1251 507 return -1; 1252 508 } 1253 509 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 518 if( DEBUG_DEV_NIC_RX < cycle ) 519 printk("\n[%s] thread[%x,%x] failure : unsupported transport protocol (%d)\n", 520 __FUNCTION__, this->process->pid, this->trdid, protocol ); 521 #endif 522 return -1; 523 524 } 1254 525 // compute IP header checksum 1255 uint32_t received_cs = (uint32_t)dev_nic_ip_checksum( buffer );526 uint32_t computed_cs = (uint32_t)dev_nic_ip_checksum( buffer ); 1256 527 1257 528 // extract IP header checksum 1258 uint32_t computed_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]);529 uint32_t received_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]); 1259 530 1260 531 // discard packet if bad checksum … … 1262 533 { 1263 534 1264 #if DEBUG_ NIC_DEV1265 thread_t * this = CURRENT_THREAD; 1266 printk("\n[%s] thread[%x,%x] computed checksum (%d) != received checksum (%d)\n",535 #if DEBUG_DEV_NIC_RX 536 if( DEBUG_DEV_NIC_RX < cycle ) 537 printk("\n[%s] thread[%x,%x] failure : computed checksum (%d) != received checksum (%d)\n", 1267 538 __FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs ); 1268 539 #endif 1269 1270 540 return -1; 1271 541 } … … 1282 552 ((uint32_t)buffer[19] ) ; 1283 553 1284 *trsp_protocol = (uint32_t)buffer[9];554 *trsp_protocol = protocol; 1285 555 1286 556 return 0; … … 1354 624 if( xlist_is_empty( root_xp ) ) return; 1355 625 1356 // take the tock protecting the sockets list626 // take the lock protecting the sockets list 1357 627 remote_busylock_acquire( lock_xp ); 1358 628 … … 1387 657 (remote_port == pkt_src_port); 1388 658 1389 if (socket_state == UDP_STATE_ CONNECT) match_socket = local_match && remote_match;1390 else 659 if (socket_state == UDP_STATE_ESTAB ) match_socket = local_match && remote_match; 660 else match_socket = local_match; 1391 661 1392 662 // exit loop when socket found … … 1406 676 1407 677 // take the lock protecting the socket 1408 remote_ rwlock_wr_acquire( socket_lock_xp );678 remote_queuelock_acquire( socket_lock_xp ); 1409 679 1410 680 // get status & space from rx_buf … … 1425 695 k_buf + UDP_HEAD_LEN, 1426 696 moved_bytes ); 1427 1428 // unblock client thread if registered 697 // unblock client thread 1429 698 if( client_xp != XPTR_NULL ) 1430 699 { … … 1433 702 1434 703 // release the lock protecting the socket 1435 remote_ rwlock_wr_release( socket_lock_xp );704 remote_queuelock_release( socket_lock_xp ); 1436 705 1437 706 } // end dev_nic_rx_handle_udp_packet() … … 1440 709 // This static function is called by the dev_nic_rx_server() function to handle one RX 1441 710 // TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments. 1442 // It the received segment doesn't match an existing local socket, or is corrupted, 1443 // this faulty segment is discarded. 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. 1444 717 /////////////////////////////////////////////////////////////////////////////////////////// 1445 718 // Implementation note: 1446 // 1) It checks the TCP checksum, and discard the corrupted segment. 1447 // 2) It scans the list of sockets attached to the RX chdev, to find the socket 1448 // matching the TCP segment header, and discards the segment if no socket found. 1449 // 3) When a socket has been found, it takes the lock protecting the socket state, 1450 // because the socket is accessed by both the NIC_TX and NIC_RX server threads. 1451 // 4) Depending on the socket state, it handle the received segment, including the 1452 // SYN, FIN, ACK and RST flags. It updates the socket state when required, moves 1453 // data to the rx_buf when possible, and registers requests to the TX server 1454 // thread in the R2T queue attached to the socket, to insert control flags in the 1455 // TX stream, as required. 1456 // 5) Finally, it releases the lock protecting the socke and returns. 1457 /////////////////////////////////////////////////////////////////////////////////////////// 1458 // @ chdev : [in] local pointer on local NIC_RX chdev descriptor. 1459 // @ k_buf : [in] pointer on the TCP packet in local kernel buffer. 1460 // @ k_length : [in] number of bytes in buffer (including TCP header). 1461 // @ seg_src_addr : [in] source IP address (from IP packet header). 1462 // @ seg_dst_addr : [in] destination IP address (from IP packet header). 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. 735 /////////////////////////////////////////////////////////////////////////////////////////// 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). 1463 741 /////////////////////////////////////////////////////////////////////////////////////////// 1464 742 static void dev_nic_rx_handle_tcp_segment( chdev_t * chdev, 1465 743 uint8_t * k_buf, 1466 744 uint32_t k_length, 1467 uint32_t seg_ src_addr,1468 uint32_t seg_ dst_addr )745 uint32_t seg_remote_addr, 746 uint32_t seg_local_addr ) 1469 747 { 1470 xptr_t root_xp; // extended pointer on attached sockets list root 1471 xptr_t lock_xp; // extended pointer on chdev lock 1472 xptr_t iter_xp; // iterator for these queues 1473 bool_t match_socket; // true if socket found 1474 xptr_t socket_xp; // extended pointer on matching socket descriptor 1475 cxy_t socket_cxy; 1476 socket_t * socket_ptr; 1477 uint32_t local_addr; // local IP address from socket 1478 uint32_t local_port; // local port from socket 1479 uint32_t remote_addr; // remote IP address from socket 1480 uint32_t remote_port; // remote port from socket 1481 uint32_t socket_state; // socket state 1482 uint32_t socket_type; // socket type 1483 uint32_t socket_tx_nxt; // next byte to send in TX stream 1484 uint32_t socket_tx_una; // first unacknowledged byte in TX stream 1485 uint32_t socket_rx_nxt; // next expected byte in RX stream 1486 uint32_t socket_rx_wnd; // current window value in RX stream 1487 xptr_t socket_lock_xp; // extended pointer on lock protecting socket state 1488 xptr_t socket_rx_buf_xp; // extended pointer on socket rx_buf 1489 xptr_t socket_r2tq_xp; // extended pointer on socket r2t queue 1490 xptr_t socket_client_xp; // extended pointer on socket rx_client thread 1491 uint16_t checksum; // computed TCP segment chechsum 1492 1493 // build extended pointer on xlist of all sockets attached to NIC_RX chdev 1494 root_xp = XPTR( local_cxy , &chdev->wait_root ); 1495 lock_xp = XPTR( local_cxy , &chdev->wait_lock ); 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; 1496 778 1497 779 // get relevant infos from TCP segment header 1498 uint32_t seg_ src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1];1499 uint32_t seg_ dst_port= ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3];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]; 1500 782 1501 783 uint32_t seg_seq_num = ((uint32_t)k_buf[4] << 24) | … … 1509 791 ((uint32_t)k_buf[11] ); 1510 792 1511 uint8_t seg_hlen = k_buf[12] >>2; // TCP header length in bytes793 uint8_t seg_hlen = k_buf[12] << 2; // TCP header length in bytes 1512 794 1513 795 uint8_t seg_flags = k_buf[13]; … … 1522 804 uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17]; 1523 805 1524 uint32_t seg_payload = k_length - seg_hlen; // number of bytes in payload 1525 1526 // 1. compute TCP checksum 806 uint32_t seg_data_len = k_length - seg_hlen; // number of bytes in payload 807 808 #if DEBUG_DEV_NIC_RX 809 thread_t * this = CURRENT_THREAD; 810 uint32_t cycle; 811 uint32_t fdid; 812 pid_t pid; 813 #endif 814 815 #if DEBUG_DEV_NIC_RX 816 cycle = (uint32_t)hal_get_cycles(); 817 if( cycle > DEBUG_DEV_NIC_RX ) 818 printk("\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; 1527 825 checksum = dev_nic_tcp_checksum( k_buf, 1528 826 k_length, 1529 seg_ src_addr,1530 seg_ dst_addr );827 seg_remote_addr, 828 seg_local_addr ); 1531 829 1532 830 // discard segment if corrupted 1533 if( seg_checksum != checksum ) return; 831 if( seg_checksum != checksum ) 832 { 833 834 #if DEBUG_DEV_NIC_RX 835 if( cycle > DEBUG_DEV_NIC_RX ) 836 printk("\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 } 1534 841 1535 match_socket = false; 1536 1537 // take the lock protecting the list of sockets 842 // scan list of attached sockets to find a matching TCP socket 843 attached_match = false; 844 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 1538 850 remote_busylock_acquire( lock_xp ); 1539 851 1540 // 2. scan list of sockets to find a matching socket1541 852 XLIST_FOREACH( root_xp , iter_xp ) 1542 853 { … … 1554 865 1555 866 // get relevant socket infos for matching 1556 local_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr ));1557 remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr ));1558 local_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port ));1559 remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port ));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 )); 1560 871 1561 // compute matching condition 1562 // (in LISTEN state, remote_port and remote_addr can be unspecified) 1563 if( socket_state == TCP_STATE_LISTEN ) 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 ) 1564 880 { 1565 match_socket = (local_addr == seg_dst_addr) && 1566 (local_port == seg_dst_port) ; 881 882 #if DEBUG_DEV_NIC_RX 883 fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) ); 884 pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) ); 885 if( cycle > DEBUG_DEV_NIC_RX ) 886 printk("\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; 1567 890 } 1568 else 891 892 } // end loop on attached sockets 893 894 // release the lock protecting the list of attached sockets 895 remote_busylock_release( lock_xp ); 896 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 ); 909 910 // take the lock protecting the matching socket 911 remote_queuelock_acquire( socket_lock_xp ); 912 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 )); 919 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 )); 925 926 // handle the received segment, depending on the matching socket state 927 switch( socket_state ) 1569 928 { 1570 match_socket = (local_addr == seg_dst_addr) && 1571 (local_port == seg_dst_port) && 1572 (remote_addr == seg_src_addr) && 1573 (remote_port == seg_src_port) ; 1574 } 1575 1576 // exit loop if matching 1577 if( match_socket ) break; 1578 1579 } // end loop on sockets 1580 1581 // release the lock protecting the list of sockets 1582 remote_busylock_release( lock_xp ); 1583 1584 // discard segment if no matching socket found 1585 if( match_socket == false ) return; 1586 1587 // From here the actions depend on both the socket state, 1588 // and the received segment flags 1589 // - update socket state, 1590 // - move data to rx_buf, 1591 // - make a R2T request when required 1592 1593 // build extended pointers on various socket fields 1594 socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock ); 1595 socket_rx_buf_xp = XPTR( socket_cxy , &socket_ptr->rx_buf ); 1596 socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq ); 1597 socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client ); 1598 1599 // 3. take the lock protecting the matching socket 1600 remote_rwlock_wr_acquire( socket_lock_xp ); 1601 1602 // get relevant socket infos from socket descriptor 1603 socket_state = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->state )); 1604 socket_rx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt )); 1605 socket_rx_wnd = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd )); 1606 socket_tx_una = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una )); 1607 socket_tx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt )); 1608 1609 switch( socket_state ) 1610 { 1611 ////////////////////// 1612 case TCP_STATE_LISTEN: 1613 { 1614 // [1] discard segment if RST flag 1615 if( seg_rst_set ) return; 1616 1617 // [2] send a RST & discard segment if ACK flag 1618 if( seg_ack_set ) 929 //////////////////////// 930 case TCP_STATE_SYN_SENT: // TCP client waiting for SYN-ACK in connect handshake 1619 931 { 1620 // set socket.tx_nxt to seg_ack_num 1621 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1622 seg_ack_num ); 1623 1624 // make RST request to R2T queue 1625 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1626 TCP_FLAG_RST ); 1627 // discard segment 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 { 937 938 #if DEBUG_DEV_NIC_RX 939 printk("\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, 941 socket_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 } 953 } 954 955 // [2] check RST flag // receive RST => report error 956 if( seg_rst_set ) 957 { 958 959 #if DEBUG_DEV_NIC_RX 960 printk("\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 ); 966 967 // signal error to local TX client thread 968 dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST ); 969 1628 970 break; 1629 971 } 1630 972 1631 // [3] handle SYN flag 1632 if( seg_syn_set ) 1633 { 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 980 printk("\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 992 // update socket.state 993 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_ESTAB ); 994 995 // make an ACK request to R2T queue 996 socket_put_r2t_request( socket_r2tq_xp, 997 TCP_FLAG_ACK, 998 chdev->channel ); 999 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 1007 printk("\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 1634 1016 // set socket.rx_nxt to seg_seq_num + 1 1635 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1636 seg_seq_num + 1 ); 1637 1638 // set socket.tx_nxt to ISS 1639 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1640 TCP_ISS ); 1641 1642 // set socket.rx_irs to seg_seq_num 1643 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ), 1644 seg_seq_num + 1 ); 1645 1646 // make SYN.ACK request to R2T queue 1647 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1648 TCP_FLAG_SYN | TCP_FLAG_ACK ); 1649 1650 // set socket.tx_nxt to ISS + 1 1651 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1652 TCP_ISS + 1 ); 1653 1654 // set socket.tx_una to ISS 1655 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1656 TCP_ISS ); 1657 1658 // update socket.state 1659 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1660 TCP_STATE_SYN_RCVD ); 1661 1662 // update socket.remote_addr 1663 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_addr ), 1664 seg_src_addr ); 1665 1666 // update socket.remote_port 1667 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_port ), 1668 seg_src_port ); 1669 } 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 } 1670 1024 break; 1671 1025 } 1672 1026 //////////////////////// 1673 case TCP_STATE_SYN_ SENT:1027 case TCP_STATE_SYN_RCVD: // TCP server waiting last ACK in connect handshake 1674 1028 { 1675 // [1] check ACK flag 1676 if( seg_ack_set ) 1677 { 1678 if( seg_ack_num != TCP_ISS + 1 ) // ACK not acceptable 1679 { 1680 // discard segment if RST 1681 if( seg_rst_set ) break; 1682 1683 // set socket.tx_nxt to seg_ack_num 1684 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1685 seg_ack_num ); 1686 1687 // make an RST request to R2T queue 1688 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1689 TCP_FLAG_RST ); 1690 // discard segment 1691 break; 1692 } 1693 } 1694 1695 // [2] check RST flag 1029 // [1] check sequence number 1030 if( seg_seq_num != socket_rx_nxt ) // unexpected SEQ_NUM => discard 1031 { 1032 1033 #if DEBUG_DEV_NIC_RX 1034 printk("\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, 1036 socket_state_str(socket_state), socket_rx_nxt, seg_seq_num ); 1037 #endif 1038 // discard segment without reporting 1039 break; 1040 } 1041 1042 // [2] handle RST flag // received RST => report error 1696 1043 if( seg_rst_set ) 1697 1044 { 1698 // TODO signal "error: connection reset" to user 1045 1046 #if DEBUG_DEV_NIC_RX 1047 printk("\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 ); 1052 1053 // report error to local TX client thread 1054 dev_nic_unblock_tx_client( socket_xp , CMD_STS_RST ); 1055 1056 break; 1057 } 1058 1059 // [3] handle security & precedence TODO ... someday 1060 1061 // [4] handle SYN flag 1062 if( seg_syn_set ) // received SYN => discard 1063 { 1064 1065 #if DEBUG_DEV_NIC_RX 1066 printk("\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 } 1072 1073 // [5] handle ACK flag 1074 if( seg_ack_set == false ) // missing ACK => discard 1075 { 1076 1077 #if DEBUG_DEV_NIC_RX 1078 printk("\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 { 1086 1087 #if DEBUG_DEV_NIC_RX 1088 printk("\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, 1090 socket_state_str(socket_state), TCP_ISS_SERVER + 1, seg_ack_num ); 1091 #endif 1092 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 ); 1097 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 { 1103 1104 #if DEBUG_DEV_NIC_RX 1105 printk("\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 ); 1699 1110 1700 1111 // update socket.state 1701 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1702 TCP_STATE_BOUND ); 1703 1704 // discard segment 1705 break; 1706 } 1707 1708 // [3] handle SYN flag when (no ACK or acceptable ACK, and no RST) 1709 if( seg_syn_set ) 1710 { 1711 // TODO Ne faut-il pas tester seg_seq_num ? 1712 1713 if( seg_ack_set ) // received both SYN and ACK 1714 { 1715 // set socket.rx_nxt to seg_seq_num + 1 1716 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1717 seg_seq_num + 1 ); 1718 1719 // set socket.tx_una to seg_ack_num 1720 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1721 seg_ack_num ); 1722 1723 // set socket.rx_irs to seg_seq_num 1724 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ), 1725 seg_seq_num ); 1726 1727 // update socket.state 1728 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1729 TCP_STATE_ESTAB ); 1730 1731 // make an ACK request to R2T queue 1732 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1733 TCP_FLAG_ACK ); 1734 } 1735 else // received SYN without ACK 1736 { 1737 // update socket.state 1738 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1739 TCP_STATE_SYN_RCVD ); 1740 1741 // set socket.tx_nxt to ISS 1742 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1743 TCP_ISS ); 1744 1745 // make a SYN.ACK request to R2T queue 1746 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1747 TCP_FLAG_SYN | TCP_FLAG_ACK ); 1748 } 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 ); 1749 1117 } 1750 1118 break; 1751 1119 } 1752 //////////////////////// 1753 case TCP_STATE_SYN_RCVD: 1120 ///////////////////// 1754 1121 case TCP_STATE_ESTAB: 1755 1122 case TCP_STATE_FIN_WAIT1: … … 1760 1127 case TCP_STATE_TIME_WAIT: 1761 1128 { 1762 // [1] check sequence number 1763 1764 // compute min & max acceptable sequence numbers 1765 uint32_t seq_min = socket_rx_nxt; 1766 uint32_t seq_max = socket_rx_nxt + socket_rx_wnd - 1; 1767 1768 // compute sequence number for last byte in segment 1769 uint32_t seg_seq_last = seg_seq_num + seg_payload - 1; 1770 1771 if( (seg_seq_num != socket_rx_nxt) || // out_of_order 1772 (is_in_window( seg_seq_last, 1773 seq_min, 1774 seq_max ) == false) ) // out_of_window 1775 { 1129 // [1] check sequence number : out_of_order segments not accepted 1130 if( seg_seq_num != socket_rx_nxt ) 1131 { 1132 1133 #if DEBUG_DEV_NIC_RX 1134 printk("\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, 1136 socket_state_str(socket_state), seg_seq_num, socket_rx_nxt ); 1137 #endif 1776 1138 // discard segment 1777 return;1139 break; 1778 1140 } 1779 1141 1780 // [2] handle RST flag 1781 1782 if( seg_rst_set ) 1783 { 1784 if( socket_state == TCP_STATE_SYN_RCVD ) 1785 { 1786 // TODO unblock all clients threads with "reset" responses 1787 } 1788 else if( (socket_state == TCP_STATE_ESTAB ) || 1789 (socket_state == TCP_STATE_FIN_WAIT1 ) || 1790 (socket_state == TCP_STATE_FIN_WAIT2 ) || 1791 (socket_state == TCP_STATE_CLOSE_WAIT) ) 1792 { 1793 // TODO all pending send & received commands 1794 // must receive "reset" responses 1795 1796 // TODO destroy the socket 1797 } 1798 else // all other states 1799 { 1800 1801 1802 } 1803 1804 // [3] handle security & precedence TODO ... someday 1805 1806 // [4] handle SYN flag 1807 1808 if( seg_syn_set ) // received SYN 1809 { 1810 // TODO signal error to user 1811 1812 // make an RST request to R2T queue 1813 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1814 TCP_FLAG_RST ); 1815 // update socket state 1816 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1817 TCP_STATE_BOUND ); 1818 } 1819 1820 // [5] handle ACK flag 1821 1822 if( seg_ack_set == false ) 1823 { 1824 // discard segment when ACK not set 1825 break; 1826 } 1827 else if( socket_state == TCP_STATE_SYN_RCVD ) 1828 { 1829 if( is_in_window( seg_ack_num , socket_tx_una , socket_tx_nxt ) ) 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; 1150 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 ) 1830 1155 { 1831 // update socket.state to ESTAB 1832 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1833 TCP_STATE_ESTAB ); 1834 } 1835 else // unacceptable ACK 1836 { 1837 // set socket.tx_nxt to seg_ack_num 1838 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1839 seg_ack_num ); 1840 1841 // make an RST request to R2T queue 1842 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1843 TCP_FLAG_RST ); 1844 } 1845 } 1846 else if( (socket_state == TCP_STATE_ESTAB) || 1847 (socket_state == TCP_STATE_FIN_WAIT1) || 1848 (socket_state == TCP_STATE_FIN_WAIT1) || 1849 (socket_state == TCP_STATE_CLOSE_WAIT) || 1850 (socket_state == TCP_STATE_CLOSING) ) 1851 { 1852 if( is_in_window( seg_ack_num + 1 , socket_tx_una , socket_tx_nxt ) ) 1853 { 1854 // update socket.tx_una 1855 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1856 seg_ack_num ); 1857 1858 // update socket.tx_wnd 1859 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_wnd ), 1860 seg_window ); 1861 } 1862 else // unacceptable ACK 1863 { 1156 1157 #if DEBUG_DEV_NIC_RX 1158 printk("\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, 1160 socket_state_str(socket_state), seg_seq_last, seq_min, seq_max ); 1161 #endif 1864 1162 // discard segment 1865 1163 break; 1866 1164 } 1867 1868 // specific for FIN_WAIT1 1869 if( socket_state == TCP_STATE_FIN_WAIT1 ) 1165 } 1166 1167 // [2] handle RST flag 1168 if( seg_rst_set ) 1169 { 1170 1171 #if DEBUG_DEV_NIC_RX 1172 printk("\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) ) 1870 1179 { 1871 if( seg_fin_set ) 1872 { 1873 // update socket.state 1874 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1875 TCP_STATE_FIN_WAIT2 ); 1876 } 1180 // TODO all pending send & received commands 1181 // must receive "reset" responses 1182 1183 // TODO destroy the socket 1877 1184 } 1878 1879 // specific for CLOSING 1880 if( socket_state == TCP_STATE_CLOSING ) 1185 else // states CLOSING / LAST_ACK / TIME_WAIT 1881 1186 { 1882 if( seg_ack_set ) 1883 { 1884 // update socket.state 1885 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1886 TCP_STATE_TIME_WAIT ); 1887 } 1888 else 1889 { 1890 // discard segment 1891 break; 1892 } 1187 // TODO 1893 1188 } 1894 } 1895 else if( socket_state == TCP_STATE_LAST_ACK ) 1896 { 1897 if( seg_ack_set ) 1189 break; 1190 } 1191 1192 // [3] handle security & precedence TODO ... someday 1193 1194 // [4] check SYN flag 1195 if( seg_syn_set ) // received SYN => ERROR 1196 { 1197 1198 #if DEBUG_DEV_NIC_RX 1199 printk("\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 1202 // TODO signal error to user 1203 1204 // make an RST request to R2T queue 1205 socket_put_r2t_request( socket_r2tq_xp, 1206 TCP_FLAG_RST, 1207 chdev->channel ); 1208 1209 // update socket state 1210 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->state), TCP_STATE_BOUND ); 1211 1212 break; 1213 } 1214 1215 // [5] check ACK 1216 if( seg_ack_set == false ) // missing ACK 1217 { 1218 1219 #if DEBUG_DEV_NIC_RX 1220 printk("\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 1224 break; 1225 } 1226 else if( is_in_window( seg_ack_num, 1227 socket_tx_una, 1228 socket_tx_nxt ) == false ) // unacceptable ACK 1229 { 1230 1231 #if DEBUG_DEV_NIC_RX 1232 printk("\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), 1234 seg_ack_num, socket_tx_una, socket_tx_nxt ); 1235 #endif 1236 // discard segment 1237 break; 1238 } 1239 else // acceptable ack 1240 { 1241 // update socket.tx_una 1242 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_una), seg_ack_num ); 1243 1244 // update socket.tx_wnd 1245 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_wnd), seg_window ); 1246 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) ) 1898 1251 { 1899 // update socket.state 1900 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1901 TCP_STATE_TIME_WAIT ); 1252 // signal success to TX client thread 1253 dev_nic_unblock_tx_client( socket_xp , CMD_STS_SUCCESS ); 1902 1254 } 1255 } 1903 1256 1904 } 1905 1906 // [6] handle URG flag TODO ... someday 1907 1908 // [7] Move DATA to rx_buf and unblock client thread 1909 1910 if( seg_payload ) 1257 // [7] handle URG flag TODO ... someday 1258 1259 // [8] Move DATA to rx_buf / ACK request to R2T queue / unblock rx_client 1260 if( seg_data_len ) 1911 1261 { 1912 1262 if( (socket_state == TCP_STATE_ESTAB) || … … 1920 1270 uint32_t space = NIC_RX_BUF_SIZE - status; 1921 1271 1922 // compute number of bytes to move : min (space , seg_ payload)1923 uint32_t nbytes = ( space < seg_ payload ) ? space : seg_payload;1272 // compute number of bytes to move : min (space , seg_data_len) 1273 uint32_t nbytes = ( space < seg_data_len ) ? space : seg_data_len; 1924 1274 1925 1275 // move payload from k_buf to rx_buf … … 1927 1277 k_buf + seg_hlen, 1928 1278 nbytes ); 1279 #if DEBUG_DEV_NIC_RX 1280 printk("\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, 1282 socket_state_str(socket_state), nbytes ); 1283 #endif 1929 1284 // update socket.rx_nxt 1930 1285 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), … … 1933 1288 // update socket.rx_wnd 1934 1289 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ), 1935 socket_rx_wnd - nbytes ); 1936 1937 // make an ACK request to R2T queue 1938 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1939 TCP_FLAG_ACK ); 1940 1941 // get extended pointer on rx_client thread 1942 xptr_t client_xp = hal_remote_l64( socket_client_xp ); 1943 1944 // unblock client thread 1945 if( client_xp != XPTR_NULL ) 1290 socket_rx_wnd - nbytes ); 1291 1292 // make an ACK request to R2T queue 1293 socket_put_r2t_request( socket_r2tq_xp, 1294 TCP_FLAG_ACK, 1295 chdev->channel ); 1296 1297 // check pending RX_RECV command 1298 if( (socket_rx_valid == true) && 1299 (socket_rx_cmd == CMD_RX_RECV) ) 1946 1300 { 1947 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 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 1307 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : unblock waiting RX client thread\n", 1308 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1309 socket_state_str(socket_state) ); 1310 #endif 1948 1311 } 1949 1312 } 1950 1313 } 1951 1314 1952 // [8] handle FIN flag 1953 1954 if( seg_fin_set ) 1955 { 1956 if( (socket_state == TCP_STATE_UNBOUND) || 1957 (socket_state == TCP_STATE_BOUND) || 1958 (socket_state == TCP_STATE_LISTEN) || 1959 (socket_state == TCP_STATE_SYN_SENT) ) 1315 // [9] handle FIN flag 1316 if( socket_state == TCP_STATE_ESTAB ) 1317 { 1318 if( seg_fin_set ) // received ACK & FIN 1960 1319 { 1961 // discard segment 1962 break; 1963 } 1964 else // all other states 1965 { 1966 // TODO signal "connection closing" 1967 1968 // make an ACK request to R2T queue 1969 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1970 TCP_FLAG_ACK ); 1971 1972 // increment socket.rx_nxt 1320 1321 #if DEBUG_DEV_NIC_RX 1322 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSE_WAIT\n", 1323 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1324 socket_state_str(socket_state) ); 1325 #endif 1326 // update socket.rx_nxt when FIN received 1973 1327 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1974 1328 socket_rx_nxt + 1 ); 1975 1329 1976 if( (socket_state == TCP_STATE_SYN_RCVD) || 1977 (socket_state == TCP_STATE_ESTAB) ) 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) ) 1978 1342 { 1979 // update socket.state 1980 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1981 TCP_STATE_TIME_WAIT ); 1982 } 1983 else if( socket_state == TCP_STATE_FIN_WAIT1 ) 1984 { 1985 if( seg_ack_set ) 1986 { 1987 // TODO start "time-wait" timer / turn off others timers 1988 1989 // update socket.state 1990 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1991 TCP_STATE_TIME_WAIT ); 1992 } 1993 else 1994 { 1995 // update socket.state 1996 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1997 TCP_STATE_CLOSING ); 1998 } 1999 } 2000 else if( socket_state == TCP_STATE_FIN_WAIT2 ) 2001 { 2002 // TODO start "time-wait" timer / turn off other timers 2003 2004 // update socket.state 2005 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2006 TCP_STATE_TIME_WAIT ); 2007 } 2008 else if( socket_state == TCP_STATE_TIME_WAIT ) 2009 { 2010 // TODO restart "time_wait" timer 2011 } 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 1349 printk("\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, 1351 socket_state_str(socket_state) ); 1352 #endif 1353 } 2012 1354 } 2013 } // end if FIN 2014 } // end case sockets synchronized 1355 } 1356 else if( socket_state == TCP_STATE_FIN_WAIT1 ) 1357 { 1358 if( seg_fin_set ) // received ACK & FIN 1359 { 1360 1361 #if DEBUG_DEV_NIC_RX 1362 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : FIN-ACK => goes CLOSING\n", 1363 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1364 socket_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 1374 // make an ACK request to R2T queue 1375 socket_put_r2t_request( socket_r2tq_xp, 1376 TCP_FLAG_ACK, 1377 chdev->channel ); 1378 } 1379 else // received ACK only 1380 { 1381 1382 #if DEBUG_DEV_NIC_RX 1383 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s : only ACK => goes FIN_WAIT2\n", 1384 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 1385 socket_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 1398 printk("\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, 1400 socket_state_str(socket_state) ); 1401 #endif 1402 // update socket.rx_nxt when FIN received 1403 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1404 socket_rx_nxt + 1 ); 1405 1406 // update socket.state 1407 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1408 TCP_STATE_CLOSED ); // TODO change to TIME_WAIT 1409 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 ); 1417 1418 // TODO start the MSL timer / turn off others timers 1419 1420 } 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 2015 1456 } // end switch socket state 2016 1457 2017 // release the lock protecting socket 2018 remote_rwlock_wr_acquire( socket_lock_xp ); 2019 2020 } // end socket found 1458 // release the lock protecting socket state 1459 remote_queuelock_release( socket_lock_xp ); 1460 1461 return; 1462 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 1493 assert( (socket_type == SOCK_STREAM ) , "illegal socket type" ); 1494 assert( (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 1509 fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid ) ); 1510 pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid ) ); 1511 if( cycle > DEBUG_DEV_NIC_RX ) 1512 printk("\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 1536 if( cycle > DEBUG_DEV_NIC_RX ) 1537 printk("\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 1548 if( cycle > DEBUG_DEV_NIC_RX ) 1549 printk("\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 1572 if( cycle > DEBUG_DEV_NIC_RX ) 1573 printk("\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 1585 if( cycle > DEBUG_DEV_NIC_RX ) 1586 printk("\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 1600 if( cycle > DEBUG_DEV_NIC_RX ) 1601 printk("\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 1615 if( cycle > DEBUG_DEV_NIC_RX ) 1616 printk("\n[%s] thread[%x,%x] exit failure : no socket found => discard segment\n", 1617 __FUNCTION__, this->process->pid, this->trdid ); 1618 #endif 2021 1619 2022 1620 } // end dev_nic_rx_handle_tcp_segment() … … 2027 1625 { 2028 1626 uint8_t k_buf[2048]; // kernel buffer for one ETH/IP/UDP packet 2029 2030 1627 uint32_t pkt_src_addr; // packet source IP address 2031 1628 uint32_t pkt_dst_addr; // packet destination IP address … … 2033 1630 uint32_t eth_length; // size of Ethernet packet (bytes) 2034 1631 uint32_t ip_length; // size of IP packet in bytes 2035 uint32_t nic_queue_readable; // NIC_RX queue non empty when true2036 1632 error_t error; 2037 1633 2038 thread_t * this = CURRENT_THREAD; 1634 thread_t * this = CURRENT_THREAD; 1635 1636 // check thread can yield 1637 thread_assert_can_yield( this , __FUNCTION__ ); 2039 1638 2040 1639 // check chdev direction and type … … 2042 1641 "illegal chdev type or direction" ); 2043 1642 2044 // check thread can yield 2045 assert( (this->busylocks == 0), 2046 "cannot yield : busylocks = %d\n", this->busylocks ); 1643 #if DEBUG_DEV_NIC_RX 1644 uint32_t cycle = (uint32_t)hal_get_cycles(); 1645 if( cycle > DEBUG_DEV_NIC_RX ) 1646 printk("\n[%s] thread[%x,%x] starts / cycle %d\n", 1647 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1648 #endif 1649 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 ); 2047 1653 2048 1654 while( 1 ) 2049 1655 { 2050 // check NIC_RX_QUEUE readable 2051 error = dev_nic_rx_queue_readable( chdev, 2052 &nic_queue_readable ); 2053 if( error ) 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 2054 1667 { 2055 printk("\n[PANIC] in %s : cannot access NIC_TX[%d] queue\n", 2056 __FUNCTION__, chdev->channel ); 1668 1669 #if DEBUG_DEV_NIC_RX 1670 cycle = (uint32_t)hal_get_cycles(); 1671 if( DEBUG_DEV_NIC_RX < cycle ) 1672 printk("\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 1686 cycle = (uint32_t)hal_get_cycles(); 1687 if( DEBUG_DEV_NIC_RX < cycle ) 1688 printk("\n[%s] thread[%x,%x] resumes / cycle %d\n", 1689 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1690 #endif 1691 2057 1692 } 2058 2059 if( nic_queue_readable ) // NIC_TX_QUEUE non empty 1693 else // success => handle packet 2060 1694 { 2061 // moves one Ethernet packet to kernel buffer 2062 error = dev_nic_rx_move_packet( chdev, 2063 k_buf, 2064 ð_length ); 2065 if( error ) 2066 { 2067 printk("\n[PANIC] in %s : cannot read the NIC_TX[%d] queue\n", 2068 __FUNCTION__, chdev->channel ); 2069 } 1695 1696 #if DEBUG_DEV_NIC_RX 1697 cycle = (uint32_t)hal_get_cycles(); 1698 if( DEBUG_DEV_NIC_RX < cycle ) 1699 dev_nic_packet_display( false, // is_tx 1700 this->process->pid, 1701 this->trdid, 1702 cycle, 1703 k_buf ); 1704 #endif 2070 1705 2071 1706 // analyse the ETH header … … 2074 1709 2075 1710 // discard packet if error reported by Ethernet layer 2076 if( error ) continue; 2077 1711 if( error ) 1712 { 1713 1714 #if DEBUG_DEV_NIC_RX 1715 cycle = (uint32_t)hal_get_cycles(); 1716 if( DEBUG_DEV_NIC_RX < cycle ) 1717 printk("\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) 1724 cycle = (uint32_t)hal_get_cycles(); 1725 if( DEBUG_DEV_NIC_RX < cycle ) 1726 printk("\n[%s] thread[%x,%x] successfully checked ETH packet / cycle %d\n", 1727 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1728 #endif 2078 1729 // analyse the IP header 2079 1730 error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN, … … 2084 1735 2085 1736 // discard packet if error reported by IP layer 2086 if( error ) continue; 1737 if( error ) 1738 { 1739 1740 #if DEBUG_DEV_NIC_RX 1741 cycle = (uint32_t)hal_get_cycles(); 1742 if( DEBUG_DEV_NIC_RX < cycle ) 1743 printk("\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 ) 1750 cycle = (uint32_t)hal_get_cycles(); 1751 if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_UDP) ) 1752 printk("\n[%s] thread[%x,%x] successfully checked UDP packet / cycle %d\n", 1753 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1754 if( (DEBUG_DEV_NIC_RX < cycle) && (trsp_protocol == PROTOCOL_TCP) ) 1755 printk("\n[%s] thread[%x,%x] successfully checked TCP segment / cycle %d\n", 1756 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1757 #endif 2087 1758 2088 1759 // call relevant transport protocol … … 2103 1774 pkt_dst_addr ); 2104 1775 } 1776 else // discard packet if unsupported transport protocol 1777 { 1778 1779 #if DEBUG_DEV_NIC_RX 1780 cycle = (uint32_t)hal_get_cycles(); 1781 if( DEBUG_DEV_NIC_RX < cycle ) 1782 printk("\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 } 2105 1787 } 2106 else // block and deschedule if NIC_RX_QUEUE empty2107 {2108 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_ISR );2109 sched_yield( "waiting RX client" );2110 }2111 2112 1788 } // end of while loop 2113 2114 1789 } // end dev_nic_rx_server() 2115 1790 … … 2117 1792 2118 1793 2119 2120 2121 2122 2123 2124 2125 1794 /////////////////////////////////////////////////////////////////////////////////////////// 2126 1795 // Functions used by the NIC_TX server thread 2127 1796 /////////////////////////////////////////////////////////////////////////////////////////// 2128 1797 2129 2130 /////////////////////////////////////////////////////////////////////////////////////////// 2131 // These static functions are called by the NIC_TX server thread to report the 2132 // completion (success or error) of a TX command. 2133 // - it print an error message in case of error. 2134 // - it updates the "tx_error" field in socket descriptor. 2135 // - it unblocks the client thread. 2136 /////////////////////////////////////////////////////////////////////////////////////////// 2137 // @ socket_xp : [in] extended pointer on socket 2138 // @ cmd_type : [in] SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE 2139 // @ socket_state : [in] current socket state 2140 /////////////////////////////////////////////////////////////////////////////////////////// 2141 static void dev_nic_tx_report_error( xptr_t socket_xp, 2142 uint32_t cmd_type, 2143 uint32_t socket_state ) 2144 { 2145 printk("\n[ERROR] in %s : command %s in %s state\n", 2146 __FUNCTION__, socket_cmd_str(cmd_type), socket_state_str(socket_state) ); 2147 2148 // get socket thread cluster and local pointer 2149 socket_t * socket_ptr = GET_PTR( socket_xp ); 2150 cxy_t socket_cxy = GET_CXY( socket_xp ); 2151 2152 // set tx_error field in socket descriptor 2153 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 1 ); 2154 2155 // get extended point on client thread 2156 xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client )); 2157 2158 // unblock the client thread 2159 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 2160 } 2161 2162 //////////////////////////////////////////////////////////// 2163 static void dev_nic_tx_report_success( xptr_t socket_xp ) 2164 { 2165 // get socket thread cluster and local pointer 2166 socket_t * socket_ptr = GET_PTR( socket_xp ); 2167 cxy_t socket_cxy = GET_CXY( socket_xp ); 2168 2169 // set tx_error field in socket descriptor 2170 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_error ) , 0 ); 2171 2172 // get extended point on client thread 2173 xptr_t client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client )); 2174 2175 // unblock the client thread 2176 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 2177 } 2178 2179 2180 2181 2182 2183 /////////////////////////////////////////////////////////////////////////////////////////// 2184 // This static function is called by the dev_nic_tx_server() function. 2185 // It calls directly the NIC driver (WRITABLE command) and returns the status 2186 // of the NIC_TX queue identified by the <chdev> argument. 2187 // in the <writable> buffer. 2188 /////////////////////////////////////////////////////////////////////////////////////////// 2189 // @ chdev : [in] local pointer on NIC_TX chdev. 2190 // @ length : [in] packet length in bytes. 2191 // @ writable : [out] zero if queue full. 2192 // @ returns 0 if success / returns -1 if failure in accessing NIC device. 2193 /////////////////////////////////////////////////////////////////////////////////////////// 2194 error_t dev_nic_tx_queue_writable( chdev_t * chdev, 2195 uint32_t length, 2196 uint32_t * writable ) 2197 { 2198 thread_t * this = CURRENT_THREAD; 2199 2200 // initialize READABLE command in thread descriptor 2201 this->nic_cmd.dev_xp = XPTR( local_cxy , chdev ); 2202 this->nic_cmd.type = NIC_CMD_WRITABLE; 2203 this->nic_cmd.length = length; 2204 2205 // call driver to test writable 2206 chdev->cmd( XPTR( local_cxy , this ) ); 2207 2208 // return status 2209 *writable = this->nic_cmd.status; 2210 2211 // return error 2212 return this->nic_cmd.error; 2213 2214 } // end dev_nic_tx_queue_writable 2215 2216 /////////////////////////////////////////////////////////////////////////////////////////// 2217 // This static function is called by the dev_nic_tx_server() function. 1798 /////////////////////////////////////////////////////////////////////////////////////////// 1799 // This static function is called by the dev_nic_tx_build_packet() function. 2218 1800 // It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and 2219 1801 // <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument. 2220 // It calls directly the NIC driver, without registering in a waiting queue, because 2221 // only this NIC_TX server thread can access this NIC_TX_QUEUE. 2222 // 1) It checks NIC_TX_QUEUE status in a while loop, using the NIC_CMD_WRITABLE command. 2223 // As long as the queue is not writable, it blocks and deschedules. It is re-activated 2224 // by the NIC-TX ISR as soon as the queue changes status. 2225 // 2) When the queue is writable, it put the ETH/IP/UDP packet into the NIC_TX_QUEUE, 2226 // using the driver NIC_CMD_WRITE command. 2227 // Both commands are successively registered in this NIC-TX server thread descriptor 2228 // to be passed to the driver. 1802 // It blocks and deschedules on the BLOCKED_ISR condition if the queue is full. 2229 1803 /////////////////////////////////////////////////////////////////////////////////////////// 2230 1804 // @ chdev : [in] local pointer on NIC_TX chdev. 2231 // @ buffer: [in] pointer on a local kernel buffer (2K bytes).1805 // @ k_buf : [in] pointer on a local kernel buffer (2K bytes). 2232 1806 // @ length : [in] actual Ethernet packet length in bytes. 2233 1807 /////////////////////////////////////////////////////////////////////////////////////////// 2234 void dev_nic_tx_move_packet( chdev_t * chdev,2235 uint8_t * buffer,2236 uint32_t length )1808 static void dev_nic_tx_move_packet( chdev_t * chdev, 1809 uint8_t * k_buf, 1810 uint32_t length ) 2237 1811 { 2238 error_t error;2239 uint32_t writable;2240 2241 1812 thread_t * this = CURRENT_THREAD; 2242 1813 … … 2245 1816 xptr_t chdev_xp = XPTR( local_cxy , chdev ); 2246 1817 2247 // get local pointer on core running this server thead2248 core_t * core = this->core;2249 2250 1818 // check thread can yield 2251 assert( (this->busylocks == 0), 2252 "cannot yield : busylocks = %d\n", this->busylocks ); 2253 2254 #if DEBUG_DEV_NIC_RX 1819 thread_assert_can_yield( this , __FUNCTION__ ); 1820 1821 #if (DEBUG_DEV_NIC_TX & 1) 2255 1822 uint32_t cycle = (uint32_t)hal_get_cycles(); 2256 if( DEBUG_DEV_NIC_RX < cycle ) 2257 printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n", 2258 __FUNCTION__, this->process->pid, this->trdid, pkd, cycle ); 2259 #endif 2260 2261 // check NIC_TX_QUEUE writable 2262 while( 1 ) 2263 { 2264 error = dev_nic_tx_queue_writable( chdev, 2265 length, 2266 &writable ); 2267 if( error ) 2268 { 2269 printk("\n[PANIC] in %s : cannot access NIC_TX queue\n", __FUNCTION__ ); 2270 return; 2271 } 2272 2273 if( writable == 0 ) // block & deschedule if non writable 2274 { 2275 // enable NIC-TX IRQ 2276 dev_pic_enable_irq( core->lid , chdev_xp ); 2277 2278 // block TX server thread 2279 thread_block( thread_xp , THREAD_BLOCKED_ISR ); 2280 2281 // deschedule TX server thread 2282 sched_yield("client blocked on NIC_TX queue full"); 2283 2284 // disable NIC-TX IRQ 2285 dev_pic_disable_irq( core->lid , chdev_xp ); 2286 } 2287 else // exit loop if writable 2288 { 2289 break; 2290 } 2291 } 1823 if( DEBUG_DEV_NIC_TX < cycle ) 1824 printk("\n[%s] thread[%x,%x] enter / buf %x / length %d / cycle %d\n", 1825 __FUNCTION__, this->process->pid, this->trdid, k_buf, length, cycle ); 1826 #endif 2292 1827 2293 1828 // initialize WRITE command in server thread descriptor 2294 1829 this->nic_cmd.dev_xp = chdev_xp; 2295 1830 this->nic_cmd.type = NIC_CMD_WRITE; 2296 this->nic_cmd.buffer = buffer;1831 this->nic_cmd.buffer = k_buf; 2297 1832 this->nic_cmd.length = length; 2298 1833 2299 // call driver to move packet 2300 chdev->cmd( thread_xp ); 2301 2302 #if DEBUG_DEV_NIC_RX 1834 while( 1 ) 1835 { 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 1841 { 1842 1843 #if (DEBUG_DEV_NIC_TX & 1) 2303 1844 cycle = (uint32_t)hal_get_cycles(); 2304 if( DEBUG_DEV_NIC_RX < cycle ) 2305 printk("\n[%s] thread[%x,%x] exit for packet %x\n", 2306 __FUNCTION__ , this->process->pid, this->trdid , pkd ); 2307 #endif 2308 2309 return; 2310 1845 if( DEBUG_DEV_NIC_TX < cycle ) 1846 printk("\n[%s] thread[%x,%x] exit SUCCESS / cycle %d\n", 1847 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1848 #endif 1849 break; 1850 } 1851 else // block and deschedule if queue full 1852 { 1853 1854 #if (DEBUG_DEV_NIC_TX & 1) 1855 cycle = (uint32_t)hal_get_cycles(); 1856 if( DEBUG_DEV_NIC_TX < cycle ) 1857 printk("\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 1864 thread_block( thread_xp , THREAD_BLOCKED_ISR ); 1865 sched_yield("client blocked on NIC_TX queue full"); 1866 1867 // disable NIC-TX IRQ 1868 dev_pic_disable_irq( this->core->lid , chdev_xp ); 1869 1870 #if (DEBUG_DEV_NIC_TX & 1) 1871 cycle = (uint32_t)hal_get_cycles(); 1872 if( DEBUG_DEV_NIC_TX < cycle ) 1873 printk("\n[%s] thread[%x,%x] resumes / cycle %d\n", 1874 __FUNCTION__, this->process->pid, this->trdid, cycle ); 1875 #endif 1876 } 1877 } 2311 1878 } // end dev_nic_tx_move_packet() 2312 1879 … … 2322 1889 // @ length : [in] number of bytes in payload. 2323 1890 /////////////////////////////////////////////////////////////////////////////////////////// 2324 void dev_nic_tx_build_udp_header( uint8_t * k_buf,2325 xptr_t socket_xp,2326 uint32_t length )1891 static void dev_nic_tx_build_udp_header( uint8_t * k_buf, 1892 xptr_t socket_xp, 1893 uint32_t length ) 2327 1894 { 2328 1895 uint16_t checksum; // checksum value … … 2375 1942 /////////////////////////////////////////////////////////////////////////////////////////// 2376 1943 // @ k_buf : [in] pointer on first byte of TCP header in kernel buffer. 1944 // @ socket_xp : [in] extended pointer on socket. 2377 1945 // @ length : [in] number of bytes in payload. 2378 // @ socket_xp : [in] extended pointer on socket.2379 1946 // @ flags : [in] flags to be set in TCP header. 2380 1947 /////////////////////////////////////////////////////////////////////////////////////////// 2381 void dev_nic_tx_build_tcp_header( uint8_t * k_buf,2382 uint32_t length,2383 xptr_t socket_xp,2384 uint8_t flags )1948 static void dev_nic_tx_build_tcp_header( uint8_t * k_buf, 1949 xptr_t socket_xp, 1950 uint32_t length, 1951 uint8_t flags ) 2385 1952 { 2386 1953 uint16_t checksum; // global segment checksum … … 2392 1959 uint32_t seq_num; // first byte of segment in TX stream 2393 1960 uint32_t ack_num; // next expected byte in RX stream 2394 uint 16_t window; // window of accepted segments in RX stream1961 uint32_t window; // window of accepted segments in RX stream 2395 1962 2396 1963 // get socket cluster an local pointer … … 2467 2034 // @ length : number of bytes in IP packet payload. 2468 2035 /////////////////////////////////////////////////////////////////////////////////////////// 2469 void dev_nic_tx_build_ip_header( uint8_t * buffer, 2470 uint32_t src_addr, 2471 uint32_t dst_addr, 2472 uint16_t length ) 2036 static 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 ) 2473 2041 { 2474 2042 uint16_t hcs; … … 2487 2055 2488 2056 buffer[8] = 0xFF; // TTL 2489 buffer[9] = 0x11; // UDPprotocol2057 buffer[9] = protocol; // transport protocol 2490 2058 2491 2059 buffer[12] = src_addr >> 24; … … 2521 2089 // @ length : number of bytes in Ethernet frame payload. 2522 2090 /////////////////////////////////////////////////////////////////////////////////////////// 2523 void dev_nic_tx_build_eth_header( uint8_t * buffer, 2524 uint16_t src_mac_54, 2525 uint16_t src_mac_32, 2526 uint16_t src_mac_10, 2527 uint16_t dst_mac_54, 2528 uint16_t dst_mac_32, 2529 uint16_t dst_mac_10, 2530 uint32_t length ) 2091 static 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 ) 2531 2105 { 2532 buffer[0] = dst_mac_5 4 >> 8;2533 buffer[1] = dst_mac_ 54;2534 buffer[2] = dst_mac_3 2 >> 8;2535 buffer[3] = dst_mac_ 32;2536 buffer[4] = dst_mac_1 0 >> 8;2537 buffer[5] = dst_mac_ 10;2538 2539 buffer[6] = src_mac_5 4 >> 8;2540 buffer[7] = src_mac_ 54;2541 buffer[8] = src_mac_3 2 >> 8;2542 buffer[9] = src_mac_ 32;2543 buffer[10] = src_mac_1 0 >> 8;2544 buffer[11] = src_mac_ 10;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; 2112 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; 2545 2119 2546 2120 buffer[12] = length >> 8; … … 2550 2124 2551 2125 /////////////////////////////////////////////////////////////////////////////////////////// 2552 // This static function is called by the dev_nic_tx_server() function to handle one 2553 // TX command, or one R2T request, registered in the socket identified by the <socket_xp> 2554 // argument. If there is one valid command, or if the R2T queue is non empty (for a TCP 2555 // socket), it builds an ETH/IP/UDP packet (or a ETH/IP/TCP segment), in the buffer 2556 // defined by the <k_buf> argument, and registers it in the NIC_TX queue defined by the 2557 // <chdev> argument. The supported commands are SOCKET_SEND/SOCKET_CONNECT/SOCKET_CLOSE. 2558 // It unblocks the client thread when the command is completed. 2559 /////////////////////////////////////////////////////////////////////////////////////////// 2560 // When there is a packet to send, it makes the following actions: 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. 2141 /////////////////////////////////////////////////////////////////////////////////////////// 2142 // To build a packet, it makes the following actions: 2561 2143 // 1) it takes the lock protecting the socket state. 2562 // 2) it get the command arguments from client thread descriptor. 2563 // 3) it build an UDP packet or a TCP segment, depending on both the command type, and 2564 // the socket state, updates the socket state, and unblocks the client thread. 2565 // 4) it release the lock protecting the socket. 2566 // 5) it build the IP header. 2567 // 6) it build the ETH header. 2568 // 7) it copies the packet in the NIC_TX queue. 2569 /////////////////////////////////////////////////////////////////////////////////////////// 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. 2151 /////////////////////////////////////////////////////////////////////////////////////////// 2152 // @ cmd_state : [in] TX command valid in socket descriptor. 2153 // @ r2t_valid : [in] R2T request valid in command descriptor. 2570 2154 // @ socket_xp : [in] extended pointer on client socket. 2571 2155 // @ k_buf : [in] local pointer on kernel buffer (2 Kbytes). 2572 2156 // @ chdev : [in] local pointer on NIC_RX chdev. 2573 2157 /////////////////////////////////////////////////////////////////////////////////////////// 2574 static void dev_nic_tx_handle_one_cmd( xptr_t socket_xp, 2575 uint8_t * k_buf, 2576 chdev_t * chdev ) 2158 static 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 ) 2577 2163 { 2578 2164 socket_t * socket_ptr; 2579 2165 cxy_t socket_cxy; 2580 2166 xptr_t client_xp; // extended pointer on client thread 2581 thread_t * client_ptr; 2582 cxy_t client_cxy; 2583 sock_cmd_t cmd; // NIC command type 2584 uint8_t * buf; // pointer on user buffer 2585 uint32_t len; // user buffer length 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) 2586 2170 uint32_t todo; // number of bytes not yet sent 2587 2171 uint32_t socket_type; // socket type (UDP/TCP) … … 2591 2175 uint32_t src_ip_addr; // source IP address 2592 2176 uint32_t dst_ip_addr; // destination IP address 2593 uint32_t tx_una; // next byte to be sent 2594 uint32_t tx_nxt; // first unacknowledged byte 2177 uint32_t tx_nxt; // next sequence number in TX stream 2595 2178 uint32_t nbytes; // number of bytes in UDP/TCP packet payload 2596 uint8_t * k_ base; // pointerUDP/TCP packet in kernel buffer2179 uint8_t * k_trsp_base; // pointer on UDP/TCP packet in kernel buffer 2597 2180 uint32_t trsp_length; // length of TCP/UDP packet 2181 uint8_t trsp_protocol; // transport protocol type (UDP/TCP) 2598 2182 uint8_t r2t_flags; // flags defined by one R2T queue request 2599 2183 bool_t do_send; // build & send a packet when true … … 2602 2186 socket_cxy = GET_CXY( socket_xp ); 2603 2187 socket_ptr = GET_PTR( socket_xp ); 2604 2605 // build extended pointer on socket lock and r2t queue 2606 socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock ); 2188 2189 #if DEBUG_DEV_NIC_TX 2190 thread_t * this = CURRENT_THREAD;; 2191 uint32_t cycle = (uint32_t)hal_get_cycles(); 2192 uint32_t fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid )); 2193 uint32_t pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 2194 if( cycle > DEBUG_DEV_NIC_TX ) 2195 printk("\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 ); 2607 2201 socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq ); 2608 2202 2609 2203 // 1. take lock protecting this socket 2610 remote_rwlock_wr_acquire( socket_lock_xp ); 2611 2612 // get pointers on TX client thread from socket 2613 client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client )); 2614 client_cxy = GET_CXY( client_xp ); 2615 client_ptr = GET_PTR( client_xp ); 2616 2617 // check valid command 2618 if( client_xp != XPTR_NULL ) // valid command found 2204 remote_queuelock_acquire( socket_lock_xp ); 2205 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 )); 2211 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 2619 2221 { 2620 2222 // 2. get command arguments from socket 2621 cmd = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_cmd )); 2622 buf = hal_remote_lpt( XPTR(socket_cxy , &socket_ptr->tx_buf )); 2623 len = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_len )); 2624 todo = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_todo )); 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 )); 2625 2228 2626 // get socket type and state 2627 socket_type = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->type )); 2628 socket_state = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->state )); 2629 2229 #if DEBUG_DEV_NIC_TX 2230 cycle = (uint32_t)hal_get_cycles(); 2231 if( cycle > DEBUG_DEV_NIC_TX ) 2232 printk("\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, 2234 socket_cmd_type_str(cmd_type), socket_state_str(socket_state), cycle ); 2235 #endif 2236 2237 ////////////////////////////////////////////////////////// 2630 2238 // 3. UDP : build UDP packet and update UDP socket state 2631 2239 if( socket_type == SOCK_DGRAM ) 2632 2240 { 2633 if( socket_state == UDP_STATE_UNBOUND ) 2241 trsp_protocol = PROTOCOL_UDP; 2242 2243 if( socket_state != UDP_STATE_ESTAB ) 2634 2244 { 2635 // report illegal command 2636 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2637 2638 do_send = false; 2245 // reset tx_valid 2246 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false ); 2247 2248 // unblock client thread / report error 2249 dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE ); 2639 2250 } 2640 else // BOUND or CONNECT state2251 else 2641 2252 { 2642 if( cmd == SOCKET_TX_SEND )2253 if( cmd_type == CMD_TX_SEND ) 2643 2254 { 2644 2255 // compute payload length 2645 2256 nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo; 2646 2257 2647 // compute UDP packet base in kernel buffer 2648 k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN; 2649 2650 // move payload to kernel buffer 2651 hal_copy_from_uspace( XPTR(local_cxy , k_base + UDP_HEAD_LEN ), 2652 buf + (len - todo), 2653 nbytes ); 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 ); 2262 2654 2263 // build UDP header 2655 dev_nic_tx_build_udp_header( k_ base,2264 dev_nic_tx_build_udp_header( k_trsp_base, 2656 2265 socket_xp, 2657 2266 nbytes ); 2658 2267 2659 2268 // update "tx_todo" in socket descriptor 2660 hal_remote_s32( XPTR(socket_cxy , socket_ptr->tx_todo), 2661 todo - nbytes ); 2662 2663 // unblock client thread when SEND command completed 2664 if( nbytes == todo ) 2269 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes ); 2270 2271 // send UDP packet 2272 trsp_length = UDP_HEAD_LEN + nbytes; 2273 do_send = true; 2274 2275 #if( DEBUG_DEV_NIC_TX & 1) 2276 cycle = (uint32_t)hal_get_cycles(); 2277 if( cycle > DEBUG_DEV_NIC_TX ) 2278 printk("\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 2665 2282 { 2666 dev_nic_tx_report_success( socket_xp ); 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 ); 2667 2288 } 2668 2669 do_send = true; 2670 } 2671 else 2672 { 2673 // report illegal command 2674 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2675 2676 do_send = false; 2289 } 2290 else // CONNECT, ACCEPT, or CLOSE commands are illegal for UDP 2291 { 2292 // reset tx_valid 2293 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ) , false ); 2294 2295 // report error 2296 dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD ); 2677 2297 } 2678 2298 } 2679 2680 // compute transport packet length2681 trsp_length = UDP_HEAD_LEN + nbytes;2682 2683 2299 } // end UDP 2684 2300 2301 /////////////////////////////////////////////////////////// 2685 2302 // 3. TCP : build TCP segment and update TCP socket state 2686 if( socket_type == SOCK_STREAM )2303 else if( socket_type == SOCK_STREAM ) 2687 2304 { 2688 // extract one request from TCP socket R2T queue if queue non empty 2689 if( remote_buf_status( socket_r2tq_xp ) ) 2305 trsp_protocol = PROTOCOL_TCP; 2306 2307 // handle R2T request / initialize r2t_flags 2308 if( r2t_valid ) 2690 2309 { 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 2691 2314 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 ); 2692 2315 } … … 2696 2319 } 2697 2320 2321 //////////////////////////////// 2322 if( cmd_type == CMD_TX_CONNECT ) // always executed by a TCP client 2323 { 2324 if( (socket_state == TCP_STATE_BOUND) || 2325 (socket_state == TCP_STATE_LISTEN) ) // send a SYN segment 2326 { 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 ); 2330 2331 // build TCP SYN segment 2332 dev_nic_tx_build_tcp_header( k_trsp_base, 2333 socket_xp, 2334 0, // length 2335 TCP_FLAG_SYN ); 2336 // send segment 2337 trsp_length = TCP_HEAD_LEN; 2338 do_send = true; 2339 2340 #if DEBUG_DEV_NIC_TX 2341 cycle = (uint32_t)hal_get_cycles(); 2342 if( cycle > DEBUG_DEV_NIC_TX ) 2343 printk("\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, 2346 socket_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 ); 2351 2352 // update socket.tx_nxt 2353 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 2354 TCP_ISS_CLIENT + 1 ); 2355 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 2360 { 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 ); 2366 } 2367 } 2368 //////////////////////////////////// 2369 else if( cmd_type == CMD_TX_ACCEPT ) // always executed by a TCP server 2370 { 2371 2372 if( socket_state == TCP_STATE_SYN_RCVD ) // send a SYN-ACK segment 2373 { 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 2388 cycle = (uint32_t)hal_get_cycles(); 2389 if( cycle > DEBUG_DEV_NIC_TX ) 2390 printk("\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, 2392 socket_state_str( socket_state ), cycle ); 2393 #endif 2394 // update socket.state 2395 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2396 TCP_STATE_SYN_RCVD ); 2397 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 ); 2404 } 2405 else // report error in all other socket states 2406 { 2407 // reset tx_valid 2408 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false ); 2409 2410 // report error to TX client thread 2411 dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE ); 2412 } 2413 } 2414 /////////////////////////////////// 2415 else if( cmd_type == CMD_TX_CLOSE ) 2416 { 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 2420 { 2421 // get "tx_nxt" from socket descriptor 2422 tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt )); 2423 2424 // compute next state 2425 uint32_t state = (socket_state == TCP_STATE_CLOSE_WAIT) ? 2426 TCP_STATE_LAST_ACK : TCP_STATE_FIN_WAIT1; 2427 2428 // update socket state 2429 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), state ); 2430 2431 // build TCP FIN segment 2432 dev_nic_tx_build_tcp_header( k_trsp_base, 2433 socket_xp, 2434 0, // length 2435 TCP_FLAG_FIN | TCP_FLAG_ACK ); 2436 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 2445 cycle = (uint32_t)hal_get_cycles(); 2446 if( cycle > DEBUG_DEV_NIC_TX ) 2447 printk("\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, 2449 socket_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 ); 2453 } 2454 else // all other states => signal error 2455 { 2456 2457 #if DEBUG_DEV_NIC_TX 2458 cycle = (uint32_t)hal_get_cycles(); 2459 if( cycle > DEBUG_DEV_NIC_TX ) 2460 printk("\n[%s] thread[%x,%x] socket[%x,%d] %s / CLOSE / error BADSTATE / cycle %d\n", 2461 __FUNCTION__, this->process->pid, this->trdid, pid, fdid, 2462 socket_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 ); 2469 } 2470 } 2698 2471 ///////////////////////////////////// 2699 if( socket_state == TCP_STATE_ESTAB ) // connected TCP socket2472 else if( cmd_type == CMD_TX_SEND ) 2700 2473 { 2701 if( cmd == SOCKET_TX_SEND ) 2702 { 2703 // get "tx_nxt", and "tx_una" from socket descriptor 2474 if( (socket_state == TCP_STATE_ESTAB ) || 2475 (socket_state == TCP_STATE_CLOSE_WAIT) ) 2476 { 2477 // get "tx_nxt" from socket descriptor 2704 2478 tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt )); 2705 tx_una = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_una ));2706 2479 2707 2480 // compute actual payload length … … 2709 2482 2710 2483 // compute TCP segment base in kernel buffer 2711 k_ base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN;2712 2713 // move payload to k ernel buffer2714 hal_copy_from_uspace( XPTR( local_cxy , k_base + TCP_HEAD_LEN ),2715 2716 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 ); 2717 2490 2718 2491 // build TCP header 2719 dev_nic_tx_build_tcp_header( k_ base,2492 dev_nic_tx_build_tcp_header( k_trsp_base, 2720 2493 socket_xp, 2721 2494 nbytes, // payload … … 2723 2496 2724 2497 // update "tx_todo" in socket descriptor 2725 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_todo ), 2726 todo - nbytes ); 2498 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_todo), todo - nbytes ); 2727 2499 2728 2500 // update "tx_nxt" in socket descriptor 2729 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 2730 tx_nxt + nbytes ); 2731 2732 // unblock client thread when SEND command completed 2733 if( (todo == 0) && (tx_nxt == tx_una) ) 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 2734 2508 { 2735 dev_nic_tx_report_success( socket_xp ); 2509 // reset tx_valid when last byte has been sent 2510 hal_remote_s32( XPTR(socket_cxy , &socket_ptr->tx_valid), false ); 2736 2511 } 2737 2512 2738 do_send = true; 2739 } 2740 else if( cmd == SOCKET_TX_CLOSE ) 2741 { 2742 // build TCP FIN segment 2743 dev_nic_tx_build_tcp_header( k_base, 2744 socket_xp, 2745 0, // payload 2746 TCP_FLAG_FIN | r2t_flags ); // flags 2747 // update socket state 2748 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2749 TCP_STATE_FIN_WAIT1 ); 2750 2751 do_send = true; 2752 } 2753 else // cmd == CONNECT 2754 { 2755 // report illegal command 2756 dev_nic_tx_report_error( socket_xp , cmd , socket_state ); 2757 2758 do_send = false; 2513 #if DEBUG_DEV_NIC_TX 2514 cycle = (uint32_t)hal_get_cycles(); 2515 if( cycle > DEBUG_DEV_NIC_TX ) 2516 printk("\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, 2519 socket_state_str( socket_state ), nbytes, cycle ); 2520 #endif 2521 } 2522 else // all other socket states 2523 { 2524 // reset tx_valid 2525 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false ); 2526 2527 // report error to TX client thread 2528 dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADSTATE ); 2759 2529 } 2760 2530 } 2761 /////////////////////////////////// ///////2762 else if( socket_state == TCP_STATE_BOUND ) // unconnected TCP socket2531 /////////////////////////////////// 2532 else // undefined TX command type 2763 2533 { 2764 if ( cmd == SOCKET_TX_CONNECT ) 2765 { 2766 // set socket.tx_nxt 2767 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 2768 TCP_ISS ); 2769 2770 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 0 ); 2771 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ), 2772 NIC_RX_BUF_SIZE); 2773 2774 // build TCP SYN segment 2775 dev_nic_tx_build_tcp_header( k_base, 2776 socket_xp, 2777 0, // payload 2778 TCP_FLAG_SYN ); // flags 2779 // update socket state 2780 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2781 TCP_STATE_SYN_SENT ); 2782 2783 do_send = true; 2784 } 2785 else // cmd == SEND / CLOSE 2786 { 2787 // report illegal command 2788 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2789 2790 do_send = false; 2791 } 2534 // reset tx_valid 2535 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_valid ), false ); 2536 2537 // report error to TX client thread 2538 dev_nic_unblock_tx_client( socket_xp , CMD_STS_BADCMD ); 2792 2539 } 2793 /////////////////////////////////////////// 2794 else if( socket_state == TCP_STATE_LISTEN ) // server wait connect 2795 { 2796 if( cmd == SOCKET_TX_CONNECT ) 2797 { 2798 // update socket.state 2799 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2800 TCP_STATE_SYN_SENT ); 2801 2802 // set socket.tx_una 2803 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 2804 TCP_ISS ); 2805 2806 // set socket.tx_nxt 2807 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 2808 TCP_ISS + 1 ); 2809 2810 // build TCP SYN segment 2811 dev_nic_tx_build_tcp_header( k_base, 2812 socket_xp, 2813 0, // payload 2814 TCP_FLAG_SYN ); // flags 2815 do_send = true; 2816 } 2817 else // cmd == CLOSE / SEND 2818 { 2819 // report illegal command 2820 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2821 2822 do_send = false; 2823 } 2824 } 2825 ///////////////////////////////////////////// 2826 else if( socket_state == TCP_STATE_SYN_RCVD ) // socket wait ACK 2827 { 2828 if( cmd == SOCKET_TX_CLOSE ) 2829 { 2830 // build TCP FIN segment 2831 dev_nic_tx_build_tcp_header( k_base, 2832 socket_xp, 2833 0, // payload 2834 TCP_FLAG_FIN ); // flags 2835 // update socket state 2836 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2837 TCP_STATE_FIN_WAIT1 ); 2838 2839 do_send = true; 2840 } 2841 else // SEND / CONNECT 2842 { 2843 // report illegal command 2844 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2845 2846 do_send = false; 2847 } 2848 } 2849 //////////////////////////////////////////////// 2850 else if( socket_state == TCP_STATE_CLOSE_WAIT ) // wait local close() 2851 { 2852 if( cmd == SOCKET_TX_CLOSE ) 2853 { 2854 // build TCP FIN segment 2855 dev_nic_tx_build_tcp_header( k_base, 2856 socket_xp, 2857 0, // payload 2858 TCP_FLAG_FIN ); // flags 2859 // update socket state 2860 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2861 TCP_STATE_LAST_ACK ); 2862 2863 do_send = true; 2864 } 2865 else // SEND / CONNECT 2866 { 2867 // report illegal command 2868 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2869 2870 do_send = false; 2871 } 2872 } 2873 //// 2874 else 2875 { 2876 // report illegal command 2877 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2878 2879 do_send = false; 2880 } 2881 2882 // compute TCP segment length 2883 trsp_length = TCP_HEAD_LEN + nbytes; 2884 } 2885 } 2886 else // no valid command found 2540 } // end TCP 2541 } 2542 else // no valid TX command => handle R2T request only 2887 2543 { 2888 if( socket_type == SOCK_DGRAM ) // UDP socket 2889 { 2890 do_send = false; 2891 } 2892 else // TCP socket 2893 { 2894 if( remote_buf_status( socket_r2tq_xp ) == 0 ) // R2T queue empty 2895 { 2896 do_send = false; 2897 } 2898 else // pending request in R2T queue 2899 { 2900 // get one request from R2T queue 2901 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 ); 2902 2903 // build TCP header for an empty segment 2904 dev_nic_tx_build_tcp_header( k_base, 2905 socket_xp, 2906 0, // payload 2907 r2t_flags ); // flags 2908 do_send = true; 2909 } 2910 } 2544 // get one request from R2T queue 2545 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 ); 2546 2547 #if DEBUG_DEV_NIC_TX 2548 cycle = (uint32_t)hal_get_cycles(); 2549 if( cycle > DEBUG_DEV_NIC_TX ) 2550 printk("\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; 2911 2563 } 2912 2564 2913 2565 // 4. release the lock protecting the socket 2914 remote_ rwlock_wr_release( socket_lock_xp );2566 remote_queuelock_release( socket_lock_xp ); 2915 2567 2916 2568 // return if no packet to send … … 2921 2573 src_ip_addr, 2922 2574 dst_ip_addr, 2923 IP_HEAD_LEN + trsp_length ); 2575 trsp_protocol, 2576 trsp_length ); 2577 2578 #if( DEBUG_DEV_NIC_TX & 1) 2579 cycle = (uint32_t)hal_get_cycles(); 2580 if( cycle > DEBUG_DEV_NIC_TX ) 2581 printk("\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 2924 2584 2925 2585 // 6. build ETH header 2926 2586 dev_nic_tx_build_eth_header( k_buf, 2927 (uint16_t)SRC_MAC_54, 2928 (uint16_t)SRC_MAC_32, 2929 (uint16_t)SRC_MAC_10, 2930 (uint16_t)DST_MAC_54, 2931 (uint16_t)DST_MAC_32, 2932 (uint16_t)DST_MAC_10, 2933 ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length ); 2934 2935 // 7. move packet to NIC_TX queue 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 ); 2600 2601 #if( DEBUG_DEV_NIC_TX & 1) 2602 cycle = (uint32_t)hal_get_cycles(); 2603 if( cycle > DEBUG_DEV_NIC_TX ) 2604 printk("\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) 2936 2609 dev_nic_tx_move_packet( chdev, 2937 2610 k_buf, 2938 2611 ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length ); 2939 2612 2940 } // end dev_nic_tx_handle_one_cmd() 2613 #if DEBUG_DEV_NIC_TX 2614 cycle = (uint32_t)hal_get_cycles(); 2615 if( cycle > DEBUG_DEV_NIC_TX ) 2616 printk("\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 2619 2620 } // end dev_nic_tx_build_packet() 2621 2941 2622 2942 2623 ///////////////////////////////////////// … … 2945 2626 uint8_t k_buf[NIC_KERNEL_BUF_SIZE]; // buffer for one packet 2946 2627 2947 xptr_t root_xp; // extended pointer on clients list root2948 xptr_t lock_xp;// extended pointer on lock protecting this list2949 xptr_t socket_xp; // extended pointer on on clientsocket2628 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 2950 2631 socket_t * socket_ptr; 2951 2632 cxy_t socket_cxy; 2952 xptr_t entry_xp; // extended pointer on socket tx_list entry 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 2953 2639 2954 2640 thread_t * this = CURRENT_THREAD; 2641 2642 #if DEBUG_DEV_NIC_TX 2643 uint32_t cycle = (uint32_t)hal_get_cycles(); 2644 uint32_t pid; 2645 uint32_t fdid; 2646 if( cycle > DEBUG_DEV_NIC_TX ) 2647 printk("\n[%s] thread[%x,%x] starts / cycle %d\n", 2648 __FUNCTION__, this->process->pid, this->trdid, cycle ); 2649 #endif 2955 2650 2956 2651 // check chdev direction and type … … 2959 2654 2960 2655 // check thread can yield 2961 assert( (this->busylocks == 0), 2962 "cannot yield : busylocks = %d\n", this->busylocks ); 2963 2964 // build extended pointer on client sockets lock & root 2965 lock_xp = XPTR( local_cxy , &chdev->wait_lock ); 2966 root_xp = XPTR( local_cxy , &chdev->wait_root ); 2656 thread_assert_can_yield( this , __FUNCTION__ ); 2657 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 ); 2967 2664 2968 2665 while( 1 ) // TX server infinite loop 2969 2666 { 2667 // initialize temporary list of registered sockets as empty 2668 xlist_root_init( temp_root_xp ); 2669 temp_nr = 0; 2670 2970 2671 // take the lock protecting the client sockets queue 2971 remote_busylock_acquire( lock_xp );2972 2973 // ///////////// block and deschedule if no clients2974 if( xlist_is_empty( root_xp ) == false )2672 remote_busylock_acquire( queue_lock_xp ); 2673 2674 // build temporary list of all registered sockets 2675 if( xlist_is_empty( queue_root_xp ) == false ) 2975 2676 { 2976 // release the lock protecting the TX client sockets queue 2977 remote_busylock_release( lock_xp ); 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 2714 cycle = (uint32_t)hal_get_cycles(); 2715 pid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->pid )); 2716 fdid = hal_remote_l32( XPTR( socket_cxy , &socket_ptr->fdid )); 2717 if( cycle > DEBUG_DEV_NIC_TX ) 2718 printk("\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 2728 cycle = (uint32_t)hal_get_cycles(); 2729 if( cycle > DEBUG_DEV_NIC_TX ) 2730 dev_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 { 2978 2747 2748 #if DEBUG_DEV_NIC_TX 2749 cycle = (uint32_t)hal_get_cycles(); 2750 if( cycle > DEBUG_DEV_NIC_TX ) 2751 printk("\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 2979 2755 // block and deschedule 2980 2756 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT ); 2981 2757 sched_yield( "waiting client" ); 2758 2759 #if DEBUG_DEV_NIC_TX 2760 cycle = (uint32_t)hal_get_cycles(); 2761 if( cycle > DEBUG_DEV_NIC_TX ) 2762 printk("\n[%s] thread[%x,%x] resumes / cycle %d\n", 2763 __FUNCTION__, this->process->pid, this->trdid, cycle ); 2764 #endif 2982 2765 } 2983 ////////////// 2984 else 2985 { 2986 // get first client socket 2987 socket_xp = XLIST_FIRST( root_xp , socket_t , tx_list ); 2988 socket_cxy = GET_CXY( socket_xp ); 2989 socket_ptr = GET_PTR( socket_xp ); 2990 2991 // build extended pointer on socket xlist_entry 2992 entry_xp = XPTR( socket_cxy , &socket_ptr->tx_list ); 2993 2994 // remove this socket from the waiting queue 2995 xlist_unlink( entry_xp ); 2996 2997 // release the lock protecting the client sockets queue 2998 remote_busylock_release( lock_xp ); 2999 3000 // handle this TX client 3001 dev_nic_tx_handle_one_cmd( socket_xp, 3002 k_buf, 3003 chdev ); 3004 3005 // take the lock protecting the client sockets queue 3006 remote_busylock_acquire( lock_xp ); 3007 3008 // add this socket in last position of queue 3009 xlist_add_last( root_xp , entry_xp ); 3010 3011 // release the lock protecting the client sockets queue 3012 remote_busylock_release( lock_xp ); 3013 } 3014 } // end while 2766 } // end infinite while loop 3015 2767 } // end dev_nic_tx_server() 3016 2768 3017 2769 2770 ///////////////////////////////////////////// 2771 void 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] ) ; 2784 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] ) ; 2791 2792 uint16_t eth_length = ((uint16_t)buf[12] << 8) | 2793 ((uint16_t)buf[13] ) ; 2794 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] ) ; 2800 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] ) ; 2805 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] ) ; 2810 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 -
trunk/kernel/devices/dev_nic.h
r657 r663 56 56 * In this case, the channel index is defined by an hash function computed from the remote 57 57 * IP address and port. This index is computed by the hardware for an RX packet, and is 58 * computed by the kernel for a TX packet, using a specific driver function. TODO ...58 * computed by the kernel for a TX packet, using a specific driver function. 59 59 * The 2*N chdevs, and the associated server threads implementing the protocols stack, 60 60 * are distributed in 2*N different clusters. … … 63 63 * 64 64 * On the user side, ALMOS-MKH implements the POSIX socket API. 65 * The kernel functions implementing the socket related syscalls are : 66 * - dev_nic_socket() : create a local socket registered in process fd_array[]. 67 * - dev_nic_bind() : attach a local IP address and port to a local socket. 68 * - dev_nic_listen() : local server makes a passive open. 69 * - dev_nic_connect() : local client makes an active open to a remote server. 70 * - dev_nic_accept() : local server accept a new remote client. 71 * - dev_nic_send() : send data on a connected socket. 72 * - dev_nic_recv() : receive data on a connected socket. 73 * - dev_nic_sendto() : send a packet to a remote (IP address/port). 74 * - dev_nic_recvfrom() : receive a paket from a remote (IP address/port). 75 * - dev_nic_close() : close a socket 76 * 77 * 3) TX stream 78 * 79 * The internal API between the client threads and the TX server thread defines 80 * the 3 following commands: 81 * . SOCKET_TX_CONNECT : request to execute the 3 steps TCP connection handshake. 82 * . SOCKET_TX_SEND : send data to a remote socket (UDP or TCP). 83 * . SOCKET_TX_CLOSE : request to execute the 3 steps TCP close handshake. 84 * 85 * - These 3 commands are blocking for the client thread that registers the command in the 86 * socket descriptor, blocks on the BLOCKED_IO condition, and deschedules. 87 * - The TX server thread is acting as a multiplexer. It scans the list of attached sockets, 88 * to handle all valid commands: one UDP packet or TCP segment per iteration. 89 * It uses the user buffer defined by the client thread, and attached to socket descriptor, 90 * as a retransmission buffer. It blocks and deschedules on the BLOCKED_CLIENT condition, 91 * when there is no more active TX command registered in any socket. It is re-activated 92 * by the first client thread registering a new TX command in the socket descriptor. 93 * It unblocks a client thread only when a command is fully completed. It signals errors 94 * to the client thread using the tx_error field in socket descriptor. 95 * 96 * 4) RX stream 97 * 98 * The communication between the RX server thread and the client threads expecting data 99 * is done through receive buffers (one private buffer per socket) that are handled 100 * as single-writer / single reader-FIFOs, called rx_buf. 101 * - The RX server thread is acting as a demultiplexor: it handle one TCP segment or UDP 102 * packet per iteration, and register the data in the rx_buf of the socket matching 103 * the packet. It simply discard all packets that does not match a registered socket. 104 * When a client thread is registered in the socket descriptor, the RX server thread 105 * unblocks this client thread as soon as there is data available in rx_buf. 106 * It blocks and deschedules on the BLOCKED_ISR condition when there is no more packets 107 * in the NIC_RX queue. It is unblocked by the hardware ISR. 108 * - The client thread simply access the rx_buf attached to socket descriptor, and consumes 109 * the available data when the rx_buf is non empty. It blocks on the BLOCKED_IO condition, 110 * and deschedules when the rx_buf is empty. 111 * 112 * 5) R2T queue 113 * 114 * To implement the TCP "3 steps handshake" protocol, the RX server thread can directly 115 * request the associated TX server thread to send control packets in the TX stream, 116 * using a dedicate R2T (RX to TX) FIFO stored in the socket descriptor. 117 * 118 * 6) NIC driver API 119 * 120 * The generic NIC device "driver" API defines the following commands to the NIC driver: 121 * - READABLE : returns true if at least one RX paquet is available in RX queue. 122 * - WRITABLE : returns true if at least one empty slot is available in TX queue. 123 * - READ : consume one packet from the RX queue. 124 * - WRITE : produce one packet to the TX queue. 65 * The following kernel functions implement the socket related syscalls : 66 * - socket_build() : create a local socket registered in process fd_array[]. 67 * - socket_bind() : attach a local IP address and port to a local socket. 68 * - socket_listen() : local server makes a passive open. 69 * - socket_connect() : local client makes an active open to a remote server. 70 * - socket_accept() : local server accept a new remote client. 71 * - socket_send() : send data on a connected socket. 72 * - socket_recv() : receive data on a connected socket. 73 * - socket_sendto() : send a packet to a remote (IP address/port). 74 * - socket_recvfrom() : receive a paket from a remote (IP address/port). 75 * 76 * 3) NIC TX and NIC_RX server threads 77 * 78 * The dev_nic_tx_server() & dev_nic_rx_server() functions defined below execute 79 * the user commands stored in the sockets to implement the [ETH / IP / TCP or UDP] 80 * protocols stack, as defined in the <ksocket.c> and <ksocket.h> files. 81 * 82 * 4) NIC driver API 83 * 84 * The generic NIC device "driver" API defines the following commands, used by the 85 * NIC_TX and NIC_RX server threads, running in the cluster containing the relevant chdev, 86 * to access the NIC_TX and NIC_RX packets queues: 87 * 88 * - READ : consume one packet from the NIC_RX queue. 89 * - WRITE : produce one packet to the NIC_TX queue. 90 * 125 91 * All RX or TX paquets are sent or received in standard 2 Kbytes kernel buffers, 126 92 * that are dynamically allocated by the protocols stack. 127 *128 93 * The actual TX an RX queues structures depends on the hardware NIC implementation, 129 94 * and are defined in the HAL specific driver code. 95 * 96 * Moreover, the generic NIC device "driver" API defines the following commands, 97 * used directly by a client thread running in any cluster, to access the NIC device 98 * configuration or status registers: 99 * 100 * - GET_KEY : get channel index from remote IP address and port 101 * - SET_RUN : activate/desactivate one channel 102 * - GET_INSTRU : get one instrumentation counter value 103 * - CLEAR_INSTRU : reset all instrumentation counters 130 104 * 131 105 * WARNING: the WTI mailboxes used by the driver ro receive events from the hardware … … 140 114 struct chdev_s; 141 115 142 /****************************************************************************************** 143 * Various constants used by the Protocols stack 144 *****************************************************************************************/ 145 146 #define SRC_MAC_54 0x54 147 #define SRC_MAC_32 0x32 148 #define SRC_MAC_10 0x10 149 #define DST_MAC_54 0x54 150 #define DST_MAC_32 0x32 151 #define DST_MAC_10 0x10 116 /***************************************************************************************** 117 * Various constants used by the protocols stack 118 ****************************************************************************************/ 119 120 #define SRC_MAC_5 0x66 // This is a temporary short-cut for debug 121 #define SRC_MAC_4 0x55 122 #define SRC_MAC_3 0x44 123 #define SRC_MAC_2 0x33 124 #define SRC_MAC_1 0x22 125 #define SRC_MAC_0 0x11 126 127 #define DST_MAC_5 0x66 // This is a temporary short-cut for debug 128 #define DST_MAC_4 0x55 129 #define DST_MAC_3 0x44 130 #define DST_MAC_2 0x33 131 #define DST_MAC_1 0x22 132 #define DST_MAC_0 0x11 152 133 153 134 #define TCP_HEAD_LEN 20 … … 159 140 #define PROTOCOL_TCP 0x06 160 141 161 #define TCP_ISS 0x10000 162 163 #define PAYLOAD_MAX_LEN 1500 // max payload for and UDP packet or a TCP segment 142 #define TCP_ISS_CLIENT 0x10000 // initial sequence number for TCP client 143 #define TCP_ISS_SERVER 0x20000 // initial sequence number for TCP server 144 #define TCP_MAX_WINDOW 0xFFFFF // initial TCP send window 145 146 #define PAYLOAD_MAX_LEN 1500 // max length for an UDP packet / TCP segment 164 147 165 148 #define TCP_FLAG_FIN 0x01 … … 172 155 #define NIC_RX_BUF_SIZE 0x100000 // 1 Mbytes 173 156 #define NIC_R2T_QUEUE_SIZE 0x64 // smallest KCM size 174 #define NIC_CRQ_QUEUE_SIZE 0x8 // 8 * sizeof(sockaddr_t) = smallest KCM size 175 #define NIC_PKT_MAX_SIZE 1500 // for Ethernet 176 #define NIC_KERNEL_BUF_SIZE 2000 // for on ETH/IP/TCP packet 157 #define NIC_CRQ_QUEUE_SIZE 0x8 // actual size is 8 * sizeof(sockaddr_t) 158 #define NIC_KERNEL_BUF_SIZE 0x800 // 2 Kbytes for one ETH/IP/TCP packet 177 159 178 160 /***************************************************************************************** 179 * This defines the extension for the generic NIC device. 180 * The actual queue descriptor depends on the implementation. 181 * 182 * WARNING : for all NIC_TX and NIC_RX chdevs, the xlist rooted in in the chdev 183 * ("wait_root" and "wait_lock" fields) is actually a list of sockets. 161 * This structure defines the specific chdev extension for NIC device: 162 * - queue : local pointer on the memory mapped queue of TX or RX packets, used 163 * by the NIC driver to move packets to/from the NIC hardware. The actual descriptor 164 * depends on the NIC implementation. 165 * - root : root of an xlist of sockets that are in the LISTEN state, waiting one or 166 * several TCP connection requests from remote processes. It is only used by the 167 * NIC_RX server thread attached to a NIC_RX chdev. 168 * - lock : lock protecting concurrent access to the litening sockets list. 184 169 ****************************************************************************************/ 185 170 186 171 typedef struct nic_extend_s 187 172 { 188 void * queue; /*! local pointer on NIC queue descriptor (RX or TX) */ 173 void * queue; /*! pointer on NIC packets queue descriptor (RX or TX) */ 174 xlist_entry_t root; /*! root of listening sockets list (only used in RX[0]) */ 175 remote_busylock_t lock; /*! lock protecting this list (only used in RX[0] */ 189 176 } 190 177 nic_extend_t; … … 204 191 /**************************************************************************************** 205 192 * This defines the (implementation independant) commands to access the NIC hardware. 206 * These commands are registered by the NIC_TX and NIC_RX server threads in the 207 * server thread descriptor, to be used by the NIC driver. 208 * The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet. 193 * There is two types of commands 194 * - The first 2 commands are used by the NIC_TX and NIC_RX server threads, and stored 195 * in the server thread descriptor, to access the NIC_RX & NIC_TX packet queues. 196 * The buffer is always a 2K bytes kernel buffer, containing an Ethernet packet. 197 * - The next 4 synchronous commands are used by the client th, and stored in the 198 * client thread descriptor, to directly access the NIC registers. 209 199 ****************************************************************************************/ 210 200 211 201 typedef enum nic_cmd_e 212 202 { 213 NIC_CMD_WRITABLE = 10, /*! test TX queue not full (for a given packet length) */ 214 NIC_CMD_WRITE = 11, /*! put one (given length) packet to TX queue */ 215 NIC_CMD_READABLE = 12, /*! test RX queue not empty (for any packet length) */ 216 NIC_CMD_READ = 13, /*! get one (any length) packet from RX queue */ 203 NIC_CMD_WRITE = 10, /*! put one (given length) packet to TX queue */ 204 NIC_CMD_READ = 11, /*! get one (any length) packet from RX queue */ 205 206 NIC_CMD_GET_KEY = 20, /*! return channel index from IP address and port */ 207 NIC_CMD_SET_RUN = 21, /*! enable/disable one NIC channel */ 208 NIC_CMD_GET_INSTRU = 22, /*! return one intrumentation register value */ 209 NIC_CMD_CLEAR_INSTRU = 23, /*! reset all instrumentation registers */ 217 210 } 218 211 nic_cmd_t; … … 222 215 xptr_t dev_xp; /*! extended pointer on NIC chdev descriptor */ 223 216 nic_cmd_t type; /*! command type */ 224 uint8_t * buffer; /*! local pointer on buffer (kernel or user space)*/217 uint8_t * buffer; /*! local pointer on kernel buffer */ 225 218 uint32_t length; /*! number of bytes in buffer */ 226 219 uint32_t status; /*! return value (depends on command type) */ … … 228 221 } 229 222 nic_command_t; 230 231 /*****************************************************************************************232 * This structure defines a socket descriptor. In order to parallelize the transfers,233 * the set of all registered sockets is split in several subsets.234 * The number of subsets is the number of NIC channels.235 * The distribution key is computed from the (remote_addr/remote_port) couple.236 * This computation is done by the NIC hardware for RX packets,237 * and by the dev_nic_connect() function for the TX packets.238 *239 * A socket is attached to the NIC_TX[channel] & NIC_RX[channel] chdevs.240 * Each socket descriptor allows the TX and TX server threads to access various buffers:241 * - the user "send" buffer contains the data to be send by the TX server thread.242 * - the kernel "receive" buffer contains the data received by the RX server thread.243 * - the kernel "r2t" buffer allows the RX server thread to make direct requests244 * to the associated TX server (to implement the TCP 3 steps handshake).245 *246 * The synchronisation mechanism between the clients threads and the servers threads247 * is different for TX and RX transfers:248 *249 * 1) For a TX transfer, it can exist only one client thread for a given socket,250 * the transfer is always initiated by the local process, and all TX commands251 * (CONNECT/SEND/CLOSE) are blocking for the client thread. The user buffer is252 * used by TCP to handle retransmissions when required.in case of re253 * The client thread registers the command in the thread descriptor, registers itself254 * in the socket descriptor, unblocks the TX server thread from the BLOCKED_CLIENT255 * condition, blocks itself on the BLOCKED_IO condition, and deschedules.256 * When the command is completed, the TX server thread unblocks the client thread.257 * The TX server blocks itself on the BLOCKED_CLIENT condition, when there is no258 * pending commands and the R2T queue is empty. It is unblocked when a client259 * register a new command, or when the TX server thread register a mew request260 * in the R2T queue.261 * The tx_valid flip-flop is SET by the client thread to signal a valid command.262 * It is RESET by the server thread when the command is completed: For a SEND,263 * all bytes have been sent (UDP) or acknowledged (TCP).264 *265 * 2) For an RX transfer, it can exist only one client thread for a given socket,266 * but the transfer is initiated by the remote process, and the RECV command267 * is not really blocking: the data can arrive before the local RECV command is268 * executed, and the server thread does not wait to receive all requested data269 * to deliver data to client thread. Therefore each socket contains a receive270 * buffer (rx_buf) handled as a single-writer/single-reader fifo.271 * The client thread consumes data from the rx_buf when possible. It blocks on the272 * BLOCKED_IO condition and deschedules when the rx_buf is empty.273 * It is unblocked by the RX server thread when new data is available in the rx_buf.274 * The RX server blocks itself on the BLOCKED_ISR condition When the NIC_RX packets275 * queue is empty. It is unblocked by the hardware when new packets are available.276 *277 * Note : the socket domains and types are defined in the "shared_socket.h" file.278 ****************************************************************************************/279 280 /******************************************************************************************281 * This function returns a printable string for a given NIC command <type>.282 ******************************************************************************************283 * @ type : NIC command type284 *****************************************************************************************/285 char * nic_cmd_str( uint32_t type );286 287 /******************************************************************************************288 * This function returns a printable string for a given socket <state>.289 ******************************************************************************************290 * @ state : socket state291 *****************************************************************************************/292 char * socket_state_str( uint32_t state );293 223 294 224 /****************************************************************************************** … … 299 229 * device and the specific data structures when required. 300 230 * It creates the associated server thread and allocates a WTI from local ICU. 301 * For a TX_NIC chedv, it allocates and initializes the R2T waiting queue used by the 302 * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server. 231 * For a TX_NIC chedv, it allocates and initializes the R2T queue used by the 232 * NIC_RX[channel] server to send direct requests to the NIC_TX[channel] server, 233 * and the CRQ queue used to register connection requests. 303 234 * It must de executed by a local thread. 235 * For NIC_TX and NIC_RX chdevs, the "wait_root" field is actually a list of sockets. 304 236 ****************************************************************************************** 305 237 * @ chdev : local pointer on NIC chdev descriptor. … … 307 239 void dev_nic_init( struct chdev_s * chdev ); 308 240 309 310 /* functions implementing the socket API */ 311 312 /**************************************************************************************** 313 * This function implements the socket() syscall. 314 * This function allocates and intializes in the calling thread cluster: 315 * - a new socket descriptor, defined by the <domain> and <type> arguments, 316 * - a new file descriptor, associated to this socket, 317 * It registers the file descriptor in the reference process fd_array[], set 318 * the socket state to IDLE, and returns the <fdid> value. 319 **************************************************************************************** 320 * @ domain : [in] socket protocol family (AF_UNIX / AF_INET) 321 * @ type : [in] socket type (SOCK_DGRAM / SOCK_STREAM). 322 * @ return a file descriptor <fdid> if success / return -1 if failure. 323 ***************************************************************************************/ 324 int dev_nic_socket( uint32_t domain, 325 uint32_t type ); 326 327 /**************************************************************************************** 328 * This function implements the bind() syscall. 329 * It initializes the "local_addr" and "local_port" fields in the socket 330 * descriptor identified by the <fdid> argument and set the socket state to BOUND. 331 * It can be called by a thread running in any cluster. 332 **************************************************************************************** 333 * @ fdid : [in] file descriptor identifying the socket. 334 * @ addr : [in] local IP address. 335 * @ port : [in] local port. 336 * @ return 0 if success / return -1 if failure. 337 ***************************************************************************************/ 338 int dev_nic_bind( uint32_t fdid, 339 uint32_t addr, 340 uint16_t port ); 341 342 /**************************************************************************************** 343 * This function implements the listen() syscall(). 344 * It is called by a (local) server process to specify the max size of the queue 345 * registering the (remote) client process connections, and set the socket identified 346 * by the <fdid> argument to LISTEN state. It applies only to sockets of type TCP. 347 * It can be called by a thread running in any cluster. 348 * TODO handle the <max_pending> argument... 349 **************************************************************************************** 350 * @ fdid : [in] file descriptor identifying the local server socket. 351 * @ max_pending : [in] max number of accepted remote client connections. 352 ***************************************************************************************/ 353 int dev_nic_listen( uint32_t fdid, 354 uint32_t max_pending ); 355 356 /**************************************************************************************** 357 * This function implements the connect() syscall. 358 * It is used by a (local) client process to connect a local socket identified by 359 * the <fdid> argument, to a remote socket identified by the <remote_addr> and 360 * <remote_port> arguments. It can be used for both UDP and TCP sockets. 361 * It computes the nic_channel index from <remote_addr> and <remote_port> values, 362 * and initializes "remote_addr","remote_port", "nic_channel" in local socket. 363 * It registers the socket in the two lists of clients rooted in the NIC_RX[channel] 364 * and NIC_TX[channel] chdevs. It can be called by a thread running in any cluster. 365 * WARNING : the clients are the socket descriptors, and NOT the threads descriptors. 366 **************************************************************************************** 367 * Implementation Note: 368 * - For a TCP socket, it updates the "remote_addr", "remote_port", "nic_channel" fields 369 * in the socket descriptor defined by the <fdid> argument, and register this socket, 370 * in the lists of sockets attached to the NIC_TX and NIC_RX chdevs. 371 * Then, it registers a CONNECT command in the "nic_cmd" field ot the client thread 372 * descriptor to request the NIC_TX server thread to execute the 3 steps handshake, 373 * and updates the "tx_client" field in the socket descriptor. It unblocks the NIC_TX 374 * server thread, blocks on the THREAD_BLOCKED_IO condition and deschedules. 375 * - For an UDP socket, it simply updates "remote_addr", "remote_port", "nic_channel" 376 * in the socket descriptor defined by the <fdid> argument, and register this socket, 377 * in the lists of sockets attached to the NIC_TX and NIC_RX chdevs. 378 * Then, it set the socket state to CONNECT, without unblocking the NIC_TX server 379 * thread, and without blocking itself. 380 * TODO : the nic_channel index computation must be done by a driver specific function. 381 **************************************************************************************** 382 * @ fdid : [in] file descriptor identifying the socket. 383 * @ remote_addr : [in] remote IP address. 384 * @ remote_port : [in] remote port. 385 * @ return 0 if success / return -1 if failure. 386 ***************************************************************************************/ 387 int dev_nic_connect( uint32_t fdid, 388 uint32_t remote_addr, 389 uint16_t remote_port ); 390 391 /**************************************************************************************** 392 * This function implements the accept() syscall(). 393 * It is executed by a server process, waiting for one (or several) client process(es) 394 * requesting a connection on a socket identified by the <fdid> argument. 395 * This socket was previouly created with socket(), bound to a local address with bind(), 396 * and is listening for connections after a listen(). 397 * This function extracts the first connection request on the CRQQ queue of pending 398 * requests, creates a new socket with the same properties as the existing socket, 399 * and allocates a new file descriptor for this new socket. 400 * If no pending connections are present on the queue, it blocks the caller until a 401 * connection is present. 402 * The new socket cannot accept more connections, but the original socket remains open. 403 * It returns the new socket <fdid>, and register in the <address> an <port> arguments 404 * the remote client IP address & port. It applies only to sockets of type SOCK_STREAM. 405 **************************************************************************************** 406 * @ fdid : [in] file descriptor identifying the listening socket. 407 * @ address : [out] server IP address. 408 * @ port : [out] server port address length in bytes. 409 * @ return the new socket <fdid> if success / return -1 if failure 410 ***************************************************************************************/ 411 int dev_nic_accept( uint32_t fdid, 412 uint32_t * address, 413 uint16_t * port ); 414 415 /**************************************************************************************** 416 * This blocking function implements the send() syscall. 417 * It is used to send data stored in the user buffer, identified the <u_buf> and <length> 418 * arguments, to a connected (TCP or UDP) socket, identified by the <fdid> argument. 419 * The work is actually done by the NIC_TX server thread, and the synchronisation 420 * between the client and the server threads uses the "rx_valid" set/reset flip-flop: 421 * The client thread registers itself in the socket descriptor, registers in the queue 422 * rooted in the NIC_TX[index] chdev, set "rx_valid", unblocks the server thread, and 423 * finally blocks on THREAD_BLOCKED_IO, and deschedules. 424 * When the TX server thread completes the command (all data has been sent for an UDP 425 * socket, or acknowledeged for a TCP socket), the server thread reset "rx_valid" and 426 * unblocks the client thread. 427 * This function can be called by a thread running in any cluster. 428 * WARNING : This implementation does not support several concurent SEND/SENDTO commands 429 * on the same socket, as only one TX thread can register in a given socket. 430 **************************************************************************************** 431 * @ fdid : [in] file descriptor identifying the socket. 432 * @ u_buf : [in] pointer on buffer containing packet in user space. 433 * @ length : [in] packet size in bytes. 434 * @ return number of sent bytes if success / return -1 if failure. 435 ***************************************************************************************/ 436 int dev_nic_send( uint32_t fdid, 437 uint8_t * u_buf, 438 uint32_t length ); 439 440 /**************************************************************************************** 441 * This blocking function implements the sendto() syscall. 442 * It registers the <remote_addr> and <remote_port> arguments in the local socket 443 * descriptor, and does the same thing as the dev_nic_send() function above, 444 * but can be called on an unconnected UDP socket. 445 **************************************************************************************** 446 * @ fdid : [in] file descriptor identifying the socket. 447 * @ u_buf : [in] pointer on buffer containing packet in user space. 448 * @ length : [in] packet size in bytes. 449 * @ remote_addr : [in] destination IP address. 450 * @ remote_port : [in] destination port. 451 * @ return number of sent bytes if success / return -1 if failure. 452 ***************************************************************************************/ 453 int dev_nic_sendto( uint32_t fdid, 454 uint8_t * u_buf, 455 uint32_t length, 456 uint32_t remote_addr, 457 uint32_t remote_port ); 458 459 /**************************************************************************************** 460 * This blocking function implements the recv() syscall. 461 * It is used to receive data that has been stored by the NIC_RX server thread in the 462 * rx_buf of a connected (TCP or UDP) socket, identified by the <fdid> argument. 463 * The synchronisation between the client and the server threads uses the "rx_valid" 464 * set/reset flip-flop: If "rx_valid" is set, the client simply moves the available 465 * data from the "rx_buf" to the user buffer identified by the <u_buf> and <length> 466 * arguments, and reset the "rx_valid" flip_flop. If "rx_valid" is not set, the client 467 * thread register itself in the socket descriptor, registers in the clients queue rooted 468 * in the NIC_RX[index] chdev, and finally blocks on THREAD_BLOCKED_IO, and deschedules. 469 * The client thread is re-activated by the RX server, that set the "rx_valid" flip-flop 470 * as soon as data is available in the "rcv_buf" (can be less than the user buffer size). 471 * This function can be called by a thread running in any cluster. 472 * WARNING : This implementation does not support several concurent RECV/RECVFROM 473 * commands on the same socket, as only one RX thread can register in a given socket. 474 **************************************************************************************** 475 * @ fdid : [in] file descriptor identifying the socket. 476 * @ u_buf : [in] pointer on buffer in user space. 477 * @ length : [in] buffer size in bytes. 478 * @ return number of received bytes if success / return -1 if failure. 479 ***************************************************************************************/ 480 int dev_nic_recv( uint32_t fdid, 481 uint8_t * u_buf, 482 uint32_t length ); 483 484 /**************************************************************************************** 485 * This blocking function implements the recvfrom() syscall. 486 * It registers the <remote_addr> and <remote_port> arguments in the local socket 487 * descriptor, and does the same thing as the dev_nic_recv() function above, 488 * but can be called on an unconnected UDP socket. 489 **************************************************************************************** 490 * @ fdid : [in] file descriptor identifying the socket. 491 * @ u_buf : [in] pointer on buffer containing packet in user space. 492 * @ length : [in] packet size in bytes. 493 * @ remote_addr : [in] destination IP address. 494 * @ remote_port : [in] destination port. 495 * @ return number of received bytes if success / return -1 if failure. 496 ***************************************************************************************/ 497 int dev_nic_recvfrom( uint32_t fdid, 498 uint8_t * u_buf, 499 uint32_t length, 500 uint32_t remote_addr, 501 uint32_t remote_port ); 502 503 504 /* Instrumentation functions */ 505 241 /* Functions directly called by a client thread in any cluster */ 242 243 /****************************************************************************************** 244 * This function compute a channel index in range [0,nic_channels[ from the remote IP 245 * address <addr> and <port>, by calling the relevant driver command. 246 ****************************************************************************************** 247 * @ addr : [in] IP address. 248 * @ port : [in] TCP/UDP port. 249 * @ return the selected channel index 250 *****************************************************************************************/ 251 uint32_t dev_nic_get_key( uint32_t addr, 252 uint16_t port ); 253 254 /****************************************************************************************** 255 * This function activate / de-activate a NIC channel DMA engine identified by the 256 * <channel> argument, as defined by the <run> argument. 257 ****************************************************************************************** 258 * @ channel : [in] NIC channel index. 259 * @ run : [in] activate if non-zero / desactivate if zero. 260 * @ return 0 if success / return -1 if error. 261 *****************************************************************************************/ 262 error_t dev_nic_set_run( uint32_t channel, 263 uint32_t run ); 506 264 507 265 /****************************************************************************************** 508 266 * This instrumentation function displays on the TXT0 kernel terminal the content 509 267 * of the instrumentation registers contained in the NIC device. 510 *****************************************************************************************/ 511 void dev_nic_print_stats( void ); 268 ****************************************************************************************** 269 * @ return 0 if success / return -1 if error. 270 *****************************************************************************************/ 271 error_t dev_nic_get_instru( void ); 512 272 513 273 /****************************************************************************************** 514 274 * This instrumentation function reset all instrumentation registers contained 515 275 * in the NIC device. 516 *****************************************************************************************/ 517 void dev_nic_clear_stats( void ); 518 276 ****************************************************************************************** 277 * @ return 0 if success / return -1 if error. 278 *****************************************************************************************/ 279 error_t dev_nic_clear_instru( void ); 519 280 520 281 /* Functions executed by the TX and RX server threads */ … … 532 293 * When the TX client threads queue is empty, it blocks on THREAD_BLOCKED_CLIENT 533 294 * condition and deschedules. It is re-activated by a client thread registering a command. 295 * When the NIC_TX packet queue is full, it blocks on the THREAD_BLOCKED_ISR condition 296 * and deschedules. It is reactivated by the NIC_TX DMA engine. 534 297 ****************************************************************************************** 535 298 * Implementation note: … … 556 319 * requests to the TX server, using the R2T queue attached to the involved socket. 557 320 * It blocks on the THREAD_BLOCKED_ISR condition and deschedules when the NIC_RX_QUEUE 558 * is empty . Itis re-activated by the NIC_RX_ISR, when the queue becomes non empty.321 * is empty, and is re-activated by the NIC_RX_ISR, when the queue becomes non empty. 559 322 ****************************************************************************************** 560 323 * Implementation note: … … 570 333 void dev_nic_rx_server( struct chdev_s * chdev ); 571 334 335 /****************************************************************************************** 336 * This function displays all the fields of an ETH/IP/TCP segment or ETH/IP/UDP packet. 337 ****************************************************************************************** 338 * @ is_tx : [in] sent packet if true / received packet if false. 339 * @ pid : [in] process identifier. 340 * @ trdid : [in] thread identifier. 341 * @ cycle : [in] date (number of cycles). 342 * @ buf : [in] local pointer on kernel buffer containing the packet. 343 *****************************************************************************************/ 344 void dev_nic_packet_display( bool_t is_tx, 345 pid_t pid, 346 trdid_t trdid, 347 uint32_t cycle, 348 uint8_t * buf ); 349 572 350 #endif /* _DEV_NIC_H */ -
trunk/kernel/devices/dev_txt.c
r657 r663 74 74 bool_t is_rx = txt->is_rx; 75 75 76 77 76 assert( (pic_xp != XPTR_NULL) || (channel == 0) , 77 "PIC not initialised before TXT" ); 78 78 79 79 // set chdev name
Note: See TracChangeset
for help on using the changeset viewer.