Changeset 683e584 in mainline for uspace/lib/c/generic/inet/addr.c


Ignore:
Timestamp:
2015-05-15T18:19:26Z (9 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bf7587b0
Parents:
d6ff08a0
Message:

Revive IPv6 address parsing and formatting.

File:
1 edited

Legend:

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

    rd6ff08a0 r683e584  
    11/*
    22 * Copyright (c) 2013 Jiri Svoboda
     3 * Copyright (c) 2013 Martin Decky
    34 * All rights reserved.
    45 *
     
    233234        if (naddr->version != addr->version)
    234235                return 0;
    235        
     236
    236237        switch (naddr->version) {
    237238        case ip_v4:
     
    260261                if (naddr->prefix > 128)
    261262                        return 0;
    262                
     263
    263264                size_t pos = 0;
    264265                for (size_t i = 0; i < 16; i++) {
     
    266267                        if (naddr->prefix < pos)
    267268                                break;
    268                        
     269
    269270                        if (naddr->prefix - pos > 8) {
    270271                                /* Comparison without masking */
     
    278279                                        return 0;
    279280                        }
    280                        
     281
    281282                        pos += 8;
    282283                }
    283                
     284
    284285                return 1;
    285286        default:
     
    305306                i++;
    306307
    307                 if (*cur == 0)
     308                if (*cur == '\0')
    308309                        break;
    309310
     
    321322        }
    322323
    323         if (i != 4 || (*cur != 0))
     324        if (i != 4 || (*cur != '\0'))
    324325                return EINVAL;
    325326
     
    332333static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix)
    333334{
    334         /* XXX */
    335         return EINVAL;
     335        uint8_t data[16];
     336
     337        memset(data, 0, 16);
     338
     339        const char *cur = str;
     340        size_t i = 0;
     341        size_t wildcard_pos = (size_t) -1;
     342        size_t wildcard_size = 0;
     343
     344        /* Handle initial wildcard */
     345        if ((str[0] == ':') && (str[1] == ':')) {
     346                cur = str + 2;
     347                wildcard_pos = 0;
     348                wildcard_size = 16;
     349
     350                /* Handle the unspecified address */
     351                if (*cur == '\0')
     352                        goto success;
     353        }
     354
     355        while (i < 16) {
     356                uint16_t bioctet;
     357                int rc = str_uint16_t(cur, &cur, 16, false, &bioctet);
     358                if (rc != EOK)
     359                        return rc;
     360
     361                data[i] = (bioctet >> 8) & 0xff;
     362                data[i + 1] = bioctet & 0xff;
     363
     364                if (wildcard_pos != (size_t) -1) {
     365                        if (wildcard_size < 2)
     366                                return EINVAL;
     367
     368                        wildcard_size -= 2;
     369                }
     370
     371                i += 2;
     372
     373                if (*cur != ':')
     374                        break;
     375
     376                if (i < 16) {
     377                        cur++;
     378
     379                        /* Handle wildcard */
     380                        if (*cur == ':') {
     381                                if (wildcard_pos != (size_t) -1)
     382                                        return EINVAL;
     383
     384                                wildcard_pos = i;
     385                                wildcard_size = 16 - i;
     386                                cur++;
     387
     388                                if (*cur == '\0' || *cur == '/')
     389                                        break;
     390                        }
     391                }
     392        }
     393
     394        if (prefix != NULL) {
     395                if (*cur != '/')
     396                        return EINVAL;
     397                cur++;
     398
     399                *prefix = strtoul(cur, (char **)&cur, 10);
     400                if (*prefix > 128)
     401                        return EINVAL;
     402        }
     403
     404        if (*cur != '\0')
     405                return EINVAL;
     406
     407        /* Create wildcard positions */
     408        if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
     409                size_t wildcard_shift = 16 - wildcard_size;
     410
     411                for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
     412                        size_t j = i - 1;
     413                        data[j + wildcard_size] = data[j];
     414                        data[j] = 0;
     415                }
     416        }
     417
     418success:
     419        raddr->version = ip_v6;
     420        memcpy(raddr->addr6, data, 16);
     421        return EOK;
    336422}
    337423
     
    388474}
    389475
    390 static int inet_ntop6(const uint8_t *data, char *address, size_t length)
    391 {
    392         /* Check output buffer size */
    393         if (length < INET6_ADDRSTRLEN)
     476static int inet_addr_format_v4(addr32_t addr, char **bufp)
     477{
     478        int rc;
     479
     480        rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff,
     481            (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
     482        if (rc < 0)
    394483                return ENOMEM;
    395        
     484
     485        return EOK;
     486}
     487
     488static int inet_addr_format_v6(const addr128_t addr, char **bufp)
     489{
     490        *bufp = (char *) malloc(INET6_ADDRSTRLEN);
     491        if (*bufp == NULL)
     492                return ENOMEM;
     493
    396494        /* Find the longest zero subsequence */
    397        
     495
    398496        uint16_t zeroes[8];
    399497        uint16_t bioctets[8];
    400        
     498
    401499        for (size_t i = 8; i > 0; i--) {
    402500                size_t j = i - 1;
    403                
    404                 bioctets[j] = (data[j << 1] << 8) | data[(j << 1) + 1];
    405                
     501
     502                bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1];
     503
    406504                if (bioctets[j] == 0) {
    407505                        zeroes[j] = 1;
     
    411509                        zeroes[j] = 0;
    412510        }
    413        
     511
    414512        size_t wildcard_pos = (size_t) -1;
    415513        size_t wildcard_size = 0;
    416        
     514
    417515        for (size_t i = 0; i < 8; i++) {
    418516                if (zeroes[i] > wildcard_size) {
     
    421519                }
    422520        }
    423        
    424         char *cur = address;
    425         size_t rest = length;
     521
     522        char *cur = *bufp;
     523        size_t rest = INET6_ADDRSTRLEN;
    426524        bool tail_zero = false;
    427525        int ret;
    428        
     526
    429527        for (size_t i = 0; i < 8; i++) {
    430528                if ((i == wildcard_pos) && (wildcard_size > 1)) {
     
    439537                        tail_zero = false;
    440538                }
    441                
     539
    442540                if (ret < 0)
    443541                        return EINVAL;
    444                
     542
    445543                cur += ret;
    446544                rest -= ret;
    447545        }
    448        
    449         if (tail_zero) {
    450                 ret = snprintf(cur, rest, ":");
    451                 if (ret < 0)
    452                         return EINVAL;
    453         }
    454        
     546
     547        if (tail_zero)
     548                (void) snprintf(cur, rest, ":");
     549
    455550        return EOK;
    456551}
    457 
    458552
    459553/** Format node address.
     
    469563int inet_addr_format(const inet_addr_t *addr, char **bufp)
    470564{
    471         int rc = 0;
    472        
     565        int rc;
     566
     567        rc = ENOTSUP;
     568
    473569        switch (addr->version) {
    474570        case ip_any:
    475571                rc = asprintf(bufp, "none");
     572                if (rc < 0)
     573                        return ENOMEM;
     574                rc = EOK;
    476575                break;
    477576        case ip_v4:
    478                 rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
    479                     (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
    480                     addr->addr & 0xff);
     577                rc = inet_addr_format_v4(addr->addr, bufp);
    481578                break;
    482579        case ip_v6:
    483                 *bufp = (char *) malloc(INET6_ADDRSTRLEN);
    484                 if (*bufp == NULL)
    485                         return ENOMEM;
    486                
    487                 return inet_ntop6(addr->addr6, *bufp, INET6_ADDRSTRLEN);
    488         default:
    489                 asprintf(bufp, "<ver=%d>", addr->version);
    490                 return ENOTSUP;
    491         }
    492        
    493         if (rc < 0)
    494                 return ENOMEM;
    495        
    496         return EOK;
     580                rc = inet_addr_format_v6(addr->addr6, bufp);
     581                break;
     582        }
     583
     584        return rc;
    497585}
    498586
     
    509597int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
    510598{
    511         int rc = 0;
    512         char prefix[INET_PREFIXSTRSIZE];
    513        
     599        int rc;
     600        char *astr;
     601
     602        rc = ENOTSUP;
     603
    514604        switch (naddr->version) {
    515605        case ip_any:
    516606                rc = asprintf(bufp, "none");
     607                if (rc < 0)
     608                        return ENOMEM;
     609                rc = EOK;
    517610                break;
    518611        case ip_v4:
    519                 rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
    520                     "/%" PRIu8, (naddr->addr >> 24) & 0xff,
    521                     (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff,
    522                     naddr->addr & 0xff, naddr->prefix);
    523                 break;
    524         case ip_v6:
    525                 *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
    526                 if (*bufp == NULL)
     612                rc = inet_addr_format_v4(naddr->addr, &astr);
     613                if (rc != EOK)
    527614                        return ENOMEM;
    528                
    529                 rc = inet_ntop6(naddr->addr6, *bufp,
    530                     INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
    531                 if (rc != EOK) {
    532                         free(*bufp);
    533                         return rc;
    534                 }
    535                
    536                 rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8,
    537                     naddr->prefix);
     615
     616                rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
    538617                if (rc < 0) {
    539                         free(*bufp);
     618                        free(astr);
    540619                        return ENOMEM;
    541620                }
    542                
    543                 str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix);
    544                
    545                 break;
    546         default:
    547                 return ENOTSUP;
    548         }
    549        
    550         if (rc < 0)
    551                 return ENOMEM;
    552        
    553         return EOK;
     621
     622                rc = EOK;
     623                break;
     624        case ip_v6:
     625                rc = inet_addr_format_v6(naddr->addr6, &astr);
     626                if (rc != EOK)
     627                        return ENOMEM;
     628
     629                rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
     630                if (rc < 0) {
     631                        free(astr);
     632                        return ENOMEM;
     633                }
     634
     635                rc = EOK;
     636                break;
     637        }
     638
     639        return rc;
    554640}
    555641
Note: See TracChangeset for help on using the changeset viewer.