rfkill.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Linux rfkill helper functions for driver wrappers 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (c) 2010, Jouni Malinen <j@w1.fi> 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This software may be distributed under the terms of the BSD license. 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * See README for more details. 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "includes.h" 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <fcntl.h> 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "utils/common.h" 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "utils/eloop.h" 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "rfkill.h" 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define RFKILL_EVENT_SIZE_V1 8 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct rfkill_event { 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) u32 idx; 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) u8 type; 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) u8 op; 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) u8 soft; 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) u8 hard; 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} STRUCT_PACKED; 25197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch 2653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)enum rfkill_operation { 277242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci RFKILL_OP_ADD = 0, 2806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) RFKILL_OP_DEL, 2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) RFKILL_OP_CHANGE, 309e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) RFKILL_OP_CHANGE_ALL, 31e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)}; 3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 33f91f5fa1608c2cdd9af1842fb5dadbe78275be2aBo Liuenum rfkill_type { 34bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles) RFKILL_TYPE_ALL = 0, 35bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles) RFKILL_TYPE_WLAN, 3651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) RFKILL_TYPE_BLUETOOTH, 37521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) RFKILL_TYPE_UWB, 38521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) RFKILL_TYPE_WIMAX, 39521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) RFKILL_TYPE_WWAN, 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RFKILL_TYPE_GPS, 41c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) RFKILL_TYPE_FM, 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) NUM_RFKILL_TYPES, 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 45df95704c49daea886ddad70775bda23618d6274dBen Murdoch 469e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)struct rfkill_data { 47df95704c49daea886ddad70775bda23618d6274dBen Murdoch struct rfkill_config *cfg; 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int fd; 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int blocked; 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 518abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void rfkill_receive(int sock, void *eloop_ctx, void *sock_ctx) 549e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles){ 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) struct rfkill_data *rfkill = eloop_ctx; 56df95704c49daea886ddad70775bda23618d6274dBen Murdoch struct rfkill_event event; 57df95704c49daea886ddad70775bda23618d6274dBen Murdoch ssize_t len; 5876c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles) int new_blocked; 599e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) 6076c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles) len = read(rfkill->fd, &event, sizeof(event)); 6176c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles) if (len < 0) { 627242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 6376c265b59aa821ccbf8c75ab2bb0d036e97d2956Torne (Richard Coles) strerror(errno)); 647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return; 65d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) } 66d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) if (len != RFKILL_EVENT_SIZE_V1) { 677242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) "%d (expected %d)", 69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) (int) len, RFKILL_EVENT_SIZE_V1); 7009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) return; 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_DEBUG, "rfkill: event: idx=%u type=%d " 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) "op=%u soft=%u hard=%u", 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) event.idx, event.type, event.op, event.soft, 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) event.hard); 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.op != RFKILL_OP_CHANGE || event.type != RFKILL_TYPE_WLAN) 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.hard) { 8002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new_blocked = 1; 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (event.soft) { 8302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 84e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) new_blocked = 1; 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_INFO, "rfkill: WLAN unblocked"); 878abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) new_blocked = 0; 889e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) } 899e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (new_blocked != rfkill->blocked) { 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rfkill->blocked = new_blocked; 9209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (new_blocked) 9309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) rfkill->cfg->blocked_cb(rfkill->cfg->ctx); 9409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) else 9509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) rfkill->cfg->unblocked_cb(rfkill->cfg->ctx); 96197021e6b966cfb06891637935ef33fff06433d1Ben Murdoch } 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 98e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 991e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)struct rfkill_data * rfkill_init(struct rfkill_config *cfg) 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 102a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) struct rfkill_data *rfkill; 103a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) struct rfkill_event event; 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ssize_t len; 1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 106df95704c49daea886ddad70775bda23618d6274dBen Murdoch rfkill = os_zalloc(sizeof(*rfkill)); 107a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) if (rfkill == NULL) 108a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) return NULL; 109a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) 110a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) rfkill->cfg = cfg; 111df95704c49daea886ddad70775bda23618d6274dBen Murdoch rfkill->fd = open("/dev/rfkill", O_RDONLY); 112df95704c49daea886ddad70775bda23618d6274dBen Murdoch if (rfkill->fd < 0) { 113df95704c49daea886ddad70775bda23618d6274dBen Murdoch wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control " 114df95704c49daea886ddad70775bda23618d6274dBen Murdoch "device"); 115df95704c49daea886ddad70775bda23618d6274dBen Murdoch goto fail; 116df95704c49daea886ddad70775bda23618d6274dBen Murdoch } 117df95704c49daea886ddad70775bda23618d6274dBen Murdoch 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (fcntl(rfkill->fd, F_SETFL, O_NONBLOCK) < 0) { 119a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) wpa_printf(MSG_ERROR, "rfkill: Cannot set non-blocking mode: " 1209e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) "%s", strerror(errno)); 121a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) goto fail2; 122a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) } 123df95704c49daea886ddad70775bda23618d6274dBen Murdoch 124c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) for (;;) { 125df95704c49daea886ddad70775bda23618d6274dBen Murdoch len = read(rfkill->fd, &event, sizeof(event)); 126e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if (len < 0) { 1279e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) if (errno == EAGAIN) 1289e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) break; /* No more entries */ 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_ERROR, "rfkill: Event read failed: %s", 130df95704c49daea886ddad70775bda23618d6274dBen Murdoch strerror(errno)); 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 132df95704c49daea886ddad70775bda23618d6274dBen Murdoch } 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (len != RFKILL_EVENT_SIZE_V1) { 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_DEBUG, "rfkill: Unexpected event size " 135a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) "%d (expected %d)", 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) (int) len, RFKILL_EVENT_SIZE_V1); 137df95704c49daea886ddad70775bda23618d6274dBen Murdoch continue; 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_DEBUG, "rfkill: initial event: idx=%u type=%d " 14002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch "op=%u soft=%u hard=%u", 141f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) event.idx, event.type, event.op, event.soft, 142f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) event.hard); 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.op != RFKILL_OP_ADD || 144e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) event.type != RFKILL_TYPE_WLAN) 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (event.hard) { 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_INFO, "rfkill: WLAN hard blocked"); 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rfkill->blocked = 1; 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (event.soft) { 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wpa_printf(MSG_INFO, "rfkill: WLAN soft blocked"); 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) rfkill->blocked = 1; 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 153d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) } 154d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles) 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL); 1561e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return rfkill; 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)fail2: 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) close(rfkill->fd); 16109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)fail: 16209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) os_free(rfkill); 16309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) return NULL; 164f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)} 165f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 166f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 16709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void rfkill_deinit(struct rfkill_data *rfkill) 16809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){ 16909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) if (rfkill == NULL) 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1717242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci 1727242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci if (rfkill->fd >= 0) { 1737242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci eloop_unregister_read_sock(rfkill->fd); 1747242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci close(rfkill->fd); 1757242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci } 176e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 177e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) os_free(rfkill->cfg); 178e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) os_free(rfkill); 179e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)} 180e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 181e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 182e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)int rfkill_is_blocked(struct rfkill_data *rfkill) 183e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles){ 184e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) if (rfkill == NULL) 185e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return 0; 186e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 187e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return rfkill->blocked; 1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1899e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles)