1 /* 2 * Linux rfkill helper functions for driver wrappers 3 * Copyright (c) 2010, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #include <fcntl.h> 11 12 #include "utils/common.h" 13 #include "utils/eloop.h" 14 #include "rfkill.h" 15 16 #define RFKILL_EVENT_SIZE_V1 8 17 18 struct rfkill_event { 19 u32 idx; 20 u8 type; 21 u8 op; 22 u8 soft; 23 u8 hard; 24 } STRUCT_PACKED; 25 26 enum rfkill_operation { 27 RFKILL_OP_ADD = 0, 28 RFKILL_OP_DEL, 29 RFKILL_OP_CHANGE, 30 RFKILL_OP_CHANGE_ALL, 31 }; 32 33 enum rfkill_type { 34 RFKILL_TYPE_ALL = 0, 35 RFKILL_TYPE_WLAN, 36 RFKILL_TYPE_BLUETOOTH, 37 RFKILL_TYPE_UWB, 38 RFKILL_TYPE_WIMAX, 39 RFKILL_TYPE_WWAN, 40 RFKILL_TYPE_GPS, 41 RFKILL_TYPE_FM, 42 NUM_RFKILL_TYPES, 43 }; 44 45 46 struct rfkill_data { 47 struct rfkill_config *cfg; 48 int fd; 49 int blocked; 50 }; 51 52 53 static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) 54 { 55 struct rfkill_data *rfkill = eloop_ctx; 56 struct rfkill_event event; 57 ssize_t len; 58 int new_blocked; 59 60 len = read(rfkill->fd, &event, sizeof(event)); 61 if (len < 0) { 62 wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 63 strerror(errno)); 64 return; 65 } 66 if (len != RFKILL_EVENT_SIZE_V1) { 67 wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 68 "%d (expected %d)", 69 (int) len, RFKILL_EVENT_SIZE_V1); 70 return; 71 } 72 wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " 73 "op=%u soft=%u hard=%u", 74 event.idx, event.type, event.op, event.soft, 75 event.hard); 76 if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) 77 return; 78 79 if (event.hard) { 80 wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 81 new_blocked = 1; 82 } else if (event.soft) { 83 wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 84 new_blocked = 1; 85 } else { 86 wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); 87 new_blocked = 0; 88 } 89 90 if (new_blocked != rfkill->blocked) { 91 rfkill->blocked = new_blocked; 92 if (new_blocked) 93 rfkill->cfg->blocked_cb(rfkill->cfg->ctx); 94 else 95 rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); 96 } 97 } 98 99 100 struct rfkill_data * rfkill_init(struct rfkill_config *cfg) 101 { 102 struct rfkill_data *rfkill; 103 struct rfkill_event event; 104 ssize_t len; 105 106 rfkill = os_zalloc(sizeof(*rfkill)); 107 if (rfkill == NULL) 108 return NULL; 109 110 rfkill->cfg = cfg; 111 rfkill->fd = open("/dev/rfkill", O_RDONLY); 112 if (rfkill->fd < 0) { 113 wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " 114 "device"); 115 goto fail; 116 } 117 118 if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { 119 wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " 120 "%s", strerror(errno)); 121 goto fail2; 122 } 123 124 for (;;) { 125 len = read(rfkill->fd, &event, sizeof(event)); 126 if (len < 0) { 127 if (errno == EAGAIN) 128 break; /* No more entries */ 129 wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 130 strerror(errno)); 131 break; 132 } 133 if (len != RFKILL_EVENT_SIZE_V1) { 134 wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 135 "%d (expected %d)", 136 (int) len, RFKILL_EVENT_SIZE_V1); 137 continue; 138 } 139 wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " 140 "op=%u soft=%u hard=%u", 141 event.idx, event.type, event.op, event.soft, 142 event.hard); 143 if (event.op != RFKILL_OP_ADD || 144 event.type != RFKILL_TYPE_WLAN) 145 continue; 146 if (event.hard) { 147 wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 148 rfkill->blocked = 1; 149 } else if (event.soft) { 150 wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 151 rfkill->blocked = 1; 152 } 153 } 154 155 eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); 156 157 return rfkill; 158 159 fail2: 160 close(rfkill->fd); 161 fail: 162 os_free(rfkill); 163 return NULL; 164 } 165 166 167 void rfkill_deinit(struct rfkill_data *rfkill) 168 { 169 if (rfkill == NULL) 170 return; 171 172 if (rfkill->fd >= 0) { 173 eloop_unregister_read_sock(rfkill->fd); 174 close(rfkill->fd); 175 } 176 177 os_free(rfkill->cfg); 178 os_free(rfkill); 179 } 180 181 182 int rfkill_is_blocked(struct rfkill_data *rfkill) 183 { 184 if (rfkill == NULL) 185 return 0; 186 187 return rfkill->blocked; 188 } 189