Subversion Repositories HelenOS

Rev

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

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