I have tested this with a smart phone using android 6.0 and with Raspbian Stretch Lite 2018-11-13, updated with
sudo bash -c 'apt update && apt full-upgrade && reboot'. WiFi Direct uses Wi-Fi Protected Setup (WPS) for authentication that knows mainly two modes: Push Button Control (PBC) and Pin Code. For this example I will only use PBC because it is a bit simpler without fiddling with a pin code.
We want to have a DHCP server running. WiFi Direct is organized in groups and every group has one group owner (GO). Only the group owner is allowed to run a DHCP server because we have to ensure that only one DHCP server is present in the group. The group owner can change and it seems that there are protocol datagrams to negotiate DHCP. I have seen a hint about this at Wi-Fi Direct vs Ad-hoc mode, section 6) Frame exchange sequence:
After that we can exchange data frames in the group, but usually the DHCP protocol will be used first to provide the client with an IP address.
But I haven't found further information how it works so for this setup I will set the RasPi to the group owner. To ensure that a device is always negotiated to a group owner we use the option
p2p_go_intent=[0..15]. 0 means the RasPi becomes a client, 15 means the RasPi becomes a group owner. 7 means a chance of 50 % to become a group owner.
I prefer to use systemd-networkd because it has all in one and is able to manage dynamically changing interfaces. WiFi Direct groups are represented by virtual wifi interfaces with increasing numbers, e.g.
p2p-wlan0-1 and so on. So switch over to systemd-networkd. For detailed information look at (1). Here only in short. Execute these commands:
# Install helper to speed up getting random numbers for encryption
rpi ~$ sudo -Es
rpi ~# apt install rng-tools
# disable classic networking
rpi ~# systemctl mask networking.service dhcpcd.service
rpi ~# mv /etc/network/interfaces /etc/network/interfaces~
rpi ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf
# enable systemd-networkd
rpi ~# systemctl enable systemd-networkd.service systemd-resolved.service
rpi ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
To configure wpa_supplicant create this file with your settings for
device_name=. By specification, the device name should always start with DIRECT-. You can just copy and paste this in one block to your command line beginning with
cat and including EOF (delimiter EOF will not get part of the file):
rpi ~# cat > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf <<EOF
# In order to support 802.11n for the p2p Group Owner
rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
rpi ~# systemctl disable wpa_supplicant.service
rpi ~# systemctl enable firstname.lastname@example.org
To give the group interface a static ip address and enable a DHCP server on it, create this file:
rpi ~# cat > /etc/systemd/network/12-p2p-wlan0.network <<EOF
To manage devices with wpa_cli we have to specify the control interface
wpa_cli -ip2p-dev-wlan0. In wpa_supplicant.conf we have specified where to find the names of the control interfaces:
rpi ~$ ls -1 /var/run/wpa_supplicant/
Then on the RasPi I start finding devices:
rpi ~$ wpa_cli -ip2p-dev-wlan0 p2p_find
Now I go to the WiFi Direct page on my smartphone
System settings -> Networks -> WiFi -> tick bar in upper right corner -> Advanced WiFi -> Wi-Fi Direct
Now I could look with
wpa_cli -ip2p-dev-wlan0 p2p_peers what mac addresses of found devices are available. Then I have to show the details for every mac address with
wpa_cli -ip2p-dev-wlan0 p2p_peer <MAC-ADDR> what name it has to find my smartphone. I do it with this one liner, for example:
rpi ~$ for i in $( wpa_cli -ip2p-dev-wlan0 p2p_peers ); do echo -n "$i "; wpa_cli -ip2p-dev-wlan0 p2p_peer $i | grep device_name=; done
a2:91:69:b2:91:a9 device_name=LG Leon 4G LTE
4e:ef:c0:a7:05:82 device_name=Fire TV stick
32:cd:a7:f2:ee:5c device_name=DIRECT-1KC48x Series
a2:91:69:b2:91:a9 for my
LG Leon 4G LTE. Now I only work with this mac address (p2p_dev_addr) and connect to it:
rpi ~$ wpa_cli -ip2p-dev-wlan0 p2p_connect a2:91:69:b2:91:a9 pbc go_intent=15
Note that we use
pbc (push button control) and
go_intent=15 to make the RasPi the group owner (see above).
On the smartphone tick SEARCH
In the popped up window I just confirm the connection by ticking ACCEPT (push button).
Advanced I find the ip address of the device, e.g. 192.168.4.102:
and just ping it from the RasPi to confirm that the smartphone is connected.
rpi ~$ ping -c3 192.168.4.102
PING 192.168.4.102 (192.168.4.102) 56(84) bytes of data.
64 bytes from 192.168.4.102: icmp_seq=1 ttl=64 time=6.90 ms
64 bytes from 192.168.4.102: icmp_seq=2 ttl=64 time=3.46 ms
64 bytes from 192.168.4.102: icmp_seq=3 ttl=64 time=3.14 ms
--- 192.168.4.102 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 3.149/4.505/6.904/1.701 ms
To finish the connection we need the group identifier. You can find it with:
rpi ~$ ip -br link | grep -Po 'p2p-wlan0-\d+'
And with this we finish the connection with
rpi ~$ wpa_cli -ip2p-dev-wlan0 p2p_group_remove p2p-wlan0-12
Or with a one-liner:
rpi ~$ wpa_cli -ip2p-dev-wlan0 P2p_group_remove $(ip -br link | grep -Po 'p2p-wlan0-\d+')
(1) Howto migrate from networking to systemd-networkd with dynamic failover
(2) Wi-Fi Direct vs Ad-hoc mode
(3) OMAP Wireless Connectivity NLCP WiFi Direct Configuration Scripts
(4) wpa_supplicant and Wi-Fi P2P
(5) wpa_supplicant and Wi-Fi Protected Setup (WPS)