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