Changeset 657 for trunk/kernel/devices/dev_nic.c
- Timestamp:
- Mar 18, 2020, 11:16:59 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/devices/dev_nic.c
r647 r657 2 2 * dev_nic.c - NIC (Network Controler) generic device API implementation. 3 3 * 4 * Author Alain Greiner (2016,2017,2018,2019 )4 * Author Alain Greiner (2016,2017,2018,2019,2020) 5 5 * 6 6 * Copyright (c) UPMC Sorbonne Universites … … 24 24 #include <hal_kernel_types.h> 25 25 #include <hal_special.h> 26 #include <hal_uspace.h> 27 #include <remote_buf.h> 26 28 #include <printk.h> 27 29 #include <chdev.h> 28 30 #include <thread.h> 31 #include <socket.h> 29 32 #include <hal_drivers.h> 30 33 #include <dev_nic.h> 34 #include <vfs.h> 35 #include <shared_socket.h> 31 36 32 37 ///////////////////////////////////////////////////////////////////////////////////////// 33 // Extern global variables38 // Extern global variables 34 39 ///////////////////////////////////////////////////////////////////////////////////////// 35 40 36 41 extern chdev_directory_t chdev_dir; // allocated in kernel_init.c 42 43 //////////////////////////////////////////////////////////////////////////////////////////// 44 // This static function is used by the dev_nic_rx_handle_tcp() & dev_nic_tx_handle_tcp() 45 // functions to check acceptability of a given sequence number. It returns true when 46 // the <seq> argument is contained in a wrap-around window defined by the <min> and <max> 47 // arguments. The window wrap-around when (min > max). 48 //////////////////////////////////////////////////////////////////////////////////////////// 49 // @ seq : [in] value to be checked. 50 // @ min : [in] first base. 51 // @ max : [in] window size. 52 //////////////////////////////////////////////////////////////////////////////////////////// 53 static inline bool_t is_in_window( uint32_t seq, 54 uint32_t min, 55 uint32_t max ) 56 { 57 if( max >= min ) // no wrap_around => only one window [min,max] 58 { 59 return( (seq >= min) && (seq <= max) ); 60 } 61 else // window wrap-around => two windows [min,0xFFFFFFFF] and [0,max] 62 { 63 return( (seq <= max) || (seq >= min) ); 64 } 65 } 66 67 //////////////////////////////////////////////////////////////////////////////////////////// 68 // this static function compute a channel index in range [0,nic_channelx[ from 69 // a remote IP address and remote port. 70 // TODO this function should be provided by the NIC driver. 71 //////////////////////////////////////////////////////////////////////////////////////////// 72 // @ addr : [in] IP address. 73 // @ port : [in] TCP/UDP port. 74 //////////////////////////////////////////////////////////////////////////////////////////// 75 static inline uint32_t dev_nic_channel_index( uint32_t addr, 76 uint16_t port ) 77 { 78 // get number of NIC channels 79 uint32_t nic_channels = LOCAL_CLUSTER->nb_nic_channels; 80 81 // compute NIC channel index 82 return ( ((addr ) & 0xFF) ^ 83 ((addr > 8 ) & 0xFF) ^ 84 ((addr > 16) & 0xFF) ^ 85 ((addr > 24) & 0xFF) ^ 86 ((port ) & 0xFF) ^ 87 ((port > 8 ) & 0xFF) ) % nic_channels; 88 } 89 90 //////////////////////////////////////////////////////////////////////////////////////// 91 // This static function computes the checksum for an IP packet header. 92 // The "checksum" field itself is not taken into account for this computation. 93 //////////////////////////////////////////////////////////////////////////////////////// 94 // @ buffer : [in] pointer on IP packet header (20 bytes) 95 // @ return the checksum value on 16 bits 96 //////////////////////////////////////////////////////////////////////////////////////// 97 uint16_t dev_nic_ip_checksum( uint8_t * buffer ) 98 { 99 uint32_t i; 100 uint32_t cs; // 32 bits accumulator 101 uint16_t * buf; 102 103 buf = (uint16_t *)buffer; 104 105 // compute checksum 106 for( i = 0 , cs = 0 ; i < 10 ; i++ ) 107 { 108 if( i != 5 ) cs += buf[i]; 109 } 110 111 // one's complement 112 return ~cs; 113 } 114 115 //////////////////////////////////////////////////////////////////////////////////////// 116 // This static function computes the checksum for an UDP packet defined by 117 // the <buffer> and <size> arguments. 118 //////////////////////////////////////////////////////////////////////////////////////// 119 // @ buffer : [in] pointer on UDP packet base. 120 // @ size : [in] number of bytes in this packet (including header). 121 // @ return the checksum value on 16 bits 122 //////////////////////////////////////////////////////////////////////////////////////// 123 uint16_t dev_nic_udp_checksum( uint8_t * buffer, 124 uint32_t size ) 125 { 126 uint32_t i; 127 uint32_t carry; 128 uint32_t cs; // 32 bits accumulator 129 uint16_t * buf; 130 uint32_t max; // number of uint16_t in packet 131 132 // compute max & buf 133 buf = (uint16_t *)buffer; 134 max = size >> 1; 135 136 // extend buffer[] if required 137 if( size & 1 ) 138 { 139 max++; 140 buffer[size] = 0; 141 } 142 143 // compute checksum for UDP packet 144 for( i = 0 , cs = 0 ; i < size ; i++ ) cs += buf[i]; 145 146 // handle carry 147 carry = (cs >> 16); 148 if( carry ) 149 { 150 cs += carry; 151 carry = (cs >> 16); 152 if( carry ) cs += carry; 153 } 154 155 // one's complement 156 return ~cs; 157 } 158 159 //////////////////////////////////////////////////////////////////////////////////////// 160 // This static function computes the checksum for a TCP segment defined by 161 // the <buffer> and <size> arguments. 162 // It includes the pseudo header defined by the <src_ip_addr>, <dst_ip_addr>, 163 // <size> arguments, and by the TCP_PROTOCOL code. 164 //////////////////////////////////////////////////////////////////////////////////////// 165 // @ buffer : [in] pointer on TCP segment base. 166 // @ size : [in] number of bytes in this segment (including header). 167 // @ src_ip_addr : [in] source IP address (pseudo header) 168 // @ dst_ip_addr : [in] destination IP address (pseudo header) 169 // @ return the checksum value on 16 bits 170 //////////////////////////////////////////////////////////////////////////////////////// 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 ) 175 { 176 uint32_t i; 177 uint32_t carry; 178 uint32_t cs; // 32 bits accumulator 179 uint16_t * buf; 180 uint32_t max; // number of uint16_t in segment 181 182 // compute max & buf 183 buf = (uint16_t *)buffer; 184 max = size >> 1; 185 186 // extend buffer[] if required 187 if( size & 1 ) 188 { 189 max++; 190 buffer[size] = 0; 191 } 192 193 // compute checksum for TCP segment 194 for( i = 0 , cs = 0 ; i < size ; i++ ) cs += buf[i]; 195 196 // complete checksum for pseudo-header 197 cs += src_ip_addr; 198 cs += dst_ip_addr; 199 cs += PROTOCOL_TCP; 200 cs += size; 201 202 // handle carry 203 carry = (cs >> 16); 204 if( carry ) 205 { 206 cs += carry; 207 carry = (cs >> 16); 208 if( carry ) cs += carry; 209 } 210 211 // one's complement 212 return ~cs; 213 } 37 214 38 215 ////////////////////////////////// … … 80 257 } // end dev_nic_init() 81 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 ) 267 { 268 uint32_t fdid; 269 socket_t * socket; 270 error_t error; 271 272 // allocate memory for the file descriptor and for the socket 273 error = socket_create( local_cxy, 274 domain, 275 type, 276 &socket, // unused here 277 &fdid ); 278 279 if( error ) return -1; 280 return fdid; 281 } 282 283 //////////////////////////////// 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 ) 302 { 303 printk("\n[ERROR] in %s : undefined fdid %d", 304 __FUNCTION__, fdid ); 305 return -1; 306 } 307 308 type = hal_remote_l32( XPTR( file_cxy , &file_ptr->type ) ); 309 socket = hal_remote_lpt( XPTR( file_cxy , &file_ptr->socket ) ); 310 311 // check file descriptor type 312 if( type != INODE_TYPE_SOCK ) 313 { 314 printk("\n[ERROR] in %s : illegal file type %s", 315 __FUNCTION__, vfs_inode_type_str( type ) ); 316 return -1; 317 } 318 319 state = (type == SOCK_STREAM) ? TCP_STATE_BOUND : UDP_STATE_BOUND; 320 321 // update the socket descriptor 322 hal_remote_s32( XPTR( file_cxy , &socket->local_addr ) , addr ); 323 hal_remote_s32( XPTR( file_cxy , &socket->local_port ) , port ); 324 hal_remote_s32( XPTR( file_cxy , &socket->state ) , state ); 325 326 return 0; 327 328 } // end dev_nic_bind() 329 330 ////////////////////////////////// 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 82 402 /////////////////////////////////// 83 error_t dev_nic_read( pkd_t * pkd ) 84 { 85 error_t error; 86 87 // get pointers on this NIC-RX kernel thread 88 thread_t * thread_ptr = CURRENT_THREAD; 89 xptr_t thread_xp = XPTR( local_cxy , thread_ptr ); 90 91 // get local pointer on core running this kernel thead 92 core_t * core = thread_ptr->core; 93 94 // check thread can yield 95 assert( (thread_ptr->busylocks == 0), 96 "cannot yield : busylocks = %d\n", thread_ptr->busylocks ); 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 1076 1077 1078 1079 /////////////////////////////////////////////////////////////////////////////////////////// 1080 // Functions called by the NIC_RX server thread 1081 /////////////////////////////////////////////////////////////////////////////////////////// 1082 1083 ///////////////////////////////////////////////////////////////////////////////////////// 1084 // This static function is called by the NIC_RX[channel] server thread to register 1085 // a send request defined by the <flags> argument in the R2T queue specified by 1086 // the <queue_xp> argument. 1087 ///////////////////////////////////////////////////////////////////////////////////////// 1088 // @ queue_xp : [in] extended pointer on the R2T qeue descriptor. 1089 // @ flags : [in] flags to be set in the TCP segment. 1090 ///////////////////////////////////////////////////////////////////////////////////////// 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 status 1109 // of the NIC_RX queue identified by the <chdev> argument. 1110 // in the <readable> buffer. 1111 /////////////////////////////////////////////////////////////////////////////////////////// 1112 // @ chdev : [in] local pointer on NIC_TX chdev. 1113 // @ readable : [out] zero if queue empty. 1114 // @ returns 0 if success / returns -1 if failure in accessing NIC device. 1115 /////////////////////////////////////////////////////////////////////////////////////////// 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 descriptor 1122 this->nic_cmd.dev_xp = XPTR( local_cxy , chdev ); 1123 this->nic_cmd.type = NIC_CMD_READABLE; 1124 1125 // call driver to test readable 1126 chdev->cmd( XPTR( local_cxy , this ) ); 1127 1128 // return status 1129 *readable = this->nic_cmd.status; 1130 1131 // return error 1132 return this->nic_cmd.error; 1133 } 1134 1135 /////////////////////////////////////////////////////////////////////////////////////////// 1136 // This static function is called by the dev_nic_rx_server() function. 1137 // It moves one Ethernet packet from the NIC_RX_QUEUE identified the <chdev> argument, 1138 // to the 2K bytes kernel buffer identified by the <buffer> argument. The actual 1139 // Ethernet packet length is returned in the <length> argument. 1140 // It calls directly the NIC driver with the READ command, without registering in the 1141 // waiting queue, because only the NIC_RX server thread can access this NIC_RX_QUEUE. 1142 /////////////////////////////////////////////////////////////////////////////////////////// 1143 // @ chdev : [in] local pointer on NIC_TX chdev. 1144 // @ buffer : [in] local pointer on destination kernel buffer. 1145 // @ length : [out] Ethernet packet size in bytes. 1146 // @ returns 0 if success / returns -1 if failure in accessing NIC device. 1147 /////////////////////////////////////////////////////////////////////////////////////////// 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; 97 1153 98 1154 #if DEBUG_DEV_NIC_RX 99 1155 uint32_t cycle = (uint32_t)hal_get_cycles(); 100 1156 if( DEBUG_DEV_NIC_RX < cycle ) 101 printk("\n[ DBG] %s : thread %x enters for packet %x in cluster %x\n",102 __FUNCTION__ , thread_ptr , pkd , local_cxy);1157 printk("\n[%s] thread[%x,%x] enters / cycle %d\n", 1158 __FUNCTION__, this->process->pid, this->trdid, cycle ); 103 1159 #endif 104 1160 105 // get pointer on NIC-RX chdev descriptor 106 uint32_t channel = thread_ptr->chdev->channel; 107 xptr_t dev_xp = chdev_dir.nic_rx[channel]; 108 cxy_t dev_cxy = GET_CXY( dev_xp ); 109 chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp ); 110 111 assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" ); 112 113 assert( (dev_cxy == local_cxy) , " chdev must be local" ); 114 115 // initialize command in thread descriptor 116 thread_ptr->nic_cmd.dev_xp = dev_xp; 117 118 // call driver to test readable 119 thread_ptr->nic_cmd.cmd = NIC_CMD_READABLE; 120 dev_ptr->cmd( thread_xp ); 1161 // initialize NIC_READ command in thread descriptor 1162 this->nic_cmd.type = NIC_CMD_READ; 1163 this->nic_cmd.buffer = k_buf; 1164 1165 // call NIC driver 1166 chdev->cmd( XPTR( local_cxy , this ) ); 1167 1168 // returns packet length 1169 *length = this->nic_cmd.length; 121 1170 122 1171 // check error 123 error = thread_ptr->nic_cmd.error; 124 if( error ) return error; 125 126 // block and deschedule if queue non readable 127 if( thread_ptr->nic_cmd.status == false ) 128 { 129 // enable NIC-RX IRQ 130 dev_pic_enable_irq( core->lid , dev_xp ); 131 132 // block client thread on THREAD_BLOCKED_IO 133 thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO ); 134 135 // deschedule client thread 136 sched_yield("client blocked on I/O"); 137 138 // disable NIC-RX IRQ 139 dev_pic_disable_irq( core->lid , dev_xp ); 140 } 141 142 // call driver for actual read 143 thread_ptr->nic_cmd.cmd = NIC_CMD_READ; 144 thread_ptr->nic_cmd.buffer = pkd->buffer; 145 dev_ptr->cmd( thread_xp ); 146 147 // check error 148 error = thread_ptr->nic_cmd.error; 149 if( error ) return error; 150 151 // returns packet length 152 pkd->length = thread_ptr->nic_cmd.length; 1172 if( this->nic_cmd.error ) 1173 { 153 1174 154 1175 #if DEBUG_DEV_NIC_RX 155 1176 cycle = (uint32_t)hal_get_cycles(); 156 1177 if( DEBUG_DEV_NIC_RX < cycle ) 157 printk("\n[ DBG] %s : thread %x exit for packet %x in cluster %x\n",158 __FUNCTION__ , thread_ptr , pkd , local_cxy);1178 printk("\n[%s] thread[%x,%x] exit / ERROR in NIC_RX / cycle %d\n", 1179 __FUNCTION__, this->process->pid, this->trdid, cycle ); 159 1180 #endif 160 1181 1182 return -1; 1183 } 1184 else 1185 { 1186 1187 #if DEBUG_DEV_NIC_RX 1188 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 #endif 1193 1194 return 0; 1195 } 1196 1197 } // end dev_nic_rx_move_packet() 1198 1199 /////////////////////////////////////////////////////////////////////////////////////////// 1200 // This static function is called by the dev_nic_rx_server() function. 1201 // It analyses an Ethernet frame contained in the kernel buffer defined 1202 // by the <buffer> argument, and returns in the <ip_length> argument the length 1203 // of the IP packet contained in the Ethernet packet payload. 1204 /////////////////////////////////////////////////////////////////////////////////////////// 1205 // @ buffer : [in] pointer on a received Ethernet packet 1206 // @ ip_length : [out] length of IP packet (in bytes). 1207 // @ return 0 if success / return -1 if illegal packet length. 1208 /////////////////////////////////////////////////////////////////////////////////////////// 1209 static error_t dev_nic_rx_check_eth( uint8_t * buffer, 1210 uint32_t * ip_length ) 1211 { 1212 uint32_t length = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13]; 1213 1214 *ip_length = length; 1215 161 1216 return 0; 162 163 } // end dev_nic_read() 164 165 166 //////////////////////////////////// 167 error_t dev_nic_write( pkd_t * pkd ) 168 { 169 error_t error; 170 171 // get pointers on the NIC-TX kernel tread 172 thread_t * thread_ptr = CURRENT_THREAD; 173 xptr_t thread_xp = XPTR( local_cxy , thread_ptr ); 174 175 // get local pointer on core running this kernel thead 176 core_t * core = thread_ptr->core; 1217 } 1218 1219 /////////////////////////////////////////////////////////////////////////////////////////// 1220 // This static function analyses the IP packet contained in the kernel buffer 1221 // defined by the <buffer> argument, and returns in the <ip_src_addr>, <ip_dst_addr>, 1222 // <header_length> and <protocol> arguments the informations contained in the IP header. 1223 // It checks the IP packet length versus the value contained in Ethernet header. 1224 // It checks the IP header checksum. 1225 /////////////////////////////////////////////////////////////////////////////////////////// 1226 // @ buffer : [in] pointer on the IP packet. 1227 // @ expected_length : [in] expected IP packet length (from Ethernet header). 1228 // @ ip_src_addr : [out] source IP address. 1229 // @ ip_dst_addr : [out] destination IP address. 1230 // @ protocol : [out] transport protocol type. 1231 // @ return 0 if success / return -1 if illegal packet. 1232 /////////////////////////////////////////////////////////////////////////////////////////// 1233 static error_t dev_nic_rx_check_ip( uint8_t * buffer, 1234 uint32_t expected_length, 1235 uint32_t * ip_src_addr, 1236 uint32_t * ip_dst_addr, 1237 uint32_t * trsp_protocol ) 1238 { 1239 uint32_t length = ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3]; 1240 1241 // discard packet if eth_length != ip_length 1242 if( length != expected_length ) 1243 { 1244 1245 #if DEBUG_NIC_DEV 1246 thread_t * this = CURRENT_THREAD; 1247 printk("\n[%s] thread[%x,%x] enters : length (%d) != expected_length (%d)\n", 1248 __FUNCTION__, this->process->pid, this->trdid, length, expected_length ); 1249 #endif 1250 1251 return -1; 1252 } 1253 1254 // compute IP header checksum 1255 uint32_t received_cs = (uint32_t)dev_nic_ip_checksum( buffer ); 1256 1257 // extract IP header checksum 1258 uint32_t computed_cs = ((uint32_t)buffer[10] << 8) | ((uint32_t)buffer[11]); 1259 1260 // discard packet if bad checksum 1261 if( received_cs != computed_cs ) 1262 { 1263 1264 #if DEBUG_NIC_DEV 1265 thread_t * this = CURRENT_THREAD; 1266 printk("\n[%s] thread[%x,%x] computed checksum (%d) != received checksum (%d)\n", 1267 __FUNCTION__, this->process->pid, this->trdid, computed_cs, received_cs ); 1268 #endif 1269 1270 return -1; 1271 } 1272 1273 1274 *ip_src_addr = ((uint32_t)buffer[12] << 24) | 1275 ((uint32_t)buffer[13] << 16) | 1276 ((uint32_t)buffer[14] << 8) | 1277 ((uint32_t)buffer[15] ) ; 1278 1279 *ip_dst_addr = ((uint32_t)buffer[16] << 24) | 1280 ((uint32_t)buffer[17] << 16) | 1281 ((uint32_t)buffer[18] << 8) | 1282 ((uint32_t)buffer[19] ) ; 1283 1284 *trsp_protocol = (uint32_t)buffer[9]; 1285 1286 return 0; 1287 } 1288 1289 /////////////////////////////////////////////////////////////////////////////////////////// 1290 // This static function analyses the UDP packet contained in the kernel buffer 1291 // defined by the <k_buf> and <k_length> arguments. 1292 // It checks the UDP checksum, and discard corrupted packets. 1293 // It scans the list of sockets attached to the NIC_RX chdev to find a matching socket, 1294 // and discard the received packet if no UDP socket found. 1295 // Finally, it copies the payload to the socket "rx_buf", as long as the packet payload 1296 // is not larger than the rx_buf. 1297 // It set the "rx_valid" flip-flop, and unblock the client thread when the last expected 1298 // byte has been received. 1299 /////////////////////////////////////////////////////////////////////////////////////////// 1300 // @ chdev : [in] local pointer on local NIC_RX chdev descriptor. 1301 // @ k_buf : [in] pointer on the UDP packet in local kernel buffer. 1302 // @ k_length : [in] number of bytes in buffer (including UDP header). 1303 // @ pkt_src_addr : [in] source IP address (from IP packet header). 1304 // @ pkt_dst_addr : [in] destination IP address (from IP packet header). 1305 /////////////////////////////////////////////////////////////////////////////////////////// 1306 static void dev_nic_rx_handle_udp_packet( chdev_t * chdev, 1307 uint8_t * k_buf, 1308 uint32_t k_length, 1309 uint32_t pkt_src_addr, 1310 uint32_t pkt_dst_addr ) 1311 { 1312 xptr_t root_xp; // extended pointer on attached sockets list root 1313 xptr_t lock_xp; // extended pointer on chdev lock 1314 xptr_t iter_xp; // iterator on socket list 1315 xptr_t socket_xp; // extended pointer on socket descriptor 1316 cxy_t socket_cxy; 1317 socket_t * socket_ptr; 1318 uint32_t socket_type; // socket type 1319 uint32_t socket_state; // socket state 1320 uint32_t local_addr; // local IP address from socket 1321 uint32_t local_port; // local port from socket 1322 uint32_t remote_addr; // remote IP address from socket 1323 uint32_t remote_port; // remote port from socket 1324 bool_t match_socket; // matching socket found 1325 uint16_t checksum; // computed checksum 1326 uint16_t pkt_checksum; // received checksum 1327 xptr_t socket_rbuf_xp; // extended pointer on socket rx_buf 1328 xptr_t socket_lock_xp; // extended pointer on socket lock 1329 xptr_t socket_client_xp; // extended pointer on socket rx_client field 1330 xptr_t client_xp; // extended pointer on client thread descriptor 1331 uint32_t payload; // number of bytes in payload 1332 uint32_t status; // number of bytes in rx_buf 1333 uint32_t space; // number of free slots in rx_buf 1334 uint32_t moved_bytes; // number of bytes actually moved to rx_buf 1335 1336 // build extended pointers on list of sockets attached to NIC_RX chdev 1337 root_xp = XPTR( local_cxy , &chdev->wait_root ); 1338 lock_xp = XPTR( local_cxy , &chdev->wait_lock ); 1339 1340 // compute UDP packet checksum 1341 checksum = dev_nic_udp_checksum( k_buf , k_length ); 1342 1343 // get checksum from received packet header 1344 pkt_checksum = ((uint16_t)k_buf[6] << 8) | (uint16_t)k_buf[7]; 1345 1346 // discard corrupted packet 1347 if( pkt_checksum != checksum ) return; 1348 1349 // get src_port and dst_port from UDP header 1350 uint32_t pkt_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1]; 1351 uint32_t pkt_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3]; 1352 1353 // discard unexpected packet 1354 if( xlist_is_empty( root_xp ) ) return; 1355 1356 // take the tock protecting the sockets list 1357 remote_busylock_acquire( lock_xp ); 1358 1359 match_socket = false; 1360 1361 // scan sockets list to find a match 1362 XLIST_FOREACH( root_xp , iter_xp ) 1363 { 1364 // get socket cluster and local pointer 1365 socket_xp = XLIST_ELEMENT( iter_xp , socket_t , rx_list ); 1366 socket_ptr = GET_PTR( socket_xp ); 1367 socket_cxy = GET_CXY( socket_xp ); 1368 1369 // get socket type 1370 socket_type = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type )); 1371 socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state )); 1372 1373 // skip TCP socket 1374 if( socket_type == SOCK_STREAM ) continue; 1375 1376 // get relevant info from socket descriptor 1377 local_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 1378 remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 1379 local_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 1380 remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 1381 1382 // compute matching 1383 bool_t local_match = (local_addr == pkt_dst_addr) && 1384 (local_port == pkt_dst_port); 1385 1386 bool_t remote_match = (remote_addr == pkt_src_addr) && 1387 (remote_port == pkt_src_port); 1388 1389 if (socket_state == UDP_STATE_CONNECT ) match_socket = local_match && remote_match; 1390 else match_socket = local_match; 1391 1392 // exit loop when socket found 1393 if( match_socket ) break; 1394 } 1395 1396 // release the lock protecting the sockets list 1397 remote_busylock_release( lock_xp ); 1398 1399 // discard unexpected packet 1400 if( match_socket == false ) return; 1401 1402 // build extended pointers on various socket fields 1403 socket_rbuf_xp = XPTR( socket_cxy , &socket_ptr->rx_buf ); 1404 socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock ); 1405 socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client ); 1406 1407 // take the lock protecting the socket 1408 remote_rwlock_wr_acquire( socket_lock_xp ); 1409 1410 // get status & space from rx_buf 1411 status = remote_buf_status( socket_rbuf_xp ); 1412 space = NIC_RX_BUF_SIZE - status; 1413 1414 // get client thread 1415 client_xp = hal_remote_l64( socket_client_xp ); 1416 1417 // get number of bytes in payload 1418 payload = k_length - UDP_HEAD_LEN; 1419 1420 // compute number of bytes to move : min (space , seg_payload) 1421 moved_bytes = ( space < payload ) ? space : payload; 1422 1423 // move payload from kernel buffer to socket rx_buf 1424 remote_buf_put_from_kernel( socket_rbuf_xp, 1425 k_buf + UDP_HEAD_LEN, 1426 moved_bytes ); 1427 1428 // unblock client thread if registered 1429 if( client_xp != XPTR_NULL ) 1430 { 1431 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 1432 } 1433 1434 // release the lock protecting the socket 1435 remote_rwlock_wr_release( socket_lock_xp ); 1436 1437 } // end dev_nic_rx_handle_udp_packet() 1438 1439 /////////////////////////////////////////////////////////////////////////////////////////// 1440 // This static function is called by the dev_nic_rx_server() function to handle one RX 1441 // TCP segment contained in a kernel buffer defined by the <k_buf> & <k_length> arguments. 1442 // It the received segment doesn't match an existing local socket, or is corrupted, 1443 // this faulty segment is discarded. 1444 /////////////////////////////////////////////////////////////////////////////////////////// 1445 // Implementation note: 1446 // 1) It checks the TCP checksum, and discard the corrupted segment. 1447 // 2) It scans the list of sockets attached to the RX chdev, to find the socket 1448 // matching the TCP segment header, and discards the segment if no socket found. 1449 // 3) When a socket has been found, it takes the lock protecting the socket state, 1450 // because the socket is accessed by both the NIC_TX and NIC_RX server threads. 1451 // 4) Depending on the socket state, it handle the received segment, including the 1452 // SYN, FIN, ACK and RST flags. It updates the socket state when required, moves 1453 // data to the rx_buf when possible, and registers requests to the TX server 1454 // thread in the R2T queue attached to the socket, to insert control flags in the 1455 // TX stream, as required. 1456 // 5) Finally, it releases the lock protecting the socke and returns. 1457 /////////////////////////////////////////////////////////////////////////////////////////// 1458 // @ chdev : [in] local pointer on local NIC_RX chdev descriptor. 1459 // @ k_buf : [in] pointer on the TCP packet in local kernel buffer. 1460 // @ k_length : [in] number of bytes in buffer (including TCP header). 1461 // @ seg_src_addr : [in] source IP address (from IP packet header). 1462 // @ seg_dst_addr : [in] destination IP address (from IP packet header). 1463 /////////////////////////////////////////////////////////////////////////////////////////// 1464 static void dev_nic_rx_handle_tcp_segment( chdev_t * chdev, 1465 uint8_t * k_buf, 1466 uint32_t k_length, 1467 uint32_t seg_src_addr, 1468 uint32_t seg_dst_addr ) 1469 { 1470 xptr_t root_xp; // extended pointer on attached sockets list root 1471 xptr_t lock_xp; // extended pointer on chdev lock 1472 xptr_t iter_xp; // iterator for these queues 1473 bool_t match_socket; // true if socket found 1474 xptr_t socket_xp; // extended pointer on matching socket descriptor 1475 cxy_t socket_cxy; 1476 socket_t * socket_ptr; 1477 uint32_t local_addr; // local IP address from socket 1478 uint32_t local_port; // local port from socket 1479 uint32_t remote_addr; // remote IP address from socket 1480 uint32_t remote_port; // remote port from socket 1481 uint32_t socket_state; // socket state 1482 uint32_t socket_type; // socket type 1483 uint32_t socket_tx_nxt; // next byte to send in TX stream 1484 uint32_t socket_tx_una; // first unacknowledged byte in TX stream 1485 uint32_t socket_rx_nxt; // next expected byte in RX stream 1486 uint32_t socket_rx_wnd; // current window value in RX stream 1487 xptr_t socket_lock_xp; // extended pointer on lock protecting socket state 1488 xptr_t socket_rx_buf_xp; // extended pointer on socket rx_buf 1489 xptr_t socket_r2tq_xp; // extended pointer on socket r2t queue 1490 xptr_t socket_client_xp; // extended pointer on socket rx_client thread 1491 uint16_t checksum; // computed TCP segment chechsum 1492 1493 // build extended pointer on xlist of all sockets attached to NIC_RX chdev 1494 root_xp = XPTR( local_cxy , &chdev->wait_root ); 1495 lock_xp = XPTR( local_cxy , &chdev->wait_lock ); 1496 1497 // get relevant infos from TCP segment header 1498 uint32_t seg_src_port = ((uint32_t)k_buf[0] << 8) | (uint32_t)k_buf[1]; 1499 uint32_t seg_dst_port = ((uint32_t)k_buf[2] << 8) | (uint32_t)k_buf[3]; 1500 1501 uint32_t seg_seq_num = ((uint32_t)k_buf[4] << 24) | 1502 ((uint32_t)k_buf[5] << 16) | 1503 ((uint32_t)k_buf[6] << 8) | 1504 ((uint32_t)k_buf[7] ); 1505 1506 uint32_t seg_ack_num = ((uint32_t)k_buf[8] << 24) | 1507 ((uint32_t)k_buf[9] << 16) | 1508 ((uint32_t)k_buf[10] << 8) | 1509 ((uint32_t)k_buf[11] ); 1510 1511 uint8_t seg_hlen = k_buf[12] >> 2; // TCP header length in bytes 1512 1513 uint8_t seg_flags = k_buf[13]; 1514 1515 bool_t seg_ack_set = ((seg_flags & TCP_FLAG_ACK) != 0); 1516 bool_t seg_syn_set = ((seg_flags & TCP_FLAG_SYN) != 0); 1517 bool_t seg_fin_set = ((seg_flags & TCP_FLAG_FIN) != 0); 1518 bool_t seg_rst_set = ((seg_flags & TCP_FLAG_RST) != 0); 1519 1520 uint16_t seg_window = ((uint32_t)k_buf[14] << 8) | (uint32_t)k_buf[15]; 1521 1522 uint16_t seg_checksum = ((uint32_t)k_buf[16] << 8) | (uint32_t)k_buf[17]; 1523 1524 uint32_t seg_payload = k_length - seg_hlen; // number of bytes in payload 1525 1526 // 1. compute TCP checksum 1527 checksum = dev_nic_tcp_checksum( k_buf, 1528 k_length, 1529 seg_src_addr, 1530 seg_dst_addr ); 1531 1532 // discard segment if corrupted 1533 if( seg_checksum != checksum ) return; 1534 1535 match_socket = false; 1536 1537 // take the lock protecting the list of sockets 1538 remote_busylock_acquire( lock_xp ); 1539 1540 // 2. scan list of sockets to find a matching socket 1541 XLIST_FOREACH( root_xp , iter_xp ) 1542 { 1543 // get socket cluster and local pointer 1544 socket_xp = XLIST_ELEMENT( iter_xp , socket_t , rx_list ); 1545 socket_ptr = GET_PTR( socket_xp ); 1546 socket_cxy = GET_CXY( socket_xp ); 1547 1548 // get socket type and state 1549 socket_type = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->type )); 1550 socket_state = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->state )); 1551 1552 // skip UDP socket 1553 if( socket_type == SOCK_DGRAM ) continue; 1554 1555 // get relevant socket infos for matching 1556 local_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 1557 remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 1558 local_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 1559 remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 1560 1561 // compute matching condition 1562 // (in LISTEN state, remote_port and remote_addr can be unspecified) 1563 if( socket_state == TCP_STATE_LISTEN ) 1564 { 1565 match_socket = (local_addr == seg_dst_addr) && 1566 (local_port == seg_dst_port) ; 1567 } 1568 else 1569 { 1570 match_socket = (local_addr == seg_dst_addr) && 1571 (local_port == seg_dst_port) && 1572 (remote_addr == seg_src_addr) && 1573 (remote_port == seg_src_port) ; 1574 } 1575 1576 // exit loop if matching 1577 if( match_socket ) break; 1578 1579 } // end loop on sockets 1580 1581 // release the lock protecting the list of sockets 1582 remote_busylock_release( lock_xp ); 1583 1584 // discard segment if no matching socket found 1585 if( match_socket == false ) return; 1586 1587 // From here the actions depend on both the socket state, 1588 // and the received segment flags 1589 // - update socket state, 1590 // - move data to rx_buf, 1591 // - make a R2T request when required 1592 1593 // build extended pointers on various socket fields 1594 socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock ); 1595 socket_rx_buf_xp = XPTR( socket_cxy , &socket_ptr->rx_buf ); 1596 socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq ); 1597 socket_client_xp = XPTR( socket_cxy , &socket_ptr->rx_client ); 1598 1599 // 3. take the lock protecting the matching socket 1600 remote_rwlock_wr_acquire( socket_lock_xp ); 1601 1602 // get relevant socket infos from socket descriptor 1603 socket_state = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->state )); 1604 socket_rx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_nxt )); 1605 socket_rx_wnd = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->rx_wnd )); 1606 socket_tx_una = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_una )); 1607 socket_tx_nxt = hal_remote_l32(XPTR( socket_cxy , &socket_ptr->tx_nxt )); 1608 1609 switch( socket_state ) 1610 { 1611 ////////////////////// 1612 case TCP_STATE_LISTEN: 1613 { 1614 // [1] discard segment if RST flag 1615 if( seg_rst_set ) return; 1616 1617 // [2] send a RST & discard segment if ACK flag 1618 if( seg_ack_set ) 1619 { 1620 // set socket.tx_nxt to seg_ack_num 1621 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1622 seg_ack_num ); 1623 1624 // make RST request to R2T queue 1625 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1626 TCP_FLAG_RST ); 1627 // discard segment 1628 break; 1629 } 1630 1631 // [3] handle SYN flag 1632 if( seg_syn_set ) 1633 { 1634 // set socket.rx_nxt to seg_seq_num + 1 1635 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1636 seg_seq_num + 1 ); 1637 1638 // set socket.tx_nxt to ISS 1639 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1640 TCP_ISS ); 1641 1642 // set socket.rx_irs to seg_seq_num 1643 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ), 1644 seg_seq_num + 1 ); 1645 1646 // make SYN.ACK request to R2T queue 1647 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1648 TCP_FLAG_SYN | TCP_FLAG_ACK ); 1649 1650 // set socket.tx_nxt to ISS + 1 1651 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1652 TCP_ISS + 1 ); 1653 1654 // set socket.tx_una to ISS 1655 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1656 TCP_ISS ); 1657 1658 // update socket.state 1659 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1660 TCP_STATE_SYN_RCVD ); 1661 1662 // update socket.remote_addr 1663 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_addr ), 1664 seg_src_addr ); 1665 1666 // update socket.remote_port 1667 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->remote_port ), 1668 seg_src_port ); 1669 } 1670 break; 1671 } 1672 //////////////////////// 1673 case TCP_STATE_SYN_SENT: 1674 { 1675 // [1] check ACK flag 1676 if( seg_ack_set ) 1677 { 1678 if( seg_ack_num != TCP_ISS + 1 ) // ACK not acceptable 1679 { 1680 // discard segment if RST 1681 if( seg_rst_set ) break; 1682 1683 // set socket.tx_nxt to seg_ack_num 1684 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1685 seg_ack_num ); 1686 1687 // make an RST request to R2T queue 1688 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1689 TCP_FLAG_RST ); 1690 // discard segment 1691 break; 1692 } 1693 } 1694 1695 // [2] check RST flag 1696 if( seg_rst_set ) 1697 { 1698 // TODO signal "error: connection reset" to user 1699 1700 // update socket.state 1701 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1702 TCP_STATE_BOUND ); 1703 1704 // discard segment 1705 break; 1706 } 1707 1708 // [3] handle SYN flag when (no ACK or acceptable ACK, and no RST) 1709 if( seg_syn_set ) 1710 { 1711 // TODO Ne faut-il pas tester seg_seq_num ? 1712 1713 if( seg_ack_set ) // received both SYN and ACK 1714 { 1715 // set socket.rx_nxt to seg_seq_num + 1 1716 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1717 seg_seq_num + 1 ); 1718 1719 // set socket.tx_una to seg_ack_num 1720 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1721 seg_ack_num ); 1722 1723 // set socket.rx_irs to seg_seq_num 1724 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_irs ), 1725 seg_seq_num ); 1726 1727 // update socket.state 1728 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1729 TCP_STATE_ESTAB ); 1730 1731 // make an ACK request to R2T queue 1732 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1733 TCP_FLAG_ACK ); 1734 } 1735 else // received SYN without ACK 1736 { 1737 // update socket.state 1738 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1739 TCP_STATE_SYN_RCVD ); 1740 1741 // set socket.tx_nxt to ISS 1742 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 1743 TCP_ISS ); 1744 1745 // make a SYN.ACK request to R2T queue 1746 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1747 TCP_FLAG_SYN | TCP_FLAG_ACK ); 1748 } 1749 } 1750 break; 1751 } 1752 //////////////////////// 1753 case TCP_STATE_SYN_RCVD: 1754 case TCP_STATE_ESTAB: 1755 case TCP_STATE_FIN_WAIT1: 1756 case TCP_STATE_FIN_WAIT2: 1757 case TCP_STATE_CLOSE_WAIT: 1758 case TCP_STATE_CLOSING: 1759 case TCP_STATE_LAST_ACK: 1760 case TCP_STATE_TIME_WAIT: 1761 { 1762 // [1] check sequence number 1763 1764 // compute min & max acceptable sequence numbers 1765 uint32_t seq_min = socket_rx_nxt; 1766 uint32_t seq_max = socket_rx_nxt + socket_rx_wnd - 1; 1767 1768 // compute sequence number for last byte in segment 1769 uint32_t seg_seq_last = seg_seq_num + seg_payload - 1; 1770 1771 if( (seg_seq_num != socket_rx_nxt) || // out_of_order 1772 (is_in_window( seg_seq_last, 1773 seq_min, 1774 seq_max ) == false) ) // out_of_window 1775 { 1776 // discard segment 1777 return; 1778 } 1779 1780 // [2] handle RST flag 1781 1782 if( seg_rst_set ) 1783 { 1784 if( socket_state == TCP_STATE_SYN_RCVD ) 1785 { 1786 // TODO unblock all clients threads with "reset" responses 1787 } 1788 else if( (socket_state == TCP_STATE_ESTAB ) || 1789 (socket_state == TCP_STATE_FIN_WAIT1 ) || 1790 (socket_state == TCP_STATE_FIN_WAIT2 ) || 1791 (socket_state == TCP_STATE_CLOSE_WAIT) ) 1792 { 1793 // TODO all pending send & received commands 1794 // must receive "reset" responses 1795 1796 // TODO destroy the socket 1797 } 1798 else // all other states 1799 { 1800 1801 1802 } 1803 1804 // [3] handle security & precedence TODO ... someday 1805 1806 // [4] handle SYN flag 1807 1808 if( seg_syn_set ) // received SYN 1809 { 1810 // TODO signal error to user 1811 1812 // make an RST request to R2T queue 1813 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1814 TCP_FLAG_RST ); 1815 // update socket state 1816 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1817 TCP_STATE_BOUND ); 1818 } 1819 1820 // [5] handle ACK flag 1821 1822 if( seg_ack_set == false ) 1823 { 1824 // discard segment when ACK not set 1825 break; 1826 } 1827 else if( socket_state == TCP_STATE_SYN_RCVD ) 1828 { 1829 if( is_in_window( seg_ack_num , socket_tx_una , socket_tx_nxt ) ) 1830 { 1831 // update socket.state to ESTAB 1832 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1833 TCP_STATE_ESTAB ); 1834 } 1835 else // unacceptable ACK 1836 { 1837 // set socket.tx_nxt to seg_ack_num 1838 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1839 seg_ack_num ); 1840 1841 // make an RST request to R2T queue 1842 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1843 TCP_FLAG_RST ); 1844 } 1845 } 1846 else if( (socket_state == TCP_STATE_ESTAB) || 1847 (socket_state == TCP_STATE_FIN_WAIT1) || 1848 (socket_state == TCP_STATE_FIN_WAIT1) || 1849 (socket_state == TCP_STATE_CLOSE_WAIT) || 1850 (socket_state == TCP_STATE_CLOSING) ) 1851 { 1852 if( is_in_window( seg_ack_num + 1 , socket_tx_una , socket_tx_nxt ) ) 1853 { 1854 // update socket.tx_una 1855 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 1856 seg_ack_num ); 1857 1858 // update socket.tx_wnd 1859 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_wnd ), 1860 seg_window ); 1861 } 1862 else // unacceptable ACK 1863 { 1864 // discard segment 1865 break; 1866 } 1867 1868 // specific for FIN_WAIT1 1869 if( socket_state == TCP_STATE_FIN_WAIT1 ) 1870 { 1871 if( seg_fin_set ) 1872 { 1873 // update socket.state 1874 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1875 TCP_STATE_FIN_WAIT2 ); 1876 } 1877 } 1878 1879 // specific for CLOSING 1880 if( socket_state == TCP_STATE_CLOSING ) 1881 { 1882 if( seg_ack_set ) 1883 { 1884 // update socket.state 1885 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1886 TCP_STATE_TIME_WAIT ); 1887 } 1888 else 1889 { 1890 // discard segment 1891 break; 1892 } 1893 } 1894 } 1895 else if( socket_state == TCP_STATE_LAST_ACK ) 1896 { 1897 if( seg_ack_set ) 1898 { 1899 // update socket.state 1900 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1901 TCP_STATE_TIME_WAIT ); 1902 } 1903 1904 } 1905 1906 // [6] handle URG flag TODO ... someday 1907 1908 // [7] Move DATA to rx_buf and unblock client thread 1909 1910 if( seg_payload ) 1911 { 1912 if( (socket_state == TCP_STATE_ESTAB) || 1913 (socket_state == TCP_STATE_FIN_WAIT1) || 1914 (socket_state == TCP_STATE_FIN_WAIT2) ) 1915 { 1916 // get number of bytes already stored in rx_buf 1917 uint32_t status = remote_buf_status( socket_rx_buf_xp ); 1918 1919 // compute empty space in rx_buf 1920 uint32_t space = NIC_RX_BUF_SIZE - status; 1921 1922 // compute number of bytes to move : min (space , seg_payload) 1923 uint32_t nbytes = ( space < seg_payload ) ? space : seg_payload; 1924 1925 // move payload from k_buf to rx_buf 1926 remote_buf_put_from_kernel( socket_rx_buf_xp, 1927 k_buf + seg_hlen, 1928 nbytes ); 1929 // update socket.rx_nxt 1930 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1931 socket_rx_nxt + nbytes ); 1932 1933 // update socket.rx_wnd 1934 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ), 1935 socket_rx_wnd - nbytes ); 1936 1937 // make an ACK request to R2T queue 1938 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1939 TCP_FLAG_ACK ); 1940 1941 // get extended pointer on rx_client thread 1942 xptr_t client_xp = hal_remote_l64( socket_client_xp ); 1943 1944 // unblock client thread 1945 if( client_xp != XPTR_NULL ) 1946 { 1947 thread_unblock( client_xp , THREAD_BLOCKED_IO ); 1948 } 1949 } 1950 } 1951 1952 // [8] handle FIN flag 1953 1954 if( seg_fin_set ) 1955 { 1956 if( (socket_state == TCP_STATE_UNBOUND) || 1957 (socket_state == TCP_STATE_BOUND) || 1958 (socket_state == TCP_STATE_LISTEN) || 1959 (socket_state == TCP_STATE_SYN_SENT) ) 1960 { 1961 // discard segment 1962 break; 1963 } 1964 else // all other states 1965 { 1966 // TODO signal "connection closing" 1967 1968 // make an ACK request to R2T queue 1969 dev_nic_rx_put_r2t_request( socket_r2tq_xp, 1970 TCP_FLAG_ACK ); 1971 1972 // increment socket.rx_nxt 1973 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 1974 socket_rx_nxt + 1 ); 1975 1976 if( (socket_state == TCP_STATE_SYN_RCVD) || 1977 (socket_state == TCP_STATE_ESTAB) ) 1978 { 1979 // update socket.state 1980 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1981 TCP_STATE_TIME_WAIT ); 1982 } 1983 else if( socket_state == TCP_STATE_FIN_WAIT1 ) 1984 { 1985 if( seg_ack_set ) 1986 { 1987 // TODO start "time-wait" timer / turn off others timers 1988 1989 // update socket.state 1990 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1991 TCP_STATE_TIME_WAIT ); 1992 } 1993 else 1994 { 1995 // update socket.state 1996 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 1997 TCP_STATE_CLOSING ); 1998 } 1999 } 2000 else if( socket_state == TCP_STATE_FIN_WAIT2 ) 2001 { 2002 // TODO start "time-wait" timer / turn off other timers 2003 2004 // update socket.state 2005 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2006 TCP_STATE_TIME_WAIT ); 2007 } 2008 else if( socket_state == TCP_STATE_TIME_WAIT ) 2009 { 2010 // TODO restart "time_wait" timer 2011 } 2012 } 2013 } // end if FIN 2014 } // end case sockets synchronized 2015 } // end switch socket state 2016 2017 // release the lock protecting socket 2018 remote_rwlock_wr_acquire( socket_lock_xp ); 2019 2020 } // end socket found 2021 2022 } // end dev_nic_rx_handle_tcp_segment() 2023 2024 2025 ///////////////////////////////////////// 2026 void dev_nic_rx_server( chdev_t * chdev ) 2027 { 2028 uint8_t k_buf[2048]; // kernel buffer for one ETH/IP/UDP packet 2029 2030 uint32_t pkt_src_addr; // packet source IP address 2031 uint32_t pkt_dst_addr; // packet destination IP address 2032 uint32_t trsp_protocol; // transport protocol (TCP / UDP) 2033 uint32_t eth_length; // size of Ethernet packet (bytes) 2034 uint32_t ip_length; // size of IP packet in bytes 2035 uint32_t nic_queue_readable; // NIC_RX queue non empty when true 2036 error_t error; 2037 2038 thread_t * this = CURRENT_THREAD; 2039 2040 // check chdev direction and type 2041 assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == true) , 2042 "illegal chdev type or direction" ); 177 2043 178 2044 // check thread can yield 179 assert( (thread_ptr->busylocks == 0), 180 "cannot yield : busylocks = %d\n", thread_ptr->busylocks ); 2045 assert( (this->busylocks == 0), 2046 "cannot yield : busylocks = %d\n", this->busylocks ); 2047 2048 while( 1 ) 2049 { 2050 // check NIC_RX_QUEUE readable 2051 error = dev_nic_rx_queue_readable( chdev, 2052 &nic_queue_readable ); 2053 if( error ) 2054 { 2055 printk("\n[PANIC] in %s : cannot access NIC_TX[%d] queue\n", 2056 __FUNCTION__, chdev->channel ); 2057 } 2058 2059 if( nic_queue_readable ) // NIC_TX_QUEUE non empty 2060 { 2061 // moves one Ethernet packet to kernel buffer 2062 error = dev_nic_rx_move_packet( chdev, 2063 k_buf, 2064 ð_length ); 2065 if( error ) 2066 { 2067 printk("\n[PANIC] in %s : cannot read the NIC_TX[%d] queue\n", 2068 __FUNCTION__, chdev->channel ); 2069 } 2070 2071 // analyse the ETH header 2072 error = dev_nic_rx_check_eth( k_buf, 2073 &ip_length ); 2074 2075 // discard packet if error reported by Ethernet layer 2076 if( error ) continue; 2077 2078 // analyse the IP header 2079 error = dev_nic_rx_check_ip( k_buf + ETH_HEAD_LEN, 2080 ip_length, 2081 &pkt_src_addr, 2082 &pkt_dst_addr, 2083 &trsp_protocol ); 2084 2085 // discard packet if error reported by IP layer 2086 if( error ) continue; 2087 2088 // call relevant transport protocol 2089 if( trsp_protocol == PROTOCOL_UDP ) 2090 { 2091 dev_nic_rx_handle_udp_packet( chdev, 2092 k_buf + ETH_HEAD_LEN + IP_HEAD_LEN, 2093 ip_length - IP_HEAD_LEN, 2094 pkt_src_addr, 2095 pkt_dst_addr ); 2096 } 2097 else if ( trsp_protocol == PROTOCOL_TCP) 2098 { 2099 dev_nic_rx_handle_tcp_segment( chdev, 2100 k_buf + ETH_HEAD_LEN + IP_HEAD_LEN, 2101 ip_length - IP_HEAD_LEN, 2102 pkt_src_addr, 2103 pkt_dst_addr ); 2104 } 2105 } 2106 else // block and deschedule if NIC_RX_QUEUE empty 2107 { 2108 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_ISR ); 2109 sched_yield( "waiting RX client" ); 2110 } 2111 2112 } // end of while loop 2113 2114 } // end dev_nic_rx_server() 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 /////////////////////////////////////////////////////////////////////////////////////////// 2126 // Functions used by the NIC_TX server thread 2127 /////////////////////////////////////////////////////////////////////////////////////////// 2128 2129 2130 /////////////////////////////////////////////////////////////////////////////////////////// 2131 // These static functions are called by the NIC_TX server thread to report the 2132 // completion (success or error) of a TX command. 2133 // - it print an error message in case of error. 2134 // - it updates the "tx_error" field in socket descriptor. 2135 // - it unblocks the client thread. 2136 /////////////////////////////////////////////////////////////////////////////////////////// 2137 // @ socket_xp : [in] extended pointer on socket 2138 // @ cmd_type : [in] SOCKET_TX_CONNECT / SOCKET_TX_SEND / SOCKET_TX_CLOSE 2139 // @ socket_state : [in] current socket state 2140 /////////////////////////////////////////////////////////////////////////////////////////// 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. 2218 // It moves one ETH/IP/UDP packet from the kernel buffer identified by the <buffer> and 2219 // <length> arguments to the NIC_TX_QUEUE identified the <chdev> argument. 2220 // It calls directly the NIC driver, without registering in a waiting queue, because 2221 // only this NIC_TX server thread can access this NIC_TX_QUEUE. 2222 // 1) It checks NIC_TX_QUEUE status in a while loop, using the NIC_CMD_WRITABLE command. 2223 // As long as the queue is not writable, it blocks and deschedules. It is re-activated 2224 // by the NIC-TX ISR as soon as the queue changes status. 2225 // 2) When the queue is writable, it put the ETH/IP/UDP packet into the NIC_TX_QUEUE, 2226 // using the driver NIC_CMD_WRITE command. 2227 // Both commands are successively registered in this NIC-TX server thread descriptor 2228 // to be passed to the driver. 2229 /////////////////////////////////////////////////////////////////////////////////////////// 2230 // @ chdev : [in] local pointer on NIC_TX chdev. 2231 // @ buffer : [in] pointer on a local kernel buffer (2K bytes). 2232 // @ length : [in] actual Ethernet packet length in bytes. 2233 /////////////////////////////////////////////////////////////////////////////////////////// 2234 void dev_nic_tx_move_packet( chdev_t * chdev, 2235 uint8_t * buffer, 2236 uint32_t length ) 2237 { 2238 error_t error; 2239 uint32_t writable; 2240 2241 thread_t * this = CURRENT_THREAD; 2242 2243 // get extended pointers on server tread and chdev 2244 xptr_t thread_xp = XPTR( local_cxy , this ); 2245 xptr_t chdev_xp = XPTR( local_cxy , chdev ); 2246 2247 // get local pointer on core running this server thead 2248 core_t * core = this->core; 2249 2250 // check thread can yield 2251 assert( (this->busylocks == 0), 2252 "cannot yield : busylocks = %d\n", this->busylocks ); 181 2253 182 2254 #if DEBUG_DEV_NIC_RX 183 2255 uint32_t cycle = (uint32_t)hal_get_cycles(); 184 2256 if( DEBUG_DEV_NIC_RX < cycle ) 185 printk("\n[ DBG] %s : thread %x enters for packet %x in cluster %x\n",186 __FUNCTION__ , thread_ptr , pkd , local_cxy);2257 printk("\n[%s] thread[%x,%x] enters for packet %x / cycle %d\n", 2258 __FUNCTION__, this->process->pid, this->trdid, pkd, cycle ); 187 2259 #endif 188 2260 189 // get pointer on NIC-TX chdev descriptor 190 uint32_t channel = thread_ptr->chdev->channel; 191 xptr_t dev_xp = chdev_dir.nic_tx[channel]; 192 cxy_t dev_cxy = GET_CXY( dev_xp ); 193 chdev_t * dev_ptr = (chdev_t *)GET_PTR( dev_xp ); 194 195 assert( (dev_xp != XPTR_NULL) , "undefined NIC chdev descriptor" ); 196 197 assert( (dev_cxy == local_cxy) , " chdev must be local" ); 198 199 // initialize command in thread descriptor 200 thread_ptr->nic_cmd.dev_xp = dev_xp; 201 202 // call driver to test writable 203 thread_ptr->nic_cmd.cmd = NIC_CMD_WRITABLE; 204 dev_ptr->cmd( thread_xp ); 205 206 // check error 207 error = thread_ptr->nic_cmd.error; 208 if( error ) return error; 209 210 // block and deschedule if queue non writable 211 if( thread_ptr->nic_cmd.status == false ) 212 { 213 // enable NIC-TX IRQ 214 dev_pic_enable_irq( core->lid ,dev_xp ); 215 216 // block client thread on THREAD_BLOCKED I/O condition 217 thread_block( XPTR( local_cxy , thread_ptr ) , THREAD_BLOCKED_IO ); 218 219 // deschedule client thread 220 sched_yield("client blocked on I/O"); 221 222 // disable NIC-TX IRQ 223 dev_pic_disable_irq( core->lid , dev_xp ); 224 } 225 226 // call driver for actual write 227 thread_ptr->nic_cmd.cmd = NIC_CMD_WRITE; 228 thread_ptr->nic_cmd.buffer = pkd->buffer; 229 thread_ptr->nic_cmd.length = pkd->length; 230 dev_ptr->cmd( thread_xp ); 231 232 // check error 233 error = thread_ptr->nic_cmd.error; 234 if( error ) return error; 2261 // check NIC_TX_QUEUE writable 2262 while( 1 ) 2263 { 2264 error = dev_nic_tx_queue_writable( chdev, 2265 length, 2266 &writable ); 2267 if( error ) 2268 { 2269 printk("\n[PANIC] in %s : cannot access NIC_TX queue\n", __FUNCTION__ ); 2270 return; 2271 } 2272 2273 if( writable == 0 ) // block & deschedule if non writable 2274 { 2275 // enable NIC-TX IRQ 2276 dev_pic_enable_irq( core->lid , chdev_xp ); 2277 2278 // block TX server thread 2279 thread_block( thread_xp , THREAD_BLOCKED_ISR ); 2280 2281 // deschedule TX server thread 2282 sched_yield("client blocked on NIC_TX queue full"); 2283 2284 // disable NIC-TX IRQ 2285 dev_pic_disable_irq( core->lid , chdev_xp ); 2286 } 2287 else // exit loop if writable 2288 { 2289 break; 2290 } 2291 } 2292 2293 // initialize WRITE command in server thread descriptor 2294 this->nic_cmd.dev_xp = chdev_xp; 2295 this->nic_cmd.type = NIC_CMD_WRITE; 2296 this->nic_cmd.buffer = buffer; 2297 this->nic_cmd.length = length; 2298 2299 // call driver to move packet 2300 chdev->cmd( thread_xp ); 235 2301 236 2302 #if DEBUG_DEV_NIC_RX 237 2303 cycle = (uint32_t)hal_get_cycles(); 238 2304 if( DEBUG_DEV_NIC_RX < cycle ) 239 printk("\n[ DBG] %s : thread %x exit for packet %x in cluster%x\n",240 __FUNCTION__ , th read_ptr , pkd , local_cxy);2305 printk("\n[%s] thread[%x,%x] exit for packet %x\n", 2306 __FUNCTION__ , this->process->pid, this->trdid , pkd ); 241 2307 #endif 242 2308 243 return 0; 244 } // end dev_nic_write() 245 246 247 2309 return; 2310 2311 } // end dev_nic_tx_move_packet() 2312 2313 /////////////////////////////////////////////////////////////////////////////////////////// 2314 // This static function is called by the dev_nic_tx_server() function to build an UDP 2315 // header in the kernel buffer defined by the <k_buf> arguement, as specified by the 2316 // <socket_xp> argument. The <length> argument defines the number of bytes in payload. 2317 // It set the "src_port", "dst_port", "total_length" and "checksum" fields in UDP header. 2318 // The payload must be previouly loaded in the pernel buffer. 2319 /////////////////////////////////////////////////////////////////////////////////////////// 2320 // @ k_buf : [in] pointer on first byte of UDP header in kernel buffer. 2321 // @ socket_xp : [in] extended pointer on socket. 2322 // @ length : [in] number of bytes in payload. 2323 /////////////////////////////////////////////////////////////////////////////////////////// 2324 void dev_nic_tx_build_udp_header( uint8_t * k_buf, 2325 xptr_t socket_xp, 2326 uint32_t length ) 2327 { 2328 uint16_t checksum; // checksum value 2329 uint32_t total_length; // total UDP packet length 2330 uint32_t local_addr; // local IP address 2331 uint32_t remote_addr; // remote IP address 2332 uint32_t local_port; // local port 2333 uint32_t remote_port; // remote port 2334 2335 // get socket cluster an local pointer 2336 socket_t * socket_ptr = GET_PTR( socket_xp ); 2337 cxy_t socket_cxy = GET_CXY( socket_xp ); 2338 2339 // get relevant infos from socket 2340 local_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_addr )); 2341 remote_addr = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_addr )); 2342 local_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->local_port )); 2343 remote_port = hal_remote_l32(XPTR(socket_cxy , &socket_ptr->remote_port )); 2344 2345 // compute UDP packet total length 2346 total_length = length + UDP_HEAD_LEN; 2347 2348 // set src_port and dst_port in header 2349 k_buf[0] = local_port >> 8; 2350 k_buf[1] = local_port; 2351 k_buf[2] = remote_port >> 8; 2352 k_buf[3] = remote_port; 2353 2354 // set packet length in header 2355 k_buf[4] = total_length >> 8; 2356 k_buf[5] = total_length; 2357 2358 // compute UDP packet checksum 2359 checksum = dev_nic_udp_checksum( k_buf , total_length ); 2360 2361 // set checksum 2362 k_buf[6] = checksum >> 8; 2363 k_buf[7] = checksum; 2364 2365 } // end dev_nic_tx_build_udp_header() 2366 2367 /////////////////////////////////////////////////////////////////////////////////////////// 2368 // This static function is called by the dev_nic_tx_server() function. 2369 // It builds a TCP header in the kernel buffer defined by the <k_buf> argument. 2370 // The payload must have been previouly registered in this buffer. 2371 // The "local_addr", "local_port", "remote_addr", "remote_port", seq_num", "ack_num", 2372 // and "window" fields are obtained from the <socket_xp> argument. 2373 // The <length> argument defines the number of bytes in payload, and the <flags> argument 2374 // defines the flags to be set in TCP header. 2375 /////////////////////////////////////////////////////////////////////////////////////////// 2376 // @ k_buf : [in] pointer on first byte of TCP header in kernel buffer. 2377 // @ length : [in] number of bytes in payload. 2378 // @ socket_xp : [in] extended pointer on socket. 2379 // @ flags : [in] flags to be set in TCP header. 2380 /////////////////////////////////////////////////////////////////////////////////////////// 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 ) 2385 { 2386 uint16_t checksum; // global segment checksum 2387 uint32_t total_length; // total UDP packet length 2388 uint32_t src_addr; // local IP address 2389 uint32_t dst_addr; // remote IP address 2390 uint16_t src_port; // local port 2391 uint16_t dst_port; // remote port 2392 uint32_t seq_num; // first byte of segment in TX stream 2393 uint32_t ack_num; // next expected byte in RX stream 2394 uint16_t window; // window of accepted segments in RX stream 2395 2396 // get socket cluster an local pointer 2397 socket_t * sock_ptr = GET_PTR( socket_xp ); 2398 cxy_t sock_cxy = GET_CXY( socket_xp ); 2399 2400 // get relevant infos from socket 2401 src_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_addr )); 2402 dst_addr = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_addr )); 2403 src_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->local_port )); 2404 dst_port = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->remote_port )); 2405 seq_num = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->tx_nxt )); 2406 ack_num = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_nxt )); 2407 window = hal_remote_l32(XPTR( sock_cxy , &sock_ptr->rx_wnd )); 2408 2409 // compute TCP segment total length 2410 total_length = length + TCP_HEAD_LEN; 2411 2412 // set "src_port" and "dst_port" 2413 k_buf[0] = src_port >> 8; 2414 k_buf[1] = src_port; 2415 k_buf[2] = dst_port >> 8; 2416 k_buf[3] = dst_port; 2417 2418 // set "seq_num" 2419 k_buf[4] = seq_num >> 24; 2420 k_buf[5] = seq_num >> 16; 2421 k_buf[6] = seq_num >> 8; 2422 k_buf[7] = seq_num; 2423 2424 // set "ack_num" 2425 k_buf[8] = ack_num >> 24; 2426 k_buf[9] = ack_num >> 16; 2427 k_buf[10] = ack_num >> 8; 2428 k_buf[11] = ack_num; 2429 2430 // set "hlen" 2431 k_buf[12] = 5; 2432 2433 // set "flags" 2434 k_buf[13] = flags & 0x3F; 2435 2436 // set "window" 2437 k_buf[14] = window >> 8; 2438 k_buf[15] = window; 2439 2440 // reset "checksum" 2441 k_buf[16] = 0; 2442 k_buf[17] = 0; 2443 2444 // set "urgent_ptr" 2445 k_buf[18] = 0; 2446 k_buf[19] = 0; 2447 2448 // compute TCP segment checksum 2449 checksum = dev_nic_tcp_checksum( k_buf, 2450 total_length, 2451 src_addr, 2452 dst_addr ); 2453 // set "checksum" 2454 k_buf[16] = checksum >> 8; 2455 k_buf[17] = checksum; 2456 2457 } // end dev_nic_tx_build_tcp_header() 2458 2459 2460 /////////////////////////////////////////////////////////////////////////////////////////// 2461 // This static function is called by the dev_nic_tx_server() function. 2462 // It builds the IP header in the 20 first bytes of <buffer>. 2463 /////////////////////////////////////////////////////////////////////////////////////////// 2464 // @ buffer : pointer on first byte of IP header in kernel buffer 2465 // @ src_addr : source IP address. 2466 // @ dst_addr : destination IP address. 2467 // @ length : number of bytes in IP packet payload. 2468 /////////////////////////////////////////////////////////////////////////////////////////// 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 ) 2473 { 2474 uint16_t hcs; 2475 2476 uint16_t total = length + IP_HEAD_LEN; 2477 2478 buffer[0] = 0x45; // IPV4 / IHL = 20 bytes 2479 buffer[1] = 0; // DSCP / ECN 2480 buffer[2] = total >> 8; 2481 buffer[3] = total; 2482 2483 buffer[4] = 0x40; // Don't Fragment 2484 buffer[5] = 0; 2485 buffer[6] = 0; 2486 buffer[7] = 0; 2487 2488 buffer[8] = 0xFF; // TTL 2489 buffer[9] = 0x11; // UDP protocol 2490 2491 buffer[12] = src_addr >> 24; 2492 buffer[13] = src_addr >> 16; 2493 buffer[14] = src_addr >> 8; 2494 buffer[15] = src_addr; 2495 2496 buffer[16] = dst_addr >> 24; 2497 buffer[17] = dst_addr >> 16; 2498 buffer[18] = dst_addr >> 8; 2499 buffer[19] = dst_addr; 2500 2501 // compute IP header checksum 2502 hcs = dev_nic_ip_checksum( buffer ); 2503 2504 // set checksum 2505 buffer[10] = hcs >> 8; 2506 buffer[11] = hcs; 2507 2508 } // end dev_nic_tx_build_ip_header 2509 2510 /////////////////////////////////////////////////////////////////////////////////////////// 2511 // This static function is called by the dev_nic_tx_server() function. 2512 // It builds the Ethernet header in the 14 first bytes of <buffer>. 2513 /////////////////////////////////////////////////////////////////////////////////////////// 2514 // @ buffer : pointer on first byte of Ethernet header in kernel buffer 2515 // @ src_mac_54 : two MSB bytes in source MAC address. 2516 // @ src_mac_32 : two MED bytes in source MAC address. 2517 // @ src_mac_10 : two LSB bytes in source MAC address. 2518 // @ dst_mac_54 : two MSB bytes in destination MAC address. 2519 // @ dst_mac_32 : two MED bytes in destination MAC address. 2520 // @ dst_mac_10 : two LSB bytes in destination MAC address. 2521 // @ length : number of bytes in Ethernet frame payload. 2522 /////////////////////////////////////////////////////////////////////////////////////////// 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 ) 2531 { 2532 buffer[0] = dst_mac_54 >> 8; 2533 buffer[1] = dst_mac_54; 2534 buffer[2] = dst_mac_32 >> 8; 2535 buffer[3] = dst_mac_32; 2536 buffer[4] = dst_mac_10 >> 8; 2537 buffer[5] = dst_mac_10; 2538 2539 buffer[6] = src_mac_54 >> 8; 2540 buffer[7] = src_mac_54; 2541 buffer[8] = src_mac_32 >> 8; 2542 buffer[9] = src_mac_32; 2543 buffer[10] = src_mac_10 >> 8; 2544 buffer[11] = src_mac_10; 2545 2546 buffer[12] = length >> 8; 2547 buffer[13] = length; 2548 2549 } // end dev_nic_tx_build_eth_header() 2550 2551 /////////////////////////////////////////////////////////////////////////////////////////// 2552 // This static function is called by the dev_nic_tx_server() function to handle one 2553 // TX command, or one R2T request, registered in the socket identified by the <socket_xp> 2554 // argument. If there is one valid command, or if the R2T queue is non empty (for a TCP 2555 // socket), it builds an ETH/IP/UDP packet (or a ETH/IP/TCP segment), in the buffer 2556 // defined by the <k_buf> argument, and registers it in the NIC_TX queue defined by the 2557 // <chdev> argument. The supported commands are SOCKET_SEND/SOCKET_CONNECT/SOCKET_CLOSE. 2558 // It unblocks the client thread when the command is completed. 2559 /////////////////////////////////////////////////////////////////////////////////////////// 2560 // When there is a packet to send, it makes the following actions: 2561 // 1) it takes the lock protecting the socket state. 2562 // 2) it get the command arguments from client thread descriptor. 2563 // 3) it build an UDP packet or a TCP segment, depending on both the command type, and 2564 // the socket state, updates the socket state, and unblocks the client thread. 2565 // 4) it release the lock protecting the socket. 2566 // 5) it build the IP header. 2567 // 6) it build the ETH header. 2568 // 7) it copies the packet in the NIC_TX queue. 2569 /////////////////////////////////////////////////////////////////////////////////////////// 2570 // @ socket_xp : [in] extended pointer on client socket. 2571 // @ k_buf : [in] local pointer on kernel buffer (2 Kbytes). 2572 // @ chdev : [in] local pointer on NIC_RX chdev. 2573 /////////////////////////////////////////////////////////////////////////////////////////// 2574 static void dev_nic_tx_handle_one_cmd( xptr_t socket_xp, 2575 uint8_t * k_buf, 2576 chdev_t * chdev ) 2577 { 2578 socket_t * socket_ptr; 2579 cxy_t socket_cxy; 2580 xptr_t client_xp; // extended pointer on client thread 2581 thread_t * client_ptr; 2582 cxy_t client_cxy; 2583 sock_cmd_t cmd; // NIC command type 2584 uint8_t * buf; // pointer on user buffer 2585 uint32_t len; // user buffer length 2586 uint32_t todo; // number of bytes not yet sent 2587 uint32_t socket_type; // socket type (UDP/TCP) 2588 uint32_t socket_state; // socket state 2589 xptr_t socket_lock_xp; // extended pointer on socket lock 2590 xptr_t socket_r2tq_xp; // extended pointer on R2T queue 2591 uint32_t src_ip_addr; // source IP address 2592 uint32_t dst_ip_addr; // destination IP address 2593 uint32_t tx_una; // next byte to be sent 2594 uint32_t tx_nxt; // first unacknowledged byte 2595 uint32_t nbytes; // number of bytes in UDP/TCP packet payload 2596 uint8_t * k_base; // pointer UDP/TCP packet in kernel buffer 2597 uint32_t trsp_length; // length of TCP/UDP packet 2598 uint8_t r2t_flags; // flags defined by one R2T queue request 2599 bool_t do_send; // build & send a packet when true 2600 2601 // get socket cluster and local pointer 2602 socket_cxy = GET_CXY( socket_xp ); 2603 socket_ptr = GET_PTR( socket_xp ); 2604 2605 // build extended pointer on socket lock and r2t queue 2606 socket_lock_xp = XPTR( socket_cxy , &socket_ptr->lock ); 2607 socket_r2tq_xp = XPTR( socket_cxy , &socket_ptr->r2tq ); 2608 2609 // 1. take lock protecting this socket 2610 remote_rwlock_wr_acquire( socket_lock_xp ); 2611 2612 // get pointers on TX client thread from socket 2613 client_xp = hal_remote_l64( XPTR( socket_cxy , &socket_ptr->tx_client )); 2614 client_cxy = GET_CXY( client_xp ); 2615 client_ptr = GET_PTR( client_xp ); 2616 2617 // check valid command 2618 if( client_xp != XPTR_NULL ) // valid command found 2619 { 2620 // 2. get command arguments from socket 2621 cmd = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_cmd )); 2622 buf = hal_remote_lpt( XPTR(socket_cxy , &socket_ptr->tx_buf )); 2623 len = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_len )); 2624 todo = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_todo )); 2625 2626 // get socket type and state 2627 socket_type = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->type )); 2628 socket_state = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->state )); 2629 2630 // 3. UDP : build UDP packet and update UDP socket state 2631 if( socket_type == SOCK_DGRAM ) 2632 { 2633 if( socket_state == UDP_STATE_UNBOUND ) 2634 { 2635 // report illegal command 2636 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2637 2638 do_send = false; 2639 } 2640 else // BOUND or CONNECT state 2641 { 2642 if( cmd == SOCKET_TX_SEND ) 2643 { 2644 // compute payload length 2645 nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo; 2646 2647 // compute UDP packet base in kernel buffer 2648 k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN; 2649 2650 // move payload to kernel buffer 2651 hal_copy_from_uspace( XPTR(local_cxy , k_base + UDP_HEAD_LEN ), 2652 buf + (len - todo), 2653 nbytes ); 2654 // build UDP header 2655 dev_nic_tx_build_udp_header( k_base, 2656 socket_xp, 2657 nbytes ); 2658 2659 // update "tx_todo" in socket descriptor 2660 hal_remote_s32( XPTR(socket_cxy , socket_ptr->tx_todo), 2661 todo - nbytes ); 2662 2663 // unblock client thread when SEND command completed 2664 if( nbytes == todo ) 2665 { 2666 dev_nic_tx_report_success( socket_xp ); 2667 } 2668 2669 do_send = true; 2670 } 2671 else 2672 { 2673 // report illegal command 2674 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2675 2676 do_send = false; 2677 } 2678 } 2679 2680 // compute transport packet length 2681 trsp_length = UDP_HEAD_LEN + nbytes; 2682 2683 } // end UDP 2684 2685 // 3. TCP : build TCP segment and update TCP socket state 2686 if( socket_type == SOCK_STREAM ) 2687 { 2688 // extract one request from TCP socket R2T queue if queue non empty 2689 if( remote_buf_status( socket_r2tq_xp ) ) 2690 { 2691 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 ); 2692 } 2693 else 2694 { 2695 r2t_flags = 0; 2696 } 2697 2698 ///////////////////////////////////// 2699 if( socket_state == TCP_STATE_ESTAB ) // connected TCP socket 2700 { 2701 if( cmd == SOCKET_TX_SEND ) 2702 { 2703 // get "tx_nxt", and "tx_una" from socket descriptor 2704 tx_nxt = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_nxt )); 2705 tx_una = hal_remote_l32( XPTR(socket_cxy , &socket_ptr->tx_una )); 2706 2707 // compute actual payload length 2708 nbytes = ( PAYLOAD_MAX_LEN < todo ) ? PAYLOAD_MAX_LEN : todo; 2709 2710 // compute TCP segment base in kernel buffer 2711 k_base = k_buf + ETH_HEAD_LEN + IP_HEAD_LEN; 2712 2713 // move payload to kernel buffer 2714 hal_copy_from_uspace( XPTR( local_cxy , k_base + TCP_HEAD_LEN ), 2715 buf + (len - todo), 2716 nbytes ); 2717 2718 // build TCP header 2719 dev_nic_tx_build_tcp_header( k_base, 2720 socket_xp, 2721 nbytes, // payload 2722 TCP_FLAG_ACK | r2t_flags ); // flags 2723 2724 // update "tx_todo" in socket descriptor 2725 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_todo ), 2726 todo - nbytes ); 2727 2728 // update "tx_nxt" in socket descriptor 2729 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 2730 tx_nxt + nbytes ); 2731 2732 // unblock client thread when SEND command completed 2733 if( (todo == 0) && (tx_nxt == tx_una) ) 2734 { 2735 dev_nic_tx_report_success( socket_xp ); 2736 } 2737 2738 do_send = true; 2739 } 2740 else if( cmd == SOCKET_TX_CLOSE ) 2741 { 2742 // build TCP FIN segment 2743 dev_nic_tx_build_tcp_header( k_base, 2744 socket_xp, 2745 0, // payload 2746 TCP_FLAG_FIN | r2t_flags ); // flags 2747 // update socket state 2748 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2749 TCP_STATE_FIN_WAIT1 ); 2750 2751 do_send = true; 2752 } 2753 else // cmd == CONNECT 2754 { 2755 // report illegal command 2756 dev_nic_tx_report_error( socket_xp , cmd , socket_state ); 2757 2758 do_send = false; 2759 } 2760 } 2761 ////////////////////////////////////////// 2762 else if( socket_state == TCP_STATE_BOUND ) // unconnected TCP socket 2763 { 2764 if ( cmd == SOCKET_TX_CONNECT ) 2765 { 2766 // set socket.tx_nxt 2767 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_nxt ), 2768 TCP_ISS ); 2769 2770 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_nxt ), 0 ); 2771 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->rx_wnd ), 2772 NIC_RX_BUF_SIZE); 2773 2774 // build TCP SYN segment 2775 dev_nic_tx_build_tcp_header( k_base, 2776 socket_xp, 2777 0, // payload 2778 TCP_FLAG_SYN ); // flags 2779 // update socket state 2780 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2781 TCP_STATE_SYN_SENT ); 2782 2783 do_send = true; 2784 } 2785 else // cmd == SEND / CLOSE 2786 { 2787 // report illegal command 2788 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2789 2790 do_send = false; 2791 } 2792 } 2793 /////////////////////////////////////////// 2794 else if( socket_state == TCP_STATE_LISTEN ) // server wait connect 2795 { 2796 if( cmd == SOCKET_TX_CONNECT ) 2797 { 2798 // update socket.state 2799 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2800 TCP_STATE_SYN_SENT ); 2801 2802 // set socket.tx_una 2803 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 2804 TCP_ISS ); 2805 2806 // set socket.tx_nxt 2807 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->tx_una ), 2808 TCP_ISS + 1 ); 2809 2810 // build TCP SYN segment 2811 dev_nic_tx_build_tcp_header( k_base, 2812 socket_xp, 2813 0, // payload 2814 TCP_FLAG_SYN ); // flags 2815 do_send = true; 2816 } 2817 else // cmd == CLOSE / SEND 2818 { 2819 // report illegal command 2820 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2821 2822 do_send = false; 2823 } 2824 } 2825 ///////////////////////////////////////////// 2826 else if( socket_state == TCP_STATE_SYN_RCVD ) // socket wait ACK 2827 { 2828 if( cmd == SOCKET_TX_CLOSE ) 2829 { 2830 // build TCP FIN segment 2831 dev_nic_tx_build_tcp_header( k_base, 2832 socket_xp, 2833 0, // payload 2834 TCP_FLAG_FIN ); // flags 2835 // update socket state 2836 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2837 TCP_STATE_FIN_WAIT1 ); 2838 2839 do_send = true; 2840 } 2841 else // SEND / CONNECT 2842 { 2843 // report illegal command 2844 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2845 2846 do_send = false; 2847 } 2848 } 2849 //////////////////////////////////////////////// 2850 else if( socket_state == TCP_STATE_CLOSE_WAIT ) // wait local close() 2851 { 2852 if( cmd == SOCKET_TX_CLOSE ) 2853 { 2854 // build TCP FIN segment 2855 dev_nic_tx_build_tcp_header( k_base, 2856 socket_xp, 2857 0, // payload 2858 TCP_FLAG_FIN ); // flags 2859 // update socket state 2860 hal_remote_s32( XPTR( socket_cxy , &socket_ptr->state ), 2861 TCP_STATE_LAST_ACK ); 2862 2863 do_send = true; 2864 } 2865 else // SEND / CONNECT 2866 { 2867 // report illegal command 2868 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2869 2870 do_send = false; 2871 } 2872 } 2873 //// 2874 else 2875 { 2876 // report illegal command 2877 dev_nic_tx_report_error( socket_xp, cmd, socket_state ); 2878 2879 do_send = false; 2880 } 2881 2882 // compute TCP segment length 2883 trsp_length = TCP_HEAD_LEN + nbytes; 2884 } 2885 } 2886 else // no valid command found 2887 { 2888 if( socket_type == SOCK_DGRAM ) // UDP socket 2889 { 2890 do_send = false; 2891 } 2892 else // TCP socket 2893 { 2894 if( remote_buf_status( socket_r2tq_xp ) == 0 ) // R2T queue empty 2895 { 2896 do_send = false; 2897 } 2898 else // pending request in R2T queue 2899 { 2900 // get one request from R2T queue 2901 remote_buf_get_to_kernel( socket_r2tq_xp , &r2t_flags , 1 ); 2902 2903 // build TCP header for an empty segment 2904 dev_nic_tx_build_tcp_header( k_base, 2905 socket_xp, 2906 0, // payload 2907 r2t_flags ); // flags 2908 do_send = true; 2909 } 2910 } 2911 } 2912 2913 // 4. release the lock protecting the socket 2914 remote_rwlock_wr_release( socket_lock_xp ); 2915 2916 // return if no packet to send 2917 if( do_send == false ) return; 2918 2919 // 5. build IP header 2920 dev_nic_tx_build_ip_header( k_buf + ETH_HEAD_LEN, 2921 src_ip_addr, 2922 dst_ip_addr, 2923 IP_HEAD_LEN + trsp_length ); 2924 2925 // 6. build ETH header 2926 dev_nic_tx_build_eth_header( k_buf, 2927 (uint16_t)SRC_MAC_54, 2928 (uint16_t)SRC_MAC_32, 2929 (uint16_t)SRC_MAC_10, 2930 (uint16_t)DST_MAC_54, 2931 (uint16_t)DST_MAC_32, 2932 (uint16_t)DST_MAC_10, 2933 ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length ); 2934 2935 // 7. move packet to NIC_TX queue 2936 dev_nic_tx_move_packet( chdev, 2937 k_buf, 2938 ETH_HEAD_LEN + IP_HEAD_LEN + trsp_length ); 2939 2940 } // end dev_nic_tx_handle_one_cmd() 2941 2942 ///////////////////////////////////////// 2943 void dev_nic_tx_server( chdev_t * chdev ) 2944 { 2945 uint8_t k_buf[NIC_KERNEL_BUF_SIZE]; // buffer for one packet 2946 2947 xptr_t root_xp; // extended pointer on clients list root 2948 xptr_t lock_xp; // extended pointer on lock protecting this list 2949 xptr_t socket_xp; // extended pointer on on client socket 2950 socket_t * socket_ptr; 2951 cxy_t socket_cxy; 2952 xptr_t entry_xp; // extended pointer on socket tx_list entry 2953 2954 thread_t * this = CURRENT_THREAD; 2955 2956 // check chdev direction and type 2957 assert( (chdev->func == DEV_FUNC_NIC) && (chdev->is_rx == false) , 2958 "illegal chdev type or direction" ); 2959 2960 // 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 ); 2967 2968 while( 1 ) // TX server infinite loop 2969 { 2970 // take the lock protecting the client sockets queue 2971 remote_busylock_acquire( lock_xp ); 2972 2973 /////////////// block and deschedule if no clients 2974 if( xlist_is_empty( root_xp ) == false ) 2975 { 2976 // release the lock protecting the TX client sockets queue 2977 remote_busylock_release( lock_xp ); 2978 2979 // block and deschedule 2980 thread_block( XPTR( local_cxy , this ) , THREAD_BLOCKED_CLIENT ); 2981 sched_yield( "waiting client" ); 2982 } 2983 ////////////// 2984 else 2985 { 2986 // get first client socket 2987 socket_xp = XLIST_FIRST( root_xp , socket_t , tx_list ); 2988 socket_cxy = GET_CXY( socket_xp ); 2989 socket_ptr = GET_PTR( socket_xp ); 2990 2991 // build extended pointer on socket xlist_entry 2992 entry_xp = XPTR( socket_cxy , &socket_ptr->tx_list ); 2993 2994 // remove this socket from the waiting queue 2995 xlist_unlink( entry_xp ); 2996 2997 // release the lock protecting the client sockets queue 2998 remote_busylock_release( lock_xp ); 2999 3000 // handle this TX client 3001 dev_nic_tx_handle_one_cmd( socket_xp, 3002 k_buf, 3003 chdev ); 3004 3005 // take the lock protecting the client sockets queue 3006 remote_busylock_acquire( lock_xp ); 3007 3008 // add this socket in last position of queue 3009 xlist_add_last( root_xp , entry_xp ); 3010 3011 // release the lock protecting the client sockets queue 3012 remote_busylock_release( lock_xp ); 3013 } 3014 } // end while 3015 } // end dev_nic_tx_server() 3016 3017
Note: See TracChangeset
for help on using the changeset viewer.