WPS: Move WPS glue code from wpas_glue.c to wps_supplicant.c
[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, struct wps_credential *cred)
45 {
46         struct wpa_supplicant *wpa_s = ctx;
47         struct wpa_ssid *ssid = wpa_s->current_ssid;
48
49         wpa_msg(wpa_s, MSG_INFO, "WPS: New credential received");
50
51         if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
52                 wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
53                            "on the received credential");
54                 os_free(ssid->eap.identity);
55                 ssid->eap.identity = NULL;
56                 ssid->eap.identity_len = 0;
57                 os_free(ssid->eap.phase1);
58                 ssid->eap.phase1 = NULL;
59                 os_free(ssid->eap.eap_methods);
60                 ssid->eap.eap_methods = NULL;
61         } else {
62                 wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
63                            "received credential");
64                 ssid = wpa_config_add_network(wpa_s->conf);
65                 if (ssid == NULL)
66                         return -1;
67         }
68
69         wpa_config_set_network_defaults(ssid);
70
71         os_free(ssid->ssid);
72         ssid->ssid = os_malloc(cred->ssid_len);
73         if (ssid->ssid) {
74                 os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
75                 ssid->ssid_len = cred->ssid_len;
76         }
77
78         switch (cred->encr_type) {
79         case WPS_ENCR_NONE:
80                 ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
81                 break;
82         case WPS_ENCR_WEP:
83                 ssid->pairwise_cipher = ssid->group_cipher =
84                         WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
85                 if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
86                     cred->key_idx < NUM_WEP_KEYS) {
87                         os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
88                                   cred->key_len);
89                         ssid->wep_key_len[cred->key_idx] = cred->key_len;
90                         ssid->wep_tx_keyidx = cred->key_idx;
91                 }
92                 break;
93         case WPS_ENCR_TKIP:
94                 ssid->pairwise_cipher = WPA_CIPHER_TKIP;
95                 ssid->group_cipher = WPA_CIPHER_TKIP;
96                 break;
97         case WPS_ENCR_AES:
98                 ssid->pairwise_cipher = WPA_CIPHER_CCMP;
99                 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
100                 break;
101         }
102
103         switch (cred->auth_type) {
104         case WPS_AUTH_OPEN:
105                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
106                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
107                 ssid->proto = 0;
108                 break;
109         case WPS_AUTH_SHARED:
110                 ssid->auth_alg = WPA_AUTH_ALG_SHARED;
111                 ssid->key_mgmt = WPA_KEY_MGMT_NONE;
112                 ssid->proto = 0;
113                 break;
114         case WPS_AUTH_WPAPSK:
115                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
116                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
117                 ssid->proto = WPA_PROTO_WPA;
118                 break;
119         case WPS_AUTH_WPA:
120                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
121                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
122                 ssid->proto = WPA_PROTO_WPA;
123                 break;
124         case WPS_AUTH_WPA2:
125                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
126                 ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
127                 ssid->proto = WPA_PROTO_RSN;
128                 break;
129         case WPS_AUTH_WPA2PSK:
130                 ssid->auth_alg = WPA_AUTH_ALG_OPEN;
131                 ssid->key_mgmt = WPA_KEY_MGMT_PSK;
132                 ssid->proto = WPA_PROTO_RSN;
133                 break;
134         }
135
136         if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
137                 if (cred->key_len == 2 * PMK_LEN) {
138                         if (hexstr2bin((const char *) cred->key, ssid->psk,
139                                        PMK_LEN)) {
140                                 wpa_printf(MSG_ERROR, "WPS: Invalid Network "
141                                            "Key");
142                                 return -1;
143                         }
144                         ssid->psk_set = 1;
145                 } else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
146                         os_free(ssid->passphrase);
147                         ssid->passphrase = os_malloc(cred->key_len + 1);
148                         if (ssid->passphrase == NULL)
149                                 return -1;
150                         os_memcpy(ssid->passphrase, cred->key, cred->key_len);
151                         ssid->passphrase[cred->key_len] = '\0';
152                         wpa_config_update_psk(ssid);
153                 } else {
154                         wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
155                                    "length %lu",
156                                    (unsigned long) cred->key_len);
157                         return -1;
158                 }
159         }
160
161 #ifndef CONFIG_NO_CONFIG_WRITE
162         if (wpa_s->conf->update_config &&
163             wpa_config_write(wpa_s->confname, wpa_s->conf)) {
164                 wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
165                 return -1;
166         }
167 #endif /* CONFIG_NO_CONFIG_WRITE */
168
169         return 0;
170 }
171
172
173 void * wpas_wps_get_cred_cb(void)
174 {
175         return wpa_supplicant_wps_cred;
176 }