From 9a5162c33017bab6677c528189cff5a501f3822a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 9 Aug 2003 16:36:18 +0000 Subject: netlink monitoring aded wireless querying improved git-svn-id: file:///home/lennart/svn/public/ifplugd/trunk@30 2bf48fe7-cfc1-0310-909f-d9042e1e0fef --- bootstrap.sh | 2 +- conf/ifplugd.conf | 4 +- src/Makefile.am | 4 +- src/ifmonitor.c | 76 ++++++ src/ifmonitor.h | 26 ++ src/ifplugd.c | 250 +++++++++++++------ src/ifstatus.c | 49 ++-- src/interface.c | 108 +++++++-- src/interface.h | 1 - src/nlapi.c | 131 ++++++++++ src/nlapi.h | 39 +++ src/wireless.15.h | 698 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1258 insertions(+), 130 deletions(-) create mode 100644 src/ifmonitor.c create mode 100644 src/ifmonitor.h create mode 100644 src/nlapi.c create mode 100644 src/nlapi.h create mode 100644 src/wireless.15.h diff --git a/bootstrap.sh b/bootstrap.sh index 27dff71..6813f92 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -34,6 +34,6 @@ else automake -a -c autoconf -Wall - ./configure "$@" + ./configure --sysconfdir=/etc "$@" fi diff --git a/conf/ifplugd.conf b/conf/ifplugd.conf index 0a48c37..7e53334 100644 --- a/conf/ifplugd.conf +++ b/conf/ifplugd.conf @@ -31,4 +31,6 @@ INTERFACES="eth0" # Additional parameters for ifplugd. # (Run "ifplugd -h" for further information.) -ARGS="-f -u0 -d10 -w -I" +ARGS="-fwI -u0 -d10" + +ARGS_wlan0="-MwI -u5 -d5" diff --git a/src/Makefile.am b/src/Makefile.am index cd2d344..e0831c5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,8 +19,8 @@ AM_CFLAGS = -DSYSCONFDIR="\"$(sysconfdir)\"" sbin_PROGRAMS = ifplugd ifstatus -ifplugd_SOURCES = ifplugd.c interface.c interface.h ethtool-kernel.h ethtool-local.h svn-revision.h -ifstatus_SOURCES = ifstatus.c interface.c interface.h ethtool-kernel.h ethtool-local.h svn-revision.h +ifplugd_SOURCES = ifplugd.c interface.c interface.h ethtool-kernel.h ethtool-local.h svn-revision.h wireless.15.h ifmonitor.h ifmonitor.c nlapi.h nlapi.c +ifstatus_SOURCES = ifstatus.c interface.c interface.h ethtool-kernel.h ethtool-local.h svn-revision.h wireless.15.h MAINTAINERCLEANFILES = svn-revision.h diff --git a/src/ifmonitor.c b/src/ifmonitor.c new file mode 100644 index 0000000..d49160b --- /dev/null +++ b/src/ifmonitor.c @@ -0,0 +1,76 @@ +/* $Id: ifplugd.c 1.12 Sat, 01 Feb 2003 03:00:07 +0100 lennart $ */ + +/* + * This file is part of ifplugd. + * + * ifplugd is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ifplugd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ifplugd; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nlapi.h" + +static int callback(struct nlmsghdr *n, void *u) { + int (*cb)(int b, int index, unsigned short type, const char *name) = u; + + if (n->nlmsg_type == RTM_NEWLINK || n->nlmsg_type == RTM_DELLINK) { + struct rtattr *a; + struct ifinfomsg *i; + char ifname[IFNAMSIZ+1]; + int la; + + i = NLMSG_DATA(n); + + if (n->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) { + fprintf(stderr, "NETLINK: Packet too small or truncated! (2)\n"); + return -1; + } + + memset(&ifname, 0, sizeof(ifname)); + + a = (void*) i + NLMSG_ALIGN(sizeof(struct ifinfomsg)); + la = NLMSG_PAYLOAD(n, sizeof(struct ifinfomsg)); + + while (RTA_OK(a, la)) { + + if(a->rta_type == IFLA_IFNAME) { + int l = RTA_PAYLOAD(a); + if (l > IFNAMSIZ) + l = IFNAMSIZ; + strncpy(ifname, RTA_DATA(a), l); + } + + a = RTA_NEXT(a, la); + } + + if (cb(n->nlmsg_type == RTM_NEWLINK, i->ifi_index, i->ifi_type, ifname[0] ? ifname : NULL) < 0) + return -1; + } + + + return 0; +} + +int ifmonitor_init(int (*cb) (int b, int index, unsigned short type, const char *name)) { + return nlapi_register(callback, cb); +} diff --git a/src/ifmonitor.h b/src/ifmonitor.h new file mode 100644 index 0000000..ada8855 --- /dev/null +++ b/src/ifmonitor.h @@ -0,0 +1,26 @@ +#ifndef fooifmonitorhfoo +#define fooifmonitorhfoo + +/* $Id: ifplugd.c 1.12 Sat, 01 Feb 2003 03:00:07 +0100 lennart $ */ + +/* + * This file is part of ifplugd. + * + * ifplugd is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ifplugd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ifplugd; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +int ifmonitor_init(int (*cb) (int b, int index, unsigned short type, const char *name)); + +#endif diff --git a/src/ifplugd.c b/src/ifplugd.c index 9445383..645efc5 100644 --- a/src/ifplugd.c +++ b/src/ifplugd.c @@ -50,6 +50,8 @@ #include "ethtool-local.h" #include "interface.h" +#include "nlapi.h" +#include "ifmonitor.h" #include "svn-revision.h" #ifdef HAVE_CONFIG_H @@ -60,17 +62,34 @@ #define IFPLUGD_ENV_PREVIOUS "IFPLUGD_PREVIOUS" #define IFPLUGD_ENV_CURRENT "IFPLUGD_CURRENT" -int interface_auto_up = 1, interface_do_message = 1; +int interface_auto_up = 1, + interface_do_message = 1; -char *interface = "eth0"; +char *interface = NULL; char *run = SYSCONFDIR"/ifplugd/ifplugd.action"; char *extra_arg = NULL; -int polltime = 1, delay_up = 0, delay_down = 5; -int daemonize = 1, use_beep = 1, no_shutdown_script = 0, wait_on_fork = 0, use_syslog = 1, ignore_retval = 0, initial_down = 0; + +int polltime = 1, + delay_up = 0, + delay_down = 5; + +int daemonize = 1, + use_beep = 1, + no_shutdown_script = 0, + wait_on_fork = 0, + use_syslog = 1, + ignore_retval = 0, + initial_down = 0, + use_ifmonitor = 0; + +int disabled = 0; + interface_status_t failure_status = IFSTATUS_ERR; enum { API_AUTO, API_ETHTOOL, API_MII, API_PRIVATE, API_WLAN } api_mode = API_AUTO; + interface_status_t (*detect_beat_func)(int, char*); +interface_status_t (*cached_detect_beat_func)(int, char*) = NULL; // 0: high, 1: low, 2: very low void beep(int b) { @@ -234,31 +253,30 @@ int action(interface_status_t status) { interface_status_t detect_beat_auto(int fd, char *iface) { interface_status_t status; - static interface_status_t (*cached_func)(int, char*) = NULL; - if (cached_func && (status = cached_func(fd, iface)) != IFSTATUS_ERR) + if (cached_detect_beat_func && (status = cached_detect_beat_func(fd, iface)) != IFSTATUS_ERR) return status; if ((status = interface_detect_beat_mii(fd, iface)) != IFSTATUS_ERR) { - cached_func = interface_detect_beat_mii; + cached_detect_beat_func = interface_detect_beat_mii; daemon_log(LOG_INFO, "Using detection mode: SIOCGMIIPHY"); return status; } if ((status = interface_detect_beat_ethtool(fd, iface)) != IFSTATUS_ERR) { - cached_func = interface_detect_beat_ethtool; + cached_detect_beat_func = interface_detect_beat_ethtool; daemon_log(LOG_INFO, "Using detection mode: SIOCETHTOOL"); return status; } if ((status = interface_detect_beat_wlan(fd, iface)) != IFSTATUS_ERR) { - cached_func = interface_detect_beat_wlan; + cached_detect_beat_func = interface_detect_beat_wlan; daemon_log(LOG_INFO, "Using detection mode: wireless extension"); return status; } if ((status = interface_detect_beat_priv(fd, iface)) != IFSTATUS_ERR) { - cached_func = interface_detect_beat_priv; + cached_detect_beat_func = interface_detect_beat_priv; daemon_log(LOG_INFO, "Using detection mode: SIOCDEVPRIVATE"); return status; } @@ -279,11 +297,14 @@ interface_status_t detect_beat(int fd, char*iface) { interface_status_t status; static interface_status_t last_status = (interface_status_t) -1; + if (disabled) + return IFSTATUS_DOWN; + if ((status = detect_beat_func(fd, iface)) == IFSTATUS_ERR) status = failure_status; if (status == IFSTATUS_ERR && detect_beat_func == detect_beat_auto) - daemon_log(LOG_INFO, "Failed to find working plug detection mode for %s", interface); + daemon_log(LOG_INFO, "Failed to detect plug status of %s", interface); if (status != last_status) { setenv(IFPLUGD_ENV_PREVIOUS, strstatus(last_status), 1); @@ -294,17 +315,11 @@ interface_status_t detect_beat(int fd, char*iface) { return status; } -int open_iface(char *iface) { - int fd; +int welcome_iface(int fd, char *iface) { struct ifreq ifr; struct ethtool_drvinfo drvinfo; char txt[256]; - if ((fd = interface_open(iface)) < 0) { - daemon_log(LOG_ERR, "Could not create socket: %s", strerror(errno)); - return fd; - } - if (interface_auto_up) interface_up(fd, iface); @@ -326,14 +341,40 @@ int open_iface(char *iface) { daemon_log(LOG_INFO, "%s with driver <%s> (version: %s)", txt, drvinfo.driver, drvinfo.version); else daemon_log(LOG_INFO, "%s", txt); - - return fd; + + cached_detect_beat_func = NULL; + + return 0; +} + +int ifmonitor_cb(int b, int index, unsigned short type, const char *name) { + if (!name) + return 0; + + if (!strcmp(name, interface)) + disabled = !b; + + return 0; } -void work() { +int is_iface_available(int s, char *p) { + struct ifreq req; + int r; + + memset(&req, 0, sizeof(req)); + strncpy(req.ifr_name, p, IFNAMSIZ); + + if ((r = ioctl(s, SIOCGIFINDEX, &req)) < 0 && errno != ENODEV) { + daemon_log(LOG_ERR, "SIOCGIFINDEX failed: %s\n", strerror(errno)); + return -1; + } + return r >= 0 && req.ifr_ifindex >= 0; +} + +void work(void) { interface_status_t status; int fd = -1; - fd_set rfds; + fd_set fds; int sigfd; time_t t = 0; int send_retval = 1; @@ -344,7 +385,9 @@ void work() { daemon_log_ident = log_ident; + daemon_log(LOG_INFO, "ifplugd "VERSION" initializing%s.", use_ifmonitor ? ", using NETLINK device monitoring" : ""); + if (daemon_pid_file_create() < 0) { daemon_log(LOG_ERR, "Could not create PID file %s.", daemon_pid_file_proc()); goto finish; @@ -367,13 +410,37 @@ void work() { break; } - if ((fd = open_iface(interface)) < 0) - goto finish; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + daemon_log(LOG_ERR, "socket(): %s", strerror(errno)); + goto finish; + } + + if (use_ifmonitor) { + int b; + if ((b = is_iface_available(fd, interface)) < 0) { + daemon_log(LOG_ERR, "Failed to check interface availabilty!"); + goto finish; + } + + disabled = !b; + + if (nlapi_open(RTMGRP_LINK) < 0) + goto finish; + + if (ifmonitor_init(ifmonitor_cb) < 0) + goto finish; + } else + disabled = 0; + + if (!disabled) { + if (welcome_iface(fd, interface) < 0) + goto finish; + } if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR) goto finish; - daemon_log(LOG_INFO, "ifplugd "VERSION" successfully initialized, link beat %sdetected.", status == IFSTATUS_UP ? "" : "not "); + daemon_log(LOG_INFO, "Initialization complete, link beat %sdetected%s.", status == IFSTATUS_UP ? "" : "not ", use_ifmonitor ? (disabled ? ", interface disabled" : ", interface enabled") : ""); beep(status == IFSTATUS_UP ? 0 : 1); if (status == IFSTATUS_UP || initial_down) @@ -386,24 +453,49 @@ void work() { send_retval = 0; } - FD_ZERO(&rfds); - FD_SET(sigfd = daemon_signal_fd(), &rfds); + FD_ZERO(&fds); + FD_SET(sigfd = daemon_signal_fd(), &fds); + + if (use_ifmonitor) + FD_SET(nlapi_fd, &fds); for (;;) { - interface_status_t r; - fd_set wrfds = rfds; + interface_status_t s; + fd_set qfds = fds; + int d; struct timeval tv = { polltime, 0 }; - if (select(FD_SETSIZE, &wrfds, NULL, NULL, &tv) < 0) { + if (select(FD_SETSIZE, &qfds, NULL, NULL, &tv) < 0) { if (errno == EINTR) continue; daemon_log(LOG_ERR, "select(): %s", strerror(errno)); goto finish; } - - if (FD_ISSET(sigfd, &wrfds)) { + d = disabled; + s = status; + + if (use_ifmonitor) { + + if (FD_ISSET(nlapi_fd, &qfds)) { + if (nlapi_work(0) < 0) + goto finish; + } + + if (d && !disabled) { + daemon_log(LOG_INFO, "Interface enabled"); + if (welcome_iface(fd, interface) < 0) + goto finish; + } + + if (!d && disabled) { + daemon_log(LOG_INFO, "Interface disabled"); + status = IFSTATUS_DOWN; + } + } + + if (FD_ISSET(sigfd, &qfds)) { int sig; if ((sig = daemon_signal_next()) < 0) { @@ -411,7 +503,6 @@ void work() { goto finish; } - switch (sig) { case SIGINT: @@ -426,6 +517,9 @@ void work() { case SIGHUP: daemon_log(LOG_INFO, "SIGHUP: %s, link detected on %s: %s", paused ? "Suspended" : "Running", interface, status == IFSTATUS_DOWN ? "no" : "yes"); + + if (use_ifmonitor) + daemon_log(LOG_INFO, "SIGHUP: Interface %s", disabled ? "disabled" : "enabled"); break; case SIGUSR1: @@ -447,32 +541,33 @@ void work() { } - if (!paused) { - if ((r = detect_beat(fd, interface)) == IFSTATUS_ERR) - break; - - if (status != r) { - status = r; - - daemon_log(LOG_INFO, "Link beat %s.", status == IFSTATUS_DOWN ? "lost" : "detected"); - beep(status == IFSTATUS_UP ? 0 : 1); - - - if (t) - t = 0; - else { - t = time(NULL); - - if (status == IFSTATUS_UP) - t += delay_up; - - if (status == IFSTATUS_DOWN) - t += delay_down; - } + if (!paused && !disabled) { + //daemon_log(LOG_INFO, "detect"); + if ((status = detect_beat(fd, interface)) == IFSTATUS_ERR) { + if (!use_ifmonitor) + break; + + status = IFSTATUS_DOWN; + } + } + + if (status != s) { + daemon_log(LOG_INFO, "Link beat %s.", status == IFSTATUS_DOWN ? "lost" : "detected"); + beep(status == IFSTATUS_UP ? 0 : 1); + + if (t) + t = 0; + else { + t = time(NULL); + + if (status == IFSTATUS_UP) + t += delay_up; + + if (status == IFSTATUS_DOWN) + t += delay_down; } } - if (t && t < time(NULL)) { t = 0; @@ -494,6 +589,9 @@ finish: if (fd >= 0) close(fd); + if (use_ifmonitor) + nlapi_close(); + if (send_retval && daemonize && wait_on_fork) daemon_retval_send(1); @@ -517,7 +615,9 @@ void usage(char *p) { if (strrchr(p, '/')) p = strchr(p, '/')+1; - printf("%s [options]\n" + printf("%s -- Network Interface Plug Detection Daemon\n\n" + "Usage: %s [options]\n\n" + "Options:\n" " -a --no-auto Do not enable interface automatically (%s)\n" " -n --no-daemon Do not daemonize (for debugging) (%s)\n" " -s --no-syslog Do not use syslog, use stderr instead (for debugging) (%s)\n" @@ -532,17 +632,18 @@ void usage(char *p) { " -d --delay-down=SECS Specify delay for deconfiguring interface (%i)\n" " -m --api-mode=MODE Force API mode (mii, priv, ethtool, wlan, auto) (%s)\n" " -q --no-shutdown Don't run script on daemon quit (%s)\n" - " -l --initial-down Run \"down\" script on startup if now cable is detected (%s)\n" + " -l --initial-down Run \"down\" script on startup if now cable is detected (%s)\n" " -w --wait-on-fork Wait until daemon fork finished (%s)\n" - " -x --extra-arg Specify an extra argument for action script\n" + " -x --extra-arg Specify an extra argument for action script\n" + " -M --monitor Use interface monitoring (%s)\n" " -h --help Show this help\n" " -k --kill Kill a running daemon\n" - " -c --check-running Check if a daemon is currently running\n" + " -c --check-running Check if a daemon is currently running\n" " -v --version Show version\n" " -S --suspend Suspend running daemon\n" " -R --resume Resume running daemon\n" " -z --info Write status of running daemon to syslog\n", - p, + p, p, !interface_auto_up ? "on" : "off", !daemonize ? "on" : "off", !use_syslog ? "on" : "off", @@ -557,8 +658,9 @@ void usage(char *p) { delay_down, m, no_shutdown_script ? "on" : "off", - initial_down ? "on" : "off", - wait_on_fork ? "on" : "off"); + initial_down ? "on" : "off", + wait_on_fork ? "on" : "off", + use_ifmonitor ? "on" : "off"); } void parse_args(int argc, char *argv[]) { @@ -586,7 +688,8 @@ void parse_args(int argc, char *argv[]) { {"suspend", no_argument, 0, 'S'}, {"resume", no_argument, 0, 'R'}, {"info", no_argument, 0, 'z'}, - {"inital-down", no_argument, 0, 'l'}, + {"inital-down", no_argument, 0, 'l'}, + {"monitor", no_argument, 0, 'M'}, {0, 0, 0, 0} }; int option_index = 0; @@ -595,7 +698,7 @@ void parse_args(int argc, char *argv[]) { for (;;) { int c; - if ((c = getopt_long(argc, argv, "asni:r:t:u:d:hkbfFvm:qwx:cISRzl", long_options, &option_index)) < 0) + if ((c = getopt_long(argc, argv, "asni:r:t:u:d:hkbfFvm:qwx:cISRzlM", long_options, &option_index)) < 0) break; switch (c) { @@ -609,6 +712,8 @@ void parse_args(int argc, char *argv[]) { daemonize = !daemonize; break; case 'i' : + if (interface) + free(interface); interface = strdup(optarg); break; case 'r': @@ -663,9 +768,9 @@ void parse_args(int argc, char *argv[]) { case 'q': no_shutdown_script = !no_shutdown_script; break; - case 'l': - initial_down = !initial_down; - break; + case 'l': + initial_down = !initial_down; + break; case 'w': wait_on_fork = !wait_on_fork; break; @@ -681,6 +786,9 @@ void parse_args(int argc, char *argv[]) { case 'z': _info = 1; break; + case 'M': + use_ifmonitor = !use_ifmonitor; + break; default: fprintf(stderr, "Unknown parameter.\n"); exit(1); @@ -688,6 +796,9 @@ void parse_args(int argc, char *argv[]) { } + if (!interface) + interface = strdup("eth0"); + if (!use_syslog) daemon_log_use = DAEMON_LOG_STDERR; @@ -752,8 +863,7 @@ int main(int argc, char* argv[]) { return 2; } - - if (daemon_pid_file_is_running() >= 0) { + if (daemon_pid_file_is_running() >= 0) { daemon_log(LOG_ERR, "Sorry, there is already an instance of ifplugd for %s running.", interface); return 4; } diff --git a/src/ifstatus.c b/src/ifstatus.c index 35a0b48..655d16f 100644 --- a/src/ifstatus.c +++ b/src/ifstatus.c @@ -45,7 +45,7 @@ int handle(char *iface) { int fd, r = 0; interface_status_t s; - if ((fd = interface_open(iface)) < 0) + if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) return -1; if (verbose > 0) { @@ -189,45 +189,32 @@ int main(int argc, char *argv[]) { return r+1; } else { - struct ifconf ifconf; - struct ifreq *ifr; - int m, n, s, fd; + FILE *f; + char ln[256]; - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "socket(): %s\n", strerror(errno)); + if (!(f = fopen("/proc/net/dev", "r"))) { + fprintf(stderr, "Failed to open /proc/net/dev: %s\n", strerror(errno)); return 1; } - s = sizeof(struct ifreq)*5; - for (;;) { - ifr = malloc(s); + fgets(ln, sizeof(ln), f); + fgets(ln, sizeof(ln), f); - ifconf.ifc_len = s; - ifconf.ifc_req = ifr; - - if (ioctl(fd, SIOCGIFCONF, &ifconf) < 0) { - fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); - free(ifr); - close(fd); + while (fgets(ln, sizeof(ln), f)) { + char *p, *e; + + p = ln+strspn(ln, " \t"); + if (!(e = strchr(p, ':'))) { + fprintf(stderr, "Parse failure in /proc/net/dev.\n"); + fclose(f); return 1; } - - - if (ifconf.ifc_len != s) - break; - - free(ifr); - s *= 2; - } - close(fd); + *e = 0; + handle(p); + } - m = ifconf.ifc_len/sizeof(struct ifreq); - for (n = 0; n < m; n++) - if (strcmp(ifconf.ifc_req[n].ifr_name, "lo")) - handle(ifconf.ifc_req[n].ifr_name); - - free(ifr); + fclose(f); } return 0; diff --git a/src/interface.c b/src/interface.c index 894922c..8f0a8f1 100644 --- a/src/interface.c +++ b/src/interface.c @@ -19,9 +19,11 @@ */ #include +#include #include +#include #include -#include +#include #include #include #include @@ -29,16 +31,14 @@ #include #include #include +#include #include "ethtool-local.h" #include "interface.h" +#include "wireless.15.h" #include -int interface_open(char *iface) { - return socket(AF_INET, SOCK_DGRAM, 0); -} - void interface_up(int fd, char *iface) { struct ifreq ifr; @@ -69,7 +69,6 @@ void interface_up(int fd, char *iface) { } } - if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { if (interface_do_message) daemon_log(LOG_WARNING, "Warning: Could not get interface flags."); @@ -164,14 +163,12 @@ interface_status_t interface_detect_beat_ethtool(int fd, char *iface) { return edata.data ? IFSTATUS_UP : IFSTATUS_DOWN; } -interface_status_t interface_detect_beat_wlan(int fd, char *iface) { + +static int get_wlan_qual_old(char *iface) { FILE *f; char buf[256]; char *bp; - int l; - - if (interface_auto_up) - interface_up(fd, iface); + int l, q = -1; l = strlen(iface); @@ -179,7 +176,7 @@ interface_status_t interface_detect_beat_wlan(int fd, char *iface) { if (interface_do_message) daemon_log(LOG_WARNING, "Failed to open /proc/net/wireless: %s",strerror(errno)); - return IFSTATUS_ERR; + return -1; } while (fgets(buf, sizeof(buf)-1, f)) { @@ -190,30 +187,93 @@ interface_status_t interface_detect_beat_wlan(int fd, char *iface) { if(!strncmp(bp, iface, l) && bp[l]==':') { - /*skip device name */ + /* skip device name */ if (!(bp = strchr(bp,' '))) break; bp++; - /*skip status*/ + /* skip status */ if (!(bp = strchr(bp,' '))) break; - fclose(f); - - if (atoi(bp) > 0) - return IFSTATUS_UP; - else - return IFSTATUS_DOWN; + q = atoi(bp); + break; }; } + + fclose(f); + + if (q < 0) { + if (interface_do_message) + daemon_log(LOG_ERR, "Failed to find interface in /proc/net/wireless"); + } + + return q; +} + +static int get_wlan_qual_new(int fd, char *iface) { + struct iwreq req; + struct iw_statistics q; + + memset(&req, 0, sizeof(req)); + strncpy(req.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); + + req.u.data.pointer = (caddr_t) &q; + req.u.data.length = sizeof(q); + req.u.data.flags = 1; + + if (ioctl(fd, SIOCGIWSTATS, &req) < 0) { + if (interface_do_message) + daemon_log(LOG_ERR, "Failed to get interface quality: %s\n", strerror(errno)); + return -1; + } + + return q.qual.qual; +} + + +static int is_assoc_ap(uint8_t mac[ETH_ALEN]) { + int b, j; + b = 1; - if (interface_do_message) - daemon_log(LOG_ERR, "Failed to find wireless interface %s\n", iface); + for (j = 1; j < ETH_ALEN; j++) + if (mac[j] != mac[0]) { + b = 0; + break; + } + + return !b || (mac[0] != 0xFF && mac[0] != 0x44 && mac[0] != 0x00); +} + +interface_status_t interface_detect_beat_wlan(int fd, char *iface) { + if (interface_auto_up) + interface_up(fd, iface); - fclose(f); + + uint8_t mac[6]; + int q; + struct iwreq req; + + memset(&req, 0, sizeof(req)); + strncpy(req.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); + + if (ioctl(fd, SIOCGIWAP, &req) < 0) { + if (interface_do_message) + daemon_log(LOG_WARNING, "Failed to get AP address: %s",strerror(errno)); + return IFSTATUS_ERR; + } + + if (!is_assoc_ap(mac)) + return IFSTATUS_DOWN; + + if ((q = get_wlan_qual_new(fd, iface)) < 0) + if ((q = get_wlan_qual_old(iface)) < 0) { + if (interface_do_message) + daemon_log(LOG_WARNING, "Failed to get wireless link quality."); + return IFSTATUS_ERR; + } - return IFSTATUS_ERR; + return q > 0 ? IFSTATUS_UP : IFSTATUS_DOWN; } diff --git a/src/interface.h b/src/interface.h index 2f9490e..d1f3826 100644 --- a/src/interface.h +++ b/src/interface.h @@ -26,7 +26,6 @@ int interface_do_message; typedef enum { IFSTATUS_UP, IFSTATUS_DOWN, IFSTATUS_ERR } interface_status_t; -int interface_open(char *iface); void interface_up(int fd, char *iface); interface_status_t interface_detect_beat_mii(int fd, char *iface); diff --git a/src/nlapi.c b/src/nlapi.c new file mode 100644 index 0000000..33b222b --- /dev/null +++ b/src/nlapi.c @@ -0,0 +1,131 @@ +/* $Id: ifplugd.c 1.12 Sat, 01 Feb 2003 03:00:07 +0100 lennart $ */ + +/* + * This file is part of ifplugd. + * + * ifplugd is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ifplugd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ifplugd; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "nlapi.h" + +int nlapi_fd = -1; + +struct callback_info { + nlapi_callback_t callback; + void *userdata; + struct callback_info * next; +}; + +struct callback_info *callbacks = NULL; + +int nlapi_open(uint32_t groups) { + struct sockaddr_nl addr; + + if ((nlapi_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) { + fprintf(stderr, "socket(PF_NETLINK): %s\n", strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_groups = groups; + addr.nl_pid = getpid(); + + if (bind(nlapi_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(nlapi_fd); + fprintf(stderr, "bind(): %s\n", strerror(errno)); + return -1; + } + + return 0; +} + +int nlapi_work(int block) { + + assert(nlapi_fd >= 0); + + for (;;) { + int bytes; + char replybuf[1024]; + struct nlmsghdr *p = (struct nlmsghdr *) replybuf; + + if ((bytes = recv(nlapi_fd, &replybuf, sizeof(replybuf), block ? 0 : MSG_DONTWAIT)) < 0) { + + if (errno == EAGAIN || errno == EINTR) + return 0; + + daemon_log(LOG_ERR, "NLAPI: recv(): %s\n", strerror(errno)); + return -1; + } + + for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) { + struct callback_info *c; + + if (!NLMSG_OK(p, bytes) || bytes < sizeof(struct nlmsghdr) || bytes < p->nlmsg_len) { + daemon_log(LOG_ERR, "NLAPI: Packet too small or truncated!\n"); + return -1; + } + + for (c = callbacks; c; c = c->next) + if (c->callback(p, c->userdata) < 0) + return -1; + } + + if (block) + break; + } + + return 0; +} + +void nlapi_close(void) { + if (nlapi_fd >= 0) + close(nlapi_fd); + nlapi_fd = -1; + + + while (callbacks) { + struct callback_info *c = callbacks; + callbacks = callbacks->next; + free(c); + } +} + +int nlapi_register(int (*callback) (struct nlmsghdr *n, void *u), void *u) { + struct callback_info *c; + + assert(callback); + + if (!(c = malloc(sizeof(struct callback_info)))) { + daemon_log(LOG_ERR, "NLAPI: Not enough memory.\n"); + return -1; + } + + c->callback = callback; + c->userdata = u; + + c->next = callbacks; + callbacks = c; + return 0; +} diff --git a/src/nlapi.h b/src/nlapi.h new file mode 100644 index 0000000..b810e20 --- /dev/null +++ b/src/nlapi.h @@ -0,0 +1,39 @@ +#ifndef foonlapihfoo +#define foonlapihfoo + +/* $Id: ifplugd.c 1.12 Sat, 01 Feb 2003 03:00:07 +0100 lennart $ */ + +/* + * This file is part of ifplugd. + * + * ifplugd is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ifplugd is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ifplugd; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include + +typedef int (*nlapi_callback_t) (struct nlmsghdr *n, void *u); + +extern int nlapi_fd; + +int nlapi_open(uint32_t groups); +void nlapi_close(void); +int nlapi_work(int block); +int nlapi_register(nlapi_callback_t cb, void *u); + +#endif diff --git a/src/wireless.15.h b/src/wireless.15.h new file mode 100644 index 0000000..bacf44b --- /dev/null +++ b/src/wireless.15.h @@ -0,0 +1,698 @@ +/* + * This file define a set of standard wireless extensions + * + * Version : 15 12.7.02 + * + * Authors : Jean Tourrilhes - HPL - + * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved. + */ + +#ifndef _LINUX_WIRELESS_H +#define _LINUX_WIRELESS_H + +/************************** DOCUMENTATION **************************/ +/* + * Initial APIs (1996 -> onward) : + * ----------------------------- + * Basically, the wireless extensions are for now a set of standard ioctl + * call + /proc/net/wireless + * + * The entry /proc/net/wireless give statistics and information on the + * driver. + * This is better than having each driver having its entry because + * its centralised and we may remove the driver module safely. + * + * Ioctl are used to configure the driver and issue commands. This is + * better than command line options of insmod because we may want to + * change dynamically (while the driver is running) some parameters. + * + * The ioctl mechanimsm are copied from standard devices ioctl. + * We have the list of command plus a structure descibing the + * data exchanged... + * Note that to add these ioctl, I was obliged to modify : + * # net/core/dev.c (two place + add include) + * # net/ipv4/af_inet.c (one place + add include) + * + * /proc/net/wireless is a copy of /proc/net/dev. + * We have a structure for data passed from the driver to /proc/net/wireless + * Too add this, I've modified : + * # net/core/dev.c (two other places) + * # include/linux/netdevice.h (one place) + * # include/linux/proc_fs.h (one place) + * + * New driver API (2002 -> onward) : + * ------------------------------- + * This file is only concerned with the user space API and common definitions. + * The new driver API is defined and documented in : + * # include/net/iw_handler.h + * + * Note as well that /proc/net/wireless implementation has now moved in : + * # include/linux/wireless.c + * + * Wireless Events (2002 -> onward) : + * -------------------------------- + * Events are defined at the end of this file, and implemented in : + * # include/linux/wireless.c + * + * Other comments : + * -------------- + * Do not add here things that are redundant with other mechanisms + * (drivers init, ifconfig, /proc/net/dev, ...) and with are not + * wireless specific. + * + * These wireless extensions are not magic : each driver has to provide + * support for them... + * + * IMPORTANT NOTE : As everything in the kernel, this is very much a + * work in progress. Contact me if you have ideas of improvements... + */ + +/***************************** INCLUDES *****************************/ + +#include /* for "caddr_t" et al */ +#include /* for "struct sockaddr" et al */ +#include /* for IFNAMSIZ and co... */ + +/***************************** VERSION *****************************/ +/* + * This constant is used to know the availability of the wireless + * extensions and to know which version of wireless extensions it is + * (there is some stuff that will be added in the future...) + * I just plan to increment with each new version. + */ +#define WIRELESS_EXT 15 + +/* + * Changes : + * + * V2 to V3 + * -------- + * Alan Cox start some incompatibles changes. I've integrated a bit more. + * - Encryption renamed to Encode to avoid US regulation problems + * - Frequency changed from float to struct to avoid problems on old 386 + * + * V3 to V4 + * -------- + * - Add sensitivity + * + * V4 to V5 + * -------- + * - Missing encoding definitions in range + * - Access points stuff + * + * V5 to V6 + * -------- + * - 802.11 support (ESSID ioctls) + * + * V6 to V7 + * -------- + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP + * + * V7 to V8 + * -------- + * - Changed my e-mail address + * - More 802.11 support (nickname, rate, rts, frag) + * - List index in frequencies + * + * V8 to V9 + * -------- + * - Support for 'mode of operation' (ad-hoc, managed...) + * - Support for unicast and multicast power saving + * - Change encoding to support larger tokens (>64 bits) + * - Updated iw_params (disable, flags) and use it for NWID + * - Extracted iw_point from iwreq for clarity + * + * V9 to V10 + * --------- + * - Add PM capability to range structure + * - Add PM modifier : MAX/MIN/RELATIVE + * - Add encoding option : IW_ENCODE_NOKEY + * - Add TxPower ioctls (work like TxRate) + * + * V10 to V11 + * ---------- + * - Add WE version in range (help backward/forward compatibility) + * - Add retry ioctls (work like PM) + * + * V11 to V12 + * ---------- + * - Add SIOCSIWSTATS to get /proc/net/wireless programatically + * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space + * - Add new statistics (frag, retry, beacon) + * - Add average quality (for user space calibration) + * + * V12 to V13 + * ---------- + * - Document creation of new driver API. + * - Extract union iwreq_data from struct iwreq (for new driver API). + * - Rename SIOCSIWNAME as SIOCSIWCOMMIT + * + * V13 to V14 + * ---------- + * - Wireless Events support : define struct iw_event + * - Define additional specific event numbers + * - Add "addr" and "param" fields in union iwreq_data + * - AP scanning stuff (SIOCSIWSCAN and friends) + * + * V14 to V15 + * ---------- + * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg + * - Make struct iw_freq signed (both m & e), add explicit padding + * - Add IWEVCUSTOM for driver specific event/scanning token + * - Add IW_MAX_GET_SPY for driver returning a lot of addresses + * - Add IW_TXPOW_RANGE for range of Tx Powers + * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points + * - Add IW_MODE_MONITOR for passive monitor + */ + +/**************************** CONSTANTS ****************************/ + +/* -------------------------- IOCTL LIST -------------------------- */ + +/* Wireless Identification */ +#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ +#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ +/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. + * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... + * Don't put the name of your driver there, it's useless. */ + +/* Basic operations */ +#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ +#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ +#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ +#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ +#define SIOCSIWMODE 0x8B06 /* set operation mode */ +#define SIOCGIWMODE 0x8B07 /* get operation mode */ +#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ +#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ + +/* Informative stuff */ +#define SIOCSIWRANGE 0x8B0A /* Unused */ +#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ +#define SIOCSIWPRIV 0x8B0C /* Unused */ +#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ +#define SIOCSIWSTATS 0x8B0E /* Unused */ +#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ +/* SIOCGIWSTATS is strictly used between user space and the kernel, and + * is never passed to the driver (i.e. the driver will never see it). */ + +/* Mobile IP support (statistics per MAC address) */ +#define SIOCSIWSPY 0x8B10 /* set spy addresses */ +#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ + +/* Access Point manipulation */ +#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ +#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ +#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ +#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ +#define SIOCGIWSCAN 0x8B19 /* get scanning results */ + +/* 802.11 specific support */ +#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ +#define SIOCGIWESSID 0x8B1B /* get ESSID */ +#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ +#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ +/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit + * within the 'iwreq' structure, so we need to use the 'data' member to + * point to a string in user space, like it is done for RANGE... */ + +/* Other parameters useful in 802.11 and some other devices */ +#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ +#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ +#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ +#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ +#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ +#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ +#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ +#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ +#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ +#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ + +/* Encoding stuff (scrambling, hardware security, WEP...) */ +#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ +#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ +/* Power saving stuff (power management, unicast and multicast) */ +#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ +#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ + +/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ + +/* These 16 ioctl are wireless device private. + * Each driver is free to use them for whatever purpose it chooses, + * however the driver *must* export the description of those ioctls + * with SIOCGIWPRIV and *must* use arguments as defined below. + * If you don't follow those rules, DaveM is going to hate you (reason : + * it make mixed 32/64bit operation impossible). + */ +#define SIOCIWFIRSTPRIV 0x8BE0 +#define SIOCIWLASTPRIV 0x8BFF +/* Previously, we were using SIOCDEVPRIVATE, but we now have our + * separate range because of collisions with other tools such as + * 'mii-tool'. + * We now have 32 commands, so a bit more space ;-). + * Also, all 'odd' commands are only usable by root and don't return the + * content of ifr/iwr to user (but you are not obliged to use the set/get + * convention, just use every other two command). + * And I repeat : you are not obliged to use them with iwspy, but you + * must be compliant with it. + */ + +/* ------------------------- IOCTL STUFF ------------------------- */ + +/* The first and the last (range) */ +#define SIOCIWFIRST 0x8B00 +#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ + +/* Even : get (world access), odd : set (root access) */ +#define IW_IS_SET(cmd) (!((cmd) & 0x1)) +#define IW_IS_GET(cmd) ((cmd) & 0x1) + +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* Those are *NOT* ioctls, do not issue request on them !!! */ +/* Most events use the same identifier as ioctl requests */ + +#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ +#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ +#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ +#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ +#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ + +#define IWEVFIRST 0x8C00 + +/* ------------------------- PRIVATE INFO ------------------------- */ +/* + * The following is used with SIOCGIWPRIV. It allow a driver to define + * the interface (name, type of data) for its private ioctl. + * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV + */ + +#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ +#define IW_PRIV_TYPE_NONE 0x0000 +#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ +#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ +#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ +#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ +#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ + +#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed nuber of args */ + +#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ + +/* + * Note : if the number of args is fixed and the size < 16 octets, + * instead of passing a pointer we will put args in the iwreq struct... + */ + +/* ----------------------- OTHER CONSTANTS ----------------------- */ + +/* Maximum frequencies in the range struct */ +#define IW_MAX_FREQUENCIES 16 +/* Note : if you have something like 80 frequencies, + * don't increase this constant and don't fill the frequency list. + * The user will be able to set by channel anyway... */ + +/* Maximum bit rates in the range struct */ +#define IW_MAX_BITRATES 8 + +/* Maximum tx powers in the range struct */ +#define IW_MAX_TXPOWER 8 +/* Note : if you more than 8 TXPowers, just set the max and min or + * a few of them in the struct iw_range. */ + +/* Maximum of address that you may set with SPY */ +#define IW_MAX_SPY 8 /* set */ +#define IW_MAX_GET_SPY 64 /* get */ + +/* Maximum of address that you may get in the + list of access points in range */ +#define IW_MAX_AP 8 + +/* Maximum size of the ESSID and NICKN strings */ +#define IW_ESSID_MAX_SIZE 32 + +/* Modes of operation */ +#define IW_MODE_AUTO 0 /* Let the driver decides */ +#define IW_MODE_ADHOC 1 /* Single cell network */ +#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ +#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ +#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ +#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ +#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ + +/* Maximum number of size of encoding token available + * they are listed in the range structure */ +#define IW_MAX_ENCODING_SIZES 8 + +/* Maximum size of the encoding token in bytes */ +#define IW_ENCODING_TOKEN_MAX 32 /* 256 bits (for now) */ + +/* Flags for encoding (along with the token) */ +#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ +#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ +#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ +#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ +#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ +#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ +#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ +#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ + +/* Power management flags available (along with the value, if any) */ +#define IW_POWER_ON 0x0000 /* No details... */ +#define IW_POWER_TYPE 0xF000 /* Type of parameter */ +#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ +#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ +#define IW_POWER_MODE 0x0F00 /* Power Management mode */ +#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ +#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ +#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ +#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ +#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ +#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ +#define IW_POWER_MIN 0x0001 /* Value is a minimum */ +#define IW_POWER_MAX 0x0002 /* Value is a maximum */ +#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/* Transmit Power flags available */ +#define IW_TXPOW_TYPE 0x00FF /* Type of value */ +#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ +#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ +#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ + +/* Retry limits and lifetime flags available */ +#define IW_RETRY_ON 0x0000 /* No details... */ +#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ +#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ +#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ +#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */ +#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ +#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ +#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ + +/* Scanning request flags */ +#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ +#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ +#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ +#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ +#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ +#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ +#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ +#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ +#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ +/* Maximum size of returned data */ +#define IW_SCAN_MAX_DATA 4096 /* In bytes */ + +/* Max number of char in custom event - use multiple of them if needed */ +#define IW_CUSTOM_MAX 256 /* In bytes */ + +/****************************** TYPES ******************************/ + +/* --------------------------- SUBTYPES --------------------------- */ +/* + * Generic format for most parameters that fit in an int + */ +struct iw_param +{ + __s32 value; /* The value of the parameter itself */ + __u8 fixed; /* Hardware should not use auto select */ + __u8 disabled; /* Disable the feature */ + __u16 flags; /* Various specifc flags (if any) */ +}; + +/* + * For all data larger than 16 octets, we need to use a + * pointer to memory allocated in user space. + */ +struct iw_point +{ + caddr_t pointer; /* Pointer to the data (in user space) */ + __u16 length; /* number of fields or size in bytes */ + __u16 flags; /* Optional params */ +}; + +/* + * A frequency + * For numbers lower than 10^9, we encode the number in 'm' and + * set 'e' to 0 + * For number greater than 10^9, we divide it by the lowest power + * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... + * The power of 10 is in 'e', the result of the division is in 'm'. + */ +struct iw_freq +{ + __s32 m; /* Mantissa */ + __s16 e; /* Exponent */ + __u8 i; /* List index (when in range struct) */ + __u8 pad; /* Unused - just for alignement */ +}; + +/* + * Quality of the link + */ +struct iw_quality +{ + __u8 qual; /* link quality (%retries, SNR, + %missed beacons or better...) */ + __u8 level; /* signal level (dBm) */ + __u8 noise; /* noise level (dBm) */ + __u8 updated; /* Flags to know if updated */ +}; + +/* + * Packet discarded in the wireless adapter due to + * "wireless" specific problems... + * Note : the list of counter and statistics in net_device_stats + * is already pretty exhaustive, and you should use that first. + * This is only additional stats... + */ +struct iw_discarded +{ + __u32 nwid; /* Rx : Wrong nwid/essid */ + __u32 code; /* Rx : Unable to code/decode (WEP) */ + __u32 fragment; /* Rx : Can't perform MAC reassembly */ + __u32 retries; /* Tx : Max MAC retries num reached */ + __u32 misc; /* Others cases */ +}; + +/* + * Packet/Time period missed in the wireless adapter due to + * "wireless" specific problems... + */ +struct iw_missed +{ + __u32 beacon; /* Missed beacons/superframe */ +}; + +/* ------------------------ WIRELESS STATS ------------------------ */ +/* + * Wireless statistics (used for /proc/net/wireless) + */ +struct iw_statistics +{ + __u16 status; /* Status + * - device dependent for now */ + + struct iw_quality qual; /* Quality of the link + * (instant/mean/max) */ + struct iw_discarded discard; /* Packet discarded counts */ + struct iw_missed miss; /* Packet missed counts */ +}; + +/* ------------------------ IOCTL REQUEST ------------------------ */ +/* + * This structure defines the payload of an ioctl, and is used + * below. + * + * Note that this structure should fit on the memory footprint + * of iwreq (which is the same as ifreq), which mean a max size of + * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... + * You should check this when increasing the structures defined + * above in this file... + */ +union iwreq_data +{ + /* Config - generic */ + char name[IFNAMSIZ]; + /* Name : used to verify the presence of wireless extensions. + * Name of the protocol/provider... */ + + struct iw_point essid; /* Extended network name */ + struct iw_param nwid; /* network id (or domain - the cell) */ + struct iw_freq freq; /* frequency or channel : + * 0-1000 = channel + * > 1000 = frequency in Hz */ + + struct iw_param sens; /* signal level threshold */ + struct iw_param bitrate; /* default bit rate */ + struct iw_param txpower; /* default transmit power */ + struct iw_param rts; /* RTS threshold threshold */ + struct iw_param frag; /* Fragmentation threshold */ + __u32 mode; /* Operation mode */ + struct iw_param retry; /* Retry limits & lifetime */ + + struct iw_point encoding; /* Encoding stuff : tokens */ + struct iw_param power; /* PM duration/timeout */ + struct iw_quality qual; /* Quality part of statistics */ + + struct sockaddr ap_addr; /* Access point address */ + struct sockaddr addr; /* Destination address (hw) */ + + struct iw_param param; /* Other small parameters */ + struct iw_point data; /* Other large parameters */ +}; + +/* + * The structure to exchange data for ioctl. + * This structure is the same as 'struct ifreq', but (re)defined for + * convenience... + * Do I need to remind you about structure size (32 octets) ? + */ +struct iwreq +{ + union + { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ + } ifr_ifrn; + + /* Data part (defined just above) */ + union iwreq_data u; +}; + +/* -------------------------- IOCTL DATA -------------------------- */ +/* + * For those ioctl which want to exchange mode data that what could + * fit in the above structure... + */ + +/* + * Range of parameters + */ + +struct iw_range +{ + /* Informative stuff (to choose between different interface) */ + __u32 throughput; /* To give an idea... */ + /* In theory this value should be the maximum benchmarked + * TCP/IP throughput, because with most of these devices the + * bit rate is meaningless (overhead an co) to estimate how + * fast the connection will go and pick the fastest one. + * I suggest people to play with Netperf or any benchmark... + */ + + /* NWID (or domain id) */ + __u32 min_nwid; /* Minimal NWID we are able to set */ + __u32 max_nwid; /* Maximal NWID we are able to set */ + + /* Frequency */ + __u16 num_channels; /* Number of channels [0; num - 1] */ + __u8 num_frequency; /* Number of entry in the list */ + struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ + /* Note : this frequency list doesn't need to fit channel numbers */ + + /* signal level threshold range */ + __s32 sensitivity; + + /* Quality of link & SNR stuff */ + struct iw_quality max_qual; /* Quality of the link */ + + /* Rates */ + __u8 num_bitrates; /* Number of entries in the list */ + __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ + + /* RTS threshold */ + __s32 min_rts; /* Minimal RTS threshold */ + __s32 max_rts; /* Maximal RTS threshold */ + + /* Frag threshold */ + __s32 min_frag; /* Minimal frag threshold */ + __s32 max_frag; /* Maximal frag threshold */ + + /* Power Management duration & timeout */ + __s32 min_pmp; /* Minimal PM period */ + __s32 max_pmp; /* Maximal PM period */ + __s32 min_pmt; /* Minimal PM timeout */ + __s32 max_pmt; /* Maximal PM timeout */ + __u16 pmp_flags; /* How to decode max/min PM period */ + __u16 pmt_flags; /* How to decode max/min PM timeout */ + __u16 pm_capa; /* What PM options are supported */ + + /* Encoder stuff */ + __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ + __u8 num_encoding_sizes; /* Number of entry in the list */ + __u8 max_encoding_tokens; /* Max number of tokens */ + + /* Transmit power */ + __u16 txpower_capa; /* What options are supported */ + __u8 num_txpower; /* Number of entries in the list */ + __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ + + /* Wireless Extension version info */ + __u8 we_version_compiled; /* Must be WIRELESS_EXT */ + __u8 we_version_source; /* Last update of source */ + + /* Retry limits and lifetime */ + __u16 retry_capa; /* What retry options are supported */ + __u16 retry_flags; /* How to decode max/min retry limit */ + __u16 r_time_flags; /* How to decode max/min retry life */ + __s32 min_retry; /* Minimal number of retries */ + __s32 max_retry; /* Maximal number of retries */ + __s32 min_r_time; /* Minimal retry lifetime */ + __s32 max_r_time; /* Maximal retry lifetime */ + + /* Average quality of link & SNR */ + struct iw_quality avg_qual; /* Quality of the link */ + /* This should contain the average/typical values of the quality + * indicator. This should be the threshold between a "good" and + * a "bad" link (example : monitor going from green to orange). + * Currently, user space apps like quality monitors don't have any + * way to calibrate the measurement. With this, they can split + * the range between 0 and max_qual in different quality level + * (using a geometric subdivision centered on the average). + * I expect that people doing the user space apps will feedback + * us on which value we need to put in each driver... + */ +}; + +/* + * Private ioctl interface information + */ + +struct iw_priv_args +{ + __u32 cmd; /* Number of the ioctl to issue */ + __u16 set_args; /* Type and number of args */ + __u16 get_args; /* Type and number of args */ + char name[IFNAMSIZ]; /* Name of the extension */ +}; + +/* ----------------------- WIRELESS EVENTS ----------------------- */ +/* + * Wireless events are carried through the rtnetlink socket to user + * space. They are encapsulated in the IFLA_WIRELESS field of + * a RTM_NEWLINK message. + */ + +/* + * A Wireless Event. Contains basically the same data as the ioctl... + */ +struct iw_event +{ + __u16 len; /* Real lenght of this stuff */ + __u16 cmd; /* Wireless IOCTL */ + union iwreq_data u; /* IOCTL fixed payload */ +}; + +/* Size of the Event prefix (including padding and alignement junk) */ +#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) +/* Size of the various events */ +#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) +#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) +#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) +#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point)) +#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) +#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) +#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) + +/* Note : in the case of iw_point, the extra data will come at the + * end of the event */ + +#endif /* _LINUX_WIRELESS_H */ -- cgit