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