[RFC] mgmt/BlueZ: explicit PDU type, independent PHY selection, SID, and directed-advertising support for extended advertising
From: kiran francis <hidden>
Date: 2026-09-12 21:39:57
First time posting to this list.
This affects both the kernel mgmt API and BlueZ's use of it, so posting as one thread rather than splitting across two.
hci_setup_ext_adv_instance_sync() decides several advertising parameters on its own instead of letting the caller set them directly:
1. PDU type isn't a parameter at all — it's guessed. The function picks the PDU type (ADV_IND, SCAN_IND, NONCONN_IND) by looking at a connectable flag combined with a separate global connectable setting, and an internal guess about whether the set is scannable. There's no parameter where a caller can just say "use this PDU type."
2. Primary and secondary PHY aren't explicit parameters either — and can't be selected independently. Like PDU type, PHY selection is derived from the SEC_2M/SEC_CODED flags rather than being fields a caller sets directly. The Core Spec allows primary PHY to be 1M or Coded (2M isn't valid on primary/legacy channels — a hardware limitation) and secondary PHY to be 1M, 2M, or Coded — six valid combinations. Today's code only reaches three of them:
if (flags & MGMT_ADV_FLAG_SEC_2M) {
cp.primary_phy = HCI_ADV_PHY_1M; cp.secondary_phy = HCI_ADV_PHY_2M;
} else if (flags & MGMT_ADV_FLAG_SEC_CODED) {
cp.primary_phy = HCI_ADV_PHY_CODED; cp.secondary_phy = HCI_ADV_PHY_CODED;
} else {
cp.primary_phy = HCI_ADV_PHY_1M; cp.secondary_phy = HCI_ADV_PHY_1M;
}
Primary=1M/secondary=Coded, primary=Coded/secondary=1M, and primary=Coded/secondary=2M are all unreachable. There's also a silent-priority bug here: if a caller sets both SEC_2M and SEC_CODED, the if wins and SEC_CODED is dropped with no error — a different result than either flag alone would suggest, with nothing telling the caller that happened.
3. Directed advertising can't be produced at all — not just unconfigurable. The PDU-type decision only ever resolves to CONN_IND, SCAN_IND, or NONCONN_IND, each as legacy or extended. Directed PDUs (ADV_DIRECT_IND and its extended form) are never one of the options, no matter what parameters are passed in. Fixing this needs new logic, not just a new field.
4. SID is always 0, with no way to change it. Every advertising set created through the normal path (add_advertising/add_ext_adv_params) gets SID 0, because the code that actually sets a non-zero SID only runs for Mesh/periodic advertising. A caller running several advertising sets at once has no way to give them distinct SIDs.
5. I've already implemented one example of this pattern locally, not yet submitted: an explicit MGMT_ADV_PARAM_CHANNEL_MAP flag/field so callers can set the channel map directly (previously also decided elsewhere, same as 1–4 above). I can include this as the first patch in the series if the general approach below looks right to you.
Proposal: add explicit parameters for PDU type, independent primary/secondary PHY, and SID, and add the missing code path for directed advertising — using the same shape as the channel-map patch above: a new flag bit plus an extra field per parameter, only active if the controller supports it.
Backward compatibility: each new field would follow the same pattern already used for channel map, so nothing changes for existing callers. The new flag bit is only ever reported as supported if the controller can actually do it, and an old kernel rejects a request that sets a bit it doesn't recognize — so a caller has to check first, the same as today. The new field is added at the end of the request struct, and the minimum accepted request size stays the same, so an old, shorter request still works unmodified. And if the new flag bit just isn't set on a given call, the kernel falls back to exactly today's behavior — same guessed PDU type, same PHY selection, same SID of 0, no directed PDU ever produced — byte for byte unchanged.
Regards,
Kiran Francis