Subversion Repositories HelenOS

Rev

Rev 4720 | Rev 4722 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4720 Rev 4721
1
/*
1
/*
2
 * Copyright (c) 2008 Lukas Mejdrech
2
 * Copyright (c) 2008 Lukas Mejdrech
3
 * All rights reserved.
3
 * All rights reserved.
4
 *
4
 *
5
 * Redistribution and use in source and binary forms, with or without
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
6
 * modification, are permitted provided that the following conditions
7
 * are met:
7
 * are met:
8
 *
8
 *
9
 * - Redistributions of source code must retain the above copyright
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
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
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.
15
 *   derived from this software without specific prior written permission.
16
 *
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
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
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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
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.
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
27
 */
28
 
28
 
29
/** @addtogroup icmp
29
/** @addtogroup icmp
30
 *  @{
30
 *  @{
31
 */
31
 */
32
 
32
 
33
/** @file
33
/** @file
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>
39
#include <atomic.h>
40
#include <fibril.h>
40
#include <fibril.h>
41
#include <fibril_sync.h>
41
#include <fibril_sync.h>
-
 
42
#include <stdint.h>
42
 
43
 
43
#include <ipc/ipc.h>
44
#include <ipc/ipc.h>
44
#include <ipc/services.h>
45
#include <ipc/services.h>
45
 
46
 
46
#include <sys/types.h>
47
#include <sys/types.h>
47
 
48
 
48
#include "../../err.h"
49
#include "../../err.h"
49
#include "../../messages.h"
50
#include "../../messages.h"
50
#include "../../modules.h"
51
#include "../../modules.h"
51
 
52
 
52
#include "../../structures/packet/packet_client.h"
53
#include "../../structures/packet/packet_client.h"
53
 
54
 
54
#include "../../include/byteorder.h"
55
#include "../../include/byteorder.h"
55
#include "../../include/crc.h"
56
#include "../../include/crc.h"
56
#include "../../include/icmp_api.h"
57
#include "../../include/icmp_api.h"
57
#include "../../include/icmp_client.h"
58
#include "../../include/icmp_client.h"
58
#include "../../include/icmp_codes.h"
59
#include "../../include/icmp_codes.h"
59
#include "../../include/icmp_common.h"
60
#include "../../include/icmp_common.h"
60
#include "../../include/icmp_interface.h"
61
#include "../../include/icmp_interface.h"
61
#include "../../include/il_interface.h"
62
#include "../../include/il_interface.h"
62
#include "../../include/inet.h"
63
#include "../../include/inet.h"
63
#include "../../include/ip_client.h"
64
#include "../../include/ip_client.h"
64
#include "../../include/ip_interface.h"
65
#include "../../include/ip_interface.h"
65
#include "../../include/ip_protocols.h"
66
#include "../../include/ip_protocols.h"
66
#include "../../include/net_interface.h"
67
#include "../../include/net_interface.h"
67
#include "../../include/socket_codes.h"
68
#include "../../include/socket_codes.h"
68
#include "../../include/socket_errno.h"
69
#include "../../include/socket_errno.h"
69
 
70
 
70
#include "../../tl/tl_messages.h"
71
#include "../../tl/tl_messages.h"
71
 
72
 
72
#include "icmp.h"
73
#include "icmp.h"
73
#include "icmp_header.h"
74
#include "icmp_header.h"
74
#include "icmp_messages.h"
75
#include "icmp_messages.h"
75
#include "icmp_module.h"
76
#include "icmp_module.h"
76
 
77
 
77
/** Original datagram length in bytes transfered to the error notification message.
78
/** Original datagram length in bytes transfered to the error notification message.
78
 */
79
 */
79
#define ICMP_KEEP_LENGTH    8
80
#define ICMP_KEEP_LENGTH    8
80
 
81
 
-
 
82
/** Free identifier numbers pool start.
-
 
83
 */
-
 
84
#define ICMP_FREE_IDS_START 1
-
 
85
 
-
 
86
/** Free identifier numbers pool end.
-
 
87
 */
-
 
88
#define ICMP_FREE_IDS_END   MAX_UINT16
-
 
89
 
81
/** Computes the ICMP datagram checksum.
90
/** Computes the ICMP datagram checksum.
82
 *  @param header The ICMP datagram header. Input/output parameter.
91
 *  @param header The ICMP datagram header. Input/output parameter.
83
 *  @param length The total datagram length. Input parameter.
92
 *  @param length The total datagram length. Input parameter.
84
 *  @returns The computed checksum.
93
 *  @returns The computed checksum.
85
 */
94
 */
86
#define ICMP_CHECKSUM( header, length )     htons( ip_checksum(( uint8_t * ) ( header ), ( length )))
95
#define ICMP_CHECKSUM( header, length )     htons( ip_checksum(( uint8_t * ) ( header ), ( length )))
87
 
96
 
88
/** An echo request datagrams pattern.
97
/** An echo request datagrams pattern.
89
 */
98
 */
90
#define ICMP_ECHO_TEXT                  "Hello from HelenOS."
99
#define ICMP_ECHO_TEXT                  "Hello from HelenOS."
91
 
100
 
92
/** Computes an ICMP reply data key.
101
/** Computes an ICMP reply data key.
93
 *  @param id The message identifier. Input parameter.
102
 *  @param id The message identifier. Input parameter.
94
 *  @param sequence The message sequence number. Input parameter.
103
 *  @param sequence The message sequence number. Input parameter.
95
 *  @returns The computed ICMP reply data key.
104
 *  @returns The computed ICMP reply data key.
96
 */
105
 */
97
#define ICMP_GET_REPLY_KEY( id, sequence )  ((( id ) << 16 ) | ( sequence & 0xFFFF ))
106
#define ICMP_GET_REPLY_KEY( id, sequence )  ((( id ) << 16 ) | ( sequence & 0xFFFF ))
98
 
107
 
99
/** Type definition of the ICMP reply timeout.
108
/** Type definition of the ICMP reply timeout.
100
 *  @see icmp_reply_timeout
109
 *  @see icmp_reply_timeout
101
 */
110
 */
102
typedef struct icmp_reply_timeout   icmp_reply_timeout_t;
111
typedef struct icmp_reply_timeout   icmp_reply_timeout_t;
103
 
112
 
104
/** Type definition of the ICMP reply timeout pointer.
113
/** Type definition of the ICMP reply timeout pointer.
105
 *  @see icmp_reply_timeout
114
 *  @see icmp_reply_timeout
106
 */
115
 */
107
typedef icmp_reply_timeout_t *  icmp_reply_timeout_ref;
116
typedef icmp_reply_timeout_t *  icmp_reply_timeout_ref;
108
 
117
 
109
/** Processes the received ICMP packet.
118
/** Processes the received ICMP packet.
110
 *  Is used as an entry point from the underlying IP module.
119
 *  Is used as an entry point from the underlying IP module.
111
 *  Releases the packet on error.
120
 *  Releases the packet on error.
112
 *  @param device_id The device identifier. Ignored parameter.
121
 *  @param device_id The device identifier. Ignored parameter.
113
 *  @param packet The received packet. Input/output parameter.
122
 *  @param packet The received packet. Input/output parameter.
114
 *  @param receiver The target service. Ignored parameter.
123
 *  @param receiver The target service. Ignored parameter.
115
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
124
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
116
 *  @returns EOK on success.
125
 *  @returns EOK on success.
117
 *  @returns Other error codes as defined for the icmp_process_packet() function.
126
 *  @returns Other error codes as defined for the icmp_process_packet() function.
118
 */
127
 */
119
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
128
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error );
120
 
129
 
121
/** Processes the received ICMP packet.
130
/** Processes the received ICMP packet.
122
 *  Notifies the destination socket application.
131
 *  Notifies the destination socket application.
123
 *  @param packet The received packet. Input/output parameter.
132
 *  @param packet The received packet. Input/output parameter.
124
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
133
 *  @param error The packet error reporting service. Prefixes the received packet. Input parameter.
125
 *  @returns EOK on success.
134
 *  @returns EOK on success.
126
 *  @returns EINVAL if the packet is not valid.
135
 *  @returns EINVAL if the packet is not valid.
127
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
136
 *  @returns EINVAL if the stored packet address is not the an_addr_t.
128
 *  @returns EINVAL if the packet does not contain any data.
137
 *  @returns EINVAL if the packet does not contain any data.
129
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
138
 *  @returns NO_DATA if the packet content is shorter than the user datagram header.
130
 *  @returns ENOMEM if there is not enough memory left.
139
 *  @returns ENOMEM if there is not enough memory left.
131
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
140
 *  @returns EADDRNOTAVAIL if the destination socket does not exist.
132
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
141
 *  @returns Other error codes as defined for the ip_client_process_packet() function.
133
 */
142
 */
134
int icmp_process_packet( packet_t packet, services_t error );
143
int icmp_process_packet( packet_t packet, services_t error );
135
 
144
 
136
/** Processes the client messages.
145
/** Processes the client messages.
137
 *  Remembers the assigned identifier and sequence numbers.
146
 *  Remembers the assigned identifier and sequence numbers.
138
 *  Runs until the client module disconnects.
147
 *  Runs until the client module disconnects.
139
 *  @param callid The message identifier. Input parameter.
148
 *  @param callid The message identifier. Input parameter.
140
 *  @param call The message parameters. Input parameter.
149
 *  @param call The message parameters. Input parameter.
141
 *  @returns EOK.
150
 *  @returns EOK.
142
 *  @see icmp_interface.h
151
 *  @see icmp_interface.h
143
 *  @see icmp_api.h
152
 *  @see icmp_api.h
144
 */
153
 */
145
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
154
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call );
146
 
155
 
147
/** Processes the generic client messages.
156
/** Processes the generic client messages.
148
 *  @param call The message parameters. Input parameter.
157
 *  @param call The message parameters. Input parameter.
149
 *  @returns EOK on success.
158
 *  @returns EOK on success.
150
 *  @returns ENOTSUP if the message is not known.
159
 *  @returns ENOTSUP if the message is not known.
151
 *  @returns Other error codes as defined for the packet_translate() function.
160
 *  @returns Other error codes as defined for the packet_translate() function.
152
 *  @returns Other error codes as defined for the icmp_destination_unreachable_msg() function.
161
 *  @returns Other error codes as defined for the icmp_destination_unreachable_msg() function.
153
 *  @returns Other error codes as defined for the icmp_source_quench_msg() function.
162
 *  @returns Other error codes as defined for the icmp_source_quench_msg() function.
154
 *  @returns Other error codes as defined for the icmp_time_exceeded_msg() function.
163
 *  @returns Other error codes as defined for the icmp_time_exceeded_msg() function.
155
 *  @returns Other error codes as defined for the icmp_parameter_problem_msg() function.
164
 *  @returns Other error codes as defined for the icmp_parameter_problem_msg() function.
156
 *  @see icmp_interface.h
165
 *  @see icmp_interface.h
157
 */
166
 */
158
int icmp_process_message( ipc_call_t * call );
167
int icmp_process_message( ipc_call_t * call );
159
 
168
 
160
/** Releases the packet and returns the result.
169
/** Releases the packet and returns the result.
161
 *  @param packet The packet queue to be released. Input parameter.
170
 *  @param packet The packet queue to be released. Input parameter.
162
 *  @param result The result to be returned. Input parameter.
171
 *  @param result The result to be returned. Input parameter.
163
 *  @returns The result parameter.
172
 *  @returns The result parameter.
164
 */
173
 */
165
int icmp_release_and_return( packet_t packet, int result );
174
int icmp_release_and_return( packet_t packet, int result );
166
 
175
 
167
/** Requests an echo message.
176
/** Requests an echo message.
168
 *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
177
 *  Sends a packet with specified parameters to the target host and waits for the reply upto the given timeout.
169
 *  Blocks the caller until the reply or the timeout occurres.
178
 *  Blocks the caller until the reply or the timeout occurres.
170
 *  @param id The message identifier. Input parameter.
179
 *  @param id The message identifier. Input parameter.
171
 *  @param sequence The message sequence parameter. Input parameter.
180
 *  @param sequence The message sequence parameter. Input parameter.
172
 *  @param size The message data length in bytes. Input parameter.
181
 *  @param size The message data length in bytes. Input parameter.
173
 *  @param timeout The timeout in miliseconds. Input parameter.
182
 *  @param timeout The timeout in miliseconds. Input parameter.
174
 *  @param ttl The time to live. Input parameter.
183
 *  @param ttl The time to live. Input parameter.
175
 *  @param tos The type of service. Input parameter.
184
 *  @param tos The type of service. Input parameter.
176
 *  @param dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery. Input parameter.
185
 *  @param dont_fragment The value indicating whether the datagram must not be fragmented. Is used as a MTU discovery. Input parameter.
177
 *  @param addr The target host address. Input parameter.
186
 *  @param addr The target host address. Input parameter.
178
 *  @param addrlen The torget host address length. Input parameter.
187
 *  @param addrlen The torget host address length. Input parameter.
179
 *  @returns ICMP_ECHO on success.
188
 *  @returns ICMP_ECHO on success.
180
 *  @returns ETIMEOUT if the reply has not arrived before the timeout.
189
 *  @returns ETIMEOUT if the reply has not arrived before the timeout.
181
 *  @returns ICMP type of the received error notification.
190
 *  @returns ICMP type of the received error notification.
182
 *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
191
 *  @returns EINVAL if the addrlen parameter is less or equal to zero (<=0).
183
 *  @returns ENOMEM if there is not enough memory left.
192
 *  @returns ENOMEM if there is not enough memory left.
184
 *  @returns EPARTY if there was an internal error.
193
 *  @returns EPARTY if there was an internal error.
185
 */
194
 */
186
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen );
195
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen );
187
 
196
 
188
/** Prepares the ICMP error packet.
197
/** Prepares the ICMP error packet.
189
 *  Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
198
 *  Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
190
 *  Prefixes and returns the ICMP header.
199
 *  Prefixes and returns the ICMP header.
191
 *  @param packet The original packet. Input/output parameter.
200
 *  @param packet The original packet. Input/output parameter.
192
 *  @returns The prefixed ICMP header.
201
 *  @returns The prefixed ICMP header.
193
 *  @returns NULL on errors.
202
 *  @returns NULL on errors.
194
 */
203
 */
195
icmp_header_ref icmp_prepare_packet( packet_t packet );
204
icmp_header_ref icmp_prepare_packet( packet_t packet );
196
 
205
 
197
/** Sends the ICMP message.
206
/** Sends the ICMP message.
198
 *  Sets the message type and code and computes the checksum.
207
 *  Sets the message type and code and computes the checksum.
199
 *  Error messages are sent only if allowed in the configuration.
208
 *  Error messages are sent only if allowed in the configuration.
200
 *  Releases the packet on errors.
209
 *  Releases the packet on errors.
201
 *  @returns EOK on success.
210
 *  @returns EOK on success.
202
 *  @returns EPERM if the error message is not allowed.
211
 *  @returns EPERM if the error message is not allowed.
203
 */
212
 */
204
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error );
213
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error );
205
 
214
 
206
/** Tries to set the pending reply result as the received message type.
215
/** Tries to set the pending reply result as the received message type.
207
 *  If the reply data are still present, the reply timeouted and the parent fibril is awaken.
216
 *  If the reply data are still present, the reply timeouted and the parent fibril is awaken.
208
 *  The global lock is not released in this case to be reused by the parent fibril.
217
 *  The global lock is not released in this case to be reused by the parent fibril.
209
 *  Releases the packet.
218
 *  Releases the packet.
210
 *  @param packet The received reply message. Input parameter.
219
 *  @param packet The received reply message. Input parameter.
211
 *  @param header The ICMP message header. Input parameter.
220
 *  @param header The ICMP message header. Input parameter.
212
 *  @param type The received reply message type. Input parameter.
221
 *  @param type The received reply message type. Input parameter.
213
 *  @param code The received reply message code. Input parameter.
222
 *  @param code The received reply message code. Input parameter.
214
 *  @returns EOK.
223
 *  @returns EOK.
215
 */
224
 */
216
int icmp_process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code );
225
int icmp_process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code );
217
 
226
 
218
/** Tries to set the pending reply result as timeouted.
227
/** Tries to set the pending reply result as timeouted.
219
 *  Sleeps the timeout period of time and then tries to obtain and set the pending reply result as timeouted and signals the reply result.
228
 *  Sleeps the timeout period of time and then tries to obtain and set the pending reply result as timeouted and signals the reply result.
220
 *  If the reply data are still present, the reply timeouted and the parent fibril is awaken.
229
 *  If the reply data are still present, the reply timeouted and the parent fibril is awaken.
221
 *  The global lock is not released in this case to be reused by the parent fibril.
230
 *  The global lock is not released in this case to be reused by the parent fibril.
222
 *  Should run in a searate fibril.
231
 *  Should run in a searate fibril.
223
 *  @param data The icmp_reply_timeout structure. Input parameter.
232
 *  @param data The icmp_reply_timeout structure. Input parameter.
224
 *  @returns EOK on success.
233
 *  @returns EOK on success.
225
 *  @returns EINVAL if the data parameter is NULL.
234
 *  @returns EINVAL if the data parameter is NULL.
226
 */
235
 */
227
int icmp_timeout_for_reply( void * data );
236
int icmp_timeout_for_reply( void * data );
228
 
237
 
-
 
238
/** Assigns a new identifier for the connection.
-
 
239
 *  Fills the echo data parameter with the assigned values.
-
 
240
 *  @param echo_data The echo data to be bound. Input/output parameter.
-
 
241
 *  @returns Index of the inserted echo data.
-
 
242
 *  @returns EBADMEM if the echo_data parameter is NULL.
-
 
243
 *  @returns ENOTCONN if no free identifier have been found.
-
 
244
 */
-
 
245
int icmp_bind_free_id( icmp_echo_ref echo_data );
-
 
246
 
229
/** ICMP reply timeout data.
247
/** ICMP reply timeout data.
230
 *  Used as a timeouting fibril argument.
248
 *  Used as a timeouting fibril argument.
231
 *  @see icmp_timeout_for_reply()
249
 *  @see icmp_timeout_for_reply()
232
 */
250
 */
233
struct icmp_reply_timeout{
251
struct icmp_reply_timeout{
234
    /** Reply data key.
252
    /** Reply data key.
235
     */
253
     */
236
    int         reply_key;
254
    int         reply_key;
237
    /** Timeout in microseconds.
255
    /** Timeout in microseconds.
238
     */
256
     */
239
    suseconds_t timeout;
257
    suseconds_t timeout;
240
};
258
};
241
 
259
 
242
/** ICMP global data.
260
/** ICMP global data.
243
 */
261
 */
244
icmp_globals_t  icmp_globals;
262
icmp_globals_t  icmp_globals;
245
 
263
 
246
INT_MAP_IMPLEMENT( icmp_replies, icmp_reply_t );
264
INT_MAP_IMPLEMENT( icmp_replies, icmp_reply_t );
247
 
265
 
248
GENERIC_FIELD_IMPLEMENT( icmp_echo_data, icmp_echo_t );
266
INT_MAP_IMPLEMENT( icmp_echo_data, icmp_echo_t );
249
 
267
 
250
int icmp_echo_msg( int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
268
int icmp_echo_msg( int icmp_phone, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
251
    icmp_echo_ref   echo_data;
269
    icmp_echo_ref   echo_data;
252
    int             res;
270
    int             res;
253
 
271
 
254
    fibril_rwlock_write_lock( & icmp_globals.lock );
272
    fibril_rwlock_write_lock( & icmp_globals.lock );
255
    // use the phone as the echo data index
273
    // use the phone as the echo data index
256
    echo_data = icmp_echo_data_get_index( & icmp_globals.echo_data, icmp_phone );
274
    echo_data = icmp_echo_data_find( & icmp_globals.echo_data, icmp_phone );
257
    if( ! echo_data ){
275
    if( ! echo_data ){
258
        res = ENOENT;
276
        res = ENOENT;
259
    }else{
277
    }else{
260
        res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen );
278
        res = icmp_echo( echo_data->id, echo_data->sequence, size, timeout, ttl, tos, dont_fragment, addr, addrlen );
-
 
279
        if( echo_data->sequence < MAX_UINT16 ){
261
        ++ echo_data->sequence;
280
            ++ echo_data->sequence;
-
 
281
        }else{
-
 
282
            echo_data->sequence = 0;
-
 
283
        }
262
    }
284
    }
263
    fibril_rwlock_write_unlock( & icmp_globals.lock );
285
    fibril_rwlock_write_unlock( & icmp_globals.lock );
264
    return res;
286
    return res;
265
}
287
}
266
 
288
 
267
int icmp_timeout_for_reply( void * data ){
289
int icmp_timeout_for_reply( void * data ){
268
    icmp_reply_ref          reply;
290
    icmp_reply_ref          reply;
269
    icmp_reply_timeout_ref  timeout = data;
291
    icmp_reply_timeout_ref  timeout = data;
270
 
292
 
271
    if( ! timeout ){
293
    if( ! timeout ){
272
        return EINVAL;
294
        return EINVAL;
273
    }
295
    }
274
    // sleep the given timeout
296
    // sleep the given timeout
275
    async_usleep( timeout->timeout );
297
    async_usleep( timeout->timeout );
276
    // lock the globals
298
    // lock the globals
277
    fibril_rwlock_write_lock( & icmp_globals.lock );
299
    fibril_rwlock_write_lock( & icmp_globals.lock );
278
    // find the pending reply
300
    // find the pending reply
279
    reply = icmp_replies_find( & icmp_globals.replies, timeout->reply_key );
301
    reply = icmp_replies_find( & icmp_globals.replies, timeout->reply_key );
280
    if( reply ){
302
    if( reply ){
281
        // set the timeout result
303
        // set the timeout result
282
        reply->result = ETIMEOUT;
304
        reply->result = ETIMEOUT;
283
        // notify the main fibril
305
        // notify the main fibril
284
        fibril_condvar_signal( & reply->condvar );
306
        fibril_condvar_signal( & reply->condvar );
285
    }else{
307
    }else{
286
        // unlock only if no reply
308
        // unlock only if no reply
287
        fibril_rwlock_write_unlock( & icmp_globals.lock );
309
        fibril_rwlock_write_unlock( & icmp_globals.lock );
288
    }
310
    }
289
    // release the timeout structure
311
    // release the timeout structure
290
    free( timeout );
312
    free( timeout );
291
    return EOK;
313
    return EOK;
292
}
314
}
293
 
315
 
294
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
316
int icmp_echo( icmp_param_t id, icmp_param_t sequence, size_t size, mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, const struct sockaddr * addr, socklen_t addrlen ){
295
    ERROR_DECLARE;
317
    ERROR_DECLARE;
296
 
318
 
297
    icmp_header_ref header;
319
    icmp_header_ref header;
298
    packet_t        packet;
320
    packet_t        packet;
299
    size_t          length;
321
    size_t          length;
300
    uint8_t *       data;
322
    uint8_t *       data;
301
    icmp_reply_ref          reply;
323
    icmp_reply_ref          reply;
302
    icmp_reply_timeout_ref  reply_timeout;
324
    icmp_reply_timeout_ref  reply_timeout;
303
    int             result;
325
    int             result;
304
    int             index;
326
    int             index;
305
    fid_t           fibril;
327
    fid_t           fibril;
306
 
328
 
307
    if( addrlen <= 0 ){
329
    if( addrlen <= 0 ){
308
        return EINVAL;
330
        return EINVAL;
309
    }
331
    }
310
    length = ( size_t ) addrlen;
332
    length = ( size_t ) addrlen;
311
    // TODO do not ask all the time
333
    // TODO do not ask all the time
312
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
334
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
313
    packet = packet_get_4( icmp_globals.net_phone, size, icmp_globals.addr_len, sizeof( icmp_header_t ) + icmp_globals.prefix, icmp_globals.suffix );
335
    packet = packet_get_4( icmp_globals.net_phone, size, icmp_globals.addr_len, sizeof( icmp_header_t ) + icmp_globals.prefix, icmp_globals.suffix );
314
    if( ! packet ) return ENOMEM;
336
    if( ! packet ) return ENOMEM;
315
 
337
 
316
    // prepare the requesting packet
338
    // prepare the requesting packet
317
    // set the destination address
339
    // set the destination address
318
    if( ERROR_OCCURRED( packet_set_addr( packet, NULL, ( const uint8_t * ) addr, length ))){
340
    if( ERROR_OCCURRED( packet_set_addr( packet, NULL, ( const uint8_t * ) addr, length ))){
319
        return icmp_release_and_return( packet, ERROR_CODE );
341
        return icmp_release_and_return( packet, ERROR_CODE );
320
    }
342
    }
321
    // allocate space in the packet
343
    // allocate space in the packet
322
    data = ( uint8_t * ) packet_suffix( packet, size );
344
    data = ( uint8_t * ) packet_suffix( packet, size );
323
    if( ! data ){
345
    if( ! data ){
324
        return icmp_release_and_return( packet, ENOMEM );
346
        return icmp_release_and_return( packet, ENOMEM );
325
    }
347
    }
326
    // fill the data
348
    // fill the data
327
    length = 0;
349
    length = 0;
328
    while( size > length + sizeof( ICMP_ECHO_TEXT )){
350
    while( size > length + sizeof( ICMP_ECHO_TEXT )){
329
        memcpy( data + length, ICMP_ECHO_TEXT, sizeof( ICMP_ECHO_TEXT ));
351
        memcpy( data + length, ICMP_ECHO_TEXT, sizeof( ICMP_ECHO_TEXT ));
330
        length += sizeof( ICMP_ECHO_TEXT );
352
        length += sizeof( ICMP_ECHO_TEXT );
331
    }
353
    }
332
    memcpy( data + length, ICMP_ECHO_TEXT, size - length );
354
    memcpy( data + length, ICMP_ECHO_TEXT, size - length );
333
    // prefix the header
355
    // prefix the header
334
    header = PACKET_PREFIX( packet, icmp_header_t );
356
    header = PACKET_PREFIX( packet, icmp_header_t );
335
    if( ! header ){
357
    if( ! header ){
336
        return icmp_release_and_return( packet, ENOMEM );
358
        return icmp_release_and_return( packet, ENOMEM );
337
    }
359
    }
338
    bzero( header, sizeof( * header ));
360
    bzero( header, sizeof( * header ));
339
    header->un.echo.id = id;
361
    header->un.echo.id = id;
340
    header->un.echo.sequence = sequence;
362
    header->un.echo.sequence = sequence;
341
 
363
 
342
    // prepare the reply and the reply timeout structures
364
    // prepare the reply and the reply timeout structures
343
    reply_timeout = malloc( sizeof( * reply_timeout ));
365
    reply_timeout = malloc( sizeof( * reply_timeout ));
344
    if( ! reply_timeout ){
366
    if( ! reply_timeout ){
345
        return icmp_release_and_return( packet, ENOMEM );
367
        return icmp_release_and_return( packet, ENOMEM );
346
    }
368
    }
347
    reply = malloc( sizeof( * reply ));
369
    reply = malloc( sizeof( * reply ));
348
    if( ! reply ){
370
    if( ! reply ){
349
        free( reply_timeout );
371
        free( reply_timeout );
350
        return icmp_release_and_return( packet, ENOMEM );
372
        return icmp_release_and_return( packet, ENOMEM );
351
    }
373
    }
352
    reply_timeout->reply_key = ICMP_GET_REPLY_KEY( header->un.echo.id, header->un.echo.sequence );
374
    reply_timeout->reply_key = ICMP_GET_REPLY_KEY( header->un.echo.id, header->un.echo.sequence );
353
    // timeout in microseconds
375
    // timeout in microseconds
354
    reply_timeout->timeout = timeout * 1000;
376
    reply_timeout->timeout = timeout * 1000;
355
    fibril_mutex_initialize( & reply->mutex );
377
    fibril_mutex_initialize( & reply->mutex );
356
    fibril_mutex_lock( & reply->mutex );
378
    fibril_mutex_lock( & reply->mutex );
357
    fibril_condvar_initialize( & reply->condvar );
379
    fibril_condvar_initialize( & reply->condvar );
358
    index = icmp_replies_add( & icmp_globals.replies, reply_timeout->reply_key, reply );
380
    index = icmp_replies_add( & icmp_globals.replies, reply_timeout->reply_key, reply );
359
    if( index < 0 ){
381
    if( index < 0 ){
360
        free( reply );
382
        free( reply );
361
        free( reply_timeout );
383
        free( reply_timeout );
362
        return icmp_release_and_return( packet, index );
384
        return icmp_release_and_return( packet, index );
363
    }
385
    }
364
    // start the timeouting thread
386
    // start the timeouting thread
365
    fibril = fibril_create( icmp_timeout_for_reply, reply_timeout );
387
    fibril = fibril_create( icmp_timeout_for_reply, reply_timeout );
366
    if( ! fibril ){
388
    if( ! fibril ){
367
        return EPARTY;
389
        return EPARTY;
368
    }
390
    }
369
    fibril_add_ready( fibril );
391
    fibril_add_ready( fibril );
370
 
392
 
371
    // unlock the globals and wait for a reply
393
    // unlock the globals and wait for a reply
372
    fibril_rwlock_write_unlock( & icmp_globals.lock );
394
    fibril_rwlock_write_unlock( & icmp_globals.lock );
373
 
395
 
374
    // send the request
396
    // send the request
375
    icmp_send_packet( ICMP_ECHO, 0, packet, header, 0 );
397
    icmp_send_packet( ICMP_ECHO, 0, packet, header, 0 );
376
 
398
 
377
    // wait for a reply
399
    // wait for a reply
378
    fibril_condvar_wait( & reply->condvar, & reply->mutex );
400
    fibril_condvar_wait( & reply->condvar, & reply->mutex );
379
    // read the result
401
    // read the result
380
    result = reply->result;
402
    result = reply->result;
381
 
403
 
382
    // destroy the reply structure
404
    // destroy the reply structure
383
    fibril_mutex_unlock( & reply->mutex );
405
    fibril_mutex_unlock( & reply->mutex );
384
    icmp_replies_exclude_index( & icmp_globals.replies, index );
406
    icmp_replies_exclude_index( & icmp_globals.replies, index );
385
    return result;
407
    return result;
386
}
408
}
387
 
409
 
388
int icmp_destination_unreachable_msg( int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet ){
410
int icmp_destination_unreachable_msg( int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet ){
389
    icmp_header_ref header;
411
    icmp_header_ref header;
390
 
412
 
391
    header = icmp_prepare_packet( packet );
413
    header = icmp_prepare_packet( packet );
392
    if( ! header ){
414
    if( ! header ){
393
        return icmp_release_and_return( packet, ENOMEM );
415
        return icmp_release_and_return( packet, ENOMEM );
394
    }
416
    }
395
    if( mtu ){
417
    if( mtu ){
396
        header->un.frag.mtu = mtu;
418
        header->un.frag.mtu = mtu;
397
    }
419
    }
398
    return icmp_send_packet( ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP );
420
    return icmp_send_packet( ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP );
399
}
421
}
400
 
422
 
401
int icmp_source_quench_msg( int icmp_phone, packet_t packet ){
423
int icmp_source_quench_msg( int icmp_phone, packet_t packet ){
402
    icmp_header_ref header;
424
    icmp_header_ref header;
403
 
425
 
404
    header = icmp_prepare_packet( packet );
426
    header = icmp_prepare_packet( packet );
405
    if( ! header ){
427
    if( ! header ){
406
        return icmp_release_and_return( packet, ENOMEM );
428
        return icmp_release_and_return( packet, ENOMEM );
407
    }
429
    }
408
    return icmp_send_packet( ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP );
430
    return icmp_send_packet( ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP );
409
}
431
}
410
 
432
 
411
int icmp_time_exceeded_msg( int icmp_phone, icmp_code_t code, packet_t packet ){
433
int icmp_time_exceeded_msg( int icmp_phone, icmp_code_t code, packet_t packet ){
412
    icmp_header_ref header;
434
    icmp_header_ref header;
413
 
435
 
414
    header = icmp_prepare_packet( packet );
436
    header = icmp_prepare_packet( packet );
415
    if( ! header ){
437
    if( ! header ){
416
        return icmp_release_and_return( packet, ENOMEM );
438
        return icmp_release_and_return( packet, ENOMEM );
417
    }
439
    }
418
    return icmp_send_packet( ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP );
440
    return icmp_send_packet( ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP );
419
}
441
}
420
 
442
 
421
int icmp_parameter_problem_msg( int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet ){
443
int icmp_parameter_problem_msg( int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet ){
422
    icmp_header_ref header;
444
    icmp_header_ref header;
423
 
445
 
424
    header = icmp_prepare_packet( packet );
446
    header = icmp_prepare_packet( packet );
425
    if( ! header ){
447
    if( ! header ){
426
        return icmp_release_and_return( packet, ENOMEM );
448
        return icmp_release_and_return( packet, ENOMEM );
427
    }
449
    }
428
    header->un.param.pointer = pointer;
450
    header->un.param.pointer = pointer;
429
    return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP );
451
    return icmp_send_packet( ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP );
430
}
452
}
431
 
453
 
432
icmp_header_ref icmp_prepare_packet( packet_t packet ){
454
icmp_header_ref icmp_prepare_packet( packet_t packet ){
433
    icmp_header_ref header;
455
    icmp_header_ref header;
434
    int             header_length;
456
    size_t          header_length;
435
    size_t          total_length;
457
    size_t          total_length;
436
 
458
 
437
    total_length = packet_get_data_length( packet );
459
    total_length = packet_get_data_length( packet );
438
    if( total_length <= 0 ) return NULL;
460
    if( total_length <= 0 ) return NULL;
439
    header_length = ip_client_header_length( packet );
461
    header_length = ip_client_header_length( packet );
440
    if( header_length <= 0 ) return NULL;
462
    if( header_length <= 0 ) return NULL;
441
    // truncate if longer than 64 bits (without the IP header)
463
    // truncate if longer than 64 bits (without the IP header)
442
    if(( total_length - header_length > ICMP_KEEP_LENGTH )
464
    if(( total_length > header_length + ICMP_KEEP_LENGTH )
443
    && ( packet_trim( packet, 0, total_length - header_length - ICMP_KEEP_LENGTH ) != EOK )){
465
    && ( packet_trim( packet, 0, total_length - header_length - ICMP_KEEP_LENGTH ) != EOK )){
444
        return NULL;
466
        return NULL;
445
    }
467
    }
446
    header = PACKET_PREFIX( packet, icmp_header_t );
468
    header = PACKET_PREFIX( packet, icmp_header_t );
447
    if( ! header ) return NULL;
469
    if( ! header ) return NULL;
448
    bzero( header, sizeof( * header ));
470
    bzero( header, sizeof( * header ));
449
    return header;
471
    return header;
450
}
472
}
451
 
473
 
452
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error ){
474
int icmp_send_packet( icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error ){
453
    ERROR_DECLARE;
475
    ERROR_DECLARE;
454
 
476
 
455
    // do not send an error if disabled
477
    // do not send an error if disabled
456
    if( error && ( ! icmp_globals.error_reporting )){
478
    if( error && ( ! icmp_globals.error_reporting )){
457
        return icmp_release_and_return( packet, EPERM );
479
        return icmp_release_and_return( packet, EPERM );
458
    }
480
    }
459
    header->type = type;
481
    header->type = type;
460
    header->code = code;
482
    header->code = code;
461
    header->checksum = 0;
483
    header->checksum = 0;
462
    header->checksum = ICMP_CHECKSUM( header, packet_get_data_length( packet ));
484
    header->checksum = ICMP_CHECKSUM( header, packet_get_data_length( packet ));
463
    if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_ICMP, 0, 0, 0, 0 ))){
485
    if( ERROR_OCCURRED( ip_client_prepare_packet( packet, IPPROTO_ICMP, 0, 0, 0, 0 ))){
464
        return icmp_release_and_return( packet, ERROR_CODE );
486
        return icmp_release_and_return( packet, ERROR_CODE );
465
    }
487
    }
466
    return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error );
488
    return ip_send_msg( icmp_globals.ip_phone, -1, packet, SERVICE_ICMP, error );
467
}
489
}
468
 
490
 
469
int icmp_connect_module( services_t service ){
491
int icmp_connect_module( services_t service ){
470
    icmp_echo_ref   echo_data;
492
    icmp_echo_ref   echo_data;
-
 
493
    icmp_param_t    id;
471
    int             index;
494
    int             index;
472
 
495
 
473
    echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data ));
496
    echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data ));
474
    if( ! echo_data ) return ENOMEM;
497
    if( ! echo_data ) return ENOMEM;
475
    // assign a new identifier
498
    // assign a new identifier
476
    fibril_rwlock_write_lock( & icmp_globals.lock );
499
    fibril_rwlock_write_lock( & icmp_globals.lock );
477
    ++ icmp_globals.last_used_id;
-
 
478
    echo_data->id = icmp_globals.last_used_id;
-
 
479
    echo_data->sequence = 0;
-
 
480
    // remember the assigned echo data
-
 
481
    index = icmp_echo_data_add( & icmp_globals.echo_data, echo_data );
500
    index = icmp_bind_free_id( echo_data );
482
    if( index < 0 ){
501
    if( index < 0 ){
483
        free( echo_data );
502
        free( echo_data );
-
 
503
    }else{
-
 
504
        id = echo_data->id;
484
    }
505
    }
485
    fibril_rwlock_write_unlock( & icmp_globals.lock );
506
    fibril_rwlock_write_unlock( & icmp_globals.lock );
486
    // return the echo data index as the ICMP phone
507
    // return the echo data identifier as the ICMP phone
487
    return index;
508
    return id;
488
}
509
}
489
 
510
 
490
int icmp_initialize( async_client_conn_t client_connection ){
511
int icmp_initialize( async_client_conn_t client_connection ){
491
    ERROR_DECLARE;
512
    ERROR_DECLARE;
492
 
513
 
493
    measured_string_t   names[] = {{ "ICMP_ERROR_REPORTING", 20 }, { "ICMP_ECHO_REPLYING", 18 }};
514
    measured_string_t   names[] = {{ "ICMP_ERROR_REPORTING", 20 }, { "ICMP_ECHO_REPLYING", 18 }};
494
    measured_string_ref configuration;
515
    measured_string_ref configuration;
495
    size_t              count = sizeof( names ) / sizeof( measured_string_t );
516
    size_t              count = sizeof( names ) / sizeof( measured_string_t );
496
    char *              data;
517
    char *              data;
497
 
518
 
498
    fibril_rwlock_initialize( & icmp_globals.lock );
519
    fibril_rwlock_initialize( & icmp_globals.lock );
499
    fibril_rwlock_write_lock( & icmp_globals.lock );
520
    fibril_rwlock_write_lock( & icmp_globals.lock );
500
    icmp_replies_initialize( & icmp_globals.replies );
521
    icmp_replies_initialize( & icmp_globals.replies );
501
    icmp_echo_data_initialize( & icmp_globals.echo_data );
522
    icmp_echo_data_initialize( & icmp_globals.echo_data );
502
    icmp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg );
523
    icmp_globals.ip_phone = ip_bind_service( SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection, icmp_received_msg );
503
    if( icmp_globals.ip_phone < 0 ){
524
    if( icmp_globals.ip_phone < 0 ){
504
        return icmp_globals.ip_phone;
525
        return icmp_globals.ip_phone;
505
    }
526
    }
506
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
527
    ERROR_PROPAGATE( ip_packet_size_req( icmp_globals.ip_phone, -1, & icmp_globals.addr_len, & icmp_globals.prefix, & icmp_globals.content, & icmp_globals.suffix ));
507
    icmp_globals.prefix += sizeof( icmp_header_t );
528
    icmp_globals.prefix += sizeof( icmp_header_t );
508
    icmp_globals.content -= sizeof( icmp_header_t );
529
    icmp_globals.content -= sizeof( icmp_header_t );
509
    configuration = & names[ 0 ];
530
    configuration = & names[ 0 ];
510
    // get configuration
531
    // get configuration
511
    ERROR_PROPAGATE( net_get_conf_req( icmp_globals.net_phone, & configuration, count, & data ));
532
    ERROR_PROPAGATE( net_get_conf_req( icmp_globals.net_phone, & configuration, count, & data ));
512
    if( configuration ){
533
    if( configuration ){
513
        icmp_globals.error_reporting = configuration[ 0 ].value && ( configuration[ 0 ].value[ 0 ] == 'y' );
534
        icmp_globals.error_reporting = configuration[ 0 ].value && ( configuration[ 0 ].value[ 0 ] == 'y' );
514
        icmp_globals.echo_replying = configuration[ 1 ].value && ( configuration[ 1 ].value[ 0 ] == 'y' );
535
        icmp_globals.echo_replying = configuration[ 1 ].value && ( configuration[ 1 ].value[ 0 ] == 'y' );
515
        net_free_settings( configuration, data );
536
        net_free_settings( configuration, data );
516
    }
537
    }
517
    fibril_rwlock_write_unlock( & icmp_globals.lock );
538
    fibril_rwlock_write_unlock( & icmp_globals.lock );
518
    return EOK;
539
    return EOK;
519
}
540
}
520
 
541
 
521
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
542
int icmp_received_msg( device_id_t device_id, packet_t packet, services_t receiver, services_t error ){
522
    ERROR_DECLARE;
543
    ERROR_DECLARE;
523
 
544
 
524
    if( ERROR_OCCURRED( icmp_process_packet( packet, error ))){
545
    if( ERROR_OCCURRED( icmp_process_packet( packet, error ))){
525
        return icmp_release_and_return( packet, ERROR_CODE );
546
        return icmp_release_and_return( packet, ERROR_CODE );
526
    }
547
    }
527
 
548
 
528
    return EOK;
549
    return EOK;
529
}
550
}
530
 
551
 
531
int icmp_process_packet( packet_t packet, services_t error ){
552
int icmp_process_packet( packet_t packet, services_t error ){
532
    ERROR_DECLARE;
553
    ERROR_DECLARE;
533
 
554
 
534
    size_t          length;
555
    size_t          length;
535
    uint8_t *       src;
556
    uint8_t *       src;
536
    int             addrlen;
557
    int             addrlen;
537
    int             result;
558
    int             result;
538
    void *          data;
559
    void *          data;
539
    icmp_header_ref header;
560
    icmp_header_ref header;
540
    icmp_type_t     type;
561
    icmp_type_t     type;
541
    icmp_code_t     code;
562
    icmp_code_t     code;
542
 
563
 
543
    if( error ){
564
    if( error ){
544
        switch( error ){
565
        switch( error ){
545
            case SERVICE_ICMP:
566
            case SERVICE_ICMP:
546
                // process error
567
                // process error
547
                // TODO remove debug dump
-
 
548
                // length = icmp_client_header_length( packet );
-
 
549
                result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
568
                result = icmp_client_process_packet( packet, & type, & code, NULL, NULL );
550
                if( result < 0 ) return result;
569
                if( result < 0 ) return result;
551
                length = ( size_t ) result;
570
                length = ( size_t ) result;
-
 
571
                // TODO remove debug dump
552
                printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) );
572
                printf( "ICMP error %d (%d) in packet %d\n", type, code, packet_get_id( packet ) );
-
 
573
                // remove the error header
553
                ERROR_PROPAGATE( packet_trim( packet, length, 0 ));
574
                ERROR_PROPAGATE( packet_trim( packet, length, 0 ));
554
                break;
575
                break;
555
            default:
576
            default:
556
                return ENOTSUP;
577
                return ENOTSUP;
557
        }
578
        }
558
    }
579
    }
559
    // get rid of the ip header
580
    // get rid of the ip header
560
    result = ip_client_process_packet( packet, NULL, NULL, NULL, NULL, NULL );
581
    length = ip_client_header_length( packet );
561
    if( result < 0 ) return result;
-
 
562
    ERROR_PROPAGATE( packet_trim( packet, ( size_t ) result, 0 ));
582
    ERROR_PROPAGATE( packet_trim( packet, length, 0 ));
563
 
583
 
564
    length = packet_get_data_length( packet );
584
    length = packet_get_data_length( packet );
565
    if( length <= 0 ) return EINVAL;
585
    if( length <= 0 ) return EINVAL;
566
    if( length < sizeof( icmp_header_t )) return EINVAL;
586
    if( length < sizeof( icmp_header_t )) return EINVAL;
567
    data = packet_get_data( packet );
587
    data = packet_get_data( packet );
568
    if( ! data ) return EINVAL;
588
    if( ! data ) return EINVAL;
569
    // get icmp header
589
    // get icmp header
570
    header = ( icmp_header_ref ) data;
590
    header = ( icmp_header_ref ) data;
571
    // checksum
591
    // checksum
572
/*  if(( header->checksum ) && ( ICMP_CHECKSUM( header, length ))){
-
 
573
        // set the original message type on error notification
-
 
574
        // type swap observed in Qemu
-
 
575
        if( error ){
-
 
576
            switch( header->type ){
-
 
577
                case ICMP_ECHOREPLY:
-
 
578
                    header->type = ICMP_ECHO;
-
 
579
                    break;
-
 
580
            }
-
 
581
        }
-
 
582
        if( ICMP_CHECKSUM( header, length )){
-
 
583
            return EINVAL;
-
 
584
        }
-
 
585
    }
-
 
586
*/  if( header->checksum ){
592
    if( header->checksum ){
587
        while( ICMP_CHECKSUM( header, length )){
593
        while( ICMP_CHECKSUM( header, length )){
588
            // set the original message type on error notification
594
            // set the original message type on error notification
589
            // type swap observed in Qemu
595
            // type swap observed in Qemu
590
            if( error ){
596
            if( error ){
591
                switch( header->type ){
597
                switch( header->type ){
592
                    case ICMP_ECHOREPLY:
598
                    case ICMP_ECHOREPLY:
593
                        header->type = ICMP_ECHO;
599
                        header->type = ICMP_ECHO;
594
                        continue;
600
                        continue;
595
                }
601
                }
596
            }
602
            }
597
            return EINVAL;
603
            return EINVAL;
598
        }
604
        }
599
    }
605
    }
600
    switch( header->type ){
606
    switch( header->type ){
601
        case ICMP_ECHOREPLY:
607
        case ICMP_ECHOREPLY:
602
            if( error ){
608
            if( error ){
603
                return icmp_process_echo_reply( packet, header, type, code );
609
                return icmp_process_echo_reply( packet, header, type, code );
604
            }else{
610
            }else{
605
                return icmp_process_echo_reply( packet, header, ICMP_ECHO, 0 );
611
                return icmp_process_echo_reply( packet, header, ICMP_ECHO, 0 );
606
            }
612
            }
607
        case ICMP_ECHO:
613
        case ICMP_ECHO:
608
            if( error ){
614
            if( error ){
609
                return icmp_process_echo_reply( packet, header, type, code );
615
                return icmp_process_echo_reply( packet, header, type, code );
610
            // do not send a reply if disabled
616
            // do not send a reply if disabled
611
            }else if( icmp_globals.echo_replying ){
617
            }else if( icmp_globals.echo_replying ){
612
                addrlen = packet_get_addr( packet, & src, NULL );
618
                addrlen = packet_get_addr( packet, & src, NULL );
613
                if(( addrlen > 0 )
619
                if(( addrlen > 0 )
614
                // set both addresses to the source one (avoids the source address deletion before setting the destination one)
620
                // set both addresses to the source one (avoids the source address deletion before setting the destination one)
615
                && ( packet_set_addr( packet, src, src, ( size_t ) addrlen ) == EOK )){
621
                && ( packet_set_addr( packet, src, src, ( size_t ) addrlen ) == EOK )){
616
                    // send the reply
622
                    // send the reply
617
                    icmp_send_packet( ICMP_ECHOREPLY, 0, packet, header, 0 );
623
                    icmp_send_packet( ICMP_ECHOREPLY, 0, packet, header, 0 );
618
                    return EOK;
624
                    return EOK;
619
                }else{
625
                }else{
620
                    return EINVAL;
626
                    return EINVAL;
621
                }
627
                }
622
            }else{
628
            }else{
623
                return EPERM;
629
                return EPERM;
624
            }
630
            }
625
        case ICMP_DEST_UNREACH:
631
        case ICMP_DEST_UNREACH:
626
        case ICMP_SOURCE_QUENCH:
632
        case ICMP_SOURCE_QUENCH:
627
        case ICMP_REDIRECT:
633
        case ICMP_REDIRECT:
628
        case ICMP_ALTERNATE_ADDR:
634
        case ICMP_ALTERNATE_ADDR:
629
        case ICMP_ROUTER_ADV:
635
        case ICMP_ROUTER_ADV:
630
        case ICMP_ROUTER_SOL:
636
        case ICMP_ROUTER_SOL:
631
        case ICMP_TIME_EXCEEDED:
637
        case ICMP_TIME_EXCEEDED:
632
        case ICMP_PARAMETERPROB:
638
        case ICMP_PARAMETERPROB:
633
        case ICMP_CONVERSION_ERROR:
639
        case ICMP_CONVERSION_ERROR:
634
        case ICMP_REDIRECT_MOBILE:
640
        case ICMP_REDIRECT_MOBILE:
635
        case ICMP_SKIP:
641
        case ICMP_SKIP:
636
        case ICMP_PHOTURIS:
642
        case ICMP_PHOTURIS:
637
            ip_received_error_msg( icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP );
643
            ip_received_error_msg( icmp_globals.ip_phone, -1, packet, SERVICE_IP, SERVICE_ICMP );
638
            return EOK;
644
            return EOK;
639
        default:
645
        default:
640
            return ENOTSUP;
646
            return ENOTSUP;
641
    }
647
    }
642
}
648
}
643
 
649
 
644
int icmp_process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code ){
650
int icmp_process_echo_reply( packet_t packet, icmp_header_ref header, icmp_type_t type, icmp_code_t code ){
645
    int             reply_key;
651
    int             reply_key;
646
    icmp_reply_ref  reply;
652
    icmp_reply_ref  reply;
647
 
653
 
648
    // compute the reply key
654
    // compute the reply key
649
    reply_key = ICMP_GET_REPLY_KEY( header->un.echo.id, header->un.echo.sequence );
655
    reply_key = ICMP_GET_REPLY_KEY( header->un.echo.id, header->un.echo.sequence );
650
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
656
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
651
    // lock the globals
657
    // lock the globals
652
    fibril_rwlock_write_lock( & icmp_globals.lock );
658
    fibril_rwlock_write_lock( & icmp_globals.lock );
653
    // find the pending reply
659
    // find the pending reply
654
    reply = icmp_replies_find( & icmp_globals.replies, reply_key );
660
    reply = icmp_replies_find( & icmp_globals.replies, reply_key );
655
    if( reply ){
661
    if( reply ){
656
        // set the result
662
        // set the result
657
        reply->result = type;
663
        reply->result = type;
658
        // notify the main fibril
664
        // notify the main fibril
659
        fibril_condvar_signal( & reply->condvar );
665
        fibril_condvar_signal( & reply->condvar );
660
    }else{
666
    }else{
661
        // unlock only if no reply
667
        // unlock only if no reply
662
        fibril_rwlock_write_unlock( & icmp_globals.lock );
668
        fibril_rwlock_write_unlock( & icmp_globals.lock );
663
    }
669
    }
664
    return EOK;
670
    return EOK;
665
}
671
}
666
 
672
 
667
int icmp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
673
int icmp_message( ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count ){
668
    ERROR_DECLARE;
674
    ERROR_DECLARE;
669
 
675
 
670
    packet_t            packet;
676
    packet_t            packet;
671
 
677
 
672
    * answer_count = 0;
678
    * answer_count = 0;
673
    switch( IPC_GET_METHOD( * call )){
679
    switch( IPC_GET_METHOD( * call )){
674
        case NET_TL_RECEIVED:
680
        case NET_TL_RECEIVED:
675
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
681
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
676
                ERROR_CODE = icmp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_ICMP, IPC_GET_ERROR( call ));
682
                ERROR_CODE = icmp_received_msg( IPC_GET_DEVICE( call ), packet, SERVICE_ICMP, IPC_GET_ERROR( call ));
677
            }
683
            }
678
            return ERROR_CODE;
684
            return ERROR_CODE;
679
        case NET_ICMP_INIT:
685
        case NET_ICMP_INIT:
680
            return icmp_process_client_messages( callid, * call );
686
            return icmp_process_client_messages( callid, * call );
681
        default:
687
        default:
682
            return icmp_process_message( call );
688
            return icmp_process_message( call );
683
    }
689
    }
684
    return ENOTSUP;
690
    return ENOTSUP;
685
}
691
}
686
 
692
 
687
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
693
int icmp_process_client_messages( ipc_callid_t callid, ipc_call_t call ){
688
    ERROR_DECLARE;
694
    ERROR_DECLARE;
689
 
695
 
690
    bool                    keep_on_going = true;
696
    bool                    keep_on_going = true;
691
    fibril_rwlock_t         lock;
697
    fibril_rwlock_t         lock;
692
    ipc_call_t              answer;
698
    ipc_call_t              answer;
693
    int                     answer_count;
699
    int                     answer_count;
694
    size_t                  length;
700
    size_t                  length;
695
    struct sockaddr *       addr;
701
    struct sockaddr *       addr;
696
    icmp_param_t            id;
-
 
697
    icmp_param_t            sequence = 0;
-
 
698
    ipc_callid_t            data_callid;
702
    ipc_callid_t            data_callid;
-
 
703
    icmp_echo_ref           echo_data;
699
 
704
 
700
    /*
705
    /*
701
     * Accept the connection
706
     * Accept the connection
702
     *  - Answer the first NET_ICMP_INIT call.
707
     *  - Answer the first NET_ICMP_INIT call.
703
     */
708
     */
704
    ipc_answer_0( callid, EOK );
709
    ipc_answer_0( callid, EOK );
705
 
710
 
706
    fibril_rwlock_initialize( & lock );
711
    fibril_rwlock_initialize( & lock );
707
 
712
 
-
 
713
    echo_data = ( icmp_echo_ref ) malloc( sizeof( * echo_data ));
-
 
714
    if( ! echo_data ) return ENOMEM;
708
    // assign a new identifier
715
    // assign a new identifier
709
    fibril_rwlock_write_lock( & icmp_globals.lock );
716
    fibril_rwlock_write_lock( & icmp_globals.lock );
710
    ++ icmp_globals.last_used_id;
-
 
711
    id = icmp_globals.last_used_id;
717
    ERROR_CODE = icmp_bind_free_id( echo_data );
712
    fibril_rwlock_write_unlock( & icmp_globals.lock );
718
    fibril_rwlock_write_unlock( & icmp_globals.lock );
-
 
719
    if( ERROR_CODE < 0 ){
-
 
720
        free( echo_data );
-
 
721
        return ERROR_CODE;
-
 
722
    }
713
 
723
 
714
    while( keep_on_going ){
724
    while( keep_on_going ){
715
        refresh_answer( & answer, & answer_count );
725
        refresh_answer( & answer, & answer_count );
716
 
726
 
717
        callid = async_get_call( & call );
727
        callid = async_get_call( & call );
718
 
728
 
719
        switch( IPC_GET_METHOD( call )){
729
        switch( IPC_GET_METHOD( call )){
720
            case IPC_M_PHONE_HUNGUP:
730
            case IPC_M_PHONE_HUNGUP:
721
                keep_on_going = false;
731
                keep_on_going = false;
722
                ERROR_CODE = EOK;
732
                ERROR_CODE = EOK;
723
                break;
733
                break;
724
            case NET_ICMP_ECHO:
734
            case NET_ICMP_ECHO:
725
                fibril_rwlock_write_lock( & lock );
735
                fibril_rwlock_write_lock( & lock );
726
                if( ! ipc_data_write_receive( & data_callid, & length )){
736
                if( ! ipc_data_write_receive( & data_callid, & length )){
727
                    ERROR_CODE = EINVAL;
737
                    ERROR_CODE = EINVAL;
728
                }else{
738
                }else{
729
                    addr = malloc( length );
739
                    addr = malloc( length );
730
                    if( ! addr ){
740
                    if( ! addr ){
731
                        ERROR_CODE = ENOMEM;
741
                        ERROR_CODE = ENOMEM;
732
                    }else{
742
                    }else{
733
                        if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, length ))){
743
                        if( ! ERROR_OCCURRED( ipc_data_write_finalize( data_callid, addr, length ))){
734
                            fibril_rwlock_write_lock( & icmp_globals.lock );
744
                            fibril_rwlock_write_lock( & icmp_globals.lock );
735
                            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, ( socklen_t ) length );
745
                            ERROR_CODE = icmp_echo( echo_data->id, echo_data->sequence, ICMP_GET_SIZE( call ), ICMP_GET_TIMEOUT( call ), ICMP_GET_TTL( call ), ICMP_GET_TOS( call ), ICMP_GET_DONT_FRAGMENT( call ), addr, ( socklen_t ) length );
736
                            fibril_rwlock_write_unlock( & icmp_globals.lock );
746
                            fibril_rwlock_write_unlock( & icmp_globals.lock );
737
                            free( addr );
747
                            free( addr );
-
 
748
                            if( echo_data->sequence < MAX_UINT16 ){
738
                            ++ sequence;
749
                                ++ echo_data->sequence;
-
 
750
                            }else{
-
 
751
                                echo_data->sequence = 0;
-
 
752
                            }
739
                        }
753
                        }
740
                    }
754
                    }
741
                }
755
                }
742
                fibril_rwlock_write_unlock( & lock );
756
                fibril_rwlock_write_unlock( & lock );
743
                break;
757
                break;
744
            default:
758
            default:
745
                ERROR_CODE = icmp_process_message( & call );
759
                ERROR_CODE = icmp_process_message( & call );
746
        }
760
        }
747
 
761
 
748
        answer_call( callid, ERROR_CODE, & answer, answer_count );
762
        answer_call( callid, ERROR_CODE, & answer, answer_count );
749
    }
763
    }
750
 
764
 
-
 
765
    // release the identifier
-
 
766
    fibril_rwlock_write_lock( & icmp_globals.lock );
-
 
767
    icmp_echo_data_exclude( & icmp_globals.echo_data, echo_data->id );
-
 
768
    fibril_rwlock_write_unlock( & icmp_globals.lock );
751
    return EOK;
769
    return EOK;
752
}
770
}
753
 
771
 
754
int icmp_process_message( ipc_call_t * call ){
772
int icmp_process_message( ipc_call_t * call ){
755
    ERROR_DECLARE;
773
    ERROR_DECLARE;
756
 
774
 
757
    packet_t    packet;
775
    packet_t    packet;
758
 
776
 
759
    switch( IPC_GET_METHOD( * call )){
777
    switch( IPC_GET_METHOD( * call )){
760
        case NET_ICMP_DEST_UNREACH:
778
        case NET_ICMP_DEST_UNREACH:
761
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
779
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
762
                ERROR_CODE = icmp_destination_unreachable_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_MTU( call ), packet );
780
                ERROR_CODE = icmp_destination_unreachable_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_MTU( call ), packet );
763
            }
781
            }
764
            return ERROR_CODE;
782
            return ERROR_CODE;
765
        case NET_ICMP_SOURCE_QUENCH:
783
        case NET_ICMP_SOURCE_QUENCH:
766
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
784
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
767
                ERROR_CODE = icmp_source_quench_msg( 0, packet );
785
                ERROR_CODE = icmp_source_quench_msg( 0, packet );
768
            }
786
            }
769
            return ERROR_CODE;
787
            return ERROR_CODE;
770
        case NET_ICMP_TIME_EXCEEDED:
788
        case NET_ICMP_TIME_EXCEEDED:
771
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
789
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
772
                ERROR_CODE = icmp_time_exceeded_msg( 0, ICMP_GET_CODE( call ), packet );
790
                ERROR_CODE = icmp_time_exceeded_msg( 0, ICMP_GET_CODE( call ), packet );
773
            }
791
            }
774
            return ERROR_CODE;
792
            return ERROR_CODE;
775
        case NET_ICMP_PARAMETERPROB:
793
        case NET_ICMP_PARAMETERPROB:
776
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
794
            if( ! ERROR_OCCURRED( packet_translate( icmp_globals.net_phone, & packet, IPC_GET_PACKET( call )))){
777
                ERROR_CODE = icmp_parameter_problem_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_POINTER( call ), packet );
795
                ERROR_CODE = icmp_parameter_problem_msg( 0, ICMP_GET_CODE( call ), ICMP_GET_POINTER( call ), packet );
778
            }
796
            }
779
            return ERROR_CODE;
797
            return ERROR_CODE;
780
        default:
798
        default:
781
            return ENOTSUP;
799
            return ENOTSUP;
782
    }
800
    }
783
}
801
}
784
 
802
 
785
int icmp_release_and_return( packet_t packet, int result ){
803
int icmp_release_and_return( packet_t packet, int result ){
786
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
804
    pq_release( icmp_globals.net_phone, packet_get_id( packet ));
787
    return result;
805
    return result;
788
}
806
}
-
 
807
 
-
 
808
int icmp_bind_free_id( icmp_echo_ref echo_data ){
-
 
809
    icmp_param_t    index;
-
 
810
 
-
 
811
    if( ! echo_data ) return EBADMEM;
-
 
812
    // from the last used one
-
 
813
    index = icmp_globals.last_used_id;
-
 
814
    do{
-
 
815
        ++ index;
-
 
816
        // til the range end
-
 
817
        if( index >= ICMP_FREE_IDS_END ){
-
 
818
            // start from the range beginning
-
 
819
            index = ICMP_FREE_IDS_START - 1;
-
 
820
            do{
-
 
821
                ++ index;
-
 
822
                // til the last used one
-
 
823
                if( index >= icmp_globals.last_used_id ){
-
 
824
                    // none found
-
 
825
                    return ENOTCONN;
-
 
826
                }
-
 
827
            }while( icmp_echo_data_find( & icmp_globals.echo_data, index ) != NULL );
-
 
828
            // found, break immediately
-
 
829
            break;
-
 
830
        }
-
 
831
    }while( icmp_echo_data_find( & icmp_globals.echo_data, index ) != NULL );
-
 
832
    echo_data->id = index;
-
 
833
    echo_data->sequence = 0;
-
 
834
    return icmp_echo_data_add( & icmp_globals.echo_data, index, echo_data );
-
 
835
}
789
 
836
 
790
/** @}
837
/** @}
791
 */
838
 */
792
 
839