wpa_supplicant AP: Add EAPOL frame TX and RX
[wpasupplicant] / src / wps / wps_ufd.c
1 /*
2  * UFD routines for Wi-Fi Protected Setup
3  * Copyright (c) 2009, Masashi Honma <honma@ictec.co.jp>
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 #include "common.h"
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/wait.h>
20 #include <fcntl.h>
21 #include <dirent.h>
22
23 #include "wps/wps.h"
24
25 #ifdef CONFIG_NATIVE_WINDOWS
26 #define UFD_DIR1 "%s\\SMRTNTKY"
27 #define UFD_DIR2 UFD_DIR1 "\\WFAWSC"
28 #define UFD_FILE UFD_DIR2 "\\%s"
29 #else /* CONFIG_NATIVE_WINDOWS */
30 #define UFD_DIR1 "%s/SMRTNTKY"
31 #define UFD_DIR2 UFD_DIR1 "/WFAWSC"
32 #define UFD_FILE UFD_DIR2 "/%s"
33 #endif /* CONFIG_NATIVE_WINDOWS */
34
35
36 struct wps_ufd_data {
37         int ufd_fd;
38 };
39
40
41 static int dev_pwd_e_file_filter(const struct dirent *entry)
42 {
43         unsigned int prefix;
44         char ext[5];
45
46         if (sscanf(entry->d_name, "%8x.%4s", &prefix, ext) != 2)
47                 return 0;
48         if (prefix == 0)
49                 return 0;
50         if (os_strcasecmp(ext, "WFA") != 0)
51                 return 0;
52
53         return 1;
54 }
55
56
57 static int wps_get_dev_pwd_e_file_name(char *path, char *file_name)
58 {
59         struct dirent **namelist;
60         int i, file_num;
61
62         file_num = scandir(path, &namelist, &dev_pwd_e_file_filter,
63                            alphasort);
64         if (file_num < 0) {
65                 wpa_printf(MSG_ERROR, "WPS: OOB file not found: %d (%s)",
66                            errno, strerror(errno));
67                 return -1;
68         }
69         if (file_num == 0) {
70                 wpa_printf(MSG_ERROR, "WPS: OOB file not found");
71                 os_free(namelist);
72                 return -1;
73         }
74         os_strlcpy(file_name, namelist[0]->d_name, 13);
75         for (i = 0; i < file_num; i++)
76                 os_free(namelist[i]);
77         os_free(namelist);
78         return 0;
79 }
80
81
82 static int get_file_name(struct wps_context *wps, int registrar,
83                          const char *path, char *file_name)
84 {
85         switch (wps->oob_conf.oob_method) {
86         case OOB_METHOD_CRED:
87                 os_snprintf(file_name, 13, "00000000.WSC");
88                 break;
89         case OOB_METHOD_DEV_PWD_E:
90                 if (registrar) {
91                         char temp[128];
92                         os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
93                         if (wps_get_dev_pwd_e_file_name(temp, file_name) < 0)
94                                 return -1;
95                 } else {
96                         u8 *mac_addr = wps->dev.mac_addr;
97
98                         os_snprintf(file_name, 13, "%02X%02X%02X%02X.WFA",
99                                     mac_addr[2], mac_addr[3], mac_addr[4],
100                                     mac_addr[5]);
101                 }
102                 break;
103         case OOB_METHOD_DEV_PWD_R:
104                 os_snprintf(file_name, 13, "00000000.WFA");
105                 break;
106         default:
107                 wpa_printf(MSG_ERROR, "WPS: Invalid USBA OOB method");
108                 return -1;
109         }
110         return 0;
111 }
112
113
114 static int ufd_mkdir(const char *path)
115 {
116         if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST) {
117                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to create directory "
118                            "'%s': %d (%s)", path, errno, strerror(errno));
119                 return -1;
120         }
121         return 0;
122 }
123
124
125 static void * init_ufd(struct wps_context *wps,
126                        struct oob_device_data *oob_dev, int registrar)
127 {
128         int write_f;
129         char temp[128];
130         char *path = oob_dev->device_path;
131         char filename[13];
132         struct wps_ufd_data *data;
133         int ufd_fd;
134
135         if (path == NULL)
136                 return NULL;
137
138         write_f = wps->oob_conf.oob_method == OOB_METHOD_DEV_PWD_E ?
139                 !registrar : registrar;
140
141         if (get_file_name(wps, registrar, path, filename) < 0) {
142                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file name");
143                 return NULL;
144         }
145
146         if (write_f) {
147                 os_snprintf(temp, sizeof(temp), UFD_DIR1, path);
148                 if (ufd_mkdir(temp))
149                         return NULL;
150                 os_snprintf(temp, sizeof(temp), UFD_DIR2, path);
151                 if (ufd_mkdir(temp))
152                         return NULL;
153         }
154
155         os_snprintf(temp, sizeof(temp), UFD_FILE, path, filename);
156         if (write_f)
157                 ufd_fd = open(temp, O_WRONLY | O_CREAT | O_TRUNC,
158                               S_IRUSR | S_IWUSR);
159         else
160                 ufd_fd = open(temp, O_RDONLY);
161         if (ufd_fd < 0) {
162                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to open %s: %s",
163                            temp, strerror(errno));
164                 return NULL;
165         }
166
167         data = os_zalloc(sizeof(*data));
168         if (data == NULL)
169                 return NULL;
170         data->ufd_fd = ufd_fd;
171         return data;
172 }
173
174
175 static struct wpabuf * read_ufd(void *priv)
176 {
177         struct wps_ufd_data *data = priv;
178         struct wpabuf *buf;
179         struct stat s;
180         size_t file_size;
181
182         if (fstat(data->ufd_fd, &s) < 0) {
183                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to get file size");
184                 return NULL;
185         }
186
187         file_size = s.st_size;
188         buf = wpabuf_alloc(file_size);
189         if (buf == NULL) {
190                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to alloc read "
191                            "buffer");
192                 return NULL;
193         }
194
195         if (read(data->ufd_fd, wpabuf_mhead(buf), file_size) !=
196             (int) file_size) {
197                 wpabuf_free(buf);
198                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to read");
199                 return NULL;
200         }
201         wpabuf_put(buf, file_size);
202         return buf;
203 }
204
205
206 static int write_ufd(void *priv, struct wpabuf *buf)
207 {
208         struct wps_ufd_data *data = priv;
209
210         if (write(data->ufd_fd, wpabuf_mhead(buf), wpabuf_len(buf)) !=
211             (int) wpabuf_len(buf)) {
212                 wpa_printf(MSG_ERROR, "WPS (UFD): Failed to write");
213                 return -1;
214         }
215         return 0;
216 }
217
218
219 static void deinit_ufd(void *priv)
220 {
221         struct wps_ufd_data *data = priv;
222         close(data->ufd_fd);
223         os_free(data);
224 }
225
226
227 struct oob_device_data oob_ufd_device_data = {
228         .device_name    = NULL,
229         .device_path    = NULL,
230         .init_func      = init_ufd,
231         .read_func      = read_ufd,
232         .write_func     = write_ufd,
233         .deinit_func    = deinit_ufd,
234 };