Wpa_supplicant
Introduction
shengjhih@gmail.com
2016/03/20
Outline
● Wha is Wpa_supplicant
● Usage
● Initialization Flow
● cfg80211 and libnl
● Layer 2 Packet Sniffing
● Event Loop
What is Wpa_supplicant
● From Wiki page: wpa_supplicant
● wpa_supplicant is widely used in Linux distributions and Android!
● These slides are based on 2.6-devel
wpa_supplicant is a free software implementation of an IEEE 802.11i supplicant for Linux,
FreeBSD, NetBSD, QNX, AROS, Microsoft Windows, Solaris, OS/2 (including eComStation) and
Haiku. In addition to being a fully featured WPA2 supplicant, it also implements WPA and older
wireless LAN security protocols. Features include:
● WPA and full IEEE 802.11i/RSN/WPA2
● WPA-PSK and WPA2-PSK ("WPA-Personal", pre-shared key)
● WPA with EAP ("WPA-Enterprise", for example with RADIUS authentication server)
● key management for CCMP, TKIP, WEP (both 104/128- and 40/64-bit)
● RSN: PMKSA caching, pre-authentication
● IEEE 802.11r
● IEEE 802.11w
● Wi-Fi Protected Setup (WPS)
Usage
● wpa_supplicant
○ -D: driver type, cfg80211 or wext
○ -B: run as a daemon
○ -b: the bridge interface
○ -c: configure file path
○ -C: control interface
○ -d: decrease debug level (show more log)
○ -e: entropy file
○ -f: debug log file
○ -g: global control interface (ctrl_interface)
○ -G: the ctrl_interface will set to be owned by the specified group
○ -h: show usage
○ -i: interface
○ -I: another configuration file
○ -K: show key in debug log
Usage
● wpa_supplicant
○ -L: show license
○ -m: p2p device configuration file
○ -o: override driver option
○ -O: override control interface option
○ -p: driver parameter
○ -P: PID file
○ -q: increase debug level (show less log)
○ -s: use syslog
○ -T: use Linux Tracing
○ -t: add timestamp in debug log
○ -u: dbus control interface
○ -v: show wpa_supplicant version
○ -W: defer the main event loop until first external program attaches wpa_supplicant
○ -N: combine multiple interface parameters
cfg80211
wpa_supplicant, hostapd, iw,
...
nl80211
libnl, libnl-genl
mac80211
User Space
Kernel Space
wireless driver
wireless device
Physical HW
Architechture
Initialization Flow
1. wpa_supplicant_init()
2. Add each interface via wpa_supplicant_add_iface()
3. Run event loop via wpa_supplicant_run()
Init Step 1: wpa_supplicant_init()
1. Init debug log setting
a. If specified to dump log to file via -f parameter, then initialize the output file via
wpa_debug_open_file(). Otherwise, initialize the standard output for debug log via
wpa_debug_setup_stdout()
b. If specified to dump log to syslog via -s parameter, then initialize syslog setting via
wpa_debug_open_syslog()
c. If specified to dump log by Linux Tracing via -T parameter, then initialize the setting via
wpa_debug_open_linux_tracing()
2. Initialize EAP methods via eap_register_methods()
3. Initialize global ctrl_interface via wpa_supplicant_global_ctrl_iface_init()
a. Open socket for the ctrl_interface
b. Set the group permission if the group is specified by -G parameters
c. Register ctrl_interface reader socket via eloop_register_read_sock()
Init Step 1: wpa_supplicant_init()
4. Initialize dbus via wpas_notify_supplicant_initialized()
5. Check global driver list wpa_drivers
6. Register a period timeout (10s) function wpas_periodic to:
a. P2P: check whether P2P peers expired via p2p_expire_peers()
b. STA: flush expired bss via wpa_bss_flush_by_age()
c. AP: check whether the acl is expired via ap_periodic()
Init Step 2: wpa_supplicant_add_iface()
1. Allocate wpa_supplicant structure fo each interface
2. If the override driver option is set by -o parameter, override the driver
specified by -D parameter
3. If the override ctrl_interface option is set by -O parameter, override the
ctrl_interface specified by -C parameter
4. wpa_supplicant_init_iface()
a. Read configuration file via wpa_config_read if the file is specified by -c parameter; if not
specified, make default configrations
b. Read another configuration file vi wpa_config_read if the file is specified by -I parameter
c. If ctrl_interface and driver_param are specified by configuration file and comman line
parameter, use the one specified by command line
Init Step 2: wpa_supplicant_add_iface()
5. wpas_init_driver()
a. Set the driver (e.g. cfg80211 driver)
b. Initialize driver via wpa_drv_init()
c. Setup driver parameter via wpa_drv_set_param() if specified by -p parameter
d. Add the interface into the wpa_s->radio_list via radio_add_interface()
6. Initialize wpa context via wpa_supplicant_init_wpa()
7. Initialize hw feature to wpa_s->hw.modes via
wpa_drv_get_hw_feature_data()
8. Get and setup driver capability via wpa_drv_get_capa()
9. etup bridge or trigger scan via wpa_supplicant_driver_init()
10. If the interface is not P2P device, initialize TDLS via wpa_tdls_init()
11. Set country via wpa_drv_set_country()
Init Step 2: wpa_supplicant_add_iface()
12. Initialize WPS via wpas_wps_init()
13. Initialize EAPOL via wpa_supplicant_init_eapol()
14. Initialize the ctrl_iface of the interface via wpa_supplicant_ctrl_iface_init()
15. Initialize GAS query via gas_query_init()
16. Initialize P2P via wpas_p2p_init(), if the interface support P2P devic
operations
17. Set WOW settings via wpas_set_wowlan_triggers()
18. If support P2P device, try to add P2P device interface via
wpas_p2p_add_p2pdev_interface()
Init Step 3: wpa_supplicant_run()
1. If -B parameter is assigned, run wpa_supplicant as daemon via
wpa_supplicant_daemon
2. If -W parameter is assigned, start the event loop after external program
starting to attach wpa_supplicant via wpa_supplicant_ctrl_iface_wait()
3. Register terminal signal SIGINT and SIGTERM handler via
eloop_register_signal_terminate
4. Register SIGHUP as reconfig signal via eloop_register_signal_reconfig()
5. Start event loop via eloop_run()
cfg80211 and libnl
What is cfg80211 and libnl
● cfg80211 is a configuration system in Linux kernel for manipulating
802.11 devices
● libnl is the bridge for user space and kernel space to interact with each
other during manipulating 802.11 devices
● nl80211 in kernel registers the generic netlink(nl) family “nl80211”
● wpa_supplicant in userspace calls libnl APIs to communicate with kernel
generic nl family “nl80211”
Wpa_supplicant to kernel cf80211 via linbl
1. Initialize netlink connection via netlink_init()
2. Initialize the connection to kernel nl80211 via
wpa_driver_nl80211_init_nl_global()
a. Allocate nl handler via global->nl = nl_create_handle(global->nl_cb, "nl");
b. Resolve nl80211 via global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
c. Allocate event handler via global->nl_event = nl_create_handle(global->nl_cb, "event");
d. Add global->nl_event to “mlme”, “scan”, “regulatory”, “vendor” groups via:
i. ret = nl_get_multicast_id(global, "nl80211", "mlme");
ii. ret = nl_socket_add_membership(global->nl_event, ret);
e. Assign the global event handler via:
i. nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event,
global);
f. Assign “mlme”, “scan”, “regulatory”, “vendor” event handler via:
i. nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive,
Layer 2 Packet Sniffing
Why Need to Access Layer 2 Packets
● To maintain the state machine of specified functions (e.g. TDLS),
wpa_supplicant needs to access layer 2(l2) packets
○ e.g. TDLS, many action frames are encapulated in layer 2 packets
Take TDLS as Example
1. wpa_supplicant calls l2_packet_init() to initialize the connection to l2 and
monitor the specified l2 packets
a. Assign the rx_callback (wpa_supplicant_rx_tdls())function for specified protocol
b. Assign the rx handle function l2_packet_receive() which will invoke the rx_callback
int wpa_tdls_init(struct wpa_sm *sm)
{
if (sm == NULL)
return -1;
sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname :
sm->ifname,
sm->own_addr,
ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls,
sm, 0);
if (sm->l2_tdls == NULL) {
wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet "
"connection");
return -1;
}
...
Event Loop
eloop_init()
● Initialize eloop.timeout list
● Initialize eloop.reader, eloop.writer, eloop.exception
eloop_run()
● eloop keeps running is eloop.terminate is not set or any count of eloop.
reader, eloop.writer, eloop.exception is not zero
● During the while loop
○ Get first timout event in eloop.timeout list and calculate the remianing time to reach the
timeout
○ Call select() to wait for coming reader, writer, exception events
○ Call eloop_process_pending_signals() to process pending signal by calling their handlers
○ Get first timout event in eloop.timeout list, if the timeout fired, call the handler to process
the timeout event
○ If reader, writer, exception socekts are changed, skip previous select() results
○ Call eloop_sock_table_dispatch() to handle all the set reader, writer, exceptions events
Reader, Writer, Exceptions Event Sources
● Reader event source
○ ctrl_iface connection
○ netlink connection between wpa_supplicant and nl80211
○ EAPOL Tx status in wpa_driver_nl80211_drv_init()
○ EAPOL socket in i802_init()
○ Socket for Monitor mode
○ …
● Writer event source
○ Dbus watch
○ http client
● Exception event source
○ Dbus watch
Reference
● https://en.wikipedia.org/wiki/Wpa_supplicant
● https://w1.fi/wpa_supplicant/
● https://w1.fi/wpa_supplicant/devel/
● https://wireless.wiki.kernel.org/
● http://git.kernel.org/cgit/linux/kernel/git/jberg/iw.git
● https://www.infradead.org/~tgr/libnl/

Wpa supplicant introduction

  • 1.
  • 2.
    Outline ● Wha isWpa_supplicant ● Usage ● Initialization Flow ● cfg80211 and libnl ● Layer 2 Packet Sniffing ● Event Loop
  • 3.
    What is Wpa_supplicant ●From Wiki page: wpa_supplicant ● wpa_supplicant is widely used in Linux distributions and Android! ● These slides are based on 2.6-devel wpa_supplicant is a free software implementation of an IEEE 802.11i supplicant for Linux, FreeBSD, NetBSD, QNX, AROS, Microsoft Windows, Solaris, OS/2 (including eComStation) and Haiku. In addition to being a fully featured WPA2 supplicant, it also implements WPA and older wireless LAN security protocols. Features include: ● WPA and full IEEE 802.11i/RSN/WPA2 ● WPA-PSK and WPA2-PSK ("WPA-Personal", pre-shared key) ● WPA with EAP ("WPA-Enterprise", for example with RADIUS authentication server) ● key management for CCMP, TKIP, WEP (both 104/128- and 40/64-bit) ● RSN: PMKSA caching, pre-authentication ● IEEE 802.11r ● IEEE 802.11w ● Wi-Fi Protected Setup (WPS)
  • 4.
    Usage ● wpa_supplicant ○ -D:driver type, cfg80211 or wext ○ -B: run as a daemon ○ -b: the bridge interface ○ -c: configure file path ○ -C: control interface ○ -d: decrease debug level (show more log) ○ -e: entropy file ○ -f: debug log file ○ -g: global control interface (ctrl_interface) ○ -G: the ctrl_interface will set to be owned by the specified group ○ -h: show usage ○ -i: interface ○ -I: another configuration file ○ -K: show key in debug log
  • 5.
    Usage ● wpa_supplicant ○ -L:show license ○ -m: p2p device configuration file ○ -o: override driver option ○ -O: override control interface option ○ -p: driver parameter ○ -P: PID file ○ -q: increase debug level (show less log) ○ -s: use syslog ○ -T: use Linux Tracing ○ -t: add timestamp in debug log ○ -u: dbus control interface ○ -v: show wpa_supplicant version ○ -W: defer the main event loop until first external program attaches wpa_supplicant ○ -N: combine multiple interface parameters
  • 6.
    cfg80211 wpa_supplicant, hostapd, iw, ... nl80211 libnl,libnl-genl mac80211 User Space Kernel Space wireless driver wireless device Physical HW Architechture
  • 7.
    Initialization Flow 1. wpa_supplicant_init() 2.Add each interface via wpa_supplicant_add_iface() 3. Run event loop via wpa_supplicant_run()
  • 8.
    Init Step 1:wpa_supplicant_init() 1. Init debug log setting a. If specified to dump log to file via -f parameter, then initialize the output file via wpa_debug_open_file(). Otherwise, initialize the standard output for debug log via wpa_debug_setup_stdout() b. If specified to dump log to syslog via -s parameter, then initialize syslog setting via wpa_debug_open_syslog() c. If specified to dump log by Linux Tracing via -T parameter, then initialize the setting via wpa_debug_open_linux_tracing() 2. Initialize EAP methods via eap_register_methods() 3. Initialize global ctrl_interface via wpa_supplicant_global_ctrl_iface_init() a. Open socket for the ctrl_interface b. Set the group permission if the group is specified by -G parameters c. Register ctrl_interface reader socket via eloop_register_read_sock()
  • 9.
    Init Step 1:wpa_supplicant_init() 4. Initialize dbus via wpas_notify_supplicant_initialized() 5. Check global driver list wpa_drivers 6. Register a period timeout (10s) function wpas_periodic to: a. P2P: check whether P2P peers expired via p2p_expire_peers() b. STA: flush expired bss via wpa_bss_flush_by_age() c. AP: check whether the acl is expired via ap_periodic()
  • 10.
    Init Step 2:wpa_supplicant_add_iface() 1. Allocate wpa_supplicant structure fo each interface 2. If the override driver option is set by -o parameter, override the driver specified by -D parameter 3. If the override ctrl_interface option is set by -O parameter, override the ctrl_interface specified by -C parameter 4. wpa_supplicant_init_iface() a. Read configuration file via wpa_config_read if the file is specified by -c parameter; if not specified, make default configrations b. Read another configuration file vi wpa_config_read if the file is specified by -I parameter c. If ctrl_interface and driver_param are specified by configuration file and comman line parameter, use the one specified by command line
  • 11.
    Init Step 2:wpa_supplicant_add_iface() 5. wpas_init_driver() a. Set the driver (e.g. cfg80211 driver) b. Initialize driver via wpa_drv_init() c. Setup driver parameter via wpa_drv_set_param() if specified by -p parameter d. Add the interface into the wpa_s->radio_list via radio_add_interface() 6. Initialize wpa context via wpa_supplicant_init_wpa() 7. Initialize hw feature to wpa_s->hw.modes via wpa_drv_get_hw_feature_data() 8. Get and setup driver capability via wpa_drv_get_capa() 9. etup bridge or trigger scan via wpa_supplicant_driver_init() 10. If the interface is not P2P device, initialize TDLS via wpa_tdls_init() 11. Set country via wpa_drv_set_country()
  • 12.
    Init Step 2:wpa_supplicant_add_iface() 12. Initialize WPS via wpas_wps_init() 13. Initialize EAPOL via wpa_supplicant_init_eapol() 14. Initialize the ctrl_iface of the interface via wpa_supplicant_ctrl_iface_init() 15. Initialize GAS query via gas_query_init() 16. Initialize P2P via wpas_p2p_init(), if the interface support P2P devic operations 17. Set WOW settings via wpas_set_wowlan_triggers() 18. If support P2P device, try to add P2P device interface via wpas_p2p_add_p2pdev_interface()
  • 13.
    Init Step 3:wpa_supplicant_run() 1. If -B parameter is assigned, run wpa_supplicant as daemon via wpa_supplicant_daemon 2. If -W parameter is assigned, start the event loop after external program starting to attach wpa_supplicant via wpa_supplicant_ctrl_iface_wait() 3. Register terminal signal SIGINT and SIGTERM handler via eloop_register_signal_terminate 4. Register SIGHUP as reconfig signal via eloop_register_signal_reconfig() 5. Start event loop via eloop_run()
  • 14.
  • 15.
    What is cfg80211and libnl ● cfg80211 is a configuration system in Linux kernel for manipulating 802.11 devices ● libnl is the bridge for user space and kernel space to interact with each other during manipulating 802.11 devices ● nl80211 in kernel registers the generic netlink(nl) family “nl80211” ● wpa_supplicant in userspace calls libnl APIs to communicate with kernel generic nl family “nl80211”
  • 16.
    Wpa_supplicant to kernelcf80211 via linbl 1. Initialize netlink connection via netlink_init() 2. Initialize the connection to kernel nl80211 via wpa_driver_nl80211_init_nl_global() a. Allocate nl handler via global->nl = nl_create_handle(global->nl_cb, "nl"); b. Resolve nl80211 via global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211"); c. Allocate event handler via global->nl_event = nl_create_handle(global->nl_cb, "event"); d. Add global->nl_event to “mlme”, “scan”, “regulatory”, “vendor” groups via: i. ret = nl_get_multicast_id(global, "nl80211", "mlme"); ii. ret = nl_socket_add_membership(global->nl_event, ret); e. Assign the global event handler via: i. nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global); f. Assign “mlme”, “scan”, “regulatory”, “vendor” event handler via: i. nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive,
  • 17.
  • 18.
    Why Need toAccess Layer 2 Packets ● To maintain the state machine of specified functions (e.g. TDLS), wpa_supplicant needs to access layer 2(l2) packets ○ e.g. TDLS, many action frames are encapulated in layer 2 packets
  • 19.
    Take TDLS asExample 1. wpa_supplicant calls l2_packet_init() to initialize the connection to l2 and monitor the specified l2 packets a. Assign the rx_callback (wpa_supplicant_rx_tdls())function for specified protocol b. Assign the rx handle function l2_packet_receive() which will invoke the rx_callback int wpa_tdls_init(struct wpa_sm *sm) { if (sm == NULL) return -1; sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : sm->ifname, sm->own_addr, ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, sm, 0); if (sm->l2_tdls == NULL) { wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " "connection"); return -1; } ...
  • 20.
  • 21.
    eloop_init() ● Initialize eloop.timeoutlist ● Initialize eloop.reader, eloop.writer, eloop.exception
  • 22.
    eloop_run() ● eloop keepsrunning is eloop.terminate is not set or any count of eloop. reader, eloop.writer, eloop.exception is not zero ● During the while loop ○ Get first timout event in eloop.timeout list and calculate the remianing time to reach the timeout ○ Call select() to wait for coming reader, writer, exception events ○ Call eloop_process_pending_signals() to process pending signal by calling their handlers ○ Get first timout event in eloop.timeout list, if the timeout fired, call the handler to process the timeout event ○ If reader, writer, exception socekts are changed, skip previous select() results ○ Call eloop_sock_table_dispatch() to handle all the set reader, writer, exceptions events
  • 23.
    Reader, Writer, ExceptionsEvent Sources ● Reader event source ○ ctrl_iface connection ○ netlink connection between wpa_supplicant and nl80211 ○ EAPOL Tx status in wpa_driver_nl80211_drv_init() ○ EAPOL socket in i802_init() ○ Socket for Monitor mode ○ … ● Writer event source ○ Dbus watch ○ http client ● Exception event source ○ Dbus watch
  • 24.
    Reference ● https://en.wikipedia.org/wiki/Wpa_supplicant ● https://w1.fi/wpa_supplicant/ ●https://w1.fi/wpa_supplicant/devel/ ● https://wireless.wiki.kernel.org/ ● http://git.kernel.org/cgit/linux/kernel/git/jberg/iw.git ● https://www.infradead.org/~tgr/libnl/