Ignore:
File:
1 edited

Legend:

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

    ra8196c9 racdb5bac  
    3939#include <net/in6.h>
    4040#include <net/inet.h>
    41 #include <inet/addr.h>
     41
    4242#include <errno.h>
    4343#include <mem.h>
     
    4545#include <str.h>
    4646
    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                 } 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 
    12947/** Prints the address into the character buffer.
    13048 *
    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.
    14157 */
    142 int inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length)
     58int
     59inet_ntop(uint16_t family, const uint8_t *data, char *address, size_t length)
    14360{
     61        if ((!data) || (!address))
     62                return EINVAL;
     63
    14464        switch (family) {
    14565        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
    14776        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
    14991        default:
    15092                return ENOTSUP;
     
    15294}
    15395
    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 
    26396/** Parses the character string into the address.
    26497 *
    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.
    26899 *
    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.
    274107 */
    275108int inet_pton(uint16_t family, const char *address, uint8_t *data)
    276109{
     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 */
    277127        switch (family) {
    278128        case AF_INET:
    279                 return inet_pton4(address, data);
     129                count = 4;
     130                base = 10;
     131                bytes = 1;
     132                break;
     133
    280134        case AF_INET6:
    281                 return inet_pton6(address, data);
     135                count = 16;
     136                base = 16;
     137                bytes = 4;
     138                break;
     139
    282140        default:
    283                 /** Unknown address family */
    284141                return ENOTSUP;
    285142        }
     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;
    286189}
    287190
Note: See TracChangeset for help on using the changeset viewer.