Subversion Repositories HelenOS

Rev

Rev 4582 | Rev 4695 | 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 );
4589 mejdrech 113
void ip_create_last_header( ip_header_ref last, ip_header_ref first );
4505 mejdrech 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
	measured_string_t	destination;
489
	measured_string_ref	translation;
490
	char *				data;
491
 
492
	// get destination hardware address
493
	if( netif->arp ){
4575 mejdrech 494
		destination.value = route->gateway.s_addr ? ( char * ) & route->gateway.s_addr : ( char * ) & dest.s_addr;
4505 mejdrech 495
		destination.length = CONVERT_SIZE( dest.s_addr, char, 1 );
496
		if( ERROR_OCCURRED( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ))){
4582 mejdrech 497
			sleep( 1 );
4505 mejdrech 498
			ERROR_PROPAGATE( arp_translate_req( netif->arp->phone, netif->device_id, SERVICE_IP, & destination, & translation, & data ));
499
		}
500
		// TODO unreachable
501
		if( ! translation ) return EINVAL;
502
		if( ! translation->value ){
503
			// TODO unreachable
504
			free( translation );
505
			free( data );
506
			return EINVAL;
507
		}
508
	}else translation = NULL;
4589 mejdrech 509
	if( ERROR_OCCURRED( ip_prepare_packet( src, dest, packet, translation ))){
510
		pq_release( ip_globals.net_phone, packet_get_id( packet ));
511
	}else{
512
		packet = ip_split_packet( packet, netif->prefix, netif->content, netif->suffix, netif->addr_len );
513
		if( packet ){
514
			nil_send_msg( netif->phone, netif->device_id, packet, SERVICE_IP );
4505 mejdrech 515
		}
4589 mejdrech 516
	}
4505 mejdrech 517
	if( translation ){
518
		free( translation );
519
		free( data );
520
	}
4589 mejdrech 521
	return ERROR_CODE;
3846 mejdrech 522
}
523
 
4575 mejdrech 524
int ip_prepare_packet( in_addr_t * source, in_addr_t dest, packet_t packet, measured_string_ref destination ){
4505 mejdrech 525
	ERROR_DECLARE;
526
 
4558 mejdrech 527
	size_t				length;
4505 mejdrech 528
	ip_header_ref		header;
4589 mejdrech 529
	ip_header_ref		last_header;
530
	ip_header_ref		middle_header;
531
	packet_t			next;
4505 mejdrech 532
 
533
	length = packet_get_data_length( packet );
534
	if(( length < sizeof( ip_header_t )) || ( length > IP_MAX_CONTENT )) return EINVAL;
535
	header = ( ip_header_ref ) packet_get_data( packet );
536
	if( destination ){
537
		ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
538
	}
539
	header->version = 4;
540
	header->fragment_offset = 0;
4589 mejdrech 541
	header->header_checksum = 0;
4575 mejdrech 542
	if( source ) header->source_address = source->s_addr;
543
	header->destination_address = dest.s_addr;
4582 mejdrech 544
	fibril_rwlock_write_lock( & ip_globals.lock );
4505 mejdrech 545
	++ ip_globals.packet_counter;
546
	header->identification = htons( ip_globals.packet_counter );
4582 mejdrech 547
	fibril_rwlock_write_unlock( & ip_globals.lock );
4589 mejdrech 548
	length = packet_get_data_length( packet );
549
	if( pq_next( packet )){
550
		last_header = ( ip_header_ref ) malloc( IP_HEADER_LENGTH( header ));
551
		if( ! last_header ) return ENOMEM;
552
		ip_create_last_header( last_header, header );
553
		next = pq_next( packet );
554
		while( pq_next( next )){
555
			middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
556
			if( ! middle_header ) return ENOMEM;
557
			memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
558
			header->flags |= IPFLAG_MORE_FRAGMENTS;
559
			middle_header->total_length = htons( packet_get_data_length( next ));
560
			middle_header->fragment_offset = length / 8;
561
			middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
562
			if( destination ){
563
				ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
564
			}
565
			length += packet_get_data_length( next );
566
			next = pq_next( next );
567
		}
568
		middle_header = ( ip_header_ref ) packet_prefix( next, IP_HEADER_LENGTH( last_header ));
569
		if( ! middle_header ) return ENOMEM;
570
		memcpy( middle_header, last_header, IP_HEADER_LENGTH( last_header ));
571
		middle_header->total_length = htons( packet_get_data_length( next ));
572
		middle_header->fragment_offset = length / 8;
573
		middle_header->header_checksum = IP_HEADER_CHECKSUM( middle_header );
574
		if( destination ){
575
			ERROR_PROPAGATE( packet_set_addr( next, NULL, ( uint8_t * ) destination->value, CONVERT_SIZE( char, uint8_t, destination->length )));
576
		}
577
		length += packet_get_data_length( next );
578
		free( last_header );
579
		header->flags |= IPFLAG_MORE_FRAGMENTS;
580
	}
581
	header->total_length = htons( length );
4505 mejdrech 582
	// unnecessary for all protocols
583
	header->header_checksum = IP_HEADER_CHECKSUM( header );
584
	return EOK;
585
}
586
 
4589 mejdrech 587
 
588
 
3846 mejdrech 589
int ip_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
590
	ERROR_DECLARE;
591
 
592
	packet_t	packet;
593
 
594
	* answer_count = 0;
595
	switch( IPC_GET_METHOD( * call )){
3466 mejdrech 596
		case IPC_M_PHONE_HUNGUP:
597
			return EOK;
3666 mejdrech 598
		case NET_IL_DEVICE:
4307 mejdrech 599
			return ip_device_req( 0, IPC_GET_DEVICE( call ), IPC_GET_SERVICE( call ));
3846 mejdrech 600
		case IPC_M_CONNECT_TO_ME:
4505 mejdrech 601
			return ip_register( IL_GET_PROTO( call ), IL_GET_SERVICE( call ), IPC_GET_PHONE( call ), NULL );
4307 mejdrech 602
		case NET_IL_SEND:
603
			ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
604
			return ip_send_msg( 0, IPC_GET_DEVICE( call ), packet, 0 );
4351 mejdrech 605
		case NET_IL_DEVICE_STATE:
606
		case NET_NIL_DEVICE_STATE:
607
			return ip_device_state_msg( 0, IPC_GET_DEVICE( call ), IPC_GET_STATE( call ));
608
		case NET_IL_RECEIVED:
609
		case NET_NIL_RECEIVED:
610
			ERROR_PROPAGATE( packet_translate( ip_globals.net_phone, & packet, IPC_GET_PACKET( call )));
4505 mejdrech 611
			return ip_received_msg( IPC_GET_DEVICE( call ), packet );
612
		case NET_IP_ADD_ROUTE:
613
			return ip_add_route_req( 0, IPC_GET_DEVICE( call ), IP_GET_ADDRESS( call ), IP_GET_NETMASK( call ), IP_GET_GATEWAY( call ));
614
		case NET_IP_SET_GATEWAY:
615
			return ip_set_gateway_req( 0, IPC_GET_DEVICE( call ), IP_GET_GATEWAY( call ));
616
		case NET_IL_PACKET_SPACE:
617
			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 )));
618
			* answer_count = 3;
619
			return EOK;
3466 mejdrech 620
	}
621
	return ENOTSUP;
622
}
623
 
4505 mejdrech 624
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 ){
625
	ip_netif_ref	netif;
4575 mejdrech 626
	int				index;
4505 mejdrech 627
 
628
	if( !( addr_len && prefix && content && suffix )) return EBADMEM;
4575 mejdrech 629
	* content = IP_MAX_CONTENT - IP_PREFIX;
4582 mejdrech 630
	fibril_rwlock_read_lock( & ip_globals.netifs_lock );
4575 mejdrech 631
	if( device_id < 0 ){
632
		* addr_len = IP_ADDR;
633
		* prefix = 0;
634
		* suffix = 0;
635
		for( index = ip_netifs_count( & ip_globals.netifs ) - 1; index >= 0; -- index ){
636
			netif = ip_netifs_get_index( & ip_globals.netifs, index );
637
			if( netif ){
638
				if( netif->addr_len > * addr_len ) * addr_len = netif->addr_len;
639
				if( netif->prefix > * prefix ) * prefix = netif->prefix;
640
				if( netif->suffix > * suffix ) * suffix = netif->suffix;
641
			}
642
		}
643
		* prefix = * prefix + IP_PREFIX;
644
		* suffix = * suffix + IP_SUFFIX;
645
	}else{
646
		netif = ip_netifs_find( & ip_globals.netifs, device_id );
647
		if( ! netif ){
4582 mejdrech 648
			fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
4575 mejdrech 649
			return ENOENT;
650
		}
651
		* addr_len = ( netif->addr_len > IP_ADDR ) ? netif->addr_len : IP_ADDR;
652
		* prefix = netif->prefix + IP_PREFIX;
653
		* suffix = netif->suffix + IP_SUFFIX;
4505 mejdrech 654
	}
4582 mejdrech 655
	fibril_rwlock_read_unlock( & ip_globals.netifs_lock );
4505 mejdrech 656
	return EOK;
657
}
658
 
659
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 ){
660
	ip_route_ref	route;
661
	ip_netif_ref	netif;
662
	int				index;
663
 
4582 mejdrech 664
	fibril_rwlock_write_lock( & ip_globals.netifs_lock );
4505 mejdrech 665
	netif = ip_netifs_find( & ip_globals.netifs, device_id );
4558 mejdrech 666
	if( ! netif ){
4582 mejdrech 667
		fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
4558 mejdrech 668
		return ENOENT;
669
	}
4505 mejdrech 670
	route = ( ip_route_ref ) malloc( sizeof( ip_route_t ));
4558 mejdrech 671
	if( ! route ){
4582 mejdrech 672
		fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
4558 mejdrech 673
		return ENOMEM;
674
	}
4505 mejdrech 675
	route->address.s_addr = address.s_addr;
676
	route->netmask.s_addr = netmask.s_addr;
677
	route->gateway.s_addr = gateway.s_addr;
678
	route->netif = netif;
679
	index = ip_routes_add( & netif->routes, route );
680
	if( index < 0 ) free( route );
4582 mejdrech 681
	fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
4505 mejdrech 682
	return index;
683
}
684
 
685
ip_route_ref ip_find_route( in_addr_t destination ){
686
	int				index;
687
	ip_route_ref	route;
688
	ip_netif_ref	netif;
689
 
690
	// start with the last netif - the newest one
691
	index = ip_netifs_count( & ip_globals.netifs ) - 1;
692
	while( index >= 0 ){
693
		netif = ip_netifs_get_index( & ip_globals.netifs, index );
694
		if( netif && ( netif->state == NETIF_ACTIVE )){
695
			route = ip_netif_find_route( netif, destination );
696
			if( route ) return route;
697
		}
698
		-- index;
699
	}
700
	return & ip_globals.gateway;
701
}
702
 
703
ip_route_ref ip_netif_find_route( ip_netif_ref netif, in_addr_t destination ){
704
	int				index;
705
	ip_route_ref	route;
706
 
707
	if( netif ){
708
		// start with the first one - the direct route
709
		for( index = 0; index < ip_routes_count( & netif->routes ); ++ index ){
710
			route = ip_routes_get_index( & netif->routes, index );
711
			if( route && (( route->address.s_addr & route->netmask.s_addr ) == ( destination.s_addr & route->netmask.s_addr ))){
712
				return route;
713
			}
714
		}
715
	}
716
	return NULL;
717
}
718
 
719
int ip_set_gateway_req( int ip_phone, device_id_t device_id, in_addr_t gateway ){
720
	ip_netif_ref	netif;
721
 
4582 mejdrech 722
	fibril_rwlock_write_lock( & ip_globals.netifs_lock );
4505 mejdrech 723
	netif = ip_netifs_find( & ip_globals.netifs, device_id );
4558 mejdrech 724
	if( ! netif ){
4582 mejdrech 725
		fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
4558 mejdrech 726
		return ENOENT;
727
	}
4505 mejdrech 728
	ip_globals.gateway.address.s_addr = 0;
729
	ip_globals.gateway.netmask.s_addr = 0;
730
	ip_globals.gateway.gateway.s_addr = gateway.s_addr;
731
	ip_globals.gateway.netif = netif;
4582 mejdrech 732
	fibril_rwlock_write_unlock( & ip_globals.netifs_lock );
4505 mejdrech 733
	return EOK;
734
}
735
 
736
packet_t ip_split_packet( packet_t packet, size_t prefix, size_t content, size_t suffix, size_t addr_len ){
737
	size_t			length;
738
	packet_t		next;
739
	packet_t		new_packet;
740
 
741
	next = packet;
742
	// check all packets
743
	while( next ){
744
		length = packet_get_data_length( next );
745
		// too long?
746
		if( length > content ){
747
			if( ip_fragment_packet( next, content, prefix, suffix, addr_len ) != EOK ){
748
				new_packet = pq_detach( next );
749
				if( next == packet ){
750
					packet = new_packet;
751
				}
752
				pq_release( ip_globals.net_phone, packet_get_id( next ));
753
				next = new_packet;
754
				continue;
755
			}
756
		}
757
		next = pq_next( next );
758
	}
759
	return packet;
760
}
761
 
762
int ip_fragment_packet( packet_t packet, size_t length, size_t prefix, size_t suffix, size_t addr_len ){
763
	ERROR_DECLARE;
764
 
765
	packet_t		new_packet;
766
	ip_header_ref	header;
767
	ip_header_ref	middle_header;
768
	ip_header_ref	last_header;
769
	uint8_t *		src;
770
	uint8_t *		dest;
771
	int				address_length;
772
 
773
	address_length = packet_get_addr( packet, & src, & dest );
774
	if( address_length <= 0 ) return EINVAL;
775
	if( packet_get_data_length( packet ) <= sizeof( ip_header_t )) return ENOMEM;
776
	// get header
777
	header = ( ip_header_ref ) packet_get_data( packet );
778
	if( ! header ) return EINVAL;
779
	// fragmentation forbidden?
780
	if( header->flags & IPFLAG_DONT_FRAGMENT ){
781
		// TODO fragmentation necessary ICMP
782
		return EPERM;
783
	}
784
	// create the last fragment
4558 mejdrech 785
	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 786
	if( ! new_packet ) return ENOMEM;
4589 mejdrech 787
	// allocate as much as originally
788
	last_header = ( ip_header_ref ) packet_suffix( new_packet, IP_HEADER_LENGTH( header ));
4505 mejdrech 789
	if( ! last_header ){
790
		pq_release( ip_globals.net_phone, packet_get_id( new_packet ));
791
		return ENOMEM;
792
	}
4589 mejdrech 793
	ip_create_last_header( last_header, header );
794
	// trim the unused space
795
	if( ERROR_OCCURRED( packet_trim( new_packet, 0, IP_HEADER_LENGTH( header ) - IP_HEADER_LENGTH( last_header )))){
796
		pq_release( ip_globals.net_phone, packet_get_id( new_packet ));
797
		return ERROR_CODE;
798
	}
4505 mejdrech 799
	// biggest multiple of 8 lower than content
800
	// TODO even fragmentation?
801
	length = length & ( ~ 0x7 );// ( content / 8 ) * 8
802
	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 ))){
803
		pq_release( ip_globals.net_phone, packet_get_id( new_packet ));
804
		return ERROR_CODE;
805
	}
806
	// mark the first as fragmented
807
	header->flags |= IPFLAG_MORE_FRAGMENTS;
808
	// create middle framgents
809
	while( IP_TOTAL_LENGTH( header ) > length ){
810
		new_packet = packet_get_4( ip_globals.net_phone, prefix, length, suffix, (( address_length >= addr_len ) ? address_length : addr_len ));
811
		if( ! new_packet ) return ENOMEM;
812
		middle_header = ip_create_middle_header( new_packet, last_header );
813
		if( ! middle_header ){
814
			pq_release( ip_globals.net_phone, packet_get_id( new_packet ));
815
			return ENOMEM;
816
		}
817
		if( ERROR_OCCURRED( ip_fragment_packet_data( packet, new_packet, header, middle_header, length - IP_HEADER_LENGTH( middle_header ), src, dest, address_length ))){
818
			pq_release( ip_globals.net_phone, packet_get_id( new_packet ));
819
			return ERROR_CODE;
820
		}
821
	}
822
	// finish the first fragment
823
	header->header_checksum = IP_HEADER_CHECKSUM( header );
824
	printf( "ok\n" );
825
	return EOK;
826
}
827
 
828
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 ){
829
	ERROR_DECLARE;
830
 
831
	void *			data;
832
 
833
	data = packet_suffix( new_packet, length );
834
	if( ! data ) return ENOMEM;
835
	memcpy( data, (( void * ) header ) + IP_TOTAL_LENGTH( header ) - length, length );
836
	ERROR_PROPAGATE( packet_trim( packet, 0, length ));
837
	header->total_length = htons( IP_TOTAL_LENGTH( header ) - length );
838
	new_header->total_length = htons( IP_HEADER_LENGTH( new_header ) + length );
839
	new_header->fragment_offset = header->fragment_offset + IP_HEADER_DATA_LENGTH( header ) / 8;
840
	new_header->header_checksum = IP_HEADER_CHECKSUM( new_header );
841
	ERROR_PROPAGATE( packet_set_addr( new_packet, src, dest, address_length ));
842
	return pq_insert_after( packet, new_packet );
843
}
844
 
845
ip_header_ref ip_create_middle_header( packet_t packet, ip_header_ref last ){
846
	ip_header_ref	middle;
847
 
848
	middle = ( ip_header_ref ) packet_suffix( packet, IP_HEADER_LENGTH( last ));
849
	if( ! middle ) return NULL;
850
	memcpy( middle, last, IP_HEADER_LENGTH( last ));
851
	middle->flags |= IPFLAG_MORE_FRAGMENTS;
852
	return middle;
853
}
854
 
4589 mejdrech 855
void ip_create_last_header( ip_header_ref last, ip_header_ref first ){
4505 mejdrech 856
	ip_option_ref	option;
857
	size_t			next;
858
	size_t			length;
859
 
860
	// copy first itself
861
	memcpy( last, first, sizeof( ip_header_t ));
862
	length = sizeof( ip_header_t );
863
	next = sizeof( ip_header_t );
864
	// process all ip options
865
	while( next < first->ihl ){
866
		option = ( ip_option_ref ) ((( void * ) first ) + next );
867
		// skip end or noop
868
		if(( option->type == IPOPT_END ) || ( option->type == IPOPT_NOOP )){
869
			++ next;
870
		}else{
871
			// copy if said so or skip
872
			if( IPOPT_COPIED( option->type )){
873
				memcpy((( void * ) last ) + length, (( void * ) first ) + next, option->length );
874
				length += option->length;
875
			}
876
			// next option
877
			next += option->length;
878
		}
879
	}
880
	// align 4 byte boundary
881
	if( length % 4 ){
882
		bzero((( void * ) last ) + length, 4 - ( length % 4 ));
883
		last->ihl = length / 4 + 1;
884
	}else{
885
		last->ihl = length / 4;
886
	}
4589 mejdrech 887
	last->header_checksum = 0;
4505 mejdrech 888
}
889
 
890
int ip_received_msg( device_id_t device_id, packet_t packet ){
891
	packet_t		next;
892
 
893
	do{
894
		next = pq_detach( packet );
895
		if( ip_process_packet( device_id, packet ) != EOK ){
896
			pq_release( ip_globals.net_phone, packet_get_id( packet ));
897
		}
898
		packet = next;
899
	}while( packet );
900
	return EOK;
901
}
902
 
903
int ip_process_packet( device_id_t device_id, packet_t packet ){
904
	ERROR_DECLARE;
905
 
906
	ip_header_ref	header;
907
	in_addr_t		dest;
908
	ip_route_ref	route;
909
 
910
	header = ( ip_header_ref ) packet_get_data( packet );
911
	if( ! header ) return ENOMEM;
912
	// checksum
913
	if(( header->header_checksum ) && ( IP_HEADER_CHECKSUM( header ))){
914
		// TODO checksum error ICMP?
915
		return EINVAL;
916
	}
917
	// TODO ttl oxceeded ICMP?
918
	if( !( -- header->ttl )) return EINVAL;
919
	// process ipopt and get destination
920
	dest = ip_get_destination( header );
921
	ERROR_PROPAGATE( packet_set_addr( packet, NULL, ( uint8_t * ) & dest.s_addr, IP_ADDR ));
922
	route = ip_find_route( dest );
923
	// TODO unreachable ICMP?
924
	if( ! route ) return ENOENT;
925
	if( route->address.s_addr == dest.s_addr ){
926
		// local delivery
927
		return ip_deliver_local( device_id, packet, header );
928
	}else{
929
		return ip_send_route( packet, route->netif, route, NULL, dest );
930
	}
931
}
932
 
933
int ip_deliver_local( device_id_t device_id, packet_t packet, ip_header_ref header ){
934
	ERROR_DECLARE;
935
 
936
	ip_proto_ref	proto;
937
 
938
	if(( header->flags & IPFLAG_MORE_FRAGMENTS ) || header->fragment_offset ){
939
		// TODO fragmented
940
		return ENOTSUP;
941
	}else{
4558 mejdrech 942
		ERROR_PROPAGATE( packet_set_addr( packet, ( uint8_t * ) & header->source_address, ( uint8_t * ) & header->destination_address, IP_ADDR ));
4582 mejdrech 943
		fibril_rwlock_read_lock( & ip_globals.protos_lock );
4505 mejdrech 944
		proto = ip_protos_find( & ip_globals.protos, header->protocol );
4558 mejdrech 945
		if( ! proto ){
4582 mejdrech 946
			fibril_rwlock_read_unlock( & ip_globals.protos_lock );
4558 mejdrech 947
			return ENOENT;
948
		}
949
		if( proto->received_msg ){
950
			ERROR_CODE = proto->received_msg( device_id, packet, SERVICE_IP );
4505 mejdrech 951
		}else{
4558 mejdrech 952
			ERROR_CODE = tl_received_msg( proto->phone, device_id, packet, proto->service );
4505 mejdrech 953
		}
4582 mejdrech 954
		fibril_rwlock_read_unlock( & ip_globals.protos_lock );
4558 mejdrech 955
		return ERROR_CODE;
4505 mejdrech 956
	}
957
}
958
 
959
in_addr_t ip_get_destination( ip_header_ref header ){
960
	in_addr_t	destination;
961
 
962
	// TODO search set ipopt route?
963
	destination.s_addr = header->destination_address; //ntohl( header->destination_address );
964
	return destination;
965
}
966
 
3466 mejdrech 967
/** @}
968
 */