summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-08-09 16:36:18 +0000
committerLennart Poettering <lennart@poettering.net>2003-08-09 16:36:18 +0000
commit9a5162c33017bab6677c528189cff5a501f3822a (patch)
tree6da7de6655a0d667bf2693a92e9eacf20412c2c4
parent3f995b59303d7fb3b95126714b94a0354b2cdb91 (diff)
netlink monitoring aded
wireless querying improved git-svn-id: file:///home/lennart/svn/public/ifplugd/trunk@30 2bf48fe7-cfc1-0310-909f-d9042e1e0fef
-rwxr-xr-xbootstrap.sh2
-rw-r--r--conf/ifplugd.conf4
-rw-r--r--src/Makefile.am4
-rw-r--r--src/ifmonitor.c76
-rw-r--r--src/ifmonitor.h26
-rw-r--r--src/ifplugd.c250
-rw-r--r--src/ifstatus.c49
-rw-r--r--src/interface.c108
-rw-r--r--src/interface.h1
-rw-r--r--src/nlapi.c131
-rw-r--r--src/nlapi.h39
-rw-r--r--src/wireless.15.h698
12 files changed, 1258 insertions, 130 deletions
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 <stdio.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#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 <linux/sockios.h>
+#include <linux/if_ether.h>
#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/ioctl.h>
-#include <net/if.h>
+#include <linux/if.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
@@ -29,16 +31,14 @@
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
+#include <assert.h>
#include "ethtool-local.h"
#include "interface.h"
+#include "wireless.15.h"
#include <libdaemon/dlog.h>
-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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libdaemon/dlog.h>
+
+#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 <stdint.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+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 - <jt@hpl.hp.com>
+ * 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 <linux/types.h> /* for "caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+#include <linux/if.h> /* 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 */