下面我们将接上一篇文章继续分析main中第二个关键函数wpa_supplicant_add_iface。

wpa_supplicant_add_iface用于向wpa_supplicant添加接口设备。所谓的添加(add iface),其实就是初始化这些设备。

[wpa_supplicant.c::wpa_supplicant_add_iface]

  1. struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
  2. struct wpa_interface *iface)
  3. {
  4. struct wpa_supplicant *wpa_s;
  5. struct wpa_interface t_iface;
  6. struct wpa_ssid *ssid;
  7. if (global == NULL || iface == NULL)
  8. return NULL;
  9. wpa_s = wpa_supplicant_alloc();
  10. if (wpa_s == NULL)
  11. return NULL;
  12. wpa_s->global = global;
  13. t_iface = *iface;
  14. if (global->params.override_driver) {
  15. wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
  16. "('%s' -> '%s')",
  17. iface->driver, global->params.override_driver);
  18. t_iface.driver = global->params.override_driver;
  19. }
  20. if (global->params.override_ctrl_interface) {
  21. wpa_printf(MSG_DEBUG, "Override interface parameter: "
  22. "ctrl_interface ('%s' -> '%s')",
  23. iface->ctrl_interface,
  24. global->params.override_ctrl_interface);
  25. t_iface.ctrl_interface =
  26. global->params.override_ctrl_interface;
  27. }
  28. if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
  29. wpa_printf(MSG_DEBUG, "Failed to add interface %s",
  30. iface->ifname);
  31. wpa_supplicant_deinit_iface(wpa_s, 0, 0);
  32. return NULL;
  33. }
  34. /* Notify the control interfaces about new iface */
  35. if (wpas_notify_iface_added(wpa_s)) {
  36. wpa_supplicant_deinit_iface(wpa_s, 1, 0);
  37. return NULL;
  38. }
  39. for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
  40. wpas_notify_network_added(wpa_s, ssid);
  41. wpa_s->next = global->ifaces;
  42. global->ifaces = wpa_s;
  43. wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
  44. wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
  45. return wpa_s;
  46. }

wpa_supplicant_add_iface的内容非常丰富,包括两个重要数据结构(wpa_supplicant和wpa_ssid)以及一个关键函数wpa_supplicant_init_iface.

1、wpa_ssid结构体

wpa_ssid用于存储某个无线网络的配置信息(如所支持的安全类型、优先级等)它其实是wpa_supplicant.conf中无线网络配置项在代码中的反映(conf文件中每一个network项都对应一个wpa_ssid对象)。它的一些主要数据成员如下所示:

struct wpa_ssid
+next:struct wpa_ssid*  //所有wpa_ssid对象都保存在一个链表中,头指针保存于另外一个结构体wpa_config的变量中
+pnext:struct wpa_ssid*  //wpa_ssid还可按priority保存在另一个链表中,头指针为wpa_config的pssid变量
+id:int  //每一个无线网络都有一个唯一的编号
+priority:int  //该无线对应的priority值,默认为0
+ssid:8*:此无线网络的ssid(即无线网络名)
+ssid_len:size_t  //ssid变量的长度
+bssid:u8数组  //用于保存bssid,数组长度为ETH_ALEN(值为6)
+bssid_set:  //该无线网络是否设置了bssid变量
+psk:u8数组  //数组长度为32,用于保存WPA中的Pre-Shared Key
+psk_set: int  //是否设置了商数的psk参数
+passphrase:char*  //为WPA设置了ASCII字符密码。
+pairwise_cipher:int  //用于单播数据加密的密钥对类型
+group_cipher: int  //用于组播数据加密的密钥对类型
+key_mgmt:int   //密钥管理类型
+proto:int  //该无线网络支持的安全保护类型
+auth_alg:int  //该无线网络支持的身份验证类型
+scan_ssid:int  //是否利用probe request帧扫描此ssid对应的无线网络
+eapol_flags:int //EAPOL选项
+eap:struct eap_peer_config  //eap peer端设置信息
+proactive_key_caching:int  //
+mode:enum wpas_mode  //
+disabled:int  //
wpa_ssid定义的wpas_mode枚举变量
enum wpas_mode{
WPAS_MODE_INFRA = 0,//代表基础结构网络的STA
WPAS_MODE_IBSS = 1,//代表IBSS网络的模式
WPAS_MODE_AP = 2,代表基础结构网络中的AP
WPAS_MODE_P2P_GO = 3,//P2P相关
WPAS_MODE_GROUP_FORMATION = 4,
}mode;

上表格中一些数据成员非常重要,下面分别介绍:

(1)安全相关成员变量

1)passphrase:该变量只和WPA/WPA2-PSK模式有关,用于存储我们输入的字符串密码。

2)pairwise_cipher和group_cipher:这两个变量和规范中的cipher suite定义有关。

  1. #define WPA_CIPHER_NONE BIT(0)<span style="white-space:pre">      </span>//不保护
  2. #define WPA_CIPHER_WEP40 BIT(1)<span style="white-space:pre">     </span>//WEP40
  3. #define WPA_CIPHER_WEP104 BIT(2)<span style="white-space:pre">    </span>//WEP104
  4. #define WPA_CIPHER_TKIP BIT(3)<span style="white-space:pre">      </span>//TKIP
  5. #define WPA_CIPHER_CCMP BIT(4)<span style="white-space:pre">      </span>//CCMP
  1. #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
  2. #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
  3. WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)

3)key_mgmt:该成员和802.11中的AKM(Authentication and Key Managment,身份验证和密钥管理)suite相关。

  1. #define WPA_KEY_MGMT_IEEE8021X BIT(0)
  2. #define WPA_KEY_MGMT_PSK BIT(1)
  3. #define WPA_KEY_MGMT_NONE BIT(2)
  4. #define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
  5. #define WPA_KEY_MGMT_WPA_NONE BIT(4)
  6. #define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
  7. #define WPA_KEY_MGMT_FT_PSK BIT(6)
  8. #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
  9. #define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
  10. #define WPA_KEY_MGMT_WPS BIT(9)
  11. #define WPA_KEY_MGMT_SAE BIT(10)
  12. #define WPA_KEY_MGMT_FT_SAE BIT(11)
  13. #define WPA_KEY_MGMT_WAPI_PSK BIT(12)
  14. #define WPA_KEY_MGMT_WAPI_CERT BIT(13)
  15. #define WPA_KEY_MGMT_CCKM BIT(14)
  1. #define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)

4)proto:代表该无线网络支持的安全协议类型。

  1. #define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
  1. #define WPA_PROTO_WPA BIT(0)
  2. #define WPA_PROTO_RSN BIT(1)
  3. #define WPA_PROTO_WAPI BIT(2)

5)auth_alg:表示该无线网络所支持的身份验证算法。其可取值如下:

  1. #define WPA_AUTH_ALG_OPEN BIT(0)<span style="white-space:pre">        </span>//open system,如果要使用WPA或RSN,必须选择它
  2. #define WPA_AUTH_ALG_SHARED BIT(1)<span style="white-space:pre">      </span>//Shard Key算法
  3. #define WPA_AUTH_ALG_LEAP BIT(2)<span style="white-space:pre">        </span>//LEAP算法,LEAP是思科公司提出的身份验证算法
  4. #define WPA_AUTH_ALG_FT BIT(3)<span style="white-space:pre">          </span>//和FT有关
  5. #define WPA_AUTH_ALG_SAE BIT(4)

6)eapol_flags:和动态WEP Key有关

  1. #define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
  2. #define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)

(2)其他成员变量

1)proactive_key_caching:该变量和OPC(Opportunistic PMK Caching)技术相关。

2)disable:该变量取值为0(代表该无线网络可用)、1(代表该无线网络被禁止使用,但可通过命令来启用它)、2(表示该无线网络和P2P有关)

3)mode:wpa_ssid结构体内部还定义了一个枚举型变量
2、wpa_supplicant结构体

wpa_supplicant结构体定义的成员变量非常多。详细请参考wpa_supplicant_i.h文件。

wpa_supplicant_init_iface函数分析

  1. static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
  2. struct wpa_interface *iface)
  3. {
  4. const char *ifname, *driver;
  5. struct wpa_driver_capa capa;
  6. wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
  7. "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
  8. iface->confname ? iface->confname : "N/A",
  9. iface->driver ? iface->driver : "default",
  10. iface->ctrl_interface ? iface->ctrl_interface : "N/A",
  11. iface->bridge_ifname ? iface->bridge_ifname : "N/A");
  12. if (iface->confname) {
  13. #ifdef CONFIG_BACKEND_FILE
  14. wpa_s->confname = os_rel2abs_path(iface->confname);
  15. if (wpa_s->confname == NULL) {
  16. wpa_printf(MSG_ERROR, "Failed to get absolute path "
  17. "for configuration file '%s'.",
  18. iface->confname);
  19. return -1;
  20. }
  21. wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
  22. iface->confname, wpa_s->confname);
  23. #else /* CONFIG_BACKEND_FILE */
  24. wpa_s->confname = os_strdup(iface->confname);
  25. #endif /* CONFIG_BACKEND_FILE */
  26. wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
  27. if (wpa_s->conf == NULL) {
  28. wpa_printf(MSG_ERROR, "Failed to read or parse "
  29. "configuration '%s'.", wpa_s->confname);
  30. return -1;
  31. }
  32. wpa_s->confanother = os_rel2abs_path(iface->confanother);
  33. wpa_config_read(wpa_s->confanother, wpa_s->conf);
  34. /*
  35. * Override ctrl_interface and driver_param if set on command
  36. * line.
  37. */
  38. if (iface->ctrl_interface) {
  39. os_free(wpa_s->conf->ctrl_interface);
  40. wpa_s->conf->ctrl_interface =
  41. os_strdup(iface->ctrl_interface);
  42. }
  43. if (iface->driver_param) {
  44. os_free(wpa_s->conf->driver_param);
  45. wpa_s->conf->driver_param =
  46. os_strdup(iface->driver_param);
  47. }
  48. if (iface->p2p_mgmt && !iface->ctrl_interface) {
  49. os_free(wpa_s->conf->ctrl_interface);
  50. wpa_s->conf->ctrl_interface = NULL;
  51. }
  52. } else
  53. wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
  54. iface->driver_param);
  55. if (wpa_s->conf == NULL) {
  56. wpa_printf(MSG_ERROR, "\nNo configuration found.");
  57. return -1;
  58. }
  59. if (iface->ifname == NULL) {
  60. wpa_printf(MSG_ERROR, "\nInterface name is required.");
  61. return -1;
  62. }
  63. if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
  64. wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
  65. iface->ifname);
  66. return -1;
  67. }
  68. os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
  69. if (iface->bridge_ifname) {
  70. if (os_strlen(iface->bridge_ifname) >=
  71. sizeof(wpa_s->bridge_ifname)) {
  72. wpa_printf(MSG_ERROR, "\nToo long bridge interface "
  73. "name '%s'.", iface->bridge_ifname);
  74. return -1;
  75. }
  76. os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
  77. sizeof(wpa_s->bridge_ifname));
  78. }
  79. /* RSNA Supplicant Key Management - INITIALIZE */
  80. eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
  81. eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
  82. /* Initialize driver interface and register driver event handler before
  83. * L2 receive handler so that association events are processed before
  84. * EAPOL-Key packets if both become available for the same select()
  85. * call. */
  86. driver = iface->driver;
  87. next_driver:
  88. if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
  89. return -1;
  90. wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
  91. if (wpa_s->drv_priv == NULL) {
  92. const char *pos;
  93. pos = driver ? os_strchr(driver, ',') : NULL;
  94. if (pos) {
  95. wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
  96. "driver interface - try next driver wrapper");
  97. driver = pos + 1;
  98. goto next_driver;
  99. }
  100. wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
  101. "interface");
  102. return -1;
  103. }
  104. if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
  105. wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
  106. "driver_param '%s'", wpa_s->conf->driver_param);
  107. return -1;
  108. }
  109. ifname = wpa_drv_get_ifname(wpa_s);
  110. if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
  111. wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
  112. "interface name with '%s'", ifname);
  113. os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
  114. }
  115. if (wpa_supplicant_init_wpa(wpa_s) < 0)
  116. return -1;
  117. wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
  118. wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
  119. NULL);
  120. wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
  121. if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
  122. wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
  123. wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
  124. wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
  125. "dot11RSNAConfigPMKLifetime");
  126. return -1;
  127. }
  128. if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
  129. wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
  130. wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
  131. wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
  132. "dot11RSNAConfigPMKReauthThreshold");
  133. return -1;
  134. }
  135. if (wpa_s->conf->dot11RSNAConfigSATimeout &&
  136. wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
  137. wpa_s->conf->dot11RSNAConfigSATimeout)) {
  138. wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
  139. "dot11RSNAConfigSATimeout");
  140. return -1;
  141. }
  142. wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
  143. &wpa_s->hw.num_modes,
  144. &wpa_s->hw.flags);
  145. if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
  146. wpa_s->drv_capa_known = 1;
  147. wpa_s->drv_flags = capa.flags;
  148. wpa_s->drv_enc = capa.enc;
  149. wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
  150. wpa_s->max_scan_ssids = capa.max_scan_ssids;
  151. wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
  152. wpa_s->sched_scan_supported = capa.sched_scan_supported;
  153. wpa_s->max_match_sets = capa.max_match_sets;
  154. wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
  155. wpa_s->max_stations = capa.max_stations;
  156. wpa_s->extended_capa = capa.extended_capa;
  157. wpa_s->extended_capa_mask = capa.extended_capa_mask;
  158. wpa_s->extended_capa_len = capa.extended_capa_len;
  159. wpa_s->num_multichan_concurrent =
  160. capa.num_multichan_concurrent;
  161. }
  162. if (wpa_s->max_remain_on_chan == 0)
  163. wpa_s->max_remain_on_chan = 1000;
  164. /*
  165. * Only take p2p_mgmt parameters when P2P Device is supported.
  166. * Doing it here as it determines whether l2_packet_init() will be done
  167. * during wpa_supplicant_driver_init().
  168. */
  169. if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
  170. wpa_s->p2p_mgmt = iface->p2p_mgmt;
  171. else
  172. iface->p2p_mgmt = 1;
  173. if (wpa_s->num_multichan_concurrent == 0)
  174. wpa_s->num_multichan_concurrent = 1;
  175. if (wpa_supplicant_driver_init(wpa_s) < 0)
  176. return -1;
  177. #ifdef CONFIG_TDLS
  178. if ((!iface->p2p_mgmt ||
  179. !(wpa_s->drv_flags &
  180. WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
  181. wpa_tdls_init(wpa_s->wpa))
  182. return -1;
  183. #endif /* CONFIG_TDLS */
  184. if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
  185. wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
  186. wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
  187. return -1;
  188. }
  189. if (wpas_wps_init(wpa_s))
  190. return -1;
  191. if (wpa_supplicant_init_eapol(wpa_s) < 0)
  192. return -1;
  193. wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
  194. wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
  195. if (wpa_s->ctrl_iface == NULL) {
  196. wpa_printf(MSG_ERROR,
  197. "Failed to initialize control interface '%s'.\n"
  198. "You may have another wpa_supplicant process "
  199. "already running or the file was\n"
  200. "left by an unclean termination of wpa_supplicant "
  201. "in which case you will need\n"
  202. "to manually remove this file before starting "
  203. "wpa_supplicant again.\n",
  204. wpa_s->conf->ctrl_interface);
  205. return -1;
  206. }
  207. wpa_s->gas = gas_query_init(wpa_s);
  208. if (wpa_s->gas == NULL) {
  209. wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
  210. return -1;
  211. }
  212. #ifdef CONFIG_P2P
  213. if (iface->p2p_mgmt && wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
  214. wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
  215. return -1;
  216. }
  217. #endif /* CONFIG_P2P */
  218. if (wpa_bss_init(wpa_s) < 0)
  219. return -1;
  220. #ifdef CONFIG_EAP_PROXY
  221. {
  222. size_t len;
  223. wpa_s->mnc_len = eap_proxy_get_imsi(wpa_s->imsi, &len);
  224. if (wpa_s->mnc_len > 0) {
  225. wpa_s->imsi[len] = '\0';
  226. wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
  227. wpa_s->imsi, wpa_s->mnc_len);
  228. } else {
  229. wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
  230. }
  231. }
  232. #endif /* CONFIG_EAP_PROXY */
  233. if (pcsc_reader_init(wpa_s) < 0)
  234. return -1;
  235. if (wpas_init_ext_pw(wpa_s) < 0)
  236. return -1;
  237. return 0;
  238. }

1、init_iface初始化的第一个工作是解析运行时配置文件。其中,wpa_s->confname的值为“/data/misc/wifi/wpa_supplicant.conf”,解析函数是wpa_config_read。

  1. struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
  2. {
  3. FILE *f;
  4. char buf[512], *pos;
  5. int errors = 0, line = 0;
  6. struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
  7. struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
  8. struct wpa_config *config;
  9. int id = 0;
  10. int cred_id = 0;
  11. if (name == NULL)
  12. return NULL;
  13. if (cfgp)
  14. config = cfgp;
  15. else
  16. config = wpa_config_alloc_empty(NULL, NULL);
  17. if (config == NULL) {
  18. wpa_printf(MSG_ERROR, "Failed to allocate config file "
  19. "structure");
  20. return NULL;
  21. }
  22. head = config->ssid;
  23. cred_head = config->cred;
  24. wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
  25. f = fopen(name, "r");
  26. if (f == NULL) {
  27. wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
  28. "error: %s", name, strerror(errno));
  29. os_free(config);
  30. return NULL;
  31. }
  32. while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
  33. if (os_strcmp(pos, "network={") == 0) {
  34. ssid = wpa_config_read_network(f, &line, id++);
  35. if (ssid == NULL) {
  36. wpa_printf(MSG_ERROR, "Line %d: failed to "
  37. "parse network block.", line);
  38. errors++;
  39. continue;
  40. }
  41. if (head == NULL) {
  42. head = tail = ssid;
  43. } else {
  44. tail->next = ssid;
  45. tail = ssid;
  46. }
  47. if (wpa_config_add_prio_network(config, ssid)) {
  48. wpa_printf(MSG_ERROR, "Line %d: failed to add "
  49. "network block to priority list.",
  50. line);
  51. errors++;
  52. continue;
  53. }
  54. } else if (os_strcmp(pos, "cred={") == 0) {
  55. cred = wpa_config_read_cred(f, &line, cred_id++);
  56. if (cred == NULL) {
  57. wpa_printf(MSG_ERROR, "Line %d: failed to "
  58. "parse cred block.", line);
  59. errors++;
  60. continue;
  61. }
  62. if (cred_head == NULL) {
  63. cred_head = cred_tail = cred;
  64. } else {
  65. cred_tail->next = cred;
  66. cred_tail = cred;
  67. }
  68. #ifndef CONFIG_NO_CONFIG_BLOBS
  69. } else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
  70. if (wpa_config_process_blob(config, f, &line, pos + 12)
  71. < 0) {
  72. wpa_printf(MSG_ERROR, "Line %d: failed to "
  73. "process blob.", line);
  74. errors++;
  75. continue;
  76. }
  77. #endif /* CONFIG_NO_CONFIG_BLOBS */
  78. } else if (wpa_config_process_global(config, pos, line) < 0) {
  79. wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
  80. "line '%s'.", line, pos);
  81. errors++;
  82. continue;
  83. }
  84. }
  85. fclose(f);
  86. config->ssid = head;
  87. wpa_config_debug_dump_networks(config);
  88. config->cred = cred_head;
  89. #ifndef WPA_IGNORE_CONFIG_ERRORS
  90. if (errors) {
  91. wpa_config_free(config);
  92. config = NULL;
  93. head = NULL;
  94. }
  95. #endif /* WPA_IGNORE_CONFIG_ERRORS */
  96. return config;
  97. }

wpa_config和wpa_ssid这两个数据结构都是配置文件中的信息在代码中的实现。
2、wpa_supplicant_set_driver将根据nl80211找到wpa_driver数组中nl80211指定的driver对象wpa_driver_nl80211_ops,然后调用其global_init函数。

global_init是wpa_driver_ops结构体重的一个类型为函数指针的成员变量。

  1. static void * nl80211_global_init(void)
  2. {
  3. struct nl80211_global *global;
  4. struct netlink_config *cfg;
  5. global = os_zalloc(sizeof(*global));
  6. if (global == NULL)
  7. return NULL;
  8. global->ioctl_sock = -1;
  9. dl_list_init(&global->interfaces);
  10. global->if_add_ifindex = -1;
  11. cfg = os_zalloc(sizeof(*cfg));
  12. if (cfg == NULL)
  13. goto err;
  14. cfg->ctx = global;
  15. cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
  16. cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
  17. global->netlink = netlink_init(cfg);
  18. if (global->netlink == NULL) {
  19. os_free(cfg);
  20. goto err;
  21. }
  22. if (wpa_driver_nl80211_init_nl_global(global) < 0)
  23. goto err;
  24. global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
  25. if (global->ioctl_sock < 0) {
  26. perror("socket(PF_INET,SOCK_DGRAM)");
  27. goto err;
  28. }
  29. return global;
  30. err:
  31. nl80211_global_deinit(global);
  32. return NULL;
  33. }
  1. static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
  2. {
  3. int ret;
  4. global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
  5. if (global->nl_cb == NULL) {
  6. wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
  7. "callbacks");
  8. return -1;
  9. }
  10. global->nl = nl_create_handle(global->nl_cb, "nl");
  11. if (global->nl == NULL)
  12. goto err;
  13. global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
  14. if (global->nl80211_id < 0) {
  15. wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
  16. "found");
  17. goto err;
  18. }
  19. global->nl_event = nl_create_handle(global->nl_cb, "event");
  20. if (global->nl_event == NULL)
  21. goto err;
  22. ret = nl_get_multicast_id(global, "nl80211", "scan");
  23. if (ret >= 0)
  24. ret = nl_socket_add_membership(global->nl_event, ret);
  25. if (ret < 0) {
  26. wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
  27. "membership for scan events: %d (%s)",
  28. ret, strerror(-ret));
  29. goto err;
  30. }
  31. ret = nl_get_multicast_id(global, "nl80211", "mlme");
  32. if (ret >= 0)
  33. ret = nl_socket_add_membership(global->nl_event, ret);
  34. if (ret < 0) {
  35. wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
  36. "membership for mlme events: %d (%s)",
  37. ret, strerror(-ret));
  38. goto err;
  39. }
  40. ret = nl_get_multicast_id(global, "nl80211", "regulatory");
  41. if (ret >= 0)
  42. ret = nl_socket_add_membership(global->nl_event, ret);
  43. if (ret < 0) {
  44. wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
  45. "membership for regulatory events: %d (%s)",
  46. ret, strerror(-ret));
  47. /* Continue without regulatory events */
  48. }
  49. nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
  50. no_seq_check, NULL);
  51. nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
  52. process_global_event, global);
  53. eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
  54. wpa_driver_nl80211_event_receive,
  55. global->nl_cb, global->nl_event);
  56. return 0;
  57. err:
  58. nl_destroy_handles(&global->nl_event);
  59. nl_destroy_handles(&global->nl);
  60. nl_cb_put(global->nl_cb);
  61. global->nl_cb = NULL;
  62. return -1;
  63. }

3、wpa_drv_init函数处理单个driver。内部调用init2函数。

    1. static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
    2. void *global_priv)
    3. {
    4. struct wpa_driver_nl80211_data *drv;
    5. struct rfkill_config *rcfg;
    6. struct i802_bss *bss;
    7. if (global_priv == NULL)
    8. return NULL;
    9. drv = os_zalloc(sizeof(*drv));
    10. if (drv == NULL)
    11. return NULL;
    12. drv->global = global_priv;
    13. drv->ctx = ctx;
    14. bss = &drv->first_bss;
    15. bss->drv = drv;
    16. bss->ctx = ctx;
    17. os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
    18. drv->monitor_ifidx = -1;
    19. drv->monitor_sock = -1;
    20. drv->eapol_tx_sock = -1;
    21. drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
    22. if (wpa_driver_nl80211_init_nl(drv)) {
    23. os_free(drv);
    24. return NULL;
    25. }
    26. if (nl80211_init_bss(bss))
    27. goto failed;
    28. rcfg = os_zalloc(sizeof(*rcfg));
    29. if (rcfg == NULL)
    30. goto failed;
    31. rcfg->ctx = drv;
    32. os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
    33. rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
    34. rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
    35. drv->rfkill = rfkill_init(rcfg);
    36. if (drv->rfkill == NULL) {
    37. wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
    38. os_free(rcfg);
    39. }
    40. if (wpa_driver_nl80211_finish_drv_init(drv))
    41. goto failed;
    42. drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
    43. if (drv->eapol_tx_sock < 0)
    44. goto failed;
    45. if (drv->data_tx_status) {
    46. int enabled = 1;
    47. if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
    48. &enabled, sizeof(enabled)) < 0) {
    49. wpa_printf(MSG_DEBUG,
    50. "nl80211: wifi status sockopt failed\n");
    51. drv->data_tx_status = 0;
    52. if (!drv->use_monitor)
    53. drv->capa.flags &=
    54. ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
    55. } else {
    56. eloop_register_read_sock(drv->eapol_tx_sock,
    57. wpa_driver_nl80211_handle_eapol_tx_status,
    58. drv, NULL);
    59. }
    60. }
    61. if (drv->global) {
    62. dl_list_add(&drv->global->interfaces, &drv->list);
    63. drv->in_interface_list = 1;
    64. }
    65. return bss;
    66. failed:
    67. wpa_driver_nl80211_deinit(bss);
    68. return NULL;
    69. }

Android4.4 wpa_supplicant深入分析之wpa_supplicant初始化流程续的更多相关文章

  1. 关于Flutter初始化流程,我必须告诉你的是...

    1. 引言 最近在做性能优化的时候发现,在混合栈开发中,第一次启动Flutter页面的耗时总会是第二次启动Flutter页面耗时的两倍左右,这样给人感觉很不好.分析发现第一次启动Flutter页面会做 ...

  2. Shiro权限管理框架(三):Shiro中权限过滤器的初始化流程和实现原理

    本篇是Shiro系列第三篇,Shiro中的过滤器初始化流程和实现原理.Shiro基于URL的权限控制是通过Filter实现的,本篇从我们注入的ShiroFilterFactoryBean开始入手,翻看 ...

  3. spring自动扫描、DispatcherServlet初始化流程、spring控制器Controller 过程剖析

    spring自动扫描1.自动扫描解析器ComponentScanBeanDefinitionParser,从doScan开始扫描解析指定包路径下的类注解信息并注册到工厂容器中. 2.进入后findCa ...

  4. 【开源】OSharp3.3框架解说系列(7.1):初始化流程概述

    OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...

  5. SpringMVC源码剖析(三)- DispatcherServlet的初始化流程

    在我们第一次学Servlet编程,学Java Web的时候,还没有那么多框架.我们开发一个简单的功能要做的事情很简单,就是继承HttpServlet,根据需要重写一下doGet,doPost方法,跳转 ...

  6. u-boot中nandflash初始化流程分析(转)

    u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...

  7. Z-stack之OSAL初始化流程

    转自点击打开链接 我使用的协议栈版本及例子信息: ZigBee2006\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\Sam ...

  8. Raid1源代码分析--初始化流程

    初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些 ...

  9. main之前初始化流程

    main之前初始化流程 本文分别介绍Keil调用的ARMCC以及ARM-NONE-EABI-GCC两个编译器在main之前的操作: Keil MDK启动文件 总结一下MDK的启动流程: 1.系统初始化 ...

随机推荐

  1. Product Device Lot

    Product是指产品: 这个Product可以在不同的设备类型上生产, 同一类型的设备也可能硬件有差异,所以会有相对应的Device(Recipe): 同一Product(或同一Device)由于数 ...

  2. [Windows Server 2012] 安装SQL Server 2012

    ★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★ 护卫神·V课堂 是护卫神旗下专业提供服务器教学视频的网站,每周更新视频.★ 本节我们将带领大家:安装SQL S ...

  3. day08-字符编码

    目录 计算机基础 启动应用程序 写文本的流程 Python解释器执行文件的原理 Python解释器与文本编辑器的区别 字符编码 字符编码发生在哪三个阶段 字符编码发展史与分类 总结 Python2与P ...

  4. Review:Microbiota, metagenome, microbiome傻傻分不清

    Microbiota 微生物群   微生物群是指研究动植物体上共生或病理的微生物生态群体.微生物群包括细菌.古菌.原生动物.真菌和病毒.研究表明其在宿主的免疫.代谢和激素等方面非常重要.近义词Micr ...

  5. 通过python xlsxwriter模块生成EXCEL柱状图、饼图

    xlsxwriter模块不是python自带的,使用pip下载 import xlsxwriter #新建一个excel文件,起名为expense01.xlsx workbook = xlsxwrit ...

  6. 如何在mac里面,把xcode代码同步到 tfs 的 git库(克隆git篇)

    如果是新的git库,还没有任何内容可以克隆,可以参考:http://www.cnblogs.com/IWings/p/6755795.html 在mac安装visual studio code htt ...

  7. 文件上传原理--FileReader

    单个文件:<div> <input value="上传" type="file" id="photos_upload"&g ...

  8. 构建秘钥对验证的SSH体系

    构建秘钥对验证的SSH 体系 首先先要在ssh 客户端以root用户身份创建秘钥对 客户端将创建的公钥文件上传至ssh服务器 服务器将公钥信息导入用户root的公钥数据库文件 客户端以root用户身份 ...

  9. Free中的buffer和cache理解

    吐血推荐文章: Linux内存中的Cache真的能被回收么? free中的buffer和cache: redhat对free输出的解读 两者都是RAM中的数据.简单来说,buffer是即将要被写入磁盘 ...

  10. (C/C++学习)7.数组及其访问方式

    说明:数组的数据类型是一种构造类型,而存储数组的内存是一段连续的存储区域.数组的数据类型决定了连续内存的访问方式,它包括数组的三要素:起始地址.步长以及元素个数. 一.一维数组 1.形式:type 数 ...