dockapps/wmwlmon/wl.c
2014-10-05 19:18:49 +01:00

574 lines
12 KiB
C

/* $Id: wl.c,v 1.18 2008/05/13 04:42:17 hacki Exp $ */
/*
* Copyright (c) 2005, 2006 Marcus Glocker <marcus@nazgul.ch>
*
* 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 <nslay@hotmail.com> 4/30/06 */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#ifdef __OpenBSD__
#include <dev/ic/if_wi_ieee.h>
#endif
#ifdef __FreeBSD__
#include <dev/wi/if_wavelan_ieee.h>
#endif
#include <err.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_ioctl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#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:
* <channel number> = 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:
* <signal strength> = 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:
* <signal strength> = 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:
* <pointer to speed> = 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:
* <pointer to status> = 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:
* <pointer to wnic> = 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:
* <pointer to speed> = 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);
}