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

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

Merged with network branch svn://svn.helenos.org/HelenOS/branches/network revision 4759; ipc_share_* and ipc_data_* changed to async_*; client connection in module.c returns on IPC_M_PHONE_HUNGUP; * Qemu scripts renamed to net-qe.*; (the dp8390 does not respond)

  • Property mode set to 100644
File size: 55.0 KB
Line 
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;
660 break;
661 // TODO IPv6
662/* case AF_INET6:
663 if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
664 address_in6 = ( struct sockaddr_in6 * ) dest;
665 address_in6.sin6_addr.s6_addr;
666*/ default:
667 return ip_release_and_return( packet, EAFNOSUPPORT );
668 }
669 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
670 // device specified?
671 if( device_id > 0 ){
672 netif = ip_netifs_find( & ip_globals.netifs, device_id );
673 route = ip_netif_find_route( netif, * dest );
674 if( netif && ( ! route ) && ( ip_globals.gateway.netif == netif )){
675 route = & ip_globals.gateway;
676 }
677 }else{
678 route = ip_find_route( * dest );
679 netif = route ? route->netif : NULL;
680 }
681 if( !( netif && route )){
682 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
683 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
684 if( phone >= 0 ){
685 // unreachable ICMP if no routing
686 icmp_destination_unreachable_msg( phone, ICMP_NET_UNREACH, 0, packet );
687 }
688 return ENOENT;
689 }
690 if( error ){
691 // do not send for broadcast, anycast packets or network broadcast
692 if(( ! dest->s_addr )
693 || ( !( ~ dest->s_addr ))
694 || ( !( ~(( dest->s_addr & ( ~ route->netmask.s_addr )) | route->netmask.s_addr )))
695 || ( !( dest->s_addr & ( ~ route->netmask.s_addr )))){
696 return ip_release_and_return( packet, EINVAL );
697 }
698 }
699 if( route->address.s_addr == dest->s_addr ){
700 // find the loopback device to deliver
701 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
702 route = ip_find_route( * dest );
703 netif = route ? route->netif : NULL;
704 if( !( netif && route )){
705 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
706 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
707 if( phone >= 0 ){
708 // unreachable ICMP if no routing
709 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
710 }
711 return ENOENT;
712 }
713 }
714 src = ip_netif_address( netif );
715 if( ! src ){
716 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
717 return ip_release_and_return( packet, ENOENT );
718 }
719 ERROR_CODE = ip_send_route( packet, netif, route, src, * dest, error );
720 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
721 return ERROR_CODE;
722}
723
724in_addr_t * ip_netif_address( ip_netif_ref netif ){
725 ip_route_ref route;
726
727 route = ip_routes_get_index( & netif->routes, 0 );
728 return route ? & route->address : NULL;
729}
730
731int 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 ){
732 ERROR_DECLARE;
733
734 measured_string_t destination;
735 measured_string_ref translation;
736 char * data;
737 int phone;
738
739 // get destination hardware address
740 if( netif->arp && ( route->address.s_addr != dest.s_addr )){
741 destination.value = route->gateway.s_addr ? ( char * ) & route->gateway.s_addr : ( char * ) & dest.s_addr;
742 destination.length = CONVERT_SIZE( dest.s_addr, char, 1 );
743 if( ERROR_OCCURRED( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ))){
744// sleep( 1 );
745// ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
746 pq_release( ip_globals.net_phone, packet_get_id( packet ));
747 return ERROR_CODE;
748 }
749 if( !( translation && translation->value )){
750 if( translation ){
751 free( translation );
752 free( data );
753 }
754 phone = ip_prepare_icmp_and_get_phone( error, packet, NULL );
755 if( phone >= 0 ){
756 // unreachable ICMP if no routing
757 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
758 }
759 return EINVAL;
760 }
761 }else translation = NULL;
762 if( ERROR_OCCURRED( ip_prepare_packet( src, dest, packet, translation ))){
763 pq_release( ip_globals.net_phone, packet_get_id( packet ));
764 }else{
765 packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len, error );
766 if( packet ){
767 nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP );
768 }
769 }
770 if( translation ){
771 free( translation );
772 free( data );
773 }
774 return ERROR_CODE;
775}
776
777int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination ){
778 ERROR_DECLARE;
779
780 size_t length;
781 ip_header_ref header;
782 ip_header_ref last_header;
783 ip_header_ref middle_header;
784 packet_t next;
785
786 length = packet_get_data_length( packet );
787 if(( length < sizeof( ip_header_t )) || ( length > IP_MAX_CONTENT )) return EINVAL;
788 header = ( ip_header_ref ) packet_get_data( packet );
789 if( destination ){
790 ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
791 }else{
792 ERROR_PROPAGATE( packet_set_addr( packet, NULL, NULL, 0 ));
793 }
794 header->version = IPV4;
795 header->fragment_offset_high = 0;
796 header->fragment_offset_low = 0;
797 header->header_checksum = 0;
798 if( source ) header->source_address = source->s_addr;
799 header->destination_address = dest.s_addr;
800 fibril_rwlock_write_lock( & ip_globals.lock );
801 ++ ip_globals.packet_counter;
802 header->identification = htons( ip_globals.packet_counter );
803 fibril_rwlock_write_unlock( & ip_globals.lock );
804// length = packet_get_data_length( packet );
805 if( pq_next( packet )){
806 last_header = ( ip_header_ref ) malloc( IP_HEADER_LENGTH( header ));
807 if( ! last_header ) return ENOMEM;
808 ip_create_last_header( last_header, header );
809 next = pq_next( packet );
810 while( pq_next( next )){
811 middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
812 if( ! middle_header ) return ENOMEM;
813 memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
814 header->flags |= IPFLAG_MORE_FRAGMENTS;
815 middle_header->total_length = htons( packet_get_data_length( next ));
816 middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
817 middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
818 middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
819 if( destination ){
820 ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
821 }
822 length += packet_get_data_length( next );
823 next = pq_next( next );
824 }
825 middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
826 if( ! middle_header ) return ENOMEM;
827 memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
828 middle_header->total_length = htons( packet_get_data_length( next ));
829 middle_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( length );
830 middle_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( length );
831 middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
832 if( destination ){
833 ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
834 }
835 length += packet_get_data_length( next );
836 free( last_header );
837 header->flags |= IPFLAG_MORE_FRAGMENTS;
838 }
839 header->total_length = htons( length );
840 // unnecessary for all protocols
841 header->header_checksum = IP_HEADER_CHECKSUM( header );
842 return EOK;
843}
844
845int ip_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
846 ERROR_DECLARE;
847
848 packet_t packet;
849 struct sockaddr * addr;
850 size_t addrlen;
851 ip_pseudo_header_ref header;
852 size_t headerlen;
853
854 * answer_count = 0;
855 switch( IPC_GET_METHOD( * call )){
856 case IPC_M_PHONE_HUNGUP:
857 return EOK;
858 case NET_IL_DEVICE:
859 return ip_device_req( 0, IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ));
860 case IPC_M_CONNECT_TO_ME:
861 return ip_register( IL_GET_PROTO( call ), IL_GET_SERVICE( call ), IPC_GET_PHONE( call ), NULL );
862 case NET_IL_SEND:
863 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
864 return ip_send_msg( 0, IPC_GET_DEVICE( call ), packet, 0, IPC_GET_ERROR( call ));
865 case NET_IL_DEVICE_STATE:
866 return ip_device_state_message( IPC_GET_DEVICE( call ), IPC_GET_STATE( call ));
867 case NET_IL_RECEIVED:
868 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
869 return ip_receive_message( IPC_GET_DEVICE( call ), packet );
870 case NET_IP_RECEIVED_ERROR:
871 ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
872 return ip_received_error_msg( 0, IPC_GET_DEVICE( call ), packet, IPC_GET_TARGET( call ), IPC_GET_ERROR( call ));
873 case NET_IP_ADD_ROUTE:
874 return ip_add_route_req( 0, IPC_GET_DEVICE( call ), IP_GET_ADDRESS( call ), IP_GET_NETMASK( call ), IP_GET_GATEWAY( call ));
875 case NET_IP_SET_GATEWAY:
876 return ip_set_gateway_req( 0, IPC_GET_DEVICE( call ), IP_GET_GATEWAY( call ));
877 case NET_IP_GET_ROUTE:
878 ERROR_PROPAGATE( data_receive(( void ** ) & addr, & addrlen ));
879 ERROR_PROPAGATE( ip_get_route_req( 0, IP_GET_PROTOCOL( call ), addr, ( socklen_t ) addrlen, IPC_SET_DEVICE( answer ), & header, & headerlen ));
880 * IP_SET_HEADERLEN( answer ) = headerlen;
881 * answer_count = 2;
882 if( ! ERROR_OCCURRED( data_reply( & headerlen, sizeof( headerlen )))){
883 ERROR_CODE = data_reply( header, headerlen );
884 }
885 free( header );
886 return ERROR_CODE;
887 case NET_IL_PACKET_SPACE:
888 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 )));
889 * answer_count = 3;
890 return EOK;
891 case NET_IL_MTU_CHANGED:
892 return ip_mtu_changed_message( IPC_GET_DEVICE( call ), IPC_GET_MTU( call ));
893 }
894 return ENOTSUP;
895}
896
897int 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 ){
898 ip_netif_ref netif;
899 int index;
900
901 if( !( addr_len && prefix && content && suffix )) return EBADMEM;
902 * content = IP_MAX_CONTENT - IP_PREFIX;
903 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
904 if( device_id < 0 ){
905 * addr_len = IP_ADDR;
906 * prefix = 0;
907 * suffix = 0;
908 for( index = ip_netifs_count( & ip_globals.netifs ) - 1; index >= 0; -- index ){
909 netif = ip_netifs_get_index( & ip_globals.netifs, index );
910 if( netif ){
911 if( netif->addr_len > * addr_len ) * addr_len = netif->addr_len;
912 if( netif->prefix > * prefix ) * prefix = netif->prefix;
913 if( netif->suffix > * suffix ) * suffix = netif->suffix;
914 }
915 }
916 * prefix = * prefix + IP_PREFIX;
917 * suffix = * suffix + IP_SUFFIX;
918 }else{
919 netif = ip_netifs_find( & ip_globals.netifs, device_id );
920 if( ! netif ){
921 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
922 return ENOENT;
923 }
924 * addr_len = ( netif->addr_len > IP_ADDR ) ? netif->addr_len : IP_ADDR;
925 * prefix = netif->prefix + IP_PREFIX;
926 * suffix = netif->suffix + IP_SUFFIX;
927 }
928 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
929 return EOK;
930}
931
932int ip_add_route_req( int ip_phone, device_id_t device_id, in_addr_t address, in_addr_t netmask, in_addr_t gateway ){
933 ip_route_ref route;
934 ip_netif_ref netif;
935 int index;
936
937 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
938 netif = ip_netifs_find( & ip_globals.netifs, device_id );
939 if( ! netif ){
940 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
941 return ENOENT;
942 }
943 route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
944 if( ! route ){
945 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
946 return ENOMEM;
947 }
948 route->address.s_addr = address.s_addr;
949 route->netmask.s_addr = netmask.s_addr;
950 route->gateway.s_addr = gateway.s_addr;
951 route->netif = netif;
952 index = ip_routes_add( & netif->routes, route );
953 if( index < 0 ) free( route );
954 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
955 return index;
956}
957
958ip_route_ref ip_find_route( in_addr_t destination ){
959 int index;
960 ip_route_ref route;
961 ip_netif_ref netif;
962
963 // start with the last netif - the newest one
964 index = ip_netifs_count( & ip_globals.netifs ) - 1;
965 while( index >= 0 ){
966 netif = ip_netifs_get_index( & ip_globals.netifs, index );
967 if( netif && ( netif->state == NETIF_ACTIVE )){
968 route = ip_netif_find_route( netif, destination );
969 if( route ) return route;
970 }
971 -- index;
972 }
973 return & ip_globals.gateway;
974}
975
976ip_route_ref ip_netif_find_route( ip_netif_ref netif, in_addr_t destination ){
977 int index;
978 ip_route_ref route;
979
980 if( netif ){
981 // start with the first one - the direct route
982 for( index = 0; index < ip_routes_count( & netif->routes ); ++ index ){
983 route = ip_routes_get_index( & netif->routes, index );
984 if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( destination.s_addr & route->netmask.s_addr ))){
985 return route;
986 }
987 }
988 }
989 return NULL;
990}
991
992int ip_set_gateway_req( int ip_phone, device_id_t device_id, in_addr_t gateway ){
993 ip_netif_ref netif;
994
995 fibril_rwlock_write_lock( & ip_globals.netifs_lock );
996 netif = ip_netifs_find( & ip_globals.netifs, device_id );
997 if( ! netif ){
998 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
999 return ENOENT;
1000 }
1001 ip_globals.gateway.address.s_addr = 0;
1002 ip_globals.gateway.netmask.s_addr = 0;
1003 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
1004 ip_globals.gateway.netif = netif;
1005 fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
1006 return EOK;
1007}
1008
1009packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, socklen_t addr_len, services_t error ){
1010 size_t length;
1011 packet_t next;
1012 packet_t new_packet;
1013 int result;
1014 int phone;
1015
1016 next = packet;
1017 // check all packets
1018 while( next ){
1019 length = packet_get_data_length( next );
1020 // too long?
1021 if( length > content ){
1022 result = ip_fragment_packet( next, content, prefix, suffix, addr_len );
1023 if( result != EOK ){
1024 new_packet = pq_detach( next );
1025 if( next == packet ){
1026 // the new first packet of the queue
1027 packet = new_packet;
1028 }
1029 // fragmentation needed?
1030 if( result == EPERM ){
1031 phone = ip_prepare_icmp_and_get_phone( error, next, NULL );
1032 if( phone >= 0 ){
1033 // fragmentation necessary ICMP
1034 icmp_destination_unreachable_msg( phone, ICMP_FRAG_NEEDED, content, next );
1035 }
1036 }else{
1037 pq_release( ip_globals.net_phone, packet_get_id( next ));
1038 }
1039 next = new_packet;
1040 continue;
1041 }
1042 }
1043 next = pq_next( next );
1044 }
1045 return packet;
1046}
1047
1048int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, socklen_t addr_len ){
1049 ERROR_DECLARE;
1050
1051 packet_t new_packet;
1052 ip_header_ref header;
1053 ip_header_ref middle_header;
1054 ip_header_ref last_header;
1055 struct sockaddr * src;
1056 struct sockaddr * dest;
1057 socklen_t addrlen;
1058 int result;
1059
1060 result = packet_get_addr( packet, ( uint8_t ** ) & src, ( uint8_t ** ) & dest );
1061 if( result <= 0 ) return EINVAL;
1062 addrlen = ( socklen_t ) result;
1063 if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
1064 // get header
1065 header = ( ip_header_ref ) packet_get_data( packet );
1066 if( ! header ) return EINVAL;
1067 // fragmentation forbidden?
1068 if( header->flags & IPFLAG_DONT_FRAGMENT ){
1069 return EPERM;
1070 }
1071 // create the last fragment
1072 new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen > addr_len ) ? addrlen : addr_len ));
1073 if( ! new_packet ) return ENOMEM;
1074 // allocate as much as originally
1075 last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
1076 if( ! last_header ){
1077 return ip_release_and_return( packet, ENOMEM );
1078 }
1079 ip_create_last_header( last_header, header );
1080 // trim the unused space
1081 if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
1082 return ip_release_and_return( packet, ERROR_CODE );
1083 }
1084 // biggest multiple of 8 lower than content
1085 // TODO even fragmentation?
1086 length = length & ( ~ 0x7 );// ( content / 8 ) * 8
1087 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 ))){
1088 return ip_release_and_return( packet, ERROR_CODE );
1089 }
1090 // mark the first as fragmented
1091 header->flags |= IPFLAG_MORE_FRAGMENTS;
1092 // create middle framgents
1093 while( IP_TOTAL_LENGTH( header ) > length ){
1094 new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( addrlen >= addr_len ) ? addrlen : addr_len ));
1095 if( ! new_packet ) return ENOMEM;
1096 middle_header = ip_create_middle_header( new_packet, last_header );
1097 if( ! middle_header ){
1098 return ip_release_and_return( packet, ENOMEM );
1099 }
1100 if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, ( length - IP_HEADER_LENGTH( middle_header )) & ( ~ 0x7 ), src, dest, addrlen ))){
1101 return ip_release_and_return( packet, ERROR_CODE );
1102 }
1103 }
1104 // finish the first fragment
1105 header->header_checksum = IP_HEADER_CHECKSUM( header );
1106 return EOK;
1107}
1108
1109int 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 ){
1110 ERROR_DECLARE;
1111
1112 void * data;
1113 size_t offset;
1114
1115 data = packet_suffix( new_packet, length );
1116 if( ! data ) return ENOMEM;
1117 memcpy( data, (( void * ) header ) + IP_TOTAL_LENGTH( header ) - length, length );
1118 ERROR_PROPAGATE( packet_trim( packet, 0, length ));
1119 header->total_length = htons( IP_TOTAL_LENGTH( header ) - length );
1120 new_header->total_length = htons( IP_HEADER_LENGTH( new_header ) + length );
1121 offset = IP_FRAGMENT_OFFSET( header ) + IP_HEADER_DATA_LENGTH( header );
1122 new_header->fragment_offset_high = IP_COMPUTE_FRAGMENT_OFFSET_HIGH( offset );
1123 new_header->fragment_offset_low = IP_COMPUTE_FRAGMENT_OFFSET_LOW( offset );
1124 new_header->header_checksum = IP_HEADER_CHECKSUM( new_header );
1125 ERROR_PROPAGATE( packet_set_addr( new_packet, ( const uint8_t * ) src, ( const uint8_t * ) dest, addrlen ));
1126 return pq_insert_after( packet, new_packet );
1127}
1128
1129ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last ){
1130 ip_header_ref middle;
1131
1132 middle = ( ip_header_ref ) packet_suffix( packet, IP_HEADER_LENGTH( last ));
1133 if( ! middle ) return NULL;
1134 memcpy( middle, last, IP_HEADER_LENGTH( last ));
1135 middle->flags |= IPFLAG_MORE_FRAGMENTS;
1136 return middle;
1137}
1138
1139void ip_create_last_header( ip_header_ref last, ip_header_ref first ){
1140 ip_option_ref option;
1141 size_t next;
1142 size_t length;
1143
1144 // copy first itself
1145 memcpy( last, first, sizeof( ip_header_t ));
1146 length = sizeof( ip_header_t );
1147 next = sizeof( ip_header_t );
1148 // process all ip options
1149 while( next < first->header_length ){
1150 option = ( ip_option_ref ) ((( uint8_t * ) first ) + next );
1151 // skip end or noop
1152 if(( option->type == IPOPT_END ) || ( option->type == IPOPT_NOOP )){
1153 ++ next;
1154 }else{
1155 // copy if said so or skip
1156 if( IPOPT_COPIED( option->type )){
1157 memcpy((( uint8_t * ) last ) + length, (( uint8_t * ) first ) + next, option->length );
1158 length += option->length;
1159 }
1160 // next option
1161 next += option->length;
1162 }
1163 }
1164 // align 4 byte boundary
1165 if( length % 4 ){
1166 bzero((( uint8_t * ) last ) + length, 4 - ( length % 4 ));
1167 last->header_length = length / 4 + 1;
1168 }else{
1169 last->header_length = length / 4;
1170 }
1171 last->header_checksum = 0;
1172}
1173
1174int ip_receive_message( device_id_t device_id, packet_t packet ){
1175 packet_t next;
1176
1177 do{
1178 next = pq_detach( packet );
1179 ip_process_packet( device_id, packet );
1180 packet = next;
1181 }while( packet );
1182 return EOK;
1183}
1184
1185int ip_process_packet( device_id_t device_id, packet_t packet ){
1186 ERROR_DECLARE;
1187
1188 ip_header_ref header;
1189 in_addr_t dest;
1190 ip_route_ref route;
1191 int phone;
1192 struct sockaddr * addr;
1193 struct sockaddr_in addr_in;
1194// struct sockaddr_in addr_in6;
1195 socklen_t addrlen;
1196
1197 header = ( ip_header_ref ) packet_get_data( packet );
1198 if( ! header ){
1199 return ip_release_and_return( packet, ENOMEM );
1200 }
1201 // checksum
1202 if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
1203 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1204 if( phone >= 0 ){
1205 // checksum error ICMP
1206 icmp_parameter_problem_msg( phone, ICMP_PARAM_POINTER, (( size_t ) (( void * ) & header->header_checksum )) - (( size_t ) (( void * ) header )), packet );
1207 }
1208 return EINVAL;
1209 }
1210 if( header->ttl <= 1 ){
1211 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1212 if( phone >= 0 ){
1213 // ttl oxceeded ICMP
1214 icmp_time_exceeded_msg( phone, ICMP_EXC_TTL, packet );
1215 }
1216 return EINVAL;
1217 }
1218 // process ipopt and get destination
1219 dest = ip_get_destination( header );
1220 // set the addrination address
1221 switch( header->version ){
1222 case IPVERSION:
1223 addrlen = sizeof( addr_in );
1224 bzero( & addr_in, addrlen );
1225 addr_in.sin_family = AF_INET;
1226 memcpy( & addr_in.sin_addr.s_addr, & dest, sizeof( dest ));
1227 addr = ( struct sockaddr * ) & addr_in;
1228 break;
1229/* case IPv6VERSION:
1230 addrlen = sizeof( dest_in6 );
1231 bzero( & dest_in6, addrlen );
1232 dest_in6.sin6_family = AF_INET6;
1233 memcpy( & dest_in6.sin6_addr.s6_addr, );
1234 dest = ( struct sockaddr * ) & dest_in;
1235 break;
1236*/ default:
1237 return ip_release_and_return( packet, EAFNOSUPPORT );
1238 }
1239 ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & addr, addrlen ));
1240 route = ip_find_route( dest );
1241 if( ! route ){
1242 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1243 if( phone >= 0 ){
1244 // unreachable ICMP
1245 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
1246 }
1247 return ENOENT;
1248 }
1249 if( route->address.s_addr == dest.s_addr ){
1250 // local delivery
1251 return ip_deliver_local( device_id, packet, header, 0 );
1252 }else{
1253 // only if routing enabled
1254 if( route->netif->routing ){
1255 -- header->ttl;
1256 return ip_send_route( packet, route->netif, route, NULL, dest, 0 );
1257 }else{
1258 phone = ip_prepare_icmp_and_get_phone( 0, packet, header );
1259 if( phone >= 0 ){
1260 // unreachable ICMP if no routing
1261 icmp_destination_unreachable_msg( phone, ICMP_HOST_UNREACH, 0, packet );
1262 }
1263 return ENOENT;
1264 }
1265 }
1266}
1267
1268int ip_received_error_msg( int ip_phone, device_id_t device_id, packet_t packet, services_t target, services_t error ){
1269 uint8_t * data;
1270 int offset;
1271 icmp_type_t type;
1272 icmp_code_t code;
1273 ip_netif_ref netif;
1274 measured_string_t address;
1275 ip_route_ref route;
1276 ip_header_ref header;
1277
1278 switch( error ){
1279 case SERVICE_ICMP:
1280 offset = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
1281 if( offset < 0 ){
1282 return ip_release_and_return( packet, ENOMEM );
1283 }
1284 data = packet_get_data( packet );
1285 header = ( ip_header_ref )( data + offset );
1286 // destination host unreachable?
1287 if(( type == ICMP_DEST_UNREACH ) && ( code == ICMP_HOST_UNREACH )){
1288 fibril_rwlock_read_lock( & ip_globals.netifs_lock );
1289 netif = ip_netifs_find( & ip_globals.netifs, device_id );
1290 if( netif && netif->arp ){
1291 route = ip_routes_get_index( & netif->routes, 0 );
1292 // from the same network?
1293 if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( header->destination_address & route->netmask.s_addr ))){
1294 // clear the ARP mapping if any
1295 address.value = ( char * ) & header->destination_address;
1296 address.length = CONVERT_SIZE( uint8_t, char, sizeof( header->destination_address ));
1297 arp_clear_address_req( netif->arp->phone, netif->device_id, SERVICE_IP, & address );
1298 }
1299 }
1300 fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
1301 }
1302 break;
1303 default:
1304 return ip_release_and_return( packet, ENOTSUP );
1305 }
1306 return ip_deliver_local( device_id, packet, header, error );
1307}
1308
1309int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header, services_t error ){
1310 ERROR_DECLARE;
1311
1312 ip_proto_ref proto;
1313 int phone;
1314 services_t service;
1315 tl_received_msg_t received_msg;
1316 struct sockaddr * src;
1317 struct sockaddr * dest;
1318 struct sockaddr_in src_in;
1319 struct sockaddr_in dest_in;
1320// struct sockaddr_in src_in6;
1321// struct sockaddr_in dest_in6;
1322 socklen_t addrlen;
1323
1324 if(( header->flags & IPFLAG_MORE_FRAGMENTS ) || IP_FRAGMENT_OFFSET( header )){
1325 // TODO fragmented
1326 return ENOTSUP;
1327 }else{
1328 switch( header->version ){
1329 case IPVERSION:
1330 addrlen = sizeof( src_in );
1331 bzero( & src_in, addrlen );
1332 src_in.sin_family = AF_INET;
1333 memcpy( & dest_in, & src_in, addrlen );
1334 memcpy( & src_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
1335 memcpy( & dest_in.sin_addr.s_addr, & header->destination_address, sizeof( header->destination_address ));
1336 src = ( struct sockaddr * ) & src_in;
1337 dest = ( struct sockaddr * ) & dest_in;
1338 break;
1339/* case IPv6VERSION:
1340 addrlen = sizeof( src_in6 );
1341 bzero( & src_in6, addrlen );
1342 src_in6.sin6_family = AF_INET6;
1343 memcpy( & dest_in6, & src_in6, addrlen );
1344 memcpy( & src_in6.sin6_addr.s6_addr, );
1345 memcpy( & dest_in6.sin6_addr.s6_addr, );
1346 src = ( struct sockaddr * ) & src_in;
1347 dest = ( struct sockaddr * ) & dest_in;
1348 break;
1349*/ default:
1350 return ip_release_and_return( packet, EAFNOSUPPORT );
1351 }
1352 if( ERROR_OCCURRED( packet_set_addr( packet, ( uint8_t * ) src, ( uint8_t * ) dest, addrlen ))){
1353 return ip_release_and_return( packet, ERROR_CODE );
1354 }
1355 // trim padding if present
1356 if(( ! error ) && ( IP_TOTAL_LENGTH( header ) < packet_get_data_length( packet ))){
1357 if( ERROR_OCCURRED( packet_trim( packet, 0, packet_get_data_length( packet ) - IP_TOTAL_LENGTH( header )))){
1358 return ip_release_and_return( packet, ERROR_CODE );
1359 }
1360 }
1361 fibril_rwlock_read_lock( & ip_globals.protos_lock );
1362 proto = ip_protos_find( & ip_globals.protos, header->protocol );
1363 if( ! proto ){
1364 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1365 phone = ip_prepare_icmp_and_get_phone( error, packet, header );
1366 if( phone >= 0 ){
1367 // unreachable ICMP
1368 icmp_destination_unreachable_msg( phone, ICMP_PROT_UNREACH, 0, packet );
1369 }
1370 return ENOENT;
1371 }
1372 if( proto->received_msg ){
1373 service = proto->service;
1374 received_msg = proto->received_msg;
1375 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1376 ERROR_CODE = received_msg( device_id, packet, service, error );
1377 }else{
1378 ERROR_CODE = tl_received_msg( proto->phone, device_id, packet, proto->service, error );
1379 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1380 }
1381 return ERROR_CODE;
1382 }
1383}
1384
1385in_addr_t ip_get_destination( ip_header_ref header ){
1386 in_addr_t destination;
1387
1388 // TODO search set ipopt route?
1389 destination.s_addr = header->destination_address;
1390 return destination;
1391}
1392
1393int ip_prepare_icmp( packet_t packet, ip_header_ref header ){
1394 packet_t next;
1395 struct sockaddr * dest;
1396 struct sockaddr_in dest_in;
1397// struct sockaddr_in dest_in6;
1398 socklen_t addrlen;
1399
1400 // detach the first packet and release the others
1401 next = pq_detach( packet );
1402 if( next ){
1403 pq_release( ip_globals.net_phone, packet_get_id( next ));
1404 }
1405 if( ! header ){
1406 if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
1407 // get header
1408 header = ( ip_header_ref ) packet_get_data( packet );
1409 if( ! header ) return EINVAL;
1410 }
1411 // only for the first fragment
1412 if( IP_FRAGMENT_OFFSET( header )) return EINVAL;
1413 // set the destination address
1414 switch( header->version ){
1415 case IPVERSION:
1416 addrlen = sizeof( dest_in );
1417 bzero( & dest_in, addrlen );
1418 dest_in.sin_family = AF_INET;
1419 memcpy( & dest_in.sin_addr.s_addr, & header->source_address, sizeof( header->source_address ));
1420 dest = ( struct sockaddr * ) & dest_in;
1421 break;
1422/* case IPv6VERSION:
1423 addrlen = sizeof( dest_in6 );
1424 bzero( & dest_in6, addrlen );
1425 dest_in6.sin6_family = AF_INET6;
1426 memcpy( & dest_in6.sin6_addr.s6_addr, );
1427 dest = ( struct sockaddr * ) & dest_in;
1428 break;
1429*/ default:
1430 return EAFNOSUPPORT;
1431 }
1432 return packet_set_addr( packet, NULL, ( uint8_t * ) dest, addrlen );
1433}
1434
1435int ip_get_icmp_phone( void ){
1436 ip_proto_ref proto;
1437 int phone;
1438
1439 fibril_rwlock_read_lock( & ip_globals.protos_lock );
1440 proto = ip_protos_find( & ip_globals.protos, IPPROTO_ICMP );
1441 phone = proto ? proto->phone : ENOENT;
1442 fibril_rwlock_read_unlock( & ip_globals.protos_lock );
1443 return phone;
1444}
1445
1446int ip_prepare_icmp_and_get_phone( services_t error, packet_t packet, ip_header_ref header ){
1447 int phone;
1448
1449 phone = ip_get_icmp_phone();
1450 if( error || ( phone < 0 ) || ip_prepare_icmp( packet, header )){
1451 return ip_release_and_return( packet, EINVAL );
1452 }
1453 return phone;
1454}
1455
1456int ip_release_and_return( packet_t packet, int result ){
1457 pq_release( ip_globals.net_phone, packet_get_id( packet ));
1458 return result;
1459}
1460
1461int 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 ){
1462 struct sockaddr_in * address_in;
1463// struct sockaddr_in6 * address_in6;
1464 in_addr_t * dest;
1465 in_addr_t * src;
1466 ip_route_ref route;
1467 ipv4_pseudo_header_ref header_in;
1468
1469 if( !( destination && ( addrlen > 0 ))) return EINVAL;
1470 if( !( device_id && header && headerlen )) return EBADMEM;
1471 if(( size_t ) addrlen < sizeof( struct sockaddr )){
1472 return EINVAL;
1473 }
1474 switch( destination->sa_family ){
1475 case AF_INET:
1476 if( addrlen != sizeof( struct sockaddr_in )){
1477 return EINVAL;
1478 }
1479 address_in = ( struct sockaddr_in * ) destination;
1480 dest = & address_in->sin_addr;
1481 break;
1482 // TODO IPv6
1483/* case AF_INET6:
1484 if( addrlen != sizeof( struct sockaddr_in6 )) return EINVAL;
1485 address_in6 = ( struct sockaddr_in6 * ) dest;
1486 address_in6.sin6_addr.s6_addr;
1487*/ default:
1488 return EAFNOSUPPORT;
1489 }
1490 fibril_rwlock_read_lock( & ip_globals.lock );
1491 route = ip_find_route( * dest );
1492 if( !( route && route->netif )){
1493 fibril_rwlock_read_unlock( & ip_globals.lock );
1494 return ENOENT;
1495 }
1496 * device_id = route->netif->device_id;
1497 src = ip_netif_address( route->netif );
1498 fibril_rwlock_read_unlock( & ip_globals.lock );
1499 * headerlen = sizeof( * header_in );
1500 header_in = ( ipv4_pseudo_header_ref ) malloc( * headerlen );
1501 if( ! header_in ) return ENOMEM;
1502 bzero( header_in, * headerlen );
1503 header_in->destination_address = dest->s_addr;
1504 header_in->source_address = src->s_addr;
1505 header_in->protocol = protocol;
1506 header_in->data_length = 0;
1507 * header = ( ip_pseudo_header_ref ) header_in;
1508 return EOK;
1509}
1510
1511/** @}
1512 */
Note: See TracBrowser for help on using the repository browser.