1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <errno.h> 29 #include <stdio.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <stdint.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include <glib.h> 37 38 #include "log.h" 39 #include "adapter.h" 40 #include "manager.h" 41 #include "hcid.h" 42 43 enum rfkill_type { 44 RFKILL_TYPE_ALL = 0, 45 RFKILL_TYPE_WLAN, 46 RFKILL_TYPE_BLUETOOTH, 47 RFKILL_TYPE_UWB, 48 RFKILL_TYPE_WIMAX, 49 RFKILL_TYPE_WWAN, 50 }; 51 52 enum rfkill_operation { 53 RFKILL_OP_ADD = 0, 54 RFKILL_OP_DEL, 55 RFKILL_OP_CHANGE, 56 RFKILL_OP_CHANGE_ALL, 57 }; 58 59 struct rfkill_event { 60 uint32_t idx; 61 uint8_t type; 62 uint8_t op; 63 uint8_t soft; 64 uint8_t hard; 65 }; 66 67 static gboolean rfkill_event(GIOChannel *chan, 68 GIOCondition cond, gpointer data) 69 { 70 unsigned char buf[32]; 71 struct rfkill_event *event = (void *) buf; 72 struct btd_adapter *adapter; 73 char sysname[PATH_MAX]; 74 ssize_t len; 75 int fd, id; 76 77 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) 78 return FALSE; 79 80 fd = g_io_channel_unix_get_fd(chan); 81 82 memset(buf, 0, sizeof(buf)); 83 84 len = read(fd, buf, sizeof(buf)); 85 if (len < 0) { 86 if (errno == EAGAIN) 87 return TRUE; 88 return FALSE; 89 } 90 91 if (len != sizeof(struct rfkill_event)) 92 return TRUE; 93 94 DBG("RFKILL event idx %u type %u op %u soft %u hard %u", 95 event->idx, event->type, event->op, 96 event->soft, event->hard); 97 98 if (event->soft || event->hard) 99 return TRUE; 100 101 if (event->op != RFKILL_OP_CHANGE) 102 return TRUE; 103 104 if (event->type != RFKILL_TYPE_BLUETOOTH && 105 event->type != RFKILL_TYPE_ALL) 106 return TRUE; 107 108 snprintf(sysname, sizeof(sysname) - 1, 109 "/sys/class/rfkill/rfkill%u/name", event->idx); 110 111 fd = open(sysname, O_RDONLY); 112 if (fd < 0) 113 return TRUE; 114 115 memset(sysname, 0, sizeof(sysname)); 116 117 if (read(fd, sysname, sizeof(sysname)) < 4) { 118 close(fd); 119 return TRUE; 120 } 121 122 close(fd); 123 124 if (g_str_has_prefix(sysname, "hci") == FALSE) 125 return TRUE; 126 127 id = atoi(sysname + 3); 128 if (id < 0) 129 return TRUE; 130 131 adapter = manager_find_adapter_by_id(id); 132 if (!adapter) 133 return TRUE; 134 135 DBG("RFKILL unblock for hci%d", id); 136 137 btd_adapter_restore_powered(adapter); 138 139 return TRUE; 140 } 141 142 static GIOChannel *channel = NULL; 143 144 void rfkill_init(void) 145 { 146 int fd; 147 148 if (!main_opts.remember_powered) 149 return; 150 151 fd = open("/dev/rfkill", O_RDWR); 152 if (fd < 0) { 153 error("Failed to open RFKILL control device"); 154 return; 155 } 156 157 channel = g_io_channel_unix_new(fd); 158 g_io_channel_set_close_on_unref(channel, TRUE); 159 160 g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, 161 rfkill_event, NULL); 162 } 163 164 void rfkill_exit(void) 165 { 166 if (!channel) 167 return; 168 169 g_io_channel_shutdown(channel, TRUE, NULL); 170 g_io_channel_unref(channel); 171 172 channel = NULL; 173 } 174