Rev 4720 | Rev 4722 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 4720 | Rev 4721 | ||
|---|---|---|---|
| Line 37... | Line 37... | ||
| 37 | 37 | ||
| 38 | #include <async.h> |
38 | #include <async.h> |
| 39 | #include <atomic.h> |
39 | #include <atomic.h> |
| 40 | #include <fibril.h> |
40 | #include <fibril.h> |
| 41 | #include <fibril_sync.h> |
41 | #include <fibril_sync.h> |
| - | 42 | #include <stdint.h> |
|
| 42 | 43 | ||
| 43 | #include <ipc/ipc.h> |
44 | #include <ipc/ipc.h> |
| 44 | #include <ipc/services.h> |
45 | #include <ipc/services.h> |
| 45 | 46 | ||
| 46 | #include <sys/types.h> |
47 | #include <sys/types.h> |
| Line 76... | Line 77... | ||
| 76 | 77 | ||
| 77 | /** Original datagram length in bytes transfered to the error notification message. |
78 | /** Original datagram length in bytes transfered to the error notification message. |
| 78 | */ |
79 | */ |
| 79 | #define ICMP_KEEP_LENGTH 8 |
80 | #define ICMP_KEEP_LENGTH 8 |
| 80 | 81 | ||
| - | 82 | /** Free identifier numbers pool start. |
|
| - | 83 | */ |
|
| - | 84 | #define ICMP_FREE_IDS_START 1 |
|
| - | 85 | ||
| - | 86 | /** Free identifier numbers pool end. |
|
| - | 87 | */ |
|
| - | 88 | #define ICMP_FREE_IDS_END MAX_UINT16 |
|
| - | 89 | ||
| 81 | /** Computes the ICMP datagram checksum. |
90 | /** Computes the ICMP datagram checksum. |
| 82 | * @param header The ICMP datagram header. Input/output parameter. |
91 | * @param header The ICMP datagram header. Input/output parameter. |
| 83 | * @param length The total datagram length. Input parameter. |
92 | * @param length The total datagram length. Input parameter. |
| 84 | * @returns The computed checksum. |
93 | * @returns The computed checksum. |
| 85 | */ |
94 | */ |
| Line 224... | Line 233... | ||
| 224 | * @returns EOK on success. |
233 | * @returns EOK on success. |
| 225 | * @returns EINVAL if the data parameter is NULL. |
234 | * @returns EINVAL if the data parameter is NULL. |
| 226 | */ |
235 | */ |
| 227 | int icmp_timeout_for_reply( void * data ); |
236 | int icmp_timeout_for_reply( void * data ); |
| 228 | 237 | ||
| - | 238 | /** Assigns a new identifier for the connection. |
|
| - | 239 | * Fills the echo data parameter with the assigned values. |
|
| - | 240 | * @param echo_data The echo data to be bound. Input/output parameter. |
|
| - | 241 | * @returns Index of the inserted echo data. |
|
| - | 242 | * @returns EBADMEM if the echo_data parameter is NULL. |
|
| - | 243 | * @returns ENOTCONN if no free identifier have been found. |
|
| - | 244 | */ |
|
| - | 245 | int icmp_bind_free_id( icmp_echo_ref echo_data ); |
|
| - | 246 | ||
| 229 | /** ICMP reply timeout data. |
247 | /** ICMP reply timeout data. |
| 230 | * Used as a timeouting fibril argument. |
248 | * Used as a timeouting fibril argument. |
| 231 | * @see icmp_timeout_for_reply() |
249 | * @see icmp_timeout_for_reply() |
| 232 | */ |
250 | */ |
| 233 | struct icmp_reply_timeout{ |
251 | struct icmp_reply_timeout{ |
| Line 243... | Line 261... | ||
| 243 | */ |
261 | */ |
| 244 | icmp_globals_t icmp_globals; |
262 | icmp_globals_t icmp_globals; |
| 245 | 263 | ||
| 246 | INT_MAP_IMPLEMENT( icmp_replies, icmp_reply_t ); |
264 | INT_MAP_IMPLEMENT( icmp_replies, icmp_reply_t ); |
| 247 | 265 | ||
| 248 | GENERIC_FIELD_IMPLEMENT( icmp_echo_data, icmp_echo_t ); |
266 | INT_MAP_IMPLEMENT( icmp_echo_data, icmp_echo_t ); |
| 249 | 267 | ||
| 250 | int icmp_echo_msg( int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){ |
268 | int icmp_echo_msg( int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){ |
| 251 | icmp_echo_ref echo_data; |
269 | icmp_echo_ref echo_data; |
| 252 | int res; |
270 | int res; |
| 253 | 271 | ||
| 254 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
272 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
| 255 | // use the phone as the echo data index |
273 | // use the phone as the echo data index |
| 256 | echo_data = icmp_echo_data_get_index( & icmp_globals.echo_data, icmp_phone ); |
274 | echo_data = icmp_echo_data_find( & icmp_globals.echo_data, icmp_phone ); |
| 257 | if( ! echo_data ){ |
275 | if( ! echo_data ){ |
| 258 | res = ENOENT; |
276 | res = ENOENT; |
| 259 | }else{ |
277 | }else{ |
| 260 | res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen ); |
278 | res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen ); |
| - | 279 | if( echo_data->sequence < MAX_UINT16 ){ |
|
| 261 | ++ echo_data->sequence; |
280 | ++ echo_data->sequence; |
| - | 281 | }else{ |
|
| - | 282 | echo_data->sequence = 0; |
|
| - | 283 | } |
|
| 262 | } |
284 | } |
| 263 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
285 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
| 264 | return res; |
286 | return res; |
| 265 | } |
287 | } |
| 266 | 288 | ||
| Line 429... | Line 451... | ||
| 429 | return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP ); |
451 | return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP ); |
| 430 | } |
452 | } |
| 431 | 453 | ||
| 432 | icmp_header_ref icmp_prepare_packet( packet_t packet ){ |
454 | icmp_header_ref icmp_prepare_packet( packet_t packet ){ |
| 433 | icmp_header_ref header; |
455 | icmp_header_ref header; |
| 434 | int header_length; |
456 | size_t header_length; |
| 435 | size_t total_length; |
457 | size_t total_length; |
| 436 | 458 | ||
| 437 | total_length = packet_get_data_length( packet ); |
459 | total_length = packet_get_data_length( packet ); |
| 438 | if( total_length <= 0 ) return NULL; |
460 | if( total_length <= 0 ) return NULL; |
| 439 | header_length = ip_client_header_length( packet ); |
461 | header_length = ip_client_header_length( packet ); |
| 440 | if( header_length <= 0 ) return NULL; |
462 | if( header_length <= 0 ) return NULL; |
| 441 | // truncate if longer than 64 bits (without the IP header) |
463 | // truncate if longer than 64 bits (without the IP header) |
| 442 | if(( total_length - header_length > ICMP_KEEP_LENGTH ) |
464 | if(( total_length > header_length + ICMP_KEEP_LENGTH ) |
| 443 | && ( packet_trim( packet, 0, total_length - header_length - ICMP_KEEP_LENGTH ) != EOK )){ |
465 | && ( packet_trim( packet, 0, total_length - header_length - ICMP_KEEP_LENGTH ) != EOK )){ |
| 444 | return NULL; |
466 | return NULL; |
| 445 | } |
467 | } |
| 446 | header = PACKET_PREFIX( packet, icmp_header_t ); |
468 | header = PACKET_PREFIX( packet, icmp_header_t ); |
| 447 | if( ! header ) return NULL; |
469 | if( ! header ) return NULL; |
| Line 466... | Line 488... | ||
| 466 | return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error ); |
488 | return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error ); |
| 467 | } |
489 | } |
| 468 | 490 | ||
| 469 | int icmp_connect_module( services_t service ){ |
491 | int icmp_connect_module( services_t service ){ |
| 470 | icmp_echo_ref echo_data; |
492 | icmp_echo_ref echo_data; |
| - | 493 | icmp_param_t id; |
|
| 471 | int index; |
494 | int index; |
| 472 | 495 | ||
| 473 | echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data )); |
496 | echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data )); |
| 474 | if( ! echo_data ) return ENOMEM; |
497 | if( ! echo_data ) return ENOMEM; |
| 475 | // assign a new identifier |
498 | // assign a new identifier |
| 476 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
499 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
| 477 | ++ icmp_globals.last_used_id; |
- | |
| 478 | echo_data->id = icmp_globals.last_used_id; |
- | |
| 479 | echo_data->sequence = 0; |
- | |
| 480 | // remember the assigned echo data |
- | |
| 481 | index = icmp_echo_data_add( & icmp_globals.echo_data, echo_data ); |
500 | index = icmp_bind_free_id( echo_data ); |
| 482 | if( index < 0 ){ |
501 | if( index < 0 ){ |
| 483 | free( echo_data ); |
502 | free( echo_data ); |
| - | 503 | }else{ |
|
| - | 504 | id = echo_data->id; |
|
| 484 | } |
505 | } |
| 485 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
506 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
| 486 | // return the echo data index as the ICMP phone |
507 | // return the echo data identifier as the ICMP phone |
| 487 | return index; |
508 | return id; |
| 488 | } |
509 | } |
| 489 | 510 | ||
| 490 | int icmp_initialize( async_client_conn_t client_connection ){ |
511 | int icmp_initialize( async_client_conn_t client_connection ){ |
| 491 | ERROR_DECLARE; |
512 | ERROR_DECLARE; |
| 492 | 513 | ||
| Line 542... | Line 563... | ||
| 542 | 563 | ||
| 543 | if( error ){ |
564 | if( error ){ |
| 544 | switch( error ){ |
565 | switch( error ){ |
| 545 | case SERVICE_ICMP: |
566 | case SERVICE_ICMP: |
| 546 | // process error |
567 | // process error |
| 547 | // TODO remove debug dump |
- | |
| 548 | // length = icmp_client_header_length( packet ); |
- | |
| 549 | result = icmp_client_process_packet( packet, & type, & code, NULL, NULL ); |
568 | result = icmp_client_process_packet( packet, & type, & code, NULL, NULL ); |
| 550 | if( result < 0 ) return result; |
569 | if( result < 0 ) return result; |
| 551 | length = ( size_t ) result; |
570 | length = ( size_t ) result; |
| - | 571 | // TODO remove debug dump |
|
| 552 | printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) ); |
572 | printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) ); |
| - | 573 | // remove the error header |
|
| 553 | ERROR_PROPAGATE( packet_trim( packet, length, 0 )); |
574 | ERROR_PROPAGATE( packet_trim( packet, length, 0 )); |
| 554 | break; |
575 | break; |
| 555 | default: |
576 | default: |
| 556 | return ENOTSUP; |
577 | return ENOTSUP; |
| 557 | } |
578 | } |
| 558 | } |
579 | } |
| 559 | // get rid of the ip header |
580 | // get rid of the ip header |
| 560 | result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL ); |
581 | length = ip_client_header_length( packet ); |
| 561 | if( result < 0 ) return result; |
- | |
| 562 | ERROR_PROPAGATE( packet_trim( packet, ( size_t ) result, 0 )); |
582 | ERROR_PROPAGATE( packet_trim( packet, length, 0 )); |
| 563 | 583 | ||
| 564 | length = packet_get_data_length( packet ); |
584 | length = packet_get_data_length( packet ); |
| 565 | if( length <= 0 ) return EINVAL; |
585 | if( length <= 0 ) return EINVAL; |
| 566 | if( length < sizeof( icmp_header_t )) return EINVAL; |
586 | if( length < sizeof( icmp_header_t )) return EINVAL; |
| 567 | data = packet_get_data( packet ); |
587 | data = packet_get_data( packet ); |
| 568 | if( ! data ) return EINVAL; |
588 | if( ! data ) return EINVAL; |
| 569 | // get icmp header |
589 | // get icmp header |
| 570 | header = ( icmp_header_ref ) data; |
590 | header = ( icmp_header_ref ) data; |
| 571 | // checksum |
591 | // checksum |
| 572 | /* if(( header->checksum ) && ( ICMP_CHECKSUM( header, length ))){ |
- | |
| 573 | // set the original message type on error notification |
- | |
| 574 | // type swap observed in Qemu |
- | |
| 575 | if( error ){ |
- | |
| 576 | switch( header->type ){ |
- | |
| 577 | case ICMP_ECHOREPLY: |
- | |
| 578 | header->type = ICMP_ECHO; |
- | |
| 579 | break; |
- | |
| 580 | } |
- | |
| 581 | } |
- | |
| 582 | if( ICMP_CHECKSUM( header, length )){ |
- | |
| 583 | return EINVAL; |
- | |
| 584 | } |
- | |
| 585 | } |
- | |
| 586 | */ if( header->checksum ){ |
592 | if( header->checksum ){ |
| 587 | while( ICMP_CHECKSUM( header, length )){ |
593 | while( ICMP_CHECKSUM( header, length )){ |
| 588 | // set the original message type on error notification |
594 | // set the original message type on error notification |
| 589 | // type swap observed in Qemu |
595 | // type swap observed in Qemu |
| 590 | if( error ){ |
596 | if( error ){ |
| 591 | switch( header->type ){ |
597 | switch( header->type ){ |
| Line 691... | Line 697... | ||
| 691 | fibril_rwlock_t lock; |
697 | fibril_rwlock_t lock; |
| 692 | ipc_call_t answer; |
698 | ipc_call_t answer; |
| 693 | int answer_count; |
699 | int answer_count; |
| 694 | size_t length; |
700 | size_t length; |
| 695 | struct sockaddr * addr; |
701 | struct sockaddr * addr; |
| 696 | icmp_param_t id; |
- | |
| 697 | icmp_param_t sequence = 0; |
- | |
| 698 | ipc_callid_t data_callid; |
702 | ipc_callid_t data_callid; |
| - | 703 | icmp_echo_ref echo_data; |
|
| 699 | 704 | ||
| 700 | /* |
705 | /* |
| 701 | * Accept the connection |
706 | * Accept the connection |
| 702 | * - Answer the first NET_ICMP_INIT call. |
707 | * - Answer the first NET_ICMP_INIT call. |
| 703 | */ |
708 | */ |
| 704 | ipc_answer_0( callid, EOK ); |
709 | ipc_answer_0( callid, EOK ); |
| 705 | 710 | ||
| 706 | fibril_rwlock_initialize( & lock ); |
711 | fibril_rwlock_initialize( & lock ); |
| 707 | 712 | ||
| - | 713 | echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data )); |
|
| - | 714 | if( ! echo_data ) return ENOMEM; |
|
| 708 | // assign a new identifier |
715 | // assign a new identifier |
| 709 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
716 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
| 710 | ++ icmp_globals.last_used_id; |
- | |
| 711 | id = icmp_globals.last_used_id; |
717 | ERROR_CODE = icmp_bind_free_id( echo_data ); |
| 712 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
718 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
| - | 719 | if( ERROR_CODE < 0 ){ |
|
| - | 720 | free( echo_data ); |
|
| - | 721 | return ERROR_CODE; |
|
| - | 722 | } |
|
| 713 | 723 | ||
| 714 | while( keep_on_going ){ |
724 | while( keep_on_going ){ |
| 715 | refresh_answer( & answer, & answer_count ); |
725 | refresh_answer( & answer, & answer_count ); |
| 716 | 726 | ||
| 717 | callid = async_get_call( & call ); |
727 | callid = async_get_call( & call ); |
| Line 730... | Line 740... | ||
| 730 | if( ! addr ){ |
740 | if( ! addr ){ |
| 731 | ERROR_CODE = ENOMEM; |
741 | ERROR_CODE = ENOMEM; |
| 732 | }else{ |
742 | }else{ |
| 733 | if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, length ))){ |
743 | if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, length ))){ |
| 734 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
744 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
| 735 | ERROR_CODE = icmp_echo( id, sequence, ICMP_GET_SIZE( call ), ICMP_GET_TIMEOUT( call ), ICMP_GET_TTL( call ), ICMP_GET_TOS( call ), ICMP_GET_DONT_FRAGMENT( call ), addr, ( socklen_t ) length ); |
745 | ERROR_CODE = icmp_echo( echo_data->id, echo_data->sequence, ICMP_GET_SIZE( call ), ICMP_GET_TIMEOUT( call ), ICMP_GET_TTL( call ), ICMP_GET_TOS( call ), ICMP_GET_DONT_FRAGMENT( call ), addr, ( socklen_t ) length ); |
| 736 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
746 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
| 737 | free( addr ); |
747 | free( addr ); |
| - | 748 | if( echo_data->sequence < MAX_UINT16 ){ |
|
| 738 | ++ sequence; |
749 | ++ echo_data->sequence; |
| - | 750 | }else{ |
|
| - | 751 | echo_data->sequence = 0; |
|
| - | 752 | } |
|
| 739 | } |
753 | } |
| 740 | } |
754 | } |
| 741 | } |
755 | } |
| 742 | fibril_rwlock_write_unlock( & lock ); |
756 | fibril_rwlock_write_unlock( & lock ); |
| 743 | break; |
757 | break; |
| Line 746... | Line 760... | ||
| 746 | } |
760 | } |
| 747 | 761 | ||
| 748 | answer_call( callid, ERROR_CODE, & answer, answer_count ); |
762 | answer_call( callid, ERROR_CODE, & answer, answer_count ); |
| 749 | } |
763 | } |
| 750 | 764 | ||
| - | 765 | // release the identifier |
|
| - | 766 | fibril_rwlock_write_lock( & icmp_globals.lock ); |
|
| - | 767 | icmp_echo_data_exclude( & icmp_globals.echo_data, echo_data->id ); |
|
| - | 768 | fibril_rwlock_write_unlock( & icmp_globals.lock ); |
|
| 751 | return EOK; |
769 | return EOK; |
| 752 | } |
770 | } |
| 753 | 771 | ||
| 754 | int icmp_process_message( ipc_call_t * call ){ |
772 | int icmp_process_message( ipc_call_t * call ){ |
| 755 | ERROR_DECLARE; |
773 | ERROR_DECLARE; |
| Line 785... | Line 803... | ||
| 785 | int icmp_release_and_return( packet_t packet, int result ){ |
803 | int icmp_release_and_return( packet_t packet, int result ){ |
| 786 | pq_release( icmp_globals.net_phone, packet_get_id( packet )); |
804 | pq_release( icmp_globals.net_phone, packet_get_id( packet )); |
| 787 | return result; |
805 | return result; |
| 788 | } |
806 | } |
| 789 | 807 | ||
| - | 808 | int icmp_bind_free_id( icmp_echo_ref echo_data ){ |
|
| - | 809 | icmp_param_t index; |
|
| - | 810 | ||
| - | 811 | if( ! echo_data ) return EBADMEM; |
|
| - | 812 | // from the last used one |
|
| - | 813 | index = icmp_globals.last_used_id; |
|
| - | 814 | do{ |
|
| - | 815 | ++ index; |
|
| - | 816 | // til the range end |
|
| - | 817 | if( index >= ICMP_FREE_IDS_END ){ |
|
| - | 818 | // start from the range beginning |
|
| - | 819 | index = ICMP_FREE_IDS_START - 1; |
|
| - | 820 | do{ |
|
| - | 821 | ++ index; |
|
| - | 822 | // til the last used one |
|
| - | 823 | if( index >= icmp_globals.last_used_id ){ |
|
| - | 824 | // none found |
|
| - | 825 | return ENOTCONN; |
|
| - | 826 | } |
|
| - | 827 | }while( icmp_echo_data_find( & icmp_globals.echo_data, index ) != NULL ); |
|
| - | 828 | // found, break immediately |
|
| - | 829 | break; |
|
| - | 830 | } |
|
| - | 831 | }while( icmp_echo_data_find( & icmp_globals.echo_data, index ) != NULL ); |
|
| - | 832 | echo_data->id = index; |
|
| - | 833 | echo_data->sequence = 0; |
|
| - | 834 | return icmp_echo_data_add( & icmp_globals.echo_data, index, echo_data ); |
|
| - | 835 | } |
|
| - | 836 | ||
| 790 | /** @} |
837 | /** @} |
| 791 | */ |
838 | */ |