cybersecurity · intermediate · ~15 min · safe pentest lab

Extract the BLE Complete Local Name from an advertisement

Bounds-safe TLV walking with overflow checks at every step.

Challenge

Your job

Implement:

#include <stdint.h>
#include <stddef.h>
int extract_local_name(const uint8_t *adv, size_t n, char *out, size_t cap);

Walk the TLV-encoded advertisement. Each record is:

[len] [type] [value bytes... (len-1 of them)]

Note: len covers type + value together, so the next record starts at offset + len + 1.

When you encounter a record with type 0x09 (Complete Local Name) OR 0x08 (Shortened Local Name), copy its value bytes into out (bounded by cap - 1, NUL-terminating), and return the number of value bytes copied.

Return -1 if:

  • Any pointer is NULL or cap == 0
  • A record's length would walk past n
  • A len == 0 record is encountered (malformed)
  • The name would not fit in cap (need room for NUL)
  • No name field is found

Hints

  1. (concept) offset starts at 0; each loop iteration reads len at adv[offset], then type at adv[offset + 1], then advances by len + 1.
  2. (common bug) Allowing len == 0 spins the loop forever.
  3. (direction) The name's value length is len - 1 (because type takes one of those bytes).

Why this matters

TLV walking is a foundational pattern that shows up in BLE, DHCP, ICMPv6 options, X.509 extensions — get it right once and the rest fall out.

Input format

A const byte buffer, its length, a bounded output buffer, and its capacity.

Output format

Number of name bytes copied (>= 0) on success, -1 otherwise.

Constraints

Every byte read must be bounds-checked. NUL-terminate the output. Fail on len==0.

Starter code

#include <stdint.h>
#include <stddef.h>
int extract_local_name(const uint8_t *adv, size_t n, char *out, size_t cap) {
    /* TODO */
    (void)adv; (void)n; (void)out; (void)cap;
    return -1;
}

Common mistakes

Forgetting that len covers type+value (so the value is len - 1 bytes). Allowing len == 0. Reading the value before bounds-checking.

Edge cases to handle

Empty buffer (n == 0). Single record with no name. Name field at the very end of the buffer.

Complexity

O(n) — visits each byte at most once.

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.