| Supported Targets | ESP32 | ESP32-C5 | ESP32-C61 | ESP32-S2 | ESP32-S31 |
| ----------------- | ----- | -------- | --------- | -------- | --------- |
# Wi-Fi Aware UDP Server Example
Publisher (Advertiser) side of the [`wifi_aware`](../../) UDP demo. This example advertises a
Wi-Fi Aware service and runs a UDP server that echoes back each message received.
## Introduction
Wi-Fi Aware (also referred to as NAN - Neighbor Awareness Networking) is a protocol that allows Wi-Fi devices to discover services in their proximity. NAN uses direct device-to-device communication and does not require any Internet or AP connection.
Multiple NAN devices which are in the vicinity will form a cluster which allows them to communicate with each other. Devices within the cluster can advertise or look for services and establish a peer-to-peer datapath with or without security.
In this example, Wi-Fi Aware Service Discovery and Datapath establishment are implemented in `example_wifi_aware.c`, while `udp_server.c` creates the UDP socket and operates over the TCP/IP stack. When Pairing is selected as the security mode, `pair_button.c` implements push button triggers to restart and erase previous pairing credentials.
## How to use the example
### With another ESP Device
This example can be paired with another ESP device running [`udp_client`](../udp_client/). The simplest way is to run the following command for both this and the [`udp_client`](../udp_client/) example.
```bash
idf.py set-target esp32c5 build flash monitor
```
The `wifi_aware` component uses service names in compliance with [RFC 6763](https://www.rfc-editor.org/rfc/rfc6763). Option `Service Type` - which defaults to `ESP-Demo` - is used to identify a service, while `Service Instance Name` identifies a device running the service.
ESP-IDF v6.1 introduces Wi-Fi Aware Pairing and Datapath security protocols as experimental features. Enable `Make experimental features visible` first, then navigate to `Component config -> Wi-Fi` and enable the following features:
1. `Enable Wi-Fi Aware: Encrypted Pairwise Datapath (NDP Security)` for:
- WPA2-PSK level passphrase based security
- that uses `NAN Datapath Passphrase` from `Example Configuration`
2. In addition enable `Enable NAN Pairing` for:
- WPA3-PSK level security using PIN Code based pairing
- that uses `Static Pairing PIN (6 digits)` from `Example Configuration`
- and retains credentials if `Persist NAN Pairing Credentials to NVS` is enabled
### With iOS
From ESP-IDF v6.1, this example can establish a secured datapath with iPhone 12 and newer running iOS 26 (and iPad 10th generation and newer running iPadOS 26).
Apple's [Accessory Design Guidelines](https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf) require certain settings for compatibility. The most important is Wi-Fi Aware Pairing with a 6-digit PIN. Choose a static or dynamic PIN under `Example Configuration -> NAN Pairing PIN Mode`.
To meet those requirements, we recommend the `ios` preset:
```bash
idf.py --preset ios set-target esp32c5 build flash monitor
```
For Wi-Fi Aware Pairing, configuring a PIN is a one-time activity (also called bootstrapping). An ESP device can be paired with only one peer at a time. If `Persist NAN Pairing Credentials to NVS` is enabled, that pairing survives a reset.
To pair with a new device, the previous credentials must be erased. On ESP-DevKitC boards, the BOOT button does this: after pairing, long-press BOOT for 5 seconds to erase the stored credentials. Repeat this if you need to pair with the same device again.
The iOS app implementation is out of scope for this document.
### With Android
Android platforms that support Wi-Fi Aware support both open and passphrase-based security. Passphrase-based security is available from ESP-IDF v6.1.
Android uses a different service-discovery encoding than the defaults. To stay compatible, we recommend the `android` preset on ESP-IDF v6.1:
```bash
idf.py --preset android set-target esp32c5 build flash monitor
```
An open datapath on older ESP-IDF versions is still possible. Select `CONFIG_WIFI_AWARE_COMPATIBILITY_ANDROID` under `Wi-Fi Aware Configuration` in the project configuration for better results.
## API Flow between `udp_server` and `udp_client`
```mermaid
sequenceDiagram
autonumber
participant App as app_main (udp_server)
participant WA as example_wifi_aware
participant Peer as Subscriber (udp_client)
participant UDP as udp_server_task
App->>App: nvs_flash_init / esp_netif_init / event_loop
App->>App: register IP_EVENT_GOT_IP6 handler
App->>App: esp_wifi_init()
App->>WA: example_wifi_aware_start(erase=false)
WA->>WA: wifi_aware_init(trigger=WA_TRIGGER_NONE)
WA->>WA: register WA_EVENT_DATAPATH_CONNECTED / _DISCONNECTED / PEER_LOST
WA->>WA: register WA_EVENT_BOOTSTRAP_INDICATION / _PAIRING_CONFIRMED
WA->>WA: wifi_aware_advertise(&pub_cfg, &session)
Note over WA,Peer: Service advertised over NAN
alt PIN-pairing security enabled
Peer-->>WA: bootstrap request from subscriber
WA->>WA: WA_EVENT_BOOTSTRAP_INDICATION (peer, method)
WA->>WA: reject unless method == WA_BOOTSTRAP_PINCODE
WA->>WA: init_pairing_pin() — log 6-digit PIN
WA->>Peer: wifi_aware_pairing_bootstrap_response(peer, true)
WA->>WA: wifi_aware_pairing_set_credentials(peer, &cred)
Note over WA,Peer: peer drives the PASN exchange
WA->>WA: WA_EVENT_PAIRING_CONFIRMED (peer, status)
end
Note over WA,Peer: NAN datapath brought up by subscriber (auto-accepted)
WA->>WA: WA_EVENT_DATAPATH_CONNECTED (peer, inbound=true)
WA-->>App: IP_EVENT_GOT_IP6 on NAN netif
App->>UDP: xTaskCreate(udp_server_task)
loop echo loop
Peer->>UDP: recvfrom() — "Message from ESP32"
UDP->>Peer: sendto() — "OK: Message from ESP32"
end
opt subscriber leaves
WA->>WA: WA_EVENT_DATAPATH_DISCONNECTED (peer, reason)
WA->>WA: WA_EVENT_PEER_LOST (peer handle invalidated)
end
```
## Example console output
```
I (478) wifi_init: WiFi IRAM OP enabled
I (478) wifi_init: WiFi RX IRAM OP enabled
I (478) wifi_init: WiFi SLP IRAM OP enabled
I (488) udp_server: Starting Wi-Fi Aware advertisement: ESP UDP Server
I (488) wifi_aware: Initializing Wi-Fi Aware service
I (498) phy_init: phy_version 282,a2b3f88,Apr 22 2026,17:01:12
I (578) wifi:11ax coex: WDEVAX_PTI0(0x040000a0), WDEVAX_PTI1(0x000082c9).
I (578) wifi:mode : NAN (da:85:ac:5b:ec:39)
I (3578) NAN: Join Cluster with Id 50:6f:9a:01:76:3f
I (3578) nan_app: NAN Discovery started.
I (3578) wifi_aware: Wi-Fi Aware service initialized successfully
I (3578) wa_service: Starting Wi-Fi Aware advertisement: ESP UDP Server
I (3588) wifi:(2.4G)set country: cc=IN schan=1 nchan=13 policy=1
I (3598) wifi_aware: Starting advertisement: instance=ESP UDP Server, service=_ESP-Demo._udp, port=3333, timeout=0 s
I (3598) wifi_aware: Created PTR record SSI: service=_ESP-Demo._udp, instance=(none), txt_len=0, len=16
I (3608) nan_app: Started Publishing _ESP-Demo._udp [Service ID - 5]
I (3618) wifi_aware: NAN service published successfully (publish_id: 5, service: _ESP-Demo._udp, port: 3333, pairable: 0)
I (3628) main_task: Returned from app_main()
I (5298) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (5308) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (5888) wifi_aware: Received follow-up from Peer da:85:ac:77:c2:6e [Our ID: 5, Peer ID: 5], SSI len: 4
I (5888) wifi_aware: SRV query received (empty GSP), responding with SRV record (instance=ESP UDP Server, port=3333)
I (5898) wifi_aware: Created SRV record SSI: service_name=_ESP-Demo._udp, port=3333, instance=(none), len=25
I (5888) nan_app: NDP Req from da:85:ac:77:c2:6e [NDP Id: 1], Accept OR Deny using NDP command
I (6388) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (6388) wifi_aware: Sent SRV record via Follow-up to da:85:ac:77:c2:6e
I (6388) wifi_aware: NDP Indication: Peer da:85:ac:77:c2:6e [NDP ID: 1, Service ID: 5]
I (6398) wifi_aware: Accepted NDP from peer da:85:ac:77:c2:6e (NDPE not supported in this ESP-IDF version)
I (6888) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (6888) wifi:(trc)phytype:CBW20-LGI, snr:0, maxRate:0, highestRateIdx:1
W (6888) wifi:(trc)band:2G, phymode:0, highestRateIdx:1, lowestRateIdx:11, dataSchedTableSize:14
I (6898) wifi:(trc)band:2G, rate(LP-1Mbps, rateIdx:11), ampdu(rate:L-MCS0, schedIdx(8, stop:8)), snr:0, ampduState:wait operational
I (6908) wifi:Committed slots 0x3fff0000 for Peer da:85:ac:77:c2:6e on Channel 6
I (6918) nan_app: NDP confirmed with Peer da:85:ac:77:c2:6e [NDP ID - 1, Peer IPv6 - FE80::D885:ACFF:FE77:C26E]
I (6928) wifi_aware: NDP Confirmed: Peer da:85:ac:77:c2:6e [NDP ID: 1]
I (6928) wifi_aware: Datapath established successfully
I (6938) wifi_aware: Derived IPv6 address from peer NDI: FE80::D885:ACFF:FE77:C26E
I (6938) wa_service: Client connected (peer=0x00000101, inbound)
I (7438) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (7928) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (8388) udp_server: Got IPv6 address, starting UDP server
I (8388) wifi_aware: Got IPv6 address on NAN interface (index: 0): fe80:0000:0000:0000:d885:acff:fe5b:ec39
I (8388) udp_server: Socket created
I (8388) udp_server: Socket bound, port 3333
I (8398) udp_server: Waiting for data
I (8548) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (8558) udp_server: Received 19 bytes from FE80::D885:ACFF:FE77:C26E:
I (8558) udp_server: Message from ESP32
I (8558) udp_server: Waiting for data
I (8988) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (8988) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (10538) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (10568) nan_app: Sent Publish to Peer da:85:ac:77:c2:6e [Peer Subscribe id - 5]
I (10608) udp_server: Received 19 bytes from FE80::D885:ACFF:FE77:C26E:
I (10608) udp_server: Message from ESP32
I (10608) udp_server: Waiting for data
```
To create a project from this example, run:
idf.py create-project-from-example "espressif/wifi_aware=0.1.0:udp_server"