Subversion Repositories HelenOS

Rev

Rev 4743 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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