]> git.decadent.org.uk Git - ap-utils.git/blob - src/ap-mrtg.c
Imported Upstream version 1.5~pre2
[ap-utils.git] / src / ap-mrtg.c
1 /*
2  *      ap-mrtg.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 <stdio.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #if defined (__GLIBC__)
28 #include <libgen.h>
29 #endif
30 #include "ap-utils.h"
31
32 #define ERR_STR_V "\n\n-\n\n"
33 #define ERR_STR_N "999999999\n999999999\n-\n\n"
34
35 short ap_type;
36 char *community = NULL;
37 int sockfd;
38 struct in_addr ap_ip;
39
40 void usage()
41 {
42     printf(_("\nUsage:\n"));
43     printf(_("\tap-mrtg -i ip -c community -t type [-b bssid] [-n name] "
44              "[-v] [-h] [-r]\n\n"));
45     printf(_("Get stats from AP and return it in MRTG parsable format\n\n"));
46     printf(_("-i ip        - AP ip address\n"));
47     printf(_("-c community - SNMP community string\n"));
48     printf(_("-t type      - statistics type <w>ireless, <e>thernet, "
49              "associated <s>tations or <l>ink quality (last one will only "));
50     printf(_("work with ATMEL410 MIB devices in AP Client mode)\n"));
51     printf(_("-b bssid     - mac address of the AP from which get link quality"
52              ", only if type=l\n"));
53     printf(_("-n name      - AP name - for check only\n")); 
54     printf(_("-v           - report MRTG about problems connecting to AP\n"));
55     printf(_("-r           - reset AP when getting LinkQuality stats\n"));
56     printf(_("-h           - print this help screen\n\n"));
57     printf(_("ap-mrtg %s Copyright (c) 2002-2003 Roman Festchook\n\n"),
58            VERSION);
59 }
60
61 int main(int argc, char **argv)
62 {
63     extern char *optarg;
64     extern int optind;
65     extern int opterr;
66     extern int optopt;
67     int opt = 0;
68
69     struct ap {
70         char mac[6];
71         unsigned char q1;
72         unsigned char q2;
73         unsigned char channel;
74         unsigned char x2;
75         unsigned char options;
76         unsigned char x3[5];
77         unsigned char essid[32];
78     } *app = NULL;
79
80     char sysDescr_NWN[] = {
81         0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00
82     };
83     char sysDescr_ATMEL[] = {
84         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x01, 0x00
85     };
86     char bridgeOperationalMode[] = {
87         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
88     };
89     char EthRxStatistics[] = {
90         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x07, 0x01, 0x00
91     };
92     char EthTxStatistics[] = {
93         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x07, 0x02, 0x00
94     };
95     char operAccessPointName[] = {
96         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x01, 0x0A, 0x00
97     };
98     char wirelessStatistics[] = {
99         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x03, 0x01, 0x00
100     };
101     char AssociatedSTAsNum[] = {
102         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x05, 0x01, 0x00
103     };
104     char wirelessKnownAPs[] = {
105         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x07, 0x01, 0x00
106     };
107
108     struct EthRxStatistics_s *EthRxStat = NULL;
109     struct EthTxStatistics_s *EthTxStat = NULL;
110     struct wirelessStatistics_s *WirelessStat = NULL;
111     varbind varbinds[2];
112     int i, reset_flag=0;
113     char message[12], bssid_flag,  stat_type = 0, *ERR_STR =
114         ERR_STR_N, *bssid = NULL, *name = NULL, *cp;
115     struct sockaddr_in client;
116
117 #ifdef HAVE_GETTEXT
118     setlocale(LC_ALL, "");
119     bindtextdomain("ap-utils", LOCALEDIR);
120     textdomain("ap-utils");
121 #endif
122
123     memset(&client, 0, sizeof client);
124     client.sin_family = AF_INET;
125     client.sin_port = INADDR_ANY;
126     client.sin_addr.s_addr = INADDR_ANY;
127
128     if (argc < 4) {
129         usage();
130         exit(0);
131     }
132
133     do {
134         opterr = 0;
135         switch (opt = getopt(argc, argv, "i:c:t:b:n:rv")) {
136         case 'i':
137             for (cp = optarg, i = 0; *cp && (cp = index(cp, '.')); cp++, i++);
138             if (i < 3 || inet_aton(optarg, &ap_ip) == 0) {
139                 printf(_("Error: invalid IP-address.\n"));
140                 return 1;
141             }
142             break;
143         case 't':
144             stat_type = optarg[0];
145             break;
146         case 'v':
147             ERR_STR = ERR_STR_V;
148             break;
149         case 'c':
150             community = malloc(strlen(optarg) + 1);
151             strncpy(community, optarg, strlen(optarg) + 1);
152             break;
153         case 'b':
154             bssid = malloc(strlen(optarg) + 1);
155             strncpy(bssid, optarg, strlen(optarg) + 1);
156             break;
157         case 'n':
158             name = malloc(strlen(optarg) + 1);
159             strncpy(name, optarg, strlen(optarg) + 1);
160             break;
161         case 'r':
162             reset_flag=1;
163             break;
164         case -1:
165             break;
166         default:
167             usage();
168             goto quit;
169         }
170     } while (opt != -1);
171
172     if (!community) {
173         usage();
174         goto quit;
175     }
176
177     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
178         perror(_("Create socket error"));
179         return 1;
180     }
181     if (bind(sockfd, (struct sockaddr *) &client, SIZE) == -1) {
182         perror(_("Bind socket error"));
183         return 1;
184     }
185
186     /*
187      * Part detecting ap_type (ATMEL AP MIB type) follows.
188      * We could use get_mib_details() here with advantage, but it would
189      * have to involve 1. putting it to separate file in lib/ and
190      * 2. patch it so it would not contain curses-related commands (TODO)
191      */
192
193     /* determine private MIB type according to enterprises ID */
194     varbinds[0].oid = sysDescr_NWN;
195     varbinds[0].len_oid = sizeof(sysDescr_NWN);
196     varbinds[0].value = NULL;
197     varbinds[0].len_val = 0;
198     varbinds[0].type = NULL_VALUE;
199     if (snmp(varbinds, 1, GET) > 0) {
200         ap_type = NWN;
201     } else {
202         varbinds[0].oid = sysDescr_ATMEL;
203         varbinds[0].len_oid = sizeof(sysDescr_ATMEL);
204         varbinds[0].value = NULL;
205         varbinds[0].len_val = 0;
206         varbinds[0].type = NULL_VALUE;
207         if (snmp(varbinds, 1, GET) > 0) {
208             ap_type = ATMEL410;
209         } else {
210             sysDescr_ATMEL[5] = 0xE0;
211             sysDescr_ATMEL[6] = 0x3E;
212             varbinds[0].oid = sysDescr_ATMEL;
213             varbinds[0].len_oid = sizeof(sysDescr_ATMEL);
214             varbinds[0].value = NULL;
215             varbinds[0].len_val = 0;
216             varbinds[0].type = NULL_VALUE;
217             if (snmp(varbinds, 1, GET) > 0) {
218                 ap_type = ATMEL12350;
219             } else {
220                 printf(_("Unable to determine AP MIB type "
221                     "(no response from AP)."));
222                 return 1;
223             }
224         }
225     }
226
227     if (ap_type == NWN) {
228         printf("NWN devices are not yet supported.");
229         return 1;
230     }
231
232     if (ap_type == ATMEL12350) {
233         bridgeOperationalMode[5] = 0xE0;
234         bridgeOperationalMode[6] = 0x3E;
235         EthRxStatistics[5] = 0xE0;
236         EthRxStatistics[6] = 0x3E;
237         EthTxStatistics[5] = 0xE0;
238         EthTxStatistics[6] = 0x3E;
239         operAccessPointName[5] = 0xE0;
240         operAccessPointName[6] = 0x3E;
241         wirelessStatistics[5] = 0xE0;
242         wirelessStatistics[6] = 0x3E;
243         AssociatedSTAsNum[5] = 0xE0;
244         AssociatedSTAsNum[6] = 0x3E;
245         wirelessKnownAPs[5] = 0xE0;
246         wirelessKnownAPs[6] = 0x3E;
247     }
248
249     switch (stat_type) {
250
251     case 'e':
252         varbinds[0].oid = EthRxStatistics;
253         varbinds[0].len_oid = sizeof(EthRxStatistics);
254         varbinds[0].value = EthRxStatistics;
255         varbinds[0].len_val = 0;
256         varbinds[0].type = NULL_VALUE;
257         varbinds[1].oid = EthTxStatistics;
258         varbinds[1].len_oid = sizeof(EthTxStatistics);
259         varbinds[1].value = EthTxStatistics;
260         varbinds[1].len_val = 0;
261         varbinds[1].type = NULL_VALUE;
262
263         if (snmp(varbinds, 2, GET) < 2) {
264             printf(ERR_STR);
265             return 1;
266         }
267
268         if (varbinds[0].len_val == 64) {
269             if (EthRxStat)
270                 free(EthRxStat);
271             EthRxStat =
272                 (struct EthRxStatistics_s *) malloc(varbinds[0].
273                                                        len_val);
274             memcpy(EthRxStat, varbinds[0].value, varbinds[0].len_val);
275         } else {
276             printf(ERR_STR);
277             return 1;
278         }
279
280         if (varbinds[1].len_val == 56) {
281             if (EthTxStat)
282                 free(EthTxStat);
283             EthTxStat =
284                 (struct EthTxStatistics_s *) malloc(varbinds[1].
285                                                        len_val);
286             memcpy(EthTxStat, varbinds[1].value, varbinds[1].len_val);
287         } else {
288             printf(ERR_STR);
289             return 1;
290         }
291         printf("%u\n%u\n", swap4(EthRxStat->TotalBytesRx),
292                swap4(EthTxStat->TotalBytesTx));
293         if (EthRxStat)
294             free(EthRxStat);
295         if (EthTxStat)
296             free(EthTxStat);
297         break;
298     case 'w':
299         varbinds[0].oid = wirelessStatistics;
300         varbinds[0].len_oid = sizeof(wirelessStatistics);
301         varbinds[0].value = wirelessStatistics;
302         varbinds[0].len_val = 0;
303         varbinds[0].type = NULL_VALUE;
304
305         if (snmp(varbinds, 1, GET) <= 0) {
306             printf(ERR_STR);
307             return 1;
308         }
309
310         if (varbinds[0].len_val == 88 || varbinds[0].len_val == 104) {
311             /*
312              * 88 ... using traditional ATMEL 12350 MIB
313              * 104 .. using functionally enhanced ATMEL 12350 MIB by EZYNET
314              */
315             if (WirelessStat)
316                 free(WirelessStat);
317             WirelessStat =
318                 (struct wirelessStatistics_s *) malloc(varbinds[0].len_val);
319             memcpy(WirelessStat, varbinds[0].value, varbinds[0].len_val);
320         } else {
321             printf(ERR_STR);
322             return 1;
323         }
324         printf("%u\n%u\n",
325                swap4(WirelessStat->UnicastReceivedPackets) +
326                swap4(WirelessStat->BroadcastReceivedPackets) +
327                swap4(WirelessStat->MulticastReceivedPackets),
328                swap4(WirelessStat->UnicastTransmittedPackets) +
329                swap4(WirelessStat->BroadcastTransmittedPackets) +
330                swap4(WirelessStat->MulticastTransmittedPackets));
331         break;
332
333     case 's':
334         varbinds[0].oid = AssociatedSTAsNum;
335         varbinds[0].len_oid = sizeof(AssociatedSTAsNum);
336         varbinds[0].value = AssociatedSTAsNum;
337         varbinds[0].len_val = 0;
338         varbinds[0].type = NULL_VALUE;
339
340         if (snmp(varbinds, 1, GET) <= 0) {
341             printf(ERR_STR);
342             return 1;
343         }
344
345         printf("%u\n0\n", *varbinds[0].value);
346         break;
347
348     case 'l':
349         varbinds[0].oid = bridgeOperationalMode;
350         varbinds[0].len_oid = sizeof(bridgeOperationalMode);
351         varbinds[0].len_val = 0;
352         varbinds[0].type = NULL_VALUE;
353
354         if (snmp(varbinds, 1, GET) <= 0) {
355             printf(ERR_STR);
356             return 1;
357         }
358
359         if (!(ap_type == ATMEL410 && *(varbinds[0].value) == 3)) {
360             printf(ERR_STR);
361             return 1;
362         }
363
364         if (reset_flag) {
365                 if (SysReset()) {
366                     printf(ERR_STR);
367                     return 1;
368                 }
369                 sleep(10);
370         }
371
372         varbinds[0].oid = wirelessKnownAPs;
373         varbinds[0].len_oid = sizeof(wirelessKnownAPs);
374         varbinds[0].type = NULL_VALUE;
375         varbinds[0].len_val = 0;
376
377         if (snmp(varbinds, 1, GET) <= 0) {
378             printf(ERR_STR);
379             return 1;
380         }
381         bssid_flag = 1;
382         for (i = 0; i < varbinds[0].len_val; i += 48) {
383             if (app)
384                 free(app);
385             app = (struct ap *) malloc(48);
386             memcpy(app, varbinds[0].value + i, 48);
387             if (!app->channel)
388                 continue;
389             if (bssid) {
390                 sprintf(message, "%02X%02X%02X%02X%02X%02X",
391                         app->mac[0] & 0xFF, app->mac[1] & 0xFF,
392                         app->mac[2] & 0xFF, app->mac[3] & 0xFF,
393                         app->mac[4] & 0xFF, app->mac[5] & 0xFF);
394                 if (memcmp(message, bssid, 12))
395                     continue;
396             };
397             printf("%d\n%d\n", app->q2,
398                    96 - app->q1);
399             bssid_flag = 0;
400             break;
401         }
402         if (bssid_flag)
403             printf(ERR_STR);
404         break;
405     default:
406         usage();
407         goto quit;
408     }
409
410     printf("-\n");
411
412     if ( name != NULL ) {
413         varbinds[0].oid = operAccessPointName;
414         varbinds[0].len_oid = sizeof(operAccessPointName);
415         varbinds[0].len_val = 0;
416         varbinds[0].type = NULL_VALUE;
417         if (snmp(varbinds, 1, GET) <= 0) {
418                 printf("\n");
419                 return 1;
420         }
421
422         for (i = 0; i < 32 && *(varbinds[0].value + i); i++)
423                 putchar(*(varbinds[0].value + i));
424                 putchar('\n');
425           if (strncmp(name,varbinds[0].value,strlen(name)) ){
426                 return 2;
427         }
428     } else {
429         printf("-\n");
430     }
431
432     close(sockfd);
433
434     
435   quit:
436     if (community)
437         free(community);
438     if (app)
439         free(app);
440     if (bssid)
441         free(bssid);
442     if (name)
443         free(name);
444     return 0;
445 }
446