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
6 * http://www.apache.org/licenses/LICENSE-2.0
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.
14 * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
15 * Copyright (C) 2008 Steven Barth <steven@midlink.org>
19 #include <net/if_arp.h>
20 #include <net/route.h>
24 #include <linux/sockios.h>
33 static int sock_iwconfig = 0;
35 typedef struct iwscan_state
38 int ap_num; /* Access Point number 1->N */
39 int val_index; /* Value in table 0->(N-1) */
45 sock_iwconfig = iw_sockets_open();
49 void iwc_shutdown(void)
53 iw_sockets_close(sock_iwconfig);
57 /* taken from wireless tools */
59 get_info(char * ifname, struct wireless_info * info)
63 memset((char*) info, 0, sizeof(struct wireless_info));
65 /* Get basic information */
66 if(iw_get_basic_config(sock_iwconfig, ifname, &(info->b)) < 0)
68 /* If no wireless name : no wireless extensions */
69 /* But let's check if the interface exists at all */
72 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
73 if(ioctl(sock_iwconfig, SIOCGIFFLAGS, &ifr) < 0)
80 if(iw_get_range_info(sock_iwconfig, ifname, &(info->range)) >= 0)
84 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWAP, &wrq) >= 0)
86 info->has_ap_addr = 1;
87 memcpy(&(info->ap_addr), &(wrq.u.ap_addr), sizeof (sockaddr));
91 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRATE, &wrq) >= 0)
93 info->has_bitrate = 1;
94 memcpy(&(info->bitrate), &(wrq.u.bitrate), sizeof(iwparam));
97 /* Get Power Management settings */
98 wrq.u.power.flags = 0;
99 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWPOWER, &wrq) >= 0)
102 memcpy(&(info->power), &(wrq.u.power), sizeof(iwparam));
106 if(iw_get_stats(sock_iwconfig, ifname, &(info->stats),
107 &info->range, info->has_range) >= 0)
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;
120 if((info->has_range) && (info->range.we_version_compiled > 9))
122 /* Get Transmit Power */
123 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWTXPOW, &wrq) >= 0)
125 info->has_txpower = 1;
126 memcpy(&(info->txpower), &(wrq.u.txpower), sizeof(iwparam));
130 /* Get sensitivity */
131 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWSENS, &wrq) >= 0)
134 memcpy(&(info->sens), &(wrq.u.sens), sizeof(iwparam));
137 if((info->has_range) && (info->range.we_version_compiled > 10))
139 /* Get retry limit/lifetime */
140 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRETRY, &wrq) >= 0)
143 memcpy(&(info->retry), &(wrq.u.retry), sizeof(iwparam));
147 /* Get RTS threshold */
148 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWRTS, &wrq) >= 0)
151 memcpy(&(info->rts), &(wrq.u.rts), sizeof(iwparam));
154 /* Get fragmentation threshold */
155 if(iw_get_ext(sock_iwconfig, ifname, SIOCGIWFRAG, &wrq) >= 0)
158 memcpy(&(info->frag), &(wrq.u.frag), sizeof(iwparam));
164 void iwc_get(lua_State *L, char *ifname)
166 struct wireless_info info;
167 int rc = get_info(ifname, &info);
172 lua_pushstring(L, ifname);
178 add_table_entry(L, "essid", info.b.essid);
180 add_table_entry(L, "essid", "off");
184 add_table_entry(L, "mode", iw_operation_mode[info.b.mode]);
188 double freq = info.b.freq; /* Frequency/channel */
189 int channel = -1; /* Converted to channel */
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);
200 add_table_entry(L, "macap", iw_sawap_ntop(&info.ap_addr, buffer));
204 iw_print_bitrate(buffer, sizeof(buffer), info.bitrate.value);
205 add_table_entry(L, "bitrate", buffer);
210 iw_print_txpower(buffer, sizeof(buffer), &info.txpower);
211 add_table_entry(L, "txpower", buffer);
216 int iwc_getall(lua_State *L)
221 fp = fopen("/proc/net/wireless", "r");
224 fgets(buffer, 128, fp);
225 fgets(buffer, 128, fp);
227 while(fgets(buffer, 128, fp))
241 /* taken from wireless tools */
242 int iwc_set_essid(lua_State *L)
246 char essid[IW_ESSID_MAX_SIZE + 1];
247 int we_kernel_version;
249 if(lua_gettop(L) != 2)
251 lua_pushstring(L, "invalid arg list");
255 ifname = (char *)lua_tostring (L, 1);
256 e = (char *)lua_tostring (L, 2);
258 if((!strcasecmp(e, "off")) | (!strcasecmp(e, "any")))
260 wrq.u.essid.flags = 0;
262 } else if(!strcasecmp(e, "on"))
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)
271 wrq.u.essid.flags = 1;
273 wrq.u.essid.flags = 1;
274 strcpy(essid, e); /* Size checked, all clear */
278 /* Get version from kernel, device may not have range... */
279 we_kernel_version = iw_get_kernel_we_version();
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++;
287 if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWESSID, &wrq))
288 lua_pushboolean(L, 1);
290 lua_pushboolean(L, 0);
294 /* taken from wireless tools */
295 int iwc_set_mode(lua_State *L)
298 unsigned int k; /* Must be unsigned */
301 if(lua_gettop(L) != 2)
303 lua_pushstring(L, "invalid arg list");
307 ifname = (char *)lua_tostring (L, 1);
308 mode = (char *)lua_tostring (L, 2);
310 /* Check if it is a uint, otherwise get is as a string */
311 if(sscanf(mode, "%ui", &k) != 1)
314 while((k < IW_NUM_OPER_MODE) && strncasecmp(mode, iw_operation_mode[k], 3))
317 if(k >= IW_NUM_OPER_MODE)
321 if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWMODE, &wrq))
322 lua_pushboolean(L, 1);
324 lua_pushboolean(L, 0);
328 int iwc_set_channel(lua_State *L)
333 if(lua_gettop(L) != 2)
335 lua_pushstring(L, "invalid arg list");
339 ifname = (char *)lua_tostring (L, 1);
340 channel = (int)lua_tointeger(L, 2);
346 wrq.u.freq.flags = 0;
348 iw_float2freq(channel, &wrq.u.freq);
349 wrq.u.freq.flags = IW_FREQ_FIXED;
351 if(!iw_set_ext(sock_iwconfig, ifname, SIOCSIWFREQ, &wrq))
352 lua_pushboolean(L, 1);
354 lua_pushboolean(L, 0);
358 static const char * iw_ie_cypher_name[] = {
366 #define IW_ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0]))
367 #define IW_IE_CYPHER_NUM IW_ARRAY_LEN(iw_ie_cypher_name)
369 static const char * iw_ie_key_mgmt_name[] = {
374 #define IW_IE_KEY_MGMT_NUM IW_ARRAY_LEN(iw_ie_key_mgmt_name)
376 static inline void iw_print_ie_wpa(lua_State *L, unsigned char * iebuf, int buflen)
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;
386 int wpa1 = 0, wpa2 = 0;
393 case 0x30: /* WPA2 */
394 /* Check if we have enough data */
400 case 0xdd: /* WPA or else */
402 /* Not all IEs that start with 0xdd are WPA.
403 * * So check that the OUI is valid. */
405 || ((memcmp(&iebuf[offset], wpa_oui, 3) != 0)
406 && (iebuf[offset+3] == 0x01)))
418 /* Pick version number (little endian) */
419 ver = iebuf[offset] | (iebuf[offset + 1] << 8);
427 if(ielen < (offset + 4))
431 add_table_entry(L, "wpa1gcipher", "TKIP");
432 add_table_entry(L, "wpa1pcipher", "TKIP");
434 add_table_entry(L, "wpa2gcipher", "TKIP");
435 add_table_entry(L, "wpa2pcipher", "TKIP");
440 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
443 add_table_entry(L, "wpa1gcipher", "Proprietary");
445 add_table_entry(L, "wpa2gcipher", "Proprietary");
448 add_table_entry(L, "wpa1gcipher", iebuf[offset+3][iw_ie_cypher_name]);
450 add_table_entry(L, "wpa2gcipher", iebuf[offset+3][iw_ie_cypher_name]);
454 if(ielen < (offset + 2))
457 add_table_entry(L, "wpa1pcipher", "TKIP");
459 add_table_entry(L, "wpa2pcipher", "TKIP");
462 /* Otherwise, we have some number of pairwise ciphers. */
463 cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
465 if(ielen < (offset + 4*cnt))
468 for(i = 0; i < cnt; i++)
471 strncat(buf, " ", 256);
472 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
474 strncat(buf, "Proprietary", 256);
476 if(iebuf[offset+3] <= IW_IE_CYPHER_NUM)
477 strncat(buf, iw_ie_cypher_name[iebuf[offset+3]], 256);
479 strncat(buf, "unknown", 256);
484 add_table_entry(L, "wpa1pcipher", buf);
486 add_table_entry(L, "wpa2pcipher", buf);
488 /* Check if we are done */
489 if(ielen < (offset + 2))
492 /* Now, we have authentication suites. */
493 cnt = iebuf[offset] | (iebuf[offset + 1] << 8);
496 if(ielen < (offset + 4*cnt))
499 for(i = 0; i < cnt; i++)
502 strncat(buf, " ", 256);
503 if(memcmp(&iebuf[offset], wpa_oui, 3) != 0)
505 strncat(buf, "Proprietary", 256);
507 if(iebuf[offset+3] <= IW_IE_KEY_MGMT_NUM)
508 strncat(buf, iw_ie_key_mgmt_name[iebuf[offset+3]], 256);
510 strncat(buf, "unknown", 256);
515 add_table_entry(L, "wpa1auth", buf);
517 add_table_entry(L, "wpa2auth", buf);
518 /* Check if we are done */
519 if(ielen < (offset + 1))
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)
526 char buffer[128]; /* Temporary buffer */
528 /* Now, let's decode the event */
532 add_table_entry(L, "addr", iw_saether_ntop(&event->u.ap_addr, buffer));
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 */
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);
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]);
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);
566 add_table_entry(L, "essid", "off/any/hidden");
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);
575 event->u.data.flags |= IW_ENCODE_NOKEY;
576 if(event->u.data.flags & IW_ENCODE_DISABLED)
578 add_table_entry(L, "key", "off");
580 iw_print_key(buffer, sizeof(buffer), key, event->u.data.length,
581 event->u.data.flags);
582 add_table_entry(L, "key", buffer);
587 if(state->val_index == 0)
589 lua_pushstring(L, "bitrates");
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);
598 /* Check for termination */
599 if(stream->value == NULL)
602 state->val_index = 0;
609 unsigned char *buffer = event->u.data.pointer;
610 int buflen = event->u.data.length;
611 while(offset <= (buflen - 2))
613 switch(buffer[offset])
615 case 0xdd: /* WPA1 (and other) */
616 case 0x30: /* WPA2 */
617 iw_print_ie_wpa(L, buffer + offset, buflen);
622 offset += buffer[offset+1] + 2;
628 } /* switch(event->cmd) */
631 int iwc_scan(lua_State *L)
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;
640 struct timeval tv; /* Select timeout */
641 int timeout = 15000000; /* 15s */
643 if(lua_gettop(L) != 1)
645 lua_pushstring(L, "invalid arg list");
649 ifname = (char *)lua_tostring (L, 1);
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))
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);
660 /* Get range stuff */
661 has_range = (iw_get_range_info(sock_iwconfig, ifname, &range) >= 0);
663 /* Check if the interface could support scanning. */
664 if((!has_range) || (range.we_version_compiled < 14))
666 lua_pushstring(L, "interface does not support scanning");
671 /* Init timeout value -> 250ms between set and first get */
675 /* Clean up set args */
676 memset(&scanopt, 0, sizeof(scanopt));
678 wrq.u.data.pointer = NULL;
679 wrq.u.data.flags = 0;
680 wrq.u.data.length = 0;
682 /* Initiate Scanning */
683 if(iw_set_ext(sock_iwconfig, ifname, SIOCSIWSCAN, &wrq) < 0)
685 if((errno != EPERM) || (scanflags != 0))
687 lua_pushstring(L, "interface does not support scanning");
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 !!! */
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);
700 timeout -= tv.tv_usec;
705 fd_set rfds; /* File descriptors for select */
706 int last_fd; /* Last fd */
709 /* Guess what ? We must re-generate rfds each time */
712 /* In here, add the rtnetlink fd in the list */
714 /* Wait until something happens */
715 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
717 /* Check if there was an error */
720 if(errno == EAGAIN || errno == EINTR)
722 lua_pushstring(L, "unhandled signal");
727 /* Check if there was a timeout */
730 unsigned char * newbuf;
733 /* (Re)allocate the buffer - realloc(NULL, len) == malloc(len) */
734 newbuf = realloc(buffer, buflen);
739 fprintf(stderr, "%s: Allocation failed\n", __FUNCTION__);
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)
750 /* Check if buffer was too small (WE-17 only) */
751 if((errno == E2BIG) && (range.we_version_compiled > 16))
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 */
761 /* Check if the driver gave us any hints. */
762 if(wrq.u.data.length > buflen)
763 buflen = wrq.u.data.length;
771 /* Check if results not available yet */
774 /* Restart timer for only 100ms*/
777 timeout -= tv.tv_usec;
779 continue; /* Try again later */
784 fprintf(stderr, "%-8.16s Failed to read scan data : %s\n\n",
785 ifname, strerror(errno));
788 /* We have the results, go to process them */
792 /* In here, check if event and event type
793 * * if scan event, read results. All errors bad & no reset timeout */
796 if(wrq.u.data.length)
799 struct stream_descr stream;
800 struct iwscan_state state = { .ap_num = 1, .val_index = 0 };
803 iw_init_event_stream(&stream, (char *) buffer, wrq.u.data.length);
807 /* Extract an event and print it */
808 ret = iw_extract_event_stream(&stream, &iwe,
809 range.we_version_compiled);
812 if(iwe.cmd == SIOCGIWAP)
817 lua_pushinteger(L, state.ap_num);
820 print_scanning_token(L, &stream, &iwe, &state, &range, has_range);