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 "manager.h" 40 #include "adapter.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 gsize len; 75 GIOError err; 76 int fd, id; 77 78 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) 79 return FALSE; 80 81 memset(buf, 0, sizeof(buf)); 82 83 err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len); 84 if (err) { 85 if (err == G_IO_ERROR_AGAIN) 86 return TRUE; 87 return FALSE; 88 } 89 90 if (len != sizeof(struct rfkill_event)) 91 return TRUE; 92 93 DBG("RFKILL event idx %u type %u op %u soft %u hard %u", 94 event->idx, event->type, event->op, 95 event->soft, event->hard); 96 97 if (event->soft || event->hard) 98 return TRUE; 99 100 if (event->op != RFKILL_OP_CHANGE) 101 return TRUE; 102 103 if (event->type != RFKILL_TYPE_BLUETOOTH && 104 event->type != RFKILL_TYPE_ALL) 105 return TRUE; 106 107 snprintf(sysname, sizeof(sysname) - 1, 108 "/sys/class/rfkill/rfkill%u/name", event->idx); 109 110 fd = open(sysname, O_RDONLY); 111 if (fd < 0) 112 return TRUE; 113 114 memset(sysname, 0, sizeof(sysname)); 115 116 if (read(fd, sysname, sizeof(sysname)) < 4) { 117 close(fd); 118 return TRUE; 119 } 120 121 close(fd); 122 123 if (g_str_has_prefix(sysname, "hci") == FALSE) 124 return TRUE; 125 126 id = atoi(sysname + 3); 127 if (id < 0) 128 return TRUE; 129 130 adapter = manager_find_adapter_by_id(id); 131 if (!adapter) 132 return TRUE; 133 134 DBG("RFKILL unblock for hci%d", id); 135 136 btd_adapter_restore_powered(adapter); 137 138 return TRUE; 139 } 140 141 static GIOChannel *channel = NULL; 142 143 void rfkill_init(void) 144 { 145 int fd; 146 147 if (!main_opts.remember_powered) 148 return; 149 150 fd = open("/dev/rfkill", O_RDWR); 151 if (fd < 0) { 152 error("Failed to open RFKILL control device"); 153 return; 154 } 155 156 channel = g_io_channel_unix_new(fd); 157 g_io_channel_set_close_on_unref(channel, TRUE); 158 159 g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, 160 rfkill_event, NULL); 161 } 162 163 void rfkill_exit(void) 164 { 165 if (!channel) 166 return; 167 168 g_io_channel_shutdown(channel, TRUE, NULL); 169 g_io_channel_unref(channel); 170 171 channel = NULL; 172 } 173