Ignore:
File:
1 edited

Legend:

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

    racdb5bac ra8196c9  
    3939#include <net/in6.h>
    4040#include <net/inet.h>
    41 
     41#include <inet/addr.h>
    4242#include <errno.h>
    4343#include <mem.h>
     
    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;
     
    94152}
    95153
     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
    96263/** Parses the character string into the address.
    97264 *
    98  *  If the string is shorter than the full address, zero bytes are added.
    99  *
    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.
     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 *
    107274 */
    108275int inet_pton(uint16_t family, const char *address, uint8_t *data)
    109276{
    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 */
    127277        switch (family) {
    128278        case AF_INET:
    129                 count = 4;
    130                 base = 10;
    131                 bytes = 1;
    132                 break;
    133 
     279                return inet_pton4(address, data);
    134280        case AF_INET6:
    135                 count = 16;
    136                 base = 16;
    137                 bytes = 4;
    138                 break;
    139 
     281                return inet_pton6(address, data);
    140282        default:
     283                /** Unknown address family */
    141284                return ENOTSUP;
    142285        }
    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;
    189286}
    190287
Note: See TracChangeset for help on using the changeset viewer.