Subversion Repositories HelenOS

Rev

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