source: mainline/uspace/srv/inet/inet.c@ 8bf672d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8bf672d was 8bf672d, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Static route configuration.

  • Property mode set to 100644
File size: 9.9 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 <fibril_synch.h>
41#include <io/log.h>
42#include <ipc/inet.h>
43#include <ipc/services.h>
44#include <loc.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <sys/types.h>
48
49#include "addrobj.h"
50#include "icmp.h"
51#include "icmp_std.h"
52#include "inet.h"
53#include "inetcfg.h"
54#include "inetping.h"
55#include "inet_link.h"
56#include "sroute.h"
57
58#define NAME "inet"
59
60static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
61
62static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
63static LIST_INITIALIZE(client_list);
64
65static int inet_init(void)
66{
67 service_id_t sid;
68 int rc;
69
70 log_msg(LVL_DEBUG, "inet_init()");
71
72 async_set_client_connection(inet_client_conn);
73
74 rc = loc_server_register(NAME);
75 if (rc != EOK) {
76 log_msg(LVL_ERROR, "Failed registering server (%d).", rc);
77 return EEXIST;
78 }
79
80 rc = loc_service_register_with_iface(SERVICE_NAME_INET, &sid,
81 INET_PORT_DEFAULT);
82 if (rc != EOK) {
83 log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
84 return EEXIST;
85 }
86
87 rc = loc_service_register_with_iface(SERVICE_NAME_INETCFG, &sid,
88 INET_PORT_CFG);
89 if (rc != EOK) {
90 log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
91 return EEXIST;
92 }
93
94 rc = loc_service_register_with_iface(SERVICE_NAME_INETPING, &sid,
95 INET_PORT_PING);
96 if (rc != EOK) {
97 log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
98 return EEXIST;
99 }
100
101 rc = inet_link_discovery_start();
102 if (rc != EOK)
103 return EEXIST;
104
105 return EOK;
106}
107
108static void inet_callback_create_srv(inet_client_t *client, ipc_callid_t callid,
109 ipc_call_t *call)
110{
111 log_msg(LVL_DEBUG, "inet_callback_create_srv()");
112
113 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
114 if (sess == NULL) {
115 async_answer_0(callid, ENOMEM);
116 return;
117 }
118
119 client->sess = sess;
120 async_answer_0(callid, EOK);
121}
122
123static int inet_find_dir(inet_addr_t *src, inet_addr_t *dest, uint8_t tos,
124 inet_dir_t *dir)
125{
126 inet_sroute_t *sr;
127
128 /* XXX Handle case where source address is specified */
129 (void) src;
130
131 dir->aobj = inet_addrobj_find(dest, iaf_net);
132 if (dir->aobj != NULL) {
133 dir->ldest = *dest;
134 dir->dtype = dt_direct;
135 } else {
136 /* No direct path, try using a static route */
137 sr = inet_sroute_find(dest);
138 if (sr != NULL) {
139 dir->aobj = inet_addrobj_find(&sr->router, iaf_net);
140 dir->ldest = sr->router;
141 dir->dtype = dt_router;
142 }
143 }
144
145 if (dir->aobj == NULL) {
146 log_msg(LVL_DEBUG, "inet_send: No route to destination.");
147 return ENOENT;
148 }
149
150 return EOK;
151}
152
153int inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
154 int df)
155{
156 inet_dir_t dir;
157 int rc;
158
159 rc = inet_find_dir(&dgram->src, &dgram->dest, dgram->tos, &dir);
160 if (rc != EOK)
161 return rc;
162
163 return inet_addrobj_send_dgram(dir.aobj, &dir.ldest, dgram,
164 proto, ttl, df);
165}
166
167static int inet_send(inet_client_t *client, inet_dgram_t *dgram,
168 uint8_t proto, uint8_t ttl, int df)
169{
170 return inet_route_packet(dgram, proto, ttl, df);
171}
172
173int inet_get_srcaddr(inet_addr_t *remote, uint8_t tos, inet_addr_t *local)
174{
175 inet_dir_t dir;
176 int rc;
177
178 rc = inet_find_dir(NULL, remote, tos, &dir);
179 if (rc != EOK)
180 return rc;
181
182 /* XXX dt_local? */
183
184 /* Take source address from the address object */
185 local->ipv4 = dir.aobj->naddr.ipv4;
186 return EOK;
187}
188
189static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t callid,
190 ipc_call_t *call)
191{
192 inet_addr_t remote;
193 uint8_t tos;
194 inet_addr_t local;
195 int rc;
196
197 log_msg(LVL_DEBUG, "inet_get_srcaddr_srv()");
198
199 remote.ipv4 = IPC_GET_ARG1(*call);
200 tos = IPC_GET_ARG2(*call);
201 local.ipv4 = 0;
202
203 rc = inet_get_srcaddr(&remote, tos, &local);
204 async_answer_1(callid, rc, local.ipv4);
205}
206
207static void inet_send_srv(inet_client_t *client, ipc_callid_t callid,
208 ipc_call_t *call)
209{
210 inet_dgram_t dgram;
211 uint8_t ttl;
212 int df;
213 int rc;
214
215 log_msg(LVL_DEBUG, "inet_send_srv()");
216
217 dgram.src.ipv4 = IPC_GET_ARG1(*call);
218 dgram.dest.ipv4 = IPC_GET_ARG2(*call);
219 dgram.tos = IPC_GET_ARG3(*call);
220 ttl = IPC_GET_ARG4(*call);
221 df = IPC_GET_ARG5(*call);
222
223 rc = async_data_write_accept(&dgram.data, false, 0, 0, 0, &dgram.size);
224 if (rc != EOK) {
225 async_answer_0(callid, rc);
226 return;
227 }
228
229 rc = inet_send(client, &dgram, client->protocol, ttl, df);
230
231 free(dgram.data);
232 async_answer_0(callid, rc);
233}
234
235static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
236 ipc_call_t *call)
237{
238 sysarg_t proto;
239
240 proto = IPC_GET_ARG1(*call);
241 log_msg(LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
242
243 if (proto > UINT8_MAX) {
244 async_answer_0(callid, EINVAL);
245 return;
246 }
247
248 client->protocol = proto;
249 async_answer_0(callid, EOK);
250}
251
252static void inet_client_init(inet_client_t *client)
253{
254 client->sess = NULL;
255
256 fibril_mutex_lock(&client_list_lock);
257 list_append(&client->client_list, &client_list);
258 fibril_mutex_unlock(&client_list_lock);
259}
260
261static void inet_client_fini(inet_client_t *client)
262{
263 async_hangup(client->sess);
264 client->sess = NULL;
265
266 fibril_mutex_lock(&client_list_lock);
267 list_remove(&client->client_list);
268 fibril_mutex_unlock(&client_list_lock);
269}
270
271static void inet_default_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
272{
273 inet_client_t client;
274
275 log_msg(LVL_DEBUG, "inet_default_conn()");
276
277 /* Accept the connection */
278 async_answer_0(iid, EOK);
279
280 inet_client_init(&client);
281
282 while (true) {
283 ipc_call_t call;
284 ipc_callid_t callid = async_get_call(&call);
285 sysarg_t method = IPC_GET_IMETHOD(call);
286
287 if (!method) {
288 /* The other side has hung up */
289 async_answer_0(callid, EOK);
290 return;
291 }
292
293 switch (method) {
294 case INET_CALLBACK_CREATE:
295 inet_callback_create_srv(&client, callid, &call);
296 break;
297 case INET_GET_SRCADDR:
298 inet_get_srcaddr_srv(&client, callid, &call);
299 break;
300 case INET_SEND:
301 inet_send_srv(&client, callid, &call);
302 break;
303 case INET_SET_PROTO:
304 inet_set_proto_srv(&client, callid, &call);
305 break;
306 default:
307 async_answer_0(callid, EINVAL);
308 }
309 }
310
311 inet_client_fini(&client);
312}
313
314static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
315{
316 sysarg_t port;
317
318 port = IPC_GET_ARG1(*icall);
319
320 switch (port) {
321 case INET_PORT_DEFAULT:
322 inet_default_conn(iid, icall, arg);
323 break;
324 case INET_PORT_CFG:
325 inet_cfg_conn(iid, icall, arg);
326 break;
327 case INET_PORT_PING:
328 inetping_conn(iid, icall, arg);
329 break;
330 default:
331 async_answer_0(iid, ENOTSUP);
332 break;
333 }
334}
335
336static inet_client_t *inet_client_find(uint8_t proto)
337{
338 fibril_mutex_lock(&client_list_lock);
339
340 list_foreach(client_list, link) {
341 inet_client_t *client = list_get_instance(link, inet_client_t,
342 client_list);
343
344 if (client->protocol == proto) {
345 fibril_mutex_unlock(&client_list_lock);
346 return client;
347 }
348 }
349
350 fibril_mutex_unlock(&client_list_lock);
351 return NULL;
352}
353
354int inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
355{
356 async_exch_t *exch = async_exchange_begin(client->sess);
357
358 ipc_call_t answer;
359 aid_t req = async_send_3(exch, INET_EV_RECV, dgram->src.ipv4,
360 dgram->dest.ipv4, dgram->tos, &answer);
361 int rc = async_data_write_start(exch, dgram->data, dgram->size);
362 async_exchange_end(exch);
363
364 if (rc != EOK) {
365 async_wait_for(req, NULL);
366 return rc;
367 }
368
369 sysarg_t retval;
370 async_wait_for(req, &retval);
371 if (retval != EOK)
372 return retval;
373
374 return EOK;
375}
376
377static int inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
378{
379 inet_client_t *client;
380
381 log_msg(LVL_DEBUG, "inet_recv_dgram_local()");
382
383 /* ICMP messages are handled internally */
384 if (proto == IP_PROTO_ICMP)
385 return icmp_recv(dgram);
386
387 client = inet_client_find(proto);
388 if (client == NULL) {
389 log_msg(LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
390 proto);
391 return ENOENT;
392 }
393
394 return inet_ev_recv(client, dgram);
395}
396
397int inet_recv_packet(inet_packet_t *packet)
398{
399 inet_addrobj_t *addr;
400 inet_dgram_t dgram;
401
402 addr = inet_addrobj_find(&packet->dest, iaf_addr);
403 if (addr != NULL) {
404 /* Destined for one of the local addresses */
405
406 /* XXX Reassemble packets */
407 dgram.src = packet->src;
408 dgram.dest = packet->dest;
409 dgram.tos = packet->tos;
410 dgram.data = packet->data;
411 dgram.size = packet->size;
412
413 return inet_recv_dgram_local(&dgram, packet->proto);
414 }
415
416 return ENOENT;
417}
418
419int main(int argc, char *argv[])
420{
421 int rc;
422
423 printf(NAME ": HelenOS Internet Protocol service\n");
424
425 if (log_init(NAME, LVL_DEBUG) != EOK) {
426 printf(NAME ": Failed to initialize logging.\n");
427 return 1;
428 }
429
430 rc = inet_init();
431 if (rc != EOK)
432 return 1;
433
434 printf(NAME ": Accepting connections.\n");
435 task_retval(0);
436 async_manager();
437
438 /* Not reached */
439 return 0;
440}
441
442/** @}
443 */
Note: See TracBrowser for help on using the repository browser.