Changes in uspace/lib/c/generic/net/inet.c [a8196c9:acdb5bac] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/net/inet.c
ra8196c9 racdb5bac 39 39 #include <net/in6.h> 40 40 #include <net/inet.h> 41 #include <inet/addr.h> 41 42 42 #include <errno.h> 43 43 #include <mem.h> … … 45 45 #include <str.h> 46 46 47 static 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 61 static 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 } else82 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 47 /** Prints the address into the character buffer. 130 48 * 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 * 49 * @param[in] family The address family. 50 * @param[in] data The address data. 51 * @param[out] address The character buffer to be filled. 52 * @param[in] length The buffer length. 53 * @return EOK on success. 54 * @return EINVAL if the data or address parameter is NULL. 55 * @return ENOMEM if the character buffer is not long enough. 56 * @return ENOTSUP if the address family is not supported. 141 57 */ 142 int inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length) 58 int 59 inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length) 143 60 { 61 if ((!data) || (!address)) 62 return EINVAL; 63 144 64 switch (family) { 145 65 case AF_INET: 146 return inet_ntop4(data, address, length); 66 /* Check output buffer size */ 67 if (length < INET_ADDRSTRLEN) 68 return ENOMEM; 69 70 /* Fill buffer with IPv4 address */ 71 snprintf(address, length, "%hhu.%hhu.%hhu.%hhu", 72 data[0], data[1], data[2], data[3]); 73 74 return EOK; 75 147 76 case AF_INET6: 148 return inet_ntop6(data, address, length); 77 /* Check output buffer size */ 78 if (length < INET6_ADDRSTRLEN) 79 return ENOMEM; 80 81 /* Fill buffer with IPv6 address */ 82 snprintf(address, length, 83 "%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:%hhx%hhx:" 84 "%hhx%hhx:%hhx%hhx", 85 data[0], data[1], data[2], data[3], data[4], data[5], 86 data[6], data[7], data[8], data[9], data[10], data[11], 87 data[12], data[13], data[14], data[15]); 88 89 return EOK; 90 149 91 default: 150 92 return ENOTSUP; … … 152 94 } 153 95 154 static 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 184 static 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 96 /** Parses the character string into the address. 264 97 * 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. 98 * If the string is shorter than the full address, zero bytes are added. 268 99 * 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 * 100 * @param[in] family The address family. 101 * @param[in] address The character buffer to be parsed. 102 * @param[out] data The address data to be filled. 103 * @return EOK on success. 104 * @return EINVAL if the data parameter is NULL. 105 * @return ENOENT if the address parameter is NULL. 106 * @return ENOTSUP if the address family is not supported. 274 107 */ 275 108 int inet_pton(uint16_t family, const char *address, uint8_t *data) 276 109 { 110 /** The base number of the values. */ 111 int base; 112 /** The number of bytes per a section. */ 113 size_t bytes; 114 /** The number of bytes of the address data. */ 115 int count; 116 117 const char *next; 118 char *last; 119 int index; 120 size_t shift; 121 unsigned long value; 122 123 if (!data) 124 return EINVAL; 125 126 /* Set processing parameters */ 277 127 switch (family) { 278 128 case AF_INET: 279 return inet_pton4(address, data); 129 count = 4; 130 base = 10; 131 bytes = 1; 132 break; 133 280 134 case AF_INET6: 281 return inet_pton6(address, data); 135 count = 16; 136 base = 16; 137 bytes = 4; 138 break; 139 282 140 default: 283 /** Unknown address family */284 141 return ENOTSUP; 285 142 } 143 144 /* Erase if no address */ 145 if (!address) { 146 memset(data, 0, count); 147 return ENOENT; 148 } 149 150 /* Process string from the beginning */ 151 next = address; 152 index = 0; 153 do { 154 /* If the actual character is set */ 155 if (next && *next) { 156 157 /* If not on the first character */ 158 if (index) { 159 /* Move to the next character */ 160 ++next; 161 } 162 163 /* Parse the actual integral value */ 164 value = strtoul(next, &last, base); 165 /* 166 * Remember the last problematic character 167 * should be either '.' or ':' but is ignored to be 168 * more generic 169 */ 170 next = last; 171 172 /* Fill the address data byte by byte */ 173 shift = bytes - 1; 174 do { 175 /* like little endian */ 176 data[index + shift] = value; 177 value >>= 8; 178 } while(shift --); 179 180 index += bytes; 181 } else { 182 /* Erase the rest of the address */ 183 memset(data + index, 0, count - index); 184 return EOK; 185 } 186 } while (index < count); 187 188 return EOK; 286 189 } 287 190
Note:
See TracChangeset
for help on using the changeset viewer.