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 char prop_value[PROPERTY_VALUE_MAX]; 155 switch(inArg.nDataType){ 156 case ARG_TYPE_DATA_HEX: 157 if(property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_LEN){ 158 strlcpy((char *)loadedBDAddr->data.bin, prop_value, BD_ADDR_LEN); 159 loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; 160 return SUCCESS; 161 } 162 break; 163 case ARG_TYPE_DATA_ASCII: 164 if(property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_STR_LEN){ 165 strlcpy(loadedBDAddr->data.sz, prop_value, BD_ADDR_STR_LEN); 166 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 167 return SUCCESS; 168 } 169 break; 170 default: 171 return FAIL; 172 } 173 }else{ 174 ALOGE("Error invalid argument : (%d)", inArg.nPathType); 175 } 176 177 ALOGE("Fail to read BDAddr from %s", inArg.szSrc); 178 return FAIL; 179 } 180 181 int writeBDAddr(OutArg outArg, LoadedBDAddr *loadedBDAddr) 182 { 183 char szTmp[BD_ADDR_STR_LEN] = {0,}; 184 185 ALOGI("Output Data type(0x%2x), bPrintout(%d), bPath(%s)", 186 outArg.dest.nDataType, outArg.bPrintOut, outArg.dest.szSrc); 187 188 ALOGI("Loaded Data type(0x%2x)", loadedBDAddr->nDataType); 189 190 if(outArg.dest.nDataType == ARG_TYPE_DATA_ASCII 191 && loadedBDAddr->nDataType == ARG_TYPE_DATA_HEX 192 ){ 193 if(!hexa_to_ascii(loadedBDAddr->data.bin, szTmp, BD_ADDR_LEN)){ 194 memcpy(loadedBDAddr->data.sz, szTmp, BD_ADDR_STR_LEN); 195 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 196 } 197 else{ 198 ALOGE("Fail to convert data"); 199 return FAIL; 200 } 201 } 202 203 if(loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII){ 204 // check out which addr data is already formated 205 if(strchr(loadedBDAddr->data.sz, '.') == NULL 206 && strchr(loadedBDAddr->data.sz, ':') == NULL 207 ){ 208 formattingBdAddr(loadedBDAddr->data.sz, outArg.cSeperator); 209 } 210 } 211 // print out szBDAddr 212 if(outArg.bPrintOut 213 && loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII 214 && strlen(loadedBDAddr->data.sz)==(BD_ADDR_STR_LEN-1)) { 215 printf("%s",loadedBDAddr->data.sz); 216 if (property_set(DEFAULT_BDADDR_PROP, loadedBDAddr->data.sz) < 0) 217 ALOGE("Failed to set address in prop %s", DEFAULT_BDADDR_PROP); 218 } 219 else{ 220 ALOGE("Invalid Data is loaded : %s", loadedBDAddr->data.sz); 221 return FAIL; 222 } 223 // TODO :: writing File or Property 224 return SUCCESS; 225 } 226 227 int main(int argc, char *argv[]) 228 { 229 int nFd, nRdCnt; 230 int c; 231 232 InArg inArg; 233 OutArg outArg; 234 LoadedBDAddr loadedBDAddr; 235 236 //initialize arg 237 memset(&inArg, 0, sizeof(InArg)); 238 memset(&outArg, 0, sizeof(OutArg)); 239 memset(&loadedBDAddr, 0, sizeof(LoadedBDAddr)); 240 241 //load args; 242 while((c=getopt(argc, argv, ":f:p:hsx")) != -1){ 243 switch(c){ 244 case 'f': // input path 245 if(optarg != NULL){ 246 ALOGI("option : f=%s", optarg); 247 inArg.szSrc = optarg; 248 }else{ 249 ALOGW("Invalid Argument(%s) of input path", optarg); 250 } 251 inArg.nPathType = ARG_TYPE_PATH_FILE; 252 break; 253 case 'p': // output path 254 if(optarg != NULL){ 255 ALOGI("option : p=%s", optarg); 256 inArg.szSrc = optarg; 257 }else{ 258 ALOGW("Invalid Argument(%s) of out Path", optarg); 259 } 260 inArg.nPathType = ARG_TYPE_PATH_PROP; 261 break; 262 case 'h': // data type to be read is hex 263 ALOGI("option : h"); 264 inArg.nDataType = ARG_TYPE_DATA_HEX; 265 break; 266 case 's': // data type to be read is ascii 267 ALOGI("option : s"); 268 inArg.nDataType = ARG_TYPE_DATA_ASCII; 269 break; 270 case 'x': 271 ALOGI("option : x"); 272 outArg.bPrintOut = 1; //true 273 break; 274 default: 275 ALOGW("Unknown option : %c", c); 276 break; 277 } 278 } 279 280 // setting up Arguments with default value 281 outArg.cSeperator = ':'; 282 outArg.dest.nDataType = ARG_TYPE_DATA_ASCII; 283 284 // load bd addr and print out bd addr in formated ascii 285 if(readBDAddr(inArg, &loadedBDAddr)){ 286 ALOGE("Fail to load data !!"); 287 return FAIL; 288 } 289 290 if(writeBDAddr(outArg, &loadedBDAddr)){ 291 ALOGE("Fail to write data !!"); 292 return FAIL; 293 } 294 295 return 1; 296 } 297