Enabling multithreaded compilation.
[debian/lxpanel.git] / src / plugins / netstat / wireless.c
index b8a01a1..f2360fc 100644 (file)
@@ -41,7 +41,7 @@ static const char * iw_ie_key_mgmt_name[] = {
 };
 */
 
-void wireless_aplist_free(APLIST *aplist)
+void wireless_aplist_free(void *aplist, GObject *dummy)
 {
        APLIST *ptr;
        APLIST *delptr;
@@ -199,16 +199,21 @@ wireless_parse_scanning_event(struct iw_event *event, ap_info *oldinfo)
        if (event->cmd==SIOCGIWAP) {
                char buf[128];
                info = g_new0(ap_info, 1);
-               info->apaddr = g_strdup(iw_saether_ntop(&event->u.ap_addr, buf));
+               info->apaddr = g_strdup(iw_sawap_ntop(&event->u.ap_addr, buf));
                info->en_method = NS_WIRELESS_AUTH_OFF;
                info->haskey = FALSE;
+               info->key_mgmt = NS_IW_IE_KEY_MGMT_NONE;
+               info->group = NS_IW_IE_CIPHER_TKIP;
+               info->pairwise = NS_IW_IE_CIPHER_TKIP;
        } else {
                info = oldinfo;
        }
 
     switch (event->cmd) {
         case SIOCGIWESSID: /* ESSID */
-                       if (!event->u.essid.flags||event->u.essid.length==0) {
+                       if (!event->u.essid.flags
+                               || event->u.essid.length==0
+                               || strlen(event->u.essid.pointer)==0) {
                                info->essid = NULL;
                        } else {
                                info->essid = g_strndup(event->u.essid.pointer, event->u.essid.length);
@@ -234,10 +239,9 @@ wireless_parse_scanning_event(struct iw_event *event, ap_info *oldinfo)
                {
                        int offset = 0;
                        int ielen = event->u.data.length;
-                       unsigned char *iebuf;
+                       unsigned char *iebuf = event->u.data.pointer;
 
                        while(offset <= (ielen - 2)) {
-                               iebuf = (event->u.data.pointer + offset);
                                /* check IE type */
                                switch(iebuf[offset]) {
                                        case 0xdd: /* WPA or else */
@@ -315,74 +319,149 @@ APLIST *wireless_scanning(int iwsockfd, const char *ifname)
 {
        APLIST *ap = NULL;
        APLIST *newap;
-       struct iwreq wrq;
-       struct iw_range range;
-       struct iw_event event;
-       struct stream_descr stream;
-       struct timeval tv;
-       fd_set rfds; /* File descriptors for select */
-       int selfd;
-       int ret;
-       char buffer[IW_SCAN_MAX_DATA];
-
-       strncpy(wrq.ifr_name, ifname, IFNAMSIZ);
 
-       /* Getting range */
-       iw_get_range_info(iwsockfd, ifname, &range);
-
-       /* check scanning support */
-       if (range.we_version_compiled < 14)
+       struct iwreq wrq;
+       int scanflags = 0;              /* Flags for scan */
+       unsigned char * buffer = NULL;  /* Results */
+       int buflen = IW_SCAN_MAX_DATA;  /* Min for compat WE < 17 */
+       struct iw_range range;
+       int has_range;
+       struct timeval tv;              /* select timeout */
+       int timeout = 15000000;         /* 15s */
+
+       /* Get range stuff */
+       has_range = (iw_get_range_info(iwsockfd, ifname, &range) >= 0);
+
+       /* Check if the interface could support scanning. */
+       if ((!has_range) || (range.we_version_compiled < 14)) {
+               fprintf(stderr, "%-8.16s  Interface doesn't support scanning.\n\n",
+                               ifname);
                return NULL;
+       }
 
-       /* Initiate Scanning */
-       wrq.u.data.pointer = buffer;
-       wrq.u.data.length = IW_SCAN_MAX_DATA;
+       /* Init timeout value -> 250ms between set and first get */
+       tv.tv_sec = 0;
+       tv.tv_usec = 250000;
+
+       wrq.u.data.pointer = NULL;
        wrq.u.data.flags = 0;
+       wrq.u.data.length = 0;
 
-       if (ioctl(iwsockfd, SIOCSIWSCAN, &wrq) < 0) {
-               if (errno!=EPERM)
+       /* Initiate Scanning */
+       if (iw_set_ext(iwsockfd, ifname, SIOCSIWSCAN, &wrq) < 0) {
+               if ((errno != EPERM) || (scanflags != 0)) {
+                       fprintf(stderr, "%-8.16s  Interface doesn't support "
+                               "scanning : %s\n\n", ifname, strerror(errno));
                        return NULL;
+               }
+               tv.tv_usec = 0;
        }
+       timeout -= tv.tv_usec;
 
-       /* Init timeout value -> 250ms */
-       tv.tv_sec = 0;
-       tv.tv_usec = 250000;
+       /* Forever */
+       while (1) {
+               fd_set rfds;            /* File descriptors for select */
+               int last_fd;    /* Last fd */
+               int ret;
 
-       /* Scanning APs */
-       while(1) {
-               if (ioctl(iwsockfd, SIOCGIWSCAN, &wrq) < 0) {
-                       if (errno == EAGAIN) { /* not yet ready */
-                               FD_ZERO(&rfds);
-                               selfd = -1;
+               /* Guess what ? We must re-generate rfds each time */
+               FD_ZERO(&rfds);
+               last_fd = -1;
 
-                               if (select(selfd + 1, &rfds, NULL, NULL, &tv)==0)
-                                       continue; /* timeout */
-                       } else {
-                               break;
-                       }
+               /* In here, add the rtnetlink fd in the list */
+
+               /* Wait until something happens */
+               ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
+
+               /* Check if there was an error */
+               if (ret < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       fprintf(stderr, "Unhandled signal - exiting...\n");
+                       return NULL;
                }
 
-               if (wrq.u.data.length <= 0)
-                       break;
+               /* Check if there was a timeout */
+               if (ret == 0) {
+                       unsigned char *newbuf;
+
+realloc:
+                       /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
+                       newbuf = realloc(buffer, buflen);
+                       if (newbuf == NULL) {
+                               if (buffer)
+                                       free(buffer);
+                               fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
+                               return NULL;
+                       }
+                       buffer = newbuf;
+
+                       /* Try to read the results */
+                       wrq.u.data.pointer = buffer;
+                       wrq.u.data.flags = 0;
+                       wrq.u.data.length = buflen;
+                       if (iw_get_ext(iwsockfd, ifname, SIOCGIWSCAN, &wrq) < 0)        {
+                               /* Check if buffer was too small (WE-17 only) */
+                               if ((errno == E2BIG) &&
+                                   (range.we_version_compiled > 16)) {
+                                       /* Check if the driver gave us any hints. */
+                                       if (wrq.u.data.length > buflen)
+                                               buflen = wrq.u.data.length;
+                                       else
+                                               buflen *= 2;
+                                       /* Try again */
+                                       goto realloc;
+                               }
 
-               /* Initializing event */
-               iw_init_event_stream(&stream, buffer, wrq.u.data.length); 
-               do {
-                       ret = iw_extract_event_stream(&stream, &event, range.we_version_compiled);
-                       if (ret > 0) {
-                               /* found a new AP */
-                               if (event.cmd==SIOCGIWAP) {
-                                       newap = g_new0(APLIST, 1);
-                                       newap->info = NULL;
-                                       newap->next = ap;
-                                       ap = newap;
+                               /* Check if results not available yet */
+                               if(errno == EAGAIN) {
+                                       /* Restart timer for only 100ms*/
+                                       tv.tv_sec = 0;
+                                       tv.tv_usec = 100000;
+                                       timeout -= tv.tv_usec;
+                                       if (timeout > 0)
+                                               continue; /* Try again later */
                                }
 
-                               /* Scanning Event */
-                               ap->info = wireless_parse_scanning_event(&event, ap->info);
+                               /* Bad error */
+                               free(buffer);
+                               fprintf(stderr, 
+                               "%-8.16s  Failed to read scan data : %s\n\n",
+                                               ifname, strerror(errno));
+                               return NULL;
                        }
-               } while (ret > 0);
+                       else
+                               /* We have the results, go to process them */
+                               break;
+               }
+
+               /* In here, check if event and event type
+                * if scan event, read results. All errors bad & no reset timeout */
+       }
+
+       if(wrq.u.data.length) {
+               struct iw_event           iwe;
+               struct stream_descr       stream;
+               int                       ret;
+
+               iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
+               do {
+                       /* Extract an event and print it */
+                       ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
+                       if (iwe.cmd==SIOCGIWAP) {
+                               newap = malloc(sizeof(APLIST));
+                               newap->info = NULL;
+                               newap->next = ap;
+                               ap = newap;
+                       }
+                       ap->info = wireless_parse_scanning_event(&iwe, ap->info);
+               }
+               while (ret > 0);
+               printf("\n");
        }
+       else
+               printf("%-8.16s  No scan results\n\n", ifname);
 
+       free(buffer);
        return ap;
 }