Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a8196c9 in mainline


Ignore:
Timestamp:
2013-06-27T12:08:23Z (7 years ago)
Author:
Martin Decky <martin@…>
Branches:
master
Children:
4fb794c
Parents:
66cb7a2
Message:

routines for IPv6 address parsing and formatting

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/net/inet.c

    r66cb7a2 ra8196c9  
    4545#include <str.h>
    4646
     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
    47129/** Prints the address into the character buffer.
    48130 *
    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.
    57  */
    58 int
    59 inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length)
    60 {
    61         if ((!data) || (!address))
    62                 return EINVAL;
    63 
     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{
    64144        switch (family) {
    65145        case AF_INET:
    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 
     146                return inet_ntop4(data, address, length);
    76147        case AF_INET6:
    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 
     148                return inet_ntop6(data, address, length);
    91149        default:
    92150                return ENOTSUP;
     
    126184static int inet_pton6(const char *address, uint8_t *data)
    127185{
    128         // FIXME TODO
    129         return ENOTSUP;
     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;
    130261}
    131262
Note: See TracChangeset for help on using the changeset viewer.