2 * aplink.c from Access Point SNMP Utils for Linux
4 * Copyright (c) 2005 Jan Rafaj <jr-aputils at cedric dot unob dot cz>
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.
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.
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
25 #define S_RSSI _("RSSI: [")
26 #define S_RSSI_AVG _("RSSI avg: [")
27 #define S_RSSI_TOP _("RSSI top: [")
28 #define S_RSSI_ROU _("RSSI rou: [")
29 #define APLINK_HELP _("P - pause, T - toggle graph view, Q - quit to menu, Other key - force update.")
31 #define GRWIN_LENGTH (COLS - MCOLS - 7)
32 #define GRWIN_HEIGHT (LAST_ROW - 10)
36 extern WINDOW *main_sub;
37 extern short ap_type, ap_vendorext;
38 extern int wait_mode, poll_delay;
41 * TODO: Implement APClientInfo as alternative, for NetGear ME102 MIB
42 * (ap_type == ATMEL12350 && ap_vendorext == NONE).
47 char bridgeOperationalMode[] = {
48 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
51 * ATMEL12350 EZYNET MIB and ATMEL410 SBRIDGES MIB specific OIDs:
52 * for ATMEL410 SBRIDGES MIB: .1.3.6.1.4.1.410.1.2.8.1.0
53 * for ATMEL12350 EZYNET MIB: .1.3.6.1.4.1.12350.1.2.7.4.0
55 char NetworkSettings[] = {
56 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x02, 0x08, 0x01, 0x00
59 /* APClient mode: AP link diagnostics */
61 struct NetworkSettings_ATMEL410_SBRIDGES sa_sb_410;
62 struct NetworkSettings_ATMEL12350_EZYNET sa_en_12350;
64 /* Used common members of the 2 structures above. */
65 unsigned char BSSID[6];
66 /* unsigned short InfoCapability; */
68 unsigned char Channel;
69 /* LinkQuality for NetworkSettings_ATMEL410_SBRIDGES */
70 /* CurrentRate for NetworkSettings_ATMEL12350_EZYNET */
72 unsigned char ESSID[32];
73 unsigned long ESSLEN; /* uchar for NetworkSettings_ATMEL410_SBRIDGES */
75 int i, j = 0, linked = 0, samples = 0, sum = 0, rssi_perc;
76 int rssi_avg = 0, rssi_avg_perc, rssi_top = 0, rssi_top_perc;
77 int rssi_rou, rssi_rou_perc, lq_perc = 0, lq_perc_top = 0;
78 int ringbuf_pos = 0, p_wait_mode = wait_mode;
81 char *gr_modes[5] = { _("RSSI [%]"),
82 _("RSSI average [%]"),
83 _("RSSI rounded [%]"),
84 _("Link Quality [%]"),
87 WINDOW *gauge_rssi_top;
88 WINDOW *gauge_rssi_avg;
89 WINDOW *gauge_rssi_rou;
91 WINDOW *grwin_rssi_avg = NULL;
92 WINDOW *grwin_rssi_rou = NULL;
93 WINDOW *grwin_lq = NULL;
96 if (ap_type == ATMEL12350) {
97 bridgeOperationalMode[5] = 0xE0;
98 bridgeOperationalMode[6] = 0x3E;
100 NetworkSettings[5] = 0xE0;
101 NetworkSettings[6] = 0x3E;
102 NetworkSettings[9] = 0x07;
103 NetworkSettings[10] = 0x04;
106 gauge_rssi = derwin(main_sub, 1, 20, 2, strlen(S_RSSI));
107 gauge_rssi_top = derwin(main_sub, 1, 20, 3, strlen(S_RSSI_TOP));
108 gauge_rssi_avg = derwin(main_sub, 1, 20, 4, strlen(S_RSSI_AVG));
109 gauge_rssi_rou = derwin(main_sub, 1, 20, 5, strlen(S_RSSI_ROU));
110 grwin_rssi = derwin(main_sub, GRWIN_HEIGHT + 2, GRWIN_LENGTH + 2, 9, 3);
112 /* find out mode the device is currently in */
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 print_help(WAIT_RET);
119 if (snmp(varbinds, 1, GET) <= 0) {
120 print_helperr(ERR_RET);
126 * Rule out all modes except APClient(3) mode and WRepeater(5) mode on
127 * device running firmware with necessary vendor extensions.
129 if(!( ((ap_type == ATMEL410 && ap_vendorext == SBRIDGES) ||
130 (ap_type == ATMEL12350 && ap_vendorext == EZYNET)) &&
131 (*(varbinds[0].value) == 3 || *(varbinds[0].value) == 5) )) {
132 mvwaddstr(main_sub, 1, 1,
133 _("Not available - device must have firmware with necessary "));
134 mvwaddstr(main_sub, 2, 1,
135 _("vendor extensions and be in either 'Access Point client'"));
136 mvwaddstr(main_sub, 3, 1,
137 _("or 'Repeater' mode."));
144 wait_mode = WAIT_TIMEOUT;
146 print_top(POLL_ON, AP_TITLE);
147 print_help(APLINK_HELP);
150 memset(ringbuf, 0, sizeof(ringbuf));
152 box(grwin_rssi, 0, 0);
153 for (i = GRWIN_HEIGHT - GRWIN_HEIGHT / 3; i > 0; i -= GRWIN_HEIGHT / 3) {
155 mvwprintw(main_sub, 9 + i, 0, "%u", j);
156 mvwaddch(grwin_rssi, i, 0, ACS_SSSS);
159 wmove(main_sub, 9, 6);
160 print_bold(main_sub, gr_modes[gr_mode]);
161 grwin_rssi = newwin(GRWIN_HEIGHT, GRWIN_LENGTH, 12, MCOLS + 4);
162 grwin_rssi_avg = newwin(GRWIN_HEIGHT, GRWIN_LENGTH, 12, MCOLS + 4);
163 grwin_rssi_rou = newwin(GRWIN_HEIGHT, GRWIN_LENGTH, 12, MCOLS + 4);
164 if (ap_type == ATMEL410)
165 grwin_lq = newwin(GRWIN_HEIGHT, GRWIN_LENGTH, 12, MCOLS + 4);
166 wattrset(grwin_rssi, COLOR_PAIR(COLOR_BLUE));
167 wattrset(grwin_rssi_avg, COLOR_PAIR(COLOR_BLUE));
168 wattrset(grwin_rssi_rou, COLOR_PAIR(COLOR_BLUE));
169 if (ap_type == ATMEL410)
170 wattrset(grwin_lq, COLOR_PAIR(COLOR_BLUE));
173 mvwaddstr(main_sub, 0, 0, "Associated with AP: ");
175 varbinds[0].oid = NetworkSettings;
176 varbinds[0].len_oid = sizeof(NetworkSettings);
177 varbinds[0].value = NetworkSettings;
178 varbinds[0].type = STRING_VALUE;
179 varbinds[0].len_val = 0;
181 if (snmp(varbinds, 1, GET) <= 0) {
183 waddstr(main_sub, NO);
185 linked = sum = samples = ringbuf_pos = 0;
186 memset(ringbuf, 0, sizeof(ringbuf));
189 clear_main_new(1, 9);
190 /* wclrtobot(main_sub); */
192 wattrset(grwin_rssi, COLOR_PAIR(COLOR_RED));
193 wattrset(grwin_rssi_avg, COLOR_PAIR(COLOR_RED));
194 wattrset(grwin_rssi_rou, COLOR_PAIR(COLOR_RED));
195 if (ap_type == ATMEL410)
196 wattrset(grwin_lq, COLOR_PAIR(COLOR_RED));
198 for (i = 0; i < GRWIN_HEIGHT; i++) {
199 mvwdelch(grwin_rssi, i, 0);
200 mvwdelch(grwin_rssi_avg, i, 0);
201 mvwdelch(grwin_rssi_rou, i, 0);
202 mvwaddch(grwin_rssi, i, GRWIN_LENGTH - 1, ACS_SBSB);
203 mvwaddch(grwin_rssi_avg, i, GRWIN_LENGTH - 1, ACS_SBSB);
204 mvwaddch(grwin_rssi_rou, i, GRWIN_LENGTH - 1, ACS_SBSB);
205 if (ap_type == ATMEL410) {
206 mvwdelch(grwin_lq, i, 0);
207 mvwaddch(grwin_lq, i, GRWIN_LENGTH - 1, ACS_SBSB);
210 wattrset(grwin_rssi, COLOR_PAIR(COLOR_BLUE));
211 wattrset(grwin_rssi_avg, COLOR_PAIR(COLOR_BLUE));
212 wattrset(grwin_rssi_rou, COLOR_PAIR(COLOR_BLUE));
213 if (ap_type == ATMEL410)
214 wattrset(grwin_lq, COLOR_PAIR(COLOR_BLUE));
217 wnoutrefresh(main_sub);
218 wnoutrefresh(gr_mode == 0 ? grwin_rssi :
219 gr_mode == 1 ? grwin_rssi_avg :
220 gr_mode == 2 ? grwin_rssi_rou : grwin_lq);
224 waddstr(main_sub, YES);
226 if (ap_type == ATMEL410) {
227 memcpy(&sa_sb_410, varbinds[0].value, varbinds[0].len_val);
229 memcpy(BSSID, sa_sb_410.BSSID, 6);
230 /* InfoCapability = sa_sb_410.InfoCapability; */
231 Rssi = sa_sb_410.Rssi;
232 Channel = sa_sb_410.Channel;
233 LQCR = sa_sb_410.LinkQuality;
234 memcpy(ESSID, sa_sb_410.ESSID, 32);
235 ESSLEN = sa_sb_410.ESSLEN;
236 } else { /* ap_type == ATMEL12350 */
237 memcpy(&sa_en_12350, varbinds[0].value, varbinds[0].len_val);
239 memcpy(BSSID, sa_en_12350.BSSID, 6);
240 /* InfoCapability = sa_en_12350.InfoCapability; */
241 Rssi = sa_en_12350.Rssi;
242 Channel = sa_en_12350.Channel;
243 LQCR = sa_en_12350.CurrentRate;
244 memcpy(ESSID, sa_en_12350.ESSID, 32);
245 ESSLEN = sa_en_12350.ESSLEN;
248 sprintf(message, "Joined BSSID: %02X%02X%02X%02X%02X%02X",
249 BSSID[0] & 0xFF, BSSID[1] & 0xFF, BSSID[2] & 0xFF,
250 BSSID[3] & 0xFF, BSSID[4] & 0xFF, BSSID[5] & 0xFF);
251 mvwaddstr(main_sub, 1, 0, message);
253 mvwaddstr(main_sub, 2, 0, S_RSSI);
254 rssi_perc = (int)((minimum (Rssi, 40)) * (float)2.5);
256 for (i = 0; i < (20 * rssi_perc / 100); i++) {
258 wattrset(gauge_rssi, COLOR_PAIR(COLOR_RED));
260 wattrset(gauge_rssi, COLOR_PAIR(COLOR_YELLOW) | A_BOLD);
262 wattrset(gauge_rssi, COLOR_PAIR(COLOR_GREEN));
263 waddch(gauge_rssi, ACS_BLOCK);
265 wnoutrefresh(gauge_rssi);
266 sprintf(message, "] [%4ddBm] [%3u%%] [%3u]",
267 dbmconv(Rssi), rssi_perc, Rssi);
268 mvwaddstr(main_sub, 2, strlen(S_RSSI) + 20, message);
270 mvwaddstr(main_sub, 3, 0, S_RSSI_TOP);
273 rssi_top_perc = (int)((minimum (rssi_top, 40)) * (float)2.5);
274 werase(gauge_rssi_top);
275 for (i = 0; i < (20 * rssi_top_perc / 100); i++) {
277 wattrset(gauge_rssi_top, COLOR_PAIR(COLOR_RED));
279 wattrset(gauge_rssi_top, COLOR_PAIR(COLOR_YELLOW) | A_BOLD);
281 wattrset(gauge_rssi_top, COLOR_PAIR(COLOR_GREEN));
282 waddch(gauge_rssi_top, ACS_BLOCK);
284 wnoutrefresh(gauge_rssi_top);
285 sprintf(message, "] [%4ddBm] [%3u%%] [%3u]",
286 dbmconv(rssi_top), rssi_top_perc, rssi_top);
287 mvwaddstr(main_sub, 3, strlen(S_RSSI_TOP) + 20, message);
289 mvwaddstr(main_sub, 4, 0, S_RSSI_AVG);
291 rssi_avg = sum / ++samples;
292 if (samples == 100000) {
296 rssi_avg_perc = (int)((minimum (rssi_avg, 40)) * (float)2.5);
297 werase(gauge_rssi_avg);
298 for (i = 0; i < (20 * rssi_avg_perc / 100); i++) {
300 wattrset(gauge_rssi_avg, COLOR_PAIR(COLOR_RED));
302 wattrset(gauge_rssi_avg, COLOR_PAIR(COLOR_YELLOW) | A_BOLD);
304 wattrset(gauge_rssi_avg, COLOR_PAIR(COLOR_GREEN));
305 waddch(gauge_rssi_avg, ACS_BLOCK);
307 wnoutrefresh(gauge_rssi_avg);
308 sprintf(message, "] [%4ddBm] [%3u%%] / %5u sampl.",
309 dbmconv(rssi_avg), rssi_avg_perc, samples);
310 mvwaddstr(main_sub, 4, strlen(S_RSSI_AVG) + 20, message);
312 mvwaddstr(main_sub, 5, 0, S_RSSI_ROU);
313 ringbuf[ringbuf_pos++] = Rssi;
314 if (ringbuf_pos == sizeof(ringbuf))
317 for (i = 0; i < (int)sizeof(ringbuf); rssi_rou += ringbuf[i], i++);
318 rssi_rou /= sizeof(ringbuf);
319 rssi_rou_perc = (int)((minimum (rssi_rou, 40)) * (float)2.5);
320 werase(gauge_rssi_rou);
321 for (i = 0; i < (20 * rssi_rou_perc / 100); i++) {
323 wattrset(gauge_rssi_rou, COLOR_PAIR(COLOR_RED));
325 wattrset(gauge_rssi_rou, COLOR_PAIR(COLOR_YELLOW) | A_BOLD);
327 wattrset(gauge_rssi_rou, COLOR_PAIR(COLOR_GREEN));
328 waddch(gauge_rssi_rou, ACS_BLOCK);
330 wnoutrefresh(gauge_rssi_rou);
331 sprintf(message, "] [%4ddBm] [%3u%%] / last %2u sam.",
332 dbmconv(rssi_rou), rssi_rou_perc, sizeof(ringbuf));
333 mvwaddstr(main_sub, 5, strlen(S_RSSI_ROU) + 20, message);
335 if (ap_type == ATMEL410) {
336 lq_perc = (int)(100 - (minimum (LQCR, 40)) * (float)2.5);
337 if (lq_perc > lq_perc_top)
338 lq_perc_top = lq_perc;
339 sprintf(message, "Link quality: %3u%% (top: %3u%%)",
340 lq_perc, lq_perc_top);
341 } else { /* ap_type == ATMEL12350 */
342 sprintf(message, "Current rate: ");
345 strcat(message, "1 Mbps ");
348 strcat(message, "2 Mbps ");
351 strcat(message, "5.5 Mbps");
354 strcat(message, "11 Mbps ");
357 mvwaddstr(main_sub, 6, 0, message);
359 sprintf(message, "Channel: %2u", Channel);
360 mvwaddstr(main_sub, 7, 0, message);
362 mvwaddstr(main_sub, 8, 0, "ESSID: ");
363 waddnstr(main_sub, ESSID, ESSLEN);
365 sprintf(message, "InfoCapability: %3u", InfoCapability & 0xFF);
366 mvwaddstr(main_sub, 9, 0, message);
368 wnoutrefresh(main_sub);
370 for (i = 0; i < GRWIN_HEIGHT; i++) {
371 mvwdelch(grwin_rssi, i, 0);
372 mvwdelch(grwin_rssi_avg, i, 0);
373 mvwdelch(grwin_rssi_rou, i, 0);
374 if (ap_type == ATMEL410)
375 mvwdelch(grwin_lq, i, 0);
377 for (i = 0; i < GRWIN_HEIGHT * rssi_perc / 100; i++)
379 GRWIN_HEIGHT - 1 - i, GRWIN_LENGTH - 1, ACS_BLOCK);
380 for (i = 0; i < GRWIN_HEIGHT * rssi_avg_perc / 100; i++)
381 mvwaddch(grwin_rssi_avg,
382 GRWIN_HEIGHT - 1 - i, GRWIN_LENGTH - 1, ACS_BLOCK);
383 for (i = 0; i < GRWIN_HEIGHT * rssi_rou_perc / 100; i++)
384 mvwaddch(grwin_rssi_rou,
385 GRWIN_HEIGHT - 1 - i, GRWIN_LENGTH - 1, ACS_BLOCK);
386 if (ap_type == ATMEL410)
387 for (i = 0; i < GRWIN_HEIGHT * lq_perc / 100; i++)
389 GRWIN_HEIGHT - 1 - i, GRWIN_LENGTH - 1, ACS_BLOCK);
391 wnoutrefresh(gr_mode == 0 ? grwin_rssi :
392 gr_mode == 1 ? grwin_rssi_avg :
393 gr_mode == 2 ? grwin_rssi_rou : grwin_lq);
400 i = wait_key(poll_delay);
412 if (gr_mode == (ap_type == ATMEL410 ? 4 : 3))
415 wmove(main_sub, 9, 6);
416 print_bold(main_sub, gr_modes[gr_mode]);
417 for (i = 0; i < 10; i++)
418 waddch(main_sub, ACS_BSBS);
420 /* either timeout for user input (i == 0) or invalid key => cont. */
424 wait_mode = p_wait_mode;
427 delwin(gauge_rssi_top);
428 delwin(gauge_rssi_avg);
429 delwin(gauge_rssi_rou);
432 delwin(grwin_rssi_avg);
433 delwin(grwin_rssi_rou);
434 if (ap_type == ATMEL410)
437 print_top(NULL, NULL);