1/*
2 * wpa_gui - AddInterface class
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include <cstdio>
10#include "common/wpa_ctrl.h"
11
12#include <QMessageBox>
13
14#include "wpagui.h"
15#include "addinterface.h"
16
17#ifdef CONFIG_NATIVE_WINDOWS
18#include <windows.h>
19
20#ifndef WPA_KEY_ROOT
21#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
22#endif
23#ifndef WPA_KEY_PREFIX
24#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
25#endif
26#endif /* CONFIG_NATIVE_WINDOWS */
27
28
29AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent)
30	: QDialog(parent), wpagui(_wpagui)
31{
32	setWindowTitle(tr("Select network interface to add"));
33	resize(400, 200);
34	vboxLayout = new QVBoxLayout(this);
35
36	interfaceWidget = new QTreeWidget(this);
37	interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
38	interfaceWidget->setUniformRowHeights(true);
39	interfaceWidget->setSortingEnabled(true);
40	interfaceWidget->setColumnCount(3);
41	interfaceWidget->headerItem()->setText(0, tr("driver"));
42	interfaceWidget->headerItem()->setText(1, tr("interface"));
43	interfaceWidget->headerItem()->setText(2, tr("description"));
44	interfaceWidget->setItemsExpandable(FALSE);
45	interfaceWidget->setRootIsDecorated(FALSE);
46	vboxLayout->addWidget(interfaceWidget);
47
48	connect(interfaceWidget,
49		SIGNAL(itemActivated(QTreeWidgetItem *, int)), this,
50		SLOT(interfaceSelected(QTreeWidgetItem *)));
51
52	addInterfaces();
53}
54
55
56void AddInterface::addInterfaces()
57{
58#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
59	struct wpa_ctrl *ctrl;
60	int ret;
61	char buf[2048];
62	size_t len;
63
64	ctrl = wpa_ctrl_open(NULL);
65	if (ctrl == NULL)
66		return;
67
68	len = sizeof(buf) - 1;
69	ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL);
70	if (ret < 0) {
71		wpa_ctrl_close(ctrl);
72		return;
73	}
74	buf[len] = '\0';
75
76	wpa_ctrl_close(ctrl);
77
78	QString ifaces(buf);
79	QStringList lines = ifaces.split(QRegExp("\\n"));
80	for (QStringList::Iterator it = lines.begin();
81	     it != lines.end(); it++) {
82		QStringList arg = (*it).split(QChar('\t'));
83		if (arg.size() < 3)
84			continue;
85		QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget);
86		if (!item)
87			break;
88
89		item->setText(0, arg[0]);
90		item->setText(1, arg[1]);
91		item->setText(2, arg[2]);
92	}
93
94	interfaceWidget->resizeColumnToContents(0);
95	interfaceWidget->resizeColumnToContents(1);
96	interfaceWidget->resizeColumnToContents(2);
97#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
98}
99
100
101#ifdef CONFIG_NATIVE_WINDOWS
102bool AddInterface::addRegistryInterface(const QString &ifname)
103{
104	HKEY hk, ihk;
105	LONG ret;
106	int id, tmp;
107	TCHAR name[10];
108	DWORD val, i;
109
110	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"),
111			   0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY,
112			   &hk);
113	if (ret != ERROR_SUCCESS)
114		return false;
115
116	id = -1;
117
118	for (i = 0; ; i++) {
119		TCHAR name[255];
120		DWORD namelen;
121
122		namelen = 255;
123		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
124				   NULL);
125
126		if (ret == ERROR_NO_MORE_ITEMS)
127			break;
128
129		if (ret != ERROR_SUCCESS)
130			break;
131
132		if (namelen >= 255)
133			namelen = 255 - 1;
134		name[namelen] = '\0';
135
136#ifdef UNICODE
137		QString s((QChar *) name, namelen);
138#else /* UNICODE */
139		QString s(name);
140#endif /* UNICODE */
141		tmp = s.toInt();
142		if (tmp > id)
143			id = tmp;
144	}
145
146	id += 1;
147
148#ifdef UNICODE
149	wsprintf(name, L"%04d", id);
150#else /* UNICODE */
151	os_snprintf(name, sizeof(name), "%04d", id);
152#endif /* UNICODE */
153	ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk,
154			     NULL);
155	RegCloseKey(hk);
156	if (ret != ERROR_SUCCESS)
157		return false;
158
159#ifdef UNICODE
160	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
161		      (LPBYTE) ifname.unicode(),
162		      (ifname.length() + 1) * sizeof(TCHAR));
163
164#else /* UNICODE */
165	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
166		      (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1);
167#endif /* UNICODE */
168	RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ,
169		      (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR));
170	RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ,
171		      (LPBYTE) TEXT(""), 1 * sizeof(TCHAR));
172	val = 1;
173	RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val,
174		      sizeof(val));
175
176	RegCloseKey(ihk);
177	return true;
178}
179#endif /* CONFIG_NATIVE_WINDOWS */
180
181
182void AddInterface::interfaceSelected(QTreeWidgetItem *sel)
183{
184	if (!sel)
185		return;
186
187#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
188	struct wpa_ctrl *ctrl;
189	int ret;
190	char buf[20], cmd[256];
191	size_t len;
192
193	/*
194	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
195	 * <driver_param>TAB<bridge_name>
196	 */
197	snprintf(cmd, sizeof(cmd),
198		 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
199		 sel->text(1).toAscii().constData(),
200		 "default",
201		 sel->text(0).toAscii().constData(),
202		 "yes", "", "");
203	cmd[sizeof(cmd) - 1] = '\0';
204
205	ctrl = wpa_ctrl_open(NULL);
206	if (ctrl == NULL)
207		return;
208
209	len = sizeof(buf) - 1;
210	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
211	wpa_ctrl_close(ctrl);
212
213	if (ret < 0) {
214		QMessageBox::warning(this, "wpa_gui",
215				     tr("Add interface command could not be "
216					"completed."));
217		return;
218	}
219
220	buf[len] = '\0';
221	if (buf[0] != 'O' || buf[1] != 'K') {
222		QMessageBox::warning(this, "wpa_gui",
223				     tr("Failed to add the interface."));
224		return;
225	}
226
227#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
228
229#ifdef CONFIG_NATIVE_WINDOWS
230	if (!addRegistryInterface(sel->text(1))) {
231		QMessageBox::information(this, "wpa_gui",
232					 tr("Failed to add the interface into "
233					    "registry."));
234	}
235#endif /* CONFIG_NATIVE_WINDOWS */
236
237	wpagui->selectAdapter(sel->text(1));
238	close();
239}
240