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

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

Move IP module messages definitions to standard library.

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