Ignore:
File:
1 edited

Legend:

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

    r9d58539 re52b4b5  
    11/*
    2  * Copyright (c) 2009 Lukas Mejdrech
     2 * Copyright (c) 2013 Martin Decky
    33 * All rights reserved.
    44 *
     
    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
     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
    47133/** Prints the address into the character buffer.
    48134 *
    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 
     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{
    64148        switch (family) {
    65149        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 
     150                return inet_ntop4(data, address, length);
    76151        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 
     152                return inet_ntop6(data, address, length);
    91153        default:
    92154                return ENOTSUP;
     
    94156}
    95157
     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
    96267/** Parses the character string into the address.
    97268 *
    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.
     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 *
    107278 */
    108279int inet_pton(uint16_t family, const char *address, uint8_t *data)
    109280{
    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 */
    127281        switch (family) {
    128282        case AF_INET:
    129                 count = 4;
    130                 base = 10;
    131                 bytes = 1;
    132                 break;
    133 
     283                return inet_pton4(address, data);
    134284        case AF_INET6:
    135                 count = 16;
    136                 base = 16;
    137                 bytes = 4;
    138                 break;
    139 
     285                return inet_pton6(address, data);
    140286        default:
     287                /** Unknown address family */
    141288                return ENOTSUP;
    142289        }
    143 
    144         /* Erase if no address */
    145         if (!address) {
    146                 bzero(data, 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                         bzero(data + index, count - index);
    184                         return EOK;
    185                 }
    186         } while (index < count);
    187 
    188         return EOK;
    189290}
    190291
Note: See TracChangeset for help on using the changeset viewer.