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