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, ¤tPolicy, &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 ALOGE("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