bluez tutorial ble link layer statemachine

 

 

bluez tutorial Non-Connectable & Scannable Advertising, Scanning State
Chapter 8 Section 8.11 — ADV_NONCONN_IND, ADV_SCAN_IND, Passive Scanning & Active Scanning
ADV_NONCONN
Listen only
ADV_SCAN
SCAN_REQ allowed
Passive Scan
Receive only
Active Scan
+ SCAN_REQ

Keywords:

BLE ADV_NONCONN_IND BLE non-connectable advertising BLE ADV_SCAN_IND BLE scannable undirected BLE passive scanning BLE active scanning SCAN_REQ BLE SCAN_REQ ScanA AdvA BlueZ hcitool lescan

Finishing the Advertising Event Types

The previous file covered Connectable Undirected (ADV_IND) and Connectable Directed (ADV_DIRECT_IND) — both of which allow devices to form connections. This file covers the remaining two event types: Non-Connectable Undirected (ADV_NONCONN_IND) and Scannable Undirected (ADV_SCAN_IND). Neither allows connections. We then move to the Scanning state and look at passive and active scanning in detail.

Event Type 3 — Non-Connectable Undirected (ADV_NONCONN_IND)

Pure Broadcast — No Connections, No Scan Requests

This advertising type is used when a device wants to broadcast information to anyone nearby but does not want anything back. The receiving scanner can only listen. It cannot send a SCAN_REQ for more data and it cannot send a CONNECT_REQ to start a connection. The information flows strictly one way.

This is the most restrictive advertising type in terms of what the receiver can do — but also the most power-efficient for the Advertiser because no response handling is needed. The Advertiser fires its packet and moves on.

Payload fields — same as ADV_IND:

AdvA (6 octets)

The Advertiser’s address. TxAdd header bit says if it is public or random.

AdvData (0–31 octets)

The actual broadcast data from the host — the payload the scanner receives.

Non-Connectable Undirected Event — One-Way Flow Only
Advertising
→→→→→→→→→→
ADV_NONCONN_IND
(AdvA + AdvData)
Scanning
(listen only)
✗ Scanner cannot send SCAN_REQ ✗ Scanner cannot send CONNECT_REQ

🔥 Example — Smart Microwave Oven:

Microwave advertises: “I’m a microwave. The food is cooked. Please take it out.”
Mobile phones, TVs, or set-top boxes in the house receive this notification and alert the user.
No device connects to or queries the microwave — it just broadcasts the status.
✈️ Example — Airport Information Beacon:

A BLE beacon near a departure gate broadcasts: “Flight ABC departs from Gate 123.”
Any passenger’s phone with a travel app can receive and display this information automatically.
Nobody connects to the beacon — it just broadcasts. The beacon could run for years on one battery.

Event Type 4 — Scannable Undirected (ADV_SCAN_IND)

Broadcast With Optional Extra Data — But Still No Connections

ADV_SCAN_IND sits between ADV_NONCONN_IND and ADV_IND in terms of what the receiver can do. Like ADV_NONCONN_IND, connections are not allowed — no device can send a CONNECT_REQ. But unlike ADV_NONCONN_IND, a Scanner can send a SCAN_REQ to request additional data from the Advertiser.

Think of it as a notice board: the Advertiser puts up a short message, and anyone can ask for the full document. But nobody can sit down and have a private conversation (connection) with the notice board.

Payload fields — same structure as ADV_NONCONN_IND:

AdvA (6 octets)

Advertiser’s address.

AdvData (0–31 octets)

The initial broadcast data. A Scanner may then ask for more via SCAN_REQ.

Scannable Undirected Event — SCAN_REQ Allowed, CONNECT_REQ Not
Advertising
ADV_SCAN_IND
Scanning
Advertising
SCAN_REQ ✓ allowed
Scanning
Advertising
CONNECT_REQ ✗ not allowed
Scanning

🎮 Real-world example — BLE Remote Control:

Remote control advertises via ADV_SCAN_IND: “I’m a remote control. A key has been pressed.”
The scanner (e.g. the TV) sends a SCAN_REQ to ask: “Which key was pressed?”
The remote responds with SCAN_RSP containing the key code.
No full connection is ever made — the TV processes the key press from the SCAN_RSP alone.

All Four Advertising Event Types — Side by Side Comparison
PDU Type SCAN_REQ? CONNECT_REQ? Use When…
ADV_IND ✓ (any device) Device wants to be discovered by and connected to anyone
ADV_DIRECT_IND ✓ (named only) Device wants to reconnect fast to one specific known peer
ADV_NONCONN_IND Device just broadcasts data, no interaction needed
ADV_SCAN_IND Device broadcasts but can provide extra data on request

8.11.1.3 — Scanning State

What the Scanning State Does

In the Scanning state, the link layer listens on the three advertising channels (37, 38, 39) for PDUs broadcast by Advertisers. The device in this state is called a Scanner. The Scanner never initiates a connection (that is the Initiating state’s job) — it only receives advertising packets and optionally asks for more data.

There are two modes of scanning, and which one is used depends on how much interaction the Scanner wants to have with Advertisers:

Passive Scanning — receive only Active Scanning — receive + SCAN_REQ

Passive Scanning — Just Listen

In passive scanning the Scanner only receives packets. It never sends anything back to the Advertiser — no SCAN_REQ, no response of any kind. The radio transmitter is completely unused in this mode. This makes passive scanning very power-efficient for the Scanner because receiving is cheaper than transmitting.

The Scanner’s job in passive mode:

  1. Receive advertising PDUs from nearby Advertisers
  2. Remove duplicate reports (the same Advertiser may be heard on all three channels in rapid succession — the Scanner deduplicates these)
  3. Pass advertising reports up to the host application, which decides what to do with the information
Passive Scanning — Receiving Multiple Advertising Packets

Advertising
ADV_IND (ch 37)
Scanning
receives

Advertising
ADV_IND (ch 38)
Scanning
duplicate

Advertising Report
(deduplicated) → Host
Scanner sends nothing back — TX is off the whole time
/* Passive BLE scan using BlueZ — hcitool lescan (passive flag) */
/* sudo hcitool lescan --passive */

/* In C using BlueZ HCI library: */
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

int start_passive_scan(int dev_id)
{
    int sock = hci_open_dev(dev_id);

    /* scan_type 0x00 = passive (never sends SCAN_REQ) */
    /* scan_type 0x01 = active  (may send SCAN_REQ)    */
    int err = hci_le_set_scan_parameters(
        sock,
        0x00,          /* passive scan — no SCAN_REQ */
        htobs(0x0010), /* scan interval 10ms         */
        htobs(0x0010), /* scan window   10ms         */
        0x00,          /* own address: public        */
        0x00,          /* accept all advertisers     */
        1000);

    if (err < 0) return err;

    /* filter_duplicates = 0x01 removes duplicate advertisers */
    return hci_le_set_scan_enable(sock, 0x01, 0x01, 1000);
}

Active Scanning — Listen and Ask for More

In active scanning the link layer does the same as passive scanning but additionally sends a SCAN_REQ to an Advertiser when it wants more information than the initial advertising packet contained. The Advertiser responds with a SCAN_RSP containing the extra data.

Important rule: The Scanner is only allowed to send a SCAN_REQ if the Advertiser used either an ADV_IND or an ADV_SCAN_IND — the two types that accept SCAN_REQ (marked “Yes” in the SCAN_REQ column of Table 8.4). If the Advertiser used ADV_DIRECT_IND or ADV_NONCONN_IND, the Scanner must stay silent and cannot ask for more data.

Active Scanning — SCAN_REQ and SCAN_RSP Exchange
Advertising
ADV_IND or ADV_SCAN_IND
Scanning
(active mode)
Advertising
SCAN_REQ
(ScanA + AdvA)
Scanning
Advertising
SCAN_RSP
(AdvA + ScanRspData)
Scanning

SCAN_REQ and SCAN_RSP Payload Fields

Both the SCAN_REQ and SCAN_RSP have defined payload structures. Knowing these fields is important when writing code that parses raw BLE advertising captures.

SCAN_REQ Payload (12 octets total)
ScanA (6 octets)

The Scanner’s own address. Public or random, indicated by the TxAdd bit in the PDU header. The Advertiser uses this to know who is asking.

AdvA (6 octets)

The Advertiser’s address. The Advertiser checks this field — if it matches its own address, it responds with SCAN_RSP. If not, it ignores the request (it was meant for someone else).

SCAN_RSP Payload (7–37 octets)
AdvA (6 octets)

The Advertiser’s address. Confirms which device is sending this response.

ScanRspData (0–31 octets)

The supplemental advertising data. This is the extra content the Advertiser sends in response to the SCAN_REQ — things like full device name, additional service UUIDs, or other information that did not fit in the original ADV_IND.

/* Parsing a SCAN_REQ/SCAN_RSP using BlueZ btmon output */
/* sudo btmon | grep -A 20 "LE Advertising Report" */

/* For an active scan, btmon output shows: */
/* > HCI Event: LE Meta Event (0x3e) plen 17                */
/*   LE Advertising Report (0x02)                           */
/*   Num reports: 1                                         */
/*   Event type: ADV_IND (connectable undirected) (0x00)    */
/*   Address type: Public (0x00)                            */
/*   Address: 00:1A:7D:DA:71:13 (Polar H7)                  */
/*   Data length: 7                                         */
/*   Flags: 0x06 (LE General Discoverable, BR/EDR not supp) */
/*   RSSI: -62 dBm                                          */

/* Then a SCAN_RSP follows automatically in active mode:    */
/* > HCI Event: LE Meta Event (0x3e) plen 27                */
/*   LE Advertising Report (0x02)                           */
/*   Event type: Scan Response (0x04)    <--- SCAN_RSP      */
/*   Address: 00:1A:7D:DA:71:13 (Polar H7)                  */
/*   Data length: 17                                        */
/*   Complete name: Polar H7             <--- extra data    */

/* Starting an active scan in code: */
hci_le_set_scan_parameters(sock,
    0x01,          /* 0x01 = ACTIVE scan mode */
    htobs(0x0010), /* interval */
    htobs(0x0010), /* window   */
    0x00, 0x00, 1000);
hci_le_set_scan_enable(sock, 0x01, 0x01, 1000);

Passive vs Active Scanning — When to Use Each
Passive Scanning

  • No SCAN_REQ sent — TX radio stays off
  • Lower power on the Scanner
  • Does not disturb the Advertiser
  • Good for background monitoring, proximity detection
  • Only gets data from the initial ADV packet
Active Scanning

  • Sends SCAN_REQ to get more data
  • Slightly higher power (TX on briefly)
  • Gets full device name and extra services
  • Good for device discovery UI, pairing screens
  • Only works with ADV_IND or ADV_SCAN_IND Advertisers

Chapter 8 — Related Files in This Series
📦

PDF 13

Packet Extensions
& Bit Stream
📡

PDF 46

Standby + Advertising
ADV_IND, ADV_DIRECT

PDF 79 (Here)

ADV_NONCONN, ADV_SCAN
& Scanning State

All Three Files Complete!

You now have complete coverage of BLE Data Packet Extensions, Bit Stream Processing, and all Link Layer non-connected states with every advertising event type and the full scanning state.

← PDF 46: Standby & Advertising ← PDF 13: Packet Extensions

Leave a Reply

Your email address will not be published. Required fields are marked *