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