source: mainline/uspace/srv/net/inetsrv/inet_link.c@ 0aa06cbe

Last change on this file since 0aa06cbe was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 11.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
35 */
36
37#include <stdbool.h>
38#include <errno.h>
39#include <str_error.h>
40#include <fibril_synch.h>
41#include <inet/iplink.h>
42#include <io/log.h>
43#include <loc.h>
44#include <stdlib.h>
45#include <str.h>
46#include "addrobj.h"
47#include "inetsrv.h"
48#include "inet_link.h"
49#include "pdu.h"
50
51static bool first_link = true;
52static bool first_link6 = true;
53
54static FIBRIL_MUTEX_INITIALIZE(ip_ident_lock);
55static uint16_t ip_ident = 0;
56
57static errno_t inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
58static errno_t inet_iplink_change_addr(iplink_t *, addr48_t);
59static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
60
61static iplink_ev_ops_t inet_iplink_ev_ops = {
62 .recv = inet_iplink_recv,
63 .change_addr = inet_iplink_change_addr,
64};
65
66static LIST_INITIALIZE(inet_links);
67static FIBRIL_MUTEX_INITIALIZE(inet_links_lock);
68
69static addr128_t link_local_node_ip =
70 {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xfe, 0, 0, 0};
71
72static void inet_link_local_node_ip(addr48_t mac_addr,
73 addr128_t ip_addr)
74{
75 memcpy(ip_addr, link_local_node_ip, 16);
76
77 ip_addr[8] = mac_addr[0] ^ 0x02;
78 ip_addr[9] = mac_addr[1];
79 ip_addr[10] = mac_addr[2];
80 ip_addr[13] = mac_addr[3];
81 ip_addr[14] = mac_addr[4];
82 ip_addr[15] = mac_addr[5];
83}
84
85static errno_t inet_iplink_recv(iplink_t *iplink, iplink_recv_sdu_t *sdu, ip_ver_t ver)
86{
87 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv()");
88
89 errno_t rc;
90 inet_packet_t packet;
91 inet_link_t *ilink;
92
93 ilink = (inet_link_t *)iplink_get_userptr(iplink);
94
95 switch (ver) {
96 case ip_v4:
97 rc = inet_pdu_decode(sdu->data, sdu->size, ilink->svc_id,
98 &packet);
99 break;
100 case ip_v6:
101 rc = inet_pdu_decode6(sdu->data, sdu->size, ilink->svc_id,
102 &packet);
103 break;
104 default:
105 log_msg(LOG_DEFAULT, LVL_DEBUG, "invalid IP version");
106 return EINVAL;
107 }
108
109 if (rc != EOK) {
110 log_msg(LOG_DEFAULT, LVL_DEBUG, "failed decoding PDU");
111 return rc;
112 }
113
114 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_recv: link_id=%zu", packet.link_id);
115 log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet()");
116 rc = inet_recv_packet(&packet);
117 log_msg(LOG_DEFAULT, LVL_DEBUG, "call inet_recv_packet -> %s", str_error_name(rc));
118 free(packet.data);
119
120 return rc;
121}
122
123static errno_t inet_iplink_change_addr(iplink_t *iplink, addr48_t mac)
124{
125 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_change_addr(): "
126 "new addr=%02x:%02x:%02x:%02x:%02x:%02x",
127 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
128
129 list_foreach(inet_links, link_list, inet_link_t, ilink) {
130 if (ilink->sess == iplink->sess)
131 memcpy(&ilink->mac, mac, sizeof(addr48_t));
132 }
133
134 return EOK;
135}
136
137static inet_link_t *inet_link_new(void)
138{
139 inet_link_t *ilink = calloc(1, sizeof(inet_link_t));
140
141 if (ilink == NULL) {
142 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed allocating link structure. "
143 "Out of memory.");
144 return NULL;
145 }
146
147 link_initialize(&ilink->link_list);
148
149 return ilink;
150}
151
152static void inet_link_delete(inet_link_t *ilink)
153{
154 if (ilink->svc_name != NULL)
155 free(ilink->svc_name);
156
157 free(ilink);
158}
159
160errno_t inet_link_open(service_id_t sid)
161{
162 inet_link_t *ilink;
163 inet_addr_t iaddr;
164 errno_t rc;
165
166 log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_link_open()");
167 ilink = inet_link_new();
168 if (ilink == NULL)
169 return ENOMEM;
170
171 ilink->svc_id = sid;
172 ilink->iplink = NULL;
173
174 rc = loc_service_get_name(sid, &ilink->svc_name);
175 if (rc != EOK) {
176 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed getting service name.");
177 goto error;
178 }
179
180 ilink->sess = loc_service_connect(sid, INTERFACE_IPLINK, 0);
181 if (ilink->sess == NULL) {
182 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed connecting '%s'", ilink->svc_name);
183 goto error;
184 }
185
186 rc = iplink_open(ilink->sess, &inet_iplink_ev_ops, ilink, &ilink->iplink);
187 if (rc != EOK) {
188 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed opening IP link '%s'",
189 ilink->svc_name);
190 goto error;
191 }
192
193 rc = iplink_get_mtu(ilink->iplink, &ilink->def_mtu);
194 if (rc != EOK) {
195 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed determinning MTU of link '%s'",
196 ilink->svc_name);
197 goto error;
198 }
199
200 /*
201 * Get the MAC address of the link. If the link has a MAC
202 * address, we assume that it supports NDP.
203 */
204 rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
205 ilink->mac_valid = (rc == EOK);
206
207 log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
208
209 fibril_mutex_lock(&inet_links_lock);
210
211 if (inet_link_get_by_id_locked(sid) != NULL) {
212 fibril_mutex_unlock(&inet_links_lock);
213 log_msg(LOG_DEFAULT, LVL_DEBUG, "Link %zu already open",
214 sid);
215 rc = EEXIST;
216 goto error;
217 }
218
219 list_append(&ilink->link_list, &inet_links);
220 fibril_mutex_unlock(&inet_links_lock);
221
222 inet_addrobj_t *addr = NULL;
223
224 /* XXX FIXME Cannot rely on loopback being the first IP link service!! */
225 if (first_link) {
226 addr = inet_addrobj_new();
227
228 inet_naddr(&addr->naddr, 127, 0, 0, 1, 24);
229 first_link = false;
230 }
231
232 if (addr != NULL) {
233 addr->ilink = ilink;
234 addr->name = str_dup("v4a");
235
236 rc = inet_addrobj_add(addr);
237 if (rc == EOK) {
238 inet_naddr_addr(&addr->naddr, &iaddr);
239 rc = iplink_addr_add(ilink->iplink, &iaddr);
240 if (rc != EOK) {
241 log_msg(LOG_DEFAULT, LVL_ERROR,
242 "Failed setting IPv4 address on internet link.");
243 inet_addrobj_remove(addr);
244 inet_addrobj_delete(addr);
245 }
246 } else {
247 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv4 address.");
248 inet_addrobj_delete(addr);
249 }
250 }
251
252 inet_addrobj_t *addr6 = NULL;
253
254 if (first_link6) {
255 addr6 = inet_addrobj_new();
256
257 inet_naddr6(&addr6->naddr, 0, 0, 0, 0, 0, 0, 0, 1, 128);
258 first_link6 = false;
259 } else if (ilink->mac_valid) {
260 addr6 = inet_addrobj_new();
261
262 addr128_t link_local;
263 inet_link_local_node_ip(ilink->mac, link_local);
264
265 inet_naddr_set6(link_local, 64, &addr6->naddr);
266 }
267
268 if (addr6 != NULL) {
269 addr6->ilink = ilink;
270 addr6->name = str_dup("v6a");
271
272 rc = inet_addrobj_add(addr6);
273 if (rc == EOK) {
274 inet_naddr_addr(&addr6->naddr, &iaddr);
275 rc = iplink_addr_add(ilink->iplink, &iaddr);
276 if (rc != EOK) {
277 log_msg(LOG_DEFAULT, LVL_ERROR,
278 "Failed setting IPv6 address on internet link.");
279 inet_addrobj_remove(addr6);
280 inet_addrobj_delete(addr6);
281 }
282 } else {
283 log_msg(LOG_DEFAULT, LVL_ERROR, "Failed adding IPv6 address.");
284 inet_addrobj_delete(addr6);
285 }
286 }
287
288 log_msg(LOG_DEFAULT, LVL_DEBUG, "Configured link '%s'.", ilink->svc_name);
289 return EOK;
290
291error:
292 if (ilink->iplink != NULL)
293 iplink_close(ilink->iplink);
294
295 inet_link_delete(ilink);
296 return rc;
297}
298
299/** Send IPv4 datagram over Internet link
300 *
301 * @param ilink Internet link
302 * @param lsrc Source IPv4 address
303 * @param ldest Destination IPv4 address
304 * @param dgram IPv4 datagram body
305 * @param proto Protocol
306 * @param ttl Time-to-live
307 * @param df Do-not-Fragment flag
308 *
309 * @return EOK on success
310 * @return ENOMEM when not enough memory to create the datagram
311 * @return ENOTSUP if networking mode is not supported
312 *
313 */
314errno_t inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
315 inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
316{
317 addr32_t src_v4;
318 ip_ver_t src_ver = inet_addr_get(&dgram->src, &src_v4, NULL);
319 if (src_ver != ip_v4)
320 return EINVAL;
321
322 addr32_t dest_v4;
323 ip_ver_t dest_ver = inet_addr_get(&dgram->dest, &dest_v4, NULL);
324 if (dest_ver != ip_v4)
325 return EINVAL;
326
327 /*
328 * Fill packet structure. Fragmentation is performed by
329 * inet_pdu_encode().
330 */
331
332 iplink_sdu_t sdu;
333
334 sdu.src = lsrc;
335 sdu.dest = ldest;
336
337 inet_packet_t packet;
338
339 packet.src = dgram->src;
340 packet.dest = dgram->dest;
341 packet.tos = dgram->tos;
342 packet.proto = proto;
343 packet.ttl = ttl;
344
345 /* Allocate identifier */
346 fibril_mutex_lock(&ip_ident_lock);
347 packet.ident = ++ip_ident;
348 fibril_mutex_unlock(&ip_ident_lock);
349
350 packet.df = df;
351 packet.data = dgram->data;
352 packet.size = dgram->size;
353
354 errno_t rc;
355 size_t offs = 0;
356
357 do {
358 /* Encode one fragment */
359
360 size_t roffs;
361 rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
362 &sdu.data, &sdu.size, &roffs);
363 if (rc != EOK)
364 return rc;
365
366 /* Send the PDU */
367 rc = iplink_send(ilink->iplink, &sdu);
368
369 free(sdu.data);
370 offs = roffs;
371 } while (offs < packet.size);
372
373 return rc;
374}
375
376/** Send IPv6 datagram over Internet link
377 *
378 * @param ilink Internet link
379 * @param ldest Destination MAC address
380 * @param dgram IPv6 datagram body
381 * @param proto Next header
382 * @param ttl Hop limit
383 * @param df Do-not-Fragment flag (unused)
384 *
385 * @return EOK on success
386 * @return ENOMEM when not enough memory to create the datagram
387 *
388 */
389errno_t inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
390 inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
391{
392 addr128_t src_v6;
393 ip_ver_t src_ver = inet_addr_get(&dgram->src, NULL, &src_v6);
394 if (src_ver != ip_v6)
395 return EINVAL;
396
397 addr128_t dest_v6;
398 ip_ver_t dest_ver = inet_addr_get(&dgram->dest, NULL, &dest_v6);
399 if (dest_ver != ip_v6)
400 return EINVAL;
401
402 iplink_sdu6_t sdu6;
403 addr48(ldest, sdu6.dest);
404
405 /*
406 * Fill packet structure. Fragmentation is performed by
407 * inet_pdu_encode6().
408 */
409
410 inet_packet_t packet;
411
412 packet.src = dgram->src;
413 packet.dest = dgram->dest;
414 packet.tos = dgram->tos;
415 packet.proto = proto;
416 packet.ttl = ttl;
417
418 /* Allocate identifier */
419 fibril_mutex_lock(&ip_ident_lock);
420 packet.ident = ++ip_ident;
421 fibril_mutex_unlock(&ip_ident_lock);
422
423 packet.df = df;
424 packet.data = dgram->data;
425 packet.size = dgram->size;
426
427 errno_t rc;
428 size_t offs = 0;
429
430 do {
431 /* Encode one fragment */
432
433 size_t roffs;
434 rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
435 &sdu6.data, &sdu6.size, &roffs);
436 if (rc != EOK)
437 return rc;
438
439 /* Send the PDU */
440 rc = iplink_send6(ilink->iplink, &sdu6);
441
442 free(sdu6.data);
443 offs = roffs;
444 } while (offs < packet.size);
445
446 return rc;
447}
448
449static inet_link_t *inet_link_get_by_id_locked(sysarg_t link_id)
450{
451 assert(fibril_mutex_is_locked(&inet_links_lock));
452
453 list_foreach(inet_links, link_list, inet_link_t, ilink) {
454 if (ilink->svc_id == link_id)
455 return ilink;
456 }
457
458 return NULL;
459}
460
461inet_link_t *inet_link_get_by_id(sysarg_t link_id)
462{
463 inet_link_t *ilink;
464
465 fibril_mutex_lock(&inet_links_lock);
466 ilink = inet_link_get_by_id_locked(link_id);
467 fibril_mutex_unlock(&inet_links_lock);
468
469 return ilink;
470}
471
472/** Get IDs of all links. */
473errno_t inet_link_get_id_list(sysarg_t **rid_list, size_t *rcount)
474{
475 sysarg_t *id_list;
476 size_t count, i;
477
478 fibril_mutex_lock(&inet_links_lock);
479 count = list_count(&inet_links);
480
481 id_list = calloc(count, sizeof(sysarg_t));
482 if (id_list == NULL) {
483 fibril_mutex_unlock(&inet_links_lock);
484 return ENOMEM;
485 }
486
487 i = 0;
488 list_foreach(inet_links, link_list, inet_link_t, ilink) {
489 id_list[i++] = ilink->svc_id;
490 }
491
492 fibril_mutex_unlock(&inet_links_lock);
493
494 *rid_list = id_list;
495 *rcount = count;
496
497 return EOK;
498}
499
500/** @}
501 */
Note: See TracBrowser for help on using the repository browser.