libiwinfo: madwifi fixes, use direct ioctl calls for vap creation, ifup and ifdown...
[project/luci.git] / contrib / package / iwinfo / src / iwinfo_lualib.c
1 /*
2  * iwinfo - Wireless Information Library - Lua Bindings
3  *
4  *   Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  * The iwinfo library is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * The iwinfo library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
17  */
18
19 #include "iwinfo_lualib.h"
20
21
22 /*
23  * ISO3166 country labels
24  */
25
26 struct iwinfo_iso3166_label ISO3166_Names[] = {
27         { 0x3030 /* 00 */, "World" },
28         { 0x4144 /* AD */, "Andorra" },
29         { 0x4145 /* AE */, "United Arab Emirates" },
30         { 0x4146 /* AF */, "Afghanistan" },
31         { 0x4147 /* AG */, "Antigua and Barbuda" },
32         { 0x4149 /* AI */, "Anguilla" },
33         { 0x414C /* AL */, "Albania" },
34         { 0x414D /* AM */, "Armenia" },
35         { 0x414E /* AN */, "Netherlands Antilles" },
36         { 0x414F /* AO */, "Angola" },
37         { 0x4151 /* AQ */, "Antarctica" },
38         { 0x4152 /* AR */, "Argentina" },
39         { 0x4153 /* AS */, "American Samoa" },
40         { 0x4154 /* AT */, "Austria" },
41         { 0x4155 /* AU */, "Australia" },
42         { 0x4157 /* AW */, "Aruba" },
43         { 0x4158 /* AX */, "Aland Islands" },
44         { 0x415A /* AZ */, "Azerbaijan" },
45         { 0x4241 /* BA */, "Bosnia and Herzegovina" },
46         { 0x4242 /* BB */, "Barbados" },
47         { 0x4244 /* BD */, "Bangladesh" },
48         { 0x4245 /* BE */, "Belgium" },
49         { 0x4246 /* BF */, "Burkina Faso" },
50         { 0x4247 /* BG */, "Bulgaria" },
51         { 0x4248 /* BH */, "Bahrain" },
52         { 0x4249 /* BI */, "Burundi" },
53         { 0x424A /* BJ */, "Benin" },
54         { 0x424C /* BL */, "Saint Barthelemy" },
55         { 0x424D /* BM */, "Bermuda" },
56         { 0x424E /* BN */, "Brunei Darussalam" },
57         { 0x424F /* BO */, "Bolivia" },
58         { 0x4252 /* BR */, "Brazil" },
59         { 0x4253 /* BS */, "Bahamas" },
60         { 0x4254 /* BT */, "Bhutan" },
61         { 0x4256 /* BV */, "Bouvet Island" },
62         { 0x4257 /* BW */, "Botswana" },
63         { 0x4259 /* BY */, "Belarus" },
64         { 0x425A /* BZ */, "Belize" },
65         { 0x4341 /* CA */, "Canada" },
66         { 0x4343 /* CC */, "Cocos (Keeling) Islands" },
67         { 0x4344 /* CD */, "Congo" },
68         { 0x4346 /* CF */, "Central African Republic" },
69         { 0x4347 /* CG */, "Congo" },
70         { 0x4348 /* CH */, "Switzerland" },
71         { 0x4349 /* CI */, "Cote d'Ivoire" },
72         { 0x434B /* CK */, "Cook Islands" },
73         { 0x434C /* CL */, "Chile" },
74         { 0x434D /* CM */, "Cameroon" },
75         { 0x434E /* CN */, "China" },
76         { 0x434F /* CO */, "Colombia" },
77         { 0x4352 /* CR */, "Costa Rica" },
78         { 0x4355 /* CU */, "Cuba" },
79         { 0x4356 /* CV */, "Cape Verde" },
80         { 0x4358 /* CX */, "Christmas Island" },
81         { 0x4359 /* CY */, "Cyprus" },
82         { 0x435A /* CZ */, "Czech Republic" },
83         { 0x4445 /* DE */, "Germany" },
84         { 0x444A /* DJ */, "Djibouti" },
85         { 0x444B /* DK */, "Denmark" },
86         { 0x444D /* DM */, "Dominica" },
87         { 0x444F /* DO */, "Dominican Republic" },
88         { 0x445A /* DZ */, "Algeria" },
89         { 0x4543 /* EC */, "Ecuador" },
90         { 0x4545 /* EE */, "Estonia" },
91         { 0x4547 /* EG */, "Egypt" },
92         { 0x4548 /* EH */, "Western Sahara" },
93         { 0x4552 /* ER */, "Eritrea" },
94         { 0x4553 /* ES */, "Spain" },
95         { 0x4554 /* ET */, "Ethiopia" },
96         { 0x4649 /* FI */, "Finland" },
97         { 0x464A /* FJ */, "Fiji" },
98         { 0x464B /* FK */, "Falkland Islands" },
99         { 0x464D /* FM */, "Micronesia" },
100         { 0x464F /* FO */, "Faroe Islands" },
101         { 0x4652 /* FR */, "France" },
102         { 0x4741 /* GA */, "Gabon" },
103         { 0x4742 /* GB */, "United Kingdom" },
104         { 0x4744 /* GD */, "Grenada" },
105         { 0x4745 /* GE */, "Georgia" },
106         { 0x4746 /* GF */, "French Guiana" },
107         { 0x4747 /* GG */, "Guernsey" },
108         { 0x4748 /* GH */, "Ghana" },
109         { 0x4749 /* GI */, "Gibraltar" },
110         { 0x474C /* GL */, "Greenland" },
111         { 0x474D /* GM */, "Gambia" },
112         { 0x474E /* GN */, "Guinea" },
113         { 0x4750 /* GP */, "Guadeloupe" },
114         { 0x4751 /* GQ */, "Equatorial Guinea" },
115         { 0x4752 /* GR */, "Greece" },
116         { 0x4753 /* GS */, "South Georgia" },
117         { 0x4754 /* GT */, "Guatemala" },
118         { 0x4755 /* GU */, "Guam" },
119         { 0x4757 /* GW */, "Guinea-Bissau" },
120         { 0x4759 /* GY */, "Guyana" },
121         { 0x484B /* HK */, "Hong Kong" },
122         { 0x484D /* HM */, "Heard and McDonald Islands" },
123         { 0x484E /* HN */, "Honduras" },
124         { 0x4852 /* HR */, "Croatia" },
125         { 0x4854 /* HT */, "Haiti" },
126         { 0x4855 /* HU */, "Hungary" },
127         { 0x4944 /* ID */, "Indonesia" },
128         { 0x4945 /* IE */, "Ireland" },
129         { 0x494C /* IL */, "Israel" },
130         { 0x494D /* IM */, "Isle of Man" },
131         { 0x494E /* IN */, "India" },
132         { 0x494F /* IO */, "Chagos Islands" },
133         { 0x4951 /* IQ */, "Iraq" },
134         { 0x4952 /* IR */, "Iran" },
135         { 0x4953 /* IS */, "Iceland" },
136         { 0x4954 /* IT */, "Italy" },
137         { 0x4A45 /* JE */, "Jersey" },
138         { 0x4A4D /* JM */, "Jamaica" },
139         { 0x4A4F /* JO */, "Jordan" },
140         { 0x4A50 /* JP */, "Japan" },
141         { 0x4B45 /* KE */, "Kenya" },
142         { 0x4B47 /* KG */, "Kyrgyzstan" },
143         { 0x4B48 /* KH */, "Cambodia" },
144         { 0x4B49 /* KI */, "Kiribati" },
145         { 0x4B4D /* KM */, "Comoros" },
146         { 0x4B4E /* KN */, "Saint Kitts and Nevis" },
147         { 0x4B50 /* KP */, "North Korea" },
148         { 0x4B52 /* KR */, "South Korea" },
149         { 0x4B57 /* KW */, "Kuwait" },
150         { 0x4B59 /* KY */, "Cayman Islands" },
151         { 0x4B5A /* KZ */, "Kazakhstan" },
152         { 0x4C41 /* LA */, "Laos" },
153         { 0x4C42 /* LB */, "Lebanon" },
154         { 0x4C43 /* LC */, "Saint Lucia" },
155         { 0x4C49 /* LI */, "Liechtenstein" },
156         { 0x4C4B /* LK */, "Sri Lanka" },
157         { 0x4C52 /* LR */, "Liberia" },
158         { 0x4C53 /* LS */, "Lesotho" },
159         { 0x4C54 /* LT */, "Lithuania" },
160         { 0x4C55 /* LU */, "Luxembourg" },
161         { 0x4C56 /* LV */, "Latvia" },
162         { 0x4C59 /* LY */, "Libyan Arab Jamahiriya" },
163         { 0x4D41 /* MA */, "Morocco" },
164         { 0x4D43 /* MC */, "Monaco" },
165         { 0x4D44 /* MD */, "Moldova" },
166         { 0x4D45 /* ME */, "Montenegro" },
167         { 0x4D46 /* MF */, "Saint Martin (French part)" },
168         { 0x4D47 /* MG */, "Madagascar" },
169         { 0x4D48 /* MH */, "Marshall Islands" },
170         { 0x4D4B /* MK */, "Macedonia" },
171         { 0x4D4C /* ML */, "Mali" },
172         { 0x4D4D /* MM */, "Myanmar" },
173         { 0x4D4E /* MN */, "Mongolia" },
174         { 0x4D4F /* MO */, "Macao" },
175         { 0x4D50 /* MP */, "Northern Mariana Islands" },
176         { 0x4D51 /* MQ */, "Martinique" },
177         { 0x4D52 /* MR */, "Mauritania" },
178         { 0x4D53 /* MS */, "Montserrat" },
179         { 0x4D54 /* MT */, "Malta" },
180         { 0x4D55 /* MU */, "Mauritius" },
181         { 0x4D56 /* MV */, "Maldives" },
182         { 0x4D57 /* MW */, "Malawi" },
183         { 0x4D58 /* MX */, "Mexico" },
184         { 0x4D59 /* MY */, "Malaysia" },
185         { 0x4D5A /* MZ */, "Mozambique" },
186         { 0x4E41 /* NA */, "Namibia" },
187         { 0x4E43 /* NC */, "New Caledonia" },
188         { 0x4E45 /* NE */, "Niger" },
189         { 0x4E46 /* NF */, "Norfolk Island" },
190         { 0x4E47 /* NG */, "Nigeria" },
191         { 0x4E49 /* NI */, "Nicaragua" },
192         { 0x4E4C /* NL */, "Netherlands" },
193         { 0x4E4F /* NO */, "Norway" },
194         { 0x4E50 /* NP */, "Nepal" },
195         { 0x4E52 /* NR */, "Nauru" },
196         { 0x4E55 /* NU */, "Niue" },
197         { 0x4E5A /* NZ */, "New Zealand" },
198         { 0x4F4D /* OM */, "Oman" },
199         { 0x5041 /* PA */, "Panama" },
200         { 0x5045 /* PE */, "Peru" },
201         { 0x5046 /* PF */, "French Polynesia" },
202         { 0x5047 /* PG */, "Papua New Guinea" },
203         { 0x5048 /* PH */, "Philippines" },
204         { 0x504B /* PK */, "Pakistan" },
205         { 0x504C /* PL */, "Poland" },
206         { 0x504D /* PM */, "Saint Pierre and Miquelon" },
207         { 0x504E /* PN */, "Pitcairn" },
208         { 0x5052 /* PR */, "Puerto Rico" },
209         { 0x5053 /* PS */, "Palestinian Territory" },
210         { 0x5054 /* PT */, "Portugal" },
211         { 0x5057 /* PW */, "Palau" },
212         { 0x5059 /* PY */, "Paraguay" },
213         { 0x5141 /* QA */, "Qatar" },
214         { 0x5245 /* RE */, "Reunion" },
215         { 0x524F /* RO */, "Romania" },
216         { 0x5253 /* RS */, "Serbia" },
217         { 0x5255 /* RU */, "Russian Federation" },
218         { 0x5257 /* RW */, "Rwanda" },
219         { 0x5341 /* SA */, "Saudi Arabia" },
220         { 0x5342 /* SB */, "Solomon Islands" },
221         { 0x5343 /* SC */, "Seychelles" },
222         { 0x5344 /* SD */, "Sudan" },
223         { 0x5345 /* SE */, "Sweden" },
224         { 0x5347 /* SG */, "Singapore" },
225         { 0x5348 /* SH */, "St. Helena and Dependencies" },
226         { 0x5349 /* SI */, "Slovenia" },
227         { 0x534A /* SJ */, "Svalbard and Jan Mayen" },
228         { 0x534B /* SK */, "Slovakia" },
229         { 0x534C /* SL */, "Sierra Leone" },
230         { 0x534D /* SM */, "San Marino" },
231         { 0x534E /* SN */, "Senegal" },
232         { 0x534F /* SO */, "Somalia" },
233         { 0x5352 /* SR */, "Suriname" },
234         { 0x5354 /* ST */, "Sao Tome and Principe" },
235         { 0x5356 /* SV */, "El Salvador" },
236         { 0x5359 /* SY */, "Syrian Arab Republic" },
237         { 0x535A /* SZ */, "Swaziland" },
238         { 0x5443 /* TC */, "Turks and Caicos Islands" },
239         { 0x5444 /* TD */, "Chad" },
240         { 0x5446 /* TF */, "French Southern Territories" },
241         { 0x5447 /* TG */, "Togo" },
242         { 0x5448 /* TH */, "Thailand" },
243         { 0x544A /* TJ */, "Tajikistan" },
244         { 0x544B /* TK */, "Tokelau" },
245         { 0x544C /* TL */, "Timor-Leste" },
246         { 0x544D /* TM */, "Turkmenistan" },
247         { 0x544E /* TN */, "Tunisia" },
248         { 0x544F /* TO */, "Tonga" },
249         { 0x5452 /* TR */, "Turkey" },
250         { 0x5454 /* TT */, "Trinidad and Tobago" },
251         { 0x5456 /* TV */, "Tuvalu" },
252         { 0x5457 /* TW */, "Taiwan" },
253         { 0x545A /* TZ */, "Tanzania" },
254         { 0x5541 /* UA */, "Ukraine" },
255         { 0x5547 /* UG */, "Uganda" },
256         { 0x554D /* UM */, "U.S. Minor Outlying Islands" },
257         { 0x5553 /* US */, "United States" },
258         { 0x5559 /* UY */, "Uruguay" },
259         { 0x555A /* UZ */, "Uzbekistan" },
260         { 0x5641 /* VA */, "Vatican City State" },
261         { 0x5643 /* VC */, "St. Vincent and Grenadines" },
262         { 0x5645 /* VE */, "Venezuela" },
263         { 0x5647 /* VG */, "Virgin Islands, British" },
264         { 0x5649 /* VI */, "Virgin Islands, U.S." },
265         { 0x564E /* VN */, "Viet Nam" },
266         { 0x5655 /* VU */, "Vanuatu" },
267         { 0x5746 /* WF */, "Wallis and Futuna" },
268         { 0x5753 /* WS */, "Samoa" },
269         { 0x5945 /* YE */, "Yemen" },
270         { 0x5954 /* YT */, "Mayotte" },
271         { 0x5A41 /* ZA */, "South Africa" },
272         { 0x5A4D /* ZM */, "Zambia" },
273         { 0x5A57 /* ZW */, "Zimbabwe" },
274         { 0,               "" }
275 };
276
277
278
279 /* Determine type */
280 static int iwinfo_L_type(lua_State *L)
281 {
282         const char *ifname = luaL_checkstring(L, 1);
283
284 #ifdef USE_NL80211
285         if( nl80211_probe(ifname) )
286                 lua_pushstring(L, "nl80211");
287         else
288 #endif
289
290 #ifdef USE_MADWIFI
291         if( madwifi_probe(ifname) )
292                 lua_pushstring(L, "madwifi");
293         else
294 #endif
295
296 #ifdef USE_WL
297         if( wl_probe(ifname) )
298                 lua_pushstring(L, "wl");
299         else
300 #endif
301
302         if( wext_probe(ifname) )
303                 lua_pushstring(L, "wext");
304
305         else
306                 lua_pushnil(L);
307
308         return 1;
309 }
310
311 /* Shutdown backends */
312 static int iwinfo_L__gc(lua_State *L)
313 {
314 #ifdef USE_WL
315         wl_close();
316 #endif
317 #ifdef USE_MADWIFI
318         madwifi_close();
319 #endif
320 #ifdef USE_NL80211
321         nl80211_close();
322 #endif
323         wext_close();
324 }
325
326 /*
327  * Build a short textual description of the crypto info
328  */
329
330 static char * iwinfo_crypto_print_ciphers(int ciphers)
331 {
332         static char str[128] = { 0 };
333         char *pos = str;
334
335         if( ciphers & IWINFO_CIPHER_WEP40 )
336                 pos += sprintf(pos, "WEP-40, ");
337
338         if( ciphers & IWINFO_CIPHER_WEP104 )
339                 pos += sprintf(pos, "WEP-104, ");
340
341         if( ciphers & IWINFO_CIPHER_TKIP )
342                 pos += sprintf(pos, "TKIP, ");
343
344         if( ciphers & IWINFO_CIPHER_CCMP )
345                 pos += sprintf(pos, "CCMP, ");
346
347         if( ciphers & IWINFO_CIPHER_WRAP )
348                 pos += sprintf(pos, "WRAP, ");
349
350         if( ciphers & IWINFO_CIPHER_AESOCB )
351                 pos += sprintf(pos, "AES-OCB, ");
352
353         if( ciphers & IWINFO_CIPHER_CKIP )
354                 pos += sprintf(pos, "CKIP, ");
355
356         if( !ciphers || (ciphers & IWINFO_CIPHER_NONE) )
357                 pos += sprintf(pos, "NONE, ");
358
359         *(pos - 2) = 0;
360
361         return str;
362 }
363
364 static char * iwinfo_crypto_print_suites(int suites)
365 {
366         static char str[64] = { 0 };
367         char *pos = str;
368
369         if( suites & IWINFO_KMGMT_PSK )
370                 pos += sprintf(pos, "PSK/");
371
372         if( suites & IWINFO_KMGMT_8021x )
373                 pos += sprintf(pos, "802.1X/");
374
375         if( !suites || (suites & IWINFO_KMGMT_NONE) )
376                 pos += sprintf(pos, "NONE/");
377
378         *(pos - 1) = 0;
379
380         return str;
381 }
382
383 static char * iwinfo_crypto_desc(struct iwinfo_crypto_entry *c)
384 {
385         static char desc[512] = { 0 };
386
387         if( c )
388         {
389                 if( c->enabled )
390                 {
391                         /* WEP */
392                         if( c->auth_algs && !c->wpa_version )
393                         {
394                                 if( (c->auth_algs & IWINFO_AUTH_OPEN) &&
395                                     (c->auth_algs & IWINFO_AUTH_SHARED) )
396                                 {
397                                         sprintf(desc, "WEP Open/Shared (%s)",
398                                                 iwinfo_crypto_print_ciphers(c->pair_ciphers));
399                                 }
400                                 else if( c->auth_algs & IWINFO_AUTH_OPEN )
401                                 {
402                                         sprintf(desc, "WEP Open System (%s)",
403                                                 iwinfo_crypto_print_ciphers(c->pair_ciphers));
404                                 }
405                                 else if( c->auth_algs & IWINFO_AUTH_SHARED )
406                                 {
407                                         sprintf(desc, "WEP Shared Auth (%s)",
408                                                 iwinfo_crypto_print_ciphers(c->pair_ciphers));
409                                 }
410                         }
411
412                         /* WPA */
413                         else if( c->wpa_version )
414                         {
415                                 switch(c->wpa_version) {
416                                         case 3:
417                                                 sprintf(desc, "mixed WPA/WPA2 %s (%s)",
418                                                         iwinfo_crypto_print_suites(c->auth_suites),
419                                                         iwinfo_crypto_print_ciphers(c->pair_ciphers));
420                                                 break;
421
422                                         case 2:
423                                                 sprintf(desc, "WPA2 %s (%s)",
424                                                         iwinfo_crypto_print_suites(c->auth_suites),
425                                                         iwinfo_crypto_print_ciphers(c->pair_ciphers));
426                                                 break;
427
428                                         case 1:
429                                                 sprintf(desc, "WPA %s (%s)",
430                                                         iwinfo_crypto_print_suites(c->auth_suites),
431                                                         iwinfo_crypto_print_ciphers(c->pair_ciphers));
432                                                 break;
433                                 }
434                         }
435                         else
436                         {
437                                 sprintf(desc, "None");
438                         }
439                 }
440                 else
441                 {
442                         sprintf(desc, "None");
443                 }
444         }
445         else
446         {
447                 sprintf(desc, "Unknown");
448         }
449
450         return desc;
451 }
452
453 /* Build Lua table from crypto data */
454 static void iwinfo_L_cryptotable(lua_State *L, struct iwinfo_crypto_entry *c)
455 {
456         int i, j;
457
458         lua_newtable(L);
459
460         lua_pushboolean(L, c->enabled);
461         lua_setfield(L, -2, "enabled");
462
463         lua_pushstring(L, iwinfo_crypto_desc(c));
464         lua_setfield(L, -2, "description");
465
466         lua_pushboolean(L, (c->enabled && !c->wpa_version));
467         lua_setfield(L, -2, "wep");
468
469         lua_pushinteger(L, c->wpa_version);
470         lua_setfield(L, -2, "wpa");
471
472         lua_newtable(L);
473         for( i = 0, j = 1; i < 8; i++ )
474         {
475                 if( c->pair_ciphers & (1 << i) )
476                 {
477                         lua_pushstring(L, IWINFO_CIPHER_NAMES[i]);
478                         lua_rawseti(L, -2, j++);
479                 }
480         }
481         lua_setfield(L, -2, "pair_ciphers");
482
483         lua_newtable(L);
484         for( i = 0, j = 1; i < 8; i++ )
485         {
486                 if( c->group_ciphers & (1 << i) )
487                 {
488                         lua_pushstring(L, IWINFO_CIPHER_NAMES[i]);
489                         lua_rawseti(L, -2, j++);
490                 }
491         }
492         lua_setfield(L, -2, "group_ciphers");
493
494         lua_newtable(L);
495         for( i = 0, j = 1; i < 8; i++ )
496         {
497                 if( c->auth_suites & (1 << i) )
498                 {
499                         lua_pushstring(L, IWINFO_KMGMT_NAMES[i]);
500                         lua_rawseti(L, -2, j++);
501                 }
502         }
503         lua_setfield(L, -2, "auth_suites");
504
505         lua_newtable(L);
506         for( i = 0, j = 1; i < 8; i++ )
507         {
508                 if( c->auth_algs & (1 << i) )
509                 {
510                         lua_pushstring(L, IWINFO_AUTH_NAMES[i]);
511                         lua_rawseti(L, -2, j++);
512                 }
513         }
514         lua_setfield(L, -2, "auth_algs");
515 }
516
517
518 /* Wrapper for assoclist */
519 static int iwinfo_L_assoclist(lua_State *L, int (*func)(const char *, char *, int *))
520 {
521         int i, len;
522         char rv[IWINFO_BUFSIZE];
523         char macstr[18];
524         const char *ifname = luaL_checkstring(L, 1);
525         struct iwinfo_assoclist_entry *e;
526
527         lua_newtable(L);
528         memset(rv, 0, sizeof(rv));
529
530         if( !(*func)(ifname, rv, &len) )
531         {
532                 for( i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry) )
533                 {
534                         e = (struct iwinfo_assoclist_entry *) &rv[i];
535
536                         sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
537                                 e->mac[0], e->mac[1], e->mac[2],
538                                 e->mac[3], e->mac[4], e->mac[5]);
539
540                         lua_newtable(L);
541
542                         lua_pushnumber(L, e->signal);
543                         lua_setfield(L, -2, "signal");
544
545                         lua_pushnumber(L, e->noise);
546                         lua_setfield(L, -2, "noise");
547
548                         lua_setfield(L, -2, macstr);
549                 }
550         }
551
552         return 1;
553 }
554
555 /* Wrapper for tx power list */
556 static int iwinfo_L_txpwrlist(lua_State *L, int (*func)(const char *, char *, int *))
557 {
558         int i, x, len;
559         char rv[IWINFO_BUFSIZE];
560         const char *ifname = luaL_checkstring(L, 1);
561         struct iwinfo_txpwrlist_entry *e;
562
563         lua_newtable(L);
564         memset(rv, 0, sizeof(rv));
565
566         if( !(*func)(ifname, rv, &len) )
567         {
568                 for( i = 0, x = 1; i < len; i += sizeof(struct iwinfo_txpwrlist_entry), x++ )
569                 {
570                         e = (struct iwinfo_txpwrlist_entry *) &rv[i];
571
572                         lua_newtable(L);
573
574                         lua_pushnumber(L, e->mw);
575                         lua_setfield(L, -2, "mw");
576
577                         lua_pushnumber(L, e->dbm);
578                         lua_setfield(L, -2, "dbm");
579
580                         lua_rawseti(L, -2, x);
581                 }
582         }
583
584         return 1;
585 }
586
587 /* Wrapper for scan list */
588 static int iwinfo_L_scanlist(lua_State *L, int (*func)(const char *, char *, int *))
589 {
590         int i, x, len;
591         char rv[IWINFO_BUFSIZE];
592         char macstr[18];
593         const char *ifname = luaL_checkstring(L, 1);
594         struct iwinfo_scanlist_entry *e;
595
596         lua_newtable(L);
597         memset(rv, 0, sizeof(rv));
598
599         if( !(*func)(ifname, rv, &len) )
600         {
601                 for( i = 0, x = 1; i < len; i += sizeof(struct iwinfo_scanlist_entry), x++ )
602                 {
603                         e = (struct iwinfo_scanlist_entry *) &rv[i];
604
605                         lua_newtable(L);
606
607                         /* BSSID */
608                         sprintf(macstr, "%02X:%02X:%02X:%02X:%02X:%02X",
609                                 e->mac[0], e->mac[1], e->mac[2],
610                                 e->mac[3], e->mac[4], e->mac[5]);
611
612                         lua_pushstring(L, macstr);
613                         lua_setfield(L, -2, "bssid");
614
615                         /* ESSID */
616                         if( e->ssid[0] )
617                         {
618                                 lua_pushstring(L, (char *) e->ssid);
619                                 lua_setfield(L, -2, "ssid");
620                         }
621
622                         /* Channel */
623                         lua_pushinteger(L, e->channel);
624                         lua_setfield(L, -2, "channel");
625
626                         /* Mode */
627                         lua_pushstring(L, (char *) e->mode);
628                         lua_setfield(L, -2, "mode");
629
630                         /* Quality, Signal */
631                         lua_pushinteger(L, e->quality);
632                         lua_setfield(L, -2, "quality");
633
634                         lua_pushinteger(L, e->quality_max);
635                         lua_setfield(L, -2, "quality_max");
636
637                         lua_pushnumber(L, (e->signal - 0x100));
638                         lua_setfield(L, -2, "signal");
639
640                         /* Crypto */
641                         iwinfo_L_cryptotable(L, &e->crypto);
642                         lua_setfield(L, -2, "encryption");
643
644                         lua_rawseti(L, -2, x);
645                 }
646         }
647
648         return 1;
649 }
650
651 /* Wrapper for frequency list */
652 static int iwinfo_L_freqlist(lua_State *L, int (*func)(const char *, char *, int *))
653 {
654         int i, x, len;
655         char rv[IWINFO_BUFSIZE];
656         const char *ifname = luaL_checkstring(L, 1);
657         struct iwinfo_freqlist_entry *e;
658
659         lua_newtable(L);
660         memset(rv, 0, sizeof(rv));
661
662         if( !(*func)(ifname, rv, &len) )
663         {
664                 for( i = 0, x = 1; i < len; i += sizeof(struct iwinfo_freqlist_entry), x++ )
665                 {
666                         e = (struct iwinfo_freqlist_entry *) &rv[i];
667
668                         lua_newtable(L);
669
670                         /* MHz */
671                         lua_pushinteger(L, e->mhz);
672                         lua_setfield(L, -2, "mhz");
673
674                         /* Channel */
675                         lua_pushinteger(L, e->channel);
676                         lua_setfield(L, -2, "channel");
677
678                         /* Restricted (DFS/TPC/Radar) */
679                         lua_pushboolean(L, e->restricted);
680                         lua_setfield(L, -2, "restricted");
681
682                         lua_rawseti(L, -2, x);
683                 }
684         }
685
686         return 1;
687 }
688
689 /* Wrapper for crypto settings */
690 static int iwinfo_L_encryption(lua_State *L, int (*func)(const char *, char *))
691 {
692         const char *ifname = luaL_checkstring(L, 1);
693         struct iwinfo_crypto_entry c = { 0 };
694
695         if( !(*func)(ifname, (char *)&c) )
696         {
697                 iwinfo_L_cryptotable(L, &c);
698                 return 1;
699         }
700
701         lua_pushnil(L);
702         return 1;
703 }
704
705 /* Wrapper for hwmode list */
706 static int iwinfo_L_hwmodelist(lua_State *L, int (*func)(const char *, int *))
707 {
708         const char *ifname = luaL_checkstring(L, 1);
709         int hwmodes = 0;
710
711         if( !(*func)(ifname, &hwmodes) )
712         {
713                 lua_newtable(L);
714
715                 lua_pushboolean(L, hwmodes & IWINFO_80211_A);
716                 lua_setfield(L, -2, "a");
717
718                 lua_pushboolean(L, hwmodes & IWINFO_80211_B);
719                 lua_setfield(L, -2, "b");
720
721                 lua_pushboolean(L, hwmodes & IWINFO_80211_G);
722                 lua_setfield(L, -2, "g");
723
724                 lua_pushboolean(L, hwmodes & IWINFO_80211_N);
725                 lua_setfield(L, -2, "n");
726
727                 return 1;
728         }
729
730         lua_pushnil(L);
731         return 1;
732 }
733
734 /* Wrapper for mbbsid_support */
735 static int iwinfo_L_mbssid_support(lua_State *L, int (*func)(const char *, int *))
736 {
737         const char *ifname = luaL_checkstring(L, 1);
738         int support = 0;
739
740         if( !(*func)(ifname, &support) )
741         {
742                 lua_pushboolean(L, support);
743                 return 1;
744         }
745
746         lua_pushnil(L);
747         return 1;
748 }
749
750 /* Wrapper for country list */
751 static char * iwinfo_L_country_lookup(char *buf, int len, int iso3166)
752 {
753         int i;
754         struct iwinfo_country_entry *c;
755
756         for( i = 0; i < len; i += sizeof(struct iwinfo_country_entry) )
757         {
758                 c = (struct iwinfo_country_entry *) &buf[i];
759
760                 if( c->iso3166 == iso3166 )
761                         return c->ccode;
762         }
763
764         return NULL;
765 }
766
767 static int iwinfo_L_countrylist(lua_State *L, int (*func)(const char *, char *, int *))
768 {
769         int len, i, j;
770         char rv[IWINFO_BUFSIZE], alpha2[3];
771         char *ccode;
772         const char *ifname = luaL_checkstring(L, 1);
773         struct iwinfo_iso3166_label *l;
774
775         lua_newtable(L);
776         memset(rv, 0, sizeof(rv));
777
778         if( !(*func)(ifname, rv, &len) )
779         {
780                 for( l = ISO3166_Names, j = 1; l->iso3166; l++ )
781                 {
782                         if( (ccode = iwinfo_L_country_lookup(rv, len, l->iso3166)) != NULL )
783                         {
784                                 sprintf(alpha2, "%c%c",
785                                         (l->iso3166 / 256), (l->iso3166 % 256));
786
787                                 lua_newtable(L);
788
789                                 lua_pushstring(L, alpha2);
790                                 lua_setfield(L, -2, "alpha2");
791
792                                 lua_pushstring(L, ccode);
793                                 lua_setfield(L, -2, "ccode");
794
795                                 lua_pushstring(L, l->name);
796                                 lua_setfield(L, -2, "name");
797
798                                 lua_rawseti(L, -2, j++);
799                         }
800                 }
801         }
802
803         return 1;
804 }
805
806
807 #ifdef USE_WL
808 /* Broadcom */
809 LUA_WRAP_INT(wl,channel)
810 LUA_WRAP_INT(wl,frequency)
811 LUA_WRAP_INT(wl,txpower)
812 LUA_WRAP_INT(wl,bitrate)
813 LUA_WRAP_INT(wl,signal)
814 LUA_WRAP_INT(wl,noise)
815 LUA_WRAP_INT(wl,quality)
816 LUA_WRAP_INT(wl,quality_max)
817 LUA_WRAP_STRING(wl,mode)
818 LUA_WRAP_STRING(wl,ssid)
819 LUA_WRAP_STRING(wl,bssid)
820 LUA_WRAP_STRING(wl,country)
821 LUA_WRAP_LIST(wl,assoclist)
822 LUA_WRAP_LIST(wl,txpwrlist)
823 LUA_WRAP_LIST(wl,scanlist)
824 LUA_WRAP_LIST(wl,freqlist)
825 LUA_WRAP_LIST(wl,countrylist)
826 LUA_WRAP_LIST(wl,hwmodelist)
827 LUA_WRAP_LIST(wl,encryption)
828 LUA_WRAP_LIST(wl,mbssid_support)
829 #endif
830
831 #ifdef USE_MADWIFI
832 /* Madwifi */
833 LUA_WRAP_INT(madwifi,channel)
834 LUA_WRAP_INT(madwifi,frequency)
835 LUA_WRAP_INT(madwifi,txpower)
836 LUA_WRAP_INT(madwifi,bitrate)
837 LUA_WRAP_INT(madwifi,signal)
838 LUA_WRAP_INT(madwifi,noise)
839 LUA_WRAP_INT(madwifi,quality)
840 LUA_WRAP_INT(madwifi,quality_max)
841 LUA_WRAP_STRING(madwifi,mode)
842 LUA_WRAP_STRING(madwifi,ssid)
843 LUA_WRAP_STRING(madwifi,bssid)
844 LUA_WRAP_STRING(madwifi,country)
845 LUA_WRAP_LIST(madwifi,assoclist)
846 LUA_WRAP_LIST(madwifi,txpwrlist)
847 LUA_WRAP_LIST(madwifi,scanlist)
848 LUA_WRAP_LIST(madwifi,freqlist)
849 LUA_WRAP_LIST(madwifi,countrylist)
850 LUA_WRAP_LIST(madwifi,hwmodelist)
851 LUA_WRAP_LIST(madwifi,encryption)
852 LUA_WRAP_LIST(madwifi,mbssid_support)
853 #endif
854
855 #ifdef USE_NL80211
856 /* NL80211 */
857 LUA_WRAP_INT(nl80211,channel)
858 LUA_WRAP_INT(nl80211,frequency)
859 LUA_WRAP_INT(nl80211,txpower)
860 LUA_WRAP_INT(nl80211,bitrate)
861 LUA_WRAP_INT(nl80211,signal)
862 LUA_WRAP_INT(nl80211,noise)
863 LUA_WRAP_INT(nl80211,quality)
864 LUA_WRAP_INT(nl80211,quality_max)
865 LUA_WRAP_STRING(nl80211,mode)
866 LUA_WRAP_STRING(nl80211,ssid)
867 LUA_WRAP_STRING(nl80211,bssid)
868 LUA_WRAP_STRING(nl80211,country)
869 LUA_WRAP_LIST(nl80211,assoclist)
870 LUA_WRAP_LIST(nl80211,txpwrlist)
871 LUA_WRAP_LIST(nl80211,scanlist)
872 LUA_WRAP_LIST(nl80211,freqlist)
873 LUA_WRAP_LIST(nl80211,countrylist)
874 LUA_WRAP_LIST(nl80211,hwmodelist)
875 LUA_WRAP_LIST(nl80211,encryption)
876 LUA_WRAP_LIST(nl80211,mbssid_support)
877 #endif
878
879 /* Wext */
880 LUA_WRAP_INT(wext,channel)
881 LUA_WRAP_INT(wext,frequency)
882 LUA_WRAP_INT(wext,txpower)
883 LUA_WRAP_INT(wext,bitrate)
884 LUA_WRAP_INT(wext,signal)
885 LUA_WRAP_INT(wext,noise)
886 LUA_WRAP_INT(wext,quality)
887 LUA_WRAP_INT(wext,quality_max)
888 LUA_WRAP_STRING(wext,mode)
889 LUA_WRAP_STRING(wext,ssid)
890 LUA_WRAP_STRING(wext,bssid)
891 LUA_WRAP_STRING(wext,country)
892 LUA_WRAP_LIST(wext,assoclist)
893 LUA_WRAP_LIST(wext,txpwrlist)
894 LUA_WRAP_LIST(wext,scanlist)
895 LUA_WRAP_LIST(wext,freqlist)
896 LUA_WRAP_LIST(wext,countrylist)
897 LUA_WRAP_LIST(wext,hwmodelist)
898 LUA_WRAP_LIST(wext,encryption)
899 LUA_WRAP_LIST(wext,mbssid_support)
900
901 #ifdef USE_WL
902 /* Broadcom table */
903 static const luaL_reg R_wl[] = {
904         LUA_REG(wl,channel),
905         LUA_REG(wl,frequency),
906         LUA_REG(wl,txpower),
907         LUA_REG(wl,bitrate),
908         LUA_REG(wl,signal),
909         LUA_REG(wl,noise),
910         LUA_REG(wl,quality),
911         LUA_REG(wl,quality_max),
912         LUA_REG(wl,mode),
913         LUA_REG(wl,ssid),
914         LUA_REG(wl,bssid),
915         LUA_REG(wl,country),
916         LUA_REG(wl,assoclist),
917         LUA_REG(wl,txpwrlist),
918         LUA_REG(wl,scanlist),
919         LUA_REG(wl,freqlist),
920         LUA_REG(wl,countrylist),
921         LUA_REG(wl,hwmodelist),
922         LUA_REG(wl,encryption),
923         LUA_REG(wl,mbssid_support),
924         { NULL, NULL }
925 };
926 #endif
927
928 #ifdef USE_MADWIFI
929 /* Madwifi table */
930 static const luaL_reg R_madwifi[] = {
931         LUA_REG(madwifi,channel),
932         LUA_REG(madwifi,frequency),
933         LUA_REG(madwifi,txpower),
934         LUA_REG(madwifi,bitrate),
935         LUA_REG(madwifi,signal),
936         LUA_REG(madwifi,noise),
937         LUA_REG(madwifi,quality),
938         LUA_REG(madwifi,quality_max),
939         LUA_REG(madwifi,mode),
940         LUA_REG(madwifi,ssid),
941         LUA_REG(madwifi,bssid),
942         LUA_REG(madwifi,country),
943         LUA_REG(madwifi,assoclist),
944         LUA_REG(madwifi,txpwrlist),
945         LUA_REG(madwifi,scanlist),
946         LUA_REG(madwifi,freqlist),
947         LUA_REG(madwifi,countrylist),
948         LUA_REG(madwifi,hwmodelist),
949         LUA_REG(madwifi,encryption),
950         LUA_REG(madwifi,mbssid_support),
951         { NULL, NULL }
952 };
953 #endif
954
955 #ifdef USE_NL80211
956 /* NL80211 table */
957 static const luaL_reg R_nl80211[] = {
958         LUA_REG(nl80211,channel),
959         LUA_REG(nl80211,frequency),
960         LUA_REG(nl80211,txpower),
961         LUA_REG(nl80211,bitrate),
962         LUA_REG(nl80211,signal),
963         LUA_REG(nl80211,noise),
964         LUA_REG(nl80211,quality),
965         LUA_REG(nl80211,quality_max),
966         LUA_REG(nl80211,mode),
967         LUA_REG(nl80211,ssid),
968         LUA_REG(nl80211,bssid),
969         LUA_REG(nl80211,country),
970         LUA_REG(nl80211,assoclist),
971         LUA_REG(nl80211,txpwrlist),
972         LUA_REG(nl80211,scanlist),
973         LUA_REG(nl80211,freqlist),
974         LUA_REG(nl80211,countrylist),
975         LUA_REG(nl80211,hwmodelist),
976         LUA_REG(nl80211,encryption),
977         LUA_REG(nl80211,mbssid_support),
978         { NULL, NULL }
979 };
980 #endif
981
982 /* Wext table */
983 static const luaL_reg R_wext[] = {
984         LUA_REG(wext,channel),
985         LUA_REG(wext,frequency),
986         LUA_REG(wext,txpower),
987         LUA_REG(wext,bitrate),
988         LUA_REG(wext,signal),
989         LUA_REG(wext,noise),
990         LUA_REG(wext,quality),
991         LUA_REG(wext,quality_max),
992         LUA_REG(wext,mode),
993         LUA_REG(wext,ssid),
994         LUA_REG(wext,bssid),
995         LUA_REG(wext,country),
996         LUA_REG(wext,assoclist),
997         LUA_REG(wext,txpwrlist),
998         LUA_REG(wext,scanlist),
999         LUA_REG(wext,freqlist),
1000         LUA_REG(wext,countrylist),
1001         LUA_REG(wext,hwmodelist),
1002         LUA_REG(wext,encryption),
1003         LUA_REG(wext,mbssid_support),
1004         { NULL, NULL }
1005 };
1006
1007 /* Common */
1008 static const luaL_reg R_common[] = {
1009         { "type", iwinfo_L_type },
1010         { "__gc", iwinfo_L__gc  },
1011         { NULL, NULL }
1012 };
1013
1014
1015 LUALIB_API int luaopen_iwinfo(lua_State *L) {
1016         luaL_register(L, IWINFO_META, R_common);
1017
1018 #ifdef USE_WL
1019         luaL_newmetatable(L, IWINFO_WL_META);
1020         luaL_register(L, NULL, R_wl);
1021         lua_pushvalue(L, -1);
1022         lua_setfield(L, -2, "__index");
1023         lua_setfield(L, -2, "wl");
1024 #endif
1025
1026 #ifdef USE_MADWIFI
1027         luaL_newmetatable(L, IWINFO_MADWIFI_META);
1028         luaL_register(L, NULL, R_madwifi);
1029         lua_pushvalue(L, -1);
1030         lua_setfield(L, -2, "__index");
1031         lua_setfield(L, -2, "madwifi");
1032 #endif
1033
1034 #ifdef USE_NL80211
1035         luaL_newmetatable(L, IWINFO_NL80211_META);
1036         luaL_register(L, NULL, R_nl80211);
1037         lua_pushvalue(L, -1);
1038         lua_setfield(L, -2, "__index");
1039         lua_setfield(L, -2, "nl80211");
1040 #endif
1041
1042         luaL_newmetatable(L, IWINFO_WEXT_META);
1043         luaL_register(L, NULL, R_wext);
1044         lua_pushvalue(L, -1);
1045         lua_setfield(L, -2, "__index");
1046         lua_setfield(L, -2, "wext");
1047
1048         return 1;
1049 }