2 * ap_search.c from Access Point SNMP Utils for Linux
4 * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
5 * Copyright (c) 2003 Jan Rafaj <aputils at cedric dot vabo dot cz>
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.
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.
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
23 #include <sys/types.h>
27 #include <sys/ioctl.h>
30 #include <sys/sockio.h>
34 #include <sys/socket.h>
42 #include "ap-curses.h"
44 #if defined (__GLIBC__)
50 #define SEARCH_HEADER _("# Type IP Description")
52 extern int atmel410_filter;
61 void scan_local_segment (struct sockaddr_in *from, struct sockaddr_in *to,
64 extern WINDOW *main_sub;
65 extern char *ap_types[];
66 unsigned char message[1024], *start;
68 * sysDescr OIDs used to detect AP type [in order of appearance
69 * according to the 'for' loop below: ATMEL410, NWN, ATMEL12350
71 char Wireless[3][12] = {
72 {0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x01, 0x00},
73 {0x2B, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00},
74 {0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x01, 0x01, 0x00}
76 int scd_ap_type, last_searched_type=ATMEL12350;
77 int c, s2, errno, len, client_len = SIZE;
78 struct in_addr to_addr_reserv;
82 struct ip_mreq mult = { {0}, {INADDR_ANY} };
85 struct timeval timeout, starttime, curtime;
89 print_help(_("Please wait while scanning, or press 'Q' to quit."));
91 if ((s2 = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
92 print_helperr(CREATE_SOCKET_ERROR);
97 if (bind(s2, (struct sockaddr *) from, SIZE) == -1) {
98 print_helperr(BIND_SOCKET_ERROR);
103 if (setsockopt (s2, SOL_SOCKET, SO_BROADCAST, &opts,
104 sizeof(struct sopts)) == -1) {
105 print_helperr(_("Can't set broadcast option on socket. "
111 inet_aton("224.0.1.43", &mult.imr_multiaddr);
112 if (setsockopt(s2, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mult,
113 sizeof(struct ip_mreq)) == -1) {
114 print_helperr(_("Can't set multicast membership on socket. "
120 mvwaddstr(main_sub, 15, 1, _("Scanning via network interface:"));
121 sprintf(message, _(" Index: %i"), f_ifctr);
122 mvwaddstr(main_sub, 16, 1, message);
123 sprintf(message, _(" Name: %s"), ifname);
124 mvwaddstr(main_sub, 17, 1, message);
125 sprintf(message, _(" IP: %s"), inet_ntoa(from->sin_addr));
126 mvwaddstr(main_sub, 18, 1, message);
128 if(atmel410_filter) {
129 last_searched_type=ATMEL410;
132 for (scd_ap_type = ATMEL410; scd_ap_type <= last_searched_type; scd_ap_type++) {
133 clear_main_new(19, 20);
134 sprintf(message, _("Scanning for AP type: %s"), ap_types[scd_ap_type]);
135 mvwaddstr(main_sub, 19, 1, message);
138 varbinds[0].oid = Wireless[scd_ap_type];
139 varbinds[0].len_oid =
140 (scd_ap_type == ATMEL410 || scd_ap_type == ATMEL12350) ?
141 sizeof(Wireless[scd_ap_type]) : 8;
142 varbinds[0].len_val = 0;
143 varbinds[0].type = NULL_VALUE;
144 len = ber(message, varbinds, 1, GET);
146 if (scd_ap_type == NWN) {
147 to_addr_reserv = to->sin_addr;
148 to->sin_addr = mult.imr_multiaddr;
152 if (sendto(s2, message, len, 0, (struct sockaddr *) to, SIZE) == -1) {
153 sprintf(message, _("Failure in sendto(): %s. Press any key."),
155 print_helperr(message);
162 gettimeofday(&starttime, &tz);
171 * Compute time difference. Note that for portability reasons,
172 * we may not rely on select() below setting up timeout to
173 * remaining time upon its return, although this works on Linux.
175 gettimeofday(&curtime, &tz);
176 c = (curtime.tv_sec * 1000000 + curtime.tv_usec) -
177 (starttime.tv_sec * 1000000 + starttime.tv_usec);
178 if (c < (2 * 1000000 + 0)) {
179 c = (2 * 1000000 + 0) - c;
180 timeout.tv_sec = c / 1000000;
181 timeout.tv_usec = c - timeout.tv_sec * 1000000;
183 /* Return if nothing has been received after timeout secs. */
186 c = select(s2 + 1, &rds, NULL, NULL, &timeout);
196 /* Key pressed. If it is 'Q', return. */
197 if (FD_ISSET(0, &rds)) {
199 if (c == 'q' || c == 'Q') {
205 /* If data are available for reading on s2, try to read them now. */
206 if (FD_ISSET(s2, &rds))
207 if ((len = recvfrom(s2, message, 512, 0,
208 (struct sockaddr *) from, &client_len)) == -1)
212 if (*start != ASN_HEADER)
215 start += (start[1] & 0x80) ? (start[1] & 0x7F) + 2 : 2;
216 start += *(start + 4) + 5;
218 if (*start != RESPONSE)
221 start += (start[1] & 0x80) ? (start[1] & 0x7F) + 2 : 2;
223 if (*(start + 5) || *(start + 9) != ASN_HEADER)
226 start += (start[10] & 0x80) ? (start[10] & 0x7F) + 11 : 11;
228 if (*(start) != ASN_HEADER)
231 start += (start[1] & 0x80) ? (start[1] & 0x7F) + 2 : 2;
232 start += *(start + 1) + 2;
234 if (start[1] & 0x80) {
235 varbinds[0].len_val = start[2];
236 start += (start[1] & 0x7F) + 2;
238 varbinds[0].len_val = start[1];
243 * Dupe check. There are 2 reasons why to do this:
244 * 1. If interface-based IP aliases are used (f.e. on Linux),
245 * it may well happen that their broadcast addresses may
246 * inadvertedly overlap each other, so the same AP IPs would
247 * answer twice (for a specific interface and its alias
249 * 2. ATMEL410 devices are capable to answer both queries with
250 * 410 as well as 12350 IDs, while ATMEL12350 device only
251 * answers queries with 12350 ID. Hence, we need to check
252 * for duplicate responses from ATMEL410 devices, when
253 * ATMEL410 check has already performed and ATMEL12350 one
255 * Note, that ATMEL410 devices may, under certain circumstances,
256 * fail to pass the ATMEL410 check, and can be accidentally
257 * marked as an ATMEL12350 device. This is a known bug and
258 * should be eventually solved in any of upcomming releases (TODO).
261 int dupcnt = 0, j = i - 1;
264 if (from->sin_addr.s_addr == fapsa[j].ip.s_addr)
272 /* new AP (unique IP/APtype pair) found */
274 fapsa[i].ip = from->sin_addr;
275 fapsa[i].type = scd_ap_type;
277 sprintf(message, "%2X %11s %15s", i, ap_types[fapsa[i].type],
278 inet_ntoa(fapsa[i].ip));
282 mvwaddstr(main_sub, i, 0, message);
283 for (len = 0; len < varbinds[0].len_val && start[len]; len++)
284 mvwaddch(main_sub, i, len + 31, start[len]);
287 /* Bail out if the number of found devices exceeds sane limit. */
292 if (scd_ap_type == NWN)
293 to->sin_addr = to_addr_reserv;
304 extern WINDOW *main_sub;
306 unsigned int ilen = 256;
307 struct sockaddr_in from, to;
310 char *ifbuf_ptr = NULL, *ifrec_ptr;
312 print_title(_("Access Points Search"));
313 mvwaddstr(main_sub, 0, 0, SEARCH_HEADER);
316 if ((s1 = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
317 print_helperr(CREATE_SOCKET_ERROR);
324 * Find all IPs of locally available IPv4 interfaces and corresponding
325 * broadcast and/or point-to-point addresses.
328 if (!(ifbuf_ptr = realloc(ifbuf_ptr, ilen))) {
329 print_helperr(_("realloc() error."));
333 ifc.ifc_buf = ifbuf_ptr;
335 if (ioctl(s1, SIOCGIFCONF, &ifc) >= 0)
336 /* Stupid condition thx to BSD and 2 SIOCGIFCONF implementations */
337 if (ifc.ifc_len + sizeof(struct ifreq) + 64 < ilen)
341 print_helperr(_("Network interface discovery error."));
344 ilen += 100 + (ilen >> 2);
346 ifrec_ptr = ifbuf_ptr;
347 while (ifrec_ptr < ifbuf_ptr + ifc.ifc_len) {
348 memset(&from.sin_addr, 0, sizeof(struct in_addr));
349 memset(&to.sin_addr, 0, sizeof(struct in_addr));
350 ifr = (struct ifreq *) ifrec_ptr;
352 ilen = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
353 if (ilen < sizeof(*ifr))
356 if (ifr->ifr_addr.sa_family == AF_INET)
357 if (ioctl(s1, SIOCGIFFLAGS, ifrec_ptr) == 0)
358 if (ifr->ifr_flags & IFF_UP)
359 if (!(ifr->ifr_flags & IFF_LOOPBACK)) {
361 ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
362 if (ifr->ifr_flags & IFF_POINTOPOINT) {
363 ioctl(s1, SIOCGIFDSTADDR, ifrec_ptr);
365 ((struct sockaddr_in *)&ifr->ifr_dstaddr)->sin_addr;
367 ioctl(s1, SIOCGIFBRDADDR, ifrec_ptr);
369 ((struct sockaddr_in *)&ifr->ifr_broadaddr)->sin_addr;
375 if (ioctl(s1, SIOCGIFFLAGS, ifrec_ptr) == 0)
376 if (ifr->ifr_flags & IFF_UP)
377 if (!(ifr->ifr_flags & IFF_LOOPBACK)) {
378 if (ifr->ifr_flags & IFF_POINTOPOINT) {
379 ioctl(s1, SIOCGIFDSTADDR, ifrec_ptr);
381 ((struct sockaddr_in *)&ifr->ifr_dstaddr)->sin_addr;
383 ioctl(s1, SIOCGIFBRDADDR, ifrec_ptr);
385 ((struct sockaddr_in *)&ifr->ifr_broadaddr)->sin_addr;
387 if (ioctl(s1, SIOCGIFADDR, ifrec_ptr) == 0)
388 if (ifr->ifr_addr.sa_family == AF_INET)
390 ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
393 if (from.sin_addr.s_addr && to.sin_addr.s_addr) {
395 from.sin_family = to.sin_family = AF_INET;
396 from.sin_port = INADDR_ANY;
397 to.sin_port = htons(161);
398 scan_local_segment(&from, &to, ifr->ifr_name);
399 clear_main_new(15, 20);
402 /* No need to process next interfaces if the table is already full, */
406 /* or if someone pressed 'Q'. */
416 print_helperr(_("No local network interfaces found. Press any key."));
418 print_help(_("No directly reachable Access Points found. "
422 mvwaddstr(main_sub, 19, 1, _("Program-hardcoded maximum number "
426 print_help(_("# - connect to AP; Q - quit"));
428 switch (ac = getch()) {
442 if (ac-'0' > (i - 1))
446 connect_options(fapsa[ac-'0'].ip.s_addr,
447 fapsa[ac-'0'].type + 1);