Subversion Repositories HelenOS

Rev

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