source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ eec201d

Last change on this file since eec201d was f5837524, checked in by Jakub Jermar <jakub@…>, 7 years ago

Use user-defined labels instead of phone hashes

This commit changes the way how the async framework maps incomming calls
to connections. Instead of abusing the kernel addresses of attached
phones as identifiers, the IPC_M_CONNECT_TO_ME and IPC_M_CONNECT_ME_TO
messages allow the server to specify an arbitrary label which is
remembered in the connected phone and consequently imprinted on each
call which is routed through this phone.

The async framework uses the address of the connection structure as the
label. This removes the need for a connection hash table because each
incoming call already remembers the connection in its label.

To disambiguate this new label and the other user-defined label used for
answers, the call structure now has the request_label member for the
former and answer_label member for the latter.

This commit also moves the kernel definition of ipc_data_t to abi/ and
removes the uspace redefinition thereof. Finally, when forwarding the
IPC_M_CONNECT_TO_ME call, the phone capability and the kernel object
allocated in request_process are now correctly disposed of.

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