1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <string.h>
350aadb33SDmitri Tikhonov
450aadb33SDmitri Tikhonov#include "lsquic.h"
550aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
650aadb33SDmitri Tikhonov#include "lsquic_version.h"
750aadb33SDmitri Tikhonov
8fb3e20e0SDmitri Tikhonov#if _MSC_VER
9fb3e20e0SDmitri Tikhonov#include "vc_compat.h"
10fb3e20e0SDmitri Tikhonov#endif
11fb3e20e0SDmitri Tikhonov
1250aadb33SDmitri Tikhonov
1350aadb33SDmitri Tikhonovstatic const unsigned char version_tags[N_LSQVER][4] =
1450aadb33SDmitri Tikhonov{
15c95974e9SDmitri Tikhonov    [LSQVER_043] = { 'Q', '0', '4', '3', },
16c7d81ce1SDmitri Tikhonov    [LSQVER_046] = { 'Q', '0', '4', '6', },
177a8b2eceSDmitri Tikhonov    [LSQVER_050] = { 'Q', '0', '5', '0', },
18bc520ef7SDmitri Tikhonov    [LSQVER_ID27] = { 0xFF, 0, 0, 27, },
194051ae3aSDmitri Tikhonov    [LSQVER_ID29] = { 0xFF, 0, 0, 29, },
2026e8f082SDmitri Tikhonov    [LSQVER_I001] = {    0, 0, 0, 1, },
215392f7a3SLiteSpeed Tech    [LSQVER_VERNEG] = { 0xFA, 0xFA, 0xFA, 0xFA, },
2250aadb33SDmitri Tikhonov};
2350aadb33SDmitri Tikhonov
2450aadb33SDmitri Tikhonov
2550aadb33SDmitri Tikhonovuint32_t
2650aadb33SDmitri Tikhonovlsquic_ver2tag (unsigned version)
2750aadb33SDmitri Tikhonov{
2850aadb33SDmitri Tikhonov    lsquic_ver_tag_t tag;
2950aadb33SDmitri Tikhonov    if (version < N_LSQVER)
3050aadb33SDmitri Tikhonov    {
3150aadb33SDmitri Tikhonov        memcpy(&tag, version_tags[version], 4);
3250aadb33SDmitri Tikhonov        return tag;
3350aadb33SDmitri Tikhonov    }
3450aadb33SDmitri Tikhonov    else
3550aadb33SDmitri Tikhonov        return 0;
3650aadb33SDmitri Tikhonov}
3750aadb33SDmitri Tikhonov
3850aadb33SDmitri Tikhonov
3950aadb33SDmitri Tikhonovenum lsquic_version
4050aadb33SDmitri Tikhonovlsquic_tag2ver (uint32_t ver_tag)
4150aadb33SDmitri Tikhonov{
4250aadb33SDmitri Tikhonov    unsigned n;
4350aadb33SDmitri Tikhonov    for (n = 0; n < sizeof(version_tags) / sizeof(version_tags[0]); ++n)
4450aadb33SDmitri Tikhonov        if (0 == memcmp(version_tags[n], &ver_tag, sizeof(ver_tag)))
4550aadb33SDmitri Tikhonov            return n;
4650aadb33SDmitri Tikhonov    return -1;
4750aadb33SDmitri Tikhonov}
4850aadb33SDmitri Tikhonov
4950aadb33SDmitri Tikhonov
505392f7a3SLiteSpeed Techconst char *const lsquic_ver2str[N_LSQVER] = {
515392f7a3SLiteSpeed Tech    [LSQVER_043] = "Q043",
525392f7a3SLiteSpeed Tech    [LSQVER_046] = "Q046",
537a8b2eceSDmitri Tikhonov    [LSQVER_050] = "Q050",
54bc520ef7SDmitri Tikhonov    [LSQVER_ID27] = "FF00001B",
554051ae3aSDmitri Tikhonov    [LSQVER_ID29] = "FF00001D",
5626e8f082SDmitri Tikhonov    [LSQVER_I001] = "00000001",
575392f7a3SLiteSpeed Tech    [LSQVER_VERNEG] = "FAFAFAFA",
585392f7a3SLiteSpeed Tech};
595392f7a3SLiteSpeed Tech
605392f7a3SLiteSpeed Tech
61082507cdSGeorge Wangconst char *const lsquic_ver2altstr[N_LSQVER] = {
62082507cdSGeorge Wang    [LSQVER_043] = NULL,
63082507cdSGeorge Wang    [LSQVER_046] = NULL,
64082507cdSGeorge Wang    [LSQVER_050] = NULL,
65082507cdSGeorge Wang    [LSQVER_ID27] = "h3-27",
66082507cdSGeorge Wang    [LSQVER_ID29] = "h3-29",
67082507cdSGeorge Wang    [LSQVER_I001] = "h3",
68082507cdSGeorge Wang    [LSQVER_VERNEG] = "VERNEG",
69082507cdSGeorge Wang};
70082507cdSGeorge Wang
71082507cdSGeorge Wang
7250aadb33SDmitri Tikhonovenum lsquic_version
7350aadb33SDmitri Tikhonovlsquic_str2ver (const char *str, size_t len)
7450aadb33SDmitri Tikhonov{
755392f7a3SLiteSpeed Tech    enum lsquic_version ver;
7650aadb33SDmitri Tikhonov    uint32_t tag;
7750aadb33SDmitri Tikhonov
7850aadb33SDmitri Tikhonov    if (len == sizeof(tag) && 'Q' == str[0])
7950aadb33SDmitri Tikhonov    {
8050aadb33SDmitri Tikhonov        memcpy(&tag, str, sizeof(tag));
8150aadb33SDmitri Tikhonov        return lsquic_tag2ver(tag);
8250aadb33SDmitri Tikhonov    }
8350aadb33SDmitri Tikhonov
845392f7a3SLiteSpeed Tech    for (ver = 0; ver < N_LSQVER; ++ver)
85082507cdSGeorge Wang    {
865392f7a3SLiteSpeed Tech        if (strlen(lsquic_ver2str[ver]) == len
875392f7a3SLiteSpeed Tech            && strncasecmp(lsquic_ver2str[ver], str, len) == 0)
885392f7a3SLiteSpeed Tech        {
895392f7a3SLiteSpeed Tech            return ver;
905392f7a3SLiteSpeed Tech        }
91082507cdSGeorge Wang        if (lsquic_ver2altstr[ver] && strlen(lsquic_ver2altstr[ver]) == len
92082507cdSGeorge Wang            && strncasecmp(lsquic_ver2altstr[ver], str, len) == 0)
93082507cdSGeorge Wang        {
94082507cdSGeorge Wang            return ver;
95082507cdSGeorge Wang        }
96082507cdSGeorge Wang    }
975392f7a3SLiteSpeed Tech    return -1;
985392f7a3SLiteSpeed Tech}
9950aadb33SDmitri Tikhonov
10050aadb33SDmitri Tikhonov
1015392f7a3SLiteSpeed Techint
1025392f7a3SLiteSpeed Techlsquic_gen_ver_tags (unsigned char *buf, size_t bufsz, unsigned version_bitmask)
1035392f7a3SLiteSpeed Tech{
1045392f7a3SLiteSpeed Tech    unsigned n;
1055392f7a3SLiteSpeed Tech    lsquic_ver_tag_t tag;
1065392f7a3SLiteSpeed Tech    unsigned char *p = buf;
1075392f7a3SLiteSpeed Tech    unsigned char *const pend = p + bufsz;
1085392f7a3SLiteSpeed Tech    for (n = 0; version_bitmask; ++n)
1095392f7a3SLiteSpeed Tech    {
1105392f7a3SLiteSpeed Tech        if (version_bitmask & (1 << n))
1115392f7a3SLiteSpeed Tech        {
1125392f7a3SLiteSpeed Tech            if (p + 4 > pend)
1135392f7a3SLiteSpeed Tech                return -1;
1145392f7a3SLiteSpeed Tech            version_bitmask &= ~(1 << n);
1155392f7a3SLiteSpeed Tech            tag = lsquic_ver2tag(n);
1165392f7a3SLiteSpeed Tech            if (0 == tag)
1175392f7a3SLiteSpeed Tech                return -1;
1185392f7a3SLiteSpeed Tech            memcpy(p, &tag, 4);
1195392f7a3SLiteSpeed Tech            p += 4;
1205392f7a3SLiteSpeed Tech        }
1215392f7a3SLiteSpeed Tech    }
1225392f7a3SLiteSpeed Tech    return p - buf;
1235392f7a3SLiteSpeed Tech}
124