Add support for indicating security methods
[connman] / plugins / 80211.c
index 558dd97..eaec342 100644 (file)
@@ -54,6 +54,10 @@ struct station_data {
        int wpa_ie_len;
        unsigned char rsn_ie[40];
        int rsn_ie_len;
+
+       int has_wep;
+       int has_wpa;
+       int has_rsn;
 };
 
 struct iface_data {
@@ -64,6 +68,28 @@ struct iface_data {
        gchar *passphrase;
 };
 
+static void report_station(struct connman_iface *iface,
+                                               struct station_data *station)
+{
+       int security = 0;
+
+       if (station == NULL)
+               return;
+
+       if (station->name == NULL)
+               return;
+
+       if (station->has_wep)
+               security |= 0x01;
+       if (station->has_wpa)
+               security |= 0x02;
+       if (station->has_rsn)
+               security |= 0x04;
+
+       connman_iface_indicate_station(iface, station->name,
+                                               station->qual, security);
+}
+
 static struct station_data *create_station(struct iface_data *iface,
                                                        const char *address)
 {
@@ -145,6 +171,9 @@ static void print_stations(struct iface_data *iface)
                //                      station->address, station->mode,
                //                              station->name, station->qual);
 
+               if (station->name == NULL)
+                       continue;
+
                g_key_file_set_string(keyfile, station->address,
                                                "Name", station->name);
 
@@ -217,28 +246,6 @@ static void iface_remove(struct connman_iface *iface)
        free(data);
 }
 
-static int iface_activate(struct connman_iface *iface)
-{
-       struct iface_data *data = connman_iface_get_data(iface);
-
-       printf("[802.11] activate %s\n", data->ifname);
-
-       connman_iface_update(iface, CONNMAN_IFACE_STATE_ENABLED);
-
-       return 0;
-}
-
-static int iface_shutdown(struct connman_iface *iface)
-{
-       struct iface_data *data = connman_iface_get_data(iface);
-
-       printf("[802.11] shutdown %s\n", data->ifname);
-
-       connman_iface_update(iface, CONNMAN_IFACE_STATE_SHUTDOWN);
-
-       return 0;
-}
-
 static int iface_scan(struct connman_iface *iface)
 {
        struct iface_data *data = connman_iface_get_data(iface);
@@ -282,7 +289,22 @@ static int iface_connect(struct connman_iface *iface,
 
        __supplicant_start(iface);
 
-       __supplicant_connect(iface, data->network, data->passphrase);
+       if (data->network != NULL)
+               __supplicant_connect(iface, data->network, data->passphrase);
+
+       return 0;
+}
+
+static int iface_disconnect(struct connman_iface *iface)
+{
+       struct iface_data *data = connman_iface_get_data(iface);
+
+       printf("[802.11] disconnect %s\n", data->ifname);
+
+       if (data->network != NULL)
+               __supplicant_disconnect(iface);
+
+       __supplicant_stop(iface);
 
        return 0;
 }
@@ -294,9 +316,15 @@ static void iface_set_network(struct connman_iface *iface,
 
        printf("[802.11] set network %s\n", data->ifname);
 
+       if (data->network != NULL)
+               __supplicant_disconnect(iface);
+
        g_free(data->network);
 
        data->network = g_strdup(network);
+
+       if (data->network != NULL)
+               __supplicant_connect(iface, data->network, data->passphrase);
 }
 
 static void iface_set_passphrase(struct connman_iface *iface,
@@ -306,16 +334,15 @@ static void iface_set_passphrase(struct connman_iface *iface,
 
        printf("[802.11] set passphrase %s\n", data->ifname);
 
+       if (data->network != NULL)
+               __supplicant_disconnect(iface);
+
        g_free(data->passphrase);
 
        data->passphrase = g_strdup(passphrase);
-}
 
-static void iface_carrier(struct connman_iface *iface, int carrier)
-{
-       printf("[802.11] carrier %s\n", carrier ? "on" : "off");
-
-       connman_iface_indicate_carrier(iface, carrier);
+       if (data->network != NULL)
+               __supplicant_connect(iface, data->network, data->passphrase);
 }
 
 static void parse_genie(struct station_data *station,
@@ -328,8 +355,10 @@ static void parse_genie(struct station_data *station,
 
                switch (data[offset]) {
                case 0xdd:      /* WPA1 (and other) */
+                       station->has_wpa = 1;
                        break;
                case 0x30:      /* WPA2 (RSN) */
+                       station->has_rsn = 1;
                        break;
                default:
                        break;
@@ -357,6 +386,7 @@ static void parse_scan_results(struct connman_iface *iface,
 
                switch (event->cmd) {
                case SIOCGIWAP:
+                       report_station(iface, station);
                        eth = (void *) &event->u.ap_addr.sa_data;
                        sprintf(addr, "%02X:%02X:%02X:%02X:%02X:%02X",
                                                eth->ether_addr_octet[0],
@@ -371,11 +401,12 @@ static void parse_scan_results(struct connman_iface *iface,
                        break;
                case SIOCGIWESSID:
                        if (station != NULL) {
-                               station->name = malloc(event->len - 7);
+                               station->name = malloc(event->len - IW_EV_POINT_LEN + 1);
                                if (station->name != NULL) {
-                                       memset(station->name, 0, event->len - 7);
-                                       memcpy(station->name, ptr + 8,
-                                                               event->len - 8);
+                                       memset(station->name, 0,
+                                               event->len - IW_EV_POINT_LEN + 1);
+                                       memcpy(station->name, ptr + IW_EV_POINT_LEN,
+                                               event->len - IW_EV_POINT_LEN);
                                }
                        }
                        break;
@@ -389,9 +420,8 @@ static void parse_scan_results(struct connman_iface *iface,
                        break;
                case SIOCGIWENCODE:
                        if (station != NULL) {
-                               if (!(event->u.data.flags & IW_ENCODE_DISABLED)) {
-                                       /* privacy */
-                               }
+                               if (!(event->u.data.flags & IW_ENCODE_DISABLED))
+                                       station->has_wep = 1;
                        }
                        break;
                case SIOCGIWRATE:
@@ -419,6 +449,8 @@ static void parse_scan_results(struct connman_iface *iface,
                len -= event->len;
        }
 
+       report_station(iface, station);
+
        printf("[802.11] found %d networks\n", num);
 }
 
@@ -426,40 +458,53 @@ static void iface_scan_results(struct connman_iface *iface)
 {
        struct iface_data *data = connman_iface_get_data(iface);
        struct iwreq iwr;
-       unsigned char *buf;
-       int sk, err, size = 1024;
+       void *buf;
+       size_t size;
+       int sk, err, done = 0;
+
+       if (data == NULL)
+               return;
+
+       memset(&iwr, 0, sizeof(iwr));
+       memcpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
 
        sk = socket(PF_INET, SOCK_DGRAM, 0);
        if (sk < 0)
                return;
 
-retrieve:
-       buf = malloc(size);
-       if (buf == NULL) {
-               close(sk);
-               return;
-       }
+       buf = NULL;
+       size = 1024;
 
-       memset(&iwr, 0, sizeof(iwr));
-       strncpy(iwr.ifr_name, data->ifname, IFNAMSIZ);
-       iwr.u.data.pointer = buf;
-       iwr.u.data.length = size;
-       iwr.u.data.flags = 0;
-
-       err = ioctl(sk, SIOCGIWSCAN, &iwr);
-       if (err < 0) {
-               if (errno == E2BIG) {
-                       free(buf);
-                       size *= 2;
-                       goto retrieve;
+       while (!done) {
+               void *newbuf;
+
+               newbuf = g_realloc(buf, size);
+               if (newbuf == NULL) {
+                       close(sk);
+                       return;
                }
-       } else
-               parse_scan_results(iface, iwr.u.data.pointer,
-                                               iwr.u.data.length);
 
-       close(sk);
+               buf = newbuf;
+               iwr.u.data.pointer = buf;
+               iwr.u.data.length = size;
+               iwr.u.data.flags = 0;
+
+               err = ioctl(sk, SIOCGIWSCAN, &iwr);
+               if (err < 0) {
+                       if (errno == E2BIG)
+                               size *= 2;
+                       else
+                               done = 1;
+               } else {
+                       parse_scan_results(iface, iwr.u.data.pointer,
+                                                       iwr.u.data.length);
+                       done = 1;
+               }
+       }
+
+       g_free(buf);
 
-       free(buf);
+       close(sk);
 
        print_stations(data);
 }
@@ -520,13 +565,11 @@ static struct connman_iface_driver iface_driver = {
        .capability     = "net.80211",
        .probe          = iface_probe,
        .remove         = iface_remove,
-       .activate       = iface_activate,
-       .shutdown       = iface_shutdown,
        .scan           = iface_scan,
        .connect        = iface_connect,
+       .disconnect     = iface_disconnect,
        .set_network    = iface_set_network,
        .set_passphrase = iface_set_passphrase,
-       .rtnl_carrier   = iface_carrier,
        .rtnl_wireless  = iface_wireless,
 };