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