1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
25392f7a3SLiteSpeed Tech/*
35392f7a3SLiteSpeed Tech * lsquic_varint.c -- routines dealing with IETF QUIC varint.
45392f7a3SLiteSpeed Tech */
55392f7a3SLiteSpeed Tech
65392f7a3SLiteSpeed Tech#include <assert.h>
75392f7a3SLiteSpeed Tech#include <stdint.h>
85392f7a3SLiteSpeed Tech#include <string.h>
95392f7a3SLiteSpeed Tech
105392f7a3SLiteSpeed Tech#include "lsquic_byteswap.h"
115392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
125392f7a3SLiteSpeed Tech
135392f7a3SLiteSpeed Tech/* Returns number of bytes read from p (1, 2, 4, or 8), or a negative
145392f7a3SLiteSpeed Tech * value on error.
155392f7a3SLiteSpeed Tech */
165392f7a3SLiteSpeed Techint
175392f7a3SLiteSpeed Techlsquic_varint_read (const unsigned char *p, const unsigned char *end,
185392f7a3SLiteSpeed Tech                                                            uint64_t *valp)
195392f7a3SLiteSpeed Tech{
205392f7a3SLiteSpeed Tech    uint64_t val;
215392f7a3SLiteSpeed Tech
225392f7a3SLiteSpeed Tech    if (p >= end)
235392f7a3SLiteSpeed Tech        return -1;
245392f7a3SLiteSpeed Tech
255392f7a3SLiteSpeed Tech    switch (*p >> 6)
265392f7a3SLiteSpeed Tech    {
275392f7a3SLiteSpeed Tech    case 0:
285392f7a3SLiteSpeed Tech        *valp = *p;
295392f7a3SLiteSpeed Tech        return 1;
305392f7a3SLiteSpeed Tech    case 1:
315392f7a3SLiteSpeed Tech        if (p + 1 >= end)
325392f7a3SLiteSpeed Tech            return -1;
335392f7a3SLiteSpeed Tech        *valp = (p[0] & VINT_MASK) << 8
345392f7a3SLiteSpeed Tech              |  p[1]
355392f7a3SLiteSpeed Tech              ;
365392f7a3SLiteSpeed Tech        return 2;
375392f7a3SLiteSpeed Tech    case 2:
385392f7a3SLiteSpeed Tech        if (p + 3 >= end)
395392f7a3SLiteSpeed Tech            return -1;
405392f7a3SLiteSpeed Tech        *valp = (p[0] & VINT_MASK) << 24
415392f7a3SLiteSpeed Tech              |  p[1] << 16
425392f7a3SLiteSpeed Tech              |  p[2] << 8
435392f7a3SLiteSpeed Tech              |  p[3] << 0
445392f7a3SLiteSpeed Tech              ;
455392f7a3SLiteSpeed Tech        return 4;
465392f7a3SLiteSpeed Tech    default:
475392f7a3SLiteSpeed Tech        if (p + 7 >= end)
485392f7a3SLiteSpeed Tech            return -1;
495392f7a3SLiteSpeed Tech        memcpy(&val, p, 8);
505392f7a3SLiteSpeed Tech#if __BYTE_ORDER == __LITTLE_ENDIAN
515392f7a3SLiteSpeed Tech        val = bswap_64(val);
525392f7a3SLiteSpeed Tech#endif
535392f7a3SLiteSpeed Tech        val &= (1ULL << 62) - 1;
545392f7a3SLiteSpeed Tech        *valp = val;
555392f7a3SLiteSpeed Tech        return 8;
565392f7a3SLiteSpeed Tech    }
575392f7a3SLiteSpeed Tech}
585392f7a3SLiteSpeed Tech
595392f7a3SLiteSpeed Tech
605392f7a3SLiteSpeed Techint
615392f7a3SLiteSpeed Techlsquic_varint_read_nb (const unsigned char **pp, const unsigned char *end,
625392f7a3SLiteSpeed Tech                                            struct varint_read_state *state)
635392f7a3SLiteSpeed Tech{
645392f7a3SLiteSpeed Tech    const unsigned char *p = *pp;
655392f7a3SLiteSpeed Tech
665392f7a3SLiteSpeed Tech    if (p >= end)
675392f7a3SLiteSpeed Tech        return -1;
685392f7a3SLiteSpeed Tech
695392f7a3SLiteSpeed Tech    switch (state->pos ? state->pos : *p >> 6)
705392f7a3SLiteSpeed Tech    {
715392f7a3SLiteSpeed Tech    case 0:
725392f7a3SLiteSpeed Tech        state->val = *p++;
735392f7a3SLiteSpeed Tech        *pp = p;
745392f7a3SLiteSpeed Tech        return 0;
755392f7a3SLiteSpeed Tech    case 1:
765392f7a3SLiteSpeed Tech        state->val = (*p++ & VINT_MASK) << 8;
77747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1000; break; }
78747be414SDmitri Tikhonov        /* fall through */
79747be414SDmitri Tikhonov    case 1000:
805392f7a3SLiteSpeed Tech        state->val |= *p++;
815392f7a3SLiteSpeed Tech        *pp = p;
825392f7a3SLiteSpeed Tech        return 0;
835392f7a3SLiteSpeed Tech    case 2:
845392f7a3SLiteSpeed Tech        if (p + 3 < end)
855392f7a3SLiteSpeed Tech        {
865392f7a3SLiteSpeed Tech            state->val = (p[0] & VINT_MASK) << 24
875392f7a3SLiteSpeed Tech                       |  p[1] << 16
885392f7a3SLiteSpeed Tech                       |  p[2] << 8
895392f7a3SLiteSpeed Tech                       |  p[3] << 0
905392f7a3SLiteSpeed Tech                       ;
915392f7a3SLiteSpeed Tech            *pp += 4;
925392f7a3SLiteSpeed Tech            return 0;
935392f7a3SLiteSpeed Tech        }
945392f7a3SLiteSpeed Tech        state->val = (*p++ & VINT_MASK) << 24;
95747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1001; break; }
96747be414SDmitri Tikhonov        /* fall through */
97747be414SDmitri Tikhonov    case 1001:
985392f7a3SLiteSpeed Tech        state->val |= *p++ << 16;
99747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1002; break; }
100747be414SDmitri Tikhonov        /* fall through */
101747be414SDmitri Tikhonov    case 1002:
1025392f7a3SLiteSpeed Tech        state->val |= *p++ << 8;
103747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1003; break; }
104747be414SDmitri Tikhonov        /* fall through */
105747be414SDmitri Tikhonov    case 1003:
1065392f7a3SLiteSpeed Tech        state->val |= *p++;
1075392f7a3SLiteSpeed Tech        *pp = p;
1085392f7a3SLiteSpeed Tech        return 0;
1095392f7a3SLiteSpeed Tech    case 3:
1105392f7a3SLiteSpeed Tech        if (p + 7 < end)
1115392f7a3SLiteSpeed Tech        {
1125392f7a3SLiteSpeed Tech            memcpy(&state->val, p, 8);
1135392f7a3SLiteSpeed Tech#if __BYTE_ORDER == __LITTLE_ENDIAN
1145392f7a3SLiteSpeed Tech            state->val = bswap_64(state->val);
1155392f7a3SLiteSpeed Tech#endif
1165392f7a3SLiteSpeed Tech            state->val &= (1ULL << 62) - 1;
1175392f7a3SLiteSpeed Tech            *pp += 8;
1185392f7a3SLiteSpeed Tech            return 0;
1195392f7a3SLiteSpeed Tech        }
1205392f7a3SLiteSpeed Tech        state->val = (uint64_t) (*p++ & VINT_MASK) << 56;
121747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1004; break; }
122747be414SDmitri Tikhonov        /* fall through */
123747be414SDmitri Tikhonov    case 1004:
1245392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 48;
125747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1005; break; }
126747be414SDmitri Tikhonov        /* fall through */
127747be414SDmitri Tikhonov    case 1005:
1285392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 40;
129747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1006; break; }
130747be414SDmitri Tikhonov        /* fall through */
131747be414SDmitri Tikhonov    case 1006:
1325392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 32;
133747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1007; break; }
134747be414SDmitri Tikhonov        /* fall through */
135747be414SDmitri Tikhonov    case 1007:
1365392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 24;
137747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1008; break; }
138747be414SDmitri Tikhonov        /* fall through */
139747be414SDmitri Tikhonov    case 1008:
1405392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 16;
141747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1009; break; }
142747be414SDmitri Tikhonov        /* fall through */
143747be414SDmitri Tikhonov    case 1009:
1445392f7a3SLiteSpeed Tech        state->val |= (uint64_t) *p++ << 8;
145747be414SDmitri Tikhonov        if (p >= end) { state->pos = 1010; break; }
146747be414SDmitri Tikhonov        /* fall through */
147747be414SDmitri Tikhonov    case 1010:
1485392f7a3SLiteSpeed Tech        state->val |= *p++;
1495392f7a3SLiteSpeed Tech        *pp = p;
1505392f7a3SLiteSpeed Tech        return 0;
1515392f7a3SLiteSpeed Tech    default:
1525392f7a3SLiteSpeed Tech        assert(0);
1535392f7a3SLiteSpeed Tech    }
1545392f7a3SLiteSpeed Tech
1555392f7a3SLiteSpeed Tech    *pp = p;
1565392f7a3SLiteSpeed Tech    return -1;
1575392f7a3SLiteSpeed Tech}
1585392f7a3SLiteSpeed Tech
1595392f7a3SLiteSpeed Tech
1605392f7a3SLiteSpeed Techint
1615392f7a3SLiteSpeed Techlsquic_varint_read_two (const unsigned char **begin, const unsigned char *end,
1625392f7a3SLiteSpeed Tech                            struct varint_read2_state *state)
1635392f7a3SLiteSpeed Tech{
1645392f7a3SLiteSpeed Tech    const unsigned char *p = *begin;
1655392f7a3SLiteSpeed Tech    int s;
1665392f7a3SLiteSpeed Tech
1675392f7a3SLiteSpeed Tech    while (p < end)
1685392f7a3SLiteSpeed Tech    {
1695392f7a3SLiteSpeed Tech        switch (state->vr2s_state)
1705392f7a3SLiteSpeed Tech        {
1715392f7a3SLiteSpeed Tech        case VR2S_READ_ONE_BEGIN:
1725392f7a3SLiteSpeed Tech            state->vr2s_varint_state.pos = 0;
1735392f7a3SLiteSpeed Tech            state->vr2s_state = VR2S_READ_ONE_CONTINUE;
1745392f7a3SLiteSpeed Tech            goto cont;
1755392f7a3SLiteSpeed Tech        case VR2S_READ_TWO_BEGIN:
1765392f7a3SLiteSpeed Tech            state->vr2s_varint_state.pos = 0;
1775392f7a3SLiteSpeed Tech            state->vr2s_state = VR2S_READ_TWO_CONTINUE;
1785392f7a3SLiteSpeed Tech            goto cont;
1795392f7a3SLiteSpeed Tech  cont: case VR2S_READ_ONE_CONTINUE:
1805392f7a3SLiteSpeed Tech        case VR2S_READ_TWO_CONTINUE:
1815392f7a3SLiteSpeed Tech            s = lsquic_varint_read_nb(&p, end, &state->vr2s_varint_state);
1825392f7a3SLiteSpeed Tech            if (s == 0)
1835392f7a3SLiteSpeed Tech            {
1845392f7a3SLiteSpeed Tech                if (state->vr2s_state == VR2S_READ_TWO_CONTINUE)
1855392f7a3SLiteSpeed Tech                    goto done;
1865392f7a3SLiteSpeed Tech                state->vr2s_one = state->vr2s_varint_state.val;
1875392f7a3SLiteSpeed Tech                state->vr2s_state = VR2S_READ_TWO_BEGIN;
1885392f7a3SLiteSpeed Tech                break;
1895392f7a3SLiteSpeed Tech            }
1905392f7a3SLiteSpeed Tech            else
1915392f7a3SLiteSpeed Tech                goto more;
1925392f7a3SLiteSpeed Tech        }
1935392f7a3SLiteSpeed Tech    }
1945392f7a3SLiteSpeed Tech
1955392f7a3SLiteSpeed Tech  more:
1965392f7a3SLiteSpeed Tech    *begin = p;
1975392f7a3SLiteSpeed Tech    return -1;
1985392f7a3SLiteSpeed Tech
1995392f7a3SLiteSpeed Tech  done:
2005392f7a3SLiteSpeed Tech    *begin = p;
2015392f7a3SLiteSpeed Tech    return 0;
2025392f7a3SLiteSpeed Tech}
203