Subversion Repositories HelenOS

Rev

Rev 4722 | Rev 4728 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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