Ignore:
File:
1 edited

Legend:

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

    re52b4b5 r9d58539  
    11/*
    2  * Copyright (c) 2013 Martin Decky
     2 * Copyright (c) 2009 Lukas Mejdrech
    33 * All rights reserved.
    44 *
     
    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 const in6_addr_t in6addr_any = {
    48         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
    49 };
    50 
    51 static 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 
    65 static 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 
    13347/** Prints the address into the character buffer.
    13448 *
    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  *
     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.
    14557 */
    146 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)
    14760{
     61        if ((!data) || (!address))
     62                return EINVAL;
     63
    14864        switch (family) {
    14965        case AF_INET:
    150                 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
    15176        case AF_INET6:
    152                 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
    15391        default:
    15492                return ENOTSUP;
     
    15694}
    15795
    158 static 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 
    188 static 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 
    26796/** Parses the character string into the address.
    26897 *
    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.
     98 *  If the string is shorter than the full address, zero bytes are added.
    27299 *
    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  *
     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.
    278107 */
    279108int inet_pton(uint16_t family, const char *address, uint8_t *data)
    280109{
     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 */
    281127        switch (family) {
    282128        case AF_INET:
    283                 return inet_pton4(address, data);
     129                count = 4;
     130                base = 10;
     131                bytes = 1;
     132                break;
     133
    284134        case AF_INET6:
    285                 return inet_pton6(address, data);
     135                count = 16;
     136                base = 16;
     137                bytes = 4;
     138                break;
     139
    286140        default:
    287                 /** Unknown address family */
    288141                return ENOTSUP;
    289142        }
     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;
    290189}
    291190
Note: See TracChangeset for help on using the changeset viewer.