1 /* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <stdlib.h> 20 #include <sys/ioctl.h> 21 #include <sys/socket.h> 22 #include <sys/types.h> 23 #include <sys/stat.h> 24 #include <getopt.h> 25 26 #define LOG_TAG "bdAddrLoader" 27 28 #include <cutils/log.h> 29 #include <cutils/properties.h> 30 31 #define FILE_PATH_MAX 100 32 #define BD_ADDR_LEN 6 33 #define BD_ADDR_STR_LEN 18 34 35 36 #define ARG_TYPE_PATH_FILE 0x11 37 #define ARG_TYPE_PATH_PROP 0x12 38 39 #define ARG_TYPE_DATA_HEX 0x21 40 #define ARG_TYPE_DATA_ASCII 0x22 41 42 typedef struct _ArgEl 43 { 44 const char *szSrc; // Source Path 45 int nPathType; // Type of Source Path 46 int nDataType; // Type of Data 47 }ArgEl; 48 49 typedef ArgEl InArg; 50 51 #define DEFAULT_BDADDR_PROP "persist.service.bdroid.bdaddr" 52 53 typedef struct _OutArg 54 { 55 ArgEl dest; 56 char cSeperator; // a character to be used for sperating like ':' of "XX:XX:XX:XX:XX:XX" 57 char bPrintOut; // Print out bd addr in standard out or not 58 }OutArg; 59 60 typedef struct _LoadedData 61 { 62 union { 63 unsigned char bin[BD_ADDR_LEN]; 64 char sz[BD_ADDR_STR_LEN]; 65 }data; 66 int nDataType; 67 }LoadedBDAddr; 68 69 typedef enum _res 70 { 71 SUCCESS = 0, 72 FAIL 73 }Res; 74 75 int hexa_to_ascii(const unsigned char* hexa, char* ascii, int nHexLen) 76 { 77 int i, j; 78 char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 79 'A', 'B', 'C', 'D', 'E', 'F'}; 80 81 for (i = 0, j = 0; i <nHexLen; i++, j += 2) { 82 ascii[j] = hex_table[hexa[i] >> 4]; 83 ascii[j + 1] = hex_table[hexa[i] & 0x0F]; 84 } 85 86 ascii[nHexLen*2] = '\0'; 87 88 ALOGI("hex_to_ascii() - converted Data (%s)", ascii); 89 90 return SUCCESS; 91 } 92 93 int readBDAddrData(const char* szFilePath, unsigned char* addrData, int nDataLen) 94 { 95 int nFd, nRdCnt; 96 97 nFd = open(szFilePath, O_RDONLY); 98 99 if(nFd < 0){ 100 ALOGW("There is no Address File in FTM area : %s\n", szFilePath); 101 return FAIL; 102 } 103 104 nRdCnt = read(nFd, addrData, nDataLen); 105 if(nRdCnt != nDataLen){ 106 ALOGE("Fail to read Address data from FTM area\n"); 107 close(nFd); 108 return FAIL; 109 } 110 close(nFd); 111 return SUCCESS; 112 } 113 114 void formattingBdAddr(char *szBDAddr, const char cSep) 115 { 116 int i=1, j=0; 117 int pos=0; 118 for(i=1; i<BD_ADDR_LEN; i++){ 119 pos = strlen(szBDAddr); 120 for(j=0; j<(BD_ADDR_LEN*2)-i*2; j++){ 121 szBDAddr[pos-j] = szBDAddr[pos-j-1]; 122 } 123 szBDAddr[pos-j]=cSep; 124 } 125 } 126 127 int readBDAddr(InArg inArg, LoadedBDAddr *loadedBDAddr) 128 { 129 Res res = FAIL; 130 unsigned char addrData[BD_ADDR_LEN] = {0,}; 131 int nDataLen = 0; 132 133 ALOGI("Read From %s by Path type(0x%2x), Data type (0x%2x)", inArg.szSrc, inArg.nPathType, inArg.nDataType); 134 135 136 if(inArg.nPathType == ARG_TYPE_PATH_FILE){ 137 switch(inArg.nDataType){ 138 case ARG_TYPE_DATA_HEX: 139 if(!readBDAddrData(inArg.szSrc, loadedBDAddr->data.bin, BD_ADDR_LEN)){ 140 loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; 141 return SUCCESS; 142 } 143 break; 144 case ARG_TYPE_DATA_ASCII: 145 if(!readBDAddrData(inArg.szSrc, (unsigned char *)loadedBDAddr->data.sz, BD_ADDR_STR_LEN)){ 146 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 147 return SUCCESS; 148 } 149 break; 150 default: 151 return FAIL; 152 } 153 }else if(inArg.nPathType == ARG_TYPE_PATH_PROP){ 154 switch(inArg.nDataType){ 155 case ARG_TYPE_DATA_HEX: 156 if(property_get(inArg.szSrc, (char *)loadedBDAddr->data.bin, "")>=0){ 157 loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; 158 return SUCCESS; 159 } 160 break; 161 case ARG_TYPE_DATA_ASCII: 162 if(property_get(inArg.szSrc, loadedBDAddr->data.sz, "")>=0){ 163 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 164 return SUCCESS; 165 } 166 break; 167 default: 168 return FAIL; 169 } 170 }else{ 171 ALOGE("Error invalid argument : (%d)", inArg.nPathType); 172 } 173 174 ALOGE("Fail to read BDAddr from %s", inArg.szSrc); 175 return FAIL; 176 } 177 178 int writeBDAddr(OutArg outArg, LoadedBDAddr *loadedBDAddr) 179 { 180 char szTmp[BD_ADDR_STR_LEN] = {0,}; 181 182 ALOGI("Output Data type(0x%2x), bPrintout(%d), bPath(%s)", 183 outArg.dest.nDataType, outArg.bPrintOut, outArg.dest.szSrc); 184 185 ALOGI("Loaded Data type(0x%2x)", loadedBDAddr->nDataType); 186 187 if(outArg.dest.nDataType == ARG_TYPE_DATA_ASCII 188 && loadedBDAddr->nDataType == ARG_TYPE_DATA_HEX 189 ){ 190 if(!hexa_to_ascii(loadedBDAddr->data.bin, szTmp, BD_ADDR_LEN)){ 191 memcpy(loadedBDAddr->data.sz, szTmp, BD_ADDR_STR_LEN); 192 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 193 } 194 else{ 195 ALOGE("Fail to convert data"); 196 return FAIL; 197 } 198 } 199 200 if(loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII){ 201 // check out which addr data is already formated 202 if(strchr(loadedBDAddr->data.sz, '.') == NULL 203 && strchr(loadedBDAddr->data.sz, ':') == NULL 204 ){ 205 formattingBdAddr(loadedBDAddr->data.sz, outArg.cSeperator); 206 } 207 } 208 // print out szBDAddr 209 if(outArg.bPrintOut 210 && loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII 211 && strlen(loadedBDAddr->data.sz)==(BD_ADDR_STR_LEN-1)) { 212 printf("%s",loadedBDAddr->data.sz); 213 if (property_set(DEFAULT_BDADDR_PROP, loadedBDAddr->data.sz) < 0) 214 ALOGE("Failed to set address in prop %s", DEFAULT_BDADDR_PROP); 215 } 216 else{ 217 ALOGE("Invalid Data is loaded : %s", loadedBDAddr->data.sz); 218 return FAIL; 219 } 220 // TODO :: writing File or Property 221 return SUCCESS; 222 } 223 224 int main(int argc, char *argv[]) 225 { 226 int nFd, nRdCnt; 227 int c; 228 229 InArg inArg; 230 OutArg outArg; 231 LoadedBDAddr loadedBDAddr; 232 233 //initialize arg 234 memset(&inArg, 0, sizeof(InArg)); 235 memset(&outArg, 0, sizeof(OutArg)); 236 memset(&loadedBDAddr, 0, sizeof(LoadedBDAddr)); 237 238 //load args; 239 while((c=getopt(argc, argv, ":f:p:hsx")) != -1){ 240 switch(c){ 241 case 'f': // input path 242 if(optarg != NULL){ 243 ALOGI("option : f=%s", optarg); 244 inArg.szSrc = optarg; 245 }else{ 246 ALOGW("Invalid Argument(%s) of input path", optarg); 247 } 248 inArg.nPathType = ARG_TYPE_PATH_FILE; 249 break; 250 case 'p': // output path 251 if(optarg != NULL){ 252 ALOGI("option : p=%s", optarg); 253 inArg.szSrc = optarg; 254 }else{ 255 ALOGW("Invalid Argument(%s) of out Path", optarg); 256 } 257 inArg.nPathType = ARG_TYPE_PATH_PROP; 258 break; 259 case 'h': // data type to be read is hex 260 ALOGI("option : h"); 261 inArg.nDataType = ARG_TYPE_DATA_HEX; 262 break; 263 case 's': // data type to be read is ascii 264 ALOGI("option : s"); 265 inArg.nDataType = ARG_TYPE_DATA_ASCII; 266 break; 267 case 'x': 268 ALOGI("option : x"); 269 outArg.bPrintOut = 1; //true 270 break; 271 default: 272 ALOGW("Unknown option : %c", c); 273 break; 274 } 275 } 276 277 // setting up Arguments with default value 278 outArg.cSeperator = ':'; 279 outArg.dest.nDataType = ARG_TYPE_DATA_ASCII; 280 281 // load bd addr and print out bd addr in formated ascii 282 if(readBDAddr(inArg, &loadedBDAddr)){ 283 ALOGE("Fail to load data !!"); 284 return FAIL; 285 } 286 287 if(writeBDAddr(outArg, &loadedBDAddr)){ 288 ALOGE("Fail to write data !!"); 289 return FAIL; 290 } 291 292 return 1; 293 } 294