source: mainline/uspace/srv/net/il/ip/ip.c@ d8b275d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d8b275d was ccca251, checked in by Martin Decky <martin@…>, 14 years ago

improve comments, use C++ style comments for TODOs and FIXMEs

  • Property mode set to 100644
File size: 54.0 KB
RevLine 
[21580dd]1/*
2 * Copyright (c) 2009 Lukas Mejdrech
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ip
[e8199d77]30 * @{
[21580dd]31 */
32
33/** @file
[e8199d77]34 * IP module implementation.
35 * @see arp.h
[21580dd]36 */
37
38#include <async.h>
39#include <errno.h>
40#include <fibril_synch.h>
41#include <stdio.h>
[19f857a]42#include <str.h>
[21580dd]43#include <ipc/services.h>
[514ee46]44#include <ipc/net.h>
[f5a3479]45#include <ipc/nil.h>
[522253c1]46#include <ipc/il.h>
[779a47d]47#include <ipc/ip.h>
[21580dd]48#include <sys/types.h>
[2687bdb]49#include <byteorder.h>
[797b704]50#include "ip.h"
[21580dd]51
[e8199d77]52#include <adt/measured_strings.h>
53#include <adt/module_map.h>
54
55#include <packet_client.h>
[058edb6]56#include <net/socket_codes.h>
[e4554d4]57#include <net/in.h>
58#include <net/in6.h>
59#include <net/inet.h>
[c7a8442]60#include <net/modules.h>
[514ee46]61#include <net/device.h>
62#include <net/packet.h>
63#include <net/icmp_codes.h>
[058edb6]64
[849ed54]65#include <arp_interface.h>
66#include <net_checksum.h>
67#include <icmp_client.h>
[f1938c6]68#include <icmp_remote.h>
[849ed54]69#include <ip_client.h>
70#include <ip_interface.h>
[4a3b501]71#include <ip_header.h>
[849ed54]72#include <net_interface.h>
[fe8dfa6]73#include <nil_remote.h>
[014dd57b]74#include <tl_remote.h>
[14f1db0]75#include <packet_remote.h>
[797b704]76#include <il_remote.h>
77#include <il_skel.h>
[21580dd]78
[e8199d77]79/** IP module name. */
80#define NAME "ip"
[849ed54]81
[e8199d77]82/** IP version 4. */
83#define IPV4 4
[21580dd]84
[e8199d77]85/** Default network interface IP version. */
[21580dd]86#define NET_DEFAULT_IPV IPV4
87
[e8199d77]88/** Default network interface IP routing. */
[21580dd]89#define NET_DEFAULT_IP_ROUTING false
90
[e8199d77]91/** Minimum IP packet content. */
92#define IP_MIN_CONTENT 576
[21580dd]93
[e8199d77]94/** ARP module name. */
95#define ARP_NAME "arp"
[21580dd]96
[e8199d77]97/** ARP module filename. */
98#define ARP_FILENAME "/srv/arp"
[21580dd]99
[e8199d77]100/** IP packet address length. */
101#define IP_ADDR sizeof(struct sockaddr_in6)
[21580dd]102
[e8199d77]103/** IP packet prefix length. */
104#define IP_PREFIX sizeof(ip_header_t)
[21580dd]105
[e8199d77]106/** IP packet suffix length. */
107#define IP_SUFFIX 0
[21580dd]108
[e8199d77]109/** IP packet maximum content length. */
110#define IP_MAX_CONTENT 65535
[21580dd]111
[e8199d77]112/** The IP localhost address. */
[aadf01e]113#define IPV4_LOCALHOST_ADDRESS htonl((127 << 24) + 1)
[21580dd]114
[e8199d77]115/** IP global data. */
116ip_globals_t ip_globals;
[21580dd]117
[e8199d77]118DEVICE_MAP_IMPLEMENT(ip_netifs, ip_netif_t);
119INT_MAP_IMPLEMENT(ip_protos, ip_proto_t);
120GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t);
[21580dd]121
[797b704]122static void ip_receiver(ipc_callid_t, ipc_call_t *);
123
[e8199d77]124/** Releases the packet and returns the result.
125 *
126 * @param[in] packet The packet queue to be released.
127 * @param[in] result The result to be returned.
128 * @return The result parameter.
[21580dd]129 */
[46d4d9f]130static int ip_release_and_return(packet_t *packet, int result)
[e8199d77]131{
132 pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
133 return result;
134}
[21580dd]135
[e8199d77]136/** Returns the ICMP phone.
137 *
138 * Searches the registered protocols.
139 *
[1bfd3d3]140 * @return The found ICMP phone.
141 * @return ENOENT if the ICMP is not registered.
[21580dd]142 */
[e8199d77]143static int ip_get_icmp_phone(void)
144{
[4e5c7ba]145 ip_proto_t *proto;
[e8199d77]146 int phone;
[21580dd]147
[e8199d77]148 fibril_rwlock_read_lock(&ip_globals.protos_lock);
149 proto = ip_protos_find(&ip_globals.protos, IPPROTO_ICMP);
150 phone = proto ? proto->phone : ENOENT;
151 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
152 return phone;
153}
[21580dd]154
[e8199d77]155/** Prepares the ICMP notification packet.
156 *
157 * Releases additional packets and keeps only the first one.
158 *
159 * @param[in] packet The packet or the packet queue to be reported as faulty.
160 * @param[in] header The first packet IP header. May be NULL.
[1bfd3d3]161 * @return EOK on success.
162 * @return EINVAL if there are no data in the packet.
163 * @return EINVAL if the packet is a fragment.
164 * @return ENOMEM if the packet is too short to contain the IP
[e8199d77]165 * header.
[1bfd3d3]166 * @return EAFNOSUPPORT if the address family is not supported.
167 * @return EPERM if the protocol is not allowed to send ICMP
[e8199d77]168 * notifications. The ICMP protocol itself.
[1bfd3d3]169 * @return Other error codes as defined for the packet_set_addr().
[21580dd]170 */
[46d4d9f]171static int ip_prepare_icmp(packet_t *packet, ip_header_t *header)
[e8199d77]172{
[46d4d9f]173 packet_t *next;
[e8199d77]174 struct sockaddr *dest;
175 struct sockaddr_in dest_in;
176 socklen_t addrlen;
[21580dd]177
[28a3e74]178 /* Detach the first packet and release the others */
[e8199d77]179 next = pq_detach(packet);
180 if (next)
181 pq_release_remote(ip_globals.net_phone, packet_get_id(next));
[21580dd]182
[e8199d77]183 if (!header) {
184 if (packet_get_data_length(packet) <= sizeof(ip_header_t))
185 return ENOMEM;
[21580dd]186
[28a3e74]187 /* Get header */
[88a1bb9]188 header = (ip_header_t *) packet_get_data(packet);
[e8199d77]189 if (!header)
190 return EINVAL;
[21580dd]191
[e8199d77]192 }
[21580dd]193
[28a3e74]194 /* Only for the first fragment */
[e8199d77]195 if (IP_FRAGMENT_OFFSET(header))
196 return EINVAL;
[21580dd]197
[28a3e74]198 /* Not for the ICMP protocol */
[e8199d77]199 if (header->protocol == IPPROTO_ICMP)
200 return EPERM;
[21580dd]201
[28a3e74]202 /* Set the destination address */
[e8199d77]203 switch (header->version) {
204 case IPVERSION:
205 addrlen = sizeof(dest_in);
206 bzero(&dest_in, addrlen);
207 dest_in.sin_family = AF_INET;
208 memcpy(&dest_in.sin_addr.s_addr, &header->source_address,
209 sizeof(header->source_address));
210 dest = (struct sockaddr *) &dest_in;
211 break;
[21580dd]212
[e8199d77]213 default:
214 return EAFNOSUPPORT;
215 }
[21580dd]216
[e8199d77]217 return packet_set_addr(packet, NULL, (uint8_t *) dest, addrlen);
218}
[21580dd]219
220/** Prepares the ICMP notification packet.
[e8199d77]221 *
222 * Releases additional packets and keeps only the first one.
223 * All packets are released on error.
224 *
225 * @param[in] error The packet error service.
226 * @param[in] packet The packet or the packet queue to be reported as faulty.
227 * @param[in] header The first packet IP header. May be NULL.
[1bfd3d3]228 * @return The found ICMP phone.
229 * @return EINVAL if the error parameter is set.
230 * @return EINVAL if the ICMP phone is not found.
231 * @return EINVAL if the ip_prepare_icmp() fails.
[21580dd]232 */
[e8199d77]233static int
[46d4d9f]234ip_prepare_icmp_and_get_phone(services_t error, packet_t *packet,
[88a1bb9]235 ip_header_t *header)
[e8199d77]236{
237 int phone;
[21580dd]238
[e8199d77]239 phone = ip_get_icmp_phone();
240 if (error || (phone < 0) || ip_prepare_icmp(packet, header))
241 return ip_release_and_return(packet, EINVAL);
242 return phone;
243}
[21580dd]244
[797b704]245int il_initialize(int net_phone)
[e8199d77]246{
[aadf01e]247 fibril_rwlock_initialize(&ip_globals.lock);
248 fibril_rwlock_write_lock(&ip_globals.lock);
249 fibril_rwlock_initialize(&ip_globals.protos_lock);
250 fibril_rwlock_initialize(&ip_globals.netifs_lock);
[797b704]251
252 ip_globals.net_phone = net_phone;
[21580dd]253 ip_globals.packet_counter = 0;
254 ip_globals.gateway.address.s_addr = 0;
255 ip_globals.gateway.netmask.s_addr = 0;
256 ip_globals.gateway.gateway.s_addr = 0;
257 ip_globals.gateway.netif = NULL;
[02314f8]258
[797b704]259 int rc = ip_netifs_initialize(&ip_globals.netifs);
[02314f8]260 if (rc != EOK)
261 goto out;
262 rc = ip_protos_initialize(&ip_globals.protos);
263 if (rc != EOK)
264 goto out;
265 rc = modules_initialize(&ip_globals.modules);
266 if (rc != EOK)
267 goto out;
[61bfc370]268 rc = add_module(NULL, &ip_globals.modules, (uint8_t *) ARP_NAME,
269 (uint8_t *) ARP_FILENAME, SERVICE_ARP, 0, arp_connect_module);
[02314f8]270
271out:
[aadf01e]272 fibril_rwlock_write_unlock(&ip_globals.lock);
[21580dd]273
[02314f8]274 return rc;
[21580dd]275}
276
[e8199d77]277/** Initializes a new network interface specific data.
278 *
279 * Connects to the network interface layer module, reads the netif
280 * configuration, starts an ARP module if needed and sets the netif routing
281 * table.
282 *
283 * The device identifier and the nil service has to be set.
284 *
285 * @param[in,out] ip_netif Network interface specific data.
[1bfd3d3]286 * @return EOK on success.
287 * @return ENOTSUP if DHCP is configured.
288 * @return ENOTSUP if IPv6 is configured.
289 * @return EINVAL if any of the addresses is invalid.
290 * @return EINVAL if the used ARP module is not known.
291 * @return ENOMEM if there is not enough memory left.
292 * @return Other error codes as defined for the
[e8199d77]293 * net_get_device_conf_req() function.
[1bfd3d3]294 * @return Other error codes as defined for the bind_service()
[e8199d77]295 * function.
[1bfd3d3]296 * @return Other error codes as defined for the specific
[e8199d77]297 * arp_device_req() function.
[1bfd3d3]298 * @return Other error codes as defined for the
[e8199d77]299 * nil_packet_size_req() function.
300 */
[4e5c7ba]301static int ip_netif_initialize(ip_netif_t *ip_netif)
[e8199d77]302{
303 measured_string_t names[] = {
304 {
[61bfc370]305 (uint8_t *) "IPV",
[e8199d77]306 3
307 },
308 {
[61bfc370]309 (uint8_t *) "IP_CONFIG",
[e8199d77]310 9
311 },
312 {
[61bfc370]313 (uint8_t *) "IP_ADDR",
[e8199d77]314 7
315 },
316 {
[61bfc370]317 (uint8_t *) "IP_NETMASK",
[e8199d77]318 10
319 },
320 {
[61bfc370]321 (uint8_t *) "IP_GATEWAY",
[e8199d77]322 10
323 },
324 {
[61bfc370]325 (uint8_t *) "IP_BROADCAST",
[e8199d77]326 12
327 },
328 {
[61bfc370]329 (uint8_t *) "ARP",
[e8199d77]330 3
331 },
332 {
[61bfc370]333 (uint8_t *) "IP_ROUTING",
[e8199d77]334 10
335 }
336 };
[4eca056]337 measured_string_t *configuration;
[aadf01e]338 size_t count = sizeof(names) / sizeof(measured_string_t);
[61bfc370]339 uint8_t *data;
[aadf01e]340 measured_string_t address;
[4e5c7ba]341 ip_route_t *route;
[aadf01e]342 in_addr_t gateway;
[02314f8]343 int index;
344 int rc;
[21580dd]345
346 ip_netif->arp = NULL;
347 route = NULL;
348 ip_netif->ipv = NET_DEFAULT_IPV;
349 ip_netif->dhcp = false;
350 ip_netif->routing = NET_DEFAULT_IP_ROUTING;
[aadf01e]351 configuration = &names[0];
[e8199d77]352
[28a3e74]353 /* Get configuration */
[02314f8]354 rc = net_get_device_conf_req(ip_globals.net_phone, ip_netif->device_id,
355 &configuration, count, &data);
356 if (rc != EOK)
357 return rc;
358
[e8199d77]359 if (configuration) {
360 if (configuration[0].value)
[61bfc370]361 ip_netif->ipv = strtol((char *) configuration[0].value, NULL, 0);
362
363 ip_netif->dhcp = !str_lcmp((char *) configuration[1].value, "dhcp",
[e8199d77]364 configuration[1].length);
365
366 if (ip_netif->dhcp) {
[ccca251]367 // TODO dhcp
[aadf01e]368 net_free_settings(configuration, data);
[21580dd]369 return ENOTSUP;
[e8199d77]370 } else if (ip_netif->ipv == IPV4) {
[4e5c7ba]371 route = (ip_route_t *) malloc(sizeof(ip_route_t));
[e8199d77]372 if (!route) {
[aadf01e]373 net_free_settings(configuration, data);
[21580dd]374 return ENOMEM;
375 }
376 route->address.s_addr = 0;
377 route->netmask.s_addr = 0;
378 route->gateway.s_addr = 0;
379 route->netif = ip_netif;
[aadf01e]380 index = ip_routes_add(&ip_netif->routes, route);
[e8199d77]381 if (index < 0) {
[aadf01e]382 net_free_settings(configuration, data);
383 free(route);
[21580dd]384 return index;
385 }
[02314f8]386
[61bfc370]387 if ((inet_pton(AF_INET, (char *) configuration[2].value,
[02314f8]388 (uint8_t *) &route->address.s_addr) != EOK) ||
[61bfc370]389 (inet_pton(AF_INET, (char *) configuration[3].value,
[02314f8]390 (uint8_t *) &route->netmask.s_addr) != EOK) ||
[61bfc370]391 (inet_pton(AF_INET, (char *) configuration[4].value,
[e8199d77]392 (uint8_t *) &gateway.s_addr) == EINVAL) ||
[61bfc370]393 (inet_pton(AF_INET, (char *) configuration[5].value,
[e8199d77]394 (uint8_t *) &ip_netif->broadcast.s_addr) == EINVAL))
395 {
[aadf01e]396 net_free_settings(configuration, data);
[21580dd]397 return EINVAL;
398 }
[e8199d77]399 } else {
[ccca251]400 // TODO ipv6 in separate module
[aadf01e]401 net_free_settings(configuration, data);
[21580dd]402 return ENOTSUP;
403 }
[e8199d77]404
405 if (configuration[6].value) {
406 ip_netif->arp = get_running_module(&ip_globals.modules,
407 configuration[6].value);
408 if (!ip_netif->arp) {
409 printf("Failed to start the arp %s\n",
410 configuration[6].value);
[aadf01e]411 net_free_settings(configuration, data);
[21580dd]412 return EINVAL;
413 }
414 }
[e8199d77]415 if (configuration[7].value)
[aadf01e]416 ip_netif->routing = (configuration[7].value[0] == 'y');
[e8199d77]417
[aadf01e]418 net_free_settings(configuration, data);
[21580dd]419 }
[e8199d77]420
[28a3e74]421 /* Bind netif service which also initializes the device */
[e8199d77]422 ip_netif->phone = nil_bind_service(ip_netif->service,
[96b02eb9]423 (sysarg_t) ip_netif->device_id, SERVICE_IP,
[797b704]424 ip_receiver);
[e8199d77]425 if (ip_netif->phone < 0) {
426 printf("Failed to contact the nil service %d\n",
427 ip_netif->service);
[21580dd]428 return ip_netif->phone;
429 }
[e8199d77]430
[28a3e74]431 /* Has to be after the device netif module initialization */
[e8199d77]432 if (ip_netif->arp) {
433 if (route) {
[61bfc370]434 address.value = (uint8_t *) &route->address.s_addr;
[1b59023]435 address.length = sizeof(in_addr_t);
[02314f8]436
437 rc = arp_device_req(ip_netif->arp->phone,
[e8199d77]438 ip_netif->device_id, SERVICE_IP, ip_netif->service,
[02314f8]439 &address);
440 if (rc != EOK)
441 return rc;
[e8199d77]442 } else {
[21580dd]443 ip_netif->arp = 0;
444 }
445 }
[e8199d77]446
[28a3e74]447 /* Get packet dimensions */
[02314f8]448 rc = nil_packet_size_req(ip_netif->phone, ip_netif->device_id,
449 &ip_netif->packet_dimension);
450 if (rc != EOK)
451 return rc;
452
[e8199d77]453 if (ip_netif->packet_dimension.content < IP_MIN_CONTENT) {
[7e752b2]454 printf("Maximum transmission unit %zu bytes is too small, at "
[e8199d77]455 "least %d bytes are needed\n",
456 ip_netif->packet_dimension.content, IP_MIN_CONTENT);
[91478aa]457 ip_netif->packet_dimension.content = IP_MIN_CONTENT;
[21580dd]458 }
[e8199d77]459
[aadf01e]460 index = ip_netifs_add(&ip_globals.netifs, ip_netif->device_id, ip_netif);
[e8199d77]461 if (index < 0)
[aadf01e]462 return index;
[e8199d77]463
464 if (gateway.s_addr) {
[28a3e74]465 /* The default gateway */
[21580dd]466 ip_globals.gateway.address.s_addr = 0;
467 ip_globals.gateway.netmask.s_addr = 0;
468 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
469 ip_globals.gateway.netif = ip_netif;
[774e6d1a]470
471 char defgateway[INET_ADDRSTRLEN];
472 inet_ntop(AF_INET, (uint8_t *) &gateway.s_addr,
473 defgateway, INET_ADDRSTRLEN);
474 printf("%s: Default gateway (%s)\n", NAME, defgateway);
[21580dd]475 }
[e8199d77]476
[21580dd]477 return EOK;
478}
479
[797b704]480static int ip_device_req_local(int il_phone, device_id_t device_id,
481 services_t netif)
[e8199d77]482{
[797b704]483 ip_netif_t *ip_netif;
484 ip_route_t *route;
485 int index;
486 int rc;
487
488 ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
489 if (!ip_netif)
490 return ENOMEM;
491
492 rc = ip_routes_initialize(&ip_netif->routes);
493 if (rc != EOK) {
494 free(ip_netif);
495 return rc;
496 }
497
498 ip_netif->device_id = device_id;
499 ip_netif->service = netif;
500 ip_netif->state = NETIF_STOPPED;
[21580dd]501
[aadf01e]502 fibril_rwlock_write_lock(&ip_globals.netifs_lock);
[797b704]503
504 rc = ip_netif_initialize(ip_netif);
505 if (rc != EOK) {
[aadf01e]506 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
[5fe7692]507 ip_routes_destroy(&ip_netif->routes, free);
[797b704]508 free(ip_netif);
509 return rc;
[21580dd]510 }
[797b704]511 if (ip_netif->arp)
512 ip_netif->arp->usage++;
513
[28a3e74]514 /* Print the settings */
[797b704]515 printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
516 NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
517 ip_netif->dhcp ? "dhcp" : "static");
518
[ccca251]519 // TODO ipv6 addresses
[797b704]520
521 char address[INET_ADDRSTRLEN];
522 char netmask[INET_ADDRSTRLEN];
523 char gateway[INET_ADDRSTRLEN];
524
525 for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
526 route = ip_routes_get_index(&ip_netif->routes, index);
527 if (route) {
528 inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
529 address, INET_ADDRSTRLEN);
530 inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
531 netmask, INET_ADDRSTRLEN);
532 inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
533 gateway, INET_ADDRSTRLEN);
534 printf("%s: Route %d (address: %s, netmask: %s, "
535 "gateway: %s)\n", NAME, index, address, netmask,
536 gateway);
537 }
538 }
539
540 inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
541 INET_ADDRSTRLEN);
[aadf01e]542 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
[e8199d77]543
[797b704]544 printf("%s: Broadcast (%s)\n", NAME, address);
[e8199d77]545
[21580dd]546 return EOK;
547}
548
[797b704]549/** Searches the network interfaces if there is a suitable route.
[e8199d77]550 *
[797b704]551 * @param[in] netif The network interface to be searched for routes. May be
552 * NULL.
553 * @param[in] destination The destination address.
554 * @return The found route.
555 * @return NULL if no route was found.
[e8199d77]556 */
[797b704]557static ip_route_t *ip_netif_find_route(ip_netif_t *netif,
558 in_addr_t destination)
[e8199d77]559{
[797b704]560 int index;
561 ip_route_t *route;
562
563 if (!netif)
564 return NULL;
565
566 /* Start with the first one (the direct route) */
567 for (index = 0; index < ip_routes_count(&netif->routes); index++) {
568 route = ip_routes_get_index(&netif->routes, index);
569 if ((route) &&
570 ((route->address.s_addr & route->netmask.s_addr) ==
571 (destination.s_addr & route->netmask.s_addr)))
572 return route;
573 }
574
575 return NULL;
576}
577
578/** Searches all network interfaces if there is a suitable route.
579 *
580 * @param[in] destination The destination address.
581 * @return The found route.
582 * @return NULL if no route was found.
583 */
584static ip_route_t *ip_find_route(in_addr_t destination) {
585 int index;
586 ip_route_t *route;
[4e5c7ba]587 ip_netif_t *netif;
[21580dd]588
[28a3e74]589 /* Start with the last netif - the newest one */
[797b704]590 index = ip_netifs_count(&ip_globals.netifs) - 1;
591 while (index >= 0) {
592 netif = ip_netifs_get_index(&ip_globals.netifs, index);
593 if (netif && (netif->state == NETIF_ACTIVE)) {
594 route = ip_netif_find_route(netif, destination);
595 if (route)
596 return route;
597 }
598 index--;
[21580dd]599 }
[e8199d77]600
[797b704]601 return &ip_globals.gateway;
[21580dd]602}
603
[797b704]604/** Returns the network interface's IP address.
[e8199d77]605 *
[797b704]606 * @param[in] netif The network interface.
607 * @return The IP address.
608 * @return NULL if no IP address was found.
[e8199d77]609 */
[797b704]610static in_addr_t *ip_netif_address(ip_netif_t *netif)
[e8199d77]611{
[797b704]612 ip_route_t *route;
[e8199d77]613
[797b704]614 route = ip_routes_get_index(&netif->routes, 0);
615 return route ? &route->address : NULL;
[21580dd]616}
617
[e8199d77]618/** Copies the fragment header.
619 *
620 * Copies only the header itself and relevant IP options.
621 *
622 * @param[out] last The created header.
623 * @param[in] first The original header to be copied.
624 */
[88a1bb9]625static void ip_create_last_header(ip_header_t *last, ip_header_t *first)
[e8199d77]626{
[88a1bb9]627 ip_option_t *option;
[e8199d77]628 size_t next;
629 size_t length;
[21580dd]630
[28a3e74]631 /* Copy first itself */
[e8199d77]632 memcpy(last, first, sizeof(ip_header_t));
633 length = sizeof(ip_header_t);
634 next = sizeof(ip_header_t);
[21580dd]635
[28a3e74]636 /* Process all IP options */
[e8199d77]637 while (next < first->header_length) {
[88a1bb9]638 option = (ip_option_t *) (((uint8_t *) first) + next);
[28a3e74]639 /* Skip end or noop */
[e8199d77]640 if ((option->type == IPOPT_END) ||
641 (option->type == IPOPT_NOOP)) {
642 next++;
643 } else {
[28a3e74]644 /* Copy if told so or skip */
[e8199d77]645 if (IPOPT_COPIED(option->type)) {
646 memcpy(((uint8_t *) last) + length,
647 ((uint8_t *) first) + next, option->length);
648 length += option->length;
[21580dd]649 }
[28a3e74]650 /* Next option */
[e8199d77]651 next += option->length;
[21580dd]652 }
653 }
654
[28a3e74]655 /* Align 4 byte boundary */
[e8199d77]656 if (length % 4) {
657 bzero(((uint8_t *) last) + length, 4 - (length % 4));
658 last->header_length = length / 4 + 1;
659 } else {
660 last->header_length = length / 4;
[21580dd]661 }
[e8199d77]662
663 last->header_checksum = 0;
[21580dd]664}
665
[e8199d77]666/** Prepares the outgoing packet or the packet queue.
667 *
668 * The packet queue is a fragmented packet
669 * Updates the first packet's IP header.
670 * Prefixes the additional packets with fragment headers.
671 *
672 * @param[in] source The source address.
673 * @param[in] dest The destination address.
674 * @param[in,out] packet The packet to be sent.
675 * @param[in] destination The destination hardware address.
[1bfd3d3]676 * @return EOK on success.
677 * @return EINVAL if the packet is too small to contain the IP
[e8199d77]678 * header.
[1bfd3d3]679 * @return EINVAL if the packet is too long than the IP allows.
680 * @return ENOMEM if there is not enough memory left.
681 * @return Other error codes as defined for the packet_set_addr()
[e8199d77]682 * function.
683 */
[797b704]684static int ip_prepare_packet(in_addr_t *source, in_addr_t dest,
685 packet_t *packet, measured_string_t *destination)
[e8199d77]686{
[aadf01e]687 size_t length;
[88a1bb9]688 ip_header_t *header;
689 ip_header_t *last_header;
690 ip_header_t *middle_header;
[46d4d9f]691 packet_t *next;
[02314f8]692 int rc;
[aadf01e]693
694 length = packet_get_data_length(packet);
[e8199d77]695 if ((length < sizeof(ip_header_t)) || (length > IP_MAX_CONTENT))
[aadf01e]696 return EINVAL;
[e8199d77]697
[88a1bb9]698 header = (ip_header_t *) packet_get_data(packet);
[e8199d77]699 if (destination) {
[02314f8]700 rc = packet_set_addr(packet, NULL, (uint8_t *) destination->value,
[7837101]701 destination->length);
[e8199d77]702 } else {
[02314f8]703 rc = packet_set_addr(packet, NULL, NULL, 0);
[21580dd]704 }
[02314f8]705 if (rc != EOK)
706 return rc;
707
[21580dd]708 header->version = IPV4;
709 header->fragment_offset_high = 0;
710 header->fragment_offset_low = 0;
711 header->header_checksum = 0;
[e8199d77]712 if (source)
[aadf01e]713 header->source_address = source->s_addr;
[21580dd]714 header->destination_address = dest.s_addr;
[e8199d77]715
[aadf01e]716 fibril_rwlock_write_lock(&ip_globals.lock);
[e8199d77]717 ip_globals.packet_counter++;
[aadf01e]718 header->identification = htons(ip_globals.packet_counter);
719 fibril_rwlock_write_unlock(&ip_globals.lock);
[e8199d77]720
721 if (pq_next(packet)) {
[88a1bb9]722 last_header = (ip_header_t *) malloc(IP_HEADER_LENGTH(header));
[e8199d77]723 if (!last_header)
[aadf01e]724 return ENOMEM;
725 ip_create_last_header(last_header, header);
726 next = pq_next(packet);
[e8199d77]727 while (pq_next(next)) {
[88a1bb9]728 middle_header = (ip_header_t *) packet_prefix(next,
[e8199d77]729 IP_HEADER_LENGTH(last_header));
[fd8e8e1]730 if (!middle_header) {
731 free(last_header);
[aadf01e]732 return ENOMEM;
[fd8e8e1]733 }
[e8199d77]734
735 memcpy(middle_header, last_header,
736 IP_HEADER_LENGTH(last_header));
[21580dd]737 header->flags |= IPFLAG_MORE_FRAGMENTS;
[e8199d77]738 middle_header->total_length =
739 htons(packet_get_data_length(next));
740 middle_header->fragment_offset_high =
741 IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
742 middle_header->fragment_offset_low =
743 IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
744 middle_header->header_checksum =
745 IP_HEADER_CHECKSUM(middle_header);
746 if (destination) {
[02314f8]747 rc = packet_set_addr(next, NULL,
[e8199d77]748 (uint8_t *) destination->value,
[7837101]749 destination->length);
[02314f8]750 if (rc != EOK) {
[fd8e8e1]751 free(last_header);
[02314f8]752 return rc;
[fd8e8e1]753 }
[21580dd]754 }
[aadf01e]755 length += packet_get_data_length(next);
756 next = pq_next(next);
[21580dd]757 }
[e8199d77]758
[88a1bb9]759 middle_header = (ip_header_t *) packet_prefix(next,
[e8199d77]760 IP_HEADER_LENGTH(last_header));
[fd8e8e1]761 if (!middle_header) {
762 free(last_header);
[aadf01e]763 return ENOMEM;
[fd8e8e1]764 }
[e8199d77]765
766 memcpy(middle_header, last_header,
767 IP_HEADER_LENGTH(last_header));
768 middle_header->total_length =
769 htons(packet_get_data_length(next));
770 middle_header->fragment_offset_high =
771 IP_COMPUTE_FRAGMENT_OFFSET_HIGH(length);
772 middle_header->fragment_offset_low =
773 IP_COMPUTE_FRAGMENT_OFFSET_LOW(length);
774 middle_header->header_checksum =
775 IP_HEADER_CHECKSUM(middle_header);
776 if (destination) {
[02314f8]777 rc = packet_set_addr(next, NULL,
[e8199d77]778 (uint8_t *) destination->value,
[7837101]779 destination->length);
[02314f8]780 if (rc != EOK) {
[fd8e8e1]781 free(last_header);
[02314f8]782 return rc;
783 }
[aadf01e]784 }
785 length += packet_get_data_length(next);
786 free(last_header);
[21580dd]787 header->flags |= IPFLAG_MORE_FRAGMENTS;
788 }
[e8199d77]789
[aadf01e]790 header->total_length = htons(length);
[28a3e74]791 /* Unnecessary for all protocols */
[aadf01e]792 header->header_checksum = IP_HEADER_CHECKSUM(header);
[e8199d77]793
[21580dd]794 return EOK;
795}
796
[e8199d77]797/** Fragments the packet from the end.
798 *
799 * @param[in] packet The packet to be fragmented.
800 * @param[in,out] new_packet The new packet fragment.
801 * @param[in,out] header The original packet header.
802 * @param[in,out] new_header The new packet fragment header.
803 * @param[in] length The new fragment length.
804 * @param[in] src The source address.
805 * @param[in] dest The destiantion address.
806 * @param[in] addrlen The address length.
[1bfd3d3]807 * @return EOK on success.
808 * @return ENOMEM if the target packet is too small.
809 * @return Other error codes as defined for the packet_set_addr()
[e8199d77]810 * function.
[1bfd3d3]811 * @return Other error codes as defined for the pq_insert_after()
[e8199d77]812 * function.
813 */
[797b704]814static int ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
[88a1bb9]815 ip_header_t *header, ip_header_t *new_header, size_t length,
[e8199d77]816 const struct sockaddr *src, const struct sockaddr *dest, socklen_t addrlen)
[14f1db0]817{
[e8199d77]818 void *data;
819 size_t offset;
[02314f8]820 int rc;
[21580dd]821
[e8199d77]822 data = packet_suffix(new_packet, length);
823 if (!data)
[21580dd]824 return ENOMEM;
825
[e8199d77]826 memcpy(data, ((void *) header) + IP_TOTAL_LENGTH(header) - length,
827 length);
[02314f8]828
829 rc = packet_trim(packet, 0, length);
830 if (rc != EOK)
831 return rc;
832
[e8199d77]833 header->total_length = htons(IP_TOTAL_LENGTH(header) - length);
834 new_header->total_length = htons(IP_HEADER_LENGTH(new_header) + length);
835 offset = IP_FRAGMENT_OFFSET(header) + IP_HEADER_DATA_LENGTH(header);
836 new_header->fragment_offset_high =
837 IP_COMPUTE_FRAGMENT_OFFSET_HIGH(offset);
838 new_header->fragment_offset_low =
839 IP_COMPUTE_FRAGMENT_OFFSET_LOW(offset);
840 new_header->header_checksum = IP_HEADER_CHECKSUM(new_header);
[02314f8]841
842 rc = packet_set_addr(new_packet, (const uint8_t *) src,
843 (const uint8_t *) dest, addrlen);
844 if (rc != EOK)
845 return rc;
[21580dd]846
[e8199d77]847 return pq_insert_after(packet, new_packet);
[21580dd]848}
849
[797b704]850/** Prefixes a middle fragment header based on the last fragment header to the
851 * packet.
852 *
853 * @param[in] packet The packet to be prefixed.
854 * @param[in] last The last header to be copied.
855 * @return The prefixed middle header.
856 * @return NULL on error.
857 */
858static ip_header_t *ip_create_middle_header(packet_t *packet,
859 ip_header_t *last)
860{
861 ip_header_t *middle;
862
863 middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
864 if (!middle)
865 return NULL;
866 memcpy(middle, last, IP_HEADER_LENGTH(last));
867 middle->flags |= IPFLAG_MORE_FRAGMENTS;
868 return middle;
869}
870
[e8199d77]871/** Checks the packet length and fragments it if needed.
872 *
873 * The new fragments are queued before the original packet.
874 *
875 * @param[in,out] packet The packet to be checked.
876 * @param[in] length The maximum packet length.
877 * @param[in] prefix The minimum prefix size.
878 * @param[in] suffix The minimum suffix size.
879 * @param[in] addr_len The minimum address length.
[1bfd3d3]880 * @return EOK on success.
881 * @return EINVAL if the packet_get_addr() function fails.
882 * @return EINVAL if the packet does not contain the IP header.
883 * @return EPERM if the packet needs to be fragmented and the
[e8199d77]884 * fragmentation is not allowed.
[1bfd3d3]885 * @return ENOMEM if there is not enough memory left.
886 * @return ENOMEM if there is no packet available.
887 * @return ENOMEM if the packet is too small to contain the IP
[e8199d77]888 * header.
[1bfd3d3]889 * @return Other error codes as defined for the packet_trim()
[e8199d77]890 * function.
[1bfd3d3]891 * @return Other error codes as defined for the
[e8199d77]892 * ip_create_middle_header() function.
[1bfd3d3]893 * @return Other error codes as defined for the
[e8199d77]894 * ip_fragment_packet_data() function.
895 */
896static int
[46d4d9f]897ip_fragment_packet(packet_t *packet, size_t length, size_t prefix, size_t suffix,
[e8199d77]898 socklen_t addr_len)
[14f1db0]899{
[46d4d9f]900 packet_t *new_packet;
[88a1bb9]901 ip_header_t *header;
902 ip_header_t *middle_header;
903 ip_header_t *last_header;
[e8199d77]904 struct sockaddr *src;
905 struct sockaddr *dest;
[aadf01e]906 socklen_t addrlen;
907 int result;
[02314f8]908 int rc;
[aadf01e]909
910 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest);
[e8199d77]911 if (result <= 0)
[aadf01e]912 return EINVAL;
[e8199d77]913
[aadf01e]914 addrlen = (socklen_t) result;
[e8199d77]915 if (packet_get_data_length(packet) <= sizeof(ip_header_t))
[aadf01e]916 return ENOMEM;
[e8199d77]917
[28a3e74]918 /* Get header */
[88a1bb9]919 header = (ip_header_t *) packet_get_data(packet);
[e8199d77]920 if (!header)
[aadf01e]921 return EINVAL;
[e8199d77]922
[28a3e74]923 /* Fragmentation forbidden? */
[e8199d77]924 if(header->flags & IPFLAG_DONT_FRAGMENT)
[21580dd]925 return EPERM;
[e8199d77]926
[28a3e74]927 /* Create the last fragment */
[e8199d77]928 new_packet = packet_get_4_remote(ip_globals.net_phone, prefix, length,
929 suffix, ((addrlen > addr_len) ? addrlen : addr_len));
930 if (!new_packet)
[aadf01e]931 return ENOMEM;
[e8199d77]932
[28a3e74]933 /* Allocate as much as originally */
[88a1bb9]934 last_header = (ip_header_t *) packet_suffix(new_packet,
[e8199d77]935 IP_HEADER_LENGTH(header));
936 if (!last_header)
[aadf01e]937 return ip_release_and_return(packet, ENOMEM);
[e8199d77]938
[aadf01e]939 ip_create_last_header(last_header, header);
[e8199d77]940
[28a3e74]941 /* Trim the unused space */
[02314f8]942 rc = packet_trim(new_packet, 0,
943 IP_HEADER_LENGTH(header) - IP_HEADER_LENGTH(last_header));
944 if (rc != EOK)
945 return ip_release_and_return(packet, rc);
[e8199d77]946
[28a3e74]947 /* Greatest multiple of 8 lower than content */
[ccca251]948 // TODO even fragmentation?
[e8199d77]949 length = length & ~0x7;
[02314f8]950
951 rc = ip_fragment_packet_data(packet, new_packet, header, last_header,
[e8199d77]952 ((IP_HEADER_DATA_LENGTH(header) -
953 ((length - IP_HEADER_LENGTH(header)) & ~0x7)) %
[02314f8]954 ((length - IP_HEADER_LENGTH(last_header)) & ~0x7)),
955 src, dest, addrlen);
956 if (rc != EOK)
957 return ip_release_and_return(packet, rc);
[e8199d77]958
[28a3e74]959 /* Mark the first as fragmented */
[21580dd]960 header->flags |= IPFLAG_MORE_FRAGMENTS;
[e8199d77]961
[28a3e74]962 /* Create middle fragments */
[e8199d77]963 while (IP_TOTAL_LENGTH(header) > length) {
964 new_packet = packet_get_4_remote(ip_globals.net_phone, prefix,
965 length, suffix,
966 ((addrlen >= addr_len) ? addrlen : addr_len));
967 if (!new_packet)
[aadf01e]968 return ENOMEM;
[e8199d77]969
970 middle_header = ip_create_middle_header(new_packet,
971 last_header);
972 if (!middle_header)
[aadf01e]973 return ip_release_and_return(packet, ENOMEM);
[e8199d77]974
[02314f8]975 rc = ip_fragment_packet_data(packet, new_packet, header,
976 middle_header,
977 (length - IP_HEADER_LENGTH(middle_header)) & ~0x7,
978 src, dest, addrlen);
979 if (rc != EOK)
980 return ip_release_and_return(packet, rc);
[21580dd]981 }
[e8199d77]982
[28a3e74]983 /* Finish the first fragment */
[aadf01e]984 header->header_checksum = IP_HEADER_CHECKSUM(header);
[e8199d77]985
[21580dd]986 return EOK;
987}
988
[e8199d77]989/** Checks the packet queue lengths and fragments the packets if needed.
990 *
991 * The ICMP_FRAG_NEEDED error notification may be sent if the packet needs to
992 * be fragmented and the fragmentation is not allowed.
993 *
994 * @param[in,out] packet The packet or the packet queue to be checked.
995 * @param[in] prefix The minimum prefix size.
996 * @param[in] content The maximum content size.
997 * @param[in] suffix The minimum suffix size.
998 * @param[in] addr_len The minimum address length.
999 * @param[in] error The error module service.
[1bfd3d3]1000 * @return The packet or the packet queue of the allowed length.
1001 * @return NULL if there are no packets left.
[e8199d77]1002 */
[46d4d9f]1003static packet_t *
1004ip_split_packet(packet_t *packet, size_t prefix, size_t content, size_t suffix,
[e8199d77]1005 socklen_t addr_len, services_t error)
1006{
1007 size_t length;
[46d4d9f]1008 packet_t *next;
1009 packet_t *new_packet;
[e8199d77]1010 int result;
1011 int phone;
1012
1013 next = packet;
[28a3e74]1014 /* Check all packets */
[e8199d77]1015 while (next) {
1016 length = packet_get_data_length(next);
1017
1018 if (length <= content) {
1019 next = pq_next(next);
1020 continue;
1021 }
1022
[28a3e74]1023 /* Too long */
[e8199d77]1024 result = ip_fragment_packet(next, content, prefix,
1025 suffix, addr_len);
1026 if (result != EOK) {
1027 new_packet = pq_detach(next);
1028 if (next == packet) {
[28a3e74]1029 /* The new first packet of the queue */
[e8199d77]1030 packet = new_packet;
1031 }
[28a3e74]1032 /* Fragmentation needed? */
[e8199d77]1033 if (result == EPERM) {
1034 phone = ip_prepare_icmp_and_get_phone(
1035 error, next, NULL);
1036 if (phone >= 0) {
[28a3e74]1037 /* Fragmentation necessary ICMP */
[e8199d77]1038 icmp_destination_unreachable_msg(phone,
1039 ICMP_FRAG_NEEDED, content, next);
1040 }
1041 } else {
1042 pq_release_remote(ip_globals.net_phone,
1043 packet_get_id(next));
1044 }
1045
1046 next = new_packet;
1047 continue;
1048 }
1049
1050 next = pq_next(next);
1051 }
1052
1053 return packet;
1054}
1055
1056/** Sends the packet or the packet queue via the specified route.
1057 *
1058 * The ICMP_HOST_UNREACH error notification may be sent if route hardware
1059 * destination address is found.
1060 *
1061 * @param[in,out] packet The packet to be sent.
1062 * @param[in] netif The target network interface.
1063 * @param[in] route The target route.
1064 * @param[in] src The source address.
1065 * @param[in] dest The destination address.
1066 * @param[in] error The error module service.
[1bfd3d3]1067 * @return EOK on success.
1068 * @return Other error codes as defined for the arp_translate_req()
[e8199d77]1069 * function.
[1bfd3d3]1070 * @return Other error codes as defined for the ip_prepare_packet()
[e8199d77]1071 * function.
1072 */
[797b704]1073static int ip_send_route(packet_t *packet, ip_netif_t *netif,
1074 ip_route_t *route, in_addr_t *src, in_addr_t dest, services_t error)
[e8199d77]1075{
1076 measured_string_t destination;
[4eca056]1077 measured_string_t *translation;
[61bfc370]1078 uint8_t *data;
[e8199d77]1079 int phone;
[02314f8]1080 int rc;
[aadf01e]1081
[28a3e74]1082 /* Get destination hardware address */
[e8199d77]1083 if (netif->arp && (route->address.s_addr != dest.s_addr)) {
1084 destination.value = route->gateway.s_addr ?
[61bfc370]1085 (uint8_t *) &route->gateway.s_addr : (uint8_t *) &dest.s_addr;
[1b59023]1086 destination.length = sizeof(dest.s_addr);
[e8199d77]1087
[02314f8]1088 rc = arp_translate_req(netif->arp->phone, netif->device_id,
1089 SERVICE_IP, &destination, &translation, &data);
1090 if (rc != EOK) {
[e8199d77]1091 pq_release_remote(ip_globals.net_phone,
1092 packet_get_id(packet));
[02314f8]1093 return rc;
[e8199d77]1094 }
1095
1096 if (!translation || !translation->value) {
1097 if (translation) {
1098 free(translation);
1099 free(data);
1100 }
1101 phone = ip_prepare_icmp_and_get_phone(error, packet,
1102 NULL);
1103 if (phone >= 0) {
[28a3e74]1104 /* Unreachable ICMP if no routing */
[e8199d77]1105 icmp_destination_unreachable_msg(phone,
1106 ICMP_HOST_UNREACH, 0, packet);
1107 }
1108 return EINVAL;
1109 }
1110
1111 } else {
1112 translation = NULL;
[aadf01e]1113 }
[e8199d77]1114
[02314f8]1115 rc = ip_prepare_packet(src, dest, packet, translation);
1116 if (rc != EOK) {
[e8199d77]1117 pq_release_remote(ip_globals.net_phone, packet_get_id(packet));
1118 } else {
1119 packet = ip_split_packet(packet, netif->packet_dimension.prefix,
1120 netif->packet_dimension.content,
1121 netif->packet_dimension.suffix,
1122 netif->packet_dimension.addr_len, error);
1123 if (packet) {
1124 nil_send_msg(netif->phone, netif->device_id, packet,
1125 SERVICE_IP);
1126 }
1127 }
1128
1129 if (translation) {
1130 free(translation);
1131 free(data);
1132 }
1133
[02314f8]1134 return rc;
[21580dd]1135}
1136
[797b704]1137static int ip_send_msg_local(int il_phone, device_id_t device_id,
1138 packet_t *packet, services_t sender, services_t error)
[e8199d77]1139{
[797b704]1140 int addrlen;
1141 ip_netif_t *netif;
[4e5c7ba]1142 ip_route_t *route;
[797b704]1143 struct sockaddr *addr;
1144 struct sockaddr_in *address_in;
1145 in_addr_t *dest;
1146 in_addr_t *src;
1147 int phone;
1148 int rc;
[e8199d77]1149
[28a3e74]1150 /*
1151 * Addresses in the host byte order
1152 * Should be the next hop address or the target destination address
1153 */
[797b704]1154 addrlen = packet_get_addr(packet, NULL, (uint8_t **) &addr);
1155 if (addrlen < 0)
1156 return ip_release_and_return(packet, addrlen);
1157 if ((size_t) addrlen < sizeof(struct sockaddr))
1158 return ip_release_and_return(packet, EINVAL);
[21580dd]1159
[797b704]1160 switch (addr->sa_family) {
1161 case AF_INET:
1162 if (addrlen != sizeof(struct sockaddr_in))
1163 return ip_release_and_return(packet, EINVAL);
1164 address_in = (struct sockaddr_in *) addr;
1165 dest = &address_in->sin_addr;
1166 if (!dest->s_addr)
1167 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
1168 break;
1169 case AF_INET6:
1170 default:
1171 return ip_release_and_return(packet, EAFNOSUPPORT);
1172 }
[e8199d77]1173
1174 netif = NULL;
1175 route = NULL;
1176 fibril_rwlock_read_lock(&ip_globals.netifs_lock);
1177
[28a3e74]1178 /* Device specified? */
[e8199d77]1179 if (device_id > 0) {
1180 netif = ip_netifs_find(&ip_globals.netifs, device_id);
[774e6d1a]1181 route = ip_netif_find_route(netif, *dest);
[e8199d77]1182 if (netif && !route && (ip_globals.gateway.netif == netif))
1183 route = &ip_globals.gateway;
1184 }
1185
1186 if (!route) {
1187 route = ip_find_route(*dest);
1188 netif = route ? route->netif : NULL;
1189 }
1190 if (!netif || !route) {
1191 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1192 phone = ip_prepare_icmp_and_get_phone(error, packet, NULL);
1193 if (phone >= 0) {
[28a3e74]1194 /* Unreachable ICMP if no routing */
[e8199d77]1195 icmp_destination_unreachable_msg(phone,
1196 ICMP_NET_UNREACH, 0, packet);
1197 }
1198 return ENOENT;
1199 }
1200
1201 if (error) {
[28a3e74]1202 /*
1203 * Do not send for broadcast, anycast packets or network
1204 * broadcast.
1205 */
[e8199d77]1206 if (!dest->s_addr || !(~dest->s_addr) ||
1207 !(~((dest->s_addr & ~route->netmask.s_addr) |
1208 route->netmask.s_addr)) ||
1209 (!(dest->s_addr & ~route->netmask.s_addr))) {
1210 return ip_release_and_return(packet, EINVAL);
1211 }
1212 }
[774e6d1a]1213
[ccca251]1214 /* If the local host is the destination */
[e8199d77]1215 if ((route->address.s_addr == dest->s_addr) &&
1216 (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
[28a3e74]1217 /* Find the loopback device to deliver */
[e8199d77]1218 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
1219 route = ip_find_route(*dest);
1220 netif = route ? route->netif : NULL;
1221 if (!netif || !route) {
1222 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1223 phone = ip_prepare_icmp_and_get_phone(error, packet,
1224 NULL);
1225 if (phone >= 0) {
[28a3e74]1226 /* Unreachable ICMP if no routing */
[e8199d77]1227 icmp_destination_unreachable_msg(phone,
1228 ICMP_HOST_UNREACH, 0, packet);
[21580dd]1229 }
[e8199d77]1230 return ENOENT;
1231 }
1232 }
1233
1234 src = ip_netif_address(netif);
1235 if (!src) {
1236 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1237 return ip_release_and_return(packet, ENOENT);
1238 }
1239
[02314f8]1240 rc = ip_send_route(packet, netif, route, src, *dest, error);
[e8199d77]1241 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1242
[02314f8]1243 return rc;
[e8199d77]1244}
1245
[797b704]1246/** Updates the device state.
[e8199d77]1247 *
1248 * @param[in] device_id The device identifier.
[797b704]1249 * @param[in] state The new state value.
[1bfd3d3]1250 * @return EOK on success.
[797b704]1251 * @return ENOENT if device is not found.
[e8199d77]1252 */
[797b704]1253static int ip_device_state_message(device_id_t device_id, device_state_t state)
[e8199d77]1254{
[4e5c7ba]1255 ip_netif_t *netif;
[e8199d77]1256
[797b704]1257 fibril_rwlock_write_lock(&ip_globals.netifs_lock);
[28a3e74]1258 /* Find the device */
[797b704]1259 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1260 if (!netif) {
1261 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1262 return ENOENT;
[e8199d77]1263 }
[797b704]1264 netif->state = state;
1265 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1266
1267 printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
[e8199d77]1268
1269 return EOK;
1270}
1271
1272/** Returns the packet destination address from the IP header.
1273 *
1274 * @param[in] header The packet IP header to be read.
[1bfd3d3]1275 * @return The packet destination address.
[e8199d77]1276 */
[88a1bb9]1277static in_addr_t ip_get_destination(ip_header_t *header)
[e8199d77]1278{
1279 in_addr_t destination;
1280
[ccca251]1281 // TODO search set ipopt route?
[e8199d77]1282 destination.s_addr = header->destination_address;
1283 return destination;
1284}
1285
1286/** Delivers the packet to the local host.
1287 *
1288 * The packet is either passed to another module or released on error.
1289 * The ICMP_PROT_UNREACH error notification may be sent if the protocol is not
1290 * found.
1291 *
1292 * @param[in] device_id The source device identifier.
1293 * @param[in] packet The packet to be delivered.
1294 * @param[in] header The first packet IP header. May be NULL.
1295 * @param[in] error The packet error service.
[1bfd3d3]1296 * @return EOK on success.
1297 * @return ENOTSUP if the packet is a fragment.
1298 * @return EAFNOSUPPORT if the address family is not supported.
1299 * @return ENOENT if the target protocol is not found.
1300 * @return Other error codes as defined for the packet_set_addr()
[e8199d77]1301 * function.
[1bfd3d3]1302 * @return Other error codes as defined for the packet_trim()
[e8199d77]1303 * function.
[1bfd3d3]1304 * @return Other error codes as defined for the protocol specific
[e8199d77]1305 * tl_received_msg() function.
1306 */
[797b704]1307static int ip_deliver_local(device_id_t device_id, packet_t *packet,
1308 ip_header_t *header, services_t error)
[e8199d77]1309{
[4e5c7ba]1310 ip_proto_t *proto;
[e8199d77]1311 int phone;
1312 services_t service;
1313 tl_received_msg_t received_msg;
1314 struct sockaddr *src;
1315 struct sockaddr *dest;
1316 struct sockaddr_in src_in;
1317 struct sockaddr_in dest_in;
1318 socklen_t addrlen;
[02314f8]1319 int rc;
[e8199d77]1320
1321 if ((header->flags & IPFLAG_MORE_FRAGMENTS) ||
1322 IP_FRAGMENT_OFFSET(header)) {
[ccca251]1323 // TODO fragmented
[e8199d77]1324 return ENOTSUP;
1325 }
1326
1327 switch (header->version) {
1328 case IPVERSION:
1329 addrlen = sizeof(src_in);
1330 bzero(&src_in, addrlen);
1331 src_in.sin_family = AF_INET;
1332 memcpy(&dest_in, &src_in, addrlen);
1333 memcpy(&src_in.sin_addr.s_addr, &header->source_address,
1334 sizeof(header->source_address));
1335 memcpy(&dest_in.sin_addr.s_addr, &header->destination_address,
1336 sizeof(header->destination_address));
1337 src = (struct sockaddr *) &src_in;
1338 dest = (struct sockaddr *) &dest_in;
1339 break;
1340
1341 default:
1342 return ip_release_and_return(packet, EAFNOSUPPORT);
1343 }
1344
[02314f8]1345 rc = packet_set_addr(packet, (uint8_t *) src, (uint8_t *) dest,
1346 addrlen);
1347 if (rc != EOK)
1348 return ip_release_and_return(packet, rc);
[e8199d77]1349
[28a3e74]1350 /* Trim padding if present */
[e8199d77]1351 if (!error &&
1352 (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
[02314f8]1353 rc = packet_trim(packet, 0,
1354 packet_get_data_length(packet) - IP_TOTAL_LENGTH(header));
1355 if (rc != EOK)
1356 return ip_release_and_return(packet, rc);
[e8199d77]1357 }
1358
1359 fibril_rwlock_read_lock(&ip_globals.protos_lock);
1360
1361 proto = ip_protos_find(&ip_globals.protos, header->protocol);
1362 if (!proto) {
1363 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
1364 phone = ip_prepare_icmp_and_get_phone(error, packet, header);
1365 if (phone >= 0) {
[28a3e74]1366 /* Unreachable ICMP */
[e8199d77]1367 icmp_destination_unreachable_msg(phone,
1368 ICMP_PROT_UNREACH, 0, packet);
[21580dd]1369 }
[e8199d77]1370 return ENOENT;
[21580dd]1371 }
1372
[e8199d77]1373 if (proto->received_msg) {
1374 service = proto->service;
1375 received_msg = proto->received_msg;
1376 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
[02314f8]1377 rc = received_msg(device_id, packet, service, error);
[e8199d77]1378 } else {
[02314f8]1379 rc = tl_received_msg(proto->phone, device_id, packet,
[e8199d77]1380 proto->service, error);
1381 fibril_rwlock_read_unlock(&ip_globals.protos_lock);
1382 }
[21580dd]1383
[02314f8]1384 return rc;
[21580dd]1385}
1386
[e8199d77]1387/** Processes the received packet.
1388 *
1389 * The packet is either passed to another module or released on error.
1390 *
1391 * The ICMP_PARAM_POINTER error notification may be sent if the checksum is
1392 * invalid.
1393 * The ICMP_EXC_TTL error notification may be sent if the TTL is less than two.
1394 * The ICMP_HOST_UNREACH error notification may be sent if no route was found.
1395 * The ICMP_HOST_UNREACH error notification may be sent if the packet is for
1396 * another host and the routing is disabled.
1397 *
1398 * @param[in] device_id The source device identifier.
1399 * @param[in] packet The received packet to be processed.
[1bfd3d3]1400 * @return EOK on success.
1401 * @return EINVAL if the TTL is less than two.
1402 * @return EINVAL if the checksum is invalid.
1403 * @return EAFNOSUPPORT if the address family is not supported.
1404 * @return ENOENT if no route was found.
1405 * @return ENOENT if the packet is for another host and the routing
[e8199d77]1406 * is disabled.
1407 */
[797b704]1408static int ip_process_packet(device_id_t device_id, packet_t *packet)
[e8199d77]1409{
[88a1bb9]1410 ip_header_t *header;
[aadf01e]1411 in_addr_t dest;
[4e5c7ba]1412 ip_route_t *route;
[aadf01e]1413 int phone;
[e8199d77]1414 struct sockaddr *addr;
[aadf01e]1415 struct sockaddr_in addr_in;
1416 socklen_t addrlen;
[02314f8]1417 int rc;
[774e6d1a]1418
[88a1bb9]1419 header = (ip_header_t *) packet_get_data(packet);
[e8199d77]1420 if (!header)
[aadf01e]1421 return ip_release_and_return(packet, ENOMEM);
[e8199d77]1422
[28a3e74]1423 /* Checksum */
[e8199d77]1424 if ((header->header_checksum) &&
1425 (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
[aadf01e]1426 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
[e8199d77]1427 if (phone >= 0) {
[28a3e74]1428 /* Checksum error ICMP */
[e8199d77]1429 icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
1430 ((size_t) ((void *) &header->header_checksum)) -
1431 ((size_t) ((void *) header)), packet);
[21580dd]1432 }
1433 return EINVAL;
1434 }
[e8199d77]1435
1436 if (header->ttl <= 1) {
[aadf01e]1437 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
[e8199d77]1438 if (phone >= 0) {
[ccca251]1439 /* TTL exceeded ICMP */
[aadf01e]1440 icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
[21580dd]1441 }
1442 return EINVAL;
1443 }
[774e6d1a]1444
[28a3e74]1445 /* Process ipopt and get destination */
[aadf01e]1446 dest = ip_get_destination(header);
[e8199d77]1447
[28a3e74]1448 /* Set the destination address */
[e8199d77]1449 switch (header->version) {
1450 case IPVERSION:
1451 addrlen = sizeof(addr_in);
1452 bzero(&addr_in, addrlen);
1453 addr_in.sin_family = AF_INET;
1454 memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
1455 addr = (struct sockaddr *) &addr_in;
1456 break;
1457
1458 default:
1459 return ip_release_and_return(packet, EAFNOSUPPORT);
[21580dd]1460 }
[e8199d77]1461
[02314f8]1462 rc = packet_set_addr(packet, NULL, (uint8_t *) &addr, addrlen);
1463 if (rc != EOK)
1464 return rc;
[774e6d1a]1465
[aadf01e]1466 route = ip_find_route(dest);
[e8199d77]1467 if (!route) {
[aadf01e]1468 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
[e8199d77]1469 if (phone >= 0) {
[28a3e74]1470 /* Unreachable ICMP */
[e8199d77]1471 icmp_destination_unreachable_msg(phone,
1472 ICMP_HOST_UNREACH, 0, packet);
[21580dd]1473 }
1474 return ENOENT;
1475 }
[e8199d77]1476
1477 if (route->address.s_addr == dest.s_addr) {
[28a3e74]1478 /* Local delivery */
[aadf01e]1479 return ip_deliver_local(device_id, packet, header, 0);
[21580dd]1480 }
[e8199d77]1481
1482 if (route->netif->routing) {
1483 header->ttl--;
1484 return ip_send_route(packet, route->netif, route, NULL, dest,
1485 0);
1486 }
1487
1488 phone = ip_prepare_icmp_and_get_phone(0, packet, header);
1489 if (phone >= 0) {
[28a3e74]1490 /* Unreachable ICMP if no routing */
[e8199d77]1491 icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
1492 packet);
1493 }
1494
1495 return ENOENT;
1496}
1497
[797b704]1498/** Returns the device packet dimensions for sending.
1499 *
1500 * @param[in] phone The service module phone.
1501 * @param[in] message The service specific message.
1502 * @param[in] device_id The device identifier.
1503 * @param[out] addr_len The minimum reserved address length.
1504 * @param[out] prefix The minimum reserved prefix size.
1505 * @param[out] content The maximum content size.
1506 * @param[out] suffix The minimum reserved suffix size.
1507 * @return EOK on success.
1508 */
1509static int ip_packet_size_message(device_id_t device_id, size_t *addr_len,
1510 size_t *prefix, size_t *content, size_t *suffix)
1511{
1512 ip_netif_t *netif;
1513 int index;
1514
1515 if (!addr_len || !prefix || !content || !suffix)
1516 return EBADMEM;
1517
1518 *content = IP_MAX_CONTENT - IP_PREFIX;
1519 fibril_rwlock_read_lock(&ip_globals.netifs_lock);
1520 if (device_id < 0) {
1521 *addr_len = IP_ADDR;
1522 *prefix = 0;
1523 *suffix = 0;
1524
1525 for (index = ip_netifs_count(&ip_globals.netifs) - 1;
1526 index >= 0; index--) {
1527 netif = ip_netifs_get_index(&ip_globals.netifs, index);
1528 if (!netif)
1529 continue;
1530
1531 if (netif->packet_dimension.addr_len > *addr_len)
1532 *addr_len = netif->packet_dimension.addr_len;
1533
1534 if (netif->packet_dimension.prefix > *prefix)
1535 *prefix = netif->packet_dimension.prefix;
1536
1537 if (netif->packet_dimension.suffix > *suffix)
1538 *suffix = netif->packet_dimension.suffix;
1539 }
1540
1541 *prefix = *prefix + IP_PREFIX;
1542 *suffix = *suffix + IP_SUFFIX;
1543 } else {
1544 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1545 if (!netif) {
1546 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1547 return ENOENT;
1548 }
1549
1550 *addr_len = (netif->packet_dimension.addr_len > IP_ADDR) ?
1551 netif->packet_dimension.addr_len : IP_ADDR;
1552 *prefix = netif->packet_dimension.prefix + IP_PREFIX;
1553 *suffix = netif->packet_dimension.suffix + IP_SUFFIX;
1554 }
1555 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1556
1557 return EOK;
1558}
1559
1560/** Updates the device content length according to the new MTU value.
1561 *
1562 * @param[in] device_id The device identifier.
1563 * @param[in] mtu The new mtu value.
1564 * @return EOK on success.
1565 * @return ENOENT if device is not found.
1566 */
1567static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
1568{
1569 ip_netif_t *netif;
1570
1571 fibril_rwlock_write_lock(&ip_globals.netifs_lock);
1572 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1573 if (!netif) {
1574 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1575 return ENOENT;
1576 }
1577 netif->packet_dimension.content = mtu;
1578 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1579
1580 printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
1581
1582 return EOK;
1583}
1584
1585/** Process IPC messages from the registered device driver modules
1586 *
1587 * @param[in] iid Message identifier.
1588 * @param[in,out] icall Message parameters.
1589 *
1590 */
1591static void ip_receiver(ipc_callid_t iid, ipc_call_t *icall)
1592{
1593 packet_t *packet;
1594 int rc;
1595
1596 while (true) {
1597 switch (IPC_GET_IMETHOD(*icall)) {
1598 case NET_IL_DEVICE_STATE:
1599 rc = ip_device_state_message(IPC_GET_DEVICE(*icall),
1600 IPC_GET_STATE(*icall));
[ffa2c8ef]1601 async_answer_0(iid, (sysarg_t) rc);
[797b704]1602 break;
1603
1604 case NET_IL_RECEIVED:
1605 rc = packet_translate_remote(ip_globals.net_phone, &packet,
1606 IPC_GET_PACKET(*icall));
1607 if (rc == EOK) {
1608 do {
1609 packet_t *next = pq_detach(packet);
1610 ip_process_packet(IPC_GET_DEVICE(*icall), packet);
1611 packet = next;
1612 } while (packet);
1613 }
1614
[ffa2c8ef]1615 async_answer_0(iid, (sysarg_t) rc);
[797b704]1616 break;
1617
1618 case NET_IL_MTU_CHANGED:
1619 rc = ip_mtu_changed_message(IPC_GET_DEVICE(*icall),
1620 IPC_GET_MTU(*icall));
[ffa2c8ef]1621 async_answer_0(iid, (sysarg_t) rc);
[797b704]1622 break;
1623
1624 default:
[ffa2c8ef]1625 async_answer_0(iid, (sysarg_t) ENOTSUP);
[797b704]1626 }
1627
1628 iid = async_get_call(icall);
1629 }
1630}
1631
1632/** Registers the transport layer protocol.
1633 *
1634 * The traffic of this protocol will be supplied using either the receive
1635 * function or IPC message.
1636 *
1637 * @param[in] protocol The transport layer module protocol.
1638 * @param[in] service The transport layer module service.
1639 * @param[in] phone The transport layer module phone.
1640 * @param[in] received_msg The receiving function.
1641 * @return EOK on success.
1642 * @return EINVAL if the protocol parameter and/or the service
1643 * parameter is zero.
1644 * @return EINVAL if the phone parameter is not a positive number
1645 * and the tl_receive_msg is NULL.
1646 * @return ENOMEM if there is not enough memory left.
1647 */
1648static int
1649ip_register(int protocol, services_t service, int phone,
1650 tl_received_msg_t received_msg)
1651{
1652 ip_proto_t *proto;
1653 int index;
1654
1655 if (!protocol || !service || ((phone < 0) && !received_msg))
1656 return EINVAL;
1657
1658 proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
1659 if (!proto)
1660 return ENOMEM;
1661
1662 proto->protocol = protocol;
1663 proto->service = service;
1664 proto->phone = phone;
1665 proto->received_msg = received_msg;
1666
1667 fibril_rwlock_write_lock(&ip_globals.protos_lock);
1668 index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
1669 if (index < 0) {
1670 fibril_rwlock_write_unlock(&ip_globals.protos_lock);
1671 free(proto);
1672 return index;
1673 }
1674 fibril_rwlock_write_unlock(&ip_globals.protos_lock);
1675
1676 printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
1677 NAME, proto->protocol, proto->phone);
1678
1679 return EOK;
1680}
1681
1682
[e8199d77]1683static int
1684ip_add_route_req_local(int ip_phone, device_id_t device_id, in_addr_t address,
1685 in_addr_t netmask, in_addr_t gateway)
1686{
[4e5c7ba]1687 ip_route_t *route;
1688 ip_netif_t *netif;
[e8199d77]1689 int index;
1690
1691 fibril_rwlock_write_lock(&ip_globals.netifs_lock);
1692
1693 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1694 if (!netif) {
1695 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1696 return ENOENT;
1697 }
1698
[4e5c7ba]1699 route = (ip_route_t *) malloc(sizeof(ip_route_t));
[e8199d77]1700 if (!route) {
1701 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1702 return ENOMEM;
1703 }
1704
1705 route->address.s_addr = address.s_addr;
1706 route->netmask.s_addr = netmask.s_addr;
1707 route->gateway.s_addr = gateway.s_addr;
1708 route->netif = netif;
1709 index = ip_routes_add(&netif->routes, route);
1710 if (index < 0)
1711 free(route);
1712
1713 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1714
1715 return index;
1716}
1717
1718static int
1719ip_set_gateway_req_local(int ip_phone, device_id_t device_id, in_addr_t gateway)
1720{
[4e5c7ba]1721 ip_netif_t *netif;
[e8199d77]1722
1723 fibril_rwlock_write_lock(&ip_globals.netifs_lock);
1724
1725 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1726 if (!netif) {
1727 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1728 return ENOENT;
1729 }
1730
1731 ip_globals.gateway.address.s_addr = 0;
1732 ip_globals.gateway.netmask.s_addr = 0;
1733 ip_globals.gateway.gateway.s_addr = gateway.s_addr;
1734 ip_globals.gateway.netif = netif;
1735
1736 fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
1737
1738 return EOK;
[21580dd]1739}
1740
[14f1db0]1741/** Notify the IP module about the received error notification packet.
1742 *
[e8199d77]1743 * @param[in] ip_phone The IP module phone used for (semi)remote calls.
1744 * @param[in] device_id The device identifier.
1745 * @param[in] packet The received packet or the received packet queue.
1746 * @param[in] target The target internetwork module service to be
1747 * delivered to.
1748 * @param[in] error The packet error reporting service. Prefixes the
1749 * received packet.
1750 * @return EOK on success.
[14f1db0]1751 *
1752 */
[e8199d77]1753static int
1754ip_received_error_msg_local(int ip_phone, device_id_t device_id,
[46d4d9f]1755 packet_t *packet, services_t target, services_t error)
[e8199d77]1756{
1757 uint8_t *data;
[aadf01e]1758 int offset;
1759 icmp_type_t type;
1760 icmp_code_t code;
[4e5c7ba]1761 ip_netif_t *netif;
[aadf01e]1762 measured_string_t address;
[4e5c7ba]1763 ip_route_t *route;
[88a1bb9]1764 ip_header_t *header;
[aadf01e]1765
[e8199d77]1766 switch (error) {
1767 case SERVICE_ICMP:
1768 offset = icmp_client_process_packet(packet, &type, &code, NULL,
1769 NULL);
1770 if (offset < 0)
1771 return ip_release_and_return(packet, ENOMEM);
[21580dd]1772
[e8199d77]1773 data = packet_get_data(packet);
[88a1bb9]1774 header = (ip_header_t *)(data + offset);
[21580dd]1775
[28a3e74]1776 /* Destination host unreachable? */
[e8199d77]1777 if ((type != ICMP_DEST_UNREACH) ||
1778 (code != ICMP_HOST_UNREACH)) {
[ccca251]1779 /* No, something else */
[e8199d77]1780 break;
[21580dd]1781 }
1782
[e8199d77]1783 fibril_rwlock_read_lock(&ip_globals.netifs_lock);
[21580dd]1784
[e8199d77]1785 netif = ip_netifs_find(&ip_globals.netifs, device_id);
1786 if (!netif || !netif->arp) {
1787 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
[21580dd]1788 break;
[e8199d77]1789 }
[21580dd]1790
[e8199d77]1791 route = ip_routes_get_index(&netif->routes, 0);
1792
[28a3e74]1793 /* From the same network? */
[e8199d77]1794 if (route && ((route->address.s_addr & route->netmask.s_addr) ==
1795 (header->destination_address & route->netmask.s_addr))) {
[28a3e74]1796 /* Clear the ARP mapping if any */
[61bfc370]1797 address.value = (uint8_t *) &header->destination_address;
[7837101]1798 address.length = sizeof(header->destination_address);
[e8199d77]1799 arp_clear_address_req(netif->arp->phone,
1800 netif->device_id, SERVICE_IP, &address);
1801 }
[21580dd]1802
[e8199d77]1803 fibril_rwlock_read_unlock(&ip_globals.netifs_lock);
1804 break;
[21580dd]1805
[e8199d77]1806 default:
1807 return ip_release_and_return(packet, ENOTSUP);
[21580dd]1808 }
1809
[e8199d77]1810 return ip_deliver_local(device_id, packet, header, error);
[21580dd]1811}
1812
[e8199d77]1813static int
1814ip_get_route_req_local(int ip_phone, ip_protocol_t protocol,
1815 const struct sockaddr *destination, socklen_t addrlen,
1816 device_id_t *device_id, void **header, size_t *headerlen)
1817{
1818 struct sockaddr_in *address_in;
1819 in_addr_t *dest;
1820 in_addr_t *src;
[4e5c7ba]1821 ip_route_t *route;
[88a1bb9]1822 ipv4_pseudo_header_t *header_in;
[aadf01e]1823
[e8199d77]1824 if (!destination || (addrlen <= 0))
[21580dd]1825 return EINVAL;
[e8199d77]1826
1827 if (!device_id || !header || !headerlen)
[aadf01e]1828 return EBADMEM;
[e8199d77]1829
1830 if ((size_t) addrlen < sizeof(struct sockaddr))
[aadf01e]1831 return EINVAL;
[e8199d77]1832
1833 switch (destination->sa_family) {
1834 case AF_INET:
1835 if (addrlen != sizeof(struct sockaddr_in))
1836 return EINVAL;
1837 address_in = (struct sockaddr_in *) destination;
1838 dest = &address_in->sin_addr;
1839 if (!dest->s_addr)
1840 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
1841 break;
1842
1843 case AF_INET6:
1844 default:
1845 return EAFNOSUPPORT;
[aadf01e]1846 }
[e8199d77]1847
[aadf01e]1848 fibril_rwlock_read_lock(&ip_globals.lock);
1849 route = ip_find_route(*dest);
[28a3e74]1850 /* If the local host is the destination */
[e8199d77]1851 if (route && (route->address.s_addr == dest->s_addr) &&
1852 (dest->s_addr != IPV4_LOCALHOST_ADDRESS)) {
[28a3e74]1853 /* Find the loopback device to deliver */
[836dd794]1854 dest->s_addr = IPV4_LOCALHOST_ADDRESS;
1855 route = ip_find_route(*dest);
1856 }
[e8199d77]1857
1858 if (!route || !route->netif) {
[aadf01e]1859 fibril_rwlock_read_unlock(&ip_globals.lock);
[21580dd]1860 return ENOENT;
1861 }
[e8199d77]1862
[aadf01e]1863 *device_id = route->netif->device_id;
1864 src = ip_netif_address(route->netif);
1865 fibril_rwlock_read_unlock(&ip_globals.lock);
[e8199d77]1866
[aadf01e]1867 *headerlen = sizeof(*header_in);
[88a1bb9]1868 header_in = (ipv4_pseudo_header_t *) malloc(*headerlen);
[e8199d77]1869 if (!header_in)
[aadf01e]1870 return ENOMEM;
[e8199d77]1871
1872 bzero(header_in, *headerlen);
[21580dd]1873 header_in->destination_address = dest->s_addr;
1874 header_in->source_address = src->s_addr;
1875 header_in->protocol = protocol;
1876 header_in->data_length = 0;
[14f1db0]1877 *header = header_in;
[e8199d77]1878
[21580dd]1879 return EOK;
1880}
1881
[e8199d77]1882/** Processes the IP message.
1883 *
1884 * @param[in] callid The message identifier.
1885 * @param[in] call The message parameters.
1886 * @param[out] answer The message answer parameters.
1887 * @param[out] answer_count The last parameter for the actual answer in the
1888 * answer parameter.
[1bfd3d3]1889 * @return EOK on success.
1890 * @return ENOTSUP if the message is not known.
[849ed54]1891 *
[e8199d77]1892 * @see ip_interface.h
[797b704]1893 * @see il_remote.h
[e8199d77]1894 * @see IS_NET_IP_MESSAGE()
1895 */
[797b704]1896int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
[774e6d1a]1897 size_t *answer_count)
[e8199d77]1898{
[46d4d9f]1899 packet_t *packet;
[e8199d77]1900 struct sockaddr *addr;
[797b704]1901 void *header;
1902 size_t headerlen;
[e8199d77]1903 size_t addrlen;
1904 size_t prefix;
1905 size_t suffix;
1906 size_t content;
1907 device_id_t device_id;
[02314f8]1908 int rc;
[e8199d77]1909
1910 *answer_count = 0;
[228e490]1911 switch (IPC_GET_IMETHOD(*call)) {
[e8199d77]1912 case IPC_M_PHONE_HUNGUP:
1913 return EOK;
1914
1915 case IPC_M_CONNECT_TO_ME:
[774e6d1a]1916 return ip_register(IL_GET_PROTO(*call), IL_GET_SERVICE(*call),
1917 IPC_GET_PHONE(*call), NULL);
[e8199d77]1918
[797b704]1919 case NET_IP_DEVICE:
[774e6d1a]1920 return ip_device_req_local(0, IPC_GET_DEVICE(*call),
1921 IPC_GET_SERVICE(*call));
[e8199d77]1922
1923 case NET_IP_RECEIVED_ERROR:
[02314f8]1924 rc = packet_translate_remote(ip_globals.net_phone, &packet,
[774e6d1a]1925 IPC_GET_PACKET(*call));
[02314f8]1926 if (rc != EOK)
1927 return rc;
[774e6d1a]1928 return ip_received_error_msg_local(0, IPC_GET_DEVICE(*call),
1929 packet, IPC_GET_TARGET(*call), IPC_GET_ERROR(*call));
[e8199d77]1930
1931 case NET_IP_ADD_ROUTE:
[774e6d1a]1932 return ip_add_route_req_local(0, IPC_GET_DEVICE(*call),
1933 IP_GET_ADDRESS(*call), IP_GET_NETMASK(*call),
1934 IP_GET_GATEWAY(*call));
[e8199d77]1935
1936 case NET_IP_SET_GATEWAY:
[774e6d1a]1937 return ip_set_gateway_req_local(0, IPC_GET_DEVICE(*call),
1938 IP_GET_GATEWAY(*call));
[e8199d77]1939
1940 case NET_IP_GET_ROUTE:
[7880d58]1941 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0,
1942 &addrlen);
[02314f8]1943 if (rc != EOK)
1944 return rc;
1945
[774e6d1a]1946 rc = ip_get_route_req_local(0, IP_GET_PROTOCOL(*call), addr,
[02314f8]1947 (socklen_t) addrlen, &device_id, &header, &headerlen);
1948 if (rc != EOK)
1949 return rc;
1950
[774e6d1a]1951 IPC_SET_DEVICE(*answer, device_id);
1952 IP_SET_HEADERLEN(*answer, headerlen);
[e8199d77]1953
1954 *answer_count = 2;
[02314f8]1955
1956 rc = data_reply(&headerlen, sizeof(headerlen));
1957 if (rc == EOK)
1958 rc = data_reply(header, headerlen);
[e8199d77]1959
1960 free(header);
[02314f8]1961 return rc;
[e8199d77]1962
[797b704]1963 case NET_IP_PACKET_SPACE:
[774e6d1a]1964 rc = ip_packet_size_message(IPC_GET_DEVICE(*call), &addrlen,
[02314f8]1965 &prefix, &content, &suffix);
1966 if (rc != EOK)
1967 return rc;
1968
[774e6d1a]1969 IPC_SET_ADDR(*answer, addrlen);
1970 IPC_SET_PREFIX(*answer, prefix);
1971 IPC_SET_CONTENT(*answer, content);
1972 IPC_SET_SUFFIX(*answer, suffix);
[e8199d77]1973 *answer_count = 4;
1974 return EOK;
1975
[797b704]1976 case NET_IP_SEND:
1977 rc = packet_translate_remote(ip_globals.net_phone, &packet,
1978 IPC_GET_PACKET(*call));
1979 if (rc != EOK)
1980 return rc;
1981
1982 return ip_send_msg_local(0, IPC_GET_DEVICE(*call), packet, 0,
1983 IPC_GET_ERROR(*call));
[e8199d77]1984 }
1985
1986 return ENOTSUP;
1987}
1988
[849ed54]1989int main(int argc, char *argv[])
1990{
1991 /* Start the module */
[797b704]1992 return il_module_start(SERVICE_IP);
[849ed54]1993}
1994
[21580dd]1995/** @}
1996 */
Note: See TracBrowser for help on using the repository browser.