source: mainline/uspace/srv/net/il/ip/ip.c@ eac9722

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eac9722 was eac9722, checked in by Lukas Mejdrech <lukasmejdrech@…>, 15 years ago

+ ip treats outgoing zero (0) address as localhost

  • Property mode set to 100644
File size: 55.2 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ip
30 * @{
31 */
32
33/** @file
34 * IP module implementation.
35 * @see arp.h
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <fibril_synch.h>
41#include <stdio.h>
42#include <string.h>
43
44#include <ipc/ipc.h>
45#include <ipc/services.h>
46
47#include <sys/types.h>
48
49#include "../../err.h"
50#include "../../messages.h"
51#include "../../modules.h"
52
53#include "../../include/arp_interface.h"
54#include "../../include/byteorder.h"
55#include "../../include/checksum.h"
56#include "../../include/device.h"
57#include "../../include/icmp_client.h"
58#include "../../include/icmp_codes.h"
59#include "../../include/icmp_interface.h"
60#include "../../include/il_interface.h"
61#include "../../include/in.h"
62#include "../../include/in6.h"
63#include "../../include/inet.h"
64#include "../../include/ip_client.h"
65#include "../../include/ip_interface.h"
66#include "../../include/net_interface.h"
67#include "../../include/nil_interface.h"
68#include "../../include/tl_interface.h"
69#include "../../include/socket_codes.h"
70#include "../../include/socket_errno.h"
71#include "../../structures/measured_strings.h"
72#include "../../structures/module_map.h"
73#include "../../structures/packet/packet_client.h"
74
75#include "../../nil/nil_messages.h"
76
77#include "../il_messages.h"
78
79#include "ip.h"
80#include "ip_header.h"
81#include "ip_messages.h"
82#include "ip_module.h"
83
84/** IP version 4.
85 */
86#define IPV4 4
87
88/** Default network interface IP version.
89 */
90#define NET_DEFAULT_IPV IPV4
91
92/** Default network interface IP routing.
93 */
94#define NET_DEFAULT_IP_ROUTING false
95
96/** Minimum IP packet content.
97 */
98#define IP_MIN_CONTENT 576
99
100/** ARP module name.
101 */
102#define ARP_NAME "arp"
103
104/** ARP module filename.
105 */
106#define ARP_FILENAME "/srv/arp"
107
108/** IP packet address length.
109 */
110#define IP_ADDR sizeof( struct sockaddr_in6 )
111
112/** IP packet prefix length.
113 */
114#define IP_PREFIX sizeof( ip_header_t )
115
116/** IP packet suffix length.
117 */
118#define IP_SUFFIX 0
119
120/** IP packet maximum content length.
121 */
122#define IP_MAX_CONTENT 65535
123
124/** The IP localhost address.
125 */
126#define IPV4_LOCALHOST_ADDRESS htonl(( 127 << 24 ) + 1 )
127
128/** IP global data.
129 */
130ip_globals_t ip_globals;
131
132DEVICE_MAP_IMPLEMENT( ip_netifs, ip_netif_t )
133
134INT_MAP_IMPLEMENT( ip_protos, ip_proto_t )
135
136GENERIC_FIELD_IMPLEMENT( ip_routes, ip_route_t )
137
138/** Updates the device content length according to the new MTU value.
139 * @param[in] device_id The device identifier.
140 * @param[in] mtu The new mtu value.
141 * @returns EOK on success.
142 * @returns ENOENT if device is not found.
143 */
144int ip_mtu_changed_message( device_id_t device_id, size_t mtu );
145
146/** Updates the device state.
147 * @param[in] device_id The device identifier.
148 * @param[in] state The new state value.
149 * @returns EOK on success.
150 * @returns ENOENT if device is not found.
151 */
152int ip_device_state_message( device_id_t device_id, device_state_t state );
153
154/** Registers the transport layer protocol.
155 * The traffic of this protocol will be supplied using either the receive function or IPC message.
156 * @param[in] protocol The transport layer module protocol.
157 * @param[in] service The transport layer module service.
158 * @param[in] phone The transport layer module phone.
159 * @param[in] tl_received_msg The receiving function.
160 * @returns EOK on success.
161 * @returns EINVAL if the protocol parameter and/or the service parameter is zero (0).
162 * @returns EINVAL if the phone parameter is not a positive number and the tl_receive_msg is NULL.
163 * @returns ENOMEM if there is not enough memory left.
164 */
165int ip_register( int protocol, services_t service, int phone, tl_received_msg_t tl_received_msg );
166
167/** Initializes a new network interface specific data.
168 * Connects to the network interface layer module, reads the netif configuration, starts an ARP module if needed and sets the netif routing table.
169 * The device identifier and the nil service has to be set.
170 * @param[in,out] ip_netif Network interface specific data.
171 * @returns EOK on success.
172 * @returns ENOTSUP if DHCP is configured.
173 * @returns ENOTSUP if IPv6 is configured.
174 * @returns EINVAL if any of the addresses is invalid.
175 * @returns EINVAL if the used ARP module is not known.
176 * @returns ENOMEM if there is not enough memory left.
177 * @returns Other error codes as defined for the net_get_device_conf_req() function.
178 * @returns Other error codes as defined for the bind_service() function.
179 * @returns Other error codes as defined for the specific arp_device_req() function.
180 * @returns Other error codes as defined for the nil_packet_size_req() function.
181 */
182int ip_netif_initialize( ip_netif_ref ip_netif );
183
184/** Sends the packet or the packet queue via the specified route.
185 * The ICMP_HOST_UNREACH error notification may be sent if route hardware destination address is found.
186 * @param[in,out] packet The packet to be sent.
187 * @param[in] netif The target network interface.
188 * @param[in] route The target route.
189 * @param[in] src The source address.
190 * @param[in] dest The destination address.
191 * @param[in] error The error module service.
192 * @returns EOK on success.
193 * @returns Other error codes as defined for the arp_translate_req() function.
194 * @returns Other error codes as defined for the ip_prepare_packet() function.
195 */
196int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error );
197
198/** Prepares the outgoing packet or the packet queue.
199 * The packet queue is a fragmented packet
200 * Updates the first packet's IP header.
201 * Prefixes the additional packets with fragment headers.
202 * @param[in] source The source address.
203 * @param[in] dest The destination address.
204 * @param[in,out] packet The packet to be sent.
205 * @param[in] destination The destination hardware address.
206 * @returns EOK on success.
207 * @returns EINVAL if the packet is too small to contain the IP header.
208 * @returns EINVAL if the packet is too long than the IP allows.
209 * @returns ENOMEM if there is not enough memory left.
210 * @returns Other error codes as defined for the packet_set_addr() function.
211 */
212int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination );
213
214/** Checks the packet queue lengths and fragments the packets if needed.
215 * The ICMP_FRAG_NEEDED error notification may be sent if the packet needs to be fragmented and the fragmentation is not allowed.
216 * @param[in,out] packet The packet or the packet queue to be checked.
217 * @param[in] prefix The minimum prefix size.
218 * @param[in] content The maximum content size.
219 * @param[in] suffix The minimum suffix size.
220 * @param[in] addr_len The minimum address length.
221 * @param[in] error The error module service.
222 * @returns The packet or the packet queue of the allowed length.
223 * @returns NULL if there are no packets left.
224 */
225packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error );
226
227/** Checks the packet length and fragments it if needed.
228 * The new fragments are queued before the original packet.
229 * @param[in,out] packet The packet to be checked.
230 * @param[in] length The maximum packet length.
231 * @param[in] prefix The minimum prefix size.
232 * @param[in] suffix The minimum suffix size.
233 * @param[in] addr_len The minimum address length.
234 * @returns EOK on success.
235 * @returns EINVAL if the packet_get_addr() function fails.
236 * @returns EINVAL if the packet does not contain the IP header.
237 * @returns EPERM if the packet needs to be fragmented and the fragmentation is not allowed.
238 * @returns ENOMEM if there is not enough memory left.
239 * @returns ENOMEM if there is no packet available.
240 * @returns ENOMEM if the packet is too small to contain the IP header.
241 * @returns Other error codes as defined for the packet_trim() function.
242 * @returns Other error codes as defined for the ip_create_middle_header() function.
243 * @returns Other error codes as defined for the ip_fragment_packet_data() function.
244 */
245int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len );
246
247/** Fragments the packet from the end.
248 * @param[in] packet The packet to be fragmented.
249 * @param[in,out] new_packet The new packet fragment.
250 * @param[in,out] header The original packet header.
251 * @param[in,out] new_header The new packet fragment header.
252 * @param[in] length The new fragment length.
253 * @param[in] src The source address.
254 * @param[in] dest The destiantion address.
255 * @param[in] addrlen The address length.
256 * @returns EOK on success.
257 * @returns ENOMEM if the target packet is too small.
258 * @returns Other error codes as defined for the packet_set_addr() function.
259 * @returns Other error codes as defined for the pq_insert_after() function.
260 */
261int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen );
262
263/** Prefixes a middle fragment header based on the last fragment header to the packet.
264 * @param[in] packet The packet to be prefixed.
265 * @param[in] last The last header to be copied.
266 * @returns The prefixed middle header.
267 * @returns NULL on error.
268 */
269ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last );
270
271/** Copies the fragment header.
272 * Copies only the header itself and relevant IP options.
273 * @param[out] last The created header.
274 * @param[in] first The original header to be copied.
275 */
276void ip_create_last_header( ip_header_ref last, ip_header_ref first );
277
278/** Returns the network interface's IP address.
279 * @param[in] netif The network interface.
280 * @returns The IP address.
281 * @returns NULL if no IP address was found.
282 */
283in_addr_t * ip_netif_address( ip_netif_ref netif );
284
285/** Searches all network interfaces if there is a suitable route.
286 * @param[in] destination The destination address.
287 * @returns The found route.
288 * @returns NULL if no route was found.
289 */
290ip_route_ref ip_find_route( in_addr_t destination );
291
292/** Searches the network interfaces if there is a suitable route.
293 * @param[in] netif The network interface to be searched for routes. May be NULL.
294 * @param[in] destination The destination address.
295 * @returns The found route.
296 * @returns NULL if no route was found.
297 */
298ip_route_ref ip_netif_find_route( ip_netif_ref netif, in_addr_t destination );
299
300/** Processes the received IP packet or the packet queue one by one.
301 * The packet is either passed to another module or released on error.
302 * @param[in] device_id The source device identifier.
303 * @param[in,out] packet The received packet.
304 * @returns EOK on success and the packet is no longer needed.
305 * @returns EINVAL if the packet is too small to carry the IP packet.
306 * @returns EINVAL if the received address lengths differs from the registered values.
307 * @returns ENOENT if the device is not found in the cache.
308 * @returns ENOENT if the protocol for the device is not found in the cache.
309 * @returns ENOMEM if there is not enough memory left.
310 */
311int ip_receive_message( device_id_t device_id, packet_t packet );
312
313/** Processes the received packet.
314 * The packet is either passed to another module or released on error.
315 * The ICMP_PARAM_POINTER error notification may be sent if the checksum is invalid.
316 * The ICMP_EXC_TTL error notification may be sent if the TTL is less than two (2).
317 * The ICMP_HOST_UNREACH error notification may be sent if no route was found.
318 * The ICMP_HOST_UNREACH error notification may be sent if the packet is for another host and the routing is disabled.
319 * @param[in] device_id The source device identifier.
320 * @param[in] packet The received packet to be processed.
321 * @returns EOK on success.
322 * @returns EINVAL if the TTL is less than two (2).
323 * @returns EINVAL if the checksum is invalid.
324 * @returns EAFNOSUPPORT if the address family is not supported.
325 * @returns ENOENT if no route was found.
326 * @returns ENOENT if the packet is for another host and the routing is disabled.
327 */
328int ip_process_packet( device_id_t device_id, packet_t packet );
329
330/** Returns the packet destination address from the IP header.
331 * @param[in] header The packet IP header to be read.
332 * @returns The packet destination address.
333 */
334in_addr_t ip_get_destination( ip_header_ref header );
335
336/** Delivers the packet to the local host.
337 * The packet is either passed to another module or released on error.
338 * The ICMP_PROT_UNREACH error notification may be sent if the protocol is not found.
339 * @param[in] device_id The source device identifier.
340 * @param[in] packet The packet to be delivered.
341 * @param[in] header The first packet IP header. May be NULL.
342 * @param[in] error The packet error service.
343 * @returns EOK on success.
344 * @returns ENOTSUP if the packet is a fragment.
345 * @returns EAFNOSUPPORT if the address family is not supported.
346 * @returns ENOENT if the target protocol is not found.
347 * @returns Other error codes as defined for the packet_set_addr() function.
348 * @returns Other error codes as defined for the packet_trim() function.
349 * @returns Other error codes as defined for the protocol specific tl_received_msg function.
350 */
351int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error );
352
353/** Prepares the ICMP notification packet.
354 * Releases additional packets and keeps only the first one.
355 * All packets is released on error.
356 * @param[in] error The packet error service.
357 * @param[in] packet The packet or the packet queue to be reported as faulty.
358 * @param[in] header The first packet IP header. May be NULL.
359 * @returns The found ICMP phone.
360 * @returns EINVAL if the error parameter is set.
361 * @returns EINVAL if the ICMP phone is not found.
362 * @returns EINVAL if the ip_prepare_icmp() fails.
363 */
364int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header );
365
366/** Returns the ICMP phone.
367 * Searches the registered protocols.
368 * @returns The found ICMP phone.
369 * @returns ENOENT if the ICMP is not registered.
370 */
371int ip_get_icmp_phone( void );
372
373/** Prepares the ICMP notification packet.
374 * Releases additional packets and keeps only the first one.
375 * @param[in] packet The packet or the packet queue to be reported as faulty.
376 * @param[in] header The first packet IP header. May be NULL.
377 * @returns EOK on success.
378 * @returns EINVAL if there are no data in the packet.
379 * @returns EINVAL if the packet is a fragment.
380 * @returns ENOMEM if the packet is too short to contain the IP header.
381 * @returns EAFNOSUPPORT if the address family is not supported.
382 * @returns Other error codes as defined for the packet_set_addr().
383 */
384int ip_prepare_icmp( packet_t packet, ip_header_ref header );
385
386/** Releases the packet and returns the result.
387 * @param[in] packet The packet queue to be released.
388 * @param[in] result The result to be returned.
389 * @return The result parameter.
390 */
391int ip_release_and_return( packet_t packet, int result );
392
393int ip_initialize( async_client_conn_t client_connection ){
394 ERROR_DECLARE;
395
396 fibril_rwlock_initialize( & ip_globals.lock );
397 fibril_rwlock_write_lock( & ip_globals.lock );
398 fibril_rwlock_initialize( & ip_globals.protos_lock );
399 fibril_rwlock_initialize( & ip_globals.netifs_lock );
400 ip_globals.packet_counter = 0;
401 ip_globals.gateway.address.s_addr = 0;
402 ip_globals.gateway.netmask.s_addr = 0;
403 ip_globals.gateway.gateway.s_addr = 0;
404 ip_globals.gateway.netif = NULL;
405 ERROR_PROPAGATE( ip_netifs_initialize( & ip_globals.netifs ));
406 ERROR_PROPAGATE( ip_protos_initialize( & ip_globals.protos ));
407 ip_globals.client_connection = client_connection;
408 ERROR_PROPAGATE( modules_initialize( & ip_globals.modules ));
409 ERROR_PROPAGATE( add_module( NULL, & ip_globals.modules, ARP_NAME, ARP_FILENAME, SERVICE_ARP, arp_task_get_id(), arp_connect_module ));
410 fibril_rwlock_write_unlock( & ip_globals.lock );
411 return EOK;
412}
413
414int ip_device_req( int il_phone, device_id_t device_id, services_t netif ){
415 ERROR_DECLARE;
416
417 ip_netif_ref ip_netif;
418 ip_route_ref route;
419 int index;
420 char * data;
421
422 ip_netif = ( ip_netif_ref ) malloc( sizeof( ip_netif_t ));
423 if( ! ip_netif ) return ENOMEM;
424 if( ERROR_OCCURRED( ip_routes_initialize( & ip_netif->routes ))){
425 free( ip_netif );
426 return ERROR_CODE;
427 }
428 ip_netif->device_id = device_id;
429 ip_netif->service = netif;
430 ip_netif->state = NETIF_STOPPED;
431 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
432 if( ERROR_OCCURRED( ip_netif_initialize( ip_netif ))){
433 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
434 ip_routes_destroy( & ip_netif->routes );
435 free( ip_netif );
436 return ERROR_CODE;
437 }
438 if( ip_netif->arp ) ++ ip_netif->arp->usage;
439 // print the settings
440 printf( "New device registered:\n\tid\t= %d\n\tphone\t= %d\n\tIPV\t= %d\n", ip_netif->device_id, ip_netif->phone, ip_netif->ipv );
441 printf( "\tconfiguration\t= %s\n", ip_netif->dhcp ? "dhcp" : "static" );
442 // TODO ipv6 addresses
443 data = ( char * ) malloc( INET_ADDRSTRLEN );
444 if( data ){
445 for( index = 0; index < ip_routes_count( & ip_netif->routes ); ++ index ){
446 route = ip_routes_get_index( & ip_netif->routes, index );
447 if( route ){
448 printf( "\tRouting %d:\n", index );
449 inet_ntop( AF_INET, ( uint8_t * ) & route->address.s_addr, data, INET_ADDRSTRLEN );
450 printf( "\t\taddress\t= %s\n", data );
451 inet_ntop( AF_INET, ( uint8_t * ) & route->netmask.s_addr, data, INET_ADDRSTRLEN );
452 printf( "\t\tnetmask\t= %s\n", data );
453 inet_ntop( AF_INET, ( uint8_t * ) & route->gateway.s_addr, data, INET_ADDRSTRLEN );
454 printf( "\t\tgateway\t= %s\n", data );
455 }
456 }
457 inet_ntop( AF_INET, ( uint8_t * ) & ip_netif->broadcast.s_addr, data, INET_ADDRSTRLEN );
458 printf( "\t\tbroadcast\t= %s\n", data );
459 free( data );
460 }
461 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
462 return EOK;
463}
464
465int ip_netif_initialize( ip_netif_ref ip_netif ){
466 ERROR_DECLARE;
467
468 measured_string_t names[] = {{ "IPV", 3 }, { "IP_CONFIG", 9 }, { "IP_ADDR", 7 }, { "IP_NETMASK", 10 }, { "IP_GATEWAY", 10 }, { "IP_BROADCAST", 12 }, { "ARP", 3 }, { "IP_ROUTING", 10 }};
469 measured_string_ref configuration;
470 size_t count = sizeof( names ) / sizeof( measured_string_t );
471 char * data;
472 measured_string_t address;
473 int index;
474 ip_route_ref route;
475 in_addr_t gateway;
476
477 ip_netif->arp = NULL;
478 route = NULL;
479 ip_netif->ipv = NET_DEFAULT_IPV;
480 ip_netif->dhcp = false;
481 ip_netif->routing = NET_DEFAULT_IP_ROUTING;
482 configuration = & names[ 0 ];
483 // get configuration
484 ERROR_PROPAGATE( net_get_device_conf_req( ip_globals.net_phone, ip_netif->device_id, & configuration, count, & data ));
485 if( configuration ){
486 if( configuration[ 0 ].value ){
487 ip_netif->ipv = strtol( configuration[ 0 ].value, NULL, 0 );
488 }
489 ip_netif->dhcp = ! str_lcmp( configuration[ 1 ].value, "dhcp", configuration[ 1 ].length );
490 if( ip_netif->dhcp ){
491 // TODO dhcp
492 net_free_settings( configuration, data );
493 return ENOTSUP;
494 }else if( ip_netif->ipv == IPV4 ){
495 route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
496 if( ! route ){
497 net_free_settings( configuration, data );
498 return ENOMEM;
499 }
500 route->address.s_addr = 0;
501 route->netmask.s_addr = 0;
502 route->gateway.s_addr = 0;
503 route->netif = ip_netif;
504 index = ip_routes_add( & ip_netif->routes, route );
505 if( index < 0 ){
506 net_free_settings( configuration, data );
507 free( route );
508 return index;
509 }
510 if( ERROR_OCCURRED( inet_pton( AF_INET, configuration[ 2 ].value, ( uint8_t * ) & route->address.s_addr ))
511 || ERROR_OCCURRED( inet_pton( AF_INET, configuration[ 3 ].value, ( uint8_t * ) & route->netmask.s_addr ))
512 || ( inet_pton( AF_INET, configuration[ 4 ].value, ( uint8_t * ) & gateway.s_addr ) == EINVAL )
513 || ( inet_pton( AF_INET, configuration[ 5 ].value, ( uint8_t * ) & ip_netif->broadcast.s_addr ) == EINVAL )){
514 net_free_settings( configuration, data );
515 return EINVAL;
516 }
517 }else{
518 // TODO ipv6 in separate module
519 net_free_settings( configuration, data );
520 return ENOTSUP;
521 }
522 if( configuration[ 6 ].value ){
523 ip_netif->arp = get_running_module( & ip_globals.modules, configuration[ 6 ].value );
524 if( ! ip_netif->arp ){
525 printf( "Failed to start the arp %s\n", configuration[ 6 ].value );
526 net_free_settings( configuration, data );
527 return EINVAL;
528 }
529 }
530 if( configuration[ 7 ].value ){
531 ip_netif->routing = ( configuration[ 7 ].value[ 0 ] == 'y' );
532 }
533 net_free_settings( configuration, data );
534 }
535 // binds the netif service which also initializes the device
536 ip_netif->phone = nil_bind_service( ip_netif->service, ( ipcarg_t ) ip_netif->device_id, SERVICE_IP, ip_globals.client_connection );
537 if( ip_netif->phone < 0 ){
538 printf( "Failed to contact the nil service %d\n", ip_netif->service );
539 return ip_netif->phone;
540 }
541 // has to be after the device netif module initialization
542 if( ip_netif->arp ){
543 if( route ){
544 address.value = ( char * ) & route->address.s_addr;
545 address.length = CONVERT_SIZE( in_addr_t, char, 1 );
546 ERROR_PROPAGATE( arp_device_req( ip_netif->arp->phone, ip_netif->device_id, SERVICE_IP, ip_netif->service, & address ));
547 }else{
548 ip_netif->arp = 0;
549 }
550 }
551 // get packet dimensions
552 ERROR_PROPAGATE( nil_packet_size_req( ip_netif->phone, ip_netif->device_id, & ip_netif->addr_len, & ip_netif->prefix, & ip_netif->content, & ip_netif->suffix ));
553 if( ip_netif->content < IP_MIN_CONTENT ){
554 printf( "Maximum transmission unit %d bytes is too small, at least %d bytes are needed\n", ip_netif->content, IP_MIN_CONTENT );
555 ip_netif->content = IP_MIN_CONTENT;
556 }
557 index = ip_netifs_add( & ip_globals.netifs, ip_netif->device_id, ip_netif );
558 if( index < 0 ) return index;
559 if( gateway.s_addr ){
560 // the default gateway
561 ip_globals.gateway.address.s_addr = 0;
562 ip_globals.gateway.netmask.s_addr = 0;
563 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
564 ip_globals.gateway.netif = ip_netif;
565 }
566 return EOK;
567}
568
569int ip_mtu_changed_message( device_id_t device_id, size_t mtu ){
570 ip_netif_ref netif;
571
572 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
573 netif = ip_netifs_find( & ip_globals.netifs, device_id );
574 if( ! netif ){
575 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
576 return ENOENT;
577 }
578 netif->content = mtu;
579 printf( "ip - device %d changed mtu to %d\n\n", device_id, mtu );
580 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
581 return EOK;
582}
583
584int ip_device_state_message( device_id_t device_id, device_state_t state ){
585 ip_netif_ref netif;
586
587 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
588 // find the device
589 netif = ip_netifs_find( & ip_globals.netifs, device_id );
590 if( ! netif ){
591 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
592 return ENOENT;
593 }
594 netif->state = state;
595 printf( "ip - device %d changed state to %d\n\n", device_id, state );
596 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
597 return EOK;
598}
599
600int ip_connect_module( services_t service ){
601 return EOK;
602}
603
604int ip_bind_service( services_t service, int protocol, services_t me, async_client_conn_t receiver, tl_received_msg_t received_msg ){
605 return ip_register( protocol, me, 0, received_msg );
606}
607
608int ip_register( int protocol, services_t service, int phone, tl_received_msg_t received_msg ){
609 ip_proto_ref proto;
610 int index;
611
612 if( !( protocol && service && (( phone > 0 ) || ( received_msg )))) return EINVAL;
613 proto = ( ip_proto_ref ) malloc( sizeof( ip_protos_t ));
614 if( ! proto ) return ENOMEM;
615 proto->protocol = protocol;
616 proto->service = service;
617 proto->phone = phone;
618 proto->received_msg = received_msg;
619 fibril_rwlock_write_lock( & ip_globals.protos_lock );
620 index = ip_protos_add( & ip_globals.protos, proto->protocol, proto );
621 if( index < 0 ){
622 fibril_rwlock_write_unlock( & ip_globals.protos_lock );
623 free( proto );
624 return index;
625 }
626 printf( "New protocol registered:\n\tprotocol\t= %d\n\tphone\t= %d\n", proto->protocol, proto->phone );
627 fibril_rwlock_write_unlock( & ip_globals.protos_lock );
628 return EOK;
629}
630
631int ip_send_msg( int il_phone, device_id_t device_id, packet_t packet, services_t sender, services_t error ){
632 ERROR_DECLARE;
633
634 int addrlen;
635 ip_netif_ref netif;
636 ip_route_ref route;
637 struct sockaddr * addr;
638 struct sockaddr_in * address_in;
639// struct sockaddr_in6 * address_in6;
640 in_addr_t * dest;
641 in_addr_t * src;
642 int phone;
643
644 // addresses in the host byte order
645 // should be the next hop address or the target destination address
646 addrlen = packet_get_addr( packet, NULL, ( uint8_t ** ) & addr );
647 if( addrlen < 0 ){
648 return ip_release_and_return( packet, addrlen );
649 }
650 if(( size_t ) addrlen < sizeof( struct sockaddr )){
651 return ip_release_and_return( packet, EINVAL );
652 }
653 switch( addr->sa_family ){
654 case AF_INET:
655 if( addrlen != sizeof( struct sockaddr_in )){
656 return ip_release_and_return( packet, EINVAL );
657 }
658 address_in = ( struct sockaddr_in * ) addr;
659 dest = & address_in->sin_addr;
[eac9722]660 if( ! dest->s_addr ){
661 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
662 }
[21580dd]663 break;
664 // TODO IPv6
665/* case AF_INET6:
666 if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
667 address_in6 = ( struct sockaddr_in6 * ) dest;
668 address_in6.sin6_addr.s6_addr;
[eac9722]669 IPV6_LOCALHOST_ADDRESS;
[21580dd]670*/ default:
671 return ip_release_and_return( packet, EAFNOSUPPORT );
672 }
673 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
674 // device specified?
675 if( device_id > 0 ){
676 netif = ip_netifs_find( & ip_globals.netifs, device_id );
677 route = ip_netif_find_route( netif, * dest );
678 if( netif && ( ! route ) && ( ip_globals.gateway.netif == netif )){
679 route = & ip_globals.gateway;
680 }
681 }else{
682 route = ip_find_route( * dest );
683 netif = route ? route->netif : NULL;
684 }
685 if( !( netif && route )){
686 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
687 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
688 if( phone >= 0 ){
689 // unreachable ICMP if no routing
690 icmp_destination_unreachable_msg( phone, ICMP_NET_UNREACH, 0, packet );
691 }
692 return ENOENT;
693 }
694 if( error ){
695 // do not send for broadcast, anycast packets or network broadcast
696 if(( ! dest->s_addr )
697 || ( !( ~ dest->s_addr ))
698 || ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
699 || ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
700 return ip_release_and_return( packet, EINVAL );
701 }
702 }
703 if( route->address.s_addr == dest->s_addr ){
704 // find the loopback device to deliver
705 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
706 route = ip_find_route( * dest );
707 netif = route ? route->netif : NULL;
708 if( !( netif && route )){
709 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
710 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
711 if( phone >= 0 ){
712 // unreachable ICMP if no routing
713 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
714 }
715 return ENOENT;
716 }
717 }
718 src = ip_netif_address( netif );
719 if( ! src ){
720 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
721 return ip_release_and_return( packet, ENOENT );
722 }
723 ERROR_CODE = ip_send_route( packet, netif, route, src, * dest, error );
724 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
725 return ERROR_CODE;
726}
727
728in_addr_t * ip_netif_address( ip_netif_ref netif ){
729 ip_route_ref route;
730
731 route = ip_routes_get_index( & netif->routes, 0 );
732 return route ? & route->address : NULL;
733}
734
735int ip_send_route( packet_t packet, ip_netif_ref netif, ip_route_ref route, in_addr_t * src, in_addr_t dest, services_t error ){
736 ERROR_DECLARE;
737
738 measured_string_t destination;
739 measured_string_ref translation;
740 char * data;
741 int phone;
742
743 // get destination hardware address
744 if( netif->arp && ( route->address.s_addr != dest.s_addr )){
745 destination.value = route->gateway.s_addr ? ( char * ) & route->gateway.s_addr : ( char * ) & dest.s_addr;
746 destination.length = CONVERT_SIZE( dest.s_addr, char, 1 );
747 if( ERROR_OCCURRED( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ))){
748// sleep( 1 );
749// ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
750 pq_release( ip_globals.net_phone, packet_get_id( packet ));
751 return ERROR_CODE;
752 }
753 if( !( translation && translation->value )){
754 if( translation ){
755 free( translation );
756 free( data );
757 }
758 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
759 if( phone >= 0 ){
760 // unreachable ICMP if no routing
761 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
762 }
763 return EINVAL;
764 }
765 }else translation = NULL;
766 if( ERROR_OCCURRED( ip_prepare_packet( src, dest, packet, translation ))){
767 pq_release( ip_globals.net_phone, packet_get_id( packet ));
768 }else{
769 packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len, error );
770 if( packet ){
771 nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP );
772 }
773 }
774 if( translation ){
775 free( translation );
776 free( data );
777 }
778 return ERROR_CODE;
779}
780
781int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination ){
782 ERROR_DECLARE;
783
784 size_t length;
785 ip_header_ref header;
786 ip_header_ref last_header;
787 ip_header_ref middle_header;
788 packet_t next;
789
790 length = packet_get_data_length( packet );
791 if(( length < sizeof( ip_header_t )) || ( length > IP_MAX_CONTENT )) return EINVAL;
792 header = ( ip_header_ref ) packet_get_data( packet );
793 if( destination ){
794 ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
795 }else{
796 ERROR_PROPAGATE( packet_set_addr( packet, NULL, NULL, 0 ));
797 }
798 header->version = IPV4;
799 header->fragment_offset_high = 0;
800 header->fragment_offset_low = 0;
801 header->header_checksum = 0;
802 if( source ) header->source_address = source->s_addr;
803 header->destination_address = dest.s_addr;
804 fibril_rwlock_write_lock( & ip_globals.lock );
805 ++ ip_globals.packet_counter;
806 header->identification = htons( ip_globals.packet_counter );
807 fibril_rwlock_write_unlock( & ip_globals.lock );
808// length = packet_get_data_length( packet );
809 if( pq_next( packet )){
810 last_header = ( ip_header_ref ) malloc( IP_HEADER_LENGTH( header ));
811 if( ! last_header ) return ENOMEM;
812 ip_create_last_header( last_header, header );
813 next = pq_next( packet );
814 while( pq_next( next )){
815 middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
816 if( ! middle_header ) return ENOMEM;
817 memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
818 header->flags |= IPFLAG_MORE_FRAGMENTS;
819 middle_header->total_length = htons( packet_get_data_length( next ));
820 middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
821 middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
822 middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
823 if( destination ){
824 ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
825 }
826 length += packet_get_data_length( next );
827 next = pq_next( next );
828 }
829 middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
830 if( ! middle_header ) return ENOMEM;
831 memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
832 middle_header->total_length = htons( packet_get_data_length( next ));
833 middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
834 middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
835 middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
836 if( destination ){
837 ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
838 }
839 length += packet_get_data_length( next );
840 free( last_header );
841 header->flags |= IPFLAG_MORE_FRAGMENTS;
842 }
843 header->total_length = htons( length );
844 // unnecessary for all protocols
845 header->header_checksum = IP_HEADER_CHECKSUM( header );
846 return EOK;
847}
848
849int ip_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
850 ERROR_DECLARE;
851
852 packet_t packet;
853 struct sockaddr * addr;
854 size_t addrlen;
855 ip_pseudo_header_ref header;
856 size_t headerlen;
857
858 * answer_count = 0;
859 switch( IPC_GET_METHOD( * call )){
860 case IPC_M_PHONE_HUNGUP:
861 return EOK;
862 case NET_IL_DEVICE:
863 return ip_device_req( 0, IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ));
864 case IPC_M_CONNECT_TO_ME:
865 return ip_register( IL_GET_PROTO( call ), IL_GET_SERVICE( call ), IPC_GET_PHONE( call ), NULL );
866 case NET_IL_SEND:
867 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
868 return ip_send_msg( 0, IPC_GET_DEVICE( call ), packet, 0, IPC_GET_ERROR( call ));
869 case NET_IL_DEVICE_STATE:
870 return ip_device_state_message( IPC_GET_DEVICE( call ), IPC_GET_STATE( call ));
871 case NET_IL_RECEIVED:
872 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
873 return ip_receive_message( IPC_GET_DEVICE( call ), packet );
874 case NET_IP_RECEIVED_ERROR:
875 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
876 return ip_received_error_msg( 0, IPC_GET_DEVICE( call ), packet, IPC_GET_TARGET( call ), IPC_GET_ERROR( call ));
877 case NET_IP_ADD_ROUTE:
878 return ip_add_route_req( 0, IPC_GET_DEVICE( call ), IP_GET_ADDRESS( call ), IP_GET_NETMASK( call ), IP_GET_GATEWAY( call ));
879 case NET_IP_SET_GATEWAY:
880 return ip_set_gateway_req( 0, IPC_GET_DEVICE( call ), IP_GET_GATEWAY( call ));
881 case NET_IP_GET_ROUTE:
882 ERROR_PROPAGATE( data_receive(( void ** ) & addr, & addrlen ));
883 ERROR_PROPAGATE( ip_get_route_req( 0, IP_GET_PROTOCOL( call ), addr, ( socklen_t ) addrlen, IPC_SET_DEVICE( answer ), & header, & headerlen ));
884 * IP_SET_HEADERLEN( answer ) = headerlen;
885 * answer_count = 2;
886 if( ! ERROR_OCCURRED( data_reply( & headerlen, sizeof( headerlen )))){
887 ERROR_CODE = data_reply( header, headerlen );
888 }
889 free( header );
890 return ERROR_CODE;
891 case NET_IL_PACKET_SPACE:
892 ERROR_PROPAGATE( ip_packet_size_req( 0, IPC_GET_DEVICE( call ), IPC_SET_ADDR( answer ), IPC_SET_PREFIX( answer ), IPC_SET_CONTENT( answer ), IPC_SET_SUFFIX( answer )));
893 * answer_count = 3;
894 return EOK;
895 case NET_IL_MTU_CHANGED:
896 return ip_mtu_changed_message( IPC_GET_DEVICE( call ), IPC_GET_MTU( call ));
897 }
898 return ENOTSUP;
899}
900
901int ip_packet_size_req( int ip_phone, device_id_t device_id, size_t * addr_len, size_t * prefix, size_t * content, size_t * suffix ){
902 ip_netif_ref netif;
903 int index;
904
905 if( !( addr_len && prefix && content && suffix )) return EBADMEM;
906 * content = IP_MAX_CONTENT - IP_PREFIX;
907 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
908 if( device_id < 0 ){
909 * addr_len = IP_ADDR;
910 * prefix = 0;
911 * suffix = 0;
912 for( index = ip_netifs_count( & ip_globals.netifs ) - 1; index >= 0; -- index ){
913 netif = ip_netifs_get_index( & ip_globals.netifs, index );
914 if( netif ){
915 if( netif->addr_len > * addr_len ) * addr_len = netif->addr_len;
916 if( netif->prefix > * prefix ) * prefix = netif->prefix;
917 if( netif->suffix > * suffix ) * suffix = netif->suffix;
918 }
919 }
920 * prefix = * prefix + IP_PREFIX;
921 * suffix = * suffix + IP_SUFFIX;
922 }else{
923 netif = ip_netifs_find( & ip_globals.netifs, device_id );
924 if( ! netif ){
925 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
926 return ENOENT;
927 }
928 * addr_len = ( netif->addr_len > IP_ADDR ) ? netif->addr_len : IP_ADDR;
929 * prefix = netif->prefix + IP_PREFIX;
930 * suffix = netif->suffix + IP_SUFFIX;
931 }
932 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
933 return EOK;
934}
935
936int ip_add_route_req( int ip_phone, device_id_t device_id, in_addr_t address, in_addr_t netmask, in_addr_t gateway ){
937 ip_route_ref route;
938 ip_netif_ref netif;
939 int index;
940
941 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
942 netif = ip_netifs_find( & ip_globals.netifs, device_id );
943 if( ! netif ){
944 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
945 return ENOENT;
946 }
947 route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
948 if( ! route ){
949 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
950 return ENOMEM;
951 }
952 route->address.s_addr = address.s_addr;
953 route->netmask.s_addr = netmask.s_addr;
954 route->gateway.s_addr = gateway.s_addr;
955 route->netif = netif;
956 index = ip_routes_add( & netif->routes, route );
957 if( index < 0 ) free( route );
958 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
959 return index;
960}
961
962ip_route_ref ip_find_route( in_addr_t destination ){
963 int index;
964 ip_route_ref route;
965 ip_netif_ref netif;
966
967 // start with the last netif - the newest one
968 index = ip_netifs_count( & ip_globals.netifs ) - 1;
969 while( index >= 0 ){
970 netif = ip_netifs_get_index( & ip_globals.netifs, index );
971 if( netif && ( netif->state == NETIF_ACTIVE )){
972 route = ip_netif_find_route( netif, destination );
973 if( route ) return route;
974 }
975 -- index;
976 }
977 return & ip_globals.gateway;
978}
979
980ip_route_ref ip_netif_find_route( ip_netif_ref netif, in_addr_t destination ){
981 int index;
982 ip_route_ref route;
983
984 if( netif ){
985 // start with the first one - the direct route
986 for( index = 0; index < ip_routes_count( & netif->routes ); ++ index ){
987 route = ip_routes_get_index( & netif->routes, index );
988 if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( destination.s_addr & route->netmask.s_addr ))){
989 return route;
990 }
991 }
992 }
993 return NULL;
994}
995
996int ip_set_gateway_req( int ip_phone, device_id_t device_id, in_addr_t gateway ){
997 ip_netif_ref netif;
998
999 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
1000 netif = ip_netifs_find( & ip_globals.netifs, device_id );
1001 if( ! netif ){
1002 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
1003 return ENOENT;
1004 }
1005 ip_globals.gateway.address.s_addr = 0;
1006 ip_globals.gateway.netmask.s_addr = 0;
1007 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
1008 ip_globals.gateway.netif = netif;
1009 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
1010 return EOK;
1011}
1012
1013packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error ){
1014 size_t length;
1015 packet_t next;
1016 packet_t new_packet;
1017 int result;
1018 int phone;
1019
1020 next = packet;
1021 // check all packets
1022 while( next ){
1023 length = packet_get_data_length( next );
1024 // too long?
1025 if( length > content ){
1026 result = ip_fragment_packet( next, content, prefix, suffix, addr_len );
1027 if( result != EOK ){
1028 new_packet = pq_detach( next );
1029 if( next == packet ){
1030 // the new first packet of the queue
1031 packet = new_packet;
1032 }
1033 // fragmentation needed?
1034 if( result == EPERM ){
1035 phone = ip_prepare_icmp_and_get_phone( error, next, NULL );
1036 if( phone >= 0 ){
1037 // fragmentation necessary ICMP
1038 icmp_destination_unreachable_msg( phone, ICMP_FRAG_NEEDED, content, next );
1039 }
1040 }else{
1041 pq_release( ip_globals.net_phone, packet_get_id( next ));
1042 }
1043 next = new_packet;
1044 continue;
1045 }
1046 }
1047 next = pq_next( next );
1048 }
1049 return packet;
1050}
1051
1052int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len ){
1053 ERROR_DECLARE;
1054
1055 packet_t new_packet;
1056 ip_header_ref header;
1057 ip_header_ref middle_header;
1058 ip_header_ref last_header;
1059 struct sockaddr * src;
1060 struct sockaddr * dest;
1061 socklen_t addrlen;
1062 int result;
1063
1064 result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
1065 if( result <= 0 ) return EINVAL;
1066 addrlen = ( socklen_t ) result;
1067 if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
1068 // get header
1069 header = ( ip_header_ref ) packet_get_data( packet );
1070 if( ! header ) return EINVAL;
1071 // fragmentation forbidden?
1072 if( header->flags & IPFLAG_DONT_FRAGMENT ){
1073 return EPERM;
1074 }
1075 // create the last fragment
1076 new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen > addr_len ) ? addrlen : addr_len ));
1077 if( ! new_packet ) return ENOMEM;
1078 // allocate as much as originally
1079 last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
1080 if( ! last_header ){
1081 return ip_release_and_return( packet, ENOMEM );
1082 }
1083 ip_create_last_header( last_header, header );
1084 // trim the unused space
1085 if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
1086 return ip_release_and_return( packet, ERROR_CODE );
1087 }
1088 // biggest multiple of 8 lower than content
1089 // TODO even fragmentation?
1090 length = length & ( ~ 0x7 );// ( content / 8 ) * 8
1091 if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, last_header, (( IP_HEADER_DATA_LENGTH( header ) - (( length - IP_HEADER_LENGTH( header )) & ( ~ 0x7 ))) % (( length - IP_HEADER_LENGTH( last_header )) & ( ~ 0x7 ))), src, dest, addrlen ))){
1092 return ip_release_and_return( packet, ERROR_CODE );
1093 }
1094 // mark the first as fragmented
1095 header->flags |= IPFLAG_MORE_FRAGMENTS;
1096 // create middle framgents
1097 while( IP_TOTAL_LENGTH( header ) > length ){
1098 new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen >= addr_len ) ? addrlen : addr_len ));
1099 if( ! new_packet ) return ENOMEM;
1100 middle_header = ip_create_middle_header( new_packet, last_header );
1101 if( ! middle_header ){
1102 return ip_release_and_return( packet, ENOMEM );
1103 }
1104 if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, ( length - IP_HEADER_LENGTH( middle_header )) & ( ~ 0x7 ), src, dest, addrlen ))){
1105 return ip_release_and_return( packet, ERROR_CODE );
1106 }
1107 }
1108 // finish the first fragment
1109 header->header_checksum = IP_HEADER_CHECKSUM( header );
1110 return EOK;
1111}
1112
1113int ip_fragment_packet_data( packet_t packet, packet_t new_packet, ip_header_ref header, ip_header_ref new_header, size_t length, const struct sockaddr * src, const struct sockaddr * dest, socklen_t addrlen ){
1114 ERROR_DECLARE;
1115
1116 void * data;
1117 size_t offset;
1118
1119 data = packet_suffix( new_packet, length );
1120 if( ! data ) return ENOMEM;
1121 memcpy( data, (( void * ) header ) + IP_TOTAL_LENGTH( header ) - length, length );
1122 ERROR_PROPAGATE( packet_trim( packet, 0, length ));
1123 header->total_length = htons( IP_TOTAL_LENGTH( header ) - length );
1124 new_header->total_length = htons( IP_HEADER_LENGTH( new_header ) + length );
1125 offset = IP_FRAGMENT_OFFSET( header ) + IP_HEADER_DATA_LENGTH( header );
1126 new_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( offset );
1127 new_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( offset );
1128 new_header->header_checksum = IP_HEADER_CHECKSUM( new_header );
1129 ERROR_PROPAGATE( packet_set_addr( new_packet, ( const uint8_t * ) src, ( const uint8_t * ) dest, addrlen ));
1130 return pq_insert_after( packet, new_packet );
1131}
1132
1133ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last ){
1134 ip_header_ref middle;
1135
1136 middle = ( ip_header_ref ) packet_suffix( packet, IP_HEADER_LENGTH( last ));
1137 if( ! middle ) return NULL;
1138 memcpy( middle, last, IP_HEADER_LENGTH( last ));
1139 middle->flags |= IPFLAG_MORE_FRAGMENTS;
1140 return middle;
1141}
1142
1143void ip_create_last_header( ip_header_ref last, ip_header_ref first ){
1144 ip_option_ref option;
1145 size_t next;
1146 size_t length;
1147
1148 // copy first itself
1149 memcpy( last, first, sizeof( ip_header_t ));
1150 length = sizeof( ip_header_t );
1151 next = sizeof( ip_header_t );
1152 // process all ip options
1153 while( next < first->header_length ){
1154 option = ( ip_option_ref ) ((( uint8_t * ) first ) + next );
1155 // skip end or noop
1156 if(( option->type == IPOPT_END ) || ( option->type == IPOPT_NOOP )){
1157 ++ next;
1158 }else{
1159 // copy if said so or skip
1160 if( IPOPT_COPIED( option->type )){
1161 memcpy((( uint8_t * ) last ) + length, (( uint8_t * ) first ) + next, option->length );
1162 length += option->length;
1163 }
1164 // next option
1165 next += option->length;
1166 }
1167 }
1168 // align 4 byte boundary
1169 if( length % 4 ){
1170 bzero((( uint8_t * ) last ) + length, 4 - ( length % 4 ));
1171 last->header_length = length / 4 + 1;
1172 }else{
1173 last->header_length = length / 4;
1174 }
1175 last->header_checksum = 0;
1176}
1177
1178int ip_receive_message( device_id_t device_id, packet_t packet ){
1179 packet_t next;
1180
1181 do{
1182 next = pq_detach( packet );
1183 ip_process_packet( device_id, packet );
1184 packet = next;
1185 }while( packet );
1186 return EOK;
1187}
1188
1189int ip_process_packet( device_id_t device_id, packet_t packet ){
1190 ERROR_DECLARE;
1191
1192 ip_header_ref header;
1193 in_addr_t dest;
1194 ip_route_ref route;
1195 int phone;
1196 struct sockaddr * addr;
1197 struct sockaddr_in addr_in;
1198// struct sockaddr_in addr_in6;
1199 socklen_t addrlen;
1200
1201 header = ( ip_header_ref ) packet_get_data( packet );
1202 if( ! header ){
1203 return ip_release_and_return( packet, ENOMEM );
1204 }
1205 // checksum
1206 if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
1207 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1208 if( phone >= 0 ){
1209 // checksum error ICMP
1210 icmp_parameter_problem_msg( phone, ICMP_PARAM_POINTER, (( size_t ) (( void * ) & header->header_checksum )) - (( size_t ) (( void * ) header )), packet );
1211 }
1212 return EINVAL;
1213 }
1214 if( header->ttl <= 1 ){
1215 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1216 if( phone >= 0 ){
1217 // ttl oxceeded ICMP
1218 icmp_time_exceeded_msg( phone, ICMP_EXC_TTL, packet );
1219 }
1220 return EINVAL;
1221 }
1222 // process ipopt and get destination
1223 dest = ip_get_destination( header );
1224 // set the addrination address
1225 switch( header->version ){
1226 case IPVERSION:
1227 addrlen = sizeof( addr_in );
1228 bzero( & addr_in, addrlen );
1229 addr_in.sin_family = AF_INET;
1230 memcpy( & addr_in.sin_addr.s_addr, & dest, sizeof( dest ));
1231 addr = ( struct sockaddr * ) & addr_in;
1232 break;
1233/* case IPv6VERSION:
1234 addrlen = sizeof( dest_in6 );
1235 bzero( & dest_in6, addrlen );
1236 dest_in6.sin6_family = AF_INET6;
1237 memcpy( & dest_in6.sin6_addr.s6_addr, );
1238 dest = ( struct sockaddr * ) & dest_in;
1239 break;
1240*/ default:
1241 return ip_release_and_return( packet, EAFNOSUPPORT );
1242 }
1243 ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & addr, addrlen ));
1244 route = ip_find_route( dest );
1245 if( ! route ){
1246 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1247 if( phone >= 0 ){
1248 // unreachable ICMP
1249 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
1250 }
1251 return ENOENT;
1252 }
1253 if( route->address.s_addr == dest.s_addr ){
1254 // local delivery
1255 return ip_deliver_local( device_id, packet, header, 0 );
1256 }else{
1257 // only if routing enabled
1258 if( route->netif->routing ){
1259 -- header->ttl;
1260 return ip_send_route( packet, route->netif, route, NULL, dest, 0 );
1261 }else{
1262 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1263 if( phone >= 0 ){
1264 // unreachable ICMP if no routing
1265 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
1266 }
1267 return ENOENT;
1268 }
1269 }
1270}
1271
1272int ip_received_error_msg( int ip_phone, device_id_t device_id, packet_t packet, services_t target, services_t error ){
1273 uint8_t * data;
1274 int offset;
1275 icmp_type_t type;
1276 icmp_code_t code;
1277 ip_netif_ref netif;
1278 measured_string_t address;
1279 ip_route_ref route;
1280 ip_header_ref header;
1281
1282 switch( error ){
1283 case SERVICE_ICMP:
1284 offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
1285 if( offset < 0 ){
1286 return ip_release_and_return( packet, ENOMEM );
1287 }
1288 data = packet_get_data( packet );
1289 header = ( ip_header_ref )( data + offset );
1290 // destination host unreachable?
1291 if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
1292 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
1293 netif = ip_netifs_find( & ip_globals.netifs, device_id );
1294 if( netif && netif->arp ){
1295 route = ip_routes_get_index( & netif->routes, 0 );
1296 // from the same network?
1297 if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( header->destination_address & route->netmask.s_addr ))){
1298 // clear the ARP mapping if any
1299 address.value = ( char * ) & header->destination_address;
1300 address.length = CONVERT_SIZE( uint8_t, char, sizeof( header->destination_address ));
1301 arp_clear_address_req( netif->arp->phone, netif->device_id, SERVICE_IP, & address );
1302 }
1303 }
1304 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
1305 }
1306 break;
1307 default:
1308 return ip_release_and_return( packet, ENOTSUP );
1309 }
1310 return ip_deliver_local( device_id, packet, header, error );
1311}
1312
1313int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error ){
1314 ERROR_DECLARE;
1315
1316 ip_proto_ref proto;
1317 int phone;
1318 services_t service;
1319 tl_received_msg_t received_msg;
1320 struct sockaddr * src;
1321 struct sockaddr * dest;
1322 struct sockaddr_in src_in;
1323 struct sockaddr_in dest_in;
1324// struct sockaddr_in src_in6;
1325// struct sockaddr_in dest_in6;
1326 socklen_t addrlen;
1327
1328 if(( header->flags & IPFLAG_MORE_FRAGMENTS ) || IP_FRAGMENT_OFFSET( header )){
1329 // TODO fragmented
1330 return ENOTSUP;
1331 }else{
1332 switch( header->version ){
1333 case IPVERSION:
1334 addrlen = sizeof( src_in );
1335 bzero( & src_in, addrlen );
1336 src_in.sin_family = AF_INET;
1337 memcpy( & dest_in, & src_in, addrlen );
1338 memcpy( & src_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
1339 memcpy( & dest_in.sin_addr.s_addr, & header->destination_address, sizeof( header->destination_address ));
1340 src = ( struct sockaddr * ) & src_in;
1341 dest = ( struct sockaddr * ) & dest_in;
1342 break;
1343/* case IPv6VERSION:
1344 addrlen = sizeof( src_in6 );
1345 bzero( & src_in6, addrlen );
1346 src_in6.sin6_family = AF_INET6;
1347 memcpy( & dest_in6, & src_in6, addrlen );
1348 memcpy( & src_in6.sin6_addr.s6_addr, );
1349 memcpy( & dest_in6.sin6_addr.s6_addr, );
1350 src = ( struct sockaddr * ) & src_in;
1351 dest = ( struct sockaddr * ) & dest_in;
1352 break;
1353*/ default:
1354 return ip_release_and_return( packet, EAFNOSUPPORT );
1355 }
1356 if( ERROR_OCCURRED( packet_set_addr( packet, ( uint8_t * ) src, ( uint8_t * ) dest, addrlen ))){
1357 return ip_release_and_return( packet, ERROR_CODE );
1358 }
1359 // trim padding if present
1360 if(( ! error ) && ( IP_TOTAL_LENGTH( header ) < packet_get_data_length( packet ))){
1361 if( ERROR_OCCURRED( packet_trim( packet, 0, packet_get_data_length( packet ) - IP_TOTAL_LENGTH( header )))){
1362 return ip_release_and_return( packet, ERROR_CODE );
1363 }
1364 }
1365 fibril_rwlock_read_lock( & ip_globals.protos_lock );
1366 proto = ip_protos_find( & ip_globals.protos, header->protocol );
1367 if( ! proto ){
1368 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1369 phone = ip_prepare_icmp_and_get_phone( error, packet, header );
1370 if( phone >= 0 ){
1371 // unreachable ICMP
1372 icmp_destination_unreachable_msg( phone, ICMP_PROT_UNREACH, 0, packet );
1373 }
1374 return ENOENT;
1375 }
1376 if( proto->received_msg ){
1377 service = proto->service;
1378 received_msg = proto->received_msg;
1379 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1380 ERROR_CODE = received_msg( device_id, packet, service, error );
1381 }else{
1382 ERROR_CODE = tl_received_msg( proto->phone, device_id, packet, proto->service, error );
1383 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1384 }
1385 return ERROR_CODE;
1386 }
1387}
1388
1389in_addr_t ip_get_destination( ip_header_ref header ){
1390 in_addr_t destination;
1391
1392 // TODO search set ipopt route?
1393 destination.s_addr = header->destination_address;
1394 return destination;
1395}
1396
1397int ip_prepare_icmp( packet_t packet, ip_header_ref header ){
1398 packet_t next;
1399 struct sockaddr * dest;
1400 struct sockaddr_in dest_in;
1401// struct sockaddr_in dest_in6;
1402 socklen_t addrlen;
1403
1404 // detach the first packet and release the others
1405 next = pq_detach( packet );
1406 if( next ){
1407 pq_release( ip_globals.net_phone, packet_get_id( next ));
1408 }
1409 if( ! header ){
1410 if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
1411 // get header
1412 header = ( ip_header_ref ) packet_get_data( packet );
1413 if( ! header ) return EINVAL;
1414 }
1415 // only for the first fragment
1416 if( IP_FRAGMENT_OFFSET( header )) return EINVAL;
1417 // set the destination address
1418 switch( header->version ){
1419 case IPVERSION:
1420 addrlen = sizeof( dest_in );
1421 bzero( & dest_in, addrlen );
1422 dest_in.sin_family = AF_INET;
1423 memcpy( & dest_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
1424 dest = ( struct sockaddr * ) & dest_in;
1425 break;
1426/* case IPv6VERSION:
1427 addrlen = sizeof( dest_in6 );
1428 bzero( & dest_in6, addrlen );
1429 dest_in6.sin6_family = AF_INET6;
1430 memcpy( & dest_in6.sin6_addr.s6_addr, );
1431 dest = ( struct sockaddr * ) & dest_in;
1432 break;
1433*/ default:
1434 return EAFNOSUPPORT;
1435 }
1436 return packet_set_addr( packet, NULL, ( uint8_t * ) dest, addrlen );
1437}
1438
1439int ip_get_icmp_phone( void ){
1440 ip_proto_ref proto;
1441 int phone;
1442
1443 fibril_rwlock_read_lock( & ip_globals.protos_lock );
1444 proto = ip_protos_find( & ip_globals.protos, IPPROTO_ICMP );
1445 phone = proto ? proto->phone : ENOENT;
1446 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1447 return phone;
1448}
1449
1450int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header ){
1451 int phone;
1452
1453 phone = ip_get_icmp_phone();
1454 if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
1455 return ip_release_and_return( packet, EINVAL );
1456 }
1457 return phone;
1458}
1459
1460int ip_release_and_return( packet_t packet, int result ){
1461 pq_release( ip_globals.net_phone, packet_get_id( packet ));
1462 return result;
1463}
1464
1465int ip_get_route_req( int ip_phone, ip_protocol_t protocol, const struct sockaddr * destination, socklen_t addrlen, device_id_t * device_id, ip_pseudo_header_ref * header, size_t * headerlen ){
1466 struct sockaddr_in * address_in;
1467// struct sockaddr_in6 * address_in6;
1468 in_addr_t * dest;
1469 in_addr_t * src;
1470 ip_route_ref route;
1471 ipv4_pseudo_header_ref header_in;
1472
1473 if( !( destination && ( addrlen > 0 ))) return EINVAL;
1474 if( !( device_id && header && headerlen )) return EBADMEM;
1475 if(( size_t ) addrlen < sizeof( struct sockaddr )){
1476 return EINVAL;
1477 }
1478 switch( destination->sa_family ){
1479 case AF_INET:
1480 if( addrlen != sizeof( struct sockaddr_in )){
1481 return EINVAL;
1482 }
1483 address_in = ( struct sockaddr_in * ) destination;
1484 dest = & address_in->sin_addr;
[eac9722]1485 if( ! dest->s_addr ){
1486 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
1487 }
[21580dd]1488 break;
1489 // TODO IPv6
1490/* case AF_INET6:
1491 if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
1492 address_in6 = ( struct sockaddr_in6 * ) dest;
1493 address_in6.sin6_addr.s6_addr;
1494*/ default:
1495 return EAFNOSUPPORT;
1496 }
1497 fibril_rwlock_read_lock( & ip_globals.lock );
1498 route = ip_find_route( * dest );
1499 if( !( route && route->netif )){
1500 fibril_rwlock_read_unlock( & ip_globals.lock );
1501 return ENOENT;
1502 }
1503 * device_id = route->netif->device_id;
1504 src = ip_netif_address( route->netif );
1505 fibril_rwlock_read_unlock( & ip_globals.lock );
1506 * headerlen = sizeof( * header_in );
1507 header_in = ( ipv4_pseudo_header_ref ) malloc( * headerlen );
1508 if( ! header_in ) return ENOMEM;
1509 bzero( header_in, * headerlen );
1510 header_in->destination_address = dest->s_addr;
1511 header_in->source_address = src->s_addr;
1512 header_in->protocol = protocol;
1513 header_in->data_length = 0;
1514 * header = ( ip_pseudo_header_ref ) header_in;
1515 return EOK;
1516}
1517
1518/** @}
1519 */
Note: See TracBrowser for help on using the repository browser.