| // Copyright (c) 2010, Atmel Corporation. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are met: |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // * Neither the name of Atmel nor the |
| // names of its contributors may be used to endorse or promote products |
| // derived from this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY |
| // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include <signal.h> |
| #include <string.h> |
| #include <pthread.h> |
| #include <semaphore.h> |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| #include <sys/stat.h> |
| #include <errno.h> |
| #include <linux/netlink.h> |
| #include <cutils/properties.h> |
| #include <hardware_legacy/power.h> |
| #include <stdlib.h> |
| #include <time.h> |
| #include <linux/capability.h> |
| #include <linux/prctl.h> |
| #include <private/android_filesystem_config.h> |
| |
| #include <linux/spi/cpcap.h> |
| #include <linux/hidraw.h> |
| |
| |
| #include "SA_Phys_Linux.h" |
| #include "SHA_CommMarshalling.h" |
| #include "SHA_Status.h" |
| #include "SHA_Comm.h" |
| #include "SHA_TimeUtils.h" |
| #include "Whisper_AccyMain.h" |
| |
| |
| /*================================================================================================== |
| LOCAL CONSTANTS |
| ==================================================================================================*/ |
| static const char xintToChar[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; |
| static const char wakeLockString[] = "ACCYDET"; |
| static const uint8_t hidStatusQuery[] = {0x3f, 0x30, 0x00, 0x00, 0x42, 0x99}; |
| static const uint8_t hidIdQuery[] = {0x3f, 0x12, 0x00, 0x01, 0xf1, 0xe2}; |
| |
| |
| /*================================================================================================== |
| LOCAL MACROS |
| ==================================================================================================*/ |
| |
| #define MAX_TRY_WAKEUP 4 |
| #define MAX_TRY_COMM 2 |
| #define UART_SWITCH_STATE_PATH "/sys/class/switch/whisper/state" |
| #define HID_SWITCH_STATE_PATH "/sys/class/switch/whisper_hid/state" |
| #define DOCK_TYPE_OFFSET 27 |
| |
| #define DOCK_ATTACHED '1' |
| #define DOCK_NOT_ATTACHED '0' |
| |
| #define HID_SUCCESS 1 |
| #define HID_FAILURE 0 |
| |
| #define ID_SUCCESS 1 |
| |
| #define IOCTL_SUCCESS 0 |
| #define MAX_TRY_IOCTL 5 |
| |
| #define HID_STATUS_QUERY_LENGTH 64 |
| #define HID_ID_QUERY_LENGTH 64 |
| #define HID_MAC_QUERY_LENGTH 64 |
| #define HID_STATUS_MSG_LENGTH 64 |
| #define HID_ID_MSG_LENGTH 64 |
| #define HID_MAC_MSG_LENGTH 64 |
| |
| #define LOG_FILE_NAME "/data/whisper/whisperd.log" |
| #define LOG_FILE_PATH "/data/whisper" |
| |
| /*================================================================================================== |
| EXTERNAL VARIABLES |
| ==================================================================================================*/ |
| |
| /*================================================================================================== |
| LOCAL FUNCTION PROTOTYPES |
| ==================================================================================================*/ |
| static void copyResults(int8_t cmdSize, uint8_t *out); |
| static int accyInit(void); |
| static void accySigHandler(signed int signal); |
| static void accyProtDaemon(void *arg); |
| static void readSwitchState(int); |
| static int accySpawnThread(); |
| static void createOutput(uint8_t *inp, char *out, int bytes); |
| static void waitForUevents(); |
| static void doIoctl(int cmd, unsigned int data, char *dev_id, char *dev_prop); |
| |
| /*================================================================================================== |
| LOCAL VARIABLES |
| ==================================================================================================*/ |
| static SHA_CommParameters* mainparms; |
| static sem_t SigAccyProtStart; |
| static int ueventFd; |
| static int wakeLock = 0; |
| static int globalState; |
| static int globalProtocol; |
| static int cpcapFd = -1; |
| static int hidFd = -1; |
| |
| /*================================================================================================== |
| GLOBAL VARIABLES |
| ==================================================================================================*/ |
| FILE *logFp = NULL; |
| int currLogSize = 0; |
| |
| /*================================================================================================== |
| LOCAL FUNCTIONS |
| ==================================================================================================*/ |
| |
| |
| static void readSwitchState(int protocolType) { |
| const int SIZE = 16; |
| int switchFd = -1; |
| char buf[SIZE]; |
| int count; |
| |
| if (protocolType == PROTOCOL_UART) { |
| switchFd = open(UART_SWITCH_STATE_PATH, O_RDONLY, 0); |
| if (switchFd == -1) { |
| DBG_ERROR("Failed opening %s, errno = %s", UART_SWITCH_STATE_PATH, strerror(errno)); |
| return; |
| } |
| } |
| else if (protocolType == PROTOCOL_HID) { |
| switchFd = open(HID_SWITCH_STATE_PATH, O_RDONLY, 0); |
| if (switchFd == -1) { |
| DBG_ERROR("Failed opening %s, errno = %s", HID_SWITCH_STATE_PATH, strerror(errno)); |
| return; |
| } |
| } |
| |
| do { |
| count = read(switchFd, buf, SIZE); |
| } while (count < 0 && errno == EINTR); |
| |
| if (count < 1) { |
| DBG_ERROR("Error reading switch, returned %d", count); |
| close(switchFd); |
| return; |
| } |
| |
| if (buf[0] == DOCK_ATTACHED) { |
| globalState = GLOBAL_STATE_DOCKED; |
| if (protocolType == PROTOCOL_HID) { |
| char hidDevice[] = "/dev/hidraw0"; |
| int i; |
| struct hidraw_devinfo hiddevinfo; |
| int status; |
| |
| globalProtocol = PROTOCOL_HID; |
| DBG_TRACE("HID Dock Attached"); |
| |
| for (i = 0; i < HIDRAW_MAX_DEVICES; i++) { |
| hidFd = open(hidDevice, O_RDWR); |
| |
| if(hidFd < 0) { |
| DBG_ERROR("Failed to open HID Device:%s", hidDevice); |
| break; |
| } |
| else { |
| status = ioctl(hidFd, HIDIOCGRAWINFO, &hiddevinfo); |
| |
| if (status != IOCTL_SUCCESS) { |
| DBG_ERROR("ioctl cmd:HIDIOCGRAWINFO failed for %s", hidDevice); |
| } |
| else { |
| if(hiddevinfo.vendor == 0x22b8 && hiddevinfo.product == 0x0938) { |
| DBG_TRACE("Found HD Dock: %s", hidDevice); |
| break; |
| } |
| else { |
| DBG_ERROR("Device: %s not a HD dock", hidDevice); |
| close(hidDevice); |
| } |
| } |
| // TODO: You cant do this. |
| hidDevice[11]++; |
| } |
| } |
| |
| hidDevice[11] = '0'; |
| } |
| else if (protocolType == PROTOCOL_UART) { |
| globalProtocol = PROTOCOL_UART; |
| } |
| } |
| else if (buf[0] == DOCK_NOT_ATTACHED) { |
| globalState = GLOBAL_STATE_UNDOCKED; |
| } |
| |
| close(switchFd); |
| } |
| |
| |
| static void waitForUevents() { |
| fd_set accySet; |
| char msg[1024]; |
| int nready, status; |
| |
| FD_ZERO(&accySet); |
| FD_SET(ueventFd, &accySet); |
| |
| /* at powerup, we might have missed the uevent. So, read switch */ |
| readSwitchState(PROTOCOL_HID); |
| |
| if (globalState == GLOBAL_STATE_DOCKED) { |
| DBG_TRACE("HID Dock attached at Power up"); |
| sem_post(&SigAccyProtStart); |
| } |
| else { |
| readSwitchState(PROTOCOL_UART); |
| if (globalState == GLOBAL_STATE_DOCKED) { |
| DBG_TRACE("UART Dock attached at Power up"); |
| sem_post(&SigAccyProtStart); |
| } |
| } |
| |
| while(1) { |
| nready = select(ueventFd+1, &accySet, NULL, NULL, NULL); |
| |
| if (nready > 0) { |
| if (FD_ISSET(ueventFd, &accySet)) { |
| status = recv(ueventFd, msg, sizeof(msg), MSG_DONTWAIT); |
| if ((status > 0) && (strcasestr(msg, "whisper_hid")) && (strcasestr(msg, "switch"))) { |
| readSwitchState(PROTOCOL_HID); |
| DBG_TRACE("HID: SEM POST after readSwitchState %d", globalState); |
| sem_post(&SigAccyProtStart); |
| } |
| else if ((status > 0) && (strcasestr(msg, "whisper")) && (strcasestr(msg, "switch"))) { |
| readSwitchState(PROTOCOL_UART); |
| DBG_TRACE("UART: SEM POST after readSwitchState %d", globalState); |
| sem_post(&SigAccyProtStart); |
| } |
| } |
| } |
| else { |
| DBG_ERROR("Select errored out. nready = %d, errno = %s", nready, strerror(errno)); |
| } |
| } |
| } |
| |
| |
| static int accySpawnThread() { |
| pthread_t id; |
| |
| if (pthread_create(&id, NULL, (void *(*)(void *))accyProtDaemon, NULL) != 0) { |
| DBG_ERROR("Pthread create failed. errno = %s", strerror(errno)); |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| /** Responsible for protocol communication */ |
| static void accyProtDaemon(void *arg) { |
| struct sched_param sched; |
| int currentPolicy, tryWakeup, tryComm; |
| pthread_t threadId; |
| uint8_t wakeupSuccess; |
| unsigned int dockDetails; |
| uint8_t dockType = NO_DOCK; |
| int status; |
| struct timespec ts; |
| struct timeval tv; |
| uint8_t statusFuse[8], FSNo[8], RomSN[8], RomRNo[8]; |
| char devInfo[32]; |
| char devProp[8]; |
| |
| threadId = pthread_self(); |
| status = pthread_getschedparam(threadId, ¤tPolicy, &sched); |
| |
| if (status != 0) { |
| DBG_ERROR("pthread_getschedparam error. erno = %s", strerror(status)); |
| return; |
| } |
| |
| currentPolicy = SCHED_RR; |
| sched.sched_priority = 70; |
| |
| status = pthread_setschedparam(threadId, currentPolicy, &sched); |
| if (status != 0) { |
| DBG_ERROR("pthread_setschedparam error. erno = %s", strerror(status)); |
| return; |
| } |
| |
| switchUser(); |
| |
| while(1) { |
| do { |
| status = sem_wait(&SigAccyProtStart); |
| } while (status < 0 && errno == EINTR); |
| |
| if (status == -1) { |
| DBG_ERROR("SEM WAIT failed with -1. errno = %s", strerror(errno)); |
| break; |
| } |
| |
| /* If already undocked, why do anything */ |
| if (globalState == GLOBAL_STATE_UNDOCKED) { |
| DBG_TRACE("Thread. GLOBAL_STATE_UNDOCKED"); |
| continue; |
| } |
| |
| if (globalProtocol == PROTOCOL_UART) { |
| doIoctl(CPCAP_IOCTL_ACCY_WHISPER, CPCAP_WHISPER_ENABLE_UART, NULL, NULL); |
| } |
| |
| wakeLock = acquire_wake_lock(PARTIAL_WAKE_LOCK, wakeLockString); |
| tryComm = 1; |
| while (tryComm && (globalState == GLOBAL_STATE_DOCKED)) { |
| if (globalProtocol == PROTOCOL_UART) { |
| if (SHA_SUCCESS == SHAP_OpenChannel()) { |
| tryWakeup = 1; |
| wakeupSuccess = 0; |
| while (tryWakeup) { |
| if (SHAC_Wakeup() == SHA_SUCCESS) { |
| DBG_TRACE("WAKEUP SUCCESS %d ", tryWakeup); |
| tryWakeup = 0; |
| wakeupSuccess = 1; |
| } |
| else { |
| if (tryWakeup == MAX_TRY_WAKEUP) { |
| DBG_ERROR("GIVING UP WAKEUP after %d tries", tryWakeup); |
| tryWakeup = 0; |
| } |
| else { |
| DBG_TRACE("TRYING WAKEUP ONCE MORE"); |
| ts.tv_sec = 0; |
| ts.tv_nsec = 10000000; // 10 ms |
| nanosleep(&ts, NULL); |
| tryWakeup++; |
| } |
| } |
| |
| if (globalState == GLOBAL_STATE_UNDOCKED) { |
| tryWakeup = 0; |
| } |
| } |
| |
| if ((wakeupSuccess) && (globalState == GLOBAL_STATE_DOCKED)) { |
| DBG_TRACE("Reading Status & MfgId"); |
| // Read Status fuses and MfgId fuses |
| status = SHAC_Read(0x01, 0x0002); |
| if (status == SHA_SUCCESS) { |
| copyResults(8, statusFuse); |
| // TODO: bytes in wrong order for some reason?? |
| uint8_t temp[2]; |
| temp[0] = statusFuse[1]; |
| temp[1] = statusFuse[3]; |
| statusFuse[1] = temp[1]; |
| statusFuse[3] = temp[0]; |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED && status == SHA_SUCCESS) { |
| DBG_TRACE("Reading Serial Number"); |
| // Read Fuse Serial number value |
| status = SHAC_Read(0x01, 0x0003); |
| if (status == SHA_SUCCESS) { |
| copyResults(8, FSNo); |
| } |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED && status == SHA_SUCCESS) { |
| DBG_TRACE("Reading ROM MfgId and ROM SN"); |
| // ROM MfgId and ROM SN |
| status = SHAC_Read(0x00, 0x0000); |
| if (status == SHA_SUCCESS) { |
| copyResults(8, RomSN); |
| DBG_TRACE("Authentication succeed"); |
| globalState = GLOBAL_STATE_DOCKED_IDSUCC; |
| } |
| } |
| } |
| } |
| |
| SHAP_CloseChannel(); |
| } |
| else if (globalProtocol == PROTOCOL_HID) { |
| uint8_t writebuff[65] = {0x0}; |
| uint8_t readbuff[65] = {0x0}; |
| uint8_t displaybuff[65] = {0x0}; |
| int hidStatus; |
| |
| DBG_TRACE("HID: Sending status query"); |
| hidStatus = HID_FAILURE; |
| memset(writebuff,0x00,sizeof(writebuff)); |
| memcpy(writebuff, hidStatusQuery, sizeof(hidStatusQuery)); |
| |
| status = write(hidFd, writebuff, HID_STATUS_QUERY_LENGTH); |
| if (status != HID_STATUS_QUERY_LENGTH) { |
| DBG_ERROR("Failed writing status query (errno = %s)", strerror(errno)); |
| } |
| else { |
| hidStatus = HID_SUCCESS; |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) { |
| DBG_TRACE("HID: Reading status query response"); |
| status = read(hidFd, readbuff, HID_STATUS_MSG_LENGTH); |
| |
| if (status != HID_STATUS_MSG_LENGTH) { |
| DBG_ERROR("HID: Failed reading status query response, errno = %s", strerror(errno)); |
| hidStatus = HID_FAILURE; |
| } |
| else { |
| DBG_TRACE("Contents of receive buffer"); |
| DBG_TRACE("first 3 bytes: %02X%02X%02X", readbuff[0], readbuff[1], readbuff[2]); |
| DBG_TRACE("Status: %02X%02X", readbuff[3], readbuff[4]); |
| DBG_TRACE("Ref Num: %02X%02X", readbuff[5], readbuff[6]); |
| DBG_TRACE("Version: %s", &readbuff[6]); |
| } |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) { |
| DBG_TRACE("HID: Sending ID query"); |
| memset(writebuff,0x00,sizeof(writebuff)); |
| memcpy(writebuff, hidIdQuery, sizeof(hidIdQuery)); |
| |
| status = write(hidFd, writebuff, HID_ID_QUERY_LENGTH); |
| if (status != HID_ID_QUERY_LENGTH) { |
| DBG_ERROR("HID: Error writing ID query, %d", status); |
| hidStatus = HID_FAILURE; |
| } |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) { |
| DBG_TRACE("Reading ID query response"); |
| status = read(hidFd, readbuff, HID_ID_MSG_LENGTH); |
| |
| if (status != HID_ID_MSG_LENGTH) { |
| DBG_ERROR("HID: Error reading ID query response, errno = %s", strerror(errno)); |
| hidStatus = HID_FAILURE; |
| } |
| else { |
| DBG_TRACE("Contents of receive buffer"); |
| DBG_TRACE("first 3-2 bytes: %02X%02X%02X", readbuff[0], readbuff[1], readbuff[2]); |
| DBG_TRACE("Status: %02X%02X", readbuff[3], readbuff[4]); |
| DBG_TRACE("Ref Num: %02X%02X", readbuff[5], readbuff[6]); |
| DBG_TRACE("SEMU ID: %02X%02X%02X", readbuff[7], readbuff[8], readbuff[9]); |
| DBG_TRACE("Manufacturer ID: %02X", readbuff[10]); |
| DBG_TRACE("ROM Revision: %02X%02X%02X%02X", readbuff[11], readbuff[12], readbuff[13], readbuff[14]); |
| DBG_TRACE("Fuse SN: %02X%02X%02X%02X", readbuff[15], readbuff[16], readbuff[17], readbuff[18]); |
| DBG_TRACE("ROM SN: %02X%02X", readbuff[19], readbuff[20]); |
| |
| statusFuse[1] = readbuff[6]; |
| statusFuse[2] = readbuff[7]; |
| statusFuse[3] = readbuff[8]; |
| FSNo[1] = readbuff[14]; |
| FSNo[2] = readbuff[15]; |
| FSNo[3] = readbuff[16]; |
| FSNo[4] = readbuff[17]; |
| RomSN[3] = readbuff[18]; |
| RomSN[4] = readbuff[19]; |
| |
| globalState = GLOBAL_STATE_DOCKED_IDSUCC; |
| } |
| } |
| } |
| |
| if (globalState == GLOBAL_STATE_DOCKED_IDSUCC) { |
| dockType = NO_DOCK; |
| if (statusFuse[1] == 0x0A && statusFuse[2] == 0xC0) { |
| dockType = LE_DOCK; |
| DBG_TRACE("It's a Low End Dock"); |
| } |
| else if (statusFuse[1] == 0x12 && statusFuse[2] == 0xC0 && statusFuse[3] == 0x00) { |
| dockType = CAR_DOCK; |
| DBG_TRACE("It's a Car Dock"); |
| } |
| else if (statusFuse[1] == 0x1A && statusFuse[2] == 0x80 && statusFuse[3] == 0x00) { |
| dockType = HE_DOCK; |
| DBG_TRACE("It's a High End Dock"); |
| } |
| |
| /* Format the output */ |
| createOutput(&FSNo[1],&devInfo[0], 4); |
| createOutput(&RomSN[3],&devInfo[8], 2); |
| devInfo[12] = 0; |
| |
| createOutput(&statusFuse[1], &devProp[0], 3); |
| devProp[6] = 0; |
| |
| DBG_TRACE("ID SUCCESS %s", devInfo); |
| if(dockType == NO_DOCK) |
| DBG_TRACE("UNKNOWN STATUS FUSES <%d><%d><%d>\n", statusFuse[1], statusFuse[2], statusFuse[3]); |
| |
| tryComm = 0; |
| dockDetails = ID_SUCCESS; |
| dockDetails |= (dockType << DOCK_TYPE_OFFSET); |
| doIoctl(CPCAP_IOCTL_ACCY_WHISPER, dockDetails, devInfo, devProp); |
| globalState = GLOBAL_STATE_DOCKED_IDSUCC; |
| memset(devInfo,0x00,sizeof(devInfo)); |
| memset(devProp,0x00,sizeof(devProp)); |
| } |
| |
| /* if the global state is still docked, then increment the retry counter */ |
| if (globalState == GLOBAL_STATE_DOCKED) { |
| if (tryComm == MAX_TRY_COMM) { |
| DBG_ERROR("GIVING UP AFTER %d tries", tryComm); |
| tryComm = 0; |
| |
| dockDetails = 0; // set bit 0, for AUTH to be failure |
| doIoctl(CPCAP_IOCTL_ACCY_WHISPER, dockDetails, NULL, NULL); |
| |
| globalState = GLOBAL_STATE_DOCKED_IDFAIL; |
| } |
| else { |
| ts.tv_sec = 0; |
| ts.tv_nsec = 100000000; // 100 ms |
| nanosleep(&ts, NULL); |
| |
| tryComm++; |
| DBG_TRACE("Trying COMM %d time", tryComm); |
| } |
| } |
| } |
| |
| if (wakeLock) { |
| release_wake_lock(wakeLockString); |
| wakeLock = 0; |
| } |
| } |
| } |
| |
| |
| static void createOutput(uint8_t *inp, char *out, int bytes) { |
| int i, j; |
| |
| for (i = 0; i < bytes; i++) { |
| j = (inp[i] & 0x0F); |
| out[i*2+1] = xintToChar[j]; |
| j = ((inp[i] >> 4) & 0xFF); |
| out[i*2] = xintToChar[j]; |
| } |
| } |
| |
| |
| static void accySigHandler(signed int signal) { |
| switch(signal) { |
| case SIGINT: |
| case SIGKILL: |
| case SIGTERM: |
| /* cose fds */ |
| if (cpcapFd > 0) |
| close(cpcapFd); |
| if (ttyFd > 0) |
| close(ttyFd); |
| if (hidFd > 0) |
| close(hidFd); |
| exit(0); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| |
| static int accyInit(void) { |
| struct sockaddr_nl addr; |
| int sz = 64*1024; |
| int s; |
| struct sigaction shutdownAction; |
| struct stat statBuf; |
| |
| #if defined(LOG_ACCY_FS) |
| if(stat(LOG_FILE_PATH, &statBuf) == 0) { |
| logFp = fopen(LOG_FILE_NAME, "w"); |
| if (logFp == NULL) { |
| ALOGE("whisperd: Unable to open the Logfile %s", LOG_FILE_NAME); |
| } |
| } |
| #endif |
| |
| cpcapFd = open("/dev/cpcap", O_RDWR); |
| |
| if (cpcapFd == -1) { |
| DBG_ERROR("/dev/cpcap could not be opened. err = %s", strerror(errno)); |
| } |
| else { |
| DBG_TRACE("/dev/cpcap opened: %d", cpcapFd); |
| } |
| |
| /* Setup the shutdown action. */ |
| shutdownAction.sa_handler = accySigHandler; |
| sigemptyset(&shutdownAction.sa_mask); |
| shutdownAction.sa_flags = 0; |
| |
| /* Setup the signal handler. */ |
| sigaction(SIGINT, &shutdownAction, NULL); |
| sigaction(SIGKILL, &shutdownAction, NULL); |
| sigaction(SIGTERM, &shutdownAction, NULL); |
| |
| globalState = GLOBAL_STATE_UNDOCKED; |
| |
| memset(&addr, 0, sizeof(addr)); |
| addr.nl_family = AF_NETLINK; |
| addr.nl_pid = getpid(); |
| addr.nl_groups = 0xffffffff; |
| |
| s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); |
| if (s < 0) { |
| DBG_ERROR("Socket failed. err = %s", strerror(errno)); |
| return 0; |
| } |
| |
| setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); |
| |
| if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
| DBG_ERROR("Bind failed. errno = %d", errno); |
| close(s); |
| return 0; |
| } |
| |
| ueventFd = s; |
| |
| return (ueventFd > 0); |
| } |
| |
| |
| |
| void doIoctl(int cmd, unsigned int data, char *dev_id, char *dev_prop) { |
| int i, status = -1; |
| struct timespec ts; |
| struct cpcap_whisper_request req; |
| |
| memset(req.dock_id, 0, CPCAP_WHISPER_ID_SIZE); |
| req.cmd = data; |
| if(dev_id != NULL) |
| strcpy(req.dock_id, dev_id); |
| if(dev_prop != NULL) |
| strcpy(req.dock_prop, dev_prop); |
| |
| for (i = 0; i < MAX_TRY_IOCTL; i++) { |
| DBG_TRACE("ioctl cmd %d: %d,", cmd, data); |
| if(dev_id == NULL) { |
| DBG_TRACE("ioctl id = NULL"); |
| } |
| else { |
| DBG_TRACE("ioctl id = <%s>\n", req.dock_id); |
| } |
| |
| status = ioctl(cpcapFd, cmd, &req); |
| |
| if (status != IOCTL_SUCCESS) { |
| DBG_ERROR("ioctl returned %d with error: %d", status, errno); |
| ts.tv_sec = 0; |
| ts.tv_nsec = 50000000; // 50 ms |
| DBG_TRACE("Wait 50ms."); |
| nanosleep(&ts, NULL); |
| globalState = GLOBAL_STATE_UNDOCKED; |
| } |
| else { |
| DBG_TRACE("ioctl success"); |
| globalState = GLOBAL_STATE_DOCKED; |
| break; |
| } |
| } |
| |
| if (hidFd > 0) { |
| close(hidFd); |
| hidFd = -1; |
| } |
| |
| return; |
| } |
| |
| |
| static void copyResults(int8_t cmdSize, uint8_t *out) { |
| int i; |
| char charOut[128]; |
| |
| mainparms = SHAC_GetData(); |
| |
| createOutput(mainparms->txBuffer, charOut, cmdSize); |
| charOut[cmdSize*2] = '\0'; |
| |
| DBG_TRACE("Send Value: %s", charOut); |
| |
| for(i = 0; i < mainparms->rxSize; i++) { |
| out[i] = mainparms->rxBuffer[i]; |
| } |
| |
| createOutput(mainparms->rxBuffer, charOut, cmdSize); |
| charOut[cmdSize*2] = '\0'; |
| DBG_TRACE("Receive Value: = %s", charOut); |
| } |
| |
| |
| |
| int main(int argc, char *argv[]) { |
| int retVal; |
| |
| retVal = accyInit(); |
| |
| if (retVal <= 0) { |
| DBG_ERROR("accyInit failed"); |
| } |
| |
| if (sem_init(&SigAccyProtStart, 0, 0) != 0) { |
| DBG_ERROR("Sem_init failed. errno = %d", errno); |
| } |
| |
| //TODO: First time failure to set parameters |
| SHAP_OpenChannel(); |
| SHAP_CloseFile(); |
| |
| retVal = accySpawnThread(); |
| |
| switchUser(); |
| waitForUevents(); |
| |
| return 1; |
| } |
| |
| |
| int switchUser( void ) { |
| int status; |
| |
| status = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); |
| if (status < 0) { |
| return status; |
| } |
| |
| status = setuid(AID_RADIO); |
| if (status < 0) { |
| return status; |
| } |
| |
| struct __user_cap_header_struct header; |
| struct __user_cap_data_struct cap; |
| header.version = _LINUX_CAPABILITY_VERSION; |
| header.pid = 0; |
| cap.effective = cap.permitted = 1 << CAP_NET_ADMIN; |
| cap.inheritable = 0; |
| status = capset(&header, &cap); |
| |
| return status; |
| } |
| |