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