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