Subversion Repositories HelenOS

Rev

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

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