/* SPDX-License-Identifier: GPL-3.0-only */ #include #include #include #include #include #include #include typedef uint8_t u8_t; typedef uint16_t u16_t; typedef int16_t s16_t; typedef struct { uint32_t addr; } ip4_addr_t; typedef struct { uint32_t client_address; bool renew; } dhcps_t; struct dhcps_state { u8_t state; }; enum { DHCPS_STATE_IDLE, DHCPS_STATE_ACK, DHCPS_STATE_NAK, DHCPS_STATE_OFFER, DHCPS_STATE_DECLINE, DHCPS_STATE_RELEASE }; /* SDK_DEFINES */ /* SDK_FUNCTIONS */ static unsigned cases; static u8_t check(dhcps_t *ctx, const u8_t *data, size_t len) { size_t page = (size_t)sysconf(_SC_PAGESIZE); u8_t *map = mmap(NULL, page * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); assert(map != MAP_FAILED && len <= page); assert(mprotect(map + page, page, PROT_NONE) == 0); u8_t *input = map + page - len; memcpy(input, data, len); u8_t result = parse_options(ctx, input, (s16_t)len); /* Upstream's pointer expressions stay within this larger backing object. */ u8_t padded[4096 + 258] = {0}; memcpy(padded, data, len); assert(result == upstream_parse_options(ctx, padded, (s16_t)len)); assert(memcmp(input, data, len) == 0); assert(munmap(map, page * 2) == 0); cases++; return result; } int main(void) { dhcps_t ctx = {.client_address = 0x04030201}; u8_t data[300] = {0}; assert(check(&ctx, data, 0) == DHCPS_STATE_IDLE); for (unsigned code = 0; code < 256; code++) { data[0] = code; check(&ctx, data, 1); for (unsigned length = 0; length < 256; length++) { data[1] = length; check(&ctx, data, 2); check(&ctx, data, 2 + length); if (length) check(&ctx, data, 1 + length); } } memset(data, 0, sizeof(data)); assert(check(&ctx, data, sizeof(data)) == DHCPS_STATE_IDLE); u8_t discover[] = {0, 0, 53, 1, 1, 255}; assert(check(&ctx, discover, sizeof(discover)) == DHCPS_STATE_OFFER); u8_t request[] = {53, 1, 3, 50, 4, 0, 0, 0, 0, 255}; memcpy(request + 5, &ctx.client_address, 4); assert(check(&ctx, request, sizeof(request)) == DHCPS_STATE_ACK); request[5] ^= 1; assert(check(&ctx, request, sizeof(request)) == DHCPS_STATE_NAK); assert(check(&ctx, request, 3) == DHCPS_STATE_NAK); ctx.renew = true; assert(check(&ctx, request, 3) == DHCPS_STATE_ACK); request[2] = 7; assert(check(&ctx, request, 3) == DHCPS_STATE_RELEASE); request[2] = 4; assert(check(&ctx, request, 3) == DHCPS_STATE_DECLINE); u8_t short_type[] = {53, 0, 255}; assert(check(&ctx, short_type, sizeof(short_type)) == DHCPS_STATE_IDLE); for (unsigned len = 0; len < 4; len++) { u8_t short_ip[] = {50, len, 1, 2, 3}; assert(check(&ctx, short_ip, len + 2) == DHCPS_STATE_IDLE); } u8_t end[] = {255, 53, 1, 1}; assert(check(&ctx, end, sizeof(end)) == DHCPS_STATE_IDLE); printf("DHCP extracted parser: %u guard-page / upstream-equivalence cases PASS\n", cases); }