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

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

add in6addr_any

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