707116928c2cac8d93756fdf03c2104156fd3ecd
[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 }