Subversion Repositories HelenOS

Rev

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