Import luanet library
[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 }