]> git.decadent.org.uk Git - ap-utils.git/blob - lib/aps.c
f2c99d7f1cbe5ab680f21c4d61e8eca3725c36fb
[ap-utils.git] / lib / aps.c
1 /*
2  *      aps.c from Access Point SNMP Utils for Linux
3  *
4  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License Version 2 from
8  * June 1991 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include "ap-utils.h"
28 #include "ap-curses.h"
29
30 extern WINDOW *main_sub/*, *win_for_menu*/;
31 extern short ap_type;
32 extern int sockfd, atmel410_filter;
33 extern struct in_addr ap_ip;
34
35 int ap_viewtype = 1;
36
37 void APs()
38 {
39     /*
40      * Structure of single record in the KnownAP table.
41      */
42     struct ap {
43         unsigned char mac[6];
44         unsigned char q1;
45         unsigned char q2;
46         unsigned char channel;
47         unsigned char x2;
48         unsigned char options;
49         unsigned char x3[5];
50         unsigned char essid[32];
51     } *app = NULL;
52
53     /*
54      * Structure used to preserve important values of AP records learnt
55      * by KnownAP scan. Used to connect to a specific AP.
56      */
57     struct known_ap {
58         char mac[6];
59         int essid_len;
60         char channel;
61         char essid[32];
62         enum { Infrastructure, AdHoc } nettype;
63     } ap[16];
64
65     /* this one is ATMEL12350 specific */
66     char SiteSurveyCommand[] = {
67         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x01, 0x07, 0x00
68     };
69
70     char bridgeOperationalMode[] = {
71         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
72     };
73     char bridgeRemoteBridgeBSSID[] = {
74         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x02, 0x00
75     };
76
77     char operChannelID[] = {
78         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x01, 0x01, 0x00
79     };
80     char operESSIDLength[] = {
81         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x01, 0x02, 0x00
82     };
83     char operESSID[] = {
84         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x01, 0x03, 0x00
85     };
86     char KnownAP[] = {
87         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x07, 0x01, 0x00
88     };
89
90     char value[] = "", c, bridge_mode;
91     char essid[33], bssid[13], message[65];
92     int i, j, errno, aps_num = 0, needs_opmode_restore = 0;
93     varbind varbinds[4];
94    
95    if (ap_type == ATMEL12350) {
96         operESSIDLength[5] = 0xE0;
97         operESSIDLength[6] = 0x3E;
98         operESSID[5] = 0xE0;
99         operESSID[6] = 0x3E;
100         operChannelID[5] = 0xE0;
101         operChannelID[6] = 0x3E;
102         KnownAP[5] = 0xE0;
103         KnownAP[6] = 0x3E;
104         bridgeOperationalMode[5] = 0xE0;
105         bridgeOperationalMode[6] = 0x3E;
106         bridgeRemoteBridgeBSSID[5] = 0xE0;
107         bridgeRemoteBridgeBSSID[6] = 0x3E;
108     }
109
110     noecho();
111     print_help(WAIT_RET);
112
113     varbinds[0].oid = bridgeOperationalMode;
114     varbinds[0].len_oid = sizeof(bridgeOperationalMode);
115     varbinds[0].value = bridgeOperationalMode;
116     varbinds[0].len_val = 0;
117     varbinds[0].type = NULL_VALUE;
118     if (snmp(varbinds, 1, GET) <= 0) {
119         print_helperr(ERR_RET);
120         goto exit;
121     }
122     bridge_mode = *(varbinds[0].value);
123
124     /* ATMEL410 firmware KnownAP scan is active in AP Client mode only */
125     if (ap_type == ATMEL410 && bridge_mode != 3) {
126         mvwaddstr(main_sub, 3, 1,
127             _
128             ("Your Access Point is not in \"AP client\" mode => getting"));
129         mvwaddstr(main_sub, 4, 1,
130             _
131             ("up-to-date \"Known APs\" info requires your AP to be"));
132         mvwaddstr(main_sub, 5, 1,
133             _
134             ("temporarily configured into \"AP client\" mode and rebooted."));
135         mvwaddstr(main_sub, 6, 1,
136             _
137             ("Your AP will be reconfigured back to original mode by this"));
138         mvwaddstr(main_sub, 7, 1,
139             _
140             ("utility once you quit the \"KnownAP\" view. This, in turn, may"));
141         mvwaddstr(main_sub, 8, 1,
142             _
143             ("cause loss of Access Point's current configuration."));
144         wattrset(main_sub, A_BOLD);
145         mvwaddstr(main_sub, 9, 1,
146             _
147             ("Do NOT answer \"Yes\" if you're connected to the Access Point"));
148         mvwaddstr(main_sub, 10, 1,
149             _
150             ("via its wireless port."));
151         wattrset(main_sub, A_NORMAL);
152         mvwaddstr(main_sub, 12, 20, _("Do you want to continue? "));
153         wrefresh(main_sub);
154         print_help(_("(Y - Yes; N - No (it's safer to answer No)"));
155         i = 1;
156         while (i)
157             switch (getch()) {
158             case 'Y':
159             case 'y':
160                 clear_main(3);
161                 i = 0;
162                 break;
163             case 'n':
164             case 'N':
165                 goto quit;
166             }
167
168         needs_opmode_restore = 1;
169         print_help(WAIT_RET);
170         varbinds[0].oid = bridgeOperationalMode;
171         varbinds[0].len_oid = sizeof(bridgeOperationalMode);
172         varbinds[0].type = INT_VALUE;
173         c = 3;
174         varbinds[0].value = &c;
175         varbinds[0].len_val = 1;
176         if (snmp(varbinds, 1, SET) <= 0) {
177             print_helperr(ERR_RET);
178             goto exit;
179         }
180
181         if (SysUpload()) {
182             print_helperr(ERR_RET);
183             goto restore_before_exit;
184         }
185         sleep(7);
186     }
187
188 get_stats:
189     varbinds[0].oid = KnownAP;
190     varbinds[0].len_oid = sizeof(KnownAP);
191     varbinds[0].type = NULL_VALUE;
192     varbinds[0].value = value;
193     varbinds[0].len_val = sizeof(value);
194
195     if (snmp(varbinds, 1, GET) <= 0) {
196         print_helperr(ERR_RET);
197         goto restore_before_exit;
198     }
199
200
201 show_stats:
202     print_title(_("Known Access Points"));
203     message[0] = ap_viewtype + '0';
204     message[1] = '\0';
205     print_viewtype(message);
206
207     /* display column info in main_sub */
208     mvwin(main_sub, 0, 0);
209     wattrset(main_sub, COLOR_PAIR(3));
210     for (i = 0; i < 64; i++)
211         waddch(main_sub, ' ');
212     switch (ap_viewtype) {
213         case 1:
214         case 2:
215             mvwaddstr(main_sub, 0, 0, "#");
216             mvwaddstr(main_sub, 0, 2, "ESSID");
217             mvwaddstr(main_sub, 0, 18, "BSSID (MAC)");
218             mvwaddstr(main_sub, 0, 31, "CN");
219             mvwaddstr(main_sub, 0, 34, _("NetworkType"));
220             mvwaddstr(main_sub, 0, 49, "P");
221             mvwaddstr(main_sub, 0, 51, "WEP");
222             mvwaddstr(main_sub, 0, 55, "RSSI");
223             if (ap_type == ATMEL410) mvwaddstr(main_sub, 0, 62, "LQ");
224             break;
225         case 3:
226             mvwaddstr(main_sub, 0, 0, "#");
227             mvwaddstr(main_sub, 0, 2, "ESSID");
228             mvwaddstr(main_sub, 0, 35, "BSSID (MAC)");
229             mvwaddstr(main_sub, 0, 48, "CN");
230             mvwaddstr(main_sub, 0, 51, "P");
231             mvwaddstr(main_sub, 0, 53, "WEP");
232             mvwaddstr(main_sub, 0, 57, "RSSI");
233             if (ap_type == ATMEL410) mvwaddstr(main_sub, 0, 62, "LQ");
234             break;
235         case 4:
236             mvwaddstr(main_sub, 0, 0, "#");
237             mvwaddstr(main_sub, 0, 2, "BSSID (MAC)");
238             mvwaddstr(main_sub, 0, 15, "Manufacturer OUI");
239             break;
240     }
241     wattrset(main_sub, A_NORMAL);
242
243     /* main loop */
244     i = aps_num = 0;
245     while (1) {
246         app = (struct ap *) &varbinds[0].value[i];
247
248         j = app->mac[0] | app->mac[1] | app->mac[2] |
249             app->mac[3] | app->mac[4] | app->mac[5];
250
251         if (!app->channel || app->channel>14 || app->mac[0] == 0xFF
252             || j == 0 || aps_num == 16)
253             break;
254
255         i += sizeof(struct ap);
256         aps_num++;
257
258         /* display number */
259         sprintf(message, "%c", (aps_num < 10) ? aps_num + '0' : aps_num + 55);
260         mvwaddstr(main_sub, aps_num+1, 0, message);
261
262         /* get BSSID */
263         sprintf(bssid, "%02X%02X%02X%02X%02X%02X",
264                 app->mac[0] & 0xFF, app->mac[1] & 0xFF,
265                 app->mac[2] & 0xFF, app->mac[3] & 0xFF,
266                 app->mac[4] & 0xFF, app->mac[5] & 0xFF);
267         bssid[13] = '\0';
268
269         /* get ESSID and its length */
270         for (j = 0; j < 32 && app->essid[j]; j++) {
271             essid[j] = app->essid[j];
272         }
273         essid[j] = '\0';
274
275         /*
276          * fill up ap[] field member to preserve ESSID, BSSID, Channel and
277          * Network type of current AP record, so we may use it later
278          * to connect to this very AP
279          */
280         memcpy(ap[aps_num-1].mac, app->mac, 6);
281         memcpy(ap[aps_num-1].essid, essid, j);
282         ap[aps_num-1].essid_len = j;
283         ap[aps_num-1].channel = app->channel;
284         ap[aps_num-1].nettype = (app->options & 1) ? Infrastructure : AdHoc;
285
286         /* display ESSID, BSSID, Channel, NetworkType, Preambule and WEP */
287         switch (ap_viewtype) {
288             case 1:
289             case 2:
290                 mvwaddnstr(main_sub, aps_num+1, 2, essid, 15);
291                 mvwaddstr(main_sub, aps_num+1, 18, bssid);
292                 sprintf(message, "%2u", app->channel);
293                 mvwaddstr(main_sub, aps_num+1, 31, message);
294                 mvwaddstr(main_sub, aps_num+1, 34,
295                     (app->options & 1) ? _("Infrastructure") : "Ad-Hoc");
296                 mvwaddstr(main_sub, aps_num+1, 49,
297                     (app->options & 32) ? "S" : "L");
298                 mvwaddstr(main_sub, aps_num+1, 51,
299                     (app->options & 16) ? ON : OFF);
300                 break;
301             case 3:
302                 mvwaddstr(main_sub, aps_num+1, 2, essid);
303                 mvwaddstr(main_sub, aps_num+1, 35, bssid);
304                 sprintf(message, "%2u", app->channel);
305                 mvwaddstr(main_sub, aps_num+1, 48, message);
306                 mvwaddstr(main_sub, aps_num+1, 51,
307                     (app->options & 32) ? "S" : "L");
308                 mvwaddstr(main_sub, aps_num+1, 53,
309                     (app->options & 16) ? ON : OFF);
310                 break;
311             case 4:
312                 mvwaddstr(main_sub, aps_num+1, 2, bssid);
313                 mvwaddnstr(main_sub, aps_num+1, 15,
314                     oui2manufacturer(app->mac), 48);
315                 break;
316         }
317
318         /* display RSSI and LQ indicators */
319         switch (ap_viewtype) {
320             case 1:
321                 sprintf(message, "%3d%%",
322                     (int)((minimum (app->q1, 40)) * (float)2.5));
323                 mvwaddstr(main_sub, aps_num+1, 55, message);
324                 if (ap_type == ATMEL410) {
325                     sprintf(message, "%3d%%",
326                         (int)(100 - (minimum (app->q2, 40)) * (float)2.5) );
327                     mvwaddstr(main_sub, aps_num+1, 60, message);
328                 }
329                 break;
330             case 2:
331                 sprintf(message, "%3d", -96 + app->q1);
332                 mvwaddstr(main_sub, aps_num+1, 56, message);
333                 if (ap_type == ATMEL410) {
334                     sprintf(message, "%3d%%",
335                         (int)(100 - (minimum (app->q2, 40)) * (float)2.5) );
336                     mvwaddstr(main_sub, aps_num+1, 60, message);
337                 }
338                 break;
339             case 3:
340                 sprintf(message, "%3d", app->q1);
341                 mvwaddstr(main_sub, aps_num+1, 57, message);
342                 if (ap_type == ATMEL410) {
343                     sprintf(message, "%3d", app->q2);
344                     mvwaddstr(main_sub, aps_num+1, 61, message);
345                 }
346                 break;
347         }
348
349     }
350
351     /* display legend in main_sub */
352     switch (ap_viewtype) {
353         case 1:
354             mvwaddstr(main_sub, LINES - 6, 0,
355                 _("CN: Channel Name; P: Preambule Type (S: Short; L: Long);"));
356             mvwaddstr(main_sub, LINES - 5, 0,
357                 _("RSSI: Radio Signal Strength Indicator [%]"));
358             if (ap_type == ATMEL410)
359                 waddstr(main_sub, _("; LQ: Link Quality [%]"));
360             break;
361         case 2:
362             mvwaddstr(main_sub, LINES - 6, 0,
363                 _("CN: Channel Name; P: Preambule Type (S: Short; L: Long);"));
364             mvwaddstr(main_sub, LINES - 5, 0,
365                 _("RSSI: Radio Signal Strength Indicator [dBm]"));
366             if (ap_type == ATMEL410)
367                 waddstr(main_sub, _("; LQ: Link Quality [%]"));
368             break;
369         case 3:
370             mvwaddstr(main_sub, LINES - 6, 0,
371                 _("CN: Channel Name; P: Preambule Type (S: Short; L: Long);"));
372             mvwaddstr(main_sub, LINES - 5, 0,
373                 _("RSSI: Radio Signal Strength Indicator [raw]"));
374             if (ap_type == ATMEL410)
375                 waddstr(main_sub, _("; LQ: Link Q. [raw]"));
376             break;
377     }
378     wrefresh(main_sub);
379
380     if (ap_type == ATMEL410)
381         print_help(_("# con. to AP #; R refresh with reset; T toggle; Q quit; Other = refr. w/o reset"));
382     else /* ATMEL12350 */
383         print_help(_("# con. to AP #; R initiate AP scan; T toggle view; Q quit; Other = refresh view"));
384
385         while (1)
386            switch (i = getch()) {
387             case 'Q':
388             case 'q':
389                 goto restore_before_exit;
390             case '1':
391             case '2':
392             case '3':
393             case '4':
394             case '5':
395             case '6':
396             case '7':
397             case '8':
398             case '9':
399             case 'a':
400             case 'A':
401             case 'b':
402             case 'B':
403             case 'c':
404             case 'C':
405             case 'd':
406             case 'D':
407             case 'e':
408             case 'E':
409             case 'f':
410             case 'F':
411             case 'g':
412             case 'G':
413                     if      (i >= 'a')
414                         j = i - 87;
415                     else if (i >= 'A')
416                         j = i - 55;
417                     else
418                         j = i - '0';
419
420                     if(j > aps_num)
421                             break;
422
423                     /* don't attempt to connect to remote AP in Ad-Hoc net */
424                     if(ap[j-1].nettype == AdHoc)
425                             break;
426
427                     print_help(WAIT_SET);
428                     varbinds[3].oid = operChannelID;
429                     varbinds[3].len_oid = sizeof(operChannelID);
430                     varbinds[3].value = &ap[j-1].channel;
431                     varbinds[3].len_val = 1;
432                     varbinds[3].type = INT_VALUE;
433                     varbinds[2].oid = bridgeRemoteBridgeBSSID;
434                     varbinds[2].len_oid = sizeof(bridgeRemoteBridgeBSSID);
435                     varbinds[2].value = ap[j-1].mac;
436                     varbinds[2].len_val = 6;
437                     varbinds[2].type = STRING_VALUE;
438                     varbinds[1].oid = operESSIDLength;
439                     varbinds[1].len_oid = sizeof(operESSIDLength);
440                     varbinds[1].value = (char *) &ap[j-1].essid_len;
441                     varbinds[1].len_val = 1;
442                     varbinds[1].type = INT_VALUE;
443                     varbinds[0].oid = operESSID;
444                     varbinds[0].len_oid = sizeof(operESSID);
445                     varbinds[0].value = ap[j-1].essid;
446                     varbinds[0].len_val = ap[j-1].essid_len;
447                     varbinds[0].type = STRING_VALUE;
448                     if (snmp(varbinds, 4, SET) <= 0) {
449                         print_helperr(ERR_SET);
450                         goto restore_before_exit;
451                     }
452
453                     if (bridge_mode != 3) {
454                         bridge_mode = 3;
455                         needs_opmode_restore = 1;
456                     }
457
458                     if (SysUpload() < 0 ) {
459                             print_helperr(ERR_SET);
460                             getch();
461                             goto restore_before_exit;
462                     }
463                     print_help(DONE_SET);
464                     getch();
465                     goto restore_before_exit;
466             case 'R':
467             case 'r':
468                     if (ap_type == ATMEL410) {
469                         /* force KnownAP scan by reset */
470                         print_help(WAIT_RET);
471                         if (SysReset() < 0) {
472                             print_helperr(ERR_RET);
473                             getch();
474                             goto restore_before_exit;
475                         }
476                         clear_main(0);
477                         sleep(7);
478                     } else { /* ATMEL12350 */
479                         /*
480                          * Init KnownAP scan by issuing SiteSurveyCommand.
481                          * Unfortunately, we may not use snmp() here becouse
482                          * it would time out, as buggy firmware in ATMEL12350
483                          * devices does not confirm our query reception
484                          * received via wireless port, in a reasonable
485                          * time frame. So we rather use sendto() here.
486                          */
487                         struct sockaddr_in toip;
488                         struct timeval tv;
489                         fd_set rfd;
490
491                         varbinds[0].oid = SiteSurveyCommand;
492                         varbinds[0].len_oid = sizeof(SiteSurveyCommand);
493                         c = 1;
494                         varbinds[0].value = &c;
495                         varbinds[0].len_val = 1;
496                         varbinds[0].type = INT_VALUE;
497
498                         memset(&toip, 0, sizeof toip);
499                         toip.sin_family = AF_INET;
500                         toip.sin_port = htons(161);
501                         toip.sin_addr.s_addr = ap_ip.s_addr;
502 /*
503                         if (snmp(varbinds, 1, SET) <= 0) {
504                             print_helperr(ERR_SET);
505                             goto exit;
506                         }
507 */
508                         errno = 0;
509                         i = ber(message, varbinds, 1, SET);
510                         if (sendto(sockfd, message, i, 0,
511                             (struct sockaddr *) &toip, SIZE) == -1) {
512                             sprintf(message, _("Failure in sendto(): %s. "
513                                 "Press any key."), strerror(errno));
514                             print_helperr(message);
515                             goto exit;
516                         }
517
518                         clear_main(0);
519                         mvwaddstr(main_sub, 3, 1,
520                             _
521                             ("You have just initiated the AP scan. Be advised that it may"));
522                         mvwaddstr(main_sub, 4, 1,
523                             _
524                             ("take a few seconds for your Access Point to find out some"));
525                         mvwaddstr(main_sub, 5, 1,
526                             _
527                             ("values, so expect finishing the scan in about 5 seconds."));
528                         mvwaddstr(main_sub, 6, 1,
529                             _
530                             ("Also note that your Access Point stops forwarding the network"));
531                         mvwaddstr(main_sub, 7, 1,
532                             _
533                             ("traffic while the scan is in progress, but restores itself"));
534                         mvwaddstr(main_sub, 8, 1,
535                             _
536                             ("to normal operation in time ranging up to 1 minute."));
537                         mvwaddstr(main_sub, 9, 1,
538                             _
539                             ("Hence, if you are connected to target Access Point via its"));
540                         mvwaddstr(main_sub, 10, 1,
541                             _
542                             ("wireless port, you need to wait a bit longer"));
543                         mvwaddstr(main_sub, 11, 1,
544                             _
545                             ("after pressing 'S'."));
546                         wrefresh(main_sub);
547                         print_help("");
548
549                         /*
550                          * Eat the confirmation packet from socket, if it
551                          * has been sent by the AP. This only happens
552                          * if we issued KnownAP scan via its ethernet
553                          * interface.
554                          */
555                         tv.tv_sec = 2;
556                         tv.tv_usec = 0;
557                         FD_ZERO(&rfd);
558                         FD_SET(sockfd, &rfd);
559                         if (select(sockfd + 1, &rfd, NULL, NULL, &tv) > 0)
560                             recv(sockfd, message, 65, 0);
561
562                         print_help("Now, you can try pressing 'S' repeatedly "
563                             "to watch the progress.");
564                         getch();
565                     }
566                     goto get_stats;
567             case 'T':
568             case 't':
569                     ap_viewtype += 1;
570                     if (ap_viewtype > 4)
571                         ap_viewtype = 1;
572                     clear_main(0);
573                     goto show_stats;
574             default:
575                     print_help(WAIT_RET);
576                     clear_main(0);
577                     goto get_stats;
578             }
579
580   restore_before_exit:
581     if (needs_opmode_restore) {
582         print_help(WAIT_SET);
583         varbinds[0].oid = bridgeOperationalMode;
584         varbinds[0].len_oid = sizeof(bridgeOperationalMode);
585         varbinds[0].value = (char *) &bridge_mode;
586         varbinds[0].len_val = 1;
587         varbinds[0].type = INT_VALUE;
588         if (snmp(varbinds, 1, SET) <= 0) {
589             print_helperr(ERR_RET);
590             goto exit;
591         }
592
593         if (SysUpload()) {
594             print_helperr(ERR_RET);
595             goto exit;
596         }
597     }
598  goto quit;
599
600  exit:
601     getch();
602  quit:
603     print_title("");
604     clear_main(0);
605 }
606