source: mainline/uspace/srv/inet/inet.c@ 1cc8b42

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

Correct handling of IP protocol field.

  • Property mode set to 100644
File size: 8.3 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 "inet.h"
51#include "inet_link.h"
52
53#define NAME "inet"
54
55static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg);
56
57static FIBRIL_MUTEX_INITIALIZE(client_list_lock);
58static LIST_INITIALIZE(client_list);
59
60static int inet_init(void)
61{
62 service_id_t sid;
63 int rc;
64
65 log_msg(LVL_DEBUG, "inet_init()");
66
67 async_set_client_connection(inet_client_conn);
68
69 rc = loc_server_register(NAME);
70 if (rc != EOK) {
71 log_msg(LVL_ERROR, "Failed registering server (%d).", rc);
72 return EEXIST;
73 }
74
75 rc = loc_service_register(SERVICE_NAME_INET, &sid);
76 if (rc != EOK) {
77 log_msg(LVL_ERROR, "Failed registering service (%d).", rc);
78 return EEXIST;
79 }
80
81 rc = inet_link_discovery_start();
82 if (rc != EOK)
83 return EEXIST;
84
85 return EOK;
86}
87
88static void inet_callback_create_srv(inet_client_t *client, ipc_callid_t callid,
89 ipc_call_t *call)
90{
91 log_msg(LVL_DEBUG, "inet_callback_create_srv()");
92
93 async_sess_t *sess = async_callback_receive(EXCHANGE_SERIALIZE);
94 if (sess == NULL) {
95 async_answer_0(callid, ENOMEM);
96 return;
97 }
98
99 client->sess = sess;
100 async_answer_0(callid, EOK);
101}
102
103static int inet_route_packet(inet_dgram_t *dgram, uint8_t proto, uint8_t ttl,
104 int df)
105{
106 inet_addrobj_t *addr;
107
108 addr = inet_addrobj_find(&dgram->dest, iaf_net);
109 if (addr != NULL) {
110 /* Destination is directly accessible */
111 return inet_addrobj_send_dgram(addr, dgram, proto, ttl, df);
112 }
113
114 /* TODO: Gateways */
115 log_msg(LVL_DEBUG, "inet_send: No route to destination.");
116 return ENOENT;
117}
118
119static int inet_send(inet_client_t *client, inet_dgram_t *dgram,
120 uint8_t proto, uint8_t ttl, int df)
121{
122 return inet_route_packet(dgram, proto, ttl, df);
123}
124
125static int inet_get_srcaddr(inet_client_t *client, inet_addr_t *remote,
126 uint8_t tos, inet_addr_t *local)
127{
128 inet_addrobj_t *addr;
129
130 addr = inet_addrobj_find(remote, iaf_net);
131 if (addr != NULL) {
132 /* Destination is directly accessible */
133 local->ipv4 = addr->naddr.ipv4;
134 return EOK;
135 }
136
137 return ENOENT;
138}
139
140static void inet_get_srcaddr_srv(inet_client_t *client, ipc_callid_t callid,
141 ipc_call_t *call)
142{
143 inet_addr_t remote;
144 uint8_t tos;
145 inet_addr_t local;
146 int rc;
147
148 log_msg(LVL_DEBUG, "inet_get_srcaddr_srv()");
149
150 remote.ipv4 = IPC_GET_ARG1(*call);
151 tos = IPC_GET_ARG2(*call);
152 local.ipv4 = 0;
153
154 rc = inet_get_srcaddr(client, &remote, tos, &local);
155 async_answer_1(callid, rc, local.ipv4);
156}
157
158static void inet_send_srv(inet_client_t *client, ipc_callid_t callid,
159 ipc_call_t *call)
160{
161 inet_dgram_t dgram;
162 uint8_t ttl;
163 int df;
164 int rc;
165
166 log_msg(LVL_DEBUG, "inet_send_srv()");
167
168 dgram.src.ipv4 = IPC_GET_ARG1(*call);
169 dgram.dest.ipv4 = IPC_GET_ARG2(*call);
170 dgram.tos = IPC_GET_ARG3(*call);
171 ttl = IPC_GET_ARG4(*call);
172 df = IPC_GET_ARG5(*call);
173
174 rc = async_data_write_accept(&dgram.data, false, 0, 0, 0, &dgram.size);
175 if (rc != EOK) {
176 async_answer_0(callid, rc);
177 return;
178 }
179
180 rc = inet_send(client, &dgram, client->protocol, ttl, df);
181
182 free(dgram.data);
183 async_answer_0(callid, rc);
184}
185
186static void inet_set_proto_srv(inet_client_t *client, ipc_callid_t callid,
187 ipc_call_t *call)
188{
189 sysarg_t proto;
190
191 proto = IPC_GET_ARG1(*call);
192 log_msg(LVL_DEBUG, "inet_set_proto_srv(%lu)", (unsigned long) proto);
193
194 if (proto > UINT8_MAX) {
195 async_answer_0(callid, EINVAL);
196 return;
197 }
198
199 client->protocol = proto;
200 async_answer_0(callid, EOK);
201}
202
203static void inet_client_init(inet_client_t *client)
204{
205 client->sess = NULL;
206
207 fibril_mutex_lock(&client_list_lock);
208 list_append(&client->client_list, &client_list);
209 fibril_mutex_unlock(&client_list_lock);
210}
211
212static void inet_client_fini(inet_client_t *client)
213{
214 async_hangup(client->sess);
215 client->sess = NULL;
216
217 fibril_mutex_lock(&client_list_lock);
218 list_remove(&client->client_list);
219 fibril_mutex_unlock(&client_list_lock);
220}
221
222static void inet_client_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
223{
224 inet_client_t client;
225
226 log_msg(LVL_DEBUG, "inet_client_conn()");
227
228 /* Accept the connection */
229 async_answer_0(iid, EOK);
230
231 inet_client_init(&client);
232
233 while (true) {
234 ipc_call_t call;
235 ipc_callid_t callid = async_get_call(&call);
236 sysarg_t method = IPC_GET_IMETHOD(call);
237
238 if (!method) {
239 /* The other side has hung up */
240 async_answer_0(callid, EOK);
241 return;
242 }
243
244 switch (method) {
245 case INET_CALLBACK_CREATE:
246 inet_callback_create_srv(&client, callid, &call);
247 break;
248 case INET_GET_SRCADDR:
249 inet_get_srcaddr_srv(&client, callid, &call);
250 break;
251 case INET_SEND:
252 inet_send_srv(&client, callid, &call);
253 break;
254 case INET_SET_PROTO:
255 inet_set_proto_srv(&client, callid, &call);
256 break;
257 default:
258 async_answer_0(callid, EINVAL);
259 }
260 }
261
262 inet_client_fini(&client);
263}
264
265static inet_client_t *inet_client_find(uint8_t proto)
266{
267 fibril_mutex_lock(&client_list_lock);
268
269 list_foreach(client_list, link) {
270 inet_client_t *client = list_get_instance(link, inet_client_t,
271 client_list);
272
273 if (client->protocol == proto) {
274 fibril_mutex_unlock(&client_list_lock);
275 return client;
276 }
277 }
278
279 fibril_mutex_unlock(&client_list_lock);
280 return NULL;
281}
282
283int inet_ev_recv(inet_client_t *client, inet_dgram_t *dgram)
284{
285 async_exch_t *exch = async_exchange_begin(client->sess);
286
287 ipc_call_t answer;
288 aid_t req = async_send_3(exch, INET_EV_RECV, dgram->src.ipv4,
289 dgram->dest.ipv4, dgram->tos, &answer);
290 int rc = async_data_write_start(exch, dgram->data, dgram->size);
291 async_exchange_end(exch);
292
293 if (rc != EOK) {
294 async_wait_for(req, NULL);
295 return rc;
296 }
297
298 sysarg_t retval;
299 async_wait_for(req, &retval);
300 if (retval != EOK)
301 return retval;
302
303 return EOK;
304}
305
306static int inet_recv_dgram_local(inet_dgram_t *dgram, uint8_t proto)
307{
308 inet_client_t *client;
309
310 log_msg(LVL_DEBUG, "inet_recv_dgram_local()");
311
312 client = inet_client_find(proto);
313 if (client == NULL) {
314 log_msg(LVL_DEBUG, "No client found for protocol 0x%" PRIx8,
315 proto);
316 return ENOENT;
317 }
318
319 return inet_ev_recv(client, dgram);
320}
321
322int inet_recv_packet(inet_packet_t *packet)
323{
324 inet_addrobj_t *addr;
325 inet_dgram_t dgram;
326
327 addr = inet_addrobj_find(&packet->dest, iaf_addr);
328 if (addr != NULL) {
329 /* Destined for one of the local addresses */
330
331 /* XXX Reassemble packets */
332 dgram.src = packet->src;
333 dgram.dest = packet->dest;
334 dgram.tos = packet->tos;
335 dgram.data = packet->data;
336 dgram.size = packet->size;
337
338 return inet_recv_dgram_local(&dgram, packet->proto);
339 }
340
341 return ENOENT;
342}
343
344int main(int argc, char *argv[])
345{
346 int rc;
347
348 printf(NAME ": HelenOS Internet Protocol service\n");
349
350 if (log_init(NAME, LVL_DEBUG) != EOK) {
351 printf(NAME ": Failed to initialize logging.\n");
352 return 1;
353 }
354
355 rc = inet_init();
356 if (rc != EOK)
357 return 1;
358
359 printf(NAME ": Accepting connections.\n");
360 task_retval(0);
361 async_manager();
362
363 /* Not reached */
364 return 0;
365}
366
367/** @}
368 */
Note: See TracBrowser for help on using the repository browser.