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