Fix compile on Linux.
[dhcpcd-ui] / src / libdhcpcd / wpa.c
1 /*
2  * libdhcpcd
3  * Copyright 2009 Roy Marples <roy@marples.name>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #define IN_LIBDHCPCD
33 #include "libdhcpcd.h"
34
35 void
36 dhcpcd_wi_scans_free(DHCPCD_WI_SCAN *wis)
37 {
38         DHCPCD_WI_SCAN *n;
39
40         while (wis) {
41                 n = wis->next;
42                 free(wis);
43                 wis = n;
44         }
45 }
46
47 static DHCPCD_WI_SCAN *
48 dhcpcd_scanresult_new(DHCPCD_CONNECTION *con, DBusMessageIter *array)
49 {
50         DBusMessageIter dict, entry, var;
51         DHCPCD_WI_SCAN *wis;
52         char *s;
53         int32_t i32;
54         int errors;
55
56         wis = malloc(sizeof(*wis));
57         if (wis == NULL) {
58                 dhcpcd_error_set(con, NULL, errno);
59                 return NULL;
60         }
61         memset(wis, 0, sizeof(*wis));
62         errors = con->errors;
63         dbus_message_iter_recurse(array, &dict);
64         for (;
65              dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
66              dbus_message_iter_next(&dict))
67         {
68                 dbus_message_iter_recurse(&dict, &entry);
69                 if (!dhcpcd_iter_get(con, &entry, DBUS_TYPE_STRING, &s))
70                     break;
71                 if (dbus_message_iter_get_arg_type(&entry) !=
72                     DBUS_TYPE_VARIANT)
73                         break;
74                 dbus_message_iter_recurse(&entry, &var);
75                 if (strcmp(s, "BSSID") == 0) {
76                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
77                                 break;
78                         strlcpy(wis->bssid, s, sizeof(wis->bssid));
79                 } else if (strcmp(s, "Frequency") == 0) {
80                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
81                                 break;
82                         wis->frequency = i32;
83                 } else if (strcmp(s, "Quality") == 0) {
84                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
85                                 break;
86                         wis->quality = i32;
87                 } else if (strcmp(s, "Noise") == 0) {
88                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
89                                 break;
90                         wis->noise = i32;
91                 } else if (strcmp(s, "Level") == 0) {
92                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_INT32, &i32))
93                                 break;
94                         wis->level = i32;
95                 } else if (strcmp(s, "Flags") == 0) {
96                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
97                                 break;
98                         strlcpy(wis->flags, s, sizeof(wis->flags));
99                 } else if (strcmp(s, "SSID") == 0) {
100                         if (!dhcpcd_iter_get(con, &var, DBUS_TYPE_STRING, &s))
101                                 break;
102                         strlcpy(wis->ssid, s, sizeof(wis->ssid));
103                 }
104         }
105         if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_INVALID) {
106                 if (con->errors == errors)
107                         dhcpcd_error_set(con, NULL, EINVAL);
108                 free(wis);
109                 return NULL;
110         }
111         return wis;
112 }
113
114 DHCPCD_WI_SCAN *
115 dhcpcd_wi_scans(DHCPCD_CONNECTION *con, DHCPCD_IF *i)
116 {
117         DBusMessage *msg;
118         DBusMessageIter args, array;
119         DHCPCD_WI_SCAN *wis, *scans, *l;
120         int errors;
121
122         msg = dhcpcd_message_reply(con, "ScanResults", i->ifname);
123         if (!dbus_message_iter_init(msg, &args) ||
124             dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
125         {
126                 dhcpcd_error_set(con, NULL, EINVAL);
127                 return NULL;
128         }
129
130         scans = l = NULL;
131         errors = con->errors;
132         dbus_message_iter_recurse(&args, &array);
133         for(;
134             dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY;
135             dbus_message_iter_next(&array))
136         {
137                 wis = dhcpcd_scanresult_new(con, &array);
138                 if (wis == NULL)
139                         break;
140                 if (l == NULL)
141                         scans = l = wis;
142                 else {
143                         l->next = wis;
144                         l = l->next;
145                 }
146         }
147         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
148                 if (con->errors == errors)
149                         dhcpcd_error_set(con, NULL, EINVAL);
150                 dhcpcd_wi_scans_free(scans);
151                 scans = NULL;
152         }
153         dbus_message_unref(msg);
154         return scans;
155 }
156
157 static int
158 dhcpcd_wpa_find_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i, const char *ssid)
159 {
160         DBusMessage *msg;
161         DBusMessageIter args, array, entry;
162         int32_t id;
163         char *s;
164         int errors;
165
166         msg = dhcpcd_message_reply(con, "ListNetworks", i->ifname);
167         if (msg == NULL)
168                 return -1;
169         if (!dbus_message_iter_init(msg, &args)) {
170                 dhcpcd_error_set(con, NULL, EINVAL);
171                 return -1;
172         }
173
174         errors = con->errors;
175         for(;
176             dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_ARRAY;
177             dbus_message_iter_next(&args))
178         {
179                 dbus_message_iter_recurse(&args, &array);
180                 for(;
181                     dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
182                     dbus_message_iter_next(&array))
183                 {
184                         dbus_message_iter_recurse(&array, &entry);
185                         if (!dhcpcd_iter_get(con, &entry,
186                                 DBUS_TYPE_INT32, &id) ||
187                             !dhcpcd_iter_get(con, &entry,
188                                 DBUS_TYPE_STRING, &s))
189                                 break;
190                         if (strcmp(s, ssid) == 0) {
191                                 dbus_message_unref(msg);
192                                 return (int)id;
193                         }
194                 }
195         }
196         if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_INVALID &&
197             con->errors == errors)
198                 dhcpcd_error_set(con, NULL, EINVAL);
199         dbus_message_unref(msg);
200         return -1;
201 }
202         
203 static int
204 dhcpcd_wpa_add_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i)
205 {
206         DBusMessage *msg;
207         DBusMessageIter args;
208         int32_t id;
209         int ret;
210
211         msg = dhcpcd_message_reply(con, "AddNetwork", i->ifname);
212         if (msg == NULL)
213                 return -1;
214         ret = -1;
215         if (dbus_message_iter_init(msg, &args)) {
216                 if (dhcpcd_iter_get(con, &args, DBUS_TYPE_INT32, &id))
217                         ret = id;
218         } else
219                 dhcpcd_error_set(con, NULL, EINVAL);
220         dbus_message_unref(msg);
221         return ret;
222 }
223
224 bool
225 dhcpcd_wpa_set_network(DHCPCD_CONNECTION *con, DHCPCD_IF *i, int id,
226     const char *opt, const char *val)
227 {
228         DBusMessage *msg, *reply;
229         DBusMessageIter args;
230         bool retval;
231         char *ifname;
232
233         msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
234             DHCPCD_SERVICE, "SetNetwork");
235         if (msg == NULL) {
236                 dhcpcd_error_set(con, 0, errno);
237                 return false;
238         }
239         dbus_message_iter_init_append(msg, &args);
240         ifname = i->ifname;
241         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &ifname);
242         dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &id);
243         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &opt);
244         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &val);
245         reply = dhcpcd_send_reply(con, msg);
246         dbus_message_unref(msg);
247         if (reply == NULL)
248                 retval = false;
249         else {
250                 dbus_message_unref(reply);
251                 retval = true;
252         }
253         return retval;
254 }
255
256 int
257 dhcpcd_wpa_find_network_new(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
258     const char *ssid)
259 {
260         int errors, id;
261         char *q;
262         size_t len;
263         bool retval;
264
265         len = strlen(ssid) + 3;
266         q = malloc(len);
267         if (q == NULL) {
268                 dhcpcd_error_set(con, 0, errno);
269                 return -1;
270         }
271         errors = con->errors;
272         id = dhcpcd_wpa_find_network(con, i, ssid);
273         if (id != -1 || con->errors != errors) {
274                 free(q);
275                 return id;
276         }
277         id = dhcpcd_wpa_add_network(con, i);
278         if (id == -1) {
279                 free(q);
280                 return -1;
281         }
282         snprintf(q, len, "\"%s\"", ssid);
283         retval = dhcpcd_wpa_set_network(con, i, id, "ssid", q);
284         free(q);
285         return retval;
286 }
287
288 bool
289 dhcpcd_wpa_command(DHCPCD_CONNECTION *con, DHCPCD_IF *i,
290     const char *cmd, int id)
291 {
292         DBusMessage *msg, *reply;
293         DBusMessageIter args;
294         char *ifname;
295         bool retval;
296         
297         msg = dbus_message_new_method_call(DHCPCD_SERVICE, DHCPCD_PATH,
298             DHCPCD_SERVICE, cmd);
299         if (msg == NULL) {
300                 dhcpcd_error_set(con, 0, errno);
301                 return false;
302         }
303         dbus_message_iter_init_append(msg, &args);
304         ifname = i->ifname;
305         dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &ifname);
306         if (id != -1)
307                 dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &id);
308         reply = dhcpcd_send_reply(con, msg);
309         dbus_message_unref(msg);
310         if (reply == NULL)
311                 retval = false;
312         else {
313                 dbus_message_unref(reply);
314                 retval = true;
315         }
316         return retval;
317 }