source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 13.0 KB
RevLine 
[c76e926]1/*
2 * Copyright (c) 2012 Jiri Svoboda
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 inet
30 * @{
31 */
32/**
33 * @file
34 * @brief Internet Protocol service
35 */
36
37#include <adt/list.h>
38#include <async.h>
39#include <errno.h>
[c1694b6b]40#include <str_error.h>
[c76e926]41#include <fibril_synch.h>
42#include <io/log.h>
43#include <ipc/inet.h>
44#include <ipc/services.h>
45#include <loc.h>
46#include <stdio.h>
[ecff3d9]47#include <stdlib.h>
[8d2dd7f2]48#include <stddef.h>
49#include <stdint.h>
[1c635d6]50#include <task.h>
[ceba4bed]51#include "addrobj.h"
[637a3b4]52#include "icmp.h"
53#include "icmp_std.h"
[1d24ad3]54#include "icmpv6.h"
55#include "icmpv6_std.h"
[b4ec1ea]56#include "inetsrv.h"
[0e25780]57#include "inetcfg.h"
[6428115]58#include "inetping.h"
[e2e56e67]59#include "inet_link.h"
[7f95c904]60#include "reass.h"
[8bf672d]61#include "sroute.h"
[c76e926]62
[b4ec1ea]63#define NAME "inetsrv"
[c76e926]64
[9ae6fc7]65static inet_naddr_t solicited_node_mask = {
[f023251]66 .version = ip_v6,
[9ae6fc7]67 .addr6 = {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, 0, 0, 0},
68 .prefix = 104
69};
70
[695b6ff]71static inet_addr_t broadcast4_all_hosts = {
[f023251]72 .version = ip_v4,
[695b6ff]73 .addr = 0xffffffff
74};
75
[9ae6fc7]76static inet_addr_t multicast_all_nodes = {
[f023251]77 .version = ip_v6,
[9ae6fc7]78 .addr6 = {0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
79};
80
[c76e926]81static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
82static LIST_INITIALIZE(client_list);
83
[f9b2cb4c]84static void inet_default_conn(ipc_callid_t, ipc_call_t *, void *);
85
[b7fd2a0]86static errno_t inet_init(void)
[c76e926]87{
[a1a101d]88 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
[1038a9c]89
[f9b2cb4c]90 port_id_t port;
[b7fd2a0]91 errno_t rc = async_create_port(INTERFACE_INET,
[f9b2cb4c]92 inet_default_conn, NULL, &port);
93 if (rc != EOK)
94 return rc;
[1038a9c]95
[f9b2cb4c]96 rc = async_create_port(INTERFACE_INETCFG,
97 inet_cfg_conn, NULL, &port);
98 if (rc != EOK)
99 return rc;
[1038a9c]100
[f9b2cb4c]101 rc = async_create_port(INTERFACE_INETPING,
102 inetping_conn, NULL, &port);
103 if (rc != EOK)
104 return rc;
[1038a9c]105
[f9b2cb4c]106 rc = loc_server_register(NAME);
[c76e926]107 if (rc != EOK) {
[c1694b6b]108 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server: %s.", str_error(rc));
[c76e926]109 return EEXIST;
110 }
[1038a9c]111
[f9b2cb4c]112 service_id_t sid;
113 rc = loc_service_register(SERVICE_NAME_INET, &sid);
[6428115]114 if (rc != EOK) {
[c1694b6b]115 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service: %s.", str_error(rc));
[6428115]116 return EEXIST;
117 }
[1038a9c]118
[c76e926]119 return EOK;
120}
121
[ceba4bed]122static void inet_callback_create_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]123 ipc_call_t *call)
124{
[a1a101d]125 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
[c76e926]126
127 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
128 if (sess == NULL) {
129 async_answer_0(callid, ENOMEM);
130 return;
131 }
132
133 client->sess = sess;
134 async_answer_0(callid, EOK);
135}
136
[b7fd2a0]137static errno_t inet_find_dir(inet_addr_t *src, inet_addr_t *dest, uint8_t tos,
[8bf672d]138 inet_dir_t *dir)
139{
140 inet_sroute_t *sr;
141
142 /* XXX Handle case where source address is specified */
143 (void) src;
144
145 dir->aobj = inet_addrobj_find(dest, iaf_net);
146 if (dir->aobj != NULL) {
147 dir->ldest = *dest;
148 dir->dtype = dt_direct;
149 } else {
150 /* No direct path, try using a static route */
151 sr = inet_sroute_find(dest);
152 if (sr != NULL) {
153 dir->aobj = inet_addrobj_find(&sr->router, iaf_net);
154 dir->ldest = sr->router;
155 dir->dtype = dt_router;
156 }
157 }
158
159 if (dir->aobj == NULL) {
[a1a101d]160 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
[8bf672d]161 return ENOENT;
162 }
163
164 return EOK;
165}
166
[b7fd2a0]167errno_t inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
[2ff150e]168 int df)
[ceba4bed]169{
[8bf672d]170 inet_dir_t dir;
[695b6ff]171 inet_link_t *ilink;
[b7fd2a0]172 errno_t rc;
[ceba4bed]173
[695b6ff]174 if (dgram->iplink != 0) {
[f023251]175 /* XXX TODO - IPv6 */
[695b6ff]176 log_msg(LOG_DEFAULT, LVL_DEBUG, "dgram directly to iplink %zu",
177 dgram->iplink);
178 /* Send packet directly to the specified IP link */
179 ilink = inet_link_get_by_id(dgram->iplink);
180 if (ilink == 0)
181 return ENOENT;
182
[f023251]183 if (dgram->src.version != ip_v4 ||
184 dgram->dest.version != ip_v4)
[695b6ff]185 return EINVAL;
186
187 return inet_link_send_dgram(ilink, dgram->src.addr,
188 dgram->dest.addr, dgram, proto, ttl, df);
189 }
190
191 log_msg(LOG_DEFAULT, LVL_DEBUG, "dgram to be routed");
192
193 /* Route packet using source/destination addresses */
194
[8bf672d]195 rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir);
196 if (rc != EOK)
197 return rc;
[ceba4bed]198
[8bf672d]199 return inet_addrobj_send_dgram(dir.aobj, &dir.ldest, dgram,
200 proto, ttl, df);
[ceba4bed]201}
202
[b7fd2a0]203static errno_t inet_send(inet_client_t *client, inet_dgram_t *dgram,
[2ff150e]204 uint8_t proto, uint8_t ttl, int df)
[e767dbf]205{
[2ff150e]206 return inet_route_packet(dgram, proto, ttl, df);
[e767dbf]207}
208
[b7fd2a0]209errno_t inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
[bd8bfc5a]210{
[8bf672d]211 inet_dir_t dir;
[b7fd2a0]212 errno_t rc;
[bd8bfc5a]213
[8bf672d]214 rc = inet_find_dir(NULL, remote, tos, &dir);
215 if (rc != EOK)
216 return rc;
[bd8bfc5a]217
[8bf672d]218 /* XXX dt_local? */
219
220 /* Take source address from the address object */
[f023251]221 if (remote->version == ip_v4 && remote->addr == 0xffffffff) {
222 /* XXX TODO - IPv6 */
223 local->version = ip_v4;
[695b6ff]224 local->addr = 0;
225 return EOK;
226 }
[f023251]227
[a2e3ee6]228 inet_naddr_addr(&dir.aobj->naddr, local);
[8bf672d]229 return EOK;
[bd8bfc5a]230}
231
[d8b47eca]232static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t iid,
233 ipc_call_t *icall)
[ecff3d9]234{
[a2e3ee6]235 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
236
[d8b47eca]237 uint8_t tos = IPC_GET_ARG1(*icall);
238
239 ipc_callid_t callid;
240 size_t size;
241 if (!async_data_write_receive(&callid, &size)) {
242 async_answer_0(callid, EREFUSED);
243 async_answer_0(iid, EREFUSED);
244 return;
245 }
246
247 if (size != sizeof(inet_addr_t)) {
248 async_answer_0(callid, EINVAL);
249 async_answer_0(iid, EINVAL);
250 return;
251 }
[a2e3ee6]252
[02a09ed]253 inet_addr_t remote;
[b7fd2a0]254 errno_t rc = async_data_write_finalize(callid, &remote, size);
[d8b47eca]255 if (rc != EOK) {
256 async_answer_0(callid, rc);
257 async_answer_0(iid, rc);
258 }
[02a09ed]259
[bd8bfc5a]260 inet_addr_t local;
[d8b47eca]261 rc = inet_get_srcaddr(&remote, tos, &local);
[a2e3ee6]262 if (rc != EOK) {
[d8b47eca]263 async_answer_0(iid, rc);
[a2e3ee6]264 return;
265 }
266
[d8b47eca]267 if (!async_data_read_receive(&callid, &size)) {
268 async_answer_0(callid, EREFUSED);
269 async_answer_0(iid, EREFUSED);
270 return;
271 }
272
273 if (size != sizeof(inet_addr_t)) {
[02a09ed]274 async_answer_0(callid, EINVAL);
[d8b47eca]275 async_answer_0(iid, EINVAL);
[a2e3ee6]276 return;
277 }
278
[d8b47eca]279 rc = async_data_read_finalize(callid, &local, size);
280 if (rc != EOK) {
281 async_answer_0(callid, rc);
282 async_answer_0(iid, rc);
283 return;
284 }
285
286 async_answer_0(iid, rc);
[ecff3d9]287}
288
[d8b47eca]289static void inet_send_srv(inet_client_t *client, ipc_callid_t iid,
290 ipc_call_t *icall)
[c76e926]291{
[a1a101d]292 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
[a2e3ee6]293
294 inet_dgram_t dgram;
295
[695b6ff]296 dgram.iplink = IPC_GET_ARG1(*icall);
297 dgram.tos = IPC_GET_ARG2(*icall);
[a2e3ee6]298
[695b6ff]299 uint8_t ttl = IPC_GET_ARG3(*icall);
[a91a935]300 int df = IPC_GET_ARG4(*icall);
[a2e3ee6]301
[d8b47eca]302 ipc_callid_t callid;
303 size_t size;
304 if (!async_data_write_receive(&callid, &size)) {
305 async_answer_0(callid, EREFUSED);
306 async_answer_0(iid, EREFUSED);
307 return;
308 }
309
310 if (size != sizeof(inet_addr_t)) {
311 async_answer_0(callid, EINVAL);
312 async_answer_0(iid, EINVAL);
313 return;
314 }
315
[b7fd2a0]316 errno_t rc = async_data_write_finalize(callid, &dgram.src, size);
[d8b47eca]317 if (rc != EOK) {
318 async_answer_0(callid, rc);
319 async_answer_0(iid, rc);
320 }
321
322 if (!async_data_write_receive(&callid, &size)) {
323 async_answer_0(callid, EREFUSED);
324 async_answer_0(iid, EREFUSED);
325 return;
326 }
327
328 if (size != sizeof(inet_addr_t)) {
329 async_answer_0(callid, EINVAL);
330 async_answer_0(iid, EINVAL);
331 return;
332 }
333
334 rc = async_data_write_finalize(callid, &dgram.dest, size);
[ecff3d9]335 if (rc != EOK) {
336 async_answer_0(callid, rc);
[d8b47eca]337 async_answer_0(iid, rc);
338 }
339
340 rc = async_data_write_accept(&dgram.data, false, 0, 0, 0,
341 &dgram.size);
342 if (rc != EOK) {
343 async_answer_0(iid, rc);
[ecff3d9]344 return;
345 }
[a2e3ee6]346
[2ff150e]347 rc = inet_send(client, &dgram, client->protocol, ttl, df);
[a2e3ee6]348
[59157eb]349 free(dgram.data);
[d8b47eca]350 async_answer_0(iid, rc);
[c76e926]351}
352
[ceba4bed]353static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
[c76e926]354 ipc_call_t *call)
355{
356 sysarg_t proto;
357
358 proto = IPC_GET_ARG1(*call);
[a1a101d]359 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
[c76e926]360
361 if (proto > UINT8_MAX) {
362 async_answer_0(callid, EINVAL);
363 return;
364 }
365
366 client->protocol = proto;
367 async_answer_0(callid, EOK);
368}
369
370static void inet_client_init(inet_client_t *client)
371{
372 client->sess = NULL;
373
374 fibril_mutex_lock(&client_list_lock);
375 list_append(&client->client_list, &client_list);
376 fibril_mutex_unlock(&client_list_lock);
377}
378
379static void inet_client_fini(inet_client_t *client)
380{
381 async_hangup(client->sess);
382 client->sess = NULL;
383
384 fibril_mutex_lock(&client_list_lock);
385 list_remove(&client->client_list);
386 fibril_mutex_unlock(&client_list_lock);
387}
388
[0e25780]389static void inet_default_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
[c76e926]390{
391 inet_client_t client;
392
[a1a101d]393 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
[c76e926]394
395 /* Accept the connection */
396 async_answer_0(iid, EOK);
397
398 inet_client_init(&client);
399
400 while (true) {
401 ipc_call_t call;
402 ipc_callid_t callid = async_get_call(&call);
403 sysarg_t method = IPC_GET_IMETHOD(call);
404
405 if (!method) {
406 /* The other side has hung up */
407 async_answer_0(callid, EOK);
408 return;
409 }
410
411 switch (method) {
412 case INET_CALLBACK_CREATE:
[ceba4bed]413 inet_callback_create_srv(&client, callid, &call);
[c76e926]414 break;
[ecff3d9]415 case INET_GET_SRCADDR:
[ceba4bed]416 inet_get_srcaddr_srv(&client, callid, &call);
[ecff3d9]417 break;
[c76e926]418 case INET_SEND:
[ceba4bed]419 inet_send_srv(&client, callid, &call);
[c76e926]420 break;
421 case INET_SET_PROTO:
[ceba4bed]422 inet_set_proto_srv(&client, callid, &call);
[c76e926]423 break;
424 default:
425 async_answer_0(callid, EINVAL);
426 }
427 }
428
429 inet_client_fini(&client);
430}
431
[fe4310f]432static inet_client_t *inet_client_find(uint8_t proto)
433{
434 fibril_mutex_lock(&client_list_lock);
435
[feeac0d]436 list_foreach(client_list, client_list, inet_client_t, client) {
[fe4310f]437 if (client->protocol == proto) {
438 fibril_mutex_unlock(&client_list_lock);
439 return client;
440 }
441 }
442
443 fibril_mutex_unlock(&client_list_lock);
444 return NULL;
445}
446
[b7fd2a0]447errno_t inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
[59157eb]448{
[02a09ed]449 async_exch_t *exch = async_exchange_begin(client->sess);
[8d48c7e]450
[02a09ed]451 ipc_call_t answer;
[8d48c7e]452
[ac415d50]453 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_ev_recv: iplink=%zu",
[8d48c7e]454 dgram->iplink);
455
456 aid_t req = async_send_2(exch, INET_EV_RECV, dgram->tos,
457 dgram->iplink, &answer);
458
[b7fd2a0]459 errno_t rc = async_data_write_start(exch, &dgram->src, sizeof(inet_addr_t));
[02a09ed]460 if (rc != EOK) {
461 async_exchange_end(exch);
462 async_forget(req);
[a2e3ee6]463 return rc;
[02a09ed]464 }
[8d48c7e]465
[02a09ed]466 rc = async_data_write_start(exch, &dgram->dest, sizeof(inet_addr_t));
467 if (rc != EOK) {
468 async_exchange_end(exch);
469 async_forget(req);
470 return rc;
471 }
[8d48c7e]472
[a2e3ee6]473 rc = async_data_write_start(exch, dgram->data, dgram->size);
[8d48c7e]474
[59157eb]475 async_exchange_end(exch);
[8d48c7e]476
[59157eb]477 if (rc != EOK) {
[50b581d]478 async_forget(req);
[59157eb]479 return rc;
480 }
[8d48c7e]481
[b7fd2a0]482 errno_t retval;
[59157eb]483 async_wait_for(req, &retval);
[8d48c7e]484
[25a179e]485 return retval;
[59157eb]486}
487
[b7fd2a0]488errno_t inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
[e767dbf]489{
[fe4310f]490 inet_client_t *client;
491
[a1a101d]492 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
[fe4310f]493
[1d24ad3]494 /* ICMP and ICMPv6 messages are handled internally */
[637a3b4]495 if (proto == IP_PROTO_ICMP)
496 return icmp_recv(dgram);
[8d48c7e]497
[1d24ad3]498 if (proto == IP_PROTO_ICMPV6)
499 return icmpv6_recv(dgram);
[637a3b4]500
[fe4310f]501 client = inet_client_find(proto);
502 if (client == NULL) {
[a1a101d]503 log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
[fe4310f]504 proto);
505 return ENOENT;
506 }
507
508 return inet_ev_recv(client, dgram);
509}
510
[b7fd2a0]511errno_t inet_recv_packet(inet_packet_t *packet)
[fe4310f]512{
513 inet_addrobj_t *addr;
514 inet_dgram_t dgram;
515
516 addr = inet_addrobj_find(&packet->dest, iaf_addr);
[9ae6fc7]517 if ((addr != NULL) ||
518 (inet_naddr_compare_mask(&solicited_node_mask, &packet->dest)) ||
[1b20da0]519 (inet_addr_compare(&multicast_all_nodes, &packet->dest)) ||
[695b6ff]520 (inet_addr_compare(&broadcast4_all_hosts, &packet->dest))) {
[fe4310f]521 /* Destined for one of the local addresses */
522
[7f95c904]523 /* Check if packet is a complete datagram */
524 if (packet->offs == 0 && !packet->mf) {
525 /* It is complete deliver it immediately */
[8d48c7e]526 dgram.iplink = packet->link_id;
[7f95c904]527 dgram.src = packet->src;
528 dgram.dest = packet->dest;
529 dgram.tos = packet->tos;
530 dgram.data = packet->data;
531 dgram.size = packet->size;
532
533 return inet_recv_dgram_local(&dgram, packet->proto);
534 } else {
535 /* It is a fragment, queue it for reassembly */
536 inet_reass_queue_packet(packet);
537 }
[fe4310f]538 }
539
540 return ENOENT;
[e767dbf]541}
542
[c76e926]543int main(int argc, char *argv[])
544{
[b7fd2a0]545 errno_t rc;
[c76e926]546
[e2e56e67]547 printf(NAME ": HelenOS Internet Protocol service\n");
[c76e926]548
[267f235]549 if (log_init(NAME) != EOK) {
[e2e56e67]550 printf(NAME ": Failed to initialize logging.\n");
[c76e926]551 return 1;
552 }
553
554 rc = inet_init();
555 if (rc != EOK)
556 return 1;
557
[ecff3d9]558 printf(NAME ": Accepting connections.\n");
[c76e926]559 task_retval(0);
560 async_manager();
561
562 /* Not reached */
563 return 0;
564}
565
566/** @}
567 */
Note: See TracBrowser for help on using the repository browser.