Subversion Repositories HelenOS

Rev

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

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