| /* |
| * Copyright 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <getopt.h> |
| |
| #define LOG_TAG "bdAddrLoader" |
| |
| #include <cutils/log.h> |
| #include <cutils/properties.h> |
| |
| #define FILE_PATH_MAX 100 |
| #define BD_ADDR_LEN 6 |
| #define BD_ADDR_STR_LEN 18 |
| |
| |
| #define ARG_TYPE_PATH_FILE 0x11 |
| #define ARG_TYPE_PATH_PROP 0x12 |
| |
| #define ARG_TYPE_DATA_HEX 0x21 |
| #define ARG_TYPE_DATA_ASCII 0x22 |
| |
| typedef struct _ArgEl |
| { |
| const char *szSrc; // Source Path |
| int nPathType; // Type of Source Path |
| int nDataType; // Type of Data |
| }ArgEl; |
| |
| typedef ArgEl InArg; |
| |
| #define DEFAULT_BDADDR_PROP "persist.service.bdroid.bdaddr" |
| |
| typedef struct _OutArg |
| { |
| ArgEl dest; |
| char cSeperator; // a character to be used for sperating like ':' of "XX:XX:XX:XX:XX:XX" |
| char bPrintOut; // Print out bd addr in standard out or not |
| }OutArg; |
| |
| typedef struct _LoadedData |
| { |
| union { |
| unsigned char bin[BD_ADDR_LEN]; |
| char sz[BD_ADDR_STR_LEN]; |
| }data; |
| int nDataType; |
| }LoadedBDAddr; |
| |
| typedef enum _res |
| { |
| SUCCESS = 0, |
| FAIL |
| }Res; |
| |
| int hexa_to_ascii(const unsigned char* hexa, char* ascii, int nHexLen) |
| { |
| int i, j; |
| char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
| 'A', 'B', 'C', 'D', 'E', 'F'}; |
| |
| for (i = 0, j = 0; i <nHexLen; i++, j += 2) { |
| ascii[j] = hex_table[hexa[i] >> 4]; |
| ascii[j + 1] = hex_table[hexa[i] & 0x0F]; |
| } |
| |
| ascii[nHexLen*2] = '\0'; |
| |
| ALOGI("hex_to_ascii() - converted Data (%s)", ascii); |
| |
| return SUCCESS; |
| } |
| |
| int readBDAddrData(const char* szFilePath, unsigned char* addrData, int nDataLen) |
| { |
| int nFd, nRdCnt; |
| |
| nFd = open(szFilePath, O_RDONLY); |
| |
| if(nFd < 0){ |
| ALOGW("There is no Address File in FTM area : %s\n", szFilePath); |
| return FAIL; |
| } |
| |
| nRdCnt = read(nFd, addrData, nDataLen); |
| if(nRdCnt != nDataLen){ |
| ALOGE("Fail to read Address data from FTM area\n"); |
| close(nFd); |
| return FAIL; |
| } |
| close(nFd); |
| return SUCCESS; |
| } |
| |
| void formattingBdAddr(char *szBDAddr, const char cSep) |
| { |
| int i=1, j=0; |
| int pos=0; |
| for(i=1; i<BD_ADDR_LEN; i++){ |
| pos = strlen(szBDAddr); |
| for(j=0; j<(BD_ADDR_LEN*2)-i*2; j++){ |
| szBDAddr[pos-j] = szBDAddr[pos-j-1]; |
| } |
| szBDAddr[pos-j]=cSep; |
| } |
| } |
| |
| int readBDAddr(InArg inArg, LoadedBDAddr *loadedBDAddr) |
| { |
| Res res = FAIL; |
| unsigned char addrData[BD_ADDR_LEN] = {0,}; |
| int nDataLen = 0; |
| |
| ALOGI("Read From %s by Path type(0x%2x), Data type (0x%2x)", inArg.szSrc, inArg.nPathType, inArg.nDataType); |
| |
| |
| if(inArg.nPathType == ARG_TYPE_PATH_FILE){ |
| switch(inArg.nDataType){ |
| case ARG_TYPE_DATA_HEX: |
| if(!readBDAddrData(inArg.szSrc, loadedBDAddr->data.bin, BD_ADDR_LEN)){ |
| loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; |
| return SUCCESS; |
| } |
| break; |
| case ARG_TYPE_DATA_ASCII: |
| if(!readBDAddrData(inArg.szSrc, (unsigned char *)loadedBDAddr->data.sz, BD_ADDR_STR_LEN)){ |
| loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; |
| return SUCCESS; |
| } |
| break; |
| default: |
| return FAIL; |
| } |
| }else if(inArg.nPathType == ARG_TYPE_PATH_PROP){ |
| switch(inArg.nDataType){ |
| case ARG_TYPE_DATA_HEX: |
| if(property_get(inArg.szSrc, (char *)loadedBDAddr->data.bin, "")>=0){ |
| loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; |
| return SUCCESS; |
| } |
| break; |
| case ARG_TYPE_DATA_ASCII: |
| if(property_get(inArg.szSrc, loadedBDAddr->data.sz, "")>=0){ |
| loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; |
| return SUCCESS; |
| } |
| break; |
| default: |
| return FAIL; |
| } |
| }else{ |
| ALOGE("Error invalid argument : (%d)", inArg.nPathType); |
| } |
| |
| ALOGE("Fail to read BDAddr from %s", inArg.szSrc); |
| return FAIL; |
| } |
| |
| int writeBDAddr(OutArg outArg, LoadedBDAddr *loadedBDAddr) |
| { |
| char szTmp[BD_ADDR_STR_LEN] = {0,}; |
| |
| ALOGI("Output Data type(0x%2x), bPrintout(%d), bPath(%s)", |
| outArg.dest.nDataType, outArg.bPrintOut, outArg.dest.szSrc); |
| |
| ALOGI("Loaded Data type(0x%2x)", loadedBDAddr->nDataType); |
| |
| if(outArg.dest.nDataType == ARG_TYPE_DATA_ASCII |
| && loadedBDAddr->nDataType == ARG_TYPE_DATA_HEX |
| ){ |
| if(!hexa_to_ascii(loadedBDAddr->data.bin, szTmp, BD_ADDR_LEN)){ |
| memcpy(loadedBDAddr->data.sz, szTmp, BD_ADDR_STR_LEN); |
| loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; |
| } |
| else{ |
| ALOGE("Fail to convert data"); |
| return FAIL; |
| } |
| } |
| |
| if(loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII){ |
| // check out which addr data is already formated |
| if(strchr(loadedBDAddr->data.sz, '.') == NULL |
| && strchr(loadedBDAddr->data.sz, ':') == NULL |
| ){ |
| formattingBdAddr(loadedBDAddr->data.sz, outArg.cSeperator); |
| } |
| } |
| // print out szBDAddr |
| if(outArg.bPrintOut |
| && loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII |
| && strlen(loadedBDAddr->data.sz)==(BD_ADDR_STR_LEN-1)) { |
| printf("%s",loadedBDAddr->data.sz); |
| if (property_set(DEFAULT_BDADDR_PROP, loadedBDAddr->data.sz) < 0) |
| ALOGE("Failed to set address in prop %s", DEFAULT_BDADDR_PROP); |
| } |
| else{ |
| ALOGE("Invalid Data is loaded : %s", loadedBDAddr->data.sz); |
| return FAIL; |
| } |
| // TODO :: writing File or Property |
| return SUCCESS; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int nFd, nRdCnt; |
| int c; |
| |
| InArg inArg; |
| OutArg outArg; |
| LoadedBDAddr loadedBDAddr; |
| |
| //initialize arg |
| memset(&inArg, 0, sizeof(InArg)); |
| memset(&outArg, 0, sizeof(OutArg)); |
| memset(&loadedBDAddr, 0, sizeof(LoadedBDAddr)); |
| |
| //load args; |
| while((c=getopt(argc, argv, ":f:p:hsx")) != -1){ |
| switch(c){ |
| case 'f': // input path |
| if(optarg != NULL){ |
| ALOGI("option : f=%s", optarg); |
| inArg.szSrc = optarg; |
| }else{ |
| ALOGW("Invalid Argument(%s) of input path", optarg); |
| } |
| inArg.nPathType = ARG_TYPE_PATH_FILE; |
| break; |
| case 'p': // output path |
| if(optarg != NULL){ |
| ALOGI("option : p=%s", optarg); |
| inArg.szSrc = optarg; |
| }else{ |
| ALOGW("Invalid Argument(%s) of out Path", optarg); |
| } |
| inArg.nPathType = ARG_TYPE_PATH_PROP; |
| break; |
| case 'h': // data type to be read is hex |
| ALOGI("option : h"); |
| inArg.nDataType = ARG_TYPE_DATA_HEX; |
| break; |
| case 's': // data type to be read is ascii |
| ALOGI("option : s"); |
| inArg.nDataType = ARG_TYPE_DATA_ASCII; |
| break; |
| case 'x': |
| ALOGI("option : x"); |
| outArg.bPrintOut = 1; //true |
| break; |
| default: |
| ALOGW("Unknown option : %c", c); |
| break; |
| } |
| } |
| |
| // setting up Arguments with default value |
| outArg.cSeperator = ':'; |
| outArg.dest.nDataType = ARG_TYPE_DATA_ASCII; |
| |
| // load bd addr and print out bd addr in formated ascii |
| if(readBDAddr(inArg, &loadedBDAddr)){ |
| ALOGE("Fail to load data !!"); |
| return FAIL; |
| } |
| |
| if(writeBDAddr(outArg, &loadedBDAddr)){ |
| ALOGE("Fail to write data !!"); |
| return FAIL; |
| } |
| |
| return 1; |
| } |