WPS: Moved mac_addr and uuid configuration into wps_context
[wpasupplicant] / wpa_supplicant / wps_supplicant.c
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"
21 #include "wpa_supplicant_i.h"
22 #include "wps/wps.h"
23 #include "wps/wps_defs.h"
24 #include "wps_supplicant.h"
25
26
27 int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
28 {
29         if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
30             !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
31                 wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
32                            "try to associate with the received credential");
33                 wpa_supplicant_deauthenticate(wpa_s,
34                                               WLAN_REASON_DEAUTH_LEAVING);
35                 wpa_s->reassociate = 1;
36                 wpa_supplicant_req_scan(wpa_s, 0, 0);
37                 return 1;
38         }
39
40         return 0;
41 }
42
43
44 static int wpa_supplicant_wps_cred(void *ctx,
45                                    const struct wps_credential *cred)
46 {
47         struct wpa_supplicant *wpa_s = ctx;
48         struct wpa_ssid *ssid = wpa_s->current_ssid;
49
50         wpa_msg(wpa_s, MSG_INFO, "WPS: New credential received");
51
52         if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
53                 wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
54                            "on the received credential");
55                 os_free(ssid->eap.identity);
56                 ssid->eap.identity = NULL;
57                 ssid->eap.identity_len = 0;
58                 os_free(ssid->eap.phase1);
59                 ssid->eap.phase1 = NULL;
60                 os_free(ssid->eap.eap_methods);
61                 ssid->eap.eap_methods = NULL;
62         } else {
63                 wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
64                            "received credential");
65                 ssid = wpa_config_add_network(wpa_s->conf);
66                 if (ssid == NULL)
67                         return -1;
68         }
69
70         wpa_config_set_network_defaults(ssid);
71
72         os_free(ssid->ssid);
73         ssid->ssid = os_malloc(cred->ssid_len);
74         if (ssid->ssid) {
75                 os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
76                 ssid->ssid_len = cred->ssid_len;
77         }
78
79         switch (cred->encr_type) {
80         case WPS_ENCR_NONE:
81                 ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
82                 break;
83         case WPS_ENCR_WEP:
84                 ssid->pairwise_cipher = ssid->group_cipher =
85                         WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
86                 if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
87                     cred->key_idx < NUM_WEP_KEYS) {
88                         os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
89                                   cred->key_len);
90                         ssid->wep_key_len[cred->key_idx] = cred->key_len;
91                         ssid->wep_tx_keyidx = cred->key_idx;
92                 }
93                 break;
94         case WPS_ENCR_TKIP:
95                 ssid->pairwise_cipher = WPA_CIPHER_TKIP;
96                 ssid->group_cipher = WPA_CIPHER_TKIP;
97                 break;
98         case WPS_ENCR_AES:
99                 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
100                 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
101                 break;
102         }
103
104         switch (cred->auth_type) {
105         case WPS_AUTH_OPEN:
106                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
107                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
108                 ssid->proto = 0;
109                 break;
110         case WPS_AUTH_SHARED:
111                 ssid->auth_alg = WPA_AUTH_ALG_SHARED;
112                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
113                 ssid->proto = 0;
114                 break;
115         case WPS_AUTH_WPAPSK:
116                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
117                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
118                 ssid->proto = WPA_PROTO_WPA;
119                 break;
120         case WPS_AUTH_WPA:
121                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
122                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
123                 ssid->proto = WPA_PROTO_WPA;
124                 break;
125         case WPS_AUTH_WPA2:
126                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
127                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
128                 ssid->proto = WPA_PROTO_RSN;
129                 break;
130         case WPS_AUTH_WPA2PSK:
131                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
132                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
133                 ssid->proto = WPA_PROTO_RSN;
134                 break;
135         }
136
137         if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
138                 if (cred->key_len == 2 * PMK_LEN) {
139                         if (hexstr2bin((const char *) cred->key, ssid->psk,
140                                        PMK_LEN)) {
141                                 wpa_printf(MSG_ERROR, "WPS: Invalid Network "
142                                            "Key");
143                                 return -1;
144                         }
145                         ssid->psk_set = 1;
146                 } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
147                         os_free(ssid->passphrase);
148                         ssid->passphrase = os_malloc(cred->key_len + 1);
149                         if (ssid->passphrase == NULL)
150                                 return -1;
151                         os_memcpy(ssid->passphrase, cred->key, cred->key_len);
152                         ssid->passphrase[cred->key_len] = '\0';
153                         wpa_config_update_psk(ssid);
154                 } else {
155                         wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
156                                    "length %lu",
157                                    (unsigned long) cred->key_len);
158                         return -1;
159                 }
160         }
161
162 #ifndef CONFIG_NO_CONFIG_WRITE
163         if (wpa_s->conf->update_config &&
164             wpa_config_write(wpa_s->confname, wpa_s->conf)) {
165                 wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
166                 return -1;
167         }
168 #endif /* CONFIG_NO_CONFIG_WRITE */
169
170         return 0;
171 }
172
173
174 void * wpas_wps_get_cred_cb(void)
175 {
176         return wpa_supplicant_wps_cred;
177 }
178
179
180 int wpas_wps_init(struct wpa_supplicant *wpa_s)
181 {
182         struct wps_context *wps;
183
184         wps = os_zalloc(sizeof(*wps));
185         if (wps == NULL)
186                 return -1;
187
188         wps->cred_cb = wpa_supplicant_wps_cred;
189         wps->cb_ctx = wpa_s;
190
191         /* TODO: make the device data configurable */
192         wps->dev.device_name = "dev name";
193         wps->dev.manufacturer = "manuf";
194         wps->dev.model_name = "model name";
195         wps->dev.model_number = "model number";
196         wps->dev.serial_number = "12345";
197         wps->dev.categ = WPS_DEV_COMPUTER;
198         wps->dev.oui = WPS_DEV_OUI_WFA;
199         wps->dev.sub_categ = WPS_DEV_COMPUTER_PC;
200         os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
201         os_memcpy(wps->uuid, wpa_s->conf->uuid, 16);
202
203         wpa_s->wps = wps;
204
205         return 0;
206 }
207
208
209 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
210 {
211         if (wpa_s->wps == NULL)
212                 return;
213
214         os_free(wpa_s->wps->network_key);
215         os_free(wpa_s->wps);
216         wpa_s->wps = NULL;
217 }