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