Subversion Repositories HelenOS

Rev

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