Subversion Repositories HelenOS

Rev

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