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:
		
							
								
								
									
										12
									
								
								src/cfg.rl
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/cfg.rl
									
									
									
									
									
								
							| @@ -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 | ||||
|     )*; | ||||
| }%% | ||||
|  | ||||
|   | ||||
							
								
								
									
										11
									
								
								src/ndhc.8
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/ndhc.8
									
									
									
									
									
								
							| @@ -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 | ||||
|   | ||||
							
								
								
									
										11
									
								
								src/ndhc.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/ndhc.c
									
									
									
									
									
								
							| @@ -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!", | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										92
									
								
								src/rfkill.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										35
									
								
								src/rfkill.h
									
									
									
									
									
										Normal 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 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user