18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Linux rfkill helper functions for driver wrappers 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2010, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h> 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rfkill.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define RFKILL_EVENT_SIZE_V1 8 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rfkill_event { 191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt u32 idx; 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 type; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 op; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 soft; 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hard; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} STRUCT_PACKED; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum rfkill_operation { 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_OP_ADD = 0, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_OP_DEL, 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_OP_CHANGE, 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_OP_CHANGE_ALL, 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtenum rfkill_type { 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_ALL = 0, 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_WLAN, 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_BLUETOOTH, 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_UWB, 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_WIMAX, 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_WWAN, 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_GPS, 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt RFKILL_TYPE_FM, 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NUM_RFKILL_TYPES, 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rfkill_data { 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rfkill_config *cfg; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int fd; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int blocked; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rfkill_data *rfkill = eloop_ctx; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rfkill_event event; 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ssize_t len; 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int new_blocked; 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = read(rfkill->fd, &event, sizeof(event)); 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len < 0) { 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strerror(errno)); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len != RFKILL_EVENT_SIZE_V1) { 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (expected %d)", 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (int) len, RFKILL_EVENT_SIZE_V1); 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "op=%u soft=%u hard=%u", 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt event.idx, event.type, event.op, event.soft, 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt event.hard); 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (event.hard) { 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_blocked = 1; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (event.soft) { 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_blocked = 1; 8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } else { 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_blocked = 0; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (new_blocked != rfkill->blocked) { 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rfkill->blocked = new_blocked; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (new_blocked) 93f20a4432808cee548326c4b35c83071ca576a239Irfan Sheriff rfkill->cfg->blocked_cb(rfkill->cfg->ctx); 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 95f20a4432808cee548326c4b35c83071ca576a239Irfan Sheriff rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); 96e78e767aea5576ec0ba7edadfe25fd9dc7dce48fIrfan Sheriff } 975b5fb02b225c5c05a4477bef58bdaceede5d68dcandy} 985b5fb02b225c5c05a4477bef58bdaceede5d68dcandy 991029477547084d210cb810e8e5463c628972b315Irfan Sheriff 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct rfkill_data * rfkill_init(struct rfkill_config *cfg) 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rfkill_data *rfkill; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rfkill_event event; 10404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt ssize_t len; 10504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 10604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt rfkill = os_zalloc(sizeof(*rfkill)); 10704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (rfkill == NULL) 10804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt return NULL; 10904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rfkill->cfg = cfg; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rfkill->fd = open("/dev/rfkill", O_RDONLY); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rfkill->fd < 0) { 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "device"); 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%s", strerror(errno)); 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail2; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = read(rfkill->fd, &event, sizeof(event)); 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len < 0) { 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (errno == EAGAIN) 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; /* No more entries */ 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt strerror(errno)); 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len != RFKILL_EVENT_SIZE_V1) { 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (expected %d)", 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (int) len, RFKILL_EVENT_SIZE_V1); 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "op=%u soft=%u hard=%u", 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt event.idx, event.type, event.op, event.soft, 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt event.hard); 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (event.op != RFKILL_OP_ADD || 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt event.type != RFKILL_TYPE_WLAN) 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (event.hard) { 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 1481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rfkill->blocked = 1; 1491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } else if (event.soft) { 1501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 1511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt rfkill->blocked = 1; 1521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt } 1541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); 1561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rfkill; 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail2: 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(rfkill->fd); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(rfkill); 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid rfkill_deinit(struct rfkill_data *rfkill) 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rfkill == NULL) 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rfkill->fd >= 0) { 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_unregister_read_sock(rfkill->fd); 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(rfkill->fd); 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(rfkill->cfg); 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(rfkill); 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint rfkill_is_blocked(struct rfkill_data *rfkill) 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rfkill == NULL) 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return rfkill->blocked; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt