Changeset 7fc092a in mainline for uspace/srv/net/tl/icmp/icmp.c
- Timestamp:
- 2011-01-27T22:09:29Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- db7ed07
- Parents:
- 9ee87f6 (diff), 6265a2b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/tl/icmp/icmp.c
r9ee87f6 r7fc092a 33 33 /** @file 34 34 * ICMP module implementation. 35 * @see icmp.h 36 */ 37 38 #include "icmp.h" 39 #include "icmp_module.h" 35 */ 40 36 41 37 #include <async.h> … … 54 50 #include <byteorder.h> 55 51 #include <errno.h> 52 #include <adt/hash_table.h> 56 53 57 54 #include <net/socket_codes.h> … … 67 64 #include <net_checksum.h> 68 65 #include <icmp_client.h> 69 #include <icmp_ interface.h>70 #include <il_ interface.h>66 #include <icmp_remote.h> 67 #include <il_remote.h> 71 68 #include <ip_client.h> 72 69 #include <ip_interface.h> 73 70 #include <net_interface.h> 74 #include <tl_ interface.h>75 #include <tl_ local.h>71 #include <tl_remote.h> 72 #include <tl_skel.h> 76 73 #include <icmp_header.h> 77 74 78 /** ICMP module name. */ 79 #define NAME "ICMP protocol" 80 81 /** Default ICMP error reporting. */ 82 #define NET_DEFAULT_ICMP_ERROR_REPORTING true 83 84 /** Default ICMP echo replying. */ 85 #define NET_DEFAULT_ICMP_ECHO_REPLYING true 86 87 /** Original datagram length in bytes transfered to the error notification 88 * message. 89 */ 90 #define ICMP_KEEP_LENGTH 8 91 92 /** Free identifier numbers pool start. */ 93 #define ICMP_FREE_IDS_START 1 94 95 /** Free identifier numbers pool end. */ 96 #define ICMP_FREE_IDS_END UINT16_MAX 97 98 /** 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. 75 /** ICMP module name */ 76 #define NAME "icmp" 77 78 /** Number of replies hash table keys */ 79 #define REPLY_KEYS 2 80 81 /** Number of replies hash table buckets */ 82 #define REPLY_BUCKETS 1024 83 84 /** 85 * Original datagram length in bytes transfered to the error 86 * notification message. 87 */ 88 #define ICMP_KEEP_LENGTH 8 89 90 /** Compute the ICMP datagram checksum. 91 * 92 * @param[in,out] header ICMP datagram header. 93 * @param[in] length Total datagram length. 94 * 95 * @return Computed checksum. 96 * 103 97 */ 104 98 #define ICMP_CHECKSUM(header, length) \ … … 106 100 107 101 /** An echo request datagrams pattern. */ 108 #define ICMP_ECHO_TEXT "Hello from HelenOS." 109 110 /** 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. */ 121 icmp_globals_t icmp_globals; 122 123 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t); 124 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t); 125 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)); 135 return result; 136 } 137 138 /** Sends the ICMP message. 139 * 140 * Sets the message type and code and computes the checksum. 102 #define ICMP_ECHO_TEXT "ICMP hello from HelenOS." 103 104 /** ICMP reply data. */ 105 typedef struct { 106 /** Hash table link */ 107 link_t link; 108 109 /** Reply identification and sequence */ 110 icmp_param_t id; 111 icmp_param_t sequence; 112 113 /** Reply signaling */ 114 fibril_condvar_t condvar; 115 116 /** Reply result */ 117 int result; 118 } icmp_reply_t; 119 120 /** Global data */ 121 static int phone_net = -1; 122 static int phone_ip = -1; 123 static bool error_reporting = true; 124 static bool echo_replying = true; 125 static packet_dimension_t icmp_dimension; 126 127 /** ICMP client identification counter */ 128 static atomic_t icmp_client; 129 130 /** ICMP identifier and sequence number (client-specific) */ 131 static fibril_local icmp_param_t icmp_id; 132 static fibril_local icmp_param_t icmp_seq; 133 134 /** Reply hash table */ 135 static fibril_mutex_t reply_lock; 136 static hash_table_t replies; 137 138 static hash_index_t replies_hash(unsigned long key[]) 139 { 140 /* 141 * ICMP identifier and sequence numbers 142 * are 16-bit values. 143 */ 144 hash_index_t index = ((key[0] & 0xffff) << 16) | (key[1] & 0xffff); 145 return (index % REPLY_BUCKETS); 146 } 147 148 static int replies_compare(unsigned long key[], hash_count_t keys, link_t *item) 149 { 150 icmp_reply_t *reply = 151 hash_table_get_instance(item, icmp_reply_t, link); 152 153 if (keys == 1) 154 return (reply->id == key[0]); 155 else 156 return ((reply->id == key[0]) && (reply->sequence == key[1])); 157 } 158 159 static void replies_remove_callback(link_t *item) 160 { 161 } 162 163 static hash_table_operations_t reply_ops = { 164 .hash = replies_hash, 165 .compare = replies_compare, 166 .remove_callback = replies_remove_callback 167 }; 168 169 /** Release the packet and return the result. 170 * 171 * @param[in] packet Packet queue to be released. 172 * 173 */ 174 static void icmp_release(packet_t *packet) 175 { 176 pq_release_remote(phone_net, packet_get_id(packet)); 177 } 178 179 /** Send the ICMP message. 180 * 181 * Set the message type and code and compute the checksum. 141 182 * 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 183 * Release the packet on errors. 184 * 185 * @param[in] type Message type. 186 * @param[in] code Message code. 187 * @param[in] packet Message packet to be sent. 188 * @param[in] header ICMP header. 189 * @param[in] error Error service to be announced. Should be 190 * SERVICE_ICMP or zero. 191 * @param[in] ttl Time to live. 192 * @param[in] tos Type of service. 193 * @param[in] dont_fragment Disable fragmentation. 194 * 195 * @return EOK on success. 196 * @return EPERM if the error message is not allowed. 197 * 198 */ 199 static int icmp_send_packet(icmp_type_t type, icmp_code_t code, 200 packet_t *packet, icmp_header_t *header, services_t error, ip_ttl_t ttl, 201 ip_tos_t tos, bool dont_fragment) 202 { 163 203 /* Do not send an error if disabled */ 164 if (error && !icmp_globals.error_reporting) 165 return icmp_release_and_return(packet, EPERM); 166 204 if ((error) && (!error_reporting)) { 205 icmp_release(packet); 206 return EPERM; 207 } 208 167 209 header->type = type; 168 210 header->code = code; 211 212 /* 213 * The checksum needs to be calculated 214 * with a virtual checksum field set to 215 * zero. 216 */ 169 217 header->checksum = 0; 170 218 header->checksum = ICMP_CHECKSUM(header, 171 219 packet_get_data_length(packet)); 172 220 173 rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,221 int rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos, 174 222 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. 223 if (rc != EOK) { 224 icmp_release(packet); 225 return rc; 226 } 227 228 return ip_send_msg(phone_ip, -1, packet, SERVICE_ICMP, error); 229 } 230 231 /** Prepare the ICMP error packet. 232 * 233 * Truncate the original packet if longer than ICMP_KEEP_LENGTH bytes. 234 * Prefix and return the ICMP header. 235 * 236 * @param[in,out] packet Original packet. 237 * 188 238 * @return The prefixed ICMP header. 189 239 * @return NULL on errors. 240 * 190 241 */ 191 242 static icmp_header_t *icmp_prepare_packet(packet_t *packet) 192 243 { 193 icmp_header_t *header; 194 size_t header_length; 195 size_t total_length; 196 197 total_length = packet_get_data_length(packet); 244 size_t total_length = packet_get_data_length(packet); 198 245 if (total_length <= 0) 199 246 return NULL; 200 201 header_length = ip_client_header_length(packet);247 248 size_t header_length = ip_client_header_length(packet); 202 249 if (header_length <= 0) 203 250 return NULL; 204 251 205 252 /* Truncate if longer than 64 bits (without the IP header) */ 206 253 if ((total_length > header_length + ICMP_KEEP_LENGTH) && 207 254 (packet_trim(packet, 0, 208 total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {255 total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) 209 256 return NULL; 210 } 211 212 header = PACKET_PREFIX(packet, icmp_header_t); 257 258 icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t); 213 259 if (!header) 214 260 return NULL; 215 261 216 262 bzero(header, sizeof(*header)); 217 263 return header; 218 264 } 219 265 220 /** Request san echo message.221 * 222 * Send s a packet with specified parameters to the target host and waits for223 * the reply upto the given timeout.224 * Block sthe 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 not233 * 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 237 * @return 238 * 239 * @return 240 * @return 241 * 242 * @return 243 * @return EPARTY if there was an internal error.266 /** Request an echo message. 267 * 268 * Send a packet with specified parameters to the target host 269 * and wait for the reply upto the given timeout. 270 * Block the caller until the reply or the timeout occurs. 271 * 272 * @param[in] id Message identifier. 273 * @param[in] sequence Message sequence parameter. 274 * @param[in] size Message data length in bytes. 275 * @param[in] timeout Timeout in miliseconds. 276 * @param[in] ttl Time to live. 277 * @param[in] tos Type of service. 278 * @param[in] dont_fragment Disable fragmentation. 279 * @param[in] addr Target host address. 280 * @param[in] addrlen Torget host address length. 281 * 282 * @return ICMP_ECHO on success. 283 * @return ETIMEOUT if the reply has not arrived before the 284 * timeout. 285 * @return ICMP type of the received error notification. 286 * @return EINVAL if the addrlen parameter is less or equal to 287 * zero. 288 * @return ENOMEM if there is not enough memory left. 289 * 244 290 */ 245 291 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; 255 int index; 256 int rc; 257 292 mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, bool dont_fragment, 293 const struct sockaddr *addr, socklen_t addrlen) 294 { 258 295 if (addrlen <= 0) 259 296 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); 297 298 size_t length = (size_t) addrlen; 299 300 packet_t *packet = packet_get_4_remote(phone_net, size, 301 icmp_dimension.addr_len, ICMP_HEADER_SIZE + icmp_dimension.prefix, 302 icmp_dimension.suffix); 272 303 if (!packet) 273 304 return ENOMEM; 274 305 275 306 /* 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 307 int rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length); 308 if (rc != EOK) { 309 icmp_release(packet); 310 return rc; 311 } 312 280 313 /* 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 314 uint8_t *data = (uint8_t *) packet_suffix(packet, size); 315 if (!data) { 316 icmp_release(packet); 317 return ENOMEM; 318 } 319 285 320 /* Fill the data */ 286 321 length = 0; … … 290 325 } 291 326 memcpy(data + length, ICMP_ECHO_TEXT, size - length); 292 327 293 328 /* 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)); 329 icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t); 330 if (!header) { 331 icmp_release(packet); 332 return ENOMEM; 333 } 334 335 bzero(header, sizeof(icmp_header_t)); 299 336 header->un.echo.identifier = id; 300 337 header->un.echo.sequence_number = sequence; 301 338 302 339 /* 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); 340 icmp_reply_t *reply = malloc(sizeof(icmp_reply_t)); 341 if (!reply) { 342 icmp_release(packet); 343 return ENOMEM; 344 } 345 346 reply->id = id; 347 reply->sequence = sequence; 309 348 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 349 350 /* Add the reply to the replies hash table */ 351 fibril_mutex_lock(&reply_lock); 352 353 unsigned long key[REPLY_KEYS] = {id, sequence}; 354 hash_table_insert(&replies, key, &reply->link); 355 321 356 /* Send the request */ 322 357 icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, 323 358 dont_fragment); 324 359 325 360 /* Wait for the reply. Timeout in microseconds. */ 326 rc = fibril_condvar_wait_timeout(&reply->condvar, &reply ->mutex,361 rc = fibril_condvar_wait_timeout(&reply->condvar, &reply_lock, 327 362 timeout * 1000); 328 363 if (rc == EOK) 329 364 rc = reply->result; 330 331 /* Drop the reply mutex before locking the globals again*/332 fibril_mutex_unlock(&reply->mutex);333 fibril_rwlock_write_lock(&icmp_globals.lock);334 335 /* Destroy the reply structure */336 icmp_replies_exclude_index(&icmp_globals.replies, index);337 365 366 /* Remove the reply from the replies hash table */ 367 hash_table_remove(&replies, key, REPLY_KEYS); 368 369 fibril_mutex_unlock(&reply_lock); 370 371 free(reply); 372 338 373 return rc; 339 374 } 340 375 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 376 static int icmp_destination_unreachable(icmp_code_t code, icmp_param_t mtu, 377 packet_t *packet) 378 { 379 icmp_header_t *header = icmp_prepare_packet(packet); 380 if (!header) { 381 icmp_release(packet); 382 return ENOMEM; 383 } 384 350 385 if (mtu) 351 386 header->un.frag.mtu = mtu; 352 387 353 388 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 389 SERVICE_ICMP, 0, 0, false); 390 } 391 392 static int icmp_source_quench(packet_t *packet) 393 { 394 icmp_header_t *header = icmp_prepare_packet(packet); 395 if (!header) { 396 icmp_release(packet); 397 return ENOMEM; 398 } 399 365 400 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, 401 SERVICE_ICMP, 0, 0, false); 402 } 403 404 static int icmp_time_exceeded(icmp_code_t code, packet_t *packet) 405 { 406 icmp_header_t *header = icmp_prepare_packet(packet); 407 if (!header) { 408 icmp_release(packet); 409 return ENOMEM; 410 } 411 412 return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header, 413 SERVICE_ICMP, 0, 0, false); 414 } 415 416 static int icmp_parameter_problem(icmp_code_t code, icmp_param_t pointer, 370 417 packet_t *packet) 371 418 { 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 419 icmp_header_t *header = icmp_prepare_packet(packet); 420 if (!header) { 421 icmp_release(packet); 422 return ENOMEM; 423 } 424 391 425 header->un.param.pointer = pointer; 392 426 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) 427 SERVICE_ICMP, 0, 0, false); 428 } 429 430 /** Try to set the pending reply result as the received message type. 431 * 432 * If the reply data is not present, the reply timed out and the other fibril 433 * is already awake. The packet is released. 434 * 435 * @param[in] packet The received reply message. 436 * @param[in] header The ICMP message header. 437 * @param[in] type The received reply message type. 438 * @param[in] code The received reply message code. 439 * 440 */ 441 static void icmp_process_echo_reply(packet_t *packet, icmp_header_t *header, 442 icmp_type_t type, icmp_code_t code) 443 { 444 unsigned long key[REPLY_KEYS] = 445 {header->un.echo.identifier, header->un.echo.sequence_number}; 446 447 /* The packet is no longer needed */ 448 icmp_release(packet); 449 450 /* Find the pending reply */ 451 fibril_mutex_lock(&reply_lock); 452 453 link_t *link = hash_table_find(&replies, key); 454 if (link != NULL) { 455 icmp_reply_t *reply = 456 hash_table_get_instance(link, icmp_reply_t, link); 457 458 reply->result = type; 459 fibril_condvar_signal(&reply->condvar); 460 } 461 462 fibril_mutex_unlock(&reply_lock); 463 } 464 465 /** Process the received ICMP packet. 466 * 467 * Notify the destination socket application. 468 * 469 * @param[in,out] packet Received packet. 470 * @param[in] error Packet error reporting service to prefix 471 * the received packet. 472 * 473 * @return EOK on success. 474 * @return EINVAL if the packet is not valid. 475 * @return EINVAL if the stored packet address is not the an_addr_t. 476 * @return EINVAL if the packet does not contain any data. 477 * @return NO_DATA if the packet content is shorter than the user 478 * datagram header. 479 * @return ENOMEM if there is not enough memory left. 480 * @return EADDRNOTAVAIL if the destination socket does not exist. 481 * @return Other error codes as defined for the 482 * ip_client_process_packet() function. 483 * 484 */ 485 static int icmp_process_packet(packet_t *packet, services_t error) 486 { 487 icmp_type_t type; 488 icmp_code_t code; 489 int rc; 490 491 switch (error) { 492 case SERVICE_NONE: 493 break; 494 case SERVICE_ICMP: 495 /* Process error */ 496 rc = icmp_client_process_packet(packet, &type, &code, NULL, NULL); 497 if (rc < 0) 498 return rc; 499 500 /* Remove the error header */ 501 rc = packet_trim(packet, (size_t) rc, 0); 502 if (rc != EOK) 503 return rc; 504 505 break; 506 default: 507 return ENOTSUP; 508 } 509 510 /* Get rid of the IP header */ 511 size_t length = ip_client_header_length(packet); 512 rc = packet_trim(packet, length, 0); 513 if (rc != EOK) 514 return rc; 515 516 length = packet_get_data_length(packet); 517 if (length <= 0) 518 return EINVAL; 519 520 if (length < ICMP_HEADER_SIZE) 521 return EINVAL; 522 523 void *data = packet_get_data(packet); 524 if (!data) 525 return EINVAL; 526 527 /* Get ICMP header */ 528 icmp_header_t *header = (icmp_header_t *) data; 529 530 if (header->checksum) { 531 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) { 532 /* 533 * Set the original message type on error notification. 534 * Type swap observed in Qemu. 535 */ 536 if (error) { 537 switch (header->type) { 538 case ICMP_ECHOREPLY: 539 header->type = ICMP_ECHO; 540 continue; 541 } 542 } 543 544 return EINVAL; 545 } 546 } 547 548 switch (header->type) { 549 case ICMP_ECHOREPLY: 550 if (error) 551 icmp_process_echo_reply(packet, header, type, code); 552 else 553 icmp_process_echo_reply(packet, header, ICMP_ECHO, 0); 554 555 return EOK; 556 557 case ICMP_ECHO: 558 if (error) { 559 icmp_process_echo_reply(packet, header, type, code); 560 return EOK; 561 } 562 563 /* Do not send a reply if disabled */ 564 if (echo_replying) { 565 uint8_t *src; 566 int addrlen = packet_get_addr(packet, &src, NULL); 567 568 /* 569 * Set both addresses to the source one (avoid the 570 * source address deletion before setting the 571 * destination one). 572 */ 573 if ((addrlen > 0) && (packet_set_addr(packet, src, src, 574 (size_t) addrlen) == EOK)) { 575 /* Send the reply */ 576 icmp_send_packet(ICMP_ECHOREPLY, 0, packet, 577 header, 0, 0, 0, 0); 578 return EOK; 579 } 580 581 return EINVAL; 582 } 583 584 return EPERM; 585 586 case ICMP_DEST_UNREACH: 587 case ICMP_SOURCE_QUENCH: 588 case ICMP_REDIRECT: 589 case ICMP_ALTERNATE_ADDR: 590 case ICMP_ROUTER_ADV: 591 case ICMP_ROUTER_SOL: 592 case ICMP_TIME_EXCEEDED: 593 case ICMP_PARAMETERPROB: 594 case ICMP_CONVERSION_ERROR: 595 case ICMP_REDIRECT_MOBILE: 596 case ICMP_SKIP: 597 case ICMP_PHOTURIS: 598 ip_received_error_msg(phone_ip, -1, packet, 599 SERVICE_IP, SERVICE_ICMP); 600 return EOK; 601 602 default: 603 return ENOTSUP; 604 } 605 } 606 607 /** Process IPC messages from the IP module 608 * 609 * @param[in] iid Message identifier. 610 * @param[in,out] icall Message parameters. 611 * 612 */ 613 static void icmp_receiver(ipc_callid_t iid, ipc_call_t *icall) 614 { 615 bool loop = true; 616 packet_t *packet; 617 int rc; 618 619 while (loop) { 620 switch (IPC_GET_IMETHOD(*icall)) { 621 case NET_TL_RECEIVED: 622 rc = packet_translate_remote(phone_net, &packet, 623 IPC_GET_PACKET(*icall)); 624 if (rc == EOK) { 625 rc = icmp_process_packet(packet, IPC_GET_ERROR(*icall)); 626 if (rc != EOK) 627 icmp_release(packet); 628 } 629 630 ipc_answer_0(iid, (sysarg_t) rc); 631 break; 632 case IPC_M_PHONE_HUNGUP: 633 loop = false; 634 continue; 635 default: 636 ipc_answer_0(iid, (sysarg_t) ENOTSUP); 637 } 638 639 iid = async_get_call(icall); 640 } 641 } 642 643 /** Initialize the ICMP module. 644 * 645 * @param[in] net_phone Network module phone. 646 * 647 * @return EOK on success. 648 * @return ENOMEM if there is not enough memory left. 649 * 650 */ 651 int tl_initialize(int net_phone) 404 652 { 405 653 measured_string_t names[] = { … … 416 664 size_t count = sizeof(names) / sizeof(measured_string_t); 417 665 uint8_t *data; 418 int rc; 419 420 fibril_rwlock_initialize(&icmp_globals.lock); 421 fibril_rwlock_write_lock(&icmp_globals.lock); 422 icmp_replies_initialize(&icmp_globals.replies); 423 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); 429 return icmp_globals.ip_phone; 430 } 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); 666 667 if (!hash_table_create(&replies, REPLY_BUCKETS, REPLY_KEYS, &reply_ops)) 668 return ENOMEM; 669 670 fibril_mutex_initialize(&reply_lock); 671 atomic_set(&icmp_client, 0); 672 673 phone_net = net_phone; 674 phone_ip = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, 675 icmp_receiver); 676 if (phone_ip < 0) 677 return phone_ip; 678 679 int rc = ip_packet_size_req(phone_ip, -1, &icmp_dimension); 680 if (rc != EOK) 436 681 return rc; 437 } 438 439 icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE; 440 icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE; 441 442 icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING; 443 icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING; 444 682 683 icmp_dimension.prefix += ICMP_HEADER_SIZE; 684 icmp_dimension.content -= ICMP_HEADER_SIZE; 685 445 686 /* Get configuration */ 446 687 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); 688 rc = net_get_conf_req(phone_net, &configuration, count, &data); 689 if (rc != EOK) 451 690 return rc; 452 }453 691 454 692 if (configuration) { 455 if (configuration[0].value) { 456 icmp_globals.error_reporting = 457 (configuration[0].value[0] == 'y'); 458 } 459 if (configuration[1].value) { 460 icmp_globals.echo_replying = 461 (configuration[1].value[0] == 'y'); 462 } 693 if (configuration[0].value) 694 error_reporting = (configuration[0].value[0] == 'y'); 695 696 if (configuration[1].value) 697 echo_replying = (configuration[1].value[0] == 'y'); 698 463 699 net_free_settings(configuration, data); 464 700 } 465 466 fibril_rwlock_write_unlock(&icmp_globals.lock); 701 467 702 return EOK; 468 703 } 469 704 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 { 522 size_t length; 523 uint8_t *src; 524 int addrlen; 525 int result; 526 void *data; 527 icmp_header_t *header; 528 icmp_type_t type; 529 icmp_code_t code; 705 /** Per-connection initialization 706 * 707 * Initialize client-specific global variables. 708 * 709 */ 710 void tl_connection(void) 711 { 712 icmp_id = (icmp_param_t) atomic_postinc(&icmp_client); 713 icmp_seq = 1; 714 } 715 716 /** Process the ICMP message. 717 * 718 * @param[in] callid Message identifier. 719 * @param[in] call Message parameters. 720 * @param[out] answer Answer. 721 * @param[out] count Number of arguments of the answer. 722 * 723 * @return EOK on success. 724 * @return ENOTSUP if the message is not known. 725 * @return Other error codes as defined for the packet_translate() 726 * function. 727 * @return Other error codes as defined for the 728 * icmp_destination_unreachable() function. 729 * @return Other error codes as defined for the 730 * icmp_source_quench() function. 731 * @return Other error codes as defined for the 732 * icmp_time_exceeded() function. 733 * @return Other error codes as defined for the 734 * icmp_parameter_problem() function. 735 * 736 * @see icmp_remote.h 737 * @see IS_NET_ICMP_MESSAGE() 738 * 739 */ 740 int tl_message(ipc_callid_t callid, ipc_call_t *call, 741 ipc_call_t *answer, size_t *count) 742 { 743 struct sockaddr *addr; 744 size_t size; 745 packet_t *packet; 530 746 int rc; 531 747 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); 748 *count = 0; 749 750 switch (IPC_GET_IMETHOD(*call)) { 751 case NET_ICMP_ECHO: 752 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &size); 544 753 if (rc != EOK) 545 754 return rc; 546 break; 547 default: 548 return ENOTSUP; 549 } 550 551 /* Get rid of the IP header */ 552 length = ip_client_header_length(packet); 553 rc = packet_trim(packet, length, 0); 554 if (rc != EOK) 755 756 rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call), 757 ICMP_GET_TIMEOUT(*call), ICMP_GET_TTL(*call), 758 ICMP_GET_TOS(*call), ICMP_GET_DONT_FRAGMENT(*call), 759 addr, (socklen_t) size); 760 761 free(addr); 762 icmp_seq++; 555 763 return rc; 556 557 length = packet_get_data_length(packet); 558 if (length <= 0) 559 return EINVAL; 560 561 if (length < ICMP_HEADER_SIZE) 562 return EINVAL; 563 564 data = packet_get_data(packet); 565 if (!data) 566 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; 582 } 583 } 584 return EINVAL; 585 } 586 } 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); 600 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; 618 } 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_IMETHOD(*call)) { 764 696 765 case NET_ICMP_DEST_UNREACH: 697 rc = packet_translate_remote( icmp_globals.net_phone, &packet,766 rc = packet_translate_remote(phone_net, &packet, 698 767 IPC_GET_PACKET(*call)); 699 768 if (rc != EOK) 700 769 return rc; 701 return icmp_destination_unreachable_msg_local(0, 702 ICMP_GET_CODE(*call), ICMP_GET_MTU(*call), packet); 770 771 return icmp_destination_unreachable(ICMP_GET_CODE(*call), 772 ICMP_GET_MTU(*call), packet); 773 703 774 case NET_ICMP_SOURCE_QUENCH: 704 rc = packet_translate_remote( icmp_globals.net_phone, &packet,775 rc = packet_translate_remote(phone_net, &packet, 705 776 IPC_GET_PACKET(*call)); 706 777 if (rc != EOK) 707 778 return rc; 708 return icmp_source_quench_msg_local(0, packet); 779 780 return icmp_source_quench(packet); 781 709 782 case NET_ICMP_TIME_EXCEEDED: 710 rc = packet_translate_remote( icmp_globals.net_phone, &packet,783 rc = packet_translate_remote(phone_net, &packet, 711 784 IPC_GET_PACKET(*call)); 712 785 if (rc != EOK) 713 786 return rc; 714 return icmp_time_exceeded_msg_local(0, ICMP_GET_CODE(*call), 715 packet); 787 788 return icmp_time_exceeded(ICMP_GET_CODE(*call), packet); 789 716 790 case NET_ICMP_PARAMETERPROB: 717 rc = packet_translate_remote( icmp_globals.net_phone, &packet,791 rc = packet_translate_remote(phone_net, &packet, 718 792 IPC_GET_PACKET(*call)); 719 793 if (rc != EOK) 720 794 return rc; 721 return icmp_parameter_problem_msg_local(0, ICMP_GET_CODE(*call), 795 796 return icmp_parameter_problem(ICMP_GET_CODE(*call), 722 797 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 { 787 bool keep_on_going = true; 788 ipc_call_t answer; 789 size_t answer_count; 790 size_t length; 791 struct sockaddr *addr; 792 ipc_callid_t data_callid; 793 icmp_echo_t *echo_data; 794 int rc = EOK; 795 796 /* 797 * Accept the connection 798 * - Answer the first NET_ICMP_INIT call. 799 */ 800 answer_count = 0; 801 802 echo_data = (icmp_echo_t *) malloc(sizeof(*echo_data)); 803 if (!echo_data) 804 return ENOMEM; 805 806 /* Assign a new identifier */ 807 fibril_rwlock_write_lock(&icmp_globals.lock); 808 rc = icmp_bind_free_id(echo_data); 809 fibril_rwlock_write_unlock(&icmp_globals.lock); 810 if (rc < 0) { 811 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 */ 820 refresh_answer(&answer, &answer_count); 821 822 /* Get the next call */ 823 callid = async_get_call(&call); 824 825 /* Process the call */ 826 switch (IPC_GET_IMETHOD(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; 835 break; 836 } 837 838 addr = malloc(length); 839 if (!addr) { 840 rc = ENOMEM; 841 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); 870 } 871 872 } 873 874 /* Release the identifier */ 875 fibril_rwlock_write_lock(&icmp_globals.lock); 876 icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier); 877 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, size_t *answer_count) 897 { 898 packet_t *packet; 899 int rc; 900 901 *answer_count = 0; 902 switch (IPC_GET_IMETHOD(*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 798 } 799 918 800 return ENOTSUP; 919 801 } 920 802 921 922 /** Default thread for new connections.923 *924 * @param[in] iid The initial message identifier.925 * @param[in] icall The initial message call structure.926 *927 */928 static void tl_client_connection(ipc_callid_t iid, ipc_call_t *icall)929 {930 /*931 * Accept the connection932 * - Answer the first IPC_M_CONNECT_ME_TO call.933 */934 ipc_answer_0(iid, EOK);935 936 while (true) {937 ipc_call_t answer;938 size_t answer_count;939 940 /* Clear the answer structure */941 refresh_answer(&answer, &answer_count);942 943 /* Fetch the next message */944 ipc_call_t call;945 ipc_callid_t callid = async_get_call(&call);946 947 /* Process the message */948 int res = tl_module_message_standalone(callid, &call, &answer,949 &answer_count);950 951 /*952 * End if told to either by the message or the processing953 * result.954 */955 if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||956 (res == EHANGUP))957 return;958 959 /* Answer the message */960 answer_call(callid, res, &answer, answer_count);961 }962 }963 964 /** Starts the module.965 *966 * @return EOK on success.967 * @return Other error codes as defined for each specific module968 * start function.969 */970 803 int main(int argc, char *argv[]) 971 804 { 972 int rc;973 974 805 /* Start the module */ 975 rc = tl_module_start_standalone(tl_client_connection); 976 return rc; 806 return tl_module_start(SERVICE_ICMP); 977 807 } 978 808 979 809 /** @} 980 810 */ 981
Note:
See TracChangeset
for help on using the changeset viewer.