5 * Copyright (C) 2007 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
35 #include <net/ethernet.h>
36 #include <linux/wireless.h>
40 #include <connman/plugin.h>
41 #include <connman/iface.h>
42 #include <connman/log.h>
44 #include "supplicant.h"
54 unsigned char wpa_ie[40];
56 unsigned char rsn_ie[40];
65 char ifname[IFNAMSIZ];
72 static void report_station(struct connman_iface *iface,
73 struct station_data *station)
80 if (station->name == NULL)
90 connman_iface_indicate_station(iface, station->name,
91 station->qual, security);
94 static struct station_data *create_station(struct iface_data *iface,
97 struct station_data *station;
100 for (list = iface->stations; list; list = list->next) {
101 station = list->data;
103 if (g_ascii_strcasecmp(station->address, address) == 0)
107 station = g_try_new0(struct station_data, 1);
111 station->address = g_strdup(address);
112 if (station->address == NULL) {
117 iface->stations = g_slist_append(iface->stations, station);
122 static void load_stations(struct iface_data *iface)
125 gchar **groups, **group;
128 keyfile = g_key_file_new();
130 if (g_key_file_load_from_file(keyfile, "/tmp/stations.list",
131 G_KEY_FILE_KEEP_COMMENTS, NULL) == FALSE)
134 groups = g_key_file_get_groups(keyfile, &length);
136 for (group = groups; *group; group++) {
137 struct station_data *station;
139 station = create_station(iface, *group);
143 station->name = g_key_file_get_string(keyfile,
144 *group, "Name", NULL);
146 station->mode = g_key_file_get_integer(keyfile,
147 *group, "Mode", NULL);
153 g_key_file_free(keyfile);
155 printf("[802.11] loaded %d stations\n",
156 g_slist_length(iface->stations));
159 static void print_stations(struct iface_data *iface)
166 keyfile = g_key_file_new();
168 for (list = iface->stations; list; list = list->next) {
169 struct station_data *station = list->data;
171 //printf("Address:%s Mode:%d ESSID:\"%s\" Quality:%d/100\n",
172 // station->address, station->mode,
173 // station->name, station->qual);
175 if (station->name == NULL)
178 g_key_file_set_string(keyfile, station->address,
179 "Name", station->name);
181 g_key_file_set_integer(keyfile, station->address,
182 "Mode", station->mode);
185 data = g_key_file_to_data(keyfile, &length, NULL);
187 g_file_set_contents("/tmp/stations.list", data, length, NULL);
189 g_key_file_free(keyfile);
192 static int wifi_probe(struct connman_iface *iface)
194 struct iface_data *data;
198 sk = socket(PF_INET, SOCK_DGRAM, 0);
202 memset(&ifr, 0, sizeof(ifr));
203 ifr.ifr_ifindex = iface->index;
205 err = ioctl(sk, SIOCGIFNAME, &ifr);
212 DBG("iface %p %s", iface, ifr.ifr_name);
214 data = malloc(sizeof(*data));
218 memset(data, 0, sizeof(*data));
220 memcpy(data->ifname, ifr.ifr_name, IFNAMSIZ);
222 iface->type = CONNMAN_IFACE_TYPE_80211;
224 iface->flags = CONNMAN_IFACE_FLAG_RTNL |
225 CONNMAN_IFACE_FLAG_IPV4 |
226 CONNMAN_IFACE_FLAG_SCANNING;
228 connman_iface_set_data(iface, data);
235 static void wifi_remove(struct connman_iface *iface)
237 struct iface_data *data = connman_iface_get_data(iface);
239 DBG("iface %p %s", iface, data->ifname);
241 __supplicant_stop(iface);
243 connman_iface_set_data(iface, NULL);
245 g_free(data->network);
246 g_free(data->passphrase);
251 static int wifi_start(struct connman_iface *iface)
253 struct iface_data *data = connman_iface_get_data(iface);
255 DBG("iface %p %s", iface, data->ifname);
257 __supplicant_start(iface);
262 static int wifi_stop(struct connman_iface *iface)
264 struct iface_data *data = connman_iface_get_data(iface);
266 DBG("iface %p %s", iface, data->ifname);
268 __supplicant_stop(iface);
273 static int wifi_scan(struct connman_iface *iface)
275 struct iface_data *data = connman_iface_get_data(iface);
277 struct iw_scan_req iws;
280 DBG("iface %p %s", iface, data->ifname);
282 sk = socket(PF_INET, SOCK_DGRAM, 0);
286 memset(&iws, 0, sizeof(iws));
287 iws.scan_type = IW_SCAN_TYPE_PASSIVE;
288 //iws.scan_type = IW_SCAN_TYPE_ACTIVE;
290 memset(&iwr, 0, sizeof(iwr));
291 strncpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
293 iwr.u.data.pointer = (caddr_t ) &iws;
294 iwr.u.data.length = sizeof(iws);
295 iwr.u.data.flags = IW_SCAN_DEFAULT;
297 err = ioctl(sk, SIOCSIWSCAN, &iwr);
302 connman_error("%s: scan initiate error %d",
303 data->ifname, errno);
308 static int wifi_connect(struct connman_iface *iface,
309 struct connman_network *network)
311 struct iface_data *data = connman_iface_get_data(iface);
313 DBG("iface %p %s", iface, data->ifname);
315 if (data->network != NULL)
316 __supplicant_connect(iface, data->network, data->passphrase);
321 static int wifi_disconnect(struct connman_iface *iface)
323 struct iface_data *data = connman_iface_get_data(iface);
325 DBG("iface %p %s", iface, data->ifname);
327 if (data->network != NULL)
328 __supplicant_disconnect(iface);
333 static void wifi_set_network(struct connman_iface *iface,
336 struct iface_data *data = connman_iface_get_data(iface);
338 DBG("iface %p %s", iface, data->ifname);
340 g_free(data->network);
342 data->network = g_strdup(network);
345 static void wifi_set_passphrase(struct connman_iface *iface,
346 const char *passphrase)
348 struct iface_data *data = connman_iface_get_data(iface);
350 DBG("iface %p %s", iface, data->ifname);
352 g_free(data->passphrase);
354 data->passphrase = g_strdup(passphrase);
357 static void parse_genie(struct station_data *station,
358 unsigned char *data, int len)
362 while (offset <= len - 2) {
365 switch (data[offset]) {
366 case 0xdd: /* WPA1 (and other) */
367 station->has_wpa = 1;
369 case 0x30: /* WPA2 (RSN) */
370 station->has_rsn = 1;
376 //for (i = 0; i < len; i++)
377 // printf(" %02x", data[i]);
380 offset += data[offset + 1] + 2;
384 static void parse_scan_results(struct connman_iface *iface,
385 unsigned char *data, int len)
387 unsigned char *ptr = data;
388 struct station_data *station = NULL;
389 struct ether_addr *eth;
393 while (len > IW_EV_LCP_PK_LEN) {
394 struct iw_event *event = (void *) ptr;
396 switch (event->cmd) {
398 report_station(iface, station);
399 eth = (void *) &event->u.ap_addr.sa_data;
400 sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
401 eth->ether_addr_octet[0],
402 eth->ether_addr_octet[1],
403 eth->ether_addr_octet[2],
404 eth->ether_addr_octet[3],
405 eth->ether_addr_octet[4],
406 eth->ether_addr_octet[5]);
407 station = create_station(connman_iface_get_data(iface),
412 if (station != NULL) {
413 station->name = malloc(event->len - IW_EV_POINT_LEN + 1);
414 if (station->name != NULL) {
415 memset(station->name, 0,
416 event->len - IW_EV_POINT_LEN + 1);
417 memcpy(station->name, ptr + IW_EV_POINT_LEN,
418 event->len - IW_EV_POINT_LEN);
426 station->mode = event->u.mode;
431 if (station != NULL) {
432 if (!event->u.data.pointer)
433 event->u.data.flags |= IW_ENCODE_NOKEY;
435 if (!(event->u.data.flags & IW_ENCODE_DISABLED))
436 station->has_wep = 1;
442 if (station != NULL) {
443 station->qual = event->u.qual.qual;
444 station->noise = event->u.qual.noise;
445 station->level = event->u.qual.level;
450 parse_genie(station, ptr + 8, event->len - 8);
455 printf("[802.11] scan element 0x%04x (len %d)\n",
456 event->cmd, event->len);
466 report_station(iface, station);
468 printf("[802.11] found %d networks\n", num);
471 static void scan_results(struct connman_iface *iface)
473 struct iface_data *data = connman_iface_get_data(iface);
477 int sk, err, done = 0;
482 memset(&iwr, 0, sizeof(iwr));
483 memcpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
485 sk = socket(PF_INET, SOCK_DGRAM, 0);
495 newbuf = g_realloc(buf, size);
496 if (newbuf == NULL) {
502 iwr.u.data.pointer = buf;
503 iwr.u.data.length = size;
504 iwr.u.data.flags = 0;
506 err = ioctl(sk, SIOCGIWSCAN, &iwr);
513 parse_scan_results(iface, iwr.u.data.pointer,
523 print_stations(data);
526 static void wifi_wireless(struct connman_iface *iface,
527 void *data, unsigned short len)
529 struct iw_event *event = data;
530 struct iw_point point;
531 struct ether_addr *eth;
534 switch (event->cmd) {
536 printf("[802.11] Set Frequency (flags %d)\n",
537 event->u.freq.flags);
540 printf("[802.11] Set Mode (mode %d)\n", event->u.mode);
543 memcpy(&point, data + IW_EV_LCP_LEN -
544 IW_EV_POINT_OFF, sizeof(point));
545 point.pointer = data + IW_EV_LCP_LEN +
546 sizeof(point) - IW_EV_POINT_OFF;
547 printf("[802.11] Set ESSID (length %d flags %d) \"%s\"\n",
548 point.length, point.flags,
549 (char *) point.pointer);
552 printf("[802.11] Set Encryption key (flags %d)\n",
553 event->u.data.flags);
557 eth = (void *) &event->u.ap_addr.sa_data;
558 sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
559 eth->ether_addr_octet[0],
560 eth->ether_addr_octet[1],
561 eth->ether_addr_octet[2],
562 eth->ether_addr_octet[3],
563 eth->ether_addr_octet[4],
564 eth->ether_addr_octet[5]);
565 printf("[802.11] New Access Point %s\n", addr);
571 printf("[802.11] Wireless event (cmd 0x%04x len %d)\n",
572 event->cmd, event->len);
577 static struct connman_iface_driver wifi_driver = {
579 .capability = "net.80211",
581 .remove = wifi_remove,
585 .connect = wifi_connect,
586 .disconnect = wifi_disconnect,
587 .set_network = wifi_set_network,
588 .set_passphrase = wifi_set_passphrase,
589 .rtnl_wireless = wifi_wireless,
592 static int wifi_init(void)
594 return connman_iface_register(&wifi_driver);
597 static void wifi_exit(void)
599 connman_iface_unregister(&wifi_driver);
602 CONNMAN_PLUGIN_DEFINE("80211", "IEEE 802.11 interface plugin", VERSION,
603 wifi_init, wifi_exit)