rfkill: Add support for reacting to radio kill switch events.

In order for this to work, the correct rfkill index must be specified
with the rfkill-idx option.

It might be possible to auto-detect the corresponding rfkill-idx option,
but I'm not sure if there's a guaranteed mapping between rfkill name and
interface name, as it seems that rfkills should represent phy devices
and not wlan devices.

The rfkill indexes can be found by checking
/sys/class/rfkill/rfkill<IDX>.
This commit is contained in:
Nicholas J. Kain 2015-02-13 16:25:36 -05:00
parent 3421f0c585
commit e3d4d4c1aa
6 changed files with 161 additions and 4 deletions

View File

@ -163,6 +163,11 @@ struct cfgparse {
case -1: allow_hostname = 0; default: break;
}
}
action rfkill_idx {
uint32_t t = atoi(ccfg.buf);
client_config.rfkillIdx = t;
client_config.enable_rfkill = 1;
}
action version { print_version(); exit(EXIT_SUCCESS); }
action help { show_usage(); exit(EXIT_SUCCESS); }
}%%
@ -206,13 +211,14 @@ struct cfgparse {
gw_metric = 'gw-metric' value @gw_metric;
resolv_conf = 'resolv-conf' value @resolv_conf;
dhcp_set_hostname = 'dhcp-set-hostname' boolval @dhcp_set_hostname;
rfkill_idx = 'rfkill-idx' value @rfkill_idx;
main := blankline |
clientid | background | pidfile | hostname | interface | now | quit |
request | vendorid | user | ifch_user | sockd_user | chroot |
state_dir | seccomp_enforce | relentless_defense | arp_probe_wait |
arp_probe_num | arp_probe_min | arp_probe_max | gw_metric |
resolv_conf | dhcp_set_hostname
resolv_conf | dhcp_set_hostname | rfkill_idx
;
}%%
@ -278,6 +284,7 @@ static void parse_cfgfile(const char *fname)
gw_metric = ('-t'|'--gw-metric') argval @gw_metric;
resolv_conf = ('-R'|'--resolv-conf') argval @resolv_conf;
dhcp_set_hostname = ('-H'|'--dhcp-set-hostname') tbv @dhcp_set_hostname;
rfkill_idx = ('-K'|'--rfkill-idx') argval @rfkill_idx;
version = ('-v'|'--version') 0 @version;
help = ('-?'|'--help') 0 @help;
@ -286,7 +293,8 @@ static void parse_cfgfile(const char *fname)
now | quit | request | vendorid | user | ifch_user | sockd_user |
chroot | state_dir | seccomp_enforce | relentless_defense |
arp_probe_wait | arp_probe_num | arp_probe_min | arp_probe_max |
gw_metric | resolv_conf | dhcp_set_hostname | version | help
gw_metric | resolv_conf | dhcp_set_hostname | rfkill_idx |
version | help
)*;
}%%

View File

@ -133,6 +133,17 @@ default is 2000ms. The precise inter-probe wait time is randomized.
Specifies the routing metric for the default gateway entry. Defaults to
0 if not specified. Higher values will de-prioritize the route entry.
.TP
.BI \-K\ RFKILLIDX ,\ \-\-rfkill\-idx= RFKILLIDX
If set, specifies the rfkill device index that corresponds to this interface.
ndhc will then listen for matching radio frequency kill switch events
and will bring the interface up and down in reaction to the events.
The rfkill devices can be found in /sys/class/rfkill/rfkill<RFKILLIDX>.
It may be useful to check the contents of the 'name' file within this
directory to determine the correct device index. In any event, if
an rfkill-idx parameter is specified, ndhc will print messages for any
rfkill events that it sees, so it should not be too difficult to locate
the proper rfkill device by checking the logs after hitting the switch.
.TP
.BI \-v ,\ \-\-version
Display the ndhc version number.
.SH SIGNALS

View File

@ -71,6 +71,7 @@
#include "ifchd.h"
#include "duiaid.h"
#include "sockd.h"
#include "rfkill.h"
struct client_state_t cs = {
.ifchWorking = 0,
@ -82,6 +83,7 @@ struct client_state_t cs = {
.arpFd = -1,
.nlFd = -1,
.nlPortId = -1,
.rfkillFd = -1,
.routerArp = "\0\0\0\0\0\0",
.serverArp = "\0\0\0\0\0\0",
};
@ -275,7 +277,7 @@ static void handle_ifch_message(void)
cs.ifchWorking = 0;
}
#define NDHC_NUM_EP_FDS 7
#define NDHC_NUM_EP_FDS 8
static void do_ndhc_work(void)
{
struct epoll_event events[NDHC_NUM_EP_FDS];
@ -295,6 +297,8 @@ static void do_ndhc_work(void)
epoll_add(cs.epollFd, ifchSock[0]);
epoll_add(cs.epollFd, ifchStream[0]);
epoll_add(cs.epollFd, sockdStream[0]);
if (client_config.enable_rfkill && cs.rfkillFd != -1)
epoll_add(cs.epollFd, cs.nlFd);
start_dhcp_listen(&cs);
nowts = curms();
goto jumpstart;
@ -330,6 +334,9 @@ static void do_ndhc_work(void)
} else if (fd == sockdStream[0]) {
if (events[i].events & (EPOLLHUP|EPOLLERR|EPOLLRDHUP))
exit(EXIT_FAILURE);
} else if (fd == cs.rfkillFd && client_config.enable_rfkill) {
if (events[i].events & EPOLLIN)
handle_rfkill_notice(&cs, client_config.rfkillIdx);
} else
suicide("epoll_wait: unknown fd");
}
@ -429,6 +436,8 @@ static void ndhc_main(void) {
if ((cs.nlFd = nl_open(NETLINK_ROUTE, RTMGRP_LINK, &cs.nlPortId)) < 0)
suicide("%s: failed to open netlink socket", __func__);
cs.rfkillFd = rfkill_open(&client_config.enable_rfkill);
if (client_config.foreground && !client_config.background_if_no_lease) {
if (file_exists(pidfile, "w") < 0)
suicide("%s: can't open pidfile '%s' for write!",

View File

@ -40,7 +40,7 @@ struct client_state_t {
int ifsPrevState;
int ifchWorking; // ifch is performing interface changes.
int ifDeconfig; // Set if the interface has already been deconfigured.
int epollFd, signalFd, listenFd, arpFd, nlFd;
int epollFd, signalFd, listenFd, arpFd, nlFd, rfkillFd;
int nlPortId;
uint32_t clientAddr, serverAddr, srcAddr, routerAddr;
uint32_t lease, renewTime, rebindTime, xid;
@ -54,6 +54,7 @@ struct client_config_t {
char quit_after_lease; // Quit after obtaining lease
char abort_if_no_lease; // Abort if no lease
char background_if_no_lease; // Fork to background if no lease
char enable_rfkill; // Listen for rfkill events
char interface[IFNAMSIZ]; // The name of the interface to use
char clientid[64]; // Optional client id to use
uint8_t clientid_len; // Length of the clientid
@ -61,6 +62,7 @@ struct client_config_t {
char vendor[64]; // Vendor identification that will be sent
int metric; // Metric for the default route
int ifindex; // Index number of the interface to use
uint32_t rfkillIdx; // Index of the corresponding rfkill device
uint8_t arp[6]; // Our arp address
};

92
src/rfkill.c Normal file
View File

@ -0,0 +1,92 @@
/* rfkill.c - rfkill interface and handling
*
* Copyright (c) 2015 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/rfkill.h>
#include "nk/log.h"
#include "nk/io.h"
#include "ndhc.h"
#include "netlink.h"
#include "rfkill.h"
int rfkill_open(char enable_rfkill[static 1])
{
if (!*enable_rfkill)
return -1;
int r = open("/dev/rfkill", O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (r < 0) {
*enable_rfkill = 0;
log_line("rfkill disabled: could not open /dev/rfkill: %s",
strerror(errno));
}
return r;
}
void handle_rfkill_notice(struct client_state_t cs[static 1], uint32_t rfkidx)
{
struct rfkill_event event;
ssize_t len = safe_read(cs->rfkillFd, (char *)&event, sizeof event);
if (len < 0) {
log_error("rfkill: safe_read failed: %s", strerror(errno));
return;
}
if (len != RFKILL_EVENT_SIZE_V1) {
log_error("rfkill: event has unexpected size: %d", len);
return;
}
log_line("rfkill: idx[%u] type[%u] op[%u] soft[%u] hard[%u]",
event.idx, event.type, event.op, event.soft, event.hard);
if (event.idx != rfkidx)
return;
if (event.op != RFKILL_OP_CHANGE && event.op != RFKILL_OP_CHANGE_ALL)
return;
if (event.soft || event.hard) {
if (cs->ifsPrevState == IFS_UP) {
log_line("rfkill: radio now blocked; bringing interface down");
cs->ifsPrevState = IFS_DOWN;
ifnocarrier_action(cs);
} else
log_line("rfkill: radio now blocked, but interface isn't up");
} else {
if (cs->ifsPrevState == IFS_DOWN) {
log_line("rfkill: radio now unblocked; bringing interface up");
cs->ifsPrevState = IFS_UP;
ifup_action(cs);
} else {
if (cs->ifsPrevState == IFS_SHUT)
log_line("rfkill: radio now unblocked, but interface was shut down by user");
else
log_line("rfkill: radio now unblocked, but interface is removed");
}
}
}

35
src/rfkill.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef NDHC_RFKILL_H_
#define NDHC_RFKILL_H_
/* rfkill.h - rfkill interface and handling
*
* Copyright (c) 2015 Nicholas J. Kain <njkain at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
int rfkill_open(char enable_rfkill[static 1]);
void handle_rfkill_notice(struct client_state_t cs[static 1], uint32_t rfkidx);
#endif