]>
Commit | Line | Data |
---|---|---|
fa201b69 JM |
1 | /* |
2 | * wpa_supplicant / WPS integration | |
3 | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "includes.h" | |
16 | ||
17 | #include "common.h" | |
18 | #include "ieee802_11_defs.h" | |
19 | #include "wpa_common.h" | |
20 | #include "config.h" | |
b01c18a8 | 21 | #include "eap_peer/eap.h" |
fa201b69 JM |
22 | #include "wpa_supplicant_i.h" |
23 | #include "wps/wps.h" | |
24 | #include "wps/wps_defs.h" | |
25 | #include "wps_supplicant.h" | |
26 | ||
27 | ||
28 | int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) | |
29 | { | |
30 | if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid && | |
31 | !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { | |
32 | wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - " | |
33 | "try to associate with the received credential"); | |
34 | wpa_supplicant_deauthenticate(wpa_s, | |
35 | WLAN_REASON_DEAUTH_LEAVING); | |
36 | wpa_s->reassociate = 1; | |
37 | wpa_supplicant_req_scan(wpa_s, 0, 0); | |
38 | return 1; | |
39 | } | |
40 | ||
41 | return 0; | |
42 | } | |
43 | ||
44 | ||
bcbbc7af JM |
45 | static int wpa_supplicant_wps_cred(void *ctx, |
46 | const struct wps_credential *cred) | |
fa201b69 JM |
47 | { |
48 | struct wpa_supplicant *wpa_s = ctx; | |
49 | struct wpa_ssid *ssid = wpa_s->current_ssid; | |
50 | ||
51 | wpa_msg(wpa_s, MSG_INFO, "WPS: New credential received"); | |
52 | ||
53 | if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) { | |
54 | wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based " | |
55 | "on the received credential"); | |
56 | os_free(ssid->eap.identity); | |
57 | ssid->eap.identity = NULL; | |
58 | ssid->eap.identity_len = 0; | |
59 | os_free(ssid->eap.phase1); | |
60 | ssid->eap.phase1 = NULL; | |
61 | os_free(ssid->eap.eap_methods); | |
62 | ssid->eap.eap_methods = NULL; | |
63 | } else { | |
64 | wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the " | |
65 | "received credential"); | |
66 | ssid = wpa_config_add_network(wpa_s->conf); | |
67 | if (ssid == NULL) | |
68 | return -1; | |
69 | } | |
70 | ||
71 | wpa_config_set_network_defaults(ssid); | |
72 | ||
73 | os_free(ssid->ssid); | |
74 | ssid->ssid = os_malloc(cred->ssid_len); | |
75 | if (ssid->ssid) { | |
76 | os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len); | |
77 | ssid->ssid_len = cred->ssid_len; | |
78 | } | |
79 | ||
80 | switch (cred->encr_type) { | |
81 | case WPS_ENCR_NONE: | |
82 | ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE; | |
83 | break; | |
84 | case WPS_ENCR_WEP: | |
85 | ssid->pairwise_cipher = ssid->group_cipher = | |
86 | WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104; | |
87 | if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN && | |
88 | cred->key_idx < NUM_WEP_KEYS) { | |
89 | os_memcpy(ssid->wep_key[cred->key_idx], cred->key, | |
90 | cred->key_len); | |
91 | ssid->wep_key_len[cred->key_idx] = cred->key_len; | |
92 | ssid->wep_tx_keyidx = cred->key_idx; | |
93 | } | |
94 | break; | |
95 | case WPS_ENCR_TKIP: | |
96 | ssid->pairwise_cipher = WPA_CIPHER_TKIP; | |
97 | ssid->group_cipher = WPA_CIPHER_TKIP; | |
98 | break; | |
99 | case WPS_ENCR_AES: | |
100 | ssid->pairwise_cipher = WPA_CIPHER_CCMP; | |
101 | ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP; | |
102 | break; | |
103 | } | |
104 | ||
105 | switch (cred->auth_type) { | |
106 | case WPS_AUTH_OPEN: | |
107 | ssid->auth_alg = WPA_AUTH_ALG_OPEN; | |
108 | ssid->key_mgmt = WPA_KEY_MGMT_NONE; | |
109 | ssid->proto = 0; | |
110 | break; | |
111 | case WPS_AUTH_SHARED: | |
112 | ssid->auth_alg = WPA_AUTH_ALG_SHARED; | |
113 | ssid->key_mgmt = WPA_KEY_MGMT_NONE; | |
114 | ssid->proto = 0; | |
115 | break; | |
116 | case WPS_AUTH_WPAPSK: | |
117 | ssid->auth_alg = WPA_AUTH_ALG_OPEN; | |
118 | ssid->key_mgmt = WPA_KEY_MGMT_PSK; | |
119 | ssid->proto = WPA_PROTO_WPA; | |
120 | break; | |
121 | case WPS_AUTH_WPA: | |
122 | ssid->auth_alg = WPA_AUTH_ALG_OPEN; | |
123 | ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
124 | ssid->proto = WPA_PROTO_WPA; | |
125 | break; | |
126 | case WPS_AUTH_WPA2: | |
127 | ssid->auth_alg = WPA_AUTH_ALG_OPEN; | |
128 | ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X; | |
129 | ssid->proto = WPA_PROTO_RSN; | |
130 | break; | |
131 | case WPS_AUTH_WPA2PSK: | |
132 | ssid->auth_alg = WPA_AUTH_ALG_OPEN; | |
133 | ssid->key_mgmt = WPA_KEY_MGMT_PSK; | |
134 | ssid->proto = WPA_PROTO_RSN; | |
135 | break; | |
136 | } | |
137 | ||
138 | if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) { | |
139 | if (cred->key_len == 2 * PMK_LEN) { | |
140 | if (hexstr2bin((const char *) cred->key, ssid->psk, | |
141 | PMK_LEN)) { | |
142 | wpa_printf(MSG_ERROR, "WPS: Invalid Network " | |
143 | "Key"); | |
144 | return -1; | |
145 | } | |
146 | ssid->psk_set = 1; | |
147 | } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) { | |
148 | os_free(ssid->passphrase); | |
149 | ssid->passphrase = os_malloc(cred->key_len + 1); | |
150 | if (ssid->passphrase == NULL) | |
151 | return -1; | |
152 | os_memcpy(ssid->passphrase, cred->key, cred->key_len); | |
153 | ssid->passphrase[cred->key_len] = '\0'; | |
154 | wpa_config_update_psk(ssid); | |
155 | } else { | |
156 | wpa_printf(MSG_ERROR, "WPS: Invalid Network Key " | |
157 | "length %lu", | |
158 | (unsigned long) cred->key_len); | |
159 | return -1; | |
160 | } | |
161 | } | |
162 | ||
163 | #ifndef CONFIG_NO_CONFIG_WRITE | |
164 | if (wpa_s->conf->update_config && | |
165 | wpa_config_write(wpa_s->confname, wpa_s->conf)) { | |
166 | wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration"); | |
167 | return -1; | |
168 | } | |
169 | #endif /* CONFIG_NO_CONFIG_WRITE */ | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | ||
b01c18a8 | 175 | u8 wpas_wps_get_req_type(struct wpa_ssid *ssid) |
fa201b69 | 176 | { |
b01c18a8 JM |
177 | if (eap_is_wps_pbc_enrollee(&ssid->eap) || |
178 | eap_is_wps_pin_enrollee(&ssid->eap)) | |
179 | return WPS_REQ_ENROLLEE; | |
180 | else | |
181 | return WPS_REQ_REGISTRAR; | |
fa201b69 | 182 | } |
116654ce JM |
183 | |
184 | ||
185 | int wpas_wps_init(struct wpa_supplicant *wpa_s) | |
186 | { | |
187 | struct wps_context *wps; | |
188 | ||
189 | wps = os_zalloc(sizeof(*wps)); | |
190 | if (wps == NULL) | |
191 | return -1; | |
192 | ||
193 | wps->cred_cb = wpa_supplicant_wps_cred; | |
194 | wps->cb_ctx = wpa_s; | |
195 | ||
196 | /* TODO: make the device data configurable */ | |
197 | wps->dev.device_name = "dev name"; | |
198 | wps->dev.manufacturer = "manuf"; | |
199 | wps->dev.model_name = "model name"; | |
200 | wps->dev.model_number = "model number"; | |
201 | wps->dev.serial_number = "12345"; | |
202 | wps->dev.categ = WPS_DEV_COMPUTER; | |
203 | wps->dev.oui = WPS_DEV_OUI_WFA; | |
204 | wps->dev.sub_categ = WPS_DEV_COMPUTER_PC; | |
120bd30c JM |
205 | wps->dev.os_version = 0; |
206 | wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; | |
398cfbf6 JM |
207 | os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN); |
208 | os_memcpy(wps->uuid, wpa_s->conf->uuid, 16); | |
116654ce JM |
209 | |
210 | wpa_s->wps = wps; | |
211 | ||
212 | return 0; | |
213 | } | |
214 | ||
215 | ||
216 | void wpas_wps_deinit(struct wpa_supplicant *wpa_s) | |
217 | { | |
218 | if (wpa_s->wps == NULL) | |
219 | return; | |
220 | ||
221 | os_free(wpa_s->wps->network_key); | |
222 | os_free(wpa_s->wps); | |
223 | wpa_s->wps = NULL; | |
224 | } |