1 /* 2 * Copyright 2013 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 const char *szSrc; // Source Path 44 int nPathType; // Type of Source Path 45 int nDataType; // Type of Data 46 } ArgEl; 47 48 typedef ArgEl InArg; 49 50 #define DEFAULT_BDADDR_PROP "persist.service.bdroid.bdaddr" 51 52 typedef struct _OutArg { 53 ArgEl dest; 54 char cSeperator; // a character to be used for sperating like ':' of "XX:XX:XX:XX:XX:XX" 55 char bPrintOut; // Print out bd addr in standard out or not 56 } OutArg; 57 58 typedef struct _LoadedData { 59 union { 60 unsigned char bin[BD_ADDR_LEN]; 61 char sz[BD_ADDR_STR_LEN]; 62 }data; 63 int nDataType; 64 } LoadedBDAddr; 65 66 typedef enum _res { 67 SUCCESS = 0, 68 FAIL 69 } Res; 70 71 int hexa_to_ascii(const unsigned char* hexa, char* ascii, int nHexLen) 72 { 73 int i, j; 74 char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 75 'A', 'B', 'C', 'D', 'E', 'F'}; 76 77 for (i = 0, j = 0; i <nHexLen; i++, j += 2) { 78 ascii[j] = hex_table[hexa[i] >> 4]; 79 ascii[j + 1] = hex_table[hexa[i] & 0x0F]; 80 } 81 82 ascii[nHexLen*2] = '\0'; 83 84 ALOGI("hex_to_ascii() - converted Data (%s)", ascii); 85 86 return SUCCESS; 87 } 88 89 int readBDAddrData(const char* szFilePath, unsigned char* addrData, int nDataLen) 90 { 91 int nFd, nRdCnt; 92 93 nFd = open(szFilePath, O_RDONLY); 94 95 if (nFd < 0) { 96 ALOGW("There is no Address File in FTM area : %s\n", szFilePath); 97 return FAIL; 98 } 99 100 nRdCnt = read(nFd, addrData, nDataLen); 101 if (nRdCnt != nDataLen) { 102 ALOGE("Fail to read Address data from FTM area\n"); 103 close(nFd); 104 return FAIL; 105 } 106 close(nFd); 107 return SUCCESS; 108 } 109 110 void formattingBdAddr(char *szBDAddr, const char cSep) 111 { 112 int i = 1, j = 0; 113 int pos = 0; 114 for (i=1; i<BD_ADDR_LEN; i++) { 115 pos = strlen(szBDAddr); 116 for (j=0; j<(BD_ADDR_LEN*2)-i*2; j++) { 117 szBDAddr[pos-j] = szBDAddr[pos-j-1]; 118 } 119 szBDAddr[pos-j]=cSep; 120 } 121 } 122 123 int readBDAddr(InArg inArg, LoadedBDAddr *loadedBDAddr) 124 { 125 Res res = FAIL; 126 unsigned char addrData[BD_ADDR_LEN] = {0,}; 127 int nDataLen = 0; 128 129 ALOGI("Read From %s by Path type(0x%2x), Data type (0x%2x)", 130 inArg.szSrc, inArg.nPathType, inArg.nDataType); 131 132 if (inArg.nPathType == ARG_TYPE_PATH_FILE) { 133 switch (inArg.nDataType) { 134 case ARG_TYPE_DATA_HEX: 135 if (!readBDAddrData(inArg.szSrc, loadedBDAddr->data.bin, BD_ADDR_LEN)) { 136 loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; 137 return SUCCESS; 138 } 139 break; 140 case ARG_TYPE_DATA_ASCII: 141 if (!readBDAddrData(inArg.szSrc, (unsigned char *)loadedBDAddr->data.sz, BD_ADDR_STR_LEN)) { 142 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 143 return SUCCESS; 144 } 145 break; 146 default: 147 return FAIL; 148 } 149 } else if (inArg.nPathType == ARG_TYPE_PATH_PROP) { 150 char prop_value[PROPERTY_VALUE_MAX]; 151 switch (inArg.nDataType) { 152 case ARG_TYPE_DATA_HEX: 153 if (property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_LEN) { 154 strlcpy((char *)loadedBDAddr->data.bin, prop_value, BD_ADDR_LEN); 155 loadedBDAddr->nDataType = ARG_TYPE_DATA_HEX; 156 return SUCCESS; 157 } 158 break; 159 case ARG_TYPE_DATA_ASCII: 160 if (property_get(inArg.szSrc, prop_value, "") >= 0 && strlen(prop_value) < BD_ADDR_STR_LEN) { 161 strlcpy(loadedBDAddr->data.sz, prop_value, BD_ADDR_STR_LEN); 162 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 163 return SUCCESS; 164 } 165 break; 166 default: 167 return FAIL; 168 } 169 } else { 170 ALOGE("Error invalid argument : (%d)", inArg.nPathType); 171 } 172 173 ALOGE("Fail to read BDAddr from %s", inArg.szSrc); 174 return FAIL; 175 } 176 177 int writeBDAddr(OutArg outArg, LoadedBDAddr *loadedBDAddr) 178 { 179 char szTmp[BD_ADDR_STR_LEN] = {0,}; 180 181 ALOGI("Output Data type(0x%2x), bPrintout(%d), bPath(%s)", 182 outArg.dest.nDataType, outArg.bPrintOut, outArg.dest.szSrc); 183 184 ALOGI("Loaded Data type(0x%2x)", loadedBDAddr->nDataType); 185 186 if (outArg.dest.nDataType == ARG_TYPE_DATA_ASCII 187 && loadedBDAddr->nDataType == ARG_TYPE_DATA_HEX) { 188 if (!hexa_to_ascii(loadedBDAddr->data.bin, szTmp, BD_ADDR_LEN)) { 189 memcpy(loadedBDAddr->data.sz, szTmp, BD_ADDR_STR_LEN); 190 loadedBDAddr->nDataType = ARG_TYPE_DATA_ASCII; 191 } else { 192 ALOGE("Fail to convert data"); 193 return FAIL; 194 } 195 } 196 197 if (loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII) { 198 // check out which addr data is already formated 199 if (strchr(loadedBDAddr->data.sz, '.') == NULL 200 && strchr(loadedBDAddr->data.sz, ':') == NULL) { 201 formattingBdAddr(loadedBDAddr->data.sz, outArg.cSeperator); 202 } 203 } 204 // print out szBDAddr 205 if (outArg.bPrintOut 206 && loadedBDAddr->nDataType == ARG_TYPE_DATA_ASCII 207 && strlen(loadedBDAddr->data.sz)==(BD_ADDR_STR_LEN-1)) { 208 printf("%s",loadedBDAddr->data.sz); 209 if (property_set(DEFAULT_BDADDR_PROP, loadedBDAddr->data.sz) < 0) 210 ALOGE("Failed to set address in prop %s", DEFAULT_BDADDR_PROP); 211 } else { 212 ALOGE("Invalid Data is loaded : %s", loadedBDAddr->data.sz); 213 return FAIL; 214 } 215 // TODO :: writing File or Property 216 return SUCCESS; 217 } 218 219 int main(int argc, char *argv[]) 220 { 221 int nFd, nRdCnt; 222 int c; 223 224 InArg inArg; 225 OutArg outArg; 226 LoadedBDAddr loadedBDAddr; 227 228 //initialize arg 229 memset(&inArg, 0, sizeof(InArg)); 230 memset(&outArg, 0, sizeof(OutArg)); 231 memset(&loadedBDAddr, 0, sizeof(LoadedBDAddr)); 232 233 //load args; 234 while((c=getopt(argc, argv, ":f:p:hsx")) != -1){ 235 switch(c){ 236 case 'f': // input path 237 if (optarg != NULL) { 238 ALOGI("option : f=%s", optarg); 239 inArg.szSrc = optarg; 240 } else { 241 ALOGW("Invalid Argument(%s) of input path", optarg); 242 } 243 inArg.nPathType = ARG_TYPE_PATH_FILE; 244 break; 245 case 'p': // output path 246 if (optarg != NULL) { 247 ALOGI("option : p=%s", optarg); 248 inArg.szSrc = optarg; 249 } else { 250 ALOGW("Invalid Argument(%s) of out Path", optarg); 251 } 252 inArg.nPathType = ARG_TYPE_PATH_PROP; 253 break; 254 case 'h': // data type to be read is hex 255 ALOGI("option : h"); 256 inArg.nDataType = ARG_TYPE_DATA_HEX; 257 break; 258 case 's': // data type to be read is ascii 259 ALOGI("option : s"); 260 inArg.nDataType = ARG_TYPE_DATA_ASCII; 261 break; 262 case 'x': 263 ALOGI("option : x"); 264 outArg.bPrintOut = 1; //true 265 break; 266 default: 267 ALOGW("Unknown option : %c", c); 268 break; 269 } 270 } 271 272 // setting up Arguments with default value 273 outArg.cSeperator = ':'; 274 outArg.dest.nDataType = ARG_TYPE_DATA_ASCII; 275 276 // load bd addr and print out bd addr in formated ascii 277 if (readBDAddr(inArg, &loadedBDAddr)) { 278 ALOGE("Fail to load data !!"); 279 return FAIL; 280 } 281 282 if (writeBDAddr(outArg, &loadedBDAddr)) { 283 ALOGE("Fail to write data !!"); 284 return FAIL; 285 } 286 287 return 1; 288 } 289