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
RevLine 
[3495654]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>
[a2e3ee6]36#include <unistd.h>
37#include <net/socket_codes.h>
[3495654]38#include <inet/addr.h>
[a2e3ee6]39#include <net/inet.h>
[3495654]40#include <stdio.h>
[02a09ed]41#include <malloc.h>
42#include <bitops.h>
[3495654]43
[02a09ed]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
[695b6ff]50const addr32_t addr32_broadcast_all_hosts = 0xffffffff;
51
[02a09ed]52const addr48_t addr48_broadcast = {
53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
54};
55
[83781a22]56static const addr48_t inet_addr48_solicited_node = {
57 0x33, 0x33, 0xff, 0, 0, 0
58};
59
[02a09ed]60static const inet_addr_t inet_addr_any_addr = {
[a2e3ee6]61 .family = AF_INET,
[02a09ed]62 .addr = 0
[a2e3ee6]63};
64
[02a09ed]65static const inet_addr_t inet_addr_any_addr6 = {
[a2e3ee6]66 .family = AF_INET6,
[02a09ed]67 .addr6 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
[a2e3ee6]68};
69
[02a09ed]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
[83781a22]80int addr48_compare(const addr48_t a, const addr48_t b)
81{
82 return memcmp(a, b, 6);
83}
84
[671b546]85int addr128_compare(const addr128_t a, const addr128_t b)
86{
87 return memcmp(a, b, 16);
88}
89
[83781a22]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
[02a09ed]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
[a2e3ee6]211/** Parse network address family.
[3495654]212 *
[a2e3ee6]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.
[3495654]217 *
218 */
[a2e3ee6]219int inet_addr_family(const char *text, uint16_t *af)
[3495654]220{
[a2e3ee6]221 char *dot = str_chr(text, '.');
222 if (dot != NULL) {
223 *af = AF_INET;
224 return EOK;
[3495654]225 }
[a2e3ee6]226
227 char *collon = str_chr(text, ':');
228 if (collon != NULL) {
229 *af = AF_INET6;
230 return EOK;
[3495654]231 }
[a2e3ee6]232
233 return EINVAL;
[3495654]234}
235
[02a09ed]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
[bb9b0c6]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
[02a09ed]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:
[671b546]272 return addr128_compare(a->addr6, b->addr6);
[02a09ed]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
[30c5d13]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
[02a09ed]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
[3495654]344/** Parse node address.
345 *
[a2e3ee6]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.
[3495654]350 *
351 */
352int inet_addr_parse(const char *text, inet_addr_t *addr)
353{
[a2e3ee6]354 int rc = inet_addr_family(text, &addr->family);
355 if (rc != EOK)
356 return rc;
357
[02a09ed]358 uint8_t buf[16];
359 rc = inet_pton(addr->family, text, buf);
[a2e3ee6]360 if (rc != EOK)
361 return rc;
362
[02a09ed]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
[a2e3ee6]375 return EOK;
376}
[3495654]377
[a2e3ee6]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)
[3495654]390 return EINVAL;
[a2e3ee6]391
392 *slash = 0;
393
394 int rc = inet_addr_family(text, &naddr->family);
395 if (rc != EOK)
396 return rc;
397
[02a09ed]398 uint8_t buf[16];
399 rc = inet_pton(naddr->family, text, buf);
[a2e3ee6]400 *slash = '/';
401
402 if (rc != EOK)
403 return rc;
404
405 slash++;
[02a09ed]406 uint8_t prefix;
[a2e3ee6]407
408 switch (naddr->family) {
409 case AF_INET:
[02a09ed]410 prefix = strtoul(slash, &slash, 10);
411 if (prefix > 32)
[a2e3ee6]412 return EINVAL;
[02a09ed]413
414 naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
415 buf[3];
416 naddr->prefix = prefix;
417
[a2e3ee6]418 break;
419 case AF_INET6:
[02a09ed]420 prefix = strtoul(slash, &slash, 10);
421 if (prefix > 128)
[3495654]422 return EINVAL;
[02a09ed]423
424 memcpy(naddr->addr6, buf, 16);
425 naddr->prefix = prefix;
426
[a2e3ee6]427 break;
428 default:
429 return ENOTSUP;
[3495654]430 }
[a2e3ee6]431
432 return EOK;
433}
[3495654]434
[a2e3ee6]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 */
[02a09ed]445int inet_addr_format(const inet_addr_t *addr, char **bufp)
[a2e3ee6]446{
[02a09ed]447 int rc = 0;
[a2e3ee6]448
449 switch (addr->family) {
450 case AF_NONE:
451 rc = asprintf(bufp, "none");
452 break;
453 case AF_INET:
[02a09ed]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);
[a2e3ee6]457 break;
458 case AF_INET6:
[02a09ed]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);
[a2e3ee6]464 default:
465 return ENOTSUP;
466 }
467
468 if (rc < 0)
469 return ENOMEM;
470
[3495654]471 return EOK;
472}
473
474/** Format network address.
475 *
[a2e3ee6]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.
[3495654]482 *
483 */
[02a09ed]484int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
[3495654]485{
[02a09ed]486 int rc = 0;
487 char prefix[INET_PREFIXSTRSIZE];
[a2e3ee6]488
489 switch (naddr->family) {
490 case AF_NONE:
491 rc = asprintf(bufp, "none");
492 break;
493 case AF_INET:
[02a09ed]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);
[a2e3ee6]498 break;
499 case AF_INET6:
[02a09ed]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;
[a2e3ee6]521 default:
522 return ENOTSUP;
523 }
524
[3495654]525 if (rc < 0)
526 return ENOMEM;
[a2e3ee6]527
528 return EOK;
529}
[3495654]530
[02a09ed]531uint16_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
[a2e3ee6]532{
[02a09ed]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 }
[a2e3ee6]545
[02a09ed]546 return addr->family;
[3495654]547}
548
[02a09ed]549uint16_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
550 uint8_t *prefix)
[3495654]551{
[02a09ed]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 }
[a2e3ee6]570
[02a09ed]571 return naddr->family;
[a2e3ee6]572}
[3495654]573
[02a09ed]574void inet_addr_set(addr32_t v4, inet_addr_t *addr)
[a2e3ee6]575{
576 addr->family = AF_INET;
[02a09ed]577 addr->addr = v4;
[a2e3ee6]578}
[3495654]579
[02a09ed]580void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
[a2e3ee6]581{
582 naddr->family = AF_INET;
[02a09ed]583 naddr->addr = v4;
[a2e3ee6]584 naddr->prefix = prefix;
585}
[3495654]586
[02a09ed]587void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
[a2e3ee6]588{
589 addr->family = AF_INET;
[02a09ed]590 addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
[a2e3ee6]591}
592
[02a09ed]593void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
[a2e3ee6]594{
[02a09ed]595 addr->family = AF_INET6;
596 memcpy(addr->addr6, v6, 16);
[a2e3ee6]597}
598
[02a09ed]599void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
[a2e3ee6]600{
[02a09ed]601 naddr->family = AF_INET6;
602 memcpy(naddr->addr6, v6, 16);
603 naddr->prefix = prefix;
[a2e3ee6]604}
605
[02a09ed]606void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,
607 inet_addr_t *addr)
[a2e3ee6]608{
[02a09ed]609 addr->family = AF_INET6;
610 addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
[a2e3ee6]611}
612
[02a09ed]613uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,
614 sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
[a2e3ee6]615{
[02a09ed]616 switch (addr->family) {
[a2e3ee6]617 case AF_INET:
[02a09ed]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;
[a2e3ee6]624 case AF_INET6:
[02a09ed]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;
[a2e3ee6]631 }
[02a09ed]632
633 return addr->family;
[a2e3ee6]634}
635
[3495654]636/** @}
637 */
Note: See TracBrowser for help on using the repository browser.