blob: 61f65530eb5cfc81a87f231a146dd235eccef8e1 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
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>
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019#include <fcntl.h>
20#include <dirent.h>
21
22#include "wps/wps.h"
23#include "wps/wps_i.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
36struct wps_ufd_data {
37 int ufd_fd;
38};
39
40
41static 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
57static 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
82static 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
114static 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
125static 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
175static 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
206static 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
219static 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
227struct 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};