Home | History | Annotate | Download | only in whisper
      1 // Copyright (c) 2010, Atmel Corporation.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above copyright
      9 //       notice, this list of conditions and the following disclaimer in the
     10 //       documentation and/or other materials provided with the distribution.
     11 //     * Neither the name of Atmel nor the
     12 //       names of its contributors may be used to endorse or promote products
     13 //       derived from this software without specific prior written permission.
     14 //
     15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
     19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25 
     26 #include <signal.h>
     27 #include <string.h>
     28 #include <pthread.h>
     29 #include <semaphore.h>
     30 #include <unistd.h>
     31 #include <stdio.h>
     32 #include <fcntl.h>
     33 #include <sys/ioctl.h>
     34 #include <sys/socket.h>
     35 #include <sys/un.h>
     36 #include <sys/stat.h>
     37 #include <errno.h>
     38 #include <linux/netlink.h>
     39 #include <cutils/properties.h>
     40 #include <hardware_legacy/power.h>
     41 #include <stdlib.h>
     42 #include <time.h>
     43 #include <linux/capability.h>
     44 #include <linux/prctl.h>
     45 #include <private/android_filesystem_config.h>
     46 
     47 #include <linux/spi/cpcap.h>
     48 #include <linux/hidraw.h>
     49 
     50 
     51 #include "SA_Phys_Linux.h"
     52 #include "SHA_CommMarshalling.h"
     53 #include "SHA_Status.h"
     54 #include "SHA_Comm.h"
     55 #include "SHA_TimeUtils.h"
     56 #include "Whisper_AccyMain.h"
     57 
     58 
     59 /*==================================================================================================
     60                                           LOCAL CONSTANTS
     61 ==================================================================================================*/
     62 static const char xintToChar[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
     63 static const char wakeLockString[] = "ACCYDET";
     64 static const uint8_t hidStatusQuery[] = {0x3f, 0x30, 0x00, 0x00, 0x42, 0x99};
     65 static const uint8_t hidIdQuery[] = {0x3f, 0x12, 0x00, 0x01, 0xf1, 0xe2};
     66 
     67 
     68 /*==================================================================================================
     69                                             LOCAL MACROS
     70 ==================================================================================================*/
     71 
     72 #define MAX_TRY_WAKEUP                  4
     73 #define MAX_TRY_COMM                    2
     74 #define UART_SWITCH_STATE_PATH          "/sys/class/switch/whisper/state"
     75 #define HID_SWITCH_STATE_PATH           "/sys/class/switch/whisper_hid/state"
     76 #define DOCK_TYPE_OFFSET                27
     77 
     78 #define DOCK_ATTACHED                   '1'
     79 #define DOCK_NOT_ATTACHED               '0'
     80 
     81 #define HID_SUCCESS                     1
     82 #define HID_FAILURE                     0
     83 
     84 #define ID_SUCCESS                      1
     85 
     86 #define IOCTL_SUCCESS                   0
     87 #define MAX_TRY_IOCTL                   5
     88 
     89 #define HID_STATUS_QUERY_LENGTH         64
     90 #define HID_ID_QUERY_LENGTH             64
     91 #define HID_MAC_QUERY_LENGTH            64
     92 #define HID_STATUS_MSG_LENGTH		64
     93 #define HID_ID_MSG_LENGTH		64
     94 #define HID_MAC_MSG_LENGTH		64
     95 
     96 #define LOG_FILE_NAME                   "/data/whisper/whisperd.log"
     97 #define LOG_FILE_PATH                   "/data/whisper"
     98 
     99 /*==================================================================================================
    100                                           EXTERNAL VARIABLES
    101 ==================================================================================================*/
    102 
    103 /*==================================================================================================
    104                                      LOCAL FUNCTION PROTOTYPES
    105 ==================================================================================================*/
    106 static void copyResults(int8_t cmdSize, uint8_t *out);
    107 static int  accyInit(void);
    108 static void accySigHandler(signed int signal);
    109 static void accyProtDaemon(void *arg);
    110 static void readSwitchState(int);
    111 static int  accySpawnThread();
    112 static void createOutput(uint8_t *inp, char *out, int bytes);
    113 static void waitForUevents();
    114 static void doIoctl(int cmd, unsigned int data, char *dev_id, char *dev_prop);
    115 
    116 /*==================================================================================================
    117                                           LOCAL VARIABLES
    118 ==================================================================================================*/
    119 static SHA_CommParameters*    mainparms;
    120 static sem_t SigAccyProtStart;
    121 static int ueventFd;
    122 static int wakeLock = 0;
    123 static int globalState;
    124 static int globalProtocol;
    125 static int cpcapFd = -1;
    126 static int hidFd = -1;
    127 
    128 /*==================================================================================================
    129                                           GLOBAL VARIABLES
    130 ==================================================================================================*/
    131 FILE *logFp = NULL;
    132 int  currLogSize = 0;
    133 
    134 /*==================================================================================================
    135                                           LOCAL FUNCTIONS
    136 ==================================================================================================*/
    137 
    138 
    139 static void readSwitchState(int protocolType) {
    140     const int SIZE = 16;
    141     int switchFd = -1;
    142     char buf[SIZE];
    143     int count;
    144 
    145     if (protocolType == PROTOCOL_UART) {
    146         switchFd = open(UART_SWITCH_STATE_PATH, O_RDONLY, 0);
    147         if (switchFd == -1) {
    148             DBG_ERROR("Failed opening %s, errno = %s", UART_SWITCH_STATE_PATH, strerror(errno));
    149             return;
    150         }
    151     }
    152     else if (protocolType == PROTOCOL_HID) {
    153         switchFd = open(HID_SWITCH_STATE_PATH, O_RDONLY, 0);
    154         if (switchFd == -1) {
    155             DBG_ERROR("Failed opening %s, errno = %s", HID_SWITCH_STATE_PATH, strerror(errno));
    156             return;
    157         }
    158     }
    159 
    160     do {
    161       count = read(switchFd, buf, SIZE);
    162     } while (count < 0 && errno == EINTR);
    163 
    164     if (count < 1) {
    165         DBG_ERROR("Error reading switch, returned %d", count);
    166         close(switchFd);
    167         return;
    168     }
    169 
    170     if (buf[0] == DOCK_ATTACHED) {
    171         globalState = GLOBAL_STATE_DOCKED;
    172         if (protocolType == PROTOCOL_HID) {
    173             char hidDevice[] = "/dev/hidraw0";
    174             int i;
    175             struct hidraw_devinfo hiddevinfo;
    176             int status;
    177 
    178             globalProtocol = PROTOCOL_HID;
    179             DBG_TRACE("HID Dock Attached");
    180 
    181             for (i = 0; i < HIDRAW_MAX_DEVICES; i++) {
    182                 hidFd = open(hidDevice, O_RDWR);
    183 
    184                 if(hidFd < 0) {
    185                     DBG_ERROR("Failed to open HID Device:%s", hidDevice);
    186                     break;
    187                 }
    188                 else {
    189                     status = ioctl(hidFd, HIDIOCGRAWINFO, &hiddevinfo);
    190 
    191                     if (status != IOCTL_SUCCESS) {
    192                         DBG_ERROR("ioctl cmd:HIDIOCGRAWINFO failed for %s", hidDevice);
    193                     }
    194                     else {
    195                         if(hiddevinfo.vendor == 0x22b8 && hiddevinfo.product == 0x0938) {
    196                             DBG_TRACE("Found HD Dock: %s", hidDevice);
    197                             break;
    198                         }
    199                         else {
    200                             DBG_ERROR("Device: %s not a HD dock", hidDevice);
    201                             close(hidDevice);
    202                         }
    203                     }
    204                     // TODO: You cant do this.
    205                     hidDevice[11]++;
    206                 }
    207             }
    208 
    209             hidDevice[11] = '0';
    210         }
    211         else if (protocolType == PROTOCOL_UART) {
    212             globalProtocol = PROTOCOL_UART;
    213         }
    214     }
    215     else if (buf[0] == DOCK_NOT_ATTACHED) {
    216         globalState = GLOBAL_STATE_UNDOCKED;
    217     }
    218 
    219     close(switchFd);
    220 }
    221 
    222 
    223 static void waitForUevents() {
    224     fd_set accySet;
    225     char msg[1024];
    226     int nready, status;
    227 
    228     FD_ZERO(&accySet);
    229     FD_SET(ueventFd, &accySet);
    230 
    231     /* at powerup, we might have missed the uevent. So, read switch */
    232     readSwitchState(PROTOCOL_HID);
    233 
    234     if (globalState == GLOBAL_STATE_DOCKED) {
    235         DBG_TRACE("HID Dock attached at Power up");
    236         sem_post(&SigAccyProtStart);
    237     }
    238     else {
    239         readSwitchState(PROTOCOL_UART);
    240         if (globalState == GLOBAL_STATE_DOCKED) {
    241             DBG_TRACE("UART Dock attached at Power up");
    242             sem_post(&SigAccyProtStart);
    243         }
    244     }
    245 
    246     while(1) {
    247         nready = select(ueventFd+1, &accySet, NULL, NULL, NULL);
    248 
    249         if (nready > 0) {
    250             if (FD_ISSET(ueventFd, &accySet)) {
    251                 status = recv(ueventFd, msg, sizeof(msg), MSG_DONTWAIT);
    252                 if ((status > 0) && (strcasestr(msg, "whisper_hid")) && (strcasestr(msg, "switch"))) {
    253                     readSwitchState(PROTOCOL_HID);
    254                     DBG_TRACE("HID: SEM POST after readSwitchState %d", globalState);
    255                     sem_post(&SigAccyProtStart);
    256                 }
    257                 else if ((status > 0) && (strcasestr(msg, "whisper")) && (strcasestr(msg, "switch"))) {
    258                     readSwitchState(PROTOCOL_UART);
    259                     DBG_TRACE("UART: SEM POST after readSwitchState %d", globalState);
    260                     sem_post(&SigAccyProtStart);
    261                 }
    262             }
    263         }
    264         else {
    265             DBG_ERROR("Select errored out. nready = %d, errno = %s", nready, strerror(errno));
    266         }
    267     }
    268 }
    269 
    270 
    271 static int accySpawnThread() {
    272     pthread_t id;
    273 
    274     if (pthread_create(&id, NULL,  (void *(*)(void *))accyProtDaemon, NULL) != 0) {
    275         DBG_ERROR("Pthread create failed. errno = %s", strerror(errno));
    276         return 0;
    277     }
    278 
    279     return 1;
    280 }
    281 
    282 /** Responsible for protocol communication */
    283 static void accyProtDaemon(void *arg) {
    284     struct sched_param sched;
    285     int currentPolicy, tryWakeup, tryComm;
    286     pthread_t threadId;
    287     uint8_t  wakeupSuccess;
    288     unsigned int dockDetails;
    289     uint8_t dockType = NO_DOCK;
    290     int status;
    291     struct timespec ts;
    292     struct timeval tv;
    293     uint8_t statusFuse[8], FSNo[8], RomSN[8], RomRNo[8];
    294     char devInfo[32];
    295     char devProp[8];
    296 
    297     threadId = pthread_self();
    298     status = pthread_getschedparam(threadId, &currentPolicy, &sched);
    299 
    300     if (status != 0) {
    301        DBG_ERROR("pthread_getschedparam error. erno = %s", strerror(status));
    302        return;
    303     }
    304 
    305     currentPolicy = SCHED_RR;
    306     sched.sched_priority = 70;
    307 
    308     status = pthread_setschedparam(threadId, currentPolicy, &sched);
    309     if (status != 0) {
    310         DBG_ERROR("pthread_setschedparam error. erno = %s", strerror(status));
    311         return;
    312     }
    313 
    314     switchUser();
    315 
    316     while(1) {
    317         do {
    318             status = sem_wait(&SigAccyProtStart);
    319         } while (status < 0 && errno == EINTR);
    320 
    321         if (status == -1) {
    322             DBG_ERROR("SEM WAIT failed with -1. errno = %s", strerror(errno));
    323             break;
    324         }
    325 
    326         /* If already undocked, why do anything */
    327         if (globalState == GLOBAL_STATE_UNDOCKED)  {
    328             DBG_TRACE("Thread. GLOBAL_STATE_UNDOCKED");
    329             continue;
    330         }
    331 
    332         if (globalProtocol == PROTOCOL_UART) {
    333             doIoctl(CPCAP_IOCTL_ACCY_WHISPER, CPCAP_WHISPER_ENABLE_UART, NULL, NULL);
    334         }
    335 
    336         wakeLock = acquire_wake_lock(PARTIAL_WAKE_LOCK, wakeLockString);
    337         tryComm = 1;
    338         while (tryComm && (globalState == GLOBAL_STATE_DOCKED)) {
    339             if (globalProtocol == PROTOCOL_UART) {
    340                 if (SHA_SUCCESS == SHAP_OpenChannel()) {
    341                     tryWakeup = 1;
    342                     wakeupSuccess = 0;
    343                     while (tryWakeup) {
    344                         if (SHAC_Wakeup() == SHA_SUCCESS) {
    345                             DBG_TRACE("WAKEUP SUCCESS %d ", tryWakeup);
    346                             tryWakeup = 0;
    347                             wakeupSuccess = 1;
    348                         }
    349                         else {
    350                             if (tryWakeup == MAX_TRY_WAKEUP) {
    351                                 DBG_ERROR("GIVING UP WAKEUP after %d tries", tryWakeup);
    352                                 tryWakeup = 0;
    353                             }
    354                             else {
    355                                 DBG_TRACE("TRYING WAKEUP ONCE MORE");
    356                                 ts.tv_sec = 0;
    357                                 ts.tv_nsec = 10000000; // 10 ms
    358                                 nanosleep(&ts, NULL);
    359                                 tryWakeup++;
    360                             }
    361                         }
    362 
    363                         if (globalState == GLOBAL_STATE_UNDOCKED) {
    364                             tryWakeup = 0;
    365                         }
    366                     }
    367 
    368                     if ((wakeupSuccess)  && (globalState == GLOBAL_STATE_DOCKED)) {
    369                         DBG_TRACE("Reading Status & MfgId");
    370                         // Read Status fuses and MfgId fuses
    371                         status = SHAC_Read(0x01, 0x0002);
    372                         if (status == SHA_SUCCESS) {
    373                             copyResults(8, statusFuse);
    374                             // TODO: bytes in wrong order for some reason??
    375                             uint8_t temp[2];
    376                             temp[0] = statusFuse[1];
    377                             temp[1] = statusFuse[3];
    378                             statusFuse[1] = temp[1];
    379                             statusFuse[3] = temp[0];
    380                         }
    381 
    382                         if (globalState == GLOBAL_STATE_DOCKED && status == SHA_SUCCESS) {
    383                             DBG_TRACE("Reading Serial Number");
    384                             // Read Fuse Serial number value
    385                             status = SHAC_Read(0x01, 0x0003);
    386                             if (status == SHA_SUCCESS) {
    387                                 copyResults(8, FSNo);
    388                             }
    389                         }
    390 
    391                         if (globalState == GLOBAL_STATE_DOCKED && status == SHA_SUCCESS) {
    392                             DBG_TRACE("Reading ROM MfgId and ROM SN");
    393                             // ROM MfgId and ROM SN
    394                             status = SHAC_Read(0x00, 0x0000);
    395                             if (status == SHA_SUCCESS) {
    396                                 copyResults(8, RomSN);
    397 				DBG_TRACE("Authentication succeed");
    398                                 globalState = GLOBAL_STATE_DOCKED_IDSUCC;
    399                             }
    400                         }
    401                     }
    402                 }
    403 
    404                 SHAP_CloseChannel();
    405             }
    406             else if (globalProtocol == PROTOCOL_HID) {
    407                 uint8_t writebuff[65] = {0x0};
    408                 uint8_t readbuff[65] = {0x0};
    409                 uint8_t displaybuff[65] = {0x0};
    410                 int hidStatus;
    411 
    412                 DBG_TRACE("HID: Sending status query");
    413                 hidStatus = HID_FAILURE;
    414                 memset(writebuff,0x00,sizeof(writebuff));
    415                 memcpy(writebuff, hidStatusQuery, sizeof(hidStatusQuery));
    416 
    417                 status = write(hidFd, writebuff, HID_STATUS_QUERY_LENGTH);
    418                 if (status != HID_STATUS_QUERY_LENGTH) {
    419                     DBG_ERROR("Failed writing status query (errno = %s)", strerror(errno));
    420                 }
    421                 else {
    422                     hidStatus = HID_SUCCESS;
    423                 }
    424 
    425                 if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) {
    426                     DBG_TRACE("HID: Reading status query response");
    427                     status = read(hidFd, readbuff, HID_STATUS_MSG_LENGTH);
    428 
    429                     if (status != HID_STATUS_MSG_LENGTH) {
    430                         DBG_ERROR("HID: Failed reading status query response, errno = %s", strerror(errno));
    431                         hidStatus = HID_FAILURE;
    432                     }
    433                     else {
    434                         DBG_TRACE("Contents of receive buffer");
    435                         DBG_TRACE("first 3 bytes: %02X%02X%02X", readbuff[0], readbuff[1], readbuff[2]);
    436                         DBG_TRACE("Status: %02X%02X", readbuff[3], readbuff[4]);
    437                         DBG_TRACE("Ref Num: %02X%02X", readbuff[5], readbuff[6]);
    438                         DBG_TRACE("Version: %s", &readbuff[6]);
    439                     }
    440                 }
    441 
    442                 if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) {
    443                     DBG_TRACE("HID: Sending ID query");
    444                     memset(writebuff,0x00,sizeof(writebuff));
    445                     memcpy(writebuff, hidIdQuery, sizeof(hidIdQuery));
    446 
    447                     status = write(hidFd, writebuff, HID_ID_QUERY_LENGTH);
    448                     if (status != HID_ID_QUERY_LENGTH) {
    449                         DBG_ERROR("HID: Error writing ID query, %d", status);
    450                         hidStatus = HID_FAILURE;
    451                     }
    452                 }
    453 
    454                 if (globalState == GLOBAL_STATE_DOCKED && hidStatus == HID_SUCCESS) {
    455                     DBG_TRACE("Reading ID query response");
    456                     status = read(hidFd, readbuff, HID_ID_MSG_LENGTH);
    457 
    458                     if (status != HID_ID_MSG_LENGTH) {
    459                         DBG_ERROR("HID: Error reading ID query response, errno = %s", strerror(errno));
    460                         hidStatus = HID_FAILURE;
    461                     }
    462                     else {
    463                         DBG_TRACE("Contents of receive buffer");
    464                         DBG_TRACE("first 3-2 bytes: %02X%02X%02X", readbuff[0], readbuff[1], readbuff[2]);
    465                         DBG_TRACE("Status: %02X%02X", readbuff[3], readbuff[4]);
    466                         DBG_TRACE("Ref Num: %02X%02X", readbuff[5], readbuff[6]);
    467                         DBG_TRACE("SEMU ID: %02X%02X%02X", readbuff[7], readbuff[8], readbuff[9]);
    468                         DBG_TRACE("Manufacturer ID: %02X", readbuff[10]);
    469                         DBG_TRACE("ROM Revision: %02X%02X%02X%02X", readbuff[11], readbuff[12], readbuff[13], readbuff[14]);
    470                         DBG_TRACE("Fuse SN: %02X%02X%02X%02X", readbuff[15], readbuff[16], readbuff[17], readbuff[18]);
    471                         DBG_TRACE("ROM SN: %02X%02X", readbuff[19], readbuff[20]);
    472 
    473                         statusFuse[1] = readbuff[6];
    474                         statusFuse[2] = readbuff[7];
    475                         statusFuse[3] = readbuff[8];
    476                         FSNo[1] = readbuff[14];
    477                         FSNo[2] = readbuff[15];
    478                         FSNo[3] = readbuff[16];
    479                         FSNo[4] = readbuff[17];
    480                         RomSN[3] = readbuff[18];
    481                         RomSN[4] = readbuff[19];
    482 
    483                         globalState = GLOBAL_STATE_DOCKED_IDSUCC;
    484                     }
    485                 }
    486             }
    487 
    488             if (globalState == GLOBAL_STATE_DOCKED_IDSUCC) {
    489                 dockType = NO_DOCK;
    490                 if (statusFuse[1] == 0x0A && statusFuse[2] == 0xC0) {
    491                     dockType = LE_DOCK;
    492                     DBG_TRACE("It's a Low End Dock");
    493                 }
    494                 else if (statusFuse[1] == 0x12 && statusFuse[2] == 0xC0 && statusFuse[3] == 0x00) {
    495                     dockType = CAR_DOCK;
    496                     DBG_TRACE("It's a Car Dock");
    497                 }
    498                 else if (statusFuse[1] == 0x1A && statusFuse[2] == 0x80 && statusFuse[3] == 0x00) {
    499                     dockType = HE_DOCK;
    500                     DBG_TRACE("It's a High End Dock");
    501                 }
    502 
    503                 /* Format the output */
    504                 createOutput(&FSNo[1],&devInfo[0], 4);
    505                 createOutput(&RomSN[3],&devInfo[8], 2);
    506                 devInfo[12] = 0;
    507 
    508                 createOutput(&statusFuse[1], &devProp[0], 3);
    509                 devProp[6] = 0;
    510 
    511                 DBG_TRACE("ID SUCCESS %s", devInfo);
    512                 if(dockType == NO_DOCK)
    513                     DBG_TRACE("UNKNOWN STATUS FUSES <%d><%d><%d>\n", statusFuse[1], statusFuse[2], statusFuse[3]);
    514 
    515                 tryComm = 0;
    516                 dockDetails = ID_SUCCESS;
    517                 dockDetails |= (dockType << DOCK_TYPE_OFFSET);
    518                 doIoctl(CPCAP_IOCTL_ACCY_WHISPER, dockDetails, devInfo, devProp);
    519                 globalState = GLOBAL_STATE_DOCKED_IDSUCC;
    520                 memset(devInfo,0x00,sizeof(devInfo));
    521                 memset(devProp,0x00,sizeof(devProp));
    522             }
    523 
    524             /* if the global state is still docked, then increment the retry counter */
    525             if (globalState == GLOBAL_STATE_DOCKED) {
    526                 if (tryComm == MAX_TRY_COMM) {
    527                     DBG_ERROR("GIVING UP AFTER %d tries", tryComm);
    528                     tryComm = 0;
    529 
    530                     dockDetails = 0; // set bit 0, for AUTH to be failure
    531                     doIoctl(CPCAP_IOCTL_ACCY_WHISPER, dockDetails, NULL, NULL);
    532 
    533                     globalState = GLOBAL_STATE_DOCKED_IDFAIL;
    534                 }
    535                 else {
    536                     ts.tv_sec = 0;
    537                     ts.tv_nsec = 100000000; // 100 ms
    538                     nanosleep(&ts, NULL);
    539 
    540                     tryComm++;
    541                     DBG_TRACE("Trying COMM %d time", tryComm);
    542                 }
    543             }
    544         }
    545 
    546         if (wakeLock) {
    547             release_wake_lock(wakeLockString);
    548             wakeLock = 0;
    549         }
    550     }
    551 }
    552 
    553 
    554 static void createOutput(uint8_t *inp, char *out, int bytes) {
    555     int i, j;
    556 
    557     for (i = 0; i < bytes; i++) {
    558         j = (inp[i]  & 0x0F);
    559         out[i*2+1] = xintToChar[j];
    560         j = ((inp[i] >> 4) & 0xFF);
    561         out[i*2] = xintToChar[j];
    562     }
    563 }
    564 
    565 
    566 static void accySigHandler(signed int signal) {
    567     switch(signal) {
    568         case SIGINT:
    569         case SIGKILL:
    570         case SIGTERM:
    571              /* cose fds */
    572             if (cpcapFd > 0)
    573                 close(cpcapFd);
    574             if (ttyFd > 0)
    575                 close(ttyFd);
    576             if (hidFd > 0)
    577                 close(hidFd);
    578             exit(0);
    579             break;
    580         default:
    581             break;
    582     }
    583 }
    584 
    585 
    586 static int accyInit(void) {
    587     struct sockaddr_nl addr;
    588     int sz = 64*1024;
    589     int s;
    590     struct sigaction shutdownAction;
    591     struct stat statBuf;
    592 
    593 #if defined(LOG_ACCY_FS)
    594     if(stat(LOG_FILE_PATH, &statBuf) == 0) {
    595         logFp = fopen(LOG_FILE_NAME, "w");
    596         if (logFp == NULL) {
    597             LOGE("whisperd: Unable to open the Logfile %s", LOG_FILE_NAME);
    598         }
    599     }
    600 #endif
    601 
    602     cpcapFd = open("/dev/cpcap", O_RDWR);
    603 
    604     if (cpcapFd == -1) {
    605         DBG_ERROR("/dev/cpcap could not be opened. err = %s", strerror(errno));
    606     }
    607     else {
    608         DBG_TRACE("/dev/cpcap opened: %d", cpcapFd);
    609     }
    610 
    611     /* Setup the shutdown action. */
    612     shutdownAction.sa_handler = accySigHandler;
    613     sigemptyset(&shutdownAction.sa_mask);
    614     shutdownAction.sa_flags = 0;
    615 
    616     /* Setup the signal handler. */
    617     sigaction(SIGINT, &shutdownAction, NULL);
    618     sigaction(SIGKILL, &shutdownAction, NULL);
    619     sigaction(SIGTERM, &shutdownAction, NULL);
    620 
    621     globalState = GLOBAL_STATE_UNDOCKED;
    622 
    623     memset(&addr, 0, sizeof(addr));
    624     addr.nl_family = AF_NETLINK;
    625     addr.nl_pid = getpid();
    626     addr.nl_groups = 0xffffffff;
    627 
    628     s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    629     if (s < 0) {
    630         DBG_ERROR("Socket failed. err = %s", strerror(errno));
    631         return 0;
    632     }
    633 
    634     setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
    635 
    636     if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    637         DBG_ERROR("Bind failed. errno = %d", errno);
    638         close(s);
    639         return 0;
    640     }
    641 
    642     ueventFd = s;
    643 
    644     return (ueventFd > 0);
    645 }
    646 
    647 
    648 
    649 void doIoctl(int cmd, unsigned int data, char *dev_id, char *dev_prop) {
    650     int i, status = -1;
    651     struct timespec ts;
    652     struct cpcap_whisper_request req;
    653 
    654     memset(req.dock_id, 0, CPCAP_WHISPER_ID_SIZE);
    655     req.cmd = data;
    656     if(dev_id != NULL)
    657       strcpy(req.dock_id, dev_id);
    658     if(dev_prop != NULL)
    659       strcpy(req.dock_prop, dev_prop);
    660 
    661     for (i = 0; i < MAX_TRY_IOCTL; i++) {
    662         DBG_TRACE("ioctl cmd %d: %d,", cmd, data);
    663         if(dev_id == NULL) {
    664             DBG_TRACE("ioctl id = NULL");
    665         }
    666         else {
    667             DBG_TRACE("ioctl id = <%s>\n", req.dock_id);
    668         }
    669 
    670         status = ioctl(cpcapFd, cmd, &req);
    671 
    672         if (status != IOCTL_SUCCESS) {
    673             DBG_ERROR("ioctl returned %d with error: %d", status, errno);
    674             ts.tv_sec = 0;
    675             ts.tv_nsec = 50000000; // 50 ms
    676             DBG_TRACE("Wait 50ms.");
    677             nanosleep(&ts, NULL);
    678             globalState = GLOBAL_STATE_UNDOCKED;
    679         }
    680         else {
    681             DBG_TRACE("ioctl success");
    682             globalState = GLOBAL_STATE_DOCKED;
    683             break;
    684         }
    685     }
    686 
    687     if (hidFd > 0) {
    688         close(hidFd);
    689         hidFd = -1;
    690     }
    691 
    692     return;
    693 }
    694 
    695 
    696 static void copyResults(int8_t cmdSize, uint8_t *out) {
    697     int i;
    698     char charOut[128];
    699 
    700     mainparms = SHAC_GetData();
    701 
    702     createOutput(mainparms->txBuffer, charOut, cmdSize);
    703     charOut[cmdSize*2] = '\0';
    704 
    705     DBG_TRACE("Send Value: %s", charOut);
    706 
    707     for(i = 0; i < mainparms->rxSize; i++) {
    708             out[i] = mainparms->rxBuffer[i];
    709     }
    710 
    711     createOutput(mainparms->rxBuffer, charOut, cmdSize);
    712     charOut[cmdSize*2] = '\0';
    713     DBG_TRACE("Receive Value: = %s", charOut);
    714 }
    715 
    716 
    717 
    718 int main(int argc, char *argv[]) {
    719     int retVal;
    720 
    721     retVal = accyInit();
    722 
    723     if (retVal <= 0) {
    724        DBG_ERROR("accyInit failed");
    725     }
    726 
    727     if (sem_init(&SigAccyProtStart, 0, 0) != 0) {
    728         DBG_ERROR("Sem_init failed. errno = %d", errno);
    729     }
    730 
    731     //TODO:  First time failure to set parameters
    732     SHAP_OpenChannel();
    733     SHAP_CloseFile();
    734 
    735     retVal = accySpawnThread();
    736 
    737     switchUser();
    738     waitForUevents();
    739 
    740     return 1;
    741 }
    742 
    743 
    744 int switchUser( void ) {
    745     int status;
    746 
    747     status = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
    748     if (status < 0) {
    749         return status;
    750     }
    751 
    752     status = setuid(AID_RADIO);
    753     if (status < 0) {
    754          return status;
    755     }
    756 
    757     struct __user_cap_header_struct header;
    758     struct __user_cap_data_struct cap;
    759     header.version = _LINUX_CAPABILITY_VERSION;
    760     header.pid = 0;
    761     cap.effective = cap.permitted = 1 << CAP_NET_ADMIN;
    762     cap.inheritable = 0;
    763     status = capset(&header, &cap);
    764 
    765     return status;
    766 }
    767 
    768