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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e8199d77 was e8199d77, checked in by Jakub Jermar <jakub@…>, 15 years ago

Cleanup ip.

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