Changeset edc5a985 in mainline
- Timestamp:
- 2010-10-31T19:19:19Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- ba1a2fd
- Parents:
- 940bb45
- Location:
- uspace/srv/net/tl/icmp
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/tl/icmp/icmp.c
r940bb45 redc5a985 28 28 29 29 /** @addtogroup icmp 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * ICMP module implementation. 35 * @see icmp.h 36 */ 34 * ICMP module implementation. 35 * @see icmp.h 36 */ 37 38 #include "icmp.h" 39 #include "icmp_module.h" 37 40 38 41 #include <async.h> … … 56 59 #include <net/ip_protocols.h> 57 60 #include <net/inet.h> 58 59 61 #include <net/modules.h> 62 #include <net/icmp_api.h> 63 #include <net/icmp_codes.h> 64 #include <net/icmp_common.h> 65 60 66 #include <packet_client.h> 61 67 #include <packet_remote.h> 62 68 #include <net_checksum.h> 63 #include <net/icmp_api.h>64 69 #include <icmp_client.h> 65 #include <net/icmp_codes.h>66 #include <net/icmp_common.h>67 70 #include <icmp_interface.h> 68 71 #include <il_interface.h> … … 74 77 #include <icmp_header.h> 75 78 76 #include "icmp.h" 77 #include "icmp_module.h" 78 79 /** ICMP module name. 80 */ 79 /** ICMP module name. */ 81 80 #define NAME "ICMP protocol" 82 81 83 /** Default ICMP error reporting. 84 */ 82 /** Default ICMP error reporting. */ 85 83 #define NET_DEFAULT_ICMP_ERROR_REPORTING true 86 84 87 /** Default ICMP echo replying. 88 */ 85 /** Default ICMP echo replying. */ 89 86 #define NET_DEFAULT_ICMP_ECHO_REPLYING true 90 87 91 /** Original datagram length in bytes transfered to the error notification message. 88 /** Original datagram length in bytes transfered to the error notification 89 * message. 92 90 */ 93 91 #define ICMP_KEEP_LENGTH 8 94 92 95 /** Free identifier numbers pool start. 96 */ 93 /** Free identifier numbers pool start. */ 97 94 #define ICMP_FREE_IDS_START 1 98 95 99 /** Free identifier numbers pool end. 100 */ 96 /** Free identifier numbers pool end. */ 101 97 #define ICMP_FREE_IDS_END UINT16_MAX 102 98 103 99 /** Computes the ICMP datagram checksum. 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." 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." 113 110 114 111 /** Computes an ICMP reply data key. 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); 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. */ 122 icmp_globals_t icmp_globals; 123 124 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t); 125 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t); 171 126 172 127 /** 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); 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 } 178 220 179 221 /** 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 */ 249 icmp_globals_t icmp_globals; 250 251 INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t); 252 253 INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t); 254 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){ 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 { 277 251 ERROR_DECLARE; 278 252 … … 280 254 packet_t packet; 281 255 size_t length; 282 uint8_t * 256 uint8_t *data; 283 257 icmp_reply_ref reply; 284 258 int reply_key; … … 286 260 int index; 287 261 288 if (addrlen <= 0){262 if (addrlen <= 0) 289 263 return EINVAL; 290 } 264 291 265 length = (size_t) addrlen; 292 266 // TODO do not ask all the time 293 ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension)); 294 packet = packet_get_4_remote(icmp_globals.net_phone, size, icmp_globals.packet_dimension.addr_len, ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix, icmp_globals.packet_dimension.suffix); 295 if(! packet){ 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) 296 275 return ENOMEM; 297 }298 276 299 277 // prepare the requesting packet 300 278 // set the destination address 301 if(ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, length))){ 279 if (ERROR_OCCURRED(packet_set_addr(packet, NULL, (const uint8_t *) addr, 280 length))) { 302 281 return icmp_release_and_return(packet, ERROR_CODE); 303 282 } 283 304 284 // allocate space in the packet 305 285 data = (uint8_t *) packet_suffix(packet, size); 306 if (! data){286 if (!data) 307 287 return icmp_release_and_return(packet, ENOMEM); 308 } 288 309 289 // fill the data 310 290 length = 0; 311 while (size > length + sizeof(ICMP_ECHO_TEXT)){291 while (size > length + sizeof(ICMP_ECHO_TEXT)) { 312 292 memcpy(data + length, ICMP_ECHO_TEXT, sizeof(ICMP_ECHO_TEXT)); 313 293 length += sizeof(ICMP_ECHO_TEXT); 314 294 } 315 295 memcpy(data + length, ICMP_ECHO_TEXT, size - length); 296 316 297 // prefix the header 317 298 header = PACKET_PREFIX(packet, icmp_header_t); 318 if (! header){299 if (!header) 319 300 return icmp_release_and_return(packet, ENOMEM); 320 } 301 321 302 bzero(header, sizeof(*header)); 322 303 header->un.echo.identifier = id; … … 325 306 // prepare the reply structure 326 307 reply = malloc(sizeof(*reply)); 327 if (! reply){308 if (!reply) 328 309 return icmp_release_and_return(packet, ENOMEM); 329 } 310 330 311 fibril_mutex_initialize(&reply->mutex); 331 312 fibril_mutex_lock(&reply->mutex); 332 313 fibril_condvar_initialize(&reply->condvar); 333 reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, header->un.echo.sequence_number); 314 reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier, 315 header->un.echo.sequence_number); 334 316 index = icmp_replies_add(&icmp_globals.replies, reply_key, reply); 335 if (index < 0){317 if (index < 0) { 336 318 free(reply); 337 319 return icmp_release_and_return(packet, index); … … 342 324 343 325 // send the request 344 icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, dont_fragment); 326 icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos, 327 dont_fragment); 345 328 346 329 // wait for the reply 347 330 // timeout in microseconds 348 if(ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex, timeout * 1000))){ 331 if (ERROR_OCCURRED(fibril_condvar_wait_timeout(&reply->condvar, 332 &reply->mutex, timeout * 1000))) { 349 333 result = ERROR_CODE; 350 } else{334 } else { 351 335 // read the result 352 336 result = reply->result; … … 359 343 // destroy the reply structure 360 344 icmp_replies_exclude_index(&icmp_globals.replies, index); 345 361 346 return result; 362 347 } 363 348 364 int icmp_destination_unreachable_msg(int icmp_phone, icmp_code_t code, icmp_param_t mtu, packet_t packet){ 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 { 365 353 icmp_header_ref header; 366 354 367 355 header = icmp_prepare_packet(packet); 368 if (! header){356 if (!header) 369 357 return icmp_release_and_return(packet, ENOMEM); 370 } 371 if (mtu){358 359 if (mtu) 372 360 header->un.frag.mtu = mtu; 373 } 374 return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header, SERVICE_ICMP, 0, 0, 0); 375 } 376 377 int icmp_source_quench_msg(int icmp_phone, packet_t packet){ 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 { 378 368 icmp_header_ref header; 379 369 380 370 header = icmp_prepare_packet(packet); 381 if (! header){371 if (!header) 382 372 return icmp_release_and_return(packet, ENOMEM); 383 } 384 return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header, SERVICE_ICMP, 0, 0, 0); 385 } 386 387 int icmp_time_exceeded_msg(int icmp_phone, icmp_code_t code, packet_t packet){ 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 { 388 381 icmp_header_ref header; 389 382 390 383 header = icmp_prepare_packet(packet); 391 if (! header){384 if (!header) 392 385 return icmp_release_and_return(packet, ENOMEM); 393 } 394 return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header, SERVICE_ICMP, 0, 0, 0); 395 } 396 397 int icmp_parameter_problem_msg(int icmp_phone, icmp_code_t code, icmp_param_t pointer, packet_t packet){ 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 { 398 395 icmp_header_ref header; 399 396 400 397 header = icmp_prepare_packet(packet); 401 if (! header){398 if (!header) 402 399 return icmp_release_and_return(packet, ENOMEM); 403 } 400 404 401 header->un.param.pointer = pointer; 405 return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header, SERVICE_ICMP, 0, 0, 0); 406 } 407 408 icmp_header_ref icmp_prepare_packet(packet_t packet){ 409 icmp_header_ref header; 410 size_t header_length; 411 size_t total_length; 412 413 total_length = packet_get_data_length(packet); 414 if(total_length <= 0){ 415 return NULL; 416 } 417 header_length = ip_client_header_length(packet); 418 if(header_length <= 0){ 419 return NULL; 420 } 421 // truncate if longer than 64 bits (without the IP header) 422 if((total_length > header_length + ICMP_KEEP_LENGTH) 423 && (packet_trim(packet, 0, total_length - header_length - ICMP_KEEP_LENGTH) != EOK)){ 424 return NULL; 425 } 426 header = PACKET_PREFIX(packet, icmp_header_t); 427 if(! header){ 428 return NULL; 429 } 430 bzero(header, sizeof(*header)); 431 return header; 432 } 433 434 int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t packet, icmp_header_ref header, services_t error, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment){ 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 { 435 415 ERROR_DECLARE; 436 416 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}}; 417 measured_string_t names[] = { 418 { 419 str_dup("ICMP_ERROR_REPORTING"), 420 20 421 }, 422 { 423 str_dup("ICMP_ECHO_REPLYING"), 424 18 425 } 426 }; 455 427 measured_string_ref configuration; 456 428 size_t count = sizeof(names) / sizeof(measured_string_t); 457 char * 429 char *data; 458 430 459 431 fibril_rwlock_initialize(&icmp_globals.lock); … … 461 433 icmp_replies_initialize(&icmp_globals.replies); 462 434 icmp_echo_data_initialize(&icmp_globals.echo_data); 463 icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP, client_connection); 464 if(icmp_globals.ip_phone < 0){ 435 icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, 436 SERVICE_ICMP, client_connection); 437 if (icmp_globals.ip_phone < 0) 465 438 return icmp_globals.ip_phone; 466 } 467 ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, &icmp_globals.packet_dimension)); 439 440 ERROR_PROPAGATE(ip_packet_size_req(icmp_globals.ip_phone, -1, 441 &icmp_globals.packet_dimension)); 468 442 icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE; 469 443 icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE; 470 // get configuration 444 471 445 icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING; 472 446 icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING; 447 448 // get configuration 473 449 configuration = &names[0]; 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'); 478 } 479 if(configuration[1].value){ 480 icmp_globals.echo_replying = (configuration[1].value[0] == 'y'); 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'); 456 } 457 if (configuration[1].value) { 458 icmp_globals.echo_replying = 459 (configuration[1].value[0] == 'y'); 481 460 } 482 461 net_free_settings(configuration, data); 483 462 } 463 484 464 fibril_rwlock_write_unlock(&icmp_globals.lock); 485 465 return EOK; 486 466 } 487 467 488 int icmp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){ 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 { 489 521 ERROR_DECLARE; 490 522 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 501 523 size_t length; 502 uint8_t * 524 uint8_t *src; 503 525 int addrlen; 504 526 int result; 505 void * 527 void *data; 506 528 icmp_header_ref header; 507 529 icmp_type_t type; 508 530 icmp_code_t code; 509 531 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 } 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 526 549 // get rid of the ip header 527 550 length = ip_client_header_length(packet); … … 529 552 530 553 length = packet_get_data_length(packet); 531 if (length <= 0){554 if (length <= 0) 532 555 return EINVAL; 533 } 534 if (length < ICMP_HEADER_SIZE){556 557 if (length < ICMP_HEADER_SIZE) 535 558 return EINVAL; 536 } 559 537 560 data = packet_get_data(packet); 538 if (! data){561 if (!data) 539 562 return EINVAL; 540 } 563 541 564 // get icmp header 542 565 header = (icmp_header_ref) data; 543 // checksum 544 if (header->checksum){545 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO){566 567 if (header->checksum) { 568 while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) { 546 569 // set the original message type on error notification 547 570 // type swap observed in Qemu 548 if (error){549 switch (header->type){550 551 552 571 if (error) { 572 switch (header->type) { 573 case ICMP_ECHOREPLY: 574 header->type = ICMP_ECHO; 575 continue; 553 576 } 554 577 } … … 556 579 } 557 580 } 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); 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); 594 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; 564 610 } 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; 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 { 656 ERROR_DECLARE; 657 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 the 672 * icmp_destination_unreachable_msg_local() function. 673 * @returns Other error codes as defined for the 674 * icmp_source_quench_msg_local() function. 675 * @returns Other error codes as defined for the 676 * icmp_time_exceeded_msg_local() function. 677 * @returns Other error codes as defined for the 678 * icmp_parameter_problem_msg_local() function. 679 * 680 * @see icmp_interface.h 681 */ 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 one 739 index = icmp_globals.last_used_id; 740 do { 741 index++; 742 // til the range end 743 if (index >= ICMP_FREE_IDS_END) { 744 // start from the range beginning 745 index = ICMP_FREE_IDS_START - 1; 746 do { 747 index++; 748 // til the last used one 749 if (index >= icmp_globals.last_used_id) { 750 // none found 751 return ENOTCONN; 579 752 } 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); 596 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){ 753 } while(icmp_echo_data_find(&icmp_globals.echo_data, 754 index) != NULL); 755 756 // found, break immediately 757 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.h 777 * @see icmp_api.h 778 */ 779 static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call) 780 { 624 781 ERROR_DECLARE; 625 782 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));633 }634 return ERROR_CODE;635 case NET_ICMP_INIT:636 return icmp_process_client_messages(callid, * call);637 default:638 return icmp_process_message(call);639 }640 return ENOTSUP;641 }642 643 int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call){644 ERROR_DECLARE;645 646 783 bool keep_on_going = true; 647 // fibril_rwlock_t lock;648 784 ipc_call_t answer; 649 785 int answer_count; 650 786 size_t length; 651 struct sockaddr * 787 struct sockaddr *addr; 652 788 ipc_callid_t data_callid; 653 789 icmp_echo_ref echo_data; … … 661 797 answer_count = 0; 662 798 663 // fibril_rwlock_initialize(&lock);664 665 799 echo_data = (icmp_echo_ref) malloc(sizeof(*echo_data)); 666 if (! echo_data){800 if (!echo_data) 667 801 return ENOMEM; 668 }669 802 670 803 // assign a new identifier … … 672 805 res = icmp_bind_free_id(echo_data); 673 806 fibril_rwlock_write_unlock(&icmp_globals.lock); 674 if (res < 0){807 if (res < 0) { 675 808 free(echo_data); 676 809 return res; 677 810 } 678 811 679 while(keep_on_going){ 680 812 while (keep_on_going) { 681 813 // answer the call 682 814 answer_call(callid, res, &answer, answer_count); … … 689 821 690 822 // process the call 691 switch(IPC_GET_METHOD(call)){ 692 case IPC_M_PHONE_HUNGUP: 693 keep_on_going = false; 694 res = EHANGUP; 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; 695 832 break; 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); 833 } 834 835 addr = malloc(length); 836 if (!addr) { 837 res = ENOMEM; 721 838 break; 722 default: 723 res = icmp_process_message(&call); 724 } 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); 867 } 868 725 869 } 726 870 … … 729 873 icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier); 730 874 fibril_rwlock_write_unlock(&icmp_globals.lock); 875 731 876 return res; 732 877 } 733 878 734 int icmp_process_message(ipc_call_t * call){ 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 { 735 896 ERROR_DECLARE; 736 897 737 898 packet_t packet; 738 899 739 switch(IPC_GET_METHOD(*call)){ 740 case NET_ICMP_DEST_UNREACH: 741 if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){ 742 ERROR_CODE = icmp_destination_unreachable_msg(0, ICMP_GET_CODE(call), ICMP_GET_MTU(call), packet); 743 } 744 return ERROR_CODE; 745 case NET_ICMP_SOURCE_QUENCH: 746 if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){ 747 ERROR_CODE = icmp_source_quench_msg(0, packet); 748 } 749 return ERROR_CODE; 750 case NET_ICMP_TIME_EXCEEDED: 751 if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){ 752 ERROR_CODE = icmp_time_exceeded_msg(0, ICMP_GET_CODE(call), packet); 753 } 754 return ERROR_CODE; 755 case NET_ICMP_PARAMETERPROB: 756 if(! ERROR_OCCURRED(packet_translate_remote(icmp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){ 757 ERROR_CODE = icmp_parameter_problem_msg(0, ICMP_GET_CODE(call), ICMP_GET_POINTER(call), packet); 758 } 759 return ERROR_CODE; 760 default: 761 return ENOTSUP; 762 } 763 } 764 765 int icmp_release_and_return(packet_t packet, int result){ 766 pq_release_remote(icmp_globals.net_phone, packet_get_id(packet)); 767 return result; 768 } 769 770 int icmp_bind_free_id(icmp_echo_ref echo_data){ 771 icmp_param_t index; 772 773 if(! echo_data){ 774 return EBADMEM; 775 } 776 // from the last used one 777 index = icmp_globals.last_used_id; 778 do{ 779 ++ index; 780 // til the range end 781 if(index >= ICMP_FREE_IDS_END){ 782 // start from the range beginning 783 index = ICMP_FREE_IDS_START - 1; 784 do{ 785 ++ index; 786 // til the last used one 787 if(index >= icmp_globals.last_used_id){ 788 // none found 789 return ENOTCONN; 790 } 791 }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL); 792 // found, break immediately 793 break; 794 } 795 }while(icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL); 796 echo_data->identifier = index; 797 echo_data->sequence_number = 0; 798 return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data); 799 } 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)); 908 } 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 800 921 801 922 /** Default thread for new connections. 802 923 * 803 * 804 * 805 * 806 */ 807 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * 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) 808 929 { 809 930 /* … … 813 934 ipc_answer_0(iid, EOK); 814 935 815 while (true) {936 while (true) { 816 937 ipc_call_t answer; 817 938 int answer_count; … … 828 949 &answer_count); 829 950 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)) 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)) 832 957 return; 833 958 … … 839 964 /** Starts the module. 840 965 * 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 * 966 * @returns EOK on success. 967 * @returns Other error codes as defined for each specific module 968 * start function. 847 969 */ 848 970 int main(int argc, char *argv[]) … … 851 973 852 974 /* Start the module */ 853 if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection))) 854 return ERROR_CODE; 855 975 ERROR_PROPAGATE(tl_module_start_standalone(tl_client_connection)); 856 976 return EOK; 857 977 } … … 859 979 /** @} 860 980 */ 981 -
uspace/srv/net/tl/icmp/icmp.h
r940bb45 redc5a985 28 28 29 29 /** @addtogroup icmp 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * 34 * ICMP module. 35 35 */ 36 36 37 #ifndef __NET_ICMP_H__38 #define __NET_ICMP_H__37 #ifndef NET_ICMP_H_ 38 #define NET_ICMP_H_ 39 39 40 40 #include <fibril_synch.h> 41 41 42 42 #include <net/icmp_codes.h> 43 #include <net/packet.h> 43 44 #include <adt/int_map.h> 44 45 #include <icmp_header.h> 45 46 46 47 /** Type definition of the ICMP reply data. 47 * 48 * @see icmp_reply 48 49 */ 49 typedef struct icmp_reply 50 typedef struct icmp_reply icmp_reply_t; 50 51 51 52 /** Type definition of the ICMP reply data pointer. 52 * 53 * @see icmp_reply 53 54 */ 54 typedef icmp_reply_t * 55 typedef icmp_reply_t *icmp_reply_ref; 55 56 56 57 /** Type definition of the ICMP global data. 57 * 58 * @see icmp_globals 58 59 */ 59 typedef struct icmp_globals 60 typedef struct icmp_globals icmp_globals_t; 60 61 61 62 /** Pending replies map. 62 * Maps message identifiers to the pending replies. 63 * Sending fibril waits for its associated reply event. 64 * Receiving fibril sets the associated reply with the return value and signals the event. 63 * 64 * Maps message identifiers to the pending replies. 65 * Sending fibril waits for its associated reply event. 66 * Receiving fibril sets the associated reply with the return value and signals 67 * the event. 65 68 */ 66 69 INT_MAP_DECLARE(icmp_replies, icmp_reply_t); 67 70 68 71 /** Echo specific data map. 69 * The identifier is used in the future semi-remote calls instead of the ICMP phone. 72 * 73 * The identifier is used in the future semi-remote calls instead of the ICMP 74 * phone. 70 75 */ 71 76 INT_MAP_DECLARE(icmp_echo_data, icmp_echo_t); 72 77 73 /** ICMP reply data. 74 */ 75 struct icmp_reply{ 76 /** Reply result. 77 */ 78 /** ICMP reply data. */ 79 struct icmp_reply { 80 /** Reply result. */ 78 81 int result; 79 /** Safety lock. 80 */ 82 /** Safety lock. */ 81 83 fibril_mutex_t mutex; 82 /** Received or timeouted reply signaling. 83 */ 84 /** Received or timeouted reply signaling. */ 84 85 fibril_condvar_t condvar; 85 86 }; 86 87 87 /** ICMP global data. 88 */ 89 struct icmp_globals{ 90 /** IP module phone. 91 */ 88 /** ICMP global data. */ 89 struct icmp_globals { 90 /** IP module phone. */ 92 91 int ip_phone; 93 /** Packet dimension. 94 */ 92 /** Packet dimension. */ 95 93 packet_dimension_t packet_dimension; 96 /** Networking module phone. 97 */ 94 /** Networking module phone. */ 98 95 int net_phone; 99 /** Indicates whether ICMP error reporting is enabled. 100 */ 96 /** Indicates whether ICMP error reporting is enabled. */ 101 97 int error_reporting; 102 /** Indicates whether ICMP echo replying (ping) is enabled. 103 */ 98 /** Indicates whether ICMP echo replying (ping) is enabled. */ 104 99 int echo_replying; 105 /** The last used identifier number. 106 */ 100 /** The last used identifier number. */ 107 101 icmp_param_t last_used_id; 108 /** The budled modules assigned echo specific data. 109 */ 102 /** The budled modules assigned echo specific data. */ 110 103 icmp_echo_data_t echo_data; 111 /** Echo timeout locks. 112 */ 104 /** Echo timeout locks. */ 113 105 icmp_replies_t replies; 114 /** Safety lock. 115 */ 106 /** Safety lock. */ 116 107 fibril_rwlock_t lock; 117 108 }; … … 121 112 /** @} 122 113 */ 123 -
uspace/srv/net/tl/icmp/icmp_module.c
r940bb45 redc5a985 28 28 29 29 /** @addtogroup icmp 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * 35 * 36 * 37 * 34 * ICMP standalone module implementation. 35 * Contains skeleton module functions mapping. 36 * The functions are used by the module skeleton as module specific entry points. 37 * @see module.c 38 38 */ 39 40 #include "icmp.h" 41 #include "icmp_module.h" 39 42 40 43 #include <async.h> … … 47 50 #include <net/packet.h> 48 51 #include <net_interface.h> 52 49 53 #include <tl_local.h> 50 54 51 #include "icmp.h" 52 #include "icmp_module.h" 55 /** ICMP module global data. */ 56 extern icmp_globals_t icmp_globals; 53 57 54 /** ICMP module global data. 55 */ 56 extern icmp_globals_t icmp_globals; 57 58 /** Starts the ICMP module. 59 * Initializes the client connection serving function, initializes the module, registers the module service and starts the async manager, processing IPC messages in an infinite loop. 60 * @param[in] client_connection The client connection processing function. The module skeleton propagates its own one. 61 * @returns EOK on successful module termination. 62 * @returns Other error codes as defined for the arp_initialize() function. 63 * @returns Other error codes as defined for the REGISTER_ME() macro function. 64 */ 65 int tl_module_start_standalone(async_client_conn_t client_connection){ 58 int tl_module_start_standalone(async_client_conn_t client_connection) 59 { 66 60 ERROR_DECLARE; 67 61 … … 70 64 async_set_client_connection(client_connection); 71 65 icmp_globals.net_phone = net_connect_module(); 72 if (icmp_globals.net_phone < 0){66 if (icmp_globals.net_phone < 0) 73 67 return icmp_globals.net_phone; 74 } 68 75 69 ERROR_PROPAGATE(pm_init()); 76 if (ERROR_OCCURRED(icmp_initialize(client_connection))77 || ERROR_OCCURRED(REGISTER_ME(SERVICE_ICMP, &phonehash))){70 if (ERROR_OCCURRED(icmp_initialize(client_connection)) || 71 ERROR_OCCURRED(REGISTER_ME(SERVICE_ICMP, &phonehash))) { 78 72 pm_destroy(); 79 73 return ERROR_CODE; … … 86 80 } 87 81 88 /** Processes the ICMP message. 89 * @param[in] callid The message identifier. 90 * @param[in] call The message parameters. 91 * @param[out] answer The message answer parameters. 92 * @param[out] answer_count The last parameter for the actual answer in the answer parameter. 93 * @returns EOK on success. 94 * @returns Other error codes as defined for the icmp_message() function. 95 */ 96 int tl_module_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){ 82 int 83 tl_module_message_standalone(ipc_callid_t callid, ipc_call_t *call, 84 ipc_call_t *answer, int *answer_count) 85 { 97 86 return icmp_message_standalone(callid, call, answer, answer_count); 98 87 } … … 100 89 /** @} 101 90 */ 91 -
uspace/srv/net/tl/icmp/icmp_module.h
r940bb45 redc5a985 28 28 29 29 /** @addtogroup icmp 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * 35 * 34 * ICMP module functions. 35 * The functions are used as ICMP module entry points. 36 36 */ 37 37 38 #ifndef __NET_ICMP_MODULE_H__39 #define __NET_ICMP_MODULE_H__38 #ifndef NET_ICMP_MODULE_H_ 39 #define NET_ICMP_MODULE_H_ 40 40 41 41 #include <async.h> 42 42 #include <ipc/ipc.h> 43 43 44 /** Initializes the ICMP module. 45 * @param[in] client_connection The client connection processing function. The module skeleton propagates its own one. 46 * @returns EOK on success. 47 * @returns ENOMEM if there is not enough memory left. 48 */ 49 int icmp_initialize(async_client_conn_t client_connection); 50 51 /** Processes the ICMP message. 52 * @param[in] callid The message identifier. 53 * @param[in] call The message parameters. 54 * @param[out] answer The message answer parameters. 55 * @param[out] answer_count The last parameter for the actual answer in the answer parameter. 56 * @returns EOK on success. 57 * @returns ENOTSUP if the message is not known. 58 * @see icmp_interface.h 59 * @see IS_NET_ICMP_MESSAGE() 60 */ 61 int icmp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count); 44 extern int icmp_initialize(async_client_conn_t); 45 extern int icmp_message_standalone(ipc_callid_t, ipc_call_t *, ipc_call_t *, 46 int *); 62 47 63 48 #endif
Note:
See TracChangeset
for help on using the changeset viewer.