Subversion Repositories HelenOS

Rev

Rev 4708 | Rev 4717 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4708 Rev 4711
Line 51... Line 51...
51
#include "../../messages.h"
51
#include "../../messages.h"
52
#include "../../modules.h"
52
#include "../../modules.h"
53
 
53
 
54
#include "../../include/net_interface.h"
54
#include "../../include/net_interface.h"
55
#include "../../include/inet.h"
55
#include "../../include/inet.h"
56
#include "../../include/socket.h"
56
#include "../../include/socket_codes.h"
57
#include "../../include/byteorder.h"
57
#include "../../include/byteorder.h"
58
#include "../../include/crc.h"
58
#include "../../include/crc.h"
59
#include "../../include/device.h"
59
#include "../../include/device.h"
60
#include "../../include/arp_interface.h"
60
#include "../../include/arp_interface.h"
61
#include "../../include/nil_interface.h"
61
#include "../../include/nil_interface.h"
Line 129... Line 129...
129
/** Returns the IP packet header checksum.
129
/** Returns the IP packet header checksum.
130
 *  @param header The IP packet header. Input parameter.
130
 *  @param header The IP packet header. Input parameter.
131
 */
131
 */
132
#define IP_HEADER_CHECKSUM( header )    ( htons( ip_checksum(( uint8_t * )( header ), IP_HEADER_LENGTH( header ))))
132
#define IP_HEADER_CHECKSUM( header )    ( htons( ip_checksum(( uint8_t * )( header ), IP_HEADER_LENGTH( header ))))
133
 
133
 
134
/** IP header checksum value for computed zero checksum.
-
 
135
 *  Zero is returned as 0xFFFF (not flipped)
-
 
136
 */
-
 
137
#define IP_HEADER_CHECKSUM_ZERO         0xFFFFu
-
 
138
 
-
 
139
/** IP global data.
134
/** IP global data.
140
 */
135
 */
141
ip_globals_t    ip_globals;
136
ip_globals_t    ip_globals;
142
 
137
 
143
DEVICE_MAP_IMPLEMENT( ip_netifs, ip_netif_t )
138
DEVICE_MAP_IMPLEMENT( ip_netifs, ip_netif_t )
Line 208... Line 203...
208
 
203
 
209
int ip_process_packet( device_id_t device_id, packet_t packet );
204
int ip_process_packet( device_id_t device_id, packet_t packet );
210
in_addr_t   ip_get_destination( ip_header_ref header );
205
in_addr_t   ip_get_destination( ip_header_ref header );
211
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error );
206
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error );
212
 
207
 
213
/** Computes the ip header checksum.
-
 
214
 *  To compute the checksum of a new packet, the checksum header field must be zero.
-
 
215
 *  To check the checksum of a received packet, the checksum may be left set.
-
 
216
 *  The zero (0) value will returned in this case if valid.
-
 
217
 *  @param data The header data. Input parameter.
-
 
218
 *  @param length The header length in bytes. Input parameter.
-
 
219
 *  @returns The internet protocol header checksum.
-
 
220
 *  @returns 0xFFFF if the computed checksum is zero.
-
 
221
 */
-
 
222
uint16_t ip_checksum( uint8_t * data, size_t length );
-
 
223
 
-
 
224
int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header );
208
int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header );
225
int ip_get_icmp_phone( void );
209
int ip_get_icmp_phone( void );
226
int ip_prepare_icmp( packet_t packet, ip_header_ref header );
210
int ip_prepare_icmp( packet_t packet, ip_header_ref header );
227
 
211
 
228
static int  release_and_return( packet_t packet, int result );
212
int ip_release_and_return( packet_t packet, int result );
229
 
-
 
230
uint16_t ip_checksum( uint8_t * data, size_t length ){
-
 
231
    uint16_t    checksum;
-
 
232
 
-
 
233
    checksum = compact_checksum(compute_checksum( 0, data, length ));
-
 
234
 
-
 
235
    // flip, zero is returned as 0xFFFF (not flipped)
-
 
236
    return ( ~ checksum ) ? ( uint16_t ) ( ~ checksum ) : IP_HEADER_CHECKSUM_ZERO;
-
 
237
}
-
 
238
 
213
 
239
int ip_initialize( async_client_conn_t client_connection ){
214
int ip_initialize( async_client_conn_t client_connection ){
240
    ERROR_DECLARE;
215
    ERROR_DECLARE;
241
 
216
 
242
    fibril_rwlock_initialize( & ip_globals.lock );
217
    fibril_rwlock_initialize( & ip_globals.lock );
Line 539... Line 514...
539
 
514
 
540
    // addresses in the host byte order
515
    // addresses in the host byte order
541
    // should be the next hop address or the target destination address
516
    // should be the next hop address or the target destination address
542
    length = packet_get_addr( packet, NULL, ( uint8_t ** ) & dest );
517
    length = packet_get_addr( packet, NULL, ( uint8_t ** ) & dest );
543
    if( length < 0 ){
518
    if( length < 0 ){
544
        return release_and_return( packet, length );
519
        return ip_release_and_return( packet, length );
545
    }
520
    }
546
    // TODO IPv6
521
    // TODO IPv6
547
    if( length != IP_ADDR ){
522
    if( length != IP_ADDR ){
548
        return release_and_return( packet, EINVAL );
523
        return ip_release_and_return( packet, EINVAL );
549
    }
524
    }
550
    fibril_rwlock_read_lock( & ip_globals.netifs_lock );
525
    fibril_rwlock_read_lock( & ip_globals.netifs_lock );
551
    // device specified?
526
    // device specified?
552
    if( device_id > 0 ){
527
    if( device_id > 0 ){
553
        netif = ip_netifs_find( & ip_globals.netifs, device_id );
528
        netif = ip_netifs_find( & ip_globals.netifs, device_id );
Line 570... Line 545...
570
        // do not send for broadcast, anycast packets or network broadcast
545
        // do not send for broadcast, anycast packets or network broadcast
571
        if(( ! dest->s_addr )
546
        if(( ! dest->s_addr )
572
        || ( !( ~ dest->s_addr ))
547
        || ( !( ~ dest->s_addr ))
573
        || ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
548
        || ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
574
        || ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
549
        || ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
575
            return release_and_return( packet, EINVAL );
550
            return ip_release_and_return( packet, EINVAL );
576
        }
551
        }
577
    }
552
    }
578
    // to me?
553
    // to me?
579
    if( route->address.s_addr == dest->s_addr ){
554
    if( route->address.s_addr == dest->s_addr ){
580
        // TODO loopback deliver
555
        // TODO loopback deliver
Line 583... Line 558...
583
    }
558
    }
584
 
559
 
585
    src = ip_netif_address( netif );
560
    src = ip_netif_address( netif );
586
    if( ! src ){
561
    if( ! src ){
587
        fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
562
        fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
588
        return release_and_return( packet, ENOENT );
563
        return ip_release_and_return( packet, ENOENT );
589
    }
564
    }
590
    if( ERROR_OCCURRED( ip_send_route( packet, netif, route, src, * dest, error ))){
565
    if( ERROR_OCCURRED( ip_send_route( packet, netif, route, src, * dest, error ))){
591
        pq_release( ip_globals.net_phone, packet_get_id( packet ));
566
        pq_release( ip_globals.net_phone, packet_get_id( packet ));
592
    }
567
    }
593
    fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
568
    fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
Line 924... Line 899...
924
    new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, ((( size_t ) address_length > addr_len ) ? ( size_t ) address_length : addr_len ));
899
    new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, ((( size_t ) address_length > addr_len ) ? ( size_t ) address_length : addr_len ));
925
    if( ! new_packet ) return ENOMEM;
900
    if( ! new_packet ) return ENOMEM;
926
    // allocate as much as originally
901
    // allocate as much as originally
927
    last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
902
    last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
928
    if( ! last_header ){
903
    if( ! last_header ){
929
        return release_and_return( packet, ENOMEM );
904
        return ip_release_and_return( packet, ENOMEM );
930
    }
905
    }
931
    ip_create_last_header( last_header, header );
906
    ip_create_last_header( last_header, header );
932
    // trim the unused space
907
    // trim the unused space
933
    if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
908
    if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
934
        return release_and_return( packet, ERROR_CODE );
909
        return ip_release_and_return( packet, ERROR_CODE );
935
    }
910
    }
936
    // biggest multiple of 8 lower than content
911
    // biggest multiple of 8 lower than content
937
    // TODO even fragmentation?
912
    // TODO even fragmentation?
938
    length = length & ( ~ 0x7 );// ( content / 8 ) * 8
913
    length = length & ( ~ 0x7 );// ( content / 8 ) * 8
939
    if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, last_header, (( IP_TOTAL_LENGTH( header ) - length ) % ( length - IP_HEADER_LENGTH( last_header ))), src, dest, address_length ))){
914
    if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, last_header, (( IP_TOTAL_LENGTH( header ) - length ) % ( length - IP_HEADER_LENGTH( last_header ))), src, dest, address_length ))){
940
        return release_and_return( packet, ERROR_CODE );
915
        return ip_release_and_return( packet, ERROR_CODE );
941
    }
916
    }
942
    // mark the first as fragmented
917
    // mark the first as fragmented
943
    header->flags |= IPFLAG_MORE_FRAGMENTS;
918
    header->flags |= IPFLAG_MORE_FRAGMENTS;
944
    // create middle framgents
919
    // create middle framgents
945
    while( IP_TOTAL_LENGTH( header ) > length ){
920
    while( IP_TOTAL_LENGTH( header ) > length ){
946
        new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( address_length >= addr_len ) ? address_length : addr_len ));
921
        new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( address_length >= addr_len ) ? address_length : addr_len ));
947
        if( ! new_packet ) return ENOMEM;
922
        if( ! new_packet ) return ENOMEM;
948
        middle_header = ip_create_middle_header( new_packet, last_header );
923
        middle_header = ip_create_middle_header( new_packet, last_header );
949
        if( ! middle_header ){
924
        if( ! middle_header ){
950
            return release_and_return( packet, ENOMEM );
925
            return ip_release_and_return( packet, ENOMEM );
951
        }
926
        }
952
        if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, address_length ))){
927
        if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, address_length ))){
953
            return release_and_return( packet, ERROR_CODE );
928
            return ip_release_and_return( packet, ERROR_CODE );
954
        }
929
        }
955
    }
930
    }
956
    // finish the first fragment
931
    // finish the first fragment
957
    header->header_checksum = IP_HEADER_CHECKSUM( header );
932
    header->header_checksum = IP_HEADER_CHECKSUM( header );
958
    return EOK;
933
    return EOK;
Line 1039... Line 1014...
1039
    ip_route_ref    route;
1014
    ip_route_ref    route;
1040
    int             phone;
1015
    int             phone;
1041
 
1016
 
1042
    header = ( ip_header_ref ) packet_get_data( packet );
1017
    header = ( ip_header_ref ) packet_get_data( packet );
1043
    if( ! header ){
1018
    if( ! header ){
1044
        return release_and_return( packet, ENOMEM );
1019
        return ip_release_and_return( packet, ENOMEM );
1045
    }
1020
    }
1046
    // checksum
1021
    // checksum
1047
    if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
1022
    if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
1048
        // TODO checksum error ICMP?
1023
        // TODO checksum error ICMP?
1049
        return release_and_return( packet, EINVAL );
1024
        return ip_release_and_return( packet, EINVAL );
1050
    }
1025
    }
1051
    if( header->ttl <= 1 ){
1026
    if( header->ttl <= 1 ){
1052
        phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1027
        phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1053
        if( phone >= 0 ){
1028
        if( phone >= 0 ){
1054
            // ttl oxceeded ICMP
1029
            // ttl oxceeded ICMP
Line 1099... Line 1074...
1099
 
1074
 
1100
    switch( error ){
1075
    switch( error ){
1101
        case SERVICE_ICMP:
1076
        case SERVICE_ICMP:
1102
            offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
1077
            offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
1103
            if( offset < 0 ){
1078
            if( offset < 0 ){
1104
                return release_and_return( packet, ENOMEM );
1079
                return ip_release_and_return( packet, ENOMEM );
1105
            }
1080
            }
1106
            data = packet_get_data( packet );
1081
            data = packet_get_data( packet );
1107
            header = ( ip_header_ref ) data + offset;
1082
            header = ( ip_header_ref ) data + offset;
1108
            // destination host unreachable?
1083
            // destination host unreachable?
1109
            if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
1084
            if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
Line 1121... Line 1096...
1121
                }
1096
                }
1122
                fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
1097
                fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
1123
            }
1098
            }
1124
            break;
1099
            break;
1125
        default:
1100
        default:
1126
            return release_and_return( packet, ENOTSUP );
1101
            return ip_release_and_return( packet, ENOTSUP );
1127
    }
1102
    }
1128
    return ip_deliver_local( device_id, packet, header, error );
1103
    return ip_deliver_local( device_id, packet, header, error );
1129
}
1104
}
1130
 
1105
 
1131
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error ){
1106
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error ){
Line 1202... Line 1177...
1202
int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header ){
1177
int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header ){
1203
    int phone;
1178
    int phone;
1204
 
1179
 
1205
    phone = ip_get_icmp_phone();
1180
    phone = ip_get_icmp_phone();
1206
    if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
1181
    if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
1207
        return release_and_return( packet, EINVAL );
1182
        return ip_release_and_return( packet, EINVAL );
1208
    }
1183
    }
1209
    return phone;
1184
    return phone;
1210
}
1185
}
1211
 
1186
 
1212
static int  release_and_return( packet_t packet, int result ){
1187
int ip_release_and_return( packet_t packet, int result ){
1213
    pq_release( ip_globals.net_phone, packet_get_id( packet ));
1188
    pq_release( ip_globals.net_phone, packet_get_id( packet ));
1214
    return result;
1189
    return result;
1215
}
1190
}
1216
 
1191
 
1217
/** @}
1192
/** @}