Subversion Repositories HelenOS

Rev

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