Subversion Repositories HelenOS

Rev

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