@@ -443,11 +443,51 @@ __ https://github.com/google/eddystone/tree/master/eddystone-url
443443 'https://scapy.net').build_set_advertising_data())
444444
445445 Once :ref: `advertising has been started <le-adv-start >`, the beacon may then be
446- detected with the `Eddystone Validator `__ (Android):
446+ detected with `Eddystone Validator `__ or ` Beacon Locator `__ (Android):
447447
448448.. image :: ../graphics/ble_eddystone_url.png
449449
450450__ https://github.com/google/eddystone/tree/master/tools/eddystone-validator
451+ __ https://github.com/vitas/beaconloc
452+
453+ .. _adv-ibeacon :
454+
455+ iBeacon
456+ ^^^^^^^
457+
458+ `iBeacon `__ is a proximity beacon protocol developed by Apple, which uses their
459+ manufacturer-specific data field. :ref: `Apple/iBeacon framing <apple-ble >`
460+ (below) describes this in more detail.
461+
462+ __ https://en.wikipedia.org/wiki/IBeacon
463+
464+ This example sets up a virtual iBeacon:
465+
466+ .. code-block :: python3
467+
468+ # Load the contrib module for iBeacon
469+ load_contrib('ibeacon')
470+
471+ # Beacon data consists of a UUID, and two 16-bit integers: "major" and
472+ # "minor".
473+ #
474+ # iBeacon sits ontop of Apple's BLE protocol.
475+ p = Apple_BLE_Submessage()/IBeacon_Data(
476+ uuid='fb0b57a2-8228-44cd-913a-94a122ba1206',
477+ major=1, minor=2)
478+
479+ # build_set_advertising_data() wraps an Apple_BLE_Submessage or
480+ # Apple_BLE_Frame into a HCI_Cmd_LE_Set_Advertising_Data payload, that can
481+ # be sent to the BLE controller.
482+ bt.sr(p.build_set_advertising_data())
483+
484+ Once :ref: `advertising has been started <le-adv-start >`, the beacon may then be
485+ detected with `Beacon Locator `__ (Android):
486+
487+ .. image :: ../graphics/ble_ibeacon.png
488+
489+ __ https://github.com/vitas/beaconloc
490+
451491
452492.. _le-adv-start :
453493
@@ -495,3 +535,104 @@ __ https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
495535
496536__ https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
497537
538+ .. _apple-ble :
539+
540+ Apple/iBeacon broadcast frames
541+ ==============================
542+
543+ .. note ::
544+
545+ This describes the wire format for Apple's Bluetooth Low Energy
546+ advertisements, based on (limited) publicly available information. It is not
547+ specific to using Bluetooth on Apple operating systems.
548+
549+ `iBeacon `__ is Apple's proximity beacon protocol. Scapy includes a contrib
550+ module, ``ibeacon ``, for working with Apple's :abbr: `BLE ( Bluetooth Low Energy ) `
551+ broadcasts:
552+
553+ __ https://en.wikipedia.org/wiki/IBeacon
554+
555+ .. code-block :: pycon
556+
557+ >>> load_contrib('ibeacon')
558+
559+ :ref: `Setting up advertising for iBeacon <adv-ibeacon >` (above) describes how to
560+ broadcast a simple beacon.
561+
562+ While this module is called ``ibeacon ``, Apple has other "submessages" which are
563+ also advertised within their manufacturer-specific data field, including:
564+
565+ * `AirDrop `__
566+ * AirPlay
567+ * AirPods
568+ * `Handoff `__
569+ * Nearby
570+
571+ __ https://en.wikipedia.org/wiki/AirDrop
572+ __ https://en.wikipedia.org/wiki/OS_X_Yosemite#Continuity
573+
574+ For compatibility with these other broadcasts, Apple BLE frames in Scapy are
575+ layered on top of ``Apple_BLE_Submessage `` and ``Apple_BLE_Frame ``:
576+
577+ * ``HCI_Cmd_LE_Set_Advertising_Data ``, ``HCI_LE_Meta_Advertising_Report ``,
578+ ``BTLE_ADV_IND ``, ``BTLE_ADV_NONCONN_IND `` or ``BTLE_ADV_SCAN_IND `` contain
579+ one or more...
580+ * ``EIR_Hdr ``, which may have a payload of one...
581+ * ``EIR_Manufacturer_Specific_Data ``, which may have a payload of one...
582+ * ``Apple_BLE_Frame ``, which contains one or more...
583+ * ``Apple_BLE_Submessage ``, which contains a payload of one...
584+ * ``Raw `` (if not supported), or ``IBeacon_Data ``.
585+
586+ This module only presently supports ``IBeacon_Data `` submessages. Other
587+ submessages are decoded as ``Raw ``.
588+
589+ One might sometimes see multiple submessages in a single broadcast, such as
590+ Handoff and Nearby. This is not mandatory -- there are also Handoff-only and
591+ Nearby-only broadcasts.
592+
593+ Inspecting a raw BTLE advertisement frame from an Apple device:
594+
595+ .. code-block :: python3
596+
597+ p = BTLE(hex_bytes('d6be898e4024320cfb574d5a02011a1aff4c000c0e009c6b8f40440f1583ec895148b410050318c0b525b8f7d4'))
598+ p.show()
599+
600+ Results in the output:
601+
602+ .. code-block :: text
603+
604+ ###[ BT4LE ]###
605+ access_addr= 0x8e89bed6
606+ crc= 0xb8f7d4
607+ ###[ BTLE advertising header ]###
608+ RxAdd= public
609+ TxAdd= random
610+ RFU= 0
611+ PDU_type= ADV_IND
612+ unused= 0
613+ Length= 0x24
614+ ###[ BTLE ADV_IND ]###
615+ AdvA= 5a:4d:57:fb:0c:32
616+ \data\
617+ |###[ EIR Header ]###
618+ | len= 2
619+ | type= flags
620+ |###[ Flags ]###
621+ | flags= general_disc_mode+simul_le_br_edr_ctrl+simul_le_br_edr_host
622+ |###[ EIR Header ]###
623+ | len= 26
624+ | type= mfg_specific_data
625+ |###[ EIR Manufacturer Specific Data ]###
626+ | company_id= 0x4c
627+ |###[ Apple BLE broadcast frame ]###
628+ | \plist\
629+ | |###[ Apple BLE submessage ]###
630+ | | subtype= handoff
631+ | | len= 14
632+ | |###[ Raw ]###
633+ | | load= '\x00\x9ck\x8f@D\x0f\x15\x83\xec\x89QH\xb4'
634+ | |###[ Apple BLE submessage ]###
635+ | | subtype= nearby
636+ | | len= 5
637+ | |###[ Raw ]###
638+ | | load= '\x03\x18\xc0\xb5%'
0 commit comments