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

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

networking stack: convert to the new async framework

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