Subversion Repositories HelenOS

Rev

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