source: mainline/uspace/lib/c/generic/inet/addr.c@ 83781a22

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 83781a22 was 83781a22, checked in by Martin Decky <martin@…>, 12 years ago

setup NIC multicast address filter based on the configured IPv6 addresses
(multicast functionality is required for NDP)

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/*
2 * Copyright (c) 2013 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 libc
30 * @{
31 */
32/** @file Internet address parsing and formatting.
33 */
34
35#include <errno.h>
36#include <unistd.h>
37#include <net/socket_codes.h>
38#include <inet/addr.h>
39#include <net/inet.h>
40#include <stdio.h>
41#include <malloc.h>
42#include <bitops.h>
43
44#define INET_PREFIXSTRSIZE 5
45
46#if !(defined(__BE__) ^ defined(__LE__))
47 #error The architecture must be either big-endian or little-endian.
48#endif
49
50const addr48_t addr48_broadcast = {
51 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
52};
53
54static const addr48_t inet_addr48_solicited_node = {
55 0x33, 0x33, 0xff, 0, 0, 0
56};
57
58static const inet_addr_t inet_addr_any_addr = {
59 .family = AF_INET,
60 .addr = 0
61};
62
63static const inet_addr_t inet_addr_any_addr6 = {
64 .family = AF_INET6,
65 .addr6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
66};
67
68void addr48(const addr48_t src, addr48_t dst)
69{
70 memcpy(dst, src, 6);
71}
72
73void addr128(const addr128_t src, addr128_t dst)
74{
75 memcpy(dst, src, 16);
76}
77
78int addr48_compare(const addr48_t a, const addr48_t b)
79{
80 return memcmp(a, b, 6);
81}
82
83int addr128_compare(const addr128_t a, const addr128_t b)
84{
85 return memcmp(a, b, 16);
86}
87
88/** Compute solicited node MAC multicast address from target IPv6 address
89 *
90 * @param ip Target IPv6 address
91 * @param mac Solicited MAC address to be assigned
92 *
93 */
94void addr48_solicited_node(const addr128_t ip, addr48_t mac)
95{
96 memcpy(mac, inet_addr48_solicited_node, 3);
97 memcpy(mac + 3, ip + 13, 3);
98}
99
100void host2addr128_t_be(const addr128_t host, addr128_t be)
101{
102#ifdef __BE__
103 memcpy(be, host, 16);
104#else
105 be[0] = host[15];
106 be[1] = host[14];
107 be[2] = host[13];
108 be[3] = host[12];
109 be[4] = host[11];
110 be[5] = host[10];
111 be[6] = host[9];
112 be[7] = host[8];
113 be[8] = host[7];
114 be[9] = host[6];
115 be[10] = host[5];
116 be[11] = host[4];
117 be[12] = host[3];
118 be[13] = host[2];
119 be[14] = host[1];
120 be[15] = host[0];
121#endif
122}
123
124void addr128_t_be2host(const addr128_t be, addr128_t host)
125{
126#ifdef __BE__
127 memcpy(host, be, 16);
128#else
129 host[0] = be[15];
130 host[1] = be[14];
131 host[2] = be[13];
132 host[3] = be[12];
133 host[4] = be[11];
134 host[5] = be[10];
135 host[6] = be[9];
136 host[7] = be[8];
137 host[8] = be[7];
138 host[9] = be[6];
139 host[10] = be[5];
140 host[11] = be[4];
141 host[12] = be[3];
142 host[13] = be[2];
143 host[14] = be[1];
144 host[15] = be[0];
145#endif
146}
147
148void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
149{
150 addr->family = AF_INET;
151 addr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
152 ((addr32_t) c << 8) | ((addr32_t) d);
153}
154
155void inet_naddr(inet_naddr_t *naddr, uint8_t a, uint8_t b, uint8_t c, uint8_t d,
156 uint8_t prefix)
157{
158 naddr->family = AF_INET;
159 naddr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
160 ((addr32_t) c << 8) | ((addr32_t) d);
161 naddr->prefix = prefix;
162}
163
164void inet_addr6(inet_addr_t *addr, uint16_t a, uint16_t b, uint16_t c,
165 uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
166{
167 addr->family = AF_INET6;
168 addr->addr6[0] = (a >> 8) & 0xff;
169 addr->addr6[1] = a & 0xff;
170 addr->addr6[2] = (b >> 8) & 0xff;
171 addr->addr6[3] = b & 0xff;
172 addr->addr6[4] = (c >> 8) & 0xff;
173 addr->addr6[5] = c & 0xff;
174 addr->addr6[6] = (d >> 8) & 0xff;
175 addr->addr6[7] = d & 0xff;
176 addr->addr6[8] = (e >> 8) & 0xff;
177 addr->addr6[9] = e & 0xff;
178 addr->addr6[10] = (f >> 8) & 0xff;
179 addr->addr6[11] = f & 0xff;
180 addr->addr6[12] = (g >> 8) & 0xff;
181 addr->addr6[13] = g & 0xff;
182 addr->addr6[14] = (h >> 8) & 0xff;
183 addr->addr6[15] = h & 0xff;
184}
185
186void inet_naddr6(inet_naddr_t *naddr, uint16_t a, uint16_t b, uint16_t c,
187 uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint8_t prefix)
188{
189 naddr->family = AF_INET6;
190 naddr->addr6[0] = (a >> 8) & 0xff;
191 naddr->addr6[1] = a & 0xff;
192 naddr->addr6[2] = (b >> 8) & 0xff;
193 naddr->addr6[3] = b & 0xff;
194 naddr->addr6[4] = (c >> 8) & 0xff;
195 naddr->addr6[5] = c & 0xff;
196 naddr->addr6[6] = (d >> 8) & 0xff;
197 naddr->addr6[7] = d & 0xff;
198 naddr->addr6[8] = (e >> 8) & 0xff;
199 naddr->addr6[9] = e & 0xff;
200 naddr->addr6[10] = (f >> 8) & 0xff;
201 naddr->addr6[11] = f & 0xff;
202 naddr->addr6[12] = (g >> 8) & 0xff;
203 naddr->addr6[13] = g & 0xff;
204 naddr->addr6[14] = (h >> 8) & 0xff;
205 naddr->addr6[15] = h & 0xff;
206 naddr->prefix = prefix;
207}
208
209/** Parse network address family.
210 *
211 * @param text Network address in common notation.
212 * @param af Place to store network address family.
213 *
214 * @return EOK on success, EINVAL if input is not in valid format.
215 *
216 */
217int inet_addr_family(const char *text, uint16_t *af)
218{
219 char *dot = str_chr(text, '.');
220 if (dot != NULL) {
221 *af = AF_INET;
222 return EOK;
223 }
224
225 char *collon = str_chr(text, ':');
226 if (collon != NULL) {
227 *af = AF_INET6;
228 return EOK;
229 }
230
231 return EINVAL;
232}
233
234void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
235{
236 addr->family = naddr->family;
237 memcpy(addr->addr6, naddr->addr6, 16);
238}
239
240void inet_addr_naddr(const inet_addr_t *addr, uint8_t prefix,
241 inet_naddr_t *naddr)
242{
243 naddr->family = addr->family;
244 memcpy(naddr->addr6, addr->addr6, 16);
245 naddr->prefix = prefix;
246}
247
248void inet_addr_any(inet_addr_t *addr)
249{
250 addr->family = AF_NONE;
251 memset(addr->addr6, 0, 16);
252}
253
254void inet_naddr_any(inet_naddr_t *naddr)
255{
256 naddr->family = AF_NONE;
257 memset(naddr->addr6, 0, 16);
258 naddr->prefix = 0;
259}
260
261int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
262{
263 if (a->family != b->family)
264 return 0;
265
266 switch (a->family) {
267 case AF_INET:
268 return (a->addr == b->addr);
269 case AF_INET6:
270 return addr128_compare(a->addr6, b->addr6);
271 default:
272 return 0;
273 }
274}
275
276int inet_addr_is_any(const inet_addr_t *addr)
277{
278 return ((addr->family == 0) ||
279 (inet_addr_compare(addr, &inet_addr_any_addr)) ||
280 (inet_addr_compare(addr, &inet_addr_any_addr6)));
281}
282
283int inet_naddr_compare(const inet_naddr_t *naddr, const inet_addr_t *addr)
284{
285 if (naddr->family != addr->family)
286 return 0;
287
288 switch (naddr->family) {
289 case AF_INET:
290 return (naddr->addr == addr->addr);
291 case AF_INET6:
292 return addr128_compare(naddr->addr6, addr->addr6);
293 default:
294 return 0;
295 }
296}
297
298int inet_naddr_compare_mask(const inet_naddr_t *naddr, const inet_addr_t *addr)
299{
300 if (naddr->family != addr->family)
301 return 0;
302
303 switch (naddr->family) {
304 case AF_INET:
305 if (naddr->prefix > 32)
306 return 0;
307
308 addr32_t mask =
309 BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
310 return ((naddr->addr & mask) == (addr->addr & mask));
311 case AF_INET6:
312 if (naddr->prefix > 128)
313 return 0;
314
315 size_t pos = 0;
316 for (size_t i = 0; i < 16; i++) {
317 /* Further bits do not matter */
318 if (naddr->prefix < pos)
319 break;
320
321 if (naddr->prefix - pos > 8) {
322 /* Comparison without masking */
323 if (naddr->addr6[i] != addr->addr6[i])
324 return 0;
325 } else {
326 /* Comparison with masking */
327 uint8_t mask =
328 BIT_RANGE(uint8_t, 8, 8 - (naddr->prefix - pos - 1));
329 if ((naddr->addr6[i] & mask) != (addr->addr6[i] & mask))
330 return 0;
331 }
332
333 pos += 8;
334 }
335
336 return 1;
337 default:
338 return 0;
339 }
340}
341
342/** Parse node address.
343 *
344 * @param text Network address in common notation.
345 * @param addr Place to store node address.
346 *
347 * @return EOK on success, EINVAL if input is not in valid format.
348 *
349 */
350int inet_addr_parse(const char *text, inet_addr_t *addr)
351{
352 int rc = inet_addr_family(text, &addr->family);
353 if (rc != EOK)
354 return rc;
355
356 uint8_t buf[16];
357 rc = inet_pton(addr->family, text, buf);
358 if (rc != EOK)
359 return rc;
360
361 switch (addr->family) {
362 case AF_INET:
363 addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
364 buf[3];
365 break;
366 case AF_INET6:
367 memcpy(addr->addr6, buf, 16);
368 break;
369 default:
370 return EINVAL;
371 }
372
373 return EOK;
374}
375
376/** Parse network address.
377 *
378 * @param text Network address in common notation.
379 * @param naddr Place to store network address.
380 *
381 * @return EOK on success, EINVAL if input is not in valid format.
382 *
383 */
384int inet_naddr_parse(const char *text, inet_naddr_t *naddr)
385{
386 char *slash = str_chr(text, '/');
387 if (slash == NULL)
388 return EINVAL;
389
390 *slash = 0;
391
392 int rc = inet_addr_family(text, &naddr->family);
393 if (rc != EOK)
394 return rc;
395
396 uint8_t buf[16];
397 rc = inet_pton(naddr->family, text, buf);
398 *slash = '/';
399
400 if (rc != EOK)
401 return rc;
402
403 slash++;
404 uint8_t prefix;
405
406 switch (naddr->family) {
407 case AF_INET:
408 prefix = strtoul(slash, &slash, 10);
409 if (prefix > 32)
410 return EINVAL;
411
412 naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
413 buf[3];
414 naddr->prefix = prefix;
415
416 break;
417 case AF_INET6:
418 prefix = strtoul(slash, &slash, 10);
419 if (prefix > 128)
420 return EINVAL;
421
422 memcpy(naddr->addr6, buf, 16);
423 naddr->prefix = prefix;
424
425 break;
426 default:
427 return ENOTSUP;
428 }
429
430 return EOK;
431}
432
433/** Format node address.
434 *
435 * @param addr Node address.
436 * @param bufp Place to store pointer to formatted string.
437 *
438 * @return EOK on success.
439 * @return ENOMEM if out of memory.
440 * @return ENOTSUP on unsupported address family.
441 *
442 */
443int inet_addr_format(const inet_addr_t *addr, char **bufp)
444{
445 int rc = 0;
446
447 switch (addr->family) {
448 case AF_NONE:
449 rc = asprintf(bufp, "none");
450 break;
451 case AF_INET:
452 rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
453 (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
454 addr->addr & 0xff);
455 break;
456 case AF_INET6:
457 *bufp = (char *) malloc(INET6_ADDRSTRLEN);
458 if (*bufp == NULL)
459 return ENOMEM;
460
461 return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN);
462 default:
463 return ENOTSUP;
464 }
465
466 if (rc < 0)
467 return ENOMEM;
468
469 return EOK;
470}
471
472/** Format network address.
473 *
474 * @param naddr Network address.
475 * @param bufp Place to store pointer to formatted string.
476 *
477 * @return EOK on success.
478 * @return ENOMEM if out of memory.
479 * @return ENOTSUP on unsupported address family.
480 *
481 */
482int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
483{
484 int rc = 0;
485 char prefix[INET_PREFIXSTRSIZE];
486
487 switch (naddr->family) {
488 case AF_NONE:
489 rc = asprintf(bufp, "none");
490 break;
491 case AF_INET:
492 rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
493 "/%" PRIu8, (naddr->addr >> 24) & 0xff,
494 (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff,
495 naddr->addr & 0xff, naddr->prefix);
496 break;
497 case AF_INET6:
498 *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
499 if (*bufp == NULL)
500 return ENOMEM;
501
502 rc = inet_ntop(AF_INET6, naddr->addr6, *bufp,
503 INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
504 if (rc != EOK) {
505 free(*bufp);
506 return rc;
507 }
508
509 rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8,
510 naddr->prefix);
511 if (rc < 0) {
512 free(*bufp);
513 return ENOMEM;
514 }
515
516 str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix);
517
518 break;
519 default:
520 return ENOTSUP;
521 }
522
523 if (rc < 0)
524 return ENOMEM;
525
526 return EOK;
527}
528
529uint16_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
530{
531 switch (addr->family) {
532 case AF_INET:
533 if (v4 != NULL)
534 *v4 = addr->addr;
535
536 break;
537 case AF_INET6:
538 if (v6 != NULL)
539 memcpy(*v6, addr->addr6, 16);
540
541 break;
542 }
543
544 return addr->family;
545}
546
547uint16_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
548 uint8_t *prefix)
549{
550 switch (naddr->family) {
551 case AF_INET:
552 if (v4 != NULL)
553 *v4 = naddr->addr;
554
555 if (prefix != NULL)
556 *prefix = naddr->prefix;
557
558 break;
559 case AF_INET6:
560 if (v6 != NULL)
561 memcpy(*v6, naddr->addr6, 16);
562
563 if (prefix != NULL)
564 *prefix = naddr->prefix;
565
566 break;
567 }
568
569 return naddr->family;
570}
571
572void inet_addr_set(addr32_t v4, inet_addr_t *addr)
573{
574 addr->family = AF_INET;
575 addr->addr = v4;
576}
577
578void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
579{
580 naddr->family = AF_INET;
581 naddr->addr = v4;
582 naddr->prefix = prefix;
583}
584
585void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
586{
587 addr->family = AF_INET;
588 addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
589}
590
591void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
592{
593 addr->family = AF_INET6;
594 memcpy(addr->addr6, v6, 16);
595}
596
597void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
598{
599 naddr->family = AF_INET6;
600 memcpy(naddr->addr6, v6, 16);
601 naddr->prefix = prefix;
602}
603
604void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,
605 inet_addr_t *addr)
606{
607 addr->family = AF_INET6;
608 addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
609}
610
611uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,
612 sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
613{
614 switch (addr->family) {
615 case AF_INET:
616 if (sockaddr_in != NULL) {
617 sockaddr_in->sin_family = AF_INET;
618 sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);
619 }
620
621 break;
622 case AF_INET6:
623 if (sockaddr_in6 != NULL) {
624 sockaddr_in6->sin6_family = AF_INET6;
625 host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);
626 }
627
628 break;
629 }
630
631 return addr->family;
632}
633
634/** @}
635 */
Note: See TracBrowser for help on using the repository browser.