/* $Id: wl.c,v 1.18 2008/05/13 04:42:17 hacki Exp $ */ /* * Copyright (c) 2005, 2006 Marcus Glocker * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Ported to FreeBSD by Nathan Lay 4/30/06 */ #include #include #include #ifdef __OpenBSD__ #include #endif #ifdef __FreeBSD__ #include #endif #include #include #include #include #include #include #include #include #include #include "wl.h" /* * global variables for this file */ #ifdef __OpenBSD__ static char *speed[25] = { "DS1", "1", "DS2", "2", "DS5", "5.5", "DS11", "11", "OFDM6", "6", "OFDM9", "9", "OFDM12", "12s", "OFDM18", "18", "OFDM24", "24", "OFDM36", "36", "OFDM48", "48", "OFDM54", "54", NULL }; #endif #ifdef __FreeBSD__ static char *speed[] = { "FH/1Mbps", "1", "FH/2Mbps", "2", "DS/1Mbps", "1", "DS/2Mbps", "2", "DS/5.5Mbps", "5.5", "DS/11Mbps", "11", "DS/22Mbps", "22", "OFDM/6Mbps", "6", "OFDM/9Mbps", "9", "OFDM/12Mbps", "12", "OFDM/18Mbps", "18", "OFDM/24Mbps", "24", "OFDM/36Mbps", "36", "OFDM/48Mbps", "48", "OFDM/54Mbps", "54", "OFDM/72Mbps", "72", "DS/354Kbps", "0.354", "DS/512Kbps", "0.512", NULL }; #endif /* * get_wep() * get wep status * Return: * 0 = wep disabled, 1 = wep enabled, -1 = error */ int get_wep(const char *interface) { int r = 0, s, inwkey; #ifdef __OpenBSD__ struct ieee80211_nwkey nwkey; #endif #ifdef __FreeBSD__ struct ieee80211req nwkey; #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (-1); memset(&nwkey, 0, sizeof(nwkey)); #ifdef __FreeBSD__ nwkey.i_type = IEEE80211_IOC_WEP; #endif strlcpy(nwkey.i_name, interface, sizeof(nwkey.i_name)); #ifdef __OpenBSD__ if ((inwkey = ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey)) == -1) { close(s); return (-1); } #endif #ifdef __FreeBSD__ if ((inwkey = ioctl(s, SIOCG80211, (caddr_t)&nwkey)) == -1) { close(s); return (-1); } #endif close(s); #ifdef __OpenBSD__ if (inwkey == 0 && nwkey.i_wepon > 0) r = 1; #endif #ifdef __FreeBSD__ if (inwkey == 0 && nwkey.i_val > 0) r = 1; #endif return (r); } /* * get_channel() * get channel number * Return: * = success, 0 = no data, -1 = error */ int get_channel(const char *interface) { int s, ichan; #ifdef __OpenBSD__ struct ieee80211chanreq channel; #endif #ifdef __FreeBSD__ struct ieee80211req channel; #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (-1); memset(&channel, 0, sizeof(channel)); #ifdef __FreeBSD__ channel.i_type = IEEE80211_IOC_CHANNEL; #endif strlcpy(channel.i_name, interface, sizeof(channel.i_name)); #ifdef __OpenBSD__ if ((ichan = ioctl(s, SIOCG80211CHANNEL, (caddr_t)&channel)) == -1) { close(s); return (-1); } #endif #ifdef __FreeBSD__ if ((ichan = ioctl(s, SIOCG80211, (caddr_t)&channel)) == -1) { close(s); return (-1); } #endif close(s); if (ichan == 0) { #ifdef __OpenBSD__ if (channel.i_channel < 1000) return (channel.i_channel); #endif #ifdef __FreeBSD__ if (channel.i_val < 1000) return (channel.i_val); #endif } return (0); } /* * get_signal() * get signal strength * Return: * = success, 0 = no data, -1 = error */ int get_signal(const char *interface, const char *network) { #ifdef __OpenBSD__ int i = 0, s, len; struct ieee80211_nodereq_all na; struct ieee80211_nodereq nr[8]; #endif #ifdef __FreeBSD__ int s, len; uint8_t buf[24 * 1024], *cp; struct ieee80211req na; #endif char network_id[IEEE80211_NWID_LEN + 1]; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (-1); memset(&na, 0, sizeof(na)); #ifdef __OpenBSD__ memset(&nr, 0, sizeof(nr)); na.na_node = nr; na.na_size = sizeof(nr); strlcpy(na.na_ifname, interface, sizeof(na.na_ifname)); #endif #ifdef __FreeBSD__ strlcpy(na.i_name, interface, sizeof(na.i_name)); na.i_type = IEEE80211_IOC_SCAN_RESULTS; na.i_data = buf; na.i_len = sizeof(buf); #endif #ifdef __OpenBSD__ if (ioctl(s, SIOCG80211ALLNODES, &na) == -1) { close(s); return (-1); } #endif #ifdef __FreeBSD__ if (ioctl(s, SIOCG80211, (caddr_t)&na) == -1) { close(s); return (-1); } #endif close(s); #ifdef __OpenBSD__ for (i = 0; i < na.na_nodes; i++) { if (nr[i].nr_nwid_len < sizeof(network_id)) len = nr[i].nr_nwid_len + 1; else len = sizeof(network_id); strlcpy(network_id, (const char *)nr[i].nr_nwid, len); if (!strcmp(network_id, network)) return (nr[i].nr_rssi); } #endif #ifdef __FreeBSD__ /* This is how ifconfig does it */ len = na.i_len; cp = buf; do { struct ieee80211req_scan_result *sr; uint8_t *vp; sr = (struct ieee80211req_scan_result *)cp; vp = (u_int8_t *)(sr + 1); strlcpy(network_id, (const char *)vp, sr->isr_ssid_len + 1); if (!strcmp(network_id, network)) return (sr->isr_rssi); cp += sr->isr_len; len -= sr->isr_len; if (sr->isr_len <= 0) /* Some weird lockup */ break; } while (len >= sizeof(struct ieee80211req_scan_result)); #endif return (0); } /* * get_wi_signal() * get signal strength for wi interfaces * Return: * = success, -1 = error */ int get_wi_signal(const char *interface) { int s; struct ifreq ifr; struct wi_req wreq; #ifdef __OpenBSD__ float link; #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (-1); bzero((char *)&wreq, sizeof(wreq)); bzero((char *)&ifr, sizeof(ifr)); wreq.wi_len = WI_MAX_DATALEN; wreq.wi_type = WI_RID_COMMS_QUALITY; ifr.ifr_data = (caddr_t)&wreq; strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGWAVELAN, &ifr) == -1) { close(s); return (-1); } close(s); #ifdef __OpenBSD__ link = wreq.wi_val[0]; /* * for future reference ... * level = wreq.wi_val[1]; * noise = wreq.wi_val[2]; */ return (letoh16(link)); #endif #ifdef __FreeBSD__ return (wreq.wi_val[1]); #endif } /* * get_speed() * get media speed * Return: * = success, NULL = no data / error */ char * get_speed(const char *interface) { int s, mword; struct ifmediareq ifmr; const struct ifmedia_description *desc; #ifdef __OpenBSD__ const struct ifmedia_description ifm_subtype_descriptions[] = IFM_SUBTYPE_DESCRIPTIONS; #endif #ifdef __FreeBSD__ const struct ifmedia_description ifm_subtype_descriptions[] = IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (NULL); memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, interface, sizeof(ifmr.ifm_name)); if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { close(s); return (NULL); } close(s); mword = ifmr.ifm_active; for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL; desc++) { if (IFM_TYPE_MATCH(desc->ifmt_word, mword) && IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword)) return (translate_speed(desc->ifmt_string)); } return (NULL); } /* * get_status() * get network status * Return: * = success, NULL = no data / error */ char * get_status(const char *interface) { #ifdef __OpenBSD__ int s, bitno; static char status[64]; const struct ifmedia_status_description *ifms; const struct ifmedia_status_description ifm_status_descriptions[] = IFM_STATUS_DESCRIPTIONS; const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; #endif #ifdef __FreeBSD__ int s; #endif struct ifmediareq ifmr; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (NULL); memset(&ifmr, 0, sizeof(ifmr)); strlcpy(ifmr.ifm_name, interface, sizeof(ifmr.ifm_name)); if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { close(s); return (NULL); } close(s); #ifdef __OpenBSD__ for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) { for (ifms = ifm_status_descriptions; ifms->ifms_valid != 0; ifms++) { if (ifms->ifms_type != IFM_TYPE(ifmr.ifm_current) || ifms->ifms_valid != ifm_status_valid_list[bitno]) continue; strlcpy(status, IFM_STATUS_DESC(ifms, ifmr.ifm_status), sizeof(status)); return (status); } } return (NULL); #endif #ifdef __FreeBSD__ if (ifmr.ifm_status & IFM_ACTIVE) return ("active"); return ("no carrier"); #endif } /* * get_nwid() * get wireless network id * Return: * pointer to network id = success, NULL = no data / error */ char * get_nwid(const char *interface) { int s, len, inwid; static char network_id[IEEE80211_NWID_LEN + 1]; #ifdef __OpenBSD__ struct ifreq ifr; struct ieee80211_nwid nwid; #endif #ifdef __FreeBSD__ struct ieee80211req nwid; #endif if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return (NULL); #ifdef __OpenBSD__ memset(&ifr, 0, sizeof(ifr)); ifr.ifr_data = (caddr_t)&nwid; strlcpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); #endif #ifdef __FreeBSD__ memset(&nwid, 0, sizeof(nwid)); strlcpy(nwid.i_name, interface, sizeof(nwid.i_name)); nwid.i_type = IEEE80211_IOC_SSID; nwid.i_data = network_id; nwid.i_len = sizeof(network_id); #endif #ifdef __OpenBSD__ if ((inwid = ioctl(s, SIOCG80211NWID, (caddr_t)&ifr)) == -1) { close(s); return (NULL); } #endif #ifdef __FreeBSD__ if ((inwid = ioctl(s, SIOCG80211, (caddr_t)&nwid)) == -1) { close(s); return (NULL); } #endif close(s); if (inwid == 0) { if (nwid.i_len < sizeof(network_id)) len = nwid.i_len + 1; else len = sizeof(network_id); #ifdef __OpenBSD__ strlcpy(network_id, (const char *)nwid.i_nwid, len); #endif #ifdef __FreeBSD__ network_id[len - 1] = '\0'; #endif return (network_id); } return (NULL); } /* * get_first_wnic() * scans interfaces and returns the first found wireless interface * Return: * = success, NULL = no nic found */ char * get_first_wnic(void) { char *r = NULL; char nic[IF_NAMESIZE]; struct ifaddrs *ifap = NULL, *ifa = NULL; memset(nic, 0, sizeof(nic)); if (getifaddrs(&ifap) != 0) errx(1, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcmp(nic, ifa->ifa_name)) { if (get_wep(ifa->ifa_name) != -1) { r = strdup(ifa->ifa_name); break; } } strlcpy(nic, ifa->ifa_name, sizeof(nic)); } freeifaddrs(ifap); return (r); } /* * check_nic() * check if the monitored interface still exists * Return: * 0 = interface gone, 1 = interface exists */ int check_nic(const char *interface) { int r = 0; char nic[IF_NAMESIZE]; struct ifaddrs *ifap = NULL, *ifa = NULL; memset(nic, 0, sizeof(nic)); if (getifaddrs(&ifap) != 0) errx(1, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (strcmp(nic, ifa->ifa_name)) { if (!strcmp(ifa->ifa_name, interface)) { r = 1; break; } } strlcpy(nic, ifa->ifa_name, sizeof(nic)); } freeifaddrs(ifap); return (r); } /* * translate_speed() * translate the result of media speed to human readable string * Return: * = success, NULL = no data / error */ char * translate_speed(const char *mode) { int i; for (i = 0; speed[i] != NULL; i++) { if (!strcmp(mode, speed[i])) return (speed[i + 1]); } return (NULL); }