Subversion Repositories HelenOS

Rev

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

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