source: mainline/uspace/lib/c/generic/net/inet.c@ 4339f09

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

routines for IPv6 address parsing and formatting

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2009 Lukas Mejdrech
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
33/** @file
34 * Internet protocol address conversion functions implementation.
35 */
36
37#include <net/socket_codes.h>
38#include <net/in.h>
39#include <net/in6.h>
40#include <net/inet.h>
41#include <inet/addr.h>
42#include <errno.h>
43#include <mem.h>
44#include <stdio.h>
45#include <str.h>
46
47static int inet_ntop4(const uint8_t *data, char *address, size_t length)
48{
49 /* Check output buffer size */
50 if (length < INET_ADDRSTRLEN)
51 return ENOMEM;
52
53 /* Fill buffer with IPv4 address */
54 snprintf(address, length,
55 "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
56 data[0], data[1], data[2], data[3]);
57
58 return EOK;
59}
60
61static int inet_ntop6(const uint8_t *data, char *address, size_t length)
62{
63 /* Check output buffer size */
64 if (length < INET6_ADDRSTRLEN)
65 return ENOMEM;
66
67 /* Find the longest zero subsequence */
68
69 uint16_t zeroes[8];
70 uint16_t bioctets[8];
71
72 for (size_t i = 8; i > 0; i--) {
73 size_t j = i - 1;
74
75 bioctets[j] = (data[j << 1] << 8) | data[(j << 1) + 1];
76
77 if (bioctets[j] == 0) {
78 zeroes[j] = 1;
79 if (j < 7)
80 zeroes[j] += zeroes[j + 1];
81 } else
82 zeroes[j] = 0;
83 }
84
85 size_t wildcard_pos = (size_t) -1;
86 size_t wildcard_size = 0;
87
88 for (size_t i = 0; i < 8; i++) {
89 if (zeroes[i] > wildcard_size) {
90 wildcard_pos = i;
91 wildcard_size = zeroes[i];
92 }
93 }
94
95 char *cur = address;
96 size_t rest = length;
97 bool tail_zero = false;
98 int ret;
99
100 for (size_t i = 0; i < 8; i++) {
101 if ((i == wildcard_pos) && (wildcard_size > 1)) {
102 ret = snprintf(cur, rest, ":");
103 i += wildcard_size - 1;
104 tail_zero = true;
105 } else if (i == 0) {
106 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]);
107 tail_zero = false;
108 } else {
109 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]);
110 tail_zero = false;
111 }
112
113 if (ret < 0)
114 return EINVAL;
115
116 cur += ret;
117 rest -= ret;
118 }
119
120 if (tail_zero) {
121 ret = snprintf(cur, rest, ":");
122 if (ret < 0)
123 return EINVAL;
124 }
125
126 return EOK;
127}
128
129/** Prints the address into the character buffer.
130 *
131 * @param[in] family Address family.
132 * @param[in] data Address data.
133 * @param[out] address Character buffer to be filled.
134 * @param[in] length Buffer length.
135 *
136 * @return EOK on success.
137 * @return EINVAL if the data or address parameter is NULL.
138 * @return ENOMEM if the character buffer is not long enough.
139 * @return ENOTSUP if the address family is not supported.
140 *
141 */
142int inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length)
143{
144 switch (family) {
145 case AF_INET:
146 return inet_ntop4(data, address, length);
147 case AF_INET6:
148 return inet_ntop6(data, address, length);
149 default:
150 return ENOTSUP;
151 }
152}
153
154static int inet_pton4(const char *address, uint8_t *data)
155{
156 memset(data, 0, 4);
157
158 const char *cur = address;
159 size_t i = 0;
160
161 while (i < 4) {
162 int rc = str_uint8_t(cur, &cur, 10, false, &data[i]);
163 if (rc != EOK)
164 return rc;
165
166 i++;
167
168 if (*cur == 0)
169 break;
170
171 if (*cur != '.')
172 return EINVAL;
173
174 if (i < 4)
175 cur++;
176 }
177
178 if ((i == 4) && (*cur != 0))
179 return EINVAL;
180
181 return EOK;
182}
183
184static int inet_pton6(const char *address, uint8_t *data)
185{
186 memset(data, 0, 16);
187
188 const char *cur = address;
189 size_t i = 0;
190 size_t wildcard_pos = (size_t) -1;
191 size_t wildcard_size = 0;
192
193 /* Handle initial wildcard */
194 if ((address[0] == ':') && (address[1] == ':')) {
195 cur = address + 2;
196 wildcard_pos = 0;
197 wildcard_size = 16;
198
199 /* Handle empty address */
200 if (*cur == 0)
201 return EOK;
202 }
203
204 while (i < 16) {
205 uint16_t bioctet;
206 int rc = str_uint16_t(cur, &cur, 16, false, &bioctet);
207 if (rc != EOK)
208 return rc;
209
210 data[i] = (bioctet >> 8) & 0xff;
211 data[i + 1] = bioctet & 0xff;
212
213 if (wildcard_pos != (size_t) -1) {
214 if (wildcard_size < 2)
215 return EINVAL;
216
217 wildcard_size -= 2;
218 }
219
220 i += 2;
221
222 if (*cur == 0)
223 break;
224
225 if (*cur != ':')
226 return EINVAL;
227
228 if (i < 16) {
229 cur++;
230
231 /* Handle wildcard */
232 if (*cur == ':') {
233 if (wildcard_pos != (size_t) -1)
234 return EINVAL;
235
236 wildcard_pos = i;
237 wildcard_size = 16 - i;
238 cur++;
239
240 if (*cur == 0)
241 break;
242 }
243 }
244 }
245
246 if ((i == 16) && (*cur != 0))
247 return EINVAL;
248
249 /* Create wildcard positions */
250 if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
251 size_t wildcard_shift = 16 - wildcard_size;
252
253 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
254 size_t j = i - 1;
255 data[j + wildcard_size] = data[j];
256 data[j] = 0;
257 }
258 }
259
260 return EOK;
261}
262
263/** Parses the character string into the address.
264 *
265 * @param[in] family The address family.
266 * @param[in] address The character buffer to be parsed.
267 * @param[out] data The address data to be filled.
268 *
269 * @return EOK on success.
270 * @return EINVAL if the data parameter is NULL.
271 * @return ENOENT if the address parameter is NULL.
272 * @return ENOTSUP if the address family is not supported.
273 *
274 */
275int inet_pton(uint16_t family, const char *address, uint8_t *data)
276{
277 switch (family) {
278 case AF_INET:
279 return inet_pton4(address, data);
280 case AF_INET6:
281 return inet_pton6(address, data);
282 default:
283 /** Unknown address family */
284 return ENOTSUP;
285 }
286}
287
288/** @}
289 */
Note: See TracBrowser for help on using the repository browser.