5fc65b607a41e03cede9c38ac96a19563c9862f5
[project/luci.git] / libs / luanet / src / iwconfig.c
1 /*
2  *  Licensed under the Apache License, Version 2.0 (the "License");
3  *  you may not use this file except in compliance with the License.
4  *  You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  *  Unless required by applicable law or agreed to in writing, software
9  *  distributed under the License is distributed on an "AS IS" BASIS,
10  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  *  See the License for the specific language governing permissions and
12  *  limitations under the License.
13  *
14  *   Copyright (C) 2008 John Crispin <blogic@openwrt.org> 
15  *   Copyright (C) 2008 Steven Barth <steven@midlink.org>
16  */
17
18 #include <net/if.h>
19 #include <net/if_arp.h>
20 #include <net/route.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <linux/sockios.h>
25 #include "iwlib.h"
26
27 #include <lua.h>
28 #include <lualib.h>
29 #include <lauxlib.h>
30
31 #include "helper.h"
32
33 static int sock_iwconfig = 0;
34
35 typedef struct iwscan_state
36 {
37         /* State */
38         int ap_num;     /* Access Point number 1->N */
39         int val_index;  /* Value in table 0->(N-1) */
40 } iwscan_state;
41
42 int iwc_startup(void)
43 {
44         if(!sock_iwconfig)
45                 sock_iwconfig = iw_sockets_open();
46         return sock_iwconfig;
47 }
48
49 void iwc_shutdown(void)
50 {
51         if(!sock_iwconfig)
52                 return;
53         iw_sockets_close(sock_iwconfig);
54         sock_iwconfig = 0;
55 }
56
57 /* taken from wireless tools */
58 static int
59 get_info(char * ifname, struct wireless_info * info)
60 {
61         struct iwreq wrq;
62
63         memset((char*) info, 0, sizeof(struct wireless_info));
64
65         /* Get basic information */
66         if(iw_get_basic_config(sock_iwconfig, ifname, &(info->b)) < 0)
67         {
68                 /* If no wireless name : no wireless extensions */
69                 /* But let's check if the interface exists at all */
70                 struct ifreq ifr;
71
72                 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
73                 if(ioctl(sock_iwconfig, SIOCGIFFLAGS, &ifr) < 0)
74                         return(-ENODEV);
75                 else
76                         return(-ENOTSUP);
77         }
78
79         /* Get ranges */
80         if(iw_get_range_info(sock_iwconfig, ifname, &(info->range)) >= 0)
81                 info->has_range = 1;
82
83         /* Get AP address */
84         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWAP, &wrq) >= 0)
85         {
86                 info->has_ap_addr = 1;
87                 memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
88         }
89
90         /* Get bit rate */
91         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRATE, &wrq) >= 0)
92         {
93                 info->has_bitrate = 1;
94                 memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
95         }
96
97         /* Get Power Management settings */
98         wrq.u.power.flags = 0;
99         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWPOWER, &wrq) >= 0)
100         {
101                 info->has_power = 1;
102                 memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
103         }
104
105         /* Get stats */
106         if(iw_get_stats(sock_iwconfig, ifname, &(info->stats),
107                 &info->range, info->has_range) >= 0)
108         {
109                 info->has_stats = 1;
110         }
111
112         /* Get NickName */
113         wrq.u.essid.pointer = (caddr_t) info->nickname;
114         wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
115         wrq.u.essid.flags = 0;
116         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWNICKN, &wrq) >= 0)
117                 if(wrq.u.data.length > 1)
118                         info->has_nickname = 1;
119
120         if((info->has_range) && (info->range.we_version_compiled > 9))
121         {
122                 /* Get Transmit Power */
123                 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWTXPOW, &wrq) >= 0)
124                 {
125                         info->has_txpower = 1;
126                         memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
127                 }
128         }
129
130         /* Get sensitivity */
131         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWSENS, &wrq) >= 0)
132         {
133                 info->has_sens = 1;
134                 memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
135         }
136
137         if((info->has_range) && (info->range.we_version_compiled > 10))
138         {
139                 /* Get retry limit/lifetime */
140                 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRETRY, &wrq) >= 0)
141                 {
142                         info->has_retry = 1;
143                         memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
144                 }
145         }
146
147         /* Get RTS threshold */
148         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRTS, &wrq) >= 0)
149         {
150                 info->has_rts = 1;
151                 memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
152         }
153
154         /* Get fragmentation threshold */
155         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWFRAG, &wrq) >= 0)
156         {
157                 info->has_frag = 1;
158                 memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
159         }
160
161         return(0);
162 }
163
164 void iwc_get(lua_State *L, char *ifname)
165 {
166         struct wireless_info info;
167         int rc = get_info(ifname, &info);
168         char buffer[128];
169         if(rc)
170                 return;
171
172         lua_pushstring(L, ifname);
173         lua_newtable(L);
174
175         if(info.b.has_essid)
176         {
177                 if(info.b.essid_on)
178                         add_table_entry(L, "essid", info.b.essid);
179                 else
180                         add_table_entry(L, "essid", "off");
181         }
182
183         if(info.b.has_mode)
184                 add_table_entry(L, "mode", iw_operation_mode[info.b.mode]);
185
186         if(info.b.has_freq)
187         {
188                 double freq = info.b.freq;    /* Frequency/channel */
189                 int channel = -1;       /* Converted to channel */
190                 char tmp[4];
191                 if(info.has_range && (freq < KILO))
192                         channel = iw_channel_to_freq((int) freq, &freq, &info.range);
193                 iw_print_freq(buffer, sizeof(buffer), freq, -1, info.b.freq_flags);
194                 snprintf(tmp, 4, "%d", channel);
195                 add_table_entry(L, "channel", tmp);
196                 add_table_entry(L, "freq", buffer);
197         }
198
199         if(info.has_ap_addr)
200                 add_table_entry(L, "macap", iw_sawap_ntop(&info.ap_addr, buffer));
201
202         if(info.has_bitrate)
203         {
204                 iw_print_bitrate(buffer, sizeof(buffer), info.bitrate.value);
205                 add_table_entry(L, "bitrate", buffer);
206         }
207
208         if(info.has_txpower)
209         {
210                 iw_print_txpower(buffer, sizeof(buffer), &info.txpower);
211                 add_table_entry(L, "txpower", buffer);
212         }
213         lua_settable(L, -3);
214 }
215
216 int iwc_getall(lua_State *L)
217 {
218         FILE *fp;
219         char buffer[128];
220         char *b = buffer;
221         fp = fopen("/proc/net/wireless", "r");
222         if(!fp)
223                 return -1;
224         fgets(buffer, 128, fp);
225         fgets(buffer, 128, fp);
226         lua_newtable(L);
227         while(fgets(buffer, 128, fp))
228         {
229                 char *t;
230                 b = buffer;
231                 while(*b == ' ')
232                         b++;
233                 t = strstr(b, ":");
234                 if(t)
235                         *t = '\0';
236                 iwc_get(L, b);
237         }
238         return 1;
239 }
240
241 /* taken from wireless tools */
242 int iwc_set_essid(lua_State *L)
243 {
244         struct iwreq wrq;
245         int i = 1;
246         char essid[IW_ESSID_MAX_SIZE + 1];
247         int we_kernel_version;
248         char *ifname, *e;
249         if(lua_gettop(L) != 2)
250         {
251                 lua_pushstring(L, "invalid arg list");
252                 lua_error(L);
253                 return 0;
254         }
255         ifname = (char *)lua_tostring (L, 1);
256         e = (char *)lua_tostring (L, 2);
257
258         if((!strcasecmp(e, "off")) | (!strcasecmp(e, "any")))
259         {
260                 wrq.u.essid.flags = 0;
261                 essid[0] = '\0';
262         } else if(!strcasecmp(e, "on"))
263         {
264                 /* Get old essid */
265                 memset(essid, '\0', sizeof(essid));
266                 wrq.u.essid.pointer = (caddr_t) essid;
267                 wrq.u.essid.length = IW_ESSID_MAX_SIZE + 1;
268                 wrq.u.essid.flags = 0;
269                 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWESSID, &wrq) < 0)
270                         return 0;
271                 wrq.u.essid.flags = 1;
272         } else {
273                 wrq.u.essid.flags = 1;
274                 strcpy(essid, e); /* Size checked, all clear */
275                 i++;
276         }
277
278         /* Get version from kernel, device may not have range... */
279         we_kernel_version = iw_get_kernel_we_version();
280
281         /* Finally set the ESSID value */
282         wrq.u.essid.pointer = (caddr_t) essid;
283         wrq.u.essid.length = strlen(essid);
284         if(we_kernel_version < 21)
285                 wrq.u.essid.length++;
286
287         if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWESSID, &wrq))
288                 lua_pushboolean(L, 1);
289         else
290                 lua_pushboolean(L, 0);
291         return 1;
292 }
293
294 /* taken from wireless tools */
295 int iwc_set_mode(lua_State *L)
296 {
297         struct iwreq wrq;
298         unsigned int k;      /* Must be unsigned */
299         char *ifname, *mode;
300
301         if(lua_gettop(L) != 2)
302         {
303                 lua_pushstring(L, "invalid arg list");
304                 lua_error(L);
305                 return 0;
306         }
307         ifname = (char *)lua_tostring (L, 1);
308         mode = (char *)lua_tostring (L, 2);
309
310         /* Check if it is a uint, otherwise get is as a string */
311         if(sscanf(mode, "%ui", &k) != 1)
312         {
313                 k = 0;
314                 while((k < IW_NUM_OPER_MODE) && strncasecmp(mode, iw_operation_mode[k], 3))
315                         k++;
316         }
317         if(k >= IW_NUM_OPER_MODE)
318                 return 0;
319
320         wrq.u.mode = k;
321         if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWMODE, &wrq))
322                 lua_pushboolean(L, 1);
323         else
324                 lua_pushboolean(L, 0);
325         return 1;
326 }
327
328 int iwc_set_channel(lua_State *L)
329 {
330         struct iwreq wrq;
331         char *ifname;
332         int channel;
333         if(lua_gettop(L) != 2)
334         {
335                 lua_pushstring(L, "invalid arg list");
336                 lua_error(L);
337                 return 0;
338         }
339         ifname = (char *)lua_tostring (L, 1);
340         channel = (int)lua_tointeger(L, 2);
341
342         if(channel == -1)
343         {
344                 wrq.u.freq.m = -1;
345                 wrq.u.freq.e = 0;
346                 wrq.u.freq.flags = 0;
347         } else {
348                 iw_float2freq(channel, &wrq.u.freq);
349                 wrq.u.freq.flags = IW_FREQ_FIXED;
350         }
351         if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWFREQ, &wrq))
352                 lua_pushboolean(L, 1);
353         else
354                 lua_pushboolean(L, 0);
355         return 1;
356 }
357
358 static const char *     iw_ie_cypher_name[] = {
359         "none",
360         "WEP-40",
361         "TKIP",
362         "WRAP",
363         "CCMP",
364         "WEP-104",
365 };
366 #define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
367 #define IW_IE_CYPHER_NUM        IW_ARRAY_LEN(iw_ie_cypher_name)
368
369 static const char *     iw_ie_key_mgmt_name[] = {
370         "none",
371         "802.1x",
372         "PSK",
373 };
374 #define IW_IE_KEY_MGMT_NUM      IW_ARRAY_LEN(iw_ie_key_mgmt_name)
375
376 static inline void iw_print_ie_wpa(lua_State *L, unsigned char * iebuf, int buflen)
377 {
378         int ielen = iebuf[1] + 2;
379         int offset = 2; /* Skip the IE id, and the length. */
380         unsigned char wpa1_oui[3] = {0x00, 0x50, 0xf2};
381         unsigned char wpa2_oui[3] = {0x00, 0x0f, 0xac};
382         unsigned char *wpa_oui;
383         int i;
384         uint16_t ver = 0;
385         uint16_t cnt = 0;
386         int wpa1 = 0, wpa2 = 0;
387         char buf[256];
388         if(ielen > buflen)
389                 ielen = buflen;
390
391         switch(iebuf[0])
392         {
393         case 0x30:      /* WPA2 */
394                 /* Check if we have enough data */
395                 if(ielen < 4)
396                         return;
397                 wpa_oui = wpa2_oui;
398                 break;
399
400         case 0xdd:      /* WPA or else */
401                 wpa_oui = wpa1_oui;
402                 /* Not all IEs that start with 0xdd are WPA. 
403                 *        * So check that the OUI is valid. */
404                 if((ielen < 8)
405                         || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
406                         && (iebuf[offset+3] == 0x01)))
407                 {
408                         return;
409                 }
410
411                 offset += 4;
412                 break;
413
414         default:
415                 return;
416         }
417
418         /* Pick version number (little endian) */
419         ver = iebuf[offset] | (iebuf[offset + 1] << 8);
420         offset += 2;
421
422         if(iebuf[0] == 0xdd)
423                 wpa1 = 1;
424         if(iebuf[0] == 0x30)
425                 wpa2 = 1;
426
427         if(ielen < (offset + 4))
428         {
429                 if(wpa1)
430                 {
431                         add_table_entry(L, "wpa1gcipher", "TKIP");
432                         add_table_entry(L, "wpa1pcipher", "TKIP");
433                 } else {
434                         add_table_entry(L, "wpa2gcipher", "TKIP");
435             add_table_entry(L, "wpa2pcipher", "TKIP");
436                 }
437                 return;
438         }
439
440         if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
441         {
442                 if(wpa1)
443                         add_table_entry(L, "wpa1gcipher", "Proprietary");
444                 else
445                         add_table_entry(L, "wpa2gcipher", "Proprietary");
446         } else {
447                 if(wpa1)
448                         add_table_entry(L, "wpa1gcipher", iebuf[offset+3][iw_ie_cypher_name]);
449                 else
450                         add_table_entry(L, "wpa2gcipher", iebuf[offset+3][iw_ie_cypher_name]);
451         }
452         offset += 4;
453
454         if(ielen < (offset + 2))
455         {
456                 if(wpa1)
457                         add_table_entry(L, "wpa1pcipher", "TKIP");
458                 else
459                         add_table_entry(L, "wpa2pcipher", "TKIP");
460                 return;
461         }
462         /* Otherwise, we have some number of pairwise ciphers. */
463         cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
464         offset += 2;
465         if(ielen < (offset + 4*cnt))
466                 return;
467         *buf = '\0';
468         for(i = 0; i < cnt; i++)
469         {
470                 if(i > 0)
471                         strncat(buf, " ", 256);
472                 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
473                 {
474                         strncat(buf, "Proprietary", 256);
475                 } else {
476                         if(iebuf[offset+3] <= IW_IE_CYPHER_NUM)
477                                 strncat(buf, iw_ie_cypher_name[iebuf[offset+3]], 256);
478                         else
479                                 strncat(buf, "unknown", 256);
480                 }
481                 offset+=4;
482         }
483         if(wpa1)
484                 add_table_entry(L, "wpa1pcipher", buf);
485         else
486                 add_table_entry(L, "wpa2pcipher", buf);
487
488         /* Check if we are done */
489         if(ielen < (offset + 2))
490                 return;
491
492         /* Now, we have authentication suites. */
493         cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
494         offset += 2;
495         *buf = '\0';
496         if(ielen < (offset + 4*cnt))
497                 return;
498
499         for(i = 0; i < cnt; i++)
500         {
501                 if(i != 0)
502                         strncat(buf, " ", 256);
503                 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
504                 {
505                         strncat(buf, "Proprietary", 256);
506                 } else {
507                         if(iebuf[offset+3] <= IW_IE_KEY_MGMT_NUM)
508                                 strncat(buf, iw_ie_key_mgmt_name[iebuf[offset+3]], 256);
509                         else
510                                 strncat(buf, "unknown", 256);
511                 }
512                 offset+=4;
513         }
514         if(wpa1)
515                 add_table_entry(L, "wpa1auth", buf);
516         else
517                 add_table_entry(L, "wpa2auth", buf);
518         /* Check if we are done */
519         if(ielen < (offset + 1))
520                 return;
521 }
522
523 static inline void print_scanning_token(lua_State *L, struct stream_descr *stream,
524         struct iw_event *event, struct iwscan_state *state, struct iw_range *iw_range, int has_range)
525 {
526         char buffer[128];    /* Temporary buffer */
527
528         /* Now, let's decode the event */
529         switch(event->cmd)
530         {
531         case SIOCGIWAP:
532                 add_table_entry(L, "addr", iw_saether_ntop(&event->u.ap_addr, buffer));
533                 state->ap_num++;
534                 break;
535         case SIOCGIWFREQ:
536                 {
537                 double freq;           /* Frequency/channel */
538                 int channel = -1;       /* Converted to channel */
539                 freq = iw_freq2float(&(event->u.freq));
540                 /* Convert to channel if possible */
541                 if(has_range)
542                         channel = iw_freq_to_channel(freq, iw_range);
543                         snprintf(buffer, 128, "%1.3f", freq);
544                         add_table_entry(L, "frequency", buffer);
545                         snprintf(buffer, 128, "%d", channel);
546                         add_table_entry(L, "channel", buffer);
547                         //iw_print_freq(buffer, sizeof(buffer), freq, channel, event->u.freq.flags);
548                         //printf("                    %s\n", buffer);
549                 }
550                 break;
551         case SIOCGIWMODE:
552                 /* Note : event->u.mode is unsigned, no need to check <= 0 */
553                 if(event->u.mode >= IW_NUM_OPER_MODE)
554                         event->u.mode = IW_NUM_OPER_MODE;
555                 add_table_entry(L, "mode", iw_operation_mode[event->u.mode]);
556                 break;
557         case SIOCGIWESSID:
558                 {
559                 char essid[IW_ESSID_MAX_SIZE+1];
560                 memset(essid, '\0', sizeof(essid));
561                 if((event->u.essid.pointer) && (event->u.essid.length))
562                         memcpy(essid, event->u.essid.pointer, event->u.essid.length);
563                 if(event->u.essid.flags)
564                         add_table_entry(L, "essid", essid);
565                 else
566                         add_table_entry(L, "essid", "off/any/hidden");
567                 }
568                 break;
569         case SIOCGIWENCODE:
570                 {
571                 unsigned char   key[IW_ENCODING_TOKEN_MAX];
572                 if(event->u.data.pointer)
573                         memcpy(key, event->u.data.pointer, event->u.data.length);
574                 else
575                         event->u.data.flags |= IW_ENCODE_NOKEY;
576                 if(event->u.data.flags & IW_ENCODE_DISABLED)
577                 {
578                         add_table_entry(L, "key", "off");
579                 } else {
580                         iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
581                                 event->u.data.flags);
582                         add_table_entry(L, "key", buffer);
583                 }
584                 }
585                 break;
586         case SIOCGIWRATE:
587                 if(state->val_index == 0)
588                 {
589                         lua_pushstring(L, "bitrates");
590                         lua_newtable(L);
591                 }
592                 //iw_print_bitrate(buffer, sizeof(buffer), event->u.bitrate.value);
593                 snprintf(buffer, sizeof(buffer), "%d", event->u.bitrate.value);
594                 lua_pushinteger(L, state->val_index + 1);
595                 lua_pushstring(L, buffer);
596                 lua_settable(L, -3);
597
598                 /* Check for termination */
599                 if(stream->value == NULL)
600                 {
601                         lua_settable(L, -3);
602                         state->val_index = 0;
603                 } else
604                         state->val_index++;
605                 break;
606          case IWEVGENIE:
607                 {
608                         int offset = 0;
609                         unsigned char *buffer = event->u.data.pointer;
610                         int buflen = event->u.data.length;
611                         while(offset <= (buflen - 2))
612                         {
613                                 switch(buffer[offset])
614                                 {
615                                 case 0xdd:  /* WPA1 (and other) */
616                                 case 0x30:  /* WPA2 */
617                                         iw_print_ie_wpa(L, buffer + offset, buflen);
618                                         break;
619                                 default:
620                                         break;
621                                 }
622                                 offset += buffer[offset+1] + 2;
623                         }
624                 }
625                 break;
626         default:
627                 break;
628         }    /* switch(event->cmd) */
629 }
630
631 int iwc_scan(lua_State *L)
632 {
633         struct iwreq wrq;
634         struct iw_scan_req scanopt;        /* Options for 'set' */
635         int scanflags = 0;      /* Flags for scan */
636         unsigned char *buffer = NULL;      /* Results */
637         int buflen = IW_SCAN_MAX_DATA; /* Min for compat WE<17 */
638         struct iw_range range;
639         int has_range;
640         struct timeval tv;             /* Select timeout */
641         int timeout = 15000000;     /* 15s */
642         char *ifname;
643         if(lua_gettop(L) != 1)
644         {
645                 lua_pushstring(L, "invalid arg list");
646                 lua_error(L);
647                 return 0;
648         }
649         ifname = (char *)lua_tostring (L, 1);
650
651         /* Debugging stuff */
652         if((IW_EV_LCP_PK2_LEN != IW_EV_LCP_PK_LEN) || (IW_EV_POINT_PK2_LEN != IW_EV_POINT_PK_LEN))
653         {
654                 fprintf(stderr, "*** Please report to jt@hpl.hp.com your platform details\n");
655                 fprintf(stderr, "*** and the following line :\n");
656                 fprintf(stderr, "*** IW_EV_LCP_PK2_LEN = %zu ; IW_EV_POINT_PK2_LEN = %zu\n\n",
657                         IW_EV_LCP_PK2_LEN, IW_EV_POINT_PK2_LEN);
658         }
659
660         /* Get range stuff */
661         has_range = (iw_get_range_info(sock_iwconfig, ifname, &range) >= 0);
662
663         /* Check if the interface could support scanning. */
664         if((!has_range) || (range.we_version_compiled < 14))
665         {
666                 lua_pushstring(L, "interface does not support scanning");
667                 lua_error(L);
668                 return 0;
669         }
670
671         /* Init timeout value -> 250ms between set and first get */
672         tv.tv_sec = 0;
673         tv.tv_usec = 250000;
674
675         /* Clean up set args */
676         memset(&scanopt, 0, sizeof(scanopt));
677
678         wrq.u.data.pointer = NULL;
679         wrq.u.data.flags = 0;
680         wrq.u.data.length = 0;
681
682         /* Initiate Scanning */
683         if(iw_set_ext(sock_iwconfig, ifname, SIOCSIWSCAN, &wrq) < 0)
684         {
685                 if((errno != EPERM) || (scanflags != 0))
686                 {
687                         lua_pushstring(L, "interface does not support scanning");
688                         lua_error(L);
689                         return 0;
690                 }
691                 /* If we don't have the permission to initiate the scan, we may
692                 *        * still have permission to read left-over results.
693                 *               * But, don't wait !!! */
694                 #if 0
695                 /* Not cool, it display for non wireless interfaces... */
696                 fprintf(stderr, "%-8.16s  (Could not trigger scanning, just reading left-over results)\n", ifname);
697                 #endif
698                 tv.tv_usec = 0;
699         }
700         timeout -= tv.tv_usec;
701
702         /* Forever */
703         while(1)
704         {
705                 fd_set rfds;       /* File descriptors for select */
706                 int last_fd;    /* Last fd */
707                 int ret;
708
709                 /* Guess what ? We must re-generate rfds each time */
710                 FD_ZERO(&rfds);
711                 last_fd = -1;
712                 /* In here, add the rtnetlink fd in the list */
713
714                 /* Wait until something happens */
715                 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
716
717                 /* Check if there was an error */
718                 if(ret < 0)
719                 {
720                         if(errno == EAGAIN || errno == EINTR)
721                                 continue;
722                         lua_pushstring(L, "unhandled signal");
723                         lua_error(L);
724                         return 0;
725                 }
726
727                 /* Check if there was a timeout */
728                 if(ret == 0)
729                 {
730                         unsigned char *   newbuf;
731
732 realloc:
733                         /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
734                         newbuf = realloc(buffer, buflen);
735                         if(newbuf == NULL)
736                         {
737                                 if(buffer)
738                                         free(buffer);
739                                 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
740                                 return 0;
741                         }
742                         buffer = newbuf;
743
744                         /* Try to read the results */
745                         wrq.u.data.pointer = buffer;
746                         wrq.u.data.flags = 0;
747                         wrq.u.data.length = buflen;
748                         if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWSCAN, &wrq) < 0)
749                         {
750                                 /* Check if buffer was too small (WE-17 only) */
751                                 if((errno == E2BIG) && (range.we_version_compiled > 16))
752                                 {
753                                         /* Some driver may return very large scan results, either
754                                          * because there are many cells, or because they have many
755                                          * large elements in cells (like IWEVCUSTOM). Most will
756                                          * only need the regular sized buffer. We now use a dynamic
757                                          * allocation of the buffer to satisfy everybody. Of course,
758                                          * as we don't know in advance the size of the array, we try
759                                          * various increasing sizes. Jean II */
760
761                                         /* Check if the driver gave us any hints. */
762                                         if(wrq.u.data.length > buflen)
763                                                 buflen = wrq.u.data.length;
764                                         else
765                                                 buflen *= 2;
766
767                                         /* Try again */
768                                         goto realloc;
769                                 }
770
771                                 /* Check if results not available yet */
772                                 if(errno == EAGAIN)
773                                 {
774                                         /* Restart timer for only 100ms*/
775                                         tv.tv_sec = 0;
776                                         tv.tv_usec = 100000;
777                                         timeout -= tv.tv_usec;
778                                         if(timeout > 0)
779                                                 continue;   /* Try again later */
780                                 }
781
782                                 /* Bad error */
783                                 free(buffer);
784                                 fprintf(stderr, "%-8.16s  Failed to read scan data : %s\n\n",
785                                 ifname, strerror(errno));
786                                 return 0;
787                         } else
788                                 /* We have the results, go to process them */
789                                 break;
790                 }
791
792                 /* In here, check if event and event type
793                 *        * if scan event, read results. All errors bad & no reset timeout */
794         }
795
796         if(wrq.u.data.length)
797         {
798                 struct iw_event       iwe;
799                 struct stream_descr   stream;
800                 struct iwscan_state   state = { .ap_num = 1, .val_index = 0 };
801                 int           ret;
802                 int table = 0;
803                 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
804                 lua_newtable(L);
805                 do
806                 {
807                         /* Extract an event and print it */
808                         ret = iw_extract_event_stream(&stream, &iwe,
809                                 range.we_version_compiled);
810                         if(ret > 0)
811                         {
812                                 if(iwe.cmd == SIOCGIWAP)
813                                 {
814                                         if(table)
815                                                 lua_settable(L, -3);
816                                         table = 1;
817                                         lua_pushinteger(L, state.ap_num);
818                                         lua_newtable(L);
819                                 }
820                                 print_scanning_token(L, &stream, &iwe, &state, &range, has_range);
821                         }
822                 } while(ret > 0);
823                 lua_settable(L, -3);
824                 free(buffer);
825                 return 1;
826         }
827         free(buffer);
828         return 0;
829 }