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 | */ |