Subversion Repositories HelenOS

Rev

Rev 4708 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4708 Rev 4715
Line 34... Line 34...
34
 *  ICMP module implementation.
34
 *  ICMP module implementation.
35
 *  @see icmp.h
35
 *  @see icmp.h
36
 */
36
 */
37
 
37
 
38
#include <async.h>
38
#include <async.h>
-
 
39
#include <atomic.h>
-
 
40
#include <fibril.h>
39
#include <fibril_sync.h>
41
#include <fibril_sync.h>
40
 
42
 
41
#include <ipc/ipc.h>
43
#include <ipc/ipc.h>
42
#include <ipc/services.h>
44
#include <ipc/services.h>
43
 
45
 
-
 
46
#include <sys/types.h>
-
 
47
 
44
#include "../../err.h"
48
#include "../../err.h"
45
#include "../../messages.h"
49
#include "../../messages.h"
46
#include "../../modules.h"
50
#include "../../modules.h"
47
 
51
 
48
#include "../../structures/packet/packet_client.h"
52
#include "../../structures/packet/packet_client.h"
49
 
53
 
-
 
54
#include "../../include/byteorder.h"
50
#include "../../include/crc.h"
55
#include "../../include/crc.h"
51
#include "../../include/icmp_codes.h"
56
#include "../../include/icmp_api.h"
52
#include "../../include/icmp_client.h"
57
#include "../../include/icmp_client.h"
-
 
58
#include "../../include/icmp_codes.h"
-
 
59
#include "../../include/icmp_common.h"
53
#include "../../include/icmp_interface.h"
60
#include "../../include/icmp_interface.h"
-
 
61
#include "../../include/il_interface.h"
-
 
62
#include "../../include/inet.h"
54
#include "../../include/ip_client.h"
63
#include "../../include/ip_client.h"
55
#include "../../include/ip_interface.h"
64
#include "../../include/ip_interface.h"
56
#include "../../include/il_interface.h"
-
 
57
#include "../../include/ip_protocols.h"
65
#include "../../include/ip_protocols.h"
-
 
66
#include "../../include/socket_codes.h"
-
 
67
#include "../../include/socket_errno.h"
58
 
68
 
59
#include "../../tl/tl_messages.h"
69
#include "../../tl/tl_messages.h"
60
 
70
 
61
#include "icmp.h"
71
#include "icmp.h"
62
#include "icmp_header.h"
72
#include "icmp_header.h"
63
#include "icmp_messages.h"
73
#include "icmp_messages.h"
64
#include "icmp_module.h"
74
#include "icmp_module.h"
65
 
75
 
66
#define ICMP_KEEP_LENGTH    8
76
#define ICMP_KEEP_LENGTH    8
67
 
77
 
68
#define ICMP_HEADER_CHECKSUM( header )      compact_checksum(compute_checksum( 0, ( uint8_t * ) header, sizeof( icmp_header_t )))
78
#define ICMP_CHECKSUM( header, length )     htons( ip_checksum(( uint8_t * ) ( header ), ( length )))
-
 
79
 
-
 
80
#define ICMP_ECHO_TEXT                  "Hello from HelenOS."
-
 
81
 
-
 
82
#define ICMP_GET_LOCK_KEY( id, sequence )   ((( id ) << 16 ) | ( sequence & 0xFFFF ))
69
 
83
 
70
/** Processes the received ICMP packet.
84
/** Processes the received ICMP packet.
71
 *  Is used as an entry point from the underlying IP module.
85
 *  Is used as an entry point from the underlying IP module.
72
 *  Releases the packet on error.
86
 *  Releases the packet on error.
73
 *  @param device_id The device identifier. Ignored parameter.
87
 *  @param device_id The device identifier. Ignored parameter.
Line 80... Line 94...
80
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
94
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
81
 
95
 
82
/** Processes the received ICMP packet.
96
/** Processes the received ICMP packet.
83
 *  Notifies the destination socket application.
97
 *  Notifies the destination socket application.
84
 *  @param packet The received packet. Input/output parameter.
98
 *  @param packet The received packet. Input/output parameter.
-
 
99
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
85
 *  @returns EOK on success.
100
 *  @returns EOK on success.
86
 *  @returns EINVAL if the packet is not valid.
101
 *  @returns EINVAL if the packet is not valid.
87
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
102
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
88
 *  @returns EINVAL if the packet does not contain any data.
103
 *  @returns EINVAL if the packet does not contain any data.
89
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
104
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
90
 *  @returns ENOMEM if there is not enough memory left.
105
 *  @returns ENOMEM if there is not enough memory left.
91
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
106
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
92
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
107
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
93
 */
108
 */
94
int icmp_process_packet( packet_t packet );
109
int icmp_process_packet( packet_t packet, services_t error );
-
 
110
 
-
 
111
/** Processes the client messages.
-
 
112
 *  Remenbers the assigned identifier and sequence numbers.
-
 
113
 *  Runs until the client module disconnects.
-
 
114
 *  @param callid The message identifier. Input parameter.
-
 
115
 *  @param call The message parameters. Input parameter.
-
 
116
 *  @returns EOK on success.
-
 
117
 *  @see icmp_interface.h
-
 
118
 */
-
 
119
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
95
 
120
 
-
 
121
/** Releases the packet and returns the result.
-
 
122
 *  @param packet The packet queue to be released. Input parameter.
-
 
123
 *  @param result The result to be returned. Input parameter.
-
 
124
 *  @return The result parameter.
-
 
125
 */
-
 
126
int icmp_release_and_return( packet_t packet, int result );
-
 
127
 
-
 
128
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen );
96
icmp_header_ref icmp_prepare_packet( packet_t packet );
129
icmp_header_ref icmp_prepare_packet( packet_t packet );
97
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header );
130
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error );
-
 
131
int process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code );
98
 
132
 
99
/** ICMP global data.
133
/** ICMP global data.
100
 */
134
 */
101
icmp_globals_t  icmp_globals;
135
icmp_globals_t  icmp_globals;
102
 
136
 
-
 
137
INT_MAP_IMPLEMENT( time_locks, atomic_t );
-
 
138
 
-
 
139
GENERIC_FIELD_IMPLEMENT( echo_data, icmp_echo_t );
-
 
140
 
103
int icmp_echo_msg( int icmp_phone, icmp_param_t identifier, icmp_param_t sequence_number, const void * data, size_t length ){
141
int icmp_echo_msg( int icmp_phone, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
-
 
142
    icmp_echo_ref   echo_data;
-
 
143
    int             res;
-
 
144
 
-
 
145
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
146
    // use the phone as the echo data index
-
 
147
    echo_data = echo_data_get_index( & icmp_globals.echo_data, icmp_phone );
-
 
148
    if( ! echo_data ){
-
 
149
        res = ENOENT;
-
 
150
    }else{
-
 
151
        res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen );
-
 
152
        ++ echo_data->sequence;
-
 
153
    }
-
 
154
    fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
155
    return res;
-
 
156
}
-
 
157
 
-
 
158
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, suseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
-
 
159
    ERROR_DECLARE;
-
 
160
 
-
 
161
    icmp_header_ref header;
-
 
162
    packet_t        packet;
-
 
163
    size_t          offset;
-
 
164
    uint8_t *       data;
-
 
165
    atomic_t *      lock;
-
 
166
    int             result;
-
 
167
    int             index;
-
 
168
    int             lock_key;
-
 
169
    struct sockaddr_in *    address_in;
-
 
170
    struct timeval  time_before;
-
 
171
    struct timeval  time_after;
-
 
172
 
104
    // TODO echo - with timeout
173
    // TODO do not ask all the time
-
 
174
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
-
 
175
    packet = packet_get_4( icmp_globals.net_phone, size, icmp_globals.addr_len, sizeof( icmp_header_t ) + icmp_globals.prefix, icmp_globals.suffix );
-
 
176
    if( ! packet ) return ENOMEM;
-
 
177
    // set the destination address
-
 
178
    if( addrlen < sizeof( struct sockaddr )){
-
 
179
        return icmp_release_and_return( packet, EINVAL );
-
 
180
    }
-
 
181
    switch( addr->sa_family ){
-
 
182
        case AF_INET:
-
 
183
            if( addrlen != sizeof( struct sockaddr_in )){
-
 
184
                return icmp_release_and_return( packet, EINVAL );
-
 
185
            }
-
 
186
            address_in = ( struct sockaddr_in * ) addr;
-
 
187
            if( ERROR_OCCURRED( packet_set_addr( packet, NULL, ( uint8_t * ) & address_in->sin_addr.s_addr, sizeof( address_in->sin_addr.s_addr )))){
-
 
188
                return icmp_release_and_return( packet, ERROR_CODE );
-
 
189
            }
-
 
190
            break;
-
 
191
        default:
-
 
192
            return icmp_release_and_return( packet, EAFNOSUPPORT );
-
 
193
    }
105
    // waits for the reply up to the timeout
194
    // allocate space in the packet
-
 
195
    data = ( uint8_t * ) packet_suffix( packet, size );
-
 
196
    if( ! data ){
-
 
197
        return icmp_release_and_return( packet, ENOMEM );
-
 
198
    }
-
 
199
    offset = 0;
-
 
200
    while( size > offset + sizeof( ICMP_ECHO_TEXT )){
-
 
201
        memcpy( data + offset, ICMP_ECHO_TEXT, sizeof( ICMP_ECHO_TEXT ));
-
 
202
        offset += sizeof( ICMP_ECHO_TEXT );
-
 
203
    }
-
 
204
    memcpy( data + offset, ICMP_ECHO_TEXT, size - offset );
-
 
205
    header = icmp_prepare_packet( packet );
-
 
206
    if( ! header ){
-
 
207
        return icmp_release_and_return( packet, ENOMEM );
-
 
208
    }
-
 
209
    header->un.echo.id = id;
-
 
210
    header->un.echo.sequence = sequence;
-
 
211
    lock_key = ICMP_GET_LOCK_KEY( header->un.echo.id, header->un.echo.sequence );
-
 
212
    // create a locked fuxed
-
 
213
    lock = malloc( sizeof( * lock ));
-
 
214
    if( ! lock ){
-
 
215
        return icmp_release_and_return( packet, ENOMEM );
-
 
216
    }
-
 
217
    atomic_set( lock, 0 );
-
 
218
    index = time_locks_add( & icmp_globals.time_locks, lock_key, lock );
-
 
219
    if( index < 0 ){
-
 
220
        free( lock );
-
 
221
        return icmp_release_and_return( packet, index );
-
 
222
    }
-
 
223
    if( ERROR_OCCURRED( icmp_send_packet( ICMP_ECHO, 0, packet, header, 0 ))){
-
 
224
        free( lock );
-
 
225
        return icmp_release_and_return( packet, ERROR_CODE );
-
 
226
    }
-
 
227
    // unlock the global to allow unlocking and other fibrils to work
-
 
228
    // try to lock again - may be unlocked by the reply
-
 
229
    ERROR_PROPAGATE( gettimeofday( & time_before, NULL ));
-
 
230
    do{
-
 
231
        result = atomic_get( lock );
-
 
232
        if( result ){
-
 
233
            break;
-
 
234
        }else{
-
 
235
            fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
236
            // TODO does not yield?
-
 
237
            //printf( "y %d\n", fibril_yield());
-
 
238
            fibril_yield();
-
 
239
            fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
240
            ERROR_PROPAGATE( gettimeofday( & time_after, NULL ));
-
 
241
        }
-
 
242
    }while( tv_sub( & time_after, & time_before ) <= timeout );
-
 
243
    if( ! result ){
-
 
244
        result = ELIMIT;
-
 
245
    }
-
 
246
    // destroy the lock
-
 
247
    time_locks_exclude_index( & icmp_globals.time_locks, index );
106
    return ENOTSUP;
248
    return result;
107
}
249
}
108
 
250
 
109
int icmp_destination_unreachable_msg( int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet ){
251
int icmp_destination_unreachable_msg( int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet ){
110
    icmp_header_ref header;
252
    icmp_header_ref header;
111
 
253
 
112
    header = icmp_prepare_packet( packet );
254
    header = icmp_prepare_packet( packet );
113
    if( ! header ) return ENOMEM;
255
    if( ! header ) return ENOMEM;
114
    if( mtu ){
256
    if( mtu ){
115
        header->un.frag.mtu = mtu;
257
        header->un.frag.mtu = mtu;
116
    }
258
    }
117
    return icmp_send_packet( ICMP_DEST_UNREACH, code, packet, header );
259
    return icmp_send_packet( ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP );
118
}
260
}
119
 
261
 
120
int icmp_source_quench_msg( int icmp_phone, packet_t packet ){
262
int icmp_source_quench_msg( int icmp_phone, packet_t packet ){
121
    icmp_header_ref header;
263
    icmp_header_ref header;
122
 
264
 
123
    header = icmp_prepare_packet( packet );
265
    header = icmp_prepare_packet( packet );
124
    if( ! header ) return ENOMEM;
266
    if( ! header ) return ENOMEM;
125
    return icmp_send_packet( ICMP_SOURCE_QUENCH, ICMP_SOURCE_QUENCH, packet, header );
267
    return icmp_send_packet( ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP );
126
}
268
}
127
 
269
 
128
int icmp_time_exceeded_msg( int icmp_phone, icmp_code_t code, packet_t packet ){
270
int icmp_time_exceeded_msg( int icmp_phone, icmp_code_t code, packet_t packet ){
129
    icmp_header_ref header;
271
    icmp_header_ref header;
130
 
272
 
131
    header = icmp_prepare_packet( packet );
273
    header = icmp_prepare_packet( packet );
132
    if( ! header ) return ENOMEM;
274
    if( ! header ) return ENOMEM;
133
    return icmp_send_packet( ICMP_TIME_EXCEEDED, code, packet, header );
275
    return icmp_send_packet( ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP );
134
}
276
}
135
 
277
 
136
int icmp_parameter_problem_msg( int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet ){
278
int icmp_parameter_problem_msg( int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet ){
137
    icmp_header_ref header;
279
    icmp_header_ref header;
138
 
280
 
139
    header = icmp_prepare_packet( packet );
281
    header = icmp_prepare_packet( packet );
140
    if( ! header ) return ENOMEM;
282
    if( ! header ) return ENOMEM;
141
    header->un.param.pointer = pointer;
283
    header->un.param.pointer = pointer;
142
    return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header );
284
    return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP );
143
}
285
}
144
 
286
 
145
icmp_header_ref icmp_prepare_packet( packet_t packet ){
287
icmp_header_ref icmp_prepare_packet( packet_t packet ){
146
    icmp_header_ref header;
288
    icmp_header_ref header;
147
    int             header_length;
289
    int             header_length;
Line 162... Line 304...
162
    }
304
    }
163
    bzero( header, sizeof( * header ));
305
    bzero( header, sizeof( * header ));
164
    return header;
306
    return header;
165
}
307
}
166
 
308
 
167
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header ){
309
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error ){
168
    ERROR_DECLARE;
310
    ERROR_DECLARE;
169
 
311
 
170
    header->type = type;
312
    header->type = type;
171
    header->code = code;
313
    header->code = code;
172
    header->checksum = 0;
314
    header->checksum = 0;
173
    header->checksum = ICMP_HEADER_CHECKSUM( header );
315
    header->checksum = ICMP_CHECKSUM( header, packet_get_data_length( packet ));
174
    if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_ICMP, 0, 0, 0, 0 ))){
316
    if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_ICMP, 0, 0, 0, 0 ))){
175
        pq_release( icmp_globals.net_phone, packet_get_id( packet ));
317
        pq_release( icmp_globals.net_phone, packet_get_id( packet ));
176
        return ERROR_CODE;
318
        return ERROR_CODE;
177
    }
319
    }
178
    return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, SERVICE_ICMP );
320
    return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error );
179
}
321
}
180
 
322
 
181
int icmp_connect_module( services_t service ){
323
int icmp_connect_module( services_t service ){
-
 
324
    icmp_echo_ref   echo_data;
-
 
325
    int             index;
-
 
326
 
-
 
327
    echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data ));
-
 
328
    if( ! echo_data ) return ENOMEM;
-
 
329
    // assign a new identifier
-
 
330
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
331
    ++ icmp_globals.last_used_id;
-
 
332
    echo_data->id = icmp_globals.last_used_id;
-
 
333
    echo_data->sequence = 0;
-
 
334
    // remember the assigned echo data
-
 
335
    index = echo_data_add( & icmp_globals.echo_data, echo_data );
-
 
336
    if( index < 0 ){
-
 
337
        free( echo_data );
-
 
338
    }
-
 
339
    fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
340
    // return the echo data index as the ICMP phone
182
    return EOK;
341
    return index;
183
}
342
}
184
 
343
 
185
int icmp_initialize( async_client_conn_t client_connection ){
344
int icmp_initialize( async_client_conn_t client_connection ){
186
    ERROR_DECLARE;
345
    ERROR_DECLARE;
187
 
346
 
188
    fibril_rwlock_initialize( & icmp_globals.lock );
347
    fibril_rwlock_initialize( & icmp_globals.lock );
189
    fibril_rwlock_write_lock( & icmp_globals.lock );
348
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
349
    time_locks_initialize( & icmp_globals.time_locks );
-
 
350
    echo_data_initialize( & icmp_globals.echo_data );
190
    icmp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg );
351
    icmp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg );
191
    if( icmp_globals.ip_phone < 0 ){
352
    if( icmp_globals.ip_phone < 0 ){
192
        return icmp_globals.ip_phone;
353
        return icmp_globals.ip_phone;
193
    }
354
    }
194
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
355
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
Line 199... Line 360...
199
}
360
}
200
 
361
 
201
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
362
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
202
    ERROR_DECLARE;
363
    ERROR_DECLARE;
203
 
364
 
204
    if( error ){
-
 
205
        pq_release( icmp_globals.net_phone, packet_get_id( packet ));
-
 
206
        return EINVAL;
-
 
207
    }
-
 
208
    if( ERROR_OCCURRED( icmp_process_packet( packet ))){
365
    if( ERROR_OCCURRED( icmp_process_packet( packet, error ))){
209
        pq_release( icmp_globals.net_phone, packet_get_id( packet ));
366
        pq_release( icmp_globals.net_phone, packet_get_id( packet ));
210
        return ERROR_CODE;
367
        return ERROR_CODE;
211
    }
368
    }
212
 
369
 
213
    return EOK;
370
    return EOK;
214
}
371
}
215
 
372
 
216
int icmp_process_packet( packet_t packet ){
373
int icmp_process_packet( packet_t packet, services_t error ){
-
 
374
    ERROR_DECLARE;
-
 
375
 
217
    size_t          length;
376
    size_t          length;
-
 
377
    uint8_t *       src;
-
 
378
    int             addrlen;
218
    int             result;
379
    int             result;
219
    void *          data;
380
    void *          data;
220
    icmp_header_ref header;
381
    icmp_header_ref header;
-
 
382
    icmp_type_t     type;
-
 
383
    icmp_code_t     code;
221
 
384
 
-
 
385
    if( error ){
-
 
386
        switch( error ){
-
 
387
            case SERVICE_ICMP:
-
 
388
                // process error
-
 
389
                // TODO remove debug dump
-
 
390
                // length = icmp_client_header_length( packet );
-
 
391
                result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
-
 
392
                if( result < 0 ) return result;
-
 
393
                length = ( size_t ) result;
-
 
394
                printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) );
-
 
395
                ERROR_PROPAGATE( packet_trim( packet, length, 0 ));
-
 
396
                break;
-
 
397
            default:
-
 
398
                return ENOTSUP;
-
 
399
        }
-
 
400
    }
222
    // get rid of the ip header
401
    // get rid of the ip header
223
    result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
402
    result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
224
    if( result < 0 ) return result;
403
    if( result < 0 ) return result;
225
    packet_trim( packet, ( size_t ) result, 0 );
404
    packet_trim( packet, ( size_t ) result, 0 );
226
 
405
 
Line 230... Line 409...
230
    data = packet_get_data( packet );
409
    data = packet_get_data( packet );
231
    if( ! data ) return EINVAL;
410
    if( ! data ) return EINVAL;
232
    // get icmp header
411
    // get icmp header
233
    header = ( icmp_header_ref ) data;
412
    header = ( icmp_header_ref ) data;
234
    // checksum
413
    // checksum
235
    if(( header->checksum ) && ( ICMP_HEADER_CHECKSUM( header ))){
414
    if(( header->checksum ) && ( ICMP_CHECKSUM( header, length ))){
236
        return EINVAL;
415
        return EINVAL;
237
    }
416
    }
-
 
417
    switch( header->type ){
-
 
418
        case ICMP_ECHOREPLY:
-
 
419
            return process_echo_reply( packet, header, ICMP_ECHO, 0 );
-
 
420
        case ICMP_ECHO:
-
 
421
            if( error ){
238
    // TODO process requests and replies
422
                return process_echo_reply( packet, header, type, code );
-
 
423
            }else{
-
 
424
                addrlen = packet_get_addr( packet, & src, NULL );
-
 
425
                if(( addrlen > 0 )
-
 
426
                // set both addresses to the source one (avoids the source address deletion before setting the destination one)
-
 
427
                && ( packet_set_addr( packet, src, src, ( size_t ) addrlen ) == EOK )){
-
 
428
                    // send the reply
-
 
429
                    return icmp_send_packet( ICMP_ECHOREPLY, 0, packet, header, 0 );
-
 
430
                }else{
-
 
431
                    return icmp_release_and_return( packet, EINVAL );
-
 
432
                }
-
 
433
            }
-
 
434
        case ICMP_DEST_UNREACH:
-
 
435
        case ICMP_SOURCE_QUENCH:
-
 
436
        case ICMP_REDIRECT:
-
 
437
        case ICMP_ALTERNATE_ADDR:
-
 
438
        case ICMP_ROUTER_ADV:
-
 
439
        case ICMP_ROUTER_SOL:
-
 
440
        case ICMP_TIME_EXCEEDED:
-
 
441
        case ICMP_PARAMETERPROB:
-
 
442
        case ICMP_CONVERSION_ERROR:
-
 
443
        case ICMP_REDIRECT_MOBILE:
-
 
444
        case ICMP_SKIP:
-
 
445
        case ICMP_PHOTURIS:
-
 
446
            fibril_rwlock_read_lock( & icmp_globals.lock );
239
    ip_received_error_msg( icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP );
447
            ip_received_error_msg( icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP );
-
 
448
            fibril_rwlock_read_unlock( & icmp_globals.lock );
-
 
449
            return EOK;
-
 
450
        default:
-
 
451
            return icmp_release_and_return( packet, ENOTSUP );
-
 
452
    }
-
 
453
}
-
 
454
 
-
 
455
int process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code ){
-
 
456
    int             lock_key;
-
 
457
    atomic_t *      lock;
-
 
458
 
-
 
459
    lock_key = ICMP_GET_LOCK_KEY( header->un.echo.id, header->un.echo.sequence );
-
 
460
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
461
    lock = time_locks_find( & icmp_globals.time_locks, lock_key );
-
 
462
    if( lock ){
-
 
463
        // unlock the lock for the waiting fibril
-
 
464
        atomic_set( lock, type );
-
 
465
    }
-
 
466
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
-
 
467
    fibril_rwlock_write_unlock( & icmp_globals.lock );
240
    return EOK;
468
    return EOK;
241
}
469
}
242
 
470
 
243
int icmp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
471
int icmp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
244
    ERROR_DECLARE;
472
    ERROR_DECLARE;
245
 
473
 
246
    packet_t    packet;
474
    packet_t            packet;
247
 
475
 
248
    * answer_count = 0;
476
    * answer_count = 0;
249
    switch( IPC_GET_METHOD( * call )){
477
    switch( IPC_GET_METHOD( * call )){
250
        case NET_TL_RECEIVED:
478
        case NET_TL_RECEIVED:
251
            fibril_rwlock_read_lock( & icmp_globals.lock );
-
 
252
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
479
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
253
                ERROR_CODE = icmp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_ICMP, IPC_GET_ERROR( call ));
480
                ERROR_CODE = icmp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_ICMP, IPC_GET_ERROR( call ));
254
            }
481
            }
255
            fibril_rwlock_read_unlock( & icmp_globals.lock );
-
 
256
            return ERROR_CODE;
482
            return ERROR_CODE;
257
        case NET_ICMP_DEST_UNREACH:
483
        case NET_ICMP_INIT:
258
            ERROR_PROPAGATE( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )));
-
 
259
            return icmp_destination_unreachable_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_MTU( call ), packet );
-
 
260
        case NET_ICMP_SOURCE_QUENCH:
-
 
261
            ERROR_PROPAGATE( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )));
-
 
262
            return icmp_source_quench_msg( 0, packet );
484
            return icmp_process_client_messages( callid, * call );
263
        case NET_ICMP_TIME_EXCEEDED:
-
 
264
            ERROR_PROPAGATE( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )));
-
 
265
            return icmp_time_exceeded_msg( 0, ICMP_GET_CODE( call ), packet );
-
 
266
        case NET_ICMP_PARAMETERPROB:
-
 
267
            ERROR_PROPAGATE( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )));
-
 
268
            return icmp_parameter_problem_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_POINTER( call ), packet );
-
 
269
    }
485
    }
270
    return ENOTSUP;
486
    return ENOTSUP;
271
}
487
}
272
 
488
 
-
 
489
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
-
 
490
    ERROR_DECLARE;
-
 
491
 
-
 
492
    bool                    keep_on_going = true;
-
 
493
    fibril_rwlock_t         lock;
-
 
494
    ipc_call_t              answer;
-
 
495
    int                     answer_count;
-
 
496
    packet_t                packet;
-
 
497
    size_t                  addrlen;
-
 
498
    struct sockaddr *       addr;
-
 
499
    icmp_param_t            id;
-
 
500
    icmp_param_t            sequence = 0;
-
 
501
    ipc_callid_t            data_callid;
-
 
502
 
-
 
503
    /*
-
 
504
     * Accept the connection
-
 
505
     *  - Answer the first NET_ICMP_INIT call.
-
 
506
     */
-
 
507
    ipc_answer_0( callid, EOK );
-
 
508
 
-
 
509
    fibril_rwlock_initialize( & lock );
-
 
510
 
-
 
511
    // assign a new identifier
-
 
512
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
513
    ++ icmp_globals.last_used_id;
-
 
514
    id = icmp_globals.last_used_id;
-
 
515
    fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
516
 
-
 
517
    while( keep_on_going ){
-
 
518
        refresh_answer( & answer, & answer_count );
-
 
519
 
-
 
520
        callid = async_get_call( & call );
-
 
521
 
-
 
522
        switch( IPC_GET_METHOD( call )){
-
 
523
            case IPC_M_PHONE_HUNGUP:
-
 
524
                keep_on_going = false;
-
 
525
                ERROR_CODE = EOK;
-
 
526
                break;
-
 
527
            case NET_ICMP_ECHO:
-
 
528
                fibril_rwlock_write_lock( & lock );
-
 
529
                if( ! ipc_data_write_receive( & data_callid, & addrlen )){
-
 
530
                    ERROR_CODE = EINVAL;
-
 
531
                }else{
-
 
532
                    addr = malloc( addrlen );
-
 
533
                    if( ! addr ){
-
 
534
                        ERROR_CODE = ENOMEM;
-
 
535
                    }else{
-
 
536
                        if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, addrlen ))){
-
 
537
                            fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
538
                            ERROR_CODE = icmp_echo( id, sequence, ICMP_GET_SIZE( call ), ICMP_GET_TIMEOUT( call ), ICMP_GET_TTL( call ), ICMP_GET_TOS( call ), ICMP_GET_DONT_FRAGMENT( call ), addr, addrlen );
-
 
539
                            fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
540
                            free( addr );
-
 
541
                            ++ sequence;
-
 
542
                        }
-
 
543
                    }
-
 
544
                }
-
 
545
                fibril_rwlock_write_unlock( & lock );
-
 
546
                break;
-
 
547
            case NET_ICMP_DEST_UNREACH:
-
 
548
                if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
-
 
549
                    ERROR_CODE = icmp_destination_unreachable_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_MTU( call ), packet );
-
 
550
                }
-
 
551
                break;
-
 
552
            case NET_ICMP_SOURCE_QUENCH:
-
 
553
                if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
-
 
554
                    ERROR_CODE = icmp_source_quench_msg( 0, packet );
-
 
555
                }
-
 
556
            case NET_ICMP_TIME_EXCEEDED:
-
 
557
                if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
-
 
558
                    ERROR_CODE = icmp_time_exceeded_msg( 0, ICMP_GET_CODE( call ), packet );
-
 
559
                }
-
 
560
                break;
-
 
561
            case NET_ICMP_PARAMETERPROB:
-
 
562
                if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( & call )))){
-
 
563
                    ERROR_CODE = icmp_parameter_problem_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_POINTER( call ), packet );
-
 
564
                }
-
 
565
            default:
-
 
566
                ERROR_CODE = ENOTSUP;
-
 
567
        }
-
 
568
 
-
 
569
        answer_call( callid, ERROR_CODE, & answer, answer_count );
-
 
570
    }
-
 
571
 
-
 
572
    return EOK;
-
 
573
}
-
 
574
 
-
 
575
int icmp_release_and_return( packet_t packet, int result ){
-
 
576
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
-
 
577
    return result;
-
 
578
}
-
 
579
 
273
/** @}
580
/** @}
274
 */
581
 */