Adventures in Wi-Fi Direct (P2P): Part 1

Sep 12, 2022

9 mins read

This blog is far overdue and unfortunately isn’t really a “Part 1”. The truth is, I’ve poked around with Wi-Fi Direct for several months now with mild success and many dead-ends that resulted in learning a lot. The purpose of this blog is to retrace my steps and document some resources before diving into some fun stuff for Part 2.

Let’s start with the basics:

Wi-Fi Direct (formerly Wi-Fi Peer-to-Peer) is a Wi-Fi standard for peer-to-peer wireless connections that allows two devices to establish a direct Wi-Fi connection without an intermediary wireless access point, router, or Internet connection. Wi-Fi Direct is single-hop communication, rather than multihop communication like wireless ad hoc networks.

This technology has been around for more than a decade. In fact, the first documented Wi-Fi Direct certified device was a Realtek RTL8192CE 2T2R 802.11bgn miniCard which released on October 25th, 2010. At the time of writing this blog, that’s 12 years ago.

I’m a technologist, why haven’t I ever seen this?

Honestly, I thought the same thing originally, but now I see it everywhere I look. It turns out that because of some design decisions it’s actually really hard to spot unless you know how to look.

First Contact

I first interacted with Wi-Fi Direct in a meeting room that had a projector mounted high on the ceiling with no available cable connection. It turns out this device used Windows Wireless Projection.

windows projection

Windows used Wi-Fi Direct to create a Peer-To-Peer (P2P) connection and initialize a Miracast stream that allowed it to display the screen on the projector wirelessly. Cool!

Overkill with MS-MICE

Naturally I did some reading and found this thing called MS-MICE. MS-MICE is a Microsoft specific extension on top of Miracast which allows the ability to transmit a multimedia stream over a local wireless network instead of P2P.

I had an older Microsoft Surface Pro 2 which ran full Windows 10, but only had a single USB port making it a hassle to use once the flimsy snap-on keyboard stopped working.

What if I made this an external display?

It turns out, you can do that! Under the settings menu, search for “Projecting to this PC” and install the optional feature of “Wireless Display”. Another computer should now see it as an available wireless display if they are both connected to the same wireless network.

This worked well enough for a time, but with higher resolution sources there was some network congestion issues. After a lot of reading, I found that discovery and negotiation of MS-MICE would also work on a wired network.

I don’t remember exactly where I read this and I’m struggling to find it, but I can promise you that for a period of 9 months I disabled Wi-Fi on the Surface Pro 2 and used it as an external display with MS-MICE and a USB-3 Ethernet adapter every. single. day. It worked great and only completely hung my OS like 3 times in 9 months!

MS-MICE Protocol

When using MS-MICE, I naturally got curious about how it worked and decided to take a peek in Wireshark. As expected, it’s very similar to plain Miracast in that it requests to start a Real Time Streaming Protocol (RTSP) stream.

Apologies for the weird red circles on these images. They’re pulled from a months old chat as the Surface Pro 2 is now dead.

RTSP Request

The wireless display then sends an RTSP response with some additional parameters.

RTSP Response

You may need to zoom a bit, but the circled red part above is showing that the server has wfd_uibc_cabality for various Human Input Devices (HID), such as Mouse and Keyboard.

UIBC Support: User Input Back Channel (UIBC) is an optional feature for sending input commands from the Miracast receiver to the Miracast sender for processing. The user can then interact naturally with the Miracast receiver’s peripherals. For example, Keyboard/Mouse/Touch/Pen inputs attached to a Miracast receiver can act as input to the Miracast Source.

Yes, you read that correctly. If I attach a mouse to my wireless display I can act as input for the casting source. If that seems backwards…you share the same reaction I did. Amazingly, it’s true.

DTLS

Finally, the protocol will typically swap to using a dTLS wrapped UDP connection to stream the Miracast source to the wireless display.

Back2WiFi

As described above, I ended up using an Microsoft specific extension of Miracast which is an Extension of WiFi Direct, but I used it over a wired connection. Let’s get back to the wireless aspects.

The actual Wi-Fi Direct Specification is available to download for free after providing a bit of information. While incredibly dense as reading material goes, it is a fantastic source of information to reference when exploring different implementations found in the real world.

For determining if a wireless device on *nix supports Wi-Fi Direct you can run:

iw list | grep "Supported interface modes" -A 8

which should return something similar to:

Supported interface modes:
         * IBSS
         * managed
         * AP
         * P2P-client
         * P2P-GO
         * P2P-device

Raspberry Pi Devices and most modern chipsets support it. If you’re looking to guarantee support, you can search for certified devices here:

Below is a list of links and resources I’ve discovered over the past few months:

Wi-Fi Direct support in Android is amazing and has a unified API:

Using Wi-Direct on *nix in a controlled environment is fairly easy. This writeup includes clear high-level details and objectives to use wpa_supplicant to establish a Wi-Direct connection.

The Android source code for wpa_supplicant is publicly available. While it’s a lot of dense C, there’s also many examples and example configs in use with hostapd.

The CLI commands for wpa_supplicant are extremely useful for debugging. Getting examples and references straight from the source is always best.

A popular repository for turning Raspberry Pi’s into wireless access points has setup scripts and a guide for configuring a Raspberry Pi Zero W to use Wi-Fi Direct.

hostp2pd is a convienient wrapper for wpa_supplicant that includes descriptive documentation and aims at making a Wi-Fi Direct connection painless.

Real World Observance

If you read any of the above links, you probably saw some mention of DIRECT- SSID’s. Per Section 3.2.1 of Wi-Fi Direct Specification (paraphrased/re-worded):

Each Wi-Fi Direct SSID will begin with "DIRECT-" followed by 2 random characters. This allows SSID’s to be filtered from legacy tech and to clean up the “Connect to WiFi” UI for modern devices.

This probably explains why you’ve never seen Wi-Fi Direct unless you were actively trying to use it. Often times it’s very existence it filtered from view despite being pretty much everywhere.

To prove this point, I wrote some small code for an ESP32 M5Stack which I knew did not have such a filter.

#include <M5Stack.h>

#include "WiFi.h"

String wfd = "DIRECT-";

void appendFile(fs::FS &fs, const char *path, const char *message)
{
    File file = fs.open(path, FILE_APPEND);
    if (!file)
    {
        return;
    }
    if (file.println(message))
    {
        Serial.println("File written");
        M5.Lcd.println("File written");
    }
    else
    {
        Serial.println("Write failed");
        M5.Lcd.println("Write failed");
    }
}

void buttons_test()
{
    if (M5.BtnB.wasReleased() || M5.BtnB.pressedFor(1000, 200))
    {
        M5.Lcd.printf("B");
        Serial.printf("B");
        esp_deep_sleep_start();
    }
}

void setup()
{
    M5.begin();
    M5.Power.begin();
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);
    M5.Lcd.print("WIFI SCAN");
}

void loop()
{
    M5.Lcd.setCursor(0, 0);
    M5.update();
    buttons_test();
    M5.Lcd.clear();
    M5.Lcd.println("scan start");
    int n = WiFi.scanNetworks();
    if (n == 0)
    {
        M5.Lcd.println("no networks found");
    }
    else
    {
        M5.Lcd.printf("networks found:%d\n\n", n);
        for (int i = 0; i < n;
             ++i)
        {
            if (WiFi.SSID(i).startsWith(wfd))
            {
                appendFile(SD, "/wfd_realworld.txt", WiFi.SSID(i).c_str());
            }
            delay(10);
        }
    }
}

This code scans for SSID’s starting with DIRECT- and writes them to a txt file on an SD card. I brought it with me this morning on the 3 minute drive to daycare to drop off my son.

DIRECT-07-HP OfficeJet Pro 8020
DIRECT-0A-HP OfficeJet Pro 8710
DIRECT-16-HP OfficeJet 4650
DIRECT-27-HP OfficeJet Pro 8710
DIRECT-4D-HP OfficeJet Pro 7740
DIRECT-61-HP OfficeJet Pro 8020
DIRECT-74-HP PageWide MFP P57750
DIRECT-78-HP ENVY 4520 series
DIRECT-7c-HP M426 LaserJet
DIRECT-9B-HP OfficeJet Pro 9020
DIRECT-9d-HP M148f LaserJet
DIRECT-a8-HP M118 LaserJet
DIRECT-AC-HP ENVY 7640 series
DIRECT-B1-HP OfficeJet Pro 9010
DIRECT-B3-HP OfficeJet Pro 8020
DIRECT-BMW 25230
DIRECT-BMW 78973
DIRECT-c9-HP M477 LaserJet
DIRECT-C9-HP M479fdw Color LJ
DIRECT-CD-HP OfficeJet Pro 8710
DIRECT-ce-Car_cafc
DIRECT-Cm-Car_774b
DIRECT-cV-Car_d502
DIRECT-D5-HP OfficeJet Pro 6960
DIRECT-D8-HP ENVY 4520 series
DIRECT-DA-HP M428fdw LJ
DIRECT-DC-HP OfficeJet Pro 8710
DIRECT-de83-TS8200series
DIRECT-E1-HP ENVY Photo 7800
DIRECT-EB-HP ENVY 7640 series
DIRECT-Es-Car_e391
DIRECT-F3-HP ENVY Photo 7100
DIRECT-GR-Car_4a46
DIRECT-H1-myGMC
DIRECT-LW-Car_d02e
DIRECT-mn-Car_f5a2
DIRECT-P3-Car_1681
DIRECT-WxEE-TS6400series
DIRECT-xi-Car_e3d9
DIRECT-xmmD

As you can see, in that short drive we saw 40 Wi-Fi direct devices. Many are Printers or… Cars? I didn’t see any smart TV’s, but that may be explained by the fact that it was 8AM in the morning.

While my determination of the device-type is made by the SSID alone, there is P2P Specific WSC IE Attributes included in the Wi-Fi Direct advertisement frames that include an OUI which allow mapping to a table.

OUI

If you’d like a PCAP file to look at in Wireshark to see what an advertisement from a Roku TV looks like, you can download it here:

Fin

I hope this was a sufficient crash course on Wi-Fi Direct and it’s uses in practice. While this blog was primarily written as a trail of breadcrumbs for myself to use later, I hope you found it useful.

Documentation and examples of Wi-Fi Direct outside of the Android ecosystem is severely lacking and I wanted to try to bring a lot of those resources together and explain the topic through a practical viewpoint.

Sharing is caring!