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
Line 
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>
40#include <str_error.h>
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>
47#include <stdlib.h>
48#include <stddef.h>
49#include <stdint.h>
50#include <task.h>
51#include "addrobj.h"
52#include "icmp.h"
53#include "icmp_std.h"
54#include "icmpv6.h"
55#include "icmpv6_std.h"
56#include "inetsrv.h"
57#include "inetcfg.h"
58#include "inetping.h"
59#include "inet_link.h"
60#include "reass.h"
61#include "sroute.h"
62
63#define NAME "inetsrv"
64
65static inet_naddr_t solicited_node_mask = {
66 .version = ip_v6,
67 .addr6 = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0xff, 0, 0, 0 },
68 .prefix = 104
69};
70
71static inet_addr_t broadcast4_all_hosts = {
72 .version = ip_v4,
73 .addr = 0xffffffff
74};
75
76static inet_addr_t multicast_all_nodes = {
77 .version = ip_v6,
78 .addr6 = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 }
79};
80
81static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
82static LIST_INITIALIZE(client_list);
83
84static void inet_default_conn(ipc_call_t *, void *);
85
86static errno_t inet_init(void)
87{
88 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_init()");
89
90 port_id_t port;
91 errno_t rc = async_create_port(INTERFACE_INET,
92 inet_default_conn, NULL, &port);
93 if (rc != EOK)
94 return rc;
95
96 rc = async_create_port(INTERFACE_INETCFG,
97 inet_cfg_conn, NULL, &port);
98 if (rc != EOK)
99 return rc;
100
101 rc = async_create_port(INTERFACE_INETPING,
102 inetping_conn, NULL, &port);
103 if (rc != EOK)
104 return rc;
105
106 rc = loc_server_register(NAME);
107 if (rc != EOK) {
108 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering server: %s.", str_error(rc));
109 return EEXIST;
110 }
111
112 service_id_t sid;
113 rc = loc_service_register(SERVICE_NAME_INET, &sid);
114 if (rc != EOK) {
115 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed registering service: %s.", str_error(rc));
116 return EEXIST;
117 }
118
119 return EOK;
120}
121
122static void inet_callback_create_srv(inet_client_t *client, ipc_call_t *call)
123{
124 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_callback_create_srv()");
125
126 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
127 if (sess == NULL) {
128 async_answer_0(call, ENOMEM);
129 return;
130 }
131
132 client->sess = sess;
133 async_answer_0(call, EOK);
134}
135
136static errno_t inet_find_dir(inet_addr_t *src, inet_addr_t *dest, uint8_t tos,
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) {
159 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send: No route to destination.");
160 return ENOENT;
161 }
162
163 return EOK;
164}
165
166errno_t inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
167 int df)
168{
169 inet_dir_t dir;
170 inet_link_t *ilink;
171 errno_t rc;
172
173 if (dgram->iplink != 0) {
174 /* XXX TODO - IPv6 */
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
182 if (dgram->src.version != ip_v4 ||
183 dgram->dest.version != ip_v4)
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
194 rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir);
195 if (rc != EOK)
196 return rc;
197
198 return inet_addrobj_send_dgram(dir.aobj, &dir.ldest, dgram,
199 proto, ttl, df);
200}
201
202static errno_t inet_send(inet_client_t *client, inet_dgram_t *dgram,
203 uint8_t proto, uint8_t ttl, int df)
204{
205 return inet_route_packet(dgram, proto, ttl, df);
206}
207
208errno_t inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
209{
210 inet_dir_t dir;
211 errno_t rc;
212
213 rc = inet_find_dir(NULL, remote, tos, &dir);
214 if (rc != EOK)
215 return rc;
216
217 /* XXX dt_local? */
218
219 /* Take source address from the address object */
220 if (remote->version == ip_v4 && remote->addr == 0xffffffff) {
221 /* XXX TODO - IPv6 */
222 local->version = ip_v4;
223 local->addr = 0;
224 return EOK;
225 }
226
227 inet_naddr_addr(&dir.aobj->naddr, local);
228 return EOK;
229}
230
231static void inet_get_srcaddr_srv(inet_client_t *client, ipc_call_t *icall)
232{
233 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_get_srcaddr_srv()");
234
235 uint8_t tos = IPC_GET_ARG1(*icall);
236
237 ipc_call_t call;
238 size_t size;
239 if (!async_data_write_receive(&call, &size)) {
240 async_answer_0(&call, EREFUSED);
241 async_answer_0(icall, EREFUSED);
242 return;
243 }
244
245 if (size != sizeof(inet_addr_t)) {
246 async_answer_0(&call, EINVAL);
247 async_answer_0(icall, EINVAL);
248 return;
249 }
250
251 inet_addr_t remote;
252 errno_t rc = async_data_write_finalize(&call, &remote, size);
253 if (rc != EOK) {
254 async_answer_0(&call, rc);
255 async_answer_0(icall, rc);
256 }
257
258 inet_addr_t local;
259 rc = inet_get_srcaddr(&remote, tos, &local);
260 if (rc != EOK) {
261 async_answer_0(icall, rc);
262 return;
263 }
264
265 if (!async_data_read_receive(&call, &size)) {
266 async_answer_0(&call, EREFUSED);
267 async_answer_0(icall, EREFUSED);
268 return;
269 }
270
271 if (size != sizeof(inet_addr_t)) {
272 async_answer_0(&call, EINVAL);
273 async_answer_0(icall, EINVAL);
274 return;
275 }
276
277 rc = async_data_read_finalize(&call, &local, size);
278 if (rc != EOK) {
279 async_answer_0(&call, rc);
280 async_answer_0(icall, rc);
281 return;
282 }
283
284 async_answer_0(icall, rc);
285}
286
287static void inet_send_srv(inet_client_t *client, ipc_call_t *icall)
288{
289 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_send_srv()");
290
291 inet_dgram_t dgram;
292
293 dgram.iplink = IPC_GET_ARG1(*icall);
294 dgram.tos = IPC_GET_ARG2(*icall);
295
296 uint8_t ttl = IPC_GET_ARG3(*icall);
297 int df = IPC_GET_ARG4(*icall);
298
299 ipc_call_t call;
300 size_t size;
301 if (!async_data_write_receive(&call, &size)) {
302 async_answer_0(&call, EREFUSED);
303 async_answer_0(icall, EREFUSED);
304 return;
305 }
306
307 if (size != sizeof(inet_addr_t)) {
308 async_answer_0(&call, EINVAL);
309 async_answer_0(icall, EINVAL);
310 return;
311 }
312
313 errno_t rc = async_data_write_finalize(&call, &dgram.src, size);
314 if (rc != EOK) {
315 async_answer_0(&call, rc);
316 async_answer_0(icall, rc);
317 }
318
319 if (!async_data_write_receive(&call, &size)) {
320 async_answer_0(&call, EREFUSED);
321 async_answer_0(icall, EREFUSED);
322 return;
323 }
324
325 if (size != sizeof(inet_addr_t)) {
326 async_answer_0(&call, EINVAL);
327 async_answer_0(icall, EINVAL);
328 return;
329 }
330
331 rc = async_data_write_finalize(&call, &dgram.dest, size);
332 if (rc != EOK) {
333 async_answer_0(&call, rc);
334 async_answer_0(icall, rc);
335 }
336
337 rc = async_data_write_accept(&dgram.data, false, 0, 0, 0,
338 &dgram.size);
339 if (rc != EOK) {
340 async_answer_0(icall, rc);
341 return;
342 }
343
344 rc = inet_send(client, &dgram, client->protocol, ttl, df);
345
346 free(dgram.data);
347 async_answer_0(icall, rc);
348}
349
350static void inet_set_proto_srv(inet_client_t *client, ipc_call_t *call)
351{
352 sysarg_t proto;
353
354 proto = IPC_GET_ARG1(*call);
355 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
356
357 if (proto > UINT8_MAX) {
358 async_answer_0(call, EINVAL);
359 return;
360 }
361
362 client->protocol = proto;
363 async_answer_0(call, EOK);
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
385static void inet_default_conn(ipc_call_t *icall, void *arg)
386{
387 inet_client_t client;
388
389 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_default_conn()");
390
391 /* Accept the connection */
392 async_answer_5(icall, EOK, 0, 0, 0, 0, async_get_label());
393
394 inet_client_init(&client);
395
396 while (true) {
397 ipc_call_t call;
398 async_get_call(&call);
399 sysarg_t method = IPC_GET_IMETHOD(call);
400
401 if (!method) {
402 /* The other side has hung up */
403 async_answer_0(&call, EOK);
404 return;
405 }
406
407 switch (method) {
408 case INET_CALLBACK_CREATE:
409 inet_callback_create_srv(&client, &call);
410 break;
411 case INET_GET_SRCADDR:
412 inet_get_srcaddr_srv(&client, &call);
413 break;
414 case INET_SEND:
415 inet_send_srv(&client, &call);
416 break;
417 case INET_SET_PROTO:
418 inet_set_proto_srv(&client, &call);
419 break;
420 default:
421 async_answer_0(&call, EINVAL);
422 }
423 }
424
425 inet_client_fini(&client);
426}
427
428static inet_client_t *inet_client_find(uint8_t proto)
429{
430 fibril_mutex_lock(&client_list_lock);
431
432 list_foreach(client_list, client_list, inet_client_t, client) {
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
443errno_t inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
444{
445 async_exch_t *exch = async_exchange_begin(client->sess);
446
447 ipc_call_t answer;
448
449 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_ev_recv: iplink=%zu",
450 dgram->iplink);
451
452 aid_t req = async_send_2(exch, INET_EV_RECV, dgram->tos,
453 dgram->iplink, &answer);
454
455 errno_t rc = async_data_write_start(exch, &dgram->src, sizeof(inet_addr_t));
456 if (rc != EOK) {
457 async_exchange_end(exch);
458 async_forget(req);
459 return rc;
460 }
461
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 }
468
469 rc = async_data_write_start(exch, dgram->data, dgram->size);
470
471 async_exchange_end(exch);
472
473 if (rc != EOK) {
474 async_forget(req);
475 return rc;
476 }
477
478 errno_t retval;
479 async_wait_for(req, &retval);
480
481 return retval;
482}
483
484errno_t inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
485{
486 inet_client_t *client;
487
488 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_recv_dgram_local()");
489
490 /* ICMP and ICMPv6 messages are handled internally */
491 if (proto == IP_PROTO_ICMP)
492 return icmp_recv(dgram);
493
494 if (proto == IP_PROTO_ICMPV6)
495 return icmpv6_recv(dgram);
496
497 client = inet_client_find(proto);
498 if (client == NULL) {
499 log_msg(LOG_DEFAULT, LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
500 proto);
501 return ENOENT;
502 }
503
504 return inet_ev_recv(client, dgram);
505}
506
507errno_t inet_recv_packet(inet_packet_t *packet)
508{
509 inet_addrobj_t *addr;
510 inet_dgram_t dgram;
511
512 addr = inet_addrobj_find(&packet->dest, iaf_addr);
513 if ((addr != NULL) ||
514 (inet_naddr_compare_mask(&solicited_node_mask, &packet->dest)) ||
515 (inet_addr_compare(&multicast_all_nodes, &packet->dest)) ||
516 (inet_addr_compare(&broadcast4_all_hosts, &packet->dest))) {
517 /* Destined for one of the local addresses */
518
519 /* Check if packet is a complete datagram */
520 if (packet->offs == 0 && !packet->mf) {
521 /* It is complete deliver it immediately */
522 dgram.iplink = packet->link_id;
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 }
534 }
535
536 return ENOENT;
537}
538
539int main(int argc, char *argv[])
540{
541 errno_t rc;
542
543 printf(NAME ": HelenOS Internet Protocol service\n");
544
545 if (log_init(NAME) != EOK) {
546 printf(NAME ": Failed to initialize logging.\n");
547 return 1;
548 }
549
550 rc = inet_init();
551 if (rc != EOK)
552 return 1;
553
554 printf(NAME ": Accepting connections.\n");
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.