| /** |
| \page p2p Wi-Fi Direct - P2P module |
| |
| Wi-Fi Direct functionality is implemented any many levels in the WLAN |
| stack from low-level driver operations to high-level GUI design. This |
| document covers the parts that can be user by %wpa_supplicant. However, |
| it should be noted that alternative designs are also possible, so some |
| of the functionality may reside in other components in the system. |
| |
| The driver (or WLAN firmware/hardware) is expected to handle low-level |
| operations related to P2P Power Management and channel scheduling. In |
| addition, support for virtual network interface and data frame |
| processing is done inside the driver. Configuration for these |
| low-level operations is defined in the driver interface: |
| src/drivers/driver.h. This defines both the commands and events used to |
| interact with the driver. |
| |
| P2P module implements higher layer functionality for management P2P |
| groups. It takes care of Device Discovery, Service Discovery, Group |
| Owner Negotiation, P2P Invitation. In addition, it maintains |
| information about neighboring P2P Devices. This module could be used |
| in designs that do not use %wpa_supplicant and it could also reside |
| inside the driver/firmware component. P2P module API is defined in |
| src/p2p/p2p.h. |
| |
| Provisioning step of Group Formation is implemented using WPS |
| (src/wps/wps.h). |
| |
| %wpa_supplicant includes code in interact with both the P2P module |
| (wpa_supplicant/p2p_supplicant.c) and WPS |
| (wpa_supplicant/wps_supplicant.c). The driver operations are passed |
| through these files, i.e., core P2P or WPS code does not interact |
| directly with the driver interface. |
| |
| |
| \section p2p_arch P2P architecture |
| |
| P2P functionality affects many areas of the system architecture. This |
| section shows couple of examples on the location of main P2P |
| components. In the diagrams below, green arrows are used to show |
| communication paths from the P2P module to upper layer management |
| functionality and all the way to a GUI that user could use to manage |
| P2P connections. Blue arrows show the path taken for lower layer |
| operations. Glue code is used to bind the P2P module API to the rest |
| of the system to provide access both towards upper and lower layer |
| functionality. |
| |
| \subsection p2p_arch_mac80211 P2P architecture with Linux/mac80211/ath9k |
| |
| An architecture where the P2P module resides inside the |
| %wpa_supplicant process is used with Linux mac80211-based drivers, |
| e.g., ath9k. The following diagram shows the main components related |
| to P2P functionality in such an architecture. |
| |
| \image html p2p_arch.png "P2P module within wpa_supplicant" |
| \image latex p2p_arch.eps "P2P module within wpa_supplicant" width=15cm |
| |
| \subsection p2p_arch_umac P2P architecture with UMAC |
| |
| The following diagram shows the main components related to P2P |
| functionality in an architecture where the P2P module resides inside |
| the kernel IEEE 802.11 stack (UMAC in the figure). |
| |
| \image html p2p_arch2.png "P2P module in kernel |
| \image latex p2p_arch2.eps "P2P module in kernel" width=15cm |
| |
| |
| \section p2p_module P2P module |
| |
| P2P module manages discovery and group formation with a single state |
| machine, i.e., only a single operation per device can be in progress |
| at any given time. The following diagram describes the P2P state |
| machine. For clarity, it does not include state transitions on |
| operation timeouts to the IDLE state. The states that are marked with |
| dotted ellipse are listed for clarity to describe the protocol |
| functionality for Device Discovery phase, but are not used in the |
| implementation (the SEARCH state is used to manage the initial Scan |
| and the alternating Listen and Search states within Find). |
| |
| \image html p2p_sm.png "P2P module state machine" |
| \image latex p2p_sm.eps "P2P module state machine" width=15cm |
| |
| \subsection p2p_module_api P2P module API |
| |
| P2P module API is defined in src/p2p/p2p.h. The API consists of |
| functions for requesting operations and for providing event |
| notifications. Similar set of callback functions are configured with |
| struct p2p_config to provide callback functions that P2P module can |
| use to request operations and to provide event notifications. In |
| addition, there are number of generic helper functions that can be |
| used for P2P related operations. |
| |
| These are the main functions for an upper layer management entity to |
| request P2P operations: |
| - p2p_find() |
| - p2p_stop_find() |
| - p2p_listen() |
| - p2p_connect() |
| - p2p_reject() |
| - p2p_prov_disc_req() |
| - p2p_sd_request() |
| - p2p_sd_cancel_request() |
| - p2p_sd_response() |
| - p2p_sd_service_update() |
| - p2p_invite() |
| |
| These are the main callback functions for P2P module to provide event |
| notifications to the upper layer management entity: |
| |
| - p2p_config::dev_found() |
| - p2p_config::go_neg_req_rx() |
| - p2p_config::go_neg_completed() |
| - p2p_config::sd_request() |
| - p2p_config::sd_response() |
| - p2p_config::prov_disc_req() |
| - p2p_config::prov_disc_resp() |
| - p2p_config::invitation_process() |
| - p2p_config::invitation_received() |
| - p2p_config::invitation_result() |
| |
| The P2P module uses following functions to request lower layer driver |
| operations: |
| |
| - p2p_config::p2p_scan() |
| - p2p_config::send_probe_resp() |
| - p2p_config::send_action() |
| - p2p_config::send_action_done() |
| - p2p_config::start_listen() |
| - p2p_config::stop_listen() |
| |
| Events from lower layer driver operations are delivered to the P2P |
| module with following functions: |
| |
| - p2p_probe_req_rx() |
| - p2p_rx_action() |
| - p2p_scan_res_handler() |
| - p2p_scan_res_handled() |
| - p2p_send_action_cb() |
| - p2p_listen_cb() |
| |
| In addition to the per-device state, the P2P module maintains |
| per-group state for group owners. This is initialized with a call to |
| p2p_group_init() when a group is created and deinitialized with |
| p2p_group_deinit(). The upper layer GO management entity uses |
| following functions to interact with the P2P per-group state: |
| |
| - p2p_group_notif_assoc() |
| - p2p_group_notif_disassoc() |
| - p2p_group_notif_formation_done() |
| - p2p_group_match_dev_type() |
| |
| The P2P module will use following callback function to update P2P IE |
| for GO Beacon and Probe Response frames: |
| |
| - p2p_group_config::ie_update() |
| |
| |
| \section p2p_driver P2P driver operations (low-level interface) |
| |
| The following driver wrapper functions are needed for P2P in addition |
| to the standard station/AP mode operations when the P2P module resides |
| within %wpa_supplicant: |
| - wpa_driver_ops::if_add() |
| - wpa_driver_ops::if_remove() |
| - wpa_driver_ops::alloc_interface_addr() |
| - wpa_driver_ops::release_interface_addr() |
| - wpa_driver_ops::remain_on_channel() |
| - wpa_driver_ops::cancel_remain_on_channel() |
| - wpa_driver_ops::send_action() |
| - wpa_driver_ops::probe_req_report() |
| - wpa_driver_ops::disable_11b_rates() |
| |
| The following driver wrapper events are needed for P2P in addition to |
| the standard station/AP mode events when the P2P module resides within |
| %wpa_supplicant: |
| - wpa_event_type::EVENT_RX_ACTION |
| - wpa_event_type::EVENT_REMAIN_ON_CHANNEL |
| - wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL |
| - wpa_event_type::EVENT_RX_PROBE_REQ |
| |
| The following driver wrapper functions are needed for P2P in addition |
| to the standard station/AP mode operations when the P2P module resides |
| in the driver or firmware: |
| - wpa_driver_ops::if_add() |
| - wpa_driver_ops::if_remove() |
| - wpa_driver_ops::alloc_interface_addr() |
| - wpa_driver_ops::release_interface_addr() |
| - wpa_driver_ops::disable_11b_rates() |
| - wpa_driver_ops::p2p_find() |
| - wpa_driver_ops::p2p_stop_find() |
| - wpa_driver_ops::p2p_listen() |
| - wpa_driver_ops::p2p_connect() |
| - wpa_driver_ops::p2p_reject() |
| - wpa_driver_ops::wps_success_cb() |
| - wpa_driver_ops::p2p_group_formation_failed() |
| - wpa_driver_ops::p2p_set_params() |
| |
| The following driver wrapper events are needed for P2P in addition to |
| the standard station/AP mode events when the P2P module resides in the |
| driver or firmware: |
| - wpa_event_type::EVENT_P2P_DEV_FOUND |
| - wpa_event_type::EVENT_P2P_GO_NEG_REQ_RX |
| - wpa_event_type::EVENT_P2P_GO_NEG_COMPLETED |
| |
| |
| \section p2p_go_neg P2P device discovery and group formation |
| |
| This section shows an example sequence of operations that can be used |
| to implement P2P device discovery and group formation. The function |
| calls are described based on the P2P module API. The exact design for |
| the glue code outside the P2P module depends on the architecture used |
| in the system. |
| |
| An upper layer management entity starts P2P device discovery by |
| calling p2p_find(). The P2P module start the discovery by requesting a |
| full scan to be completed by calling p2p_config::p2p_scan(). Results |
| from the scan will be reported by calling p2p_scan_res_handler() and |
| after last result, the scan result processing is terminated with a |
| call to p2p_scan_res_handled(). The P2P peers that are found during |
| the full scan are reported with the p2p_config::dev_found() callback. |
| |
| After the full scan, P2P module start alternating between Listen and |
| Search states until the device discovery operation times out or |
| terminated, e.g., with a call to p2p_stop_find(). |
| |
| When going into the Listen state, the P2P module requests the driver |
| to be configured to be awake on the listen channel with a call to |
| p2p_config::start_listen(). The glue code using the P2P module may |
| implement this, e.g., by using remain-on-channel low-level driver |
| functionality for off-channel operation. Once the driver is available |
| on the requested channel, notification of this is delivered by calling |
| p2p_listen_cb(). The Probe Request frames that are received during the |
| Listen period are delivered to the P2P module by calling |
| p2p_config::p2p_probe_req_rx() and P2P module request a response to |
| these to be sent by using p2p_config::send_probe_resp() callback |
| function. If a group owner negotiation from another P2P device is |
| received during the device discovery phase, that is indicated to the |
| upper layer code with the p2p_config::go_neg_req_tx() callback. |
| |
| The Search state is implemented by using the normal scan interface, |
| i.e., the P2P module will call p2p_config::p2p_scan() just like in the |
| full scan phase described. Similarly, scan results from the search |
| operation will be delivered to the P2P module using the |
| p2p_scan_res_handler() and p2p_scan_res_handled() functions. |
| |
| Once the upper layer management entity has found a peer with which it |
| wants to connect by forming a new group, it initiates group owner |
| negotiation by calling p2p_connect(). Before doing this, the upper |
| layer code is responsible for asking the user to provide the PIN to be |
| used during the provisioning step with the peer or the push button |
| press for PBC mode. The glue code will need to figure out the intended |
| interface address for the group before group owner negotiation can be |
| started. |
| |
| Optional Provision Discovery mechanism can be used to request the peer |
| to display a PIN for the local device to enter (and vice versa). Upper |
| layer management entity can request the specific mechanism by calling |
| p2p_prov_disc_req(). The response to this will be reported with the |
| p2p_config::prov_disc_resp() callback. If the peer device started |
| Provision Discovery, an accepted request will be reported with the |
| p2p_config::prov_disc_req() callback. The P2P module will |
| automatically accept the Provision Discovery for display and keypad |
| methods, but it is up to the upper layer manegement entity to actually |
| generate the PIN and to configure it with following p2p_connect() call |
| to actually authorize the connection. |
| |
| The P2P module will use p2p_config::send_action() callback to request |
| lower layer code to transmit an Action frame during group owner |
| negotiation. p2p_send_action_cb() is used to report the result of |
| transmission. If the peer is not reachable, the P2P module will try to |
| find it by alternating between Action frame send and Listen |
| states. The Listen state for this phase will be used similarly to the |
| Listen state during device discovery as described above. |
| |
| Once the group owner negotiation has been completed, its results will |
| be reported with the p2p_config::go_neg_completed() callback. The |
| upper layer management code or the glue code using the P2P module API |
| is responsible for creating a new group interface and starting |
| provisioning step at this point by configuring WPS Registrar or |
| Enrollee functionality based on the reported group owner negotiation |
| results. The upper layer code is also responsible for timing out WPS |
| provisioning if it cannot be completed in 15 seconds. |
| |
| Successful completion of the WPS provisioning is reported with a call |
| to p2p_wps_success_cb(). The P2P module will clear its group formation |
| state at this point and allows new group formation attempts to be |
| started. The upper layer management code is responsible for configuring |
| the GO to accept associations from devices and the client to connect to |
| the GO with the provisioned credentials. GO is also responsible for |
| calling p2p_group_notif_formation_done() as described below. |
| |
| If the WPS provisioning step fails or times out, this is reported with |
| a call to p2p_group_formation_failed(). The P2P module will clear its |
| group formation state at this point and allows new group formation |
| attempts to be started. The upper layer management code is responsible |
| for removing the group interface for the failed group. |
| |
| |
| \section p2p_sd P2P service discovery |
| |
| P2P protocol includes service discovery functionality that can be used |
| to discover which services are provided by the peers before forming a |
| group. This leverages the Generic Advertisement Service (GAS) protocol |
| from IEEE 802.11u and P2P vendor-specific contents inside the Native |
| GAS messages. |
| |
| The P2P module takes care of GAS encapsulation, fragmentation, and |
| actual transmission and reception of the Action frames needed for |
| service discovery. The user of the P2P module is responsible for |
| providing P2P specific Service Request TLV(s) for queries and Service |
| Response TLV(s) for responses. |
| |
| \subsection p2p_sd_query Quering services of peers |
| |
| Service discovery is implemented by processing pending queries as a |
| part of the device discovery phase. p2p_sd_request() function is used |
| to schedule service discovery queries to a specific peer or to all |
| discovered peers. p2p_sd_cancel_request() can be used to cancel a |
| scheduled query. Queries that are specific to a single peer will be |
| removed automatically after the response has been received. |
| |
| After the service discovery queries have been queued, device discovery |
| is started with a call to p2p_find(). The pending service discovery |
| queries are then sent whenever a peer is discovered during the find |
| operation. Responses to the queries will be reported with the |
| p2p_config::sd_response() callback. |
| |
| \subsection p2p_sd_response Replying to service discovery queries from peers |
| |
| The received service discovery requests will be indicated with the |
| p2p_config::sd_request() callback. The response to the query is sent |
| by calling p2p_sd_response(). |
| |
| \subsection p2p_sd_indicator Service update indicator |
| |
| P2P service discovery provides a mechanism to notify peers about |
| changes in available services. This works by incrementing Service |
| Update Indicator value whenever there is a change in the |
| services. This value is included in all SD request and response |
| frames. The value received from the peers will be included in the |
| p2p_config::sd_request() and p2p_config::sd_response() callbacks. The |
| value to be sent to the peers is incremented with a call to |
| p2p_sd_service_update() whenever availibility of the local services |
| changes. |
| |
| |
| \section p2p_go P2P group owner |
| |
| This section describes how P2P module can be used for managing |
| per-group information in a group owner. The function calls are |
| described based on the P2P module API. The exact design for the glue |
| code outside the P2P module depends on the architecture used in the |
| system. |
| |
| When a P2P group interface is created in group owner role, per-group |
| data is initialized with p2p_group_init(). This call provides a |
| pointer to the per-device P2P module context and configures the |
| per-group operation. The configured p2p_group_config::ie_update() |
| callback is used to set the initial P2P IE for Beacon and Probe |
| Response frames in the group owner. The AP mode implementation may use |
| this information to add IEs into the frames. |
| |
| Once the group formation has been completed (or if it is skipped in |
| case of manual group setup), p2p_group_notif_formation_done() is |
| called. This will allow the P2P module to update the P2P IE for |
| Beacon and Probe Response frames. |
| |
| The SME/MLME code that managements IEEE 802.11 association processing |
| needs to inform P2P module whenever a P2P client associates or |
| disassociates with the group. This is done by calling |
| p2p_group_notif_assoc() and p2p_group_notif_disassoc(). The P2P module |
| manages a list of group members and updates the P2P Group Information |
| subelement in the P2P IE based on the information from the P2P |
| clients. The p2p_group_config::ie_update() callback is used whenever |
| the P2P IE in Probe Response frames needs to be changed. |
| |
| The SME/MLME code that takes care of replying to Probe Request frames |
| can use p2p_group_match_dev_type() to check whether the Probe Request |
| frame request a reply only from groups that include a specific device |
| type in one of the clients or GO. A match will be reported if the |
| Probe Request does not request a specific device type, so this |
| function can be used to filter or received Probe Request frames and |
| only the ones that result in non-zero return value need to be replied. |
| |
| When the P2P group interface for GO role is removed, |
| p2p_group_deinit() is used to deinitialize the per-group P2P module |
| state. |
| |
| |
| \section p2p_ctrl_iface P2P control interface |
| |
| %wpa_supplicant \ref ctrl_iface_page "control interface" can be used |
| to manage P2P functionality from an external program (e.g., a GUI or a |
| system configuration manager). This interface can be used directly |
| through the control interface backend mechanism (e.g., local domain |
| sockets on Linux) or with help of wpa_cli (e.g., from a script). |
| |
| The following P2P-related commands are available: |
| - \ref ctrl_iface_P2P_FIND P2P_FIND |
| - \ref ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND |
| - \ref ctrl_iface_P2P_CONNECT P2P_CONNECT |
| - \ref ctrl_iface_P2P_LISTEN P2P_LISTEN |
| - \ref ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE |
| - \ref ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD |
| - \ref ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC |
| - \ref ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ |
| - \ref ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ |
| - \ref ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP |
| - \ref ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE |
| - \ref ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL |
| - \ref ctrl_iface_P2P_REJECT P2P_REJECT |
| - \ref ctrl_iface_P2P_INVITE P2P_INVITE |
| |
| The following P2P-related events are used: |
| - \ref ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND |
| - \ref ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST |
| - \ref ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS |
| - \ref ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE |
| - \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS |
| - \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE |
| - \ref ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED |
| - \ref ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED |
| - \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN |
| - \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN |
| - \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ |
| - \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP |
| - \ref ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED |
| - \ref ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT |
| |
| |
| \subsection p2p_wpa_gui GUI example (wpa_gui) |
| |
| wpa_gui has an example implementation of a GUI that could be used to |
| manage P2P operations. The P2P related functionality is contained |
| mostly in wpa_supplicant/wpa_gui-qt4/peers.cpp and it shows how the |
| control interface commands and events can be used. |
| |
| |
| \subsection p2p_wpa_cli wpa_cli example |
| |
| wpa_cli can be used to control %wpa_supplicant in interactive |
| mode. The following sessions show examples of commands used for |
| device discovery and group formation. The lines starting with "> " are |
| commands from the user (followed by command result indication) and |
| lines starting with "<2>" are event messages from %wpa_supplicant. |
| |
| P2P device "Wireless Client": |
| |
| \verbatim |
| > p2p_find |
| OK |
| > <2>P2P-DEVICE-FOUND 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7 |
| pri_dev_type=1-0050F204-1 name='Wireless Client 2' config_methods=0x18c |
| dev_capab=0x1 group_capab=0x0 |
| <2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7 |
| <2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7 |
| > p2p_connect 02:40:61:c2:f3:b7 pbc |
| OK |
| <2>P2P-GO-NEG-SUCCESS |
| <2>P2P-GROUP-FORMATION-SUCCESS |
| <2>P2P-GROUP-STARTED sta0-p2p-0 client DIRECT-vM |
| > interface |
| Available interfaces: |
| sta0-p2p-0 |
| sta0 |
| > p2p_group_remove sta0-p2p-0 |
| <2>P2P-GROUP-REMOVED sta0-p2p-0 client |
| OK |
| > term |
| OK |
| \endverbatim |
| |
| |
| P2P device "Wireless Client2" (which ended up operating in GO role): |
| |
| \verbatim |
| > p2p_find |
| OK |
| <2>P2P-DEVICE-FOUND 02:f0:bc:44:87:62 p2p_dev_addr=02:f0:bc:44:87:62 |
| pri_dev_type=1-0050F204-1 name='Wireless Client' config_methods=0x18c |
| dev_capab=0x1 group_capab=0x0 |
| > p2p_connect 02:f0:bc:44:87:62 pbc |
| OK |
| <2>P2P-GO-NEG-SUCCESS |
| <2>P2P-GROUP-FORMATION-SUCCESS |
| <2>P2P-GROUP-STARTED sta1-p2p-0 GO DIRECT-vM |
| > interface |
| Available interfaces: |
| sta1-p2p-0 |
| sta1 |
| > p2p_group_remove sta1-p2p-0 |
| <2>P2P-GROUP-REMOVED sta1-p2p-0 GO |
| OK |
| > term |
| OK |
| \endverbatim |
| |
| */ |