Subversion Repositories HelenOS

Rev

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