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
hexa_to_ascii(const unsigned char * hexa,char * ascii,int nHexLen)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
readBDAddrData(const char * szFilePath,unsigned char * addrData,int nDataLen)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
formattingBdAddr(char * szBDAddr,const char cSep)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
readBDAddr(InArg inArg,LoadedBDAddr * loadedBDAddr)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
writeBDAddr(OutArg outArg,LoadedBDAddr * loadedBDAddr)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
main(int argc,char * argv[])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