source: mainline/uspace/srv/net/inetsrv/inetsrv.c@ 3e6a98c5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3e6a98c5 was a1a101d, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

Get rid of log_log_msg()

All calls to log_msg(LVL_*) were rewritten to
log_msg(LOG_DEFAULT, LVL_*).

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