source: mainline/uspace/lib/c/generic/inet/addr.c@ 695b6ff

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

Crude DHCP client prototype.

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